Просмотр исходного кода

Merge remote-tracking branch 'remotes/origin/WebAssembly' into users/micfer/wasm/i64

# Conflicts:
#	test/WasmSpec/baselines/left-to-right.baseline
Michael Ferris 9 лет назад
Родитель
Сommit
6a3f3acfe1
71 измененных файлов с 1442 добавлено и 802 удалено
  1. 2 0
      .gitignore
  2. 5 2
      Build/Common.Build.Default.props
  3. 1 1
      Build/scripts/finalize_build.ps1
  4. 110 50
      Build/scripts/init_build.ps1
  5. 0 143
      Build/scripts/pogo_build.ps1
  6. 10 2
      Build/scripts/post_build.ps1
  7. 4 6
      Build/scripts/pre_build.ps1
  8. 12 2
      Build/scripts/pre_post_util.ps1
  9. 91 16
      Build/scripts/run_build.ps1
  10. 11 7
      Build/scripts/util.ps1
  11. 5 4
      bin/CoreCommon.ver
  12. 2 2
      lib/Backend/BackwardPass.cpp
  13. 4 0
      lib/Backend/Chakra.Backend.vcxproj
  14. 2 0
      lib/Backend/Chakra.Backend.vcxproj.filters
  15. 6 0
      lib/Backend/Func.h
  16. 1 1
      lib/Backend/GlobOpt.cpp
  17. 5 3
      lib/Backend/IR.cpp
  18. 0 1
      lib/Backend/IRBuilderAsmJs.cpp
  19. 19 11
      lib/Backend/Inline.cpp
  20. 192 53
      lib/Backend/InterpreterThunkEmitter.cpp
  21. 38 15
      lib/Backend/InterpreterThunkEmitter.h
  22. 32 33
      lib/Backend/Lower.cpp
  23. 6 13
      lib/Backend/LowerMDShared.cpp
  24. 8 11
      lib/Backend/NativeCodeGenerator.cpp
  25. 6 1
      lib/Backend/Opnd.cpp
  26. 136 0
      lib/Backend/PageAllocatorPool.cpp
  27. 60 0
      lib/Backend/PageAllocatorPool.h
  28. 68 2
      lib/Backend/ServerScriptContext.cpp
  29. 12 1
      lib/Backend/ServerScriptContext.h
  30. 46 113
      lib/Backend/ServerThreadContext.cpp
  31. 17 19
      lib/Backend/ServerThreadContext.h
  32. 21 27
      lib/Backend/Sym.cpp
  33. 8 11
      lib/Backend/Sym.h
  34. 7 10
      lib/Backend/TempTracker.cpp
  35. 2 11
      lib/Backend/i386/EncoderMD.cpp
  36. 2 1
      lib/Common/ChakraCoreVersion.h
  37. 12 1
      lib/Common/ConfigFlagsList.h
  38. 29 18
      lib/Common/Memory/CustomHeap.cpp
  39. 68 0
      lib/JITClient/JITManager.cpp
  40. 17 0
      lib/JITClient/JITManager.h
  41. 19 0
      lib/JITIDL/ChakraJIT.idl
  42. 15 19
      lib/JITIDL/JITTypes.h
  43. 182 21
      lib/JITServer/JITServer.cpp
  44. 2 0
      lib/JITServer/JITServer.h
  45. 1 0
      lib/JITServer/JITServerPch.h
  46. 2 1
      lib/Runtime/Base/FunctionBody.cpp
  47. 2 0
      lib/Runtime/Base/FunctionBody.h
  48. 29 2
      lib/Runtime/Base/ScriptContext.cpp
  49. 9 2
      lib/Runtime/Base/ScriptContext.h
  50. 5 0
      lib/Runtime/Base/ScriptContextInfo.h
  51. 21 32
      lib/Runtime/Base/ThreadContext.cpp
  52. 5 8
      lib/Runtime/Base/ThreadContext.h
  53. 1 6
      lib/Runtime/Base/ThreadContextInfo.h
  54. 4 5
      lib/Runtime/Debug/TTEventLog.cpp
  55. 1 1
      lib/Runtime/Debug/TTEventLog.h
  56. 10 21
      lib/Runtime/Debug/TTInflateMap.cpp
  57. 4 4
      lib/Runtime/Debug/TTInflateMap.h
  58. 4 4
      lib/Runtime/Debug/TTRuntimeInfoTracker.h
  59. 10 22
      lib/Runtime/Debug/TTRuntmeInfoTracker.cpp
  60. 6 0
      lib/Runtime/Language/FunctionCodeGenJitTimeData.cpp
  61. 4 0
      lib/Runtime/Language/FunctionCodeGenJitTimeData.h
  62. 1 54
      lib/Runtime/Library/JavascriptArray.cpp
  63. 0 3
      lib/Runtime/Library/JavascriptArray.h
  64. 1 1
      lib/WasmReader/WasmBinaryOpCodes.h
  65. 1 2
      test/WasmSpec/baselines/left-to-right.baseline
  66. 17 0
      test/es5/es5array_objproto_builtin.js
  67. 5 0
      test/es5/rlexe.xml
  68. 1 0
      test/wasm/misc.baseline
  69. 1 1
      test/wasm/misc.js
  70. BIN
      test/wasm/misc.wasm
  71. 2 2
      test/wasm/misc.wast

+ 2 - 0
.gitignore

@@ -40,6 +40,7 @@ Build/VCBuild/
 buildchk.*
 buildfre.*
 BuildLinux/
+_DROP/
 
 # Generated Files
 *.bc
