Explorar el Código

Merge unreleased/rs3 to release/1.7

Taylor Woll hace 8 años
padre
commit
036fe50c38
Se han modificado 100 ficheros con 1652 adiciones y 909 borrados
  1. 6 0
      .gitattributes
  2. 14 0
      Build/Common.Build.ProjectConfiguration.props
  3. 5 5
      Build/Common.Build.props
  4. 1 1
      bin/GCStress/GCStress.vcxproj
  5. 1 7
      bin/GCStress/StubExternalApi.cpp
  6. 6 6
      bin/NativeTests/MemoryPolicyTest.cpp
  7. 1 1
      jenkins/check_eol.sh
  8. 4 1
      lib/Backend/BailOut.cpp
  9. 1 1
      lib/Backend/Func.h
  10. 1 0
      lib/Backend/GlobOpt.cpp
  11. 11 8
      lib/Backend/GlobOptBlockData.cpp
  12. 0 1
      lib/Backend/IR.cpp
  13. 2 1
      lib/Backend/IR.h
  14. 1 1
      lib/Backend/IRBuilder.cpp
  15. 8 5
      lib/Backend/IRBuilder.h
  16. 2 2
      lib/Backend/Inline.cpp
  17. 7 7
      lib/Backend/InterpreterThunkEmitter.cpp
  18. 14 1
      lib/Backend/InterpreterThunkEmitter.h
  19. 1 1
      lib/Backend/JnHelperMethod.h
  20. 1 2
      lib/Backend/LinearScan.cpp
  21. 10 9
      lib/Backend/Lower.cpp
  22. 10 1
      lib/Backend/Security.cpp
  23. 2 1
      lib/Backend/Security.h
  24. 1 0
      lib/Backend/ServerThreadContext.cpp
  25. 1 2
      lib/Backend/ServerThreadContext.h
  26. 0 1
      lib/Backend/arm/LowerMD.cpp
  27. 4 3
      lib/Backend/arm64/LowerMD.h
  28. 1 1
      lib/Common/ChakraCoreVersion.h
  29. 0 1
      lib/Common/Common.h
  30. 6 0
      lib/Common/Common/GetCurrentFrameId.h
  31. 1 0
      lib/Common/Common/UInt16Math.h
  32. 9 0
      lib/Common/CommonDefines.h
  33. 7 2
      lib/Common/ConfigFlagsList.h
  34. 1 0
      lib/Common/DefaultCommonExternalApi.cpp
  35. 6 0
      lib/Common/Exceptions/ReportError.cpp
  36. 2 0
      lib/Common/Exceptions/ReportError.h
  37. 7 0
      lib/Common/Memory/CustomHeap.cpp
  38. 1 0
      lib/Common/Memory/Recycler.cpp
  39. 5 0
      lib/Common/Memory/Recycler.h
  40. 1 1
      lib/Common/Memory/RecyclerWriteBarrierManager.cpp
  41. 5 1
      lib/JITClient/JITManager.cpp
  42. 1 0
      lib/JITIDL/JITTypes.h
  43. 2 1
      lib/JITServer/JITServer.cpp
  44. 6 1
      lib/Jsrt/ChakraCommon.h
  45. 7 1
      lib/Jsrt/Jsrt.cpp
  46. 1 0
      lib/Jsrt/JsrtDebugManager.cpp
  47. 69 27
      lib/Parser/Parse.cpp
  48. 0 1
      lib/Parser/RegexRuntime.cpp
  49. 18 9
      lib/Runtime/Base/Exception.cpp
  50. 1 0
      lib/Runtime/Base/FunctionBody.cpp
  51. 1 0
      lib/Runtime/Base/ScriptContext.cpp
  52. 1 0
      lib/Runtime/Base/ScriptContext.h
  53. 65 3
      lib/Runtime/Base/ThreadContext.cpp
  54. 20 0
      lib/Runtime/Base/ThreadContext.h
  55. 2 2
      lib/Runtime/ByteCode/ByteCodeCacheReleaseFileVersion.h
  56. 5 4
      lib/Runtime/ByteCode/ByteCodeEmitter.cpp
  57. 1 2
      lib/Runtime/ByteCode/ByteCodeGenerator.cpp
  58. 0 1
      lib/Runtime/ByteCode/ScopeInfo.h
  59. 2 2
      lib/Runtime/Debug/Chakra.Runtime.Debug.vcxproj
  60. 1 0
      lib/Runtime/Debug/DiagObjectModel.cpp
  61. 1 1
      lib/Runtime/Debug/DiagProbe.cpp
  62. 2 1
      lib/Runtime/Debug/DiagProbe.h
  63. 45 0
      lib/Runtime/Debug/ProbeContainer.cpp
  64. 3 0
      lib/Runtime/Debug/ProbeContainer.h
  65. 20 0
      lib/Runtime/Language/Arguments.h
  66. 1 0
      lib/Runtime/Language/AsmJsByteCodeGenerator.cpp
  67. 441 434
      lib/Runtime/Language/AsmJsModule.cpp
  68. 1 0
      lib/Runtime/Language/AsmJsUtils.cpp
  69. 13 0
      lib/Runtime/Language/InlineCache.cpp
  70. 2 1
      lib/Runtime/Language/InterpreterStackFrame.cpp
  71. 17 4
      lib/Runtime/Language/JavascriptStackWalker.cpp
  72. 20 10
      lib/Runtime/Library/GlobalObject.cpp
  73. 25 9
      lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp
  74. 4 1
      lib/Runtime/Library/JSON.cpp
  75. 5 1
      lib/Runtime/Library/JSONParser.cpp
  76. 223 176
      lib/Runtime/Library/JavascriptArray.cpp
  77. 17 3
      lib/Runtime/Library/JavascriptArray.h
  78. 60 2
      lib/Runtime/Library/JavascriptArray.inl
  79. 28 8
      lib/Runtime/Library/JavascriptExternalFunction.cpp
  80. 16 6
      lib/Runtime/Library/JavascriptExternalFunction.h
  81. 20 8
      lib/Runtime/Library/JavascriptFunction.cpp
  82. 36 19
      lib/Runtime/Library/JavascriptLibrary.cpp
  83. 9 6
      lib/Runtime/Library/JavascriptLibrary.h
  84. 4 4
      lib/Runtime/Library/JavascriptLibraryBase.h
  85. 4 1
      lib/Runtime/Library/JavascriptNumber.cpp
  86. 1 1
      lib/Runtime/Library/JavascriptProxy.cpp
  87. 18 5
      lib/Runtime/Library/JavascriptRegularExpression.cpp
  88. 103 26
      lib/Runtime/Library/JavascriptString.cpp
  89. 11 0
      lib/Runtime/Library/JavascriptString.h
  90. 6 2
      lib/Runtime/Library/JavascriptSymbol.cpp
  91. 30 15
      lib/Runtime/Library/RegexHelper.cpp
  92. 15 12
      lib/Runtime/Library/ScriptFunction.cpp
  93. 17 4
      lib/Runtime/Library/UriHelper.cpp
  94. 8 4
      lib/Runtime/Library/WabtInterface.cpp
  95. 6 2
      lib/Runtime/Library/WebAssemblyModule.cpp
  96. 3 1
      lib/Runtime/Types/PathTypeHandler.cpp
  97. 9 7
      test/Array/CopyOnAccessArray_bugs.baseline
  98. 8 0
      test/Array/CopyOnAccessArray_bugs.js
  99. 24 1
      test/AsmJs/rlexe.xml
  100. 6 6
      test/Basics/ScriptFunctionToStrings.js

+ 6 - 0
.gitattributes

@@ -3,3 +3,9 @@
 test/**/*.js -crlf
 test/es6/HTMLComments.js binary diff=cpp
 *.wasm binary
+*.cpp text eol=lf diff=cpp
+*.h text eol=lf diff=cpp
+*.inl text eol=lf diff=cpp
+*.vcproj text eol=crlf diff=xml
+*.vcxproj text eol=crlf diff=xml
+*.sln text eol=crlf diff=xml

+ 14 - 0
Build/Common.Build.ProjectConfiguration.props

@@ -42,5 +42,19 @@
       <Platform>ARM</Platform>
     </ProjectConfiguration>
   </ItemGroup>
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|CHPE">
+      <Configuration>Debug</Configuration>
+      <Platform>CHPE</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Test|CHPE">
+      <Configuration>Test</Configuration>
+      <Platform>CHPE</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|CHPE">
+      <Configuration>Release</Configuration>
+      <Platform>CHPE</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
 </Project>
 

+ 5 - 5
Build/Common.Build.props

@@ -29,7 +29,6 @@
       <!-- ======== sources.inc ======== -->
       <!-- generates SAL annotations for our interface -->
       <AdditionalOptions>%(AdditionalOptions) -sal_local</AdditionalOptions>
-      
       <PreprocessorDefinitions>%(PreprocessorDefinitions);WINVER=$(Win32_WinNTVersion)</PreprocessorDefinitions>
     </Midl>
     <ClCompile>
@@ -54,11 +53,11 @@
       <RuntimeTypeInfo>false</RuntimeTypeInfo>
       <!-- /Zi -->
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
-      <DebugInformationFormat Condition="'$(MultiProcessorCompilation)' == 'true'">OldStyle</DebugInformationFormat>
+      <DebugInformationFormat Condition="'%(MultiProcessorCompilation)' == 'true'">OldStyle</DebugInformationFormat>
       <!-- /EHsc- -->
       <ExceptionHandling>SyncCThrow</ExceptionHandling>
       <!-- /Gz -->
-      <CallingConvention Condition="'$(Platform)'=='Win32'">StdCall</CallingConvention>
+      <CallingConvention Condition="'$(Platform)'=='Win32' or '$(Platform)'=='chpe'">StdCall</CallingConvention>
       <!-- /Zp8 -->
       <StructMemberAlignment>8Bytes</StructMemberAlignment>
       <!-- /GS -->
@@ -132,7 +131,8 @@
   <ItemDefinitionGroup Condition="'$(OptimizedBuild)'=='true' AND '$(ENABLE_CODECOVERAGE)'!='true'">
     <ClCompile>
       <Optimization>MaxSpeed</Optimization>
-      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <!-- HYB-TODO: When a CHPE toolchain arrives that supports LTCG, remove this condition. -->
+      <WholeProgramOptimization Condition="'$(Platform)' != 'chpe'">true</WholeProgramOptimization>
     </ClCompile>
   </ItemDefinitionGroup>
   
@@ -162,7 +162,7 @@
       <LinkTimeCodeGeneration Condition="'$(PlatformToolset)'!='v120' AND '$(TF_BUILD)'==''">UseFastLinkTimeCodeGeneration</LinkTimeCodeGeneration>
     </Link>
     <Lib>
-      <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
+      <LinkTimeCodeGeneration Condition="'$(Platform)' != 'chpe'">true</LinkTimeCodeGeneration>
     </Lib>
   </ItemDefinitionGroup>
   <ItemGroup Condition="'$(ConfigurationType)'=='DynamicLibrary' OR '$(ConfigurationType)'=='Application'">

+ 1 - 1
bin/GCStress/GCStress.vcxproj

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <Import Condition="'$(ChakraBuildPathImported)'!='true'" Project="$(SolutionDir)Chakra.Build.Paths.props" />
   <Import Project="$(BuildConfigPropsPath)Chakra.Build.ProjectConfiguration.props" />

+ 1 - 7
bin/GCStress/StubExternalApi.cpp

