Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ChakraCore servicing update for August, 2019 #6243

Merged
merged 8 commits into from
Aug 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Build/NuGet/.pack-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.11.11
1.11.12
12 changes: 6 additions & 6 deletions lib/Backend/BackwardPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
BackwardPass::BackwardPass(Func * func, GlobOpt * globOpt, Js::Phase tag)
: func(func), globOpt(globOpt), tag(tag), currentPrePassLoop(nullptr), tempAlloc(nullptr),
preOpBailOutInstrToProcess(nullptr),
considerSymAsRealUseInNoImplicitCallUses(nullptr),
isCollectionPass(false), currentRegion(nullptr),
collectionPassSubPhase(CollectionPassSubPhase::None),
isLoopPrepass(false)
Expand Down Expand Up @@ -412,6 +411,8 @@ BackwardPass::Optimize()
candidateSymsRequiredToBeInt = &localCandidateSymsRequiredToBeInt;
BVSparse<JitArenaAllocator> localCandidateSymsRequiredToBeLossyInt(tempAlloc);
candidateSymsRequiredToBeLossyInt = &localCandidateSymsRequiredToBeLossyInt;
BVSparse<JitArenaAllocator> localConsiderSymsAsRealUsesInNoImplicitCallUses(tempAlloc);
considerSymsAsRealUsesInNoImplicitCallUses = &localConsiderSymsAsRealUsesInNoImplicitCallUses;
intOverflowCurrentlyMattersInRange = true;

FloatSymEquivalenceMap localFloatSymEquivalenceMap(tempAlloc);
Expand Down Expand Up @@ -3755,7 +3756,7 @@ BackwardPass::ProcessBlock(BasicBlock * block)
block->loop->regAlloc.liveOnBackEdgeSyms = block->upwardExposedUses->CopyNew(this->func->m_alloc);
}

Assert(!considerSymAsRealUseInNoImplicitCallUses);
Assert(considerSymsAsRealUsesInNoImplicitCallUses->IsEmpty());

#if DBG_DUMP
TraceBlockUses(block, false);
Expand Down Expand Up @@ -4228,9 +4229,8 @@ BackwardPass::ProcessNoImplicitCallUses(IR::Instr *const instr)
{
IR::RegOpnd *const regSrc = src->AsRegOpnd();
sym = regSrc->m_sym;
if(considerSymAsRealUseInNoImplicitCallUses && considerSymAsRealUseInNoImplicitCallUses == sym)
if(considerSymsAsRealUsesInNoImplicitCallUses->TestAndClear(sym->m_id))
{
considerSymAsRealUseInNoImplicitCallUses = nullptr;
ProcessStackSymUse(sym->AsStackSym(), true);
}
if(regSrc->IsArrayRegOpnd())
Expand Down Expand Up @@ -4648,7 +4648,6 @@ BackwardPass::ProcessArrayRegOpndUse(IR::Instr *const instr, IR::ArrayRegOpnd *c
// ProcessNoImplicitCallUses automatically marks JS array reg opnds and their corresponding syms as live. A typed
// array's head segment length sym also needs to be marked as live at its use in the NoImplicitCallUses instruction,
// but it is just in a reg opnd. Flag the opnd to have the sym be marked as live when that instruction is processed.
Assert(!considerSymAsRealUseInNoImplicitCallUses);
IR::Opnd *const use =
FindNoImplicitCallUse(
instr,
Expand All @@ -4659,7 +4658,7 @@ BackwardPass::ProcessArrayRegOpndUse(IR::Instr *const instr, IR::ArrayRegOpnd *c
});
if(use)
{
considerSymAsRealUseInNoImplicitCallUses = arrayRegOpnd->HeadSegmentLengthSym();
considerSymsAsRealUsesInNoImplicitCallUses->Set(arrayRegOpnd->HeadSegmentLengthSym()->m_id);
}
}
}
Expand Down Expand Up @@ -6555,6 +6554,7 @@ BackwardPass::TrackIntUsage(IR::Instr *const instr)
case Js::OpCode::Coerce_Regex:
case Js::OpCode::Coerce_StrOrRegex:
case Js::OpCode::Conv_PrimStr:
case Js::OpCode::Conv_Prop:
// These instructions don't generate -0, and their behavior is the same for any src that is -0 or +0
SetNegativeZeroDoesNotMatterIfLastUse(instr->GetSrc1());
SetNegativeZeroDoesNotMatterIfLastUse(instr->GetSrc2());
Expand Down
2 changes: 1 addition & 1 deletion lib/Backend/BackwardPass.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ class BackwardPass
BVSparse<JitArenaAllocator> * intOverflowDoesNotMatterInRangeBySymId;
BVSparse<JitArenaAllocator> * candidateSymsRequiredToBeInt;
BVSparse<JitArenaAllocator> * candidateSymsRequiredToBeLossyInt;
StackSym * considerSymAsRealUseInNoImplicitCallUses;
BVSparse<JitArenaAllocator> * considerSymsAsRealUsesInNoImplicitCallUses;
bool intOverflowCurrentlyMattersInRange;
bool isCollectionPass;
enum class CollectionPassSubPhase
Expand Down
58 changes: 56 additions & 2 deletions lib/Backend/GlobOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2695,7 +2695,7 @@ GlobOpt::OptInstr(IR::Instr *&instr, bool* isInstrRemoved)
}

