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

August 2018 Security Update #5596

Merged
merged 11 commits into from
Aug 15, 2018
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.10.1
1.10.2
9 changes: 7 additions & 2 deletions lib/Backend/BackwardPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2245,6 +2245,11 @@ BackwardPass::DeadStoreTypeCheckBailOut(IR::Instr * instr)
IR::PropertySymOpnd *propertySymOpnd =
(instr->GetDst() && instr->GetDst()->IsSymOpnd()) ? instr->GetDst()->AsPropertySymOpnd() : instr->GetSrc1()->AsPropertySymOpnd();

if (propertySymOpnd->TypeCheckRequired())
{
return;
}

bool isTypeCheckProtected = false;
IR::BailOutKind bailOutKind;
if (GlobOpt::NeedsTypeCheckBailOut(instr, propertySymOpnd, propertySymOpnd == instr->GetDst(), &isTypeCheckProtected, &bailOutKind))
Expand Down Expand Up @@ -4902,8 +4907,8 @@ BackwardPass::UpdateArrayBailOutKind(IR::Instr *const instr)
}

IR::BailOutKind includeBailOutKinds = IR::BailOutInvalid;
if(!baseValueType.IsNotNativeArray() &&
(!baseValueType.IsLikelyNativeArray() || !instr->GetSrc1()->IsInt32()) &&
if (!baseValueType.IsNotNativeArray() &&
(!baseValueType.IsLikelyNativeArray() || instr->GetSrc1()->IsVar()) &&
!currentBlock->noImplicitCallNativeArrayUses->IsEmpty() &&
!(instr->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall))
{
Expand Down
31 changes: 29 additions & 2 deletions lib/Backend/BailOut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,13 @@ uint32 BailOutRecord::GetArgumentsObjectOffset()
return argumentsObjectOffset;
}

Js::FunctionEntryPointInfo *BailOutRecord::GetFunctionEntryPointInfo() const
{
Js::EntryPointInfo* result = this->globalBailOutRecordTable->entryPointInfo;
AssertOrFailFast(result->IsFunctionEntryPointInfo());
return (Js::FunctionEntryPointInfo*)result;
}

Js::Var BailOutRecord::EnsureArguments(Js::InterpreterStackFrame * newInstance, Js::JavascriptCallStackLayout * layout, Js::ScriptContext* scriptContext, Js::Var* pArgumentsObject) const
{
Assert(globalBailOutRecordTable->hasStackArgOpt);
Expand Down Expand Up @@ -1706,7 +1713,27 @@ void BailOutRecord::ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::S
BailOutRecord * bailOutRecordNotConst = (BailOutRecord *)(void *)bailOutRecord;
bailOutRecordNotConst->bailOutCount++;

Js::FunctionEntryPointInfo *entryPointInfo = function->GetFunctionEntryPointInfo();
Js::FunctionEntryPointInfo *entryPointInfo = bailOutRecord->GetFunctionEntryPointInfo();

#if DBG
// BailOutRecord is not recycler-allocated, so make sure something the recycler can see was keeping the entry point info alive.
// We expect the entry point to be kept alive as follows:
// 1. The function's current type might still have the same entry point info as when we entered the function (easy case)
// 2. The function might have moved to a successor path type, which still keeps the previous type and its entry point info alive
// 3. The entry point info might be held by the ThreadContext (QueueFreeOldEntryPointInfoIfInScript):
// a. If the entry point info was replaced on the type that used to hold it (ScriptFunction::ChangeEntryPoint)
// b. If the function's last-added property was deleted and it moved to a previous type (ScriptFunction::ReplaceTypeWithPredecessorType)
// c. If the function's path type got replaced with a dictionary, then all previous entry point infos in that path are queued on the ThreadContext (ScriptFunction::PrepareForConversionToNonPathType)
bool foundEntryPoint = false;
executeFunction->MapEntryPointsUntil([&](int index, Js::FunctionEntryPointInfo* info)
{
foundEntryPoint = info == entryPointInfo;
return foundEntryPoint;
});
foundEntryPoint = foundEntryPoint || function->GetScriptContext()->GetThreadContext()->IsOldEntryPointInfo(entryPointInfo);
Assert(foundEntryPoint);
#endif

uint8 callsCount = entryPointInfo->callsCount > 255 ? 255 : static_cast<uint8>(entryPointInfo->callsCount);
RejitReason rejitReason = RejitReason::None;
bool reThunk = false;
Expand Down Expand Up @@ -2235,7 +2262,7 @@ void BailOutRecord::ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::S
if (bailOutRecord->IsForLoopTop() && IR::IsTypeCheckBailOutKind(bailOutRecord->bailOutKind))
{
// Disable FieldPRE if we're triggering a type check rejit due to a bailout at the loop top.
// Most likely this was caused by a CheckFixedFld that was hoisted from a branch block where
// Most likely this was caused by a CheckFixedFld that was hoisted from a branch block where
// only certain types flowed, to the loop top, where more types (different or non-equivalent)
// were flowing in.
profileInfo->DisableFieldPRE();
Expand Down
5 changes: 4 additions & 1 deletion lib/Backend/BailOut.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ class BailOutRecord
void SetType(BailoutRecordType type) { this->type = type; }
bool IsShared() const { return type == Shared || type == SharedForLoopTop; }
bool IsForLoopTop() const { return type == SharedForLoopTop; }

Js::FunctionEntryPointInfo *GetFunctionEntryPointInfo() const;
protected:
struct BailOutReturnValue
{
Expand Down Expand Up @@ -237,7 +239,7 @@ class BailOutRecord

static void UpdatePolymorphicFieldAccess(Js::JavascriptFunction * function, BailOutRecord const * bailOutRecord);

static void ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind,
static void ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind,
uint32 actualBailOutOffset, Js::ImplicitCallFlags savedImplicitCallFlags, void * returnAddress);
static void ScheduleLoopBodyCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind);
static void CheckPreemptiveRejit(Js::FunctionBody* executeFunction, IR::BailOutKind bailOutKind, BailOutRecord* bailoutRecord, uint8& callsOrIterationsCount, int loopNumber);
Expand Down Expand Up @@ -416,6 +418,7 @@ struct GlobalBailOutRecordDataTable
// The offset to 'registerSaveSpace' is hard-coded in LinearScanMD::SaveAllRegisters, so let this be the first member variable
Js::Var *registerSaveSpace;
GlobalBailOutRecordDataRow *globalBailOutRecordDataRows;
Js::EntryPointInfo *entryPointInfo;
uint32 length;
uint32 size;
int32 firstActualStackOffset;
Expand Down
9 changes: 8 additions & 1 deletion lib/Backend/FunctionJITTimeInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ FunctionJITTimeInfo::BuildJITTimeData(
jitData->isInlined = codeGenData->GetIsInlined();
jitData->weakFuncRef = (intptr_t)codeGenData->GetWeakFuncRef();
jitData->inlineesBv = (BVFixedIDL*)(const BVFixed*)codeGenData->inlineesBv;
jitData->entryPointInfoAddr = (intptr_t)codeGenData->GetEntryPointInfo();

if (!codeGenData->GetFunctionBody() || !codeGenData->GetFunctionBody()->GetByteCode())
{
Expand Down Expand Up @@ -62,7 +63,7 @@ FunctionJITTimeInfo::BuildJITTimeData(
Assert(defaultEntryPointInfo->IsFunctionEntryPointInfo());
Js::FunctionEntryPointInfo *functionEntryPointInfo = static_cast<Js::FunctionEntryPointInfo*>(defaultEntryPointInfo);
jitData->callsCountAddress = (intptr_t)&functionEntryPointInfo->callsCount;

jitData->sharedPropertyGuards = codeGenData->sharedPropertyGuards;
jitData->sharedPropGuardCount = codeGenData->sharedPropertyGuardCount;
}
Expand Down Expand Up @@ -203,6 +204,12 @@ FunctionJITTimeInfo::GetFunctionInfoAddr() const
return m_data.functionInfoAddr;
}

intptr_t
FunctionJITTimeInfo::GetEntryPointInfoAddr() const
{
return m_data.entryPointInfoAddr;
}

intptr_t
FunctionJITTimeInfo::GetWeakFuncRef() const
{
Expand Down
1 change: 1 addition & 0 deletions lib/Backend/FunctionJITTimeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class FunctionJITTimeInfo
JITTimeFunctionBody * GetBody() const;
bool IsPolymorphicCallSite(Js::ProfileId profiledCallSiteId) const;
intptr_t GetFunctionInfoAddr() const;
intptr_t GetEntryPointInfoAddr() const;
intptr_t GetWeakFuncRef() const;
uint GetLocalFunctionId() const;
uint GetSourceContextId() const;
Expand Down
3 changes: 3 additions & 0 deletions lib/Backend/GlobOpt.h
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,9 @@ class GlobOpt
template<bool makeChanges>
bool ProcessPropOpInTypeCheckSeq(IR::Instr* instr, IR::PropertySymOpnd *opnd, BasicBlock* block, bool updateExistingValue, bool* emitsTypeCheckOut = nullptr, bool* changesTypeValueOut = nullptr, bool *isObjTypeChecked = nullptr);
void KillObjectHeaderInlinedTypeSyms(BasicBlock *block, bool isObjTypeSpecialized, SymID symId = SymID_Invalid);
bool HasLiveObjectHeaderInlinedTypeSym(BasicBlock *block, bool isObjTypeSpecialized, SymID symId = SymID_Invalid);
template<class Fn>
bool MapObjectHeaderInlinedTypeSymsUntil(BasicBlock *block, bool isObjTypeSpecialized, SymID opndId, Fn fn);
void ValueNumberObjectType(IR::Opnd *dstOpnd, IR::Instr *instr);
void SetSingleTypeOnObjectTypeValue(Value* value, const JITTypeHolder type);
void SetTypeSetOnObjectTypeValue(Value* value, Js::EquivalentTypeSet* typeSet);
Expand Down
179 changes: 78 additions & 101 deletions lib/Backend/GlobOptArrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -897,19 +897,8 @@ void GlobOpt::ArraySrcOpt::DoLowerBoundCheck()
Assert(!indexIntSym || indexIntSym->GetType() == TyInt32 || indexIntSym->GetType() == TyUint32);
}

// The info in the landing pad may be better than the info in the current block due to changes made to
// the index sym inside the loop. Check if the bound check we intend to hoist is unnecessary in the
// landing pad.
if (!ValueInfo::IsLessThanOrEqualTo(
nullptr,
0,
0,
hoistInfo.IndexValue(),
hoistInfo.IndexConstantBounds().LowerBound(),
hoistInfo.IndexConstantBounds().UpperBound(),
hoistInfo.Offset()))
if (hoistInfo.IndexSym())
{
Assert(hoistInfo.IndexSym());
Assert(hoistInfo.Loop()->bailOutInfo);
globOpt->EnsureBailTarget(hoistInfo.Loop());

Expand Down Expand Up @@ -1156,106 +1145,94 @@ void GlobOpt::ArraySrcOpt::DoUpperBoundCheck()
Assert(!indexIntSym || indexIntSym->GetType() == TyInt32 || indexIntSym->GetType() == TyUint32);
}

// The info in the landing pad may be better than the info in the current block due to changes made to the
// index sym inside the loop. Check if the bound check we intend to hoist is unnecessary in the landing pad.
if (!ValueInfo::IsLessThanOrEqualTo(
hoistInfo.IndexValue(),
hoistInfo.IndexConstantBounds().LowerBound(),
hoistInfo.IndexConstantBounds().UpperBound(),
hoistInfo.HeadSegmentLengthValue(),
hoistInfo.HeadSegmentLengthConstantBounds().LowerBound(),
hoistInfo.HeadSegmentLengthConstantBounds().UpperBound(),
hoistInfo.Offset()))
{
Assert(hoistInfo.Loop()->bailOutInfo);
globOpt->EnsureBailTarget(hoistInfo.Loop());
Assert(hoistInfo.Loop()->bailOutInfo);
globOpt->EnsureBailTarget(hoistInfo.Loop());

if (hoistInfo.LoopCount())
if (hoistInfo.LoopCount())
{
// Generate the loop count and loop count based bound that will be used for the bound check
if (!hoistInfo.LoopCount()->HasBeenGenerated())
{
// Generate the loop count and loop count based bound that will be used for the bound check
if (!hoistInfo.LoopCount()->HasBeenGenerated())
{
globOpt->GenerateLoopCount(hoistInfo.Loop(), hoistInfo.LoopCount());
}
globOpt->GenerateSecondaryInductionVariableBound(
hoistInfo.Loop(),
indexVarSym->GetInt32EquivSym(nullptr),
hoistInfo.LoopCount(),
hoistInfo.MaxMagnitudeChange(),
hoistInfo.IndexSym());
globOpt->GenerateLoopCount(hoistInfo.Loop(), hoistInfo.LoopCount());
}
globOpt->GenerateSecondaryInductionVariableBound(
hoistInfo.Loop(),
indexVarSym->GetInt32EquivSym(nullptr),
hoistInfo.LoopCount(),
hoistInfo.MaxMagnitudeChange(),
hoistInfo.IndexSym());
}

IR::Opnd* lowerBound = indexIntSym
? static_cast<IR::Opnd *>(IR::RegOpnd::New(indexIntSym, TyInt32, instr->m_func))
: IR::IntConstOpnd::New(
hoistInfo.IndexConstantBounds().LowerBound(),
TyInt32,
instr->m_func);

lowerBound->SetIsJITOptimizedReg(true);
IR::Opnd* upperBound = IR::RegOpnd::New(headSegmentLengthSym, headSegmentLengthSym->GetType(), instr->m_func);
upperBound->SetIsJITOptimizedReg(true);
IR::Opnd* lowerBound = indexIntSym
? static_cast<IR::Opnd *>(IR::RegOpnd::New(indexIntSym, TyInt32, instr->m_func))
: IR::IntConstOpnd::New(
hoistInfo.IndexConstantBounds().LowerBound(),
TyInt32,
instr->m_func);

// indexSym <= headSegmentLength + offset (src1 <= src2 + dst)
IR::Instr *const boundCheck = globOpt->CreateBoundsCheckInstr(
lowerBound,
upperBound,
hoistInfo.Offset(),
hoistInfo.IsLoopCountBasedBound()
? IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck
: IR::BailOutOnFailedHoistedBoundCheck,
hoistInfo.Loop()->bailOutInfo,
hoistInfo.Loop()->bailOutInfo->bailOutFunc);
lowerBound->SetIsJITOptimizedReg(true);
IR::Opnd* upperBound = IR::RegOpnd::New(headSegmentLengthSym, headSegmentLengthSym->GetType(), instr->m_func);
upperBound->SetIsJITOptimizedReg(true);

InsertInstrInLandingPad(boundCheck, hoistInfo.Loop());
// indexSym <= headSegmentLength + offset (src1 <= src2 + dst)
IR::Instr *const boundCheck = globOpt->CreateBoundsCheckInstr(
lowerBound,
upperBound,
hoistInfo.Offset(),
hoistInfo.IsLoopCountBasedBound()
? IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck
: IR::BailOutOnFailedHoistedBoundCheck,
hoistInfo.Loop()->bailOutInfo,
hoistInfo.Loop()->bailOutInfo->bailOutFunc);

if (indexIntSym)
{
TRACE_PHASE_INSTR(
Js::Phase::BoundCheckHoistPhase,
instr,
_u("Hoisting array upper bound check out of loop %u to landing pad block %u, as (s%u <= s%u + %d)\n"),
hoistInfo.Loop()->GetLoopNumber(),
landingPad->GetBlockNum(),
hoistInfo.IndexSym()->m_id,
headSegmentLengthSym->m_id,
hoistInfo.Offset());
}
else
{
TRACE_PHASE_INSTR(
Js::Phase::BoundCheckHoistPhase,
instr,
_u("Hoisting array upper bound check out of loop %u to landing pad block %u, as (%d <= s%u + %d)\n"),
hoistInfo.Loop()->GetLoopNumber(),
landingPad->GetBlockNum(),
hoistInfo.IndexConstantBounds().LowerBound(),
headSegmentLengthSym->m_id,
hoistInfo.Offset());
}
InsertInstrInLandingPad(boundCheck, hoistInfo.Loop());

TESTTRACE_PHASE_INSTR(
if (indexIntSym)
{
TRACE_PHASE_INSTR(
Js::Phase::BoundCheckHoistPhase,
instr,
_u("Hoisting array upper bound check out of loop %u to landing pad block %u, as (s%u <= s%u + %d)\n"),
hoistInfo.Loop()->GetLoopNumber(),
landingPad->GetBlockNum(),
hoistInfo.IndexSym()->m_id,
headSegmentLengthSym->m_id,
hoistInfo.Offset());
}
else
{
TRACE_PHASE_INSTR(
Js::Phase::BoundCheckHoistPhase,
instr,
_u("Hoisting array upper bound check out of loop\n"));
_u("Hoisting array upper bound check out of loop %u to landing pad block %u, as (%d <= s%u + %d)\n"),
hoistInfo.Loop()->GetLoopNumber(),
landingPad->GetBlockNum(),
hoistInfo.IndexConstantBounds().LowerBound(),
headSegmentLengthSym->m_id,
hoistInfo.Offset());
}

// Record the bound check instruction as available
const IntBoundCheck boundCheckInfo(
hoistInfo.IndexValue() ? hoistInfo.IndexValueNumber() : ZeroValueNumber,
hoistInfo.HeadSegmentLengthValue()->GetValueNumber(),
boundCheck,
landingPad);
{
const bool added = globOpt->CurrentBlockData()->availableIntBoundChecks->AddNew(boundCheckInfo) >= 0;
Assert(added || failedToUpdateCompatibleUpperBoundCheck);
}
for (InvariantBlockBackwardIterator it(globOpt, globOpt->currentBlock, landingPad, nullptr);
it.IsValid();
it.MoveNext())
{
const bool added = it.Block()->globOptData.availableIntBoundChecks->AddNew(boundCheckInfo) >= 0;
Assert(added || failedToUpdateCompatibleUpperBoundCheck);
}
TESTTRACE_PHASE_INSTR(
Js::Phase::BoundCheckHoistPhase,
instr,
_u("Hoisting array upper bound check out of loop\n"));

// Record the bound check instruction as available
const IntBoundCheck boundCheckInfo(
hoistInfo.IndexValue() ? hoistInfo.IndexValueNumber() : ZeroValueNumber,
hoistInfo.HeadSegmentLengthValue()->GetValueNumber(),
boundCheck,
landingPad);
{
const bool added = globOpt->CurrentBlockData()->availableIntBoundChecks->AddNew(boundCheckInfo) >= 0;
Assert(added || failedToUpdateCompatibleUpperBoundCheck);
}
for (InvariantBlockBackwardIterator it(globOpt, globOpt->currentBlock, landingPad, nullptr);
it.IsValid();
it.MoveNext())
{
const bool added = it.Block()->globOptData.availableIntBoundChecks->AddNew(boundCheckInfo) >= 0;
Assert(added || failedToUpdateCompatibleUpperBoundCheck);
}
}

Expand Down
Loading