@@ -1537,6 +1537,7 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
15371537 break;
15381538
15391539 case Js::OpCode::IsIn:
1540+ this->GenerateFastInlineIsIn(instr);
15401541 this->LowerBinaryHelperMem(instr, IR::HelperOp_IsIn);
15411542 break;
15421543
@@ -19398,6 +19399,101 @@ Lowerer::GenerateFastInlineRegExpExec(IR::Instr * instr)
1939819399 RelocateCallDirectToHelperPath(tmpInstr, labelHelper);
1939919400}
1940019401
19402+ // Generate a fast path for the "in" operator that check quickly if we have an array or not and if the index of the data is contained in the array's length.
19403+ void Lowerer::GenerateFastInlineIsIn(IR::Instr * instr)
19404+ {
19405+ // operator "foo in bar"
19406+ IR::Opnd* src1 = instr->GetSrc1(); // foo
19407+ IR::Opnd* src2 = instr->GetSrc2(); // bar
19408+
19409+ if (!src2->GetValueType().IsLikelyArray() || !src2->GetValueType().HasNoMissingValues())
19410+ {
19411+ return;
19412+ }
19413+
19414+ IR::LabelInstr* helperLabel = IR::LabelInstr::New(Js::OpCode::Label, m_func, true);
19415+ IR::LabelInstr* doneFalseLabel = IR::LabelInstr::New(Js::OpCode::Label, m_func);
19416+ IR::LabelInstr* doneLabel = IR::LabelInstr::New(Js::OpCode::Label, m_func);
19417+ IR::LabelInstr* isArrayLabel = IR::LabelInstr::New(Js::OpCode::Label, m_func);
19418+
19419+ IR::RegOpnd* src1Untagged = GenerateUntagVar(src1->AsRegOpnd(), helperLabel, instr);
19420+ IR::RegOpnd* src2RegOpnd = IR::RegOpnd::New(TyMachPtr, m_func);
19421+ InsertMove(src2RegOpnd, src2, instr);
19422+
19423+
19424+ IR::AutoReuseOpnd autoReuseArrayOpnd;
19425+ m_lowererMD.GenerateObjectTest(src2RegOpnd, instr, helperLabel);
19426+ IR::RegOpnd* arrayOpnd = src2RegOpnd->Copy(instr->m_func)->AsRegOpnd();
19427+ autoReuseArrayOpnd.Initialize(arrayOpnd, instr->m_func, false /* autoDelete */);
19428+
19429+ IR::Opnd* vtableOpnd = LoadVTableValueOpnd(instr, VTableValue::VtableJavascriptArray);
19430+ InsertCompareBranch(
19431+ IR::IndirOpnd::New(arrayOpnd, 0, TyMachPtr, instr->m_func),
19432+ vtableOpnd,
19433+ Js::OpCode::BrEq_A,
19434+ isArrayLabel,
19435+ instr);
19436+
19437+ vtableOpnd = LoadVTableValueOpnd(instr, VTableValue::VtableNativeIntArray);
19438+ InsertCompareBranch(
19439+ IR::IndirOpnd::New(arrayOpnd, 0, TyMachPtr, instr->m_func),
19440+ vtableOpnd,
19441+ Js::OpCode::BrEq_A,
19442+ isArrayLabel,
19443+ instr);
19444+
19445+ vtableOpnd = LoadVTableValueOpnd(instr, VTableValue::VtableNativeFloatArray);
19446+ InsertCompareBranch(
19447+ IR::IndirOpnd::New(arrayOpnd, 0, TyMachPtr, instr->m_func),
19448+ vtableOpnd,
19449+ Js::OpCode::BrNeq_A,
19450+ helperLabel,
19451+ instr);
19452+
19453+ instr->InsertBefore(isArrayLabel);
19454+
19455+ InsertTestBranch(
19456+ IR::IndirOpnd::New(src2RegOpnd, Js::JavascriptArray::GetOffsetOfArrayFlags(), TyUint8, m_func),
19457+ IR::IntConstOpnd::New(static_cast<uint8>(Js::DynamicObjectFlags::HasNoMissingValues), TyUint8, m_func, true),
19458+ Js::OpCode::BrEq_A,
19459+ helperLabel,
19460+ instr);
19461+
19462+ IR::AutoReuseOpnd autoReuseHeadSegmentOpnd;
19463+ IR::AutoReuseOpnd autoReuseHeadSegmentLengthOpnd;
19464+ IR::IndirOpnd* indirOpnd = IR::IndirOpnd::New(src2RegOpnd, Js::JavascriptArray::GetOffsetOfHead(), TyMachPtr, this->m_func);
19465+ IR::RegOpnd* headSegmentOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
19466+ autoReuseHeadSegmentOpnd.Initialize(headSegmentOpnd, m_func);
19467+ InsertMove(headSegmentOpnd, indirOpnd, instr);
19468+
19469+ IR::Opnd* headSegmentLengthOpnd = IR::IndirOpnd::New(headSegmentOpnd, Js::SparseArraySegmentBase::GetOffsetOfLength(), TyUint32, m_func);
19470+ autoReuseHeadSegmentLengthOpnd.Initialize(headSegmentLengthOpnd, m_func);
19471+
19472+ InsertCompareBranch(
19473+ src1Untagged,
19474+ headSegmentLengthOpnd,
19475+ Js::OpCode::BrGe_A,
19476+ doneFalseLabel,
19477+ instr);
19478+
19479+ InsertCompareBranch(
19480+ src1Untagged,
19481+ IR::IntConstOpnd::New(0, src1Untagged->GetType(), this->m_func),
19482+ Js::OpCode::BrLt_A,
19483+ doneFalseLabel,
19484+ instr);
19485+
19486+ InsertMove(instr->GetDst(), LoadLibraryValueOpnd(instr, LibraryValue::ValueTrue), instr);
19487+ InsertBranch(Js::OpCode::Br, doneLabel, instr);
19488+
19489+ instr->InsertBefore(doneFalseLabel);
19490+ InsertMove(instr->GetDst(), LoadLibraryValueOpnd(instr, LibraryValue::ValueFalse), instr);
19491+ InsertBranch(Js::OpCode::Br, doneLabel, instr);
19492+ instr->InsertBefore(helperLabel);
19493+
19494+ instr->InsertAfter(doneLabel);
19495+ }
19496+
1940119497void Lowerer::GenerateTruncWithCheck(IR::Instr* instr)
1940219498{
1940319499
0 commit comments