bool
GlobOpt::IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt) const
GlobOpt::IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt, bool *isSafeToTransferInPrepass /*=nullptr*/) const
{
if (opnd == nullptr)
{
Expand Down Expand Up @@ -2725,12 +2725,18 @@ GlobOpt::IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt) const
{
return true;
}

bool isSafeToTransfer = this->IsSafeToTransferInPrepass(opnd->m_sym, opndValueInfo);
if (isSafeToTransferInPrepass != nullptr)
{
*isSafeToTransferInPrepass = isSafeToTransfer;
}
if (this->prePassLoop->preservesNumberValue->Test(opnd->m_sym->m_id))
{
return false;
}

return !this->IsSafeToTransferInPrepass(opnd->m_sym, opndValueInfo);
return !isSafeToTransfer;
}

return true;
Expand Down Expand Up @@ -13143,6 +13149,37 @@ GlobOpt::OptArraySrc(IR::Instr ** const instrRef, Value ** src1Val, Value ** src
arraySrcOpt.Optimize();
}

void
GlobOpt::ProcessNoImplicitCallArrayUses(IR::RegOpnd * baseOpnd, IR::ArrayRegOpnd * baseArrayOpnd, IR::Instr * instr, bool isLikelyJsArray, bool useNoMissingValues)
{
if (isLikelyJsArray)
{
// Insert an instruction to indicate to the dead-store pass that implicit calls need to be kept disabled until this
// instruction. Operations other than LdElem, StElem and IsIn don't benefit much from arrays having no missing values,
// so no need to ensure that the array still has no missing values. For a particular array, if none of the accesses
// benefit much from the no-missing-values information, it may be beneficial to avoid checking for no missing
// values, especially in the case for a single array access, where the cost of the check could be relatively
// significant. An StElem has to do additional checks in the common path if the array may have missing values, and
// a StElem that operates on an array that has no missing values is more likely to keep the no-missing-values info
// on the array more precise, so it still benefits a little from the no-missing-values info.
this->CaptureNoImplicitCallUses(baseOpnd, isLikelyJsArray);
}
else if (baseArrayOpnd && baseArrayOpnd->HeadSegmentLengthSym())
{
// A typed array's array buffer may be transferred to a web worker as part of an implicit call, in which case the typed
// array's length is set to zero. Insert an instruction to indicate to the dead-store pass that implicit calls need to
// be disabled until this instruction.
IR::RegOpnd *const headSegmentLengthOpnd =
IR::RegOpnd::New(
baseArrayOpnd->HeadSegmentLengthSym(),
baseArrayOpnd->HeadSegmentLengthSym()->GetType(),
instr->m_func);

const IR::AutoReuseOpnd autoReuseHeadSegmentLengthOpnd(headSegmentLengthOpnd, instr->m_func);
this->CaptureNoImplicitCallUses(headSegmentLengthOpnd, false);
}
}

