Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions lib/Backend/IRBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1891,6 +1891,20 @@ IRBuilder::BuildReg2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, Js::Re
this->AddInstr(bailInLabel, offset);
this->m_func->AddYieldOffsetResumeLabel(nextOffset, bailInLabel);


#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
if (PHASE_TRACE(Js::Phase::BailInPhase, this->m_func))
{
IR::LabelInstr* traceBailInLabel = IR::LabelInstr::New(Js::OpCode::GeneratorOutputBailInTraceLabel, m_func);
traceBailInLabel->m_hasNonBranchRef = true; // set to true so that we don't move this label around
LABELNAMESET(traceBailInLabel, "OutputBailInTrace");
this->AddInstr(traceBailInLabel, offset);

IR::Instr* traceBailIn = IR::Instr::New(Js::OpCode::GeneratorOutputBailInTrace, m_func);
this->AddInstr(traceBailIn, offset);
}
#endif

// This label indicates the section where we start loading the ResumeYieldData on the stack
// that comes from either .next(), .return(), or .throw() to the right symbol and finally
// extract its data through Op_ResumeYield
Expand Down
4 changes: 4 additions & 0 deletions lib/Backend/JnHelperMethodList.h
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,10 @@ HELPERCALL(Await, Js::InterpreterStackFrame::OP_Await, Att

HELPERCALL(CreateInterpreterStackFrameForGenerator, Js::InterpreterStackFrame::CreateInterpreterStackFrameForGenerator, AttrCanNotBeReentrant)

#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
HELPERCALL(OutputGeneratorBailInTrace, Js::JavascriptGenerator::OutputBailInTrace, AttrCanNotBeReentrant)
#endif

#if DBG
HELPERCALL(IntRangeCheckFailure, Js::JavascriptNativeOperators::IntRangeCheckFailure, AttrCanNotBeReentrant)
#endif
Expand Down
73 changes: 73 additions & 0 deletions lib/Backend/LinearScan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5039,6 +5039,15 @@ IR::Instr* LinearScan::GeneratorBailIn::GenerateBailIn(IR::Instr* resumeLabelIns
this->InsertRestoreSymbols(bailOutInfo->byteCodeUpwardExposedUsed, insertionPoint);
Assert(!this->func->IsStackArgsEnabled());

#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
if (PHASE_TRACE(Js::Phase::BailInPhase, this->func))
{
IR::Instr* insertBailInTraceBefore = instrAfter;
Assert(insertBailInTraceBefore->m_opcode == Js::OpCode::GeneratorOutputBailInTraceLabel);
this->InsertBailInTrace(bailOutInfo->byteCodeUpwardExposedUsed, insertBailInTraceBefore->m_next);
}
#endif

return instrAfter;
}

Expand Down Expand Up @@ -5195,3 +5204,67 @@ uint32 LinearScan::GeneratorBailIn::GetOffsetFromInterpreterStackFrame(Js::RegSl
return regSlot * sizeof(Js::Var) + Js::InterpreterStackFrame::GetOffsetOfLocals();
}
}