@@ -112,10 +112,4 @@ HRESULT MemProtectHeapSynchronizeWithCollector(void * heapHandle) { return E_NOT
 void MemProtectHeapSetDisableConcurrentThreadExitedCheck(void * heapHandle) {};
 #endif
 
-#if DBG && defined(RECYCLER_VERIFY_MARK)
-bool IsLikelyRuntimeFalseReference(char* objectStartAddress, size_t offset,
-    const char* typeName)
-{
-    return false;
-}
-#endif
+IMPLEMENT_STUB_IsLikelyRuntimeFalseReference()

+ 6 - 6
bin/NativeTests/MemoryPolicyTest.cpp

@@ -79,20 +79,20 @@ namespace MemoryPolicyTests
 
     TEST_CASE("MemoryPolicyTest_UnboundedMemory", "[MemoryPolicyTest]")
     {
-        BasicTest(JsRuntimeAttributeNone, "UnboundedMemory.js");
-        BasicTest(JsRuntimeAttributeDisableBackgroundWork, "UnboundedMemory.js");
+        BasicTest(JsRuntimeAttributeDisableFatalOnOOM, "UnboundedMemory.js");
+        BasicTest((JsRuntimeAttributes)(JsRuntimeAttributeDisableBackgroundWork | JsRuntimeAttributeDisableFatalOnOOM), "UnboundedMemory.js");
     }
 
     TEST_CASE("MemoryPolicyTest_ArrayTest", "[MemoryPolicyTest]")
     {
-        BasicTest(JsRuntimeAttributeNone, "arrayTest.js");
-        BasicTest(JsRuntimeAttributeDisableBackgroundWork, "arrayTest.js");
+        BasicTest(JsRuntimeAttributeDisableFatalOnOOM, "arrayTest.js");
+        BasicTest((JsRuntimeAttributes)(JsRuntimeAttributeDisableBackgroundWork | JsRuntimeAttributeDisableFatalOnOOM), "arrayTest.js");
     }
 
     TEST_CASE("MemoryPolicyTest_ArrayBuffer", "[MemoryPolicyTest]")
     {
-        BasicTest(JsRuntimeAttributeNone, "arraybuffer.js");
-        BasicTest(JsRuntimeAttributeDisableBackgroundWork, "arraybuffer.js");
+        BasicTest(JsRuntimeAttributeDisableFatalOnOOM, "arraybuffer.js");
+        BasicTest((JsRuntimeAttributes)(JsRuntimeAttributeDisableBackgroundWork | JsRuntimeAttributeDisableFatalOnOOM), "arraybuffer.js");
     }
 
     void OOSTest(JsRuntimeAttributes attributes)

+ 1 - 1
jenkins/check_eol.sh

@@ -15,7 +15,7 @@ fi
 ERRFILE=check_eol.sh.err
 rm -f $ERRFILE
 
-git diff --name-only `git merge-base origin/master HEAD` HEAD | grep -v -E "(test/.*\\.js|\\.cmd|\\.baseline|\\.wasm)" | xargs -I % ./jenkins/check_file_eol.sh %
+git diff --name-only `git merge-base origin/master HEAD` HEAD | grep -v -E "(test/.*\\.js|\\.cmd|\\.baseline|\\.wasm|\\.vcxproj|\\.vcproj|\\.sln)" | xargs -I % ./jenkins/check_file_eol.sh %
 
 if [ -e $ERRFILE ]; then # if error file exists then there were errors
     >&2 echo "--------------" # leading >&2 means echo to stderr

+ 4 - 1
lib/Backend/BailOut.cpp

@@ -1228,6 +1228,10 @@ BailOutRecord::BailOutFromLoopBodyInlinedCommon(Js::JavascriptCallStackLayout *
     uint32 bailOutOffset, void * returnAddress, IR::BailOutKind bailOutKind, Js::Var branchValue)
 {
     Assert(bailOutRecord->parent != nullptr);
+    // This isn't strictly necessary if there's no allocations on this path, but because such an
+    // issue would be hard to notice and introduce some significant issues, we can do this copy.
+    // The problem from not doing this and then doing an allocation before RestoreValues is that
+    // the GC doesn't check the BailOutRegisterSaveSpace.
     Js::Var registerSaves[BailOutRegisterSaveSlotCount];
     js_memcpy_s(registerSaves, sizeof(registerSaves), (Js::Var *)layout->functionObject->GetScriptContext()->GetThreadContext()->GetBailOutRegisterSaveSpace(),
         sizeof(registerSaves));
@@ -2951,7 +2955,6 @@ void  GlobalBailOutRecordDataTable::AddOrUpdateRow(JitArenaAllocator *allocator,
         if(rowToUpdate->offset == offset &&
             rowToUpdate->isInt == (unsigned)isInt &&
             rowToUpdate->isFloat == (unsigned)isFloat &&
-
 #ifdef ENABLE_SIMDJS
             // SIMD_JS
             rowToUpdate->isSimd128F4    == (unsigned) isSimd128F4 &&

+ 1 - 1
lib/Backend/Func.h

@@ -725,7 +725,7 @@ public:
     bool                hasThrow : 1;
     bool                hasUnoptimizedArgumentsAccess : 1; // True if there are any arguments access beyond the simple case of this.apply pattern
     bool                m_canDoInlineArgsOpt : 1;
-    bool                applyTargetInliningRemovedArgumentsAccess :1;
+    bool                applyTargetInliningRemovedArgumentsAccess : 1;
     bool                isGetterSetter : 1;
     const bool          isInlinedConstructor: 1;
     bool                hasImplicitCalls: 1;

+ 1 - 0
lib/Backend/GlobOpt.cpp

@@ -14702,6 +14702,7 @@ GlobOpt::OptArraySrc(IR::Instr * *const instrRef)
                     IR::Opnd* lowerBound = baseOwnerIndir->GetIndexOpnd()
                         ? static_cast<IR::Opnd *>(baseOwnerIndir->GetIndexOpnd())
                         : IR::IntConstOpnd::New(baseOwnerIndir->GetOffset(), TyInt32, instr->m_func);
+
                     lowerBound->SetIsJITOptimizedReg(true);
                     IR::Opnd* upperBound = IR::RegOpnd::New(headSegmentLengthSym, headSegmentLengthSym->GetType(), instr->m_func);
                     upperBound->SetIsJITOptimizedReg(true);

+ 11 - 8
lib/Backend/GlobOptBlockData.cpp

@@ -1052,18 +1052,18 @@ GlobOptBlockData::MergeValueInfo(
     ValueInfo *const toDataValueInfo = toDataVal->GetValueInfo();
     ValueInfo *const fromDataValueInfo = fromDataVal->GetValueInfo();
 
-    // Same value
-    if (toDataValueInfo == fromDataValueInfo)
-    {
-        return toDataValueInfo;
-    }
-
     if (toDataValueInfo->IsJsType() || fromDataValueInfo->IsJsType())
     {
         Assert(toDataValueInfo->IsJsType() && fromDataValueInfo->IsJsType());
         return this->MergeJsTypeValueInfo(toDataValueInfo->AsJsType(), fromDataValueInfo->AsJsType(), isLoopBackEdge, sameValueNumber);
     }
 
+    // Same value
+    if (toDataValueInfo == fromDataValueInfo)
+    {
+        return toDataValueInfo;
+    }
+
     ValueType newValueType(toDataValueInfo->Type().Merge(fromDataValueInfo->Type()));
     if (newValueType.IsLikelyInt())
     {
@@ -1118,8 +1118,6 @@ GlobOptBlockData::MergeValueInfo(
 JsTypeValueInfo*
 GlobOptBlockData::MergeJsTypeValueInfo(JsTypeValueInfo * toValueInfo, JsTypeValueInfo * fromValueInfo, bool isLoopBackEdge, bool sameValueNumber)
 {
-    Assert(toValueInfo != fromValueInfo);
-
     // On loop back edges we must be conservative and only consider type values which are invariant throughout the loop.
     // That's because in dead store pass we can't correctly track object pointer assignments (o = p), and we may not
     // be able to register correct type checks for the right properties upstream. If we ever figure out how to enhance
@@ -1129,6 +1127,11 @@ GlobOptBlockData::MergeJsTypeValueInfo(JsTypeValueInfo * toValueInfo, JsTypeValu
         return nullptr;
     }
 
+    if (toValueInfo == fromValueInfo)
+    {
+        return toValueInfo;
+    }
+
     const JITTypeHolder toType = toValueInfo->GetJsType();
     const JITTypeHolder fromType = fromValueInfo->GetJsType();
     const JITTypeHolder mergedType = toType == fromType ? toType : JITTypeHolder(nullptr);

+ 0 - 1
lib/Backend/IR.cpp

@@ -4639,4 +4639,3 @@ Instr::DumpRange(Instr *instrEnd)
 #endif
 
 } // namespace IR
-

+ 2 - 1
lib/Backend/IR.h

@@ -151,7 +151,8 @@ protected:
         ignoreOverflowBitCount(32),
         isCtorCall(false),
         isCallInstrProtectedByNoProfileBailout(false),
-        hasSideEffects(false)
+        hasSideEffects(false),
+        isNonFastPathFrameDisplay(false)
     {
     }
 public:

+ 1 - 1
lib/Backend/IRBuilder.cpp

@@ -10,7 +10,7 @@
 #pragma prefast(disable:28652, "Prefast complains that the OR are causing the compiler to emit dynamic initializers and the variable to be allocated in read/write mem...")
 
 static const IR::BailOutKind c_debuggerBailOutKindForCall =
-    IR::BailOutForceByFlag | IR::BailOutStackFrameBase | IR::BailOutBreakPointInFunction | IR::BailOutLocalValueChanged | IR::BailOutIgnoreException;
+    IR::BailOutForceByFlag | IR::BailOutStackFrameBase | IR::BailOutBreakPointInFunction | IR::BailOutLocalValueChanged | IR::BailOutIgnoreException | IR::BailOutStep;
 static const IR::BailOutKind c_debuggerBaseBailOutKindForHelper = IR::BailOutIgnoreException | IR::BailOutForceByFlag;
 
 #pragma prefast(pop)

+ 8 - 5
lib/Backend/IRBuilder.h

@@ -87,9 +87,10 @@ public:
     {
         auto loopCount = func->GetJITFunctionBody()->GetLoopCount();
         if (loopCount > 0) {
-            m_saveLoopImplicitCallFlags = (IR::Opnd**)func->m_alloc->Alloc(sizeof(IR::Opnd*) * loopCount);
 #if DBG
-            memset(m_saveLoopImplicitCallFlags, 0, sizeof(IR::Opnd*) * loopCount);
+            m_saveLoopImplicitCallFlags = AnewArrayZ(func->m_alloc, IR::Opnd*, loopCount);
+#else
+            m_saveLoopImplicitCallFlags = AnewArray(func->m_alloc, IR::Opnd*, loopCount);
 #endif
         }
 
@@ -97,10 +98,12 @@ public:
         func->m_workItem->InitializeReader(&m_jnReader, &m_statementReader, func->m_alloc);
     };
 
-    ~IRBuilder() {
+    ~IRBuilder()
+    {
         Assert(m_func->GetJITFunctionBody()->GetLoopCount() == 0 || m_saveLoopImplicitCallFlags);
-        if (m_saveLoopImplicitCallFlags) {
-            m_func->m_alloc->Free(m_saveLoopImplicitCallFlags, sizeof(IR::Opnd*) * m_func->GetJITFunctionBody()->GetLoopCount());
+        if (m_saveLoopImplicitCallFlags)
+        {
+            AdeleteArray(m_func->m_alloc, m_func->GetJITFunctionBody()->GetLoopCount(), m_saveLoopImplicitCallFlags);
         }
     }
 

+ 2 - 2
lib/Backend/Inline.cpp

@@ -1716,7 +1716,7 @@ Inline::TryOptimizeCallInstrWithFixedMethod(IR::Instr *callInstr, const Function
     else
     {
         // We patch later for constructor inlining.
-        Assert(
+        AssertOrFailFast(
             callInstr->m_opcode == Js::OpCode::NewScObject ||
             callInstr->m_opcode == Js::OpCode::NewScObjArray);
     }
@@ -3759,7 +3759,7 @@ void Inline::InlineDOMGetterSetterFunction(IR::Instr *ldFldInstr, const Function
     // type-specific optimizations. Otherwise, this optimization to reduce calls into the host will also
     // result in relatively more expensive calls in the runtime.
     tmpDst->SetValueType(ldFldInstr->GetDst()->GetValueType());
-    
+
     IR::Opnd * callInstrDst = ldFldInstr->UnlinkDst();
     ldFldInstr->SetDst(tmpDst);
 

+ 7 - 7
lib/Backend/InterpreterThunkEmitter.cpp

@@ -25,7 +25,7 @@ const BYTE InterpreterThunkEmitter::StackAllocSize = 0x28;
 // Hence, we allocate 0x28 bytes of stack space for the callee to use. The callee uses 8 bytes to push the first
 // argument and the rest 0x20 ensures alignment is correct.
 //
-const BYTE InterpreterThunkEmitter::InterpreterThunk[] = {
+const BYTE InterpreterThunkEmitter::InterpreterThunk[INTERPRETER_THUNK_SIZE] = {
     0x48, 0x89, 0x54, 0x24, 0x10,                                  // mov         qword ptr [rsp+10h],rdx
     0x48, 0x89, 0x4C, 0x24, 0x08,                                  // mov         qword ptr [rsp+8],rcx
     0x4C, 0x89, 0x44, 0x24, 0x18,                                  // mov         qword ptr [rsp+18h],r8
@@ -69,7 +69,7 @@ const BYTE InterpreterThunkEmitter::ThunkAddressOffset = 61;
 const BYTE InterpreterThunkEmitter::PrologSize = 60;
 const BYTE InterpreterThunkEmitter::StackAllocSize = 0x0;
 
-const BYTE InterpreterThunkEmitter::InterpreterThunk[] = {
+const BYTE InterpreterThunkEmitter::InterpreterThunk[INTERPRETER_THUNK_SIZE] = {
     0x55,                                                       // push   rbp                   // Prolog - setup the stack frame
     0x48, 0x89, 0xe5,                                           // mov    rbp, rsp
     0x48, 0x8b, 0x47, 0x00,                                     // mov    rax, qword ptr [rdi + FunctionInfoOffset]
@@ -106,7 +106,7 @@ const BYTE InterpreterThunkEmitter::CallBlockStartAddressInstrOffset = 42;
 const BYTE InterpreterThunkEmitter::CallThunkSizeInstrOffset = 54;
 const BYTE InterpreterThunkEmitter::ErrorOffset = 64;
 
-const BYTE InterpreterThunkEmitter::InterpreterThunk[] = {
+const BYTE InterpreterThunkEmitter::InterpreterThunk[INTERPRETER_THUNK_SIZE] = {
     0x0F, 0xB4,                                                      // push        {r0-r3}
     0x2D, 0xE9, 0x00, 0x48,                                          // push        {r11,lr}
     0xEB, 0x46,                                                      // mov         r11,sp
@@ -152,7 +152,7 @@ const BYTE InterpreterThunkEmitter::DynamicThunkAddressOffset = 32;
 const BYTE InterpreterThunkEmitter::ThunkAddressOffset = 36;
 
 //TODO: saravind :Implement Range Check for ARM64
-const BYTE InterpreterThunkEmitter::InterpreterThunk[] = {
+const BYTE InterpreterThunkEmitter::InterpreterThunk[INTERPRETER_THUNK_SIZE] = {
     0xFD, 0x7B, 0xBB, 0xA9,                                         //stp         fp, lr, [sp, #-80]!   ;Prologue
     0xFD, 0x03, 0x00, 0x91,                                         //mov         fp, sp                ;update frame pointer to the stack pointer
     0xE0, 0x07, 0x01, 0xA9,                                         //stp         x0, x1, [sp, #16]     ;Prologue again; save all registers
@@ -191,7 +191,7 @@ const BYTE InterpreterThunkEmitter::ThunkSizeOffset = 26;
 const BYTE InterpreterThunkEmitter::ErrorOffset = 33;
 const BYTE InterpreterThunkEmitter::ThunkAddressOffset = 44;
 
-const BYTE InterpreterThunkEmitter::InterpreterThunk[] = {
+const BYTE InterpreterThunkEmitter::InterpreterThunk[INTERPRETER_THUNK_SIZE] = {
     0x55,                                                           //   push        ebp                ;Prolog - setup the stack frame
     0x8B, 0xEC,                                                     //   mov         ebp,esp
     0x8B, 0x45, 0x08,                                               //   mov         eax, dword ptr [ebp+8]
@@ -547,7 +547,7 @@ void InterpreterThunkEmitter::EncodeInterpreterThunk(
     __in const DWORD epilogSize,
     __in const intptr_t interpreterThunk)
 {
-    _Analysis_assume_(thunkSize == HeaderSize());
+    _Analysis_assume_(thunkSize == INTERPRETER_THUNK_SIZE);
     // Encode MOVW
     DWORD lowerThunkBits = (uint32)interpreterThunk & 0x0000FFFF;
     DWORD movW = EncodeMove(/*Opcode*/ 0x0000F240, /*register*/1, lowerThunkBits);
@@ -621,7 +621,7 @@ void InterpreterThunkEmitter::EncodeInterpreterThunk(
 {
     int addrOffset = ThunkAddressOffset;
 
-    _Analysis_assume_(thunkSize == HeaderSize());
+    _Analysis_assume_(thunkSize == INTERPRETER_THUNK_SIZE);
     AssertMsg(thunkSize == HeaderSize(), "Mismatch in the size of the InterpreterHeaderThunk and the thunkSize used in this API (EncodeInterpreterThunk)");
 
     // Following 4 MOV Instrs are to move the 64-bit address of the InterpreterThunk address into register x1.

+ 14 - 1
lib/Backend/InterpreterThunkEmitter.h

@@ -81,7 +81,20 @@ private:
     static const BYTE CallBlockStartAddressInstrOffset;
     static const BYTE CallThunkSizeInstrOffset;
 #endif
-    static const BYTE InterpreterThunk[];
+#ifdef _M_X64
+#ifdef _WIN32
+#define INTERPRETER_THUNK_SIZE 96
+#else  // Sys V AMD64
+#define INTERPRETER_THUNK_SIZE 72
+#endif
+#elif defined(_M_ARM)
+#define INTERPRETER_THUNK_SIZE 72
+#elif defined(_M_ARM64)
+#define INTERPRETER_THUNK_SIZE 60
+#else
+#define INTERPRETER_THUNK_SIZE 56
+#endif
+    static const BYTE InterpreterThunk[INTERPRETER_THUNK_SIZE];
 
     // Call buffer includes a call to the inner interpreter thunk and eventual jump to the epilog
     static const BYTE JmpOffset;

+ 1 - 1
lib/Backend/JnHelperMethod.h

@@ -7,7 +7,7 @@
 extern "C"
 {
 #ifdef _M_IX86
-    void __cdecl _chkstk(int);
+    DECLSPEC_CHPE_GUEST void __cdecl _chkstk(int);
 #else
     void __cdecl __chkstk(int);
 #endif

+ 1 - 2
lib/Backend/LinearScan.cpp

@@ -222,11 +222,10 @@ LinearScan::RegAlloc()
         }
 
         this->SetSrcRegs(instr);
+        this->EndDeadLifetimes(instr);
 
         this->CheckOpHelper(instr);
 
-        this->EndDeadLifetimes(instr);
-
         this->KillImplicitRegs(instr);
 
         this->AllocateNewLifetimes(instr);

+ 10 - 9
lib/Backend/Lower.cpp

@@ -308,7 +308,7 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
                     // s2 = current function.
                     IR::Opnd * paramOpnd = LoadFunctionBodyOpnd(instr);
                     this->m_lowererMD.LoadHelperArgument(instr, paramOpnd);
-                    
+
                     m_lowererMD.ChangeToHelperCallMem(instr, IR::HelperOP_NewScopeObjectWithFormals);
                 }
                 else
@@ -6375,7 +6375,7 @@ Lowerer::GenerateScriptFunctionInit(IR::RegOpnd * regOpnd, IR::Opnd * vtableAddr
     IR::Opnd * typeOpnd = IR::RegOpnd::New(TyMachPtr, func);
     InsertMove(typeOpnd, IR::IndirOpnd::New(functionProxyOpnd->AsRegOpnd(), Js::FunctionProxy::GetOffsetOfDeferredPrototypeType(),
         TyMachPtr, func), insertBeforeInstr);
-    
+
     IR::LabelInstr * labelHelper = IR::LabelInstr::New(Js::OpCode::Label, func, true);
     InsertTestBranch(typeOpnd, typeOpnd, Js::OpCode::BrEq_A, labelHelper, insertBeforeInstr);
     IR::LabelInstr * labelDone = IR::LabelInstr::New(Js::OpCode::Label, func, false);
@@ -6388,7 +6388,7 @@ Lowerer::GenerateScriptFunctionInit(IR::RegOpnd * regOpnd, IR::Opnd * vtableAddr
     insertBeforeInstr->InsertBefore(callHelperInstr);
     m_lowererMD.LowerCall(callHelperInstr, 0);
     insertBeforeInstr->InsertBefore(labelDone);
-    
+
     GenerateMemInit(regOpnd, 0, vtableAddressOpnd, insertBeforeInstr, isZeroed);
     GenerateMemInit(regOpnd, Js::ScriptFunction::GetOffsetOfType(), typeOpnd, insertBeforeInstr, isZeroed);
     GenerateMemInitNull(regOpnd, Js::ScriptFunction::GetOffsetOfAuxSlots(), insertBeforeInstr, isZeroed);
@@ -6396,7 +6396,7 @@ Lowerer::GenerateScriptFunctionInit(IR::RegOpnd * regOpnd, IR::Opnd * vtableAddr
     GenerateMemInit(regOpnd, Js::ScriptFunction::GetOffsetOfConstructorCache(),
     LoadLibraryValueOpnd(insertBeforeInstr, LibraryValue::ValueConstructorCacheDefaultInstance),
         insertBeforeInstr, isZeroed);
-    
+
     GenerateMemInit(regOpnd, Js::ScriptFunction::GetOffsetOfFunctionInfo(), functionInfoOpnd, insertBeforeInstr, isZeroed);
     GenerateMemInit(regOpnd, Js::ScriptFunction::GetOffsetOfEnvironment(), envOpnd, insertBeforeInstr, isZeroed);
     GenerateMemInitNull(regOpnd, Js::ScriptFunction::GetOffsetOfCachedScopeObj(), insertBeforeInstr, isZeroed);
@@ -18834,7 +18834,7 @@ void Lowerer::GenerateTruncWithCheck(IR::Instr* instr)
         {
             m_lowererMD.LoadFloatHelperArgument(instr, instr->GetSrc1());
         }
-        else 
+        else
         {
             m_lowererMD.LoadDoubleHelperArgument(instr, instr->GetSrc1());
         }
@@ -22185,7 +22185,7 @@ Lowerer::TryGenerateFastBrOrCmTypeOf(IR::Instr *instr, IR::Instr **prev, bool is
             return true;
         }
     }
-    
+
     if (instrSrc1 && instrSrc1->GetStackSym()->IsSingleDef() && instrSrc2 && instrSrc2->GetStackSym()->IsSingleDef() &&
         instrSrc1->GetStackSym()->GetInstrDef()->m_opcode == Js::OpCode::Typeof &&
         instrSrc2->GetStackSym()->GetInstrDef()->m_opcode == Js::OpCode::Typeof)
@@ -22435,7 +22435,7 @@ Lowerer::GenerateFastCmTypeOf(IR::Instr *compare, IR::RegOpnd *object, IR::IntCo
     IR::LabelInstr *helper= IR::LabelInstr::New(Js::OpCode::Label, m_func, true);
     IR::RegOpnd    *dst      = compare->GetDst()->IsRegOpnd() ? compare->GetDst()->AsRegOpnd() : nullptr;
     IR::RegOpnd    *typeRegOpnd  = IR::RegOpnd::New(TyMachReg, m_func);
-    
+
     Assert(dst);
 
     if (dst->IsEqual(object))
@@ -23931,7 +23931,7 @@ Lowerer::LowerDivI4Common(IR::Instr * instr)
             {
                 InsertCompareBranch(src2, IR::IntConstOpnd::NewFromType(-1, src2->GetType(), m_func), Js::OpCode::BrNeq_A, divLabel, divLabel);
             }
-            
+
             InsertMove(dst, !isRem ? src1 : IR::IntConstOpnd::NewFromType(0, dst->GetType(), m_func), divLabel);
             InsertBranch(Js::OpCode::Br, doneLabel, divLabel);
         }
@@ -24210,7 +24210,7 @@ Lowerer::LowerNewScopeSlots(IR::Instr * instr, bool doStackSlots)
     {
         GenerateRecyclerAlloc(IR::HelperAllocMemForVarArray, allocSize, dst, instr);
     }
-   
+
     m_lowererMD.GenerateMemInit(dst, Js::ScopeSlots::EncodedSlotCountSlotIndex * sizeof(Js::Var),
             (size_t)min<uint>(actualSlotCount, Js::ScopeSlots::MaxEncodedSlotCount), instr, !doStackSlots);
 
@@ -25154,6 +25154,7 @@ Lowerer::LowerFrameDisplayCheck(IR::Instr * instr)
                 indirOpnd = IR::IndirOpnd::New(slotArrayOpnd,
                                                Js::ScopeSlots::EncodedSlotCountSlotIndex * sizeof(Js::Var),
                                                TyVar, m_func, true);
+
                 IR::IntConstOpnd * slotIdOpnd = IR::IntConstOpnd::New(slotId - Js::ScopeSlots::FirstSlotIndex,
                                                                       TyUint32, m_func);
                 InsertCompareBranch(indirOpnd, slotIdOpnd, Js::OpCode::BrLe_A, true, errorLabel, insertInstr);

+ 10 - 1
lib/Backend/Security.cpp

@@ -298,6 +298,8 @@ Security::DontEncode(IR::Opnd *opnd)
         IR::IndirOpnd *indirOpnd = opnd->AsIndirOpnd();
         return indirOpnd->m_dontEncode || indirOpnd->GetOffset() == 0;
     }
+    case IR::OpndKindInt64Const:
+        return false;
     default:
         return true;
     }
@@ -312,6 +314,13 @@ Security::CalculateConstSize(IR::Opnd *opnd)
     }
     switch (opnd->GetKind())
     {
+#if TARGET_64
+    case IR::OpndKindInt64Const:
+    {
+        IR::Int64ConstOpnd *intConstOpnd = opnd->AsInt64ConstOpnd();
+        return GetByteCount(intConstOpnd->GetValue());
+    }
+#endif
     case IR::OpndKindIntConst:
     {
         IR::IntConstOpnd *intConstOpnd = opnd->AsIntConstOpnd();
@@ -411,7 +420,7 @@ Security::EncodeOpnd(IR::Instr * instr, IR::Opnd *opnd)
             {
                 IR::RegOpnd * newBaseOpnd = IR::RegOpnd::New(TyMachReg, instr->m_func);
                 Lowerer::InsertAdd(false, newBaseOpnd, newOpnd, indirOpnd->GetBaseOpnd(), instr);
-                indirOpnd->SetBaseOpnd(newBaseOpnd);
+                indirOpnd->ReplaceBaseOpnd(newBaseOpnd);
             }
             else
             {

+ 2 - 1
lib/Backend/Security.h

@@ -8,12 +8,13 @@ class Security
 {
 private:
     Func *func;
+    uint currentConstSize;
     IR::RegOpnd * basePlusCookieOpnd;
     IR::IntConstOpnd * cookieOpnd;
     IR::RegOpnd * baseOpnd;
 
 public:
-    Security(Func * func) : func(func), basePlusCookieOpnd(nullptr), cookieOpnd(nullptr), baseOpnd(nullptr) { }
+    Security(Func * func) : func(func), currentConstSize(0), basePlusCookieOpnd(nullptr), cookieOpnd(nullptr), baseOpnd(nullptr) { }
 
     void            EncodeLargeConstants();
     void            InsertNOPs();

+ 1 - 0
lib/Backend/ServerThreadContext.cpp

@@ -10,6 +10,7 @@
 
 ServerThreadContext::ServerThreadContext(ThreadContextDataIDL * data, HANDLE processHandle) :
     m_autoProcessHandle(processHandle),
+    m_processHandle(processHandle),
     m_threadContextData(*data),
     m_refCount(0),
     m_numericPropertyBV(nullptr),

+ 1 - 2
lib/Backend/ServerThreadContext.h

@@ -60,7 +60,6 @@ public:
     static intptr_t GetJITCRTBaseAddress();
 
 private:
-
     AutoCloseHandle m_autoProcessHandle;
 
     BVSparse<HeapAllocator> * m_numericPropertyBV;
@@ -75,7 +74,7 @@ private:
     OOPCodeGenAllocators m_codeGenAlloc;
     // only allocate with this from foreground calls (never from CodeGen calls)
     PageAllocator m_pageAlloc;
-
+    HANDLE m_processHandle;
     ThreadContextDataIDL m_threadContextData;
 
     DWORD m_pid; //save client process id for easier diagnose

+ 0 - 1
lib/Backend/arm/LowerMD.cpp

@@ -8430,7 +8430,6 @@ LowererMD::EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert,
 
     instr = IR::Instr::New(Js::OpCode::Call, dst, this->m_func);
     instrInsert->InsertBefore(instr);
-
     if (BailOutInfo::IsBailOutOnImplicitCalls(bailOutKind))
     {
         _Analysis_assume_(instrBailOut != nullptr);

+ 4 - 3
lib/Backend/arm64/LowerMD.h

@@ -63,8 +63,9 @@ public:
             IR::Instr *     ChangeToHelperCall(IR::Instr * instr, IR::JnHelperMethod helperMethod, IR::LabelInstr *labelBailOut = NULL,
                             IR::Opnd *opndInstance = NULL, IR::PropertySymOpnd * propSymOpnd = nullptr, bool isHelperContinuation = false) { __debugbreak(); return 0; }
             IR::Instr *     ChangeToHelperCallMem(IR::Instr * instr, IR::JnHelperMethod helperMethod) { __debugbreak(); return 0; }
-    static  IR::Instr *     CreateAssign(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsertPt) { __debugbreak(); return 0; }
+    static  IR::Instr *     CreateAssign(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsertPt, bool generateWriteBarrier = true) { __debugbreak(); return 0; }
     static  IR::Instr *     ChangeToAssign(IR::Instr * instr) { __debugbreak(); return 0; }
+    static  IR::Instr *     ChangeToAssignNoBarrierCheck(IR::Instr * instr) { __debugbreak(); return 0;}
     static  IR::Instr *     ChangeToAssign(IR::Instr * instr, IRType type) { __debugbreak(); return 0; }
     static  IR::Instr *     ChangeToLea(IR::Instr *const instr, bool postRegAlloc = false) { __debugbreak(); return 0; }
     static  IR::Instr *     ForceDstToReg(IR::Instr *instr) { __debugbreak(); return 0; }
@@ -84,7 +85,7 @@ public:
               IR::Instr *     LowerLdSuper(IR::Instr * instr, IR::JnHelperMethod helperOpCode) { __debugbreak(); return 0; }
               IR::Instr *     GenerateSmIntPairTest(IR::Instr * instrInsert, IR::Opnd * opndSrc1, IR::Opnd * opndSrc2, IR::LabelInstr * labelFail) { __debugbreak(); return 0; }
 #if DBG
-      static  void            GenerateDebugBreak(IR::Instr * insertInstr) { __debugbreak(); return 0; };
+      static  void            GenerateDebugBreak(IR::Instr * insertInstr) { __debugbreak(); };
 #endif
               void            GenerateTaggedZeroTest( IR::Opnd * opndSrc, IR::Instr * instrInsert, IR::LabelInstr * labelHelper = NULL) { __debugbreak(); }
               void            GenerateObjectPairTest(IR::Opnd * opndSrc1, IR::Opnd * opndSrc2, IR::Instr * insertInstr, IR::LabelInstr * labelTarget) { __debugbreak(); }
@@ -261,7 +262,7 @@ public:
               static void GenerateLdLocalFldFromFlagInlineCache(IR::Instr * instrLdFld, IR::RegOpnd * opndBase, IR::Opnd * opndDst, IR::RegOpnd * opndInlineCache, IR::LabelInstr * labelFallThru, bool isInlineSlot) { __debugbreak(); }
               static void GenerateStFldFromLocalInlineCache(IR::Instr * instrStFld, IR::RegOpnd * opndBase, IR::Opnd * opndSrc, IR::RegOpnd * opndInlineCache, IR::LabelInstr * labelFallThru, bool isInlineSlot) { __debugbreak(); }
 
-              static IR::Instr * ChangeToWriteBarrierAssign(IR::Instr * assignInstr, const Func* func) { __debugbreak(); }
+              static IR::Instr * ChangeToWriteBarrierAssign(IR::Instr * assignInstr, const Func* func) { __debugbreak(); return 0; }
 
               int                 GetHelperArgsCount() { __debugbreak(); return 0; }
               void                ResetHelperArgsCount() { __debugbreak(); }

+ 1 - 1
lib/Common/ChakraCoreVersion.h

@@ -60,4 +60,4 @@
 // Chakra RELEASE flag
 // Mostly redundant with CHAKRA_CORE_VERSION_RELEASE,
 // but semantically refers to Chakra rather than ChakraCore.
-#define CHAKRA_VERSION_RELEASE 0
+#define CHAKRA_VERSION_RELEASE 1

+ 0 - 1
lib/Common/Common.h

@@ -30,7 +30,6 @@ typedef _Return_type_success_(return >= 0) LONG NTSTATUS;
 #endif
 
 #include "Common/GetCurrentFrameId.h"
-
 namespace Js
 {
     typedef int32 PropertyId;

+ 6 - 0
lib/Common/Common/GetCurrentFrameId.h

@@ -18,8 +18,14 @@
 
 #ifndef GET_CURRENT_FRAME_ID
 #if defined(_M_IX86)
+#if defined(_M_HYBRID_X86_ARM64)
+__MACHINEARM64(unsigned __int64 __getReg(int))
+#define GET_CURRENT_FRAME_ID(f) \
+    (f = (void*)__getReg(29))
+#else
 #define GET_CURRENT_FRAME_ID(f) \
     __asm { mov f, ebp }
+#endif
 #elif defined(_M_X64)
 #ifdef _WIN32
 #define GET_CURRENT_FRAME_ID(f) \

+ 1 - 0
lib/Common/Common/UInt16Math.h

@@ -81,6 +81,7 @@ public:
     }
 
 };
+
 using ArgSlotMath = UInt16Math;
 
 template <>

+ 9 - 0
lib/Common/CommonDefines.h

@@ -67,6 +67,14 @@
 #define TARGET_64 1
 #endif
 
+#ifndef DECLSPEC_CHPE_GUEST
+// For CHPE build aka Arm64.x86
+// https://osgwiki.com/wiki/ARM64_CHPE
+// On ChakraCore alone we do not support this
+// so we define to nothing to avoid build breaks
+#define DECLSPEC_CHPE_GUEST
+#endif
+
 // Memory Protections
 #ifdef _CONTROL_FLOW_GUARD
 #define PAGE_EXECUTE_RO_TARGETS_INVALID   (PAGE_EXECUTE | PAGE_TARGETS_INVALID)
@@ -337,6 +345,7 @@
         //#define TELEMETRY_ESB_GetConstructorPropertyPolyfillDetection // Whether telemetry will inspect the `.constructor` property of every Object instance to determine if it's a polyfill of a known ES built-in.
     #endif
 
+    #define REJIT_STATS
 #else
 
     #define TELEMETRY_OPCODE_OFFSET_ENABLED false

+ 7 - 2
lib/Common/ConfigFlagsList.h

@@ -437,6 +437,7 @@ PHASE(All)
 #define DEFAULT_CONFIG_ExtendedErrorStackForTestHost (false)
 #define DEFAULT_CONFIG_ForceSplitScope      (false)
 #define DEFAULT_CONFIG_DelayFullJITSmallFunc (0)
+#define DEFAULT_CONFIG_EnableFatalErrorOnOOM (true)
 #define DEFAULT_CONFIG_RedeferralCap         (3)
 
 //Following determines inline thresholds
@@ -511,6 +512,7 @@ PHASE(All)
 #define DEFAULT_CONFIG_GoptCleanupThreshold  (25)
 #define DEFAULT_CONFIG_AsmGoptCleanupThreshold  (500)
 #define DEFAULT_CONFIG_OptimizeForManyInstances (false)
+#define DEFAULT_CONFIG_EnableArrayTypeMutation (false)
 
 #define DEFAULT_CONFIG_DeferParseThreshold             (4 * 1024) // Unit is number of characters
 #define DEFAULT_CONFIG_ProfileBasedDeferParseThreshold (100)      // Unit is number of characters
@@ -1125,6 +1127,7 @@ FLAGNR(Boolean, ForceJITLoopBody      , "Force jit loop body only", DEFAULT_CONF
 FLAGNR(Boolean, ForceStaticInterpreterThunk, "Force using static interpreter thunk", DEFAULT_CONFIG_ForceStaticInterpreterThunk)
 FLAGNR(Boolean, DumpCommentsFromReferencedFiles, "Allow printing comments of comment-table of the referenced file as well (use with -trace:CommentTable)", DEFAULT_CONFIG_DumpCommentsFromReferencedFiles)
 FLAGNR(Number,  DelayFullJITSmallFunc , "Scale Full JIT threshold for small functions which are going to be inlined soon. To provide fraction scale, the final scale is scale following this option divided by 10", DEFAULT_CONFIG_DelayFullJITSmallFunc)
+FLAGNR(Boolean, EnableFatalErrorOnOOM, "Enabling failfast fatal error on OOM", DEFAULT_CONFIG_EnableFatalErrorOnOOM)
 
 #ifdef _M_ARM
 FLAGNR(Boolean, ForceLocalsPtr        , "Force use of alternative locals pointer (JIT only)", false)
@@ -1250,8 +1253,8 @@ FLAGR(Number,   MinDeferredFuncTokenCount, "Minimum length in tokens of defer-pa
 #if DBG
 FLAGNR(Number,  SkipFuncCountForBailOnNoProfile,  "Initial Number of functions in a func body to be skipped from forcibly inserting BailOnNoProfile.", DEFAULT_CONFIG_SkipFuncCountForBailOnNoProfile)
 #endif
-FLAGNR(Number, MaxJITFunctionBytecodeByteLength, "The biggest function we'll JIT (bytecode bytelength)", DEFAULT_CONFIG_MaxJITFunctionBytecodeByteLength)
-FLAGNR(Number, MaxJITFunctionBytecodeCount, "The biggest function we'll JIT (bytecode count)", DEFAULT_CONFIG_MaxJITFunctionBytecodeCount)
+FLAGNR(Number,  MaxJITFunctionBytecodeByteLength, "The biggest function we'll JIT (bytecode bytelength)", DEFAULT_CONFIG_MaxJITFunctionBytecodeByteLength)
+FLAGNR(Number,  MaxJITFunctionBytecodeCount, "The biggest function we'll JIT (bytecode count)", DEFAULT_CONFIG_MaxJITFunctionBytecodeCount)
 FLAGNR(Number,  MaxLoopsPerFunction   , "Maximum number of loops in any function in the script", DEFAULT_CONFIG_MaxLoopsPerFunction)
 FLAGNR(Number,  FuncObjectInlineCacheThreshold  , "Maximum number of inline caches a function body may have to allow for inline caches to be allocated on the function object", DEFAULT_CONFIG_FuncObjectInlineCacheThreshold)
 FLAGNR(Boolean, NoDeferParse          , "Disable deferred parsing", false)
@@ -1444,6 +1447,8 @@ FLAGR (Number,  DynamicRegexMruListSize, "Size of the MRU list for dynamic regex
 #endif
 
 FLAGR (Boolean, OptimizeForManyInstances, "Optimize script engine for many instances (low memory footprint per engine, assume low spare CPU cycles) (default: false)", DEFAULT_CONFIG_OptimizeForManyInstances)
+FLAGNR(Boolean, EnableArrayTypeMutation, "Enable force array type mutation on re-entrant region", DEFAULT_CONFIG_EnableArrayTypeMutation)
+FLAGNR(Number,  ArrayMutationTestSeed, "Seed used for the array mutation", 0)
 FLAGNR(Phases,  TestTrace             , "Test trace for the given phase", )
 FLAGNR(Boolean, EnableEvalMapCleanup, "Enable cleaning up the eval map", true)
 #ifdef PROFILE_MEM

+ 1 - 0
lib/Common/DefaultCommonExternalApi.cpp

@@ -51,3 +51,4 @@ void ConfigParserAPI::DisplayInitialOutput(__in LPWSTR moduleName)
 {
 }
 
+IMPLEMENT_STUB_IsLikelyRuntimeFalseReference()

+ 6 - 0
lib/Common/Exceptions/ReportError.cpp

@@ -138,4 +138,10 @@ _NOINLINE void RpcFailure_fatal_error(HRESULT hr)
     ReportFatalException(NULL, hr, Fatal_RpcFailure, scenario);
 }
 
+_NOINLINE void OutOfMemory_fatal_error()
+{
+    int scenario = 9;
+    ReportFatalException(NULL, E_OUTOFMEMORY, Fatal_OutOfMemory, scenario);
+}
+
 #pragma optimize("",on)

+ 2 - 0
lib/Common/Exceptions/ReportError.h

@@ -27,6 +27,7 @@ enum ErrorReason
     Fatal_JsReentrancy_Error = 19,
     Fatal_TTDAbort = 20,
     Fatal_Failed_API_Result = 21,
+    Fatal_OutOfMemory = 22
 };
 
 extern "C" void ReportFatalException(
@@ -70,6 +71,7 @@ void LargeHeapBlock_Metadata_Corrupted(
 void FromDOM_NoScriptScope_fatal_error();
 void Debugger_AttachDetach_fatal_error(HRESULT hr);
 void RpcFailure_fatal_error(HRESULT hr);
+void OutOfMemory_fatal_error();
 
 #ifndef DISABLE_SEH
 // RtlReportException is available on Vista and up, but we cannot use it for OOB release.

+ 7 - 0
lib/Common/Memory/CustomHeap.cpp

@@ -620,6 +620,13 @@ bool Heap<TAlloc, TPreReservedAlloc>::AllocInPage(Page* page, size_t bytes, usho
         return false;
     }
 
+    //Section of the Page should already be freed.
+    if (!page->freeBitVector.TestRange(index, length))
+    {
+        CustomHeap_BadPageState_fatal_error((ULONG_PTR)this);
+        return false;
+    }
+
     page->freeBitVector.ClearRange(index, length);
     VerboseHeapTrace(_u("ChunkSize: %d, Index: %d, Free bit vector in page: "), length, index);
 

+ 1 - 0
lib/Common/Memory/Recycler.cpp

@@ -4879,6 +4879,7 @@ Recycler::FinalizeConcurrent(bool restoreState)
     }
 
     this->threadService = nullptr;
+
     if (concurrentThread != NULL)
     {
         CloseHandle(concurrentThread);

+ 5 - 0
lib/Common/Memory/Recycler.h

@@ -2533,8 +2533,13 @@ extern bool IsLikelyRuntimeFalseReference(
     private: \
         friend bool ::IsLikelyRuntimeFalseReference( \
             char* objectStartAddress, size_t offset, const char* typeName);
+#define IMPLEMENT_STUB_IsLikelyRuntimeFalseReference() \
+    bool IsLikelyRuntimeFalseReference( \
+            char* objectStartAddress, size_t offset, const char* typeName) \
+    {  return false; }
 #else
 #define DECLARE_RECYCLER_VERIFY_MARK_FRIEND()
+#define IMPLEMENT_STUB_IsLikelyRuntimeFalseReference()
 #endif
 
 template <typename ExternalAllocFunc>

+ 1 - 1
lib/Common/Memory/RecyclerWriteBarrierManager.cpp

@@ -55,7 +55,7 @@ X64WriteBarrierCardTableManager::OnThreadInit()
     // So any writes to stack allocated vars can also have the write barrier set
 
     // xplat-todo: Replace this on Windows too with GetCurrentThreadStackBounds
-#ifdef _WIN32
+#if defined(_WIN32) && defined(_M_X64)
     // check StackProber.cpp for the stack pages layout information
     NT_TIB* teb = (NT_TIB*) ::NtCurrentTeb();
     char* stackBase = (char*) teb->StackBase;

+ 5 - 1
lib/JITClient/JITManager.cpp

@@ -218,7 +218,11 @@ HRESULT
 JITManager::ConnectRpcServer(__in HANDLE jitProcessHandle, __in_opt void* serverSecurityDescriptor, __in UUID connectionUuid)
 {
     Assert(IsOOPJITEnabled());
-    Assert(m_rpcBindingHandle == nullptr);
+    if(m_rpcBindingHandle != nullptr)
+    {
+        // TODO: change this to allow connecting a new JIT process to new ThreadContexts
+        return E_FAIL;
+    }
 
     HRESULT hr = E_FAIL;
 

+ 1 - 0
lib/JITIDL/JITTypes.h

@@ -10,6 +10,7 @@ import "wtypes.idl";
 #include "sdkddkver.h"
 #endif
 
+
 #if defined(WINVER) && WINVER >= _WIN32_WINNT_WINBLUE // on 8.1+, RPC can marshal process handle for us
 #ifdef __midl
 cpp_quote("#define USE_RPC_HANDLE_MARSHALLING 1")

+ 2 - 1
lib/JITServer/JITServer.cpp

@@ -449,6 +449,7 @@ ServerCleanupScriptContext(
         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;
@@ -967,4 +968,4 @@ HRESULT ServerCallWrapper(ServerScriptContext* scriptContextInfo, Fn fn)
     {
         return E_ACCESSDENIED;
     }
-}
+}

+ 6 - 1
lib/Jsrt/ChakraCommon.h

@@ -443,7 +443,12 @@ typedef unsigned short uint16_t;
         ///     Calling <c>JsSetException</c> will also dispatch the exception to the script debugger
         ///     (if any) giving the debugger a chance to break on the exception.
         /// </summary>
-        JsRuntimeAttributeDispatchSetExceptionsToDebugger = 0x00000040
+        JsRuntimeAttributeDispatchSetExceptionsToDebugger = 0x00000040,
+        /// <summary>
+        ///     Disable Failfast fatal error on OOM
+        /// </summary>
+        JsRuntimeAttributeDisableFatalOnOOM = 0x00000080,
+
     } JsRuntimeAttributes;
 
     /// <summary>

+ 7 - 1
lib/Jsrt/Jsrt.cpp

@@ -269,7 +269,8 @@ JsErrorCode CreateRuntimeCore(_In_ JsRuntimeAttributes attributes,
             JsRuntimeAttributeDisableEval |
             JsRuntimeAttributeDisableNativeCodeGeneration |
             JsRuntimeAttributeEnableExperimentalFeatures |
-            JsRuntimeAttributeDispatchSetExceptionsToDebugger
+            JsRuntimeAttributeDispatchSetExceptionsToDebugger |
+            JsRuntimeAttributeDisableFatalOnOOM
 #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
             | JsRuntimeAttributeSerializeLibraryByteCode
 #endif
@@ -321,6 +322,11 @@ JsErrorCode CreateRuntimeCore(_In_ JsRuntimeAttributes attributes,
             threadContext->SetThreadContextFlag(ThreadContextFlagNoJIT);
         }
 
+        if (attributes & JsRuntimeAttributeDisableFatalOnOOM)
+        {
+            threadContext->SetThreadContextFlag(ThreadContextFlagDisableFatalOnOOM);
+        }
+
 #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
         if (Js::Configuration::Global.flags.PrimeRecycler)
         {

+ 1 - 0
lib/Jsrt/JsrtDebugManager.cpp

@@ -106,6 +106,7 @@ void JsrtDebugManager::DispatchHalt(Js::InterpreterHaltState* haltState)
     case Js::STOP_EXCEPTIONTHROW: /*JsDiagDebugEventRuntimeException*/
         this->ReportExceptionBreak(haltState);
         break;
+    case Js::STOP_DOMMUTATIONBREAKPOINT:
     case Js::STOP_MUTATIONBREAKPOINT:
         AssertMsg(false, "Not yet handled");
         break;

+ 69 - 27
lib/Parser/Parse.cpp

@@ -910,7 +910,7 @@ Symbol* Parser::AddDeclForPid(ParseNodePtr pnode, IdentPtr pid, SymbolType symbo
             // because in that case we don't need a GlobalEvalScope.
             Assert(!fBlockScope || (this->m_grfscr & fscrConsoleScopeEval) == fscrConsoleScopeEval);
             CheckRedeclarationErrorForBlockId(pid, 1);
-        }
+            }
         else if (!pnodeFnc->sxFnc.IsBodyAndParamScopeMerged()
             && scope->GetScopeType() == ScopeType_FunctionBody
             && (pnode->nop == knopLetDecl || pnode->nop == knopConstDecl))
@@ -3694,6 +3694,7 @@ ParseNodePtr Parser::ParsePostfixOperators(
         case tkLParen:
             {
                 AutoMarkInParsingArgs autoMarkInParsingArgs(this);
+
                 if (fInNew)
                 {
                     ParseNodePtr pnodeArgs = ParseArgList<buildAST>(&callOfConstants, &spreadArgCount, &count);
@@ -4671,20 +4672,66 @@ ParseNodePtr Parser::ParseMemberList(LPCOLESTR pNameHint, uint32* pNameHintLengt
                 {
                     Error(ERRUnexpectedEllipsis);
                 }
-                pnodeExpr = ParseDestructuredVarDecl<buildAST>(declarationType, declarationType != tkLCurly, nullptr/* *hasSeenRest*/, false /*topLevel*/, false /*allowEmptyExpression*/);
 
-                if (m_token.tk != tkComma && m_token.tk != tkRCurly)
+                RestorePoint atExpression;
+                if (!buildAST && declarationType == tkLCurly && IsPossiblePatternStart())
                 {
-                    if (m_token.IsOperator())
+                    m_pscan->Capture(&atExpression);
+
+                    // It is possible that we might encounter the shorthand init error. Lets find that out.
+                    bool savedDeferredInitError = m_hasDeferredShorthandInitError;
+                    m_hasDeferredShorthandInitError = false;
+
+                    IdentToken token;
+                    BOOL fLikelyPattern = false;
+
+                    // First identify that the current expression is indeed the object/array literal. Otherwise we will just use the ParsrExpr to parse that.
+
+                    ParseTerm<buildAST>(/* fAllowCall */ m_token.tk != tkSUPER, nullptr /*pNameHint*/, nullptr /*pHintLength*/, nullptr /*pShortNameOffset*/, &token, false /*fUnaryOrParen*/,
+                        nullptr /*pfCanAssign*/, &fLikelyPattern);
+
+                    m_pscan->SeekTo(atExpression);
+
+                    if (fLikelyPattern)
                     {
-                        Error(ERRDestructNoOper);
+                        pnodeExpr = ParseDestructuredVarDecl<buildAST>(declarationType, declarationType != tkLCurly, nullptr/* *hasSeenRest*/, false /*topLevel*/, false /*allowEmptyExpression*/);
+                        if (m_token.tk != tkComma && m_token.tk != tkRCurly)
+                        {
+                            if (m_token.IsOperator())
+                            {
+                                Error(ERRDestructNoOper);
+                            }
+                            Error(ERRsyntax);
+                        }
+                    }
+                    else
+                    {
+                        if (m_hasDeferredShorthandInitError)
+                        {
+                            Error(ERRnoColon);
+                        }
+
+                        pnodeExpr = ParseExpr<buildAST>(koplCma, nullptr/*pfCantAssign*/, TRUE/*fAllowIn*/, FALSE/*fAllowEllipsis*/, pFullNameHint, &fullNameHintLength, &shortNameOffset);
+                    }
+
+                    m_hasDeferredShorthandInitError = savedDeferredInitError;
+                }
+                else
+                {
+                    pnodeExpr = ParseDestructuredVarDecl<buildAST>(declarationType, declarationType != tkLCurly, nullptr/* *hasSeenRest*/, false /*topLevel*/, false /*allowEmptyExpression*/);
+                    if (m_token.tk != tkComma && m_token.tk != tkRCurly)
+                    {
+                        if (m_token.IsOperator())
+                        {
+                            Error(ERRDestructNoOper);
+                        }
+                        Error(ERRsyntax);
                     }
-                    Error(ERRsyntax);
                 }
             }
             else
             {
-                pnodeExpr = ParseExpr<buildAST>(koplCma, nullptr, TRUE, FALSE, pFullNameHint, &fullNameHintLength, &shortNameOffset);
+                pnodeExpr = ParseExpr<buildAST>(koplCma, nullptr/*pfCantAssign*/, TRUE/*fAllowIn*/, FALSE/*fAllowEllipsis*/, pFullNameHint, &fullNameHintLength, &shortNameOffset);
             }
 #if DEBUG
             if((m_grfscr & fscrEnforceJSON) && !IsJSONValid(pnodeExpr))
@@ -5556,6 +5603,7 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
                     }
                     return false;
                 });
+
                 if (pnodeFnc->sxFnc.IsBodyAndParamScopeMerged() && !fDeclaration && pnodeFnc->sxFnc.pnodeName != nullptr)
                 {
                     Symbol* funcSym = pnodeFnc->sxFnc.pnodeName->sxVar.sym;
@@ -8749,9 +8797,6 @@ ParseNodePtr Parser::ParseExpr(int oplMin,
                 this->SetHasDestructuringPattern(true);
                 pnode = ConvertToPattern(pnode);
             }
-
-            // The left-hand side is found to be destructuring pattern - so the shorthand can have initializer.
-            m_hasDeferredShorthandInitError = false;
         }
 
         if (buildAST)
@@ -13007,6 +13052,12 @@ ParseNodePtr Parser::ParseDestructuredVarDecl(tokens declarationType, bool isDec
 
     if (IsPossiblePatternStart())
     {
+        // For the possible pattern start we do not allow the parens before
+        if (parenCount != 0)
+        {
+            Error(ERRDestructIDRef);
+        }
+
         // Go recursively
         pnodeElem = ParseDestructuredLiteral<buildAST>(declarationType, isDecl, false /*topLevel*/, seenRest ? DIC_ShouldNotParseInitializer : DIC_None);
         if (!isDecl)
@@ -13076,6 +13127,14 @@ ParseNodePtr Parser::ParseDestructuredVarDecl(tokens declarationType, bool isDec
             m_pscan->Scan();
             --parenCount;
         }
+
+        // Restore the Block ID of the current block after the parsing of destructured variable declarations and initializers.
+        GetCurrentBlock()->sxBlock.blockId = originalCurrentBlockId;
+    }
+
+    if (parenCount != 0)
+    {
+        Error(ERRnoRparen);
     }
 
     if (hasSeenRest != nullptr)
@@ -13113,19 +13172,6 @@ ParseNodePtr Parser::ParseDestructuredVarDecl(tokens declarationType, bool isDec
         pnodeElem = pnodeRest;
     }
 
-    // We eat the left parentheses only when its not a declaration. This will make sure we throw syntax errors early. We need to do the same for right parentheses.
-    if (!isDecl)
-    {
-        while (m_token.tk == tkRParen)
-        {
-            m_pscan->Scan();
-            --parenCount;
-        }
-
-        // Restore the Block ID of the current block after the parsing of destructured variable declarations and initializers.
-        GetCurrentBlock()->sxBlock.blockId = originalCurrentBlockId;
-    }
-
     if (!(m_token.tk == tkComma || m_token.tk == tkRBrack || m_token.tk == tkRCurly))
     {
         if (m_token.IsOperator())
@@ -13135,10 +13181,6 @@ ParseNodePtr Parser::ParseDestructuredVarDecl(tokens declarationType, bool isDec
         Error(ERRsyntax);
     }
 
-    if (parenCount != 0)
-    {
-        Error(ERRnoRparen);
-    }
     return pnodeElem;
 }
 

+ 0 - 1
lib/Parser/RegexRuntime.cpp

@@ -4296,7 +4296,6 @@ namespace UnifiedRegex
         // If loopInfo->number now is less than begins->repeats.lower, the loop
         // shouldn't match anything. In that case, stop backtracking.
         loopInfo->number = max(loopInfo->number, begin->repeats.lower);
-
         // Rewind input
         inputOffset = loopInfo->startInputOffset + loopInfo->number;
 

+ 18 - 9
lib/Runtime/Base/Exception.cpp

@@ -12,18 +12,27 @@ namespace Js
     {
         ThreadContext *threadContext = ThreadContext::GetContextForCurrentThread();
 
-        if (threadContext != nullptr && threadContext->IsScriptActive())
+        if (threadContext != nullptr)
         {
-            switch (kind) {
-            case ExceptionKind_OutOfMemory:
-                AssertMsg(returnAddress == NULL, "should not have returnAddress passed in");
-                JavascriptError::ThrowOutOfMemoryError(scriptContext);
+            if (kind == ExceptionKind_OutOfMemory &&
+                CONFIG_FLAG(EnableFatalErrorOnOOM) && !threadContext->TestThreadContextFlag(ThreadContextFlagDisableFatalOnOOM))
+            {
+                OutOfMemory_fatal_error();
+            }
 
-            case ExceptionKind_StackOverflow:
-                JavascriptError::ThrowStackOverflowError(scriptContext, returnAddress);
+            if (threadContext->IsScriptActive())
+            {
+                switch (kind) {
+                case ExceptionKind_OutOfMemory:
+                    AssertMsg(returnAddress == NULL, "should not have returnAddress passed in");
+                    JavascriptError::ThrowOutOfMemoryError(scriptContext);
 
-            default:
-                AssertMsg(false, "Invalid ExceptionKind");
+                case ExceptionKind_StackOverflow:
+                    JavascriptError::ThrowStackOverflowError(scriptContext, returnAddress);
+
+                default:
+                    AssertMsg(false, "Invalid ExceptionKind");
+                }
             }
         }
 

+ 1 - 0
lib/Runtime/Base/FunctionBody.cpp

@@ -951,6 +951,7 @@ namespace Js
         this->RedeferFunctionObjectTypes();
 
         this->Cleanup(false);
+
         if (GetIsFuncRegistered())
         {
             this->GetUtf8SourceInfo()->RemoveFunctionBody(this);

+ 1 - 0
lib/Runtime/Base/ScriptContext.cpp

@@ -6336,3 +6336,4 @@ void ScriptContext::RegisterPrototypeChainEnsuredToHaveOnlyWritableDataPropertie
     }
 
 } // End namespace Js
+

+ 1 - 0
lib/Runtime/Base/ScriptContext.h

@@ -1956,3 +1956,4 @@ private:
 #define RELEASE_TEMP_GUEST_ALLOCATOR(allocator, scriptContext) \
     if (tempGuest##allocator) \
     scriptContext->ReleaseTemporaryGuestAllocator(tempGuest##allocator);
+

+ 65 - 3
lib/Runtime/Base/ThreadContext.cpp

@@ -267,6 +267,11 @@ ThreadContext::ThreadContext(AllocationPolicyManager * allocationPolicyManager,
 #endif
 #endif
 
+#if DBG
+    arrayMutationSeed = (Js::Configuration::Global.flags.ArrayMutationTestSeed != 0) ? (uint)Js::Configuration::Global.flags.ArrayMutationTestSeed : (uint)time(NULL);
+    srand(arrayMutationSeed);
+#endif
+
     this->InitAvailableCommit();
 }
 
@@ -1838,7 +1843,8 @@ void ThreadContext::DisposeOnLeaveScript()
 {
     PHASE_PRINT_TRACE1(Js::DisposePhase, _u("[Dispose] NeedDispose in LeaveScriptStart: %d\n"), this->recycler->NeedDispose());
 
-    if (this->callDispose && this->recycler->NeedDispose())
+    if (this->callDispose && this->recycler->NeedDispose()
+        && !recycler->IsCollectionDisabled())
     {
         this->recycler->FinishDisposeObjectsNow<FinishDispose>();
     }
@@ -2508,10 +2514,8 @@ ThreadContext::UnregisterScriptContext(Js::ScriptContext *scriptContext)
     {
         scriptContext->next->prev = scriptContext->prev;
     }
-
     scriptContext->prev = nullptr;
     scriptContext->next = nullptr;
-
 #if DBG || defined(RUNTIME_DATA_COLLECTION)
     scriptContextCount--;
 #endif
@@ -4772,3 +4776,61 @@ AutoTagNativeLibraryEntry::~AutoTagNativeLibraryEntry()
     Assert(threadContext->PeekNativeLibraryEntry() == &entry);
     threadContext->PopNativeLibraryEntry();
 }
+
+#if ENABLE_JS_REENTRANCY_CHECK
+#if DBG
+
+void JsReentLock::setObjectForMutation(Js::Var object)
+{
+    m_arrayObject = nullptr;
+
+    if (object != nullptr && Js::DynamicObject::IsAnyArray(object))
+    {
+        m_arrayObject = object;
+    }
+
+    // Don't care about any other objects for now
+}
+
+void JsReentLock::setSecondObjectForMutation(Js::Var object)
+{
+    m_arrayObject2 = nullptr;
+
+    if (object != nullptr && Js::DynamicObject::IsAnyArray(object))
+    {
+        m_arrayObject2 = object;
+    }
+
+    // Don't care about any other objects for now
+}
+
+void JsReentLock::MutateArrayObject(Js::Var arrayObject)
+{
+    if (arrayObject)
+    {
+        Js::JavascriptArray *arr = Js::JavascriptArray::FromAnyArray(arrayObject);
+        uint32 random = static_cast<unsigned int>(rand());
+
+        if (random % 20 == 0)
+        {
+            arr->DoTypeMutation();
+        }
+        else if (random % 20 == 1)
+        {
+            // TODO : modify the length of the current array
+            //       Or other opportunities
+        }
+    }
+}
+
+void JsReentLock::MutateArrayObject()
+{
+    if (CONFIG_FLAG(EnableArrayTypeMutation))
+    {
+        JsReentLock::MutateArrayObject(m_arrayObject);
+        JsReentLock::MutateArrayObject(m_arrayObject2);
+    }
+}
+
+#endif
+#endif

+ 20 - 0
lib/Runtime/Base/ThreadContext.h

@@ -41,6 +41,7 @@ enum ThreadContextFlags
     ThreadContextFlagCanDisableExecution           = 0x00000001,
     ThreadContextFlagEvalDisabled                  = 0x00000002,
     ThreadContextFlagNoJIT                         = 0x00000004,
+    ThreadContextFlagDisableFatalOnOOM             = 0x00000008,
 };
 
 const int LS_MAX_STACK_SIZE_KB = 300;
@@ -750,6 +751,7 @@ private:
     uint unregisteredInlineCacheCount;
 #if DBG
     uint totalUnregisteredCacheCount;
+    uint arrayMutationSeed; // This is mostly to aid in debugging.
 #endif
 
     typedef JsUtil::BaseDictionary<Js::Var, Js::IsInstInlineCache*, ArenaAllocator, PrimeSizePolicy> IsInstInlineCacheListMapByFunction;
@@ -1835,10 +1837,18 @@ private:
 class JsReentLock
 {
     ThreadContext *m_threadContext;
+#if DBG
+    Js::Var m_arrayObject;
+    Js::Var m_arrayObject2; // This is for adding the second object in the mutation equation.
+#endif
+
     bool m_savedNoJsReentrancy;
 
 public:
     JsReentLock(ThreadContext *threadContext)
+#if DBG
+        : m_arrayObject(nullptr), m_arrayObject2(nullptr)
+#endif
     {
         m_savedNoJsReentrancy = threadContext->GetNoJsReentrancy();
         threadContext->SetNoJsReentrancy(true);
@@ -1848,9 +1858,19 @@ public:
     void unlock() { m_threadContext->SetNoJsReentrancy(m_savedNoJsReentrancy); }
     void relock() { m_threadContext->SetNoJsReentrancy(true); }
 
+#if DBG
+    void setObjectForMutation(Js::Var object);
+    void setSecondObjectForMutation(Js::Var object);
+    void MutateArrayObject();
+#endif
+
     ~JsReentLock()
     {
         m_threadContext->SetNoJsReentrancy(m_savedNoJsReentrancy);
     }
+#if DBG
+private:
+    static void MutateArrayObject(Js::Var arrayObject);
+#endif
 };
 #endif

+ 2 - 2
lib/Runtime/ByteCode/ByteCodeCacheReleaseFileVersion.h

@@ -4,6 +4,6 @@
 //-------------------------------------------------------------------------------------------------------
 // NOTE: If there is a merge conflict the correct fix is to make a new GUID.
 
-// {C6C1CBF8-B232-4E4C-8681-34E404F78F16}
+// {F856871A-E536-4CA1-83E6-819E26C7DC99}
 const GUID byteCodeCacheReleaseFileVersion =
-{ 0xC6C1CBF8, 0xB232, 0x4E4C, { 0x86, 0x81, 0x34, 0xE4, 0x04, 0xF7, 0x8F, 0x16 } };
+{ 0xF856871A, 0xE536, 0x4CA1, { 0x83, 0xE6, 0x81, 0x9E, 0x26, 0xC7, 0xDC, 0x99 } };

+ 5 - 4
lib/Runtime/ByteCode/ByteCodeEmitter.cpp

@@ -2072,7 +2072,7 @@ void ByteCodeGenerator::LoadAllConstants(FuncInfo *funcInfo)
                     this->m_writer.Property(Js::OpCode::StFuncExpr, sym->GetLocation(), scopeLocation,
                         funcInfo->FindOrAddReferencedPropertyId(sym->GetPosition()));
                 }
-                else if (funcInfo->bodyScope->GetIsObject())
+                else if ((funcInfo->paramScope->GetIsObject() || (funcInfo->paramScope->GetCanMerge() && funcInfo->bodyScope->GetIsObject())))
                 {
                     this->m_writer.ElementU(Js::OpCode::StLocalFuncExpr, sym->GetLocation(),
                         funcInfo->FindOrAddReferencedPropertyId(sym->GetPosition()));
@@ -2758,7 +2758,7 @@ void ByteCodeGenerator::EmitOneFunction(ParseNode *pnode)
     // we're generating byte code.
     if (deferParseFunction->IsDeferred() || (funcInfo->originalAttributes & Js::FunctionInfo::Attributes::CanDefer))
     {
-        Js::ScopeInfo::SaveEnclosingScopeInfo(this, funcInfo);        
+        Js::ScopeInfo::SaveEnclosingScopeInfo(this, funcInfo);
     }
 
     if (funcInfo->root->sxFnc.pnodeBody == nullptr)
@@ -3389,7 +3389,7 @@ void ByteCodeGenerator::EmitScopeList(ParseNode *pnode, ParseNode *breakOnBodySc
                 }
                 else
                 {
-                    // if asm.js parse error happened, reparse with asm.js disabled.
+                    // If deferral is not allowed, throw and reparse everything with asm.js disabled.
                     throw Js::AsmJsParseException();
                 }
             }
@@ -7961,7 +7961,6 @@ void EmitNew(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator, FuncInfo* f
     }
     else
     {
-
         uint32 actualArgCount = 0;
 
         if (IsCallOfConstants(pnode))
@@ -7986,8 +7985,10 @@ void EmitNew(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator, FuncInfo* f
 
 
             Js::AuxArray<uint32> *spreadIndices = nullptr;
+
             actualArgCount = EmitArgList(pnode->sxCall.pnodeArgs, Js::Constants::NoRegister, Js::Constants::NoRegister, Js::Constants::NoRegister,
                 false, true, byteCodeGenerator, funcInfo, callSiteId, argCount, pnode->sxCall.hasDestructuring, pnode->sxCall.spreadArgCount, &spreadIndices);
+
             funcInfo->ReleaseLoc(pnode->sxCall.pnodeTarget);
 
             if (pnode->sxCall.spreadArgCount > 0)

+ 1 - 2
lib/Runtime/ByteCode/ByteCodeGenerator.cpp

@@ -1023,10 +1023,9 @@ void ByteCodeGenerator::RestoreScopeInfo(Js::ScopeInfo *scopeInfo, FuncInfo * fu
         if (newFunc)
         {
             func = Anew(alloc, FuncInfo, pfi->GetDisplayName(), alloc, this, nullptr, nullptr, nullptr, pfi);
-            newFunc = true;
         }
 
-
+        // Recursively restore enclosing scope info so outermost scopes/funcs are pushed first.
         this->RestoreScopeInfo(scopeInfo->GetParentScopeInfo(), func);
         this->RestoreOneScope(scopeInfo, func);
 

+ 0 - 1
lib/Runtime/ByteCode/ScopeInfo.h

@@ -43,7 +43,6 @@ namespace Js {
         Field(BYTE) mustInstantiate : 1;       // the scope must be instantiated as an object/array
         Field(BYTE) isCached : 1;              // indicates that local vars and functions are cached across invocations
         Field(BYTE) areNamesCached : 1;
-        Field(BYTE) canMergeWithBodyScope : 1;
         Field(BYTE) hasLocalInClosure : 1;
 
         FieldNoBarrier(Scope *) scope;

+ 2 - 2
lib/Runtime/Debug/Chakra.Runtime.Debug.vcxproj

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <Import Condition="'$(ChakraBuildPathImported)'!='true'" Project="$(SolutionDir)Chakra.Build.Paths.props" />
   <Import Project="$(BuildConfigPropsPath)Chakra.Build.ProjectConfiguration.props" />
@@ -70,7 +70,7 @@
     <ClCompile Include="$(MSBuildThisFileDirectory)TTSnapTypes.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)TTSnapValues.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)TTSupport.cpp" />
-    <ClCompile Include="TTExecutionInfo.cpp" />
+    <ClCompile Include="$(MSBuildThisFileDirectory)TTExecutionInfo.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="DebugContext.h" />

+ 1 - 0
lib/Runtime/Debug/DiagObjectModel.cpp

@@ -644,6 +644,7 @@ namespace Js
                 else if (pFBody->GetPropertyIdsForScopeSlotArray() != nullptr)
                 {
                     uint slotArrayCount = static_cast<uint>(slotArray.GetCount());
+
                     pMembersList = JsUtil::List<DebuggerPropertyDisplayInfo *, ArenaAllocator>::New(arena, slotArrayCount);
 
                     for (uint32 i = 0; i < slotArrayCount; i++)

+ 1 - 1
lib/Runtime/Debug/DiagProbe.cpp

@@ -20,7 +20,7 @@ namespace Js
         stringBuilder(nullptr),
         activeMutationBP(_activeMutationBP)
     {
-        Assert(executingFunction || (stopType == STOP_EXCEPTIONTHROW || stopType == STOP_MUTATIONBREAKPOINT));
+        Assert(executingFunction || (stopType == STOP_EXCEPTIONTHROW || stopType == STOP_MUTATIONBREAKPOINT || stopType == STOP_DOMMUTATIONBREAKPOINT));
     }
 
     FunctionBody* InterpreterHaltState::GetFunction()

+ 2 - 1
lib/Runtime/Debug/DiagProbe.h

@@ -14,7 +14,8 @@ namespace Js
         STOP_STEPCOMPLETE,
         STOP_EXCEPTIONTHROW,
         STOP_ASYNCBREAK,
-        STOP_MUTATIONBREAKPOINT
+        STOP_MUTATIONBREAKPOINT,
+        STOP_DOMMUTATIONBREAKPOINT
     };
 
     struct ReturnedValue

+ 45 - 0
lib/Runtime/Debug/ProbeContainer.cpp

@@ -473,6 +473,51 @@ namespace Js
         return fSuccess;
     }
 
+    void ProbeContainer::DispatchDOMMutationBreakpoint()
+    {
+        InterpreterHaltState haltState(STOP_DOMMUTATIONBREAKPOINT, /*_executingFunction*/nullptr);
+        OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchDOMMutationBreakpoint: start: this=%p, pHaltState=%p\n"), this, haltState);
+        if (!CanDispatchHalt(&haltState))
+        {
+            return;
+        }
+
+        int currentOffset = -1;
+        TryFinally([&]()
+        {
+            InitializeLocation(&haltState);
+            OUTPUT_TRACE(Js::DebuggerPhase, _u("ProbeContainer::DispatchDOMMutationBreakpoint: initialized location: pHaltState=%p, pHaltState->IsValid()=%d\n"),
+                haltState, haltState.IsValid());
+
+            if (haltState.IsValid())
+            {
+                if (haltState.topFrame->IsInterpreterFrame())
+                {
+                    currentOffset = haltState.GetCurrentOffset();
+                    Assert(currentOffset > 0);
+                    haltState.SetCurrentOffset(currentOffset - 1);
+                }
+                debugManager->stepController.Deactivate(&haltState);
+                debugManager->asyncBreakController.Deactivate();
+
+                haltState.GetFunction()->CheckAndRegisterFuncToDiag(pScriptContext);
+
+                Assert(haltState.GetFunction()->GetScriptContext() == pScriptContext);
+
+                haltCallbackProbe->DispatchHalt(&haltState);
+            }
+        },
+            [&](bool)
+        {
+            // Restore the current offset;
+            if (currentOffset != -1 && haltState.topFrame->IsInterpreterFrame())
+            {
+                haltState.SetCurrentOffset(currentOffset);
+            }
+            DestroyLocation();
+        });
+    }
+
     void ProbeContainer::DispatchMutationBreakpoint(InterpreterHaltState* pHaltState)
     {
         Assert(pHaltState->stopType == STOP_MUTATIONBREAKPOINT);

+ 3 - 0
lib/Runtime/Debug/ProbeContainer.h

@@ -137,6 +137,9 @@ namespace Js
         // When on mutation breakpoint hit
         void DispatchMutationBreakpoint(InterpreterHaltState* pHaltState);
 
+        // When DOM mutation breakpoint hit
+        void DispatchDOMMutationBreakpoint();
+
         void UpdateStep(bool fDuringSetupDebugApp = false);
         void DeactivateStep();
 

+ 20 - 0
lib/Runtime/Language/Arguments.h

@@ -85,7 +85,20 @@ inline int _count_args(const T1&, const T2&, const T3&, const T4&, Js::CallInfo
     CALL_ENTRYPOINT_NOASSERT(function->GetEntryPoint(), \
                     function, callInfo, ##__VA_ARGS__)
 
+#if DBG && ENABLE_JS_REENTRANCY_CHECK
+#define SETOBJECT_FOR_MUTATION(reentrancyLock, arrayObject) reentrancyLock.setObjectForMutation(arrayObject)
+#define SET_SECOND_OBJECT_FOR_MUTATION(reentrancyLock, arrayObject) reentrancyLock.setSecondObjectForMutation(arrayObject)
+#define MUTATE_ARRAY_OBJECT(reentrancyLock) reentrancyLock.MutateArrayObject()
+#else
+#define SETOBJECT_FOR_MUTATION(reentrancyLock, arrayObject) 
+#define SET_SECOND_OBJECT_FOR_MUTATION(reentrancyLock, arrayObject) 
+#define MUTATE_ARRAY_OBJECT(reentrancyLock) 
+#endif
+
 #if ENABLE_JS_REENTRANCY_CHECK
+#define JS_REENTRANCY_CHECK(threadContext, ...) \
+    (threadContext->AssertJsReentrancy(), \
+    __VA_ARGS__);
 #define CALL_FUNCTION(threadContext, function, callInfo, ...) \
     (threadContext->AssertJsReentrancy(), \
     CALL_FUNCTION_NOASSERT(function, callInfo, ##__VA_ARGS__));
@@ -93,6 +106,11 @@ inline int _count_args(const T1&, const T2&, const T3&, const T4&, Js::CallInfo
     (threadContext->AssertJsReentrancy(), \
     CALL_ENTRYPOINT_NOASSERT(entryPoint, function, callInfo, ##__VA_ARGS__));
 #define JS_REENTRANT(reentrancyLock, ...) \
+    reentrancyLock.unlock(); \
+    __VA_ARGS__; \
+    MUTATE_ARRAY_OBJECT(reentrancyLock); \
+    reentrancyLock.relock();
+#define JS_REENTRANT_NO_MUTATE(reentrancyLock, ...) \
     reentrancyLock.unlock(); \
     __VA_ARGS__; \
     reentrancyLock.relock();
@@ -108,6 +126,8 @@ inline int _count_args(const T1&, const T2&, const T3&, const T4&, Js::CallInfo
     CALL_ENTRYPOINT_NOASSERT(entryPoint, function, callInfo, ##__VA_ARGS__);
 #define JS_REENTRANT(reentrancyLock, ...) \
     __VA_ARGS__;
+#define JS_REENTRANT_NO_MUTATE(reentrancyLock, ...) \
+    __VA_ARGS__;
 #define JS_REENTRANT_UNLOCK(reentrancyLock, ...) \
     __VA_ARGS__;
 #define JS_REENTRANCY_LOCK(reentrancyLock, threadContext)

+ 1 - 0
lib/Runtime/Language/AsmJsByteCodeGenerator.cpp

@@ -1405,6 +1405,7 @@ namespace Js
             mWriter.EmptyAsm(OpCodeAsmJs::CheckHeap);
             mCompiler->SetUsesHeapBuffer(true);
         }
+
         EndStatement(pnode);
         --mNestedCallCount;
         Assert(mNestedCallCount >= 0);

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 441 - 434
lib/Runtime/Language/AsmJsModule.cpp


+ 1 - 0
lib/Runtime/Language/AsmJsUtils.cpp

@@ -408,6 +408,7 @@ namespace Js
             }
             ++origArgs;
         }
+
         AsmJsModuleInfo::EnsureHeapAttached(func);
 
         // for convenience, lets take the opportunity to return the asm.js entrypoint address

+ 13 - 0
lib/Runtime/Language/InlineCache.cpp

@@ -945,6 +945,13 @@ namespace Js
             return;
         }
 
+        if (this->functionBody->GetScriptContext() == nullptr)
+        {
+            // If caches were made during ScriptContext initialization, and initialization failed the ScriptContext
+            // and InlineCacheAllocator will be freed, so we don't need to do anything during finalization
+            return;
+        }
+
         uint unregisteredInlineCacheCount = 0;
 
         Assert(inlineCaches && size > 0);
@@ -1035,6 +1042,12 @@ namespace Js
             Assert(!inlineCaches);
             return;
         }
+        if (this->javascriptLibrary->scriptContext == nullptr)
+        {
+            // If caches were made during ScriptContext initialization, and initialization failed the ScriptContext
+            // and InlineCacheAllocator will be freed, so we don't need to do anything during finalization
+            return;
+        }
 
         uint unregisteredInlineCacheCount = 0;
 

+ 2 - 1
lib/Runtime/Language/InterpreterStackFrame.cpp

@@ -1919,6 +1919,7 @@ namespace Js
             // when resuming a generator and so it only used here if a frame already exists on the
             // generator object.
             AssertOrFailFastMsg(args.Info.Count == 2 && ((args.Info.Flags & CallFlags_ExtraArg) == CallFlags_None), "Generator ScriptFunctions should only be invoked by generator APIs with the pair of arguments they pass in -- the generator object and a ResumeYieldData pointer");
+
             JavascriptGenerator* generator = JavascriptGenerator::FromVar(args[0]);
             newInstance = generator->GetFrame();
 
@@ -8795,7 +8796,7 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
     {
         if (!PHASE_OFF(ClosureRangeCheckPhase, this->m_functionBody))
         {
-            if (((FrameDisplay*)instance)->GetLength() < slotIndex - Js::FrameDisplay::GetOffsetOfScopes()/sizeof(Var))
+            if (((FrameDisplay*)instance)->GetLength() <= slotIndex - Js::FrameDisplay::GetOffsetOfScopes()/sizeof(Var))
             {
                 Js::Throw::FatalInternalError();
             }

+ 17 - 4
lib/Runtime/Language/JavascriptStackWalker.cpp

@@ -846,15 +846,27 @@ namespace Js
         return false;
     }
 
+    bool AlignAndCheckAddressOfReturnAddressMatch(void* addressOfReturnAddress, void* nativeLibraryEntryAddress)
+    {
+        return addressOfReturnAddress == nativeLibraryEntryAddress
+#if defined(_M_IX86)
+            // Under some odd cases on x86, addressOfReturnAddress and stashed entry address need to be aligned.
+            // This happens when code is generated using two stack pointers. One or both have the address of 
+            // return address offset by 4, 8, or 12.
+            || ((uint)addressOfReturnAddress & ~0xFF) == ((uint)nativeLibraryEntryAddress & ~0xFF)
+#endif
+            ;
+    }
+
     void ** JavascriptStackWalker::GetCurrentArgv() const
     {
         Assert(this->IsJavascriptFrame());
         Assert(this->interpreterFrame != nullptr ||
-               (this->prevNativeLibraryEntry && this->currentFrame.GetAddressOfReturnAddress() == this->prevNativeLibraryEntry->addr) ||
+               (this->prevNativeLibraryEntry && AlignAndCheckAddressOfReturnAddressMatch(this->currentFrame.GetAddressOfReturnAddress(), this->prevNativeLibraryEntry->addr)) ||
                JavascriptFunction::IsNativeAddress(this->scriptContext, (void*)this->currentFrame.GetInstructionPointer()));
 
         bool isNativeAddr = (this->interpreterFrame == nullptr) &&
-                            (!this->prevNativeLibraryEntry || (this->currentFrame.GetAddressOfReturnAddress() != this->prevNativeLibraryEntry->addr));
+                            (!this->prevNativeLibraryEntry || !AlignAndCheckAddressOfReturnAddressMatch(this->currentFrame.GetAddressOfReturnAddress(), this->prevNativeLibraryEntry->addr));
         void ** argv = currentFrame.GetArgv(isNativeAddr, false /*shouldCheckForNativeAddr*/);
         Assert(argv);
         return argv;
@@ -915,8 +927,9 @@ namespace Js
         if (IsLibraryStackFrameEnabled(this->scriptContext) && this->nativeLibraryEntry)
         {
             void* addressOfReturnAddress = this->currentFrame.GetAddressOfReturnAddress();
-            AssertMsg(addressOfReturnAddress <= this->nativeLibraryEntry->addr, "Missed matching native library entry?");
-            if (addressOfReturnAddress == this->nativeLibraryEntry->addr)
+            void* nativeLibraryEntryAddress = this->nativeLibraryEntry->addr;
+            AssertMsg(addressOfReturnAddress <= nativeLibraryEntryAddress, "Missed matching native library entry?");
+            if (AlignAndCheckAddressOfReturnAddressMatch(addressOfReturnAddress, nativeLibraryEntryAddress))
             {
                 this->isNativeLibraryFrame = true;
                 this->shouldDetectPartiallyInitializedInterpreterFrame = false;

+ 20 - 10
lib/Runtime/Library/GlobalObject.cpp

@@ -591,8 +591,9 @@ namespace Js
         // so this Eval acts as the first source compile for scriptContext, transition to debugMode as needed
         scriptContext->TransitionToDebugModeIfFirstSource(/* utf8SourceInfo = */ nullptr);
 
-        JavascriptString *argString = JavascriptString::FromVar(evalArg);
         ScriptFunction *pfuncScript = nullptr;
+        ENTER_PINNED_SCOPE(JavascriptString, argString);
+        argString = JavascriptString::FromVar(evalArg);
         char16 const * sourceString = argString->GetSz();
         charcount_t sourceLen = argString->GetLength();
         FastEvalMapString key(sourceString, sourceLen, moduleID, strictMode, isLibraryCode);
@@ -614,7 +615,6 @@ namespace Js
                 scriptContext->AddToEvalMap(key, isIndirect, pfuncScript);
             }
         }
-
 #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
         else
         {
@@ -674,6 +674,8 @@ namespace Js
         }
 #endif
 
+        LEAVE_PINNED_SCOPE();    // argString
+
         //We shouldn't be serializing eval functions; unless with -ForceSerialized flag
         if (CONFIG_FLAG(ForceSerialized)) {
             pfuncScript->GetFunctionProxy()->EnsureDeserialized();
@@ -1233,7 +1235,8 @@ namespace Js
 
         AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
 
-        JavascriptString *str;
+        double result = 0;
+        ENTER_PINNED_SCOPE(JavascriptString, str);
 
         if(args.Info.Count < 2)
         {
@@ -1271,7 +1274,8 @@ namespace Js
         const char16 *pch = scriptContext->GetCharClassifier()->SkipWhiteSpace(str->GetSz());
 
         // perform the string -> float conversion
-        double result = NumberUtilities::StrToDbl(pch, &pch, scriptContext);
+        result = NumberUtilities::StrToDbl(pch, &pch, scriptContext);
+        LEAVE_PINNED_SCOPE();   // str
 
         return JavascriptNumber::ToVarNoCheck(result, scriptContext);
     }
@@ -1407,9 +1411,11 @@ namespace Js
             return scriptContext->GetLibrary()->GetUndefinedDisplayString();
         }
 
-        JavascriptString *src = JavascriptConversion::ToString(args[1], scriptContext);
+        CompoundString * bs = nullptr;
+        ENTER_PINNED_SCOPE(JavascriptString, src);
+        src = JavascriptConversion::ToString(args[1], scriptContext);
+        bs = CompoundString::NewWithCharCapacity(src->GetLength(), scriptContext->GetLibrary());
 
-        CompoundString *const bs = CompoundString::NewWithCharCapacity(src->GetLength(), scriptContext->GetLibrary());
         char16 chw;
         char16 * pchSrc;
         char16 * pchLim;
@@ -1443,6 +1449,8 @@ namespace Js
             }
         }
 
+        LEAVE_PINNED_SCOPE();   // src
+
         return bs;
     }
 
@@ -1469,10 +1477,10 @@ namespace Js
         char16 * pchLim;
         char16 * pchMin;
 
-        JavascriptString *src = JavascriptConversion::ToString(args[1], scriptContext);
-
-        CompoundString *const bs = CompoundString::NewWithCharCapacity(src->GetLength(), scriptContext->GetLibrary());
-
+        CompoundString * bs = nullptr;
+        ENTER_PINNED_SCOPE(JavascriptString, src);
+        src = JavascriptConversion::ToString(args[1], scriptContext);
+        bs = CompoundString::NewWithCharCapacity(src->GetLength(), scriptContext->GetLibrary());
         pchSrc = const_cast<char16 *>(src->GetString());
         pchLim = pchSrc + src->GetLength();
         while (pchSrc < pchLim)
@@ -1526,6 +1534,8 @@ LHexError:
             bs->AppendChars(chw);
         }
 
+        LEAVE_PINNED_SCOPE();   // src
+
         return bs;
     }
 

+ 25 - 9
lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp

@@ -681,8 +681,10 @@ namespace Js
             return scriptContext->GetLibrary()->GetUndefined();
         }
 
-        JavascriptString *argString = JavascriptString::FromVar(args.Values[1]);
-        PCWSTR passedLocale = argString->GetSz();
+        JavascriptString* toReturn = nullptr;
+        ENTER_PINNED_SCOPE(JavascriptString, localeStrings);
+        localeStrings = JavascriptString::FromVar(args.Values[1]);
+        PCWSTR passedLocale = localeStrings->GetSz();
 
 #if defined(INTL_ICU)
         char16 resolvedLocaleName[ULOC_FULLNAME_CAPACITY] = { 0 };
@@ -706,6 +708,7 @@ namespace Js
             HandleOOMSOEHR(hr);
             return scriptContext->GetLibrary()->GetUndefined();
         }
+
         AutoHSTRING locale;
         if (FAILED(hr = wga->GetResolvedLanguage(formatter, &locale)))
         {
@@ -713,7 +716,11 @@ namespace Js
             return scriptContext->GetLibrary()->GetUndefined();
         }
 
-        return JavascriptString::NewCopySz(wgl->WindowsGetStringRawBuffer(*locale, NULL), scriptContext);
+        toReturn = JavascriptString::NewCopySz(wgl->WindowsGetStringRawBuffer(*locale, NULL), scriptContext);
+
+        LEAVE_PINNED_SCOPE();   // localeStrings
+
+        return toReturn;
 #endif
     }
 
@@ -1217,20 +1224,27 @@ namespace Js
         }
 
         DWORD compareFlags = 0;
-        JavascriptString* str1 = JavascriptString::FromVar(args.Values[1]);
-        JavascriptString* str2 = JavascriptString::FromVar(args.Values[2]);
-
+        int compareResult = 0;
+        DWORD lastError = S_OK;
         WCHAR defaultLocale[LOCALE_NAME_MAX_LENGTH];
         const char16 *givenLocale = nullptr;
         defaultLocale[0] = '\0';
 
+        ENTER_PINNED_SCOPE(JavascriptString, str1);
+        ENTER_PINNED_SCOPE(JavascriptString, str2);
+        ENTER_PINNED_SCOPE(JavascriptString, givenLocaleStr);
+        str1 = JavascriptString::FromVar(args.Values[1]);
+        str2 = JavascriptString::FromVar(args.Values[2]);
+        givenLocaleStr = nullptr;
+
         if (!JavascriptOperators::IsUndefinedObject(args.Values[3]))
         {
             if (!JavascriptString::Is(args.Values[3]))
             {
                 return scriptContext->GetLibrary()->GetUndefined();
             }
-            givenLocale = JavascriptString::FromVar(args.Values[3])->GetSz();
+            givenLocaleStr = JavascriptString::FromVar(args.Values[3]);
+            givenLocale = givenLocaleStr->GetSz();
         }
 
         if (!JavascriptOperators::IsUndefinedObject(args.Values[4]))
@@ -1282,8 +1296,6 @@ namespace Js
             JavascriptError::MapAndThrowError(scriptContext, HRESULT_FROM_WIN32(GetLastError()));
         }
 
-        int compareResult = 0;
-        DWORD lastError = S_OK;
         BEGIN_TEMP_ALLOCATOR(tempAllocator, scriptContext, _u("localeCompare"))
         {
             using namespace PlatformAgnostic;
@@ -1329,6 +1341,10 @@ namespace Js
         }
         END_TEMP_ALLOCATOR(tempAllocator, scriptContext);
 
+        LEAVE_PINNED_SCOPE();   //  str1
+        LEAVE_PINNED_SCOPE();   //  str2
+        LEAVE_PINNED_SCOPE();   //  givenLocaleStr
+
         // CompareStringEx returns 1, 2, 3 on success; 2 if the strings are equal, 1 if the first string is lexically less than second, 3 otherwise.
         if (compareResult != 0)
         {

+ 4 - 1
lib/Runtime/Library/JSON.cpp

@@ -798,8 +798,11 @@ namespace JSON
                                 nameTable[index++] = propertyName;
                             }
 
+                            // If the enumeration changed, assert - We want to identify code that hits this, but don't want to break release cases.
+                            Assert(index == precisePropertyCount);
+
                             // walk the property name list
-                            // Note that we're only walking up to index, not precisePropertyCount, as we only know that we've filled the array up to index
+                            // Note that we're only walking up to index, not precisePropertyCount, as we only know that we've filled the array up to index (in release)
                             for (uint k = 0; k < index; k++)
                             {
                                 propertyName = Js::JavascriptString::FromVar(nameTable[k]);

+ 5 - 1
lib/Runtime/Library/JSONParser.cpp

@@ -43,7 +43,11 @@ namespace JSON
 
     Js::Var JSONParser::Parse(Js::JavascriptString* input)
     {
-        return Parse(input->GetSz(), input->GetLength());
+        Js::Var result = nullptr;
+        EnterPinnedScope((volatile void**)& input);
+        result = Parse(input->GetSz(), input->GetLength());
+        LeavePinnedScope();    // input
+        return result;
     }
 
     Js::Var JSONParser::Walk(Js::JavascriptString* name, Js::PropertyId id, Js::Var holder, uint32 index)

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 223 - 176
lib/Runtime/Library/JavascriptArray.cpp


+ 17 - 3
lib/Runtime/Library/JavascriptArray.h

@@ -84,6 +84,13 @@ namespace Js
         Field(SparseArraySegmentBase *) lastUsedSegment;
     };
 
+    enum ConcatSpreadableState
+    {
+        ConcatSpreadableState_NotChecked,
+        ConcatSpreadableState_CheckedAndFalse,
+        ConcatSpreadableState_CheckedAndTrue
+    };
+
     class JavascriptArray : public ArrayObject
     {
         template <class TPropertyIndex>
@@ -323,6 +330,9 @@ namespace Js
         void CheckForceES5Array();
 #endif
 
+#if DBG
+        void DoTypeMutation();
+#endif
         virtual PropertyQueryFlags HasPropertyQuery(PropertyId propertyId) override;
         virtual BOOL DeleteProperty(PropertyId propertyId, PropertyOperationFlags flags) override;
         virtual BOOL DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags flags) override;
@@ -814,7 +824,7 @@ namespace Js
         };
 
         void GenericDirectSetItemAt(const BigIndex& index, Var newValue) { index.SetItem(this, newValue); }
-        void GenericDirectSetItemAt(const uint32 index, Var newValue) { this->DirectSetItemAt(index, newValue); }
+        void GenericDirectSetItemAt(const uint32 index, Var newValue);
         void DirectSetItemIfNotExist(const BigIndex& index, Var newValue) { index.SetItemIfNotExist(this, newValue); }
         void DirectAppendItem(Var newValue) { BigIndex(this->GetLength()).SetItem(this, newValue); }
         void TruncateToProperties(const BigIndex& index, uint32 start);
@@ -839,9 +849,13 @@ namespace Js
         static void SetConcatItem(Var aItem, uint idxArg, JavascriptArray* pDestArray, RecyclableObject* pDestObj, T idxDest, ScriptContext *scriptContext);
 
         template<typename T>
-        static void ConcatArgs(RecyclableObject* pDestObj, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext, uint start, BigIndex startIdxDest, BOOL firstPromotedItemIsSpreadable, BigIndex firstPromotedItemLength, bool spreadableCheckedAndTrue = false);
+        static void ConcatArgs(RecyclableObject* pDestObj, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext, uint start, 
+            BigIndex startIdxDest, ConcatSpreadableState previousItemSpreadableState = ConcatSpreadableState_NotChecked, BigIndex *firstPromotedItemLength = nullptr);
+
         template<typename T>
-        static void ConcatArgs(RecyclableObject* pDestObj, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext, uint start = 0, uint startIdxDest = 0u, BOOL FirstPromotedItemIsSpreadable = false, BigIndex FirstPromotedItemLength = 0u, bool spreadableCheckedAndTrue = false);
+        static void ConcatArgs(RecyclableObject* pDestObj, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext, uint start = 0, uint startIdxDest = 0u, 
+            ConcatSpreadableState previousItemSpreadableState = ConcatSpreadableState_NotChecked, BigIndex *firstPromotedItemLength = nullptr);
+
         static JavascriptArray* ConcatIntArgs(JavascriptNativeIntArray* pDestArray, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext);
         static bool PromoteToBigIndex(BigIndex lhs, BigIndex rhs);
         static bool PromoteToBigIndex(BigIndex lhs, uint32 rhs);

+ 60 - 2
lib/Runtime/Library/JavascriptArray.inl

@@ -5,6 +5,8 @@
 
 #pragma once
 
+#define Assert_FailFast(x) if (!(x)) { Assert(x); Js::Throw::FatalInternalError(); }
+
 namespace Js
 {
     //
@@ -401,14 +403,65 @@ namespace Js
         return NewLiteral<typename T::TElement, T, InlinePropertySlots>(length, arrayType, arrayType->GetRecycler());
     }
 
-    template<typename T>
+    template <>
+    inline void JavascriptArray::DirectSetItemAt<int32>(uint32 itemIndex, int32 newValue)
+    {
+        Assert_FailFast(this->GetTypeId() == TypeIds_NativeIntArray);
+
+        Assert(itemIndex < InvalidIndex); // Otherwise the code below could overflow and set length = 0
+
+        SparseArraySegment<int32> *seg = (SparseArraySegment<int32>*)this->GetLastUsedSegment();
+        uint32 offset = itemIndex - seg->left;
+        if(itemIndex >= seg->left && offset < seg->size)
+        {
+            DirectSetItemInLastUsedSegmentAt(offset, newValue);
+            return;
+        }
+        DirectSetItem_Full(itemIndex, newValue);
+    }
+
+    template <>
+    inline void JavascriptArray::DirectSetItemAt<double>(uint32 itemIndex, double newValue)
+    {
+        Assert_FailFast(this->GetTypeId() == TypeIds_NativeFloatArray);
+
+        Assert(itemIndex < InvalidIndex); // Otherwise the code below could overflow and set length = 0
+
+        SparseArraySegment<double> *seg = (SparseArraySegment<double>*)this->GetLastUsedSegment();
+        uint32 offset = itemIndex - seg->left;
+        if (itemIndex >= seg->left && offset < seg->size)
+        {
+            DirectSetItemInLastUsedSegmentAt(offset, newValue);
+            return;
+        }
+        DirectSetItem_Full(itemIndex, newValue);
+    }
+
+    template <>
+    inline void JavascriptArray::DirectSetItemAt<Var>(uint32 itemIndex, Var newValue)
+    {
+        Assert_FailFast(this->GetTypeId() == TypeIds_Array || this->GetTypeId() == TypeIds_ES5Array);
+
+        Assert(itemIndex < InvalidIndex); // Otherwise the code below could overflow and set length = 0
+
+        SparseArraySegment<Var> *seg = (SparseArraySegment<Var>*)this->GetLastUsedSegment();
+        uint32 offset = itemIndex - seg->left;
+        if (itemIndex >= seg->left && offset < seg->size)
+        {
+            DirectSetItemInLastUsedSegmentAt(offset, newValue);
+            return;
+        }
+        DirectSetItem_Full(itemIndex, newValue);
+    }
+
+    template <typename T>
     inline void JavascriptArray::DirectSetItemAt(uint32 itemIndex, T newValue)
     {
         Assert(itemIndex < InvalidIndex); // Otherwise the code below could overflow and set length = 0
 
         SparseArraySegment<T> *seg = (SparseArraySegment<T>*)this->GetLastUsedSegment();
         uint32 offset = itemIndex - seg->left;
-        if(itemIndex >= seg->left && offset < seg->size)
+        if (itemIndex >= seg->left && offset < seg->size)
         {
             DirectSetItemInLastUsedSegmentAt(offset, newValue);
             return;
@@ -416,6 +469,11 @@ namespace Js
         DirectSetItem_Full(itemIndex, newValue);
     }
 
+    inline void JavascriptArray::GenericDirectSetItemAt(const uint32 index, Var newValue)
+    {
+        this->DirectSetItemAt(index, newValue);
+    }
+
     template<typename T>
     inline void JavascriptArray::DirectSetItemInLastUsedSegmentAt(const uint32 offset, const T newValue)
     {

+ 28 - 8
lib/Runtime/Library/JavascriptExternalFunction.cpp

@@ -15,21 +15,21 @@ namespace Js
 
     JavascriptExternalFunction::JavascriptExternalFunction(ExternalMethod entryPoint, DynamicType* type)
         : RuntimeFunction(type, &EntryInfo::ExternalFunctionThunk), nativeMethod(entryPoint), signature(nullptr), callbackState(nullptr), initMethod(nullptr),
-        oneBit(1), typeSlots(0), hasAccessors(0), prototypeTypeId(-1), flags(0)
+        oneBit(1), typeSlots(0), hasAccessors(0), flags(0), deferredLength(0)
     {
         DebugOnly(VerifyEntryPoint());
     }
 
     JavascriptExternalFunction::JavascriptExternalFunction(ExternalMethod entryPoint, DynamicType* type, InitializeMethod method, unsigned short deferredSlotCount, bool accessors)
         : RuntimeFunction(type, &EntryInfo::ExternalFunctionThunk), nativeMethod(entryPoint), signature(nullptr), callbackState(nullptr), initMethod(method),
-        oneBit(1), typeSlots(deferredSlotCount), hasAccessors(accessors),prototypeTypeId(-1), flags(0)
+        oneBit(1), typeSlots(deferredSlotCount), hasAccessors(accessors), flags(0), deferredLength(0)
     {
         DebugOnly(VerifyEntryPoint());
     }
 
     JavascriptExternalFunction::JavascriptExternalFunction(DynamicType* type, InitializeMethod method, unsigned short deferredSlotCount, bool accessors)
         : RuntimeFunction(type, &EntryInfo::DefaultExternalFunctionThunk), nativeMethod(nullptr), signature(nullptr), callbackState(nullptr), initMethod(method),
-        oneBit(1), typeSlots(deferredSlotCount), hasAccessors(accessors), prototypeTypeId(-1), flags(0)
+        oneBit(1), typeSlots(deferredSlotCount), hasAccessors(accessors), flags(0), deferredLength(0)
     {
         DebugOnly(VerifyEntryPoint());
     }
@@ -37,26 +37,38 @@ namespace Js
 
     JavascriptExternalFunction::JavascriptExternalFunction(JavascriptExternalFunction* entryPoint, DynamicType* type)
         : RuntimeFunction(type, &EntryInfo::WrappedFunctionThunk), wrappedMethod(entryPoint), callbackState(nullptr), initMethod(nullptr),
-        oneBit(1), typeSlots(0), hasAccessors(0), prototypeTypeId(-1), flags(0)
+        oneBit(1), typeSlots(0), hasAccessors(0), flags(0), deferredLength(0)
     {
         DebugOnly(VerifyEntryPoint());
     }
 
     JavascriptExternalFunction::JavascriptExternalFunction(StdCallJavascriptMethod entryPoint, DynamicType* type)
         : RuntimeFunction(type, &EntryInfo::StdCallExternalFunctionThunk), stdCallNativeMethod(entryPoint), signature(nullptr), callbackState(nullptr), initMethod(nullptr),
-        oneBit(1), typeSlots(0), hasAccessors(0), prototypeTypeId(-1), flags(0)
+        oneBit(1), typeSlots(0), hasAccessors(0), flags(0), deferredLength(0)
     {
         DebugOnly(VerifyEntryPoint());
     }
 
     JavascriptExternalFunction::JavascriptExternalFunction(DynamicType *type)
         : RuntimeFunction(type, &EntryInfo::ExternalFunctionThunk), nativeMethod(nullptr), signature(nullptr), callbackState(nullptr), initMethod(nullptr),
-        oneBit(1), typeSlots(0), hasAccessors(0), prototypeTypeId(-1), flags(0)
+        oneBit(1), typeSlots(0), hasAccessors(0), flags(0), deferredLength(0)
     {
         DebugOnly(VerifyEntryPoint());
     }
 
-    bool __cdecl JavascriptExternalFunction::DeferredInitializer(DynamicObject* instance, DeferredTypeHandlerBase* typeHandler, DeferredInitializeMode mode)
+    bool __cdecl JavascriptExternalFunction::DeferredLengthInitializer(DynamicObject * instance, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode)
+    {
+        Js::JavascriptLibrary::InitializeFunction<true>(instance, typeHandler, mode);
+
+        JavascriptExternalFunction* object = static_cast<JavascriptExternalFunction*>(instance);
+
+        object->UndeferLength(instance->GetScriptContext());
+
+        return true;
+    }
+
+    // Note: non-constructors will probably use JavascriptFunction::InitiailizeFunction for undeferral.
+    bool __cdecl JavascriptExternalFunction::DeferredConstructorInitializer(DynamicObject* instance, DeferredTypeHandlerBase* typeHandler, DeferredInitializeMode mode)
     {
         JavascriptExternalFunction* object = static_cast<JavascriptExternalFunction*>(instance);
         HRESULT hr = E_FAIL;
@@ -100,7 +112,6 @@ namespace Js
         {
             object->SetPropertyWithAttributes(PropertyIds::name, functionName, PropertyConfigurable, nullptr);
         }
-
         return true;
     }
 
@@ -338,6 +349,15 @@ namespace Js
         return DynamicObject::SetPropertyWithAttributes(PropertyIds::length, length, PropertyConfigurable, NULL, PropertyOperation_None, SideEffects_None);
     }
 
+    void JavascriptExternalFunction::UndeferLength(ScriptContext *scriptContext)
+    {
+        if (deferredLength > 0)
+        {
+            SetLengthProperty(Js::JavascriptNumber::ToVar(deferredLength, scriptContext));
+            deferredLength = 0;
+        }
+    }
+
 #if ENABLE_TTD
     TTD::NSSnapObjects::SnapObjectType JavascriptExternalFunction::GetSnapTag_TTD() const
     {

+ 16 - 6
lib/Runtime/Library/JavascriptExternalFunction.h

@@ -26,7 +26,7 @@ namespace Js
         JavascriptExternalFunction(JavascriptExternalFunction* wrappedMethod, DynamicType* type);
         JavascriptExternalFunction(StdCallJavascriptMethod nativeMethod, DynamicType* type);
 
-        virtual BOOL IsExternalFunction() override {return TRUE; }
+        virtual BOOL IsExternalFunction() override { return TRUE; }
         inline void SetSignature(Var signature) { this->signature = signature; }
         Var GetSignature() { return signature; }
         inline void SetCallbackState(void *callbackState) { this->callbackState = callbackState; }
@@ -45,10 +45,18 @@ namespace Js
         ExternalMethod GetNativeMethod() { return nativeMethod; }
         BOOL SetLengthProperty(Var length);
 
-        void SetPrototypeTypeId(JavascriptTypeId prototypeTypeId) { this->prototypeTypeId = prototypeTypeId; }
         void SetExternalFlags(UINT64 flags) { this->flags = flags; }
 
+        unsigned char GetDeferredLength() const { return deferredLength; }
+        void SetDeferredLength(unsigned char deferredLength)
+        {
+            AssertOrFailFastMsg(this->deferredLength == 0, "Deferred length is already pending");
+            this->deferredLength = deferredLength;
+        }
+        void UndeferLength(ScriptContext *scriptContext);
+
     private:
+        Field(UINT64) flags;
         Field(Var) signature;
         Field(void *) callbackState;
         union
@@ -65,16 +73,18 @@ namespace Js
         Field(unsigned int) typeSlots:15;
         // Determines if we need are a dictionary type
         Field(unsigned int) hasAccessors:1;
-        Field(unsigned int) unused:15;
+        Field(unsigned int) unused:7;
 
-        Field(JavascriptTypeId) prototypeTypeId;
-        Field(UINT64) flags;
+        // DOM Direct functions need to be able to set the length at construction time without undeferring the function.
+        // We can store the length here so it can be set at the time of undeferral.
+        Field(unsigned int) deferredLength:8;
 
         static Var ExternalFunctionThunk(RecyclableObject* function, CallInfo callInfo, ...);
         static Var WrappedFunctionThunk(RecyclableObject* function, CallInfo callInfo, ...);
         static Var StdCallExternalFunctionThunk(RecyclableObject* function, CallInfo callInfo, ...);
         static Var DefaultExternalFunctionThunk(RecyclableObject* function, CallInfo callInfo, ...);
-        static bool __cdecl DeferredInitializer(DynamicObject* instance, DeferredTypeHandlerBase* typeHandler, DeferredInitializeMode mode);
+        static bool __cdecl DeferredLengthInitializer(DynamicObject* instance, DeferredTypeHandlerBase* typeHandler, DeferredInitializeMode mode);
+        static bool __cdecl DeferredConstructorInitializer(DynamicObject* instance, DeferredTypeHandlerBase* typeHandler, DeferredInitializeMode mode);
 
         void PrepareExternalCall(Arguments * args);
 

+ 20 - 8
lib/Runtime/Library/JavascriptFunction.cpp

@@ -154,9 +154,14 @@ namespace Js
             || JavascriptOperators::GetTypeId(args[0]) == TypeIds_HostDispatch);
 
         JavascriptString* separator = library->GetCommaDisplayString();
+        JavascriptFunction* pfuncScript;
 
+        ENTER_PINNED_SCOPE(JavascriptString, formals);
+        ENTER_PINNED_SCOPE(JavascriptString, fnBody);
+        fnBody = NULL;
         // Gather all the formals into a string like (fml1, fml2, fml3)
-        JavascriptString *formals = library->GetOpenRBracketString();
+        formals = library->GetOpenRBracketString();
+
         for (uint i = 1; i < args.Info.Count - 1; ++i)
         {
             if (i != 1)
@@ -167,7 +172,6 @@ namespace Js
         }
         formals = JavascriptString::Concat(formals, library->GetNewLineCloseRBracketString());
         // Function body, last argument to Function(...)
-        JavascriptString *fnBody = NULL;
         if (args.Info.Count > 1)
         {
             fnBody = JavascriptConversion::ToString(args.Values[args.Info.Count - 1], scriptContext);
@@ -181,11 +185,13 @@ namespace Js
             0 // " {"  GetSpaceOpenBracketString
             == numberLinesPrependedToAnonymousFunction); // Be sure to add exactly one line to anonymous function
 
-        JavascriptString *bs = functionKind == FunctionKind::Async ?
+        ENTER_PINNED_SCOPE(JavascriptString, bs);
+        bs = functionKind == FunctionKind::Async ?
             library->GetAsyncFunctionAnonymouseString() :
             functionKind == FunctionKind::Generator ?
             library->GetFunctionPTRAnonymousString() :
             library->GetFunctionAnonymousString();
+
         bs = JavascriptString::Concat(bs, formals);
         bs = JavascriptString::Concat(bs, library->GetSpaceOpenBracketString());
         if (fnBody != NULL)
@@ -199,7 +205,6 @@ namespace Js
 
         BOOL strictMode = FALSE;
 
-        JavascriptFunction *pfuncScript;
         FunctionInfo *pfuncInfoCache = NULL;
         char16 const * sourceString = bs->GetSz();
         charcount_t sourceLen = bs->GetLength();
@@ -294,6 +299,10 @@ namespace Js
         }
 #endif
 
+        LEAVE_PINNED_SCOPE();   //  bs
+        LEAVE_PINNED_SCOPE();   //  fnBody
+        LEAVE_PINNED_SCOPE();   //  formals
+
         JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_FUNCTION(pfuncScript, EtwTrace::GetFunctionId(pfuncScript->GetFunctionProxy())));
 
         if (functionKind == FunctionKind::Generator || functionKind == FunctionKind::Async)
@@ -1355,7 +1364,8 @@ dbl_align:
         CheckIsExecutable(function, entryPoint);
 #endif
 
-        return amd64_CallFunction(function, entryPoint, args.Info, args.Info.Count, &args.Values[0]);
+        return JS_REENTRANCY_CHECK(function->GetScriptContext()->GetThreadContext(),
+            amd64_CallFunction(function, entryPoint, args.Info, args.Info.Count, &args.Values[0]));
     }
 #elif defined(_M_ARM)
     extern "C"
@@ -1394,7 +1404,8 @@ dbl_align:
         }
         else
         {
-            varResult = arm_CallFunction((JavascriptFunction*)function, args.Info, args.Values, entryPoint);
+            varResult = JS_REENTRANCY_CHECK(function->GetScriptContext()->GetThreadContext(),
+                arm_CallFunction((JavascriptFunction*)function, args.Info, args.Values, entryPoint));
         }
 
         return varResult;
@@ -1421,7 +1432,8 @@ dbl_align:
 #endif
         Js::Var varResult;
 
-        varResult = arm64_CallFunction((JavascriptFunction*)function, args.Info, args.Values, entryPoint);
+        varResult = JS_REENTRANCY_CHECK(function->GetScriptContext()->GetThreadContext(),
+            arm64_CallFunction((JavascriptFunction*)function, args.Info, args.Values, entryPoint));
 
         return varResult;
     }
@@ -1708,7 +1720,7 @@ LABEL1:
         }
         catch (JavascriptException&)
         {
-                Js::Throw::FatalInternalError();
+            Js::Throw::FatalInternalError();
         }
     }
 

+ 36 - 19
lib/Runtime/Library/JavascriptLibrary.cpp

@@ -547,14 +547,15 @@ namespace Js
         functionWithPrototypeTypeHandler->SetHasKnownSlot0();
 
         externalFunctionWithDeferredPrototypeType = CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptExternalFunction::ExternalFunctionThunk, true /*isShared*/);
+        externalFunctionWithLengthAndDeferredPrototypeType = CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptExternalFunction::ExternalFunctionThunk, true /*isShared*/, /* isLengthAvailable */ true);
         wrappedFunctionWithDeferredPrototypeType = CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptExternalFunction::WrappedFunctionThunk, true /*isShared*/);
         stdCallFunctionWithDeferredPrototypeType = CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptExternalFunction::StdCallExternalFunctionThunk, true /*isShared*/);
         idMappedFunctionWithPrototypeType = DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, JavascriptExternalFunction::ExternalFunctionThunk,
             &SharedIdMappedFunctionWithPrototypeTypeHandler, true, true);
         externalConstructorFunctionWithDeferredPrototypeType = DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, JavascriptExternalFunction::ExternalFunctionThunk,
-            Js::DeferredTypeHandler<Js::JavascriptExternalFunction::DeferredInitializer>::GetDefaultInstance(), true, true);
+            Js::DeferredTypeHandler<Js::JavascriptExternalFunction::DeferredConstructorInitializer>::GetDefaultInstance(), true, true);
         defaultExternalConstructorFunctionWithDeferredPrototypeType = DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, JavascriptExternalFunction::DefaultExternalFunctionThunk,
-            Js::DeferredTypeHandler<Js::JavascriptExternalFunction::DeferredInitializer>::GetDefaultInstance(), true, true);
+            Js::DeferredTypeHandler<Js::JavascriptExternalFunction::DeferredConstructorInitializer>::GetDefaultInstance(), true, true);
 
         if (config->IsES6FunctionNameEnabled())
         {
@@ -571,7 +572,7 @@ namespace Js
         crossSiteIdMappedFunctionWithPrototypeType = DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, scriptContext->CurrentCrossSiteThunk,
             &SharedIdMappedFunctionWithPrototypeTypeHandler, true, true);
         crossSiteExternalConstructFunctionWithPrototypeType = DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, scriptContext->CurrentCrossSiteThunk,
-            Js::DeferredTypeHandler<Js::JavascriptExternalFunction::DeferredInitializer>::GetDefaultInstance(), true, true);
+            Js::DeferredTypeHandler<Js::JavascriptExternalFunction::DeferredConstructorInitializer>::GetDefaultInstance(), true, true);
 
         // Initialize Number types
         numberTypeStatic = StaticType::New(scriptContext, TypeIds_Number, numberPrototype, nullptr);
@@ -842,7 +843,7 @@ namespace Js
         return nullptr;
     }
 
-    template<bool isNameAvailable, bool isPrototypeAvailable>
+    template<bool isNameAvailable, bool isPrototypeAvailable, bool isLengthAvailable = false>
     class InitializeFunctionDeferredTypeHandlerFilter
     {
     public:
@@ -855,15 +856,17 @@ namespace Js
                 return isPrototypeAvailable;
             case PropertyIds::name:
                 return isNameAvailable;
+            case PropertyIds::length:
+                return isLengthAvailable;
             }
             return false;
         }
     };
 
-    template<bool isNameAvailable, bool isPrototypeAvailable>
+    template<bool isNameAvailable, bool isPrototypeAvailable, bool isLengthAvailable>
     DynamicTypeHandler * JavascriptLibrary::GetDeferredFunctionTypeHandlerBase()
     {
-        return DeferredTypeHandler<InitializeFunction<isPrototypeAvailable>, InitializeFunctionDeferredTypeHandlerFilter<isNameAvailable, isPrototypeAvailable>>::GetDefaultInstance();
+        return DeferredTypeHandler<InitializeFunction<isPrototypeAvailable>, InitializeFunctionDeferredTypeHandlerFilter<isNameAvailable, isPrototypeAvailable, isLengthAvailable>>::GetDefaultInstance();
     }
 
     template<bool isNameAvailable, bool isPrototypeAvailable>
@@ -922,11 +925,23 @@ namespace Js
     {
         if (scriptContext->GetConfig()->IsES6FunctionNameEnabled())
         {
-            return JavascriptLibrary::GetDeferredFunctionTypeHandlerBase</*isNameAvailable*/ true>();
+            return JavascriptLibrary::GetDeferredFunctionTypeHandlerBase</* isNameAvailable */ true>();
+        }
+        else
+        {
+            return JavascriptLibrary::GetDeferredFunctionTypeHandlerBase</* isNameAvailable */ false>();
+        }
+    }
+
+    DynamicTypeHandler * JavascriptLibrary::GetDeferredPrototypeFunctionWithLengthTypeHandler(ScriptContext* scriptContext)
+    {
+        if (scriptContext->GetConfig()->IsES6FunctionNameEnabled())
+        {
+            return DeferredTypeHandler<Js::JavascriptExternalFunction::DeferredLengthInitializer, InitializeFunctionDeferredTypeHandlerFilter</* isNameAvailable */ true, /* isPrototypeAvailable */ true, /* isLengthAvailable */ true>>::GetDefaultInstance();
         }
         else
         {
-            return JavascriptLibrary::GetDeferredFunctionTypeHandlerBase</*isNameAvailable*/ false>();
+            return DeferredTypeHandler<Js::JavascriptExternalFunction::DeferredLengthInitializer, InitializeFunctionDeferredTypeHandlerFilter</* isNameAvailable */ false, /* isPrototypeAvailable */ true, /* isLengthAvailable */ true>>::GetDefaultInstance();
         }
     }
 
@@ -980,13 +995,14 @@ namespace Js
         return CreateDeferredPrototypeFunctionTypeNoProfileThunk(this->inDispatchProfileMode ? ProfileEntryThunk : entrypoint);
     }
 
-    DynamicType * JavascriptLibrary::CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared)
+    DynamicType * JavascriptLibrary::CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared, bool isLengthAvailable)
     {
         // Note: the lack of TypeHandler switching here based on the isAnonymousFunction flag is intentional.
         // We can't switch shared typeHandlers and RuntimeFunctions do not produce script code for us to know if a function is Anonymous.
         // As a result we may have an issue where hasProperty would say you have a name property but getProperty returns undefined
         return DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, entrypoint,
-            GetDeferredPrototypeFunctionTypeHandler(scriptContext), isShared, isShared);
+            isLengthAvailable ? GetDeferredPrototypeFunctionWithLengthTypeHandler(scriptContext) : GetDeferredPrototypeFunctionTypeHandler(scriptContext),
+            isShared, isShared);
     }
     DynamicType * JavascriptLibrary::CreateFunctionType(JavascriptMethod entrypoint, RecyclableObject* prototype)
     {
@@ -5660,8 +5676,9 @@ namespace Js
             if (!function->GetFunctionProxy()->GetIsAnonymousFunction())
             {
                 Assert(function->GetFunctionInfo()->IsConstructor() ?
-                    function->GetDynamicType()->GetTypeHandler() == JavascriptLibrary::GetDeferredPrototypeFunctionTypeHandler(this->GetScriptContext()) :
-                    function->GetDynamicType()->GetTypeHandler() == JavascriptLibrary::GetDeferredFunctionTypeHandler());
+                    (function->GetDynamicType()->GetTypeHandler() == JavascriptLibrary::GetDeferredPrototypeFunctionTypeHandler(this->GetScriptContext())
+                        || function->GetDynamicType()->GetTypeHandler() == JavascriptLibrary::GetDeferredPrototypeFunctionWithLengthTypeHandler(this->GetScriptContext()))
+                    : function->GetDynamicType()->GetTypeHandler() == JavascriptLibrary::GetDeferredFunctionTypeHandler());
             }
             else
             {
@@ -5681,11 +5698,12 @@ namespace Js
         else
         {
             DynamicTypeHandler * typeHandler = function->GetDynamicType()->GetTypeHandler();
-            if (typeHandler == JavascriptLibrary::GetDeferredPrototypeFunctionTypeHandler(this->GetScriptContext()))
+            if (typeHandler == JavascriptLibrary::GetDeferredPrototypeFunctionTypeHandler(this->GetScriptContext())
+                || typeHandler == JavascriptLibrary::GetDeferredPrototypeFunctionWithLengthTypeHandler(this->GetScriptContext()))
             {
                 function->ReplaceType(crossSiteDeferredPrototypeFunctionType);
             }
-            else if (typeHandler == Js::DeferredTypeHandler<Js::JavascriptExternalFunction::DeferredInitializer>::GetDefaultInstance())
+            else if (typeHandler == Js::DeferredTypeHandler<Js::JavascriptExternalFunction::DeferredConstructorInitializer>::GetDefaultInstance())
             {
                 function->ReplaceType(crossSiteExternalConstructFunctionWithPrototypeType);
             }
@@ -5698,17 +5716,16 @@ namespace Js
     }
 
     JavascriptExternalFunction*
-    JavascriptLibrary::CreateExternalFunction(ExternalMethod entryPoint, PropertyId nameId, Var signature, JavascriptTypeId prototypeTypeId, UINT64 flags)
+    JavascriptLibrary::CreateExternalFunction(ExternalMethod entryPoint, PropertyId nameId, Var signature, UINT64 flags, bool isLengthAvailable)
     {
         Assert(nameId == 0 || scriptContext->IsTrackedPropertyId(nameId));
-        return CreateExternalFunction(entryPoint, TaggedInt::ToVarUnchecked(nameId), signature, prototypeTypeId, flags);
+        return CreateExternalFunction(entryPoint, TaggedInt::ToVarUnchecked(nameId), signature, flags, isLengthAvailable);
     }
 
     JavascriptExternalFunction*
-    JavascriptLibrary::CreateExternalFunction(ExternalMethod entryPoint, Var nameId, Var signature, JavascriptTypeId prototypeTypeId, UINT64 flags)
+    JavascriptLibrary::CreateExternalFunction(ExternalMethod entryPoint, Var nameId, Var signature, UINT64 flags, bool isLengthAvailable)
     {
-        JavascriptExternalFunction* function = this->CreateIdMappedExternalFunction(entryPoint, externalFunctionWithDeferredPrototypeType);
-        function->SetPrototypeTypeId(prototypeTypeId);
+        JavascriptExternalFunction* function = this->CreateIdMappedExternalFunction(entryPoint, isLengthAvailable ? externalFunctionWithLengthAndDeferredPrototypeType : externalFunctionWithDeferredPrototypeType);
         function->SetExternalFlags(flags);
         function->SetFunctionNameId(nameId);
         function->SetSignature(signature);

+ 9 - 6
lib/Runtime/Library/JavascriptLibrary.h

@@ -298,6 +298,7 @@ namespace Js
         Field(DynamicTypeHandler *) functionTypeHandler;
         Field(DynamicTypeHandler *) functionWithPrototypeTypeHandler;
         Field(DynamicType *) externalFunctionWithDeferredPrototypeType;
+        Field(DynamicType *) externalFunctionWithLengthAndDeferredPrototypeType;
         Field(DynamicType *) wrappedFunctionWithDeferredPrototypeType;
         Field(DynamicType *) stdCallFunctionWithDeferredPrototypeType;
         Field(DynamicType *) idMappedFunctionWithPrototypeType;
@@ -393,6 +394,7 @@ namespace Js
 #endif
 
         Field(JavascriptFunction*) evalFunctionObject;
+        Field(JavascriptFunction*) arrayPrototypeValuesFunction;
         Field(JavascriptFunction*) parseIntFunctionObject;
         Field(JavascriptFunction*) parseFloatFunctionObject;
         Field(JavascriptFunction*) arrayPrototypeToStringFunction;
@@ -1004,6 +1006,7 @@ namespace Js
         DynamicType * CreateDeferredPrototypeAsyncFunctionType(JavascriptMethod entrypoint, bool isAnonymousFunction, bool isShared = false);
 
         static DynamicTypeHandler * GetDeferredPrototypeFunctionTypeHandler(ScriptContext* scriptContext);
+        static DynamicTypeHandler * GetDeferredPrototypeFunctionWithLengthTypeHandler(ScriptContext* scriptContext);
         static DynamicTypeHandler * GetDeferredAnonymousPrototypeFunctionTypeHandler();
         static DynamicTypeHandler * GetDeferredAnonymousPrototypeGeneratorFunctionTypeHandler();
         static DynamicTypeHandler * GetDeferredAnonymousPrototypeAsyncFunctionTypeHandler();
@@ -1011,7 +1014,7 @@ namespace Js
         DynamicTypeHandler * GetDeferredFunctionTypeHandler();
         DynamicTypeHandler * ScriptFunctionTypeHandler(bool noPrototypeProperty, bool isAnonymousFunction);
         DynamicTypeHandler * GetDeferredAnonymousFunctionTypeHandler();
-        template<bool isNameAvailable, bool isPrototypeAvailable = true>
+        template<bool isNameAvailable, bool isPrototypeAvailable = true, bool isLengthAvailable = false>
         static DynamicTypeHandler * GetDeferredFunctionTypeHandlerBase();
         template<bool isNameAvailable, bool isPrototypeAvailable = true>
         static DynamicTypeHandler * GetDeferredGeneratorFunctionTypeHandlerBase();
@@ -1019,7 +1022,7 @@ namespace Js
         static DynamicTypeHandler * GetDeferredAsyncFunctionTypeHandlerBase();
 
         DynamicType * CreateDeferredPrototypeFunctionType(JavascriptMethod entrypoint);
-        DynamicType * CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared = false);
+        DynamicType * CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared = false, bool isLengthAvailable = false);
         DynamicType * CreateFunctionType(JavascriptMethod entrypoint, RecyclableObject* prototype = nullptr);
         DynamicType * CreateFunctionWithLengthType(FunctionInfo * functionInfo);
         DynamicType * CreateFunctionWithLengthAndNameType(FunctionInfo * functionInfo);
@@ -1039,8 +1042,8 @@ namespace Js
         JavascriptNumber* CreateNumber(double value, RecyclerJavascriptNumberAllocator * numberAllocator);
         JavascriptGeneratorFunction* CreateGeneratorFunction(JavascriptMethod entryPoint, GeneratorVirtualScriptFunction* scriptFunction);
         JavascriptAsyncFunction* CreateAsyncFunction(JavascriptMethod entryPoint, GeneratorVirtualScriptFunction* scriptFunction);
-        JavascriptExternalFunction* CreateExternalFunction(ExternalMethod entryPointer, PropertyId nameId, Var signature, JavascriptTypeId prototypeTypeId, UINT64 flags);
-        JavascriptExternalFunction* CreateExternalFunction(ExternalMethod entryPointer, Var nameId, Var signature, JavascriptTypeId prototypeTypeId, UINT64 flags);
+        JavascriptExternalFunction* CreateExternalFunction(ExternalMethod entryPointer, PropertyId nameId, Var signature, UINT64 flags, bool isLengthAvailable = false);
+        JavascriptExternalFunction* CreateExternalFunction(ExternalMethod entryPointer, Var nameId, Var signature, UINT64 flags, bool isLengthAvailable = false);
         JavascriptExternalFunction* CreateStdCallExternalFunction(StdCallJavascriptMethod entryPointer, PropertyId nameId, void *callbackState);
         JavascriptExternalFunction* CreateStdCallExternalFunction(StdCallJavascriptMethod entryPointer, Var name, void *callbackState);
         JavascriptPromiseAsyncSpawnExecutorFunction* CreatePromiseAsyncSpawnExecutorFunction(JavascriptMethod entryPoint, JavascriptGenerator* generator, Var target);
@@ -1334,8 +1337,6 @@ namespace Js
 
 
         static bool __cdecl InitializeGeneratorFunction(DynamicObject* function, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode);
-        template<bool addPrototype>
-        static bool __cdecl InitializeFunction(DynamicObject* function, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode);
 
         static size_t const LibraryFunctionArgC[BuiltinFunction::Count + 1];
         static int const LibraryFunctionFlags[BuiltinFunction::Count + 1];   // returns enum BuiltInFlags.
@@ -1344,6 +1345,8 @@ namespace Js
 #endif
 
     public:
+        template<bool addPrototype>
+        static bool __cdecl InitializeFunction(DynamicObject* function, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode);
         virtual void Finalize(bool isShutdown) override;
 
 #if DBG

+ 4 - 4
lib/Runtime/Library/JavascriptLibraryBase.h

@@ -297,10 +297,6 @@ namespace Js
         Field(JavascriptSymbol*) symbolToPrimitive;
         Field(JavascriptSymbol*) symbolToStringTag;
         Field(JavascriptSymbol*) symbolUnscopables;
-        Field(JavascriptFunction*) arrayPrototypeForEachFunction;
-        Field(JavascriptFunction*) arrayPrototypeKeysFunction;
-        Field(JavascriptFunction*) arrayPrototypeValuesFunction;
-        Field(JavascriptFunction*) arrayPrototypeEntriesFunction;
 
     public:
         Field(ScriptContext*) scriptContext;
@@ -311,6 +307,10 @@ namespace Js
         virtual void Mark(Recycler *recycler) override { AssertMsg(false, "Mark called on object that isn't TrackableObject"); }
 
     protected:
+        Field(JavascriptFunction*) arrayPrototypeForEachFunction;
+        Field(JavascriptFunction*) arrayPrototypeKeysFunction;
+        Field(JavascriptFunction*) arrayPrototypeValuesFunction;
+        Field(JavascriptFunction*) arrayPrototypeEntriesFunction;
         Field(JavascriptFunction*) debugEval;
         Field(JavascriptFunction*) getStackTrace;
 #ifdef EDIT_AND_CONTINUE

+ 4 - 1
lib/Runtime/Library/JavascriptNumber.cpp

@@ -1082,8 +1082,9 @@ namespace Js
         }
 
         JavascriptString *result = nullptr;
+        ENTER_PINNED_SCOPE(JavascriptString, dblStr);
+        dblStr = JavascriptString::FromVar(FormatDoubleToString(value, NumberUtilities::FormatFixed, -1, scriptContext));
 
-        JavascriptString *dblStr = JavascriptString::FromVar(FormatDoubleToString(value, NumberUtilities::FormatFixed, -1, scriptContext));
         const char16* szValue = dblStr->GetSz();
         const size_t szLength = dblStr->GetLength();
 
@@ -1115,6 +1116,8 @@ namespace Js
             }
         }
 
+        LEAVE_PINNED_SCOPE();   //  dblStr
+
         if ( pszToBeFreed )
         {
             HeapDeleteArray(count, pszToBeFreed);

+ 1 - 1
lib/Runtime/Library/JavascriptProxy.cpp

@@ -4,7 +4,6 @@
 //-------------------------------------------------------------------------------------------------------
 #include "RuntimeLibraryPch.h"
 
-
 namespace Js
 {
     BOOL JavascriptProxy::Is(Var obj)
@@ -2191,6 +2190,7 @@ namespace Js
             {
                 newValues = stackArgs;
             }
+
             CallInfo calleeInfo((CallFlags)(args.Info.Flags), newCount);
             if (isNewCall)
             {

+ 18 - 5
lib/Runtime/Library/JavascriptRegularExpression.cpp

@@ -329,7 +329,11 @@ namespace Js
 
     UnifiedRegex::RegexPattern* JavascriptRegExp::CreatePattern(Var aValue, Var options, ScriptContext *scriptContext)
     {
-        JavascriptString * strBody;
+        UnifiedRegex::RegexPattern* pattern = nullptr;
+
+        ENTER_PINNED_SCOPE(JavascriptString, strBody);
+        ENTER_PINNED_SCOPE(JavascriptString, strOptions);
+        strOptions = nullptr;
 
         if (JavascriptString::Is(aValue))
         {
@@ -349,7 +353,6 @@ namespace Js
         int cOpts = 0;
         const char16 *szOptions = nullptr;
 
-        JavascriptString * strOptions = nullptr;
         if (options != nullptr && !JavascriptOperators::IsUndefinedObject(options))
         {
             if (JavascriptString::Is(options))
@@ -365,7 +368,10 @@ namespace Js
             cOpts = strOptions->GetLength();
         }
 
-        UnifiedRegex::RegexPattern* pattern = RegexHelper::CompileDynamic(scriptContext, szRegex, cBody, szOptions, cOpts, false);
+        pattern = RegexHelper::CompileDynamic(scriptContext, szRegex, cBody, szOptions, cOpts, false);
+
+        LEAVE_PINNED_SCOPE();   //strOptions
+        LEAVE_PINNED_SCOPE();   //strBody
 
         return pattern;
     }
@@ -567,7 +573,11 @@ namespace Js
         else
         {
             //compile with a string
-            JavascriptString * strBody;
+            ENTER_PINNED_SCOPE(JavascriptString, strBody);
+            ENTER_PINNED_SCOPE(JavascriptString, strOptions);
+            strBody = nullptr;
+            strOptions = nullptr;
+
             if (JavascriptString::Is(args[1]))
             {
                 strBody = JavascriptString::FromVar(args[1]);
@@ -586,7 +596,6 @@ namespace Js
             int cOpts = 0;
             const char16 *szOptions = nullptr;
 
-            JavascriptString * strOptions = nullptr;
             if (callInfo.Count > 2 && !JavascriptOperators::IsUndefinedObject(args[2]))
             {
                 if (JavascriptString::Is(args[2]))
@@ -601,7 +610,11 @@ namespace Js
                 szOptions = strOptions->GetSz(); // must be null terminated!
                 cOpts = strOptions->GetLength();
             }
+
             pattern = RegexHelper::CompileDynamic(scriptContext, szRegex, cBody, szOptions, cOpts, false);
+
+            LEAVE_PINNED_SCOPE();   //strOptions
+            LEAVE_PINNED_SCOPE();   //strBody
         }
 
         thisRegularExpression->SetPattern(pattern);

+ 103 - 26
lib/Runtime/Library/JavascriptString.cpp

@@ -1060,8 +1060,10 @@ case_2:
         // The indexOf function is intentionally generic; it does not require that its this value be a String object. Therefore, it can be transferred to other kinds of objects for use as a method.
         //
 
-        JavascriptString * pThis;
-        JavascriptString * searchString;
+        int result = -1;
+
+        ENTER_PINNED_SCOPE(JavascriptString, pThis);
+        ENTER_PINNED_SCOPE(JavascriptString, searchString);
 
         GetThisAndSearchStringArguments(args, scriptContext, apiNameForErrorMsg, &pThis, &searchString, isRegExpAnAllowedArg);
 
@@ -1089,8 +1091,6 @@ case_2:
             return position;
         }
 
-        int result = -1;
-
         if (position < pThis->GetLengthAsSignedInt())
         {
             const char16* searchStr = searchString->GetString();
@@ -1118,6 +1118,10 @@ case_2:
                 }
             }
         }
+
+        LEAVE_PINNED_SCOPE();   //  searchString
+        LEAVE_PINNED_SCOPE();   //  pThis
+
         return result;
     }
 
@@ -1137,11 +1141,14 @@ case_2:
         // 2. Let S be ? ToString(O).
         // 3. Let searchStr be ? ToString(searchString).
 
-        JavascriptString * pThis = nullptr;
+        // default search string if the search argument is not provided
+        ENTER_PINNED_SCOPE(JavascriptString, pThis);
+        ENTER_PINNED_SCOPE(JavascriptString, searchArg);
+        pThis = nullptr;
+        searchArg = nullptr;
+
         GetThisStringArgument(args, scriptContext, _u("String.prototype.lastIndexOf"), &pThis);
 
-        // default search string if the search argument is not provided
-        JavascriptString * searchArg;
         if(args.Info.Count > 1)
         {
             if (JavascriptString::Is(args[1]))
@@ -1249,6 +1256,10 @@ case_2:
             }
             --currentPos;
         }
+
+        LEAVE_PINNED_SCOPE(); //pThis
+        LEAVE_PINNED_SCOPE(); //searchArg
+
         return JavascriptNumber::ToVar(-1, scriptContext);
     }
 
@@ -1324,8 +1335,9 @@ case_2:
         }
         AssertMsg(args.Info.Count > 0, "Negative argument count");
 
-        JavascriptString * pThis;
-        JavascriptString * pThat;
+        Var resultVar = scriptContext->GetLibrary()->GetUndefined();
+        ENTER_PINNED_SCOPE(JavascriptString, pThis);
+        ENTER_PINNED_SCOPE(JavascriptString, pThat);
 
         GetThisAndSearchStringArguments(args, scriptContext, _u("String.prototype.localeCompare"), &pThis, &pThat, true);
 
@@ -1380,12 +1392,17 @@ case_2:
             JavascriptError::ThrowRangeError(function->GetScriptContext(),
                 VBSERR_InternalError /* TODO-ERROR: _u("Failed compare operation")*/ );
         }
-        return JavascriptNumber::ToVar(result-2, scriptContext);
+        resultVar = JavascriptNumber::ToVar(result-2, scriptContext);
 #else // !ENABLE_GLOBALIZATION
         // no ICU / or external support for localization. Use c-lib
         const int result = wcscmp(pThisStr, pThatStr);
-        return JavascriptNumber::ToVar(result > 0 ? 1 : result == 0 ? 0 : -1, scriptContext);
+        resultVar = JavascriptNumber::ToVar(result > 0 ? 1 : result == 0 ? 0 : -1, scriptContext);
 #endif
+
+        LEAVE_PINNED_SCOPE();    //  pThat
+        LEAVE_PINNED_SCOPE();    //  pThis
+
+        return resultVar;
     }
 
 
@@ -2081,7 +2098,7 @@ case_2:
 
         if (maxLength > JavascriptString::MaxCharLength)
         {
-            Throw::OutOfMemory();
+            JavascriptError::ThrowRangeError(scriptContext, JSERR_OutOfBoundString);
         }
 
         JavascriptString * fillerString = nullptr;
@@ -2243,6 +2260,8 @@ case_2:
 
     Var JavascriptString::ToCaseCore(JavascriptString* pThis, ToCase toCase)
     {
+        Var resultVar = nullptr;
+        EnterPinnedScope((volatile void**)& pThis);
         charcount_t count = pThis->GetLength();
 
         const char16* inStr = pThis->GetString();
@@ -2302,7 +2321,7 @@ case_2:
             *o++ = *inStr++;
         }
 
-        if(toCase == ToUpper)
+        if (toCase == ToUpper)
         {
 #if DBG
             DWORD converted =
@@ -2324,7 +2343,11 @@ case_2:
             Assert(converted == countToCase);
         }
 
-        return builder.ToString();
+        resultVar = builder.ToString();
+
+        LeavePinnedScope();     //  pThis
+
+        return resultVar;
     }
 
     Var JavascriptString::EntryTrim(RecyclableObject* function, CallInfo callInfo, ...)