void
GlobOpt::CaptureNoImplicitCallUses(
IR::Opnd *opnd,
Expand Down Expand Up @@ -13464,6 +13501,7 @@ GlobOpt::CheckJsArrayKills(IR::Instr *const instr)
case IR::HelperArray_Splice:
case IR::HelperArray_Unshift:
case IR::HelperArray_Concat:
case IR::HelperArray_Slice:
kills.SetKillsArrayHeadSegments();
kills.SetKillsArrayHeadSegmentLengths();
break;
Expand Down Expand Up @@ -17031,11 +17069,27 @@ GlobOpt::EmitMemop(Loop * loop, LoopCount *loopCount, const MemOpEmitData* emitD
}
#endif

Assert(noImplicitCallUsesToInsert->Count() == 0);
bool isLikelyJsArray;
if (emitData->stElemInstr->GetDst()->IsIndirOpnd())
{
baseOpnd = emitData->stElemInstr->GetDst()->AsIndirOpnd()->GetBaseOpnd();
isLikelyJsArray = baseOpnd->GetValueType().IsLikelyArrayOrObjectWithArray();
ProcessNoImplicitCallArrayUses(baseOpnd, baseOpnd->IsArrayRegOpnd() ? baseOpnd->AsArrayRegOpnd() : nullptr, emitData->stElemInstr, isLikelyJsArray, true);
}
RemoveMemOpSrcInstr(memopInstr, emitData->stElemInstr, emitData->block);
if (!isMemset)
{
if (((MemCopyEmitData*)emitData)->ldElemInstr->GetSrc1()->IsIndirOpnd())
{
baseOpnd = ((MemCopyEmitData*)emitData)->ldElemInstr->GetSrc1()->AsIndirOpnd()->GetBaseOpnd();
isLikelyJsArray = baseOpnd->GetValueType().IsLikelyArrayOrObjectWithArray();
ProcessNoImplicitCallArrayUses(baseOpnd, baseOpnd->IsArrayRegOpnd() ? baseOpnd->AsArrayRegOpnd() : nullptr, emitData->stElemInstr, isLikelyJsArray, true);
}
RemoveMemOpSrcInstr(memopInstr, ((MemCopyEmitData*)emitData)->ldElemInstr, emitData->block);
}
InsertNoImplicitCallUses(memopInstr);
noImplicitCallUsesToInsert->Clear();
}

bool
Expand Down
3 changes: 2 additions & 1 deletion lib/Backend/GlobOpt.h
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,7 @@ class GlobOpt
private:
void CaptureNoImplicitCallUses(IR::Opnd *opnd, const bool usesNoMissingValuesInfo, IR::Instr *const includeCurrentInstr = nullptr);
void InsertNoImplicitCallUses(IR::Instr *const instr);
void ProcessNoImplicitCallArrayUses(IR::RegOpnd * baseOpnd, IR::ArrayRegOpnd * baseArrayOpnd, IR::Instr * instr, bool isLikelyJsArray, bool useNoMissingValues);
void PrepareLoopArrayCheckHoist();

public:
Expand Down Expand Up @@ -773,7 +774,7 @@ class GlobOpt
const bool lossy = false, const bool forceInvariantHoisting = false, IR::BailOutKind bailoutKind = IR::BailOutInvalid);
void HoistInvariantValueInfo(ValueInfo *const invariantValueInfoToHoist, Value *const valueToUpdate, BasicBlock *const targetBlock);
void OptHoistUpdateValueType(Loop* loop, IR::Instr* instr, IR::Opnd** srcOpndPtr, Value *const srcVal);
bool IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt) const;
bool IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt, bool *isSafeToTransferInPrepass = nullptr) const;

public:
static bool IsTypeSpecPhaseOff(Func const * func);
Expand Down
27 changes: 1 addition & 26 deletions lib/Backend/GlobOptArrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1929,32 +1929,7 @@ void GlobOpt::ArraySrcOpt::Optimize()
baseArrayOpnd = nullptr;
}