#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
void LinearScan::GeneratorBailIn::InsertBailInTrace(BVSparse<JitArenaAllocator>* symbols, IR::Instr* insertBeforeInstr)
{
IR::RegOpnd* traceBailInSymbolsArrayRegOpnd = this->interpreterFrameRegOpnd;

// Load JavascriptGenerator->bailInSymbolsTraceArray
{
LinearScan::InsertMove(traceBailInSymbolsArrayRegOpnd, this->CreateGeneratorObjectOpnd(), insertBeforeInstr);
IR::IndirOpnd* traceBailInSymbolsArrayIndirOpnd = IR::IndirOpnd::New(traceBailInSymbolsArrayRegOpnd, Js::JavascriptGenerator::GetBailInSymbolsTraceArrayOffset(), TyMachPtr, this->func);
LinearScan::InsertMove(traceBailInSymbolsArrayRegOpnd, traceBailInSymbolsArrayIndirOpnd, insertBeforeInstr);
}

int count = 0;
FOREACH_BITSET_IN_SPARSEBV(symId, symbols)
{
StackSym* stackSym = this->func->m_symTable->FindStackSym(symId);
Lifetime* lifetime = stackSym->scratch.linearScan.lifetime;

if (!this->NeedsReloadingValueWhenBailIn(stackSym, lifetime))
{
continue;
}

int offset = sizeof(Js::JavascriptGenerator::BailInSymbol) * count;

// Assign JavascriptGenerator->bailInSymbolsTraceArray[count]->id
{
IR::IndirOpnd* idIndirOpnd = IR::IndirOpnd::New(traceBailInSymbolsArrayRegOpnd, offset + Js::JavascriptGenerator::BailInSymbol::GetBailInSymbolIdOffset(), TyMachPtr, this->func);
IR::IntConstOpnd* idConstOpnd = IR::IntConstOpnd::New(stackSym->m_id, TyUint8, this->func);
LinearScan::InsertMove(idIndirOpnd, idConstOpnd, insertBeforeInstr);
}

// Assign JavascriptGenerator->bailInSymbolsTraceArray[count]->value
{
IR::IndirOpnd* valueIndirOpnd = IR::IndirOpnd::New(traceBailInSymbolsArrayRegOpnd, offset + Js::JavascriptGenerator::BailInSymbol::GetBailInSymbolValueOffset(), TyMachPtr, this->func);
IR::Opnd* srcOpnd;
if (lifetime->isSpilled)
{
IR::SymOpnd* stackSymOpnd = IR::SymOpnd::New(stackSym, stackSym->GetType(), this->func);
LinearScan::InsertMove(this->tempRegOpnd, stackSymOpnd, insertBeforeInstr);
srcOpnd = this->tempRegOpnd;
}
else
{
srcOpnd = IR::RegOpnd::New(stackSym, stackSym->GetType(), this->func);
srcOpnd->AsRegOpnd()->SetReg(lifetime->reg);
}
LinearScan::InsertMove(valueIndirOpnd, srcOpnd, insertBeforeInstr);
}

count++;
}
NEXT_BITSET_IN_SPARSEBV;

// Assign JavascriptGenerator->bailInSymbolsTraceArrayCount
{
LinearScan::InsertMove(this->tempRegOpnd, this->CreateGeneratorObjectOpnd(), insertBeforeInstr);
IR::IndirOpnd* traceBailInSymbolsArrayCountIndirOpnd = IR::IndirOpnd::New(this->tempRegOpnd, Js::JavascriptGenerator::GetBailInSymbolsTraceArrayCountOffset(), TyMachPtr, this->func);
IR::IntConstOpnd* countOpnd = IR::IntConstOpnd::New(count, TyInt32, this->func);
LinearScan::InsertMove(traceBailInSymbolsArrayCountIndirOpnd, countOpnd, insertBeforeInstr);
}
}
#endif
3 changes: 3 additions & 0 deletions lib/Backend/LinearScan.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,9 @@ class LinearScan

void InsertRestoreSymbols(BVSparse<JitArenaAllocator>* symbols, BailInInsertionPoint& insertionPoint);

#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
void InsertBailInTrace(BVSparse<JitArenaAllocator>* symbols, IR::Instr* insertBeforeInstr);
#endif
public:
GeneratorBailIn(Func* func, LinearScan* linearScan);
IR::Instr* GenerateBailIn(IR::Instr* resumeLabelInstr, BailOutInfo* bailOutInfo);
Expand Down
26 changes: 26 additions & 0 deletions lib/Backend/Lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3031,6 +3031,14 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
break;
}

#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
case Js::OpCode::GeneratorOutputBailInTrace:
{
this->m_lowerGeneratorHelper.LowerGeneratorTraceBailIn(instr);
break;
}
#endif