@@ -2499,11 +2522,14 @@ case_2:
         Assert(currentString->GetLength() > 0);
         Assert(count > 0);
 
+        charcount_t finalBufferCount = 0;
+        char16* buffer = nullptr;
+        EnterPinnedScope((volatile void**)& currentString);
         const char16* currentRawString = currentString->GetString();
         charcount_t currentLength = currentString->GetLength();
 
-        charcount_t finalBufferCount = UInt32Math::Add(UInt32Math::Mul(count, currentLength), 1);
-        char16* buffer = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), char16, finalBufferCount);
+        finalBufferCount = UInt32Math::Add(UInt32Math::Mul(count, currentLength), 1);
+        buffer = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), char16, finalBufferCount);
 
         if (currentLength == 1)
         {
@@ -2526,6 +2552,8 @@ case_2:
             *bufferDst = '\0';
         }
 
+        LeavePinnedScope();     //  currentString
+
         return JavascriptString::NewWithBuffer(buffer, finalBufferCount - 1, scriptContext);
     }
 
@@ -2545,8 +2573,8 @@ case_2:
         Assert(!(callInfo.Flags & CallFlags_New));
         CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(String_Prototype_startsWith);
 
-        JavascriptString * pThis;
-        JavascriptString * pSearch;
+        ENTER_PINNED_SCOPE(JavascriptString, pThis);
+        ENTER_PINNED_SCOPE(JavascriptString, pSearch);
 
         GetThisAndSearchStringArguments(args, scriptContext, _u("String.prototype.startsWith"), &pThis, &pSearch, false);
 
