@@ -989,6 +989,25 @@ BailOutRecord::RestoreValue(IR::BailOutKind bailOutKind, Js::JavascriptCallStack
989
989
value = Js::JavascriptNumber::ToVar (int32Value, scriptContext);
990
990
BAILOUT_VERBOSE_TRACE (newInstance->function ->GetFunctionBody (), bailOutKind, _u (" , value: %10d (ToVar: 0x%p)" ), int32Value, value);
991
991
}
992
+ else if (regSlot == newInstance->function ->GetFunctionBody ()->GetYieldRegister () && newInstance->function ->GetFunctionBody ()->IsCoroutine ())
993
+ {
994
+ // This value can only either be:
995
+ // 1) the ResumeYieldData. Even though this value is on the stack, it is only used to extract the data as part of Op_ResumeYield.
996
+ // So there is no need to box the value.
997
+ // 2) the object used as the return value for yield statement. This object is created on the heap, so no need to box either.
998
+ Assert (value);
999
+
1000
+ #if ENABLE_DEBUG_CONFIG_OPTIONS
1001
+ if (ThreadContext::IsOnStack (value))
1002
+ {
1003
+ BAILOUT_VERBOSE_TRACE (newInstance->function ->GetFunctionBody (), bailOutKind, _u (" , value: 0x%p (ResumeYieldData)" ), value);
1004
+ }
1005
+ else
1006
+ {
1007
+ BAILOUT_VERBOSE_TRACE (newInstance->function ->GetFunctionBody (), bailOutKind, _u (" , value: 0x%p (Yield Return Value)" ), value);
1008
+ }
1009
+ #endif
1010
+ }
992
1011
else
993
1012
{
994
1013
BAILOUT_VERBOSE_TRACE (newInstance->function ->GetFunctionBody (), bailOutKind, _u (" , value: 0x%p" ), value);
@@ -1507,63 +1526,32 @@ BailOutRecord::BailOutHelper(Js::JavascriptCallStackLayout * layout, Js::ScriptF
1507
1526
if (executeFunction->IsCoroutine ())
1508
1527
{
1509
1528
// If the FunctionBody is a generator then this call is being made by one of the three
1510
- // generator resuming methods: next(), throw(), or return(). They all pass the generator
1511
- // object as the first of two arguments. The real user arguments are obtained from the
1512
- // generator object. The second argument is the ResumeYieldData which is only needed
1513
- // when resuming a generator and not needed when yielding from a generator, as is occurring
1514
- // here.
1529
+ // generator resuming methods: next(), throw(), or return(). They all pass the generator
1530
+ // object as the first of two arguments. The real user arguments are obtained from the
1531
+ // generator object. The second argument is the ResumeYieldData which is only needed when
1532
+ // resuming a generator and not needed when yielding from a generator, as is occurring here.
1515
1533
AssertMsg (args.Info .Count == 2 , " Generator ScriptFunctions should only be invoked by generator APIs with the pair of arguments they pass in -- the generator object and a ResumeYieldData pointer" );
1516
1534
Js::JavascriptGenerator* generator = Js::VarTo<Js::JavascriptGenerator>(args[0 ]);
1517
1535
newInstance = generator->GetFrame ();
1518
1536
1519
- if (newInstance != nullptr )
1520
- {
1521
- // BailOut will recompute OutArg pointers based on BailOutRecord. Reset them back
1522
- // to initial position before that happens so that OP_StartCall calls don't accumulate
1523
- // incorrectly over multiple yield bailouts.
1524
- newInstance->ResetOut ();
1525
-
1526
- // The debugger relies on comparing stack addresses of frames to decide when a step_out is complete so
1527
- // give the InterpreterStackFrame a legit enough stack address to make this comparison work.
1528
- newInstance->m_stackAddress = reinterpret_cast <DWORD_PTR>(&generator);
1529
- }
1530
- else
1531
- {
1532
- //
1533
- // Allocate a new InterpreterStackFrame instance on the recycler heap.
1534
- // It will live with the JavascriptGenerator object.
1535
- //
1536
- Js::Arguments generatorArgs = generator->GetArguments ();
1537
- Js::InterpreterStackFrame::Setup setup (function, generatorArgs, true , isInlinee);
1538
- Assert (setup.GetStackAllocationVarCount () == 0 );
1539
- size_t varAllocCount = setup.GetAllocationVarCount ();
1540
- size_t varSizeInBytes = varAllocCount * sizeof (Js::Var);
1541
- DWORD_PTR stackAddr = reinterpret_cast <DWORD_PTR>(&generator); // as mentioned above, use any stack address from this frame to ensure correct debugging functionality
1542
- Js::LoopHeader* loopHeaderArray = executeFunction->GetHasAllocatedLoopHeaders () ? executeFunction->GetLoopHeaderArrayPtr () : nullptr ;
1543
-
1544
- allocation = RecyclerNewPlus (functionScriptContext->GetRecycler (), varSizeInBytes, Js::Var);
1545
-
1546
- // Initialize the interpreter stack frame (constants) but not the param, the bailout record will restore the value
1547
- #if DBG
1548
- // Allocate invalidVar on GC instead of stack since this InterpreterStackFrame will out live the current real frame
1549
- Js::Var invalidVar = (Js::RecyclableObject*)RecyclerNewPlusLeaf (functionScriptContext->GetRecycler (), sizeof (Js::RecyclableObject), Js::Var);
1550
- memset (invalidVar, 0xFE , sizeof (Js::RecyclableObject));
1551
- #endif
1537
+ // The jit relies on the interpreter stack frame to store various information such as
1538
+ // for-in enumerators. Therefore, we always create an interpreter stack frame for generator
1539
+ // as part of the resume jump table, at the beginning of the jit'd function, if it doesn't
1540
+ // already exist.
1541
+ Assert (newInstance != nullptr );
1552
1542
1553
- newInstance = setup.InitializeAllocation (allocation, nullptr , false , false , loopHeaderArray, stackAddr
1554
- #if DBG
1555
- , invalidVar
1556
- #endif
1557
- );
1543
+ // BailOut will recompute OutArg pointers based on BailOutRecord. Reset them back
1544
+ // to initial position before that happens so that OP_StartCall calls don't accumulate
1545
+ // incorrectly over multiple yield bailouts.
1546
+ newInstance->ResetOut ();
1558
1547
1559
- newInstance->m_reader .Create (executeFunction);
1560
-
1561
- generator->SetFrame (newInstance, varSizeInBytes);
1562
- }
1548
+ // The debugger relies on comparing stack addresses of frames to decide when a step_out is complete so
1549
+ // give the InterpreterStackFrame a legit enough stack address to make this comparison work.
1550
+ newInstance->m_stackAddress = reinterpret_cast <DWORD_PTR>(&generator);
1563
1551
}
1564
1552
else
1565
1553
{
1566
- Js::InterpreterStackFrame::Setup setup (function, args, true , isInlinee);
1554
+ Js::InterpreterStackFrame::Setup setup (function, args, true /* bailedOut */ , isInlinee);
1567
1555
size_t varAllocCount = setup.GetAllocationVarCount ();
1568
1556
size_t stackVarAllocCount = setup.GetStackAllocationVarCount ();
1569
1557
size_t varSizeInBytes;
@@ -2826,7 +2814,7 @@ void BailOutRecord::CheckPreemptiveRejit(Js::FunctionBody* executeFunction, IR::
2826
2814
2827
2815
Js::Var BailOutRecord::BailOutForElidedYield (void * framePointer)
2828
2816
{
2829
- JIT_HELPER_REENTRANT_HEADER (NoSaveRegistersBailOutForElidedYield);
2817
+ JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER (NoSaveRegistersBailOutForElidedYield);
2830
2818
Js::JavascriptCallStackLayout * const layout = Js::JavascriptCallStackLayout::FromFramePointer (framePointer);
2831
2819
Js::ScriptFunction ** functionRef = (Js::ScriptFunction **)&layout->functionObject ;
2832
2820
Js::ScriptFunction * function = *functionRef;
0 commit comments