@@ -56,6 +57,7 @@ test/*/*.baseline.rebase
 test/benchmarks/*.dpl
 test/benchmarks/*.txt
 testout*
+packages.config
 
 # CMake Files
 cmake_install.cmake

+ 5 - 2
Build/Common.Build.Default.props

@@ -53,7 +53,6 @@
     <PlatformPathNameAlt Condition="'$(Platform)'=='x64'">amd64</PlatformPathNameAlt>
   </PropertyGroup>
 
-
   <!-- Default output directories -->
   <PropertyGroup>
     <OutBaseDir Condition="'$(OutBaseDir)'!=''">$(OutBaseDir)\$(SolutionName)</OutBaseDir>
@@ -64,7 +63,11 @@
   </PropertyGroup>
 
   <!-- Import generated build info -->
-  <Import Project="$(TF_BUILD_BUILDDIRECTORY)\Chakra.Generated.BuildInfo.props" Condition="'$(TF_BUILD_BUILDDIRECTORY)' != '' AND exists('$(TF_BUILD_BUILDDIRECTORY)\Chakra.Generated.BuildInfo.props')" />
+  <PropertyGroup>
+    <ObjectDirectory Condition="'$(TF_BUILD_BUILDDIRECTORY)'!=''">$(TF_BUILD_BUILDDIRECTORY)</ObjectDirectory>
+    <ObjectDirectory Condition="'$(TF_BUILD_BUILDDIRECTORY)'==''">$(IntBaseDir)\obj\$(PlatformPathName.ToLower())_$(Configuration.ToLower())</ObjectDirectory>
+  </PropertyGroup>
+  <Import Project="$(ObjectDirectory)\Chakra.Generated.BuildInfo.props" Condition="'$(ObjectDirectory)'!='' AND exists('$(ObjectDirectory)\Chakra.Generated.BuildInfo.props')" />
 
   <!-- Output directories -->
   <PropertyGroup>

+ 1 - 1
Build/scripts/finalize_build.ps1

@@ -101,7 +101,7 @@ $buildFlavorJson | Add-Member -type NoteProperty -name flavor -value $Env:BuildC
 $buildFlavorJson | Add-Member -type NoteProperty -name subtype -value $Env:BuildSubtype
 
 $buildFlavorJson | ConvertTo-Json | Write-Output
-$buildFlavorJson | ConvertTo-Json | Out-File $buildFlavorJsonFile -Encoding ascii
+$buildFlavorJson | ConvertTo-Json | Out-File $buildFlavorJsonFile -Encoding utf8
 
 #
 # Copy outputs to metadata directory

+ 110 - 50
Build/scripts/init_build.ps1

@@ -12,23 +12,47 @@
 # before running the Pre-Build script.
 
 param (
+    [ValidateSet("x86", "x64", "arm", "")]
+    [string]$arch = "",
+    [ValidateSet("debug", "release", "test", "codecoverage", "")]
+    [string]$flavor = "",
+    [ValidateSet("default", "codecoverage", "pogo")]
+    [string]$subtype = "default",
+    [string]$buildtype,
+
     [string]$envConfigScript = "ComputedEnvironment.cmd",
 
     [string[]]$supportedPogoBuildTypes = @("x64_release", "x86_release"),
 
-    [Parameter(Mandatory=$True)]
+    [string]$verMajor = "",
+    [string]$verMinor = "",
+    [string]$verPatch = "",
+    [string]$verSecurity = "",
+
+    [string]$dropRoot,
+
+    [switch]$cleanBinDir,
+
     [string]$oauth
 )
 
-# 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"
+#
+# Define values for variables based on parameters and environment variables
+# with default values in case the environment variables are not defined.
+#
+
+. $PSScriptRoot\util.ps1
+$gitExe = GetGitPath
+
+$BuildType = UseValueOrDefault $buildtype $Env:BuildType
+$BuildPlatform = UseValueOrDefault $arch $Env:BuildPlatform
+$BuildConfiguration = UseValueOrDefault $flavor $Env:BuildConfiguration
+$BuildSubtype = UseValueOrDefault $subtype $Env:BuildSubtype
 
-if (Test-Path Env:\BuildType) {
-    $BuildType = $Env:BuildType
+# If $BuildType is specified, extract BuildPlatform and BuildConfiguration
+# Otherwise, if $BuildPlatform and $BuildConfiguration are specified, construct $BuildType
+# $BuildSubtype will remain as "default" if not already specified, or become e.g. "pogo", "codecoverage"
+if ($BuildType) {
     $buildTypeSegments = $BuildType.split("_")
     $BuildPlatform = $buildTypeSegments[0]
     $BuildConfiguration = $buildTypeSegments[1]
@@ -42,12 +66,10 @@ if (Test-Path Env:\BuildType) {
         $BuildSubtype = "codecoverage" # keep information about codecoverage in the subtype
     }
 
-    if (-not ($BuildSubtype -in @("default","pogo","codecoverage"))) {
+    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
+} elseif ($BuildPlatform -and $BuildConfiguration) {
     $BuildType = "${BuildPlatform}_${BuildConfiguration}"
 } else {
     Write-Error (@"
@@ -56,67 +78,92 @@ if (Test-Path Env:\BuildType) {
         BuildType={0}
         BuildPlatform={1}
         BuildConfiguration={2}
+        BuildSubtype={3}
 
-"@ -f $Env:BuildType, $Env:BuildPlatform, $Env:BuildConfiguration)
+"@ -f $BuildType, $BuildPlatform, $BuildConfiguration, $BuildSubtype)
 
     exit 1
 }
 
+$CommitHash = UseValueOrDefault $Env:BUILD_SOURCEVERSION $(iex "${gitExe} rev-parse HEAD")
+
+$branchFullName  = UseValueOrDefault $Env:BUILD_SOURCEBRANCH $(iex "${gitExe} rev-parse --symbolic-full-name HEAD")
+
+$SourcesDirectory = UseValueOrDefault $Env:BUILD_SOURCESDIRECTORY $(GetRepoRoot)
+$BinariesDirectory = UseValueOrDefault (Join-Path $SourcesDirectory "Build\VcBuild")
+$ObjectDirectory = Join-Path $BinariesDirectory "obj\${BuildPlatform}_${BuildConfiguration}"
+
+$DropRoot = UseValueOrDefault $dropRoot $Env:DROP_ROOT (Join-Path $(GetRepoRoot) "_DROP")
+
 # 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 = iex "$gitExe rev-parse --symbolic-full-name HEAD"
-}
-
-$BranchName = $branch.split('/',3)[2]
+$BranchName = $branchFullName.split('/',3)[2]
 $BranchPath = $BranchName.replace('/','\')
-$CommitHash = $Env:BUILD_SOURCEVERSION
+
 if (-not $CommitHash) {
-    $CommitHash = iex "$gitExe rev-parse HEAD"
+    $CommitHash = iex "${gitExe} rev-parse HEAD"
 }
+$CommitShortHash = $(iex "${gitExe} rev-parse --short $CommitHash")
 
-$Username = (iex "$gitExe log $CommitHash -1 --pretty=%ae").split('@')[0]
-$CommitDateTime = [DateTime]$(iex "$gitExe 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
 
 #
 # Get Build Info
 #
 
-$info = GetBuildInfo $oauth $CommitHash
+$buildPushDate = $null
+$buildPushIdString = $null
 
-$BuildPushDate = [datetime]$info.push.date
-$PushDate = Get-Date $BuildPushDate -Format yyMMdd.HHmm
+if (-not $oauth)
+{
+    $buildPushIdPart1 = 65535
+    $buildPushIdPart2 = 65535
+    $buildPushIdString = "65535.65535"
+    $buildPushDate = [DateTime]$CommitDateTime
+}
+else
+{
+    $info = GetBuildInfo $oauth $CommitHash
+    $_, $buildPushIdPart1, $buildPushIdPart2, $buildPushIdString = GetBuildPushId $info
+    $buildPushDate = [DateTime]$info.push.date
+}
+
+$PushDate = Get-Date $buildPushDate -Format yyMMdd.HHmm
+
+$VersionMajor       = UseValueOrDefault $verMajor       $Env:VERSION_MAJOR  (GetVersionField "CHAKRA_CORE_MAJOR_VERSION")       "0"
+$VersionMinor       = UseValueOrDefault $verMinor       $Env:VERSION_MINOR  (GetVersionField "CHAKRA_CORE_MINOR_VERSION")       "0"
+$VersionPatch       = UseValueOrDefault $verPatch       $Env:VERSION_PATCH  (GetVersionField "CHAKRA_CORE_PATCH_VERSION")       "0"
+$VersionSecurity    = UseValueOrDefault $verSecurity    $Env:VERSION_QFE    (GetVersionField "CHAKRA_CORE_VERSION_RELEASE_QFE") "0"
 
-$buildPushId, $buildPushIdPart1, $buildPushIdPart2, $buildPushIdString = GetBuildPushId $info
+$VersionString = "${VersionMajor}.${VersionMinor}.${VersionPatch}" # Only use MAJOR.MINOR.PATCH to align with SemVer
 
-$VersionMajor = UseValueOrDefault "$Env:VERSION_MAJOR" "1"
-$VersionMinor = UseValueOrDefault "$Env:VERSION_MINOR" "2"
-$VersionPatch = UseValueOrDefault "$Env:VERSION_PATCH" "0"
-$VersionQFE   = UseValueOrDefault "$Env:VERSION_QFE"   "0"
+$buildVersionString = "{0}-{1}" -f $buildPushIdPart1.ToString("00000"), $buildPushIdPart2.ToString("00000")
+$PreviewVersionString = "${VersionString}-preview-${buildVersionString}"
 
-$VersionString = "${VersionMajor}.${VersionMinor}.${VersionPatch}.${VersionQFE}"
-$PreviewVersionString = "${VersionString}-preview"
+$ShortBranch = "commit"
+if ($BranchName -eq "master") {
+    $ShortBranch = "master"
+} elseif ($BranchName.StartsWith("release")) {
+    $ShortBranch = $BranchName.replace("release/","")
+}
 
 # unless it is a build branch, subdivide the output directory by month
 if ($BranchPath.StartsWith("build")) {
     $YearAndMonth = ""
 } else {
-    $YearAndMonth = (Get-Date $BuildPushDate -Format yyMM) + "\"
+    $YearAndMonth = (Get-Date $buildPushDate -Format yyMM) + "\"
 }
 
 $BuildIdentifier = "${buildPushIdString}_${PushDate}_${Username}_${CommitHash}"
 $ComputedDropPathSegment = "${BranchPath}\${YearAndMonth}${BuildIdentifier}"
-$BinariesDirectory = "${Env:BUILD_SOURCESDIRECTORY}\Build\VcBuild"
 $ObjectDirectory = "${BinariesDirectory}\obj\${BuildPlatform}_${BuildConfiguration}"
 
 # Create a sentinel file for each build flavor to track whether the build is complete.
@@ -128,9 +175,9 @@ This could mean that the build is in progress, or that it was unable to run to c
 The contents of this directory should not be relied on until the build completes.
 "@
 
-$DropPath = Join-Path $Env:DROP_ROOT $ComputedDropPathSegment
+$DropPath = Join-Path $DropRoot $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 $SourcesDirectory "test\logs")
 New-Item -ItemType Directory -Force -Path (Join-Path $BinariesDirectory "buildlogs")
 New-Item -ItemType Directory -Force -Path (Join-Path $BinariesDirectory "logs")
 
@@ -138,26 +185,33 @@ $FlavorBuildIncompleteFile = Join-Path $DropPath "${BuildType}.incomplete"
 
 if (-not (Test-Path $FlavorBuildIncompleteFile)) {
     ($buildIncompleteFileContentsString -f "Build of ${BuildType}") `
-        | Out-File $FlavorBuildIncompleteFile -Encoding Ascii
+        | Out-File $FlavorBuildIncompleteFile -Encoding utf8
 }
 
-$PogoConfig = $supportedPogoBuildTypes -contains "${Env:BuildPlatform}_${Env:BuildConfiguration}"
+$PogoConfig = $supportedPogoBuildTypes -contains "${BuildPlatform}_${BuildConfiguration}"
 
 # Write the $envConfigScript
 
 @"
 set BranchName=${BranchName}
+set ShortBranch=${ShortBranch}
 set BranchPath=${BranchPath}
 set YearAndMonth=${YearAndMonth}
 set BuildIdentifier=${BuildIdentifier}
 
-set buildPushIdString=${buildPushIdString}
+set VersionMajor=${VersionMajor}
+set VersionMinor=${VersionMinor}
+set VersionPatch=${VersionPatch}
+set VersionSecurity=${VersionSecurity}
+
+set BuildPushIdString=${buildPushIdString}
 set VersionString=${VersionString}
 set PreviewVersionString=${PreviewVersionString}
 set PushDate=${PushDate}
 set CommitTime=${CommitTime}
 set Username=${Username}
 set CommitHash=${CommitHash}
+set CommitShortHash=${CommitShortHash}
 
 set ComputedDropPathSegment=${ComputedDropPathSegment}
 set BinariesDirectory=${BinariesDirectory}
@@ -174,24 +228,30 @@ set FlavorBuildIncompleteFile=${FlavorBuildIncompleteFile}
 set PogoConfig=${PogoConfig}
 
 "@ `
-    | Out-File $envConfigScript -Encoding Ascii
+    | Out-File $envConfigScript -Encoding ASCII
 
 # 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_SOURCEGETVERSION=LG:${branchFullName}:${CommitHash}
 set TF_BUILD_DROPLOCATION=${BinariesDirectory}
 
-set TF_BUILD_SOURCESDIRECTORY=${Env:BUILD_SOURCESDIRECTORY}
+set TF_BUILD_SOURCESDIRECTORY=${SourcesDirectory}
 set TF_BUILD_BUILDDIRECTORY=${ObjectDirectory}
 set TF_BUILD_BINARIESDIRECTORY=${BinariesDirectory}
 
+REM The following variables are only used for logging build metadata.
 set TF_BUILD_BUILDDEFINITIONNAME=${Env:BUILD_DEFINITIONNAME}
 set TF_BUILD_BUILDNUMBER=${Env:BUILD_BUILDNUMBER}
 set TF_BUILD_BUILDURI=${Env:BUILD_BUILDURI}
 "@ `
-    | Out-File $envConfigScript -Encoding Ascii -Append
+    | Out-File $envConfigScript -Encoding ASCII -Append
+
+# Print contents of $envConfigScript as a sanity check
+Write-Output ""
+Get-Content $envConfigScript | Write-Output
+Write-Output ""
 
 # 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.
@@ -216,10 +276,10 @@ Write-Output "Setting VSO variable VSO_VersionString = ${VersionString}"
 Write-Output "##vso[task.setvariable variable=VSO_VersionString;]${VersionString}"
 
 #
-# Clean up files that might have been left behind from a previous build.
+# Optionally ($cleanBinDir): clean up files that might have been left behind from a previous build.
 #
 
-if ((Test-Path Env:\BUILD_BINARIESDIRECTORY) -and (Test-Path "$Env:BUILD_BINARIESDIRECTORY"))
+if ($BinariesDirectory -and (Test-Path "$BinariesDirectory") -and $cleanBinDir)
 {
-    Remove-Item -Verbose "${Env:BUILD_BINARIESDIRECTORY}\*" -Recurse
+    Remove-Item -Verbose "${BinariesDirectory}\*" -Recurse
 }

+ 0 - 143
Build/scripts/pogo_build.ps1

@@ -1,143 +0,0 @@
-#-------------------------------------------------------------------------------------------------------
-# 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 }
-}

+ 10 - 2
Build/scripts/post_build.ps1

@@ -37,9 +37,15 @@ param (
     [string[]]$pogo = @(),
     [string]$pogoscript = "",
 
-    [switch]$noaction
+    #
+    # Skip flags
+    #
+
+    [switch]$skipTests # or set $Env:SKIP_TESTS before invoking build
 )
 
+$skipTests = $skipTests -or (Test-Path Env:\SKIP_TESTS)
+
 $global:exitcode = 0
 
 if ($arch -eq "*") {
@@ -105,7 +111,9 @@ if ($arch -eq "*") {
         }
 
         # run tests
-        ExecuteCommand("$bvtcmdpath -$arch$flavor")
+        if (-not $skipTests) {
+            ExecuteCommand("$bvtcmdpath -$arch$flavor")
+        }
     }
 
     # check prefast

+ 4 - 6
Build/scripts/pre_build.ps1

@@ -20,7 +20,7 @@
 #   $Env:TF_BUILD_BUILDDIRECTORY    (a.k.a. $objpath)
 #   $Env:TF_BUILD_BINARIESDIRECTORY (a.k.a. $binpath)
 #
-# Optional information:
+# Optional information (metadata only):
 #   $Env:TF_BUILD_BUILDDEFINITIONNAME
 #   $Env:TF_BUILD_BUILDNUMBER
 #   $Env:TF_BUILD_BUILDURI
@@ -32,7 +32,6 @@ param (
     [Parameter(Mandatory=$True)]
     [ValidateSet("debug", "release", "test", "codecoverage")]
     [string]$flavor,
-
     [ValidateSet("default", "codecoverage", "pogo")]
     [string]$subtype = "default",
 
@@ -43,7 +42,6 @@ param (
 
     [string]$corePath = "core",
 
-    [Parameter(Mandatory=$True)]
     [string]$oauth
 )
 
@@ -108,7 +106,7 @@ if (Test-Path Env:\TF_BUILD_SOURCEGETVERSION)
 
     $info = GetBuildInfo $oauth $commitHash
 
-    $BuildDate = ([datetime]$info.push.date).toString("yyMMdd-HHmm")
+    $BuildDate = ([DateTime]$info.push.date).toString("yyMMdd-HHmm")
 
     $buildPushId, $buildPushIdPart1, $buildPushIdPart2, $buildPushIdString = GetBuildPushId $info
 
@@ -157,12 +155,12 @@ $CommitMessage
     $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
+    $changeJson | Add-Member -type NoteProperty -name CommitMessage -value $CommitMessageLines
 
     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 utf8
 
     $buildInfoOutputDir = $objpath
     if (-not(Test-Path -Path $buildInfoOutputDir)) {

+ 12 - 2
Build/scripts/pre_post_util.ps1

@@ -4,7 +4,6 @@
 #-------------------------------------------------------------------------------------------------------
 
 . "$PSScriptRoot\util.ps1"
-. "$PSScriptRoot\locate_msbuild.ps1"
 
 function WriteCommonArguments() {
     WriteMessage "  Source Path: $srcpath"
@@ -12,6 +11,17 @@ function WriteCommonArguments() {
     WriteMessage "Binaries Path: $binpath"
 }
 
+function GetVersionField($fieldname) {
+    $gitExe = GetGitPath
+    $query = "#define ${fieldname} (\d+)"
+    $line = (iex "${gitExe} grep -P ""${query}"" :/")
+    $matches = $line | Select-String $query
+    if ($matches) {
+        return $matches[0].Matches.Groups[1].Value
+    }
+    return ""
+}
+
 function GetBuildInfo($oauth, $commitHash) {
     # Get the git remote path and construct the REST API URI
     $gitExe = GetGitPath
@@ -21,7 +31,7 @@ function 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) }
+    $header = @{ Authorization=("Basic {0}" -f $oauthToken) }
     $info = Invoke-RestMethod -Headers $header -Uri $uri -Method GET
 
     return $info

+ 91 - 16
Build/scripts/run_build.ps1

@@ -3,54 +3,75 @@
 # 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)
+# Use this script to run a 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 = "default",
 
     [Parameter(Mandatory=$True)]
-    [string]$solutionFile = "",
+    [string]$solutionFile,
 
     [switch]$clean,
 
-    # $binDir will be inferred if not provided.
-    [string]$binDir = "",
+    [string]$binDir = "", # will be inferred if not provided.
     [string]$buildlogsSubdir = "buildlogs",
 
     # assume NuGet is on the path, otherwise the caller must specify an explicit path
     [string]$nugetExe = "NuGet.exe",
 
-    [string]$logFile = ""
+    [string]$logFile = "",
+
+    #
+    # Skip flags
+    #
+
+    [switch]$skipPogo, # or set $Env:SKIP_POGO before invoking build
+
+    #
+    # POGO training parameters
+    #
+
+    [string[]]$scenarios = @(),
+    [string]$binpath, # will be inferred if not provided
+    [string]$binaryName = "ch.exe"
 )
 
+#
+# Configure logging
+#
+
 $OuterScriptRoot = $PSScriptRoot
 . $PSScriptRoot\pre_post_util.ps1
+. $PSScriptRoot\locate_msbuild.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\run_build.${Env:BuildName}.log"
-    if (Test-Path -Path $logFile) {
-        Remove-Item $logFile -Force
-    }
+}
+
+if (($logFile -ne "") -and (Test-Path $logFile)) {
+    Remove-Item $logFile -Force
 }
 
 #
 # NuGet restore
 #
 
-ExecuteCommand "& $nugetExe restore $solutionFile -NonInteractive"
+if (-not (Get-Command $nugetExe -ErrorAction SilentlyContinue)) {
+    ExecuteCommand "& $nugetExe restore $solutionFile -NonInteractive"
+}
 
 #
-# Setup and build
+# Setup
 #
 
 $msbuildExe = Locate-MSBuild
@@ -62,6 +83,12 @@ if (-not $msbuildExe) {
 $binDir = UseValueOrDefault "$binDir" "${Env:BinariesDirectory}" "${Env:BUILD_SOURCESDIRECTORY}\Build\VcBuild"
 $buildlogsPath = Join-Path $binDir $buildlogsSubdir
 
+$skipPogo = $skipPogo -or (Test-Path Env:\SKIP_POGO)
+
+if (("$binpath" -ne "") -or (-not (Test-Path $binpath))) {
+    $binpath = Join-Path $binDir "bin\${buildName}"
+}
+
 $defaultParams = "$solutionFile /nologo /m /nr:false /p:platform=`"${arch}`" /p:configuration=`"${flavor}`""
 $loggingParams = @(
     "/fl1 `"/flp1:logfile=${buildlogsPath}\build.${Env:BuildName}.log;verbosity=normal`"",
@@ -75,11 +102,59 @@ if ($clean) {
     $targets += "`"/t:Clean,Rebuild`""
 }
 
-if ($subtype -eq "codecoverage") {
-    $subtypeParams = "/p:ENABLE_CODECOVERAGE=true"
+#
+# Build
+#
+
+function Build($targets="", $extraParams) {
+    $buildCommand = "& `"$msbuildExe`" $targets $defaultParams $loggingParams $extraParams"
+    ExecuteCommand "$buildCommand"
+    if ($global:LastExitCode -ne 0) {
+        WriteErrorMessage "Failed msbuild command:`n$buildCommand`n"
+        WriteErrorMessage "Build failed. Exiting..."
+        exit 1
+    }
 }
 
-$buildCommand = "& `"$msbuildExe`" $targets $defaultParams $loggingParams $subtypeParams"
-ExecuteCommand "$buildCommand"
+if ($subtype -eq "pogo") {
+    if ($scenarios.Length -eq 0) {
+        WriteMessage "No training scenarios selected for pogo build. Please specify training scenarios using the -scenarios parameter."
+        exit 1
+    }
+
+    Build -extraParams "`"/p:POGO_TYPE=PGI`"" -targets "$targets"
+
+    if (-not $skipPogo) {
+        $scenariosParamValue = $scenarios -join ','
+        $binary = Join-Path $binpath $binaryName
+        if (($binary -ne "") -and (Test-Path $binary)) {
+            $pogoTrainingCommand = "& `"${PSScriptRoot}\pgo\pogo_training.ps1`" -arch $arch -flavor $flavor -subtype $subtype -binary $binary -scenarios $scenariosParamValue"
+            ExecuteCommand "$pogoTrainingCommand"
+        } else {
+            WriteMessage "Binary not found at `"$binary`". Exiting..."
+            exit 1
+        }
+
+        Build -extraParams "`"/p:POGO_TYPE=PGO`""
+    }
+} else {
+    $subtypeParams = ""
+    if ($subtype -eq "codecoverage") {
+        $subtypeParams = "/p:ENABLE_CODECOVERAGE=true"
+    }
+
+    Build -extraParams $subTypeParams -targets $targets
+}
+
+#
+# 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 }
+}
 
 exit $global:lastexitcode

+ 11 - 7
Build/scripts/util.ps1

@@ -3,14 +3,13 @@
 # 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 UseValueOrDefault() {
+    foreach ($value in $args) {
+        if ($value) {
+            return $value
+        }
     }
+    return ""
 }
 
 function GetGitPath() {
@@ -26,6 +25,11 @@ function GetGitPath() {
     return $gitExe
 }
 
+function GetRepoRoot() {
+    $gitExe = GetGitPath
+    return iex "$gitExe rev-parse --show-toplevel"
+}
+
 function WriteMessage($str) {
     Write-Output $str
     if ($logFile -ne "") {

+ 5 - 4
bin/CoreCommon.ver

@@ -18,8 +18,8 @@
 ///         CHAKRA_VERSION_BUILD_QFE
 ///
 /// Binary version string is composed from the following values:
-///     CHAKRA_CORE_MAJOR_VERSION . CHAKRA_CORE_MINOR_VERSION . VER_PRODUCTBUILD . CHAKRA_CORE_VERSION_RELEASE_QFE
-///     e.g. 1.2.0.0
+///     CHAKRA_CORE_MAJOR_VERSION . CHAKRA_CORE_MINOR_VERSION . CHAKRA_CORE_PATCH_VERSION . CHAKRA_CORE_VERSION_RELEASE_QFE
+///     e.g. 1.2.1.0
 /// These fields must be explicitly set in the source.
 /// Note: VER_PRODUCTBUILD is always set to 0.
 
@@ -30,6 +30,7 @@
 
 #define VER_PRODUCTMAJORVERSION     CHAKRA_CORE_MAJOR_VERSION
 #define VER_PRODUCTMINORVERSION     CHAKRA_CORE_MINOR_VERSION
+#define VER_PRODUCTPATCHVERSION     CHAKRA_CORE_PATCH_VERSION
 
 // File Flags
 #if DBG
@@ -126,7 +127,7 @@
 
 #endif // defined(CHAKRA_VERSION_BUILD_NUMBER) && defined(CHAKRA_VERSION_BUILD_QFE)
 
-#define VER_PRODUCTVERSION          VER_PRODUCTMAJORVERSION,VER_PRODUCTMINORVERSION,VER_PRODUCTBUILD,VER_PRODUCTBUILD_QFE
+#define VER_PRODUCTVERSION          VER_PRODUCTMAJORVERSION,VER_PRODUCTMINORVERSION,VER_PRODUCTPATCHVERSION,VER_PRODUCTBUILD_QFE
 
 #define VER_PRODUCTVERSION_MAJORMINOR2(x,y) #x "." #y
 #define VER_PRODUCTVERSION_MAJORMINOR1(x,y) VER_PRODUCTVERSION_MAJORMINOR2(x, y)
@@ -136,7 +137,7 @@
 #define VER_PRODUCTVERSION_STR3(x)   VER_PRODUCTVERSION_STR4(x)
 #define VER_PRODUCTVERSION_STR2(x,y) VER_PRODUCTVERSION_STRING "." #x "." #y
 #define VER_PRODUCTVERSION_STR1(x,y) VER_PRODUCTVERSION_STR2(x, y)
-#define VER_PRODUCTVERSION_STR       VER_PRODUCTVERSION_STR1(VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE)
+#define VER_PRODUCTVERSION_STR       VER_PRODUCTVERSION_STR1(VER_PRODUCTPATCHVERSION, VER_PRODUCTBUILD_QFE)
 
 #ifdef VER_FILEDESCRIPTION_SUFFIX1_STR
 #ifdef VER_FILEDESCRIPTION_SUFFIX2_STR

+ 2 - 2
lib/Backend/BackwardPass.cpp

@@ -4344,7 +4344,7 @@ BackwardPass::TrackObjTypeSpecProperties(IR::PropertySymOpnd *opnd, BasicBlock *
             //Assert(!existingFldInfo->IsPoly() || !opnd->IsPoly() || GlobOpt::AreTypeSetsIdentical(existingFldInfo->GetEquivalentTypeSet(), opnd->GetEquivalentTypeSet()));
             //Assert(existingFldInfo->GetSlotIndex() == opnd->GetSlotIndex());
 
-            if (PHASE_TRACE(Js::EquivObjTypeSpecPhase, this->func))
+            if (PHASE_TRACE(Js::EquivObjTypeSpecPhase, this->func) && !JITManager::GetJITManager()->IsJITServer())
             {
                 if (existingFldInfo->IsPoly() && opnd->IsPoly() &&
                     (!GlobOpt::AreTypeSetsIdentical(existingFldInfo->GetEquivalentTypeSet(), opnd->GetEquivalentTypeSet()) ||
@@ -4354,7 +4354,7 @@ BackwardPass::TrackObjTypeSpecProperties(IR::PropertySymOpnd *opnd, BasicBlock *
 
                     Output::Print(_u("EquivObjTypeSpec: top function %s (%s): duplicate property clash on %s(#%d) on operation %u \n"),
                         this->func->GetJITFunctionBody()->GetDisplayName(), this->func->GetDebugNumberSet(debugStringBuffer),
-                        this->func->GetThreadContextInfo()->GetPropertyRecord(opnd->GetPropertyId())->GetBuffer(), opnd->GetPropertyId(), opnd->GetObjTypeSpecFldId());
+                        this->func->GetInProcThreadContext()->GetPropertyRecord(opnd->GetPropertyId())->GetBuffer(), opnd->GetPropertyId(), opnd->GetObjTypeSpecFldId());
                     Output::Flush();
                 }
             }

+ 4 - 0
lib/Backend/Chakra.Backend.vcxproj

@@ -403,6 +403,7 @@
     <ClInclude Include="LinearScanMDShared.h" />
     <ClInclude Include="LowerMDShared.h" />
     <ClInclude Include="NativeCodeData.h" />
+    <ClInclude Include="PageAllocatorPool.h" />
     <ClInclude Include="PDataManager.h" />
     <ClInclude Include="PrologEncoder.h">
       <ExcludedFromBuild Condition="'$(Platform)'!='x64'">true</ExcludedFromBuild>
@@ -460,6 +461,9 @@
       <FileType>CppCode</FileType>
     </ClInclude>
   </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="PageAllocatorPool.cpp" />
+  </ItemGroup>
   <Import Project="$(BuildConfigPropsPath)Chakra.Build.targets" Condition="exists('$(BuildConfigPropsPath)Chakra.Build.targets')" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">

+ 2 - 0
lib/Backend/Chakra.Backend.vcxproj.filters

@@ -126,6 +126,7 @@
     <ClCompile Include="$(MSBuildThisFileDirectory)ServerScriptContext.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)ServerThreadContext.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)JITTimeFixedField.cpp" />
+    <ClCompile Include="PageAllocatorPool.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="AgenPeeps.h" />
@@ -337,6 +338,7 @@
     <ClInclude Include="ExternalLowerer.h" />
     <ClInclude Include="JITRecyclableObject.h" />
     <ClInclude Include="CRC.h" />
+    <ClInclude Include="PageAllocatorPool.h" />
   </ItemGroup>
   <ItemGroup>
     <MASM Include="$(MSBuildThisFileDirectory)amd64\LinearScanMdA.asm">

+ 6 - 0
lib/Backend/Func.h

@@ -215,6 +215,12 @@ public:
         return m_workItem;
     }
 
+    ThreadContext * GetInProcThreadContext() const
+    {
+        Assert(!IsOOPJIT());
+        return (ThreadContext*)m_threadContextInfo;
+    }
+
     ThreadContextInfo * GetThreadContextInfo() const
     {
         return m_threadContextInfo;

+ 1 - 1
lib/Backend/GlobOpt.cpp

@@ -21050,7 +21050,7 @@ GlobOpt::GenerateBailOutMarkTempObjectIfNeeded(IR::Instr * instr, IR::Opnd * opn
                     const Js::PropertyId propertyId = propertySymOpnd->m_sym->AsPropertySym()->m_propertyId;
 
                     // We don't need to track numeric properties init
-                    if (!this->func->GetThreadContextInfo()->GetPropertyRecord(propertyId)->IsNumeric())
+                    if (!this->func->GetThreadContextInfo()->IsNumericProperty(propertyId))
                     {
                         DebugOnly(bool found = false);
                         globOptData.stackLiteralInitFldDataMap->RemoveIf(stackSym,

+ 5 - 3
lib/Backend/IR.cpp

@@ -123,8 +123,8 @@ Instr::TryOptimizeInstrWithFixedDataProperty(IR::Instr **pInstr, GlobOpt * globo
             IR::Instr* loadInstr = IR::Instr::NewConstantLoad(dataValueDstOpnd, (intptr_t)fixedValue, valType, instr->m_func);
 
             OUTPUT_VERBOSE_TRACE(Js::UseFixedDataPropsPhase,
-                _u("FixedFields: Replacing the source (fixed Data prop) with property id %s with 0x%x .\n"),
-                propSymOpnd->GetPropertySym()->GetName(), fixedValue);
+                _u("FixedFields: Replacing the source (fixed Data prop) with property id %u with 0x%x .\n"),
+                propSymOpnd->GetPropertyId(), fixedValue);
 
             instr->InsertAfter(loadInstr);
             propSymOpnd->SetUsesFixedValue(true);
@@ -3910,11 +3910,13 @@ Instr::DumpTestTrace()
         switch (propertySym->m_fieldKind)
         {
         case PropertyKindData:
+            if (!JITManager::GetJITManager()->IsOOPJITEnabled())
             {
-                Js::PropertyRecord const* fieldName = propertySym->GetFunc()->GetThreadContextInfo()->GetPropertyRecord(propertySym->m_propertyId);
+                Js::PropertyRecord const* fieldName = propertySym->GetFunc()->GetInProcThreadContext()->GetPropertyRecord(propertySym->m_propertyId);
                 Output::Print(_u("field: %s "), fieldName->GetBuffer());
                 break;
             }
+            // else fall through
         case PropertyKindSlots:
             Output::Print(_u("field: [%d] "), propertySym->m_propertyId);
             break;

+ 0 - 1
lib/Backend/IRBuilderAsmJs.cpp

@@ -2758,7 +2758,6 @@ IRBuilderAsmJs::BuildDouble3(Js::OpCodeAsmJs newOpcode, uint32 offset, Js::RegSl
         break;
 
     case Js::OpCodeAsmJs::Copysign_Db:
-        Assert(UNREACHED); // Not yet fully implemented
         instr = IR::Instr::New(Js::OpCode::Copysign_A, dstOpnd, src1Opnd, src2Opnd, m_func);
         break;
 

+ 19 - 11
lib/Backend/Inline.cpp

@@ -1328,7 +1328,7 @@ Inline::TryOptimizeCallInstrWithFixedMethod(IR::Instr *callInstr, const Function
             (isCtor && (
                 PHASE_TRACE(Js::FixedNewObjPhase, callInstr->m_func) ||
                 PHASE_TESTTRACE(Js::FixedNewObjPhase, callInstr->m_func)))
-        ) && !dontOptimizeJustCheck;
+        ) && !dontOptimizeJustCheck && !JITManager::GetJITManager()->IsJITServer();
 
     if (printFixedFieldsTrace)
     {
@@ -1414,7 +1414,7 @@ Inline::TryOptimizeCallInstrWithFixedMethod(IR::Instr *callInstr, const Function
             const char16* calleeName = calleeFunctionBody != nullptr ? calleeFunctionBody->GetDisplayName() : _u("<unknown>");
 
             Js::PropertyId methodPropertyId = callInstr->m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(methodPropertyOpnd->m_inlineCacheIndex);
-            Js::PropertyRecord const * const methodPropertyRecord = callInstr->m_func->GetThreadContextInfo()->GetPropertyRecord(methodPropertyId);
+            Js::PropertyRecord const * const methodPropertyRecord = callInstr->m_func->GetInProcThreadContext()->GetPropertyRecord(methodPropertyId);
 
             Output::Print(_u("FixedFields: function %s (#%u): %s non-fixed method %s (%s #%u) (cache id: %d), because %s fixed %s %s is disabled.\n"),
                 callInstr->m_func->GetJITFunctionBody()->GetDisplayName(), callInstr->m_func->GetDebugNumberSet(debugStringBuffer),
@@ -1436,7 +1436,7 @@ Inline::TryOptimizeCallInstrWithFixedMethod(IR::Instr *callInstr, const Function
             JITTimeFunctionBody* calleeFunctionBody = inlineeInfo != nullptr && inlineeInfo->HasBody() ? inlineeInfo->GetBody() : nullptr;
             const char16* calleeName = calleeFunctionBody != nullptr ? calleeFunctionBody->GetDisplayName() : _u("<unknown>");
             Js::PropertyId methodPropertyId = callInstr->m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(methodPropertyOpnd->m_inlineCacheIndex);
-            Js::PropertyRecord const * const methodPropertyRecord = callInstr->m_func->GetThreadContextInfo()->GetPropertyRecord(methodPropertyId);
+            Js::PropertyRecord const * const methodPropertyRecord = callInstr->m_func->GetInProcThreadContext()->GetPropertyRecord(methodPropertyId);
 
             Output::Print(_u("FixedFields: function %s (%s): %s non-fixed method %s (%s %s) (cache id: %d), because inline cache has no cached type.\n"),
                 callInstr->m_func->GetJITFunctionBody()->GetDisplayName(), callInstr->m_func->GetDebugNumberSet(debugStringBuffer),
@@ -1468,7 +1468,7 @@ Inline::TryOptimizeCallInstrWithFixedMethod(IR::Instr *callInstr, const Function
             const char16* calleeName = calleeFunctionBody != nullptr ? calleeFunctionBody->GetDisplayName() : _u("<unknown>");
 
             Js::PropertyId methodPropertyId = callInstr->m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(methodPropertyOpnd->m_inlineCacheIndex);
-            Js::PropertyRecord const * const methodPropertyRecord = callInstr->m_func->GetThreadContextInfo()->GetPropertyRecord(methodPropertyId);
+            Js::PropertyRecord const * const methodPropertyRecord = callInstr->m_func->GetInProcThreadContext()->GetPropertyRecord(methodPropertyId);
 
             Output::Print(_u("FixedFields: function %s (%s): %s non-fixed method %s (%s %s) (cache id: %d, layout: %s), because inline cache has no fixed function object.\n"),
                 callInstr->m_func->GetJITFunctionBody()->GetDisplayName(), callInstr->m_func->GetDebugNumberSet(debugStringBuffer),
@@ -1494,7 +1494,7 @@ Inline::TryOptimizeCallInstrWithFixedMethod(IR::Instr *callInstr, const Function
             const char16* calleeName = calleeFunctionBody != nullptr ? calleeFunctionBody->GetDisplayName() : _u("<unknown>");
 
             Js::PropertyId methodPropertyId = callInstr->m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(methodPropertyOpnd->m_inlineCacheIndex);
-            Js::PropertyRecord const * const methodPropertyRecord = callInstr->m_func->GetThreadContextInfo()->GetPropertyRecord(methodPropertyId);
+            Js::PropertyRecord const * const methodPropertyRecord = callInstr->m_func->GetInProcThreadContext()->GetPropertyRecord(methodPropertyId);
 
             Output::Print(_u("FixedFields: function %s (%s): %s non-fixed method %s (%s %s) (cache id: %d, layout: %s), because callee is a built-in with fast path in lowerer.\n"),
                 callInstr->m_func->GetJITFunctionBody()->GetDisplayName(), callInstr->m_func->GetDebugNumberSet(debugStringBuffer),
@@ -1515,7 +1515,7 @@ Inline::TryOptimizeCallInstrWithFixedMethod(IR::Instr *callInstr, const Function
         {
             char16 debugStringBuffer3[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
             Js::PropertyId methodPropertyId = callInstr->m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(methodPropertyOpnd->m_inlineCacheIndex);
-            Js::PropertyRecord const * const methodPropertyRecord = callInstr->m_func->GetThreadContextInfo()->GetPropertyRecord(methodPropertyId);
+            Js::PropertyRecord const * const methodPropertyRecord = callInstr->m_func->GetInProcThreadContext()->GetPropertyRecord(methodPropertyId);
             bool isProto = methodPropertyOpnd->IsLoadedFromProto();
             bool isAccessor = methodPropertyOpnd->UsesAccessor();
             Js::FunctionBody* fixedFunctionBody   = functionObject->GetFunctionInfo()->GetFunctionBody();
@@ -1556,7 +1556,7 @@ Inline::TryOptimizeCallInstrWithFixedMethod(IR::Instr *callInstr, const Function
         {
             JITTimeFunctionBody* calleeFunctionBody = inlineeInfo != nullptr && inlineeInfo->HasBody() ? inlineeInfo->GetBody() : nullptr;
             Js::PropertyId methodPropertyId = callInstr->m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(methodPropertyOpnd->m_inlineCacheIndex);
-            Js::PropertyRecord const * const methodPropertyRecord = callInstr->m_func->GetThreadContextInfo()->GetPropertyRecord(methodPropertyId);
+            Js::PropertyRecord const * const methodPropertyRecord = callInstr->m_func->GetInProcThreadContext()->GetPropertyRecord(methodPropertyId);
             const char16* fixedFunctionName = calleeFunctionBody != nullptr ? calleeFunctionBody->GetDisplayName() : _u("<unknown>");
             Js::FunctionBody* fixedFunctionBody = functionObject->GetFunctionInfo()->GetFunctionBody();
             const char16* fixedFunctionNumbers = fixedFunctionBody ? fixedFunctionBody->GetDebugNumberSet(debugStringBuffer2) : _u("(null)");
@@ -3486,10 +3486,18 @@ Inline::InlineGetterSetterFunction(IR::Instr *accessorInstr, const FunctionJITTi
         char16 debugStringBuffer [MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
         char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
         PropertySym *propertySym = isGetter ? accessorInstr->GetSrc1()->AsSymOpnd()->m_sym->AsPropertySym() : accessorInstr->GetDst()->AsSymOpnd()->m_sym->AsPropertySym();
-
-        Output::Print(_u("INLINING: %s: \tInlinee: %s (%s)\tCaller: %s (%s)\t fieldName: %s\n"), isGetter ? _u("Getter") : _u("Setter"),
-        funcBody->GetDisplayName(), inlineeData->GetDebugNumberSet(debugStringBuffer), funcCaller->GetDisplayName(), accessorInstr->m_func->GetWorkItem()->GetJITTimeInfo()->GetDebugNumberSet(debugStringBuffer2),
-            propertySym->GetFunc()->GetThreadContextInfo()->GetPropertyRecord(propertySym->m_propertyId)->GetBuffer());
+        if (JITManager::GetJITManager()->IsOOPJITEnabled())
+        {
+            Output::Print(_u("INLINING: %s: \tInlinee: %s (%s)\tCaller: %s (%s)\t fieldId: %d\n"), isGetter ? _u("Getter") : _u("Setter"),
+                funcBody->GetDisplayName(), inlineeData->GetDebugNumberSet(debugStringBuffer), funcCaller->GetDisplayName(), accessorInstr->m_func->GetWorkItem()->GetJITTimeInfo()->GetDebugNumberSet(debugStringBuffer2),
+                propertySym->m_propertyId);
+        }
+        else
+        {
+            Output::Print(_u("INLINING: %s: \tInlinee: %s (%s)\tCaller: %s (%s)\t fieldName: %s\n"), isGetter ? _u("Getter") : _u("Setter"),
+                funcBody->GetDisplayName(), inlineeData->GetDebugNumberSet(debugStringBuffer), funcCaller->GetDisplayName(), accessorInstr->m_func->GetWorkItem()->GetJITTimeInfo()->GetDebugNumberSet(debugStringBuffer2),
+                propertySym->GetFunc()->GetInProcThreadContext()->GetPropertyRecord(propertySym->m_propertyId)->GetBuffer());
+        }
         Output::Flush();
     }
 #endif

+ 192 - 53
lib/Backend/InterpreterThunkEmitter.cpp

@@ -228,15 +228,26 @@ const BYTE InterpreterThunkEmitter::HeaderSize = sizeof(InterpreterThunk);
 const BYTE InterpreterThunkEmitter::ThunkSize = sizeof(Call);
 const uint InterpreterThunkEmitter::ThunksPerBlock = (BlockSize - HeaderSize) / ThunkSize;
 
-InterpreterThunkEmitter::InterpreterThunkEmitter(ArenaAllocator* allocator, CustomHeap::CodePageAllocators * codePageAllocators, bool isAsmInterpreterThunk) :
-    // TODO: michhol oop JIT move interpreter thunk emitter out of process
-    emitBufferManager(allocator, codePageAllocators, /*scriptContext*/ nullptr, _u("Interpreter thunk buffer"), GetCurrentProcess()),
-    allocation(nullptr),
+InterpreterThunkEmitter::InterpreterThunkEmitter(Js::ScriptContext* context, ArenaAllocator* allocator, CustomHeap::CodePageAllocators * codePageAllocators, bool isAsmInterpreterThunk) :
+    emitBufferManager(nullptr),
+    scriptContext(context),
     allocator(allocator),
     thunkCount(0),
     thunkBuffer(nullptr),
     isAsmInterpreterThunk(isAsmInterpreterThunk)
 {
+    if (!JITManager::GetJITManager()->IsOOPJITEnabled())
+    {
+        emitBufferManager = HeapNew(EmitBufferManager<>, allocator, codePageAllocators, /*scriptContext*/ nullptr, _u("Interpreter thunk buffer"), GetCurrentProcess());
+    }
+}
+
+InterpreterThunkEmitter::~InterpreterThunkEmitter()
+{
+    if (emitBufferManager != nullptr)
+    {
+        HeapDelete(emitBufferManager);
+    }
 }
 
 //