@@ -2579,6 +2607,9 @@ case_2:
             }
         }
 
+        LEAVE_PINNED_SCOPE();   //  pSearch
+        LEAVE_PINNED_SCOPE();  //  pThis
+
         return scriptContext->GetLibrary()->GetFalse();
     }
 
@@ -2598,8 +2629,8 @@ case_2:
         Assert(!(callInfo.Flags & CallFlags_New));
         CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(String_Prototype_endsWith);
 
-        JavascriptString * pThis;
-        JavascriptString * pSearch;
+        ENTER_PINNED_SCOPE(JavascriptString, pThis);
+        ENTER_PINNED_SCOPE(JavascriptString, pSearch);
 
         GetThisAndSearchStringArguments(args, scriptContext, _u("String.prototype.endsWith"), &pThis, &pSearch, false);
 
@@ -2632,6 +2663,9 @@ case_2:
             }
         }
 
+        LEAVE_PINNED_SCOPE();   //  pSearch
+        LEAVE_PINNED_SCOPE();  //  pThis
+
         return scriptContext->GetLibrary()->GetFalse();
     }
 
@@ -3115,8 +3149,11 @@ case_2:
         charcount_t cchPropertyValue;
         charcount_t cchTotalChars;
         charcount_t ich;
-        JavascriptString * pThis;
-        JavascriptString * pPropertyValue = nullptr;
+        JavascriptString * resultString = nullptr;
+        ENTER_PINNED_SCOPE(JavascriptString, pThis);
+        ENTER_PINNED_SCOPE(JavascriptString, pPropertyValue);
+        pThis = nullptr;
+        pPropertyValue = nullptr;
         const char16 * propertyValueStr = nullptr;
         uint quotesCount = 0;
         const char16 quotStr[] = _u("&quot;");
