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

17-06 ChakraCore servicing release #3166

Merged
merged 8 commits into from
Jun 15, 2017
5 changes: 5 additions & 0 deletions Build/Chakra.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<ClCompile>
<PreprocessorDefinitions>
%(PreprocessorDefinitions);
_CHAKRACOREBUILD;
_WIN32_WINNT=$(Win32_WinNTVersion);
WINVER=$(Win32_WinNTVersion);
WIN32_LEAN_AND_MEAN=1
Expand Down Expand Up @@ -52,6 +53,10 @@
<Optimization Condition="'$(ENABLE_CODECOVERAGE)'=='true'">Disabled</Optimization>
</ClCompile>

<ResourceCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_CHAKRACOREBUILD</PreprocessorDefinitions>
</ResourceCompile>

<Link>
<!-- ======== For Code Coverage ======== -->
<AdditionalOptions Condition="'$(ENABLE_CODECOVERAGE)'=='true'">%(AdditionalOptions) /DEBUGTYPE:CV,FIXUP</AdditionalOptions>
Expand Down
2 changes: 1 addition & 1 deletion Build/Common.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<AdditionalOptions>%(AdditionalOptions) -sal_local</AdditionalOptions>
</Midl>
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_CHAKRACOREBUILD;NOMINMAX;USE_EDGEMODE_JSRT</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);NOMINMAX;USE_EDGEMODE_JSRT</PreprocessorDefinitions>
<!-- Some of our STDMETHOD can throw
TODO: Code review STDMETHOD and separate out API that can throw and those that can't -->
<PreprocessorDefinitions>%(PreprocessorDefinitions);COM_STDMETHOD_CAN_THROW</PreprocessorDefinitions>
Expand Down
48 changes: 40 additions & 8 deletions lib/Backend/Inline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4674,16 +4674,22 @@ Inline::MapFormals(Func *inlinee,
{
break;
}

int excess;
uint restFuncFormalCount = 0;
if (instr->m_func != inlinee)
{
// this can happen only when we are inlining a function which has inlined an apply call with the arguments object
formalCount = instr->m_func->GetJITFunctionBody()->GetInParamsCount();
restFuncFormalCount = instr->m_func->GetJITFunctionBody()->GetInParamsCount();
Assert(restFuncFormalCount < 1 << 24); // 24 bits for arg count (see CallInfo.h)
excess = actualCount - restFuncFormalCount;
}
else
{
excess = actualCount - formalCount;
}

IR::Opnd *restDst = instr->GetDst();

Assert(actualCount < 1 << 24 && formalCount < 1 << 24); // 24 bits for arg count (see CallInfo.h)
int excess = actualCount - formalCount;

if (excess < 0)
{
Expand All @@ -4701,11 +4707,37 @@ Inline::MapFormals(Func *inlinee,
IR::Instr *newArrInstr = IR::Instr::New(Js::OpCode::NewScArray, restDst, IR::IntConstOpnd::New(excess, TyUint32, inlinee), inlinee);
instr->InsertBefore(newArrInstr);

for (uint i = formalCount; i < actualCount; ++i)
if (instr->m_func != inlinee)
{
IR::IndirOpnd *arrayLocOpnd = IR::IndirOpnd::New(restDst->AsRegOpnd(), i - formalCount, TyVar, inlinee);
IR::Instr *stElemInstr = IR::Instr::New(Js::OpCode::StElemC, arrayLocOpnd, argOutsExtra[i]->GetBytecodeArgOutCapture()->GetDst(), inlinee);
instr->InsertBefore(stElemInstr);
uint index = 0;
for (uint i = restFuncFormalCount; i < min(actualCount, formalCount); ++i)
{
IR::IndirOpnd *arrayLocOpnd = IR::IndirOpnd::New(restDst->AsRegOpnd(), index, TyVar, inlinee);
IR::Instr *stElemInstr = IR::Instr::New(Js::OpCode::StElemC, arrayLocOpnd, argOuts[i]->GetBytecodeArgOutCapture()->GetDst(), inlinee);
instr->InsertBefore(stElemInstr);
index++;
}
for (uint i = max(formalCount, restFuncFormalCount); i < actualCount; ++i)
{
IR::IndirOpnd *arrayLocOpnd = IR::IndirOpnd::New(restDst->AsRegOpnd(), index, TyVar, inlinee);
IR::Instr *stElemInstr = IR::Instr::New(Js::OpCode::StElemC, arrayLocOpnd, argOutsExtra[i]->GetBytecodeArgOutCapture()->GetDst(), inlinee);
instr->InsertBefore(stElemInstr);
index++;
}
AssertMsg(index == (uint)excess, "Incorrect rest args built");
if (index != (uint)excess)
{
throw Js::OperationAbortedException();
}
}
else
{
for (uint i = formalCount; i < actualCount; ++i)
{
IR::IndirOpnd *arrayLocOpnd = IR::IndirOpnd::New(restDst->AsRegOpnd(), i - formalCount, TyVar, inlinee);
IR::Instr *stElemInstr = IR::Instr::New(Js::OpCode::StElemC, arrayLocOpnd, argOutsExtra[i]->GetBytecodeArgOutCapture()->GetDst(), inlinee);
instr->InsertBefore(stElemInstr);
}
}

instr->Remove();
Expand Down
12 changes: 12 additions & 0 deletions lib/Backend/Lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15889,10 +15889,22 @@ Lowerer::GenerateFastElemIIntIndexCommon(
// For typed array, call ToNumber before we fallThrough.
if (instr->GetSrc1()->GetType() == TyVar && !instr->GetSrc1()->GetValueType().IsPrimitive())
{
// Enter an ophelper block
IR::LabelInstr * opHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
instr->InsertBefore(opHelper);

IR::Instr *toNumberInstr = IR::Instr::New(Js::OpCode::Call, this->m_func);
toNumberInstr->SetSrc1(instr->GetSrc1());
instr->InsertBefore(toNumberInstr);

if (BailOutInfo::IsBailOutOnImplicitCalls(bailOutKind))
{
// Bail out if this conversion triggers implicit calls.
toNumberInstr = toNumberInstr->ConvertToBailOutInstr(instr->GetBailOutInfo(), bailOutKind);
IR::Instr * instrShare = instr->ShareBailOut();
LowerBailTarget(instrShare);
}

LowerUnaryHelperMem(toNumberInstr, IR::HelperOp_ConvNumber_Full);
}
InsertBranch(Js::OpCode::Br, labelFallthrough, instr); //Jump to fallThrough
Expand Down
6 changes: 5 additions & 1 deletion lib/JITServer/JITServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,11 +422,15 @@ ServerCleanupScriptContext(
return RPC_S_INVALID_ARG;
}

if (!scriptContextInfo->IsClosed())
{
scriptContextInfo->Close();
ServerContextManager::UnRegisterScriptContext(scriptContextInfo);
}
// This tells the run-time, when it is marshalling the out
// parameters, that the context handle has been closed normally.
*scriptContextInfoAddress = nullptr;

Assert(scriptContextInfo->IsClosed());
HeapDelete(scriptContextInfo);

return S_OK;
Expand Down
6 changes: 3 additions & 3 deletions lib/Runtime/Language/JavascriptOperators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6435,7 +6435,7 @@ namespace Js
aParent = CrossSite::MarshalVar(scriptContext, aParent);
if (i == length)
{
length += 8;
length = UInt16Math::Add(length, 8);
FrameDisplay * tmp = RecyclerNewPlus(scriptContext->GetRecycler(), length * sizeof(void*), FrameDisplay, length);
js_memcpy_s((char*)tmp + tmp->GetOffsetOfScopes(), tmp->GetLength() * sizeof(void *), (char*)pDisplay + pDisplay->GetOffsetOfScopes(), pDisplay->GetLength() * sizeof(void*));
pDisplay = tmp;
Expand Down Expand Up @@ -6493,10 +6493,10 @@ namespace Js

FrameDisplay *pDisplay = nullptr;
FrameDisplay *envDisplay = (FrameDisplay*)argEnv;
uint16 length = envDisplay->GetLength() + 1;
uint16 length = UInt16Math::Add(envDisplay->GetLength(), 1);

pDisplay = RecyclerNewPlus(scriptContext->GetRecycler(), length * sizeof(void*), FrameDisplay, length);
for (int j = 0; j < length - 1; j++)
for (uint16 j = 0; j < length - 1; j++)
{
pDisplay->SetItem(j + 1, envDisplay->GetItem(j));
}
Expand Down
48 changes: 27 additions & 21 deletions lib/Runtime/Library/JavascriptArray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5253,16 +5253,30 @@ namespace Js

if (hasInlineSegment)
{
SparseArraySegmentBase* headSegBase = array->head;
SparseArraySegment<T>* headSeg = (SparseArraySegment<T>*)headSegBase;
AnalysisAssert(array->head);
SparseArraySegment<T>* newHeadSeg = array->ReallocNonLeafSegment((SparseArraySegment<T>*)PointerValue(array->head), array->head->next);
array->head = newHeadSeg;
}
}

AnalysisAssert(headSeg);
SparseArraySegment<T>* newHeadSeg = SparseArraySegment<T>::template AllocateSegmentImpl<false>(recycler,
headSeg->left, headSeg->length, headSeg->size, headSeg->next);
template <typename T>
void JavascriptArray::ReallocateNonLeafLastSegmentIfLeaf(JavascriptArray * arr, Recycler * recycler)
{
Assert(arr->head && arr->head->next); // Doesn't make sense to reallocate a leaf last segment as a non-leaf if its not going to point to any other segments.

newHeadSeg = SparseArraySegment<T>::CopySegment(recycler, newHeadSeg, headSeg->left, headSeg, headSeg->left, headSeg->length);
newHeadSeg->next = headSeg->next;
array->head = newHeadSeg;
// TODO: Consider utilizing lastUsedSegment once we fix CopyHeadIfInlinedHeadSegment in that respect.
SparseArraySegmentBase *lastSeg = nullptr;
SparseArraySegmentBase *seg = arr->head;
while (seg)
{
lastSeg = seg;
seg = seg->next;
}

if (SparseArraySegmentBase::IsLeafSegment(lastSeg, recycler))
{
AnalysisAssert(lastSeg);
arr->ReallocNonLeafSegment((SparseArraySegment<T>*)lastSeg, lastSeg->next, true /*forceNonLeaf*/);
}
}

Expand Down Expand Up @@ -5369,6 +5383,8 @@ namespace Js
bool isIntArray = false;
bool isFloatArray = false;

pArr->ClearSegmentMap(); // Just dump the segment map on reverse

if (JavascriptNativeIntArray::Is(pArr))
{
isIntArray = true;
Expand All @@ -5386,10 +5402,12 @@ namespace Js
if (isIntArray)
{
CopyHeadIfInlinedHeadSegment<int32>(pArr, recycler);
ReallocateNonLeafLastSegmentIfLeaf<int32>(pArr, recycler);
}
else if (isFloatArray)
{
CopyHeadIfInlinedHeadSegment<double>(pArr, recycler);
ReallocateNonLeafLastSegmentIfLeaf<double>(pArr, recycler);
}
else
{
Expand Down Expand Up @@ -5437,33 +5455,21 @@ namespace Js
}

pArr->head = prevSeg;

// Just dump the segment map on reverse
pArr->ClearSegmentMap();
pArr->InvalidateLastUsedSegment(); // lastUsedSegment might be 0-length and discarded above

if (isIntArray)
{
if (pArr->head && pArr->head->next && SparseArraySegmentBase::IsLeafSegment(pArr->head, recycler))
{
pArr->ReallocNonLeafSegment(SparseArraySegment<int32>::From(pArr->head), pArr->head->next);
}
pArr->EnsureHeadStartsFromZero<int32>(recycler);
}
else if (isFloatArray)
{
if (pArr->head && pArr->head->next && SparseArraySegmentBase::IsLeafSegment(pArr->head, recycler))
{
pArr->ReallocNonLeafSegment(SparseArraySegment<double>::From(pArr->head), pArr->head->next);
}
pArr->EnsureHeadStartsFromZero<double>(recycler);
}
else
{
pArr->EnsureHeadStartsFromZero<Var>(recycler);
}

pArr->InvalidateLastUsedSegment(); // lastUsedSegment might be 0-length and discarded above

#ifdef VALIDATE_ARRAY
pArr->ValidateArray();
#endif
Expand Down
4 changes: 3 additions & 1 deletion lib/Runtime/Library/JavascriptArray.h
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ namespace Js
JavascriptArray(JavascriptArray * instance, bool boxHead);

template<typename T> inline void LinkSegments(SparseArraySegment<T>* prev, SparseArraySegment<T>* current);
template<typename T> inline SparseArraySegment<T>* ReallocNonLeafSegment(SparseArraySegment<T>* seg, SparseArraySegmentBase* nextSeg);
template<typename T> inline SparseArraySegment<T>* ReallocNonLeafSegment(SparseArraySegment<T>* seg, SparseArraySegmentBase* nextSeg, bool forceNonLeaf = false);
void TryAddToSegmentMap(Recycler* recycler, SparseArraySegmentBase* seg);

private:
Expand Down Expand Up @@ -575,6 +575,8 @@ namespace Js

template<typename T>
static void CopyHeadIfInlinedHeadSegment(JavascriptArray *array, Recycler *recycler);
template<typename T>
static void ReallocateNonLeafLastSegmentIfLeaf(JavascriptArray * arr, Recycler * recycler);

template<typename T>
static void ArraySpliceHelper(JavascriptArray* pNewArr, JavascriptArray* pArr, uint32 start, uint32 deleteLen,
Expand Down
12 changes: 10 additions & 2 deletions lib/Runtime/Library/JavascriptArray.inl
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ namespace Js
}

template<typename T>
inline SparseArraySegment<T>* JavascriptArray::ReallocNonLeafSegment(SparseArraySegment<T> *seg, SparseArraySegmentBase* nextSeg)
inline SparseArraySegment<T>* JavascriptArray::ReallocNonLeafSegment(SparseArraySegment<T> *seg, SparseArraySegmentBase* nextSeg, bool forceNonLeaf)
{
// Find the segment prior to seg.
SparseArraySegmentBase *prior = nullptr;
Expand All @@ -106,8 +106,16 @@ namespace Js
Assert(prior->next);
}
}
SparseArraySegment<T> *newSeg = nullptr;
Recycler *recycler = this->GetScriptContext()->GetRecycler();
SparseArraySegment<T> *newSeg = SparseArraySegment<T>::AllocateSegment(recycler, seg->left, seg->length, nextSeg);
if (forceNonLeaf)
{
newSeg = SparseArraySegment<T>::template AllocateSegmentImpl<false /*isLeaf*/>(recycler, seg->left, seg->length, nextSeg);
}
else
{
newSeg = SparseArraySegment<T>::AllocateSegment(recycler, seg->left, seg->length, nextSeg);
}
CopyArray(newSeg->elements, seg->length, seg->elements, seg->length);

LinkSegmentsCommon(prior, newSeg);
Expand Down
6 changes: 5 additions & 1 deletion lib/Runtime/Types/DictionaryPropertyDescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ namespace Js
if (this->IsAccessor)
{
Assert(this->Data == NoSlots);
if (addingLetConstGlobal)
{
this->Data = nextPropertyIndex++;
}
}
else if (addingLetConstGlobal)
{
Expand All @@ -165,7 +169,7 @@ namespace Js
this->Getter = nextPropertyIndex++;
}
this->Attributes |= PropertyLetConstGlobal;
Assert(GetDataPropertyIndex<false>() != NoSlots);
Assert((addingLetConstGlobal ? GetDataPropertyIndex<true>() : GetDataPropertyIndex<false>()) != NoSlots);
}

template <typename TPropertyIndex>
Expand Down
3 changes: 2 additions & 1 deletion lib/Runtime/Types/SimpleDictionaryTypeHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ namespace Js

if(isUnordered)
{
newTypeHandler->CopyUnorderedStateFrom(*AsUnordered());
newTypeHandler->CopyUnorderedStateFrom(*AsUnordered(), instance);
}
else
{
Expand Down Expand Up @@ -2685,6 +2685,7 @@ namespace Js
->AddProperty(instance, propertyKey, value, attributes, info, flags, possibleSideEffects);
}

// CONSIDER: Do this after TryReuseDeletedPropertyIndex. If we can reuse slots, no need to grow right now.
if (this->GetSlotCapacity() <= nextPropertyIndex)
{
if (this->GetSlotCapacity() >= MaxPropertyIndexSize)
Expand Down
20 changes: 19 additions & 1 deletion lib/Runtime/Types/SimpleDictionaryUnorderedTypeHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,30 @@ namespace Js

private:
template<class OtherTPropertyIndex, class OtherTMapKey, bool OtherIsNotExtensibleSupported>
void CopyUnorderedStateFrom(const SimpleDictionaryUnorderedTypeHandler<OtherTPropertyIndex, OtherTMapKey, OtherIsNotExtensibleSupported> &other)
void CopyUnorderedStateFrom(const SimpleDictionaryUnorderedTypeHandler<OtherTPropertyIndex, OtherTMapKey, OtherIsNotExtensibleSupported> &other,
DynamicObject *const object)
{
CompileAssert(sizeof(TPropertyIndex) >= sizeof(OtherTPropertyIndex));
if (other.deletedPropertyIndex != PropertyIndexRanges<OtherTPropertyIndex>::NoSlots)
{
deletedPropertyIndex = other.deletedPropertyIndex;

// If terminator values are different, walk to end of chain and update terminator value
if ((int)PropertyIndexRanges<TPropertyIndex>::NoSlots != (int)PropertyIndexRanges<OtherTPropertyIndex>::NoSlots)
{
OtherTPropertyIndex cur = other.deletedPropertyIndex;
for (;;)
{
OtherTPropertyIndex next = static_cast<OtherTPropertyIndex>(TaggedInt::ToInt32(object->GetSlot(cur)));
if (next == PropertyIndexRanges<OtherTPropertyIndex>::NoSlots)
{
this->SetSlotUnchecked(object, cur, TaggedInt::ToVarUnchecked(PropertyIndexRanges<TPropertyIndex>::NoSlots));
break;
}

cur = next;
}
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions test/LetConst/rlexe.xml
Original file line number Diff line number Diff line change
Expand Up @@ -379,4 +379,9 @@
<compile-flags>-args summary -endargs</compile-flags>
</default>
</test>
<test>
<default>
<files>shadowedsetter.js</files>
</default>
</test>
</regress-exe>
18 changes: 18 additions & 0 deletions test/LetConst/shadowedsetter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

evaluate = WScript.LoadScript;

__defineSetter__("x", function () { });

evaluate(`
let x = 'let';
Object.defineProperty(this, "x", { value:
0xdec0 })
if (x === 'let' && this.x === 57024)
{
WScript.Echo('pass');
}
`);