@@ -287,40 +298,110 @@ void* InterpreterThunkEmitter::ConvertToEntryPoint(PVOID dynamicInterpreterThunk
 
 void InterpreterThunkEmitter::NewThunkBlock()
 {
-    Assert(this->thunkCount == 0);
-    BYTE* buffer;
-    BYTE* currentBuffer;
-    DWORD bufferSize = BlockSize;
-    DWORD thunkCount = 0;
-
-    void * interpreterThunk = nullptr;
-
-    // the static interpreter thunk invoked by the dynamic emitted thunk
-#ifdef ASMJS_PLAT
-    if (isAsmInterpreterThunk)
+#ifdef ENABLE_OOP_NATIVE_CODEGEN
+    if (JITManager::GetJITManager()->IsOOPJITEnabled())
     {
-        interpreterThunk = (void*)Js::InterpreterStackFrame::InterpreterAsmThunk;
+        NewOOPJITThunkBlock();
+        return;
     }
-    else
 #endif
-    {
-        interpreterThunk = (void*)Js::InterpreterStackFrame::InterpreterThunk;
-    }
 
-    allocation = emitBufferManager.AllocateBuffer(bufferSize, &buffer);
+    Assert(this->thunkCount == 0);
+    BYTE* buffer;
+
+    EmitBufferAllocation * allocation = emitBufferManager->AllocateBuffer(BlockSize, &buffer);
     if (allocation == nullptr) 
     {
         Js::Throw::OutOfMemory();
     }
-    if (!emitBufferManager.ProtectBufferWithExecuteReadWriteForInterpreter(allocation))
+    if (!emitBufferManager->ProtectBufferWithExecuteReadWriteForInterpreter(allocation))
+    {
+        Js::Throw::OutOfMemory();
+    }
+
+#if PDATA_ENABLED
+    PRUNTIME_FUNCTION pdataStart;
+    intptr_t epilogEnd;
+#endif
+
+    FillBuffer(
+        this->allocator,
+        this->scriptContext->GetThreadContext(),
+        this->isAsmInterpreterThunk,
+        (intptr_t)buffer,
+        BlockSize,
+        buffer,
+#if PDATA_ENABLED
+        &pdataStart,
+        &epilogEnd,
+#endif
+        &this->thunkCount
+    );
+
+    if (!emitBufferManager->CommitReadWriteBufferForInterpreter(allocation, buffer, BlockSize))
     {
         Js::Throw::OutOfMemory();
     }
 
-    currentBuffer = buffer;
+    // Call to set VALID flag for CFG check
+    ThreadContext::GetContextForCurrentThread()->SetValidCallTargetForCFG(buffer);
+
+    // Update object state only at the end when everything has succeeded - and no exceptions can be thrown.
+    auto block = this->thunkBlocks.PrependNode(allocator, buffer);
+#if PDATA_ENABLED
+    void* pdataTable;
+    PDataManager::RegisterPdata((PRUNTIME_FUNCTION)pdataStart, (ULONG_PTR)buffer, (ULONG_PTR)epilogEnd, &pdataTable);
+    block->SetPdata(pdataTable);
+#else
+    Unused(block);
+#endif
+    this->thunkBuffer = buffer;
+}
+
+#ifdef ENABLE_OOP_NATIVE_CODEGEN
+void InterpreterThunkEmitter::NewOOPJITThunkBlock()
+{
+    InterpreterThunkInfoIDL thunkInfo;
+    HRESULT hr = JITManager::GetJITManager()->NewInterpreterThunkBlock(
+        this->scriptContext->GetRemoteScriptAddr(),
+        this->isAsmInterpreterThunk,
+        &thunkInfo
+    );
+    JITManager::HandleServerCallResult(hr);
 
+    this->thunkBuffer = (BYTE*)thunkInfo.thunkBlockAddr;
+
+    // Update object state only at the end when everything has succeeded - and no exceptions can be thrown.
+    auto block = this->thunkBlocks.PrependNode(allocator, this->thunkBuffer);
+#if PDATA_ENABLED
+    void* pdataTable;
+    PDataManager::RegisterPdata((PRUNTIME_FUNCTION)thunkInfo.pdataTableStart, (ULONG_PTR)this->thunkBuffer, (ULONG_PTR)thunkInfo.epilogEndAddr, &pdataTable);
+    block->SetPdata(pdataTable);
+#else
+    Unused(block);
+#endif
+
+    this->thunkCount = thunkInfo.thunkCount;
+}
+#endif
+
+/* static */
+void InterpreterThunkEmitter::FillBuffer(
+    _In_ ArenaAllocator * arena,
+    _In_ ThreadContextInfo * threadContext,
+    _In_ bool asmJsThunk,
+    _In_ intptr_t finalAddr,
+    _In_ size_t bufferSize,
+    _Out_writes_bytes_all_(bufferSize) BYTE* buffer,
+#if PDATA_ENABLED
+    _Out_ PRUNTIME_FUNCTION * pdataTableStart,
+    _Out_ intptr_t * epilogEndAddr,
+#endif
+    _Out_ DWORD * thunkCount
+    )
+{
 #ifdef _M_X64
-    PrologEncoder prologEncoder(allocator);
+    PrologEncoder prologEncoder(arena);
     prologEncoder.EncodeSmallProlog(PrologSize, StackAllocSize);
     DWORD pdataSize = prologEncoder.SizeOfPData();
 #elif defined(_M_ARM32_OR_ARM64)
@@ -328,23 +409,43 @@ void InterpreterThunkEmitter::NewThunkBlock()
 #else
     DWORD pdataSize = 0;
 #endif
-    DWORD bytesRemaining = bufferSize;
+    DWORD bytesRemaining = BlockSize;
     DWORD bytesWritten = 0;
     DWORD epilogSize = sizeof(Epilog);
+    DWORD thunks = 0;
+
+    intptr_t interpreterThunk;
+
+    // the static interpreter thunk invoked by the dynamic emitted thunk
+#ifdef ASMJS_PLAT
+    if (asmJsThunk)
+    {
+        interpreterThunk = SHIFT_ADDR(threadContext, &Js::InterpreterStackFrame::InterpreterAsmThunk);
+    }
+    else
+#endif
+    {
+        interpreterThunk = SHIFT_ADDR(threadContext, &Js::InterpreterStackFrame::InterpreterThunk);
+    }
 
+    BYTE * currentBuffer = buffer;
     // Ensure there is space for PDATA at the end
-    BYTE* pdataStart = currentBuffer + (bufferSize - Math::Align(pdataSize, EMIT_BUFFER_ALIGNMENT));
+    BYTE* pdataStart = currentBuffer + (BlockSize - Math::Align(pdataSize, EMIT_BUFFER_ALIGNMENT));
     BYTE* epilogStart = pdataStart - Math::Align(epilogSize, EMIT_BUFFER_ALIGNMENT);
 
+    // Ensure there is space for PDATA at the end
+    intptr_t finalPdataStart = finalAddr + (BlockSize - Math::Align(pdataSize, EMIT_BUFFER_ALIGNMENT));
+    intptr_t finalEpilogStart = finalPdataStart - Math::Align(epilogSize, EMIT_BUFFER_ALIGNMENT);
+
     // Copy the thunk buffer and modify it.
     js_memcpy_s(currentBuffer, bytesRemaining, InterpreterThunk, HeaderSize);
-    EncodeInterpreterThunk(currentBuffer, buffer, HeaderSize, epilogStart, epilogSize, interpreterThunk);
+    EncodeInterpreterThunk(currentBuffer, finalAddr, HeaderSize, finalEpilogStart, epilogSize, interpreterThunk);
     currentBuffer += HeaderSize;
     bytesRemaining -= HeaderSize;
 
     // Copy call buffer
     DWORD callSize = sizeof(Call);
-    while(currentBuffer < epilogStart - callSize)
+    while (currentBuffer < epilogStart - callSize)
     {
         js_memcpy_s(currentBuffer, bytesRemaining, Call, callSize);
 #if _M_ARM
@@ -367,7 +468,7 @@ void InterpreterThunkEmitter::NewThunkBlock()
 #endif
         currentBuffer += callSize;
         bytesRemaining -= callSize;
-        thunkCount++;
+        thunks++;
     }
 
     // Fill any gap till start of epilog
@@ -394,30 +495,20 @@ void InterpreterThunkEmitter::NewThunkBlock()
     GeneratePdata(buffer, functionSize, &pdata);
     bytesWritten = CopyWithAlignment(pdataStart, bytesRemaining, (const BYTE*)&pdata, pdataSize, EMIT_BUFFER_ALIGNMENT);
 #endif
-    void* pdataTable;
-    PDataManager::RegisterPdata((PRUNTIME_FUNCTION) pdataStart, (ULONG_PTR) buffer, (ULONG_PTR) epilogEnd, &pdataTable);
+    *pdataTableStart = (PRUNTIME_FUNCTION)finalPdataStart;
+    *epilogEndAddr = finalEpilogStart;
 #endif
-    if (!emitBufferManager.CommitReadWriteBufferForInterpreter(allocation, buffer, bufferSize))
-    {
-        Js::Throw::OutOfMemory();
-    }
-
-    // Call to set VALID flag for CFG check
-    ThreadContext::GetContextForCurrentThread()->SetValidCallTargetForCFG(buffer);
-
-    // Update object state only at the end when everything has succeeded - and no exceptions can be thrown.
-    ThunkBlock* block = this->thunkBlocks.PrependNode(allocator, buffer);
-    UNREFERENCED_PARAMETER(block);
-#if PDATA_ENABLED
-    block->SetPdata(pdataTable);
-#endif
-    this->thunkCount = thunkCount;
-    this->thunkBuffer = buffer;
+    *thunkCount = thunks;
 }
 
-
 #if _M_ARM
-void InterpreterThunkEmitter::EncodeInterpreterThunk(__in_bcount(thunkSize) BYTE* thunkBuffer, __in_bcount(thunkSize) BYTE* thunkBufferStartAddress, __in const DWORD thunkSize, __in_bcount(epilogSize) BYTE* epilogStart, __in const DWORD epilogSize, __in void * const interpreterThunk)
+void InterpreterThunkEmitter::EncodeInterpreterThunk(
+    __in_bcount(thunkSize) BYTE* thunkBuffer,
+    __in const intptr_t thunkBufferStartAddress,
+    __in const DWORD thunkSize,
+    __in const intptr_t epilogStart,
+    __in const DWORD epilogSize,
+    __in const intptr_t interpreterThunk)
 {
     _Analysis_assume_(thunkSize == HeaderSize);
     // Encode MOVW
@@ -482,7 +573,13 @@ void InterpreterThunkEmitter::GeneratePdata(_In_ const BYTE* entryPoint, _In_ co
 }
 
 #elif _M_ARM64
-void InterpreterThunkEmitter::EncodeInterpreterThunk(__in_bcount(thunkSize) BYTE* thunkBuffer, __in_bcount(thunkSize) BYTE* thunkBufferStartAddress, __in const DWORD thunkSize, __in_bcount(epilogSize) BYTE* epilogStart, __in const DWORD epilogSize, __in void * const interpreterThunk)
+void InterpreterThunkEmitter::EncodeInterpreterThunk(
+    __in_bcount(thunkSize) BYTE* thunkBuffer,
+    __in const intptr_t thunkBufferStartAddress,
+    __in const DWORD thunkSize,
+    __in const intptr_t epilogStart,
+    __in const DWORD epilogSize,
+    __in const intptr_t interpreterThunk)
 {
     int addrOffset = ThunkAddressOffset;
 
@@ -556,7 +653,13 @@ void InterpreterThunkEmitter::GeneratePdata(_In_ const BYTE* entryPoint, _In_ co
     function->FrameSize = 5;                    // the number of bytes of stack that is allocated for this function divided by 16
 }
 #else
-void InterpreterThunkEmitter::EncodeInterpreterThunk(__in_bcount(thunkSize) BYTE* thunkBuffer, __in_bcount(thunkSize) BYTE* thunkBufferStartAddress, __in const DWORD thunkSize, __in_bcount(epilogSize) BYTE* epilogStart, __in const DWORD epilogSize, __in void * const interpreterThunk)
+void InterpreterThunkEmitter::EncodeInterpreterThunk(
+    __in_bcount(thunkSize) BYTE* thunkBuffer,
+    __in const intptr_t thunkBufferStartAddress,
+    __in const DWORD thunkSize,
+    __in const intptr_t epilogStart,
+    __in const DWORD epilogSize,
+    __in const intptr_t interpreterThunk)
 {
     _Analysis_assume_(thunkSize == HeaderSize);
     Emit(thunkBuffer, ThunkAddressOffset, (uintptr_t)interpreterThunk);
@@ -579,7 +682,6 @@ DWORD InterpreterThunkEmitter::FillDebugBreak(_In_ BYTE* dest, _In_ DWORD count)
 #elif defined(_M_ARM64)
     Assert(count % 4 == 0);
 #endif
-    // TODO: michhol OOP JIT. after mving OOP, change to runtime process handle
     CustomHeap::FillDebugBreak(dest, count, GetCurrentProcess());
     return count;
 }
@@ -607,6 +709,30 @@ DWORD InterpreterThunkEmitter::CopyWithAlignment(
     return srcSize;
 }
 
+#if DBG
+bool
+InterpreterThunkEmitter::IsInHeap(void* address)
+{
+#ifdef ENABLE_OOP_NATIVE_CODEGEN
+    if (JITManager::GetJITManager()->IsOOPJITEnabled())
+    {
+        intptr_t remoteScript = this->scriptContext->GetRemoteScriptAddr(false);
+        if (!remoteScript)
+        {
+            return false;
+        }
+        boolean result;
+        JITManager::GetJITManager()->IsInterpreterThunkAddr(remoteScript, (intptr_t)address, this->isAsmInterpreterThunk, &result);
+        return result != FALSE;
+    }
+    else
+#endif
+    {
+        return emitBufferManager->IsInHeap(address);
+    }
+}
+#endif
+
 // We only decommit at close because there might still be some
 // code running here.
 // The destructor of emitBufferManager will cause the eventual release.
@@ -622,7 +748,20 @@ void InterpreterThunkEmitter::Close()
 #endif
     this->thunkBlocks.Clear(allocator);
     this->freeListedThunkBlocks.Clear(allocator);
-    emitBufferManager.Decommit();
+#ifdef ENABLE_OOP_NATIVE_CODEGEN
+    if (JITManager::GetJITManager()->IsOOPJITEnabled())
+    {
+        intptr_t remoteScript = this->scriptContext->GetRemoteScriptAddr(false);
+        if (remoteScript)
+        {
+            JITManager::GetJITManager()->DecommitInterpreterBufferManager(remoteScript, this->isAsmInterpreterThunk);
+        }
+    }
+    else
+#endif
+    {
+        emitBufferManager->Decommit();
+    }
     this->thunkBuffer = nullptr;
     this->thunkCount = 0;
 }

+ 38 - 15
lib/Backend/InterpreterThunkEmitter.h

@@ -57,13 +57,13 @@ class InterpreterThunkEmitter
 {
 private:
     /* ------- instance methods --------*/
-    EmitBufferManager<> emitBufferManager;
-    EmitBufferAllocation *allocation;
+    EmitBufferManager<> * emitBufferManager;
     SListBase<ThunkBlock> thunkBlocks;
     SListBase<ThunkBlock> freeListedThunkBlocks;
     bool isAsmInterpreterThunk; // To emit address of InterpreterAsmThunk or InterpreterThunk
     BYTE*                thunkBuffer;
     ArenaAllocator*      allocator;
+    Js::ScriptContext *  scriptContext;
     DWORD thunkCount;                      // Count of thunks available in the current thunk block
 
     /* -------static constants ----------*/
@@ -94,10 +94,21 @@ private:
 
     /* ------private helpers -----------*/
     void NewThunkBlock();
-    void EncodeInterpreterThunk(__in_bcount(thunkSize) BYTE* thunkBuffer, __in_bcount(thunkSize) BYTE* thunkBufferStartAddress, __in const DWORD thunkSize, __in_bcount(epilogSize) BYTE* epilogStart, __in const DWORD epilogSize, __in void * const interpreterThunk);
+
+#ifdef ENABLE_OOP_NATIVE_CODEGEN
+    void NewOOPJITThunkBlock();
+#endif
+
+    static void EncodeInterpreterThunk(
+        __in_bcount(thunkSize) BYTE* thunkBuffer,
+        __in const intptr_t thunkBufferStartAddress,
+        __in const DWORD thunkSize,
+        __in const intptr_t epilogStart,
+        __in const DWORD epilogSize,
+        __in const intptr_t interpreterThunk);
 #if defined(_M_ARM32_OR_ARM64)
-    DWORD EncodeMove(DWORD opCode, int reg, DWORD imm16);
-    void GeneratePdata(_In_ const BYTE* entryPoint, _In_ const DWORD functionSize, _Out_ RUNTIME_FUNCTION* function);
+    static DWORD EncodeMove(DWORD opCode, int reg, DWORD imm16);
+    static void GeneratePdata(_In_ const BYTE* entryPoint, _In_ const DWORD functionSize, _Out_ RUNTIME_FUNCTION* function);
 #endif
 
     /*-------static helpers ---------*/
@@ -109,6 +120,8 @@ private:
         AssertMsg(*(T*) (dest + offset) == 0, "Overwriting an already existing opcode?");
         *(T*)(dest + offset) = value;
     };
+
+    BYTE* AllocateFromFreeList(PVOID* ppDynamicInterpreterThunk);
 public:
     static const BYTE HeaderSize;
     static const BYTE ThunkSize;
@@ -116,24 +129,34 @@ public:
     static const uint BlockSize;
     static void* ConvertToEntryPoint(PVOID dynamicInterpreterThunk);
 
-    InterpreterThunkEmitter(ArenaAllocator* allocator, CustomHeap::CodePageAllocators * codePageAllocators, bool isAsmInterpreterThunk = false);
-
+    InterpreterThunkEmitter(Js::ScriptContext * context, ArenaAllocator* allocator, CustomHeap::CodePageAllocators * codePageAllocators, bool isAsmInterpreterThunk = false);
+    ~InterpreterThunkEmitter();
     BYTE* GetNextThunk(PVOID* ppDynamicInterpreterThunk);
 
-    BYTE* AllocateFromFreeList(PVOID* ppDynamicInterpreterThunk);
-
     void Close();
     void Release(BYTE* thunkAddress, bool addtoFreeList);
-
     // Returns true if the argument falls within the range managed by this buffer.
-    inline bool IsInHeap(void* address)
-    {
-        return emitBufferManager.IsInHeap(address);
-    }
+#if DBG
+    bool IsInHeap(void* address);
+#endif
     const EmitBufferManager<>* GetEmitBufferManager() const
     {
-        return &emitBufferManager;
+        return emitBufferManager;
     }
 
+    static void FillBuffer(
+        _In_ ArenaAllocator * arena,
+        _In_ ThreadContextInfo * context,
+        _In_ bool asmJsThunk,
+        _In_ intptr_t finalAddr,
+        _In_ size_t bufferSize,
+        _Out_writes_bytes_all_(bufferSize) BYTE* buffer,
+#if PDATA_ENABLED
+        _Out_ PRUNTIME_FUNCTION * pdataTableStart,
+        _Out_ intptr_t * epilogEndAddr,
+#endif
+        _Out_ DWORD * thunkCount
+    );
+
 };
 #endif

+ 32 - 33
lib/Backend/Lower.cpp

@@ -5942,10 +5942,9 @@ Lowerer::GenerateLdFldWithCachedType(IR::Instr * instrLdFld, bool* continueAsHel
     PHASE_PRINT_TESTTRACE(
         Js::ObjTypeSpecPhase,
         this->m_func,
-        _u("Field load: %s, property: %s, func: %s, cache ID: %d, cloned cache: true, layout: %s, redundant check: %s\n"),
+        _u("Field load: %s, property ID: %d, func: %s, cache ID: %d, cloned cache: true, layout: %s, redundant check: %s\n"),
         Js::OpCodeUtil::GetOpCodeName(instrLdFld->m_opcode),
-        this->m_func->GetThreadContextInfo()->GetPropertyRecord(
-            propertySymOpnd->m_sym->AsPropertySym()->m_propertyId)->GetBuffer(),
+        propertySymOpnd->m_sym->AsPropertySym()->m_propertyId,
         this->m_func->GetJITFunctionBody()->GetDisplayName(),
         propertySymOpnd->m_inlineCacheIndex,
         propertySymOpnd->GetCacheLayoutString(),
@@ -6150,9 +6149,9 @@ Lowerer::GenerateCheckFixedFld(IR::Instr * instrChkFld)
     OUTPUT_TRACE_FUNC(
         Js::ObjTypeSpecPhase,
         this->m_func,
-        _u("Fixed field check: %s, property: %s, cache ID: %u, cloned cache: true, layout: %s, redundant check: %s count of props: %u \n"),
+        _u("Fixed field check: %s, property ID: %d, cache ID: %u, cloned cache: true, layout: %s, redundant check: %s count of props: %u \n"),
         Js::OpCodeUtil::GetOpCodeName(instrChkFld->m_opcode),
-        this->m_func->GetThreadContextInfo()->GetPropertyRecord(propertySym->m_propertyId)->GetBuffer(),
+        propertySym->m_propertyId,
         inlineCacheIndex, propertySymOpnd->GetCacheLayoutString(), propertySymOpnd->IsTypeChecked() ? _u("true") : _u("false"),
         propertySymOpnd->GetGuardedPropOps() ? propertySymOpnd->GetGuardedPropOps()->Count() : 0);
 
@@ -6250,9 +6249,9 @@ Lowerer::GenerateCheckObjType(IR::Instr * instrChkObjType)
     PHASE_PRINT_TESTTRACE(
         Js::ObjTypeSpecPhase,
         this->m_func,
-        _u("Object type check: %s, property: %s, func: %s, cache ID: %d, cloned cache: true, layout: %s, redundant check: %s\n"),
+        _u("Object type check: %s, property ID: %d, func: %s, cache ID: %d, cloned cache: true, layout: %s, redundant check: %s\n"),
         Js::OpCodeUtil::GetOpCodeName(instrChkObjType->m_opcode),
-        this->m_func->GetThreadContextInfo()->GetPropertyRecord(propertySym->m_propertyId)->GetBuffer(),
+        propertySym->m_propertyId,
         this->m_func->GetJITFunctionBody()->GetDisplayName(),
         inlineCacheIndex, propertySymOpnd->GetCacheLayoutString(), _u("false"));
 
@@ -7043,9 +7042,9 @@ Lowerer::GenerateStFldWithCachedType(IR::Instr *instrStFld, bool* continueAsHelp
     PHASE_PRINT_TESTTRACE(
         Js::ObjTypeSpecPhase,
         this->m_func,
-        _u("Field store: %s, property: %s, func: %s, cache ID: %d, cloned cache: true, layout: %s, redundant check: %s\n"),
+        _u("Field store: %s, property ID: %d, func: %s, cache ID: %d, cloned cache: true, layout: %s, redundant check: %s\n"),
         Js::OpCodeUtil::GetOpCodeName(instrStFld->m_opcode),
-        this->m_func->GetThreadContextInfo()->GetPropertyRecord(propertySymOpnd->m_sym->AsPropertySym()->m_propertyId)->GetBuffer(),
+        propertySymOpnd->m_sym->AsPropertySym()->m_propertyId,
         this->m_func->GetJITFunctionBody()->GetDisplayName(),
         propertySymOpnd->m_inlineCacheIndex, propertySymOpnd->GetCacheLayoutString(),
         propertySymOpnd->IsTypeChecked() ? _u("true") : _u("false"));
@@ -7343,9 +7342,9 @@ Lowerer::PinTypeRef(JITTypeHolder type, void* typeRef, IR::Instr* instr, Js::Pro
     if (PHASE_TRACE(Js::TracePinnedTypesPhase, this->m_func))
     {
         char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-        Output::Print(_u("PinnedTypes: function %s(%s) instr %s property %s(#%u) pinned %s reference 0x%p to type 0x%p.\n"),
+        Output::Print(_u("PinnedTypes: function %s(%s) instr %s property ID %u pinned %s reference 0x%p to type 0x%p.\n"),
             this->m_func->GetJITFunctionBody()->GetDisplayName(), this->m_func->GetDebugNumberSet(debugStringBuffer),
-            Js::OpCodeUtil::GetOpCodeName(instr->m_opcode), m_func->GetThreadContextInfo()->GetPropertyRecord(propertyId)->GetBuffer(), propertyId,
+            Js::OpCodeUtil::GetOpCodeName(instr->m_opcode), propertyId,
             typeRef == type.t ? _u("strong") : _u("weak"), typeRef, type.t);
         Output::Flush();
     }
@@ -7456,9 +7455,9 @@ Lowerer::CreateTypePropertyGuardForGuardedProperties(JITTypeHolder type, IR::Pro
                 if (PHASE_TRACE(Js::ObjTypeSpecPhase, this->m_func) || PHASE_TRACE(Js::TracePropertyGuardsPhase, this->m_func))
                 {
                     char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-                    Output::Print(_u("ObjTypeSpec: function %s(%s) registered guard 0x%p with value 0x%p for property %s (%u).\n"),
+                    Output::Print(_u("ObjTypeSpec: function %s(%s) registered guard 0x%p with value 0x%p for property ID %u.\n"),
                         m_func->GetJITFunctionBody()->GetDisplayName(), this->m_func->GetDebugNumberSet(debugStringBuffer),
-                        guard, guard->GetValue(), m_func->GetThreadContextInfo()->GetPropertyRecord(propertyId)->GetBuffer(), propertyId);
+                        guard, guard->GetValue(), propertyId);
                     Output::Flush();
                 }
 
@@ -7486,9 +7485,9 @@ Lowerer::CreateEquivalentTypeGuardAndLinkToGuardedProperties(JITTypeHolder type,
             if (PHASE_TRACE(Js::ObjTypeSpecPhase, this->m_func) || PHASE_TRACE(Js::TracePropertyGuardsPhase, this->m_func))
             {
                 char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-                Output::Print(_u("ObjTypeSpec: function %s(%s) registered equivalent type spec guard 0x%p with value 0x%p for property %s (%u).\n"),
+                Output::Print(_u("ObjTypeSpec: function %s(%s) registered equivalent type spec guard 0x%p with value 0x%p for property ID %u.\n"),
                     this->m_func->GetJITFunctionBody()->GetDisplayName(), this->m_func->GetDebugNumberSet(debugStringBuffer),
-                    guard, guard->GetValue(), m_func->GetThreadContextInfo()->GetPropertyRecord(propertyId)->GetBuffer(), propertyId);
+                    guard, guard->GetValue(), propertyId);
                 Output::Flush();
             }
 
@@ -7565,8 +7564,8 @@ Lowerer::CreateEquivalentTypeGuardAndLinkToGuardedProperties(JITTypeHolder type,
                 if (PHASE_TRACE(Js::EquivObjTypeSpecPhase, this->m_func))
                 {
                     char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-                    Output::Print(_u("EquivObjTypeSpec: top function %s (%s): duplicate property clash on %s(#%d) \n"),
-                        m_func->GetJITFunctionBody()->GetDisplayName(), m_func->GetDebugNumberSet(debugStringBuffer), propertyId, m_func->GetThreadContextInfo()->GetPropertyRecord(propertyId)->GetBuffer());
+                    Output::Print(_u("EquivObjTypeSpec: top function %s (%s): duplicate property clash on %d \n"),
+                        m_func->GetJITFunctionBody()->GetDisplayName(), m_func->GetDebugNumberSet(debugStringBuffer), propertyId);
                     Output::Flush();
                 }
                 Assert(propIdCount < propOpCount);
@@ -7620,9 +7619,9 @@ Lowerer::LinkCtorCacheToGuardedProperties(JITTimeConstructorCache* ctorCache)
             if (PHASE_TRACE(Js::ObjTypeSpecPhase, this->m_func) || PHASE_TRACE(Js::TracePropertyGuardsPhase, this->m_func))
             {
                 char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
-                Output::Print(_u("ObjTypeSpec: function %s(%s) registered ctor cache 0x%p with value 0x%p for property %s (%u).\n"),
+                Output::Print(_u("ObjTypeSpec: function %s(%s) registered ctor cache 0x%p with value 0x%p for property %u.\n"),
                     this->m_func->GetJITFunctionBody()->GetDisplayName(), this->m_func->GetDebugNumberSet(debugStringBuffer),
-                    ctorCache->GetRuntimeCacheAddr(), ctorCache->GetType()->GetAddr(), m_func->GetThreadContextInfo()->GetPropertyRecord(propertyId)->GetBuffer(), propertyId);
+                    ctorCache->GetRuntimeCacheAddr(), ctorCache->GetType()->GetAddr(), propertyId);
                 Output::Flush();
             }
 
@@ -11662,7 +11661,7 @@ Lowerer::LowerBailForDebugger(IR::Instr* instr, bool isInsideHelper /* = false *
 
     if (!(bailOutKind & IR::BailOutExplicit))
     {
-        intptr_t flags = m_func->GetThreadContextInfo()->GetDebuggingFlagsAddr();
+        intptr_t flags = m_func->GetScriptContextInfo()->GetDebuggingFlagsAddr();
 
         // Check 1 (do we need to bail out?)
         // JXX bailoutLabel
@@ -11736,13 +11735,13 @@ Lowerer::LowerBailForDebugger(IR::Instr* instr, bool isInsideHelper /* = false *
         {
             // TEST STEP_BAILOUT, [&stepController->StepType]
             // BNE BailoutLabel
-            IR::Opnd* opnd1 = IR::MemRefOpnd::New(m_func->GetThreadContextInfo()->GetDebugStepTypeAddr(), TyInt8, m_func);
+            IR::Opnd* opnd1 = IR::MemRefOpnd::New(m_func->GetScriptContextInfo()->GetDebugStepTypeAddr(), TyInt8, m_func);
             IR::Opnd* opnd2 = IR::IntConstOpnd::New(Js::STEP_BAILOUT, TyInt8, this->m_func, /*dontEncode*/ true);
             InsertTestBranch(opnd1, opnd2, Js::OpCode::BrNeq_A, bailOutLabel, continueBranchInstr);
 
             // CMP  STEP_DOCUMENT, [&stepController->StepType]
             // BEQ BailoutDocumentLabel
-            opnd1 = IR::MemRefOpnd::New(m_func->GetThreadContextInfo()->GetDebugStepTypeAddr(), TyInt8, m_func);
+            opnd1 = IR::MemRefOpnd::New(m_func->GetScriptContextInfo()->GetDebugStepTypeAddr(), TyInt8, m_func);
             opnd2 = IR::IntConstOpnd::New(Js::STEP_DOCUMENT, TyInt8, this->m_func, /*dontEncode*/ true);
             InsertCompareBranch(opnd1, opnd2, Js::OpCode::BrEq_A, /*isUnsigned*/ true, bailOutDocumentLabel, continueBranchInstr);
 
@@ -11763,12 +11762,12 @@ Lowerer::LowerBailForDebugger(IR::Instr* instr, bool isInsideHelper /* = false *
             effectiveFrameBaseReg = m_lowererMD.GetRegFramePointer();
 #endif
             IR::Opnd* opnd1 = IR::RegOpnd::New(nullptr, effectiveFrameBaseReg, TyMachReg, m_func);
-            IR::Opnd* opnd2 = IR::MemRefOpnd::New(m_func->GetThreadContextInfo()->GetDebugFrameAddressAddr(), TyMachReg, m_func);
+            IR::Opnd* opnd2 = IR::MemRefOpnd::New(m_func->GetScriptContextInfo()->GetDebugFrameAddressAddr(), TyMachReg, m_func);
             this->InsertCompareBranch(opnd1, opnd2, Js::OpCode::BrGt_A, /*isUnsigned*/ true, bailOutLabel, continueBranchInstr);
 
             // CMP  STEP_DOCUMENT, [&stepController->StepType]
             // BEQ BailoutDocumentLabel
-            opnd1 = IR::MemRefOpnd::New(m_func->GetThreadContextInfo()->GetDebugStepTypeAddr(), TyInt8, m_func);
+            opnd1 = IR::MemRefOpnd::New(m_func->GetScriptContextInfo()->GetDebugStepTypeAddr(), TyInt8, m_func);
             opnd2 = IR::IntConstOpnd::New(Js::STEP_DOCUMENT, TyInt8, this->m_func, /*dontEncode*/ true);
             InsertCompareBranch(opnd1, opnd2, Js::OpCode::BrEq_A, /*isUnsigned*/ true, bailOutDocumentLabel, continueBranchInstr);
 
@@ -11803,7 +11802,7 @@ Lowerer::LowerBailForDebugger(IR::Instr* instr, bool isInsideHelper /* = false *
             // bailOutLabel:                // (fallthrough bailOutLabel)
             IR::Opnd* opnd1 = IR::MemRefOpnd::New(m_func->GetJITFunctionBody()->GetScriptIdAddr(), TyInt32, m_func);
 
-            IR::Opnd* opnd2 = IR::MemRefOpnd::New(m_func->GetThreadContextInfo()->GetDebugScriptIdWhenSetAddr(), TyInt32, m_func);
+            IR::Opnd* opnd2 = IR::MemRefOpnd::New(m_func->GetScriptContextInfo()->GetDebugScriptIdWhenSetAddr(), TyInt32, m_func);
             IR::RegOpnd* reg1 = IR::RegOpnd::New(TyInt32, m_func);
             InsertMove(reg1, opnd2, bailOutLabel);
 
@@ -19202,9 +19201,9 @@ Lowerer::GenerateFastLdFld(IR::Instr * const instrLdFld, IR::JnHelperMethod help
     PHASE_PRINT_TESTTRACE(
         Js::ObjTypeSpecPhase,
         this->m_func,
-        _u("Field load: %s, property: %s, func: %s, cache ID: %d, cloned cache: false\n"),
+        _u("Field load: %s, property ID: %d, func: %s, cache ID: %d, cloned cache: false\n"),
         Js::OpCodeUtil::GetOpCodeName(instrLdFld->m_opcode),
-        this->m_func->GetThreadContextInfo()->GetPropertyRecord(propertySym->m_propertyId)->GetBuffer(),
+        propertySym->m_propertyId,
         this->m_func->GetJITFunctionBody()->GetDisplayName(),
         propertySymOpnd->m_inlineCacheIndex);
 
@@ -19457,9 +19456,9 @@ Lowerer::GenerateFastStFld(IR::Instr * const instrStFld, IR::JnHelperMethod help
     PHASE_PRINT_TESTTRACE(
         Js::ObjTypeSpecPhase,
         this->m_func,
-        _u("Field store: %s, property: %s, func: %s, cache ID: %d, cloned cache: false\n"),
+        _u("Field store: %s, property ID: %u, func: %s, cache ID: %d, cloned cache: false\n"),
         Js::OpCodeUtil::GetOpCodeName(instrStFld->m_opcode),
-        this->m_func->GetThreadContextInfo()->GetPropertyRecord(propertySym->m_propertyId)->GetBuffer(),
+        propertySym->m_propertyId,
         this->m_func->GetJITFunctionBody()->GetDisplayName(),
         propertySymOpnd->m_inlineCacheIndex);
 
@@ -19503,9 +19502,9 @@ Lowerer::GenerateFastStFld(IR::Instr * const instrStFld, IR::JnHelperMethod help
                 char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
                 #endif
                 PHASE_PRINT_TRACE(Js::AddFldFastPathPhase, this->m_func,
-                    _u("AddFldFastPath: function: %s(%s) property: %s(#%d) no fast path, because the phase is off.\n"),
+                    _u("AddFldFastPath: function: %s(%s) property ID: %u no fast path, because the phase is off.\n"),
                     this->m_func->GetJITFunctionBody()->GetDisplayName(), this->m_func->GetDebugNumberSet(debugStringBuffer),
-                    this->m_func->GetThreadContextInfo()->GetPropertyRecord(propertySym->m_propertyId)->GetBuffer(), propertySym->m_propertyId);
+                    propertySym->m_propertyId);
             }
 
             if ((profiledInstrStFld->u.FldInfo().flags & (Js::FldInfo_FromInlineSlots | Js::FldInfo_FromAuxSlots)) == Js::FldInfo_FromInlineSlots)
@@ -19544,9 +19543,9 @@ Lowerer::GenerateFastStFld(IR::Instr * const instrStFld, IR::JnHelperMethod help
         char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
 #endif
         PHASE_PRINT_TRACE(Js::AddFldFastPathPhase, this->m_func,
-            _u("AddFldFastPath: function: %s(%s) property: %s(#%d) %s fast path for %s.\n"),
+            _u("AddFldFastPath: function: %s(%s) property ID: %d %s fast path for %s.\n"),
             this->m_func->GetJITFunctionBody()->GetDisplayName(), this->m_func->GetDebugNumberSet(debugStringBuffer),
-            this->m_func->GetThreadContextInfo()->GetPropertyRecord(propertySym->m_propertyId)->GetBuffer(), propertySym->m_propertyId,
+            propertySym->m_propertyId,
             usePolymorphicInlineCache ? _u("poly") : _u("mono"), doStore ? _u("store and add") : _u("add only"));
     }
 

+ 6 - 13
lib/Backend/LowerMDShared.cpp

@@ -6219,21 +6219,14 @@ LowererMD::GenerateCopysign(IR::Instr * instr)
 
     // Copy sign from src2 to src1
     IR::Opnd* src1 = instr->GetSrc1();
+    Assert(src1->IsFloat32() || src1->IsFloat64());
     GenerateFloatAbs(src1->AsRegOpnd(), instr);
 
-    if (src1->IsFloat64())
-    {
-        Assert(UNREACHED);
-    }
-    else
-    {
-        Assert(src1->IsFloat32());
-        IR::Instr* t2 = IR::Instr::New(Js::OpCode::ANDPS, instr->GetSrc2(), instr->GetSrc2(),
-            IR::MemRefOpnd::New(this->m_func->GetThreadContextInfo()->GetSgnBitCst(), TyFloat32, this->m_func, IR::AddrOpndKindDynamicFloatRef),
-            m_func);
-        instr->InsertBefore(t2);
-        Legalize(t2);
-    }
+    IR::Instr* t2 = IR::Instr::New(Js::OpCode::ANDPS, instr->GetSrc2(), instr->GetSrc2(),
+        IR::MemRefOpnd::New(this->m_func->GetThreadContextInfo()->GetSgnBitCst(), src1->GetType(), this->m_func, src1->IsFloat32() ? IR::AddrOpndKindDynamicFloatRef : IR::AddrOpndKindDynamicDoubleRef),
+        m_func);
+    instr->InsertBefore(t2);
+    Legalize(t2);
 
     instr->m_opcode = Js::OpCode::ORPS;
     Legalize(instr);

+ 8 - 11
lib/Backend/NativeCodeGenerator.cpp

@@ -890,7 +890,7 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
 #if !FLOATVAR
     workItem->GetJITData()->xProcNumberPageSegment = scriptContext->GetThreadContext()->GetXProcNumberPageSegmentManager()->GetFreeSegment(&alloc);
 #endif
-    workItem->GetJITData()->globalThisAddr = (intptr_t)scriptContext->GetLibrary()->GetGlobalObject()->ToThis();
+    workItem->GetJITData()->globalThisAddr = (intptr_t)workItem->RecyclableData()->JitTimeData()->GetGlobalThisObject();
 
     LARGE_INTEGER start_time = { 0 };
     NativeCodeGenerator::LogCodeGenStart(workItem, &start_time);
@@ -2021,20 +2021,17 @@ NativeCodeGenerator::UpdateJITState()
         }
 
         // update all property records on server that have been changed since last jit
-        ThreadContext::PropertyMap * pendingProps = scriptContext->GetThreadContext()->GetPendingJITProperties();
-        PropertyRecordIDL ** newPropArray = nullptr;
+        ThreadContext::PropertyList * pendingProps = scriptContext->GetThreadContext()->GetPendingJITProperties();
+        int * newPropArray = nullptr;
         uint newCount = 0;
         if (pendingProps->Count() > 0)
         {
             newCount = (uint)pendingProps->Count();
-            newPropArray = HeapNewArray(PropertyRecordIDL*, newCount);
+            newPropArray = HeapNewArray(int, newCount);
             uint index = 0;
-            auto iter = pendingProps->GetIteratorWithRemovalSupport();
-            while (iter.IsValid())
+            while (!pendingProps->Empty())
             {
-                newPropArray[index++] = (PropertyRecordIDL*)iter.CurrentValue();
-                iter.RemoveCurrent();
-                iter.MoveNext();
+                newPropArray[index++] = (int)pendingProps->Pop();
             }
             Assert(index == newCount);
         }
@@ -2059,8 +2056,8 @@ NativeCodeGenerator::UpdateJITState()
             UpdatedPropertysIDL props = {0};
             props.reclaimedPropertyCount = reclaimedCount;
             props.reclaimedPropertyIdArray = reclaimedPropArray;
-            props.newRecordCount = newCount;
-            props.newRecordArray = newPropArray;
+            props.newPropertyCount = newCount;
+            props.newPropertyIdArray = newPropArray;
 
             HRESULT hr = JITManager::GetJITManager()->UpdatePropertyRecordMap(scriptContext->GetThreadContext()->GetRemoteThreadContextAddr(), &props);
 

+ 6 - 1
lib/Backend/Opnd.cpp

@@ -2909,7 +2909,12 @@ Opnd::Dump(IRDumpFlags flags, Func *func)
                             Output::Print(_u(","));
                         }
                         const JITObjTypeSpecFldInfo* propertyOpInfo = func->GetTopFunc()->GetGlobalObjTypeSpecFldInfo(propertyOpId);
-                        Output::Print(_u("%s(%u)"), func->GetThreadContextInfo()->GetPropertyRecord(propertyOpInfo->GetPropertyId())->GetBuffer(), propertyOpId);
+                        if (!JITManager::GetJITManager()->IsOOPJITEnabled())
+                        {
+                            Output::Print(_u("%s"), func->GetInProcThreadContext()->GetPropertyRecord(propertyOpInfo->GetPropertyId())->GetBuffer(), propertyOpId);
+                        }
+                        Output::Print(_u("(%u)"), propertyOpId);
+                        
                         if (propertyOpInfo->IsLoadedFromProto())
                         {
                             Output::Print(_u("~"));

+ 136 - 0
lib/Backend/PageAllocatorPool.cpp

@@ -0,0 +1,136 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+#include "Backend.h"
+
+#if ENABLE_OOP_NATIVE_CODEGEN
+#include "JITServer/JITServer.h"
+#include "PageAllocatorPool.h"
+
+CriticalSection PageAllocatorPool::cs;
+PageAllocatorPool* PageAllocatorPool::Instance = nullptr;
+
+PageAllocatorPool::PageAllocatorPool()
+    :pageAllocators(&NoThrowHeapAllocator::Instance),
+    activePageAllocatorCount(0)
+{
+    idleCleanupTimer = CreateWaitableTimerEx(NULL, L"JITServerIdle", 0/*auto reset*/, TIMER_ALL_ACCESS);
+}
+
+PageAllocatorPool::~PageAllocatorPool()
+{
+    RemoveAll();
+}
+
+void PageAllocatorPool::Initialize()
+{
+    Instance = HeapNewNoThrow(PageAllocatorPool);
+    if (Instance == nullptr)
+    {
+        Js::Throw::FatalInternalError();
+    }
+}
+void PageAllocatorPool::Shutdown()
+{
+    AutoCriticalSection autoCS(&cs);
+    if (Instance)
+    {
+        CloseHandle(Instance->idleCleanupTimer);
+        HeapDelete(Instance);
+        Instance = nullptr;
+    }
+}
+void PageAllocatorPool::RemoveAll()
+{
+    AutoCriticalSection autoCS(&cs);
+    while (!pageAllocators.Empty())
+    {
+        HeapDelete(pageAllocators.Pop());
+    }
+}
+
+unsigned int PageAllocatorPool::GetInactivePageAllocatorCount()
+{
+    AutoCriticalSection autoCS(&cs);
+    return pageAllocators.Count();
+}
+
+PageAllocator* PageAllocatorPool::GetPageAllocator()
+{
+    AutoCriticalSection autoCS(&cs);
+    PageAllocator* pageAllocator = nullptr;
+    if (pageAllocators.Count() > 0)
+    {
+        // TODO: OOP JIT, select the page allocator with right count of free pages
+        // base on some heuristic
+        pageAllocator = this->pageAllocators.Pop();
+    }
+    else
+    {
+        pageAllocator = HeapNew(PageAllocator, nullptr, Js::Configuration::Global.flags, PageAllocatorType_BGJIT,
+            AutoSystemInfo::Data.IsLowMemoryProcess() ? PageAllocator::DefaultLowMaxFreePageCount : PageAllocator::DefaultMaxFreePageCount);
+    }
+
+    activePageAllocatorCount++;
+    return pageAllocator;
+
+}
+void PageAllocatorPool::ReturnPageAllocator(PageAllocator* pageAllocator)
+{
+    AutoCriticalSection autoCS(&cs);
+    if (!this->pageAllocators.PrependNoThrow(&HeapAllocator::Instance, pageAllocator))
+    {
+        HeapDelete(pageAllocator);
+    }
+
+    activePageAllocatorCount--;
+    if (activePageAllocatorCount == 0 || GetInactivePageAllocatorCount() > (uint)Js::Configuration::Global.flags.JITServerMaxInactivePageAllocatorCount)
+    {
+        PageAllocatorPool::IdleCleanup();
+    }
+}
+
+void PageAllocatorPool::IdleCleanup()
+{
+    AutoCriticalSection autoCS(&cs);
+    if (Instance)
+    {
+        LARGE_INTEGER liDueTime;
+        liDueTime.QuadPart = Js::Configuration::Global.flags.JITServerIdleTimeout * -10000000LL; // wait for 10 seconds to do the cleanup
+
+        // If the timer is already active when you call SetWaitableTimer, the timer is stopped, then it is reactivated.
+        if (!SetWaitableTimer(Instance->idleCleanupTimer, &liDueTime, 0, IdleCleanupRoutine, NULL, 0))
+        {
+            Instance->RemoveAll();
+        }
+    }
+}
+
+VOID CALLBACK PageAllocatorPool::IdleCleanupRoutine(
+    _In_opt_ LPVOID lpArgToCompletionRoutine,
+    _In_     DWORD  dwTimerLowValue,
+    _In_     DWORD  dwTimerHighValue)
+{
+    AUTO_NESTED_HANDLED_EXCEPTION_TYPE(static_cast<ExceptionType>(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
+    try
+    {
+        if (Instance)
+        {
+            // TODO: OOP JIT, use better stragtegy to do the cleanup, like do not remove all,
+            // instead keep couple inactivate page allocator for next calls
+            Instance->RemoveAll();
+        }
+
+        ServerContextManager::IdleCleanup();
+    }
+    catch (Js::OutOfMemoryException&)
+    {
+    }
+    catch (...)
+    {
+        Assert(false);
+    }
+}
+#endif

+ 60 - 0
lib/Backend/PageAllocatorPool.h

@@ -0,0 +1,60 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+#pragma once
+
+class PageAllocatorPool
+{
+    friend class AutoReturnPageAllocator;
+public:
+    PageAllocatorPool();
+    ~PageAllocatorPool();
+    void RemoveAll();
+
+    static void Initialize();
+    static void Shutdown();
+    static void IdleCleanup();
+private:
+
+    static VOID CALLBACK IdleCleanupRoutine(
+        _In_opt_ LPVOID lpArgToCompletionRoutine,
+        _In_     DWORD  dwTimerLowValue,
+        _In_     DWORD  dwTimerHighValue);
+
+    PageAllocator* GetPageAllocator();
+    void ReturnPageAllocator(PageAllocator* pageAllocator);
+    unsigned int GetInactivePageAllocatorCount();
+
+    SList<PageAllocator*, NoThrowHeapAllocator, RealCount> pageAllocators;
+    static CriticalSection cs;
+    static PageAllocatorPool* Instance;
+    HANDLE idleCleanupTimer;
+    volatile unsigned long long activePageAllocatorCount;
+};
+
+class AutoReturnPageAllocator
+{
+public:
+    AutoReturnPageAllocator() :pageAllocator(nullptr) {}
+    ~AutoReturnPageAllocator()
+    {
+        if (pageAllocator)
+        {
+            PageAllocatorPool::Instance->ReturnPageAllocator(pageAllocator);
+        }
+    }
+    PageAllocator* GetPageAllocator()
+    {
+        if (pageAllocator == nullptr)
+        {
+            pageAllocator = PageAllocatorPool::Instance->GetPageAllocator();
+        }
+
+        return pageAllocator;
+    }
+
+private:
+    PageAllocator* pageAllocator;
+};

+ 68 - 2
lib/Backend/ServerScriptContext.cpp

@@ -12,6 +12,9 @@ ServerScriptContext::ServerScriptContext(ScriptContextDataIDL * contextData, Ser
     m_contextData(*contextData),
     threadContextInfo(threadContextInfo),
     m_isPRNGSeeded(false),
+    m_interpreterThunkBufferManager(nullptr),
+    m_asmJsInterpreterThunkBufferManager(nullptr),
+    m_sourceCodeArena(_u("JITSourceCodeArena"), threadContextInfo->GetForegroundPageAllocator(), Js::Throw::OutOfMemory),
     m_domFastPathHelperMap(nullptr),
     m_moduleRecords(&HeapAllocator::Instance),
     m_globalThisAddr(0),
@@ -26,6 +29,10 @@ ServerScriptContext::ServerScriptContext(ScriptContextDataIDL * contextData, Ser
     {
         m_codeGenProfiler = HeapNew(Js::ScriptContextProfiler);
     }
+#endif
+#if DYNAMIC_INTERPRETER_THUNK || defined(ASMJS_PLAT)
+    m_interpreterThunkBufferManager = HeapNew(EmitBufferManager<>, &m_sourceCodeArena, threadContextInfo->GetThunkPageAllocators(), nullptr, _u("Interpreter thunk buffer"), threadContextInfo->GetProcessHandle());
+    m_asmJsInterpreterThunkBufferManager = HeapNew(EmitBufferManager<>, &m_sourceCodeArena, threadContextInfo->GetThunkPageAllocators(), nullptr, _u("Asm.js interpreter thunk buffer"), threadContextInfo->GetProcessHandle());
 #endif
     m_domFastPathHelperMap = HeapNew(JITDOMFastPathHelperMap, &HeapAllocator::Instance, 17);
 }
@@ -44,6 +51,14 @@ ServerScriptContext::~ServerScriptContext()
         HeapDelete(m_codeGenProfiler);
     }
 #endif
+    if (m_asmJsInterpreterThunkBufferManager)
+    {
+        HeapDelete(m_asmJsInterpreterThunkBufferManager);
+    }
+    if (m_interpreterThunkBufferManager)
+    {
+        HeapDelete(m_interpreterThunkBufferManager);
+    }
 }
 
 intptr_t
@@ -193,8 +208,6 @@ ServerScriptContext::GetGlobalObjectThisAddr() const
 void
 ServerScriptContext::UpdateGlobalObjectThisAddr(intptr_t globalThis)
 {
-    // this should stay constant once context initialization is complete
-    Assert(!m_globalThisAddr || m_globalThisAddr == globalThis);
     m_globalThisAddr = globalThis;
 }
 
@@ -259,6 +272,30 @@ ServerScriptContext::IsPRNGSeeded() const
     return m_isPRNGSeeded;
 }
 
+intptr_t
+ServerScriptContext::GetDebuggingFlagsAddr() const
+{
+    return static_cast<intptr_t>(m_contextData.debuggingFlagsAddr);
+}
+
+intptr_t
+ServerScriptContext::GetDebugStepTypeAddr() const
+{
+    return static_cast<intptr_t>(m_contextData.debugStepTypeAddr);
+}
+
+intptr_t
+ServerScriptContext::GetDebugFrameAddressAddr() const
+{
+    return static_cast<intptr_t>(m_contextData.debugFrameAddressAddr);
+}
+
+intptr_t
+ServerScriptContext::GetDebugScriptIdWhenSetAddr() const
+{
+    return static_cast<intptr_t>(m_contextData.debugScriptIdWhenSetAddr);
+}
+
 bool
 ServerScriptContext::IsClosed() const
 {
@@ -271,6 +308,35 @@ ServerScriptContext::AddToDOMFastPathHelperMap(intptr_t funcInfoAddr, IR::JnHelp
     m_domFastPathHelperMap->Add(funcInfoAddr, helper);
 }
 
+ArenaAllocator *
+ServerScriptContext::GetSourceCodeArena()
+{
+    return &m_sourceCodeArena;
+}
+
+void
+ServerScriptContext::DecommitEmitBufferManager(bool asmJsManager)
+{
+    EmitBufferManager<> * manager = GetEmitBufferManager(asmJsManager);
+    if (manager != nullptr)
+    {
+        manager->Decommit();
+    }
+}
+
+EmitBufferManager<> *
+ServerScriptContext::GetEmitBufferManager(bool asmJsManager)
+{
+    if (asmJsManager)
+    {
+        return m_asmJsInterpreterThunkBufferManager;
+    }
+    else
+    {
+        return m_interpreterThunkBufferManager;
+    }
+}
+
 IR::JnHelperMethod
 ServerScriptContext::GetDOMFastPathHelper(intptr_t funcInfoAddr)
 {

+ 12 - 1
lib/Backend/ServerScriptContext.h

@@ -42,6 +42,11 @@ public:
     virtual bool IsClosed() const override;
     virtual intptr_t GetBuiltinFunctionsBaseAddr() const override;
 
+    virtual intptr_t GetDebuggingFlagsAddr() const override;
+    virtual intptr_t GetDebugStepTypeAddr() const override;
+    virtual intptr_t GetDebugFrameAddressAddr() const override;
+    virtual intptr_t GetDebugScriptIdWhenSetAddr() const override;
+
     virtual intptr_t GetAddr() const override;
 
     virtual intptr_t GetVTableAddress(VTableValue vtableType) const override;
@@ -61,10 +66,12 @@ public:
     void SetIsPRNGSeeded(bool value);
     void AddModuleRecordInfo(unsigned int moduleId, __int64 localExportSlotsAddr);
     void UpdateGlobalObjectThisAddr(intptr_t globalThis);
-
+    EmitBufferManager<> * GetEmitBufferManager(bool asmJsManager);
+    void DecommitEmitBufferManager(bool asmJsManager);
     Js::ScriptContextProfiler *  GetCodeGenProfiler() const;
     ServerThreadContext* GetThreadContext() { return threadContextInfo; }
 
+    ArenaAllocator * GetSourceCodeArena();
     void Close();
     void AddRef();
     void Release();
@@ -74,6 +81,10 @@ private:
 #ifdef PROFILE_EXEC
     Js::ScriptContextProfiler * m_codeGenProfiler;
 #endif
+    ArenaAllocator m_sourceCodeArena;
+
+    EmitBufferManager<> * m_interpreterThunkBufferManager;
+    EmitBufferManager<> * m_asmJsInterpreterThunkBufferManager;
 
     ScriptContextDataIDL m_contextData;
     intptr_t m_globalThisAddr;

+ 46 - 113
lib/Backend/ServerThreadContext.cpp

@@ -4,19 +4,26 @@
 //-------------------------------------------------------------------------------------------------------
 
 #include "Backend.h"
+
 #if ENABLE_OOP_NATIVE_CODEGEN
 #include "JITServer/JITServer.h"
-#endif
+#endif //ENABLE_OOP_NATIVE_CODEGEN
 
 ServerThreadContext::ServerThreadContext(ThreadContextDataIDL * data) :
     m_threadContextData(*data),
     m_refCount(0),
-    m_policyManager(true),
-    m_propertyMap(nullptr),
-    m_pageAllocs(&HeapAllocator::Instance),
+    m_numericPropertySet(nullptr),
     m_preReservedVirtualAllocator((HANDLE)data->processHandle),
-    m_codePageAllocators(&m_policyManager, ALLOC_XDATA, &m_preReservedVirtualAllocator, (HANDLE)data->processHandle),
-    m_codeGenAlloc(&m_policyManager, nullptr, &m_codePageAllocators, (HANDLE)data->processHandle),
+    m_codePageAllocators(nullptr, ALLOC_XDATA, &m_preReservedVirtualAllocator, (HANDLE)data->processHandle),
+#if DYNAMIC_INTERPRETER_THUNK || defined(ASMJS_PLAT)
+    m_thunkPageAllocators(nullptr, /* allocXData */ false, /* virtualAllocator */ nullptr, (HANDLE)data->processHandle),
+#endif
+    m_codeGenAlloc(nullptr, nullptr, &m_codePageAllocators, (HANDLE)data->processHandle),
+    m_pageAlloc(nullptr, Js::Configuration::Global.flags, PageAllocatorType_BGJIT,
+        AutoSystemInfo::Data.IsLowMemoryProcess() ?
+        PageAllocator::DefaultLowMaxFreePageCount :
+        PageAllocator::DefaultMaxFreePageCount
+    ),
     // TODO: OOP JIT, don't hardcode name
 #ifdef NTBUILD
     m_jitChakraBaseAddress((intptr_t)GetModuleHandle(_u("Chakra.dll"))),
@@ -32,26 +39,18 @@ ServerThreadContext::ServerThreadContext(ThreadContextDataIDL * data) :
 #if !_M_X64_OR_ARM64 && _CONTROL_FLOW_GUARD
     m_codeGenAlloc.canCreatePreReservedSegment = data->allowPrereserveAlloc != FALSE;
 #endif
-    m_propertyMap = HeapNew(PropertyMap, &HeapAllocator::Instance, TotalNumberOfBuiltInProperties + 700);
+    m_numericPropertySet = HeapNew(PropertySet, &HeapAllocator::Instance);
 }
 
 ServerThreadContext::~ServerThreadContext()
 {
     // TODO: OOP JIT, clear out elements of map. maybe should arena alloc?
-    if (this->m_propertyMap != nullptr)
+    if (this->m_numericPropertySet != nullptr)
     {
-        this->m_propertyMap->Map([](const Js::PropertyRecord* record)
-        {
-            size_t allocLength = record->byteCount + sizeof(char16) + (record->isNumeric ? sizeof(uint32) : 0);
-            HeapDeletePlus(allocLength, const_cast<Js::PropertyRecord*>(record));
-        });
-        HeapDelete(m_propertyMap);
-        this->m_propertyMap = nullptr;
+        HeapDelete(m_numericPropertySet);
+        this->m_numericPropertySet = nullptr;
     }
-    this->m_pageAllocs.Map([](DWORD thread, PageAllocator* alloc)
-    {
-        HeapDelete(alloc);
-    });
+
 }
 
 PreReservedVirtualAllocWrapper *
@@ -60,56 +59,12 @@ ServerThreadContext::GetPreReservedVirtualAllocator()
     return &m_preReservedVirtualAllocator;
 }
 
-PageAllocator*
-ServerThreadContext::GetPageAllocator()
-{
-    PageAllocator * alloc;
-
-    if (!m_pageAllocs.TryGetValue(GetCurrentThreadId(), &alloc))
-    {
-        alloc = HeapNew(PageAllocator,
-            &m_policyManager,
-            Js::Configuration::Global.flags, PageAllocatorType_BGJIT,
-            AutoSystemInfo::Data.IsLowMemoryProcess() ?
-            PageAllocator::DefaultLowMaxFreePageCount :
-            PageAllocator::DefaultMaxFreePageCount);
-
-        m_pageAllocs.Add(GetCurrentThreadId(), alloc);
-    }
-    return alloc;
-}
-
-
 intptr_t
 ServerThreadContext::GetBailOutRegisterSaveSpaceAddr() const
 {
     return static_cast<intptr_t>(m_threadContextData.bailOutRegisterSaveSpaceAddr);
 }
 
-intptr_t
-ServerThreadContext::GetDebuggingFlagsAddr() const
-{
-    return static_cast<intptr_t>(m_threadContextData.debuggingFlagsAddr);
-}
-
-intptr_t
-ServerThreadContext::GetDebugStepTypeAddr() const
-{
-    return static_cast<intptr_t>(m_threadContextData.debugStepTypeAddr);
-}
-
-intptr_t
-ServerThreadContext::GetDebugFrameAddressAddr() const
-{
-    return static_cast<intptr_t>(m_threadContextData.debugFrameAddressAddr);
-}
-
-intptr_t
-ServerThreadContext::GetDebugScriptIdWhenSetAddr() const
-{
-    return static_cast<intptr_t>(m_threadContextData.debugScriptIdWhenSetAddr);
-}
-
 ptrdiff_t
 ServerThreadContext::GetChakraBaseAddressDifference() const
 {
@@ -167,6 +122,14 @@ ServerThreadContext::GetProcessHandle() const
     return reinterpret_cast<HANDLE>(m_threadContextData.processHandle);
 }
 
+#if DYNAMIC_INTERPRETER_THUNK || defined(ASMJS_PLAT)
+CustomHeap::CodePageAllocators *
+ServerThreadContext::GetThunkPageAllocators()
+{
+    return &m_thunkPageAllocators;
+}
+#endif
+
 CustomHeap::CodePageAllocators *
 ServerThreadContext::GetCodePageAllocators()
 {
@@ -179,12 +142,6 @@ ServerThreadContext::GetCodeGenAllocators()
     return &m_codeGenAlloc;
 }
 
-AllocationPolicyManager *
-ServerThreadContext::GetAllocationPolicyManager()
-{
-    return &m_policyManager;
-}
-
 intptr_t
 ServerThreadContext::GetRuntimeChakraBaseAddress() const
 {
@@ -197,36 +154,34 @@ ServerThreadContext::GetRuntimeCRTBaseAddress() const
     return static_cast<intptr_t>(m_threadContextData.crtBaseAddress);
 }
 
-Js::PropertyRecord const *
-ServerThreadContext::GetPropertyRecord(Js::PropertyId propertyId)
+PageAllocator *
+ServerThreadContext::GetForegroundPageAllocator()
+{
+    return &m_pageAlloc;
+}
+
+bool
+ServerThreadContext::IsNumericProperty(Js::PropertyId propertyId)
 {
     if (propertyId >= 0 && Js::IsInternalPropertyId(propertyId))
     {
-        return Js::InternalPropertyRecords::GetInternalPropertyName(propertyId);
+        return Js::InternalPropertyRecords::GetInternalPropertyName(propertyId)->IsNumeric();
     }
 
-    const Js::PropertyRecord * propertyRecord = nullptr;
-    m_propertyMap->LockResize();
-    bool found = m_propertyMap->TryGetValue(propertyId, &propertyRecord);
-    m_propertyMap->UnlockResize();
+    m_numericPropertySet->LockResize();
+    bool found = m_numericPropertySet->ContainsKey(propertyId);
+    m_numericPropertySet->UnlockResize();
 
-    AssertMsg(found && propertyRecord != nullptr, "using invalid propertyid");
-    return propertyRecord;
+    return found;
 }
 
 void
-ServerThreadContext::RemoveFromPropertyMap(Js::PropertyId reclaimedId)
+ServerThreadContext::RemoveFromNumericPropertySet(Js::PropertyId reclaimedId)
 {
-    const Js::PropertyRecord * oldRecord = nullptr;
-    if (m_propertyMap->TryGetValue(reclaimedId, &oldRecord))
+    if (m_numericPropertySet->ContainsKey(reclaimedId))
     {
         // if there was reclaimed property that had its pid reused, delete the old property record
-        m_propertyMap->Remove(oldRecord);
-
-        PropertyRecordTrace(_u("Reclaimed JIT property '%s' at 0x%08x, pid = %d\n"), oldRecord->GetBuffer(), oldRecord, oldRecord->pid);
-
-        size_t oldLength = oldRecord->byteCount + sizeof(char16) + (oldRecord->isNumeric ? sizeof(uint32) : 0);
-        HeapDeletePlus(oldLength, const_cast<Js::PropertyRecord*>(oldRecord));
+        m_numericPropertySet->Remove(reclaimedId);
     }
     else
     {
@@ -236,37 +191,15 @@ ServerThreadContext::RemoveFromPropertyMap(Js::PropertyId reclaimedId)
 }
 
 void
-ServerThreadContext::AddToPropertyMap(const Js::PropertyRecord * origRecord)
+ServerThreadContext::AddToNumericPropertySet(Js::PropertyId propId)
 {
-    size_t allocLength = origRecord->byteCount + sizeof(char16) + (origRecord->isNumeric ? sizeof(uint32) : 0);
-    Js::PropertyRecord * record = HeapNewPlus(allocLength, Js::PropertyRecord, origRecord->byteCount, origRecord->isNumeric, origRecord->hash, origRecord->isSymbol);
-    record->isBound = origRecord->isBound;
-
-    char16* buffer = (char16 *)(record + 1);
-    js_memcpy_s(buffer, origRecord->byteCount, origRecord->GetBuffer(), origRecord->byteCount);
-
-    buffer[record->GetLength()] = _u('\0');
-
-    if (record->isNumeric)
-    {
-        *(uint32 *)(buffer + record->GetLength() + 1) = origRecord->GetNumericValue();
-        Assert(record->GetNumericValue() == origRecord->GetNumericValue());
-    }
-    record->pid = origRecord->pid;
-
-    const Js::PropertyRecord * oldRecord = nullptr;
-
     // this should only happen if there was reclaimed property that we failed to add to reclaimed list due to a prior oom
-    if (m_propertyMap->TryGetValue(origRecord->GetPropertyId(), &oldRecord))
+    if (m_numericPropertySet->ContainsKey(propId))
     {
-        m_propertyMap->Remove(oldRecord);
-        size_t oldLength = oldRecord->byteCount + sizeof(char16) + (oldRecord->isNumeric ? sizeof(uint32) : 0);
-        HeapDeletePlus(oldLength, const_cast<Js::PropertyRecord*>(oldRecord));
+        m_numericPropertySet->Remove(propId);
     }
 
-    m_propertyMap->Add(record);
-
-    PropertyRecordTrace(_u("Added JIT property '%s' at 0x%08x, pid = %d\n"), record->GetBuffer(), record, record->pid);
+    m_numericPropertySet->Add(propId);
 }
 
 void ServerThreadContext::AddRef()

+ 17 - 19
lib/Backend/ServerThreadContext.h

@@ -27,29 +27,25 @@ public:
     virtual intptr_t GetImplicitCallFlagsAddr() const override;
     virtual intptr_t GetBailOutRegisterSaveSpaceAddr() const override;
 
-    virtual intptr_t GetDebuggingFlagsAddr() const override;
-    virtual intptr_t GetDebugStepTypeAddr() const override;
-    virtual intptr_t GetDebugFrameAddressAddr() const override;
-    virtual intptr_t GetDebugScriptIdWhenSetAddr() const override;
+    virtual PreReservedVirtualAllocWrapper * GetPreReservedVirtualAllocator() override;
+
+    virtual bool IsNumericProperty(Js::PropertyId propId) override;
 
     ptrdiff_t GetChakraBaseAddressDifference() const;
     ptrdiff_t GetCRTBaseAddressDifference() const;
 
-    virtual Js::PropertyRecord const * GetPropertyRecord(Js::PropertyId propertyId) override;
-    virtual PreReservedVirtualAllocWrapper * GetPreReservedVirtualAllocator() override;
-
     CodeGenAllocators * GetCodeGenAllocators();
-    AllocationPolicyManager * GetAllocationPolicyManager();
     CustomHeap::CodePageAllocators * GetCodePageAllocators();
-    PageAllocator* GetPageAllocator();
-    void RemoveFromPropertyMap(Js::PropertyId reclaimedId);
-    void AddToPropertyMap(const Js::PropertyRecord * propertyRecord);
+    void RemoveFromNumericPropertySet(Js::PropertyId reclaimedId);
+    void AddToNumericPropertySet(Js::PropertyId propertyId);
     void SetWellKnownHostTypeId(Js::TypeId typeId) { this->wellKnownHostTypeHTMLAllCollectionTypeId = typeId; }
-
+#if DYNAMIC_INTERPRETER_THUNK || defined(ASMJS_PLAT)
+    CustomHeap::CodePageAllocators * GetThunkPageAllocators();
+#endif
     void AddRef();
     void Release();
     void Close();
-
+    PageAllocator * GetForegroundPageAllocator();
 #ifdef STACK_BACK_TRACE
     DWORD GetRuntimePid() { return m_pid; }
 #endif
@@ -58,15 +54,18 @@ private:
     intptr_t GetRuntimeChakraBaseAddress() const;
     intptr_t GetRuntimeCRTBaseAddress() const;
 
-    typedef JsUtil::BaseHashSet<const Js::PropertyRecord *, HeapAllocator, PrimeSizePolicy, const Js::PropertyRecord *,
-        DefaultComparer, JsUtil::SimpleHashedEntry, JsUtil::AsymetricResizeLock> PropertyMap;
-    PropertyMap * m_propertyMap;
+    typedef JsUtil::BaseHashSet<Js::PropertyId, HeapAllocator, PrimeSizePolicy, Js::PropertyId,
+        DefaultComparer, JsUtil::SimpleHashedEntry, JsUtil::AsymetricResizeLock> PropertySet;
+    PropertySet * m_numericPropertySet;
 
-    AllocationPolicyManager m_policyManager;
-    JsUtil::BaseDictionary<DWORD, PageAllocator*, HeapAllocator> m_pageAllocs;
     PreReservedVirtualAllocWrapper m_preReservedVirtualAllocator;
+#if DYNAMIC_INTERPRETER_THUNK || defined(ASMJS_PLAT)
+    CustomHeap::CodePageAllocators m_thunkPageAllocators;
+#endif
     CustomHeap::CodePageAllocators m_codePageAllocators;
     CodeGenAllocators m_codeGenAlloc;
+    // only allocate with this from foreground calls (never from CodeGen calls)
+    PageAllocator m_pageAlloc;
 
     ThreadContextDataIDL m_threadContextData;
 
@@ -75,5 +74,4 @@ private:
     intptr_t m_jitChakraBaseAddress;
     intptr_t m_jitCRTBaseAddress;
     uint m_refCount;
-
 };

+ 21 - 27
lib/Backend/Sym.cpp

@@ -46,10 +46,10 @@ StackSym::New(SymID id, IRType type, Js::RegSlot byteCodeRegSlot, Func *func)
     stackSym->m_isStrEmpty = false;
     stackSym->m_allocated = false;
     stackSym->m_isTypeSpec = false;
-	stackSym->m_isArgSlotSym = false;
-	stackSym->m_isArgSlotRegSym = false;
-	stackSym->m_isParamSym = false;
-	stackSym->m_isImplicitParamSym = false;
+    stackSym->m_isArgSlotSym = false;
+    stackSym->m_isArgSlotRegSym = false;
+    stackSym->m_isParamSym = false;
+    stackSym->m_isImplicitParamSym = false;
     stackSym->m_isBailOutReferenced = false;
     stackSym->m_isArgCaptured = false;
     stackSym->m_requiresBailOnNotNumber = false;
@@ -116,20 +116,20 @@ StackSym::New(IRType type, Func *func)
 StackSym *
 StackSym::NewImplicitParamSym(Js::ArgSlot paramSlotNum, Func * func)
 {
-	return func->m_symTable->GetImplicitParam(paramSlotNum);
+    return func->m_symTable->GetImplicitParam(paramSlotNum);
 }
 
 StackSym *
 StackSym::NewParamSlotSym(Js::ArgSlot paramSlotNum, Func * func)
 {
-	return NewParamSlotSym(paramSlotNum, func, TyVar);
+    return NewParamSlotSym(paramSlotNum, func, TyVar);
 }
 
 StackSym *
 StackSym::NewParamSlotSym(Js::ArgSlot paramSlotNum, Func * func, IRType type)
 {
     StackSym * stackSym = StackSym::New(type, func);
-	stackSym->m_isParamSym = true;
+    stackSym->m_isParamSym = true;
     stackSym->m_slotNum = paramSlotNum;
     return stackSym;
 }
@@ -486,10 +486,10 @@ StackSym::CloneDef(Func *func)
         newSym->m_isConst = m_isConst;
         newSym->m_isIntConst = m_isIntConst;
         newSym->m_isTaggableIntConst = m_isTaggableIntConst;
-		newSym->m_isArgSlotSym = m_isArgSlotSym;
-		newSym->m_isArgSlotRegSym = m_isArgSlotRegSym;
-		newSym->m_isParamSym = m_isParamSym;
-		newSym->m_isImplicitParamSym = m_isImplicitParamSym;
+        newSym->m_isArgSlotSym = m_isArgSlotSym;
+        newSym->m_isArgSlotRegSym = m_isArgSlotRegSym;
+        newSym->m_isParamSym = m_isParamSym;
+        newSym->m_isImplicitParamSym = m_isImplicitParamSym;
         newSym->m_isArgCaptured = m_isArgCaptured;
         newSym->m_isBailOutReferenced = m_isBailOutReferenced;
         newSym->m_slotNum = m_slotNum;
@@ -1006,17 +1006,6 @@ PropertySym::FindOrCreate(SymID stackSymID, int32 propertyId, uint32 propertyIdI
 
     return PropertySym::New(stackSymID, propertyId, propertyIdIndex, inlineCacheIndex, fieldKind, func);
 }
-#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
-const char16* PropertySym::GetName() const
-{
-    if (this->m_fieldKind == PropertyKindData)
-    {
-        return m_func->GetThreadContextInfo()->GetPropertyRecord(this->m_propertyId)->GetBuffer();
-    }
-    Assert(false);
-    return _u("");
-}
-#endif
 #if DBG_DUMP || defined(ENABLE_IR_VIEWER)
 
 ///----------------------------------------------------------------------------
@@ -1100,7 +1089,7 @@ Sym::Dump(IRDumpFlags flags, const ValueType valueType)
                         {
                             uint index = stackSym->GetByteCodeRegSlot() - stackSym->GetByteCodeFunc()->GetJITFunctionBody()->GetConstCount();
                             Js::PropertyId propertyId = functionBody->GetPropertyIdOnRegSlotsContainer()->propertyIdsForRegSlots[index];
-                            Output::Print(_u("(%s)"), stackSym->GetByteCodeFunc()->GetThreadContextInfo()->GetPropertyRecord(propertyId)->GetBuffer());
+                            Output::Print(_u("(%s)"), stackSym->GetByteCodeFunc()->GetInProcThreadContext()->GetPropertyRecord(propertyId)->GetBuffer());
                         }
                     }
                 }
@@ -1142,12 +1131,17 @@ Sym::Dump(IRDumpFlags flags, const ValueType valueType)
         switch (propertySym->m_fieldKind)
         {
         case PropertyKindData:
-        {
             propertySym->m_stackSym->Dump(flags, valueType);
-            Js::PropertyRecord const* fieldName = propertySym->m_func->GetThreadContextInfo()->GetPropertyRecord(propertySym->m_propertyId);
-            Output::Print(_u("->%s"), fieldName->GetBuffer());
+            if (JITManager::GetJITManager()->IsOOPJITEnabled())
+            {
+                Output::Print(_u("->#%d"), propertySym->m_propertyId);
+            }
+            else
+            {
+                Js::PropertyRecord const* fieldName = propertySym->m_func->GetInProcThreadContext()->GetPropertyRecord(propertySym->m_propertyId);
+                Output::Print(_u("->%s"), fieldName->GetBuffer());
+            }
             break;
-        }
         case PropertyKindSlots:
         case PropertyKindSlotArray:
             propertySym->m_stackSym->Dump(flags, valueType);

+ 8 - 11
lib/Backend/Sym.h

@@ -91,7 +91,7 @@ public:
     static StackSym * NewArgSlotRegSym(Js::ArgSlot argSlotNum, Func * func, IRType = TyVar);
     static StackSym * NewParamSlotSym(Js::ArgSlot argSlotNum, Func * func);
     static StackSym * NewParamSlotSym(Js::ArgSlot argSlotNum, Func * func, IRType type);
-	static StackSym *NewImplicitParamSym(Js::ArgSlot paramSlotNum, Func * func);
+    static StackSym *NewImplicitParamSym(Js::ArgSlot paramSlotNum, Func * func);
     static StackSym * New(SymID id, IRType type, Js::RegSlot byteCodeRegSlot, Func *func);
     static StackSym * New(IRType type, Func *func);
     static StackSym * New(Func *func);
@@ -99,8 +99,8 @@ public:
 
     IRType          GetType() const { return this->m_type; }
     bool            IsArgSlotSym() const;
-	bool            IsParamSlotSym() const;
-	bool            IsImplicitParamSym() const { return this->m_isImplicitParamSym; }
+    bool            IsParamSlotSym() const;
+    bool            IsImplicitParamSym() const { return this->m_isImplicitParamSym; }
     bool            IsAllocated() const;
     int32           GetIntConstValue() const;
     Js::Var         GetFloatConstValueAsVar_PostGlobOpt() const;
@@ -196,7 +196,7 @@ private:
     Js::ArgSlot     m_slotNum;
 public:
     uint8           m_isSingleDef:1;            // the symbol only has a single definition in the IR
-	uint8           m_isNotInt:1;
+    uint8           m_isNotInt:1;
     uint8           m_isSafeThis : 1;
     uint8           m_isConst : 1;              // single def and it is a constant
     uint8           m_isIntConst : 1;           // a constant and it's value is an Int32
@@ -216,10 +216,10 @@ public:
     uint8           m_isFromByteCodeConstantTable:1;
     uint8           m_mayNotBeTempLastUse:1;
     uint8           m_isArgSlotSym: 1;        // When set this implies an argument stack slot with no lifetime for register allocation
-	uint8           m_isArgSlotRegSym : 1;
-	uint8           m_isParamSym : 1;
-	uint8           m_isImplicitParamSym : 1;
-	uint8           m_isBailOutReferenced: 1;        // argument sym referenced by bailout
+    uint8           m_isArgSlotRegSym : 1;
+    uint8           m_isParamSym : 1;
+    uint8           m_isImplicitParamSym : 1;
+    uint8           m_isBailOutReferenced: 1;        // argument sym referenced by bailout
     uint8           m_isArgCaptured: 1;       // True if there is a ByteCodeArgOutCapture for this symbol
     uint8           m_nonEscapingArgObjAlias : 1;
     uint8           m_isCatchObjectSym : 1;   // a catch object sym (used while jitting loop bodies)
@@ -319,9 +319,6 @@ public:
     Func *          m_func;
     Func *          m_loadInlineCacheFunc;
     uint            m_loadInlineCacheIndex;
-#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
-    const char16* GetName() const;
-#endif
 private:
     uint32          m_propertyIdIndex;
     uint            m_inlineCacheIndex;

+ 7 - 10
lib/Backend/TempTracker.cpp

@@ -263,9 +263,8 @@ TempTracker<T>::ProcessUse(StackSym * sym, BackwardPass * backwardPass)
 #if DBG_DUMP
         if (T::DoTrace(backwardPass) && this->tempTransferDependencies)
         {
-            Output::Print(_u("%s: %8s (PropId:%d %s)+[] -> s%d: "), T::GetTraceName(),
-                backwardPass->IsPrePass() ? _u("Prepass ") : _u(""), propertySym->m_propertyId,
-                backwardPass->func->GetThreadContextInfo()->GetPropertyRecord(propertySym->m_propertyId)->GetBuffer(), usedSymID);
+            Output::Print(_u("%s: %8s (PropId:%d)+[] -> s%d: "), T::GetTraceName(),
+                backwardPass->IsPrePass() ? _u("Prepass ") : _u(""), propertySym->m_propertyId, usedSymID);
             BVSparse<JitArenaAllocator> ** transferDependencies = this->tempTransferDependencies->Get(usedSymID);
             if (transferDependencies)
             {
@@ -712,7 +711,7 @@ NumberTemp::IsTempPropertyTransferStore(IR::Instr * instr, BackwardPass * backwa
                 PropertySym *propertySym = dst->AsSymOpnd()->m_sym->AsPropertySym();
                 SymID propertySymId = this->GetRepresentativePropertySymId(propertySym, backwardPass);
                 return !this->nonTempSyms.Test(propertySymId) &&
-                    !instr->m_func->GetThreadContextInfo()->GetPropertyRecord(propertySym->m_propertyId)->IsNumeric();
+                    !instr->m_func->GetThreadContextInfo()->IsNumericProperty(propertySym->m_propertyId);
             }
         };
 
@@ -914,9 +913,8 @@ NumberTemp::ProcessPropertySymUse(IR::SymOpnd * symOpnd, IR::Instr * instr, Back
 #if DBG_DUMP
         if (NumberTemp::DoTrace(backwardPass))
         {
-            Output::Print(_u("%s: %8s s%d -> PropId:%d %s: "), NumberTemp::GetTraceName(),
-                backwardPass->IsPrePass() ? _u("Prepass ") : _u(""), dstSymID, propertySym->m_propertyId,
-                backwardPass->func->GetThreadContextInfo()->GetPropertyRecord(propertySym->m_propertyId)->GetBuffer());
+            Output::Print(_u("%s: %8s s%d -> PropId:%d: "), NumberTemp::GetTraceName(),
+                backwardPass->IsPrePass() ? _u("Prepass ") : _u(""), dstSymID, propertySym->m_propertyId);
             (*this->propertyIdsTempTransferDependencies->Get(propertySym->m_propertyId))->Dump();
         }
 #endif
@@ -925,9 +923,8 @@ NumberTemp::ProcessPropertySymUse(IR::SymOpnd * symOpnd, IR::Instr * instr, Back
 #if DBG_DUMP
     if (NumberTemp::DoTrace(backwardPass))
     {
-        Output::Print(_u("%s: %8s%4sTemp Use (PropId:%d %s)"), NumberTemp::GetTraceName(),
-            backwardPass->IsPrePass() ? _u("Prepass ") : _u(""), isTempUse ? _u("") : _u("Non "), propertySym->m_propertyId,
-            backwardPass->func->GetThreadContextInfo()->GetPropertyRecord(propertySym->m_propertyId)->GetBuffer());
+        Output::Print(_u("%s: %8s%4sTemp Use (PropId:%d)"), NumberTemp::GetTraceName(),
+            backwardPass->IsPrePass() ? _u("Prepass ") : _u(""), isTempUse ? _u("") : _u("Non "), propertySym->m_propertyId);
         instr->DumpSimple();
     }
 #endif

+ 2 - 11
lib/Backend/i386/EncoderMD.cpp

@@ -921,7 +921,7 @@ modrm:
             {
                 AppendRelocEntry(RelocTypeCallPcrel, (void*)m_pc, nullptr, (void*)opr1->AsIntConstOpnd()->GetValue());
                 this->EmitConst(0, 4);
-                AssertMsg( ( ((BYTE*)opr1->AsIntConstOpnd()->GetValue()) < m_encoder->m_encodeBuffer || ((BYTE *)opr1->AsIntConstOpnd()->GetValue()) >= m_encoder->m_encodeBuffer + m_encoder->m_encodeBufferSize), "Call Target within buffer.");
+                AssertMsg(m_func->IsOOPJIT() || ( ((BYTE*)opr1->AsIntConstOpnd()->GetValue()) < m_encoder->m_encodeBuffer || ((BYTE *)opr1->AsIntConstOpnd()->GetValue()) >= m_encoder->m_encodeBuffer + m_encoder->m_encodeBufferSize), "Call Target within buffer.");
             }
             else if (opr1->IsHelperCallOpnd())
             {
@@ -929,16 +929,7 @@ modrm:
                 AppendRelocEntry(RelocTypeCallPcrel, (void*)m_pc, nullptr, fnAddress);
                 AssertMsg(sizeof(uint32) == sizeof(void*), "Sizes of void* assumed to be 32-bits");
                 this->EmitConst(0, 4);
-#if DBG
-                if (this->m_func->IsOOPJIT())
-                {
-                    // TODO: OOP JIT, use the helper function address from JIT process to do the assertion
-                }
-                else
-                {
-                    AssertMsg((((BYTE*)fnAddress) < m_encoder->m_encodeBuffer || ((BYTE *)fnAddress) >= m_encoder->m_encodeBuffer + m_encoder->m_encodeBufferSize), "Call Target within buffer.");
-                }
-#endif
+                AssertMsg(m_func->IsOOPJIT() || (((BYTE*)fnAddress) < m_encoder->m_encodeBuffer || ((BYTE *)fnAddress) >= m_encoder->m_encodeBuffer + m_encoder->m_encodeBufferSize), "Call Target within buffer.");
             }
             else
             {

+ 2 - 1
lib/Common/ChakraCoreVersion.h

@@ -17,7 +17,8 @@
 // ChakraCore version number definitions (used in ChakraCore binary metadata)
 #define CHAKRA_CORE_MAJOR_VERSION 1
 #define CHAKRA_CORE_MINOR_VERSION 4
-#define CHAKRA_CORE_VERSION_RELEASE_QFE 0
+#define CHAKRA_CORE_PATCH_VERSION 0
+#define CHAKRA_CORE_VERSION_RELEASE_QFE 0 // Redundant with PATCH_VERSION. Keep this value set to 0.
 
 // -------------
 // RELEASE FLAGS

+ 12 - 1
lib/Common/ConfigFlagsList.h

@@ -580,7 +580,12 @@ PHASE(All)
 #define DEFAULT_CONFIG_ES7TrailingComma        (true)
 #define DEFAULT_CONFIG_ES7ValuesEntries        (true)
 #define DEFAULT_CONFIG_ESObjectGetOwnPropertyDescriptors (true)
+
+#ifdef COMPILE_DISABLE_ESSharedArrayBuffer
+#define DEFAULT_CONFIG_ESSharedArrayBuffer     (false)
+#else
 #define DEFAULT_CONFIG_ESSharedArrayBuffer     (false)
+#endif
 #define DEFAULT_CONFIG_ES6Verbose              (false)
 #define DEFAULT_CONFIG_ES6All                  (false)
 // ES6 DEFAULT BEHAVIOR
@@ -795,7 +800,7 @@ PHASE(All)
 // Release flags with parent and acronym
 #ifndef FLAGPRA
 #define FLAGPRA(Type, ParentName, Name, Acronym, String, Default) \
-        FLAGPR(Type, ParentName, Name, String, Default) \
+        FLAG_REGOVR_EXP(Type, Name, String, Default, ParentName, FALSE) \
         FLAGNR(Type, Acronym, String, Default)
 #endif
 
@@ -1027,6 +1032,10 @@ FLAGPR           (Boolean, ES6, ES6Verbose             , "Enable ES6 verbose tra
 FLAGPR_REGOVR_EXP(Boolean, ES6, ArrayBufferTransfer    , "Enable ArrayBuffer.transfer"                              , DEFAULT_CONFIG_ArrayBufferTransfer)
 
 FLAGPR           (Boolean, ES6, ESObjectGetOwnPropertyDescriptors, "Enable Object.getOwnPropertyDescriptors"        , DEFAULT_CONFIG_ESObjectGetOwnPropertyDescriptors)
+
+#ifndef COMPILE_DISABLE_ESSharedArrayBuffer
+    #define COMPILE_DISABLE_ESSharedArrayBuffer 0
+#endif
 FLAGPRA          (Boolean, ES6, ESSharedArrayBuffer    , sab     , "Enable SharedArrayBuffer"                       , DEFAULT_CONFIG_ESSharedArrayBuffer)
 
 // /ES6 (BLUE+1) features/flags
@@ -1479,6 +1488,8 @@ FLAGNR(Boolean, CFG, "Force enable CFG on jshost. version in the jshost's manife
     FLAGNR(Number, SimulatePolyCacheWithOneTypeForInlineCacheIndex, "Use with SimulatePolyCacheWithOneTypeForFunction to simulate creating a polymorphic inline cache containing only one type due to a collision, for testing ObjTypeSpec", -1)
 #endif
 
+FLAGR(Number, JITServerIdleTimeout, "Idle timeout in seconds to do the cleanup in JIT server", 10)
+FLAGR(Number, JITServerMaxInactivePageAllocatorCount, "Max inactive page allocators to keep before schedule a cleanup", 10)
 #undef FLAG_REGOVR_EXP
 #undef FLAG_REGOVR_ASMJS
 

+ 29 - 18
lib/Common/Memory/CustomHeap.cpp

@@ -1053,31 +1053,42 @@ void FillDebugBreak(_In_ BYTE* buffer, __in size_t byteCount, HANDLE processHand
     CompileAssert(sizeof(char16) == 2);
     char16 pattern = 0xDEFE;
 
-    const bool isLocalProc = processHandle == GetCurrentProcess();
-    BYTE * writeBuffer;
-
-    if (isLocalProc)
+    if (processHandle == GetCurrentProcess())
     {
-        writeBuffer = buffer;
+        BYTE * writeBuffer = buffer;
+        wmemset((char16 *)writeBuffer, pattern, byteCount / 2);
+        if (byteCount % 2)
+        {
+            // Note: this is valid scenario: in JIT mode, we may not be 2-byte-aligned in the end of unwind info.
+            *(writeBuffer + byteCount - 1) = 0;  // Fill last remaining byte.
+        }
     }
     else
     {
-        writeBuffer = HeapNewArray(BYTE, byteCount);
-    }
-    wmemset((char16 *)writeBuffer, pattern, byteCount / 2);
-    if (byteCount % 2)
-    {
-        // Note: this is valid scenario: in JIT mode, we may not be 2-byte-aligned in the end of unwind info.
-        *(writeBuffer + byteCount - 1) = 0;  // Fill last remaining byte.
-    }
+        const size_t bufferSize = 0x1000;
+        byte localBuffer[bufferSize];
+        wmemset((char16 *)localBuffer, pattern, (bufferSize < byteCount ? bufferSize : byteCount) / 2);
 
-    if (!isLocalProc)
-    {
-        if (!WriteProcessMemory(processHandle, buffer, writeBuffer, byteCount, NULL))
+        for (size_t i = 0; i < byteCount / bufferSize; i++)
         {
-            MemoryOperationLastError::RecordLastErrorAndThrow();
+            if (!WriteProcessMemory(processHandle, buffer, localBuffer, bufferSize, NULL))
+            {
+                MemoryOperationLastError::CheckProcessAndThrowFatalError(processHandle);
+            }
+            buffer += bufferSize;
+        }
+
+        if (byteCount % bufferSize > 0)
+        {
+            if (byteCount % 2 != 0)
+            {
+                localBuffer[(byteCount - 1) % bufferSize] = 0;
+            }
+            if (!WriteProcessMemory(processHandle, buffer, localBuffer, byteCount % bufferSize, NULL))
+            {
+                MemoryOperationLastError::CheckProcessAndThrowFatalError(processHandle);
+            }
         }
-        HeapDeleteArray(byteCount, writeBuffer);
     }
 
 #elif defined(_M_ARM64)

+ 68 - 0
lib/JITClient/JITManager.cpp

@@ -373,6 +373,49 @@ JITManager::SetIsPRNGSeeded(
 
 }
 
+HRESULT
+JITManager::DecommitInterpreterBufferManager(
+    __in intptr_t scriptContextInfoAddress,
+    __in boolean asmJsThunk)
+{
+    Assert(IsOOPJITEnabled());
+
+    HRESULT hr = E_FAIL;
+    RpcTryExcept
+    {
+        hr = ClientDecommitInterpreterBufferManager(m_rpcBindingHandle, scriptContextInfoAddress, asmJsThunk);
+    }
+    RpcExcept(RpcExceptionFilter(RpcExceptionCode()))
+    {
+        hr = HRESULT_FROM_WIN32(RpcExceptionCode());
+    }
+    RpcEndExcept;
+
+    return hr;
+}
+
+HRESULT
+JITManager::NewInterpreterThunkBlock(
+    __in intptr_t scriptContextInfoAddress,
+    __in boolean asmJsThunk,
+    __out InterpreterThunkInfoIDL * thunkInfo)
+{
+    Assert(IsOOPJITEnabled());
+
+    HRESULT hr = E_FAIL;
+    RpcTryExcept
+    {
+        hr = ClientNewInterpreterThunkBlock(m_rpcBindingHandle, scriptContextInfoAddress, asmJsThunk, thunkInfo);
+    }
+    RpcExcept(RpcExceptionFilter(RpcExceptionCode()))
+    {
+        hr = HRESULT_FROM_WIN32(RpcExceptionCode());
+    }
+    RpcEndExcept;
+
+    return hr;
+}
+
 HRESULT 
 JITManager::AddModuleRecordInfo(
     /* [in] */ intptr_t scriptContextInfoAddress,
@@ -523,6 +566,31 @@ JITManager::FreeAllocation(
     return hr;
 }
 
+#if DBG
+HRESULT
+JITManager::IsInterpreterThunkAddr(
+    __in intptr_t scriptContextInfoAddress,
+    __in intptr_t address,
+    __in boolean asmjsThunk,
+    __out boolean * result)
+{
+    Assert(IsOOPJITEnabled());
+
+    HRESULT hr = E_FAIL;
+    RpcTryExcept
+    {
+        hr = ClientIsInterpreterThunkAddr(m_rpcBindingHandle, scriptContextInfoAddress, address, asmjsThunk, result);
+    }
+        RpcExcept(RpcExceptionFilter(RpcExceptionCode()))
+    {
+        hr = HRESULT_FROM_WIN32(RpcExceptionCode());
+    }
+    RpcEndExcept;
+
+    return hr;
+}
+#endif
+
 HRESULT
 JITManager::IsNativeAddr(
     __in intptr_t threadContextInfoAddress,

+ 17 - 0
lib/JITClient/JITManager.h

@@ -33,6 +33,15 @@ public:
         __in intptr_t threadContextInfoAddress,
         __in UpdatedPropertysIDL * updatedProps);
 
+    HRESULT DecommitInterpreterBufferManager(
+        __in intptr_t scriptContextInfoAddress,
+        __in boolean asmJsThunk);
+
+    HRESULT NewInterpreterThunkBlock(
+        __in intptr_t scriptContextInfoAddress,
+        __in boolean asmJsThunk,
+        __out InterpreterThunkInfoIDL * thunkInfo);
+
     HRESULT AddDOMFastPathHelper(
         __in intptr_t scriptContextInfoAddress,
         __in intptr_t funcInfoAddr,
@@ -78,6 +87,14 @@ public:
         __in intptr_t scriptContextInfoAddress,
         __out JITOutputIDL *jitData);
 
+#if DBG
+    HRESULT IsInterpreterThunkAddr(
+        __in intptr_t scriptContextInfoAddress,
+        __in intptr_t address,
+        __in boolean asmjsThunk,
+        __out boolean * result);
+#endif
+
     HRESULT Shutdown();
 
 

+ 19 - 0
lib/JITIDL/ChakraJIT.idl

@@ -68,6 +68,17 @@ interface IChakraJIT
         [in] CHAKRA_PTR threadContextInfoAddress,
         [in] CHAKRA_PTR address);
 
+    HRESULT NewInterpreterThunkBlock(
+        [in] handle_t binding,
+        [in] CHAKRA_PTR scriptContextInfoAddress,
+        [in] boolean asmJsThunk,
+        [out] InterpreterThunkInfoIDL * thunkInfo);
+
+    HRESULT DecommitInterpreterBufferManager(
+        [in] handle_t binding,
+        [in] CHAKRA_PTR scriptContextInfoAddress,
+        [in] boolean asmJsManager);
+
     HRESULT IsNativeAddr(
         [in] handle_t binding,
         [in] CHAKRA_PTR threadContextInfoAddress,
@@ -85,4 +96,12 @@ interface IChakraJIT
         [in] CodeGenWorkItemIDL * workItemData,
         [out] JITOutputIDL * jitData);
 
+#if DBG
+    HRESULT IsInterpreterThunkAddr(
+        [in] handle_t binding,
+        [in] CHAKRA_PTR scriptContextInfoAddress,
+        [in] CHAKRA_PTR address,
+        [in] boolean asmjsThunk,
+        [out] boolean * result);
+#endif
 }

+ 15 - 19
lib/JITIDL/JITTypes.h

@@ -283,10 +283,6 @@ typedef struct ThreadContextDataIDL
     CHAKRA_PTR bailOutRegisterSaveSpaceAddr;
     CHAKRA_PTR disableImplicitFlagsAddr;
     CHAKRA_PTR implicitCallFlagsAddr;
-    CHAKRA_PTR debuggingFlagsAddr;
-    CHAKRA_PTR debugStepTypeAddr;
-    CHAKRA_PTR debugFrameAddressAddr;
-    CHAKRA_PTR debugScriptIdWhenSetAddr;
     CHAKRA_PTR stringReplaceNameAddr;
     CHAKRA_PTR stringMatchNameAddr;
     CHAKRA_PTR simdTempAreaBaseAddr;
@@ -328,6 +324,10 @@ typedef struct ScriptContextDataIDL
     CHAKRA_PTR numberAllocatorAddr;
     CHAKRA_PTR recyclerAddr;
     CHAKRA_PTR builtinFunctionsBaseAddr;
+    CHAKRA_PTR debuggingFlagsAddr;
+    CHAKRA_PTR debugStepTypeAddr;
+    CHAKRA_PTR debugFrameAddressAddr;
+    CHAKRA_PTR debugScriptIdWhenSetAddr;
 } ScriptContextDataIDL;
 
 typedef struct SmallSpanSequenceIDL
@@ -383,19 +383,6 @@ typedef struct AsmJsDataIDL
     IDL_DEF([size_is(argCount)]) byte * argTypeArray;
 } AsmJsDataIDL;
 
-typedef struct PropertyRecordIDL
-{
-    CHAKRA_PTR vTable;
-    int pid;
-    unsigned int hash;
-    boolean isNumeric;
-    boolean isBound;
-    boolean isSymbol;
-    IDL_PAD1(0)
-    unsigned int byteCount;
-    IDL_DEF([size_is(byteCount + sizeof(wchar_t) + (isNumeric ? sizeof(unsigned int) : 0))]) byte buffer[IDL_DEF(*)];
-} PropertyRecordIDL;
-
 typedef struct FunctionJITRuntimeIDL
 {
     unsigned int clonedCacheCount;
@@ -798,7 +785,16 @@ typedef struct JITOutputIDL
 typedef struct UpdatedPropertysIDL
 {
     unsigned int reclaimedPropertyCount;
-    unsigned int newRecordCount;
+    unsigned int newPropertyCount;
     [size_is(reclaimedPropertyCount)] int * reclaimedPropertyIdArray;
-    [size_is(newRecordCount)] PropertyRecordIDL ** newRecordArray;
+    [size_is(newPropertyCount)] int * newPropertyIdArray;
 } UpdatedPropertysIDL;
+
+typedef struct InterpreterThunkInfoIDL
+{
+    unsigned int thunkCount;
+    X64_PAD4(0)
+    CHAKRA_PTR pdataTableStart;
+    CHAKRA_PTR epilogEndAddr;
+    CHAKRA_PTR thunkBlockAddr;
+} InterpreterThunkInfoIDL;

+ 182 - 21
lib/JITServer/JITServer.cpp

@@ -51,6 +51,7 @@ HRESULT JsInitializeJITServer(
     {
         return status;
     }
+
     status = RpcServerInqBindings(&bindingVector);
     if (status != RPC_S_OK)
     {
@@ -62,14 +63,20 @@ HRESULT JsInitializeJITServer(
         bindingVector,
         &uuidVector,
         NULL);
+    if (status != RPC_S_OK)
+    {
+        return status;
+    }
 
-    RpcBindingVectorFree(&bindingVector);
+    status = RpcBindingVectorFree(&bindingVector);
 
     if (status != RPC_S_OK)
     {
         return status;
     }
+
     JITManager::GetJITManager()->SetIsJITServer();
+    PageAllocatorPool::Initialize();
 
     status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, FALSE);
 
@@ -88,6 +95,7 @@ ShutdownCommon()
     status = RpcServerUnregisterIf(ServerIChakraJIT_v0_0_s_ifspec, NULL, FALSE);
 
     ServerContextManager::Shutdown();
+    PageAllocatorPool::Shutdown();
     return status;
 }
 
@@ -131,15 +139,18 @@ ServerInitializeThreadContext(
     /* [out] */ __RPC__out intptr_t *threadContextRoot,
     /* [out] */ __RPC__out intptr_t *prereservedRegionAddr)
 {
-    AUTO_NESTED_HANDLED_EXCEPTION_TYPE(static_cast<ExceptionType>(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
-
-    ServerThreadContext * contextInfo = HeapNewNoThrow(ServerThreadContext, threadContextData);
-    if (contextInfo == nullptr)
+    ServerThreadContext * contextInfo = nullptr;
+    try
+    {
+        AUTO_NESTED_HANDLED_EXCEPTION_TYPE(static_cast<ExceptionType>(ExceptionType_OutOfMemory));
+        contextInfo = HeapNew(ServerThreadContext, threadContextData);
+        ServerContextManager::RegisterThreadContext(contextInfo);
+    }
+    catch (Js::OutOfMemoryException)
     {
         return E_OUTOFMEMORY;
     }
 
-    ServerContextManager::RegisterThreadContext(contextInfo);
     return ServerCallWrapper(contextInfo, [&]()->HRESULT
     {
         *threadContextRoot = (intptr_t)EncodePointer(contextInfo);
@@ -175,8 +186,6 @@ ServerUpdatePropertyRecordMap(
     /* [in] */ intptr_t threadContextInfoAddress,
     /* [in] */ __RPC__in UpdatedPropertysIDL * updatedProps)
 {
-    AUTO_NESTED_HANDLED_EXCEPTION_TYPE(static_cast<ExceptionType>(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
-
     ServerThreadContext * threadContextInfo = (ServerThreadContext*)DecodePointer((void*)threadContextInfoAddress);
 
     if (threadContextInfo == nullptr)
@@ -189,12 +198,12 @@ ServerUpdatePropertyRecordMap(
     {
         for (uint i = 0; i < updatedProps->reclaimedPropertyCount; ++i)
         {
-            threadContextInfo->RemoveFromPropertyMap((Js::PropertyId)updatedProps->reclaimedPropertyIdArray[i]);
+            threadContextInfo->RemoveFromNumericPropertySet((Js::PropertyId)updatedProps->reclaimedPropertyIdArray[i]);
         }
 
-        for (uint i = 0; i < updatedProps->newRecordCount; ++i)
+        for (uint i = 0; i < updatedProps->newPropertyCount; ++i)
         {
-            threadContextInfo->AddToPropertyMap((Js::PropertyRecord *)updatedProps->newRecordArray[i]);
+            threadContextInfo->AddToNumericPropertySet((Js::PropertyId)updatedProps->newPropertyIdArray[i]);
         }
 
         return S_OK;
@@ -208,8 +217,6 @@ ServerAddDOMFastPathHelper(
     /* [in] */ intptr_t funcInfoAddr,
     /* [in] */ int helper)
 {
-    AUTO_NESTED_HANDLED_EXCEPTION_TYPE(static_cast<ExceptionType>(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
-
     ServerScriptContext * scriptContextInfo = (ServerScriptContext*)DecodePointer((void*)scriptContextRoot);
 
     if (scriptContextInfo == nullptr)
@@ -232,8 +239,6 @@ ServerAddModuleRecordInfo(
     /* [in] */ unsigned int moduleId,
     /* [in] */ intptr_t localExportSlotsAddr)
 {
-    AUTO_NESTED_HANDLED_EXCEPTION_TYPE(static_cast<ExceptionType>(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
-
     ServerScriptContext * serverScriptContext = (ServerScriptContext*)DecodePointer((void*)scriptContextInfoAddress);
     if (serverScriptContext == nullptr)
     {
@@ -277,8 +282,6 @@ ServerInitializeScriptContext(
     /* [in] */ intptr_t threadContextInfoAddress,
     /* [out] */ __RPC__out intptr_t * scriptContextInfoAddress)
 {
-    AUTO_NESTED_HANDLED_EXCEPTION_TYPE(static_cast<ExceptionType>(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
-
     ServerThreadContext * threadContextInfo = (ServerThreadContext*)DecodePointer((void*)threadContextInfoAddress);
 
     *scriptContextInfoAddress = 0;
@@ -350,6 +353,110 @@ ServerCloseScriptContext(
     });
 }
 
+HRESULT
+ServerDecommitInterpreterBufferManager(
+    /* [in] */ handle_t binding,
+    /* [in] */ intptr_t scriptContextInfoAddress,
+    /* [in] */ boolean asmJsManager)
+{
+    ServerScriptContext * scriptContext = (ServerScriptContext *)DecodePointer((void*)scriptContextInfoAddress);
+
+    if (scriptContext == nullptr)
+    {
+        Assert(false);
+        return RPC_S_INVALID_ARG;
+    }
+
+    return ServerCallWrapper(scriptContext, [&]()->HRESULT
+    {
+        scriptContext->DecommitEmitBufferManager(asmJsManager != FALSE);
+        return S_OK;
+    });
+}
+
+HRESULT
+ServerNewInterpreterThunkBlock(
+    /* [in] */ handle_t binding,
+    /* [in] */ intptr_t scriptContextInfo,
+    /* [in] */ boolean asmJsThunk,
+    /* [out] */ __RPC__out InterpreterThunkInfoIDL * thunkInfo)
+{
+    ServerScriptContext * scriptContext = (ServerScriptContext *)DecodePointer((void*)scriptContextInfo);
+
+    memset(thunkInfo, 0, sizeof(InterpreterThunkInfoIDL));
+
+    if (scriptContext == nullptr)
+    {
+        Assert(false);
+        return RPC_S_INVALID_ARG;
+    }
+
+    return ServerCallWrapper(scriptContext, [&]()->HRESULT
+    {
+        const DWORD bufferSize = InterpreterThunkEmitter::BlockSize;
+        DWORD thunkCount = 0;
+
+#if PDATA_ENABLED
+        PRUNTIME_FUNCTION pdataStart;
+        intptr_t epilogEnd;
+#endif
+        ServerThreadContext * threadContext = scriptContext->GetThreadContext();
+        EmitBufferManager<> * emitBufferManager = scriptContext->GetEmitBufferManager(asmJsThunk != FALSE);
+
+        // REVIEW: OOP JIT should we clear arena at end?
+        ArenaAllocator * arena = scriptContext->GetSourceCodeArena();
+        BYTE * localBuffer = AnewArray(arena, BYTE, bufferSize);
+
+        BYTE* remoteBuffer;
+        EmitBufferAllocation * allocation = emitBufferManager->AllocateBuffer(bufferSize, &remoteBuffer);
+        if (!allocation)
+        {
+            Js::Throw::OutOfMemory();
+        }
+
+        InterpreterThunkEmitter::FillBuffer(
+            arena,
+            threadContext,
+            asmJsThunk != FALSE,
+            (intptr_t)remoteBuffer,
+            bufferSize,
+            localBuffer,
+#if PDATA_ENABLED
+            &pdataStart,
+            &epilogEnd,
+#endif
+            &thunkCount
+        );
+
+        if (!emitBufferManager->ProtectBufferWithExecuteReadWriteForInterpreter(allocation))
+        {
+            MemoryOperationLastError::CheckProcessAndThrowFatalError(threadContext->GetProcessHandle());
+        }
+
+        if (!WriteProcessMemory(threadContext->GetProcessHandle(), remoteBuffer, localBuffer, bufferSize, nullptr))
+        {
+            MemoryOperationLastError::CheckProcessAndThrowFatalError(threadContext->GetProcessHandle());
+        }
+
+        if (!emitBufferManager->CommitReadWriteBufferForInterpreter(allocation, remoteBuffer, bufferSize))
+        {
+            MemoryOperationLastError::CheckProcessAndThrowFatalError(threadContext->GetProcessHandle());
+        }
+
+        // Call to set VALID flag for CFG check
+        threadContext->SetValidCallTargetForCFG(remoteBuffer);
+
+        thunkInfo->thunkBlockAddr = (intptr_t)remoteBuffer;
+        thunkInfo->thunkCount = thunkCount;
+#if PDATA_ENABLED
+        thunkInfo->pdataTableStart = (intptr_t)pdataStart;
+        thunkInfo->epilogEndAddr = epilogEnd;
+#endif
+
+        return S_OK;
+    });
+}
+
 HRESULT
 ServerFreeAllocation(
     /* [in] */ handle_t binding,
@@ -372,6 +479,35 @@ ServerFreeAllocation(
     });
 }
 
+#if DBG
+HRESULT
+ServerIsInterpreterThunkAddr(
+    /* [in] */ handle_t binding,
+    /* [in] */ intptr_t scriptContextInfoAddress,
+    /* [in] */ intptr_t address,
+    /* [in] */ boolean asmjsThunk,
+    /* [out] */ __RPC__out boolean * result)
+{
+    ServerScriptContext * context = (ServerScriptContext*)DecodePointer((void*)scriptContextInfoAddress);
+
+    if (context == nullptr)
+    {
+        *result = false;
+        return RPC_S_INVALID_ARG;
+    }
+    EmitBufferManager<> * manager = context->GetEmitBufferManager(asmjsThunk != FALSE);
+    if (manager == nullptr)
+    {
+        *result = false;
+        return S_OK;
+    }
+
+    *result = manager->IsInHeap((void*)address);
+
+    return S_OK;
+}
+#endif
+
 HRESULT
 ServerIsNativeAddr(
     /* [in] */ handle_t binding,
@@ -437,8 +573,6 @@ ServerRemoteCodeGen(
     /* [in] */ __RPC__in CodeGenWorkItemIDL *workItemData,
     /* [out] */ __RPC__out JITOutputIDL *jitData)
 {
-    AUTO_NESTED_HANDLED_EXCEPTION_TYPE(static_cast<ExceptionType>(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
-
     memset(jitData, 0, sizeof(JITOutputIDL));
 
     ServerScriptContext * scriptContextInfo = (ServerScriptContext*)DecodePointer((void*)scriptContextInfoAddress);
@@ -460,7 +594,10 @@ ServerRemoteCodeGen(
         scriptContextInfo->UpdateGlobalObjectThisAddr(workItemData->globalThisAddr);
         ServerThreadContext * threadContextInfo = scriptContextInfo->GetThreadContext();
 
-        NoRecoverMemoryJitArenaAllocator jitArena(L"JITArena", threadContextInfo->GetPageAllocator(), Js::Throw::OutOfMemory);
+        AutoReturnPageAllocator autoReturnPageAllocator;
+        PageAllocator* pageAllocator = autoReturnPageAllocator.GetPageAllocator();
+
+        NoRecoverMemoryJitArenaAllocator jitArena(L"JITArena", pageAllocator, Js::Throw::OutOfMemory);
         JITTimeWorkItem * jitWorkItem = Anew(&jitArena, JITTimeWorkItem, workItemData);
 
         if (PHASE_VERBOSE_TRACE_RAW(Js::BackEndPhase, jitWorkItem->GetJITTimeInfo()->GetSourceContextId(), jitWorkItem->GetJITTimeInfo()->GetLocalFunctionId()))
@@ -481,7 +618,7 @@ ServerRemoteCodeGen(
 #ifdef PROFILE_EXEC
         if (profiler && !profiler->IsInitialized())
         {
-            profiler->Initialize(threadContextInfo->GetPageAllocator(), nullptr);
+            profiler->Initialize(pageAllocator, nullptr);
         }
 #endif
         if (jitWorkItem->GetWorkItemData()->xProcNumberPageSegment)
@@ -656,6 +793,29 @@ bool ServerContextManager::CheckLivenessAndAddref(ServerThreadContext* context)
     return false;
 }
 
+void ServerContextManager::IdleCleanup()
+{
+    JsUtil::BaseHashSet<HANDLE, HeapAllocator> clientProcesses(&HeapAllocator::Instance);
+    {
+        AutoCriticalSection autoCS(&cs);
+        threadContexts.Map([&clientProcesses](ServerThreadContext* threadContext)
+        {
+            if (!clientProcesses.ContainsKey(threadContext->GetProcessHandle()))
+            {
+                clientProcesses.Add(threadContext->GetProcessHandle());
+            }
+        });
+    }
+
+    clientProcesses.Map([](HANDLE hProcess)
+    {
+        DWORD exitCode = STILL_ACTIVE;
+        if (!GetExitCodeProcess(hProcess, &exitCode) && exitCode != STILL_ACTIVE)
+        {
+            CleanUpForProcess(hProcess);
+        }
+    });
+}
 
 template<typename Fn>
 HRESULT ServerCallWrapper(ServerThreadContext* threadContextInfo, Fn fn)
@@ -664,6 +824,7 @@ HRESULT ServerCallWrapper(ServerThreadContext* threadContextInfo, Fn fn)
     HRESULT hr = S_OK;
     try
     {
+        AUTO_NESTED_HANDLED_EXCEPTION_TYPE(static_cast<ExceptionType>(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
         AutoReleaseThreadContext autoThreadContext(threadContextInfo);
         hr = fn();
 

+ 2 - 0
lib/JITServer/JITServer.h

@@ -17,6 +17,8 @@ public:
     static bool CheckLivenessAndAddref(ServerScriptContext* context);
     static bool CheckLivenessAndAddref(ServerThreadContext* context);
 
+    static void IdleCleanup();
+
 private:
     static JsUtil::BaseHashSet<ServerThreadContext*, HeapAllocator> threadContexts;
     static JsUtil::BaseHashSet<ServerScriptContext*, HeapAllocator> scriptContexts;

+ 1 - 0
lib/JITServer/JITServerPch.h

@@ -12,3 +12,4 @@
 #include "Runtime.h"
 #include "Backend.h"
 #include "JITServer.h"
+#include "PageAllocatorPool.h"

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

@@ -851,7 +851,7 @@ namespace Js
         entryPointInfo->entryPointIndex = this->entryPoints->Add(recycler->CreateWeakReferenceHandle(entryPointInfo));
     }
 
-
+#if DBG
     BOOL FunctionBody::IsInterpreterThunk() const
     {
         bool isInterpreterThunk = this->originalEntryPoint == DefaultEntryThunk;
@@ -869,6 +869,7 @@ namespace Js
         return FALSE;
 #endif
     }
+#endif
 
     FunctionEntryPointInfo * FunctionBody::TryGetEntryPointInfo(int index) const
     {

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

@@ -2639,8 +2639,10 @@ namespace Js
         void AddEntryPointToEntryPointList(FunctionEntryPointInfo* entryPoint);
 
         // Kind of entry point for original entry point
+#if DBG
         BOOL IsInterpreterThunk() const;
         BOOL IsDynamicInterpreterThunk() const;
+#endif
         BOOL IsNativeOriginalEntryPoint() const;
         bool IsSimpleJitOriginalEntryPoint() const;
 

+ 29 - 2
lib/Runtime/Base/ScriptContext.cpp

@@ -1210,11 +1210,11 @@ if (!sourceList)
         }
 
 #if DYNAMIC_INTERPRETER_THUNK
-        interpreterThunkEmitter = HeapNew(InterpreterThunkEmitter, SourceCodeAllocator(), this->GetThreadContext()->GetThunkPageAllocators());
+        interpreterThunkEmitter = HeapNew(InterpreterThunkEmitter, this, SourceCodeAllocator(), this->GetThreadContext()->GetThunkPageAllocators());
 #endif
 
 #ifdef ASMJS_PLAT
-        asmJsInterpreterThunkEmitter = HeapNew(InterpreterThunkEmitter, SourceCodeAllocator(), this->GetThreadContext()->GetThunkPageAllocators(),
+        asmJsInterpreterThunkEmitter = HeapNew(InterpreterThunkEmitter, this, SourceCodeAllocator(), this->GetThreadContext()->GetThunkPageAllocators(),
             true);
 #endif
 
@@ -4489,6 +4489,11 @@ void ScriptContext::RegisterPrototypeChainEnsuredToHaveOnlyWritableDataPropertie
         contextData.isRecyclerVerifyEnabled = FALSE;
         contextData.recyclerVerifyPad = 0;
 #endif
+        contextData.debuggingFlagsAddr = GetDebuggingFlagsAddr();
+        contextData.debugStepTypeAddr = GetDebugStepTypeAddr();
+        contextData.debugFrameAddressAddr = GetDebugFrameAddressAddr();
+        contextData.debugScriptIdWhenSetAddr = GetDebugScriptIdWhenSetAddr();
+
         contextData.numberAllocatorAddr = (intptr_t)GetNumberAllocator();
         contextData.isSIMDEnabled = GetConfig()->IsSimdjsEnabled();
         CompileAssert(VTableValue::Count == VTABLE_COUNT); // need to update idl when this changes
@@ -4651,6 +4656,26 @@ void ScriptContext::RegisterPrototypeChainEnsuredToHaveOnlyWritableDataPropertie
         return (intptr_t)GetRecycler();
     }
 
+    intptr_t ScriptContext::GetDebuggingFlagsAddr() const
+    {
+        return this->threadContext->GetDebugManager()->GetDebuggingFlagsAddr();
+    }
+
+    intptr_t ScriptContext::GetDebugStepTypeAddr() const
+    {
+        return (intptr_t)this->threadContext->GetDebugManager()->stepController.GetAddressOfStepType();
+    }
+
+    intptr_t ScriptContext::GetDebugFrameAddressAddr() const
+    {
+        return (intptr_t)this->threadContext->GetDebugManager()->stepController.GetAddressOfFrameAddress();
+    }
+
+    intptr_t ScriptContext::GetDebugScriptIdWhenSetAddr() const
+    {
+        return (intptr_t)this->threadContext->GetDebugManager()->stepController.GetAddressOfScriptIdWhenSet();
+    }
+
     bool ScriptContext::GetRecyclerAllowNativeCodeBumpAllocation() const
     {
         return GetRecycler()->AllowNativeCodeBumpAllocation();
@@ -4849,10 +4874,12 @@ void ScriptContext::RegisterPrototypeChainEnsuredToHaveOnlyWritableDataPropertie
         return (JavascriptMethod)this->interpreterThunkEmitter->GetNextThunk(ppDynamicInterpreterThunk);
     }
 
+#if DBG
     BOOL ScriptContext::IsDynamicInterpreterThunk(JavascriptMethod address)
     {
         return this->interpreterThunkEmitter->IsInHeap((void*)address);
     }
+#endif
 
     void ScriptContext::ReleaseDynamicInterpreterThunk(BYTE* address, bool addtoFreeList)
     {

+ 9 - 2
lib/Runtime/Base/ScriptContext.h

@@ -912,10 +912,10 @@ private:
         void SetDirectHostTypeId(TypeId typeId) {directHostTypeId = typeId; }
         TypeId GetDirectHostTypeId() const { return directHostTypeId; }
 
-        intptr_t GetRemoteScriptAddr() 
+        intptr_t GetRemoteScriptAddr(bool allowInitialize = true) 
         {
 #if ENABLE_OOP_NATIVE_CODEGEN
-            if (!m_remoteScriptContextAddr)
+            if (!m_remoteScriptContextAddr && allowInitialize)
             {
                 InitializeRemoteScriptContext();
             }
@@ -1658,7 +1658,9 @@ private:
 #if DYNAMIC_INTERPRETER_THUNK
         JavascriptMethod GetNextDynamicAsmJsInterpreterThunk(PVOID* ppDynamicInterpreterThunk);
         JavascriptMethod GetNextDynamicInterpreterThunk(PVOID* ppDynamicInterpreterThunk);
+#if DBG
         BOOL IsDynamicInterpreterThunk(JavascriptMethod address);
+#endif
         void ReleaseDynamicInterpreterThunk(BYTE* address, bool addtoFreeList);
         void ReleaseDynamicAsmJsInterpreterThunk(BYTE* address, bool addtoFreeList);
 #endif
@@ -1760,6 +1762,11 @@ private:
         virtual bool IsPRNGSeeded() const override;
         virtual intptr_t GetBuiltinFunctionsBaseAddr() const override;
 
+        virtual intptr_t GetDebuggingFlagsAddr() const override;
+        virtual intptr_t GetDebugStepTypeAddr() const override;
+        virtual intptr_t GetDebugFrameAddressAddr() const override;
+        virtual intptr_t GetDebugScriptIdWhenSetAddr() const override;
+
 #if ENABLE_NATIVE_CODEGEN
         virtual void AddToDOMFastPathHelperMap(intptr_t funcInfoAddr, IR::JnHelperMethod helper) override;
         virtual IR::JnHelperMethod GetDOMFastPathHelper(intptr_t funcInfoAddr) override;

+ 5 - 0
lib/Runtime/Base/ScriptContextInfo.h

@@ -50,6 +50,11 @@ public:
 
     virtual Js::Var* GetModuleExportSlotArrayAddress(uint moduleIndex, uint slotIndex) = 0;
 
+    virtual intptr_t GetDebuggingFlagsAddr() const = 0;
+    virtual intptr_t GetDebugStepTypeAddr() const = 0;
+    virtual intptr_t GetDebugFrameAddressAddr() const = 0;
+    virtual intptr_t GetDebugScriptIdWhenSetAddr() const = 0;
+
 #if ENABLE_NATIVE_CODEGEN
     virtual void AddToDOMFastPathHelperMap(intptr_t funcInfoAddr, IR::JnHelperMethod helper) = 0;
     virtual IR::JnHelperMethod GetDOMFastPathHelper(intptr_t funcInfoAddr) = 0;

+ 21 - 32
lib/Runtime/Base/ThreadContext.cpp

@@ -341,30 +341,6 @@ ThreadContext::GetImplicitCallFlagsAddr() const
     return (intptr_t)&implicitCallFlags;
 }
 
-intptr_t
-ThreadContext::GetDebuggingFlagsAddr() const
-{
-    return this->debugManager->GetDebuggingFlagsAddr();
-}
-
-intptr_t
-ThreadContext::GetDebugStepTypeAddr() const
-{
-    return (intptr_t)this->debugManager->stepController.GetAddressOfStepType();
-}
-
-intptr_t
-ThreadContext::GetDebugFrameAddressAddr() const
-{
-    return (intptr_t)this->debugManager->stepController.GetAddressOfFrameAddress();
-}
-
-intptr_t
-ThreadContext::GetDebugScriptIdWhenSetAddr() const
-{
-    return (intptr_t)this->debugManager->stepController.GetAddressOfScriptIdWhenSet();
-}
-
 ptrdiff_t
 ThreadContext::GetChakraBaseAddressDifference() const
 {
@@ -905,6 +881,12 @@ ThreadContext::GetPropertyRecord(Js::PropertyId propertyId)
     return GetPropertyNameLocked(propertyId);
 }
 
+bool
+ThreadContext::IsNumericProperty(Js::PropertyId propertyId)
+{
+    return GetPropertyRecord(propertyId)->IsNumeric();
+}
+
 const Js::PropertyRecord *
 ThreadContext::FindPropertyRecord(const char16 * propertyName, int propertyNameLength)
 {
@@ -1130,8 +1112,11 @@ ThreadContext::AddPropertyRecordInternal(const Js::PropertyRecord * propertyReco
     if (m_pendingJITProperties)
     {
         Assert(m_reclaimedJITProperties);
-        m_pendingJITProperties->Add(propertyRecord);
-        m_reclaimedJITProperties->Remove(propertyRecord->GetPropertyId());
+        if (propertyRecord->IsNumeric())
+        {
+            m_pendingJITProperties->Prepend(propertyRecord->GetPropertyId());
+            m_reclaimedJITProperties->Remove(propertyRecord->GetPropertyId());
+        }
     }
 #endif
 
@@ -1288,7 +1273,7 @@ void ThreadContext::InvalidatePropertyRecord(const Js::PropertyRecord * property
 {
     InternalInvalidateProtoTypePropertyCaches(propertyRecord->GetPropertyId());     // use the internal version so we don't check for active property id
 #if ENABLE_NATIVE_CODEGEN
-    if (m_pendingJITProperties && !m_pendingJITProperties->Remove(propertyRecord))
+    if (propertyRecord->IsNumeric() && m_pendingJITProperties && !m_pendingJITProperties->Remove(propertyRecord->GetPropertyId()))
     {
         // if it wasn't pending, that means it was already sent to the jit, so add to list that jit needs to reclaim
         m_reclaimedJITProperties->PrependNoThrow(&HeapAllocator::Instance, propertyRecord->GetPropertyId());
@@ -1994,10 +1979,6 @@ ThreadContext::EnsureJITThreadContext(bool allowPrereserveAlloc)
     contextData.bailOutRegisterSaveSpaceAddr = (intptr_t)bailOutRegisterSaveSpace;
     contextData.disableImplicitFlagsAddr = (intptr_t)GetAddressOfDisableImplicitFlags();
     contextData.implicitCallFlagsAddr = (intptr_t)GetAddressOfImplicitCallFlags();
-    contextData.debuggingFlagsAddr = (intptr_t)this->debugManager->GetDebuggingFlags();
-    contextData.debugStepTypeAddr = (intptr_t)this->debugManager->stepController.GetAddressOfStepType();
-    contextData.debugFrameAddressAddr = (intptr_t)this->debugManager->stepController.GetAddressOfFrameAddress();
-    contextData.debugScriptIdWhenSetAddr = (intptr_t)this->debugManager->stepController.GetAddressOfScriptIdWhenSet();
     contextData.scriptStackLimit = GetScriptStackLimit();
     contextData.isThreadBound = IsThreadBound();
     contextData.allowPrereserveAlloc = allowPrereserveAlloc;
@@ -2006,7 +1987,15 @@ ThreadContext::EnsureJITThreadContext(bool allowPrereserveAlloc)
 #endif
 
     m_reclaimedJITProperties = HeapNew(PropertyList, &HeapAllocator::Instance);
-    m_pendingJITProperties = propertyMap->Clone();
+    m_pendingJITProperties = HeapNew(PropertyList, &HeapAllocator::Instance);
+    
+    for (auto iter = propertyMap->GetIterator(); iter.IsValid(); iter.MoveNext())
+    {
+        if (iter.CurrentKey()->IsNumeric())
+        {
+            m_pendingJITProperties->Prepend(iter.CurrentKey()->GetPropertyId());
+        }
+    }
 
     HRESULT hr = JITManager::GetJITManager()->InitializeThreadContext(&contextData, &m_remoteThreadContextInfo, &m_prereservedRegionAddr);
     JITManager::HandleServerCallResult(hr);

+ 5 - 8
lib/Runtime/Base/ThreadContext.h

@@ -385,7 +385,9 @@ public:
     void SetHeapEnum(IActiveScriptProfilerHeapEnum* newHeapEnum);
     void ClearHeapEnum();
 
-    virtual Js::PropertyRecord const * GetPropertyRecord(Js::PropertyId propertyId) override;
+    Js::PropertyRecord const * GetPropertyRecord(Js::PropertyId propertyId);
+
+    virtual bool IsNumericProperty(Js::PropertyId propertyId) override;
 
 #ifdef ENABLE_BASIC_TELEMETRY
     Js::LanguageStats* GetLanguageStats()
@@ -482,7 +484,7 @@ private:
     intptr_t m_prereservedRegionAddr;
 
 #if ENABLE_NATIVE_CODEGEN
-    PropertyMap * m_pendingJITProperties;
+    PropertyList * m_pendingJITProperties;
     PropertyList  * m_reclaimedJITProperties;
 public:
 
@@ -491,7 +493,7 @@ public:
         return m_reclaimedJITProperties;
     }
 
-    PropertyMap * GetPendingJITProperties() const
+    PropertyList * GetPendingJITProperties() const
     {
         return m_pendingJITProperties;
     }
@@ -1216,11 +1218,6 @@ public:
     virtual intptr_t GetDisableImplicitFlagsAddr() const override;
     virtual intptr_t GetImplicitCallFlagsAddr() const override;
 
-    virtual intptr_t GetDebuggingFlagsAddr() const override;
-    virtual intptr_t GetDebugStepTypeAddr() const override;
-    virtual intptr_t GetDebugFrameAddressAddr() const override;
-    virtual intptr_t GetDebugScriptIdWhenSetAddr() const override;
-
     ptrdiff_t GetChakraBaseAddressDifference() const;
     ptrdiff_t GetCRTBaseAddressDifference() const;
 

+ 1 - 6
lib/Runtime/Base/ThreadContextInfo.h

@@ -92,12 +92,7 @@ public:
     virtual PreReservedVirtualAllocWrapper * GetPreReservedVirtualAllocator() = 0;
 #endif
 
-    virtual intptr_t GetDebuggingFlagsAddr() const = 0;
-    virtual intptr_t GetDebugStepTypeAddr() const = 0;
-    virtual intptr_t GetDebugFrameAddressAddr() const = 0;
-    virtual intptr_t GetDebugScriptIdWhenSetAddr() const = 0;
-
-    virtual Js::PropertyRecord const * GetPropertyRecord(Js::PropertyId propertyId) = 0;
+    virtual bool IsNumericProperty(Js::PropertyId propertyId) = 0;
 
     bool CanBeFalsy(Js::TypeId typeId) { return typeId == this->wellKnownHostTypeHTMLAllCollectionTypeId; }
 

+ 4 - 5
lib/Runtime/Debug/TTEventLog.cpp

@@ -536,8 +536,7 @@ namespace TTD
 
         if(this->m_propertyRecordPinSet != nullptr)
         {
-            this->m_propertyRecordPinSet->GetAllocator()->RootRelease(this->m_propertyRecordPinSet);
-            this->m_propertyRecordPinSet = nullptr;
+            this->m_propertyRecordPinSet.Unroot(this->m_propertyRecordPinSet->GetAllocator());
         }
     }
 
@@ -710,15 +709,15 @@ namespace TTD
         m_modeStack(), m_currentMode(TTDMode::Pending),
         m_ttdContext(nullptr),
         m_snapExtractor(), m_elapsedExecutionTimeSinceSnapshot(0.0),
-        m_lastInflateSnapshotTime(-1), m_lastInflateMap(nullptr), m_propertyRecordPinSet(nullptr), m_propertyRecordList(&this->m_miscSlabAllocator),
+        m_lastInflateSnapshotTime(-1), m_lastInflateMap(nullptr), m_propertyRecordList(&this->m_miscSlabAllocator),
         m_loadedTopLevelScripts(&this->m_miscSlabAllocator), m_newFunctionTopLevelScripts(&this->m_miscSlabAllocator), m_evalTopLevelScripts(&this->m_miscSlabAllocator)
     {
         this->InitializeEventListVTable();
 
         this->m_modeStack.Push(TTDMode::Pending);
 
-        this->m_propertyRecordPinSet = RecyclerNew(threadContext->GetRecycler(), PropertyRecordPinSet, threadContext->GetRecycler());
-        this->m_threadContext->GetRecycler()->RootAddRef(this->m_propertyRecordPinSet);
+        Recycler * recycler = threadContext->GetRecycler();
+        this->m_propertyRecordPinSet.Root(RecyclerNew(recycler, PropertyRecordPinSet, recycler), recycler);
     }
 
     EventLog::~EventLog()

+ 1 - 1
lib/Runtime/Debug/TTEventLog.h

@@ -220,7 +220,7 @@ namespace TTD
         InflateMap* m_lastInflateMap;
 
         //Pin set of all property records created during this logging session
-        PropertyRecordPinSet* m_propertyRecordPinSet;
+        RecyclerRootPtr<PropertyRecordPinSet> m_propertyRecordPinSet;
         UnorderedArrayList<NSSnapType::SnapPropertyRecord, TTD_ARRAY_LIST_SIZE_DEFAULT> m_propertyRecordList;
 
         //A list of all *root* scripts that have been loaded during this session

+ 10 - 21
lib/Runtime/Debug/TTInflateMap.cpp

@@ -13,7 +13,6 @@ namespace TTD
         m_tagToGlobalObjectMap(), m_objectMap(),
         m_functionBodyMap(), m_environmentMap(), m_slotArrayMap(), m_promiseDataMap(&HeapAllocator::Instance),
         m_debuggerScopeHomeBodyMap(), m_debuggerScopeChainIndexMap(),
-        m_inflatePinSet(nullptr), m_environmentPinSet(nullptr), m_slotArrayPinSet(nullptr), m_oldInflatePinSet(nullptr),
         m_oldObjectMap(), m_oldFunctionBodyMap(), m_propertyReset(&HeapAllocator::Instance)
     {
         ;
@@ -23,26 +22,22 @@ namespace TTD
     {
         if(this->m_inflatePinSet != nullptr)
         {
-            this->m_inflatePinSet->GetAllocator()->RootRelease(this->m_inflatePinSet);
-            this->m_inflatePinSet = nullptr;
+            this->m_inflatePinSet.Unroot(this->m_inflatePinSet->GetAllocator());
         }
 
         if(this->m_environmentPinSet != nullptr)
         {
-            this->m_environmentPinSet->GetAllocator()->RootRelease(this->m_environmentPinSet);
-            this->m_environmentPinSet = nullptr;
+            this->m_environmentPinSet.Unroot(this->m_environmentPinSet->GetAllocator());
         }
 
         if(this->m_slotArrayPinSet != nullptr)
         {
-            this->m_slotArrayPinSet->GetAllocator()->RootRelease(this->m_slotArrayPinSet);
-            this->m_slotArrayPinSet = nullptr;
+            this->m_slotArrayPinSet.Unroot(this->m_slotArrayPinSet->GetAllocator());
         }
 
         if(this->m_oldInflatePinSet != nullptr)
         {
-            this->m_oldInflatePinSet->GetAllocator()->RootRelease(this->m_oldInflatePinSet);
-            this->m_oldInflatePinSet = nullptr;
+            this->m_oldInflatePinSet.Unroot(this->m_oldInflatePinSet->GetAllocator());
         }
     }
 
@@ -59,14 +54,10 @@ namespace TTD
         this->m_slotArrayMap.Initialize(slotCount);
         this->m_promiseDataMap.Clear();
 
-        this->m_inflatePinSet = RecyclerNew(threadContext->GetRecycler(), ObjectPinSet, threadContext->GetRecycler(), objectCount);
-        threadContext->GetRecycler()->RootAddRef(this->m_inflatePinSet);
-
-        this->m_environmentPinSet = RecyclerNew(threadContext->GetRecycler(), EnvironmentPinSet, threadContext->GetRecycler(), objectCount);
-        threadContext->GetRecycler()->RootAddRef(this->m_environmentPinSet);
-
-        this->m_slotArrayPinSet = RecyclerNew(threadContext->GetRecycler(), SlotArrayPinSet, threadContext->GetRecycler(), objectCount);
-        threadContext->GetRecycler()->RootAddRef(this->m_slotArrayPinSet);
+        Recycler * recycler = threadContext->GetRecycler();
+        this->m_inflatePinSet.Root(RecyclerNew(recycler, ObjectPinSet, recycler, objectCount), recycler);
+        this->m_environmentPinSet.Root(RecyclerNew(recycler, EnvironmentPinSet, recycler, objectCount), recycler);
+        this->m_slotArrayPinSet.Root(RecyclerNew(recycler, SlotArrayPinSet, recycler, objectCount), recycler);
     }
 
     void InflateMap::PrepForReInflate(uint32 ctxCount, uint32 handlerCount, uint32 typeCount, uint32 objectCount, uint32 bodyCount, uint32 dbgScopeCount, uint32 envCount, uint32 slotCount)
@@ -91,8 +82,7 @@ namespace TTD
         //allocate the old pin set and fill it
         AssertMsg(this->m_oldInflatePinSet == nullptr, "Old pin set is not null.");
         Recycler* pinRecycler = this->m_inflatePinSet->GetAllocator();
-        this->m_oldInflatePinSet = RecyclerNew(pinRecycler, ObjectPinSet, pinRecycler, this->m_inflatePinSet->Count());
-        pinRecycler->RootAddRef(this->m_oldInflatePinSet);
+        this->m_oldInflatePinSet.Root(RecyclerNew(pinRecycler, ObjectPinSet, pinRecycler, this->m_inflatePinSet->Count()), pinRecycler);
 
         for(auto iter = this->m_inflatePinSet->GetIterator(); iter.IsValid(); iter.MoveNext())
         {
@@ -125,8 +115,7 @@ namespace TTD
 
         if(this->m_oldInflatePinSet != nullptr)
         {
-            this->m_oldInflatePinSet->GetAllocator()->RootRelease(this->m_oldInflatePinSet);
-            this->m_oldInflatePinSet = nullptr;
+            this->m_oldInflatePinSet.Unroot(this->m_oldInflatePinSet->GetAllocator());
         }
     }
 

+ 4 - 4
lib/Runtime/Debug/TTInflateMap.h

@@ -32,12 +32,12 @@ namespace TTD
         JsUtil::BaseDictionary<TTD_PTR_ID, void*, HeapAllocator> m_promiseDataMap;
 
         //A set we use to pin all the inflated objects live during/after the inflate process (to avoid accidental collection)
-        ObjectPinSet* m_inflatePinSet;
-        EnvironmentPinSet* m_environmentPinSet;
-        SlotArrayPinSet* m_slotArrayPinSet;
+        RecyclerRootPtr<ObjectPinSet> m_inflatePinSet;
+        RecyclerRootPtr<EnvironmentPinSet> m_environmentPinSet;
+        RecyclerRootPtr<SlotArrayPinSet> m_slotArrayPinSet;
 
         //A set we use to keep some old objects alive during inflate in case we want to re-use them
-        ObjectPinSet* m_oldInflatePinSet;
+        RecyclerRootPtr<ObjectPinSet> m_oldInflatePinSet;
 
         //Temp data structures for holding info during the inflate process
         TTDIdentifierDictionary<TTD_PTR_ID, Js::RecyclableObject*> m_oldObjectMap;

+ 4 - 4
lib/Runtime/Debug/TTRuntimeInfoTracker.h

@@ -30,8 +30,8 @@ namespace TTD
         Js::ScriptContext* m_ctx;
 
         //Keep track of roots (and local roots as needed)
-        ObjectPinSet* m_ttdRootSet;
-        ObjectPinSet* m_ttdLocalRootSet;
+        RecyclerRootPtr<ObjectPinSet> m_ttdRootSet;
+        RecyclerRootPtr<ObjectPinSet> m_ttdLocalRootSet;
         JsUtil::BaseDictionary<TTD_LOG_PTR_ID, Js::RecyclableObject*, HeapAllocator> m_ttdRootTagIdMap;
 
         //List of pending async modifications to array buffers
@@ -43,14 +43,14 @@ namespace TTD
         JsUtil::List<TTD::TopLevelFunctionInContextRelation, HeapAllocator> m_ttdTopLevelEval;
 
         //need to add back pin set for functionBody to make sure they don't get collected on us
-        TTD::FunctionBodyPinSet* m_ttdPinnedRootFunctionSet;
+        RecyclerRootPtr<TTD::FunctionBodyPinSet> m_ttdPinnedRootFunctionSet;
         JsUtil::BaseDictionary<Js::FunctionBody*, Js::FunctionBody*, HeapAllocator> m_ttdFunctionBodyParentMap;
 
     public:
         //
         //TODO: this results in a memory leak for programs with weak collections -- we should fix this
         //
-        ObjectPinSet* TTDWeakReferencePinSet;
+        RecyclerRootPtr<ObjectPinSet> TTDWeakReferencePinSet;
 
         ScriptContextTTD(Js::ScriptContext* ctx);
         ~ScriptContextTTD();

+ 10 - 22
lib/Runtime/Debug/TTRuntmeInfoTracker.cpp

@@ -10,38 +10,28 @@ namespace TTD
 {
     ScriptContextTTD::ScriptContextTTD(Js::ScriptContext* ctx)
         : m_ctx(ctx),
-        m_ttdRootSet(nullptr), m_ttdLocalRootSet(nullptr), m_ttdRootTagIdMap(&HeapAllocator::Instance), m_ttdPendingAsyncModList(&HeapAllocator::Instance),
+        m_ttdRootTagIdMap(&HeapAllocator::Instance), m_ttdPendingAsyncModList(&HeapAllocator::Instance),
         m_ttdTopLevelScriptLoad(&HeapAllocator::Instance), m_ttdTopLevelNewFunction(&HeapAllocator::Instance), m_ttdTopLevelEval(&HeapAllocator::Instance),
-        m_ttdPinnedRootFunctionSet(nullptr), m_ttdFunctionBodyParentMap(&HeapAllocator::Instance),
-        TTDWeakReferencePinSet(nullptr)
+        m_ttdFunctionBodyParentMap(&HeapAllocator::Instance)
     {
         Recycler* ctxRecycler = this->m_ctx->GetRecycler();
 
-        this->m_ttdRootSet = RecyclerNew(ctxRecycler, TTD::ObjectPinSet, ctxRecycler);
-        ctxRecycler->RootAddRef(this->m_ttdRootSet);
-
-        this->m_ttdLocalRootSet = RecyclerNew(ctxRecycler, TTD::ObjectPinSet, ctxRecycler);
-        ctxRecycler->RootAddRef(this->m_ttdLocalRootSet);
-
-        this->m_ttdPinnedRootFunctionSet = RecyclerNew(ctxRecycler, TTD::FunctionBodyPinSet, ctxRecycler);
-        ctxRecycler->RootAddRef(this->m_ttdPinnedRootFunctionSet);
-
-        this->TTDWeakReferencePinSet = RecyclerNew(ctxRecycler, TTD::ObjectPinSet, ctxRecycler);
-        ctxRecycler->RootAddRef(this->TTDWeakReferencePinSet);
+        this->m_ttdRootSet.Root(RecyclerNew(ctxRecycler, TTD::ObjectPinSet, ctxRecycler), ctxRecycler);
+        this->m_ttdLocalRootSet.Root(RecyclerNew(ctxRecycler, TTD::ObjectPinSet, ctxRecycler), ctxRecycler);
+        this->m_ttdPinnedRootFunctionSet.Root(RecyclerNew(ctxRecycler, TTD::FunctionBodyPinSet, ctxRecycler), ctxRecycler);
+        this->TTDWeakReferencePinSet.Root(RecyclerNew(ctxRecycler, TTD::ObjectPinSet, ctxRecycler), ctxRecycler);        
     }
 
     ScriptContextTTD::~ScriptContextTTD()
     {
         if(this->m_ttdRootSet != nullptr)
         {
-            this->m_ttdRootSet->GetAllocator()->RootRelease(this->m_ttdRootSet);
-            this->m_ttdRootSet = nullptr;
+            this->m_ttdRootSet.Unroot(this->m_ttdRootSet->GetAllocator());            
         }
 
         if(this->m_ttdLocalRootSet != nullptr)
         {
-            this->m_ttdLocalRootSet->GetAllocator()->RootRelease(this->m_ttdLocalRootSet);
-            this->m_ttdLocalRootSet = nullptr;
+            this->m_ttdLocalRootSet.Unroot(this->m_ttdLocalRootSet->GetAllocator());
         }
 
         this->m_ttdRootTagIdMap.Clear();
@@ -54,16 +44,14 @@ namespace TTD
 
         if(this->m_ttdPinnedRootFunctionSet != nullptr)
         {
-            this->m_ttdPinnedRootFunctionSet->GetAllocator()->RootRelease(this->m_ttdPinnedRootFunctionSet);
-            this->m_ttdPinnedRootFunctionSet = nullptr;
+            this->m_ttdPinnedRootFunctionSet.Unroot(this->m_ttdPinnedRootFunctionSet->GetAllocator());
         }
 
         this->m_ttdFunctionBodyParentMap.Clear();
 
         if(this->TTDWeakReferencePinSet != nullptr)
         {
-            this->TTDWeakReferencePinSet->GetAllocator()->RootRelease(this->TTDWeakReferencePinSet);
-            this->TTDWeakReferencePinSet = nullptr;
+            this->TTDWeakReferencePinSet.Unroot(this->TTDWeakReferencePinSet->GetAllocator());
         }
     }
 

+ 6 - 0
lib/Runtime/Language/FunctionCodeGenJitTimeData.cpp

@@ -16,6 +16,7 @@ namespace Js
 #endif
         next(0),
         ldFldInlinees(nullptr),
+        globalThisObject(GetFunctionBody() && GetFunctionBody()->GetByteCode() ? GetFunctionBody()->GetScriptContext()->GetLibrary()->GetGlobalObject()->ToThis() : 0),
         profiledIterations(GetFunctionBody() && GetFunctionBody()->GetByteCode() ? GetFunctionBody()->GetProfiledIterations() : 0)
     {
     }
@@ -35,6 +36,11 @@ namespace Js
         return this->functionInfo->GetFunctionBody();
     }
 
+    Var FunctionCodeGenJitTimeData::GetGlobalThisObject() const
+    {
+        return this->globalThisObject;
+    }
+
     bool FunctionCodeGenJitTimeData::IsPolymorphicCallSite(const ProfileId profiledCallSiteId) const
     {
         Assert(GetFunctionBody());

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

@@ -37,6 +37,9 @@ namespace Js
         PolymorphicInlineCacheInfoIDL* selfInfo;
         PolymorphicInlineCacheIDL* polymorphicInlineCaches;
 
+        // current value of global this object, may be changed in case of script engine invalidation
+        Var globalThisObject;
+
         // Number of functions that are to be inlined (this is not the length of the 'inlinees' array above, includes getter setter inlinee count)
         uint inlineeCount;
         // Number of counts of getter setter to be inlined. This is not an exact count as inline caches are shared and we have no way of knowing
@@ -70,6 +73,7 @@ namespace Js
 
         FunctionInfo *GetFunctionInfo() const;
         FunctionBody *GetFunctionBody() const;
+        Var GetGlobalThisObject() const;
         FunctionBodyDataIDL *GetJITBody() const;
         FunctionCodeGenJitTimeData *GetNext() const { return next; }
 

+ 1 - 54
lib/Runtime/Library/JavascriptArray.cpp

@@ -10055,59 +10055,6 @@ Case0:
     }
 #endif
 
-    template <typename Fn>
-    void JavascriptArray::ForEachOwnArrayIndexOfObject(RecyclableObject* obj, uint32 startIndex, uint32 limitIndex, Fn fn)
-    {
-        Assert(DynamicObject::IsAnyArray(obj) || JavascriptOperators::IsObject(obj));
-
-        JavascriptArray* arr = nullptr;
-        if (DynamicObject::IsAnyArray(obj))
-        {
-            arr = JavascriptArray::FromAnyArray(obj);
-        }
-        else if (DynamicType::Is(obj->GetTypeId()))
-        {
-            DynamicObject* dynobj = DynamicObject::FromVar(obj);
-            arr = dynobj->GetObjectArray();
-        }
-
-        if (arr != nullptr)
-        {
-            if (JavascriptArray::Is(arr))
-            {
-                ArrayElementEnumerator e(arr, startIndex, limitIndex);
-
-                while(e.MoveNext<Var>())
-                {
-                    fn(e.GetIndex(), e.GetItem<Var>());
-                }
-            }
-            else
-            {
-                ScriptContext* scriptContext = obj->GetScriptContext();
-
-                Assert(ES5Array::Is(arr));
-
-                ES5Array* es5Array = ES5Array::FromVar(arr);
-                ES5ArrayIndexEnumerator<true> e(es5Array);
-
-                while (e.MoveNext())
-                {
-                    uint32 index = e.GetIndex();
-
-                    if (index < startIndex) continue;
-                    else if (index >= limitIndex) break;
-
-                    Var value = nullptr;
-                    if (JavascriptOperators::GetOwnItem(es5Array, index, &value, scriptContext))
-                    {
-                        fn(index, value);
-                    }
-                }
-            }
-        }
-    }
-
     template <typename T, typename Fn>
     void JavascriptArray::ForEachOwnMissingArrayIndexOfObject(JavascriptArray *baseArray, JavascriptArray *destArray, RecyclableObject* obj, uint32 startIndex, uint32 limitIndex, T destIndex, Fn fn)
     {
@@ -10166,7 +10113,7 @@ Case0:
                         if (destArray == nullptr || !destArray->DirectGetItemAt(n, &oldValue))
                         {
                             Var value = nullptr;
-                            if (JavascriptOperators::GetOwnItem(es5Array, index, &value, scriptContext))
+                            if (JavascriptOperators::GetOwnItem(obj, index, &value, scriptContext))
                             {
                                 fn(index, value);
                             }

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

@@ -572,9 +572,6 @@ namespace Js
         static int __cdecl CompareElements(void* context, const void* elem1, const void* elem2);
         void SortElements(Element* elements, uint32 left, uint32 right);
 
-        template <typename Fn>
-        static void ForEachOwnArrayIndexOfObject(RecyclableObject* obj, uint32 startIndex, uint32 limitIndex, Fn fn);
-
         template <typename T, typename Fn>
         static void ForEachOwnMissingArrayIndexOfObject(JavascriptArray *baseArr, JavascriptArray *destArray, RecyclableObject* obj, uint32 startIndex, uint32 limitIndex, T destIndex, Fn fn);
 

+ 1 - 1
lib/WasmReader/WasmBinaryOpCodes.h

@@ -209,7 +209,7 @@ WASM_BINARY_OPCODE(F64Min,            0x8d, D_DD, Min_Db         , false)
 WASM_BINARY_OPCODE(F64Max,            0x8e, D_DD, Max_Db         , false)
 WASM_UNARY__OPCODE(F64Abs,            0x8f, D_D , Abs_Db         , false)
 WASM_UNARY__OPCODE(F64Neg,            0x90, D_D , Neg_Db         , false)
-WASM_BINARY_OPCODE(F64CopySign,       0x91, D_DD, Copysign_Db    , true)
+WASM_BINARY_OPCODE(F64CopySign,       0x91, D_DD, Copysign_Db    , false)
 WASM_UNARY__OPCODE(F64Ceil,           0x92, D_D , Ceil_Db        , false)
 WASM_UNARY__OPCODE(F64Floor,          0x93, D_D , Floor_Db       , false)
 WASM_UNARY__OPCODE(F64Trunc,          0x94, D_D , Trunc_Db       , false)

+ 1 - 2
test/WasmSpec/baselines/left-to-right.baseline

@@ -1,2 +1 @@
-left-to-right.wast:217: $assert_return_68 unexpectedly threw: Error: Compiling wasm failed: function f64_copysign[115] at offset 8/12: Operator F64CopySign NYI
-94/95 tests passed.
+95/95 tests passed.

+ 17 - 0
test/es5/es5array_objproto_builtin.js

@@ -0,0 +1,17 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+var ary = Array(1);
+ary.prop = "Got array property. Failed";
+Object.prototype.prop = "pass";
+Array.prototype.prop = "Got array prototype. Failed";
+Object.defineProperty(Object.prototype, 0, {
+  get: function () {
+    print(this.prop);
+    return 3;
+  }
+});
+ary.slice();
+

+ 5 - 0
test/es5/rlexe.xml

@@ -284,6 +284,11 @@
       <baseline>es5array_objproto.baseline</baseline>
     </default>
   </test>
+  <test>
+    <default>
+      <files>es5array_objproto_builtin.js</files>
+    </default>
+  </test>
   <test>
     <default>
       <files>es5array_arrayproto.js</files>

+ 1 - 0
test/wasm/misc.baseline

@@ -35,3 +35,4 @@ NaN
 NaN
 Infinity
 -Infinity
+-255

+ 1 - 1
test/wasm/misc.js

@@ -43,4 +43,4 @@ print(a.f64nearest(NaN)); // == NaN
 print(a.f64nearest(-NaN)); // == NaN
 print(a.f64nearest(Infinity)); // == Infinity
 print(a.f64nearest(-Infinity)); // == -Infinity
-//print(a.f64copysign(255.0,-1.0)); // == -255.0
+print(a.f64copysign(255.0,-1.0)); // == -255.0

BIN
test/wasm/misc.wasm


+ 2 - 2
test/wasm/misc.wast

@@ -7,8 +7,8 @@
   (func (export "f32copysign") (param f32) (param f32) (result f32)
     (return (f32.copysign (get_local 0) (get_local 1))))
 
-  ;;(func (export "f64copysign") (param f64) (param f64) (result f64)
-  ;;  (return (f64.copysign (get_local 0) (get_local 1))))
+  (func (export "f64copysign") (param f64) (param f64) (result f64)
+    (return (f64.copysign (get_local 0) (get_local 1))))
 
   (func (export "eqz") (param i32) (result i32)
     (return (i32.eqz (get_local 0))))