@@ -3321,13 +3358,18 @@ case_2:
         // Assert we ended at the right place.
         AssertMsg((charcount_t)(pResult - builder.DangerousGetWritableBuffer()) == cchTotalChars, "Exceeded allocated string limit");
 
-        return builder.ToString();
+        resultString = builder.ToString();
+
+        LEAVE_PINNED_SCOPE();   // pThis
+        LEAVE_PINNED_SCOPE();   // pPropertyValue
+
+        return resultString;
     }
     Var JavascriptString::ToLocaleCaseHelper(Var thisObj, bool toUpper, ScriptContext *scriptContext)
     {
         using namespace PlatformAgnostic::UnicodeText;
-
-        JavascriptString * pThis;
+        JavascriptString * resultString = nullptr;
+        ENTER_PINNED_SCOPE(JavascriptString, pThis);
 
         if (JavascriptString::Is(thisObj))
         {
@@ -3367,7 +3409,11 @@ case_2:
             Throw::InternalError();
         }
 
-        return builder.ToString();
+        resultString = builder.ToString();
+
+        LEAVE_PINNED_SCOPE();   // pThis
+
+        return resultString;
     }
 
     int JavascriptString::IndexOfUsingJmpTable(JmpTable jmpTable, const char16* inputStr, charcount_t len, const char16* searchStr, int searchLen, int position)