case Js::OpCode::GeneratorResumeJumpTable:
{
this->m_lowerGeneratorHelper.InsertBailOutForElidedYield();
Expand Down Expand Up @@ -3140,6 +3148,9 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
instrPrev = this->LowerStPropIdArrFromVar(instr);
break;

#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
case Js::OpCode::GeneratorOutputBailInTraceLabel:
#endif
case Js::OpCode::GeneratorBailInLabel:
case Js::OpCode::GeneratorResumeYieldLabel:
case Js::OpCode::GeneratorEpilogueFrameNullOut:
Expand Down Expand Up @@ -26550,6 +26561,9 @@ Lowerer::ValidOpcodeAfterLower(IR::Instr* instr, Func * func)
Assert(func->HasTry() && func->DoOptimizeTry());
return func && !func->isPostFinalLower; //Lowered in FinalLower phase

#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
case Js::OpCode::GeneratorOutputBailInTraceLabel:
#endif
case Js::OpCode::GeneratorBailInLabel:
case Js::OpCode::GeneratorResumeYieldLabel:
case Js::OpCode::GeneratorEpilogueFrameNullOut:
Expand Down Expand Up @@ -29286,6 +29300,18 @@ Lowerer::LowerGeneratorHelper::LowerCreateInterpreterStackFrameForGenerator(IR::
this->lowererMD.ChangeToHelperCall(instr, IR::HelperCreateInterpreterStackFrameForGenerator);
}

#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
void
Lowerer::LowerGeneratorHelper::LowerGeneratorTraceBailIn(IR::Instr* instr)
{
StackSym* genParamSym = StackSym::NewParamSlotSym(1, instr->m_func);
instr->m_func->SetArgOffset(genParamSym, LowererMD::GetFormalParamOffset() * MachPtr);
IR::SymOpnd* genParamOpnd = IR::SymOpnd::New(genParamSym, TyMachPtr, instr->m_func);
this->lowererMD.LoadHelperArgument(instr, genParamOpnd);
this->lowererMD.ChangeToHelperCall(instr, IR::HelperOutputGeneratorBailInTrace);
}
#endif

IR::SymOpnd*
Lowerer::LowerGeneratorHelper::CreateResumeYieldDataOpnd() const
{
Expand Down
4 changes: 4 additions & 0 deletions lib/Backend/Lower.h
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,10 @@ class Lowerer
void LowerResumeGenerator(IR::Instr* instr);
void LowerYield(IR::Instr* instr);
void LowerGeneratorLoadResumeYieldData(IR::Instr* instr);

#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
void LowerGeneratorTraceBailIn(IR::Instr* instr);
#endif
};

LowerGeneratorHelper m_lowerGeneratorHelper;
Expand Down
1 change: 1 addition & 0 deletions lib/Common/ConfigFlagsList.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ PHASE(All)
PHASE(FinishPartial)
PHASE(Host)
PHASE(BailOut)
PHASE(BailIn)
PHASE(RegexQc)
PHASE(RegexOptBT)
PHASE(InlineCache)
Expand Down
2 changes: 2 additions & 0 deletions lib/Runtime/ByteCode/OpCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,8 @@ MACRO_BACKEND_ONLY(LazyBailOutThunkLabel, Empty, None)
MACRO_BACKEND_ONLY(GeneratorResumeJumpTable, Reg1, OpSideEffect) // OpSideEffect because we don't want this to be deadstored
MACRO_BACKEND_ONLY(GeneratorCreateInterpreterStackFrame, Reg1, OpSideEffect) // OpSideEffect because we don't want this to be deadstored
MACRO_BACKEND_ONLY(GeneratorLoadResumeYieldData, Reg1, OpSideEffect) // OpSideEffect because we don't want this to be deadstored
MACRO_BACKEND_ONLY(GeneratorOutputBailInTrace, Empty, OpSideEffect) // OpSideEffect because we don't want this to be deadstored
MACRO_BACKEND_ONLY(GeneratorOutputBailInTraceLabel, Empty, None)
MACRO_BACKEND_ONLY(GeneratorBailInLabel, Empty, None)
MACRO_BACKEND_ONLY(GeneratorResumeYieldLabel, Empty, None)
MACRO_BACKEND_ONLY(GeneratorEpilogueFrameNullOut, Empty, None)
Expand Down
14 changes: 14 additions & 0 deletions lib/Runtime/Language/InterpreterStackFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1844,6 +1844,20 @@ namespace Js
newInstance->m_reader.Create(executeFunction);

generator->SetFrame(newInstance, varSizeInBytes);

// Moving this to when we create the generator instance in the first place would be nice.
// But at that point the function might not have been parsed yet, so we don't have the locals count.
// We are also allocating more space than we actually need because we shouldn't need to
// reload all the symbols when bailing in.
#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
if (PHASE_TRACE(Js::Phase::BailInPhase, function->GetFunctionBody()))
{
generator->bailInSymbolsTraceArray = (Js::JavascriptGenerator::BailInSymbol*) RecyclerNewArrayLeafZ(
functionScriptContext->GetRecycler(), Js::JavascriptGenerator::BailInSymbol, executeFunction->GetFunctionBody()->GetLocalsCount()
);
}
#endif

return newInstance;
}

