Skip to content

Commit 5fd7a32

Browse files
author
Meghana Gupta
committed
[MERGE chakra-core#4803 @meg-gupta] Enable fastpath for in operator
Merge pull request chakra-core#4803 from meg-gupta:isinfast This was originally developed by Etienne Baudoux for javascript implementation of indexOf. Merging this now with bug fix.
2 parents 549391b + 52025a5 commit 5fd7a32

2 files changed

Lines changed: 97 additions & 0 deletions

File tree

lib/Backend/Lower.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
1940119497
void Lowerer::GenerateTruncWithCheck(IR::Instr* instr)
1940219498
{
1940319499

lib/Backend/Lower.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ class Lowerer
156156
bool GenerateLdThisCheck(IR::Instr * instr);
157157
bool GenerateLdThisStrict(IR::Instr * instr);
158158
bool GenerateFastIsInst(IR::Instr * instr);
159+
void GenerateFastInlineIsIn(IR::Instr * instr);
159160

160161
void GenerateProtoLdFldFromFlagInlineCache(
161162
IR::Instr * insertBeforeInstr,

0 commit comments

Comments
 (0)