@@ -3516,6 +3562,16 @@ case_2:
     {
         uint i;
 
+        // We want to pin the strings string and substring because flattening of any of these strings could cause a GC and result in the other string getting collected if it was optimized
+        // away by the compiler. We would normally have called the EnterPinnedScope/LeavePinnedScope methods here but it adds extra call instructions to the assembly code. As Equals
+        // methods could get called a lot of times this can show up as regressions in benchmarks.
+        volatile Js::JavascriptString** keepAliveString1 = (volatile Js::JavascriptString**)& string;
+        volatile Js::JavascriptString** keepAliveString2 = (volatile Js::JavascriptString**)& substring;
+        auto keepAliveLambda = [&]() {
+            UNREFERENCED_PARAMETER(keepAliveString1);
+            UNREFERENCED_PARAMETER(keepAliveString2);
+        };
+
         const char16 *stringOrig = string->GetString();
         uint stringLenOrig = string->GetLength();
         const char16 *stringSz = stringOrig + start;
@@ -3569,6 +3625,16 @@ case_2:
         uint string1Len = string1->GetLength();
         uint string2Len = string2->GetLength();
 
+        // We want to pin the strings string1 and string2 because flattening of any of these strings could cause a GC and result in the other string getting collected if it was optimized
+        // away by the compiler. We would normally have called the EnterPinnedScope/LeavePinnedScope methods here but it adds extra call instructions to the assembly code. As Equals
+        // methods could get called a lot of times this can show up as regressions in benchmarks.
+        volatile Js::JavascriptString** keepAliveString1 = (volatile Js::JavascriptString**)& string1;
+        volatile Js::JavascriptString** keepAliveString2 = (volatile Js::JavascriptString**)& string2;
+        auto keepAliveLambda = [&]() {
+            UNREFERENCED_PARAMETER(keepAliveString1);
+            UNREFERENCED_PARAMETER(keepAliveString2);
+        };
+
         int result = wmemcmp(string1->GetString(), string2->GetString(), min(string1Len, string2Len));
 
         return (result == 0) ? (int)(string1Len - string2Len) : result;
@@ -3914,6 +3980,16 @@ case_2:
         T *leftString = T::FromVar(aLeft);
         T *rightString = T::FromVar(aRight);
 
+        // We want to pin the strings leftString and rightString because flattening of any of these strings could cause a GC and result in the other string getting collected if it was optimized
+        // away by the compiler. We would normally have called the EnterPinnedScope/LeavePinnedScope methods here but it adds extra call instructions to the assembly code. As Equals
+        // methods could get called a lot of times this can show up as regressions in benchmarks.
+        volatile T** keepAliveLeftString = (volatile T**)& leftString;
+        volatile T** keepAliveRightString = (volatile T**)& rightString;
+        auto keepAliveLambda = [&]() {
+            UNREFERENCED_PARAMETER(keepAliveLeftString);
+            UNREFERENCED_PARAMETER(keepAliveRightString);
+        };
+
         if (leftString->GetLength() != rightString->GetLength())
         {
             return false;
@@ -3923,6 +3999,7 @@ case_2:
         {
             return true;
         }
+
         return false;
     }
 

+ 11 - 0
lib/Runtime/Library/JavascriptString.h

@@ -159,6 +159,7 @@ namespace Js
         static Var ToCaseCore(JavascriptString* pThis, ToCase toCase);
         static int IndexOfUsingJmpTable(JmpTable jmpTable, const char16* inputStr, charcount_t len, const char16* searchStr, int searchLen, int position);
         static int LastIndexOfUsingJmpTable(JmpTable jmpTable, const char16* inputStr, charcount_t len, const char16* searchStr, charcount_t searchLen, charcount_t position);
+
         static bool BuildLastCharForwardBoyerMooreTable(JmpTable jmpTable, const char16* searchStr, int searchLen);
         static bool BuildFirstCharBackwardBoyerMooreTable(JmpTable jmpTable, const char16* searchStr, int searchLen);
         static charcount_t ConvertToIndex(Var varIndex, ScriptContext *scriptContext);
@@ -374,6 +375,16 @@ namespace Js
     {
         inline static bool Equals(JavascriptString * str1, JavascriptString * str2)
         {
+            // We want to pin the strings str1 and str2 because flattening of any of these strings could cause a GC and result in the other string getting collected if it was optimized 
+            // away by the compiler. We would normally have called the EnterPinnedScope/LeavePinnedScope methods here but it adds extra call instructions to the assembly code. As Equals 
+            // methods could get called a lot of times this can show up as regressions in benchmarks.
+            volatile Js::JavascriptString** keepAliveString1 = (volatile Js::JavascriptString**)& str1;
+            volatile Js::JavascriptString** keepAliveString2 = (volatile Js::JavascriptString**)& str2;
+            auto keepAliveLambda = [&]() {
+                UNREFERENCED_PARAMETER(keepAliveString1);
+                UNREFERENCED_PARAMETER(keepAliveString2);
+            };
+
             return (str1->GetLength() == str2->GetLength() &&
                 JsUtil::CharacterBuffer<WCHAR>::StaticEquals(str1->GetString(), str2->GetString(), str1->GetLength()));
         }

+ 6 - 2
lib/Runtime/Library/JavascriptSymbol.cpp

@@ -116,10 +116,12 @@ namespace Js
         AssertMsg(args.Info.Count, "Should always have implicit 'this'.");
         ScriptContext* scriptContext = function->GetScriptContext();
         JavascriptLibrary* library = scriptContext->GetLibrary();
+        const Js::PropertyRecord* propertyRecord = nullptr;
 
         Assert(!(callInfo.Flags & CallFlags_New));
 
-        JavascriptString* key;
+        ENTER_PINNED_SCOPE(JavascriptString, key);
+
         if (args.Info.Count > 1)
         {
             key = JavascriptConversion::ToString(args[1], scriptContext);
@@ -132,7 +134,7 @@ namespace Js
         // Search the global symbol registration map for a symbol with description equal to the string key.
         // The map can only have one symbol with that description so if we found a symbol, that is the registered
         // symbol for the string key.
-        const Js::PropertyRecord* propertyRecord = scriptContext->GetThreadContext()->GetSymbolFromRegistrationMap(key->GetString(), key->GetLength());
+        propertyRecord = scriptContext->GetThreadContext()->GetSymbolFromRegistrationMap(key->GetString(), key->GetLength());
 
         // If we didn't find a PropertyRecord in the map, we'll create a new symbol with description equal to the key string.
         // This is the only place we add new PropertyRecords to the map, so we should never have multiple PropertyRecords in the
@@ -142,6 +144,8 @@ namespace Js
             propertyRecord = scriptContext->GetThreadContext()->AddSymbolToRegistrationMap(key->GetString(), key->GetLength());
         }
 
+        LEAVE_PINNED_SCOPE();   //  key
+
         Assert(propertyRecord != nullptr);
 
         return library->CreateSymbol(propertyRecord);

+ 30 - 15
lib/Runtime/Library/RegexHelper.cpp

@@ -323,7 +323,9 @@ namespace Js
         Assert(regExp);
         Assert(input);
 
+        EnterPinnedScope((volatile void**)& input);
         RegexHelperTrace(scriptContext, use, regExp, input->GetString(), input->GetLength());
+        LeavePinnedScope();    // input
     }
 
     static void RegexHelperTrace(ScriptContext* scriptContext, UnifiedRegex::RegexStats::Use use, JavascriptRegExp* regExp, JavascriptString* input, JavascriptString* replace)
@@ -332,7 +334,12 @@ namespace Js
         Assert(input);
         Assert(replace);
 
+        EnterPinnedScope((volatile void**)& input);
+        EnterPinnedScope((volatile void**)& replace);
         RegexHelperTrace(scriptContext, use, regExp, input->GetString(), input->GetLength(), replace->GetString(), replace->GetLength());
+
+        LeavePinnedScope();    // replace
+        LeavePinnedScope();    // input
     }
 #endif
 
