|
|
@@ -6067,163 +6067,6 @@ LowererMD::EnsureEHEpilogLabel()
|
|
|
return labelInstr;
|
|
|
}
|
|
|
|
|
|
-// given object instanceof function, functionReg is a register with function,
|
|
|
-// objectReg is a register with instance and inlineCache is an InstIsInlineCache.
|
|
|
-// We want to generate:
|
|
|
-//
|
|
|
-// fallback on helper (will patch the inline cache) if function does not match the cache
|
|
|
-// LDIMM dst, Js::false
|
|
|
-// LDR cache, [&(inlineCache->function)]
|
|
|
-// CMP functionReg, cache
|
|
|
-// BNE helper
|
|
|
-//
|
|
|
-// fallback if object is a tagged int
|
|
|
-// TST objectReg, Js::AtomTag
|
|
|
-// BNE done
|
|
|
-//
|
|
|
-// return false if object is a primitive
|
|
|
-// LDR typeReg, objectSrc + offsetof(RecyclableObject::type)
|
|
|
-// LDR typeID, [typeReg + offsetof(Type::typeid)]
|
|
|
-// CMP typeID, TypeIds_LastJavascriptPrimitiveType
|
|
|
-// BLE done
|
|
|
-//
|
|
|
-// fallback if object's type is not the cached type
|
|
|
-// CMP typeReg, [&(inlineCache->type]
|
|
|
-// BNE helper
|
|
|
-//
|
|
|
-// use the cached result and fallthrough
|
|
|
-// LDR dst, [&(inlineCache->result)]
|
|
|
-// B done
|
|
|
-//
|
|
|
-// $helper
|
|
|
-// $done
|
|
|
-bool
|
|
|
-LowererMD::GenerateFastIsInst(IR::Instr * instr)
|
|
|
-{
|
|
|
- IR::LabelInstr * helper = IR::LabelInstr::New(Js::OpCode::Label, m_func, true);
|
|
|
- IR::LabelInstr * done = IR::LabelInstr::New(Js::OpCode::Label, m_func);
|
|
|
- IR::RegOpnd * typeReg = IR::RegOpnd::New(TyMachReg, this->m_func);
|
|
|
- IR::Opnd * objectSrc;
|
|
|
- IR::RegOpnd * objectReg;
|
|
|
- IR::Opnd * functionSrc;
|
|
|
- IR::RegOpnd * functionReg;
|
|
|
- intptr_t inlineCache;
|
|
|
- IR::Instr * instrArg;
|
|
|
-
|
|
|
- // We are going to use the extra ArgOut_A instructions to lower the helper call later,
|
|
|
- // so we leave them alone here and clean them up then.
|
|
|
- inlineCache = instr->m_func->GetJITFunctionBody()->GetIsInstInlineCache(uint(instr->GetSrc1()->AsIntConstOpnd()->GetValue()));
|
|
|
- Assert(instr->GetSrc2()->AsRegOpnd()->m_sym->m_isSingleDef);
|
|
|
- instrArg = instr->GetSrc2()->AsRegOpnd()->m_sym->m_instrDef;
|
|
|
-
|
|
|
- objectSrc = instrArg->GetSrc1();
|
|
|
- Assert(instrArg->GetSrc2()->AsRegOpnd()->m_sym->m_isSingleDef);
|
|
|
- instrArg = instrArg->GetSrc2()->AsRegOpnd()->m_sym->m_instrDef;
|
|
|
-
|
|
|
- functionSrc = instrArg->GetSrc1();
|
|
|
- Assert(instrArg->GetSrc2() == nullptr);
|
|
|
-
|
|
|
- IR::Opnd* opndDst = instr->GetDst();
|
|
|
- if (!opndDst->IsRegOpnd())
|
|
|
- {
|
|
|
- opndDst = IR::RegOpnd::New(opndDst->GetType(), this->m_func);
|
|
|
- }
|
|
|
-
|
|
|
- // LDR dst, Js::false
|
|
|
- instr->InsertBefore(IR::Instr::New(Js::OpCode::LDR, opndDst,
|
|
|
- m_lowerer->LoadLibraryValueOpnd(instr, LibraryValue::ValueFalse), m_func));
|
|
|
-
|
|
|
- if (functionSrc->IsRegOpnd())
|
|
|
- {
|
|
|
- functionReg = functionSrc->AsRegOpnd();
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- functionReg = IR::RegOpnd::New(TyMachReg, this->m_func);
|
|
|
- Lowerer::InsertMove(functionReg, functionSrc, instr);
|
|
|
- }
|
|
|
-
|
|
|
- // CMP functionReg, [&(inlineCache->function)]
|
|
|
- {
|
|
|
- IR::Instr * cmp = IR::Instr::New(Js::OpCode::CMP, m_func);
|
|
|
- cmp->SetSrc1(functionReg);
|
|
|
- cmp->SetSrc2(IR::MemRefOpnd::New(inlineCache + Js::IsInstInlineCache::OffsetOfFunction(), TyMachReg, m_func,
|
|
|
- IR::AddrOpndKindDynamicIsInstInlineCacheFunctionRef));
|
|
|
- instr->InsertBefore(cmp);
|
|
|
- LegalizeMD::LegalizeInstr(cmp, false);
|
|
|
- }
|
|
|
-
|
|
|
- // BNE helper
|
|
|
- instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::BNE, helper, m_func));
|
|
|
-
|
|
|
- if (objectSrc->IsRegOpnd())
|
|
|
- {
|
|
|
- objectReg = objectSrc->AsRegOpnd();
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- objectReg = IR::RegOpnd::New(TyMachReg, this->m_func);
|
|
|
- Lowerer::InsertMove(objectReg, objectSrc, instr);
|
|
|
- }
|
|
|
-
|
|
|
- // TST objectReg, Js::AtomTag
|
|
|
- // BNE done
|
|
|
- if (!objectReg->m_sym->m_isNotInt)
|
|
|
- {
|
|
|
- GenerateObjectTest(objectReg, instr, done);
|
|
|
- }
|
|
|
-
|
|
|
- // LDR typeReg, objectSrc + offsetof(RecyclableObject::type)
|
|
|
- instr->InsertBefore(IR::Instr::New(Js::OpCode::LDR, typeReg,
|
|
|
- IR::IndirOpnd::New(objectReg, Js::RecyclableObject::GetOffsetOfType(), TyMachReg, m_func),
|
|
|
- m_func));
|
|
|
-
|
|
|
- // CMP [typeReg + offsetof(Type::typeid)], TypeIds_LastJavascriptPrimitiveType
|
|
|
- {
|
|
|
- IR::Instr * cmp = IR::Instr::New(Js::OpCode::CMP, m_func);
|
|
|
- cmp->SetSrc1(IR::IndirOpnd::New(typeReg, Js::Type::GetOffsetOfTypeId(), TyInt32, m_func));
|
|
|
- cmp->SetSrc2(IR::IntConstOpnd::New(Js::TypeId::TypeIds_LastJavascriptPrimitiveType, TyInt32, m_func));
|
|
|
- instr->InsertBefore(cmp);
|
|
|
- LegalizeMD::LegalizeInstr(cmp, false);
|
|
|
- }
|
|
|
-
|
|
|
- // BLE done
|
|
|
- instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::BLE, done, m_func));
|
|
|
-
|
|
|
- // CMP typeReg, [&(inlineCache->type]
|
|
|
- {
|
|
|
- IR::Instr * cmp = IR::Instr::New(Js::OpCode::CMP, m_func);
|
|
|
- cmp->SetSrc1(typeReg);
|
|
|
- cmp->SetSrc2(IR::MemRefOpnd::New(inlineCache + Js::IsInstInlineCache::OffsetOfType(), TyMachReg, m_func));
|
|
|
- instr->InsertBefore(cmp);
|
|
|
- LegalizeMD::LegalizeInstr(cmp, false);
|
|
|
- }
|
|
|
-
|
|
|
- // BNE helper
|
|
|
- instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::BNE, helper, m_func));
|
|
|
-
|
|
|
- // LDR dst, [&(inlineCache->result)]
|
|
|
- IR::Instr *result = IR::Instr::New(Js::OpCode::LDR, opndDst,
|
|
|
- IR::MemRefOpnd::New(inlineCache + Js::IsInstInlineCache::OffsetOfResult(), TyMachReg, m_func), m_func);
|
|
|
- instr->InsertBefore(result);
|
|
|
- LegalizeMD::LegalizeInstr(result, false);
|
|
|
-
|
|
|
- if (opndDst != instr->GetDst())
|
|
|
- {
|
|
|
- Lowerer::InsertMove(instr->GetDst(), opndDst, instr);
|
|
|
- }
|
|
|
-
|
|
|
- // B done
|
|
|
- instr->InsertBefore(IR::BranchInstr::New(Js::OpCode::B, done, m_func));
|
|
|
-
|
|
|
- // LABEL helper
|
|
|
- instr->InsertBefore(helper);
|
|
|
-
|
|
|
- instr->InsertAfter(done);
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
// Helper method: inserts legalized assign for given srcOpnd into RegD0 in front of given instr in the following way:
|
|
|
// dstReg = InsertMove srcOpnd
|
|
|
// Used to put args of inline built-in call into RegD0 and RegD1 before we call actual CRT function.
|