Ver código fonte

Merge remote-tracking branch 'origin/master' into linux

Conflicts fixed in following files:
	test/JSON/jx2.baseline
	test/es5/jx2.baseline
	test/es5/rlexe.xml
	test/es6/rlexe.xml

Also fixed a bug in entrypoint calling in JavascriptArray.cpp
Hitesh Kanwathirtha 9 anos atrás
pai
commit
52c55cd83f
100 arquivos alterados com 3030 adições e 2322 exclusões
  1. 0 1
      Build/Common.Build.Default.props
  2. 65 0
      Build/scripts/add_msbuild_path.cmd
  3. 16 4
      Build/scripts/compose_build.ps1
  4. 98 20
      Build/scripts/finalize_build.ps1
  5. 110 51
      Build/scripts/init_build.ps1
  6. 52 0
      Build/scripts/locate_msbuild.ps1
  7. 7 3
      Build/scripts/pgo/pogo_training.ps1
  8. 143 0
      Build/scripts/pogo_build.ps1
  9. 32 24
      Build/scripts/post_build.ps1
  10. 70 54
      Build/scripts/pre_build.ps1
  11. 54 22
      Build/scripts/pre_post_util.ps1
  12. 85 0
      Build/scripts/run_build.ps1
  13. 28 5
      Build/scripts/util.ps1
  14. 8 0
      README.md
  15. 3 2
      bin/ch/Debugger.cpp
  16. 3 3
      lib/Backend/BackwardPass.cpp
  17. 132 59
      lib/Backend/BailOut.cpp
  18. 8 8
      lib/Backend/BailOut.h
  19. 8 23
      lib/Backend/FlowGraph.cpp
  20. 2 2
      lib/Backend/FlowGraph.h
  21. 10 0
      lib/Backend/Func.cpp
  22. 1 0
      lib/Backend/Func.h
  23. 53 50
      lib/Backend/GlobOpt.cpp
  24. 1 2
      lib/Backend/GlobOpt.h
  25. 2 2
      lib/Backend/GlobOptFields.cpp
  26. 2 2
      lib/Backend/IR.cpp
  27. 1 1
      lib/Backend/IR.h
  28. 7 1
      lib/Backend/Lower.cpp
  29. 0 126
      lib/Backend/LowerMDSharedSimd128.cpp
  30. 27 5
      lib/Backend/NativeCodeGenerator.cpp
  31. 5 0
      lib/Common/Common/NumberUtilities.cpp
  32. 10 6
      lib/Common/ConfigFlagsList.h
  33. 0 1
      lib/Common/Core/ProfileInstrument.cpp
  34. 1 2
      lib/Common/Core/ProfileInstrument.h
  35. 5 0
      lib/Common/Memory/ArenaAllocator.cpp
  36. 6 5
      lib/Common/Memory/HeapAllocator.cpp
  37. 5 0
      lib/Common/Memory/HeapBlockMap.cpp
  38. 7 0
      lib/Common/Memory/HeapInfo.cpp
  39. 2 0
      lib/Common/Memory/Recycler.cpp
  40. 8 2
      lib/Common/Memory/Recycler.h
  41. 23 2
      lib/Jsrt/ChakraDebug.h
  42. 20 12
      lib/Jsrt/JsrtDebugManager.cpp
  43. 2 2
      lib/Jsrt/JsrtDebugManager.h
  44. 1 3
      lib/Jsrt/JsrtDebugUtils.cpp
  45. 3 3
      lib/Jsrt/JsrtDebugUtils.h
  46. 36 11
      lib/Jsrt/JsrtDebuggerObject.cpp
  47. 1 1
      lib/Jsrt/JsrtDebuggerObject.h
  48. 5 4
      lib/Jsrt/JsrtDiag.cpp
  49. 2 2
      lib/Jsrt/JsrtInternal.h
  50. 6 1
      lib/Parser/CharSet.cpp
  51. 5 0
      lib/Parser/CharTrie.cpp
  52. 2 28
      lib/Parser/Parse.cpp
  53. 0 3
      lib/Parser/Parse.h
  54. 5 0
      lib/Parser/RegexCompileTime.cpp
  55. 11 0
      lib/Parser/rterrors.h
  56. 5 0
      lib/Runtime/Base/Constants.cpp
  57. 13 0
      lib/Runtime/Base/FunctionBody.cpp
  58. 22 8
      lib/Runtime/Base/FunctionBody.h
  59. 0 2
      lib/Runtime/Base/JnDirectFields.h
  60. 48 41
      lib/Runtime/Base/ScriptContext.cpp
  61. 58 5
      lib/Runtime/Base/ThreadContext.cpp
  62. 7 4
      lib/Runtime/Base/ThreadContext.h
  63. 7 25
      lib/Runtime/ByteCode/ByteCodeEmitter.cpp
  64. 0 3
      lib/Runtime/ByteCode/OpCodesSimd.h
  65. 13 5
      lib/Runtime/Debug/DebugContext.cpp
  66. 2 2
      lib/Runtime/Debug/DebugManager.cpp
  67. 2 3
      lib/Runtime/Debug/DebugManager.h
  68. 0 2
      lib/Runtime/Language/AsmJsBuiltInNames.h
  69. 0 2
      lib/Runtime/Language/AsmJsModule.cpp
  70. 2 0
      lib/Runtime/Language/DynamicProfileInfo.cpp
  71. 8 1
      lib/Runtime/Language/DynamicProfileInfo.h
  72. 0 3
      lib/Runtime/Language/InterpreterHandlerAsmJs.inl
  73. 12 0
      lib/Runtime/Language/InterpreterStackFrame.cpp
  74. 2 1
      lib/Runtime/Language/JavascriptOperators.cpp
  75. 268 235
      lib/Runtime/Language/JavascriptStackWalker.cpp
  76. 19 14
      lib/Runtime/Language/JavascriptStackWalker.h
  77. 18 0
      lib/Runtime/Language/ProfilingHelpers.cpp
  78. 8 0
      lib/Runtime/Language/ReadOnlyDynamicProfileInfo.h
  79. 0 43
      lib/Runtime/Language/SimdFloat32x4Operation.cpp
  80. 0 4
      lib/Runtime/Language/SimdFloat32x4Operation.h
  81. 0 58
      lib/Runtime/Language/SimdFloat32x4OperationX86X64.cpp
  82. 0 1
      lib/Runtime/Language/amd64/JavascriptOperatorsA.asm
  83. 5 0
      lib/Runtime/Library/ConcatString.cpp
  84. 293 293
      lib/Runtime/Library/InJavascript/Intl.js.bc.32b.h
  85. 293 293
      lib/Runtime/Library/InJavascript/Intl.js.bc.64b.h
  86. 291 291
      lib/Runtime/Library/InJavascript/Intl.js.nojit.bc.32b.h
  87. 291 291
      lib/Runtime/Library/InJavascript/Intl.js.nojit.bc.64b.h
  88. 9 9
      lib/Runtime/Library/JSONParser.cpp
  89. 1 1
      lib/Runtime/Library/JSONParser.h
  90. 17 17
      lib/Runtime/Library/JSONScanner.cpp
  91. 9 2
      lib/Runtime/Library/JSONScanner.h
  92. 34 25
      lib/Runtime/Library/JavascriptArray.cpp
  93. 2 0
      lib/Runtime/Library/JavascriptArray.h
  94. 0 2
      lib/Runtime/Library/JavascriptBuiltInFunctionList.h
  95. 11 10
      lib/Runtime/Library/JavascriptFunction.cpp
  96. 1 4
      lib/Runtime/Library/JavascriptLibrary.cpp
  97. 5 0
      lib/Runtime/Library/JavascriptRegExpConstructor.cpp
  98. 50 5
      lib/Runtime/Library/JavascriptString.cpp
  99. 5 0
      lib/Runtime/Library/ProfileString.cpp
  100. 0 59
      lib/Runtime/Library/SimdFloat32x4Lib.cpp

+ 0 - 1
Build/Common.Build.Default.props

@@ -43,7 +43,6 @@
   <!-- Change configuration name to output to a different folder -->
   <!-- POGO instrumentation -->
   <PropertyGroup>
-    <IsPogoBuild />
     <IsPogoBuild Condition="('$(POGO_TYPE)'=='PGO' OR '$(POGO_TYPE)'=='PGI')">true</IsPogoBuild>
     <OutDirName Condition="'$(IsPogoBuild)'=='true'">$(Configuration.ToLower())_pogo</OutDirName>
   </PropertyGroup>

+ 65 - 0
Build/scripts/add_msbuild_path.cmd

@@ -0,0 +1,65 @@
+::-------------------------------------------------------------------------------------------------------
+:: Copyright (C) Microsoft. All rights reserved.
+:: Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+::-------------------------------------------------------------------------------------------------------
+
+:: add_msbuild_path.cmd
+::
+:: Locate msbuild.exe and add it to the PATH
+
+set USE_MSBUILD_12=%1
+
+if "%USE_MSBUILD_12%" == "True" (
+    echo Skipping Dev14 and trying Dev12...
+    goto :LABEL_USE_MSBUILD_12
+)
+
+where /q msbuild.exe
+if "%ERRORLEVEL%" == "0" (
+    goto :SkipMsBuildSetup
+)
+
+REM Try Dev14 first
+set MSBUILD_VERSION=14.0
+set MSBUILD_PATH="%ProgramFiles%\msbuild\%MSBUILD_VERSION%\Bin\x86"
+
+if not exist %MSBUILD_PATH%\msbuild.exe (
+    set MSBUILD_PATH="%ProgramFiles(x86)%\msbuild\%MSBUILD_VERSION%\Bin"
+)
+
+if not exist %MSBUILD_PATH%\msbuild.exe (
+    set MSBUILD_PATH="%ProgramFiles(x86)%\msbuild\%MSBUILD_VERSION%\Bin\amd64"
+)
+
+if exist %MSBUILD_PATH%\msbuild.exe (
+    goto :MSBuildFound
+)
+
+echo Dev14 not found, trying Dev12...
+
+:LABEL_USE_MSBUILD_12
+set MSBUILD_VERSION=12.0
+set MSBUILD_PATH="%ProgramFiles%\msbuild\%MSBUILD_VERSION%\Bin\x86"
+echo Dev14 not found, trying Dev %MSBUILD_VERSION%
+
+if not exist %MSBUILD_PATH%\msbuild.exe (
+    set MSBUILD_PATH="%ProgramFiles(x86)%\msbuild\%MSBUILD_VERSION%\Bin"
+)
+
+if not exist %MSBUILD_PATH%\msbuild.exe (
+    set MSBUILD_PATH="%ProgramFiles(x86)%\msbuild\%MSBUILD_VERSION%\Bin\amd64"
+)
+
+if not exist %MSBUILD_PATH%\msbuild.exe (
+    echo Can't find msbuild.exe in %MSBUILD_PATH%
+    goto :SkipMsBuildSetup
+)
+
+:MSBuildFound
+echo MSBuild located at %MSBUILD_PATH%
+
+set PATH=%MSBUILD_PATH%;%PATH%
+set USE_MSBUILD_12=
+set MSBUILD_PATH=
+
+:SkipMsBuildSetup

+ 16 - 4
Build/scripts/compose_build.ps1

@@ -17,17 +17,29 @@ param (
 # Aggregate build metadata and produce build.json
 #
 
-$outputJsonFile = Join-Path -Path $rootPath -ChildPath "build.json"
+$outputJsonFile = Join-Path $rootPath "build.json"
 $buildInfo = New-Object System.Object
 
-$changeJson = (Get-ChildItem -Path $rootPath "change.json" -Recurse)[0] | % { $_.FullName }
+$changeJson = (Get-ChildItem -Path $rootPath "change.json" -Recurse)[0].FullName
+$changeText = (Get-ChildItem -Path $rootPath "change.txt"  -Recurse)[0].FullName
+Copy-Item -Verbose -Force -Path $changeJson -Destination $rootPath
+Copy-Item -Verbose -Force -Path $changeText -Destination $rootPath
+
 $changeInfo = (Get-Content $changeJson) -join "`n" | ConvertFrom-Json
 
+# Recursively locate ${arch}_${flavor}.json and move to $rootPath.
+# This ensures that in the rebuild scenario, we don't have duplication of *.json files
+# between the partially-composed root and the metadata directories.
+
+Get-ChildItem -Path $rootPath "*.json" -Recurse `
+    | ? { -not ($_.Name -in @("change.json", "build.json")) } `
+    | % { Move-Item -Verbose -Force -Path $_.FullName -Destination $rootPath }
+
 # Determine the overall build status. Mark the build as "passed" until "failed" is encountered.
 $overallBuildStatus = "passed"
 
 $files = Get-ChildItem -Path $rootPath "*.json" -Recurse `
-    | ? { ($_.Name -ne "change.json") -and ($_.Name -ne "build.json") } `
+    | ? { -not ($_.Name -in @("change.json", "build.json")) } `
     | % { $_.FullName }
 $builds = New-Object System.Collections.ArrayList
 foreach ($file in $files) {
@@ -44,4 +56,4 @@ $buildInfo | Add-Member -type NoteProperty -name change -value $changeInfo
 $buildInfo | Add-Member -type NoteProperty -name builds -value $builds
 
 $buildInfo | ConvertTo-Json | Write-Output
-$buildInfo | ConvertTo-Json | Out-File $outputJsonFile -Encoding ascii
+$buildInfo | ConvertTo-Json | Out-File $outputJsonFile -Encoding Ascii

+ 98 - 20
Build/scripts/finalize_build.ps1

@@ -8,16 +8,28 @@
 # This script is run as the final step in a build definition
 # to clean up and produce metadata about the build.
 
-#
-# Copy _pogo binary folder, if present.
-#
+param (
+    [Parameter(Mandatory=$True)]
+    [ValidateSet("x86", "x64", "arm")]
+    [string]$arch,
 
-$PogoFolder = Join-Path $Env:BinariesDirectory "bin\${Env:BuildType}_pogo"
-if (Test-Path $PogoFolder) {
-    $BinDropPath = Join-Path $Env:DropPath "bin"
-    Write-Output "Copying `"$PogoFolder`" to `"$BinDropPath`"..."
-    Copy-Item $PogoFolder $BinDropPath -Recurse -Force
-}
+    [Parameter(Mandatory=$True)]
+    [ValidateSet("debug", "release", "test", "codecoverage")]
+    [string]$flavor,
+
+    [ValidateSet("default", "codecoverage", "pogo")]
+    [string]$subtype = "default",
+
+    $corePathSegment = "" # e.g. "core"
+)
+
+$sourcesDir = $Env:BUILD_SOURCESDIRECTORY
+$coreSourcesDir = Join-Path $sourcesDir $corePathSegment
+
+$OuterScriptRoot = $PSScriptRoot
+. "$PSScriptRoot\pre_post_util.ps1"
+
+$buildName = ConstructBuildName -arch $arch -flavor $flavor -subtype $subtype
 
 #
 # Clean up the sentinel which previously marked this build flavor as incomplete.