@@ -428,7 +435,11 @@ namespace Js
     template <bool updateHistory>
     Var RegexHelper::RegexEs5MatchImpl(ScriptContext* scriptContext, JavascriptRegExp *regularExpression, JavascriptString *input, bool noResult, void *const stackAllocationPointer)
     {
+        JavascriptArray* arrayResult = nullptr;
         UnifiedRegex::RegexPattern* pattern = regularExpression->GetPattern();
+
+        EnterPinnedScope((volatile void**)& input);
+
         const char16* inputStr = input->GetString();
         CharCount inputLength = input->GetLength();
 
@@ -441,18 +452,19 @@ namespace Js
 
 #ifdef REGEX_TRIGRAMS
         UnifiedRegex::TrigramAlphabet* trigramAlphabet = scriptContext->GetTrigramAlphabet();
-        UnifiedRegex::TrigramInfo* trigramInfo= pattern->rep.unified.trigramInfo;
-        if (trigramAlphabet!=NULL && inputLength>=MinTrigramInputLength && trigramInfo!=NULL)
+        UnifiedRegex::TrigramInfo* trigramInfo = pattern->rep.unified.trigramInfo;
+        if (trigramAlphabet != NULL && inputLength >= MinTrigramInputLength && trigramInfo != NULL)
         {
-            if (trigramAlphabet->input==NULL)
-                trigramAlphabet->MegaMatch((char16*)inputStr,inputLength);
-
+            if (trigramAlphabet->input == NULL)
+            {
+                trigramAlphabet->MegaMatch((char16*)inputStr, inputLength);
+            }
             if (trigramInfo->isTrigramPattern)
             {
                 if (trigramInfo->resultCount > 0)
                 {
-                    lastSuccessfulMatch.offset=trigramInfo->offsets[trigramInfo->resultCount-1];
-                    lastSuccessfulMatch.length=UnifiedRegex::TrigramInfo::PatternLength;
+                    lastSuccessfulMatch.offset = trigramInfo->offsets[trigramInfo->resultCount - 1];
+                    lastSuccessfulMatch.length = UnifiedRegex::TrigramInfo::PatternLength;
                 }
                 // else: leave lastMatch undefined
 
@@ -465,7 +477,7 @@ namespace Js
 
                 Assert(pattern->IsGlobal());
 
-                JavascriptArray* arrayResult = CreateMatchResult(stackAllocationPointer, scriptContext, /* isGlobal */ true, pattern->NumGroups(), input);
+                arrayResult = CreateMatchResult(stackAllocationPointer, scriptContext, /* isGlobal */ true, pattern->NumGroups(), input);
                 FinalizeMatchResult(scriptContext, /* isGlobal */ true, arrayResult, lastSuccessfulMatch);
 
                 if (trigramInfo->resultCount > 0)
@@ -480,7 +492,7 @@ namespace Js
                     }
                     else
                     {
-                        for (int k = 0;  k < trigramInfo->resultCount; k++)
+                        for (int k = 0; k < trigramInfo->resultCount; k++)
                         {
                             JavascriptString * str = SubString::New(input, trigramInfo->offsets[k], UnifiedRegex::TrigramInfo::PatternLength);
                             trigramInfo->cachedResult[k] = str;
@@ -505,7 +517,6 @@ namespace Js
 
         const bool isGlobal = pattern->IsGlobal();
         const bool isSticky = pattern->IsSticky();
-        JavascriptArray* arrayResult = 0;
         RegexMatchState state;
 
         // If global = false and sticky = true, set offset = lastIndex, else set offset = 0
@@ -535,7 +546,7 @@ namespace Js
                 if (arrayResult == 0)
                     arrayResult = CreateMatchResult(stackAllocationPointer, scriptContext, isGlobal, pattern->NumGroups(), input);
                 JavascriptString *const matchedString = SubString::New(input, lastActualMatch.offset, lastActualMatch.length);
-                if(isGlobal)
+                if (isGlobal)
                     arrayResult->DirectSetItemAt(globalIndex, matchedString);
                 else
                 {
@@ -549,7 +560,7 @@ namespace Js
             offset = lastActualMatch.offset + max(lastActualMatch.length, static_cast<CharCountOrFlag>(1));
         } while (isGlobal);
         PrimEndMatch(state, scriptContext, pattern);
-        if(updateHistory)
+        if (updateHistory)
         {
             PropagateLastMatch(scriptContext, isGlobal, isSticky, regularExpression, input, lastSuccessfulMatch, lastActualMatch, true, true);
         }
@@ -580,6 +591,8 @@ namespace Js
             FinalizeMatchResult(scriptContext, /* isGlobal */ true, arrayResult, lastSuccessfulMatch);
         }
 
+        LeavePinnedScope();    // input
+
         return arrayResult;
     }
 
@@ -1016,7 +1029,9 @@ namespace Js
                     CharCount substringLength = position - nextSourcePosition;
                     accumulatedResultBuilder.Append(input, nextSourcePosition, substringLength);
 
+                    EnterPinnedScope((volatile void**)& matchStr);
                     appendReplacement(accumulatedResultBuilder, tempAlloc, matchStr, (int) numberOfCapturesToKeep, (Var*)captures, position);
+                    LeavePinnedScope();     // matchStr
 
                     nextSourcePosition = JavascriptRegExp::AddIndex(position, matchStr->GetLength());
                 }
@@ -1186,9 +1201,9 @@ namespace Js
     Var RegexHelper::RegexEs5ReplaceImpl(ScriptContext* scriptContext, JavascriptRegExp* regularExpression, JavascriptString* input, JavascriptFunction* replacefn)
     {
         UnifiedRegex::RegexPattern* pattern = regularExpression->GetPattern();
+        JavascriptString* newString = nullptr;
         const char16* inputStr = input->GetString();
         CharCount inputLength = input->GetLength();
-        JavascriptString* newString = nullptr;
         const int numGroups = pattern->NumGroups();
         Var nonMatchValue = NonMatchValue(scriptContext, false);
         UnifiedRegex::GroupInfo lastMatch; // initially undefined
@@ -1419,8 +1434,8 @@ namespace Js
             CharCount newLength = prefixLength + postfixLength + replace->GetLength();
             BufferStringBuilder bufferString(newLength, match->GetScriptContext());
             bufferString.SetContent(prefixStr, prefixLength,
-                                    replace->GetString(), replace->GetLength(),
-                                    postfixStr, postfixLength);
+                replace->GetString(), replace->GetLength(),
+                postfixStr, postfixLength);
             return bufferString.ToString();
         }
 