if (isLikelyJsArray)
{
// Insert an instruction to indicate to the dead-store pass that implicit calls need to be kept disabled until this
// instruction. Operations other than LdElem, StElem and IsIn don't benefit much from arrays having no missing values,
// so no need to ensure that the array still has no missing values. For a particular array, if none of the accesses
// benefit much from the no-missing-values information, it may be beneficial to avoid checking for no missing
// values, especially in the case for a single array access, where the cost of the check could be relatively
// significant. An StElem has to do additional checks in the common path if the array may have missing values, and
// a StElem that operates on an array that has no missing values is more likely to keep the no-missing-values info
// on the array more precise, so it still benefits a little from the no-missing-values info.
globOpt->CaptureNoImplicitCallUses(baseOpnd, isLoad || isStore || instr->m_opcode == Js::OpCode::IsIn);
}
else if (baseArrayOpnd && baseArrayOpnd->HeadSegmentLengthSym())
{
// A typed array's array buffer may be transferred to a web worker as part of an implicit call, in which case the typed
// array's length is set to zero. Insert an instruction to indicate to the dead-store pass that implicit calls need to
// be disabled until this instruction.
IR::RegOpnd *const headSegmentLengthOpnd =
IR::RegOpnd::New(
baseArrayOpnd->HeadSegmentLengthSym(),
baseArrayOpnd->HeadSegmentLengthSym()->GetType(),
instr->m_func);

const IR::AutoReuseOpnd autoReuseHeadSegmentLengthOpnd(headSegmentLengthOpnd, instr->m_func);
globOpt->CaptureNoImplicitCallUses(headSegmentLengthOpnd, false);
}
globOpt->ProcessNoImplicitCallArrayUses(baseOpnd, baseArrayOpnd, instr, isLikelyJsArray, isLoad || isStore || instr->m_opcode == Js::OpCode::IsIn);

