Skip to content

Commit ebb5998

Browse files
committed
Use PIC for PropertyString
1 parent 958cf06 commit ebb5998

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+927
-768
lines changed

lib/Backend/Lower.cpp

Lines changed: 141 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15123,14 +15123,14 @@ Lowerer::GenerateFastElemICommon(
1512315123
IR::RegOpnd *indexOpnd = indirOpnd->GetIndexOpnd();
1512415124
if (indexOpnd)
1512515125
{
15126-
if (indexOpnd->GetValueType().IsString())
15126+
if (indexOpnd->GetValueType().IsLikelyString())
1512715127
{
1512815128
if (!baseOpnd->GetValueType().IsLikelyOptimizedTypedArray())
1512915129
{
1513015130
// If profile data says that it's a typed array - do not generate the property string fast path as the src. could be a temp and that would cause a bug.
1513115131
*pIsTypedArrayElement = false;
1513215132
*pIsStringIndex = true;
15133-
return m_lowererMD.GenerateFastElemIStringIndexCommon(instr, isStore, indirOpnd, labelHelper);
15133+
return GenerateFastElemIStringIndexCommon(instr, isStore, indirOpnd, labelHelper);
1513415134
}
1513515135
else
1513615136
{
@@ -15157,6 +15157,110 @@ Lowerer::GenerateFastElemICommon(
1515715157
indirOpndOverflowed);
1515815158
}
1515915159

15160+
void
15161+
Lowerer::GenerateDynamicLoadPolymorphicInlineCacheSlot(IR::Instr * instrInsert, IR::RegOpnd * inlineCacheOpnd, IR::Opnd * objectTypeOpnd)
15162+
{
15163+
// Generates:
15164+
// MOV opndOffset, objectTypeOpnd
15165+
// SHR opndOffset, PolymorphicInlineCacheShift
15166+
// MOVZX cacheIndexOpnd, inlineCacheOpnd->size
15167+
// DEC cacheIndexOpnd
15168+
// AND opndOffset, cacheIndexOpnd
15169+
// SHL opndOffset, Math::Log2(sizeof(Js::InlineCache))
15170+
// MOV inlineCacheOpnd, inlineCacheOpnd->inlineCaches
15171+
// LEA inlineCacheOpnd, [inlineCacheOpnd + opndOffset]
15172+
15173+
IntConstType rightShiftAmount = PolymorphicInlineCacheShift;
15174+
IntConstType leftShiftAmount = Math::Log2(sizeof(Js::InlineCache));
15175+
Assert(rightShiftAmount > leftShiftAmount);
15176+
IR::RegOpnd * opndOffset = IR::RegOpnd::New(TyMachPtr, m_func);
15177+
InsertShift(Js::OpCode::ShrU_A, false, opndOffset, objectTypeOpnd, IR::IntConstOpnd::New(rightShiftAmount, TyUint8, m_func, true), instrInsert);
15178+
15179+
IR::RegOpnd * cacheIndexOpnd = IR::RegOpnd::New(TyMachPtr, m_func);
15180+
InsertMove(cacheIndexOpnd, IR::IndirOpnd::New(inlineCacheOpnd, Js::PolymorphicInlineCache::GetOffsetOfSize(), TyUint16, m_func), instrInsert);
15181+
InsertSub(false, cacheIndexOpnd, cacheIndexOpnd, IR::IntConstOpnd::New(1, TyMachPtr, m_func), instrInsert);
15182+
InsertAnd(opndOffset, opndOffset, cacheIndexOpnd, instrInsert);
15183+
InsertShift(Js::OpCode::Shl_A, false, opndOffset, opndOffset, IR::IntConstOpnd::New(leftShiftAmount, TyUint8, m_func), instrInsert);
15184+
InsertMove(inlineCacheOpnd, IR::IndirOpnd::New(inlineCacheOpnd, Js::PolymorphicInlineCache::GetOffsetOfInlineCaches(), TyMachPtr, m_func), instrInsert);
15185+
InsertLea(inlineCacheOpnd, IR::IndirOpnd::New(inlineCacheOpnd, opndOffset, TyMachPtr, m_func), instrInsert);
15186+
}
15187+
15188+
IR::IndirOpnd *
15189+
Lowerer::GenerateFastElemIStringIndexCommon(IR::Instr * instrInsert, bool isStore, IR::IndirOpnd * indirOpnd, IR::LabelInstr * labelHelper)
15190+
{
15191+
IR::RegOpnd *indexOpnd = indirOpnd->GetIndexOpnd();
15192+
IR::RegOpnd *baseOpnd = indirOpnd->GetBaseOpnd();
15193+
Assert(baseOpnd != nullptr);
15194+
Assert(indexOpnd->GetValueType().IsLikelyString());
15195+
15196+
// Generates:
15197+
// StringTest(indexOpnd, $helper) ; verify index is string type
15198+
// CMP indexOpnd, PropertyString::`vtable' ; verify index is property string
15199+
// JNE $helper
15200+
// MOV inlineCacheOpnd, index->inlineCache
15201+
// GenerateObjectTest(baseOpnd, $helper) ; verify base is an object
15202+
// MOV objectTypeOpnd, baseOpnd->type
15203+
// GenerateDynamicLoadPolymorphicInlineCacheSlot(inlineCacheOpnd, objectTypeOpnd) ; loads inline cache for given type
15204+
// LocalInlineCacheCheck(objectTypeOpnd, inlineCacheOpnd, $notInlineSlots) ; check for type in local inline slots, jump to $notInlineSlotsLabel on failure
15205+
// MOV opndSlotArray, baseOpnd
15206+
// JMP slotArrayLoadedLabel
15207+
// $notInlineSlotsLabel
15208+
// opndTaggedType = GenerateLoadTaggedType(objectTypeOpnd) ; load objectTypeOpnd with InlineCacheAuxSlotTypeTag into opndTaggedType
15209+
// LocalInlineCacheCheck(opndTaggedType, inlineCacheOpnd, $helper) ; check for type in local aux slots, jump to $helper on failure
15210+
// MOV opndSlotArray, baseOpnd->auxSlots ; load the aux slot array
15211+
// $slotArrayLoadedLabel
15212+
// MOV opndSlotIndex, inlineCacheOpnd->u.local.slotIndex ; load the cached slot offset or index
15213+
// INC indexOpnd->hitRate
15214+
15215+
GenerateStringTest(indexOpnd, instrInsert, labelHelper);
15216+
15217+
InsertCompareBranch(
15218+
IR::IndirOpnd::New(indexOpnd, 0, TyMachPtr, m_func),
15219+
LoadVTableValueOpnd(instrInsert, VTableValue::VtablePropertyString),
15220+
Js::OpCode::BrNeq_A, labelHelper, instrInsert);
15221+
15222+
m_lowererMD.GenerateObjectTest(baseOpnd, instrInsert, labelHelper);
15223+
15224+
IR::RegOpnd * objectTypeOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
15225+
InsertMove(objectTypeOpnd, IR::IndirOpnd::New(baseOpnd, Js::RecyclableObject::GetOffsetOfType(), TyMachPtr, m_func), instrInsert);
15226+
15227+
const uint32 inlineCacheOffset = isStore ? Js::PropertyString::GetOffsetOfStElemInlineCache() : Js::PropertyString::GetOffsetOfLdElemInlineCache();
15228+
15229+
IR::RegOpnd * inlineCacheOpnd = IR::RegOpnd::New(TyMachPtr, m_func);
15230+
InsertMove(inlineCacheOpnd, IR::IndirOpnd::New(indexOpnd, inlineCacheOffset, TyMachPtr, m_func), instrInsert);
15231+
15232+
GenerateDynamicLoadPolymorphicInlineCacheSlot(instrInsert, inlineCacheOpnd, objectTypeOpnd);
15233+
15234+
IR::LabelInstr * notInlineSlotsLabel = IR::LabelInstr::New(Js::OpCode::Label, m_func);
15235+
IR::LabelInstr * slotArrayLoadedLabel = IR::LabelInstr::New(Js::OpCode::Label, m_func);
15236+
15237+
m_lowererMD.GenerateLocalInlineCacheCheck(instrInsert, objectTypeOpnd, inlineCacheOpnd, notInlineSlotsLabel);
15238+
15239+
IR::RegOpnd * opndSlotArray = IR::RegOpnd::New(TyMachReg, instrInsert->m_func);
15240+
InsertMove(opndSlotArray, baseOpnd, instrInsert);
15241+
InsertBranch(Js::OpCode::Br, slotArrayLoadedLabel, instrInsert);
15242+
15243+
instrInsert->InsertBefore(notInlineSlotsLabel);
15244+
IR::RegOpnd * opndTaggedType = IR::RegOpnd::New(TyMachReg, this->m_func);
15245+
m_lowererMD.GenerateLoadTaggedType(instrInsert, objectTypeOpnd, opndTaggedType);
15246+
m_lowererMD.GenerateLocalInlineCacheCheck(instrInsert, opndTaggedType, inlineCacheOpnd, labelHelper);
15247+
15248+
IR::IndirOpnd * opndIndir = IR::IndirOpnd::New(baseOpnd, Js::DynamicObject::GetOffsetOfAuxSlots(), TyMachReg, instrInsert->m_func);
15249+
InsertMove(opndSlotArray, opndIndir, instrInsert);
15250+
15251+
instrInsert->InsertBefore(slotArrayLoadedLabel);
15252+
15253+
IR::RegOpnd * opndSlotIndex = IR::RegOpnd::New(TyMachReg, instrInsert->m_func);
15254+
InsertMove(opndSlotIndex, IR::IndirOpnd::New(inlineCacheOpnd, (int32)offsetof(Js::InlineCache, u.local.slotIndex), TyUint16, instrInsert->m_func), instrInsert);
15255+
15256+
IR::IndirOpnd * hitRateOpnd = IR::IndirOpnd::New(indexOpnd, Js::PropertyString::GetOffsetOfHitRate(), TyInt32, m_func);
15257+
IR::IntConstOpnd * incOpnd = IR::IntConstOpnd::New(1, TyInt32, instrInsert->m_func);
15258+
InsertAdd(false, hitRateOpnd, hitRateOpnd, incOpnd, instrInsert);
15259+
15260+
// return [opndSlotArray + opndSlotIndex * PtrSize]
15261+
return IR::IndirOpnd::New(opndSlotArray, opndSlotIndex, m_lowererMD.GetDefaultIndirScale(), TyMachReg, instrInsert->m_func);
15262+
}
15263+
1516015264
IR::IndirOpnd *
1516115265
Lowerer::GenerateFastElemIIntIndexCommon(
1516215266
IR::Instr * instr,
@@ -17924,63 +18028,73 @@ Lowerer::GenerateFastInlineHasOwnProperty(IR::Instr * instr)
1792418028
return;
1792518029
}
1792618030

17927-
// fast path case where hasOwnProperty is being called using a property name loaded via a for-in loop
17928-
bool generateForInFastpath = argsOpnd[1]->GetValueType().IsString()
17929-
&& argsOpnd[1]->AsRegOpnd()->m_sym->m_isSingleDef
17930-
&& (argsOpnd[1]->AsRegOpnd()->m_sym->m_instrDef->m_opcode == Js::OpCode::BrOnEmpty
17931-
|| argsOpnd[1]->AsRegOpnd()->m_sym->m_instrDef->m_opcode == Js::OpCode::BrOnNotEmpty);
17932-
1793318031
IR::RegOpnd * thisObj = argsOpnd[0]->AsRegOpnd();
1793418032
IR::RegOpnd * propOpnd = argsOpnd[1]->AsRegOpnd();
1793518033

18034+
// fast path case where hasOwnProperty is being called using a property name loaded via a for-in loop
18035+
bool generateForInFastpath = propOpnd->GetValueType().IsString()
18036+
&& propOpnd->m_sym->m_isSingleDef
18037+
&& (propOpnd->m_sym->m_instrDef->m_opcode == Js::OpCode::BrOnEmpty
18038+
|| propOpnd->m_sym->m_instrDef->m_opcode == Js::OpCode::BrOnNotEmpty);
18039+
1793618040
IR::LabelInstr * doneLabel = InsertLabel(false, instr->m_next);
1793718041
IR::LabelInstr * labelHelper = InsertLabel(true, instr);
1793818042

17939-
IR::LabelInstr * cacheMissLabel = generateForInFastpath ? InsertLabel(true, labelHelper) : labelHelper;
18043+
IR::LabelInstr * cacheMissLabel = generateForInFastpath ? IR::LabelInstr::New(Js::OpCode::Label, m_func, true) : labelHelper;
1794018044

17941-
IR::Instr * insertInstr = cacheMissLabel;
18045+
IR::Instr * insertInstr = labelHelper;
1794218046

17943-
// TEST indexOpnd, AtomTag
18047+
// GenerateObjectTest(propOpnd, $labelHelper)
1794418048
// CMP indexOpnd, PropertyString::`vtable'
1794518049
// JNE $helper
17946-
// MOV propertyCacheOpnd, propOpnd->propCache
17947-
// TEST thisObj, AtomTag
17948-
// JNE $labelHelper
18050+
// GenerateObjectTest(thisObj, $labelHelper)
18051+
// MOV inlineCacheOpnd, propOpnd->lsElemInlineCache
1794918052
// MOV objectTypeOpnd, thisObj->type
17950-
// CMP propertyCacheOpnd->type, objectTypeOpnd
17951-
// JNE $cacheMissLabel
18053+
// GenerateDynamicLoadPolymorphicInlineCacheSlot(inlineCacheOpnd, objectTypeOpnd) ; loads inline cache for given type
18054+
// GenerateLocalInlineCacheCheck(objectTypeOpnd, inlineCacheOpnd, $notInlineSlotsLabel) ; check for type in inline slots, jump to $notInlineSlotsLabel on failure
18055+
// MOV dst, ValueTrue
18056+
// JMP $done
18057+
// $notInlineSlotsLabel:
18058+
// GenerateLoadTaggedType(objectTypeOpnd, opndTaggedType)
18059+
// GenerateLocalInlineCacheCheck(opndTaggedType, inlineCacheOpnd, $cacheMissLabel) ; check for type in aux slot, jump to $cacheMissLabel on failure
1795218060
// MOV dst, ValueTrue
1795318061
// JMP $done
1795418062

17955-
if (!propOpnd->IsNotTaggedValue())
17956-
{
17957-
m_lowererMD.GenerateObjectTest(propOpnd, insertInstr, labelHelper);
17958-
}
18063+
m_lowererMD.GenerateObjectTest(propOpnd, insertInstr, labelHelper);
1795918064

1796018065
InsertCompareBranch(IR::IndirOpnd::New(propOpnd, 0, TyMachPtr, m_func), LoadVTableValueOpnd(insertInstr, VTableValue::VtablePropertyString), Js::OpCode::BrNeq_A, labelHelper, insertInstr);
1796118066

17962-
IR::RegOpnd * propertyCacheOpnd = IR::RegOpnd::New(TyMachPtr, m_func);
17963-
InsertMove(propertyCacheOpnd, IR::IndirOpnd::New(propOpnd, Js::PropertyString::GetOffsetOfPropertyCache(), TyMachPtr, m_func), insertInstr);
18067+
m_lowererMD.GenerateObjectTest(thisObj, insertInstr, labelHelper);
1796418068

17965-
if (!thisObj->IsNotTaggedValue())
17966-
{
17967-
m_lowererMD.GenerateObjectTest(thisObj, insertInstr, labelHelper);
17968-
}
18069+
IR::RegOpnd * inlineCacheOpnd = IR::RegOpnd::New(TyMachPtr, m_func);
18070+
InsertMove(inlineCacheOpnd, IR::IndirOpnd::New(propOpnd, Js::PropertyString::GetOffsetOfLdElemInlineCache(), TyMachPtr, m_func), insertInstr);
1796918071

1797018072
IR::RegOpnd * objectTypeOpnd = IR::RegOpnd::New(TyMachPtr, m_func);
1797118073
InsertMove(objectTypeOpnd, IR::IndirOpnd::New(thisObj, Js::RecyclableObject::GetOffsetOfType(), TyMachPtr, m_func), insertInstr);
1797218074

17973-
InsertCompareBranch(IR::IndirOpnd::New(propertyCacheOpnd, (int32)offsetof(Js::PropertyCache, type), TyMachPtr, m_func), objectTypeOpnd, Js::OpCode::BrNeq_A, cacheMissLabel, insertInstr);
18075+
GenerateDynamicLoadPolymorphicInlineCacheSlot(insertInstr, inlineCacheOpnd, objectTypeOpnd);
18076+
18077+
IR::LabelInstr * notInlineSlotsLabel = IR::LabelInstr::New(Js::OpCode::Label, m_func);
18078+
m_lowererMD.GenerateLocalInlineCacheCheck(insertInstr, objectTypeOpnd, inlineCacheOpnd, notInlineSlotsLabel);
1797418079

1797518080
InsertMove(instr->GetDst(), LoadLibraryValueOpnd(instr, LibraryValue::ValueTrue), insertInstr);
1797618081
InsertBranch(Js::OpCode::Br, doneLabel, insertInstr);
1797718082

18083+
insertInstr->InsertBefore(notInlineSlotsLabel);
18084+
IR::RegOpnd * opndTaggedType = IR::RegOpnd::New(TyMachReg, m_func);
18085+
m_lowererMD.GenerateLoadTaggedType(insertInstr, objectTypeOpnd, opndTaggedType);
18086+
m_lowererMD.GenerateLocalInlineCacheCheck(insertInstr, opndTaggedType, inlineCacheOpnd, cacheMissLabel);
18087+
InsertMove(instr->GetDst(), LoadLibraryValueOpnd(instr, LibraryValue::ValueTrue), insertInstr);
18088+
InsertBranch(Js::OpCode::Br, doneLabel, insertInstr);
18089+
1797818090
if (!generateForInFastpath)
1797918091
{
1798018092
RelocateCallDirectToHelperPath(tmpInstr, labelHelper);
1798118093
return;
1798218094
}
1798318095

18096+
insertInstr->InsertBefore(cacheMissLabel);
18097+
1798418098
// CMP forInEnumeratorOpnd->canUseJitFastPath, 0
1798518099
// JEQ $labelHelper
1798618100
// MOV cachedDataTypeOpnd, forInEnumeratorOpnd->enumeratorInitialType

lib/Backend/Lower.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ class Lowerer
289289
bool GenerateFastBrBool(IR::BranchInstr *const instr);
290290
bool GenerateFastStringCheck(IR::Instr *instr, IR::RegOpnd *srcReg1, IR::RegOpnd *srcReg2, bool isEqual, bool isStrict, IR::LabelInstr *labelHelper, IR::LabelInstr *labelBranchSuccess, IR::LabelInstr *labelBranchFail);
291291
bool GenerateFastBrOrCmString(IR::Instr* instr);
292+
void GenerateDynamicLoadPolymorphicInlineCacheSlot(IR::Instr * instrInsert, IR::RegOpnd * inlineCacheOpnd, IR::Opnd * objectTypeOpnd);
292293
static IR::Instr *LoadFloatFromNonReg(IR::Opnd * opndOrig, IR::Opnd * regOpnd, IR::Instr * instrInsert);
293294
void LoadInt32FromUntaggedVar(IR::Instr *const instrLoad);
294295
bool GetValueFromIndirOpnd(IR::IndirOpnd *indirOpnd, IR::Opnd **pValueOpnd, IntConstType *pValue);
@@ -424,6 +425,7 @@ class Lowerer
424425
IR::LabelInstr *bailOutLabelInstr = nullptr,
425426
bool * indirOpndOverflowed = nullptr);
426427

428+
IR::IndirOpnd * GenerateFastElemIStringIndexCommon(IR::Instr * ldElem, bool isStore, IR::IndirOpnd * indirOpnd, IR::LabelInstr * labelHelper);
427429
bool GenerateFastLdElemI(IR::Instr *& ldElem, bool *instrIsInHelperBlockRef);
428430
bool GenerateFastStElemI(IR::Instr *& StElem, bool *instrIsInHelperBlockRef);
429431
bool GenerateFastLdLen(IR::Instr *ldLen, bool *instrIsInHelperBlockRef);

0 commit comments

Comments
 (0)