+ 15 - 12
lib/Runtime/Library/ScriptFunction.cpp

@@ -232,17 +232,17 @@ namespace Js
             entryPointInfo->jsMethod = entryPoint;
         }
 
-            ProxyEntryPointInfo* oldEntryPointInfo = this->GetScriptFunctionType()->GetEntryPointInfo();
-            if (oldEntryPointInfo
-                && oldEntryPointInfo != entryPointInfo
-                && oldEntryPointInfo->SupportsExpiration())
-            {
-                // The old entry point could be executing so we need root it to make sure
-                // it isn't prematurely collected. The rooting is done by queuing it up on the threadContext
-                ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
+        ProxyEntryPointInfo* oldEntryPointInfo = this->GetScriptFunctionType()->GetEntryPointInfo();
+        if (oldEntryPointInfo
+            && oldEntryPointInfo != entryPointInfo
+            && oldEntryPointInfo->SupportsExpiration())
+        {
+            // The old entry point could be executing so we need root it to make sure
+            // it isn't prematurely collected. The rooting is done by queuing it up on the threadContext
+            ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
 
-                threadContext->QueueFreeOldEntryPointInfoIfInScript((FunctionEntryPointInfo*)oldEntryPointInfo);
-            }
+            threadContext->QueueFreeOldEntryPointInfoIfInScript((FunctionEntryPointInfo*)oldEntryPointInfo);
+        }
 
         this->GetScriptFunctionType()->SetEntryPointInfo(entryPointInfo);
     }
@@ -330,6 +330,10 @@ namespace Js
     {
         FunctionProxy* proxy = this->GetFunctionProxy();
         ParseableFunctionInfo * pFuncBody = proxy->EnsureDeserialized();
+        Var returnStr = nullptr;
+
+        EnterPinnedScope((volatile void**)& inputString);
+
         const char16 * inputStr = inputString->GetString();
         const char16 * paramStr = wcschr(inputStr, _u('('));
 
@@ -347,7 +351,6 @@ namespace Js
         uint prefixStringLength = 0;
         const char16* name = _u("");
         charcount_t nameLength = 0;
-        Var returnStr = nullptr;
 
         if (!isClassMethod)
         {
@@ -381,7 +384,6 @@ namespace Js
         }
         else
         {
-
             if (this->GetFunctionInfo()->IsClassConstructor())
             {
                 name = _u("constructor");
@@ -429,6 +431,7 @@ namespace Js
         returnStr = LiteralString::NewCopyBuffer(funcBodyStr, (charcount_t)totalLength, scriptContext);
 
         LEAVE_PINNED_SCOPE();
+        LeavePinnedScope();     //  inputString
 
         return returnStr;
     }

+ 17 - 4
lib/Runtime/Library/UriHelper.cpp

@@ -9,7 +9,8 @@ namespace Js
     Var UriHelper::EncodeCoreURI(ScriptContext* scriptContext, Arguments& args, unsigned char flags )
     {
         AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
-        JavascriptString * strURI;
+        Var result = nullptr;
+        ENTER_PINNED_SCOPE(JavascriptString, strURI);
         //TODO make sure this string is pinned when the memory recycler is in
         if(args.Info.Count < 2)
         {
@@ -27,7 +28,11 @@ namespace Js
                 strURI = JavascriptConversion::ToString(args[1], scriptContext);
             }
         }
-        return Encode(strURI->GetSz(), strURI->GetLength(), flags, scriptContext);
+
+        result = Encode(strURI->GetSz(), strURI->GetLength(), flags, scriptContext);
+
+        LEAVE_PINNED_SCOPE();   //strURI
+        return result;
     }
 
     unsigned char UriHelper::s_uriProps[128] =
@@ -239,7 +244,10 @@ namespace Js
     Var UriHelper::DecodeCoreURI(ScriptContext* scriptContext, Arguments& args, unsigned char reservedFlags )
     {
         AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
-        JavascriptString * strURI;
+
+        Var result = nullptr;
+        ENTER_PINNED_SCOPE(JavascriptString, strURI);
+
         //TODO make sure this string is pinned when the memory recycler is in
         if(args.Info.Count < 2)
         {
@@ -257,7 +265,12 @@ namespace Js
                 strURI = JavascriptConversion::ToString(args[1], scriptContext);
             }
         }
-        return Decode(strURI->GetSz(), strURI->GetLength(), reservedFlags, scriptContext);
+
+        result = Decode(strURI->GetSz(), strURI->GetLength(), reservedFlags, scriptContext);
+
+        LEAVE_PINNED_SCOPE();   // strURI
+
+        return result;
     }
 
     // The Decode algorithm described in sec. 15.1.3 of the spec. The input string is

+ 8 - 4
lib/Runtime/Library/WabtInterface.cpp

@@ -134,18 +134,22 @@ Js::Var WabtInterface::EntryConvertWast2Wasm(RecyclableObject* function, CallInf
         Js::Var isSpecVar = JavascriptOperators::OP_GetProperty(configObject, PropertyIds::spec, scriptContext);
         isSpecText = JavascriptConversion::ToBool(isSpecVar, scriptContext);
     }
-    JavascriptString* string = (JavascriptString*)args[1];
-    const char16* str = string->GetString();
+
     ArenaAllocator arena(_u("Wast2Wasm"), scriptContext->GetThreadContext()->GetPageAllocator(), Throw::OutOfMemory);
     Context context;
+    size_t wastSize;
+    char* wastBuffer = nullptr;
+
+    ENTER_PINNED_SCOPE(JavascriptString, string);
+    string = (JavascriptString*)args[1];
+    const char16* str = string->GetString();
     context.allocator = &arena;
     context.scriptContext = scriptContext;
 
     size_t origSize = string->GetLength();
-    size_t wastSize;
-    char* wastBuffer = nullptr;
     auto allocator = [&arena](size_t size) {return (utf8char_t*)AnewArray(&arena, byte, size);};
     utf8::WideStringToNarrow(allocator, str, origSize, &wastBuffer, &wastSize);
+    LEAVE_PINNED_SCOPE();   //  string
 
     try
     {

+ 6 - 2
lib/Runtime/Library/WebAssemblyModule.cpp

@@ -174,11 +174,13 @@ Var WebAssemblyModule::EntryCustomSections(RecyclableObject* function, CallInfo
     Var sectionNameVar = args.Info.Count > 2 ? args[2] : scriptContext->GetLibrary()->GetUndefined();
 
     WebAssemblyModule * module = WebAssemblyModule::FromVar(args[1]);
-    JavascriptString * sectionName = JavascriptConversion::ToString(sectionNameVar, scriptContext);
+    Var customSections = nullptr;
+    ENTER_PINNED_SCOPE(JavascriptString, sectionName);
+    sectionName = JavascriptConversion::ToString(sectionNameVar, scriptContext);
     const char16* sectionNameBuf = sectionName->GetString();
     charcount_t sectionNameLength = sectionName->GetLength();
 
-    Var customSections = JavascriptOperators::NewJavascriptArrayNoArg(scriptContext);
+    customSections = JavascriptOperators::NewJavascriptArrayNoArg(scriptContext);
     for (uint32 i = 0; i < module->GetCustomSectionCount(); ++i)
     {
         Wasm::CustomSection customSection = module->GetCustomSection(i);
@@ -196,6 +198,8 @@ Var WebAssemblyModule::EntryCustomSections(RecyclableObject* function, CallInfo
         }
     }
 
+    LEAVE_PINNED_SCOPE();   // sectionName
+
     return customSections;
 }
 

+ 3 - 1
lib/Runtime/Types/PathTypeHandler.cpp

@@ -1549,7 +1549,9 @@ namespace Js
         char16 reason[1024];
         swprintf_s(reason, 1024, _u("Cache not populated."));
 #endif
-        if (useCache && newPrototype->GetInternalProperty(newPrototype, Js::InternalPropertyIds::TypeOfPrototypeObjectDictionary, (Js::Var*)&oldTypeToPromotedTypeMap, nullptr, scriptContext) && oldTypeToPromotedTypeMap != nullptr)
+        if (useCache && newPrototype->GetInternalProperty(newPrototype, Js::InternalPropertyIds::TypeOfPrototypeObjectDictionary, (Js::Var*)&oldTypeToPromotedTypeMap, nullptr, scriptContext)
+            && oldTypeToPromotedTypeMap != nullptr
+            )
         {
             AssertOrFailFast((Js::Var)oldTypeToPromotedTypeMap != scriptContext->GetLibrary()->GetUndefined());
             oldTypeToPromotedTypeMap = reinterpret_cast<TypeTransitionMap*>(oldTypeToPromotedTypeMap);

+ 9 - 7
test/Array/CopyOnAccessArray_bugs.baseline

@@ -28,16 +28,18 @@ PASSED
 PASSED
 *** Running test #11 (10): OS3713376: Accessing COA through proxy
 PASSED
-*** Running test #12 (11): Reflect.defineProperty
+*** Running test #12 (11): Reflect.set
 PASSED
-*** Running test #13 (12): Reflect.set
+*** Running test #13 (12): Reflect.defineProperty
 PASSED
-*** Running test #14 (13): Array.of
+*** Running test #14 (13): Reflect.set
 PASSED
-*** Running test #15 (14): CopyOnAccess in ForInEnumerator - native ints
+*** Running test #15 (14): Array.of
 PASSED
-*** Running test #16 (15): CopyOnAccess in ForInEnumerator - native floats
+*** Running test #16 (15): CopyOnAccess in ForInEnumerator - native ints
 PASSED
-*** Running test #17 (16): CopyOnAccess in for..of - native ints
+*** Running test #17 (16): CopyOnAccess in ForInEnumerator - native floats
 PASSED
-Summary of tests: total executed: 17; passed: 17; failed: 0
+*** Running test #18 (17): CopyOnAccess in for..of - native ints
+PASSED
+Summary of tests: total executed: 18; passed: 18; failed: 0

+ 8 - 0
test/Array/CopyOnAccessArray_bugs.js

@@ -119,6 +119,14 @@ var tests = [
             assert.areEqual('1,0,0,0,0', q.toString(), 'Setting array element through Proxy');
         }
     },
+    {
+        name: "Reflect.set",
+        body: function ()
+        {
+            assert.isTrue(Reflect.set([1950, 1960, 1970, 1980, 1990], "0", 1), "Should be able to set property on int array");
+            assert.isTrue(Reflect.set([1950, 1960.1, 1970, 1980, 1990], "0", 1), "Should be able to set property on float array");
+        }
+    },
     {
         name: "Reflect.defineProperty",
         body: function ()

+ 24 - 1
test/AsmJs/rlexe.xml

@@ -923,6 +923,7 @@
     <default>
       <files>bug12239366.js</files>
       <compile-flags>-lic:1 -bgjit-</compile-flags>
+      <tags>exclude_drt</tags>
     </default>
   </test>
   <test>
@@ -937,6 +938,12 @@
       <files>bugGH2270.js</files>
     </default>
   </test>
+  <test>
+    <default>
+      <files>lotsOfLocals.js</files>
+      <tags>exclude_chk,exclude_razzle</tags>
+    </default>
+  </test>
   <test>
     <default>
       <files>bug9883547.js</files>
@@ -958,7 +965,7 @@
     <default>
       <files>params.js</files>
       <baseline>params.baseline</baseline>
-      <compile-flags>-testtrace:asmjs -args 14000 -endargs</compile-flags>
+      <compile-flags>-testtrace:asmjs -args 14000 -endargs -EnableFatalErrorOnOOM-</compile-flags>
       <!-- todo:: On unix platforms there is more stack available,
            so we need to find the right limit to test in order to not timeout -->
       <tags>exclude_dynapogo,exclude_xplat</tags>
@@ -987,6 +994,22 @@
       <tags>exclude_drt</tags>
     </default>
   </test>
+  <test>
+    <default>
+      <files>badFunctionType.js</files>
+      <baseline>badFunctionType.baseline</baseline>
+      <compile-flags>-testtrace:asmjs</compile-flags>
+      <tags>exclude_drt</tags>
+    </default>
+  </test>
+  <test>
+    <default>
+      <files>badFunctionType.js</files>
+      <baseline>badFunctionType.baseline</baseline>
+      <compile-flags>-testtrace:asmjs</compile-flags>
+      <tags>exclude_drt</tags>
+    </default>
+  </test>
   <test>
     <default>
       <files>exports.js</files>

+ 6 - 6
test/Basics/ScriptFunctionToStrings.js

@@ -92,15 +92,15 @@ var tests = [
     {
         name: "class constructor test",
         body: function ()
-        {
-            // [19.2.3.5] Function.prototype.toString()
-            // The string representation must have the syntax of a FunctionDeclaration, FunctionExpression, GeneratorDeclaration,
-            //     GeneratorExpression, AsyncFunctionDeclaration, AsyncFunctionExpression, ClassDeclaration, ClassExpression, ArrowFunction,
-            //     AsyncArrowFunction, or MethodDefinition depending upon the actual characteristics of the object.
+        {
+            // [19.2.3.5] Function.prototype.toString()
+            // The string representation must have the syntax of a FunctionDeclaration, FunctionExpression, GeneratorDeclaration,
+            //     GeneratorExpression, AsyncFunctionDeclaration, AsyncFunctionExpression, ClassDeclaration, ClassExpression, ArrowFunction,
+            //     AsyncArrowFunction, or MethodDefinition depending upon the actual characteristics of the object.
 
             eval("var qux = class { constructor(){} static func(){} method(){} get getter(){} set setter(v){}}");
             var quxObj = new qux();
-            assert.areEqual("class { constructor(){} static func(){} method(){} get getter(){} set setter(v){}}",
+            assert.areEqual("class { constructor(){} static func(){} method(){} get getter(){} set setter(v){}}",
                 quxObj.constructor.toString(), "The string representation must have the syntax of a ClassExpression");
 
             var qux = class { };

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio