diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 index 00000000000..b63284ba2fd --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,48 @@ +#------------------------------------------------------------------------------------------------------- +# Copyright (C) Microsoft. All rights reserved. +# Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +#------------------------------------------------------------------------------------------------------- + +action("ChakraCoreBuild") { + script = "tools/run_msbuild.py" + + chakracore_solution = rebase_path("Build\Chakra.Core.sln") + + # NOSORT + sources = [ + chakracore_solution + ] + + outputs = [ + "$target_gen_dir/ChakraCore.lib", + "$target_gen_dir/../../../ChakraCore.pdb", + "$target_gen_dir/../../../ChakraCore.dll" + ] + + # The path should be like: "Build/VcBuild/bin/x64_debug"" + outdir = "Build/VcBuild/bin/" + current_cpu + + if (is_debug) { + config = "Debug" + outdir = outdir + "_debug" + } + else { + config = "Release" + outdir = outdir + "_release" + } + + outdir = rebase_path(outdir) + +# On Windows, run msbuild.exe on sln and copy lib, dll, pdb files to appropriate locations, +# def main(sln, outdir, target_gen_dir, *flags): + + args = [ + chakracore_solution, + outdir, + rebase_path(target_gen_dir), + "/m", + "/t:Build", + "/p:Configuration=$config", + "/p:platform=$current_cpu" + ] +} diff --git a/Build/Chakra.Core.sln b/Build/Chakra.Core.sln index 0a852832b0e..8921de1bc04 100644 --- a/Build/Chakra.Core.sln +++ b/Build/Chakra.Core.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26228.4 +VisualStudioVersion = 15.0.26726.0 MinimumVisualStudioVersion = 14.0.00000.0 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ChakraCore", "..\bin\ChakraCore\ChakraCore.vcxproj", "{EA882C8D-81FC-42FE-ABD5-2666DB933FDB}" ProjectSection(ProjectDependencies) = postProject @@ -166,18 +166,23 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chakra.ICU.i18n", "..\deps\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chakra.ICU.Stubdata", "..\deps\Chakra.ICU\Chakra.ICU.Stubdata.vcxproj", "{E14F373D-05A0-4259-A5E9-AFE8405FB847}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chakra.SCACore", "..\lib\SCACore\Chakra.SCACore.vcxproj", "{4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM Debug|ARM64 = Debug|ARM64 + Debug|CHPE = Debug|CHPE Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|ARM = Release|ARM Release|ARM64 = Release|ARM64 + Release|CHPE = Release|CHPE Release|x64 = Release|x64 Release|x86 = Release|x86 Test|ARM = Test|ARM Test|ARM64 = Test|ARM64 + Test|CHPE = Test|CHPE Test|x64 = Test|x64 Test|x86 = Test|x86 EndGlobalSection @@ -186,6 +191,8 @@ Global {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Debug|ARM.Build.0 = Debug|ARM {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Debug|ARM64.ActiveCfg = Debug|ARM64 {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Debug|ARM64.Build.0 = Debug|ARM64 + {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Debug|CHPE.ActiveCfg = Debug|CHPE + {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Debug|CHPE.Build.0 = Debug|CHPE {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Debug|x64.ActiveCfg = Debug|x64 {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Debug|x64.Build.0 = Debug|x64 {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Debug|x86.ActiveCfg = Debug|Win32 @@ -194,6 +201,8 @@ Global {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Release|ARM.Build.0 = Release|ARM {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Release|ARM64.ActiveCfg = Release|ARM64 {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Release|ARM64.Build.0 = Release|ARM64 + {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Release|CHPE.ActiveCfg = Release|CHPE + {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Release|CHPE.Build.0 = Release|CHPE {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Release|x64.ActiveCfg = Release|x64 {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Release|x64.Build.0 = Release|x64 {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Release|x86.ActiveCfg = Release|Win32 @@ -202,6 +211,8 @@ Global {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Test|ARM.Build.0 = Test|ARM {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Test|ARM64.ActiveCfg = Test|ARM64 {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Test|ARM64.Build.0 = Test|ARM64 + {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Test|CHPE.ActiveCfg = Test|CHPE + {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Test|CHPE.Build.0 = Test|CHPE {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Test|x64.ActiveCfg = Test|x64 {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Test|x64.Build.0 = Test|x64 {EA882C8D-81FC-42FE-ABD5-2666DB933FDB}.Test|x86.ActiveCfg = Test|Win32 @@ -210,6 +221,10 @@ Global {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Debug|ARM.Build.0 = Debug|ARM {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Debug|ARM64.ActiveCfg = Debug|ARM64 {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Debug|ARM64.Build.0 = Debug|ARM64 + {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Debug|CHPE.ActiveCfg = Debug|CHPE + {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Debug|CHPE.Build.0 = Debug|CHPE + {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Debug|CHPE.Deploy.0 = Debug|CHPE {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Debug|x64.ActiveCfg = Debug|x64 {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Debug|x64.Build.0 = Debug|x64 {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Debug|x86.ActiveCfg = Debug|Win32 @@ -218,6 +233,10 @@ Global {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Release|ARM.Build.0 = Release|ARM {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Release|ARM64.ActiveCfg = Release|ARM64 {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Release|ARM64.Build.0 = Release|ARM64 + {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Release|ARM64.Deploy.0 = Release|ARM64 + {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Release|CHPE.ActiveCfg = Release|CHPE + {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Release|CHPE.Build.0 = Release|CHPE + {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Release|CHPE.Deploy.0 = Release|CHPE {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Release|x64.ActiveCfg = Release|x64 {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Release|x64.Build.0 = Release|x64 {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Release|x86.ActiveCfg = Release|Win32 @@ -226,6 +245,10 @@ Global {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Test|ARM.Build.0 = Test|ARM {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Test|ARM64.ActiveCfg = Test|ARM64 {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Test|ARM64.Build.0 = Test|ARM64 + {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Test|ARM64.Deploy.0 = Test|ARM64 + {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Test|CHPE.ActiveCfg = Test|CHPE + {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Test|CHPE.Build.0 = Test|CHPE + {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Test|CHPE.Deploy.0 = Test|CHPE {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Test|x64.ActiveCfg = Test|x64 {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Test|x64.Build.0 = Test|x64 {1876E800-AD77-48C4-A2F7-E5265F24AC38}.Test|x86.ActiveCfg = Test|Win32 @@ -234,6 +257,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9110F5}.Debug|ARM.Build.0 = Debug|ARM {706083F7-6AA4-4558-A153-6352EF9110F5}.Debug|ARM64.ActiveCfg = Debug|ARM64 {706083F7-6AA4-4558-A153-6352EF9110F5}.Debug|ARM64.Build.0 = Debug|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F5}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F5}.Debug|CHPE.ActiveCfg = Debug|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F5}.Debug|CHPE.Build.0 = Debug|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F5}.Debug|CHPE.Deploy.0 = Debug|CHPE {706083F7-6AA4-4558-A153-6352EF9110F5}.Debug|x64.ActiveCfg = Debug|x64 {706083F7-6AA4-4558-A153-6352EF9110F5}.Debug|x64.Build.0 = Debug|x64 {706083F7-6AA4-4558-A153-6352EF9110F5}.Debug|x86.ActiveCfg = Debug|Win32 @@ -242,6 +269,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9110F5}.Release|ARM.Build.0 = Release|ARM {706083F7-6AA4-4558-A153-6352EF9110F5}.Release|ARM64.ActiveCfg = Release|ARM64 {706083F7-6AA4-4558-A153-6352EF9110F5}.Release|ARM64.Build.0 = Release|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F5}.Release|ARM64.Deploy.0 = Release|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F5}.Release|CHPE.ActiveCfg = Release|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F5}.Release|CHPE.Build.0 = Release|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F5}.Release|CHPE.Deploy.0 = Release|CHPE {706083F7-6AA4-4558-A153-6352EF9110F5}.Release|x64.ActiveCfg = Release|x64 {706083F7-6AA4-4558-A153-6352EF9110F5}.Release|x64.Build.0 = Release|x64 {706083F7-6AA4-4558-A153-6352EF9110F5}.Release|x86.ActiveCfg = Release|Win32 @@ -250,6 +281,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9110F5}.Test|ARM.Build.0 = Test|ARM {706083F7-6AA4-4558-A153-6352EF9110F5}.Test|ARM64.ActiveCfg = Test|ARM64 {706083F7-6AA4-4558-A153-6352EF9110F5}.Test|ARM64.Build.0 = Test|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F5}.Test|ARM64.Deploy.0 = Test|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F5}.Test|CHPE.ActiveCfg = Test|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F5}.Test|CHPE.Build.0 = Test|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F5}.Test|CHPE.Deploy.0 = Test|CHPE {706083F7-6AA4-4558-A153-6352EF9110F5}.Test|x64.ActiveCfg = Test|x64 {706083F7-6AA4-4558-A153-6352EF9110F5}.Test|x64.Build.0 = Test|x64 {706083F7-6AA4-4558-A153-6352EF9110F5}.Test|x86.ActiveCfg = Test|Win32 @@ -258,6 +293,10 @@ Global {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Debug|ARM.Build.0 = Debug|ARM {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Debug|ARM64.ActiveCfg = Debug|ARM64 {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Debug|ARM64.Build.0 = Debug|ARM64 + {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Debug|CHPE.ActiveCfg = Debug|CHPE + {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Debug|CHPE.Build.0 = Debug|CHPE + {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Debug|CHPE.Deploy.0 = Debug|CHPE {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Debug|x64.ActiveCfg = Debug|x64 {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Debug|x64.Build.0 = Debug|x64 {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Debug|x86.ActiveCfg = Debug|Win32 @@ -266,6 +305,10 @@ Global {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Release|ARM.Build.0 = Release|ARM {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Release|ARM64.ActiveCfg = Release|ARM64 {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Release|ARM64.Build.0 = Release|ARM64 + {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Release|ARM64.Deploy.0 = Release|ARM64 + {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Release|CHPE.ActiveCfg = Release|CHPE + {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Release|CHPE.Build.0 = Release|CHPE + {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Release|CHPE.Deploy.0 = Release|CHPE {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Release|x64.ActiveCfg = Release|x64 {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Release|x64.Build.0 = Release|x64 {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Release|x86.ActiveCfg = Release|Win32 @@ -274,6 +317,10 @@ Global {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Test|ARM.Build.0 = Test|ARM {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Test|ARM64.ActiveCfg = Test|ARM64 {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Test|ARM64.Build.0 = Test|ARM64 + {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Test|ARM64.Deploy.0 = Test|ARM64 + {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Test|CHPE.ActiveCfg = Test|CHPE + {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Test|CHPE.Build.0 = Test|CHPE + {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Test|CHPE.Deploy.0 = Test|CHPE {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Test|x64.ActiveCfg = Test|x64 {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Test|x64.Build.0 = Test|x64 {8C61E4E7-F0D6-420D-A352-3E6E50D406DD}.Test|x86.ActiveCfg = Test|Win32 @@ -282,6 +329,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9110F8}.Debug|ARM.Build.0 = Debug|ARM {706083F7-6AA4-4558-A153-6352EF9110F8}.Debug|ARM64.ActiveCfg = Debug|ARM64 {706083F7-6AA4-4558-A153-6352EF9110F8}.Debug|ARM64.Build.0 = Debug|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F8}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F8}.Debug|CHPE.ActiveCfg = Debug|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F8}.Debug|CHPE.Build.0 = Debug|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F8}.Debug|CHPE.Deploy.0 = Debug|CHPE {706083F7-6AA4-4558-A153-6352EF9110F8}.Debug|x64.ActiveCfg = Debug|x64 {706083F7-6AA4-4558-A153-6352EF9110F8}.Debug|x64.Build.0 = Debug|x64 {706083F7-6AA4-4558-A153-6352EF9110F8}.Debug|x86.ActiveCfg = Debug|Win32 @@ -290,6 +341,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9110F8}.Release|ARM.Build.0 = Release|ARM {706083F7-6AA4-4558-A153-6352EF9110F8}.Release|ARM64.ActiveCfg = Release|ARM64 {706083F7-6AA4-4558-A153-6352EF9110F8}.Release|ARM64.Build.0 = Release|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F8}.Release|ARM64.Deploy.0 = Release|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F8}.Release|CHPE.ActiveCfg = Release|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F8}.Release|CHPE.Build.0 = Release|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F8}.Release|CHPE.Deploy.0 = Release|CHPE {706083F7-6AA4-4558-A153-6352EF9110F8}.Release|x64.ActiveCfg = Release|x64 {706083F7-6AA4-4558-A153-6352EF9110F8}.Release|x64.Build.0 = Release|x64 {706083F7-6AA4-4558-A153-6352EF9110F8}.Release|x86.ActiveCfg = Release|Win32 @@ -298,6 +353,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9110F8}.Test|ARM.Build.0 = Test|ARM {706083F7-6AA4-4558-A153-6352EF9110F8}.Test|ARM64.ActiveCfg = Test|ARM64 {706083F7-6AA4-4558-A153-6352EF9110F8}.Test|ARM64.Build.0 = Test|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F8}.Test|ARM64.Deploy.0 = Test|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F8}.Test|CHPE.ActiveCfg = Test|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F8}.Test|CHPE.Build.0 = Test|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F8}.Test|CHPE.Deploy.0 = Test|CHPE {706083F7-6AA4-4558-A153-6352EF9110F8}.Test|x64.ActiveCfg = Test|x64 {706083F7-6AA4-4558-A153-6352EF9110F8}.Test|x64.Build.0 = Test|x64 {706083F7-6AA4-4558-A153-6352EF9110F8}.Test|x86.ActiveCfg = Test|Win32 @@ -306,6 +365,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9110F7}.Debug|ARM.Build.0 = Debug|ARM {706083F7-6AA4-4558-A153-6352EF9110F7}.Debug|ARM64.ActiveCfg = Debug|ARM64 {706083F7-6AA4-4558-A153-6352EF9110F7}.Debug|ARM64.Build.0 = Debug|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F7}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F7}.Debug|CHPE.ActiveCfg = Debug|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F7}.Debug|CHPE.Build.0 = Debug|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F7}.Debug|CHPE.Deploy.0 = Debug|CHPE {706083F7-6AA4-4558-A153-6352EF9110F7}.Debug|x64.ActiveCfg = Debug|x64 {706083F7-6AA4-4558-A153-6352EF9110F7}.Debug|x64.Build.0 = Debug|x64 {706083F7-6AA4-4558-A153-6352EF9110F7}.Debug|x86.ActiveCfg = Debug|Win32 @@ -314,6 +377,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9110F7}.Release|ARM.Build.0 = Release|ARM {706083F7-6AA4-4558-A153-6352EF9110F7}.Release|ARM64.ActiveCfg = Release|ARM64 {706083F7-6AA4-4558-A153-6352EF9110F7}.Release|ARM64.Build.0 = Release|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F7}.Release|ARM64.Deploy.0 = Release|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F7}.Release|CHPE.ActiveCfg = Release|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F7}.Release|CHPE.Build.0 = Release|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F7}.Release|CHPE.Deploy.0 = Release|CHPE {706083F7-6AA4-4558-A153-6352EF9110F7}.Release|x64.ActiveCfg = Release|x64 {706083F7-6AA4-4558-A153-6352EF9110F7}.Release|x64.Build.0 = Release|x64 {706083F7-6AA4-4558-A153-6352EF9110F7}.Release|x86.ActiveCfg = Release|Win32 @@ -322,6 +389,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9110F7}.Test|ARM.Build.0 = Test|ARM {706083F7-6AA4-4558-A153-6352EF9110F7}.Test|ARM64.ActiveCfg = Test|ARM64 {706083F7-6AA4-4558-A153-6352EF9110F7}.Test|ARM64.Build.0 = Test|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F7}.Test|ARM64.Deploy.0 = Test|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F7}.Test|CHPE.ActiveCfg = Test|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F7}.Test|CHPE.Build.0 = Test|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F7}.Test|CHPE.Deploy.0 = Test|CHPE {706083F7-6AA4-4558-A153-6352EF9110F7}.Test|x64.ActiveCfg = Test|x64 {706083F7-6AA4-4558-A153-6352EF9110F7}.Test|x64.Build.0 = Test|x64 {706083F7-6AA4-4558-A153-6352EF9110F7}.Test|x86.ActiveCfg = Test|Win32 @@ -330,6 +401,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9110F6}.Debug|ARM.Build.0 = Debug|ARM {706083F7-6AA4-4558-A153-6352EF9110F6}.Debug|ARM64.ActiveCfg = Debug|ARM64 {706083F7-6AA4-4558-A153-6352EF9110F6}.Debug|ARM64.Build.0 = Debug|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F6}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F6}.Debug|CHPE.ActiveCfg = Debug|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F6}.Debug|CHPE.Build.0 = Debug|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F6}.Debug|CHPE.Deploy.0 = Debug|CHPE {706083F7-6AA4-4558-A153-6352EF9110F6}.Debug|x64.ActiveCfg = Debug|x64 {706083F7-6AA4-4558-A153-6352EF9110F6}.Debug|x64.Build.0 = Debug|x64 {706083F7-6AA4-4558-A153-6352EF9110F6}.Debug|x86.ActiveCfg = Debug|Win32 @@ -338,6 +413,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9110F6}.Release|ARM.Build.0 = Release|ARM {706083F7-6AA4-4558-A153-6352EF9110F6}.Release|ARM64.ActiveCfg = Release|ARM64 {706083F7-6AA4-4558-A153-6352EF9110F6}.Release|ARM64.Build.0 = Release|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F6}.Release|ARM64.Deploy.0 = Release|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F6}.Release|CHPE.ActiveCfg = Release|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F6}.Release|CHPE.Build.0 = Release|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F6}.Release|CHPE.Deploy.0 = Release|CHPE {706083F7-6AA4-4558-A153-6352EF9110F6}.Release|x64.ActiveCfg = Release|x64 {706083F7-6AA4-4558-A153-6352EF9110F6}.Release|x64.Build.0 = Release|x64 {706083F7-6AA4-4558-A153-6352EF9110F6}.Release|x86.ActiveCfg = Release|Win32 @@ -346,6 +425,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9110F6}.Test|ARM.Build.0 = Test|ARM {706083F7-6AA4-4558-A153-6352EF9110F6}.Test|ARM64.ActiveCfg = Test|ARM64 {706083F7-6AA4-4558-A153-6352EF9110F6}.Test|ARM64.Build.0 = Test|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F6}.Test|ARM64.Deploy.0 = Test|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110F6}.Test|CHPE.ActiveCfg = Test|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F6}.Test|CHPE.Build.0 = Test|CHPE + {706083F7-6AA4-4558-A153-6352EF9110F6}.Test|CHPE.Deploy.0 = Test|CHPE {706083F7-6AA4-4558-A153-6352EF9110F6}.Test|x64.ActiveCfg = Test|x64 {706083F7-6AA4-4558-A153-6352EF9110F6}.Test|x64.Build.0 = Test|x64 {706083F7-6AA4-4558-A153-6352EF9110F6}.Test|x86.ActiveCfg = Test|Win32 @@ -354,6 +437,10 @@ Global {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|ARM.Build.0 = Debug|ARM {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|ARM64.ActiveCfg = Debug|ARM64 {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|ARM64.Build.0 = Debug|ARM64 + {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|CHPE.ActiveCfg = Debug|CHPE + {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|CHPE.Build.0 = Debug|CHPE + {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|CHPE.Deploy.0 = Debug|CHPE {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|x64.ActiveCfg = Debug|x64 {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|x64.Build.0 = Debug|x64 {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|x86.ActiveCfg = Debug|Win32 @@ -362,6 +449,10 @@ Global {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Release|ARM.Build.0 = Release|ARM {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Release|ARM64.ActiveCfg = Release|ARM64 {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Release|ARM64.Build.0 = Release|ARM64 + {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Release|ARM64.Deploy.0 = Release|ARM64 + {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Release|CHPE.ActiveCfg = Release|CHPE + {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Release|CHPE.Build.0 = Release|CHPE + {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Release|CHPE.Deploy.0 = Release|CHPE {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Release|x64.ActiveCfg = Release|x64 {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Release|x64.Build.0 = Release|x64 {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Release|x86.ActiveCfg = Release|Win32 @@ -370,6 +461,10 @@ Global {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Test|ARM.Build.0 = Test|ARM {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Test|ARM64.ActiveCfg = Test|ARM64 {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Test|ARM64.Build.0 = Test|ARM64 + {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Test|ARM64.Deploy.0 = Test|ARM64 + {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Test|CHPE.ActiveCfg = Test|CHPE + {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Test|CHPE.Build.0 = Test|CHPE + {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Test|CHPE.Deploy.0 = Test|CHPE {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Test|x64.ActiveCfg = Test|x64 {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Test|x64.Build.0 = Test|x64 {BB4153FF-AC3E-4734-B562-CC23812DF31B}.Test|x86.ActiveCfg = Test|Win32 @@ -378,6 +473,10 @@ Global {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|ARM.Build.0 = Debug|ARM {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|ARM64.ActiveCfg = Debug|ARM64 {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|ARM64.Build.0 = Debug|ARM64 + {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|CHPE.ActiveCfg = Debug|CHPE + {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|CHPE.Build.0 = Debug|CHPE + {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|CHPE.Deploy.0 = Debug|CHPE {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|x64.ActiveCfg = Debug|x64 {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|x64.Build.0 = Debug|x64 {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Debug|x86.ActiveCfg = Debug|Win32 @@ -386,6 +485,10 @@ Global {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Release|ARM.Build.0 = Release|ARM {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Release|ARM64.ActiveCfg = Release|ARM64 {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Release|ARM64.Build.0 = Release|ARM64 + {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Release|ARM64.Deploy.0 = Release|ARM64 + {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Release|CHPE.ActiveCfg = Release|CHPE + {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Release|CHPE.Build.0 = Release|CHPE + {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Release|CHPE.Deploy.0 = Release|CHPE {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Release|x64.ActiveCfg = Release|x64 {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Release|x64.Build.0 = Release|x64 {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Release|x86.ActiveCfg = Release|Win32 @@ -394,6 +497,10 @@ Global {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Test|ARM.Build.0 = Test|ARM {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Test|ARM64.ActiveCfg = Test|ARM64 {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Test|ARM64.Build.0 = Test|ARM64 + {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Test|ARM64.Deploy.0 = Test|ARM64 + {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Test|CHPE.ActiveCfg = Test|CHPE + {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Test|CHPE.Build.0 = Test|CHPE + {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Test|CHPE.Deploy.0 = Test|CHPE {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Test|x64.ActiveCfg = Test|x64 {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Test|x64.Build.0 = Test|x64 {CC4153FF-AC3E-4734-B562-CC23812DF31B}.Test|x86.ActiveCfg = Test|Win32 @@ -402,6 +509,10 @@ Global {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Debug|ARM.Build.0 = Debug|ARM {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Debug|ARM64.ActiveCfg = Debug|ARM64 {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Debug|ARM64.Build.0 = Debug|ARM64 + {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Debug|CHPE.ActiveCfg = Debug|CHPE + {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Debug|CHPE.Build.0 = Debug|CHPE + {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Debug|CHPE.Deploy.0 = Debug|CHPE {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Debug|x64.ActiveCfg = Debug|x64 {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Debug|x64.Build.0 = Debug|x64 {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Debug|x86.ActiveCfg = Debug|Win32 @@ -410,6 +521,10 @@ Global {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Release|ARM.Build.0 = Release|ARM {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Release|ARM64.ActiveCfg = Release|ARM64 {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Release|ARM64.Build.0 = Release|ARM64 + {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Release|ARM64.Deploy.0 = Release|ARM64 + {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Release|CHPE.ActiveCfg = Release|CHPE + {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Release|CHPE.Build.0 = Release|CHPE + {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Release|CHPE.Deploy.0 = Release|CHPE {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Release|x64.ActiveCfg = Release|x64 {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Release|x64.Build.0 = Release|x64 {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Release|x86.ActiveCfg = Release|Win32 @@ -418,6 +533,10 @@ Global {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Test|ARM.Build.0 = Test|ARM {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Test|ARM64.ActiveCfg = Test|ARM64 {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Test|ARM64.Build.0 = Test|ARM64 + {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Test|ARM64.Deploy.0 = Test|ARM64 + {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Test|CHPE.ActiveCfg = Test|CHPE + {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Test|CHPE.Build.0 = Test|CHPE + {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Test|CHPE.Deploy.0 = Test|CHPE {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Test|x64.ActiveCfg = Test|x64 {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Test|x64.Build.0 = Test|x64 {5643D42A-C38D-4D82-9662-58470B3AC9F7}.Test|x86.ActiveCfg = Test|Win32 @@ -426,6 +545,10 @@ Global {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Debug|ARM.Build.0 = Debug|ARM {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Debug|ARM64.ActiveCfg = Debug|ARM64 {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Debug|ARM64.Build.0 = Debug|ARM64 + {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Debug|CHPE.ActiveCfg = Debug|CHPE + {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Debug|CHPE.Build.0 = Debug|CHPE + {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Debug|CHPE.Deploy.0 = Debug|CHPE {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Debug|x64.ActiveCfg = Debug|x64 {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Debug|x64.Build.0 = Debug|x64 {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Debug|x86.ActiveCfg = Debug|Win32 @@ -434,6 +557,10 @@ Global {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Release|ARM.Build.0 = Release|ARM {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Release|ARM64.ActiveCfg = Release|ARM64 {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Release|ARM64.Build.0 = Release|ARM64 + {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Release|ARM64.Deploy.0 = Release|ARM64 + {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Release|CHPE.ActiveCfg = Release|CHPE + {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Release|CHPE.Build.0 = Release|CHPE + {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Release|CHPE.Deploy.0 = Release|CHPE {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Release|x64.ActiveCfg = Release|x64 {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Release|x64.Build.0 = Release|x64 {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Release|x86.ActiveCfg = Release|Win32 @@ -442,6 +569,10 @@ Global {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Test|ARM.Build.0 = Test|ARM {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Test|ARM64.ActiveCfg = Test|ARM64 {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Test|ARM64.Build.0 = Test|ARM64 + {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Test|ARM64.Deploy.0 = Test|ARM64 + {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Test|CHPE.ActiveCfg = Test|CHPE + {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Test|CHPE.Build.0 = Test|CHPE + {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Test|CHPE.Deploy.0 = Test|CHPE {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Test|x64.ActiveCfg = Test|x64 {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Test|x64.Build.0 = Test|x64 {FD8EEC40-4141-448A-BF4B-1589FBE4F60D}.Test|x86.ActiveCfg = Test|Win32 @@ -450,6 +581,10 @@ Global {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Debug|ARM.Build.0 = Debug|ARM {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Debug|ARM64.ActiveCfg = Debug|ARM64 {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Debug|ARM64.Build.0 = Debug|ARM64 + {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Debug|CHPE.ActiveCfg = Debug|CHPE + {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Debug|CHPE.Build.0 = Debug|CHPE + {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Debug|CHPE.Deploy.0 = Debug|CHPE {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Debug|x64.ActiveCfg = Debug|x64 {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Debug|x64.Build.0 = Debug|x64 {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Debug|x86.ActiveCfg = Debug|Win32 @@ -458,6 +593,10 @@ Global {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Release|ARM.Build.0 = Release|ARM {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Release|ARM64.ActiveCfg = Release|ARM64 {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Release|ARM64.Build.0 = Release|ARM64 + {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Release|ARM64.Deploy.0 = Release|ARM64 + {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Release|CHPE.ActiveCfg = Release|CHPE + {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Release|CHPE.Build.0 = Release|CHPE + {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Release|CHPE.Deploy.0 = Release|CHPE {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Release|x64.ActiveCfg = Release|x64 {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Release|x64.Build.0 = Release|x64 {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Release|x86.ActiveCfg = Release|Win32 @@ -466,6 +605,10 @@ Global {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Test|ARM.Build.0 = Test|ARM {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Test|ARM64.ActiveCfg = Test|ARM64 {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Test|ARM64.Build.0 = Test|ARM64 + {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Test|ARM64.Deploy.0 = Test|ARM64 + {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Test|CHPE.ActiveCfg = Test|CHPE + {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Test|CHPE.Build.0 = Test|CHPE + {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Test|CHPE.Deploy.0 = Test|CHPE {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Test|x64.ActiveCfg = Test|x64 {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Test|x64.Build.0 = Test|x64 {BB4153FF-AC3E-4734-B562-FF23812DF31B}.Test|x86.ActiveCfg = Test|Win32 @@ -474,6 +617,10 @@ Global {18CF279F-188D-4655-B03D-74F65388E7D1}.Debug|ARM.Build.0 = Debug|ARM {18CF279F-188D-4655-B03D-74F65388E7D1}.Debug|ARM64.ActiveCfg = Debug|ARM64 {18CF279F-188D-4655-B03D-74F65388E7D1}.Debug|ARM64.Build.0 = Debug|ARM64 + {18CF279F-188D-4655-B03D-74F65388E7D1}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {18CF279F-188D-4655-B03D-74F65388E7D1}.Debug|CHPE.ActiveCfg = Debug|CHPE + {18CF279F-188D-4655-B03D-74F65388E7D1}.Debug|CHPE.Build.0 = Debug|CHPE + {18CF279F-188D-4655-B03D-74F65388E7D1}.Debug|CHPE.Deploy.0 = Debug|CHPE {18CF279F-188D-4655-B03D-74F65388E7D1}.Debug|x64.ActiveCfg = Debug|x64 {18CF279F-188D-4655-B03D-74F65388E7D1}.Debug|x64.Build.0 = Debug|x64 {18CF279F-188D-4655-B03D-74F65388E7D1}.Debug|x86.ActiveCfg = Debug|Win32 @@ -482,6 +629,10 @@ Global {18CF279F-188D-4655-B03D-74F65388E7D1}.Release|ARM.Build.0 = Release|ARM {18CF279F-188D-4655-B03D-74F65388E7D1}.Release|ARM64.ActiveCfg = Release|ARM64 {18CF279F-188D-4655-B03D-74F65388E7D1}.Release|ARM64.Build.0 = Release|ARM64 + {18CF279F-188D-4655-B03D-74F65388E7D1}.Release|ARM64.Deploy.0 = Release|ARM64 + {18CF279F-188D-4655-B03D-74F65388E7D1}.Release|CHPE.ActiveCfg = Release|CHPE + {18CF279F-188D-4655-B03D-74F65388E7D1}.Release|CHPE.Build.0 = Release|CHPE + {18CF279F-188D-4655-B03D-74F65388E7D1}.Release|CHPE.Deploy.0 = Release|CHPE {18CF279F-188D-4655-B03D-74F65388E7D1}.Release|x64.ActiveCfg = Release|x64 {18CF279F-188D-4655-B03D-74F65388E7D1}.Release|x64.Build.0 = Release|x64 {18CF279F-188D-4655-B03D-74F65388E7D1}.Release|x86.ActiveCfg = Release|Win32 @@ -490,6 +641,10 @@ Global {18CF279F-188D-4655-B03D-74F65388E7D1}.Test|ARM.Build.0 = Test|ARM {18CF279F-188D-4655-B03D-74F65388E7D1}.Test|ARM64.ActiveCfg = Test|ARM64 {18CF279F-188D-4655-B03D-74F65388E7D1}.Test|ARM64.Build.0 = Test|ARM64 + {18CF279F-188D-4655-B03D-74F65388E7D1}.Test|ARM64.Deploy.0 = Test|ARM64 + {18CF279F-188D-4655-B03D-74F65388E7D1}.Test|CHPE.ActiveCfg = Test|CHPE + {18CF279F-188D-4655-B03D-74F65388E7D1}.Test|CHPE.Build.0 = Test|CHPE + {18CF279F-188D-4655-B03D-74F65388E7D1}.Test|CHPE.Deploy.0 = Test|CHPE {18CF279F-188D-4655-B03D-74F65388E7D1}.Test|x64.ActiveCfg = Test|x64 {18CF279F-188D-4655-B03D-74F65388E7D1}.Test|x64.Build.0 = Test|x64 {18CF279F-188D-4655-B03D-74F65388E7D1}.Test|x86.ActiveCfg = Test|Win32 @@ -498,6 +653,10 @@ Global {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Debug|ARM.Build.0 = Debug|ARM {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Debug|ARM64.ActiveCfg = Debug|ARM64 {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Debug|ARM64.Build.0 = Debug|ARM64 + {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Debug|CHPE.ActiveCfg = Debug|CHPE + {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Debug|CHPE.Build.0 = Debug|CHPE + {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Debug|CHPE.Deploy.0 = Debug|CHPE {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Debug|x64.ActiveCfg = Debug|x64 {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Debug|x64.Build.0 = Debug|x64 {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Debug|x86.ActiveCfg = Debug|Win32 @@ -506,6 +665,10 @@ Global {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Release|ARM.Build.0 = Release|ARM {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Release|ARM64.ActiveCfg = Release|ARM64 {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Release|ARM64.Build.0 = Release|ARM64 + {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Release|ARM64.Deploy.0 = Release|ARM64 + {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Release|CHPE.ActiveCfg = Release|CHPE + {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Release|CHPE.Build.0 = Release|CHPE + {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Release|CHPE.Deploy.0 = Release|CHPE {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Release|x64.ActiveCfg = Release|x64 {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Release|x64.Build.0 = Release|x64 {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Release|x86.ActiveCfg = Release|Win32 @@ -514,6 +677,10 @@ Global {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Test|ARM.Build.0 = Test|ARM {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Test|ARM64.ActiveCfg = Test|ARM64 {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Test|ARM64.Build.0 = Test|ARM64 + {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Test|ARM64.Deploy.0 = Test|ARM64 + {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Test|CHPE.ActiveCfg = Test|CHPE + {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Test|CHPE.Build.0 = Test|CHPE + {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Test|CHPE.Deploy.0 = Test|CHPE {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Test|x64.ActiveCfg = Test|x64 {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Test|x64.Build.0 = Test|x64 {F6FAD160-5A4B-476A-93AC-33E0B3A18C0C}.Test|x86.ActiveCfg = Test|Win32 @@ -522,6 +689,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9220F5}.Debug|ARM.Build.0 = Debug|ARM {706083F7-6AA4-4558-A153-6352EF9220F5}.Debug|ARM64.ActiveCfg = Debug|ARM64 {706083F7-6AA4-4558-A153-6352EF9220F5}.Debug|ARM64.Build.0 = Debug|ARM64 + {706083F7-6AA4-4558-A153-6352EF9220F5}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {706083F7-6AA4-4558-A153-6352EF9220F5}.Debug|CHPE.ActiveCfg = Debug|CHPE + {706083F7-6AA4-4558-A153-6352EF9220F5}.Debug|CHPE.Build.0 = Debug|CHPE + {706083F7-6AA4-4558-A153-6352EF9220F5}.Debug|CHPE.Deploy.0 = Debug|CHPE {706083F7-6AA4-4558-A153-6352EF9220F5}.Debug|x64.ActiveCfg = Debug|x64 {706083F7-6AA4-4558-A153-6352EF9220F5}.Debug|x64.Build.0 = Debug|x64 {706083F7-6AA4-4558-A153-6352EF9220F5}.Debug|x86.ActiveCfg = Debug|Win32 @@ -530,6 +701,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9220F5}.Release|ARM.Build.0 = Release|ARM {706083F7-6AA4-4558-A153-6352EF9220F5}.Release|ARM64.ActiveCfg = Release|ARM64 {706083F7-6AA4-4558-A153-6352EF9220F5}.Release|ARM64.Build.0 = Release|ARM64 + {706083F7-6AA4-4558-A153-6352EF9220F5}.Release|ARM64.Deploy.0 = Release|ARM64 + {706083F7-6AA4-4558-A153-6352EF9220F5}.Release|CHPE.ActiveCfg = Release|CHPE + {706083F7-6AA4-4558-A153-6352EF9220F5}.Release|CHPE.Build.0 = Release|CHPE + {706083F7-6AA4-4558-A153-6352EF9220F5}.Release|CHPE.Deploy.0 = Release|CHPE {706083F7-6AA4-4558-A153-6352EF9220F5}.Release|x64.ActiveCfg = Release|x64 {706083F7-6AA4-4558-A153-6352EF9220F5}.Release|x64.Build.0 = Release|x64 {706083F7-6AA4-4558-A153-6352EF9220F5}.Release|x86.ActiveCfg = Release|Win32 @@ -538,6 +713,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9220F5}.Test|ARM.Build.0 = Test|ARM {706083F7-6AA4-4558-A153-6352EF9220F5}.Test|ARM64.ActiveCfg = Test|ARM64 {706083F7-6AA4-4558-A153-6352EF9220F5}.Test|ARM64.Build.0 = Test|ARM64 + {706083F7-6AA4-4558-A153-6352EF9220F5}.Test|ARM64.Deploy.0 = Test|ARM64 + {706083F7-6AA4-4558-A153-6352EF9220F5}.Test|CHPE.ActiveCfg = Test|CHPE + {706083F7-6AA4-4558-A153-6352EF9220F5}.Test|CHPE.Build.0 = Test|CHPE + {706083F7-6AA4-4558-A153-6352EF9220F5}.Test|CHPE.Deploy.0 = Test|CHPE {706083F7-6AA4-4558-A153-6352EF9220F5}.Test|x64.ActiveCfg = Test|x64 {706083F7-6AA4-4558-A153-6352EF9220F5}.Test|x64.Build.0 = Test|x64 {706083F7-6AA4-4558-A153-6352EF9220F5}.Test|x86.ActiveCfg = Test|Win32 @@ -546,6 +725,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9220EE}.Debug|ARM.Build.0 = Debug|ARM {706083F7-6AA4-4558-A153-6352EF9220EE}.Debug|ARM64.ActiveCfg = Debug|ARM64 {706083F7-6AA4-4558-A153-6352EF9220EE}.Debug|ARM64.Build.0 = Debug|ARM64 + {706083F7-6AA4-4558-A153-6352EF9220EE}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {706083F7-6AA4-4558-A153-6352EF9220EE}.Debug|CHPE.ActiveCfg = Debug|CHPE + {706083F7-6AA4-4558-A153-6352EF9220EE}.Debug|CHPE.Build.0 = Debug|CHPE + {706083F7-6AA4-4558-A153-6352EF9220EE}.Debug|CHPE.Deploy.0 = Debug|CHPE {706083F7-6AA4-4558-A153-6352EF9220EE}.Debug|x64.ActiveCfg = Debug|x64 {706083F7-6AA4-4558-A153-6352EF9220EE}.Debug|x64.Build.0 = Debug|x64 {706083F7-6AA4-4558-A153-6352EF9220EE}.Debug|x86.ActiveCfg = Debug|Win32 @@ -554,6 +737,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9220EE}.Release|ARM.Build.0 = Release|ARM {706083F7-6AA4-4558-A153-6352EF9220EE}.Release|ARM64.ActiveCfg = Release|ARM64 {706083F7-6AA4-4558-A153-6352EF9220EE}.Release|ARM64.Build.0 = Release|ARM64 + {706083F7-6AA4-4558-A153-6352EF9220EE}.Release|ARM64.Deploy.0 = Release|ARM64 + {706083F7-6AA4-4558-A153-6352EF9220EE}.Release|CHPE.ActiveCfg = Release|CHPE + {706083F7-6AA4-4558-A153-6352EF9220EE}.Release|CHPE.Build.0 = Release|CHPE + {706083F7-6AA4-4558-A153-6352EF9220EE}.Release|CHPE.Deploy.0 = Release|CHPE {706083F7-6AA4-4558-A153-6352EF9220EE}.Release|x64.ActiveCfg = Release|x64 {706083F7-6AA4-4558-A153-6352EF9220EE}.Release|x64.Build.0 = Release|x64 {706083F7-6AA4-4558-A153-6352EF9220EE}.Release|x86.ActiveCfg = Release|Win32 @@ -562,6 +749,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9220EE}.Test|ARM.Build.0 = Test|ARM {706083F7-6AA4-4558-A153-6352EF9220EE}.Test|ARM64.ActiveCfg = Test|ARM64 {706083F7-6AA4-4558-A153-6352EF9220EE}.Test|ARM64.Build.0 = Test|ARM64 + {706083F7-6AA4-4558-A153-6352EF9220EE}.Test|ARM64.Deploy.0 = Test|ARM64 + {706083F7-6AA4-4558-A153-6352EF9220EE}.Test|CHPE.ActiveCfg = Test|CHPE + {706083F7-6AA4-4558-A153-6352EF9220EE}.Test|CHPE.Build.0 = Test|CHPE + {706083F7-6AA4-4558-A153-6352EF9220EE}.Test|CHPE.Deploy.0 = Test|CHPE {706083F7-6AA4-4558-A153-6352EF9220EE}.Test|x64.ActiveCfg = Test|x64 {706083F7-6AA4-4558-A153-6352EF9220EE}.Test|x64.Build.0 = Test|x64 {706083F7-6AA4-4558-A153-6352EF9220EE}.Test|x86.ActiveCfg = Test|Win32 @@ -570,6 +761,10 @@ Global {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Debug|ARM.Build.0 = Debug|ARM {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Debug|ARM64.ActiveCfg = Debug|ARM64 {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Debug|ARM64.Build.0 = Debug|ARM64 + {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Debug|CHPE.ActiveCfg = Debug|CHPE + {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Debug|CHPE.Build.0 = Debug|CHPE + {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Debug|CHPE.Deploy.0 = Debug|CHPE {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Debug|x64.ActiveCfg = Debug|x64 {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Debug|x64.Build.0 = Debug|x64 {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Debug|x86.ActiveCfg = Debug|Win32 @@ -578,6 +773,10 @@ Global {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Release|ARM.Build.0 = Release|ARM {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Release|ARM64.ActiveCfg = Release|ARM64 {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Release|ARM64.Build.0 = Release|ARM64 + {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Release|ARM64.Deploy.0 = Release|ARM64 + {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Release|CHPE.ActiveCfg = Release|CHPE + {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Release|CHPE.Build.0 = Release|CHPE + {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Release|CHPE.Deploy.0 = Release|CHPE {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Release|x64.ActiveCfg = Release|x64 {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Release|x64.Build.0 = Release|x64 {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Release|x86.ActiveCfg = Release|Win32 @@ -586,6 +785,10 @@ Global {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Test|ARM.Build.0 = Test|ARM {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Test|ARM64.ActiveCfg = Test|ARM64 {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Test|ARM64.Build.0 = Test|ARM64 + {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Test|ARM64.Deploy.0 = Test|ARM64 + {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Test|CHPE.ActiveCfg = Test|CHPE + {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Test|CHPE.Build.0 = Test|CHPE + {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Test|CHPE.Deploy.0 = Test|CHPE {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Test|x64.ActiveCfg = Test|x64 {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Test|x64.Build.0 = Test|x64 {ABC904AD-9415-46F8-AA23-E33193F81F7C}.Test|x86.ActiveCfg = Test|Win32 @@ -594,6 +797,10 @@ Global {6979EC58-7A28-465C-A694-F3323A1F5401}.Debug|ARM.Build.0 = Debug|ARM {6979EC58-7A28-465C-A694-F3323A1F5401}.Debug|ARM64.ActiveCfg = Debug|ARM64 {6979EC58-7A28-465C-A694-F3323A1F5401}.Debug|ARM64.Build.0 = Debug|ARM64 + {6979EC58-7A28-465C-A694-F3323A1F5401}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {6979EC58-7A28-465C-A694-F3323A1F5401}.Debug|CHPE.ActiveCfg = Debug|CHPE + {6979EC58-7A28-465C-A694-F3323A1F5401}.Debug|CHPE.Build.0 = Debug|CHPE + {6979EC58-7A28-465C-A694-F3323A1F5401}.Debug|CHPE.Deploy.0 = Debug|CHPE {6979EC58-7A28-465C-A694-F3323A1F5401}.Debug|x64.ActiveCfg = Debug|x64 {6979EC58-7A28-465C-A694-F3323A1F5401}.Debug|x64.Build.0 = Debug|x64 {6979EC58-7A28-465C-A694-F3323A1F5401}.Debug|x86.ActiveCfg = Debug|Win32 @@ -602,6 +809,10 @@ Global {6979EC58-7A28-465C-A694-F3323A1F5401}.Release|ARM.Build.0 = Release|ARM {6979EC58-7A28-465C-A694-F3323A1F5401}.Release|ARM64.ActiveCfg = Release|ARM64 {6979EC58-7A28-465C-A694-F3323A1F5401}.Release|ARM64.Build.0 = Release|ARM64 + {6979EC58-7A28-465C-A694-F3323A1F5401}.Release|ARM64.Deploy.0 = Release|ARM64 + {6979EC58-7A28-465C-A694-F3323A1F5401}.Release|CHPE.ActiveCfg = Release|CHPE + {6979EC58-7A28-465C-A694-F3323A1F5401}.Release|CHPE.Build.0 = Release|CHPE + {6979EC58-7A28-465C-A694-F3323A1F5401}.Release|CHPE.Deploy.0 = Release|CHPE {6979EC58-7A28-465C-A694-F3323A1F5401}.Release|x64.ActiveCfg = Release|x64 {6979EC58-7A28-465C-A694-F3323A1F5401}.Release|x64.Build.0 = Release|x64 {6979EC58-7A28-465C-A694-F3323A1F5401}.Release|x86.ActiveCfg = Release|Win32 @@ -610,6 +821,10 @@ Global {6979EC58-7A28-465C-A694-F3323A1F5401}.Test|ARM.Build.0 = Test|ARM {6979EC58-7A28-465C-A694-F3323A1F5401}.Test|ARM64.ActiveCfg = Test|ARM64 {6979EC58-7A28-465C-A694-F3323A1F5401}.Test|ARM64.Build.0 = Test|ARM64 + {6979EC58-7A28-465C-A694-F3323A1F5401}.Test|ARM64.Deploy.0 = Test|ARM64 + {6979EC58-7A28-465C-A694-F3323A1F5401}.Test|CHPE.ActiveCfg = Test|CHPE + {6979EC58-7A28-465C-A694-F3323A1F5401}.Test|CHPE.Build.0 = Test|CHPE + {6979EC58-7A28-465C-A694-F3323A1F5401}.Test|CHPE.Deploy.0 = Test|CHPE {6979EC58-7A28-465C-A694-F3323A1F5401}.Test|x64.ActiveCfg = Test|x64 {6979EC58-7A28-465C-A694-F3323A1F5401}.Test|x64.Build.0 = Test|x64 {6979EC58-7A28-465C-A694-F3323A1F5401}.Test|x86.ActiveCfg = Test|Win32 @@ -618,6 +833,8 @@ Global {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Debug|ARM.Build.0 = Debug|ARM {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Debug|ARM64.ActiveCfg = Debug|ARM64 {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Debug|ARM64.Build.0 = Debug|ARM64 + {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Debug|CHPE.ActiveCfg = Debug|CHPE + {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Debug|CHPE.Build.0 = Debug|CHPE {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Debug|x64.ActiveCfg = Debug|x64 {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Debug|x64.Build.0 = Debug|x64 {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Debug|x86.ActiveCfg = Debug|Win32 @@ -626,6 +843,8 @@ Global {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Release|ARM.Build.0 = Release|ARM {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Release|ARM64.ActiveCfg = Release|ARM64 {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Release|ARM64.Build.0 = Release|ARM64 + {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Release|CHPE.ActiveCfg = Release|CHPE + {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Release|CHPE.Build.0 = Release|CHPE {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Release|x64.ActiveCfg = Release|x64 {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Release|x64.Build.0 = Release|x64 {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Release|x86.ActiveCfg = Release|Win32 @@ -634,6 +853,8 @@ Global {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Test|ARM.Build.0 = Test|ARM {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Test|ARM64.ActiveCfg = Test|ARM64 {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Test|ARM64.Build.0 = Test|ARM64 + {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Test|CHPE.ActiveCfg = Test|CHPE + {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Test|CHPE.Build.0 = Test|CHPE {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Test|x64.ActiveCfg = Test|x64 {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Test|x64.Build.0 = Test|x64 {0216C4BE-86CE-478D-A134-23EAEE545B9D}.Test|x86.ActiveCfg = Test|Win32 @@ -642,6 +863,10 @@ Global {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Debug|ARM.Build.0 = Debug|ARM {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Debug|ARM64.ActiveCfg = Debug|ARM64 {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Debug|ARM64.Build.0 = Debug|ARM64 + {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Debug|CHPE.ActiveCfg = Debug|CHPE + {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Debug|CHPE.Build.0 = Debug|CHPE + {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Debug|CHPE.Deploy.0 = Debug|CHPE {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Debug|x64.ActiveCfg = Debug|x64 {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Debug|x64.Build.0 = Debug|x64 {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Debug|x86.ActiveCfg = Debug|Win32 @@ -650,6 +875,10 @@ Global {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Release|ARM.Build.0 = Release|ARM {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Release|ARM64.ActiveCfg = Release|ARM64 {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Release|ARM64.Build.0 = Release|ARM64 + {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Release|ARM64.Deploy.0 = Release|ARM64 + {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Release|CHPE.ActiveCfg = Release|CHPE + {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Release|CHPE.Build.0 = Release|CHPE + {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Release|CHPE.Deploy.0 = Release|CHPE {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Release|x64.ActiveCfg = Release|x64 {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Release|x64.Build.0 = Release|x64 {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Release|x86.ActiveCfg = Release|Win32 @@ -658,6 +887,10 @@ Global {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Test|ARM.Build.0 = Test|ARM {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Test|ARM64.ActiveCfg = Test|ARM64 {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Test|ARM64.Build.0 = Test|ARM64 + {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Test|ARM64.Deploy.0 = Test|ARM64 + {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Test|CHPE.ActiveCfg = Test|CHPE + {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Test|CHPE.Build.0 = Test|CHPE + {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Test|CHPE.Deploy.0 = Test|CHPE {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Test|x64.ActiveCfg = Test|x64 {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Test|x64.Build.0 = Test|x64 {80A70F57-0F89-458F-AFD3-CE2159EB9BB1}.Test|x86.ActiveCfg = Test|Win32 @@ -666,6 +899,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9110EE}.Debug|ARM.Build.0 = Debug|ARM {706083F7-6AA4-4558-A153-6352EF9110EE}.Debug|ARM64.ActiveCfg = Debug|ARM64 {706083F7-6AA4-4558-A153-6352EF9110EE}.Debug|ARM64.Build.0 = Debug|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110EE}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110EE}.Debug|CHPE.ActiveCfg = Debug|CHPE + {706083F7-6AA4-4558-A153-6352EF9110EE}.Debug|CHPE.Build.0 = Debug|CHPE + {706083F7-6AA4-4558-A153-6352EF9110EE}.Debug|CHPE.Deploy.0 = Debug|CHPE {706083F7-6AA4-4558-A153-6352EF9110EE}.Debug|x64.ActiveCfg = Debug|x64 {706083F7-6AA4-4558-A153-6352EF9110EE}.Debug|x64.Build.0 = Debug|x64 {706083F7-6AA4-4558-A153-6352EF9110EE}.Debug|x86.ActiveCfg = Debug|Win32 @@ -674,6 +911,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9110EE}.Release|ARM.Build.0 = Release|ARM {706083F7-6AA4-4558-A153-6352EF9110EE}.Release|ARM64.ActiveCfg = Release|ARM64 {706083F7-6AA4-4558-A153-6352EF9110EE}.Release|ARM64.Build.0 = Release|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110EE}.Release|ARM64.Deploy.0 = Release|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110EE}.Release|CHPE.ActiveCfg = Release|CHPE + {706083F7-6AA4-4558-A153-6352EF9110EE}.Release|CHPE.Build.0 = Release|CHPE + {706083F7-6AA4-4558-A153-6352EF9110EE}.Release|CHPE.Deploy.0 = Release|CHPE {706083F7-6AA4-4558-A153-6352EF9110EE}.Release|x64.ActiveCfg = Release|x64 {706083F7-6AA4-4558-A153-6352EF9110EE}.Release|x64.Build.0 = Release|x64 {706083F7-6AA4-4558-A153-6352EF9110EE}.Release|x86.ActiveCfg = Release|Win32 @@ -682,6 +923,10 @@ Global {706083F7-6AA4-4558-A153-6352EF9110EE}.Test|ARM.Build.0 = Test|ARM {706083F7-6AA4-4558-A153-6352EF9110EE}.Test|ARM64.ActiveCfg = Test|ARM64 {706083F7-6AA4-4558-A153-6352EF9110EE}.Test|ARM64.Build.0 = Test|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110EE}.Test|ARM64.Deploy.0 = Test|ARM64 + {706083F7-6AA4-4558-A153-6352EF9110EE}.Test|CHPE.ActiveCfg = Test|CHPE + {706083F7-6AA4-4558-A153-6352EF9110EE}.Test|CHPE.Build.0 = Test|CHPE + {706083F7-6AA4-4558-A153-6352EF9110EE}.Test|CHPE.Deploy.0 = Test|CHPE {706083F7-6AA4-4558-A153-6352EF9110EE}.Test|x64.ActiveCfg = Test|x64 {706083F7-6AA4-4558-A153-6352EF9110EE}.Test|x64.Build.0 = Test|x64 {706083F7-6AA4-4558-A153-6352EF9110EE}.Test|x86.ActiveCfg = Test|Win32 @@ -690,6 +935,10 @@ Global {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Debug|ARM.Build.0 = Debug|ARM {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Debug|ARM64.ActiveCfg = Debug|ARM64 {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Debug|ARM64.Build.0 = Debug|ARM64 + {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Debug|CHPE.ActiveCfg = Debug|CHPE + {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Debug|CHPE.Build.0 = Debug|CHPE + {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Debug|CHPE.Deploy.0 = Debug|CHPE {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Debug|x64.ActiveCfg = Debug|x64 {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Debug|x64.Build.0 = Debug|x64 {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Debug|x86.ActiveCfg = Debug|Win32 @@ -698,6 +947,10 @@ Global {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Release|ARM.Build.0 = Release|ARM {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Release|ARM64.ActiveCfg = Release|ARM64 {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Release|ARM64.Build.0 = Release|ARM64 + {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Release|ARM64.Deploy.0 = Release|ARM64 + {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Release|CHPE.ActiveCfg = Release|CHPE + {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Release|CHPE.Build.0 = Release|CHPE + {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Release|CHPE.Deploy.0 = Release|CHPE {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Release|x64.ActiveCfg = Release|x64 {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Release|x64.Build.0 = Release|x64 {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Release|x86.ActiveCfg = Release|Win32 @@ -706,6 +959,10 @@ Global {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Test|ARM.Build.0 = Test|ARM {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Test|ARM64.ActiveCfg = Test|ARM64 {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Test|ARM64.Build.0 = Test|ARM64 + {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Test|ARM64.Deploy.0 = Test|ARM64 + {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Test|CHPE.ActiveCfg = Test|CHPE + {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Test|CHPE.Build.0 = Test|CHPE + {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Test|CHPE.Deploy.0 = Test|CHPE {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Test|x64.ActiveCfg = Test|x64 {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Test|x64.Build.0 = Test|x64 {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD}.Test|x86.ActiveCfg = Test|Win32 @@ -714,6 +971,10 @@ Global {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Debug|ARM.Build.0 = Debug|ARM {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Debug|ARM64.ActiveCfg = Debug|ARM64 {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Debug|ARM64.Build.0 = Debug|ARM64 + {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Debug|CHPE.ActiveCfg = Debug|CHPE + {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Debug|CHPE.Build.0 = Debug|CHPE + {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Debug|CHPE.Deploy.0 = Debug|CHPE {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Debug|x64.ActiveCfg = Debug|x64 {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Debug|x64.Build.0 = Debug|x64 {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Debug|x86.ActiveCfg = Debug|Win32 @@ -722,6 +983,10 @@ Global {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Release|ARM.Build.0 = Release|ARM {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Release|ARM64.ActiveCfg = Release|ARM64 {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Release|ARM64.Build.0 = Release|ARM64 + {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Release|ARM64.Deploy.0 = Release|ARM64 + {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Release|CHPE.ActiveCfg = Release|CHPE + {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Release|CHPE.Build.0 = Release|CHPE + {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Release|CHPE.Deploy.0 = Release|CHPE {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Release|x64.ActiveCfg = Release|x64 {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Release|x64.Build.0 = Release|x64 {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Release|x86.ActiveCfg = Release|Win32 @@ -730,6 +995,10 @@ Global {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Test|ARM.Build.0 = Test|ARM {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Test|ARM64.ActiveCfg = Test|ARM64 {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Test|ARM64.Build.0 = Test|ARM64 + {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Test|ARM64.Deploy.0 = Test|ARM64 + {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Test|CHPE.ActiveCfg = Test|CHPE + {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Test|CHPE.Build.0 = Test|CHPE + {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Test|CHPE.Deploy.0 = Test|CHPE {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Test|x64.ActiveCfg = Test|x64 {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Test|x64.Build.0 = Test|x64 {73CE5C59-E0BA-413D-A73C-3EECE067891B}.Test|x86.ActiveCfg = Test|Win32 @@ -738,6 +1007,10 @@ Global {129AC184-877C-441F-AC49-A692CE700E62}.Debug|ARM.Build.0 = Debug|ARM {129AC184-877C-441F-AC49-A692CE700E62}.Debug|ARM64.ActiveCfg = Debug|ARM64 {129AC184-877C-441F-AC49-A692CE700E62}.Debug|ARM64.Build.0 = Debug|ARM64 + {129AC184-877C-441F-AC49-A692CE700E62}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {129AC184-877C-441F-AC49-A692CE700E62}.Debug|CHPE.ActiveCfg = Debug|CHPE + {129AC184-877C-441F-AC49-A692CE700E62}.Debug|CHPE.Build.0 = Debug|CHPE + {129AC184-877C-441F-AC49-A692CE700E62}.Debug|CHPE.Deploy.0 = Debug|CHPE {129AC184-877C-441F-AC49-A692CE700E62}.Debug|x64.ActiveCfg = Debug|x64 {129AC184-877C-441F-AC49-A692CE700E62}.Debug|x64.Build.0 = Debug|x64 {129AC184-877C-441F-AC49-A692CE700E62}.Debug|x86.ActiveCfg = Debug|Win32 @@ -746,6 +1019,10 @@ Global {129AC184-877C-441F-AC49-A692CE700E62}.Release|ARM.Build.0 = Release|ARM {129AC184-877C-441F-AC49-A692CE700E62}.Release|ARM64.ActiveCfg = Release|ARM64 {129AC184-877C-441F-AC49-A692CE700E62}.Release|ARM64.Build.0 = Release|ARM64 + {129AC184-877C-441F-AC49-A692CE700E62}.Release|ARM64.Deploy.0 = Release|ARM64 + {129AC184-877C-441F-AC49-A692CE700E62}.Release|CHPE.ActiveCfg = Release|CHPE + {129AC184-877C-441F-AC49-A692CE700E62}.Release|CHPE.Build.0 = Release|CHPE + {129AC184-877C-441F-AC49-A692CE700E62}.Release|CHPE.Deploy.0 = Release|CHPE {129AC184-877C-441F-AC49-A692CE700E62}.Release|x64.ActiveCfg = Release|x64 {129AC184-877C-441F-AC49-A692CE700E62}.Release|x64.Build.0 = Release|x64 {129AC184-877C-441F-AC49-A692CE700E62}.Release|x86.ActiveCfg = Release|Win32 @@ -754,6 +1031,10 @@ Global {129AC184-877C-441F-AC49-A692CE700E62}.Test|ARM.Build.0 = Test|ARM {129AC184-877C-441F-AC49-A692CE700E62}.Test|ARM64.ActiveCfg = Test|ARM64 {129AC184-877C-441F-AC49-A692CE700E62}.Test|ARM64.Build.0 = Test|ARM64 + {129AC184-877C-441F-AC49-A692CE700E62}.Test|ARM64.Deploy.0 = Test|ARM64 + {129AC184-877C-441F-AC49-A692CE700E62}.Test|CHPE.ActiveCfg = Test|CHPE + {129AC184-877C-441F-AC49-A692CE700E62}.Test|CHPE.Build.0 = Test|CHPE + {129AC184-877C-441F-AC49-A692CE700E62}.Test|CHPE.Deploy.0 = Test|CHPE {129AC184-877C-441F-AC49-A692CE700E62}.Test|x64.ActiveCfg = Test|x64 {129AC184-877C-441F-AC49-A692CE700E62}.Test|x64.Build.0 = Test|x64 {129AC184-877C-441F-AC49-A692CE700E62}.Test|x86.ActiveCfg = Test|Win32 @@ -762,6 +1043,10 @@ Global {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Debug|ARM.Build.0 = Debug|ARM {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Debug|ARM64.ActiveCfg = Debug|ARM64 {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Debug|ARM64.Build.0 = Debug|ARM64 + {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Debug|CHPE.ActiveCfg = Debug|CHPE + {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Debug|CHPE.Build.0 = Debug|CHPE + {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Debug|CHPE.Deploy.0 = Debug|CHPE {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Debug|x64.ActiveCfg = Debug|x64 {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Debug|x64.Build.0 = Debug|x64 {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Debug|x86.ActiveCfg = Debug|Win32 @@ -770,6 +1055,10 @@ Global {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Release|ARM.Build.0 = Release|ARM {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Release|ARM64.ActiveCfg = Release|ARM64 {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Release|ARM64.Build.0 = Release|ARM64 + {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Release|ARM64.Deploy.0 = Release|ARM64 + {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Release|CHPE.ActiveCfg = Release|CHPE + {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Release|CHPE.Build.0 = Release|CHPE + {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Release|CHPE.Deploy.0 = Release|CHPE {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Release|x64.ActiveCfg = Release|x64 {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Release|x64.Build.0 = Release|x64 {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Release|x86.ActiveCfg = Release|Win32 @@ -778,6 +1067,10 @@ Global {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Test|ARM.Build.0 = Test|ARM {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Test|ARM64.ActiveCfg = Test|ARM64 {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Test|ARM64.Build.0 = Test|ARM64 + {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Test|ARM64.Deploy.0 = Test|ARM64 + {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Test|CHPE.ActiveCfg = Test|CHPE + {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Test|CHPE.Build.0 = Test|CHPE + {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Test|CHPE.Deploy.0 = Test|CHPE {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Test|x64.ActiveCfg = Test|x64 {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Test|x64.Build.0 = Test|x64 {FFD0FA88-7A39-407E-A92D-D3A06273E1AC}.Test|x86.ActiveCfg = Test|Win32 @@ -786,6 +1079,10 @@ Global {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Debug|ARM.Build.0 = Debug|ARM {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Debug|ARM64.ActiveCfg = Debug|ARM64 {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Debug|ARM64.Build.0 = Debug|ARM64 + {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Debug|CHPE.ActiveCfg = Debug|CHPE + {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Debug|CHPE.Build.0 = Debug|CHPE + {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Debug|CHPE.Deploy.0 = Debug|CHPE {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Debug|x64.ActiveCfg = Debug|x64 {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Debug|x64.Build.0 = Debug|x64 {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Debug|x86.ActiveCfg = Debug|Win32 @@ -794,6 +1091,10 @@ Global {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Release|ARM.Build.0 = Release|ARM {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Release|ARM64.ActiveCfg = Release|ARM64 {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Release|ARM64.Build.0 = Release|ARM64 + {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Release|ARM64.Deploy.0 = Release|ARM64 + {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Release|CHPE.ActiveCfg = Release|CHPE + {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Release|CHPE.Build.0 = Release|CHPE + {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Release|CHPE.Deploy.0 = Release|CHPE {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Release|x64.ActiveCfg = Release|x64 {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Release|x64.Build.0 = Release|x64 {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Release|x86.ActiveCfg = Release|Win32 @@ -802,6 +1103,10 @@ Global {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Test|ARM.Build.0 = Test|ARM {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Test|ARM64.ActiveCfg = Test|ARM64 {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Test|ARM64.Build.0 = Test|ARM64 + {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Test|ARM64.Deploy.0 = Test|ARM64 + {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Test|CHPE.ActiveCfg = Test|CHPE + {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Test|CHPE.Build.0 = Test|CHPE + {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Test|CHPE.Deploy.0 = Test|CHPE {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Test|x64.ActiveCfg = Test|x64 {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Test|x64.Build.0 = Test|x64 {0DB5ECBC-9385-4A65-BE2C-4EF7C65CB719}.Test|x86.ActiveCfg = Test|Win32 @@ -810,6 +1115,10 @@ Global {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Debug|ARM.Build.0 = Debug|ARM {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Debug|ARM64.ActiveCfg = Debug|ARM64 {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Debug|ARM64.Build.0 = Debug|ARM64 + {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Debug|CHPE.ActiveCfg = Debug|CHPE + {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Debug|CHPE.Build.0 = Debug|CHPE + {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Debug|CHPE.Deploy.0 = Debug|CHPE {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Debug|x64.ActiveCfg = Debug|x64 {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Debug|x64.Build.0 = Debug|x64 {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Debug|x86.ActiveCfg = Debug|Win32 @@ -818,6 +1127,10 @@ Global {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Release|ARM.Build.0 = Release|ARM {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Release|ARM64.ActiveCfg = Release|ARM64 {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Release|ARM64.Build.0 = Release|ARM64 + {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Release|ARM64.Deploy.0 = Release|ARM64 + {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Release|CHPE.ActiveCfg = Release|CHPE + {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Release|CHPE.Build.0 = Release|CHPE + {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Release|CHPE.Deploy.0 = Release|CHPE {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Release|x64.ActiveCfg = Release|x64 {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Release|x64.Build.0 = Release|x64 {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Release|x86.ActiveCfg = Release|Win32 @@ -826,6 +1139,10 @@ Global {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Test|ARM.Build.0 = Test|ARM {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Test|ARM64.ActiveCfg = Test|ARM64 {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Test|ARM64.Build.0 = Test|ARM64 + {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Test|ARM64.Deploy.0 = Test|ARM64 + {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Test|CHPE.ActiveCfg = Test|CHPE + {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Test|CHPE.Build.0 = Test|CHPE + {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Test|CHPE.Deploy.0 = Test|CHPE {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Test|x64.ActiveCfg = Test|x64 {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Test|x64.Build.0 = Test|x64 {31024620-7B97-4EC7-96E8-E7B296A17DF4}.Test|x86.ActiveCfg = Test|Win32 @@ -834,6 +1151,10 @@ Global {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Debug|ARM.Build.0 = Debug|ARM {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Debug|ARM64.ActiveCfg = Debug|ARM64 {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Debug|ARM64.Build.0 = Debug|ARM64 + {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Debug|CHPE.ActiveCfg = Debug|CHPE + {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Debug|CHPE.Build.0 = Debug|CHPE + {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Debug|CHPE.Deploy.0 = Debug|CHPE {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Debug|x64.ActiveCfg = Debug|x64 {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Debug|x64.Build.0 = Debug|x64 {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Debug|x86.ActiveCfg = Debug|Win32 @@ -842,6 +1163,10 @@ Global {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Release|ARM.Build.0 = Release|ARM {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Release|ARM64.ActiveCfg = Release|ARM64 {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Release|ARM64.Build.0 = Release|ARM64 + {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Release|ARM64.Deploy.0 = Release|ARM64 + {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Release|CHPE.ActiveCfg = Release|CHPE + {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Release|CHPE.Build.0 = Release|CHPE + {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Release|CHPE.Deploy.0 = Release|CHPE {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Release|x64.ActiveCfg = Release|x64 {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Release|x64.Build.0 = Release|x64 {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Release|x86.ActiveCfg = Release|Win32 @@ -850,6 +1175,10 @@ Global {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Test|ARM.Build.0 = Test|ARM {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Test|ARM64.ActiveCfg = Test|ARM64 {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Test|ARM64.Build.0 = Test|ARM64 + {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Test|ARM64.Deploy.0 = Test|ARM64 + {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Test|CHPE.ActiveCfg = Test|CHPE + {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Test|CHPE.Build.0 = Test|CHPE + {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Test|CHPE.Deploy.0 = Test|CHPE {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Test|x64.ActiveCfg = Test|x64 {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Test|x64.Build.0 = Test|x64 {EDEB02E2-F389-4CBF-AE7D-3041A934F86B}.Test|x86.ActiveCfg = Test|Win32 @@ -858,6 +1187,10 @@ Global {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Debug|ARM.Build.0 = Debug|ARM {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Debug|ARM64.ActiveCfg = Debug|ARM64 {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Debug|ARM64.Build.0 = Debug|ARM64 + {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Debug|CHPE.ActiveCfg = Debug|CHPE + {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Debug|CHPE.Build.0 = Debug|CHPE + {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Debug|CHPE.Deploy.0 = Debug|CHPE {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Debug|x64.ActiveCfg = Debug|x64 {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Debug|x64.Build.0 = Debug|x64 {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Debug|x86.ActiveCfg = Debug|Win32 @@ -866,6 +1199,10 @@ Global {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Release|ARM.Build.0 = Release|ARM {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Release|ARM64.ActiveCfg = Release|ARM64 {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Release|ARM64.Build.0 = Release|ARM64 + {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Release|ARM64.Deploy.0 = Release|ARM64 + {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Release|CHPE.ActiveCfg = Release|CHPE + {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Release|CHPE.Build.0 = Release|CHPE + {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Release|CHPE.Deploy.0 = Release|CHPE {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Release|x64.ActiveCfg = Release|x64 {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Release|x64.Build.0 = Release|x64 {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Release|x86.ActiveCfg = Release|Win32 @@ -874,34 +1211,68 @@ Global {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Test|ARM.Build.0 = Test|ARM {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Test|ARM64.ActiveCfg = Test|ARM64 {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Test|ARM64.Build.0 = Test|ARM64 + {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Test|ARM64.Deploy.0 = Test|ARM64 + {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Test|CHPE.ActiveCfg = Test|CHPE + {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Test|CHPE.Build.0 = Test|CHPE + {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Test|CHPE.Deploy.0 = Test|CHPE {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Test|x64.ActiveCfg = Test|x64 {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Test|x64.Build.0 = Test|x64 {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Test|x86.ActiveCfg = Test|Win32 {2F6A1847-BFAF-4B8A-9463-AC39FB46B96A}.Test|x86.Build.0 = Test|Win32 {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Debug|ARM.ActiveCfg = Debug|Win32 {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Debug|ARM64.Build.0 = Debug|ARM64 + {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Debug|CHPE.ActiveCfg = Debug|CHPE + {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Debug|CHPE.Build.0 = Debug|CHPE + {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Debug|CHPE.Deploy.0 = Debug|CHPE {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Debug|x64.ActiveCfg = Debug|x64 {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Debug|x86.ActiveCfg = Debug|Win32 {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Release|ARM.ActiveCfg = Release|Win32 {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Release|ARM64.ActiveCfg = Release|ARM64 + {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Release|ARM64.Build.0 = Release|ARM64 + {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Release|ARM64.Deploy.0 = Release|ARM64 + {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Release|CHPE.ActiveCfg = Release|CHPE + {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Release|CHPE.Build.0 = Release|CHPE + {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Release|CHPE.Deploy.0 = Release|CHPE {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Release|x64.ActiveCfg = Release|x64 {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Release|x86.ActiveCfg = Release|Win32 {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Test|ARM.ActiveCfg = Release|x64 {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Test|ARM64.ActiveCfg = Test|ARM64 + {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Test|ARM64.Build.0 = Test|ARM64 + {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Test|ARM64.Deploy.0 = Test|ARM64 + {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Test|CHPE.ActiveCfg = Test|CHPE + {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Test|CHPE.Build.0 = Test|CHPE + {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Test|CHPE.Deploy.0 = Test|CHPE {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Test|x64.ActiveCfg = Release|x64 {02D4FD92-AD34-40CA-85DF-4D6C7E3A1F22}.Test|x86.ActiveCfg = Release|Win32 {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Debug|ARM.ActiveCfg = Debug|ARM {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Debug|ARM64.Build.0 = Debug|ARM64 + {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Debug|CHPE.ActiveCfg = Debug|CHPE + {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Debug|CHPE.Build.0 = Debug|CHPE + {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Debug|CHPE.Deploy.0 = Debug|CHPE {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Debug|x64.ActiveCfg = Debug|x64 {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Debug|x64.Build.0 = Debug|x64 {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Debug|x86.ActiveCfg = Debug|Win32 {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Debug|x86.Build.0 = Debug|Win32 {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Release|ARM.ActiveCfg = Release|ARM {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Release|ARM64.ActiveCfg = Release|ARM64 + {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Release|ARM64.Build.0 = Release|ARM64 + {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Release|ARM64.Deploy.0 = Release|ARM64 + {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Release|CHPE.ActiveCfg = Release|CHPE + {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Release|CHPE.Build.0 = Release|CHPE + {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Release|CHPE.Deploy.0 = Release|CHPE {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Release|x64.ActiveCfg = Release|x64 {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Release|x86.ActiveCfg = Release|Win32 {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Test|ARM.ActiveCfg = Test|ARM {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Test|ARM64.ActiveCfg = Test|ARM64 + {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Test|ARM64.Build.0 = Test|ARM64 + {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Test|ARM64.Deploy.0 = Test|ARM64 + {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Test|CHPE.ActiveCfg = Test|CHPE + {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Test|CHPE.Build.0 = Test|CHPE + {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Test|CHPE.Deploy.0 = Test|CHPE {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Test|x64.ActiveCfg = Test|x64 {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Test|x64.Build.0 = Test|x64 {F48B3491-81DF-4F49-B35F-3308CBE6A379}.Test|x86.ActiveCfg = Test|Win32 @@ -910,6 +1281,10 @@ Global {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Debug|ARM.Build.0 = Debug|ARM {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Debug|ARM64.ActiveCfg = Debug|ARM64 {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Debug|ARM64.Build.0 = Debug|ARM64 + {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Debug|CHPE.ActiveCfg = Debug|CHPE + {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Debug|CHPE.Build.0 = Debug|CHPE + {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Debug|CHPE.Deploy.0 = Debug|CHPE {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Debug|x64.ActiveCfg = Debug|x64 {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Debug|x64.Build.0 = Debug|x64 {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Debug|x86.ActiveCfg = Debug|Win32 @@ -918,6 +1293,10 @@ Global {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Release|ARM.Build.0 = Release|ARM {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Release|ARM64.ActiveCfg = Release|ARM64 {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Release|ARM64.Build.0 = Release|ARM64 + {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Release|ARM64.Deploy.0 = Release|ARM64 + {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Release|CHPE.ActiveCfg = Release|CHPE + {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Release|CHPE.Build.0 = Release|CHPE + {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Release|CHPE.Deploy.0 = Release|CHPE {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Release|x64.ActiveCfg = Release|x64 {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Release|x64.Build.0 = Release|x64 {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Release|x86.ActiveCfg = Release|Win32 @@ -926,6 +1305,10 @@ Global {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Test|ARM.Build.0 = Test|ARM {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Test|ARM64.ActiveCfg = Test|ARM64 {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Test|ARM64.Build.0 = Test|ARM64 + {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Test|ARM64.Deploy.0 = Test|ARM64 + {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Test|CHPE.ActiveCfg = Test|CHPE + {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Test|CHPE.Build.0 = Test|CHPE + {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Test|CHPE.Deploy.0 = Test|CHPE {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Test|x64.ActiveCfg = Test|x64 {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Test|x64.Build.0 = Test|x64 {EE2A3111-4D85-427C-B0AB-E6B0EA7FFB44}.Test|x86.ActiveCfg = Test|Win32 @@ -934,6 +1317,10 @@ Global {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Debug|ARM.Build.0 = Debug|ARM {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Debug|ARM64.ActiveCfg = Debug|ARM64 {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Debug|ARM64.Build.0 = Debug|ARM64 + {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Debug|CHPE.ActiveCfg = Debug|CHPE + {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Debug|CHPE.Build.0 = Debug|CHPE + {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Debug|CHPE.Deploy.0 = Debug|CHPE {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Debug|x64.ActiveCfg = Debug|x64 {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Debug|x64.Build.0 = Debug|x64 {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Debug|x86.ActiveCfg = Debug|Win32 @@ -942,6 +1329,10 @@ Global {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Release|ARM.Build.0 = Release|ARM {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Release|ARM64.ActiveCfg = Release|ARM64 {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Release|ARM64.Build.0 = Release|ARM64 + {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Release|ARM64.Deploy.0 = Release|ARM64 + {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Release|CHPE.ActiveCfg = Release|CHPE + {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Release|CHPE.Build.0 = Release|CHPE + {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Release|CHPE.Deploy.0 = Release|CHPE {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Release|x64.ActiveCfg = Release|x64 {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Release|x64.Build.0 = Release|x64 {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Release|x86.ActiveCfg = Release|Win32 @@ -950,6 +1341,10 @@ Global {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Test|ARM.Build.0 = Test|ARM {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Test|ARM64.ActiveCfg = Test|ARM64 {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Test|ARM64.Build.0 = Test|ARM64 + {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Test|ARM64.Deploy.0 = Test|ARM64 + {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Test|CHPE.ActiveCfg = Test|CHPE + {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Test|CHPE.Build.0 = Test|CHPE + {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Test|CHPE.Deploy.0 = Test|CHPE {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Test|x64.ActiveCfg = Test|x64 {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Test|x64.Build.0 = Test|x64 {347824B1-7100-4EE6-8A6B-4FF64E66B0C0}.Test|x86.ActiveCfg = Test|Win32 @@ -958,6 +1353,10 @@ Global {0494C753-5BB9-45AA-874E-E61B9922E88F}.Debug|ARM.Build.0 = Debug|ARM {0494C753-5BB9-45AA-874E-E61B9922E88F}.Debug|ARM64.ActiveCfg = Debug|ARM64 {0494C753-5BB9-45AA-874E-E61B9922E88F}.Debug|ARM64.Build.0 = Debug|ARM64 + {0494C753-5BB9-45AA-874E-E61B9922E88F}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {0494C753-5BB9-45AA-874E-E61B9922E88F}.Debug|CHPE.ActiveCfg = Debug|CHPE + {0494C753-5BB9-45AA-874E-E61B9922E88F}.Debug|CHPE.Build.0 = Debug|CHPE + {0494C753-5BB9-45AA-874E-E61B9922E88F}.Debug|CHPE.Deploy.0 = Debug|CHPE {0494C753-5BB9-45AA-874E-E61B9922E88F}.Debug|x64.ActiveCfg = Debug|x64 {0494C753-5BB9-45AA-874E-E61B9922E88F}.Debug|x64.Build.0 = Debug|x64 {0494C753-5BB9-45AA-874E-E61B9922E88F}.Debug|x86.ActiveCfg = Debug|Win32 @@ -966,6 +1365,10 @@ Global {0494C753-5BB9-45AA-874E-E61B9922E88F}.Release|ARM.Build.0 = Release|ARM {0494C753-5BB9-45AA-874E-E61B9922E88F}.Release|ARM64.ActiveCfg = Release|ARM64 {0494C753-5BB9-45AA-874E-E61B9922E88F}.Release|ARM64.Build.0 = Release|ARM64 + {0494C753-5BB9-45AA-874E-E61B9922E88F}.Release|ARM64.Deploy.0 = Release|ARM64 + {0494C753-5BB9-45AA-874E-E61B9922E88F}.Release|CHPE.ActiveCfg = Release|CHPE + {0494C753-5BB9-45AA-874E-E61B9922E88F}.Release|CHPE.Build.0 = Release|CHPE + {0494C753-5BB9-45AA-874E-E61B9922E88F}.Release|CHPE.Deploy.0 = Release|CHPE {0494C753-5BB9-45AA-874E-E61B9922E88F}.Release|x64.ActiveCfg = Release|x64 {0494C753-5BB9-45AA-874E-E61B9922E88F}.Release|x64.Build.0 = Release|x64 {0494C753-5BB9-45AA-874E-E61B9922E88F}.Release|x86.ActiveCfg = Release|Win32 @@ -974,6 +1377,10 @@ Global {0494C753-5BB9-45AA-874E-E61B9922E88F}.Test|ARM.Build.0 = Test|ARM {0494C753-5BB9-45AA-874E-E61B9922E88F}.Test|ARM64.ActiveCfg = Test|ARM64 {0494C753-5BB9-45AA-874E-E61B9922E88F}.Test|ARM64.Build.0 = Test|ARM64 + {0494C753-5BB9-45AA-874E-E61B9922E88F}.Test|ARM64.Deploy.0 = Test|ARM64 + {0494C753-5BB9-45AA-874E-E61B9922E88F}.Test|CHPE.ActiveCfg = Test|CHPE + {0494C753-5BB9-45AA-874E-E61B9922E88F}.Test|CHPE.Build.0 = Test|CHPE + {0494C753-5BB9-45AA-874E-E61B9922E88F}.Test|CHPE.Deploy.0 = Test|CHPE {0494C753-5BB9-45AA-874E-E61B9922E88F}.Test|x64.ActiveCfg = Test|x64 {0494C753-5BB9-45AA-874E-E61B9922E88F}.Test|x64.Build.0 = Test|x64 {0494C753-5BB9-45AA-874E-E61B9922E88F}.Test|x86.ActiveCfg = Test|Win32 @@ -982,6 +1389,10 @@ Global {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Debug|ARM.Build.0 = Debug|ARM {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Debug|ARM64.ActiveCfg = Debug|ARM64 {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Debug|ARM64.Build.0 = Debug|ARM64 + {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Debug|CHPE.ActiveCfg = Debug|CHPE + {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Debug|CHPE.Build.0 = Debug|CHPE + {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Debug|CHPE.Deploy.0 = Debug|CHPE {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Debug|x64.ActiveCfg = Debug|x64 {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Debug|x64.Build.0 = Debug|x64 {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Debug|x86.ActiveCfg = Debug|Win32 @@ -990,6 +1401,10 @@ Global {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Release|ARM.Build.0 = Release|ARM {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Release|ARM64.ActiveCfg = Release|ARM64 {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Release|ARM64.Build.0 = Release|ARM64 + {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Release|ARM64.Deploy.0 = Release|ARM64 + {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Release|CHPE.ActiveCfg = Release|CHPE + {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Release|CHPE.Build.0 = Release|CHPE + {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Release|CHPE.Deploy.0 = Release|CHPE {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Release|x64.ActiveCfg = Release|x64 {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Release|x64.Build.0 = Release|x64 {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Release|x86.ActiveCfg = Release|Win32 @@ -998,10 +1413,44 @@ Global {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Test|ARM.Build.0 = Test|ARM {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Test|ARM64.ActiveCfg = Test|ARM64 {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Test|ARM64.Build.0 = Test|ARM64 + {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Test|ARM64.Deploy.0 = Test|ARM64 + {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Test|CHPE.ActiveCfg = Test|CHPE + {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Test|CHPE.Build.0 = Test|CHPE + {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Test|CHPE.Deploy.0 = Test|CHPE {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Test|x64.ActiveCfg = Test|x64 {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Test|x64.Build.0 = Test|x64 {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Test|x86.ActiveCfg = Test|Win32 {E14F373D-05A0-4259-A5E9-AFE8405FB847}.Test|x86.Build.0 = Test|Win32 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Debug|ARM.ActiveCfg = Debug|ARM + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Debug|ARM.Build.0 = Debug|ARM + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Debug|ARM64.Build.0 = Debug|ARM64 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Debug|CHPE.ActiveCfg = Debug|CHPE + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Debug|CHPE.Build.0 = Debug|CHPE + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Debug|x64.ActiveCfg = Debug|x64 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Debug|x64.Build.0 = Debug|x64 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Debug|x86.ActiveCfg = Debug|Win32 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Debug|x86.Build.0 = Debug|Win32 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Release|ARM.ActiveCfg = Release|ARM + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Release|ARM.Build.0 = Release|ARM + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Release|ARM64.ActiveCfg = Release|ARM64 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Release|ARM64.Build.0 = Release|ARM64 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Release|CHPE.ActiveCfg = Release|CHPE + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Release|CHPE.Build.0 = Release|CHPE + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Release|x64.ActiveCfg = Release|x64 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Release|x64.Build.0 = Release|x64 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Release|x86.ActiveCfg = Release|Win32 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Release|x86.Build.0 = Release|Win32 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Test|ARM.ActiveCfg = Test|ARM + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Test|ARM.Build.0 = Test|ARM + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Test|ARM64.ActiveCfg = Test|ARM64 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Test|ARM64.Build.0 = Test|ARM64 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Test|CHPE.ActiveCfg = Test|CHPE + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Test|CHPE.Build.0 = Test|CHPE + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Test|x64.ActiveCfg = Test|x64 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Test|x64.Build.0 = Test|x64 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Test|x86.ActiveCfg = Test|Win32 + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5}.Test|x86.Build.0 = Test|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1049,6 +1498,7 @@ Global {347824B1-7100-4EE6-8A6B-4FF64E66B0C0} = {6C6BC844-3D86-42B4-B3C4-7478487D2C38} {0494C753-5BB9-45AA-874E-E61B9922E88F} = {6C6BC844-3D86-42B4-B3C4-7478487D2C38} {E14F373D-05A0-4259-A5E9-AFE8405FB847} = {6C6BC844-3D86-42B4-B3C4-7478487D2C38} + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5} = {D8216B93-BD6E-4293-8D98-79CEF7CF66BC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {1F6CA1BC-6C01-4C82-8505-6A7690EBD556} diff --git a/bin/ChakraCore/ChakraCore.vcxproj b/bin/ChakraCore/ChakraCore.vcxproj index 5aef42ee598..240f60137a9 100644 --- a/bin/ChakraCore/ChakraCore.vcxproj +++ b/bin/ChakraCore/ChakraCore.vcxproj @@ -164,6 +164,9 @@ {abc904ad-9415-46f8-aa23-e33193f81f7c} + + {4da3a367-6ed2-4ee8-9698-5bcd0b8af7f5} + {53D52B0B-86D9-4D31-AD09-0D6B3C063ADD} @@ -194,4 +197,4 @@ - + \ No newline at end of file diff --git a/bin/ChakraCore/TestHooks.h b/bin/ChakraCore/TestHooks.h index 159d4cc4ae0..1b593c887d9 100644 --- a/bin/ChakraCore/TestHooks.h +++ b/bin/ChakraCore/TestHooks.h @@ -5,7 +5,7 @@ #pragma once #ifdef ENABLE_TEST_HOOKS - +#include interface ICustomConfigFlags; #if defined(_WIN32) || defined(_MSC_VER) diff --git a/bin/NativeTests/JsRTApiTest.cpp b/bin/NativeTests/JsRTApiTest.cpp index 8274a98f616..f7a3b1eb348 100644 --- a/bin/NativeTests/JsRTApiTest.cpp +++ b/bin/NativeTests/JsRTApiTest.cpp @@ -257,6 +257,11 @@ namespace JsRTApiTest CHECK(data == (void *)0xdeadbeef); } + void CALLBACK ExternalObjectTraceCallback(void *data) + { + CHECK(data == (void *)0xdeadbeef); + } + void CrossContextSetPropertyTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime) { bool hasExternalData; @@ -292,6 +297,11 @@ namespace JsRTApiTest REQUIRE(JsSetPrototype(jsrtExternalObjectRef, mainObjectRef) == JsNoError); REQUIRE(JsHasExternalData(jsrtExternalObjectRef, &hasExternalData) == JsNoError); REQUIRE(hasExternalData); + + JsValueRef object3 = JS_INVALID_REFERENCE; + JsGetterSetterInterceptor * interceptor3 = nullptr; + JsValueRef prototype2 = JS_INVALID_REFERENCE; + REQUIRE(JsCreateCustomExternalObject((void *)0xdeadbeef, 0, ExternalObjectTraceCallback, ExternalObjectFinalizeCallback, &interceptor3, prototype2, &object3) == JsNoError); } TEST_CASE("ApiTest_CrossContextSetPropertyTest", "[ApiTest]") diff --git a/bin/ch/ChakraRtInterface.cpp b/bin/ch/ChakraRtInterface.cpp index 16c46ff02d2..5062066195a 100644 --- a/bin/ch/ChakraRtInterface.cpp +++ b/bin/ch/ChakraRtInterface.cpp @@ -78,12 +78,20 @@ bool ChakraRTInterface::LoadChakraDll(ArgInfo* argInfo, HINSTANCE *outLibrary) m_jsApiHooks.pfJsrtCreateRuntime = (JsAPIHooks::JsrtCreateRuntimePtr)GetChakraCoreSymbol(library, "JsCreateRuntime"); m_jsApiHooks.pfJsrtCreateContext = (JsAPIHooks::JsrtCreateContextPtr)GetChakraCoreSymbol(library, "JsCreateContext"); m_jsApiHooks.pfJsrtSetObjectBeforeCollectCallback = (JsAPIHooks::JsrtSetObjectBeforeCollectCallbackPtr)GetChakraCoreSymbol(library, "JsSetObjectBeforeCollectCallback"); + m_jsApiHooks.pfJsrtSetRuntimeDomWrapperTracingCallbacks = (JsAPIHooks::JsrtSetRuntimeDomWrapperTracingCallbacksPtr)GetChakraCoreSymbol(library, "JsSetRuntimeDomWrapperTracingCallbacks"); m_jsApiHooks.pfJsrtSetRuntimeMemoryLimit = (JsAPIHooks::JsrtSetRuntimeMemoryLimitPtr)GetChakraCoreSymbol(library, "JsSetRuntimeMemoryLimit"); m_jsApiHooks.pfJsrtSetCurrentContext = (JsAPIHooks::JsrtSetCurrentContextPtr)GetChakraCoreSymbol(library, "JsSetCurrentContext"); m_jsApiHooks.pfJsrtGetCurrentContext = (JsAPIHooks::JsrtGetCurrentContextPtr)GetChakraCoreSymbol(library, "JsGetCurrentContext"); m_jsApiHooks.pfJsrtDisposeRuntime = (JsAPIHooks::JsrtDisposeRuntimePtr)GetChakraCoreSymbol(library, "JsDisposeRuntime"); m_jsApiHooks.pfJsrtCreateObject = (JsAPIHooks::JsrtCreateObjectPtr)GetChakraCoreSymbol(library, "JsCreateObject"); m_jsApiHooks.pfJsrtCreateExternalObject = (JsAPIHooks::JsrtCreateExternalObjectPtr)GetChakraCoreSymbol(library, "JsCreateExternalObject"); + m_jsApiHooks.pfJsrtGetArrayForEachFunction = (JsAPIHooks::JsrtGetArrayForEachFunctionPtr)GetChakraCoreSymbol(library, "JsGetArrayForEachFunction");; + m_jsApiHooks.pfJsrtGetArrayKeysFunction = (JsAPIHooks::JsrtGetArrayKeysFunctionPtr)GetChakraCoreSymbol(library, "JsGetArrayKeysFunction");; + m_jsApiHooks.pfJsrtGetArrayValuesFunction = (JsAPIHooks::JsrtGetArrayValuesFunctionPtr)GetChakraCoreSymbol(library, "JsGetArrayValuesFunction");; + m_jsApiHooks.pfJsrtGetArrayEntriesFunction = (JsAPIHooks::JsrtGetArrayEntriesFunctionPtr)GetChakraCoreSymbol(library, "JsGetArrayEntriesFunction");; + m_jsApiHooks.pfJsrtGetPropertyIdSymbolIterator = (JsAPIHooks::JsrtGetPropertyIdSymbolIteratorPtr)GetChakraCoreSymbol(library, "JsGetPropertyIdSymbolIterator");; + m_jsApiHooks.pfJsrtGetErrorPrototype = (JsAPIHooks::JsrtGetErrorPrototypePtr)GetChakraCoreSymbol(library, "JsGetErrorPrototype");; + m_jsApiHooks.pfJsrtGetIteratorPrototype = (JsAPIHooks::JsrtGetIteratorPrototypePtr)GetChakraCoreSymbol(library, "JsGetIteratorPrototype");; m_jsApiHooks.pfJsrtCreateFunction = (JsAPIHooks::JsrtCreateFunctionPtr)GetChakraCoreSymbol(library, "JsCreateFunction"); m_jsApiHooks.pfJsrtCreateNamedFunction = (JsAPIHooks::JsCreateNamedFunctionPtr)GetChakraCoreSymbol(library, "JsCreateNamedFunction"); m_jsApiHooks.pfJsrtSetProperty = (JsAPIHooks::JsrtSetPropertyPtr)GetChakraCoreSymbol(library, "JsSetProperty"); @@ -105,6 +113,7 @@ bool ChakraRTInterface::LoadChakraDll(ArgInfo* argInfo, HINSTANCE *outLibrary) m_jsApiHooks.pfJsrtDoubleToNumber = (JsAPIHooks::JsrtDoubleToNumberPtr)GetChakraCoreSymbol(library, "JsDoubleToNumber"); m_jsApiHooks.pfJsrtGetExternalData = (JsAPIHooks::JsrtGetExternalDataPtr)GetChakraCoreSymbol(library, "JsGetExternalData"); m_jsApiHooks.pfJsrtSetExternalData = (JsAPIHooks::JsrtSetExternalDataPtr)GetChakraCoreSymbol(library, "JsSetExternalData"); + m_jsApiHooks.pfJsrtCloneObject = (JsAPIHooks::JsrtCloneObjectPtr)GetChakraCoreSymbol(library, "JsCloneObject"); m_jsApiHooks.pfJsrtCreateArray = (JsAPIHooks::JsrtCreateArrayPtr)GetChakraCoreSymbol(library, "JsCreateArray"); m_jsApiHooks.pfJsrtCreateArrayBuffer = (JsAPIHooks::JsrtCreateArrayBufferPtr)GetChakraCoreSymbol(library, "JsCreateArrayBuffer"); m_jsApiHooks.pfJsrtCreateSharedArrayBufferWithSharedContent = (JsAPIHooks::JsrtCreateSharedArrayBufferWithSharedContentPtr)GetChakraCoreSymbol(library, "JsCreateSharedArrayBufferWithSharedContent"); @@ -119,6 +128,7 @@ bool ChakraRTInterface::LoadChakraDll(ArgInfo* argInfo, HINSTANCE *outLibrary) m_jsApiHooks.pfJsrtRelease = (JsAPIHooks::JsrtReleasePtr)GetChakraCoreSymbol(library, "JsRelease"); m_jsApiHooks.pfJsrtAddRef = (JsAPIHooks::JsrtAddRefPtr)GetChakraCoreSymbol(library, "JsAddRef"); m_jsApiHooks.pfJsrtGetValueType = (JsAPIHooks::JsrtGetValueType)GetChakraCoreSymbol(library, "JsGetValueType"); + m_jsApiHooks.pfJsrtGetIndexedProperty = (JsAPIHooks::JsrtGetIndexedPropertyPtr)GetChakraCoreSymbol(library, "JsGetIndexedProperty"); m_jsApiHooks.pfJsrtSetIndexedProperty = (JsAPIHooks::JsrtSetIndexedPropertyPtr)GetChakraCoreSymbol(library, "JsSetIndexedProperty"); m_jsApiHooks.pfJsrtSetPromiseContinuationCallback = (JsAPIHooks::JsrtSetPromiseContinuationCallbackPtr)GetChakraCoreSymbol(library, "JsSetPromiseContinuationCallback"); m_jsApiHooks.pfJsrtSetHostPromiseRejectionTracker = (JsAPIHooks::JsrtSetHostPromiseRejectionTrackerPtr)GetChakraCoreSymbol(library, "JsSetHostPromiseRejectionTracker"); @@ -178,6 +188,18 @@ bool ChakraRTInterface::LoadChakraDll(ArgInfo* argInfo, HINSTANCE *outLibrary) m_jsApiHooks.pfJsrtTTDGetSnapTimeTopLevelEventMove = (JsAPIHooks::JsrtTTDGetSnapTimeTopLevelEventMovePtr)GetChakraCoreSymbol(library, "JsTTDGetSnapTimeTopLevelEventMove"); m_jsApiHooks.pfJsrtTTDMoveToTopLevelEvent = (JsAPIHooks::JsrtTTDMoveToTopLevelEventPtr)GetChakraCoreSymbol(library, "JsTTDMoveToTopLevelEvent"); m_jsApiHooks.pfJsrtTTDReplayExecution = (JsAPIHooks::JsrtTTDReplayExecutionPtr)GetChakraCoreSymbol(library, "JsTTDReplayExecution"); + m_jsApiHooks.pfJsrtVarSerializer = (JsAPIHooks::JsrtVarSerializerPtr)GetChakraCoreSymbol(library, "JsVarSerializer"); + m_jsApiHooks.pfJsrtVarSerializerSetTransferableVars = (JsAPIHooks::JsrtVarSerializerSetTransferableVarsPtr)GetChakraCoreSymbol(library, "JsVarSerializerSetTransferableVars"); + m_jsApiHooks.pfJsrtVarSerializerWriteValue = (JsAPIHooks::JsrtVarSerializerWriteValuePtr)GetChakraCoreSymbol(library, "JsVarSerializerWriteValue"); + m_jsApiHooks.pfJsrtVarSerializerReleaseData = (JsAPIHooks::JsrtVarSerializerReleaseDataPtr)GetChakraCoreSymbol(library, "JsVarSerializerReleaseData"); + m_jsApiHooks.pfJsrtVarSerializerFree = (JsAPIHooks::JsrtVarSerializerFreePtr)GetChakraCoreSymbol(library, "JsVarSerializerFree"); + m_jsApiHooks.pfJsrtVarDeserializer = (JsAPIHooks::JsrtVarDeserializerPtr)GetChakraCoreSymbol(library, "JsVarDeserializer"); + m_jsApiHooks.pfJsrtVarDeserializerSetTransferableVars = (JsAPIHooks::JsrtVarDeserializerSetTransferableVarsPtr)GetChakraCoreSymbol(library, "JsVarDeserializerSetTransferableVars"); + m_jsApiHooks.pfJsrtVarDeserializerReadValue = (JsAPIHooks::JsrtVarDeserializerReadValuePtr)GetChakraCoreSymbol(library, "JsVarDeserializerReadValue"); + m_jsApiHooks.pfJsrtVarDeserializerFree = (JsAPIHooks::JsrtVarDeserializerFreePtr)GetChakraCoreSymbol(library, "JsVarDeserializerFree"); + + m_jsApiHooks.pfJsrtDetachArrayBuffer = (JsAPIHooks::JsrtDetachArrayBufferPtr)GetChakraCoreSymbol(library, "JsDetachArrayBuffer"); + #ifdef _WIN32 m_jsApiHooks.pfJsrtConnectJITProcess = (JsAPIHooks::JsrtConnectJITProcess)GetChakraCoreSymbol(library, "JsConnectJITProcess"); #endif diff --git a/bin/ch/ChakraRtInterface.h b/bin/ch/ChakraRtInterface.h index cb091bcfa22..2b80b490d61 100644 --- a/bin/ch/ChakraRtInterface.h +++ b/bin/ch/ChakraRtInterface.h @@ -9,12 +9,20 @@ struct JsAPIHooks typedef JsErrorCode (WINAPI *JsrtCreateRuntimePtr)(JsRuntimeAttributes attributes, JsThreadServiceCallback threadService, JsRuntimeHandle *runtime); typedef JsErrorCode (WINAPI *JsrtCreateContextPtr)(JsRuntimeHandle runtime, JsContextRef *newContext); typedef JsErrorCode (WINAPI *JsrtSetObjectBeforeCollectCallbackPtr)(JsRef ref, void* callbackState, JsObjectBeforeCollectCallback objectBeforeCollectCallback); + typedef JsErrorCode(WINAPI *JsrtSetRuntimeDomWrapperTracingCallbacksPtr)(JsRuntimeHandle runtime, JsRef wrapperTracingState, JsDOMWrapperTracingCallback wrapperTracingCallback, JsDOMWrapperTracingDoneCallback wrapperTracingDoneCallback, JsDOMWrapperTracingEnterFinalPauseCallback enterFinalPauseCallback); typedef JsErrorCode (WINAPI *JsrtSetRuntimeMemoryLimitPtr)(JsRuntimeHandle runtime, size_t memoryLimit); typedef JsErrorCode (WINAPI *JsrtSetCurrentContextPtr)(JsContextRef context); typedef JsErrorCode (WINAPI *JsrtGetCurrentContextPtr)(JsContextRef* context); typedef JsErrorCode (WINAPI *JsrtDisposeRuntimePtr)(JsRuntimeHandle runtime); typedef JsErrorCode (WINAPI *JsrtCreateObjectPtr)(JsValueRef *object); typedef JsErrorCode (WINAPI *JsrtCreateExternalObjectPtr)(void* data, JsFinalizeCallback callback, JsValueRef *object); + typedef JsErrorCode (WINAPI *JsrtGetArrayForEachFunctionPtr)(JsValueRef *result); + typedef JsErrorCode (WINAPI *JsrtGetArrayKeysFunctionPtr)(JsValueRef *result); + typedef JsErrorCode (WINAPI *JsrtGetArrayValuesFunctionPtr)(JsValueRef *result); + typedef JsErrorCode (WINAPI *JsrtGetArrayEntriesFunctionPtr)(JsValueRef *result); + typedef JsErrorCode (WINAPI *JsrtGetPropertyIdSymbolIteratorPtr)(JsPropertyIdRef *propertyId); + typedef JsErrorCode (WINAPI *JsrtGetErrorPrototypePtr)(JsValueRef *result); + typedef JsErrorCode (WINAPI *JsrtGetIteratorPrototypePtr)(JsValueRef *result); typedef JsErrorCode (WINAPI *JsrtCreateFunctionPtr)(JsNativeFunction nativeFunction, void *callbackState, JsValueRef *function); typedef JsErrorCode (WINAPI *JsrtCreateEnhancedFunctionPtr)(JsEnhancedNativeFunction nativeFunction, JsValueRef metadata, void *callbackState, JsValueRef *function); typedef JsErrorCode (WINAPI *JsCreateNamedFunctionPtr)(JsValueRef name, JsNativeFunction nativeFunction, void *callbackState, JsValueRef *function); @@ -40,6 +48,7 @@ struct JsAPIHooks typedef JsErrorCode (WINAPI *JsrtDoubleToNumberPtr)(double doubleValue, JsValueRef* value); typedef JsErrorCode (WINAPI *JsrtGetExternalDataPtr)(JsValueRef object, void **data); typedef JsErrorCode (WINAPI *JsrtSetExternalDataPtr)(JsValueRef object, void *data); + typedef JsErrorCode(WINAPI *JsrtCloneObjectPtr)(JsValueRef object, JsValueRef *newObject); typedef JsErrorCode (WINAPI *JsrtCreateArrayPtr)(unsigned int length, JsValueRef *result); typedef JsErrorCode (WINAPI *JsrtCreateArrayBufferPtr)(unsigned int byteLength, JsValueRef *result); typedef JsErrorCode (WINAPI *JsrtCreateSharedArrayBufferWithSharedContentPtr)(JsSharedArrayBufferContentHandle sharedContent, JsValueRef *result); @@ -54,6 +63,7 @@ struct JsAPIHooks typedef JsErrorCode (WINAPI *JsrtReleasePtr)(JsRef ref, unsigned int* count); typedef JsErrorCode (WINAPI *JsrtAddRefPtr)(JsRef ref, unsigned int* count); typedef JsErrorCode (WINAPI *JsrtGetValueType)(JsValueRef value, JsValueType *type); + typedef JsErrorCode(WINAPI *JsrtGetIndexedPropertyPtr)(JsValueRef object, JsValueRef index, JsValueRef *value); typedef JsErrorCode (WINAPI *JsrtSetIndexedPropertyPtr)(JsValueRef object, JsValueRef index, JsValueRef value); typedef JsErrorCode (WINAPI *JsrtSetPromiseContinuationCallbackPtr)(JsPromiseContinuationCallback callback, void *callbackState); typedef JsErrorCode (WINAPI *JsrtSetHostPromiseRejectionTrackerPtr)(JsHostPromiseRejectionTrackerCallback callback, void *callbackState); @@ -116,15 +126,37 @@ struct JsAPIHooks typedef JsErrorCode(WINAPI *JsrtConnectJITProcess)(HANDLE processHandle, void* serverSecurityDescriptor, UUID connectionId); #endif + typedef JsErrorCode(WINAPI *JsrtVarSerializerPtr)(ReallocateBufferMemoryFunc reallocateBufferMemory, WriteHostObjectFunc writeHostObject, void * callbackState, JsVarSerializerHandle *serializerHandle); + typedef JsErrorCode(WINAPI *JsrtVarSerializerSetTransferableVarsPtr)(JsVarSerializerHandle serializerHandle, JsValueRef *transferableVars, size_t transferableVarsCount); + typedef JsErrorCode(WINAPI *JsrtVarSerializerWriteValuePtr)(JsVarSerializerHandle serializerHandle, JsValueRef rootObject); + typedef JsErrorCode(WINAPI *JsrtVarSerializerReleaseDataPtr)(JsVarSerializerHandle serializerHandle, byte** data, size_t *dataLength); + typedef JsErrorCode(WINAPI *JsrtVarSerializerFreePtr)(JsVarSerializerHandle serializerHandle); + + typedef JsErrorCode(WINAPI *JsrtVarDeserializerPtr)(void *data, size_t dataLength, ReadHostObjectFunc readHostObject, GetSharedArrayBufferFromIdFunc getSharedArrayBufferFromId, void* callbackState, JsVarDeserializerHandle *deserializerHandle); + typedef JsErrorCode(WINAPI *JsrtVarDeserializerSetTransferableVarsPtr)(JsVarDeserializerHandle deserializerHandle, JsValueRef *transferableVars, size_t transferableVarsCount); + typedef JsErrorCode(WINAPI *JsrtVarDeserializerReadValuePtr)(JsVarDeserializerHandle deserializerHandle, JsValueRef* value); + typedef JsErrorCode(WINAPI *JsrtVarDeserializerFreePtr)(JsVarDeserializerHandle deserializerHandle); + + typedef JsErrorCode(WINAPI *JsrtDetachArrayBufferPtr)(JsValueRef buffer); + JsrtCreateRuntimePtr pfJsrtCreateRuntime; JsrtCreateContextPtr pfJsrtCreateContext; JsrtSetObjectBeforeCollectCallbackPtr pfJsrtSetObjectBeforeCollectCallback; + JsrtSetRuntimeDomWrapperTracingCallbacksPtr pfJsrtSetRuntimeDomWrapperTracingCallbacks; JsrtSetRuntimeMemoryLimitPtr pfJsrtSetRuntimeMemoryLimit; JsrtSetCurrentContextPtr pfJsrtSetCurrentContext; JsrtGetCurrentContextPtr pfJsrtGetCurrentContext; JsrtDisposeRuntimePtr pfJsrtDisposeRuntime; JsrtCreateObjectPtr pfJsrtCreateObject; JsrtCreateExternalObjectPtr pfJsrtCreateExternalObject; + JsrtGetArrayForEachFunctionPtr pfJsrtGetArrayForEachFunction; + JsrtGetArrayKeysFunctionPtr pfJsrtGetArrayKeysFunction; + JsrtGetArrayValuesFunctionPtr pfJsrtGetArrayValuesFunction; + JsrtGetArrayEntriesFunctionPtr pfJsrtGetArrayEntriesFunction; + JsrtGetPropertyIdSymbolIteratorPtr pfJsrtGetPropertyIdSymbolIterator; + JsrtGetErrorPrototypePtr pfJsrtGetErrorPrototype; + JsrtGetIteratorPrototypePtr pfJsrtGetIteratorPrototype; + JsrtCreateFunctionPtr pfJsrtCreateFunction; JsrtCreateEnhancedFunctionPtr pfJsrtCreateEnhancedFunction; JsCreateNamedFunctionPtr pfJsrtCreateNamedFunction; @@ -153,6 +185,7 @@ struct JsAPIHooks JsrtDoubleToNumberPtr pfJsrtDoubleToNumber; JsrtGetExternalDataPtr pfJsrtGetExternalData; JsrtSetExternalDataPtr pfJsrtSetExternalData; + JsrtCloneObjectPtr pfJsrtCloneObject; JsrtCreateArrayPtr pfJsrtCreateArray; JsrtCreateArrayBufferPtr pfJsrtCreateArrayBuffer; JsrtCreateSharedArrayBufferWithSharedContentPtr pfJsrtCreateSharedArrayBufferWithSharedContent; @@ -167,6 +200,7 @@ struct JsAPIHooks JsrtReleasePtr pfJsrtRelease; JsrtAddRefPtr pfJsrtAddRef; JsrtGetValueType pfJsrtGetValueType; + JsrtGetIndexedPropertyPtr pfJsrtGetIndexedProperty; JsrtSetIndexedPropertyPtr pfJsrtSetIndexedProperty; JsrtSetPromiseContinuationCallbackPtr pfJsrtSetPromiseContinuationCallback; JsrtSetHostPromiseRejectionTrackerPtr pfJsrtSetHostPromiseRejectionTracker; @@ -222,6 +256,18 @@ struct JsAPIHooks JsrtTTDMoveToTopLevelEventPtr pfJsrtTTDMoveToTopLevelEvent; JsrtTTDReplayExecutionPtr pfJsrtTTDReplayExecution; + JsrtVarSerializerPtr pfJsrtVarSerializer; + JsrtVarSerializerSetTransferableVarsPtr pfJsrtVarSerializerSetTransferableVars; + JsrtVarSerializerWriteValuePtr pfJsrtVarSerializerWriteValue; + JsrtVarSerializerReleaseDataPtr pfJsrtVarSerializerReleaseData; + JsrtVarSerializerFreePtr pfJsrtVarSerializerFree; + + JsrtVarDeserializerPtr pfJsrtVarDeserializer; + JsrtVarDeserializerSetTransferableVarsPtr pfJsrtVarDeserializerSetTransferableVars; + JsrtVarDeserializerReadValuePtr pfJsrtVarDeserializerReadValue; + JsrtVarDeserializerFreePtr pfJsrtVarDeserializerFree; + + JsrtDetachArrayBufferPtr pfJsrtDetachArrayBuffer; #ifdef _WIN32 JsrtConnectJITProcess pfJsrtConnectJITProcess; #endif @@ -331,12 +377,20 @@ class ChakraRTInterface static JsErrorCode WINAPI JsCreateRuntime(JsRuntimeAttributes attributes, JsThreadServiceCallback threadService, JsRuntimeHandle *runtime) { return HOOK_JS_API(CreateRuntime(attributes, threadService, runtime)); } static JsErrorCode WINAPI JsCreateContext(JsRuntimeHandle runtime, JsContextRef *newContext) { return HOOK_JS_API(CreateContext(runtime, newContext)); } static JsErrorCode WINAPI JsSetObjectBeforeCollectCallback(JsRef ref, void* callbackState, JsObjectBeforeCollectCallback objectBeforeCollectCallback) { return HOOK_JS_API(SetObjectBeforeCollectCallback(ref, callbackState, objectBeforeCollectCallback)); } + static JsErrorCode WINAPI JsSetRuntimeDomWrapperTracingCallbacks(JsRuntimeHandle runtime, JsRef wrapperTracingState, JsDOMWrapperTracingCallback wrapperTracingCallback, JsDOMWrapperTracingDoneCallback wrapperTracingDoneCallback, JsDOMWrapperTracingEnterFinalPauseCallback enterFinalPauseCallback) { return HOOK_JS_API(SetRuntimeDomWrapperTracingCallbacks(runtime, wrapperTracingState, wrapperTracingCallback, wrapperTracingDoneCallback, enterFinalPauseCallback)); } static JsErrorCode WINAPI JsSetRuntimeMemoryLimit(JsRuntimeHandle runtime, size_t memory) { return HOOK_JS_API(SetRuntimeMemoryLimit(runtime, memory)); } static JsErrorCode WINAPI JsSetCurrentContext(JsContextRef context) { return HOOK_JS_API(SetCurrentContext(context)); } static JsErrorCode WINAPI JsGetCurrentContext(JsContextRef* context) { return HOOK_JS_API(GetCurrentContext(context)); } static JsErrorCode WINAPI JsDisposeRuntime(JsRuntimeHandle runtime) { return HOOK_JS_API(DisposeRuntime(runtime)); } static JsErrorCode WINAPI JsCreateObject(JsValueRef *object) { return HOOK_JS_API(CreateObject(object)); } static JsErrorCode WINAPI JsCreateExternalObject(void *data, JsFinalizeCallback callback, JsValueRef *object) { return HOOK_JS_API(CreateExternalObject(data, callback, object)); } + static JsErrorCode WINAPI JsGetArrayForEachFunction(JsValueRef * result) { return HOOK_JS_API(GetArrayForEachFunction(result)); } + static JsErrorCode WINAPI JsGetArrayKeysFunction(JsValueRef * result) { return HOOK_JS_API(GetArrayKeysFunction(result)); } + static JsErrorCode WINAPI JsGetArrayValuesFunction(JsValueRef * result) { return HOOK_JS_API(GetArrayValuesFunction(result)); } + static JsErrorCode WINAPI JsGetArrayEntriesFunction(JsValueRef * result) { return HOOK_JS_API(GetArrayEntriesFunction(result)); } + static JsErrorCode WINAPI JsGetPropertyIdSymbolIterator(JsPropertyIdRef * propertyId) { return HOOK_JS_API(GetPropertyIdSymbolIterator(propertyId)); } + static JsErrorCode WINAPI JsGetErrorPrototype(JsValueRef * result) { return HOOK_JS_API(GetErrorPrototype(result)); } + static JsErrorCode WINAPI JsGetIteratorPrototype(JsValueRef * result) { return HOOK_JS_API(GetIteratorPrototype(result)); } static JsErrorCode WINAPI JsCreateFunction(JsNativeFunction nativeFunction, void *callbackState, JsValueRef *function) { return HOOK_JS_API(CreateFunction(nativeFunction, callbackState, function)); } static JsErrorCode WINAPI JsCreateEnhancedFunction(JsEnhancedNativeFunction nativeFunction, JsValueRef metadata, void *callbackState, JsValueRef *function) { return HOOK_JS_API(CreateEnhancedFunction(nativeFunction, metadata, callbackState, function)); } static JsErrorCode WINAPI JsCreateNamedFunction(JsValueRef name, JsNativeFunction nativeFunction, void *callbackState, JsValueRef *function) { return HOOK_JS_API(CreateNamedFunction(name, nativeFunction, callbackState, function)); } @@ -359,6 +413,7 @@ class ChakraRTInterface static JsErrorCode WINAPI JsDoubleToNumber(double doubleValue, JsValueRef* value) { return HOOK_JS_API(DoubleToNumber(doubleValue, value)); } static JsErrorCode WINAPI JsGetExternalData(JsValueRef object, void **data) { return HOOK_JS_API(GetExternalData(object, data)); } static JsErrorCode WINAPI JsSetExternalData(JsValueRef object, void *data) { return HOOK_JS_API(SetExternalData(object, data)); } + static JsErrorCode WINAPI JsCloneObject(JsValueRef object, JsValueRef *data) { return HOOK_JS_API(CloneObject(object, data)); } static JsErrorCode WINAPI JsCreateArray(unsigned int length, JsValueRef *result) { return HOOK_JS_API(CreateArray(length, result)); } static JsErrorCode WINAPI JsCreateArrayBuffer(unsigned int byteLength, JsValueRef *result) { return HOOK_JS_API(CreateArrayBuffer(byteLength, result)); } static JsErrorCode WINAPI JsCreateSharedArrayBufferWithSharedContent(JsSharedArrayBufferContentHandle sharedContent, JsValueRef *result) { return HOOK_JS_API(CreateSharedArrayBufferWithSharedContent(sharedContent, result)); } @@ -373,6 +428,7 @@ class ChakraRTInterface static JsErrorCode WINAPI JsRelease(JsRef ref, unsigned int* count) { return HOOK_JS_API(Release(ref, count)); } static JsErrorCode WINAPI JsAddRef(JsRef ref, unsigned int* count) { return HOOK_JS_API(AddRef(ref, count)); } static JsErrorCode WINAPI JsGetValueType(JsValueRef value, JsValueType *type) { return HOOK_JS_API(GetValueType(value, type)); } + static JsErrorCode WINAPI JsGetIndexedProperty(JsValueRef object, JsValueRef index, JsValueRef *value) { return HOOK_JS_API(GetIndexedProperty(object, index, value)); } static JsErrorCode WINAPI JsSetIndexedProperty(JsValueRef object, JsValueRef index, JsValueRef value) { return HOOK_JS_API(SetIndexedProperty(object, index, value)); } static JsErrorCode WINAPI JsSetPromiseContinuationCallback(JsPromiseContinuationCallback callback, void *callbackState) { return HOOK_JS_API(SetPromiseContinuationCallback(callback, callbackState)); } static JsErrorCode WINAPI JsSetHostPromiseRejectionTracker(JsHostPromiseRejectionTrackerCallback callback, void *callbackState) { return HOOK_JS_API(SetHostPromiseRejectionTracker(callback, callbackState)); } @@ -435,6 +491,18 @@ class ChakraRTInterface static JsErrorCode WINAPI JsSerializeParserState(JsValueRef script, JsValueRef *buffer, JsParseScriptAttributes parseAttributes) { return HOOK_JS_API(SerializeParserState(script, buffer, parseAttributes)); } static JsErrorCode WINAPI JsRunScriptWithParserState(JsValueRef script, JsSourceContext sourceContext, JsValueRef sourceUrl, JsParseScriptAttributes parseAttributes, JsValueRef parserState, JsValueRef * result) { return HOOK_JS_API(RunScriptWithParserState(script, sourceContext, sourceUrl, parseAttributes, parserState, result)); } + static JsErrorCode WINAPI JsVarSerializer(ReallocateBufferMemoryFunc reallocateBufferMemory, WriteHostObjectFunc writeHostObject, void * callbackState, JsVarSerializerHandle *serializerHandle) { return HOOK_JS_API(VarSerializer(reallocateBufferMemory, writeHostObject, callbackState, serializerHandle)); } + static JsErrorCode WINAPI JsVarSerializerSetTransferableVars(JsVarSerializerHandle serializerHandle, JsValueRef *transferableVars, size_t transferableVarsCount) { return HOOK_JS_API(VarSerializerSetTransferableVars(serializerHandle, transferableVars, transferableVarsCount)); } + static JsErrorCode WINAPI JsVarSerializerWriteValue(JsVarSerializerHandle serializerHandle, JsValueRef rootObject) { return HOOK_JS_API(VarSerializerWriteValue(serializerHandle, rootObject)); } + static JsErrorCode WINAPI JsVarSerializerReleaseData(JsVarSerializerHandle serializerHandle, byte** data, size_t *dataLength) { return HOOK_JS_API(VarSerializerReleaseData(serializerHandle, data, dataLength)); } + static JsErrorCode WINAPI JsVarSerializerFree(JsVarSerializerHandle serializerHandle) { return HOOK_JS_API(VarSerializerFree(serializerHandle)); } + + static JsErrorCode WINAPI JsVarDeserializer(void *data, size_t dataLength, ReadHostObjectFunc readHostObject, GetSharedArrayBufferFromIdFunc getSharedArrayBufferFromId, void* callbackState, JsVarDeserializerHandle *deserializerHandle) { return HOOK_JS_API(VarDeserializer(data, dataLength, readHostObject, getSharedArrayBufferFromId, callbackState, deserializerHandle)); } + static JsErrorCode WINAPI JsVarDeserializerSetTransferableVars(JsVarDeserializerHandle deserializerHandle, JsValueRef* transferableVars, size_t transferableVarsCount) { return HOOK_JS_API(VarDeserializerSetTransferableVars(deserializerHandle, transferableVars, transferableVarsCount)); } + static JsErrorCode WINAPI JsVarDeserializerReadValue(JsVarDeserializerHandle deserializerHandle, JsValueRef* value) { return HOOK_JS_API(VarDeserializerReadValue(deserializerHandle, value)); } + static JsErrorCode WINAPI JsVarDeserializerFree(JsVarDeserializerHandle deserializerHandle) { return HOOK_JS_API(VarDeserializerFree(deserializerHandle)); } + + static JsErrorCode WINAPI JsDetachArrayBuffer(JsValueRef buffer) { return HOOK_JS_API(DetachArrayBuffer(buffer)); } static JsErrorCode WINAPI JsQueueBackgroundParse_Experimental(JsScriptContents* contents, DWORD* dwBgParseCookie) { return HOOK_JS_API(QueueBackgroundParse_Experimental)(contents, dwBgParseCookie); } static JsErrorCode WINAPI JsDiscardBackgroundParse_Experimental(DWORD dwBgParseCookie, void* buffer, bool* callerOwnsBuffer) { return HOOK_JS_API(DiscardBackgroundParse_Experimental(dwBgParseCookie, buffer, callerOwnsBuffer)); } static JsErrorCode WINAPI JsExecuteBackgroundParse_Experimental(DWORD dwBgParseCookie, JsValueRef script, JsSourceContext sourceContext, WCHAR *url, JsParseScriptAttributes parseAttributes, JsValueRef parserState, JsValueRef *result) { return HOOK_JS_API(ExecuteBackgroundParse_Experimental(dwBgParseCookie, script, sourceContext, url, parseAttributes, parserState, result)); } diff --git a/bin/ch/WScriptJsrt.cpp b/bin/ch/WScriptJsrt.cpp index c475ff84a2d..ea1238f8b6d 100644 --- a/bin/ch/WScriptJsrt.cpp +++ b/bin/ch/WScriptJsrt.cpp @@ -44,6 +44,13 @@ #define INTL_LIBRARY_TEXT "" #endif +struct SerializerBlob +{ + void *data; + size_t dataLength; + std::vector< std::pair > transferableArrays; +}; + MessageQueue* WScriptJsrt::messageQueue = nullptr; std::map WScriptJsrt::moduleRecordMap; std::map WScriptJsrt::moduleDirMap; @@ -252,6 +259,209 @@ JsValueRef WScriptJsrt::LoadScriptFileHelper(JsValueRef callee, JsValueRef *argu return returnValue; } +void WScriptJsrt::SetExceptionIf(JsErrorCode errorCode, LPCWSTR errorMessage) +{ + if (errorCode != JsNoError) + { + JsValueRef errorObject; + JsValueRef errorMessageString; + + if (wcscmp(errorMessage, _u("")) == 0) + { + errorMessage = ConvertErrorCodeToMessage(errorCode); + } + + ERROR_MESSAGE_TO_STRING(errCode, errorMessage, errorMessageString); + + ChakraRTInterface::JsCreateError(errorMessageString, &errorObject); + ChakraRTInterface::JsSetException(errorObject); + } +} + +byte * CHAKRA_CALLBACK ReallocateBufferMemory(void * state, byte *oldBuffer, size_t newSize, size_t *allocatedSize) +{ + void* data = realloc((void*)oldBuffer, newSize); + if (allocatedSize) + { + *allocatedSize = newSize; + } + return (byte*)data; +} + +bool CHAKRA_CALLBACK WriteHostObject(void * state, JsValueRef data) +{ + // Not implemented + return true; +} + +JsValueRef __stdcall WScriptJsrt::SerializeObject(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState) +{ + JsErrorCode errorCode = JsNoError; + LPCWSTR errorMessage = _u(""); + JsValueRef returnValue = JS_INVALID_REFERENCE; + HRESULT hr = S_OK; + JsValueRef *transferVarsArray = nullptr; + int transferVarsCount = 0; + if (argumentCount < 2) + { + errorCode = JsErrorInvalidArgument; + errorMessage = _u("Need an argument for WScript.Serialize"); + } + else + { + JsValueRef rootObject = arguments[1]; + JsValueRef transferArray = nullptr; + if (argumentCount > 2) + { + JsValueType argumentType = JsUndefined; + transferArray = arguments[2]; + IfJsrtErrorSetGo(ChakraRTInterface::JsGetValueType(transferArray, &argumentType)); + + if (argumentType != JsUndefined) + { + if (argumentType != JsArray) + { + errorCode = JsErrorInvalidArgument; + goto Error; + } + + JsPropertyIdRef lengthPropId; + JsValueRef arrayLengthObj = JS_INVALID_REFERENCE; + int arrayLength = 0; + IfJsrtErrorSetGo(CreatePropertyIdFromString("length", &lengthPropId)); + IfJsrtErrorSetGo(ChakraRTInterface::JsGetProperty(transferArray, lengthPropId, &arrayLengthObj)); + IfJsrtErrorSetGo(ChakraRTInterface::JsNumberToInt(arrayLengthObj, &arrayLength)); + if (arrayLength > 0) + { + transferVarsArray = new JsValueRef[arrayLength]; + if (transferVarsArray == nullptr) + { + errorCode = JsErrorOutOfMemory; + goto Error; + } + + for (int i = 0; i < arrayLength; i++) + { + JsValueRef index; + JsValueRef value = JS_INVALID_REFERENCE; + JsValueType jsType = JsUndefined; + + IfJsrtErrorSetGo(ChakraRTInterface::JsIntToNumber(i, &index)); + IfJsrtErrorSetGo(ChakraRTInterface::JsGetIndexedProperty(transferArray, index, &value)); + IfJsrtErrorSetGo(ChakraRTInterface::JsGetValueType(value, &jsType)); + if (jsType == JsArrayBuffer) + { + *(transferVarsArray + transferVarsCount) = value; + transferVarsCount++; + } + } + } + } + } + + JsVarSerializerHandle serializerHandle = nullptr; + + // This memory will be claimed at WScriptJsrt::Deserialize. + SerializerBlob *blob = new SerializerBlob(); + IfJsrtErrorSetGo(ChakraRTInterface::JsVarSerializer(ReallocateBufferMemory, WriteHostObject, nullptr, &serializerHandle)); + IfJsrtErrorSetGo(ChakraRTInterface::JsVarSerializerSetTransferableVars(serializerHandle, transferVarsArray, transferVarsCount)); + IfJsrtErrorSetGo(ChakraRTInterface::JsVarSerializerWriteValue(serializerHandle, rootObject)); + IfJsrtErrorSetGo(ChakraRTInterface::JsVarSerializerReleaseData(serializerHandle, (byte**)&blob->data, &blob->dataLength)); + + for (int i = 0; i < transferVarsCount; i++) + { + JsValueRef arrayBuffer = transferVarsArray[i]; + BYTE *buffer = nullptr; + uint32 bufferLength = 0; + IfJsrtErrorSetGo(ChakraRTInterface::JsGetArrayBufferStorage(arrayBuffer, &buffer, &bufferLength)); + blob->transferableArrays.push_back(std::make_pair((void*)buffer, bufferLength)); + IfJsrtErrorSetGo(ChakraRTInterface::JsDetachArrayBuffer(arrayBuffer)); + } + + errorCode = ChakraRTInterface::JsCreateExternalArrayBuffer((void*)blob, sizeof(SerializerBlob), nullptr, nullptr, &returnValue); + IfJsrtErrorSetGo(ChakraRTInterface::JsVarSerializerFree(serializerHandle)); + } +Error: + SetExceptionIf(errorCode, errorMessage); + + if (transferVarsArray) + { + delete[] transferVarsArray; + } + + return returnValue; +} + +JsValueRef CHAKRA_CALLBACK ReadHostObject(void * state) +{ + Assert(false); // TBD + return nullptr; +} + +JsValueRef CHAKRA_CALLBACK GetSharedArrayBufferFromId(void * state, uint32_t id) +{ + Assert(false); // TBD + return nullptr; +} +JsValueRef CHAKRA_CALLBACK GetWasmModuleFromId(void * state, uint32_t transfer_id) +{ + Assert(false); // TBD + return nullptr; +} + +JsValueRef __stdcall WScriptJsrt::Deserialize(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState) +{ + JsErrorCode errorCode = JsNoError; + LPCWSTR errorMessage = _u(""); + JsValueRef returnValue = JS_INVALID_REFERENCE; + JsValueRef * transferables = nullptr; + HRESULT hr = S_OK; + if (argumentCount < 2) + { + errorCode = JsErrorInvalidArgument; + errorMessage = _u("Need an argument for WScript.Deserialize"); + } + else + { + JsValueRef dataObject = arguments[1]; + uint32 dataLength = 0; + BYTE *data = nullptr; + IfJsrtErrorSetGo(ChakraRTInterface::JsGetArrayBufferStorage(dataObject, &data, &dataLength)); + SerializerBlob *blob = (SerializerBlob*)data; + JsVarDeserializerHandle deserializerHandle = nullptr; + IfJsrtErrorSetGo(ChakraRTInterface::JsVarDeserializer(blob->data, blob->dataLength, ReadHostObject, GetSharedArrayBufferFromId, nullptr, &deserializerHandle)); + + size_t arraySize = blob->transferableArrays.size(); + if (arraySize > 0) + { + transferables = new JsValueRef[arraySize]; + + for (size_t i = 0; i < arraySize; ++i) + { + JsValueRef result = nullptr; + IfJsrtErrorSetGo(ChakraRTInterface::JsCreateExternalArrayBuffer(blob->transferableArrays[i].first, blob->transferableArrays[i].second, nullptr, nullptr, &result)); + transferables[i] = result; + } + + IfJsrtErrorSetGo(ChakraRTInterface::JsVarDeserializerSetTransferableVars(deserializerHandle, transferables, arraySize)); + } + + IfJsrtErrorSetGo(ChakraRTInterface::JsVarDeserializerReadValue(deserializerHandle, &returnValue)); + IfJsrtErrorSetGo(ChakraRTInterface::JsVarDeserializerFree(deserializerHandle)); + delete blob; + + } + +Error: + SetExceptionIf(errorCode, errorMessage); + if (transferables) + { + delete[] transferables; + } + + return returnValue; +} + JsValueRef __stdcall WScriptJsrt::GetModuleNamespace(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState) { JsErrorCode errorCode = JsNoError; @@ -295,21 +505,7 @@ JsValueRef __stdcall WScriptJsrt::GetModuleNamespace(JsValueRef callee, bool isC } } - if (errorCode != JsNoError) - { - JsValueRef errorObject; - JsValueRef errorMessageString; - - if (wcscmp(errorMessage, _u("")) == 0) - { - errorMessage = ConvertErrorCodeToMessage(errorCode); - } - - ERROR_MESSAGE_TO_STRING(errCode, errorMessage, errorMessageString); - - ChakraRTInterface::JsCreateError(errorMessageString, &errorObject); - ChakraRTInterface::JsSetException(errorObject); - } + SetExceptionIf(errorCode, errorMessage); return returnValue; } @@ -983,7 +1179,10 @@ bool WScriptJsrt::Initialize() IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "RegisterModuleSource", RegisterModuleSourceCallback)); IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "GetModuleNamespace", GetModuleNamespace)); IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "GetProxyProperties", GetProxyPropertiesCallback)); - + + IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "SerializeObject", SerializeObject)); + IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Deserialize", Deserialize)); + // ToDo Remove IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Edit", EmptyCallback)); diff --git a/bin/ch/WScriptJsrt.h b/bin/ch/WScriptJsrt.h index f7996d2079d..dc4bb49c6dc 100644 --- a/bin/ch/WScriptJsrt.h +++ b/bin/ch/WScriptJsrt.h @@ -110,6 +110,7 @@ class WScriptJsrt static void FinalizeFree(void * addr); static void RegisterScriptDir(DWORD_PTR sourceContext, LPCSTR fullDirNarrow); private: + static void SetExceptionIf(JsErrorCode errorCode, LPCWSTR errorMessage); static bool CreateArgumentsObject(JsValueRef *argsObject); static bool CreateNamedFunction(const char*, JsNativeFunction callback, JsValueRef* functionVar); static void GetDir(LPCSTR fullPathNarrow, std::string *fullDirNarrow); @@ -144,6 +145,9 @@ class WScriptJsrt static JsValueRef CALLBACK SleepCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState); static JsValueRef CALLBACK GetProxyPropertiesCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState); + static JsValueRef CALLBACK SerializeObject(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState); + static JsValueRef CALLBACK Deserialize(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState); + static JsErrorCode FetchImportedModuleHelper(JsModuleRecord referencingModule, JsValueRef specifier, __out JsModuleRecord* dependentModuleRecord, LPCSTR refdir = nullptr); static MessageQueue *messageQueue; diff --git a/bin/ch/ch.cpp b/bin/ch/ch.cpp index c78cad60e1f..f2d80254696 100644 --- a/bin/ch/ch.cpp +++ b/bin/ch/ch.cpp @@ -868,12 +868,12 @@ HRESULT ExecuteTest(const char* fileName) JsContextRef context = JS_INVALID_REFERENCE; IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateContext(runtime, true, &context)); + IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context)); + #if ENABLE_TTD //We need this here since this context is created in record IfJsErrorFailLog(ChakraRTInterface::JsSetObjectBeforeCollectCallback(context, nullptr, WScriptJsrt::JsContextBeforeCollectCallback)); #endif - - IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context)); } else { diff --git a/bin/rl/rl.cpp b/bin/rl/rl.cpp index e1a8f9b503f..99e1a5bd178 100644 --- a/bin/rl/rl.cpp +++ b/bin/rl/rl.cpp @@ -4620,7 +4620,13 @@ UpdateTitleStatus() // start at 1: skip primary thread 0 (unless we decide to let it do real work) for (i = 1; i <= NumberOfThreads; i++) { ThreadInfo[i].GetCurrentTest(tempBuf); - s += sprintf_s(s, REMAININGARRAYLEN(TitleStatus, s), "; %s", tempBuf); + size_t remainingCount = REMAININGARRAYLEN(TitleStatus, s); + size_t testLen = strnlen_s(tempBuf, BUFFER_SIZE); + // Accounting for formatting string and endofbuffer char. + if ((testLen + 3) >= remainingCount) { + break; + } + s += sprintf_s(s, remainingCount, "; %s", tempBuf); } LeaveCriticalSection(&csTitleBar); diff --git a/lib/Backend/BackwardPass.cpp b/lib/Backend/BackwardPass.cpp index aa94e5f1947..59829c0fad4 100644 --- a/lib/Backend/BackwardPass.cpp +++ b/lib/Backend/BackwardPass.cpp @@ -3863,6 +3863,7 @@ BackwardPass::ProcessBlock(BasicBlock * block) && !block->GetFirstInstr()->m_func->GetJITFunctionBody()->IsWasmFunction() && !block->isDead && !block->isDeleted + && CONFIG_FLAG_RELEASE(AddMaskingBlocks) ) { FOREACH_PREDECESSOR_BLOCK(blockPred, block) diff --git a/lib/Backend/Inline.cpp b/lib/Backend/Inline.cpp index f008bb5ab56..cbc44dd3ffe 100644 --- a/lib/Backend/Inline.cpp +++ b/lib/Backend/Inline.cpp @@ -2860,6 +2860,7 @@ bool Inline::TryGetCallApplyAndTargetLdInstrs(IR::Instr * callInstr, _Outptr_res return false; } + Assert(applySym->GetInstrDef()->GetSrc1()->IsSymOpnd() && applySym->GetInstrDef()->GetSrc1()->AsSymOpnd()->IsPropertySymOpnd()); StackSym * targetSym = applySym->GetInstrDef()->GetSrc1()->AsSymOpnd()->AsPropertySymOpnd()->GetObjectSym(); if (!targetSym->IsSingleDef()) { diff --git a/lib/Backend/NativeCodeGenerator.cpp b/lib/Backend/NativeCodeGenerator.cpp index 875a04c631f..43b1e2ebc45 100644 --- a/lib/Backend/NativeCodeGenerator.cpp +++ b/lib/Backend/NativeCodeGenerator.cpp @@ -788,7 +788,7 @@ NativeCodeGenerator::IsValidVar(const Js::Var var, Recycler *const recycler) return false; } - // Not using DynamicObject::FromVar since there's a virtual call in there + // Not using VarTo since there's a virtual call in there DynamicObject *const object = static_cast(recyclableObject); if(!recycler->IsValidObject(object, sizeof(*object))) { diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index ec8a3805f9f..0cbeec680c4 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -40,6 +40,7 @@ add_library (ChakraCoreStatic STATIC $ $ $ + $ ${wasm_objects} ${wabt_objects} ${lttng_objects} @@ -77,6 +78,7 @@ target_include_directories ( ${CHAKRACORE_SOURCE_DIR}/lib/Runtime/ByteCode ${CHAKRACORE_SOURCE_DIR}/lib/Parser ${CHAKRACORE_SOURCE_DIR}/lib/Jsrt + ${CHAKRACORE_SOURCE_DIR}/lib/SCACore ${wasm_includes} ${wabt_includes} ) @@ -87,6 +89,7 @@ endif() add_subdirectory (Common) add_subdirectory (Parser) +add_subdirectory (SCACore) add_subdirectory (Runtime) add_subdirectory (Jsrt) if (CC_TARGETS_AMD64) diff --git a/lib/Common/CommonDefines.h b/lib/Common/CommonDefines.h index c330e1efebc..a20b0e49e3d 100644 --- a/lib/Common/CommonDefines.h +++ b/lib/Common/CommonDefines.h @@ -269,6 +269,8 @@ // JIT features +#define ENABLE_SPECTRE_RUNTIME_MITIGATIONS + #if DISABLE_JIT #define ENABLE_NATIVE_CODEGEN 0 #define ENABLE_PROFILE_INFO 0 diff --git a/lib/Common/ConfigFlagsList.h b/lib/Common/ConfigFlagsList.h index b7b3bfedc6c..55f9bc1e52f 100644 --- a/lib/Common/ConfigFlagsList.h +++ b/lib/Common/ConfigFlagsList.h @@ -525,8 +525,11 @@ PHASE(All) #define DEFAULT_CONFIG_MaxJitThreadCount (2) #define DEFAULT_CONFIG_ForceMaxJitThreadCount (false) +#ifdef ENABLE_SPECTRE_RUNTIME_MITIGATIONS #define DEFAULT_CONFIG_MitigateSpectre (true) +#define DEFAULT_CONFIG_AddMaskingBlocks (true) + #define DEFAULT_CONFIG_PoisonVarArrayLoad (true) #define DEFAULT_CONFIG_PoisonIntArrayLoad (true) #define DEFAULT_CONFIG_PoisonFloatArrayLoad (true) @@ -540,6 +543,25 @@ PHASE(All) #define DEFAULT_CONFIG_PoisonTypedArrayStore (true) #define DEFAULT_CONFIG_PoisonStringStore (true) #define DEFAULT_CONFIG_PoisonObjectsForStores (true) +#else +#define DEFAULT_CONFIG_MitigateSpectre (false) + +#define DEFAULT_CONFIG_AddMaskingBlocks (false) + +#define DEFAULT_CONFIG_PoisonVarArrayLoad (false) +#define DEFAULT_CONFIG_PoisonIntArrayLoad (false) +#define DEFAULT_CONFIG_PoisonFloatArrayLoad (false) +#define DEFAULT_CONFIG_PoisonTypedArrayLoad (false) +#define DEFAULT_CONFIG_PoisonStringLoad (false) +#define DEFAULT_CONFIG_PoisonObjectsForLoads (false) + +#define DEFAULT_CONFIG_PoisonVarArrayStore (false) +#define DEFAULT_CONFIG_PoisonIntArrayStore (false) +#define DEFAULT_CONFIG_PoisonFloatArrayStore (false) +#define DEFAULT_CONFIG_PoisonTypedArrayStore (false) +#define DEFAULT_CONFIG_PoisonStringStore (false) +#define DEFAULT_CONFIG_PoisonObjectsForStores (false) +#endif #ifdef RECYCLER_PAGE_HEAP #define DEFAULT_CONFIG_PageHeap ((Js::Number) PageHeapMode::PageHeapModeOff) @@ -1323,6 +1345,8 @@ FLAGNR(Boolean, ForceMaxJitThreadCount, "Force the number of parallel jit thread FLAGR(Boolean, MitigateSpectre, "Use mitigations for Spectre", DEFAULT_CONFIG_MitigateSpectre) +FLAGPR(Boolean, MitigateSpectre, AddMaskingBlocks, "Optimize Spectre mitigations by masking on loop out edges", DEFAULT_CONFIG_AddMaskingBlocks) + FLAGPR(Boolean, MitigateSpectre, PoisonVarArrayLoad, "Poison loads from Var arrays", DEFAULT_CONFIG_PoisonVarArrayLoad) FLAGPR(Boolean, MitigateSpectre, PoisonIntArrayLoad, "Poison loads from Int arrays", DEFAULT_CONFIG_PoisonIntArrayLoad) FLAGPR(Boolean, MitigateSpectre, PoisonFloatArrayLoad, "Poison loads from Float arrays", DEFAULT_CONFIG_PoisonFloatArrayLoad) diff --git a/lib/Common/Core/ConfigParser.cpp b/lib/Common/Core/ConfigParser.cpp index 6f0700941b5..166c070de3c 100644 --- a/lib/Common/Core/ConfigParser.cpp +++ b/lib/Common/Core/ConfigParser.cpp @@ -579,32 +579,33 @@ void ConfigParser::ProcessConfiguration(HANDLE hmod) FILE *fp; // fail usually means there is an existing console. We don't really care. - AllocConsole(); - - fd = _open_osfhandle((intptr_t)GetStdHandle(STD_OUTPUT_HANDLE), O_TEXT); - fp = _wfdopen(fd, _u("w")); - - if (fp != nullptr) + if (AllocConsole()) { - *stdout = *fp; - setvbuf(stdout, nullptr, _IONBF, 0); - - fd = _open_osfhandle((intptr_t)GetStdHandle(STD_ERROR_HANDLE), O_TEXT); + fd = _open_osfhandle((intptr_t)GetStdHandle(STD_OUTPUT_HANDLE), O_TEXT); fp = _wfdopen(fd, _u("w")); if (fp != nullptr) { - *stderr = *fp; - setvbuf(stderr, nullptr, _IONBF, 0); + *stdout = *fp; + setvbuf(stdout, nullptr, _IONBF, 0); - char16 buffer[_MAX_PATH + 70]; + fd = _open_osfhandle((intptr_t)GetStdHandle(STD_ERROR_HANDLE), O_TEXT); + fp = _wfdopen(fd, _u("w")); - if (ConfigParserAPI::FillConsoleTitle(buffer, _MAX_PATH + 20, modulename)) + if (fp != nullptr) { - SetConsoleTitle(buffer); - } + *stderr = *fp; + setvbuf(stderr, nullptr, _IONBF, 0); - hasOutput = true; + char16 buffer[_MAX_PATH + 70]; + + if (ConfigParserAPI::FillConsoleTitle(buffer, _MAX_PATH + 20, modulename)) + { + SetConsoleTitle(buffer); + } + + hasOutput = true; + } } } } diff --git a/lib/Common/Memory/Recycler.cpp b/lib/Common/Memory/Recycler.cpp index 3dd06207a69..31261be9be3 100644 --- a/lib/Common/Memory/Recycler.cpp +++ b/lib/Common/Memory/Recycler.cpp @@ -192,6 +192,7 @@ Recycler::Recycler(AllocationPolicyManager * policyManager, IdleDecommitPageAllo inDisposeWrapper(false), hasDisposableObject(false), hasNativeGCHost(false), + needExternalWrapperTracing(false), tickCountNextDispose(0), transientPinnedObject(nullptr), pinnedObjectMap(1024, HeapAllocator::GetNoMemProtectInstance()), @@ -247,8 +248,9 @@ Recycler::Recycler(AllocationPolicyManager * policyManager, IdleDecommitPageAllo , capturePageHeapAllocStack(false) , capturePageHeapFreeStack(false) #endif - , objectBeforeCollectCallbackMap(nullptr) + , objectBeforeCollectCallbackList(nullptr) , objectBeforeCollectCallbackState(ObjectBeforeCollectCallback_None) + , objectBeforeCollectCallbackArena(_u("BeforeCollect-List"), pageAllocator, Js::Throw::OutOfMemory) #if GLOBAL_ENABLE_WRITE_BARRIER , pendingWriteBarrierBlockMap(&HeapAllocator::Instance) #endif @@ -950,6 +952,18 @@ Recycler::SetHasNativeGCHost() this->hasNativeGCHost = true; } +void +Recycler::SetNeedExternalWrapperTracing() +{ + this->needExternalWrapperTracing = true; +} + +void +Recycler::ClearNeedExternalWrapperTracing() +{ + this->needExternalWrapperTracing = false; +} + bool Recycler::NeedOOMRescan() const { @@ -2117,6 +2131,13 @@ Recycler::CheckAllocExternalMark() const } #endif +void +Recycler::TryExternalMarkNonInterior(void* candidate) +{ + Assert(!this->IsConcurrentExecutingState()); + this->TryMarkNonInterior(candidate); +} + void Recycler::TryMarkNonInterior(void* candidate, void* parentReference) { @@ -2528,6 +2549,7 @@ Recycler::DoParallelMark() if (actualSplitCount == 0) { this->ProcessMark(false); + return; } @@ -2773,6 +2795,23 @@ Recycler::EndMarkCheckOOMRescan() return oomRescan; } +void +Recycler::FinishWrapperObjectTracing() +{ + //TODO:akatti:Add ETW event for this. + // Tracing would have generated more work for mark and marking might generate more work for tracing. + // We continue until we find no more pending tracing work. + do + { + this->collectionWrapper->EndMarkDomWrapperTracingCallback(); + this->ProcessMark(false); + } while (!this->collectionWrapper->EndMarkDomWrapperTracingDoneCallback()); + + // This is just to wait until tracing has finished. + this->collectionWrapper->EndMarkDomWrapperTracingCallback(); + this->ClearNeedExternalWrapperTracing(); +} + bool Recycler::EndMark() { @@ -2786,6 +2825,12 @@ Recycler::EndMark() { // We have finished marking AUTO_NO_EXCEPTION_REGION; + if (this->needExternalWrapperTracing) + { + this->collectionWrapper->EndMarkDomWrapperTracingEnterFinalPauseCallback(); + this->FinishWrapperObjectTracing(); + } + collectionWrapper->EndMarkCallback(); } @@ -2888,8 +2933,15 @@ Recycler::EndMarkOnLowMemory() } #endif - // Drain the mark stack - ProcessMark(false); + // Drain the mark stack along with any required DOM wrapper tracing. + if (this->needExternalWrapperTracing) + { + this->FinishWrapperObjectTracing(); + } + else + { + this->ProcessMark(false); + } #ifdef ENABLE_DEBUG_CONFIG_OPTIONS iterations++; @@ -2937,7 +2989,14 @@ Recycler::PostHeapEnumScan(PostHeapEnumScanCallback callback, void *data) this->postHeapEnunScanData = data; FindRoots(); - ProcessMark(false); + if (this->needExternalWrapperTracing) + { + this->FinishWrapperObjectTracing(); + } + else + { + this->ProcessMark(false); + } this->pfPostHeapEnumScanCallback = NULL; this->postHeapEnunScanData = NULL; @@ -6482,7 +6541,11 @@ Recycler::DoTwoPassConcurrentSweepPreCheck() // SLIST during concurrent sweep. // 2. We are not in a Partial GC. // 3. At-least one heap bucket exceeds the RecyclerHeuristic::AllocDuringConcurrentSweepHeapBlockThreshold. - this->allowAllocationsDuringConcurrentSweepForCollection = this->isInScript && !this->recyclerSweepManager->InPartialCollect(); + bool inPartialCollect = false; +#if ENABLE_PARTIAL_GC + inPartialCollect = this->recyclerSweepManager->InPartialCollect(); +#endif + this->allowAllocationsDuringConcurrentSweepForCollection = this->isInScript && !inPartialCollect; // Do the actual 2-pass check only if the first 2 checks pass. if (this->allowAllocationsDuringConcurrentSweepForCollection) @@ -8951,14 +9014,14 @@ void Recycler::SetObjectBeforeCollectCallback(void* object, return; // NOP at shutdown } - if (objectBeforeCollectCallbackMap == nullptr) + if (objectBeforeCollectCallbackList == nullptr) { if (callback == nullptr) return; - objectBeforeCollectCallbackMap = HeapNew(ObjectBeforeCollectCallbackMap, &HeapAllocator::Instance); + objectBeforeCollectCallbackList = Anew(&this->objectBeforeCollectCallbackArena, ObjectBeforeCollectCallbackList, &this->objectBeforeCollectCallbackArena); } // only allow 1 callback per object - objectBeforeCollectCallbackMap->Item(object, ObjectBeforeCollectCallbackData(callbackWrapper, callback, callbackState, threadContext)); + objectBeforeCollectCallbackList->Push(ObjectBeforeCollectCallbackData(object, callbackWrapper, callback, callbackState, threadContext)); if (callback != nullptr && this->IsInObjectBeforeCollectCallback()) // revive { @@ -8967,9 +9030,28 @@ void Recycler::SetObjectBeforeCollectCallback(void* object, } } +void Recycler::SetDOMWrapperTracingCallback(void * state, DOMWrapperTracingCallback tracingCallback, DOMWrapperTracingDoneCallback tracingDoneCallback, DOMWrapperTracingEnterFinalPauseCallback enterFinalPauseCallback) +{ + Assert(state); + Assert(tracingCallback); + Assert(enterFinalPauseCallback); + this->collectionWrapper->SetWrapperTracingCallbackState(state); + this->collectionWrapper->SetDOMWrapperTracingCallback(tracingCallback); + this->collectionWrapper->SetDOMWrapperTracingDoneCallback(tracingDoneCallback); + this->collectionWrapper->SetDOMWrapperTracingEnterFinalPauseCallback(enterFinalPauseCallback); +} + +void Recycler::ClearDOMWrapperTracingCallback() +{ + this->collectionWrapper->SetWrapperTracingCallbackState(nullptr); + this->collectionWrapper->SetDOMWrapperTracingCallback(nullptr); + this->collectionWrapper->SetDOMWrapperTracingDoneCallback(nullptr); + this->collectionWrapper->SetDOMWrapperTracingEnterFinalPauseCallback(nullptr); +} + bool Recycler::ProcessObjectBeforeCollectCallbacks(bool atShutdown/*= false*/) { - if (this->objectBeforeCollectCallbackMap == nullptr) + if (this->objectBeforeCollectCallbackList == nullptr) { return false; // no callbacks } @@ -8977,21 +9059,21 @@ bool Recycler::ProcessObjectBeforeCollectCallbacks(bool atShutdown/*= false*/) Assert(!this->IsInObjectBeforeCollectCallback()); AutoRestoreValue autoInObjectBeforeCollectCallback(&objectBeforeCollectCallbackState, - atShutdown ? ObjectBeforeCollectCallback_Shutdown: ObjectBeforeCollectCallback_Normal); + atShutdown ? ObjectBeforeCollectCallback_Shutdown : ObjectBeforeCollectCallback_Normal); // The callbacks may register/unregister callbacks while we are enumerating the current map. To avoid // conflicting usage of the callback map, we swap it out. New registration will go to a new map. - AutoAllocatorObjectPtr oldCallbackMap( - this->objectBeforeCollectCallbackMap, &HeapAllocator::Instance); - this->objectBeforeCollectCallbackMap = nullptr; + AutoAllocatorObjectPtr oldCallbackList( + this->objectBeforeCollectCallbackList, &this->objectBeforeCollectCallbackArena); + this->objectBeforeCollectCallbackList = nullptr; bool hasRemainingCallbacks = false; - oldCallbackMap->MapAndRemoveIf([&](const ObjectBeforeCollectCallbackMap::EntryType& entry) + FOREACH_SLIST_ENTRY_EDITING(ObjectBeforeCollectCallbackData, data, oldCallbackList, iter) { - const ObjectBeforeCollectCallbackData& data = entry.Value(); + bool remove = true; if (data.callback != nullptr) { - void* object = entry.Key(); + void* object = data.object; if (atShutdown || !this->IsObjectMarked(object)) { if (data.callbackWrapper != nullptr) @@ -9006,33 +9088,32 @@ bool Recycler::ProcessObjectBeforeCollectCallbacks(bool atShutdown/*= false*/) else { hasRemainingCallbacks = true; - return false; // Do not remove this entry, remaining callback for future + remove = false; // Do not remove this entry, remaining callback for future } } - - return true; // Remove this entry - }); + if (remove) + { + iter.RemoveCurrent(); + } + } NEXT_SLIST_ENTRY_EDITING; // Merge back remaining callbacks if any if (hasRemainingCallbacks) { - if (this->objectBeforeCollectCallbackMap == nullptr) + if (this->objectBeforeCollectCallbackList == nullptr) { - this->objectBeforeCollectCallbackMap = oldCallbackMap.Detach(); + this->objectBeforeCollectCallbackList = oldCallbackList.Detach(); } else { - if (oldCallbackMap->Count() > this->objectBeforeCollectCallbackMap->Count()) - { - // Swap so that oldCallbackMap is the smaller one - ObjectBeforeCollectCallbackMap* tmp = oldCallbackMap.Detach(); - *&oldCallbackMap = this->objectBeforeCollectCallbackMap; - this->objectBeforeCollectCallbackMap = tmp; - } + // Swap back, since old list is likely larger + ObjectBeforeCollectCallbackList* tmp = oldCallbackList.Detach(); + *&oldCallbackList = this->objectBeforeCollectCallbackList; + this->objectBeforeCollectCallbackList = tmp; - oldCallbackMap->Map([&](void* object, const ObjectBeforeCollectCallbackData& data) + oldCallbackList->Map([&](const ObjectBeforeCollectCallbackData& data) { - this->objectBeforeCollectCallbackMap->Item(object, data); + this->objectBeforeCollectCallbackList->Push(data); }); } } @@ -9044,7 +9125,7 @@ void Recycler::ClearObjectBeforeCollectCallbacks() { // This is called at shutting down. All objects will be gone. Invoke each registered callback if any. ProcessObjectBeforeCollectCallbacks(/*atShutdown*/true); - Assert(objectBeforeCollectCallbackMap == nullptr); + Assert(objectBeforeCollectCallbackList == nullptr); } #ifdef RECYCLER_TEST_SUPPORT diff --git a/lib/Common/Memory/Recycler.h b/lib/Common/Memory/Recycler.h index 8a45bc5aeff..089d050e121 100644 --- a/lib/Common/Memory/Recycler.h +++ b/lib/Common/Memory/Recycler.h @@ -177,6 +177,7 @@ class RecyclerWeakReferenceRegion { #define RecyclerNewFinalized(recycler,T,...) static_cast(static_cast(AllocatorNewBase(Recycler, recycler, AllocFinalizedInlined, T, __VA_ARGS__))) #define RecyclerNewFinalizedPlus(recycler, size, T,...) static_cast(static_cast(AllocatorNewPlusBase(Recycler, recycler, AllocFinalized, size, T, __VA_ARGS__))) #define RecyclerNewTracked(recycler,T,...) static_cast(static_cast(AllocatorNewBase(Recycler, recycler, AllocTrackedInlined, T, __VA_ARGS__))) +#define RecyclerNewTrackedPlus(recycler, size, T,...) static_cast(static_cast(AllocatorNewPlusBase(Recycler, recycler, AllocTracked, size, T, __VA_ARGS__))) #define RecyclerNewEnumClass(recycler, enumClass, T, ...) new (TRACK_ALLOC_INFO(static_cast(recycler), T, Recycler, 0, (size_t)-1), InfoBitsWrapper()) T(__VA_ARGS__) #define RecyclerNewWithInfoBits(recycler, infoBits, T, ...) new (TRACK_ALLOC_INFO(static_cast(recycler), T, Recycler, 0, (size_t)-1), InfoBitsWrapper()) T(__VA_ARGS__) #define RecyclerNewFinalizedClientTracked(recycler,T,...) static_cast(static_cast(AllocatorNewBase(Recycler, recycler, AllocFinalizedClientTrackedInlined, T, __VA_ARGS__))) @@ -304,6 +305,10 @@ class RecyclerWeakReferenceRegion { typedef void (__cdecl* ExternalRootMarker)(void *); +typedef void (*DOMWrapperTracingCallback)(_In_opt_ void *data); +typedef bool (*DOMWrapperTracingDoneCallback)(_In_opt_ void *data); +typedef void (*DOMWrapperTracingEnterFinalPauseCallback)(_In_opt_ void *data); + class RecyclerCollectionWrapper { public: @@ -359,8 +364,58 @@ class RecyclerCollectionWrapper _isScriptContextCloseGCPending = TRUE; } + void SetDOMWrapperTracingCallback(DOMWrapperTracingCallback callback) + { + wrapperTracingCallback = callback; + } + + void SetWrapperTracingCallbackState(void * state) + { + wrapperTracingCallbackState = state; + } + + void SetDOMWrapperTracingEnterFinalPauseCallback(DOMWrapperTracingEnterFinalPauseCallback callback) + { + wrapperTracingEnterFinalPauseCallback = callback; + } + + void SetDOMWrapperTracingDoneCallback(DOMWrapperTracingDoneCallback callback) + { + wrapperTracingDoneCallback = callback; + } + + void EndMarkDomWrapperTracingCallback() + { + if (this->wrapperTracingCallback) + { + this->wrapperTracingCallback(this->wrapperTracingCallbackState); + } + } + + bool EndMarkDomWrapperTracingDoneCallback() + { + if (this->wrapperTracingDoneCallback) + { + return this->wrapperTracingDoneCallback(this->wrapperTracingCallbackState); + } + + return true; + } + + void EndMarkDomWrapperTracingEnterFinalPauseCallback() + { + if (this->wrapperTracingEnterFinalPauseCallback) + { + this->wrapperTracingEnterFinalPauseCallback(this->wrapperTracingCallbackState); + } + } + protected: BOOL _isScriptContextCloseGCPending; + void * wrapperTracingCallbackState; + DOMWrapperTracingCallback wrapperTracingCallback; + DOMWrapperTracingDoneCallback wrapperTracingDoneCallback; + DOMWrapperTracingEnterFinalPauseCallback wrapperTracingEnterFinalPauseCallback; }; class DefaultRecyclerCollectionWrapper : public RecyclerCollectionWrapper @@ -914,6 +969,7 @@ class Recycler bool allowDispose; bool inDisposeWrapper; bool needOOMRescan; + bool needExternalWrapperTracing; bool hasDisposableObject; bool hasNativeGCHost; DWORD tickCountNextDispose; @@ -1178,6 +1234,8 @@ class Recycler void SetIsInScript(bool isInScript); bool HasNativeGCHost() const; void SetHasNativeGCHost(); + void SetNeedExternalWrapperTracing(); + void ClearNeedExternalWrapperTracing(); bool ShouldIdleCollectOnExit(); void ScheduleNextCollection(); @@ -1208,6 +1266,7 @@ class Recycler #endif // FindRoots + void TryExternalMarkNonInterior(void * candidate); void TryMarkNonInterior(void* candidate, void* parentReference = nullptr); void TryMarkInterior(void *candidate, void* parentReference = nullptr); @@ -1601,6 +1660,7 @@ class Recycler void DoParallelMark(); void DoBackgroundParallelMark(); #endif + void FinishWrapperObjectTracing(); size_t RootMark(CollectionState markState); @@ -2041,22 +2101,25 @@ class Recycler ObjectBeforeCollectCallbackWrapper callbackWrapper, void* threadContext); void ClearObjectBeforeCollectCallbacks(); + void SetDOMWrapperTracingCallback(void * state, DOMWrapperTracingCallback tracingCallback, DOMWrapperTracingDoneCallback tracingDoneCallback, DOMWrapperTracingEnterFinalPauseCallback enterFinalPauseCallback); + void ClearDOMWrapperTracingCallback(); bool IsInObjectBeforeCollectCallback() const { return objectBeforeCollectCallbackState != ObjectBeforeCollectCallback_None; } private: struct ObjectBeforeCollectCallbackData { + void* object; ObjectBeforeCollectCallback callback; void* callbackState; void* threadContext; ObjectBeforeCollectCallbackWrapper callbackWrapper; ObjectBeforeCollectCallbackData() {} - ObjectBeforeCollectCallbackData(ObjectBeforeCollectCallbackWrapper callbackWrapper, ObjectBeforeCollectCallback callback, void* callbackState, void* threadContext) : - callbackWrapper(callbackWrapper), callback(callback), callbackState(callbackState), threadContext(threadContext) {} + ObjectBeforeCollectCallbackData(void* object, ObjectBeforeCollectCallbackWrapper callbackWrapper, ObjectBeforeCollectCallback callback, void* callbackState, void* threadContext) : + object(object), callbackWrapper(callbackWrapper), callback(callback), callbackState(callbackState), threadContext(threadContext) {} }; - typedef JsUtil::BaseDictionary ObjectBeforeCollectCallbackMap; - ObjectBeforeCollectCallbackMap* objectBeforeCollectCallbackMap; + typedef SList ObjectBeforeCollectCallbackList; + ObjectBeforeCollectCallbackList* objectBeforeCollectCallbackList; + ArenaAllocator objectBeforeCollectCallbackArena; enum ObjectBeforeCollectCallbackState { diff --git a/lib/Common/Memory/SmallNormalHeapBucket.cpp b/lib/Common/Memory/SmallNormalHeapBucket.cpp index 0354160f610..98365a50f46 100644 --- a/lib/Common/Memory/SmallNormalHeapBucket.cpp +++ b/lib/Common/Memory/SmallNormalHeapBucket.cpp @@ -23,12 +23,14 @@ SmallNormalHeapBucketBase::AggregateBucketStats() { __super::AggregateBucketStats(); +#if ENABLE_PARTIAL_GC HeapBlockList::ForEach(partialHeapBlockList, [this](TBlockType* heapBlock) { heapBlock->AggregateBlockStats(this->memStats); }); HeapBlockList::ForEach(partialSweptHeapBlockList, [this](TBlockType* heapBlock) { heapBlock->AggregateBlockStats(this->memStats); }); +#endif } #endif diff --git a/lib/Jsrt/CMakeLists.txt b/lib/Jsrt/CMakeLists.txt index cc85fef3eab..222fd88cdaf 100644 --- a/lib/Jsrt/CMakeLists.txt +++ b/lib/Jsrt/CMakeLists.txt @@ -26,4 +26,5 @@ target_include_directories ( ../Runtime/ByteCode ../Runtime/Debug ../Parser + ../SCACore ) diff --git a/lib/Jsrt/Chakra.Jsrt.vcxproj b/lib/Jsrt/Chakra.Jsrt.vcxproj index 06d734e6144..f183c5ef8aa 100644 --- a/lib/Jsrt/Chakra.Jsrt.vcxproj +++ b/lib/Jsrt/Chakra.Jsrt.vcxproj @@ -30,6 +30,7 @@ $(MSBuildThisFileDirectory)..\Runtime\Base; $(MSBuildThisFileDirectory)..\Runtime\Debug; $(MSBuildThisFileDirectory)..\Parser; + $(MSBuildThisFileDirectory)..\SCACore; $(MSBuildThisFileDirectory)..\WasmReader; $(MSBuildThisFileDirectory)..\Backend; $(IntDir); diff --git a/lib/Jsrt/ChakraCommon.h b/lib/Jsrt/ChakraCommon.h index 68ce2934e1c..aa5b5deb61d 100644 --- a/lib/Jsrt/ChakraCommon.h +++ b/lib/Jsrt/ChakraCommon.h @@ -25,12 +25,13 @@ // Platform specific code #if defined(_WIN32) && defined(_MSC_VER) -#include +#include // Header macros #define CHAKRA_CALLBACK CALLBACK #define CHAKRA_API STDAPI_(JsErrorCode) +typedef unsigned char byte; typedef DWORD_PTR ChakraCookie; typedef BYTE* ChakraBytePtr; #else // Non-Windows VC++ @@ -41,6 +42,7 @@ typedef BYTE* ChakraBytePtr; #define _In_z_ #define _In_opt_ #define _Inout_ +#define _Inout_opt_ #define _Out_ #define _Out_opt_ #define _In_reads_(x) @@ -314,6 +316,18 @@ typedef unsigned short uint16_t; /// VM was unable to perform the request action /// JsErrorDiagUnableToPerformAction, + /// + /// Serializer/Deserializer does not support current data + /// + JsSerializerNotSupported, + /// + /// Current object is not transferable during serialization + /// + JsTransferableNotSupported, + /// + /// Current object is already detached when serialized + /// + JsTransferableAlreadyDetached, } JsErrorCode; /// @@ -550,6 +564,10 @@ typedef unsigned short uint16_t; /// This one needs to be set for Utf16 /// JsParseScriptAttributeArrayBufferIsUtf16Encoded = 0x2, + /// + /// Script should be parsed in strict mode + /// + JsParseScriptAttributeStrictMode = 0x4, } JsParseScriptAttributes; /// diff --git a/lib/Jsrt/ChakraCore.h b/lib/Jsrt/ChakraCore.h index 936929849d9..494af0b0bc8 100644 --- a/lib/Jsrt/ChakraCore.h +++ b/lib/Jsrt/ChakraCore.h @@ -48,6 +48,23 @@ typedef void* JsModuleRecord; /// typedef void *JsSharedArrayBufferContentHandle; +/// +/// A reference to a SCA Serializer. +/// +/// +/// This represents the internal state of a Serializer +/// +typedef void *JsVarSerializerHandle; + +/// +/// A reference to a SCA Deserializer. +/// +/// +/// This represents the internal state of a Deserializer +/// +typedef void *JsVarDeserializerHandle; + + /// /// Flags for parsing a module. /// @@ -216,6 +233,44 @@ typedef _Ret_maybenull_ JsValueRef(CHAKRA_CALLBACK * JsEnhancedNativeFunction)(_ /// The state passed to JsSetHostPromiseRejectionTracker. typedef void (CHAKRA_CALLBACK *JsHostPromiseRejectionTrackerCallback)(_In_ JsValueRef promise, _In_ JsValueRef reason, _In_ bool handled, _In_opt_ void *callbackState); +/// +/// A structure containing information about interceptors. +/// +typedef struct _JsGetterSetterInterceptor { + JsValueRef getTrap; + JsValueRef setTrap; + JsValueRef deletePropertyTrap; + JsValueRef enumerateTrap; + JsValueRef ownKeysTrap; + JsValueRef hasTrap; + JsValueRef getOwnPropertyDescriptorTrap; + JsValueRef definePropertyTrap; + JsValueRef initializerTrap; +} JsGetterSetterInterceptor; + +/// +/// A callback for tracing references back from Chakra to DOM wrappers. +/// +typedef void (CHAKRA_CALLBACK *JsDOMWrapperTracingCallback)(_In_opt_ void *data); + +/// +/// A callback for checking whether tracing from Chakra to DOM wrappers has completed. +/// +typedef bool (CHAKRA_CALLBACK *JsDOMWrapperTracingDoneCallback)(_In_opt_ void *data); + +/// +/// A callback for entering final pause for tracing DOM wrappers. +/// +typedef void(CHAKRA_CALLBACK *JsDOMWrapperTracingEnterFinalPauseCallback)(_In_opt_ void *data); + +/// +/// A trace callback. +/// +/// +/// The external data that was passed in when creating the object being traced. +/// +typedef void (CHAKRA_CALLBACK *JsTraceCallback)(_In_opt_ void *data); + /// /// Creates a new enhanced JavaScript function. /// @@ -595,6 +650,32 @@ CHAKRA_API _In_ size_t length, _Out_ JsPropertyIdRef *propertyId); +/// +/// Creates the property ID associated with the name. +/// +/// +/// +/// Property IDs are specific to a context and cannot be used across contexts. +/// +/// +/// Requires an active script context. +/// +/// +/// +/// The name of the property ID to get or create. The name may consist of only digits. +/// The string is expected to be ASCII / utf8 encoded. +/// +/// length of the name in bytes +/// The property string in this runtime for the given name. +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsCreatePropertyString( + _In_z_ const char *name, + _In_ size_t length, + _Out_ JsValueRef* propertyString); + /// /// Copies the name associated with the property ID into a buffer. /// @@ -1002,6 +1083,209 @@ CHAKRA_API _In_opt_ JsValueRef prototype, _Out_ JsValueRef *object); +/// +/// Creates a new object (with prototype) that stores some data. +/// +/// +/// Requires an active script context. +/// +/// External data that the object will represent. May be null. +/// +/// A callback for when the object is traced. May be null. +/// +/// A callback for when the object is finalized. May be null. +/// +/// Prototype object or nullptr. +/// The new object. +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsCreateTracedExternalObject( + _In_opt_ void *data, + _In_opt_ size_t inlineSlotSize, + _In_opt_ JsTraceCallback traceCallback, + _In_opt_ JsFinalizeCallback finalizeCallback, + _In_opt_ JsValueRef prototype, + _Out_ JsValueRef *object); + +/// +/// Creates a new object (with prototype) that stores some external data and also supports interceptors. +/// +/// +/// Requires an active script context. +/// +/// External data that the object will represent. May be null. +/// +/// A callback for when the object is finalized. May be null. +/// +/// Prototype object or nullptr. +/// The new object. +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsCreateCustomExternalObject( + _In_opt_ void *data, + _In_opt_ size_t inlineSlotSize, + _In_opt_ JsTraceCallback traceCallback, + _In_opt_ JsFinalizeCallback finalizeCallback, + _Inout_opt_ JsGetterSetterInterceptor ** getterSetterInterceptor, + _In_opt_ JsValueRef prototype, + _Out_ JsValueRef * object); + +/// +/// Returns a reference to the Array.Prototype.forEach function. The function is created if it's not already present. +/// +/// A reference to the Array.Prototype.forEach function. +CHAKRA_API +JsGetArrayForEachFunction(_Out_ JsValueRef * result); + +/// +/// Returns a reference to the Array.Prototype.keys function. The function is created if it's not already present. +/// +/// A reference to the Array.Prototype.keys function. +CHAKRA_API +JsGetArrayKeysFunction(_Out_ JsValueRef * result); + +/// +/// Returns a reference to the Array.Prototype.values function. The function is created if it's not already present. +/// +/// A reference to the Array.Prototype.values function. +CHAKRA_API +JsGetArrayValuesFunction(_Out_ JsValueRef * result); + +/// +/// Returns a reference to the Array.Prototype.entries function. The function is created if it's not already present. +/// +/// A reference to the Array.Prototype.entries function. +CHAKRA_API +JsGetArrayEntriesFunction(_Out_ JsValueRef * result); + +/// +/// Returns the property id of the Symbol.iterator property. +/// +/// The property id of the Symbol.iterator property. +CHAKRA_API +JsGetPropertyIdSymbolIterator(_Out_ JsPropertyIdRef * propertyId); + +/// +/// Returns a reference to the Javascript error prototype object. +/// +/// A reference to the Javascript error prototype object. +CHAKRA_API +JsGetErrorPrototype(_Out_ JsValueRef * result); + +/// +/// Returns a reference to the Javascript iterator prototype object. +/// +/// A reference to the Javascript iterator prototype object. +CHAKRA_API +JsGetIteratorPrototype(_Out_ JsValueRef * result); + +/// +/// Returns a value that indicates whether an object is a constructor. +/// +/// +/// Requires an active script context. +/// +/// The object to test. +/// If the object is a constructor, true, false otherwise. +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsIsConstructor( + _In_ JsValueRef object, + _Out_ bool *isConstructor); + +/// +/// Clones an object +/// +/// The original object. +/// +/// Pointer to the cloned object. +/// +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsCloneObject( + _In_ JsValueRef source, + _Out_ JsValueRef* clonedObject); + +/// +/// Determines whether an object has a private property. +/// +/// +/// Requires an active script context. +/// +/// The object that may contain the property. +/// The key (JavascriptString or JavascriptSymbol) to the property. +/// Whether the object (or a prototype) has the property. +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsPrivateHasProperty( + _In_ JsValueRef object, + _In_ JsValueRef key, + _Out_ bool *hasProperty); + +/// +/// Gets an object's private property +/// +/// +/// Requires an active script context. +/// +/// The object that contains the property. +/// The key (JavascriptString or JavascriptSymbol) to the property. +/// The value of the property. +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsPrivateGetProperty( + _In_ JsValueRef object, + _In_ JsValueRef key, + _Out_ JsValueRef *value); + +/// +/// Puts an object's private property. +/// +/// +/// Requires an active script context. +/// +/// The object that contains the property. +/// The key (JavascriptString or JavascriptSymbol) to the property. +/// The new value of the property. +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsPrivateSetProperty( + _In_ JsValueRef object, + _In_ JsValueRef key, + _In_ JsValueRef value); + +/// +/// Deletes an object's private property. +/// +/// +/// Requires an active script context. +/// +/// The object that contains the property. +/// The key (JavascriptString or JavascriptSymbol) to the property. +/// Whether the property was deleted. +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsPrivateDeleteProperty( + _In_ JsValueRef object, + _In_ JsValueRef key, + _Out_ JsValueRef *result); + /// /// Gets an object's property. /// @@ -1078,6 +1362,31 @@ CHAKRA_API _In_ JsValueRef propertyDescriptor, _Out_ bool *result); +/// +/// Defines a new object's own property from a property descriptor. +/// +/// +/// Requires an active script context. +/// +/// The object that has the property. +/// The key (JavascriptString or JavascriptSymbol) to the property. +/// The property descriptor. +/// Whether the property was defined. +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsObjectDefinePropertyFull( + _In_ JsValueRef object, + _In_ JsValueRef key, + _In_opt_ JsValueRef value, + _In_opt_ JsValueRef getter, + _In_opt_ JsValueRef setter, + _In_ bool writable, + _In_ bool enumerable, + _In_ bool configurable, + _Out_ bool *result); + /// /// Deletes an object's property. /// @@ -1273,10 +1582,276 @@ CHAKRA_API _In_ JsValueRef parserState, _Out_ JsValueRef * result); +typedef void (CHAKRA_CALLBACK *JsBeforeSweepCallback)(_In_opt_ void *callbackState); + +CHAKRA_API + JsSetRuntimeBeforeSweepCallback( + _In_ JsRuntimeHandle runtimeHandle, + _In_opt_ void *callbackState, + _In_ JsBeforeSweepCallback beforeSweepCallback); + +CHAKRA_API +JsSetRuntimeDomWrapperTracingCallbacks( + _In_ JsRuntimeHandle runtimeHandle, + _In_ JsRef wrapperTracingState, + _In_ JsDOMWrapperTracingCallback wrapperTracingCallback, + _In_ JsDOMWrapperTracingDoneCallback wrapperTracingDoneCallback, + _In_ JsDOMWrapperTracingEnterFinalPauseCallback enterFinalPauseCallback); + +CHAKRA_API +JsTraceExternalReference( + _In_ JsRuntimeHandle runtimeHandle, + _In_ JsValueRef value + ); + +CHAKRA_API +JsAllocRawData( + _In_ JsRuntimeHandle runtimeHandle, + _In_ size_t sizeInBytes, + _In_ bool zeroed, + _Out_ JsRef * buffer +); + +/// +/// A callback function to ask host to re-allocated buffer to the new size when the current buffer is full +/// +/// Pointer representing state of the serializer +/// An old memory buffer, which may be null, to be reallocated +/// Request host to allocate buffer of this size +/// Actual size of the new buffer +/// +/// New buffer will be returned upon success, null otherwise. +/// +typedef byte * (CHAKRA_CALLBACK *ReallocateBufferMemoryFunc)(void* state, byte *oldBuffer, size_t newSize, size_t *allocatedSize); + +/// +/// A callback to ask host write current Host object to the serialization buffer. +/// +/// +/// A Boolean true is returned upon success, false otherwise. +/// +typedef bool (CHAKRA_CALLBACK *WriteHostObjectFunc)(void* state, void* hostObject); + +/// +/// Initialize Serialization of the object. +/// +/// A callback function to ask host to re-allocated buffer to the new size when the current buffer is full +/// A callback function to interact with host during serialization +/// A state object to pass to callback functions +/// A handle which provides various functionalities to serialize objects +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsVarSerializer( + _In_ ReallocateBufferMemoryFunc reallocateBufferMemory, + _In_ WriteHostObjectFunc writeHostObject, + _In_opt_ void * callbackState, + _Out_ JsVarSerializerHandle *serializerHandle); + +/// +/// Write raw bytes to the buffer. +/// +/// Source byte buffer +/// Length of bytes to write from source raw byte buffer +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsVarSerializerWriteRawBytes( + _In_ JsVarSerializerHandle serializerHandle, + _In_ const void* source, + _In_ size_t length); + +/// +/// A method to serialize given Javascript object to the serialization buffer +/// +/// A Javascript object to be serialized +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsVarSerializerWriteValue( + _In_ JsVarSerializerHandle serializerHandle, + _In_ JsValueRef rootObject); + +/// +/// A method to pass on the current serialized buffer (this buffer was allocated using ReallocateBufferMemory) to host. +/// +/// A buffer which holds current serialized data +/// Length of the buffer +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsVarSerializerReleaseData( + _In_ JsVarSerializerHandle serializerHandle, + _Out_ byte** data, + _Out_ size_t *dataLength); + +/// +/// Detach all array buffers which were passed using SetTransferableVars. +/// +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsVarSerializerDetachArrayBuffer(_In_ JsVarSerializerHandle serializerHandle); + +/// +/// Host provides all the objects which has transferable semantics (Such as ArrayBuffers). +/// +/// An array of transferable objects +/// Length of transferableVars array +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsVarSerializerSetTransferableVars( + _In_ JsVarSerializerHandle serializerHandle, + _In_opt_ JsValueRef *transferableVars, + _In_ size_t transferableVarsCount); + +/// +/// Free current object (which was created upon JsVarSerializer) when the serialization is done. SerializerHandleBase object should not be used further after FreeSelf call. +/// +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsVarSerializerFree(_In_ JsVarSerializerHandle serializerHandle); + +/// +/// A callback to ask host to read the current data from the serialization buffer as a Host object. +/// +/// +/// A valid host object is returned upon success, an exception is thrown otherwise. +/// +typedef JsValueRef(*ReadHostObjectFunc)(void* state); + +/// +/// A callback to ask host to retrieve SharedArrayBuffer object from given ID. +/// +/// An ID, which was provided by SerializerCallbackBase::GetSharedArrayBufferId method +/// +/// A valid SharedArrayBuffer is returned upon success, an exception is thrown otherwise. +/// +typedef JsValueRef(*GetSharedArrayBufferFromIdFunc)(void* state, uint32_t id); + +/// +/// Initiate Deserialization of the memory buffer to a Javascript object. +/// +/// A memory buffer which holds the serialized data +/// Length of the passed data in bytes +/// A callback to ask host to read the current data from the serialization buffer as a Host object. +/// A callback to ask host to retrieve SharedArrayBuffer object from given ID. +/// A callback object to interact with host during deserialization +/// A handle which provides various functionalities to deserailize a buffer to an object +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsVarDeserializer( + _In_ void *data, + _In_ size_t size, + _In_ ReadHostObjectFunc readHostObject, + _In_ GetSharedArrayBufferFromIdFunc getSharedArrayBufferFromId, + _In_opt_ void* callbackState, + _Out_ JsVarDeserializerHandle *deserializerHandle); + +/// +/// A method to read bytes from the serialized buffer. Caller should not allocate the data buffer. +/// +/// Advance current buffer's position by length +/// The data will be pointing to the raw serialized buffer +/// +/// A Boolean value true is returned upon success, false otherwise. +/// +CHAKRA_API +JsVarDeserializerReadRawBytes(_In_ JsVarDeserializerHandle deserializerHandle, _In_ size_t length, _Out_ void **data); + +/// +/// A method to read bytes from the serialized buffer. Caller must allocate data buffer by length. +/// +/// Length of data buffer +/// data buffer to be populated from the serialized buffer till the given length +/// +/// A Boolean value true is returned upon success, false otherwise. +/// +CHAKRA_API +JsVarDeserializerReadBytes(_In_ JsVarDeserializerHandle deserializerHandle, _In_ size_t length, _Out_ void **data); + +/// +/// Deserialized current buffer and pass the root object. +/// +/// +/// A valid Javascript object is returned upon success, an exception is thrown otherwise. +/// +CHAKRA_API +JsVarDeserializerReadValue(_In_ JsVarDeserializerHandle deserializerHandle, _Out_ JsValueRef* value); + +/// +/// Host provides all the objects which has transferable semantics (Such as ArrayBuffers). +/// +/// An array of transferable objects +/// Length of transferableVars array +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsVarDeserializerSetTransferableVars(_In_ JsVarDeserializerHandle deserializerHandle, _In_opt_ JsValueRef *transferableVars, _In_ size_t transferableVarsCount); + +/// +/// Free current object (which was created upon JsVarSerializer) when the serialization is done. JsVarSerializerHandle object should not be used further after FreeSelf call. +/// +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsVarDeserializerFree(_In_ JsVarDeserializerHandle deserializerHandle); + +/// +/// Extract extra info stored from an ArrayBuffer object +/// +/// An ArrayBuffer from which the extrainfor needed to extracted +/// The host information (some flags such as object externalized, detached) stored in the object +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsGetArrayBufferExtraInfo( + _In_ JsValueRef arrayBuffer, + _Out_ char *extraInfo); + +/// +/// Set Extra info (host data) to an ArrayBuffer object. +/// +/// An ArrayBuffer on which the host information will be stored +/// The host data +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsSetArrayBufferExtraInfo( + _In_ JsValueRef arrayBuffer, + _In_ char extraInfo); + +/// +/// Neuter current ArrayBuffer +/// +/// An ArrayBuffer which will be neutered +/// +/// The code JsNoError if the operation succeeded, a failure code otherwise. +/// +CHAKRA_API +JsDetachArrayBuffer( + _In_ JsValueRef arrayBuffer); + #ifdef _WIN32 #include "ChakraCoreWindows.h" #endif // _WIN32 + #endif // _CHAKRACOREBUILD #endif // _CHAKRACORE_H_ diff --git a/lib/Jsrt/ChakraCoreWindows.h b/lib/Jsrt/ChakraCoreWindows.h index 71b116baf1c..b4edfd778b3 100644 --- a/lib/Jsrt/ChakraCoreWindows.h +++ b/lib/Jsrt/ChakraCoreWindows.h @@ -10,6 +10,8 @@ #ifndef _CHAKRACOREWINDOWS_H_ #define _CHAKRACOREWINDOWS_H_ +#include + /// /// Enables out-of-process JIT by connecting to a Chakra JIT process that was initialized by calling JsInitializeJITServer /// diff --git a/lib/Jsrt/Core/CMakeLists.txt b/lib/Jsrt/Core/CMakeLists.txt index a8b38c3d095..b707163adef 100644 --- a/lib/Jsrt/Core/CMakeLists.txt +++ b/lib/Jsrt/Core/CMakeLists.txt @@ -10,5 +10,6 @@ target_include_directories ( ../../Runtime ../../Runtime/ByteCode ../../Parser + ../../SCACore ../ ) diff --git a/lib/Jsrt/Core/Chakra.Jsrt.Core.vcxproj b/lib/Jsrt/Core/Chakra.Jsrt.Core.vcxproj index b87c054e19a..fff7742db1f 100644 --- a/lib/Jsrt/Core/Chakra.Jsrt.Core.vcxproj +++ b/lib/Jsrt/Core/Chakra.Jsrt.Core.vcxproj @@ -29,6 +29,7 @@ $(MSBuildThisFileDirectory)..\..\Runtime\ByteCode; $(MSBuildThisFileDirectory)..\..\Common; $(MSBuildThisFileDirectory)..\..\Parser; + $(MSBuildThisFileDirectory)..\..\SCACore; $(MSBuildThisFileDirectory)..\..\WasmReader; $(MSBuildThisFileDirectory)..\..\Backend; %(AdditionalIncludeDirectories) diff --git a/lib/Jsrt/Core/JsrtContextCore.cpp b/lib/Jsrt/Core/JsrtContextCore.cpp index 5fb1a17006a..cde48fa4417 100644 --- a/lib/Jsrt/Core/JsrtContextCore.cpp +++ b/lib/Jsrt/Core/JsrtContextCore.cpp @@ -4,6 +4,7 @@ //------------------------------------------------------------------------------------------------------- #include "Runtime.h" #include "JsrtContext.h" +#include "SCACorePch.h" #include "JsrtContextCore.h" JsrtContext *JsrtContext::New(JsrtRuntime * runtime) @@ -158,3 +159,141 @@ HRESULT ChakraCoreHostScriptContext::NotifyHostAboutModuleReady(Js::ModuleRecord return E_INVALIDARG; } +ChakraCoreStreamWriter::~ChakraCoreStreamWriter() +{ + HeapDelete(m_serializerCore); +} + +byte * ChakraCoreStreamWriter::ExtendBuffer(byte *oldBuffer, size_t newSize, size_t *allocatedSize) +{ + m_data = this->reallocateBufferMemory(this->callbackState, oldBuffer, newSize, allocatedSize); + m_length = newSize; + + if (m_data == nullptr) + { + // free(m_data); + OutOfMemory_unrecoverable_error(); + } + return m_data; +} + +bool ChakraCoreStreamWriter::WriteHostObject(void* data) +{ + return this->writeHostObject(this->callbackState, data); +} + +void ChakraCoreStreamWriter::SetSerializer(Js::SCACore::Serializer *s) +{ + m_serializerCore = s; +} + +void ChakraCoreStreamWriter::WriteRawBytes(const void* source, size_t length) +{ + Assert(m_serializerCore); + m_serializerCore->WriteRawBytes(source, length); +} + +bool ChakraCoreStreamWriter::WriteValue(JsValueRef root) +{ + Assert(m_serializerCore); + return m_serializerCore->WriteValue((Js::Var)root); +} + +bool ChakraCoreStreamWriter::ReleaseData(byte** data, size_t *dataLength) +{ + if (m_data) + { + Assert(m_serializerCore); + return m_serializerCore->Release(data, dataLength); + } + return false; +} + +bool ChakraCoreStreamWriter::DetachArrayBuffer() +{ + Assert(m_serializerCore); + return m_serializerCore->DetachArrayBuffer(); +} + +JsErrorCode ChakraCoreStreamWriter::SetTransferableVars(JsValueRef *transferableVars, size_t transferableVarsCount) +{ + Assert(m_serializerCore); + HRESULT hr = m_serializerCore->SetTransferableVars((Js::Var *)transferableVars, transferableVarsCount); + if (hr == S_OK) + { + return JsNoError; + } + else if (hr == E_SCA_TRANSFERABLE_UNSUPPORTED) + { + return JsTransferableNotSupported; + } + else if (hr == E_SCA_TRANSFERABLE_NEUTERED) + { + return JsTransferableAlreadyDetached; + } + return JsSerializerNotSupported; +} + +void ChakraCoreStreamWriter::FreeSelf() +{ + HeapDelete(this); +} + +ChakraHostDeserializerHandle::~ChakraHostDeserializerHandle() +{ + HeapDelete(m_deserializer); +} + +void ChakraHostDeserializerHandle::SetDeserializer(Js::SCACore::Deserializer *deserializer) +{ + m_deserializer = deserializer; +} + +bool ChakraHostDeserializerHandle::ReadRawBytes(size_t length, void **data) +{ + Assert(m_deserializer); + return m_deserializer->ReadRawBytes(length, data); +} + +bool ChakraHostDeserializerHandle::ReadBytes(size_t length, void **data) +{ + Assert(m_deserializer); + return m_deserializer->ReadBytes(length, data); +} + +JsValueRef ChakraHostDeserializerHandle::ReadValue() +{ + Assert(m_deserializer); + return m_deserializer->ReadValue(); +} + +JsErrorCode ChakraHostDeserializerHandle::SetTransferableVars(JsValueRef *transferableVars, size_t transferableVarsCount) +{ + Assert(m_deserializer); + HRESULT hr = m_deserializer->SetTransferableVars((Js::Var *)transferableVars, transferableVarsCount); + if (hr == S_OK) + { + return JsNoError; + } + else if (hr == E_SCA_TRANSFERABLE_UNSUPPORTED) + { + return JsTransferableNotSupported; + } + else if (hr == E_SCA_TRANSFERABLE_NEUTERED) + { + return JsTransferableAlreadyDetached; + } + return JsSerializerNotSupported; +} + + +void ChakraHostDeserializerHandle::FreeSelf() +{ + HeapDelete(this); +} + +Js::Var ChakraHostDeserializerHandle::ReadHostObject() +{ + return (Js::Var)this->readHostObject(this->callbackState); +} + diff --git a/lib/Jsrt/Core/JsrtContextCore.h b/lib/Jsrt/Core/JsrtContextCore.h index bd79bc5ea07..4c50e50582e 100644 --- a/lib/Jsrt/Core/JsrtContextCore.h +++ b/lib/Jsrt/Core/JsrtContextCore.h @@ -7,6 +7,15 @@ #include "JsrtRuntime.h" class ChakraCoreHostScriptContext; +namespace Js +{ + namespace SCACore + { + class Serializer; + class Deserializer; + } +} + class JsrtContextCore sealed : public JsrtContext { public: @@ -24,6 +33,69 @@ class JsrtContextCore sealed : public JsrtContext FieldNoBarrier(ChakraCoreHostScriptContext*) hostContext; }; +class ChakraCoreStreamWriter : public HostStream +{ + Js::SCACore::Serializer *m_serializerCore; + byte* m_data; + size_t m_length; + + ReallocateBufferMemoryFunc reallocateBufferMemory; + WriteHostObjectFunc writeHostObject; + void * callbackState; +public: + ChakraCoreStreamWriter(ReallocateBufferMemoryFunc reallocateBufferMemory, WriteHostObjectFunc writeHostObject, void * callbackState) : + reallocateBufferMemory(reallocateBufferMemory), + writeHostObject(writeHostObject), + callbackState(callbackState), + m_data(nullptr), + m_length(0), + m_serializerCore(nullptr) + { + } + + ~ChakraCoreStreamWriter(); + + void SetSerializer(Js::SCACore::Serializer *s); + + void WriteRawBytes(const void* source, size_t length); + bool WriteValue(JsValueRef root); + bool ReleaseData(byte** data, size_t *dataLength); + bool DetachArrayBuffer(); + JsErrorCode SetTransferableVars(JsValueRef *transferableVars, size_t transferableVarsCount); + void FreeSelf(); + + virtual bool WriteHostObject(void* data) override; + virtual byte * ExtendBuffer(byte *oldBuffer, size_t newSize, size_t *allocatedSize) override; +}; + +class ChakraHostDeserializerHandle : public HostReadStream +{ + Js::SCACore::Deserializer *m_deserializer; + ReadHostObjectFunc readHostObject; + GetSharedArrayBufferFromIdFunc getSharedArrayBufferFromId; + void* callbackState; + +public: + ChakraHostDeserializerHandle(ReadHostObjectFunc readHostObject, GetSharedArrayBufferFromIdFunc getSharedArrayBufferFromId, void* callbackState) : + readHostObject(readHostObject), + getSharedArrayBufferFromId(getSharedArrayBufferFromId), + callbackState(callbackState), + m_deserializer(nullptr) + { } + + ~ChakraHostDeserializerHandle(); + + void SetDeserializer(Js::SCACore::Deserializer *deserializer); + bool ReadRawBytes(size_t length, void **data); + virtual bool ReadBytes(size_t length, void **data); + virtual JsErrorCode SetTransferableVars(JsValueRef *transferableVars, size_t transferableVarsCount); + JsValueRef ReadValue(); + void FreeSelf(); + + virtual Js::Var ReadHostObject() override; + +}; + class ChakraCoreHostScriptContext sealed : public HostScriptContext { public: @@ -161,6 +233,13 @@ class ChakraCoreHostScriptContext sealed : public HostScriptContext return nullptr; } + HRESULT ThrowIfFailed(HRESULT hr) override + { + hr; + // No support yet + return S_OK; + } + HRESULT EnqueuePromiseTask(Js::Var taskVar) override { return E_NOTIMPL; @@ -195,3 +274,6 @@ class ChakraCoreHostScriptContext sealed : public HostScriptContext FetchImportedModuleFromScriptCallBack fetchImportedModuleFromScriptCallback; NotifyModuleReadyCallback notifyModuleReadyCallback; }; + + + diff --git a/lib/Jsrt/Core/JsrtCore.cpp b/lib/Jsrt/Core/JsrtCore.cpp index 19d75321f07..11c772e70a9 100644 --- a/lib/Jsrt/Core/JsrtCore.cpp +++ b/lib/Jsrt/Core/JsrtCore.cpp @@ -4,10 +4,20 @@ //------------------------------------------------------------------------------------------------------- #include "JsrtPch.h" #include "JsrtInternal.h" +#include "JsrtExternalObject.h" +#include "JsrtExternalArrayBuffer.h" #include "jsrtHelper.h" +#include "SCACorePch.h" #include "JsrtContextCore.h" #include "ChakraCore.h" +#include "Common/ByteSwap.h" +#include "Library/DataView.h" +#include "Library/JavascriptExceptionMetadata.h" +#include "Base/ThreadContextTlsEntry.h" +#include "Library/JavascriptPromise.h" +#include "Codex/Utf8Helper.h" + CHAKRA_API JsInitializeModuleRecord( _In_opt_ JsModuleRecord referencingModule, @@ -255,3 +265,1181 @@ CHAKRA_API JsGetModuleNamespace(_In_ JsModuleRecord requestModule, _Outptr_resul *moduleNamespace = static_cast(moduleRecord->GetNamespace()); return JsNoError; } + +CHAKRA_API +JsVarSerializer( + _In_ ReallocateBufferMemoryFunc reallocateBufferMemory, + _In_ WriteHostObjectFunc writeHostObject, + _In_opt_ void * callbackState, + _Out_ JsVarSerializerHandle *serializerHandle) +{ + PARAM_NOT_NULL(reallocateBufferMemory); + PARAM_NOT_NULL(writeHostObject); + PARAM_NOT_NULL(serializerHandle); + JsErrorCode errorCode = ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + + ChakraCoreStreamWriter *writer = HeapNew(ChakraCoreStreamWriter, reallocateBufferMemory, writeHostObject, callbackState); + writer->SetSerializer(HeapNew(Js::SCACore::Serializer, scriptContext, writer)); + *serializerHandle = writer; + return JsNoError; + }); + + return errorCode; + +} + +CHAKRA_API +JsVarSerializerWriteRawBytes( + _In_ JsVarSerializerHandle serializerHandle, + _In_ const void* source, + _In_ size_t length) +{ + PARAM_NOT_NULL(serializerHandle); + PARAM_NOT_NULL(source); + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + ChakraCoreStreamWriter* streamWriter = reinterpret_cast(serializerHandle); + streamWriter->WriteRawBytes(source, length); + return JsNoError; + }); +} + +CHAKRA_API +JsVarSerializerWriteValue( + _In_ JsVarSerializerHandle serializerHandle, + _In_ JsValueRef rootObject) +{ + PARAM_NOT_NULL(serializerHandle); + PARAM_NOT_NULL(rootObject); + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + ChakraCoreStreamWriter* streamWriter = reinterpret_cast(serializerHandle); + streamWriter->WriteValue(rootObject); + return JsNoError; + }); +} + +CHAKRA_API +JsVarSerializerReleaseData( + _In_ JsVarSerializerHandle serializerHandle, + _Out_ byte** data, + _Out_ size_t *dataLength) +{ + PARAM_NOT_NULL(serializerHandle); + PARAM_NOT_NULL(data); + PARAM_NOT_NULL(dataLength); + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + ChakraCoreStreamWriter* streamWriter = reinterpret_cast(serializerHandle); + if (!streamWriter->ReleaseData(data, dataLength)) + { + return JsErrorInvalidArgument; + } + return JsNoError; + }); +} + +CHAKRA_API +JsVarSerializerDetachArrayBuffer(_In_ JsVarSerializerHandle serializerHandle) +{ + PARAM_NOT_NULL(serializerHandle); + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + ChakraCoreStreamWriter* streamWriter = reinterpret_cast(serializerHandle); + if (!streamWriter->DetachArrayBuffer()) + { + return JsErrorInvalidArgument; + } + return JsNoError; + }); +} + +CHAKRA_API +JsVarSerializerSetTransferableVars( + _In_ JsVarSerializerHandle serializerHandle, + _In_opt_ JsValueRef *transferableVars, + _In_ size_t transferableVarsCount) +{ + PARAM_NOT_NULL(serializerHandle); + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + ChakraCoreStreamWriter* streamWriter = reinterpret_cast(serializerHandle); + return streamWriter->SetTransferableVars(transferableVars, transferableVarsCount); + }); + +} + +CHAKRA_API +JsVarSerializerFree(_In_ JsVarSerializerHandle serializerHandle) +{ + PARAM_NOT_NULL(serializerHandle); + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + ChakraCoreStreamWriter* streamWriter = reinterpret_cast(serializerHandle); + streamWriter->FreeSelf(); + return JsNoError; + }); +} + +CHAKRA_API +JsVarDeserializer( + _In_ void *data, + _In_ size_t size, + _In_ ReadHostObjectFunc readHostObject, + _In_ GetSharedArrayBufferFromIdFunc getSharedArrayBufferFromId, + _In_opt_ void* callbackState, + _Out_ JsVarDeserializerHandle *deserializerHandle) +{ + PARAM_NOT_NULL(data); + PARAM_NOT_NULL(readHostObject); + PARAM_NOT_NULL(getSharedArrayBufferFromId); + PARAM_NOT_NULL(deserializerHandle); + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + ChakraHostDeserializerHandle *reader = HeapNew(ChakraHostDeserializerHandle, readHostObject, getSharedArrayBufferFromId, callbackState); + reader->SetDeserializer(HeapNew(Js::SCACore::Deserializer, data, size, scriptContext, reader)); + *deserializerHandle = reader; + return JsNoError; + }); +} + +CHAKRA_API +JsVarDeserializerReadRawBytes(_In_ JsVarDeserializerHandle deserializerHandle, _In_ size_t length, _Out_ void **data) +{ + PARAM_NOT_NULL(deserializerHandle); + PARAM_NOT_NULL(data); + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + ChakraHostDeserializerHandle* deserializer = reinterpret_cast(deserializerHandle); + if (!deserializer->ReadRawBytes(length, data)) + { + return JsErrorInvalidArgument; + } + return JsNoError; + }); +} + +CHAKRA_API +JsVarDeserializerReadBytes(_In_ JsVarDeserializerHandle deserializerHandle, _In_ size_t length, _Out_ void **data) +{ + PARAM_NOT_NULL(deserializerHandle); + PARAM_NOT_NULL(data); + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + ChakraHostDeserializerHandle* deserializer = reinterpret_cast(deserializerHandle); + if (!deserializer->ReadBytes(length, data)) + { + return JsErrorInvalidArgument; + } + return JsNoError; + }); +} + +CHAKRA_API +JsVarDeserializerReadValue(_In_ JsVarDeserializerHandle deserializerHandle, _Out_ JsValueRef* value) +{ + PARAM_NOT_NULL(deserializerHandle); + PARAM_NOT_NULL(value); + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + ChakraHostDeserializerHandle* deserializer = reinterpret_cast(deserializerHandle); + *value = deserializer->ReadValue(); + return JsNoError; + }); +} + +CHAKRA_API +JsVarDeserializerSetTransferableVars(_In_ JsVarDeserializerHandle deserializerHandle, _In_opt_ JsValueRef *transferableVars, _In_ size_t transferableVarsCount) +{ + PARAM_NOT_NULL(deserializerHandle); + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + ChakraHostDeserializerHandle* deserializer = reinterpret_cast(deserializerHandle); + return deserializer->SetTransferableVars(transferableVars, transferableVarsCount); + }); +} + +CHAKRA_API +JsVarDeserializerFree(_In_ JsVarDeserializerHandle deserializerHandle) +{ + PARAM_NOT_NULL(deserializerHandle); + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + ChakraHostDeserializerHandle* deserializer = reinterpret_cast(deserializerHandle); + deserializer->FreeSelf(); + return JsNoError; + }); +} + +CHAKRA_API +JsGetArrayBufferExtraInfo( + _In_ JsValueRef arrayBuffer, + _Out_ char *extraInfo) +{ + VALIDATE_JSREF(arrayBuffer); + PARAM_NOT_NULL(extraInfo); + BEGIN_JSRT_NO_EXCEPTION + { + if (!Js::VarIs(arrayBuffer)) + { + RETURN_NO_EXCEPTION(JsErrorInvalidArgument); + } + + *extraInfo = Js::VarTo(arrayBuffer)->GetExtraInfoBits(); + } + END_JSRT_NO_EXCEPTION + +} + +CHAKRA_API +JsSetArrayBufferExtraInfo( + _In_ JsValueRef arrayBuffer, + _In_ char extraInfo) +{ + VALIDATE_JSREF(arrayBuffer); + BEGIN_JSRT_NO_EXCEPTION + { + if (!Js::VarIs(arrayBuffer)) + { + RETURN_NO_EXCEPTION(JsErrorInvalidArgument); + } + + Js::VarTo(arrayBuffer)->SetExtraInfoBits(extraInfo); + } + END_JSRT_NO_EXCEPTION +} + +CHAKRA_API +JsDetachArrayBuffer( + _In_ JsValueRef arrayBuffer) +{ + VALIDATE_JSREF(arrayBuffer); + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + + if (!Js::VarIs(arrayBuffer)) + { + return JsErrorInvalidArgument; + } + + Js::VarTo(arrayBuffer)->Detach(); + return JsNoError; + }); +} + +CHAKRA_API JsCreateSharedArrayBufferWithSharedContent(_In_ JsSharedArrayBufferContentHandle sharedContents, _Out_ JsValueRef *result) +{ + return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + + PARAM_NOT_NULL(result); + + Js::JavascriptLibrary* library = scriptContext->GetLibrary(); + *result = library->CreateSharedArrayBuffer((Js::SharedContents*)sharedContents); + + PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result); + + JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(*result)); + return JsNoError; + }); +} + +CHAKRA_API JsGetSharedArrayBufferContent(_In_ JsValueRef sharedArrayBuffer, _Out_ JsSharedArrayBufferContentHandle *sharedContents) +{ + return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + + PARAM_NOT_NULL(sharedContents); + + if (!Js::VarIs(sharedArrayBuffer)) + { + return JsErrorInvalidArgument; + } + + Js::SharedContents**& content = (Js::SharedContents**&)sharedContents; + *content = Js::VarTo(sharedArrayBuffer)->GetSharedContents(); + + if (*content == nullptr) + { + return JsErrorFatal; + } + + (*content)->AddRef(); + + return JsNoError; + }); +} + +CHAKRA_API JsReleaseSharedArrayBufferContentHandle(_In_ JsSharedArrayBufferContentHandle sharedContents) +{ + return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + ((Js::SharedContents*)sharedContents)->Release(); + return JsNoError; + }); +} + +CHAKRA_API JsCreateCustomExternalObject( + _In_opt_ void *data, + _In_opt_ size_t inlineSlotSize, + _In_opt_ JsTraceCallback traceCallback, + _In_opt_ JsFinalizeCallback finalizeCallback, + _Inout_opt_ JsGetterSetterInterceptor ** getterSetterInterceptor, + _In_opt_ JsValueRef prototype, + _Out_ JsValueRef * object) +{ + return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateExternalObject, prototype); + + PARAM_NOT_NULL(object); + + Js::RecyclableObject * prototypeObject = nullptr; + if (prototype != JS_INVALID_REFERENCE) + { + VALIDATE_INCOMING_OBJECT_OR_NULL(prototype, scriptContext); + prototypeObject = Js::VarTo(prototype); + } + if (inlineSlotSize > UINT32_MAX) + { + return JsErrorInvalidArgument; + } + + Js::JsGetterSetterInterceptor * interceptor = nullptr; + *object = Js::CustomExternalWrapperObject::Create(data, (uint)inlineSlotSize, traceCallback, finalizeCallback, &interceptor, prototypeObject, scriptContext); + Assert(interceptor); + *getterSetterInterceptor = reinterpret_cast(interceptor); + + PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, object); + + return JsNoError; + }); +} + +CHAKRA_API JsCreateTracedExternalObject( + _In_opt_ void *data, + _In_opt_ size_t inlineSlotSize, + _In_opt_ JsTraceCallback traceCallback, + _In_opt_ JsFinalizeCallback finalizeCallback, + _In_opt_ JsValueRef prototype, + _Out_ JsValueRef *object) +{ + return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateExternalObject, prototype); + + PARAM_NOT_NULL(object); + + Js::RecyclableObject * prototypeObject = nullptr; + if (prototype != JS_INVALID_REFERENCE) + { + VALIDATE_INCOMING_OBJECT_OR_NULL(prototype, scriptContext); + prototypeObject = Js::VarTo(prototype); + } + if (inlineSlotSize > UINT32_MAX) + { + return JsErrorInvalidArgument; + } + *object = JsrtExternalObject::Create(data, (uint)inlineSlotSize, traceCallback, finalizeCallback, prototypeObject, scriptContext, nullptr); + + PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, object); + + return JsNoError; + }); +} + +CHAKRA_API JsPrivateHasProperty( + _In_ JsValueRef object, + _In_ JsValueRef key, + _Out_ bool *hasProperty) +{ + return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext); + + VALIDATE_INCOMING_OBJECT(object, scriptContext); + VALIDATE_INCOMING_REFERENCE(key, scriptContext); + PARAM_NOT_NULL(hasProperty); + *hasProperty = false; + + Js::DynamicObject* dynObj = Js::VarTo(object); + if (!dynObj->HasObjectArray()) + { + return JsNoError; + } + *hasProperty = Js::JavascriptOperators::OP_HasItem(dynObj->GetObjectArray(), key, scriptContext) != 0; + + return JsNoError; + }); +} + +CHAKRA_API JsPrivateGetProperty( + _In_ JsValueRef object, + _In_ JsValueRef key, + _Out_ JsValueRef *value) +{ + return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetIndex, key, object); + + VALIDATE_INCOMING_OBJECT(object, scriptContext); + VALIDATE_INCOMING_REFERENCE(key, scriptContext); + PARAM_NOT_NULL(value); + *value = nullptr; + Js::DynamicObject* dynObj = Js::VarTo(object); + + if (!dynObj->HasObjectArray()) + { + *value = scriptContext->GetLibrary()->GetUndefined(); + PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, value); + return JsNoError; + } + *value = (JsValueRef)Js::JavascriptOperators::OP_GetElementI(dynObj->GetObjectArray(), key, scriptContext); + + PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, value); + + return JsNoError; + }); +} + +CHAKRA_API JsPrivateSetProperty( + _In_ JsValueRef object, + _In_ JsValueRef key, + _In_ JsValueRef value) +{ + return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTSetIndex, object, key, value); + + VALIDATE_INCOMING_OBJECT(object, scriptContext); + VALIDATE_INCOMING_REFERENCE(key, scriptContext); + VALIDATE_INCOMING_REFERENCE(value, scriptContext); + + Js::DynamicObject* dynObj = Js::VarTo(object); + + if (!dynObj->HasObjectArray()) + { + Js::ArrayObject* objArray = scriptContext->GetLibrary()->CreateArray(); + dynObj->SetObjectArray(objArray); + } + Js::JavascriptOperators::OP_SetElementI(dynObj->GetObjectArray(), key, value, scriptContext); + + return JsNoError; + }); +} + +CHAKRA_API JsPrivateDeleteProperty( + _In_ JsValueRef object, + _In_ JsValueRef key, + _Out_ JsValueRef *result) +{ + return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext); + + VALIDATE_INCOMING_OBJECT(object, scriptContext); + VALIDATE_INCOMING_REFERENCE(key, scriptContext); + + Js::DynamicObject* dynObj = Js::VarTo(object); + if (!dynObj->HasObjectArray()) + { + *result = scriptContext->GetLibrary()->GetFalse(); + return JsNoError; + } + *result = Js::JavascriptOperators::OP_DeleteElementI(dynObj->GetObjectArray(), key, scriptContext); + + return JsNoError; + }); +} + +CHAKRA_API JsCloneObject(_In_ JsValueRef source, _Out_ JsValueRef* newObject) +{ + VALIDATE_JSREF(source); + + return ContextAPINoScriptWrapper([&](Js::ScriptContext* scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + if (Js::VarIs(source)) + { + source = Js::UnsafeVarTo(source)->GetTarget(); + } + JsrtExternalObject* externalSource = Js::JavascriptOperators::TryFromVar(source); + if (externalSource) + { + JsrtExternalType* externalType = externalSource->GetExternalType(); + JsrtExternalObject* target = JsrtExternalObject::Create( + externalSource->GetSlotData(), + externalSource->GetInlineSlotSize(), + externalType->GetJsTraceCallback(), + externalType->GetJsFinalizeCallback(), + externalSource->GetPrototype(), + scriptContext, + externalType); + bool success = target->TryCopy(externalSource, true); + AssertOrFailFast(success); + *newObject = target; + return JsNoError; + } + else + { + Js::CustomExternalWrapperObject * externalWrapper = Js::JavascriptOperators::TryFromVar(source); + if (externalWrapper != nullptr) { + Js::CustomExternalWrapperObject * target = Js::CustomExternalWrapperObject::Clone(externalWrapper, scriptContext); + Assert(target); + *newObject = target; + return JsNoError; + } + } + + Js::DynamicObject* objSource = Js::JavascriptOperators::TryFromVar(source); + if (objSource) + { + if (!objSource->ShareType()) + { + AssertOrFailFast(UNREACHED); // TODO + return JsErrorInvalidArgument; + } + *newObject = objSource->Copy(true); + return JsNoError; + } + return JsErrorInvalidArgument; + }); +} + +template +static void CastCopy(const SrcChar* src, DstChar* dst, size_t count) +{ + const SrcChar* end = src + count; + while (src < end) + { + *dst++ = static_cast(*src++); + } +} + +CHAKRA_API JsCreateString( + _In_ const char *content, + _In_ size_t length, + _Out_ JsValueRef *value) +{ + PARAM_NOT_NULL(content); + PARAM_NOT_NULL(value); + *value = JS_INVALID_REFERENCE; + + if (length == static_cast(-1)) + { + length = strlen(content); + } + + if (length > MaxCharCount) + { + return JsErrorOutOfMemory; + } + + return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + + Js::JavascriptString *stringValue = Js::LiteralStringWithPropertyStringPtr:: + NewFromCString(content, (CharCount)length, scriptContext->GetLibrary()); + + PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateString, stringValue->GetSz(), stringValue->GetLength()); + + *value = stringValue; + + PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, value); + + return JsNoError; + }); +} + +CHAKRA_API JsCreateStringUtf16( + _In_ const uint16_t *content, + _In_ size_t length, + _Out_ JsValueRef *value) +{ + PARAM_NOT_NULL(content); + PARAM_NOT_NULL(value); + *value = JS_INVALID_REFERENCE; + + if (length == static_cast(-1)) + { + length = wcslen((const char16 *)content); + } + + if (length > static_cast(-1)) + { + return JsErrorOutOfMemory; + } + + return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + + Js::JavascriptString *stringValue = Js::LiteralStringWithPropertyStringPtr:: + NewFromWideString((const char16 *)content, (CharCount)length, scriptContext->GetLibrary()); + + PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateString, stringValue->GetSz(), stringValue->GetLength()); + + *value = stringValue; + + PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, value); + + return JsNoError; + }); +} + + +CHAKRA_API JsCreatePropertyString( + _In_z_ const char *name, + _In_ size_t length, + _Out_ JsValueRef *propertyString) +{ + return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext); + Js::PropertyRecord* propertyRecord; + JsErrorCode errorCode = JsCreatePropertyId(name, length, (JsPropertyIdRef *)&propertyRecord); + + if (errorCode != JsNoError) + { + return errorCode; + } + + *propertyString = scriptContext->GetPropertyString(propertyRecord); + return JsNoError; + }); +} + +CHAKRA_API JsCreatePromise(_Out_ JsValueRef *promise, _Out_ JsValueRef *resolve, _Out_ JsValueRef *reject) +{ + return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext); + + PARAM_NOT_NULL(promise); + PARAM_NOT_NULL(resolve); + PARAM_NOT_NULL(reject); + + *promise = nullptr; + *resolve = nullptr; + *reject = nullptr; + + Js::JavascriptPromiseResolveOrRejectFunction *jsResolve = nullptr; + Js::JavascriptPromiseResolveOrRejectFunction *jsReject = nullptr; + Js::JavascriptPromise *jsPromise = scriptContext->GetLibrary()->CreatePromise(); + Js::JavascriptPromise::InitializePromise(jsPromise, &jsResolve, &jsReject, scriptContext); + + *promise = (JsValueRef)jsPromise; + *resolve = (JsValueRef)jsResolve; + *reject = (JsValueRef)jsReject; + + return JsNoError; + }); +} + +CHAKRA_API JsGetPromiseState(_In_ JsValueRef promise, _Out_ JsPromiseState *state) +{ + return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext); + + VALIDATE_INCOMING_REFERENCE(promise, scriptContext); + PARAM_NOT_NULL(state); + + *state = JsPromiseStatePending; + + if (!Js::VarIs(promise)) + { + return JsErrorInvalidArgument; + } + + Js::JavascriptPromise *jsPromise = Js::VarTo(promise); + Js::JavascriptPromise::PromiseStatus status = jsPromise->GetStatus(); + + switch (status) + { + case Js::JavascriptPromise::PromiseStatus::PromiseStatusCode_HasRejection: + *state = JsPromiseStateRejected; + break; + + case Js::JavascriptPromise::PromiseStatus::PromiseStatusCode_HasResolution: + *state = JsPromiseStateFulfilled; + break; + } + + return JsNoError; + }); +} + +CHAKRA_API JsGetPromiseResult(_In_ JsValueRef promise, _Out_ JsValueRef *result) +{ + return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext); + + VALIDATE_INCOMING_REFERENCE(promise, scriptContext); + PARAM_NOT_NULL(result); + + *result = JS_INVALID_REFERENCE; + + if (!Js::VarIs(promise)) + { + return JsErrorInvalidArgument; + } + + Js::JavascriptPromise *jsPromise = Js::VarTo(promise); + Js::Var jsResult = jsPromise->GetResult(); + + if (jsResult == nullptr) + { + return JsErrorPromisePending; + } + + *result = (JsValueRef)jsResult; + return JsNoError; + }); +} + +CHAKRA_API JsCreateWeakReference( + _In_ JsValueRef value, + _Out_ JsWeakRef* weakRef) +{ + VALIDATE_JSREF(value); + PARAM_NOT_NULL(weakRef); + *weakRef = nullptr; + + if (Js::TaggedNumber::Is(value)) + { + return JsNoWeakRefRequired; + } + + return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode { + ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread(); + if (threadContext == nullptr) + { + return JsErrorNoCurrentContext; + } + + Recycler* recycler = threadContext->GetRecycler(); + if (recycler->IsInObjectBeforeCollectCallback()) + { + return JsErrorInObjectBeforeCollectCallback; + } + + RecyclerHeapObjectInfo dummyObjectInfo; + if (!recycler->FindHeapObject(value, Memory::FindHeapObjectFlags::FindHeapObjectFlags_NoFlags, dummyObjectInfo)) + { + // value is not recyler-allocated + return JsErrorInvalidArgument; + } + + recycler->FindOrCreateWeakReferenceHandle( + reinterpret_cast(value), + reinterpret_cast**>(weakRef)); + return JsNoError; + }); +} + +CHAKRA_API JsGetWeakReferenceValue( + _In_ JsWeakRef weakRef, + _Out_ JsValueRef* value) +{ + VALIDATE_JSREF(weakRef); + PARAM_NOT_NULL(value); + *value = JS_INVALID_REFERENCE; + + return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode { + Memory::RecyclerWeakReference* recyclerWeakReference = + reinterpret_cast*>(weakRef); + *value = reinterpret_cast(recyclerWeakReference->Get()); + return JsNoError; + }); +} + +CHAKRA_API JsGetAndClearExceptionWithMetadata(_Out_ JsValueRef *metadata) +{ + PARAM_NOT_NULL(metadata); + *metadata = nullptr; + + JsrtContext *currentContext = JsrtContext::GetCurrent(); + + if (currentContext == nullptr) + { + return JsErrorNoCurrentContext; + } + + Js::ScriptContext *scriptContext = currentContext->GetScriptContext(); + Assert(scriptContext != nullptr); + + if (scriptContext->GetRecycler() && scriptContext->GetRecycler()->IsHeapEnumInProgress()) + { + return JsErrorHeapEnumInProgress; + } + else if (scriptContext->GetThreadContext()->IsInThreadServiceCallback()) + { + return JsErrorInThreadServiceCallback; + } + + if (scriptContext->GetThreadContext()->IsExecutionDisabled()) + { + return JsErrorInDisabledState; + } + + HRESULT hr = S_OK; + Js::JavascriptExceptionObject *recordedException = nullptr; + + BEGIN_TRANSLATE_OOM_TO_HRESULT + if (scriptContext->HasRecordedException()) + { + recordedException = scriptContext->GetAndClearRecordedException(); + } + END_TRANSLATE_OOM_TO_HRESULT(hr) + + if (hr == E_OUTOFMEMORY) + { + recordedException = scriptContext->GetThreadContext()->GetRecordedException(); + } + if (recordedException == nullptr) + { + return JsErrorInvalidArgument; + } + + Js::Var exception = recordedException->GetThrownObject(nullptr); + + if (exception == nullptr) + { + // TODO: How does this early bailout impact TTD? + return JsErrorInvalidArgument; + } + + return ContextAPIWrapper([&](Js::ScriptContext* scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + Js::Var exceptionMetadata = Js::JavascriptExceptionMetadata::CreateMetadataVar(scriptContext); + Js::JavascriptOperators::OP_SetProperty(exceptionMetadata, Js::PropertyIds::exception, exception, scriptContext); + + Js::FunctionBody *functionBody = recordedException->GetFunctionBody(); + if (functionBody == nullptr) + { + // This is probably a parse error. We can get the error location metadata from the thrown object. + Js::JavascriptExceptionMetadata::PopulateMetadataFromCompileException(exceptionMetadata, exception, scriptContext); + } + else + { + if (!Js::JavascriptExceptionMetadata::PopulateMetadataFromException(exceptionMetadata, recordedException, scriptContext)) + { + return JsErrorInvalidArgument; + } + } + + *metadata = exceptionMetadata; + +#if ENABLE_TTD + if (hr != E_OUTOFMEMORY) + { + PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetAndClearExceptionWithMetadata); + PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, metadata); + } +#endif + + + return JsNoError; + }); +} + +CHAKRA_API JsGetDataViewInfo( + _In_ JsValueRef dataView, + _Out_opt_ JsValueRef *arrayBuffer, + _Out_opt_ unsigned int *byteOffset, + _Out_opt_ unsigned int *byteLength) +{ + VALIDATE_JSREF(dataView); + + BEGIN_JSRT_NO_EXCEPTION + { + if (!Js::VarIs(dataView)) + { + RETURN_NO_EXCEPTION(JsErrorInvalidArgument); + } + + Js::DataView* dv = Js::VarTo(dataView); + if (arrayBuffer != nullptr) { + *arrayBuffer = dv->GetArrayBuffer(); + } + + if (byteOffset != nullptr) { + *byteOffset = dv->GetByteOffset(); + } + + if (byteLength != nullptr) { + *byteLength = dv->GetLength(); + } + } + +#if ENABLE_TTD + Js::ScriptContext* scriptContext = Js::VarTo(dataView)->GetScriptContext(); + if (PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext) && arrayBuffer != nullptr) + { + scriptContext->GetThreadContext()->TTDLog->RecordJsRTGetDataViewInfo(dataView, *arrayBuffer); + } +#endif + + END_JSRT_NO_EXCEPTION +} + +CHAKRA_API JsSetHostPromiseRejectionTracker(_In_ JsHostPromiseRejectionTrackerCallback promiseRejectionTrackerCallback, _In_opt_ void *callbackState) +{ + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + scriptContext->GetLibrary()->SetNativeHostPromiseRejectionTrackerCallback((Js::JavascriptLibrary::HostPromiseRejectionTrackerCallback) promiseRejectionTrackerCallback, callbackState); + return JsNoError; + }, + /*allowInObjectBeforeCollectCallback*/true); +} + +CHAKRA_API JsGetProxyProperties(_In_ JsValueRef object, _Out_ bool* isProxy, _Out_opt_ JsValueRef* target, _Out_opt_ JsValueRef* handler) +{ + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext * scriptContext) -> JsErrorCode { + VALIDATE_INCOMING_REFERENCE(object, scriptContext); + PARAM_NOT_NULL(isProxy); + + if (target != nullptr) + { + *target = JS_INVALID_REFERENCE; + } + + if (handler != nullptr) + { + *handler = JS_INVALID_REFERENCE; + } + + *isProxy = Js::VarIs(object); + + if (!*isProxy) + { + return JsNoError; + } + + Js::JavascriptProxy* proxy = Js::UnsafeVarTo(object); + bool revoked = proxy->IsRevoked(); + + if (target != nullptr && !revoked) + { + *target = static_cast(proxy->GetTarget()); + } + + if (handler != nullptr && !revoked) + { + *handler = static_cast(proxy->GetHandler()); + } + + return JsNoError; + }, + /*allowInObjectBeforeCollectCallback*/true); +} + +CHAKRA_API JsSetRuntimeBeforeSweepCallback(_In_ JsRuntimeHandle runtimeHandle, _In_opt_ void *callbackState, _In_ JsBeforeSweepCallback beforeSweepCallback) +{ + return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode { + VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle); + + JsrtRuntime::FromHandle(runtimeHandle)->SetBeforeSweepCallback(beforeSweepCallback, callbackState); + return JsNoError; + }); +} + +CHAKRA_API +JsSetRuntimeDomWrapperTracingCallbacks( + _In_ JsRuntimeHandle runtimeHandle, + _In_ JsRef wrapperTracingState, + _In_ JsDOMWrapperTracingCallback wrapperTracingCallback, + _In_ JsDOMWrapperTracingDoneCallback wrapperTracingDoneCallback, + _In_ JsDOMWrapperTracingEnterFinalPauseCallback enterFinalPauseCallback) +{ + return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode { + VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle); + + ThreadContext * threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext(); + ThreadContextScope scope(threadContext); + + if (!scope.IsValid()) + { + return JsErrorWrongThread; + } + + Recycler * recycler = threadContext->GetRecycler(); + recycler->SetDOMWrapperTracingCallback(wrapperTracingState, reinterpret_cast(wrapperTracingCallback), reinterpret_cast(wrapperTracingDoneCallback), reinterpret_cast(enterFinalPauseCallback)); + return JsNoError; + }); +} + +CHAKRA_API +JsGetArrayForEachFunction(_Out_ JsValueRef * result) +{ + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + PARAM_NOT_NULL(result); + + *result = scriptContext->GetLibrary()->EnsureArrayPrototypeForEachFunction(); + + return JsNoError; + }, + /*allowInObjectBeforeCollectCallback*/true); +} + +CHAKRA_API +JsGetArrayKeysFunction(_Out_ JsValueRef * result) +{ + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + PARAM_NOT_NULL(result); + + *result = scriptContext->GetLibrary()->EnsureArrayPrototypeKeysFunction(); + + return JsNoError; + }, + /*allowInObjectBeforeCollectCallback*/true); +} + +CHAKRA_API +JsGetArrayValuesFunction(_Out_ JsValueRef * result) +{ + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + PARAM_NOT_NULL(result); + + *result = scriptContext->GetLibrary()->EnsureArrayPrototypeValuesFunction(); + + return JsNoError; + }, + /*allowInObjectBeforeCollectCallback*/true); +} + +CHAKRA_API +JsGetArrayEntriesFunction(_Out_ JsValueRef * result) +{ + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + PARAM_NOT_NULL(result); + + *result = scriptContext->GetLibrary()->EnsureArrayPrototypeEntriesFunction(); + + return JsNoError; + }, + /*allowInObjectBeforeCollectCallback*/true); +} + +CHAKRA_API +JsGetPropertyIdSymbolIterator(_Out_ JsPropertyIdRef * propertyId) +{ + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + PARAM_NOT_NULL(propertyId); + + Js::PropertyId symbolIteratorPropertyId = scriptContext->GetLibrary()->GetPropertyIdSymbolIterator(); + *propertyId = Js::JavascriptNumber::ToVar(symbolIteratorPropertyId, scriptContext); + + return JsNoError; + }, + /*allowInObjectBeforeCollectCallback*/true); +} + +CHAKRA_API +JsGetErrorPrototype(_Out_ JsValueRef * result) +{ + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + PARAM_NOT_NULL(result); + + *result = scriptContext->GetLibrary()->GetErrorPrototype(); + if (*result == JS_INVALID_REFERENCE) + { + return JsErrorFatal; + } + + return JsNoError; + }, + /*allowInObjectBeforeCollectCallback*/true); +} + +CHAKRA_API +JsGetIteratorPrototype(_Out_ JsValueRef * result) +{ + return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { + PARAM_NOT_NULL(result); + + *result = scriptContext->GetLibrary()->GetIteratorPrototype(); + if (*result == JS_INVALID_REFERENCE) + { + return JsErrorFatal; + } + + return JsNoError; + }, + /*allowInObjectBeforeCollectCallback*/true); +} + +CHAKRA_API JsTraceExternalReference(_In_ JsRuntimeHandle runtimeHandle, _In_ JsValueRef value) +{ + return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode { + VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle); + + ThreadContext * threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext(); + ThreadContextScope scope(threadContext); + + if (!scope.IsValid()) + { + return JsErrorWrongThread; + } + + Recycler * recycler = threadContext->GetRecycler(); + recycler->TryExternalMarkNonInterior(value); + return JsNoError; + }); +} + +CHAKRA_API JsAllocRawData(_In_ JsRuntimeHandle runtimeHandle, _In_ size_t sizeInBytes, _In_ bool zeroed, _Out_ JsRef * buffer) +{ + PARAM_NOT_NULL(buffer); + + return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode { + VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle); + + ThreadContext * threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext(); + ThreadContextScope scope(threadContext); + + if (!scope.IsValid()) + { + return JsErrorWrongThread; + } + + Recycler * recycler = threadContext->GetRecycler(); + if (zeroed) + { + *buffer = RecyclerNewArray(recycler, char, sizeInBytes); + } + return JsNoError; + }); +} + +CHAKRA_API JsIsConstructor(_In_ JsValueRef object, _Out_ bool *isConstructor) +{ + return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { + PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext); + VALIDATE_INCOMING_OBJECT(object, scriptContext); + PARAM_NOT_NULL(isConstructor); + + Js::RecyclableObject * instance = Js::VarTo(object); + AssertMsg(scriptContext->GetThreadContext()->IsScriptActive(), "Caller is expected to be under ContextAPIWrapper!"); + + *isConstructor = Js::JavascriptOperators::IsConstructor(instance); + + return JsNoError; + }); +} + +CHAKRA_API +JsQueueBackgroundParse_Experimental( + _In_ JsScriptContents* contents, + _Out_ DWORD* dwBgParseCookie) +{ + HRESULT hr; + if (Js::Configuration::Global.flags.BgParse && !CONFIG_FLAG(ForceDiagnosticsMode) + // For now, only UTF8 buffers are supported for BGParse + && contents->encodingType == JsScriptEncodingType::Utf8 + && contents->containerType == JsScriptContainerType::HeapAllocatedBuffer + // SourceContext not needed for BGParse + && contents->sourceContext == 0) + { + hr = BGParseManager::GetBGParseManager()->QueueBackgroundParse((LPUTF8)contents->container, contents->contentLengthInBytes, (char16*)contents->fullPath, dwBgParseCookie); + } + else + { + hr = E_NOTIMPL; + } + + JsErrorCode res = (hr == S_OK) ? JsNoError : JsErrorFatal; + + return res; +} + +CHAKRA_API +JsDiscardBackgroundParse_Experimental( + _In_ DWORD dwBgParseCookie, + _In_ void* buffer, + _Out_ bool* callerOwnsBuffer) +{ + (*callerOwnsBuffer) = BGParseManager::GetBGParseManager()->DiscardParseResults(dwBgParseCookie, buffer); + return JsNoError; +} + +#ifdef _WIN32 +CHAKRA_API +JsConnectJITProcess(_In_ HANDLE processHandle, _In_opt_ void* serverSecurityDescriptor, _In_ UUID connectionId) +{ +#ifdef ENABLE_OOP_NATIVE_CODEGEN + JITManager::GetJITManager()->EnableOOPJIT(); + ThreadContext::SetJITConnectionInfo(processHandle, serverSecurityDescriptor, connectionId); +#endif + return JsNoError; +} +#endif diff --git a/lib/Jsrt/Jsrt.cpp b/lib/Jsrt/Jsrt.cpp index c824628851e..439f17838c5 100644 --- a/lib/Jsrt/Jsrt.cpp +++ b/lib/Jsrt/Jsrt.cpp @@ -12,8 +12,6 @@ #include "ByteCode/ByteCodeSerializer.h" #include "Common/ByteSwap.h" #include "Library/DataView.h" -#include "Library/JavascriptExceptionMetadata.h" -#include "Library/JavascriptPromise.h" #include "Base/ThreadContextTlsEntry.h" #include "Codex/Utf8Helper.h" @@ -233,7 +231,7 @@ void CALLBACK CreateExternalObject_TTDCallback(Js::ScriptContext* ctx, Js::Var p prototypeObject = Js::VarTo(prototype); } - *object = JsrtExternalObject::Create(nullptr, nullptr, prototypeObject, ctx); + *object = JsrtExternalObject::Create(nullptr, 0, nullptr, prototypeObject, ctx, nullptr); } void CALLBACK TTDDummyPromiseContinuationCallback(JsValueRef task, void *callbackState) @@ -1350,7 +1348,7 @@ CHAKRA_API JsCreateExternalObjectWithPrototype(_In_opt_ void *data, prototypeObject = Js::VarTo(prototype); } - *object = JsrtExternalObject::Create(data, finalizeCallback, prototypeObject, scriptContext); + *object = JsrtExternalObject::Create(data, 0, finalizeCallback, prototypeObject, scriptContext, nullptr); PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, object); @@ -1461,10 +1459,10 @@ CHAKRA_API JsPreventExtension(_In_ JsValueRef object) } CHAKRA_API JsHasOwnPropertyCommon(Js::ScriptContext * scriptContext, _In_ JsValueRef object, - _In_ const Js::PropertyRecord * propertyRecord, _Out_ bool *hasOwnProperty) + _In_ const Js::PropertyRecord * propertyRecord, _Out_ bool *hasOwnProperty, _In_opt_ Js::PropertyString * propString) { *hasOwnProperty = Js::JavascriptOperators::OP_HasOwnProperty(object, - propertyRecord->GetPropertyId(), scriptContext) != 0; + propertyRecord->GetPropertyId(), scriptContext, propString) != 0; return JsNoError; } @@ -1472,7 +1470,7 @@ CHAKRA_API JsHasOwnPropertyCommon(Js::ScriptContext * scriptContext, _In_ JsValu CHAKRA_API JsHasOwnProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _Out_ bool *hasOwnProperty) { - return ContextAPIWrapper([&] (Js::ScriptContext *scriptContext, + return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTHasOwnProperty, (const Js::PropertyRecord *)propertyId, object); @@ -1482,7 +1480,7 @@ CHAKRA_API JsHasOwnProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propert *hasOwnProperty = false; return JsHasOwnPropertyCommon(scriptContext, object, - (const Js::PropertyRecord *)propertyId, hasOwnProperty); + (const Js::PropertyRecord *)propertyId, hasOwnProperty, nullptr); }); } @@ -1529,7 +1527,7 @@ CHAKRA_API JsObjectHasOwnProperty(_In_ JsValueRef object, _In_ JsValueRef proper return errorValue; } - return JsHasOwnPropertyCommon(scriptContext, object, propertyRecord, hasOwnProperty); + return JsHasOwnPropertyCommon(scriptContext, object, propertyRecord, hasOwnProperty, Js::VarIs(propertyId) ? (Js::PropertyString*)propertyId : nullptr); }); } #endif @@ -1747,10 +1745,19 @@ CHAKRA_API JsHasProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId { return ContextAPIWrapper(internalHasProperty); } - else +#ifdef _CHAKRACOREBUILD + else if (typeId == Js::TypeIds_Object) { - return ContextAPINoScriptWrapper(internalHasProperty); + // CEOs can also have traps so we would want the Enter/Leave semantics for those. + Js::CustomExternalWrapperObject * externalWrapper = Js::JavascriptOperators::TryFromVar(object); + if (externalWrapper) + { + return ContextAPIWrapper(internalHasProperty); + } } +#endif + + return ContextAPINoScriptWrapper(internalHasProperty); } #ifdef _CHAKRACOREBUILD @@ -1793,10 +1800,17 @@ CHAKRA_API JsObjectHasProperty(_In_ JsValueRef object, _In_ JsValueRef propertyI { return ContextAPIWrapper(internalHasProperty); } - else + else if (typeId == Js::TypeIds_Object) { - return ContextAPINoScriptWrapper(internalHasProperty); + // CEOs can also have traps so we would want the Enter/Leave semantics for those. + Js::CustomExternalWrapperObject * externalWrapper = Js::JavascriptOperators::TryFromVar(object); + if (externalWrapper) + { + return ContextAPIWrapper(internalHasProperty); + } } + + return ContextAPINoScriptWrapper(internalHasProperty); } #endif @@ -1903,6 +1917,71 @@ CHAKRA_API JsDefineProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propert } #ifdef _CHAKRACOREBUILD + +CHAKRA_API +JsObjectDefinePropertyFull( + _In_ JsValueRef object, + _In_ JsValueRef key, + _In_opt_ JsValueRef value, + _In_opt_ JsValueRef getter, + _In_opt_ JsValueRef setter, + _In_ bool writable, + _In_ bool enumerable, + _In_ bool configurable, + _Out_ bool *result) +{ + return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, + TTDRecorder& _actionEntryPopper) -> JsErrorCode { + PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext); + AssertMsg(scriptContext->GetThreadContext()->IsScriptActive(), "Caller is expected to be under ContextAPIWrapper!"); + + VALIDATE_INCOMING_OBJECT(object, scriptContext); + VALIDATE_INCOMING_RECYCLABLE(key, scriptContext); + PARAM_NOT_NULL(result); + *result = false; + + const Js::PropertyRecord *propertyRecord = nullptr; + JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext, + Js::VarTo(key), &propertyRecord); + + if (errorValue != JsNoError) + { + return errorValue; + } + + Js::PropertyDescriptor propertyDescriptor; + if (value) + { + propertyDescriptor.SetValue(value); + } + if (getter) + { + propertyDescriptor.SetGetter(getter); + } + if (setter) + { + propertyDescriptor.SetSetter(setter); + } + if (writable) + { + propertyDescriptor.SetWritable(writable); + } + if (enumerable) + { + propertyDescriptor.SetEnumerable(enumerable); + } + if (configurable) + { + propertyDescriptor.SetConfigurable(configurable); + } + + *result = Js::JavascriptOperators::DefineOwnPropertyDescriptor( + Js::VarTo(object), propertyRecord->GetPropertyId(), + propertyDescriptor, true, scriptContext) != 0; + return JsNoError; + }); +} + CHAKRA_API JsObjectDefineProperty(_In_ JsValueRef object, _In_ JsValueRef propertyId, _In_ JsValueRef propertyDescriptor, _Out_ bool *result) { @@ -1998,57 +2077,6 @@ CHAKRA_API JsCreateArrayBuffer(_In_ unsigned int byteLength, _Out_ JsValueRef *r }); } -#ifdef _CHAKRACOREBUILD -CHAKRA_API JsCreateSharedArrayBufferWithSharedContent(_In_ JsSharedArrayBufferContentHandle sharedContents, _Out_ JsValueRef *result) -{ - return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { - - PARAM_NOT_NULL(result); - - Js::JavascriptLibrary* library = scriptContext->GetLibrary(); - *result = library->CreateSharedArrayBuffer((Js::SharedContents*)sharedContents); - - PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result); - - JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(*result)); - return JsNoError; - }); -} - -CHAKRA_API JsGetSharedArrayBufferContent(_In_ JsValueRef sharedArrayBuffer, _Out_ JsSharedArrayBufferContentHandle *sharedContents) -{ - return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { - - PARAM_NOT_NULL(sharedContents); - - if (!Js::VarIs(sharedArrayBuffer)) - { - return JsErrorInvalidArgument; - } - - Js::SharedContents**& content = (Js::SharedContents**&)sharedContents; - *content = Js::VarTo(sharedArrayBuffer)->GetSharedContents(); - - if (*content == nullptr) - { - return JsErrorFatal; - } - - (*content)->AddRef(); - - return JsNoError; - }); -} - -CHAKRA_API JsReleaseSharedArrayBufferContentHandle(_In_ JsSharedArrayBufferContentHandle sharedContents) -{ - return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { - ((Js::SharedContents*)sharedContents)->Release(); - return JsNoError; - }); -} -#endif // _CHAKRACOREBUILD - CHAKRA_API JsCreateExternalArrayBuffer(_Pre_maybenull_ _Pre_writable_byte_size_(byteLength) void *data, _In_ unsigned int byteLength, _In_opt_ JsFinalizeCallback finalizeCallback, _In_opt_ void *callbackState, _Out_ JsValueRef *result) { @@ -2694,7 +2722,15 @@ CHAKRA_API JsHasExternalData(_In_ JsValueRef object, _Out_ bool *value) BEGIN_JSRT_NO_EXCEPTION { - *value = Js::VarIs(object); + if (Js::VarIs(object)) + { + object = Js::VarTo(object); + } + *value = (Js::VarIs(object) +#ifdef _CHAKRACOREBUILD + || Js::VarIs(object) +#endif + ); } END_JSRT_NO_EXCEPTION } @@ -2706,10 +2742,20 @@ CHAKRA_API JsGetExternalData(_In_ JsValueRef object, _Out_ void **data) BEGIN_JSRT_NO_EXCEPTION { + if (Js::VarIs(object)) + { + object = Js::VarTo(object)->GetTarget(); + } if (Js::VarIs(object)) { *data = Js::VarTo(object)->GetSlotData(); } +#ifdef _CHAKRACOREBUILD + else if (Js::VarIs(object)) + { + *data = Js::VarTo(object)->GetSlotData(); + } +#endif else { *data = nullptr; @@ -2725,10 +2771,20 @@ CHAKRA_API JsSetExternalData(_In_ JsValueRef object, _In_opt_ void *data) BEGIN_JSRT_NO_EXCEPTION { + if (Js::VarIs(object)) + { + object = Js::VarTo(object)->GetTarget(); + } if (Js::VarIs(object)) { Js::VarTo(object)->SetSlotData(data); } +#ifdef _CHAKRACOREBUILD + else if (Js::VarIs(object)) + { + Js::VarTo(object)->SetSlotData(data); + } +#endif else { RETURN_NO_EXCEPTION(JsErrorInvalidArgument); @@ -3527,6 +3583,7 @@ JsErrorCode RunScriptCore(JsValueRef scriptSource, const byte *script, size_t cb loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_Expression); } bool isLibraryCode = (parseAttributes & JsParseScriptAttributeLibraryCode) == JsParseScriptAttributeLibraryCode; + bool isStrictMode = (parseAttributes & JsParseScriptAttributeStrictMode) == JsParseScriptAttributeStrictMode; if (isLibraryCode) { loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_LibraryCode); @@ -3535,6 +3592,10 @@ JsErrorCode RunScriptCore(JsValueRef scriptSource, const byte *script, size_t cb { loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_Module); } + if (isStrictMode) + { + loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_StrictMode); + } #if ENABLE_TTD TTD::NSLogEvents::EventLogEntry* parseEvent = nullptr; @@ -4794,84 +4855,6 @@ CHAKRA_API JsTTDDiagSetAutoTraceStatus(_In_ bool status) #ifdef _CHAKRACOREBUILD -template -static void CastCopy(const SrcChar* src, DstChar* dst, size_t count) -{ - const SrcChar* end = src + count; - while (src < end) - { - *dst++ = static_cast(*src++); - } -} - -CHAKRA_API JsCreateString( - _In_ const char *content, - _In_ size_t length, - _Out_ JsValueRef *value) -{ - PARAM_NOT_NULL(content); - PARAM_NOT_NULL(value); - *value = JS_INVALID_REFERENCE; - - if (length == static_cast(-1)) - { - length = strlen(content); - } - - if (length > MaxCharCount) - { - return JsErrorOutOfMemory; - } - - return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { - - Js::JavascriptString *stringValue = Js::LiteralStringWithPropertyStringPtr:: - NewFromCString(content, (CharCount)length, scriptContext->GetLibrary()); - - PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateString, stringValue->GetSz(), stringValue->GetLength()); - - *value = stringValue; - - PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, value); - - return JsNoError; - }); -} - -CHAKRA_API JsCreateStringUtf16( - _In_ const uint16_t *content, - _In_ size_t length, - _Out_ JsValueRef *value) -{ - PARAM_NOT_NULL(content); - PARAM_NOT_NULL(value); - *value = JS_INVALID_REFERENCE; - - if (length == static_cast(-1)) - { - length = wcslen((const char16 *)content); - } - - if (length > static_cast(-1)) - { - return JsErrorOutOfMemory; - } - - return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { - - Js::JavascriptString *stringValue = Js::LiteralStringWithPropertyStringPtr:: - NewFromWideString((const char16 *)content, (CharCount)length, scriptContext->GetLibrary()); - - PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateString, stringValue->GetSz(), stringValue->GetLength()); - - *value = stringValue; - - PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, value); - - return JsNoError; - }); -} - template JsErrorCode WriteStringCopy( @@ -4979,8 +4962,8 @@ _ALWAYSINLINE JsErrorCode CompileRun( PARAM_NOT_NULL(sourceUrl); bool isExternalArray = Js::VarIs(scriptVal), - isString = false; - bool isUtf8 = !(parseAttributes & JsParseScriptAttributeArrayBufferIsUtf16Encoded); + isString = false; + bool isUtf8 = !(parseAttributes & JsParseScriptAttributeArrayBufferIsUtf16Encoded); LoadScriptFlag scriptFlag = LoadScriptFlag_None; const byte* script; @@ -5234,237 +5217,6 @@ CHAKRA_API JsRunSerialized( buffer, arrayBuffer, sourceContext, url, 0, false, false, result, Js::Constants::InvalidSourceIndex); } -CHAKRA_API JsCreatePromise(_Out_ JsValueRef *promise, _Out_ JsValueRef *resolve, _Out_ JsValueRef *reject) -{ - return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { - PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext); - - PARAM_NOT_NULL(promise); - PARAM_NOT_NULL(resolve); - PARAM_NOT_NULL(reject); - - *promise = nullptr; - *resolve = nullptr; - *reject = nullptr; - - Js::JavascriptPromiseResolveOrRejectFunction *jsResolve = nullptr; - Js::JavascriptPromiseResolveOrRejectFunction *jsReject = nullptr; - Js::JavascriptPromise *jsPromise = scriptContext->GetLibrary()->CreatePromise(); - Js::JavascriptPromise::InitializePromise(jsPromise, &jsResolve, &jsReject, scriptContext); - - *promise = (JsValueRef)jsPromise; - *resolve = (JsValueRef)jsResolve; - *reject = (JsValueRef)jsReject; - - return JsNoError; - }); -} - -CHAKRA_API JsGetPromiseState(_In_ JsValueRef promise, _Out_ JsPromiseState *state) -{ - return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { - PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext); - - VALIDATE_INCOMING_REFERENCE(promise, scriptContext); - PARAM_NOT_NULL(state); - - *state = JsPromiseStatePending; - - if (!Js::VarIs(promise)) - { - return JsErrorInvalidArgument; - } - - Js::JavascriptPromise *jsPromise = Js::VarTo(promise); - Js::JavascriptPromise::PromiseStatus status = jsPromise->GetStatus(); - - switch (status) - { - case Js::JavascriptPromise::PromiseStatus::PromiseStatusCode_HasRejection: - *state = JsPromiseStateRejected; - break; - - case Js::JavascriptPromise::PromiseStatus::PromiseStatusCode_HasResolution: - *state = JsPromiseStateFulfilled; - break; - } - - return JsNoError; - }); -} - -CHAKRA_API JsGetPromiseResult(_In_ JsValueRef promise, _Out_ JsValueRef *result) -{ - return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { - PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext); - - VALIDATE_INCOMING_REFERENCE(promise, scriptContext); - PARAM_NOT_NULL(result); - - *result = JS_INVALID_REFERENCE; - - if (!Js::VarIs(promise)) - { - return JsErrorInvalidArgument; - } - - Js::JavascriptPromise *jsPromise = Js::VarTo(promise); - Js::Var jsResult = jsPromise->GetResult(); - - if (jsResult == nullptr) - { - return JsErrorPromisePending; - } - - *result = (JsValueRef)jsResult; - return JsNoError; - }); -} - -CHAKRA_API JsCreateWeakReference( - _In_ JsValueRef value, - _Out_ JsWeakRef* weakRef) -{ - VALIDATE_JSREF(value); - PARAM_NOT_NULL(weakRef); - *weakRef = nullptr; - - if (Js::TaggedNumber::Is(value)) - { - return JsNoWeakRefRequired; - } - - return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode { - ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread(); - if (threadContext == nullptr) - { - return JsErrorNoCurrentContext; - } - - Recycler* recycler = threadContext->GetRecycler(); - if (recycler->IsInObjectBeforeCollectCallback()) - { - return JsErrorInObjectBeforeCollectCallback; - } - - RecyclerHeapObjectInfo dummyObjectInfo; - if (!recycler->FindHeapObject(value, Memory::FindHeapObjectFlags::FindHeapObjectFlags_NoFlags, dummyObjectInfo)) - { - // value is not recyler-allocated - return JsErrorInvalidArgument; - } - - recycler->FindOrCreateWeakReferenceHandle( - reinterpret_cast(value), - reinterpret_cast**>(weakRef)); - return JsNoError; - }); -} - -CHAKRA_API JsGetWeakReferenceValue( - _In_ JsWeakRef weakRef, - _Out_ JsValueRef* value) -{ - VALIDATE_JSREF(weakRef); - PARAM_NOT_NULL(value); - *value = JS_INVALID_REFERENCE; - - return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode { - Memory::RecyclerWeakReference* recyclerWeakReference = - reinterpret_cast*>(weakRef); - *value = reinterpret_cast(recyclerWeakReference->Get()); - return JsNoError; - }); -} - -CHAKRA_API JsGetAndClearExceptionWithMetadata(_Out_ JsValueRef *metadata) -{ - PARAM_NOT_NULL(metadata); - *metadata = nullptr; - - JsrtContext *currentContext = JsrtContext::GetCurrent(); - - if (currentContext == nullptr) - { - return JsErrorNoCurrentContext; - } - - Js::ScriptContext *scriptContext = currentContext->GetScriptContext(); - Assert(scriptContext != nullptr); - - if (scriptContext->GetRecycler() && scriptContext->GetRecycler()->IsHeapEnumInProgress()) - { - return JsErrorHeapEnumInProgress; - } - else if (scriptContext->GetThreadContext()->IsInThreadServiceCallback()) - { - return JsErrorInThreadServiceCallback; - } - - if (scriptContext->GetThreadContext()->IsExecutionDisabled()) - { - return JsErrorInDisabledState; - } - - HRESULT hr = S_OK; - Js::JavascriptExceptionObject *recordedException = nullptr; - - BEGIN_TRANSLATE_OOM_TO_HRESULT - if (scriptContext->HasRecordedException()) - { - recordedException = scriptContext->GetAndClearRecordedException(); - } - END_TRANSLATE_OOM_TO_HRESULT(hr) - - if (hr == E_OUTOFMEMORY) - { - recordedException = scriptContext->GetThreadContext()->GetRecordedException(); - } - if (recordedException == nullptr) - { - return JsErrorInvalidArgument; - } - - Js::Var exception = recordedException->GetThrownObject(nullptr); - - if (exception == nullptr) - { - // TODO: How does this early bailout impact TTD? - return JsErrorInvalidArgument; - } - - return ContextAPIWrapper([&](Js::ScriptContext* scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { - Js::Var exceptionMetadata = Js::JavascriptExceptionMetadata::CreateMetadataVar(scriptContext); - Js::JavascriptOperators::OP_SetProperty(exceptionMetadata, Js::PropertyIds::exception, exception, scriptContext); - - Js::FunctionBody *functionBody = recordedException->GetFunctionBody(); - if (functionBody == nullptr) - { - // This is probably a parse error. We can get the error location metadata from the thrown object. - Js::JavascriptExceptionMetadata::PopulateMetadataFromCompileException(exceptionMetadata, exception, scriptContext); - } - else - { - if (!Js::JavascriptExceptionMetadata::PopulateMetadataFromException(exceptionMetadata, recordedException, scriptContext)) - { - return JsErrorInvalidArgument; - } - } - - *metadata = exceptionMetadata; - -#if ENABLE_TTD - if (hr != E_OUTOFMEMORY) - { - PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetAndClearExceptionWithMetadata); - PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, metadata); - } -#endif - - - return JsNoError; - }); -} CHAKRA_API JsCopyStringOneByte( _In_ JsValueRef value, @@ -5489,96 +5241,6 @@ CHAKRA_API JsCopyStringOneByte( }); } -CHAKRA_API JsGetDataViewInfo( - _In_ JsValueRef dataView, - _Out_opt_ JsValueRef *arrayBuffer, - _Out_opt_ unsigned int *byteOffset, - _Out_opt_ unsigned int *byteLength) -{ - VALIDATE_JSREF(dataView); - - BEGIN_JSRT_NO_EXCEPTION - { - if (!Js::VarIs(dataView)) - { - RETURN_NO_EXCEPTION(JsErrorInvalidArgument); - } - - Js::DataView* dv = Js::VarTo(dataView); - if (arrayBuffer != nullptr) { - *arrayBuffer = dv->GetArrayBuffer(); - } - - if (byteOffset != nullptr) { - *byteOffset = dv->GetByteOffset(); - } - - if (byteLength != nullptr) { - *byteLength = dv->GetLength(); - } - } - -#if ENABLE_TTD - Js::ScriptContext* scriptContext = Js::VarTo(dataView)->GetScriptContext(); - if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext) && arrayBuffer != nullptr) - { - scriptContext->GetThreadContext()->TTDLog->RecordJsRTGetDataViewInfo(dataView, *arrayBuffer); - } -#endif - - END_JSRT_NO_EXCEPTION -} - -CHAKRA_API JsSetHostPromiseRejectionTracker(_In_ JsHostPromiseRejectionTrackerCallback promiseRejectionTrackerCallback, _In_opt_ void *callbackState) -{ - return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode { - scriptContext->GetLibrary()->SetNativeHostPromiseRejectionTrackerCallback((Js::JavascriptLibrary::HostPromiseRejectionTrackerCallback) promiseRejectionTrackerCallback, callbackState); - return JsNoError; - }, - /*allowInObjectBeforeCollectCallback*/true); -} - -CHAKRA_API JsGetProxyProperties (_In_ JsValueRef object, _Out_ bool* isProxy, _Out_opt_ JsValueRef* target, _Out_opt_ JsValueRef* handler) -{ - return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext * scriptContext) -> JsErrorCode { - VALIDATE_INCOMING_REFERENCE(object, scriptContext); - PARAM_NOT_NULL(isProxy); - - if (target != nullptr) - { - *target = JS_INVALID_REFERENCE; - } - - if (handler != nullptr) - { - *handler = JS_INVALID_REFERENCE; - } - - *isProxy = Js::VarIs(object); - - if (!*isProxy) - { - return JsNoError; - } - - Js::JavascriptProxy* proxy = Js::UnsafeVarTo(object); - bool revoked = proxy->IsRevoked(); - - if (target != nullptr && !revoked) - { - *target = static_cast(proxy->GetTarget()); - } - - if (handler != nullptr && !revoked) - { - *handler = static_cast(proxy->GetHandler()); - } - - return JsNoError; - }, - /*allowInObjectBeforeCollectCallback*/true); -} - CHAKRA_API JsSerializeParserStateCore( _In_z_ const byte* script, _In_ size_t cb, @@ -5841,40 +5503,6 @@ CHAKRA_API JsRunScriptWithParserState( } } -CHAKRA_API -JsQueueBackgroundParse_Experimental( - _In_ JsScriptContents* contents, - _Out_ DWORD* dwBgParseCookie) -{ - HRESULT hr; - if (Js::Configuration::Global.flags.BgParse && !CONFIG_FLAG(ForceDiagnosticsMode) - // For now, only UTF8 buffers are supported for BGParse - && contents->encodingType == JsScriptEncodingType::Utf8 - && contents->containerType == JsScriptContainerType::HeapAllocatedBuffer - // SourceContext not needed for BGParse - && contents->sourceContext == 0) - { - hr = BGParseManager::GetBGParseManager()->QueueBackgroundParse((LPUTF8)contents->container, contents->contentLengthInBytes, (char16*)contents->fullPath, dwBgParseCookie); - } - else - { - hr = E_NOTIMPL; - } - - JsErrorCode res = (hr == S_OK) ? JsNoError : JsErrorFatal; - - return res; -} - -CHAKRA_API -JsDiscardBackgroundParse_Experimental( - _In_ DWORD dwBgParseCookie, - _In_ void* buffer, - _Out_ bool* callerOwnsBuffer) -{ - (*callerOwnsBuffer) = BGParseManager::GetBGParseManager()->DiscardParseResults(dwBgParseCookie, buffer); - return JsNoError; -} CHAKRA_API JsExecuteBackgroundParse_Experimental( @@ -5904,17 +5532,4 @@ JsExecuteBackgroundParse_Experimental( return JsErrorFatal; } } - -#ifdef _WIN32 -CHAKRA_API -JsConnectJITProcess(_In_ HANDLE processHandle, _In_opt_ void* serverSecurityDescriptor, _In_ UUID connectionId) -{ -#ifdef ENABLE_OOP_NATIVE_CODEGEN - JITManager::GetJITManager()->EnableOOPJIT(); - ThreadContext::SetJITConnectionInfo(processHandle, serverSecurityDescriptor, connectionId); -#endif - return JsNoError; -} #endif - -#endif // _CHAKRACOREBUILD diff --git a/lib/Jsrt/JsrtCommonExports.inc b/lib/Jsrt/JsrtCommonExports.inc index 06d54dc09fc..a948c20dcbd 100644 --- a/lib/Jsrt/JsrtCommonExports.inc +++ b/lib/Jsrt/JsrtCommonExports.inc @@ -104,31 +104,68 @@ JsIdle JsSetPromiseContinuationCallback #ifndef NTBUILD - JsCreateString - JsCreateStringUtf16 - JsCopyString - JsCopyStringUtf16 - JsParse - JsRun - JsSerialize - JsParseSerialized - JsRunSerialized - JsCreatePropertyId + JsAllocRawData + JsCloneObject JsConnectJITProcess JsCopyPropertyId + JsCopyString + JsCopyStringOneByte + JsCopyStringUtf16 + JsCreateCustomExternalObject + JsCreateExternalObjectWithPrototype JsCreatePromise + JsCreateTracedExternalObject + JsCreatePropertyId + JsCreatePropertyString + JsCreateString + JsCreateStringUtf16 JsCreateWeakReference - JsGetWeakReferenceValue + JsDetachArrayBuffer + JsGetArrayBufferExtraInfo JsGetAndClearExceptionWithMetadata - JsHasOwnProperty - JsCopyStringOneByte + JsGetArrayEntriesFunction + JsGetArrayForEachFunction + JsGetArrayKeysFunction + JsGetArrayValuesFunction JsGetDataViewInfo - JsCreateExternalObjectWithPrototype + JsGetErrorPrototype + JsGetIteratorPrototype + JsGetPropertyIdSymbolIterator + JsGetWeakReferenceValue + JsHasOwnProperty + JsIsConstructor + JsObjectDefineProperty + JsObjectDefinePropertyFull + JsObjectDeleteProperty + JsObjectGetOwnPropertyDescriptor JsObjectGetProperty + JsObjectHasOwnProperty JsObjectHasProperty JsObjectSetProperty - JsObjectDeleteProperty - JsObjectHasOwnProperty - JsObjectGetOwnPropertyDescriptor - JsObjectDefineProperty + JsParse + JsParseSerialized + JsPrivateDeleteProperty + JsPrivateGetProperty + JsPrivateHasProperty + JsPrivateSetProperty + JsRun + JsRunSerialized + JsSerialize + JsSetArrayBufferExtraInfo + JsSetRuntimeBeforeSweepCallback + JsSetRuntimeDomWrapperTracingCallbacks + JsTraceExternalReference + JsVarDeserializer + JsVarDeserializerFree + JsVarDeserializerReadBytes + JsVarDeserializerReadRawBytes + JsVarDeserializerReadValue + JsVarDeserializerSetTransferableVars + JsVarSerializer + JsVarSerializerDetachArrayBuffer + JsVarSerializerFree + JsVarSerializerReleaseData + JsVarSerializerSetTransferableVars + JsVarSerializerWriteRawBytes + JsVarSerializerWriteValue #endif diff --git a/lib/Jsrt/JsrtContext.h b/lib/Jsrt/JsrtContext.h index 986a370325c..3519b6c8ec0 100644 --- a/lib/Jsrt/JsrtContext.h +++ b/lib/Jsrt/JsrtContext.h @@ -42,3 +42,4 @@ class JsrtContext : public FinalizableObject Field(TaggedPointer) previous; Field(TaggedPointer) next; }; + diff --git a/lib/Jsrt/JsrtExternalObject.cpp b/lib/Jsrt/JsrtExternalObject.cpp index 20944a48658..1979a9ea7ce 100644 --- a/lib/Jsrt/JsrtExternalObject.cpp +++ b/lib/Jsrt/JsrtExternalObject.cpp @@ -7,57 +7,162 @@ #include "JsrtExternalObject.h" #include "Types/PathTypeHandler.h" -JsrtExternalType::JsrtExternalType(Js::ScriptContext* scriptContext, JsFinalizeCallback finalizeCallback) +#ifdef _CHAKRACOREBUILD +JsrtExternalType::JsrtExternalType(Js::ScriptContext* scriptContext, JsTraceCallback traceCallback, JsFinalizeCallback finalizeCallback, Js::RecyclableObject * prototype) : Js::DynamicType( scriptContext, Js::TypeIds_Object, - scriptContext->GetLibrary()->GetObjectPrototype(), + prototype, nullptr, Js::PathTypeHandlerNoAttr::New(scriptContext, scriptContext->GetLibrary()->GetRootPath(), 0, 0, 0, true, true), true, true) - , jsFinalizeCallback(finalizeCallback) + , jsTraceCallback(traceCallback) + , jsFinalizeCallback(finalizeCallback) +{ + this->flags |= TypeFlagMask_JsrtExternal; +} +#endif +JsrtExternalType::JsrtExternalType(Js::ScriptContext* scriptContext, JsFinalizeCallback finalizeCallback, Js::RecyclableObject * prototype) + : Js::DynamicType( + scriptContext, + Js::TypeIds_Object, + prototype, + nullptr, + Js::PathTypeHandlerNoAttr::New(scriptContext, scriptContext->GetLibrary()->GetRootPath(), 0, 0, 0, true, true), + true, + true) +#ifdef _CHAKRACOREBUILD + , jsTraceCallback(nullptr) +#endif + , jsFinalizeCallback(finalizeCallback) { this->flags |= TypeFlagMask_JsrtExternal; } -JsrtExternalObject::JsrtExternalObject(JsrtExternalType * type, void *data) : - slot(data), - Js::DynamicObject(type, false/* initSlots*/) +JsrtExternalObject::JsrtExternalObject(JsrtExternalType * type, void *data, uint inlineSlotSize) : + Js::DynamicObject(type, true /* initSlots*/) { + if (inlineSlotSize != 0) + { + this->slotType = SlotType::Inline; + this->u.inlineSlotSize = inlineSlotSize; + if (data) + { + memcpy_s(this->GetInlineSlots(), inlineSlotSize, data, inlineSlotSize); + } + } + else + { + this->slotType = SlotType::External; + this->u.slot = data; + } } +#ifdef _CHAKRACOREBUILD /* static */ -JsrtExternalObject* JsrtExternalObject::Create(void *data, JsFinalizeCallback finalizeCallback, Js::RecyclableObject * prototype, Js::ScriptContext *scriptContext) +JsrtExternalObject* JsrtExternalObject::Create(void *data, uint inlineSlotSize, JsTraceCallback traceCallback, JsFinalizeCallback finalizeCallback, Js::RecyclableObject * prototype, Js::ScriptContext *scriptContext, JsrtExternalType * type) { - Js::DynamicType * dynamicType = scriptContext->GetLibrary()->GetCachedJsrtExternalType(reinterpret_cast(finalizeCallback)); + if (prototype == nullptr) + { + prototype = scriptContext->GetLibrary()->GetObjectPrototype(); + } + if (type == nullptr) + { + type = scriptContext->GetLibrary()->GetCachedJsrtExternalType(reinterpret_cast(traceCallback), reinterpret_cast(finalizeCallback), reinterpret_cast(prototype)); - if (dynamicType == nullptr) + if (type == nullptr) + { + type = RecyclerNew(scriptContext->GetRecycler(), JsrtExternalType, scriptContext, traceCallback, finalizeCallback, prototype); + scriptContext->GetLibrary()->CacheJsrtExternalType(reinterpret_cast(traceCallback), reinterpret_cast(finalizeCallback), reinterpret_cast(prototype), type); + } + } + + Assert(type->IsJsrtExternal()); + + JsrtExternalObject * externalObject; + if (traceCallback != nullptr) + { + externalObject = RecyclerNewTrackedPlus(scriptContext->GetRecycler(), inlineSlotSize, JsrtExternalObject, static_cast(type), data, inlineSlotSize); + } + else if (finalizeCallback != nullptr) + { + externalObject = RecyclerNewFinalizedPlus(scriptContext->GetRecycler(), inlineSlotSize, JsrtExternalObject, static_cast(type), data, inlineSlotSize); + } + else { - dynamicType = RecyclerNew(scriptContext->GetRecycler(), JsrtExternalType, scriptContext, finalizeCallback); - scriptContext->GetLibrary()->CacheJsrtExternalType(reinterpret_cast(finalizeCallback), dynamicType); + externalObject = RecyclerNewPlus(scriptContext->GetRecycler(), inlineSlotSize, JsrtExternalObject, static_cast(type), data, inlineSlotSize); } - Assert(dynamicType->IsJsrtExternal()); - Assert(dynamicType->GetIsShared()); + return externalObject; +} +#endif +/* static */ +JsrtExternalObject* JsrtExternalObject::Create(void *data, uint inlineSlotSize, JsFinalizeCallback finalizeCallback, Js::RecyclableObject * prototype, Js::ScriptContext *scriptContext, JsrtExternalType * type) +{ + if (prototype == nullptr) + { + prototype = scriptContext->GetLibrary()->GetObjectPrototype(); + } + if (type == nullptr) + { +#ifdef _CHAKRACOREBUILD + type = scriptContext->GetLibrary()->GetCachedJsrtExternalType(0, reinterpret_cast(finalizeCallback), reinterpret_cast(prototype)); +#else + type = scriptContext->GetLibrary()->GetCachedJsrtExternalType(reinterpret_cast(finalizeCallback), reinterpret_cast(prototype)); +#endif + + if (type == nullptr) + { + type = RecyclerNew(scriptContext->GetRecycler(), JsrtExternalType, scriptContext, finalizeCallback, prototype); +#ifdef _CHAKRACOREBUILD + scriptContext->GetLibrary()->CacheJsrtExternalType(0, reinterpret_cast(finalizeCallback), reinterpret_cast(prototype), type); +#else + scriptContext->GetLibrary()->CacheJsrtExternalType(reinterpret_cast(finalizeCallback), reinterpret_cast(prototype), type); +#endif + } + } - JsrtExternalObject * externalObject = RecyclerNewFinalized(scriptContext->GetRecycler(), JsrtExternalObject, static_cast(dynamicType), data); + Assert(type->IsJsrtExternal()); - if (prototype != nullptr) + JsrtExternalObject * externalObject; + if (finalizeCallback != nullptr) { - externalObject->SetPrototype(prototype); + externalObject = RecyclerNewFinalizedPlus(scriptContext->GetRecycler(), inlineSlotSize, JsrtExternalObject, static_cast(type), data, inlineSlotSize); + } + else + { + externalObject = RecyclerNewPlus(scriptContext->GetRecycler(), inlineSlotSize, JsrtExternalObject, static_cast(type), data, inlineSlotSize); } return externalObject; } +void JsrtExternalObject::Mark(Recycler * recycler) +{ +#ifdef _CHAKRACOREBUILD + recycler->SetNeedExternalWrapperTracing(); + JsTraceCallback traceCallback = this->GetExternalType()->GetJsTraceCallback(); + Assert(nullptr != traceCallback); + JsrtCallbackState scope(nullptr); + traceCallback(this->GetSlotData()); +#else + Assert(UNREACHED); +#endif +} + void JsrtExternalObject::Finalize(bool isShutdown) { JsFinalizeCallback finalizeCallback = this->GetExternalType()->GetJsFinalizeCallback(); +#ifdef _CHAKRACOREBUILD + Assert(this->GetExternalType()->GetJsTraceCallback() != nullptr || finalizeCallback != nullptr); +#else + Assert(finalizeCallback != nullptr); +#endif if (nullptr != finalizeCallback) { JsrtCallbackState scope(nullptr); - finalizeCallback(this->slot); + finalizeCallback(this->GetSlotData()); } } @@ -67,12 +172,29 @@ void JsrtExternalObject::Dispose(bool isShutdown) void * JsrtExternalObject::GetSlotData() const { - return this->slot; + return this->slotType == SlotType::External + ? unsafe_write_barrier_cast(this->u.slot) + : GetInlineSlots(); } void JsrtExternalObject::SetSlotData(void * data) { - this->slot = data; + this->slotType = SlotType::External; + this->u.slot = data; +} + +int JsrtExternalObject::GetInlineSlotSize() const +{ + return this->slotType == SlotType::External + ? 0 + : this->u.inlineSlotSize; +} + +void * JsrtExternalObject::GetInlineSlots() const +{ + return this->slotType == SlotType::External + ? nullptr + : (void *)((uintptr_t)this + sizeof(JsrtExternalObject)); } Js::DynamicType* JsrtExternalObject::DuplicateType() diff --git a/lib/Jsrt/JsrtExternalObject.h b/lib/Jsrt/JsrtExternalObject.h index 2dcc0264424..627ad55a540 100644 --- a/lib/Jsrt/JsrtExternalObject.h +++ b/lib/Jsrt/JsrtExternalObject.h @@ -27,14 +27,28 @@ class JsrtExternalType sealed : public Js::DynamicType { public: - JsrtExternalType(JsrtExternalType *type) : Js::DynamicType(type), jsFinalizeCallback(type->jsFinalizeCallback) {} - JsrtExternalType(Js::ScriptContext* scriptContext, JsFinalizeCallback finalizeCallback); + JsrtExternalType(JsrtExternalType *type) : + Js::DynamicType(type), +#ifdef _CHAKRACOREBUILD + jsTraceCallback(type->jsTraceCallback), +#endif + jsFinalizeCallback(type->jsFinalizeCallback) {} +#ifdef _CHAKRACOREBUILD + JsrtExternalType(Js::ScriptContext* scriptContext, JsTraceCallback traceCallback, JsFinalizeCallback finalizeCallback, Js::RecyclableObject * prototype); +#endif + JsrtExternalType(Js::ScriptContext* scriptContext, JsFinalizeCallback finalizeCallback, Js::RecyclableObject * prototype); //Js::PropertyId GetNameId() const { return ((Js::PropertyRecord *)typeDescription.className)->GetPropertyId(); } +#ifdef _CHAKRACOREBUILD + JsTraceCallback GetJsTraceCallback() const { return this->jsTraceCallback; } +#endif JsFinalizeCallback GetJsFinalizeCallback() const { return this->jsFinalizeCallback; } private: - FieldNoBarrier(JsFinalizeCallback) jsFinalizeCallback; + FieldNoBarrier(JsFinalizeCallback const) jsFinalizeCallback; +#ifdef _CHAKRACOREBUILD + FieldNoBarrier(JsTraceCallback const) jsTraceCallback; +#endif }; AUTO_REGISTER_RECYCLER_OBJECT_DUMPER(JsrtExternalType, &Js::Type::DumpObjectFunction); @@ -45,12 +59,16 @@ class JsrtExternalObject : public Js::DynamicObject DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(JsrtExternalObject); public: - JsrtExternalObject(JsrtExternalType * type, void *data); + JsrtExternalObject(JsrtExternalType * type, void *data, uint inlineSlotSize); - static JsrtExternalObject * Create(void *data, JsFinalizeCallback finalizeCallback, Js::RecyclableObject * prototype, Js::ScriptContext *scriptContext); +#ifdef _CHAKRACOREBUILD + static JsrtExternalObject * Create(void *data, uint inlineSlotSize, JsTraceCallback traceCallback, JsFinalizeCallback finalizeCallback, Js::RecyclableObject * prototype, Js::ScriptContext *scriptContext, JsrtExternalType * type); +#endif + static JsrtExternalObject * Create(void *data, uint inlineSlotSize, JsFinalizeCallback finalizeCallback, Js::RecyclableObject * prototype, Js::ScriptContext *scriptContext, JsrtExternalType * type); JsrtExternalType * GetExternalType() const { return (JsrtExternalType *)this->GetType(); } + void Mark(Recycler * recycler) override; void Finalize(bool isShutdown) override; void Dispose(bool isShutdown) override; @@ -60,9 +78,27 @@ class JsrtExternalObject : public Js::DynamicObject void * GetSlotData() const; void SetSlotData(void * data); + int GetInlineSlotSize() const; + void* GetInlineSlots() const; + Field(bool) initialized = true; private: - Field(void *) slot; + enum class SlotType { + Inline, + External + }; + + Field(SlotType) slotType; + union SlotInfo + { + Field(void *) slot; + Field(uint) inlineSlotSize; + SlotInfo() + { + memset(this, 0, sizeof(SlotInfo)); + } + }; + Field(SlotInfo) u; #if ENABLE_TTD public: diff --git a/lib/Jsrt/JsrtRuntime.cpp b/lib/Jsrt/JsrtRuntime.cpp index a77a497fcbe..d89506f2646 100644 --- a/lib/Jsrt/JsrtRuntime.cpp +++ b/lib/Jsrt/JsrtRuntime.cpp @@ -14,7 +14,11 @@ JsrtRuntime::JsrtRuntime(ThreadContext * threadContext, bool useIdle, bool dispa this->contextList = NULL; this->collectCallback = NULL; this->beforeCollectCallback = NULL; - this->callbackContext = NULL; + this->beforeCollectCallbackContext = NULL; +#ifdef _CHAKRACOREBUILD + this->beforeSweepCallback = NULL; + this->beforeSweepCallbackContext = NULL; +#endif this->allocationPolicyManager = threadContext->GetAllocationPolicyManager(); this->useIdle = useIdle; this->dispatchExceptions = dispatchExceptions; @@ -85,44 +89,98 @@ void JsrtRuntime::CloseContexts() void JsrtRuntime::SetBeforeCollectCallback(JsBeforeCollectCallback beforeCollectCallback, void * callbackContext) { - if (beforeCollectCallback != NULL) + if (beforeCollectCallback != nullptr) { - if (this->collectCallback == NULL) + if (this->collectCallback == nullptr) { this->collectCallback = this->threadContext->AddRecyclerCollectCallBack(RecyclerCollectCallbackStatic, this); } this->beforeCollectCallback = beforeCollectCallback; - this->callbackContext = callbackContext; + this->beforeCollectCallbackContext = callbackContext; } else { - if (this->collectCallback != NULL) + if (this->collectCallback != nullptr +#ifdef _CHAKRACOREBUILD + && this->beforeSweepCallback == nullptr +#endif + ) { this->threadContext->RemoveRecyclerCollectCallBack(this->collectCallback); - this->collectCallback = NULL; + this->collectCallback = nullptr; } - this->beforeCollectCallback = NULL; - this->callbackContext = NULL; + this->beforeCollectCallback = nullptr; + this->beforeCollectCallbackContext = nullptr; } } +#ifdef _CHAKRACOREBUILD +void JsrtRuntime::SetBeforeSweepCallback(JsBeforeSweepCallback afterCollectCallback, void * callbackContext) +{ + if (afterCollectCallback != nullptr) + { + if (this->collectCallback == nullptr) + { + this->collectCallback = this->threadContext->AddRecyclerCollectCallBack(RecyclerCollectCallbackStatic, this); + } + + this->beforeSweepCallback = afterCollectCallback; + this->beforeSweepCallbackContext = callbackContext; + } + else + { + if (this->collectCallback != nullptr && this->beforeCollectCallback == nullptr) + { + this->threadContext->RemoveRecyclerCollectCallBack(this->collectCallback); + this->collectCallback = nullptr; + } + + this->beforeSweepCallback = nullptr; + this->beforeSweepCallbackContext = nullptr; + } +} +#endif + void JsrtRuntime::RecyclerCollectCallbackStatic(void * context, RecyclerCollectCallBackFlags flags) { if (flags & Collect_Begin) { JsrtRuntime * _this = reinterpret_cast(context); + if (_this->beforeCollectCallback == nullptr) + { + return; + } try { JsrtCallbackState scope(reinterpret_cast(_this->GetThreadContext())); - _this->beforeCollectCallback(_this->callbackContext); + _this->beforeCollectCallback(_this->beforeCollectCallbackContext); } catch (...) { AssertMsg(false, "Unexpected non-engine exception."); } } +#ifdef _CHAKRACOREBUILD + else if (flags & Collect_Begin_Sweep) + { + JsrtRuntime * _this = reinterpret_cast(context); + if (_this->beforeSweepCallback == nullptr) + { + return; + } + try + { + JsrtCallbackState scope(reinterpret_cast(_this->GetThreadContext())); + _this->beforeSweepCallback(_this->beforeSweepCallbackContext); + } + catch (...) + { + AssertMsg(false, "Unexpected non-engine exception."); + } + } +#endif } unsigned int JsrtRuntime::Idle() diff --git a/lib/Jsrt/JsrtRuntime.h b/lib/Jsrt/JsrtRuntime.h index 32c5304c7ef..72a5d2a7edf 100644 --- a/lib/Jsrt/JsrtRuntime.h +++ b/lib/Jsrt/JsrtRuntime.h @@ -38,6 +38,9 @@ class JsrtRuntime void CloseContexts(); void SetBeforeCollectCallback(JsBeforeCollectCallback beforeCollectCallback, void * callbackContext); +#ifdef _CHAKRACOREBUILD + void SetBeforeSweepCallback(JsBeforeSweepCallback beforeCollectCallback, void * callbackContext); +#endif #ifdef ENABLE_DEBUG_CONFIG_OPTIONS void SetSerializeByteCodeForLibrary(bool set) { serializeByteCodeForLibrary = set; } @@ -65,8 +68,12 @@ class JsrtRuntime JsrtContext * contextList; ThreadContext::CollectCallBack * collectCallback; JsBeforeCollectCallback beforeCollectCallback; +#ifdef _CHAKRACOREBUILD + JsBeforeSweepCallback beforeSweepCallback; + void * beforeSweepCallbackContext; +#endif JsrtThreadService threadService; - void * callbackContext; + void * beforeCollectCallbackContext; bool useIdle; bool dispatchExceptions; #ifdef ENABLE_DEBUG_CONFIG_OPTIONS diff --git a/lib/Parser/Parse.cpp b/lib/Parser/Parse.cpp index cab9031bc1a..a54d609d684 100644 --- a/lib/Parser/Parse.cpp +++ b/lib/Parser/Parse.cpp @@ -501,6 +501,11 @@ HRESULT Parser::ParseSourceInternal( this->m_fUseStrictMode = TRUE; } + if ((grfscr & fscrUseStrictMode) != 0) + { + this->m_fUseStrictMode = TRUE; + } + // parse the source pnodeBase = Parse(pszSrc, offsetInBytes, encodedCharCount, offsetInChars, isUtf8, grfscr, lineNumber, nextFunctionId, pse); diff --git a/lib/Parser/ParseFlags.h b/lib/Parser/ParseFlags.h index 57aa7a50269..53254436b81 100644 --- a/lib/Parser/ParseFlags.h +++ b/lib/Parser/ParseFlags.h @@ -51,5 +51,6 @@ enum fscrIsModuleCode = 1 << 26, // Current code should be parsed as a module body fscrDeferredFncIsMethod = 1 << 27, - fscrAll = (1 << 28) - 1 + fscrUseStrictMode = 1 << 28, + fscrAll = (1 << 29) - 1 }; diff --git a/lib/Runtime/Base/ScriptContext.cpp b/lib/Runtime/Base/ScriptContext.cpp index 2c3805d3aa1..ac452a0290e 100644 --- a/lib/Runtime/Base/ScriptContext.cpp +++ b/lib/Runtime/Base/ScriptContext.cpp @@ -2024,6 +2024,11 @@ namespace Js } } + if ((loadScriptFlag & LoadScriptFlag_StrictMode) == LoadScriptFlag_StrictMode) + { + grfscr |= fscrUseStrictMode; + } + if ((loadScriptFlag & LoadScriptFlag_disableAsmJs) == LoadScriptFlag_disableAsmJs) { grfscr |= fscrNoAsmJs; diff --git a/lib/Runtime/Base/ScriptContext.h b/lib/Runtime/Base/ScriptContext.h index 8829ce83997..f2d9f91e919 100644 --- a/lib/Runtime/Base/ScriptContext.h +++ b/lib/Runtime/Base/ScriptContext.h @@ -124,7 +124,8 @@ enum LoadScriptFlag LoadScriptFlag_Utf8Source = 0x40, // input buffer is utf8 encoded. LoadScriptFlag_LibraryCode = 0x80, // for debugger, indicating 'not my code' LoadScriptFlag_ExternalArrayBuffer = 0x100, // for ExternalArrayBuffer - LoadScriptFlag_CreateParserState = 0x200 // create the parser state cache while parsing. + LoadScriptFlag_CreateParserState = 0x200, // create the parser state cache while parsing. + LoadScriptFlag_StrictMode = 0x400 // parse using strict mode semantics }; enum class ScriptContextPrivilegeLevel @@ -184,6 +185,8 @@ class HostScriptContext virtual HRESULT FetchImportedModuleFromScript(DWORD_PTR dwReferencingSourceContext, LPCOLESTR specifier, Js::ModuleRecordBase** dependentModuleRecord) = 0; virtual HRESULT NotifyHostAboutModuleReady(Js::ModuleRecordBase* referencingModule, Js::Var exceptionVar) = 0; + virtual HRESULT ThrowIfFailed(HRESULT hr) = 0; + Js::ScriptContext* GetScriptContext() { return scriptContext; } virtual bool SetCrossSiteForFunctionType(Js::JavascriptFunction * function) = 0; @@ -197,6 +200,19 @@ class HostScriptContext Js::ScriptContext* scriptContext; }; +class HostStream +{ +public: + virtual byte * ExtendBuffer(byte *oldBuffer, size_t newSize, size_t *allocatedSize) = 0; + virtual bool WriteHostObject(void* data) = 0; +}; + +class HostReadStream +{ +public: + virtual Js::Var ReadHostObject() = 0; +}; + #if ENABLE_TTD typedef void (CALLBACK *JsTTDOnScriptLoadCallback)(FinalizableObject* hostContext, Js::FunctionBody* body, Js::Utf8SourceInfo* utf8SourceInfo, CompileScriptException* compileException, bool notify); typedef uint32 (CALLBACK *JsTTDOnBPRegisterCallback)(void* hostRuntime, int64 bpID, Js::ScriptContext* scriptContext, Js::Utf8SourceInfo* utf8SourceInfo, uint32 line, uint32 column, BOOL* isNewBP); diff --git a/lib/Runtime/Base/ThreadContext.cpp b/lib/Runtime/Base/ThreadContext.cpp index 18536884264..e4e9a663bb4 100644 --- a/lib/Runtime/Base/ThreadContext.cpp +++ b/lib/Runtime/Base/ThreadContext.cpp @@ -2600,6 +2600,8 @@ ThreadContext::PreCollectionCallBack(CollectionFlags flags) void ThreadContext::PreSweepCallback() { + CollectionCallBack(Collect_Begin_Sweep); + #ifdef PERSISTENT_INLINE_CACHES ClearInlineCachesWithDeadWeakRefs(); #else diff --git a/lib/Runtime/Base/ThreadContext.h b/lib/Runtime/Base/ThreadContext.h index f5c11d11f69..6fcef11f7a1 100644 --- a/lib/Runtime/Base/ThreadContext.h +++ b/lib/Runtime/Base/ThreadContext.h @@ -189,7 +189,8 @@ enum RecyclerCollectCallBackFlags Collect_Begin_Partial = 0x21, Collect_Begin_Concurrent_Partial = Collect_Begin_Concurrent | Collect_Begin_Partial, Collect_End = 0x02, - Collect_Wait = 0x04 // callback can be from another thread + Collect_Wait = 0x04, // callback can be from another thread + Collect_Begin_Sweep = 0x08 }; typedef void (__cdecl *RecyclerCollectCallBackFunction)(void * context, RecyclerCollectCallBackFlags flags); diff --git a/lib/Runtime/ByteCode/ByteCodeSerializer.cpp b/lib/Runtime/ByteCode/ByteCodeSerializer.cpp index 9dc001be0c8..ae607f605c8 100644 --- a/lib/Runtime/ByteCode/ByteCodeSerializer.cpp +++ b/lib/Runtime/ByteCode/ByteCodeSerializer.cpp @@ -3169,7 +3169,7 @@ class ByteCodeBufferReader string16IndexTable = (StringIndexRecord*)ReadInt32(string16s, &string16Count); lineCharacterOffsetCacheBuffer = (charcount_t *)ReadInt32(lineInfoCaches, &lineInfoCacheCount); byte haslineByteOffsetCacheBuffer; - current = ReadByte(lineInfoCaches + sizeof(charcount_t) * lineInfoCacheCount, &haslineByteOffsetCacheBuffer); + current = ReadByte((byte*)lineCharacterOffsetCacheBuffer + sizeof(charcount_t) * lineInfoCacheCount, &haslineByteOffsetCacheBuffer); if (haslineByteOffsetCacheBuffer) { lineByteOffsetCacheBuffer = (charcount_t *)current; diff --git a/lib/Runtime/Language/JavascriptOperators.cpp b/lib/Runtime/Language/JavascriptOperators.cpp index cf334c29829..7c64a6f4063 100644 --- a/lib/Runtime/Language/JavascriptOperators.cpp +++ b/lib/Runtime/Language/JavascriptOperators.cpp @@ -1098,6 +1098,16 @@ using namespace Js; { return proxy->PropertyKeysTrap(JavascriptProxy::KeysTrapKind::GetOwnPropertyNamesKind, scriptContext); } +#ifdef _CHAKRACOREBUILD + else + { + CustomExternalWrapperObject * wrapper = JavascriptOperators::TryFromVar(instance); + if (wrapper) + { + return wrapper->PropertyKeysTrap(CustomExternalWrapperObject::KeysTrapKind::GetOwnPropertyNamesKind, scriptContext); + } + } +#endif return JavascriptObject::CreateOwnStringPropertiesHelper(object, scriptContext); } @@ -1113,6 +1123,16 @@ using namespace Js; { return proxy->PropertyKeysTrap(JavascriptProxy::KeysTrapKind::GetOwnPropertySymbolKind, scriptContext); } +#ifdef _CHAKRACOREBUILD + else + { + CustomExternalWrapperObject * wrapper = JavascriptOperators::TryFromVar(instance); + if (wrapper) + { + return wrapper->PropertyKeysTrap(CustomExternalWrapperObject::KeysTrapKind::GetOwnPropertySymbolKind, scriptContext); + } + } +#endif return JavascriptObject::CreateOwnSymbolPropertiesHelper(object, scriptContext); } @@ -1127,6 +1147,16 @@ using namespace Js; { return proxy->PropertyKeysTrap(JavascriptProxy::KeysTrapKind::KeysKind, scriptContext); } +#ifdef _CHAKRACOREBUILD + else + { + CustomExternalWrapperObject * wrapper = JavascriptOperators::TryFromVar(instance); + if (wrapper) + { + return wrapper->PropertyKeysTrap(CustomExternalWrapperObject::KeysTrapKind::KeysKind, scriptContext); + } + } +#endif return JavascriptObject::CreateOwnStringSymbolPropertiesHelper(object, scriptContext); } @@ -1162,6 +1192,44 @@ using namespace Js; } return proxyResultToReturn; } +#ifdef _CHAKRACOREBUILD + else + { + CustomExternalWrapperObject * wrapper = JavascriptOperators::TryFromVar(object); + if (wrapper) + { + JavascriptArray* wrapperResult = wrapper->PropertyKeysTrap(CustomExternalWrapperObject::KeysTrapKind::GetOwnEnumerablePropertyNamesKind, scriptContext); + JavascriptArray* wrapperResultToReturn = scriptContext->GetLibrary()->CreateArray(0); + if (wrapperResult != nullptr) + { + // filter enumerable keys + uint32 resultLength = wrapperResult->GetLength(); + Var element; + const Js::PropertyRecord *propertyRecord = nullptr; + uint32 index = 0; + for (uint32 i = 0; i < resultLength; i++) + { + element = wrapperResult->DirectGetItem(i); + + Assert(!VarIs(element)); + + PropertyDescriptor propertyDescriptor; + JavascriptConversion::ToPropertyKey(element, scriptContext, &propertyRecord, nullptr); + if (JavascriptOperators::GetOwnPropertyDescriptor(object, propertyRecord->GetPropertyId(), scriptContext, &propertyDescriptor)) + { + if (propertyDescriptor.IsEnumerable()) + { + wrapperResultToReturn->DirectSetItemAt(index++, CrossSite::MarshalVar(scriptContext, element)); + } + } + } + } + + return wrapperResultToReturn; + } + } +#endif + return JavascriptObject::CreateOwnEnumerableStringPropertiesHelper(object, scriptContext); } @@ -1172,6 +1240,17 @@ using namespace Js; { return proxy->PropertyKeysTrap(JavascriptProxy::KeysTrapKind::KeysKind, scriptContext); } +#ifdef _CHAKRACOREBUILD + else + { + CustomExternalWrapperObject * wrapper = JavascriptOperators::TryFromVar(object); + if (wrapper) + { + return wrapper->PropertyKeysTrap(CustomExternalWrapperObject::KeysTrapKind::EnumerableKeysKind, scriptContext); + } + } +#endif + return JavascriptObject::CreateOwnEnumerableStringSymbolPropertiesHelper(object, scriptContext); } @@ -1571,12 +1650,12 @@ using namespace Js; JIT_HELPER_END(Op_HasProperty); } - BOOL JavascriptOperators::OP_HasOwnProperty(Var instance, PropertyId propertyId, ScriptContext* scriptContext) + BOOL JavascriptOperators::OP_HasOwnProperty(Var instance, PropertyId propertyId, ScriptContext* scriptContext, _In_opt_ PropertyString * propString) { RecyclableObject* object = TaggedNumber::Is(instance) ? scriptContext->GetLibrary()->GetNumberPrototype() : VarTo(instance); - BOOL result = HasOwnProperty(object, propertyId, scriptContext, nullptr); + BOOL result = HasOwnProperty(object, propertyId, scriptContext, propString); return result; } @@ -1842,13 +1921,19 @@ using namespace Js; void JavascriptOperators::TryCacheMissingProperty(Var instance, Var cacheInstance, bool isRoot, PropertyId propertyId, ScriptContext* requestContext, _Inout_ PropertyValueInfo * info) { // Here, any well-behaved subclasses of DynamicObject can opt in to getting included in the missing property cache. - // For now, we only include basic objects and arrays. CustomExternalObject in particular is problematic because in - // some cases it can add new properties without transitioning its type handler. + // For now, we only include basic objects and arrays. if (PHASE_OFF1(MissingPropertyCachePhase) || isRoot || !(DynamicObject::IsBaseDynamicObject(instance) || DynamicObject::IsAnyArray(instance))) { return; } + // CustomExternalObject in particular is problematic because in some cases it can report missing when implicit callsare disabled. + // See CustomExternalObject::GetPropertyQuery for an example. + if (UnsafeVarTo(instance)->GetType()->IsJsrtExternal() && requestContext->GetThreadContext()->IsDisableImplicitCall()) + { + return; + } + DynamicTypeHandler* handler = UnsafeVarTo(instance)->GetDynamicType()->GetTypeHandler(); // Only cache missing property lookups for non-root field loads on objects that have PathTypeHandlers, because only these types have the right behavior @@ -3840,7 +3925,9 @@ using namespace Js; Var JavascriptOperators::OP_GetElementI(Var instance, Var index, ScriptContext* scriptContext) { +#ifdef ENABLE_SPECTRE_RUNTIME_MITIGATIONS instance = BreakSpeculation(instance); +#endif if (TaggedInt::Is(index)) { return GetElementIIntIndex(instance, index, scriptContext); @@ -8731,6 +8818,17 @@ using namespace Js; { return JavascriptProxy::DefineOwnPropertyDescriptor(obj, propId, descriptor, throwOnError, scriptContext); } +#ifdef _CHAKRACOREBUILD + else if (VarIs(obj)) + { + // See if there is a trap for defineProperty. + BOOL wrapperResult = CustomExternalWrapperObject::DefineOwnPropertyDescriptor(obj, propId, descriptor, throwOnError, scriptContext); + if (wrapperResult) + { + return TRUE; + } + } +#endif PropertyDescriptor currentDescriptor; BOOL isCurrentDescriptorDefined = JavascriptOperators::GetOwnPropertyDescriptor(obj, propId, scriptContext, ¤tDescriptor); diff --git a/lib/Runtime/Language/JavascriptOperators.h b/lib/Runtime/Language/JavascriptOperators.h index 55052300a04..fa4d1826da0 100644 --- a/lib/Runtime/Language/JavascriptOperators.h +++ b/lib/Runtime/Language/JavascriptOperators.h @@ -330,7 +330,7 @@ namespace Js static RecyclableObject* OP_GetPrototype(Var instance, ScriptContext* scriptContext); static BOOL OP_HasProperty(Var instance, PropertyId propertyId, ScriptContext* scriptContext); - static BOOL OP_HasOwnProperty(Var instance, PropertyId propertyId, ScriptContext* scriptContext); + static BOOL OP_HasOwnProperty(Var instance, PropertyId propertyId, ScriptContext* scriptContext, _In_opt_ PropertyString * propString = nullptr); static BOOL HasOwnPropertyNoHostObject(Var instance, PropertyId propertyId); static BOOL HasOwnPropertyNoHostObjectForHeapEnum(Var instance, PropertyId propertyId, ScriptContext* scriptContext, Var& getter, Var& setter); static Var GetOwnPropertyNoHostObjectForHeapEnum(Var instance, PropertyId propertyId, ScriptContext* scriptContext, Var& getter, Var &setter); diff --git a/lib/Runtime/Language/RuntimeLanguagePch.h b/lib/Runtime/Language/RuntimeLanguagePch.h index 1b91a3d543c..0f612d89276 100644 --- a/lib/Runtime/Language/RuntimeLanguagePch.h +++ b/lib/Runtime/Language/RuntimeLanguagePch.h @@ -34,6 +34,9 @@ #include "Types/TypePropertyCache.h" #include "Library/JavascriptVariantDate.h" +#ifdef _CHAKRACOREBUILD +#include "Library/CustomExternalWrapperObject.h" +#endif #include "Library/JavascriptProxy.h" #include "Library/JavascriptSymbolObject.h" #include "Library/JavascriptGenerator.h" diff --git a/lib/Runtime/Library/ArrayBuffer.h b/lib/Runtime/Library/ArrayBuffer.h index aec12999b2b..c7822c8254c 100644 --- a/lib/Runtime/Library/ArrayBuffer.h +++ b/lib/Runtime/Library/ArrayBuffer.h @@ -77,7 +77,7 @@ namespace Js virtual void MarshalToScriptContext(Js::ScriptContext * scriptContext) = 0; - ArrayBufferBase(DynamicType *type) : DynamicObject(type), isDetached(false) { } + ArrayBufferBase(DynamicType *type) : DynamicObject(type), isDetached(false), infoBits(0) { } bool IsDetached() { return isDetached; } #if ENABLE_TTD @@ -94,10 +94,14 @@ namespace Js virtual BYTE* GetBuffer() const = 0; virtual bool IsValidVirtualBufferLength(uint length) const { return false; }; + char GetExtraInfoBits() { return infoBits; } + void SetExtraInfoBits(char info) { infoBits = info; } + static int GetIsDetachedOffset() { return offsetof(ArrayBufferBase, isDetached); } protected: Field(bool) isDetached; + Field(char) infoBits; }; template <> bool VarIsImpl(RecyclableObject* obj); @@ -202,8 +206,9 @@ namespace Js RefCountedBuffer *GetBufferContent() { return bufferContent; } static int GetBufferContentsOffset() { return offsetof(ArrayBuffer, bufferContent); } static int GetByteLengthOffset() { return offsetof(ArrayBuffer, bufferLength); } - virtual void AddParent(ArrayBufferParent* parent) override; + + void Detach(); #if defined(TARGET_64) //maximum 2G -1 for amd64 static const uint32 MaxArrayBufferLength = 0x7FFFFFFF; @@ -224,7 +229,6 @@ namespace Js protected: virtual void ReportExternalMemoryFree(); - void Detach(); typedef void __cdecl FreeFn(void* ptr); virtual ArrayBufferDetachedStateBase* CreateDetachedState(RefCountedBuffer * content, DECLSPEC_GUARD_OVERFLOW uint32 bufferLength) = 0; diff --git a/lib/Runtime/Library/CMakeLists.txt b/lib/Runtime/Library/CMakeLists.txt index bcd34ec8e72..f9dbe1140c7 100644 --- a/lib/Runtime/Library/CMakeLists.txt +++ b/lib/Runtime/Library/CMakeLists.txt @@ -33,6 +33,7 @@ set(CRLIB_SOURCE_CODES CommonExternalApiImpl.cpp CompoundString.cpp ConcatString.cpp + CustomExternalWrapperObject.cpp DataView.cpp DateImplementation.cpp ES5Array.cpp diff --git a/lib/Runtime/Library/Chakra.Runtime.Library.vcxproj b/lib/Runtime/Library/Chakra.Runtime.Library.vcxproj index a6f988fa899..14a6672ea6a 100644 --- a/lib/Runtime/Library/Chakra.Runtime.Library.vcxproj +++ b/lib/Runtime/Library/Chakra.Runtime.Library.vcxproj @@ -149,6 +149,7 @@ + @@ -160,6 +161,7 @@ + diff --git a/lib/Runtime/Library/Chakra.Runtime.Library.vcxproj.filters b/lib/Runtime/Library/Chakra.Runtime.Library.vcxproj.filters index dddbac76355..b9efe2ee03c 100644 --- a/lib/Runtime/Library/Chakra.Runtime.Library.vcxproj.filters +++ b/lib/Runtime/Library/Chakra.Runtime.Library.vcxproj.filters @@ -103,6 +103,7 @@ + @@ -232,6 +233,7 @@ + @@ -293,4 +295,4 @@ - \ No newline at end of file + diff --git a/lib/Runtime/Library/CustomExternalWrapperObject.cpp b/lib/Runtime/Library/CustomExternalWrapperObject.cpp new file mode 100644 index 00000000000..3959793eb51 --- /dev/null +++ b/lib/Runtime/Library/CustomExternalWrapperObject.cpp @@ -0,0 +1,1373 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +#include "RuntimeLibraryPch.h" + +#ifdef _CHAKRACOREBUILD +#include "Types/PathTypeHandler.h" + +using namespace Js; + +CustomExternalWrapperType::CustomExternalWrapperType(Js::ScriptContext* scriptContext, JsTraceCallback traceCallback, JsFinalizeCallback finalizeCallback, Js::RecyclableObject * prototype) + : Js::DynamicType( + scriptContext, + Js::TypeIds_Object, + prototype, + nullptr, + Js::PathTypeHandlerNoAttr::New(scriptContext, scriptContext->GetLibrary()->GetRootPath(), 0, 0, 0, true, true), + true, + true) + , jsTraceCallback(traceCallback) + , jsFinalizeCallback(finalizeCallback) +{ + this->jsGetterSetterInterceptor = RecyclerNewStructZ(scriptContext->GetRecycler(), JsGetterSetterInterceptor); + this->flags |= TypeFlagMask_JsrtExternal; +} + +CustomExternalWrapperObject::CustomExternalWrapperObject(CustomExternalWrapperType * type, void *data, uint inlineSlotSize) : + Js::DynamicObject(type, false/* initSlots*/) +{ + if (inlineSlotSize != 0) + { + this->slotType = SlotType::Inline; + this->u.inlineSlotSize = inlineSlotSize; + if (data) + { + memcpy_s(this->GetInlineSlots(), inlineSlotSize, data, inlineSlotSize); + } + } + else + { + this->slotType = SlotType::External; + this->u.slot = data; + } +} + +/* static */ +CustomExternalWrapperObject* CustomExternalWrapperObject::Create(void *data, uint inlineSlotSize, JsTraceCallback traceCallback, JsFinalizeCallback finalizeCallback, JsGetterSetterInterceptor ** getterSetterInterceptor, Js::RecyclableObject * prototype, Js::ScriptContext *scriptContext) +{ + if (prototype == nullptr) + { + prototype = scriptContext->GetLibrary()->GetObjectPrototype(); + } + + Js::DynamicType * dynamicType = scriptContext->GetLibrary()->GetCachedCustomExternalWrapperType(reinterpret_cast(traceCallback), reinterpret_cast(finalizeCallback), reinterpret_cast(*getterSetterInterceptor), reinterpret_cast(prototype)); + if (dynamicType == nullptr) + { + dynamicType = RecyclerNew(scriptContext->GetRecycler(), CustomExternalWrapperType, scriptContext, traceCallback, finalizeCallback, prototype); + *getterSetterInterceptor = reinterpret_cast(dynamicType)->GetJsGetterSetterInterceptor(); + scriptContext->GetLibrary()->CacheCustomExternalWrapperType(reinterpret_cast(traceCallback), reinterpret_cast(finalizeCallback), reinterpret_cast(*getterSetterInterceptor), reinterpret_cast(prototype), dynamicType); + } + else + { + if (*getterSetterInterceptor == nullptr) + { + *getterSetterInterceptor = reinterpret_cast(dynamicType)->GetJsGetterSetterInterceptor(); + } + else + { + Assert(*getterSetterInterceptor == reinterpret_cast(dynamicType)->GetJsGetterSetterInterceptor()); + } + } + + Assert(dynamicType->IsJsrtExternal()); + + CustomExternalWrapperObject * externalObject; + if (traceCallback != nullptr) + { + externalObject = RecyclerNewTrackedPlus(scriptContext->GetRecycler(), inlineSlotSize, CustomExternalWrapperObject, static_cast(dynamicType), data, inlineSlotSize); + } + else if (finalizeCallback != nullptr) + { + externalObject = RecyclerNewFinalizedPlus(scriptContext->GetRecycler(), inlineSlotSize, CustomExternalWrapperObject, static_cast(dynamicType), data, inlineSlotSize); + } + else + { + externalObject = RecyclerNewPlus(scriptContext->GetRecycler(), inlineSlotSize, CustomExternalWrapperObject, static_cast(dynamicType), data, inlineSlotSize); + } + + return externalObject; +} + +BOOL CustomExternalWrapperObject::EnsureInitialized(ScriptContext* requestContext) +{ + ThreadContext* threadContext = requestContext->GetThreadContext(); + if (this->initialized) + { + return TRUE; + } + void* initializeTrap = this->GetExternalType()->GetJsGetterSetterInterceptor()->initializeTrap; + if (initializeTrap == nullptr) + { + return TRUE; + } + if (threadContext->IsDisableImplicitCall()) + { + threadContext->AddImplicitCallFlags(Js::ImplicitCall_External); + return FALSE; + } + + this->initialized = true; + JavascriptFunction * initializeMethod = Js::VarTo(initializeTrap); + + Js::RecyclableObject * targetObj = this; + threadContext->ExecuteImplicitCall(initializeMethod, Js::ImplicitCall_Accessor, [=]()->Js::Var + { + return CALL_FUNCTION(threadContext, initializeMethod, Js::CallInfo(Js::CallFlags_Value, 1), targetObj); + }); + return TRUE; +} + +CustomExternalWrapperObject * CustomExternalWrapperObject::Clone(CustomExternalWrapperObject * source, ScriptContext * scriptContext) +{ + Js::CustomExternalWrapperType * externalType = source->GetExternalType(); + Js::JsGetterSetterInterceptor * originalInterceptors = externalType->GetJsGetterSetterInterceptor(); + Js::JsGetterSetterInterceptor * newInterceptors = originalInterceptors; + Js::CustomExternalWrapperObject * target = Js::CustomExternalWrapperObject::Create( + source->GetSlotData(), + source->GetInlineSlotSize(), + externalType->GetJsTraceCallback(), + externalType->GetJsFinalizeCallback(), + &newInterceptors, + source->GetPrototype(), + scriptContext); + target->initialized = source->initialized; + + bool success = target->TryCopy(source, true); + AssertOrFailFast(success); + + //TODO:akatti: We will always used a cached type, so the following code can be removed. + // If we are using type from the cache we don't need to copy the interceptors over. + if (newInterceptors != originalInterceptors) + { + memcpy_s(newInterceptors, sizeof(Js::JsGetterSetterInterceptor), originalInterceptors, sizeof(Js::JsGetterSetterInterceptor)); + } + + return target; +} + +BOOL CustomExternalWrapperObject::IsObjectAlive() +{ + return !this->GetScriptContext()->IsClosed(); +} + +BOOL CustomExternalWrapperObject::VerifyObjectAlive() +{ + Js::ScriptContext* scriptContext = GetScriptContext(); + if (!scriptContext->VerifyAlive()) + { + return FALSE; + } + + // Perform an extended host object invalidation check only for external host objects. + if (scriptContext->IsInvalidatedForHostObjects()) + { + if (!scriptContext->GetThreadContext()->RecordImplicitException()) + return FALSE; + Js::JavascriptError::MapAndThrowError(scriptContext, E_ACCESSDENIED); + } + return TRUE; +} + +BOOL CustomExternalWrapperObject::Equals(__in Var other, __out BOOL* value, ScriptContext* requestContext) +{ + // Reject implicit call + ThreadContext* threadContext = requestContext->GetThreadContext(); + if (threadContext->IsDisableImplicitCall()) + { + threadContext->AddImplicitCallFlags(Js::ImplicitCall_External); + *value = FALSE; + return FALSE; + } + + // We need to implement comparison to other by reference in case the object + // is in the left side of the comparison, and does not call a toString + // method (like different objects) when compared to string. For Node, such + // comparision is used for Buffers. + *value = (other == this); + return true; +} + +BOOL CustomExternalWrapperObject::StrictEquals(__in Var other, __out BOOL* value, ScriptContext* requestContext) +{ + *value = FALSE; + // Reject implicit call + ThreadContext* threadContext = requestContext->GetThreadContext(); + if (threadContext->IsDisableImplicitCall()) + { + threadContext->AddImplicitCallFlags(Js::ImplicitCall_External); + return FALSE; + } + + // We need to implement comparison to other by reference in case the object + // is in the left side of the comparison, and does not call a toString + // method (like different objects) when compared to string. For Node, such + // comparision is used for Buffers. + *value = (other == this); + return true; +} + +void CustomExternalWrapperObject::Mark(Recycler * recycler) +{ + recycler->SetNeedExternalWrapperTracing(); + JsTraceCallback traceCallback = this->GetExternalType()->GetJsTraceCallback(); + Assert(nullptr != traceCallback); + traceCallback(this->GetSlotData()); +} + +void CustomExternalWrapperObject::Finalize(bool isShutdown) +{ + JsFinalizeCallback finalizeCallback = this->GetExternalType()->GetJsFinalizeCallback(); + Assert(this->GetExternalType()->GetJsTraceCallback() != nullptr || finalizeCallback != nullptr); + if (nullptr != finalizeCallback) + { + finalizeCallback(this->GetSlotData()); + } +} + +void CustomExternalWrapperObject::Dispose(bool isShutdown) +{ +} + +void * CustomExternalWrapperObject::GetSlotData() const +{ + return this->slotType == SlotType::External + ? unsafe_write_barrier_cast(this->u.slot) + : GetInlineSlots(); +} + +void CustomExternalWrapperObject::SetSlotData(void * data) +{ + this->slotType = SlotType::External; + this->u.slot = data; +} + +int CustomExternalWrapperObject::GetInlineSlotSize() const +{ + return this->slotType == SlotType::External + ? 0 + : this->u.inlineSlotSize; +} + +void* CustomExternalWrapperObject::GetInlineSlots() const +{ + return this->slotType == SlotType::External + ? nullptr + : (void*)((uintptr_t)this + sizeof(CustomExternalWrapperObject)); +} + +Js::DynamicType* CustomExternalWrapperObject::DuplicateType() +{ + return RecyclerNew(this->GetScriptContext()->GetRecycler(), CustomExternalWrapperType, this->GetExternalType()); +} + +void CustomExternalWrapperObject::SetPrototype(RecyclableObject* newPrototype) +{ + if (!this->VerifyObjectAlive()) + { + return; + } + + // setting the value could be deferred and now we are on a different context from + // make sure the value has the same context as the containing object. + newPrototype = VarTo(Js::CrossSite::MarshalVar(this->GetScriptContext(), newPrototype)); + DynamicObject::SetPrototype(newPrototype); +} + +Js::Var CustomExternalWrapperObject::GetValueFromDescriptor(Js::Var instance, Js::PropertyDescriptor propertyDescriptor, Js::ScriptContext * requestContext) +{ + if (propertyDescriptor.ValueSpecified()) + { + return propertyDescriptor.GetValue(); + } + if (propertyDescriptor.GetterSpecified()) + { + return Js::JavascriptOperators::CallGetter(VarTo(propertyDescriptor.GetGetter()), instance, requestContext); + } + Assert(FALSE); + return requestContext->GetLibrary()->GetUndefined(); +} + +void CustomExternalWrapperObject::PropertyIdFromInt(uint32 index, Js::PropertyRecord const** propertyRecord) +{ + char16 buffer[22]; + int pos = Js::TaggedInt::ToBuffer(index, buffer, _countof(buffer)); + + GetScriptContext()->GetOrAddPropertyRecord((LPCWSTR)buffer + pos, (_countof(buffer) - 1) - pos, propertyRecord); +} + +Js::Var CustomExternalWrapperObject::GetName(Js::ScriptContext* requestContext, Js::PropertyId propertyId, Var * isPropertyNameNumeric, Var * propertyNameNumericValue) +{ + const Js::PropertyRecord* propertyRecord = requestContext->GetThreadContext()->GetPropertyName(propertyId); + Js::Var name; + if (propertyRecord->IsSymbol()) + { + name = requestContext->GetSymbol(propertyRecord); + } + else + { + name = requestContext->GetPropertyString(propertyRecord); + } + + *isPropertyNameNumeric = propertyRecord->IsNumeric() ? requestContext->GetLibrary()->GetTrue() : requestContext->GetLibrary()->GetFalse(); + *propertyNameNumericValue = propertyRecord->IsNumeric() ? JavascriptNumber::ToVar(propertyRecord->GetNumericValue(), requestContext) : nullptr; + return name; +} + +template +BOOL CustomExternalWrapperObject::GetPropertyTrap(Js::Var instance, Js::PropertyDescriptor * propertyDescriptor, Fn fn, GetPropertyNameFunc getPropertyName, Js::ScriptContext * requestContext) +{ + PROBE_STACK(GetScriptContext(), Js::Constants::MinStackDefault); + + // Reject implicit call + ThreadContext* threadContext = requestContext->GetThreadContext(); + if (threadContext->IsDisableImplicitCall()) + { + threadContext->AddImplicitCallFlags(Js::ImplicitCall_External); + return FALSE; + } + + if (!this->EnsureInitialized(requestContext)) + { + return FALSE; + } + + Js::RecyclableObject * targetObj = this; + CustomExternalWrapperType * type = this->GetExternalType(); + Js::JavascriptFunction* getGetMethod = nullptr; + if (type->GetJsGetterSetterInterceptor()->getTrap != nullptr) + { + getGetMethod = Js::VarTo(type->GetJsGetterSetterInterceptor()->getTrap); + } + + if (nullptr == getGetMethod || requestContext->IsHeapEnumInProgress()) + { + return fn(targetObj); + } + + Js::Var isPropertyNameNumeric; + Js::Var propertyNameNumericValue; + Js::Var propertyName = getPropertyName(requestContext, &isPropertyNameNumeric, &propertyNameNumericValue); + + Js::Var getGetResult = threadContext->ExecuteImplicitCall(getGetMethod, Js::ImplicitCall_Accessor, [=]()->Js::Var + { + return CALL_FUNCTION(threadContext, getGetMethod, Js::CallInfo(Js::CallFlags_Value, 4), targetObj, propertyName, isPropertyNameNumeric, propertyNameNumericValue); + }); + + Js::TypeId getResultTypeId = Js::JavascriptOperators::GetTypeId(getGetResult); + if (getResultTypeId == Js::TypeIds_Undefined) + { + return FALSE; + } + + propertyDescriptor->SetValue(getGetResult); + return TRUE; +} + +template +BOOL CustomExternalWrapperObject::HasPropertyTrap(Fn fn, GetPropertyNameFunc getPropertyName) +{ + PROBE_STACK(GetScriptContext(), Js::Constants::MinStackDefault); + + // Reject implicit call + ThreadContext* threadContext = GetScriptContext()->GetThreadContext(); + if (threadContext->IsDisableImplicitCall()) + { + threadContext->AddImplicitCallFlags(Js::ImplicitCall_External); + return FALSE; + } + + // Caller does not pass requestContext. Retrieve from host scriptContext stack. + Js::ScriptContext* requestContext = + threadContext->GetPreviousHostScriptContext()->GetScriptContext(); + + if (!this->EnsureInitialized(requestContext)) + { + return FALSE; + } + + Js::RecyclableObject *targetObj = this; + CustomExternalWrapperType * type = this->GetExternalType(); + Js::JavascriptFunction* hasMethod = nullptr; + if (type->GetJsGetterSetterInterceptor()->hasTrap != nullptr) + { + hasMethod = Js::VarTo(type->GetJsGetterSetterInterceptor()->hasTrap); + } + + if (nullptr == hasMethod || requestContext->IsHeapEnumInProgress()) + { + return fn(targetObj); + } + + Js::Var isPropertyNameNumeric; + Js::Var propertyNameNumericValue; + Js::Var propertyName = getPropertyName(requestContext, &isPropertyNameNumeric, &propertyNameNumericValue); + + Js::Var getHasResult = threadContext->ExecuteImplicitCall(hasMethod, Js::ImplicitCall_Accessor, [=]()->Js::Var + { + return CALL_FUNCTION(threadContext, hasMethod, Js::CallInfo(Js::CallFlags_Value, 4), targetObj, propertyName, isPropertyNameNumeric, propertyNameNumericValue); + }); + + BOOL hasProperty = Js::JavascriptConversion::ToBoolean(getHasResult, requestContext); + return hasProperty; +} + +Js::PropertyQueryFlags CustomExternalWrapperObject::HasPropertyQuery(Js::PropertyId propertyId, _Inout_opt_ Js::PropertyValueInfo* info) +{ + auto fn = [&](RecyclableObject* object)->BOOL { + return JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasPropertyQuery(propertyId, info)); + }; + auto getPropertyName = [&](Js::ScriptContext * requestContext, Js::Var * isPropertyNameNumeric, Js::Var * propertyNameNumericValue)->Js::Var + { + return GetName(requestContext, propertyId, isPropertyNameNumeric, propertyNameNumericValue); + }; + return Js::JavascriptConversion::BooleanToPropertyQueryFlags(HasPropertyTrap(fn, getPropertyName)); +} + +BOOL CustomExternalWrapperObject::GetPropertyDescriptorTrap(Js::PropertyId propertyId, Js::PropertyDescriptor* resultDescriptor, Js::ScriptContext* requestContext) +{ + PROBE_STACK(GetScriptContext(), Js::Constants::MinStackDefault); + + // Reject implicit call + ThreadContext* threadContext = requestContext->GetThreadContext(); + if (threadContext->IsDisableImplicitCall()) + { + threadContext->AddImplicitCallFlags(Js::ImplicitCall_External); + return FALSE; + } + + if (!this->EnsureInitialized(requestContext)) + { + return FALSE; + } + + Js::RecyclableObject * targetObj = this; + + CustomExternalWrapperType * type = this->GetExternalType(); + Js::JavascriptFunction* gOPDMethod = nullptr; + if (type->GetJsGetterSetterInterceptor()->getOwnPropertyDescriptorTrap != nullptr) + { + gOPDMethod = Js::VarTo(type->GetJsGetterSetterInterceptor()->getOwnPropertyDescriptorTrap); + } + + if (GetScriptContext()->IsHeapEnumInProgress()) + { + return FALSE; + } + + if (nullptr == gOPDMethod) + { + Var getter, setter; + if (false == JavascriptOperators::GetOwnAccessors(this, propertyId, &getter, &setter, requestContext)) + { + Var value = nullptr; + if (false == JavascriptOperators::GetOwnProperty(this, propertyId, &value, requestContext, nullptr)) + { + return FALSE; + } + if (nullptr != value) + { + resultDescriptor->SetValue(value); + } + + resultDescriptor->SetWritable(FALSE != this->IsWritable(propertyId)); + } + else + { + if (nullptr == getter) + { + getter = requestContext->GetLibrary()->GetUndefined(); + } + resultDescriptor->SetGetter(getter); + + if (nullptr == setter) + { + setter = requestContext->GetLibrary()->GetUndefined(); + } + resultDescriptor->SetSetter(setter); + } + + resultDescriptor->SetConfigurable(FALSE != this->IsConfigurable(propertyId)); + resultDescriptor->SetEnumerable(FALSE != this->IsEnumerable(propertyId)); + return TRUE; + } + + Js::Var isPropertyNameNumeric; + Js::Var propertyNameNumericValue; + Js::Var propertyName = GetName(requestContext, propertyId, &isPropertyNameNumeric, &propertyNameNumericValue); + + Assert(Js::VarIs(propertyName) || Js::VarIs(propertyName)); + + Js::Var getResult = threadContext->ExecuteImplicitCall(gOPDMethod, Js::ImplicitCall_Accessor, [=]()->Js::Var + { + return CALL_FUNCTION(threadContext, gOPDMethod, Js::CallInfo(Js::CallFlags_Value, 4), targetObj, propertyName, isPropertyNameNumeric, propertyNameNumericValue); + }); + + Js::TypeId getResultTypeId = Js::JavascriptOperators::GetTypeId(getResult); + if (Js::StaticType::Is(getResultTypeId) && getResultTypeId != Js::TypeIds_Undefined) + { + Js::JavascriptError::ThrowTypeError(requestContext, JSERR_NeedObject, _u("getOwnPropertyDescriptor")); + } + + BOOL toProperty = Js::JavascriptOperators::ToPropertyDescriptor(getResult, resultDescriptor, requestContext); + Js::JavascriptOperators::CompletePropertyDescriptor(resultDescriptor, nullptr, requestContext); + return toProperty; +} + +BOOL CustomExternalWrapperObject::GetOwnPropertyDescriptor(Js::RecyclableObject * obj, Js::PropertyId propertyId, Js::ScriptContext * requestContext, Js::PropertyDescriptor * propertyDescriptor) +{ + CustomExternalWrapperObject * customObject = VarTo(obj); + return customObject->GetPropertyDescriptorTrap(propertyId, propertyDescriptor, requestContext); +} + +BOOL CustomExternalWrapperObject::DefineOwnPropertyDescriptor(Js::RecyclableObject * obj, Js::PropertyId propId, const Js::PropertyDescriptor& descriptor, bool throwOnError, Js::ScriptContext * requestContext) +{ + PROBE_STACK(requestContext, Js::Constants::MinStackDefault); + + // Reject implicit call + ThreadContext* threadContext = requestContext->GetThreadContext(); + if (threadContext->IsDisableImplicitCall()) + { + threadContext->AddImplicitCallFlags(Js::ImplicitCall_External); + return FALSE; + } + + CustomExternalWrapperObject * customObject = VarTo(obj); + + if (!customObject->EnsureInitialized(requestContext)) + { + return FALSE; + } + + Js::RecyclableObject * targetObj = obj; + + CustomExternalWrapperType * type = customObject->GetExternalType(); + Js::JavascriptFunction* defineOwnPropertyMethod = nullptr; + if (type->GetJsGetterSetterInterceptor()->definePropertyTrap != nullptr) + { + defineOwnPropertyMethod = Js::VarTo(type->GetJsGetterSetterInterceptor()->definePropertyTrap); + } + + Assert(!requestContext->IsHeapEnumInProgress()); + if (nullptr == defineOwnPropertyMethod) + { + Js::PropertyDescriptor desc = descriptor; + + if(desc.ValueSpecified()) + { + // setting the value could be deferred and now we are on a different context from + // make sure the value has the same context as the containing object. + desc.SetValue(Js::CrossSite::MarshalVar(targetObj->GetScriptContext(), descriptor.GetValue())); + } + + PropertyDescriptor currentDescriptor; + BOOL isCurrentDescriptorDefined = JavascriptOperators::GetOwnPropertyDescriptor(obj, propId, requestContext, ¤tDescriptor); + + bool isExtensible = !!obj->IsExtensible(); + return Js::JavascriptOperators::ValidateAndApplyPropertyDescriptor(obj, propId, desc, isCurrentDescriptorDefined ? ¤tDescriptor : nullptr, isExtensible, throwOnError, requestContext); + } + + Js::Var descVar = descriptor.GetOriginal(); + if (descVar == nullptr) + { + descVar = Js::JavascriptOperators::FromPropertyDescriptor(descriptor, requestContext); + } + + Js::Var isPropertyNameNumeric; + Js::Var propertyNameNumericValue; + Js::Var propertyName = customObject->GetName(requestContext, propId, &isPropertyNameNumeric, &propertyNameNumericValue); + + Js::Var definePropertyResult = threadContext->ExecuteImplicitCall(defineOwnPropertyMethod, Js::ImplicitCall_Accessor, [=]()->Js::Var + { + return CALL_FUNCTION(threadContext, defineOwnPropertyMethod, Js::CallInfo(Js::CallFlags_Value, 5), targetObj, propertyName, isPropertyNameNumeric, propertyNameNumericValue, descVar); + }); + + BOOL defineResult = Js::JavascriptConversion::ToBoolean(definePropertyResult, requestContext); + if (defineResult) + { + return defineResult; + } + + Js::PropertyDescriptor targetDescriptor; + BOOL hasProperty = Js::JavascriptOperators::GetOwnPropertyDescriptor(targetObj, propId, requestContext, &targetDescriptor); + BOOL isExtensible = targetObj->IsExtensible(); + BOOL settingConfigFalse = (descriptor.ConfigurableSpecified() && !descriptor.IsConfigurable()); + if (!hasProperty) + { + if (!isExtensible || settingConfigFalse) + { + Js::JavascriptError::ThrowTypeError(requestContext, JSERR_InconsistentTrapResult, _u("defineProperty")); + } + } + else + { + if (!Js::JavascriptOperators::IsCompatiblePropertyDescriptor(descriptor, hasProperty ? &targetDescriptor : nullptr, !!isExtensible, true, requestContext)) + { + Js::JavascriptError::ThrowTypeError(requestContext, JSERR_InconsistentTrapResult, _u("defineProperty")); + } + if (settingConfigFalse && targetDescriptor.IsConfigurable()) + { + Js::JavascriptError::ThrowTypeError(requestContext, JSERR_InconsistentTrapResult, _u("defineProperty")); + } + } + return hasProperty; +} + +BOOL CustomExternalWrapperObject::SetPropertyTrap(Js::Var receiver, SetPropertyTrapKind setPropertyTrapKind, Js::JavascriptString * propertyNameString, Js::Var newValue, Js::ScriptContext * requestContext, Js::PropertyOperationFlags propertyOperationFlags) +{ + auto getPropertyName = [&](Js::ScriptContext * requestContext, Js::Var * isPropertyNameNumeric, Js::Var * propertyNameNumericValue)->Js::Var + { + const Js::PropertyRecord* propertyRecord; + propertyNameString->GetPropertyRecord(&propertyRecord); + return GetName(requestContext, propertyRecord->GetPropertyId(), isPropertyNameNumeric, propertyNameNumericValue); + }; + auto fn = [&]()->BOOL + { + // setting the value could be deferred and now we are on a different context from + // make sure the value has the same context as the containing object. + newValue = Js::CrossSite::MarshalVar(this->GetScriptContext(), newValue); + return DynamicObject::SetProperty(propertyNameString, newValue, propertyOperationFlags, nullptr); + }; + return SetPropertyTrap(receiver, setPropertyTrapKind, getPropertyName, newValue, requestContext, propertyOperationFlags, FALSE, fn); +} + +template +BOOL CustomExternalWrapperObject::SetPropertyTrap(Js::Var receiver, SetPropertyTrapKind setPropertyTrapKind, GetPropertyNameFunc getPropertyName, Js::Var newValue, Js::ScriptContext * requestContext, Js::PropertyOperationFlags propertyOperationFlags, BOOL skipPrototypeCheck, Fn fn) +{ + PROBE_STACK(GetScriptContext(), Js::Constants::MinStackDefault); + + // Reject implicit call + ThreadContext* threadContext = requestContext->GetThreadContext(); + if (threadContext->IsDisableImplicitCall()) + { + threadContext->AddImplicitCallFlags(Js::ImplicitCall_External); + return FALSE; + } + + if (!this->EnsureInitialized(requestContext)) + { + return FALSE; + } + + Js::RecyclableObject *targetObj = this; + CustomExternalWrapperType * type = this->GetExternalType(); + Js::JavascriptFunction* setMethod = nullptr; + if (type->GetJsGetterSetterInterceptor()->setTrap != nullptr) + { + setMethod = Js::VarTo(type->GetJsGetterSetterInterceptor()->setTrap); + } + else + { + return fn(); + } + + Assert(!GetScriptContext()->IsHeapEnumInProgress()); + Js::Var isPropertyNameNumeric; + Js::Var propertyNameNumericValue; + Js::Var propertyName = getPropertyName(requestContext, &isPropertyNameNumeric, &propertyNameNumericValue); + + if (nullptr != setMethod) + { + Js::Var setPropertyResult = threadContext->ExecuteImplicitCall(setMethod, Js::ImplicitCall_Accessor, [=]()->Js::Var + { + return CALL_FUNCTION(threadContext, setMethod, Js::CallInfo(Js::CallFlags_Value, 5), targetObj, propertyName, isPropertyNameNumeric, propertyNameNumericValue, newValue); + }); + + BOOL setResult = Js::JavascriptConversion::ToBoolean(setPropertyResult, requestContext); + return setResult; + } + + return FALSE; +} + +Js::PropertyQueryFlags CustomExternalWrapperObject::GetPropertyQuery(Js::Var originalInstance, Js::PropertyId propertyId, Js::Var* value, Js::PropertyValueInfo* info, Js::ScriptContext* requestContext) +{ + if (!this->VerifyObjectAlive()) return Js::PropertyQueryFlags::Property_NotFound; + Js::PropertyDescriptor result; + + auto fn = [&](Js::RecyclableObject* object)-> BOOL { + BOOL found = JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext)); + result.SetValue(*value); + return found; + }; + auto getPropertyName = [&](Js::ScriptContext * requestContext, Js::Var * isPropertyNameNumeric, Js::Var * propertyNameNumericValue)->Js::Var + { + return GetName(requestContext, propertyId, isPropertyNameNumeric, propertyNameNumericValue); + }; + BOOL foundProperty = GetPropertyTrap(originalInstance, &result, fn, getPropertyName, requestContext); + if (!foundProperty) + { + *value = requestContext->GetMissingPropertyResult(); + } + else + { + *value = GetValueFromDescriptor(originalInstance, result, requestContext); + } + return Js::JavascriptConversion::BooleanToPropertyQueryFlags(foundProperty); +} + +Js::PropertyQueryFlags CustomExternalWrapperObject::GetPropertyQuery(Js::Var originalInstance, Js::JavascriptString* propertyNameString, Js::Var* value, Js::PropertyValueInfo* info, Js::ScriptContext* requestContext) +{ + if (!this->VerifyObjectAlive()) return Js::PropertyQueryFlags::Property_NotFound; + Js::PropertyDescriptor result; + + auto fn = [&](Js::RecyclableObject* object)-> BOOL { + BOOL found = JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetPropertyQuery(originalInstance, propertyNameString, value, info, requestContext)); + result.SetValue(*value); + return found; + }; + + auto getPropertyName = [&](Js::ScriptContext * requestContext, Js::Var * isPropertyNameNumeric, Js::Var * propertyNameNumericValue)->Js::Var + { + const Js::PropertyRecord* propertyRecord; + propertyNameString->GetPropertyRecord(&propertyRecord); + return GetName(requestContext, propertyRecord->GetPropertyId(), isPropertyNameNumeric, propertyNameNumericValue); + }; + + BOOL foundProperty = GetPropertyTrap(originalInstance, &result, fn, getPropertyName, requestContext); + if (!foundProperty) + { + *value = requestContext->GetMissingPropertyResult(); + } + else + { + *value = GetValueFromDescriptor(originalInstance, result, requestContext); + } + return Js::JavascriptConversion::BooleanToPropertyQueryFlags(foundProperty); +} + +Js::PropertyQueryFlags CustomExternalWrapperObject::GetPropertyReferenceQuery(Js::Var originalInstance, Js::PropertyId propertyId, Js::Var* value, Js::PropertyValueInfo* info, Js::ScriptContext* requestContext) +{ + if (!this->VerifyObjectAlive()) return Js::PropertyQueryFlags::Property_NotFound; + Js::PropertyDescriptor result; + + auto fn = [&](Js::RecyclableObject* object)-> BOOL { + BOOL found = JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetPropertyReferenceQuery(originalInstance, propertyId, value, info, requestContext)); + result.SetValue(*value); + return found; + }; + + auto getPropertyName = [&](Js::ScriptContext * requestContext, Js::Var * isPropertyNameNumeric, Js::Var * propertyNameNumericValue)->Js::Var + { + return GetName(requestContext, propertyId, isPropertyNameNumeric, propertyNameNumericValue); + }; + + BOOL foundProperty = GetPropertyTrap(originalInstance, &result, fn, getPropertyName, requestContext); + if (!foundProperty) + { + *value = requestContext->GetMissingPropertyResult(); + } + else + { + *value = GetValueFromDescriptor(originalInstance, result, requestContext); + } + return Js::JavascriptConversion::BooleanToPropertyQueryFlags(foundProperty); +} + +Js::PropertyQueryFlags CustomExternalWrapperObject::HasItemQuery(uint32 index) +{ + auto fn = [&](Js::RecyclableObject* object)-> BOOL { + return JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasItemQuery(index)); + }; + + auto getPropertyName = [&](Js::ScriptContext * requestContext, Js::Var * isPropertyNameNumeric, Js::Var * propertyNameNumericValue)->Js::Var + { + *isPropertyNameNumeric = requestContext->GetLibrary()->GetTrue(); + *propertyNameNumericValue = JavascriptNumber::ToVar(index, requestContext); + return nullptr; + }; + + return Js::JavascriptConversion::BooleanToPropertyQueryFlags(HasPropertyTrap(fn, getPropertyName)); +} + +BOOL CustomExternalWrapperObject::HasOwnItem(uint32 index) +{ + auto fn = [&](Js::RecyclableObject* object)-> BOOL { + return DynamicObject::HasOwnItem(index); + }; + auto getPropertyName = [&](Js::ScriptContext * requestContext, Js::Var * isPropertyNameNumeric, Js::Var * propertyNameNumericValue)->Js::Var + { + *isPropertyNameNumeric = requestContext->GetLibrary()->GetTrue(); + *propertyNameNumericValue = JavascriptNumber::ToVar(index, requestContext); + return nullptr; + }; + + return HasPropertyTrap(fn, getPropertyName); +} + +Js::PropertyQueryFlags CustomExternalWrapperObject::GetItemQuery(Js::Var originalInstance, uint32 index, Js::Var* value, Js::ScriptContext * requestContext) +{ + if (!this->VerifyObjectAlive()) return Js::PropertyQueryFlags::Property_NotFound; + Js::PropertyDescriptor result; + + auto fn = [&](Js::RecyclableObject* object)-> BOOL { + BOOL found = JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetItemQuery(originalInstance, index, value, requestContext)); + result.SetValue(*value); + return found; + }; + + auto getPropertyName = [&](Js::ScriptContext * requestContext, Js::Var * isPropertyNameNumeric, Js::Var * propertyNameNumericValue)->Js::Var + { + *isPropertyNameNumeric = requestContext->GetLibrary()->GetTrue(); + *propertyNameNumericValue = JavascriptNumber::ToVar(index, requestContext); + return nullptr; + }; + + BOOL foundProperty = GetPropertyTrap(originalInstance, &result, fn, getPropertyName, requestContext); + if (!foundProperty) + { + *value = requestContext->GetMissingItemResult(); + } + else + { + *value = GetValueFromDescriptor(originalInstance, result, requestContext); + } + return Js::JavascriptConversion::BooleanToPropertyQueryFlags(foundProperty); +} + +Js::PropertyQueryFlags CustomExternalWrapperObject::GetItemReferenceQuery(Js::Var originalInstance, uint32 index, Js::Var* value, Js::ScriptContext * requestContext) +{ + if (!this->VerifyObjectAlive()) return Js::PropertyQueryFlags::Property_NotFound; + + Js::PropertyDescriptor result; + auto fn = [&](Js::RecyclableObject* object)-> BOOL { + BOOL found = JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetItemReferenceQuery(originalInstance, index, value, requestContext)); + result.SetValue(*value); + return found; + }; + + auto getPropertyName = [&](Js::ScriptContext * requestContext, Js::Var * isPropertyNameNumeric, Js::Var * propertyNameNumericValue)->Js::Var + { + *isPropertyNameNumeric = requestContext->GetLibrary()->GetTrue(); + *propertyNameNumericValue = JavascriptNumber::ToVar(index, requestContext); + return nullptr; + }; + + BOOL foundProperty = GetPropertyTrap(originalInstance, &result, fn, getPropertyName, requestContext); + if (!foundProperty) + { + *value = requestContext->GetMissingItemResult(); + } + else + { + *value = GetValueFromDescriptor(originalInstance, result, requestContext); + } + return Js::JavascriptConversion::BooleanToPropertyQueryFlags(foundProperty); +} + +BOOL CustomExternalWrapperObject::SetItem(uint32 index, Js::Var value, Js::PropertyOperationFlags flags) +{ + if (!this->VerifyObjectAlive()) return FALSE; + + auto getPropertyName = [&](Js::ScriptContext * requestContext, Js::Var * isPropertyNameNumeric, Js::Var * propertyNameNumericValue)->Js::Var + { + *isPropertyNameNumeric = requestContext->GetLibrary()->GetTrue(); + *propertyNameNumericValue = JavascriptNumber::ToVar(index, requestContext); + return nullptr; + }; + + auto fn = [&]()->BOOL + { + // setting the value could be deferred and now we are on a different context from + // make sure the value has the same context as the containing object. + value = Js::CrossSite::MarshalVar(this->GetScriptContext(), value); + return DynamicObject::SetItem(index, value, flags); + }; + BOOL trapResult = SetPropertyTrap(this, CustomExternalWrapperObject::SetPropertyTrapKind::SetItemKind, getPropertyName, value, GetScriptContext(), flags, FALSE, fn); + if (!trapResult) + { + // setting the value could be deferred and now we are on a different context from + // make sure the value has the same context as the containing object. + value = Js::CrossSite::MarshalVar(this->GetScriptContext(), value); + return Js::DynamicObject::SetItem(index, value, flags); + } + + return TRUE; +} + +BOOL CustomExternalWrapperObject::DeleteItem(uint32 index, Js::PropertyOperationFlags flags) +{ + if (!this->VerifyObjectAlive()) return FALSE; + const PropertyRecord* propertyRecord = nullptr; + PropertyIdFromInt(index, &propertyRecord); + return this->DeleteProperty(propertyRecord->GetPropertyId(), flags); +} + +BOOL CustomExternalWrapperObject::GetEnumerator(Js::JavascriptStaticEnumerator * enumerator, Js::EnumeratorFlags flags, Js::ScriptContext* requestContext, Js::EnumeratorCache * enumeratorCache) +{ + if (!this->VerifyObjectAlive()) return FALSE; + // Reject implicit call + ThreadContext* threadContext = requestContext->GetThreadContext(); + if (threadContext->IsDisableImplicitCall()) + { + threadContext->AddImplicitCallFlags(Js::ImplicitCall_External); + return FALSE; + } + + if (!this->EnsureInitialized(requestContext)) + { + return FALSE; + } + + CustomExternalWrapperType * type = this->GetExternalType(); + Js::JavascriptFunction* getEnumeratorMethod = nullptr; + if (type->GetJsGetterSetterInterceptor()->enumerateTrap != nullptr) + { + getEnumeratorMethod = Js::VarTo(type->GetJsGetterSetterInterceptor()->enumerateTrap); + } + + Js::RecyclableObject * targetObj = this; + JavascriptArray * trapResult = nullptr; + if (getEnumeratorMethod == nullptr) + { + return DynamicObject::GetEnumerator(enumerator, flags, requestContext, enumeratorCache); + } + else + { + Js::Var getGetEnumeratorResult = threadContext->ExecuteImplicitCall(getEnumeratorMethod, Js::ImplicitCall_Accessor, [=]()->Js::Var + { + return CALL_FUNCTION(threadContext, getEnumeratorMethod, Js::CallInfo(Js::CallFlags_Value, 1), targetObj); + }); + + Js::TypeId getResultTypeId = Js::JavascriptOperators::GetTypeId(getGetEnumeratorResult); + if (getResultTypeId == Js::TypeIds_Undefined) + { + return FALSE; + } + + trapResult = JavascriptOperators::TryFromVar(getGetEnumeratorResult); + if (trapResult == nullptr) + { + return FALSE; + } + } + + struct WrapperOwnKeysEnumerator : public JavascriptEnumerator + { + typedef JsUtil::BaseHashSet, Recycler> VisitedNamesHashSet; + Field(VisitedNamesHashSet*) visited; + Field(JavascriptArray*) trapResult; + Field(CustomExternalWrapperObject*) wrapper; + FieldNoBarrier(ScriptContext*) scriptContext; + Field(uint32) index; + + DEFINE_VTABLE_CTOR_ABSTRACT(WrapperOwnKeysEnumerator, JavascriptEnumerator) + + WrapperOwnKeysEnumerator(ScriptContext* scriptContext, CustomExternalWrapperObject* wrapper, JavascriptArray* trapResult) + :JavascriptEnumerator(scriptContext), scriptContext(scriptContext), wrapper(wrapper), trapResult(trapResult) + { + visited = RecyclerNew(scriptContext->GetRecycler(), VisitedNamesHashSet, scriptContext->GetRecycler()); + } + virtual void Reset() override + { + index = 0; + visited->Reset(); + } + + virtual JavascriptString * MoveAndGetNext(PropertyId& propertyId, PropertyAttributes* attributes = nullptr) override + { + propertyId = Constants::NoProperty; + if (attributes != nullptr) + { + *attributes = PropertyEnumerable; + } + // 13.7.5.15 EnumerateObjectProperties(O) (https://tc39.github.io/ecma262/#sec-enumerate-object-properties) + // for (let key of Reflect.ownKeys(obj)) { + if (trapResult != nullptr) + { + uint32 len = trapResult->GetLength(); + while (index < len) + { + Var var = trapResult->DirectGetItem(index++); + if (var) + { + // if (typeof key === "string") { + if (VarIs(var)) + { + JavascriptString* propertyName = VarTo(var); + // let desc = Reflect.getOwnPropertyDescriptor(obj, key); + Js::PropertyDescriptor desc; + BOOL ret = JavascriptOperators::GetOwnPropertyDescriptor(wrapper, propertyName, scriptContext, &desc); + const JsUtil::CharacterBuffer propertyString(propertyName->GetString(), propertyName->GetLength()); + // if (desc && !visited.has(key)) { + if (ret && !visited->Contains(propertyString)) + { + visited->Add(propertyString); + // if (desc.enumerable) yield key; + if (desc.IsEnumerable()) + { + //TODO: (vsadov) not sure if should marshal here, it is "getting" + return VarTo(CrossSite::MarshalVar( + scriptContext, propertyName, propertyName->GetScriptContext())); + } + } + } + } + } + } + return nullptr; + } + }; + + WrapperOwnKeysEnumerator* ownKeysEnum = RecyclerNew(requestContext->GetRecycler(), WrapperOwnKeysEnumerator, requestContext, this, trapResult); + + return enumerator->Initialize(ownKeysEnum, nullptr, nullptr, flags, requestContext, enumeratorCache); +} + +BOOL CustomExternalWrapperObject::SetProperty(Js::PropertyId propertyId, Js::Var value, Js::PropertyOperationFlags flags, Js::PropertyValueInfo* info) +{ + if (!this->VerifyObjectAlive()) return FALSE; + PROBE_STACK(GetScriptContext(), Js::Constants::MinStackDefault); + + auto getPropertyName = [&](Js::ScriptContext * requestContext, Js::Var * isPropertyNameNumeric, Js::Var * propertyNameNumericValue)->Js::Var + { + return GetName(requestContext, propertyId, isPropertyNameNumeric, propertyNameNumericValue); + }; + + auto fn = [&]()->BOOL + { + // setting the value could be deferred and now we are on a different context from + // make sure the value has the same context as the containing object. + value = Js::CrossSite::MarshalVar(this->GetScriptContext(), value); + return DynamicObject::SetProperty(propertyId, value, flags, info); + }; + + return SetPropertyTrap(this, CustomExternalWrapperObject::SetPropertyTrapKind::SetPropertyKind, getPropertyName, value, GetScriptContext(), flags, FALSE, fn); +} + +BOOL CustomExternalWrapperObject::SetProperty(Js::JavascriptString* propertyNameString, Js::Var value, Js::PropertyOperationFlags flags, Js::PropertyValueInfo* info) +{ + if (!this->VerifyObjectAlive()) return FALSE; + PROBE_STACK(GetScriptContext(), Js::Constants::MinStackDefault); + + auto getPropertyName = [&](Js::ScriptContext * requestContext, Js::Var * isPropertyNameNumeric, Js::Var * propertyNameNumericValue)->Js::Var + { + return propertyNameString; + }; + + auto fn = [&]()->BOOL + { + // setting the value could be deferred and now we are on a different context from + // make sure the value has the same context as the containing object. + value = Js::CrossSite::MarshalVar(this->GetScriptContext(), value); + return DynamicObject::SetProperty(propertyNameString, value, flags, info); + }; + + return SetPropertyTrap(this, CustomExternalWrapperObject::SetPropertyTrapKind::SetPropertyKind, getPropertyName, value, GetScriptContext(), flags, FALSE, fn); +} + +BOOL CustomExternalWrapperObject::EnsureNoRedeclProperty(Js::PropertyId propertyId) +{ + CustomExternalWrapperObject::HasOwnPropertyCheckNoRedecl(propertyId); + return true; +} + +BOOL CustomExternalWrapperObject::InitProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info) +{ + if (!this->VerifyObjectAlive()) return FALSE; + + // Reject implicit call + ThreadContext* threadContext = GetScriptContext()->GetThreadContext(); + if (threadContext->IsDisableImplicitCall()) + { + threadContext->AddImplicitCallFlags(Js::ImplicitCall_External); + return FALSE; + } + + // Caller does not pass requestContext. Retrieve from host scriptContext stack. + Js::ScriptContext* requestContext = + threadContext->GetPreviousHostScriptContext()->GetScriptContext(); + + if (!this->EnsureInitialized(requestContext)) + { + return FALSE; + } + + // setting the value could be deferred and now we are on a different context from + // make sure the value has the same context as the containing object. + value = Js::CrossSite::MarshalVar(this->GetScriptContext(), value); + return DynamicObject::InitProperty(propertyId, value, flags, info); +} + +BOOL CustomExternalWrapperObject::DeleteProperty(Js::PropertyId propertyId, Js::PropertyOperationFlags flags) +{ + if (!this->VerifyObjectAlive()) return FALSE; + + PROBE_STACK(GetScriptContext(), Js::Constants::MinStackDefault); + + // Reject implicit call + ThreadContext* threadContext = GetScriptContext()->GetThreadContext(); + if (threadContext->IsDisableImplicitCall()) + { + threadContext->AddImplicitCallFlags(Js::ImplicitCall_External); + return FALSE; + } + + // Caller does not pass requestContext. Retrieve from host scriptContext stack. + Js::ScriptContext* requestContext = + threadContext->GetPreviousHostScriptContext()->GetScriptContext(); + + if (!this->EnsureInitialized(requestContext)) + { + return FALSE; + } + + RecyclableObject * targetObj = this; + CustomExternalWrapperType * type = this->GetExternalType(); + Js::JavascriptFunction* deleteMethod = nullptr; + if (type->GetJsGetterSetterInterceptor()->deletePropertyTrap != nullptr) + { + deleteMethod = Js::VarTo(type->GetJsGetterSetterInterceptor()->deletePropertyTrap); + } + + Assert(!GetScriptContext()->IsHeapEnumInProgress()); + if (nullptr == deleteMethod) + { + return __super::DeleteProperty(propertyId, flags); + } + + Js::Var isPropertyNameNumeric; + Js::Var propertyNameNumericValue; + Js::Var propertyName = GetName(requestContext, propertyId, &isPropertyNameNumeric, &propertyNameNumericValue); + + Js::Var deletePropertyResult = threadContext->ExecuteImplicitCall(deleteMethod, Js::ImplicitCall_Accessor, [=]()->Js::Var + { + return CALL_FUNCTION(threadContext, deleteMethod, Js::CallInfo(Js::CallFlags_Value, 4), targetObj, propertyName, isPropertyNameNumeric, propertyNameNumericValue); + }); + + BOOL trapResult = Js::JavascriptConversion::ToBoolean(deletePropertyResult, requestContext); + if (!trapResult) + { + if (flags & Js::PropertyOperation_StrictMode) + { + Js::JavascriptError::ThrowTypeError(requestContext, JSERR_InconsistentTrapResult, _u("deleteProperty")); + } + return trapResult; + } + + Js::PropertyDescriptor targetPropertyDescriptor; + if (!Js::JavascriptOperators::GetOwnPropertyDescriptor(targetObj, propertyId, requestContext, &targetPropertyDescriptor)) + { + return TRUE; + } + if (!targetPropertyDescriptor.IsConfigurable()) + { + Js::JavascriptError::ThrowTypeError(requestContext, JSERR_InconsistentTrapResult, _u("deleteProperty")); + } + return TRUE; +} + +BOOL CustomExternalWrapperObject::DeleteProperty(Js::JavascriptString *propertyNameString, Js::PropertyOperationFlags flags) +{ + if (!this->VerifyObjectAlive()) return FALSE; + Js::PropertyRecord const *propertyRecord = nullptr; + if (Js::JavascriptOperators::ShouldTryDeleteProperty(this, propertyNameString, &propertyRecord)) + { + Assert(propertyRecord); + return DeleteProperty(propertyRecord->GetPropertyId(), flags); + } + + return TRUE; +} + +Js::JavascriptArray * CustomExternalWrapperObject::PropertyKeysTrap(KeysTrapKind keysTrapKind, Js::ScriptContext * requestContext) +{ + PROBE_STACK(GetScriptContext(), Js::Constants::MinStackDefault); + + // Reject implicit call + ThreadContext* threadContext = requestContext->GetThreadContext(); + if (threadContext->IsDisableImplicitCall()) + { + threadContext->AddImplicitCallFlags(Js::ImplicitCall_External); + return nullptr; + } + + if (!this->EnsureInitialized(requestContext)) + { + return nullptr; + } + + Js::RecyclableObject * targetObj = this; + CustomExternalWrapperType * type = this->GetExternalType(); + Js::JavascriptFunction* ownKeysMethod = nullptr; + if (type->GetJsGetterSetterInterceptor()->ownKeysTrap != nullptr) + { + ownKeysMethod = Js::VarTo(type->GetJsGetterSetterInterceptor()->ownKeysTrap); + } + + Assert(!GetScriptContext()->IsHeapEnumInProgress()); + + if (nullptr == ownKeysMethod) + { + switch (keysTrapKind) + { + case KeysTrapKind::GetOwnPropertyNamesKind: + return JavascriptObject::CreateOwnStringPropertiesHelper(this, requestContext); + case KeysTrapKind::GetOwnPropertySymbolKind: + return JavascriptObject::CreateOwnSymbolPropertiesHelper(this, requestContext); + case KeysTrapKind::KeysKind: + return JavascriptObject::CreateOwnStringSymbolPropertiesHelper(this, requestContext); + case KeysTrapKind::GetOwnEnumerablePropertyNamesKind: + return JavascriptObject::CreateOwnEnumerableStringPropertiesHelper(this, requestContext); + case KeysTrapKind::EnumerableKeysKind: + return JavascriptObject::CreateOwnEnumerableStringSymbolPropertiesHelper(this, requestContext); + default: + Assume(UNREACHED); + } + } + + Js::Var ownKeysResult = threadContext->ExecuteImplicitCall(ownKeysMethod, Js::ImplicitCall_Accessor, [=]()->Js::Var + { + return CALL_FUNCTION(threadContext, ownKeysMethod, Js::CallInfo(Js::CallFlags_Value, 1), targetObj); + }); + + if (!Js::JavascriptOperators::IsObject(ownKeysResult)) + { + Js::JavascriptError::ThrowTypeError(requestContext, JSERR_InconsistentTrapResult, _u("ownKeys")); + } + + Js::RecyclableObject* trapResultArray = Js::VarTo(ownKeysResult); + Js::JavascriptArray* trapResult = requestContext->GetLibrary()->CreateArray(0); + bool isConfigurableKeyMissingFromTrapResult = false; + bool isNonconfigurableKeyMissingFromTrapResult = false; + bool isKeyMissingFromTrapResult = false; + bool isKeyMissingFromTargetResult = false; + bool isAnyNonconfigurableKeyPresent = false; + Js::Var element; + Js::PropertyId propertyId; + const Js::PropertyRecord* propertyRecord = nullptr; + BOOL isTargetExtensible = FALSE; + + BEGIN_TEMP_ALLOCATOR(tempAllocator, requestContext, _u("Runtime")) + { + // Dictionary containing intersection of keys present in targetKeys and trapResult + Js::Var lenValue = Js::JavascriptOperators::OP_GetLength(trapResultArray, requestContext); + uint32 len = (uint32)Js::JavascriptConversion::ToLength(lenValue, requestContext); + JsUtil::BaseDictionary targetToTrapResultMap(tempAllocator, len); + + // Trap result to return. + // Note : This will not necessarily have all elements present in trapResultArray. E.g. If trap was called from GetOwnPropertySymbols() + // trapResult will only contain symbol elements from trapResultArray. + switch (keysTrapKind) + { + case GetOwnPropertyNamesKind: + case KeysTrapKind::GetOwnEnumerablePropertyNamesKind: + GetOwnPropertyKeysHelper(requestContext, trapResultArray, len, trapResult, targetToTrapResultMap, + [&](const Js::PropertyRecord *propertyRecord)->bool + { + return !propertyRecord->IsSymbol(); + }); + break; + case GetOwnPropertySymbolKind: + GetOwnPropertyKeysHelper(requestContext, trapResultArray, len, trapResult, targetToTrapResultMap, + [&](const Js::PropertyRecord *propertyRecord)->bool + { + return propertyRecord->IsSymbol(); + }); + break; + case KeysKind: + case EnumerableKeysKind: + GetOwnPropertyKeysHelper(requestContext, trapResultArray, len, trapResult, targetToTrapResultMap, + [&](const Js::PropertyRecord *propertyRecord)->bool + { + return true; + }); + break; + } + + isTargetExtensible = targetObj->IsExtensible(); + Js::JavascriptArray * targetKeys = Js::JavascriptOperators::GetOwnPropertyKeys(targetObj, requestContext); + + for (uint32 i = 0; i < targetKeys->GetLength(); i++) + { + element = targetKeys->DirectGetItem(i); + AssertMsg(Js::VarIs(element) || Js::VarIs(element), "Invariant check during ownKeys wrapper trap should make sure we only get property key here. (symbol or string primitives)"); + Js::JavascriptConversion::ToPropertyKey(element, requestContext, &propertyRecord, nullptr); + propertyId = propertyRecord->GetPropertyId(); + + if (propertyId == Js::Constants::NoProperty) + continue; + + // If not present in intersection means either the property is not present in targetKeys or + // we have already visited the property in targetKeys + if (targetToTrapResultMap.ContainsKey(propertyId)) + { + isKeyMissingFromTrapResult = false; + targetToTrapResultMap.Remove(propertyId); + } + else + { + isKeyMissingFromTrapResult = true; + } + + Js::PropertyDescriptor targetKeyPropertyDescriptor; + if (Js::JavascriptOperators::GetOwnPropertyDescriptor(targetObj, propertyId, requestContext, &targetKeyPropertyDescriptor) && !targetKeyPropertyDescriptor.IsConfigurable()) + { + isAnyNonconfigurableKeyPresent = true; + if (isKeyMissingFromTrapResult) + { + isNonconfigurableKeyMissingFromTrapResult = true; + } + } + else + { + if (isKeyMissingFromTrapResult) + { + isConfigurableKeyMissingFromTrapResult = true; + } + } + } + // Keys that were not found in targetKeys will continue to remain in the map + isKeyMissingFromTargetResult = targetToTrapResultMap.Count() != 0; + } + END_TEMP_ALLOCATOR(tempAllocator, requestContext) + + + // 19. + if (isTargetExtensible && !isAnyNonconfigurableKeyPresent) + { + return trapResult; + } + + // 21. + if (isNonconfigurableKeyMissingFromTrapResult) + { + Js::JavascriptError::ThrowTypeError(requestContext, JSERR_InconsistentTrapResult, _u("ownKeys")); + } + + // 22. + if (isTargetExtensible) + { + return trapResult; + } + + // 23. + if (isConfigurableKeyMissingFromTrapResult) + { + Js::JavascriptError::ThrowTypeError(requestContext, JSERR_InconsistentTrapResult, _u("ownKeys")); + } + + // 24. + if (isKeyMissingFromTargetResult) + { + Js::JavascriptError::ThrowTypeError(requestContext, JSERR_InconsistentTrapResult, _u("ownKeys")); + } + + return trapResult; +} + +#if ENABLE_TTD +TTD::NSSnapObjects::SnapObjectType CustomExternalWrapperObject::GetSnapTag_TTD() const +{ + //TODO:akatti: TTD. Do we need to define a new TTD object type for CustomExternalWrapperObject? + return TTD::NSSnapObjects::SnapObjectType::SnapExternalObject; +} + +void CustomExternalWrapperObject::ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) +{ + TTD::NSSnapObjects::StdExtractSetKindSpecificInfo(objData, nullptr); +} +#endif +#endif // _CHAKRACOREBUILD diff --git a/lib/Runtime/Library/CustomExternalWrapperObject.h b/lib/Runtime/Library/CustomExternalWrapperObject.h new file mode 100644 index 00000000000..31954c9c9b4 --- /dev/null +++ b/lib/Runtime/Library/CustomExternalWrapperObject.h @@ -0,0 +1,233 @@ +//------------------------------------------------------------------------------------------------------- +// 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 + +namespace Js +{ + typedef void (*JsTraceCallback)(void * data); + typedef void (*JsFinalizeCallback)(void * data); + + typedef struct _JsGetterSetterInterceptor { + Field(void *) getTrap; + Field(void *) setTrap; + Field(void *) deletePropertyTrap; + Field(void *) enumerateTrap; + Field(void *) ownKeysTrap; + Field(void *) hasTrap; + Field(void *) getOwnPropertyDescriptorTrap; + Field(void *) definePropertyTrap; + Field(void *) initializeTrap; + } JsGetterSetterInterceptor; + + class CustomExternalWrapperType sealed : public DynamicType + { + public: + CustomExternalWrapperType(CustomExternalWrapperType * type) : DynamicType(type), jsTraceCallback(type->jsTraceCallback), jsFinalizeCallback(type->jsFinalizeCallback), jsGetterSetterInterceptor(type->jsGetterSetterInterceptor) {} + CustomExternalWrapperType(ScriptContext * scriptContext, JsTraceCallback traceCallback, JsFinalizeCallback finalizeCallback, RecyclableObject * prototype); + + JsTraceCallback GetJsTraceCallback() const { return this->jsTraceCallback; } + JsFinalizeCallback GetJsFinalizeCallback() const { return this->jsFinalizeCallback; } + JsGetterSetterInterceptor * GetJsGetterSetterInterceptor() const { return this->jsGetterSetterInterceptor; } + + private: + FieldNoBarrier(JsTraceCallback const) jsTraceCallback; + FieldNoBarrier(JsFinalizeCallback const) jsFinalizeCallback; + FieldNoBarrier(JsGetterSetterInterceptor *) jsGetterSetterInterceptor; + }; + + class CustomExternalWrapperObject : public DynamicObject + { + protected: + DEFINE_VTABLE_CTOR(CustomExternalWrapperObject, DynamicObject); + DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(CustomExternalWrapperObject); + + public: + typedef enum SetPropertyTrapKind { + SetItemOnTaggedNumberKind, + SetPropertyOnTaggedNumberKind, + SetPropertyKind, + SetItemKind, + SetPropertyWPCacheKind, + } SetPropertyTrapKind; + + enum KeysTrapKind { + GetOwnEnumerablePropertyNamesKind, + GetOwnPropertyNamesKind, + GetOwnPropertySymbolKind, + EnumerableKeysKind, + KeysKind + }; + + CustomExternalWrapperObject(CustomExternalWrapperType * type, void *data, uint inlineSlotSize); + + BOOL IsObjectAlive(); + BOOL VerifyObjectAlive(); + + static CustomExternalWrapperObject * Create(void *data, uint inlineSlotSize, JsTraceCallback traceCallback, JsFinalizeCallback finalizeCallback, JsGetterSetterInterceptor ** getterSetterInterceptor, RecyclableObject * prototype, ScriptContext *scriptContext); + static CustomExternalWrapperObject * Clone(CustomExternalWrapperObject * source, ScriptContext * scriptContext); + + static BOOL GetOwnPropertyDescriptor(RecyclableObject * obj, PropertyId propertyId, ScriptContext* requestContext, PropertyDescriptor* propertyDescriptor); + static BOOL DefineOwnPropertyDescriptor(RecyclableObject * obj, PropertyId propId, const PropertyDescriptor& descriptor, bool throwOnError, ScriptContext* requestContext); + + CustomExternalWrapperType * GetExternalType() const { return (CustomExternalWrapperType *)this->GetType(); } + + BOOL EnsureInitialized(ScriptContext* requestContext); + + void Mark(Recycler * recycler) override; + void Finalize(bool isShutdown) override; + void Dispose(bool isShutdown) override; + + bool HasReadOnlyPropertiesInvisibleToTypeHandler() override { return true; } + bool IsInitialized() const { return this->initialized; } + + virtual PropertyQueryFlags GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var * value, PropertyValueInfo * info, ScriptContext * requestContext) override; + virtual PropertyQueryFlags GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var * value, PropertyValueInfo * info, ScriptContext * requestContext) override; + virtual PropertyQueryFlags GetPropertyReferenceQuery(Var originalInstance, PropertyId propertyId, Var * value, PropertyValueInfo * info, ScriptContext * requestContext) override; + virtual PropertyQueryFlags HasPropertyQuery(PropertyId propertyId, _Inout_opt_ PropertyValueInfo* info) override; + virtual BOOL SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo * info) override; + virtual BOOL SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo * info) override; + virtual BOOL EnsureNoRedeclProperty(PropertyId propertyId) override; + virtual BOOL InitProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags = PropertyOperation_None, PropertyValueInfo* info = nullptr) override; + virtual BOOL DeleteProperty(PropertyId propertyId, PropertyOperationFlags flags) override; + virtual BOOL DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags flags) override; + virtual PropertyQueryFlags HasItemQuery(uint32 index) override; + virtual BOOL HasOwnItem(uint32 index) override; + virtual PropertyQueryFlags GetItemQuery(Var originalInstance, uint32 index, Var * value, ScriptContext * requestContext) override; + virtual PropertyQueryFlags GetItemReferenceQuery(Var originalInstance, uint32 index, Var * value, ScriptContext * requestContext) override; + virtual BOOL SetItem(uint32 index, Var value, PropertyOperationFlags flags) override; + virtual BOOL DeleteItem(uint32 index, PropertyOperationFlags flags) override; + virtual BOOL GetEnumerator(JavascriptStaticEnumerator * enumerator, EnumeratorFlags flags, ScriptContext * requestContext, EnumeratorCache * enumeratorCache = nullptr) override; + virtual BOOL Equals(__in Var other, __out BOOL* value, ScriptContext* requestContext) override; + virtual BOOL StrictEquals(__in Var other, __out BOOL* value, ScriptContext* requestContext) override; + + virtual DynamicType* DuplicateType() override; + virtual void SetPrototype(RecyclableObject* newPrototype) override; + + void PropertyIdFromInt(uint32 index, PropertyRecord const** propertyRecord); + + template + BOOL SetPropertyTrap(Var receiver, SetPropertyTrapKind setPropertyTrapKind, GetPropertyNameFunc getPropertyName, Var newValue, ScriptContext * requestContext, PropertyOperationFlags propertyOperationFlags, BOOL skipPrototypeCheck, Fn fn); + BOOL SetPropertyTrap(Var receiver, SetPropertyTrapKind setPropertyTrapKind, JavascriptString * propertyString, Var newValue, ScriptContext * requestContext, PropertyOperationFlags propertyOperationFlags); + + JavascriptArray * PropertyKeysTrap(KeysTrapKind keysTrapKind, ScriptContext * requestContext); + + void * GetSlotData() const; + void SetSlotData(void * data); + int GetInlineSlotSize() const; + void* GetInlineSlots() const; + + virtual PropertyId GetPropertyId(PropertyIndex index) override { if (!EnsureInitialized(GetScriptContext())) { return Constants::NoProperty; } return DynamicObject::GetPropertyId(index); } + virtual PropertyId GetPropertyId(BigPropertyIndex index) override { if (!EnsureInitialized(GetScriptContext())) { return Constants::NoProperty; } return DynamicObject::GetPropertyId(index); } + virtual BOOL HasOwnProperty(PropertyId propertyId) override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::HasOwnProperty(propertyId); } + virtual DescriptorFlags GetSetter(PropertyId propertyId, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext) override { if (!EnsureInitialized(GetScriptContext())) { return None; } return DynamicObject::GetSetter(propertyId, setterValue, info, requestContext); } + virtual DescriptorFlags GetSetter(JavascriptString* propertyNameString, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext) override { if (!EnsureInitialized(GetScriptContext())) { return None; } return DynamicObject::GetSetter(propertyNameString, setterValue, info, requestContext); } + virtual BOOL SetPropertyWithAttributes(PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags = PropertyOperation_None, SideEffects possibleSideEffects = SideEffects_Any) override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::SetPropertyWithAttributes(propertyId, value, attributes, info, flags, possibleSideEffects); } +#if ENABLE_FIXED_FIELDS + virtual BOOL IsFixedProperty(PropertyId propertyId) override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::IsFixedProperty(propertyId); } +#endif + virtual DescriptorFlags GetItemSetter(uint32 index, Var* setterValue, ScriptContext* requestContext) override { if (!EnsureInitialized(GetScriptContext())) { return None; } return DynamicObject::GetItemSetter(index, setterValue, requestContext); } + virtual BOOL ToPrimitive(JavascriptHint hint, Var* result, ScriptContext * requestContext) override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::ToPrimitive(hint, result, requestContext); } + virtual BOOL SetAccessors(PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags = PropertyOperation_None) override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::SetAccessors(propertyId, getter, setter, flags); } + _Check_return_ _Success_(return) virtual BOOL GetAccessors(PropertyId propertyId, _Outptr_result_maybenull_ Var* getter, _Outptr_result_maybenull_ Var* setter, ScriptContext* requestContext) override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::GetAccessors(propertyId, getter, setter, requestContext); } + virtual BOOL IsWritable(PropertyId propertyId) override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::IsWritable(propertyId); } + virtual BOOL IsConfigurable(PropertyId propertyId) override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::IsConfigurable(propertyId); } + virtual BOOL IsEnumerable(PropertyId propertyId) override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::IsEnumerable(propertyId); } + virtual BOOL SetEnumerable(PropertyId propertyId, BOOL value) override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::SetEnumerable(propertyId, value); } + virtual BOOL SetWritable(PropertyId propertyId, BOOL value) override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::SetWritable(propertyId, value); } + virtual BOOL SetConfigurable(PropertyId propertyId, BOOL value) override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::SetConfigurable(propertyId, value); } + virtual BOOL SetAttributes(PropertyId propertyId, PropertyAttributes attributes) override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::SetAttributes(propertyId, attributes); } + virtual BOOL Seal() override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::Seal(); } + virtual BOOL Freeze() override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::Freeze(); } + +#if DBG + virtual bool CanStorePropertyValueDirectly(PropertyId propertyId, bool allowLetConst) override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::CanStorePropertyValueDirectly(propertyId, allowLetConst); } +#endif + + virtual void RemoveFromPrototype(ScriptContext * requestContext, bool * allProtoCachesInvalidated) override { if (!EnsureInitialized(GetScriptContext())) { return; } return DynamicObject::RemoveFromPrototype(requestContext, allProtoCachesInvalidated); } + virtual void AddToPrototype(ScriptContext * requestContext, bool * allProtoCachesInvalidated) override { if (!EnsureInitialized(GetScriptContext())) { return; } return DynamicObject::AddToPrototype(requestContext, allProtoCachesInvalidated); } + virtual bool ClearProtoCachesWereInvalidated() override { if (!EnsureInitialized(GetScriptContext())) { return FALSE; } return DynamicObject::ClearProtoCachesWereInvalidated(); } + private: + enum class SlotType { + Inline, + External + }; + + Field(bool) initialized = false; + Field(SlotType) slotType; + union SlotInfo + { + Field(void *) slot; + Field(uint) inlineSlotSize; + SlotInfo() + { + memset(this, 0, sizeof(SlotInfo)); + } + }; + Field(SlotInfo) u; + + Var GetValueFromDescriptor(Var instance, PropertyDescriptor propertyDescriptor, ScriptContext * requestContext); + Var GetName(ScriptContext* requestContext, PropertyId propertyId, Var * isPropertyNameNumeric, Var * propertyNameNumericValue); + + BOOL GetPropertyDescriptorTrap(PropertyId propertyId, PropertyDescriptor * resultDescriptor, ScriptContext * requestContext); + + template + BOOL GetPropertyTrap(Var instance, PropertyDescriptor * propertyDescriptor, Fn fn, GetPropertyNameFunc getPropertyName, ScriptContext * requestContext); + + template + BOOL HasPropertyTrap(Fn fn, GetPropertyNameFunc getPropertyName); + + template + void GetOwnPropertyKeysHelper(ScriptContext * scriptContext, RecyclableObject * trapResultArray, uint32 len, JavascriptArray * trapResult, + JsUtil::BaseDictionary& targetToTrapResultMap, Fn fn) + { + Var element = nullptr; + const PropertyRecord* propertyRecord; + uint32 trapResultIndex = 0; + PropertyId propertyId; + for (uint32 i = 0; i < len; i++) + { + if (!JavascriptOperators::GetItem(trapResultArray, i, &element, scriptContext) || // missing + !(VarIs(element) || VarIs(element))) // neither String nor Symbol + { + JavascriptError::ThrowTypeError(scriptContext, JSERR_InconsistentTrapResult, _u("ownKeys")); + } + + JavascriptConversion::ToPropertyKey(element, scriptContext, &propertyRecord, nullptr); + propertyId = propertyRecord->GetPropertyId(); + + if (propertyId != Constants::NoProperty) + { + if (targetToTrapResultMap.AddNew(propertyId, true) == -1) + { + JavascriptError::ThrowTypeError(scriptContext, JSERR_InconsistentTrapResult); + } + } + + if (fn(propertyRecord)) + { + trapResult->DirectSetItemAt(trapResultIndex++, element); + } + } + } + +#if ENABLE_TTD + public: + virtual TTD::NSSnapObjects::SnapObjectType GetSnapTag_TTD() const override; + virtual void ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) override; +#endif + }; + + template <> inline bool VarIsImpl(RecyclableObject* obj) + { + return (VirtualTableInfo::HasVirtualTable(obj)) || + (VirtualTableInfo>::HasVirtualTable(obj)); + } + +} + +#ifndef __APPLE__ // TODO: for some reason on OSX builds this initialization happens before PAL initialization +AUTO_REGISTER_RECYCLER_OBJECT_DUMPER(Js::CustomExternalWrapperType, &Js::Type::DumpObjectFunction); +AUTO_REGISTER_RECYCLER_OBJECT_DUMPER(Js::CustomExternalWrapperObject, &Js::RecyclableObject::DumpObjectFunction); +#endif diff --git a/lib/Runtime/Library/JavascriptExceptionMetadata.cpp b/lib/Runtime/Library/JavascriptExceptionMetadata.cpp index 4b94df25ed2..370ad3da8ca 100644 --- a/lib/Runtime/Library/JavascriptExceptionMetadata.cpp +++ b/lib/Runtime/Library/JavascriptExceptionMetadata.cpp @@ -105,8 +105,8 @@ namespace Js { if (nextLine >= cache->GetLineCount()) { - endByteOffset = functionBody->LengthInBytes(); - endCharOffset = functionBody->LengthInChars(); + endByteOffset = startByteOffset + functionBody->LengthInBytes(); + endCharOffset = startCharOffset + functionBody->LengthInChars(); } else { diff --git a/lib/Runtime/Library/JavascriptExternalFunction.cpp b/lib/Runtime/Library/JavascriptExternalFunction.cpp index 92b2be41d35..8672559b969 100644 --- a/lib/Runtime/Library/JavascriptExternalFunction.cpp +++ b/lib/Runtime/Library/JavascriptExternalFunction.cpp @@ -314,24 +314,6 @@ namespace Js END_LEAVE_SCRIPT(scriptContext); #endif - bool marshallingMayBeNeeded = false; - if (result != nullptr) - { - marshallingMayBeNeeded = Js::VarIs(result); - if (marshallingMayBeNeeded) - { - Js::RecyclableObject * obj = Js::VarTo(result); - - // For JSRT, we could get result marshalled in different context. - bool isJSRT = scriptContext->GetThreadContext()->IsJSRT(); - marshallingMayBeNeeded = obj->GetScriptContext() != scriptContext; - if (!isJSRT && marshallingMayBeNeeded) - { - Js::Throw::InternalError(); - } - } - } - if (scriptContext->HasRecordedException()) { bool considerPassingToDebugger = false; @@ -354,7 +336,7 @@ namespace Js { result = scriptContext->GetLibrary()->GetUndefined(); } - else if (marshallingMayBeNeeded) + else { result = CrossSite::MarshalVar(scriptContext, result); } diff --git a/lib/Runtime/Library/JavascriptLibrary.cpp b/lib/Runtime/Library/JavascriptLibrary.cpp index d7ea10845ed..3dda3c5a623 100644 --- a/lib/Runtime/Library/JavascriptLibrary.cpp +++ b/lib/Runtime/Library/JavascriptLibrary.cpp @@ -4469,7 +4469,12 @@ namespace Js return function; } - DynamicType* JavascriptLibrary::GetCachedJsrtExternalType(uintptr_t finalizeCallback) + JsrtExternalType* JavascriptLibrary::GetCachedJsrtExternalType( +#ifdef _CHAKRACOREBUILD + uintptr_t traceCallback, +#endif + uintptr_t finalizeCallback, + uintptr_t prototype) { RecyclerWeakReference* dynamicTypeWeakRef = nullptr; DynamicType* dynamicType = nullptr; @@ -4479,17 +4484,53 @@ namespace Js // Register for periodic cleanup scriptContext->RegisterWeakReferenceDictionary(jsrtExternalTypesCache); } - if (jsrtExternalTypesCache->TryGetValue(finalizeCallback, &dynamicTypeWeakRef)) + if (jsrtExternalTypesCache->TryGetValue(JsrtExternalCallbacks( +#ifdef _CHAKRACOREBUILD + traceCallback, +#endif + finalizeCallback, + prototype), &dynamicTypeWeakRef)) + { + dynamicType = dynamicTypeWeakRef->Get(); + } + return (JsrtExternalType*)dynamicType; + } + +#ifdef _CHAKRACOREBUILD + void JavascriptLibrary::CacheJsrtExternalType(uintptr_t traceCallback, uintptr_t finalizeCallback, uintptr_t prototype, JsrtExternalType* dynamicTypeToCache) + { + jsrtExternalTypesCache->Item(JsrtExternalCallbacks(traceCallback, finalizeCallback, prototype), recycler->CreateWeakReferenceHandle((DynamicType*)dynamicTypeToCache)); + } +#else + void JavascriptLibrary::CacheJsrtExternalType(uintptr_t finalizeCallback, uintptr_t prototype, JsrtExternalType* dynamicTypeToCache) + { + jsrtExternalTypesCache->Item(JsrtExternalCallbacks(finalizeCallback, prototype), recycler->CreateWeakReferenceHandle((DynamicType*)dynamicTypeToCache)); + } +#endif + +#ifdef _CHAKRACOREBUILD + DynamicType* JavascriptLibrary::GetCachedCustomExternalWrapperType(uintptr_t traceCallback, uintptr_t finalizeCallback, uintptr_t interceptors, uintptr_t prototype) + { + RecyclerWeakReference* dynamicTypeWeakRef = nullptr; + DynamicType* dynamicType = nullptr; + if (customExternalWrapperTypesCache == nullptr) + { + customExternalWrapperTypesCache = RecyclerNew(recycler, CustomExternalWrapperTypesCache, recycler, 3); + // Register for periodic cleanup + scriptContext->RegisterWeakReferenceDictionary(customExternalWrapperTypesCache); + } + if (customExternalWrapperTypesCache->TryGetValue(CustomExternalWrapperCallbacks(traceCallback, finalizeCallback, interceptors, prototype), &dynamicTypeWeakRef)) { dynamicType = dynamicTypeWeakRef->Get(); } return dynamicType; } - void JavascriptLibrary::CacheJsrtExternalType(uintptr_t finalizeCallback, DynamicType* dynamicTypeToCache) + void JavascriptLibrary::CacheCustomExternalWrapperType(uintptr_t traceCallback, uintptr_t finalizeCallback, uintptr_t interceptors, uintptr_t prototype, DynamicType* dynamicTypeToCache) { - jsrtExternalTypesCache->Item(finalizeCallback, recycler->CreateWeakReferenceHandle(dynamicTypeToCache)); + customExternalWrapperTypesCache->Item(CustomExternalWrapperCallbacks(traceCallback, finalizeCallback, interceptors, prototype), recycler->CreateWeakReferenceHandle(dynamicTypeToCache)); } +#endif void JavascriptLibrary::DefaultCreateFunction(ParseableFunctionInfo * functionInfo, int length, DynamicObject * prototype, PropertyId nameId) { @@ -6055,20 +6096,8 @@ namespace Js JavascriptExternalFunction* JavascriptLibrary::CreateStdCallExternalFunction(StdCallJavascriptMethod entryPoint, Var name, void *callbackState) { - Var functionNameOrId = name; - if (VarIs(name)) - { - JavascriptString * functionName = VarTo(name); - const char16 * functionNameBuffer = functionName->GetString(); - int functionNameBufferLength = functionName->GetLengthAsSignedInt(); - - PropertyId functionNamePropertyId = scriptContext->GetOrAddPropertyIdTracked(functionNameBuffer, functionNameBufferLength); - functionNameOrId = TaggedInt::ToVarUnchecked(functionNamePropertyId); - } - - AssertOrFailFast(TaggedInt::Is(functionNameOrId)); JavascriptExternalFunction* function = this->CreateIdMappedExternalFunction(entryPoint, stdCallFunctionWithDeferredPrototypeType); - function->SetFunctionNameId(functionNameOrId); + function->SetFunctionNameId(name); function->SetCallbackState(callbackState); return function; } @@ -6391,6 +6420,11 @@ namespace Js return GetEnumeratorCache(type, &this->cache.assignCache); } + EnumeratorCache* JavascriptLibrary::GetCreateKeysCache(Type* type) + { + return GetEnumeratorCache(type, &this->cache.createKeysCache); + } + EnumeratorCache* JavascriptLibrary::GetStringifyCache(Type* type) { return GetEnumeratorCache(type, &this->cache.stringifyCache); diff --git a/lib/Runtime/Library/JavascriptLibrary.h b/lib/Runtime/Library/JavascriptLibrary.h index 8e9dc09fa3e..d2b08fe3394 100644 --- a/lib/Runtime/Library/JavascriptLibrary.h +++ b/lib/Runtime/Library/JavascriptLibrary.h @@ -20,6 +20,7 @@ class ActiveScriptExternalLibrary; class ProjectionExternalLibrary; class EditAndContinue; class ChakraHostScriptContext; +class JsrtExternalType; #ifdef ENABLE_PROJECTION namespace Projection @@ -73,6 +74,7 @@ namespace Js { static const uint AssignCacheSize = 16; static const uint StringifyCacheSize = 16; + static const uint CreateKeysCacheSize = 16; Field(PropertyStringMap*) propertyStrings[80]; Field(JavascriptString *) lastNumberToStringRadix10String; @@ -93,6 +95,7 @@ namespace Js Field(ScriptContextPolymorphicInlineCache*) toJSONCache; Field(EnumeratorCache*) assignCache; Field(EnumeratorCache*) stringifyCache; + Field(EnumeratorCache*) createKeysCache; #if ENABLE_PROFILE_INFO #if DBG_DUMP || defined(DYNAMIC_PROFILE_STORAGE) || defined(RUNTIME_DATA_COLLECTION) Field(DynamicProfileInfoList*) profileInfoList; @@ -439,7 +442,31 @@ namespace Js Field(void *) nativeHostPromiseContinuationFunctionState; typedef SList FunctionReferenceList; - typedef JsUtil::WeakReferenceDictionary> JsrtExternalTypesCache; +#ifdef _CHAKRACOREBUILD + struct JsrtExternalCallbacks + { + JsrtExternalCallbacks() : traceCallback(0), finalizeCallback(0), prototype(0) {} + JsrtExternalCallbacks(uintptr_t traceCallback, uintptr_t finalizeCallback, uintptr_t prototype) : traceCallback(traceCallback), finalizeCallback(finalizeCallback), prototype(prototype) {} + + uintptr_t traceCallback; + uintptr_t finalizeCallback; + uintptr_t prototype; + + operator hash_t() const { return (hash_t)(traceCallback ^ finalizeCallback ^ prototype); } + }; +#else + struct JsrtExternalCallbacks + { + JsrtExternalCallbacks() : finalizeCallback(0), prototype(0) {} + JsrtExternalCallbacks(uintptr_t finalizeCallback, uintptr_t prototype) : finalizeCallback(finalizeCallback), prototype(prototype) {} + + uintptr_t finalizeCallback; + uintptr_t prototype; + + operator hash_t() const { return (hash_t)(finalizeCallback ^ prototype); } + }; +#endif + typedef JsUtil::WeakReferenceDictionary> JsrtExternalTypesCache; Field(void *) bindRefChunkBegin; Field(Field(void*)*) bindRefChunkCurrent; @@ -452,6 +479,21 @@ namespace Js Field(JsrtExternalTypesCache*) jsrtExternalTypesCache; Field(FunctionBody*) fakeGlobalFuncForUndefer; + struct CustomExternalWrapperCallbacks + { + CustomExternalWrapperCallbacks() : traceCallback(0), finalizeCallback(0), interceptors(0), prototype(0) {} + CustomExternalWrapperCallbacks(uintptr_t traceCallback, uintptr_t finalizeCallback, uintptr_t interceptors, uintptr_t prototype) : traceCallback(traceCallback), finalizeCallback(finalizeCallback), interceptors(interceptors), prototype(prototype) {} + uintptr_t traceCallback; + uintptr_t finalizeCallback; + uintptr_t interceptors; + uintptr_t prototype; + + operator hash_t() const { return (hash_t)(traceCallback ^ finalizeCallback ^ interceptors ^ prototype); } + }; + typedef JsUtil::WeakReferenceDictionary> CustomExternalWrapperTypesCache; + + Field(CustomExternalWrapperTypesCache*) customExternalWrapperTypesCache; + Field(ModuleRecordList*) moduleRecordList; Field(OnlyWritablePropertyProtoChainCache) typesWithOnlyWritablePropertyProtoChain; @@ -522,6 +564,7 @@ namespace Js throwerFunction(nullptr), jsrtContextObject(nullptr), jsrtExternalTypesCache(nullptr), + customExternalWrapperTypesCache(nullptr), fakeGlobalFuncForUndefer(nullptr), externalLibraryList(nullptr), #if ENABLE_COPYONACCESS_ARRAY @@ -887,8 +930,16 @@ namespace Js JavascriptExternalFunction* CreateIdMappedExternalFunction(MethodType entryPoint, DynamicType *pPrototypeType); JavascriptExternalFunction* CreateExternalConstructor(Js::ExternalMethod entryPoint, PropertyId nameId, RecyclableObject * prototype); JavascriptExternalFunction* CreateExternalConstructor(Js::ExternalMethod entryPoint, PropertyId nameId, InitializeMethod method, unsigned short deferredTypeSlots, bool hasAccessors); - DynamicType* GetCachedJsrtExternalType(uintptr_t finalizeCallback); - void CacheJsrtExternalType(uintptr_t finalizeCallback, DynamicType* dynamicType); +#ifdef _CHAKRACOREBUILD + DynamicType* GetCachedCustomExternalWrapperType(uintptr_t traceCallback, uintptr_t finalizeCallback, uintptr_t interceptors, uintptr_t prototype); + void CacheCustomExternalWrapperType(uintptr_t traceCallback, uintptr_t finalizeCallback, uintptr_t interceptors, uintptr_t prototype, DynamicType* dynamicType); + + JsrtExternalType* GetCachedJsrtExternalType(uintptr_t traceCallback, uintptr_t finalizeCallback, uintptr_t prototype); + void CacheJsrtExternalType(uintptr_t traceCallback, uintptr_t finalizeCallback, uintptr_t prototype, JsrtExternalType* dynamicType); +#else + JsrtExternalType* GetCachedJsrtExternalType(uintptr_t finalizeCallback, uintptr_t prototype); + void CacheJsrtExternalType(uintptr_t finalizeCallback, uintptr_t prototype, JsrtExternalType* dynamicType); +#endif static DynamicTypeHandler * GetDeferredPrototypeGeneratorFunctionTypeHandler(ScriptContext* scriptContext); static DynamicTypeHandler * GetDeferredPrototypeAsyncFunctionTypeHandler(ScriptContext* scriptContext); DynamicType * CreateDeferredPrototypeGeneratorFunctionType(JavascriptMethod entrypoint, bool isAnonymousFunction, bool isShared = false); @@ -1104,6 +1155,7 @@ namespace Js } EnumeratorCache* GetObjectAssignCache(Type* type); + EnumeratorCache* GetCreateKeysCache(Type* type); EnumeratorCache* GetStringifyCache(Type* type); bool GetArrayObjectHasUserDefinedSpecies() const { return arrayObjectHasUserDefinedSpecies; } diff --git a/lib/Runtime/Library/JavascriptObject.cpp b/lib/Runtime/Library/JavascriptObject.cpp index 02e9e3cfb2b..4998b0dfea7 100644 --- a/lib/Runtime/Library/JavascriptObject.cpp +++ b/lib/Runtime/Library/JavascriptObject.cpp @@ -1209,9 +1209,8 @@ JavascriptArray* JavascriptObject::CreateKeysHelper(RecyclableObject* object, Sc AssertMsg(includeStringProperties || includeSymbolProperties, "Should either get string or symbol properties."); JavascriptStaticEnumerator enumerator; + EnumeratorFlags flags = EnumeratorFlags::SnapShotSemantics | EnumeratorFlags::UseCache; JavascriptArray* newArr = scriptContext->GetLibrary()->CreateArray(0); - JavascriptArray* newArrForSymbols = scriptContext->GetLibrary()->CreateArray(0); - EnumeratorFlags flags = EnumeratorFlags::None; if (includeNonEnumerable) { flags |= EnumeratorFlags::EnumNonEnumerable; @@ -1220,7 +1219,8 @@ JavascriptArray* JavascriptObject::CreateKeysHelper(RecyclableObject* object, Sc { flags |= EnumeratorFlags::EnumSymbols; } - if (!object->GetEnumerator(&enumerator, flags, scriptContext)) + EnumeratorCache* cache = scriptContext->GetLibrary()->GetCreateKeysCache(object->GetType()); + if (!object->GetEnumerator(&enumerator, flags, scriptContext, cache)) { return newArr; // Return an empty array if we don't have an enumerator } @@ -1231,7 +1231,7 @@ JavascriptArray* JavascriptObject::CreateKeysHelper(RecyclableObject* object, Sc uint32 symbolIndex = 0; const PropertyRecord* propertyRecord; JavascriptSymbol* symbol; - + JavascriptArray* newArrForSymbols = nullptr; while ((propertyName = enumerator.MoveAndGetNext(propertyId)) != NULL) { if (propertyName) @@ -1244,6 +1244,10 @@ JavascriptArray* JavascriptObject::CreateKeysHelper(RecyclableObject* object, Sc { symbol = scriptContext->GetSymbol(propertyRecord); // no need to marshal symbol because it is created from scriptContext + if (!newArrForSymbols) + { + newArrForSymbols = scriptContext->GetLibrary()->CreateArray(0); + } newArrForSymbols->DirectSetItemAt(symbolIndex++, symbol); continue; } @@ -1266,11 +1270,14 @@ JavascriptArray* JavascriptObject::CreateKeysHelper(RecyclableObject* object, Sc } } - // Append all the symbols at the end of list - uint32 totalSymbols = newArrForSymbols->GetLength(); - for (uint32 symIndex = 0; symIndex < totalSymbols; symIndex++) + if (newArrForSymbols) { - newArr->DirectSetItemAt(propertyIndex++, newArrForSymbols->DirectGetItem(symIndex)); + // Append all the symbols at the end of list + uint32 totalSymbols = newArrForSymbols->GetLength(); + for (uint32 symIndex = 0; symIndex < totalSymbols; symIndex++) + { + newArr->DirectSetItemAt(propertyIndex++, newArrForSymbols->DirectGetItem(symIndex)); + } } return newArr; diff --git a/lib/Runtime/Library/JavascriptString.cpp b/lib/Runtime/Library/JavascriptString.cpp index ec27408fd98..b037a57d521 100644 --- a/lib/Runtime/Library/JavascriptString.cpp +++ b/lib/Runtime/Library/JavascriptString.cpp @@ -733,7 +733,9 @@ namespace Js Var value; if (pThis->GetItemAt(idxPosition, &value)) { +#ifdef ENABLE_SPECTRE_RUNTIME_MITIGATIONS value = BreakSpeculation(value); +#endif return value; } else @@ -782,7 +784,11 @@ namespace Js return scriptContext->GetLibrary()->GetNaN(); } - return BreakSpeculation(TaggedInt::ToVarUnchecked(pThis->GetItem(idxPosition))); + Var charCode = TaggedInt::ToVarUnchecked(pThis->GetItem(idxPosition)); +#ifdef ENABLE_SPECTRE_RUNTIME_MITIGATIONS + charCode = BreakSpeculation(charCode); +#endif + return charCode; } Var JavascriptString::EntryCodePointAt(RecyclableObject* function, CallInfo callInfo, ...) @@ -1837,7 +1843,9 @@ namespace Js idxEnd = idxStart; } +#ifdef ENABLE_SPECTRE_RUNTIME_MITIGATIONS pThis = (JavascriptString*)BreakSpeculation(pThis); +#endif return SubstringCore(pThis, idxStart, idxEnd - idxStart, scriptContext); } @@ -1958,7 +1966,9 @@ namespace Js return pThis; } +#ifdef ENABLE_SPECTRE_RUNTIME_MITIGATIONS pThis = (JavascriptString*)BreakSpeculation(pThis); +#endif return SubstringCore(pThis, idxStart, idxEnd - idxStart, scriptContext); } @@ -2016,7 +2026,9 @@ namespace Js return pThis; } +#ifdef ENABLE_SPECTRE_RUNTIME_MITIGATIONS pThis = (JavascriptString*)BreakSpeculation(pThis); +#endif Assert(0 <= idxStart && idxStart <= idxEnd && idxEnd <= len); return SubstringCore(pThis, idxStart, idxEnd - idxStart, scriptContext); diff --git a/lib/Runtime/Library/RuntimeFunction.cpp b/lib/Runtime/Library/RuntimeFunction.cpp index a6a4cc97788..aa0e445eb6f 100644 --- a/lib/Runtime/Library/RuntimeFunction.cpp +++ b/lib/Runtime/Library/RuntimeFunction.cpp @@ -7,15 +7,15 @@ namespace Js { RuntimeFunction::RuntimeFunction(DynamicType * type) - : JavascriptFunction(type), functionNameId(nullptr) + : JavascriptFunction(type), isDisplayString(false), functionNameId(nullptr) {} RuntimeFunction::RuntimeFunction(DynamicType * type, FunctionInfo * functionInfo) - : JavascriptFunction(type, functionInfo), functionNameId(nullptr) + : JavascriptFunction(type, functionInfo), isDisplayString(false), functionNameId(nullptr) {} RuntimeFunction::RuntimeFunction(DynamicType * type, FunctionInfo * functionInfo, ConstructorCache* cache) - : JavascriptFunction(type, functionInfo, cache), functionNameId(nullptr) + : JavascriptFunction(type, functionInfo, cache), isDisplayString(false), functionNameId(nullptr) {} JavascriptString * @@ -24,33 +24,39 @@ namespace Js JavascriptLibrary* library = this->GetLibrary(); ScriptContext * scriptContext = library->GetScriptContext(); JavascriptString * retStr = nullptr; + if (this->isDisplayString) + { + return VarTo(this->functionNameId); + } + if (this->functionNameId == nullptr) { retStr = library->GetFunctionDisplayString(); - this->functionNameId = retStr; } else { + if (this->GetTypeHandler()->IsDeferredTypeHandler()) + { + JavascriptString* functionName = nullptr; + DebugOnly(bool status = ) this->GetFunctionName(&functionName); + Assert(status); + this->SetPropertyWithAttributes(PropertyIds::name, functionName, PropertyConfigurable, nullptr); + } if (TaggedInt::Is(this->functionNameId)) { - if (this->GetTypeHandler()->IsDeferredTypeHandler()) - { - JavascriptString* functionName = nullptr; - DebugOnly(bool status = ) this->GetFunctionName(&functionName); - Assert(status); - this->SetPropertyWithAttributes(PropertyIds::name, functionName, PropertyConfigurable, nullptr); - } - // This has a side-effect where any other code (such as debugger) that uses functionNameId value will now get the value like "function foo() { native code }" // instead of just "foo". Alternative ways will need to be devised; if it's not desirable to use this full display name value in those cases. - retStr = GetNativeFunctionDisplayString(scriptContext, scriptContext->GetPropertyString(TaggedInt::ToInt32(this->functionNameId))); - this->functionNameId = retStr; + retStr = GetNativeFunctionDisplayString(scriptContext, scriptContext->GetPropertyString(TaggedInt::ToInt32(this->functionNameId))); } else { - retStr = VarTo(this->functionNameId); + retStr = GetNativeFunctionDisplayString(scriptContext, VarTo(this->functionNameId)); } } + + this->functionNameId = retStr; + this->isDisplayString = true; + return retStr; } @@ -62,6 +68,7 @@ namespace Js // We are only reference the propertyId, it needs to be tracked to stay alive Assert(!TaggedInt::Is(nameId) || this->GetScriptContext()->IsTrackedPropertyId(TaggedInt::ToInt32(nameId))); + this->isDisplayString = false; this->functionNameId = nameId; } diff --git a/lib/Runtime/Library/RuntimeFunction.h b/lib/Runtime/Library/RuntimeFunction.h index d8f3abe4380..bf9c807d663 100644 --- a/lib/Runtime/Library/RuntimeFunction.h +++ b/lib/Runtime/Library/RuntimeFunction.h @@ -25,6 +25,7 @@ namespace Js // NOTE: This has a side-effect that after toString() is called for the first time on a built-in function the functionNameId gets replaced with a string like "function foo() { native code }". // As a result any code like debugger(F12) that shows the functionNameId to the user will need to pre-process this string as it may not be desirable to use this as-is in some cases. // See RuntimeFunction::EnsureSourceString() for details. + Field(bool) isDisplayString; Field(Var) functionNameId; virtual Var GetSourceString() const { return functionNameId; } virtual JavascriptString * EnsureSourceString(); diff --git a/lib/Runtime/Library/RuntimeLibraryPch.h b/lib/Runtime/Library/RuntimeLibraryPch.h index 9d21f3703e5..f2f258df3bb 100644 --- a/lib/Runtime/Library/RuntimeLibraryPch.h +++ b/lib/Runtime/Library/RuntimeLibraryPch.h @@ -40,6 +40,9 @@ #include "Library/JavascriptVariantDate.h" #include "Library/JavascriptPromise.h" #include "Library/JavascriptSymbolObject.h" +#ifdef _CHAKRACOREBUILD +#include "Library/CustomExternalWrapperObject.h" +#endif #include "Library/JavascriptProxy.h" #include "Library/JavascriptReflect.h" #include "Library/JavascriptGenerator.h" diff --git a/lib/Runtime/Runtime.h b/lib/Runtime/Runtime.h index 0b0a3f9e6ea..fb0638c26a5 100644 --- a/lib/Runtime/Runtime.h +++ b/lib/Runtime/Runtime.h @@ -98,6 +98,9 @@ namespace Js class JavascriptBooleanObject; class JavascriptSymbol; class JavascriptSymbolObject; +#ifdef _CHAKRACOREBUILD + class CustomExternalWrapperObject; +#endif class JavascriptProxy; class JavascriptReflect; class JavascriptEnumeratorIterator; @@ -527,6 +530,9 @@ enum tagDEBUG_EVENT_INFO_TYPE #include "Types/ScriptFunctionType.h" #include "Library/ScriptFunction.h" +#ifdef _CHAKRACOREBUILD +#include "Library/CustomExternalWrapperObject.h" +#endif #include "Library/JavascriptProxy.h" #if ENABLE_TTD diff --git a/lib/Runtime/Types/DynamicObject.cpp b/lib/Runtime/Types/DynamicObject.cpp index 13efe77a1c1..14735c07fcb 100644 --- a/lib/Runtime/Types/DynamicObject.cpp +++ b/lib/Runtime/Types/DynamicObject.cpp @@ -825,7 +825,7 @@ namespace Js return reinterpret_cast(reinterpret_cast(this) + this->GetOffsetOfInlineSlots()); } - bool DynamicObject::IsCompatibleForCopy(DynamicObject* from) const + bool DynamicObject::IsCompatibleForCopy(DynamicObject* from, bool ignoreSideEffects) const { if (this->GetTypeHandler()->GetInlineSlotCapacity() != from->GetTypeHandler()->GetInlineSlotCapacity()) { @@ -861,7 +861,7 @@ namespace Js } return false; } - if (PathTypeHandlerBase::FromTypeHandler(from->GetTypeHandler())->HasAccessors()) + if (PathTypeHandlerBase::FromTypeHandler(from->GetTypeHandler())->HasAccessors() && !ignoreSideEffects) { if (PHASE_TRACE1(ObjectCopyPhase)) { @@ -877,7 +877,7 @@ namespace Js } return false; } - if (!from->GetTypeHandler()->AllPropertiesAreEnumerable()) + if (!from->GetTypeHandler()->AllPropertiesAreEnumerable() && !ignoreSideEffects) { if (PHASE_TRACE1(ObjectCopyPhase)) { @@ -885,7 +885,7 @@ namespace Js } return false; } - if (from->IsExternal()) + if (from->IsExternal() && !ignoreSideEffects) { if (PHASE_TRACE1(ObjectCopyPhase)) { @@ -905,7 +905,7 @@ namespace Js return true; } - bool DynamicObject::TryCopy(DynamicObject* from) + bool DynamicObject::TryCopy(DynamicObject* from, bool ignoreSideEffects) { #if ENABLE_TTD if (from->GetScriptContext()->ShouldPerformRecordOrReplayAction()) @@ -919,7 +919,7 @@ namespace Js return false; } // Validate that objects are compatible - if (!this->IsCompatibleForCopy(from)) + if (!this->IsCompatibleForCopy(from, ignoreSideEffects)) { return false; } @@ -1015,6 +1015,20 @@ namespace Js return GetRecycler()->CreateWeakReferenceHandle(this); } + DynamicObject * + DynamicObject::Copy(bool deepCopy) + { + size_t inlineSlotsSize = this->GetTypeHandler()->GetInlineSlotsSize(); + if (inlineSlotsSize) + { + return RecyclerNewPlusZ(GetRecycler(), inlineSlotsSize, DynamicObject, this, deepCopy); + } + else + { + return RecyclerNew(GetRecycler(), DynamicObject, this, deepCopy); + } + } + DynamicObject * DynamicObject::BoxStackInstance(DynamicObject * instance, bool deepCopy) { @@ -1027,15 +1041,7 @@ namespace Js return boxedInstance; } - size_t inlineSlotsSize = instance->GetTypeHandler()->GetInlineSlotsSize(); - if (inlineSlotsSize) - { - boxedInstance = RecyclerNewPlusZ(instance->GetRecycler(), inlineSlotsSize, DynamicObject, instance, deepCopy); - } - else - { - boxedInstance = RecyclerNew(instance->GetRecycler(), DynamicObject, instance, deepCopy); - } + boxedInstance = instance->Copy(deepCopy); *boxedInstanceRef = boxedInstance; return boxedInstance; diff --git a/lib/Runtime/Types/DynamicObject.h b/lib/Runtime/Types/DynamicObject.h index f25585644ca..79c97dc811f 100644 --- a/lib/Runtime/Types/DynamicObject.h +++ b/lib/Runtime/Types/DynamicObject.h @@ -172,7 +172,7 @@ namespace Js #endif private: - bool IsCompatibleForCopy(DynamicObject* from) const; + bool IsCompatibleForCopy(DynamicObject* from, bool ignoreSideEffects) const; bool IsObjectHeaderInlinedTypeHandlerUnchecked() const; public: @@ -232,7 +232,7 @@ namespace Js void InvalidateHasOnlyWritableDataPropertiesInPrototypeChainCacheIfPrototype(); void ResetObject(DynamicType* type, BOOL keepProperties); - bool TryCopy(DynamicObject* from); + bool TryCopy(DynamicObject* from, bool ignoreSideEffects = false); virtual void SetIsPrototype(); @@ -332,6 +332,8 @@ namespace Js RecyclerWeakReference* CreateWeakReferenceToSelf(); void SetObjectArray(ArrayObject* objectArray); + + DynamicObject * Copy(bool deepCopy); protected: BOOL GetEnumeratorWithPrefix(JavascriptEnumerator * prefixEnumerator, JavascriptStaticEnumerator * enumerator, EnumeratorFlags flags, ScriptContext * scriptContext, EnumeratorCache * enumeratorCache); diff --git a/lib/Runtime/Types/DynamicObjectPropertyEnumerator.cpp b/lib/Runtime/Types/DynamicObjectPropertyEnumerator.cpp index 02c21f31328..ca388f418ff 100644 --- a/lib/Runtime/Types/DynamicObjectPropertyEnumerator.cpp +++ b/lib/Runtime/Types/DynamicObjectPropertyEnumerator.cpp @@ -73,7 +73,7 @@ namespace Js Assert(data != nullptr); Assert(data->scriptContext == this->scriptContext); // The cache data script context should be the same as request context - if (data->enumNonEnumerable == GetEnumNonEnumerable()) + if (data->enumNonEnumerable == GetEnumNonEnumerable() && data->enumSymbols == GetEnumSymbols()) { Initialize(type, data, data->propertyCount); return true; diff --git a/lib/Runtime/Types/RecyclableObject.cpp b/lib/Runtime/Types/RecyclableObject.cpp index 9ebd9e18294..002e9f6dc4c 100644 --- a/lib/Runtime/Types/RecyclableObject.cpp +++ b/lib/Runtime/Types/RecyclableObject.cpp @@ -195,7 +195,11 @@ namespace Js { DynamicObject* obj = UnsafeVarTo(this); return obj->GetTypeHandler()->GetHasOnlyWritableDataProperties() && - (!obj->HasObjectArray() || obj->GetObjectArrayOrFlagsAsArray()->HasOnlyWritableDataProperties()); + (!obj->HasObjectArray() || obj->GetObjectArrayOrFlagsAsArray()->HasOnlyWritableDataProperties()) +#ifdef _CHAKRACOREBUILD + && (!VarIs(obj) || UnsafeVarTo(obj)->IsInitialized()) +#endif + ; } return true; @@ -207,7 +211,11 @@ namespace Js { DynamicObject* obj = UnsafeVarTo(this); return obj->GetTypeHandler()->GetHasSpecialProperties() || - (obj->HasObjectArray() && obj->GetObjectArrayOrFlagsAsArray()->HasAnySpecialProperties()); + (obj->HasObjectArray() && obj->GetObjectArrayOrFlagsAsArray()->HasAnySpecialProperties()) +#ifdef _CHAKRACOREBUILD + || (VarIs(obj) && !UnsafeVarTo(obj)->IsInitialized()) +#endif + ; } return true; diff --git a/lib/Runtime/Types/TypePropertyCache.cpp b/lib/Runtime/Types/TypePropertyCache.cpp index 3673bdde787..28d2974a146 100644 --- a/lib/Runtime/Types/TypePropertyCache.cpp +++ b/lib/Runtime/Types/TypePropertyCache.cpp @@ -302,7 +302,7 @@ namespace Js DebugOnly(Var getPropertyValue = JavascriptOperators::GetProperty(propertyObject, propertyId, requestContext)); Assert(*propertyValue == getPropertyValue || // In some cases, such as CustomExternalObject, if implicit calls are disabled GetPropertyQuery may return null. See CustomExternalObject::GetPropertyQuery for an example. - (getPropertyValue == requestContext->GetLibrary()->GetNull() && requestContext->GetThreadContext()->IsDisableImplicitCall() && propertyObject->GetType()->IsExternal())); + (getPropertyValue == requestContext->GetMissingPropertyResult() && requestContext->GetThreadContext()->IsDisableImplicitCall() && propertyObject->GetType()->IsJsrtExternal())); } if(propertyObject->GetScriptContext() != requestContext) diff --git a/lib/SCACore/CMakeLists.txt b/lib/SCACore/CMakeLists.txt new file mode 100644 index 00000000000..3eebc41cf56 --- /dev/null +++ b/lib/SCACore/CMakeLists.txt @@ -0,0 +1,22 @@ +add_library (Chakra.SCACore OBJECT + SCACore.cpp + SCACorePch.cpp + SCADeserialization.cpp + SCAEngine.cpp + SCAPropBag.cpp + SCASerialization.cpp + StreamHelper.cpp + StreamReader.cpp + StreamWriter.cpp + ) + + +target_include_directories ( + Chakra.SCACore PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + ../Parser + ../Common + ../Backend + ../JITIDL + ../Runtime + ../Runtime/ByteCode + ) diff --git a/lib/SCACore/Chakra.SCACore.vcxproj b/lib/SCACore/Chakra.SCACore.vcxproj new file mode 100644 index 00000000000..40d97cb9848 --- /dev/null +++ b/lib/SCACore/Chakra.SCACore.vcxproj @@ -0,0 +1,65 @@ + + + + + + Chakra.SCACore + {4DA3A367-6ED2-4EE8-9698-5BCD0B8AF7F5} + JS + Win32Proj + + + StaticLibrary + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + + + $(MSBuildThisFileDirectory)..\Common; + $(MSBuildThisFileDirectory)..\Parser; + $(MSBuildThisFileDirectory)..\Backend; + $(MSBuildThisFileDirectory)..\WasmReader; + $(MSBuildThisFileDirectory)..\JITClient; + $(MSBuildThisFileDirectory)..\Runtime; + $(MSBuildThisFileDirectory)..\Runtime\ByteCode; + $(ChakraManifestsIncludeDirectory); + %(AdditionalIncludeDirectories) + + Use + SCACorePch.h + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/SCACore/SCACore.cpp b/lib/SCACore/SCACore.cpp new file mode 100644 index 00000000000..25d907882aa --- /dev/null +++ b/lib/SCACore/SCACore.cpp @@ -0,0 +1,135 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +#include "SCACorePch.h" + +namespace Js +{ + namespace SCACore + { + HRESULT ValidateTransferableVars(Var *vars, size_t count) + { + for (size_t i = 0; i < count; i++) + { + Js::TypeId typeId = Js::JavascriptOperators::GetTypeId(vars[i]); + if (typeId != TypeIds_ArrayBuffer) + { + + AssertMsg(false, "These should have been filtered out by the host."); + return E_SCA_TRANSFERABLE_UNSUPPORTED; + } + + if (Js::JavascriptOperators::IsObjectDetached(vars[i])) + { + return E_SCA_TRANSFERABLE_NEUTERED; + } + } + return S_OK; + } + + + HRESULT Serializer::SetTransferableVars(Var *vars, size_t count) + { + if (m_transferableVars != nullptr) + { + Assert(false); + return E_FAIL; + } + else if (count > 0) + { + HRESULT hr = ValidateTransferableVars(vars, count); + if (hr != S_OK) + { + return hr; + } + m_transferableVars = vars; + m_cTransferableVars = count; + } + return S_OK; + } + + bool Serializer::WriteValue(Var rootObject) + { + ScriptContext *scriptContext = m_streamWriter.GetScriptContext(); + BEGIN_JS_RUNTIME_CALL(scriptContext) + { + Js::SCASerializationEngine::Serialize(rootObject, &m_streamWriter, m_transferableVars, m_cTransferableVars, nullptr /*TBD*/); + } + END_JS_RUNTIME_CALL(scriptContext) + return true; + } + + bool Serializer::DetachArrayBuffer() + { + Assert(false); + return true; + } + + void Serializer::WriteRawBytes(const void* source, size_t length) + { + ScriptContext *scriptContext = m_streamWriter.GetScriptContext(); + BEGIN_JS_RUNTIME_CALL(scriptContext) + { + m_streamWriter.Write(source, length); + } + END_JS_RUNTIME_CALL(scriptContext) + } + + bool Serializer::Release(byte** data, size_t *dataLength) + { + *data = m_streamWriter.GetBuffer(); + *dataLength = m_streamWriter.GetLength(); + return true; + } + + bool Deserializer::ReadRawBytes(size_t length, void **data) + { + m_streamReader.ReadRawBytes(data, length); + return true; + } + + bool Deserializer::ReadBytes(size_t length, void **data) + { + m_streamReader.Read(*data, length); + return true; + } + + Var Deserializer::ReadValue() + { + Var returnedValue = nullptr; + ScriptContext *scriptContext = m_streamReader.GetScriptContext(); + BEGIN_JS_RUNTIME_CALL(scriptContext) + { + returnedValue = Js::SCADeserializationEngine::Deserialize(&m_streamReader, m_transferableVars, m_cTransferableVars); + } + END_JS_RUNTIME_CALL(scriptContext) + return returnedValue; + } + + HRESULT Deserializer::SetTransferableVars(Var *vars, size_t count) + { + if (m_transferableVars != nullptr) + { + Assert(false); + return E_FAIL; + } + else if (count > 0) + { + HRESULT hr = ValidateTransferableVars(vars, count); + if (hr != S_OK) + { + return hr; + } + m_transferableVars = vars; + m_cTransferableVars = count; + } + return S_OK; + } + + } + +} + + diff --git a/lib/SCACore/SCACore.h b/lib/SCACore/SCACore.h new file mode 100644 index 00000000000..314c4ba42da --- /dev/null +++ b/lib/SCACore/SCACore.h @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------------------------------- +// 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 + +namespace Js +{ + namespace SCACore + { + class Serializer + { + public: + Serializer(ScriptContext *scriptContext, HostStream *stream) + : m_streamWriter(scriptContext, stream) + { + } + + HRESULT SetTransferableVars(Var *vars, size_t count); + + void WriteRawBytes(const void* source, size_t length); + bool WriteValue(Var rootObject); + bool DetachArrayBuffer(); + + bool Release(byte** data, size_t *dataLength); + + private: + StreamWriter m_streamWriter; + Var* m_transferableVars = nullptr; + size_t m_cTransferableVars = 0; + }; + + class Deserializer + { + public: + Deserializer(void *data, size_t length, ScriptContext *scriptContext, HostReadStream *stream) + : m_streamReader(scriptContext, (byte*)data, length, stream) + { + } + + HRESULT SetTransferableVars(Var *vars, size_t count); + + bool ReadRawBytes(size_t length, void **data); + bool ReadBytes(size_t length, void **data); + Var ReadValue(); + + private: + StreamReader m_streamReader; + Var* m_transferableVars = nullptr; + size_t m_cTransferableVars = 0; + }; + } + +} + diff --git a/lib/SCACore/SCACorePch.cpp b/lib/SCACore/SCACorePch.cpp new file mode 100644 index 00000000000..af1a47e71f3 --- /dev/null +++ b/lib/SCACore/SCACorePch.cpp @@ -0,0 +1,5 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- +#include "SCACorePch.h" diff --git a/lib/SCACore/SCACorePch.h b/lib/SCACore/SCACorePch.h new file mode 100644 index 00000000000..3e3520e0b57 --- /dev/null +++ b/lib/SCACore/SCACorePch.h @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------------------------------- +// 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 + +#if defined(__ANDROID__) +#include +#endif + +#include "Runtime.h" +#include "Library/JavascriptRegularExpression.h" +#include "Library/JavascriptProxy.h" +#include "Library/SameValueComparer.h" +#include "Library/MapOrSetDataList.h" +#include "Library/JavascriptMap.h" +#include "Library/JavascriptSet.h" +#include "Library/JavascriptWeakMap.h" +#include "Library/JavascriptWeakSet.h" +// ================= + +#include "SCATypes.h" +#include "SCAEngine.h" +#include "SCAPropBag.h" +#include "StreamHelper.h" +#include "StreamReader.h" +#include "StreamWriter.h" +#include "SCADeserialization.h" +#include "SCASerialization.h" +#include "SCACore.h" diff --git a/lib/SCACore/SCADeserialization.cpp b/lib/SCACore/SCADeserialization.cpp new file mode 100644 index 00000000000..89f65f424cb --- /dev/null +++ b/lib/SCACore/SCADeserialization.cpp @@ -0,0 +1,593 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +#include "SCACorePch.h" + +namespace Js +{ + template + bool DeserializationCloner::TryClonePrimitive(SrcTypeId typeId, Src src, Dst* dst) + { + if (!IsSCAPrimitive(typeId)) + { + return false; + } + + ScriptContext* scriptContext = this->GetScriptContext(); + JavascriptLibrary* lib = scriptContext->GetLibrary(); + + switch (typeId) + { + case SCA_None: + *dst = NULL; + break; + + case SCA_Reference: // Handle reference explictly as a primitive + { + scaposition_t pos; + m_reader->Read(&pos); + if (!this->GetEngine()->TryGetClonedObject(pos, dst)) + { + this->ThrowSCADataCorrupt(); + } + } + break; + + case SCA_NullValue: + *dst = lib->GetNull(); + break; + + case SCA_UndefinedValue: + *dst = lib->GetUndefined(); + break; + + case SCA_TrueValue: + *dst = lib->GetTrue(); + break; + + case SCA_FalseValue: + *dst = lib->GetFalse(); + break; + + case SCA_Int32Value: + { + int32 n; + m_reader->Read(&n); + *dst = JavascriptNumber::ToVar(n, scriptContext); + } + break; + + case SCA_DoubleValue: + { + double dbl; + m_reader->Read(&dbl); + *dst = JavascriptNumber::ToVarWithCheck(dbl, scriptContext); + } + break; + + case SCA_Int64Value: + { + __int64 n; + m_reader->Read(&n); + *dst = JavascriptInt64Number::ToVar(n, scriptContext); + } + break; + + case SCA_Uint64Value: + { + unsigned __int64 n; + m_reader->Read(&n); + *dst = JavascriptUInt64Number::ToVar(n, scriptContext); + } + break; + + default: + return false; // Not a recognized primitive type + } + + return true; + } + + template + bool DeserializationCloner::TryCloneObject(SrcTypeId typeId, Src src, Dst* dst, SCADeepCloneType* deepClone) + { + ScriptContext* scriptContext = this->GetScriptContext(); + JavascriptLibrary* lib = scriptContext->GetLibrary(); + *deepClone = SCADeepCloneType::None; + bool isObject = true; + + if (typeId == SCA_Transferable) + { + scaposition_t pos; + m_reader->Read(&pos); + + *dst = this->GetEngine()->ClaimTransferable(pos, lib); + if (*dst == nullptr) + { + this->ThrowSCADataCorrupt(); + } + + return true; + } + + if (IsSCAHostObject(typeId)) + { + *dst = m_reader->ReadHostObject(); + *deepClone = SCADeepCloneType::HostObject; + return true; + } + + switch (typeId) + { + case SCA_StringValue: // Clone string value as object type to resolve multiple references + { + charcount_t len; + const char16* buf = ReadString(&len); + *dst = Js::JavascriptString::NewWithBuffer(buf, len, scriptContext); + isObject = false; + } + break; + + case SCA_BooleanTrueObject: + *dst = lib->CreateBooleanObject(TRUE); + break; + + case SCA_BooleanFalseObject: + *dst = lib->CreateBooleanObject(FALSE); + break; + + case SCA_DateObject: + { + double dbl; + m_reader->Read(&dbl); + *dst = lib->CreateDate(dbl); + } + break; + + case SCA_NumberObject: + { + double dbl; + m_reader->Read(&dbl); + *dst = lib->CreateNumberObjectWithCheck(dbl); + } + break; + + case SCA_StringObject: + { + charcount_t len; + const char16* buf = ReadString(&len); + *dst = lib->CreateStringObject(buf, len); + } + break; + + case SCA_RegExpObject: + { + charcount_t len; + const char16* buf = ReadString(&len); + + DWORD flags; + m_reader->Read(&flags); + *dst = JavascriptRegExp::CreateRegEx(buf, len, + static_cast(flags), scriptContext); + } + break; + + case SCA_Object: + { + *dst = lib->CreateObject(); + *deepClone = SCADeepCloneType::Object; + } + break; + + case SCA_Map: + { + *dst = JavascriptMap::New(scriptContext); + *deepClone = SCADeepCloneType::Map; + } + break; + + case SCA_Set: + { + *dst = JavascriptSet::New(scriptContext); + *deepClone = SCADeepCloneType::Set; + } + break; + + case SCA_DenseArray: + case SCA_SparseArray: + { + uint32 length; + Read(&length); + *dst = lib->CreateArray(length); + *deepClone = SCADeepCloneType::Object; + } + break; + + case SCA_ArrayBuffer: + { + uint32 len; + m_reader->Read(&len); + ArrayBuffer* arrayBuffer = lib->CreateArrayBuffer(len); + Read(arrayBuffer->GetBuffer(), arrayBuffer->GetByteLength()); + *dst = arrayBuffer; + } + break; + + case SCA_SharedArrayBuffer: + { + SharedContents * sharedContents; + m_reader->Read((intptr_t*)&sharedContents); + + SharedArrayBuffer* arrayBuffer = lib->CreateSharedArrayBuffer(sharedContents); + Assert(arrayBuffer->IsWebAssemblyArrayBuffer() == sharedContents->IsWebAssembly()); + *dst = arrayBuffer; + } + break; + +//#ifdef ENABLE_WASM +// case SCA_WebAssemblyModule: +// { +// uint32 len; +// m_reader->Read(&len); +// byte* buffer = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), byte, len); +// Read(buffer, len); +// WebAssemblySource wasmSrc(buffer, len, true, scriptContext); +// *dst = WebAssemblyModule::CreateModule(scriptContext, &wasmSrc); +// break; +// } +// case SCA_WebAssemblyMemory: +// { +// uint32 initialLength = 0; +// uint32 maximumLength = 0; +// uint32 isShared = 0; +// m_reader->Read(&initialLength); +// m_reader->Read(&maximumLength); +// +//#ifdef ENABLE_WASM_THREADS +// m_reader->Read(&isShared); +// if (isShared) +// { +// SharedContents * sharedContents; +// m_reader->Read((intptr_t*)&sharedContents); +// *dst = WebAssemblyMemory::CreateFromSharedContents(initialLength, maximumLength, sharedContents, scriptContext); +// } +// else +//#endif +// { +// uint32 len; +// m_reader->Read(&len); +// WebAssemblyMemory* mem = WebAssemblyMemory::CreateForExistingBuffer(initialLength, maximumLength, len, scriptContext); +// Read(mem->GetBuffer()->GetBuffer(), len); +// *dst = mem; +// } +// break; +// } +//#endif + + case SCA_Uint8ClampedArray: + // If Khronos Interop is not enabled, we don't have Uint8ClampedArray available. + // This is a scenario where the source buffer was created in a newer document mode + // but needs to be deserialized in an older document mode. + // What we want to do is return the buffer as a CanvasPixelArray instead of + // Uint8ClampedArray since the older document mode knows what CanvasPixelArray is but + // not what Uint8ClampedArray is. + // We don't support pixelarray in edge anymore. + // Intentionally fall through to default (TypedArray) label + + default: + if (IsSCATypedArray(typeId) || typeId == SCA_DataView) + { + ReadTypedArray(typeId, dst); + break; + } + return false; // Not a supported object type + } + +#ifdef ENABLE_JS_ETW + if (EventEnabledJSCRIPT_RECYCLER_ALLOCATE_OBJECT() && isObject) + { + EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(*dst); + } +#endif +#if ENABLE_DEBUG_CONFIG_OPTIONS + if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag)) + { + *dst = JavascriptProxy::AutoProxyWrapper(*dst); + } +#endif + return true; + } + + template + void DeserializationCloner::CloneHostObjectProperties(SrcTypeId typeId, Src src, Dst dst) + { + // We have already created host obect. + } + + template + void DeserializationCloner::CloneProperties(SrcTypeId typeId, Src src, Dst dst) + { + // ScriptContext* scriptContext = GetScriptContext(); + RecyclableObject* obj = VarTo(dst); + + if (obj->IsExternal()) // Read host object properties + { + Assert(false); + } + else // Read native object properties + { + // Read array index named properties + if (typeId == SCA_DenseArray) + { + JavascriptArray* arr = JavascriptArray::FromAnyArray(obj); // (might be ES5Array if -ForceES5Array) + uint32 length = arr->GetLength(); + for (uint32 i = 0; i < length; i++) + { + Dst value = NULL; + this->GetEngine()->Clone(m_reader->GetPosition(), &value); + if (value) + { + arr->DirectSetItemAt(i, value); //Note: no prototype check + } + } + } + else if (typeId == SCA_SparseArray) + { + JavascriptArray* arr = JavascriptArray::FromAnyArray(obj); // (might be ES5Array if -ForceES5Array) + while (true) + { + uint32 i; + Read(&i); + if (i == SCA_PROPERTY_TERMINATOR) + { + break; + } + + Dst value = NULL; + this->GetEngine()->Clone(m_reader->GetPosition(), &value); + if (value == NULL) + { + this->ThrowSCADataCorrupt(); + } + + arr->DirectSetItemAt(i, value); //Note: no prototype check + } + } + + // Read non-index named properties + ReadObjectPropertiesIntoObject(obj); + } + } + + template + void DeserializationCloner::CloneMap(Src src, Dst dst) + { + JavascriptMap* map = VarTo(dst); + + int32 size; + m_reader->Read(&size); + + for (int i = 0; i < size; i++) + { + Var key; + Var value; + + this->GetEngine()->Clone(m_reader->GetPosition(), &key); + if (!key) + { + this->ThrowSCADataCorrupt(); + } + + this->GetEngine()->Clone(m_reader->GetPosition(), &value); + if (!value) + { + this->ThrowSCADataCorrupt(); + } + + map->Set(key, value); + } + } + + template + void DeserializationCloner::CloneSet(Src src, Dst dst) + { + JavascriptSet* set = VarTo(dst); + + int32 size; + m_reader->Read(&size); + + for (int i = 0; i < size; i++) + { + Var value; + + this->GetEngine()->Clone(m_reader->GetPosition(), &value); + if (!value) + { + this->ThrowSCADataCorrupt(); + } + + set->Add(value); + } + } + + template + void DeserializationCloner::CloneObjectReference(Src src, Dst dst) + { + Assert(FALSE); // Should never call this. Object reference handled explictly. + } + + // + // Try to read a SCAString layout in the form of: [byteLen] [string content] [padding]. + // SCAString is also used for property name in object layout. In case of property terminator, + // SCA_PROPERTY_TERMINATOR will appear at the place of [byteLen]. Return false in this case. + // + // If buffer is not null and the size is appropriate, will try reusing it + // + template + const char16* DeserializationCloner::TryReadString(charcount_t* len, bool reuseBuffer) const + { + // m_buffer is allocated on GC heap and stored in a regular field. + // that is ok since 'this' is always a stack instance. + Assert(ThreadContext::IsOnStack(this)); + + uint32 byteLen; + m_reader->Read(&byteLen); + + if (byteLen == SCA_PROPERTY_TERMINATOR) + { + return nullptr; + } + else if (byteLen == 0) + { + *len = 0; + return _u(""); + } + else + { + charcount_t newLen = byteLen / sizeof(char16); + char16* buf; + + if (reuseBuffer) + { + if (this->m_bufferLength < newLen) + { + Recycler* recycler = this->GetScriptContext()->GetRecycler(); + this->m_buffer = RecyclerNewArrayLeaf(recycler, char16, newLen + 1); + this->m_bufferLength = newLen; + } + + buf = this->m_buffer; + } + else + { + Recycler* recycler = this->GetScriptContext()->GetRecycler(); + buf = RecyclerNewArrayLeaf(recycler, char16, newLen + 1); + } + + m_reader->Read(buf, byteLen); + buf[newLen] = NULL; + *len = newLen; + + uint32 unalignedLen = byteLen % sizeof(uint32); + if (unalignedLen) + { + uint32 padding; + m_reader->Read(&padding, sizeof(uint32) - unalignedLen); + } + + return buf; + } + } + + // + // Read a SCAString value from layout: [byteLen] [string content] [padding]. + // Throw if seeing SCA_PROPERTY_TERMINATOR. + // + template + const char16* DeserializationCloner::ReadString(charcount_t* len) const + { + const char16* str = TryReadString(len, false); + + if (str == nullptr) + { + this->ThrowSCADataCorrupt(); + } + + return str; + } + + // + // Read bytes data: [bytes] [padding] + // + template + void DeserializationCloner::Read(BYTE* buf, uint32 len) const + { + m_reader->Read(buf, len); + + uint32 unalignedLen = len % sizeof(uint32); + if (unalignedLen) + { + uint32 padding; + m_reader->Read(&padding, sizeof(uint32) - unalignedLen); + } + } + + // + // Read a TypedArray or DataView. + // + template + void DeserializationCloner::ReadTypedArray(SrcTypeId typeId, Dst* dst) const + { + switch (typeId) + { + case SCA_Int8Array: + ReadTypedArray(dst); + break; + + case SCA_Uint8Array: + ReadTypedArray(dst); + break; + + case SCA_Uint8ClampedArray: + ReadTypedArray(dst); + break; + + case SCA_Int16Array: + ReadTypedArray(dst); + break; + + case SCA_Uint16Array: + ReadTypedArray(dst); + break; + + case SCA_Int32Array: + ReadTypedArray(dst); + break; + + case SCA_Uint32Array: + ReadTypedArray(dst); + break; + + case SCA_Float32Array: + ReadTypedArray(dst); + break; + + case SCA_Float64Array: + ReadTypedArray(dst); + break; + + case SCA_DataView: + ReadTypedArray(dst); + break; + + default: + Assert(false); + break; + } + } + + template class DeserializationCloner; + + Var SCADeserializationEngine::Deserialize(StreamReader* reader, Var* transferableVars, size_t cTransferableVars) + { + ScriptContext* scriptContext = reader->GetScriptContext(); + StreamDeserializationCloner cloner(scriptContext, reader); + + // Read version + uint32 version; + reader->Read(&version); + if (GetSCAMajor(version) > SCA_FORMAT_MAJOR) + { + cloner.ThrowSCANewVersion(); + } + Var value = SCAEngine::Clone(reader->GetPosition(), &cloner, transferableVars, cTransferableVars); + if (!value) + { + cloner.ThrowSCADataCorrupt(); + } + + return value; + } +} diff --git a/lib/SCACore/SCADeserialization.h b/lib/SCACore/SCADeserialization.h new file mode 100644 index 00000000000..9df0af36e47 --- /dev/null +++ b/lib/SCACore/SCADeserialization.h @@ -0,0 +1,171 @@ +//------------------------------------------------------------------------------------------------------- +// 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 +namespace Js +{ + class SCAPropBag; + + // + // DeserializationCloner helps clone a Var from a stream location. + // + template + class DeserializationCloner: + public ClonerBase > + { + public: + using typename ClonerBase >::Dst; + using typename ClonerBase >::Src; + using typename ClonerBase >::SrcTypeId; + private: + //AutoCOMPtr m_pSCAHost; + //AutoCOMPtr m_pSCAContext; + Reader* m_reader; + mutable char16* m_buffer; + mutable charcount_t m_bufferLength; + + + private: + SCATypeId ReadTypeId() const + { + uint32 typeId; + m_reader->Read(&typeId); + return static_cast(typeId); + } + + void Read(uint32* value) const + { + m_reader->Read(value); + } + + const char16* TryReadString(charcount_t* len, bool reuseBuffer) const; + const char16* ReadString(charcount_t* len) const; + void Read(BYTE* buf, uint32 len) const; + + // + // Read a TypedArray or DataView. + // + template + void ReadTypedArray(Dst* dst) const + { + typedef TypedArrayTrace trace_type; + + Dst arrayBuffer; + this->GetEngine()->Clone(m_reader->GetPosition(), &arrayBuffer); + if (!arrayBuffer || !VarIs(arrayBuffer)) + { + this->ThrowSCADataCorrupt(); + } + + uint32 byteOffset, length; + Read(&byteOffset); + Read(&length); + *dst = trace_type::CreateTypedArray( + VarTo(arrayBuffer), byteOffset, length, this->GetScriptContext()); + } + + void ReadTypedArray(SrcTypeId typeId, Dst* dst) const; + + // + // Read a SCAProperties section: {SCAPropertyName SCAValue} SCAPropertiesTerminator + // + void ReadObjectPropertiesIntoObject(RecyclableObject* m_obj) + { + ScriptContext* scriptContext = this->GetScriptContext(); + + for(;;) + { + charcount_t len = 0; + const char16* name = TryReadString(&len, /*reuseBuffer*/ true); + if (!name) + { + break; + } + + Js::PropertyRecord const * propertyRecord; + scriptContext->GetOrAddPropertyRecord(name, len, &propertyRecord); + + // NOTE: 'Clone' may reenter here and use the buffer that backs the 'name'. + // That is ok, since we do not need it past this point. + // The propertyRecord keeps its own copy od the data. + + Var value; + this->GetEngine()->Clone(m_reader->GetPosition(), &value); + if (!value) + { + this->ThrowSCADataCorrupt(); + } + + m_obj->SetProperty(propertyRecord->GetPropertyId(), value, PropertyOperation_None, NULL); //Note: no prototype check + } + } + + void ReadObjectPropertiesIntoBag(SCAPropBag* m_propbag) + { + for (;;) + { + charcount_t len = 0; + // NOTE: we will not reuse buffer here since the propbag may retain the string. + const char16* name = TryReadString(&len, /*reuseBuffer*/ false); + if (!name) + { + break; + } + + Var value; + this->GetEngine()->Clone(m_reader->GetPosition(), &value); + if (!value) + { + this->ThrowSCADataCorrupt(); + } + + HRESULT hr = m_propbag->InternalAddNoCopy(name, len, value); + m_propbag->ThrowIfFailed(hr); + } + } + + public: + DeserializationCloner(ScriptContext* scriptContext, Reader* reader) + : ClonerBase >(scriptContext), m_reader(reader), + m_buffer(nullptr), m_bufferLength(0) + { + } + + static bool ShouldLookupReference() + { + // Never lookup reference when cloning from stream location. DeserializationCloner + // handles object reference lookup explictly when seeing a reference SCATypeId. + return false; + } + + SrcTypeId GetTypeId(Src src) const + { + Assert(m_reader->GetPosition() == src); // Only allow the current position + return ReadTypeId(); + } + + void ThrowSCAUnsupported() const + { + // Unexpected SCATypeId indicates data corruption. + this->ThrowSCADataCorrupt(); + } + + bool TryClonePrimitive(SrcTypeId typeId, Src src, Dst* dst); + bool TryCloneObject(SrcTypeId typeId, Src src, Dst* dst, SCADeepCloneType* deepClone); + void CloneProperties(SrcTypeId typeId, Src src, Dst dst); + void CloneHostObjectProperties(SrcTypeId typeId, Src src, Dst dst); + void CloneMap(Src src, Dst dst); + void CloneSet(Src src, Dst dst); + void CloneObjectReference(Src src, Dst dst); + }; + + class SCADeserializationEngine + { + typedef DeserializationCloner StreamDeserializationCloner; + + public: + static Var Deserialize(StreamReader* reader, Var* transferableVars, size_t cTransferableVars); + }; +} diff --git a/lib/SCACore/SCAEngine.cpp b/lib/SCACore/SCAEngine.cpp new file mode 100644 index 00000000000..4d859286b1d --- /dev/null +++ b/lib/SCACore/SCAEngine.cpp @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +#include "SCACorePch.h" +#ifdef ENABLE_SCRIPT_DEBUGGING +#include "Debug/ProbeContainer.h" +#include "Debug/DebugContext.h" +#endif + +namespace Js +{ + void ScriptContextHolder::ThrowIfFailed(HRESULT hr) const + { + if (FAILED(hr)) + { + m_scriptContext->GetHostScriptContext()->ThrowIfFailed(hr); + + // No debugger support yet. + } + } +}; diff --git a/lib/SCACore/SCAEngine.h b/lib/SCACore/SCAEngine.h new file mode 100644 index 00000000000..aa316f15624 --- /dev/null +++ b/lib/SCACore/SCAEngine.h @@ -0,0 +1,234 @@ +//------------------------------------------------------------------------------------------------------- +// 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 +namespace Js +{ + enum class SCADeepCloneType + { + None, + Object, + Map, + Set, + HostObject + }; + + // + // SCAEngine performs the SCA algorithm by "cloning" a JavaScript var from Src representation + // to Dst represetation. The representation could be a Var, or a location in a stream. + // + template + class SCAEngine + { + private: + // The map type that stores a map of cloned objects {Src->Dst}. Use + // non leaf allocator because the map contains Vars. + typedef JsUtil::BaseDictionary ClonedObjectDictionary; + + Cloner* m_cloner; + ClonedObjectDictionary* m_clonedObjects; + Var* m_transferableVars; + size_t m_cTransferableVars; + + private: + SCAEngine(Cloner* cloner, Var* m_transferableVars, size_t cTransferableVars) + : m_cloner(cloner), + m_transferableVars(m_transferableVars), + m_cTransferableVars(cTransferableVars) + { + Recycler* recycler = cloner->GetScriptContext()->GetRecycler(); + m_clonedObjects = RecyclerNew(recycler, ClonedObjectDictionary, recycler); + m_cloner->SetEngine(this); + } + + public: + + void Clone(Src src, Dst* dst) + { + PROBE_STACK(m_cloner->GetScriptContext(), Constants::MinStackDefault); + +#if ENABLE_COPYONACCESS_ARRAY + JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray(src); +#endif + + typename Cloner::SrcTypeId typeId = m_cloner->GetTypeId(src); + + if (m_cloner->TryClonePrimitive(typeId, src, dst)) + { + return; + } + + if (Cloner::ShouldLookupReference() && TryGetClonedObject(src, dst)) + { + m_cloner->CloneObjectReference(src, *dst); + return; + } + + SCADeepCloneType deepClone; + if (m_cloner->TryCloneObject(typeId, src, dst, &deepClone)) + { + m_clonedObjects->Add(src, *dst); + + if (deepClone == SCADeepCloneType::Map) + { + m_cloner->CloneMap(src, *dst); + deepClone = SCADeepCloneType::Object; + } + else if (deepClone == SCADeepCloneType::Set) + { + m_cloner->CloneSet(src, *dst); + deepClone = SCADeepCloneType::Object; + } + + if (deepClone == SCADeepCloneType::HostObject) + { + m_cloner->CloneHostObjectProperties(typeId, src, *dst); + } + else if (deepClone == SCADeepCloneType::Object) + { + m_cloner->CloneProperties(typeId, src, *dst); + } + return; + } + + // Unsupported src type, throw + m_cloner->ThrowSCAUnsupported(); + } + + void Clone(Src src) + { + Dst unused; + Clone(src, &unused); + } + + bool TryGetClonedObject(Src src, Dst* dst) const + { + return m_clonedObjects->TryGetValue(src, dst); + } + + bool TryGetTransferredOrShared(Var source, size_t* outDestination) + { + if (m_transferableVars == nullptr) + { + return false; + } + + for (size_t i = 0; i < m_cTransferableVars; i++) + { + if (m_transferableVars[i] == source) + { + if (outDestination != nullptr) + { + *outDestination = i; + } + + return true; + } + } + + return false; + } + + Dst ClaimTransferable(size_t index, JavascriptLibrary* library) + { + AssertMsg(index < this->m_cTransferableVars, "Index out of range."); + ArrayBuffer *ab = VarTo(m_transferableVars[index]); + + // TODO reuse the same ArrayBuffer instead of creating a new ArrayBuffer. + // Current ArrayBuffer's from m_transferableVars are JsrtExternalArrayBuffer. + return library->CreateArrayBuffer((byte*)ab->GetBuffer(), ab->GetByteLength()); + } + + static Dst Clone(Src root, Cloner* cloner, Var* transferableVars, size_t cTransferableVars) + { + SCAEngine engine(cloner, transferableVars, cTransferableVars); + Dst dst; + engine.Clone(root, &dst); + return dst; + } + }; + + // + // Helper class that simply contains a ScriptContext*. + // + class ScriptContextHolder + { + private: + ScriptContext* m_scriptContext; + + public: + ScriptContextHolder(ScriptContext* scriptContext) + : m_scriptContext(scriptContext) + { + } + + ScriptContext* GetScriptContext() const + { + return m_scriptContext; + } + + void ThrowIfFailed(HRESULT hr) const; + + void __declspec(noreturn) ThrowSCAUnsupported() const + { + // E_SCA_UNSUPPORTED + ThrowIfFailed(E_FAIL); + } + + void __declspec(noreturn) ThrowSCANewVersion() const + { + // E_SCA_NEWVERSION + ThrowIfFailed(E_FAIL); + } + + void __declspec(noreturn) ThrowSCADataCorrupt() const + { + // E_SCA_DATACORRUPT + ThrowIfFailed(E_FAIL); + } + + void __declspec(noreturn) ThrowSCAObjectDetached() const + { + // E_SCA_TRANSFERABLE_NEUTERED + ThrowIfFailed(E_FAIL); + } + }; + + // + // Helper class to implement Cloner. + // + template + class ClonerBase : public ScriptContextHolder + { + public: + typedef TSrc Src; + typedef TDst Dst; + typedef TSrcTypeId SrcTypeId; + typedef SCAEngine Engine; + + private: + Engine* m_engine; + + public: + ClonerBase(ScriptContext* scriptContext) + : ScriptContextHolder(scriptContext), + m_engine(NULL) + { + } + + Engine* GetEngine() const + { + Assert(m_engine); // Must have been set + return m_engine; + } + + void SetEngine(Engine* engine) + { + Assert(!m_engine); // Can only be set once + m_engine = engine; + } + }; + +} diff --git a/lib/SCACore/SCAPropBag.cpp b/lib/SCACore/SCAPropBag.cpp new file mode 100644 index 00000000000..24efd93f259 --- /dev/null +++ b/lib/SCACore/SCAPropBag.cpp @@ -0,0 +1,168 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +#include "SCACorePch.h" + + +#define IfFailGoto(expr, label) \ + do \ + { \ + hr = (expr); \ + if (FAILED (hr)) \ + { \ + goto label; \ + } \ + } while (FALSE) \ + +#define IfFailGo(expr) IfFailGoto(expr, Error) + +namespace Js +{ + SCAPropBag::SCAPropBag(ScriptContext* scriptContext) + : ScriptContextHolder(scriptContext), m_refCount(1) + { + Recycler* recycler = GetScriptContext()->GetRecycler(); + m_properties.Root(RecyclerNew(recycler, PropertyDictionary, recycler), recycler); + } + + SCAPropBag::~SCAPropBag() + { + Recycler* recycler = GetScriptContext()->GetRecycler(); + m_properties.Unroot(recycler); + } + + void SCAPropBag::CreateInstance(ScriptContext* scriptContext, SCAPropBag** ppInstance) + { + *ppInstance = HeapNew(SCAPropBag, scriptContext); + } + + STDMETHODIMP_(ULONG) SCAPropBag::AddRef() + { + Assert(m_refCount > 0); + return InterlockedIncrement(&m_refCount); + } + + STDMETHODIMP_(ULONG) SCAPropBag::Release() + { + Assert(m_refCount > 0); + ULONG ref = InterlockedDecrement(&m_refCount); + if (ref == 0) + { + HeapDelete(this); + } + return ref; + } + + STDMETHODIMP SCAPropBag::QueryInterface(REFIID riid, void** ppv) + { + if (ppv == nullptr) + { + return E_POINTER; + } + + if (IsEqualGUID(riid, IID_IUnknown)) + { + *ppv = static_cast(this); + AddRef(); + return S_OK; + } + + *ppv = nullptr; + return E_NOINTERFACE; + } + + HRESULT SCAPropBag::Add(LPCWSTR name, Var value) + { + HRESULT hr = S_OK; + ScriptContext* scriptContext = GetScriptContext(); + + BEGIN_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT + { + BEGIN_JS_RUNTIME_CALL_EX(scriptContext, false) + { + charcount_t len; + IfFailGo(SizeTToUInt(wcslen(name), &len)); + IfFailGo(InternalAdd(name, len, value)); +Error: + ; // Fall through + } + END_JS_RUNTIME_CALL(scriptContext); + } + END_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT(hr); + + return hr; + } + + HRESULT SCAPropBag::Get(LPCWSTR name, Var* pValue) + { + HRESULT hr = S_OK; + ScriptContext* scriptContext = GetScriptContext(); + + BEGIN_JS_RUNTIME_CALL_EX(scriptContext, false) + { + int len; + IfFailGo(SizeTToInt(wcslen(name), &len)); + + if (!m_properties->TryGetValue(InternalString(name, len), pValue)) + { + hr = E_FAIL; + } + } + END_JS_RUNTIME_CALL(scriptContext); +Error: + return hr; + } + + HRESULT SCAPropBag::InternalAdd(LPCWSTR name, charcount_t len, Var value) + { + char16* buf = nullptr; + HRESULT hr = S_OK; + ScriptContext* scriptContext = GetScriptContext(); + Recycler* recycler = scriptContext->GetRecycler(); + charcount_t fullLen; + charcount_t byteLen; + + // fullLen == len + 1 + IfFailGo(UIntAdd(len, 1, &fullLen)); + + // byte length (excluding null terminator) + IfFailGo(UIntMult(len, sizeof(char16), &byteLen)); + + // Make a copy of name + buf = RecyclerNewArrayLeaf(recycler, char16, fullLen); + js_memcpy_s(buf, byteLen, name, byteLen); + buf[len] = _u('\0'); + + // Add to the property bag + IfFailGo(InternalAddNoCopy(buf, len, value)); + +Error: + return hr; + } + + HRESULT SCAPropBag::InternalAddNoCopy(LPCWSTR name, charcount_t len, Var value) + { + HRESULT hr = S_OK; + + int intLen; + IfFailGo(UIntToInt(len, &intLen)); + m_properties->Item(InternalString(name, intLen), value); + +Error: + return hr; + } + + bool SCAPropBag::PropBagEnumerator::MoveNext() + { + while (++m_curIndex < m_properties->Count()) + { + if (m_properties->GetValueAt(m_curIndex)) + { + return true; + } + } + return false; + } +} diff --git a/lib/SCACore/SCAPropBag.h b/lib/SCACore/SCAPropBag.h new file mode 100644 index 00000000000..4e11093f952 --- /dev/null +++ b/lib/SCACore/SCAPropBag.h @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------------------------------- +// 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 +namespace Js +{ + // + // Implements ISCAPropBag. + // + class SCAPropBag sealed : + public ScriptContextHolder, + public IUnknown + { + typedef JsUtil::BaseDictionary PropertyDictionary; + + private: + RecyclerRootPtr m_properties; + ULONG m_refCount; + + SCAPropBag(ScriptContext* scriptContext); + HRESULT InternalAdd(LPCWSTR name, charcount_t len, Var value); + + public: + ~SCAPropBag(); + static void CreateInstance(ScriptContext* scriptContext, SCAPropBag** ppInstance); + + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + STDMETHODIMP QueryInterface(REFIID riid, void** ppv); + + HRESULT Add(LPCWSTR name, Var value); + HRESULT Get(LPCWSTR name, Var* pValue); + + HRESULT InternalAddNoCopy(LPCWSTR name, charcount_t len, Var value); + + // + // PropBag property enumerator for WriteObjectProperties. + // + class PropBagEnumerator + { + private: + PropertyDictionary* m_properties; + int m_curIndex; + + public: + PropBagEnumerator(SCAPropBag* propBag) + : m_properties(propBag->m_properties), m_curIndex(-1) + { + } + + bool MoveNext(); + + const char16* GetNameString() const + { + return m_properties->GetKeyAt(m_curIndex).GetBuffer(); + } + + charcount_t GetNameLength() const + { + return m_properties->GetKeyAt(m_curIndex).GetLength(); + } + + Var GetValue() const + { + return m_properties->GetValueAt(m_curIndex); + } + }; + }; +} diff --git a/lib/SCACore/SCASerialization.cpp b/lib/SCACore/SCASerialization.cpp new file mode 100644 index 00000000000..e49ff5b020a --- /dev/null +++ b/lib/SCACore/SCASerialization.cpp @@ -0,0 +1,637 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +#include "SCACorePch.h" +#include "Common/ByteSwap.h" +#include "Library/JavascriptNumberObject.h" +#include "Library/JavascriptStringObject.h" +#include "Library/JavascriptBooleanObject.h" +#include "Library/DateImplementation.h" +#include "Library/JavascriptDate.h" +#include "Library/DataView.h" +#include "Library/ES5Array.h" + +#include "Types/PropertyIndexRanges.h" +#include "Types/DictionaryPropertyDescriptor.h" +#include "Types/DictionaryTypeHandler.h" +#include "Types/ES5ArrayTypeHandler.h" +#include "Library/JavascriptArrayIndexStaticEnumerator.h" +#include "Library/ES5ArrayIndexStaticEnumerator.h" + +namespace Js +{ + template + bool SerializationCloner::TryClonePrimitive(SrcTypeId typeId, Src src, Dst* dst) + { + switch (typeId) + { + case TypeIds_Undefined: + WriteTypeId(SCA_UndefinedValue); + break; + + case TypeIds_Null: + WriteTypeId(SCA_NullValue); + break; + + case TypeIds_Boolean: + WriteTypeId( + VarTo(src)->GetValue() ? SCA_TrueValue : SCA_FalseValue); + break; + + case TypeIds_Integer: + { + WriteTypeId(SCA_Int32Value); + m_writer->Write(TaggedInt::ToInt32(src)); + } + break; + + case TypeIds_Number: + { + WriteTypeId(SCA_DoubleValue); + m_writer->Write(JavascriptNumber::GetValue(src)); + } + break; + + case TypeIds_Int64Number: + { + WriteTypeId(SCA_Int64Value); + m_writer->Write(VarTo(src)->GetValue()); + } + break; + + case TypeIds_UInt64Number: + { + WriteTypeId(SCA_Uint64Value); + m_writer->Write(VarTo(src)->GetValue()); + } + break; + + default: + return false; // Not a recognized primitive type + } + + return true; + } + + template + bool SerializationCloner::TryCloneObject(SrcTypeId typeId, Src src, Dst* dst, SCADeepCloneType* deepClone) + { + RecyclableObject* obj = VarTo(src); + scaposition_t beginPos = m_writer->GetPosition(); + *deepClone = SCADeepCloneType::None; + + size_t transferredIndex = 0; + if (this->CanBeTransferred(typeId) && this->GetEngine()->TryGetTransferredOrShared(src, &transferredIndex)) + { + WriteTypeId(SCA_Transferable); + m_writer->Write((uint32)transferredIndex); + } + else if (JavascriptOperators::IsObjectDetached(src)) + { + //Object is detached, throw error + this->ThrowSCAObjectDetached(); + } + else + { + switch (typeId) + { + case TypeIds_String: // Clone string value as object type to resolve multiple references + { + JavascriptString* str = VarTo(obj); + WriteTypeId(SCA_StringValue); + Write(str->GetString(), str->GetLength()); + } + break; + + case TypeIds_Object: + { + WriteTypeId(SCA_Object); + *deepClone = SCADeepCloneType::Object; + } + break; + + case TypeIds_Proxy: + { + // Currently SCA algorithm does not support proxy. We'll see + // if the spec will be updated. I don't support QueryObjectInterface in proxy + // so we don't want to go through the default code path. + return false; + } + case TypeIds_Array: + case TypeIds_ES5Array: + case TypeIds_NativeIntArray: + case TypeIds_NativeFloatArray: + { + // Postpone writing to CloneProperties + *deepClone = SCADeepCloneType::Object; + } + break; + + case TypeIds_Date: + { + WriteTypeId(SCA_DateObject); + m_writer->Write(VarTo(src)->GetTime()); + } + break; + + case TypeIds_RegEx: + { + JavascriptRegExp* regex = VarTo(src); + InternalString str = regex->GetSource(); + DWORD flags = static_cast(regex->GetFlags()); + WriteTypeId(SCA_RegExpObject); + Write(str.GetBuffer(), str.GetLength()); + m_writer->Write(flags); + } + break; + + case TypeIds_BooleanObject: + WriteTypeId(VarTo(src)->GetValue() ? + SCA_BooleanTrueObject : SCA_BooleanFalseObject); + break; + + case TypeIds_NumberObject: + { + WriteTypeId(SCA_NumberObject); + m_writer->Write(VarTo(src)->GetValue()); + } + break; + + case TypeIds_StringObject: + { + JavascriptString* str = VarTo(src)->Unwrap(); + WriteTypeId(SCA_StringObject); + Write(str->GetString(), str->GetLength()); + } + break; + + case TypeIds_ArrayBuffer: + { + ArrayBuffer* buf = VarTo(src); + WriteTypeId(SCA_ArrayBuffer); + Write(buf->GetBuffer(), buf->GetByteLength()); + } + break; + + case TypeIds_SharedArrayBuffer: + { + // TBD + + //SCAContextType contextType; + //if (FAILED(this->m_pSCAContext->GetContext(&contextType))) + //{ + // return false; + //} + // + //if(contextType == SCAContext_CrossProcess || contextType == SCAContext_Persist) + //{ + // return false; + //} + + SharedArrayBuffer* buf = VarTo(src); + SharedContents* sharedContents = buf->GetSharedContents(); + Assert(buf->IsWebAssemblyArrayBuffer() == sharedContents->IsWebAssembly()); + sharedContents->AddRef(); + this->m_sharedContentsrList->Add(sharedContents); + WriteTypeId(SCA_SharedArrayBuffer); + m_writer->Write((intptr_t)sharedContents); + } + break; + + case TypeIds_Map: + { + WriteTypeId(SCA_Map); + *deepClone = SCADeepCloneType::Map; + } + break; + + case TypeIds_Set: + { + WriteTypeId(SCA_Set); + *deepClone = SCADeepCloneType::Set; + } + break; + +#ifdef ENABLE_WASM + case TypeIds_WebAssemblyModule: + { + WebAssemblyModule* wasmModule = VarTo(src); + WriteTypeId(SCA_WebAssemblyModule); + Write(wasmModule->GetBinaryBuffer(), wasmModule->GetBinaryBufferLength()); + } + break; + case TypeIds_WebAssemblyMemory: + { + WebAssemblyMemory* wasmMem = VarTo(src); + ArrayBufferBase* buffer = wasmMem->GetBuffer(); + WriteTypeId(SCA_WebAssemblyMemory); + Write(wasmMem->GetInitialLength()); + Write(wasmMem->GetMaximumLength()); +#ifdef ENABLE_WASM_THREADS + Write((uint32)wasmMem->IsSharedMemory()); + if (wasmMem->IsSharedMemory()) + { + WebAssemblySharedArrayBuffer* buf = VarTo(buffer); + SharedContents* sharedContents = buf->GetSharedContents(); + sharedContents->AddRef(); + this->m_sharedContentsrList->Add(sharedContents); + m_writer->Write((intptr_t)sharedContents); + } + else +#endif + { + Write(buffer->GetBuffer(), buffer->GetByteLength()); + } + break; + } +#endif + +#if ENABLE_COPYONACCESS_ARRAY + case TypeIds_CopyOnAccessNativeIntArray: + Assert(false); + // fall-through +#endif + + default: + if (IsTypedArray(typeId)) + { + WriteTypedArray(typeId, src); + } + else + { + // Try Host Object + *deepClone = SCADeepCloneType::HostObject; + } + break; + } + } + + *dst = beginPos; + return true; + } + + template + void SerializationCloner::CloneHostObjectProperties(SrcTypeId srcTypeId, Src src, Dst dst) + { + WriteTypeId(SCA_FirstHostObject); + + // Ask host to fill rest of the properties + m_writer->WriteHostObject((void*)src); + } + + template + void SerializationCloner::CloneProperties(SrcTypeId srcTypeId, Src src, Dst dst) + { + RecyclableObject* obj = VarTo(src); + // allocate the JavascriptStaticEnumerator on the heap to avoid blowing the stack + JavascriptStaticEnumerator enumerator; + ScriptContext* scriptContext = this->GetScriptContext(); + if (DynamicObject::IsAnyArrayTypeId(srcTypeId)) + { + JavascriptArray* arr = JavascriptArray::FromAnyArray(src); + bool isSparseArray = IsSparseArray(arr); + + WriteTypeId(isSparseArray ? SCA_SparseArray : SCA_DenseArray); + Write(arr->GetLength()); + + if (isSparseArray) + { + WriteSparseArrayIndexProperties(arr); + } + else + { + WriteDenseArrayIndexProperties(arr); + } + + // Now we only need to write remaining non-index properties + arr->GetNonIndexEnumerator(&enumerator, scriptContext); + } + else if (!obj->GetEnumerator(&enumerator, EnumeratorFlags::SnapShotSemantics, scriptContext)) + { + // Mark property end if we don't have enumerator + m_writer->Write(static_cast(SCA_PROPERTY_TERMINATOR)); + return; + } + + ObjectPropertyEnumerator propEnumerator(scriptContext, obj, &enumerator); + WriteObjectProperties(&propEnumerator); + } + + template + void SerializationCloner::CloneMap(Src src, Dst dst) + { + JavascriptMap* map = VarTo(src); + + Write((int32)(map->Size())); + + JavascriptMap::MapDataList::Iterator iter = map->GetIterator(); + while (iter.Next()) + { + const JavascriptMap::MapDataKeyValuePair& entry = iter.Current(); + this->GetEngine()->Clone(entry.Key()); + this->GetEngine()->Clone(entry.Value()); + } + } + + template + void SerializationCloner::CloneSet(Src src, Dst dst) + { + JavascriptSet* set = VarTo(src); + + Write((int32)(set->Size())); + + JavascriptSet::SetDataList::Iterator iter = set->GetIterator(); + while (iter.Next()) + { + this->GetEngine()->Clone(iter.Current()); + } + } + + template + void SerializationCloner::CloneObjectReference(Src src, Dst dst) + { + WriteTypeId(SCA_Reference); + m_writer->Write(dst); + } + + // + // Write layout: [byteLen] [string content] [padding] + // + template + void SerializationCloner::Write(const char16* str, charcount_t len) const + { + uint32 byteLen = static_cast(sizeof(char16) * len); + m_writer->Write(byteLen); + m_writer->Write(str, byteLen); + uint32 unalignedLen = byteLen % sizeof(uint32); + if (unalignedLen) + { + uint32 padding = 0; + m_writer->Write(&padding, sizeof(uint32) - unalignedLen); + } + } + + // + // Write layout: [byteLen] [byte data] [padding] + // + template + void SerializationCloner::Write(const BYTE* bytes, uint32 len) const + { + m_writer->Write(len); + m_writer->Write(bytes, len); + uint32 unalignedLen = len % sizeof(uint32); + if (unalignedLen) + { + uint32 padding = 0; + m_writer->Write(&padding, sizeof(uint32) - unalignedLen); + } + } + + // + // Check if a SrcTypeId is of a TypedArray or DataView. + // + template + bool SerializationCloner::IsTypedArray(SrcTypeId typeId) + { + return (typeId >= TypeIds_TypedArraySCAMin && typeId <= TypeIds_TypedArraySCAMax) + || typeId == TypeIds_DataView; + } + + // + // Write a TypedArray or a DataView layout. + // + template + void SerializationCloner::WriteTypedArray(SrcTypeId typeId, Src src) const + { + switch (typeId) + { + case TypeIds_Int8Array: + if (Int8VirtualArray::HasVirtualTableInfo(src)) + { + WriteTypedArray(src); + } + else + { + WriteTypedArray(src); + } + break; + + case TypeIds_Uint8Array: + if (Uint8VirtualArray::HasVirtualTableInfo(src)) + { + WriteTypedArray(src); + } + else + { + WriteTypedArray(src); + } + break; + + case TypeIds_Uint8ClampedArray: + if (Uint8ClampedVirtualArray::HasVirtualTableInfo(src)) + { + WriteTypedArray(src); + } + else + { + WriteTypedArray(src); + } + break; + + case TypeIds_Int16Array: + if (Int16VirtualArray::HasVirtualTableInfo(src)) + { + WriteTypedArray(src); + } + else + { + WriteTypedArray(src); + } + break; + + case TypeIds_Uint16Array: + if (Uint16VirtualArray::HasVirtualTableInfo(src)) + { + WriteTypedArray(src); + } + else + { + WriteTypedArray(src); + } + break; + + case TypeIds_Int32Array: + if (Int32VirtualArray::HasVirtualTableInfo(src)) + { + WriteTypedArray(src); + } + else + { + WriteTypedArray(src); + } + break; + + case TypeIds_Uint32Array: + if (Uint32VirtualArray::HasVirtualTableInfo(src)) + { + WriteTypedArray(src); + } + else + { + WriteTypedArray(src); + } + break; + + case TypeIds_Float32Array: + if (Float32VirtualArray::HasVirtualTableInfo(src)) + { + WriteTypedArray(src); + } + else + { + WriteTypedArray(src); + } + break; + + case TypeIds_Float64Array: + if (Float64VirtualArray::HasVirtualTableInfo(src)) + { + WriteTypedArray(src); + } + else + { + WriteTypedArray(src); + } + break; + + case TypeIds_DataView: + WriteTypedArray(src); + break; + + default: + Assert(false); + } + } + + // + // Do an arbitrary test to determine serializing a JavascriptArray as sparse array or not. + // + template + bool SerializationCloner::IsSparseArray(JavascriptArray* arr) + { + uint32 length = arr->GetLength(); + if (length > SparseArraySegmentBase::HEAD_CHUNK_SIZE) + { + // Consider it a sparse array if the array size is non-trivial, and there + // are empty slots found by some arbitrary sampling. + return !JavascriptOperators::HasOwnItem(arr, length / 4) + || !JavascriptOperators::HasOwnItem(arr, length / 2) + || !JavascriptOperators::HasOwnItem(arr, length / 2 + length / 4); + } + + return false; + } + + // + // Write dense array index named properties. + // + template + void SerializationCloner::WriteDenseArrayIndexProperties(JavascriptArray* arr) + { + if (JavascriptArray::IsNonES5Array(arr)) + { + if (!arr->IsCrossSiteObject()) + { + WriteArrayIndexProperties(arr); + } + else + { + WriteArrayIndexProperties(arr); + } + } + else + { + WriteArrayIndexProperties(arr); + } + } + + // + // Write sparse array index named properties. + // + template + void SerializationCloner::WriteSparseArrayIndexProperties(JavascriptArray* arr) + { + if (JavascriptArray::IsNonES5Array(arr)) + { + if (!arr->IsCrossSiteObject()) + { + WriteSparseArrayIndexProperties< + JavascriptArrayIndexStaticEnumerator, JavascriptArrayDirectItemAccessor>(arr); + } + else + { + WriteSparseArrayIndexProperties< + JavascriptArrayIndexStaticEnumerator, JavascriptArrayItemAccessor>(arr); + } + } + else + { + // We don't need JavascriptArrayEnumerableItemAccessor to check enumberable since we'll + // enumerate enumerable index named properties through ES5ArrayIndexEnumerator. Just use + // JavascriptArrayItemAccessor. + WriteSparseArrayIndexProperties< + ES5ArrayIndexStaticEnumerator<>, JavascriptArrayItemAccessor>(VarTo(arr)); + } + } + + template class SerializationCloner; + + bool ObjectPropertyEnumerator::MoveNext() + { + if (m_innerEnumerator) + { + ScriptContext* scriptContext = this->GetScriptContext(); + Var undefined = scriptContext->GetLibrary()->GetUndefined(); + Var propertyName; + PropertyId propertyId; + + while ((propertyName = m_innerEnumerator->MoveAndGetNext(propertyId)) != NULL) + { + if (propertyName != undefined) //There are some code paths in which GetCurrentIndex can return undefined + { + m_name = VarTo(propertyName); + + if (propertyId != Constants::NoProperty) + { + m_value = JavascriptOperators::GetProperty(m_obj, propertyId, scriptContext); + } + else + { + m_value = JavascriptOperators::OP_GetElementI(m_obj, propertyName, scriptContext); + } + + return true; + } + } + + // No more properties, mark end + m_innerEnumerator = NULL; + } + + return false; + } + + void SCASerializationEngine::Serialize(Var root, StreamWriter* writer, Var* transferableVars, size_t cTransferableVars, + JsUtil::List* sharedContentsList) + { + ScriptContext* scriptContext = writer->GetScriptContext(); + + // Write version + writer->Write(static_cast(SCA_FORMAT_VERSION)); + + StreamSerializationCloner cloner(scriptContext, writer, sharedContentsList); + SCAEngine::Clone(root, &cloner, transferableVars, cTransferableVars); + } +} diff --git a/lib/SCACore/SCASerialization.h b/lib/SCACore/SCASerialization.h new file mode 100644 index 00000000000..9d4724610f8 --- /dev/null +++ b/lib/SCACore/SCASerialization.h @@ -0,0 +1,339 @@ +//------------------------------------------------------------------------------------------------------- +// 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 +namespace Js +{ + // + // SerializationCloner helps clone a Var to a stream location. + // + template + class SerializationCloner: + public ClonerBase > + { + public: + using typename ClonerBase >::Dst; + using typename ClonerBase >::Src; + using typename ClonerBase >::SrcTypeId; + + private: + //AutoCOMPtr m_pSCAContext; + Writer* m_writer; + // AutoCOMPtr m_pSCASerializable; // Temporary, QI from a host object + JsUtil::List* m_sharedContentsrList; + + private: + void WriteTypeId(SCATypeId typeId) const + { + Write(static_cast(typeId)); + } + + void Write(uint32 data) const + { + m_writer->Write(data); + } + + void Write(const char16* str, charcount_t len) const; + void Write(const BYTE* bytes, uint32 len) const; + + // + // Write a TypedArray or a DataView layout: [SCATypeId] [ArrayBuffer] [byteOffset] [length] + // + template + void WriteTypedArray(Src src) const + { + typedef TypedArrayTrace trace_type; + typedef typename trace_type::TypedArrayType array_type; + + WriteTypeId(trace_type::GetSCATypeId()); + array_type* arr = VarTo(src); + + this->GetEngine()->Clone(arr->GetArrayBuffer()); + + Write(arr->GetByteOffset()); + Write(arr->GetLength()); + } + + static bool IsTypedArray(SrcTypeId typeId); + void WriteTypedArray(SrcTypeId typeId, Src src) const; + + static bool IsSparseArray(JavascriptArray* arr); + void WriteDenseArrayIndexProperties(JavascriptArray* arr); + void WriteSparseArrayIndexProperties(JavascriptArray* arr); + + // + // Write array index named properties. + // + template + void WriteArrayIndexProperties(JavascriptArray* arr) + { + ScriptContext* scriptContext = this->GetScriptContext(); + uint32 length = arr->GetLength(); + + for (uint32 i = 0; i < length; i++) + { + Var value = nullptr; + if (ArrayItemAccessor::GetItem(arr, i, &value, scriptContext)) + { + this->GetEngine()->Clone(value); + } + else + { + WriteTypeId(SCA_None); + } + } + } + + // + // Write sparse array index named properties using an array index enumerator. + // + template + void WriteSparseArrayIndexProperties(typename IndexEnumerator::ArrayType* arr) + { + ScriptContext* scriptContext = this->GetScriptContext(); + IndexEnumerator e(arr); + Var value = nullptr; + + while (e.MoveNext()) + { + uint32 i = e.GetIndex(); + if (ArrayItemAccessor::GetItem(arr, i, &value, scriptContext)) + { + Write(i); + this->GetEngine()->Clone(value); + } + } + + Write(static_cast(SCA_PROPERTY_TERMINATOR)); + } + + // + // Write a SCAProperties section: {SCAPropertyName SCAValue} SCAPropertiesTerminator + // + template + void WriteObjectProperties(Enumerator* enumerator) + { + while (enumerator->MoveNext()) + { + // Write property name + Write(enumerator->GetNameString(), enumerator->GetNameLength()); + + // Write property value + this->GetEngine()->Clone(enumerator->GetValue()); + } + + // Write property terminator + m_writer->Write(static_cast(SCA_PROPERTY_TERMINATOR)); + } + + // Direct item accessor used on non-crosssite JavascriptArray for WriteArrayIndexProperties. + class JavascriptArrayDirectItemAccessor + { + public: + static BOOL GetItem(JavascriptArray* arr, uint32 index, Var* value, ScriptContext* scriptContext) + { + return arr->GetItem(arr, index, value, scriptContext); + } + }; + + // Item accessor used on cross-site JavascriptArray for WriteArrayIndexProperties. + class JavascriptArrayItemAccessor + { + public: + static BOOL GetItem(JavascriptArray* arr, uint32 index, Var* value, ScriptContext* scriptContext) + { + return JavascriptOperators::GetOwnItem(arr, index, value, scriptContext); + } + }; + + // Item accessor used on ES5Array for WriteArrayIndexProperties. + class JavascriptArrayEnumerableItemAccessor + { + public: + static BOOL GetItem(JavascriptArray* arr, uint32 index, Var* value, ScriptContext* scriptContext) + { + return arr->IsItemEnumerable(index) + && JavascriptOperators::GetOwnItem(arr, index, value, scriptContext); + } + }; + + public: + SerializationCloner(ScriptContext* scriptContext, Writer* writer, JsUtil::List* sharedContentsrList) + : ClonerBase >(scriptContext), m_writer(writer), m_sharedContentsrList(sharedContentsrList) + { + } + + static bool ShouldLookupReference() + { + // Always lookup reference when cloning Vars + return true; + } + + SrcTypeId GetTypeId(Src src) const + { + return JavascriptOperators::GetTypeId(src); + } + + bool TryClonePrimitive(SrcTypeId typeId, Src src, Dst* dst); + bool TryCloneObject(SrcTypeId typeId, Src src, Dst* dst, SCADeepCloneType* deepClone); + void CloneProperties(SrcTypeId typeId, Src src, Dst dst); + void CloneHostObjectProperties(SrcTypeId typeId, Src src, Dst dst); + void CloneMap(Src src, Dst dst); + void CloneSet(Src src, Dst dst); + void CloneObjectReference(Src src, Dst dst); + bool CanBeTransferred(SrcTypeId typeId) { return typeId == TypeIds_ArrayBuffer; } + }; + + // + // Object property enumerator for WriteObjectProperties. + // + class ObjectPropertyEnumerator: public ScriptContextHolder + { + private: + RecyclableObject* m_obj; + JavascriptStaticEnumerator* m_innerEnumerator; + JavascriptString* m_name; + Var m_value; + + public: + ObjectPropertyEnumerator(ScriptContext* scriptContext, RecyclableObject* obj, JavascriptStaticEnumerator* enumerator) + : ScriptContextHolder(scriptContext), + m_obj(obj), + m_innerEnumerator(enumerator), + m_name(NULL), + m_value(NULL) + { + } + + bool MoveNext(); + + const char16* GetNameString() const + { + return m_name->GetString(); + } + + charcount_t GetNameLength() const + { + return m_name->GetLength(); + } + + Var GetValue() const + { + return m_value; + } + }; + + // + // Template and specializations for TypedArray/DataView SCA. + // + template struct TypedArrayTrace + { + // Generic TypedArrayTrace is empty. Specializations provide implementation. + }; + + // Base implementation shared by data type TypedArrays. + template struct TypedArrayTraceBase + { + typedef TypedArray TypedArrayType; + static Var CreateTypedArray(ArrayBufferBase* arrayBuffer, uint32 byteOffset, uint32 length, + ScriptContext* scriptContext) + { + JavascriptLibrary* lib = scriptContext->GetLibrary(); + return TypedArrayType::Create(arrayBuffer, byteOffset, length, lib); + } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Int8Array; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Uint8Array; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Uint8ClampedArray; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Int16Array; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Uint16Array; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Int32Array; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Uint32Array; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Float32Array; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Float64Array; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Int8Array; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Uint8Array; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Uint8ClampedArray; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Int16Array; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Uint16Array; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Int32Array; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Uint32Array; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Float32Array; } + }; + template<> struct TypedArrayTrace: TypedArrayTraceBase + { + static SCATypeId GetSCATypeId() { return SCA_Float64Array; } + }; + template<> struct TypedArrayTrace + { + typedef DataView TypedArrayType; + static Var CreateTypedArray(ArrayBufferBase* arrayBuffer, uint32 byteOffset, uint32 length, + ScriptContext* scriptContext) + { + JavascriptLibrary* lib = scriptContext->GetLibrary(); + return lib->CreateDataView(arrayBuffer, byteOffset, length); + } + static SCATypeId GetSCATypeId() { return SCA_DataView; } + }; + + class SCASerializationEngine + { + typedef SerializationCloner StreamSerializationCloner; + + public: + static void Serialize(Var root, StreamWriter* writer, Var* transferableVars, size_t cTransferableVars, + JsUtil::List* sharedContentsList); + }; +} diff --git a/lib/SCACore/SCATypes.h b/lib/SCACore/SCATypes.h new file mode 100644 index 00000000000..a3d672a1a18 --- /dev/null +++ b/lib/SCACore/SCATypes.h @@ -0,0 +1,79 @@ +//------------------------------------------------------------------------------------------------------- +// 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 + +#define SCA_FORMAT_MAJOR 1 +#define SCA_FORMAT_MINOR 0 +#define SCA_FORMAT_VERSION (MAKELONG(0, MAKEWORD(SCA_FORMAT_MINOR, SCA_FORMAT_MAJOR))) +#define GetSCAMajor(header) HIBYTE(HIWORD(header)) +#define GetSCAMinor(header) LOBYTE(HIWORD(header)) +typedef +enum SCATypeId +{ + SCA_None = 0, + SCA_Reference = 1, + SCA_NullValue = 2, + SCA_UndefinedValue = 3, + SCA_TrueValue = 4, + SCA_FalseValue = 5, + SCA_Int32Value = 6, + SCA_DoubleValue = 7, + SCA_StringValue = 8, + SCA_Int64Value = 9, + SCA_Uint64Value = 10, + SCA_LastPrimitive = SCA_Uint64Value, + SCA_BooleanTrueObject = 21, + SCA_BooleanFalseObject = 22, + SCA_DateObject = 23, + SCA_NumberObject = 24, + SCA_StringObject = 25, + SCA_RegExpObject = 26, + SCA_Object = 27, + SCA_Transferable = 28, + SCA_DenseArray = 50, + SCA_SparseArray = 51, + SCA_CanvasPixelArray = 52, + SCA_ArrayBuffer = 60, + SCA_Int8Array = 61, + SCA_Uint8Array = 62, + SCA_Int16Array = 63, + SCA_Uint16Array = 64, + SCA_Int32Array = 65, + SCA_Uint32Array = 66, + SCA_Float32Array = 67, + SCA_Float64Array = 68, + SCA_DataView = 69, + SCA_Uint8ClampedArray = 70, + SCA_TypedArrayMin = SCA_Int8Array, + SCA_TypedArrayMax = SCA_Float64Array, + SCA_Map = 80, + SCA_Set = 81, + SCA_SharedArrayBuffer = 82, + SCA_WebAssemblyModule = 85, + SCA_WebAssemblyMemory = 86, + SCA_FirstHostObject = 100, + SCA_BlobObject = 101, + SCA_FileObject = 102, + SCA_ImageDataObject = 103, + SCA_FileListObject = 104, + SCA_StreamObject = 105, + SCA_WebCryptoKeyObject = 106, + SCA_MessagePort = 107, + SCA_Last = (SCA_MessagePort + 1) +} SCATypeId; + +typedef unsigned int scaposition_t; + +#define SCA_PROPERTY_TERMINATOR 0xFFFFFFFF +#define IsSCAPrimitive(scaTypeId) ((scaTypeId) <= SCA_LastPrimitive) +#define IsSCAHostObject(scaTypeId) ((scaTypeId) >= SCA_FirstHostObject) +#define IsSCATypedArray(scaTypeId) ((scaTypeId) == SCA_Uint8ClampedArray || ((scaTypeId) >= SCA_TypedArrayMin && (scaTypeId) <= SCA_TypedArrayMax)) +#define FACILITY_SCA FACILITY_ITF +#define E_SCA_UNSUPPORTED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_SCA, 0x1000) +#define E_SCA_NEWVERSION MAKE_HRESULT(SEVERITY_ERROR, FACILITY_SCA, 0x1001) +#define E_SCA_DATACORRUPT MAKE_HRESULT(SEVERITY_ERROR, FACILITY_SCA, 0x1002) +#define E_SCA_TRANSFERABLE_UNSUPPORTED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_SCA, 0x1003) +#define E_SCA_TRANSFERABLE_NEUTERED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_SCA, 0x1004) diff --git a/lib/SCACore/StreamHelper.cpp b/lib/SCACore/StreamHelper.cpp new file mode 100644 index 00000000000..0b5f73f6404 --- /dev/null +++ b/lib/SCACore/StreamHelper.cpp @@ -0,0 +1,10 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +#include "SCACorePch.h" + +namespace Js +{ +} diff --git a/lib/SCACore/StreamHelper.h b/lib/SCACore/StreamHelper.h new file mode 100644 index 00000000000..29efffbd067 --- /dev/null +++ b/lib/SCACore/StreamHelper.h @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------------------------------- +// 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 +namespace Js +{ + // + // Helper class to implement stream reader/writer. Note that this stream helper class + // maintains its own stream position and ensures the stream position fits scaposition_t. + // + class StreamHelper: public ScriptContextHolder + { + private: + HostStream *m_stream; + + protected: + HostStream* GetStream() const + { + return m_stream; + } + + void ThrowOverflow() const + { + ::Math::DefaultOverflowPolicy(); + } + + public: + StreamHelper(ScriptContext* scriptContext, HostStream* stream) + : ScriptContextHolder(scriptContext), + m_stream(stream) + { + } + }; +} diff --git a/lib/SCACore/StreamReader.cpp b/lib/SCACore/StreamReader.cpp new file mode 100644 index 00000000000..8d126739586 --- /dev/null +++ b/lib/SCACore/StreamReader.cpp @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +#include "SCACorePch.h" + +namespace Js +{ + void StreamReader::Read(void* pv, size_t cb) + { + Assert(cb < m_length); + // Read from buffer + js_memcpy_s(pv, cb, m_buffer + m_current, cb); + m_current += cb; + } + + Var StreamReader::ReadHostObject() + { + Var object = nullptr; + ScriptContext* scriptContext = GetScriptContext(); + BEGIN_LEAVE_SCRIPT(scriptContext) + { + object = m_stream->ReadHostObject(); + } + END_LEAVE_SCRIPT(scriptContext); + return object; + } + + // + // Overload to count for buffer position. + // + scaposition_t StreamReader::GetPosition() const + { + return static_cast(m_current); + } +} diff --git a/lib/SCACore/StreamReader.h b/lib/SCACore/StreamReader.h new file mode 100644 index 00000000000..de141c7c857 --- /dev/null +++ b/lib/SCACore/StreamReader.h @@ -0,0 +1,67 @@ +//------------------------------------------------------------------------------------------------------- +// 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 +namespace Js +{ + // + // A simple stream reader that hides low level stream details. + // + class StreamReader: public ScriptContextHolder + { + private: + HostReadStream *m_stream; + byte *m_buffer; + size_t m_current; + size_t m_length; + + // + // Get number of bytes left for read in the buffer. + // + size_t GetBytesInBuffer() const + { + return m_length - m_current; + } + + // ULONG RealRead(void* pv, ULONG cb); + + public: + StreamReader(ScriptContext* scriptContext, byte* buffer, size_t length, HostReadStream *stream) + : ScriptContextHolder(scriptContext), + m_stream(stream), + m_buffer(buffer), + m_current(0), + m_length(length) + { + } + + Var ReadHostObject(); + void Read(void* pv, size_t cb); + + void ReadRawBytes(void** pv, size_t cb) + { + Assert(cb < m_length); + *pv = (m_buffer + m_current); + m_current += cb; + } + + template + void Read(T* value) + { + if (GetBytesInBuffer() >= sizeof(T)) + { + *value = *(T*)(m_buffer + m_current); + m_current += sizeof(T); + } + else + { + Read(value, sizeof(T)); + } + } + + scaposition_t GetPosition() const; + }; + +} diff --git a/lib/SCACore/StreamWriter.cpp b/lib/SCACore/StreamWriter.cpp new file mode 100644 index 00000000000..036784184b6 --- /dev/null +++ b/lib/SCACore/StreamWriter.cpp @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +#include "SCACorePch.h" + +namespace Js +{ + void StreamWriter::Write(const void* pv, size_t cb) + { + ScriptContext* scriptContext = GetScriptContext(); + uint32 newSize = UInt32Math::Add((uint32)m_current, (uint32)cb); + if (newSize >= m_capacity) + { + size_t newCapacity = UInt32Math::Add(max(newSize, UInt32Math::Mul((uint32)m_capacity, 2)), 100); + BEGIN_LEAVE_SCRIPT(scriptContext) + { + m_buffer = m_stream->ExtendBuffer(m_buffer, newCapacity, &m_capacity); + } + END_LEAVE_SCRIPT(scriptContext); + } + + Assert(m_buffer != nullptr); + js_memcpy_s(m_buffer + m_current, cb, pv, cb); + m_current += cb; + } + + void StreamWriter::WriteHostObject(void* data) + { + ScriptContext* scriptContext = GetScriptContext(); + BEGIN_LEAVE_SCRIPT(scriptContext) + { + m_stream->WriteHostObject(data); + } + END_LEAVE_SCRIPT(scriptContext); + } + + // + // Overload to count for buffer position. + // + scaposition_t StreamWriter::GetPosition() const + { + // If this overflows, we will throw during Flush/RealWrite. So skip checking here. + return static_cast(m_current); + } +} diff --git a/lib/SCACore/StreamWriter.h b/lib/SCACore/StreamWriter.h new file mode 100644 index 00000000000..5897b73d9f2 --- /dev/null +++ b/lib/SCACore/StreamWriter.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 +namespace Js +{ + // + // A simple stream writer that hides low level stream details. + // + // Note: + // This stream writer uses an internal buffer. Must call Flush() at the end to ensure + // any remained content in the internal buffer is sent to the output stream. + // + class StreamWriter: public ScriptContextHolder + { + private: + HostStream *m_stream; + byte *m_buffer; + size_t m_current; + size_t m_capacity; + + public: + StreamWriter(ScriptContext* scriptContext, HostStream* stream) + : ScriptContextHolder(scriptContext), + m_stream(stream), + m_buffer(nullptr), + m_current(0), + m_capacity(0) + { + } + + byte* GetBuffer() { return m_buffer; } + size_t GetLength() { return m_current; } + + void Write(const void* pv, size_t cb); + void WriteHostObject(void* data); + + template + void Write(const T& value) + { + if ((m_current + sizeof(T)) < m_capacity) + { + *(T*)(m_buffer + m_current) = value; + m_current += sizeof(T); + } + else + { + Write(&value, sizeof(T)); + } + } + + + //_Post_satisfies_(m_cur == 0) + //void Flush(); + + scaposition_t GetPosition() const; + }; +} diff --git a/pal/inc/rt/unknwn.h b/pal/inc/rt/unknwn.h index 1397cdbec9d..355730aa4c0 100644 --- a/pal/inc/rt/unknwn.h +++ b/pal/inc/rt/unknwn.h @@ -12,6 +12,7 @@ #include "rpc.h" #include "rpcndr.h" +#include #ifndef __IUnknown_INTERFACE_DEFINED__ #define __IUnknown_INTERFACE_DEFINED__ @@ -21,7 +22,7 @@ typedef interface IUnknown IUnknown; typedef /* [unique] */ IUnknown *LPUNKNOWN; // 00000000-0000-0000-C000-000000000046 -EXTERN_C const IID IID_IUnknown; +DEFINE_GUID(IID_IUnknown, 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); MIDL_INTERFACE("00000000-0000-0000-C000-000000000046") IUnknown diff --git a/pal/pal.vcxproj b/pal/pal.vcxproj index 17631cf7938..3087ff6ed48 100644 --- a/pal/pal.vcxproj +++ b/pal/pal.vcxproj @@ -1,6 +1,6 @@  - + @@ -208,6 +208,6 @@ - + - + \ No newline at end of file diff --git a/pal/pal.vcxproj.filters b/pal/pal.vcxproj.filters index 07720ad9f8a..56bc8f77504 100644 --- a/pal/pal.vcxproj.filters +++ b/pal/pal.vcxproj.filters @@ -191,11 +191,5 @@ - - - - - - \ No newline at end of file diff --git a/test/es6/ES6TypedArrayExtensions.js b/test/es6/ES6TypedArrayExtensions.js index dfc78d9070c..8e2f39b2317 100644 --- a/test/es6/ES6TypedArrayExtensions.js +++ b/test/es6/ES6TypedArrayExtensions.js @@ -106,11 +106,11 @@ var tests = [ assert.isTrue(typedArrayPrototype === Float32Array.prototype.__proto__, "All TypedArray prototypes have their [[prototype]] slot set to the %TypedArrayPrototype% intrinsic"); assert.isTrue(typedArrayPrototype === Float64Array.prototype.__proto__, "All TypedArray prototypes have their [[prototype]] slot set to the %TypedArrayPrototype% intrinsic"); - verifyTypedArrayPrototypePropertyAccessor(typedArrayPrototype, "buffer", "%TypedArrayPrototype%.buffer", "get buffer"); - verifyTypedArrayPrototypePropertyAccessor(typedArrayPrototype, "byteLength", "%TypedArrayPrototype%.byteLength", "get byteLength"); - verifyTypedArrayPrototypePropertyAccessor(typedArrayPrototype, "byteOffset", "%TypedArrayPrototype%.byteOffset", "get byteOffset"); - verifyTypedArrayPrototypePropertyAccessor(typedArrayPrototype, "length", "%TypedArrayPrototype%.length", "get length"); - verifyTypedArrayPrototypePropertyAccessor(typedArrayPrototype, Symbol.toStringTag, "%TypedArrayPrototype%[@@toStringTag]", "get [Symbol.toStringTag]"); + verifyTypedArrayPrototypePropertyAccessor(typedArrayPrototype, "buffer", "%TypedArrayPrototype%.buffer", "function get buffer() { [native code] }"); + verifyTypedArrayPrototypePropertyAccessor(typedArrayPrototype, "byteLength", "%TypedArrayPrototype%.byteLength", "function get byteLength() { [native code] }"); + verifyTypedArrayPrototypePropertyAccessor(typedArrayPrototype, "byteOffset", "%TypedArrayPrototype%.byteOffset", "function get byteOffset() { [native code] }"); + verifyTypedArrayPrototypePropertyAccessor(typedArrayPrototype, "length", "%TypedArrayPrototype%.length", "function get length() { [native code] }"); + verifyTypedArrayPrototypePropertyAccessor(typedArrayPrototype, Symbol.toStringTag, "%TypedArrayPrototype%[@@toStringTag]", "function get [Symbol.toStringTag]() { [native code] }"); verifyTypedArrayPrototypePropertyFunction(typedArrayPrototype, "set", 2, "%TypedArrayPrototype%.set"); verifyTypedArrayPrototypePropertyFunction(typedArrayPrototype, "subarray", 2, "%TypedArrayPrototype%.subarray"); diff --git a/tools/run_msbuild.py b/tools/run_msbuild.py new file mode 100644 index 00000000000..e0141d00c98 --- /dev/null +++ b/tools/run_msbuild.py @@ -0,0 +1,62 @@ +#------------------------------------------------------------------------------------------------------- +# Copyright (C) Microsoft. All rights reserved. +# Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +#------------------------------------------------------------------------------------------------------- + +import glob +import json +import os +import pipes +import platform +import re +import shutil +import stat +import subprocess +import sys + +# add build to path +BUILD_TOOLS_DIR = os.path.abspath(os.path.join( + os.path.dirname(__file__), "../../../build")) +sys.path.append(BUILD_TOOLS_DIR) +import find_depot_tools + +find_depot_tools.add_depot_tools_to_path() +import vswhere + + +# On Windows, run msbuild.exe on sln and copy lib, dll, pdb files to appropriate locations, +def main(sln, outdir, target_gen_dir, *flags): + + # On non-Windows, that's all we can do. + if sys.platform != 'win32': + print "builds on non-windows are NYI!!" + return 1 + + status_code, vsInstallRoot = vswhere.get_vs_path() + if status_code != 0: + print "Visual Studio not found!!" + return 1 + + msbuildPath = os.path.join(vsInstallRoot["path"], r"MSBuild\15.0\Bin\MSBuild.exe") + args = [msbuildPath, os.path.normpath(sln)] + list(flags) + + print "== BUILDING CHAKRACORE:" + print " ".join(args) + + popen = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + out, _ = popen.communicate() + + if popen.returncode != 0: + print out + return popen.returncode + + # Now copy the lib target_gen_dir and dll/pdb to the build root + # 2 levels above ( above gen\third_party\chakracore ) + shutil.copy(os.path.join(outdir, "ChakraCore.lib"), target_gen_dir) + shutil.copy(os.path.join(outdir, "ChakraCore.dll"), os.path.join(target_gen_dir, "../../..")) + shutil.copy(os.path.join(outdir, "ChakraCore.pdb"), os.path.join(target_gen_dir, "../../..")) + + return 0 + +if __name__ == '__main__': + sys.exit(main(*sys.argv[1:]))