Expand Down
22 changes: 22 additions & 0 deletions lib/Runtime/Library/JavascriptGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,28 @@ namespace Js
return function->GetScriptContext()->GetLibrary()->GetUndefined();
}

#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
void JavascriptGenerator::OutputBailInTrace(JavascriptGenerator* generator)
{
char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
FunctionBody *fnBody = generator->scriptFunction->GetFunctionBody();
Output::Print(_u("BailIn: function: %s (%s) offset: #%04x\n"), fnBody->GetDisplayName(), fnBody->GetDebugNumberSet(debugStringBuffer), generator->frame->m_reader.GetCurrentOffset());

if (generator->bailInSymbolsTraceArrayCount == 0)
{
Output::Print(_u("BailIn: No symbols reloaded\n"), fnBody->GetDisplayName(), fnBody->GetDebugNumberSet(debugStringBuffer));
}
else
{
for (int i = 0; i < generator->bailInSymbolsTraceArrayCount; i++)
{
const JavascriptGenerator::BailInSymbol& symbol = generator->bailInSymbolsTraceArray[i];
Output::Print(_u("BailIn: Register #%4d, value: 0x%p\n"), symbol.id, symbol.value);
}
}
}
#endif

template <> bool VarIsImpl<AsyncGeneratorNextProcessor>(RecyclableObject* obj)
{
if (VarIs<JavascriptFunction>(obj))
Expand Down
17 changes: 17 additions & 0 deletions lib/Runtime/Library/JavascriptGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,23 @@ namespace Js
virtual void ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) override;
//virtual void ProcessCorePaths() override;
#endif

#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
public:
struct BailInSymbol {
uint32 id;
Var value;
static uint32 GetBailInSymbolIdOffset() { return offsetof(BailInSymbol, id); }
static uint32 GetBailInSymbolValueOffset() { return offsetof(BailInSymbol, value); }
};

Field(BailInSymbol*) bailInSymbolsTraceArray = nullptr;
Field(int) bailInSymbolsTraceArrayCount = 0;

static uint32 GetBailInSymbolsTraceArrayOffset() { return offsetof(JavascriptGenerator, bailInSymbolsTraceArray); }
static uint32 GetBailInSymbolsTraceArrayCountOffset() { return offsetof(JavascriptGenerator, bailInSymbolsTraceArrayCount); }
static void OutputBailInTrace(JavascriptGenerator* generator);
#endif
};

template <> bool VarIsImpl<JavascriptGenerator>(RecyclableObject* obj);
Expand Down