diff --git a/lib/Backend/BailOut.cpp b/lib/Backend/BailOut.cpp index c026951859d..a784a37008a 100644 --- a/lib/Backend/BailOut.cpp +++ b/lib/Backend/BailOut.cpp @@ -1006,7 +1006,7 @@ BailOutRecord::RestoreValue(IR::BailOutKind bailOutKind, Js::JavascriptCallStack if (boxStackInstance) { Js::Var oldValue = value; - value = Js::JavascriptOperators::BoxStackInstance(oldValue, scriptContext, /* allowStackFunction */ true); + value = Js::JavascriptOperators::BoxStackInstance(oldValue, scriptContext, /* allowStackFunction */ true, /* deepCopy */ false); if (oldValue != value) { @@ -1275,7 +1275,7 @@ BailOutRecord::BailOutInlinedHelper(Js::JavascriptCallStackLayout * layout, Bail if (inlineeFrameRecord) { InlinedFrameLayout* outerMostFrame = (InlinedFrameLayout *)(((uint8 *)Js::JavascriptCallStackLayout::ToFramePointer(layout)) - entryPointInfo->frameHeight); - inlineeFrameRecord->RestoreFrames(functionBody, outerMostFrame, layout); + inlineeFrameRecord->RestoreFrames(functionBody, outerMostFrame, layout, false /* deepCopy */); } } @@ -1480,7 +1480,7 @@ BailOutRecord::BailOutHelper(Js::JavascriptCallStackLayout * layout, Js::ScriptF { const Js::Var arg = args.Values[i]; BAILOUT_VERBOSE_TRACE(executeFunction, bailOutKind, _u("BailOut: Argument #%3u: value: 0x%p"), i, arg); - const Js::Var boxedArg = Js::JavascriptOperators::BoxStackInstance(arg, functionScriptContext, true); + const Js::Var boxedArg = Js::JavascriptOperators::BoxStackInstance(arg, functionScriptContext, /* allowStackFunction */ true, /* deepCopy */ false); if(boxedArg != arg) { args.Values[i] = boxedArg; @@ -1775,7 +1775,7 @@ BailOutRecord::BailOutHelper(Js::JavascriptCallStackLayout * layout, Js::ScriptF aReturn = Js::JavascriptFunction::FinishConstructor(aReturn, args.Values[0], function); Js::Var oldValue = aReturn; - aReturn = Js::JavascriptOperators::BoxStackInstance(oldValue, functionScriptContext, /* allowStackFunction */ true); + aReturn = Js::JavascriptOperators::BoxStackInstance(oldValue, functionScriptContext, /* allowStackFunction */ true, /* deepCopy */ false); #if ENABLE_DEBUG_CONFIG_OPTIONS if (oldValue != aReturn) { diff --git a/lib/Backend/InlineeFrameInfo.cpp b/lib/Backend/InlineeFrameInfo.cpp index 97aa7bd41b6..b5e2d69c517 100644 --- a/lib/Backend/InlineeFrameInfo.cpp +++ b/lib/Backend/InlineeFrameInfo.cpp @@ -199,13 +199,14 @@ void InlineeFrameRecord::Finalize(Func* inlinee, uint32 currentOffset) Assert(this->inlineDepth != 0); } -void InlineeFrameRecord::Restore(Js::FunctionBody* functionBody, InlinedFrameLayout *inlinedFrame, Js::JavascriptCallStackLayout * layout) const +void InlineeFrameRecord::Restore(Js::FunctionBody* functionBody, InlinedFrameLayout *inlinedFrame, Js::JavascriptCallStackLayout * layout, bool deepCopy) const { Assert(this->inlineDepth != 0); Assert(inlineeStartOffset != 0); BAILOUT_VERBOSE_TRACE(functionBody, _u("Restore function object: ")); - Js::Var varFunction = this->Restore(this->functionOffset, /*isFloat64*/ false, /*isInt32*/ false, layout, functionBody); + // No deepCopy needed for just the function + Js::Var varFunction = this->Restore(this->functionOffset, /*isFloat64*/ false, /*isInt32*/ false, layout, functionBody, /*deepCopy*/ false); Assert(Js::ScriptFunction::Is(varFunction)); Js::ScriptFunction* function = Js::ScriptFunction::FromVar(varFunction); @@ -219,7 +220,9 @@ void InlineeFrameRecord::Restore(Js::FunctionBody* functionBody, InlinedFrameLay bool isInt32 = losslessInt32Args.Test(i) != 0; BAILOUT_VERBOSE_TRACE(functionBody, _u("Restore argument %d: "), i); - Js::Var var = this->Restore(this->argOffsets[i], isFloat64, isInt32, layout, functionBody); + // Forward deepCopy flag for the arguments in case their data must be guaranteed + // to have its own lifetime + Js::Var var = this->Restore(this->argOffsets[i], isFloat64, isInt32, layout, functionBody, deepCopy); #if DBG if (!Js::TaggedNumber::Is(var)) { @@ -233,7 +236,7 @@ void InlineeFrameRecord::Restore(Js::FunctionBody* functionBody, InlinedFrameLay BAILOUT_FLUSH(functionBody); } -void InlineeFrameRecord::RestoreFrames(Js::FunctionBody* functionBody, InlinedFrameLayout* outerMostFrame, Js::JavascriptCallStackLayout* callstack) +void InlineeFrameRecord::RestoreFrames(Js::FunctionBody* functionBody, InlinedFrameLayout* outerMostFrame, Js::JavascriptCallStackLayout* callstack, bool deepCopy) { InlineeFrameRecord* innerMostRecord = this; class AutoReverse @@ -271,7 +274,7 @@ void InlineeFrameRecord::RestoreFrames(Js::FunctionBody* functionBody, InlinedFr while (currentRecord) { - currentRecord->Restore(functionBody, currentFrame, callstack); + currentRecord->Restore(functionBody, currentFrame, callstack, deepCopy); currentRecord = currentRecord->parent; currentFrame = currentFrame->Next(); } @@ -280,7 +283,7 @@ void InlineeFrameRecord::RestoreFrames(Js::FunctionBody* functionBody, InlinedFr currentFrame->callInfo.Count = 0; } -Js::Var InlineeFrameRecord::Restore(int offset, bool isFloat64, bool isInt32, Js::JavascriptCallStackLayout * layout, Js::FunctionBody* functionBody) const +Js::Var InlineeFrameRecord::Restore(int offset, bool isFloat64, bool isInt32, Js::JavascriptCallStackLayout * layout, Js::FunctionBody* functionBody, bool deepCopy) const { Js::Var value; bool boxStackInstance = true; @@ -322,7 +325,7 @@ Js::Var InlineeFrameRecord::Restore(int offset, bool isFloat64, bool isInt32, Js if (boxStackInstance) { Js::Var oldValue = value; - value = Js::JavascriptOperators::BoxStackInstance(oldValue, functionBody->GetScriptContext(), /* allowStackFunction */ true); + value = Js::JavascriptOperators::BoxStackInstance(oldValue, functionBody->GetScriptContext(), /* allowStackFunction */ true, deepCopy); #if ENABLE_DEBUG_CONFIG_OPTIONS if (oldValue != value) diff --git a/lib/Backend/InlineeFrameInfo.h b/lib/Backend/InlineeFrameInfo.h index 830551abf11..a5d4b10ac5a 100644 --- a/lib/Backend/InlineeFrameInfo.h +++ b/lib/Backend/InlineeFrameInfo.h @@ -108,7 +108,7 @@ struct InlineeFrameRecord } void PopulateParent(Func* func); - void RestoreFrames(Js::FunctionBody* functionBody, InlinedFrameLayout* outerMostInlinee, Js::JavascriptCallStackLayout* callstack); + void RestoreFrames(Js::FunctionBody* functionBody, InlinedFrameLayout* outerMostInlinee, Js::JavascriptCallStackLayout* callstack, bool deepCopy); void Finalize(Func* inlinee, uint currentOffset); #if DBG_DUMP void Dump() const; @@ -123,8 +123,8 @@ struct InlineeFrameRecord } private: - void Restore(Js::FunctionBody* functionBody, InlinedFrameLayout *outerMostFrame, Js::JavascriptCallStackLayout * layout) const; - Js::Var Restore(int offset, bool isFloat64, bool isInt32, Js::JavascriptCallStackLayout * layout, Js::FunctionBody* functionBody) const; + void Restore(Js::FunctionBody* functionBody, InlinedFrameLayout *outerMostFrame, Js::JavascriptCallStackLayout * layout, bool deepCopy) const; + Js::Var Restore(int offset, bool isFloat64, bool isInt32, Js::JavascriptCallStackLayout * layout, Js::FunctionBody* functionBody, bool deepCopy) const; InlineeFrameRecord* Reverse(); }; diff --git a/lib/Runtime/Debug/DiagObjectModel.h b/lib/Runtime/Debug/DiagObjectModel.h index 12f44069f2b..ee3b86dc061 100644 --- a/lib/Runtime/Debug/DiagObjectModel.h +++ b/lib/Runtime/Debug/DiagObjectModel.h @@ -370,7 +370,7 @@ namespace Js { activeScopeObject->SetPropertyWithAttributes( resolveObject.propId, - JavascriptOperators::BoxStackInstance(resolveObject.obj, scriptContext), //The value escapes, box if necessary. + JavascriptOperators::BoxStackInstance(resolveObject.obj, scriptContext, /* allowStackFunction */ false, /* deepCopy */ false), //The value escapes, box if necessary. resolveObject.isConst ? PropertyConstDefaults : PropertyDynamicTypeDefaults, nullptr); } diff --git a/lib/Runtime/Debug/DiagStackFrame.cpp b/lib/Runtime/Debug/DiagStackFrame.cpp index 14611247fb8..0348c3a5c1b 100644 --- a/lib/Runtime/Debug/DiagStackFrame.cpp +++ b/lib/Runtime/Debug/DiagStackFrame.cpp @@ -348,7 +348,7 @@ namespace Js { activeScopeObject->SetPropertyWithAttributes( Js::PropertyIds::_this, - JavascriptOperators::BoxStackInstance(varThis, scriptContext), //The value escapes, box if necessary. + JavascriptOperators::BoxStackInstance(varThis, scriptContext, /* allowStackFunction */ false, /* deepCopy */ false), //The value escapes, box if necessary. PropertyConstDefaults, nullptr); #if DBG diff --git a/lib/Runtime/Language/JavascriptOperators.cpp b/lib/Runtime/Language/JavascriptOperators.cpp index 4ed5cecaefa..23a3b6a32d0 100644 --- a/lib/Runtime/Language/JavascriptOperators.cpp +++ b/lib/Runtime/Language/JavascriptOperators.cpp @@ -9790,7 +9790,7 @@ namespace Js } Js::Var - JavascriptOperators::BoxStackInstance(Js::Var instance, ScriptContext * scriptContext, bool allowStackFunction) + JavascriptOperators::BoxStackInstance(Js::Var instance, ScriptContext * scriptContext, bool allowStackFunction, bool deepCopy) { if (!ThreadContext::IsOnStack(instance) || (allowStackFunction && !TaggedNumber::Is(instance) && (*(int*)instance & 1))) { @@ -9812,11 +9812,11 @@ namespace Js case Js::TypeIds_Object: return DynamicObject::BoxStackInstance(DynamicObject::FromVar(instance)); case Js::TypeIds_Array: - return JavascriptArray::BoxStackInstance(JavascriptArray::FromVar(instance)); + return JavascriptArray::BoxStackInstance(JavascriptArray::FromVar(instance), deepCopy); case Js::TypeIds_NativeIntArray: - return JavascriptNativeIntArray::BoxStackInstance(JavascriptNativeIntArray::FromVar(instance)); + return JavascriptNativeIntArray::BoxStackInstance(JavascriptNativeIntArray::FromVar(instance), deepCopy); case Js::TypeIds_NativeFloatArray: - return JavascriptNativeFloatArray::BoxStackInstance(JavascriptNativeFloatArray::FromVar(instance)); + return JavascriptNativeFloatArray::BoxStackInstance(JavascriptNativeFloatArray::FromVar(instance), deepCopy); case Js::TypeIds_Function: Assert(allowStackFunction); // Stack functions are deal with not mar mark them, but by nested function escape analysis diff --git a/lib/Runtime/Language/JavascriptOperators.h b/lib/Runtime/Language/JavascriptOperators.h index fd9e912d4ef..e229173b2e9 100644 --- a/lib/Runtime/Language/JavascriptOperators.h +++ b/lib/Runtime/Language/JavascriptOperators.h @@ -611,7 +611,7 @@ namespace Js #endif static RecyclableObject *GetCallableObjectOrThrow(const Var callee, ScriptContext *const scriptContext); - static Js::Var BoxStackInstance(Js::Var value, ScriptContext * scriptContext, bool allowStackFunction = false); + static Js::Var BoxStackInstance(Js::Var value, ScriptContext * scriptContext, bool allowStackFunction, bool deepCopy); static BOOL PropertyReferenceWalkUnscopable(Var instance, RecyclableObject** propertyObject, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext); static BOOL PropertyReferenceWalk(Var instance, RecyclableObject** propertyObject, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext); diff --git a/lib/Runtime/Language/JavascriptStackWalker.cpp b/lib/Runtime/Language/JavascriptStackWalker.cpp index 99c768e4b55..1a6eb32f616 100644 --- a/lib/Runtime/Language/JavascriptStackWalker.cpp +++ b/lib/Runtime/Language/JavascriptStackWalker.cpp @@ -450,7 +450,7 @@ namespace Js // are inlined frames on the stack the InlineeCallInfo of the first inlined frame // has the native offset of the current physical frame. Assert(!*inlinee); - InlinedFrameWalker::FromPhysicalFrame(tmpFrameWalker, currentFrame, ScriptFunction::FromVar(parentFunction), PreviousInterpreterFrameIsFromBailout(), loopNum, this, useInternalFrameInfo); + InlinedFrameWalker::FromPhysicalFrame(tmpFrameWalker, currentFrame, ScriptFunction::FromVar(parentFunction), PreviousInterpreterFrameIsFromBailout(), loopNum, this, useInternalFrameInfo, false /*noAlloc*/, false /*deepCopy*/); inlineeOffset = tmpFrameWalker.GetBottomMostInlineeOffset(); tmpFrameWalker.Close(); } @@ -555,7 +555,8 @@ namespace Js } bool hasInlinedFramesOnStack = InlinedFrameWalker::FromPhysicalFrame(inlinedFrameWalker, currentFrame, - ScriptFunction::FromVar(function), true /*fromBailout*/, loopNum, this, false /*useInternalFrameInfo*/); + ScriptFunction::FromVar(function), true /*fromBailout*/, loopNum, this, false /*useInternalFrameInfo*/, false /*noAlloc*/, this->deepCopyForArgs); + if (hasInlinedFramesOnStack) { // We're now back in the state where currentFrame == physical frame of the inliner, but @@ -602,7 +603,18 @@ namespace Js // Check whether there are inlined frames nested in this native frame. The corresponding check for // a jitted loop body frame should have been done in CheckJavascriptFrame Assert(lastInternalFrameInfo.codeAddress == nullptr); - if (InlinedFrameWalker::FromPhysicalFrame(inlinedFrameWalker, currentFrame, ScriptFunction::FromVar(function))) + bool inlinedFramesFound = InlinedFrameWalker::FromPhysicalFrame( + inlinedFrameWalker, + currentFrame, + ScriptFunction::FromVar(function), + false, // fromBailout + -1, // loopNum + nullptr,// walker + false, // useInternalFrameInfo + false, // noAlloc + this->deepCopyForArgs + ); + if (inlinedFramesFound) { this->inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo); this->hasInlinedFramesOnStack = true; @@ -621,7 +633,8 @@ namespace Js _NOINLINE JavascriptStackWalker::JavascriptStackWalker(ScriptContext * scriptContext, bool useEERContext, PVOID returnAddress, bool _forceFullWalk /*=false*/) : inlinedFrameCallInfo(CallFlags_None, 0), shouldDetectPartiallyInitializedInterpreterFrame(true), forceFullWalk(_forceFullWalk), - previousInterpreterFrameIsFromBailout(false), previousInterpreterFrameIsForLoopBody(false), hasInlinedFramesOnStack(false) + previousInterpreterFrameIsFromBailout(false), previousInterpreterFrameIsForLoopBody(false), hasInlinedFramesOnStack(false), + deepCopyForArgs(false) { if (scriptContext == NULL) { @@ -917,7 +930,7 @@ namespace Js Assert((this->interpreterFrame->GetFlags() & Js::InterpreterStackFrameFlags_FromBailOut) != 0); InlinedFrameWalker tmpFrameWalker; Assert(InlinedFrameWalker::FromPhysicalFrame(tmpFrameWalker, currentFrame, Js::ScriptFunction::FromVar(argv[JavascriptFunctionArgIndex_Function]), - true /*fromBailout*/, this->tempInterpreterFrame->GetCurrentLoopNum(), this, false /*useInternalFrameInfo*/, true /*noAlloc*/)); + true /*fromBailout*/, this->tempInterpreterFrame->GetCurrentLoopNum(), this, false /*useInternalFrameInfo*/, true /*noAlloc*/, false /*deepCopy*/)); tmpFrameWalker.Close(); } #endif //DBG @@ -964,9 +977,10 @@ namespace Js { if (includeInlineFrames && InlinedFrameWalker::FromPhysicalFrame(inlinedFrameWalker, currentFrame, Js::ScriptFunction::FromVar(argv[JavascriptFunctionArgIndex_Function]), - false /*fromBailout*/, this->tempInterpreterFrame->GetCurrentLoopNum(), this, false /*useInternalFrameInfo*/)) + false /*fromBailout*/, this->tempInterpreterFrame->GetCurrentLoopNum(), this, false /*useInternalFrameInfo*/, false /*noAlloc*/, this->deepCopyForArgs)) { // Found inlined frames in a jitted loop body. We dont want to skip the inlined frames; walk all of them before setting codeAddress on lastInternalFrameInfo. + // DeepCopy here because, if there is an inlinee in a loop body, FromPhysicalFrame won't be called from UpdateFrame this->inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo); this->hasInlinedFramesOnStack = true; Assert(inlinedFramesBeingWalked); @@ -1208,7 +1222,7 @@ namespace Js #if ENABLE_NATIVE_CODEGEN bool InlinedFrameWalker::FromPhysicalFrame(InlinedFrameWalker& self, StackFrame& physicalFrame, Js::ScriptFunction *parent, bool fromBailout, - int loopNum, const JavascriptStackWalker * const stackWalker, bool useInternalFrameInfo, bool noAlloc) + int loopNum, const JavascriptStackWalker * const stackWalker, bool useInternalFrameInfo, bool noAlloc, bool deepCopy) { bool inlinedFramesFound = false; FunctionBody* parentFunctionBody = parent->GetFunctionBody(); @@ -1261,7 +1275,7 @@ namespace Js if (record) { - record->RestoreFrames(parent->GetFunctionBody(), outerMostFrame, JavascriptCallStackLayout::FromFramePointer(framePointer)); + record->RestoreFrames(parent->GetFunctionBody(), outerMostFrame, JavascriptCallStackLayout::FromFramePointer(framePointer), deepCopy); } } @@ -1347,7 +1361,7 @@ namespace Js for (size_t i = 0; i < argCount; i++) { - args[i] = Js::JavascriptOperators::BoxStackInstance(args[i], scriptContext); + args[i] = Js::JavascriptOperators::BoxStackInstance(args[i], scriptContext, false /*allowStackFunction*/, false /*deepCopy*/); } } diff --git a/lib/Runtime/Language/JavascriptStackWalker.h b/lib/Runtime/Language/JavascriptStackWalker.h index de3a5ee088b..9dd22540f98 100644 --- a/lib/Runtime/Language/JavascriptStackWalker.h +++ b/lib/Runtime/Language/JavascriptStackWalker.h @@ -96,8 +96,8 @@ namespace Js Assert(currentIndex == -1); } - static bool FromPhysicalFrame(InlinedFrameWalker& self, StackFrame& physicalFrame, Js::ScriptFunction *parent, bool fromBailout = false, - int loopNum = -1, const JavascriptStackWalker * const walker = nullptr, bool useInternalFrameInfo = false, bool noAlloc = false); + static bool FromPhysicalFrame(InlinedFrameWalker& self, StackFrame& physicalFrame, Js::ScriptFunction *parent, bool fromBailout, + int loopNum, const JavascriptStackWalker * const walker, bool useInternalFrameInfo, bool noAlloc, bool deepCopy); void Close(); bool Next(CallInfo& callInfo); size_t GetArgc() const; @@ -304,6 +304,8 @@ namespace Js { return previousInterpreterFrameIsFromBailout; } + + void SetDeepCopyForArguments() { deepCopyForArgs = true; } #if DBG static bool ValidateTopJitFrame(Js::ScriptContext* scriptContext); #endif @@ -328,6 +330,7 @@ namespace Js bool previousInterpreterFrameIsFromBailout : 1; bool previousInterpreterFrameIsForLoopBody : 1; bool forceFullWalk : 1; // ignoring hasCaller + bool deepCopyForArgs : 1; // indicates when Var's data should be deep-copied when gathering Arguments for the frame Var GetThisFromFrame() const; // returns 'this' object from the physical frame Var GetCurrentArgumentsObject() const; // returns arguments object from the current frame, which may be virtual (belonging to an inlinee) diff --git a/lib/Runtime/Library/JavascriptArray.cpp b/lib/Runtime/Library/JavascriptArray.cpp index f922d696549..5480b5ebc62 100644 --- a/lib/Runtime/Library/JavascriptArray.cpp +++ b/lib/Runtime/Library/JavascriptArray.cpp @@ -11782,28 +11782,59 @@ namespace Js #endif template - void JavascriptArray::InitBoxedInlineHeadSegment(SparseArraySegment * dst, SparseArraySegment * src) + void JavascriptArray::InitBoxedInlineSegments(SparseArraySegment * dst, SparseArraySegment * src, bool deepCopy) { // Don't copy the segment map, we will build it again SetFlags(GetFlags() & ~DynamicObjectFlags::HasSegmentMap); SetHeadAndLastUsedSegment(dst); + // Copy head segment data dst->left = src->left; dst->length = src->length; dst->size = src->size; dst->CheckLengthvsSize(); - dst->next = src->next; - CopyArray(dst->elements, dst->size, src->elements, src->size); + + if (!deepCopy) + { + // Without a deep copy, point to the existing next segment + dst->next = src->next; + } + else + { + // When deepCopy is true, make a separate copy of each segment. While this involves data + // duplication, it allows the new object to have a separate lifetime without sharing data. + AutoDisableInterrupt failFastError(GetScriptContext()->GetThreadContext()); + do + { + if (src->next != nullptr) + { + // Allocate a new segment in the destination and copy from src + src = static_cast*>(src->next); + + dst->next = dst->AllocateSegment(GetRecycler(), src->left, src->length, src->size, src->next); + dst = static_cast*>(dst->next); + + CopyArray(dst->elements, dst->size, src->elements, src->size); + } + else + { + // Terminate the loop + dst->next = nullptr; + dst = nullptr; + } + } while (dst != nullptr); + failFastError.Completed(); + } } - JavascriptArray::JavascriptArray(JavascriptArray * instance, bool boxHead) + JavascriptArray::JavascriptArray(JavascriptArray * instance, bool boxHead, bool deepCopy) : ArrayObject(instance) { if (boxHead) { - InitBoxedInlineHeadSegment(DetermineInlineHeadSegmentPointer(this), SparseArraySegment::From(instance->head)); + InitBoxedInlineSegments(DetermineInlineHeadSegmentPointer(this), SparseArraySegment::From(instance->head), false); } else { @@ -11815,7 +11846,7 @@ namespace Js } template - T * JavascriptArray::BoxStackInstance(T * instance) + T * JavascriptArray::BoxStackInstance(T * instance, bool deepCopy) { Assert(ThreadContext::IsOnStack(instance)); // On the stack, the we reserved a pointer before the object as to store the boxed value @@ -11831,15 +11862,15 @@ namespace Js { boxedInstance = RecyclerNewPlusZ(instance->GetRecycler(), inlineSlotsSize + sizeof(Js::SparseArraySegmentBase) + instance->head->size * sizeof(typename T::TElement), - T, instance, true); + T, instance, true, deepCopy); } else if(inlineSlotsSize) { - boxedInstance = RecyclerNewPlusZ(instance->GetRecycler(), inlineSlotsSize, T, instance, false); + boxedInstance = RecyclerNewPlusZ(instance->GetRecycler(), inlineSlotsSize, T, instance, false, false); } else { - boxedInstance = RecyclerNew(instance->GetRecycler(), T, instance, false); + boxedInstance = RecyclerNew(instance->GetRecycler(), T, instance, false, false); } *boxedInstanceRef = boxedInstance; @@ -11847,9 +11878,9 @@ namespace Js } JavascriptArray * - JavascriptArray::BoxStackInstance(JavascriptArray * instance) + JavascriptArray::BoxStackInstance(JavascriptArray * instance, bool deepCopy) { - return BoxStackInstance(instance); + return BoxStackInstance(instance, deepCopy); } #if ENABLE_TTD @@ -11917,17 +11948,17 @@ namespace Js #endif JavascriptNativeArray::JavascriptNativeArray(JavascriptNativeArray * instance) : - JavascriptArray(instance, false), + JavascriptArray(instance, false, false), weakRefToFuncBody(instance->weakRefToFuncBody) { } - JavascriptNativeIntArray::JavascriptNativeIntArray(JavascriptNativeIntArray * instance, bool boxHead) : + JavascriptNativeIntArray::JavascriptNativeIntArray(JavascriptNativeIntArray * instance, bool boxHead, bool deepCopy) : JavascriptNativeArray(instance) { if (boxHead) { - InitBoxedInlineHeadSegment(DetermineInlineHeadSegmentPointer(this), SparseArraySegment::From(instance->head)); + InitBoxedInlineSegments(DetermineInlineHeadSegmentPointer(this), SparseArraySegment::From(instance->head), deepCopy); } else { @@ -11938,9 +11969,9 @@ namespace Js } JavascriptNativeIntArray * - JavascriptNativeIntArray::BoxStackInstance(JavascriptNativeIntArray * instance) + JavascriptNativeIntArray::BoxStackInstance(JavascriptNativeIntArray * instance, bool deepCopy) { - return JavascriptArray::BoxStackInstance(instance); + return JavascriptArray::BoxStackInstance(instance, deepCopy); } #if ENABLE_TTD @@ -11968,12 +11999,12 @@ namespace Js #endif #endif - JavascriptNativeFloatArray::JavascriptNativeFloatArray(JavascriptNativeFloatArray * instance, bool boxHead) : + JavascriptNativeFloatArray::JavascriptNativeFloatArray(JavascriptNativeFloatArray * instance, bool boxHead, bool deepCopy) : JavascriptNativeArray(instance) { if (boxHead) { - InitBoxedInlineHeadSegment(DetermineInlineHeadSegmentPointer(this), SparseArraySegment::From(instance->head)); + InitBoxedInlineSegments(DetermineInlineHeadSegmentPointer(this), SparseArraySegment::From(instance->head), deepCopy); } else { @@ -11984,9 +12015,9 @@ namespace Js } JavascriptNativeFloatArray * - JavascriptNativeFloatArray::BoxStackInstance(JavascriptNativeFloatArray * instance) + JavascriptNativeFloatArray::BoxStackInstance(JavascriptNativeFloatArray * instance, bool deepCopy) { - return JavascriptArray::BoxStackInstance(instance); + return JavascriptArray::BoxStackInstance(instance, deepCopy); } #if ENABLE_TTD diff --git a/lib/Runtime/Library/JavascriptArray.h b/lib/Runtime/Library/JavascriptArray.h index 57197de4fe2..8b0632ffa70 100644 --- a/lib/Runtime/Library/JavascriptArray.h +++ b/lib/Runtime/Library/JavascriptArray.h @@ -425,7 +425,7 @@ namespace Js JavascriptArray(uint32 length, DynamicType * type); // For BoxStackInstance - JavascriptArray(JavascriptArray * instance, bool boxHead); + JavascriptArray(JavascriptArray * instance, bool boxHead, bool deepCopy); template inline void LinkSegments(SparseArraySegment* prev, SparseArraySegment* current); template inline SparseArraySegment* ReallocNonLeafSegment(SparseArraySegment* seg, SparseArraySegmentBase* nextSeg, bool forceNonLeaf = false); @@ -897,11 +897,11 @@ namespace Js static Var SpreadArrayArgs(Var arrayToSpread, const Js::AuxArray *spreadIndices, ScriptContext *scriptContext); static uint32 GetSpreadArgLen(Var spreadArg, ScriptContext *scriptContext); - static JavascriptArray * BoxStackInstance(JavascriptArray * instance); + static JavascriptArray * BoxStackInstance(JavascriptArray * instance, bool deepCopy); protected: - template void InitBoxedInlineHeadSegment(SparseArraySegment * dst, SparseArraySegment * src); + template void InitBoxedInlineSegments(SparseArraySegment * dst, SparseArraySegment * src, bool deepCopy); - template static T * BoxStackInstance(T * instance); + template static T * BoxStackInstance(T * instance, bool deepCopy); public: template static size_t DetermineAllocationSize(const uint inlineElementSlots, size_t *const allocationPlusSizeRef = nullptr, uint *const alignedInlineElementSlotsRef = nullptr); @@ -1019,7 +1019,7 @@ namespace Js JavascriptNativeArray(length, type) {} // For BoxStackInstance - JavascriptNativeIntArray(JavascriptNativeIntArray * instance, bool boxHead); + JavascriptNativeIntArray(JavascriptNativeIntArray * instance, bool boxHead, bool deepCopy); public: static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...); static Var NewInstance(RecyclableObject* function, Arguments args); @@ -1077,7 +1077,7 @@ namespace Js return LibraryValue::ValueNativeIntArrayType; } static DynamicType * GetInitialType(ScriptContext * scriptContext); - static JavascriptNativeIntArray * BoxStackInstance(JavascriptNativeIntArray * instance); + static JavascriptNativeIntArray * BoxStackInstance(JavascriptNativeIntArray * instance, bool deepCopy); private: virtual int32 HeadSegmentIndexOfHelper(Var search, uint32 &fromIndex, uint32 toIndex, bool includesAlgorithm, ScriptContext * scriptContext) override; @@ -1182,7 +1182,7 @@ namespace Js JavascriptNativeArray(length, type) {} // For BoxStackInstance - JavascriptNativeFloatArray(JavascriptNativeFloatArray * instance, bool boxHead); + JavascriptNativeFloatArray(JavascriptNativeFloatArray * instance, bool boxHead, bool deepCopy); public: static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...); @@ -1244,7 +1244,7 @@ namespace Js static DynamicType * GetInitialType(ScriptContext * scriptContext); static Var Push(ScriptContext * scriptContext, Var * nativeFloatArray, double value); - static JavascriptNativeFloatArray * BoxStackInstance(JavascriptNativeFloatArray * instance); + static JavascriptNativeFloatArray * BoxStackInstance(JavascriptNativeFloatArray * instance, bool deepCopy); static double Pop(ScriptContext * scriptContext, Var nativeFloatArray); private: virtual int32 HeadSegmentIndexOfHelper(Var search, uint32 &fromIndex, uint32 toIndex, bool includesAlgorithm, ScriptContext * scriptContext) override; diff --git a/lib/Runtime/Library/JavascriptFunction.cpp b/lib/Runtime/Library/JavascriptFunction.cpp index 23f883981f3..32b2b4038c2 100644 --- a/lib/Runtime/Library/JavascriptFunction.cpp +++ b/lib/Runtime/Library/JavascriptFunction.cpp @@ -2885,6 +2885,7 @@ void __cdecl _alloca_probe_16() // and foo.arguments[n] will be maintained after this object is returned. JavascriptStackWalker walker(scriptContext); + walker.SetDeepCopyForArguments(); if (walker.WalkToTarget(this)) {