const auto OnEliminated = [&](const Js::Phase phase, const char *const eliminatedLoad)
{
Expand Down
17 changes: 15 additions & 2 deletions lib/Backend/GlobOptFields.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,8 @@ GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, IR::Opnd * valueOpnd, BVSparse
// - We check the type specialization status for the sym as well. For the purpose of doing kills, we can assume that
// if type specialization happened, that fields don't need to be killed. Note that they may be killed in the next
// pass based on the value.
if (func->GetThisOrParentInlinerHasArguments() || this->IsNonNumericRegOpnd(indexOpnd, inGlobOpt))
bool isSafeToTransfer = true;
if (func->GetThisOrParentInlinerHasArguments() || this->IsNonNumericRegOpnd(indexOpnd, inGlobOpt, &isSafeToTransfer))
{
this->KillAllFields(bv); // This also kills all property type values, as the same bit-vector tracks those stack syms
SetAnyPropertyMayBeWrittenTo();
Expand All @@ -236,7 +237,7 @@ GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, IR::Opnd * valueOpnd, BVSparse
ValueInfo * indexValueInfo = indexValue ? indexValue->GetValueInfo() : nullptr;
int indexLowerBound = 0;

if (indirOpnd->GetOffset() < 0 || (indexOpnd && (!indexValueInfo || !indexValueInfo->TryGetIntConstantLowerBound(&indexLowerBound, false) || indexLowerBound < 0)))
if (!isSafeToTransfer || indirOpnd->GetOffset() < 0 || (indexOpnd && (!indexValueInfo || !indexValueInfo->TryGetIntConstantLowerBound(&indexLowerBound, false) || indexLowerBound < 0)))
{
// Write/delete to a non-integer numeric index can't alias a name on the RHS of a dot, but it change object layout
this->KillAllObjectTypes(bv);
Expand Down Expand Up @@ -517,6 +518,18 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
}
break;

case IR::JnHelperMethod::HelperArray_Slice:
case IR::JnHelperMethod::HelperArray_Concat:
if (inGlobOpt && this->objectTypeSyms)
{
if (this->currentBlock->globOptData.maybeWrittenTypeSyms == nullptr)
{
this->currentBlock->globOptData.maybeWrittenTypeSyms = JitAnew(this->alloc, BVSparse<JitArenaAllocator>, this->alloc);
}
this->currentBlock->globOptData.maybeWrittenTypeSyms->Or(this->objectTypeSyms);
}
break;

case IR::JnHelperMethod::HelperRegExp_Exec:
case IR::JnHelperMethod::HelperRegExp_ExecResultNotUsed:
case IR::JnHelperMethod::HelperRegExp_ExecResultUsed:
Expand Down
15 changes: 11 additions & 4 deletions lib/Backend/GlobOptIntBounds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1278,13 +1278,20 @@ GlobOpt::InvalidateInductionVariables(IR::Instr * instr)
}

// If this is an induction variable, then treat it the way the prepass would have if it had seen
// the assignment and the resulting change to the value number, and mark it as indeterminate.
// the assignment and the resulting change to the value number, and mark induction variables
// for the loop as indeterminate.
// We need to invalidate all induction variables for the loop, because we might have used the
// invalidated induction variable to calculate the loopCount, and this now invalid loopCount
// also impacts bound checks for secondary induction variables
for (Loop * loop = this->currentBlock->loop; loop; loop = loop->parent)
{
InductionVariable *iv = nullptr;
if (loop->inductionVariables && loop->inductionVariables->TryGetReference(dstSym->m_id, &iv))
if (loop->inductionVariables && loop->inductionVariables->ContainsKey(dstSym->m_id))
{
iv->SetChangeIsIndeterminate();
for (auto it = loop->inductionVariables->GetIterator(); it.IsValid(); it.MoveNext())
{
InductionVariable& inductionVariable = it.CurrentValueReference();
inductionVariable.SetChangeIsIndeterminate();
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions lib/Backend/JnHelperMethodList.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ HELPERCALL_MATH(Op_MaxInAnArray, Js::JavascriptMath::MaxInAnArray, AttrCanThrow)
HELPERCALL_MATH(Op_MinInAnArray, Js::JavascriptMath::MinInAnArray, AttrCanThrow)

HELPERCALLCHK(Op_ConvString, Js::JavascriptConversion::ToString, AttrCanThrow)
HELPERCALLCHK(Op_ConvPropertyKey, Js::JavascriptOperators::OP_ToPropertyKey, AttrCanThrow)
HELPERCALLCHK(Op_CoerseString, Js::JavascriptConversion::CoerseString, AttrCanThrow)
HELPERCALLCHK(Op_CoerseRegex, (Js::JavascriptRegExp* (*) (Js::Var aValue, Js::Var options, Js::ScriptContext *scriptContext))Js::JavascriptRegExp::CreateRegEx, AttrCanThrow)

Expand Down
10 changes: 10 additions & 0 deletions lib/Backend/Lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2826,6 +2826,10 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
this->LowerConvPrimStr(instr);
break;

case Js::OpCode::Conv_Prop:
this->LowerConvPropertyKey(instr);
break;

case Js::OpCode::ClearAttributes:
this->LowerBinaryHelper(instr, IR::HelperOP_ClearAttributes);
break;
Expand Down Expand Up @@ -25474,6 +25478,12 @@ Lowerer::GenerateGetImmutableOrScriptUnreferencedString(IR::RegOpnd * strOpnd, I
return dstOpnd;
}

void
Lowerer::LowerConvPropertyKey(IR::Instr* instr)
{
LowerConvStrCommon(IR::HelperOp_ConvPropertyKey, instr);
}

void
Lowerer::LowerConvStrCommon(IR::JnHelperMethod helper, IR::Instr * instr)
{
Expand Down
2 changes: 2 additions & 0 deletions lib/Backend/Lower.h
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,8 @@ class Lowerer
void LowerConvPrimStr(IR::Instr * instr);
void LowerConvStrCommon(IR::JnHelperMethod helper, IR::Instr * instr);

void LowerConvPropertyKey(IR::Instr* instr);

void GenerateRecyclerAlloc(IR::JnHelperMethod allocHelper, size_t allocSize, IR::RegOpnd* newObjDst, IR::Instr* insertionPointInstr, bool inOpHelper = false);

template <typename ArrayType>
Expand Down
2 changes: 1 addition & 1 deletion lib/Common/ChakraCoreVersion.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// ChakraCore version number definitions (used in ChakraCore binary metadata)
#define CHAKRA_CORE_MAJOR_VERSION 1
#define CHAKRA_CORE_MINOR_VERSION 11
#define CHAKRA_CORE_PATCH_VERSION 11
#define CHAKRA_CORE_PATCH_VERSION 12
#define CHAKRA_CORE_VERSION_RELEASE_QFE 0 // Redundant with PATCH_VERSION. Keep this value set to 0.

// -------------
Expand Down
Loading