diff --git a/lib/Backend/GlobOpt.cpp b/lib/Backend/GlobOpt.cpp index 57d506b57ef..91e0887feb4 100644 --- a/lib/Backend/GlobOpt.cpp +++ b/lib/Backend/GlobOpt.cpp @@ -14635,6 +14635,7 @@ GlobOpt::OptIsInvariant(IR::Opnd *src, BasicBlock *block, Loop *loop, Value *src sym = src->AsSymOpnd()->m_sym; if (src->AsSymOpnd()->IsPropertySymOpnd()) { +#if 0 if (src->AsSymOpnd()->AsPropertySymOpnd()->IsTypeChecked()) { // We do not handle hoisting these yet. We might be hoisting this across the instr with the type check protecting this one. @@ -14642,6 +14643,7 @@ GlobOpt::OptIsInvariant(IR::Opnd *src, BasicBlock *block, Loop *loop, Value *src // For CheckFixedFld, there is no benefit hoisting these if they don't have a type check as they won't generate code. return false; } +#endif } break; @@ -14654,6 +14656,7 @@ GlobOpt::OptIsInvariant(IR::Opnd *src, BasicBlock *block, Loop *loop, Value *src default: return false; } + return OptIsInvariant(sym, block, loop, srcVal, isNotTypeSpecConv, allowNonPrimitives); } @@ -14868,18 +14871,26 @@ GlobOpt::OptIsInvariant( } break; case Js::OpCode::CheckObjType: + case Js::OpCode::CheckFixedFld: // Bug 11712101: If the operand is a field, ensure that its containing object type is invariant // before hoisting -- that is, don't hoist a CheckObjType over a DeleteFld on that object. // (CheckObjType only checks the operand and its immediate parent, so we don't need to go // any farther up the object graph.) Assert(instr->GetSrc1()); - PropertySym *propertySym = instr->GetSrc1()->AsPropertySymOpnd()->GetPropertySym(); - if (propertySym->HasObjectTypeSym()) { - StackSym *objectTypeSym = propertySym->GetObjectTypeSym(); + IR::PropertySymOpnd *propertySymOpnd = instr->GetSrc1()->AsPropertySymOpnd(); + if (propertySymOpnd->IsTypeCheckSeqCandidate() && !propertySymOpnd->IsTypeChecked()) { + StackSym *objectTypeSym = propertySymOpnd->GetObjectTypeSym(); if (!this->OptIsInvariant(objectTypeSym, block, loop, this->CurrentBlockData()->FindValue(objectTypeSym), true, true)) { return false; } } + if (propertySymOpnd->IsAuxSlotPtrSymAvailable()) + { + StackSym* auxSlotPtrSym = propertySymOpnd->GetAuxSlotPtrSym(); + if (!this->OptIsInvariant(auxSlotPtrSym, block, loop, this->CurrentBlockData()->FindValue(auxSlotPtrSym), true, true)) { + return false; + } + } break; } @@ -15035,6 +15046,22 @@ GlobOpt::OptHoistInvariant( src1->AsRegOpnd()->m_isTempLastUse = false; } + if (src1->IsSymOpnd() && src1->AsSymOpnd()->IsPropertySymOpnd()) + { + IR::PropertySymOpnd* opnd = src1->AsSymOpnd()->AsPropertySymOpnd(); + FinishOptPropOp(instr, opnd, loop->landingPad); + + if (opnd->IsAuxSlotPtrSymAvailable()) + { + block->globOptData.liveFields->Clear(opnd->GetAuxSlotPtrSym()->m_id); + } + + if (opnd->IsTypeCheckSeqCandidate() && !opnd->IsTypeChecked()) + { + block->globOptData.liveFields->Clear(opnd->GetObjectTypeSym()->m_id); + } + } + IR::Opnd* src2 = instr->GetSrc2(); if (src2) { diff --git a/lib/Backend/GlobOptExpr.cpp b/lib/Backend/GlobOptExpr.cpp index 14c6ac03e25..1f055608ba9 100644 --- a/lib/Backend/GlobOptExpr.cpp +++ b/lib/Backend/GlobOptExpr.cpp @@ -640,7 +640,7 @@ GlobOpt::CSEOptimize(BasicBlock *block, IR::Instr * *const instrRef, Value **pSr Assert(instr->m_opcode == Js::OpCode::CheckFixedFld); IR::PropertySymOpnd *propOpnd = src1->AsSymOpnd()->AsPropertySymOpnd(); - if (!propOpnd->IsTypeChecked() && !propOpnd->IsRootObjectNonConfigurableFieldLoad()) + if ((!propOpnd->IsTypeChecked() && !propOpnd->IsRootObjectNonConfigurableFieldLoad())) { // Require m_CachedTypeChecked for 2 reasons: // - We may be relying on this instruction to do a type check for a downstream reference. @@ -696,9 +696,9 @@ GlobOpt::CSEOptimize(BasicBlock *block, IR::Instr * *const instrRef, Value **pSr } } + IR::Opnd* src1 = instr->GetSrc1(); if (needsBailOnImplicitCall) { - IR::Opnd *src1 = instr->GetSrc1(); if (src1) { if (src1->IsRegOpnd()) @@ -791,6 +791,16 @@ GlobOpt::CSEOptimize(BasicBlock *block, IR::Instr * *const instrRef, Value **pSr cseOpnd->SetValueType(valueInfo->Type()); } + if (src1 && src1->IsSymOpnd() && src1->AsSymOpnd()->IsPropertySymOpnd()) + { + Assert(instr->m_opcode == Js::OpCode::CheckFixedFld); + IR::PropertySymOpnd* propOpnd = src1->AsSymOpnd()->AsPropertySymOpnd(); + if (propOpnd->UsesAuxSlot() && !propOpnd->IsAuxSlotPtrSymAvailable()) + { + block->globOptData.liveFields->Clear(propOpnd->GetAuxSlotPtrSym()->m_id); + } + } + *pSrc1Val = val; { diff --git a/test/fieldopts/auxslot_bug.js b/test/fieldopts/auxslot_bug.js new file mode 100644 index 00000000000..831048a5a93 --- /dev/null +++ b/test/fieldopts/auxslot_bug.js @@ -0,0 +1,27 @@ +var obj0 = {}; +var obj1 = {}; +var arrObj0 = {}; +var func1 = function () { + function func5() { + } + obj6 = func5(); + while (obj1) { + obj6 = obj6; + if (ary.shift() >> new EvalError()) { + length; + } else { + break; + } + } +}; +var func3 = function () { + func1(); +}; +obj0.method0 = func3; +obj0.method1 = obj0.method0; +arrObj0.method0 = obj0.method1; +var ary = Array(); + +for (var i = 0; i < 200; i++) arrObj0.method0(); + +print("Passed"); \ No newline at end of file diff --git a/test/fieldopts/rlexe.xml b/test/fieldopts/rlexe.xml index 6e4023368ba..ac680f34f6f 100644 --- a/test/fieldopts/rlexe.xml +++ b/test/fieldopts/rlexe.xml @@ -1,5 +1,10 @@ + + + auxslot_bug.js + + depolymorph01.js