Index: ps/trunk/build/premake/extern_libs5.lua =================================================================== --- ps/trunk/build/premake/extern_libs5.lua +++ ps/trunk/build/premake/extern_libs5.lua @@ -585,7 +585,7 @@ compile_settings = function() if _OPTIONS["with-system-mozjs"] then if not _OPTIONS["android"] then - pkgconfig.add_includes("mozjs-60") + pkgconfig.add_includes("mozjs-68") end else if os.istarget("windows") then @@ -605,15 +605,15 @@ link_settings = function() if _OPTIONS["with-system-mozjs"] then if _OPTIONS["android"] then - links { "mozjs-60" } + links { "mozjs-68" } else - pkgconfig.add_links("mozjs-60") + pkgconfig.add_links("mozjs-68") end else filter { "Debug" } - links { "mozjs60-ps-debug" } + links { "mozjs68-ps-debug" } filter { "Release" } - links { "mozjs60-ps-release" } + links { "mozjs68-ps-release" } filter { } add_source_lib_paths("spidermonkey") end Index: ps/trunk/build/workspaces/clean-workspaces.sh =================================================================== --- ps/trunk/build/workspaces/clean-workspaces.sh +++ ps/trunk/build/workspaces/clean-workspaces.sh @@ -33,14 +33,15 @@ (cd ../../libraries/source/fcollada/src && rm -rf ./output) (cd ../../libraries/source/nvtt/src && rm -rf ./build) (cd ../../libraries/source/spidermonkey && rm -f .already-built) - (cd ../../libraries/source/spidermonkey && rm -rf ./lib) + (cd ../../libraries/source/spidermonkey && rm -rf ./lib/*.a && rm -rf ./lib/*.so) (cd ../../libraries/source/spidermonkey && rm -rf ./include-unix-debug) (cd ../../libraries/source/spidermonkey && rm -rf ./include-unix-release) - (cd ../../libraries/source/spidermonkey && rm -rf ./mozjs-62.9.1) + (cd ../../libraries/source/spidermonkey && rm -rf ./mozjs-68.12.1) fi # Still delete the directory of previous SpiderMonkey versions to # avoid wasting disk space if people clean workspaces after updating. +(cd ../../libraries/source/spidermonkey && rm -rf ./mozjs-62.9.1) (cd ../../libraries/source/spidermonkey && rm -rf ./mozjs-52.9.1pre1) (cd ../../libraries/source/spidermonkey && rm -rf ./mozjs-45.0.2) (cd ../../libraries/source/spidermonkey && rm -rf ./mozjs-38.0.0) Index: ps/trunk/libraries/source/spidermonkey/FixBindgenClang.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/FixBindgenClang.diff +++ ps/trunk/libraries/source/spidermonkey/FixBindgenClang.diff @@ -0,0 +1,492 @@ + +# HG changeset patch +# User Mike Hommey +# Date 1559702900 0 +# Node ID ccd1356fc8f1d0bfa9d896e88d3cc924425623da +# Parent b26eb4a5540b3bf21b0e0eb91e975cb69c4462b1 +Bug 1526857 - Improve bindgen configuration wrt clang. r=chmanchester + +The current setup for bindgen relies on either finding clang/libclang +from the output of llvm-config, or from the paths given via the +configure flags --with-clang-path/--with-libclang-path. + +One _very_ common problem is that the llvm-config we end up using does +not correspond to the clang used for compilation, which has some +undesirable side effect, like failing to build. + +So instead of relying on llvm-config, we do the following: +- when the compiler is clang, we just use that +- when the compiler is clang-cl, we use clang from the same directory +- otherwise, we either try to find clang in PATH, or rely on + --with-clang-path. + +Once clang is found, we try to deduce the location of the corresponding +libclang via the output of `clang -print-search-dirs`, or rely on +--with-libclang-path. + +Differential Revision: https://phabricator.services.mozilla.com/D33241 + +diff --git a/build/moz.configure/bindgen.configure b/build/moz.configure/bindgen.configure +--- a/build/moz.configure/bindgen.configure ++++ b/build/moz.configure/bindgen.configure +@@ -63,220 +63,158 @@ set_config('CBINDGEN', cbindgen) + + # Bindgen can use rustfmt to format Rust file, but it's not required. + js_option(env='RUSTFMT', nargs=1, help='Path to the rustfmt program') + + rustfmt = check_prog('RUSTFMT', ['rustfmt'], paths=toolchain_search_path, + input='RUSTFMT', allow_missing=True) + + +-# We support setting up the appropriate options for bindgen via setting +-# LLVM_CONFIG or by providing explicit configure options. The Windows +-# installer of LLVM/Clang doesn't provide llvm-config, so we need both +-# methods to support all of our tier-1 platforms. +-@depends(host) +-@imports('os') +-def llvm_config_paths(host): +- llvm_supported_versions = ['6.0', '5.0', '4.0', '3.9'] +- llvm_config_progs = [] +- for version in llvm_supported_versions: +- llvm_config_progs += [ +- 'llvm-config-%s' % version, +- 'llvm-config-mp-%s' % version, # MacPorts' chosen naming scheme. +- 'llvm-config%s' % version.replace('.', ''), +- ] +- llvm_config_progs.append('llvm-config') +- +- # Homebrew on macOS doesn't make clang available on PATH, so we have to +- # look for it in non-standard places. +- if host.kernel == 'Darwin': +- brew = find_program('brew') +- if brew: +- brew_config = check_cmd_output(brew, 'config').strip() +- +- for line in brew_config.splitlines(): +- if line.startswith('HOMEBREW_PREFIX'): +- fields = line.split(None, 2) +- prefix = fields[1] if len(fields) == 2 else '' +- path = ['opt', 'llvm', 'bin', 'llvm-config'] +- llvm_config_progs.append(os.path.join(prefix, *path)) +- break +- +- # Also add in the location to which `mach bootstrap` or +- # `mach artifact toolchain` installs clang. +- mozbuild_state_dir = os.environ.get('MOZBUILD_STATE_PATH', +- os.path.expanduser(os.path.join('~', '.mozbuild'))) +- bootstrap_llvm_config = os.path.join(mozbuild_state_dir, 'clang', 'bin', 'llvm-config') +- +- llvm_config_progs.append(bootstrap_llvm_config) +- +- return llvm_config_progs +- +-js_option(env='LLVM_CONFIG', nargs=1, help='Path to llvm-config') +- +-llvm_config = check_prog('LLVM_CONFIG', llvm_config_paths, input='LLVM_CONFIG', +- what='llvm-config', allow_missing=True) +- + js_option('--with-libclang-path', nargs=1, + help='Absolute path to a directory containing Clang/LLVM libraries for bindgen (version 3.9.x or above)') + js_option('--with-clang-path', nargs=1, + help='Absolute path to a Clang binary for bindgen (version 3.9.x or above)') + +-def invoke_llvm_config(llvm_config, *options): +- '''Invoke llvm_config with the given options and return the first line of +- output.''' +- lines = check_cmd_output(llvm_config, *options).splitlines() +- return lines[0] + +-@imports(_from='textwrap', _import='dedent') +-def check_minimum_llvm_config_version(llvm_config): +- version = Version(invoke_llvm_config(llvm_config, '--version')) +- min_version = Version('3.9.0') +- if version < min_version: +- die(dedent('''\ +- llvm installation {} is incompatible with bindgen. ++@depends('--with-clang-path', c_compiler, cxx_compiler, toolchain_search_path, ++ target, macos_sdk) ++@checking('for clang for bindgen', lambda x: x.path if x else 'not found') ++def bindgen_clang_compiler(clang_path, c_compiler, cxx_compiler, ++ toolchain_search_path, target, macos_sdk): ++ # When the target compiler is clang, use that, including flags. ++ if cxx_compiler.type == 'clang': ++ if clang_path and clang_path[0] not in (c_compiler.compiler, ++ cxx_compiler.compiler): ++ die('--with-clang-path is not valid when the target compiler is %s', ++ cxx_compiler.type) ++ return namespace( ++ path=cxx_compiler.compiler, ++ flags=cxx_compiler.flags, ++ ) ++ # When the target compiler is clang-cl, use clang in the same directory, ++ # and figure the right flags to use. ++ if cxx_compiler.type == 'clang-cl': ++ if clang_path and os.path.dirname(clang_path[0]) != \ ++ os.path.dirname(cxx_compiler.compiler): ++ die('--with-clang-path must point to clang in the same directory ' ++ 'as the target compiler') ++ if not clang_path: ++ clang_path = [os.path.join(os.path.dirname(cxx_compiler.compiler), ++ 'clang')] + +- Please install version {} or greater of Clang + LLVM +- and ensure that the 'llvm-config' from that +- installation is first on your path. ++ clang_path = find_program(clang_path[0] if clang_path else 'clang++', ++ toolchain_search_path) ++ if not clang_path: ++ return ++ flags = prepare_flags(target, macos_sdk) ++ info = check_compiler([clang_path] + flags, 'C++', target) ++ return namespace( ++ path=clang_path, ++ flags=flags + info.flags, ++ ) + +- You can verify this by typing 'llvm-config --version'. +- '''.format(version, min_version))) + +-@depends(llvm_config, '--with-libclang-path', '--with-clang-path', +- host_library_name_info, host, build_project) +-@imports('os.path') ++@depends('--with-libclang-path', bindgen_clang_compiler, ++ host_library_name_info, host) ++@checking('for libclang for bindgen', lambda x: x if x else 'not found') + @imports('glob') +-@imports(_from='textwrap', _import='dedent') +-def bindgen_config_paths(llvm_config, libclang_path, clang_path, +- library_name_info, host, build_project): +- def search_for_libclang(path): +- # Try to ensure that the clang shared library that bindgen is going +- # to look for is actually present. The files that we search for +- # mirror the logic in clang-sys/build.rs. +- libclang_choices = [] +- if host.os == 'WINNT': +- libclang_choices.append('libclang.dll') +- libclang_choices.append('%sclang%s' % (library_name_info.dll.prefix, +- library_name_info.dll.suffix)) +- if host.kernel == 'Linux': +- libclang_choices.append('libclang.so.1') ++@imports(_from='os', _import='pathsep') ++@imports(_from='os.path', _import='split', _as='pathsplit') ++@imports('re') ++def bindgen_libclang_path(libclang_path, clang, library_name_info, host): ++ if not clang: ++ if libclang_path: ++ die('--with-libclang-path is not valid without a clang compiler ' ++ 'for bindgen') ++ return ++ ++ # Try to ensure that the clang shared library that bindgen is going ++ # to look for is actually present. The files that we search for ++ # mirror the logic in clang-sys/build.rs. ++ libclang_choices = [] ++ if host.os == 'WINNT': ++ libclang_choices.append('libclang.dll') ++ libclang_choices.append('%sclang%s' % (library_name_info.dll.prefix, ++ library_name_info.dll.suffix)) ++ if host.kernel == 'Linux': ++ libclang_choices.append('libclang.so.1') ++ ++ if host.os == 'OpenBSD': ++ libclang_choices.append('libclang.so.*.*') + +- if host.os == 'OpenBSD': +- libclang_choices = glob.glob(path + '/libclang.so.*.*') ++ candidates = [] ++ if not libclang_path: ++ # Try to find libclang_path based on clang search dirs. ++ clang_search_dirs = check_cmd_output(clang.path, '-print-search-dirs') ++ for line in clang_search_dirs.splitlines(): ++ name, _, value = line.partition(': =') ++ if host.os == 'WINNT' and name == 'programs': ++ # On Windows, libclang.dll is in bin/ rather than lib/, ++ # so scan the programs search dirs. ++ # To make matters complicated, clang before version 9 uses `:` ++ # separate between paths (and `;` in newer versions) ++ if pathsep in value: ++ dirs = value.split(pathsep) ++ else: ++ for part in value.split(':'): ++ # Assume that if previous "candidate" was of length 1, ++ # it's a drive letter and the current part is the rest of ++ # the corresponding full path. ++ if candidates and len(candidates[-1]) == 1: ++ candidates[-1] += ':' + part ++ else: ++ candidates.append(part) ++ elif host.os != 'WINNT' and name == 'libraries': ++ # On other platforms, use the directories from the libraries ++ # search dirs that looks like $something/clang/$version. ++ for dir in value.split(pathsep): ++ dir, version = pathsplit(dir) ++ if re.match(r'[0-9.]+', version): ++ dir, name = pathsplit(dir) ++ if name == 'clang': ++ candidates.append(dir) ++ else: ++ candidates.append(libclang_path[0]) + +- # At least one of the choices must be found. +- for choice in libclang_choices: +- libclang = os.path.join(path, choice) +- if os.path.exists(libclang): +- return (libclang, None) +- else: +- return (None, list(set(libclang_choices))) ++ for dir in candidates: ++ for pattern in libclang_choices: ++ log.debug('Trying "%s" in "%s"', pattern, dir) ++ libs = glob.glob(os.path.join(dir, pattern)) ++ if libs: ++ return libs[0] + ++ ++@depends(bindgen_clang_compiler, bindgen_libclang_path, build_project) ++def bindgen_config_paths(clang, libclang, build_project): + # XXX: we want this code to be run for both Gecko and JS, but we don't + # necessarily want to force a bindgen/Rust dependency on JS just yet. + # Actually, we don't want to force an error if we're not building the + # browser generally. We therefore whitelist the projects that require + # bindgen facilities at this point and leave it at that. +- bindgen_projects = ('browser', 'mobile/android') +- +- if not libclang_path and not clang_path: +- # We must have LLVM_CONFIG in this case. +- if not llvm_config: +- if build_project not in bindgen_projects: +- return namespace() +- +- die(dedent('''\ +- Could not find LLVM/Clang installation for compiling bindgen. +- Please specify the 'LLVM_CONFIG' environment variable +- (recommended), pass the '--with-libclang-path' and '--with-clang-path' +- options to configure, or put 'llvm-config' in your PATH. Altering your +- PATH may expose 'clang' as well, potentially altering your compiler, +- which may not be what you intended.''')) +- +- check_minimum_llvm_config_version(llvm_config) +- libclang_arg = '--bindir' if host.os == 'WINNT' else '--libdir' +- libclang_path = invoke_llvm_config(llvm_config, libclang_arg) +- clang_path = os.path.join(invoke_llvm_config(llvm_config, '--bindir'), +- 'clang') +- libclang_path = normsep(libclang_path) +- clang_path = normsep(clang_path) ++ if build_project in ('browser', 'mobile/android'): ++ if not clang: ++ die('Could not find clang to generate run bindings for C/C++. ' ++ 'Please install the necessary packages, run `mach bootstrap`, ' ++ 'or use --with-clang-path to give the location of clang.') + +- # Debian-based distros, at least, can have llvm-config installed +- # but not have other packages installed. Since the user is trying +- # to use their system packages, we can't be more specific about what +- # they need. +- clang_resolved = find_program(clang_path) +- if not clang_resolved: +- die(dedent('''\ +- The file {} returned by `llvm-config {}` does not exist. +- clang is required to build Firefox. Please install the +- necessary packages, or run `mach bootstrap`. +- '''.format(clang_path, '--bindir'))) ++ if not libclang: ++ die('Could not find libclang to generate rust bindings for C/C++. ' ++ 'Please install the necessary packages, run `mach bootstrap`, ' ++ 'or use --with-libclang-path to give the path containing it.') + +- if not os.path.exists(libclang_path): +- die(dedent('''\ +- The directory {} returned by `llvm-config {}` does not exist. +- clang is required to build Firefox. Please install the +- necessary packages, or run `mach bootstrap`. +- '''.format(libclang_path, libclang_arg))) +- +- (libclang, searched) = search_for_libclang(libclang_path) +- if not libclang: +- die(dedent('''\ +- Could not find the clang shared library in the path {} +- returned by `llvm-config {}` (searched for files {}). +- clang is required to build Firefox. Please install the +- necessary packages, or run `mach bootstrap`. +- '''.format(libclang_path, libclang_arg, searched))) +- ++ if clang and libclang: + return namespace( + libclang=libclang, +- libclang_path=libclang_path, +- clang_path=clang_resolved, ++ libclang_path=os.path.dirname(libclang), ++ clang_path=clang.path, ++ clang_flags=clang.flags, + ) + +- if (not libclang_path and clang_path) or \ +- (libclang_path and not clang_path): +- if build_project not in bindgen_projects: +- return namespace() + +- die(dedent('''\ +- You must provide both of --with-libclang-path and --with-clang-path +- or neither of them.''')) +- +- libclang_path = libclang_path[0] +- clang_path = clang_path[0] +- +- if not os.path.exists(libclang_path) or \ +- not os.path.isdir(libclang_path): +- die(dedent('''\ +- The argument to --with-libclang-path is not a directory: {} +- '''.format(libclang_path))) +- +- (libclang, searched) = search_for_libclang(libclang_path) +- if not libclang: +- die(dedent('''\ +- Could not find the clang shared library in the path {} +- specified by --with-libclang-path (searched for files {}). +- '''.format(libclang_path, searched))) +- +- clang_resolved = find_program(clang_path) +- if not clang_resolved: +- die(dedent('''\ +- The argument to --with-clang-path is not a file: {} +- '''.format(clang_path))) +- +- return namespace( +- libclang=libclang, +- libclang_path=libclang_path, +- clang_path=clang_resolved, +- ) +- +-@depends(bindgen_config_paths.libclang) ++@depends(bindgen_config_paths.libclang, when=bindgen_config_paths) + @checking('that libclang is new enough', lambda s: 'yes' if s else 'no') + @imports(_from='ctypes', _import='CDLL') + @imports(_from='textwrap', _import='dedent') + def min_libclang_version(libclang): + try: + lib = CDLL(libclang.encode('utf-8')) + # We want at least 4.0. The API we test below is enough for that. + # Just accessing it should throw if not found. +@@ -292,19 +230,19 @@ def min_libclang_version(libclang): + return False + + + set_config('MOZ_LIBCLANG_PATH', bindgen_config_paths.libclang_path) + set_config('MOZ_CLANG_PATH', bindgen_config_paths.clang_path) + + + @depends(target, target_is_unix, cxx_compiler, bindgen_cflags_android, +- bindgen_config_paths.clang_path, macos_sdk) ++ bindgen_config_paths.clang_flags) + def basic_bindgen_cflags(target, is_unix, compiler_info, android_cflags, +- clang_path, macos_sdk): ++ clang_flags): + args = [ + '-x', 'c++', '-fno-sized-deallocation', + '-DTRACING=1', '-DIMPL_LIBXUL', '-DMOZILLA_INTERNAL_API', + '-DRUST_BINDGEN' + ] + + if is_unix: + args += ['-DOS_POSIX=1'] +@@ -334,30 +272,17 @@ def basic_bindgen_cflags(target, is_unix + # static_assert(). + '-D_CRT_USE_BUILTIN_OFFSETOF', + # Enable hidden attribute (which is not supported by MSVC and + # thus not enabled by default with a MSVC-compatibile build) + # to exclude hidden symbols from the generated file. + '-DHAVE_VISIBILITY_HIDDEN_ATTRIBUTE=1', + ] + +- # We want to pass the same base flags as we'd pass clang. +- # check_compiler from toolchain.configure gives us that. +- # XXX: We should actually use the compiler from toolchain.configure. +- # See bug 1526857. +- info = check_compiler([clang_path], 'C++', target) +- +- args += info.flags +- +- # XXX We wouldn't have to do this if we were using the compiler from +- # toolchain.configure, rather than just `check_compiler`. +- if macos_sdk and target.os == 'OSX': +- args += ['-isysroot', macos_sdk] +- +- return args ++ return args + (clang_flags or []) + + + js_option(env='BINDGEN_CFLAGS', + nargs=1, + help='Options bindgen should pass to the C/C++ parser') + + + @depends(basic_bindgen_cflags, 'BINDGEN_CFLAGS') +diff --git a/build/moz.configure/toolchain.configure b/build/moz.configure/toolchain.configure +--- a/build/moz.configure/toolchain.configure ++++ b/build/moz.configure/toolchain.configure +@@ -891,16 +891,22 @@ def provided_program(env_var): + wrapper=without_flags[:-1], + program=without_flags[-1], + flags=cmd[len(without_flags):], + ) + + return provided + + ++def prepare_flags(host_or_target, macos_sdk): ++ if macos_sdk and host_or_target.os == 'OSX': ++ return ['-isysroot', macos_sdk] ++ return [] ++ ++ + @template + def compiler(language, host_or_target, c_compiler=None, other_compiler=None, + other_c_compiler=None): + '''Template handling the generic base checks for the compiler for the + given `language` on the given platform (`host_or_target`). + `host_or_target` is either `host` or `target` (the @depends functions + from init.configure. + When the language is 'C++', `c_compiler` is the result of the `compiler` +@@ -969,18 +975,18 @@ def compiler(language, host_or_target, c + # --with-ccache. + if provided_wrapper[:len(wrapper)] == wrapper: + provided_wrapper = provided_wrapper[len(wrapper):] + wrapper.extend(provided_wrapper) + flags = provided_compiler.flags + else: + flags = [] + +- if not flags and macos_sdk and host_or_target.os == 'OSX': +- flags = ['-isysroot', macos_sdk] ++ if not flags: ++ flags = prepare_flags(host_or_target, macos_sdk) + + info = check_compiler(wrapper + [compiler] + flags, language, + host_or_target) + + # Check that the additional flags we got are enough to not require any + # more flags. If we get an exception, just ignore it; it's liable to be + # invalid command-line flags, which means the compiler we're checking + # doesn't support those command-line flags and will fail one or more of +diff --git a/build/unix/mozconfig.unix b/build/unix/mozconfig.unix +--- a/build/unix/mozconfig.unix ++++ b/build/unix/mozconfig.unix +@@ -4,16 +4,17 @@ TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir} + + if [ -n "$FORCE_GCC" ]; then + CC="$TOOLTOOL_DIR/gcc/bin/gcc" + CXX="$TOOLTOOL_DIR/gcc/bin/g++" + + # We want to make sure we use binutils and other binaries in the tooltool + # package. + mk_add_options "export PATH=$TOOLTOOL_DIR/gcc/bin:$PATH" ++ ac_add_options --with-clang-path=$TOOLTOOL_DIR/clang/bin/clang + else + CC="$TOOLTOOL_DIR/clang/bin/clang" + CXX="$TOOLTOOL_DIR/clang/bin/clang++" + export ENABLE_CLANG_PLUGIN=1 + case "$PERFHERDER_EXTRA_OPTIONS" in + base-toolchains*) + # Clang versions < 7.0 don't support the -fcrash-diagnostics-dir flag. + ;; +diff --git a/taskcluster/scripts/builder/hazard-analysis.sh b/taskcluster/scripts/builder/hazard-analysis.sh Index: ps/trunk/libraries/source/spidermonkey/FixPublicExport.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/FixPublicExport.diff +++ ps/trunk/libraries/source/spidermonkey/FixPublicExport.diff @@ -0,0 +1,21 @@ +--- a/js/public/AllocPolicy.h ++++ b/js/public/AllocPolicy.h +@@ -107,7 +107,7 @@ + * Non-inline helper to call JSRuntime::onOutOfMemory with minimal + * code bloat. + */ +- JS_FRIEND_API void* onOutOfMemory(arena_id_t arenaId, AllocFunction allocFunc, ++ void* onOutOfMemory(arena_id_t arenaId, AllocFunction allocFunc, + size_t nbytes, void* reallocPtr = nullptr); + + template +@@ -172,7 +172,7 @@ + js_free(p); + } + +- JS_FRIEND_API void reportAllocOverflow() const; ++ void reportAllocOverflow() const; + + bool checkSimulatedOOM() const { + if (js::oom::ShouldFailWithOOM()) { + Index: ps/trunk/libraries/source/spidermonkey/README.txt =================================================================== --- ps/trunk/libraries/source/spidermonkey/README.txt +++ ps/trunk/libraries/source/spidermonkey/README.txt @@ -28,8 +28,15 @@ We provide precompiled binaries for Windows. If you still need to build on Windows, here's a short guide. -Setting up the build environment: -1. Go to https://firefox-source-docs.mozilla.org/setup/windows_build.html#mozillabuild -2. Download the latest mozbuild package and install it to C:/mozilla-build (default). -3. Run MozillaBuild 3.x (start-shell.bat) -4. cd to the build.sh directory and run ./build.sh +The basic idea is to follow the instructions to build Firefox: +https://firefox-source-docs.mozilla.org/setup/windows_build.html#mozillabuild +And after running "mach boostrap", run ./build.sh + +The customised option (which I used): +- Install mozilla-build per the instructions above +- Install rust (make sure to add it to your PATH) +- Open Powershell and run "rustup install i686-pc-windows-msvc" and "rustup install x86_64-pc-windows-msvc" +- Install LLVM 8 prebuilt binaries from https://releases.llvm.org somewhere (the script plans for C:/Program Files/LLVM) +- From powershell, run ". C:/mozilla-build/start-shell.bat", cd to 0ad/libraries/source/spidermonkey and then run "./build.sh" + +At that point, everything should be setup and run correctly. Index: ps/trunk/libraries/source/spidermonkey/RenameLibs.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/RenameLibs.diff +++ ps/trunk/libraries/source/spidermonkey/RenameLibs.diff @@ -2,18 +2,18 @@ index 7d621b52ce..85e2934fa9 100644 --- a/js/src/old-configure +++ b/js/src/old-configure -@@ -10469,12 +10469,12 @@ done +@@ -7013,11 +7013,11 @@ -if test -n "$JS_STANDALONE"; then MOZ_APP_NAME="mozjs" - MOZ_APP_VERSION="$MOZILLA_SYMBOLVERSION" -JS_LIBRARY_NAME="mozjs-$MOZILLA_SYMBOLVERSION" +-else +-JS_LIBRARY_NAME="mozjs" +if test -n "$MOZ_DEBUG"; then +JS_LIBRARY_NAME="mozjs$MOZILLA_SYMBOLVERSION-ps-debug" - else --JS_LIBRARY_NAME="mozjs" ++else +JS_LIBRARY_NAME="mozjs$MOZILLA_SYMBOLVERSION-ps-release" fi JS_CONFIG_LIBS="$NSPR_LIBS $LIBS" Index: ps/trunk/libraries/source/spidermonkey/StandardDbgMacro.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/StandardDbgMacro.diff +++ ps/trunk/libraries/source/spidermonkey/StandardDbgMacro.diff @@ -0,0 +1,58 @@ + +# HG changeset patch +# User Jeff Walden +# Date 1582109071 0 +# Node ID 0f4fc4e582d369244c46b28ee9f86d0b02dc9e39 +# Parent 2779aefcb6c5e2d1cedaf974fe67b30fbf7805d0 +Bug 1614243 - Make mfbt/DbgMacro.h use standard variadic macro syntax, not gcc/clang extension syntax. r=froydnj + +Differential Revision: https://phabricator.services.mozilla.com/D63283 + +diff --git a/mfbt/DbgMacro.h b/mfbt/DbgMacro.h +--- a/mfbt/DbgMacro.h ++++ b/mfbt/DbgMacro.h +@@ -167,18 +167,18 @@ std::ostream& operator<<(std::ostream& a + // B b1 = B(); // fine, initializes b1 directly + // + // B b2 = MOZ_DBG(B()); // compile error: MOZ_DBG needs to materialize a + // // temporary for B() so it can be passed to + // // operator<<, but that temporary is returned from + // // MOZ_DBG as an rvalue reference and so wants to + // // invoke B's move constructor to initialize b2 + #ifndef MOZILLA_OFFICIAL +-# define MOZ_DBG(expression_...) \ +- mozilla::detail::MozDbg(__FILE__, __LINE__, #expression_, expression_) ++# define MOZ_DBG(...) \ ++ mozilla::detail::MozDbg(__FILE__, __LINE__, #__VA_ARGS__, __VA_ARGS__) + #endif + + // Helper macro for MOZ_DEFINE_DBG. + #define MOZ_DBG_FIELD(name_) << #name_ << " = " << aValue.name_ + + // Macro to define an operator<<(ostream&) for a struct or class that displays + // the type name and the values of the specified member variables. Must be + // called inside the struct or class. +@@ -189,18 +189,18 @@ std::ostream& operator<<(std::ostream& a + // float x; + // float y; + // + // MOZ_DEFINE_DBG(Point, x, y) + // }; + // + // generates an operator<< that outputs strings like + // "Point { x = 1.0, y = 2.0 }". +-#define MOZ_DEFINE_DBG(type_, members_...) \ ++#define MOZ_DEFINE_DBG(type_, ...) \ + friend std::ostream& operator<<(std::ostream& aOut, const type_& aValue) { \ + return aOut << #type_ \ +- << (MOZ_ARG_COUNT(members_) == 0 ? "" : " { ") \ ++ << (MOZ_ARG_COUNT(__VA_ARGS__) == 0 ? "" : " { ") \ + MOZ_FOR_EACH_SEPARATED(MOZ_DBG_FIELD, (<< ", "), (), \ +- (members_)) \ +- << (MOZ_ARG_COUNT(members_) == 0 ? "" : " }"); \ ++ (__VA_ARGS__)) \ ++ << (MOZ_ARG_COUNT(__VA_ARGS__) == 0 ? "" : " }"); \ + } + + #endif // mozilla_DbgMacro_h + Index: ps/trunk/libraries/source/spidermonkey/build.sh =================================================================== --- ps/trunk/libraries/source/spidermonkey/build.sh +++ ps/trunk/libraries/source/spidermonkey/build.sh @@ -3,10 +3,10 @@ set -e # This should match the version in config/milestone.txt -FOLDER="mozjs-60.9.1" +FOLDER="mozjs-68.12.1" # If same-version changes are needed, increment this. -LIB_VERSION="60.9.1+0" -LIB_NAME="mozjs60-ps" +LIB_VERSION="68.12.1+0" +LIB_NAME="mozjs68-ps" # Since this script is called by update-workspaces.sh, we want to quickly # avoid doing any work if SpiderMonkey is already built and up-to-date. @@ -43,7 +43,13 @@ # to match your environment. if [ "${OS}" = "Windows_NT" ] then - CONF_OPTS="${CONF_OPTS} --enable-nspr-build --with-visual-studio-version=2015" + # On windows, you may either use the full firefox build process (via mach bootstrap) + # or simply install LLVM to some convenient directory and hack the env. + if [ ! -d "~/.mozbuild"]; + then + export MOZBUILD_STATE_PATH="C:/Program Files/LLVM" + fi + CONF_OPTS="${CONF_OPTS} --enable-nspr-build --with-visual-studio-version=2017 --target=i686" else CONF_OPTS="${CONF_OPTS} --enable-posix-nspr-emulation" fi @@ -68,6 +74,13 @@ CONF_OPTS="${CONF_OPTS} --enable-valgrind" fi +# Quick sanity check to print explicit error messages +if [ ! "$(command -v rustc)" ] +then + echo "Error: rustc is not available. Install the rust toolchain before proceeding." + exit 1 +fi + # We need to be able to override CHOST in case it is 32bit userland on 64bit kernel CONF_OPTS="${CONF_OPTS} \ ${CBUILD:+--build=${CBUILD}} \ @@ -86,7 +99,7 @@ then # The tarball is committed to svn, but it's useful to let jenkins download it (when testing upgrade scripts). download="$(command -v wget || echo "curl -L -o "${FOLDER}.tar.bz2"")" - $download "https://github.com/wraitii/spidermonkey-tarballs/releases/download/v60.9.1/${FOLDER}.tar.bz2" + $download "https://github.com/wraitii/spidermonkey-tarballs/releases/download/v68.12.1/${FOLDER}.tar.bz2" fi tar xjf "${FOLDER}.tar.bz2" @@ -105,8 +118,9 @@ mkdir -p build-debug cd build-debug -# SM build scripts check for autoconf, but it isn't actually needed, so just pass something. -CXXFLAGS="${CXXFLAGS}" ../js/src/configure AUTOCONF="false" ${CONF_OPTS} \ +# SM configure checks for autoconf and llvm-objdump, but neither are actually used for building. +# To avoid a dependency, pass something arbitrary (it does need to be an actual program). +CXXFLAGS="${CXXFLAGS}" ../js/src/configure AUTOCONF="ls" LLVM_OBJDUMP="ls" ${CONF_OPTS} \ --enable-debug \ --disable-optimize \ --enable-gczeal @@ -115,7 +129,7 @@ mkdir -p build-release cd build-release -CXXFLAGS="${CXXFLAGS}" ../js/src/configure AUTOCONF="false" ${CONF_OPTS} \ +CXXFLAGS="${CXXFLAGS}" ../js/src/configure AUTOCONF="ls" LLVM_OBJDUMP="ls" ${CONF_OPTS} \ --enable-optimize ${MAKE} ${MAKE_OPTS} cd .. Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/double-conversion/double-conversion.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/double-conversion/double-conversion.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/double-conversion/double-conversion.h @@ -296,13 +296,18 @@ // should be at least kBase10MaximalLength + 1 characters long. static const MFBT_DATA int kBase10MaximalLength = 17; - // Converts the given double 'v' to ascii. 'v' must not be NaN, +Infinity, or - // -Infinity. In SHORTEST_SINGLE-mode this restriction also applies to 'v' - // after it has been casted to a single-precision float. That is, in this - // mode static_cast(v) must not be NaN, +Infinity or -Infinity. + // Converts the given double 'v' to digit characters. 'v' must not be NaN, + // +Infinity, or -Infinity. In SHORTEST_SINGLE-mode this restriction also + // applies to 'v' after it has been casted to a single-precision float. That + // is, in this mode static_cast(v) must not be NaN, +Infinity or + // -Infinity. // // The result should be interpreted as buffer * 10^(point-length). // + // The digits are written to the buffer in the platform's charset, which is + // often UTF-8 (with ASCII-range digits) but may be another charset, such + // as EBCDIC. + // // The output depends on the given mode: // - SHORTEST: produce the least amount of digits for which the internal // identity requirement is still satisfied. If the digits are printed @@ -376,7 +381,7 @@ const int max_leading_padding_zeroes_in_precision_mode_; const int max_trailing_padding_zeroes_in_precision_mode_; - DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter); + DC_DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter); }; @@ -540,7 +545,7 @@ bool read_as_double, int* processed_characters_count) const; - DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter); + DC_DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter); }; } // namespace double_conversion Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/double-conversion/utils.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/double-conversion/utils.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/double-conversion/utils.h @@ -68,7 +68,7 @@ // disabled.) // On Linux,x86 89255e-22 != Div_double(89255.0/1e22) #if defined(_M_X64) || defined(__x86_64__) || \ - defined(__ARMEL__) || defined(__avr32__) || \ + defined(__ARMEL__) || defined(__avr32__) || defined(_M_ARM) || defined(_M_ARM64) || \ defined(__hppa__) || defined(__ia64__) || \ defined(__mips__) || \ defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \ @@ -79,7 +79,8 @@ defined(__AARCH64EL__) || defined(__aarch64__) || \ defined(__riscv) #define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 -#elif defined(__mc68000__) +#elif defined(__mc68000__) || \ + defined(__pnacl__) || defined(__native_client__) #undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS #elif defined(_M_IX86) || defined(__i386__) || defined(__i386) #if defined(_WIN32) @@ -92,14 +93,24 @@ #error Target architecture was not detected as supported by Double-Conversion. #endif -#if defined(__GNUC__) -#define DOUBLE_CONVERSION_UNUSED __attribute__((unused)) +#if defined(_WIN32) && !defined(__MINGW32__) + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; // NOLINT +typedef unsigned short uint16_t; // NOLINT +typedef int int32_t; +typedef unsigned int uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +// intptr_t and friends are defined in crtdefs.h through stdio.h. + #else -#define DOUBLE_CONVERSION_UNUSED -#endif #include +#endif + typedef uint16_t uc16; // The following macro works on both 32 and 64-bit platforms. @@ -120,8 +131,8 @@ // A macro to disallow the evil copy constructor and operator= functions // This should be used in the private: declarations for a class -#ifndef DISALLOW_COPY_AND_ASSIGN -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ +#ifndef DC_DISALLOW_COPY_AND_ASSIGN +#define DC_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&); \ void operator=(const TypeName&) #endif @@ -132,10 +143,10 @@ // This should be used in the private: declarations for a class // that wants to prevent anyone from instantiating it. This is // especially useful for classes containing only static methods. -#ifndef DISALLOW_IMPLICIT_CONSTRUCTORS -#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ +#ifndef DC_DISALLOW_IMPLICIT_CONSTRUCTORS +#define DC_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ TypeName(); \ - DISALLOW_COPY_AND_ASSIGN(TypeName) + DC_DISALLOW_COPY_AND_ASSIGN(TypeName) #endif namespace double_conversion { @@ -277,7 +288,7 @@ bool is_finalized() const { return position_ < 0; } - DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder); + DC_DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder); }; // The type-based aliasing rule allows the compiler to assume that pointers of @@ -308,8 +319,12 @@ inline Dest BitCast(const Source& source) { // Compile time assertion: sizeof(Dest) == sizeof(Source) // A compile error here means your Dest and Source have different sizes. - DOUBLE_CONVERSION_UNUSED - typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1]; +#if __cplusplus >= 201103L + static_assert(sizeof(Dest) == sizeof(Source), + "source and destination size mismatch"); +#else + typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1]; +#endif Dest dest; memmove(&dest, &source, sizeof(dest)); Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js-config.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js-config.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js-config.h @@ -38,6 +38,13 @@ /* Define to 1 if SpiderMonkey should include ctypes support. */ /* #undef JS_HAS_CTYPES */ +/* Define to 1 if SpiderMonkey should include trace logging support. */ +/* #undef JS_TRACE_LOGGING */ + +/* Define to 1 if SpiderMonkey should include a breakpoint function for + * artificial OOMs. */ +/* #undef JS_OOM_BREAKPOINT */ + /* Define to 1 if SpiderMonkey should support the ability to perform entirely too much GC. */ #define JS_GC_ZEAL 1 @@ -48,14 +55,27 @@ /* Define to 1 to perform extra assertions and heap poisoning. */ /* #undef JS_CRASH_DIAGNOSTICS */ +/* Define to 1 if SpiderMonkey is compiled with support for private values at + * odd-numbered memory addresses. */ +/* #undef JS_UNALIGNED_PRIVATE_VALUES */ + /* Define to 1 if SpiderMonkey is in NUNBOX32 mode. */ #define JS_NUNBOX32 1 /* Define to 1 if SpiderMonkey is in PUNBOX64 mode. */ /* #undef JS_PUNBOX64 */ +/* Define exactly one of these to 1 to indicate JIT code generation mode. */ +/* #undef JS_CODEGEN_NONE */ +/* #undef JS_CODEGEN_ARM */ +/* #undef JS_CODEGEN_ARM64 */ +/* #undef JS_CODEGEN_MIPS32 */ +/* #undef JS_CODEGEN_MIPS64 */ +#define JS_CODEGEN_X86 1 +/* #undef JS_CODEGEN_X64 */ + /* MOZILLA JSAPI version number components */ -#define MOZJS_MAJOR_VERSION 60 -#define MOZJS_MINOR_VERSION 9 +#define MOZJS_MAJOR_VERSION 68 +#define MOZJS_MINOR_VERSION 12 #endif /* js_config_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js.msg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js.msg +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js.msg @@ -41,7 +41,7 @@ MSG_DEF(JSMSG_NOT_AN_ERROR, 0, JSEXN_ERR, "") MSG_DEF(JSMSG_NOT_DEFINED, 1, JSEXN_REFERENCEERR, "{0} is not defined") -MSG_DEF(JSMSG_MORE_ARGS_NEEDED, 3, JSEXN_TYPEERR, "{0} requires more than {1} argument{2}") +MSG_DEF(JSMSG_MORE_ARGS_NEEDED, 4, JSEXN_TYPEERR, "{0} requires at least {1} argument{2}, but only {3} were passed") MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}") MSG_DEF(JSMSG_NO_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} has no constructor") MSG_DEF(JSMSG_BAD_SORT_ARG, 0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument") @@ -50,6 +50,7 @@ MSG_DEF(JSMSG_CANT_TRUNCATE_ARRAY, 0, JSEXN_TYPEERR, "can't delete non-configurable array element") MSG_DEF(JSMSG_NOT_FUNCTION, 1, JSEXN_TYPEERR, "{0} is not a function") MSG_DEF(JSMSG_NOT_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} is not a constructor") +MSG_DEF(JSMSG_BOGUS_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} constructor can't be used directly") MSG_DEF(JSMSG_CANT_CONVERT_TO, 2, JSEXN_TYPEERR, "can't convert {0} to {1}") MSG_DEF(JSMSG_TOPRIMITIVE_NOT_CALLABLE, 2, JSEXN_TYPEERR, "can't convert {0} to {1}: its [Symbol.toPrimitive] property is not a function") MSG_DEF(JSMSG_TOPRIMITIVE_RETURNED_OBJECT, 2, JSEXN_TYPEERR, "can't convert {0} to {1}: its [Symbol.toPrimitive] method returned an object") @@ -63,6 +64,7 @@ MSG_DEF(JSMSG_BAD_WEAKMAP_KEY, 0, JSEXN_TYPEERR, "cannot use the given object as a weak map key") MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER, 1, JSEXN_TYPEERR, "invalid {0} usage") MSG_DEF(JSMSG_BAD_ARRAY_LENGTH, 0, JSEXN_RANGEERR, "invalid array length") +MSG_DEF(JSMSG_SOURCE_ARRAY_TOO_LONG, 0, JSEXN_RANGEERR, "source array is too long") MSG_DEF(JSMSG_REDECLARED_PREV, 2, JSEXN_NOTE, "Previously declared at line {0}, column {1}") MSG_DEF(JSMSG_REDECLARED_VAR, 2, JSEXN_SYNTAXERR, "redeclaration of {0} {1}") MSG_DEF(JSMSG_UNDECLARED_VAR, 1, JSEXN_REFERENCEERR, "assignment to undeclared variable {0}") @@ -82,6 +84,7 @@ MSG_DEF(JSMSG_NOT_NONNULL_OBJECT, 1, JSEXN_TYPEERR, "{0} is not a non-null object") MSG_DEF(JSMSG_NOT_NONNULL_OBJECT_NAME, 2, JSEXN_TYPEERR, "{0} must be an object, got {1}") MSG_DEF(JSMSG_NOT_NONNULL_OBJECT_ARG, 3, JSEXN_TYPEERR, "{0} argument of {1} must be an object, got {2}") +MSG_DEF(JSMSG_WRONG_TYPE_ARG, 4, JSEXN_TYPEERR, "argument {0} to {1} must be an object of type {2}, got {3}") MSG_DEF(JSMSG_SET_NON_OBJECT_RECEIVER, 2, JSEXN_TYPEERR, "can't assign to property {1} on {0}: not an object") MSG_DEF(JSMSG_INVALID_DESCRIPTOR, 0, JSEXN_TYPEERR, "property descriptors must not specify a value or be writable when a getter or setter has been specified") MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE, 1, JSEXN_TYPEERR, "{0}: Object is not extensible") @@ -101,12 +104,12 @@ MSG_DEF(JSMSG_CANT_SET_PROTO_CYCLE, 0, JSEXN_TYPEERR, "can't set prototype: it would cause a prototype chain cycle") MSG_DEF(JSMSG_INVALID_ARG_TYPE, 3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}") MSG_DEF(JSMSG_TERMINATED, 1, JSEXN_ERR, "Script terminated by timeout at:\n{0}") -MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with |new|") -MSG_DEF(JSMSG_UNINITIALIZED_THIS, 1, JSEXN_REFERENCEERR, "must call super constructor before using |this| in {0} class constructor") -MSG_DEF(JSMSG_UNINITIALIZED_THIS_ARROW, 0, JSEXN_REFERENCEERR, "must call super constructor before using |this| in arrow function in derived class constructor") +MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with 'new'") +MSG_DEF(JSMSG_UNINITIALIZED_THIS, 0, JSEXN_REFERENCEERR, "must call super constructor before using 'this' in derived class constructor") MSG_DEF(JSMSG_BAD_DERIVED_RETURN, 1, JSEXN_TYPEERR, "derived class constructor returned invalid value {0}") MSG_DEF(JSMSG_BAD_HERITAGE, 2, JSEXN_TYPEERR, "class heritage {0} is {1}") MSG_DEF(JSMSG_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0} is not an object or null") +MSG_DEF(JSMSG_CONSTRUCTOR_DISABLED, 1, JSEXN_TYPEERR, "{0} is disabled") // JSON MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data") @@ -134,7 +137,6 @@ MSG_DEF(JSMSG_NEGATIVE_REPETITION_COUNT, 0, JSEXN_RANGEERR, "repeat count must be non-negative") MSG_DEF(JSMSG_NOT_A_CODEPOINT, 1, JSEXN_RANGEERR, "{0} is not a valid code point") MSG_DEF(JSMSG_RESULTING_STRING_TOO_LARGE, 0, JSEXN_RANGEERR, "repeat count must be less than infinity and not overflow maximum string size") -MSG_DEF(JSMSG_DEPRECATED_STRING_METHOD, 2, JSEXN_WARN, "String.{0} is deprecated; use String.prototype.{1} instead") // Number MSG_DEF(JSMSG_BAD_RADIX, 0, JSEXN_RANGEERR, "radix must be an integer at least 2 and no greater than 36") @@ -151,8 +153,8 @@ MSG_DEF(JSMSG_TOO_MANY_ARGUMENTS, 0, JSEXN_RANGEERR, "too many arguments provided for a function call") // CSP -MSG_DEF(JSMSG_CSP_BLOCKED_EVAL, 0, JSEXN_ERR, "call to eval() blocked by CSP") -MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION, 0, JSEXN_ERR, "call to Function() blocked by CSP") +MSG_DEF(JSMSG_CSP_BLOCKED_EVAL, 0, JSEXN_EVALERR, "call to eval() blocked by CSP") +MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION, 0, JSEXN_EVALERR, "call to Function() blocked by CSP") // Wrappers MSG_DEF(JSMSG_ACCESSOR_DEF_DENIED, 1, JSEXN_ERR, "Permission denied to define accessor property {0}") @@ -186,7 +188,7 @@ MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 0, JSEXN_INTERNALERR, "array initializer too large") MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as' after import *") MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'") -MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await can't be used in default expression") +MSG_DEF(JSMSG_AWAIT_IN_PARAMETER, 0, JSEXN_SYNTAXERR, "await expression can't be used in parameter") MSG_DEF(JSMSG_AWAIT_OUTSIDE_ASYNC, 0, JSEXN_SYNTAXERR, "await is only valid in async functions and async generators") MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)") MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated") @@ -203,7 +205,6 @@ MSG_DEF(JSMSG_LET_STARTING_FOROF_LHS, 0, JSEXN_SYNTAXERR, "an expression X in 'for (X of Y)' must not start with 'let'") MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand") MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition") -MSG_DEF(JSMSG_BAD_OCTAL, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant") MSG_DEF(JSMSG_BAD_POW_LEFTSIDE, 0, JSEXN_SYNTAXERR, "unparenthesized unary expression can't appear on the left-hand side of '**'") MSG_DEF(JSMSG_BAD_PROP_ID, 0, JSEXN_SYNTAXERR, "invalid property id") MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 1, JSEXN_SYNTAXERR, "{0} not in function") @@ -214,6 +215,7 @@ MSG_DEF(JSMSG_BAD_SUPER, 0, JSEXN_SYNTAXERR, "invalid use of keyword 'super'") MSG_DEF(JSMSG_BAD_SUPERPROP, 1, JSEXN_SYNTAXERR, "use of super {0} accesses only valid within methods or eval code within methods") MSG_DEF(JSMSG_BAD_SUPERCALL, 0, JSEXN_SYNTAXERR, "super() is only valid in derived class constructors") +MSG_DEF(JSMSG_BAD_ARGUMENTS, 0, JSEXN_SYNTAXERR, "arguments is not valid in fields") MSG_DEF(JSMSG_BRACKET_AFTER_LIST, 0, JSEXN_SYNTAXERR, "missing ] after element list") MSG_DEF(JSMSG_BRACKET_IN_INDEX, 0, JSEXN_SYNTAXERR, "missing ] in index expression") MSG_DEF(JSMSG_BRACKET_OPENED, 2, JSEXN_NOTE, "[ opened at line {0}, column {1}") @@ -242,11 +244,8 @@ MSG_DEF(JSMSG_DECLARATION_AFTER_EXPORT,0, JSEXN_SYNTAXERR, "missing declaration after 'export' keyword") MSG_DEF(JSMSG_DECLARATION_AFTER_IMPORT,0, JSEXN_SYNTAXERR, "missing declaration after 'import' keyword") MSG_DEF(JSMSG_DEPRECATED_DELETE_OPERAND, 0, JSEXN_SYNTAXERR, "applying the 'delete' operator to an unqualified name is deprecated") -MSG_DEF(JSMSG_DEPRECATED_EXPR_CLOSURE, 0, JSEXN_WARN, "expression closures are deprecated") -MSG_DEF(JSMSG_DEPRECATED_FOR_EACH, 0, JSEXN_WARN, "JavaScript 1.6's for-each-in loops are deprecated; consider using ES6 for-of instead") MSG_DEF(JSMSG_DEPRECATED_OCTAL, 0, JSEXN_SYNTAXERR, "\"0\"-prefixed octal literals and octal escape sequences are deprecated; for octal literals use the \"0o\" prefix instead") MSG_DEF(JSMSG_DEPRECATED_PRAGMA, 1, JSEXN_WARN, "Using //@ to indicate {0} pragmas is deprecated. Use //# instead") -MSG_DEF(JSMSG_DEPRECATED_BLOCK_SCOPE_FUN_REDECL, 1, JSEXN_WARN, "redeclaration of block-scoped function `{0}' is deprecated") MSG_DEF(JSMSG_DUPLICATE_EXPORT_NAME, 1, JSEXN_SYNTAXERR, "duplicate export name '{0}'") MSG_DEF(JSMSG_DUPLICATE_FORMAL, 1, JSEXN_SYNTAXERR, "duplicate formal argument {0}") MSG_DEF(JSMSG_DUPLICATE_LABEL, 0, JSEXN_SYNTAXERR, "duplicate label") @@ -263,12 +262,15 @@ MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT, 2, JSEXN_SYNTAXERR, "unexpected garbage after {0}, starting with {1}") MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER, 0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal") MSG_DEF(JSMSG_BAD_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid escape sequence") +MSG_DEF(JSMSG_MISSING_PRIVATE_NAME, 0, JSEXN_SYNTAXERR, "'#' not followed by identifier") MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 0, JSEXN_SYNTAXERR, "illegal character") +MSG_DEF(JSMSG_IMPORT_META_OUTSIDE_MODULE, 0, JSEXN_SYNTAXERR, "import.meta may only appear in a module") MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level of a module") MSG_DEF(JSMSG_OF_AFTER_FOR_LOOP_DECL, 0, JSEXN_SYNTAXERR, "a declaration in the head of a for-of loop can't have an initializer") MSG_DEF(JSMSG_IN_AFTER_LEXICAL_FOR_DECL,0,JSEXN_SYNTAXERR, "a lexical declaration in the head of a for-in loop can't have an initializer") MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers") MSG_DEF(JSMSG_INVALID_ID, 1, JSEXN_SYNTAXERR, "{0} is an invalid identifier") +MSG_DEF(JSMSG_SEPARATOR_IN_ZERO_PREFIXED_NUMBER, 0, JSEXN_SYNTAXERR, "numeric separators '_' are not allowed in numbers that start with '0'") MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found") MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, 1, JSEXN_SYNTAXERR, "{0} declaration not directly within block") MSG_DEF(JSMSG_LEXICAL_DECL_LABEL, 1, JSEXN_SYNTAXERR, "{0} declarations cannot be labelled") @@ -284,6 +286,7 @@ MSG_DEF(JSMSG_MISSING_FORMAL, 0, JSEXN_SYNTAXERR, "missing formal parameter") MSG_DEF(JSMSG_MISSING_HEXDIGITS, 0, JSEXN_SYNTAXERR, "missing hexadecimal digits after '0x'") MSG_DEF(JSMSG_MISSING_OCTAL_DIGITS, 0, JSEXN_SYNTAXERR, "missing octal digits after '0o'") +MSG_DEF(JSMSG_MISSING_DIGIT_AFTER_SEPARATOR, 0, JSEXN_SYNTAXERR, "missing digit after '_' numeric separator") MSG_DEF(JSMSG_MODULE_SPEC_AFTER_FROM, 0, JSEXN_SYNTAXERR, "missing module specifier after 'from' keyword") MSG_DEF(JSMSG_NAME_AFTER_DOT, 0, JSEXN_SYNTAXERR, "missing name after . operator") MSG_DEF(JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT, 0, JSEXN_SYNTAXERR, "expected named imports or namespace import after comma") @@ -323,14 +326,13 @@ MSG_DEF(JSMSG_STRICT_CODE_WITH, 0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements") MSG_DEF(JSMSG_STRICT_NON_SIMPLE_PARAMS, 1, JSEXN_SYNTAXERR, "\"use strict\" not allowed in function with {0} parameter") MSG_DEF(JSMSG_TEMPLSTR_UNTERM_EXPR, 0, JSEXN_SYNTAXERR, "missing } in template string") -MSG_DEF(JSMSG_SIMD_NOT_A_VECTOR, 2, JSEXN_TYPEERR, "expecting a SIMD {0} object as argument {1}") MSG_DEF(JSMSG_TOO_MANY_CASES, 0, JSEXN_INTERNALERR, "too many switch cases") MSG_DEF(JSMSG_TOO_MANY_CATCH_VARS, 0, JSEXN_SYNTAXERR, "too many catch variables") MSG_DEF(JSMSG_TOO_MANY_CON_ARGS, 0, JSEXN_SYNTAXERR, "too many constructor arguments") MSG_DEF(JSMSG_TOO_MANY_DEFAULTS, 0, JSEXN_SYNTAXERR, "more than one switch default") MSG_DEF(JSMSG_TOO_MANY_FUN_ARGS, 0, JSEXN_SYNTAXERR, "too many function arguments") MSG_DEF(JSMSG_TOO_MANY_LOCALS, 0, JSEXN_SYNTAXERR, "too many local variables") -MSG_DEF(JSMSG_TOO_MANY_YIELDS, 0, JSEXN_SYNTAXERR, "too many yield expressions") +MSG_DEF(JSMSG_TOO_MANY_RESUME_INDEXES, 0, JSEXN_SYNTAXERR, "too many yield/await/finally/case locations") MSG_DEF(JSMSG_TOUGH_BREAK, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch") MSG_DEF(JSMSG_UNEXPECTED_TOKEN, 2, JSEXN_SYNTAXERR, "expected {0}, got {1}") MSG_DEF(JSMSG_UNEXPECTED_TOKEN_NO_EXPECT, 1, JSEXN_SYNTAXERR, "unexpected token: {0}") @@ -346,20 +348,31 @@ MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL, 0, JSEXN_SYNTAXERR, "\"use asm\" is only meaningful in the Directive Prologue of a function body") MSG_DEF(JSMSG_VAR_HIDES_ARG, 1, JSEXN_TYPEERR, "variable {0} redeclares argument") MSG_DEF(JSMSG_WHILE_AFTER_DO, 0, JSEXN_SYNTAXERR, "missing while after do-loop body") -MSG_DEF(JSMSG_YIELD_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "yield in default expression") +MSG_DEF(JSMSG_YIELD_IN_PARAMETER, 0, JSEXN_SYNTAXERR, "yield expression can't be used in parameter") MSG_DEF(JSMSG_YIELD_OUTSIDE_GENERATOR, 0, JSEXN_SYNTAXERR, "yield expression is only valid in generators") MSG_DEF(JSMSG_BAD_COLUMN_NUMBER, 0, JSEXN_RANGEERR, "column number out of range") MSG_DEF(JSMSG_COMPUTED_NAME_IN_PATTERN,0, JSEXN_SYNTAXERR, "computed property names aren't supported in this destructuring declaration") MSG_DEF(JSMSG_DEFAULT_IN_PATTERN, 0, JSEXN_SYNTAXERR, "destructuring defaults aren't supported in this destructuring declaration") MSG_DEF(JSMSG_BAD_NEWTARGET, 0, JSEXN_SYNTAXERR, "new.target only allowed within functions") MSG_DEF(JSMSG_ESCAPED_KEYWORD, 0, JSEXN_SYNTAXERR, "keywords must be written literally, without embedded escapes") +MSG_DEF(JSMSG_FIELDS_NOT_SUPPORTED, 0, JSEXN_SYNTAXERR, "fields are not currently supported") + +// UTF-8 source text encoding errors +MSG_DEF(JSMSG_BAD_LEADING_UTF8_UNIT, 1, JSEXN_SYNTAXERR, "{0} byte doesn't begin a valid UTF-8 code point") +MSG_DEF(JSMSG_NOT_ENOUGH_CODE_UNITS, 5, JSEXN_SYNTAXERR, "{0} byte in UTF-8 must be followed by {1} byte{2}, but {3} byte{4} present") +MSG_DEF(JSMSG_BAD_TRAILING_UTF8_UNIT, 1, JSEXN_SYNTAXERR, "bad trailing UTF-8 byte {0} doesn't match the pattern 0b10xxxxxx") +MSG_DEF(JSMSG_FORBIDDEN_UTF8_CODE_POINT,2,JSEXN_SYNTAXERR, "{0} isn't a valid code point because {1}") +MSG_DEF(JSMSG_BAD_CODE_UNITS, 1, JSEXN_NOTE, "the code units comprising this invalid code point were: {0}") // asm.js MSG_DEF(JSMSG_USE_ASM_TYPE_FAIL, 1, JSEXN_TYPEERR, "asm.js type error: {0}") MSG_DEF(JSMSG_USE_ASM_LINK_FAIL, 1, JSEXN_TYPEERR, "asm.js link error: {0}") -MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 1, JSEXN_WARN, "Successfully compiled asm.js code ({0})") +MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 1, JSEXN_WARN, "Successfully compiled asm.js code (total compilation time {0}ms)") +MSG_DEF(JSMSG_USE_ASM_TYPE_OK_NO_TIME, 0, JSEXN_WARN, "Successfully compiled asm.js code ()") // wasm +MSG_DEF(JSMSG_WASM_VERBOSE, 1, JSEXN_WARN, "WebAssembly verbose: {0}") +MSG_DEF(JSMSG_WASM_COMPILE_WARNING, 1, JSEXN_WARN, "WebAssembly module validated with warning: {0}") MSG_DEF(JSMSG_WASM_COMPILE_ERROR, 1, JSEXN_WASMCOMPILEERROR, "{0}") MSG_DEF(JSMSG_WASM_NO_SHMEM_COMPILE, 0, JSEXN_WASMCOMPILEERROR, "shared memory is disabled") MSG_DEF(JSMSG_WASM_BAD_IMPORT_TYPE, 2, JSEXN_WASMLINKERROR, "import object field '{0}' is not a {1}") @@ -371,6 +384,9 @@ MSG_DEF(JSMSG_WASM_BAD_FIT, 2, JSEXN_WASMLINKERROR, "{0} segment does not fit in {1}") MSG_DEF(JSMSG_WASM_BAD_I64_LINK, 0, JSEXN_WASMLINKERROR, "cannot pass i64 to or from JS") MSG_DEF(JSMSG_WASM_NO_SHMEM_LINK, 0, JSEXN_WASMLINKERROR, "shared memory is disabled") +MSG_DEF(JSMSG_WASM_BAD_GLOB_MUT_LINK, 0, JSEXN_WASMLINKERROR, "imported global mutability mismatch") +MSG_DEF(JSMSG_WASM_BAD_GLOB_TYPE_LINK, 0, JSEXN_WASMLINKERROR, "imported global type mismatch") +MSG_DEF(JSMSG_WASM_BAD_TBL_TYPE_LINK, 0, JSEXN_WASMLINKERROR, "imported table type mismatch") MSG_DEF(JSMSG_WASM_IND_CALL_TO_NULL, 0, JSEXN_WASMRUNTIMEERROR, "indirect call to null") MSG_DEF(JSMSG_WASM_IND_CALL_BAD_SIG, 0, JSEXN_WASMRUNTIMEERROR, "indirect call signature mismatch") MSG_DEF(JSMSG_WASM_UNREACHABLE, 0, JSEXN_WASMRUNTIMEERROR, "unreachable executed") @@ -380,20 +396,25 @@ MSG_DEF(JSMSG_WASM_OUT_OF_BOUNDS, 0, JSEXN_WASMRUNTIMEERROR, "index out of bounds") MSG_DEF(JSMSG_WASM_UNALIGNED_ACCESS, 0, JSEXN_WASMRUNTIMEERROR, "unaligned memory access") MSG_DEF(JSMSG_WASM_WAKE_OVERFLOW, 0, JSEXN_WASMRUNTIMEERROR, "too many woken agents") -MSG_DEF(JSMSG_WASM_BAD_UINT32, 2, JSEXN_RANGEERR, "bad {0} {1}") +MSG_DEF(JSMSG_WASM_DROPPED_DATA_SEG, 0, JSEXN_WASMRUNTIMEERROR, "use of dropped data segment") +MSG_DEF(JSMSG_WASM_DROPPED_ELEM_SEG, 0, JSEXN_WASMRUNTIMEERROR, "use of dropped element segment") +MSG_DEF(JSMSG_WASM_DEREF_NULL, 0, JSEXN_WASMRUNTIMEERROR, "dereferencing null pointer") +MSG_DEF(JSMSG_WASM_BAD_RANGE , 2, JSEXN_RANGEERR, "bad {0} {1}") MSG_DEF(JSMSG_WASM_BAD_GROW, 1, JSEXN_RANGEERR, "failed to grow {0}") +MSG_DEF(JSMSG_WASM_TABLE_OUT_OF_BOUNDS, 0, JSEXN_RANGEERR, "table index out of bounds") +MSG_DEF(JSMSG_WASM_BAD_UINT32, 2, JSEXN_TYPEERR, "bad {0} {1}") MSG_DEF(JSMSG_WASM_BAD_BUF_ARG, 0, JSEXN_TYPEERR, "first argument must be an ArrayBuffer or typed array object") MSG_DEF(JSMSG_WASM_BAD_MOD_ARG, 0, JSEXN_TYPEERR, "first argument must be a WebAssembly.Module") MSG_DEF(JSMSG_WASM_BAD_BUF_MOD_ARG, 0, JSEXN_TYPEERR, "first argument must be a WebAssembly.Module, ArrayBuffer or typed array object") MSG_DEF(JSMSG_WASM_BAD_DESC_ARG, 1, JSEXN_TYPEERR, "first argument must be a {0} descriptor") -MSG_DEF(JSMSG_WASM_BAD_ELEMENT, 0, JSEXN_TYPEERR, "\"element\" property of table descriptor must be \"anyfunc\"") +MSG_DEF(JSMSG_WASM_BAD_ELEMENT, 0, JSEXN_TYPEERR, "\"element\" property of table descriptor must be \"funcref\"") +MSG_DEF(JSMSG_WASM_BAD_ELEMENT_GENERALIZED, 0, JSEXN_TYPEERR, "\"element\" property of table descriptor must be \"funcref\" or \"anyref\"") MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG, 0, JSEXN_TYPEERR, "second argument must be an object") MSG_DEF(JSMSG_WASM_BAD_IMPORT_FIELD, 1, JSEXN_TYPEERR, "import object field '{0}' is not an Object") -MSG_DEF(JSMSG_WASM_BAD_TABLE_VALUE, 0, JSEXN_TYPEERR, "can only assign WebAssembly exported functions to Table") +MSG_DEF(JSMSG_WASM_BAD_FUNCREF_VALUE, 0, JSEXN_TYPEERR, "can only pass WebAssembly exported functions to funcref") MSG_DEF(JSMSG_WASM_BAD_I64_TYPE, 0, JSEXN_TYPEERR, "cannot pass i64 to or from JS") MSG_DEF(JSMSG_WASM_BAD_GLOBAL_TYPE, 0, JSEXN_TYPEERR, "bad type for a WebAssembly.Global") MSG_DEF(JSMSG_WASM_NO_TRANSFER, 0, JSEXN_TYPEERR, "cannot transfer WebAssembly/asm.js ArrayBuffer") -MSG_DEF(JSMSG_WASM_STREAM_ERROR, 0, JSEXN_TYPEERR, "stream error during WebAssembly compilation") MSG_DEF(JSMSG_WASM_TEXT_FAIL, 1, JSEXN_SYNTAXERR, "wasm text error: {0}") MSG_DEF(JSMSG_WASM_MISSING_MAXIMUM, 0, JSEXN_TYPEERR, "'shared' is true but maximum is not specified") MSG_DEF(JSMSG_WASM_GLOBAL_IMMUTABLE, 0, JSEXN_TYPEERR, "can't set value of immutable global") @@ -454,6 +475,7 @@ MSG_DEF(JSMSG_DEBUG_BAD_RESUMPTION, 0, JSEXN_TYPEERR, "debugger resumption value must be undefined, {throw: val}, {return: val}, or null") MSG_DEF(JSMSG_DEBUG_BAD_YIELD, 0, JSEXN_TYPEERR, "generator yielded invalid value") MSG_DEF(JSMSG_DEBUG_CANT_DEBUG_GLOBAL, 0, JSEXN_TYPEERR, "passing non-debuggable global to addDebuggee") +MSG_DEF(JSMSG_DEBUG_SAME_COMPARTMENT, 0, JSEXN_TYPEERR, "debugger and debuggee must be in different compartments") MSG_DEF(JSMSG_DEBUG_CCW_REQUIRED, 1, JSEXN_TYPEERR, "{0}: argument must be an object from a different compartment") MSG_DEF(JSMSG_DEBUG_COMPARTMENT_MISMATCH, 2, JSEXN_TYPEERR, "{0}: descriptor .{1} property is an object in a different compartment than the target object") MSG_DEF(JSMSG_DEBUG_LOOP, 0, JSEXN_TYPEERR, "cannot debug an object in same compartment as debugger or a compartment that is already debugging the debugger") @@ -465,6 +487,8 @@ MSG_DEF(JSMSG_DEBUG_PROTO, 2, JSEXN_TYPEERR, "{0}.prototype is not a valid {1} instance") MSG_DEF(JSMSG_DEBUG_WRONG_OWNER, 1, JSEXN_TYPEERR, "{0} belongs to a different Debugger") MSG_DEF(JSMSG_DEBUG_OPTIMIZED_OUT, 1, JSEXN_ERR, "variable `{0}' has been optimized out") +MSG_DEF(JSMSG_DEBUG_OPTIMIZED_OUT_FUN, 0, JSEXN_ERR, "function is optimized out") +MSG_DEF(JSMSG_DEBUG_FORCED_RETURN_DISALLOWED, 0, JSEXN_TYPEERR, "can't force return from a generator before the initial yield") MSG_DEF(JSMSG_DEBUG_RESUMPTION_VALUE_DISALLOWED, 0, JSEXN_TYPEERR, "resumption values are disallowed in this hook") MSG_DEF(JSMSG_DEBUG_VARIABLE_NOT_FOUND,0, JSEXN_TYPEERR, "variable not found in environment") MSG_DEF(JSMSG_DEBUG_WRAPPER_IN_WAY, 3, JSEXN_TYPEERR, "{0} is {1}{2}a global object, but a direct reference is required") @@ -489,9 +513,8 @@ MSG_DEF(JSMSG_TRACELOGGER_ENABLE_FAIL, 1, JSEXN_ERR, "enabling tracelogger failed: {0}") // Intl -MSG_DEF(JSMSG_DATE_NOT_FINITE, 0, JSEXN_RANGEERR, "date value is not finite in DateTimeFormat.format()") +MSG_DEF(JSMSG_DATE_NOT_FINITE, 1, JSEXN_RANGEERR, "date value is not finite in {0}.format()") MSG_DEF(JSMSG_INTERNAL_INTL_ERROR, 0, JSEXN_ERR, "internal error while computing Intl data") -MSG_DEF(JSMSG_INTL_OBJECT_NOT_INITED, 3, JSEXN_TYPEERR, "Intl.{0}.prototype.{1} called on value that's not an object initialized as a {2}") MSG_DEF(JSMSG_INVALID_CURRENCY_CODE, 1, JSEXN_RANGEERR, "invalid currency code in NumberFormat(): {0}") MSG_DEF(JSMSG_INVALID_DIGITS_VALUE, 1, JSEXN_RANGEERR, "invalid digits value: {0}") MSG_DEF(JSMSG_INVALID_KEYS_TYPE, 0, JSEXN_TYPEERR, "calendar info keys must be an object or undefined") @@ -517,8 +540,8 @@ MSG_DEF(JSMSG_NOTHING_TO_REPEAT, 0, JSEXN_SYNTAXERR, "nothing to repeat") MSG_DEF(JSMSG_NUMBERS_OUT_OF_ORDER, 0, JSEXN_SYNTAXERR, "numbers out of order in {} quantifier.") MSG_DEF(JSMSG_RANGE_WITH_CLASS_ESCAPE, 0, JSEXN_SYNTAXERR, "character class escape cannot be used in class range in regular expression") -MSG_DEF(JSMSG_RAW_BRACE_IN_REGEP, 0, JSEXN_SYNTAXERR, "raw brace is not allowed in regular expression with unicode flag") -MSG_DEF(JSMSG_RAW_BRACKET_IN_REGEP, 0, JSEXN_SYNTAXERR, "raw bracket is not allowed in regular expression with unicode flag") +MSG_DEF(JSMSG_RAW_BRACE_IN_REGEXP, 0, JSEXN_SYNTAXERR, "raw brace is not allowed in regular expression with unicode flag") +MSG_DEF(JSMSG_RAW_BRACKET_IN_REGEXP, 0, JSEXN_SYNTAXERR, "raw bracket is not allowed in regular expression with unicode flag") MSG_DEF(JSMSG_TOO_MANY_PARENS, 0, JSEXN_INTERNALERR, "too many parentheses in regular expression") MSG_DEF(JSMSG_UNICODE_OVERFLOW, 1, JSEXN_SYNTAXERR, "Unicode codepoint must not be greater than 0x10FFFF in {0}") MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression") @@ -528,18 +551,20 @@ MSG_DEF(JSMSG_DEFAULT_LOCALE_ERROR, 0, JSEXN_ERR, "internal error getting the default locale") MSG_DEF(JSMSG_NO_SUCH_SELF_HOSTED_PROP,1, JSEXN_ERR, "No such property on self-hosted object: {0}") -// Typed object / SIMD +// Typed object MSG_DEF(JSMSG_INVALID_PROTOTYPE, 0, JSEXN_TYPEERR, "prototype field is not an object") MSG_DEF(JSMSG_TYPEDOBJECT_BAD_ARGS, 0, JSEXN_TYPEERR, "invalid arguments") MSG_DEF(JSMSG_TYPEDOBJECT_BINARYARRAY_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index") MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED, 0, JSEXN_TYPEERR, "handle unattached") MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_ARGS, 0, JSEXN_RANGEERR, "invalid field descriptor") +MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_NOT_CALLABLE, 0, JSEXN_TYPEERR, "not callable") MSG_DEF(JSMSG_TYPEDOBJECT_TOO_BIG, 0, JSEXN_ERR, "Type is too large to allocate") -MSG_DEF(JSMSG_SIMD_FAILED_CONVERSION, 0, JSEXN_RANGEERR, "SIMD conversion loses precision") -MSG_DEF(JSMSG_SIMD_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert SIMD value to number") +MSG_DEF(JSMSG_TYPEDOBJECT_SETTING_IMMUTABLE, 0, JSEXN_ERR, "setting immutable field") +MSG_DEF(JSMSG_TYPEDOBJECT_NOT_CONSTRUCTIBLE, 0, JSEXN_TYPEERR, "not constructible") // Array MSG_DEF(JSMSG_TOO_LONG_ARRAY, 0, JSEXN_TYPEERR, "Too long array") +MSG_DEF(JSMSG_DEPRECATED_ARRAY_METHOD, 2, JSEXN_WARN, "Array.{0} is deprecated; use Array.prototype.{1} instead") // Typed array MSG_DEF(JSMSG_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index") @@ -578,8 +603,10 @@ MSG_DEF(JSMSG_CANT_DELETE_WINDOW_ELEMENT, 0, JSEXN_TYPEERR, "can't delete elements from a Window object") MSG_DEF(JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY, 1, JSEXN_TYPEERR, "can't delete property {0} from window's named properties object") MSG_DEF(JSMSG_CANT_PREVENT_EXTENSIONS, 0, JSEXN_TYPEERR, "can't prevent extensions on this proxy object") +MSG_DEF(JSMSG_CANT_DEFINE_WINDOW_NC, 0, JSEXN_TYPEERR, "can't define non-configurable property on WindowProxy") MSG_DEF(JSMSG_NO_NAMED_SETTER, 2, JSEXN_TYPEERR, "{0} doesn't have a named property setter for '{1}'") MSG_DEF(JSMSG_NO_INDEXED_SETTER, 2, JSEXN_TYPEERR, "{0} doesn't have an indexed property setter for '{1}'") +MSG_DEF(JSMSG_NOT_DATA_DESCRIPTOR, 2, JSEXN_TYPEERR, "can't define a getter/setter for element '{1}' of {0} object") // Super MSG_DEF(JSMSG_CANT_DELETE_SUPER, 0, JSEXN_REFERENCEERR, "invalid delete involving 'super'") @@ -594,6 +621,9 @@ MSG_DEF(JSMSG_MISSING_NAMESPACE_EXPORT, 0, JSEXN_SYNTAXERR, "export not found for namespace") MSG_DEF(JSMSG_MISSING_EXPORT, 1, JSEXN_SYNTAXERR, "local binding for export '{0}' not found") MSG_DEF(JSMSG_BAD_MODULE_STATUS, 0, JSEXN_INTERNALERR, "module record has unexpected status") +MSG_DEF(JSMSG_NO_DYNAMIC_IMPORT, 0, JSEXN_SYNTAXERR, "dynamic module import is not implemented") +MSG_DEF(JSMSG_DYNAMIC_IMPORT_FAILED, 0, JSEXN_TYPEERR, "error loading dynamically imported module") +MSG_DEF(JSMSG_BAD_MODULE_SPECIFIER, 1, JSEXN_TYPEERR, "error resolving module specifier '{0}'") // Promise MSG_DEF(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself.") @@ -614,12 +644,13 @@ // ReadableStream MSG_DEF(JSMSG_READABLESTREAM_UNDERLYINGSOURCE_TYPE_WRONG,0, JSEXN_RANGEERR,"'underlyingSource.type' must be \"bytes\" or undefined.") +MSG_DEF(JSMSG_READABLESTREAM_BYTES_TYPE_NOT_IMPLEMENTED, 0, JSEXN_RANGEERR,"'underlyingSource.type' must be \"bytes\" or undefined.") MSG_DEF(JSMSG_READABLESTREAM_INVALID_READER_MODE, 0, JSEXN_RANGEERR,"'mode' must be \"byob\" or undefined.") MSG_DEF(JSMSG_NUMBER_MUST_BE_FINITE_NON_NEGATIVE, 1, JSEXN_RANGEERR, "'{0}' must be a finite, non-negative number.") MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_BYTESWRITTEN, 0, JSEXN_RANGEERR, "'bytesWritten' exceeds remaining length.") MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_VIEW_SIZE, 0, JSEXN_RANGEERR, "view size does not match requested data.") MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_VIEW_OFFSET, 0, JSEXN_RANGEERR, "view offset does not match requested position.") -MSG_DEF(JSMSG_READABLESTREAM_NOT_LOCKED, 1, JSEXN_TYPEERR, "'{0}' may only be called on a locked stream.") +MSG_DEF(JSMSG_READABLESTREAM_LOCKED_METHOD, 1, JSEXN_TYPEERR, "'{0}' can't be called on a locked stream.") MSG_DEF(JSMSG_READABLESTREAM_LOCKED, 0, JSEXN_TYPEERR, "A Reader may only be created for an unlocked ReadableStream.") MSG_DEF(JSMSG_READABLESTREAM_NOT_BYTE_STREAM_CONTROLLER, 1, JSEXN_TYPEERR, "{0} requires a ReadableByteStreamController.") MSG_DEF(JSMSG_READABLESTREAM_NOT_DEFAULT_CONTROLLER, 1, JSEXN_TYPEERR, "{0} requires a ReadableStreamDefaultController.") @@ -638,7 +669,8 @@ MSG_DEF(JSMSG_READABLESTREAM_METHOD_NOT_IMPLEMENTED, 1, JSEXN_TYPEERR, "ReadableStream method {0} not yet implemented") // Other Stream-related -MSG_DEF(JSMSG_STREAM_INVALID_HIGHWATERMARK, 0, JSEXN_RANGEERR, "'highWaterMark' must be a non-negative, non-NaN number.") +MSG_DEF(JSMSG_STREAM_INVALID_HIGHWATERMARK, 0, JSEXN_RANGEERR, "'highWaterMark' must be a non-negative, non-NaN number.") +MSG_DEF(JSMSG_STREAM_CONSUME_ERROR, 0, JSEXN_TYPEERR, "error consuming stream body") // Response-related MSG_DEF(JSMSG_ERROR_CONSUMING_RESPONSE, 0, JSEXN_TYPEERR, "there was an error consuming the Response") @@ -647,3 +679,17 @@ MSG_DEF(JSMSG_BAD_RESPONSE_CORS_SAME_ORIGIN, 0, JSEXN_TYPEERR, "Response.type must be 'basic', 'cors' or 'default'") MSG_DEF(JSMSG_BAD_RESPONSE_STATUS, 0, JSEXN_TYPEERR, "Response does not have ok status") MSG_DEF(JSMSG_RESPONSE_ALREADY_CONSUMED, 0, JSEXN_TYPEERR, "Response already consumed") + +// BigInt +MSG_DEF(JSMSG_BIGINT_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert BigInt to number") +MSG_DEF(JSMSG_NUMBER_TO_BIGINT, 0, JSEXN_RANGEERR, "can't convert non-finite number to BigInt") +MSG_DEF(JSMSG_BIGINT_TOO_LARGE, 0, JSEXN_RANGEERR, "BigInt is too large to allocate") +MSG_DEF(JSMSG_BIGINT_DIVISION_BY_ZERO, 0, JSEXN_RANGEERR, "BigInt division by zero") +MSG_DEF(JSMSG_BIGINT_NEGATIVE_EXPONENT, 0, JSEXN_RANGEERR, "BigInt negative exponent") +MSG_DEF(JSMSG_BIGINT_INVALID_SYNTAX, 0, JSEXN_SYNTAXERR, "invalid BigInt syntax") +MSG_DEF(JSMSG_NOT_BIGINT, 0, JSEXN_TYPEERR, "not a BigInt") +MSG_DEF(JSMSG_BIGINT_NOT_SERIALIZABLE, 0, JSEXN_TYPEERR, "BigInt value can't be serialized in JSON") +MSG_DEF(JSMSG_SC_BIGINT_DISABLED, 0, JSEXN_ERR, "BigInt not cloned - feature disabled in receiver") + +// BinAST +MSG_DEF(JSMSG_BINAST, 1, JSEXN_SYNTAXERR, "BinAST Parsing Error: {0}") Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/AllocPolicy.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/AllocPolicy.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/AllocPolicy.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -17,44 +17,79 @@ #include "js/TypeDecls.h" #include "js/Utility.h" -extern JS_PUBLIC_API void JS_ReportOutOfMemory(JSContext* cx); +extern MOZ_COLD JS_PUBLIC_API void JS_ReportOutOfMemory(JSContext* cx); namespace js { enum class AllocFunction { Malloc, Calloc, Realloc }; -/* Policy for using system memory functions and doing no error reporting. */ -class SystemAllocPolicy { + +/* Base class allocation policies providing allocation methods. */ +class AllocPolicyBase { public: template + T* maybe_pod_arena_malloc(arena_id_t arenaId, size_t numElems) { + return js_pod_arena_malloc(arenaId, numElems); + } + template + T* maybe_pod_arena_calloc(arena_id_t arenaId, size_t numElems) { + return js_pod_arena_calloc(arenaId, numElems); + } + template + T* maybe_pod_arena_realloc(arena_id_t arenaId, T* p, size_t oldSize, size_t newSize) { + return js_pod_arena_realloc(arenaId, p, oldSize, newSize); + } + template + T* pod_arena_malloc(arena_id_t arenaId, size_t numElems) { + return maybe_pod_arena_malloc(arenaId, numElems); + } + template + T* pod_arena_calloc(arena_id_t arenaId, size_t numElems) { + return maybe_pod_arena_calloc(arenaId, numElems); + } + template + T* pod_arena_realloc(arena_id_t arenaId, T* p, size_t oldSize, size_t newSize) { + return maybe_pod_arena_realloc(arenaId, p, oldSize, newSize); + } + + template T* maybe_pod_malloc(size_t numElems) { - return js_pod_malloc(numElems); + return maybe_pod_arena_malloc(js::MallocArena, numElems); } template T* maybe_pod_calloc(size_t numElems) { - return js_pod_calloc(numElems); + return maybe_pod_arena_calloc(js::MallocArena, numElems); } template T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) { - return js_pod_realloc(p, oldSize, newSize); + return maybe_pod_arena_realloc(js::MallocArena, p, oldSize, newSize); } template T* pod_malloc(size_t numElems) { - return maybe_pod_malloc(numElems); + return pod_arena_malloc(js::MallocArena, numElems); } template T* pod_calloc(size_t numElems) { - return maybe_pod_calloc(numElems); + return pod_arena_calloc(js::MallocArena, numElems); } template T* pod_realloc(T* p, size_t oldSize, size_t newSize) { - return maybe_pod_realloc(p, oldSize, newSize); + return pod_arena_realloc(js::MallocArena, p, oldSize, newSize); + } + + template + void free_(T* p, size_t numElems = 0) { + js_free(p); } - void free_(void* p) { js_free(p); } +}; + +/* Policy for using system memory functions and doing no error reporting. */ +class SystemAllocPolicy : public AllocPolicyBase { + public: void reportAllocOverflow() const {} bool checkSimulatedOOM() const { return !js::oom::ShouldFailWithOOM(); } }; -JS_FRIEND_API void ReportOutOfMemory(JSContext* cx); +MOZ_COLD JS_FRIEND_API void ReportOutOfMemory(JSContext* cx); /* * Allocation policy that calls the system memory functions and reports errors @@ -65,69 +100,79 @@ * FIXME bug 647103 - rewrite this in terms of temporary allocation functions, * not the system ones. */ -class TempAllocPolicy { +class TempAllocPolicy : public AllocPolicyBase { JSContext* const cx_; /* * Non-inline helper to call JSRuntime::onOutOfMemory with minimal * code bloat. */ - JS_FRIEND_API void* onOutOfMemory(AllocFunction allocFunc, size_t nbytes, - void* reallocPtr = nullptr); + void* onOutOfMemory(arena_id_t arenaId, AllocFunction allocFunc, + size_t nbytes, void* reallocPtr = nullptr); template - T* onOutOfMemoryTyped(AllocFunction allocFunc, size_t numElems, - void* reallocPtr = nullptr) { + T* onOutOfMemoryTyped(arena_id_t arenaId, AllocFunction allocFunc, + size_t numElems, void* reallocPtr = nullptr) { size_t bytes; - if (MOZ_UNLIKELY(!CalculateAllocSize(numElems, &bytes))) return nullptr; - return static_cast(onOutOfMemory(allocFunc, bytes, reallocPtr)); + if (MOZ_UNLIKELY(!CalculateAllocSize(numElems, &bytes))) { + return nullptr; + } + return static_cast( + onOutOfMemory(arenaId, allocFunc, bytes, reallocPtr)); } public: MOZ_IMPLICIT TempAllocPolicy(JSContext* cx) : cx_(cx) {} template - T* maybe_pod_malloc(size_t numElems) { - return js_pod_malloc(numElems); + T* pod_arena_malloc(arena_id_t arenaId, size_t numElems) { + T* p = this->maybe_pod_arena_malloc(arenaId, numElems); + if (MOZ_UNLIKELY(!p)) { + p = onOutOfMemoryTyped(arenaId, AllocFunction::Malloc, numElems); + } + return p; } template - T* maybe_pod_calloc(size_t numElems) { - return js_pod_calloc(numElems); + T* pod_arena_calloc(arena_id_t arenaId, size_t numElems) { + T* p = this->maybe_pod_arena_calloc(arenaId, numElems); + if (MOZ_UNLIKELY(!p)) { + p = onOutOfMemoryTyped(arenaId, AllocFunction::Calloc, numElems); + } + return p; } template - T* maybe_pod_realloc(T* prior, size_t oldSize, size_t newSize) { - return js_pod_realloc(prior, oldSize, newSize); + T* pod_arena_realloc(arena_id_t arenaId, T* prior, size_t oldSize, size_t newSize) { + T* p2 = this->maybe_pod_arena_realloc(arenaId, prior, oldSize, newSize); + if (MOZ_UNLIKELY(!p2)) { + p2 = onOutOfMemoryTyped(arenaId, AllocFunction::Realloc, newSize, + prior); + } + return p2; } template T* pod_malloc(size_t numElems) { - T* p = maybe_pod_malloc(numElems); - if (MOZ_UNLIKELY(!p)) - p = onOutOfMemoryTyped(AllocFunction::Malloc, numElems); - return p; + return pod_arena_malloc(js::MallocArena, numElems); } template T* pod_calloc(size_t numElems) { - T* p = maybe_pod_calloc(numElems); - if (MOZ_UNLIKELY(!p)) - p = onOutOfMemoryTyped(AllocFunction::Calloc, numElems); - return p; + return pod_arena_calloc(js::MallocArena, numElems); } template T* pod_realloc(T* prior, size_t oldSize, size_t newSize) { - T* p2 = maybe_pod_realloc(prior, oldSize, newSize); - if (MOZ_UNLIKELY(!p2)) - p2 = onOutOfMemoryTyped(AllocFunction::Realloc, newSize, prior); - return p2; + return pod_arena_realloc(js::MallocArena, prior, oldSize, newSize); } - void free_(void* p) { js_free(p); } + template + void free_(T* p, size_t numElems = 0) { + js_free(p); + } - JS_FRIEND_API void reportAllocOverflow() const; + void reportAllocOverflow() const; bool checkSimulatedOOM() const { if (js::oom::ShouldFailWithOOM()) { @@ -139,45 +184,6 @@ } }; -/* - * Allocation policy that uses Zone::pod_malloc and friends, so that memory - * pressure is accounted for on the zone. This is suitable for memory associated - * with GC things allocated in the zone. - * - * Since it doesn't hold a JSContext (those may not live long enough), it can't - * report out-of-memory conditions itself; the caller must check for OOM and - * take the appropriate action. - * - * FIXME bug 647103 - replace these *AllocPolicy names. - */ -class ZoneAllocPolicy { - JS::Zone* const zone; - - public: - MOZ_IMPLICIT ZoneAllocPolicy(JS::Zone* z) : zone(z) {} - - // These methods are defined in gc/Zone.h. - template - inline T* maybe_pod_malloc(size_t numElems); - template - inline T* maybe_pod_calloc(size_t numElems); - template - inline T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize); - template - inline T* pod_malloc(size_t numElems); - template - inline T* pod_calloc(size_t numElems); - template - inline T* pod_realloc(T* p, size_t oldSize, size_t newSize); - - void free_(void* p) { js_free(p); } - void reportAllocOverflow() const {} - - MOZ_MUST_USE bool checkSimulatedOOM() const { - return !js::oom::ShouldFailWithOOM(); - } -}; - } /* namespace js */ #endif /* js_AllocPolicy_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ArrayBuffer.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ArrayBuffer.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ArrayBuffer.h @@ -0,0 +1,237 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* ArrayBuffer functionality. */ + +#ifndef js_ArrayBuffer_h +#define js_ArrayBuffer_h + +#include // size_t +#include // uint32_t + +#include "jstypes.h" // JS_PUBLIC_API + +#include "js/GCAPI.h" // JS::AutoRequireNoGC +#include "js/RootingAPI.h" // JS::Handle + +struct JS_PUBLIC_API JSContext; +class JS_PUBLIC_API JSObject; + +namespace JS { + +// CREATION + +/** + * Create a new ArrayBuffer with the given byte length. + */ +extern JS_PUBLIC_API JSObject* NewArrayBuffer(JSContext* cx, uint32_t nbytes); + +/** + * Create a new ArrayBuffer with the given |contents|, which may be null only + * if |nbytes == 0|. |contents| must be allocated compatible with deallocation + * by |JS_free|. + * + * If and only if an ArrayBuffer is successfully created and returned, + * ownership of |contents| is transferred to the new ArrayBuffer. + */ +extern JS_PUBLIC_API JSObject* NewArrayBufferWithContents(JSContext* cx, + size_t nbytes, + void* contents); + +using BufferContentsFreeFunc = void (*)(void* contents, void* userData); + +/** + * Create a new ArrayBuffer with the given contents. The contents must not be + * modified by any other code, internal or external. + * + * When the ArrayBuffer is ready to be disposed of, `freeFunc(contents, + * freeUserData)` will be called to release the ArrayBuffer's reference on the + * contents. + * + * `freeFunc()` must not call any JSAPI functions that could cause a garbage + * collection. + * + * The caller must keep the buffer alive until `freeFunc()` is called, or, if + * `freeFunc` is null, until the JSRuntime is destroyed. + * + * The caller must not access the buffer on other threads. The JS engine will + * not allow the buffer to be transferred to other threads. If you try to + * transfer an external ArrayBuffer to another thread, the data is copied to a + * new malloc buffer. `freeFunc()` must be threadsafe, and may be called from + * any thread. + * + * This allows ArrayBuffers to be used with embedder objects that use reference + * counting, for example. In that case the caller is responsible + * for incrementing the reference count before passing the contents to this + * function. This also allows using non-reference-counted contents that must be + * freed with some function other than free(). + */ +extern JS_PUBLIC_API JSObject* NewExternalArrayBuffer( + JSContext* cx, size_t nbytes, void* contents, + BufferContentsFreeFunc freeFunc, void* freeUserData = nullptr); + +/** + * Create a new ArrayBuffer with the given non-null |contents|. + * + * Ownership of |contents| remains with the caller: it isn't transferred to the + * returned ArrayBuffer. Callers of this function *must* ensure that they + * perform these two steps, in this order, to properly relinquish ownership of + * |contents|: + * + * 1. Call |JS::DetachArrayBuffer| on the buffer returned by this function. + * (|JS::DetachArrayBuffer| is generally fallible, but a call under these + * circumstances is guaranteed to succeed.) + * 2. |contents| may be deallocated or discarded consistent with the manner + * in which it was allocated. + * + * Do not simply allow the returned buffer to be garbage-collected before + * deallocating |contents|, because in general there is no way to know *when* + * an object is fully garbage-collected to the point where this would be safe. + */ +extern JS_PUBLIC_API JSObject* NewArrayBufferWithUserOwnedContents( + JSContext* cx, size_t nbytes, void* contents); + +/** + * Create a new mapped ArrayBuffer with the given memory mapped contents. It + * must be legal to free the contents pointer by unmapping it. On success, + * ownership is transferred to the new mapped ArrayBuffer. + */ +extern JS_PUBLIC_API JSObject* NewMappedArrayBufferWithContents(JSContext* cx, + size_t nbytes, + void* contents); + +/** + * Create memory mapped ArrayBuffer contents. + * Caller must take care of closing fd after calling this function. + */ +extern JS_PUBLIC_API void* CreateMappedArrayBufferContents(int fd, + size_t offset, + size_t length); + +/** + * Release the allocated resource of mapped ArrayBuffer contents before the + * object is created. + * If a new object has been created by JS::NewMappedArrayBufferWithContents() + * with this content, then JS::DetachArrayBuffer() should be used instead to + * release the resource used by the object. + */ +extern JS_PUBLIC_API void ReleaseMappedArrayBufferContents(void* contents, + size_t length); + +// TYPE TESTING + +/* + * Check whether obj supports the JS::GetArrayBuffer* APIs. Note that this may + * return false if a security wrapper is encountered that denies the unwrapping. + * If this test succeeds, then it is safe to call the various predicate and + * accessor JSAPI calls defined below. + */ +extern JS_PUBLIC_API bool IsArrayBufferObject(JSObject* obj); + +// PREDICATES + +/** + * Check whether the obj is a detached ArrayBufferObject. Note that this may + * return false if a security wrapper is encountered that denies the + * unwrapping. + */ +extern JS_PUBLIC_API bool IsDetachedArrayBufferObject(JSObject* obj); + +/** + * Check whether the obj is ArrayBufferObject and memory mapped. Note that this + * may return false if a security wrapper is encountered that denies the + * unwrapping. + */ +extern JS_PUBLIC_API bool IsMappedArrayBufferObject(JSObject* obj); + +/** + * Return true if the ArrayBuffer |obj| contains any data, i.e. it is not a + * detached ArrayBuffer. (ArrayBuffer.prototype is not an ArrayBuffer.) + * + * |obj| must have passed a JS::IsArrayBufferObject test, or somehow be known + * that it would pass such a test: it is an ArrayBuffer or a wrapper of an + * ArrayBuffer, and the unwrapping will succeed. + */ +extern JS_PUBLIC_API bool ArrayBufferHasData(JSObject* obj); + +// ACCESSORS + +extern JS_PUBLIC_API JSObject* UnwrapArrayBuffer(JSObject* obj); + +/** + * Attempt to unwrap |obj| as an ArrayBuffer. + * + * If |obj| *is* an ArrayBuffer, return it unwrapped and set |*length| and + * |*data| to weakly refer to the ArrayBuffer's contents. + * + * If |obj| isn't an ArrayBuffer, return nullptr and do not modify |*length| or + * |*data|. + */ +extern JS_PUBLIC_API JSObject* GetObjectAsArrayBuffer(JSObject* obj, + uint32_t* length, + uint8_t** data); + +/** + * Return the available byte length of an ArrayBuffer. + * + * |obj| must have passed a JS::IsArrayBufferObject test, or somehow be known + * that it would pass such a test: it is an ArrayBuffer or a wrapper of an + * ArrayBuffer, and the unwrapping will succeed. + */ +extern JS_PUBLIC_API uint32_t GetArrayBufferByteLength(JSObject* obj); + +// This one isn't inlined because there are a bunch of different ArrayBuffer +// classes that would have to be individually handled here. +// +// There is an isShared out argument for API consistency (eases use from DOM). +// It will always be set to false. +extern JS_PUBLIC_API void GetArrayBufferLengthAndData(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + uint8_t** data); + +/** + * Return a pointer to the start of the data referenced by a typed array. The + * data is still owned by the typed array, and should not be modified on + * another thread. Furthermore, the pointer can become invalid on GC (if the + * data is small and fits inside the array's GC header), so callers must take + * care not to hold on across anything that could GC. + * + * |obj| must have passed a JS::IsArrayBufferObject test, or somehow be known + * that it would pass such a test: it is an ArrayBuffer or a wrapper of an + * ArrayBuffer, and the unwrapping will succeed. + * + * |*isSharedMemory| is always set to false. The argument is present to + * simplify its use from code that also interacts with SharedArrayBuffer. + */ +extern JS_PUBLIC_API uint8_t* GetArrayBufferData(JSObject* obj, + bool* isSharedMemory, + const AutoRequireNoGC&); + +// MUTATORS + +/** + * Detach an ArrayBuffer, causing all associated views to no longer refer to + * the ArrayBuffer's original attached memory. + * + * This function throws only if it is provided a non-ArrayBuffer object or if + * the provided ArrayBuffer is a WASM-backed ArrayBuffer or an ArrayBuffer used + * in asm.js code. + */ +extern JS_PUBLIC_API bool DetachArrayBuffer(JSContext* cx, + Handle obj); + +/** + * Steal the contents of the given ArrayBuffer. The ArrayBuffer has its length + * set to 0 and its contents array cleared. The caller takes ownership of the + * return value and must free it or transfer ownership via + * JS::NewArrayBufferWithContents when done using it. + */ +extern JS_PUBLIC_API void* StealArrayBufferContents(JSContext* cx, + Handle obj); + +} // namespace JS + +#endif /* js_ArrayBuffer_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/BuildId.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/BuildId.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/BuildId.h @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Embedding-provided build ID information, used by SpiderMonkey to tag cached + * compilation data so that cached data can be reused when possible, or + * discarded and regenerated if necessary. + */ + +#ifndef js_BuildId_h +#define js_BuildId_h + +#include "mozilla/Attributes.h" // MOZ_MUST_USE + +#include "jstypes.h" // JS_PUBLIC_API + +#include "js/Vector.h" // js::Vector + +namespace js { + +class SystemAllocPolicy; + +} // namespace js + +namespace JS { + +/** Vector of characters used for holding build ids. */ +using BuildIdCharVector = js::Vector; + +/** + * Return the buildId (represented as a sequence of characters) associated with + * the currently-executing build. If the JS engine is embedded such that a + * single cache entry can be observed by different compiled versions of the JS + * engine, it is critical that the buildId shall change for each new build of + * the JS engine. + */ +using BuildIdOp = bool (*)(BuildIdCharVector* buildId); + +/** + * Embedder hook to set the buildId-generating function. + */ +extern JS_PUBLIC_API void SetProcessBuildIdOp(BuildIdOp buildIdOp); + +/** + * Some cached data is, in addition to being build-specific, CPU-specific: the + * cached data depends on CPU features like a particular level of SSE support. + * + * This function produces a buildId that includes: + * + * * the buildId defined by the embedder-provided BuildIdOp set by + * JS::SetProcessBuildIdOp, and + * * CPU feature information for the current CPU. + * + * Embedders may use this function to tag cached data whose validity depends + * on having consistent buildId *and* on the CPU supporting features identical + * to those in play when the cached data was computed. + */ +extern MOZ_MUST_USE JS_PUBLIC_API bool GetOptimizedEncodingBuildId( + BuildIdCharVector* buildId); + +} // namespace JS + +#endif /* js_BuildId_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CallArgs.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CallArgs.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CallArgs.h @@ -1,10 +1,12 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* + * [SMDOC] JS::CallArgs API + * * Helper classes encapsulating access to the callee, |this| value, arguments, * and argument count for a call/construct operation. * @@ -46,10 +48,7 @@ * * It's possible (albeit deprecated) to manually index into |vp| to access the * callee, |this|, and arguments of a function, and to set its return value. - * It's also possible to use the supported API of JS_CALLEE, JS_THIS, JS_ARGV, - * JS_RVAL, and JS_SET_RVAL to the same ends. - * - * But neither API has the error-handling or moving-GC correctness of CallArgs. + * This does not have the error-handling or moving-GC correctness of CallArgs. * New code should use CallArgs instead whenever possible. * * The eventual plan is to change JSNative to take |const CallArgs&| directly, @@ -74,7 +73,7 @@ #include "js/Value.h" /* Typedef for native functions called by the JS VM. */ -typedef bool (*JSNative)(JSContext* cx, unsigned argc, JS::Value* vp); +using JSNative = bool (*)(JSContext* cx, unsigned argc, JS::Value* vp); namespace JS { @@ -86,7 +85,8 @@ * Compute |this| for the |vp| inside a JSNative, either boxing primitives or * replacing with the global object as necessary. */ -extern JS_PUBLIC_API Value ComputeThis(JSContext* cx, JS::Value* vp); +extern JS_PUBLIC_API bool ComputeThis(JSContext* cx, JS::Value* vp, + MutableHandleObject thisObject); #ifdef JS_DEBUG extern JS_PUBLIC_API void CheckIsValidConstructible(const Value& v); @@ -158,10 +158,14 @@ // CALLING/CONSTRUCTING-DIFFERENTIATIONS bool isConstructing() const { - if (!argv_[-1].isMagic()) return false; + if (!argv_[-1].isMagic()) { + return false; + } #ifdef JS_DEBUG - if (!this->usedRval()) CheckIsValidConstructible(calleev()); + if (!this->usedRval()) { + CheckIsValidConstructible(calleev()); + } #endif return true; @@ -187,10 +191,13 @@ return HandleValue::fromMarkedLocation(&argv_[-1]); } - Value computeThis(JSContext* cx) const { - if (thisv().isObject()) return thisv(); + bool computeThis(JSContext* cx, MutableHandleObject thisObject) const { + if (thisv().isObject()) { + thisObject.set(&thisv().toObject()); + return true; + } - return ComputeThis(cx, base()); + return ComputeThis(cx, base(), thisObject); } // ARGUMENTS @@ -239,6 +246,13 @@ return MutableHandleValue::fromMarkedLocation(&argv_[-2]); } + /* + * Returns true if there are at least |required| arguments passed in. If + * false, it reports an error message on the context. + */ + JS_PUBLIC_API inline bool requireAtLeast(JSContext* cx, const char* fnname, + unsigned required) const; + public: // These methods are publicly exposed, but they are *not* to be used when // implementing a JSNative method and encapsulating access to |vp| within @@ -293,22 +307,40 @@ args.constructing_ = constructing; args.ignoresReturnValue_ = ignoresReturnValue; #ifdef DEBUG - MOZ_ASSERT(ValueIsNotGray(args.thisv())); - MOZ_ASSERT(ValueIsNotGray(args.calleev())); - for (unsigned i = 0; i < argc; ++i) MOZ_ASSERT(ValueIsNotGray(argv[i])); + AssertValueIsNotGray(args.thisv()); + AssertValueIsNotGray(args.calleev()); + for (unsigned i = 0; i < argc; ++i) { + AssertValueIsNotGray(argv[i]); + } #endif return args; } public: /* - * Returns true if there are at least |required| arguments passed in. If - * false, it reports an error message on the context. + * Helper for requireAtLeast to report the actual exception. Public + * so we can call it from CallArgsBase and not need multiple + * per-template instantiations of it. */ - JS_PUBLIC_API bool requireAtLeast(JSContext* cx, const char* fnname, - unsigned required) const; + static JS_PUBLIC_API void reportMoreArgsNeeded(JSContext* cx, + const char* fnname, + unsigned required, + unsigned actual); }; +namespace detail { +template +JS_PUBLIC_API inline bool CallArgsBase::requireAtLeast( + JSContext* cx, const char* fnname, unsigned required) const { + if (MOZ_LIKELY(required <= length())) { + return true; + } + + CallArgs::reportMoreArgsNeeded(cx, fnname, required, length()); + return false; +} +} // namespace detail + MOZ_ALWAYS_INLINE CallArgs CallArgsFromVp(unsigned argc, Value* vp) { return CallArgs::create(argc, vp + 2, vp[1].isMagic(JS_IS_CONSTRUCTING)); } @@ -325,47 +357,4 @@ } // namespace JS -/* - * Macros to hide interpreter stack layout details from a JSNative using its - * JS::Value* vp parameter. DO NOT USE THESE! Instead use JS::CallArgs and - * friends, above. These macros will be removed when we change JSNative to - * take a const JS::CallArgs&. - */ - -/* - * Return |this| if |this| is an object. Otherwise, return the global object - * if |this| is null or undefined, and finally return a boxed version of any - * other primitive. - * - * Note: if this method returns null, an error has occurred and must be - * propagated or caught. - */ -MOZ_ALWAYS_INLINE JS::Value JS_THIS(JSContext* cx, JS::Value* vp) { - return vp[1].isPrimitive() ? JS::detail::ComputeThis(cx, vp) : vp[1]; -} - -/* - * A note on JS_THIS_OBJECT: no equivalent method is part of the CallArgs - * interface, and we're unlikely to add one (functions shouldn't be implicitly - * exposing the global object to arbitrary callers). Continue using |vp| - * directly for this case, but be aware this API will eventually be replaced - * with a function that operates directly upon |args.thisv()|. - */ -#define JS_THIS_OBJECT(cx, vp) (JS_THIS(cx, vp).toObjectOrNull()) - -/* - * |this| is passed to functions in ES5 without change. Functions themselves - * do any post-processing they desire to box |this|, compute the global object, - * &c. This macro retrieves a function's unboxed |this| value. - * - * This macro must not be used in conjunction with JS_THIS or JS_THIS_OBJECT, - * or vice versa. Either use the provided this value with this macro, or - * compute the boxed |this| value using those. JS_THIS_VALUE must not be used - * if the function is being called as a constructor. - * - * But: DO NOT USE THIS! Instead use JS::CallArgs::thisv(), above. - * - */ -#define JS_THIS_VALUE(cx, vp) ((vp)[1]) - #endif /* js_CallArgs_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CallNonGenericMethod.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CallNonGenericMethod.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CallNonGenericMethod.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -48,8 +48,9 @@ // static bool // IsAnswerObject(const Value& v) // { -// if (!v.isObject()) +// if (!v.isObject()) { // return false; +// } // return JS_GetClass(&v.toObject()) == &AnswerClass; // } // @@ -98,7 +99,9 @@ MOZ_ALWAYS_INLINE bool CallNonGenericMethod(JSContext* cx, const CallArgs& args) { HandleValue thisv = args.thisv(); - if (Test(thisv)) return Impl(cx, args); + if (Test(thisv)) { + return Impl(cx, args); + } return detail::CallMethodIfWrapped(cx, Test, Impl, args); } @@ -108,7 +111,9 @@ NativeImpl Impl, const CallArgs& args) { HandleValue thisv = args.thisv(); - if (Test(thisv)) return Impl(cx, args); + if (Test(thisv)) { + return Impl(cx, args); + } return detail::CallMethodIfWrapped(cx, Test, Impl, args); } Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CharacterEncoding.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CharacterEncoding.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CharacterEncoding.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -75,6 +75,28 @@ UTF8Chars(const char* aBytes, size_t aLength) : Base(reinterpret_cast(const_cast(aBytes)), aLength) {} + UTF8Chars(mozilla::Utf8Unit* aUnits, size_t aLength) + : UTF8Chars(reinterpret_cast(aUnits), aLength) {} + UTF8Chars(const mozilla::Utf8Unit* aUnits, size_t aLength) + : UTF8Chars(reinterpret_cast(aUnits), aLength) {} +}; + +/* + * Similar to UTF8Chars, but contains WTF-8. + * https://simonsapin.github.io/wtf-8/ + */ +class WTF8Chars : public mozilla::Range { + typedef mozilla::Range Base; + + public: + using CharT = unsigned char; + + WTF8Chars() : Base() {} + WTF8Chars(char* aBytes, size_t aLength) + : Base(reinterpret_cast(aBytes), aLength) {} + WTF8Chars(const char* aBytes, size_t aLength) + : Base(reinterpret_cast(const_cast(aBytes)), + aLength) {} }; /* @@ -97,6 +119,9 @@ MOZ_ASSERT(aBytes[aLength] == '\0'); } + UTF8CharsZ(mozilla::Utf8Unit* aUnits, size_t aLength) + : UTF8CharsZ(reinterpret_cast(aUnits), aLength) {} + using Base::operator=; char* c_str() { return reinterpret_cast(get()); } @@ -106,7 +131,7 @@ * A wrapper for a "const char*" that is encoded using UTF-8. * This class does not manage ownership of the data; that is left * to others. This differs from UTF8CharsZ in that the chars are - * const and it allows assignment. + * const and it disallows assignment. */ class JS_PUBLIC_API ConstUTF8CharsZ { const char* data_; @@ -222,25 +247,36 @@ * - On success, returns a malloc'd TwoByteCharsZ, and updates |outlen| to hold * its length; the length value excludes the trailing null. */ -extern JS_PUBLIC_API TwoByteCharsZ UTF8CharsToNewTwoByteCharsZ( - JSContext* cx, const UTF8Chars utf8, size_t* outlen); +extern JS_PUBLIC_API TwoByteCharsZ +UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen, + arena_id_t destArenaId); + +/* + * Like UTF8CharsToNewTwoByteCharsZ, but for WTF8Chars. + */ +extern JS_PUBLIC_API TwoByteCharsZ +WTF8CharsToNewTwoByteCharsZ(JSContext* cx, const WTF8Chars wtf8, size_t* outlen, + arena_id_t destArenaId); /* * Like UTF8CharsToNewTwoByteCharsZ, but for ConstUTF8CharsZ. */ -extern JS_PUBLIC_API TwoByteCharsZ UTF8CharsToNewTwoByteCharsZ( - JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen); +extern JS_PUBLIC_API TwoByteCharsZ +UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, + size_t* outlen, arena_id_t destArenaId); /* * The same as UTF8CharsToNewTwoByteCharsZ(), except that any malformed UTF-8 * characters will be replaced by \uFFFD. No exception will be thrown for * malformed UTF-8 input. */ -extern JS_PUBLIC_API TwoByteCharsZ LossyUTF8CharsToNewTwoByteCharsZ( - JSContext* cx, const UTF8Chars utf8, size_t* outlen); - -extern JS_PUBLIC_API TwoByteCharsZ LossyUTF8CharsToNewTwoByteCharsZ( - JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen); +extern JS_PUBLIC_API TwoByteCharsZ +LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, + size_t* outlen, arena_id_t destArenaId); + +extern JS_PUBLIC_API TwoByteCharsZ +LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, + size_t* outlen, arena_id_t destArenaId); /* * Returns the length of the char buffer required to encode |s| as UTF8. @@ -285,15 +321,17 @@ * Latin1CharsZ() on failure. */ extern JS_PUBLIC_API Latin1CharsZ -UTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); +UTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen, + arena_id_t destArenaId); /* * Return a null-terminated Latin-1 string copied from the input string, * storing its length (excluding null terminator) in |*outlen|. Non-Latin-1 * codepoints are replaced by '?'. Returns Latin1CharsZ() on failure. */ -extern JS_PUBLIC_API Latin1CharsZ LossyUTF8CharsToNewLatin1CharsZ( - JSContext* cx, const UTF8Chars utf8, size_t* outlen); +extern JS_PUBLIC_API Latin1CharsZ +LossyUTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, + size_t* outlen, arena_id_t destArenaId); /* * Returns true if all characters in the given null-terminated string are @@ -301,15 +339,65 @@ */ extern JS_PUBLIC_API bool StringIsASCII(const char* s); -/* - * Returns true if the given length-delimited string is a valid UTF-8 string, - * false otherwise. - */ -extern JS_PUBLIC_API bool StringIsUTF8(const uint8_t* s, uint32_t length); - } // namespace JS inline void JS_free(JS::Latin1CharsZ& ptr) { js_free((void*)ptr.get()); } inline void JS_free(JS::UTF8CharsZ& ptr) { js_free((void*)ptr.get()); } +/** + * DEPRECATED + * + * Allocate memory sufficient to contain the characters of |str| truncated to + * Latin-1 and a trailing null terminator, fill the memory with the characters + * interpreted in that manner plus the null terminator, and return a pointer to + * the memory. + * + * This function *loses information* when it copies the characters of |str| if + * |str| contains code units greater than 0xFF. Additionally, users that + * depend on null-termination will misinterpret the copied characters if |str| + * contains any nulls. Avoid using this function if possible, because it will + * eventually be removed. + */ +extern JS_PUBLIC_API JS::UniqueChars JS_EncodeStringToLatin1(JSContext* cx, + JSString* str); + +/** + * DEPRECATED + * + * Same behavior as JS_EncodeStringToLatin1(), but encode into a UTF-8 string. + * + * This function *loses information* when it copies the characters of |str| if + * |str| contains invalid UTF-16: U+FFFD REPLACEMENT CHARACTER will be copied + * instead. + * + * The returned string is also subject to misinterpretation if |str| contains + * any nulls (which are faithfully transcribed into the returned string, but + * which will implicitly truncate the string if it's passed to functions that + * expect null-terminated strings). + * + * Avoid using this function if possible, because we'll remove it once we can + * devise a better API for the task. + */ +extern JS_PUBLIC_API JS::UniqueChars JS_EncodeStringToUTF8( + JSContext* cx, JS::Handle str); + +/** + * DEPRECATED + * + * Same behavior as JS_EncodeStringToLatin1(), but encode into an ASCII string. + * + * This function asserts in debug mode that the input string contains only + * ASCII characters. + * + * The returned string is also subject to misinterpretation if |str| contains + * any nulls (which are faithfully transcribed into the returned string, but + * which will implicitly truncate the string if it's passed to functions that + * expect null-terminated strings). + * + * Avoid using this function if possible, because we'll remove it once we can + * devise a better API for the task. + */ +extern JS_PUBLIC_API JS::UniqueChars JS_EncodeStringToASCII(JSContext* cx, + JSString* str); + #endif /* js_CharacterEncoding_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Class.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Class.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Class.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -9,6 +9,8 @@ #ifndef js_Class_h #define js_Class_h +#include "mozilla/Attributes.h" + #include "jstypes.h" #include "js/CallArgs.h" @@ -23,7 +25,7 @@ */ struct JSAtomState; -struct JSFreeOp; +struct JS_PUBLIC_API JSFreeOp; struct JSFunctionSpec; namespace js { @@ -95,14 +97,16 @@ * Typical usage: * * ObjectOpResult result; - * if (!DefineProperty(cx, obj, id, ..., result)) + * if (!DefineProperty(cx, obj, id, ..., result)) { * return false; - * if (!result) + * } + * if (!result) { * return result.reportError(cx, obj, id); + * } * * Users don't have to call `result.report()`; another possible ending is: * - * argv.rval().setBoolean(bool(result)); + * argv.rval().setBoolean(result.reallyOk()); * return true; */ class ObjectOpResult { @@ -121,16 +125,25 @@ public: enum SpecialCodes : uintptr_t { OkCode = 0, Uninitialized = uintptr_t(-1) }; + static const uintptr_t SoftFailBit = uintptr_t(1) + << (sizeof(uintptr_t) * 8 - 1); + ObjectOpResult() : code_(Uninitialized) {} - /* Return true if succeed() was called. */ + /* Return true if succeed() or failSoft() was called. */ bool ok() const { MOZ_ASSERT(code_ != Uninitialized); - return code_ == OkCode; + return code_ == OkCode || (code_ & SoftFailBit); } explicit operator bool() const { return ok(); } + /* Return true if succeed() was called. */ + bool reallyOk() const { + MOZ_ASSERT(code_ != Uninitialized); + return code_ == OkCode; + } + /* Set this ObjectOpResult to true and return true. */ bool succeed() { code_ = OkCode; @@ -142,18 +155,35 @@ * * Always returns true, as a convenience. Typical usage will be: * - * if (funny condition) + * if (funny condition) { * return result.fail(JSMSG_CANT_DO_THE_THINGS); + * } * * The true return value indicates that no exception is pending, and it * would be OK to ignore the failure and continue. */ bool fail(uint32_t msg) { MOZ_ASSERT(msg != OkCode); + MOZ_ASSERT((msg & SoftFailBit) == 0); code_ = msg; return true; } + /* + * DEPRECATED: This is a non-standard compatibility hack. + * + * Set this ObjectOpResult to true, but remembers an error code. + * This is used for situations where we really want to fail, + * but can't for legacy reasons. + * + * Always returns true, as a convenience. + */ + bool failSoft(uint32_t msg) { + // The msg code is currently never extracted again. + code_ = msg | SoftFailBit; + return true; + } + JS_PUBLIC_API bool failCantRedefineProp(); JS_PUBLIC_API bool failReadOnly(); JS_PUBLIC_API bool failGetterOnly(); @@ -167,6 +197,10 @@ JS_PUBLIC_API bool failCantSetProto(); JS_PUBLIC_API bool failNoNamedSetter(); JS_PUBLIC_API bool failNoIndexedSetter(); + JS_PUBLIC_API bool failNotDataDescriptor(); + + // Careful: This case has special handling in Object.defineProperty. + JS_PUBLIC_API bool failCantDefineWindowNonConfigurable(); uint32_t failureCode() const { MOZ_ASSERT(!ok()); @@ -189,7 +223,9 @@ */ bool checkStrictErrorOrWarning(JSContext* cx, HandleObject obj, HandleId id, bool strict) { - if (ok()) return true; + if (ok()) { + return true; + } return reportStrictErrorOrWarning(cx, obj, id, strict); } @@ -383,7 +419,7 @@ * add enumerable properties. */ typedef bool (*JSNewEnumerateOp)(JSContext* cx, JS::HandleObject obj, - JS::AutoIdVector& properties, + JS::MutableHandleIdVector properties, bool enumerableOnly); /** @@ -457,8 +493,6 @@ */ typedef void (*JSTraceOp)(JSTracer* trc, JSObject* obj); -typedef JSObject* (*JSWeakmapKeyDelegateOp)(JSObject* obj); - typedef size_t (*JSObjectMovedOp)(JSObject* obj, JSObject* old); /* js::Class operation signatures. */ @@ -587,12 +621,7 @@ cOps->trace(trc, obj); \ } -// XXX: MOZ_NONHEAP_CLASS allows objects to be created statically or on the -// stack. We actually want to ban stack objects too, but that's currently not -// possible. So we define JS_STATIC_CLASS to make the intention clearer. -#define JS_STATIC_CLASS MOZ_NONHEAP_CLASS - -struct JS_STATIC_CLASS ClassOps { +struct MOZ_STATIC_CLASS ClassOps { /* Function pointer members (may be null). */ JSAddPropertyOp addProperty; JSDeletePropertyOp delProperty; @@ -619,7 +648,7 @@ const size_t JSCLASS_CACHED_PROTO_WIDTH = 6; -struct JS_STATIC_CLASS ClassSpec { +struct MOZ_STATIC_CLASS ClassSpec { ClassObjectCreationOp createConstructor; ClassObjectCreationOp createPrototype; const JSFunctionSpec* constructorFunctions; @@ -642,7 +671,9 @@ static_assert(JSProto_Null == 0, "zeroed key must be null"); // Default: Inherit from Object. - if (!(flags & ProtoKeyMask)) return JSProto_Object; + if (!(flags & ProtoKeyMask)) { + return JSProto_Object; + } return JSProtoKey(flags & ProtoKeyMask); } @@ -653,20 +684,7 @@ } }; -struct JS_STATIC_CLASS ClassExtension { - /** - * If an object is used as a key in a weakmap, it may be desirable for the - * garbage collector to keep that object around longer than it otherwise - * would. A common case is when the key is a wrapper around an object in - * another compartment, and we want to avoid collecting the wrapper (and - * removing the weakmap entry) as long as the wrapped object is alive. In - * that case, the wrapped object is returned by the wrapper's - * weakmapKeyDelegateOp hook. As long as the wrapper is used as a weakmap - * key, it will not be collected (and remain in the weakmap) until the - * wrapped object is collected. - */ - JSWeakmapKeyDelegateOp weakmapKeyDelegateOp; - +struct MOZ_STATIC_CLASS ClassExtension { /** * Optional hook called when an object is moved by generational or * compacting GC. @@ -691,7 +709,7 @@ #define JS_NULL_CLASS_SPEC nullptr #define JS_NULL_CLASS_EXT nullptr -struct JS_STATIC_CLASS ObjectOps { +struct MOZ_STATIC_CLASS ObjectOps { LookupPropertyOp lookupProperty; DefinePropertyOp defineProperty; HasPropertyOp hasProperty; @@ -711,7 +729,7 @@ typedef void (*JSClassInternal)(); -struct JS_STATIC_CLASS JSClassOps { +struct MOZ_STATIC_CLASS JSClassOps { /* Function pointer members (may be null). */ JSAddPropertyOp addProperty; JSDeletePropertyOp delProperty; @@ -783,8 +801,8 @@ #define JSCLASS_HIGH_FLAGS_SHIFT \ (JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH) -static const uint32_t JSCLASS_IS_ANONYMOUS = 1 - << (JSCLASS_HIGH_FLAGS_SHIFT + 0); +static const uint32_t JSCLASS_INTERNAL_FLAG1 = + 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 0); static const uint32_t JSCLASS_IS_GLOBAL = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 1); static const uint32_t JSCLASS_INTERNAL_FLAG2 = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 2); @@ -850,7 +868,7 @@ namespace js { -struct JS_STATIC_CLASS Class { +struct MOZ_STATIC_CLASS Class { JS_CLASS_MEMBERS(js::ClassOps, FreeOp); const ClassSpec* spec; const ClassExtension* ext; @@ -919,9 +937,6 @@ return spec ? spec->finishInit : nullptr; } - JSWeakmapKeyDelegateOp extWeakmapKeyDelegateOp() const { - return ext ? ext->weakmapKeyDelegateOp : nullptr; - } JSObjectMovedOp extObjectMovedOp() const { return ext ? ext->objectMovedOp : nullptr; } @@ -1023,6 +1038,7 @@ SetIterator, Arguments, Error, + BigInt, /** None of the above. */ Other Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CompilationAndEvaluation.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CompilationAndEvaluation.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CompilationAndEvaluation.h @@ -0,0 +1,312 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Functions for compiling and evaluating scripts. */ + +#ifndef js_CompilationAndEvaluation_h +#define js_CompilationAndEvaluation_h + +#include "mozilla/Utf8.h" // mozilla::Utf8Unit + +#include // size_t +#include // FILE + +#include "jstypes.h" // JS_PUBLIC_API + +#include "js/CompileOptions.h" // JS::CompileOptions, JS::ReadOnlyCompileOptions +#include "js/RootingAPI.h" // JS::Handle, JS::MutableHandle +#include "js/Value.h" // JS::Value and specializations of JS::*Handle-related types + +struct JS_PUBLIC_API JSContext; +class JS_PUBLIC_API JSFunction; +class JS_PUBLIC_API JSObject; +class JS_PUBLIC_API JSScript; + +namespace JS { + +template +class SourceText; + +} // namespace JS + +/** + * Given a buffer, return false if the buffer might become a valid JavaScript + * script with the addition of more lines, or true if the validity of such a + * script is conclusively known (because it's the prefix of a valid script -- + * and possibly the entirety of such a script). + * + * The intent of this function is to enable interactive compilation: accumulate + * lines in a buffer until JS_Utf8BufferIsCompilableUnit is true, then pass it + * to the compiler. + * + * The provided buffer is interpreted as UTF-8 data. An error is reported if + * a UTF-8 encoding error is encountered. + */ +extern JS_PUBLIC_API bool JS_Utf8BufferIsCompilableUnit( + JSContext* cx, JS::Handle obj, const char* utf8, size_t length); + +/* + * NB: JS_ExecuteScript and the JS::Evaluate APIs come in two flavors: either + * they use the global as the scope, or they take a HandleValueVector of + * objects to use as the scope chain. In the former case, the global is also + * used as the "this" keyword value and the variables object (ECMA parlance for + * where 'var' and 'function' bind names) of the execution context for script. + * In the latter case, the first object in the provided list is used, unless the + * list is empty, in which case the global is used. + * + * Why a runtime option? The alternative is to add APIs duplicating those + * for the other value of flags, and that doesn't seem worth the code bloat + * cost. Such new entry points would probably have less obvious names, too, so + * would not tend to be used. The ContextOptionsRef adjustment, OTOH, can be + * more easily hacked into existing code that does not depend on the bug; such + * code can continue to use the familiar JS::Evaluate, etc., entry points. + */ + +/** + * Evaluate a script in the scope of the current global of cx. + */ +extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx, + JS::Handle script, + JS::MutableHandle rval); + +extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx, + JS::Handle script); + +/** + * As above, but providing an explicit scope chain. envChain must not include + * the global object on it; that's implicit. It needs to contain the other + * objects that should end up on the script's scope chain. + */ +extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx, + JS::HandleObjectVector envChain, + JS::Handle script, + JS::MutableHandle rval); + +extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx, + JS::HandleObjectVector envChain, + JS::Handle script); + +namespace JS { + +/** + * Like the above, but handles a cross-compartment script. If the script is + * cross-compartment, it is cloned into the current compartment before + * executing. + */ +extern JS_PUBLIC_API bool CloneAndExecuteScript(JSContext* cx, + Handle script, + MutableHandle rval); + +/** + * Like CloneAndExecuteScript above, but allows executing under a non-syntactic + * environment chain. + */ +extern JS_PUBLIC_API bool CloneAndExecuteScript(JSContext* cx, + HandleObjectVector envChain, + Handle script, + MutableHandle rval); + +/** + * Evaluate the given source buffer in the scope of the current global of cx, + * and return the completion value in |rval|. + */ +extern JS_PUBLIC_API bool Evaluate(JSContext* cx, + const ReadOnlyCompileOptions& options, + SourceText& srcBuf, + MutableHandle rval); + +/** + * As above, but providing an explicit scope chain. envChain must not include + * the global object on it; that's implicit. It needs to contain the other + * objects that should end up on the script's scope chain. + */ +extern JS_PUBLIC_API bool Evaluate(JSContext* cx, HandleObjectVector envChain, + const ReadOnlyCompileOptions& options, + SourceText& srcBuf, + MutableHandle rval); + +/** + * Evaluate the provided UTF-8 data in the scope of the current global of |cx|, + * and return the completion value in |rval|. If the data contains invalid + * UTF-8, an error is reported. + */ +extern JS_PUBLIC_API bool Evaluate(JSContext* cx, + const ReadOnlyCompileOptions& options, + SourceText& srcBuf, + MutableHandle rval); + +/** + * Evaluate the provided UTF-8 data in the scope of the current global of |cx|, + * and return the completion value in |rval|. If the data contains invalid + * UTF-8, an error is reported. + * + * The "DontInflate" suffix and (semantically unobservable) don't-inflate + * characteristic are temporary while bugs in UTF-8 compilation are ironed out. + * In the long term |JS::Evaluate| for UTF-8 will just never inflate, and this + * separate function will die. + * + * NOTE: UTF-8 compilation is currently experimental, and it's possible it has + * as-yet-undiscovered bugs that the UTF-16 compilation functions do not + * have. Use only if you're willing to take a risk! + */ +extern JS_PUBLIC_API bool EvaluateDontInflate( + JSContext* cx, const ReadOnlyCompileOptions& options, + SourceText& srcBuf, MutableHandle rval); + +/** + * Evaluate the UTF-8 contents of the file at the given path, and return the + * completion value in |rval|. (The path itself is in the system encoding, not + * [necessarily] UTF-8.) If the contents contain any malformed UTF-8, an error + * is reported. + */ +extern JS_PUBLIC_API bool EvaluateUtf8Path( + JSContext* cx, const ReadOnlyCompileOptions& options, const char* filename, + MutableHandle rval); + +/** + * Compile the provided script using the given options. Return the script on + * success, or return null on failure (usually with an error reported). + */ +extern JS_PUBLIC_API JSScript* Compile(JSContext* cx, + const ReadOnlyCompileOptions& options, + SourceText& srcBuf); + +/** + * Compile the provided script using the given options. Return the script on + * success, or return null on failure (usually with an error reported). + */ +extern JS_PUBLIC_API JSScript* Compile(JSContext* cx, + const ReadOnlyCompileOptions& options, + SourceText& srcBuf); + +/** + * Identical to |JS::Compile| for UTF-8, except this function directly parses + * its UTF-8 input without inflating it to UTF-16 and parsing that. + * + * The "DontInflate" suffix and (semantically unobservable) don't-inflate + * characteristic are temporary while bugs in UTF-8 compilation are ironed out. + * In the long term |JS::Compile| for UTF-8 will just never inflate, and this + * separate function will die. + * + * NOTE: UTF-8 compilation is currently experimental, and it's possible it has + * as-yet-undiscovered bugs that the UTF-16 compilation functions do not + * have. Use only if you're willing to take a risk! + */ +extern JS_PUBLIC_API JSScript* CompileDontInflate( + JSContext* cx, const ReadOnlyCompileOptions& options, + SourceText& srcBuf); + +/** + * Compile the UTF-8 contents of the given file into a script. It is an error + * if the file contains invalid UTF-8. Return the script on success, or return + * null on failure (usually with an error reported). + */ +extern JS_PUBLIC_API JSScript* CompileUtf8File( + JSContext* cx, const ReadOnlyCompileOptions& options, FILE* file); + +/** + * Compile the UTF-8 contents of the given file into a script. It is an error + * if the file contains invalid UTF-8. Return the script on success, or return + * null on failure (usually with an error reported). + * + * NOTE: UTF-8 compilation is currently experimental, and it's possible it has + * as-yet-undiscovered bugs not present in |JS::CompileUtf8File| that + * first inflates to UTF-16. Use only if you're willing to take a risk! + */ +extern JS_PUBLIC_API JSScript* CompileUtf8FileDontInflate( + JSContext* cx, const ReadOnlyCompileOptions& options, FILE* file); + +/** + * Compile the UTF-8 contents of the file at the given path into a script. + * (The path itself is in the system encoding, not [necessarily] UTF-8.) It + * is an error if the file's contents are invalid UTF-8. Return the script on + * success, or return null on failure (usually with an error reported). + */ +extern JS_PUBLIC_API JSScript* CompileUtf8Path( + JSContext* cx, const ReadOnlyCompileOptions& options, const char* filename); + +extern JS_PUBLIC_API JSScript* CompileForNonSyntacticScope( + JSContext* cx, const ReadOnlyCompileOptions& options, + SourceText& srcBuf); + +/** + * Compile the provided UTF-8 data into a script in a non-syntactic scope. It + * is an error if the data contains invalid UTF-8. Return the script on + * success, or return null on failure (usually with an error reported). + */ +extern JS_PUBLIC_API JSScript* CompileForNonSyntacticScope( + JSContext* cx, const ReadOnlyCompileOptions& options, + SourceText& srcBuf); + +/** + * Compile the provided UTF-8 data into a script in a non-syntactic scope. It + * is an error if the data contains invalid UTF-8. Return the script on + * success, or return null on failure (usually with an error reported). + * + * The "DontInflate" suffix and (semantically unobservable) don't-inflate + * characteristic are temporary while bugs in UTF-8 compilation are ironed out. + * In the long term |JS::CompileForNonSyntacticScope| for UTF-8 will just never + * inflate, and this separate function will die. + * + * NOTE: UTF-8 compilation is currently experimental, and it's possible it has + * as-yet-undiscovered bugs that the UTF-16 compilation functions do not + * have. Use only if you're willing to take a risk! + */ +extern JS_PUBLIC_API JSScript* CompileForNonSyntacticScopeDontInflate( + JSContext* cx, const ReadOnlyCompileOptions& options, + SourceText& srcBuf); + +/** + * Compile a function with envChain plus the global as its scope chain. + * envChain must contain objects in the current compartment of cx. The actual + * scope chain used for the function will consist of With wrappers for those + * objects, followed by the current global of the compartment cx is in. This + * global must not be explicitly included in the scope chain. + */ +extern JS_PUBLIC_API JSFunction* CompileFunction( + JSContext* cx, HandleObjectVector envChain, + const ReadOnlyCompileOptions& options, const char* name, unsigned nargs, + const char* const* argnames, SourceText& srcBuf); + +/** + * Compile a function with envChain plus the global as its scope chain. + * envChain must contain objects in the current compartment of cx. The actual + * scope chain used for the function will consist of With wrappers for those + * objects, followed by the current global of the compartment cx is in. This + * global must not be explicitly included in the scope chain. + */ +extern JS_PUBLIC_API JSFunction* CompileFunction( + JSContext* cx, HandleObjectVector envChain, + const ReadOnlyCompileOptions& options, const char* name, unsigned nargs, + const char* const* argnames, SourceText& srcBuf); + +/** + * Identical to the CompileFunction overload above for UTF-8, but with + * Rust-friendly ergonomics. + */ +extern JS_PUBLIC_API JSFunction* CompileFunctionUtf8( + JSContext* cx, HandleObjectVector envChain, + const ReadOnlyCompileOptions& options, const char* name, unsigned nargs, + const char* const* argnames, const char* utf8, size_t length); + +/* + * Associate an element wrapper and attribute name with a previously compiled + * script, for debugging purposes. Calling this function is optional, but should + * be done before script execution if it is required. + */ +extern JS_PUBLIC_API bool InitScriptSourceElement( + JSContext* cx, Handle script, Handle element, + Handle elementAttrName = nullptr); + +/* + * For a script compiled with the hideScriptFromDebugger option, expose the + * script to the debugger by calling the debugger's onNewScript hook. + */ +extern JS_PUBLIC_API void ExposeScriptToDebugger(JSContext* cx, + Handle script); + +} /* namespace JS */ + +#endif /* js_CompilationAndEvaluation_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CompileOptions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CompileOptions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CompileOptions.h @@ -0,0 +1,557 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Options for JavaScript compilation. + * + * In the most common use case, a CompileOptions instance is allocated on the + * stack, and holds non-owning references to non-POD option values: strings, + * principals, objects, and so on. The code declaring the instance guarantees + * that such option values will outlive the CompileOptions itself: objects are + * otherwise rooted, principals have had their reference counts bumped, and + * strings won't be freed until the CompileOptions goes out of scope. In this + * situation, CompileOptions only refers to things others own, so it can be + * lightweight. + * + * In some cases, however, we need to hold compilation options with a + * non-stack-like lifetime. For example, JS::CompileOffThread needs to save + * compilation options where a worker thread can find them, then return + * immediately. The worker thread will come along at some later point, and use + * the options. + * + * The compiler itself just needs to be able to access a collection of options; + * it doesn't care who owns them, or what's keeping them alive. It does its + * own addrefs/copies/tracing/etc. + * + * Furthermore, in some cases compile options are propagated from one entity to + * another (e.g. from a script to a function defined in that script). This + * involves copying over some, but not all, of the options. + * + * So we have a class hierarchy that reflects these four use cases: + * + * - TransitiveCompileOptions is the common base class, representing options + * that should get propagated from a script to functions defined in that + * script. This class is abstract and is only ever used as a subclass. + * + * - ReadOnlyCompileOptions is the only subclass of TransitiveCompileOptions, + * representing a full set of compile options. It can be used by code that + * simply needs to access options set elsewhere, like the compiler. This + * class too is abstract and is only ever used as a subclass. + * + * - The usual CompileOptions class must be stack-allocated, and holds + * non-owning references to the filename, element, and so on. It's derived + * from ReadOnlyCompileOptions, so the compiler can use it. + * + * - OwningCompileOptions roots / copies / reference counts of all its values, + * and unroots / frees / releases them when it is destructed. It too is + * derived from ReadOnlyCompileOptions, so the compiler accepts it. + */ + +#ifndef js_CompileOptions_h +#define js_CompileOptions_h + +#include "mozilla/Attributes.h" // MOZ_MUST_USE +#include "mozilla/MemoryReporting.h" // mozilla::MallocSizeOf + +#include // size_t +#include // uint8_t + +#include "jstypes.h" // JS_PUBLIC_API + +#include "js/RootingAPI.h" // JS::PersistentRooted, JS::Rooted + +struct JS_PUBLIC_API JSContext; +class JS_PUBLIC_API JSObject; +class JS_PUBLIC_API JSScript; +class JS_PUBLIC_API JSString; + +namespace JS { + +enum class AsmJSOption : uint8_t { + Enabled, + Disabled, + DisabledByDebugger, +}; + +/** + * The common base class for the CompileOptions hierarchy. + * + * Use this in code that needs to propagate compile options from one + * compilation unit to another. + */ +class JS_PUBLIC_API TransitiveCompileOptions { + protected: + /** + * The Web Platform allows scripts to be loaded from arbitrary cross-origin + * sources. This allows an attack by which a malicious website loads a + * sensitive file (say, a bank statement) cross-origin (using the user's + * cookies), and sniffs the generated syntax errors (via a window.onerror + * handler) for juicy morsels of its contents. + * + * To counter this attack, HTML5 specifies that script errors should be + * sanitized ("muted") when the script is not same-origin with the global + * for which it is loaded. Callers should set this flag for cross-origin + * scripts, and it will be propagated appropriately to child scripts and + * passed back in JSErrorReports. + */ + bool mutedErrors_ = false; + + const char* filename_ = nullptr; + const char* introducerFilename_ = nullptr; + const char16_t* sourceMapURL_ = nullptr; + + public: + // POD options. + bool selfHostingMode = false; + bool canLazilyParse = true; + bool strictOption = false; + bool extraWarningsOption = false; + bool werrorOption = false; + AsmJSOption asmJSOption = AsmJSOption::Disabled; + bool throwOnAsmJSValidationFailureOption = false; + bool forceAsync = false; + bool sourceIsLazy = false; + bool allowHTMLComments = true; + bool isProbablySystemCode = false; + bool hideScriptFromDebugger = false; + bool bigIntEnabledOption = false; + bool fieldsEnabledOption = false; + + /** + * |introductionType| is a statically allocated C string: one of "eval", + * "Function", or "GeneratorFunction". + */ + const char* introductionType = nullptr; + + unsigned introductionLineno = 0; + uint32_t introductionOffset = 0; + bool hasIntroductionInfo = false; + + protected: + TransitiveCompileOptions() = default; + + // Set all POD options (those not requiring reference counts, copies, + // rooting, or other hand-holding) to their values in |rhs|. + void copyPODTransitiveOptions(const TransitiveCompileOptions& rhs); + + public: + // Read-only accessors for non-POD options. The proper way to set these + // depends on the derived type. + bool mutedErrors() const { return mutedErrors_; } + const char* filename() const { return filename_; } + const char* introducerFilename() const { return introducerFilename_; } + const char16_t* sourceMapURL() const { return sourceMapURL_; } + virtual JSObject* element() const = 0; + virtual JSString* elementAttributeName() const = 0; + virtual JSScript* introductionScript() const = 0; + + // For some compilations the spec requires the ScriptOrModule field of the + // resulting script to be set to the currently executing script. This can be + // achieved by setting this option with setScriptOrModule() below. + // + // Note that this field doesn't explicitly exist in our implementation; + // instead the ScriptSourceObject's private value is set to that associated + // with the specified script. + virtual JSScript* scriptOrModule() const = 0; + + private: + void operator=(const TransitiveCompileOptions&) = delete; +}; + +class JS_PUBLIC_API CompileOptions; + +/** + * The class representing a full set of compile options. + * + * Use this in code that only needs to access compilation options created + * elsewhere, like the compiler. Don't instantiate this class (the constructor + * is protected anyway); instead, create instances only of the derived classes: + * CompileOptions and OwningCompileOptions. + */ +class JS_PUBLIC_API ReadOnlyCompileOptions : public TransitiveCompileOptions { + public: + // POD options. + unsigned lineno = 1; + unsigned column = 0; + + // The offset within the ScriptSource's full uncompressed text of the first + // character we're presenting for compilation with this CompileOptions. + // + // When we compile a LazyScript, we pass the compiler only the substring of + // the source the lazy function occupies. With chunked decompression, we + // may not even have the complete uncompressed source present in memory. But + // parse node positions are offsets within the ScriptSource's full text, + // and LazyScripts indicate their substring of the full source by its + // starting and ending offsets within the full text. This + // scriptSourceOffset field lets the frontend convert between these + // offsets and offsets within the substring presented for compilation. + unsigned scriptSourceOffset = 0; + + // isRunOnce only applies to non-function scripts. + bool isRunOnce = false; + + bool nonSyntacticScope = false; + bool noScriptRval = false; + bool allowSyntaxParser = true; + + private: + friend class CompileOptions; + + protected: + ReadOnlyCompileOptions() = default; + + // Set all POD options (those not requiring reference counts, copies, + // rooting, or other hand-holding) to their values in |rhs|. + void copyPODOptions(const ReadOnlyCompileOptions& rhs); + + public: + // Read-only accessors for non-POD options. The proper way to set these + // depends on the derived type. + bool mutedErrors() const { return mutedErrors_; } + const char* filename() const { return filename_; } + const char* introducerFilename() const { return introducerFilename_; } + const char16_t* sourceMapURL() const { return sourceMapURL_; } + JSObject* element() const override = 0; + JSString* elementAttributeName() const override = 0; + JSScript* introductionScript() const override = 0; + JSScript* scriptOrModule() const override = 0; + + private: + void operator=(const ReadOnlyCompileOptions&) = delete; +}; + +/** + * Compilation options, with dynamic lifetime. An instance of this type + * makes a copy of / holds / roots all dynamically allocated resources + * (principals; elements; strings) that it refers to. Its destructor frees + * / drops / unroots them. This is heavier than CompileOptions, below, but + * unlike CompileOptions, it can outlive any given stack frame. + * + * Note that this *roots* any JS values it refers to - they're live + * unconditionally. Thus, instances of this type can't be owned, directly + * or indirectly, by a JavaScript object: if any value that this roots ever + * comes to refer to the object that owns this, then the whole cycle, and + * anything else it entrains, will never be freed. + */ +class JS_PUBLIC_API OwningCompileOptions final : public ReadOnlyCompileOptions { + PersistentRooted elementRoot; + PersistentRooted elementAttributeNameRoot; + PersistentRooted introductionScriptRoot; + PersistentRooted scriptOrModuleRoot; + + public: + // A minimal constructor, for use with OwningCompileOptions::copy. + explicit OwningCompileOptions(JSContext* cx); + ~OwningCompileOptions(); + + JSObject* element() const override { return elementRoot; } + JSString* elementAttributeName() const override { + return elementAttributeNameRoot; + } + JSScript* introductionScript() const override { + return introductionScriptRoot; + } + JSScript* scriptOrModule() const override { return scriptOrModuleRoot; } + + /** Set this to a copy of |rhs|. Return false on OOM. */ + bool copy(JSContext* cx, const ReadOnlyCompileOptions& rhs); + + /* These setters make copies of their string arguments and are fallible. */ + MOZ_MUST_USE bool setFile(JSContext* cx, const char* f); + MOZ_MUST_USE bool setFileAndLine(JSContext* cx, const char* f, unsigned l); + MOZ_MUST_USE bool setSourceMapURL(JSContext* cx, const char16_t* s); + MOZ_MUST_USE bool setIntroducerFilename(JSContext* cx, const char* s); + + /* These setters are infallible, and can be chained. */ + + OwningCompileOptions& setLine(unsigned l) { + lineno = l; + return *this; + } + + OwningCompileOptions& setElement(JSObject* e) { + elementRoot = e; + return *this; + } + + OwningCompileOptions& setElementAttributeName(JSString* p) { + elementAttributeNameRoot = p; + return *this; + } + + OwningCompileOptions& setIntroductionScript(JSScript* s) { + introductionScriptRoot = s; + return *this; + } + + OwningCompileOptions& setScriptOrModule(JSScript* s) { + scriptOrModuleRoot = s; + return *this; + } + + OwningCompileOptions& setMutedErrors(bool mute) { + mutedErrors_ = mute; + return *this; + } + + OwningCompileOptions& setColumn(unsigned c) { + column = c; + return *this; + } + + OwningCompileOptions& setScriptSourceOffset(unsigned o) { + scriptSourceOffset = o; + return *this; + } + + OwningCompileOptions& setIsRunOnce(bool once) { + isRunOnce = once; + return *this; + } + + OwningCompileOptions& setNoScriptRval(bool nsr) { + noScriptRval = nsr; + return *this; + } + + OwningCompileOptions& setSelfHostingMode(bool shm) { + selfHostingMode = shm; + return *this; + } + + OwningCompileOptions& setCanLazilyParse(bool clp) { + canLazilyParse = clp; + return *this; + } + + OwningCompileOptions& setAllowSyntaxParser(bool clp) { + allowSyntaxParser = clp; + return *this; + } + + OwningCompileOptions& setSourceIsLazy(bool l) { + sourceIsLazy = l; + return *this; + } + + OwningCompileOptions& setNonSyntacticScope(bool n) { + nonSyntacticScope = n; + return *this; + } + + OwningCompileOptions& setIntroductionType(const char* t) { + introductionType = t; + return *this; + } + + bool setIntroductionInfo(JSContext* cx, const char* introducerFn, + const char* intro, unsigned line, JSScript* script, + uint32_t offset) { + if (!setIntroducerFilename(cx, introducerFn)) { + return false; + } + + introductionType = intro; + introductionLineno = line; + introductionScriptRoot = script; + introductionOffset = offset; + hasIntroductionInfo = true; + return true; + } + + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + private: + void operator=(const CompileOptions& rhs) = delete; +}; + +/** + * Compilation options stored on the stack. An instance of this type + * simply holds references to dynamically allocated resources (element; + * filename; source map URL) that are owned by something else. If you + * create an instance of this type, it's up to you to guarantee that + * everything you store in it will outlive it. + */ +class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final + : public ReadOnlyCompileOptions { + private: + Rooted elementRoot; + Rooted elementAttributeNameRoot; + Rooted introductionScriptRoot; + Rooted scriptOrModuleRoot; + + public: + explicit CompileOptions(JSContext* cx); + + CompileOptions(JSContext* cx, const ReadOnlyCompileOptions& rhs) + : ReadOnlyCompileOptions(), + elementRoot(cx), + elementAttributeNameRoot(cx), + introductionScriptRoot(cx), + scriptOrModuleRoot(cx) { + copyPODOptions(rhs); + + filename_ = rhs.filename(); + introducerFilename_ = rhs.introducerFilename(); + sourceMapURL_ = rhs.sourceMapURL(); + elementRoot = rhs.element(); + elementAttributeNameRoot = rhs.elementAttributeName(); + introductionScriptRoot = rhs.introductionScript(); + scriptOrModuleRoot = rhs.scriptOrModule(); + } + + CompileOptions(JSContext* cx, const TransitiveCompileOptions& rhs) + : ReadOnlyCompileOptions(), + elementRoot(cx), + elementAttributeNameRoot(cx), + introductionScriptRoot(cx), + scriptOrModuleRoot(cx) { + copyPODTransitiveOptions(rhs); + + filename_ = rhs.filename(); + introducerFilename_ = rhs.introducerFilename(); + sourceMapURL_ = rhs.sourceMapURL(); + elementRoot = rhs.element(); + elementAttributeNameRoot = rhs.elementAttributeName(); + introductionScriptRoot = rhs.introductionScript(); + scriptOrModuleRoot = rhs.scriptOrModule(); + } + + JSObject* element() const override { return elementRoot; } + + JSString* elementAttributeName() const override { + return elementAttributeNameRoot; + } + + JSScript* introductionScript() const override { + return introductionScriptRoot; + } + + JSScript* scriptOrModule() const override { return scriptOrModuleRoot; } + + CompileOptions& setFile(const char* f) { + filename_ = f; + return *this; + } + + CompileOptions& setLine(unsigned l) { + lineno = l; + return *this; + } + + CompileOptions& setFileAndLine(const char* f, unsigned l) { + filename_ = f; + lineno = l; + return *this; + } + + CompileOptions& setSourceMapURL(const char16_t* s) { + sourceMapURL_ = s; + return *this; + } + + CompileOptions& setElement(JSObject* e) { + elementRoot = e; + return *this; + } + + CompileOptions& setElementAttributeName(JSString* p) { + elementAttributeNameRoot = p; + return *this; + } + + CompileOptions& setIntroductionScript(JSScript* s) { + introductionScriptRoot = s; + return *this; + } + + CompileOptions& setScriptOrModule(JSScript* s) { + scriptOrModuleRoot = s; + return *this; + } + + CompileOptions& setMutedErrors(bool mute) { + mutedErrors_ = mute; + return *this; + } + + CompileOptions& setColumn(unsigned c) { + column = c; + return *this; + } + + CompileOptions& setScriptSourceOffset(unsigned o) { + scriptSourceOffset = o; + return *this; + } + + CompileOptions& setIsRunOnce(bool once) { + isRunOnce = once; + return *this; + } + + CompileOptions& setNoScriptRval(bool nsr) { + noScriptRval = nsr; + return *this; + } + + CompileOptions& setSelfHostingMode(bool shm) { + selfHostingMode = shm; + return *this; + } + + CompileOptions& setCanLazilyParse(bool clp) { + canLazilyParse = clp; + return *this; + } + + CompileOptions& setAllowSyntaxParser(bool clp) { + allowSyntaxParser = clp; + return *this; + } + + CompileOptions& setSourceIsLazy(bool l) { + sourceIsLazy = l; + return *this; + } + + CompileOptions& setNonSyntacticScope(bool n) { + nonSyntacticScope = n; + return *this; + } + + CompileOptions& setIntroductionType(const char* t) { + introductionType = t; + return *this; + } + + CompileOptions& setIntroductionInfo(const char* introducerFn, + const char* intro, unsigned line, + JSScript* script, uint32_t offset) { + introducerFilename_ = introducerFn; + introductionType = intro; + introductionLineno = line; + introductionScriptRoot = script; + introductionOffset = offset; + hasIntroductionInfo = true; + return *this; + } + + // Set introduction information according to any currently executing script. + CompileOptions& setIntroductionInfoToCaller(JSContext* cx, + const char* introductionType); + + CompileOptions& maybeMakeStrictMode(bool strict) { + strictOption = strictOption || strict; + return *this; + } + + private: + void operator=(const CompileOptions& rhs) = delete; +}; + +} // namespace JS + +#endif /* js_CompileOptions_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ContextOptions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ContextOptions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ContextOptions.h @@ -0,0 +1,251 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* JavaScript API. */ + +#ifndef js_ContextOptions_h +#define js_ContextOptions_h + +#include "jstypes.h" // JS_PUBLIC_API + +struct JS_PUBLIC_API JSContext; + +namespace JS { + +class JS_PUBLIC_API ContextOptions { + public: + ContextOptions() + : baseline_(true), + ion_(true), + asmJS_(true), + wasm_(true), + wasmVerbose_(false), + wasmBaseline_(true), + wasmIon_(true), +#ifdef ENABLE_WASM_CRANELIFT + wasmCranelift_(false), +#endif +#ifdef ENABLE_WASM_GC + wasmGc_(false), +#endif + testWasmAwaitTier2_(false), + throwOnAsmJSValidationFailure_(false), + nativeRegExp_(true), + asyncStack_(true), + throwOnDebuggeeWouldRun_(true), + dumpStackOnDebuggeeWouldRun_(false), + werror_(false), + strictMode_(false), + extraWarnings_(false) +#ifdef FUZZING + , + fuzzing_(false) +#endif + { + } + + bool baseline() const { return baseline_; } + ContextOptions& setBaseline(bool flag) { + baseline_ = flag; + return *this; + } + ContextOptions& toggleBaseline() { + baseline_ = !baseline_; + return *this; + } + + bool ion() const { return ion_; } + ContextOptions& setIon(bool flag) { + ion_ = flag; + return *this; + } + ContextOptions& toggleIon() { + ion_ = !ion_; + return *this; + } + + bool asmJS() const { return asmJS_; } + ContextOptions& setAsmJS(bool flag) { + asmJS_ = flag; + return *this; + } + ContextOptions& toggleAsmJS() { + asmJS_ = !asmJS_; + return *this; + } + + bool wasm() const { return wasm_; } + ContextOptions& setWasm(bool flag) { + wasm_ = flag; + return *this; + } + ContextOptions& toggleWasm() { + wasm_ = !wasm_; + return *this; + } + + bool wasmVerbose() const { return wasmVerbose_; } + ContextOptions& setWasmVerbose(bool flag) { + wasmVerbose_ = flag; + return *this; + } + + bool wasmBaseline() const { return wasmBaseline_; } + ContextOptions& setWasmBaseline(bool flag) { + wasmBaseline_ = flag; + return *this; + } + + bool wasmIon() const { return wasmIon_; } + ContextOptions& setWasmIon(bool flag) { + wasmIon_ = flag; + return *this; + } + +#ifdef ENABLE_WASM_CRANELIFT + bool wasmCranelift() const { return wasmCranelift_; } + ContextOptions& setWasmCranelift(bool flag) { + wasmCranelift_ = flag; + return *this; + } +#endif + + bool testWasmAwaitTier2() const { return testWasmAwaitTier2_; } + ContextOptions& setTestWasmAwaitTier2(bool flag) { + testWasmAwaitTier2_ = flag; + return *this; + } + +#ifdef ENABLE_WASM_GC + bool wasmGc() const { return wasmGc_; } + ContextOptions& setWasmGc(bool flag) { + wasmGc_ = flag; + return *this; + } +#endif + + bool throwOnAsmJSValidationFailure() const { + return throwOnAsmJSValidationFailure_; + } + ContextOptions& setThrowOnAsmJSValidationFailure(bool flag) { + throwOnAsmJSValidationFailure_ = flag; + return *this; + } + ContextOptions& toggleThrowOnAsmJSValidationFailure() { + throwOnAsmJSValidationFailure_ = !throwOnAsmJSValidationFailure_; + return *this; + } + + bool nativeRegExp() const { return nativeRegExp_; } + ContextOptions& setNativeRegExp(bool flag) { + nativeRegExp_ = flag; + return *this; + } + + bool asyncStack() const { return asyncStack_; } + ContextOptions& setAsyncStack(bool flag) { + asyncStack_ = flag; + return *this; + } + + bool throwOnDebuggeeWouldRun() const { return throwOnDebuggeeWouldRun_; } + ContextOptions& setThrowOnDebuggeeWouldRun(bool flag) { + throwOnDebuggeeWouldRun_ = flag; + return *this; + } + + bool dumpStackOnDebuggeeWouldRun() const { + return dumpStackOnDebuggeeWouldRun_; + } + ContextOptions& setDumpStackOnDebuggeeWouldRun(bool flag) { + dumpStackOnDebuggeeWouldRun_ = flag; + return *this; + } + + bool werror() const { return werror_; } + ContextOptions& setWerror(bool flag) { + werror_ = flag; + return *this; + } + ContextOptions& toggleWerror() { + werror_ = !werror_; + return *this; + } + + bool strictMode() const { return strictMode_; } + ContextOptions& setStrictMode(bool flag) { + strictMode_ = flag; + return *this; + } + ContextOptions& toggleStrictMode() { + strictMode_ = !strictMode_; + return *this; + } + + bool extraWarnings() const { return extraWarnings_; } + ContextOptions& setExtraWarnings(bool flag) { + extraWarnings_ = flag; + return *this; + } + ContextOptions& toggleExtraWarnings() { + extraWarnings_ = !extraWarnings_; + return *this; + } + +#ifdef FUZZING + bool fuzzing() const { return fuzzing_; } + ContextOptions& setFuzzing(bool flag) { + fuzzing_ = flag; + return *this; + } +#endif + + void disableOptionsForSafeMode() { + setBaseline(false); + setIon(false); + setAsmJS(false); + setWasm(false); + setWasmBaseline(false); + setWasmIon(false); +#ifdef ENABLE_WASM_GC + setWasmGc(false); +#endif + setNativeRegExp(false); + } + + private: + bool baseline_ : 1; + bool ion_ : 1; + bool asmJS_ : 1; + bool wasm_ : 1; + bool wasmVerbose_ : 1; + bool wasmBaseline_ : 1; + bool wasmIon_ : 1; +#ifdef ENABLE_WASM_CRANELIFT + bool wasmCranelift_ : 1; +#endif +#ifdef ENABLE_WASM_GC + bool wasmGc_ : 1; +#endif + bool testWasmAwaitTier2_ : 1; + bool throwOnAsmJSValidationFailure_ : 1; + bool nativeRegExp_ : 1; + bool asyncStack_ : 1; + bool throwOnDebuggeeWouldRun_ : 1; + bool dumpStackOnDebuggeeWouldRun_ : 1; + bool werror_ : 1; + bool strictMode_ : 1; + bool extraWarnings_ : 1; +#ifdef FUZZING + bool fuzzing_ : 1; +#endif +}; + +JS_PUBLIC_API ContextOptions& ContextOptionsRef(JSContext* cx); + +} // namespace JS + +#endif // js_ContextOptions_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Conversions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Conversions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Conversions.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -10,6 +10,7 @@ #define js_Conversions_h #include "mozilla/Casting.h" +#include "mozilla/Compiler.h" #include "mozilla/FloatingPoint.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/TypeTraits.h" @@ -103,16 +104,24 @@ /* ES6 draft 20141224, 7.1.2. */ MOZ_ALWAYS_INLINE bool ToBoolean(HandleValue v) { - if (v.isBoolean()) return v.toBoolean(); - if (v.isInt32()) return v.toInt32() != 0; - if (v.isNullOrUndefined()) return false; + if (v.isBoolean()) { + return v.toBoolean(); + } + if (v.isInt32()) { + return v.toInt32() != 0; + } + if (v.isNullOrUndefined()) { + return false; + } if (v.isDouble()) { double d = v.toDouble(); return !mozilla::IsNaN(d) && d != 0; } - if (v.isSymbol()) return true; + if (v.isSymbol()) { + return true; + } - /* The slow path handles strings and objects. */ + /* The slow path handles strings, BigInts and objects. */ return js::ToBooleanSlow(v); } @@ -129,10 +138,14 @@ /* ES6 draft 20141224, ToInteger (specialized for doubles). */ inline double ToInteger(double d) { - if (d == 0) return d; + if (d == 0) { + return d; + } if (!mozilla::IsFinite(d)) { - if (mozilla::IsNaN(d)) return 0; + if (mozilla::IsNaN(d)) { + return 0; + } return d; } @@ -237,7 +250,9 @@ MOZ_ALWAYS_INLINE JSString* ToString(JSContext* cx, HandleValue v) { detail::AssertArgumentsAreSane(cx, v); - if (v.isString()) return v.toString(); + if (v.isString()) { + return v.toString(); + } return js::ToStringSlow(cx, v); } @@ -245,29 +260,29 @@ inline JSObject* ToObject(JSContext* cx, HandleValue v) { detail::AssertArgumentsAreSane(cx, v); - if (v.isObject()) return &v.toObject(); + if (v.isObject()) { + return &v.toObject(); + } return js::ToObjectSlow(cx, v, false); } -namespace detail { - -/* - * Convert a double value to ResultType (an unsigned integral type) using +/** + * Convert a double value to UnsignedInteger (an unsigned integral type) using * ECMAScript-style semantics (that is, in like manner to how ECMAScript's * ToInt32 converts to int32_t). * * If d is infinite or NaN, return 0. - * Otherwise compute d2 = sign(d) * floor(abs(d)), and return the ResultType - * value congruent to d2 mod 2**(bit width of ResultType). + * Otherwise compute d2 = sign(d) * floor(abs(d)), and return the + * UnsignedInteger value congruent to d2 % 2**(bit width of UnsignedInteger). * * The algorithm below is inspired by that found in - * + * * but has been generalized to all integer widths. */ -template -inline ResultType ToUintWidth(double d) { - static_assert(mozilla::IsUnsigned::value, - "ResultType must be an unsigned type"); +template +inline UnsignedInteger ToUnsignedInteger(double d) { + static_assert(mozilla::IsUnsigned::value, + "UnsignedInteger must be an unsigned type"); uint64_t bits = mozilla::BitwiseCast(d); unsigned DoubleExponentShift = mozilla::FloatingPoint::kExponentShift; @@ -281,28 +296,32 @@ // If the exponent's less than zero, abs(d) < 1, so the result is 0. (This // also handles subnormals.) - if (exp < 0) return 0; + if (exp < 0) { + return 0; + } uint_fast16_t exponent = mozilla::AssertedCast(exp); // If the exponent is greater than or equal to the bits of precision of a - // double plus ResultType's width, the number is either infinite, NaN, or - // too large to have lower-order bits in the congruent value. (Example: + // double plus UnsignedInteger's width, the number is either infinite, NaN, + // or too large to have lower-order bits in the congruent value. (Example: // 2**84 is exactly representable as a double. The next exact double is - // 2**84 + 2**32. Thus if ResultType is int32_t, an exponent >= 84 implies - // floor(abs(d)) == 0 mod 2**32.) Return 0 in all these cases. - const size_t ResultWidth = CHAR_BIT * sizeof(ResultType); - if (exponent >= DoubleExponentShift + ResultWidth) return 0; + // 2**84 + 2**32. Thus if UnsignedInteger is uint32_t, an exponent >= 84 + // implies floor(abs(d)) == 0 mod 2**32.) Return 0 in all these cases. + constexpr size_t ResultWidth = CHAR_BIT * sizeof(UnsignedInteger); + if (exponent >= DoubleExponentShift + ResultWidth) { + return 0; + } // The significand contains the bits that will determine the final result. // Shift those bits left or right, according to the exponent, to their // locations in the unsigned binary representation of floor(abs(d)). - static_assert(sizeof(ResultType) <= sizeof(uint64_t), - "Left-shifting below would lose upper bits"); - ResultType result = + static_assert(sizeof(UnsignedInteger) <= sizeof(uint64_t), + "left-shifting below would lose upper bits"); + UnsignedInteger result = (exponent > DoubleExponentShift) - ? ResultType(bits << (exponent - DoubleExponentShift)) - : ResultType(bits >> (DoubleExponentShift - exponent)); + ? UnsignedInteger(bits << (exponent - DoubleExponentShift)) + : UnsignedInteger(bits >> (DoubleExponentShift - exponent)); // Two further complications remain. First, |result| may contain bogus // sign/exponent bits. Second, IEEE-754 numbers' significands (excluding @@ -329,7 +348,8 @@ // The implicit leading bit matters identically to the other case, so // again, |exponent < ResultWidth|. if (exponent < ResultWidth) { - ResultType implicitOne = ResultType(1) << exponent; + const auto implicitOne = + static_cast(UnsignedInteger{1} << exponent); result &= implicitOne - 1; // remove bogus bits result += implicitOne; // add the implicit bit } @@ -339,24 +359,23 @@ : result; } -template -inline ResultType ToIntWidth(double d) { - static_assert(mozilla::IsSigned::value, - "ResultType must be a signed type"); +template +inline SignedInteger ToSignedInteger(double d) { + static_assert(mozilla::IsSigned::value, + "SignedInteger must be a signed type"); - using UnsignedResult = typename mozilla::MakeUnsigned::Type; - UnsignedResult u = ToUintWidth(d); + using UnsignedInteger = typename mozilla::MakeUnsigned::Type; + UnsignedInteger u = ToUnsignedInteger(d); return mozilla::WrapToSigned(u); } -} // namespace detail - -/* ES5 9.5 ToInt32 (specialized for doubles). */ -inline int32_t ToInt32(double d) { // clang crashes compiling this when targeting arm: // https://llvm.org/bugs/show_bug.cgi?id=22974 -#if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) +#if defined(__arm__) && MOZ_IS_GCC + +template <> +inline int32_t ToSignedInteger(double d) { int32_t i; uint32_t tmp0; uint32_t tmp1; @@ -481,30 +500,59 @@ : "4"(d) : "cc"); return i; -#else - return detail::ToIntWidth(d); -#endif } -/* ES5 9.6 (specialized for doubles). */ -inline uint32_t ToUint32(double d) { return detail::ToUintWidth(d); } +#endif // defined (__arm__) && MOZ_IS_GCC + +namespace detail { + +template ::value> +struct ToSignedOrUnsignedInteger; + +template +struct ToSignedOrUnsignedInteger { + static IntegerType compute(double d) { + return ToUnsignedInteger(d); + } +}; + +template +struct ToSignedOrUnsignedInteger { + static IntegerType compute(double d) { + return ToSignedInteger(d); + } +}; + +} // namespace detail + +template +inline IntegerType ToSignedOrUnsignedInteger(double d) { + return detail::ToSignedOrUnsignedInteger::compute(d); +} /* WEBIDL 4.2.4 */ -inline int8_t ToInt8(double d) { return detail::ToIntWidth(d); } +inline int8_t ToInt8(double d) { return ToSignedInteger(d); } /* ECMA-262 7.1.10 ToUInt8() specialized for doubles. */ -inline int8_t ToUint8(double d) { return detail::ToUintWidth(d); } +inline int8_t ToUint8(double d) { return ToUnsignedInteger(d); } /* WEBIDL 4.2.6 */ -inline int16_t ToInt16(double d) { return detail::ToIntWidth(d); } +inline int16_t ToInt16(double d) { return ToSignedInteger(d); } -inline uint16_t ToUint16(double d) { return detail::ToUintWidth(d); } +inline uint16_t ToUint16(double d) { return ToUnsignedInteger(d); } + +/* ES5 9.5 ToInt32 (specialized for doubles). */ +inline int32_t ToInt32(double d) { return ToSignedInteger(d); } + +/* ES5 9.6 (specialized for doubles). */ +inline uint32_t ToUint32(double d) { return ToUnsignedInteger(d); } /* WEBIDL 4.2.10 */ -inline int64_t ToInt64(double d) { return detail::ToIntWidth(d); } +inline int64_t ToInt64(double d) { return ToSignedInteger(d); } /* WEBIDL 4.2.11 */ -inline uint64_t ToUint64(double d) { return detail::ToUintWidth(d); } +inline uint64_t ToUint64(double d) { return ToUnsignedInteger(d); } } // namespace JS Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Date.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Date.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Date.h @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -29,11 +29,15 @@ * of accessor methods to the various aspects of the represented date. */ -#include "mozilla/FloatingPoint.h" -#include "mozilla/MathAlgorithms.h" +#include "mozilla/FloatingPoint.h" // mozilla::{IsFinite,IsNaN}, mozilla::UnspecifiedNaN +#include "mozilla/MathAlgorithms.h" // mozilla::Abs -#include "js/Conversions.h" -#include "js/Value.h" +#include "js/Conversions.h" // JS::ToInteger +#include "js/RootingAPI.h" // JS::Handle +#include "js/Value.h" // JS::CanonicalizeNaN, JS::DoubleValue, JS::Value + +struct JS_PUBLIC_API JSContext; +class JS_PUBLIC_API JSObject; namespace JS { @@ -43,12 +47,12 @@ * cause all Date object non-UTC methods and formatting functions to produce * appropriately adjusted results. * - * Left to its own devices, SpiderMonkey itself may occasionally call this - * method to attempt to keep up with system time changes. However, no - * particular frequency of checking is guaranteed. Embedders unable to accept - * occasional inaccuracies should call this method in response to system time - * changes, or immediately before operations requiring instantaneous - * correctness, to guarantee correct behavior. + * Left to its own devices, SpiderMonkey itself may occasionally try to detect + * system time changes. However, no particular frequency of checking is + * guaranteed. Embedders unable to accept occasional inaccuracies should call + * this method in response to system time changes, or immediately before + * operations requiring instantaneous correctness, to guarantee correct + * behavior. */ extern JS_PUBLIC_API void ResetTimeZone(); @@ -99,8 +103,9 @@ inline ClippedTime TimeClip(double time) { // Steps 1-2. const double MaxTimeMagnitude = 8.64e15; - if (!mozilla::IsFinite(time) || mozilla::Abs(time) > MaxTimeMagnitude) + if (!mozilla::IsFinite(time) || mozilla::Abs(time) > MaxTimeMagnitude) { return ClippedTime(mozilla::UnspecifiedNaN()); + } // Step 3. return ClippedTime(ToInteger(time) + (+0.0)); @@ -109,7 +114,7 @@ // Produce a double Value from the given time. Because times may be NaN, // prefer using this to manual canonicalization. inline Value TimeValue(ClippedTime time) { - return DoubleValue(JS::CanonicalizeNaN(time.toDouble())); + return DoubleValue(CanonicalizeNaN(time.toDouble())); } // Create a new Date object whose [[DateValue]] internal slot contains the @@ -117,6 +122,31 @@ // another representation.) extern JS_PUBLIC_API JSObject* NewDateObject(JSContext* cx, ClippedTime time); +/** + * Create a new Date object for a year/month/day-of-month/hour/minute/second. + * + * The created date is initialized with the time value + * + * TimeClip(UTC(MakeDate(MakeDay(year, mon, mday), + * MakeTime(hour, min, sec, 0.0)))) + * + * where each function/operation is as specified in ECMAScript. + */ +extern JS_PUBLIC_API JSObject* NewDateObject(JSContext* cx, int year, int mon, + int mday, int hour, int min, + int sec); + +/** + * On success, returns true, setting |*isDate| to true if |obj| is a Date + * object or a wrapper around one, or to false if not. Returns false on + * failure. + * + * This method returns true with |*isDate == false| when passed an ES6 proxy + * whose target is a Date, or when passed a revoked proxy. + */ +extern JS_PUBLIC_API bool ObjectIsDate(JSContext* cx, Handle obj, + bool* isDate); + // Year is a year, month is 0-11, day is 1-based. The return value is a number // of milliseconds since the epoch. // Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Debug.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Debug.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Debug.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -27,6 +27,8 @@ namespace JS { namespace dbg { +// [SMDOC] Debugger builder API +// // Helping embedding code build objects for Debugger // ------------------------------------------------- // @@ -95,8 +97,9 @@ // Builder::Object& result) // { // JSObject* eventObject = ... obtain debuggee event object somehow ...; -// if (!eventObject) +// if (!eventObject) { // return false; +// } // result = builder.newObject(cx); // return result && // result.defineProperty(cx, "eventType", @@ -152,7 +155,7 @@ PersistentRooted value; BuiltThing(JSContext* cx, Builder& owner_, - T value_ = GCPolicy::initial()) + T value_ = SafelyInitialized()) : owner(owner_), value(cx, value_) { owner.assertBuilt(value_); } @@ -292,7 +295,7 @@ // Append each of the debuggee global objects observed by the Debugger object // |dbgObj| to |vector|. Returns true on success, false on failure. JS_PUBLIC_API bool GetDebuggeeGlobals(JSContext* cx, JSObject& dbgObj, - AutoObjectVector& vector); + MutableHandleObjectVector vector); // Hooks for reporting where JavaScript execution began. // Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Equality.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Equality.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Equality.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Equality operations. */ + +#ifndef js_Equality_h +#define js_Equality_h + +#include "jstypes.h" // JS_PUBLIC_API + +#include "js/RootingAPI.h" // JS::Handle +#include "js/Value.h" // JS::Value + +struct JS_PUBLIC_API JSContext; + +namespace JS { + +/** + * Store |v1 === v2| to |*equal| -- strict equality, which performs no + * conversions on |v1| or |v2| before comparing. + * + * This operation can fail only if an internal error occurs (e.g. OOM while + * linearizing a string value). + */ +extern JS_PUBLIC_API bool StrictlyEqual(JSContext* cx, JS::Handle v1, + JS::Handle v2, bool* equal); + +/** + * Store |v1 == v2| to |*equal| -- loose equality, which may perform + * user-modifiable conversions on |v1| or |v2|. + * + * This operation can fail if a user-modifiable conversion fails *or* if an + * internal error occurs. (e.g. OOM while linearizing a string value). + */ +extern JS_PUBLIC_API bool LooselyEqual(JSContext* cx, JS::Handle v1, + JS::Handle v2, bool* equal); + +/** + * Stores |SameValue(v1, v2)| to |*equal| -- using the SameValue operation + * defined in ECMAScript, initially exposed to script as |Object.is|. SameValue + * behaves identically to strict equality, except that it equates two NaN values + * and does not equate differently-signed zeroes. It performs no conversions on + * |v1| or |v2| before comparing. + * + * This operation can fail only if an internal error occurs (e.g. OOM while + * linearizing a string value). + */ +extern JS_PUBLIC_API bool SameValue(JSContext* cx, JS::Handle v1, + JS::Handle v2, bool* same); + +} // namespace JS + +#endif /* js_Equality_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ErrorReport.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ErrorReport.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ErrorReport.h @@ -0,0 +1,281 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Error-reporting types and structures. + * + * Despite these types and structures existing in js/public, significant parts + * of their heritage date back to distant SpiderMonkey past, and they are not + * all universally well-thought-out as ideal, intended-to-be-permanent API. + * We may eventually replace this with something more consistent with + * ECMAScript the language and less consistent with '90s-era JSAPI inventions, + * but it's doubtful this will happen any time soon. + */ + +#ifndef js_ErrorReport_h +#define js_ErrorReport_h + +#include "mozilla/Assertions.h" // MOZ_ASSERT + +#include // std::input_iterator_tag, std::iterator +#include // size_t +#include // int16_t, uint16_t +#include // strlen + +#include "jstypes.h" // JS_PUBLIC_API + +#include "js/AllocPolicy.h" // js::SystemAllocPolicy +#include "js/CharacterEncoding.h" // JS::ConstUTF8CharsZ +#include "js/UniquePtr.h" // js::UniquePtr +#include "js/Vector.h" // js::Vector + +struct JS_PUBLIC_API JSContext; +class JS_PUBLIC_API JSString; + +/** + * Possible exception types. These types are part of a JSErrorFormatString + * structure. They define which error to throw in case of a runtime error. + * + * JSEXN_WARN is used for warnings in js.msg files (for instance because we + * don't want to prepend 'Error:' to warning messages). This value can go away + * if we ever decide to use an entirely separate mechanism for warnings. + */ +enum JSExnType { + JSEXN_ERR, + JSEXN_FIRST = JSEXN_ERR, + JSEXN_INTERNALERR, + JSEXN_EVALERR, + JSEXN_RANGEERR, + JSEXN_REFERENCEERR, + JSEXN_SYNTAXERR, + JSEXN_TYPEERR, + JSEXN_URIERR, + JSEXN_DEBUGGEEWOULDRUN, + JSEXN_WASMCOMPILEERROR, + JSEXN_WASMLINKERROR, + JSEXN_WASMRUNTIMEERROR, + JSEXN_ERROR_LIMIT, + JSEXN_WARN = JSEXN_ERROR_LIMIT, + JSEXN_NOTE, + JSEXN_LIMIT +}; + +struct JSErrorFormatString { + /** The error message name in ASCII. */ + const char* name; + + /** The error format string in ASCII. */ + const char* format; + + /** The number of arguments to expand in the formatted error message. */ + uint16_t argCount; + + /** One of the JSExnType constants above. */ + int16_t exnType; +}; + +using JSErrorCallback = + const JSErrorFormatString* (*)(void* userRef, const unsigned errorNumber); + +/** + * Base class that implements parts shared by JSErrorReport and + * JSErrorNotes::Note. + */ +class JSErrorBase { + private: + // The (default) error message. + // If ownsMessage_ is true, the it is freed in destructor. + JS::ConstUTF8CharsZ message_; + + public: + // Source file name, URL, etc., or null. + const char* filename; + + // Unique identifier for the script source. + unsigned sourceId; + + // Source line number. + unsigned lineno; + + // Zero-based column index in line. + unsigned column; + + // the error number, e.g. see js.msg. + unsigned errorNumber; + + private: + bool ownsMessage_ : 1; + + public: + JSErrorBase() + : filename(nullptr), + sourceId(0), + lineno(0), + column(0), + errorNumber(0), + ownsMessage_(false) {} + + ~JSErrorBase() { freeMessage(); } + + public: + const JS::ConstUTF8CharsZ message() const { return message_; } + + void initOwnedMessage(const char* messageArg) { + initBorrowedMessage(messageArg); + ownsMessage_ = true; + } + void initBorrowedMessage(const char* messageArg) { + MOZ_ASSERT(!message_); + message_ = JS::ConstUTF8CharsZ(messageArg, strlen(messageArg)); + } + + JSString* newMessageString(JSContext* cx); + + private: + void freeMessage(); +}; + +/** + * Notes associated with JSErrorReport. + */ +class JSErrorNotes { + public: + class Note final : public JSErrorBase {}; + + private: + // Stores pointers to each note. + js::Vector, 1, js::SystemAllocPolicy> notes_; + + public: + JSErrorNotes(); + ~JSErrorNotes(); + + // Add an note to the given position. + bool addNoteASCII(JSContext* cx, const char* filename, unsigned sourceId, + unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + bool addNoteLatin1(JSContext* cx, const char* filename, unsigned sourceId, + unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + bool addNoteUTF8(JSContext* cx, const char* filename, unsigned sourceId, + unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + + JS_PUBLIC_API size_t length(); + + // Create a deep copy of notes. + js::UniquePtr copy(JSContext* cx); + + class iterator final { + private: + js::UniquePtr* note_; + + public: + using iterator_category = std::input_iterator_tag; + using value_type = js::UniquePtr; + using difference_type = ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + + explicit iterator(js::UniquePtr* note = nullptr) : note_(note) {} + + bool operator==(iterator other) const { return note_ == other.note_; } + bool operator!=(iterator other) const { return !(*this == other); } + iterator& operator++() { + note_++; + return *this; + } + reference operator*() { return *note_; } + }; + + JS_PUBLIC_API iterator begin(); + JS_PUBLIC_API iterator end(); +}; + +/** + * Describes a single error or warning that occurs in the execution of script. + */ +class JSErrorReport : public JSErrorBase { + private: + // Offending source line without final '\n'. + // If ownsLinebuf_ is true, the buffer is freed in destructor. + const char16_t* linebuf_; + + // Number of chars in linebuf_. Does not include trailing '\0'. + size_t linebufLength_; + + // The 0-based offset of error token in linebuf_. + size_t tokenOffset_; + + public: + // Associated notes, or nullptr if there's no note. + js::UniquePtr notes; + + // error/warning, etc. + unsigned flags; + + // One of the JSExnType constants. + int16_t exnType; + + // See the comment in TransitiveCompileOptions. + bool isMuted : 1; + + private: + bool ownsLinebuf_ : 1; + + public: + JSErrorReport() + : linebuf_(nullptr), + linebufLength_(0), + tokenOffset_(0), + notes(nullptr), + flags(0), + exnType(0), + isMuted(false), + ownsLinebuf_(false) {} + + ~JSErrorReport() { freeLinebuf(); } + + public: + const char16_t* linebuf() const { return linebuf_; } + size_t linebufLength() const { return linebufLength_; } + size_t tokenOffset() const { return tokenOffset_; } + void initOwnedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, + size_t tokenOffsetArg) { + initBorrowedLinebuf(linebufArg, linebufLengthArg, tokenOffsetArg); + ownsLinebuf_ = true; + } + void initBorrowedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, + size_t tokenOffsetArg); + + private: + void freeLinebuf(); +}; + +/* + * JSErrorReport flag values. These may be freely composed. + */ +#define JSREPORT_ERROR 0x0 /* pseudo-flag for default case */ +#define JSREPORT_WARNING 0x1 /* reported via JS::Warn* */ +#define JSREPORT_EXCEPTION 0x2 /* exception was thrown */ +#define JSREPORT_STRICT 0x4 /* error or warning due to strict option */ + +#define JSREPORT_USER_1 0x8 /* user-defined flag */ + +/* + * If JSREPORT_EXCEPTION is set, then a JavaScript-catchable exception + * has been thrown for this runtime error, and the host should ignore it. + * Exception-aware hosts should also check for JS_IsExceptionPending if + * JS_ExecuteScript returns failure, and signal or propagate the exception, as + * appropriate. + */ +#define JSREPORT_IS_WARNING(flags) (((flags)&JSREPORT_WARNING) != 0) +#define JSREPORT_IS_EXCEPTION(flags) (((flags)&JSREPORT_EXCEPTION) != 0) +#define JSREPORT_IS_STRICT(flags) (((flags)&JSREPORT_STRICT) != 0) + +#endif /* js_ErrorReport_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ForOfIterator.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ForOfIterator.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ForOfIterator.h @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * A convenience class that makes it easy to perform the operations of a for-of + * loop. + */ + +#ifndef js_ForOfIterator_h +#define js_ForOfIterator_h + +#include "mozilla/Attributes.h" // MOZ_MUST_USE, MOZ_STACK_CLASS + +#include // UINT32_MAX, uint32_t + +#include "jstypes.h" // JS_PUBLIC_API + +#include "js/RootingAPI.h" // JS::{Handle,Rooted} +#include "js/Value.h" // JS::Value, JS::{,Mutable}Handle + +struct JS_PUBLIC_API JSContext; +class JS_PUBLIC_API JSObject; + +namespace JS { + +/** + * A convenience class for imitating a JS for-of loop. Typical usage: + * + * JS::ForOfIterator it(cx); + * if (!it.init(iterable)) { + * return false; + * } + * JS::Rooted val(cx); + * while (true) { + * bool done; + * if (!it.next(&val, &done)) { + * return false; + * } + * if (done) { + * break; + * } + * if (!DoStuff(cx, val)) { + * return false; + * } + * } + */ +class MOZ_STACK_CLASS JS_PUBLIC_API ForOfIterator { + protected: + JSContext* cx_; + + // Use the ForOfPIC on the global object (see vm/GlobalObject.h) to try to + // optimize iteration across arrays. + // + // Case 1: Regular Iteration + // iterator - pointer to the iterator object. + // nextMethod - value of |iterator|.next. + // index - fixed to NOT_ARRAY (== UINT32_MAX) + // + // Case 2: Optimized Array Iteration + // iterator - pointer to the array object. + // nextMethod - the undefined value. + // index - current position in array. + // + // The cases are distinguished by whether |index == NOT_ARRAY|. + Rooted iterator; + Rooted nextMethod; + + static constexpr uint32_t NOT_ARRAY = UINT32_MAX; + + uint32_t index = NOT_ARRAY; + + ForOfIterator(const ForOfIterator&) = delete; + ForOfIterator& operator=(const ForOfIterator&) = delete; + + public: + explicit ForOfIterator(JSContext* cx) + : cx_(cx), iterator(cx), nextMethod(cx) {} + + enum NonIterableBehavior { ThrowOnNonIterable, AllowNonIterable }; + + /** + * Initialize the iterator. If AllowNonIterable is passed then if getting + * the @@iterator property from iterable returns undefined init() will just + * return true instead of throwing. Callers must then check + * valueIsIterable() before continuing with the iteration. + */ + MOZ_MUST_USE bool init( + Handle iterable, + NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable); + + /** + * Get the next value from the iterator. If false *done is true + * after this call, do not examine val. + */ + MOZ_MUST_USE bool next(MutableHandle val, bool* done); + + /** + * Close the iterator. + * For the case that completion type is throw. + */ + void closeThrow(); + + /** + * If initialized with throwOnNonCallable = false, check whether + * the value is iterable. + */ + bool valueIsIterable() const { return iterator; } + + private: + inline bool nextFromOptimizedArray(MutableHandle val, bool* done); +}; + +} // namespace JS + +#endif // js_ForOfIterator_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCAPI.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCAPI.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCAPI.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -19,19 +19,9 @@ #include "js/UniquePtr.h" #include "js/Utility.h" -struct JSFreeOp; - -#ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wattributes" -#endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING - +struct JS_PUBLIC_API JSFreeOp; class JS_PUBLIC_API JSTracer; -#ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING -#pragma GCC diagnostic pop -#endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING - namespace js { namespace gc { class GCRuntime; @@ -48,11 +38,11 @@ /** Perform per-zone GCs until too much garbage has accumulated. */ JSGC_MODE_ZONE = 1, - /** - * Collect in short time slices rather than all at once. Implies - * JSGC_MODE_ZONE. - */ - JSGC_MODE_INCREMENTAL = 2 + /** Collect in short time slices rather than all at once. */ + JSGC_MODE_INCREMENTAL = 2, + + /** Both of the above. */ + JSGC_MODE_ZONE_INCREMENTAL = 3, } JSGCMode; /** @@ -91,6 +81,9 @@ /** * Maximum size of the generational GC nurseries. * + * This will be rounded to the nearest gc::ChunkSize. The special value 0 + * will disable generational GC. + * * Pref: javascript.options.mem.nursery.max_kb * Default: JS::DefaultNurseryBytes */ @@ -108,7 +101,7 @@ * See: JSGCMode in GCAPI.h * prefs: javascript.options.mem.gc_per_zone and * javascript.options.mem.gc_incremental. - * Default: JSGC_MODE_INCREMENTAL + * Default: JSGC_MODE_ZONE_INCREMENTAL */ JSGC_MODE = 6, @@ -135,18 +128,38 @@ JSGC_MARK_STACK_LIMIT = 10, /** - * GCs less than this far apart in time will be considered 'high-frequency - * GCs'. + * The "do we collect?" decision depends on various parameters and can be + * summarised as: * - * See setGCLastBytes in jsgc.cpp. + * ZoneSize * 1/UsageFactor > Max(ThresholdBase, LastSize) * GrowthFactor + * + * Where + * ZoneSize: Current size of this zone. + * LastSize: Heap size immediately after the most recent collection. + * ThresholdBase: The JSGC_ALLOCATION_THRESHOLD parameter + * GrowthFactor: A number above 1, calculated based on some of the + * following parameters. + * See computeZoneHeapGrowthFactorForHeapSize() in GC.cpp + * UsageFactor: JSGC_ALLOCATION_THRESHOLD_FACTOR or + * JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT or 1.0 for + * non-incremental collections. + * + * The RHS of the equation above is calculated and sets + * zone->threshold.gcTriggerBytes(). When usage.gcBytes() surpasses + * threshold.gcTriggerBytes() for a zone, the zone may be scheduled for a GC. + */ + + /** + * GCs less than this far apart in milliseconds will be considered + * 'high-frequency GCs'. * * Pref: javascript.options.mem.gc_high_frequency_time_limit_ms - * Default: HighFrequencyThresholdUsec + * Default: HighFrequencyThreshold */ JSGC_HIGH_FREQUENCY_TIME_LIMIT = 11, /** - * Start of dynamic heap growth. + * Start of dynamic heap growth (MB). * * Pref: javascript.options.mem.gc_high_frequency_low_limit_mb * Default: HighFrequencyLowLimitBytes @@ -154,7 +167,7 @@ JSGC_HIGH_FREQUENCY_LOW_LIMIT = 12, /** - * End of dynamic heap growth. + * End of dynamic heap growth (MB). * * Pref: javascript.options.mem.gc_high_frequency_high_limit_mb * Default: HighFrequencyHighLimitBytes @@ -162,7 +175,7 @@ JSGC_HIGH_FREQUENCY_HIGH_LIMIT = 13, /** - * Upper bound of heap growth. + * Upper bound of heap growth percentage. * * Pref: javascript.options.mem.gc_high_frequency_heap_growth_max * Default: HighFrequencyHeapGrowthMax @@ -170,7 +183,7 @@ JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX = 14, /** - * Lower bound of heap growth. + * Lower bound of heap growth percentage. * * Pref: javascript.options.mem.gc_high_frequency_heap_growth_min * Default: HighFrequencyHeapGrowthMin @@ -178,7 +191,7 @@ JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN = 15, /** - * Heap growth for low frequency GCs. + * Heap growth percentage for low frequency GCs. * * Pref: javascript.options.mem.gc_low_frequency_heap_growth * Default: LowFrequencyHeapGrowth @@ -203,11 +216,9 @@ JSGC_DYNAMIC_MARK_SLICE = 18, /** - * Lower limit after which we limit the heap growth. + * Lower limit for collecting a zone. * - * The base value used to compute zone->threshold.gcTriggerBytes(). When - * usage.gcBytes() surpasses threshold.gcTriggerBytes() for a zone, the - * zone may be scheduled for a GC, depending on the exact circumstances. + * Zones smaller than this size will not normally be collected. * * Pref: javascript.options.mem.gc_allocation_threshold_mb * Default GCZoneAllocThresholdBase @@ -241,7 +252,10 @@ JSGC_COMPACTING_ENABLED = 23, /** - * Factor for triggering a GC based on JSGC_ALLOCATION_THRESHOLD + * Percentage for triggering a GC based on zone->threshold.gcTriggerBytes(). + * + * When the heap reaches this percentage of the allocation threshold an + * incremental collection is started. * * Default: ZoneAllocThresholdFactorDefault * Pref: None @@ -249,13 +263,78 @@ JSGC_ALLOCATION_THRESHOLD_FACTOR = 25, /** - * Factor for triggering a GC based on JSGC_ALLOCATION_THRESHOLD. - * Used if another GC (in different zones) is already running. + * Percentage for triggering a GC based on zone->threshold.gcTriggerBytes(). + * + * Used instead of the above percentage if if another GC (in different zones) + * is already running. * * Default: ZoneAllocThresholdFactorAvoidInterruptDefault * Pref: None */ JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT = 26, + + /** + * Attempt to run a minor GC in the idle time if the free space falls + * below this number of bytes. + * + * Default: NurseryChunkUsableSize / 4 + * Pref: None + */ + JSGC_NURSERY_FREE_THRESHOLD_FOR_IDLE_COLLECTION = 27, + + /** + * If this percentage of the nursery is tenured and the nursery is at least + * 4MB, then proceed to examine which groups we should pretenure. + * + * Default: PretenureThreshold + * Pref: None + */ + JSGC_PRETENURE_THRESHOLD = 28, + + /** + * If the above condition is met, then any object group that tenures more than + * this number of objects will be pretenured (if it can be). + * + * Default: PretenureGroupThreshold + * Pref: None + */ + JSGC_PRETENURE_GROUP_THRESHOLD = 29, + + /** + * Attempt to run a minor GC in the idle time if the free space falls + * below this percentage (from 0 to 99). + * + * Default: 25 + * Pref: None + */ + JSGC_NURSERY_FREE_THRESHOLD_FOR_IDLE_COLLECTION_PERCENT = 30, + + /** + * Minimum size of the generational GC nurseries. + * + * This value will be rounded to the nearest Nursery::SubChunkStep if below + * gc::ChunkSize, otherwise it'll be rounded to the nearest gc::ChunkSize. + * + * Default: Nursery::SubChunkLimit + * Pref: javascript.options.mem.nursery.min_kb + */ + JSGC_MIN_NURSERY_BYTES = 31, + + /* + * The minimum time to allow between triggering last ditch GCs in seconds. + * + * Default: 60 seconds + * Pref: None + */ + JSGC_MIN_LAST_DITCH_GC_PERIOD = 32, + + /* + * The delay (in heapsize kilobytes) between slices of an incremental GC. + * + * Default: ZoneAllocDelayBytes + */ + JSGC_ZONE_ALLOC_DELAY_KB = 33, + } JSGCParamKey; /* @@ -303,7 +382,7 @@ typedef void (*JSWeakPointerZonesCallback)(JSContext* cx, void* data); typedef void (*JSWeakPointerCompartmentCallback)(JSContext* cx, - JSCompartment* comp, + JS::Compartment* comp, void* data); /** @@ -318,72 +397,69 @@ #define GCREASONS(D) \ /* Reasons internal to the JS engine */ \ - D(API) \ - D(EAGER_ALLOC_TRIGGER) \ - D(DESTROY_RUNTIME) \ - D(ROOTS_REMOVED) \ - D(LAST_DITCH) \ - D(TOO_MUCH_MALLOC) \ - D(ALLOC_TRIGGER) \ - D(DEBUG_GC) \ - D(COMPARTMENT_REVIVED) \ - D(RESET) \ - D(OUT_OF_NURSERY) \ - D(EVICT_NURSERY) \ - D(DELAYED_ATOMS_GC) \ - D(SHARED_MEMORY_LIMIT) \ - D(IDLE_TIME_COLLECTION) \ - D(INCREMENTAL_TOO_SLOW) \ - D(ABORT_GC) \ - D(FULL_WHOLE_CELL_BUFFER) \ - D(FULL_GENERIC_BUFFER) \ - D(FULL_VALUE_BUFFER) \ - D(FULL_CELL_PTR_BUFFER) \ - D(FULL_SLOT_BUFFER) \ - D(FULL_SHAPE_BUFFER) \ + D(API, 0) \ + D(EAGER_ALLOC_TRIGGER, 1) \ + D(DESTROY_RUNTIME, 2) \ + D(ROOTS_REMOVED, 3) \ + D(LAST_DITCH, 4) \ + D(TOO_MUCH_MALLOC, 5) \ + D(ALLOC_TRIGGER, 6) \ + D(DEBUG_GC, 7) \ + D(COMPARTMENT_REVIVED, 8) \ + D(RESET, 9) \ + D(OUT_OF_NURSERY, 10) \ + D(EVICT_NURSERY, 11) \ + D(DELAYED_ATOMS_GC, 12) \ + D(SHARED_MEMORY_LIMIT, 13) \ + D(IDLE_TIME_COLLECTION, 14) \ + D(INCREMENTAL_TOO_SLOW, 15) \ + D(ABORT_GC, 16) \ + D(FULL_WHOLE_CELL_BUFFER, 17) \ + D(FULL_GENERIC_BUFFER, 18) \ + D(FULL_VALUE_BUFFER, 19) \ + D(FULL_CELL_PTR_BUFFER, 20) \ + D(FULL_SLOT_BUFFER, 21) \ + D(FULL_SHAPE_BUFFER, 22) \ + D(TOO_MUCH_WASM_MEMORY, 23) \ + D(DISABLE_GENERATIONAL_GC, 24) \ + D(FINISH_GC, 25) \ + D(PREPARE_FOR_TRACING, 26) \ \ /* These are reserved for future use. */ \ - D(RESERVED0) \ - D(RESERVED1) \ - D(RESERVED2) \ - D(RESERVED3) \ - D(RESERVED4) \ - D(RESERVED5) \ - D(RESERVED6) \ - D(RESERVED7) \ - D(RESERVED8) \ - D(RESERVED9) \ + D(RESERVED3, 27) \ + D(RESERVED4, 28) \ + D(RESERVED5, 29) \ + D(RESERVED6, 30) \ + D(RESERVED7, 31) \ + D(RESERVED8, 32) \ \ /* Reasons from Firefox */ \ - D(DOM_WINDOW_UTILS) \ - D(COMPONENT_UTILS) \ - D(MEM_PRESSURE) \ - D(CC_WAITING) \ - D(CC_FORCED) \ - D(LOAD_END) \ - D(POST_COMPARTMENT) \ - D(PAGE_HIDE) \ - D(NSJSCONTEXT_DESTROY) \ - D(SET_NEW_DOCUMENT) \ - D(SET_DOC_SHELL) \ - D(DOM_UTILS) \ - D(DOM_IPC) \ - D(DOM_WORKER) \ - D(INTER_SLICE_GC) \ - D(UNUSED1) \ - D(FULL_GC_TIMER) \ - D(SHUTDOWN_CC) \ - D(UNUSED2) \ - D(USER_INACTIVE) \ - D(XPCONNECT_SHUTDOWN) \ - D(DOCSHELL) \ - D(HTML_PARSER) - -namespace gcreason { - -/* GCReasons will end up looking like JSGC_MAYBEGC */ -enum Reason { -#define MAKE_REASON(name) name, + D(DOM_WINDOW_UTILS, 33) \ + D(COMPONENT_UTILS, 34) \ + D(MEM_PRESSURE, 35) \ + D(CC_WAITING, 36) \ + D(CC_FORCED, 37) \ + D(LOAD_END, 38) \ + D(UNUSED3, 39) \ + D(PAGE_HIDE, 40) \ + D(NSJSCONTEXT_DESTROY, 41) \ + D(WORKER_SHUTDOWN, 42) \ + D(SET_DOC_SHELL, 43) \ + D(DOM_UTILS, 44) \ + D(DOM_IPC, 45) \ + D(DOM_WORKER, 46) \ + D(INTER_SLICE_GC, 47) \ + D(UNUSED1, 48) \ + D(FULL_GC_TIMER, 49) \ + D(SHUTDOWN_CC, 50) \ + D(UNUSED2, 51) \ + D(USER_INACTIVE, 52) \ + D(XPCONNECT_SHUTDOWN, 53) \ + D(DOCSHELL, 54) \ + D(HTML_PARSER, 55) + +enum class GCReason { +#define MAKE_REASON(name, val) name = val, GCREASONS(MAKE_REASON) #undef MAKE_REASON NO_REASON, @@ -391,9 +467,8 @@ /* * For telemetry, we want to keep a fixed max bucket size over time so we - * don't have to switch histograms. 100 is conservative; as of this writing - * there are 52. But the cost of extra buckets seems to be low while the - * cost of switching histograms is high. + * don't have to switch histograms. 100 is conservative; but the cost of extra + * buckets seems to be low while the cost of switching histograms is high. */ NUM_TELEMETRY_REASONS = 100 }; @@ -401,9 +476,7 @@ /** * Get a statically allocated C string explaining the given GC reason. */ -extern JS_PUBLIC_API const char* ExplainReason(JS::gcreason::Reason reason); - -} /* namespace gcreason */ +extern JS_PUBLIC_API const char* ExplainGCReason(JS::GCReason reason); /* * Zone GC: @@ -463,8 +536,9 @@ * to objects will be cleared and all unreferenced objects will be removed from * the system. */ -extern JS_PUBLIC_API void GCForReason(JSContext* cx, JSGCInvocationKind gckind, - gcreason::Reason reason); +extern JS_PUBLIC_API void NonIncrementalGC(JSContext* cx, + JSGCInvocationKind gckind, + GCReason reason); /* * Incremental GC: @@ -479,8 +553,8 @@ * must be met: * - The collection must be run by calling JS::IncrementalGC() rather than * JS_GC(). - * - The GC mode must have been set to JSGC_MODE_INCREMENTAL with - * JS_SetGCParameter(). + * - The GC mode must have been set to JSGC_MODE_INCREMENTAL or + * JSGC_MODE_ZONE_INCREMENTAL with JS_SetGCParameter(). * * Note: Even if incremental GC is enabled and working correctly, * non-incremental collections can still happen when low on memory. @@ -497,7 +571,7 @@ */ extern JS_PUBLIC_API void StartIncrementalGC(JSContext* cx, JSGCInvocationKind gckind, - gcreason::Reason reason, + GCReason reason, int64_t millis = 0); /** @@ -508,18 +582,24 @@ * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or * shorter than the requested interval. */ -extern JS_PUBLIC_API void IncrementalGCSlice(JSContext* cx, - gcreason::Reason reason, +extern JS_PUBLIC_API void IncrementalGCSlice(JSContext* cx, GCReason reason, int64_t millis = 0); /** + * Return whether an incremental GC has work to do on the foreground thread and + * would make progress if a slice was run now. If this returns false then the GC + * is waiting for background threads to finish their work and a slice started + * now would return immediately. + */ +extern JS_PUBLIC_API bool IncrementalGCHasForegroundWork(JSContext* cx); + +/** * If IsIncrementalGCInProgress(cx), this call finishes the ongoing collection * by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(cx), - * this is equivalent to GCForReason. When this function returns, + * this is equivalent to NonIncrementalGC. When this function returns, * IsIncrementalGCInProgress(cx) will always be false. */ -extern JS_PUBLIC_API void FinishIncrementalGC(JSContext* cx, - gcreason::Reason reason); +extern JS_PUBLIC_API void FinishIncrementalGC(JSContext* cx, GCReason reason); /** * If IsIncrementalGCInProgress(cx), this call aborts the ongoing collection and @@ -595,10 +675,10 @@ bool isZone_; bool isComplete_; JSGCInvocationKind invocationKind_; - gcreason::Reason reason_; + GCReason reason_; GCDescription(bool isZone, bool isComplete, JSGCInvocationKind kind, - gcreason::Reason reason) + GCReason reason) : isZone_(isZone), isComplete_(isComplete), invocationKind_(kind), @@ -606,15 +686,16 @@ char16_t* formatSliceMessage(JSContext* cx) const; char16_t* formatSummaryMessage(JSContext* cx) const; - char16_t* formatJSON(JSContext* cx, uint64_t timestamp) const; mozilla::TimeStamp startTime(JSContext* cx) const; mozilla::TimeStamp endTime(JSContext* cx) const; mozilla::TimeStamp lastSliceStart(JSContext* cx) const; mozilla::TimeStamp lastSliceEnd(JSContext* cx) const; - JS::UniqueChars sliceToJSON(JSContext* cx) const; - JS::UniqueChars summaryToJSON(JSContext* cx) const; + char16_t* formatJSONTelemetry(JSContext* cx, uint64_t timestamp) const; + + JS::UniqueChars sliceToJSONProfiler(JSContext* cx) const; + JS::UniqueChars formatJSONProfiler(JSContext* cx) const; JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSContext* cx) const; }; @@ -652,7 +733,7 @@ */ using GCNurseryCollectionCallback = void (*)(JSContext* cx, GCNurseryProgress progress, - gcreason::Reason reason); + GCReason reason); /** * Set the nursery collection callback for the given runtime. When set, it will @@ -729,13 +810,6 @@ extern JS_PUBLIC_API bool IsGenerationalGCEnabled(JSRuntime* rt); /** - * Returns the GC's "number". This does not correspond directly to the number - * of GCs that have been run, but is guaranteed to be monotonically increasing - * with GC activity. - */ -extern JS_PUBLIC_API size_t GetGCNumber(); - -/** * Pass a subclass of this "abstract" class to callees to require that they * never GC. Subclasses can use assertions or the hazard analysis to ensure no * GC happens. @@ -861,7 +935,8 @@ JSTraceDataOp traceOp, void* data); -extern JS_PUBLIC_API void JS_GC(JSContext* cx); +extern JS_PUBLIC_API void JS_GC(JSContext* cx, + JS::GCReason reason = JS::GCReason::API); extern JS_PUBLIC_API void JS_MaybeGC(JSContext* cx); Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCAnnotations.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCAnnotations.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCAnnotations.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -11,20 +11,31 @@ // and functions. #ifdef XGILL_PLUGIN +# define JS_EXPECT_HAZARDS __attribute__((annotate("Expect Hazards"))) + // Mark a type as being a GC thing (eg js::gc::Cell has this annotation). -#define JS_HAZ_GC_THING __attribute__((tag("GC Thing"))) +# define JS_HAZ_GC_THING __attribute__((annotate("GC Thing"))) // Mark a type as holding a pointer to a GC thing (eg JS::Value has this -// annotation.) -#define JS_HAZ_GC_POINTER __attribute__((tag("GC Pointer"))) +// annotation.) "Inherited" by templatized types with +// MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS. +# define JS_HAZ_GC_POINTER __attribute__((annotate("GC Pointer"))) // Mark a type as a rooted pointer, suitable for use on the stack (eg all -// Rooted instantiations should have this.) -#define JS_HAZ_ROOTED __attribute__((tag("Rooted Pointer"))) +// Rooted instantiations should have this.) "Inherited" by templatized types +// with MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS. +# define JS_HAZ_ROOTED __attribute__((annotate("Rooted Pointer"))) // Mark a type as something that should not be held live across a GC, but which -// is not itself a GC pointer. -#define JS_HAZ_GC_INVALIDATED __attribute__((tag("Invalidated by GC"))) +// is not itself a GC pointer. Note that this property is *not* inherited by +// templatized types with MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS. +# define JS_HAZ_GC_INVALIDATED __attribute__((annotate("Invalidated by GC"))) + +// Mark a class as a base class of rooted types, eg CustomAutoRooter. All +// descendants of this class will be considered rooted, though classes that +// merely contain these as a field member will not be. "Inherited" by +// templatized types with MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS +# define JS_HAZ_ROOTED_BASE __attribute__((annotate("Rooted Base"))) // Mark a type that would otherwise be considered a GC Pointer (eg because it // contains a JS::Value field) as a non-GC pointer. It is handled almost the @@ -33,24 +44,38 @@ // but makes sense for something like ErrorResult, which only contains a GC // pointer when it holds an exception (and it does its own rooting, // conditionally.) -#define JS_HAZ_NON_GC_POINTER __attribute__((tag("Suppressed GC Pointer"))) +# define JS_HAZ_NON_GC_POINTER \ + __attribute__((annotate("Suppressed GC Pointer"))) // Mark a function as something that runs a garbage collection, potentially // invalidating GC pointers. -#define JS_HAZ_GC_CALL __attribute__((tag("GC Call"))) +# define JS_HAZ_GC_CALL __attribute__((annotate("GC Call"))) // Mark an RAII class as suppressing GC within its scope. -#define JS_HAZ_GC_SUPPRESSED __attribute__((tag("Suppress GC"))) +# define JS_HAZ_GC_SUPPRESSED __attribute__((annotate("Suppress GC"))) + +// Mark a function as one that can run script if called. This obviously +// subsumes JS_HAZ_GC_CALL, since anything that can run script can GC.` +# define JS_HAZ_CAN_RUN_SCRIPT __attribute__((annotate("Can run script"))) + +// Mark a function as able to call JSNatives. Otherwise, JSNatives don't show +// up in the callgraph. This doesn't matter for the can-GC analysis, but it is +// very nice for other uses of the callgraph. +# define JS_HAZ_JSNATIVE_CALLER __attribute__((annotate("Calls JSNatives"))) #else -#define JS_HAZ_GC_THING -#define JS_HAZ_GC_POINTER -#define JS_HAZ_ROOTED -#define JS_HAZ_GC_INVALIDATED -#define JS_HAZ_NON_GC_POINTER -#define JS_HAZ_GC_CALL -#define JS_HAZ_GC_SUPPRESSED +# define JS_EXPECT_HAZARDS +# define JS_HAZ_GC_THING +# define JS_HAZ_GC_POINTER +# define JS_HAZ_ROOTED +# define JS_HAZ_GC_INVALIDATED +# define JS_HAZ_ROOTED_BASE +# define JS_HAZ_NON_GC_POINTER +# define JS_HAZ_GC_CALL +# define JS_HAZ_GC_SUPPRESSED +# define JS_HAZ_CAN_RUN_SCRIPT +# define JS_HAZ_JSNATIVE_CALLER #endif Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCHashTable.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCHashTable.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCHashTable.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -58,40 +58,40 @@ public: explicit GCHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {} + explicit GCHashMap(size_t length) : Base(length) {} + GCHashMap(AllocPolicy a, size_t length) : Base(a, length) {} static void trace(GCHashMap* map, JSTracer* trc) { map->trace(trc); } void trace(JSTracer* trc) { - if (!this->initialized()) return; for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { GCPolicy::trace(trc, &e.front().value(), "hashmap value"); GCPolicy::trace(trc, &e.front().mutableKey(), "hashmap key"); } } - bool needsSweep() const { return this->initialized() && !this->empty(); } + bool needsSweep() const { return !this->empty(); } void sweep() { - if (!this->initialized()) return; - for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { if (MapSweepPolicy::needsSweep(&e.front().mutableKey(), - &e.front().value())) + &e.front().value())) { e.removeFront(); + } } } // GCHashMap is movable - GCHashMap(GCHashMap&& rhs) : Base(mozilla::Move(rhs)) {} + GCHashMap(GCHashMap&& rhs) : Base(std::move(rhs)) {} void operator=(GCHashMap&& rhs) { MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - Base::operator=(mozilla::Move(rhs)); + Base::operator=(std::move(rhs)); } private: // GCHashMap is not copyable or assignable GCHashMap(const GCHashMap& hm) = delete; GCHashMap& operator=(const GCHashMap& hm) = delete; -}; +} MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS; } // namespace JS @@ -112,26 +112,27 @@ public: explicit GCRekeyableHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {} + explicit GCRekeyableHashMap(size_t length) : Base(length) {} + GCRekeyableHashMap(AllocPolicy a, size_t length) : Base(a, length) {} void sweep() { - if (!this->initialized()) return; - for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { Key key(e.front().key()); - if (MapSweepPolicy::needsSweep(&key, &e.front().value())) + if (MapSweepPolicy::needsSweep(&key, &e.front().value())) { e.removeFront(); - else if (!HashPolicy::match(key, e.front().key())) + } else if (!HashPolicy::match(key, e.front().key())) { e.rekeyFront(key); + } } } // GCRekeyableHashMap is movable - GCRekeyableHashMap(GCRekeyableHashMap&& rhs) : Base(mozilla::Move(rhs)) {} + GCRekeyableHashMap(GCRekeyableHashMap&& rhs) : Base(std::move(rhs)) {} void operator=(GCRekeyableHashMap&& rhs) { MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - Base::operator=(mozilla::Move(rhs)); + Base::operator=(std::move(rhs)); } -}; +} MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS; template class WrappedPtrOperations, Wrapper> { @@ -145,9 +146,7 @@ using Ptr = typename Map::Ptr; using Range = typename Map::Range; - bool initialized() const { return map().initialized(); } Ptr lookup(const Lookup& l) const { return map().lookup(l); } - AddPtr lookupForAdd(const Lookup& l) const { return map().lookupForAdd(l); } Range all() const { return map().all(); } bool empty() const { return map().empty(); } uint32_t count() const { return map().count(); } @@ -177,38 +176,35 @@ using Ptr = typename Map::Ptr; using Range = typename Map::Range; - bool init(uint32_t len = 16) { return map().init(len); } void clear() { map().clear(); } - void finish() { map().finish(); } + void clearAndCompact() { map().clearAndCompact(); } void remove(Ptr p) { map().remove(p); } + AddPtr lookupForAdd(const Lookup& l) { return map().lookupForAdd(l); } template bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { - return map().add(p, mozilla::Forward(k), - mozilla::Forward(v)); + return map().add(p, std::forward(k), std::forward(v)); } template bool add(AddPtr& p, KeyInput&& k) { - return map().add(p, mozilla::Forward(k), Map::Value()); + return map().add(p, std::forward(k), Map::Value()); } template bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { - return map().relookupOrAdd(p, k, mozilla::Forward(k), - mozilla::Forward(v)); + return map().relookupOrAdd(p, k, std::forward(k), + std::forward(v)); } template bool put(KeyInput&& k, ValueInput&& v) { - return map().put(mozilla::Forward(k), - mozilla::Forward(v)); + return map().put(std::forward(k), std::forward(v)); } template bool putNew(KeyInput&& k, ValueInput&& v) { - return map().putNew(mozilla::Forward(k), - mozilla::Forward(v)); + return map().putNew(std::forward(k), std::forward(v)); } }; @@ -236,35 +232,38 @@ public: explicit GCHashSet(AllocPolicy a = AllocPolicy()) : Base(a) {} + explicit GCHashSet(size_t length) : Base(length) {} + GCHashSet(AllocPolicy a, size_t length) : Base(a, length) {} static void trace(GCHashSet* set, JSTracer* trc) { set->trace(trc); } void trace(JSTracer* trc) { - if (!this->initialized()) return; - for (typename Base::Enum e(*this); !e.empty(); e.popFront()) + for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { GCPolicy::trace(trc, &e.mutableFront(), "hashset element"); + } } - bool needsSweep() const { return this->initialized() && !this->empty(); } + bool needsSweep() const { return !this->empty(); } void sweep() { - if (!this->initialized()) return; for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { - if (GCPolicy::needsSweep(&e.mutableFront())) e.removeFront(); + if (GCPolicy::needsSweep(&e.mutableFront())) { + e.removeFront(); + } } } // GCHashSet is movable - GCHashSet(GCHashSet&& rhs) : Base(mozilla::Move(rhs)) {} + GCHashSet(GCHashSet&& rhs) : Base(std::move(rhs)) {} void operator=(GCHashSet&& rhs) { MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - Base::operator=(mozilla::Move(rhs)); + Base::operator=(std::move(rhs)); } private: // GCHashSet is not copyable or assignable GCHashSet(const GCHashSet& hs) = delete; GCHashSet& operator=(const GCHashSet& hs) = delete; -}; +} MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS; } // namespace JS @@ -283,9 +282,7 @@ using Ptr = typename Set::Ptr; using Range = typename Set::Range; - bool initialized() const { return set().initialized(); } Ptr lookup(const Lookup& l) const { return set().lookup(l); } - AddPtr lookupForAdd(const Lookup& l) const { return set().lookupForAdd(l); } Range all() const { return set().all(); } bool empty() const { return set().empty(); } uint32_t count() const { return set().count(); } @@ -316,35 +313,36 @@ using Ptr = typename Set::Ptr; using Range = typename Set::Range; - bool init(uint32_t len = 16) { return set().init(len); } void clear() { set().clear(); } - void finish() { set().finish(); } + void clearAndCompact() { set().clearAndCompact(); } + MOZ_MUST_USE bool reserve(uint32_t len) { return set().reserve(len); } void remove(Ptr p) { set().remove(p); } void remove(const Lookup& l) { set().remove(l); } + AddPtr lookupForAdd(const Lookup& l) { return set().lookupForAdd(l); } template bool add(AddPtr& p, TInput&& t) { - return set().add(p, mozilla::Forward(t)); + return set().add(p, std::forward(t)); } template bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) { - return set().relookupOrAdd(p, l, mozilla::Forward(t)); + return set().relookupOrAdd(p, l, std::forward(t)); } template bool put(TInput&& t) { - return set().put(mozilla::Forward(t)); + return set().put(std::forward(t)); } template bool putNew(TInput&& t) { - return set().putNew(mozilla::Forward(t)); + return set().putNew(std::forward(t)); } template bool putNew(const Lookup& l, TInput&& t) { - return set().putNew(l, mozilla::Forward(t)); + return set().putNew(l, std::forward(t)); } }; @@ -368,20 +366,18 @@ template explicit WeakCache(Zone* zone, Args&&... args) : WeakCacheBase(zone), - map(mozilla::Forward(args)...), + map(std::forward(args)...), needsBarrier(false) {} template explicit WeakCache(JSRuntime* rt, Args&&... args) : WeakCacheBase(rt), - map(mozilla::Forward(args)...), + map(std::forward(args)...), needsBarrier(false) {} ~WeakCache() { MOZ_ASSERT(!needsBarrier); } bool needsSweep() override { return map.needsSweep(); } size_t sweep() override { - if (!this->initialized()) return 0; - size_t steps = map.count(); map.sweep(); return steps; @@ -428,7 +424,9 @@ typename Map::Range range; void settle() { - while (!empty() && entryNeedsSweep(front())) popFront(); + while (!empty() && entryNeedsSweep(front())) { + popFront(); + } } }; @@ -440,8 +438,6 @@ } }; - bool initialized() const { return map.initialized(); } - Ptr lookup(const Lookup& l) const { Ptr ptr = map.lookup(l); if (needsBarrier && ptr && entryNeedsSweep(*ptr)) { @@ -451,7 +447,7 @@ return ptr; } - AddPtr lookupForAdd(const Lookup& l) const { + AddPtr lookupForAdd(const Lookup& l) { AddPtr ptr = map.lookupForAdd(l); if (needsBarrier && ptr && entryNeedsSweep(*ptr)) { const_cast(map).remove(ptr); @@ -486,12 +482,7 @@ return map.sizeOfExcludingThis(mallocSizeOf); } size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return mallocSizeOf(this) + map.sizeOfExcludingThis(mallocSizeOf); - } - - bool init(uint32_t len = 16) { - MOZ_ASSERT(!needsBarrier); - return map.init(len); + return mallocSizeOf(this) + map.shallowSizeOfExcludingThis(mallocSizeOf); } void clear() { @@ -501,11 +492,11 @@ map.clear(); } - void finish() { + void clearAndCompact() { // This operation is not currently allowed while barriers are in place - // since it doesn't make sense to destroy a cache while it is being swept. + // since it doesn't make sense to clear a cache while it is being swept. MOZ_ASSERT(!needsBarrier); - map.finish(); + map.clearAndCompact(); } void remove(Ptr p) { @@ -517,39 +508,32 @@ void remove(const Lookup& l) { Ptr p = lookup(l); - if (p) remove(p); - } - - template - bool add(AddPtr& p, KeyInput&& k) { - using mozilla::Forward; - return map.add(p, Forward(k)); + if (p) { + remove(p); + } } template bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { - using mozilla::Forward; - return map.add(p, Forward(k), Forward(v)); + return map.add(p, std::forward(k), std::forward(v)); } template bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { - using mozilla::Forward; - return map.relookupOrAdd(p, Forward(k), Forward(v)); + return map.relookupOrAdd(p, std::forward(k), + std::forward(v)); } template bool put(KeyInput&& k, ValueInput&& v) { - using mozilla::Forward; - return map.put(Forward(k), Forward(v)); + return map.put(std::forward(k), std::forward(v)); } template bool putNew(KeyInput&& k, ValueInput&& v) { - using mozilla::Forward; - return map.putNew(Forward(k), Forward(v)); + return map.putNew(std::forward(k), std::forward(v)); } -}; +} JS_HAZ_NON_GC_POINTER; // Specialize WeakCache for GCHashSet to provide a barriered set that does not // need to be swept immediately. @@ -568,17 +552,15 @@ template explicit WeakCache(Zone* zone, Args&&... args) : WeakCacheBase(zone), - set(mozilla::Forward(args)...), + set(std::forward(args)...), needsBarrier(false) {} template explicit WeakCache(JSRuntime* rt, Args&&... args) : WeakCacheBase(rt), - set(mozilla::Forward(args)...), + set(std::forward(args)...), needsBarrier(false) {} size_t sweep() override { - if (!this->initialized()) return 0; - size_t steps = set.count(); set.sweep(); return steps; @@ -623,7 +605,9 @@ typename Set::Range range; void settle() { - while (!empty() && entryNeedsSweep(front())) popFront(); + while (!empty() && entryNeedsSweep(front())) { + popFront(); + } } }; @@ -635,8 +619,6 @@ } }; - bool initialized() const { return set.initialized(); } - Ptr lookup(const Lookup& l) const { Ptr ptr = set.lookup(l); if (needsBarrier && ptr && entryNeedsSweep(*ptr)) { @@ -646,7 +628,7 @@ return ptr; } - AddPtr lookupForAdd(const Lookup& l) const { + AddPtr lookupForAdd(const Lookup& l) { AddPtr ptr = set.lookupForAdd(l); if (needsBarrier && ptr && entryNeedsSweep(*ptr)) { const_cast(set).remove(ptr); @@ -678,15 +660,10 @@ bool has(const Lookup& l) const { return lookup(l).found(); } size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return set.sizeOfExcludingThis(mallocSizeOf); + return set.shallowSizeOfExcludingThis(mallocSizeOf); } size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return mallocSizeOf(this) + set.sizeOfExcludingThis(mallocSizeOf); - } - - bool init(uint32_t len = 16) { - MOZ_ASSERT(!needsBarrier); - return set.init(len); + return mallocSizeOf(this) + set.shallowSizeOfExcludingThis(mallocSizeOf); } void clear() { @@ -696,11 +673,11 @@ set.clear(); } - void finish() { + void clearAndCompact() { // This operation is not currently allowed while barriers are in place - // since it doesn't make sense to destroy a cache while it is being swept. + // since it doesn't make sense to clear a cache while it is being swept. MOZ_ASSERT(!needsBarrier); - set.finish(); + set.clearAndCompact(); } void remove(Ptr p) { @@ -712,34 +689,36 @@ void remove(const Lookup& l) { Ptr p = lookup(l); - if (p) remove(p); + if (p) { + remove(p); + } } template bool add(AddPtr& p, TInput&& t) { - return set.add(p, mozilla::Forward(t)); + return set.add(p, std::forward(t)); } template bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) { - return set.relookupOrAdd(p, l, mozilla::Forward(t)); + return set.relookupOrAdd(p, l, std::forward(t)); } template bool put(TInput&& t) { - return set.put(mozilla::Forward(t)); + return set.put(std::forward(t)); } template bool putNew(TInput&& t) { - return set.putNew(mozilla::Forward(t)); + return set.putNew(std::forward(t)); } template bool putNew(const Lookup& l, TInput&& t) { - return set.putNew(l, mozilla::Forward(t)); + return set.putNew(l, std::forward(t)); } -}; +} JS_HAZ_NON_GC_POINTER; } // namespace JS Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCPolicyAPI.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCPolicyAPI.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCPolicyAPI.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -13,9 +13,6 @@ // // The GCPolicy provides at a minimum: // -// static T initial() -// - Construct and return an empty T. -// // static void trace(JSTracer, T* tp, const char* name) // - Trace the edge |*tp|, calling the edge |name|. Containers like // GCHashMap and GCHashSet use this method to trace their children. @@ -28,6 +25,11 @@ // from the container. Specializing this method is the standard way to // get custom weak behavior from a container type. // +// static bool isValid(const T& t) +// - Return false only if |t| is corrupt in some way. The built-in GC +// types do some memory layout checks. For debugging only; it is ok +// to always return true or even to omit this member entirely. +// // The default GCPolicy assumes that T has a default constructor and |trace| // and |needsSweep| methods, and forwards to them. GCPolicy has appropriate // specializations for pointers to GC things and pointer-like types like @@ -50,6 +52,7 @@ // Expand the given macro D for each public GC pointer. #define FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \ D(JS::Symbol*) \ + D(JS::BigInt*) \ D(JSAtom*) \ D(JSFunction*) \ D(JSObject*) \ @@ -69,7 +72,8 @@ // policy dispatches to the underlying struct for GC interactions. template struct StructGCPolicy { - static T initial() { return T(); } + static_assert(!mozilla::IsPointer::value, + "Pointer type not allowed for StructGCPolicy"); static void trace(JSTracer* trc, T* tp, const char* name) { tp->trace(trc); } @@ -90,7 +94,6 @@ // This policy ignores any GC interaction, e.g. for non-GC types. template struct IgnoreGCPolicy { - static T initial() { return T(); } static void trace(JSTracer* trc, T* t, const char* name) {} static bool needsSweep(T* v) { return false; } static bool isValid(const T& v) { return true; } @@ -102,37 +105,41 @@ template struct GCPointerPolicy { - static T initial() { return nullptr; } + static_assert(mozilla::IsPointer::value, + "Non-pointer type not allowed for GCPointerPolicy"); + static void trace(JSTracer* trc, T* vp, const char* name) { - if (*vp) js::UnsafeTraceManuallyBarrieredEdge(trc, vp, name); + if (*vp) { + js::UnsafeTraceManuallyBarrieredEdge(trc, vp, name); + } } static bool needsSweep(T* vp) { - if (*vp) return js::gc::IsAboutToBeFinalizedUnbarriered(vp); + if (*vp) { + return js::gc::IsAboutToBeFinalizedUnbarriered(vp); + } return false; } static bool isValid(T v) { return js::gc::IsCellPointerValidOrNull(v); } }; -template <> -struct GCPolicy : public GCPointerPolicy {}; -template <> -struct GCPolicy : public GCPointerPolicy {}; -template <> -struct GCPolicy : public GCPointerPolicy {}; -template <> -struct GCPolicy : public GCPointerPolicy {}; -template <> -struct GCPolicy : public GCPointerPolicy {}; -template <> -struct GCPolicy : public GCPointerPolicy {}; +#define EXPAND_SPECIALIZE_GCPOLICY(Type) \ + template <> \ + struct GCPolicy : public GCPointerPolicy {}; \ + template <> \ + struct GCPolicy : public GCPointerPolicy {}; +FOR_EACH_PUBLIC_GC_POINTER_TYPE(EXPAND_SPECIALIZE_GCPOLICY) +#undef EXPAND_SPECIALIZE_GCPOLICY template struct NonGCPointerPolicy { - static T initial() { return nullptr; } static void trace(JSTracer* trc, T* vp, const char* name) { - if (*vp) (*vp)->trace(trc); + if (*vp) { + (*vp)->trace(trc); + } } static bool needsSweep(T* vp) { - if (*vp) return (*vp)->needsSweep(); + if (*vp) { + return (*vp)->needsSweep(); + } return false; } static bool isValid(T v) { return true; } @@ -151,19 +158,22 @@ // GCPolicy> forwards the contained pointer to GCPolicy. template struct GCPolicy> { - static mozilla::UniquePtr initial() { - return mozilla::UniquePtr(); - } static void trace(JSTracer* trc, mozilla::UniquePtr* tp, const char* name) { - if (tp->get()) GCPolicy::trace(trc, tp->get(), name); + if (tp->get()) { + GCPolicy::trace(trc, tp->get(), name); + } } static bool needsSweep(mozilla::UniquePtr* tp) { - if (tp->get()) return GCPolicy::needsSweep(tp->get()); + if (tp->get()) { + return GCPolicy::needsSweep(tp->get()); + } return false; } static bool isValid(const mozilla::UniquePtr& t) { - if (t.get()) return GCPolicy::isValid(*t.get()); + if (t.get()) { + return GCPolicy::isValid(*t.get()); + } return true; } }; @@ -172,16 +182,21 @@ // when the Maybe is full. template struct GCPolicy> { - static mozilla::Maybe initial() { return mozilla::Maybe(); } static void trace(JSTracer* trc, mozilla::Maybe* tp, const char* name) { - if (tp->isSome()) GCPolicy::trace(trc, tp->ptr(), name); + if (tp->isSome()) { + GCPolicy::trace(trc, tp->ptr(), name); + } } static bool needsSweep(mozilla::Maybe* tp) { - if (tp->isSome()) return GCPolicy::needsSweep(tp->ptr()); + if (tp->isSome()) { + return GCPolicy::needsSweep(tp->ptr()); + } return false; } static bool isValid(const mozilla::Maybe& t) { - if (t.isSome()) return GCPolicy::isValid(t.ref()); + if (t.isSome()) { + return GCPolicy::isValid(t.ref()); + } return true; } }; Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCVariant.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCVariant.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCVariant.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -47,8 +47,7 @@ template static void trace(JSTracer* trc, ConcreteVariant* v, const char* name) { T& thing = v->template as(); - if (!mozilla::IsPointer::value || thing) - GCPolicy::trace(trc, &thing, name); + GCPolicy::trace(trc, &thing, name); } template @@ -75,8 +74,7 @@ static void trace(JSTracer* trc, ConcreteVariant* v, const char* name) { if (v->template is()) { T& thing = v->template as(); - if (!mozilla::IsPointer::value || thing) - GCPolicy::trace(trc, &thing, name); + GCPolicy::trace(trc, &thing, name); } else { Next::trace(trc, v, name); } @@ -109,25 +107,17 @@ struct GCPolicy> { using Impl = detail::GCVariantImplementation; - // Variants do not provide initial(). They do not have a default initial - // value and one must be provided. - static void trace(JSTracer* trc, mozilla::Variant* v, const char* name) { Impl::trace(trc, v, name); } static bool isValid(const mozilla::Variant& v) { - return v.match(IsValidMatcher()); + return v.match([](auto& v) { + return GCPolicy< + typename mozilla::RemoveReference::Type>::isValid(v); + }); } - - private: - struct IsValidMatcher { - template - bool match(T& v) { - return GCPolicy::isValid(v); - }; - }; }; } // namespace JS Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCVector.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCVector.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCVector.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -38,10 +38,10 @@ public: explicit GCVector(AllocPolicy alloc = AllocPolicy()) : vector(alloc) {} - GCVector(GCVector&& vec) : vector(mozilla::Move(vec.vector)) {} + GCVector(GCVector&& vec) : vector(std::move(vec.vector)) {} GCVector& operator=(GCVector&& vec) { - vector = mozilla::Move(vec.vector); + vector = std::move(vec.vector); return *this; } @@ -72,17 +72,17 @@ template bool append(U&& item) { - return vector.append(mozilla::Forward(item)); + return vector.append(std::forward(item)); } template MOZ_MUST_USE bool emplaceBack(Args&&... args) { - return vector.emplaceBack(mozilla::Forward(args)...); + return vector.emplaceBack(std::forward(args)...); } template void infallibleAppend(U&& aU) { - return vector.infallibleAppend(mozilla::Forward(aU)); + return vector.infallibleAppend(std::forward(aU)); } void infallibleAppendN(const T& aT, size_t aN) { return vector.infallibleAppendN(aT, aN); @@ -128,7 +128,9 @@ static void trace(GCVector* vec, JSTracer* trc) { vec->trace(trc); } void trace(JSTracer* trc) { - for (auto& elem : vector) GCPolicy::trace(trc, &elem, "vector element"); + for (auto& elem : vector) { + GCPolicy::trace(trc, &elem, "vector element"); + } } bool needsSweep() const { return !this->empty(); } @@ -137,15 +139,30 @@ uint32_t src, dst = 0; for (src = 0; src < length(); src++) { if (!GCPolicy::needsSweep(&vector[src])) { - if (dst != src) vector[dst] = vector[src].unbarrieredGet(); + if (dst != src) { + vector[dst] = vector[src].unbarrieredGet(); + } dst++; } } - if (dst != length()) vector.shrinkTo(dst); + if (dst != length()) { + vector.shrinkTo(dst); + } } }; +// AllocPolicy is optional. It has a default value declared in TypeDecls.h +template +class MOZ_STACK_CLASS StackGCVector : public GCVector { + public: + using Base = GCVector; + + private: + // Inherit constructor from GCVector. + using Base::Base; +}; + } // namespace JS namespace js { @@ -217,11 +234,11 @@ void clearAndFree() { vec().clearAndFree(); } template MOZ_MUST_USE bool append(U&& aU) { - return vec().append(mozilla::Forward(aU)); + return vec().append(std::forward(aU)); } template MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) { - return vec().emplaceBack(mozilla::Forward(aArgs...)); + return vec().emplaceBack(std::forward(aArgs)...); } template MOZ_MUST_USE bool appendAll(const U& aU) { @@ -240,7 +257,7 @@ } template void infallibleAppend(U&& aU) { - vec().infallibleAppend(mozilla::Forward(aU)); + vec().infallibleAppend(std::forward(aU)); } void infallibleAppendN(const T& aT, size_t aN) { vec().infallibleAppendN(aT, aN); @@ -257,24 +274,45 @@ T popCopy() { return vec().popCopy(); } template T* insert(T* aP, U&& aVal) { - return vec().insert(aP, mozilla::Forward(aVal)); + return vec().insert(aP, std::forward(aVal)); } void erase(T* aT) { vec().erase(aT); } void erase(T* aBegin, T* aEnd) { vec().erase(aBegin, aEnd); } }; +template +class WrappedPtrOperations, Wrapper> + : public WrappedPtrOperations< + typename JS::StackGCVector::Base, Wrapper> {}; + +template +class MutableWrappedPtrOperations, Wrapper> + : public MutableWrappedPtrOperations< + typename JS::StackGCVector::Base, Wrapper> {}; + } // namespace js namespace JS { -// An automatically rooted vector for stack use. +// An automatically rooted GCVector for stack use. template -class AutoVector : public Rooted> { - using Vec = GCVector; +class RootedVector : public Rooted> { + using Vec = StackGCVector; using Base = Rooted; public: - explicit AutoVector(JSContext* cx) : Base(cx, Vec(cx)) {} + explicit RootedVector(JSContext* cx) : Base(cx, Vec(cx)) {} +}; + +// For use in rust code, an analog to RootedVector that doesn't require +// instances to be destroyed in LIFO order. +template +class PersistentRootedVector : public PersistentRooted> { + using Vec = StackGCVector; + using Base = PersistentRooted; + + public: + explicit PersistentRootedVector(JSContext* cx) : Base(cx, Vec(cx)) {} }; } // namespace JS Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/HashTable.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/HashTable.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/HashTable.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -7,1816 +7,32 @@ #ifndef js_HashTable_h #define js_HashTable_h -#include "mozilla/Alignment.h" -#include "mozilla/Assertions.h" -#include "mozilla/Attributes.h" -#include "mozilla/Casting.h" -#include "mozilla/HashFunctions.h" -#include "mozilla/MemoryReporting.h" -#include "mozilla/Move.h" -#include "mozilla/Opaque.h" -#include "mozilla/PodOperations.h" -#include "mozilla/ReentrancyGuard.h" -#include "mozilla/TemplateLib.h" -#include "mozilla/TypeTraits.h" -#include "mozilla/UniquePtr.h" +#include "mozilla/HashTable.h" -#include "js/Utility.h" +#include "jstypes.h" namespace js { -class TempAllocPolicy; -template -struct DefaultHasher; -template -class HashMapEntry; -namespace detail { -template -class HashTableEntry; -template -class HashTable; -} // namespace detail - -/*****************************************************************************/ - -// The "generation" of a hash table is an opaque value indicating the state of -// modification of the hash table through its lifetime. If the generation of -// a hash table compares equal at times T1 and T2, then lookups in the hash -// table, pointers to (or into) hash table entries, etc. at time T1 are valid -// at time T2. If the generation compares unequal, these computations are all -// invalid and must be performed again to be used. -// -// Generations are meaningfully comparable only with respect to a single hash -// table. It's always nonsensical to compare the generation of distinct hash -// tables H1 and H2. -using Generation = mozilla::Opaque; - -// A JS-friendly, STL-like container providing a hash-based map from keys to -// values. In particular, HashMap calls constructors and destructors of all -// objects added so non-PODs may be used safely. -// -// Key/Value requirements: -// - movable, destructible, assignable -// HashPolicy requirements: -// - see Hash Policy section below -// AllocPolicy: -// - see AllocPolicy.h -// -// Note: -// - HashMap is not reentrant: Key/Value/HashPolicy/AllocPolicy members -// called by HashMap must not call back into the same HashMap object. -// - Due to the lack of exception handling, the user must call |init()|. -template , - class AllocPolicy = TempAllocPolicy> -class HashMap { - typedef HashMapEntry TableEntry; - - struct MapHashPolicy : HashPolicy { - using Base = HashPolicy; - typedef Key KeyType; - static const Key& getKey(TableEntry& e) { return e.key(); } - static void setKey(TableEntry& e, Key& k) { - HashPolicy::rekey(e.mutableKey(), k); - } - }; - - typedef detail::HashTable Impl; - Impl impl; - - public: - typedef typename HashPolicy::Lookup Lookup; - typedef TableEntry Entry; - - // HashMap construction is fallible (due to OOM); thus the user must call - // init after constructing a HashMap and check the return value. - explicit HashMap(AllocPolicy a = AllocPolicy()) : impl(a) {} - MOZ_MUST_USE bool init(uint32_t len = 16) { return impl.init(len); } - bool initialized() const { return impl.initialized(); } - - // Return whether the given lookup value is present in the map. E.g.: - // - // typedef HashMap HM; - // HM h; - // if (HM::Ptr p = h.lookup(3)) { - // const HM::Entry& e = *p; // p acts like a pointer to Entry - // assert(p->key == 3); // Entry contains the key - // char val = p->value; // and value - // } - // - // Also see the definition of Ptr in HashTable above (with T = Entry). - typedef typename Impl::Ptr Ptr; - MOZ_ALWAYS_INLINE Ptr lookup(const Lookup& l) const { return impl.lookup(l); } - - // Like lookup, but does not assert if two threads call lookup at the same - // time. Only use this method when none of the threads will modify the map. - MOZ_ALWAYS_INLINE Ptr readonlyThreadsafeLookup(const Lookup& l) const { - return impl.readonlyThreadsafeLookup(l); - } - - // Assuming |p.found()|, remove |*p|. - void remove(Ptr p) { impl.remove(p); } - - // Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient - // insertion of Key |k| (where |HashPolicy::match(k,l) == true|) using - // |add(p,k,v)|. After |add(p,k,v)|, |p| points to the new Entry. E.g.: - // - // typedef HashMap HM; - // HM h; - // HM::AddPtr p = h.lookupForAdd(3); - // if (!p) { - // if (!h.add(p, 3, 'a')) - // return false; - // } - // const HM::Entry& e = *p; // p acts like a pointer to Entry - // assert(p->key == 3); // Entry contains the key - // char val = p->value; // and value - // - // Also see the definition of AddPtr in HashTable above (with T = Entry). - // - // N.B. The caller must ensure that no mutating hash table operations - // occur between a pair of |lookupForAdd| and |add| calls. To avoid - // looking up the key a second time, the caller may use the more efficient - // relookupOrAdd method. This method reuses part of the hashing computation - // to more efficiently insert the key if it has not been added. For - // example, a mutation-handling version of the previous example: - // - // HM::AddPtr p = h.lookupForAdd(3); - // if (!p) { - // call_that_may_mutate_h(); - // if (!h.relookupOrAdd(p, 3, 'a')) - // return false; - // } - // const HM::Entry& e = *p; - // assert(p->key == 3); - // char val = p->value; - typedef typename Impl::AddPtr AddPtr; - MOZ_ALWAYS_INLINE AddPtr lookupForAdd(const Lookup& l) const { - return impl.lookupForAdd(l); - } - - template - MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { - return impl.add(p, mozilla::Forward(k), - mozilla::Forward(v)); - } - - template - MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k) { - return impl.add(p, mozilla::Forward(k), Value()); - } - - template - MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { - return impl.relookupOrAdd(p, k, mozilla::Forward(k), - mozilla::Forward(v)); - } - - // |all()| returns a Range containing |count()| elements. E.g.: - // - // typedef HashMap HM; - // HM h; - // for (HM::Range r = h.all(); !r.empty(); r.popFront()) - // char c = r.front().value(); - // - // Also see the definition of Range in HashTable above (with T = Entry). - typedef typename Impl::Range Range; - Range all() const { return impl.all(); } - - // Typedef for the enumeration class. An Enum may be used to examine and - // remove table entries: - // - // typedef HashMap HM; - // HM s; - // for (HM::Enum e(s); !e.empty(); e.popFront()) - // if (e.front().value() == 'l') - // e.removeFront(); - // - // Table resize may occur in Enum's destructor. Also see the definition of - // Enum in HashTable above (with T = Entry). - typedef typename Impl::Enum Enum; - - // Remove all entries. This does not shrink the table. For that consider - // using the finish() method. - void clear() { impl.clear(); } - - // Remove all entries. Unlike clear() this method tries to shrink the table. - // Unlike finish() it does not require the map to be initialized again. - void clearAndShrink() { impl.clearAndShrink(); } - - // Remove all the entries and release all internal buffers. The map must - // be initialized again before any use. - void finish() { impl.finish(); } - - // Does the table contain any entries? - bool empty() const { return impl.empty(); } - - // Number of live elements in the map. - uint32_t count() const { return impl.count(); } - - // Total number of allocation in the dynamic table. Note: resize will - // happen well before count() == capacity(). - size_t capacity() const { return impl.capacity(); } - - // Don't just call |impl.sizeOfExcludingThis()| because there's no - // guarantee that |impl| is the first field in HashMap. - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return impl.sizeOfExcludingThis(mallocSizeOf); - } - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); - } - - Generation generation() const { return impl.generation(); } - - /************************************************** Shorthand operations */ - - bool has(const Lookup& l) const { return impl.lookup(l).found(); } - - // Overwrite existing value with v. Return false on oom. - template - MOZ_MUST_USE bool put(KeyInput&& k, ValueInput&& v) { - AddPtr p = lookupForAdd(k); - if (p) { - p->value() = mozilla::Forward(v); - return true; - } - return add(p, mozilla::Forward(k), - mozilla::Forward(v)); - } - - // Like put, but assert that the given key is not already present. - template - MOZ_MUST_USE bool putNew(KeyInput&& k, ValueInput&& v) { - return impl.putNew(k, mozilla::Forward(k), - mozilla::Forward(v)); - } - - // Only call this to populate an empty map after reserving space with init(). - template - void putNewInfallible(KeyInput&& k, ValueInput&& v) { - impl.putNewInfallible(k, mozilla::Forward(k), - mozilla::Forward(v)); - } - - // Add (k,defaultValue) if |k| is not found. Return a false-y Ptr on oom. - Ptr lookupWithDefault(const Key& k, const Value& defaultValue) { - AddPtr p = lookupForAdd(k); - if (p) return p; - bool ok = add(p, k, defaultValue); - MOZ_ASSERT_IF(!ok, !p); // p is left false-y on oom. - (void)ok; - return p; - } - - // Remove if present. - void remove(const Lookup& l) { - if (Ptr p = lookup(l)) remove(p); - } - - // Infallibly rekey one entry, if necessary. - // Requires template parameters Key and HashPolicy::Lookup to be the same - // type. - void rekeyIfMoved(const Key& old_key, const Key& new_key) { - if (old_key != new_key) rekeyAs(old_key, new_key, new_key); - } - - // Infallibly rekey one entry if present, and return whether that happened. - bool rekeyAs(const Lookup& old_lookup, const Lookup& new_lookup, - const Key& new_key) { - if (Ptr p = lookup(old_lookup)) { - impl.rekeyAndMaybeRehash(p, new_lookup, new_key); - return true; - } - return false; - } - - // HashMap is movable - HashMap(HashMap&& rhs) : impl(mozilla::Move(rhs.impl)) {} - void operator=(HashMap&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - impl = mozilla::Move(rhs.impl); - } - - private: - // HashMap is not copyable or assignable - HashMap(const HashMap& hm) = delete; - HashMap& operator=(const HashMap& hm) = delete; - - friend class Impl::Enum; -}; - -/*****************************************************************************/ - -// A JS-friendly, STL-like container providing a hash-based set of values. In -// particular, HashSet calls constructors and destructors of all objects added -// so non-PODs may be used safely. -// -// T requirements: -// - movable, destructible, assignable -// HashPolicy requirements: -// - see Hash Policy section below -// AllocPolicy: -// - see AllocPolicy.h -// -// Note: -// - HashSet is not reentrant: T/HashPolicy/AllocPolicy members called by -// HashSet must not call back into the same HashSet object. -// - Due to the lack of exception handling, the user must call |init()|. -template , - class AllocPolicy = TempAllocPolicy> -class HashSet { - struct SetOps : HashPolicy { - using Base = HashPolicy; - typedef T KeyType; - static const KeyType& getKey(const T& t) { return t; } - static void setKey(T& t, KeyType& k) { HashPolicy::rekey(t, k); } - }; - - typedef detail::HashTable Impl; - Impl impl; - - public: - typedef typename HashPolicy::Lookup Lookup; - typedef T Entry; - - // HashSet construction is fallible (due to OOM); thus the user must call - // init after constructing a HashSet and check the return value. - explicit HashSet(AllocPolicy a = AllocPolicy()) : impl(a) {} - MOZ_MUST_USE bool init(uint32_t len = 16) { return impl.init(len); } - bool initialized() const { return impl.initialized(); } - - // Return whether the given lookup value is present in the map. E.g.: - // - // typedef HashSet HS; - // HS h; - // if (HS::Ptr p = h.lookup(3)) { - // assert(*p == 3); // p acts like a pointer to int - // } - // - // Also see the definition of Ptr in HashTable above. - typedef typename Impl::Ptr Ptr; - MOZ_ALWAYS_INLINE Ptr lookup(const Lookup& l) const { return impl.lookup(l); } - - // Like lookup, but does not assert if two threads call lookup at the same - // time. Only use this method when none of the threads will modify the map. - MOZ_ALWAYS_INLINE Ptr readonlyThreadsafeLookup(const Lookup& l) const { - return impl.readonlyThreadsafeLookup(l); - } - - // Assuming |p.found()|, remove |*p|. - void remove(Ptr p) { impl.remove(p); } - - // Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient - // insertion of T value |t| (where |HashPolicy::match(t,l) == true|) using - // |add(p,t)|. After |add(p,t)|, |p| points to the new element. E.g.: - // - // typedef HashSet HS; - // HS h; - // HS::AddPtr p = h.lookupForAdd(3); - // if (!p) { - // if (!h.add(p, 3)) - // return false; - // } - // assert(*p == 3); // p acts like a pointer to int - // - // Also see the definition of AddPtr in HashTable above. - // - // N.B. The caller must ensure that no mutating hash table operations - // occur between a pair of |lookupForAdd| and |add| calls. To avoid - // looking up the key a second time, the caller may use the more efficient - // relookupOrAdd method. This method reuses part of the hashing computation - // to more efficiently insert the key if it has not been added. For - // example, a mutation-handling version of the previous example: - // - // HS::AddPtr p = h.lookupForAdd(3); - // if (!p) { - // call_that_may_mutate_h(); - // if (!h.relookupOrAdd(p, 3, 3)) - // return false; - // } - // assert(*p == 3); - // - // Note that relookupOrAdd(p,l,t) performs Lookup using |l| and adds the - // entry |t|, where the caller ensures match(l,t). - typedef typename Impl::AddPtr AddPtr; - MOZ_ALWAYS_INLINE AddPtr lookupForAdd(const Lookup& l) const { - return impl.lookupForAdd(l); - } - - template - MOZ_MUST_USE bool add(AddPtr& p, U&& u) { - return impl.add(p, mozilla::Forward(u)); - } - - template - MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, U&& u) { - return impl.relookupOrAdd(p, l, mozilla::Forward(u)); - } - - // |all()| returns a Range containing |count()| elements: - // - // typedef HashSet HS; - // HS h; - // for (HS::Range r = h.all(); !r.empty(); r.popFront()) - // int i = r.front(); - // - // Also see the definition of Range in HashTable above. - typedef typename Impl::Range Range; - Range all() const { return impl.all(); } - - // Typedef for the enumeration class. An Enum may be used to examine and - // remove table entries: - // - // typedef HashSet HS; - // HS s; - // for (HS::Enum e(s); !e.empty(); e.popFront()) - // if (e.front() == 42) - // e.removeFront(); - // - // Table resize may occur in Enum's destructor. Also see the definition of - // Enum in HashTable above. - typedef typename Impl::Enum Enum; - - // Remove all entries. This does not shrink the table. For that consider - // using the finish() method. - void clear() { impl.clear(); } - - // Remove all entries. Unlike clear() this method tries to shrink the table. - // Unlike finish() it does not require the set to be initialized again. - void clearAndShrink() { impl.clearAndShrink(); } - - // Remove all the entries and release all internal buffers. The set must - // be initialized again before any use. - void finish() { impl.finish(); } - - // Does the table contain any entries? - bool empty() const { return impl.empty(); } - - // Number of live elements in the map. - uint32_t count() const { return impl.count(); } - - // Total number of allocation in the dynamic table. Note: resize will - // happen well before count() == capacity(). - size_t capacity() const { return impl.capacity(); } - - // Don't just call |impl.sizeOfExcludingThis()| because there's no - // guarantee that |impl| is the first field in HashSet. - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return impl.sizeOfExcludingThis(mallocSizeOf); - } - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); - } - - Generation generation() const { return impl.generation(); } - - /************************************************** Shorthand operations */ - - bool has(const Lookup& l) const { return impl.lookup(l).found(); } - - // Add |u| if it is not present already. Return false on oom. - template - MOZ_MUST_USE bool put(U&& u) { - AddPtr p = lookupForAdd(u); - return p ? true : add(p, mozilla::Forward(u)); - } - - // Like put, but assert that the given key is not already present. - template - MOZ_MUST_USE bool putNew(U&& u) { - return impl.putNew(u, mozilla::Forward(u)); - } - - template - MOZ_MUST_USE bool putNew(const Lookup& l, U&& u) { - return impl.putNew(l, mozilla::Forward(u)); - } - - // Only call this to populate an empty set after reserving space with init(). - template - void putNewInfallible(const Lookup& l, U&& u) { - impl.putNewInfallible(l, mozilla::Forward(u)); - } +using HashNumber = mozilla::HashNumber; +static const uint32_t kHashNumberBits = mozilla::kHashNumberBits; - void remove(const Lookup& l) { - if (Ptr p = lookup(l)) remove(p); - } - - // Infallibly rekey one entry, if present. - // Requires template parameters T and HashPolicy::Lookup to be the same type. - void rekeyIfMoved(const Lookup& old_value, const T& new_value) { - if (old_value != new_value) rekeyAs(old_value, new_value, new_value); - } - - // Infallibly rekey one entry if present, and return whether that happened. - bool rekeyAs(const Lookup& old_lookup, const Lookup& new_lookup, - const T& new_value) { - if (Ptr p = lookup(old_lookup)) { - impl.rekeyAndMaybeRehash(p, new_lookup, new_value); - return true; - } - return false; - } - - // Infallibly replace the current key at |p| with an equivalent key. - // Specifically, both HashPolicy::hash and HashPolicy::match must return - // identical results for the new and old key when applied against all - // possible matching values. - void replaceKey(Ptr p, const T& new_value) { - MOZ_ASSERT(p.found()); - MOZ_ASSERT(*p != new_value); - MOZ_ASSERT(HashPolicy::hash(*p) == HashPolicy::hash(new_value)); - MOZ_ASSERT(HashPolicy::match(*p, new_value)); - const_cast(*p) = new_value; - } - - // HashSet is movable - HashSet(HashSet&& rhs) : impl(mozilla::Move(rhs.impl)) {} - void operator=(HashSet&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - impl = mozilla::Move(rhs.impl); - } - - private: - // HashSet is not copyable or assignable - HashSet(const HashSet& hs) = delete; - HashSet& operator=(const HashSet& hs) = delete; - - friend class Impl::Enum; -}; - -/*****************************************************************************/ - -// Hash Policy -// -// A hash policy P for a hash table with key-type Key must provide: -// - a type |P::Lookup| to use to lookup table entries; -// - a static member function |P::hash| with signature -// -// static js::HashNumber hash(Lookup) -// -// to use to hash the lookup type; and -// - a static member function |P::match| with signature -// -// static bool match(Key, Lookup) -// -// to use to test equality of key and lookup values. -// -// Normally, Lookup = Key. In general, though, different values and types of -// values can be used to lookup and store. If a Lookup value |l| is != to the -// added Key value |k|, the user must ensure that |P::match(k,l)|. E.g.: -// -// js::HashSet::AddPtr p = h.lookup(l); -// if (!p) { -// assert(P::match(k, l)); // must hold -// h.add(p, k); -// } - -// Pointer hashing policy that uses HashGeneric() to create good hashes for -// pointers. Note that we don't shift out the lowest k bits to generate a -// good distribution for arena allocated pointers. -template -struct PointerHasher { - typedef Key Lookup; - static HashNumber hash(const Lookup& l) { - size_t word = reinterpret_cast(l); - return mozilla::HashGeneric(word); - } - static bool match(const Key& k, const Lookup& l) { return k == l; } - static void rekey(Key& k, const Key& newKey) { k = newKey; } -}; - -// Default hash policy: just use the 'lookup' value. This of course only -// works if the lookup value is integral. HashTable applies ScrambleHashCode to -// the result of the 'hash' which means that it is 'ok' if the lookup value is -// not well distributed over the HashNumber domain. -template -struct DefaultHasher { - typedef Key Lookup; - static HashNumber hash(const Lookup& l) { - // Hash if can implicitly cast to hash number type. - return l; - } - static bool match(const Key& k, const Lookup& l) { - // Use builtin or overloaded operator==. - return k == l; - } - static void rekey(Key& k, const Key& newKey) { k = newKey; } -}; - -// Specialize hashing policy for pointer types. It assumes that the type is -// at least word-aligned. For types with smaller size use PointerHasher. -template -struct DefaultHasher : PointerHasher {}; - -// Specialize hashing policy for mozilla::UniquePtr to proxy the UniquePtr's -// raw pointer to PointerHasher. -template -struct DefaultHasher> { - using Lookup = mozilla::UniquePtr; - using PtrHasher = PointerHasher; - - static HashNumber hash(const Lookup& l) { return PtrHasher::hash(l.get()); } - static bool match(const mozilla::UniquePtr& k, const Lookup& l) { - return PtrHasher::match(k.get(), l.get()); - } - static void rekey(mozilla::UniquePtr& k, - mozilla::UniquePtr&& newKey) { - k = mozilla::Move(newKey); - } -}; - -// For doubles, we can xor the two uint32s. -template <> -struct DefaultHasher { - typedef double Lookup; - static HashNumber hash(double d) { - static_assert(sizeof(HashNumber) == 4, - "subsequent code assumes a four-byte hash"); - uint64_t u = mozilla::BitwiseCast(d); - return HashNumber(u ^ (u >> 32)); - } - static bool match(double lhs, double rhs) { - return mozilla::BitwiseCast(lhs) == - mozilla::BitwiseCast(rhs); - } -}; - -template <> -struct DefaultHasher { - typedef float Lookup; - static HashNumber hash(float f) { - static_assert(sizeof(HashNumber) == 4, - "subsequent code assumes a four-byte hash"); - return HashNumber(mozilla::BitwiseCast(f)); - } - static bool match(float lhs, float rhs) { - return mozilla::BitwiseCast(lhs) == - mozilla::BitwiseCast(rhs); - } -}; - -// A hash policy that compares C strings. -struct CStringHasher { - typedef const char* Lookup; - static js::HashNumber hash(Lookup l) { return mozilla::HashString(l); } - static bool match(const char* key, Lookup lookup) { - return strcmp(key, lookup) == 0; - } -}; - -// Fallible hashing interface. -// -// Most of the time generating a hash code is infallible so this class provides -// default methods that always succeed. Specialize this class for your own hash -// policy to provide fallible hashing. -// -// This is used by MovableCellHasher to handle the fact that generating a unique -// ID for cell pointer may fail due to OOM. -template -struct FallibleHashMethods { - // Return true if a hashcode is already available for its argument. Once - // this returns true for a specific argument it must continue to do so. - template - static bool hasHash(Lookup&& l) { - return true; - } - - // Fallible method to ensure a hashcode exists for its argument and create - // one if not. Returns false on error, e.g. out of memory. - template - static bool ensureHash(Lookup&& l) { - return true; - } -}; - -template -static bool HasHash(Lookup&& l) { - return FallibleHashMethods::hasHash( - mozilla::Forward(l)); -} - -template -static bool EnsureHash(Lookup&& l) { - return FallibleHashMethods::ensureHash( - mozilla::Forward(l)); -} - -/*****************************************************************************/ - -// Both HashMap and HashSet are implemented by a single HashTable that is even -// more heavily parameterized than the other two. This leaves HashTable gnarly -// and extremely coupled to HashMap and HashSet; thus code should not use -// HashTable directly. - -template -class HashMapEntry { - Key key_; - Value value_; - - template - friend class detail::HashTable; - template - friend class detail::HashTableEntry; - template - friend class HashMap; - - public: - template - HashMapEntry(KeyInput&& k, ValueInput&& v) - : key_(mozilla::Forward(k)), - value_(mozilla::Forward(v)) {} - - HashMapEntry(HashMapEntry&& rhs) - : key_(mozilla::Move(rhs.key_)), value_(mozilla::Move(rhs.value_)) {} - - void operator=(HashMapEntry&& rhs) { - key_ = mozilla::Move(rhs.key_); - value_ = mozilla::Move(rhs.value_); - } - - typedef Key KeyType; - typedef Value ValueType; - - const Key& key() const { return key_; } - Key& mutableKey() { return key_; } - const Value& value() const { return value_; } - Value& value() { return value_; } - - private: - HashMapEntry(const HashMapEntry&) = delete; - void operator=(const HashMapEntry&) = delete; -}; - -} // namespace js - -namespace mozilla { - -template -struct IsPod> : IsPod {}; - -template -struct IsPod> - : IntegralConstant::value && IsPod::value> {}; - -} // namespace mozilla - -namespace js { - -namespace detail { - -template -class HashTable; +class JS_PUBLIC_API TempAllocPolicy; template -class HashTableEntry { - template - friend class HashTable; - typedef typename mozilla::RemoveConst::Type NonConstT; - - HashNumber keyHash; - mozilla::AlignedStorage2 mem; - - static const HashNumber sFreeKey = 0; - static const HashNumber sRemovedKey = 1; - static const HashNumber sCollisionBit = 1; - - static bool isLiveHash(HashNumber hash) { return hash > sRemovedKey; } - - HashTableEntry(const HashTableEntry&) = delete; - void operator=(const HashTableEntry&) = delete; - ~HashTableEntry() = delete; - - public: - // NB: HashTableEntry is treated as a POD: no constructor or destructor calls. - - void destroyIfLive() { - if (isLive()) mem.addr()->~T(); - } - - void destroy() { - MOZ_ASSERT(isLive()); - mem.addr()->~T(); - } - - void swap(HashTableEntry* other) { - if (this == other) return; - MOZ_ASSERT(isLive()); - if (other->isLive()) { - mozilla::Swap(*mem.addr(), *other->mem.addr()); - } else { - *other->mem.addr() = mozilla::Move(*mem.addr()); - destroy(); - } - mozilla::Swap(keyHash, other->keyHash); - } - - T& get() { - MOZ_ASSERT(isLive()); - return *mem.addr(); - } - NonConstT& getMutable() { - MOZ_ASSERT(isLive()); - return *mem.addr(); - } - - bool isFree() const { return keyHash == sFreeKey; } - void clearLive() { - MOZ_ASSERT(isLive()); - keyHash = sFreeKey; - mem.addr()->~T(); - } - void clear() { - if (isLive()) mem.addr()->~T(); - keyHash = sFreeKey; - } - bool isRemoved() const { return keyHash == sRemovedKey; } - void removeLive() { - MOZ_ASSERT(isLive()); - keyHash = sRemovedKey; - mem.addr()->~T(); - } - bool isLive() const { return isLiveHash(keyHash); } - void setCollision() { - MOZ_ASSERT(isLive()); - keyHash |= sCollisionBit; - } - void unsetCollision() { keyHash &= ~sCollisionBit; } - bool hasCollision() const { return keyHash & sCollisionBit; } - bool matchHash(HashNumber hn) { return (keyHash & ~sCollisionBit) == hn; } - HashNumber getKeyHash() const { return keyHash & ~sCollisionBit; } - - template - void setLive(HashNumber hn, Args&&... args) { - MOZ_ASSERT(!isLive()); - keyHash = hn; - new (mem.addr()) T(mozilla::Forward(args)...); - MOZ_ASSERT(isLive()); - } -}; - -template -class HashTable : private AllocPolicy { - friend class mozilla::ReentrancyGuard; - - typedef typename mozilla::RemoveConst::Type NonConstT; - typedef typename HashPolicy::KeyType Key; - typedef typename HashPolicy::Lookup Lookup; - - public: - typedef HashTableEntry Entry; - - // A nullable pointer to a hash table element. A Ptr |p| can be tested - // either explicitly |if (p.found()) p->...| or using boolean conversion - // |if (p) p->...|. Ptr objects must not be used after any mutating hash - // table operations unless |generation()| is tested. - class Ptr { - friend class HashTable; - - Entry* entry_; -#ifdef JS_DEBUG - const HashTable* table_; - Generation generation; -#endif - - protected: - Ptr(Entry& entry, const HashTable& tableArg) - : entry_(&entry) -#ifdef JS_DEBUG - , - table_(&tableArg), - generation(tableArg.generation()) -#endif - { - } - - public: - Ptr() - : entry_(nullptr) -#ifdef JS_DEBUG - , - table_(nullptr), - generation(0) -#endif - { - } - - bool isValid() const { return !!entry_; } - - bool found() const { - if (!isValid()) return false; -#ifdef JS_DEBUG - MOZ_ASSERT(generation == table_->generation()); -#endif - return entry_->isLive(); - } - - explicit operator bool() const { return found(); } - - bool operator==(const Ptr& rhs) const { - MOZ_ASSERT(found() && rhs.found()); - return entry_ == rhs.entry_; - } - - bool operator!=(const Ptr& rhs) const { -#ifdef JS_DEBUG - MOZ_ASSERT(generation == table_->generation()); -#endif - return !(*this == rhs); - } - - T& operator*() const { -#ifdef JS_DEBUG - MOZ_ASSERT(found()); - MOZ_ASSERT(generation == table_->generation()); -#endif - return entry_->get(); - } +using DefaultHasher = mozilla::DefaultHasher; - T* operator->() const { -#ifdef JS_DEBUG - MOZ_ASSERT(found()); - MOZ_ASSERT(generation == table_->generation()); -#endif - return &entry_->get(); - } - }; - - // A Ptr that can be used to add a key after a failed lookup. - class AddPtr : public Ptr { - friend class HashTable; - HashNumber keyHash; -#ifdef JS_DEBUG - uint64_t mutationCount; -#endif - - AddPtr(Entry& entry, const HashTable& tableArg, HashNumber hn) - : Ptr(entry, tableArg), - keyHash(hn) -#ifdef JS_DEBUG - , - mutationCount(tableArg.mutationCount) -#endif - { - } - - public: - AddPtr() : keyHash(0) {} - }; - - // A collection of hash table entries. The collection is enumerated by - // calling |front()| followed by |popFront()| as long as |!empty()|. As - // with Ptr/AddPtr, Range objects must not be used after any mutating hash - // table operation unless the |generation()| is tested. - class Range { - protected: - friend class HashTable; - - Range(const HashTable& tableArg, Entry* c, Entry* e) - : cur(c), - end(e) -#ifdef JS_DEBUG - , - table_(&tableArg), - mutationCount(tableArg.mutationCount), - generation(tableArg.generation()), - validEntry(true) -#endif - { - while (cur < end && !cur->isLive()) ++cur; - } - - Entry* cur; - Entry* end; -#ifdef JS_DEBUG - const HashTable* table_; - uint64_t mutationCount; - Generation generation; - bool validEntry; -#endif - - public: - Range() - : cur(nullptr), - end(nullptr) -#ifdef JS_DEBUG - , - table_(nullptr), - mutationCount(0), - generation(0), - validEntry(false) -#endif - { - } - - bool empty() const { -#ifdef JS_DEBUG - MOZ_ASSERT(generation == table_->generation()); - MOZ_ASSERT(mutationCount == table_->mutationCount); -#endif - return cur == end; - } - - T& front() const { - MOZ_ASSERT(!empty()); -#ifdef JS_DEBUG - MOZ_ASSERT(validEntry); - MOZ_ASSERT(generation == table_->generation()); - MOZ_ASSERT(mutationCount == table_->mutationCount); -#endif - return cur->get(); - } - - void popFront() { - MOZ_ASSERT(!empty()); -#ifdef JS_DEBUG - MOZ_ASSERT(generation == table_->generation()); - MOZ_ASSERT(mutationCount == table_->mutationCount); -#endif - while (++cur < end && !cur->isLive()) continue; -#ifdef JS_DEBUG - validEntry = true; -#endif - } - }; - - // A Range whose lifetime delimits a mutating enumeration of a hash table. - // Since rehashing when elements were removed during enumeration would be - // bad, it is postponed until the Enum is destructed. Since the Enum's - // destructor touches the hash table, the user must ensure that the hash - // table is still alive when the destructor runs. - class Enum : public Range { - friend class HashTable; - - HashTable& table_; - bool rekeyed; - bool removed; - - // Enum is movable but not copyable. - Enum(const Enum&) = delete; - void operator=(const Enum&) = delete; - - public: - template - explicit Enum(Map& map) - : Range(map.all()), table_(map.impl), rekeyed(false), removed(false) {} - - MOZ_IMPLICIT Enum(Enum&& other) - : Range(other), - table_(other.table_), - rekeyed(other.rekeyed), - removed(other.removed) { - other.rekeyed = false; - other.removed = false; - } - - // Removes the |front()| element from the table, leaving |front()| - // invalid until the next call to |popFront()|. For example: - // - // HashSet s; - // for (HashSet::Enum e(s); !e.empty(); e.popFront()) - // if (e.front() == 42) - // e.removeFront(); - void removeFront() { - table_.remove(*this->cur); - removed = true; -#ifdef JS_DEBUG - this->validEntry = false; - this->mutationCount = table_.mutationCount; -#endif - } - - NonConstT& mutableFront() { - MOZ_ASSERT(!this->empty()); -#ifdef JS_DEBUG - MOZ_ASSERT(this->validEntry); - MOZ_ASSERT(this->generation == this->Range::table_->generation()); - MOZ_ASSERT(this->mutationCount == this->Range::table_->mutationCount); -#endif - return this->cur->getMutable(); - } - - // Removes the |front()| element and re-inserts it into the table with - // a new key at the new Lookup position. |front()| is invalid after - // this operation until the next call to |popFront()|. - void rekeyFront(const Lookup& l, const Key& k) { - MOZ_ASSERT(&k != &HashPolicy::getKey(this->cur->get())); - Ptr p(*this->cur, table_); - table_.rekeyWithoutRehash(p, l, k); - rekeyed = true; -#ifdef JS_DEBUG - this->validEntry = false; - this->mutationCount = table_.mutationCount; -#endif - } - - void rekeyFront(const Key& k) { rekeyFront(k, k); } - - // Potentially rehashes the table. - ~Enum() { - if (rekeyed) { - table_.gen++; - table_.checkOverRemoved(); - } - - if (removed) table_.compactIfUnderloaded(); - } - }; - - // HashTable is movable - HashTable(HashTable&& rhs) : AllocPolicy(rhs) { - mozilla::PodAssign(this, &rhs); - rhs.table = nullptr; - } - void operator=(HashTable&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - if (table) destroyTable(*this, table, capacity()); - mozilla::PodAssign(this, &rhs); - rhs.table = nullptr; - } - - private: - // HashTable is not copyable or assignable - HashTable(const HashTable&) = delete; - void operator=(const HashTable&) = delete; - - private: - static const size_t CAP_BITS = 30; - - public: - uint64_t gen : 56; // entry storage generation number - uint64_t hashShift : 8; // multiplicative hash shift - Entry* table; // entry storage - uint32_t entryCount; // number of entries in table - uint32_t removedCount; // removed entry sentinels in table - -#ifdef JS_DEBUG - uint64_t mutationCount; - mutable bool mEntered; - // Note that some updates to these stats are not thread-safe. See the - // comment on the three-argument overloading of HashTable::lookup(). - mutable struct Stats { - uint32_t searches; // total number of table searches - uint32_t steps; // hash chain links traversed - uint32_t hits; // searches that found key - uint32_t misses; // searches that didn't find key - uint32_t addOverRemoved; // adds that recycled a removed entry - uint32_t removes; // calls to remove - uint32_t removeFrees; // calls to remove that freed the entry - uint32_t grows; // table expansions - uint32_t shrinks; // table contractions - uint32_t compresses; // table compressions - uint32_t rehashes; // tombstone decontaminations - } stats; -#define METER(x) x -#else -#define METER(x) -#endif - - // The default initial capacity is 32 (enough to hold 16 elements), but it - // can be as low as 4. - static const unsigned sMinCapacityLog2 = 2; - static const unsigned sMinCapacity = 1 << sMinCapacityLog2; - static const unsigned sMaxInit = JS_BIT(CAP_BITS - 1); - static const unsigned sMaxCapacity = JS_BIT(CAP_BITS); - static const unsigned sHashBits = mozilla::tl::BitSize::value; - - // Hash-table alpha is conceptually a fraction, but to avoid floating-point - // math we implement it as a ratio of integers. - static const uint8_t sAlphaDenominator = 4; - static const uint8_t sMinAlphaNumerator = 1; // min alpha: 1/4 - static const uint8_t sMaxAlphaNumerator = 3; // max alpha: 3/4 - - static const HashNumber sFreeKey = Entry::sFreeKey; - static const HashNumber sRemovedKey = Entry::sRemovedKey; - static const HashNumber sCollisionBit = Entry::sCollisionBit; - - void setTableSizeLog2(unsigned sizeLog2) { hashShift = sHashBits - sizeLog2; } - - static bool isLiveHash(HashNumber hash) { return Entry::isLiveHash(hash); } - - static HashNumber prepareHash(const Lookup& l) { - HashNumber keyHash = ScrambleHashCode(HashPolicy::hash(l)); - - // Avoid reserved hash codes. - if (!isLiveHash(keyHash)) keyHash -= (sRemovedKey + 1); - return keyHash & ~sCollisionBit; - } - - enum FailureBehavior { DontReportFailure = false, ReportFailure = true }; - - static Entry* createTable(AllocPolicy& alloc, uint32_t capacity, - FailureBehavior reportFailure = ReportFailure) { - static_assert(sFreeKey == 0, - "newly-calloc'd tables have to be considered empty"); - if (reportFailure) return alloc.template pod_calloc(capacity); - - return alloc.template maybe_pod_calloc(capacity); - } - - static Entry* maybeCreateTable(AllocPolicy& alloc, uint32_t capacity) { - static_assert(sFreeKey == 0, - "newly-calloc'd tables have to be considered empty"); - return alloc.template maybe_pod_calloc(capacity); - } - - static void destroyTable(AllocPolicy& alloc, Entry* oldTable, - uint32_t capacity) { - Entry* end = oldTable + capacity; - for (Entry* e = oldTable; e < end; ++e) e->destroyIfLive(); - alloc.free_(oldTable); - } - - public: - explicit HashTable(AllocPolicy ap) - : AllocPolicy(ap), - gen(0), - hashShift(sHashBits), - table(nullptr), - entryCount(0), - removedCount(0) -#ifdef JS_DEBUG - , - mutationCount(0), - mEntered(false) -#endif - { - } - - MOZ_MUST_USE bool init(uint32_t length) { - MOZ_ASSERT(!initialized()); - - // Reject all lengths whose initial computed capacity would exceed - // sMaxCapacity. Round that maximum length down to the nearest power - // of two for speedier code. - if (MOZ_UNLIKELY(length > sMaxInit)) { - this->reportAllocOverflow(); - return false; - } - - static_assert( - (sMaxInit * sAlphaDenominator) / sAlphaDenominator == sMaxInit, - "multiplication in numerator below could overflow"); - static_assert( - sMaxInit * sAlphaDenominator <= UINT32_MAX - sMaxAlphaNumerator, - "numerator calculation below could potentially overflow"); - - // Compute the smallest capacity allowing |length| elements to be - // inserted without rehashing: ceil(length / max-alpha). (Ceiling - // integral division: .) - uint32_t newCapacity = - (length * sAlphaDenominator + sMaxAlphaNumerator - 1) / - sMaxAlphaNumerator; - if (newCapacity < sMinCapacity) newCapacity = sMinCapacity; - - // FIXME: use JS_CEILING_LOG2 when PGO stops crashing (bug 543034). - uint32_t roundUp = sMinCapacity, roundUpLog2 = sMinCapacityLog2; - while (roundUp < newCapacity) { - roundUp <<= 1; - ++roundUpLog2; - } - - newCapacity = roundUp; - MOZ_ASSERT(newCapacity >= length); - MOZ_ASSERT(newCapacity <= sMaxCapacity); - - table = createTable(*this, newCapacity); - if (!table) return false; - - setTableSizeLog2(roundUpLog2); - METER(memset(&stats, 0, sizeof(stats))); - return true; - } - - bool initialized() const { return !!table; } - - ~HashTable() { - if (table) destroyTable(*this, table, capacity()); - } - - private: - HashNumber hash1(HashNumber hash0) const { return hash0 >> hashShift; } - - struct DoubleHash { - HashNumber h2; - HashNumber sizeMask; - }; - - DoubleHash hash2(HashNumber curKeyHash) const { - unsigned sizeLog2 = sHashBits - hashShift; - DoubleHash dh = {((curKeyHash << sizeLog2) >> hashShift) | 1, - (HashNumber(1) << sizeLog2) - 1}; - return dh; - } - - static HashNumber applyDoubleHash(HashNumber h1, const DoubleHash& dh) { - return (h1 - dh.h2) & dh.sizeMask; - } - - bool overloaded() { - static_assert(sMaxCapacity <= UINT32_MAX / sMaxAlphaNumerator, - "multiplication below could overflow"); - return entryCount + removedCount >= - capacity() * sMaxAlphaNumerator / sAlphaDenominator; - } - - // Would the table be underloaded if it had the given capacity and entryCount? - static bool wouldBeUnderloaded(uint32_t capacity, uint32_t entryCount) { - static_assert(sMaxCapacity <= UINT32_MAX / sMinAlphaNumerator, - "multiplication below could overflow"); - return capacity > sMinCapacity && - entryCount <= capacity * sMinAlphaNumerator / sAlphaDenominator; - } - - bool underloaded() { return wouldBeUnderloaded(capacity(), entryCount); } - - static MOZ_ALWAYS_INLINE bool match(Entry& e, const Lookup& l) { - return HashPolicy::match(HashPolicy::getKey(e.get()), l); - } - - // Warning: in order for readonlyThreadsafeLookup() to be safe this - // function must not modify the table in any way when |collisionBit| is 0. - // (The use of the METER() macro to increment stats violates this - // restriction but we will live with that for now because it's enabled so - // rarely.) - MOZ_ALWAYS_INLINE Entry& lookup(const Lookup& l, HashNumber keyHash, - unsigned collisionBit) const { - MOZ_ASSERT(isLiveHash(keyHash)); - MOZ_ASSERT(!(keyHash & sCollisionBit)); - MOZ_ASSERT(collisionBit == 0 || collisionBit == sCollisionBit); - MOZ_ASSERT(table); - METER(stats.searches++); - - // Compute the primary hash address. - HashNumber h1 = hash1(keyHash); - Entry* entry = &table[h1]; - - // Miss: return space for a new entry. - if (entry->isFree()) { - METER(stats.misses++); - return *entry; - } - - // Hit: return entry. - if (entry->matchHash(keyHash) && match(*entry, l)) { - METER(stats.hits++); - return *entry; - } - - // Collision: double hash. - DoubleHash dh = hash2(keyHash); - - // Save the first removed entry pointer so we can recycle later. - Entry* firstRemoved = nullptr; - - while (true) { - if (MOZ_UNLIKELY(entry->isRemoved())) { - if (!firstRemoved) firstRemoved = entry; - } else { - if (collisionBit == sCollisionBit) entry->setCollision(); - } - - METER(stats.steps++); - h1 = applyDoubleHash(h1, dh); - - entry = &table[h1]; - if (entry->isFree()) { - METER(stats.misses++); - return firstRemoved ? *firstRemoved : *entry; - } - - if (entry->matchHash(keyHash) && match(*entry, l)) { - METER(stats.hits++); - return *entry; - } - } - } - - // This is a copy of lookup hardcoded to the assumptions: - // 1. the lookup is a lookupForAdd - // 2. the key, whose |keyHash| has been passed is not in the table, - // 3. no entries have been removed from the table. - // This specialized search avoids the need for recovering lookup values - // from entries, which allows more flexible Lookup/Key types. - Entry& findFreeEntry(HashNumber keyHash) { - MOZ_ASSERT(!(keyHash & sCollisionBit)); - MOZ_ASSERT(table); - METER(stats.searches++); - - // We assume 'keyHash' has already been distributed. - - // Compute the primary hash address. - HashNumber h1 = hash1(keyHash); - Entry* entry = &table[h1]; - - // Miss: return space for a new entry. - if (!entry->isLive()) { - METER(stats.misses++); - return *entry; - } - - // Collision: double hash. - DoubleHash dh = hash2(keyHash); - - while (true) { - MOZ_ASSERT(!entry->isRemoved()); - entry->setCollision(); - - METER(stats.steps++); - h1 = applyDoubleHash(h1, dh); - - entry = &table[h1]; - if (!entry->isLive()) { - METER(stats.misses++); - return *entry; - } - } - } - - enum RebuildStatus { NotOverloaded, Rehashed, RehashFailed }; - - RebuildStatus changeTableSize(int deltaLog2, - FailureBehavior reportFailure = ReportFailure) { - // Look, but don't touch, until we succeed in getting new entry store. - Entry* oldTable = table; - uint32_t oldCap = capacity(); - uint32_t newLog2 = sHashBits - hashShift + deltaLog2; - uint32_t newCapacity = JS_BIT(newLog2); - if (MOZ_UNLIKELY(newCapacity > sMaxCapacity)) { - if (reportFailure) this->reportAllocOverflow(); - return RehashFailed; - } - - Entry* newTable = createTable(*this, newCapacity, reportFailure); - if (!newTable) return RehashFailed; - - // We can't fail from here on, so update table parameters. - setTableSizeLog2(newLog2); - removedCount = 0; - gen++; - table = newTable; - - // Copy only live entries, leaving removed ones behind. - Entry* end = oldTable + oldCap; - for (Entry* src = oldTable; src < end; ++src) { - if (src->isLive()) { - HashNumber hn = src->getKeyHash(); - findFreeEntry(hn).setLive( - hn, - mozilla::Move(const_cast(src->get()))); - src->destroy(); - } - } - - // All entries have been destroyed, no need to destroyTable. - this->free_(oldTable); - return Rehashed; - } - - bool shouldCompressTable() { - // Compress if a quarter or more of all entries are removed. - return removedCount >= (capacity() >> 2); - } - - RebuildStatus checkOverloaded(FailureBehavior reportFailure = ReportFailure) { - if (!overloaded()) return NotOverloaded; - - int deltaLog2; - if (shouldCompressTable()) { - METER(stats.compresses++); - deltaLog2 = 0; - } else { - METER(stats.grows++); - deltaLog2 = 1; - } - - return changeTableSize(deltaLog2, reportFailure); - } - - // Infallibly rehash the table if we are overloaded with removals. - void checkOverRemoved() { - if (overloaded()) { - if (checkOverloaded(DontReportFailure) == RehashFailed) - rehashTableInPlace(); - } - } - - void remove(Entry& e) { - MOZ_ASSERT(table); - METER(stats.removes++); - - if (e.hasCollision()) { - e.removeLive(); - removedCount++; - } else { - METER(stats.removeFrees++); - e.clearLive(); - } - entryCount--; -#ifdef JS_DEBUG - mutationCount++; -#endif - } - - void checkUnderloaded() { - if (underloaded()) { - METER(stats.shrinks++); - (void)changeTableSize(-1, DontReportFailure); - } - } - - // Resize the table down to the largest capacity which doesn't underload the - // table. Since we call checkUnderloaded() on every remove, you only need - // to call this after a bulk removal of items done without calling remove(). - void compactIfUnderloaded() { - int32_t resizeLog2 = 0; - uint32_t newCapacity = capacity(); - while (wouldBeUnderloaded(newCapacity, entryCount)) { - newCapacity = newCapacity >> 1; - resizeLog2--; - } - - if (resizeLog2 != 0) (void)changeTableSize(resizeLog2, DontReportFailure); - } - - // This is identical to changeTableSize(currentSize), but without requiring - // a second table. We do this by recycling the collision bits to tell us if - // the element is already inserted or still waiting to be inserted. Since - // already-inserted elements win any conflicts, we get the same table as we - // would have gotten through random insertion order. - void rehashTableInPlace() { - METER(stats.rehashes++); - removedCount = 0; - gen++; - for (size_t i = 0; i < capacity(); ++i) table[i].unsetCollision(); - - for (size_t i = 0; i < capacity();) { - Entry* src = &table[i]; - - if (!src->isLive() || src->hasCollision()) { - ++i; - continue; - } - - HashNumber keyHash = src->getKeyHash(); - HashNumber h1 = hash1(keyHash); - DoubleHash dh = hash2(keyHash); - Entry* tgt = &table[h1]; - while (true) { - if (!tgt->hasCollision()) { - src->swap(tgt); - tgt->setCollision(); - break; - } - - h1 = applyDoubleHash(h1, dh); - tgt = &table[h1]; - } - } - - // TODO: this algorithm leaves collision bits on *all* elements, even if - // they are on no collision path. We have the option of setting the - // collision bits correctly on a subsequent pass or skipping the rehash - // unless we are totally filled with tombstones: benchmark to find out - // which approach is best. - } - - // Note: |l| may be a reference to a piece of |u|, so this function - // must take care not to use |l| after moving |u|. - // - // Prefer to use putNewInfallible; this function does not check - // invariants. - template - void putNewInfallibleInternal(const Lookup& l, Args&&... args) { - MOZ_ASSERT(table); - - HashNumber keyHash = prepareHash(l); - Entry* entry = &findFreeEntry(keyHash); - MOZ_ASSERT(entry); - - if (entry->isRemoved()) { - METER(stats.addOverRemoved++); - removedCount--; - keyHash |= sCollisionBit; - } - - entry->setLive(keyHash, mozilla::Forward(args)...); - entryCount++; -#ifdef JS_DEBUG - mutationCount++; -#endif - } - - public: - void clear() { - if (mozilla::IsPod::value) { - memset(table, 0, sizeof(*table) * capacity()); - } else { - uint32_t tableCapacity = capacity(); - Entry* end = table + tableCapacity; - for (Entry* e = table; e < end; ++e) e->clear(); - } - removedCount = 0; - entryCount = 0; -#ifdef JS_DEBUG - mutationCount++; -#endif - } - - void clearAndShrink() { - clear(); - compactIfUnderloaded(); - } - - void finish() { -#ifdef JS_DEBUG - MOZ_ASSERT(!mEntered); -#endif - if (!table) return; - - destroyTable(*this, table, capacity()); - table = nullptr; - gen++; - entryCount = 0; - removedCount = 0; -#ifdef JS_DEBUG - mutationCount++; -#endif - } - - Range all() const { - MOZ_ASSERT(table); - return Range(*this, table, table + capacity()); - } - - bool empty() const { - MOZ_ASSERT(table); - return !entryCount; - } - - uint32_t count() const { - MOZ_ASSERT(table); - return entryCount; - } - - uint32_t capacity() const { - MOZ_ASSERT(table); - return JS_BIT(sHashBits - hashShift); - } - - Generation generation() const { - MOZ_ASSERT(table); - return Generation(gen); - } - - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return mallocSizeOf(table); - } - - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf); - } - - MOZ_ALWAYS_INLINE Ptr lookup(const Lookup& l) const { - mozilla::ReentrancyGuard g(*this); - if (!HasHash(l)) return Ptr(); - HashNumber keyHash = prepareHash(l); - return Ptr(lookup(l, keyHash, 0), *this); - } - - MOZ_ALWAYS_INLINE Ptr readonlyThreadsafeLookup(const Lookup& l) const { - if (!HasHash(l)) return Ptr(); - HashNumber keyHash = prepareHash(l); - return Ptr(lookup(l, keyHash, 0), *this); - } - - MOZ_ALWAYS_INLINE AddPtr lookupForAdd(const Lookup& l) const { - mozilla::ReentrancyGuard g(*this); - if (!EnsureHash(l)) return AddPtr(); - HashNumber keyHash = prepareHash(l); - // Calling constructor in return statement here avoid excess copying - // when build with Visual Studio 2015 and 2017, but it triggers a bug in - // gcc which is fixed in gcc-6. See bug 1385181. -#if MOZ_IS_GCC && __GNUC__ < 6 - AddPtr p(lookup(l, keyHash, sCollisionBit), *this, keyHash); - return p; -#else - return AddPtr(lookup(l, keyHash, sCollisionBit), *this, keyHash); -#endif - } - - template - MOZ_MUST_USE bool add(AddPtr& p, Args&&... args) { - mozilla::ReentrancyGuard g(*this); - MOZ_ASSERT(table); - MOZ_ASSERT_IF(p.isValid(), p.table_ == this); - MOZ_ASSERT(!p.found()); - MOZ_ASSERT(!(p.keyHash & sCollisionBit)); - - // Check for error from ensureHash() here. - if (!p.isValid()) return false; - - MOZ_ASSERT(p.generation == generation()); -#ifdef JS_DEBUG - MOZ_ASSERT(p.mutationCount == mutationCount); -#endif - - // Changing an entry from removed to live does not affect whether we - // are overloaded and can be handled separately. - if (p.entry_->isRemoved()) { - if (!this->checkSimulatedOOM()) return false; - METER(stats.addOverRemoved++); - removedCount--; - p.keyHash |= sCollisionBit; - } else { - // Preserve the validity of |p.entry_|. - RebuildStatus status = checkOverloaded(); - if (status == RehashFailed) return false; - if (status == NotOverloaded && !this->checkSimulatedOOM()) return false; - if (status == Rehashed) p.entry_ = &findFreeEntry(p.keyHash); - } - - p.entry_->setLive(p.keyHash, mozilla::Forward(args)...); - entryCount++; -#ifdef JS_DEBUG - mutationCount++; - p.generation = generation(); - p.mutationCount = mutationCount; -#endif - return true; - } - - // Note: |l| may be a reference to a piece of |u|, so this function - // must take care not to use |l| after moving |u|. - template - void putNewInfallible(const Lookup& l, Args&&... args) { - MOZ_ASSERT(!lookup(l).found()); - mozilla::ReentrancyGuard g(*this); - putNewInfallibleInternal(l, mozilla::Forward(args)...); - } - - // Note: |l| may be alias arguments in |args|, so this function must take - // care not to use |l| after moving |args|. - template - MOZ_MUST_USE bool putNew(const Lookup& l, Args&&... args) { - if (!this->checkSimulatedOOM()) return false; - - if (!EnsureHash(l)) return false; - - if (checkOverloaded() == RehashFailed) return false; - - putNewInfallible(l, mozilla::Forward(args)...); - return true; - } - - // Note: |l| may be a reference to a piece of |u|, so this function - // must take care not to use |l| after moving |u|. - template - MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, Args&&... args) { - // Check for error from ensureHash() here. - if (!p.isValid()) return false; - -#ifdef JS_DEBUG - p.generation = generation(); - p.mutationCount = mutationCount; -#endif - { - mozilla::ReentrancyGuard g(*this); - MOZ_ASSERT(prepareHash(l) == p.keyHash); // l has not been destroyed - p.entry_ = &lookup(l, p.keyHash, sCollisionBit); - } - return p.found() || add(p, mozilla::Forward(args)...); - } - - void remove(Ptr p) { - MOZ_ASSERT(table); - mozilla::ReentrancyGuard g(*this); - MOZ_ASSERT(p.found()); - MOZ_ASSERT(p.generation == generation()); - remove(*p.entry_); - checkUnderloaded(); - } - - void rekeyWithoutRehash(Ptr p, const Lookup& l, const Key& k) { - MOZ_ASSERT(table); - mozilla::ReentrancyGuard g(*this); - MOZ_ASSERT(p.found()); - MOZ_ASSERT(p.generation == generation()); - typename HashTableEntry::NonConstT t(mozilla::Move(*p)); - HashPolicy::setKey(t, const_cast(k)); - remove(*p.entry_); - putNewInfallibleInternal(l, mozilla::Move(t)); - } +template +using PointerHasher = mozilla::PointerHasher; - void rekeyAndMaybeRehash(Ptr p, const Lookup& l, const Key& k) { - rekeyWithoutRehash(p, l, k); - checkOverRemoved(); - } +template , + class AllocPolicy = TempAllocPolicy> +using HashSet = mozilla::HashSet; -#undef METER -}; +template , + class AllocPolicy = TempAllocPolicy> +using HashMap = mozilla::HashMap; -} // namespace detail } // namespace js #endif /* js_HashTable_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/HeapAPI.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/HeapAPI.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/HeapAPI.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -14,6 +14,8 @@ #include "js/TraceKind.h" #include "js/Utility.h" +struct JSStringFinalizer; + /* These values are private to the JS engine. */ namespace js { @@ -23,12 +25,6 @@ struct Cell; -/* - * The low bit is set so this should never equal a normal pointer, and the high - * bit is set so this should never equal the upper 32 bits of a 64-bit pointer. - */ -const uint32_t Relocated = uintptr_t(0xbad0bad1); - const size_t ArenaShift = 12; const size_t ArenaSize = size_t(1) << ArenaShift; const size_t ArenaMask = ArenaSize - 1; @@ -134,7 +130,14 @@ namespace shadow { struct Zone { - enum GCState : uint8_t { NoGC, Mark, MarkGray, Sweep, Finished, Compact }; + enum GCState : uint8_t { + NoGC, + MarkBlackOnly, + MarkBlackAndGray, + Sweep, + Finished, + Compact + }; protected: JSRuntime* const runtime_; @@ -157,7 +160,7 @@ return barrierTracer_; } - JSRuntime* runtimeFromActiveCooperatingThread() const { + JSRuntime* runtimeFromMainThread() const { MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); return runtime_; } @@ -168,12 +171,14 @@ GCState gcState() const { return gcState_; } bool wasGCStarted() const { return gcState_ != NoGC; } - bool isGCMarkingBlack() const { return gcState_ == Mark; } - bool isGCMarkingGray() const { return gcState_ == MarkGray; } + bool isGCMarkingBlackOnly() const { return gcState_ == MarkBlackOnly; } + bool isGCMarkingBlackAndGray() const { return gcState_ == MarkBlackAndGray; } bool isGCSweeping() const { return gcState_ == Sweep; } bool isGCFinished() const { return gcState_ == Finished; } bool isGCCompacting() const { return gcState_ == Compact; } - bool isGCMarking() const { return gcState_ == Mark || gcState_ == MarkGray; } + bool isGCMarking() const { + return isGCMarkingBlackOnly() || isGCMarkingBlackAndGray(); + } bool isGCSweepingOrCompacting() const { return gcState_ == Sweep || gcState_ == Compact; } @@ -183,6 +188,54 @@ } }; +struct String { + static const uint32_t NON_ATOM_BIT = JS_BIT(1); + static const uint32_t LINEAR_BIT = JS_BIT(4); + static const uint32_t INLINE_CHARS_BIT = JS_BIT(6); + static const uint32_t LATIN1_CHARS_BIT = JS_BIT(9); + static const uint32_t EXTERNAL_FLAGS = LINEAR_BIT | NON_ATOM_BIT | JS_BIT(8); + static const uint32_t TYPE_FLAGS_MASK = JS_BITMASK(9) - JS_BIT(2) - JS_BIT(0); + static const uint32_t PERMANENT_ATOM_MASK = NON_ATOM_BIT | JS_BIT(8); + static const uint32_t PERMANENT_ATOM_FLAGS = JS_BIT(8); + + uintptr_t flags_; +#if JS_BITS_PER_WORD == 32 + uint32_t length_; +#endif + + union { + const JS::Latin1Char* nonInlineCharsLatin1; + const char16_t* nonInlineCharsTwoByte; + JS::Latin1Char inlineStorageLatin1[1]; + char16_t inlineStorageTwoByte[1]; + }; + const JSStringFinalizer* externalFinalizer; + + inline uint32_t flags() const { return uint32_t(flags_); } + inline uint32_t length() const { +#if JS_BITS_PER_WORD == 32 + return length_; +#else + return uint32_t(flags_ >> 32); +#endif + } + + static bool isPermanentAtom(const js::gc::Cell* cell) { + uint32_t flags = reinterpret_cast(cell)->flags(); + return (flags & PERMANENT_ATOM_MASK) == PERMANENT_ATOM_FLAGS; + } +}; + +struct Symbol { + void* _1; + uint32_t code_; + static const uint32_t WellKnownAPILimit = 0x80000000; + + static bool isWellKnownSymbol(const js::gc::Cell* cell) { + return reinterpret_cast(cell)->code_ < WellKnownAPILimit; + } +}; + } /* namespace shadow */ /** @@ -214,7 +267,9 @@ JS::TraceKind kind() const { JS::TraceKind traceKind = JS::TraceKind(ptr & OutOfLineTraceKindMask); - if (uintptr_t(traceKind) != OutOfLineTraceKindMask) return traceKind; + if (uintptr_t(traceKind) != OutOfLineTraceKindMask) { + return traceKind; + } return outOfLineKind(); } @@ -259,9 +314,14 @@ } MOZ_ALWAYS_INLINE bool mayBeOwnedByOtherRuntime() const { - if (is() || is()) - return mayBeOwnedByOtherRuntimeSlow(); - return false; + if (!is() && !is()) { + return false; + } + if (is()) { + return JS::shadow::String::isPermanentAtom(asCell()); + } + MOZ_ASSERT(is()); + return JS::shadow::Symbol::isWellKnownSymbol(asCell()); } private: @@ -284,33 +344,44 @@ uintptr_t ptr; }; -inline bool operator==(const GCCellPtr& ptr1, const GCCellPtr& ptr2) { - return ptr1.asCell() == ptr2.asCell(); -} - -inline bool operator!=(const GCCellPtr& ptr1, const GCCellPtr& ptr2) { - return !(ptr1 == ptr2); -} - -// Unwraps the given GCCellPtr and calls the given functor with a template -// argument of the actual type of the pointer. -template -auto DispatchTyped(F f, GCCellPtr thing, Args&&... args) - -> decltype(f(static_cast(nullptr), - mozilla::Forward(args)...)) { +// Unwraps the given GCCellPtr, calls the functor |f| with a template argument +// of the actual type of the pointer, and returns the result. +template +auto MapGCThingTyped(GCCellPtr thing, F&& f) { switch (thing.kind()) { -#define JS_EXPAND_DEF(name, type, _) \ - case JS::TraceKind::name: \ - return f(&thing.as(), mozilla::Forward(args)...); +#define JS_EXPAND_DEF(name, type, _, _1) \ + case JS::TraceKind::name: \ + return f(&thing.as()); JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); #undef JS_EXPAND_DEF default: - MOZ_CRASH("Invalid trace kind in DispatchTyped for GCCellPtr."); + MOZ_CRASH("Invalid trace kind in MapGCThingTyped for GCCellPtr."); } } +// Unwraps the given GCCellPtr and calls the functor |f| with a template +// argument of the actual type of the pointer. Doesn't return anything. +template +void ApplyGCThingTyped(GCCellPtr thing, F&& f) { + // This function doesn't do anything but is supplied for symmetry with other + // MapGCThingTyped/ApplyGCThingTyped implementations that have to wrap the + // functor to return a dummy value that is ignored. + MapGCThingTyped(thing, f); +} + } /* namespace JS */ +// These are defined in the toplevel namespace instead of within JS so that +// they won't shadow other operator== overloads (see bug 1456512.) + +inline bool operator==(const JS::GCCellPtr& ptr1, const JS::GCCellPtr& ptr2) { + return ptr1.asCell() == ptr2.asCell(); +} + +inline bool operator!=(const JS::GCCellPtr& ptr1, const JS::GCCellPtr& ptr2) { + return !(ptr1 == ptr2); +} + namespace js { namespace gc { namespace detail { @@ -353,7 +424,9 @@ uintptr_t *grayWord, grayMask; js::gc::detail::GetGCThingMarkWordAndMask( uintptr_t(cell), js::gc::ColorBit::GrayOrBlackBit, &grayWord, &grayMask); - if (!(*grayWord & grayMask)) return false; + if (!(*grayWord & grayMask)) { + return false; + } uintptr_t *blackWord, blackMask; js::gc::detail::GetGCThingMarkWordAndMask( @@ -363,14 +436,16 @@ static MOZ_ALWAYS_INLINE bool CellIsMarkedGray(const Cell* cell) { MOZ_ASSERT(cell); - if (js::gc::IsInsideNursery(cell)) return false; + if (js::gc::IsInsideNursery(cell)) { + return false; + } return TenuredCellIsMarkedGray(cell); } extern JS_PUBLIC_API bool CellIsMarkedGrayIfKnown(const Cell* cell); #ifdef DEBUG -extern JS_PUBLIC_API bool CellIsNotGray(const Cell* cell); +extern JS_PUBLIC_API void AssertCellIsNotGray(const Cell* cell); extern JS_PUBLIC_API bool ObjectIsMarkedBlack(const JSObject* obj); #endif @@ -392,7 +467,9 @@ } /* namespace detail */ MOZ_ALWAYS_INLINE bool IsInsideNursery(const js::gc::Cell* cell) { - if (!cell) return false; + if (!cell) { + return false; + } auto location = detail::GetCellLocation(cell); MOZ_ASSERT(location == ChunkLocation::Nursery || location == ChunkLocation::TenuredHeap); @@ -401,17 +478,23 @@ MOZ_ALWAYS_INLINE bool IsCellPointerValid(const void* cell) { auto addr = uintptr_t(cell); - if (addr < ChunkSize || addr % CellAlignBytes != 0) return false; + if (addr < ChunkSize || addr % CellAlignBytes != 0) { + return false; + } auto location = detail::GetCellLocation(cell); - if (location == ChunkLocation::TenuredHeap) + if (location == ChunkLocation::TenuredHeap) { return !!detail::GetGCThingZone(addr); - if (location == ChunkLocation::Nursery) + } + if (location == ChunkLocation::Nursery) { return detail::NurseryCellHasStoreBuffer(cell); + } return false; } MOZ_ALWAYS_INLINE bool IsCellPointerValidOrNull(const void* cell) { - if (!cell) return true; + if (!cell) { + return true; + } return IsCellPointerValid(cell); } @@ -428,17 +511,18 @@ extern JS_PUBLIC_API Zone* GetNurseryStringZone(JSString* str); static MOZ_ALWAYS_INLINE Zone* GetStringZone(JSString* str) { - if (!js::gc::IsInsideNursery(reinterpret_cast(str))) + if (!js::gc::IsInsideNursery(reinterpret_cast(str))) { return js::gc::detail::GetGCThingZone(reinterpret_cast(str)); + } return GetNurseryStringZone(str); } extern JS_PUBLIC_API Zone* GetObjectZone(JSObject* obj); -extern JS_PUBLIC_API Zone* GetValueZone(const Value& value); - static MOZ_ALWAYS_INLINE bool GCThingIsMarkedGray(GCCellPtr thing) { - if (thing.mayBeOwnedByOtherRuntime()) return false; + if (thing.mayBeOwnedByOtherRuntime()) { + return false; + } return js::gc::detail::CellIsMarkedGrayIfKnown(thing.asCell()); } @@ -463,6 +547,12 @@ extern JS_PUBLIC_API void IncrementalPreWriteBarrier(JSObject* obj); /* + * Notify the GC that a reference to a tenured GC cell is about to be + * overwritten. This method must be called if IsIncrementalBarrierNeeded. + */ +extern JS_PUBLIC_API void IncrementalPreWriteBarrier(GCCellPtr thing); + +/* * Notify the GC that a weak reference to a GC thing has been read. * This method must be called if IsIncrementalBarrierNeeded. */ @@ -485,10 +575,10 @@ MOZ_ASSERT(thing); MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell())); - // TODO: I'd like to assert !CurrentThreadIsHeapBusy() here but this gets + // TODO: I'd like to assert !RuntimeHeapIsBusy() here but this gets // called while we are tracing the heap, e.g. during memory reporting // (see bug 1313318). - MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting()); + MOZ_ASSERT(!JS::RuntimeHeapIsCollecting()); JS::Zone* zone = JS::GetTenuredGCThingZone(thing); return JS::shadow::Zone::asShadowZone(zone)->needsIncrementalBarrier(); @@ -498,16 +588,21 @@ // GC things residing in the nursery cannot be gray: they have no mark bits. // All live objects in the nursery are moved to tenured at the beginning of // each GC slice, so the gray marker never sees nursery things. - if (IsInsideNursery(thing.asCell())) return; + if (IsInsideNursery(thing.asCell())) { + return; + } // There's nothing to do for permanent GC things that might be owned by // another runtime. - if (thing.mayBeOwnedByOtherRuntime()) return; + if (thing.mayBeOwnedByOtherRuntime()) { + return; + } - if (IsIncrementalBarrierNeededOnTenuredGCThing(thing)) + if (IsIncrementalBarrierNeededOnTenuredGCThing(thing)) { JS::IncrementalReadBarrier(thing); - else if (js::gc::detail::TenuredCellIsMarkedGray(thing.asCell())) + } else if (js::gc::detail::TenuredCellIsMarkedGray(thing.asCell())) { JS::UnmarkGrayGCThingRecursively(thing); + } MOZ_ASSERT(!js::gc::detail::TenuredCellIsMarkedGray(thing.asCell())); } @@ -519,12 +614,16 @@ // This function does not handle updating nursery pointers. Raw JSObject // pointers should be updated separately or replaced with // JS::Heap which handles this automatically. - MOZ_ASSERT(!JS::CurrentThreadIsHeapMinorCollecting()); - if (IsInsideNursery(reinterpret_cast(*objp))) return false; + MOZ_ASSERT(!JS::RuntimeHeapIsMinorCollecting()); + if (IsInsideNursery(reinterpret_cast(*objp))) { + return false; + } auto zone = JS::shadow::Zone::asShadowZone(detail::GetGCThingZone(uintptr_t(*objp))); - if (!zone->isGCSweepingOrCompacting()) return false; + if (!zone->isGCSweepingOrCompacting()) { + return false; + } return EdgeNeedsSweepUnbarrieredSlow(objp); } Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Id.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Id.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Id.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -20,6 +20,8 @@ // A jsid is not implicitly convertible to or from a Value; JS_ValueToId or // JS_IdToValue must be used instead. +#include "mozilla/Maybe.h" + #include "jstypes.h" #include "js/HeapAPI.h" @@ -27,30 +29,58 @@ #include "js/TypeDecls.h" #include "js/Utility.h" -struct jsid { - size_t asBits; - bool operator==(const jsid& rhs) const { return asBits == rhs.asBits; } - bool operator!=(const jsid& rhs) const { return asBits != rhs.asBits; } -} JS_HAZ_GC_POINTER; -#define JSID_BITS(id) (id.asBits) +// All jsids with the low bit set are integer ids. This means the other type +// tags must all be even. +#define JSID_TYPE_INT_BIT 0x1 +// Use 0 for JSID_TYPE_STRING to avoid a bitwise op for atom <-> id conversions. #define JSID_TYPE_STRING 0x0 -#define JSID_TYPE_INT 0x1 #define JSID_TYPE_VOID 0x2 #define JSID_TYPE_SYMBOL 0x4 +#define JSID_TYPE_EMPTY 0x6 #define JSID_TYPE_MASK 0x7 +namespace JS { + +struct PropertyKey { + size_t asBits; + + constexpr PropertyKey() : asBits(JSID_TYPE_VOID) {} + + static constexpr MOZ_ALWAYS_INLINE PropertyKey fromRawBits(size_t bits) { + PropertyKey id; + id.asBits = bits; + return id; + } + + bool operator==(const PropertyKey& rhs) const { return asBits == rhs.asBits; } + bool operator!=(const PropertyKey& rhs) const { return asBits != rhs.asBits; } + + MOZ_ALWAYS_INLINE bool isInt() const { + return !!(asBits & JSID_TYPE_INT_BIT); + } + +} JS_HAZ_GC_POINTER; + +} // namespace JS + +using jsid = JS::PropertyKey; + +#define JSID_BITS(id) (id.asBits) + // Avoid using canonical 'id' for jsid parameters since this is a magic word in // Objective-C++ which, apparently, wants to be able to #include jsapi.h. #define id iden static MOZ_ALWAYS_INLINE bool JSID_IS_STRING(jsid id) { - return (JSID_BITS(id) & JSID_TYPE_MASK) == 0; + return (JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_STRING; } static MOZ_ALWAYS_INLINE JSString* JSID_TO_STRING(jsid id) { + // Use XOR instead of `& ~JSID_TYPE_MASK` because small immediates can be + // encoded more efficiently on some platorms. MOZ_ASSERT(JSID_IS_STRING(id)); - return (JSString*)JSID_BITS(id); + return (JSString*)(JSID_BITS(id) ^ JSID_TYPE_STRING); } /** @@ -63,11 +93,12 @@ JS_PUBLIC_API jsid INTERNED_STRING_TO_JSID(JSContext* cx, JSString* str); static MOZ_ALWAYS_INLINE bool JSID_IS_INT(jsid id) { - return !!(JSID_BITS(id) & JSID_TYPE_INT); + return !!(JSID_BITS(id) & JSID_TYPE_INT_BIT); } static MOZ_ALWAYS_INLINE int32_t JSID_TO_INT(jsid id) { MOZ_ASSERT(JSID_IS_INT(id)); + MOZ_ASSERT(id.isInt()); uint32_t bits = static_cast(JSID_BITS(id)) >> 1; return static_cast(bits); } @@ -80,19 +111,18 @@ static MOZ_ALWAYS_INLINE jsid INT_TO_JSID(int32_t i) { jsid id; MOZ_ASSERT(INT_FITS_IN_JSID(i)); - uint32_t bits = (static_cast(i) << 1) | JSID_TYPE_INT; + uint32_t bits = (static_cast(i) << 1) | JSID_TYPE_INT_BIT; JSID_BITS(id) = static_cast(bits); return id; } static MOZ_ALWAYS_INLINE bool JSID_IS_SYMBOL(jsid id) { - return (JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_SYMBOL && - JSID_BITS(id) != JSID_TYPE_SYMBOL; + return (JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_SYMBOL; } static MOZ_ALWAYS_INLINE JS::Symbol* JSID_TO_SYMBOL(jsid id) { MOZ_ASSERT(JSID_IS_SYMBOL(id)); - return (JS::Symbol*)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); + return (JS::Symbol*)(JSID_BITS(id) ^ JSID_TYPE_SYMBOL); } static MOZ_ALWAYS_INLINE jsid SYMBOL_TO_JSID(JS::Symbol* sym) { @@ -110,23 +140,27 @@ static MOZ_ALWAYS_INLINE JS::GCCellPtr JSID_TO_GCTHING(jsid id) { void* thing = (void*)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); - if (JSID_IS_STRING(id)) return JS::GCCellPtr(thing, JS::TraceKind::String); + if (JSID_IS_STRING(id)) { + return JS::GCCellPtr(thing, JS::TraceKind::String); + } MOZ_ASSERT(JSID_IS_SYMBOL(id)); return JS::GCCellPtr(thing, JS::TraceKind::Symbol); } static MOZ_ALWAYS_INLINE bool JSID_IS_VOID(const jsid id) { - MOZ_ASSERT_IF(((size_t)JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_VOID, + MOZ_ASSERT_IF((JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_VOID, JSID_BITS(id) == JSID_TYPE_VOID); - return (size_t)JSID_BITS(id) == JSID_TYPE_VOID; + return JSID_BITS(id) == JSID_TYPE_VOID; } static MOZ_ALWAYS_INLINE bool JSID_IS_EMPTY(const jsid id) { - return (size_t)JSID_BITS(id) == JSID_TYPE_SYMBOL; + MOZ_ASSERT_IF((JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_EMPTY, + JSID_BITS(id) == JSID_TYPE_EMPTY); + return JSID_BITS(id) == JSID_TYPE_EMPTY; } -extern JS_PUBLIC_DATA const jsid JSID_VOID; -extern JS_PUBLIC_DATA const jsid JSID_EMPTY; +constexpr const jsid JSID_VOID; +constexpr const jsid JSID_EMPTY = jsid::fromRawBits(JSID_TYPE_EMPTY); extern JS_PUBLIC_DATA const JS::HandleId JSID_VOIDHANDLE; extern JS_PUBLIC_DATA const JS::HandleId JSID_EMPTYHANDLE; @@ -135,7 +169,6 @@ template <> struct GCPolicy { - static jsid initial() { return JSID_VOID; } static void trace(JSTracer* trc, jsid* idp, const char* name) { js::UnsafeTraceManuallyBarrieredEdge(trc, idp, name); } @@ -146,10 +179,10 @@ }; #ifdef DEBUG -MOZ_ALWAYS_INLINE bool IdIsNotGray(jsid id) { - if (!JSID_IS_GCTHING(id)) return true; - - return CellIsNotGray(JSID_TO_GCTHING(id).asCell()); +MOZ_ALWAYS_INLINE void AssertIdIsNotGray(jsid id) { + if (JSID_IS_GCTHING(id)) { + AssertCellIsNotGray(JSID_TO_GCTHING(id).asCell()); + } } #endif @@ -160,31 +193,54 @@ template <> struct BarrierMethods { static gc::Cell* asGCThingOrNull(jsid id) { - if (JSID_IS_STRING(id)) + if (JSID_IS_STRING(id)) { return reinterpret_cast(JSID_TO_STRING(id)); - if (JSID_IS_SYMBOL(id)) + } + if (JSID_IS_SYMBOL(id)) { return reinterpret_cast(JSID_TO_SYMBOL(id)); + } return nullptr; } - static void postBarrier(jsid* idp, jsid prev, jsid next) {} + static void writeBarriers(jsid* idp, jsid prev, jsid next) { + if (JSID_IS_STRING(prev)) { + JS::IncrementalPreWriteBarrier(JS::GCCellPtr(JSID_TO_STRING(prev))); + } + if (JSID_IS_SYMBOL(prev)) { + JS::IncrementalPreWriteBarrier(JS::GCCellPtr(JSID_TO_SYMBOL(prev))); + } + } static void exposeToJS(jsid id) { - if (JSID_IS_GCTHING(id)) + if (JSID_IS_GCTHING(id)) { js::gc::ExposeGCThingToActiveJS(JSID_TO_GCTHING(id)); + } } }; -// If the jsid is a GC pointer type, convert to that type and call |f| with -// the pointer. If the jsid is not a GC type, calls F::defaultValue. -template -auto DispatchTyped(F f, const jsid& id, Args&&... args) - -> decltype(f(static_cast(nullptr), - mozilla::Forward(args)...)) { - if (JSID_IS_STRING(id)) - return f(JSID_TO_STRING(id), mozilla::Forward(args)...); - if (JSID_IS_SYMBOL(id)) - return f(JSID_TO_SYMBOL(id), mozilla::Forward(args)...); +// If the jsid is a GC pointer type, convert to that type and call |f| with the +// pointer and return the result wrapped in a Maybe, otherwise return None(). +template +auto MapGCThingTyped(const jsid& id, F&& f) { + if (JSID_IS_STRING(id)) { + return mozilla::Some(f(JSID_TO_STRING(id))); + } + if (JSID_IS_SYMBOL(id)) { + return mozilla::Some(f(JSID_TO_SYMBOL(id))); + } MOZ_ASSERT(!JSID_IS_GCTHING(id)); - return F::defaultValue(id); + using ReturnType = decltype(f(static_cast(nullptr))); + return mozilla::Maybe(); +} + +// If the jsid is a GC pointer type, convert to that type and call |f| with the +// pointer. Return whether this happened. +template +bool ApplyGCThingTyped(const jsid& id, F&& f) { + return MapGCThingTyped(id, + [&f](auto t) { + f(t); + return true; + }) + .isSome(); } #undef id Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Initialization.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Initialization.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Initialization.h @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/JSON.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/JSON.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/JSON.h @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * JSON serialization and deserialization operations. + */ + +#ifndef js_JSON_h +#define js_JSON_h + +#include // uint32_t + +#include "jstypes.h" // JS_PUBLIC_API + +#include "js/RootingAPI.h" // JS::Handle, JS::MutableHandle + +struct JS_PUBLIC_API JSContext; +class JS_PUBLIC_API JSObject; +class JS_PUBLIC_API JSString; + +namespace JS { +union JS_PUBLIC_API Value; +} + +using JSONWriteCallback = bool (*)(const char16_t* buf, uint32_t len, + void* data); + +/** + * Performs the JSON.stringify operation, as specified by ECMAScript, except + * writing stringified data by repeated calls of |callback|, with each such + * call passed |data| as argument. + */ +extern JS_PUBLIC_API bool JS_Stringify(JSContext* cx, + JS::MutableHandle value, + JS::Handle replacer, + JS::Handle space, + JSONWriteCallback callback, void* data); + +namespace JS { + +/** + * An API akin to JS_Stringify but with the goal of not having observable + * side-effects when the stringification is performed. This means it does not + * allow a replacer or a custom space and has the following constraints on its + * input: + * + * 1) The input must be a plain object or array, not an abitrary value. + * 2) Every value in the graph reached by the algorithm starting with this + * object must be one of the following: null, undefined, a string (NOT a + * string object!), a boolean, a finite number (i.e. no NaN or Infinity or + * -Infinity), a plain object with no accessor properties, or an Array with + * no holes. + * + * The actual behavior differs from JS_Stringify only in asserting the above and + * NOT attempting to get the "toJSON" property from things, since that could + * clearly have side-effects. + */ +extern JS_PUBLIC_API bool ToJSONMaybeSafely(JSContext* cx, + JS::Handle input, + JSONWriteCallback callback, + void* data); + +} /* namespace JS */ + +/** + * Performs the JSON.parse operation as specified by ECMAScript. + */ +extern JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, const char16_t* chars, + uint32_t len, + JS::MutableHandle vp); + +/** + * Performs the JSON.parse operation as specified by ECMAScript. + */ +extern JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, JS::Handle str, + JS::MutableHandle vp); + +/** + * Performs the JSON.parse operation as specified by ECMAScript, using the + * given |reviver| argument as the corresponding optional argument to that + * function. + */ +extern JS_PUBLIC_API bool JS_ParseJSONWithReviver( + JSContext* cx, const char16_t* chars, uint32_t len, + JS::Handle reviver, JS::MutableHandle vp); + +/** + * Performs the JSON.parse operation as specified by ECMAScript, using the + * given |reviver| argument as the corresponding optional argument to that + * function. + */ +extern JS_PUBLIC_API bool JS_ParseJSONWithReviver( + JSContext* cx, JS::Handle str, JS::Handle reviver, + JS::MutableHandle vp); + +#endif /* js_JSON_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/LocaleSensitive.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/LocaleSensitive.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/LocaleSensitive.h @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Functions and structures related to locale-sensitive behavior, including + * exposure of the default locale (used by operations like toLocaleString). + */ + +#ifndef js_LocaleSensitive_h +#define js_LocaleSensitive_h + +#include "jstypes.h" // JS_PUBLIC_API + +#include "js/RootingAPI.h" // JS::Handle, JS::MutableHandle +#include "js/Utility.h" // JS::UniqueChars + +struct JS_PUBLIC_API JSContext; +struct JS_PUBLIC_API JSRuntime; +class JS_PUBLIC_API JSString; + +namespace JS { +union JS_PUBLIC_API Value; +} + +/** + * Set the default locale for the ECMAScript Internationalization API + * (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat, and others that will + * arise as time passes). (Note that the Internationalization API encourages + * clients to specify their own locales; this default locale is only used when + * no locale is specified, e.g. calling a toLocaleString function without + * passing a locale argument to it.) + * + * The locale string remains owned by the caller. + */ +extern JS_PUBLIC_API bool JS_SetDefaultLocale(JSRuntime* rt, + const char* locale); + +/** + * Return a copy of the default locale for the ECMAScript Internationalization + * API (and for various ECMAScript functions that will invoke it). The locale + * is retrieved from the |JSRuntime| that corresponds to |cx|. + * + * XXX Bug 1483961 means it's difficult to interpret the meaning of a null + * return value for the time being, and we should fix this! + */ +extern JS_PUBLIC_API JS::UniqueChars JS_GetDefaultLocale(JSContext* cx); + +/** Reset the default locale to OS defaults. */ +extern JS_PUBLIC_API void JS_ResetDefaultLocale(JSRuntime* rt); + +using JSLocaleToUpperCase = bool (*)(JSContext* cx, JS::Handle src, + JS::MutableHandle rval); + +using JSLocaleToLowerCase = bool (*)(JSContext* cx, JS::Handle src, + JS::MutableHandle rval); + +using JSLocaleCompare = bool (*)(JSContext* cx, JS::Handle src1, + JS::Handle src2, + JS::MutableHandle rval); + +using JSLocaleToUnicode = bool (*)(JSContext* cx, const char* src, + JS::MutableHandle rval); + +/** + * A suite of locale-specific string conversion and error message callbacks + * used to implement locale-sensitive behaviors (such as those performed by + * the various toLocaleString and toLocale{Date,Time}String functions). + * + * If SpiderMonkey is compiled --with-intl-api, then #if EXPOSE_INTL_API. In + * this case, SpiderMonkey itself will implement ECMA-402-compliant behavior by + * calling on ICU, and none of the fields in this struct will ever be used. + * (You'll still be able to call the get/set-callbacks functions; they just + * won't affect JavaScript semantics.) + */ +struct JSLocaleCallbacks { + JSLocaleToUpperCase localeToUpperCase; + JSLocaleToLowerCase localeToLowerCase; + JSLocaleCompare localeCompare; + JSLocaleToUnicode localeToUnicode; +}; + +/** + * Set locale callbacks to be used in builds not compiled --with-intl-api. + * |callbacks| must persist as long as the |JSRuntime|. Pass |nullptr| to + * restore default behavior. + */ +extern JS_PUBLIC_API void JS_SetLocaleCallbacks( + JSRuntime* rt, const JSLocaleCallbacks* callbacks); + +/** + * Return the current locale callbacks, which may be nullptr. + */ +extern JS_PUBLIC_API const JSLocaleCallbacks* JS_GetLocaleCallbacks( + JSRuntime* rt); + +#endif /* js_LocaleSensitive_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/MemoryFunctions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/MemoryFunctions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/MemoryFunctions.h @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Low-level memory-allocation functions. */ + +#ifndef js_MemoryFunctions_h +#define js_MemoryFunctions_h + +#include "mozilla/Assertions.h" // MOZ_ASSERT +#include "mozilla/Attributes.h" // MOZ_MUST_USE + +#include // size_t + +#include "jstypes.h" // JS_PUBLIC_API + +struct JS_PUBLIC_API JSContext; +struct JS_PUBLIC_API JSRuntime; + +struct JSFreeOp { + protected: + JSRuntime* runtime_; + + explicit JSFreeOp(JSRuntime* rt) : runtime_(rt) {} + + public: + JSRuntime* runtime() const { + MOZ_ASSERT(runtime_); + return runtime_; + } +}; + +extern JS_PUBLIC_API void* JS_malloc(JSContext* cx, size_t nbytes); + +extern JS_PUBLIC_API void* JS_realloc(JSContext* cx, void* p, size_t oldBytes, + size_t newBytes); + +/** + * A wrapper for |js_free(p)| that may delay |js_free(p)| invocation as a + * performance optimization. |cx| may be nullptr. + */ +extern JS_PUBLIC_API void JS_free(JSContext* cx, void* p); + +/** + * Same as above, but for buffers that will be used with the BYOB + * (Bring Your Own Buffer) JSString creation functions, such as + * JS_NewLatin1String and JS_NewUCString + */ +extern JS_PUBLIC_API void* JS_string_malloc(JSContext* cx, size_t nbytes); + +extern JS_PUBLIC_API void* JS_string_realloc(JSContext* cx, void* p, + size_t oldBytes, size_t newBytes); + +extern JS_PUBLIC_API void JS_string_free(JSContext* cx, void* p); + +/** + * A wrapper for |js_free(p)| that may delay |js_free(p)| invocation as a + * performance optimization as specified by the given JSFreeOp instance. + */ +extern JS_PUBLIC_API void JS_freeop(JSFreeOp* fop, void* p); + +namespace JS { + +/** + * The different possible memory uses to pass to Add/RemoveAssociatedMemory. + */ +#define JS_FOR_EACH_PUBLIC_MEMORY_USE(_) \ + _(XPCWrappedNative) \ + _(DOMBinding) \ + _(Embedding1) \ + _(Embedding2) \ + _(Embedding3) \ + _(Embedding4) \ + _(Embedding5) + +enum class MemoryUse : uint8_t { +#define DEFINE_MEMORY_USE(Name) Name, + JS_FOR_EACH_PUBLIC_MEMORY_USE(DEFINE_MEMORY_USE) +#undef DEFINE_MEMORY_USE +}; + +/** + * Advise the GC of external memory owned by a JSObject. This is used to + * determine when to collect zones. Calls must be matched by calls to + * RemoveAssociatedMemory() when the memory is deallocated or no longer owned by + * the object. + */ +extern JS_PUBLIC_API void AddAssociatedMemory(JSObject* obj, size_t nbytes, + MemoryUse use); + +/** + * Advise the GC that external memory reported by JS::AddAssociatedMemory() is + * no longer owned by a JSObject. Calls must match those to + * AddAssociatedMemory(). + */ +extern JS_PUBLIC_API void RemoveAssociatedMemory(JSObject* obj, size_t nbytes, + MemoryUse use); + +} // namespace JS + +#endif /* js_MemoryFunctions_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/MemoryMetrics.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/MemoryMetrics.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/MemoryMetrics.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -11,7 +11,6 @@ // at your own risk. #include "mozilla/MemoryReporting.h" -#include "mozilla/PodOperations.h" #include "mozilla/TypeTraits.h" #include @@ -31,7 +30,7 @@ struct TabSizes { enum Kind { Objects, Strings, Private, Other }; - TabSizes() { mozilla::PodZero(this); } + TabSizes() : objects(0), strings(0), private_(0), other(0) {} void add(Kind kind, size_t n) { switch (kind) { @@ -70,7 +69,7 @@ Ignore }; - ServoSizes() { mozilla::PodZero(this); } + ServoSizes() = default; void add(Kind kind, size_t n) { switch (kind) { @@ -99,12 +98,12 @@ } } - size_t gcHeapUsed; - size_t gcHeapUnused; - size_t gcHeapAdmin; - size_t gcHeapDecommitted; - size_t mallocHeap; - size_t nonHeap; + size_t gcHeapUsed = 0; + size_t gcHeapUnused = 0; + size_t gcHeapAdmin = 0; + size_t gcHeapDecommitted = 0; + size_t mallocHeap = 0; + size_t nonHeap = 0; }; } // namespace JS @@ -133,12 +132,6 @@ static bool match(const JSString* const& k, const Lookup& l); }; -struct CStringHashPolicy { - typedef const char* Lookup; - static HashNumber hash(const Lookup& l); - static bool match(const char* const& k, const Lookup& l); -}; - // This file features many classes with numerous size_t fields, and each such // class has one or more methods that need to operate on all of these fields. // Writing these individually is error-prone -- it's easy to add a new field @@ -305,8 +298,8 @@ /** Data for tracking GC memory usage. */ struct GCSizes { -// |nurseryDecommitted| is marked as NonHeap rather than GCHeapDecommitted -// because we don't consider the nursery to be part of the GC heap. + // |nurseryDecommitted| is marked as NonHeap rather than GCHeapDecommitted + // because we don't consider the nursery to be part of the GC heap. #define FOR_EACH_SIZE(MACRO) \ MACRO(_, MallocHeap, marker) \ MACRO(_, NonHeap, nurseryCommitted) \ @@ -461,6 +454,42 @@ NotableScriptSourceInfo(const NotableScriptSourceInfo& info) = delete; }; +struct HelperThreadStats { +#define FOR_EACH_SIZE(MACRO) \ + MACRO(_, MallocHeap, stateData) \ + MACRO(_, MallocHeap, parseTask) \ + MACRO(_, MallocHeap, ionBuilder) \ + MACRO(_, MallocHeap, wasmCompile) + + explicit HelperThreadStats() + : FOR_EACH_SIZE(ZERO_SIZE) idleThreadCount(0), activeThreadCount(0) {} + + FOR_EACH_SIZE(DECL_SIZE) + + unsigned idleThreadCount; + unsigned activeThreadCount; + +#undef FOR_EACH_SIZE +}; + +/** + * Measurements that not associated with any individual runtime. + */ +struct GlobalStats { +#define FOR_EACH_SIZE(MACRO) MACRO(_, MallocHeap, tracelogger) + + explicit GlobalStats(mozilla::MallocSizeOf mallocSizeOf) + : FOR_EACH_SIZE(ZERO_SIZE) mallocSizeOf_(mallocSizeOf) {} + + FOR_EACH_SIZE(DECL_SIZE) + + HelperThreadStats helperThread; + + mozilla::MallocSizeOf mallocSizeOf_; + +#undef FOR_EACH_SIZE +}; + /** * These measurements relate directly to the JSRuntime, and not to zones, * compartments, and realms within it. @@ -473,12 +502,13 @@ MACRO(_, MallocHeap, contexts) \ MACRO(_, MallocHeap, temporary) \ MACRO(_, MallocHeap, interpreterStack) \ - MACRO(_, MallocHeap, mathCache) \ MACRO(_, MallocHeap, sharedImmutableStringsCache) \ MACRO(_, MallocHeap, sharedIntlData) \ MACRO(_, MallocHeap, uncompressedSourceCache) \ MACRO(_, MallocHeap, scriptData) \ - MACRO(_, MallocHeap, tracelogger) + MACRO(_, MallocHeap, tracelogger) \ + MACRO(_, MallocHeap, wasmRuntime) \ + MACRO(_, MallocHeap, jitLazyLink) RuntimeSizes() : FOR_EACH_SIZE(ZERO_SIZE) scriptSourceInfo(), @@ -486,7 +516,9 @@ gc(), notableScriptSources() { allScriptSources = js_new(); - if (!allScriptSources || !allScriptSources->init()) MOZ_CRASH("oom"); + if (!allScriptSources) { + MOZ_CRASH("oom"); + } } ~RuntimeSizes() { @@ -512,7 +544,7 @@ CodeSizes code; GCSizes gc; - typedef js::HashMap ScriptSourcesHashMap; @@ -537,6 +569,7 @@ MACRO(Other, GCHeapUnused, objectGroup) \ MACRO(Other, GCHeapUnused, string) \ MACRO(Other, GCHeapUnused, symbol) \ + MACRO(Other, GCHeapUnused, bigInt) \ MACRO(Other, GCHeapUnused, jitcode) \ MACRO(Other, GCHeapUnused, scope) \ MACRO(Other, GCHeapUnused, regExpShared) @@ -557,6 +590,9 @@ case JS::TraceKind::Symbol: symbol += n; break; + case JS::TraceKind::BigInt: + bigInt += n; + break; case JS::TraceKind::Script: script += n; break; @@ -608,25 +644,30 @@ }; struct ZoneStats { -#define FOR_EACH_SIZE(MACRO) \ - MACRO(Other, GCHeapUsed, symbolsGCHeap) \ - MACRO(Other, GCHeapAdmin, gcHeapArenaAdmin) \ - MACRO(Other, GCHeapUsed, lazyScriptsGCHeap) \ - MACRO(Other, MallocHeap, lazyScriptsMallocHeap) \ - MACRO(Other, GCHeapUsed, jitCodesGCHeap) \ - MACRO(Other, GCHeapUsed, objectGroupsGCHeap) \ - MACRO(Other, MallocHeap, objectGroupsMallocHeap) \ - MACRO(Other, GCHeapUsed, scopesGCHeap) \ - MACRO(Other, MallocHeap, scopesMallocHeap) \ - MACRO(Other, GCHeapUsed, regExpSharedsGCHeap) \ - MACRO(Other, MallocHeap, regExpSharedsMallocHeap) \ - MACRO(Other, MallocHeap, typePool) \ - MACRO(Other, MallocHeap, regexpZone) \ - MACRO(Other, MallocHeap, jitZone) \ - MACRO(Other, MallocHeap, baselineStubsOptimized) \ - MACRO(Other, MallocHeap, cachedCFG) \ - MACRO(Other, MallocHeap, uniqueIdMap) \ - MACRO(Other, MallocHeap, shapeTables) +#define FOR_EACH_SIZE(MACRO) \ + MACRO(Other, GCHeapUsed, symbolsGCHeap) \ + MACRO(Other, GCHeapUsed, bigIntsGCHeap) \ + MACRO(Other, MallocHeap, bigIntsMallocHeap) \ + MACRO(Other, GCHeapAdmin, gcHeapArenaAdmin) \ + MACRO(Other, GCHeapUsed, lazyScriptsGCHeap) \ + MACRO(Other, MallocHeap, lazyScriptsMallocHeap) \ + MACRO(Other, GCHeapUsed, jitCodesGCHeap) \ + MACRO(Other, GCHeapUsed, objectGroupsGCHeap) \ + MACRO(Other, MallocHeap, objectGroupsMallocHeap) \ + MACRO(Other, GCHeapUsed, scopesGCHeap) \ + MACRO(Other, MallocHeap, scopesMallocHeap) \ + MACRO(Other, GCHeapUsed, regExpSharedsGCHeap) \ + MACRO(Other, MallocHeap, regExpSharedsMallocHeap) \ + MACRO(Other, MallocHeap, typePool) \ + MACRO(Other, MallocHeap, regexpZone) \ + MACRO(Other, MallocHeap, jitZone) \ + MACRO(Other, MallocHeap, baselineStubsOptimized) \ + MACRO(Other, MallocHeap, cachedCFG) \ + MACRO(Other, MallocHeap, uniqueIdMap) \ + MACRO(Other, MallocHeap, shapeTables) \ + MACRO(Other, MallocHeap, compartmentObjects) \ + MACRO(Other, MallocHeap, crossCompartmentWrappersTables) \ + MACRO(Other, MallocHeap, compartmentsPrivateData) ZoneStats() : FOR_EACH_SIZE(ZERO_SIZE) unusedGCThings(), @@ -639,12 +680,12 @@ ZoneStats(ZoneStats&& other) : FOR_EACH_SIZE(COPY_OTHER_SIZE) - unusedGCThings(mozilla::Move(other.unusedGCThings)), - stringInfo(mozilla::Move(other.stringInfo)), - shapeInfo(mozilla::Move(other.shapeInfo)), + unusedGCThings(std::move(other.unusedGCThings)), + stringInfo(std::move(other.stringInfo)), + shapeInfo(std::move(other.shapeInfo)), extra(other.extra), allStrings(other.allStrings), - notableStrings(mozilla::Move(other.notableStrings)), + notableStrings(std::move(other.notableStrings)), isTotals(other.isTotals) { other.allStrings = nullptr; MOZ_ASSERT(!other.isTotals); @@ -718,11 +759,11 @@ #undef FOR_EACH_SIZE }; -struct CompartmentStats { -// We assume that |objectsPrivate| is on the malloc heap, but it's not -// actually guaranteed. But for Servo, at least, it's a moot point because -// it doesn't provide an ObjectPrivateVisitor so the value will always be -// zero. +struct RealmStats { + // We assume that |objectsPrivate| is on the malloc heap, but it's not + // actually guaranteed. But for Servo, at least, it's a moot point because + // it doesn't provide an ObjectPrivateVisitor so the value will always be + // zero. #define FOR_EACH_SIZE(MACRO) \ MACRO(Private, MallocHeap, objectsPrivate) \ MACRO(Other, GCHeapUsed, scriptsGCHeap) \ @@ -734,40 +775,37 @@ MACRO(Other, MallocHeap, typeInferenceAllocationSiteTables) \ MACRO(Other, MallocHeap, typeInferenceArrayTypeTables) \ MACRO(Other, MallocHeap, typeInferenceObjectTypeTables) \ - MACRO(Other, MallocHeap, compartmentObject) \ - MACRO(Other, MallocHeap, compartmentTables) \ + MACRO(Other, MallocHeap, realmObject) \ + MACRO(Other, MallocHeap, realmTables) \ MACRO(Other, MallocHeap, innerViewsTable) \ MACRO(Other, MallocHeap, lazyArrayBuffersTable) \ MACRO(Other, MallocHeap, objectMetadataTable) \ - MACRO(Other, MallocHeap, crossCompartmentWrappersTable) \ MACRO(Other, MallocHeap, savedStacksSet) \ MACRO(Other, MallocHeap, varNamesSet) \ MACRO(Other, MallocHeap, nonSyntacticLexicalScopesTable) \ - MACRO(Other, MallocHeap, jitCompartment) \ - MACRO(Other, MallocHeap, privateData) \ + MACRO(Other, MallocHeap, jitRealm) \ MACRO(Other, MallocHeap, scriptCountsMap) - CompartmentStats() + RealmStats() : FOR_EACH_SIZE(ZERO_SIZE) classInfo(), extra(), allClasses(nullptr), notableClasses(), isTotals(true) {} - CompartmentStats(CompartmentStats&& other) - : FOR_EACH_SIZE(COPY_OTHER_SIZE) - classInfo(mozilla::Move(other.classInfo)), + RealmStats(RealmStats&& other) + : FOR_EACH_SIZE(COPY_OTHER_SIZE) classInfo(std::move(other.classInfo)), extra(other.extra), allClasses(other.allClasses), - notableClasses(mozilla::Move(other.notableClasses)), + notableClasses(std::move(other.notableClasses)), isTotals(other.isTotals) { other.allClasses = nullptr; MOZ_ASSERT(!other.isTotals); } - CompartmentStats(const CompartmentStats&) = delete; // disallow copying + RealmStats(const RealmStats&) = delete; // disallow copying - ~CompartmentStats() { + ~RealmStats() { // |allClasses| is usually deleted and set to nullptr before this // destructor runs. But there are failure cases due to OOMs that may // prevent that, so it doesn't hurt to try again here. @@ -776,7 +814,7 @@ bool initClasses(); - void addSizes(const CompartmentStats& other) { + void addSizes(const RealmStats& other) { MOZ_ASSERT(isTotals); FOR_EACH_SIZE(ADD_OTHER_SIZE) classInfo.add(other.classInfo); @@ -809,7 +847,7 @@ ClassInfo classInfo; void* extra; // This field can be used by embedders. - typedef js::HashMap ClassesHashMap; @@ -821,16 +859,15 @@ #undef FOR_EACH_SIZE }; -typedef js::Vector - CompartmentStatsVector; +typedef js::Vector RealmStatsVector; typedef js::Vector ZoneStatsVector; struct RuntimeStats { -// |gcHeapChunkTotal| is ignored because it's the sum of all the other -// values. |gcHeapGCThings| is ignored because it's the sum of some of the -// values from the zones and compartments. Both of those values are not -// reported directly, but are just present for sanity-checking other -// values. + // |gcHeapChunkTotal| is ignored because it's the sum of all the other + // values. |gcHeapGCThings| is ignored because it's the sum of some of the + // values from the zones and compartments. Both of those values are not + // reported directly, but are just present for sanity-checking other + // values. #define FOR_EACH_SIZE(MACRO) \ MACRO(_, Ignore, gcHeapChunkTotal) \ MACRO(_, GCHeapDecommitted, gcHeapDecommittedArenas) \ @@ -841,9 +878,9 @@ explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf) : FOR_EACH_SIZE(ZERO_SIZE) runtime(), - cTotals(), + realmTotals(), zTotals(), - compartmentStatsVector(), + realmStatsVector(), zoneStatsVector(), currZoneStats(nullptr), mallocSizeOf_(mallocSizeOf) {} @@ -880,19 +917,18 @@ RuntimeSizes runtime; - CompartmentStats - cTotals; // The sum of this runtime's compartments' measurements. - ZoneStats zTotals; // The sum of this runtime's zones' measurements. + RealmStats realmTotals; // The sum of this runtime's realms' measurements. + ZoneStats zTotals; // The sum of this runtime's zones' measurements. - CompartmentStatsVector compartmentStatsVector; + RealmStatsVector realmStatsVector; ZoneStatsVector zoneStatsVector; ZoneStats* currZoneStats; mozilla::MallocSizeOf mallocSizeOf_; - virtual void initExtraCompartmentStats(JSCompartment* c, - CompartmentStats* cstats) = 0; + virtual void initExtraRealmStats(JS::Handle realm, + RealmStats* rstats) = 0; virtual void initExtraZoneStats(JS::Zone* zone, ZoneStats* zstats) = 0; #undef FOR_EACH_SIZE @@ -913,15 +949,19 @@ : getISupports_(getISupports) {} }; +extern JS_PUBLIC_API bool CollectGlobalStats(GlobalStats* gStats); + extern JS_PUBLIC_API bool CollectRuntimeStats(JSContext* cx, RuntimeStats* rtStats, ObjectPrivateVisitor* opv, bool anonymize); extern JS_PUBLIC_API size_t SystemCompartmentCount(JSContext* cx); - extern JS_PUBLIC_API size_t UserCompartmentCount(JSContext* cx); +extern JS_PUBLIC_API size_t SystemRealmCount(JSContext* cx); +extern JS_PUBLIC_API size_t UserRealmCount(JSContext* cx); + extern JS_PUBLIC_API size_t PeakSizeOfTemporary(const JSContext* cx); extern JS_PUBLIC_API bool AddSizeOfTab(JSContext* cx, JS::HandleObject obj, @@ -934,8 +974,6 @@ ObjectPrivateVisitor* opv, ServoSizes* sizes); -extern JS_PUBLIC_API void CollectTraceLoggerStateStats(RuntimeStats* rtStats); - } // namespace JS #undef DECL_SIZE Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/OffThreadScriptCompilation.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/OffThreadScriptCompilation.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/OffThreadScriptCompilation.h @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Types and functions related to the compilation of JavaScript off the + * direct JSAPI-using thread. + */ + +#ifndef js_OffThreadScriptCompilation_h +#define js_OffThreadScriptCompilation_h + +#include "mozilla/Range.h" // mozilla::Range +#include "mozilla/Vector.h" // mozilla::Vector + +#include // size_t + +#include "jstypes.h" // JS_PUBLIC_API + +#include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions +#include "js/GCVector.h" // JS::GCVector +#include "js/Transcoding.h" // JS::TranscodeSource + +struct JS_PUBLIC_API JSContext; +class JS_PUBLIC_API JSScript; + +namespace JS { + +template +class SourceText; + +} // namespace JS + +namespace JS { + +class OffThreadToken; + +using OffThreadCompileCallback = void (*)(OffThreadToken* token, + void* callbackData); + +extern JS_PUBLIC_API bool CanCompileOffThread( + JSContext* cx, const ReadOnlyCompileOptions& options, size_t length); + +extern JS_PUBLIC_API bool CanDecodeOffThread( + JSContext* cx, const ReadOnlyCompileOptions& options, size_t length); + +/* + * Off thread compilation control flow. + * + * After successfully triggering an off thread compile of a script, the + * callback will eventually be invoked with the specified data and a token + * for the compilation. The callback will be invoked while off thread, + * so must ensure that its operations are thread safe. Afterwards, one of the + * following functions must be invoked on the runtime's main thread: + * + * - FinishOffThreadScript, to get the result script (or nullptr on failure). + * - CancelOffThreadScript, to free the resources without creating a script. + * + * The characters passed in to CompileOffThread must remain live until the + * callback is invoked, and the resulting script will be rooted until the call + * to FinishOffThreadScript. + */ + +extern JS_PUBLIC_API bool CompileOffThread( + JSContext* cx, const ReadOnlyCompileOptions& options, + SourceText& srcBuf, OffThreadCompileCallback callback, + void* callbackData); + +extern JS_PUBLIC_API JSScript* FinishOffThreadScript(JSContext* cx, + OffThreadToken* token); + +extern JS_PUBLIC_API void CancelOffThreadScript(JSContext* cx, + OffThreadToken* token); + +extern JS_PUBLIC_API bool CompileOffThreadModule( + JSContext* cx, const ReadOnlyCompileOptions& options, + SourceText& srcBuf, OffThreadCompileCallback callback, + void* callbackData); + +extern JS_PUBLIC_API JSObject* FinishOffThreadModule(JSContext* cx, + OffThreadToken* token); + +extern JS_PUBLIC_API void CancelOffThreadModule(JSContext* cx, + OffThreadToken* token); + +extern JS_PUBLIC_API bool DecodeOffThreadScript( + JSContext* cx, const ReadOnlyCompileOptions& options, + mozilla::Vector& buffer /* TranscodeBuffer& */, size_t cursor, + OffThreadCompileCallback callback, void* callbackData); + +extern JS_PUBLIC_API bool DecodeOffThreadScript( + JSContext* cx, const ReadOnlyCompileOptions& options, + const mozilla::Range& range /* TranscodeRange& */, + OffThreadCompileCallback callback, void* callbackData); + +extern JS_PUBLIC_API JSScript* FinishOffThreadScriptDecoder( + JSContext* cx, OffThreadToken* token); + +extern JS_PUBLIC_API void CancelOffThreadScriptDecoder(JSContext* cx, + OffThreadToken* token); + +extern JS_PUBLIC_API bool DecodeMultiOffThreadScripts( + JSContext* cx, const ReadOnlyCompileOptions& options, + mozilla::Vector& sources, + OffThreadCompileCallback callback, void* callbackData); + +extern JS_PUBLIC_API bool FinishMultiOffThreadScriptsDecoder( + JSContext* cx, OffThreadToken* token, + MutableHandle> scripts); + +extern JS_PUBLIC_API void CancelMultiOffThreadScriptsDecoder( + JSContext* cx, OffThreadToken* token); + +#if defined(JS_BUILD_BINAST) + +extern JS_PUBLIC_API bool CanDecodeBinASTOffThread( + JSContext* cx, const ReadOnlyCompileOptions& options, size_t length); + +#endif // defined(JS_BUILD_BINAST) + +} // namespace JS + +#endif /* js_OffThreadScriptCompilation_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Principals.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Principals.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Principals.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -15,15 +15,14 @@ #include "jspubtd.h" -#include "js/StructuredClone.h" - -namespace js { -struct JS_PUBLIC_API PerformanceGroup; -} // namespace js +struct JSStructuredCloneReader; +struct JSStructuredCloneWriter; struct JSPrincipals { /* Don't call "destroy"; use reference counting macros below. */ - mozilla::Atomic refcount; + mozilla::Atomic + refcount; #ifdef JS_DEBUG /* A helper to facilitate principals debugging. */ @@ -63,9 +62,9 @@ /* * Used to check if a CSP instance wants to disable eval() and friends. - * See js_CheckCSPPermitsJSAction() in jsobj. + * See GlobalObject::isRuntimeCodeGenEnabled() in vm/GlobalObject.cpp. */ -typedef bool (*JSCSPEvalChecker)(JSContext* cx); +typedef bool (*JSCSPEvalChecker)(JSContext* cx, JS::HandleValue value); struct JSSecurityCallbacks { JSCSPEvalChecker contentSecurityPolicyAllows; Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Printf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Printf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Printf.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ProfilingCategory.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ProfilingCategory.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ProfilingCategory.h @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef js_ProfilingCategory_h +#define js_ProfilingCategory_h + +#include "jstypes.h" // JS_FRIEND_API + +// clang-format off + +// This higher-order macro lists all categories with their subcategories. +// +// PROFILING_CATEGORY_LIST(BEGIN_CATEGORY, SUBCATEGORY, END_CATEGORY) +// BEGIN_CATEGORY(name, labelAsString, colorAsString) +// SUBCATEGORY(category, name, labelAsString) +// END_CATEGORY +// +// The list of available color names for categories is: +// transparent, grey, purple, yellow, orange, lightblue, green, blue, magenta +// +// Categories and subcategories are used for stack-based instrumentation. They +// are specified in label frames in the profiling stack, see ProfilingStack.h. +// At any point, the category pair of the topmost profiler label frame in the +// label stack determines the category pair of that stack. +// Each category describes a type of workload that the CPU can be busy with. +// Categories should be non-overlapping: the list of categories should be +// chosen in such a way that every possible stack can be mapped to a single +// category unambiguously. + +#define PROFILING_CATEGORY_LIST(BEGIN_CATEGORY, SUBCATEGORY, END_CATEGORY) \ + BEGIN_CATEGORY(IDLE, "Idle", "transparent") \ + SUBCATEGORY(IDLE, IDLE, "Other") \ + END_CATEGORY \ + BEGIN_CATEGORY(OTHER, "Other", "grey") \ + SUBCATEGORY(OTHER, OTHER, "Other") \ + END_CATEGORY \ + BEGIN_CATEGORY(LAYOUT, "Layout", "purple") \ + SUBCATEGORY(LAYOUT, LAYOUT, "Other") \ + SUBCATEGORY(LAYOUT, LAYOUT_FrameConstruction, "Frame construction") \ + SUBCATEGORY(LAYOUT, LAYOUT_Reflow, "Reflow") \ + SUBCATEGORY(LAYOUT, LAYOUT_CSSParsing, "CSS parsing") \ + SUBCATEGORY(LAYOUT, LAYOUT_SelectorQuery, "Selector query") \ + SUBCATEGORY(LAYOUT, LAYOUT_StyleComputation, "Style computation") \ + END_CATEGORY \ + BEGIN_CATEGORY(JS, "JavaScript", "yellow") \ + SUBCATEGORY(JS, JS, "Other") \ + SUBCATEGORY(JS, JS_Parsing, "JS Parsing") \ + SUBCATEGORY(JS, JS_IonCompilation, "Ion JIT Compilation") \ + SUBCATEGORY(JS, JS_BaselineCompilation, "Baseline JIT Compilation") \ + END_CATEGORY \ + BEGIN_CATEGORY(GCCC, "GC / CC", "orange") \ + SUBCATEGORY(GCCC, GCCC, "Other") \ + END_CATEGORY \ + BEGIN_CATEGORY(NETWORK, "Network", "lightblue") \ + SUBCATEGORY(NETWORK, NETWORK, "Other") \ + END_CATEGORY \ + BEGIN_CATEGORY(GRAPHICS, "Graphics", "green") \ + SUBCATEGORY(GRAPHICS, GRAPHICS, "Other") \ + SUBCATEGORY(GRAPHICS, GRAPHICS_DisplayListBuilding, "DisplayList building") \ + SUBCATEGORY(GRAPHICS, GRAPHICS_DisplayListMerging, "DisplayList merging") \ + SUBCATEGORY(GRAPHICS, GRAPHICS_LayerBuilding, "Layer building") \ + SUBCATEGORY(GRAPHICS, GRAPHICS_TileAllocation, "Tile allocation") \ + SUBCATEGORY(GRAPHICS, GRAPHICS_WRDisplayList, "WebRender display list") \ + SUBCATEGORY(GRAPHICS, GRAPHICS_Rasterization, "Rasterization") \ + SUBCATEGORY(GRAPHICS, GRAPHICS_FlushingAsyncPaints, "Flushing async paints") \ + SUBCATEGORY(GRAPHICS, GRAPHICS_ImageDecoding, "Image decoding") \ + END_CATEGORY \ + BEGIN_CATEGORY(DOM, "DOM", "blue") \ + SUBCATEGORY(DOM, DOM, "Other") \ + END_CATEGORY + +namespace JS { + +// An enum that lists all possible category pairs in one list. +// This is the enum that is used in profiler stack labels. Having one list that +// includes subcategories from all categories in one list allows assigning the +// category pair to a stack label with just one number. +#define CATEGORY_ENUM_BEGIN_CATEGORY(name, labelAsString, color) +#define CATEGORY_ENUM_SUBCATEGORY(supercategory, name, labelAsString) name, +#define CATEGORY_ENUM_END_CATEGORY +enum class ProfilingCategoryPair : uint32_t { + PROFILING_CATEGORY_LIST(CATEGORY_ENUM_BEGIN_CATEGORY, + CATEGORY_ENUM_SUBCATEGORY, + CATEGORY_ENUM_END_CATEGORY) + COUNT, + LAST = COUNT - 1, +}; +#undef CATEGORY_ENUM_BEGIN_CATEGORY +#undef CATEGORY_ENUM_SUBCATEGORY +#undef CATEGORY_ENUM_END_CATEGORY + +// An enum that lists just the categories without their subcategories. +#define SUPERCATEGORY_ENUM_BEGIN_CATEGORY(name, labelAsString, color) name, +#define SUPERCATEGORY_ENUM_SUBCATEGORY(supercategory, name, labelAsString) +#define SUPERCATEGORY_ENUM_END_CATEGORY +enum class ProfilingCategory : uint32_t { + PROFILING_CATEGORY_LIST(SUPERCATEGORY_ENUM_BEGIN_CATEGORY, + SUPERCATEGORY_ENUM_SUBCATEGORY, + SUPERCATEGORY_ENUM_END_CATEGORY) + COUNT, + LAST = COUNT - 1, +}; +#undef SUPERCATEGORY_ENUM_BEGIN_CATEGORY +#undef SUPERCATEGORY_ENUM_SUBCATEGORY +#undef SUPERCATEGORY_ENUM_END_CATEGORY + +// clang-format on + +struct ProfilingCategoryPairInfo { + ProfilingCategory mCategory; + uint32_t mSubcategoryIndex; + const char* mLabel; +}; + +JS_FRIEND_API const ProfilingCategoryPairInfo& GetProfilingCategoryPairInfo( + ProfilingCategoryPair aCategoryPair); + +} // namespace JS + +#endif /* js_ProfilingCategory_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ProfilingFrameIterator.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ProfilingFrameIterator.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ProfilingFrameIterator.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -112,6 +112,7 @@ void* stackAddress; void* returnAddress; void* activation; + void* endStackAddress; const char* label; } JS_HAZ_GC_INVALIDATED; Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ProfilingStack.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ProfilingStack.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ProfilingStack.h @@ -1,5 +1,5 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -12,57 +12,62 @@ #include "jstypes.h" +#include "js/ProfilingCategory.h" #include "js/TypeDecls.h" #include "js/Utility.h" -class JSTracer; -class PseudoStack; +class JS_PUBLIC_API JSTracer; +class JS_FRIEND_API ProfilingStack; -// This file defines the classes PseudoStack and ProfileEntry. -// The PseudoStack manages an array of ProfileEntries. +// This file defines the classes ProfilingStack and ProfilingStackFrame. +// The ProfilingStack manages an array of ProfilingStackFrames. +// It keeps track of the "label stack" and the JS interpreter stack. +// The two stack types are interleaved. +// // Usage: // -// PseudoStack* pseudoStack = ...; +// ProfilingStack* profilingStack = ...; // -// // For CPP stack frames: -// pseudoStack->pushCppFrame(...); -// // Execute some code. When finished, pop the entry: -// pseudoStack->pop(); +// // For label frames: +// profilingStack->pushLabelFrame(...); +// // Execute some code. When finished, pop the frame: +// profilingStack->pop(); // // // For JS stack frames: -// pseudoStack->pushJSFrame(...); -// // Execute some code. When finished, pop the entry: -// pseudoStack->pop(); +// profilingStack->pushJSFrame(...); +// // Execute some code. When finished, pop the frame: +// profilingStack->pop(); // // // Concurrency considerations // -// A thread's pseudo stack (and the entries inside it) is only modified by -// that thread. However, the pseudo stack can be *read* by a different thread, -// the sampler thread: Whenever the profiler wants to sample a given thread A, -// the following happens: +// A thread's profiling stack (and the frames inside it) is only modified by +// that thread. However, the profiling stack can be *read* by a different +// thread, the sampler thread: Whenever the profiler wants to sample a given +// thread A, the following happens: // (1) Thread A is suspended. -// (2) The sampler thread (thread S) reads the PseudoStack of thread A, -// including all ProfileEntries that are currently in that stack -// (pseudoStack->entries[0..pseudoStack->stackSize()]). +// (2) The sampler thread (thread S) reads the ProfilingStack of thread A, +// including all ProfilingStackFrames that are currently in that stack +// (profilingStack->frames[0..profilingStack->stackSize()]). // (3) Thread A is resumed. // // Thread suspension is achieved using platform-specific APIs; refer to each // platform's Sampler::SuspendAndSampleAndResumeThread implementation in // platform-*.cpp for details. // -// When the thread is suspended, the values in pseudoStack->stackPointer and in -// the entry range pseudoStack->entries[0..pseudoStack->stackPointer] need to -// be in a consistent state, so that thread S does not read partially- -// constructed profile entries. More specifically, we have two requirements: -// (1) When adding a new entry at the top of the stack, its ProfileEntry data -// needs to be put in place *before* the stackPointer is incremented, and -// the compiler + CPU need to know that this order matters. -// (2) When popping an entry from the stack and then preparing the -// ProfileEntry data for the next frame that is about to be pushed, the -// decrement of the stackPointer in pop() needs to happen *before* the -// ProfileEntry for the new frame is being popuplated, and the compiler + -// CPU need to know that this order matters. +// When the thread is suspended, the values in profilingStack->stackPointer and +// in the stack frame range +// profilingStack->frames[0..profilingStack->stackPointer] need to be in a +// consistent state, so that thread S does not read partially- constructed stack +// frames. More specifically, we have two requirements: +// (1) When adding a new frame at the top of the stack, its ProfilingStackFrame +// data needs to be put in place *before* the stackPointer is incremented, +// and the compiler + CPU need to know that this order matters. +// (2) When popping an frame from the stack and then preparing the +// ProfilingStackFrame data for the next frame that is about to be pushed, +// the decrement of the stackPointer in pop() needs to happen *before* the +// ProfilingStackFrame for the new frame is being popuplated, and the +// compiler + CPU need to know that this order matters. // // We can express the relevance of these orderings in multiple ways. // Option A is to make stackPointer an atomic with SequentiallyConsistent @@ -70,19 +75,19 @@ // reordered across any writes to stackPointer, which satisfies requirements // (1) and (2) at the same time. Option A is the simplest. // Option B is to use ReleaseAcquire memory ordering both for writes to -// stackPointer *and* for writes to ProfileEntry fields. Release-stores ensure -// that all writes that happened *before this write in program order* are not -// reordered to happen after this write. ReleaseAcquire ordering places no +// stackPointer *and* for writes to ProfilingStackFrame fields. Release-stores +// ensure that all writes that happened *before this write in program order* are +// not reordered to happen after this write. ReleaseAcquire ordering places no // requirements on the ordering of writes that happen *after* this write in // program order. // Using release-stores for writes to stackPointer expresses requirement (1), -// and using release-stores for writes to the ProfileEntry fields expresses -// requirement (2). +// and using release-stores for writes to the ProfilingStackFrame fields +// expresses requirement (2). // // Option B is more complicated than option A, but has much better performance // on x86/64: In a microbenchmark run on a Macbook Pro from 2017, switching // from option A to option B reduced the overhead of pushing+popping a -// ProfileEntry by 10 nanoseconds. +// ProfilingStackFrame by 10 nanoseconds. // On x86/64, release-stores require no explicit hardware barriers or lock // instructions. // On ARM/64, option B may be slower than option A, because the compiler will @@ -95,12 +100,12 @@ namespace js { // A call stack can be specified to the JS engine such that all JS entry/exits -// to functions push/pop an entry to/from the specified stack. +// to functions push/pop a stack frame to/from the specified stack. // // For more detailed information, see vm/GeckoProfiler.h. // -class ProfileEntry { - // A ProfileEntry represents either a C++ profile entry or a JS one. +class ProfilingStackFrame { + // A ProfilingStackFrame represents either a label frame or a JS frame. // WARNING WARNING WARNING // @@ -108,100 +113,176 @@ // that writes to these fields are release-writes, which ensures that // earlier writes in this thread don't get reordered after the writes to // these fields. In particular, the decrement of the stack pointer in - // PseudoStack::pop() is a write that *must* happen before the values in - // this ProfileEntry are changed. Otherwise, the sampler thread might see - // an inconsistent state where the stack pointer still points to a - // ProfileEntry which has already been popped off the stack and whose + // ProfilingStack::pop() is a write that *must* happen before the values in + // this ProfilingStackFrame are changed. Otherwise, the sampler thread might + // see an inconsistent state where the stack pointer still points to a + // ProfilingStackFrame which has already been popped off the stack and whose // fields have now been partially repopulated with new values. // See the "Concurrency considerations" paragraph at the top of this file // for more details. - // Descriptive label for this entry. Must be a static string! Can be an - // empty string, but not a null pointer. - mozilla::Atomic label_; + // Descriptive label for this stack frame. Must be a static string! Can be + // an empty string, but not a null pointer. + mozilla::Atomic + label_; - // An additional descriptive string of this entry which is combined with + // An additional descriptive string of this frame which is combined with // |label_| in profiler output. Need not be (and usually isn't) static. Can // be null. - mozilla::Atomic dynamicString_; - - // Stack pointer for non-JS entries, the script pointer otherwise. - mozilla::Atomic spOrScript; - - // Line number for non-JS entries, the bytecode offset otherwise. - mozilla::Atomic lineOrPcOffset; - - // Bits 0...1 hold the Kind. Bits 2...3 are unused. Bits 4...12 hold the - // Category. - mozilla::Atomic kindAndCategory_; + mozilla::Atomic + dynamicString_; + + // Stack pointer for non-JS stack frames, the script pointer otherwise. + mozilla::Atomic + spOrScript; + + // The bytecode offset for JS stack frames. + // Must not be used on non-JS frames; it'll contain either the default 0, + // or a leftover value from a previous JS stack frame that was using this + // ProfilingStackFrame object. + mozilla::Atomic + pcOffsetIfJS_; + + // Bits 0...8 hold the Flags. Bits 9...31 hold the category pair. + mozilla::Atomic + flagsAndCategoryPair_; static int32_t pcToOffset(JSScript* aScript, jsbytecode* aPc); public: - enum class Kind : uint32_t { - // A normal C++ frame. - CPP_NORMAL = 0, - - // A special C++ frame indicating the start of a run of JS pseudostack - // entries. CPP_MARKER_FOR_JS frames are ignored, except for the sp - // field. - CPP_MARKER_FOR_JS = 1, - - // A normal JS frame. - JS_NORMAL = 2, - - // An interpreter JS frame that has OSR-ed into baseline. JS_NORMAL - // frames can be converted to JS_OSR and back. JS_OSR frames are - // ignored. - JS_OSR = 3, + ProfilingStackFrame() = default; + ProfilingStackFrame& operator=(const ProfilingStackFrame& other) { + label_ = other.label(); + dynamicString_ = other.dynamicString(); + void* spScript = other.spOrScript; + spOrScript = spScript; + int32_t offsetIfJS = other.pcOffsetIfJS_; + pcOffsetIfJS_ = offsetIfJS; + uint32_t flagsAndCategory = other.flagsAndCategoryPair_; + flagsAndCategoryPair_ = flagsAndCategory; + return *this; + } + + // 9 bits for the flags. + // That leaves 32 - 9 = 23 bits for the category pair. + enum class Flags : uint32_t { + // The first three flags describe the kind of the frame and are + // mutually exclusive. (We still give them individual bits for + // simplicity.) + + // A regular label frame. These usually come from AutoProfilerLabel. + IS_LABEL_FRAME = 1 << 0, + + // A special frame indicating the start of a run of JS profiling stack + // frames. IS_SP_MARKER_FRAME frames are ignored, except for the sp + // field. These frames are needed to get correct ordering between JS + // and LABEL frames because JS frames don't carry sp information. + // SP is short for "stack pointer". + IS_SP_MARKER_FRAME = 1 << 1, + + // A JS frame. + IS_JS_FRAME = 1 << 2, + + // An interpreter JS frame that has OSR-ed into baseline. IS_JS_FRAME + // frames can have this flag set and unset during their lifetime. + // JS_OSR frames are ignored. + JS_OSR = 1 << 3, + + // The next three are mutually exclusive. + // By default, for profiling stack frames that have both a label and a + // dynamic string, the two strings are combined into one string of the + // form "