@@ -25,30 +37,96 @@ if (Test-Path $PogoFolder) {
 
 Remove-Item -Path $Env:FlavorBuildIncompleteFile -Force
 
+#
+# Copy all logs to DropPath
+#
+
+$buildlogsDropPath = Join-Path $Env:DropPath "buildlogs"
+$logsDropPath = Join-Path $Env:DropPath "logs"
+$testlogsDropPath = Join-Path $Env:DropPath "testlogs"
+
+New-Item -Force -ItemType Directory -Path $buildlogsDropPath
+New-Item -Force -ItemType Directory -Path $logsDropPath
+New-Item -Force -ItemType Directory -Path $testlogsDropPath
+
+$buildlogsSourcePath = Join-Path $Env:BinariesDirectory "buildlogs"
+$logsSourcePath = Join-Path $Env:BinariesDirectory "logs"
+$testlogsSourcePath = Join-Path $Env:BinariesDirectory "testlogs"
+
+if (Test-Path $buildlogsSourcePath) {
+    Copy-Item -Verbose -Recurse -Force (Join-Path $buildlogsSourcePath "*") $buildlogsDropPath
+}
+if (Test-Path $logsSourcePath) {
+    Copy-Item -Verbose -Recurse -Force (Join-Path $logsSourcePath "*") $logsDropPath
+}
+if (Test-Path $testlogsSourcePath) {
+    Copy-Item -Verbose -Recurse -Force (Join-Path $testlogsSourcePath "*") $testlogsDropPath
+}
+
 #
 # Create build status JSON file for this flavor.
 #
 
-$BuildLogsPath = Join-Path $Env:DropPath "buildlogs"
-$buildFlavorErrFile = Join-Path $BuildLogsPath "build_${Env:BuildPlatform}${Env:BuildConfiguration}.err"
+$buildErrFile = Join-Path $buildLogsDropPath "build.${buildName}.err"
+$testSummaryFile = Join-Path $testLogsDropPath "summary.${arch}${flavor}.log"
 
-# If build_{}{}.err contains any text then there were build errors and we record that the build failed.
-$BuildFailed = $false
-if (Test-Path $buildFlavorErrFile) {
-    $BuildFailed = (Get-Item $buildFlavorErrFile).length -gt 0
+# if build.*.err contains any text then there were build errors
+$BuildSucceeded = $true
+if (Test-Path $buildErrFile) {
+    # build errors file has non-zero length iff the build failed
+    $BuildSucceeded = (Get-Item $buildErrFile).length -eq 0
 }
 
-$status = "passed"
-if ($BuildFailed) {
-    $status = "failed"
+# if summary.*.err contains any text then there were test failures
+$TestsPassed = $true
+if (Test-Path $testSummaryFile) {
+    # summary file has non-zero length iff the tests failed
+    $TestsPassed = (Get-Item $testSummaryFile).length -eq 0
 }
 
-$buildFlavorJsonFile = Join-Path $Env:DropPath "${Env:BuildType}.json"
+$Status = "passed"
+if ((-not $BuildSucceeded) -or (-not $TestsPassed)) {
+    $Status = "failed"
+}
+
+$buildFlavorJsonFile = Join-Path $Env:DropPath "${Env:BuildName}.json"
 $buildFlavorJson = New-Object System.Object
 
-$buildFlavorJson | Add-Member -type NoteProperty -name status -value $status
+$buildFlavorJson | Add-Member -type NoteProperty -name buildName -value $Env:BuildName
+$buildFlavorJson | Add-Member -type NoteProperty -name status -value $Status
+$buildFlavorJson | Add-Member -type NoteProperty -name BuildSucceeded -value $BuildSucceeded
+$buildFlavorJson | Add-Member -type NoteProperty -name testsPassed -value $TestsPassed
 $buildFlavorJson | Add-Member -type NoteProperty -name arch -value $Env:BuildPlatform
 $buildFlavorJson | Add-Member -type NoteProperty -name flavor -value $Env:BuildConfiguration
+$buildFlavorJson | Add-Member -type NoteProperty -name subtype -value $Env:BuildSubtype
 
 $buildFlavorJson | ConvertTo-Json | Write-Output
 $buildFlavorJson | ConvertTo-Json | Out-File $buildFlavorJsonFile -Encoding ascii
+
+#
+# Copy outputs to metadata directory
+#
+
+$metadataDir = Join-Path $coreSourcesDir "metadata"
+New-Item -Force -ItemType Directory -Path $metadataDir
+
+Copy-Item -Verbose -Force (Join-Path $sourcesDir "ComputedEnvironment.cmd") $metadataDir
+Copy-Item -Verbose -Force (Join-Path $coreSourcesDir "Build\scripts\compose_build.ps1") $metadataDir
+Copy-Item -Verbose -Force (Join-Path $Env:BinariesDirectory "change.json") $metadataDir
+Copy-Item -Verbose -Force (Join-Path $Env:BinariesDirectory "change.txt") $metadataDir
+Copy-Item -Verbose -Force $buildFlavorJsonFile $metadataDir
+
+# Search for *.nuspec files and copy them to $metadataDir
+Get-ChildItem -Path (Join-Path $sourcesDir "Build") "*.nuspec" `
+    | % { Copy-Item -Verbose -Force $_.FullName $metadataDir }
+
+#
+# Copy POGO directory if present for this build
+#
+
+$PogoFolder = Join-Path $Env:BinariesDirectory "bin\${Env:BuildType}_pogo"
+if (Test-Path $PogoFolder) {
+    $BinDropPath = Join-Path $Env:DropPath "bin"
+    Write-Output "Copying `"$PogoFolder`" to `"$BinDropPath`"..."
+    Copy-Item -Verbose $PogoFolder $BinDropPath -Recurse -Force
+}

+ 110 - 51
Build/scripts/init_build.ps1

@@ -8,62 +8,99 @@
 # Run this as the very first step in the build to configure the environment.
 # This is distinct from the Pre-Build script as there may be more non-script steps that need to be
 # taken before setting up and running the build.
-# For example, this script creates a cmd script which should be run to initialize environment variables.
+# For example, this script creates a cmd script which should be run to initialize environment variables
+# before running the Pre-Build script.
 
 param (
-    [string]$envconfig = "ComputedEnvironment.cmd",
+    [string]$envConfigScript = "ComputedEnvironment.cmd",
 
-    [string[]]$SupportedPogoBuildTypes = @("x64_release", "x86_release"),
+    [string[]]$supportedPogoBuildTypes = @("x64_release", "x86_release"),
 
     [Parameter(Mandatory=$True)]
     [string]$oauth
 )
 
-$branch = $env:BUILD_SOURCEBRANCH
+# If $Env:BuildType is specified, extract BuildPlatform and BuildConfiguration
+# Otherwise, if $Env:BuildPlatform and $Env:BuildConfiguration are specified, construct $BuildType
+$BuildPlatform = $Env:BuildPlatform
+$BuildConfiguration = $Env:BuildConfiguration
+$BuildType = $Env:BuildType
+$BuildSubtype = "default" # will remain as "default" or become e.g. "pogo", "codecoverage"
+
+if (Test-Path Env:\BuildType) {
+    $BuildType = $Env:BuildType
+    $buildTypeSegments = $BuildType.split("_")
+    $BuildPlatform = $buildTypeSegments[0]
+    $BuildConfiguration = $buildTypeSegments[1]
+    if ($buildTypeSegments[2]) {
+        # overwrite with new value if it exists, otherwise keep as "default"
+        $BuildSubtype = $buildTypeSegments[2]
+    }
+
+    if ($BuildConfiguration -eq "codecoverage") {
+        $BuildConfiguration = "test" # codecoverage builds are actually "test" configuration
+        $BuildSubtype = "codecoverage" # keep information about codecoverage in the subtype
+    }
+
+    if (-not ($BuildSubtype -in @("default","pogo","codecoverage"))) {
+        Write-Error "Unsupported BuildSubtype: $BuildSubtype"
+    }
+} elseif ((Test-Path Env:\BuildPlatform) -and (Test-Path Env:\BuildConfiguration)) {
+    $BuildPlatform = $Env:BuildPlatform
+    $BuildConfiguration = $Env:BuildConfiguration
+    $BuildType = "${BuildPlatform}_${BuildConfiguration}"
+} else {
+    Write-Error (@"
+
+    Not enough information about BuildType:
+        BuildType={0}
+        BuildPlatform={1}
+        BuildConfiguration={2}
+
+"@ -f $Env:BuildType, $Env:BuildPlatform, $Env:BuildConfiguration)
+
+    exit 1
+}
+
+# set up required variables and import pre_post_util.ps1
+$arch = $BuildPlatform
+$flavor = $BuildConfiguration
+$OuterScriptRoot = $PSScriptRoot # Used in pre_post_util.ps1
+. "$PSScriptRoot\pre_post_util.ps1"
+
+$gitExe = GetGitPath
+
+$BuildName = ConstructBuildName -arch $BuildPlatform -flavor $BuildConfiguration -subtype $BuildSubtype
+
+$branch = $Env:BUILD_SOURCEBRANCH
 if (-not $branch) {
-    $branch = $(git rev-parse --symbolic-full-name HEAD)
+    $branch = iex "$gitExe rev-parse --symbolic-full-name HEAD"
 }
 
 $BranchName = $branch.split('/',3)[2]
 $BranchPath = $BranchName.replace('/','\')
-$CommitHash = $env:BUILD_SOURCEVERSION
+$CommitHash = $Env:BUILD_SOURCEVERSION
 if (-not $CommitHash) {
-    $CommitHash = $(git rev-parse HEAD)
+    $CommitHash = iex "$gitExe rev-parse HEAD"
 }
 
-$Username = $(git log $CommitHash -1 --pretty=%ae).split('@')[0]
-$CommitDateTime = [DateTime]$(git log $CommitHash -1 --pretty=%aD)
+$Username = (iex "$gitExe log $CommitHash -1 --pretty=%ae").split('@')[0]
+$CommitDateTime = [DateTime]$(iex "$gitExe log $CommitHash -1 --pretty=%aD")
 $CommitTime = Get-Date $CommitDateTime -Format yyMMdd.HHmm
 
 #
-# (borrowed from pre_build.ps1)
-# Get PushID and PushDate from VSO
-# TODO (doilij) refactor this into a method in a util script.
+# Get Build Info
 #
 
-# Get the git remote path and construct the rest API URI
-$remote = (iex "git remote -v")[0].split()[1].replace("_git", "_apis/git/repositories");
-$remote = $remote.replace("mshttps", "https")
-
-# Get the pushId and push date time to use that for build number and build date time
-$uri = ("{0}/commits/{1}?api-version=1.0" -f $remote, $commitHash)
-$oauthToken = Get-Content $oauth
-$header = @{ Authorization=("Basic {0}" -f $oauthToken) }
-$info = Invoke-RestMethod -Headers $header -Uri $uri -Method GET
+$info = GetBuildInfo $oauth $CommitHash
 
 $BuildPushDate = [datetime]$info.push.date
 $PushDate = Get-Date $BuildPushDate -Format yyMMdd.HHmm
-$buildPushId = $info.push.pushId
-$buildPushIdPart1 = [int]([math]::Floor($buildPushId / 65536))
-$buildPushIdPart2 = [int]($buildPushId % 65536)
 
-$PushID = "{0}.{1}" -f $buildPushIdPart1.ToString("00000"), $buildPushIdPart2.ToString("00000")
-$VersionString = "${Env:VERSION_MAJOR}.${Env:VERSION_MINOR}.${PushID}"
-$PreviewVersionString = "${VersionString}-preview"
+$buildPushId, $buildPushIdPart1, $buildPushIdPart2, $buildPushIdString = GetBuildPushId $info
 
-#
-# (end code borrowed from pre_build.ps1)
-#
+$VersionString = "${Env:VERSION_MAJOR}.${Env:VERSION_MINOR}.${buildPushIdString}"
+$PreviewVersionString = "${VersionString}-preview"
 
 # unless it is a build branch, subdivide the output directory by month
 if ($BranchPath.StartsWith("build")) {
@@ -72,36 +109,35 @@ if ($BranchPath.StartsWith("build")) {
     $YearAndMonth = (Get-Date $BuildPushDate -Format yyMM) + "\"
 }
 
-$BuildIdentifier = "${PushID}_${PushDate}_${Username}_${CommitHash}"
+$BuildIdentifier = "${buildPushIdString}_${PushDate}_${Username}_${CommitHash}"
 $ComputedDropPathSegment = "${BranchPath}\${YearAndMonth}${BuildIdentifier}"
-$BuildType = "${Env:BuildPlatform}_${Env:BuildConfiguration}"
 $BinariesDirectory = "${Env:BUILD_SOURCESDIRECTORY}\Build\VcBuild"
 
 # Create a sentinel file for each build flavor to track whether the build is complete.
 # * ${arch}_${flavor}.incomplete       # will be deleted when the build of this flavor completes
 
 $buildIncompleteFileContentsString = @"
-{0} in progress.
+{0} is incomplete.
+This could mean that the build is in progress, or that it was unable to run to completion.
 The contents of this directory should not be relied on until the build completes.
 "@
 
-$DropPath = Join-Path $env:DROP_ROOT $ComputedDropPathSegment
+$DropPath = Join-Path $Env:DROP_ROOT $ComputedDropPathSegment
 New-Item -ItemType Directory -Force -Path $DropPath
 New-Item -ItemType Directory -Force -Path (Join-Path $Env:BUILD_SOURCESDIRECTORY "test\logs")
-New-Item -ItemType Directory -Force -Path (Join-Path $BinariesDirectory "testlogs")
 New-Item -ItemType Directory -Force -Path (Join-Path $BinariesDirectory "buildlogs")
 New-Item -ItemType Directory -Force -Path (Join-Path $BinariesDirectory "logs")
 
-$flavorBuildIncompleteFile = Join-Path $DropPath "${BuildType}.incomplete"
+$FlavorBuildIncompleteFile = Join-Path $DropPath "${BuildType}.incomplete"
 
-if (-not (Test-Path $flavorBuildIncompleteFile)) {
+if (-not (Test-Path $FlavorBuildIncompleteFile)) {
     ($buildIncompleteFileContentsString -f "Build of ${BuildType}") `
-        | Out-File $flavorBuildIncompleteFile -Encoding Ascii
+        | Out-File $FlavorBuildIncompleteFile -Encoding Ascii
 }
 
-$PogoConfig = $SupportedPogoBuildTypes -contains "${Env:BuildPlatform}_${Env:BuildConfiguration}"
+$PogoConfig = $supportedPogoBuildTypes -contains "${Env:BuildPlatform}_${Env:BuildConfiguration}"
 
-# Write the $envconfig script.
+# Write the $envConfigScript
 
 @"
 set BranchName=${BranchName}
@@ -109,7 +145,7 @@ set BranchPath=${BranchPath}
 set YearAndMonth=${YearAndMonth}
 set BuildIdentifier=${BuildIdentifier}
 
-set PushID=${PushID}
+set buildPushIdString=${buildPushIdString}
 set VersionString=${VersionString}
 set PreviewVersionString=${PreviewVersionString}
 set PushDate=${PushDate}
@@ -120,30 +156,49 @@ set CommitHash=${CommitHash}
 set ComputedDropPathSegment=${ComputedDropPathSegment}
 set BinariesDirectory=${BinariesDirectory}
 set DropPath=${DropPath}
+
 set BuildType=${BuildType}
+set BuildPlatform=${BuildPlatform}
+set BuildConfiguration=${BuildConfiguration}
+set BuildSubtype=${BuildSubtype}
+set BuildName=${BuildName}
 
-set FlavorBuildIncompleteFile=${flavorBuildIncompleteFile}
+set FlavorBuildIncompleteFile=${FlavorBuildIncompleteFile}
 
 set PogoConfig=${PogoConfig}
+
 "@ `
-    | Out-File $envconfig -Encoding Ascii
+    | Out-File $envConfigScript -Encoding Ascii
 
-# Use the MBv2 environment to construct a MBv1 VSO environment
+# Use the VSTS environment vars to construct a backwards-compatible VSO build environment
 # for the sake of reusing the pre-build and post-build scripts as they are.
 
 @"
 set TF_BUILD_SOURCEGETVERSION=LG:${branch}:${CommitHash}
 set TF_BUILD_DROPLOCATION=${BinariesDirectory}
-set TF_BUILD_BINARIESDIRECTORY=${BinariesDirectory}
+
 set TF_BUILD_SOURCESDIRECTORY=${Env:BUILD_SOURCESDIRECTORY}
+REM set TF_BUILD_BUILDDIRECTORY=${Env:AGENT_BUILDDIRECTORY}\b  # note: inferred location works
+set TF_BUILD_BINARIESDIRECTORY=${BinariesDirectory}
 
 set TF_BUILD_BUILDDEFINITIONNAME=${Env:BUILD_DEFINITIONNAME}
 set TF_BUILD_BUILDNUMBER=${Env:BUILD_BUILDNUMBER}
 set TF_BUILD_BUILDURI=${Env:BUILD_BUILDURI}
 "@ `
-    | Out-File $envconfig -Encoding Ascii -Append
-
-# Set VSO variables that can be consumed by other VSO tasks.
+    | Out-File $envConfigScript -Encoding Ascii -Append
+
+# Export VSO variables that can be consumed by other VSO tasks where the task
+# definition in VSO itself needs to know the value of the variable.
+# If the task definition itself doesn't need to know the value of the variables,
+# the variables that are added to the environment via the script generated above
+# will be interpolated when the tasks run the associated command line with the
+# given parameters.
+#
+# For example, for a Publish Artifacts task, VSO itself needs to know
+# the value of DropPath in order to construct links to the artifacts correctly.
+# Thus, we export a variable called VSO_DropPath (VSO_ prefix by convention)
+# that the VSO build definition, not just the command environment, will know about.
+#
 # Uses command syntax documented here:
 # https://github.com/Microsoft/vso-agent-tasks/blob/master/docs/authoring/commands.md
 # Lines written to stdout that match this pattern are interpreted with this command syntax.
@@ -154,7 +209,11 @@ Write-Output "##vso[task.setvariable variable=VSO_DropPath;]${DropPath}"
 Write-Output "Setting VSO variable VSO_VersionString = ${VersionString}"
 Write-Output "##vso[task.setvariable variable=VSO_VersionString;]${VersionString}"
 
-# TODO (doilij): move this up and assign values
+#
+# Clean up files that might have been left behind from a previous build.
+#
 
-# Inferable Environment (if not specified, inferred by pre_post_util.ps1):
-#   $Env:TF_BUILD_BUILDDIRECTORY    (a.k.a. $objpath)
+if ((Test-Path Env:\BUILD_BINARIESDIRECTORY) -and (Test-Path "$Env:BUILD_BINARIESDIRECTORY"))
+{
+    Remove-Item -Verbose "${Env:BUILD_BINARIESDIRECTORY}\*" -Recurse
+}

+ 52 - 0
Build/scripts/locate_msbuild.ps1

@@ -0,0 +1,52 @@
+#-------------------------------------------------------------------------------------------------------
+# Copyright (C) Microsoft. All rights reserved.
+# Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+#-------------------------------------------------------------------------------------------------------
+
+# Locate-MSBuild
+#
+# Locate and return the preferred location of MSBuild on this machine.
+
+. $PSScriptRoot\util.ps1
+
+# helper to try to locate a single version
+function Locate-MSBuild-Version([string]$version) {
+    $msbuildTemplate = "{0}\msbuild\{1}\Bin\{2}\msbuild.exe"
+    $msbuildUnscoped = "{0}\msbuild\{1}\Bin\msbuild.exe"
+
+    $msbuildExe = $msbuildTemplate -f "${Env:ProgramFiles}", $version, "x86"
+    $_ = WriteMessage "Trying `"$msbuildExe`""
+    if (Test-Path $msbuildExe) { return $msbuildExe }
+
+    $msbuildExe = $msbuildUnscoped -f "${Env:ProgramFiles(x86)}", $version
+    $_ = WriteMessage "Trying `"$msbuildExe`""
+    if (Test-Path $msbuildExe) { return $msbuildExe }
+
+    $msbuildExe = $msbuildTemplate -f "${Env:ProgramFiles(x86)}", $version, "amd64"
+    $_ = WriteMessage "Trying `"$msbuildExe`""
+    if (Test-Path $msbuildExe) { return $msbuildExe }
+
+    return "" # didn't find it so return empty string
+}
+
+function Locate-MSBuild() {
+    $msbuildExe = "msbuild.exe"
+    if (Get-Command $msbuildExe -ErrorAction SilentlyContinue) { return $msbuildExe }
+
+    $msbuildExe = Locate-MSBuild-Version("14.0")
+    if ($msbuildExe -and (Test-Path $msbuildExe)) {
+        $_ = WriteMessage "Found `"$msbuildExe`""
+        return $msbuildExe
+    }
+
+    $_ = WriteMessage "Dev14 not found, trying Dev12..."
+
+    $msbuildExe = Locate-MSBuild-Version("12.0")
+    if ($msbuildExe -and (Test-Path $msbuildExe)) {
+        $_ = WriteMessage "Found `"$msbuildExe`""
+        return $msbuildExe
+    }
+
+    WriteErrorMessage "Can't find msbuild.exe."
+    return "" # return empty string
+}

+ 7 - 3
Build/scripts/pgo/pogo_training.ps1

@@ -21,17 +21,21 @@ param (
     [Parameter(Mandatory=$True)]
     [string]$arch,
 
+    [ValidateSet("default", "codecoverage", "pogo")]
+    [string]$subtype = "default",
+
     # force callers to specify this in case of future use
     [Parameter(Mandatory=$True)]
     [string]$flavor,
 
-    [string]$vcinstallroot = ${env:ProgramFiles(x86)},
+    [string]$vcinstallroot = ${Env:ProgramFiles(x86)},
     [string]$vcbinpath = "Microsoft Visual Studio 14.0\VC\bin",
     [string]$dllname = "pgort140.dll",
     [string]$dllCheckName = "pgort*.dll"
 )
 
-if (${Env:PogoConfig} -eq "False") {
+$pogoConfig = ($subtype -eq "pogo") -or (${Env:PogoConfig} -eq "True")
+if (-not $pogoConfig) {
     Write-Host "---- Not a Pogo Config. Skipping step."
     return 0
 }
@@ -55,7 +59,7 @@ for ($i = 0; $i -lt $scenarios.Length; $i = $i + 1) {
     $items = @()
     if (Test-Path $path -PathType Container) {
         # *.js files in directories
-        $items = Get-ChildItem -Path $path -Filter "*.js" | % {join-path $path $_ }
+        $items = Get-ChildItem -Path $path -Filter "*.js" | % { join-path $path $_ }
     } else {
         $items = @($path)
     }

+ 143 - 0
Build/scripts/pogo_build.ps1

@@ -0,0 +1,143 @@
+#-------------------------------------------------------------------------------------------------------
+# Copyright (C) Microsoft. All rights reserved.
+# Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+#-------------------------------------------------------------------------------------------------------
+
+# Use this script to run a POGO build for the given BuildType (arch, flavor, subtype)
+
+param (
+    [ValidateSet("x86", "x64", "arm")]
+    [Parameter(Mandatory=$True)]
+    [string]$arch,
+
+    # We do not use ValidateSet here because this $flavor param is used to name the BuildConfuration
+    # from the solution file. MsBuild will determine whether it is valid.
+    [Parameter(Mandatory=$True)]
+    [string]$flavor,
+
+    [ValidateSet("default", "codecoverage", "pogo")]
+    [string]$subtype = "pogo",
+
+    [Parameter(Mandatory=$True)]
+    [string]$solutionFile,
+
+    [switch]$clean,
+
+    # $binDir will be inferred if not provided.
+    [string]$binDir = "",
+    [string]$buildlogsSubdir = "buildlogs",
+
+    # Assume NuGet is on the path, otherwise the caller must specify an explicit path.
+    [string]$nugetExe = "NuGet.exe",
+
+    [string]$logFile = "",
+
+    #
+    # POGO training parameters
+    #
+
+    [string[]]$scenarios = @(),
+
+    [Parameter(Mandatory=$True)]
+    [string]$binpath,
+
+    [string]$binaryName = "ch.exe"
+)
+
+#
+# Configure logging
+#
+
+$OuterScriptRoot = $PSScriptRoot
+. $PSScriptRoot\pre_post_util.ps1
+
+$buildName = ConstructBuildName -arch $arch -flavor $flavor -subtype $subtype
+
+if (($logFile -eq "") -and (Test-Path Env:\TF_BUILD_BINARIESDIRECTORY)) {
+    $logFile = "${Env:TF_BUILD_BINARIESDIRECTORY}\logs\pogo_build.${buildName}.log"
+}
+
+if (($logFile -ne "") -and (Test-Path $logFile)) {
+    Remove-Item $logFile -Force
+}
+
+#
+# Only continue with this build if it is a valid pogo build configuration
+#
+
+if ($subtype -ne "pogo") {
+    WriteMessage "This build's subtype is not pogo (subtype: $subtype). Skipping build."
+    exit 0
+}
+
+if ($scenarios.Length -eq 0) {
+    WriteMessage "No training scenarios selected. Please specify training scenarios using the -scenarios parameter."
+    exit 0
+}
+
+#
+# NuGet restore
+#
+
+ExecuteCommand "& $nugetExe restore $solutionFile -NonInteractive"
+
+#
+# Setup
+#
+
+$msbuildExe = Locate-MSBuild
+if (-not $msbuildExe) {
+    WriteErrorMessage "Error: Could not find msbuild.exe -- exiting (1)..."
+    exit 1
+}
+
+$binDir = UseValueOrDefault "$binDir" "${Env:BinariesDirectory}" "${Env:BUILD_SOURCESDIRECTORY}\Build\VcBuild"
+$buildlogsPath = Join-Path $binDir $buildlogsSubdir
+
+$defaultParams = "$solutionFile /nologo /m /nr:false /p:platform=`"${arch}`" /p:configuration=`"${flavor}`""
+$loggingParams = @(
+    "/fl1 `"/flp1:logfile=${buildlogsPath}\build.${buildName}.log;verbosity=normal`"",
+    "/fl2 `"/flp2:logfile=${buildlogsPath}\build.${buildName}.err;errorsonly`"",
+    "/fl3 `"/flp3:logfile=${buildlogsPath}\build.${buildName}.wrn;warningsonly`"",
+    "/verbosity:normal"
+    ) -join " "
+
+$targets = ""
+if ($clean) {
+    $targets += "`"/t:Clean,Rebuild`""
+}
+
+$binary = Join-Path $binpath $binaryName
+
+#
+# Build
+#
+
+function Build($targets="", $pogoParams) {
+    $buildCommand = "& `"$msbuildExe`" $targets $defaultParams $loggingParams $pogoParams"
+    ExecuteCommand "$buildCommand"
+    if ($global:LastExitCode -ne 0) {
+        WriteErrorMessage "Failed msbuild command:`n$buildCommand`n"
+        WriteErrorMessage "Build failed. Exiting..."
+        exit 1
+    }
+}
+
+Build -pogoParams "`"/p:POGO_TYPE=PGI`"" -targets "$targets"
+
+$scenariosParamValue = $scenarios -join ','
+$pogoTrainingCommand = "& `"${PSScriptRoot}\pgo\pogo_training.ps1`" -arch $arch -flavor $flavor -subtype $subtype -binary $binary -scenarios $scenariosParamValue"
+ExecuteCommand "$pogoTrainingCommand"
+
+Build -pogoParams "`"/p:POGO_TYPE=PGO`""
+
+#
+# Clean up
+#
+
+if (("$binpath" -ne "") -and (Test-Path $binpath)) {
+    # remove *.pgc, *.pgd, and pgort*
+    Get-ChildItem -Recurse -Path $binpath "*" `
+        | ? { $_.Name -match "(.*\.pg[cd]|pgort.*)" } `
+        | % { Remove-Item -Force $_.FullName }
+}

+ 32 - 24
Build/scripts/post_build.ps1

@@ -19,6 +19,9 @@ param (
     [ValidateSet("debug", "release", "test", "codecoverage", "*")]
     [string]$flavor = "*",
 
+    [ValidateSet("default", "codecoverage", "pogo")]
+    [string]$subtype = "default",
+
     [string]$srcpath = "",
     [string]$binpath = "",
     [string]$objpath = "",
@@ -34,9 +37,6 @@ param (
     [string[]]$pogo = @(),
     [string]$pogoscript = "",
 
-    # Support output folders with e.g. _pogo suffix
-    [string]$buildTypeSuffix = "",
-
     [switch]$noaction
 )
 
@@ -46,65 +46,73 @@ if ($arch -eq "*") {
 
     . "$PSScriptRoot\util.ps1"
     foreach ($arch in ("x86", "x64", "arm")) {
-        ExecuteCommand "$PSScriptRoot\post_build.ps1 -arch $arch -flavor $flavor -srcpath ""$srcpath"" -binpath ""$binpath"" -objpath ""$objpath"" -srcsrvcmdpath ""$srcsrvcmdpath"" -bvtcmdpath ""$bvtcmdpath"" -repo ""$repo""" -logFile ""$logFile"";
+        ExecuteCommand "$PSScriptRoot\post_build.ps1 -arch $arch -flavor $flavor -srcpath ""$srcpath"" -binpath ""$binpath"" -objpath ""$objpath"" -srcsrvcmdpath ""$srcsrvcmdpath"" -bvtcmdpath ""$bvtcmdpath"" -repo ""$repo""" -logFile ""$logFile""
     }
 
 } elseif ($flavor -eq "*") {
 
     . "$PSScriptRoot\util.ps1"
     foreach ($flavor in ("debug", "test", "release")) {
-        ExecuteCommand "$PSScriptRoot\post_build.ps1 -arch $arch -flavor $flavor -srcpath ""$srcpath"" -binpath ""$binpath"" -objpath ""$objpath"" -srcsrvcmdpath ""$srcsrvcmdpath"" -bvtcmdpath ""$bvtcmdpath"" -repo ""$repo""" -logFile ""$logFile"";
+        ExecuteCommand "$PSScriptRoot\post_build.ps1 -arch $arch -flavor $flavor -srcpath ""$srcpath"" -binpath ""$binpath"" -objpath ""$objpath"" -srcsrvcmdpath ""$srcsrvcmdpath"" -bvtcmdpath ""$bvtcmdpath"" -repo ""$repo""" -logFile ""$logFile""
     }
 
 } else {
-    $OuterScriptRoot = $PSScriptRoot;
+
+    $OuterScriptRoot = $PSScriptRoot
     . "$PSScriptRoot\pre_post_util.ps1"
 
+    $buildName = ConstructBuildName -arch $arch -flavor $flavor -subtype $subtype
+
     if (($logFile -eq "") -and (Test-Path Env:\TF_BUILD_BINARIESDIRECTORY)) {
-        $logFile = "${Env:TF_BUILD_BINARIESDIRECTORY}\logs\post_build_${arch}_${flavor}.log"
+        $logFile = "${Env:TF_BUILD_BINARIESDIRECTORY}\logs\post_build.${buildName}.log"
         if (Test-Path -Path $logFile) {
             Remove-Item $logFile -Force
         }
     }
 
     WriteMessage "======================================================================================"
-    WriteMessage "Post build script for $arch $flavor";
+    WriteMessage "Post build script for $arch $flavor"
     WriteMessage "======================================================================================"
-    $bvtcmdpath =  UseValueOrDefault $bvtcmdpath "" (Resolve-Path "$PSScriptRoot\..\..\test\runcitests.cmd");
 
-    WriteCommonArguments;
+    $bvtcmdpath =  UseValueOrDefault $bvtcmdpath "" (Resolve-Path "$PSScriptRoot\..\..\test\runcitests.cmd")
+
+    WriteCommonArguments
     WriteMessage "BVT Command  : $bvtcmdpath"
     WriteMessage ""
 
-    $srcsrvcmd = ("{0} {1} {2} {3}\bin\{4}_{5}{6}\*.pdb" -f $srcsrvcmdpath, $repo, $srcpath, $binpath, $arch, $flavor, $buildTypeSuffix);
-    $pogocmd = ("{0} {1} {2}" -f $pogoscript, $arch, $flavor);
-    $prefastlog = ("{0}\logs\PrefastCheck_{1}_{2}.log" -f $binpath, $arch, $flavor);
-    $prefastcmd = "$PSScriptRoot\check_prefast_error.ps1 -directory $objpath -logFile $prefastlog";
+    $srcsrvcmd = ("{0} {1} {2} {3}\bin\{4}\*.pdb" -f $srcsrvcmdpath, $repo, $srcpath, $binpath, $buildName)
+    $prefastlog = ("{0}\logs\PrefastCheck.{1}.log" -f $binpath, $buildName)
+    $prefastcmd = "$PSScriptRoot\check_prefast_error.ps1 -directory $objpath -logFile $prefastlog"
 
     # generate srcsrv
     if ((Test-Path $srcsrvcmdpath) -and (Test-Path $srcpath) -and (Test-Path $binpath)) {
-        ExecuteCommand($srcsrvcmd);
+        ExecuteCommand($srcsrvcmd)
     }
 
-    # do PoGO
+    # do POGO
     $doPogo=$False
     for ($i=0; $i -lt $pogo.length; $i=$i+2) {
         if (($pogo[$i] -eq $arch) -and ($pogo[$i+1] -eq $flavor)) {
             $doPogo=$True
         }
     }
-    if ($doPogo) {
-        WriteMessage "Building pogo for $arch $flavor"
-        ExecuteCommand($pogocmd);
-    }
 
-    # run test
-    ExecuteCommand("$bvtcmdpath -$arch$flavor");
+    if ($subtype -ne "codecoverage") {
+        if ($doPogo -and ("$pogoscript" -ne "")) {
+            WriteMessage "Building pogo for $arch $flavor"
+            $pogocmd = ("{0} {1} {2}" -f $pogoscript, $arch, $flavor)
+            ExecuteCommand($pogocmd)
+        }
+
+        # run tests
+        ExecuteCommand("$bvtcmdpath -$arch$flavor")
+    }
 
     # check prefast
-    ExecuteCommand($prefastcmd);
+    ExecuteCommand($prefastcmd)
+
+    WriteMessage ""
 
-    WriteMessage "";
 }
 
 exit $global:exitcode

+ 70 - 54
Build/scripts/pre_build.ps1

@@ -26,31 +26,39 @@
 #   $Env:TF_BUILD_BUILDURI
 
 param (
-    [ValidateSet("x86", "x64", "arm", "")]
-    [string]$arch = "",
-    [ValidateSet("debug", "release", "test", "codecoverage", "")]
-    [string]$flavor = "",
+    [Parameter(Mandatory=$True)]
+    [ValidateSet("x86", "x64", "arm")]
+    [string]$arch,
+    [Parameter(Mandatory=$True)]
+    [ValidateSet("debug", "release", "test", "codecoverage")]
+    [string]$flavor,
+
+    [ValidateSet("default", "codecoverage", "pogo")]
+    [string]$subtype = "default",
 
     [string]$srcpath = "",
     [string]$binpath = "",
     [string]$objpath = "",
     [string]$logFile = "",
+
+    [Parameter(Mandatory=$True)]
     [string]$oauth
 )
 
-$OuterScriptRoot = $PSScriptRoot;
+$OuterScriptRoot = $PSScriptRoot # Used in pre_post_util.ps1
 . "$PSScriptRoot\pre_post_util.ps1"
+
 if (($logFile -eq "") -and (Test-Path Env:\TF_BUILD_BINARIESDIRECTORY)) {
-    if (-not(Test-Path -Path "$Env:TF_BUILD_BINARIESDIRECTORY\logs")) {
-        $dummy = New-Item -Path "$Env:TF_BUILD_BINARIESDIRECTORY\logs" -ItemType Directory -Force
+    if (-not(Test-Path -Path "${Env:TF_BUILD_BINARIESDIRECTORY}\logs")) {
+        $dummy = New-Item -Path "${Env:TF_BUILD_BINARIESDIRECTORY}\logs" -ItemType Directory -Force
     }
-    $logFile = "$Env:TF_BUILD_BINARIESDIRECTORY\logs\pre_build_${arch}_${flavor}.log"
+    $logFile = "${Env:TF_BUILD_BINARIESDIRECTORY}\logs\pre_build.${Env:BuildName}.log"
     if (Test-Path -Path $logFile) {
         Remove-Item $logFile -Force
     }
 }
 
-WriteCommonArguments;
+WriteCommonArguments
 
 #
 # Create packages.config files
@@ -63,10 +71,10 @@ $packagesConfigFileText = @"
 </packages>
 "@
 
-$PackagesFiles = Get-ChildItem -Path $Env:TF_BUILD_SOURCESDIRECTORY *.vcxproj -Recurse `
+$packagesFiles = Get-ChildItem -Path $Env:TF_BUILD_SOURCESDIRECTORY *.vcxproj -Recurse `
     | % { Join-Path $_.DirectoryName "packages.config" }
 
-foreach ($file in $PackagesFiles) {
+foreach ($file in $packagesFiles) {
     if (-not (Test-Path $file)) {
         Write-Output $packagesConfigFileText | Out-File $file -Encoding utf8
     }
@@ -79,68 +87,70 @@ foreach ($file in $PackagesFiles) {
 if (Test-Path Env:\TF_BUILD_SOURCEGETVERSION)
 {
     $commitHash = ($Env:TF_BUILD_SOURCEGETVERSION).split(':')[2]
-    $gitExe = GetGitPath;
+    $gitExe = GetGitPath
 
     $outputDir = $Env:TF_BUILD_DROPLOCATION
     if (-not(Test-Path -Path $outputDir)) {
         $dummy = New-Item -Path $outputDir -ItemType Directory -Force
     }
 
-    Push-Location $srcpath;
-    $outputFile = Join-Path -Path $outputDir -ChildPath "change.txt"
-
-    Write-Output "TF_BUILD_BUILDDEFINITIONNAME = $Env:TF_BUILD_BUILDDEFINITIONNAME" | Out-File $outputFile
-    Write-Output "TF_BUILD_BUILDNUMBER = $Env:TF_BUILD_BUILDNUMBER" | Out-File $outputFile -Append
-    Write-Output "TF_BUILD_SOURCEGETVERSION = $Env:TF_BUILD_SOURCEGETVERSION" | Out-File $outputFile -Append
-    Write-Output "TF_BUILD_BUILDURI = $Env:TF_BUILD_BUILDURI" | Out-File $outputFile -Append
-    Write-Output "" | Out-File $outputFile -Append
+    Push-Location $srcpath
 
-    # Get the git remote path and construct the rest API URI
-    $remote = (iex "$gitExe remote -v")[0].split()[1].replace("_git", "_apis/git/repositories");
-    $remote = $remote.replace("mshttps", "https");
+    $info = GetBuildInfo $oauth $commitHash
 
-    # Get the pushId and push date time to use that for build number and build date time
-    $uri = ("{0}/commits/{1}?api-version=1.0" -f $remote, $commitHash)
-    $oauthToken = Get-Content $oauth;
-    $header = @{Authorization=("Basic {0}" -f $oauthToken) }
-    $info = Invoke-RestMethod -Headers $header -Uri $uri -Method GET
+    $BuildDate = ([datetime]$info.push.date).toString("yyMMdd-HHmm")
 
-    $buildDate = ([datetime]$info.push.date).toString("yyMMdd-HHmm")
-    $buildPushId = $info.push.pushId
-    $buildPushIdPart1 = [int]([math]::Floor($buildPushId / 65536))
-    $buildPushIdPart2 = [int]($buildPushId % 65536)
-    $buildPushIdString = "{0}.{1}" -f $buildPushIdPart1.ToString("00000"), $buildPushIdPart2.ToString("00000")
-
-    Write-Output "PushId = $buildPushId $buildPushIdString" | Out-File $outputFile -Append
-    Write-Output "PushDate = $buildDate"                    | Out-File $outputFile -Append
-    Write-Output ""                                         | Out-File $outputFile -Append
+    $buildPushId, $buildPushIdPart1, $buildPushIdPart2, $buildPushIdString = GetBuildPushId $info
 
     # commit message
     $command = "$gitExe log -1 --name-status -p $commitHash"
-    iex $command | Out-File $outputFile -Append
+    $CommitMessage = iex $command
+
+    $changeTextFile = Join-Path -Path $outputDir -ChildPath "change.txt"
+
+    $changeTextFileContent = @"
+TF_BUILD_BUILDDEFINITIONNAME = $Env:TF_BUILD_BUILDDEFINITIONNAME
+TF_BUILD_BUILDNUMBER = $Env:TF_BUILD_BUILDNUMBER
+TF_BUILD_SOURCEGETVERSION = $Env:TF_BUILD_SOURCEGETVERSION
+TF_BUILD_BUILDURI = $Env:TF_BUILD_BUILDURI
+
+PushId = $buildPushId $buildPushIdString
+PushDate = $buildDate
+
+$CommitMessage
+"@
+
+    Write-Output "-----"
+    Write-Output $changeTextFile
+    Write-Output $changeTextFileContent
+    Write-Output $changeTextFileContent | Out-File $changeTextFile -Encoding utf8 -Append
+
     Pop-Location
 
     # commit hash
-    $buildCommit = ($Env:TF_BUILD_SOURCEGETVERSION).SubString(14);
-    $commitHash = $buildCommit.Split(":")[1]
+    $buildCommit = ($Env:TF_BUILD_SOURCEGETVERSION).SubString(14)
+    $CommitHash = $buildCommit.Split(":")[1]
 
     $outputJsonFile = Join-Path -Path $outputDir -ChildPath "change.json"
     $changeJson = New-Object System.Object
 
     $changeJson | Add-Member -type NoteProperty -name BuildDefinitionName -value $Env:TF_BUILD_BUILDDEFINITIONNAME
     $changeJson | Add-Member -type NoteProperty -name BuildNumber -value $Env:TF_BUILD_BUILDNUMBER
-    $changeJson | Add-Member -type NoteProperty -name BuildDate -value $buildDate
     $changeJson | Add-Member -type NoteProperty -name BuildUri -value $Env:TF_BUILD_BUILDURI
+    $changeJson | Add-Member -type NoteProperty -name BuildDate -value $BuildDate
     $changeJson | Add-Member -type NoteProperty -name Branch -value $Env:BranchName
-    $changeJson | Add-Member -type NoteProperty -name CommitHash -value $commitHash
-    $changeJson | Add-Member -type NoteProperty -name PushId -value $buildPushId
-    $changeJson | Add-Member -type NoteProperty -name PushIdPart1 -value $buildPushIdPart1
-    $changeJson | Add-Member -type NoteProperty -name PushIdPart2 -value $buildPushIdPart2
-    $changeJson | Add-Member -type NoteProperty -name PushIdString -value $buildPushIdString
-    $changeJson | Add-Member -type NoteProperty -name SourceGetVersion -value $Env:TF_BUILD_SOURCEGETVERSION
-
+    $changeJson | Add-Member -type NoteProperty -name CommitHash -value $CommitHash
+    $changeJson | Add-Member -type NoteProperty -name PushId -value $BuildPushId
+    $changeJson | Add-Member -type NoteProperty -name PushIdPart1 -value $BuildPushIdPart1
+    $changeJson | Add-Member -type NoteProperty -name PushIdPart2 -value $BuildPushIdPart2
+    $changeJson | Add-Member -type NoteProperty -name PushIdString -value $BuildPushIdString
+    $changeJson | Add-Member -type NoteProperty -name Username -value $Env:Username
+    $changeJson | Add-Member -type NoteProperty -name CommitMessage -value $CommitMessage
+
+    Write-Output "-----"
+    Write-Output $outputJsonFile
     $changeJson | ConvertTo-Json | Write-Output
-    $changeJson | ConvertTo-Json | Out-File $outputJsonFile -Encoding ascii
+    $changeJson | ConvertTo-Json | Out-File $outputJsonFile -Encoding Ascii
 
     $buildInfoOutputDir = $objpath
     if (-not(Test-Path -Path $buildInfoOutputDir)) {
@@ -148,8 +158,8 @@ if (Test-Path Env:\TF_BUILD_SOURCEGETVERSION)
     }
 
     # generate build version prop file
-    $buildInfoOutputFile = Join-Path -Path $buildInfoOutputDir -ChildPath "Chakra.Generated.BuildInfo.props"
-    $propsFile = @"
+    $propsFile = Join-Path -Path $buildInfoOutputDir -ChildPath "Chakra.Generated.BuildInfo.props"
+    $propsFileTemplate = @"
 <?xml version="1.0" encoding="utf-16"?>
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
@@ -162,13 +172,19 @@ if (Test-Path Env:\TF_BUILD_SOURCEGETVERSION)
   </PropertyGroup>
 </Project>
 "@
-    Write-Output ($propsFile -f $binpath, $objpath, $buildPushIdPart1, $buildPushIdPart2, $buildCommit, $buildDate) | Out-File $buildInfoOutputFile
+
+    $propsFileContent = $propsFileTemplate -f $binpath, $objpath, $buildPushIdPart1, $buildPushIdPart2, $buildCommit, $buildDate
+
+    Write-Output "-----"
+    Write-Output $propsFile
+    Write-Output $propsFileContent
+    Write-Output $propsFileContent | Out-File $propsFile
 }
 
 #
 # Clean up code analysis summary files in case they get left behind
 #
 
-if (Test-Path $objpath) {
-    Get-ChildItem $objpath -include vc.nativecodeanalysis.all.xml -recurse | Remove-Item
+if (($objpath -ne "") -and (Test-Path $objpath)) {
+    Get-ChildItem $objpath -Include vc.nativecodeanalysis.all.xml -Recurse | Remove-Item -Verbose
 }

+ 54 - 22
Build/scripts/pre_post_util.ps1

@@ -4,34 +4,66 @@
 #-------------------------------------------------------------------------------------------------------
 
 . "$PSScriptRoot\util.ps1"
-
-function UseValueOrDefault($value, $defaultvalue, $defaultvalue2) {
-    if ($value -ne "") {
-        return $value;
-    } elseif ($defaultvalue -ne "") {
-        return $defaultvalue;
-    }
-    return $defaultvalue2;
-}
+. "$PSScriptRoot\locate_msbuild.ps1"
 
 function WriteCommonArguments() {
-    WriteMessage "Source Path  : $srcpath"
-    WriteMessage "Object Path  : $objpath"
+    WriteMessage "  Source Path: $srcpath"
+    WriteMessage "  Object Path: $objpath"
     WriteMessage "Binaries Path: $binpath"
 }
 
-function GetGitPath() {
-    $gitExe = "git.exe"
+function GetBuildInfo($oauth, $commitHash) {
+    # Get the git remote path and construct the rest API URI
+    $gitExe = GetGitPath
+    $remote = (iex "$gitExe remote -v")[0].split()[1].replace("_git", "_apis/git/repositories")
+    $remote = $remote.replace("mshttps", "https")
+
+    # Get the pushId and push date time to use that for build number and build date time
+    $uri = ("{0}/commits/{1}?api-version=1.0" -f $remote, $commitHash)
+    $oauthToken = Get-Content $oauth
+    $header = @{Authorization=("Basic {0}" -f $oauthToken) }
+    $info = Invoke-RestMethod -Headers $header -Uri $uri -Method GET
+
+    return $info
+}
+
+function GetBuildPushId($info) {
+    $buildPushId = $info.push.pushId
+    $buildPushIdPart1 = [int]([math]::Floor($buildPushId / 65536))
+    $buildPushIdPart2 = [int]($buildPushId % 65536)
+    $buildPushIdString = "{0}.{1}" -f $buildPushIdPart1.ToString("00000"), $buildPushIdPart2.ToString("00000")
 
-    if (!(Get-Command $gitExe -ErrorAction SilentlyContinue)) {
-        $gitExe = "C:\1image\Git\bin\git.exe"
-        if (!(Test-Path $gitExe)) {
-            throw "git.exe not found in path- aborting."
-        }
+    return @($buildPushId, $buildPushIdPart1, $buildPushIdPart2, $buildPushIdString)
+}
+
+function ConstructBuildName($arch, $flavor, $subtype) {
+    if ($subtype -eq "codecoverage") {
+        # TODO eliminate tools' dependency on this particular formatting exception
+        # Normalize the $BuildName of even if the $BuildType is e.g. x64_test_codecoverage
+        return "${arch}_codecoverage"
+    } elseif ($subtype -eq "pogo") {
+        return "${arch}_${flavor}_${subtype}"
+    } else {
+        return "${arch}_${flavor}"
     }
-    return $gitExe;
 }
 
-$srcpath = UseValueOrDefault $srcpath "$env:TF_BUILD_SOURCESDIRECTORY" (Resolve-Path "$OuterScriptRoot\..\..");
-$objpath = UseValueOrDefault $objpath "$env:TF_BUILD_BUILDDIRECTORY" "${srcpath}\Build\VcBuild\obj\${arch}_${flavor}";
-$binpath = UseValueOrDefault $binpath "$env:TF_BUILD_BINARIESDIRECTORY" "${srcpath}\Build\VcBuild";
+# Compute paths
+
+if (("$arch" -eq "") -or ("$flavor" -eq "") -or ("$OuterScriptRoot" -eq ""))
+{
+    WriteErrorMessage @"
+
+    Required variables not set before script was included:
+        `$arch = $arch
+        `$flavor = $flavor
+        `$OuterScriptRoot = $OuterScriptRoot
+
+"@
+
+    throw "Cannot continue - required variables not set."
+}
+
+$srcpath = UseValueOrDefault $srcpath "$env:TF_BUILD_SOURCESDIRECTORY" (Resolve-Path "$OuterScriptRoot\..\..")
+$objpath = UseValueOrDefault $objpath "$env:TF_BUILD_BUILDDIRECTORY" "${srcpath}\Build\VcBuild\obj\${arch}_${flavor}"
+$binpath = UseValueOrDefault $binpath "$env:TF_BUILD_BINARIESDIRECTORY" "${srcpath}\Build\VcBuild"

+ 85 - 0
Build/scripts/run_build.ps1

@@ -0,0 +1,85 @@
+#-------------------------------------------------------------------------------------------------------
+# Copyright (C) Microsoft. All rights reserved.
+# Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+#-------------------------------------------------------------------------------------------------------
+
+# Use this script to run a build command for the given BuildType (arch, flavor, subtype)
+
+param (
+    [ValidateSet("x86", "x64", "arm")]
+    [Parameter(Mandatory=$True)]
+    [string]$arch,
+
+    # We do not use ValidateSet here because this $flavor param is used to name the BuildConfuration
+    # from the solution file. MsBuild will determine whether it is valid.
+    [Parameter(Mandatory=$True)]
+    [string]$flavor,
+
+    [ValidateSet("default", "codecoverage", "pogo")]
+    [string]$subtype = "default",
+
+    [Parameter(Mandatory=$True)]
+    [string]$solutionFile = "",
+
+    [switch]$clean,
+
+    # $binDir will be inferred if not provided.
+    [string]$binDir = "",
+    [string]$buildlogsSubdir = "buildlogs",
+
+    # assume NuGet is on the path, otherwise the caller must specify an explicit path
+    [string]$nugetExe = "NuGet.exe",
+
+    [string]$logFile = ""
+)
+
+$OuterScriptRoot = $PSScriptRoot
+. $PSScriptRoot\pre_post_util.ps1
+
+if (($logFile -eq "") -and (Test-Path Env:\TF_BUILD_BINARIESDIRECTORY)) {
+    $logFile = "${Env:TF_BUILD_BINARIESDIRECTORY}\logs\run_build.${Env:BuildName}.log"
+    if (Test-Path -Path $logFile) {
+        Remove-Item $logFile -Force
+    }
+}
+
+#
+# NuGet restore
+#
+
+ExecuteCommand "& $nugetExe restore $solutionFile -NonInteractive"
+
+#
+# Setup and build
+#
+
+$msbuildExe = Locate-MSBuild
+if (-not $msbuildExe) {
+    WriteErrorMessage "Could not find msbuild.exe -- exiting..."
+    exit 1
+}
+
+$binDir = UseValueOrDefault "$binDir" "${Env:BinariesDirectory}" "${Env:BUILD_SOURCESDIRECTORY}\Build\VcBuild"
+$buildlogsPath = Join-Path $binDir $buildlogsSubdir
+
+$defaultParams = "$solutionFile /nologo /m /nr:false /p:platform=`"${arch}`" /p:configuration=`"${flavor}`""
+$loggingParams = @(
+    "/fl1 `"/flp1:logfile=${buildlogsPath}\build.${Env:BuildName}.log;verbosity=normal`"",
+    "/fl2 `"/flp2:logfile=${buildlogsPath}\build.${Env:BuildName}.err;errorsonly`"",
+    "/fl3 `"/flp3:logfile=${buildlogsPath}\build.${Env:BuildName}.wrn;warningsonly`"",
+    "/verbosity:normal"
+    ) -join " "
+
+$targets = ""
+if ($clean) {
+    $targets += "`"/t:Clean,Rebuild`""
+}
+
+if ($subtype -eq "codecoverage") {
+    $subtypeParams = "/p:ENABLE_CODECOVERAGE=true"
+}
+
+$buildCommand = "& `"$msbuildExe`" $targets $defaultParams $loggingParams $subtypeParams"
+ExecuteCommand "$buildCommand"
+
+exit $global:lastexitcode

+ 28 - 5
Build/scripts/util.ps1

@@ -3,6 +3,29 @@
 # Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 #-------------------------------------------------------------------------------------------------------
 
+function UseValueOrDefault($value, $defaultvalue, $defaultvalue2) {
+    if ($value -ne "") {
+        return $value
+    } elseif ($defaultvalue -ne "") {
+        return $defaultvalue
+    } else {
+        return $defaultvalue2
+    }
+}
+
+function GetGitPath() {
+    $gitExe = "git.exe"
+
+    if (!(Get-Command $gitExe -ErrorAction SilentlyContinue)) {
+        $gitExe = "C:\1image\Git\bin\git.exe"
+        if (!(Test-Path $gitExe)) {
+            throw "git.exe not found in path -- aborting."
+        }
+    }
+
+    return $gitExe
+}
+
 function WriteMessage($str) {
     Write-Output $str
     if ($logFile -ne "") {
@@ -11,7 +34,7 @@ function WriteMessage($str) {
 }
 
 function WriteErrorMessage($str) {
-    $host.ui.WriteErrorLine($str);
+    $host.ui.WriteErrorLine($str)
     if ($logFile -ne "") {
         Write-Output $str | Out-File $logFile -Append
     }
@@ -19,17 +42,17 @@ function WriteErrorMessage($str) {
 
 function ExecuteCommand($cmd) {
     if ($cmd -eq "") {
-        return;
+        return
     }
     WriteMessage "-------------------------------------"
     WriteMessage "Running $cmd"
     if ($noaction) {
-        return;
+        return
     }
     Invoke-Expression $cmd
-    if($lastexitcode -ne 0) {
+    if ($lastexitcode -ne 0) {
         WriteErrorMessage "ERROR: Command failed: exit code $LastExitCode"
-        $global:exitcode = $LastExitCode;
+        $global:exitcode = $LastExitCode
     }
     WriteMessage ""
 }

+ 8 - 0
README.md

@@ -13,6 +13,9 @@ You can stay up-to-date on progress by following the [MSEdge developer blog](htt
 | __x86__ | [![x86debug][x86dbgicon]][x86dbglink] | [![x86test][x86testicon]][x86testlink] | [![x86release][x86relicon]][x86rellink] |
 | __x64__ | [![x64debug][x64dbgicon]][x64dbglink] | [![x64test][x64testicon]][x64testlink] | [![x64release][x64relicon]][x64rellink] |
 | __arm__ | [![armdebug][armdbgicon]][armdbglink] | [![armtest][armtesticon]][armtestlink] | [![armrelease][armrelicon]][armrellink] |
+| __linux__ | [![linuxdebug][linuxdbgicon]][linuxdbglink] | N/A | [![linuxrelease][linuxrelicon]][linuxrellink] |
+
+*If you see badges reading "Build: Unknown" it is likely because a build was skipped due to changes being only in files known not to affect the health of the build.*
 
 [x86dbgicon]: http://dotnet-ci.cloudapp.net/job/Microsoft_ChakraCore/job/master/job/x86_debug/badge/icon
 [x86dbglink]: http://dotnet-ci.cloudapp.net/job/Microsoft_ChakraCore/job/master/job/x86_debug/
@@ -35,6 +38,11 @@ You can stay up-to-date on progress by following the [MSEdge developer blog](htt
 [armrelicon]: http://dotnet-ci.cloudapp.net/job/Microsoft_ChakraCore/job/master/job/arm_release/badge/icon
 [armrellink]: http://dotnet-ci.cloudapp.net/job/Microsoft_ChakraCore/job/master/job/arm_release/
 
+[linuxdbgicon]: http://dotnet-ci.cloudapp.net/job/Microsoft_ChakraCore/job/master/job/ubuntu_linux_debug/badge/icon
+[linuxdbglink]: http://dotnet-ci.cloudapp.net/job/Microsoft_ChakraCore/job/master/job/ubuntu_linux_debug
+[linuxrelicon]: http://dotnet-ci.cloudapp.net/job/Microsoft_ChakraCore/job/master/job/ubuntu_linux_release/badge/icon
+[linuxrellink]: http://dotnet-ci.cloudapp.net/job/Microsoft_ChakraCore/job/master/job/ubuntu_linux_release/
+
 Above is a table of our rolling build status. We run additional builds on a daily basis. See [Build Status](https://github.com/Microsoft/ChakraCore/wiki/Build-Status) for the status of all builds.
 
 ## Security

+ 3 - 2
bin/ch/Debugger.cpp

@@ -171,14 +171,15 @@ JsValueRef Debugger::Evaluate(JsValueRef callee, bool isConstructCall, JsValueRe
     int stackFrameIndex;
     JsValueRef result = JS_INVALID_REFERENCE;
 
-    if (argumentCount > 2) {
+    if (argumentCount > 2)
+    {
         IfJsErrorFailLogAndRet(ChakraRTInterface::JsNumberToInt(arguments[1], &stackFrameIndex));
 
         LPCWSTR str = nullptr;
         size_t length;
         IfJsErrorFailLogAndRet(ChakraRTInterface::JsValueToWchar(arguments[2], &str, &length));
 
-        IfJsErrorFailLogAndRet(ChakraRTInterface::JsDiagEvaluate(str, stackFrameIndex, &result));
+        ChakraRTInterface::JsDiagEvaluate(str, stackFrameIndex, &result);
     }
 
     return result;

+ 3 - 3
lib/Backend/BackwardPass.cpp

@@ -444,7 +444,7 @@ BackwardPass::MergeSuccBlocksInfo(BasicBlock * block)
             char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
 #endif
             // save the byteCodeUpwardExposedUsed from deleting for the block right after the memop loop
-            if (this->tag == Js::DeadStorePhase && !this->IsPrePass() && globOpt->DoMemOp(block->loop) && blockSucc->loop != block->loop)
+            if (this->tag == Js::DeadStorePhase && !this->IsPrePass() && globOpt->HasMemOp(block->loop) && blockSucc->loop != block->loop)
             {
                 Assert(block->loop->memOpInfo->inductionVariablesUsedAfterLoop == nullptr);
                 block->loop->memOpInfo->inductionVariablesUsedAfterLoop = JitAnew(this->tempAlloc, BVSparse<JitArenaAllocator>, this->tempAlloc);
@@ -7117,7 +7117,7 @@ BackwardPass::DoDeadStoreLdStForMemop(IR::Instr *instr)
 
     Loop *loop = this->currentBlock->loop;
 
-    if (globOpt->DoMemOp(loop))
+    if (globOpt->HasMemOp(loop))
     {
         if (instr->m_opcode == Js::OpCode::StElemI_A && instr->GetDst()->IsIndirOpnd())
         {
@@ -7185,7 +7185,7 @@ BackwardPass::RestoreInductionVariableValuesAfterMemOp(Loop *loop)
 bool
 BackwardPass::IsEmptyLoopAfterMemOp(Loop *loop)
 {
-    if (globOpt->DoMemOp(loop))
+    if (globOpt->HasMemOp(loop))
     {
         const auto IsInductionVariableUse = [&](IR::Opnd *opnd) -> bool
         {

+ 132 - 59
lib/Backend/BailOut.cpp

@@ -1050,6 +1050,15 @@ Js::Var BailOutRecord::BailOut(BailOutRecord const * bailOutRecord)
 #endif
 
     Js::JavascriptCallStackLayout *const layout = bailOutRecord->GetStackLayout();
+    Js::ScriptFunction * function = (Js::ScriptFunction *)layout->functionObject;
+
+    if (bailOutRecord->bailOutKind == IR::BailOutOnImplicitCalls)
+    {
+        function->GetScriptContext()->GetThreadContext()->CheckAndResetImplicitCallAccessorFlag();
+    }
+
+    Js::ImplicitCallFlags savedImplicitCallFlags = function->GetScriptContext()->GetThreadContext()->GetImplicitCallFlags();
+
     if(bailOutRecord->globalBailOutRecordTable->isLoopBody)
     {
         if (bailOutRecord->globalBailOutRecordTable->isInlinedFunction)
@@ -1060,9 +1069,9 @@ Js::Var BailOutRecord::BailOut(BailOutRecord const * bailOutRecord)
     }
     if(bailOutRecord->globalBailOutRecordTable->isInlinedFunction)
     {
-        return BailOutInlined(layout, bailOutRecord, _ReturnAddress());
+        return BailOutInlined(layout, bailOutRecord, _ReturnAddress(), savedImplicitCallFlags);
     }
-    return BailOutFromFunction(layout, bailOutRecord, _ReturnAddress(), argoutRestoreAddr);
+    return BailOutFromFunction(layout, bailOutRecord, _ReturnAddress(), argoutRestoreAddr, savedImplicitCallFlags);
 }
 
 uint32
@@ -1073,18 +1082,18 @@ BailOutRecord::BailOutFromLoopBody(Js::JavascriptCallStackLayout * layout, BailO
 }
 
 Js::Var
-BailOutRecord::BailOutFromFunction(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord, void * returnAddress, void * argoutRestoreAddress)
+BailOutRecord::BailOutFromFunction(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord, void * returnAddress, void * argoutRestoreAddress, Js::ImplicitCallFlags savedImplicitCallFlags)
 {
     Assert(bailOutRecord->parent == nullptr);
 
-    return BailOutCommon(layout, bailOutRecord, bailOutRecord->bailOutOffset, returnAddress, bailOutRecord->bailOutKind, nullptr, nullptr, argoutRestoreAddress);
+    return BailOutCommon(layout, bailOutRecord, bailOutRecord->bailOutOffset, returnAddress, bailOutRecord->bailOutKind, savedImplicitCallFlags, nullptr, nullptr, argoutRestoreAddress);
 }
 
 Js::Var
-BailOutRecord::BailOutInlined(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord, void * returnAddress)
+BailOutRecord::BailOutInlined(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord, void * returnAddress, Js::ImplicitCallFlags savedImplicitCallFlags)
 {
     Assert(bailOutRecord->parent != nullptr);
-    return BailOutInlinedCommon(layout, bailOutRecord, bailOutRecord->bailOutOffset, returnAddress, bailOutRecord->bailOutKind);
+    return BailOutInlinedCommon(layout, bailOutRecord, bailOutRecord->bailOutOffset, returnAddress, bailOutRecord->bailOutKind, savedImplicitCallFlags);
 }
 
 uint32
@@ -1109,7 +1118,7 @@ BailOutRecord::BailOutCommonNoCodeGen(Js::JavascriptCallStackLayout * layout, Ba
 
 Js::Var
 BailOutRecord::BailOutCommon(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord,
-uint32 bailOutOffset, void * returnAddress, IR::BailOutKind bailOutKind, Js::Var branchValue, BailOutReturnValue * bailOutReturnValue, void * argoutRestoreAddress)
+uint32 bailOutOffset, void * returnAddress, IR::BailOutKind bailOutKind, Js::ImplicitCallFlags savedImplicitCallFlags, Js::Var branchValue, BailOutReturnValue * bailOutReturnValue, void * argoutRestoreAddress)
 {
     // Do not remove the following code.
     // Need to capture the int registers on stack as threadContext->bailOutRegisterSaveSpace is allocated from ThreadAlloc and is not scanned by recycler.
@@ -1119,13 +1128,13 @@ uint32 bailOutOffset, void * returnAddress, IR::BailOutKind bailOutKind, Js::Var
         sizeof(registerSaves));
 
     Js::Var result = BailOutCommonNoCodeGen(layout, bailOutRecord, bailOutOffset, returnAddress, bailOutKind, branchValue, nullptr, bailOutReturnValue, argoutRestoreAddress);
-    ScheduleFunctionCodeGen(Js::ScriptFunction::FromVar(layout->functionObject), nullptr, bailOutRecord, bailOutKind, returnAddress);
+    ScheduleFunctionCodeGen(Js::ScriptFunction::FromVar(layout->functionObject), nullptr, bailOutRecord, bailOutKind, savedImplicitCallFlags, returnAddress);
     return result;
 }
 
 Js::Var
 BailOutRecord::BailOutInlinedCommon(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord, uint32 bailOutOffset,
-    void * returnAddress, IR::BailOutKind bailOutKind, Js::Var branchValue)
+    void * returnAddress, IR::BailOutKind bailOutKind, Js::ImplicitCallFlags savedImplicitCallFlags, Js::Var branchValue)
 {
     Assert(bailOutRecord->parent != nullptr);
 
@@ -1140,7 +1149,7 @@ BailOutRecord::BailOutInlinedCommon(Js::JavascriptCallStackLayout * layout, Bail
     BailOutInlinedHelper(layout, currentBailOutRecord, bailOutOffset, returnAddress, bailOutKind, registerSaves, &bailOutReturnValue, &innerMostInlinee, false, branchValue);
     Js::Var result = BailOutCommonNoCodeGen(layout, currentBailOutRecord, currentBailOutRecord->bailOutOffset, returnAddress, bailOutKind, branchValue,
         registerSaves, &bailOutReturnValue);
-    ScheduleFunctionCodeGen(Js::ScriptFunction::FromVar(layout->functionObject), innerMostInlinee, currentBailOutRecord, bailOutKind, returnAddress);
+    ScheduleFunctionCodeGen(Js::ScriptFunction::FromVar(layout->functionObject), innerMostInlinee, currentBailOutRecord, bailOutKind, savedImplicitCallFlags, returnAddress);
     return result;
 }
 
@@ -1704,7 +1713,7 @@ BailOutRecord::BailOutHelper(Js::JavascriptCallStackLayout * layout, Js::ScriptF
 // we "rethunk" the bailing out function rather that incurring a rejit.
 
 void BailOutRecord::ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee,
-    BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind, void * returnAddress)
+    BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind, Js::ImplicitCallFlags savedImplicitCallFlags, void * returnAddress)
 {
     if (bailOutKind == IR::BailOnSimpleJitToFullJitLoopBody ||
         bailOutKind == IR::BailOutForGeneratorYield ||
@@ -1732,40 +1741,7 @@ void BailOutRecord::ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::S
 
     callsCount = callsCount <= Js::FunctionEntryPointInfo::GetDecrCallCountPerBailout() ? 0 : callsCount - Js::FunctionEntryPointInfo::GetDecrCallCountPerBailout() ;
 
-    if (bailOutKind == IR::BailOutOnNoProfile && executeFunction->IncrementBailOnMisingProfileCount() > CONFIG_FLAG(BailOnNoProfileLimit))
-    {
-        // A rejit here should improve code quality, so lets avoid too many unnecessary bailouts.
-        executeFunction->ResetBailOnMisingProfileCount();
-        bailOutRecordNotConst->bailOutCount = 0;
-        callsCount = 0;
-    }
-    else if (bailOutRecordNotConst->bailOutCount > CONFIG_FLAG(RejitMaxBailOutCount))
-    {
-        switch(bailOutKind)
-        {
-            case IR::BailOutOnPolymorphicInlineFunction:
-            case IR::BailOutOnFailedPolymorphicInlineTypeCheck:
-            case IR::BailOutFailedInlineTypeCheck:
-            case IR::BailOutOnInlineFunction:
-            case IR::BailOutFailedTypeCheck:
-            case IR::BailOutFailedFixedFieldTypeCheck:
-            case IR::BailOutFailedCtorGuardCheck:
-            case IR::BailOutFailedFixedFieldCheck:
-            case IR::BailOutFailedEquivalentTypeCheck:
-            case IR::BailOutFailedEquivalentFixedFieldTypeCheck:
-                {
-                    // If we consistently see RejitMaxBailOutCount bailouts for these kinds, then likely we have stale profile data and it is beneficial to rejit.
-                    // Note you need to include only bailout kinds which don't disable the entire optimizations.
-                    REJIT_KIND_TESTTRACE(bailOutKind, _u("Force rejit as RejitMaxBailoOutCount reached for a bailout record: function: %s, bailOutKindName: (%S), bailOutCount: %d, callCount: %d RejitMaxBailoutCount: %d\r\n"),
-                        function->GetFunctionBody()->GetDisplayName(), ::GetBailOutKindName(bailOutKind), bailOutRecordNotConst->bailOutCount, callsCount, CONFIG_FLAG(RejitMaxBailOutCount));
-
-                    bailOutRecordNotConst->bailOutCount = 0;
-                    callsCount = 0;
-                    break;
-                }
-            default: break;
-        }
-    }
+    CheckPreemptiveRejit(executeFunction, bailOutKind, bailOutRecordNotConst, callsCount, -1);
 
     entryPointInfo->callsCount = callsCount;
 
@@ -1865,10 +1841,10 @@ void BailOutRecord::ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::S
                 // Check if the implicit call flags in the profile have changed since we last JITed this
                 // function body. If so, and they indicate an implicit call of some sort occurred
                 // then we need to reJIT.
-                if (executeFunction->GetSavedImplicitCallsFlags() == Js::ImplicitCall_None ||
-                    executeFunction->GetSavedImplicitCallsFlags() == Js::ImplicitCall_HasNoInfo)
+                if ((executeFunction->GetSavedImplicitCallsFlags() & savedImplicitCallFlags) == Js::ImplicitCall_None)
                 {
-                    profileInfo->RecordImplicitCallFlags(executeFunction->GetScriptContext()->GetThreadContext()->GetImplicitCallFlags());
+                    profileInfo->RecordImplicitCallFlags(savedImplicitCallFlags);
+                    profileInfo->DisableLoopImplicitCallInfo();
                     rejitReason = RejitReason::ImplicitCallFlagsChanged;
                 }
                 else
@@ -1894,7 +1870,17 @@ void BailOutRecord::ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::S
                 break;
 
             case IR::BailOutOnNotNativeArray:
-                rejitReason = RejitReason::ExpectingNativeArray;
+
+                // REVIEW: We have an issue with array profile info.  The info on the type of array we have won't 
+                //         get fixed by rejitting.  For now, just give up after 50 rejits.
+                if (profileInfo->GetRejitCount() >= 50)
+                {
+                    reThunk = true;
+                }
+                else
+                {
+                    rejitReason = RejitReason::ExpectingNativeArray;
+                }
                 break;
 
             case IR::BailOutConvertedNativeArray:
@@ -2173,6 +2159,21 @@ void BailOutRecord::ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::S
         rejitReason = RejitReason::Forced;
     }
 
+    // REVIEW: Temporary fix for RS1.  Disable Rejiting if it looks like it is not fixing the problem.
+    //         For RS2, turn this into an assert and let's fix all these issues.
+    if (!reThunk && rejitReason != RejitReason::None)
+    {
+        if (executeFunction->GetDynamicProfileInfo()->GetRejitCount() >= 100)
+        {
+            reThunk = true;
+            rejitReason = RejitReason::None;
+        }
+        else
+        {
+            executeFunction->GetDynamicProfileInfo()->IncRejitCount();
+        }
+    }
+
     REJIT_KIND_TESTTRACE(bailOutKind, _u("Bailout from function: function: %s, bailOutKindName: (%S), bailOutCount: %d, callCount: %d, reJitReason: %S, reThunk: %s\r\n"),
         function->GetFunctionBody()->GetDisplayName(), ::GetBailOutKindName(bailOutKind), bailOutRecord->bailOutCount, callsCount,
         RejitReasonNames[rejitReason], reThunk ? trueString : falseString);
@@ -2263,15 +2264,28 @@ void BailOutRecord::ScheduleLoopBodyCodeGen(Js::ScriptFunction * function, Js::S
     Assert(loopHeader != nullptr);
 
     BailOutRecord * bailOutRecordNotConst = (BailOutRecord *)(void *)bailOutRecord;
+    bailOutRecordNotConst->bailOutCount++;
+
     RejitReason rejitReason = RejitReason::None;
     Assert(bailOutKind != IR::BailOutInvalid);
 
-    if (bailOutRecordNotConst->bailOutCount < 1)
+    Js::LoopEntryPointInfo* entryPointInfo = loopHeader->GetCurrentEntryPointInfo();
+
+    entryPointInfo->totalJittedLoopIterations += entryPointInfo->jittedLoopIterationsSinceLastBailout;
+    entryPointInfo->jittedLoopIterationsSinceLastBailout = 0;
+    if (entryPointInfo->totalJittedLoopIterations > UINT8_MAX)
     {
-        // Ignore the first bailout
-        bailOutRecordNotConst->bailOutCount++;
+        entryPointInfo->totalJittedLoopIterations = UINT8_MAX;
     }
-    else if (executeFunction->HasDynamicProfileInfo())
+    uint8 totalJittedLoopIterations = (uint8)entryPointInfo->totalJittedLoopIterations;
+    totalJittedLoopIterations = totalJittedLoopIterations <= Js::LoopEntryPointInfo::GetDecrLoopCountPerBailout() ? 0 : totalJittedLoopIterations - Js::LoopEntryPointInfo::GetDecrLoopCountPerBailout();
+
+    CheckPreemptiveRejit(executeFunction, bailOutKind, bailOutRecordNotConst, totalJittedLoopIterations, interpreterFrame->GetCurrentLoopNum());
+    
+    entryPointInfo->totalJittedLoopIterations = totalJittedLoopIterations;
+    
+    if ((executeFunction->HasDynamicProfileInfo() && totalJittedLoopIterations == 0) ||
+        PHASE_FORCE(Js::ReJITPhase, executeFunction))
     {
         Js::DynamicProfileInfo * profileInfo = executeFunction->GetAnyDynamicProfileInfo();
 
@@ -2490,6 +2504,11 @@ void BailOutRecord::ScheduleLoopBodyCodeGen(Js::ScriptFunction * function, Js::S
         }
     }
 
+    if (PHASE_FORCE(Js::ReJITPhase, executeFunction) && rejitReason == RejitReason::None)
+    {
+        rejitReason = RejitReason::Forced;
+    }
+
     REJIT_KIND_TESTTRACE(bailOutKind, _u("Bailout from loop: function: %s, loopNumber: %d, bailOutKindName: (%S), reJitReason: %S\r\n"),
         function->GetFunctionBody()->GetDisplayName(), executeFunction->GetLoopNumber(loopHeader),
         ::GetBailOutKindName(bailOutKind), RejitReasonNames[rejitReason]);
@@ -2536,6 +2555,51 @@ void BailOutRecord::ScheduleLoopBodyCodeGen(Js::ScriptFunction * function, Js::S
     }
 }
 
+void BailOutRecord::CheckPreemptiveRejit(Js::FunctionBody* executeFunction, IR::BailOutKind bailOutKind, BailOutRecord* bailoutRecord, uint8& callsOrIterationsCount, int loopNumber)
+{
+    if (bailOutKind == IR::BailOutOnNoProfile && executeFunction->IncrementBailOnMisingProfileCount() > CONFIG_FLAG(BailOnNoProfileLimit))
+    {
+        // A rejit here should improve code quality, so lets avoid too many unnecessary bailouts.
+        executeFunction->ResetBailOnMisingProfileCount();
+        bailoutRecord->bailOutCount = 0;
+        callsOrIterationsCount = 0;
+    }
+    else if (bailoutRecord->bailOutCount > CONFIG_FLAG(RejitMaxBailOutCount))
+    {
+        switch (bailOutKind)
+        {
+        case IR::BailOutOnPolymorphicInlineFunction:
+        case IR::BailOutOnFailedPolymorphicInlineTypeCheck:
+        case IR::BailOutFailedInlineTypeCheck:
+        case IR::BailOutOnInlineFunction:
+        case IR::BailOutFailedTypeCheck:
+        case IR::BailOutFailedFixedFieldTypeCheck:
+        case IR::BailOutFailedCtorGuardCheck:
+        case IR::BailOutFailedFixedFieldCheck:
+        case IR::BailOutFailedEquivalentTypeCheck:
+        case IR::BailOutFailedEquivalentFixedFieldTypeCheck:
+        {
+            // If we consistently see RejitMaxBailOutCount bailouts for these kinds, then likely we have stale profile data and it is beneficial to rejit.
+            // Note you need to include only bailout kinds which don't disable the entire optimizations.
+            if (loopNumber == -1)
+            {
+                REJIT_KIND_TESTTRACE(bailOutKind, _u("Force rejit as RejitMaxBailoOutCount reached for a bailout record: function: %s, bailOutKindName: (%S), bailOutCount: %d, callCount: %d RejitMaxBailoutCount: %d\r\n"),
+                    executeFunction->GetDisplayName(), ::GetBailOutKindName(bailOutKind), bailoutRecord->bailOutCount, callsOrIterationsCount, CONFIG_FLAG(RejitMaxBailOutCount));
+            }
+            else
+            {
+                REJIT_KIND_TESTTRACE(bailOutKind, _u("Force rejit as RejitMaxBailoOutCount reached for a bailout record: function: %s, loopNumber: %d, bailOutKindName: (%S), bailOutCount: %d, callCount: %d RejitMaxBailoutCount: %d\r\n"),
+                    executeFunction->GetDisplayName(), loopNumber, ::GetBailOutKindName(bailOutKind), bailoutRecord->bailOutCount, callsOrIterationsCount, CONFIG_FLAG(RejitMaxBailOutCount));
+            }
+            bailoutRecord->bailOutCount = 0;
+            callsOrIterationsCount = 0;
+            break;
+        }
+        default: break;
+        }
+    }
+}
+
 Js::Var BailOutRecord::BailOutForElidedYield(void * framePointer)
 {
     Js::JavascriptCallStackLayout * const layout = Js::JavascriptCallStackLayout::FromFramePointer(framePointer);
@@ -2599,6 +2663,15 @@ Js::Var BranchBailOutRecord::BailOut(BranchBailOutRecord const * bailOutRecord,
 #endif
 
     Js::JavascriptCallStackLayout *const layout = bailOutRecord->GetStackLayout();
+    Js::ScriptFunction * function = (Js::ScriptFunction *)layout->functionObject;
+
+    if (bailOutRecord->bailOutKind == IR::BailOutOnImplicitCalls)
+    {
+        function->GetScriptContext()->GetThreadContext()->CheckAndResetImplicitCallAccessorFlag();
+    }
+
+    Js::ImplicitCallFlags savedImplicitCallFlags = function->GetScriptContext()->GetThreadContext()->GetImplicitCallFlags();
+
     if(bailOutRecord->globalBailOutRecordTable->isLoopBody)
     {
         if (bailOutRecord->globalBailOutRecordTable->isInlinedFunction)
@@ -2609,13 +2682,13 @@ Js::Var BranchBailOutRecord::BailOut(BranchBailOutRecord const * bailOutRecord,
     }
     if(bailOutRecord->globalBailOutRecordTable->isInlinedFunction)
     {
-        return BailOutInlined(layout, bailOutRecord, cond, _ReturnAddress());
+        return BailOutInlined(layout, bailOutRecord, cond, _ReturnAddress(), savedImplicitCallFlags);
     }
-    return BailOutFromFunction(layout, bailOutRecord, cond, _ReturnAddress(), argoutRestoreAddr);
+    return BailOutFromFunction(layout, bailOutRecord, cond, _ReturnAddress(), argoutRestoreAddr, savedImplicitCallFlags);
 }
 
 Js::Var
-BranchBailOutRecord::BailOutFromFunction(Js::JavascriptCallStackLayout * layout, BranchBailOutRecord const * bailOutRecord, BOOL cond, void * returnAddress, void * argoutRestoreAddress)
+BranchBailOutRecord::BailOutFromFunction(Js::JavascriptCallStackLayout * layout, BranchBailOutRecord const * bailOutRecord, BOOL cond, void * returnAddress, void * argoutRestoreAddress, Js::ImplicitCallFlags savedImplicitCallFlags)
 {
     Assert(bailOutRecord->parent == nullptr);
     uint32 bailOutOffset = cond? bailOutRecord->bailOutOffset : bailOutRecord->falseBailOutOffset;
@@ -2625,7 +2698,7 @@ BranchBailOutRecord::BailOutFromFunction(Js::JavascriptCallStackLayout * layout,
         Js::ScriptContext *scriptContext = layout->functionObject->GetScriptContext();
         branchValue = (cond ? scriptContext->GetLibrary()->GetTrue() : scriptContext->GetLibrary()->GetFalse());
     }
-    return __super::BailOutCommon(layout, bailOutRecord, bailOutOffset, returnAddress, bailOutRecord->bailOutKind,  branchValue, nullptr, argoutRestoreAddress);
+    return __super::BailOutCommon(layout, bailOutRecord, bailOutOffset, returnAddress, bailOutRecord->bailOutKind, savedImplicitCallFlags, branchValue, nullptr, argoutRestoreAddress);
 }
 
 uint32
@@ -2643,7 +2716,7 @@ BranchBailOutRecord::BailOutFromLoopBody(Js::JavascriptCallStackLayout * layout,
 }
 
 Js::Var
-BranchBailOutRecord::BailOutInlined(Js::JavascriptCallStackLayout * layout, BranchBailOutRecord const * bailOutRecord, BOOL cond, void * returnAddress)
+BranchBailOutRecord::BailOutInlined(Js::JavascriptCallStackLayout * layout, BranchBailOutRecord const * bailOutRecord, BOOL cond, void * returnAddress, Js::ImplicitCallFlags savedImplicitCallFlags)
 {
     Assert(bailOutRecord->parent != nullptr);
     uint32 bailOutOffset = cond? bailOutRecord->bailOutOffset : bailOutRecord->falseBailOutOffset;
@@ -2653,7 +2726,7 @@ BranchBailOutRecord::BailOutInlined(Js::JavascriptCallStackLayout * layout, Bran
         Js::ScriptContext *scriptContext = layout->functionObject->GetScriptContext();
         branchValue = (cond ? scriptContext->GetLibrary()->GetTrue() : scriptContext->GetLibrary()->GetFalse());
     }
-    return __super::BailOutInlinedCommon(layout, bailOutRecord, bailOutOffset, returnAddress, bailOutRecord->bailOutKind, branchValue);
+    return __super::BailOutInlinedCommon(layout, bailOutRecord, bailOutOffset, returnAddress, bailOutRecord->bailOutKind, savedImplicitCallFlags, branchValue);
 }
 
 uint32

+ 8 - 8
lib/Backend/BailOut.h

@@ -166,10 +166,10 @@ class BailOutRecord
 public:
     BailOutRecord(uint32 bailOutOffset, uint bailOutCacheIndex, IR::BailOutKind kind, Func *bailOutFunc);
     static Js::Var BailOut(BailOutRecord const * bailOutRecord);
-    static Js::Var BailOutFromFunction(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord, void * returnAddress, void * argoutRestoreAddress);
+    static Js::Var BailOutFromFunction(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord, void * returnAddress, void * argoutRestoreAddress, Js::ImplicitCallFlags savedImplicitCallFlags);
     static uint32 BailOutFromLoopBody(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord);
 
-    static Js::Var BailOutInlined(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord, void * returnAddress);
+    static Js::Var BailOutInlined(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord, void * returnAddress, Js::ImplicitCallFlags savedImplicitCallFlags);
     static uint32 BailOutFromLoopBodyInlined(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord, void * returnAddress);
 
     static Js::Var BailOutForElidedYield(void * framePointer);
@@ -217,9 +217,9 @@ protected:
         uint32 bailOutOffset, void * returnAddress, IR::BailOutKind bailOutKind, Js::Var branchValue = nullptr, Js::Var * registerSaves = nullptr,
         BailOutReturnValue * returnValue = nullptr, void * argoutRestoreAddress = nullptr);
     static Js::Var BailOutCommon(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord,
-        uint32 bailOutOffset, void * returnAddress, IR::BailOutKind bailOutKind, Js::Var branchValue = nullptr, BailOutReturnValue * returnValue = nullptr, void * argoutRestoreAddress = nullptr);
+        uint32 bailOutOffset, void * returnAddress, IR::BailOutKind bailOutKind, Js::ImplicitCallFlags savedImplicitCallFlags, Js::Var branchValue = nullptr, BailOutReturnValue * returnValue = nullptr, void * argoutRestoreAddress = nullptr);
     static Js::Var BailOutInlinedCommon(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord,
-        uint32 bailOutOffset, void * returnAddress, IR::BailOutKind bailOutKind, Js::Var branchValue = nullptr);
+        uint32 bailOutOffset, void * returnAddress, IR::BailOutKind bailOutKind, Js::ImplicitCallFlags savedImplicitCallFlags, Js::Var branchValue = nullptr);
     static uint32 BailOutFromLoopBodyCommon(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord,
         uint32 bailOutOffset, IR::BailOutKind bailOutKind, Js::Var branchValue = nullptr);
     static uint32 BailOutFromLoopBodyInlinedCommon(Js::JavascriptCallStackLayout * layout, BailOutRecord const * bailOutRecord,
@@ -235,9 +235,9 @@ protected:
 
     static void UpdatePolymorphicFieldAccess(Js::JavascriptFunction *  function, BailOutRecord const * bailOutRecord);
 
-    static void ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind, void * returnAddress);
+    static void ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind, Js::ImplicitCallFlags savedImplicitCallFlags, void * returnAddress);
     static void ScheduleLoopBodyCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind);
-
+    static void CheckPreemptiveRejit(Js::FunctionBody* executeFunction, IR::BailOutKind bailOutKind, BailOutRecord* bailoutRecord, uint8& callsOrIterationsCount, int loopNumber);
     void RestoreValues(IR::BailOutKind bailOutKind, Js::JavascriptCallStackLayout * layout, Js::InterpreterStackFrame * newInstance, Js::ScriptContext * scriptContext,
         bool fromLoopBody, Js::Var * registerSaves, BailOutReturnValue * returnValue, Js::Var* pArgumentsObject, Js::Var branchValue = nullptr, void* returnAddress = nullptr, bool useStartCall = true, void * argoutRestoreAddress = nullptr) const;
     void RestoreValues(IR::BailOutKind bailOutKind, Js::JavascriptCallStackLayout * layout, uint count, __in_ecount_opt(count) int * offsets, int argOutSlotId,
@@ -337,10 +337,10 @@ public:
     BranchBailOutRecord(uint32 trueBailOutOffset, uint32 falseBailOutOffset, Js::RegSlot resultByteCodeReg, IR::BailOutKind kind, Func *bailOutFunc);
 
     static Js::Var BailOut(BranchBailOutRecord const * bailOutRecord, BOOL cond);
-    static Js::Var BailOutFromFunction(Js::JavascriptCallStackLayout * layout, BranchBailOutRecord const * bailOutRecord, BOOL cond, void * returnAddress, void * argoutRestoreAddress);
+    static Js::Var BailOutFromFunction(Js::JavascriptCallStackLayout * layout, BranchBailOutRecord const * bailOutRecord, BOOL cond, void * returnAddress, void * argoutRestoreAddress, Js::ImplicitCallFlags savedImplicitCallFlags);
     static uint32 BailOutFromLoopBody(Js::JavascriptCallStackLayout * layout, BranchBailOutRecord const * bailOutRecord, BOOL cond);
 
-    static Js::Var BailOutInlined(Js::JavascriptCallStackLayout * layout, BranchBailOutRecord const * bailOutRecord, BOOL cond, void * returnAddress);
+    static Js::Var BailOutInlined(Js::JavascriptCallStackLayout * layout, BranchBailOutRecord const * bailOutRecord, BOOL cond, void * returnAddress, Js::ImplicitCallFlags savedImplicitCallFlags);
     static uint32 BailOutFromLoopBodyInlined(Js::JavascriptCallStackLayout * layout, BranchBailOutRecord const * bailOutRecord, BOOL cond, void * returnAddress);
 private:
     uint falseBailOutOffset;

+ 8 - 23
lib/Backend/FlowGraph.cpp

@@ -747,6 +747,7 @@ FlowGraph::BuildLoop(BasicBlock *headBlock, BasicBlock *tailBlock, Loop *parentL
     loop->hasDeadStoreCollectionPass = false;
     loop->hasDeadStorePrepass = false;
     loop->memOpInfo = nullptr;
+    loop->doMemOp = true;
 
     NoRecoverMemoryJitArenaAllocator tempAlloc(_u("BE-LoopBuilder"), this->func->m_alloc->GetPageAllocator(), Js::Throw::OutOfMemory);
 
@@ -761,6 +762,10 @@ FlowGraph::BuildLoop(BasicBlock *headBlock, BasicBlock *tailBlock, Loop *parentL
     if (firstInstr->IsProfiledLabelInstr())
     {
         loop->SetImplicitCallFlags(firstInstr->AsProfiledLabelInstr()->loopImplicitCallFlags);
+        if (this->func->GetProfileInfo()->IsLoopImplicitCallInfoDisabled())
+        {
+            loop->SetImplicitCallFlags(this->func->GetProfileInfo()->GetImplicitCallFlags());
+        }
         loop->SetLoopFlags(firstInstr->AsProfiledLabelInstr()->loopFlags);
     }
     else
@@ -782,8 +787,10 @@ Loop::MemSetCandidate* Loop::MemOpCandidate::AsMemSet()
     return (Loop::MemSetCandidate*)this;
 }
 
-bool Loop::EnsureMemOpVariablesInitialized()
+void
+Loop::EnsureMemOpVariablesInitialized()
 {
+    Assert(this->doMemOp);
     if (this->memOpInfo == nullptr)
     {
         JitArenaAllocator *allocator = this->GetFunc()->GetTopFunc()->m_fg->alloc;
@@ -793,32 +800,10 @@ bool Loop::EnsureMemOpVariablesInitialized()
         this->memOpInfo->startIndexOpndCache[1] = nullptr;
         this->memOpInfo->startIndexOpndCache[2] = nullptr;
         this->memOpInfo->startIndexOpndCache[3] = nullptr;
-        if (this->GetLoopFlags().isInterpreted && !this->GetLoopFlags().memopMinCountReached)
-        {
-#if DBG_DUMP
-            Func* func = this->GetFunc();
-            if (Js::Configuration::Global.flags.Verbose && PHASE_TRACE(Js::MemOpPhase, func))
-            {
-                char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-                Output::Print(_u("MemOp skipped: minimum loop count not reached: Function: %s %s,  Loop: %d\n"),
-                              func->GetJnFunction()->GetDisplayName(),
-                              func->GetJnFunction()->GetDebugNumberSet(debugStringBuffer),
-                              this->GetLoopNumber()
-                              );
-            }
-#endif
-            this->memOpInfo->doMemOp = false;
-            this->memOpInfo->inductionVariableChangeInfoMap = nullptr;
-            this->memOpInfo->inductionVariableOpndPerUnrollMap = nullptr;
-            this->memOpInfo->candidates = nullptr;
-            return false;
-        }
-        this->memOpInfo->doMemOp = true;
         this->memOpInfo->inductionVariableChangeInfoMap = JitAnew(allocator, Loop::InductionVariableChangeInfoMap, allocator);
         this->memOpInfo->inductionVariableOpndPerUnrollMap = JitAnew(allocator, Loop::InductionVariableOpndPerUnrollMap, allocator);
         this->memOpInfo->candidates = JitAnew(allocator, Loop::MemOpList, allocator);
     }
-    return true;
 }
 
 // Walk the basic blocks backwards until we find the loop header.

+ 2 - 2
lib/Backend/FlowGraph.h

@@ -664,7 +664,6 @@ public:
     typedef struct
     {
         MemOpList *candidates;
-        bool doMemOp : 1;
         BVSparse<JitArenaAllocator> *inductionVariablesUsedAfterLoop;
         InductionVariableChangeInfoMap *inductionVariableChangeInfoMap;
         InductionVariableOpndPerUnrollMap *inductionVariableOpndPerUnrollMap;
@@ -674,6 +673,7 @@ public:
         IR::RegOpnd* startIndexOpndCache[4];
     } MemOpInfo;
 
+    bool doMemOp : 1;
     MemOpInfo *memOpInfo;
 
     struct RegAlloc
@@ -729,7 +729,7 @@ public:
     BasicBlock *        GetHeadBlock() const { Assert(headBlock == blockList.Head()); return headBlock; }
     bool                IsDescendentOrSelf(Loop const * loop) const;
 
-    bool                EnsureMemOpVariablesInitialized();
+    void                EnsureMemOpVariablesInitialized();
 
     Js::ImplicitCallFlags GetImplicitCallFlags();
     void                SetImplicitCallFlags(Js::ImplicitCallFlags flags);

+ 10 - 0
lib/Backend/Func.cpp

@@ -1275,6 +1275,16 @@ Func::GetCallsCountAddress() const
     return functionCodeGen->GetFunctionBody()->GetCallsCountAddress(functionCodeGen->GetEntryPoint());
 }
 
+uint *
+Func::GetJittedLoopIterationsSinceLastBailoutAddress() const
+{
+    Assert(this->m_workItem->Type() == JsLoopBodyWorkItemType);
+
+    JsLoopBodyCodeGen * loopBodyCodeGen = static_cast<JsLoopBodyCodeGen *>(this->m_workItem);
+
+    return loopBodyCodeGen->GetFunctionBody()->GetJittedLoopIterationsSinceLastBailoutAddress(loopBodyCodeGen->GetEntryPoint());
+}
+
 RecyclerWeakReference<Js::FunctionBody> *
 Func::GetWeakFuncRef() const
 {

+ 1 - 0
lib/Backend/Func.h

@@ -273,6 +273,7 @@ static const unsigned __int64 c_debugFillPattern8 = 0xcececececececece;
     void SetLocalFrameDisplaySym(StackSym *sym) { m_localFrameDisplaySym = sym; }
 
     uint8 *GetCallsCountAddress() const;
+    uint *GetJittedLoopIterationsSinceLastBailoutAddress() const;
 
     void EnsurePinnedTypeRefs();
     void PinTypeRef(void* typeRef);

+ 53 - 50
lib/Backend/GlobOpt.cpp

@@ -4192,31 +4192,34 @@ GlobOpt::IsAllowedForMemOpt(IR::Instr* instr, bool isMemset, IR::RegOpnd *baseOp
     Assert(iv->IsChangeDeterminate() && iv->IsChangeUnidirectional());
     const IntConstantBounds & bounds = iv->ChangeBounds();
 
-    // Only accept induction variables that increments by 1
-    Loop::InductionVariableChangeInfo inductionVariableChangeInfo = { 0, 0 };
-    inductionVariableChangeInfo = loop->memOpInfo->inductionVariableChangeInfoMap->Lookup(indexSymID, inductionVariableChangeInfo);
-
-    if (
-        (bounds.LowerBound() != 1 && bounds.LowerBound() != -1) ||
-        (bounds.UpperBound() != bounds.LowerBound()) ||
-        inductionVariableChangeInfo.unroll > 1 // Must be 0 (not seen yet) or 1 (already seen)
-    )
+    if (loop->memOpInfo)
     {
-        TRACE_MEMOP_VERBOSE(loop, instr, _u("The index does not change by 1: %d><%d, unroll=%d"), bounds.LowerBound(), bounds.UpperBound(), inductionVariableChangeInfo.unroll);
-        return false;
-    }
+        // Only accept induction variables that increments by 1
+        Loop::InductionVariableChangeInfo inductionVariableChangeInfo = { 0, 0 };
+        inductionVariableChangeInfo = loop->memOpInfo->inductionVariableChangeInfoMap->Lookup(indexSymID, inductionVariableChangeInfo);
 
-    // Check if the index is the same in all MemOp optimization in this loop
-    if (!loop->memOpInfo->candidates->Empty())
-    {
-        Loop::MemOpCandidate* previousCandidate = loop->memOpInfo->candidates->Head();
-
-        // All MemOp operations within the same loop must use the same index
-        if (previousCandidate->index != indexSymID)
+        if (
+            (bounds.LowerBound() != 1 && bounds.LowerBound() != -1) ||
+            (bounds.UpperBound() != bounds.LowerBound()) ||
+            inductionVariableChangeInfo.unroll > 1 // Must be 0 (not seen yet) or 1 (already seen)
+        )
         {
-            TRACE_MEMOP_VERBOSE(loop, instr, _u("The index is not the same as other MemOp in the loop"));
+            TRACE_MEMOP_VERBOSE(loop, instr, _u("The index does not change by 1: %d><%d, unroll=%d"), bounds.LowerBound(), bounds.UpperBound(), inductionVariableChangeInfo.unroll);
             return false;
         }
+
+        // Check if the index is the same in all MemOp optimization in this loop
+        if (!loop->memOpInfo->candidates->Empty())
+        {
+            Loop::MemOpCandidate* previousCandidate = loop->memOpInfo->candidates->Head();
+
+            // All MemOp operations within the same loop must use the same index
+            if (previousCandidate->index != indexSymID)
+            {
+                TRACE_MEMOP_VERBOSE(loop, instr, _u("The index is not the same as other MemOp in the loop"));
+                return false;
+            }
+        }
     }
 
     return true;
@@ -4240,6 +4243,7 @@ GlobOpt::CollectMemcopyLdElementI(IR::Instr *instr, Loop *loop)
     SymID inductionSymID = GetVarSymID(indexOpnd->GetStackSym());
     Assert(IsSymIDInductionVariable(inductionSymID, loop));
 
+    loop->EnsureMemOpVariablesInitialized();
     bool isIndexPreIncr = loop->memOpInfo->inductionVariableChangeInfoMap->ContainsKey(inductionSymID);
 
     IR::Opnd * dst = instr->GetDst();
@@ -4310,6 +4314,7 @@ GlobOpt::CollectMemsetStElementI(IR::Instr *instr, Loop *loop)
     SymID inductionSymID = GetVarSymID(indexOp->GetStackSym());
     Assert(IsSymIDInductionVariable(inductionSymID, loop));
 
+    loop->EnsureMemOpVariablesInitialized();
     bool isIndexPreIncr = loop->memOpInfo->inductionVariableChangeInfoMap->ContainsKey(inductionSymID);
 
     Loop::MemSetCandidate* memsetInfo = JitAnewStruct(this->func->GetTopFunc()->m_fg->alloc, Loop::MemSetCandidate);
@@ -4325,6 +4330,12 @@ GlobOpt::CollectMemsetStElementI(IR::Instr *instr, Loop *loop)
 
 bool GlobOpt::CollectMemcopyStElementI(IR::Instr *instr, Loop *loop)
 {
+    if (!loop->memOpInfo || loop->memOpInfo->candidates->Empty())
+    {
+        // There is no ldElem matching this stElem
+        return false;
+    }
+
     Assert(instr->GetDst()->IsIndirOpnd());
     IR::IndirOpnd *dst = instr->GetDst()->AsIndirOpnd();
     IR::Opnd *indexOp = dst->GetIndexOpnd();
@@ -4353,11 +4364,6 @@ bool GlobOpt::CollectMemcopyStElementI(IR::Instr *instr, Loop *loop)
     SymID srcSymID = GetVarSymID(src1->GetStackSym());
 
     // Prepare the memcopyCandidate entry
-    if (loop->memOpInfo->candidates->Empty())
-    {
-        // There is no ldElem matching this stElem
-        return false;
-    }
     Loop::MemOpCandidate* previousCandidate = loop->memOpInfo->candidates->Head();
     if (!previousCandidate->IsMemCopy())
     {
@@ -4422,12 +4428,13 @@ GlobOpt::CollectMemOpInfo(IR::Instr *instr, Value *src1Val, Value *src2Val)
         return false;
     }
 
-    if (!loop->EnsureMemOpVariablesInitialized())
+    if (loop->GetLoopFlags().isInterpreted && !loop->GetLoopFlags().memopMinCountReached)
     {
+        TRACE_MEMOP_VERBOSE(loop, instr, _u("minimum loop count not reached"))
+        loop->doMemOp = false;
         return false;
     }
-
-    Assert(loop->memOpInfo->doMemOp);
+    Assert(loop->doMemOp);
 
     bool isIncr = true, isChangedByOne = false;
     switch (instr->m_opcode)
@@ -4436,14 +4443,14 @@ GlobOpt::CollectMemOpInfo(IR::Instr *instr, Value *src1Val, Value *src2Val)
     case Js::OpCode::StElemI_A_Strict:
         if (!CollectMemOpStElementI(instr, loop))
         {
-            loop->memOpInfo->doMemOp = false;
+            loop->doMemOp = false;
             return false;
         }
         break;
     case Js::OpCode::LdElemI_A:
         if (!CollectMemOpLdElementI(instr, loop))
         {
-            loop->memOpInfo->doMemOp = false;
+            loop->doMemOp = false;
             return false;
         }
         break;
@@ -4500,6 +4507,7 @@ MemOpCheckInductionVariable:
                 }
             }
 
+            loop->EnsureMemOpVariablesInitialized();
             if (!isChangedByOne)
             {
                 Loop::InductionVariableChangeInfo inductionVariableChangeInfo = { Js::Constants::InvalidLoopUnrollFactor, 0 };
@@ -4536,12 +4544,12 @@ MemOpCheckInductionVariable:
     default:
         if (IsInstrInvalidForMemOp(instr, loop, src1Val, src2Val))
         {
-            loop->memOpInfo->doMemOp = false;
+            loop->doMemOp = false;
             return false;
         }
 
         // Make sure this instruction doesn't use the memcopy transfer sym before it is checked by StElemI
-        if (!loop->memOpInfo->candidates->Empty())
+        if (loop->memOpInfo && !loop->memOpInfo->candidates->Empty())
         {
             Loop::MemOpCandidate* prevCandidate = loop->memOpInfo->candidates->Head();
             if (prevCandidate->IsMemCopy())
@@ -4551,7 +4559,7 @@ MemOpCheckInductionVariable:
                 {
                     if (instr->FindRegUse(memcopyCandidate->transferSym))
                     {
-                        loop->memOpInfo->doMemOp = false;
+                        loop->doMemOp = false;
                         TRACE_MEMOP_PHASE_VERBOSE(MemCopy, loop, instr, _u("Found illegal use of LdElemI value(s%d)"), GetVarSymID(memcopyCandidate->transferSym));
                         return false;
                     }
@@ -4873,7 +4881,7 @@ GlobOpt::OptInstr(IR::Instr *&instr, bool* isInstrRemoved)
         this->currentBlock->loop && !IsLoopPrePass() &&
         !func->IsJitInDebugMode() &&
         (func->HasProfileInfo() && !func->GetProfileInfo()->IsMemOpDisabled()) &&
-        (!this->currentBlock->loop->memOpInfo || this->currentBlock->loop->memOpInfo->doMemOp))
+        this->currentBlock->loop->doMemOp)
     {
         CollectMemOpInfo(instr, src1Val, src2Val);
     }
@@ -7929,7 +7937,6 @@ GlobOpt::IsPrepassSrcValueInfoPrecise(IR::Opnd *const src, Value *const srcValue
             !Js::TaggedInt::IsOverflow(intConstantValue) &&
             GetTaggedIntConstantStackSym(intConstantValue) == srcSym
         ) ||
-        this->IsDefinedInCurrentLoopIteration(this->currentBlock->loop, srcValue) ||
         !currentBlock->loop->regAlloc.liveOnBackEdgeSyms->Test(srcSym->m_id);
 }
 
@@ -8025,11 +8032,6 @@ GlobOpt::IsSafeToTransferInPrePass(IR::Opnd *src, Value *srcValue)
         return false;
     }
 
-    if (this->IsDefinedInCurrentLoopIteration(this->prePassLoop, srcValue))
-    {
-        return true;
-    }
-
     if (src->IsRegOpnd())
     {
         StackSym *srcSym = src->AsRegOpnd()->m_sym;
@@ -18605,7 +18607,14 @@ GlobOpt::OptHoistInvariant(
                 {
                     instr->GetSrc1()->SetValueType(landingPadSrc1val->GetValueInfo()->Type());
                     EnsureBailTarget(loop);
-                    instr = instr->ConvertToBailOutInstr(instr, bailoutKind);
+                    if (block->IsLandingPad())
+                    {
+                        instr = instr->ConvertToBailOutInstr(instr, bailoutKind, loop->bailOutInfo->bailOutOffset);
+                    }
+                    else
+                    {
+                        instr = instr->ConvertToBailOutInstr(instr, bailoutKind);
+                    }
                 };
 
                 // A definite type in the source position and not a definite type in the destination (landing pad)
@@ -20130,12 +20139,6 @@ ValueInfo::GetIntValMinMax(int *pMin, int *pMax, bool doAggressiveIntTypeSpec)
     return false;
 }
 
-bool
-GlobOpt::IsDefinedInCurrentLoopIteration(Loop *loop, Value *val) const
-{
-     return false;
-}
-
 bool
 GlobOpt::IsPREInstrCandidateLoad(Js::OpCode opcode)
 {
@@ -21379,7 +21382,7 @@ GlobOpt::ProcessMemOp()
 {
     FOREACH_LOOP_IN_FUNC_EDITING(loop, this->func)
     {
-        if (DoMemOp(loop))
+        if (HasMemOp(loop))
         {
             const int candidateCount = loop->memOpInfo->candidates->Count();
             Assert(candidateCount > 0);
@@ -21390,7 +21393,7 @@ GlobOpt::ProcessMemOp()
             if (!loopCount || !(loopCount->LoopCountMinusOneSym() || loopCount->LoopCountMinusOneConstantValue()))
             {
                 TRACE_MEMOP(loop, nullptr, _u("MemOp skipped for no loop count"));
-                loop->memOpInfo->doMemOp = false;
+                loop->doMemOp = false;
                 loop->memOpInfo->candidates->Clear();
                 continue;
             }
@@ -21419,7 +21422,7 @@ GlobOpt::ProcessMemOp()
                 }
 
                 // One of the memop candidates did not validate. Do not emit for this loop.
-                loop->memOpInfo->doMemOp = false;
+                loop->doMemOp = false;
                 loop->memOpInfo->candidates->Clear();
             }
 

+ 1 - 2
lib/Backend/GlobOpt.h

@@ -1452,7 +1452,7 @@ private:
     IR::Instr*              FindArraySegmentLoadInstr(IR::Instr* instr);
     void                    RemoveMemOpSrcInstr(IR::Instr* memopInstr, IR::Instr* srcInstr, BasicBlock* block);
     void                    GetMemOpSrcInfo(Loop* loop, IR::Instr* instr, IR::RegOpnd*& base, IR::RegOpnd*& index, IRType& arrayType);
-    bool                    DoMemOp(Loop * loop);
+    bool                    HasMemOp(Loop * loop);
 
 private:
     void                    ChangeValueType(BasicBlock *const block, Value *const value, const ValueType newValueType, const bool preserveSubclassInfo, const bool allowIncompatibleType = false) const;
@@ -1802,7 +1802,6 @@ private:
     IR::Instr *             TrackMarkTempObject(IR::Instr * instrStart, IR::Instr * instrEnd);
     void                    TrackTempObjectSyms(IR::Instr * instr, IR::RegOpnd * opnd);
     IR::Instr *             GenerateBailOutMarkTempObjectIfNeeded(IR::Instr * instr, IR::Opnd * opnd, bool isDst);
-    bool                    IsDefinedInCurrentLoopIteration(Loop *loop, Value *val) const;
 
     void                    KillStateForGeneratorYield();
 

+ 2 - 2
lib/Backend/GlobOptFields.cpp

@@ -262,17 +262,17 @@ GlobOpt::DoFieldPRE(Loop *loop) const
     return DoFieldOpts(loop);
 }
 
-bool GlobOpt::DoMemOp(Loop *loop)
+bool GlobOpt::HasMemOp(Loop *loop)
 {
 #pragma prefast(suppress: 6285, "logical-or of constants is by design")
     return (
         loop &&
+        loop->doMemOp &&
         (
             !PHASE_OFF(Js::MemSetPhase, this->func) ||
             !PHASE_OFF(Js::MemCopyPhase, this->func)
         ) &&
         loop->memOpInfo &&
-        loop->memOpInfo->doMemOp &&
         loop->memOpInfo->candidates &&
         !loop->memOpInfo->candidates->Empty()
     );

+ 2 - 2
lib/Backend/IR.cpp

@@ -2942,10 +2942,10 @@ Instr::TransferTo(Instr * instr)
 }
 
 IR::Instr *
-Instr::ConvertToBailOutInstr(IR::Instr * bailOutTarget, IR::BailOutKind kind)
+Instr::ConvertToBailOutInstr(IR::Instr * bailOutTarget, IR::BailOutKind kind, uint32 bailOutOffset)
 {
     Func * func = bailOutTarget->m_func;
-    BailOutInfo * bailOutInfo = JitAnew(func->m_alloc, BailOutInfo, bailOutTarget->GetByteCodeOffset(), func);
+    BailOutInfo * bailOutInfo = JitAnew(func->m_alloc, BailOutInfo, bailOutOffset == Js::Constants::NoByteCodeOffset ? bailOutTarget->GetByteCodeOffset() : bailOutOffset , func);
 #if ENABLE_DEBUG_CONFIG_OPTIONS
     bailOutInfo->bailOutOpcode = this->m_opcode;
 #endif

+ 1 - 1
lib/Backend/IR.h

@@ -250,7 +250,7 @@ public:
     void            TransferDstAttributesTo(Instr * instr);
     IR::Instr *     Copy();
     IR::Instr *     Clone();
-    IR::Instr *     ConvertToBailOutInstr(IR::Instr * bailOutTarget, BailOutKind kind);
+    IR::Instr *     ConvertToBailOutInstr(IR::Instr * bailOutTarget, BailOutKind kind, uint32 bailOutOffset = Js::Constants::NoByteCodeOffset);
     IR::Instr *     ConvertToBailOutInstr(BailOutInfo * bailOutInfo, BailOutKind kind, bool useAuxBailout = false);
     IR::Instr *     GetNextRealInstr() const;
     IR::Instr *     GetNextRealInstrOrLabel() const;

+ 7 - 1
lib/Backend/Lower.cpp

@@ -2401,12 +2401,18 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
             break;
 
         case Js::OpCode::IncrLoopBodyCount:
+        {
             Assert(this->m_func->IsLoopBody());
             instr->m_opcode = Js::OpCode::Add_I4;
             instr->SetSrc2(IR::IntConstOpnd::New(1, TyUint32, this->m_func));
             this->m_lowererMD.EmitInt4Instr(instr);
-            break;
 
+            // Update the jittedLoopIterations field on the entryPointInfo
+            IR::MemRefOpnd *iterationsAddressOpnd = IR::MemRefOpnd::New(this->m_func->GetJittedLoopIterationsSinceLastBailoutAddress(), TyUint32, this->m_func);
+            m_lowererMD.CreateAssign(iterationsAddressOpnd, instr->GetDst(), instr);
+
+            break;
+        }
 #if !FLOATVAR
         case Js::OpCode::StSlotBoxTemp:
             this->LowerStSlotBoxTemp(instr);

+ 0 - 126
lib/Backend/LowerMDSharedSimd128.cpp

@@ -348,10 +348,6 @@ IR::Instr* LowererMD::Simd128LowerUnMappedInstruction(IR::Instr *instr)
     case Js::OpCode::Simd128_Max_F4:
         return Simd128LowerMinMax_F4(instr);
 
-    case Js::OpCode::Simd128_MinNum_F4:
-    case Js::OpCode::Simd128_MaxNum_F4:
-        return Simd128LowerMinMaxNum(instr);
-
     case Js::OpCode::Simd128_AnyTrue_B4:
     case Js::OpCode::Simd128_AnyTrue_B8:
     case Js::OpCode::Simd128_AnyTrue_B16:
@@ -2243,128 +2239,6 @@ IR::Instr* LowererMD::Simd128LowerMinMax_F4(IR::Instr* instr)
 
 }
 
-
-IR::Instr* LowererMD::Simd128LowerMinMaxNum(IR::Instr* instr)
-{
-    IR::Instr *pInstr;
-    IR::Opnd* dst = instr->GetDst();
-    IR::Opnd* src1 = instr->GetSrc1();
-    IR::Opnd* src2 = instr->GetSrc2();
-    Assert(dst->IsRegOpnd() && dst->IsSimd128());
-    Assert(src1->IsRegOpnd() && src1->IsSimd128());
-    Assert(src2->IsRegOpnd() && src2->IsSimd128());
-    IR::RegOpnd* tmp1 = IR::RegOpnd::New(src1->GetType(), m_func);
-    IR::RegOpnd* tmp2 = IR::RegOpnd::New(src1->GetType(), m_func);
-    IR::RegOpnd* mask = IR::RegOpnd::New(src1->GetType(), m_func);
-    IR::RegOpnd* mask2 = IR::RegOpnd::New(src1->GetType(), m_func);
-
-    if (instr->m_opcode == Js::OpCode::Simd128_MinNum_F4)
-    {
-        // dst = MINPS src1, src2
-        // This is the correct result or b if either is NaN or both are +/-0.0
-        pInstr = IR::Instr::New(Js::OpCode::MINPS, dst, src1, src2, m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-
-        // mask = CMPUNORD src2, src2
-        // Find NaNs in b
-        pInstr = IR::Instr::New(Js::OpCode::CMPUNORDPS, mask, src2, src2, m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-
-        // mask2 = PCMPEQD src1, [X86_TWO_31_I4]
-        // Find -0.0 in a
-        pInstr = IR::Instr::New(Js::OpCode::PCMPEQD, mask2, src1, IR::MemRefOpnd::New((void*)&X86_TWO_31_I4, TySimd128I4, m_func), m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-
-        // mask2 = ANDPS mask2, [X86_TWO_31_I4]
-        // mask2 is -0.0 where a is -0.0
-        pInstr = IR::Instr::New(Js::OpCode::ANDPS, mask2, mask2, IR::MemRefOpnd::New((void*)&X86_TWO_31_I4, TySimd128I4, m_func), m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-
-        // dst = ORPS dst, mask2
-        // For lanes where a is -0.0, the result is either correct (negative), or b which is possibly +0.0
-        // Safe to force sign to negative for those lanes, +0.0 becomes -0.0.
-        pInstr = IR::Instr::New(Js::OpCode::ORPS, dst, dst, mask2, m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-
-        // tmp1 = ANDPS src1, mask
-        // tmp2 = ANDNPS mask, dst
-        // dst = ORPS tmp1, tmp2
-        // For NaNs in b, choose a, else keep result.
-        pInstr = IR::Instr::New(Js::OpCode::ANDPS, tmp1, src1, mask, m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-
-        pInstr = IR::Instr::New(Js::OpCode::ANDNPS, tmp2, mask, dst, m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-
-        pInstr = IR::Instr::New(Js::OpCode::ORPS, dst, tmp1, tmp2, m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-    }
-    else if (instr->m_opcode == Js::OpCode::Simd128_MaxNum_F4)
-    {
-        // dst = MAXPS src1, src2
-        // This is the correct result or b if either is NaN or both are +/-0.0
-        pInstr = IR::Instr::New(Js::OpCode::MAXPS, dst, src1, src2, m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-
-        // Find NaNs in b
-        // mask = CMPUNORPS src2, src2
-        pInstr = IR::Instr::New(Js::OpCode::CMPUNORDPS, mask, src2, src2, m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-
-        // mask2 = PCMPEQD src1, [X86_ALL_ZEROS]
-        // Find +0.0 in a
-        pInstr = IR::Instr::New(Js::OpCode::PCMPEQD, mask2, src1, IR::MemRefOpnd::New((void*)&X86_ALL_ZEROS, TySimd128I4, m_func), m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-
-        // mask2 = ANDPS mask2, [X86_TWO_31_I4]
-        // mask2 is -0.0 (sign mask) where a is +0.0
-        pInstr = IR::Instr::New(Js::OpCode::ANDPS, mask2, mask2, IR::MemRefOpnd::New((void*)&X86_TWO_31_I4, TySimd128I4, m_func), m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-
-        // dst = ANDNPS mask2, dst
-        // For lanes where a is +0.0, the result is either correct (positive), or b which is possibly -0.0
-        // Safe to force sign to positive for those lanes, +0.0 becomes -0.0.
-        pInstr = IR::Instr::New(Js::OpCode::ANDNPS, dst, mask2, dst, m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-
-        // tmp1 = ANDPS src1, mask
-        // tmp2 = ANDNPS mask, dst
-        // dst = ORPS tmp1, tmp2
-        // For NaNs in b, choose a, else keep result.
-        pInstr = IR::Instr::New(Js::OpCode::ANDPS, tmp1, src1, mask, m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-
-        pInstr = IR::Instr::New(Js::OpCode::ANDNPS, tmp2, mask, dst, m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-
-        pInstr = IR::Instr::New(Js::OpCode::ORPS, dst, tmp1, tmp2, m_func);
-        instr->InsertBefore(pInstr);
-        Legalize(pInstr);
-    }
-    else
-    {
-        Assert(UNREACHED);
-    }
-    pInstr = instr->m_prev;
-    instr->Remove();
-    return pInstr;
-}
-
 IR::Instr* LowererMD::Simd128LowerAnyTrue(IR::Instr* instr)
 {
     Assert(instr->m_opcode == Js::OpCode::Simd128_AnyTrue_B4 || instr->m_opcode == Js::OpCode::Simd128_AnyTrue_B8 ||

+ 27 - 5
lib/Backend/NativeCodeGenerator.cpp

@@ -123,6 +123,14 @@ NativeCodeGenerator::~NativeCodeGenerator()
         {
             Js::ScriptContextProfiler *codegenProfiler = this->backgroundCodeGenProfiler;
             this->backgroundCodeGenProfiler = this->backgroundCodeGenProfiler->next;
+            // background codegen profiler is allocated in background thread,
+            // clear the thead Id before release
+#ifdef DBG
+            if (codegenProfiler->pageAllocator != nullptr)
+            {
+                codegenProfiler->pageAllocator->SetDisableThreadAccessCheck();
+            }
+#endif
             codegenProfiler->Release();
         }
     }
@@ -2816,13 +2824,27 @@ NativeCodeGenerator::ProfilePrint()
     else
     {
         //Merge all the codegenProfiler for single snapshot.
-        codegenProfiler = codegenProfiler->next;
-        while (codegenProfiler)
+        Js::ScriptContextProfiler* mergeToProfiler = codegenProfiler;
+
+        // find the first initialized profiler
+        while (mergeToProfiler != nullptr && !mergeToProfiler->IsInitialized())
         {
-            this->backgroundCodeGenProfiler->ProfileMerge(codegenProfiler);
-            codegenProfiler = codegenProfiler->next;
+            mergeToProfiler = mergeToProfiler->next;
+        }
+        if (mergeToProfiler != nullptr)
+        {
+            // merge the rest profiler to the above initialized profiler
+            codegenProfiler = mergeToProfiler->next;
+            while (codegenProfiler)
+            {
+                if (codegenProfiler->IsInitialized())
+                {
+                    mergeToProfiler->ProfileMerge(codegenProfiler);
+                }
+                codegenProfiler = codegenProfiler->next;
+            }
+            mergeToProfiler->ProfilePrint(Js::Configuration::Global.flags.Profile.GetFirstPhase());
         }
-        this->backgroundCodeGenProfiler->ProfilePrint(Js::Configuration::Global.flags.Profile.GetFirstPhase());
     }
 }
 

+ 5 - 0
lib/Common/Common/NumberUtilities.cpp

@@ -9,6 +9,10 @@
 
 namespace Js
 {
+    // The VS2013 linker treats this as a redefinition of an already
+    // defined constant and complains. So skip the declaration if we're compiling
+    // with VS2013 or below.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
     // Redeclare static constants
     const UINT64 NumberConstantsBase::k_Nan;
     const INT64 NumberUtilitiesBase::Pos_InvalidInt64;
@@ -31,6 +35,7 @@ namespace Js
     const uint32 NumberConstants::k_Float32NegZero;
     const uint32 NumberConstants::k_Float32TwoToFraction;
     const uint32 NumberConstants::k_Float32NegTwoToFraction;
+#endif
 
     const double NumberConstants::MAX_VALUE = *(double*)(&NumberConstants::k_PosMax);
     const double NumberConstants::MIN_VALUE = *(double*)(&NumberConstants::k_PosMin);

+ 10 - 6
lib/Common/ConfigFlagsList.h

@@ -566,10 +566,11 @@ PHASE(All)
 #define DEFAULT_CONFIG_SkipFuncCountForBailOnNoProfile (0) //Initial Number of functions in a func body to be skipped from forcibly inserting BailOnNoProfile.
 #endif
 #define DEFAULT_CONFIG_BailOnNoProfileLimit    200      // The limit of bailout on no profile info before triggering a rejit
-#define DEFAULT_CONFIG_BailOnNoProfileRejitLimit (-1)   // The limit of bailout on no profile info before disable all the no profile bailouts
-#define DEFAULT_CONFIG_CallsToBailoutsRatioForRejit 5   // Ratio of function calls to bailouts on a single bailout record
-                                                        // above which a rejit is considered
+#define DEFAULT_CONFIG_BailOnNoProfileRejitLimit (50)   // The limit of bailout on no profile info before disable all the no profile bailouts
+#define DEFAULT_CONFIG_CallsToBailoutsRatioForRejit 10   // Ratio of function calls to bailouts above which a rejit is considered
+#define DEFAULT_CONFIG_LoopIterationsToBailoutsRatioForRejit 50 // Ratio of loop iteration count to bailouts above which a rejit of the loop body is considered
 #define DEFAULT_CONFIG_MinBailOutsBeforeRejit 2         // Minimum number of bailouts for a single bailout record after which a rejit is considered
+#define DEFAULT_CONFIG_MinBailOutsBeforeRejitForLoops 2         // Minimum number of bailouts for a single bailout record after which a rejit is considered
 #define DEFAULT_CONFIG_RejitMaxBailOutCount 500         // Maximum number of bailouts for a single bailout record after which rejit is forced.
 
 
@@ -603,6 +604,7 @@ PHASE(All)
 #define DEFAULT_CONFIG_FuncObjectInlineCacheThreshold   (2) // Maximum number of inline caches a function body may have to allow for inline caches to be allocated on the function object.
 #define DEFAULT_CONFIG_ShareInlineCaches (true)
 #define DEFAULT_CONFIG_InlineCacheInvalidationListCompactionThreshold (4)
+#define DEFAULT_CONFIG_ConstructorCacheInvalidationThreshold (500)
 
 #define DEFAULT_CONFIG_InMemoryTrace                (false)
 #define DEFAULT_CONFIG_InMemoryTraceBufferSize      (1024)
@@ -899,7 +901,7 @@ FLAGPR           (Boolean, ES6, ES6Unscopables         , "Enable ES6 With Statem
 FLAGPR           (Boolean, ES6, ES6RegExSticky         , "Enable ES6 RegEx sticky flag"                             , DEFAULT_CONFIG_ES6RegExSticky)
 FLAGPR_REGOVR_EXP(Boolean, ES6, ES6RegExPrototypeProperties, "Enable ES6 properties on the RegEx prototype"         , DEFAULT_CONFIG_ES6RegExPrototypeProperties)
 FLAGPR_REGOVR_EXP(Boolean, ES6, ES6RegExSymbols        , "Enable ES6 RegExp symbols"                                , DEFAULT_CONFIG_ES6RegExSymbols)
-FLAGPR           (Boolean, ES6, ES6HasInstance         , "Enable ES6 @@hasInstance symbol"                          , DEFAULT_CONFIG_ES6HasInstanceOf)
+FLAGPR_REGOVR_EXP(Boolean, ES6, ES6HasInstance         , "Enable ES6 @@hasInstance symbol"                          , DEFAULT_CONFIG_ES6HasInstanceOf)
 FLAGPR           (Boolean, ES6, ES6Verbose             , "Enable ES6 verbose trace"                                 , DEFAULT_CONFIG_ES6Verbose)
 FLAGPR_REGOVR_EXP(Boolean, ES6, ArrayBufferTransfer    , "Enable ArrayBuffer.transfer"                              , DEFAULT_CONFIG_ArrayBufferTransfer)
 // /ES6 (BLUE+1) features/flags
@@ -1132,9 +1134,10 @@ FLAGNR(Boolean, ProfileBailOutRecordMemory, "Profile bailout record memory stati
 #endif
 
 FLAGNR(Number,  RejitMaxBailOutCount, "Maximum number of bailouts for a bailout record after which rejit is forced", DEFAULT_CONFIG_RejitMaxBailOutCount)
-FLAGNR(Number,  CallsToBailoutsRatioForRejit, "Ratio of function calls to bailouts on a single bailout record above which a rejit is considered", DEFAULT_CONFIG_CallsToBailoutsRatioForRejit)
+FLAGNR(Number,  CallsToBailoutsRatioForRejit, "Ratio of function calls to bailouts above which a rejit is considered", DEFAULT_CONFIG_CallsToBailoutsRatioForRejit)
+FLAGNR(Number,  LoopIterationsToBailoutsRatioForRejit, "Ratio of loop iteration count to bailouts above which a rejit of the loop body is considered", DEFAULT_CONFIG_LoopIterationsToBailoutsRatioForRejit)
 FLAGNR(Number,  MinBailOutsBeforeRejit, "Minimum number of bailouts for a single bailout record after which a rejit is considered", DEFAULT_CONFIG_MinBailOutsBeforeRejit)
-
+FLAGNR(Number,  MinBailOutsBeforeRejitForLoops, "Minimum number of bailouts for a single bailout record after which a rejit is considered", DEFAULT_CONFIG_MinBailOutsBeforeRejitForLoops)
 FLAGNR(Boolean, LibraryStackFrame           , "Display library stack frame", DEFAULT_CONFIG_LibraryStackFrame)
 FLAGNR(Boolean, LibraryStackFrameDebugger   , "Assume debugger support for library stack frame", DEFAULT_CONFIG_LibraryStackFrameDebugger)
 #ifdef RECYCLER_STRESS
@@ -1317,6 +1320,7 @@ FLAGNR(Number, PRNGSeed1, "Override seed1 for Math.Random()", 0)
 
 FLAGNR(Boolean, ClearInlineCachesOnCollect, "Clear all inline caches on every garbage collection", false)
 FLAGNR(Number, InlineCacheInvalidationListCompactionThreshold, "Compact inline cache invalidation lists if their utilization falls below this threshold", DEFAULT_CONFIG_InlineCacheInvalidationListCompactionThreshold)
+FLAGNR(Number, ConstructorCacheInvalidationThreshold, "Clear uniquePropertyGuard entries from recyclableData if number of invalidations of constructor caches happened are more than the threshold.", DEFAULT_CONFIG_ConstructorCacheInvalidationThreshold)
 
 #ifdef IR_VIEWER
 FLAGNR(Boolean, IRViewer, "Enable IRViewer functionality (improved UI for various stages of IR generation)", false)

+ 0 - 1
lib/Common/Core/ProfileInstrument.cpp

@@ -81,7 +81,6 @@ namespace Js
         }
     }
 
-
     ///----------------------------------------------------------------------------
     ///
     /// Profiler::Begin

+ 1 - 2
lib/Common/Core/ProfileInstrument.h

@@ -118,10 +118,9 @@ namespace Js
 
                 ArenaAllocator  *alloc;
 
-
     // Constructor
     public:
-                Profiler(ArenaAllocator *alloc);
+                Profiler(ArenaAllocator* alloc);
 
     // Implementation
     private:

+ 5 - 0
lib/Common/Memory/ArenaAllocator.cpp

@@ -6,7 +6,12 @@
 
 #define ASSERT_THREAD() AssertMsg(this->pageAllocator->ValidThreadAccess(), "Arena allocation should only be used by a single thread")
 
+// The VS2013 linker treats this as a redefinition of an already
+// defined constant and complains. So skip the declaration if we're compiling
+// with VS2013 or below.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const uint Memory::StandAloneFreeListPolicy::MaxEntriesGrowth;
+#endif
 
 // We need this function to be inlined for perf
 template _ALWAYSINLINE BVSparseNode * BVSparse<JitArenaAllocator>::NodeFromIndex(BVIndex i, BVSparseNode *** prevNextFieldOut, bool create);

+ 6 - 5
lib/Common/Memory/HeapAllocator.cpp

@@ -358,11 +358,6 @@ HeapAllocator::HeapAllocator(bool useAllocMemProtect)
 
 HeapAllocator::~HeapAllocator()
 {
-    if (CONFIG_FLAG(PrivateHeap))
-    {
-        this->DestroyPrivateHeap();
-    }
-
 #ifdef HEAP_TRACK_ALLOC
     bool hasFakeHeapLeak = false;
     auto fakeHeapLeak = [&]()
@@ -422,6 +417,12 @@ HeapAllocator::~HeapAllocator()
 #endif // CHECK_MEMORY_LEAK
 #endif // HEAP_TRACK_ALLOC
 
+    // destroy private heap after leak check
+    if (CONFIG_FLAG(PrivateHeap))
+    {
+        this->DestroyPrivateHeap();
+    }
+
 #ifdef INTERNAL_MEM_PROTECT_HEAP_ALLOC
     if (memProtectHeapHandle != nullptr)
     {

+ 5 - 0
lib/Common/Memory/HeapBlockMap.cpp

@@ -4,8 +4,13 @@
 //-------------------------------------------------------------------------------------------------------
 #include "CommonMemoryPch.h"
 
+// The VS2013 linker treats this as a redefinition of an already
+// defined constant and complains. So skip the declaration if we're compiling
+// with VS2013 or below.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const uint Memory::HeapBlockMap32::L1Count;
 const uint Memory::HeapBlockMap32::L2Count;
+#endif
 
 #if defined(_M_X64_OR_ARM64)
 HeapBlockMap32::HeapBlockMap32(__in char * startAddress) :

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

@@ -14,8 +14,13 @@
 
 template _ALWAYSINLINE char* HeapInfo::RealAlloc<NoBit, false>(Recycler * recycler, size_t sizeCat, size_t size);
 
+// The VS2013 linker treats this as a redefinition of an already
+// defined constant and complains. So skip the declaration if we're compiling
+// with VS2013 or below.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const uint SmallAllocationBlockAttributes::MaxSmallObjectCount;
 const uint MediumAllocationBlockAttributes::MaxSmallObjectCount;
+#endif
 
 HeapInfo::ValidPointersMap<SmallAllocationBlockAttributes>  HeapInfo::smallAllocValidPointersMap;
 HeapInfo::ValidPointersMap<MediumAllocationBlockAttributes> HeapInfo::mediumAllocValidPointersMap;
@@ -884,6 +889,8 @@ HeapInfo::AddLargeHeapBlock(size_t size)
 void HeapInfo::SweepBuckets(RecyclerSweep& recyclerSweep, bool concurrent)
 {
     Recycler * recycler = recyclerSweep.GetRecycler();
+    // TODO: Remove below workaround for unreferenced local after enabled -profile for GC
+    static_cast<Recycler*>(recycler);
     for (uint i = 0; i < HeapConstants::BucketCount; i++)
     {
         heapBuckets[i].SweepFinalizableObjects(recyclerSweep);

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

@@ -5266,6 +5266,8 @@ Recycler::FinishConcurrentCollect(CollectionFlags flags)
 
 #ifdef PROFILE_EXEC
     Js::Phase concurrentPhase = Js::ConcurrentCollectPhase;
+    // TODO: Remove this workaround for unreferenced local after enabled -profile for GC
+    static_cast<Js::Phase>(concurrentPhase);
 #endif
 #if ENABLE_PARTIAL_GC
     RECYCLER_PROFILE_EXEC_BEGIN2(this, Js::RecyclerPhase,

+ 8 - 2
lib/Common/Memory/Recycler.h

@@ -749,7 +749,6 @@ private:
     };
     DListBase<GuestArenaAllocator> guestArenaList;
     DListBase<ArenaData*> externalGuestArenaList;    // guest arenas are scanned for roots
-    HeapInfo autoHeap;
 #ifdef RECYCLER_PAGE_HEAP
 
     inline bool IsPageHeapEnabled() const { return isPageHeapEnabled; }
@@ -993,6 +992,10 @@ private:
     PageAllocator backgroundProfilerPageAllocator;
     DListBase<ArenaAllocator> backgroundProfilerArena;
 #endif
+
+    // destruct autoHeap after backgroundProfilerPageAllocator;
+    HeapInfo autoHeap;
+
 #ifdef PROFILE_MEM
     RecyclerMemoryData * memoryData;
 #endif
@@ -2396,7 +2399,10 @@ struct ForceLeafAllocator<RecyclerNonLeafAllocator>
     typedef RecyclerLeafAllocator AllocatorType;
 };
 
-#ifdef PROFILE_EXEC
+// TODO: enable -profile for GC phases.
+// access the same profiler object from multiple GC threads which shares one recyler object,
+// but profiler object is not thread safe
+#if defined(PROFILE_EXEC) && 0
 #define RECYCLER_PROFILE_EXEC_BEGIN(recycler, phase) if (recycler->profiler != nullptr) { recycler->profiler->Begin(phase); }
 #define RECYCLER_PROFILE_EXEC_END(recycler, phase) if (recycler->profiler != nullptr) { recycler->profiler->End(phase); }
 

+ 23 - 2
lib/Jsrt/ChakraDebug.h

@@ -394,6 +394,14 @@
     /// <param name="properties">Object of properties array (properties, scopes and globals).</param>
     /// <remarks>
     ///     <para>
+    ///     propertyAttributes is a bit mask of
+    ///         NONE = 0x1,
+    ///         HAVE_CHILDRENS = 0x2,
+    ///         READ_ONLY_VALUE = 0x4,
+    ///     </para>
+    /// </remarks>
+    /// <remarks>
+    ///     <para>
     ///     {
     ///         "thisObject": {
     ///             "name": "this",
@@ -539,18 +547,31 @@
     /// <param name="evalResult">Result of evaluation.</param>
     /// <remarks>
     ///     <para>
+    ///     evalResult when evaluating 'this' and return is JsNoError
     ///     {
     ///         "name" : "this",
     ///         "type" : "object",
-    ///         "display" : "{...}",
     ///         "className" : "Object",
+    ///         "display" : "{...}",
+    ///         "propertyAttributes" : 1,
+    ///         "handle" : 18
+    ///     }
+    ///
+    ///     evalResult when evaluating a script which throws JavaScript error and return is JsErrorScriptException
+    ///     {
+    ///         "name" : "a.b.c",
+    ///         "type" : "object",
+    ///         "className" : "Error",
+    ///         "display" : "'a' is undefined",
     ///         "propertyAttributes" : 1,
     ///         "handle" : 18
     ///     }
     ///     </para>
     /// </remarks>
     /// <returns>
-    ///     The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.
+    ///     The code <c>JsNoError</c> if the operation succeeded, evalResult will contain the result
+    ///     The code <c>JsErrorScriptException</c> if evaluate generated a JavaScript exception, evalResult will contain the error details
+    ///     Other error code for invalid parameters or API was not called at break
     /// </returns>
     /// <remarks>
     ///     The current runtime should be in debug state. This API can only be called when runtime is at a break.

+ 20 - 12
lib/Jsrt/JsrtDebugManager.cpp

@@ -201,7 +201,7 @@ void JsrtDebugManager::ReportScriptCompile(Js::JavascriptFunction* scriptFunctio
             jsDiagDebugEvent = JsDiagDebugEventSourceCompile;
         }
 
-        this->CallDebugEventCallback(jsDiagDebugEvent, eventDataObject, scriptContext);
+        this->CallDebugEventCallback(jsDiagDebugEvent, eventDataObject, scriptContext, false /*isBreak*/);
     }
 }
 
@@ -327,15 +327,16 @@ bool JsrtDebugManager::EnableAsyncBreak(Js::ScriptContext* scriptContext)
     return false;
 }
 
-void JsrtDebugManager::CallDebugEventCallback(JsDiagDebugEvent debugEvent, Js::DynamicObject* eventDataObject, Js::ScriptContext* scriptContext)
+void JsrtDebugManager::CallDebugEventCallback(JsDiagDebugEvent debugEvent, Js::DynamicObject* eventDataObject, Js::ScriptContext* scriptContext, bool isBreak)
 {
     class AutoClear
     {
     public:
-        AutoClear(JsrtDebugManager* jsrtDebug)
+        AutoClear(JsrtDebugManager* jsrtDebug, void* dispatchHaltFrameAddress)
         {
             this->jsrtDebugManager = jsrtDebug;
             jsrtDebugManager->callBackDepth++;
+            this->jsrtDebugManager->GetThreadContext()->GetDebugManager()->SetDispatchHaltFrameAddress(dispatchHaltFrameAddress);
         }
 
         ~AutoClear()
@@ -355,7 +356,7 @@ void JsrtDebugManager::CallDebugEventCallback(JsDiagDebugEvent debugEvent, Js::D
                     jsrtDebugManager->stackFrames = nullptr;
                 }
             }
-
+            this->jsrtDebugManager->GetThreadContext()->GetDebugManager()->SetDispatchHaltFrameAddress(nullptr);
             this->jsrtDebugManager = nullptr;
         }
     private:
@@ -364,8 +365,20 @@ void JsrtDebugManager::CallDebugEventCallback(JsDiagDebugEvent debugEvent, Js::D
 
     auto funcPtr = [&]()
     {
-        AutoClear autoClear(this);
-        this->debugEventCallback(debugEvent, eventDataObject, this->callbackState);
+        if (isBreak)
+        {
+            void *frameAddress = _AddressOfReturnAddress();
+            // If we are reporting break we should clear all objects after call returns
+
+            // Save the frame address, when asking for stack we will only give stack which is under this address
+            // because host can execute javascript after break which should not be part of stack.
+            AutoClear autoClear(this, frameAddress);
+            this->debugEventCallback(debugEvent, eventDataObject, this->callbackState);
+        }
+        else
+        {
+            this->debugEventCallback(debugEvent, eventDataObject, this->callbackState);
+        }
     };
 
     if (scriptContext->GetThreadContext()->IsScriptActive())
@@ -386,12 +399,7 @@ void JsrtDebugManager::CallDebugEventCallbackForBreak(JsDiagDebugEvent debugEven
 {
     AutoSetDispatchHaltFlag autoSetDispatchHaltFlag(scriptContext, scriptContext->GetThreadContext());
 
-#if DBG
-    void *frameAddress = _AddressOfReturnAddress();
-    scriptContext->GetThreadContext()->GetDebugManager()->SetDispatchHaltFrameAddress(frameAddress);
-#endif
-
-    this->CallDebugEventCallback(debugEvent, eventDataObject, scriptContext);
+    this->CallDebugEventCallback(debugEvent, eventDataObject, scriptContext, true /*isBreak*/);
 
     for (Js::ScriptContext *tempScriptContext = scriptContext->GetThreadContext()->GetScriptContextList();
     tempScriptContext != nullptr && !tempScriptContext->IsClosed();

+ 2 - 2
lib/Jsrt/JsrtDebugManager.h

@@ -27,7 +27,7 @@ public:
 
     bool EnableAsyncBreak(Js::ScriptContext* scriptContext);
 
-    void CallDebugEventCallback(JsDiagDebugEvent debugEvent, Js::DynamicObject* eventDataObject, Js::ScriptContext* scriptContext);
+    void CallDebugEventCallback(JsDiagDebugEvent debugEvent, Js::DynamicObject* eventDataObject, Js::ScriptContext* scriptContext, bool isBreak);
     void CallDebugEventCallbackForBreak(JsDiagDebugEvent debugEvent, Js::DynamicObject* eventDataObject, Js::ScriptContext* scriptContext);
 
     Js::JavascriptArray* GetScripts(Js::ScriptContext* scriptContext);
@@ -55,7 +55,7 @@ public:
     JsDiagBreakOnExceptionAttributes GetBreakOnException();
 
     JsDiagDebugEvent GetDebugEventFromStopType(Js::StopType stopType);
-
+    ThreadContext* GetThreadContext() const { return this->threadContext; }
 private:
     ThreadContext* threadContext;
     JsDiagDebugEventCallback debugEventCallback;

+ 1 - 3
lib/Jsrt/JsrtDebugUtils.cpp

@@ -27,9 +27,7 @@ void JsrtDebugUtils::AddFileNameOrScriptTypeToObject(Js::DynamicObject* object,
 
         Js::FunctionBody* anyFunctionBody = utf8SourceInfo->GetAnyParsedFunction();
 
-        Assert(anyFunctionBody != nullptr);
-
-        LPCWSTR sourceName = anyFunctionBody->GetSourceName();
+        LPCWSTR sourceName = (anyFunctionBody != nullptr) ? anyFunctionBody->GetSourceName() : Js::Constants::UnknownScriptCode;
 
         JsrtDebugUtils::AddPropertyToObject(object, JsrtDebugPropertyId::scriptType, sourceName, wcslen(sourceName), utf8SourceInfo->GetScriptContext());
     }

+ 3 - 3
lib/Jsrt/JsrtDebugUtils.h

@@ -11,9 +11,9 @@ BEGIN_ENUM_UINT(JsrtDebugPropertyId)
 END_ENUM_UINT()
 
 BEGIN_ENUM_UINT(JsrtDebugPropertyAttribute)
-    NONE,
-    HAVE_CHILDRENS,
-    READ_ONLY_VALUE,
+    NONE = 0x1,
+    HAVE_CHILDRENS = 0x2,
+    READ_ONLY_VALUE = 0x4,
 END_ENUM_UINT()
 
 class JsrtDebugUtils

+ 36 - 11
lib/Jsrt/JsrtDebuggerObject.cpp

@@ -452,14 +452,16 @@ Js::DynamicObject * JsrtDebuggerStackFrame::GetLocalsObject(Js::ScriptContext* s
     return propertiesObject;
 }
 
-Js::DynamicObject* JsrtDebuggerStackFrame::Evaluate(Js::ScriptContext* scriptContext, const char16 *source, int sourceLength, bool isLibraryCode)
+bool JsrtDebuggerStackFrame::Evaluate(Js::ScriptContext* scriptContext, const char16 *source, int sourceLength, bool isLibraryCode, Js::DynamicObject** evalResult)
 {
-    Js::DynamicObject* evalResult = nullptr;
+    *evalResult = nullptr;
+    bool success = false;
     if (this->stackFrame != nullptr)
     {
         Js::ResolvedObject resolvedObject;
         HRESULT hr = S_OK;
         Js::ScriptContext* frameScriptContext = this->stackFrame->GetScriptContext();
+
         Js::JavascriptExceptionObject *exceptionObject = nullptr;
         {
             BEGIN_JS_RUNTIME_CALL_EX_AND_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT_NESTED(frameScriptContext, false)
@@ -469,6 +471,7 @@ Js::DynamicObject* JsrtDebuggerStackFrame::Evaluate(Js::ScriptContext* scriptCon
             }
             END_JS_RUNTIME_CALL_AND_TRANSLATE_AND_GET_EXCEPTION_AND_ERROROBJECT_TO_HRESULT(hr, frameScriptContext, exceptionObject);
         }
+
         if (resolvedObject.obj == nullptr)
         {
             resolvedObject.name = _u("{exception}");
@@ -484,26 +487,36 @@ Js::DynamicObject* JsrtDebuggerStackFrame::Evaluate(Js::ScriptContext* scriptCon
                 resolvedObject.obj = scriptContext->GetLibrary()->GetUndefined();
             }
         }
+        else
+        {
+          success = true;
+        }
+
         if (resolvedObject.obj != nullptr)
         {
             resolvedObject.scriptContext = scriptContext;
 
             charcount_t len = Js::JavascriptString::GetBufferLength(source);
             resolvedObject.name = AnewNoThrowArray(this->debuggerObjectsManager->GetDebugObjectArena(), WCHAR, len + 1);
-            if (resolvedObject.name == nullptr)
+
+            if (resolvedObject.name != nullptr)
             {
-                return nullptr;
+                wcscpy_s((WCHAR*)resolvedObject.name, len + 1, source);
+            }
+            else
+            {
+                // len can be big, if we failed just have empty string
+                resolvedObject.name = _u("");
             }
-            wcscpy_s((WCHAR*)resolvedObject.name, len + 1, source);
 
             resolvedObject.typeId = Js::JavascriptOperators::GetTypeId(resolvedObject.obj);
             JsrtDebuggerObjectBase::CreateDebuggerObject<JsrtDebuggerObjectProperty>(this->debuggerObjectsManager, resolvedObject, scriptContext, [&](Js::Var marshaledObj)
             {
-                evalResult = (Js::DynamicObject*)marshaledObj;
+                *evalResult = (Js::DynamicObject*)marshaledObj;
             });
         }
     }
-    return evalResult;
+    return success;
 }
 
 JsrtDebuggerObjectProperty::JsrtDebuggerObjectProperty(JsrtDebuggerObjectsManager* debuggerObjectsManager, WeakArenaReference<Js::IDiagObjectModelDisplay>* objectDisplay) :
@@ -797,7 +810,12 @@ Js::JavascriptArray * JsrtDebugStackFrames::StackFrames(Js::ScriptContext * scri
 
     uint frameCount = 0;
 
-    for (Js::ScriptContext *tempScriptContext = scriptContext->GetThreadContext()->GetScriptContextList();
+    ThreadContext* threadContext = scriptContext->GetThreadContext();
+
+    DWORD_PTR dispatchHaltFrameAddress = threadContext->GetDebugManager()->GetDispatchHaltFrameAddress();
+    AssertMsg(dispatchHaltFrameAddress, "Didn't set the dispatchHaltFrameAddress at time of break?");
+
+    for (Js::ScriptContext *tempScriptContext = threadContext->GetScriptContextList();
     tempScriptContext != nullptr && tempScriptContext->IsScriptContextInDebugMode();
         tempScriptContext = tempScriptContext->next)
     {
@@ -811,12 +829,19 @@ Js::JavascriptArray * JsrtDebugStackFrames::StackFrames(Js::ScriptContext * scri
                 for (int frameIndex = 0; frameIndex < count; ++frameIndex)
                 {
                     Js::DiagStackFrame* stackFrame = stackFrames->Peek(frameIndex);
-                    Js::DynamicObject* stackTraceObject = this->GetStackFrame(stackFrame, frameCount);
 
-                    Js::Var marshaledObj = Js::CrossSite::MarshalVar(scriptContext, stackTraceObject);
-                    Js::JavascriptOperators::OP_SetElementI((Js::Var)stackTraceArray, Js::JavascriptNumber::ToVar(frameCount++, scriptContext), marshaledObj, scriptContext);
+                    DWORD_PTR stackAddress = stackFrame->GetStackAddress();
+                    // Only give frames which were preset when break was triggered as we might have other user (non-library) scripts executed after break
+                    if (stackAddress >= dispatchHaltFrameAddress)
+                    {
+                        Js::DynamicObject* stackTraceObject = this->GetStackFrame(stackFrame, frameCount);
+
+                        Js::Var marshaledObj = Js::CrossSite::MarshalVar(scriptContext, stackTraceObject);
+                        Js::JavascriptOperators::OP_SetElementI((Js::Var)stackTraceArray, Js::JavascriptNumber::ToVar(frameCount++, scriptContext), marshaledObj, scriptContext);
+                    }
                 }
             }
+
             framePointers->ReleaseStrongReference();
             HeapDelete(framePointers);
         }

+ 1 - 1
lib/Jsrt/JsrtDebuggerObject.h

@@ -120,7 +120,7 @@ public:
     ~JsrtDebuggerStackFrame();
     Js::DynamicObject* GetJSONObject(Js::ScriptContext* scriptContext);
     Js::DynamicObject* GetLocalsObject(Js::ScriptContext* scriptContext);
-    Js::DynamicObject* Evaluate(Js::ScriptContext* scriptContext, const char16 *source, int sourceLength, bool isLibraryCode);
+    bool Evaluate(Js::ScriptContext* scriptContext, const char16 *source, int sourceLength, bool isLibraryCode, Js::DynamicObject** evalResult);
     uint GetIndex() const { return this->frameIndex; }
 
 private:

+ 5 - 4
lib/Jsrt/JsrtDiag.cpp

@@ -658,14 +658,15 @@ CHAKRA_API JsDiagEvaluate(
             return JsErrorInvalidArgument;
         }
 
-        Js::DynamicObject* result = debuggerStackFrame->Evaluate(scriptContext, expression, static_cast<int>(len), false);
+        Js::DynamicObject* result = nullptr;
+        bool success = debuggerStackFrame->Evaluate(scriptContext, expression, static_cast<int>(len), false, &result);
 
         if (result != nullptr)
         {
             *evalResult = result;
-            return JsNoError;
         }
 
-        return JsErrorDiagUnableToPerformAction;
-    });
+        return success ? JsNoError : JsErrorScriptException;
+
+    }, false /*allowInObjectBeforeCollectCallback*/, true /*scriptExceptionAllowed*/);
 }

+ 2 - 2
lib/Jsrt/JsrtInternal.h

@@ -177,7 +177,7 @@ JsErrorCode ContextAPIWrapper(Fn fn)
 
 // allowInObjectBeforeCollectCallback only when current API is guaranteed not to do recycler allocation.
 template <class Fn>
-JsErrorCode ContextAPINoScriptWrapper(Fn fn, bool allowInObjectBeforeCollectCallback = false)
+JsErrorCode ContextAPINoScriptWrapper(Fn fn, bool allowInObjectBeforeCollectCallback = false, bool scriptExceptionAllowed = false)
 {
     JsrtContext *currentContext = JsrtContext::GetCurrent();
     JsErrorCode errCode = CheckContext(currentContext, /*verifyRuntimeState*/true, allowInObjectBeforeCollectCallback);
@@ -204,7 +204,7 @@ JsErrorCode ContextAPINoScriptWrapper(Fn fn, bool allowInObjectBeforeCollectCall
             errCode != JsErrorInExceptionState &&
             errCode != JsErrorInDisabledState &&
             errCode != JsErrorOutOfMemory &&
-            errCode != JsErrorScriptException &&
+            (scriptExceptionAllowed || errCode != JsErrorScriptException) &&
             errCode != JsErrorScriptTerminated);
     }
     CATCH_STATIC_JAVASCRIPT_EXCEPTION_OBJECT

+ 6 - 1
lib/Parser/CharSet.cpp

@@ -1870,11 +1870,16 @@ namespace UnifiedRegex
     }
 #endif
 
-    const int  CharSetNode::directBits;
+    // The VS2013 linker treats this as a redefinition of an already
+    // defined constant and complains. So skip the declaration if we're compiling
+    // with VS2013 or below.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+	const int  CharSetNode::directBits;
     const uint CharSetNode::directSize;
     const uint CharSetNode::innerMask;
     const int  CharSetNode::bitsPerLeafLevel;
     const int  CharSetNode::branchingPerLeafLevel;
     const uint CharSetNode::leafMask;
     const uint CharSetNode::levels;
+#endif
 }

+ 5 - 0
lib/Parser/CharTrie.cpp

@@ -6,7 +6,12 @@
 
 namespace UnifiedRegex
 {
+    // The VS2013 linker treats this as a redefinition of an already
+    // defined constant and complains. So skip the declaration if we're compiling
+    // with VS2013 or below.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
     const int CharTrie::initCapacity;
+#endif
 
     // ----------------------------------------------------------------------
     // CharTrie

+ 2 - 28
lib/Parser/Parse.cpp

@@ -1632,23 +1632,8 @@ void Parser::BindPidRefs(BlockInfoStack *blockInfo, uint maxBlockId)
             Assert(pnode);
             switch (pnode->nop)
             {
-            case knopLetDecl:
             case knopVarDecl:
-                pid = pnode->sxVar.pid;
-                if (backgroundPidRef)
-                {
-                    pid = this->m_pscan->m_phtbl->FindExistingPid(pid->Psz(), pid->Cch(), pid->Hash(), nullptr, nullptr
-#if PROFILE_DICTIONARY
-                                                                  , depth
-#endif
-                        );
-                    if (pid == nullptr)
-                    {
-                        break;
-                    }
-                }
-                this->BindPidRefsInScope(pid, sym, blockId, maxBlockId);
-                break;
+            case knopLetDecl:
             case knopConstDecl:
                 pid = pnode->sxVar.pid;
                 if (backgroundPidRef)
@@ -1663,7 +1648,7 @@ void Parser::BindPidRefs(BlockInfoStack *blockInfo, uint maxBlockId)
                         break;
                     }
                 }
-                this->BindConstPidRefsInScope(pid, sym, blockId, maxBlockId);
+                this->BindPidRefsInScope(pid, sym, blockId, maxBlockId);
                 break;
             case knopName:
                 pid = pnode->sxPid.pid;
@@ -1692,17 +1677,6 @@ void Parser::BindPidRefs(BlockInfoStack *blockInfo, uint maxBlockId)
 }
 
 void Parser::BindPidRefsInScope(IdentPtr pid, Symbol *sym, int blockId, uint maxBlockId)
-{
-    this->BindPidRefsInScopeImpl<false>(pid, sym, blockId, maxBlockId);
-}
-
-void Parser::BindConstPidRefsInScope(IdentPtr pid, Symbol *sym, int blockId, uint maxBlockId)
-{
-    this->BindPidRefsInScopeImpl<true>(pid, sym, blockId, maxBlockId);
-}
-
-template<const bool isConstBinding>
-void Parser::BindPidRefsInScopeImpl(IdentPtr pid, Symbol *sym, int blockId, uint maxBlockId)
 {
     PidRefStack *ref, *nextRef, *lastRef = nullptr;
     Assert(sym);

+ 0 - 3
lib/Parser/Parse.h

@@ -709,9 +709,6 @@ private:
     template<const bool backgroundPidRefs>
     void BindPidRefs(BlockInfoStack *blockInfo, uint maxBlockId = (uint)-1);
     void BindPidRefsInScope(IdentPtr pid, Symbol *sym, int blockId, uint maxBlockId = (uint)-1);
-    void BindConstPidRefsInScope(IdentPtr pid, Symbol *sym, int blockId, uint maxBlockId = (uint)-1);
-    template<const bool constBinding>
-    void BindPidRefsInScopeImpl(IdentPtr pid, Symbol *sym, int blockId, uint maxBlockId = (uint)-1);
     void PushScope(Scope *scope);
     void PopScope(Scope *scope);
 

+ 5 - 0
lib/Parser/RegexCompileTime.cpp

@@ -11,7 +11,12 @@ namespace UnifiedRegex
     // Compiler (inlines etc)
     // ----------------------------------------------------------------------
 
+    // The VS2013 linker treats this as a redefinition of an already
+    // defined constant and complains. So skip the declaration if we're compiling
+    // with VS2013 or below.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
     const CharCount Compiler::initInstBufSize;
+#endif
 
     uint8* Compiler::Emit(size_t size)
     {

+ 11 - 0
lib/Parser/rterrors.h

@@ -342,3 +342,14 @@ RT_ERROR_MSG(JSERR_ResolveExportFailed, 5647, "Resolve export %s failed due to c
 
 RT_ERROR_MSG(JSERR_ObjectCoercible, 5648, "", "Cannot convert null or undefined to object", kjstTypeError, 0)
 RT_ERROR_MSG(JSERR_SIMDConversion, 5649, "%s: cannot be converted to a number", "Cannot be converted to a number", kjstTypeError, 0)
+
+
+// JSON.parse errors. When this happens we want to make it explicitly clear the issue is in JSON.parse and not in the code
+RT_ERROR_MSG(JSERR_JsonSyntax, 5650, "JSON.parse Error: Unexpected input at position:%s", "JSON.parse syntax error", kjstTypeError, 0)
+RT_ERROR_MSG(JSERR_JsonNoColon, 5651,"JSON.parse Error: Expected ':' at position:%s", "JSON.parse syntax error", kjstTypeError, 0)
+RT_ERROR_MSG(JSERR_JsonNoRbrack, 5652, "JSON.parse Error: Expected ']' at position:%s", "JSON.parse syntax error", kjstTypeError, 0)
+RT_ERROR_MSG(JSERR_JsonNoRcurly, 5653, "JSON.parse Error: Expected '}' at position:%s", "JSON.parse syntax error", kjstTypeError, 0)
+RT_ERROR_MSG(JSERR_JsonBadNumber, 5654, "JSON.parse Error: Invalid number at position:%s", "JSON.parse syntax error", kjstTypeError, 0)
+RT_ERROR_MSG(JSERR_JsonIllegalChar, 5655, "JSON.parse Error: Invalid character at position:%s", "JSON.parse syntax error", kjstTypeError, 0)
+RT_ERROR_MSG(JSERR_JsonBadHexDigit, 5656, "JSON.parse Error: Expected hexadecimal digit at position:%s", "JSON.parse syntax error", kjstTypeError, 0)
+RT_ERROR_MSG(JSERR_JsonNoStrEnd, 5657, "JSON.parse Error: Unterminated string constant at position:%s", "JSON.parse syntax error", kjstTypeError, 0)

+ 5 - 0
lib/Runtime/Base/Constants.cpp

@@ -6,8 +6,13 @@
 
 using namespace Js;
 
+// The VS2013 linker treats this as a redefinition of an already
+// defined constant and complains. So skip the declaration if we're compiling
+// with VS2013 or below.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const uint Constants::InvalidSourceIndex;
 const RegSlot Constants::NoRegister;
+#endif
 
 const char16 Constants::AnonymousFunction[] = _u("Anonymous function");
 const char16 Constants::Anonymous[] = _u("anonymous");

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

@@ -33,7 +33,12 @@
 
 namespace Js
 {
+    // The VS2013 linker treats this as a redefinition of an already
+    // defined constant and complains. So skip the declaration if we're compiling
+    // with VS2013 or below.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
     uint const ScopeSlots::MaxEncodedSlotCount;
+#endif
 
     CriticalSection FunctionProxy::GlobalLock;
 
@@ -3245,6 +3250,14 @@ namespace Js
         Assert(((LoopEntryPointInfo*) entryPointInfo)->loopHeader == loopHeader);
         Assert(reinterpret_cast<void*>(entryPointInfo->jsMethod) == nullptr);
         entryPointInfo->jsMethod = entryPoint;
+
+        ((Js::LoopEntryPointInfo*)entryPointInfo)->totalJittedLoopIterations = 
+            static_cast<uint8>(
+                min(
+                    static_cast<uint>(static_cast<uint8>(CONFIG_FLAG(MinBailOutsBeforeRejitForLoops))) *
+                    (Js::LoopEntryPointInfo::GetDecrLoopCountPerBailout() - 1),
+                    0xffu));
+
         // reset the counter to 1 less than the threshold for TJLoopBody
         if (loopHeader->GetCurrentEntryPointInfo()->GetIsAsmJSFunction())
         {

+ 22 - 8
lib/Runtime/Base/FunctionBody.h

@@ -942,11 +942,6 @@ namespace Js
         FunctionEntryPointInfo* mOldFunctionEntryPointInfo; // strong ref to oldEntryPointInfo(Int or TJ) in asm to ensure we don't collect it before JIT is completed
         bool       mIsTemplatizedJitMode; // true only if in TJ mode, used only for debugging
     public:
-        static const uint8 GetDecrCallCountPerBailout()
-        {
-            return (100 / (uint8)CONFIG_FLAG(CallsToBailoutsRatioForRejit)) + 1;
-        }
-
         FunctionEntryPointInfo(FunctionProxy * functionInfo, Js::JavascriptMethod method, ThreadContext* context, void* validationCookie);
 
 #ifndef TEMP_DISABLE_ASMJS
@@ -968,6 +963,10 @@ namespace Js
         virtual void Expire() override;
         virtual void EnterExpirableCollectMode() override;
         virtual void ResetOnNativeCodeInstallFailure() override;
+        static const uint8 GetDecrCallCountPerBailout()
+        {
+            return (uint8)CONFIG_FLAG(CallsToBailoutsRatioForRejit) + 1;
+        }
 #endif
 
         virtual void OnCleanup(bool isShutdown) override;
@@ -984,9 +983,14 @@ namespace Js
     {
     public:
         LoopHeader* loopHeader;
+        uint jittedLoopIterationsSinceLastBailout; // number of times the loop iterated in the jitted code before bailing out 
+        uint totalJittedLoopIterations; // total number of times the loop has iterated in the jitted code for this entry point for a particular invocation of the loop
         LoopEntryPointInfo(LoopHeader* loopHeader, Js::JavascriptLibrary* library, void* validationCookie) :
-            loopHeader(loopHeader), mIsTemplatizedJitMode(false),EntryPointInfo(nullptr, library, validationCookie, /*threadContext*/ nullptr, /*isLoopBody*/ true)
-
+            EntryPointInfo(nullptr, library, validationCookie, /*threadContext*/ nullptr, /*isLoopBody*/ true),
+            loopHeader(loopHeader),
+            jittedLoopIterationsSinceLastBailout(0),
+            totalJittedLoopIterations(0),
+            mIsTemplatizedJitMode(false)
 #ifdef BGJIT_STATS
             ,used(false)
 #endif
@@ -998,6 +1002,10 @@ namespace Js
 
 #if ENABLE_NATIVE_CODEGEN
         virtual void ResetOnNativeCodeInstallFailure() override;
+        static const uint8 GetDecrLoopCountPerBailout()
+        {
+            return (uint8)CONFIG_FLAG(LoopIterationsToBailoutsRatioForRejit) + 1;
+        }
 #endif
 
 #ifndef TEMP_DISABLE_ASMJS
@@ -1064,7 +1072,7 @@ namespace Js
         static const uint GetOffsetOfProfiledLoopCounter() { return offsetof(LoopHeader, profiledLoopCounter); }
         static const uint GetOffsetOfInterpretCount() { return offsetof(LoopHeader, interpretCount); }
 
-                bool Contains(Js::LoopHeader * loopHeader) const
+        bool Contains(Js::LoopHeader * loopHeader) const
         {
             return (this->startOffset <= loopHeader->startOffset && loopHeader->endOffset <= this->endOffset);
         }
@@ -2206,6 +2214,12 @@ namespace Js
             return &entryPoint->callsCount;
         }
 
+        uint *GetJittedLoopIterationsSinceLastBailoutAddress(EntryPointInfo* info) const
+        {
+            LoopEntryPointInfo* entryPoint = (LoopEntryPointInfo*)info;
+            return &entryPoint->jittedLoopIterationsSinceLastBailout;
+        }
+
         FunctionEntryPointInfo* GetDefaultFunctionEntryPointInfo() const;
         void SetDefaultFunctionEntryPointInfo(FunctionEntryPointInfo* entryPointInfo, const JavascriptMethod originalEntryPoint);
 

+ 0 - 2
lib/Runtime/Base/JnDirectFields.h

@@ -139,8 +139,6 @@ ENTRY(equal)
 ENTRY(notEqual)
 ENTRY(greaterThanOrEqual)
 ENTRY(greaterThan)
-ENTRY(minNum)
-ENTRY(maxNum)
 ENTRY(shiftLeft)
 ENTRY(shiftLeftByScalar)
 ENTRY(shiftRightByScalar)

+ 48 - 41
lib/Runtime/Base/ScriptContext.cpp

@@ -2732,62 +2732,64 @@ if (!sourceList)
 
         hr = this->GetDebugContext()->RundownSourcesAndReparse(shouldPerformSourceRundown, /*shouldReparseFunctions*/ true);
 
+        if (this->IsClosed())
+        {
+            return hr;
+        }
+
         // Debugger attach/detach failure is catastrophic, take down the process
         DEBUGGER_ATTACHDETACH_FATAL_ERROR_IF_FAILED(hr);
 
-        if (!this->IsClosed())
-        {
-            HRESULT hrEntryPointUpdate = S_OK;
-            BEGIN_TRANSLATE_OOM_TO_HRESULT_NESTED
+        HRESULT hrEntryPointUpdate = S_OK;
+        BEGIN_TRANSLATE_OOM_TO_HRESULT_NESTED
 #ifdef ASMJS_PLAT
-                TempArenaAllocatorObject* tmpAlloc = GetTemporaryAllocator(_u("DebuggerTransition"));
-                debugTransitionAlloc = tmpAlloc->GetAllocator();
+            TempArenaAllocatorObject* tmpAlloc = GetTemporaryAllocator(_u("DebuggerTransition"));
+            debugTransitionAlloc = tmpAlloc->GetAllocator();
 
-                asmJsEnvironmentMap = Anew(debugTransitionAlloc, AsmFunctionMap, debugTransitionAlloc);
+            asmJsEnvironmentMap = Anew(debugTransitionAlloc, AsmFunctionMap, debugTransitionAlloc);
 #endif
 
-                // Still do the pass on the function's entrypoint to reflect its state with the functionbody's entrypoint.
-                this->UpdateRecyclerFunctionEntryPointsForDebugger();
+            // Still do the pass on the function's entrypoint to reflect its state with the functionbody's entrypoint.
+            this->UpdateRecyclerFunctionEntryPointsForDebugger();
 
 #ifdef ASMJS_PLAT
-                auto asmEnvIter = asmJsEnvironmentMap->GetIterator();
-                while (asmEnvIter.IsValid())
+            auto asmEnvIter = asmJsEnvironmentMap->GetIterator();
+            while (asmEnvIter.IsValid())
+            {
+                // we are attaching, change frame setup for asm.js frame to javascript frame
+                SList<AsmJsScriptFunction *> * funcList = asmEnvIter.CurrentValue();
+                Assert(!funcList->Empty());
+                void* newEnv = AsmJsModuleInfo::ConvertFrameForJavascript(asmEnvIter.CurrentKey(), funcList->Head());
+                funcList->Iterate([&](AsmJsScriptFunction * func)
                 {
-                    // we are attaching, change frame setup for asm.js frame to javascript frame
-                    SList<AsmJsScriptFunction *> * funcList = asmEnvIter.CurrentValue();
-                    Assert(!funcList->Empty());
-                    void* newEnv = AsmJsModuleInfo::ConvertFrameForJavascript(asmEnvIter.CurrentKey(), funcList->Head());
-                    funcList->Iterate([&](AsmJsScriptFunction * func)
-                    {
-                        func->GetEnvironment()->SetItem(0, newEnv);
-                    });
-                    asmEnvIter.MoveNext();
-                }
+                    func->GetEnvironment()->SetItem(0, newEnv);
+                });
+                asmEnvIter.MoveNext();
+            }
 
-                // walk through and clean up the asm.js fields as a discrete step, because module might be multiply linked
-                auto asmCleanupIter = asmJsEnvironmentMap->GetIterator();
-                while (asmCleanupIter.IsValid())
+            // walk through and clean up the asm.js fields as a discrete step, because module might be multiply linked
+            auto asmCleanupIter = asmJsEnvironmentMap->GetIterator();
+            while (asmCleanupIter.IsValid())
+            {
+                SList<AsmJsScriptFunction *> * funcList = asmCleanupIter.CurrentValue();
+                Assert(!funcList->Empty());
+                funcList->Iterate([](AsmJsScriptFunction * func)
                 {
-                    SList<AsmJsScriptFunction *> * funcList = asmCleanupIter.CurrentValue();
-                    Assert(!funcList->Empty());
-                    funcList->Iterate([](AsmJsScriptFunction * func)
-                    {
-                        func->SetModuleMemory(nullptr);
-                        func->GetFunctionBody()->ResetAsmJsInfo();
-                    });
-                    asmCleanupIter.MoveNext();
-                }
+                    func->SetModuleMemory(nullptr);
+                    func->GetFunctionBody()->ResetAsmJsInfo();
+                });
+                asmCleanupIter.MoveNext();
+            }
 
-                ReleaseTemporaryAllocator(tmpAlloc);
+            ReleaseTemporaryAllocator(tmpAlloc);
 #endif
-            END_TRANSLATE_OOM_TO_HRESULT(hrEntryPointUpdate);
+        END_TRANSLATE_OOM_TO_HRESULT(hrEntryPointUpdate);
 
-            if (hrEntryPointUpdate != S_OK)
-            {
-                // should only be here for OOM
-                Assert(hrEntryPointUpdate == E_OUTOFMEMORY);
-                return hrEntryPointUpdate;
-            }
+        if (hrEntryPointUpdate != S_OK)
+        {
+            // should only be here for OOM
+            Assert(hrEntryPointUpdate == E_OUTOFMEMORY);
+            return hrEntryPointUpdate;
         }
 
         OUTPUT_TRACE(Js::DebuggerPhase, _u("ScriptContext::OnDebuggerAttached: done 0x%p, hr = 0x%X\n"), this, hr);
@@ -2827,6 +2829,11 @@ if (!sourceList)
         // Force a reparse so that indirect function caches are updated.
         hr = this->GetDebugContext()->RundownSourcesAndReparse(/*shouldPerformSourceRundown*/ false, /*shouldReparseFunctions*/ true);
 
+        if (this->IsClosed())
+        {
+            return hr;
+        }
+
         // Debugger attach/detach failure is catastrophic, take down the process
         DEBUGGER_ATTACHDETACH_FATAL_ERROR_IF_FAILED(hr);
 

+ 58 - 5
lib/Runtime/Base/ThreadContext.cpp

@@ -88,7 +88,8 @@ ThreadContext::RecyclableData::RecyclableData(Recycler *const recycler) :
     typesWithProtoPropertyCache(recycler),
     propertyGuards(recycler, 128),
     oldEntryPointInfo(nullptr),
-    returnedValueList(nullptr)
+    returnedValueList(nullptr),
+    constructorCacheInvalidationCount(0)
 {
 }
 
@@ -2531,6 +2532,39 @@ ThreadContext::ClearInlineCachesWithDeadWeakRefs()
     }
 }
 
+void
+ThreadContext::ClearInvalidatedUniqueGuards()
+{
+    // If a propertyGuard was invalidated, make sure to remove it's entry from unique property guard table of other property records.
+    PropertyGuardDictionary &guards = this->recyclableData->propertyGuards;
+
+    guards.Map([this](Js::PropertyRecord const * propertyRecord, PropertyGuardEntry* entry, const RecyclerWeakReference<const Js::PropertyRecord>* weakRef)
+    {
+        entry->uniqueGuards.MapAndRemoveIf([=](RecyclerWeakReference<Js::PropertyGuard>* guardWeakRef)
+        {
+            Js::PropertyGuard* guard = guardWeakRef->Get();
+            bool shouldRemove = guard != nullptr && !guard->IsValid();
+            if (shouldRemove)
+            {
+                if (PHASE_TRACE1(Js::TracePropertyGuardsPhase) || PHASE_VERBOSE_TRACE1(Js::FixedMethodsPhase))
+                {
+                    Output::Print(_u("FixedFields: invalidating guard: name: %s, address: 0x%p, value: 0x%p, value address: 0x%p\n"),
+                                  propertyRecord->GetBuffer(), guard, guard->GetValue(), guard->GetAddressOfValue());
+                    Output::Flush();
+                }
+                if (PHASE_TESTTRACE1(Js::TracePropertyGuardsPhase) || PHASE_VERBOSE_TESTTRACE1(Js::FixedMethodsPhase))
+                {
+                    Output::Print(_u("FixedFields: invalidating guard: name: %s, value: 0x%p\n"),
+                                  propertyRecord->GetBuffer(), guard->GetValue());
+                    Output::Flush();
+                }
+            }
+
+            return shouldRemove;
+        });
+    });
+}
+
 void
 ThreadContext::ClearInlineCaches()
 {
@@ -2916,6 +2950,8 @@ ThreadContext::RegisterUniquePropertyGuard(Js::PropertyId propertyId, RecyclerWe
     const Js::PropertyRecord * propertyRecord = GetPropertyName(propertyId);
 
     bool foundExistingGuard;
+
+    
     PropertyGuardEntry* entry = EnsurePropertyGuardEntry(propertyRecord, foundExistingGuard);
 
     entry->uniqueGuards.Item(guardWeakRef);
@@ -2944,7 +2980,7 @@ ThreadContext::RegisterConstructorCache(Js::PropertyId propertyId, Js::Construct
 }
 
 void
-ThreadContext::InvalidatePropertyGuardEntry(const Js::PropertyRecord* propertyRecord, PropertyGuardEntry* entry)
+ThreadContext::InvalidatePropertyGuardEntry(const Js::PropertyRecord* propertyRecord, PropertyGuardEntry* entry, bool isAllPropertyGuardsInvalidation)
 {
     Assert(entry != nullptr);
 
@@ -2968,7 +3004,8 @@ ThreadContext::InvalidatePropertyGuardEntry(const Js::PropertyRecord* propertyRe
         guard->Invalidate();
     }
 
-    entry->uniqueGuards.Map([propertyRecord](RecyclerWeakReference<Js::PropertyGuard>* guardWeakRef)
+    uint count = 0;
+    entry->uniqueGuards.Map([&count, propertyRecord](RecyclerWeakReference<Js::PropertyGuard>* guardWeakRef)
     {
         Js::PropertyGuard* guard = guardWeakRef->Get();
         if (guard != nullptr)
@@ -2988,11 +3025,27 @@ ThreadContext::InvalidatePropertyGuardEntry(const Js::PropertyRecord* propertyRe
             }
 
             guard->Invalidate();
+            count++;
         }
     });
 
     entry->uniqueGuards.Clear();
 
+    
+    // Count no. of invalidations done so far. Exclude if this is all property guards invalidation in which case
+    // the unique Guards will be cleared anyway.
+    if (!isAllPropertyGuardsInvalidation)
+    {
+        this->recyclableData->constructorCacheInvalidationCount += count;
+        if (this->recyclableData->constructorCacheInvalidationCount > (uint)CONFIG_FLAG(ConstructorCacheInvalidationThreshold))
+        {
+            // TODO: In future, we should compact the uniqueGuards dictionary so this function can be called from PreCollectionCallback
+            // instead
+            this->ClearInvalidatedUniqueGuards();
+            this->recyclableData->constructorCacheInvalidationCount = 0;
+        }
+    }
+
     if (entry->entryPoints && entry->entryPoints->Count() > 0)
     {
         Js::JavascriptStackWalker stackWalker(this->GetScriptContextList());
@@ -3031,7 +3084,7 @@ ThreadContext::InvalidatePropertyGuards(Js::PropertyId propertyId)
     PropertyGuardEntry* entry;
     if (guards.TryGetValueAndRemove(propertyRecord, &entry))
     {
-        InvalidatePropertyGuardEntry(propertyRecord, entry);
+        InvalidatePropertyGuardEntry(propertyRecord, entry, false);
     }
 }
 
@@ -3043,7 +3096,7 @@ ThreadContext::InvalidateAllPropertyGuards()
     {
         guards.Map([this](Js::PropertyRecord const * propertyRecord, PropertyGuardEntry* entry, const RecyclerWeakReference<const Js::PropertyRecord>* weakRef)
         {
-            InvalidatePropertyGuardEntry(propertyRecord, entry);
+            InvalidatePropertyGuardEntry(propertyRecord, entry, true);
         });
 
         guards.Clear();

+ 7 - 4
lib/Runtime/Base/ThreadContext.h

@@ -497,9 +497,9 @@ private:
         typedef JsUtil::WeaklyReferencedKeyDictionary<Js::EntryPointInfo, BYTE> EntryPointDictionary;
         // The sharedGuard is strongly referenced and will be kept alive by ThreadContext::propertyGuards until it's invalidated or
         // the property record itself is collected.  If the code using the guard needs access to it after it's been invalidated, it
-        // (the code) is responsible for keeping it alive.  Each unique guard, is weakly referenced, such that it can be reclaimed
-        // if not referenced elsewhere even without being invalidated.  It's up to the owner of that guard to keep it alive as long
-        // as necessary.
+        // (the code) is responsible for keeping it alive.
+        // Each unique guard, is weakly referenced, such that it can be reclaimed if not referenced elsewhere even without being
+        // invalidated.  The entry of a unique guard is removed from the table once the corresponding cache is invalidated.
         Js::PropertyGuard* sharedGuard;
         PropertyGuardHashSet uniqueGuards;
         EntryPointDictionary* entryPoints;
@@ -597,6 +597,8 @@ private:
         // Just holding the reference to the returnedValueList of the stepController. This way that list will not get recycled prematurely.
         Js::ReturnedValueList *returnedValueList;
 
+        uint constructorCacheInvalidationCount;
+
 #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
         // use for autoProxy called from Debug.setAutoProxyName. we need to keep the buffer from GetSz() alive.
         LPCWSTR autoProxyName;
@@ -1226,7 +1228,7 @@ private:
 #if ENABLE_NATIVE_CODEGEN
     void InvalidateFixedFieldGuard(Js::PropertyGuard* guard);
     PropertyGuardEntry* EnsurePropertyGuardEntry(const Js::PropertyRecord* propertyRecord, bool& foundExistingEntry);
-    void InvalidatePropertyGuardEntry(const Js::PropertyRecord* propertyRecord, PropertyGuardEntry* entry);
+    void InvalidatePropertyGuardEntry(const Js::PropertyRecord* propertyRecord, PropertyGuardEntry* entry, bool isAllPropertyGuardsInvalidation);
 #endif
 
 public:
@@ -1277,6 +1279,7 @@ public:
 #ifdef PERSISTENT_INLINE_CACHES
     void ClearInlineCachesWithDeadWeakRefs();
 #endif
+    void ClearInvalidatedUniqueGuards();
     void ClearInlineCaches();
     void ClearIsInstInlineCaches();
     void ClearEquivalentTypeCaches();

+ 7 - 25
lib/Runtime/ByteCode/ByteCodeEmitter.cpp

@@ -4226,7 +4226,7 @@ void ByteCodeGenerator::StartEmitCatch(ParseNode *pnodeCatch)
 
         // Catch object is stored in the catch scope if there may be an ambiguous lookup or a var declaration that hides it.
         scope->SetCapturesAll(funcInfo->GetCallsEval() || funcInfo->GetChildCallsEval() || sym->GetHasNonLocalReference());
-        scope->SetMustInstantiate(scope->GetCapturesAll() || funcInfo->IsGlobalFunction() || currentScope != funcInfo->GetBodyScope());
+        scope->SetMustInstantiate(scope->GetCapturesAll() || funcInfo->IsGlobalFunction());
 
         if (funcInfo->IsGlobalFunction())
         {
@@ -4239,27 +4239,17 @@ void ByteCodeGenerator::StartEmitCatch(ParseNode *pnodeCatch)
             // Also in order to make IsInSlot to return true - forcing the sym-has-non-local-reference.
             sym->SetHasNonLocalReference(true, this);
             sym->EnsureScopeSlot(funcInfo);
-
-            PushScope(scope);
-        }
-        else
-        {
-            // Add it to the parent function's scope and treat it like any other local.
-            // We can only do this if we don't need to get the symbol from a slot, though, because adding it to the
-            // parent's scope object on entry to the catch could re-size the slot array.
-            funcInfo->bodyScope->AddSymbol(sym);
         }
+
+        PushScope(scope);
     }
 }
 
 void ByteCodeGenerator::EndEmitCatch(ParseNode *pnodeCatch)
 {
     Assert(pnodeCatch->nop == knopCatch);
-    if (pnodeCatch->sxCatch.scope->GetMustInstantiate() || pnodeCatch->sxCatch.pnodeParam->nop == knopParamPattern)
-    {
-        Assert(currentScope == pnodeCatch->sxCatch.scope);
-        PopScope();
-    }
+    Assert(currentScope == pnodeCatch->sxCatch.scope);
+    PopScope();
 }
 
 void ByteCodeGenerator::StartEmitBlock(ParseNode *pnodeBlock)
@@ -10796,11 +10786,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
         byteCodeGenerator->Writer()->Reg1(Js::OpCode::Catch, location);
 
         Scope *scope = pnodeCatch->sxCatch.scope;
-
-        if (isPattern || scope->GetMustInstantiate())
-        {
-            byteCodeGenerator->PushScope(scope);
-        }
+        byteCodeGenerator->PushScope(scope);
 
         if (scope->GetMustInstantiate())
         {
@@ -10815,7 +10801,6 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
 
                 int index = Js::DebuggerScope::InvalidScopeIndex;
                 debuggerScope = byteCodeGenerator->RecordStartScopeObject(pnode, Js::DiagCatchScopeInSlot, funcInfo->InnerScopeToRegSlot(scope), &index);
-
                 byteCodeGenerator->Writer()->Num3(Js::OpCode::NewInnerScopeSlots, scope->GetInnerScopeIndex(), scope->GetScopeSlotCount() + Js::ScopeSlots::FirstSlotIndex, index);
             }
         }
@@ -10913,10 +10898,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
             byteCodeGenerator->tryScopeRecordsList.UnlinkFromEnd();
         }
 
-        if (scope->GetMustInstantiate() || isPattern)
-        {
-            byteCodeGenerator->PopScope();
-        }
+        byteCodeGenerator->PopScope();
 
         byteCodeGenerator->RecordEndScopeObject(pnode);
 

+ 0 - 3
lib/Runtime/ByteCode/OpCodesSimd.h

@@ -293,9 +293,6 @@ MACRO_SIMD_EXTEND_WMS     ( Simd128_FromUint16x8Bits_F4         , Float32x4_1Uin
 MACRO_SIMD_EXTEND_WMS     ( Simd128_FromInt8x16Bits_F4          , Float32x4_1Int8x16_1              , None           ,        OpCanCSE          ,      0)
 MACRO_SIMD_EXTEND_WMS     ( Simd128_FromUint8x16Bits_F4         , Float32x4_1Uint8x16_1             , None           ,        OpCanCSE          ,      0)
 
-MACRO_SIMD_EXTEND_WMS     ( Simd128_MinNum_F4                   , Float32x4_3                      , None           ,        OpCanCSE           ,      0)
-MACRO_SIMD_EXTEND_WMS     ( Simd128_MaxNum_F4                   , Float32x4_3                      , None           ,        OpCanCSE           ,      0)
-
 MACRO_SIMD_EXTEND_WMS     ( Simd128_LtEq_I4                     , Bool32x4_1Int32x4_2              , None           ,        None               ,      0)
 MACRO_SIMD_EXTEND_WMS     ( Simd128_GtEq_I4                     , Bool32x4_1Int32x4_2              , None           ,        None               ,      0)
 MACRO_SIMD_EXTEND_WMS     ( Simd128_Neq_I4                      , Bool32x4_1Int32x4_2              , None           ,        None               ,      0)

+ 13 - 5
lib/Runtime/Debug/DebugContext.cpp

@@ -148,6 +148,9 @@ namespace Js
             return hr;
         }
 
+        // VSO 6707388 - Cache ScriptContext as multiple calls below can go out of engine and ScriptContext can be closed which will delete DebugContext
+        Js::ScriptContext* cachedScriptContext = this->scriptContext;
+
         utf8SourceInfoList->MapUntil([&](int index, Js::Utf8SourceInfo * sourceInfo) -> bool
         {
             OUTPUT_TRACE(Js::DebuggerPhase, _u("DebugContext::RundownSourcesAndReparse scriptContext 0x%p, sourceInfo 0x%p, HasDebugDocument %d\n"),
@@ -211,14 +214,14 @@ namespace Js
 
                 if (shouldReparseFunctions)
                 {
-                    if (this->scriptContext == nullptr || this->scriptContext->IsClosed())
+                    if (cachedScriptContext->IsClosed())
                     {
                         // scriptContext can be closed in previous call
                         hr = E_FAIL;
                         return true;
                     }
 
-                    BEGIN_JS_RUNTIME_CALL_EX_AND_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT_NESTED(this->scriptContext, false)
+                    BEGIN_JS_RUNTIME_CALL_EX_AND_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT_NESTED(cachedScriptContext, false)
                     {
                         pFuncBody->Parse();
                         // This is the first call to the function, ensure dynamic profile info
@@ -258,11 +261,11 @@ namespace Js
             return false;
         });
 
-        if (this->scriptContext != nullptr && !this->scriptContext->IsClosed())
+        if (!cachedScriptContext->IsClosed())
         {
-            if (shouldPerformSourceRundown && this->scriptContext->HaveCalleeSources())
+            if (shouldPerformSourceRundown && cachedScriptContext->HaveCalleeSources())
             {
-                this->scriptContext->MapCalleeSources([=](Js::Utf8SourceInfo* calleeSourceInfo)
+                cachedScriptContext->MapCalleeSources([=](Js::Utf8SourceInfo* calleeSourceInfo)
                 {
                     if (this->hostDebugContext != nullptr)
                     {
@@ -271,6 +274,11 @@ namespace Js
                 });
             }
         }
+        else
+        {
+            hr = E_FAIL;
+        }
+
         threadContext->ReleaseTemporaryAllocator(tempAllocator);
 
         return hr;

+ 2 - 2
lib/Runtime/Debug/DebugManager.cpp

@@ -21,11 +21,11 @@ namespace Js
         jscriptBlockRegistrationCount(0),
         isDebuggerAttaching(false),
         nextBreakPointId(0),
-        localsDisplayFlags(LocalsDisplayFlags_None)
+        localsDisplayFlags(LocalsDisplayFlags_None),
+        dispatchHaltFrameAddress(nullptr)
     {
         Assert(_pThreadContext != nullptr);
 #if DBG
-        dispatchHaltFrameAddress = nullptr;
         // diagnosticPageAllocator may be used in multiple thread, but it's usage is synchronized.
         diagnosticPageAllocator.SetDisableThreadAccessCheck();
         diagnosticPageAllocator.debugName = _u("Diagnostic");

+ 2 - 3
lib/Runtime/Debug/DebugManager.h

@@ -33,9 +33,7 @@ namespace Js
         DebuggingFlags debuggingFlags;
         UINT nextBreakPointId;
         DWORD localsDisplayFlags;
-#if DBG
         void * dispatchHaltFrameAddress;
-#endif
     public:
         StepController stepController;
         AsyncBreakController asyncBreakController;
@@ -64,8 +62,9 @@ namespace Js
         FrameDisplay *GetFrameDisplay(ScriptContext* scriptContext, DynamicObject* scopeAtZero, DynamicObject* scopeAtOne);
         void UpdateConsoleScope(DynamicObject* copyFromScope, ScriptContext* scriptContext);
         PageAllocator * GetDiagnosticPageAllocator() { return &this->diagnosticPageAllocator; }
-#if DBG
         void SetDispatchHaltFrameAddress(void * returnAddress) { this->dispatchHaltFrameAddress = returnAddress; }
+        DWORD_PTR GetDispatchHaltFrameAddress() const { return (DWORD_PTR)this->dispatchHaltFrameAddress; }
+#if DBG
         void ValidateDebugAPICall();
 #endif
         void SetDebuggerAttaching(bool attaching) { this->isDebuggerAttaching = attaching; }

+ 0 - 2
lib/Runtime/Language/AsmJsBuiltInNames.h

@@ -190,8 +190,6 @@ ASMJS_SIMD_O_NAMES(float32x4_mul,                             mul,
 ASMJS_SIMD_O_NAMES(float32x4_div,                             div,                          Float32x4,        Div                         )
 ASMJS_SIMD_O_NAMES(float32x4_min,                             min,                          Float32x4,        Min                         )
 ASMJS_SIMD_O_NAMES(float32x4_max,                             max,                          Float32x4,        Max                         )
-ASMJS_SIMD_O_NAMES(float32x4_minNum,                          minNum,                       Float32x4,        MinNum                      )
-ASMJS_SIMD_O_NAMES(float32x4_maxNum,                          maxNum,                       Float32x4,        MaxNum                      )
 ASMJS_SIMD_O_NAMES(float32x4_reciprocal,                      reciprocalApproximation,      Float32x4,        Reciprocal                  )
 ASMJS_SIMD_O_NAMES(float32x4_reciprocalSqrt,                  reciprocalSqrtApproximation,  Float32x4,        ReciprocalSqrt              )
 ASMJS_SIMD_O_NAMES(float32x4_sqrt,                            sqrt,                         Float32x4,        Sqrt                        )

+ 0 - 2
lib/Runtime/Language/AsmJsModule.cpp

@@ -1537,8 +1537,6 @@ namespace Js
         simdFunctions[AsmJsSIMDBuiltin_float32x4_div]               = SIMDFunc(PropertyIds::div, Anew(&mAllocator, AsmJsSIMDFunction, nullptr, &mAllocator, 2, AsmJsSIMDBuiltin_float32x4_div, OpCodeAsmJs::Simd128_Div_F4, AsmJsRetType::Float32x4, AsmJsType::Float32x4, AsmJsType::Float32x4));
         simdFunctions[AsmJsSIMDBuiltin_float32x4_min]               = SIMDFunc(PropertyIds::min, Anew(&mAllocator, AsmJsSIMDFunction, nullptr, &mAllocator, 2, AsmJsSIMDBuiltin_float32x4_min, OpCodeAsmJs::Simd128_Min_F4, AsmJsRetType::Float32x4, AsmJsType::Float32x4, AsmJsType::Float32x4));
         simdFunctions[AsmJsSIMDBuiltin_float32x4_max]               = SIMDFunc(PropertyIds::max, Anew(&mAllocator, AsmJsSIMDFunction, nullptr, &mAllocator, 2, AsmJsSIMDBuiltin_float32x4_max, OpCodeAsmJs::Simd128_Max_F4, AsmJsRetType::Float32x4, AsmJsType::Float32x4, AsmJsType::Float32x4));
-        simdFunctions[AsmJsSIMDBuiltin_float32x4_minNum]            = SIMDFunc(PropertyIds::minNum, Anew(&mAllocator, AsmJsSIMDFunction, nullptr, &mAllocator, 2, AsmJsSIMDBuiltin_float32x4_minNum, OpCodeAsmJs::Simd128_MinNum_F4, AsmJsRetType::Float32x4, AsmJsType::Float32x4, AsmJsType::Float32x4));
-        simdFunctions[AsmJsSIMDBuiltin_float32x4_maxNum]            = SIMDFunc(PropertyIds::maxNum, Anew(&mAllocator, AsmJsSIMDFunction, nullptr, &mAllocator, 2, AsmJsSIMDBuiltin_float32x4_maxNum, OpCodeAsmJs::Simd128_MaxNum_F4, AsmJsRetType::Float32x4, AsmJsType::Float32x4, AsmJsType::Float32x4));
         simdFunctions[AsmJsSIMDBuiltin_float32x4_reciprocal]        = SIMDFunc(PropertyIds::reciprocalApproximation, Anew(&mAllocator, AsmJsSIMDFunction, nullptr, &mAllocator, 1, AsmJsSIMDBuiltin_float32x4_reciprocal, OpCodeAsmJs::Simd128_Rcp_F4, AsmJsRetType::Float32x4, AsmJsType::Float32x4));
         simdFunctions[AsmJsSIMDBuiltin_float32x4_reciprocalSqrt]    = SIMDFunc(PropertyIds::reciprocalSqrtApproximation, Anew(&mAllocator, AsmJsSIMDFunction, nullptr, &mAllocator, 1, AsmJsSIMDBuiltin_float32x4_reciprocalSqrt, OpCodeAsmJs::Simd128_RcpSqrt_F4, AsmJsRetType::Float32x4, AsmJsType::Float32x4));
         simdFunctions[AsmJsSIMDBuiltin_float32x4_sqrt]              = SIMDFunc(PropertyIds::sqrt, Anew(&mAllocator, AsmJsSIMDFunction, nullptr, &mAllocator, 1, AsmJsSIMDBuiltin_float32x4_sqrt, OpCodeAsmJs::Simd128_Sqrt_F4, AsmJsRetType::Float32x4, AsmJsType::Float32x4));

+ 2 - 0
lib/Runtime/Language/DynamicProfileInfo.cpp

@@ -187,6 +187,8 @@ namespace Js
         {
             returnTypeInfo[i] = ValueType::Uninitialized;
         }
+
+        this->rejitCount = 0;
 #if DBG
         for (ProfileId i = 0; i < functionBody->GetProfiledArrayCallSiteCount(); ++i)
         {

+ 8 - 1
lib/Runtime/Language/DynamicProfileInfo.h

@@ -499,11 +499,13 @@ namespace Js
             bool disableEquivalentObjTypeSpec : 1;
             bool disableObjTypeSpec_jitLoopBody : 1;
             bool disablePowIntIntTypeSpec : 1;
+            bool disableLoopImplicitCallInfo : 1;
         } bits;
 
         uint32 m_recursiveInlineInfo; // Bit is set for each callsites where the function is called recursively
-        BYTE currentInlinerVersion; // Used to detect when inlining profile changes
         uint32 polymorphicCacheState;
+        uint16 rejitCount;
+        BYTE currentInlinerVersion; // Used to detect when inlining profile changes
         bool hasFunctionBody;
 
 #if DBG
@@ -644,6 +646,8 @@ namespace Js
         void DisableFloatTypeSpec() { this->bits.disableFloatTypeSpec = true; }
         bool IsCheckThisDisabled() const { return this->bits.disableCheckThis; }
         void DisableCheckThis() { this->bits.disableCheckThis = true; }
+        bool IsLoopImplicitCallInfoDisabled() const { return this->bits.disableLoopImplicitCallInfo; }
+        void DisableLoopImplicitCallInfo() { this->bits.disableLoopImplicitCallInfo = true; }
 
         bool IsArrayCheckHoistDisabled(const bool isJitLoopBody) const
         {
@@ -785,6 +789,9 @@ namespace Js
         void DisablePowIntIntTypeSpec() { this->bits.disablePowIntIntTypeSpec = true; }
 
         static bool IsCallSiteNoInfo(Js::LocalFunctionId functionId) { return functionId == CallSiteNoInfo; }
+        int IncRejitCount() { return this->rejitCount++; }
+        int GetRejitCount() { return this->rejitCount; }
+
 #if DBG_DUMP
         void Dump(FunctionBody* functionBody, ArenaAllocator * dynamicProfileInfoAllocator = nullptr);
 #endif

+ 0 - 3
lib/Runtime/Language/InterpreterHandlerAsmJs.inl

@@ -377,9 +377,6 @@ EXDEF2    (NOPASMJS          , NopEx        , Empty
   EXDEF3_WMS   ( CUSTOM_ASMJS      , Simd128_StArrConst_F4   , OP_SimdStArrConstIndex  , AsmSimdTypedArr   )
   EXDEF3_WMS   ( CUSTOM_ASMJS      , Simd128_StArrConst_I4   , OP_SimdStArrConstIndex  , AsmSimdTypedArr   )
 
-  EXDEF2_WMS   ( SIMD_F4_2toF4_1    , Simd128_MinNum_F4            , Js::SIMDFloat32x4Operation::OpMinNum   )
-  EXDEF2_WMS   ( SIMD_F4_2toF4_1    , Simd128_MaxNum_F4            , Js::SIMDFloat32x4Operation::OpMaxNum   )
-  
   EXDEF2_WMS   ( SIMD_U4_1toF4_1    , Simd128_FromUint32x4_F4      , Js::SIMDFloat32x4Operation::OpFromUint32x4  )
   EXDEF2_WMS   ( SIMD_I8_1toF4_1    , Simd128_FromInt16x8Bits_F4   , Js::SIMDUtils::FromSimdBits            )
   EXDEF2_WMS   ( SIMD_I16_1toF4_1   , Simd128_FromInt8x16Bits_F4   , Js::SIMDUtils::FromSimdBits            )

+ 12 - 0
lib/Runtime/Language/InterpreterStackFrame.cpp

@@ -5877,6 +5877,18 @@ const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
                 {
                     this->CheckIfLoopIsHot(loopHeader->profiledLoopCounter);
                 }
+
+                if (newOffset >= loopHeader->endOffset)
+                {
+                    // Reset the totalJittedLoopIterations for the next invocation of this loop entry point
+                    entryPointInfo->totalJittedLoopIterations =
+                        static_cast<uint8>(
+                            min(
+                                static_cast<uint>(static_cast<uint8>(CONFIG_FLAG(MinBailOutsBeforeRejit))) *
+                                (Js::LoopEntryPointInfo::GetDecrLoopCountPerBailout() - 1),
+                                entryPointInfo->totalJittedLoopIterations));
+                    entryPointInfo->jittedLoopIterationsSinceLastBailout = 0;
+                }
                 m_reader.SetCurrentOffset(newOffset);
             }
 

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

@@ -6998,7 +6998,8 @@ CommonNumber:
         if (scriptContext->GetConfig()->IsES6HasInstanceEnabled())
         {
             Var instOfHandler = JavascriptOperators::GetProperty(constructor, PropertyIds::_symbolHasInstance, scriptContext);
-            if (JavascriptOperators::IsUndefinedObject(instOfHandler))
+            if (JavascriptOperators::IsUndefinedObject(instOfHandler) 
+                || instOfHandler == scriptContext->GetBuiltInLibraryFunction(JavascriptFunction::EntryInfo::SymbolHasInstance.GetOriginalEntryPoint()))
             {
                 return JavascriptBoolean::ToVar(constructor->HasInstance(instance, scriptContext, inlineCache), scriptContext);
             }

+ 268 - 235
lib/Runtime/Language/JavascriptStackWalker.cpp

@@ -298,147 +298,212 @@ namespace Js
 
     uint32 JavascriptStackWalker::GetByteCodeOffset() const
     {
+        uint32 offset = 0;
         if (this->IsJavascriptFrame())
         {
-            if (this->interpreterFrame
-#if ENABLE_NATIVE_CODEGEN
-                && this->lastInternalFrameInfo.codeAddress == nullptr
-#endif
-                )
+            if (this->interpreterFrame)
             {
-                uint32 offset = this->interpreterFrame->GetReader()->GetCurrentOffset();
-                if (offset == 0)
+                if (this->TryGetByteCodeOffsetFromInterpreterFrame(offset))
                 {
-                    // This will be the case when we are broken on the debugger on very first statement (due to async break).
-                    // Or the interpreter loop can throw OOS on entrance before executing bytecode.
                     return offset;
                 }
-                else
-                {
-                    // Note : For many cases, we move the m_currentLocation of ByteCodeReader already to next available opcode.
-                    // This could create problem in binding the exception to proper line offset.
-                    // Reducing by 1 will make sure the current offset falls under, current executing opcode.
-                    return offset - 1;
-                }
             }
 
 #if ENABLE_NATIVE_CODEGEN
-            DWORD_PTR pCodeAddr;
-            uint loopNum = LoopHeader::NoLoop;
-            if (this->lastInternalFrameInfo.codeAddress != nullptr)
+            if (TryGetByteCodeOffsetFromNativeFrame(offset))
             {
-                if (this->lastInternalFrameInfo.loopBodyFrameType == InternalFrameType_LoopBody)
-                {
-                    AnalysisAssert(this->interpreterFrame);
-                    loopNum = this->interpreterFrame->GetCurrentLoopNum();
-                    Assert(loopNum != LoopHeader::NoLoop);
-                }
-
-                pCodeAddr = (DWORD_PTR)this->lastInternalFrameInfo.codeAddress;
-            }
-            else
-            {
-                if (this->IsCurrentPhysicalFrameForLoopBody())
-                {
-                    // Internal frame but codeAddress on lastInternalFrameInfo not set. We must be in an inlined frame in the loop body.
-                    Assert(this->tempInterpreterFrame);
-                    loopNum = this->tempInterpreterFrame->GetCurrentLoopNum();
-                    Assert(loopNum != LoopHeader::NoLoop);
-                }
-                pCodeAddr = (DWORD_PTR)this->GetCurrentCodeAddr();
+                return offset;
             }
+#endif
+        }
+        return offset;
+    }
+
+    bool JavascriptStackWalker::TryGetByteCodeOffsetFromInterpreterFrame(uint32& offset) const
+    {
+#if ENABLE_NATIVE_CODEGEN
+        if (this->lastInternalFrameInfo.codeAddress != nullptr)
+        {
+            return false;
+        }
+#endif
+        offset = this->interpreterFrame->GetReader()->GetCurrentOffset();
+        if (offset == 0)
+        {
+            // This will be the case when we are broken on the debugger on very first statement (due to async break).
+            // Or the interpreter loop can throw OOS on entrance before executing bytecode.
+        }
+        else
+        {
+            // Note : For many cases, we move the m_currentLocation of ByteCodeReader already to next available opcode.
+            // This could create problem in binding the exception to proper line offset.
+            // Reducing by 1 will make sure the current offset falls under, current executing opcode.
+            offset--;
+        }
+        return true;
+    }
 
-            // If the current instruction's return address is the beginning of the next statement then we will show error for the next line, which would be completely wrong.
-            // The quick fix would be to look the address which is at least lesser than current return address.
+#if ENABLE_NATIVE_CODEGEN
+    bool JavascriptStackWalker::TryGetByteCodeOffsetFromNativeFrame(uint32& offset) const
+    {
+        DWORD_PTR pCodeAddr;
+        if (this->lastInternalFrameInfo.codeAddress != nullptr)
+        {
+            pCodeAddr = (DWORD_PTR)this->lastInternalFrameInfo.codeAddress;
+        }
+        else
+        {
+            pCodeAddr = (DWORD_PTR)this->GetCurrentCodeAddr();
+        }
 
-            // Assert to verify at what places this can happen.
-            Assert(pCodeAddr);
+        // If the current instruction's return address is the beginning of the next statement then we will show error for the next line, which would be completely wrong.
+        // The quick fix would be to look the address which is at least lesser than current return address.
 
-            if (pCodeAddr)
-            {
+        // Assert to verify at what places this can happen.
+        Assert(pCodeAddr);
+
+        if (pCodeAddr)
+        {
 #if defined(_M_ARM32_OR_ARM64)
-                // Note that DWORD_PTR is not actually a pointer type (!) but is simple unsigned long/__int64 (see BaseTsd.h).
-                // Thus, decrement would be by 1 byte and not 4 bytes as in pointer arithmetic. That's exactly what we need.
-                // For ARM the 'return address' is always odd and is 'next instr addr' + 1 byte, so to get to the BLX instr, we need to subtract 2 bytes from it.
-                AssertMsg(pCodeAddr % 2 == 1, "Got even number for pCodeAddr! It's expected to be return address, which should be odd.");
-                pCodeAddr--;
+            // Note that DWORD_PTR is not actually a pointer type (!) but is simple unsigned long/__int64 (see BaseTsd.h).
+            // Thus, decrement would be by 1 byte and not 4 bytes as in pointer arithmetic. That's exactly what we need.
+            // For ARM the 'return address' is always odd and is 'next instr addr' + 1 byte, so to get to the BLX instr, we need to subtract 2 bytes from it.
+            AssertMsg(pCodeAddr % 2 == 1, "Got even number for pCodeAddr! It's expected to be return address, which should be odd.");
+            pCodeAddr--;
 #endif
-                pCodeAddr--;
+            pCodeAddr--;
+        }
+
+        uint loopNum = GetLoopNumber();
+
+        JavascriptFunction *function = nullptr;
+        FunctionBody *inlinee = nullptr;
+
+        if (this->interpreterFrame == nullptr) //Inlining is disabled in Jit Loopbody. Don't attempt to get the statement map from the inlined frame.
+        {
+            function = this->GetCurrentFunctionFromPhysicalFrame();
+
+            // If there are inlined frames on the stack, we have to be able to return the byte code offsets of those inlined calls
+            // from their respective callers. But, we can use the current native address as IP for only the topmost inlined frame.
+            // TryGetByteCodeOffsetOfInlinee takes care of these conditions and sets up the offset of an inlinee in 'offset', if the
+            // current inlinee frame is not the topmost of the inlinee frames.
+            if (HasInlinedFramesOnStack() && TryGetByteCodeOffsetOfInlinee(function, loopNum, pCodeAddr, &inlinee, offset))
+            {
+                return true;
             }
+        }
+        else
+        {
+            //Get the function from the interpreterFrame in jit loop body case
+            //This is exactly same as this->GetCurrentFunctionFromPhysicalFrame() if the interpreterFrame is not
+            //called from bailout path.
+            Assert(this->lastInternalFrameInfo.codeAddress);
+            function = this->interpreterFrame->GetJavascriptFunction();
+        }
 
-            JavascriptFunction *function = nullptr;
-            FunctionBody *inlinee = nullptr;
-            StatementData data;
+        StatementData data;
+        if (function->GetFunctionBody() && function->GetFunctionBody()->GetMatchingStatementMapFromNativeAddress(pCodeAddr, data, loopNum, inlinee))
+        {
+            offset = data.bytecodeBegin;
+            return true;
+        }
+
+        return false;
+    }
 
-            if (this->interpreterFrame == nullptr) //Inlining is disabled in Jit Loopbody. Don't attempt to get the statement map from the inlined frame.
+    uint JavascriptStackWalker::GetLoopNumber() const
+    {
+        uint loopNum = LoopHeader::NoLoop;
+        if (this->lastInternalFrameInfo.codeAddress != nullptr)
+        {
+            if (this->lastInternalFrameInfo.frameType == InternalFrameType_LoopBody)
             {
-                // For inlined frames, translation from native offset -> source code happens in two steps.
-                // The native offset is first translated into a statement index using the physical frame's
-                // source context info. This statement index is then looked up in the *inlinee*'s source
-                // context info to get the bytecode offset.
-                //
-                // For all inlined frames contained within a physical frame we have only one offset == (IP - entry).
-                // Since we can't use that to get the other inlined callers' IPs, we save the IP of all inlined
-                // callers in its "callinfo" (See InlineeCallInfo). The top most inlined frame uses the IP
-                // of the physical frame. All other inlined frames use the preceding inlined frame's offset.
-                //
-                function = this->GetCurrentFunctionFromPhysicalFrame();
-                inlinee = inlinedFramesBeingWalked ? inlinedFrameWalker.GetFunctionObject()->GetFunctionBody() : nullptr;
-                InlinedFrameWalker  tmpFrameWalker;
-                if (inlinedFramesBeingWalked)
-                {
-                    // Inlined frames are being walked right now. The top most frame is where the IP is.
-                    if (!inlinedFrameWalker.IsTopMostFrame())
-                    {
-                        if (function->GetFunctionBody()->GetMatchingStatementMapFromNativeOffset(pCodeAddr,
-                            inlinedFrameWalker.GetCurrentInlineeOffset(),
-                            data,
-                            loopNum,
-                            inlinee))
-                        {
-                            return data.bytecodeBegin;
-                        }
-                    }
-                }
-                else if (ScriptFunction::Is(function) &&
-                    InlinedFrameWalker::FromPhysicalFrame(tmpFrameWalker, currentFrame, ScriptFunction::FromVar(function), previousInterpreterFrameIsFromBailout, loopNum, this))
-                {
-                    // Inlined frames are not being walked right now. However, if there
-                    // are inlined frames on the stack the InlineeCallInfo of the first inlined frame
-                    // has the native offset of the current physical frame.
-                    Assert(!inlinee);
-                    uint32 inlineeOffset = tmpFrameWalker.GetBottomMostInlineeOffset();
-                    tmpFrameWalker.Close();
-
-                    if (this->GetCurrentFunctionFromPhysicalFrame()->GetFunctionBody()->GetMatchingStatementMapFromNativeOffset(pCodeAddr,
-                        inlineeOffset,
-                        data,
-                        loopNum,
-                        inlinee))
-                    {
-                        return data.bytecodeBegin;
-                    }
-                }
+                AnalysisAssert(this->interpreterFrame);
+                loopNum = this->interpreterFrame->GetCurrentLoopNum();
+                Assert(loopNum != LoopHeader::NoLoop);
             }
-            else
+        }
+        else
+        {
+            if (this->IsCurrentPhysicalFrameForLoopBody())
             {
-                //Get the function from the interpreterFrame in jit loop body case
-                //This is exactly same as this->GetCurrentFunctionFromPhysicalFrame() if the interpreterFrame is not
-                //called from bailout path.
-                Assert(this->lastInternalFrameInfo.codeAddress);
-                function = this->interpreterFrame->GetJavascriptFunction();
+                // Internal frame but codeAddress on lastInternalFrameInfo not set. We must be in an inlined frame in the loop body.
+                Assert(this->tempInterpreterFrame);
+                loopNum = this->tempInterpreterFrame->GetCurrentLoopNum();
+                Assert(loopNum != LoopHeader::NoLoop);
             }
+        }
+
+        return loopNum;
+    }
+
+    bool JavascriptStackWalker::TryGetByteCodeOffsetOfInlinee(Js::JavascriptFunction* function, uint loopNum, DWORD_PTR pCodeAddr, Js::FunctionBody** inlinee, uint32& offset) const
+    {
+        // For inlined frames, translation from native offset -> source code happens in two steps.
+        // The native offset is first translated into a statement index using the physical frame's
+        // source context info. This statement index is then looked up in the *inlinee*'s source
+        // context info to get the bytecode offset.
+        //
+        // For all inlined frames contained within a physical frame we have only one offset == (IP - entry).
+        // Since we can't use that to get the other inlined callers' IPs, we save the IP of all inlined
+        // callers in their "callinfo" (See InlineeCallInfo). The top most inlined frame uses the IP
+        // of the physical frame. All other inlined frames use the InlineeStartOffset stored in their call info
+        // to calculate the byte code offset of the callsite of the inlinee they called.
+
+        StatementData data;
+        uint32 inlineeOffset = 0;
+        *inlinee = InlinedFramesBeingWalked() ? inlinedFrameWalker.GetFunctionObject()->GetFunctionBody() : nullptr;
 
-            if (function->GetFunctionBody() && function->GetFunctionBody()->GetMatchingStatementMapFromNativeAddress(pCodeAddr, data, loopNum, inlinee))
+        InlinedFrameWalker  tmpFrameWalker;
+        if (InlinedFramesBeingWalked())
+        {
+            // Inlined frames are being walked right now. The top most frame is where the IP is.
+            if (!inlinedFrameWalker.IsTopMostFrame())
             {
-                return data.bytecodeBegin;
+                inlineeOffset = inlinedFrameWalker.GetCurrentInlineeOffset();
             }
-#endif
+        }
+        else if (ScriptFunction::Is(function) && HasInlinedFramesOnStack())
+        {
+            // Inlined frames are not being walked right now. However, if there
+            // are inlined frames on the stack the InlineeCallInfo of the first inlined frame
+            // has the native offset of the current physical frame.
+            Assert(!*inlinee);
+            InlinedFrameWalker::FromPhysicalFrame(tmpFrameWalker, currentFrame, ScriptFunction::FromVar(function), previousInterpreterFrameIsFromBailout, loopNum, this);
+            inlineeOffset = tmpFrameWalker.GetBottomMostInlineeOffset();
+            tmpFrameWalker.Close();
+        }
+
+        if (inlineeOffset != 0 && 
+            this->GetCurrentFunctionFromPhysicalFrame()->GetFunctionBody()->GetMatchingStatementMapFromNativeOffset(pCodeAddr, inlineeOffset, data, loopNum, *inlinee))
+        {
+            offset = data.bytecodeBegin;
+            return true;
+        }
+
+        return false;
+    }
+
+    bool JavascriptStackWalker::InlinedFramesBeingWalked() const
+    {
+        if (lastInternalFrameInfo.codeAddress)
+        {
+            return false;
         }
 
-        return 0;
+        return inlinedFramesBeingWalked;
     }
 
+    bool JavascriptStackWalker::HasInlinedFramesOnStack() const
+    {
+        if (lastInternalFrameInfo.codeAddress)
+        {
+            return lastInternalFrameInfo.hasInlinedFramesOnStack;
+        }
+
+        return this->hasInlinedFramesOnStack;
+    }
+#endif
 
     bool JavascriptStackWalker::GetSourcePosition(const WCHAR** sourceFileName, ULONG* line, LONG* column)
     {
@@ -471,59 +536,93 @@ namespace Js
             // In case we have a cross site thunk, update the script context
             Js::JavascriptFunction *function = this->GetCurrentFunction();
 
-            // We might've bailed out of an inlinee, so check if there were any inlinees.
-            if (this->interpreterFrame && (this->interpreterFrame->GetFlags() & InterpreterStackFrameFlags_FromBailOut))
+#if ENABLE_NATIVE_CODEGEN
+            bool isCurrentPhysicalFrameForLoopBody = this->IsCurrentPhysicalFrameForLoopBody();
+#endif
+            if (this->interpreterFrame)
             {
-                previousInterpreterFrameIsFromBailout = true;
 #if ENABLE_NATIVE_CODEGEN
-                bool isCurrentPhysicalFrameForLoopBody = this->IsCurrentPhysicalFrameForLoopBody();
-                Assert(!inlinedFramesBeingWalked);
-                if (includeInlineFrames)
+                if (lastInternalFrameInfo.codeAddress != nullptr)
                 {
-                    int loopNum = -1;
-                    if (isCurrentPhysicalFrameForLoopBody)
-                    {
-                        loopNum = this->tempInterpreterFrame->GetCurrentLoopNum();
-                    }
+                    this->previousInterpreterFrameIsForLoopBody = true;
+                }
+                else
+#endif
+                {
+                    this->previousInterpreterFrameIsForLoopBody = false;
+                }
 
-                    bool inlinedFramesOnStack = InlinedFrameWalker::FromPhysicalFrame(inlinedFrameWalker, currentFrame,
-                        ScriptFunction::FromVar(function), true /*fromBailout*/, loopNum, this);
-                    if (inlinedFramesOnStack)
+                // We might've bailed out of an inlinee, so check if there were any inlinees.
+                if (this->interpreterFrame->GetFlags() & InterpreterStackFrameFlags_FromBailOut)
+                {
+                    previousInterpreterFrameIsFromBailout = true;
+
+#if ENABLE_NATIVE_CODEGEN
+                    Assert(!inlinedFramesBeingWalked);
+                    if (includeInlineFrames)
                     {
-                        inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo);
-                        Assert(inlinedFramesBeingWalked);
-                        Assert(StackScriptFunction::GetCurrentFunctionObject(this->interpreterFrame->GetJavascriptFunction()) == inlinedFrameWalker.GetFunctionObject());
-                        // We're now back in the state where currentFrame == physical frame of the inliner, but
-                        // since interpreterFrame != null, we'll pick values from the interpreterFrame (the bailout
-                        // frame of the inliner). Set a flag to tell the stack walker that it needs to start from the
-                        // inlinee frames on the stack when Walk() is called.
+                        int loopNum = -1;
+                        if (isCurrentPhysicalFrameForLoopBody)
+                        {
+                            loopNum = this->tempInterpreterFrame->GetCurrentLoopNum();
+                        }
+
+                        bool hasInlinedFramesOnStack = InlinedFrameWalker::FromPhysicalFrame(inlinedFrameWalker, currentFrame,
+                            ScriptFunction::FromVar(function), true /*fromBailout*/, loopNum, this);
+                        if (hasInlinedFramesOnStack)
+                        {
+                            // We're now back in the state where currentFrame == physical frame of the inliner, but
+                            // since interpreterFrame != null, we'll pick values from the interpreterFrame (the bailout
+                            // frame of the inliner). Set a flag to tell the stack walker that it needs to start from the
+                            // inlinee frames on the stack when Walk() is called.
+                            this->inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo);
+                            this->hasInlinedFramesOnStack = hasInlinedFramesOnStack;
+                            Assert(inlinedFramesBeingWalked);
+                            Assert(StackScriptFunction::GetCurrentFunctionObject(this->interpreterFrame->GetJavascriptFunction()) == inlinedFrameWalker.GetFunctionObject());
+                        }
+                        else
+                        {
+                            Assert(!isCurrentPhysicalFrameForLoopBody);
+                        }
                     }
-                    else
+                    else if (isCurrentPhysicalFrameForLoopBody)
                     {
-                        Assert(!isCurrentPhysicalFrameForLoopBody);
+                        // Getting here is only possible when the current interpreterFrame is for a function which
+                        // encountered a bailout after getting inlined in a jitted loop body. If we are not including
+                        // inlined frames in the stack walk, we need to set the codeAddress on lastInternalFrameInfo,
+                        // which would have otherwise been set upon closing the inlinedFrameWalker, now.
+                        // Note that we already have an assert in CheckJavascriptFrame to ensure this.
+                        SetCachedInternalFrameInfo(InternalFrameType_LoopBody, false /*hasInlinedFramesOnStack*/);
                     }
+#else
+                    // How did we bail out when JIT was disabled?
+                    Assert(false);
+#endif
                 }
-                else if (isCurrentPhysicalFrameForLoopBody)
+                else
                 {
-                    // Getting here is only possible when the current interpreterFrame is for a function which
-                    // encountered a bailout after getting inlined in a jitted loop body. If we are not including
-                    // inlined frames in the stack walk, we need to set the codeAddress on lastInternalFrameInfo,
-                    // which would have otherwise been set upon closing the inlinedFrameWalker, now.
-                    // Note that we already have an assert in CheckJavascriptFrame to ensure this.
-                    SetCachedInternalFrameInfo(InternalFrameType_LoopBody, InternalFrameType_LoopBody);
+                    Assert(StackScriptFunction::GetCurrentFunctionObject(this->interpreterFrame->GetJavascriptFunction()) == function);
+                    previousInterpreterFrameIsFromBailout = false;
                 }
-#else
-                // How did we bail out when JIT was disabled?
-                Assert(false);
-#endif
             }
-            else
+            else if (!this->isNativeLibraryFrame)
             {
-                Assert(this->interpreterFrame == nullptr || StackScriptFunction::GetCurrentFunctionObject(this->interpreterFrame->GetJavascriptFunction()) == function);
-                if (this->interpreterFrame)
+#if ENABLE_NATIVE_CODEGEN
+                Assert(!HasInlinedFramesOnStack() || (includeInlineFrames && isCurrentPhysicalFrameForLoopBody));
+
+                if (!HasInlinedFramesOnStack() && includeInlineFrames)
                 {
-                    previousInterpreterFrameIsFromBailout = false;
+                    // Check whether there are inlined frames nested in this native frame. The corresponding check for
+                    // a jitted loop body frame should have been done in CheckJavascriptFrame
+                    Assert(lastInternalFrameInfo.codeAddress == nullptr);
+                    if (InlinedFrameWalker::FromPhysicalFrame(inlinedFrameWalker, currentFrame, ScriptFunction::FromVar(function)))
+                    {
+                        this->inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo);
+                        this->hasInlinedFramesOnStack = true;
+                        Assert(inlinedFramesBeingWalked);
+                    }
                 }
+#endif
             }
             this->scriptContext = function->GetScriptContext();
             return function;
@@ -539,7 +638,7 @@ namespace Js
     __declspec(noinline)
     JavascriptStackWalker::JavascriptStackWalker(ScriptContext * scriptContext, bool useEERContext, PVOID returnAddress, bool _forceFullWalk /*=false*/) :
         inlinedFrameCallInfo(CallFlags_None, 0), shouldDetectPartiallyInitializedInterpreterFrame(true), forceFullWalk(_forceFullWalk),
-        previousInterpreterFrameIsFromBailout(false), ehFramesBeingWalkedFromBailout(false)
+        previousInterpreterFrameIsFromBailout(false), previousInterpreterFrameIsForLoopBody(false), hasInlinedFramesOnStack(false)
     {
         if (scriptContext == NULL)
         {
@@ -590,14 +689,14 @@ namespace Js
         this->interpreterFrame = NULL;
 
 #if ENABLE_NATIVE_CODEGEN
+        if (lastInternalFrameInfo.codeAddress != nullptr && this->previousInterpreterFrameIsForLoopBody)
+        {
+            ClearCachedInternalFrameInfo();
+        }
+
         if (inlinedFramesBeingWalked)
         {
             Assert(includeInlineFrames);
-            if (this->lastInternalFrameInfo.frameConsumed)
-            {
-                ClearCachedInternalFrameInfo();
-            }
-
             inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo);
             if (!inlinedFramesBeingWalked)
             {
@@ -606,7 +705,7 @@ namespace Js
                 {
                     // Done walking inlined frames in a loop body, cache the native code address now
                     // in order to skip the loop body frame.
-                    this->SetCachedInternalFrameInfo(InternalFrameType_LoopBody, InternalFrameType_LoopBody);
+                    this->SetCachedInternalFrameInfo(InternalFrameType_LoopBody, true /*hasInlinedFramesOnStack*/);
                     isJavascriptFrame = false;
                 }
             }
@@ -614,7 +713,7 @@ namespace Js
             return true;
         }
 #endif
-
+        this->hasInlinedFramesOnStack = false;
         if (this->isInitialFrame)
         {
             this->isInitialFrame = false; // Only walk initial frame once
@@ -769,24 +868,19 @@ namespace Js
 
     bool JavascriptStackWalker::CheckJavascriptFrame(bool includeInlineFrames)
     {
-#if ENABLE_NATIVE_CODEGEN
-        if (this->lastInternalFrameInfo.frameConsumed)
-        {
-            ClearCachedInternalFrameInfo();
-        }
-#endif
-
         this->isNativeLibraryFrame = false; // Clear previous result
 
         void * codeAddr = this->currentFrame.GetInstructionPointer();
         if (this->tempInterpreterFrame && codeAddr == this->tempInterpreterFrame->GetReturnAddress())
         {
+            bool isBailoutInterpreter = (this->tempInterpreterFrame->GetFlags() & Js::InterpreterStackFrameFlags_FromBailOut) != 0;
+
             // We need to skip over the first interpreter frame on the stack if it is the partially initialized frame
             // otherwise it is a real frame and we should continue.
             // For fully initialized frames (PushPopHelper was called) the thunk stack addr is equal or below addressOfReturnAddress
             // as the latter one is obtained in InterpreterStackFrame::InterpreterThunk called by the thunk.
             bool isPartiallyInitializedFrame = this->shouldDetectPartiallyInitializedInterpreterFrame &&
-                this->currentFrame.GetAddressOfReturnAddress(false /*isCurrentContextNative*/, false /*shouldCheckForNativeAddr*/) < this->tempInterpreterFrame->GetAddressOfReturnAddress();
+                this->currentFrame.GetAddressOfReturnAddress(isBailoutInterpreter /*isCurrentContextNative*/, false /*shouldCheckForNativeAddr*/) < this->tempInterpreterFrame->GetAddressOfReturnAddress();
             this->shouldDetectPartiallyInitializedInterpreterFrame = false;
 
             if (isPartiallyInitializedFrame)
@@ -794,20 +888,13 @@ namespace Js
                 return false; // Skip it.
             }
 
-            void ** argv = this->currentFrame.GetArgv(false /*isCurrentContextNative*/, false /*shouldCheckForNativeAddr*/);
+            void ** argv = this->currentFrame.GetArgv(isBailoutInterpreter /*isCurrentContextNative*/, false /*shouldCheckForNativeAddr*/);
             if (argv == nullptr)
             {
                 // NOTE: When we switch to walking the stack ourselves and skip non engine frames, this should never happen.
                 return false;
             }
 
-#if defined(_M_AMD64)
-            if (argv[JavascriptFunctionArgIndex_Function] == amd64_ReturnFromCallWithFakeFrame)
-            {
-                this->ehFramesBeingWalkedFromBailout = true;
-                return false;
-            }
-#endif
             this->interpreterFrame = this->tempInterpreterFrame;
 
             this->tempInterpreterFrame = this->interpreterFrame->GetPreviousFrame();
@@ -826,16 +913,6 @@ namespace Js
                 tmpFrameWalker.Close();
             }
 #endif //DBG
-
-            if (!this->interpreterFrame->IsCurrentLoopNativeAddr(this->lastInternalFrameInfo.codeAddress))
-            {
-                ClearCachedInternalFrameInfo();
-            }
-            else
-            {
-                Assert(this->lastInternalFrameInfo.codeAddress);
-                this->lastInternalFrameInfo.frameConsumed = true;
-            }
 #endif //ENABLE_NATIVE_CODEGEN
 
             return true;
@@ -867,18 +944,6 @@ namespace Js
                 return false;
             }
 
-#if defined(_M_AMD64)
-            if (argv[JavascriptFunctionArgIndex_Function] == amd64_ReturnFromCallWithFakeFrame)
-            {
-                // There could be nested internal frames in the case of try...catch..finally
-                // let's not set the last internal frame address if it has already been set.
-                if(!this->lastInternalFrameInfo.codeAddress && !this->ehFramesBeingWalkedFromBailout)
-                {
-                    SetCachedInternalFrameInfo(InternalFrameType_EhFrame, InternalFrameType_None);
-                }
-                return false;
-            }
-#endif
             ScriptFunction* funcObj = Js::ScriptFunction::FromVar(argv[JavascriptFunctionArgIndex_Function]);
             if (funcObj->GetFunctionBody()->GetIsAsmjsMode())
             {
@@ -893,45 +958,16 @@ namespace Js
                         false /*fromBailout*/, this->tempInterpreterFrame->GetCurrentLoopNum(), this))
                 {
                     // Found inlined frames in a jitted loop body. We dont want to skip the inlined frames; walk all of them before setting codeAddress on lastInternalFrameInfo.
-                    inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo);
+                    this->inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo);
+                    this->hasInlinedFramesOnStack = true;
                     Assert(inlinedFramesBeingWalked);
                     return true;
                 }
 
-                SetCachedInternalFrameInfo(InternalFrameType_LoopBody, InternalFrameType_LoopBody);
+                SetCachedInternalFrameInfo(InternalFrameType_LoopBody, false /*hasInlinedFramesOnStack*/);
                 return false;
             }
 
-            if (this->lastInternalFrameInfo.codeAddress)
-            {
-                this->lastInternalFrameInfo.frameConsumed = true;
-            }
-
-            if (includeInlineFrames &&
-                InlinedFrameWalker::FromPhysicalFrame(inlinedFrameWalker, currentFrame, Js::ScriptFunction::FromVar(argv[JavascriptFunctionArgIndex_Function])))
-            {
-                inlinedFramesBeingWalked = inlinedFrameWalker.Next(inlinedFrameCallInfo);
-                Assert(inlinedFramesBeingWalked);
-            }
-
-            if (this->ehFramesBeingWalkedFromBailout)
-            {
-                AnalysisAssert(this->tempInterpreterFrame != nullptr);
-                this->interpreterFrame = this->tempInterpreterFrame;
-                this->tempInterpreterFrame = this->tempInterpreterFrame->GetPreviousFrame();
-
-                if (!this->interpreterFrame->IsCurrentLoopNativeAddr(this->lastInternalFrameInfo.codeAddress))
-                {
-                    ClearCachedInternalFrameInfo();
-                }
-                else
-                {
-                    Assert(this->lastInternalFrameInfo.codeAddress);
-                    this->lastInternalFrameInfo.frameConsumed = true;
-                }
-                this->ehFramesBeingWalkedFromBailout = false;
-            }
-
             return true;
         }
 #endif
@@ -1035,13 +1071,12 @@ namespace Js
         this->lastInternalFrameInfo.Clear();
     }
 
-    void JavascriptStackWalker::SetCachedInternalFrameInfo(InternalFrameType frameType, InternalFrameType loopBodyFrameType)
+    void JavascriptStackWalker::SetCachedInternalFrameInfo(InternalFrameType frameType, bool hasInlinedFramesOnStack)
     {
         if (!this->lastInternalFrameInfo.codeAddress)
         {
-            this->lastInternalFrameInfo.Set(this->GetCurrentCodeAddr(), this->currentFrame.GetFrame(), this->currentFrame.GetStackCheckCodeHeight(), frameType, loopBodyFrameType);
+            this->lastInternalFrameInfo.Set(this->GetCurrentCodeAddr(), this->currentFrame.GetFrame(), this->currentFrame.GetStackCheckCodeHeight(), frameType, hasInlinedFramesOnStack);
         }
-        this->lastInternalFrameInfo.loopBodyFrameType = loopBodyFrameType;
     }
 #endif
 
@@ -1391,7 +1426,7 @@ namespace Js
         return inlinedFrame;
     }
 
-    void InternalFrameInfo::Set(void *codeAddress, void *framePointer, size_t stackCheckCodeHeight, InternalFrameType frameType, InternalFrameType loopBodyFrameType)
+    void InternalFrameInfo::Set(void *codeAddress, void *framePointer, size_t stackCheckCodeHeight, InternalFrameType frameType, bool hasInlinedFramesOnStack)
     {
         // We skip a jitted loop body's native frame when walking the stack and refer to the loop body's interpreter frame to get the function. 
         // However, if the loop body has inlinees, to retrieve inlinee frames we need to cache some info about the loop body's native frame.
@@ -1399,8 +1434,7 @@ namespace Js
         this->framePointer = framePointer;
         this->stackCheckCodeHeight = stackCheckCodeHeight;
         this->frameType = frameType;
-        this->loopBodyFrameType = loopBodyFrameType;
-        this->frameConsumed = false;
+        this->hasInlinedFramesOnStack = hasInlinedFramesOnStack;
     }
 
     void InternalFrameInfo::Clear()
@@ -1409,8 +1443,7 @@ namespace Js
         this->framePointer = nullptr;
         this->stackCheckCodeHeight = (uint)-1;
         this->frameType = InternalFrameType_None;
-        this->loopBodyFrameType = InternalFrameType_None;
-        this->frameConsumed = false;
+        this->hasInlinedFramesOnStack = false;
     }
 #endif
 

+ 19 - 14
lib/Runtime/Language/JavascriptStackWalker.h

@@ -152,21 +152,19 @@ namespace Js
         void *framePointer;
         size_t stackCheckCodeHeight;
         InternalFrameType frameType;
-        InternalFrameType loopBodyFrameType;
-        bool frameConsumed;
+        bool hasInlinedFramesOnStack;
 
         InternalFrameInfo() :
             codeAddress(nullptr),
             framePointer(nullptr),
             stackCheckCodeHeight((uint)-1),
             frameType(InternalFrameType_None),
-            loopBodyFrameType(InternalFrameType_None),
-            frameConsumed(false)
+            hasInlinedFramesOnStack(false)
         {
         }
 
         void Clear();
-        void Set(void *codeAddress, void *framePointer, size_t stackCheckCodeHeight, InternalFrameType frameType, InternalFrameType loopBodyFrameType);
+        void Set(void *codeAddress, void *framePointer, size_t stackCheckCodeHeight, InternalFrameType frameType, bool hasInlinedFramesOnStack);
     };
 #endif
 
@@ -228,7 +226,7 @@ namespace Js
 
 #if ENABLE_NATIVE_CODEGEN
         void ClearCachedInternalFrameInfo();
-        void SetCachedInternalFrameInfo(InternalFrameType frameType, InternalFrameType loopBodyFrameType);
+        void SetCachedInternalFrameInfo(InternalFrameType frameType, bool hasInlinedFramesOnStack);
         InternalFrameInfo GetCachedInternalFrameInfo() const { return this->lastInternalFrameInfo; }
 #endif
         bool IsCurrentPhysicalFrameForLoopBody() const;
@@ -317,20 +315,27 @@ namespace Js
 #endif
         CallInfo                inlinedFrameCallInfo;
         bool                    inlinedFramesBeingWalked    : 1;
+        bool                    hasInlinedFramesOnStack     : 1;
         bool                    isJavascriptFrame           : 1;
         bool                    isNativeLibraryFrame        : 1;
         bool                    isInitialFrame              : 1; // If we need to walk the initial frame
         bool                    shouldDetectPartiallyInitializedInterpreterFrame : 1;
         bool                    previousInterpreterFrameIsFromBailout : 1;
-        bool                    ehFramesBeingWalkedFromBailout : 1;
-        bool                    forceFullWalk; // ignoring hasCaller
-
-        Var GetThisFromFrame() const;
-        Var GetCurrentArgumentsObject() const;
-        void SetCurrentArgumentsObject(Var args);
-        Var GetCurrentNativeArgumentsObject() const;
-        void SetCurrentNativeArgumentsObject(Var args);
+        bool                    previousInterpreterFrameIsForLoopBody : 1;
+        bool                    forceFullWalk               : 1; // ignoring hasCaller
+
+        Var GetThisFromFrame() const;                   // returns 'this' object from the physical frame
+        Var GetCurrentArgumentsObject() const;          // returns arguments object from the current frame, which may be virtual (belonging to an inlinee)
+        void SetCurrentArgumentsObject(Var args);       // sets arguments object for the current frame, which may be virtual (belonging to an inlinee)
+        Var GetCurrentNativeArgumentsObject() const;    // returns arguments object from the physical native frame
+        void SetCurrentNativeArgumentsObject(Var args); // sets arguments object on the physical native frame
+        bool TryGetByteCodeOffsetFromInterpreterFrame(uint32& offset) const;
 #if ENABLE_NATIVE_CODEGEN
+        bool TryGetByteCodeOffsetFromNativeFrame(uint32& offset) const;
+        bool TryGetByteCodeOffsetOfInlinee(Js::JavascriptFunction* function, uint loopNum, DWORD_PTR pCodeAddr, Js::FunctionBody** inlinee, uint32& offset) const;
+        uint GetLoopNumber() const;
+        bool InlinedFramesBeingWalked() const;
+        bool HasInlinedFramesOnStack() const;
         InternalFrameInfo lastInternalFrameInfo;
 #endif
         mutable StackFrame currentFrame;

+ 18 - 0
lib/Runtime/Language/ProfilingHelpers.cpp

@@ -1076,6 +1076,10 @@ namespace Js
                     &operationInfo,
                     &propertyValueInfo))
             {
+                ThreadContext* threadContext = scriptContext->GetThreadContext();
+                ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
+                threadContext->ClearImplicitCallFlags();
+
                 Type *const oldType = object->GetType();
 
                 if (Root)
@@ -1091,6 +1095,20 @@ namespace Js
                     oldType,
                     &operationInfo,
                     &propertyValueInfo);
+
+                // Setting to __proto__ property invokes a setter and changes the prototype.So, although PatchPut* populates the cache,
+                // the setter invalidates it (since it changes the prototype). PretendTrySetProperty looks at the inline cache type to
+                // update the cacheType on PropertyOperationInfo, which is used in populating the field info flags for this operation on
+                // the profile. Since the cache was invalidated, we dont get a match with either the type of the object with property or
+                // without it and the cacheType defaults to CacheType_None. This leads the profile info to say that this operation doesn't
+                // cause an accessor implicit call and JIT then doesn't kill live fields accross it and ends up putting a BailOutOnImplicitCalls
+                // if there were live fields. This bailout always bails out.
+                    Js::ImplicitCallFlags accessorCallFlag = (Js::ImplicitCallFlags)(Js::ImplicitCall_Accessor & ~Js::ImplicitCall_None);
+                if ((threadContext->GetImplicitCallFlags() & accessorCallFlag) != 0)
+                {
+                    operationInfo.cacheType = CacheType_Setter;
+                }
+                threadContext->SetImplicitCallFlags((Js::ImplicitCallFlags)(savedImplicitCallFlags | threadContext->GetImplicitCallFlags()));
             }
 
             // Only make the field polymorphic if we are not using the root object inline cache

+ 8 - 0
lib/Runtime/Language/ReadOnlyDynamicProfileInfo.h

@@ -49,6 +49,7 @@ namespace Js
             isEquivalentObjTypeSpecDisabled(false),
             isObjTypeSpecDisabled_jitLoopBody(false),
             isPowIntIntTypeSpecDisabled(false),
+            isLoopImplicitCallInfoDisabled(false),
             ldElemInfo(nullptr),
             stElemInfo(nullptr)
         {
@@ -87,6 +88,7 @@ namespace Js
             this->isEquivalentObjTypeSpecDisabled = profileInfo->IsEquivalentObjTypeSpecDisabled();
             this->isObjTypeSpecDisabled_jitLoopBody = profileInfo->IsObjTypeSpecDisabledInJitLoopBody();
             this->isPowIntIntTypeSpecDisabled = profileInfo->IsPowIntIntTypeSpecDisabled();
+			this->isLoopImplicitCallInfoDisabled = profileInfo->IsLoopImplicitCallInfoDisabled();
         }
 
         void OnBackgroundAllocatorReset()
@@ -347,6 +349,11 @@ namespace Js
             return this->isPowIntIntTypeSpecDisabled;
         }
 
+        bool IsLoopImplicitCallInfoDisabled() const
+        {
+            return this->isLoopImplicitCallInfoDisabled;
+        }
+
     private:
         const DynamicProfileInfo * profileInfo;
         ArenaAllocator *const backgroundAllocator; // null if the work item is being jitted in the foreground
@@ -383,6 +390,7 @@ namespace Js
         bool isEquivalentObjTypeSpecDisabled : 1;
         bool isObjTypeSpecDisabled_jitLoopBody : 1;
         bool isPowIntIntTypeSpecDisabled : 1;
+        bool isLoopImplicitCallInfoDisabled : 1;
         const LdElemInfo *ldElemInfo;
         const StElemInfo *stElemInfo;
 

+ 0 - 43
lib/Runtime/Language/SimdFloat32x4Operation.cpp

@@ -215,11 +215,6 @@ namespace Js
     Min/Max(a, b) spec semantics:
     If any value is NaN, return NaN
     a < b ? a : b; where +0.0 > -0.0 (vice versa for Max)
-
-    MinNum/MaxNum(a, b) spec semantics:
-    If 1st value is NaN, return 2nd
-    If 2nd value is NaN, return 1st
-    return Min/Max(a, b)
     */
     SIMDValue SIMDFloat32x4Operation::OpMin(const SIMDValue& aValue, const SIMDValue& bValue)
     {
@@ -283,44 +278,6 @@ namespace Js
         return result;
     }
 
-    SIMDValue SIMDFloat32x4Operation::OpMinNum(const SIMDValue& aValue, const SIMDValue& bValue)
-    {
-        SIMDValue result = OpMin(aValue, bValue);
-        for (uint i = 0; i < 4; i++)
-        {
-            float a = aValue.f32[i];
-            float b = bValue.f32[i];
-            if (Js::NumberUtilities::IsNan(a))
-            {
-                result.f32[i] = b;
-            }
-            else if (Js::NumberUtilities::IsNan(b))
-            {
-                result.f32[i] = a;
-            }
-        }
-        return result;
-    }
-
-    SIMDValue SIMDFloat32x4Operation::OpMaxNum(const SIMDValue& aValue, const SIMDValue& bValue)
-    {
-        SIMDValue result = OpMax(aValue, bValue);
-        for (uint i = 0; i < 4; i++)
-        {
-            float a = aValue.f32[i];
-            float b = bValue.f32[i];
-            if (Js::NumberUtilities::IsNan(a))
-            {
-                result.f32[i] = b;
-            }
-            else if (Js::NumberUtilities::IsNan(b))
-            {
-                result.f32[i] = a;
-            }
-        }
-        return result;
-    }
-
     SIMDValue SIMDFloat32x4Operation::OpScale(const SIMDValue& Value, float scaleValue)
     {
         SIMDValue result;

+ 0 - 4
lib/Runtime/Language/SimdFloat32x4Operation.h

@@ -40,10 +40,6 @@ namespace Js {
         static SIMDValue OpXor(const SIMDValue& aValue, const SIMDValue& bValue);
         static SIMDValue OpMin(const SIMDValue& aValue, const SIMDValue& bValue);
         static SIMDValue OpMax(const SIMDValue& aValue, const SIMDValue& bValue);
-        static SIMDValue OpMinNum(const SIMDValue& aValue, const SIMDValue& bValue);
-        static SIMDValue OpMaxNum(const SIMDValue& aValue, const SIMDValue& bValue);
-
-
         static SIMDValue OpScale(const SIMDValue& Value, float scaleValue);
 
         static SIMDValue OpLessThan(const SIMDValue& aValue, const SIMDValue& bValue);

+ 0 - 58
lib/Runtime/Language/SimdFloat32x4OperationX86X64.cpp

@@ -221,11 +221,6 @@ namespace Js
     If any value is NaN, return NaN
     a < b ? a : b; where +0.0 > -0.0 (vice versa for Max)
 
-    MinNum/MaxNum(a, b) spec semantics:
-    If 1st value is NaN, return 2nd
-    If 2nd value is NaN, return 1st
-    return Min/Max(a, b)
-
     X86 MIN/MAXPS semantics:
     If any value is NaN, return 2nd operand
     If both values are +/-0.0, return 2nd operand
@@ -273,59 +268,6 @@ namespace Js
         return X86SIMDValue::ToSIMDValue(x86Result);
     }
 
-
-    SIMDValue SIMDFloat32x4Operation::OpMinNum(const SIMDValue& aValue, const SIMDValue& bValue)
-    {
-        X86SIMDValue x86Result;
-        X86SIMDValue tmpaValue = X86SIMDValue::ToX86SIMDValue(aValue);
-        X86SIMDValue tmpbValue = X86SIMDValue::ToX86SIMDValue(bValue);
-        X86SIMDValue mask, mask2, t1, t2;
-
-        // This is the correct result or b if either is NaN or both are +/-0.0
-        x86Result.m128_value = _mm_min_ps(tmpaValue.m128_value, tmpbValue.m128_value);
-        // Find NaNs in b
-        mask.m128_value  = _mm_cmpunord_ps(tmpbValue.m128_value, tmpbValue.m128_value);
-        // Find -0.0 in a
-        mask2.m128i_value = _mm_cmpeq_epi32(tmpaValue.m128i_value, X86_TWO_31_I4.m128i_value);
-        // mask2 is -0.0 where a is -0.0
-        mask2.m128_value = _mm_and_ps(mask2.m128_value, X86_TWO_31_I4.m128_value);
-        // For lanes where a is -0.0, the result is either correct (negative), or b which is possibly +0.0
-        // Safe to force sign to negative for those lanes, +0.0 becomes -0.0.
-        x86Result.m128_value = _mm_or_ps(x86Result.m128_value, mask2.m128_value);
-        // For NaNs in b, choose a, else keep result.
-        t1.m128_value = _mm_and_ps(tmpaValue.m128_value, mask.m128_value);
-        t2.m128_value = _mm_andnot_ps(mask.m128_value, x86Result.m128_value);
-        x86Result.m128_value = _mm_or_ps(t1.m128_value, t2.m128_value);
-
-        return X86SIMDValue::ToSIMDValue(x86Result);
-    }
-
-    SIMDValue SIMDFloat32x4Operation::OpMaxNum(const SIMDValue& aValue, const SIMDValue& bValue)
-    {
-        X86SIMDValue x86Result;
-        X86SIMDValue tmpaValue = X86SIMDValue::ToX86SIMDValue(aValue);
-        X86SIMDValue tmpbValue = X86SIMDValue::ToX86SIMDValue(bValue);
-        X86SIMDValue mask, mask2, t1, t2;
-
-        // This is the correct result or b if either is NaN or both are +/-0.0
-        x86Result.m128_value = _mm_max_ps(tmpaValue.m128_value, tmpbValue.m128_value);
-        // Find NaNs in b
-        mask.m128_value = _mm_cmpunord_ps(tmpbValue.m128_value, tmpbValue.m128_value);
-        // Find +0.0 in a
-        mask2.m128i_value = _mm_cmpeq_epi32(tmpaValue.m128i_value, X86_ALL_ZEROS.m128i_value);
-        // mask2 is -0.0 where a is +0.0
-        mask2.m128_value = _mm_and_ps(mask2.m128_value, X86_TWO_31_I4.m128_value);
-        // For lanes where a is +0.0, the result is either correct (positive), or b which is possibly -0.0
-        // Safe to force sign to positive for those lanes, +0.0 becomes -0.0.
-        x86Result.m128_value = _mm_andnot_ps(mask2.m128_value, x86Result.m128_value);
-        // For NaNs in b, choose a, else keep result.
-        t1.m128_value = _mm_and_ps(tmpaValue.m128_value, mask.m128_value);
-        t2.m128_value = _mm_andnot_ps(mask.m128_value, x86Result.m128_value);
-        x86Result.m128_value = _mm_or_ps(t1.m128_value, t2.m128_value);
-
-        return X86SIMDValue::ToSIMDValue(x86Result);
-    }
-
     SIMDValue SIMDFloat32x4Operation::OpScale(const SIMDValue& Value, float scaleValue)
     {
         X86SIMDValue x86Result;

+ 0 - 1
lib/Runtime/Language/amd64/JavascriptOperatorsA.asm

@@ -28,7 +28,6 @@ amd64_CallWithFakeFrame PROC
 
 chkstk_done:
         ;; The stack walker uses this marker to skip this frame.
-        lea rax, amd64_ReturnFromCallWithFakeFrame
         mov [rsp+8h], rax
 
         mov rax, [rsp + 28h]

+ 5 - 0
lib/Runtime/Library/ConcatString.cpp

@@ -120,7 +120,12 @@ namespace Js
     /////////////////////// ConcatStringBuilder //////////////////////////
 
     // MAX number of slots in one chunk. Until we fit into this, we realloc, otherwise create new chunk.
+    // The VS2013 linker treats this as a redefinition of an already
+    // defined constant and complains. So skip the declaration if we're compiling
+    // with VS2013 or below.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
     const int ConcatStringBuilder::c_maxChunkSlotCount;
+#endif
 
     ConcatStringBuilder::ConcatStringBuilder(ScriptContext* scriptContext, int initialSlotCount) :
         ConcatStringBase(scriptContext->GetLibrary()->GetStringTypeStatic()),

Diferenças do arquivo suprimidas por serem muito extensas
+ 293 - 293
lib/Runtime/Library/InJavascript/Intl.js.bc.32b.h


Diferenças do arquivo suprimidas por serem muito extensas
+ 293 - 293
lib/Runtime/Library/InJavascript/Intl.js.bc.64b.h


Diferenças do arquivo suprimidas por serem muito extensas
+ 291 - 291
lib/Runtime/Library/InJavascript/Intl.js.nojit.bc.32b.h


Diferenças do arquivo suprimidas por serem muito extensas
+ 291 - 291
lib/Runtime/Library/InJavascript/Intl.js.nojit.bc.64b.h


+ 9 - 9
lib/Runtime/Library/JSONParser.cpp

@@ -35,7 +35,7 @@ namespace JSON
         Js::Var ret = ParseObject();
         if (m_token.tk != tkEOF)
         {
-            Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRsyntax);
+            m_scanner.ThrowSyntaxError(JSERR_JsonSyntax);
         }
         return ret;
     }
@@ -232,7 +232,7 @@ namespace JSON
             }
             else
             {
-                Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRbadNumber);
+                m_scanner.ThrowSyntaxError(JSERR_JsonBadNumber);
             }
 
         case tkLBrack:
@@ -260,11 +260,11 @@ namespace JSON
                     Scan();
                     if(tkRBrack == m_token.tk)
                     {
-                        Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRillegalChar);
+                        m_scanner.ThrowSyntaxError(JSERR_JsonIllegalChar);
                     }
                 }
                 //check and consume the ending ']'
-                CheckCurrentToken(tkRBrack, ERRnoRbrack);
+                CheckCurrentToken(tkRBrack, JSERR_JsonNoRbrack);
                 return arrayObj;
 
             }
@@ -311,7 +311,7 @@ namespace JSON
                     //pick "name"
                     if(tkStrCon != m_token.tk)
                     {
-                        Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRsyntax);
+                        m_scanner.ThrowSyntaxError(JSERR_JsonIllegalChar);
                     }
 
                     // currentStrLength = length w/o null-termination
@@ -332,7 +332,7 @@ namespace JSON
                             //check and consume ":"
                             if(Scan() != tkColon )
                             {
-                                Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRnoColon);
+                                m_scanner.ThrowSyntaxError(JSERR_JsonNoColon);
                             }
                             Scan();
 
@@ -365,7 +365,7 @@ namespace JSON
                     //check and consume ":"
                     if(Scan() != tkColon )
                     {
-                        Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRnoColon);
+                        m_scanner.ThrowSyntaxError(JSERR_JsonNoColon);
                     }
                     Scan();
                     Js::Var value = ParseObject();
@@ -404,12 +404,12 @@ namespace JSON
                 }
 
                 // check  and consume the ending '}"
-                CheckCurrentToken(tkRCurly, ERRnoRcurly);
+                CheckCurrentToken(tkRCurly, JSERR_JsonNoRcurly);
                 return object;
             }
 
         default:
-            Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRsyntax);
+            m_scanner.ThrowSyntaxError(JSERR_JsonSyntax);
         }
     }
 } // namespace JSON

+ 1 - 1
lib/Runtime/Library/JSONParser.h

@@ -70,7 +70,7 @@ namespace JSON
         void CheckCurrentToken(int tk, int wErr)
         {
             if (m_token.tk != tk)
-                Js::JavascriptError::ThrowSyntaxError(scriptContext, wErr);
+                m_scanner.ThrowSyntaxError(wErr);
             Scan();
         }
 

+ 17 - 17
lib/Runtime/Library/JSONScanner.cpp

@@ -82,7 +82,7 @@ namespace JSON
                     const char16* saveCurrentChar = currentChar;
                     if(!IsJSONNumber())
                     {
-                        Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRbadNumber);
+                       ThrowSyntaxError(JSERR_JsonBadNumber);
                     }
                     currentChar = saveCurrentChar;
                     double val;
@@ -90,7 +90,7 @@ namespace JSON
                     val = Js::NumberUtilities::StrToDbl(currentChar, &end, scriptContext);
                     if(currentChar == end)
                     {
-                        Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRbadNumber);
+                       ThrowSyntaxError(JSERR_JsonBadNumber);
                     }
                     AssertMsg(!Js::JavascriptNumber::IsNan(val), "Bad result from string to double conversion");
                     pToken->tk = tkFltCon;
@@ -121,7 +121,7 @@ namespace JSON
                     currentChar += 3;
                     return (pToken->tk = tkNULL);
                 }
-                Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRillegalChar);
+               ThrowSyntaxError(JSERR_JsonIllegalChar);
 
             case 't':
                 //check for 'true'
@@ -130,7 +130,7 @@ namespace JSON
                     currentChar += 3;
                     return (pToken->tk = tkTRUE);
                 }
-                Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRillegalChar);
+               ThrowSyntaxError(JSERR_JsonIllegalChar);
 
             case 'f':
                 //check for 'false'
@@ -139,7 +139,7 @@ namespace JSON
                     currentChar += 4;
                     return (pToken->tk = tkFALSE);
                 }
-                Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRillegalChar);
+               ThrowSyntaxError(JSERR_JsonIllegalChar);
 
             case '{':
                 return (pToken->tk = tkLCurly);
@@ -148,7 +148,7 @@ namespace JSON
                 return (pToken->tk = tkRCurly);
 
             default:
-                Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRillegalChar);
+               ThrowSyntaxError(JSERR_JsonIllegalChar);
             }
 
         }
@@ -245,12 +245,12 @@ namespace JSON
             else if (ch <= 0x1F)
             {
                 //JSON doesn't accept \u0000 - \u001f range, LS(\u2028) and PS(\u2029) are ok
-                Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRillegalChar);
+               ThrowSyntaxError(JSERR_JsonIllegalChar);
             }
             else if ( 0 == ch )
             {
                 currentChar--;
-                Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRnoStrEnd);
+               ThrowSyntaxError(JSERR_JsonNoStrEnd);
             }
             else if ('\\' == ch)
             {
@@ -258,7 +258,7 @@ namespace JSON
                 // unlikely V5.8 regular chars are not escaped, i.e '\g'' in a string is illegal not 'g'
                 if (currentChar >= inputText + inputLen )
                 {
-                    Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRnoStrEnd);
+                   ThrowSyntaxError(JSERR_JsonNoStrEnd);
                 }
 
                 ch = ReadNextChar();
@@ -266,7 +266,7 @@ namespace JSON
                 {
                 case 0:
                     currentChar--;
-                    Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRnoStrEnd);
+                   ThrowSyntaxError(JSERR_JsonNoStrEnd);
 
                 case '"':
                 case '/':
@@ -301,30 +301,30 @@ namespace JSON
                         if (currentChar + 3 >= inputText + inputLen)
                         {
                             //no room left for 4 hex chars
-                            Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRnoStrEnd);
+                           ThrowSyntaxError(JSERR_JsonNoStrEnd);
 
                         }
                         if (!Js::NumberUtilities::FHexDigit((WCHAR)ReadNextChar(), &tempHex))
                         {
-                            Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRbadHexDigit);
+                           ThrowSyntaxError(JSERR_JsonBadHexDigit);
                         }
                         chcode = tempHex * 0x1000;
 
                         if (!Js::NumberUtilities::FHexDigit((WCHAR)ReadNextChar(), &tempHex))
                         {
-                            Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRbadHexDigit);
+                           ThrowSyntaxError(JSERR_JsonBadHexDigit);
                         }
                         chcode += tempHex * 0x0100;
 
                         if (!Js::NumberUtilities::FHexDigit((WCHAR)ReadNextChar(), &tempHex))
                         {
-                            Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRbadHexDigit);
+                           ThrowSyntaxError(JSERR_JsonBadHexDigit);
                         }
                         chcode += tempHex * 0x0010;
 
                         if (!Js::NumberUtilities::FHexDigit((WCHAR)ReadNextChar(), &tempHex))
                         {
-                            Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRbadHexDigit);
+                           ThrowSyntaxError(JSERR_JsonBadHexDigit);
                         }
                         chcode += tempHex;
                         AssertMsg(chcode == (chcode & 0xFFFF), "Bad unicode code");
@@ -334,7 +334,7 @@ namespace JSON
 
                 default:
                     // Any other '\o' is an error in JSON
-                    Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRillegalChar);
+                   ThrowSyntaxError(JSERR_JsonIllegalChar);
                 }
 
                 // flush
@@ -367,7 +367,7 @@ namespace JSON
         if (!endFound)
         {
             // no ending '"' found
-            Js::JavascriptError::ThrowSyntaxError(scriptContext, ERRnoStrEnd);
+           ThrowSyntaxError(JSERR_JsonNoStrEnd);
         }
 
         if (isStringDirectInputTextMapped == false)

+ 9 - 2
lib/Runtime/Library/JSONScanner.h

@@ -20,9 +20,16 @@ namespace JSON
             ::Js::ScriptContext* sc, const char16* current, ArenaAllocator* allocator);
 
         void Finalizer();
-        char16* GetCurrentString(){return currentString;}
-        uint GetCurrentStringLen(){return currentIndex;}
+        char16* GetCurrentString() { return currentString; } 
+        uint GetCurrentStringLen() { return currentIndex; }
+        uint GetScanPosition() { return uint(currentChar - inputText); }
 
+        void __declspec(noreturn) ThrowSyntaxError(int wErr)
+        {
+            char16 scanPos[16];
+            ::_itow_s(GetScanPosition(), scanPos, _countof(scanPos) / sizeof(char16), 10);
+            Js::JavascriptError::ThrowSyntaxError(scriptContext, wErr, scanPos);
+        }
 
     private:
 

+ 34 - 25
lib/Runtime/Library/JavascriptArray.cpp

@@ -8998,13 +8998,9 @@ Case0:
             JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NullOrUndefined, _u("Array.prototype.filter"));
         }
 
-        RecyclableObject* newObj = nullptr;
-        JavascriptArray* newArr = nullptr;
         BigIndex length;
         JavascriptArray* pArr = nullptr;
         RecyclableObject* dynamicObject = nullptr;
-        RecyclableObject* callBackFn = nullptr;
-        Var thisArg = nullptr;
 
         if (JavascriptArray::Is(args[0]) && !JavascriptArray::FromVar(args[0])->IsCrossSiteObject())
         {
@@ -9038,11 +9034,23 @@ Case0:
             length = pArr->length;
         }
 
+        if (length.IsSmallIndex())
+        {
+            return JavascriptArray::FilterHelper(pArr, dynamicObject, length.GetSmallIndex(), args, scriptContext);
+        }
+        return JavascriptArray::FilterHelper(pArr, dynamicObject, length.GetBigIndex(), args, scriptContext);
+    }
+
+    template <typename T>
+    Var JavascriptArray::FilterHelper(JavascriptArray* pArr, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext)
+    {
         if (args.Info.Count < 2 || !JavascriptConversion::IsCallable(args[1]))
         {
             JavascriptError::ThrowTypeError(scriptContext, JSERR_FunctionArgument_NeedFunction, _u("Array.prototype.filter"));
         }
-        callBackFn = RecyclableObject::FromVar(args[1]);
+
+        RecyclableObject* callBackFn = RecyclableObject::FromVar(args[1]);
+        Var thisArg = nullptr;
 
         if (args.Info.Count > 2)
         {
@@ -9054,7 +9062,8 @@ Case0:
         }
 
         // If the source object is an Array exotic object we should try to load the constructor property and use it to construct the return object.
-        newObj = ArraySpeciesCreate(dynamicObject, 0, scriptContext);
+        RecyclableObject* newObj = ArraySpeciesCreate(obj, 0, scriptContext);
+        JavascriptArray* newArr = nullptr;
 
         if (newObj == nullptr)
         {
@@ -9071,28 +9080,26 @@ Case0:
             }
         }
 
-        // The correct flag value is CallFlags_Value but we pass CallFlags_None in compat modes
-        CallFlags flags = CallFlags_Value;
         Var element = nullptr;
         Var selected = nullptr;
-        BigIndex i = 0u;
 
         if (pArr)
         {
-            uint32 arrayLength = length.IsUint32Max() ? MaxArrayLength : length.GetSmallIndex();
+            Assert(length <= MaxArrayLength);
+            uint32 i = 0;
 
-            // If source was an array object, the return object might be any random object
-            for (uint32 k = 0; k < arrayLength; k++)
+            for (uint32 k = 0; k < length; k++)
             {
                 if (!pArr->DirectGetItemAtFull(k, &element))
                 {
                     continue;
                 }
 
-                selected = CALL_FUNCTION(callBackFn, CallInfo(flags, 4), thisArg,
-                                                                element,
-                                                                JavascriptNumber::ToVar(k, scriptContext),
-                                                                pArr);
+                selected = CALL_ENTRYPOINT(callBackFn->GetEntryPoint(), callBackFn, CallInfo(CallFlags_Value, 4),
+                    thisArg,
+                    element,
+                    JavascriptNumber::ToVar(k, scriptContext),
+                    pArr);
 
                 if (JavascriptConversion::ToBoolean(selected, scriptContext))
                 {
@@ -9103,7 +9110,7 @@ Case0:
                     }
                     else
                     {
-                        JavascriptArray::SetArrayLikeObjects(RecyclableObject::FromVar(newObj), i, element);
+                        JavascriptArray::SetArrayLikeObjects(newObj, i, element);
                     }
                     ++i;
                 }
@@ -9111,15 +9118,18 @@ Case0:
         }
         else
         {
-            for (BigIndex k = 0u; k < length; ++k)
+            BigIndex i = 0u;
+
+            for (T k = 0; k < length; k++)
             {
-                if (JavascriptOperators::HasItem(dynamicObject, k.IsSmallIndex() ? k.GetSmallIndex() : k.GetBigIndex()))
+                if (JavascriptOperators::HasItem(obj, k))
                 {
-                    element = JavascriptOperators::GetItem(dynamicObject, k.IsSmallIndex() ? k.GetSmallIndex() : k.GetBigIndex(), scriptContext);
-                    selected = CALL_FUNCTION(callBackFn, CallInfo(flags, 4), thisArg,
+                    element = JavascriptOperators::GetItem(obj, k, scriptContext);
+                    selected = CALL_ENTRYPOINT(callBackFn->GetEntryPoint(), callBackFn, CallInfo(CallFlags_Value, 4),
+                        thisArg,
                         element,
-                        JavascriptNumber::ToVar(k.IsSmallIndex() ? k.GetSmallIndex() : k.GetBigIndex(), scriptContext),
-                        dynamicObject);
+                        JavascriptNumber::ToVar(k, scriptContext),
+                        obj);
 
                     if (JavascriptConversion::ToBoolean(selected, scriptContext))
                     {
@@ -9129,7 +9139,7 @@ Case0:
                         }
                         else
                         {
-                            JavascriptArray::SetArrayLikeObjects(RecyclableObject::FromVar(newObj), i, element);
+                            JavascriptArray::SetArrayLikeObjects(newObj, i, element);
                         }
                         ++i;
                     }
@@ -9185,7 +9195,6 @@ Case0:
             if (scriptContext->GetConfig()->IsES6ToLengthEnabled())
             {
                 length = (uint64) JavascriptConversion::ToLength(JavascriptOperators::OP_GetLength(obj, scriptContext), scriptContext);
-
             }
             else
             {

+ 2 - 0
lib/Runtime/Library/JavascriptArray.h

@@ -467,6 +467,8 @@ namespace Js
         static Var FindHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, int64 length, Arguments& args, ScriptContext* scriptContext);
         template <typename T = uint32>
         static Var ReduceHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
+        template <typename T>
+        static Var FilterHelper(JavascriptArray* pArr, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
         template <typename T = uint32>
         static Var ReduceRightHelper(JavascriptArray* pArr, Js::TypedArrayBase* typedArrayBase, RecyclableObject* obj, T length, Arguments& args, ScriptContext* scriptContext);
         static Var OfHelper(bool isTypedArrayEntryPoint, Arguments& args, ScriptContext* scriptContext);

+ 0 - 2
lib/Runtime/Library/JavascriptBuiltInFunctionList.h

@@ -332,8 +332,6 @@ BUILTIN(SIMDFloat32x4Lib, Or,  EntryOr,  FunctionInfo::None)
 BUILTIN(SIMDFloat32x4Lib, Xor, EntryXor, FunctionInfo::None)
 BUILTIN(SIMDFloat32x4Lib, Min, EntryMin, FunctionInfo::None)
 BUILTIN(SIMDFloat32x4Lib, Max, EntryMax, FunctionInfo::None)
-BUILTIN(SIMDFloat32x4Lib, MinNum, EntryMinNum, FunctionInfo::None)
-BUILTIN(SIMDFloat32x4Lib, MaxNum, EntryMaxNum, FunctionInfo::None)
 BUILTIN(SIMDFloat32x4Lib, Scale, EntryScale, FunctionInfo::None)
 // CompareOps
 BUILTIN(SIMDFloat32x4Lib, LessThan, EntryLessThan, FunctionInfo::None)

+ 11 - 10
lib/Runtime/Library/JavascriptFunction.cpp

@@ -22,7 +22,12 @@ extern "C" void __cdecl _alloca_probe_16();
 
 namespace Js
 {
+    // The VS2013 linker treats this as a redefinition of an already
+    // defined constant and complains. So skip the declaration if we're compiling
+    // with VS2013 or below.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
     const charcount_t JavascriptFunction::DIAG_MAX_FUNCTION_STRING;
+#endif
 
     DEFINE_RECYCLER_TRACKER_PERF_COUNTER(JavascriptFunction);
     JavascriptFunction::JavascriptFunction(DynamicType * type)
@@ -2688,7 +2693,7 @@ LABEL1:
 
         BOOL result = DynamicObject::SetProperty(propertyId, value, flags, info);
 
-        if (propertyId == PropertyIds::prototype)
+        if (propertyId == PropertyIds::prototype || propertyId == PropertyIds::_symbolHasInstance)
         {
             PropertyValueInfo::SetNoCache(info, this);
             InvalidateConstructorCacheOnPrototypeChange();
@@ -2702,7 +2707,7 @@ LABEL1:
     {
         BOOL result = __super::SetPropertyWithAttributes(propertyId, value, attributes, info, flags, possibleSideEffects);
 
-        if (propertyId == PropertyIds::prototype)
+        if (propertyId == PropertyIds::prototype || propertyId == PropertyIds::_symbolHasInstance)
         {
             PropertyValueInfo::SetNoCache(info, this);
             InvalidateConstructorCacheOnPrototypeChange();
@@ -2750,7 +2755,7 @@ LABEL1:
 
         BOOL result = DynamicObject::DeleteProperty(propertyId, flags);
 
-        if (result && propertyId == PropertyIds::prototype)
+        if (result && propertyId == PropertyIds::prototype || propertyId == PropertyIds::_symbolHasInstance)
         {
             InvalidateConstructorCacheOnPrototypeChange();
             this->GetScriptContext()->GetThreadContext()->InvalidateIsInstInlineCachesForFunction(this);
@@ -2967,18 +2972,14 @@ LABEL1:
 
         Assert(!(callInfo.Flags & CallFlags_New));
 
-        if (args.Info.Count < 2)
-        {
-            JavascriptError::ThrowTypeError(scriptContext, JSERR_FunctionArgument_NeedObject, _u("Function[Symbol.hasInstance]"));
-        }
-
         RecyclableObject * constructor = RecyclableObject::FromVar(args[0]);
-        Var instance = args[1];
-        if (!JavascriptConversion::IsCallable(constructor))
+        if (!JavascriptConversion::IsCallable(constructor) || args.Info.Count < 2)
         {
             return JavascriptBoolean::ToVar(FALSE, scriptContext);
         }
 
+        Var instance = args[1];
+
         Assert(JavascriptProxy::Is(constructor) || JavascriptFunction::Is(constructor));
         return JavascriptBoolean::ToVar(constructor->HasInstance(instance, scriptContext, NULL), scriptContext);
     }

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

@@ -2547,6 +2547,7 @@ namespace Js
                                                      library->AddFunctionToLibraryObjectWithName(functionPrototype, PropertyIds::_symbolHasInstance, PropertyIds::_RuntimeFunctionNameId_hasInstance,
                                                                                                  &JavascriptFunction::EntryInfo::SymbolHasInstance, 1));
             functionPrototype->SetWritable(PropertyIds::_symbolHasInstance, false);
+            functionPrototype->SetConfigurable(PropertyIds::_symbolHasInstance, false);
         }
 
         DebugOnly(CheckRegisteredBuiltIns(builtinFuncs, scriptContext));
@@ -2700,8 +2701,6 @@ namespace Js
 
         builtinFuncs[BuiltinFunction::SIMD_Float32x4_Min] = library->AddFunctionToLibraryObject(float32x4Function, PropertyIds::min,    &SIMDFloat32x4Lib::EntryInfo::Min,   3);
         builtinFuncs[BuiltinFunction::SIMD_Float32x4_Max] = library->AddFunctionToLibraryObject(float32x4Function, PropertyIds::max,    &SIMDFloat32x4Lib::EntryInfo::Max,   3);
-        library->AddFunctionToLibraryObject(float32x4Function, PropertyIds::minNum, &SIMDFloat32x4Lib::EntryInfo::MinNum, 3);
-        library->AddFunctionToLibraryObject(float32x4Function, PropertyIds::maxNum, &SIMDFloat32x4Lib::EntryInfo::MaxNum, 3);
         // unary ops
         builtinFuncs[BuiltinFunction::SIMD_Float32x4_Abs] = library->AddFunctionToLibraryObject(float32x4Function, PropertyIds::abs,            &SIMDFloat32x4Lib::EntryInfo::Abs,            2);
         builtinFuncs[BuiltinFunction::SIMD_Float32x4_Neg] = library->AddFunctionToLibraryObject(float32x4Function, PropertyIds::neg,            &SIMDFloat32x4Lib::EntryInfo::Neg,            2);
@@ -7173,8 +7172,6 @@ namespace Js
         REG_OBJECTS_LIB_FUNC(xor_, SIMDFloat32x4Lib::EntryXor);
         REG_OBJECTS_LIB_FUNC(min, SIMDFloat32x4Lib::EntryMin);
         REG_OBJECTS_LIB_FUNC(max, SIMDFloat32x4Lib::EntryMax);
-        REG_OBJECTS_LIB_FUNC(minNum, SIMDFloat32x4Lib::EntryMinNum);
-        REG_OBJECTS_LIB_FUNC(maxNum, SIMDFloat32x4Lib::EntryMaxNum);
         REG_OBJECTS_LIB_FUNC(abs, SIMDFloat32x4Lib::EntryAbs);
         REG_OBJECTS_LIB_FUNC(neg, SIMDFloat32x4Lib::EntryNeg);
         REG_OBJECTS_LIB_FUNC(not_, SIMDFloat32x4Lib::EntryNot);

+ 5 - 0
lib/Runtime/Library/JavascriptRegExpConstructor.cpp

@@ -7,7 +7,12 @@
 
 namespace Js
 {
+    // The VS2013 linker treats this as a redefinition of an already
+    // defined constant and complains. So skip the declaration if we're compiling
+    // with VS2013 or below.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
     const int JavascriptRegExpConstructor::NumCtorCaptures;
+#endif
 
     JavascriptRegExpConstructor::JavascriptRegExpConstructor(DynamicType * type) :
         RuntimeFunction(type, &JavascriptRegExp::EntryInfo::NewInstance),

+ 50 - 5
lib/Runtime/Library/JavascriptString.cpp

@@ -2205,8 +2205,53 @@ case_2:
     {
         charcount_t count = pThis->GetLength();
 
+        const char16* inStr = pThis->GetString();
+        const char16* inStrLim = inStr + count;
+        const char16* i = inStr;
+
+        // Try to find out the chars that do not need casing (in the ASCII range)
+        if (toCase == ToUpper)
+        {
+            while (i < inStrLim)
+            {
+                // first range of ascii lower-case (97-122)
+                // second range of ascii lower-case (223-255)
+                // non-ascii chars (255+)
+                if (*i >= 'a')
+                {
+                    if (*i <= 'z') { break; }
+                    if (*i >= 'ß') { break; }
+                }
+                i++;
+            }
+        }
+        else
+        {
+            Assert(toCase == ToLower);
+            while (i < inStrLim)
+            {
+                // first range of ascii uppercase (65-90)
+                // second range of ascii uppercase (192-222)
+                // non-ascii chars (255+)
+                if (*i >= 'A')
+                {
+                    if (*i <= 'Z') { break; }
+                    if (*i >= 'À')
+                    { 
+                        if (*i < 'ß') { break; }
+                        if (*i >= 'ÿ') { break; }
+                    }
+                }
+                i++;
+            }
+        }
+
+        // If no char needs casing, return immediately
+        if (i == inStrLim) { return pThis; }
+
+        // Otherwise, copy the string and start casing
+        charcount_t countToCase = (charcount_t)(inStrLim - i);
         BufferStringBuilder builder(count, pThis->type->GetScriptContext());
-        const char16 *inStr = pThis->GetString();
         char16 *outStr = builder.DangerousGetWritableBuffer();
 
         char16* outStrLim = outStr + count;
@@ -2223,9 +2268,9 @@ case_2:
             DWORD converted =
 #endif
                 PlatformAgnostic::UnicodeText::ChangeStringCaseInPlace(
-                    PlatformAgnostic::UnicodeText::CaseFlags::CaseFlagsUpper, outStr, count);
+                    PlatformAgnostic::UnicodeText::CaseFlags::CaseFlagsUpper, outStrLim - countToCase, countToCase);
 
-            Assert(converted == count);
+            Assert(converted == countToCase);
         }
         else
         {
@@ -2234,9 +2279,9 @@ case_2:
             DWORD converted =
 #endif
                 PlatformAgnostic::UnicodeText::ChangeStringCaseInPlace(
-                    PlatformAgnostic::UnicodeText::CaseFlags::CaseFlagsLower, outStr, count);
+                    PlatformAgnostic::UnicodeText::CaseFlags::CaseFlagsLower, outStrLim - countToCase, countToCase);
 
-            Assert(converted == count);
+            Assert(converted == countToCase);
         }
 
         return builder.ToString();

+ 5 - 0
lib/Runtime/Library/ProfileString.cpp

@@ -8,7 +8,12 @@
 
 namespace Js
 {
+    // The VS2013 linker treats this as a redefinition of an already
+    // defined constant and complains. So skip the declaration if we're compiling
+    // with VS2013 or below.
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
     const uint StringProfiler::k_MaxConcatLength;
+#endif
 
     StringProfiler::StringProfiler(PageAllocator * pageAllocator)
       : allocator(_u("StringProfiler"), pageAllocator, Throw::OutOfMemory ),

+ 0 - 59
lib/Runtime/Library/SimdFloat32x4Lib.cpp

@@ -686,65 +686,6 @@ namespace Js
             return JavascriptSIMDFloat32x4::New(&result, scriptContext);
         }
 
-        JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdFloat32x4TypeMismatch, _u("maxNum"));
-    }
-
-
-    Var SIMDFloat32x4Lib::EntryMinNum(RecyclableObject* function, CallInfo callInfo, ...)
-    {
-        PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
-
-        ARGUMENTS(args, callInfo);
-        ScriptContext* scriptContext = function->GetScriptContext();
-
-        AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
-        Assert(!(callInfo.Flags & CallFlags_New));
-
-        // If any of the args are missing, then it is Undefined type which causes TypeError exception.
-        // strict type on both operands
-        if (args.Info.Count >= 3 && JavascriptSIMDFloat32x4::Is(args[1]) && JavascriptSIMDFloat32x4::Is(args[2]))
-        {
-            JavascriptSIMDFloat32x4 *a = JavascriptSIMDFloat32x4::FromVar(args[1]);
-            JavascriptSIMDFloat32x4 *b = JavascriptSIMDFloat32x4::FromVar(args[2]);
-            SIMDValue result, aValue, bValue;
-
-            aValue = a->GetValue();
-            bValue = b->GetValue();
-
-            result = SIMDFloat32x4Operation::OpMinNum(aValue, bValue);
-
-            return JavascriptSIMDFloat32x4::New(&result, scriptContext);
-        }
-
-        JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdFloat32x4TypeMismatch, _u("minNum"));
-    }
-
-    Var SIMDFloat32x4Lib::EntryMaxNum(RecyclableObject* function, CallInfo callInfo, ...)
-    {
-        PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
-
-        ARGUMENTS(args, callInfo);
-        ScriptContext* scriptContext = function->GetScriptContext();
-
-        AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
-        Assert(!(callInfo.Flags & CallFlags_New));
-
-        // If any of the args are missing, then it is Undefined type which causes TypeError exception.
-        // strict type on both operands
-        if (args.Info.Count >= 3 && JavascriptSIMDFloat32x4::Is(args[1]) && JavascriptSIMDFloat32x4::Is(args[2]))
-        {
-            JavascriptSIMDFloat32x4 *a = JavascriptSIMDFloat32x4::FromVar(args[1]);
-            JavascriptSIMDFloat32x4 *b = JavascriptSIMDFloat32x4::FromVar(args[2]);
-            SIMDValue result, aValue, bValue;
-
-            aValue = a->GetValue();
-            bValue = b->GetValue();
-
-            result = SIMDFloat32x4Operation::OpMaxNum(aValue, bValue);
-
-            return JavascriptSIMDFloat32x4::New(&result, scriptContext);
-        }
-
         JavascriptError::ThrowTypeError(scriptContext, JSERR_SimdFloat32x4TypeMismatch, _u("max"));
     }
 

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff