Index: ps/trunk/build/premake/extern_libs5.lua =================================================================== --- ps/trunk/build/premake/extern_libs5.lua +++ ps/trunk/build/premake/extern_libs5.lua @@ -533,9 +533,9 @@ }, spidermonkey = { compile_settings = function() - if _OPTIONS["with-system-mozjs45"] then + if _OPTIONS["with-system-mozjs52"] then if not _OPTIONS["android"] then - pkgconfig.add_includes("mozjs-45") + pkgconfig.add_includes("mozjs-52") end else if os.istarget("windows") then @@ -553,21 +553,21 @@ end end, link_settings = function() - if _OPTIONS["with-system-mozjs45"] then + if _OPTIONS["with-system-mozjs52"] then if _OPTIONS["android"] then - links { "mozjs-45" } + links { "mozjs-52" } else - pkgconfig.add_links("mozjs-45") + pkgconfig.add_links("mozjs-52") end else filter { "Debug", "action:vs2015" } - links { "mozjs45-ps-debug-vc140" } + links { "mozjs52-ps-debug-vc140" } filter { "Release", "action:vs2015" } - links { "mozjs45-ps-release-vc140" } + links { "mozjs52-ps-release-vc140" } filter { "Debug", "action:not vs*" } - links { "mozjs45-ps-debug" } + links { "mozjs52-ps-debug" } filter { "Release", "action:not vs*" } - links { "mozjs45-ps-release" } + links { "mozjs52-ps-release" } filter { } add_source_lib_paths("spidermonkey") end Index: ps/trunk/build/premake/premake5.lua =================================================================== --- ps/trunk/build/premake/premake5.lua +++ ps/trunk/build/premake/premake5.lua @@ -6,7 +6,7 @@ newoption { trigger = "jenkins-tests", description = "Configure CxxTest to use the XmlPrinter runner which produces Jenkins-compatible output" } newoption { trigger = "minimal-flags", description = "Only set compiler/linker flags that are really needed. Has no effect on Windows builds" } newoption { trigger = "outpath", description = "Location for generated project files" } -newoption { trigger = "with-system-mozjs45", description = "Search standard paths for libmozjs45, instead of using bundled copy" } +newoption { trigger = "with-system-mozjs52", description = "Search standard paths for libmozjs52, instead of using bundled copy" } newoption { trigger = "with-system-nvtt", description = "Search standard paths for nvidia-texture-tools library, instead of using bundled copy" } newoption { trigger = "without-audio", description = "Disable use of OpenAL/Ogg/Vorbis APIs" } newoption { trigger = "without-lobby", description = "Disable the use of gloox and the multiplayer lobby" } Index: ps/trunk/libraries/osx/build-osx-libs.sh =================================================================== --- ps/trunk/libraries/osx/build-osx-libs.sh +++ ps/trunk/libraries/osx/build-osx-libs.sh @@ -48,12 +48,11 @@ SODIUM_VERSION="libsodium-1.0.18" # -------------------------------------------------------------- # Bundled with the game: -# * SpiderMonkey 45 +# * SpiderMonkey # * NVTT # * FCollada # -------------------------------------------------------------- # We use suffixes here in order to force rebuilding when patching these libs -SPIDERMONKEY_VERSION="mozjs-45.0.2+wildfiregames.2" NVTT_VERSION="nvtt-2.1.1+wildfiregames.1" FCOLLADA_VERSION="fcollada-3.05+wildfiregames.1" # -------------------------------------------------------------- @@ -911,88 +910,16 @@ # be customized, so we build and install them from bundled sources # -------------------------------------------------------------------- # SpiderMonkey - bundled, no download -echo -e "Building SpiderMonkey..." - -LIB_VERSION="${SPIDERMONKEY_VERSION}" -LIB_DIRECTORY="mozjs-45.0.2" -LIB_ARCHIVE="$LIB_DIRECTORY.tar.bz2" - pushd ../source/spidermonkey/ > /dev/null -if [[ "$force_rebuild" = "true" ]] || [[ ! -e .already-built ]] || [[ "$(<.already-built)" != "$LIB_VERSION" ]] +if [[ "$force_rebuild" = "true" ]] then - INSTALL_DIR="$(pwd)" - INCLUDE_DIR_DEBUG=$INSTALL_DIR/include-unix-debug - INCLUDE_DIR_RELEASE=$INSTALL_DIR/include-unix-release - rm -f .already-built - rm -f lib/*.a - rm -rf $LIB_DIRECTORY $INCLUDE_DIR_DEBUG $INCLUDE_DIR_RELEASE - tar -xf $LIB_ARCHIVE - - # Apply patches - pushd $LIB_DIRECTORY - . ../patch.sh - popd - - pushd $LIB_DIRECTORY/js/src - - CONF_OPTS="--target=$ARCH-apple-darwin - --prefix=${INSTALL_DIR} - --enable-posix-nspr-emulation - --with-system-zlib=${ZLIB_DIR} - --disable-tests - --disable-shared-js - --disable-jemalloc - --without-intl-api" - # Change the default location where the tracelogger should store its output, which is /tmp/ on OSX. - TLCXXFLAGS='-DTRACE_LOG_DIR="\"../../source/tools/tracelogger/\""' - if [[ $MIN_OSX_VERSION && ${MIN_OSX_VERSION-_} ]]; then - CONF_OPTS="$CONF_OPTS --enable-macos-target=$MIN_OSX_VERSION" - fi - if [[ $SYSROOT && ${SYSROOT-_} ]]; then - CONF_OPTS="$CONF_OPTS --with-macosx-sdk=$SYSROOT" - fi +fi - # We want separate debug/release versions of the library, so change their install name in the Makefile - perl -i.bak -pe 's/(^STATIC_LIBRARY_NAME\s+=).*/$1'\''mozjs45-ps-debug'\''/' moz.build - mkdir -p build-debug - pushd build-debug - (CC="clang" CXX="clang++" CXXFLAGS="${TLCXXFLAGS}" AR=ar CROSS_COMPILE=1 \ - ../configure $CONF_OPTS \ - --enable-debug \ - --disable-optimize \ - --enable-js-diagnostics \ - --enable-gczeal \ - && make ${JOBS}) || die "SpiderMonkey build failed" - # js-config.h is different for debug and release builds, so we need different include directories for both - mkdir -p $INCLUDE_DIR_DEBUG - cp -R -L dist/include/* $INCLUDE_DIR_DEBUG/ - cp dist/sdk/lib/*.a $INSTALL_DIR/lib - cp js/src/*.a $INSTALL_DIR/lib - popd - mv moz.build.bak moz.build +# Use the regular build script for SM. +JOBS="$JOBS" ZLIB_DIR="$ZLIB_DIR" ./build.sh - perl -i.bak -pe 's/(^STATIC_LIBRARY_NAME\s+=).*/$1'\''mozjs45-ps-release'\''/' moz.build - mkdir -p build-release - pushd build-release - (CC="clang" CXX="clang++" CXXFLAGS="${TLCXXFLAGS}" AR=ar CROSS_COMPILE=1 \ - ../configure $CONF_OPTS \ - --enable-optimize \ - && make ${JOBS}) || die "SpiderMonkey build failed" - # js-config.h is different for debug and release builds, so we need different include directories for both - mkdir -p $INCLUDE_DIR_RELEASE - cp -R -L dist/include/* $INCLUDE_DIR_RELEASE/ - cp dist/sdk/lib/*.a $INSTALL_DIR/lib - cp js/src/*.a $INSTALL_DIR/lib - popd - mv moz.build.bak moz.build - - popd - echo "$LIB_VERSION" > .already-built -else - already_built -fi popd > /dev/null # -------------------------------------------------------------- Index: ps/trunk/libraries/source/spidermonkey/DisableGCC9WerrorFormat.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/DisableGCC9WerrorFormat.diff +++ ps/trunk/libraries/source/spidermonkey/DisableGCC9WerrorFormat.diff @@ -0,0 +1,26 @@ +diff --git a/js/src/moz.build b/js/src/moz.build +--- a/js/src/moz.build 2020-07-16 11:42:39.578932510 +0200 ++++ b/js/src/moz.build 2020-07-16 11:45:18.937079912 +0200 +@@ -785,7 +785,7 @@ + DEFINES['FFI_BUILDING'] = True + + if CONFIG['GNU_CXX']: +- CXXFLAGS += ['-Wno-shadow', '-Werror=format'] ++ CXXFLAGS += ['-Wno-shadow'] + + # Suppress warnings in third-party code. + if CONFIG['CLANG_CXX']: +diff --git a/js/src/shell/moz.build b/js/src/shell/moz.build +--- a/js/src/shell/moz.build 2020-07-16 11:46:16.786621311 +0200 ++++ b/js/src/shell/moz.build 2020-07-16 11:46:35.616493037 +0200 +@@ -51,7 +51,7 @@ + ] + + if CONFIG['GNU_CXX']: +- CXXFLAGS += ['-Wno-shadow', '-Werror=format'] ++ CXXFLAGS += ['-Wno-shadow'] + + # This is intended as a temporary workaround to enable VS2015. + if CONFIG['_MSC_VER']: + + Index: ps/trunk/libraries/source/spidermonkey/ExportJSPropertyDescriptor.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/ExportJSPropertyDescriptor.diff +++ ps/trunk/libraries/source/spidermonkey/ExportJSPropertyDescriptor.diff @@ -1,26 +0,0 @@ -diff --git a/js/src/jsapi.h b/js/src/jsapi.h -index 29406243..2370457f 100644 ---- a/js/src/jsapi.h -+++ b/js/src/jsapi.h -@@ -2399,7 +2399,7 @@ JS_FreezeObject(JSContext* cx, JS::Handle obj); - - /*** Property descriptors ************************************************************************/ - --struct JSPropertyDescriptor : public JS::Traceable { -+struct JS_PUBLIC_API(JSPropertyDescriptor) : public JS::Traceable { - JSObject* obj; - unsigned attrs; - JSGetterOp getter; -diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h -index ba592525..3c185527 100644 ---- a/js/src/jspubtd.h -+++ b/js/src/jspubtd.h -@@ -97,7 +97,7 @@ struct JSFunctionSpec; - struct JSLocaleCallbacks; - struct JSObjectMap; - struct JSPrincipals; --struct JSPropertyDescriptor; -+struct JS_PUBLIC_API(JSPropertyDescriptor); - struct JSPropertyName; - struct JSPropertySpec; - struct JSRuntime; Index: ps/trunk/libraries/source/spidermonkey/FixLinking.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/FixLinking.diff +++ ps/trunk/libraries/source/spidermonkey/FixLinking.diff @@ -1,49 +0,0 @@ -From dcf520da15d940c900d7e8ffd5a9b05427c54dc8 Mon Sep 17 00:00:00 2001 -From: Philip Chimento -Date: Wed, 5 Jul 2017 22:47:44 -0700 -Subject: [PATCH 4/9] headers: Fix symbols visibility - -Some symbols that need to be public are not marked as such. ---- - js/public/Utility.h | 2 +- - js/src/jsalloc.h | 4 +++- - 2 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/js/public/Utility.h b/js/public/Utility.h -index 75214c32..f50fd8dd 100644 ---- a/js/public/Utility.h -+++ b/js/public/Utility.h -@@ -77,7 +77,7 @@ enum ThreadType { - # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) - extern bool InitThreadType(void); - extern void SetThreadType(ThreadType); --extern uint32_t GetThreadType(void); -+extern JS_FRIEND_API(uint32_t) GetThreadType(void); - # else - inline bool InitThreadType(void) { return true; } - inline void SetThreadType(ThreadType t) {}; -diff --git a/js/src/jsalloc.h b/js/src/jsalloc.h -index b9ae5190..234ea9dc 100644 ---- a/js/src/jsalloc.h -+++ b/js/src/jsalloc.h -@@ -17,6 +17,8 @@ - #include "js/TypeDecls.h" - #include "js/Utility.h" - -+extern JS_PUBLIC_API(void) JS_ReportOutOfMemory(JSContext* cx); -+ - namespace js { - - enum class AllocFunction { -@@ -130,7 +132,7 @@ class TempAllocPolicy - - bool checkSimulatedOOM() const { - if (js::oom::ShouldFailWithOOM()) { -- js::ReportOutOfMemory(reinterpret_cast(cx_)); -+ JS_ReportOutOfMemory(reinterpret_cast(cx_)); - return false; - } - --- -2.11.0 (Apple Git-81) - Index: ps/trunk/libraries/source/spidermonkey/FixMSVCBuild.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/FixMSVCBuild.diff +++ ps/trunk/libraries/source/spidermonkey/FixMSVCBuild.diff @@ -0,0 +1,447 @@ + +# HG changeset patch +# User Vladimir Vukicevic +# Date 1479240485 21600 +# Node ID 9822e0525b82bcca19078eab6532c8972977a156 +# Parent 07fa89dfac8390c8529181cbf818b6e5c1a75bf1 +Bug 1300925 - Change Intl.cpp stubs to an anonymous namespace. r=Waldo + +MozReview-Commit-ID: 9Ed1gglWsby + +diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp +--- a/js/src/builtin/Intl.cpp ++++ b/js/src/builtin/Intl.cpp +@@ -69,26 +69,28 @@ using mozilla::PodCopy; + * against ICU. However, we still want to compile this code in order to prevent + * bit rot. The following stub implementations for ICU functions make this + * possible. The functions using them should never be called, so they assert + * and return error codes. Signatures adapted from ICU header files locid.h, + * numsys.h, ucal.h, ucol.h, udat.h, udatpg.h, uenum.h, unum.h; see the ICU + * directory for license. + */ + ++namespace { ++ + typedef bool UBool; + typedef char16_t UChar; + typedef double UDate; + + enum UErrorCode { + U_ZERO_ERROR, + U_BUFFER_OVERFLOW_ERROR, + }; + +-static inline UBool ++inline UBool + U_FAILURE(UErrorCode code) + { + MOZ_CRASH("U_FAILURE: Intl API disabled"); + } + + inline const UChar* + Char16ToUChar(const char16_t* chars) + { +@@ -96,37 +98,37 @@ Char16ToUChar(const char16_t* chars) + } + + inline UChar* + Char16ToUChar(char16_t* chars) + { + MOZ_CRASH("Char16ToUChar: Intl API disabled"); + } + +-static int32_t ++int32_t + u_strlen(const UChar* s) + { + MOZ_CRASH("u_strlen: Intl API disabled"); + } + + struct UEnumeration; + +-static int32_t ++int32_t + uenum_count(UEnumeration* en, UErrorCode* status) + { + MOZ_CRASH("uenum_count: Intl API disabled"); + } + +-static const char* ++const char* + uenum_next(UEnumeration* en, int32_t* resultLength, UErrorCode* status) + { + MOZ_CRASH("uenum_next: Intl API disabled"); + } + +-static void ++void + uenum_close(UEnumeration* en) + { + MOZ_CRASH("uenum_close: Intl API disabled"); + } + + struct UCollator; + + enum UColAttribute { +@@ -151,54 +153,54 @@ enum UColAttributeValue { + }; + + enum UCollationResult { + UCOL_EQUAL = 0, + UCOL_GREATER = 1, + UCOL_LESS = -1 + }; + +-static int32_t ++int32_t + ucol_countAvailable() + { + MOZ_CRASH("ucol_countAvailable: Intl API disabled"); + } + +-static const char* ++const char* + ucol_getAvailable(int32_t localeIndex) + { + MOZ_CRASH("ucol_getAvailable: Intl API disabled"); + } + +-static UCollator* ++UCollator* + ucol_open(const char* loc, UErrorCode* status) + { + MOZ_CRASH("ucol_open: Intl API disabled"); + } + +-static void ++void + ucol_setAttribute(UCollator* coll, UColAttribute attr, UColAttributeValue value, UErrorCode* status) + { + MOZ_CRASH("ucol_setAttribute: Intl API disabled"); + } + +-static UCollationResult ++UCollationResult + ucol_strcoll(const UCollator* coll, const UChar* source, int32_t sourceLength, + const UChar* target, int32_t targetLength) + { + MOZ_CRASH("ucol_strcoll: Intl API disabled"); + } + +-static void ++void + ucol_close(UCollator* coll) + { + MOZ_CRASH("ucol_close: Intl API disabled"); + } + +-static UEnumeration* ++UEnumeration* + ucol_getKeywordValuesForLocale(const char* key, const char* locale, UBool commonlyUsed, + UErrorCode* status) + { + MOZ_CRASH("ucol_getKeywordValuesForLocale: Intl API disabled"); + } + + struct UParseError; + struct UFieldPosition; +@@ -227,76 +229,76 @@ enum UNumberFormatAttribute { + UNUM_MIN_SIGNIFICANT_DIGITS, + UNUM_MAX_SIGNIFICANT_DIGITS, + }; + + enum UNumberFormatTextAttribute { + UNUM_CURRENCY_CODE, + }; + +-static int32_t ++int32_t + unum_countAvailable() + { + MOZ_CRASH("unum_countAvailable: Intl API disabled"); + } + +-static const char* ++const char* + unum_getAvailable(int32_t localeIndex) + { + MOZ_CRASH("unum_getAvailable: Intl API disabled"); + } + +-static UNumberFormat* ++UNumberFormat* + unum_open(UNumberFormatStyle style, const UChar* pattern, int32_t patternLength, + const char* locale, UParseError* parseErr, UErrorCode* status) + { + MOZ_CRASH("unum_open: Intl API disabled"); + } + +-static void ++void + unum_setAttribute(UNumberFormat* fmt, UNumberFormatAttribute attr, int32_t newValue) + { + MOZ_CRASH("unum_setAttribute: Intl API disabled"); + } + +-static int32_t ++int32_t + unum_formatDouble(const UNumberFormat* fmt, double number, UChar* result, + int32_t resultLength, UFieldPosition* pos, UErrorCode* status) + { + MOZ_CRASH("unum_formatDouble: Intl API disabled"); + } + +-static void ++void + unum_close(UNumberFormat* fmt) + { + MOZ_CRASH("unum_close: Intl API disabled"); + } + +-static void ++void + unum_setTextAttribute(UNumberFormat* fmt, UNumberFormatTextAttribute tag, const UChar* newValue, + int32_t newValueLength, UErrorCode* status) + { + MOZ_CRASH("unum_setTextAttribute: Intl API disabled"); + } + + typedef void* UNumberingSystem; + +-static UNumberingSystem* ++UNumberingSystem* + unumsys_open(const char* locale, UErrorCode* status) + { + MOZ_CRASH("unumsys_open: Intl API disabled"); + } + +-static const char* ++const char* + unumsys_getName(const UNumberingSystem* unumsys) + { + MOZ_CRASH("unumsys_getName: Intl API disabled"); + } + +-static void ++void + unumsys_close(UNumberingSystem* unumsys) + { + MOZ_CRASH("unumsys_close: Intl API disabled"); + } + + typedef void* UCalendar; + + enum UCalendarType { +@@ -350,97 +352,97 @@ enum UCalendarDateFields { + UCAL_EXTENDED_YEAR, + UCAL_JULIAN_DAY, + UCAL_MILLISECONDS_IN_DAY, + UCAL_IS_LEAP_MONTH, + UCAL_FIELD_COUNT, + UCAL_DAY_OF_MONTH = UCAL_DATE + }; + +-static UCalendar* ++UCalendar* + ucal_open(const UChar* zoneID, int32_t len, const char* locale, + UCalendarType type, UErrorCode* status) + { + MOZ_CRASH("ucal_open: Intl API disabled"); + } + +-static const char* ++const char* + ucal_getType(const UCalendar* cal, UErrorCode* status) + { + MOZ_CRASH("ucal_getType: Intl API disabled"); + } + +-static UEnumeration* ++UEnumeration* + ucal_getKeywordValuesForLocale(const char* key, const char* locale, + UBool commonlyUsed, UErrorCode* status) + { + MOZ_CRASH("ucal_getKeywordValuesForLocale: Intl API disabled"); + } + +-static void ++void + ucal_close(UCalendar* cal) + { + MOZ_CRASH("ucal_close: Intl API disabled"); + } + +-static UCalendarWeekdayType ++UCalendarWeekdayType + ucal_getDayOfWeekType(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode* status) + { + MOZ_CRASH("ucal_getDayOfWeekType: Intl API disabled"); + } + +-static int32_t ++int32_t + ucal_getAttribute(const UCalendar* cal, + UCalendarAttribute attr) + { + MOZ_CRASH("ucal_getAttribute: Intl API disabled"); + } + +-static int32_t ++int32_t + ucal_get(const UCalendar *cal, UCalendarDateFields field, UErrorCode *status) + { + MOZ_CRASH("ucal_get: Intl API disabled"); + } + +-static UEnumeration* ++UEnumeration* + ucal_openTimeZones(UErrorCode* status) + { + MOZ_CRASH("ucal_openTimeZones: Intl API disabled"); + } + +-static int32_t ++int32_t + ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len, UChar* result, int32_t resultCapacity, + UBool* isSystemID, UErrorCode* status) + { + MOZ_CRASH("ucal_getCanonicalTimeZoneID: Intl API disabled"); + } + +-static int32_t ++int32_t + ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* status) + { + MOZ_CRASH("ucal_getDefaultTimeZone: Intl API disabled"); + } + + typedef void* UDateTimePatternGenerator; + +-static UDateTimePatternGenerator* ++UDateTimePatternGenerator* + udatpg_open(const char* locale, UErrorCode* pErrorCode) + { + MOZ_CRASH("udatpg_open: Intl API disabled"); + } + +-static int32_t ++int32_t + udatpg_getBestPattern(UDateTimePatternGenerator* dtpg, const UChar* skeleton, + int32_t length, UChar* bestPattern, int32_t capacity, + UErrorCode* pErrorCode) + { + MOZ_CRASH("udatpg_getBestPattern: Intl API disabled"); + } + +-static void ++void + udatpg_close(UDateTimePatternGenerator* dtpg) + { + MOZ_CRASH("udatpg_close: Intl API disabled"); + } + + typedef void* UCalendar; + typedef void* UDateFormat; + +@@ -486,87 +488,89 @@ enum UDateFormatField { + UDAT_FIELD_COUNT = 38 + }; + + enum UDateFormatStyle { + UDAT_PATTERN = -2, + UDAT_IGNORE = UDAT_PATTERN + }; + +-static int32_t ++int32_t + udat_countAvailable() + { + MOZ_CRASH("udat_countAvailable: Intl API disabled"); + } + +-static const char* ++const char* + udat_getAvailable(int32_t localeIndex) + { + MOZ_CRASH("udat_getAvailable: Intl API disabled"); + } + +-static UDateFormat* ++UDateFormat* + udat_open(UDateFormatStyle timeStyle, UDateFormatStyle dateStyle, const char* locale, + const UChar* tzID, int32_t tzIDLength, const UChar* pattern, + int32_t patternLength, UErrorCode* status) + { + MOZ_CRASH("udat_open: Intl API disabled"); + } + +-static const UCalendar* ++const UCalendar* + udat_getCalendar(const UDateFormat* fmt) + { + MOZ_CRASH("udat_getCalendar: Intl API disabled"); + } + +-static void ++void + ucal_setGregorianChange(UCalendar* cal, UDate date, UErrorCode* pErrorCode) + { + MOZ_CRASH("ucal_setGregorianChange: Intl API disabled"); + } + +-static int32_t ++int32_t + udat_format(const UDateFormat* format, UDate dateToFormat, UChar* result, + int32_t resultLength, UFieldPosition* position, UErrorCode* status) + { + MOZ_CRASH("udat_format: Intl API disabled"); + } + +-static int32_t ++int32_t + udat_formatForFields(const UDateFormat* format, UDate dateToFormat, + UChar* result, int32_t resultLength, UFieldPositionIterator* fpositer, + UErrorCode* status) + { + MOZ_CRASH("udat_formatForFields: Intl API disabled"); + } + +-static UFieldPositionIterator* ++UFieldPositionIterator* + ufieldpositer_open(UErrorCode* status) + { + MOZ_CRASH("ufieldpositer_open: Intl API disabled"); + } + +-static void ++void + ufieldpositer_close(UFieldPositionIterator* fpositer) + { + MOZ_CRASH("ufieldpositer_close: Intl API disabled"); + } + +-static int32_t ++int32_t + ufieldpositer_next(UFieldPositionIterator* fpositer, int32_t* beginIndex, int32_t* endIndex) + { + MOZ_CRASH("ufieldpositer_next: Intl API disabled"); + } + +-static void ++void + udat_close(UDateFormat* format) + { + MOZ_CRASH("udat_close: Intl API disabled"); + } + ++} // anonymous namespace ++ + #endif + + + /******************** Common to Intl constructors ********************/ + + static bool + IntlInitialize(JSContext* cx, HandleObject obj, Handle initializer, + HandleValue locales, HandleValue options) + Index: ps/trunk/libraries/source/spidermonkey/FixMozglue.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/FixMozglue.diff +++ ps/trunk/libraries/source/spidermonkey/FixMozglue.diff @@ -0,0 +1,70 @@ +From 4de4b45ff25690aabd5797928b66005555379ffa Mon Sep 17 00:00:00 2001 +From: Till Schneidereit +Date: Thu, 1 Oct 2015 12:59:09 +0200 +Subject: [PATCH 5/9] Disable MOZ_GLUE_IN_PROGRAM in stand-alone builds on all + platforms + +Otherwise, build fails not being able to find HashBytes. + +Patch ported forward to mozjs52 by Philip Chimento +. + +https://bugzilla.mozilla.org/show_bug.cgi?id=1176787 +--- + js/src/old-configure.in | 23 ++++++++++++++--------- + mozglue/build/moz.build | 2 +- + 2 files changed, 15 insertions(+), 10 deletions(-) + +diff --git a/js/src/old-configure.in b/js/src/old-configure.in +index c40eb962..336e1aa7 100644 +--- a/js/src/old-configure.in ++++ b/js/src/old-configure.in +@@ -1620,16 +1620,21 @@ dnl ======================================================== + dnl = Enable jemalloc + dnl ======================================================== + +-case "${OS_TARGET}" in +-Android|WINNT|Darwin) ++dnl In stand-alone builds we always only want to link executables against mozglue. ++if test "$JS_STANDALONE"; then + MOZ_GLUE_IN_PROGRAM= +- ;; +-*) +- dnl On !Android !Windows !OSX, we only want to link executables against mozglue +- MOZ_GLUE_IN_PROGRAM=1 +- AC_DEFINE(MOZ_GLUE_IN_PROGRAM) +- ;; +-esac ++else ++ case "${OS_TARGET}" in ++ Android|WINNT|Darwin) ++ MOZ_GLUE_IN_PROGRAM= ++ ;; ++ *) ++ dnl On !Android !Windows !OSX, we only want to link executables against mozglue ++ MOZ_GLUE_IN_PROGRAM=1 ++ AC_DEFINE(MOZ_GLUE_IN_PROGRAM) ++ ;; ++ esac ++fi + + if test "$MOZ_MEMORY"; then + if test "x$MOZ_DEBUG" = "x1"; then +diff --git a/mozglue/build/moz.build b/mozglue/build/moz.build +index d289747785a1..fd1e78a543ed 100644 +--- a/mozglue/build/moz.build ++++ b/mozglue/build/moz.build +@@ -4,9 +4,12 @@ + # 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/. + ++if CONFIG['JS_STANDALONE']: ++ Library('mozglue') ++ FINAL_LIBRARY = 'js' + # Build mozglue as a shared lib on Windows, OSX and Android. + # If this is ever changed, update MOZ_SHARED_MOZGLUE in browser/installer/Makefile.in +-if CONFIG['OS_TARGET'] in ('WINNT', 'Darwin', 'Android'): ++elif CONFIG['OS_TARGET'] in ('WINNT', 'Darwin', 'Android'): + SharedLibrary('mozglue') + else: + Library('mozglue') Index: ps/trunk/libraries/source/spidermonkey/FixMozglueStatic.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/FixMozglueStatic.diff +++ ps/trunk/libraries/source/spidermonkey/FixMozglueStatic.diff @@ -1,20 +0,0 @@ -diff --git a/mozglue/build/moz.build b/mozglue/build/moz.build -index 58e2db6..1cfb504 100644 ---- a/mozglue/build/moz.build -+++ b/mozglue/build/moz.build -@@ -4,12 +4,9 @@ - # 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/. - --# Build mozglue as a shared lib on Windows, OSX and Android. --# If this is ever changed, update MOZ_SHARED_MOZGLUE in browser/installer/Makefile.in --if CONFIG['OS_TARGET'] in ('WINNT', 'Darwin', 'Android'): -- SharedLibrary('mozglue') --else: -- Library('mozglue') -+# Build mozglue as a static lib into js for 0 A.D. -+Library('mozglue') -+FINAL_LIBRARY = 'js' - - if not CONFIG['MOZ_CRT']: - SDK_LIBRARY = True Index: ps/trunk/libraries/source/spidermonkey/FixNonx86.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/FixNonx86.diff +++ ps/trunk/libraries/source/spidermonkey/FixNonx86.diff @@ -1,229 +0,0 @@ -diff --git a/js/src/gc/Memory.cpp b/js/src/gc/Memory.cpp ---- a/js/src/gc/Memory.cpp -+++ b/js/src/gc/Memory.cpp -@@ -430,17 +430,17 @@ InitMemorySubsystem() - if (pageSize == 0) - pageSize = allocGranularity = size_t(sysconf(_SC_PAGESIZE)); - } - - static inline void* - MapMemoryAt(void* desired, size_t length, int prot = PROT_READ | PROT_WRITE, - int flags = MAP_PRIVATE | MAP_ANON, int fd = -1, off_t offset = 0) - { --#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__)) -+#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__)) || defined(__aarch64__) - MOZ_ASSERT(0xffff800000000000ULL & (uintptr_t(desired) + length - 1) == 0); - #endif - void* region = mmap(desired, length, prot, flags, fd, offset); - if (region == MAP_FAILED) - return nullptr; - /* - * mmap treats the given address as a hint unless the MAP_FIXED flag is - * used (which isn't usually what you want, as this overrides existing -@@ -480,16 +480,51 @@ MapMemory(size_t length, int prot = PROT - * as out of memory. - */ - if ((uintptr_t(region) + (length - 1)) & 0xffff800000000000) { - if (munmap(region, length)) - MOZ_ASSERT(errno == ENOMEM); - return nullptr; - } - return region; -+#elif defined(__aarch64__) -+ /* -+ * There might be similar virtual address issue on arm64 which depends on -+ * hardware and kernel configurations. But the work around is slightly -+ * different due to the different mmap behavior. -+ * -+ * TODO: Merge with the above code block if this implementation works for -+ * ia64 and sparc64. -+ */ -+ const uintptr_t start = UINT64_C(0x0000070000000000); -+ const uintptr_t end = UINT64_C(0x0000800000000000); -+ const uintptr_t step = js::gc::ChunkSize; -+ /* -+ * Optimization options if there are too many retries in practice: -+ * 1. Examine /proc/self/maps to find an available address. This file is -+ * not always available, however. In addition, even if we examine -+ * /proc/self/maps, we may still need to retry several times due to -+ * racing with other threads. -+ * 2. Use a global/static variable with lock to track the addresses we have -+ * allocated or tried. -+ */ -+ uintptr_t hint; -+ void* region = MAP_FAILED; -+ for (hint = start; region == MAP_FAILED && hint + length <= end; hint += step) { -+ region = mmap((void*)hint, length, prot, flags, fd, offset); -+ if (region != MAP_FAILED) { -+ if ((uintptr_t(region) + (length - 1)) & 0xffff800000000000) { -+ if (munmap(region, length)) { -+ MOZ_ASSERT(errno == ENOMEM); -+ } -+ region = MAP_FAILED; -+ } -+ } -+ } -+ return region == MAP_FAILED ? nullptr : region; - #else - void* region = MozTaggedAnonymousMmap(nullptr, length, prot, flags, fd, offset, "js-gc-heap"); - if (region == MAP_FAILED) - return nullptr; - return region; - #endif - } - -diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h ---- a/js/src/jit/none/MacroAssembler-none.h -+++ b/js/src/jit/none/MacroAssembler-none.h -@@ -254,16 +254,18 @@ class MacroAssemblerNone : public Assemb - template void branchSub32(Condition, T, S, Label*) { MOZ_CRASH(); } - template void branchPtr(Condition, T, S, Label*) { MOZ_CRASH(); } - template void branchTestPtr(Condition, T, S, Label*) { MOZ_CRASH(); } - template void branchDouble(DoubleCondition, T, S, Label*) { MOZ_CRASH(); } - template void branchFloat(DoubleCondition, T, S, Label*) { MOZ_CRASH(); } - template void branchPrivatePtr(Condition, T, S, Label*) { MOZ_CRASH(); } - template void decBranchPtr(Condition, T, S, Label*) { MOZ_CRASH(); } - template void branchTest64(Condition, T, T, S, Label*) { MOZ_CRASH(); } -+ template void branch64(Condition, T, S, Label*) { MOZ_CRASH(); } -+ template void branch64(Condition, T, T, S, Label*) { MOZ_CRASH(); } - template void mov(T, S) { MOZ_CRASH(); } - template void movq(T, S) { MOZ_CRASH(); } - template void movePtr(T, S) { MOZ_CRASH(); } - template void move32(T, S) { MOZ_CRASH(); } - template void moveFloat32(T, S) { MOZ_CRASH(); } - template void moveDouble(T, S) { MOZ_CRASH(); } - template void move64(T, S) { MOZ_CRASH(); } - template CodeOffset movWithPatch(T, Register) { MOZ_CRASH(); } - -diff --git a/js/src/jsapi-tests/testGCAllocator.cpp b/js/src/jsapi-tests/testGCAllocator.cpp ---- a/js/src/jsapi-tests/testGCAllocator.cpp -+++ b/js/src/jsapi-tests/testGCAllocator.cpp -@@ -307,48 +307,72 @@ void* mapMemoryAt(void* desired, size_t - void* mapMemory(size_t length) { return nullptr; } - void unmapPages(void* p, size_t size) { } - - #elif defined(XP_UNIX) - - void* - mapMemoryAt(void* desired, size_t length) - { --#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__)) -+#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__)) || defined(__aarch64__) - MOZ_RELEASE_ASSERT(0xffff800000000000ULL & (uintptr_t(desired) + length - 1) == 0); - #endif - void* region = mmap(desired, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); - if (region == MAP_FAILED) - return nullptr; - if (region != desired) { - if (munmap(region, length)) - MOZ_RELEASE_ASSERT(errno == ENOMEM); - return nullptr; - } - return region; - } - - void* - mapMemory(size_t length) - { -- void* hint = nullptr; -+ int prot = PROT_READ | PROT_WRITE; -+ int flags = MAP_PRIVATE | MAP_ANON; -+ int fd = -1; -+ off_t offset = 0; -+ // The test code must be aligned with the implementation in gc/Memory.cpp. - #if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__)) -- hint = (void*)0x0000070000000000ULL; --#endif -- void* region = mmap(hint, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); -+ void* region = mmap((void*)0x0000070000000000, length, prot, flags, fd, offset); - if (region == MAP_FAILED) - return nullptr; --#if defined(__ia64__) || (defined(__sparc64__) && defined(__NetBSD__)) -- if ((uintptr_t(region) + (length - 1)) & 0xffff800000000000ULL) { -+ if ((uintptr_t(region) + (length - 1)) & 0xffff800000000000) { - if (munmap(region, length)) - MOZ_RELEASE_ASSERT(errno == ENOMEM); - return nullptr; - } -+ return region; -+#elif defined(__aarch64__) -+ const uintptr_t start = UINT64_C(0x0000070000000000); -+ const uintptr_t end = UINT64_C(0x0000800000000000); -+ const uintptr_t step = js::gc::ChunkSize; -+ uintptr_t hint; -+ void* region = MAP_FAILED; -+ for (hint = start; region == MAP_FAILED && hint + length <= end; hint += step) { -+ region = mmap((void*)hint, length, prot, flags, fd, offset); -+ if (region != MAP_FAILED) { -+ if ((uintptr_t(region) + (length - 1)) & 0xffff800000000000) { -+ if (munmap(region, length)) { -+ MOZ_RELEASE_ASSERT(errno == ENOMEM); -+ } -+ region = MAP_FAILED; -+ } -+ } -+ } -+ return region == MAP_FAILED ? nullptr : region; -+#else -+ void* region = mmap(nullptr, length, prot, flags, fd, offset); -+ if (region == MAP_FAILED) -+ return nullptr; -+ return region; - #endif -- return region; - } - - void - unmapPages(void* p, size_t size) - { - if (munmap(p, size)) - MOZ_RELEASE_ASSERT(errno == ENOMEM); - } - -diff --git a/js/src/jit/AtomicOperations.h b/js/src/jit/AtomicOperations.h -index 8606a18..60af775 100644 ---- a/js/src/jit/AtomicOperations.h -+++ b/js/src/jit/AtomicOperations.h -@@ -302,7 +302,9 @@ AtomicOperations::isLockfree(int32_t size) - # include "jit/mips-shared/AtomicOperations-mips-shared.h" - #elif defined(__ppc64__) || defined(__PPC64_) \ - || defined(__ppc64le__) || defined(__PPC64LE__) \ -- || defined(__ppc__) || defined(__PPC__) -+ || defined(__ppc__) || defined(__PPC__) \ -+ || defined(__aarch64__) || defined(__arm__) \ -+ || defined(__s390x__) || defined(__mips__) - # include "jit/none/AtomicOperations-ppc.h" - #elif defined(JS_CODEGEN_NONE) - # include "jit/none/AtomicOperations-none.h" - -diff --git a/js/src/tests/js1_5/Array/regress-157652.js b/js/src/tests/js1_5/Array/regress-157652.js -index 0bdba8f..9d77802 100644 ---- a/js/src/tests/js1_5/Array/regress-157652.js -+++ b/js/src/tests/js1_5/Array/regress-157652.js -@@ -1,4 +1,4 @@ --// |reftest| skip-if(xulRuntime.XPCOMABI.match(/x86_64/)||Android) -- No test results -+// |reftest| skip-if(xulRuntime.XPCOMABI.match(/x86_64|aarch64|ppc64|ppc64le|s390x/)||Android) -- No test results - /* -*- Mode: C++; tab-width: 2; 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 -diff --git a/js/src/tests/js1_5/Array/regress-330812.js b/js/src/tests/js1_5/Array/regress-330812.js -index 3a39297..c48f4c8 100644 ---- a/js/src/tests/js1_5/Array/regress-330812.js -+++ b/js/src/tests/js1_5/Array/regress-330812.js -@@ -1,4 +1,4 @@ --// |reftest| skip-if(xulRuntime.XPCOMABI.match(/x86_64/)||Android) -- No test results -+// |reftest| skip-if(xulRuntime.XPCOMABI.match(/x86_64|aarch64|ppc64|ppc64le|s390x/)||Android) -- No test results - /* -*- Mode: C++; tab-width: 2; 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 -diff --git a/js/src/tests/js1_5/Regress/regress-422348.js b/js/src/tests/js1_5/Regress/regress-422348.js -index f2443c2..7ae83f4 100644 ---- a/js/src/tests/js1_5/Regress/regress-422348.js -+++ b/js/src/tests/js1_5/Regress/regress-422348.js -@@ -1,4 +1,4 @@ --// |reftest| skip-if(xulRuntime.XPCOMABI.match(/x86_64/)) -- On 64-bit, takes forever rather than throwing -+// |reftest| skip-if(xulRuntime.XPCOMABI.match(/x86_64|aarch64|ppc64|ppc64le|s390x/)) -- On 64-bit, takes forever rather than throwing - /* -*- Mode: C++; tab-width: 2; 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 - Index: ps/trunk/libraries/source/spidermonkey/FixTracelogger.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/FixTracelogger.diff +++ ps/trunk/libraries/source/spidermonkey/FixTracelogger.diff @@ -1,223 +0,0 @@ -diff --git a/js/src/jit-test/tests/tracelogger/bug1266649.js b/js/src/jit-test/tests/tracelogger/bug1266649.js -new file mode 100644 -index 0000000..2878e0c ---- /dev/null -+++ b/js/src/jit-test/tests/tracelogger/bug1266649.js -@@ -0,0 +1,8 @@ -+ -+var du = new Debugger(); -+if (typeof du.setupTraceLogger === "function") { -+ du.setupTraceLogger({ -+ Scripts: true -+ }) -+ oomTest(() => function(){}); -+} -diff --git a/js/src/vm/TraceLogging.cpp b/js/src/vm/TraceLogging.cpp -index ce7acc6..8f8aca4 100644 ---- a/js/src/vm/TraceLogging.cpp -+++ b/js/src/vm/TraceLogging.cpp -@@ -393,14 +393,14 @@ TraceLoggerThread::getOrCreateEventPayload(const char* text) - return nullptr; - } - -- if (!pointerMap.add(p, text, payload)) -- return nullptr; -- - if (graph.get()) - graph->addTextId(textId, str); - - nextTextId++; - -+ if (!pointerMap.add(p, text, payload)) -+ return nullptr; -+ - return payload; - } - -@@ -420,10 +420,13 @@ TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId type, const char* f - if (!traceLoggerState->isTextIdEnabled(type)) - return getOrCreateEventPayload(type); - -- PointerHashMap::AddPtr p = pointerMap.lookupForAdd(ptr); -- if (p) { -- MOZ_ASSERT(p->value()->textId() < nextTextId); // Sanity check. -- return p->value(); -+ PointerHashMap::AddPtr p; -+ if (ptr) { -+ p = pointerMap.lookupForAdd(ptr); -+ if (p) { -+ MOZ_ASSERT(p->value()->textId() < nextTextId); // Sanity check. -+ return p->value(); -+ } - } - - // Compute the length of the string to create. -@@ -455,14 +458,16 @@ TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId type, const char* f - return nullptr; - } - -- if (!pointerMap.add(p, ptr, payload)) -- return nullptr; -- - if (graph.get()) - graph->addTextId(textId, str); - - nextTextId++; - -+ if (ptr) { -+ if (!pointerMap.add(p, ptr, payload)) -+ return nullptr; -+ } -+ - return payload; - } - -@@ -477,7 +482,7 @@ TraceLoggerEventPayload* - TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId type, - const JS::ReadOnlyCompileOptions& script) - { -- return getOrCreateEventPayload(type, script.filename(), script.lineno, script.column, &script); -+ return getOrCreateEventPayload(type, script.filename(), script.lineno, script.column, nullptr); - } - - void -@@ -550,19 +555,42 @@ TraceLoggerThread::log(uint32_t id) - return; - - MOZ_ASSERT(traceLoggerState); -- if (!events.ensureSpaceBeforeAdd()) { -+ if (!events.hasSpaceForAdd(3)) { - uint64_t start = rdtsc() - traceLoggerState->startupTime; - -- if (graph.get()) -- graph->log(events); -+ if (!events.ensureSpaceBeforeAdd(3)) { -+ if (graph.get()) -+ graph->log(events); - -- iteration_++; -- events.clear(); -+ iteration_++; -+ events.clear(); -+ -+ // Remove the item in the pointerMap for which the payloads -+ // have no uses anymore -+ for (PointerHashMap::Enum e(pointerMap); !e.empty(); e.popFront()) { -+ if (e.front().value()->uses() != 0) -+ continue; -+ -+ TextIdHashMap::Ptr p = textIdPayloads.lookup(e.front().value()->textId()); -+ MOZ_ASSERT(p); -+ textIdPayloads.remove(p); -+ -+ e.removeFront(); -+ } -+ -+ // Free all payloads that have no uses anymore. -+ for (TextIdHashMap::Enum e(textIdPayloads); !e.empty(); e.popFront()) { -+ if (e.front().value()->uses() == 0) { -+ js_delete(e.front().value()); -+ e.removeFront(); -+ } -+ } -+ } - - // Log the time it took to flush the events as being from the - // Tracelogger. - if (graph.get()) { -- MOZ_ASSERT(events.capacity() > 2); -+ MOZ_ASSERT(events.capacity() - events.size() > 2); - EventEntry& entryStart = events.pushUninitialized(); - entryStart.time = start; - entryStart.textId = TraceLogger_Internal; -@@ -572,26 +600,6 @@ TraceLoggerThread::log(uint32_t id) - entryStop.textId = TraceLogger_Stop; - } - -- // Remove the item in the pointerMap for which the payloads -- // have no uses anymore -- for (PointerHashMap::Enum e(pointerMap); !e.empty(); e.popFront()) { -- if (e.front().value()->uses() != 0) -- continue; -- -- TextIdHashMap::Ptr p = textIdPayloads.lookup(e.front().value()->textId()); -- MOZ_ASSERT(p); -- textIdPayloads.remove(p); -- -- e.removeFront(); -- } -- -- // Free all payloads that have no uses anymore. -- for (TextIdHashMap::Enum e(textIdPayloads); !e.empty(); e.popFront()) { -- if (e.front().value()->uses() == 0) { -- js_delete(e.front().value()); -- e.removeFront(); -- } -- } - } - - uint64_t time = rdtsc() - traceLoggerState->startupTime; -diff --git a/js/src/vm/TraceLogging.h b/js/src/vm/TraceLogging.h -index 270478c..313950e 100644 ---- a/js/src/vm/TraceLogging.h -+++ b/js/src/vm/TraceLogging.h -@@ -242,7 +242,7 @@ class TraceLoggerThread - - // If we are in a consecutive iteration we are only sure we didn't lose any events, - // when the lastSize equals the maximum size 'events' can get. -- if (lastIteration == iteration_ - 1 && lastSize == CONTINUOUSSPACE_LIMIT) -+ if (lastIteration == iteration_ - 1 && lastSize == events.max_items()) - return false; - - return true; -diff --git a/js/src/vm/TraceLoggingTypes.h b/js/src/vm/TraceLoggingTypes.h -index bb8ccc7..1d98bf6 100644 ---- a/js/src/vm/TraceLoggingTypes.h -+++ b/js/src/vm/TraceLoggingTypes.h -@@ -130,15 +130,15 @@ TLTextIdIsTreeEvent(uint32_t id) - id >= TraceLogger_Last; - } - --// The maximum amount of ram memory a continuous space structure can take (in bytes). --static const uint32_t CONTINUOUSSPACE_LIMIT = 200 * 1024 * 1024; -- - template - class ContinuousSpace { - T* data_; - uint32_t size_; - uint32_t capacity_; - -+ // The maximum amount of ram memory a continuous space structure can take (in bytes). -+ static const uint32_t LIMIT = 200 * 1024 * 1024; -+ - public: - ContinuousSpace () - : data_(nullptr) -@@ -160,6 +160,10 @@ class ContinuousSpace { - data_ = nullptr; - } - -+ uint32_t max_items() { -+ return LIMIT / sizeof(T); -+ } -+ - T* data() { - return data_; - } -@@ -197,11 +201,14 @@ class ContinuousSpace { - return true; - - uint32_t nCapacity = capacity_ * 2; -- if (size_ + count > nCapacity || nCapacity * sizeof(T) > CONTINUOUSSPACE_LIMIT) { -+ if (size_ + count > nCapacity) - nCapacity = size_ + count; - -+ if (nCapacity > max_items()) { -+ nCapacity = max_items(); -+ - // Limit the size of a continuous buffer. -- if (nCapacity * sizeof(T) > CONTINUOUSSPACE_LIMIT) -+ if (size_ + count > nCapacity) - return false; - } - Index: ps/trunk/libraries/source/spidermonkey/FixZLibMozBuild.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/FixZLibMozBuild.diff +++ ps/trunk/libraries/source/spidermonkey/FixZLibMozBuild.diff @@ -1,11 +0,0 @@ ---- a/config/external/zlib/moz.build -+++ b/config/external/zlib/moz.build -@@ -15,7 +15,7 @@ - # USE_LIBS += [ - # 'mozglue' - # ] - pass - DIRS += [ -- '../../../modules/zlib', -+ '../../../modules/src', - ] Index: ps/trunk/libraries/source/spidermonkey/README.txt =================================================================== --- ps/trunk/libraries/source/spidermonkey/README.txt +++ ps/trunk/libraries/source/spidermonkey/README.txt @@ -1,15 +1,15 @@ Important notice: ----------------- This version of SpiderMonkey comes from -https://ftp.mozilla.org/pub/spidermonkey/releases/45.0.2/mozjs-45.0.2.tar.bz2 +https://ftp.mozilla.org/pub/spidermonkey/prereleases/52/pre1/mozjs-52.9.1pre1.tar.bz2 -The game must be compiled with precisely this version since SpiderMonkey -does not guarantee API stability and may have behavioural changes that +The game must be compiled with precisely this version since SpiderMonkey +does not guarantee API stability and may have behavioural changes that cause subtle bugs or network out-of-sync errors. A standard system-provided version of the library may only be used if it's -exactly the same version or if it's another minor release that does not +exactly the same version or if it's another minor release that does not change the behaviour of the scripts executed by SpiderMonkey. Also it's -crucial that "--enable-gcgenerational" was used for building the system +crucial that "--enable-gcgenerational" was used for building the system provided libraries and that exact stack rooting was not disabled. Using different settings for compiling SpiderMonkey and 0 A.D. causes incompatibilities on the ABI (binary) level and can lead to @@ -33,23 +33,25 @@ Setting up the build environment: 1. Get https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Windows_Prerequisites#MozillaBuild +2. Download both an older version (2.x) which uses the old Mozilla build system, for NSPR; and the latest version to build + SpiderMonkey. Install them to different locations. Building NSPR: -1. Get nspr. We are using nspr-4.12 which was the newest version when SM45.0.2 was out. +1. Get nspr. We are using nspr-4.26 which was the newest version when this was written. Newer versions should probably work too. Download link: https://ftp.mozilla.org/pub/mozilla.org/nspr/releases/ -2. Run mozillabuild (start-shell-msvc2015.bat) as administrator +2. Run MozillaBuild 2.x (start-shell-msvc2015.bat) 3. Extract nspr to libraries/source/spidermonkey - tar -xzvf nspr-4.12.tar.gz - cd nspr-4.12 + tar -xzvf nspr-4.26.tar.gz + cd nspr-4.26 cd nspr -4. Patch nspr with https://bugzilla.mozilla.org/show_bug.cgi?id=1238154#c7 +4. Patch nspr with https://bugzilla.mozilla.org/show_bug.cgi?id=1238154#c15 5. Call configure. I've used this command: ./configure --disable-debug --enable-optimize --enable-win32-target=WIN95 6. Call make Building SpiderMonkey: 1. Adjust the absolute paths to nspr in the build.sh file to match your environment. -2. Run mozillabuild (start-shell-msvc2015.bat) as administrator and run ./build.sh. +2. Run MozillaBuild 3.x (start-shell.bat) and run ./build.sh. Index: ps/trunk/libraries/source/spidermonkey/RemoveNSPRDependency.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/RemoveNSPRDependency.diff +++ ps/trunk/libraries/source/spidermonkey/RemoveNSPRDependency.diff @@ -1,51 +0,0 @@ - -# HG changeset patch -# User Philip Chimento -# Date 1501017350 25200 -# Node ID 5d95b2833b30582ab3df4e28373d749ddbf7c04e -# Parent c24e6fc9f689aeb32de0bf7916b1d0098d4a2bb9 -Bug 1379539 - Remove unnecessary NSPR dependency. r=glandium, a=jcristau - -diff --git a/build/autoconf/nspr-build.m4 b/build/autoconf/nspr-build.m4 -index 970e1e7..66d96b1 100644 ---- a/build/autoconf/nspr-build.m4 -+++ b/build/autoconf/nspr-build.m4 -@@ -167,11 +167,8 @@ fi - - AC_SUBST_LIST(NSPR_CFLAGS) - --NSPR_PKGCONF_CHECK="nspr" -+PKGCONF_REQUIRES_PRIVATE="Requires.private: nspr" - if test -n "$MOZ_NATIVE_NSPR"; then -- # piggy back on $MOZ_NATIVE_NSPR to set a variable for the nspr check for js.pc -- NSPR_PKGCONF_CHECK="nspr >= $NSPR_MINVER" -- - _SAVE_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS $NSPR_CFLAGS" - AC_TRY_COMPILE([#include "prlog.h"], -@@ -181,8 +178,12 @@ if test -n "$MOZ_NATIVE_NSPR"; then - , - AC_MSG_ERROR([system NSPR does not support PR_STATIC_ASSERT])) - CFLAGS=$_SAVE_CFLAGS -+ # piggy back on $MOZ_NATIVE_NSPR to set a variable for the nspr check for js.pc -+ PKGCONF_REQUIRES_PRIVATE="Requires.private: nspr >= $NSPR_MINVER" -+elif test -n "$JS_POSIX_NSPR"; then -+ PKGCONF_REQUIRES_PRIVATE= - fi --AC_SUBST(NSPR_PKGCONF_CHECK) -+AC_SUBST([PKGCONF_REQUIRES_PRIVATE]) - - fi # _IS_OUTER_CONFIGURE - -diff --git a/js/src/js.pc.in b/js/src/js.pc.in -index 1efea33..2eae393 100644 ---- a/js/src/js.pc.in -+++ b/js/src/js.pc.in -@@ -6,6 +6,6 @@ includedir=@includedir@ - Name: SpiderMonkey @MOZILLA_VERSION@ - Description: The Mozilla library for JavaScript - Version: @MOZILLA_VERSION@ --Requires.private: @NSPR_PKGCONF_CHECK@ -+@PKGCONF_REQUIRES_PRIVATE@ - Libs: -L${libdir} -l@JS_LIBRARY_NAME@ - Cflags: -include ${includedir}/@JS_LIBRARY_NAME@/js/RequiredDefines.h -I${includedir}/@JS_LIBRARY_NAME@ Index: ps/trunk/libraries/source/spidermonkey/RenameLibs.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/RenameLibs.diff +++ ps/trunk/libraries/source/spidermonkey/RenameLibs.diff @@ -0,0 +1,20 @@ +diff --git a/js/src/old-configure b/js/src/old-configure +index 7d621b52ce..85e2934fa9 100644 +--- a/js/src/old-configure ++++ b/js/src/old-configure +@@ -10469,12 +10469,12 @@ done + + + +-if test -n "$JS_STANDALONE"; then + MOZ_APP_NAME="mozjs" + MOZ_APP_VERSION="$MOZILLA_SYMBOLVERSION" +-JS_LIBRARY_NAME="mozjs-$MOZILLA_SYMBOLVERSION" ++if test -n "$MOZ_DEBUG"; then ++JS_LIBRARY_NAME="mozjs$MOZILLA_SYMBOLVERSION-ps-debug" + else +-JS_LIBRARY_NAME="mozjs" ++JS_LIBRARY_NAME="mozjs$MOZILLA_SYMBOLVERSION-ps-release" + fi + JS_CONFIG_LIBS="$NSPR_LIBS $LIBS" + if test -n "$GNU_CC"; then Index: ps/trunk/libraries/source/spidermonkey/build.sh =================================================================== --- ps/trunk/libraries/source/spidermonkey/build.sh +++ ps/trunk/libraries/source/spidermonkey/build.sh @@ -1,14 +1,18 @@ #!/bin/sh - +# This script is called by update-workspaces.sh / build-osx-libraries.sh set -e +# This should match the version in config/milestone.txt +FOLDER="mozjs-52.9.1pre1" +# If same-version changes are needed, increment this. +LIB_VERSION="52.9.1pre1+0" +LIB_NAME="mozjs52-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. # Running SM's Makefile is a bit slow and noisy, so instead we'll make a -# special file and only rebuild if it's older than SVN. -# README.txt should be updated whenever we update SM, so use that as -# a time comparison. -if [ -e .already-built -a .already-built -nt README.txt ] +# special file and only rebuild if the build.sh version differs. +if [ -e .already-built ] && [ "$(cat .already-built)" = "${LIB_VERSION}" ] then echo "SpiderMonkey is already up to date" exit @@ -27,37 +31,34 @@ MAKE_OPTS="${JOBS}" -# jemalloc is outdated on SM45, do not use it -CONF_OPTS="--disable-tests --disable-jemalloc --enable-shared-js --without-intl-api" - -# Bug 1269319 -# When compiled with GCC 6 (or later), SpiderMonkey 45 (and versions up to 49) is -# subject to segfaults. Disabling a few optimizations fixes that. -# See also #4053 -if [ "${OS}" != "Windows_NT" ] -then - if [ "`${CXX:=g++} -dumpversion | cut -f1 -d.`" -ge "6" ] - then - CXXFLAGS="${CXXFLAGS} -fno-schedule-insns2 -fno-delete-null-pointer-checks" - fi -fi - -# Change the default location where the tracelogger should store its output. -# The default location is . on Windows and /tmp/ on *nix. -TLCXXFLAGS='-DTRACE_LOG_DIR="\"../../source/tools/tracelogger/\""' +# Standalone SpiderMonkey can not use jemalloc (see https://bugzilla.mozilla.org/show_bug.cgi?id=1465038) +CONF_OPTS="--disable-tests + --disable-jemalloc + --disable-js-shell + --without-intl-api + --enable-shared-js" # We're linking statically but JS has quirks with static-only compilation. # NSPR is needed on Windows for POSIX emulation. -# If you want to build on Windows, check README.txt and edit the absolute paths +# If you want to build on Windows, check README.txt and edit the absolute paths # to match your environment. if [ "${OS}" = "Windows_NT" ] then - NSPR_INCLUDES="-ID:/nspr-4.12/nspr/dist/include/nspr" - NSPR_LIBS=" \ - D:/nspr-4.12/nspr/dist/lib/nspr4 \ - D:/nspr-4.12/nspr/dist/lib/plds4 \ - D:/nspr-4.12/nspr/dist/lib/plc4" + CONF_OPTS="${CONF_OPTS} --with-nspr-prefix="D:/nspr-4.21/nspr/"" else - CONF_OPTS="${CONF_OPTS} --enable-posix-nspr-emulation" + CONF_OPTS="${CONF_OPTS} --enable-posix-nspr-emulation" +fi + +if [ "`uname -s`" = "Darwin" ] +then + # Link to custom-built zlib + CONF_OPTS="${CONF_OPTS} --with-system-zlib=${ZLIB_DIR}" + # Specify target versions and SDK + if [ "${MIN_OSX_VERSION}" ] && [ "${MIN_OSX_VERSION-_}" ]; then + CONF_OPTS="${CONF_OPTS} --enable-macos-target=$MIN_OSX_VERSION" + fi + if [ "${SYSROOT}" ] && [ "${SYSROOT-_}" ]; then + CONF_OPTS="${CONF_OPTS} --with-macosx-sdk=${SYSROOT}" + fi fi # If Valgrind looks like it's installed, then set up SM to support it @@ -74,98 +75,64 @@ ${CTARGET:+--target=${CTARGET}}" echo "SpiderMonkey build options: ${CONF_OPTS}" -echo ${CONF_OPTS} - -FOLDER=mozjs-45.0.2 - -# Delete the existing directory to avoid conflicts and extract the tarball -rm -rf $FOLDER -tar xjf mozjs-45.0.2.tar.bz2 - -# Clean up header files that may be left over by earlier versions of SpiderMonkey -rm -rf include-unix-* - -cd $FOLDER -# Apply patches -. ../patch.sh - -cd js/src +# It can occasionally be useful to not rebuild everything, but don't do this by default. +REBUILD=true +if $REBUILD = true; +then + # Delete the existing directory to avoid conflicts and extract the tarball + rm -rf "$FOLDER" + if [ ! -e "${FOLDER}.tar.bz2" ]; + 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/v52.9.1/${FOLDER}.tar.bz2" + fi + tar xjf "${FOLDER}.tar.bz2" -# Clean up data generated by previous builds that could cause problems -rm -rf build-debug -rm -rf build-release + # Clean up header files that may be left over by earlier versions of SpiderMonkey + rm -rf include-unix-debug + rm -rf include-unix-release + + # Apply patches + cd "$FOLDER" + . ../patch.sh + # Prevent complaining that configure is outdated. + touch ./js/src/configure +else + cd "$FOLDER" +fi -# We want separate debug/release versions of the library, so we have to change -# the LIBRARY_NAME for each build. -# (We use perl instead of sed so that it works with MozillaBuild on Windows, -# which has an ancient sed.) -perl -i.bak -pe 's/(SHARED_LIBRARY_NAME\s+=).*/$1 '\''mozjs45-ps-debug'\''/' moz.build mkdir -p build-debug cd build-debug -if [ "${OS}" = "Windows_NT" ] -then - CXXFLAGS="${CXXFLAGS} ${TLCXXFLAGS}" ../configure ${CONF_OPTS} \ - --with-nspr-cflags="${NSPR_INCLUDES}" --with-nspr-libs="${NSPR_LIBS}" \ - --enable-debug \ - --disable-optimize \ - --enable-js-diagnostics \ - --enable-gczeal -else - CXXFLAGS="${CXXFLAGS} ${TLCXXFLAGS}" ../configure ${CONF_OPTS} \ - --enable-debug \ - --disable-optimize \ - --enable-js-diagnostics \ - --enable-gczeal -fi +# 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} \ + --enable-debug \ + --disable-optimize \ + --enable-gczeal ${MAKE} ${MAKE_OPTS} cd .. -perl -i.bak -pe 's/(SHARED_LIBRARY_NAME\s+=).*/$1 '\''mozjs45-ps-release'\''/' moz.build mkdir -p build-release cd build-release -if [ "${OS}" = "Windows_NT" ] -then - CXXFLAGS="${CXXFLAGS} ${TLCXXFLAGS}" ../configure ${CONF_OPTS} \ - --with-nspr-cflags="${NSPR_INCLUDES}" --with-nspr-libs="${NSPR_LIBS}" \ - --enable-optimize \ - #--enable-gczeal \ - #--enable-debug-symbols -else - CXXFLAGS="${CXXFLAGS} ${TLCXXFLAGS}" ../configure ${CONF_OPTS} \ - --enable-optimize \ - #--enable-gczeal \ - #--enable-debug-symbols -fi +CXXFLAGS="${CXXFLAGS}" ../js/src/configure AUTOCONF="false" ${CONF_OPTS} \ + --enable-optimize ${MAKE} ${MAKE_OPTS} cd .. -cd ../../.. +cd .. if [ "${OS}" = "Windows_NT" ] then INCLUDE_DIR_DEBUG=include-win32-debug INCLUDE_DIR_RELEASE=include-win32-release - DLL_SRC_SUFFIX=.dll - DLL_DST_SUFFIX=.dll LIB_PREFIX= - LIB_SRC_SUFFIX=.lib - LIB_DST_SUFFIX=.lib + LIB_SUFFIX=.lib else INCLUDE_DIR_DEBUG=include-unix-debug INCLUDE_DIR_RELEASE=include-unix-release - DLL_SRC_SUFFIX=.so - DLL_DST_SUFFIX=.so LIB_PREFIX=lib - LIB_SRC_SUFFIX=.so - LIB_DST_SUFFIX=.so - if [ "`uname -s`" = "OpenBSD" ] - then - DLL_SRC_SUFFIX=.so.1.0 - DLL_DST_SUFFIX=.so.1.0 - LIB_SRC_SUFFIX=.so.1.0 - LIB_DST_SUFFIX=:so.1.0 - fi + LIB_SUFFIX=.a fi if [ "${OS}" = "Windows_NT" ] @@ -173,10 +140,10 @@ # Bug #776126 # SpiderMonkey uses a tweaked zlib when building, and it wrongly copies its own files to include dirs # afterwards, so we have to remove them to not have them conflicting with the regular zlib - pushd ${FOLDER}/js/src/build-release/dist/include + pushd "${FOLDER}/build-release/dist/include" rm mozzconf.h zconf.h zlib.h popd - pushd ${FOLDER}/js/src/build-debug/dist/include + pushd "${FOLDER}/build-debug/dist/include" rm mozzconf.h zconf.h zlib.h popd fi @@ -184,23 +151,26 @@ # Copy files into the necessary locations for building and running the game # js-config.h is different for debug and release builds, so we need different include directories for both -mkdir -p ${INCLUDE_DIR_DEBUG} -mkdir -p ${INCLUDE_DIR_RELEASE} -cp -R -L ${FOLDER}/js/src/build-release/dist/include/* ${INCLUDE_DIR_RELEASE}/ -cp -R -L ${FOLDER}/js/src/build-debug/dist/include/* ${INCLUDE_DIR_DEBUG}/ +mkdir -p "${INCLUDE_DIR_DEBUG}" +mkdir -p "${INCLUDE_DIR_RELEASE}" +cp -R -L "${FOLDER}"/build-release/dist/include/* "${INCLUDE_DIR_RELEASE}/" +cp -R -L "${FOLDER}"/build-debug/dist/include/* "${INCLUDE_DIR_DEBUG}/" mkdir -p lib/ -cp -L ${FOLDER}/js/src/build-debug/dist/sdk/lib/${LIB_PREFIX}mozjs45-ps-debug${LIB_SRC_SUFFIX} lib/${LIB_PREFIX}mozjs45-ps-debug${LIB_DST_SUFFIX} -cp -L ${FOLDER}/js/src/build-release/dist/sdk/lib/${LIB_PREFIX}mozjs45-ps-release${LIB_SRC_SUFFIX} lib/${LIB_PREFIX}mozjs45-ps-release${LIB_DST_SUFFIX} -cp -L ${FOLDER}/js/src/build-debug/dist/bin/${LIB_PREFIX}mozjs45-ps-debug${DLL_SRC_SUFFIX} ../../../binaries/system/${LIB_PREFIX}mozjs45-ps-debug${DLL_DST_SUFFIX} -cp -L ${FOLDER}/js/src/build-release/dist/bin/${LIB_PREFIX}mozjs45-ps-release${DLL_SRC_SUFFIX} ../../../binaries/system/${LIB_PREFIX}mozjs45-ps-release${DLL_DST_SUFFIX} +cp -L "${FOLDER}/build-debug/js/src/${LIB_PREFIX}js_static${LIB_SUFFIX}" "lib/${LIB_PREFIX}${LIB_NAME}-debug${LIB_SUFFIX}" +cp -L "${FOLDER}/build-release/js/src/${LIB_PREFIX}js_static${LIB_SUFFIX}" "lib/${LIB_PREFIX}${LIB_NAME}-release${LIB_SUFFIX}" -# On Windows, also copy debugging symbols files +# On Windows, also copy nspr .DLL and .pdb debug symbols. if [ "${OS}" = "Windows_NT" ] then - cp -L ${FOLDER}/js/src/build-debug/js/src/${LIB_PREFIX}mozjs45-ps-debug-vc140.pdb ../../../binaries/system/${LIB_PREFIX}mozjs45-ps-debug-vc140.pdb - cp -L ${FOLDER}/js/src/build-release/js/src/${LIB_PREFIX}mozjs45-ps-release-vc140.pdb ../../../binaries/system/${LIB_PREFIX}mozjs45-ps-release-vc140.pdb + cp -L "${FOLDER}/build-debug/js/src/${LIB_PREFIX}nspr4.dll" "../../../binaries/system/${LIB_PREFIX}nspr4.dll" + cp -L "${FOLDER}/build-debug/js/src/${LIB_PREFIX}plc4.dll" "../../../binaries/system/${LIB_PREFIX}plc4.dll" + cp -L "${FOLDER}/build-debug/js/src/${LIB_PREFIX}plds4.dll" "../../../binaries/system/${LIB_PREFIX}plds4.dll" + cp -L "${FOLDER}/build-debug/js/src/${LIB_PREFIX}mozjs-52-debug.dll" "lib/${LIB_PREFIX}${LIB_NAME}-debug.dll" + cp -L "${FOLDER}/build-debug/js/src/${LIB_PREFIX}mozjs-52-debug.pdb" "lib/${LIB_PREFIX}${LIB_NAME}-debug.pdb" + cp -L "${FOLDER}/build-release/js/src/${LIB_PREFIX}mozjs-52-release.dll" "lib/${LIB_PREFIX}${LIB_NAME}-release.dll" + cp -L "${FOLDER}/build-release/js/src/${LIB_PREFIX}mozjs-52-release.pdb" "lib/${LIB_PREFIX}${LIB_NAME}-release.pdb" fi # Flag that it's already been built successfully so we can skip it next time -touch .already-built +echo "${LIB_VERSION}" > .already-built Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/fdlibm.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/fdlibm.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/fdlibm.h @@ -0,0 +1,65 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * from: @(#)fdlibm.h 5.1 93/09/24 + * $FreeBSD$ + */ + +#ifndef mozilla_imported_fdlibm_h +#define mozilla_imported_fdlibm_h + +namespace fdlibm { + +double acos(double); +double asin(double); +double atan(double); +double atan2(double, double); + +double cosh(double); +double sinh(double); +double tanh(double); + +double exp(double); +double log(double); +double log10(double); + +double pow(double, double); +double sqrt(double); +double fabs(double); + +double floor(double); +double trunc(double); +double ceil(double); + +double acosh(double); +double asinh(double); +double atanh(double); +double cbrt(double); +double expm1(double); +double hypot(double, double); +double log1p(double); +double log2(double); +double rint(double); +double copysign(double, double); +double nearbyint(double); +double scalbn(double, int); + +float ceilf(float); +float floorf(float); + +float nearbyintf(float); +float rintf(float); +float truncf(float); + +} /* namespace fdlibm */ + +#endif /* mozilla_imported_fdlibm_h */ 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 @@ -15,6 +15,20 @@ /* Define to 1 if SpiderMonkey is in debug mode. */ #define JS_DEBUG 1 +/* + * NB: We have a special case for rust-bindgen, which wants to be able to + * generate both debug and release bindings on a single objdir. + */ +#ifdef JS_DEBUG +#if !defined(DEBUG) && !defined(RUST_BINDGEN) +# error "SpiderMonkey was configured with --enable-debug, so DEBUG must be defined when including this header" +# endif +#else +# if defined(DEBUG) && !defined(RUST_BINDGEN) +# error "SpiderMonkey was configured with --disable-debug, so DEBUG must be not defined when including this header" +# endif +#endif + /* Define to 1 if SpiderMonkey should not use struct types in debug builds. */ /* #undef JS_NO_JSVAL_JSID_STRUCT_TYPES */ @@ -34,18 +48,6 @@ /* Define to 1 to perform extra assertions and heap poisoning. */ /* #undef JS_CRASH_DIAGNOSTICS */ -/* Define to 1 if the header is present and - useable. See jscpucfg.h. */ -/* #undef JS_HAVE_ENDIAN_H */ - -/* Define to 1 if the header is present and - useable. See jscpucfg.h. */ -/* #undef JS_HAVE_MACHINE_ENDIAN_H */ - -/* Define to 1 if the header is present and - useable. See jscpucfg.h. */ -/* #undef JS_HAVE_SYS_ISA_DEFS_H */ - /* Define to 1 if SpiderMonkey is in NUNBOX32 mode. */ #define JS_NUNBOX32 1 @@ -53,7 +55,7 @@ /* #undef JS_PUNBOX64 */ /* MOZILLA JSAPI version number components */ -#define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 0 +#define MOZJS_MAJOR_VERSION 52 +#define MOZJS_MINOR_VERSION 9 #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 @@ -34,14 +34,14 @@ * * can be used: * - * JS_ReportErrorNumber(JSMSG_NOT_A_SUBSPECIES, "Rhino", "Monkey"); + * JS_ReportErrorNumberASCII(JSMSG_NOT_A_SUBSPECIES, "Rhino", "Monkey"); * * to report: * * "Rhino is not a member of the Monkey family" */ -MSG_DEF(JSMSG_NOT_AN_ERROR, 0, JSEXN_NONE, "") +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_INCOMPATIBLE_PROTO, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}") @@ -63,7 +63,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_REDECLARED_VAR, 2, JSEXN_TYPEERR, "redeclaration of {0} {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}") MSG_DEF(JSMSG_GETTER_ONLY, 0, JSEXN_TYPEERR, "setting a property that has only a getter") MSG_DEF(JSMSG_OVERWRITING_ACCESSOR, 1, JSEXN_TYPEERR, "can't overwrite accessor property {0}") @@ -71,14 +71,12 @@ MSG_DEF(JSMSG_INVALID_MAP_ITERABLE, 1, JSEXN_TYPEERR, "iterable for {0} should have array-like objects") MSG_DEF(JSMSG_NESTING_GENERATOR, 0, JSEXN_TYPEERR, "already executing generator") MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}") -MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED, 0, JSEXN_NONE, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead") -MSG_DEF(JSMSG_TYPE_ERR_BAD_ARGS, 0, JSEXN_TYPEERR, "invalid arguments") +MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED, 0, JSEXN_WARN, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead") +MSG_DEF(JSMSG_ARRAYBUFFER_SLICE_DEPRECATED, 0, JSEXN_WARN, "ArrayBuffer.slice is deprecated; use ArrayBuffer.prototype.slice instead") MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 1, JSEXN_TYPEERR, "bad surrogate character {0}") MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large") MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR, 1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}") -MSG_DEF(JSMSG_WRONG_CONSTRUCTOR, 1, JSEXN_TYPEERR, "wrong constructor called for {0}") MSG_DEF(JSMSG_BUILTIN_CTOR_NO_NEW, 1, JSEXN_TYPEERR, "calling a builtin {0} constructor without new is forbidden") -MSG_DEF(JSMSG_PROTO_SETTING_SLOW, 0, JSEXN_NONE, "mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create") MSG_DEF(JSMSG_BAD_GENERATOR_YIELD, 1, JSEXN_TYPEERR, "yield from closing generator {0}") MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value") MSG_DEF(JSMSG_UNEXPECTED_TYPE, 2, JSEXN_TYPEERR, "{0} is {1}") @@ -89,14 +87,15 @@ MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE, 1, JSEXN_TYPEERR, "{0}: Object is not extensible") MSG_DEF(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE, 2, JSEXN_TYPEERR, "can't define property {1}: {0} is not extensible") MSG_DEF(JSMSG_CANT_REDEFINE_PROP, 1, JSEXN_TYPEERR, "can't redefine non-configurable property {0}") -MSG_DEF(JSMSG_CANT_APPEND_TO_ARRAY, 0, JSEXN_TYPEERR, "can't add elements past the end of an array if its length property is unwritable") MSG_DEF(JSMSG_CANT_REDEFINE_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't redefine array length") MSG_DEF(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't define array index property past the end of an array with non-writable length") MSG_DEF(JSMSG_BAD_GET_SET_FIELD, 1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function") MSG_DEF(JSMSG_THROW_TYPE_ERROR, 0, JSEXN_TYPEERR, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them") MSG_DEF(JSMSG_NOT_EXPECTED_TYPE, 3, JSEXN_TYPEERR, "{0}: expected {1}, got {2}") MSG_DEF(JSMSG_NOT_ITERABLE, 1, JSEXN_TYPEERR, "{0} is not iterable") -MSG_DEF(JSMSG_ALREADY_HAS_PRAGMA, 2, JSEXN_NONE, "{0} is being assigned a {1}, but already has one") +MSG_DEF(JSMSG_NOT_ITERATOR, 1, JSEXN_TYPEERR, "{0} is not iterator") +MSG_DEF(JSMSG_ALREADY_HAS_PRAGMA, 2, JSEXN_WARN, "{0} is being assigned a {1}, but already has one") +MSG_DEF(JSMSG_GET_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.iterator]() returned a non-object value") MSG_DEF(JSMSG_NEXT_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "iterator.next() returned a non-object value") MSG_DEF(JSMSG_CANT_SET_PROTO, 0, JSEXN_TYPEERR, "can't set prototype of this object") MSG_DEF(JSMSG_CANT_SET_PROTO_OF, 1, JSEXN_TYPEERR, "can't set prototype of {0}") @@ -106,11 +105,12 @@ MSG_DEF(JSMSG_PROTO_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0}.prototype is not an object or null") 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, "|this| used uninitialized in {0} class constructor") +MSG_DEF(JSMSG_UNINITIALIZED_THIS_ARROW, 0, JSEXN_REFERENCEERR, "|this| used uninitialized in arrow function in class constructor") MSG_DEF(JSMSG_BAD_DERIVED_RETURN, 1, JSEXN_TYPEERR, "derived class constructor returned invalid value {0}") // JSON MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data") -MSG_DEF(JSMSG_JSON_CYCLIC_VALUE, 1, JSEXN_TYPEERR, "cyclic {0} value") +MSG_DEF(JSMSG_JSON_CYCLIC_VALUE, 0, JSEXN_TYPEERR, "cyclic object value") // Runtime errors MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS, 1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}") @@ -121,6 +121,7 @@ MSG_DEF(JSMSG_TOO_MANY_FUN_SPREADARGS, 0, JSEXN_RANGEERR, "too many function arguments") MSG_DEF(JSMSG_UNINITIALIZED_LEXICAL, 1, JSEXN_REFERENCEERR, "can't access lexical declaration `{0}' before initialization") MSG_DEF(JSMSG_BAD_CONST_ASSIGN, 1, JSEXN_TYPEERR, "invalid assignment to const `{0}'") +MSG_DEF(JSMSG_CANT_DECLARE_GLOBAL_BINDING, 2, JSEXN_TYPEERR, "cannot declare global binding `{0}': {1}") // Date MSG_DEF(JSMSG_INVALID_DATE, 0, JSEXN_RANGEERR, "invalid date") @@ -132,7 +133,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_CONTAINS, 0, JSEXN_NONE, "String.prototype.contains() is deprecated and will be removed in a future release; use String.prototype.includes() instead") // Number MSG_DEF(JSMSG_BAD_RADIX, 0, JSEXN_RANGEERR, "radix must be an integer at least 2 and no greater than 36") @@ -146,7 +146,7 @@ MSG_DEF(JSMSG_NOT_SCRIPTED_FUNCTION, 1, JSEXN_TYPEERR, "{0} is not a scripted function") MSG_DEF(JSMSG_NO_REST_NAME, 0, JSEXN_SYNTAXERR, "no parameter name after ...") MSG_DEF(JSMSG_PARAMETER_AFTER_REST, 0, JSEXN_SYNTAXERR, "parameter after rest parameter") -MSG_DEF(JSMSG_TOO_MANY_FUN_APPLY_ARGS, 0, JSEXN_RANGEERR, "arguments array passed to Function.prototype.apply is too large") +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") @@ -158,10 +158,7 @@ MSG_DEF(JSMSG_UNWRAP_DENIED, 0, JSEXN_ERR, "permission denied to unwrap object") // JSAPI-only (Not thrown as JS exceptions) -MSG_DEF(JSMSG_BAD_CHAR, 1, JSEXN_INTERNALERR, "invalid format character {0}") MSG_DEF(JSMSG_BAD_CLONE_FUNOBJ_SCOPE, 0, JSEXN_TYPEERR, "bad cloned function scope chain") -MSG_DEF(JSMSG_BAD_NEW_RESULT, 1, JSEXN_TYPEERR, "invalid new expression result {0}") -MSG_DEF(JSMSG_BAD_TYPE, 1, JSEXN_TYPEERR, "unknown type {0}") MSG_DEF(JSMSG_CANT_CLONE_OBJECT, 0, JSEXN_TYPEERR, "can't clone object") MSG_DEF(JSMSG_CANT_OPEN, 2, JSEXN_ERR, "can't open {0}: {1}") MSG_DEF(JSMSG_USER_DEFINED_ERROR, 0, JSEXN_ERR, "JS_ReportError was called") @@ -169,11 +166,10 @@ // Internal errors MSG_DEF(JSMSG_ALLOC_OVERFLOW, 0, JSEXN_INTERNALERR, "allocation size overflow") MSG_DEF(JSMSG_BAD_BYTECODE, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}") -MSG_DEF(JSMSG_BAD_SCRIPT_MAGIC, 0, JSEXN_INTERNALERR, "bad script XDR magic number") MSG_DEF(JSMSG_BUFFER_TOO_SMALL, 0, JSEXN_INTERNALERR, "buffer too small") +MSG_DEF(JSMSG_BUILD_ID_NOT_AVAILABLE, 0, JSEXN_INTERNALERR, "build ID is not available") MSG_DEF(JSMSG_BYTECODE_TOO_BIG, 2, JSEXN_INTERNALERR, "bytecode {0} too large (limit {1})") -MSG_DEF(JSMSG_CANT_SET_ARRAY_ATTRS, 0, JSEXN_INTERNALERR, "can't set attributes on indexed array properties") -MSG_DEF(JSMSG_INACTIVE, 0, JSEXN_INTERNALERR, "nothing active on context") +MSG_DEF(JSMSG_ERR_DURING_THROW, 0, JSEXN_INTERNALERR, "an internal error occurred while throwing an exception") MSG_DEF(JSMSG_NEED_DIET, 1, JSEXN_INTERNALERR, "{0} too large") MSG_DEF(JSMSG_OUT_OF_MEMORY, 0, JSEXN_INTERNALERR, "out of memory") MSG_DEF(JSMSG_OVER_RECURSED, 0, JSEXN_INTERNALERR, "too much recursion") @@ -185,9 +181,11 @@ // Frontend MSG_DEF(JSMSG_ACCESSOR_WRONG_ARGS, 3, JSEXN_SYNTAXERR, "{0} functions must have {1} argument{2}") MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid array comprehension left-hand side") -MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 0, JSEXN_INTERNALERR, "array initialiser too large") +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_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method can't be async") +MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await can't be used in default expression") MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "anonymous generator function returns a value") 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") @@ -199,18 +197,19 @@ MSG_DEF(JSMSG_BAD_DESTRUCT_DECL, 0, JSEXN_SYNTAXERR, "missing = in destructuring declaration") MSG_DEF(JSMSG_BAD_DUP_ARGS, 0, JSEXN_SYNTAXERR, "duplicate argument names not allowed in this context") MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 0, JSEXN_SYNTAXERR, "invalid for each loop") -MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for/in left-hand side") -MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 1, JSEXN_TYPEERR, "generator function {0} returns a value") -MSG_DEF(JSMSG_BAD_YIELD_SYNTAX, 0, JSEXN_SYNTAXERR, "yield expression must be parenthesized") -MSG_DEF(JSMSG_BAD_GENERATOR_SYNTAX, 0, JSEXN_SYNTAXERR, "generator expression must be parenthesized") +MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for-in/of left-hand side") +MSG_DEF(JSMSG_LEXICAL_DECL_DEFINES_LET,0, JSEXN_SYNTAXERR, "a lexical declaration can't define a 'let' binding") +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_GENERATOR_RETURN, 1, JSEXN_TYPEERR, "generator function {0} returns a value") MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression") MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_REFERENCEERR, "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_OPERAND, 1, JSEXN_SYNTAXERR, "invalid {0} operand") +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") -MSG_DEF(JSMSG_BAD_STRICT_ASSIGN, 1, JSEXN_SYNTAXERR, "can't assign to {0} in strict mode") +MSG_DEF(JSMSG_BAD_STRICT_ASSIGN, 1, JSEXN_SYNTAXERR, "'{0}' can't be defined or assigned to in strict mode code") MSG_DEF(JSMSG_BAD_SWITCH, 0, JSEXN_SYNTAXERR, "invalid switch statement") 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") @@ -230,13 +229,11 @@ MSG_DEF(JSMSG_CURLY_AFTER_BODY, 0, JSEXN_SYNTAXERR, "missing } after function body") MSG_DEF(JSMSG_CURLY_AFTER_CATCH, 0, JSEXN_SYNTAXERR, "missing } after catch block") MSG_DEF(JSMSG_CURLY_AFTER_FINALLY, 0, JSEXN_SYNTAXERR, "missing } after finally block") -MSG_DEF(JSMSG_CURLY_AFTER_LET, 0, JSEXN_SYNTAXERR, "missing } after let block") MSG_DEF(JSMSG_CURLY_AFTER_LIST, 0, JSEXN_SYNTAXERR, "missing } after property list") MSG_DEF(JSMSG_CURLY_AFTER_TRY, 0, JSEXN_SYNTAXERR, "missing } after try block") MSG_DEF(JSMSG_CURLY_BEFORE_BODY, 0, JSEXN_SYNTAXERR, "missing { before function body") MSG_DEF(JSMSG_CURLY_BEFORE_CATCH, 0, JSEXN_SYNTAXERR, "missing { before catch block") MSG_DEF(JSMSG_CURLY_BEFORE_CLASS, 0, JSEXN_SYNTAXERR, "missing { before class body") -MSG_DEF(JSMSG_CURLY_BEFORE_LET, 0, JSEXN_SYNTAXERR, "missing { before let block") MSG_DEF(JSMSG_CURLY_BEFORE_FINALLY, 0, JSEXN_SYNTAXERR, "missing { before finally block") MSG_DEF(JSMSG_CURLY_BEFORE_SWITCH, 0, JSEXN_SYNTAXERR, "missing { before switch body") MSG_DEF(JSMSG_CURLY_BEFORE_TRY, 0, JSEXN_SYNTAXERR, "missing { before try block") @@ -244,32 +241,37 @@ 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_NONE, "expression closures are deprecated") -MSG_DEF(JSMSG_DEPRECATED_FLAGS_ARG, 0, JSEXN_NONE, "flags argument of String.prototype.{search,match,replace} is deprecated") -MSG_DEF(JSMSG_DEPRECATED_FOR_EACH, 0, JSEXN_NONE, "JavaScript 1.6's for-each-in loops are deprecated; consider using ES6 for-of instead") -MSG_DEF(JSMSG_DEPRECATED_OCTAL, 0, JSEXN_SYNTAXERR, "octal literals and octal escape sequences are deprecated") -MSG_DEF(JSMSG_DEPRECATED_PRAGMA, 1, JSEXN_NONE, "Using //@ to indicate {0} pragmas is deprecated. Use //# instead") +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") MSG_DEF(JSMSG_DUPLICATE_PROPERTY, 1, JSEXN_SYNTAXERR, "property name {0} appears more than once in object literal") +MSG_DEF(JSMSG_DUPLICATE_PROTO_PROPERTY, 0, JSEXN_SYNTAXERR, "property name __proto__ appears more than once in object literal") MSG_DEF(JSMSG_EMPTY_CONSEQUENT, 0, JSEXN_SYNTAXERR, "mistyped ; after conditional?") MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 0, JSEXN_SYNTAXERR, "test for equality (==) mistyped as assignment (=)?") MSG_DEF(JSMSG_EXPORT_DECL_AT_TOP_LEVEL,0, JSEXN_SYNTAXERR, "export declarations may only appear at top level of a module") MSG_DEF(JSMSG_FINALLY_WITHOUT_TRY, 0, JSEXN_SYNTAXERR, "finally without try") +MSG_DEF(JSMSG_FORBIDDEN_AS_STATEMENT, 1, JSEXN_SYNTAXERR, "{0} can't appear in single-statement context") MSG_DEF(JSMSG_FROM_AFTER_IMPORT_CLAUSE, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after import clause") MSG_DEF(JSMSG_FROM_AFTER_EXPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after export *") 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_ILLEGAL_CHARACTER, 0, JSEXN_SYNTAXERR, "illegal character") 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_INVALID_FOR_INOF_DECL_WITH_INIT,1,JSEXN_SYNTAXERR,"for-{0} loop head declarations may not have initializers") -MSG_DEF(JSMSG_IN_AFTER_FOR_NAME, 0, JSEXN_SYNTAXERR, "missing 'in' or 'of' after for") +MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers") MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found") -MSG_DEF(JSMSG_LET_CLASS_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a class") MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable") 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") +MSG_DEF(JSMSG_GENERATOR_LABEL, 0, JSEXN_SYNTAXERR, "generator functions cannot be labelled") +MSG_DEF(JSMSG_FUNCTION_LABEL, 0, JSEXN_SYNTAXERR, "functions cannot be labelled") +MSG_DEF(JSMSG_SLOPPY_FUNCTION_LABEL, 0, JSEXN_SYNTAXERR, "functions can only be labelled inside blocks") MSG_DEF(JSMSG_LINE_BREAK_AFTER_THROW, 0, JSEXN_SYNTAXERR, "no line break is allowed between 'throw' and its expression") +MSG_DEF(JSMSG_LINE_BREAK_BEFORE_ARROW, 0, JSEXN_SYNTAXERR, "no line break is allowed before '=>'") MSG_DEF(JSMSG_MALFORMED_ESCAPE, 1, JSEXN_SYNTAXERR, "malformed {0} character escape sequence") MSG_DEF(JSMSG_MISSING_BINARY_DIGITS, 0, JSEXN_SYNTAXERR, "missing binary digits after '0b'") MSG_DEF(JSMSG_MISSING_EXPONENT, 0, JSEXN_SYNTAXERR, "missing exponent") @@ -279,11 +281,8 @@ MSG_DEF(JSMSG_MISSING_OCTAL_DIGITS, 0, JSEXN_SYNTAXERR, "missing octal digits after '0o'") 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_NAME_AFTER_IMPORT_STAR_AS, 0, JSEXN_SYNTAXERR, "missing name after import * as") MSG_DEF(JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT, 0, JSEXN_SYNTAXERR, "expected named imports or namespace import after comma") -MSG_DEF(JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT, 0, JSEXN_SYNTAXERR, "parameter(s) with default followed by parameter without default") MSG_DEF(JSMSG_NO_BINDING_NAME, 0, JSEXN_SYNTAXERR, "missing binding name") -MSG_DEF(JSMSG_NO_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class default constructors not yet implemented") MSG_DEF(JSMSG_NO_EXPORT_NAME, 0, JSEXN_SYNTAXERR, "missing export name") MSG_DEF(JSMSG_NO_IMPORT_NAME, 0, JSEXN_SYNTAXERR, "missing import name") MSG_DEF(JSMSG_NO_VARIABLE_NAME, 0, JSEXN_SYNTAXERR, "missing variable name") @@ -295,32 +294,30 @@ MSG_DEF(JSMSG_PAREN_AFTER_FORMAL, 0, JSEXN_SYNTAXERR, "missing ) after formal parameters") MSG_DEF(JSMSG_PAREN_AFTER_FOR_CTRL, 0, JSEXN_SYNTAXERR, "missing ) after for-loop control") MSG_DEF(JSMSG_PAREN_AFTER_FOR_OF_ITERABLE, 0, JSEXN_SYNTAXERR, "missing ) after for-of iterable") -MSG_DEF(JSMSG_PAREN_AFTER_LET, 0, JSEXN_SYNTAXERR, "missing ) after let head") MSG_DEF(JSMSG_PAREN_AFTER_SWITCH, 0, JSEXN_SYNTAXERR, "missing ) after switch expression") MSG_DEF(JSMSG_PAREN_AFTER_WITH, 0, JSEXN_SYNTAXERR, "missing ) after with-statement object") MSG_DEF(JSMSG_PAREN_BEFORE_CATCH, 0, JSEXN_SYNTAXERR, "missing ( before catch") MSG_DEF(JSMSG_PAREN_BEFORE_COND, 0, JSEXN_SYNTAXERR, "missing ( before condition") MSG_DEF(JSMSG_PAREN_BEFORE_FORMAL, 0, JSEXN_SYNTAXERR, "missing ( before formal parameters") -MSG_DEF(JSMSG_PAREN_BEFORE_LET, 0, JSEXN_SYNTAXERR, "missing ( before let head") MSG_DEF(JSMSG_PAREN_BEFORE_SWITCH, 0, JSEXN_SYNTAXERR, "missing ( before switch expression") MSG_DEF(JSMSG_PAREN_BEFORE_WITH, 0, JSEXN_SYNTAXERR, "missing ( before with-statement object") MSG_DEF(JSMSG_PAREN_IN_PAREN, 0, JSEXN_SYNTAXERR, "missing ) in parenthetical") MSG_DEF(JSMSG_RC_AFTER_EXPORT_SPEC_LIST, 0, JSEXN_SYNTAXERR, "missing '}' after export specifier list") MSG_DEF(JSMSG_RC_AFTER_IMPORT_SPEC_LIST, 0, JSEXN_SYNTAXERR, "missing '}' after module specifier list") -MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 1, JSEXN_TYPEERR, "redeclaration of identifier '{0}' in catch") -MSG_DEF(JSMSG_REDECLARED_PARAM, 1, JSEXN_TYPEERR, "redeclaration of formal parameter {0}") +MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 1, JSEXN_SYNTAXERR, "redeclaration of identifier '{0}' in catch") MSG_DEF(JSMSG_RESERVED_ID, 1, JSEXN_SYNTAXERR, "{0} is a reserved identifier") +MSG_DEF(JSMSG_REST_WITH_COMMA, 0, JSEXN_SYNTAXERR, "rest element may not have a trailing comma") MSG_DEF(JSMSG_REST_WITH_DEFAULT, 0, JSEXN_SYNTAXERR, "rest parameter may not have a default") MSG_DEF(JSMSG_SELFHOSTED_TOP_LEVEL_LEXICAL, 1, JSEXN_SYNTAXERR, "self-hosted code cannot contain top-level {0} declarations") +MSG_DEF(JSMSG_SELFHOSTED_METHOD_CALL, 0, JSEXN_SYNTAXERR, "self-hosted code may not contain direct method calls. Use callFunction() or callContentFunction()") MSG_DEF(JSMSG_SELFHOSTED_UNBOUND_NAME, 0, JSEXN_TYPEERR, "self-hosted code may not contain unbound name lookups") -MSG_DEF(JSMSG_SELFHOSTED_METHOD_CALL, 0, JSEXN_SYNTAXERR, "self-hosted code may not contain direct method calls") MSG_DEF(JSMSG_SEMI_AFTER_FOR_COND, 0, JSEXN_SYNTAXERR, "missing ; after for-loop condition") MSG_DEF(JSMSG_SEMI_AFTER_FOR_INIT, 0, JSEXN_SYNTAXERR, "missing ; after for-loop initializer") MSG_DEF(JSMSG_SEMI_BEFORE_STMNT, 0, JSEXN_SYNTAXERR, "missing ; before statement") MSG_DEF(JSMSG_SOURCE_TOO_LONG, 0, JSEXN_RANGEERR, "source is too long") -MSG_DEF(JSMSG_STMT_AFTER_RETURN, 0, JSEXN_NONE, "unreachable code after return statement") +MSG_DEF(JSMSG_STMT_AFTER_RETURN, 0, JSEXN_WARN, "unreachable code after return statement") MSG_DEF(JSMSG_STRICT_CODE_WITH, 0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements") -MSG_DEF(JSMSG_STRICT_FUNCTION_STATEMENT, 0, JSEXN_SYNTAXERR, "in strict mode code, functions may be declared only at top level or immediately within another function") +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") @@ -343,19 +340,53 @@ MSG_DEF(JSMSG_WHILE_AFTER_DO, 0, JSEXN_SYNTAXERR, "missing while after do-loop body") MSG_DEF(JSMSG_YIELD_IN_ARROW, 0, JSEXN_SYNTAXERR, "arrow function may not contain yield") MSG_DEF(JSMSG_YIELD_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "yield in default expression") +MSG_DEF(JSMSG_YIELD_IN_METHOD, 0, JSEXN_SYNTAXERR, "non-generator method definitions may not contain yield") 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 in non-exotic functions") +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") // 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_NONE, "Successfully compiled asm.js code ({0})") +MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 1, JSEXN_WARN, "Successfully compiled asm.js code ({0})") + +// wasm +MSG_DEF(JSMSG_WASM_COMPILE_ERROR, 1, JSEXN_WASMCOMPILEERROR, "{0}") +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") +MSG_DEF(JSMSG_WASM_INTEGER_OVERFLOW, 0, JSEXN_WASMRUNTIMEERROR, "integer overflow") +MSG_DEF(JSMSG_WASM_INVALID_CONVERSION, 0, JSEXN_WASMRUNTIMEERROR, "invalid conversion to integer") +MSG_DEF(JSMSG_WASM_INT_DIVIDE_BY_ZERO, 0, JSEXN_WASMRUNTIMEERROR, "integer divide by zero") +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_BAD_UINT32, 2, JSEXN_RANGEERR, "bad {0} {1}") +MSG_DEF(JSMSG_WASM_BAD_GROW, 1, JSEXN_RANGEERR, "failed to grow {0}") +MSG_DEF(JSMSG_WASM_BAD_FIT, 2, JSEXN_RANGEERR, "{0} segment does not fit in {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_IMP_SIZE, 1, JSEXN_TYPEERR, "imported {0} with incompatible size") +MSG_DEF(JSMSG_WASM_BAD_IMP_MAX, 1, JSEXN_TYPEERR, "imported {0} with incompatible maximum size") +MSG_DEF(JSMSG_WASM_BAD_ELEMENT, 0, JSEXN_TYPEERR, "\"element\" property of table descriptor must be \"anyfunc\"") +MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG, 0, JSEXN_TYPEERR, "second argument must be an object") +MSG_DEF(JSMSG_WASM_BAD_IMPORT_FIELD, 2, JSEXN_TYPEERR, "import object field '{0}' is not {1}") +MSG_DEF(JSMSG_WASM_BAD_IMPORT_SIG, 0, JSEXN_TYPEERR, "imported function signature mismatch") +MSG_DEF(JSMSG_WASM_BAD_TABLE_VALUE, 0, JSEXN_TYPEERR, "can only assign WebAssembly exported functions to Table") +MSG_DEF(JSMSG_WASM_BAD_I64, 0, JSEXN_TYPEERR, "cannot pass i64 to or from JS") +MSG_DEF(JSMSG_WASM_NO_TRANSFER, 0, JSEXN_TYPEERR, "cannot transfer WebAssembly/asm.js ArrayBuffer") +MSG_DEF(JSMSG_WASM_TEXT_FAIL, 1, JSEXN_SYNTAXERR, "wasm text error: {0}") // Proxy MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE, 2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value") +MSG_DEF(JSMSG_BAD_GETPROTOTYPEOF_TRAP_RETURN,0,JSEXN_TYPEERR,"proxy getPrototypeOf handler returned a non-object, non-null value") +MSG_DEF(JSMSG_INCONSISTENT_GETPROTOTYPEOF_TRAP,0,JSEXN_TYPEERR,"proxy getPrototypeOf handler didn't return the target object's prototype") +MSG_DEF(JSMSG_PROXY_SETPROTOTYPEOF_RETURNED_FALSE, 0, JSEXN_TYPEERR, "proxy setPrototypeOf handler returned false") +MSG_DEF(JSMSG_PROXY_ISEXTENSIBLE_RETURNED_FALSE,0,JSEXN_TYPEERR,"proxy isExtensible handler must return the same extensibility as target") +MSG_DEF(JSMSG_INCONSISTENT_SETPROTOTYPEOF_TRAP,0,JSEXN_TYPEERR,"proxy setPrototypeOf handler returned true, even though the target's prototype is immutable because the target is non-extensible") MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 0, JSEXN_TYPEERR, "can't change object's extensibility") MSG_DEF(JSMSG_CANT_DEFINE_INVALID, 0, JSEXN_TYPEERR, "proxy can't define an incompatible property descriptor") MSG_DEF(JSMSG_CANT_DEFINE_NEW, 0, JSEXN_TYPEERR, "proxy can't define a new property on a non-extensible object") @@ -374,7 +405,6 @@ MSG_DEF(JSMSG_CANT_SET_NW_NC, 0, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property") MSG_DEF(JSMSG_CANT_SET_WO_SETTER, 0, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property without a setter") MSG_DEF(JSMSG_CANT_SKIP_NC, 0, JSEXN_TYPEERR, "proxy can't skip a non-configurable property") -MSG_DEF(JSMSG_INVALID_TRAP_RESULT, 2, JSEXN_TYPEERR, "trap {1} for {0} returned an invalid result") MSG_DEF(JSMSG_ONWKEYS_STR_SYM, 0, JSEXN_TYPEERR, "proxy [[OwnPropertyKeys]] must return an array with only string and symbol elements") MSG_DEF(JSMSG_MUST_REPORT_SAME_VALUE, 0, JSEXN_TYPEERR, "proxy must report the same value for a non-writable, non-configurable property") MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED, 0, JSEXN_TYPEERR, "proxy must report undefined for a non-configurable accessor property without a getter") @@ -385,6 +415,7 @@ MSG_DEF(JSMSG_PROXY_GETOWN_OBJORUNDEF, 0, JSEXN_TYPEERR, "proxy [[GetOwnProperty]] must return an object or undefined") MSG_DEF(JSMSG_PROXY_REVOKED, 0, JSEXN_TYPEERR, "illegal operation attempted on a revoked proxy") MSG_DEF(JSMSG_PROXY_ARG_REVOKED, 1, JSEXN_TYPEERR, "argument {0} cannot be a revoked proxy") +MSG_DEF(JSMSG_BAD_TRAP, 1, JSEXN_TYPEERR, "proxy handler's {0} trap wasn't undefined, null, or callable") // Structured cloning MSG_DEF(JSMSG_SC_BAD_CLONE_VERSION, 0, JSEXN_ERR, "unsupported structured clone version") @@ -392,14 +423,18 @@ MSG_DEF(JSMSG_SC_DUP_TRANSFERABLE, 0, JSEXN_TYPEERR, "duplicate transferable for structured clone") MSG_DEF(JSMSG_SC_NOT_TRANSFERABLE, 0, JSEXN_TYPEERR, "invalid transferable array for structured clone") MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE, 0, JSEXN_TYPEERR, "unsupported type for structured data") -MSG_DEF(JSMSG_SC_SHMEM_MUST_TRANSFER, 0, JSEXN_TYPEERR, "SharedArrayBuffer must be explicitly transfered during structured cloning") +MSG_DEF(JSMSG_SC_NOT_CLONABLE, 1, JSEXN_TYPEERR, "{0} cannot be cloned in this context") +MSG_DEF(JSMSG_SC_SAB_TRANSFER, 0, JSEXN_WARN, "SharedArrayBuffer must not be in the transfer list") +MSG_DEF(JSMSG_SC_SAB_DISABLED, 0, JSEXN_TYPEERR, "SharedArrayBuffer not cloned - shared memory disabled in receiver") // Debugger MSG_DEF(JSMSG_ASSIGN_FUNCTION_OR_NULL, 1, JSEXN_TYPEERR, "value assigned to {0} must be a function or null") +MSG_DEF(JSMSG_DEBUG_BAD_AWAIT, 0, JSEXN_TYPEERR, "await expression received invalid value") MSG_DEF(JSMSG_DEBUG_BAD_LINE, 0, JSEXN_TYPEERR, "invalid line number") MSG_DEF(JSMSG_DEBUG_BAD_OFFSET, 0, JSEXN_TYPEERR, "invalid script offset") MSG_DEF(JSMSG_DEBUG_BAD_REFERENT, 2, JSEXN_TYPEERR, "{0} does not refer to {1}") 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_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") @@ -408,22 +443,25 @@ MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGING, 0, JSEXN_ERR, "can't set breakpoint: script global is not a debuggee") MSG_DEF(JSMSG_DEBUG_NOT_IDLE, 0, JSEXN_ERR, "can't start debugging: a debuggee script is on the stack") MSG_DEF(JSMSG_DEBUG_NOT_LIVE, 1, JSEXN_ERR, "{0} is not live") -MSG_DEF(JSMSG_DEBUG_NO_SCOPE_OBJECT, 0, JSEXN_TYPEERR, "declarative Environments don't have binding objects") -MSG_DEF(JSMSG_DEBUG_OBJECT_PROTO, 0, JSEXN_TYPEERR, "Debugger.Object.prototype is not a valid Debugger.Object") -MSG_DEF(JSMSG_DEBUG_OBJECT_WRONG_OWNER,0, JSEXN_TYPEERR, "Debugger.Object belongs to a different Debugger") -MSG_DEF(JSMSG_DEBUG_OPTIMIZED_OUT, 0, JSEXN_ERR, "variable has been optimized out") +MSG_DEF(JSMSG_DEBUG_NO_ENV_OBJECT, 0, JSEXN_TYPEERR, "declarative Environments don't have binding objects") +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_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") +MSG_DEF(JSMSG_DEBUGGEE_WOULD_RUN, 2, JSEXN_DEBUGGEEWOULDRUN, "debuggee `{0}:{1}' would run") MSG_DEF(JSMSG_NOT_CALLABLE_OR_UNDEFINED, 0, JSEXN_TYPEERR, "value is not a function or undefined") MSG_DEF(JSMSG_NOT_TRACKING_ALLOCATIONS, 1, JSEXN_ERR, "Cannot call {0} without setting trackingAllocationSites to true") -MSG_DEF(JSMSG_NOT_TRACKING_TENURINGS, 1, JSEXN_ERR, "Cannot call {0} without setting trackingTenurePromotions to true") MSG_DEF(JSMSG_OBJECT_METADATA_CALLBACK_ALREADY_SET, 0, JSEXN_ERR, "Cannot track object allocation, because other tools are already doing so") MSG_DEF(JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL, 0, JSEXN_TYPEERR, "findScripts query object with 'innermost' property must have 'line' and either 'displayURL', 'url', or 'source'") MSG_DEF(JSMSG_QUERY_LINE_WITHOUT_URL, 0, JSEXN_TYPEERR, "findScripts query object has 'line' property, but no 'displayURL', 'url', or 'source' property") MSG_DEF(JSMSG_DEBUG_CANT_SET_OPT_ENV, 1, JSEXN_REFERENCEERR, "can't set `{0}' in an optimized-out environment") MSG_DEF(JSMSG_DEBUG_INVISIBLE_COMPARTMENT, 0, JSEXN_TYPEERR, "object in compartment marked as invisible to Debugger") MSG_DEF(JSMSG_DEBUG_CENSUS_BREAKDOWN, 1, JSEXN_TYPEERR, "unrecognized 'by' value in takeCensus breakdown: {0}") +MSG_DEF(JSMSG_DEBUG_PROMISE_NOT_RESOLVED, 0, JSEXN_TYPEERR, "Promise hasn't been resolved") +MSG_DEF(JSMSG_DEBUG_PROMISE_NOT_FULFILLED, 0, JSEXN_TYPEERR, "Promise hasn't been fulfilled") +MSG_DEF(JSMSG_DEBUG_PROMISE_NOT_REJECTED, 0, JSEXN_TYPEERR, "Promise hasn't been rejected") // Tracelogger MSG_DEF(JSMSG_TRACELOGGER_ENABLE_FAIL, 1, JSEXN_ERR, "enabling tracelogger failed: {0}") @@ -443,14 +481,23 @@ MSG_DEF(JSMSG_UNDEFINED_CURRENCY, 0, JSEXN_TYPEERR, "undefined currency in NumberFormat() with currency style") // RegExp +MSG_DEF(JSMSG_BACK_REF_OUT_OF_RANGE, 0, JSEXN_SYNTAXERR, "back reference out of range in regular expression") MSG_DEF(JSMSG_BAD_CLASS_RANGE, 0, JSEXN_SYNTAXERR, "invalid range in character class") MSG_DEF(JSMSG_ESCAPE_AT_END_OF_REGEXP, 0, JSEXN_SYNTAXERR, "\\ at end of pattern") +MSG_DEF(JSMSG_EXEC_NOT_OBJORNULL, 0, JSEXN_TYPEERR, "RegExp exec method should return object or null") +MSG_DEF(JSMSG_INVALID_DECIMAL_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid decimal escape in regular expression") MSG_DEF(JSMSG_INVALID_GROUP, 0, JSEXN_SYNTAXERR, "invalid regexp group") +MSG_DEF(JSMSG_INVALID_IDENTITY_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid identity escape in regular expression") +MSG_DEF(JSMSG_INVALID_UNICODE_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid unicode escape in regular expression") MSG_DEF(JSMSG_MISSING_PAREN, 0, JSEXN_SYNTAXERR, "unterminated parenthetical") MSG_DEF(JSMSG_NEWREGEXP_FLAGGED, 0, JSEXN_TYPEERR, "can't supply flags when constructing one RegExp from another") 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_TOO_MANY_PARENS, 0, JSEXN_INTERNALERR, "too many parentheses in regular expression") +MSG_DEF(JSMSG_UNICODE_OVERFLOW, 0, JSEXN_SYNTAXERR, "unicode codepoint should not be greater than 0x10FFFF in regular expression") MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression") MSG_DEF(JSMSG_UNTERM_CLASS, 0, JSEXN_SYNTAXERR, "unterminated character class") @@ -466,30 +513,34 @@ MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_ARGS, 0, JSEXN_RANGEERR, "invalid field descriptor") 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") + +// Array +MSG_DEF(JSMSG_TOO_LONG_ARRAY, 0, JSEXN_TYPEERR, "Too long array") // Typed array MSG_DEF(JSMSG_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index") +MSG_DEF(JSMSG_NON_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected ArrayBuffer, but species constructor returned non-ArrayBuffer") +MSG_DEF(JSMSG_SAME_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected different ArrayBuffer, but species constructor returned same ArrayBuffer") +MSG_DEF(JSMSG_SHORT_ARRAY_BUFFER_RETURNED, 2, JSEXN_TYPEERR, "expected ArrayBuffer with at least {0} bytes, but species constructor returns ArrayBuffer with {1} bytes") MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS, 0, JSEXN_TYPEERR, "invalid arguments") -MSG_DEF(JSMSG_TYPED_ARRAY_BAD_OBJECT, 0, JSEXN_TYPEERR, "invalid object argument") -MSG_DEF(JSMSG_TYPED_ARRAY_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index") MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG,1, JSEXN_RANGEERR, "argument {0} must be >= 0") MSG_DEF(JSMSG_TYPED_ARRAY_DETACHED, 0, JSEXN_TYPEERR, "attempting to access detached ArrayBuffer") +MSG_DEF(JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS, 0, JSEXN_RANGEERR, "attempting to construct out-of-bounds TypedArray on ArrayBuffer") +MSG_DEF(JSMSG_TYPED_ARRAY_CALL_OR_CONSTRUCT, 1, JSEXN_TYPEERR, "cannot directly {0} builtin %TypedArray%") +MSG_DEF(JSMSG_NON_TYPED_ARRAY_RETURNED, 0, JSEXN_TYPEERR, "constructor didn't return TypedArray object") +MSG_DEF(JSMSG_SHORT_TYPED_ARRAY_RETURNED, 2, JSEXN_TYPEERR, "expected TypedArray of at least length {0}, but constructor returned TypedArray of length {1}") // Shared array buffer -MSG_DEF(JSMSG_SHARED_ARRAY_BAD_OBJECT, 0, JSEXN_TYPEERR, "invalid object argument") MSG_DEF(JSMSG_SHARED_ARRAY_BAD_LENGTH, 0, JSEXN_RANGEERR, "length argument out of range") - -// Shared typed array -MSG_DEF(JSMSG_SHARED_TYPED_ARRAY_BAD_OBJECT, 0, JSEXN_TYPEERR, "invalid object argument") -MSG_DEF(JSMSG_SHARED_TYPED_ARRAY_BAD_ARGS, 0, JSEXN_RANGEERR, "bad combination of offset, length, and element size") -MSG_DEF(JSMSG_SHARED_TYPED_ARRAY_ARG_RANGE, 1, JSEXN_RANGEERR, "argument {0} out of range") -MSG_DEF(JSMSG_SHARED_TYPED_ARRAY_BAD_LENGTH, 0, JSEXN_TYPEERR, "length argument must not be an object") +MSG_DEF(JSMSG_NON_SHARED_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected SharedArrayBuffer, but species constructor returned non-SharedArrayBuffer") +MSG_DEF(JSMSG_SAME_SHARED_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected different SharedArrayBuffer, but species constructor returned same SharedArrayBuffer") +MSG_DEF(JSMSG_SHORT_SHARED_ARRAY_BUFFER_RETURNED, 2, JSEXN_TYPEERR, "expected SharedArrayBuffer with at least {0} bytes, but species constructor returns SharedArrayBuffer with {1} bytes") // Reflect MSG_DEF(JSMSG_BAD_PARSE_NODE, 0, JSEXN_INTERNALERR, "bad parse node") // Symbol -MSG_DEF(JSMSG_BAD_SYMBOL, 1, JSEXN_TYPEERR, "{0} is not a well-known @@-symbol") MSG_DEF(JSMSG_SYMBOL_TO_STRING, 0, JSEXN_TYPEERR, "can't convert symbol to string") MSG_DEF(JSMSG_SYMBOL_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert symbol to number") @@ -497,7 +548,6 @@ MSG_DEF(JSMSG_ATOMICS_BAD_ARRAY, 0, JSEXN_TYPEERR, "invalid array type for the operation") MSG_DEF(JSMSG_ATOMICS_TOO_LONG, 0, JSEXN_RANGEERR, "timeout value too large") MSG_DEF(JSMSG_ATOMICS_WAIT_NOT_ALLOWED, 0, JSEXN_ERR, "waiting is not allowed on this thread") -MSG_DEF(JSMSG_ATOMICS_BAD_INDEX, 0, JSEXN_RANGEERR, "out-of-range index for atomic access") // XPConnect wrappers and DOM bindings MSG_DEF(JSMSG_CANT_SET_INTERPOSED, 1, JSEXN_TYPEERR, "unable to set interposed data property '{0}'") @@ -520,3 +570,12 @@ MSG_DEF(JSMSG_AMBIGUOUS_IMPORT, 1, JSEXN_SYNTAXERR, "ambiguous import '{0}'") 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_MODULE_INSTANTIATE_FAILED, 0, JSEXN_INTERNALERR, "attempt to re-instantiate module after failure") +MSG_DEF(JSMSG_BAD_MODULE_STATE, 0, JSEXN_INTERNALERR, "module record in unexpected state") + +// Promise +MSG_DEF(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself.") +MSG_DEF(JSMSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY, 0, JSEXN_TYPEERR, "GetCapabilitiesExecutor function already invoked with non-undefined values.") +MSG_DEF(JSMSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the resolve function.") +MSG_DEF(JSMSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the reject function.") +MSG_DEF(JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON,0, JSEXN_INTERNALERR, "Promise rejection value is a non-unwrappable cross-compartment wrapper.") 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 @@ -6,16 +6,51 @@ /* * Helper classes encapsulating access to the callee, |this| value, arguments, - * and argument count for a function call. + * and argument count for a call/construct operation. * - * The intent of JS::CallArgs and JS::CallReceiver is that they be used to - * encapsulate access to the un-abstracted |unsigned argc, Value* vp| arguments - * to a function. 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 or CallReceiver. - * New code should use CallArgs and CallReceiver instead whenever possible. + * JS::CallArgs encapsulates access to a JSNative's un-abstracted + * |unsigned argc, Value* vp| arguments. The principal way to create a + * JS::CallArgs is using JS::CallArgsFromVp: + * + * // If provided no arguments or a non-numeric first argument, return zero. + * // Otherwise return |this| exactly as given, without boxing. + * static bool + * Func(JSContext* cx, unsigned argc, JS::Value* vp) + * { + * JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + * + * // Guard against no arguments or a non-numeric arg0. + * if (args.length() == 0 || !args[0].isNumber()) { + * args.rval().setInt32(0); + * return true; + * } + * + * // Access to the callee must occur before accessing/setting + * // the return value. + * JSObject& callee = args.callee(); + * args.rval().setObject(callee); + * + * // callee() and calleev() will now assert. + * + * // It's always fine to access thisv(). + * HandleValue thisv = args.thisv(); + * args.rval().set(thisv); + * + * // As the return value was last set to |this|, returns |this|. + * return true; + * } + * + * CallArgs is exposed publicly and used internally. Not all parts of its + * public interface are meant to be used by embedders! See inline comments to + * for details. + * + * 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. + * New code should use CallArgs instead whenever possible. * * The eventual plan is to change JSNative to take |const CallArgs&| directly, * for automatic assertion of correct use and to make calling functions more @@ -42,118 +77,99 @@ typedef bool (* JSNative)(JSContext* cx, unsigned argc, JS::Value* vp); -/* - * Compute |this| for the |vp| inside a JSNative, either boxing primitives or - * replacing with the global object as necessary. - * - * This method will go away at some point: instead use |args.thisv()|. If the - * value is an object, no further work is required. If that value is |null| or - * |undefined|, use |JS_GetGlobalForObject| to compute the global object. If - * the value is some other primitive, use |JS_ValueToObject| to box it. - */ -extern JS_PUBLIC_API(JS::Value) -JS_ComputeThis(JSContext* cx, JS::Value* vp); - namespace JS { extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue; +namespace detail { + /* - * JS::CallReceiver encapsulates access to the callee, |this|, and eventual - * return value for a function call. The principal way to create a - * CallReceiver is using JS::CallReceiverFromVp: - * - * static bool - * FunctionReturningThis(JSContext* cx, unsigned argc, JS::Value* vp) - * { - * JS::CallReceiver rec = JS::CallReceiverFromVp(vp); - * - * // Access to the callee must occur before accessing/setting - * // the return value. - * JSObject& callee = rec.callee(); - * rec.rval().set(JS::ObjectValue(callee)); - * - * // callee() and calleev() will now assert. - * - * // It's always fine to access thisv(). - * HandleValue thisv = rec.thisv(); - * rec.rval().set(thisv); - * - * // As the return value was last set to |this|, returns |this|. - * return true; - * } - * - * A note on JS_ComputeThis and JS_THIS_OBJECT: these methods currently aren't - * part of the CallReceiver interface. We will likely add them at some point. - * Until then, you should probably continue using |vp| directly for these two - * cases. - * - * CallReceiver is exposed publicly and used internally. Not all parts of its - * public interface are meant to be used by embedders! See inline comments to - * for details. + * Compute |this| for the |vp| inside a JSNative, either boxing primitives or + * replacing with the global object as necessary. */ - -namespace detail { +extern JS_PUBLIC_API(Value) +ComputeThis(JSContext* cx, JS::Value* vp); #ifdef JS_DEBUG extern JS_PUBLIC_API(void) -CheckIsValidConstructible(Value v); +CheckIsValidConstructible(const Value& v); #endif -enum UsedRval { IncludeUsedRval, NoUsedRval }; - -template -class MOZ_STACK_CLASS UsedRvalBase; - -template<> -class MOZ_STACK_CLASS UsedRvalBase +class MOZ_STACK_CLASS IncludeUsedRval { protected: +#ifdef JS_DEBUG mutable bool usedRval_; void setUsedRval() const { usedRval_ = true; } void clearUsedRval() const { usedRval_ = false; } + void assertUnusedRval() const { MOZ_ASSERT(!usedRval_); } +#else + void setUsedRval() const {} + void clearUsedRval() const {} + void assertUnusedRval() const {} +#endif }; -template<> -class MOZ_STACK_CLASS UsedRvalBase +class MOZ_STACK_CLASS NoUsedRval { protected: void setUsedRval() const {} void clearUsedRval() const {} + void assertUnusedRval() const {} }; -template -class MOZ_STACK_CLASS CallReceiverBase : public UsedRvalBase< -#ifdef JS_DEBUG - WantUsedRval -#else - NoUsedRval -#endif - > +template +class MOZ_STACK_CLASS CallArgsBase : public WantUsedRval { + static_assert(mozilla::IsSame::value || + mozilla::IsSame::value, + "WantUsedRval can only be IncludeUsedRval or NoUsedRval"); + protected: Value* argv_; + unsigned argc_; + bool constructing_; public: - /* - * Returns the function being called, as an object. Must not be called - * after rval() has been used! - */ - JSObject& callee() const { - MOZ_ASSERT(!this->usedRval_); - return argv_[-2].toObject(); - } + // CALLEE ACCESS /* * Returns the function being called, as a value. Must not be called after * rval() has been used! */ HandleValue calleev() const { - MOZ_ASSERT(!this->usedRval_); + this->assertUnusedRval(); return HandleValue::fromMarkedLocation(&argv_[-2]); } /* + * Returns the function being called, as an object. Must not be called + * after rval() has been used! + */ + JSObject& callee() const { + return calleev().toObject(); + } + + // CALLING/CONSTRUCTING-DIFFERENTIATIONS + + bool isConstructing() const { + if (!argv_[-1].isMagic()) + return false; + +#ifdef JS_DEBUG + if (!this->usedRval_) + CheckIsValidConstructible(calleev()); +#endif + + return true; + } + + MutableHandleValue newTarget() const { + MOZ_ASSERT(constructing_); + return MutableHandleValue::fromMarkedLocation(&this->argv_[argc_]); + } + + /* * Returns the |this| value passed to the function. This method must not * be called when the function is being called as a constructor via |new|. * The value may or may not be an object: it is the individual function's @@ -170,17 +186,40 @@ if (thisv().isObject()) return thisv(); - return JS_ComputeThis(cx, base()); + return ComputeThis(cx, base()); } - bool isConstructing() const { -#ifdef JS_DEBUG - if (this->usedRval_) - CheckIsValidConstructible(calleev()); -#endif - return argv_[-1].isMagic(); + // ARGUMENTS + + /* Returns the number of arguments. */ + unsigned length() const { return argc_; } + + /* Returns the i-th zero-indexed argument. */ + MutableHandleValue operator[](unsigned i) const { + MOZ_ASSERT(i < argc_); + return MutableHandleValue::fromMarkedLocation(&this->argv_[i]); + } + + /* + * Returns the i-th zero-indexed argument, or |undefined| if there's no + * such argument. + */ + HandleValue get(unsigned i) const { + return i < length() + ? HandleValue::fromMarkedLocation(&this->argv_[i]) + : UndefinedHandleValue; + } + + /* + * Returns true if the i-th zero-indexed argument is present and is not + * |undefined|. + */ + bool hasDefined(unsigned i) const { + return i < argc_ && !this->argv_[i].isUndefined(); } + // RETURN VALUE + /* * Returns the currently-set return value. The initial contents of this * value are unspecified. Once this method has been called, callee() and @@ -198,135 +237,41 @@ } public: - // These methods are only intended for internal use. Embedders shouldn't - // use them! - - Value* base() const { return argv_ - 2; } - - Value* spAfterCall() const { - this->setUsedRval(); - return argv_ - 1; - } - - public: // These methods are publicly exposed, but they are *not* to be used when // implementing a JSNative method and encapsulating access to |vp| within // it. You probably don't want to use these! - void setCallee(Value aCalleev) const { + void setCallee(const Value& aCalleev) const { this->clearUsedRval(); argv_[-2] = aCalleev; } - void setThis(Value aThisv) const { + void setThis(const Value& aThisv) const { argv_[-1] = aThisv; } MutableHandleValue mutableThisv() const { return MutableHandleValue::fromMarkedLocation(&argv_[-1]); } -}; - -} // namespace detail - -class MOZ_STACK_CLASS CallReceiver : public detail::CallReceiverBase -{ - private: - friend CallReceiver CallReceiverFromVp(Value* vp); - friend CallReceiver CallReceiverFromArgv(Value* argv); -}; - -MOZ_ALWAYS_INLINE CallReceiver -CallReceiverFromArgv(Value* argv) -{ - CallReceiver receiver; - receiver.clearUsedRval(); - receiver.argv_ = argv; - return receiver; -} - -MOZ_ALWAYS_INLINE CallReceiver -CallReceiverFromVp(Value* vp) -{ - return CallReceiverFromArgv(vp + 2); -} - -/* - * JS::CallArgs encapsulates everything JS::CallReceiver does, plus access to - * the function call's arguments. The principal way to create a CallArgs is - * like so, using JS::CallArgsFromVp: - * - * static bool - * FunctionReturningArgcTimesArg0(JSContext* cx, unsigned argc, JS::Value* vp) - * { - * JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - * - * // Guard against no arguments or a non-numeric arg0. - * if (args.length() == 0 || !args[0].isNumber()) { - * args.rval().setInt32(0); - * return true; - * } - * - * args.rval().set(JS::NumberValue(args.length() * args[0].toNumber())); - * return true; - * } - * - * CallArgs is exposed publicly and used internally. Not all parts of its - * public interface are meant to be used by embedders! See inline comments to - * for details. - */ -namespace detail { - -template -class MOZ_STACK_CLASS CallArgsBase : - public mozilla::Conditional >::Type -{ - protected: - unsigned argc_; - bool constructing_; public: - /* Returns the number of arguments. */ - unsigned length() const { return argc_; } + // These methods are publicly exposed, but we're unsure of the interfaces + // (because they're hackish and drop assertions). Avoid using these if you + // can. - /* Returns the i-th zero-indexed argument. */ - MutableHandleValue operator[](unsigned i) const { - MOZ_ASSERT(i < argc_); - return MutableHandleValue::fromMarkedLocation(&this->argv_[i]); - } + Value* array() const { return argv_; } + Value* end() const { return argv_ + argc_ + constructing_; } - /* - * Returns the i-th zero-indexed argument, or |undefined| if there's no - * such argument. - */ - HandleValue get(unsigned i) const { - return i < length() - ? HandleValue::fromMarkedLocation(&this->argv_[i]) - : UndefinedHandleValue; - } + public: + // These methods are only intended for internal use. Embedders shouldn't + // use them! - /* - * Returns true if the i-th zero-indexed argument is present and is not - * |undefined|. - */ - bool hasDefined(unsigned i) const { - return i < argc_ && !this->argv_[i].isUndefined(); - } + Value* base() const { return argv_ - 2; } - MutableHandleValue newTarget() const { - MOZ_ASSERT(constructing_); - return MutableHandleValue::fromMarkedLocation(&this->argv_[argc_]); + Value* spAfterCall() const { + this->setUsedRval(); + return argv_ - 1; } - - public: - // These methods are publicly exposed, but we're less sure of the interface - // here than we'd like (because they're hackish and drop assertions). Try - // to avoid using these if you can. - - Value* array() const { return this->argv_; } - Value* end() const { return this->argv_ + argc_ + constructing_; } }; } // namespace detail @@ -343,6 +288,10 @@ args.argv_ = argv; args.argc_ = argc; args.constructing_ = constructing; +#ifdef DEBUG + for (unsigned i = 0; i < argc; ++i) + MOZ_ASSERT_IF(argv[i].isMarkable(), !GCThingIsMarkedGray(GCCellPtr(argv[i]))); +#endif return args; } @@ -351,7 +300,7 @@ * Returns true if there are at least |required| arguments passed in. If * false, it reports an error message on the context. */ - bool requireAtLeast(JSContext* cx, const char* fnname, unsigned required) const; + JS_PUBLIC_API(bool) requireAtLeast(JSContext* cx, const char* fnname, unsigned required) const; }; @@ -379,19 +328,30 @@ * take a const JS::CallArgs&. */ -#define JS_THIS_OBJECT(cx,vp) (JS_THIS(cx,vp).toObjectOrNull()) - /* + * 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_ComputeThis(cx, vp) : vp[1]; + 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. 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 @@ -31,6 +31,8 @@ typedef mozilla::Range Base; public: + using CharT = Latin1Char; + Latin1Chars() : Base() {} Latin1Chars(char* aBytes, size_t aLength) : Base(reinterpret_cast(aBytes), aLength) {} Latin1Chars(const Latin1Char* aBytes, size_t aLength) @@ -49,6 +51,8 @@ typedef mozilla::RangedPtr Base; public: + using CharT = Latin1Char; + Latin1CharsZ() : Base(nullptr, 0) {} Latin1CharsZ(char* aBytes, size_t aLength) @@ -73,6 +77,8 @@ typedef mozilla::Range Base; public: + using CharT = unsigned char; + UTF8Chars() : Base() {} UTF8Chars(char* aBytes, size_t aLength) : Base(reinterpret_cast(aBytes), aLength) @@ -90,6 +96,8 @@ typedef mozilla::RangedPtr Base; public: + using CharT = unsigned char; + UTF8CharsZ() : Base(nullptr, 0) {} UTF8CharsZ(char* aBytes, size_t aLength) @@ -110,6 +118,43 @@ }; /* + * 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. + */ +class JS_PUBLIC_API(ConstUTF8CharsZ) +{ + const char* data_; + + public: + using CharT = unsigned char; + + ConstUTF8CharsZ() : data_(nullptr) + {} + + ConstUTF8CharsZ(const char* aBytes, size_t aLength) + : data_(aBytes) + { + MOZ_ASSERT(aBytes[aLength] == '\0'); +#ifdef DEBUG + validate(aLength); +#endif + } + + const void* get() const { return data_; } + + const char* c_str() const { return data_; } + + explicit operator bool() const { return data_ != nullptr; } + + private: +#ifdef DEBUG + void validate(size_t aLength); +#endif +}; + +/* * SpiderMonkey uses a 2-byte character representation: it is a * 2-byte-at-a-time view of a UTF-16 byte stream. This is similar to UCS-2, * but unlike UCS-2, we do not strip UTF-16 extension bytes. This allows a @@ -122,6 +167,8 @@ typedef mozilla::Range Base; public: + using CharT = char16_t; + TwoByteChars() : Base() {} TwoByteChars(char16_t* aChars, size_t aLength) : Base(aChars, aLength) {} TwoByteChars(const char16_t* aChars, size_t aLength) : Base(const_cast(aChars), aLength) {} @@ -135,6 +182,8 @@ typedef mozilla::RangedPtr Base; public: + using CharT = char16_t; + TwoByteCharsZ() : Base(nullptr, 0) {} TwoByteCharsZ(char16_t* chars, size_t length) @@ -156,6 +205,8 @@ typedef mozilla::Range Base; public: + using CharT = char16_t; + ConstTwoByteChars() : Base() {} ConstTwoByteChars(const char16_t* aChars, size_t aLength) : Base(aChars, aLength) {} }; @@ -174,11 +225,18 @@ LossyTwoByteCharsToNewLatin1CharsZ(js::ExclusiveContext* cx, const mozilla::Range tbchars); +inline Latin1CharsZ +LossyTwoByteCharsToNewLatin1CharsZ(js::ExclusiveContext* cx, const char16_t* begin, size_t length) +{ + const mozilla::Range tbchars(begin, length); + return JS::LossyTwoByteCharsToNewLatin1CharsZ(cx, tbchars); +} + template extern UTF8CharsZ -CharsToNewUTF8CharsZ(js::ExclusiveContext* maybeCx, const mozilla::Range chars); +CharsToNewUTF8CharsZ(js::ExclusiveContext* maybeCx, const mozilla::Range chars); -uint32_t +JS_PUBLIC_API(uint32_t) Utf8ToOneUcs4Char(const uint8_t* utf8Buffer, int utf8Length); /* @@ -187,17 +245,26 @@ * - On success, returns a malloc'd TwoByteCharsZ, and updates |outlen| to hold * its length; the length value excludes the trailing null. */ -extern TwoByteCharsZ +extern JS_PUBLIC_API(TwoByteCharsZ) UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); /* + * Like UTF8CharsToNewTwoByteCharsZ, but for ConstUTF8CharsZ. + */ +extern JS_PUBLIC_API(TwoByteCharsZ) +UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen); + +/* * 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 TwoByteCharsZ +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); + /* * Returns the length of the char buffer required to encode |s| as UTF8. * Does not include the null-terminator. @@ -206,11 +273,62 @@ GetDeflatedUTF8StringLength(JSFlatString* s); /* - * Encode |src| as UTF8. The caller must ensure |dst| has enough space. - * Does not write the null terminator. + * Encode |src| as UTF8. The caller must either ensure |dst| has enough space + * to encode the entire string or pass the length of the buffer as |dstlenp|, + * in which case the function will encode characters from the string until + * the buffer is exhausted. Does not write the null terminator. + * + * If |dstlenp| is provided, it will be updated to hold the number of bytes + * written to the buffer. If |numcharsp| is provided, it will be updated to hold + * the number of Unicode characters written to the buffer (which can be less + * than the length of the string, if the buffer is exhausted before the string + * is fully encoded). */ JS_PUBLIC_API(void) -DeflateStringToUTF8Buffer(JSFlatString* src, mozilla::RangedPtr dst); +DeflateStringToUTF8Buffer(JSFlatString* src, mozilla::RangedPtr dst, + size_t* dstlenp = nullptr, size_t* numcharsp = nullptr); + +/* + * The smallest character encoding capable of fully representing a particular + * string. + */ +enum class SmallestEncoding { + ASCII, + Latin1, + UTF16 +}; + +/* + * Returns the smallest encoding possible for the given string: if all + * codepoints are <128 then ASCII, otherwise if all codepoints are <256 + * Latin-1, else UTF16. + */ +JS_PUBLIC_API(SmallestEncoding) +FindSmallestEncoding(UTF8Chars utf8); + +/* + * Return a null-terminated Latin-1 string copied from the input string, + * storing its length (excluding null terminator) in |*outlen|. Fail and + * report an error if the string contains non-Latin-1 codepoints. Returns + * Latin1CharsZ() on failure. + */ +extern JS_PUBLIC_API(Latin1CharsZ) +UTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); + +/* + * 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); + +/* + * Returns true if all characters in the given null-terminated string are + * ASCII, i.e. < 0x80, false otherwise. + */ +extern JS_PUBLIC_API(bool) +StringIsASCII(const char* s); } // namespace JS 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 @@ -9,8 +9,6 @@ #ifndef js_Class_h #define js_Class_h -#include "mozilla/DebugOnly.h" - #include "jstypes.h" #include "js/CallArgs.h" @@ -42,9 +40,7 @@ namespace JS { -template -class AutoVectorRooter; -typedef AutoVectorRooter AutoIdVector; +class AutoIdVector; /** * The answer to a successful query as to whether an object is an Array per @@ -337,8 +333,8 @@ * (e.g., the DOM attributes for a given node reflected as obj) on demand. * * JS looks for a property in an object, and if not found, tries to resolve - * the given id. *resolvedp should be set to true iff the property was - * was defined on |obj|. + * the given id. *resolvedp should be set to true iff the property was defined + * on |obj|. */ typedef bool (* JSResolveOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, @@ -368,7 +364,7 @@ /** Finalizes external strings created by JS_NewExternalString. */ struct JSStringFinalizer { - void (*finalize)(const JSStringFinalizer* fin, char16_t* chars); + void (*finalize)(JS::Zone* zone, const JSStringFinalizer* fin, char16_t* chars); }; /** @@ -383,8 +379,8 @@ /** * Function type for trace operation of the class called to enumerate all * traceable things reachable from obj's private data structure. For each such - * thing, a trace implementation must call one of the JS_Call*Tracer variants - * on the thing. + * thing, a trace implementation must call JS::TraceEdge on the thing's + * location. * * JSTraceOp implementation can assume that no other threads mutates object * state. It must not change state of the object or corresponding native @@ -412,7 +408,7 @@ JS::MutableHandleObject objp, JS::MutableHandle propp); typedef bool (* DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result); typedef bool (* HasPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); @@ -424,7 +420,7 @@ JS::HandleValue receiver, JS::ObjectOpResult& result); typedef bool (* GetOwnPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); typedef bool (* DeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::ObjectOpResult& result); @@ -453,15 +449,25 @@ JS::Value* vp_; uint32_t index_; - mozilla::DebugOnly length_; +#ifdef DEBUG + uint32_t length_; +#endif GetBehavior getBehavior_; public: ElementAdder(JSContext* cx, JSObject* obj, uint32_t length, GetBehavior behavior) - : resObj_(cx, obj), vp_(nullptr), index_(0), length_(length), getBehavior_(behavior) + : resObj_(cx, obj), vp_(nullptr), index_(0), +#ifdef DEBUG + length_(length), +#endif + getBehavior_(behavior) {} ElementAdder(JSContext* cx, JS::Value* vp, uint32_t length, GetBehavior behavior) - : resObj_(cx), vp_(vp), index_(0), length_(length), getBehavior_(behavior) + : resObj_(cx), vp_(vp), index_(0), +#ifdef DEBUG + length_(length), +#endif + getBehavior_(behavior) {} GetBehavior getBehavior() const { return getBehavior_; } @@ -477,23 +483,55 @@ typedef void (* FinalizeOp)(FreeOp* fop, JSObject* obj); -#define JS_CLASS_MEMBERS(FinalizeOpType) \ - const char* name; \ - uint32_t flags; \ - \ - /* Function pointer members (may be null). */ \ - JSAddPropertyOp addProperty; \ - JSDeletePropertyOp delProperty; \ - JSGetterOp getProperty; \ - JSSetterOp setProperty; \ - JSEnumerateOp enumerate; \ - JSResolveOp resolve; \ - JSMayResolveOp mayResolve; \ - FinalizeOpType finalize; \ - JSNative call; \ - JSHasInstanceOp hasInstance; \ - JSNative construct; \ - JSTraceOp trace +// The special treatment of |finalize| and |trace| is necessary because if we +// assign either of those hooks to a local variable and then call it -- as is +// done with the other hooks -- the GC hazard analysis gets confused. +#define JS_CLASS_MEMBERS(ClassOpsType, FreeOpType) \ + const char* name; \ + uint32_t flags; \ + const ClassOpsType* cOps; \ + \ + JSAddPropertyOp getAddProperty() const { return cOps ? cOps->addProperty : nullptr; } \ + JSDeletePropertyOp getDelProperty() const { return cOps ? cOps->delProperty : nullptr; } \ + JSGetterOp getGetProperty() const { return cOps ? cOps->getProperty : nullptr; } \ + JSSetterOp getSetProperty() const { return cOps ? cOps->setProperty : nullptr; } \ + JSEnumerateOp getEnumerate() const { return cOps ? cOps->enumerate : nullptr; } \ + JSResolveOp getResolve() const { return cOps ? cOps->resolve : nullptr; } \ + JSMayResolveOp getMayResolve() const { return cOps ? cOps->mayResolve : nullptr; } \ + JSNative getCall() const { return cOps ? cOps->call : nullptr; } \ + JSHasInstanceOp getHasInstance() const { return cOps ? cOps->hasInstance : nullptr; } \ + JSNative getConstruct() const { return cOps ? cOps->construct : nullptr; } \ + \ + bool hasFinalize() const { return cOps && cOps->finalize; } \ + bool hasTrace() const { return cOps && cOps->trace; } \ + \ + bool isTrace(JSTraceOp trace) const { return cOps && cOps->trace == trace; } \ + \ + void doFinalize(FreeOpType* fop, JSObject* obj) const { \ + MOZ_ASSERT(cOps && cOps->finalize); \ + cOps->finalize(fop, obj); \ + } \ + void doTrace(JSTracer* trc, JSObject* obj) const { \ + MOZ_ASSERT(cOps && cOps->trace); \ + cOps->trace(trc, obj); \ + } + +struct ClassOps +{ + /* Function pointer members (may be null). */ + JSAddPropertyOp addProperty; + JSDeletePropertyOp delProperty; + JSGetterOp getProperty; + JSSetterOp setProperty; + JSEnumerateOp enumerate; + JSResolveOp resolve; + JSMayResolveOp mayResolve; + FinalizeOp finalize; + JSNative call; + JSHasInstanceOp hasInstance; + JSNative construct; + JSTraceOp trace; +}; /** Callback for the creation of constructor and prototype objects. */ typedef JSObject* (*ClassObjectCreationOp)(JSContext* cx, JSProtoKey key); @@ -516,11 +554,11 @@ FinishClassInitOp finishInit_; uintptr_t flags; - static const size_t ParentKeyWidth = JSCLASS_CACHED_PROTO_WIDTH; + static const size_t ProtoKeyWidth = JSCLASS_CACHED_PROTO_WIDTH; - static const uintptr_t ParentKeyMask = (1 << ParentKeyWidth) - 1; - static const uintptr_t DontDefineConstructor = 1 << ParentKeyWidth; - static const uintptr_t IsDelegated = 1 << (ParentKeyWidth + 1); + static const uintptr_t ProtoKeyMask = (1 << ProtoKeyWidth) - 1; + static const uintptr_t DontDefineConstructor = 1 << ProtoKeyWidth; + static const uintptr_t IsDelegated = 1 << (ProtoKeyWidth + 1); bool defined() const { return !!createConstructor_; } @@ -528,14 +566,16 @@ return (flags & IsDelegated); } - bool dependent() const { + // The ProtoKey this class inherits from. + JSProtoKey inheritanceProtoKey() const { MOZ_ASSERT(defined()); - return (flags & ParentKeyMask); - } - - JSProtoKey parentKey() const { static_assert(JSProto_Null == 0, "zeroed key must be null"); - return JSProtoKey(flags & ParentKeyMask); + + // Default: Inherit from Object. + if (!(flags & ProtoKeyMask)) + return JSProto_Object; + + return JSProtoKey(flags & ProtoKeyMask); } bool shouldDefineConstructor() const { @@ -588,12 +628,6 @@ struct ClassExtension { /** - * isWrappedNative is true only if the class is an XPCWrappedNative. - * WeakMaps use this to override the wrapper disposal optimization. - */ - bool isWrappedNative; - - /** * 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 @@ -624,28 +658,26 @@ return reinterpret_cast(const_cast(spec)); } -#define JS_NULL_CLASS_SPEC {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr} -#define JS_NULL_CLASS_EXT {false,nullptr} +#define JS_NULL_CLASS_SPEC nullptr +#define JS_NULL_CLASS_EXT nullptr struct ObjectOps { - LookupPropertyOp lookupProperty; - DefinePropertyOp defineProperty; - HasPropertyOp hasProperty; - GetPropertyOp getProperty; - SetPropertyOp setProperty; - GetOwnPropertyOp getOwnPropertyDescriptor; - DeletePropertyOp deleteProperty; - WatchOp watch; - UnwatchOp unwatch; - GetElementsOp getElements; - JSNewEnumerateOp enumerate; - JSFunToStringOp funToString; -}; - -#define JS_NULL_OBJECT_OPS \ - {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, \ - nullptr, nullptr, nullptr, nullptr} + LookupPropertyOp lookupProperty; + DefinePropertyOp defineProperty; + HasPropertyOp hasProperty; + GetPropertyOp getProperty; + SetPropertyOp setProperty; + GetOwnPropertyOp getOwnPropertyDescriptor; + DeletePropertyOp deleteProperty; + WatchOp watch; + UnwatchOp unwatch; + GetElementsOp getElements; + JSNewEnumerateOp enumerate; + JSFunToStringOp funToString; +}; + +#define JS_NULL_OBJECT_OPS nullptr } // namespace js @@ -653,19 +685,54 @@ typedef void (*JSClassInternal)(); +struct JSClassOps +{ + /* Function pointer members (may be null). */ + JSAddPropertyOp addProperty; + JSDeletePropertyOp delProperty; + JSGetterOp getProperty; + JSSetterOp setProperty; + JSEnumerateOp enumerate; + JSResolveOp resolve; + JSMayResolveOp mayResolve; + JSFinalizeOp finalize; + JSNative call; + JSHasInstanceOp hasInstance; + JSNative construct; + JSTraceOp trace; +}; + +#define JS_NULL_CLASS_OPS nullptr + struct JSClass { - JS_CLASS_MEMBERS(JSFinalizeOp); + JS_CLASS_MEMBERS(JSClassOps, JSFreeOp); - void* reserved[23]; + void* reserved[3]; }; #define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot -#define JSCLASS_DELAY_METADATA_CALLBACK (1<<1) // class's initialization code +#define JSCLASS_DELAY_METADATA_BUILDER (1<<1) // class's initialization code // will call // SetNewObjectMetadata itself +#define JSCLASS_IS_WRAPPED_NATIVE (1<<2) // class is an XPCWrappedNative. + // WeakMaps use this to override + // the wrapper disposal + // mechanism. #define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) // private is (nsISupports*) #define JSCLASS_IS_DOMJSCLASS (1<<4) // objects are DOM -// Bit 5 is unused. +#define JSCLASS_HAS_XRAYED_CONSTRUCTOR (1<<5) // if wrapped by an xray + // wrapper, the builtin + // class's constructor won't + // be unwrapped and invoked. + // Instead, the constructor is + // resolved in the caller's + // compartment and invoked + // with a wrapped newTarget. + // The constructor has to + // detect and handle this + // situation. + // See PromiseConstructor for + // details. #define JSCLASS_EMULATES_UNDEFINED (1<<6) // objects of this class act // like the value undefined, // in some contexts @@ -700,6 +767,7 @@ #define JSCLASS_USERBIT3 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+7)) #define JSCLASS_BACKGROUND_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+8)) +#define JSCLASS_FOREGROUND_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+9)) // Bits 26 through 31 are reserved for the CACHED_PROTO_KEY mechanism, see // below. @@ -719,7 +787,7 @@ // application. #define JSCLASS_GLOBAL_APPLICATION_SLOTS 5 #define JSCLASS_GLOBAL_SLOT_COUNT \ - (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 36) + (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 39) #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \ (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n))) #define JSCLASS_GLOBAL_FLAGS \ @@ -745,10 +813,10 @@ struct Class { - JS_CLASS_MEMBERS(FinalizeOp); - ClassSpec spec; - ClassExtension ext; - ObjectOps ops; + JS_CLASS_MEMBERS(js::ClassOps, FreeOp); + const ClassSpec* spec; + const ClassExtension* ext; + const ObjectOps* oOps; /* * Objects of this class aren't native objects. They don't have Shapes that @@ -777,7 +845,7 @@ bool nonProxyCallable() const { MOZ_ASSERT(!isProxy()); - return isJSFunction() || call; + return isJSFunction() || getCall(); } bool isProxy() const { @@ -788,40 +856,89 @@ return flags & JSCLASS_IS_DOMJSCLASS; } - bool shouldDelayMetadataCallback() const { - return flags & JSCLASS_DELAY_METADATA_CALLBACK; + bool shouldDelayMetadataBuilder() const { + return flags & JSCLASS_DELAY_METADATA_BUILDER; + } + + bool isWrappedNative() const { + return flags & JSCLASS_IS_WRAPPED_NATIVE; } static size_t offsetOfFlags() { return offsetof(Class, flags); } + + bool specDefined() const { return spec ? spec->defined() : false; } + JSProtoKey specInheritanceProtoKey() + const { return spec ? spec->inheritanceProtoKey() : JSProto_Null; } + bool specShouldDefineConstructor() + const { return spec ? spec->shouldDefineConstructor() : true; } + ClassObjectCreationOp specCreateConstructorHook() + const { return spec ? spec->createConstructorHook() : nullptr; } + ClassObjectCreationOp specCreatePrototypeHook() + const { return spec ? spec->createPrototypeHook() : nullptr; } + const JSFunctionSpec* specConstructorFunctions() + const { return spec ? spec->constructorFunctions() : nullptr; } + const JSPropertySpec* specConstructorProperties() + const { return spec ? spec->constructorProperties() : nullptr; } + const JSFunctionSpec* specPrototypeFunctions() + const { return spec ? spec->prototypeFunctions() : nullptr; } + const JSPropertySpec* specPrototypeProperties() + const { return spec ? spec->prototypeProperties() : nullptr; } + FinishClassInitOp specFinishInitHook() + const { return spec ? spec->finishInitHook() : nullptr; } + + JSWeakmapKeyDelegateOp extWeakmapKeyDelegateOp() + const { return ext ? ext->weakmapKeyDelegateOp : nullptr; } + JSObjectMovedOp extObjectMovedOp() + const { return ext ? ext->objectMovedOp : nullptr; } + + LookupPropertyOp getOpsLookupProperty() const { return oOps ? oOps->lookupProperty : nullptr; } + DefinePropertyOp getOpsDefineProperty() const { return oOps ? oOps->defineProperty : nullptr; } + HasPropertyOp getOpsHasProperty() const { return oOps ? oOps->hasProperty : nullptr; } + GetPropertyOp getOpsGetProperty() const { return oOps ? oOps->getProperty : nullptr; } + SetPropertyOp getOpsSetProperty() const { return oOps ? oOps->setProperty : nullptr; } + GetOwnPropertyOp getOpsGetOwnPropertyDescriptor() + const { return oOps ? oOps->getOwnPropertyDescriptor + : nullptr; } + DeletePropertyOp getOpsDeleteProperty() const { return oOps ? oOps->deleteProperty : nullptr; } + WatchOp getOpsWatch() const { return oOps ? oOps->watch : nullptr; } + UnwatchOp getOpsUnwatch() const { return oOps ? oOps->unwatch : nullptr; } + GetElementsOp getOpsGetElements() const { return oOps ? oOps->getElements : nullptr; } + JSNewEnumerateOp getOpsEnumerate() const { return oOps ? oOps->enumerate : nullptr; } + JSFunToStringOp getOpsFunToString() const { return oOps ? oOps->funToString : nullptr; } }; +static_assert(offsetof(JSClassOps, addProperty) == offsetof(ClassOps, addProperty), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, delProperty) == offsetof(ClassOps, delProperty), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, getProperty) == offsetof(ClassOps, getProperty), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, setProperty) == offsetof(ClassOps, setProperty), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, enumerate) == offsetof(ClassOps, enumerate), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, resolve) == offsetof(ClassOps, resolve), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, mayResolve) == offsetof(ClassOps, mayResolve), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, finalize) == offsetof(ClassOps, finalize), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, call) == offsetof(ClassOps, call), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, construct) == offsetof(ClassOps, construct), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, hasInstance) == offsetof(ClassOps, hasInstance), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, trace) == offsetof(ClassOps, trace), + "ClassOps and JSClassOps must be consistent"); +static_assert(sizeof(JSClassOps) == sizeof(ClassOps), + "ClassOps and JSClassOps must be consistent"); + static_assert(offsetof(JSClass, name) == offsetof(Class, name), "Class and JSClass must be consistent"); static_assert(offsetof(JSClass, flags) == offsetof(Class, flags), "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, addProperty) == offsetof(Class, addProperty), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, delProperty) == offsetof(Class, delProperty), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, getProperty) == offsetof(Class, getProperty), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, setProperty) == offsetof(Class, setProperty), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, enumerate) == offsetof(Class, enumerate), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, resolve) == offsetof(Class, resolve), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, mayResolve) == offsetof(Class, mayResolve), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, finalize) == offsetof(Class, finalize), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, call) == offsetof(Class, call), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, construct) == offsetof(Class, construct), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, hasInstance) == offsetof(Class, hasInstance), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, trace) == offsetof(Class, trace), +static_assert(offsetof(JSClass, cOps) == offsetof(Class, cOps), "Class and JSClass must be consistent"); static_assert(sizeof(JSClass) == sizeof(Class), "Class and JSClass must be consistent"); @@ -842,17 +959,30 @@ * Enumeration describing possible values of the [[Class]] internal property * value of objects. */ -enum ESClassValue { - ESClass_Object, ESClass_Array, ESClass_Number, ESClass_String, - ESClass_Boolean, ESClass_RegExp, ESClass_ArrayBuffer, ESClass_SharedArrayBuffer, - ESClass_Date, ESClass_Set, ESClass_Map, +enum class ESClass { + Object, + Array, + Number, + String, + Boolean, + RegExp, + ArrayBuffer, + SharedArrayBuffer, + Date, + Set, + Map, + Promise, + MapIterator, + SetIterator, + Arguments, + Error, /** None of the above. */ - ESClass_Other + Other }; /* Fills |vp| with the unboxed value for boxed types, or undefined otherwise. */ -inline bool +bool Unbox(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp); #ifdef DEBUG 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 @@ -30,12 +30,16 @@ /* DO NOT CALL THIS. Use JS::ToNumber. */ extern JS_PUBLIC_API(bool) -ToNumberSlow(JSContext* cx, JS::Value v, double* dp); +ToNumberSlow(JSContext* cx, JS::HandleValue v, double* dp); /* DO NOT CALL THIS. Use JS::ToInt8. */ extern JS_PUBLIC_API(bool) ToInt8Slow(JSContext *cx, JS::HandleValue v, int8_t *out); +/* DO NOT CALL THIS. Use JS::ToUint8. */ +extern JS_PUBLIC_API(bool) +ToUint8Slow(JSContext *cx, JS::HandleValue v, uint8_t *out); + /* DO NOT CALL THIS. Use JS::ToInt16. */ extern JS_PUBLIC_API(bool) ToInt16Slow(JSContext *cx, JS::HandleValue v, int16_t *out); @@ -215,6 +219,19 @@ return js::ToInt8Slow(cx, v, out); } +/* ES6 ECMA-262, 7.1.10 */ +MOZ_ALWAYS_INLINE bool +ToUint8(JSContext *cx, JS::HandleValue v, uint8_t *out) +{ + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = uint8_t(v.toInt32()); + return true; + } + return js::ToUint8Slow(cx, v, out); +} + /* * Non-standard, with behavior similar to that of ToInt32, except in its * producing an int64_t. @@ -383,9 +400,9 @@ inline int32_t ToInt32(double d) { - // clang crashes compiling this when targeting arm-darwin: + // clang crashes compiling this when targeting arm: // https://llvm.org/bugs/show_bug.cgi?id=22974 -#if defined (__arm__) && defined (__GNUC__) && !defined(__APPLE__) +#if defined (__arm__) && defined (__GNUC__) && !defined(__clang__) int32_t i; uint32_t tmp0; uint32_t tmp1; @@ -525,6 +542,13 @@ return detail::ToIntWidth(d); } +/* ECMA-262 7.1.10 ToUInt8() specialized for doubles. */ +inline int8_t +ToUint8(double d) +{ + return detail::ToUintWidth(d); +} + /* WEBIDL 4.2.6 */ inline int16_t ToInt16(double d) @@ -532,6 +556,12 @@ return detail::ToIntWidth(d); } +inline uint16_t +ToUint16(double d) +{ + return detail::ToUintWidth(d); +} + /* WEBIDL 4.2.10 */ inline int64_t ToInt64(double d) 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 @@ -149,6 +149,22 @@ JS_PUBLIC_API(double) DayFromTime(double time); +// Takes an integer year and returns the number of days from epoch to the given +// year. +// NOTE: The calculation performed by this function is literally that given in +// the ECMAScript specification. Nonfinite years, years containing fractional +// components, and years outside ECMAScript's date range are not handled with +// any particular intelligence. Garbage in, garbage out. +JS_PUBLIC_API(double) +DayFromYear(double year); + +// Takes an integer number of milliseconds since the epoch and an integer year, +// returns the number of days in that year. If |time| is nonfinite, returns NaN. +// Otherwise |time| *must* correspond to a time within the valid year |year|. +// This should usually be ensured by computing |year| as |JS::DayFromYear(time)|. +JS_PUBLIC_API(double) +DayWithinYear(double time, double year); + } // namespace JS #endif /* js_Date_h */ 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 @@ -12,7 +12,6 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/MemoryReporting.h" -#include "mozilla/UniquePtr.h" #include "jsapi.h" #include "jspubtd.h" @@ -26,9 +25,6 @@ } // namespace js namespace JS { - -using mozilla::UniquePtr; - namespace dbg { // Helping embedding code build objects for Debugger @@ -154,7 +150,7 @@ // A rooted reference to our value. PersistentRooted value; - BuiltThing(JSContext* cx, Builder& owner_, T value_ = js::GCMethods::initial()) + BuiltThing(JSContext* cx, Builder& owner_, T value_ = GCPolicy::initial()) : owner(owner_), value(cx, value_) { owner.assertBuilt(value_); @@ -261,15 +257,15 @@ // and returns the number of bytes allocated to that block. SpiderMonkey itself // doesn't know which function is appropriate to use, but the embedding does. -// Tell Debuggers in |runtime| to use |mallocSizeOf| to find the size of +// Tell Debuggers in |cx| to use |mallocSizeOf| to find the size of // malloc'd blocks. JS_PUBLIC_API(void) -SetDebuggerMallocSizeOf(JSRuntime* runtime, mozilla::MallocSizeOf mallocSizeOf); +SetDebuggerMallocSizeOf(JSContext* cx, mozilla::MallocSizeOf mallocSizeOf); -// Get the MallocSizeOf function that the given runtime is using to find the +// Get the MallocSizeOf function that the given context is using to find the // size of malloc'd blocks. JS_PUBLIC_API(mozilla::MallocSizeOf) -GetDebuggerMallocSizeOf(JSRuntime* runtime); +GetDebuggerMallocSizeOf(JSContext* cx); @@ -344,7 +340,7 @@ // call the appropriate |Entry| member function to indicate where we've begun // execution. -class MOZ_STACK_CLASS AutoEntryMonitor { +class MOZ_STACK_CLASS JS_PUBLIC_API(AutoEntryMonitor) { JSRuntime* runtime_; AutoEntryMonitor* savedMonitor_; @@ -355,20 +351,25 @@ // SpiderMonkey reports the JavaScript entry points occuring within this // AutoEntryMonitor's scope to the following member functions, which the // embedding is expected to override. + // + // It is important to note that |asyncCause| is owned by the caller and its + // lifetime must outlive the lifetime of the AutoEntryMonitor object. It is + // strongly encouraged that |asyncCause| be a string constant or similar + // statically allocated string. // We have begun executing |function|. Note that |function| may not be the // actual closure we are running, but only the canonical function object to // which the script refers. virtual void Entry(JSContext* cx, JSFunction* function, HandleValue asyncStack, - HandleString asyncCause) = 0; + const char* asyncCause) = 0; // Execution has begun at the entry point of |script|, which is not a // function body. (This is probably being executed by 'eval' or some // JSAPI equivalent.) virtual void Entry(JSContext* cx, JSScript* script, HandleValue asyncStack, - HandleString asyncCause) = 0; + const char* asyncCause) = 0; // Execution of the function or script has ended. virtual void Exit(JSContext* cx) { } 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 @@ -7,10 +7,11 @@ #ifndef js_GCAPI_h #define js_GCAPI_h -#include "mozilla/UniquePtr.h" #include "mozilla/Vector.h" +#include "js/GCAnnotations.h" #include "js/HeapAPI.h" +#include "js/UniquePtr.h" namespace js { namespace gc { @@ -25,12 +26,12 @@ /** Perform only global GCs. */ JSGC_MODE_GLOBAL = 0, - /** Perform per-compartment GCs until too much garbage has accumulated. */ - JSGC_MODE_COMPARTMENT = 1, + /** 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_COMPARTMENT. + * JSGC_MODE_ZONE. */ JSGC_MODE_INCREMENTAL = 2 } JSGCMode; @@ -48,14 +49,12 @@ namespace JS { -using mozilla::UniquePtr; - #define GCREASONS(D) \ /* Reasons internal to the JS engine */ \ D(API) \ D(EAGER_ALLOC_TRIGGER) \ D(DESTROY_RUNTIME) \ - D(DESTROY_CONTEXT) \ + D(UNUSED0) \ D(LAST_DITCH) \ D(TOO_MUCH_MALLOC) \ D(ALLOC_TRIGGER) \ @@ -66,7 +65,7 @@ D(EVICT_NURSERY) \ D(FULL_STORE_BUFFER) \ D(SHARED_MEMORY_LIMIT) \ - D(PERIODIC_FULL_GC) \ + D(UNUSED1) \ D(INCREMENTAL_TOO_SLOW) \ D(ABORT_GC) \ \ @@ -130,6 +129,12 @@ NUM_TELEMETRY_REASONS = 100 }; +/** + * Get a statically allocated C string explaining the given GC reason. + */ +extern JS_PUBLIC_API(const char*) +ExplainReason(JS::gcreason::Reason reason); + } /* namespace gcreason */ /* @@ -156,7 +161,7 @@ * Schedule all zones to be collected in the next GC. */ extern JS_PUBLIC_API(void) -PrepareForFullGC(JSRuntime* rt); +PrepareForFullGC(JSContext* cx); /** * When performing an incremental GC, the zones that were selected for the @@ -164,14 +169,14 @@ * This function selects those slices automatically. */ extern JS_PUBLIC_API(void) -PrepareForIncrementalGC(JSRuntime* rt); +PrepareForIncrementalGC(JSContext* cx); /** * Returns true if any zone in the system has been scheduled for GC with one of * the functions above or by the JS engine. */ extern JS_PUBLIC_API(bool) -IsGCScheduled(JSRuntime* rt); +IsGCScheduled(JSContext* cx); /** * Undoes the effect of the Prepare methods above. The given zone will not be @@ -196,7 +201,7 @@ * the system. */ extern JS_PUBLIC_API(void) -GCForReason(JSRuntime* rt, JSGCInvocationKind gckind, gcreason::Reason reason); +GCForReason(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason); /* * Incremental GC: @@ -222,43 +227,43 @@ * Begin an incremental collection and perform one slice worth of work. When * this function returns, the collection may not be complete. * IncrementalGCSlice() must be called repeatedly until - * !IsIncrementalGCInProgress(rt). + * !IsIncrementalGCInProgress(cx). * * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or * shorter than the requested interval. */ extern JS_PUBLIC_API(void) -StartIncrementalGC(JSRuntime* rt, JSGCInvocationKind gckind, gcreason::Reason reason, +StartIncrementalGC(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason, int64_t millis = 0); /** * Perform a slice of an ongoing incremental collection. When this function * returns, the collection may not be complete. It must be called repeatedly - * until !IsIncrementalGCInProgress(rt). + * until !IsIncrementalGCInProgress(cx). * * 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(JSRuntime* rt, gcreason::Reason reason, int64_t millis = 0); +IncrementalGCSlice(JSContext* cx, gcreason::Reason reason, int64_t millis = 0); /** - * If IsIncrementalGCInProgress(rt), this call finishes the ongoing collection - * by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(rt), + * 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, - * IsIncrementalGCInProgress(rt) will always be false. + * IsIncrementalGCInProgress(cx) will always be false. */ extern JS_PUBLIC_API(void) -FinishIncrementalGC(JSRuntime* rt, gcreason::Reason reason); +FinishIncrementalGC(JSContext* cx, gcreason::Reason reason); /** - * If IsIncrementalGCInProgress(rt), this call aborts the ongoing collection and + * If IsIncrementalGCInProgress(cx), this call aborts the ongoing collection and * performs whatever work needs to be done to return the collector to its idle * state. This may take an arbitrarily long time. When this function returns, - * IsIncrementalGCInProgress(rt) will always be false. + * IsIncrementalGCInProgress(cx) will always be false. */ extern JS_PUBLIC_API(void) -AbortIncrementalGC(JSRuntime* rt); +AbortIncrementalGC(JSContext* cx); namespace dbg { @@ -300,7 +305,7 @@ , collections() { } - using Ptr = UniquePtr>; + using Ptr = js::UniquePtr; static Ptr Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t majorGCNumber); JSObject* toJSObject(JSContext* cx) const; @@ -328,22 +333,22 @@ }; struct JS_PUBLIC_API(GCDescription) { - bool isCompartment_; + bool isZone_; JSGCInvocationKind invocationKind_; gcreason::Reason reason_; - GCDescription(bool isCompartment, JSGCInvocationKind kind, gcreason::Reason reason) - : isCompartment_(isCompartment), invocationKind_(kind), reason_(reason) {} + GCDescription(bool isZone, JSGCInvocationKind kind, gcreason::Reason reason) + : isZone_(isZone), invocationKind_(kind), reason_(reason) {} - char16_t* formatSliceMessage(JSRuntime* rt) const; - char16_t* formatSummaryMessage(JSRuntime* rt) const; - char16_t* formatJSON(JSRuntime* rt, uint64_t timestamp) const; + char16_t* formatSliceMessage(JSContext* cx) const; + char16_t* formatSummaryMessage(JSContext* cx) const; + char16_t* formatJSON(JSContext* cx, uint64_t timestamp) const; - JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSRuntime* rt) const; + JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSContext* cx) const; }; typedef void -(* GCSliceCallback)(JSRuntime* rt, GCProgress progress, const GCDescription& desc); +(* GCSliceCallback)(JSContext* cx, GCProgress progress, const GCDescription& desc); /** * The GC slice callback is called at the beginning and end of each slice. This @@ -351,7 +356,45 @@ * marking. */ extern JS_PUBLIC_API(GCSliceCallback) -SetGCSliceCallback(JSRuntime* rt, GCSliceCallback callback); +SetGCSliceCallback(JSContext* cx, GCSliceCallback callback); + +/** + * Describes the progress of an observed nursery collection. + */ +enum class GCNurseryProgress { + /** + * The nursery collection is starting. + */ + GC_NURSERY_COLLECTION_START, + /** + * The nursery collection is ending. + */ + GC_NURSERY_COLLECTION_END +}; + +/** + * A nursery collection callback receives the progress of the nursery collection + * and the reason for the collection. + */ +using GCNurseryCollectionCallback = void(*)(JSContext* cx, GCNurseryProgress progress, + gcreason::Reason reason); + +/** + * Set the nursery collection callback for the given runtime. When set, it will + * be called at the start and end of every nursery collection. + */ +extern JS_PUBLIC_API(GCNurseryCollectionCallback) +SetGCNurseryCollectionCallback(JSContext* cx, GCNurseryCollectionCallback callback); + +typedef void +(* DoCycleCollectionCallback)(JSContext* cx); + +/** + * The purge gray callback is called after any COMPARTMENT_REVIVED GC in which + * the majority of compartments have been marked gray. + */ +extern JS_PUBLIC_API(DoCycleCollectionCallback) +SetDoCycleCollectionCallback(JSContext* cx, DoCycleCollectionCallback callback); /** * Incremental GC defaults to enabled, but may be disabled for testing or in @@ -360,7 +403,7 @@ * disabled on the runtime. */ extern JS_PUBLIC_API(void) -DisableIncrementalGC(JSRuntime* rt); +DisableIncrementalGC(JSContext* cx); /** * Returns true if incremental GC is enabled. Simply having incremental GC @@ -371,14 +414,14 @@ * collections are not happening incrementally when expected. */ extern JS_PUBLIC_API(bool) -IsIncrementalGCEnabled(JSRuntime* rt); +IsIncrementalGCEnabled(JSContext* cx); /** * Returns true while an incremental GC is ongoing, both when actively * collecting and between slices. */ extern JS_PUBLIC_API(bool) -IsIncrementalGCInProgress(JSRuntime* rt); +IsIncrementalGCInProgress(JSContext* cx); /* * Returns true when writes to GC things must call an incremental (pre) barrier. @@ -386,9 +429,6 @@ * At other times, the barrier may be elided for performance. */ extern JS_PUBLIC_API(bool) -IsIncrementalBarrierNeeded(JSRuntime* rt); - -extern JS_PUBLIC_API(bool) IsIncrementalBarrierNeeded(JSContext* cx); /* @@ -408,7 +448,7 @@ * Returns true if the most recent GC ran incrementally. */ extern JS_PUBLIC_API(bool) -WasIncrementalGC(JSRuntime* rt); +WasIncrementalGC(JSContext* cx); /* * Generational GC: @@ -444,37 +484,35 @@ GetGCNumber(); /** - * The GC does not immediately return the unused memory freed by a collection - * back to the system incase it is needed soon afterwards. This call forces the - * GC to return this memory immediately. - */ -extern JS_PUBLIC_API(void) -ShrinkGCBuffers(JSRuntime* rt); + * 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. + */ +class JS_PUBLIC_API(AutoRequireNoGC) +{ + protected: + AutoRequireNoGC() {} + ~AutoRequireNoGC() {} +}; /** - * Assert if a GC occurs while this class is live. This class does not disable - * the static rooting hazard analysis. + * Diagnostic assert (see MOZ_DIAGNOSTIC_ASSERT) that GC cannot occur while this + * class is live. This class does not disable the static rooting hazard + * analysis. + * + * This works by entering a GC unsafe region, which is checked on allocation and + * on GC. */ -class JS_PUBLIC_API(AutoAssertOnGC) +class JS_PUBLIC_API(AutoAssertNoGC) : public AutoRequireNoGC { -#ifdef DEBUG js::gc::GCRuntime* gc; size_t gcNumber; public: - AutoAssertOnGC(); - explicit AutoAssertOnGC(JSRuntime* rt); - ~AutoAssertOnGC(); - - static void VerifyIsSafeToGC(JSRuntime* rt); -#else - public: - AutoAssertOnGC() {} - explicit AutoAssertOnGC(JSRuntime* rt) {} - ~AutoAssertOnGC() {} - - static void VerifyIsSafeToGC(JSRuntime* rt) {} -#endif + AutoAssertNoGC(); + explicit AutoAssertNoGC(JSRuntime* rt); + explicit AutoAssertNoGC(JSContext* cx); + ~AutoAssertNoGC(); }; /** @@ -488,18 +526,32 @@ public: AutoAssertNoAlloc() : gc(nullptr) {} - explicit AutoAssertNoAlloc(JSRuntime* rt); + explicit AutoAssertNoAlloc(JSContext* cx); void disallowAlloc(JSRuntime* rt); ~AutoAssertNoAlloc(); #else public: AutoAssertNoAlloc() {} - explicit AutoAssertNoAlloc(JSRuntime* rt) {} + explicit AutoAssertNoAlloc(JSContext* cx) {} void disallowAlloc(JSRuntime* rt) {} #endif }; /** + * Assert if a GC barrier is invoked while this class is live. This class does + * not disable the static rooting hazard analysis. + */ +class JS_PUBLIC_API(AutoAssertOnBarrier) +{ + JSContext* context; + bool prev; + + public: + explicit AutoAssertOnBarrier(JSContext* cx); + ~AutoAssertOnBarrier(); +}; + +/** * Disable the static rooting hazard analysis in the live region and assert if * any allocation that could potentially trigger a GC occurs while this guard * object is live. This is most useful to help the exact rooting hazard analysis @@ -517,8 +569,8 @@ { public: AutoSuppressGCAnalysis() : AutoAssertNoAlloc() {} - explicit AutoSuppressGCAnalysis(JSRuntime* rt) : AutoAssertNoAlloc(rt) {} -}; + explicit AutoSuppressGCAnalysis(JSContext* cx) : AutoAssertNoAlloc(cx) {} +} JS_HAZ_GC_SUPPRESSED; /** * Assert that code is only ever called from a GC callback, disable the static @@ -536,24 +588,36 @@ /** * Place AutoCheckCannotGC in scopes that you believe can never GC. These - * annotations will be verified both dynamically via AutoAssertOnGC, and + * annotations will be verified both dynamically via AutoAssertNoGC, and * statically with the rooting hazard analysis (implemented by making the * analysis consider AutoCheckCannotGC to be a GC pointer, and therefore * complain if it is live across a GC call.) It is useful when dealing with * internal pointers to GC things where the GC thing itself may not be present * for the static analysis: e.g. acquiring inline chars from a JSString* on the * heap. + * + * We only do the assertion checking in DEBUG builds. */ -class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertOnGC +#ifdef DEBUG +class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertNoGC { public: - AutoCheckCannotGC() : AutoAssertOnGC() {} - explicit AutoCheckCannotGC(JSRuntime* rt) : AutoAssertOnGC(rt) {} -}; + AutoCheckCannotGC() : AutoAssertNoGC() {} + explicit AutoCheckCannotGC(JSContext* cx) : AutoAssertNoGC(cx) {} +} JS_HAZ_GC_INVALIDATED; +#else +class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoRequireNoGC +{ + public: + AutoCheckCannotGC() {} + explicit AutoCheckCannotGC(JSContext* cx) {} +} JS_HAZ_GC_INVALIDATED; +#endif /** * Unsets the gray bit for anything reachable from |thing|. |kind| should not be - * JS::TraceKind::Shape. |thing| should be non-null. + * JS::TraceKind::Shape. |thing| should be non-null. The return value indicates + * if anything was unmarked. */ extern JS_FRIEND_API(bool) UnmarkGrayGCThingRecursively(GCCellPtr thing); @@ -566,31 +630,42 @@ static MOZ_ALWAYS_INLINE void ExposeGCThingToActiveJS(JS::GCCellPtr thing) { - MOZ_ASSERT(thing.kind() != JS::TraceKind::Shape); - - /* - * 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. - */ + // 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; - JS::shadow::Runtime* rt = detail::GetGCThingRuntime(thing.unsafeAsUIntPtr()); + + // There's nothing to do for permanent GC things that might be owned by + // another runtime. + if (thing.mayBeOwnedByOtherRuntime()) + return; + + JS::shadow::Runtime* rt = detail::GetCellRuntime(thing.asCell()); + MOZ_DIAGNOSTIC_ASSERT(rt->allowGCBarriers()); + if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing)) JS::IncrementalReferenceBarrier(thing); - else if (JS::GCThingIsMarkedGray(thing)) + else if (!thing.mayBeOwnedByOtherRuntime() && js::gc::detail::CellIsMarkedGray(thing.asCell())) JS::UnmarkGrayGCThingRecursively(thing); } static MOZ_ALWAYS_INLINE void MarkGCThingAsLive(JSRuntime* aRt, JS::GCCellPtr thing) { - JS::shadow::Runtime* rt = JS::shadow::Runtime::asShadowRuntime(aRt); - /* - * Any object in the nursery will not be freed during any GC running at that time. - */ + // Any object in the nursery will not be freed during any GC running at that + // time. 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; + + JS::shadow::Runtime* rt = JS::shadow::Runtime::asShadowRuntime(aRt); + MOZ_DIAGNOSTIC_ASSERT(rt->allowGCBarriers()); + if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing)) JS::IncrementalReferenceBarrier(thing); } @@ -609,6 +684,7 @@ static MOZ_ALWAYS_INLINE void ExposeObjectToActiveJS(JSObject* obj) { + MOZ_ASSERT(obj); js::gc::ExposeGCThingToActiveJS(GCCellPtr(obj)); } @@ -634,13 +710,13 @@ * Note: this is not related to the PokeGC in nsJSEnvironment. */ extern JS_FRIEND_API(void) -PokeGC(JSRuntime* rt); +PokeGC(JSContext* cx); /* * Internal to Firefox. */ extern JS_FRIEND_API(void) -NotifyDidPaint(JSRuntime* rt); +NotifyDidPaint(JSContext* cx); } /* namespace JS */ 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 @@ -0,0 +1,57 @@ +/* -*- 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_GCAnnotations_h +#define js_GCAnnotations_h + +// Set of annotations for the rooting hazard analysis, used to categorize types +// and functions. +#ifdef XGILL_PLUGIN + +// Mark a type as being a GC thing (eg js::gc::Cell has this annotation). +# define JS_HAZ_GC_THING __attribute__((tag("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"))) + +// 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"))) + +// 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"))) + +// 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 +// same in the analysis as a rooted pointer, except it will not be reported as +// an unnecessary root if used across a GC call. This should rarely be used, +// 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"))) + +// Mark a function as something that runs a garbage collection, potentially +// invalidating GC pointers. +# define JS_HAZ_GC_CALL __attribute__((tag("GC Call"))) + +// Mark an RAII class as suppressing GC within its scope. +# define JS_HAZ_GC_SUPPRESSED __attribute__((tag("Suppress GC"))) + +#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 + +#endif + +#endif /* js_GCAnnotations_h */ 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 @@ -7,54 +7,54 @@ #ifndef GCHashTable_h #define GCHashTable_h +#include "js/GCPolicyAPI.h" #include "js/HashTable.h" #include "js/RootingAPI.h" +#include "js/SweepingAPI.h" #include "js/TracingAPI.h" -namespace js { +namespace JS { // Define a reasonable default GC policy for GC-aware Maps. template -struct DefaultMapGCPolicy { - using KeyPolicy = DefaultGCPolicy; - using ValuePolicy = DefaultGCPolicy; - +struct DefaultMapSweepPolicy { static bool needsSweep(Key* key, Value* value) { - return KeyPolicy::needsSweep(key) || ValuePolicy::needsSweep(value); + return GCPolicy::needsSweep(key) || GCPolicy::needsSweep(value); } }; // A GCHashMap is a GC-aware HashMap, meaning that it has additional trace and // sweep methods that know how to visit all keys and values in the table. // HashMaps that contain GC pointers will generally want to use this GCHashMap -// specialization in lieu of HashMap, either because those pointers must be -// traced to be kept alive -- in which case, KeyPolicy and/or ValuePolicy -// should do the appropriate tracing -- or because those pointers are weak and -// must be swept during a GC -- in which case needsSweep should be set -// appropriately. +// specialization instead of HashMap, because this conveniently supports tracing +// keys and values, and cleaning up weak entries. // -// Most types of GC pointers as keys and values can be traced with no extra -// infrastructure. For structs, the DefaultGCPolicy will call a trace() -// method on the struct. For other structs and non-gc-pointer members, ensure -// that there is a specialization of DefaultGCPolicy with an appropriate -// trace() static method available to handle the custom type. Generic helpers -// can be found in js/public/TracingAPI.h. +// GCHashMap::trace applies GCPolicy::trace to each entry's key and value. +// Most types of GC pointers already have appropriate specializations of +// GCPolicy, so they should just work as keys and values. Any struct type with a +// default constructor and trace and sweep functions should work as well. If you +// need to define your own GCPolicy specialization, generic helpers can be found +// in js/public/TracingAPI.h. // -// Note that this HashMap only knows *how* to trace and sweep (and the tracing -// can handle keys that move), but it does not itself cause tracing or sweeping -// to be invoked. For tracing, it must be used with Rooted or PersistentRooted, -// or barriered and traced manually. For sweeping, currently it requires an -// explicit call to .sweep(). +// The MapSweepPolicy template parameter controls how the table drops entries +// when swept. GCHashMap::sweep applies MapSweepPolicy::needsSweep to each table +// entry; if it returns true, the entry is dropped. The default MapSweepPolicy +// drops the entry if either the key or value is about to be finalized, +// according to its GCPolicy::needsSweep method. (This default is almost +// always fine: it's hard to imagine keeping such an entry around anyway.) // +// Note that this HashMap only knows *how* to trace and sweep, but it does not +// itself cause tracing or sweeping to be invoked. For tracing, it must be used +// with Rooted or PersistentRooted, or barriered and traced manually. For +// sweeping, currently it requires an explicit call to .sweep(). template , - typename AllocPolicy = TempAllocPolicy, - typename GCPolicy = DefaultMapGCPolicy> -class GCHashMap : public HashMap, - public JS::Traceable + typename HashPolicy = js::DefaultHasher, + typename AllocPolicy = js::TempAllocPolicy, + typename MapSweepPolicy = DefaultMapSweepPolicy> +class GCHashMap : public js::HashMap { - using Base = HashMap; + using Base = js::HashMap; public: explicit GCHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {} @@ -64,8 +64,8 @@ if (!this->initialized()) return; for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { - GCPolicy::ValuePolicy::trace(trc, &e.front().value(), "hashmap value"); - GCPolicy::KeyPolicy::trace(trc, &e.front().mutableKey(), "hashmap key"); + GCPolicy::trace(trc, &e.front().value(), "hashmap value"); + GCPolicy::trace(trc, &e.front().mutableKey(), "hashmap key"); } } @@ -74,16 +74,16 @@ return; for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { - if (GCPolicy::needsSweep(&e.front().mutableKey(), &e.front().value())) + if (MapSweepPolicy::needsSweep(&e.front().mutableKey(), &e.front().value())) e.removeFront(); } } // GCHashMap is movable - GCHashMap(GCHashMap&& rhs) : Base(mozilla::Forward(rhs)) {} + GCHashMap(GCHashMap&& rhs) : Base(mozilla::Move(rhs)) {} void operator=(GCHashMap&& rhs) { MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - Base::operator=(mozilla::Forward(rhs)); + Base::operator=(mozilla::Move(rhs)); } private: @@ -92,19 +92,61 @@ GCHashMap& operator=(const GCHashMap& hm) = delete; }; +} // namespace JS + +namespace js { + +// HashMap that supports rekeying. +// +// If your keys are pointers to something like JSObject that can be tenured or +// compacted, prefer to use GCHashMap with MovableCellHasher, which takes +// advantage of the Zone's stable id table to make rekeying unnecessary. +template , + typename AllocPolicy = TempAllocPolicy, + typename MapSweepPolicy = JS::DefaultMapSweepPolicy> +class GCRekeyableHashMap : public JS::GCHashMap +{ + using Base = JS::GCHashMap; + + public: + explicit GCRekeyableHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {} + + 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())) + e.removeFront(); + else if (!HashPolicy::match(key, e.front().key())) + e.rekeyFront(key); + } + } + + // GCRekeyableHashMap is movable + GCRekeyableHashMap(GCRekeyableHashMap&& rhs) : Base(mozilla::Move(rhs)) {} + void operator=(GCRekeyableHashMap&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); + Base::operator=(mozilla::Move(rhs)); + } +}; + template class GCHashMapOperations { - using Map = GCHashMap; + using Map = JS::GCHashMap; using Lookup = typename Map::Lookup; - using Ptr = typename Map::Ptr; - using AddPtr = typename Map::AddPtr; - using Range = typename Map::Range; - using Enum = typename Map::Enum; const Map& map() const { return static_cast(this)->get(); } public: + using AddPtr = typename Map::AddPtr; + 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); } @@ -113,22 +155,29 @@ uint32_t count() const { return map().count(); } size_t capacity() const { return map().capacity(); } bool has(const Lookup& l) const { return map().lookup(l).found(); } + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return map().sizeOfExcludingThis(mallocSizeOf); + } + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return mallocSizeOf(this) + map().sizeOfExcludingThis(mallocSizeOf); + } }; template class MutableGCHashMapOperations : public GCHashMapOperations { - using Map = GCHashMap; + using Map = JS::GCHashMap; using Lookup = typename Map::Lookup; - using Ptr = typename Map::Ptr; - using AddPtr = typename Map::AddPtr; - using Range = typename Map::Range; - using Enum = typename Map::Enum; Map& map() { return static_cast(this)->get(); } public: + using AddPtr = typename Map::AddPtr; + struct Enum : public Map::Enum { explicit Enum(Outer& o) : Map::Enum(o.map()) {} }; + 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(); } @@ -163,41 +212,48 @@ }; template -class RootedBase> - : public MutableGCHashMapOperations>, A,B,C,D,E> +class RootedBase> + : public MutableGCHashMapOperations>, A,B,C,D,E> +{}; + +template +class MutableHandleBase> + : public MutableGCHashMapOperations>, A,B,C,D,E> {}; template -class MutableHandleBase> - : public MutableGCHashMapOperations>, A,B,C,D,E> +class HandleBase> + : public GCHashMapOperations>, A,B,C,D,E> {}; template -class HandleBase> - : public GCHashMapOperations>, A,B,C,D,E> +class WeakCacheBase> + : public MutableGCHashMapOperations>, A,B,C,D,E> {}; +} // namespace js + +namespace JS { + // A GCHashSet is a HashSet with an additional trace method that knows // be traced to be kept alive will generally want to use this GCHashSet -// specializeation in lieu of HashSet. +// specialization in lieu of HashSet. // // Most types of GC pointers can be traced with no extra infrastructure. For // structs and non-gc-pointer members, ensure that there is a specialization of -// DefaultGCPolicy with an appropriate trace method available to handle the -// custom type. Generic helpers can be found in js/public/TracingAPI.h. +// GCPolicy with an appropriate trace method available to handle the custom +// type. Generic helpers can be found in js/public/TracingAPI.h. // // Note that although this HashSet's trace will deal correctly with moved // elements, it does not itself know when to barrier or trace elements. To // function properly it must either be used with Rooted or barriered and traced // manually. template , - typename AllocPolicy = TempAllocPolicy, - typename GCPolicy = DefaultGCPolicy> -class GCHashSet : public HashSet, - public JS::Traceable + typename HashPolicy = js::DefaultHasher, + typename AllocPolicy = js::TempAllocPolicy> +class GCHashSet : public js::HashSet { - using Base = HashSet; + using Base = js::HashSet; public: explicit GCHashSet(AllocPolicy a = AllocPolicy()) : Base(a) {} @@ -207,23 +263,23 @@ if (!this->initialized()) return; for (typename Base::Enum e(*this); !e.empty(); e.popFront()) - GCPolicy::trace(trc, &e.mutableFront(), "hashset element"); + GCPolicy::trace(trc, &e.mutableFront(), "hashset element"); } void sweep() { if (!this->initialized()) return; for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { - if (GCPolicy::needsSweep(&e.mutableFront())) + if (GCPolicy::needsSweep(&e.mutableFront())) e.removeFront(); } } // GCHashSet is movable - GCHashSet(GCHashSet&& rhs) : Base(mozilla::Forward(rhs)) {} + GCHashSet(GCHashSet&& rhs) : Base(mozilla::Move(rhs)) {} void operator=(GCHashSet&& rhs) { MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - Base::operator=(mozilla::Forward(rhs)); + Base::operator=(mozilla::Move(rhs)); } private: @@ -232,19 +288,24 @@ GCHashSet& operator=(const GCHashSet& hs) = delete; }; +} // namespace JS + +namespace js { + template class GCHashSetOperations { - using Set = GCHashSet; + using Set = JS::GCHashSet; using Lookup = typename Set::Lookup; - using Ptr = typename Set::Ptr; - using AddPtr = typename Set::AddPtr; - using Range = typename Set::Range; - using Enum = typename Set::Enum; - const Set& set() const { return static_cast(this)->extract(); } + const Set& set() const { return static_cast(this)->get(); } public: + using AddPtr = typename Set::AddPtr; + using Entry = typename Set::Entry; + 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); } @@ -253,25 +314,34 @@ uint32_t count() const { return set().count(); } size_t capacity() const { return set().capacity(); } bool has(const Lookup& l) const { return set().lookup(l).found(); } + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return set().sizeOfExcludingThis(mallocSizeOf); + } + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return mallocSizeOf(this) + set().sizeOfExcludingThis(mallocSizeOf); + } }; template class MutableGCHashSetOperations : public GCHashSetOperations { - using Set = GCHashSet; + using Set = JS::GCHashSet; using Lookup = typename Set::Lookup; - using Ptr = typename Set::Ptr; - using AddPtr = typename Set::AddPtr; - using Range = typename Set::Range; - using Enum = typename Set::Enum; - Set& set() { return static_cast(this)->extract(); } + Set& set() { return static_cast(this)->get(); } public: + using AddPtr = typename Set::AddPtr; + using Entry = typename Set::Entry; + struct Enum : public Set::Enum { explicit Enum(Outer& o) : Set::Enum(o.set()) {} }; + 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 remove(Ptr p) { set().remove(p); } void remove(const Lookup& l) { set().remove(l); } template @@ -300,41 +370,28 @@ } }; -template -class RootedBase> - : public MutableGCHashSetOperations>, T, HP, AP, GP> +template +class RootedBase> + : public MutableGCHashSetOperations>, T, HP, AP> { - using Set = GCHashSet; - - friend class GCHashSetOperations, T, HP, AP, GP>; - const Set& extract() const { return *static_cast*>(this)->address(); } - - friend class MutableGCHashSetOperations, T, HP, AP, GP>; - Set& extract() { return *static_cast*>(this)->address(); } }; -template -class MutableHandleBase> - : public MutableGCHashSetOperations>, T, HP, AP, GP> +template +class MutableHandleBase> + : public MutableGCHashSetOperations>, T, HP, AP> { - using Set = GCHashSet; - - friend class GCHashSetOperations, T, HP, AP, GP>; - const Set& extract() const { - return *static_cast*>(this)->address(); - } +}; - friend class MutableGCHashSetOperations, T, HP, AP, GP>; - Set& extract() { return *static_cast*>(this)->address(); } +template +class HandleBase> + : public GCHashSetOperations>, T, HP, AP> +{ }; -template -class HandleBase> - : public GCHashSetOperations>, T, HP, AP, GP> +template +class WeakCacheBase> + : public MutableGCHashSetOperations>, T, HP, AP> { - using Set = GCHashSet; - friend class GCHashSetOperations, T, HP, AP, GP>; - const Set& extract() const { return *static_cast*>(this)->address(); } }; } /* 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 @@ -0,0 +1,164 @@ +/* -*- 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/. */ + +// GC Policy Mechanism + +// A GCPolicy controls how the GC interacts with both direct pointers to GC +// things (e.g. JSObject* or JSString*), tagged and/or optional pointers to GC +// things (e.g. Value or jsid), and C++ container types (e.g. +// JSPropertyDescriptor or GCHashMap). +// +// 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. +// +// static bool needsSweep(T* tp) +// - Return true if |*tp| is about to be finalized. Otherwise, update the +// edge for moving GC, and return false. Containers like GCHashMap and +// GCHashSet use this method to decide when to remove an entry: if this +// function returns true on a key/value/member/etc, its entry is dropped +// from the container. Specializing this method is the standard way to +// get custom weak behavior from a container type. +// +// 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 +// JS::Heap and mozilla::UniquePtr. +// +// There are some stock structs your specializations can inherit from. +// IgnoreGCPolicy does nothing. StructGCPolicy forwards the methods to the +// referent type T. + +#ifndef GCPolicyAPI_h +#define GCPolicyAPI_h + +#include "mozilla/UniquePtr.h" + +#include "js/TraceKind.h" +#include "js/TracingAPI.h" + +// Expand the given macro D for each public GC pointer. +#define FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \ + D(JS::Symbol*) \ + D(JSAtom*) \ + D(JSFunction*) \ + D(JSObject*) \ + D(JSScript*) \ + D(JSString*) + +// Expand the given macro D for each public tagged GC pointer type. +#define FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(D) \ + D(JS::Value) \ + D(jsid) + +#define FOR_EACH_PUBLIC_AGGREGATE_GC_POINTER_TYPE(D) \ + D(JSPropertyDescriptor) + +class JSAtom; +class JSFunction; +class JSObject; +class JSScript; +class JSString; +namespace JS { +class Symbol; +} + +namespace JS { + +// Defines a policy for container types with non-GC, i.e. C storage. This +// policy dispatches to the underlying struct for GC interactions. +template +struct StructGCPolicy +{ + static T initial() { + return T(); + } + + static void trace(JSTracer* trc, T* tp, const char* name) { + tp->trace(trc); + } + + static void sweep(T* tp) { + return tp->sweep(); + } + + static bool needsSweep(T* tp) { + return tp->needsSweep(); + } +}; + +// The default GC policy attempts to defer to methods on the underlying type. +// Most C++ structures that contain a default constructor, a trace function and +// a sweep function will work out of the box with Rooted, Handle, GCVector, +// and GCHash{Set,Map}. +template struct GCPolicy : public StructGCPolicy {}; + +// 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; } +}; +template <> struct GCPolicy : public IgnoreGCPolicy {}; +template <> struct GCPolicy : public IgnoreGCPolicy {}; + +template +struct GCPointerPolicy +{ + static T initial() { return nullptr; } + static void trace(JSTracer* trc, T* vp, const char* name) { + if (*vp) + js::UnsafeTraceManuallyBarrieredEdge(trc, vp, name); + } + static bool needsSweep(T* vp) { + if (*vp) + return js::gc::IsAboutToBeFinalizedUnbarriered(vp); + return false; + } +}; +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 {}; + +template +struct GCPolicy> +{ + static void trace(JSTracer* trc, JS::Heap* thingp, const char* name) { + TraceEdge(trc, thingp, name); + } + static bool needsSweep(JS::Heap* thingp) { + return js::gc::EdgeNeedsSweep(thingp); + } +}; + +// 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); + } + static bool needsSweep(mozilla::UniquePtr* tp) { + if (tp->get()) + return GCPolicy::needsSweep(tp->get()); + return false; + } +}; + +} // namespace JS + +#endif // GCPolicyAPI_h 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 @@ -0,0 +1,198 @@ +/* -*- 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_GCVariant_h +#define js_GCVariant_h + +#include "mozilla/Variant.h" + +#include "js/GCPolicyAPI.h" +#include "js/RootingAPI.h" +#include "js/TracingAPI.h" + +namespace JS { + +// These template specializations allow Variant to be used inside GC wrappers. +// +// When matching on GC wrappers around Variants, matching should be done on +// the wrapper itself. The matcher class's methods should take Handles or +// MutableHandles. For example, +// +// struct MyMatcher +// { +// using ReturnType = const char*; +// ReturnType match(HandleObject o) { return "object"; } +// ReturnType match(HandleScript s) { return "script"; } +// }; +// +// Rooted> v(cx, someScript); +// MyMatcher mm; +// v.match(mm); +// +// If you get compile errors about inability to upcast subclasses (e.g., from +// NativeObject* to JSObject*) and are inside js/src, be sure to also include +// "gc/Policy.h". + +namespace detail { + +template +struct GCVariantImplementation; + +// The base case. +template +struct GCVariantImplementation +{ + 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); + } + + template + static typename Matcher::ReturnType + match(Matcher& matcher, Handle v) { + const T& thing = v.get().template as(); + return matcher.match(Handle::fromMarkedLocation(&thing)); + } + + template + static typename Matcher::ReturnType + match(Matcher& matcher, MutableHandle v) { + T& thing = v.get().template as(); + return matcher.match(MutableHandle::fromMarkedLocation(&thing)); + } +}; + +// The inductive case. +template +struct GCVariantImplementation +{ + using Next = GCVariantImplementation; + + template + 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); + } else { + Next::trace(trc, v, name); + } + } + + template + static typename Matcher::ReturnType + match(Matcher& matcher, Handle v) { + if (v.get().template is()) { + const T& thing = v.get().template as(); + return matcher.match(Handle::fromMarkedLocation(&thing)); + } + return Next::match(matcher, v); + } + + template + static typename Matcher::ReturnType + match(Matcher& matcher, MutableHandle v) { + if (v.get().template is()) { + T& thing = v.get().template as(); + return matcher.match(MutableHandle::fromMarkedLocation(&thing)); + } + return Next::match(matcher, v); + } +}; + +} // namespace detail + +template +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); + } +}; + +} // namespace JS + +namespace js { + +template +class GCVariantOperations +{ + using Impl = JS::detail::GCVariantImplementation; + using Variant = mozilla::Variant; + + const Variant& variant() const { return static_cast(this)->get(); } + + public: + template + bool is() const { + return variant().template is(); + } + + template + JS::Handle as() const { + return Handle::fromMarkedLocation(&variant().template as()); + } + + template + typename Matcher::ReturnType + match(Matcher& matcher) const { + return Impl::match(matcher, JS::Handle::fromMarkedLocation(&variant())); + } +}; + +template +class MutableGCVariantOperations + : public GCVariantOperations +{ + using Impl = JS::detail::GCVariantImplementation; + using Variant = mozilla::Variant; + + const Variant& variant() const { return static_cast(this)->get(); } + Variant& variant() { return static_cast(this)->get(); } + + public: + template + JS::MutableHandle as() { + return JS::MutableHandle::fromMarkedLocation(&variant().template as()); + } + + template + typename Matcher::ReturnType + match(Matcher& matcher) { + return Impl::match(matcher, JS::MutableHandle::fromMarkedLocation(&variant())); + } +}; + +template +class RootedBase> + : public MutableGCVariantOperations>, Ts...> +{ }; + +template +class MutableHandleBase> + : public MutableGCVariantOperations>, Ts...> +{ }; + +template +class HandleBase> + : public GCVariantOperations>, Ts...> +{ }; + +template +class PersistentRootedBase> + : public MutableGCVariantOperations>, Ts...> +{ }; + +} // namespace js + +#endif // js_GCVariant_h 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 @@ -0,0 +1,249 @@ +/* -*- 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_GCVector_h +#define js_GCVector_h + +#include "mozilla/Vector.h" + +#include "js/GCPolicyAPI.h" +#include "js/RootingAPI.h" +#include "js/TracingAPI.h" +#include "js/Vector.h" + +namespace JS { + +// A GCVector is a Vector with an additional trace method that knows how +// to visit all of the items stored in the Vector. For vectors that contain GC +// things, this is usually more convenient than manually iterating and marking +// the contents. +// +// Most types of GC pointers as keys and values can be traced with no extra +// infrastructure. For structs and non-gc-pointer members, ensure that there is +// a specialization of GCPolicy with an appropriate trace method available +// to handle the custom type. Generic helpers can be found in +// js/public/TracingAPI.h. +// +// Note that although this Vector's trace will deal correctly with moved items, +// it does not itself know when to barrier or trace items. To function properly +// it must either be used with Rooted, or barriered and traced manually. +template +class GCVector +{ + mozilla::Vector vector; + + public: + explicit GCVector(AllocPolicy alloc = AllocPolicy()) + : vector(alloc) + {} + + GCVector(GCVector&& vec) + : vector(mozilla::Move(vec.vector)) + {} + + GCVector& operator=(GCVector&& vec) { + vector = mozilla::Move(vec.vector); + return *this; + } + + size_t length() const { return vector.length(); } + bool empty() const { return vector.empty(); } + size_t capacity() const { return vector.capacity(); } + + T* begin() { return vector.begin(); } + const T* begin() const { return vector.begin(); } + + T* end() { return vector.end(); } + const T* end() const { return vector.end(); } + + T& operator[](size_t i) { return vector[i]; } + const T& operator[](size_t i) const { return vector[i]; } + + T& back() { return vector.back(); } + const T& back() const { return vector.back(); } + + bool initCapacity(size_t cap) { return vector.initCapacity(cap); } + bool reserve(size_t req) { return vector.reserve(req); } + void shrinkBy(size_t amount) { return vector.shrinkBy(amount); } + bool growBy(size_t amount) { return vector.growBy(amount); } + bool resize(size_t newLen) { return vector.resize(newLen); } + + void clear() { return vector.clear(); } + + template bool append(U&& item) { return vector.append(mozilla::Forward(item)); } + + template + bool + emplaceBack(Args&&... args) { + return vector.emplaceBack(mozilla::Forward(args)...); + } + + template + void infallibleAppend(U&& aU) { + return vector.infallibleAppend(mozilla::Forward(aU)); + } + void infallibleAppendN(const T& aT, size_t aN) { + return vector.infallibleAppendN(aT, aN); + } + template void + infallibleAppend(const U* aBegin, const U* aEnd) { + return vector.infallibleAppend(aBegin, aEnd); + } + template void infallibleAppend(const U* aBegin, size_t aLength) { + return vector.infallibleAppend(aBegin, aLength); + } + + template + bool appendAll(const mozilla::Vector& aU) { return vector.appendAll(aU); } + template + bool appendAll(const GCVector& aU) { return vector.append(aU.begin(), aU.length()); } + + bool appendN(const T& val, size_t count) { return vector.appendN(val, count); } + + template bool append(const U* aBegin, const U* aEnd) { + return vector.append(aBegin, aEnd); + } + template bool append(const U* aBegin, size_t aLength) { + return vector.append(aBegin, aLength); + } + + void popBack() { return vector.popBack(); } + T popCopy() { return vector.popCopy(); } + + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return vector.sizeOfExcludingThis(mallocSizeOf); + } + + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return vector.sizeOfIncludingThis(mallocSizeOf); + } + + static void trace(GCVector* vec, JSTracer* trc) { vec->trace(trc); } + + void trace(JSTracer* trc) { + for (auto& elem : vector) + GCPolicy::trace(trc, &elem, "vector element"); + } +}; + +} // namespace JS + +namespace js { + +template +class GCVectorOperations +{ + using Vec = JS::GCVector; + const Vec& vec() const { return static_cast(this)->get(); } + + public: + const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); } + size_t length() const { return vec().length(); } + bool empty() const { return vec().empty(); } + size_t capacity() const { return vec().capacity(); } + const T* begin() const { return vec().begin(); } + const T* end() const { return vec().end(); } + const T& back() const { return vec().back(); } + + JS::Handle operator[](size_t aIndex) const { + return JS::Handle::fromMarkedLocation(&vec().operator[](aIndex)); + } +}; + +template +class MutableGCVectorOperations + : public GCVectorOperations +{ + using Vec = JS::GCVector; + const Vec& vec() const { return static_cast(this)->get(); } + Vec& vec() { return static_cast(this)->get(); } + + public: + const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); } + AllocPolicy& allocPolicy() { return vec().allocPolicy(); } + const T* begin() const { return vec().begin(); } + T* begin() { return vec().begin(); } + const T* end() const { return vec().end(); } + T* end() { return vec().end(); } + const T& back() const { return vec().back(); } + T& back() { return vec().back(); } + + JS::Handle operator[](size_t aIndex) const { + return JS::Handle::fromMarkedLocation(&vec().operator[](aIndex)); + } + JS::MutableHandle operator[](size_t aIndex) { + return JS::MutableHandle::fromMarkedLocation(&vec().operator[](aIndex)); + } + + bool initCapacity(size_t aRequest) { return vec().initCapacity(aRequest); } + bool reserve(size_t aRequest) { return vec().reserve(aRequest); } + void shrinkBy(size_t aIncr) { vec().shrinkBy(aIncr); } + bool growBy(size_t aIncr) { return vec().growBy(aIncr); } + bool resize(size_t aNewLength) { return vec().resize(aNewLength); } + bool growByUninitialized(size_t aIncr) { return vec().growByUninitialized(aIncr); } + void infallibleGrowByUninitialized(size_t aIncr) { vec().infallibleGrowByUninitialized(aIncr); } + bool resizeUninitialized(size_t aNewLength) { return vec().resizeUninitialized(aNewLength); } + void clear() { vec().clear(); } + void clearAndFree() { vec().clearAndFree(); } + template bool append(U&& aU) { return vec().append(mozilla::Forward(aU)); } + template bool emplaceBack(Args&&... aArgs) { + return vec().emplaceBack(mozilla::Forward(aArgs...)); + } + template + bool appendAll(const mozilla::Vector& aU) { return vec().appendAll(aU); } + template + bool appendAll(const JS::GCVector& aU) { return vec().appendAll(aU); } + bool appendN(const T& aT, size_t aN) { return vec().appendN(aT, aN); } + template bool append(const U* aBegin, const U* aEnd) { + return vec().append(aBegin, aEnd); + } + template bool append(const U* aBegin, size_t aLength) { + return vec().append(aBegin, aLength); + } + template void infallibleAppend(U&& aU) { + vec().infallibleAppend(mozilla::Forward(aU)); + } + void infallibleAppendN(const T& aT, size_t aN) { vec().infallibleAppendN(aT, aN); } + template void infallibleAppend(const U* aBegin, const U* aEnd) { + vec().infallibleAppend(aBegin, aEnd); + } + template void infallibleAppend(const U* aBegin, size_t aLength) { + vec().infallibleAppend(aBegin, aLength); + } + void popBack() { vec().popBack(); } + T popCopy() { return vec().popCopy(); } + template T* insert(T* aP, U&& aVal) { + return vec().insert(aP, mozilla::Forward(aVal)); + } + void erase(T* aT) { vec().erase(aT); } + void erase(T* aBegin, T* aEnd) { vec().erase(aBegin, aEnd); } +}; + +template +class RootedBase> + : public MutableGCVectorOperations>, T,N,AP> +{}; + +template +class MutableHandleBase> + : public MutableGCVectorOperations>, T,N,AP> +{}; + +template +class HandleBase> + : public GCVectorOperations>, T,N,AP> +{}; + +template +class PersistentRootedBase> + : public MutableGCVectorOperations>, T,N,AP> +{}; + +} // namespace js + +#endif // js_GCVector_h 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 @@ -11,6 +11,7 @@ #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" @@ -34,6 +35,16 @@ /*****************************************************************************/ +// 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 @@ -61,6 +72,7 @@ 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); } @@ -76,8 +88,8 @@ // 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) {} - bool init(uint32_t len = 16) { return impl.init(len); } - bool initialized() const { return impl.initialized(); } + 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.: // @@ -139,19 +151,19 @@ } template - bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { + MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { return impl.add(p, mozilla::Forward(k), mozilla::Forward(v)); } template - bool add(AddPtr& p, KeyInput&& k) { + MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k) { return impl.add(p, mozilla::Forward(k), Value()); } template - bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { + MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { return impl.relookupOrAdd(p, k, mozilla::Forward(k), mozilla::Forward(v)); @@ -208,8 +220,6 @@ return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); } - // If |generation()| is the same before and after a HashMap operation, - // pointers into the table remain valid. Generation generation() const { return impl.generation(); } @@ -222,7 +232,7 @@ // Overwrite existing value with v. Return false on oom. template - bool put(KeyInput&& k, ValueInput&& v) { + MOZ_MUST_USE bool put(KeyInput&& k, ValueInput&& v) { AddPtr p = lookupForAdd(k); if (p) { p->value() = mozilla::Forward(v); @@ -233,7 +243,7 @@ // Like put, but assert that the given key is not already present. template - bool putNew(KeyInput&& k, ValueInput&& v) { + MOZ_MUST_USE bool putNew(KeyInput&& k, ValueInput&& v) { return impl.putNew(k, mozilla::Forward(k), mozilla::Forward(v)); } @@ -248,7 +258,9 @@ AddPtr p = lookupForAdd(k); if (p) return p; - (void)add(p, k, defaultValue); // p is left false-y on oom. + bool ok = add(p, k, defaultValue); + MOZ_ASSERT_IF(!ok, !p); // p is left false-y on oom. + (void)ok; return p; } @@ -313,6 +325,7 @@ { 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); } @@ -328,8 +341,8 @@ // 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) {} - bool init(uint32_t len = 16) { return impl.init(len); } - bool initialized() const { return impl.initialized(); } + 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.: // @@ -386,12 +399,12 @@ AddPtr lookupForAdd(const Lookup& l) const { return impl.lookupForAdd(l); } template - bool add(AddPtr& p, U&& u) { + MOZ_MUST_USE bool add(AddPtr& p, U&& u) { return impl.add(p, mozilla::Forward(u)); } template - bool relookupOrAdd(AddPtr& p, const Lookup& l, U&& u) { + MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, U&& u) { return impl.relookupOrAdd(p, l, mozilla::Forward(u)); } @@ -446,8 +459,6 @@ return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); } - // If |generation()| is the same before and after a HashSet operation, - // pointers into the table remain valid. Generation generation() const { return impl.generation(); } @@ -460,19 +471,19 @@ // Add |u| if it is not present already. Return false on oom. template - bool put(U&& u) { + 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 - bool putNew(U&& u) { + MOZ_MUST_USE bool putNew(U&& u) { return impl.putNew(u, mozilla::Forward(u)); } template - bool putNew(const Lookup& l, U&& u) { + MOZ_MUST_USE bool putNew(const Lookup& l, U&& u) { return impl.putNew(l, mozilla::Forward(u)); } @@ -503,11 +514,16 @@ return false; } - // Infallibly rekey one entry with a new key that is equivalent. - void rekeyInPlace(Ptr p, const T& new_value) - { + // 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)); - impl.rekeyInPlace(p, new_value); + const_cast(*p) = new_value; } // HashSet is movable @@ -606,21 +622,21 @@ struct DefaultHasher : PointerHasher::value> {}; -// Specialize hashing policy for mozilla::UniquePtr to proxy the UniquePtr's +// Specialize hashing policy for mozilla::UniquePtr to proxy the UniquePtr's // raw pointer to PointerHasher. -template -struct DefaultHasher> +template +struct DefaultHasher> { - using Lookup = mozilla::UniquePtr; + using Lookup = mozilla::UniquePtr; using PtrHasher = PointerHasher::value>; static HashNumber hash(const Lookup& l) { return PtrHasher::hash(l.get()); } - static bool match(const mozilla::UniquePtr& k, const Lookup& l) { + 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) { + static void rekey(mozilla::UniquePtr& k, mozilla::UniquePtr&& newKey) { k = mozilla::Move(newKey); } }; @@ -655,6 +671,50 @@ } }; +// 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 @@ -684,6 +744,11 @@ 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; @@ -754,8 +819,16 @@ } 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); - mozilla::Swap(mem, other->mem); } T& get() { MOZ_ASSERT(isLive()); return *mem.addr(); } @@ -819,14 +892,21 @@ {} public: - // Leaves Ptr uninitialized. - Ptr() { + Ptr() + : entry_(nullptr) #ifdef JS_DEBUG - entry_ = (Entry*)0xbad; + , 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 @@ -851,6 +931,7 @@ T& operator*() const { #ifdef JS_DEBUG + MOZ_ASSERT(found()); MOZ_ASSERT(generation == table_->generation()); #endif return entry_->get(); @@ -858,6 +939,7 @@ T* operator->() const { #ifdef JS_DEBUG + MOZ_ASSERT(found()); MOZ_ASSERT(generation == table_->generation()); #endif return &entry_->get(); @@ -882,8 +964,7 @@ {} public: - // Leaves AddPtr uninitialized. - AddPtr() {} + AddPtr() : keyHash(0) {} }; // A collection of hash table entries. The collection is enumerated by @@ -1173,7 +1254,7 @@ #endif {} - MOZ_WARN_UNUSED_RESULT bool init(uint32_t length) + MOZ_MUST_USE bool init(uint32_t length) { MOZ_ASSERT(!initialized()); @@ -1543,6 +1624,33 @@ // 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() { @@ -1622,12 +1730,16 @@ 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); } Ptr readonlyThreadsafeLookup(const Lookup& l) const { + if (!HasHash(l)) + return Ptr(); HashNumber keyHash = prepareHash(l); return Ptr(lookup(l, keyHash, 0), *this); } @@ -1635,6 +1747,8 @@ AddPtr lookupForAdd(const Lookup& l) const { mozilla::ReentrancyGuard g(*this); + if (!EnsureHash(l)) + return AddPtr(); HashNumber keyHash = prepareHash(l); Entry& entry = lookup(l, keyHash, sCollisionBit); AddPtr p(entry, *this, keyHash); @@ -1642,13 +1756,17 @@ } template - bool add(AddPtr& p, Args&&... args) + MOZ_MUST_USE bool add(AddPtr& p, Args&&... args) { mozilla::ReentrancyGuard g(*this); MOZ_ASSERT(table); MOZ_ASSERT(!p.found()); MOZ_ASSERT(!(p.keyHash & sCollisionBit)); + // Check for error from ensureHash() here. + if (p.isValid()) + return false; + // Changing an entry from removed to live does not affect whether we // are overloaded and can be handled separately. if (p.entry_->isRemoved()) { @@ -1662,7 +1780,7 @@ RebuildStatus status = checkOverloaded(); if (status == RehashFailed) return false; - if (!this->checkSimulatedOOM()) + if (status == NotOverloaded && !this->checkSimulatedOOM()) return false; if (status == Rehashed) p.entry_ = &findFreeEntry(p.keyHash); @@ -1683,33 +1801,22 @@ template void putNewInfallible(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 + 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 - bool putNew(const Lookup& l, Args&&... args) + 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; @@ -1720,8 +1827,12 @@ // 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 - bool relookupOrAdd(AddPtr& p, const Lookup& l, Args&&... args) + 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; @@ -1751,7 +1862,7 @@ typename HashTableEntry::NonConstT t(mozilla::Move(*p)); HashPolicy::setKey(t, const_cast(k)); remove(*p.entry_); - putNewInfallible(l, mozilla::Move(t)); + putNewInfallibleInternal(l, mozilla::Move(t)); } void rekeyAndMaybeRehash(Ptr p, const Lookup& l, const Key& k) @@ -1760,14 +1871,6 @@ checkOverRemoved(); } - void rekeyInPlace(Ptr p, const Key& k) - { - MOZ_ASSERT(table); - mozilla::ReentrancyGuard g(*this); - MOZ_ASSERT(p.found()); - HashPolicy::rekey(const_cast(*p), const_cast(k)); - } - #undef METER }; 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 @@ -17,11 +17,6 @@ /* These values are private to the JS engine. */ namespace js { -// Whether the current thread is permitted access to any part of the specified -// runtime or zone. -JS_FRIEND_API(bool) -CurrentThreadCanAccessRuntime(JSRuntime* rt); - JS_FRIEND_API(bool) CurrentThreadCanAccessZone(JS::Zone* zone); @@ -56,7 +51,9 @@ const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*); const size_t ChunkTrailerSize = 2 * sizeof(uintptr_t) + sizeof(uint64_t); const size_t ChunkLocationOffset = ChunkSize - ChunkTrailerSize; -const size_t ArenaZoneOffset = 0; +const size_t ArenaZoneOffset = sizeof(size_t); +const size_t ArenaHeaderSize = sizeof(size_t) + 2 * sizeof(uintptr_t) + + sizeof(size_t) + sizeof(uintptr_t); /* * Live objects are marked black. How many other additional colors are available @@ -67,19 +64,15 @@ static const uint32_t GRAY = 1; /* - * The "location" field in the Chunk trailer is a bit vector indicting various - * roles of the chunk. - * - * The value 0 for the "location" field is invalid, at least one bit must be - * set. - * - * Some bits preclude others, for example, any "nursery" bit precludes any - * "tenured" or "middle generation" bit. + * The "location" field in the Chunk trailer is a enum indicating various roles + * of the chunk. */ -const uintptr_t ChunkLocationBitNursery = 1; // Standard GGC nursery -const uintptr_t ChunkLocationBitTenuredHeap = 2; // Standard GGC tenured generation - -const uintptr_t ChunkLocationAnyNursery = ChunkLocationBitNursery; +enum class ChunkLocation : uint32_t +{ + Invalid = 0, + Nursery = 1, + TenuredHeap = 2 +}; #ifdef JS_DEBUG /* When downcasting, ensure we are actually the right type. */ @@ -113,13 +106,20 @@ JSTracer* const barrierTracer_; // A pointer to the JSRuntime's |gcMarker|. public: + // Stack GC roots for Rooted GC pointers. + js::RootedListHeads stackRoots_; + template friend class JS::Rooted; + bool needsIncrementalBarrier_; Zone(JSRuntime* runtime, JSTracer* barrierTracerArg) : runtime_(runtime), barrierTracer_(barrierTracerArg), needsIncrementalBarrier_(false) - {} + { + for (auto& stackRootPtr : stackRoots_) + stackRootPtr = nullptr; + } bool needsIncrementalBarrier() const { return needsIncrementalBarrier_; @@ -142,7 +142,7 @@ return runtime_; } - static JS::shadow::Zone* asShadowZone(JS::Zone* zone) { + static MOZ_ALWAYS_INLINE JS::shadow::Zone* asShadowZone(JS::Zone* zone) { return reinterpret_cast(zone); } }; @@ -280,14 +280,6 @@ return reinterpret_cast(bmap_addr); } -static MOZ_ALWAYS_INLINE JS::shadow::Runtime* -GetGCThingRuntime(const uintptr_t addr) -{ - MOZ_ASSERT(addr); - const uintptr_t rt_addr = (addr & ~ChunkMask) | ChunkRuntimeOffset; - return *reinterpret_cast(rt_addr); -} - static MOZ_ALWAYS_INLINE void GetGCThingMarkWordAndMask(const uintptr_t addr, uint32_t color, uintptr_t** wordp, uintptr_t* maskp) @@ -310,16 +302,30 @@ } +static MOZ_ALWAYS_INLINE JS::shadow::Runtime* +GetCellRuntime(const Cell* cell) +{ + MOZ_ASSERT(cell); + const uintptr_t addr = uintptr_t(cell); + const uintptr_t rt_addr = (addr & ~ChunkMask) | ChunkRuntimeOffset; + return *reinterpret_cast(rt_addr); +} + static MOZ_ALWAYS_INLINE bool CellIsMarkedGray(const Cell* cell) { MOZ_ASSERT(cell); - MOZ_ASSERT(!js::gc::IsInsideNursery(cell)); + if (js::gc::IsInsideNursery(cell)) + return false; + uintptr_t* word, mask; js::gc::detail::GetGCThingMarkWordAndMask(uintptr_t(cell), js::gc::GRAY, &word, &mask); return *word & mask; } +extern JS_PUBLIC_API(bool) +CellIsMarkedGrayIfKnown(const Cell* cell); + } /* namespace detail */ MOZ_ALWAYS_INLINE bool @@ -330,9 +336,9 @@ uintptr_t addr = uintptr_t(cell); addr &= ~js::gc::ChunkMask; addr |= js::gc::ChunkLocationOffset; - uint32_t location = *reinterpret_cast(addr); - MOZ_ASSERT(location != 0); - return location & ChunkLocationAnyNursery; + auto location = *reinterpret_cast(addr); + MOZ_ASSERT(location == ChunkLocation::Nursery || location == ChunkLocation::TenuredHeap); + return location == ChunkLocation::Nursery; } } /* namespace gc */ @@ -357,40 +363,16 @@ GetObjectZone(JSObject* obj); static MOZ_ALWAYS_INLINE bool -ObjectIsTenured(JSObject* obj) -{ - return !js::gc::IsInsideNursery(reinterpret_cast(obj)); -} - -static MOZ_ALWAYS_INLINE bool -ObjectIsMarkedGray(JSObject* obj) -{ - /* - * 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 (js::gc::IsInsideNursery(reinterpret_cast(obj))) - return false; - return js::gc::detail::CellIsMarkedGray(reinterpret_cast(obj)); -} - -static MOZ_ALWAYS_INLINE bool -ScriptIsMarkedGray(JSScript* script) -{ - return js::gc::detail::CellIsMarkedGray(reinterpret_cast(script)); -} - -static MOZ_ALWAYS_INLINE bool GCThingIsMarkedGray(GCCellPtr thing) { - if (js::gc::IsInsideNursery(thing.asCell())) - return false; if (thing.mayBeOwnedByOtherRuntime()) return false; - return js::gc::detail::CellIsMarkedGray(thing.asCell()); + return js::gc::detail::CellIsMarkedGrayIfKnown(thing.asCell()); } +extern JS_PUBLIC_API(JS::TraceKind) +GCThingTraceKind(void* thing); + } /* namespace JS */ namespace js { @@ -401,8 +383,11 @@ { MOZ_ASSERT(thing); MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell())); - if (rt->isHeapBusy()) - return false; + + // TODO: I'd like to assert !isHeapBusy() here but this gets called while we + // are tracing the heap, e.g. during memory reporting (see bug 1313318). + MOZ_ASSERT(!rt->isHeapCollecting()); + JS::Zone* zone = JS::GetTenuredGCThingZone(thing); return JS::shadow::Zone::asShadowZone(zone)->needsIncrementalBarrier(); } 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 @@ -30,9 +30,9 @@ struct jsid { size_t asBits; - bool operator==(jsid rhs) const { return asBits == rhs.asBits; } - bool operator!=(jsid rhs) const { return asBits != rhs.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) #define JSID_TYPE_STRING 0x0 @@ -69,12 +69,6 @@ INTERNED_STRING_TO_JSID(JSContext* cx, JSString* str); static MOZ_ALWAYS_INLINE bool -JSID_IS_ZERO(jsid id) -{ - return JSID_BITS(id) == 0; -} - -static MOZ_ALWAYS_INLINE bool JSID_IS_INT(jsid id) { return !!(JSID_BITS(id) & JSID_TYPE_INT); @@ -166,20 +160,36 @@ extern JS_PUBLIC_DATA(const JS::HandleId) JSID_VOIDHANDLE; extern JS_PUBLIC_DATA(const JS::HandleId) JSID_EMPTYHANDLE; -namespace js { +namespace JS { template <> -struct GCMethods +struct GCPolicy { static jsid initial() { return JSID_VOID; } + static void trace(JSTracer* trc, jsid* idp, const char* name) { + js::UnsafeTraceManuallyBarrieredEdge(trc, idp, name); + } +}; + +} // namespace JS + +namespace js { + +template <> +struct BarrierMethods +{ static void postBarrier(jsid* idp, jsid prev, jsid next) {} + static void exposeToJS(jsid 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, jsid& id, Args&&... args) +DispatchTyped(F f, const jsid& id, Args&&... args) -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) { if (JSID_IS_STRING(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 @@ -25,6 +25,9 @@ extern JS_PUBLIC_DATA(InitState) libraryInitState; +extern JS_PUBLIC_API(const char*) +InitWithFailureDiagnostic(bool isDebugBuild); + } // namespace detail } // namespace JS @@ -58,8 +61,46 @@ * is, calling JS_Init/JSAPI methods/JS_ShutDown in that order, then doing so * again). This restriction may eventually be lifted. */ -extern JS_PUBLIC_API(bool) -JS_Init(void); +inline bool +JS_Init(void) +{ +#ifdef DEBUG + return !JS::detail::InitWithFailureDiagnostic(true); +#else + return !JS::detail::InitWithFailureDiagnostic(false); +#endif +} + +/** + * A variant of JS_Init. On success it returns nullptr. On failure it returns a + * pointer to a string literal that describes how initialization failed, which + * can be useful for debugging purposes. + */ +inline const char* +JS_InitWithFailureDiagnostic(void) +{ +#ifdef DEBUG + return JS::detail::InitWithFailureDiagnostic(true); +#else + return JS::detail::InitWithFailureDiagnostic(false); +#endif +} + +/* + * Returns true if SpiderMonkey has been initialized successfully, even if it has + * possibly been shut down. + * + * Note that it is the responsibility of the embedder to call JS_Init() and + * JS_ShutDown() at the correct times, and therefore this API should ideally not + * be necessary to use. This is only intended to be used in cases where the + * embedder isn't in full control of deciding whether to initialize SpiderMonkey + * or hand off the task to another consumer. + */ +inline bool +JS_IsInitialized(void) +{ + return JS::detail::libraryInitState != JS::detail::InitState::Uninitialized; +} /** * Destroy free-standing resources allocated by SpiderMonkey, not associated 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 @@ -166,23 +166,17 @@ #define FOR_EACH_SIZE(macro) \ macro(Objects, GCHeapUsed, objectsGCHeap) \ macro(Objects, MallocHeap, objectsMallocHeapSlots) \ - macro(Objects, MallocHeap, objectsMallocHeapElementsNonAsmJS) \ + macro(Objects, MallocHeap, objectsMallocHeapElementsNormal) \ macro(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \ - macro(Objects, NonHeap, objectsNonHeapElementsAsmJS) \ - macro(Objects, NonHeap, objectsNonHeapElementsMapped) \ - macro(Objects, NonHeap, objectsNonHeapCodeAsmJS) \ macro(Objects, MallocHeap, objectsMallocHeapMisc) \ - \ - macro(Other, GCHeapUsed, shapesGCHeapTree) \ - macro(Other, GCHeapUsed, shapesGCHeapDict) \ - macro(Other, GCHeapUsed, shapesGCHeapBase) \ - macro(Other, MallocHeap, shapesMallocHeapTreeTables) \ - macro(Other, MallocHeap, shapesMallocHeapDictTables) \ - macro(Other, MallocHeap, shapesMallocHeapTreeKids) + macro(Objects, NonHeap, objectsNonHeapElementsNormal) \ + macro(Objects, NonHeap, objectsNonHeapElementsShared) \ + macro(Objects, NonHeap, objectsNonHeapElementsWasm) \ + macro(Objects, NonHeap, objectsNonHeapCodeWasm) ClassInfo() : FOR_EACH_SIZE(ZERO_SIZE) - dummy() + wasmGuardPages(0) {} void add(const ClassInfo& other) { @@ -219,6 +213,55 @@ } FOR_EACH_SIZE(DECL_SIZE) + size_t wasmGuardPages; + +#undef FOR_EACH_SIZE +}; + +struct ShapeInfo +{ +#define FOR_EACH_SIZE(macro) \ + macro(Other, GCHeapUsed, shapesGCHeapTree) \ + macro(Other, GCHeapUsed, shapesGCHeapDict) \ + macro(Other, GCHeapUsed, shapesGCHeapBase) \ + macro(Other, MallocHeap, shapesMallocHeapTreeTables) \ + macro(Other, MallocHeap, shapesMallocHeapDictTables) \ + macro(Other, MallocHeap, shapesMallocHeapTreeKids) + + ShapeInfo() + : FOR_EACH_SIZE(ZERO_SIZE) + dummy() + {} + + void add(const ShapeInfo& other) { + FOR_EACH_SIZE(ADD_OTHER_SIZE) + } + + void subtract(const ShapeInfo& other) { + FOR_EACH_SIZE(SUB_OTHER_SIZE) + } + + size_t sizeOfAllThings() const { + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N) + return n; + } + + size_t sizeOfLiveGCThings() const { + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) + return n; + } + + void addToTabSizes(TabSizes* sizes) const { + FOR_EACH_SIZE(ADD_TO_TAB_SIZES) + } + + void addToServoSizes(ServoSizes *sizes) const { + FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) + } + + FOR_EACH_SIZE(DECL_SIZE) int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE) #undef FOR_EACH_SIZE @@ -282,7 +325,6 @@ #define FOR_EACH_SIZE(macro) \ macro(_, MallocHeap, marker) \ macro(_, NonHeap, nurseryCommitted) \ - macro(_, NonHeap, nurseryDecommitted) \ macro(_, MallocHeap, nurseryMallocedBuffers) \ macro(_, MallocHeap, storeBufferVals) \ macro(_, MallocHeap, storeBufferCells) \ @@ -396,8 +438,6 @@ struct ScriptSourceInfo { #define FOR_EACH_SIZE(macro) \ - macro(_, MallocHeap, compressed) \ - macro(_, MallocHeap, uncompressed) \ macro(_, MallocHeap, misc) ScriptSourceInfo() @@ -468,12 +508,12 @@ macro(_, MallocHeap, object) \ macro(_, MallocHeap, atomsTable) \ macro(_, MallocHeap, contexts) \ - macro(_, MallocHeap, dtoa) \ macro(_, MallocHeap, temporary) \ macro(_, MallocHeap, interpreterStack) \ macro(_, MallocHeap, mathCache) \ + macro(_, MallocHeap, sharedImmutableStringsCache) \ + macro(_, MallocHeap, sharedIntlData) \ macro(_, MallocHeap, uncompressedSourceCache) \ - macro(_, MallocHeap, compressedSourceSet) \ macro(_, MallocHeap, scriptData) RuntimeSizes() @@ -537,6 +577,7 @@ macro(Other, GCHeapUnused, string) \ macro(Other, GCHeapUnused, symbol) \ macro(Other, GCHeapUnused, jitcode) \ + macro(Other, GCHeapUnused, scope) UnusedGCThingSizes() : FOR_EACH_SIZE(ZERO_SIZE) @@ -559,6 +600,7 @@ case JS::TraceKind::JitCode: jitcode += n; break; case JS::TraceKind::LazyScript: lazyScript += n; break; case JS::TraceKind::ObjectGroup: objectGroup += n; break; + case JS::TraceKind::Scope: scope += n; break; default: MOZ_CRASH("Bad trace kind for UnusedGCThingSizes"); } @@ -598,14 +640,18 @@ macro(Other, GCHeapUsed, jitCodesGCHeap) \ macro(Other, GCHeapUsed, objectGroupsGCHeap) \ macro(Other, MallocHeap, objectGroupsMallocHeap) \ + macro(Other, GCHeapUsed, scopesGCHeap) \ + macro(Other, MallocHeap, scopesMallocHeap) \ macro(Other, MallocHeap, typePool) \ macro(Other, MallocHeap, baselineStubsOptimized) \ - macro(Other, MallocHeap, uniqueIdMap) + macro(Other, MallocHeap, uniqueIdMap) \ + macro(Other, MallocHeap, shapeTables) ZoneStats() : FOR_EACH_SIZE(ZERO_SIZE) unusedGCThings(), stringInfo(), + shapeInfo(), extra(), allStrings(nullptr), notableStrings(), @@ -616,6 +662,7 @@ : FOR_EACH_SIZE(COPY_OTHER_SIZE) unusedGCThings(mozilla::Move(other.unusedGCThings)), stringInfo(mozilla::Move(other.stringInfo)), + shapeInfo(mozilla::Move(other.shapeInfo)), extra(other.extra), allStrings(other.allStrings), notableStrings(mozilla::Move(other.notableStrings)), @@ -639,6 +686,7 @@ FOR_EACH_SIZE(ADD_OTHER_SIZE) unusedGCThings.addSizes(other.unusedGCThings); stringInfo.add(other.stringInfo); + shapeInfo.add(other.shapeInfo); } size_t sizeOfLiveGCThings() const { @@ -646,6 +694,7 @@ size_t n = 0; FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) n += stringInfo.sizeOfLiveGCThings(); + n += shapeInfo.sizeOfLiveGCThings(); return n; } @@ -654,6 +703,7 @@ FOR_EACH_SIZE(ADD_TO_TAB_SIZES) unusedGCThings.addToTabSizes(sizes); stringInfo.addToTabSizes(sizes); + shapeInfo.addToTabSizes(sizes); } void addToServoSizes(JS::ServoSizes *sizes) const { @@ -661,6 +711,7 @@ FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) unusedGCThings.addToServoSizes(sizes); stringInfo.addToServoSizes(sizes); + shapeInfo.addToServoSizes(sizes); } // These string measurements are initially for all strings. At the end, @@ -670,6 +721,7 @@ FOR_EACH_SIZE(DECL_SIZE) UnusedGCThingSizes unusedGCThings; StringInfo stringInfo; + ShapeInfo shapeInfo; void* extra; // This field can be used by embedders. typedef js::HashMap storage_; - js::AsmJSProfilingFrameIterator& asmJSIter() { + js::wasm::ProfilingFrameIterator& wasmIter() { MOZ_ASSERT(!done()); - MOZ_ASSERT(isAsmJS()); - return *reinterpret_cast(storage_.addr()); + MOZ_ASSERT(isWasm()); + return *reinterpret_cast(storage_.addr()); } - const js::AsmJSProfilingFrameIterator& asmJSIter() const { + const js::wasm::ProfilingFrameIterator& wasmIter() const { MOZ_ASSERT(!done()); - MOZ_ASSERT(isAsmJS()); - return *reinterpret_cast(storage_.addr()); + MOZ_ASSERT(isWasm()); + return *reinterpret_cast(storage_.addr()); } js::jit::JitProfilingFrameIterator& jitIter() { @@ -87,7 +97,7 @@ void* lr; }; - ProfilingFrameIterator(JSRuntime* rt, const RegisterState& state, + ProfilingFrameIterator(JSContext* cx, const RegisterState& state, uint32_t sampleBufferGen = UINT32_MAX); ~ProfilingFrameIterator(); void operator++(); @@ -104,7 +114,7 @@ { Frame_Baseline, Frame_Ion, - Frame_AsmJS + Frame_Wasm }; struct Frame @@ -113,10 +123,10 @@ void* stackAddress; void* returnAddress; void* activation; - const char* label; + UniqueChars label; }; - bool isAsmJS() const; + bool isWasm() const; bool isJit() const; uint32_t extractStack(Frame* frames, uint32_t offset, uint32_t end) const; @@ -133,7 +143,7 @@ }; JS_FRIEND_API(bool) -IsProfilingEnabledForRuntime(JSRuntime* runtime); +IsProfilingEnabledForContext(JSContext* cx); /** * After each sample run, this method should be called with the latest sample @@ -144,7 +154,7 @@ * JSRuntime for documentation about what these values are used for. */ JS_FRIEND_API(void) -UpdateJSRuntimeProfilerSampleBufferGen(JSRuntime* runtime, uint32_t generation, +UpdateJSContextProfilerSampleBufferGen(JSContext* cx, uint32_t generation, uint32_t lapCount); struct ForEachProfiledFrameOp @@ -153,7 +163,7 @@ // lookups on JitcodeGlobalTable. class MOZ_STACK_CLASS FrameHandle { - friend JS_PUBLIC_API(void) ForEachProfiledFrame(JSRuntime* rt, void* addr, + friend JS_PUBLIC_API(void) ForEachProfiledFrame(JSContext* cx, void* addr, ForEachProfiledFrameOp& op); JSRuntime* rt_; @@ -175,10 +185,13 @@ bool hasTrackedOptimizations() const { return optsIndex_.isSome(); } void* canonicalAddress() const { return canonicalAddr_; } - ProfilingFrameIterator::FrameKind frameKind() const; - void forEachOptimizationAttempt(ForEachTrackedOptimizationAttemptOp& op, - JSScript** scriptOut, jsbytecode** pcOut) const; - void forEachOptimizationTypeInfo(ForEachTrackedOptimizationTypeInfoOp& op) const; + JS_PUBLIC_API(ProfilingFrameIterator::FrameKind) frameKind() const; + JS_PUBLIC_API(void) forEachOptimizationAttempt(ForEachTrackedOptimizationAttemptOp& op, + JSScript** scriptOut, + jsbytecode** pcOut) const; + + JS_PUBLIC_API(void) + forEachOptimizationTypeInfo(ForEachTrackedOptimizationTypeInfoOp& op) const; }; // Called once per frame. @@ -186,7 +199,7 @@ }; JS_PUBLIC_API(void) -ForEachProfiledFrame(JSRuntime* rt, void* addr, ForEachProfiledFrameOp& op); +ForEachProfiledFrame(JSContext* cx, void* addr, ForEachProfiledFrameOp& op); } // namespace JS 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 @@ -14,6 +14,7 @@ #include "js/Utility.h" struct JSRuntime; +class JSTracer; namespace js { @@ -42,14 +43,14 @@ void * volatile spOrScript; // Line number for non-JS entries, the bytecode offset otherwise. - int32_t volatile lineOrPc; + int32_t volatile lineOrPcOffset; // General purpose storage describing this frame. uint32_t volatile flags_; public: // These traits are bit masks. Make sure they're powers of 2. - enum Flags { + enum Flags : uint32_t { // Indicate whether a profile entry represents a CPP frame. If not set, // a JS frame is assumed by default. You're not allowed to publicly // change the frame type. Instead, initialize the ProfileEntry as either @@ -75,7 +76,7 @@ CATEGORY_MASK = ~ALL }; - // Keep these in sync with devtools/client/performance/modules/global.js + // Keep these in sync with devtools/client/performance/modules/categories.js enum class Category : uint32_t { OTHER = 0x10, CSS = 0x20, @@ -115,7 +116,7 @@ void initCppFrame(void* aSp, uint32_t aLine) volatile { flags_ = IS_CPP_ENTRY; spOrScript = aSp; - lineOrPc = static_cast(aLine); + lineOrPcOffset = static_cast(aLine); } void setFlag(uint32_t flag) volatile { @@ -160,19 +161,24 @@ MOZ_ASSERT(!isJs()); return spOrScript; } - JSScript* script() const volatile { - MOZ_ASSERT(isJs()); - return (JSScript*)spOrScript; - } + JS_PUBLIC_API(JSScript*) script() const volatile; uint32_t line() const volatile { MOZ_ASSERT(!isJs()); - return static_cast(lineOrPc); + return static_cast(lineOrPcOffset); + } + + // Note that the pointer returned might be invalid. + JSScript* rawScript() const volatile { + MOZ_ASSERT(isJs()); + return (JSScript*)spOrScript; } // We can't know the layout of JSScript, so look in vm/SPSProfiler.cpp. JS_FRIEND_API(jsbytecode*) pc() const volatile; JS_FRIEND_API(void) setPC(jsbytecode* pc) volatile; + void trace(JSTracer* trc); + // The offset of a pc into a script's code can actually be 0, so to // signify a nullptr pc, use a -1 index. This is checked against in // pc() and setPC() to set/get the right pc. @@ -180,22 +186,22 @@ static size_t offsetOfLabel() { return offsetof(ProfileEntry, string); } static size_t offsetOfSpOrScript() { return offsetof(ProfileEntry, spOrScript); } - static size_t offsetOfLineOrPc() { return offsetof(ProfileEntry, lineOrPc); } + static size_t offsetOfLineOrPcOffset() { return offsetof(ProfileEntry, lineOrPcOffset); } static size_t offsetOfFlags() { return offsetof(ProfileEntry, flags_); } }; JS_FRIEND_API(void) -SetRuntimeProfilingStack(JSRuntime* rt, ProfileEntry* stack, uint32_t* size, +SetContextProfilingStack(JSContext* cx, ProfileEntry* stack, uint32_t* size, uint32_t max); JS_FRIEND_API(void) -EnableRuntimeProfilingStack(JSRuntime* rt, bool enabled); +EnableContextProfilingStack(JSContext* cx, bool enabled); JS_FRIEND_API(void) -RegisterRuntimeProfilingEventMarker(JSRuntime* rt, void (*fn)(const char*)); +RegisterContextProfilingEventMarker(JSContext* cx, void (*fn)(const char*)); JS_FRIEND_API(jsbytecode*) -ProfilingGetPC(JSRuntime* rt, JSScript* script, void* ip); +ProfilingGetPC(JSContext* cx, JSScript* script, void* ip); } // namespace js Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Proxy.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Proxy.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Proxy.h @@ -29,6 +29,7 @@ using JS::NativeImpl; using JS::ObjectOpResult; using JS::PrivateValue; +using JS::PropertyDescriptor; using JS::Value; class RegExpGuard; @@ -58,16 +59,15 @@ * * ### Proxies and internal methods * - * ES6 draft rev 27 (24 August 2014) specifies 14 internal methods. The runtime - * semantics of just about everything a script can do to an object is specified - * in terms of these internal methods. For example: + * ES2016 specifies 13 internal methods. The runtime semantics of just + * about everything a script can do to an object is specified in terms + * of these internal methods. For example: * * JS code ES6 internal method that gets called * --------------------------- -------------------------------- * obj.prop obj.[[Get]](obj, "prop") * "prop" in obj obj.[[HasProperty]]("prop") * new obj() obj.[[Construct]]() - * for (k in obj) {} obj.[[Enumerate]]() * * With regard to the implementation of these internal methods, there are three * very different kinds of object in SpiderMonkey. @@ -101,10 +101,8 @@ * * BaseProxyHandler * | - * DirectProxyHandler // has a target - * | - * Wrapper // can be unwrapped, revealing target - * | // (see js::CheckedUnwrap) + * Wrapper // has a target, can be unwrapped to reveal + * | // target (see js::CheckedUnwrap) * | * CrossCompartmentWrapper // target is in another compartment; * // implements membrane between compartments @@ -191,7 +189,7 @@ bool mHasSecurityPolicy; public: - explicit MOZ_CONSTEXPR BaseProxyHandler(const void* aFamily, bool aHasPrototype = false, + explicit constexpr BaseProxyHandler(const void* aFamily, bool aHasPrototype = false, bool aHasSecurityPolicy = false) : mFamily(aFamily), mHasPrototype(aHasPrototype), @@ -213,7 +211,7 @@ return offsetof(BaseProxyHandler, mFamily); } - virtual bool finalizeInBackground(Value priv) const { + virtual bool finalizeInBackground(const Value& priv) const { /* * Called on creation of a proxy to determine whether its finalize * method can be finalized on the background thread. @@ -221,6 +219,14 @@ return true; } + virtual bool canNurseryAllocate() const { + /* + * Nursery allocation is allowed if and only if it is safe to not + * run |finalize| when the ProxyObject dies. + */ + return false; + } + /* Policy enforcement methods. * * enter() allows the policy to specify whether the caller may perform |act| @@ -251,9 +257,9 @@ /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const = 0; + MutableHandle desc) const = 0; virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const = 0; virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const = 0; @@ -261,14 +267,6 @@ ObjectOpResult& result) const = 0; /* - * Because [[Enumerate]] is one of the standard traps it should be overridden. - * However for convenience BaseProxyHandler includes a pure virtual implementation, - * that turns the properties returned by getOwnEnumerablePropertyKeys (and proto walking) - * into an Iterator object. - */ - virtual bool enumerate(JSContext* cx, HandleObject proxy, MutableHandleObject objp) const = 0; - - /* * These methods are standard, but the engine does not normally call them. * They're opt-in. See "Proxy prototype chains" above. * @@ -278,7 +276,9 @@ virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result) const; - /* Non-standard but conceptual kin to {g,s}etPrototype, so lives here. */ + /* Non-standard but conceptual kin to {g,s}etPrototype, so these live here. */ + virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const = 0; virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const; virtual bool preventExtensions(JSContext* cx, HandleObject proxy, @@ -314,8 +314,9 @@ virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const; /* SpiderMonkey extensions. */ + virtual bool enumerate(JSContext* cx, HandleObject proxy, MutableHandleObject objp) const; virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const; + MutableHandle desc) const; virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const; virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const; @@ -323,7 +324,7 @@ const CallArgs& args) const; virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp) const; virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, - ESClassValue* classValue) const; + ESClass* cls) const; virtual bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const; virtual const char* className(JSContext* cx, HandleObject proxy) const; virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const; @@ -354,79 +355,6 @@ virtual bool isScripted() const { return false; } }; -/* - * DirectProxyHandler includes a notion of a target object. All methods are - * reimplemented such that they forward their behavior to the target. This - * allows consumers of this class to forward to another object as transparently - * and efficiently as possible. - * - * Important: If you add a method implementation here, you probably also need - * to add an override in CrossCompartmentWrapper. If you don't, you risk - * compartment mismatches. See bug 945826 comment 0. - */ -class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler -{ - public: - explicit MOZ_CONSTEXPR DirectProxyHandler(const void* aFamily, bool aHasPrototype = false, - bool aHasSecurityPolicy = false) - : BaseProxyHandler(aFamily, aHasPrototype, aHasSecurityPolicy) - { } - - /* Standard internal methods. */ - virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const override; - virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, - ObjectOpResult& result) const override; - virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy, - AutoIdVector& props) const override; - virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id, - ObjectOpResult& result) const override; - virtual bool enumerate(JSContext* cx, HandleObject proxy, - MutableHandleObject objp) const override; - virtual bool getPrototype(JSContext* cx, HandleObject proxy, - MutableHandleObject protop) const override; - virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, - ObjectOpResult& result) const override; - virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, - bool* succeeded) const override; - virtual bool preventExtensions(JSContext* cx, HandleObject proxy, - ObjectOpResult& result) const override; - virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override; - virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, - bool* bp) const override; - virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, - HandleId id, MutableHandleValue vp) const override; - virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result) const override; - virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const override; - virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override; - - /* SpiderMonkey extensions. */ - virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const override; - virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, - bool* bp) const override; - virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, - AutoIdVector& props) const override; - virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, - const CallArgs& args) const override; - virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, - bool* bp) const override; - virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, - ESClassValue* classValue) const override; - virtual bool isArray(JSContext* cx, HandleObject proxy, - JS::IsArrayAnswer* answer) const override; - virtual const char* className(JSContext* cx, HandleObject proxy) const override; - virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, - unsigned indent) const override; - virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, - RegExpGuard* g) const override; - virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override; - virtual bool isCallable(JSObject* obj) const override; - virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const override; -}; - extern JS_FRIEND_DATA(const js::Class* const) ProxyClassPtr; inline bool IsProxy(const JSObject* obj) @@ -434,6 +362,7 @@ return GetObjectClass(obj)->isProxy(); } +namespace detail { const uint32_t PROXY_EXTRA_SLOTS = 2; // Layout of the values stored by a proxy. Note that API clients require the @@ -470,7 +399,6 @@ const uint32_t ProxyDataOffset = 2 * sizeof(void*); -// This method should only be used internally and by the accessors below. inline ProxyDataLayout* GetProxyDataLayout(JSObject* obj) { @@ -478,16 +406,25 @@ return reinterpret_cast(reinterpret_cast(obj) + ProxyDataOffset); } +inline const ProxyDataLayout* +GetProxyDataLayout(const JSObject* obj) +{ + MOZ_ASSERT(IsProxy(obj)); + return reinterpret_cast(reinterpret_cast(obj) + + ProxyDataOffset); +} +} // namespace detail + inline const BaseProxyHandler* -GetProxyHandler(JSObject* obj) +GetProxyHandler(const JSObject* obj) { - return GetProxyDataLayout(obj)->handler; + return detail::GetProxyDataLayout(obj)->handler; } inline const Value& -GetProxyPrivate(JSObject* obj) +GetProxyPrivate(const JSObject* obj) { - return GetProxyDataLayout(obj)->values->privateSlot; + return detail::GetProxyDataLayout(obj)->values->privateSlot; } inline JSObject* @@ -497,16 +434,16 @@ } inline const Value& -GetProxyExtra(JSObject* obj, size_t n) +GetProxyExtra(const JSObject* obj, size_t n) { - MOZ_ASSERT(n < PROXY_EXTRA_SLOTS); - return GetProxyDataLayout(obj)->values->extraSlots[n]; + MOZ_ASSERT(n < detail::PROXY_EXTRA_SLOTS); + return detail::GetProxyDataLayout(obj)->values->extraSlots[n]; } inline void SetProxyHandler(JSObject* obj, const BaseProxyHandler* handler) { - GetProxyDataLayout(obj)->handler = handler; + detail::GetProxyDataLayout(obj)->handler = handler; } JS_FRIEND_API(void) @@ -515,8 +452,8 @@ inline void SetProxyExtra(JSObject* obj, size_t n, const Value& extra) { - MOZ_ASSERT(n < PROXY_EXTRA_SLOTS); - Value* vp = &GetProxyDataLayout(obj)->values->extraSlots[n]; + MOZ_ASSERT(n < detail::PROXY_EXTRA_SLOTS); + Value* vp = &detail::GetProxyDataLayout(obj)->values->extraSlots[n]; // Trigger a barrier before writing the slot. if (vp->isMarkable() || extra.isMarkable()) @@ -526,13 +463,13 @@ } inline bool -IsScriptedProxy(JSObject* obj) +IsScriptedProxy(const JSObject* obj) { return IsProxy(obj) && GetProxyHandler(obj)->isScripted(); } inline const Value& -GetReservedOrProxyPrivateSlot(JSObject* obj, size_t slot) +GetReservedOrProxyPrivateSlot(const JSObject* obj, size_t slot) { MOZ_ASSERT(slot == 0); MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)) || IsProxy(obj)); @@ -597,7 +534,7 @@ JSObject* proto, const ProxyOptions& options = ProxyOptions()); JSObject* -RenewProxyObject(JSContext* cx, JSObject* obj, BaseProxyHandler* handler, Value priv); +RenewProxyObject(JSContext* cx, JSObject* obj, BaseProxyHandler* handler, const Value& priv); class JS_FRIEND_API(AutoEnterPolicy) { Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Realm.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Realm.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Realm.h @@ -0,0 +1,42 @@ +/* -*- 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/. */ + +/* + * Ways to get various per-Realm objects. All the getters declared in this + * header operate on the Realm corresponding to the current compartment on the + * JSContext. + */ + +#ifndef js_Realm_h +#define js_Realm_h + +#include "jstypes.h" + +struct JSContext; +class JSObject; + +namespace JS { + +extern JS_PUBLIC_API(JSObject*) +GetRealmObjectPrototype(JSContext* cx); + +extern JS_PUBLIC_API(JSObject*) +GetRealmFunctionPrototype(JSContext* cx); + +extern JS_PUBLIC_API(JSObject*) +GetRealmArrayPrototype(JSContext* cx); + +extern JS_PUBLIC_API(JSObject*) +GetRealmErrorPrototype(JSContext* cx); + +extern JS_PUBLIC_API(JSObject*) +GetRealmIteratorPrototype(JSContext* cx); + +} // namespace JS + +#endif // js_Realm_h + + Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/RootingAPI.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/RootingAPI.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/RootingAPI.h @@ -14,11 +14,16 @@ #include "mozilla/Move.h" #include "mozilla/TypeTraits.h" +#include + #include "jspubtd.h" +#include "js/GCAnnotations.h" #include "js/GCAPI.h" +#include "js/GCPolicyAPI.h" #include "js/HeapAPI.h" #include "js/TypeDecls.h" +#include "js/UniquePtr.h" #include "js/Utility.h" /* @@ -105,8 +110,7 @@ namespace js { template -struct GCMethods { - static T initial() { return T(); } +struct BarrierMethods { }; template @@ -121,6 +125,14 @@ template class HeapBase {}; +// Cannot use FOR_EACH_HEAP_ABLE_GC_POINTER_TYPE, as this would import too many macros into scope +template struct IsHeapConstructibleType { static constexpr bool value = false; }; +#define DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE(T) \ + template <> struct IsHeapConstructibleType { static constexpr bool value = true; }; +FOR_EACH_PUBLIC_GC_POINTER_TYPE(DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE) +FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE) +#undef DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE + template class PersistentRootedBase {}; @@ -132,14 +144,14 @@ struct PersistentRootedMarker; } /* namespace gc */ -#define DECLARE_POINTER_COMPARISON_OPS(T) \ +#define DECLARE_POINTER_COMPARISON_OPS(T) \ bool operator==(const T& other) const { return get() == other; } \ bool operator!=(const T& other) const { return get() != other; } // Important: Return a reference so passing a Rooted, etc. to // something that takes a |const T&| is not a GC hazard. -#define DECLARE_POINTER_CONSTREF_OPS(T) \ - operator const T&() const { return get(); } \ +#define DECLARE_POINTER_CONSTREF_OPS(T) \ + operator const T&() const { return get(); } \ const T& operator->() const { return get(); } // Assignment operators on a base class are hidden by the implicitly defined @@ -150,12 +162,16 @@ set(p); \ return *this; \ } \ + Wrapper& operator=(T&& p) { \ + set(mozilla::Move(p)); \ + return *this; \ + } \ Wrapper& operator=(const Wrapper& other) { \ set(other.get()); \ return *this; \ } \ -#define DELETE_ASSIGNMENT_OPS(Wrapper, T) \ +#define DELETE_ASSIGNMENT_OPS(Wrapper, T) \ template Wrapper& operator=(S) = delete; \ Wrapper& operator=(const Wrapper&) = delete; @@ -212,18 +228,21 @@ * Heap objects should only be used on the heap. GC references stored on the * C/C++ stack must use Rooted/Handle/MutableHandle instead. * - * Type T must be one of: JS::Value, jsid, JSObject*, JSString*, JSScript* + * Type T must be a public GC pointer type. */ template -class Heap : public js::HeapBase +class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase { + // Please note: this can actually also be used by nsXBLMaybeCompiled, for legacy reasons. + static_assert(js::IsHeapConstructibleType::value, + "Type T must be a public GC pointer type"); public: Heap() { static_assert(sizeof(T) == sizeof(Heap), "Heap must be binary compatible with T."); - init(js::GCMethods::initial()); + init(GCPolicy::initial()); } - explicit Heap(T p) { init(p); } + explicit Heap(const T& p) { init(p); } /* * For Heap, move semantics are equivalent to copy semantics. In C++, a @@ -234,50 +253,91 @@ explicit Heap(const Heap& p) { init(p.ptr); } ~Heap() { - post(ptr, js::GCMethods::initial()); + post(ptr, GCPolicy::initial()); } DECLARE_POINTER_CONSTREF_OPS(T); DECLARE_POINTER_ASSIGN_OPS(Heap, T); - DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); - T* unsafeGet() { return &ptr; } + const T* address() const { return &ptr; } - /* - * Set the pointer to a value which will cause a crash if it is - * dereferenced. - */ - void setToCrashOnTouch() { - ptr = reinterpret_cast(crashOnTouchPointer); + void exposeToActiveJS() const { + js::BarrierMethods::exposeToJS(ptr); + } + const T& get() const { + exposeToActiveJS(); + return ptr; + } + const T& unbarrieredGet() const { + return ptr; } - bool isSetToCrashOnTouch() { - return ptr == crashOnTouchPointer; + T* unsafeGet() { return &ptr; } + + explicit operator bool() const { + return bool(js::BarrierMethods::asGCThingOrNull(ptr)); + } + explicit operator bool() { + return bool(js::BarrierMethods::asGCThingOrNull(ptr)); } private: - void init(T newPtr) { + void init(const T& newPtr) { ptr = newPtr; - post(js::GCMethods::initial(), ptr); + post(GCPolicy::initial(), ptr); } - void set(T newPtr) { + void set(const T& newPtr) { T tmp = ptr; ptr = newPtr; post(tmp, ptr); } void post(const T& prev, const T& next) { - js::GCMethods::postBarrier(&ptr, prev, next); + js::BarrierMethods::postBarrier(&ptr, prev, next); } - enum { - crashOnTouchPointer = 1 - }; - T ptr; }; +static MOZ_ALWAYS_INLINE bool +ObjectIsTenured(JSObject* obj) +{ + return !js::gc::IsInsideNursery(reinterpret_cast(obj)); +} + +static MOZ_ALWAYS_INLINE bool +ObjectIsTenured(const Heap& obj) +{ + return ObjectIsTenured(obj.unbarrieredGet()); +} + +static MOZ_ALWAYS_INLINE bool +ObjectIsMarkedGray(JSObject* obj) +{ + auto cell = reinterpret_cast(obj); + return js::gc::detail::CellIsMarkedGrayIfKnown(cell); +} + +static MOZ_ALWAYS_INLINE bool +ObjectIsMarkedGray(const JS::Heap& obj) +{ + return ObjectIsMarkedGray(obj.unbarrieredGet()); +} + +static MOZ_ALWAYS_INLINE bool +ScriptIsMarkedGray(JSScript* script) +{ + auto cell = reinterpret_cast(script); + return js::gc::detail::CellIsMarkedGrayIfKnown(cell); +} + +static MOZ_ALWAYS_INLINE bool +ScriptIsMarkedGray(const Heap& script) +{ + return ScriptIsMarkedGray(script.unbarrieredGet()); +} + /** * The TenuredHeap class is similar to the Heap class above in that it * encapsulates the GC concerns of an on-heap reference to a JS object. However, @@ -343,12 +403,27 @@ return (bits & flag) != 0; } - T getPtr() const { return reinterpret_cast(bits & ~flagsMask); } + T unbarrieredGetPtr() const { return reinterpret_cast(bits & ~flagsMask); } uintptr_t getFlags() const { return bits & flagsMask; } + void exposeToActiveJS() const { + js::BarrierMethods::exposeToJS(unbarrieredGetPtr()); + } + T getPtr() const { + exposeToActiveJS(); + return unbarrieredGetPtr(); + } + operator T() const { return getPtr(); } T operator->() const { return getPtr(); } + explicit operator bool() const { + return bool(js::BarrierMethods::asGCThingOrNull(unbarrieredGetPtr())); + } + explicit operator bool() { + return bool(js::BarrierMethods::asGCThingOrNull(unbarrieredGetPtr())); + } + TenuredHeap& operator=(T p) { setPtr(p); return *this; @@ -417,7 +492,7 @@ * for the lifetime of the handle, as its users may not expect its value * to change underneath them. */ - static MOZ_CONSTEXPR Handle fromMarkedLocation(const T* p) { + static constexpr Handle fromMarkedLocation(const T* p) { return Handle(p, DeliberatelyChoosingThisOverload, ImUsingThisOnlyInFromFromMarkedLocation); } @@ -452,7 +527,7 @@ enum Disambiguator { DeliberatelyChoosingThisOverload = 42 }; enum CallerIdentity { ImUsingThisOnlyInFromFromMarkedLocation = 17 }; - MOZ_CONSTEXPR Handle(const T* p, Disambiguator, CallerIdentity) : ptr(p) {} + constexpr Handle(const T* p, Disambiguator, CallerIdentity) : ptr(p) {} const T* ptr; }; @@ -477,9 +552,12 @@ MutableHandle(decltype(nullptr)) = delete; public: - void set(T v) { + void set(const T& v) { *ptr = v; } + void set(T&& v) { + *ptr = mozilla::Move(v); + } /* * This may be called only if the location of the T is guaranteed @@ -509,36 +587,28 @@ namespace js { -/** - * By default, things should use the inheritance hierarchy to find their - * ThingRootKind. Some pointer types are explicitly set in jspubtd.h so that - * Rooted may be used without the class definition being available. - */ -template -struct RootKind -{ - static ThingRootKind rootKind() { return T::rootKind(); } -}; - -template -struct RootKind -{ - static ThingRootKind rootKind() { return T::rootKind(); } -}; - template -struct GCMethods +struct BarrierMethods { static T* initial() { return nullptr; } + static gc::Cell* asGCThingOrNull(T* v) { + if (!v) + return nullptr; + MOZ_ASSERT(uintptr_t(v) > 32); + return reinterpret_cast(v); + } static void postBarrier(T** vp, T* prev, T* next) { if (next) JS::AssertGCThingIsNotAnObjectSubclass(reinterpret_cast(next)); } - static void relocate(T** vp) {} + static void exposeToJS(T* t) { + if (t) + js::gc::ExposeGCThingToActiveJS(JS::GCCellPtr(t)); + } }; template <> -struct GCMethods +struct BarrierMethods { static JSObject* initial() { return nullptr; } static gc::Cell* asGCThingOrNull(JSObject* v) { @@ -550,17 +620,31 @@ static void postBarrier(JSObject** vp, JSObject* prev, JSObject* next) { JS::HeapObjectPostBarrier(vp, prev, next); } + static void exposeToJS(JSObject* obj) { + if (obj) + JS::ExposeObjectToActiveJS(obj); + } }; template <> -struct GCMethods +struct BarrierMethods { static JSFunction* initial() { return nullptr; } + static gc::Cell* asGCThingOrNull(JSFunction* v) { + if (!v) + return nullptr; + MOZ_ASSERT(uintptr_t(v) > 32); + return reinterpret_cast(v); + } static void postBarrier(JSFunction** vp, JSFunction* prev, JSFunction* next) { JS::HeapObjectPostBarrier(reinterpret_cast(vp), reinterpret_cast(prev), reinterpret_cast(next)); } + static void exposeToJS(JSFunction* fun) { + if (fun) + JS::ExposeObjectToActiveJS(reinterpret_cast(fun)); + } }; // Provide hash codes for Cell kinds that may be relocated and, thus, not have @@ -580,6 +664,8 @@ using Key = T; using Lookup = T; + static bool hasHash(const Lookup& l); + static bool ensureHash(const Lookup& l); static HashNumber hash(const Lookup& l); static bool match(const Key& k, const Lookup& l); static void rekey(Key& k, const Key& newKey) { k = newKey; } @@ -591,47 +677,52 @@ using Key = JS::Heap; using Lookup = T; + static bool hasHash(const Lookup& l) { return MovableCellHasher::hasHash(l); } + static bool ensureHash(const Lookup& l) { return MovableCellHasher::ensureHash(l); } static HashNumber hash(const Lookup& l) { return MovableCellHasher::hash(l); } - static bool match(const Key& k, const Lookup& l) { return MovableCellHasher::match(k, l); } + static bool match(const Key& k, const Lookup& l) { + return MovableCellHasher::match(k.unbarrieredGet(), l); + } static void rekey(Key& k, const Key& newKey) { k.unsafeSet(newKey); } }; -} /* namespace js */ - -namespace JS { - -// Non pointer types -- structs or classes that contain GC pointers, either as -// a member or in a more complex container layout -- can also be stored in a -// [Persistent]Rooted if it derives from JS::Traceable. A JS::Traceable stored -// in a [Persistent]Rooted must implement the method: -// |static void trace(T*, JSTracer*)| -class Traceable +template +struct FallibleHashMethods> { - public: - static js::ThingRootKind rootKind() { return js::THING_ROOT_TRACEABLE; } + template static bool hasHash(Lookup&& l) { + return MovableCellHasher::hasHash(mozilla::Forward(l)); + } + template static bool ensureHash(Lookup&& l) { + return MovableCellHasher::ensureHash(mozilla::Forward(l)); + } }; -} /* namespace JS */ +} /* namespace js */ namespace js { +// The alignment must be set because the Rooted and PersistentRooted ptr fields +// may be accessed through reinterpret_cast*>, and +// the compiler may choose a different alignment for the ptr field when it +// knows the actual type stored in DispatchWrapper. +// +// It would make more sense to align only those specific fields of type +// DispatchWrapper, rather than DispatchWrapper itself, but that causes MSVC to +// fail when Rooted is used in an IsConvertible test. template -class DispatchWrapper +class alignas(8) DispatchWrapper { - static_assert(mozilla::IsBaseOf::value, + static_assert(JS::MapTypeToRootKind::kind == JS::RootKind::Traceable, "DispatchWrapper is intended only for usage with a Traceable"); - using TraceFn = void (*)(T*, JSTracer*); + using TraceFn = void (*)(JSTracer*, T*, const char*); TraceFn tracer; -#if JS_BITS_PER_WORD == 32 - uint32_t padding; // Ensure the storage fields have CellSize alignment. -#endif - T storage; + alignas(gc::CellSize) T storage; public: template MOZ_IMPLICIT DispatchWrapper(U&& initial) - : tracer(&T::trace), + : tracer(&JS::GCPolicy::trace), storage(mozilla::Forward(initial)) { } @@ -643,37 +734,13 @@ // Trace the contained storage (of unknown type) using the trace function // we set aside when we did know the type. - static void TraceWrapped(JSTracer* trc, JS::Traceable* thingp, const char* name) { + static void TraceWrapped(JSTracer* trc, T* thingp, const char* name) { auto wrapper = reinterpret_cast( uintptr_t(thingp) - offsetof(DispatchWrapper, storage)); - wrapper->tracer(&wrapper->storage, trc); + wrapper->tracer(trc, &wrapper->storage, name); } }; -inline RootLists& -RootListsForRootingContext(JSContext* cx) -{ - return ContextFriendFields::get(cx)->roots; -} - -inline RootLists& -RootListsForRootingContext(js::ContextFriendFields* cx) -{ - return cx->roots; -} - -inline RootLists& -RootListsForRootingContext(JSRuntime* rt) -{ - return PerThreadDataFriendFields::getMainThread(rt)->roots; -} - -inline RootLists& -RootListsForRootingContext(js::PerThreadDataFriendFields* pt) -{ - return pt->roots; -} - } /* namespace js */ namespace JS { @@ -689,30 +756,38 @@ template class MOZ_RAII Rooted : public js::RootedBase { - static_assert(!mozilla::IsConvertible::value, - "Rooted takes pointer or Traceable types but not Traceable* type"); - - /* Note: CX is a subclass of either ContextFriendFields or PerThreadDataFriendFields. */ - void registerWithRootLists(js::RootLists& roots) { - js::ThingRootKind kind = js::RootKind::rootKind(); - this->stack = &roots.stackRoots_[kind]; + inline void registerWithRootLists(js::RootedListHeads& roots) { + this->stack = &roots[JS::MapTypeToRootKind::kind]; this->prev = *stack; *stack = reinterpret_cast*>(this); } + inline js::RootedListHeads& rootLists(JS::RootingContext* cx) { + return rootLists(static_cast(cx)); + } + inline js::RootedListHeads& rootLists(js::ContextFriendFields* cx) { + if (JS::Zone* zone = cx->zone_) + return JS::shadow::Zone::asShadowZone(zone)->stackRoots_; + MOZ_ASSERT(cx->isJSContext); + return cx->roots.stackRoots_; + } + inline js::RootedListHeads& rootLists(JSContext* cx) { + return rootLists(js::ContextFriendFields::get(cx)); + } + public: template explicit Rooted(const RootingContext& cx) - : ptr(js::GCMethods::initial()) + : ptr(GCPolicy::initial()) { - registerWithRootLists(js::RootListsForRootingContext(cx)); + registerWithRootLists(rootLists(cx)); } template Rooted(const RootingContext& cx, S&& initial) : ptr(mozilla::Forward(initial)) { - registerWithRootLists(js::RootListsForRootingContext(cx)); + registerWithRootLists(rootLists(cx)); } ~Rooted() { @@ -726,9 +801,12 @@ * This method is public for Rooted so that Codegen.py can use a Rooted * interchangeably with a MutableHandleValue. */ - void set(T value) { + void set(const T& value) { ptr = value; } + void set(T&& value) { + ptr = mozilla::Move(value); + } DECLARE_POINTER_COMPARISON_OPS(T); DECLARE_POINTER_CONSTREF_OPS(T); @@ -747,20 +825,20 @@ /* * For pointer types, the TraceKind for tracing is based on the list it is - * in (selected via rootKind), so no additional storage is required here. - * All Traceable, however, share the same list, so the function to - * call for tracing is stored adjacent to the struct. Since C++ cannot - * templatize on storage class, this is implemented via the wrapper class - * DispatchWrapper. + * in (selected via MapTypeToRootKind), so no additional storage is + * required here. Non-pointer types, however, share the same list, so the + * function to call for tracing is stored adjacent to the struct. Since C++ + * cannot templatize on storage class, this is implemented via the wrapper + * class DispatchWrapper. */ using MaybeWrapped = typename mozilla::Conditional< - mozilla::IsBaseOf::value, + MapTypeToRootKind::kind == JS::RootKind::Traceable, js::DispatchWrapper, T>::Type; MaybeWrapped ptr; Rooted(const Rooted&) = delete; -}; +} JS_HAZ_ROOTED; } /* namespace JS */ @@ -808,7 +886,7 @@ { public: template - explicit FakeRooted(CX* cx) : ptr(GCMethods::initial()) {} + explicit FakeRooted(CX* cx) : ptr(JS::GCPolicy::initial()) {} template FakeRooted(CX* cx, T initial) : ptr(initial) {} @@ -842,7 +920,7 @@ ptr = root->address(); } - void set(T v) { + void set(const T& v) { *ptr = v; } @@ -899,7 +977,7 @@ template class MaybeRooted { public: - typedef T HandleType; + typedef const T& HandleType; typedef FakeRooted RootType; typedef FakeMutableHandle MutableHandleType; @@ -970,7 +1048,7 @@ * These roots can be used in heap-allocated data structures, so they are not * associated with any particular JSContext or stack. They are registered with * the JSRuntime itself, without locking, so they require a full JSContext to be - * initialized, not one of its more restricted superclasses. Initialization may + * initialized, not one of its more restricted superclasses. Initialization may * take place on construction, or in two phases if the no-argument constructor * is called followed by init(). * @@ -1001,45 +1079,43 @@ class PersistentRooted : public js::PersistentRootedBase, private mozilla::LinkedListElement> { - typedef mozilla::LinkedListElement> ListBase; + using ListBase = mozilla::LinkedListElement>; friend class mozilla::LinkedList; friend class mozilla::LinkedListElement; - friend struct js::gc::PersistentRootedMarker; - - friend void js::gc::FinishPersistentRootedChains(js::RootLists&); - void registerWithRootLists(js::RootLists& roots) { MOZ_ASSERT(!initialized()); - js::ThingRootKind kind = js::RootKind::rootKind(); + JS::RootKind kind = JS::MapTypeToRootKind::kind; roots.heapRoots_[kind].insertBack(reinterpret_cast*>(this)); - // Until marking and destruction support the full set, we assert that - // we don't try to add any unsupported types. - MOZ_ASSERT(kind == js::THING_ROOT_OBJECT || - kind == js::THING_ROOT_SCRIPT || - kind == js::THING_ROOT_STRING || - kind == js::THING_ROOT_SYMBOL || - kind == js::THING_ROOT_ID || - kind == js::THING_ROOT_VALUE || - kind == js::THING_ROOT_TRACEABLE); } + js::RootLists& rootLists(JSContext* cx) { + return rootLists(JS::RootingContext::get(cx)); + } + js::RootLists& rootLists(JS::RootingContext* cx) { + MOZ_ASSERT(cx->isJSContext); + return cx->roots; + } + + // Disallow ExclusiveContext*. + js::RootLists& rootLists(js::ContextFriendFields* cx) = delete; + public: - PersistentRooted() : ptr(js::GCMethods::initial()) {} + PersistentRooted() : ptr(GCPolicy::initial()) {} template explicit PersistentRooted(const RootingContext& cx) - : ptr(js::GCMethods::initial()) + : ptr(GCPolicy::initial()) { - registerWithRootLists(js::RootListsForRootingContext(cx)); + registerWithRootLists(rootLists(cx)); } template PersistentRooted(const RootingContext& cx, U&& initial) : ptr(mozilla::Forward(initial)) { - registerWithRootLists(js::RootListsForRootingContext(cx)); + registerWithRootLists(rootLists(cx)); } PersistentRooted(const PersistentRooted& rhs) @@ -1063,18 +1139,18 @@ template void init(const RootingContext& cx) { - init(cx, js::GCMethods::initial()); + init(cx, GCPolicy::initial()); } template void init(const RootingContext& cx, U&& initial) { ptr = mozilla::Forward(initial); - registerWithRootLists(js::RootListsForRootingContext(cx)); + registerWithRootLists(rootLists(cx)); } void reset() { if (initialized()) { - set(js::GCMethods::initial()); + set(GCPolicy::initial()); ListBase::remove(); } } @@ -1097,19 +1173,19 @@ } private: - void set(T value) { + template + void set(U&& value) { MOZ_ASSERT(initialized()); - ptr = value; + ptr = mozilla::Forward(value); } // See the comment above Rooted::ptr. using MaybeWrapped = typename mozilla::Conditional< - mozilla::IsBaseOf::value, + MapTypeToRootKind::kind == JS::RootKind::Traceable, js::DispatchWrapper, T>::Type; - MaybeWrapped ptr; -}; +} JS_HAZ_ROOTED; class JS_PUBLIC_API(ObjectPtr) { @@ -1120,20 +1196,26 @@ explicit ObjectPtr(JSObject* obj) : value(obj) {} + ObjectPtr(const ObjectPtr& other) : value(other.value) {} + + ObjectPtr(ObjectPtr&& other) + : value(other.value) + { + other.value = nullptr; + } + /* Always call finalize before the destructor. */ ~ObjectPtr() { MOZ_ASSERT(!value); } - void finalize(JSRuntime* rt) { - if (IsIncrementalBarrierNeeded(rt)) - IncrementalObjectBarrier(value); - value = nullptr; - } + void finalize(JSRuntime* rt); + void finalize(JSContext* cx); void init(JSObject* obj) { value = obj; } JSObject* get() const { return value; } + JSObject* unbarrieredGet() const { return value.unbarrieredGet(); } - void writeBarrierPre(JSRuntime* rt) { + void writeBarrierPre(JSContext* cx) { IncrementalObjectBarrier(value); } @@ -1150,11 +1232,57 @@ JSObject& operator*() const { return *value; } JSObject* operator->() const { return value; } operator JSObject*() const { return value; } + + explicit operator bool() const { return value.unbarrieredGet(); } + explicit operator bool() { return value.unbarrieredGet(); } }; } /* namespace JS */ namespace js { + +template +class UniquePtrOperations +{ + const UniquePtr& uniquePtr() const { return static_cast(this)->get(); } + + public: + explicit operator bool() const { return !!uniquePtr(); } + T* get() const { return uniquePtr().get(); } + T* operator->() const { return get(); } + T& operator*() const { return *uniquePtr(); } +}; + +template +class MutableUniquePtrOperations : public UniquePtrOperations +{ + UniquePtr& uniquePtr() { return static_cast(this)->get(); } + + public: + MOZ_MUST_USE typename UniquePtr::Pointer release() { return uniquePtr().release(); } + void reset(T* ptr = T()) { uniquePtr().reset(ptr); } +}; + +template +class RootedBase> + : public MutableUniquePtrOperations>, T, D> +{ }; + +template +class MutableHandleBase> + : public MutableUniquePtrOperations>, T, D> +{ }; + +template +class HandleBase> + : public UniquePtrOperations>, T, D> +{ }; + +template +class PersistentRootedBase> + : public MutableUniquePtrOperations>, T, D> +{ }; + namespace gc { template @@ -1163,7 +1291,7 @@ { static_assert(sizeof(T) == sizeof(JS::Heap), "T and Heap must be compatible."); MOZ_ASSERT(v); - mozilla::DebugOnly cell = GCMethods::asGCThingOrNull(*v); + mozilla::DebugOnly cell = BarrierMethods::asGCThingOrNull(*v); MOZ_ASSERT(cell); MOZ_ASSERT(!IsInsideNursery(cell)); JS::Heap* asHeapT = reinterpret_cast*>(v); Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/StructuredClone.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/StructuredClone.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/StructuredClone.h @@ -7,6 +7,10 @@ #ifndef js_StructuredClone_h #define js_StructuredClone_h +#include "mozilla/Attributes.h" +#include "mozilla/BufferList.h" +#include "mozilla/Move.h" + #include #include "jstypes.h" @@ -22,6 +26,41 @@ // API for the HTML5 internal structured cloning algorithm. namespace JS { + +enum class StructuredCloneScope : uint32_t { + SameProcessSameThread, + SameProcessDifferentThread, + + /** + * When writing, this means we're writing for an audience in a different + * process. Produce serialized data that can be sent to other processes, + * bitwise copied, or even stored as bytes in a database and read by later + * versions of Firefox years from now. The HTML5 spec refers to this as + * "ForStorage" as in StructuredSerializeForStorage, though we use + * DifferentProcess for IPC as well as storage. + * + * Transferable objects are limited to ArrayBuffers, whose contents are + * copied into the serialized data (rather than just writing a pointer). + */ + DifferentProcess, + + /** + * Handle a backwards-compatibility case with IndexedDB (bug 1434308): when + * reading, this means to treat legacy SameProcessSameThread data as if it + * were DifferentProcess. + * + * Do not use this for writing; use DifferentProcess instead. + */ + DifferentProcessForIndexedDB, + + /** + * Existing code wants to be able to create an uninitialized + * JSStructuredCloneData without knowing the scope, then populate it with + * data (at which point the scope *is* known.) + */ + Unassigned +}; + enum TransferableOwnership { /** Transferable data has not been filled in yet */ SCTAG_TMO_UNFILLED = 0, @@ -35,23 +74,54 @@ /** Data is a pointer that can be freed */ SCTAG_TMO_ALLOC_DATA = 2, - /** Data is a SharedArrayBufferObject's buffer */ - SCTAG_TMO_SHARED_BUFFER = 3, - /** Data is a memory mapped pointer */ - SCTAG_TMO_MAPPED_DATA = 4, + SCTAG_TMO_MAPPED_DATA = 3, /** * Data is embedding-specific. The engine can free it by calling the * freeTransfer op. The embedding can also use SCTAG_TMO_USER_MIN and * greater, up to 32 bits, to distinguish specific ownership variants. */ - SCTAG_TMO_CUSTOM = 5, + SCTAG_TMO_CUSTOM = 4, SCTAG_TMO_USER_MIN }; + +class CloneDataPolicy +{ + bool sharedArrayBuffer_; + + public: + // The default is to allow all policy-controlled aspects. + + CloneDataPolicy() : + sharedArrayBuffer_(true) + {} + + // In the JS engine, SharedArrayBuffers can only be cloned intra-process + // because the shared memory areas are allocated in process-private memory. + // Clients should therefore deny SharedArrayBuffers when cloning data that + // are to be transmitted inter-process. + // + // Clients should also deny SharedArrayBuffers when cloning data that are to + // be transmitted intra-process if policy needs dictate such denial. + + CloneDataPolicy& denySharedArrayBuffer() { + sharedArrayBuffer_ = false; + return *this; + } + + bool isSharedArrayBufferAllowed() const { + return sharedArrayBuffer_; + } +}; + } /* namespace JS */ +namespace js { +template struct BufferIterator; +} + /** * Read structured data from the reader r. This hook is used to read a value * previously serialized by a call to the WriteStructuredCloneOp hook. @@ -123,9 +193,9 @@ uint64_t* extraData); /** - * Called when JS_ClearStructuredClone has to free an unknown transferable - * object. Note that it should never trigger a garbage collection (and will - * assert in a debug build if it does.) + * Called when freeing an unknown transferable object. Note that it + * should never trigger a garbage collection (and will assert in a + * debug build if it does.) */ typedef void (*FreeTransferStructuredCloneOp)(uint32_t tag, JS::TransferableOwnership ownership, void* content, uint64_t extraData, void* closure); @@ -134,7 +204,7 @@ // Increment this when anything at all changes in the serialization format. // (Note that this does not need to be bumped for Transferable-only changes, // since they are never saved to persistent storage.) -#define JS_STRUCTURED_CLONE_VERSION 6 +#define JS_STRUCTURED_CLONE_VERSION 8 struct JSStructuredCloneCallbacks { ReadStructuredCloneOp read; @@ -145,97 +215,239 @@ FreeTransferStructuredCloneOp freeTransfer; }; +enum OwnTransferablePolicy { + OwnsTransferablesIfAny, + IgnoreTransferablesIfAny, + NoTransferables +}; + +/** + * JSStructuredCloneData represents structured clone data together with the + * information needed to read/write/transfer/free the records within it, in the + * form of a set of callbacks. + */ +class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(JSStructuredCloneData) { + public: + using BufferList = mozilla::BufferList; + using Iterator = BufferList::IterImpl; + + private: + static const size_t kStandardCapacity = 4096; + + BufferList bufList_; + + // The (address space, thread) scope within which this clone is valid. Note + // that this must be either set during construction, or start out as + // Unassigned and transition once to something else. + JS::StructuredCloneScope scope_; + + const JSStructuredCloneCallbacks* callbacks_; + void* closure_; + OwnTransferablePolicy ownTransferables_; + + friend struct JSStructuredCloneWriter; + friend class JS_PUBLIC_API(JSAutoStructuredCloneBuffer); + template friend struct js::BufferIterator; + + public: + // The constructor must be infallible but SystemAllocPolicy is not, so both + // the initial size and initial capacity of the BufferList must be zero. + explicit JSStructuredCloneData(JS::StructuredCloneScope aScope) + : bufList_(0, 0, kStandardCapacity, js::SystemAllocPolicy()) + , scope_(aScope) + , callbacks_(nullptr) + , closure_(nullptr) + , ownTransferables_(OwnTransferablePolicy::NoTransferables) + {} + + // Steal the raw data from a BufferList. In this case, we don't know the + // scope and none of the callback info is assigned yet. + JSStructuredCloneData(BufferList&& buffers, JS::StructuredCloneScope aScope) + : bufList_(mozilla::Move(buffers)) + , scope_(aScope) + , callbacks_(nullptr) + , closure_(nullptr) + , ownTransferables_(OwnTransferablePolicy::NoTransferables) + {} + MOZ_IMPLICIT JSStructuredCloneData(BufferList&& buffers) + : JSStructuredCloneData(mozilla::Move(buffers), JS::StructuredCloneScope::Unassigned) + {} + JSStructuredCloneData(JSStructuredCloneData&& other) = default; + JSStructuredCloneData& operator=(JSStructuredCloneData&& other) = default; + ~JSStructuredCloneData() { discardTransferables(); } + + void setCallbacks(const JSStructuredCloneCallbacks* callbacks, + void* closure, + OwnTransferablePolicy policy) + { + callbacks_ = callbacks; + closure_ = closure; + ownTransferables_ = policy; + } + + JS::StructuredCloneScope scope() const { return scope_; } + + void initScope(JS::StructuredCloneScope aScope) { + MOZ_ASSERT(Size() == 0, "initScope() of nonempty JSStructuredCloneData"); + if (scope_ != JS::StructuredCloneScope::Unassigned) + MOZ_ASSERT(scope_ == aScope, "Cannot change scope after it has been initialized"); + scope_ = aScope; + } + + size_t Size() const { return bufList_.Size(); } + + const Iterator Start() const { return bufList_.Iter(); } + + bool Advance(Iterator& iter, size_t distance) const { + return iter.AdvanceAcrossSegments(bufList_, distance); + } + + bool ReadBytes(Iterator& iter, char* buffer, size_t size) const { + return bufList_.ReadBytes(iter, buffer, size); + } + + // Append new data to the end of the buffer. + bool AppendBytes(const char* data, size_t size) { + MOZ_ASSERT(scope_ != JS::StructuredCloneScope::Unassigned); + return bufList_.WriteBytes(data, size); + } + + // Update data stored within the existing buffer. There must be at least + // 'size' bytes between the position of 'iter' and the end of the buffer. + bool UpdateBytes(Iterator& iter, const char* data, size_t size) const { + MOZ_ASSERT(scope_ != JS::StructuredCloneScope::Unassigned); + while (size > 0) { + size_t remaining = iter.RemainingInSegment(); + size_t nbytes = std::min(remaining, size); + memcpy(iter.Data(), data, nbytes); + data += nbytes; + size -= nbytes; + iter.Advance(bufList_, nbytes); + } + return true; + } + + void Clear() { + discardTransferables(); + bufList_.Clear(); + } + + // Return a new read-only JSStructuredCloneData that "borrows" the contents + // of |this|. Its lifetime should not exceed the donor's. This is only + // allowed for DifferentProcess clones, so finalization of the borrowing + // clone will do nothing. + JSStructuredCloneData Borrow(Iterator& iter, size_t size, bool* success) const + { + MOZ_ASSERT(scope_ == JS::StructuredCloneScope::DifferentProcess); + return JSStructuredCloneData(bufList_.Borrow(iter, size, success), + scope_); + } + + // Iterate over all contained data, one BufferList segment's worth at a + // time, and invoke the given FunctionToApply with the data pointer and + // size. The function should return a bool value, and this loop will exit + // with false if the function ever returns false. + template + bool ForEachDataChunk(FunctionToApply&& function) const { + Iterator iter = bufList_.Iter(); + while (!iter.Done()) { + if (!function(iter.Data(), iter.RemainingInSegment())) + return false; + iter.Advance(bufList_, iter.RemainingInSegment()); + } + return true; + } + + // Append the entire contents of other's bufList_ to our own. + bool Append(const JSStructuredCloneData& other) { + MOZ_ASSERT(scope_ == other.scope_); + return other.ForEachDataChunk([&](const char* data, size_t size) { + return AppendBytes(data, size); + }); + } + + void discardTransferables(); +}; + /** Note: if the *data contains transferable objects, it can be read only once. */ JS_PUBLIC_API(bool) -JS_ReadStructuredClone(JSContext* cx, uint64_t* data, size_t nbytes, uint32_t version, +JS_ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data, uint32_t version, + JS::StructuredCloneScope scope, JS::MutableHandleValue vp, const JSStructuredCloneCallbacks* optionalCallbacks, void* closure); -/** - * Note: On success, the caller is responsible for calling - * JS_ClearStructuredClone(*datap, nbytes, optionalCallbacks, closure). - */ JS_PUBLIC_API(bool) -JS_WriteStructuredClone(JSContext* cx, JS::HandleValue v, uint64_t** datap, size_t* nbytesp, +JS_WriteStructuredClone(JSContext* cx, JS::HandleValue v, JSStructuredCloneData* data, + JS::StructuredCloneScope scope, + JS::CloneDataPolicy cloneDataPolicy, const JSStructuredCloneCallbacks* optionalCallbacks, void* closure, JS::HandleValue transferable); JS_PUBLIC_API(bool) -JS_ClearStructuredClone(uint64_t* data, size_t nbytes, - const JSStructuredCloneCallbacks* optionalCallbacks, - void *closure, bool freeData = true); - -JS_PUBLIC_API(bool) -JS_StructuredCloneHasTransferables(const uint64_t* data, size_t nbytes, bool* hasTransferable); +JS_StructuredCloneHasTransferables(JSStructuredCloneData& data, bool* hasTransferable); JS_PUBLIC_API(bool) JS_StructuredClone(JSContext* cx, JS::HandleValue v, JS::MutableHandleValue vp, const JSStructuredCloneCallbacks* optionalCallbacks, void* closure); -/** RAII sugar for JS_WriteStructuredClone. */ +/** + * The C-style API calls to read and write structured clones are fragile -- + * they rely on the caller to properly handle ownership of the clone data, and + * the handling of the input data as well as the interpretation of the contents + * of the clone buffer are dependent on the callbacks passed in. If you + * serialize and deserialize with different callbacks, the results are + * questionable. + * + * JSAutoStructuredCloneBuffer wraps things up in an RAII class for data + * management, and uses the same callbacks for both writing and reading + * (serializing and deserializing). + */ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) { - uint64_t* data_; - size_t nbytes_; + const JS::StructuredCloneScope scope_; + JSStructuredCloneData data_; uint32_t version_; - enum { - OwnsTransferablesIfAny, - IgnoreTransferablesIfAny, - NoTransferables - } ownTransferables_; - - const JSStructuredCloneCallbacks* callbacks_; - void* closure_; public: - JSAutoStructuredCloneBuffer() - : data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION), - ownTransferables_(NoTransferables), - callbacks_(nullptr), closure_(nullptr) - {} - - JSAutoStructuredCloneBuffer(const JSStructuredCloneCallbacks* callbacks, void* closure) - : data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION), - ownTransferables_(NoTransferables), - callbacks_(callbacks), closure_(closure) - {} + JSAutoStructuredCloneBuffer(JS::StructuredCloneScope aScope, + const JSStructuredCloneCallbacks* callbacks, void* closure) + : scope_(aScope), data_(aScope), version_(JS_STRUCTURED_CLONE_VERSION) + { + data_.setCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables); + } JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other); JSAutoStructuredCloneBuffer& operator=(JSAutoStructuredCloneBuffer&& other); ~JSAutoStructuredCloneBuffer() { clear(); } - uint64_t* data() const { return data_; } - size_t nbytes() const { return nbytes_; } + JSStructuredCloneData& data() { return data_; } + bool empty() const { return !data_.Size(); } - void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr); + void clear(); - /** Copy some memory. It will be automatically freed by the destructor. */ - bool copy(const uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION, - const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr); + JS::StructuredCloneScope scope() const { return scope_; } /** * Adopt some memory. It will be automatically freed by the destructor. * data must have been allocated by the JS engine (e.g., extracted via * JSAutoStructuredCloneBuffer::steal). */ - void adopt(uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION, + void adopt(JSStructuredCloneData&& data, uint32_t version=JS_STRUCTURED_CLONE_VERSION, const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr); /** - * Release the buffer and transfer ownership to the caller. The caller is - * responsible for calling JS_ClearStructuredClone or feeding the memory - * back to JSAutoStructuredCloneBuffer::adopt. + * Release the buffer and transfer ownership to the caller. */ - void steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp=nullptr, + void steal(JSStructuredCloneData* data, uint32_t* versionp=nullptr, const JSStructuredCloneCallbacks** callbacks=nullptr, void** closure=nullptr); /** * Abandon ownership of any transferable objects stored in the buffer, * without freeing the buffer itself. Useful when copying the data out into - * an external container, though note that you will need to use adopt() or - * JS_ClearStructuredClone to properly release that data eventually. + * an external container, though note that you will need to use adopt() to + * properly release that data eventually. */ - void abandon() { ownTransferables_ = IgnoreTransferablesIfAny; } + void abandon() { data_.ownTransferables_ = OwnTransferablePolicy::IgnoreTransferablesIfAny; } bool read(JSContext* cx, JS::MutableHandleValue vp, const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr); @@ -244,6 +456,7 @@ const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr); bool write(JSContext* cx, JS::HandleValue v, JS::HandleValue transferable, + JS::CloneDataPolicy cloneDataPolicy, const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr); private: @@ -259,6 +472,7 @@ #define JS_SCERR_RECURSION 0 #define JS_SCERR_TRANSFERABLE 1 #define JS_SCERR_DUP_TRANSFERABLE 2 +#define JS_SCERR_UNSUPPORTED_TYPE 3 JS_PUBLIC_API(bool) JS_ReadUint32Pair(JSStructuredCloneReader* r, uint32_t* p1, uint32_t* p2); @@ -281,4 +495,10 @@ JS_PUBLIC_API(bool) JS_WriteTypedArray(JSStructuredCloneWriter* w, JS::HandleValue v); +JS_PUBLIC_API(bool) +JS_ObjectNotWritten(JSStructuredCloneWriter* w, JS::HandleObject obj); + +JS_PUBLIC_API(JS::StructuredCloneScope) +JS_GetStructuredCloneScope(JSStructuredCloneWriter* w); + #endif /* js_StructuredClone_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/SweepingAPI.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/SweepingAPI.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/SweepingAPI.h @@ -0,0 +1,65 @@ +/* -*- 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_SweepingAPI_h +#define js_SweepingAPI_h + +#include "js/HeapAPI.h" + +namespace js { +template +class WeakCacheBase {}; +} // namespace js + +namespace JS { +template class WeakCache; + +namespace shadow { +JS_PUBLIC_API(void) +RegisterWeakCache(JS::Zone* zone, JS::WeakCache* cachep); +} // namespace shadow + +// A WeakCache stores the given Sweepable container and links itself into a +// list of such caches that are swept during each GC. +template +class WeakCache : public js::WeakCacheBase, + private mozilla::LinkedListElement> +{ + friend class mozilla::LinkedListElement>; + friend class mozilla::LinkedList>; + + WeakCache() = delete; + WeakCache(const WeakCache&) = delete; + + using SweepFn = void (*)(T*); + SweepFn sweeper; + T cache; + + public: + using Type = T; + + template + WeakCache(Zone* zone, U&& initial) + : cache(mozilla::Forward(initial)) + { + sweeper = GCPolicy::sweep; + shadow::RegisterWeakCache(zone, reinterpret_cast*>(this)); + } + WeakCache(WeakCache&& other) + : sweeper(other.sweeper), + cache(mozilla::Move(other.cache)) + { + } + + const T& get() const { return cache; } + T& get() { return cache; } + + void sweep() { sweeper(&cache); } +}; + +} // namespace JS + +#endif // js_SweepingAPI_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/TraceKind.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/TraceKind.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/TraceKind.h @@ -7,6 +7,8 @@ #ifndef js_TraceKind_h #define js_TraceKind_h +#include "mozilla/UniquePtr.h" + #include "js/TypeDecls.h" // Forward declarations of all the types a TraceKind can denote. @@ -15,6 +17,7 @@ class LazyScript; class ObjectGroup; class Shape; +class Scope; namespace jit { class JitCode; } // namespace jit @@ -53,18 +56,31 @@ // The following kinds do not have an exposed C++ idiom. BaseShape = 0x0F, JitCode = 0x1F, - LazyScript = 0x2F + LazyScript = 0x2F, + Scope = 0x3F }; const static uintptr_t OutOfLineTraceKindMask = 0x07; static_assert(uintptr_t(JS::TraceKind::BaseShape) & OutOfLineTraceKindMask, "mask bits are set"); static_assert(uintptr_t(JS::TraceKind::JitCode) & OutOfLineTraceKindMask, "mask bits are set"); static_assert(uintptr_t(JS::TraceKind::LazyScript) & OutOfLineTraceKindMask, "mask bits are set"); +static_assert(uintptr_t(JS::TraceKind::Scope) & OutOfLineTraceKindMask, "mask bits are set"); + +// When this header is imported inside SpiderMonkey, the class definitions are +// available and we can query those definitions to find the correct kind +// directly from the class hierarchy. +template +struct MapTypeToTraceKind { + static const JS::TraceKind kind = T::TraceKind; +}; +// When this header is used outside SpiderMonkey, the class definitions are not +// available, so the following table containing all public GC types is used. #define JS_FOR_EACH_TRACEKIND(D) \ /* PrettyName TypeName AddToCCKind */ \ D(BaseShape, js::BaseShape, true) \ D(JitCode, js::jit::JitCode, true) \ D(LazyScript, js::LazyScript, true) \ + D(Scope, js::Scope, true) \ D(Object, JSObject, true) \ D(ObjectGroup, js::ObjectGroup, true) \ D(Script, JSScript, true) \ @@ -72,8 +88,7 @@ D(String, JSString, false) \ D(Symbol, JS::Symbol, false) -// Map from base trace type to the trace kind. -template struct MapTypeToTraceKind {}; +// Map from all public types to their trace kind. #define JS_EXPAND_DEF(name, type, _) \ template <> struct MapTypeToTraceKind { \ static const JS::TraceKind kind = JS::TraceKind::name; \ @@ -81,6 +96,60 @@ JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); #undef JS_EXPAND_DEF +// RootKind is closely related to TraceKind. Whereas TraceKind's indices are +// laid out for convenient embedding as a pointer tag, the indicies of RootKind +// are designed for use as array keys via EnumeratedArray. +enum class RootKind : int8_t +{ + // These map 1:1 with trace kinds. +#define EXPAND_ROOT_KIND(name, _0, _1) \ + name, +JS_FOR_EACH_TRACEKIND(EXPAND_ROOT_KIND) +#undef EXPAND_ROOT_KIND + + // These tagged pointers are special-cased for performance. + Id, + Value, + + // Everything else. + Traceable, + + Limit +}; + +// Most RootKind correspond directly to a trace kind. +template struct MapTraceKindToRootKind {}; +#define JS_EXPAND_DEF(name, _0, _1) \ + template <> struct MapTraceKindToRootKind { \ + static const JS::RootKind kind = JS::RootKind::name; \ + }; +JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF) +#undef JS_EXPAND_DEF + +// Specify the RootKind for all types. Value and jsid map to special cases; +// pointer types we can derive directly from the TraceKind; everything else +// should go in the Traceable list and use GCPolicy::trace for tracing. +template +struct MapTypeToRootKind { + static const JS::RootKind kind = JS::RootKind::Traceable; +}; +template +struct MapTypeToRootKind { + static const JS::RootKind kind = + JS::MapTraceKindToRootKind::kind>::kind; +}; +template +struct MapTypeToRootKind> { + static const JS::RootKind kind = JS::MapTypeToRootKind::kind; +}; +template <> struct MapTypeToRootKind { + static const JS::RootKind kind = JS::RootKind::Value; +}; +template <> struct MapTypeToRootKind { + static const JS::RootKind kind = JS::RootKind::Id; +}; +template <> struct MapTypeToRootKind : public MapTypeToRootKind {}; + // Fortunately, few places in the system need to deal with fully abstract // cells. In those places that do, we generally want to move to a layout // templated function as soon as possible. This template wraps the upcast Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/TraceableVector.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/TraceableVector.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/TraceableVector.h @@ -1,239 +0,0 @@ -/* -*- 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_TraceableVector_h -#define js_TraceableVector_h - -#include "mozilla/Vector.h" - -#include "js/RootingAPI.h" -#include "js/TracingAPI.h" -#include "js/Vector.h" - -namespace js { - -// A TraceableVector is a Vector with an additional trace method that knows how -// to visit all of the items stored in the Vector. For vectors that contain GC -// things, this is usually more convenient than manually iterating and marking -// the contents. -// -// Most types of GC pointers as keys and values can be traced with no extra -// infrastructure. For structs and non-gc-pointer members, ensure that there -// is a specialization of DefaultGCPolicy with an appropriate trace method -// available to handle the custom type. Generic helpers can be found in -// js/public/TracingAPI.h. -// -// Note that although this Vector's trace will deal correctly with moved items, -// it does not itself know when to barrier or trace items. To function properly -// it must either be used with Rooted, or barriered and traced manually. -template > -class TraceableVector : public JS::Traceable -{ - mozilla::Vector vector; - - public: - explicit TraceableVector(AllocPolicy alloc = AllocPolicy()) - : vector(alloc) - {} - - TraceableVector(TraceableVector&& vec) - : vector(mozilla::Move(vec.vector)) - {} - - TraceableVector& operator=(TraceableVector&& vec) { - vector = mozilla::Move(vec.vector); - return *this; - } - - size_t length() const { return vector.length(); } - bool empty() const { return vector.empty(); } - size_t capacity() const { return vector.capacity(); } - - T* begin() { return vector.begin(); } - const T* begin() const { return vector.begin(); } - - T* end() { return vector.end(); } - const T* end() const { return vector.end(); } - - T& operator[](size_t i) { return vector[i]; } - const T& operator[](size_t i) const { return vector[i]; } - - T& back() { return vector.back(); } - const T& back() const { return vector.back(); } - - bool initCapacity(size_t cap) { return vector.initCapacity(cap); } - bool reserve(size_t req) { return vector.reserve(req); } - void shrinkBy(size_t amount) { return vector.shrinkBy(amount); } - bool growBy(size_t amount) { return vector.growBy(amount); } - bool resize(size_t newLen) { return vector.resize(newLen); } - - void clear() { return vector.clear(); } - - template bool append(U&& item) { return vector.append(mozilla::Forward(item)); } - - template - bool - emplaceBack(Args&&... args) { - return vector.emplaceBack(mozilla::Forward(args)...); - } - - template - void infallibleAppend(U&& aU) { - return vector.infallibleAppend(mozilla::Forward(aU)); - } - void infallibleAppendN(const T& aT, size_t aN) { - return vector.infallibleAppendN(aT, aN); - } - template void - infallibleAppend(const U* aBegin, const U* aEnd) { - return vector.infallibleAppend(aBegin, aEnd); - } - template void infallibleAppend(const U* aBegin, size_t aLength) { - return vector.infallibleAppend(aBegin, aLength); - } - - bool appendN(const T& val, size_t count) { return vector.appendN(val, count); } - - template bool append(const U* aBegin, const U* aEnd) { - return vector.append(aBegin, aEnd); - } - template bool append(const U* aBegin, size_t aLength) { - return vector.append(aBegin, aLength); - } - - void popBack() { return vector.popBack(); } - T popCopy() { return vector.popCopy(); } - - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return vector.sizeOfExcludingThis(mallocSizeOf); - } - - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return vector.sizeOfIncludingThis(mallocSizeOf); - } - - static void trace(TraceableVector* vec, JSTracer* trc) { vec->trace(trc); } - - void trace(JSTracer* trc) { - for (auto& elem : vector) - GCPolicy::trace(trc, &elem, "vector element"); - } -}; - -template -class TraceableVectorOperations -{ - using Vec = TraceableVector; - const Vec& vec() const { return static_cast(this)->get(); } - - public: - const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); } - size_t length() const { return vec().length(); } - bool empty() const { return vec().empty(); } - size_t capacity() const { return vec().capacity(); } - const T* begin() const { return vec().begin(); } - const T* end() const { return vec().end(); } - const T& back() const { return vec().back(); } - bool canAppendWithoutRealloc(size_t aNeeded) const { return vec().canAppendWithoutRealloc(); } - - JS::Handle operator[](size_t aIndex) const { - return JS::Handle::fromMarkedLocation(&vec().operator[](aIndex)); - } -}; - -template -class MutableTraceableVectorOperations - : public TraceableVectorOperations -{ - using Vec = TraceableVector; - const Vec& vec() const { return static_cast(this)->get(); } - Vec& vec() { return static_cast(this)->get(); } - - public: - const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); } - AllocPolicy& allocPolicy() { return vec().allocPolicy(); } - const T* begin() const { return vec().begin(); } - T* begin() { return vec().begin(); } - const T* end() const { return vec().end(); } - T* end() { return vec().end(); } - const T& operator[](size_t aIndex) const { return vec().operator[](aIndex); } - const T& back() const { return vec().back(); } - T& back() { return vec().back(); } - - JS::MutableHandle operator[](size_t aIndex) { - return JS::MutableHandle::fromMarkedLocation(&vec().operator[](aIndex)); - } - - bool initCapacity(size_t aRequest) { return vec().initCapacity(aRequest); } - bool reserve(size_t aRequest) { return vec().reserve(aRequest); } - void shrinkBy(size_t aIncr) { vec().shrinkBy(aIncr); } - bool growBy(size_t aIncr) { return vec().growBy(aIncr); } - bool resize(size_t aNewLength) { return vec().resize(aNewLength); } - bool growByUninitialized(size_t aIncr) { return vec().growByUninitialized(aIncr); } - void infallibleGrowByUninitialized(size_t aIncr) { vec().infallibleGrowByUninitialized(aIncr); } - bool resizeUninitialized(size_t aNewLength) { return vec().resizeUninitialized(aNewLength); } - void clear() { vec().clear(); } - void clearAndFree() { vec().clearAndFree(); } - template bool append(U&& aU) { return vec().append(mozilla::Forward(aU)); } - template bool emplaceBack(Args&&... aArgs) { - return vec().emplaceBack(mozilla::Forward(aArgs...)); - } - template - bool appendAll(const mozilla::Vector& aU) { return vec().appendAll(aU); } - bool appendN(const T& aT, size_t aN) { return vec().appendN(aT, aN); } - template bool append(const U* aBegin, const U* aEnd) { - return vec().append(aBegin, aEnd); - } - template bool append(const U* aBegin, size_t aLength) { - return vec().append(aBegin, aLength); - } - template void infallibleAppend(U&& aU) { - vec().infallibleAppend(mozilla::Forward(aU)); - } - void infallibleAppendN(const T& aT, size_t aN) { vec().infallibleAppendN(aT, aN); } - template void infallibleAppend(const U* aBegin, const U* aEnd) { - vec().infallibleAppend(aBegin, aEnd); - } - template void infallibleAppend(const U* aBegin, size_t aLength) { - vec().infallibleAppend(aBegin, aLength); - } - void popBack() { vec().popBack(); } - T popCopy() { return vec().popCopy(); } - template T* insert(T* aP, U&& aVal) { - return vec().insert(aP, mozilla::Forward(aVal)); - } - void erase(T* aT) { vec().erase(aT); } - void erase(T* aBegin, T* aEnd) { vec().erase(aBegin, aEnd); } -}; - -template -class RootedBase> - : public MutableTraceableVectorOperations>, T,N,AP,GP> -{}; - -template -class MutableHandleBase> - : public MutableTraceableVectorOperations>, - T,N,AP,GP> -{}; - -template -class HandleBase> - : public TraceableVectorOperations>, T,N,AP,GP> -{}; - -template -class PersistentRootedBase> - : public MutableTraceableVectorOperations>, - T,N,AP,GP> -{}; - -} // namespace js - -#endif // js_TraceableVector_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/TracingAPI.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/TracingAPI.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/TracingAPI.h @@ -27,13 +27,15 @@ } // namespace JS enum WeakMapTraceKind { - /** Do true ephemeron marking with an iterative weak marking phase. */ + /** + * Do not trace into weak map keys or values during traversal. Users must + * handle weak maps manually. + */ DoNotTraceWeakMaps, /** * Do true ephemeron marking with a weak key lookup marking phase. This is - * expected to be constant for the lifetime of a JSTracer; it does not - * change when switching from "plain" marking to weak marking. + * the default for GCMarker. */ ExpandWeakMaps, @@ -59,11 +61,24 @@ // Return the weak map tracing behavior currently set on this tracer. WeakMapTraceKind weakMapAction() const { return weakMapAction_; } - // An intermediate state on the road from C to C++ style dispatch. enum class TracerKindTag { + // Marking path: a tracer used only for marking liveness of cells, not + // for moving them. The kind will transition to WeakMarking after + // everything reachable by regular edges has been marked. Marking, - WeakMarking, // In weak marking phase: looking up every marked obj/script. + + // Same as Marking, except we have now moved on to the "weak marking + // phase", in which every marked obj/script is immediately looked up to + // see if it is a weak map key (and therefore might require marking its + // weak map value). + WeakMarking, + + // A tracer that traverses the graph for the purposes of moving objects + // from the nursery to the tenured area. Tenuring, + + // General-purpose traversal that invokes a callback on each cell. + // Traversing children is the responsibility of the callback. Callback }; bool isMarkingTracer() const { return tag_ == TracerKindTag::Marking || tag_ == TracerKindTag::WeakMarking; } @@ -71,19 +86,37 @@ bool isTenuringTracer() const { return tag_ == TracerKindTag::Tenuring; } bool isCallbackTracer() const { return tag_ == TracerKindTag::Callback; } inline JS::CallbackTracer* asCallbackTracer(); +#ifdef DEBUG + bool checkEdges() { return checkEdges_; } +#endif protected: JSTracer(JSRuntime* rt, TracerKindTag tag, WeakMapTraceKind weakTraceKind = TraceWeakMapValues) - : runtime_(rt), weakMapAction_(weakTraceKind), tag_(tag) + : runtime_(rt) + , weakMapAction_(weakTraceKind) +#ifdef DEBUG + , checkEdges_(true) +#endif + , tag_(tag) {} +#ifdef DEBUG + // Set whether to check edges are valid in debug builds. + void setCheckEdges(bool check) { + checkEdges_ = check; + } +#endif + private: - JSRuntime* runtime_; - WeakMapTraceKind weakMapAction_; + JSRuntime* runtime_; + WeakMapTraceKind weakMapAction_; +#ifdef DEBUG + bool checkEdges_; +#endif protected: - TracerKindTag tag_; + TracerKindTag tag_; }; namespace JS { @@ -99,6 +132,7 @@ : JSTracer(rt, JSTracer::TracerKindTag::Callback, weakTraceKind), contextName_(nullptr), contextIndex_(InvalidIndex), contextFunctor_(nullptr) {} + CallbackTracer(JSContext* cx, WeakMapTraceKind weakTraceKind = TraceWeakMapValues); // Override these methods to receive notification when an edge is visited // with the type contained in the callback. The default implementation @@ -124,6 +158,9 @@ virtual void onLazyScriptEdge(js::LazyScript** lazyp) { onChild(JS::GCCellPtr(*lazyp, JS::TraceKind::LazyScript)); } + virtual void onScopeEdge(js::Scope** scopep) { + onChild(JS::GCCellPtr(*scopep, JS::TraceKind::Scope)); + } // Override this method to receive notification when a node in the GC // heap graph is visited. @@ -193,6 +230,7 @@ void dispatchToOnEdge(js::BaseShape** basep) { onBaseShapeEdge(basep); } void dispatchToOnEdge(js::jit::JitCode** codep) { onJitCodeEdge(codep); } void dispatchToOnEdge(js::LazyScript** lazyp) { onLazyScriptEdge(lazyp); } + void dispatchToOnEdge(js::Scope** scopep) { onScopeEdge(scopep); } private: friend class AutoTracingName; @@ -281,151 +319,85 @@ return static_cast(this); } -// The JS_Call*Tracer family of functions traces the given GC thing reference. -// This performs the tracing action configured on the given JSTracer: -// typically calling the JSTracer::callback or marking the thing as live. +namespace JS { + +// The JS::TraceEdge family of functions traces the given GC thing reference. +// This performs the tracing action configured on the given JSTracer: typically +// calling the JSTracer::callback or marking the thing as live. // -// The argument to JS_Call*Tracer is an in-out param: when the function -// returns, the garbage collector might have moved the GC thing. In this case, -// the reference passed to JS_Call*Tracer will be updated to the object's new -// location. Callers of this method are responsible for updating any state -// that is dependent on the object's address. For example, if the object's -// address is used as a key in a hashtable, then the object must be removed -// and re-inserted with the correct hash. +// The argument to JS::TraceEdge is an in-out param: when the function returns, +// the garbage collector might have moved the GC thing. In this case, the +// reference passed to JS::TraceEdge will be updated to the thing's new +// location. Callers of this method are responsible for updating any state that +// is dependent on the object's address. For example, if the object's address +// is used as a key in a hashtable, then the object must be removed and +// re-inserted with the correct hash. // -extern JS_PUBLIC_API(void) -JS_CallValueTracer(JSTracer* trc, JS::Heap* valuep, const char* name); - -extern JS_PUBLIC_API(void) -JS_CallIdTracer(JSTracer* trc, JS::Heap* idp, const char* name); - -extern JS_PUBLIC_API(void) -JS_CallObjectTracer(JSTracer* trc, JS::Heap* objp, const char* name); - -extern JS_PUBLIC_API(void) -JS_CallStringTracer(JSTracer* trc, JS::Heap* strp, const char* name); - -extern JS_PUBLIC_API(void) -JS_CallScriptTracer(JSTracer* trc, JS::Heap* scriptp, const char* name); - -extern JS_PUBLIC_API(void) -JS_CallFunctionTracer(JSTracer* trc, JS::Heap* funp, const char* name); - -namespace JS { +// Note that while |edgep| must never be null, it is fine for |*edgep| to be +// nullptr. template extern JS_PUBLIC_API(void) TraceEdge(JSTracer* trc, JS::Heap* edgep, const char* name); -} // namespace JS - -// The following JS_CallUnbarriered*Tracer functions should only be called where -// you know for sure that a heap post barrier is not required. Use with extreme -// caution! -extern JS_PUBLIC_API(void) -JS_CallUnbarrieredValueTracer(JSTracer* trc, JS::Value* valuep, const char* name); extern JS_PUBLIC_API(void) -JS_CallUnbarrieredIdTracer(JSTracer* trc, jsid* idp, const char* name); +TraceEdge(JSTracer* trc, JS::TenuredHeap* edgep, const char* name); +// Edges that are always traced as part of root marking do not require +// incremental barriers. This function allows for marking non-barriered +// pointers, but asserts that this happens during root marking. +// +// Note that while |edgep| must never be null, it is fine for |*edgep| to be +// nullptr. +template extern JS_PUBLIC_API(void) -JS_CallUnbarrieredObjectTracer(JSTracer* trc, JSObject** objp, const char* name); +UnsafeTraceRoot(JSTracer* trc, T* edgep, const char* name); extern JS_PUBLIC_API(void) -JS_CallUnbarrieredStringTracer(JSTracer* trc, JSString** strp, const char* name); +TraceChildren(JSTracer* trc, GCCellPtr thing); -extern JS_PUBLIC_API(void) -JS_CallUnbarrieredScriptTracer(JSTracer* trc, JSScript** scriptp, const char* name); +using ZoneSet = js::HashSet, js::SystemAllocPolicy>; +using CompartmentSet = js::HashSet, + js::SystemAllocPolicy>; /** - * Trace an object that is known to always be tenured. No post barriers are - * required in this case. + * Trace every value within |compartments| that is wrapped by a + * cross-compartment wrapper from a compartment that is not an element of + * |compartments|. */ extern JS_PUBLIC_API(void) -JS_CallTenuredObjectTracer(JSTracer* trc, JS::TenuredHeap* objp, const char* name); +TraceIncomingCCWs(JSTracer* trc, const JS::CompartmentSet& compartments); -extern JS_PUBLIC_API(void) -JS_TraceRuntime(JSTracer* trc); - -namespace JS { -extern JS_PUBLIC_API(void) -TraceChildren(JSTracer* trc, GCCellPtr thing); - -typedef js::HashSet, js::SystemAllocPolicy> ZoneSet; } // namespace JS -/** - * Trace every value within |zones| that is wrapped by a cross-compartment - * wrapper from a zone that is not an element of |zones|. - */ -extern JS_PUBLIC_API(void) -JS_TraceIncomingCCWs(JSTracer* trc, const JS::ZoneSet& zones); - extern JS_PUBLIC_API(void) JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, void* thing, JS::TraceKind kind, bool includeDetails); namespace js { -namespace gc { -template -extern JS_PUBLIC_API(bool) -EdgeNeedsSweep(JS::Heap* edgep); -} // namespace gc -// Automates static dispatch for GC interaction with TraceableContainers. -template -struct DefaultGCPolicy; - -// This policy dispatches GC methods to a method on the type. +// Trace an edge that is not a GC root and is not wrapped in a barriered +// wrapper for some reason. +// +// This method does not check if |*edgep| is non-null before tracing through +// it, so callers must check any nullable pointer before calling this method. template -struct StructGCPolicy { - static void trace(JSTracer* trc, T* t, const char* name) { - // This is the default GC policy for storing GC things in containers. - // If your build is failing here, it means you either need an - // implementation of DefaultGCPolicy for your type or, if this is - // the right policy for you, your struct or container is missing a - // trace method. - t->trace(trc); - } - - static bool needsSweep(T* t) { - return t->needsSweep(); - } -}; +extern JS_PUBLIC_API(void) +UnsafeTraceManuallyBarrieredEdge(JSTracer* trc, T* edgep, const char* name); -// This policy ignores any GC interaction, e.g. for non-GC types. -template -struct IgnoreGCPolicy { - static void trace(JSTracer* trc, T* t, const char* name) {} - static bool needsSweep(T* v) { return false; } -}; +namespace gc { -// The default policy when no other more specific policy fits (e.g. for a -// direct GC pointer), is to assume a struct type that implements the needed -// methods. +// Return true if the given edge is not live and is about to be swept. template -struct DefaultGCPolicy : public StructGCPolicy {}; - -template <> -struct DefaultGCPolicy -{ - static void trace(JSTracer* trc, jsid* id, const char* name) { - JS_CallUnbarrieredIdTracer(trc, id, name); - } -}; - -template <> struct DefaultGCPolicy : public IgnoreGCPolicy {}; -template <> struct DefaultGCPolicy : public IgnoreGCPolicy {}; +extern JS_PUBLIC_API(bool) +EdgeNeedsSweep(JS::Heap* edgep); +// Not part of the public API, but declared here so we can use it in GCPolicy +// which is. template -struct DefaultGCPolicy> -{ - static void trace(JSTracer* trc, JS::Heap* thingp, const char* name) { - JS::TraceEdge(trc, thingp, name); - } - static bool needsSweep(JS::Heap* thingp) { - return gc::EdgeNeedsSweep(thingp); - } -}; +bool +IsAboutToBeFinalizedUnbarriered(T* thingp); +} // namespace gc } // namespace js #endif /* js_TracingAPI_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/TrackedOptimizationInfo.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/TrackedOptimizationInfo.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/TrackedOptimizationInfo.h @@ -16,6 +16,7 @@ _(GetProp_ArgumentsCallee) \ _(GetProp_InferredConstant) \ _(GetProp_Constant) \ + _(GetProp_NotDefined) \ _(GetProp_StaticName) \ _(GetProp_SimdGetter) \ _(GetProp_TypedObject) \ @@ -51,6 +52,12 @@ _(SetElem_Arguments) \ _(SetElem_InlineCache) \ \ + _(BinaryArith_Concat) \ + _(BinaryArith_SpecializedTypes) \ + _(BinaryArith_SpecializedOnBaselineTypes) \ + _(BinaryArith_SharedCache) \ + _(BinaryArith_Call) \ + \ _(InlineCache_OptimizedStub) \ \ _(Call_Inline) @@ -74,6 +81,7 @@ _(NotObject) \ _(NotStruct) \ _(NotUnboxed) \ + _(NotUndefined) \ _(UnboxedConvertedToNative) \ _(StructNoField) \ _(InconsistentFieldType) \ @@ -88,13 +96,17 @@ _(ArrayDoubleConversion) \ _(ArrayRange) \ _(ArraySeenNegativeIndex) \ - _(TypedObjectNeutered) \ + _(TypedObjectHasDetachedBuffer) \ _(TypedObjectArrayRange) \ _(AccessNotDense) \ _(AccessNotSimdObject) \ _(AccessNotTypedObject) \ _(AccessNotTypedArray) \ _(AccessNotString) \ + _(OperandNotString) \ + _(OperandNotNumber) \ + _(OperandNotStringOrNumber) \ + _(OperandNotSimpleArith) \ _(StaticTypedArrayUint32) \ _(StaticTypedArrayCantComputeMask) \ _(OutOfBounds) \ @@ -144,6 +156,7 @@ \ _(ICNameStub_ReadSlot) \ _(ICNameStub_CallGetter) \ + _(ICNameStub_TypeOfNoProperty) \ \ _(CantInlineGeneric) \ _(CantInlineNoTarget) \ @@ -180,6 +193,7 @@ #define TRACKED_TYPESITE_LIST(_) \ _(Receiver) \ + _(Operand) \ _(Index) \ _(Value) \ _(Call_Target) \ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNode.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNode.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNode.h @@ -15,7 +15,6 @@ #include "mozilla/Move.h" #include "mozilla/RangedPtr.h" #include "mozilla/TypeTraits.h" -#include "mozilla/UniquePtr.h" #include "mozilla/Variant.h" #include "jspubtd.h" @@ -25,6 +24,7 @@ #include "js/RootingAPI.h" #include "js/TracingAPI.h" #include "js/TypeDecls.h" +#include "js/UniquePtr.h" #include "js/Value.h" #include "js/Vector.h" @@ -71,7 +71,7 @@ // One can construct a ubi::Node value given a pointer to a type that ubi::Node // supports. In the other direction, one can convert a ubi::Node back to a // pointer; these downcasts are checked dynamically. In particular, one can -// convert a 'JSRuntime*' to a ubi::Node, yielding a node with an outgoing edge +// convert a 'JSContext*' to a ubi::Node, yielding a node with an outgoing edge // for every root registered with the runtime; starting from this, one can walk // the entire heap. (Of course, one could also start traversal at any other kind // of type to which one has a pointer.) @@ -174,16 +174,6 @@ } // namespace ubi } // namespace JS -namespace mozilla { - -template<> -class DefaultDelete : public JS::DeletePolicy { }; - -template<> -class DefaultDelete : public JS::DeletePolicy { }; - -} // namespace mozilla - namespace JS { namespace ubi { @@ -191,9 +181,11 @@ using mozilla::Maybe; using mozilla::Move; using mozilla::RangedPtr; -using mozilla::UniquePtr; using mozilla::Variant; +template +using Vector = mozilla::Vector; + /*** ubi::StackFrame ******************************************************************************/ // Concrete JS::ubi::StackFrame instances backed by a live SavedFrame object @@ -201,7 +193,7 @@ // heap snapshots store their strings as const char16_t*. In order to provide // zero-cost accessors to these strings in a single interface that works with // both cases, we use this variant type. -class AtomOrTwoByteChars : public Variant { +class JS_PUBLIC_API(AtomOrTwoByteChars) : public Variant { using Base = Variant; public: @@ -267,7 +259,7 @@ // Return true if this frame's function is a self-hosted JavaScript builtin, // false otherwise. - virtual bool isSelfHosted() const = 0; + virtual bool isSelfHosted(JSContext* cx) const = 0; // Construct a SavedFrame stack for the stack starting with this frame and // containing all of its parents. The SavedFrame objects will be placed into @@ -294,8 +286,9 @@ // simplifies the principals check into the boolean isSystem() state. This // is fine because we only expose JS::ubi::Stack to devtools and chrome // code, and not to the web platform. - virtual bool constructSavedFrameStack(JSContext* cx, - MutableHandleObject outSavedFrameStack) const = 0; + virtual MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx, + MutableHandleObject outSavedFrameStack) + const = 0; // Trace the concrete implementation of JS::ubi::StackFrame. virtual void trace(JSTracer* trc) = 0; @@ -319,7 +312,7 @@ // valid within the scope of an AutoCheckCannotGC; if the graph being analyzed // is an offline heap snapshot, the JS::ubi::StackFrame is valid as long as the // offline heap snapshot is alive. -class StackFrame : public JS::Traceable { +class StackFrame { // Storage in which we allocate BaseStackFrame subclasses. mozilla::AlignedStorage2 storage; @@ -409,12 +402,6 @@ size_t sourceLength(); size_t functionDisplayNameLength(); - // JS::Traceable implementation just forwards to our virtual trace method. - static void trace(StackFrame* frame, JSTracer* trc) { - if (frame) - frame->trace(trc); - } - // Methods that forward to virtual calls through BaseStackFrame. void trace(JSTracer* trc) { base()->trace(trc); } @@ -429,9 +416,9 @@ AtomOrTwoByteChars functionDisplayName() const { return base()->functionDisplayName(); } StackFrame parent() const { return base()->parent(); } bool isSystem() const { return base()->isSystem(); } - bool isSelfHosted() const { return base()->isSelfHosted(); } - bool constructSavedFrameStack(JSContext* cx, - MutableHandleObject outSavedFrameStack) const { + bool isSelfHosted(JSContext* cx) const { return base()->isSelfHosted(cx); } + MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx, + MutableHandleObject outSavedFrameStack) const { return base()->constructSavedFrameStack(cx, outSavedFrameStack); } @@ -463,7 +450,9 @@ uint64_t identifier() const override { return 0; } void trace(JSTracer* trc) override { } - bool constructSavedFrameStack(JSContext* cx, MutableHandleObject out) const override { + MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx, MutableHandleObject out) + const override + { out.set(nullptr); return true; } @@ -474,11 +463,13 @@ AtomOrTwoByteChars functionDisplayName() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } StackFrame parent() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } bool isSystem() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } - bool isSelfHosted() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } + bool isSelfHosted(JSContext* cx) const override { MOZ_CRASH("null JS::ubi::StackFrame"); } }; -bool ConstructSavedFrameStackSlow(JSContext* cx, JS::ubi::StackFrame& frame, - MutableHandleObject outSavedFrameStack); +MOZ_MUST_USE JS_PUBLIC_API(bool) +ConstructSavedFrameStackSlow(JSContext* cx, + JS::ubi::StackFrame& frame, + MutableHandleObject outSavedFrameStack); /*** ubi::Node ************************************************************************************/ @@ -529,7 +520,7 @@ // The base class implemented by each ubi::Node referent type. Subclasses must // not add data members to this class. -class Base { +class JS_PUBLIC_API(Base) { friend class Node; // For performance's sake, we'd prefer to avoid a virtual destructor; and @@ -579,7 +570,7 @@ virtual CoarseType coarseType() const { return CoarseType::Other; } // Return a human-readable name for the referent's type. The result should - // be statically allocated. (You can use MOZ_UTF16("strings") for this.) + // be statically allocated. (You can use u"strings" for this.) // // This must always return Concrete::concreteTypeName; we use that // pointer as a tag for this particular referent type. @@ -589,6 +580,11 @@ // node owns exclusively that are not exposed as their own ubi::Nodes. // |mallocSizeOf| should be a malloc block sizing function; see // |mfbt/MemoryReporting.h|. + // + // Because we can use |JS::ubi::Node|s backed by a snapshot that was taken + // on a 64-bit platform when we are currently on a 32-bit platform, we + // cannot rely on |size_t| for node sizes. Instead, |Size| is uint64_t on + // all platforms. using Size = uint64_t; virtual Size size(mozilla::MallocSizeOf mallocSizeof) const { return 1; } @@ -597,7 +593,7 @@ // // If wantNames is true, compute names for edges. Doing so can be expensive // in time and memory. - virtual UniquePtr edges(JSRuntime* rt, bool wantNames) const = 0; + virtual js::UniquePtr edges(JSContext* cx, bool wantNames) const = 0; // Return the Zone to which this node's referent belongs, or nullptr if the // referent is not of a type allocated in SpiderMonkey Zones. @@ -633,8 +629,9 @@ // Otherwise, place nullptr in the out parameter. Caller maintains ownership // of the out parameter. True is returned on success, false is returned on // OOM. - virtual bool jsObjectConstructorName(JSContext* cx, - UniquePtr& outName) const { + virtual MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) + const + { outName.reset(nullptr); return true; } @@ -651,28 +648,28 @@ }; // A traits template with a specialization for each referent type that -// ubi::Node supports. The specialization must be the concrete subclass of -// Base that represents a pointer to the referent type. It must also -// include the members described here. +// ubi::Node supports. The specialization must be the concrete subclass of Base +// that represents a pointer to the referent type. It must include these +// members: +// +// // The specific char16_t array returned by Concrete::typeName(). +// static const char16_t concreteTypeName[]; +// +// // Construct an instance of this concrete class in |storage| referring +// // to |referent|. Implementations typically use a placement 'new'. +// // +// // In some cases, |referent| will contain dynamic type information that +// // identifies it a some more specific subclass of |Referent|. For +// // example, when |Referent| is |JSObject|, then |referent->getClass()| +// // could tell us that it's actually a JSFunction. Similarly, if +// // |Referent| is |nsISupports|, we would like a ubi::Node that knows its +// // final implementation type. +// // +// // So we delegate the actual construction to this specialization, which +// // knows Referent's details. +// static void construct(void* storage, Referent* referent); template -struct Concrete { - // The specific char16_t array returned by Concrete::typeName. - static const char16_t concreteTypeName[]; - - // Construct an instance of this concrete class in |storage| referring - // to |referent|. Implementations typically use a placement 'new'. - // - // In some cases, |referent| will contain dynamic type information that - // identifies it a some more specific subclass of |Referent|. For example, - // when |Referent| is |JSObject|, then |referent->getClass()| could tell us - // that it's actually a JSFunction. Similarly, if |Referent| is - // |nsISupports|, we would like a ubi::Node that knows its final - // implementation type. - // - // So, we delegate the actual construction to this specialization, which - // knows Referent's details. - static void construct(void* storage, Referent* referent); -}; +class Concrete; // A container for a Base instance; all members simply forward to the contained // instance. This container allows us to pass ubi::Node instances by value. @@ -686,6 +683,8 @@ void construct(T* ptr) { static_assert(sizeof(Concrete) == sizeof(*base()), "ubi::Base specializations must be the same size as ubi::Base"); + static_assert(mozilla::IsBaseOf>::value, + "ubi::Concrete must inherit from ubi::Base"); Concrete::construct(base(), ptr); } struct ConstructFunctor; @@ -780,8 +779,7 @@ JS::Zone* zone() const { return base()->zone(); } JSCompartment* compartment() const { return base()->compartment(); } const char* jsObjectClassName() const { return base()->jsObjectClassName(); } - bool jsObjectConstructorName(JSContext* cx, - UniquePtr& outName) const { + MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) const { return base()->jsObjectConstructorName(cx, outName); } @@ -796,8 +794,8 @@ return size; } - UniquePtr edges(JSRuntime* rt, bool wantNames = true) const { - return base()->edges(rt, wantNames); + js::UniquePtr edges(JSContext* cx, bool wantNames = true) const { + return base()->edges(cx, wantNames); } bool hasAllocationStack() const { return base()->hasAllocationStack(); } @@ -827,10 +825,12 @@ }; }; +using NodeSet = js::HashSet, js::SystemAllocPolicy>; +using NodeSetPtr = mozilla::UniquePtr>; /*** Edge and EdgeRange ***************************************************************************/ -using EdgeName = UniquePtr; +using EdgeName = UniqueTwoByteChars; // An outgoing edge to a referent node. class Edge { @@ -863,7 +863,8 @@ // false as the wantNames parameter. // // The storage is owned by this Edge, and will be freed when this Edge is - // destructed. + // destructed. You may take ownership of the name by `mozilla::Move`ing it + // out of the edge; it is just a UniquePtr. // // (In real life we'll want a better representation for names, to avoid // creating tons of strings when the names follow a pattern; and we'll need @@ -959,7 +960,7 @@ // // { // mozilla::Maybe maybeNoGC; -// JS::ubi::RootList rootList(rt, maybeNoGC); +// JS::ubi::RootList rootList(cx, maybeNoGC); // if (!rootList.init()) // return false; // @@ -970,22 +971,23 @@ // // ... // } -class MOZ_STACK_CLASS RootList { +class MOZ_STACK_CLASS JS_PUBLIC_API(RootList) { Maybe& noGC; public: - JSRuntime* rt; + JSContext* cx; EdgeVector edges; bool wantNames; - RootList(JSRuntime* rt, Maybe& noGC, bool wantNames = false); + RootList(JSContext* cx, Maybe& noGC, bool wantNames = false); // Find all GC roots. - bool init(); - // Find only GC roots in the provided set of |Zone|s. - bool init(ZoneSet& debuggees); - // Find only GC roots in the given Debugger object's set of debuggee zones. - bool init(HandleObject debuggees); + MOZ_MUST_USE bool init(); + // Find only GC roots in the provided set of |JSCompartment|s. + MOZ_MUST_USE bool init(CompartmentSet& debuggees); + // Find only GC roots in the given Debugger object's set of debuggee + // compartments. + MOZ_MUST_USE bool init(HandleObject debuggees); // Returns true if the RootList has been initialized successfully, false // otherwise. @@ -994,64 +996,53 @@ // Explicitly add the given Node as a root in this RootList. If wantNames is // true, you must pass an edgeName. The RootList does not take ownership of // edgeName. - bool addRoot(Node node, const char16_t* edgeName = nullptr); + MOZ_MUST_USE bool addRoot(Node node, const char16_t* edgeName = nullptr); }; /*** Concrete classes for ubi::Node referent types ************************************************/ template<> -struct Concrete : public Base { - UniquePtr edges(JSRuntime* rt, bool wantNames) const override; - const char16_t* typeName() const override { return concreteTypeName; } - +class JS_PUBLIC_API(Concrete) : public Base { protected: explicit Concrete(RootList* ptr) : Base(ptr) { } RootList& get() const { return *static_cast(ptr); } public: - static const char16_t concreteTypeName[]; static void construct(void* storage, RootList* ptr) { new (storage) Concrete(ptr); } + + js::UniquePtr edges(JSContext* cx, bool wantNames) const override; + + const char16_t* typeName() const override { return concreteTypeName; } + static const char16_t concreteTypeName[]; }; // A reusable ubi::Concrete specialization base class for types supported by // JS::TraceChildren. template -class TracerConcrete : public Base { - const char16_t* typeName() const override { return concreteTypeName; } - UniquePtr edges(JSRuntime* rt, bool wantNames) const override; +class JS_PUBLIC_API(TracerConcrete) : public Base { + js::UniquePtr edges(JSContext* cx, bool wantNames) const override; JS::Zone* zone() const override; protected: explicit TracerConcrete(Referent* ptr) : Base(ptr) { } Referent& get() const { return *static_cast(ptr); } - - public: - static const char16_t concreteTypeName[]; - static void construct(void* storage, Referent* ptr) { new (storage) TracerConcrete(ptr); } }; // For JS::TraceChildren-based types that have a 'compartment' method. template -class TracerConcreteWithCompartment : public TracerConcrete { +class JS_PUBLIC_API(TracerConcreteWithCompartment) : public TracerConcrete { typedef TracerConcrete TracerBase; JSCompartment* compartment() const override; protected: explicit TracerConcreteWithCompartment(Referent* ptr) : TracerBase(ptr) { } - - public: - static void construct(void* storage, Referent* ptr) { - new (storage) TracerConcreteWithCompartment(ptr); - } }; // Define specializations for some commonly-used public JSAPI types. // These can use the generic templates above. template<> -struct Concrete : TracerConcrete { - Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - +class JS_PUBLIC_API(Concrete) : TracerConcrete { protected: explicit Concrete(JS::Symbol* ptr) : TracerConcrete(ptr) { } @@ -1059,33 +1050,32 @@ static void construct(void* storage, JS::Symbol* ptr) { new (storage) Concrete(ptr); } -}; -template<> struct Concrete : TracerConcreteWithCompartment { - CoarseType coarseType() const final { return CoarseType::Script; } Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - const char* scriptFilename() const final; + const char16_t* typeName() const override { return concreteTypeName; } + static const char16_t concreteTypeName[]; +}; + +template<> +class JS_PUBLIC_API(Concrete) : TracerConcreteWithCompartment { protected: explicit Concrete(JSScript *ptr) : TracerConcreteWithCompartment(ptr) { } public: static void construct(void *storage, JSScript *ptr) { new (storage) Concrete(ptr); } -}; -// The JSObject specialization. -template<> -class Concrete : public TracerConcreteWithCompartment { - const char* jsObjectClassName() const override; - bool jsObjectConstructorName(JSContext* cx, - UniquePtr& outName) const override; + CoarseType coarseType() const final { return CoarseType::Script; } Size size(mozilla::MallocSizeOf mallocSizeOf) const override; + const char* scriptFilename() const final; - bool hasAllocationStack() const override; - StackFrame allocationStack() const override; - - CoarseType coarseType() const final { return CoarseType::Object; } + const char16_t* typeName() const override { return concreteTypeName; } + static const char16_t concreteTypeName[]; +}; +// The JSObject specialization. +template<> +class JS_PUBLIC_API(Concrete) : public TracerConcreteWithCompartment { protected: explicit Concrete(JSObject* ptr) : TracerConcreteWithCompartment(ptr) { } @@ -1093,27 +1083,44 @@ static void construct(void* storage, JSObject* ptr) { new (storage) Concrete(ptr); } -}; -// For JSString, we extend the generic template with a 'size' implementation. -template<> struct Concrete : TracerConcrete { + const char* jsObjectClassName() const override; + MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) + const override; Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - CoarseType coarseType() const final { return CoarseType::String; } + bool hasAllocationStack() const override; + StackFrame allocationStack() const override; + + CoarseType coarseType() const final { return CoarseType::Object; } + const char16_t* typeName() const override { return concreteTypeName; } + static const char16_t concreteTypeName[]; +}; + +// For JSString, we extend the generic template with a 'size' implementation. +template<> +class JS_PUBLIC_API(Concrete) : TracerConcrete { protected: explicit Concrete(JSString *ptr) : TracerConcrete(ptr) { } public: static void construct(void *storage, JSString *ptr) { new (storage) Concrete(ptr); } + + Size size(mozilla::MallocSizeOf mallocSizeOf) const override; + + CoarseType coarseType() const final { return CoarseType::String; } + + const char16_t* typeName() const override { return concreteTypeName; } + static const char16_t concreteTypeName[]; }; // The ubi::Node null pointer. Any attempt to operate on a null ubi::Node asserts. template<> -class Concrete : public Base { +class JS_PUBLIC_API(Concrete) : public Base { const char16_t* typeName() const override; Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - UniquePtr edges(JSRuntime* rt, bool wantNames) const override; + js::UniquePtr edges(JSContext* cx, bool wantNames) const override; JS::Zone* zone() const override; JSCompartment* compartment() const override; CoarseType coarseType() const final; @@ -1122,7 +1129,6 @@ public: static void construct(void* storage, void* ptr) { new (storage) Concrete(ptr); } - static const char16_t concreteTypeName[]; }; Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNodeBreadthFirst.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNodeBreadthFirst.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNodeBreadthFirst.h @@ -83,8 +83,8 @@ // // We do nothing with noGC, other than require it to exist, with a lifetime // that encloses our own. - BreadthFirst(JSRuntime* rt, Handler& handler, const JS::AutoCheckCannotGC& noGC) - : wantNames(true), rt(rt), visited(), handler(handler), pending(), + BreadthFirst(JSContext* cx, Handler& handler, const JS::AutoCheckCannotGC& noGC) + : wantNames(true), cx(cx), visited(), handler(handler), pending(), traversalBegun(false), stopRequested(false), abandonRequested(false) { } @@ -126,7 +126,7 @@ pending.popFront(); // Get a range containing all origin's outgoing edges. - auto range = origin.edges(rt, wantNames); + auto range = origin.edges(cx, wantNames); if (!range) return false; @@ -134,7 +134,7 @@ for (; !range->empty(); range->popFront()) { MOZ_ASSERT(!stopRequested); - const Edge& edge = range->front(); + Edge& edge = range->front(); typename NodeMap::AddPtr a = visited.lookupForAdd(edge.referent); bool first = !a; @@ -181,8 +181,8 @@ // Other edges *to* that referent will still be traversed. void abandonReferent() { abandonRequested = true; } - // The runtime with which we were constructed. - JSRuntime* rt; + // The context with which we were constructed. + JSContext* cx; // A map associating each node N that we have reached with a // Handler::NodeData, for |handler|'s use. This is public, so that Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNodeCensus.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNodeCensus.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNodeCensus.h @@ -7,8 +7,11 @@ #ifndef js_UbiNodeCensus_h #define js_UbiNodeCensus_h +#include "mozilla/Attributes.h" #include "mozilla/Move.h" +#include + #include "jsapi.h" #include "js/UbiNode.h" @@ -80,14 +83,14 @@ class CountBase; struct CountDeleter { - void operator()(CountBase*); + JS_PUBLIC_API(void) operator()(CountBase*); }; -using CountBasePtr = UniquePtr; +using CountBasePtr = js::UniquePtr; // Abstract base class for CountType nodes. struct CountType { - explicit CountType(Census& census) : census(census) { } + explicit CountType() { } virtual ~CountType() { } // Destruct a count tree node that this type instance constructed. @@ -102,17 +105,17 @@ // Implement the 'count' method for counts returned by this CountType // instance's 'newCount' method. - virtual bool count(CountBase& count, const Node& node) = 0; + virtual MOZ_MUST_USE bool count(CountBase& count, + mozilla::MallocSizeOf mallocSizeOf, + const Node& node) = 0; // Implement the 'report' method for counts returned by this CountType // instance's 'newCount' method. - virtual bool report(CountBase& count, MutableHandleValue report) = 0; - - protected: - Census& census; + virtual MOZ_MUST_USE bool report(JSContext* cx, CountBase& count, + MutableHandleValue report) = 0; }; -using CountTypePtr = UniquePtr>; +using CountTypePtr = js::UniquePtr; // An abstract base class for count tree nodes. class CountBase { @@ -126,15 +129,39 @@ ~CountBase() { } public: - explicit CountBase(CountType& type) : type(type), total_(0) { } + explicit CountBase(CountType& type) + : type(type) + , total_(0) + , smallestNodeIdCounted_(SIZE_MAX) + { } // Categorize and count |node| as appropriate for this count's type. - bool count(const Node& node) { return type.count(*this, node); } + MOZ_MUST_USE bool count(mozilla::MallocSizeOf mallocSizeOf, const Node& node) { + total_++; + + auto id = node.identifier(); + if (id < smallestNodeIdCounted_) { + smallestNodeIdCounted_ = id; + } + +#ifdef DEBUG + size_t oldTotal = total_; +#endif + + bool ret = type.count(*this, mallocSizeOf, node); + + MOZ_ASSERT(total_ == oldTotal, + "CountType::count should not increment total_, CountBase::count handles that"); + + return ret; + } // Construct a JavaScript object reporting the counts recorded in this // count, and store it in |report|. Return true on success, or false on // failure. - bool report(MutableHandleValue report) { return type.report(*this, report); } + MOZ_MUST_USE bool report(JSContext* cx, MutableHandleValue report) { + return type.report(cx, *this, report); + } // Down-cast this CountBase to its true type, based on its 'type' member, // and run its destructor. @@ -144,6 +171,10 @@ void trace(JSTracer* trc) { type.traceCount(*this, trc); } size_t total_; + + // The smallest JS::ubi::Node::identifier() passed to this instance's + // count() method. This provides a stable way to sort sets. + Node::Id smallestNodeIdCounted_; }; class RootedCount : JS::CustomAutoRooter { @@ -172,19 +203,7 @@ explicit Census(JSContext* cx) : cx(cx), atomsZone(nullptr) { } - bool init(); - - // A 'new' work-alike that behaves like TempAllocPolicy: report OOM on this - // census's context, but don't charge the memory allocated to our context's - // GC pressure counters. - template - T* new_(Args&&... args) MOZ_HEAP_ALLOCATOR { - void* memory = js_malloc(sizeof(T)); - if (MOZ_UNLIKELY(!memory)) { - return nullptr; - } - return new(memory) T(mozilla::Forward(args)...); - } + MOZ_MUST_USE JS_PUBLIC_API(bool) init(); }; // A BreadthFirst handler type that conducts a census, using a CountBase to @@ -192,31 +211,40 @@ class CensusHandler { Census& census; CountBasePtr& rootCount; + mozilla::MallocSizeOf mallocSizeOf; public: - CensusHandler(Census& census, CountBasePtr& rootCount) + CensusHandler(Census& census, CountBasePtr& rootCount, mozilla::MallocSizeOf mallocSizeOf) : census(census), - rootCount(rootCount) + rootCount(rootCount), + mallocSizeOf(mallocSizeOf) { } - bool report(MutableHandleValue report) { - return rootCount->report(report); + MOZ_MUST_USE bool report(JSContext* cx, MutableHandleValue report) { + return rootCount->report(cx, report); } // This class needs to retain no per-node data. class NodeData { }; - bool operator() (BreadthFirst& traversal, - Node origin, const Edge& edge, - NodeData* referentData, bool first); + MOZ_MUST_USE JS_PUBLIC_API(bool) operator() (BreadthFirst& traversal, + Node origin, const Edge& edge, + NodeData* referentData, bool first); }; using CensusTraversal = BreadthFirst; -// Examine the census options supplied by the API consumer, and use that to -// build a CountType tree. -bool ParseCensusOptions(JSContext* cx, Census& census, HandleObject options, - CountTypePtr& outResult); +// Examine the census options supplied by the API consumer, and (among other +// things) use that to build a CountType tree. +MOZ_MUST_USE JS_PUBLIC_API(bool) ParseCensusOptions(JSContext* cx, + Census& census, HandleObject options, + CountTypePtr& outResult); + +// Parse the breakdown language (as described in +// js/src/doc/Debugger/Debugger.Memory.md) into a CountTypePtr. A null pointer +// is returned on error and is reported to the cx. +JS_PUBLIC_API(CountTypePtr) ParseBreakdown(JSContext* cx, HandleValue breakdownValue); + } // namespace ubi } // namespace JS Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNodeDominatorTree.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNodeDominatorTree.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNodeDominatorTree.h @@ -7,6 +7,7 @@ #ifndef js_UbiNodeDominatorTree_h #define js_UbiNodeDominatorTree_h +#include "mozilla/Attributes.h" #include "mozilla/DebugOnly.h" #include "mozilla/Maybe.h" #include "mozilla/Move.h" @@ -71,8 +72,6 @@ private: // Types. - using NodeSet = js::HashSet, js::SystemAllocPolicy>; - using NodeSetPtr = mozilla::UniquePtr>; using PredecessorSets = js::HashMap, js::SystemAllocPolicy>; using NodeToIndexMap = js::HashMap, @@ -95,10 +94,10 @@ { friend class DominatedSetRange; - const mozilla::Vector& postOrder; + const JS::ubi::Vector& postOrder; const uint32_t* ptr; - DominatedNodePtr(const mozilla::Vector& postOrder, const uint32_t* ptr) + DominatedNodePtr(const JS::ubi::Vector& postOrder, const uint32_t* ptr) : postOrder(postOrder) , ptr(ptr) { } @@ -119,11 +118,11 @@ { friend class DominatedSets; - const mozilla::Vector& postOrder; + const JS::ubi::Vector& postOrder; const uint32_t* beginPtr; const uint32_t* endPtr; - DominatedSetRange(mozilla::Vector& postOrder, const uint32_t* begin, const uint32_t* end) + DominatedSetRange(JS::ubi::Vector& postOrder, const uint32_t* begin, const uint32_t* end) : postOrder(postOrder) , beginPtr(begin) , endPtr(end) @@ -180,10 +179,10 @@ */ class DominatedSets { - mozilla::Vector dominated; - mozilla::Vector indices; + JS::ubi::Vector dominated; + JS::ubi::Vector indices; - DominatedSets(mozilla::Vector&& dominated, mozilla::Vector&& indices) + DominatedSets(JS::ubi::Vector&& dominated, JS::ubi::Vector&& indices) : dominated(mozilla::Move(dominated)) , indices(mozilla::Move(indices)) { } @@ -211,7 +210,7 @@ * immediate dominator. Returns `Some` on success, `Nothing` on OOM * failure. */ - static mozilla::Maybe Create(const mozilla::Vector& doms) { + static mozilla::Maybe Create(const JS::ubi::Vector& doms) { auto length = doms.length(); MOZ_ASSERT(length < UINT32_MAX); @@ -236,8 +235,8 @@ // filled in. After having filled in all of a bucket's entries, // the index points to the start of the bucket. - mozilla::Vector dominated; - mozilla::Vector indices; + JS::ubi::Vector dominated; + JS::ubi::Vector indices; if (!dominated.growBy(length) || !indices.growBy(length)) return mozilla::Nothing(); @@ -279,7 +278,7 @@ * Get the set of nodes immediately dominated by the node at * `postOrder[nodeIndex]`. */ - DominatedSetRange dominatedSet(mozilla::Vector& postOrder, uint32_t nodeIndex) const { + DominatedSetRange dominatedSet(JS::ubi::Vector& postOrder, uint32_t nodeIndex) const { MOZ_ASSERT(postOrder.length() == indices.length()); MOZ_ASSERT(nodeIndex < indices.length()); auto end = nodeIndex == indices.length() - 1 @@ -291,11 +290,11 @@ private: // Data members. - mozilla::Vector postOrder; + JS::ubi::Vector postOrder; NodeToIndexMap nodeToPostOrderIndex; - mozilla::Vector doms; + JS::ubi::Vector doms; DominatedSets dominatedSets; - mozilla::Maybe> retainedSizes; + mozilla::Maybe> retainedSizes; private: // We use `UNDEFINED` as a sentinel value in the `doms` vector to signal @@ -303,8 +302,8 @@ // index in `postOrder` yet. static const uint32_t UNDEFINED = UINT32_MAX; - DominatorTree(mozilla::Vector&& postOrder, NodeToIndexMap&& nodeToPostOrderIndex, - mozilla::Vector&& doms, DominatedSets&& dominatedSets) + DominatorTree(JS::ubi::Vector&& postOrder, NodeToIndexMap&& nodeToPostOrderIndex, + JS::ubi::Vector&& doms, DominatedSets&& dominatedSets) : postOrder(mozilla::Move(postOrder)) , nodeToPostOrderIndex(mozilla::Move(nodeToPostOrderIndex)) , doms(mozilla::Move(doms)) @@ -312,7 +311,7 @@ , retainedSizes(mozilla::Nothing()) { } - static uint32_t intersect(mozilla::Vector& doms, uint32_t finger1, uint32_t finger2) { + static uint32_t intersect(JS::ubi::Vector& doms, uint32_t finger1, uint32_t finger2) { while (finger1 != finger2) { if (finger1 < finger2) finger1 = doms[finger1]; @@ -324,8 +323,9 @@ // Do the post order traversal of the heap graph and populate our // predecessor sets. - static bool doTraversal(JSRuntime* rt, AutoCheckCannotGC& noGC, const Node& root, - mozilla::Vector& postOrder, PredecessorSets& predecessorSets) { + static MOZ_MUST_USE bool doTraversal(JSContext* cx, AutoCheckCannotGC& noGC, const Node& root, + JS::ubi::Vector& postOrder, + PredecessorSets& predecessorSets) { uint32_t nodeCount = 0; auto onNode = [&](const Node& node) { nodeCount++; @@ -349,7 +349,7 @@ return p->value()->put(origin); }; - PostOrder traversal(rt, noGC); + PostOrder traversal(cx, noGC); return traversal.init() && traversal.addStart(root) && traversal.traverse(onNode, onEdge); @@ -357,7 +357,8 @@ // Populates the given `map` with an entry for each node to its index in // `postOrder`. - static bool mapNodesToTheirIndices(mozilla::Vector& postOrder, NodeToIndexMap& map) { + static MOZ_MUST_USE bool mapNodesToTheirIndices(JS::ubi::Vector& postOrder, + NodeToIndexMap& map) { MOZ_ASSERT(!map.initialized()); MOZ_ASSERT(postOrder.length() < UINT32_MAX); uint32_t length = postOrder.length(); @@ -370,12 +371,12 @@ // Convert the Node -> NodeSet predecessorSets to a index -> Vector // form. - static bool convertPredecessorSetsToVectors( + static MOZ_MUST_USE bool convertPredecessorSetsToVectors( const Node& root, - mozilla::Vector& postOrder, + JS::ubi::Vector& postOrder, PredecessorSets& predecessorSets, NodeToIndexMap& nodeToPostOrderIndex, - mozilla::Vector>& predecessorVectors) + JS::ubi::Vector>& predecessorVectors) { MOZ_ASSERT(postOrder.length() < UINT32_MAX); uint32_t length = postOrder.length(); @@ -409,7 +410,8 @@ // Initialize `doms` such that the immediate dominator of the `root` is the // `root` itself and all others are `UNDEFINED`. - static bool initializeDominators(mozilla::Vector& doms, uint32_t length) { + static MOZ_MUST_USE bool initializeDominators(JS::ubi::Vector& doms, + uint32_t length) { MOZ_ASSERT(doms.length() == 0); if (!doms.growByUninitialized(length)) return false; @@ -425,7 +427,7 @@ MOZ_ASSERT_IF(retainedSizes.isSome(), postOrder.length() == retainedSizes->length()); } - bool computeRetainedSizes(mozilla::MallocSizeOf mallocSizeOf) { + MOZ_MUST_USE bool computeRetainedSizes(mozilla::MallocSizeOf mallocSizeOf) { MOZ_ASSERT(retainedSizes.isNothing()); auto length = postOrder.length(); @@ -511,10 +513,10 @@ * responsibility to handle and report the OOM. */ static mozilla::Maybe - Create(JSRuntime* rt, AutoCheckCannotGC& noGC, const Node& root) { - mozilla::Vector postOrder; + Create(JSContext* cx, AutoCheckCannotGC& noGC, const Node& root) { + JS::ubi::Vector postOrder; PredecessorSets predecessorSets; - if (!predecessorSets.init() || !doTraversal(rt, noGC, root, postOrder, predecessorSets)) + if (!predecessorSets.init() || !doTraversal(cx, noGC, root, postOrder, predecessorSets)) return mozilla::Nothing(); MOZ_ASSERT(postOrder.length() < UINT32_MAX); @@ -531,12 +533,12 @@ if (!mapNodesToTheirIndices(postOrder, nodeToPostOrderIndex)) return mozilla::Nothing(); - mozilla::Vector> predecessorVectors; + JS::ubi::Vector> predecessorVectors; if (!convertPredecessorSetsToVectors(root, postOrder, predecessorSets, nodeToPostOrderIndex, predecessorVectors)) return mozilla::Nothing(); - mozilla::Vector doms; + JS::ubi::Vector doms; if (!initializeDominators(doms, length)) return mozilla::Nothing(); @@ -650,8 +652,8 @@ * `outSize`, or 0 if `node` is not a member of the dominator tree. Returns * false on OOM failure, leaving `outSize` unchanged. */ - bool getRetainedSize(const Node& node, mozilla::MallocSizeOf mallocSizeOf, - Node::Size& outSize) { + MOZ_MUST_USE bool getRetainedSize(const Node& node, mozilla::MallocSizeOf mallocSizeOf, + Node::Size& outSize) { assertSanity(); auto ptr = nodeToPostOrderIndex.lookup(node); if (!ptr) { Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNodePostOrder.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNodePostOrder.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNodePostOrder.h @@ -7,7 +7,7 @@ #ifndef js_UbiNodePostOrder_h #define js_UbiNodePostOrder_h -#include "mozilla/DebugOnly.h" +#include "mozilla/Attributes.h" #include "mozilla/Maybe.h" #include "mozilla/Move.h" @@ -83,13 +83,15 @@ using Stack = js::Vector; using Set = js::HashSet, js::SystemAllocPolicy>; - JSRuntime* rt; + JSContext* cx; Set seen; Stack stack; - mozilla::DebugOnly traversed; +#ifdef DEBUG + bool traversed; +#endif private: - bool fillEdgesFromRange(EdgeVector& edges, UniquePtr& range) { + MOZ_MUST_USE bool fillEdgesFromRange(EdgeVector& edges, js::UniquePtr& range) { MOZ_ASSERT(range); for ( ; !range->empty(); range->popFront()) { if (!edges.append(mozilla::Move(range->front()))) @@ -98,9 +100,9 @@ return true; } - bool pushForTraversing(const Node& node) { + MOZ_MUST_USE bool pushForTraversing(const Node& node) { EdgeVector edges; - auto range = node.edges(rt, /* wantNames */ false); + auto range = node.edges(cx, /* wantNames */ false); return range && fillEdgesFromRange(edges, range) && stack.append(OriginAndEdges(node, mozilla::Move(edges))); @@ -113,19 +115,21 @@ // The traversal asserts that no GC happens in its runtime during its // lifetime via the `AutoCheckCannotGC&` parameter. We do nothing with it, // other than require it to exist with a lifetime that encloses our own. - PostOrder(JSRuntime* rt, AutoCheckCannotGC&) - : rt(rt) + PostOrder(JSContext* cx, AutoCheckCannotGC&) + : cx(cx) , seen() , stack() +#ifdef DEBUG , traversed(false) +#endif { } // Initialize this traversal object. Return false on OOM. - bool init() { return seen.init(); } + MOZ_MUST_USE bool init() { return seen.init(); } // Add `node` as a starting point for the traversal. You may add // as many starting points as you like. Returns false on OOM. - bool addStart(const Node& node) { + MOZ_MUST_USE bool addStart(const Node& node) { if (!seen.put(node)) return false; return pushForTraversing(node); @@ -141,9 +145,11 @@ // Return false on OOM or error return from `onNode::operator()` or // `onEdge::operator()`. template - bool traverse(NodeVisitor onNode, EdgeVisitor onEdge) { + MOZ_MUST_USE bool traverse(NodeVisitor onNode, EdgeVisitor onEdge) { +#ifdef DEBUG MOZ_ASSERT(!traversed, "Can only traverse() once!"); traversed = true; +#endif while (!stack.empty()) { auto& origin = stack.back().origin; Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNodeShortestPaths.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNodeShortestPaths.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UbiNodeShortestPaths.h @@ -0,0 +1,350 @@ +/* -*- 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_UbiNodeShortestPaths_h +#define js_UbiNodeShortestPaths_h + +#include "mozilla/Attributes.h" +#include "mozilla/Maybe.h" +#include "mozilla/Move.h" + +#include "jsalloc.h" + +#include "js/UbiNodeBreadthFirst.h" +#include "js/Vector.h" + +namespace JS { +namespace ubi { + +/** + * A back edge along a path in the heap graph. + */ +struct JS_PUBLIC_API(BackEdge) +{ + private: + Node predecessor_; + EdgeName name_; + + public: + using Ptr = mozilla::UniquePtr>; + + BackEdge() : predecessor_(), name_(nullptr) { } + + MOZ_MUST_USE bool init(const Node& predecessor, Edge& edge) { + MOZ_ASSERT(!predecessor_); + MOZ_ASSERT(!name_); + + predecessor_ = predecessor; + name_ = mozilla::Move(edge.name); + return true; + } + + BackEdge(const BackEdge&) = delete; + BackEdge& operator=(const BackEdge&) = delete; + + BackEdge(BackEdge&& rhs) + : predecessor_(rhs.predecessor_) + , name_(mozilla::Move(rhs.name_)) + { + MOZ_ASSERT(&rhs != this); + } + + BackEdge& operator=(BackEdge&& rhs) { + this->~BackEdge(); + new(this) BackEdge(Move(rhs)); + return *this; + } + + Ptr clone() const; + + const EdgeName& name() const { return name_; } + EdgeName& name() { return name_; } + + const JS::ubi::Node& predecessor() const { return predecessor_; } +}; + +/** + * A path is a series of back edges from which we discovered a target node. + */ +using Path = JS::ubi::Vector; + +/** + * The `JS::ubi::ShortestPaths` type represents a collection of up to N shortest + * retaining paths for each of a target set of nodes, starting from the same + * root node. + */ +struct JS_PUBLIC_API(ShortestPaths) +{ + private: + // Types, type aliases, and data members. + + using BackEdgeVector = JS::ubi::Vector; + using NodeToBackEdgeVectorMap = js::HashMap, + js::SystemAllocPolicy>; + + struct Handler; + using Traversal = BreadthFirst; + + /** + * A `JS::ubi::BreadthFirst` traversal handler that records back edges for + * how we reached each node, allowing us to reconstruct the shortest + * retaining paths after the traversal. + */ + struct Handler + { + using NodeData = BackEdge; + + ShortestPaths& shortestPaths; + size_t totalMaxPathsToRecord; + size_t totalPathsRecorded; + + explicit Handler(ShortestPaths& shortestPaths) + : shortestPaths(shortestPaths) + , totalMaxPathsToRecord(shortestPaths.targets_.count() * shortestPaths.maxNumPaths_) + , totalPathsRecorded(0) + { + } + + bool + operator()(Traversal& traversal, JS::ubi::Node origin, JS::ubi::Edge& edge, + BackEdge* back, bool first) + { + MOZ_ASSERT(back); + MOZ_ASSERT(origin == shortestPaths.root_ || traversal.visited.has(origin)); + MOZ_ASSERT(totalPathsRecorded < totalMaxPathsToRecord); + + if (first && !back->init(origin, edge)) + return false; + + if (!shortestPaths.targets_.has(edge.referent)) + return true; + + // If `first` is true, then we moved the edge's name into `back` in + // the above call to `init`. So clone that back edge to get the + // correct edge name. If `first` is not true, then our edge name is + // still in `edge`. This accounts for the asymmetry between + // `back->clone()` in the first branch, and the `init` call in the + // second branch. + + if (first) { + BackEdgeVector paths; + if (!paths.reserve(shortestPaths.maxNumPaths_)) + return false; + auto cloned = back->clone(); + if (!cloned) + return false; + paths.infallibleAppend(mozilla::Move(cloned)); + if (!shortestPaths.paths_.putNew(edge.referent, mozilla::Move(paths))) + return false; + totalPathsRecorded++; + } else { + auto ptr = shortestPaths.paths_.lookup(edge.referent); + MOZ_ASSERT(ptr, + "This isn't the first time we have seen the target node `edge.referent`. " + "We should have inserted it into shortestPaths.paths_ the first time we " + "saw it."); + + if (ptr->value().length() < shortestPaths.maxNumPaths_) { + BackEdge::Ptr thisBackEdge(js_new()); + if (!thisBackEdge || !thisBackEdge->init(origin, edge)) + return false; + ptr->value().infallibleAppend(mozilla::Move(thisBackEdge)); + totalPathsRecorded++; + } + } + + MOZ_ASSERT(totalPathsRecorded <= totalMaxPathsToRecord); + if (totalPathsRecorded == totalMaxPathsToRecord) + traversal.stop(); + + return true; + } + + }; + + // The maximum number of paths to record for each node. + uint32_t maxNumPaths_; + + // The root node we are starting the search from. + Node root_; + + // The set of nodes we are searching for paths to. + NodeSet targets_; + + // The resulting paths. + NodeToBackEdgeVectorMap paths_; + + // Need to keep alive the traversal's back edges so we can walk them later + // when the traversal is over when recreating the shortest paths. + Traversal::NodeMap backEdges_; + + private: + // Private methods. + + ShortestPaths(uint32_t maxNumPaths, const Node& root, NodeSet&& targets) + : maxNumPaths_(maxNumPaths) + , root_(root) + , targets_(mozilla::Move(targets)) + , paths_() + , backEdges_() + { + MOZ_ASSERT(maxNumPaths_ > 0); + MOZ_ASSERT(root_); + MOZ_ASSERT(targets_.initialized()); + } + + bool initialized() const { + return targets_.initialized() && + paths_.initialized() && + backEdges_.initialized(); + } + + public: + // Public methods. + + ShortestPaths(ShortestPaths&& rhs) + : maxNumPaths_(rhs.maxNumPaths_) + , root_(rhs.root_) + , targets_(mozilla::Move(rhs.targets_)) + , paths_(mozilla::Move(rhs.paths_)) + , backEdges_(mozilla::Move(rhs.backEdges_)) + { + MOZ_ASSERT(this != &rhs, "self-move is not allowed"); + } + + ShortestPaths& operator=(ShortestPaths&& rhs) { + this->~ShortestPaths(); + new (this) ShortestPaths(mozilla::Move(rhs)); + return *this; + } + + ShortestPaths(const ShortestPaths&) = delete; + ShortestPaths& operator=(const ShortestPaths&) = delete; + + /** + * Construct a new `JS::ubi::ShortestPaths`, finding up to `maxNumPaths` + * shortest retaining paths for each target node in `targets` starting from + * `root`. + * + * The resulting `ShortestPaths` instance must not outlive the + * `JS::ubi::Node` graph it was constructed from. + * + * - For `JS::ubi::Node` graphs backed by the live heap graph, this means + * that the `ShortestPaths`'s lifetime _must_ be contained within the + * scope of the provided `AutoCheckCannotGC` reference because a GC will + * invalidate the nodes. + * + * - For `JS::ubi::Node` graphs backed by some other offline structure + * provided by the embedder, the resulting `ShortestPaths`'s lifetime is + * bounded by that offline structure's lifetime. + * + * Returns `mozilla::Nothing()` on OOM failure. It is the caller's + * responsibility to handle and report the OOM. + */ + static mozilla::Maybe + Create(JSContext* cx, AutoCheckCannotGC& noGC, uint32_t maxNumPaths, const Node& root, NodeSet&& targets) { + MOZ_ASSERT(targets.count() > 0); + MOZ_ASSERT(maxNumPaths > 0); + + size_t count = targets.count(); + ShortestPaths paths(maxNumPaths, root, mozilla::Move(targets)); + if (!paths.paths_.init(count)) + return mozilla::Nothing(); + + Handler handler(paths); + Traversal traversal(cx, handler, noGC); + traversal.wantNames = true; + if (!traversal.init() || !traversal.addStart(root) || !traversal.traverse()) + return mozilla::Nothing(); + + // Take ownership of the back edges we created while traversing the + // graph so that we can follow them from `paths_` and don't + // use-after-free. + paths.backEdges_ = mozilla::Move(traversal.visited); + + MOZ_ASSERT(paths.initialized()); + return mozilla::Some(mozilla::Move(paths)); + } + + /** + * Get a range that iterates over each target node we searched for retaining + * paths for. The returned range must not outlive the `ShortestPaths` + * instance. + */ + NodeSet::Range eachTarget() const { + MOZ_ASSERT(initialized()); + return targets_.all(); + } + + /** + * Invoke the provided functor/lambda/callable once for each retaining path + * discovered for `target`. The `func` is passed a single `JS::ubi::Path&` + * argument, which contains each edge along the path ordered starting from + * the root and ending at the target, and must not outlive the scope of the + * call. + * + * Note that it is possible that we did not find any paths from the root to + * the given target, in which case `func` will not be invoked. + */ + template + MOZ_MUST_USE bool forEachPath(const Node& target, Func func) { + MOZ_ASSERT(initialized()); + MOZ_ASSERT(targets_.has(target)); + + auto ptr = paths_.lookup(target); + + // We didn't find any paths to this target, so nothing to do here. + if (!ptr) + return true; + + MOZ_ASSERT(ptr->value().length() <= maxNumPaths_); + + Path path; + for (const auto& backEdge : ptr->value()) { + path.clear(); + + if (!path.append(backEdge.get())) + return false; + + Node here = backEdge->predecessor(); + MOZ_ASSERT(here); + + while (here != root_) { + auto p = backEdges_.lookup(here); + MOZ_ASSERT(p); + if (!path.append(&p->value())) + return false; + here = p->value().predecessor(); + MOZ_ASSERT(here); + } + + path.reverse(); + + if (!func(path)) + return false; + } + + return true; + } +}; + +#ifdef DEBUG +// A helper function to dump the first `maxNumPaths` shortest retaining paths to +// `node` from the GC roots. Useful when GC things you expect to have been +// reclaimed by the collector haven't been! +// +// Usage: +// +// JSObject* foo = ...; +// JS::ubi::dumpPaths(rt, JS::ubi::Node(foo)); +JS_PUBLIC_API(void) +dumpPaths(JSRuntime* rt, Node node, uint32_t maxNumPaths = 10); +#endif + +} // namespace ubi +} // namespace JS + +#endif // js_UbiNodeShortestPaths_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UniquePtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UniquePtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/UniquePtr.h @@ -0,0 +1,61 @@ +/* -*- 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_UniquePtr_h +#define js_UniquePtr_h + +#include "mozilla/UniquePtr.h" + +#include "js/Utility.h" + +namespace js { + +// Replacement for mozilla::UniquePtr that defaults to js::DefaultDelete. +template > +using UniquePtr = mozilla::UniquePtr; + +namespace detail { + +template +struct UniqueSelector +{ + typedef UniquePtr SingleObject; +}; + +template +struct UniqueSelector +{ + typedef UniquePtr UnknownBound; +}; + +template +struct UniqueSelector +{ + typedef UniquePtr KnownBound; +}; + +} // namespace detail + +// Replacement for mozilla::MakeUnique that correctly calls js_new and produces +// a js::UniquePtr. +template +typename detail::UniqueSelector::SingleObject +MakeUnique(Args&&... aArgs) +{ + return UniquePtr(js_new(mozilla::Forward(aArgs)...)); +} + +template +typename detail::UniqueSelector::UnknownBound +MakeUnique(decltype(sizeof(int)) aN) = delete; + +template +typename detail::UniqueSelector::KnownBound +MakeUnique(Args&&... aArgs) = delete; + +} // namespace js + +#endif /* js_UniquePtr_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Utility.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Utility.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Utility.h @@ -8,6 +8,7 @@ #define js_Utility_h #include "mozilla/Assertions.h" +#include "mozilla/Atomics.h" #include "mozilla/Attributes.h" #include "mozilla/Compiler.h" #include "mozilla/Move.h" @@ -34,22 +35,6 @@ /* The private JS engine namespace. */ namespace js {} -/* - * Patterns used by SpiderMonkey to overwrite unused memory. If you are - * accessing an object with one of these pattern, you probably have a dangling - * pointer. - */ -#define JS_FRESH_NURSERY_PATTERN 0x2F -#define JS_SWEPT_NURSERY_PATTERN 0x2B -#define JS_ALLOCATED_NURSERY_PATTERN 0x2D -#define JS_FRESH_TENURED_PATTERN 0x4F -#define JS_MOVED_TENURED_PATTERN 0x49 -#define JS_SWEPT_TENURED_PATTERN 0x4B -#define JS_ALLOCATED_TENURED_PATTERN 0x4D -#define JS_EMPTY_STOREBUFFER_PATTERN 0x1B -#define JS_SWEPT_CODE_PATTERN 0x3B -#define JS_SWEPT_FRAME_PATTERN 0x5B - #define JS_STATIC_ASSERT(cond) static_assert(cond, "JS_STATIC_ASSERT") #define JS_STATIC_ASSERT_IF(cond, expr) MOZ_STATIC_ASSERT_IF(cond, expr, "JS_STATIC_ASSERT_IF") @@ -81,6 +66,7 @@ THREAD_TYPE_COMPRESS, // 5 THREAD_TYPE_GCHELPER, // 6 THREAD_TYPE_GCPARALLEL, // 7 + THREAD_TYPE_PROMISE_TASK, // 8 THREAD_TYPE_MAX // Used to check shell function arguments }; @@ -103,15 +89,6 @@ # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) -/* - * In order to test OOM conditions, when the testing function - * oomAfterAllocations COUNT is passed, we fail continuously after the NUM'th - * allocation from now. - */ -extern JS_PUBLIC_DATA(uint32_t) OOM_maxAllocations; /* set in builtin/TestingFunctions.cpp */ -extern JS_PUBLIC_DATA(uint32_t) OOM_counter; /* data race, who cares. */ -extern JS_PUBLIC_DATA(bool) OOM_failAlways; - #ifdef JS_OOM_BREAKPOINT static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); } #define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint() @@ -122,28 +99,42 @@ namespace js { namespace oom { +/* + * Out of memory testing support. We provide various testing functions to + * simulate OOM conditions and so we can test that they are handled correctly. + */ + extern JS_PUBLIC_DATA(uint32_t) targetThread; +extern JS_PUBLIC_DATA(uint64_t) maxAllocations; +extern JS_PUBLIC_DATA(uint64_t) counter; +extern JS_PUBLIC_DATA(bool) failAlways; -static inline bool +extern void +SimulateOOMAfter(uint64_t allocations, uint32_t thread, bool always); + +extern void +ResetSimulatedOOM(); + +inline bool IsThreadSimulatingOOM() { return js::oom::targetThread && js::oom::targetThread == js::oom::GetThreadType(); } -static inline bool +inline bool IsSimulatedOOMAllocation() { - return IsThreadSimulatingOOM() && (OOM_counter == OOM_maxAllocations || - (OOM_counter > OOM_maxAllocations && OOM_failAlways)); + return IsThreadSimulatingOOM() && + (counter == maxAllocations || (counter > maxAllocations && failAlways)); } -static inline bool +inline bool ShouldFailWithOOM() { if (!IsThreadSimulatingOOM()) return false; - OOM_counter++; + counter++; if (IsSimulatedOOMAllocation()) { JS_OOM_CALL_BP_FUNC(); return true; @@ -151,6 +142,11 @@ return false; } +inline bool +HadSimulatedOOM() { + return counter >= maxAllocations; +} + } /* namespace oom */ } /* namespace js */ @@ -182,32 +178,44 @@ namespace js { /* Disable OOM testing in sections which are not OOM safe. */ -struct MOZ_RAII AutoEnterOOMUnsafeRegion +struct MOZ_RAII JS_PUBLIC_DATA(AutoEnterOOMUnsafeRegion) { MOZ_NORETURN MOZ_COLD void crash(const char* reason); + MOZ_NORETURN MOZ_COLD void crash(size_t size, const char* reason); + + using AnnotateOOMAllocationSizeCallback = void(*)(size_t); + static AnnotateOOMAllocationSizeCallback annotateOOMSizeCallback; + static void setAnnotateOOMAllocationSizeCallback(AnnotateOOMAllocationSizeCallback callback) { + annotateOOMSizeCallback = callback; + } #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) AutoEnterOOMUnsafeRegion() - : oomEnabled_(oom::IsThreadSimulatingOOM() && OOM_maxAllocations != UINT32_MAX), + : oomEnabled_(oom::IsThreadSimulatingOOM() && oom::maxAllocations != UINT64_MAX), oomAfter_(0) { if (oomEnabled_) { - oomAfter_ = int64_t(OOM_maxAllocations) - OOM_counter; - OOM_maxAllocations = UINT32_MAX; + MOZ_ALWAYS_TRUE(owner_.compareExchange(nullptr, this)); + oomAfter_ = int64_t(oom::maxAllocations) - int64_t(oom::counter); + oom::maxAllocations = UINT64_MAX; } } ~AutoEnterOOMUnsafeRegion() { if (oomEnabled_) { - MOZ_ASSERT(OOM_maxAllocations == UINT32_MAX); - int64_t maxAllocations = OOM_counter + oomAfter_; - MOZ_ASSERT(maxAllocations >= 0 && maxAllocations < UINT32_MAX, + MOZ_ASSERT(oom::maxAllocations == UINT64_MAX); + int64_t maxAllocations = int64_t(oom::counter) + oomAfter_; + MOZ_ASSERT(maxAllocations >= 0, "alloc count + oom limit exceeds range, your oom limit is probably too large"); - OOM_maxAllocations = uint32_t(maxAllocations); + oom::maxAllocations = uint64_t(maxAllocations); + MOZ_ALWAYS_TRUE(owner_.compareExchange(this, nullptr)); } } private: + // Used to catch concurrent use from other threads. + static mozilla::Atomic owner_; + bool oomEnabled_; int64_t oomAfter_; #endif @@ -235,6 +243,11 @@ static inline void* js_realloc(void* p, size_t bytes) { + // realloc() with zero size is not portable, as some implementations may + // return nullptr on success and free |p| for this. We assume nullptr + // indicates failure and that |p| is still valid. + MOZ_ASSERT(bytes != 0); + JS_OOM_POSSIBLY_FAIL(); return realloc(p, bytes); } @@ -302,14 +315,14 @@ * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS, * or the build will break. */ -#define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS)\ +#define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \ template \ QUALIFIERS T * \ NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \ void* memory = ALLOCATOR(sizeof(T)); \ - return memory \ - ? new(memory) T(mozilla::Forward(args)...) \ - : nullptr; \ + return MOZ_LIKELY(memory) \ + ? new(memory) T(mozilla::Forward(args)...) \ + : nullptr; \ } /* @@ -339,7 +352,7 @@ * instances of type |T|. Return false if the calculation overflowed. */ template -MOZ_WARN_UNUSED_RESULT inline bool +MOZ_MUST_USE inline bool CalculateAllocSize(size_t numElems, size_t* bytesOut) { *bytesOut = numElems * sizeof(T); @@ -352,7 +365,7 @@ * false if the calculation overflowed. */ template -MOZ_WARN_UNUSED_RESULT inline bool +MOZ_MUST_USE inline bool CalculateAllocSizeWithExtra(size_t numExtra, size_t* bytesOut) { *bytesOut = sizeof(T) + numExtra * sizeof(Extra); @@ -460,6 +473,14 @@ template struct DeletePolicy { + constexpr DeletePolicy() {} + + template + MOZ_IMPLICIT DeletePolicy(DeletePolicy other, + typename mozilla::EnableIf::value, + int>::Type dummy = 0) + {} + void operator()(const T* ptr) { js_delete(const_cast(ptr)); } @@ -472,6 +493,9 @@ } }; +typedef mozilla::UniquePtr UniqueChars; +typedef mozilla::UniquePtr UniqueTwoByteChars; + } // namespace JS namespace js { @@ -480,13 +504,6 @@ typedef uint32_t HashNumber; const unsigned HashNumberSizeBits = 32; -typedef mozilla::UniquePtr UniqueChars; - -static inline UniqueChars make_string_copy(const char* str) -{ - return UniqueChars(js_strdup(str)); -} - namespace detail { /* Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Value.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Value.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Value.h @@ -10,6 +10,7 @@ #define js_Value_h #include "mozilla/Attributes.h" +#include "mozilla/Casting.h" #include "mozilla/FloatingPoint.h" #include "mozilla/Likely.h" @@ -29,34 +30,12 @@ #define JSVAL_INT_MIN ((int32_t)0x80000000) #define JSVAL_INT_MAX ((int32_t)0x7fffffff) -/* - * Try to get jsvals 64-bit aligned. We could almost assert that all values are - * aligned, but MSVC and GCC occasionally break alignment. - */ -#if defined(__GNUC__) || defined(__xlc__) || defined(__xlC__) -# define JSVAL_ALIGNMENT __attribute__((aligned (8))) -#elif defined(_MSC_VER) - /* - * Structs can be aligned with MSVC, but not if they are used as parameters, - * so we just don't try to align. - */ -# define JSVAL_ALIGNMENT -#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# define JSVAL_ALIGNMENT -#elif defined(__HP_cc) || defined(__HP_aCC) -# define JSVAL_ALIGNMENT -#endif - #if defined(JS_PUNBOX64) # define JSVAL_TAG_SHIFT 47 #endif -/* - * We try to use enums so that printing a jsval_layout in the debugger shows - * nice symbolic type tags, however we can only do this when we can force the - * underlying type of the enum to be the desired size. - */ -#if !defined(__SUNPRO_CC) && !defined(__xlC__) +// Use enums so that printing a JS::Value in the debugger shows nice +// symbolic type tags. #if defined(_MSC_VER) # define JS_ENUM_HEADER(id, type) enum id : type @@ -76,8 +55,9 @@ JSVAL_TYPE_MAGIC = 0x04, JSVAL_TYPE_STRING = 0x05, JSVAL_TYPE_SYMBOL = 0x06, - JSVAL_TYPE_NULL = 0x07, - JSVAL_TYPE_OBJECT = 0x08, + JSVAL_TYPE_PRIVATE_GCTHING = 0x07, + JSVAL_TYPE_NULL = 0x08, + JSVAL_TYPE_OBJECT = 0x0c, /* These never appear in a jsval; they are only provided as an out-of-band value. */ JSVAL_TYPE_UNKNOWN = 0x20, @@ -100,7 +80,8 @@ JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN, JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC, JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL, - JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT + JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT, + JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING } JS_ENUM_FOOTER(JSValueTag); static_assert(sizeof(JSValueTag) == sizeof(uint32_t), @@ -119,7 +100,8 @@ JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN, JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC, JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL, - JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT + JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT, + JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING } JS_ENUM_FOOTER(JSValueTag); static_assert(sizeof(JSValueTag) == sizeof(uint32_t), @@ -127,15 +109,16 @@ JS_ENUM_HEADER(JSValueShiftedTag, uint64_t) { - JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF), - JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) + JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF), + JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT) } JS_ENUM_FOOTER(JSValueShiftedTag); static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t), @@ -153,64 +136,12 @@ #undef JS_ENUM_HEADER #undef JS_ENUM_FOOTER -#else /* !defined(__SUNPRO_CC) && !defined(__xlC__) */ - -typedef uint8_t JSValueType; -#define JSVAL_TYPE_DOUBLE ((uint8_t)0x00) -#define JSVAL_TYPE_INT32 ((uint8_t)0x01) -#define JSVAL_TYPE_UNDEFINED ((uint8_t)0x02) -#define JSVAL_TYPE_BOOLEAN ((uint8_t)0x03) -#define JSVAL_TYPE_MAGIC ((uint8_t)0x04) -#define JSVAL_TYPE_STRING ((uint8_t)0x05) -#define JSVAL_TYPE_SYMBOL ((uint8_t)0x06) -#define JSVAL_TYPE_NULL ((uint8_t)0x07) -#define JSVAL_TYPE_OBJECT ((uint8_t)0x08) -#define JSVAL_TYPE_UNKNOWN ((uint8_t)0x20) - -#if defined(JS_NUNBOX32) - -typedef uint32_t JSValueTag; -#define JSVAL_TAG_CLEAR ((uint32_t)(0xFFFFFF80)) -#define JSVAL_TAG_INT32 ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32)) -#define JSVAL_TAG_UNDEFINED ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED)) -#define JSVAL_TAG_STRING ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING)) -#define JSVAL_TAG_SYMBOL ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL)) -#define JSVAL_TAG_BOOLEAN ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN)) -#define JSVAL_TAG_MAGIC ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC)) -#define JSVAL_TAG_NULL ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL)) -#define JSVAL_TAG_OBJECT ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT)) - -#elif defined(JS_PUNBOX64) - -typedef uint32_t JSValueTag; -#define JSVAL_TAG_MAX_DOUBLE ((uint32_t)(0x1FFF0)) -#define JSVAL_TAG_INT32 (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32) -#define JSVAL_TAG_UNDEFINED (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED) -#define JSVAL_TAG_STRING (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING) -#define JSVAL_TAG_SYMBOL (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL) -#define JSVAL_TAG_BOOLEAN (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN) -#define JSVAL_TAG_MAGIC (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC) -#define JSVAL_TAG_NULL (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL) -#define JSVAL_TAG_OBJECT (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT) - -typedef uint64_t JSValueShiftedTag; -#define JSVAL_SHIFTED_TAG_MAX_DOUBLE ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF) -#define JSVAL_SHIFTED_TAG_INT32 (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_UNDEFINED (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_STRING (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_SYMBOL (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_BOOLEAN (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_MAGIC (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_NULL (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_OBJECT (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) - -#endif /* JS_PUNBOX64 */ -#endif /* !defined(__SUNPRO_CC) && !defined(__xlC__) */ - #if defined(JS_NUNBOX32) #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) +#define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << 32) + #define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 @@ -218,6 +149,8 @@ #elif defined(JS_PUNBOX64) +#define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) + #define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL #define JSVAL_TAG_MASK 0xFFFF800000000000LL #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type))) @@ -267,9 +200,6 @@ /** magic value passed to natives to indicate construction */ JS_IS_CONSTRUCTING, - /** arguments.callee has been overwritten */ - JS_OVERWRITTEN_CALLEE, - /** value of static block object slot */ JS_BLOCK_NEEDS_CLONE, @@ -294,686 +224,22 @@ JS_WHY_MAGIC_COUNT } JSWhyMagic; -#if defined(IS_LITTLE_ENDIAN) -# if defined(JS_NUNBOX32) -typedef union jsval_layout -{ - uint64_t asBits; - struct { - union { - int32_t i32; - uint32_t u32; - uint32_t boo; // Don't use |bool| -- it must be four bytes. - JSString* str; - JS::Symbol* sym; - JSObject* obj; - js::gc::Cell* cell; - void* ptr; - JSWhyMagic why; - size_t word; - uintptr_t uintptr; - } payload; - JSValueTag tag; - } s; - double asDouble; - void* asPtr; -} JSVAL_ALIGNMENT jsval_layout; -# elif defined(JS_PUNBOX64) -typedef union jsval_layout -{ - uint64_t asBits; -#if !defined(_WIN64) - /* MSVC does not pack these correctly :-( */ - struct { - uint64_t payload47 : 47; - JSValueTag tag : 17; - } debugView; -#endif - struct { - union { - int32_t i32; - uint32_t u32; - JSWhyMagic why; - } payload; - } s; - double asDouble; - void* asPtr; - size_t asWord; - uintptr_t asUIntPtr; -} JSVAL_ALIGNMENT jsval_layout; -# endif /* JS_PUNBOX64 */ -#else /* defined(IS_LITTLE_ENDIAN) */ -# if defined(JS_NUNBOX32) -typedef union jsval_layout -{ - uint64_t asBits; - struct { - JSValueTag tag; - union { - int32_t i32; - uint32_t u32; - uint32_t boo; // Don't use |bool| -- it must be four bytes. - JSString* str; - JS::Symbol* sym; - JSObject* obj; - js::gc::Cell* cell; - void* ptr; - JSWhyMagic why; - size_t word; - uintptr_t uintptr; - } payload; - } s; - double asDouble; - void* asPtr; -} JSVAL_ALIGNMENT jsval_layout; -# elif defined(JS_PUNBOX64) -typedef union jsval_layout -{ - uint64_t asBits; - struct { - JSValueTag tag : 17; - uint64_t payload47 : 47; - } debugView; - struct { - uint32_t padding; - union { - int32_t i32; - uint32_t u32; - JSWhyMagic why; - } payload; - } s; - double asDouble; - void* asPtr; - size_t asWord; - uintptr_t asUIntPtr; -} JSVAL_ALIGNMENT jsval_layout; -# endif /* JS_PUNBOX64 */ -#endif /* defined(IS_LITTLE_ENDIAN) */ - -JS_STATIC_ASSERT(sizeof(jsval_layout) == 8); - -/* - * For codesize purposes on some platforms, it's important that the - * compiler know that JS::Values constructed from constant values can be - * folded to constant bit patterns at compile time, rather than - * constructed at runtime. Doing this requires a fair amount of C++11 - * features, which are not supported on all of our compilers. Set up - * some defines and helper macros in an attempt to confine the ugliness - * here, rather than scattering it all about the file. The important - * features are: - * - * - constexpr; - * - defaulted functions; - * - C99-style designated initializers. - */ -#if defined(__clang__) -# if __has_feature(cxx_constexpr) && __has_feature(cxx_defaulted_functions) -# define JS_VALUE_IS_CONSTEXPR -# endif -#elif defined(__GNUC__) -/* - * We need 4.5 for defaulted functions, 4.6 for constexpr, 4.7 because 4.6 - * doesn't understand |(X) { .field = ... }| syntax, and 4.7.3 because - * versions prior to that have bugs in the C++ front-end that cause crashes. - */ -# if MOZ_GCC_VERSION_AT_LEAST(4, 7, 3) -# define JS_VALUE_IS_CONSTEXPR -# endif -#endif - -#if defined(JS_VALUE_IS_CONSTEXPR) -# define JS_RETURN_LAYOUT_FROM_BITS(BITS) \ - return (jsval_layout) { .asBits = (BITS) } -# define JS_VALUE_CONSTEXPR MOZ_CONSTEXPR -# define JS_VALUE_CONSTEXPR_VAR MOZ_CONSTEXPR_VAR -#else -# define JS_RETURN_LAYOUT_FROM_BITS(BITS) \ - jsval_layout l; \ - l.asBits = (BITS); \ - return l; -# define JS_VALUE_CONSTEXPR -# define JS_VALUE_CONSTEXPR_VAR const -#endif - -#if defined(JS_NUNBOX32) - -/* - * N.B. GCC, in some but not all cases, chooses to emit signed comparison of - * JSValueTag even though its underlying type has been forced to be uint32_t. - * Thus, all comparisons should explicitly cast operands to uint32_t. - */ - -static inline JS_VALUE_CONSTEXPR jsval_layout -BUILD_JSVAL(JSValueTag tag, uint32_t payload) -{ - JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << 32) | payload); -} - -static inline bool -JSVAL_IS_DOUBLE_IMPL(jsval_layout l) -{ - return (uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_CLEAR; -} - -static inline jsval_layout -DOUBLE_TO_JSVAL_IMPL(double d) -{ - jsval_layout l; - l.asDouble = d; - MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); - return l; -} - -static inline bool -JSVAL_IS_INT32_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_INT32; -} - -static inline int32_t -JSVAL_TO_INT32_IMPL(jsval_layout l) -{ - return l.s.payload.i32; -} - -static inline JS_VALUE_CONSTEXPR jsval_layout -INT32_TO_JSVAL_IMPL(int32_t i) -{ -#if defined(JS_VALUE_IS_CONSTEXPR) - return BUILD_JSVAL(JSVAL_TAG_INT32, i); -#else - jsval_layout l; - l.s.tag = JSVAL_TAG_INT32; - l.s.payload.i32 = i; - return l; -#endif -} - -static inline bool -JSVAL_IS_NUMBER_IMPL(jsval_layout l) -{ - JSValueTag tag = l.s.tag; - MOZ_ASSERT(tag != JSVAL_TAG_CLEAR); - return (uint32_t)tag <= (uint32_t)JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET; -} - -static inline bool -JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_UNDEFINED; -} - -static inline bool -JSVAL_IS_STRING_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_STRING; -} - -static inline jsval_layout -STRING_TO_JSVAL_IMPL(JSString* str) -{ - jsval_layout l; - MOZ_ASSERT(uintptr_t(str) > 0x1000); - l.s.tag = JSVAL_TAG_STRING; - l.s.payload.str = str; - return l; -} - -static inline JSString* -JSVAL_TO_STRING_IMPL(jsval_layout l) -{ - return l.s.payload.str; -} - -static inline bool -JSVAL_IS_SYMBOL_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_SYMBOL; -} - -static inline jsval_layout -SYMBOL_TO_JSVAL_IMPL(JS::Symbol* sym) -{ - jsval_layout l; - MOZ_ASSERT(uintptr_t(sym) > 0x1000); - l.s.tag = JSVAL_TAG_SYMBOL; - l.s.payload.sym = sym; - return l; -} - -static inline JS::Symbol* -JSVAL_TO_SYMBOL_IMPL(jsval_layout l) -{ - return l.s.payload.sym; -} - -static inline bool -JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_BOOLEAN; -} - -static inline bool -JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) -{ - return l.s.payload.boo; -} - -static inline jsval_layout -BOOLEAN_TO_JSVAL_IMPL(bool b) -{ - jsval_layout l; - l.s.tag = JSVAL_TAG_BOOLEAN; - l.s.payload.boo = b; - return l; -} - -static inline bool -JSVAL_IS_MAGIC_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_MAGIC; -} - -static inline bool -JSVAL_IS_OBJECT_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_OBJECT; -} - -static inline bool -JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) -{ - return (uint32_t)l.s.tag < (uint32_t)JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET; -} - -static inline bool -JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) -{ - MOZ_ASSERT((uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_OBJECT); - return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET; -} - -static inline JSObject* -JSVAL_TO_OBJECT_IMPL(jsval_layout l) -{ - return l.s.payload.obj; -} - -static inline jsval_layout -OBJECT_TO_JSVAL_IMPL(JSObject* obj) -{ - jsval_layout l; - MOZ_ASSERT(uintptr_t(obj) > 0x1000 || uintptr_t(obj) == 0x42); - l.s.tag = JSVAL_TAG_OBJECT; - l.s.payload.obj = obj; - return l; -} - -static inline bool -JSVAL_IS_NULL_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_NULL; -} - -static inline jsval_layout -PRIVATE_PTR_TO_JSVAL_IMPL(void* ptr) -{ - jsval_layout l; - MOZ_ASSERT(((uint32_t)ptr & 1) == 0); - l.s.tag = (JSValueTag)0; - l.s.payload.ptr = ptr; - MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); - return l; -} - -static inline void* -JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) -{ - return l.s.payload.ptr; -} - -static inline bool -JSVAL_IS_GCTHING_IMPL(jsval_layout l) -{ - /* gcc sometimes generates signed < without explicit casts. */ - return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET; -} - -static inline js::gc::Cell* -JSVAL_TO_GCTHING_IMPL(jsval_layout l) -{ - return l.s.payload.cell; -} - -static inline uint32_t -JSVAL_TRACE_KIND_IMPL(jsval_layout l) -{ - static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String), - "Value type tags must correspond with JS::TraceKinds."); - static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol), - "Value type tags must correspond with JS::TraceKinds."); - static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object), - "Value type tags must correspond with JS::TraceKinds."); - return l.s.tag & 0x03; -} - -static inline bool -JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32) -{ - return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32; -} - -static inline bool -JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(jsval_layout l, bool b) -{ - return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == uint32_t(b)); -} - -static inline jsval_layout -MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) -{ - jsval_layout l; - l.s.tag = JSVAL_TAG_MAGIC; - l.s.payload.why = why; - return l; -} - -static inline jsval_layout -MAGIC_UINT32_TO_JSVAL_IMPL(uint32_t payload) -{ - jsval_layout l; - l.s.tag = JSVAL_TAG_MAGIC; - l.s.payload.u32 = payload; - return l; -} - -static inline bool -JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) -{ - JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag; - return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR); -} - -static inline JSValueType -JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) -{ - uint32_t type = l.s.tag & 0xF; - MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); - return (JSValueType)type; -} - -#elif defined(JS_PUNBOX64) - -static inline JS_VALUE_CONSTEXPR jsval_layout -BUILD_JSVAL(JSValueTag tag, uint64_t payload) -{ - JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << JSVAL_TAG_SHIFT) | payload); -} - -static inline bool -JSVAL_IS_DOUBLE_IMPL(jsval_layout l) -{ - return l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE; -} - -static inline jsval_layout -DOUBLE_TO_JSVAL_IMPL(double d) -{ - jsval_layout l; - l.asDouble = d; - MOZ_ASSERT(l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE); - return l; -} - -static inline bool -JSVAL_IS_INT32_IMPL(jsval_layout l) -{ - return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_INT32; -} - -static inline int32_t -JSVAL_TO_INT32_IMPL(jsval_layout l) -{ - return (int32_t)l.asBits; -} - -static inline JS_VALUE_CONSTEXPR jsval_layout -INT32_TO_JSVAL_IMPL(int32_t i32) -{ - JS_RETURN_LAYOUT_FROM_BITS(((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32); -} - -static inline bool -JSVAL_IS_NUMBER_IMPL(jsval_layout l) -{ - return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET; -} - -static inline bool -JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) -{ - return l.asBits == JSVAL_SHIFTED_TAG_UNDEFINED; -} - -static inline bool -JSVAL_IS_STRING_IMPL(jsval_layout l) -{ - return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING; -} - -static inline jsval_layout -STRING_TO_JSVAL_IMPL(JSString* str) -{ - jsval_layout l; - uint64_t strBits = (uint64_t)str; - MOZ_ASSERT(uintptr_t(str) > 0x1000); - MOZ_ASSERT((strBits >> JSVAL_TAG_SHIFT) == 0); - l.asBits = strBits | JSVAL_SHIFTED_TAG_STRING; - return l; -} - -static inline JSString* -JSVAL_TO_STRING_IMPL(jsval_layout l) -{ - return (JSString*)(l.asBits & JSVAL_PAYLOAD_MASK); -} - -static inline bool -JSVAL_IS_SYMBOL_IMPL(jsval_layout l) -{ - return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_SYMBOL; -} - -static inline jsval_layout -SYMBOL_TO_JSVAL_IMPL(JS::Symbol* sym) -{ - jsval_layout l; - uint64_t symBits = (uint64_t)sym; - MOZ_ASSERT(uintptr_t(sym) > 0x1000); - MOZ_ASSERT((symBits >> JSVAL_TAG_SHIFT) == 0); - l.asBits = symBits | JSVAL_SHIFTED_TAG_SYMBOL; - return l; -} - -static inline JS::Symbol* -JSVAL_TO_SYMBOL_IMPL(jsval_layout l) -{ - return (JS::Symbol*)(l.asBits & JSVAL_PAYLOAD_MASK); -} - -static inline bool -JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) -{ - return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_BOOLEAN; -} - -static inline bool -JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) -{ - return (bool)(l.asBits & JSVAL_PAYLOAD_MASK); -} - -static inline jsval_layout -BOOLEAN_TO_JSVAL_IMPL(bool b) -{ - jsval_layout l; - l.asBits = ((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN; - return l; -} - -static inline bool -JSVAL_IS_MAGIC_IMPL(jsval_layout l) -{ - return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC; -} - -static inline bool -JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) -{ - return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET; -} - -static inline bool -JSVAL_IS_OBJECT_IMPL(jsval_layout l) -{ - MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); - return l.asBits >= JSVAL_SHIFTED_TAG_OBJECT; -} - -static inline bool -JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) -{ - MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); - return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET; -} - -static inline JSObject* -JSVAL_TO_OBJECT_IMPL(jsval_layout l) -{ - uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; - MOZ_ASSERT((ptrBits & 0x7) == 0); - return (JSObject*)ptrBits; -} - -static inline jsval_layout -OBJECT_TO_JSVAL_IMPL(JSObject* obj) -{ - jsval_layout l; - uint64_t objBits = (uint64_t)obj; - MOZ_ASSERT(uintptr_t(obj) > 0x1000 || uintptr_t(obj) == 0x42); - MOZ_ASSERT((objBits >> JSVAL_TAG_SHIFT) == 0); - l.asBits = objBits | JSVAL_SHIFTED_TAG_OBJECT; - return l; -} - -static inline bool -JSVAL_IS_NULL_IMPL(jsval_layout l) -{ - return l.asBits == JSVAL_SHIFTED_TAG_NULL; -} - -static inline bool -JSVAL_IS_GCTHING_IMPL(jsval_layout l) -{ - return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET; -} - -static inline js::gc::Cell* -JSVAL_TO_GCTHING_IMPL(jsval_layout l) -{ - uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; - MOZ_ASSERT((ptrBits & 0x7) == 0); - return reinterpret_cast(ptrBits); -} - -static inline uint32_t -JSVAL_TRACE_KIND_IMPL(jsval_layout l) -{ - static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String), - "Value type tags must correspond with JS::TraceKinds."); - static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol), - "Value type tags must correspond with JS::TraceKinds."); - static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object), - "Value type tags must correspond with JS::TraceKinds."); - return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) & 0x03; -} - -static inline jsval_layout -PRIVATE_PTR_TO_JSVAL_IMPL(void* ptr) -{ - jsval_layout l; - uint64_t ptrBits = (uint64_t)ptr; - MOZ_ASSERT((ptrBits & 1) == 0); - l.asBits = ptrBits >> 1; - MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); - return l; -} - -static inline void* -JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) -{ - MOZ_ASSERT((l.asBits & 0x8000000000000000LL) == 0); - return (void*)(l.asBits << 1); -} - -static inline bool -JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32) -{ - return l.asBits == (((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32); -} - -static inline bool -JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(jsval_layout l, bool b) -{ - return l.asBits == (((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN); -} - -static inline jsval_layout -MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) -{ - jsval_layout l; - l.asBits = ((uint64_t)(uint32_t)why) | JSVAL_SHIFTED_TAG_MAGIC; - return l; -} - -static inline jsval_layout -MAGIC_UINT32_TO_JSVAL_IMPL(uint32_t payload) -{ - jsval_layout l; - l.asBits = ((uint64_t)payload) | JSVAL_SHIFTED_TAG_MAGIC; - return l; -} - -static inline bool -JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) -{ - uint64_t lbits = lhs.asBits, rbits = rhs.asBits; - return (lbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE && rbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE) || - (((lbits ^ rbits) & 0xFFFF800000000000LL) == 0); -} - -static inline JSValueType -JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) -{ - uint64_t type = (l.asBits >> JSVAL_TAG_SHIFT) & 0xF; - MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); - return (JSValueType)type; -} +namespace JS { -#endif /* JS_PUNBOX64 */ +static inline constexpr JS::Value UndefinedValue(); +static inline JS::Value PoisonedObjectValue(JSObject* obj); -static inline bool -JSVAL_IS_TRACEABLE_IMPL(jsval_layout l) -{ - return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l); -} +namespace detail { -static inline jsval_layout JSVAL_TO_IMPL(JS::Value v); -static inline JS_VALUE_CONSTEXPR JS::Value IMPL_TO_JSVAL(jsval_layout l); +constexpr int CanonicalizedNaNSignBit = 0; +constexpr uint64_t CanonicalizedNaNSignificand = 0x8000000000000ULL; -namespace JS { +constexpr uint64_t CanonicalizedNaNBits = + mozilla::SpecificNaNBits::value; -static inline JS_VALUE_CONSTEXPR JS::Value UndefinedValue(); +} // namespace detail /** * Returns a generic quiet NaN value, with all payload bits set to zero. @@ -984,7 +250,8 @@ static MOZ_ALWAYS_INLINE double GenericNaN() { - return mozilla::SpecificNaN(0, 0x8000000000000ULL); + return mozilla::SpecificNaN(detail::CanonicalizedNaNSignBit, + detail::CanonicalizedNaNSignificand); } /* MSVC with PGO miscompiles this function. */ @@ -1033,17 +300,21 @@ * 32-bit user code should avoid copying jsval/JS::Value as much as possible, * preferring to pass by const Value&. */ -class Value +class MOZ_NON_PARAM alignas(8) Value { public: +#if defined(JS_NUNBOX32) + using PayloadType = uint32_t; +#elif defined(JS_PUNBOX64) + using PayloadType = uint64_t; +#endif + /* * N.B. the default constructor leaves Value unitialized. Adding a default * constructor prevents Value from being stored in a union. */ -#if defined(JS_VALUE_IS_CONSTEXPR) Value() = default; Value(const Value& v) = default; -#endif /** * Returns false if creating a NumberValue containing the given type would @@ -1057,15 +328,15 @@ /*** Mutators ***/ void setNull() { - data.asBits = BUILD_JSVAL(JSVAL_TAG_NULL, 0).asBits; + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_NULL, 0); } void setUndefined() { - data.asBits = BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0).asBits; + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0); } void setInt32(int32_t i) { - data = INT32_TO_JSVAL_IMPL(i); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i)); } int32_t& getInt32Ref() { @@ -1074,7 +345,10 @@ } void setDouble(double d) { - data = DOUBLE_TO_JSVAL_IMPL(d); + // Don't assign to data.asDouble to fix a miscompilation with + // GCC 5.2.1 and 5.3.1. See bug 1312488. + data = layout(d); + MOZ_ASSERT(isDouble()); } void setNaN() { @@ -1087,27 +361,45 @@ } void setString(JSString* str) { - data = STRING_TO_JSVAL_IMPL(str); + MOZ_ASSERT(uintptr_t(str) > 0x1000); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_STRING, PayloadType(str)); } void setSymbol(JS::Symbol* sym) { - data = SYMBOL_TO_JSVAL_IMPL(sym); + MOZ_ASSERT(uintptr_t(sym) > 0x1000); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym)); } void setObject(JSObject& obj) { - data = OBJECT_TO_JSVAL_IMPL(&obj); + MOZ_ASSERT(uintptr_t(&obj) > 0x1000 || uintptr_t(&obj) == 0x48); +#if defined(JS_PUNBOX64) + // VisualStudio cannot contain parenthesized C++ style cast and shift + // inside decltype in template parameter: + // AssertionConditionType> 1))> + // It throws syntax error. + MOZ_ASSERT((((uintptr_t)&obj) >> JSVAL_TAG_SHIFT) == 0); +#endif + setObjectNoCheck(&obj); + } + + private: + void setObjectNoCheck(JSObject* obj) { + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_OBJECT, PayloadType(obj)); } + friend inline Value PoisonedObjectValue(JSObject* obj); + + public: void setBoolean(bool b) { - data = BOOLEAN_TO_JSVAL_IMPL(b); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(b)); } void setMagic(JSWhyMagic why) { - data = MAGIC_TO_JSVAL_IMPL(why); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, uint32_t(why)); } void setMagicUint32(uint32_t payload) { - data = MAGIC_UINT32_TO_JSVAL_IMPL(payload); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, payload); } bool setNumber(uint32_t ui) { @@ -1144,14 +436,54 @@ data.asBits = tmp; } + private: + JSValueTag toTag() const { +#if defined(JS_NUNBOX32) + return data.s.tag; +#elif defined(JS_PUNBOX64) + return JSValueTag(data.asBits >> JSVAL_TAG_SHIFT); +#endif + } + + public: + /*** JIT-only interfaces to interact with and create raw Values ***/ +#if defined(JS_NUNBOX32) + PayloadType toNunboxPayload() const { + return data.s.payload.i32; + } + + JSValueTag toNunboxTag() const { + return data.s.tag; + } +#elif defined(JS_PUNBOX64) + const void* bitsAsPunboxPointer() const { + return reinterpret_cast(data.asBits); + } +#endif + /*** Value type queries ***/ + /* + * N.B. GCC, in some but not all cases, chooses to emit signed comparison + * of JSValueTag even though its underlying type has been forced to be + * uint32_t. Thus, all comparisons should explicitly cast operands to + * uint32_t. + */ + bool isUndefined() const { - return JSVAL_IS_UNDEFINED_IMPL(data); +#if defined(JS_NUNBOX32) + return toTag() == JSVAL_TAG_UNDEFINED; +#elif defined(JS_PUNBOX64) + return data.asBits == JSVAL_SHIFTED_TAG_UNDEFINED; +#endif } bool isNull() const { - return JSVAL_IS_NULL_IMPL(data); +#if defined(JS_NUNBOX32) + return toTag() == JSVAL_TAG_NULL; +#elif defined(JS_PUNBOX64) + return data.asBits == JSVAL_SHIFTED_TAG_NULL; +#endif } bool isNullOrUndefined() const { @@ -1159,73 +491,109 @@ } bool isInt32() const { - return JSVAL_IS_INT32_IMPL(data); + return toTag() == JSVAL_TAG_INT32; } bool isInt32(int32_t i32) const { - return JSVAL_IS_SPECIFIC_INT32_IMPL(data, i32); + return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i32)); } bool isDouble() const { - return JSVAL_IS_DOUBLE_IMPL(data); +#if defined(JS_NUNBOX32) + return uint32_t(toTag()) <= uint32_t(JSVAL_TAG_CLEAR); +#elif defined(JS_PUNBOX64) + return (data.asBits | mozilla::DoubleTypeTraits::kSignBit) <= JSVAL_SHIFTED_TAG_MAX_DOUBLE; +#endif } bool isNumber() const { - return JSVAL_IS_NUMBER_IMPL(data); +#if defined(JS_NUNBOX32) + MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR); + return uint32_t(toTag()) <= uint32_t(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET); +#elif defined(JS_PUNBOX64) + return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET; +#endif } bool isString() const { - return JSVAL_IS_STRING_IMPL(data); + return toTag() == JSVAL_TAG_STRING; } bool isSymbol() const { - return JSVAL_IS_SYMBOL_IMPL(data); + return toTag() == JSVAL_TAG_SYMBOL; } bool isObject() const { - return JSVAL_IS_OBJECT_IMPL(data); +#if defined(JS_NUNBOX32) + return toTag() == JSVAL_TAG_OBJECT; +#elif defined(JS_PUNBOX64) + MOZ_ASSERT((data.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); + return data.asBits >= JSVAL_SHIFTED_TAG_OBJECT; +#endif } bool isPrimitive() const { - return JSVAL_IS_PRIMITIVE_IMPL(data); +#if defined(JS_NUNBOX32) + return uint32_t(toTag()) < uint32_t(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET); +#elif defined(JS_PUNBOX64) + return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET; +#endif } bool isObjectOrNull() const { - return JSVAL_IS_OBJECT_OR_NULL_IMPL(data); + MOZ_ASSERT(uint32_t(toTag()) <= uint32_t(JSVAL_TAG_OBJECT)); +#if defined(JS_NUNBOX32) + return uint32_t(toTag()) >= uint32_t(JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET); +#elif defined(JS_PUNBOX64) + return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET; +#endif } bool isGCThing() const { - return JSVAL_IS_GCTHING_IMPL(data); +#if defined(JS_NUNBOX32) + /* gcc sometimes generates signed < without explicit casts. */ + return uint32_t(toTag()) >= uint32_t(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET); +#elif defined(JS_PUNBOX64) + return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET; +#endif } bool isBoolean() const { - return JSVAL_IS_BOOLEAN_IMPL(data); + return toTag() == JSVAL_TAG_BOOLEAN; } bool isTrue() const { - return JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(data, true); + return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(true)); } bool isFalse() const { - return JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(data, false); + return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(false)); } bool isMagic() const { - return JSVAL_IS_MAGIC_IMPL(data); + return toTag() == JSVAL_TAG_MAGIC; } bool isMagic(JSWhyMagic why) const { MOZ_ASSERT_IF(isMagic(), data.s.payload.why == why); - return JSVAL_IS_MAGIC_IMPL(data); + return isMagic(); } bool isMarkable() const { - return JSVAL_IS_TRACEABLE_IMPL(data); + return isGCThing() && !isNull(); } JS::TraceKind traceKind() const { MOZ_ASSERT(isMarkable()); - return JS::TraceKind(JSVAL_TRACE_KIND_IMPL(data)); + static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String), + "Value type tags must correspond with JS::TraceKinds."); + static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol), + "Value type tags must correspond with JS::TraceKinds."); + static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object), + "Value type tags must correspond with JS::TraceKinds."); + if (MOZ_UNLIKELY(isPrivateGCThing())) + return JS::GCThingTraceKind(toGCThing()); + return JS::TraceKind(toTag() & 0x03); } JSWhyMagic whyMagic() const { @@ -1254,7 +622,11 @@ int32_t toInt32() const { MOZ_ASSERT(isInt32()); - return JSVAL_TO_INT32_IMPL(data); +#if defined(JS_NUNBOX32) + return data.s.payload.i32; +#elif defined(JS_PUNBOX64) + return int32_t(data.asBits); +#endif } double toDouble() const { @@ -1269,27 +641,56 @@ JSString* toString() const { MOZ_ASSERT(isString()); - return JSVAL_TO_STRING_IMPL(data); +#if defined(JS_NUNBOX32) + return data.s.payload.str; +#elif defined(JS_PUNBOX64) + return reinterpret_cast(data.asBits & JSVAL_PAYLOAD_MASK); +#endif } JS::Symbol* toSymbol() const { MOZ_ASSERT(isSymbol()); - return JSVAL_TO_SYMBOL_IMPL(data); +#if defined(JS_NUNBOX32) + return data.s.payload.sym; +#elif defined(JS_PUNBOX64) + return reinterpret_cast(data.asBits & JSVAL_PAYLOAD_MASK); +#endif } JSObject& toObject() const { MOZ_ASSERT(isObject()); - return *JSVAL_TO_OBJECT_IMPL(data); +#if defined(JS_NUNBOX32) + return *data.s.payload.obj; +#elif defined(JS_PUNBOX64) + return *toObjectOrNull(); +#endif } JSObject* toObjectOrNull() const { MOZ_ASSERT(isObjectOrNull()); - return JSVAL_TO_OBJECT_IMPL(data); +#if defined(JS_NUNBOX32) + return data.s.payload.obj; +#elif defined(JS_PUNBOX64) + uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK; + MOZ_ASSERT((ptrBits & 0x7) == 0); + return reinterpret_cast(ptrBits); +#endif } js::gc::Cell* toGCThing() const { MOZ_ASSERT(isGCThing()); - return JSVAL_TO_GCTHING_IMPL(data); +#if defined(JS_NUNBOX32) + return data.s.payload.cell; +#elif defined(JS_PUNBOX64) + uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK; + MOZ_ASSERT((ptrBits & 0x7) == 0); + return reinterpret_cast(ptrBits); +#endif + } + + js::gc::Cell* toMarkablePointer() const { + MOZ_ASSERT(isMarkable()); + return toGCThing(); } GCCellPtr toGCCellPtr() const { @@ -1298,7 +699,11 @@ bool toBoolean() const { MOZ_ASSERT(isBoolean()); - return JSVAL_TO_BOOLEAN_IMPL(data); +#if defined(JS_NUNBOX32) + return bool(data.s.payload.boo); +#elif defined(JS_PUNBOX64) + return bool(data.asBits & JSVAL_PAYLOAD_MASK); +#endif } uint32_t payloadAsRawUint32() const { @@ -1311,7 +716,9 @@ } JSValueType extractNonDoubleType() const { - return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data); + uint32_t type = toTag() & 0xF; + MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); + return JSValueType(type); } /* @@ -1324,12 +731,24 @@ */ void setPrivate(void* ptr) { - data = PRIVATE_PTR_TO_JSVAL_IMPL(ptr); + MOZ_ASSERT((uintptr_t(ptr) & 1) == 0); +#if defined(JS_NUNBOX32) + data.s.tag = JSValueTag(0); + data.s.payload.ptr = ptr; +#elif defined(JS_PUNBOX64) + data.asBits = uintptr_t(ptr) >> 1; +#endif + MOZ_ASSERT(isDouble()); } void* toPrivate() const { - MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(data)); - return JSVAL_TO_PRIVATE_PTR_IMPL(data); + MOZ_ASSERT(isDouble()); +#if defined(JS_NUNBOX32) + return data.s.payload.ptr; +#elif defined(JS_PUNBOX64) + MOZ_ASSERT((data.asBits & 0x8000000000000000ULL) == 0); + return reinterpret_cast(data.asBits << 1); +#endif } void setPrivateUint32(uint32_t ui) { @@ -1342,17 +761,35 @@ } /* - * An unmarked value is just a void* cast as a Value. Thus, the Value is - * not safe for GC and must not be marked. This API avoids raw casts - * and the ensuing strict-aliasing warnings. + * Private GC Thing API + * + * Non-JSObject, JSString, and JS::Symbol cells may be put into the 64-bit + * payload as private GC things. Such Values are considered isMarkable() + * and isGCThing(), and as such, automatically marked. Their traceKind() + * is gotten via their cells. */ - void setUnmarkedPtr(void* ptr) { - data.asPtr = ptr; + void setPrivateGCThing(js::gc::Cell* cell) { + MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String, + "Private GC thing Values must not be strings. Make a StringValue instead."); + MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol, + "Private GC thing Values must not be symbols. Make a SymbolValue instead."); + MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object, + "Private GC thing Values must not be objects. Make an ObjectValue instead."); + + MOZ_ASSERT(uintptr_t(cell) > 0x1000); +#if defined(JS_PUNBOX64) + // VisualStudio cannot contain parenthesized C++ style cast and shift + // inside decltype in template parameter: + // AssertionConditionType> 1))> + // It throws syntax error. + MOZ_ASSERT((((uintptr_t)cell) >> JSVAL_TAG_SHIFT) == 0); +#endif + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_PRIVATE_GCTHING, PayloadType(cell)); } - void* toUnmarkedPtr() const { - return data.asPtr; + bool isPrivateGCThing() const { + return toTag() == JSVAL_TAG_PRIVATE_GCTHING; } const size_t* payloadWord() const { @@ -1378,12 +815,117 @@ private: #endif - jsval_layout data; +#if MOZ_LITTLE_ENDIAN +# if defined(JS_NUNBOX32) + union layout { + uint64_t asBits; + struct { + union { + int32_t i32; + uint32_t u32; + uint32_t boo; // Don't use |bool| -- it must be four bytes. + JSString* str; + JS::Symbol* sym; + JSObject* obj; + js::gc::Cell* cell; + void* ptr; + JSWhyMagic why; + size_t word; + uintptr_t uintptr; + } payload; + JSValueTag tag; + } s; + double asDouble; + void* asPtr; + + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} + explicit constexpr layout(uint64_t bits) : asBits(bits) {} + explicit constexpr layout(double d) : asDouble(d) {} + } data; +# elif defined(JS_PUNBOX64) + union layout { + uint64_t asBits; +#if !defined(_WIN64) + /* MSVC does not pack these correctly :-( */ + struct { + uint64_t payload47 : 47; + JSValueTag tag : 17; + } debugView; +#endif + struct { + union { + int32_t i32; + uint32_t u32; + JSWhyMagic why; + } payload; + } s; + double asDouble; + void* asPtr; + size_t asWord; + uintptr_t asUIntPtr; + + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} + explicit constexpr layout(uint64_t bits) : asBits(bits) {} + explicit constexpr layout(double d) : asDouble(d) {} + } data; +# endif /* JS_PUNBOX64 */ +#else /* MOZ_LITTLE_ENDIAN */ +# if defined(JS_NUNBOX32) + union layout { + uint64_t asBits; + struct { + JSValueTag tag; + union { + int32_t i32; + uint32_t u32; + uint32_t boo; // Don't use |bool| -- it must be four bytes. + JSString* str; + JS::Symbol* sym; + JSObject* obj; + js::gc::Cell* cell; + void* ptr; + JSWhyMagic why; + size_t word; + uintptr_t uintptr; + } payload; + } s; + double asDouble; + void* asPtr; + + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} + explicit constexpr layout(uint64_t bits) : asBits(bits) {} + explicit constexpr layout(double d) : asDouble(d) {} + } data; +# elif defined(JS_PUNBOX64) + union layout { + uint64_t asBits; + struct { + JSValueTag tag : 17; + uint64_t payload47 : 47; + } debugView; + struct { + uint32_t padding; + union { + int32_t i32; + uint32_t u32; + JSWhyMagic why; + } payload; + } s; + double asDouble; + void* asPtr; + size_t asWord; + uintptr_t asUIntPtr; + + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} + explicit constexpr layout(uint64_t bits) : asBits(bits) {} + explicit constexpr layout(double d) : asDouble(d) {} + } data; +# endif /* JS_PUNBOX64 */ +#endif /* MOZ_LITTLE_ENDIAN */ private: -#if defined(JS_VALUE_IS_CONSTEXPR) - MOZ_IMPLICIT JS_VALUE_CONSTEXPR Value(jsval_layout layout) : data(layout) {} -#endif + explicit constexpr Value(uint64_t asBits) : data(asBits) {} + explicit constexpr Value(double d) : data(d) {} void staticAssertions() { JS_STATIC_ASSERT(sizeof(JSValueType) == 1); @@ -1392,11 +934,86 @@ JS_STATIC_ASSERT(sizeof(Value) == 8); } - friend jsval_layout (::JSVAL_TO_IMPL)(Value); - friend Value JS_VALUE_CONSTEXPR (::IMPL_TO_JSVAL)(jsval_layout l); - friend Value JS_VALUE_CONSTEXPR (JS::UndefinedValue)(); + friend constexpr Value JS::UndefinedValue(); + + public: + static constexpr uint64_t + bitsFromTagAndPayload(JSValueTag tag, PayloadType payload) + { +#if defined(JS_NUNBOX32) + return (uint64_t(uint32_t(tag)) << 32) | payload; +#elif defined(JS_PUNBOX64) + return (uint64_t(uint32_t(tag)) << JSVAL_TAG_SHIFT) | payload; +#endif + } + + static constexpr Value + fromTagAndPayload(JSValueTag tag, PayloadType payload) + { + return fromRawBits(bitsFromTagAndPayload(tag, payload)); + } + + static constexpr Value + fromRawBits(uint64_t asBits) { + return Value(asBits); + } + + static constexpr Value + fromInt32(int32_t i) { + return fromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i)); + } + + static constexpr Value + fromDouble(double d) { + return Value(d); + } +} JS_HAZ_GC_POINTER; + +/** + * This is a null-constructible structure that can convert to and from + * a Value, allowing UninitializedValue to be stored in unions. + */ +struct MOZ_NON_PARAM alignas(8) UninitializedValue +{ + private: + uint64_t bits; + + public: + UninitializedValue() = default; + UninitializedValue(const UninitializedValue&) = default; + MOZ_IMPLICIT UninitializedValue(const Value& val) : bits(val.asRawBits()) {} + + inline uint64_t asRawBits() const { + return bits; + } + + inline Value& asValueRef() { + return *reinterpret_cast(this); + } + inline const Value& asValueRef() const { + return *reinterpret_cast(this); + } + + inline operator Value&() { + return asValueRef(); + } + inline operator Value const&() const { + return asValueRef(); + } + inline operator Value() const { + return asValueRef(); + } + + inline void operator=(Value const& other) { + asValueRef() = other; + } }; +static_assert(sizeof(Value) == 8, "Value size must leave three tag bits, be a binary power, and is ubiquitously depended upon everywhere"); + +static_assert(sizeof(UninitializedValue) == sizeof(Value), "Value and UninitializedValue must be the same size"); +static_assert(alignof(UninitializedValue) == alignof(Value), "Value and UninitializedValue must have same alignment"); + inline bool IsOptimizedPlaceholderMagicValue(const Value& v) { @@ -1424,22 +1041,16 @@ return v; } -static inline JS_VALUE_CONSTEXPR Value +static inline constexpr Value UndefinedValue() { -#if defined(JS_VALUE_IS_CONSTEXPR) - return Value(BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0)); -#else - JS::Value v; - v.setUndefined(); - return v; -#endif + return Value::fromTagAndPayload(JSVAL_TAG_UNDEFINED, 0); } -static inline JS_VALUE_CONSTEXPR Value +static inline constexpr Value Int32Value(int32_t i32) { - return IMPL_TO_JSVAL(INT32_TO_JSVAL_IMPL(i32)); + return Value::fromInt32(i32); } static inline Value @@ -1450,27 +1061,23 @@ return v; } -static inline JS_VALUE_CONSTEXPR Value +static inline Value CanonicalizedDoubleValue(double d) { - /* - * This is a manually inlined version of: - * d = JS_CANONICALIZE_NAN(d); - * return IMPL_TO_JSVAL(DOUBLE_TO_JSVAL_IMPL(d)); - * because GCC from XCode 3.1.4 miscompiles the above code. - */ -#if defined(JS_VALUE_IS_CONSTEXPR) - return IMPL_TO_JSVAL(MOZ_UNLIKELY(mozilla::IsNaN(d)) - ? (jsval_layout) { .asBits = 0x7FF8000000000000LL } - : (jsval_layout) { .asDouble = d }); -#else - jsval_layout l; - if (MOZ_UNLIKELY(d != d)) - l.asBits = 0x7FF8000000000000LL; - else - l.asDouble = d; - return IMPL_TO_JSVAL(l); -#endif + return MOZ_UNLIKELY(mozilla::IsNaN(d)) + ? Value::fromRawBits(detail::CanonicalizedNaNBits) + : Value::fromDouble(d); +} + +static inline bool +IsCanonicalized(double d) +{ + if (mozilla::IsInfinite(d) || mozilla::IsFinite(d)) + return true; + + uint64_t bits; + mozilla::BitwiseCast(d, &bits); + return (bits & ~mozilla::DoubleTypeTraits::kSignBit) == detail::CanonicalizedNaNBits; } static inline Value @@ -1541,7 +1148,7 @@ ObjectValueCrashOnTouch() { Value v; - v.setObject(*reinterpret_cast(0x42)); + v.setObject(*reinterpret_cast(0x48)); return v; } @@ -1607,12 +1214,12 @@ return Int32Value(i); } -static inline JS_VALUE_CONSTEXPR Value +static inline constexpr Value NumberValue(uint32_t i) { return i <= JSVAL_INT_MAX ? Int32Value(int32_t(i)) - : CanonicalizedDoubleValue(double(i)); + : Value::fromDouble(double(i)); } namespace detail { @@ -1683,10 +1290,32 @@ return v; } +static inline Value +PrivateGCThingValue(js::gc::Cell* cell) +{ + Value v; + v.setPrivateGCThing(cell); + return v; +} + +static inline Value +PoisonedObjectValue(JSObject* obj) +{ + Value v; + v.setObjectNoCheck(obj); + return v; +} + inline bool SameType(const Value& lhs, const Value& rhs) { - return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data); +#if defined(JS_NUNBOX32) + JSValueTag ltag = lhs.toTag(), rtag = rhs.toTag(); + return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR); +#elif defined(JS_PUNBOX64) + return (lhs.isDouble() && rhs.isDouble()) || + (((lhs.data.asBits ^ rhs.data.asBits) & 0xFFFF800000000000ULL) == 0); +#endif } } // namespace JS @@ -1695,24 +1324,35 @@ namespace JS { JS_PUBLIC_API(void) HeapValuePostBarrier(Value* valuep, const Value& prev, const Value& next); -} // namespace JS -namespace js { - -template <> struct GCMethods +template <> +struct GCPolicy { - static JS::Value initial() { return JS::UndefinedValue(); } + static Value initial() { return UndefinedValue(); } + static void trace(JSTracer* trc, Value* v, const char* name) { + js::UnsafeTraceManuallyBarrieredEdge(trc, v, name); + } + static bool isTenured(const Value& thing) { + return !thing.isGCThing() || !IsInsideNursery(thing.toGCThing()); + } }; -template <> struct GCMethods +} // namespace JS + +namespace js { + +template <> +struct BarrierMethods { - static JS::Value initial() { return JS::UndefinedValue(); } static gc::Cell* asGCThingOrNull(const JS::Value& v) { return v.isMarkable() ? v.toGCThing() : nullptr; } static void postBarrier(JS::Value* v, const JS::Value& prev, const JS::Value& next) { JS::HeapValuePostBarrier(v, prev, next); } + static void exposeToJS(const JS::Value& v) { + JS::ExposeValueToActiveJS(v); + } }; template class MutableValueOperations; @@ -1762,10 +1402,11 @@ JSObject* toObjectOrNull() const { return value().toObjectOrNull(); } gc::Cell* toGCThing() const { return value().toGCThing(); } JS::TraceKind traceKind() const { return value().traceKind(); } - uint64_t asRawBits() const { return value().asRawBits(); } + void* toPrivate() const { return value().toPrivate(); } + uint32_t toPrivateUint32() const { return value().toPrivateUint32(); } + uint64_t asRawBits() const { return value().asRawBits(); } JSValueType extractNonDoubleType() const { return value().extractNonDoubleType(); } - uint32_t toPrivateUint32() const { return value().toPrivateUint32(); } JSWhyMagic whyMagic() const { return value().whyMagic(); } uint32_t magicUint32() const { return value().magicUint32(); } @@ -1796,6 +1437,9 @@ void setSymbol(JS::Symbol* sym) { this->value().setSymbol(sym); } void setObject(JSObject& obj) { this->value().setObject(obj); } void setObjectOrNull(JSObject* arg) { this->value().setObjectOrNull(arg); } + void setPrivate(void* ptr) { this->value().setPrivate(ptr); } + void setPrivateUint32(uint32_t ui) { this->value().setPrivateUint32(ui); } + void setPrivateGCThing(js::gc::Cell* cell) { this->value().setPrivateGCThing(cell); } }; /* @@ -1824,6 +1468,7 @@ void setString(JSString* str) { setBarriered(JS::StringValue(str)); } void setSymbol(JS::Symbol* sym) { setBarriered(JS::SymbolValue(sym)); } void setObject(JSObject& obj) { setBarriered(JS::ObjectValue(obj)); } + void setPrivateGCThing(js::gc::Cell* cell) { setBarriered(JS::PrivateGCThingValue(cell)); } bool setNumber(uint32_t ui) { if (ui > JSVAL_INT_MAX) { @@ -1885,55 +1530,18 @@ return f(&val.toObject(), mozilla::Forward(args)...); if (val.isSymbol()) return f(val.toSymbol(), mozilla::Forward(args)...); + if (MOZ_UNLIKELY(val.isPrivateGCThing())) + return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward(args)...); MOZ_ASSERT(!val.isMarkable()); return F::defaultValue(val); } -template struct VoidDefaultAdaptor { static void defaultValue(S) {} }; +template struct VoidDefaultAdaptor { static void defaultValue(const S&) {} }; template struct IdentityDefaultAdaptor { static S defaultValue(const S& v) {return v;} }; -template struct BoolDefaultAdaptor { static bool defaultValue(S) { return v; } }; +template struct BoolDefaultAdaptor { static bool defaultValue(const S&) { return v; } }; } // namespace js -inline jsval_layout -JSVAL_TO_IMPL(JS::Value v) -{ - return v.data; -} - -inline JS_VALUE_CONSTEXPR JS::Value -IMPL_TO_JSVAL(jsval_layout l) -{ -#if defined(JS_VALUE_IS_CONSTEXPR) - return JS::Value(l); -#else - JS::Value v; - v.data = l; - return v; -#endif -} - -namespace JS { - -#ifdef JS_DEBUG -namespace detail { - -struct ValueAlignmentTester { char c; JS::Value v; }; -static_assert(sizeof(ValueAlignmentTester) == 16, - "JS::Value must be 16-byte-aligned"); - -struct LayoutAlignmentTester { char c; jsval_layout l; }; -static_assert(sizeof(LayoutAlignmentTester) == 16, - "jsval_layout must be 16-byte-aligned"); - -} // namespace detail -#endif /* JS_DEBUG */ - -} // namespace JS - -static_assert(sizeof(jsval_layout) == sizeof(JS::Value), - "jsval_layout and JS::Value must have identical layouts"); - /************************************************************************/ namespace JS { @@ -1945,7 +1553,4 @@ } // namespace JS -#undef JS_VALUE_IS_CONSTEXPR -#undef JS_RETURN_LAYOUT_FROM_BITS - #endif /* js_Value_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Vector.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Vector.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Vector.h @@ -34,15 +34,9 @@ template ::value>::Type -#endif + typename = typename mozilla::EnableIf::value>::Type > using Vector = mozilla::Vector; Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsalloc.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsalloc.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsalloc.h @@ -51,7 +51,7 @@ }; class ExclusiveContext; -void ReportOutOfMemory(ExclusiveContext* cxArg); +JS_FRIEND_API(void) ReportOutOfMemory(ExclusiveContext* cxArg); /* * Allocation policy that calls the system memory functions and reports errors @@ -132,7 +132,7 @@ bool checkSimulatedOOM() const { if (js::oom::ShouldFailWithOOM()) { - JS_ReportOutOfMemory(reinterpret_cast(cx_)); + js::ReportOutOfMemory(reinterpret_cast(cx_)); return false; } Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsapi.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsapi.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsapi.h @@ -14,7 +14,9 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/Range.h" #include "mozilla/RangedPtr.h" +#include "mozilla/RefCounted.h" #include "mozilla/RefPtr.h" +#include "mozilla/Variant.h" #include #include @@ -25,12 +27,14 @@ #include "jspubtd.h" #include "js/CallArgs.h" +#include "js/CharacterEncoding.h" #include "js/Class.h" +#include "js/GCVector.h" #include "js/HashTable.h" #include "js/Id.h" #include "js/Principals.h" +#include "js/Realm.h" #include "js/RootingAPI.h" -#include "js/TraceableVector.h" #include "js/TracingAPI.h" #include "js/Utility.h" #include "js/Value.h" @@ -123,14 +127,14 @@ size_t length() const { return vector.length(); } bool empty() const { return vector.empty(); } - bool append(const T& v) { return vector.append(v); } - bool appendN(const T& v, size_t len) { return vector.appendN(v, len); } - bool append(const T* ptr, size_t len) { return vector.append(ptr, len); } - bool appendAll(const AutoVectorRooterBase& other) { + MOZ_MUST_USE bool append(const T& v) { return vector.append(v); } + MOZ_MUST_USE bool appendN(const T& v, size_t len) { return vector.appendN(v, len); } + MOZ_MUST_USE bool append(const T* ptr, size_t len) { return vector.append(ptr, len); } + MOZ_MUST_USE bool appendAll(const AutoVectorRooterBase& other) { return vector.appendAll(other.vector); } - bool insert(T* p, const T& val) { return vector.insert(p, val); } + MOZ_MUST_USE bool insert(T* p, const T& val) { return vector.insert(p, val); } /* For use when space has already been reserved. */ void infallibleAppend(const T& v) { vector.infallibleAppend(v); } @@ -138,7 +142,7 @@ void popBack() { vector.popBack(); } T popCopy() { return vector.popCopy(); } - bool growBy(size_t inc) { + MOZ_MUST_USE bool growBy(size_t inc) { size_t oldLength = vector.length(); if (!vector.growByUninitialized(inc)) return false; @@ -146,7 +150,7 @@ return true; } - bool resize(size_t newLength) { + MOZ_MUST_USE bool resize(size_t newLength) { size_t oldLength = vector.length(); if (newLength <= oldLength) { vector.shrinkBy(oldLength - newLength); @@ -160,7 +164,7 @@ void clear() { vector.clear(); } - bool reserve(size_t newLength) { + MOZ_MUST_USE bool reserve(size_t newLength) { return vector.reserve(newLength); } @@ -214,13 +218,36 @@ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; -typedef AutoVectorRooter AutoValueVector; -typedef AutoVectorRooter AutoIdVector; -typedef AutoVectorRooter AutoObjectVector; - -using ValueVector = js::TraceableVector; -using IdVector = js::TraceableVector; -using ScriptVector = js::TraceableVector; +class AutoValueVector : public Rooted> { + using Vec = GCVector; + using Base = Rooted; + public: + explicit AutoValueVector(JSContext* cx) : Base(cx, Vec(cx)) {} + explicit AutoValueVector(js::ContextFriendFields* cx) : Base(cx, Vec(cx)) {} +}; + +class AutoIdVector : public Rooted> { + using Vec = GCVector; + using Base = Rooted; + public: + explicit AutoIdVector(JSContext* cx) : Base(cx, Vec(cx)) {} + explicit AutoIdVector(js::ContextFriendFields* cx) : Base(cx, Vec(cx)) {} + + bool appendAll(const AutoIdVector& other) { return this->Base::appendAll(other.get()); } +}; + +class AutoObjectVector : public Rooted> { + using Vec = GCVector; + using Base = Rooted; + public: + explicit AutoObjectVector(JSContext* cx) : Base(cx, Vec(cx)) {} + explicit AutoObjectVector(js::ContextFriendFields* cx) : Base(cx, Vec(cx)) {} +}; + +using ValueVector = JS::GCVector; +using IdVector = JS::GCVector; +using ScriptVector = JS::GCVector; +using StringVector = JS::GCVector; template class MOZ_RAII AutoHashMapRooter : protected AutoGCRooter @@ -454,7 +481,7 @@ { public: template - explicit CustomAutoRooter(CX* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + explicit CustomAutoRooter(const CX& cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : AutoGCRooter(cx, CUSTOM) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; @@ -463,6 +490,8 @@ friend void AutoGCRooter::trace(JSTracer* trc); protected: + virtual ~CustomAutoRooter() {} + /** Supplied by derived class to trace roots. */ virtual void trace(JSTracer* trc) = 0; @@ -518,15 +547,15 @@ /************************************************************************/ struct JSFreeOp { - private: + protected: JSRuntime* runtime_; - protected: explicit JSFreeOp(JSRuntime* rt) : runtime_(rt) { } public: JSRuntime* runtime() const { + MOZ_ASSERT(runtime_); return runtime_; } }; @@ -535,46 +564,28 @@ /************************************************************************/ -typedef enum JSContextOp { - JSCONTEXT_NEW, - JSCONTEXT_DESTROY -} JSContextOp; - -/** - * The possible values for contextOp when the runtime calls the callback are: - * JSCONTEXT_NEW JS_NewContext successfully created a new JSContext - * instance. The callback can initialize the instance as - * required. If the callback returns false, the instance - * will be destroyed and JS_NewContext returns null. In - * this case the callback is not called again. - * JSCONTEXT_DESTROY One of JS_DestroyContext* methods is called. The - * callback may perform its own cleanup and must always - * return true. - * Any other value For future compatibility the callback must do nothing - * and return true in this case. - */ -typedef bool -(* JSContextCallback)(JSContext* cx, unsigned contextOp, void* data); - typedef enum JSGCStatus { JSGC_BEGIN, JSGC_END } JSGCStatus; typedef void -(* JSGCCallback)(JSRuntime* rt, JSGCStatus status, void* data); +(* JSGCCallback)(JSContext* cx, JSGCStatus status, void* data); + +typedef void +(* JSObjectsTenuredCallback)(JSContext* cx, void* data); typedef enum JSFinalizeStatus { /** - * Called when preparing to sweep a group of compartments, before anything - * has been swept. The collector will not yield to the mutator before - * calling the callback with JSFINALIZE_GROUP_END status. + * Called when preparing to sweep a group of zones, before anything has been + * swept. The collector will not yield to the mutator before calling the + * callback with JSFINALIZE_GROUP_END status. */ JSFINALIZE_GROUP_START, /** - * Called when preparing to sweep a group of compartments. Weak references - * to unmarked things have been removed and things that are not swept + * Called when preparing to sweep a group of zones. Weak references to + * unmarked things have been removed and things that are not swept * incrementally have been finalized at this point. The collector may yield * to the mutator after this point. */ @@ -587,28 +598,48 @@ } JSFinalizeStatus; typedef void -(* JSFinalizeCallback)(JSFreeOp* fop, JSFinalizeStatus status, bool isCompartment, void* data); +(* JSFinalizeCallback)(JSFreeOp* fop, JSFinalizeStatus status, bool isZoneGC, void* data); typedef void -(* JSWeakPointerZoneGroupCallback)(JSRuntime* rt, void* data); +(* JSWeakPointerZoneGroupCallback)(JSContext* cx, void* data); typedef void -(* JSWeakPointerCompartmentCallback)(JSRuntime* rt, JSCompartment* comp, void* data); +(* JSWeakPointerCompartmentCallback)(JSContext* cx, JSCompartment* comp, void* data); typedef bool (* JSInterruptCallback)(JSContext* cx); +typedef JSObject* +(* JSGetIncumbentGlobalCallback)(JSContext* cx); + +typedef bool +(* JSEnqueuePromiseJobCallback)(JSContext* cx, JS::HandleObject job, + JS::HandleObject allocationSite, JS::HandleObject incumbentGlobal, + void* data); + +enum class PromiseRejectionHandlingState { + Unhandled, + Handled +}; + typedef void -(* JSErrorReporter)(JSContext* cx, const char* message, JSErrorReport* report); +(* JSPromiseRejectionTrackerCallback)(JSContext* cx, JS::HandleObject promise, + PromiseRejectionHandlingState state, void* data); + +typedef void +(* JSProcessPromiseCallback)(JSContext* cx, JS::HandleObject promise); /** * Possible exception types. These types are part of a JSErrorFormatString * structure. They define which error to throw in case of a runtime error. - * JSEXN_NONE marks an unthrowable 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. */ typedef enum JSExnType { - JSEXN_NONE = -1, - JSEXN_ERR, + JSEXN_ERR, + JSEXN_FIRST = JSEXN_ERR, JSEXN_INTERNALERR, JSEXN_EVALERR, JSEXN_RANGEERR, @@ -616,10 +647,17 @@ JSEXN_SYNTAXERR, JSEXN_TYPEERR, JSEXN_URIERR, - JSEXN_LIMIT + JSEXN_DEBUGGEEWOULDRUN, + JSEXN_WASMCOMPILEERROR, + JSEXN_WASMRUNTIMEERROR, + JSEXN_WARN, + JSEXN_LIMIT } JSExnType; typedef struct JSErrorFormatString { + /** The error message name in ASCII. */ + const char* name; + /** The error format string in ASCII. */ const char* format; @@ -663,9 +701,10 @@ * for wrapping in a context. This might include unwrapping other wrappers * or even finding a more suitable object for the new compartment. */ -typedef JSObject* +typedef void (* JSPreWrapCallback)(JSContext* cx, JS::HandleObject scope, JS::HandleObject obj, - JS::HandleObject objectPassedToWrap); + JS::HandleObject objectPassedToWrap, + JS::MutableHandleObject retObj); struct JSWrapObjectCallbacks { @@ -676,11 +715,15 @@ typedef void (* JSDestroyCompartmentCallback)(JSFreeOp* fop, JSCompartment* compartment); +typedef size_t +(* JSSizeOfIncludingThisCompartmentCallback)(mozilla::MallocSizeOf mallocSizeOf, + JSCompartment* compartment); + typedef void (* JSZoneCallback)(JS::Zone* zone); typedef void -(* JSCompartmentNameCallback)(JSRuntime* rt, JSCompartment* compartment, +(* JSCompartmentNameCallback)(JSContext* cx, JSCompartment* compartment, char* buf, size_t bufsize); /************************************************************************/ @@ -746,6 +789,16 @@ } } + SourceBufferHolder(SourceBufferHolder&& other) + : data_(other.data_), + length_(other.length_), + ownsChars_(other.ownsChars_) + { + other.data_ = nullptr; + other.length_ = 0; + other.ownsChars_ = false; + } + ~SourceBufferHolder() { if (ownsChars_) js_free(const_cast(data_)); @@ -815,29 +868,17 @@ object that delegates to a prototype containing this property */ #define JSPROP_INTERNAL_USE_BIT 0x80 /* internal JS engine use only */ -#define JSPROP_DEFINE_LATE 0x100 /* Don't define property when initially creating - the constructor. Some objects like Function/Object - have self-hosted functions that can only be defined - after the initialization is already finished. */ #define JSFUN_STUB_GSOPS 0x200 /* use JS_PropertyStub getter/setter instead of defaulting to class gsops for property holding function */ #define JSFUN_CONSTRUCTOR 0x400 /* native that can be called as a ctor */ -/* - * Specify a generic native prototype methods, i.e., methods of a class - * prototype that are exposed as static methods taking an extra leading - * argument: the generic |this| parameter. - * - * If you set this flag in a JSFunctionSpec struct's flags initializer, then - * that struct must live at least as long as the native static method object - * created due to this flag by JS_DefineFunctions or JS_InitClass. Typically - * JSFunctionSpec structs are allocated in static arrays. - */ -#define JSFUN_GENERIC_NATIVE 0x800 +// 0x800 /* Unused */ + +#define JSFUN_HAS_REST 0x1000 /* function has ...rest parameter. */ -#define JSFUN_FLAGS_MASK 0xe00 /* | of all the JSFUN_* flags */ +#define JSFUN_FLAGS_MASK 0x1e00 /* | of all the JSFUN_* flags */ /* * If set, will allow redefining a non-configurable property, but only on a @@ -873,17 +914,6 @@ specified when passed to Object.defineProperty from script. */ -/** - * The first call to JS_CallOnce by any thread in a process will call 'func'. - * Later calls to JS_CallOnce with the same JSCallOnceType object will be - * suppressed. - * - * Equivalently: each distinct JSCallOnceType object will allow one JS_CallOnce - * to invoke its JSInitCallback. - */ -extern JS_PUBLIC_API(bool) -JS_CallOnce(JSCallOnceType* once, JSInitCallback func); - /** Microseconds since the epoch, midnight, January 1, 1970 UTC. */ extern JS_PUBLIC_API(int64_t) JS_Now(void); @@ -902,7 +932,7 @@ JS_GetEmptyStringValue(JSContext* cx); extern JS_PUBLIC_API(JSString*) -JS_GetEmptyString(JSRuntime* rt); +JS_GetEmptyString(JSContext* cx); extern JS_PUBLIC_API(bool) JS_ValueToObject(JSContext* cx, JS::HandleValue v, JS::MutableHandleObject objp); @@ -922,6 +952,13 @@ extern JS_PUBLIC_API(JSType) JS_TypeOfValue(JSContext* cx, JS::Handle v); +namespace JS { + +extern JS_PUBLIC_API(const char*) +InformalValueTypeName(const JS::Value& v); + +} /* namespace JS */ + extern JS_PUBLIC_API(bool) JS_StrictlyEqual(JSContext* cx, JS::Handle v1, JS::Handle v2, bool* equal); @@ -944,19 +981,19 @@ /* * Locking, contexts, and memory allocation. * - * It is important that SpiderMonkey be initialized, and the first runtime and - * first context be created, in a single-threaded fashion. Otherwise the - * behavior of the library is undefined. + * It is important that SpiderMonkey be initialized, and the first context + * be created, in a single-threaded fashion. Otherwise the behavior of the + * library is undefined. * See: http://developer.mozilla.org/en/docs/Category:JSAPI_Reference */ -extern JS_PUBLIC_API(JSRuntime*) -JS_NewRuntime(uint32_t maxbytes, +extern JS_PUBLIC_API(JSContext*) +JS_NewContext(uint32_t maxbytes, uint32_t maxNurseryBytes = JS::DefaultNurseryBytes, - JSRuntime* parentRuntime = nullptr); + JSContext* parentContext = nullptr); extern JS_PUBLIC_API(void) -JS_DestroyRuntime(JSRuntime* rt); +JS_DestroyContext(JSContext* cx); typedef double (*JS_CurrentEmbedderTimeFunction)(); @@ -978,16 +1015,13 @@ JS_GetCurrentEmbedderTime(); JS_PUBLIC_API(void*) -JS_GetRuntimePrivate(JSRuntime* rt); - -extern JS_PUBLIC_API(JSRuntime*) -JS_GetRuntime(JSContext* cx); - -extern JS_PUBLIC_API(JSRuntime*) -JS_GetParentRuntime(JSContext* cx); +JS_GetContextPrivate(JSContext* cx); JS_PUBLIC_API(void) -JS_SetRuntimePrivate(JSRuntime* rt, void* data); +JS_SetContextPrivate(JSContext* cx, void* data); + +extern JS_PUBLIC_API(JSContext*) +JS_GetParentContext(JSContext* cx); extern JS_PUBLIC_API(void) JS_BeginRequest(JSContext* cx); @@ -995,14 +1029,14 @@ extern JS_PUBLIC_API(void) JS_EndRequest(JSContext* cx); +extern JS_PUBLIC_API(void) +JS_SetFutexCanWait(JSContext* cx); + namespace js { void AssertHeapIsIdle(JSRuntime* rt); -void -AssertHeapIsIdle(JSContext* cx); - } /* namespace js */ class MOZ_RAII JSAutoRequest @@ -1030,36 +1064,6 @@ #endif }; -extern JS_PUBLIC_API(void) -JS_SetContextCallback(JSRuntime* rt, JSContextCallback cxCallback, void* data); - -extern JS_PUBLIC_API(JSContext*) -JS_NewContext(JSRuntime* rt, size_t stackChunkSize); - -extern JS_PUBLIC_API(void) -JS_DestroyContext(JSContext* cx); - -extern JS_PUBLIC_API(void) -JS_DestroyContextNoGC(JSContext* cx); - -extern JS_PUBLIC_API(void*) -JS_GetContextPrivate(JSContext* cx); - -extern JS_PUBLIC_API(void) -JS_SetContextPrivate(JSContext* cx, void* data); - -extern JS_PUBLIC_API(void*) -JS_GetSecondContextPrivate(JSContext* cx); - -extern JS_PUBLIC_API(void) -JS_SetSecondContextPrivate(JSContext* cx, void* data); - -extern JS_PUBLIC_API(JSRuntime*) -JS_GetRuntime(JSContext* cx); - -extern JS_PUBLIC_API(JSContext*) -JS_ContextIterator(JSRuntime* rt, JSContext** iterp); - extern JS_PUBLIC_API(JSVersion) JS_GetVersion(JSContext* cx); @@ -1082,16 +1086,20 @@ namespace JS { -class JS_PUBLIC_API(RuntimeOptions) { +class JS_PUBLIC_API(ContextOptions) { public: - RuntimeOptions() + ContextOptions() : baseline_(true), ion_(true), asmJS_(true), + wasm_(false), + wasmAlwaysBaseline_(false), throwOnAsmJSValidationFailure_(false), nativeRegExp_(true), unboxedArrays_(false), asyncStack_(true), + throwOnDebuggeeWouldRun_(true), + dumpStackOnDebuggeeWouldRun_(false), werror_(false), strictMode_(false), extraWarnings_(false) @@ -1099,89 +1107,121 @@ } bool baseline() const { return baseline_; } - RuntimeOptions& setBaseline(bool flag) { + ContextOptions& setBaseline(bool flag) { baseline_ = flag; return *this; } - RuntimeOptions& toggleBaseline() { + ContextOptions& toggleBaseline() { baseline_ = !baseline_; return *this; } bool ion() const { return ion_; } - RuntimeOptions& setIon(bool flag) { + ContextOptions& setIon(bool flag) { ion_ = flag; return *this; } - RuntimeOptions& toggleIon() { + ContextOptions& toggleIon() { ion_ = !ion_; return *this; } bool asmJS() const { return asmJS_; } - RuntimeOptions& setAsmJS(bool flag) { + ContextOptions& setAsmJS(bool flag) { asmJS_ = flag; return *this; } - RuntimeOptions& toggleAsmJS() { + 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 wasmAlwaysBaseline() const { return wasmAlwaysBaseline_; } + ContextOptions& setWasmAlwaysBaseline(bool flag) { + wasmAlwaysBaseline_ = flag; + return *this; + } + ContextOptions& toggleWasmAlwaysBaseline() { + wasmAlwaysBaseline_ = !wasmAlwaysBaseline_; + return *this; + } + bool throwOnAsmJSValidationFailure() const { return throwOnAsmJSValidationFailure_; } - RuntimeOptions& setThrowOnAsmJSValidationFailure(bool flag) { + ContextOptions& setThrowOnAsmJSValidationFailure(bool flag) { throwOnAsmJSValidationFailure_ = flag; return *this; } - RuntimeOptions& toggleThrowOnAsmJSValidationFailure() { + ContextOptions& toggleThrowOnAsmJSValidationFailure() { throwOnAsmJSValidationFailure_ = !throwOnAsmJSValidationFailure_; return *this; } bool nativeRegExp() const { return nativeRegExp_; } - RuntimeOptions& setNativeRegExp(bool flag) { + ContextOptions& setNativeRegExp(bool flag) { nativeRegExp_ = flag; return *this; } bool unboxedArrays() const { return unboxedArrays_; } - RuntimeOptions& setUnboxedArrays(bool flag) { + ContextOptions& setUnboxedArrays(bool flag) { unboxedArrays_ = flag; return *this; } bool asyncStack() const { return asyncStack_; } - RuntimeOptions& setAsyncStack(bool flag) { + 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_; } - RuntimeOptions& setWerror(bool flag) { + ContextOptions& setWerror(bool flag) { werror_ = flag; return *this; } - RuntimeOptions& toggleWerror() { + ContextOptions& toggleWerror() { werror_ = !werror_; return *this; } bool strictMode() const { return strictMode_; } - RuntimeOptions& setStrictMode(bool flag) { + ContextOptions& setStrictMode(bool flag) { strictMode_ = flag; return *this; } - RuntimeOptions& toggleStrictMode() { + ContextOptions& toggleStrictMode() { strictMode_ = !strictMode_; return *this; } bool extraWarnings() const { return extraWarnings_; } - RuntimeOptions& setExtraWarnings(bool flag) { + ContextOptions& setExtraWarnings(bool flag) { extraWarnings_ = flag; return *this; } - RuntimeOptions& toggleExtraWarnings() { + ContextOptions& toggleExtraWarnings() { extraWarnings_ = !extraWarnings_; return *this; } @@ -1190,94 +1230,36 @@ bool baseline_ : 1; bool ion_ : 1; bool asmJS_ : 1; + bool wasm_ : 1; + bool wasmAlwaysBaseline_ : 1; bool throwOnAsmJSValidationFailure_ : 1; bool nativeRegExp_ : 1; bool unboxedArrays_ : 1; bool asyncStack_ : 1; + bool throwOnDebuggeeWouldRun_ : 1; + bool dumpStackOnDebuggeeWouldRun_ : 1; bool werror_ : 1; bool strictMode_ : 1; bool extraWarnings_ : 1; }; -JS_PUBLIC_API(RuntimeOptions&) -RuntimeOptionsRef(JSRuntime* rt); - -JS_PUBLIC_API(RuntimeOptions&) -RuntimeOptionsRef(JSContext* cx); - -class JS_PUBLIC_API(ContextOptions) { - public: - ContextOptions() - : privateIsNSISupports_(false), - dontReportUncaught_(false), - autoJSAPIOwnsErrorReporting_(false) - { - } - - bool privateIsNSISupports() const { return privateIsNSISupports_; } - ContextOptions& setPrivateIsNSISupports(bool flag) { - privateIsNSISupports_ = flag; - return *this; - } - ContextOptions& togglePrivateIsNSISupports() { - privateIsNSISupports_ = !privateIsNSISupports_; - return *this; - } - - bool dontReportUncaught() const { return dontReportUncaught_; } - ContextOptions& setDontReportUncaught(bool flag) { - dontReportUncaught_ = flag; - return *this; - } - ContextOptions& toggleDontReportUncaught() { - dontReportUncaught_ = !dontReportUncaught_; - return *this; - } - - bool autoJSAPIOwnsErrorReporting() const { return autoJSAPIOwnsErrorReporting_; } - ContextOptions& setAutoJSAPIOwnsErrorReporting(bool flag) { - autoJSAPIOwnsErrorReporting_ = flag; - return *this; - } - ContextOptions& toggleAutoJSAPIOwnsErrorReporting() { - autoJSAPIOwnsErrorReporting_ = !autoJSAPIOwnsErrorReporting_; - return *this; - } - - - private: - bool privateIsNSISupports_ : 1; - bool dontReportUncaught_ : 1; - // dontReportUncaught isn't respected by all JSAPI codepaths, particularly the - // JS_ReportError* functions that eventually report the error even when dontReportUncaught is - // set, if script is not running. We want a way to indicate that the embedder will always - // handle any exceptions, and that SpiderMonkey should just leave them on the context. This is - // the way we want to do all future error handling in Gecko - stealing the exception explicitly - // from the context and handling it as per the situation. This will eventually become the - // default and these 2 flags should go away. - bool autoJSAPIOwnsErrorReporting_ : 1; -}; - JS_PUBLIC_API(ContextOptions&) ContextOptionsRef(JSContext* cx); -class JS_PUBLIC_API(AutoSaveContextOptions) { - public: - explicit AutoSaveContextOptions(JSContext* cx) - : cx_(cx), - oldOptions_(ContextOptionsRef(cx_)) - { - } - - ~AutoSaveContextOptions() - { - ContextOptionsRef(cx_) = oldOptions_; - } +/** + * Initialize the runtime's self-hosted code. Embeddings should call this + * exactly once per runtime/context, before the first JS_NewGlobalObject + * call. + */ +JS_PUBLIC_API(bool) +InitSelfHostedCode(JSContext* cx); - private: - JSContext* cx_; - JS::ContextOptions oldOptions_; -}; +/** + * Asserts (in debug and release builds) that `obj` belongs to the current + * thread's context. + */ +JS_PUBLIC_API(void) +AssertObjectBelongsToCurrentThread(JSObject* obj); } /* namespace JS */ @@ -1285,19 +1267,23 @@ JS_GetImplementationVersion(void); extern JS_PUBLIC_API(void) -JS_SetDestroyCompartmentCallback(JSRuntime* rt, JSDestroyCompartmentCallback callback); +JS_SetDestroyCompartmentCallback(JSContext* cx, JSDestroyCompartmentCallback callback); + +extern JS_PUBLIC_API(void) +JS_SetSizeOfIncludingThisCompartmentCallback(JSContext* cx, + JSSizeOfIncludingThisCompartmentCallback callback); extern JS_PUBLIC_API(void) -JS_SetDestroyZoneCallback(JSRuntime* rt, JSZoneCallback callback); +JS_SetDestroyZoneCallback(JSContext* cx, JSZoneCallback callback); extern JS_PUBLIC_API(void) -JS_SetSweepZoneCallback(JSRuntime* rt, JSZoneCallback callback); +JS_SetSweepZoneCallback(JSContext* cx, JSZoneCallback callback); extern JS_PUBLIC_API(void) -JS_SetCompartmentNameCallback(JSRuntime* rt, JSCompartmentNameCallback callback); +JS_SetCompartmentNameCallback(JSContext* cx, JSCompartmentNameCallback callback); extern JS_PUBLIC_API(void) -JS_SetWrapObjectCallbacks(JSRuntime* rt, const JSWrapObjectCallbacks* callbacks); +JS_SetWrapObjectCallbacks(JSContext* cx, const JSWrapObjectCallbacks* callbacks); extern JS_PUBLIC_API(void) JS_SetCompartmentPrivate(JSCompartment* compartment, void* data); @@ -1391,7 +1377,7 @@ extern JS_PUBLIC_API(void) JS_LeaveCompartment(JSContext* cx, JSCompartment* oldCompartment); -typedef void (*JSIterateCompartmentCallback)(JSRuntime* rt, void* data, JSCompartment* compartment); +typedef void (*JSIterateCompartmentCallback)(JSContext* cx, void* data, JSCompartment* compartment); /** * This function calls |compartmentCallback| on every compartment. Beware that @@ -1399,7 +1385,7 @@ * returns. Also, barriers are disabled via the TraceSession. */ extern JS_PUBLIC_API(void) -JS_IterateCompartments(JSRuntime* rt, void* data, +JS_IterateCompartments(JSContext* cx, void* data, JSIterateCompartmentCallback compartmentCallback); /** @@ -1509,13 +1495,13 @@ JS_IsGlobalObject(JSObject* obj); extern JS_PUBLIC_API(JSObject*) -JS_GlobalLexicalScope(JSObject* obj); +JS_GlobalLexicalEnvironment(JSObject* obj); extern JS_PUBLIC_API(bool) -JS_HasExtensibleLexicalScope(JSObject* obj); +JS_HasExtensibleLexicalEnvironment(JSObject* obj); extern JS_PUBLIC_API(JSObject*) -JS_ExtensibleLexicalScope(JSObject* obj); +JS_ExtensibleLexicalEnvironment(JSObject* obj); /** * May return nullptr, if |c| never had a global (e.g. the atoms compartment), @@ -1607,50 +1593,47 @@ extern JS_PUBLIC_API(void) JS_freeop(JSFreeOp* fop, void* p); -extern JS_PUBLIC_API(JSFreeOp*) -JS_GetDefaultFreeOp(JSRuntime* rt); - extern JS_PUBLIC_API(void) JS_updateMallocCounter(JSContext* cx, size_t nbytes); extern JS_PUBLIC_API(char*) JS_strdup(JSContext* cx, const char* s); -/** Duplicate a string. Does not report an error on failure. */ -extern JS_PUBLIC_API(char*) -JS_strdup(JSRuntime* rt, const char* s); - /** * Register externally maintained GC roots. * * traceOp: the trace operation. For each root the implementation should call - * JS_CallTracer whenever the root contains a traceable thing. + * JS::TraceEdge whenever the root contains a traceable thing. * data: the data argument to pass to each invocation of traceOp. */ extern JS_PUBLIC_API(bool) -JS_AddExtraGCRootsTracer(JSRuntime* rt, JSTraceDataOp traceOp, void* data); +JS_AddExtraGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp, void* data); /** Undo a call to JS_AddExtraGCRootsTracer. */ extern JS_PUBLIC_API(void) -JS_RemoveExtraGCRootsTracer(JSRuntime* rt, JSTraceDataOp traceOp, void* data); +JS_RemoveExtraGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp, void* data); /* * Garbage collector API. */ extern JS_PUBLIC_API(void) -JS_GC(JSRuntime* rt); +JS_GC(JSContext* cx); extern JS_PUBLIC_API(void) JS_MaybeGC(JSContext* cx); extern JS_PUBLIC_API(void) -JS_SetGCCallback(JSRuntime* rt, JSGCCallback cb, void* data); +JS_SetGCCallback(JSContext* cx, JSGCCallback cb, void* data); + +extern JS_PUBLIC_API(void) +JS_SetObjectsTenuredCallback(JSContext* cx, JSObjectsTenuredCallback cb, + void* data); extern JS_PUBLIC_API(bool) -JS_AddFinalizeCallback(JSRuntime* rt, JSFinalizeCallback cb, void* data); +JS_AddFinalizeCallback(JSContext* cx, JSFinalizeCallback cb, void* data); extern JS_PUBLIC_API(void) -JS_RemoveFinalizeCallback(JSRuntime* rt, JSFinalizeCallback cb); +JS_RemoveFinalizeCallback(JSContext* cx, JSFinalizeCallback cb); /* * Weak pointers and garbage collection @@ -1687,17 +1670,17 @@ */ extern JS_PUBLIC_API(bool) -JS_AddWeakPointerZoneGroupCallback(JSRuntime* rt, JSWeakPointerZoneGroupCallback cb, void* data); +JS_AddWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb, void* data); extern JS_PUBLIC_API(void) -JS_RemoveWeakPointerZoneGroupCallback(JSRuntime* rt, JSWeakPointerZoneGroupCallback cb); +JS_RemoveWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb); extern JS_PUBLIC_API(bool) -JS_AddWeakPointerCompartmentCallback(JSRuntime* rt, JSWeakPointerCompartmentCallback cb, +JS_AddWeakPointerCompartmentCallback(JSContext* cx, JSWeakPointerCompartmentCallback cb, void* data); extern JS_PUBLIC_API(void) -JS_RemoveWeakPointerCompartmentCallback(JSRuntime* rt, JSWeakPointerCompartmentCallback cb); +JS_RemoveWeakPointerCompartmentCallback(JSContext* cx, JSWeakPointerCompartmentCallback cb); extern JS_PUBLIC_API(void) JS_UpdateWeakPointerAfterGC(JS::Heap* objp); @@ -1718,9 +1701,6 @@ /** Number of times GC has been invoked. Includes both major and minor GC. */ JSGC_NUMBER = 4, - /** Max size of the code cache in bytes. */ - JSGC_MAX_CODE_CACHE_BYTES = 5, - /** Select GC mode. */ JSGC_MODE = 6, @@ -1770,13 +1750,6 @@ JSGC_ALLOCATION_THRESHOLD = 19, /** - * We decommit memory lazily. If more than this number of megabytes is - * available to be decommitted, then JS_MaybeGC will trigger a shrinking GC - * to decommit it. - */ - JSGC_DECOMMIT_THRESHOLD = 20, - - /** * We try to keep at least this many unused chunks in the free chunk pool at * all times, even after a shrinking GC. */ @@ -1786,23 +1759,20 @@ JSGC_MAX_EMPTY_CHUNK_COUNT = 22, /** Whether compacting GC is enabled. */ - JSGC_COMPACTING_ENABLED = 23 -} JSGCParamKey; - -extern JS_PUBLIC_API(void) -JS_SetGCParameter(JSRuntime* rt, JSGCParamKey key, uint32_t value); + JSGC_COMPACTING_ENABLED = 23, -extern JS_PUBLIC_API(uint32_t) -JS_GetGCParameter(JSRuntime* rt, JSGCParamKey key); + /** If true, painting can trigger IGC slices. */ + JSGC_REFRESH_FRAME_SLICES_ENABLED = 24, +} JSGCParamKey; extern JS_PUBLIC_API(void) -JS_SetGCParameterForThread(JSContext* cx, JSGCParamKey key, uint32_t value); +JS_SetGCParameter(JSContext* cx, JSGCParamKey key, uint32_t value); extern JS_PUBLIC_API(uint32_t) -JS_GetGCParameterForThread(JSContext* cx, JSGCParamKey key); +JS_GetGCParameter(JSContext* cx, JSGCParamKey key); extern JS_PUBLIC_API(void) -JS_SetGCParametersBasedOnAvailableMemory(JSRuntime* rt, uint32_t availMem); +JS_SetGCParametersBasedOnAvailableMemory(JSContext* cx, uint32_t availMem); /** * Create a new JSString whose chars member refers to external memory, i.e., @@ -1844,7 +1814,7 @@ * and before any code is executed and/or interrupts requested. */ extern JS_PUBLIC_API(void) -JS_SetNativeStackQuota(JSRuntime* cx, size_t systemCodeStackSize, +JS_SetNativeStackQuota(JSContext* cx, size_t systemCodeStackSize, size_t trustedScriptStackSize = 0, size_t untrustedScriptStackSize = 0); @@ -1927,22 +1897,42 @@ */ struct JSPropertySpec { struct SelfHostedWrapper { - void* unused; + void* unused; const char* funname; }; + struct ValueWrapper { + uintptr_t type; + union { + const char* string; + int32_t int32; + }; + }; + const char* name; uint8_t flags; union { - JSNativeWrapper native; - SelfHostedWrapper selfHosted; - } getter; - union { - JSNativeWrapper native; - SelfHostedWrapper selfHosted; - } setter; + struct { + union { + JSNativeWrapper native; + SelfHostedWrapper selfHosted; + } getter; + union { + JSNativeWrapper native; + SelfHostedWrapper selfHosted; + } setter; + } accessors; + ValueWrapper value; + }; + + bool isAccessor() const { + return !(flags & JSPROP_INTERNAL_USE_BIT); + } + JS_PUBLIC_API(bool) getValue(JSContext* cx, JS::MutableHandleValue value) const; bool isSelfHosted() const { + MOZ_ASSERT(isAccessor()); + #ifdef DEBUG // Verify that our accessors match our JSPROP_GETTER flag. if (flags & JSPROP_GETTER) @@ -1961,17 +1951,17 @@ "JSNativeWrapper::info"); private: void checkAccessorsAreNative() const { - MOZ_ASSERT(getter.native.op); + MOZ_ASSERT(accessors.getter.native.op); // We may not have a setter at all. So all we can assert here, for the // native case is that if we have a jitinfo for the setter then we have // a setter op too. This is good enough to make sure we don't have a // SelfHostedWrapper for the setter. - MOZ_ASSERT_IF(setter.native.info, setter.native.op); + MOZ_ASSERT_IF(accessors.setter.native.info, accessors.setter.native.op); } void checkAccessorsAreSelfHosted() const { - MOZ_ASSERT(!getter.selfHosted.unused); - MOZ_ASSERT(!setter.selfHosted.unused); + MOZ_ASSERT(!accessors.getter.selfHosted.unused); + MOZ_ASSERT(!accessors.setter.selfHosted.unused); } }; @@ -1986,13 +1976,15 @@ inline int CheckIsCharacterLiteral(const char (&arr)[N]); +/* NEVER DEFINED, DON'T USE. For use by JS_CAST_INT32_TO only. */ +inline int CheckIsInt32(int32_t value); + /* NEVER DEFINED, DON'T USE. For use by JS_PROPERTYOP_GETTER only. */ inline int CheckIsGetterOp(JSGetterOp op); /* NEVER DEFINED, DON'T USE. For use by JS_PROPERTYOP_SETTER only. */ inline int CheckIsSetterOp(JSSetterOp op); - } // namespace detail } // namespace JS @@ -2004,6 +1996,10 @@ (static_cast(sizeof(JS::detail::CheckIsCharacterLiteral(s))), \ reinterpret_cast(s)) +#define JS_CAST_INT32_TO(s, To) \ + (static_cast(sizeof(JS::detail::CheckIsInt32(s))), \ + reinterpret_cast(s)) + #define JS_CHECK_ACCESSOR_FLAGS(flags) \ (static_cast::Type>(0), \ (flags)) @@ -2020,37 +2016,50 @@ #define JS_STUBSETTER JS_PROPERTYOP_SETTER(JS_StrictPropertyStub) +#define JS_PS_ACCESSOR_SPEC(name, getter, setter, flags, extraFlags) \ + { name, uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | extraFlags), \ + { { getter, setter } } } +#define JS_PS_VALUE_SPEC(name, value, flags) \ + { name, uint8_t(flags | JSPROP_INTERNAL_USE_BIT), \ + { { value, JSNATIVE_WRAPPER(nullptr) } } } + +#define SELFHOSTED_WRAPPER(name) \ + { { nullptr, JS_CAST_STRING_TO(name, const JSJitInfo*) } } +#define STRINGVALUE_WRAPPER(value) \ + { { reinterpret_cast(JSVAL_TYPE_STRING), JS_CAST_STRING_TO(value, const JSJitInfo*) } } +#define INT32VALUE_WRAPPER(value) \ + { { reinterpret_cast(JSVAL_TYPE_INT32), JS_CAST_INT32_TO(value, const JSJitInfo*) } } + /* * JSPropertySpec uses JSNativeWrapper. These macros encapsulate the definition * of JSNative-backed JSPropertySpecs, by defining the JSNativeWrappers for * them. */ #define JS_PSG(name, getter, flags) \ - {name, \ - uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED), \ - JSNATIVE_WRAPPER(getter), \ - JSNATIVE_WRAPPER(nullptr)} + JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(nullptr), flags, \ + JSPROP_SHARED) #define JS_PSGS(name, getter, setter, flags) \ - {name, \ - uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED), \ - JSNATIVE_WRAPPER(getter), \ - JSNATIVE_WRAPPER(setter)} + JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(setter), flags, \ + JSPROP_SHARED) #define JS_SELF_HOSTED_GET(name, getterName, flags) \ - {name, \ - uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_GETTER), \ - { { nullptr, JS_CAST_STRING_TO(getterName, const JSJitInfo*) } }, \ - JSNATIVE_WRAPPER(nullptr) } + JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), JSNATIVE_WRAPPER(nullptr), flags, \ + JSPROP_SHARED | JSPROP_GETTER) #define JS_SELF_HOSTED_GETSET(name, getterName, setterName, flags) \ - {name, \ - uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_GETTER | JSPROP_SETTER), \ - { nullptr, JS_CAST_STRING_TO(getterName, const JSJitInfo*) }, \ - { nullptr, JS_CAST_STRING_TO(setterName, const JSJitInfo*) } } -#define JS_PS_END { nullptr, 0, JSNATIVE_WRAPPER(nullptr), JSNATIVE_WRAPPER(nullptr) } + JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), SELFHOSTED_WRAPPER(setterName), \ + flags, JSPROP_SHARED | JSPROP_GETTER | JSPROP_SETTER) #define JS_SELF_HOSTED_SYM_GET(symbol, getterName, flags) \ - {reinterpret_cast(uint32_t(::JS::SymbolCode::symbol) + 1), \ - uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_GETTER), \ - { { nullptr, JS_CAST_STRING_TO(getterName, const JSJitInfo*) } }, \ - JSNATIVE_WRAPPER(nullptr) } + JS_PS_ACCESSOR_SPEC(reinterpret_cast(uint32_t(::JS::SymbolCode::symbol) + 1), \ + SELFHOSTED_WRAPPER(getterName), JSNATIVE_WRAPPER(nullptr), flags, \ + JSPROP_SHARED | JSPROP_GETTER) +#define JS_STRING_PS(name, string, flags) \ + JS_PS_VALUE_SPEC(name, STRINGVALUE_WRAPPER(string), flags) +#define JS_STRING_SYM_PS(symbol, string, flags) \ + JS_PS_VALUE_SPEC(reinterpret_cast(uint32_t(::JS::SymbolCode::symbol) + 1), \ + STRINGVALUE_WRAPPER(string), flags) +#define JS_INT32_PS(name, value, flags) \ + JS_PS_VALUE_SPEC(name, INT32VALUE_WRAPPER(value), flags) +#define JS_PS_END \ + JS_PS_ACCESSOR_SPEC(nullptr, JSNATIVE_WRAPPER(nullptr), JSNATIVE_WRAPPER(nullptr), 0, 0) /** * To define a native function, set call to a JSNativeWrapper. To define a @@ -2128,6 +2137,17 @@ extern JS_PUBLIC_API(bool) JS_HasInstance(JSContext* cx, JS::Handle obj, JS::Handle v, bool* bp); +namespace JS { + +// Implementation of +// http://www.ecma-international.org/ecma-262/6.0/#sec-ordinaryhasinstance. If +// you're looking for the equivalent of "instanceof", you want JS_HasInstance, +// not this function. +extern JS_PUBLIC_API(bool) +OrdinaryHasInstance(JSContext* cx, HandleObject objArg, HandleValue v, bool* bp); + +} // namespace JS + extern JS_PUBLIC_API(void*) JS_GetPrivate(JSObject* obj); @@ -2148,7 +2168,121 @@ SystemZone = 1 }; -class JS_PUBLIC_API(CompartmentOptions) +/** + * CompartmentCreationOptions specifies options relevant to creating a new + * compartment, that are either immutable characteristics of that compartment + * or that are discarded after the compartment has been created. + * + * Access to these options on an existing compartment is read-only: if you + * need particular selections, make them before you create the compartment. + */ +class JS_PUBLIC_API(CompartmentCreationOptions) +{ + public: + CompartmentCreationOptions() + : addonId_(nullptr), + traceGlobal_(nullptr), + invisibleToDebugger_(false), + mergeable_(false), + preserveJitCode_(false), + cloneSingletons_(false), + sharedMemoryAndAtomics_(false), + secureContext_(false) + { + zone_.spec = JS::FreshZone; + } + + // A null add-on ID means that the compartment is not associated with an + // add-on. + JSAddonId* addonIdOrNull() const { return addonId_; } + CompartmentCreationOptions& setAddonId(JSAddonId* id) { + addonId_ = id; + return *this; + } + + JSTraceOp getTrace() const { + return traceGlobal_; + } + CompartmentCreationOptions& setTrace(JSTraceOp op) { + traceGlobal_ = op; + return *this; + } + + void* zonePointer() const { + MOZ_ASSERT(uintptr_t(zone_.pointer) > uintptr_t(JS::SystemZone)); + return zone_.pointer; + } + ZoneSpecifier zoneSpecifier() const { return zone_.spec; } + CompartmentCreationOptions& setZone(ZoneSpecifier spec); + CompartmentCreationOptions& setSameZoneAs(JSObject* obj); + + // Certain scopes (i.e. XBL compilation scopes) are implementation details + // of the embedding, and references to them should never leak out to script. + // This flag causes the this compartment to skip firing onNewGlobalObject + // and makes addDebuggee a no-op for this global. + bool invisibleToDebugger() const { return invisibleToDebugger_; } + CompartmentCreationOptions& setInvisibleToDebugger(bool flag) { + invisibleToDebugger_ = flag; + return *this; + } + + // Compartments used for off-thread compilation have their contents merged + // into a target compartment when the compilation is finished. This is only + // allowed if this flag is set. The invisibleToDebugger flag must also be + // set for such compartments. + bool mergeable() const { return mergeable_; } + CompartmentCreationOptions& setMergeable(bool flag) { + mergeable_ = flag; + return *this; + } + + // Determines whether this compartment should preserve JIT code on + // non-shrinking GCs. + bool preserveJitCode() const { return preserveJitCode_; } + CompartmentCreationOptions& setPreserveJitCode(bool flag) { + preserveJitCode_ = flag; + return *this; + } + + bool cloneSingletons() const { return cloneSingletons_; } + CompartmentCreationOptions& setCloneSingletons(bool flag) { + cloneSingletons_ = flag; + return *this; + } + + bool getSharedMemoryAndAtomicsEnabled() const; + CompartmentCreationOptions& setSharedMemoryAndAtomicsEnabled(bool flag); + + // This flag doesn't affect JS engine behavior. It is used by Gecko to + // mark whether content windows and workers are "Secure Context"s. See + // https://w3c.github.io/webappsec-secure-contexts/ + // https://bugzilla.mozilla.org/show_bug.cgi?id=1162772#c34 + bool secureContext() const { return secureContext_; } + CompartmentCreationOptions& setSecureContext(bool flag) { + secureContext_ = flag; + return *this; + } + + private: + JSAddonId* addonId_; + JSTraceOp traceGlobal_; + union { + ZoneSpecifier spec; + void* pointer; // js::Zone* is not exposed in the API. + } zone_; + bool invisibleToDebugger_; + bool mergeable_; + bool preserveJitCode_; + bool cloneSingletons_; + bool sharedMemoryAndAtomics_; + bool secureContext_; +}; + +/** + * CompartmentBehaviors specifies behaviors of a compartment that can be + * changed after the compartment's been created. + */ +class JS_PUBLIC_API(CompartmentBehaviors) { public: class Override { @@ -2179,140 +2313,119 @@ Mode mode_; }; - explicit CompartmentOptions() + CompartmentBehaviors() : version_(JSVERSION_UNKNOWN) - , invisibleToDebugger_(false) - , mergeable_(false) , discardSource_(false) , disableLazyParsing_(false) - , cloneSingletons_(false) - , traceGlobal_(nullptr) , singletonsAsTemplates_(true) - , addonId_(nullptr) - , preserveJitCode_(false) { - zone_.spec = JS::FreshZone; } JSVersion version() const { return version_; } - CompartmentOptions& setVersion(JSVersion aVersion) { + CompartmentBehaviors& setVersion(JSVersion aVersion) { MOZ_ASSERT(aVersion != JSVERSION_UNKNOWN); version_ = aVersion; return *this; } - // Certain scopes (i.e. XBL compilation scopes) are implementation details - // of the embedding, and references to them should never leak out to script. - // This flag causes the this compartment to skip firing onNewGlobalObject - // and makes addDebuggee a no-op for this global. - bool invisibleToDebugger() const { return invisibleToDebugger_; } - CompartmentOptions& setInvisibleToDebugger(bool flag) { - invisibleToDebugger_ = flag; - return *this; - } - - // Compartments used for off-thread compilation have their contents merged - // into a target compartment when the compilation is finished. This is only - // allowed if this flag is set. The invisibleToDebugger flag must also be - // set for such compartments. - bool mergeable() const { return mergeable_; } - CompartmentOptions& setMergeable(bool flag) { - mergeable_ = flag; - return *this; - } - // For certain globals, we know enough about the code that will run in them // that we can discard script source entirely. bool discardSource() const { return discardSource_; } - CompartmentOptions& setDiscardSource(bool flag) { + CompartmentBehaviors& setDiscardSource(bool flag) { discardSource_ = flag; return *this; } bool disableLazyParsing() const { return disableLazyParsing_; } - CompartmentOptions& setDisableLazyParsing(bool flag) { + CompartmentBehaviors& setDisableLazyParsing(bool flag) { disableLazyParsing_ = flag; return *this; } - bool cloneSingletons() const { return cloneSingletons_; } - CompartmentOptions& setCloneSingletons(bool flag) { - cloneSingletons_ = flag; - return *this; - } - - bool extraWarnings(JSRuntime* rt) const; bool extraWarnings(JSContext* cx) const; Override& extraWarningsOverride() { return extraWarningsOverride_; } - void* zonePointer() const { - MOZ_ASSERT(uintptr_t(zone_.pointer) > uintptr_t(JS::SystemZone)); - return zone_.pointer; - } - ZoneSpecifier zoneSpecifier() const { return zone_.spec; } - CompartmentOptions& setZone(ZoneSpecifier spec); - CompartmentOptions& setSameZoneAs(JSObject* obj); - - void setSingletonsAsValues() { - singletonsAsTemplates_ = false; - } bool getSingletonsAsTemplates() const { return singletonsAsTemplates_; } - - // A null add-on ID means that the compartment is not associated with an - // add-on. - JSAddonId* addonIdOrNull() const { return addonId_; } - CompartmentOptions& setAddonId(JSAddonId* id) { - addonId_ = id; - return *this; - } - - CompartmentOptions& setTrace(JSTraceOp op) { - traceGlobal_ = op; - return *this; - } - JSTraceOp getTrace() const { - return traceGlobal_; - } - - bool preserveJitCode() const { return preserveJitCode_; } - CompartmentOptions& setPreserveJitCode(bool flag) { - preserveJitCode_ = flag; + CompartmentBehaviors& setSingletonsAsValues() { + singletonsAsTemplates_ = false; return *this; } private: JSVersion version_; - bool invisibleToDebugger_; - bool mergeable_; bool discardSource_; bool disableLazyParsing_; - bool cloneSingletons_; Override extraWarningsOverride_; - union { - ZoneSpecifier spec; - void* pointer; // js::Zone* is not exposed in the API. - } zone_; - JSTraceOp traceGlobal_; // To XDR singletons, we need to ensure that all singletons are all used as // templates, by making JSOP_OBJECT return a clone of the JSScript // singleton, instead of returning the value which is baked in the JSScript. bool singletonsAsTemplates_; +}; - JSAddonId* addonId_; - bool preserveJitCode_; +/** + * CompartmentOptions specifies compartment characteristics: both those that + * can't be changed on a compartment once it's been created + * (CompartmentCreationOptions), and those that can be changed on an existing + * compartment (CompartmentBehaviors). + */ +class JS_PUBLIC_API(CompartmentOptions) +{ + public: + explicit CompartmentOptions() + : creationOptions_(), + behaviors_() + {} + + CompartmentOptions(const CompartmentCreationOptions& compartmentCreation, + const CompartmentBehaviors& compartmentBehaviors) + : creationOptions_(compartmentCreation), + behaviors_(compartmentBehaviors) + {} + + // CompartmentCreationOptions specify fundamental compartment + // characteristics that must be specified when the compartment is created, + // that can't be changed after the compartment is created. + CompartmentCreationOptions& creationOptions() { + return creationOptions_; + } + const CompartmentCreationOptions& creationOptions() const { + return creationOptions_; + } + + // CompartmentBehaviors specify compartment characteristics that can be + // changed after the compartment is created. + CompartmentBehaviors& behaviors() { + return behaviors_; + } + const CompartmentBehaviors& behaviors() const { + return behaviors_; + } + + private: + CompartmentCreationOptions creationOptions_; + CompartmentBehaviors behaviors_; }; -JS_PUBLIC_API(CompartmentOptions&) -CompartmentOptionsRef(JSCompartment* compartment); +JS_PUBLIC_API(const CompartmentCreationOptions&) +CompartmentCreationOptionsRef(JSCompartment* compartment); + +JS_PUBLIC_API(const CompartmentCreationOptions&) +CompartmentCreationOptionsRef(JSObject* obj); -JS_PUBLIC_API(CompartmentOptions&) -CompartmentOptionsRef(JSObject* obj); +JS_PUBLIC_API(const CompartmentCreationOptions&) +CompartmentCreationOptionsRef(JSContext* cx); -JS_PUBLIC_API(CompartmentOptions&) -CompartmentOptionsRef(JSContext* cx); +JS_PUBLIC_API(CompartmentBehaviors&) +CompartmentBehaviorsRef(JSCompartment* compartment); + +JS_PUBLIC_API(CompartmentBehaviors&) +CompartmentBehaviorsRef(JSObject* obj); + +JS_PUBLIC_API(CompartmentBehaviors&) +CompartmentBehaviorsRef(JSContext* cx); /** * During global creation, we fire notifications to callbacks registered @@ -2346,7 +2459,7 @@ extern JS_PUBLIC_API(JSObject*) JS_NewGlobalObject(JSContext* cx, const JSClass* clasp, JSPrincipals* principals, JS::OnNewGlobalHookOption hookOption, - const JS::CompartmentOptions& options = JS::CompartmentOptions()); + const JS::CompartmentOptions& options); /** * Spidermonkey does not have a good way of keeping track of what compartments should be marked on * their own. We can mark the roots unconditionally, but marking GC things only relevant in live @@ -2368,9 +2481,6 @@ extern JS_PUBLIC_API(bool) JS_IsNative(JSObject* obj); -extern JS_PUBLIC_API(JSRuntime*) -JS_GetObjectRuntime(JSObject* obj); - /** * Unlike JS_NewObject, JS_NewObjectWithGivenProto does not compute a default * proto. If proto is nullptr, the JS object will have `null` as [[Prototype]]. @@ -2399,27 +2509,27 @@ /*** Property descriptors ************************************************************************/ -struct JS_PUBLIC_API(JSPropertyDescriptor) : public JS::Traceable { +namespace JS { + +struct JS_PUBLIC_API(PropertyDescriptor) { JSObject* obj; unsigned attrs; JSGetterOp getter; JSSetterOp setter; JS::Value value; - JSPropertyDescriptor() + PropertyDescriptor() : obj(nullptr), attrs(0), getter(nullptr), setter(nullptr), value(JS::UndefinedValue()) {} - static void trace(JSPropertyDescriptor* self, JSTracer* trc) { self->trace(trc); } + static void trace(PropertyDescriptor* self, JSTracer* trc) { self->trace(trc); } void trace(JSTracer* trc); }; -namespace JS { - template class PropertyDescriptorOperations { - const JSPropertyDescriptor& desc() const { return static_cast(this)->get(); } + const PropertyDescriptor& desc() const { return static_cast(this)->get(); } bool has(unsigned bit) const { MOZ_ASSERT(bit != 0); @@ -2551,7 +2661,7 @@ template class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations { - JSPropertyDescriptor& desc() { return static_cast(this)->get(); } + PropertyDescriptor& desc() { return static_cast(this)->get(); } public: void clear() { @@ -2574,7 +2684,7 @@ setSetter(setterOp); } - void assign(JSPropertyDescriptor& other) { + void assign(PropertyDescriptor& other) { object().set(other.obj); setAttributes(other.attrs); setGetter(other.getter); @@ -2662,18 +2772,18 @@ namespace js { template <> -class RootedBase - : public JS::MutablePropertyDescriptorOperations> +class RootedBase + : public JS::MutablePropertyDescriptorOperations> {}; template <> -class HandleBase - : public JS::PropertyDescriptorOperations> +class HandleBase + : public JS::PropertyDescriptorOperations> {}; template <> -class MutableHandleBase - : public JS::MutablePropertyDescriptorOperations> +class MutableHandleBase + : public JS::MutablePropertyDescriptorOperations> {}; } /* namespace js */ @@ -2684,7 +2794,17 @@ ObjectToCompletePropertyDescriptor(JSContext* cx, JS::HandleObject obj, JS::HandleValue descriptor, - JS::MutableHandle desc); + JS::MutableHandle desc); + +/* + * ES6 draft rev 32 (2015 Feb 2) 6.2.4.4 FromPropertyDescriptor(Desc). + * + * If desc.object() is null, then vp is set to undefined. + */ +extern JS_PUBLIC_API(bool) +FromPropertyDescriptor(JSContext* cx, + JS::Handle desc, + JS::MutableHandleValue vp); } // namespace JS @@ -2715,6 +2835,17 @@ JS_GetPrototype(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject result); /** + * If |obj| (underneath any functionally-transparent wrapper proxies) has as + * its [[GetPrototypeOf]] trap the ordinary [[GetPrototypeOf]] behavior defined + * for ordinary objects, set |*isOrdinary = true| and store |obj|'s prototype + * in |result|. Otherwise set |*isOrdinary = false|. In case of error, both + * outparams have unspecified value. + */ +extern JS_PUBLIC_API(bool) +JS_GetPrototypeIfOrdinary(JSContext* cx, JS::HandleObject obj, bool* isOrdinary, + JS::MutableHandleObject result); + +/** * Change the prototype of obj. * * Implements: ES6 [[SetPrototypeOf]] internal method. @@ -2771,15 +2902,15 @@ */ extern JS_PUBLIC_API(bool) JS_GetOwnPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); extern JS_PUBLIC_API(bool) JS_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, - JS::MutableHandle desc); + JS::MutableHandle desc); extern JS_PUBLIC_API(bool) JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, - JS::MutableHandle desc); + JS::MutableHandle desc); /** * Like JS_GetOwnPropertyDescriptorById, but also searches the prototype chain @@ -2789,11 +2920,11 @@ */ extern JS_PUBLIC_API(bool) JS_GetPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); extern JS_PUBLIC_API(bool) JS_GetPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, - JS::MutableHandle desc); + JS::MutableHandle desc); /** * Define a property on obj. @@ -2808,7 +2939,7 @@ */ extern JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result); /** @@ -2817,7 +2948,7 @@ */ extern JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc); + JS::Handle desc); extern JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value, @@ -2869,12 +3000,12 @@ extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result); extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::Handle desc); + JS::Handle desc); extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, @@ -3099,8 +3230,8 @@ * This is the closest thing we currently have to the ES6 [[Enumerate]] * internal method. * - * The JSIdArray returned by JS_Enumerate must be rooted to protect its - * contents from garbage collection. Use JS::AutoIdArray. + * The array of ids returned by JS_Enumerate must be rooted to protect its + * contents from garbage collection. Use JS::Rooted. */ extern JS_PUBLIC_API(bool) JS_Enumerate(JSContext* cx, JS::HandleObject obj, JS::MutableHandle props); @@ -3213,21 +3344,18 @@ */ extern JS_PUBLIC_API(bool) Construct(JSContext* cx, JS::HandleValue fun, HandleObject newTarget, - const JS::HandleValueArray &args, MutableHandleValue rval); + const JS::HandleValueArray &args, MutableHandleObject objp); /** * Invoke a constructor. This is the C++ equivalent of * `rval = new fun(...args)`. * - * The value left in rval on success is always an object in practice, - * though at the moment this is not enforced by the C++ type system. - * * Implements: ES6 7.3.13 Construct(F, [argumentsList], [newTarget]), when * newTarget is omitted. */ extern JS_PUBLIC_API(bool) Construct(JSContext* cx, JS::HandleValue fun, const JS::HandleValueArray& args, - MutableHandleValue rval); + MutableHandleObject objp); } /* namespace JS */ @@ -3304,6 +3432,30 @@ extern JS_PUBLIC_API(bool) JS_SetArrayLength(JSContext* cx, JS::Handle obj, uint32_t length); +namespace JS { + +/** + * Returns true and sets |*isMap| indicating whether |obj| is an Map object + * or a wrapper around one, otherwise returns false on failure. + * + * This method returns true with |*isMap == false| when passed a proxy whose + * target is an Map, or when passed a revoked proxy. + */ +extern JS_PUBLIC_API(bool) +IsMapObject(JSContext* cx, JS::HandleObject obj, bool* isMap); + +/** + * Returns true and sets |*isSet| indicating whether |obj| is an Set object + * or a wrapper around one, otherwise returns false on failure. + * + * This method returns true with |*isSet == false| when passed a proxy whose + * target is an Set, or when passed a revoked proxy. + */ +extern JS_PUBLIC_API(bool) +IsSetObject(JSContext* cx, JS::HandleObject obj, bool* isSet); + +} /* namespace JS */ + /** * Assign 'undefined' to all of the object's non-reserved slots. Note: this is * done for all slots, regardless of the associated property descriptor. @@ -3320,6 +3472,13 @@ JS_NewArrayBufferWithContents(JSContext* cx, size_t nbytes, void* contents); /** + * Create a new array buffer with the given contents. The array buffer does not take ownership of + * contents, and JS_DetachArrayBuffer must be called before the contents are disposed of. + */ +extern JS_PUBLIC_API(JSObject*) +JS_NewArrayBufferWithExternalContents(JSContext* cx, size_t nbytes, void* contents); + +/** * Steal the contents of the given array buffer. The array buffer 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 @@ -3329,6 +3488,25 @@ JS_StealArrayBufferContents(JSContext* cx, JS::HandleObject obj); /** + * Returns a pointer to the ArrayBuffer |obj|'s data. |obj| and its views will store and expose + * the data in the returned pointer: assigning into the returned pointer will affect values exposed + * by views of |obj| and vice versa. + * + * The caller must ultimately deallocate the returned pointer to avoid leaking. The memory is + * *not* garbage-collected with |obj|. These steps must be followed to deallocate: + * + * 1. The ArrayBuffer |obj| must be detached using JS_DetachArrayBuffer. + * 2. The returned pointer must be freed using JS_free. + * + * To perform step 1, callers *must* hold a reference to |obj| until they finish using the returned + * pointer. They *must not* attempt to let |obj| be GC'd, then JS_free the pointer. + * + * If |obj| isn't an ArrayBuffer, this function returns null and reports an error. + */ +extern JS_PUBLIC_API(void*) +JS_ExternalizeArrayBufferContents(JSContext* cx, JS::HandleObject obj); + +/** * Create a new mapped array buffer 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 array buffer. @@ -3347,7 +3525,7 @@ * Release the allocated resource of mapped array buffer contents before the * object is created. * If a new object has been created by JS_NewMappedArrayBufferWithContents() - * with this content, then JS_NeuterArrayBuffer() should be used instead to + * with this content, then JS_DetachArrayBuffer() should be used instead to * release the resource used by the object. */ extern JS_PUBLIC_API(void) @@ -3357,7 +3535,7 @@ JS_GetReservedSlot(JSObject* obj, uint32_t index); extern JS_PUBLIC_API(void) -JS_SetReservedSlot(JSObject* obj, uint32_t index, JS::Value v); +JS_SetReservedSlot(JSObject* obj, uint32_t index, const JS::Value& v); /************************************************************************/ @@ -3432,20 +3610,8 @@ extern JS_PUBLIC_API(bool) JS_IsConstructor(JSFunction* fun); -/** - * This enum is used to select if properties with JSPROP_DEFINE_LATE flag - * should be defined on the object. - * Normal JSAPI consumers probably always want DefineAllProperties here. - */ -enum PropertyDefinitionBehavior { - DefineAllProperties, - OnlyDefineLateProperties, - DontDefineLateProperties -}; - extern JS_PUBLIC_API(bool) -JS_DefineFunctions(JSContext* cx, JS::Handle obj, const JSFunctionSpec* fs, - PropertyDefinitionBehavior behavior = DefineAllProperties); +JS_DefineFunctions(JSContext* cx, JS::Handle obj, const JSFunctionSpec* fs); extern JS_PUBLIC_API(JSFunction*) JS_DefineFunction(JSContext* cx, JS::Handle obj, const char* name, JSNative call, @@ -3460,6 +3626,12 @@ JS_DefineFunctionById(JSContext* cx, JS::Handle obj, JS::Handle id, JSNative call, unsigned nargs, unsigned attrs); +extern JS_PUBLIC_API(bool) +JS_IsFunctionBound(JSFunction* fun); + +extern JS_PUBLIC_API(JSObject*) +JS_GetBoundFunctionTarget(JSFunction* fun); + namespace JS { /** @@ -3680,7 +3852,6 @@ lineno(1), column(0), isRunOnce(false), - forEval(false), noScriptRval(false) { } @@ -3704,7 +3875,6 @@ unsigned column; // isRunOnce only applies to non-function scripts. bool isRunOnce; - bool forEval; bool noScriptRval; private: @@ -3726,7 +3896,6 @@ */ class JS_FRIEND_API(OwningCompileOptions) : public ReadOnlyCompileOptions { - JSRuntime* runtime; PersistentRootedObject elementRoot; PersistentRootedString elementAttributeNameRoot; PersistentRootedScript introductionScriptRoot; @@ -3778,7 +3947,6 @@ OwningCompileOptions& setUTF8(bool u) { utf8 = u; return *this; } OwningCompileOptions& setColumn(unsigned c) { column = c; return *this; } OwningCompileOptions& setIsRunOnce(bool once) { isRunOnce = once; return *this; } - OwningCompileOptions& setForEval(bool eval) { forEval = eval; 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; } @@ -3808,7 +3976,7 @@ * 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_FRIEND_API(CompileOptions) : public ReadOnlyCompileOptions +class MOZ_STACK_CLASS JS_FRIEND_API(CompileOptions) final : public ReadOnlyCompileOptions { RootedObject elementRoot; RootedString elementAttributeNameRoot; @@ -3875,7 +4043,6 @@ CompileOptions& setUTF8(bool u) { utf8 = u; return *this; } CompileOptions& setColumn(unsigned c) { column = c; return *this; } CompileOptions& setIsRunOnce(bool once) { isRunOnce = once; return *this; } - CompileOptions& setForEval(bool eval) { forEval = eval; 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; } @@ -3953,10 +4120,11 @@ * 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 the main thread, - * so must ensure that its operations are thread safe. Afterwards, - * FinishOffThreadScript must be invoked on the main thread to get the result - * script or nullptr. If maybecx is not specified, the resources will be freed, - * but no script will be returned. + * so must ensure that its operations are thread safe. Afterwards, one of the + * following functions must be invoked on the 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 @@ -3969,17 +4137,31 @@ OffThreadCompileCallback callback, void* callbackData); extern JS_PUBLIC_API(JSScript*) -FinishOffThreadScript(JSContext* maybecx, JSRuntime* rt, void* token); +FinishOffThreadScript(JSContext* cx, void* token); + +extern JS_PUBLIC_API(void) +CancelOffThreadScript(JSContext* cx, void* token); + +extern JS_PUBLIC_API(bool) +CompileOffThreadModule(JSContext* cx, const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + OffThreadCompileCallback callback, void* callbackData); + +extern JS_PUBLIC_API(JSObject*) +FinishOffThreadModule(JSContext* cx, void* token); + +extern JS_PUBLIC_API(void) +CancelOffThreadModule(JSContext* cx, void* token); /** - * Compile a function with scopeChain plus the global as its scope chain. - * scopeChain must contain objects in the current compartment of cx. The actual + * 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(bool) -CompileFunction(JSContext* cx, AutoObjectVector& scopeChain, +CompileFunction(JSContext* cx, AutoObjectVector& envChain, const ReadOnlyCompileOptions& options, const char* name, unsigned nargs, const char* const* argnames, const char16_t* chars, size_t length, JS::MutableHandleFunction fun); @@ -3988,7 +4170,7 @@ * Same as above, but taking a SourceBufferHolder for the function body. */ extern JS_PUBLIC_API(bool) -CompileFunction(JSContext* cx, AutoObjectVector& scopeChain, +CompileFunction(JSContext* cx, AutoObjectVector& envChain, const ReadOnlyCompileOptions& options, const char* name, unsigned nargs, const char* const* argnames, SourceBufferHolder& srcBuf, JS::MutableHandleFunction fun); @@ -3997,7 +4179,7 @@ * Same as above, but taking a const char * for the function body. */ extern JS_PUBLIC_API(bool) -CompileFunction(JSContext* cx, AutoObjectVector& scopeChain, +CompileFunction(JSContext* cx, AutoObjectVector& envChain, const ReadOnlyCompileOptions& options, const char* name, unsigned nargs, const char* const* argnames, const char* bytes, size_t length, JS::MutableHandleFunction fun); @@ -4029,7 +4211,7 @@ * 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 RuntimeOptionsRef adjustment, OTOH, can be + * 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. */ @@ -4044,16 +4226,16 @@ JS_ExecuteScript(JSContext* cx, JS::HandleScript script); /** - * As above, but providing an explicit scope chain. scopeChain must not include + * 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::AutoObjectVector& scopeChain, +JS_ExecuteScript(JSContext* cx, JS::AutoObjectVector& envChain, JS::HandleScript script, JS::MutableHandleValue rval); extern JS_PUBLIC_API(bool) -JS_ExecuteScript(JSContext* cx, JS::AutoObjectVector& scopeChain, JS::HandleScript script); +JS_ExecuteScript(JSContext* cx, JS::AutoObjectVector& envChain, JS::HandleScript script); namespace JS { @@ -4062,7 +4244,8 @@ * cross-compartment, it is cloned into the current compartment before executing. */ extern JS_PUBLIC_API(bool) -CloneAndExecuteScript(JSContext* cx, JS::Handle script); +CloneAndExecuteScript(JSContext* cx, JS::Handle script, + JS::MutableHandleValue rval); } /* namespace JS */ @@ -4076,12 +4259,12 @@ SourceBufferHolder& srcBuf, JS::MutableHandleValue rval); /** - * As above, but providing an explicit scope chain. scopeChain must not include + * 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, AutoObjectVector& scopeChain, const ReadOnlyCompileOptions& options, +Evaluate(JSContext* cx, AutoObjectVector& envChain, const ReadOnlyCompileOptions& options, SourceBufferHolder& srcBuf, JS::MutableHandleValue rval); /** @@ -4092,12 +4275,12 @@ const char16_t* chars, size_t length, JS::MutableHandleValue rval); /** - * As above, but providing an explicit scope chain. scopeChain must not include + * 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, AutoObjectVector& scopeChain, const ReadOnlyCompileOptions& options, +Evaluate(JSContext* cx, AutoObjectVector& envChain, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, JS::MutableHandleValue rval); /** @@ -4114,6 +4297,80 @@ Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, const char* filename, JS::MutableHandleValue rval); +/** + * Get the HostResolveImportedModule hook for a global. + */ +extern JS_PUBLIC_API(JSFunction*) +GetModuleResolveHook(JSContext* cx); + +/** + * Set the HostResolveImportedModule hook for a global to the given function. + */ +extern JS_PUBLIC_API(void) +SetModuleResolveHook(JSContext* cx, JS::HandleFunction func); + +/** + * Parse the given source buffer as a module in the scope of the current global + * of cx and return a source text module record. + */ +extern JS_PUBLIC_API(bool) +CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options, + SourceBufferHolder& srcBuf, JS::MutableHandleObject moduleRecord); + +/** + * Set the [[HostDefined]] field of a source text module record to the given + * value. + */ +extern JS_PUBLIC_API(void) +SetModuleHostDefinedField(JSObject* module, const JS::Value& value); + +/** + * Get the [[HostDefined]] field of a source text module record. + */ +extern JS_PUBLIC_API(JS::Value) +GetModuleHostDefinedField(JSObject* module); + +/* + * Perform the ModuleDeclarationInstantiation operation on on the give source + * text module record. + * + * This transitively resolves all module dependencies (calling the + * HostResolveImportedModule hook) and initializes the environment record for + * the module. + */ +extern JS_PUBLIC_API(bool) +ModuleDeclarationInstantiation(JSContext* cx, JS::HandleObject moduleRecord); + +/* + * Perform the ModuleEvaluation operation on on the give source text module + * record. + * + * This does nothing if this module has already been evaluated. Otherwise, it + * transitively evaluates all dependences of this module and then evaluates this + * module. + * + * ModuleDeclarationInstantiation must have completed prior to calling this. + */ +extern JS_PUBLIC_API(bool) +ModuleEvaluation(JSContext* cx, JS::HandleObject moduleRecord); + +/* + * Get a list of the module specifiers used by a source text module + * record to request importation of modules. + * + * The result is a JavaScript array of string values. To extract the individual + * values use only JS_GetArrayLength and JS_GetElement with indices 0 to + * length - 1. + */ +extern JS_PUBLIC_API(JSObject*) +GetRequestedModules(JSContext* cx, JS::HandleObject moduleRecord); + +/* + * Get the script associated with a module. + */ +extern JS_PUBLIC_API(JSScript*) +GetModuleScript(JSContext* cx, JS::HandleObject moduleRecord); + } /* namespace JS */ extern JS_PUBLIC_API(bool) @@ -4122,7 +4379,7 @@ /* * These functions allow setting an interrupt callback that will be called * from the JS thread some time after any thread triggered the callback using - * JS_RequestInterruptCallback(rt). + * JS_RequestInterruptCallback(cx). * * To schedule the GC and for other activities the engine internally triggers * interrupt callbacks. The embedding should thus not rely on callbacks being @@ -4132,34 +4389,257 @@ * if it re-enters the JS engine. The embedding must ensure that the callback * is disconnected before attempting such re-entry. */ -extern JS_PUBLIC_API(JSInterruptCallback) -JS_SetInterruptCallback(JSRuntime* rt, JSInterruptCallback callback); +extern JS_PUBLIC_API(bool) +JS_AddInterruptCallback(JSContext* cx, JSInterruptCallback callback); + +extern JS_PUBLIC_API(bool) +JS_DisableInterruptCallback(JSContext* cx); + +extern JS_PUBLIC_API(void) +JS_ResetInterruptCallback(JSContext* cx, bool enable); + +extern JS_PUBLIC_API(void) +JS_RequestInterruptCallback(JSContext* cx); + +namespace JS { + +/** + * Sets the callback that's invoked whenever an incumbent global is required. + * + * SpiderMonkey doesn't itself have a notion of incumbent globals as defined + * by the html spec, so we need the embedding to provide this. + * See dom/base/ScriptSettings.h for details. + */ +extern JS_PUBLIC_API(void) +SetGetIncumbentGlobalCallback(JSContext* cx, JSGetIncumbentGlobalCallback callback); -extern JS_PUBLIC_API(JSInterruptCallback) -JS_GetInterruptCallback(JSRuntime* rt); +/** + * Sets the callback that's invoked whenever a Promise job should be enqeued. + * + * SpiderMonkey doesn't schedule Promise resolution jobs itself; instead, + * using this function the embedding can provide a callback to do that + * scheduling. The provided `callback` is invoked with the promise job, + * the corresponding Promise's allocation stack, and the `data` pointer + * passed here as arguments. + */ +extern JS_PUBLIC_API(void) +SetEnqueuePromiseJobCallback(JSContext* cx, JSEnqueuePromiseJobCallback callback, + void* data = nullptr); +/** + * Sets the callback that's invoked whenever a Promise is rejected without + * a rejection handler, and when a Promise that was previously rejected + * without a handler gets a handler attached. + */ extern JS_PUBLIC_API(void) -JS_RequestInterruptCallback(JSRuntime* rt); +SetPromiseRejectionTrackerCallback(JSContext* cx, JSPromiseRejectionTrackerCallback callback, + void* data = nullptr); +/** + * Returns a new instance of the Promise builtin class in the current + * compartment, with the right slot layout. If a `proto` is passed, that gets + * set as the instance's [[Prototype]] instead of the original value of + * `Promise.prototype`. + */ +extern JS_PUBLIC_API(JSObject*) +NewPromiseObject(JSContext* cx, JS::HandleObject executor, JS::HandleObject proto = nullptr); + +/** + * Returns true if the given object is an unwrapped PromiseObject, false + * otherwise. + */ extern JS_PUBLIC_API(bool) -JS_IsRunning(JSContext* cx); +IsPromiseObject(JS::HandleObject obj); -/* - * Saving and restoring frame chains. +/** + * Returns the current compartment's original Promise constructor. + */ +extern JS_PUBLIC_API(JSObject*) +GetPromiseConstructor(JSContext* cx); + +/** + * Returns the current compartment's original Promise.prototype. + */ +extern JS_PUBLIC_API(JSObject*) +GetPromisePrototype(JSContext* cx); + +// Keep this in sync with the PROMISE_STATE defines in SelfHostingDefines.h. +enum class PromiseState { + Pending, + Fulfilled, + Rejected +}; + +/** + * Returns the given Promise's state as a JS::PromiseState enum value. + * + * Returns JS::PromiseState::Pending if the given object is a wrapper that + * can't safely be unwrapped. + */ +extern JS_PUBLIC_API(PromiseState) +GetPromiseState(JS::HandleObject promise); + +/** + * Returns the given Promise's process-unique ID. + */ +JS_PUBLIC_API(uint64_t) +GetPromiseID(JS::HandleObject promise); + +/** + * Returns the given Promise's result: either the resolution value for + * fulfilled promises, or the rejection reason for rejected ones. + */ +extern JS_PUBLIC_API(JS::Value) +GetPromiseResult(JS::HandleObject promise); + +/** + * Returns a js::SavedFrame linked list of the stack that lead to the given + * Promise's allocation. + */ +extern JS_PUBLIC_API(JSObject*) +GetPromiseAllocationSite(JS::HandleObject promise); + +extern JS_PUBLIC_API(JSObject*) +GetPromiseResolutionSite(JS::HandleObject promise); + +#ifdef DEBUG +extern JS_PUBLIC_API(void) +DumpPromiseAllocationSite(JSContext* cx, JS::HandleObject promise); + +extern JS_PUBLIC_API(void) +DumpPromiseResolutionSite(JSContext* cx, JS::HandleObject promise); +#endif + +/** + * Calls the current compartment's original Promise.resolve on the original + * Promise constructor, with `resolutionValue` passed as an argument. + */ +extern JS_PUBLIC_API(JSObject*) +CallOriginalPromiseResolve(JSContext* cx, JS::HandleValue resolutionValue); + +/** + * Calls the current compartment's original Promise.reject on the original + * Promise constructor, with `resolutionValue` passed as an argument. + */ +extern JS_PUBLIC_API(JSObject*) +CallOriginalPromiseReject(JSContext* cx, JS::HandleValue rejectionValue); + +/** + * Resolves the given Promise with the given `resolutionValue`. + * + * Calls the `resolve` function that was passed to the executor function when + * the Promise was created. + */ +extern JS_PUBLIC_API(bool) +ResolvePromise(JSContext* cx, JS::HandleObject promise, JS::HandleValue resolutionValue); + +/** + * Rejects the given `promise` with the given `rejectionValue`. + * + * Calls the `reject` function that was passed to the executor function when + * the Promise was created. + */ +extern JS_PUBLIC_API(bool) +RejectPromise(JSContext* cx, JS::HandleObject promise, JS::HandleValue rejectionValue); + +/** + * Calls the current compartment's original Promise.prototype.then on the + * given `promise`, with `onResolve` and `onReject` passed as arguments. + * + * Asserts if the passed-in `promise` object isn't an unwrapped instance of + * `Promise` or a subclass or `onResolve` and `onReject` aren't both either + * `nullptr` or callable objects. + */ +extern JS_PUBLIC_API(JSObject*) +CallOriginalPromiseThen(JSContext* cx, JS::HandleObject promise, + JS::HandleObject onResolve, JS::HandleObject onReject); + +/** + * Unforgeable, optimized version of the JS builtin Promise.prototype.then. * - * These two functions are used to set aside cx's call stack while that stack - * is inactive. After a call to JS_SaveFrameChain, it looks as if there is no - * code running on cx. Before calling JS_RestoreFrameChain, cx's call stack - * must be balanced and all nested calls to JS_SaveFrameChain must have had - * matching JS_RestoreFrameChain calls. + * Takes a Promise instance and `onResolve`, `onReject` callables to enqueue + * as reactions for that promise. In difference to Promise.prototype.then, + * this doesn't create and return a new Promise instance. * - * JS_SaveFrameChain deals with cx not having any code running on it. + * Asserts if the passed-in `promise` object isn't an unwrapped instance of + * `Promise` or a subclass or `onResolve` and `onReject` aren't both callable + * objects. */ extern JS_PUBLIC_API(bool) -JS_SaveFrameChain(JSContext* cx); +AddPromiseReactions(JSContext* cx, JS::HandleObject promise, + JS::HandleObject onResolve, JS::HandleObject onReject); + +/** + * Unforgeable version of the JS builtin Promise.all. + * + * Takes an AutoObjectVector of Promise objects and returns a promise that's + * resolved with an array of resolution values when all those promises have + * been resolved, or rejected with the rejection value of the first rejected + * promise. + * + * Asserts that all objects in the `promises` vector are, maybe wrapped, + * instances of `Promise` or a subclass of `Promise`. + */ +extern JS_PUBLIC_API(JSObject*) +GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises); + +/** + * An AsyncTask represents a SpiderMonkey-internal operation that starts on a + * JSContext's owner thread, possibly executes on other threads, completes, and + * then needs to be scheduled to run again on the JSContext's owner thread. The + * embedding provides for this final dispatch back to the JSContext's owner + * thread by calling methods on this interface when requested. + */ +struct JS_PUBLIC_API(AsyncTask) +{ + AsyncTask() : user(nullptr) {} + virtual ~AsyncTask() {} + + /** + * After the FinishAsyncTaskCallback is called and succeeds, one of these + * two functions will be called on the original JSContext's owner thread. + */ + virtual void finish(JSContext* cx) = 0; + virtual void cancel(JSContext* cx) = 0; + + /* The embedding may use this field to attach arbitrary data to a task. */ + void* user; +}; + +/** + * A new AsyncTask object, created inside SpiderMonkey on the JSContext's owner + * thread, will be passed to the StartAsyncTaskCallback before it is dispatched + * to another thread. The embedding may use the AsyncTask::user field to attach + * additional task state. + * + * If this function succeeds, SpiderMonkey will call the FinishAsyncTaskCallback + * at some point in the future. Otherwise, FinishAsyncTaskCallback will *not* + * be called. SpiderMonkey assumes that, if StartAsyncTaskCallback fails, it is + * because the JSContext is being shut down. + */ +typedef bool +(*StartAsyncTaskCallback)(JSContext* cx, AsyncTask* task); +/** + * The FinishAsyncTaskCallback may be called from any thread and will only be + * passed AsyncTasks that have already been started via StartAsyncTaskCallback. + * If the embedding returns 'true', indicating success, the embedding must call + * either task->finish() or task->cancel() on the JSContext's owner thread at + * some point in the future. + */ +typedef bool +(*FinishAsyncTaskCallback)(AsyncTask* task); + +/** + * Set the above callbacks for the given context. + */ extern JS_PUBLIC_API(void) -JS_RestoreFrameChain(JSContext* cx); +SetAsyncTaskCallbacks(JSContext* cx, StartAsyncTaskCallback start, FinishAsyncTaskCallback finish); + +} // namespace JS + +extern JS_PUBLIC_API(bool) +JS_IsRunning(JSContext* cx); namespace JS { @@ -4184,7 +4664,7 @@ { JSContext* cx; RootedObject oldAsyncStack; - RootedString oldAsyncCause; + const char* oldAsyncCause; bool oldAsyncCallIsExplicit; public: @@ -4201,8 +4681,13 @@ // ambiguous whether that would clear any scheduled async stack and make the // normal stack reappear in the new call, or just keep the async stack // already scheduled for the new call, if any. + // + // asyncCause is owned by the caller and its lifetime must outlive the + // lifetime of the AutoSetAsyncStackForNewCalls object. It is strongly + // encouraged that asyncCause be a string constant or similar statically + // allocated string. AutoSetAsyncStackForNewCalls(JSContext* cx, HandleObject stack, - HandleString asyncCause, + const char* asyncCause, AsyncCallKind kind = AsyncCallKind::IMPLICIT); ~AutoSetAsyncStackForNewCalls(); }; @@ -4227,9 +4712,21 @@ JS_NewStringCopyZ(JSContext* cx, const char* s); extern JS_PUBLIC_API(JSString*) +JS_NewStringCopyUTF8Z(JSContext* cx, const JS::ConstUTF8CharsZ s); + +extern JS_PUBLIC_API(JSString*) +JS_NewStringCopyUTF8N(JSContext* cx, const JS::UTF8Chars s); + +extern JS_PUBLIC_API(JSString*) JS_AtomizeAndPinJSString(JSContext* cx, JS::HandleString str); extern JS_PUBLIC_API(JSString*) +JS_AtomizeStringN(JSContext* cx, const char* s, size_t length); + +extern JS_PUBLIC_API(JSString*) +JS_AtomizeString(JSContext* cx, const char* s); + +extern JS_PUBLIC_API(JSString*) JS_AtomizeAndPinStringN(JSContext* cx, const char* s, size_t length); extern JS_PUBLIC_API(JSString*) @@ -4245,6 +4742,12 @@ JS_NewUCStringCopyZ(JSContext* cx, const char16_t* s); extern JS_PUBLIC_API(JSString*) +JS_AtomizeUCStringN(JSContext* cx, const char16_t* s, size_t length); + +extern JS_PUBLIC_API(JSString*) +JS_AtomizeUCString(JSContext* cx, const char16_t* s); + +extern JS_PUBLIC_API(JSString*) JS_AtomizeAndPinUCStringN(JSContext* cx, const char16_t* s, size_t length); extern JS_PUBLIC_API(JSString*) @@ -4453,7 +4956,7 @@ } ~JSAutoByteString() { - js_free(mBytes); + JS_free(nullptr, mBytes); } /* Take ownership of the given byte array. */ @@ -4498,7 +5001,7 @@ } private: - char* mBytes; + char* mBytes; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER /* Copy and assignment are not supported. */ @@ -4556,17 +5059,31 @@ GetSymbolDescription(HandleSymbol symbol); /* Well-known symbols. */ +#define JS_FOR_EACH_WELL_KNOWN_SYMBOL(macro) \ + macro(isConcatSpreadable) \ + macro(iterator) \ + macro(match) \ + macro(replace) \ + macro(search) \ + macro(species) \ + macro(hasInstance) \ + macro(split) \ + macro(toPrimitive) \ + macro(toStringTag) \ + macro(unscopables) + enum class SymbolCode : uint32_t { - iterator, // well-known symbols - match, - species, - toPrimitive, + // There is one SymbolCode for each well-known symbol. +#define JS_DEFINE_SYMBOL_ENUM(name) name, + JS_FOR_EACH_WELL_KNOWN_SYMBOL(JS_DEFINE_SYMBOL_ENUM) // SymbolCode::iterator, etc. +#undef JS_DEFINE_SYMBOL_ENUM + Limit, InSymbolRegistry = 0xfffffffe, // created by Symbol.for() or JS::GetSymbolFor() UniqueSymbol = 0xffffffff // created by Symbol() or JS::NewSymbol() }; /* For use in loops that iterate over the well-known symbols. */ -const size_t WellKnownSymbolLimit = 4; +const size_t WellKnownSymbolLimit = size_t(SymbolCode::Limit); /** * Return the SymbolCode telling what sort of symbol `symbol` is. @@ -4625,6 +5142,31 @@ JS_Stringify(JSContext* cx, JS::MutableHandleValue value, JS::HandleObject replacer, JS::HandleValue 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. + */ +JS_PUBLIC_API(bool) +ToJSONMaybeSafely(JSContext* cx, JS::HandleObject input, + JSONWriteCallback callback, void* data); + +} /* namespace JS */ + /** * JSON.parse as specified by ES5. */ @@ -4652,13 +5194,19 @@ * The locale string remains owned by the caller. */ extern JS_PUBLIC_API(bool) -JS_SetDefaultLocale(JSRuntime* rt, const char* locale); +JS_SetDefaultLocale(JSContext* cx, const char* locale); + +/** + * Look up the default locale for the ECMAScript Internationalization API. + */ +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); +JS_ResetDefaultLocale(JSContext* cx); /** * Locale specific string conversion and error message callbacks. @@ -4672,17 +5220,17 @@ /** * Establish locale callbacks. The pointer must persist as long as the - * JSRuntime. Passing nullptr restores the default behaviour. + * JSContext. Passing nullptr restores the default behaviour. */ extern JS_PUBLIC_API(void) -JS_SetLocaleCallbacks(JSRuntime* rt, const JSLocaleCallbacks* callbacks); +JS_SetLocaleCallbacks(JSContext* cx, const JSLocaleCallbacks* callbacks); /** * Return the address of the current locale callbacks struct, which may * be nullptr. */ extern JS_PUBLIC_API(const JSLocaleCallbacks*) -JS_GetLocaleCallbacks(JSRuntime* rt); +JS_GetLocaleCallbacks(JSContext* cx); /************************************************************************/ @@ -4696,23 +5244,49 @@ /** * Report an exception represented by the sprintf-like conversion of format - * and its arguments. This exception message string is passed to a pre-set - * JSErrorReporter function (set by JS_SetErrorReporter). + * and its arguments. */ extern JS_PUBLIC_API(void) -JS_ReportError(JSContext* cx, const char* format, ...); +JS_ReportErrorASCII(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API(void) +JS_ReportErrorLatin1(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API(void) +JS_ReportErrorUTF8(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); /* * Use an errorNumber to retrieve the format string, args are char* */ extern JS_PUBLIC_API(void) -JS_ReportErrorNumber(JSContext* cx, JSErrorCallback errorCallback, - void* userRef, const unsigned errorNumber, ...); +JS_ReportErrorNumberASCII(JSContext* cx, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, ...); + +extern JS_PUBLIC_API(void) +JS_ReportErrorNumberASCIIVA(JSContext* cx, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, va_list ap); + +extern JS_PUBLIC_API(void) +JS_ReportErrorNumberLatin1(JSContext* cx, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, ...); #ifdef va_start extern JS_PUBLIC_API(void) -JS_ReportErrorNumberVA(JSContext* cx, JSErrorCallback errorCallback, - void* userRef, const unsigned errorNumber, va_list ap); +JS_ReportErrorNumberLatin1VA(JSContext* cx, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, va_list ap); +#endif + +extern JS_PUBLIC_API(void) +JS_ReportErrorNumberUTF8(JSContext* cx, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, ...); + +#ifdef va_start +extern JS_PUBLIC_API(void) +JS_ReportErrorNumberUTF8VA(JSContext* cx, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, va_list ap); #endif /* @@ -4734,12 +5308,31 @@ * being set, false otherwise. */ extern JS_PUBLIC_API(bool) -JS_ReportWarning(JSContext* cx, const char* format, ...); +JS_ReportWarningASCII(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API(bool) +JS_ReportWarningLatin1(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API(bool) +JS_ReportWarningUTF8(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API(bool) +JS_ReportErrorFlagsAndNumberASCII(JSContext* cx, unsigned flags, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + +extern JS_PUBLIC_API(bool) +JS_ReportErrorFlagsAndNumberLatin1(JSContext* cx, unsigned flags, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); extern JS_PUBLIC_API(bool) -JS_ReportErrorFlagsAndNumber(JSContext* cx, unsigned flags, - JSErrorCallback errorCallback, void* userRef, - const unsigned errorNumber, ...); +JS_ReportErrorFlagsAndNumberUTF8(JSContext* cx, unsigned flags, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); extern JS_PUBLIC_API(bool) JS_ReportErrorFlagsAndNumberUC(JSContext* cx, unsigned flags, @@ -4760,7 +5353,12 @@ class JSErrorReport { + // The (default) error message. + // If ownsMessage_ is true, the it is freed in destructor. + JS::ConstUTF8CharsZ message_; + // 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'. @@ -4772,21 +5370,30 @@ public: JSErrorReport() : linebuf_(nullptr), linebufLength_(0), tokenOffset_(0), - filename(nullptr), lineno(0), column(0), isMuted(false), - flags(0), errorNumber(0), ucmessage(nullptr), - messageArgs(nullptr), exnType(0) + filename(nullptr), lineno(0), column(0), + flags(0), errorNumber(0), + exnType(0), isMuted(false), + ownsLinebuf_(false), ownsMessage_(false) {} + ~JSErrorReport() { + freeLinebuf(); + freeMessage(); + } + const char* filename; /* source file name, URL, etc., or null */ unsigned lineno; /* source line number */ unsigned column; /* zero-based column index in line */ - bool isMuted; /* See the comment in ReadOnlyCompileOptions. */ unsigned flags; /* error/warning, etc. */ unsigned errorNumber; /* the error number, e.g. see js.msg */ - const char16_t* ucmessage; /* the (default) error message */ - const char16_t** messageArgs; /* arguments for the error message */ int16_t exnType; /* One of the JSExnType constants */ + bool isMuted : 1; /* See the comment in ReadOnlyCompileOptions. */ + private: + bool ownsLinebuf_ : 1; + bool ownsMessage_ : 1; + + public: const char16_t* linebuf() const { return linebuf_; } @@ -4796,7 +5403,29 @@ size_t tokenOffset() const { return tokenOffset_; } - void initLinebuf(const char16_t* linebuf, size_t linebufLength, size_t 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); + void freeLinebuf(); + + 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); + + void freeMessage(); }; /* @@ -4807,14 +5436,7 @@ #define JSREPORT_EXCEPTION 0x2 /* exception was thrown */ #define JSREPORT_STRICT 0x4 /* error or warning due to strict option */ -/* - * This condition is an error in strict mode code, a warning if - * JS_HAS_STRICT_OPTION(cx), and otherwise should not be reported at - * all. We check the strictness of the context's top frame's script; - * where that isn't appropriate, the caller should do the right checks - * itself instead of using this flag. - */ -#define JSREPORT_STRICT_MODE_ERROR 0x8 +#define JSREPORT_USER_1 0x8 /* user-defined flag */ /* * If JSREPORT_EXCEPTION is set, then a JavaScript-catchable exception @@ -4826,16 +5448,17 @@ #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) -#define JSREPORT_IS_STRICT_MODE_ERROR(flags) (((flags) & \ - JSREPORT_STRICT_MODE_ERROR) != 0) -extern JS_PUBLIC_API(JSErrorReporter) -JS_GetErrorReporter(JSRuntime* rt); - -extern JS_PUBLIC_API(JSErrorReporter) -JS_SetErrorReporter(JSRuntime* rt, JSErrorReporter er); namespace JS { +using WarningReporter = void (*)(JSContext* cx, JSErrorReport* report); + +extern JS_PUBLIC_API(WarningReporter) +SetWarningReporter(JSContext* cx, WarningReporter reporter); + +extern JS_PUBLIC_API(WarningReporter) +GetWarningReporter(JSContext* cx); + extern JS_PUBLIC_API(bool) CreateError(JSContext* cx, JSExnType type, HandleObject stack, HandleString fileName, uint32_t lineNumber, uint32_t columnNumber, @@ -4959,18 +5582,16 @@ #define JSREG_GLOB 0x02u /* global exec, creates array of matches */ #define JSREG_MULTILINE 0x04u /* treat ^ and $ as begin and end of line */ #define JSREG_STICKY 0x08u /* only match starting at lastIndex */ +#define JSREG_UNICODE 0x10u /* unicode */ extern JS_PUBLIC_API(JSObject*) -JS_NewRegExpObject(JSContext* cx, JS::HandleObject obj, const char* bytes, size_t length, - unsigned flags); +JS_NewRegExpObject(JSContext* cx, const char* bytes, size_t length, unsigned flags); extern JS_PUBLIC_API(JSObject*) -JS_NewUCRegExpObject(JSContext* cx, JS::HandleObject obj, const char16_t* chars, size_t length, - unsigned flags); +JS_NewUCRegExpObject(JSContext* cx, const char16_t* chars, size_t length, unsigned flags); extern JS_PUBLIC_API(bool) -JS_SetRegExpInput(JSContext* cx, JS::HandleObject obj, JS::HandleString input, - bool multiline); +JS_SetRegExpInput(JSContext* cx, JS::HandleObject obj, JS::HandleString input); extern JS_PUBLIC_API(bool) JS_ClearRegExpStatics(JSContext* cx, JS::HandleObject obj); @@ -4982,12 +5603,6 @@ /* RegExp interface for clients without a global object. */ -extern JS_PUBLIC_API(JSObject*) -JS_NewRegExpObjectNoStatics(JSContext* cx, char* bytes, size_t length, unsigned flags); - -extern JS_PUBLIC_API(JSObject*) -JS_NewUCRegExpObjectNoStatics(JSContext* cx, char16_t* chars, size_t length, unsigned flags); - extern JS_PUBLIC_API(bool) JS_ExecuteRegExpNoStatics(JSContext* cx, JS::HandleObject reobj, char16_t* chars, size_t length, size_t* indexp, bool test, JS::MutableHandleValue rval); @@ -5022,9 +5637,6 @@ extern JS_PUBLIC_API(void) JS_ClearPendingException(JSContext* cx); -extern JS_PUBLIC_API(bool) -JS_ReportPendingException(JSContext* cx); - namespace JS { /** @@ -5102,8 +5714,15 @@ extern JS_PUBLIC_API(JSErrorReport*) JS_ErrorFromException(JSContext* cx, JS::HandleObject obj); +/** + * If the given object is an exception object (or an unwrappable + * cross-compartment wrapper for one), return the stack for that exception, if + * any. Will return null if the given object is not an exception object + * (including if it's null or a security wrapper that can't be unwrapped) or if + * the exception has no stack. + */ extern JS_PUBLIC_API(JSObject*) -ExceptionStackOrNull(JSContext* cx, JS::HandleObject obj); +ExceptionStackOrNull(JS::HandleObject obj); /* * Throws a StopIteration exception on cx. @@ -5112,23 +5731,20 @@ JS_ThrowStopIteration(JSContext* cx); extern JS_PUBLIC_API(bool) -JS_IsStopIteration(JS::Value v); - -extern JS_PUBLIC_API(intptr_t) -JS_GetCurrentThread(); +JS_IsStopIteration(const JS::Value& v); /** - * A JS runtime always has an "owner thread". The owner thread is set when the - * runtime is created (to the current thread) and practically all entry points - * into the JS engine check that a runtime (or anything contained in the - * runtime: context, compartment, object, etc) is only touched by its owner + * A JS context always has an "owner thread". The owner thread is set when the + * context is created (to the current thread) and practically all entry points + * into the JS engine check that a context (or anything contained in the + * context: runtime, compartment, object, etc) is only touched by its owner * thread. Embeddings may check this invariant outside the JS engine by calling * JS_AbortIfWrongThread (which will abort if not on the owner thread, even for * non-debug builds). */ extern JS_PUBLIC_API(void) -JS_AbortIfWrongThread(JSRuntime* rt); +JS_AbortIfWrongThread(JSContext* cx); /************************************************************************/ @@ -5146,7 +5762,7 @@ #define JS_DEFAULT_ZEAL_FREQ 100 extern JS_PUBLIC_API(void) -JS_GetGCZeal(JSContext* cx, uint8_t* zeal, uint32_t* frequency, uint32_t* nextScheduled); +JS_GetGCZealBits(JSContext* cx, uint32_t* zealBits, uint32_t* frequency, uint32_t* nextScheduled); extern JS_PUBLIC_API(void) JS_SetGCZeal(JSContext* cx, uint8_t zeal, uint32_t frequency); @@ -5156,10 +5772,10 @@ #endif extern JS_PUBLIC_API(void) -JS_SetParallelParsingEnabled(JSRuntime* rt, bool enabled); +JS_SetParallelParsingEnabled(JSContext* cx, bool enabled); extern JS_PUBLIC_API(void) -JS_SetOffthreadIonCompilationEnabled(JSRuntime* rt, bool enabled); +JS_SetOffthreadIonCompilationEnabled(JSContext* cx, bool enabled); #define JIT_COMPILER_OPTIONS(Register) \ Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \ @@ -5167,9 +5783,14 @@ Register(ION_GVN_ENABLE, "ion.gvn.enable") \ Register(ION_FORCE_IC, "ion.forceinlineCaches") \ Register(ION_ENABLE, "ion.enable") \ + Register(ION_INTERRUPT_WITHOUT_SIGNAL, "ion.interrupt-without-signals") \ + Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \ Register(BASELINE_ENABLE, "baseline.enable") \ Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \ - Register(SIGNALS_ENABLE, "signals.enable") + Register(JUMP_THRESHOLD, "jump-threshold") \ + Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \ + Register(WASM_TEST_MODE, "wasm.test-mode") \ + Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets") typedef enum JSJitCompilerOption { #define JIT_COMPILER_DECLARE(key, str) \ @@ -5182,9 +5803,9 @@ } JSJitCompilerOption; extern JS_PUBLIC_API(void) -JS_SetGlobalJitCompilerOption(JSRuntime* rt, JSJitCompilerOption opt, uint32_t value); -extern JS_PUBLIC_API(int) -JS_GetGlobalJitCompilerOption(JSRuntime* rt, JSJitCompilerOption opt); +JS_SetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t value); +extern JS_PUBLIC_API(bool) +JS_GetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t* valueOut); /** * Convert a uint32_t index into a jsid. @@ -5214,26 +5835,38 @@ extern JS_PUBLIC_API(bool) JS_IsIdentifier(const char16_t* chars, size_t length); +namespace js { +class ScriptSource; +} // namespace js + namespace JS { -/** - * AutoFilename encapsulates a pointer to a C-string and keeps the C-string - * alive for as long as the associated AutoFilename object is alive. - */ -class MOZ_STACK_CLASS JS_PUBLIC_API(AutoFilename) +class MOZ_RAII JS_PUBLIC_API(AutoFilename) { - void* scriptSource_; + private: + js::ScriptSource* ss_; + mozilla::Variant filename_; AutoFilename(const AutoFilename&) = delete; - void operator=(const AutoFilename&) = delete; + AutoFilename& operator=(const AutoFilename&) = delete; public: - AutoFilename() : scriptSource_(nullptr) {} - ~AutoFilename() { reset(nullptr); } + AutoFilename() + : ss_(nullptr), + filename_(mozilla::AsVariant(nullptr)) + {} - const char* get() const; + ~AutoFilename() { + reset(); + } - void reset(void* newScriptSource); + void reset(); + + void setOwned(UniqueChars&& filename); + void setUnowned(const char* filename); + void setScriptSource(js::ScriptSource* ss); + + const char* get() const; }; /** @@ -5288,23 +5921,62 @@ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; -} /* namespace JS */ - /* * Encode/Decode interpreted scripts and functions to/from memory. */ -extern JS_PUBLIC_API(void*) -JS_EncodeScript(JSContext* cx, JS::HandleScript script, uint32_t* lengthp); +typedef mozilla::Vector TranscodeBuffer; -extern JS_PUBLIC_API(void*) -JS_EncodeInterpretedFunction(JSContext* cx, JS::HandleObject funobj, uint32_t* lengthp); +enum TranscodeResult +{ + // Successful encoding / decoding. + TranscodeResult_Ok = 0, -extern JS_PUBLIC_API(JSScript*) -JS_DecodeScript(JSContext* cx, const void* data, uint32_t length); + // A warning message, is set to the message out-param. + TranscodeResult_Failure = 0x100, + TranscodeResult_Failure_BadBuildId = TranscodeResult_Failure | 0x1, + TranscodeResult_Failure_RunOnceNotSupported = TranscodeResult_Failure | 0x2, + TranscodeResult_Failure_AsmJSNotSupported = TranscodeResult_Failure | 0x3, + TranscodeResult_Failure_UnknownClassKind = TranscodeResult_Failure | 0x4, -extern JS_PUBLIC_API(JSObject*) -JS_DecodeInterpretedFunction(JSContext* cx, const void* data, uint32_t length); + // A error, the JSContext has a pending exception. + TranscodeResult_Throw = 0x200 +}; + +extern JS_PUBLIC_API(TranscodeResult) +EncodeScript(JSContext* cx, TranscodeBuffer& buffer, JS::HandleScript script); + +extern JS_PUBLIC_API(TranscodeResult) +EncodeInterpretedFunction(JSContext* cx, TranscodeBuffer& buffer, JS::HandleObject funobj); + +extern JS_PUBLIC_API(TranscodeResult) +DecodeScript(JSContext* cx, TranscodeBuffer& buffer, JS::MutableHandleScript scriptp, + size_t cursorIndex = 0); + +extern JS_PUBLIC_API(TranscodeResult) +DecodeInterpretedFunction(JSContext* cx, TranscodeBuffer& buffer, JS::MutableHandleFunction funp, + size_t cursorIndex = 0); + +} /* namespace JS */ + +namespace js { + +enum class StackFormat { SpiderMonkey, V8, Default }; + +/* + * Sets the format used for stringifying Error stacks. + * + * The default format is StackFormat::SpiderMonkey. Use StackFormat::V8 + * in order to emulate V8's stack formatting. StackFormat::Default can't be + * used here. + */ +extern JS_PUBLIC_API(void) +SetStackFormat(JSContext* cx, StackFormat format); + +extern JS_PUBLIC_API(StackFormat) +GetStackFormat(JSContext* cx); + +} namespace JS { @@ -5326,8 +5998,8 @@ /** The list of reasons why an asm.js module may not be stored in the cache. */ enum AsmJSCacheResult { - AsmJSCache_MIN, - AsmJSCache_Success = AsmJSCache_MIN, + AsmJSCache_Success, + AsmJSCache_MIN = AsmJSCache_Success, AsmJSCache_ModuleTooSmall, AsmJSCache_SynchronousScript, AsmJSCache_QuotaExceeded, @@ -5336,6 +6008,8 @@ AsmJSCache_Disabled_ShellFlags, AsmJSCache_Disabled_JitInspector, AsmJSCache_InternalError, + AsmJSCache_Disabled_PrivateBrowsing, + AsmJSCache_ESR52, AsmJSCache_LIMIT }; @@ -5361,7 +6035,16 @@ typedef void (* CloseAsmJSCacheEntryForWriteOp)(size_t size, uint8_t* memory, intptr_t handle); -typedef js::Vector BuildIdCharVector; +struct AsmJSCacheOps +{ + OpenAsmJSCacheEntryForReadOp openEntryForRead; + CloseAsmJSCacheEntryForReadOp closeEntryForRead; + OpenAsmJSCacheEntryForWriteOp openEntryForWrite; + CloseAsmJSCacheEntryForWriteOp closeEntryForWrite; +}; + +extern JS_PUBLIC_API(void) +SetAsmJSCacheOps(JSContext* cx, const AsmJSCacheOps* callbacks); /** * Return the buildId (represented as a sequence of characters) associated with @@ -5370,20 +6053,64 @@ * engine, it is critical that the buildId shall change for each new build of * the JS engine. */ +typedef js::Vector BuildIdCharVector; + typedef bool (* BuildIdOp)(BuildIdCharVector* buildId); -struct AsmJSCacheOps +extern JS_PUBLIC_API(void) +SetBuildIdOp(JSContext* cx, BuildIdOp buildIdOp); + +/** + * The WasmModule interface allows the embedding to hold a reference to the + * underying C++ implementation of a JS WebAssembly.Module object for purposes + * of (de)serialization off the object's JSRuntime's thread. + * + * - Serialization starts when WebAssembly.Module is passed to the + * structured-clone algorithm. JS::GetWasmModule is called on the JSRuntime + * thread that initiated the structured clone to get the JS::WasmModule. + * This interface is then taken to a background thread where serializedSize() + * and serialize() are called to write the object to two files: a bytecode file + * that always allows successful deserialization and a compiled-code file keyed + * on cpu- and build-id that may become invalid if either of these change between + * serialization and deserialization. After serialization, the reference is + * dropped from the background thread. + * + * - Deserialization starts when the structured clone algorithm encounters a + * serialized WebAssembly.Module. On a background thread, the compiled-code file + * is opened and CompiledWasmModuleAssumptionsMatch is called to see if it is + * still valid (as described above). DeserializeWasmModule is then called to + * construct a JS::WasmModule (also on the background thread), passing the + * bytecode file descriptor and, if valid, the compiled-code file descriptor. + * The JS::WasmObject is then transported to the JSRuntime thread (which + * originated the request) and the wrapping WebAssembly.Module object is created + * by calling createObject(). + */ + +struct WasmModule : mozilla::external::AtomicRefCounted { - OpenAsmJSCacheEntryForReadOp openEntryForRead; - CloseAsmJSCacheEntryForReadOp closeEntryForRead; - OpenAsmJSCacheEntryForWriteOp openEntryForWrite; - CloseAsmJSCacheEntryForWriteOp closeEntryForWrite; - BuildIdOp buildId; + MOZ_DECLARE_REFCOUNTED_TYPENAME(WasmModule) + virtual ~WasmModule() {} + + virtual void serializedSize(size_t* maybeBytecodeSize, size_t* maybeCompiledSize) const = 0; + virtual void serialize(uint8_t* maybeBytecodeBegin, size_t maybeBytecodeSize, + uint8_t* maybeCompiledBegin, size_t maybeCompiledSize) const = 0; + + virtual JSObject* createObject(JSContext* cx) = 0; }; -extern JS_PUBLIC_API(void) -SetAsmJSCacheOps(JSRuntime* rt, const AsmJSCacheOps* callbacks); +extern JS_PUBLIC_API(bool) +IsWasmModuleObject(HandleObject obj); + +extern JS_PUBLIC_API(RefPtr) +GetWasmModule(HandleObject obj); + +extern JS_PUBLIC_API(bool) +CompiledWasmModuleAssumptionsMatch(PRFileDesc* compiled, BuildIdCharVector&& buildId); + +extern JS_PUBLIC_API(RefPtr) +DeserializeWasmModule(PRFileDesc* bytecode, PRFileDesc* maybeCompiled, BuildIdCharVector&& buildId, + JS::UniqueChars filename, unsigned line, unsigned column); /** * Convenience class for imitating a JS level for-of loop. Typical usage: @@ -5475,7 +6202,7 @@ (* LargeAllocationFailureCallback)(void* data); extern JS_PUBLIC_API(void) -SetLargeAllocationFailureCallback(JSRuntime* rt, LargeAllocationFailureCallback afc, void* data); +SetLargeAllocationFailureCallback(JSContext* cx, LargeAllocationFailureCallback afc, void* data); /** * Unlike the error reporter, which is only called if the exception for an OOM @@ -5492,17 +6219,99 @@ (* OutOfMemoryCallback)(JSContext* cx, void* data); extern JS_PUBLIC_API(void) -SetOutOfMemoryCallback(JSRuntime* rt, OutOfMemoryCallback cb, void* data); +SetOutOfMemoryCallback(JSContext* cx, OutOfMemoryCallback cb, void* data); + +/** + * Capture all frames. + */ +struct AllFrames { }; + +/** + * Capture at most this many frames. + */ +struct MaxFrames +{ + uint32_t maxFrames; + + explicit MaxFrames(uint32_t max) + : maxFrames(max) + { + MOZ_ASSERT(max > 0); + } +}; + +/** + * Capture the first frame with the given principals. By default, do not + * consider self-hosted frames with the given principals as satisfying the stack + * capture. + */ +struct JS_PUBLIC_API(FirstSubsumedFrame) +{ + JSContext* cx; + JSPrincipals* principals; + bool ignoreSelfHosted; + + /** + * Use the cx's current compartment's principals. + */ + explicit FirstSubsumedFrame(JSContext* cx, bool ignoreSelfHostedFrames = true); + explicit FirstSubsumedFrame(JSContext* ctx, JSPrincipals* p, bool ignoreSelfHostedFrames = true) + : cx(ctx) + , principals(p) + , ignoreSelfHosted(ignoreSelfHostedFrames) + { + if (principals) + JS_HoldPrincipals(principals); + } + + // No copying because we want to avoid holding and dropping principals + // unnecessarily. + FirstSubsumedFrame(const FirstSubsumedFrame&) = delete; + FirstSubsumedFrame& operator=(const FirstSubsumedFrame&) = delete; + + FirstSubsumedFrame(FirstSubsumedFrame&& rhs) + : principals(rhs.principals) + , ignoreSelfHosted(rhs.ignoreSelfHosted) + { + MOZ_ASSERT(this != &rhs, "self move disallowed"); + rhs.principals = nullptr; + } + + FirstSubsumedFrame& operator=(FirstSubsumedFrame&& rhs) { + new (this) FirstSubsumedFrame(mozilla::Move(rhs)); + return *this; + } + + ~FirstSubsumedFrame() { + if (principals) + JS_DropPrincipals(cx, principals); + } +}; + +using StackCapture = mozilla::Variant; /** * Capture the current call stack as a chain of SavedFrame JSObjects, and set * |stackp| to the SavedFrame for the youngest stack frame, or nullptr if there - * are no JS frames on the stack. If |maxFrameCount| is non-zero, capture at - * most the youngest |maxFrameCount| frames. + * are no JS frames on the stack. + * + * The |capture| parameter describes the portion of the JS stack to capture: + * + * * |JS::AllFrames|: Capture all frames on the stack. + * + * * |JS::MaxFrames|: Capture no more than |JS::MaxFrames::maxFrames| from the + * stack. + * + * * |JS::FirstSubsumedFrame|: Capture the first frame whose principals are + * subsumed by |JS::FirstSubsumedFrame::principals|. By default, do not + * consider self-hosted frames; this can be controlled via the + * |JS::FirstSubsumedFrame::ignoreSelfHosted| flag. Do not capture any async + * stack. */ extern JS_PUBLIC_API(bool) -CaptureCurrentStack(JSContext* cx, MutableHandleObject stackp, unsigned maxFrameCount = 0); +CaptureCurrentStack(JSContext* cx, MutableHandleObject stackp, + StackCapture&& capture = StackCapture(AllFrames())); /* * This is a utility function for preparing an async stack to be used @@ -5632,7 +6441,15 @@ * each line. */ extern JS_PUBLIC_API(bool) -BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp, size_t indent = 0); +BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp, + size_t indent = 0, js::StackFormat stackFormat = js::StackFormat::Default); + +/** + * Return true iff the given object is either a SavedFrame object or wrapper + * around a SavedFrame object, and it is not the SavedFrame.prototype object. + */ +extern JS_PUBLIC_API(bool) +IsSavedFrame(JSObject* obj); } /* namespace JS */ @@ -5649,7 +6466,7 @@ * provide a concrete implementation of this class, as well as the * relevant callbacks (see below). */ -struct PerformanceGroup { +struct JS_PUBLIC_API(PerformanceGroup) { PerformanceGroup(); // The current iteration of the event loop. @@ -5745,6 +6562,8 @@ uint64_t refCount_; }; +using PerformanceGroupVector = mozilla::Vector, 0, SystemAllocPolicy>; + /** * Commit any Performance Monitoring data. * @@ -5752,19 +6571,19 @@ * to the outside world and can cancelled with a call to `ResetMonitoring`. */ extern JS_PUBLIC_API(bool) -FlushPerformanceMonitoring(JSRuntime*); +FlushPerformanceMonitoring(JSContext*); /** * Cancel any measurement that hasn't been committed. */ extern JS_PUBLIC_API(void) -ResetPerformanceMonitoring(JSRuntime*); +ResetPerformanceMonitoring(JSContext*); /** * Cleanup any memory used by performance monitoring. */ extern JS_PUBLIC_API(void) -DisposePerformanceMonitoring(JSRuntime*); +DisposePerformanceMonitoring(JSContext*); /** * Turn on/off stopwatch-based CPU monitoring. @@ -5774,20 +6593,17 @@ * happen if we are out of memory. */ extern JS_PUBLIC_API(bool) -SetStopwatchIsMonitoringCPOW(JSRuntime*, bool); +SetStopwatchIsMonitoringCPOW(JSContext*, bool); extern JS_PUBLIC_API(bool) -GetStopwatchIsMonitoringCPOW(JSRuntime*); +GetStopwatchIsMonitoringCPOW(JSContext*); extern JS_PUBLIC_API(bool) -SetStopwatchIsMonitoringJank(JSRuntime*, bool); -extern JS_PUBLIC_API(bool) -GetStopwatchIsMonitoringJank(JSRuntime*); - +SetStopwatchIsMonitoringJank(JSContext*, bool); extern JS_PUBLIC_API(bool) -IsStopwatchActive(JSRuntime*); +GetStopwatchIsMonitoringJank(JSContext*); // Extract the CPU rescheduling data. extern JS_PUBLIC_API(void) -GetPerfMonitoringTestCpuRescheduling(JSRuntime*, uint64_t* stayed, uint64_t* moved); +GetPerfMonitoringTestCpuRescheduling(JSContext*, uint64_t* stayed, uint64_t* moved); /** @@ -5795,22 +6611,22 @@ * since process start. */ extern JS_PUBLIC_API(void) -AddCPOWPerformanceDelta(JSRuntime*, uint64_t delta); +AddCPOWPerformanceDelta(JSContext*, uint64_t delta); typedef bool (*StopwatchStartCallback)(uint64_t, void*); extern JS_PUBLIC_API(bool) -SetStopwatchStartCallback(JSRuntime*, StopwatchStartCallback, void*); +SetStopwatchStartCallback(JSContext*, StopwatchStartCallback, void*); typedef bool -(*StopwatchCommitCallback)(uint64_t, mozilla::Vector>&, void*); +(*StopwatchCommitCallback)(uint64_t, PerformanceGroupVector&, void*); extern JS_PUBLIC_API(bool) -SetStopwatchCommitCallback(JSRuntime*, StopwatchCommitCallback, void*); +SetStopwatchCommitCallback(JSContext*, StopwatchCommitCallback, void*); typedef bool -(*GetGroupsCallback)(JSContext*, mozilla::Vector>&, void*); +(*GetGroupsCallback)(JSContext*, PerformanceGroupVector&, void*); extern JS_PUBLIC_API(bool) -SetGetPerformanceGroupsCallback(JSRuntime*, GetGroupsCallback, void*); +SetGetPerformanceGroupsCallback(JSContext*, GetGroupsCallback, void*); } /* namespace js */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/jscpucfg.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/jscpucfg.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/jscpucfg.h @@ -7,119 +7,7 @@ #ifndef jscpucfg_h #define jscpucfg_h -#define JS_HAVE_LONG_LONG - -#if defined(_WIN64) - -# if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_) -# define IS_LITTLE_ENDIAN 1 -# undef IS_BIG_ENDIAN -# else /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */ -# error "CPU type is unknown" -# endif /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */ - -#elif defined(_WIN32) - -# ifdef __WATCOMC__ -# define HAVE_VA_LIST_AS_ARRAY 1 -# endif - -# define IS_LITTLE_ENDIAN 1 -# undef IS_BIG_ENDIAN - -#elif defined(__APPLE__) || defined(__powerpc__) || defined(__ppc__) -# if __LITTLE_ENDIAN__ -# define IS_LITTLE_ENDIAN 1 -# undef IS_BIG_ENDIAN -# elif __BIG_ENDIAN__ -# undef IS_LITTLE_ENDIAN -# define IS_BIG_ENDIAN 1 -# endif - -#elif defined(JS_HAVE_ENDIAN_H) -# include - -/* - * Historically, OSes providing only defined - * __BYTE_ORDER to either __LITTLE_ENDIAN or __BIG_ENDIAN. - * The Austin group decided to standardise in - * POSIX around 2011, expecting it to provide a BYTE_ORDER - * #define set to either LITTLE_ENDIAN or BIG_ENDIAN. We - * should try to cope with both possibilities here. - */ - -# if defined(__BYTE_ORDER) || defined(BYTE_ORDER) -# if defined(__BYTE_ORDER) -# if __BYTE_ORDER == __LITTLE_ENDIAN -# define IS_LITTLE_ENDIAN 1 -# undef IS_BIG_ENDIAN -# elif __BYTE_ORDER == __BIG_ENDIAN -# undef IS_LITTLE_ENDIAN -# define IS_BIG_ENDIAN 1 -# endif -# endif -# if defined(BYTE_ORDER) -# if BYTE_ORDER == LITTLE_ENDIAN -# define IS_LITTLE_ENDIAN 1 -# undef IS_BIG_ENDIAN -# elif BYTE_ORDER == BIG_ENDIAN -# undef IS_LITTLE_ENDIAN -# define IS_BIG_ENDIAN 1 -# endif -# endif -# else /* !defined(__BYTE_ORDER) */ -# error "endian.h does not define __BYTE_ORDER nor BYTE_ORDER. Cannot determine endianness." -# endif - -/* BSDs */ -#elif defined(JS_HAVE_MACHINE_ENDIAN_H) -# include -# include - -# if defined(_BYTE_ORDER) -# if _BYTE_ORDER == _LITTLE_ENDIAN -# define IS_LITTLE_ENDIAN 1 -# undef IS_BIG_ENDIAN -# elif _BYTE_ORDER == _BIG_ENDIAN -# undef IS_LITTLE_ENDIAN -# define IS_BIG_ENDIAN 1 -# endif -# else /* !defined(_BYTE_ORDER) */ -# error "machine/endian.h does not define _BYTE_ORDER. Cannot determine endianness." -# endif - -#elif defined(JS_HAVE_SYS_ISA_DEFS_H) -# include - -# if defined(_BIG_ENDIAN) -# undef IS_LITTLE_ENDIAN -# define IS_BIG_ENDIAN 1 -# elif defined(_LITTLE_ENDIAN) -# define IS_LITTLE_ENDIAN 1 -# undef IS_BIG_ENDIAN -# else /* !defined(_LITTLE_ENDIAN) */ -# error "sys/isa_defs.h does not define _BIG_ENDIAN or _LITTLE_ENDIAN. Cannot determine endianness." -# endif -# if !defined(JS_STACK_GROWTH_DIRECTION) -# if defined(_STACK_GROWS_UPWARD) -# define JS_STACK_GROWTH_DIRECTION (1) -# elif defined(_STACK_GROWS_DOWNWARD) -# define JS_STACK_GROWTH_DIRECTION (-1) -# endif -# endif - -#elif defined(__sparc) || defined(__sparc__) || \ - defined(_POWER) || defined(__hppa) || \ - defined(_MIPSEB) || defined(_BIG_ENDIAN) -/* IA64 running HP-UX will have _BIG_ENDIAN defined. - * IA64 running Linux will have endian.h and be handled above. - */ -# undef IS_LITTLE_ENDIAN -# define IS_BIG_ENDIAN 1 - -#else /* !defined(__sparc) && !defined(__sparc__) && ... */ -# error "Cannot determine endianness of your platform. Please add support to jscpucfg.h." -#endif +#include "mozilla/EndianUtils.h" #ifndef JS_STACK_GROWTH_DIRECTION # ifdef __hppa Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsfriendapi.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsfriendapi.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsfriendapi.h @@ -9,6 +9,7 @@ #include "mozilla/Atomics.h" #include "mozilla/Casting.h" +#include "mozilla/Maybe.h" #include "mozilla/MemoryReporting.h" #include "mozilla/UniquePtr.h" @@ -19,6 +20,7 @@ #include "js/CallArgs.h" #include "js/CallNonGenericMethod.h" #include "js/Class.h" +#include "js/Utility.h" #if JS_STACK_GROWTH_DIRECTION > 0 # define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) < (limit))) @@ -43,7 +45,7 @@ } /* namespace js */ extern JS_FRIEND_API(void) -JS_SetGrayGCRootsTracer(JSRuntime* rt, JSTraceDataOp traceOp, void* data); +JS_SetGrayGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp, void* data); extern JS_FRIEND_API(JSObject*) JS_FindCompilationScope(JSContext* cx, JS::HandleObject obj); @@ -72,9 +74,6 @@ extern JS_FRIEND_API(size_t) JS_SetProtoCalled(JSContext* cx); -extern JS_FRIEND_API(bool) -JS_ImmutablePrototypesEnabled(); - extern JS_FRIEND_API(size_t) JS_GetCustomIteratorCount(JSContext* cx); @@ -108,36 +107,46 @@ enum { JS_TELEMETRY_GC_REASON, - JS_TELEMETRY_GC_IS_COMPARTMENTAL, + JS_TELEMETRY_GC_IS_ZONE_GC, JS_TELEMETRY_GC_MS, JS_TELEMETRY_GC_BUDGET_MS, JS_TELEMETRY_GC_ANIMATION_MS, JS_TELEMETRY_GC_MAX_PAUSE_MS, JS_TELEMETRY_GC_MARK_MS, JS_TELEMETRY_GC_SWEEP_MS, + JS_TELEMETRY_GC_COMPACT_MS, JS_TELEMETRY_GC_MARK_ROOTS_MS, JS_TELEMETRY_GC_MARK_GRAY_MS, JS_TELEMETRY_GC_SLICE_MS, JS_TELEMETRY_GC_SLOW_PHASE, JS_TELEMETRY_GC_MMU_50, JS_TELEMETRY_GC_RESET, + JS_TELEMETRY_GC_RESET_REASON, JS_TELEMETRY_GC_INCREMENTAL_DISABLED, JS_TELEMETRY_GC_NON_INCREMENTAL, + JS_TELEMETRY_GC_NON_INCREMENTAL_REASON, JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, JS_TELEMETRY_GC_MINOR_REASON, JS_TELEMETRY_GC_MINOR_REASON_LONG, JS_TELEMETRY_GC_MINOR_US, + JS_TELEMETRY_GC_NURSERY_BYTES, + JS_TELEMETRY_GC_PRETENURE_COUNT, JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT, JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_ADDONS, - JS_TELEMETRY_ADDON_EXCEPTIONS + JS_TELEMETRY_ADDON_EXCEPTIONS, + JS_TELEMETRY_AOT_USAGE, + JS_TELEMETRY_END }; typedef void (*JSAccumulateTelemetryDataCallback)(int id, uint32_t sample, const char* key); extern JS_FRIEND_API(void) -JS_SetAccumulateTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback); +JS_SetAccumulateTelemetryCallback(JSContext* cx, JSAccumulateTelemetryDataCallback callback); + +extern JS_FRIEND_API(bool) +JS_GetIsSecureContext(JSCompartment* compartment); extern JS_FRIEND_API(JSPrincipals*) JS_GetCompartmentPrincipals(JSCompartment* compartment); @@ -178,7 +187,7 @@ namespace js { JS_FRIEND_API(bool) -GetBuiltinClass(JSContext* cx, JS::HandleObject obj, ESClassValue* classValue); +GetBuiltinClass(JSContext* cx, JS::HandleObject obj, ESClass* cls); JS_FRIEND_API(const char*) ObjectClassName(JSContext* cx, JS::HandleObject obj); @@ -198,41 +207,57 @@ #ifdef JS_DEBUG /* - * Routines to print out values during debugging. These are FRIEND_API to help + * Routines to print out values during debugging. These are FRIEND_API to help * the debugger find them and to support temporarily hacking js::Dump* calls - * into other code. + * into other code. Note that there are overloads that do not require the FILE* + * parameter, which will default to stderr. */ extern JS_FRIEND_API(void) -DumpString(JSString* str); +DumpString(JSString* str, FILE* fp); extern JS_FRIEND_API(void) -DumpAtom(JSAtom* atom); +DumpAtom(JSAtom* atom, FILE* fp); extern JS_FRIEND_API(void) -DumpObject(JSObject* obj); +DumpObject(JSObject* obj, FILE* fp); extern JS_FRIEND_API(void) -DumpChars(const char16_t* s, size_t n); +DumpChars(const char16_t* s, size_t n, FILE* fp); extern JS_FRIEND_API(void) -DumpValue(const JS::Value& val); +DumpValue(const JS::Value& val, FILE* fp); extern JS_FRIEND_API(void) -DumpId(jsid id); +DumpId(jsid id, FILE* fp); extern JS_FRIEND_API(void) -DumpInterpreterFrame(JSContext* cx, InterpreterFrame* start = nullptr); +DumpInterpreterFrame(JSContext* cx, FILE* fp, InterpreterFrame* start = nullptr); extern JS_FRIEND_API(bool) -DumpPC(JSContext* cx); +DumpPC(JSContext* cx, FILE* fp); extern JS_FRIEND_API(bool) -DumpScript(JSContext* cx, JSScript* scriptArg); +DumpScript(JSContext* cx, JSScript* scriptArg, FILE* fp); + +// Versions for use directly in a debugger (default parameters are not handled +// well in gdb; built-in handles like stderr are not handled well in lldb.) +extern JS_FRIEND_API(void) DumpString(JSString* str); +extern JS_FRIEND_API(void) DumpAtom(JSAtom* atom); +extern JS_FRIEND_API(void) DumpObject(JSObject* obj); +extern JS_FRIEND_API(void) DumpChars(const char16_t* s, size_t n); +extern JS_FRIEND_API(void) DumpValue(const JS::Value& val); +extern JS_FRIEND_API(void) DumpId(jsid id); +extern JS_FRIEND_API(void) DumpInterpreterFrame(JSContext* cx, InterpreterFrame* start = nullptr); +extern JS_FRIEND_API(bool) DumpPC(JSContext* cx); +extern JS_FRIEND_API(bool) DumpScript(JSContext* cx, JSScript* scriptArg); #endif extern JS_FRIEND_API(void) +DumpBacktrace(JSContext* cx, FILE* fp); + +extern JS_FRIEND_API(void) DumpBacktrace(JSContext* cx); } // namespace js @@ -243,6 +268,13 @@ extern JS_FRIEND_API(char*) FormatStackDump(JSContext* cx, char* buf, bool showArgs, bool showLocals, bool showThisProps); +/** + * Set all of the uninitialized lexicals on an object to undefined. Return + * true if any lexicals were initialized and false otherwise. + * */ +extern JS_FRIEND_API(bool) +ForceLexicalInitialization(JSContext *cx, HandleObject obj); + } // namespace JS /** @@ -275,7 +307,7 @@ PropertyCopyBehavior copyBehavior = CopyNonConfigurableAsIs); extern JS_FRIEND_API(bool) -JS_WrapPropertyDescriptor(JSContext* cx, JS::MutableHandle desc); +JS_WrapPropertyDescriptor(JSContext* cx, JS::MutableHandle desc); struct JSFunctionSpecWithHelp { const char* name; @@ -300,61 +332,37 @@ namespace js { +extern JS_FRIEND_DATA(const js::ClassOps) ProxyClassOps; +extern JS_FRIEND_DATA(const js::ClassExtension) ProxyClassExtension; +extern JS_FRIEND_DATA(const js::ObjectOps) ProxyObjectOps; + /* * Helper Macros for creating JSClasses that function as proxies. * * NB: The macro invocation must be surrounded by braces, so as to * allow for potential JSClass extensions. */ -#define PROXY_MAKE_EXT(isWrappedNative, objectMoved) \ +#define PROXY_MAKE_EXT(objectMoved) \ { \ - isWrappedNative, \ js::proxy_WeakmapKeyDelegate, \ objectMoved \ } -#define PROXY_CLASS_WITH_EXT(name, flags, ext) \ +#define PROXY_CLASS_WITH_EXT(name, flags, extPtr) \ { \ name, \ js::Class::NON_NATIVE | \ JSCLASS_IS_PROXY | \ - JSCLASS_DELAY_METADATA_CALLBACK | \ + JSCLASS_DELAY_METADATA_BUILDER | \ flags, \ - nullptr, /* addProperty */ \ - nullptr, /* delProperty */ \ - nullptr, /* getProperty */ \ - nullptr, /* setProperty */ \ - nullptr, /* enumerate */ \ - nullptr, /* resolve */ \ - nullptr, /* mayResolve */ \ - js::proxy_Finalize, /* finalize */ \ - nullptr, /* call */ \ - js::proxy_HasInstance, /* hasInstance */ \ - nullptr, /* construct */ \ - js::proxy_Trace, /* trace */ \ + &js::ProxyClassOps, \ JS_NULL_CLASS_SPEC, \ - ext, \ - { \ - js::proxy_LookupProperty, \ - js::proxy_DefineProperty, \ - js::proxy_HasProperty, \ - js::proxy_GetProperty, \ - js::proxy_SetProperty, \ - js::proxy_GetOwnPropertyDescriptor, \ - js::proxy_DeleteProperty, \ - js::proxy_Watch, js::proxy_Unwatch, \ - js::proxy_GetElements, \ - nullptr, /* enumerate */ \ - js::proxy_FunToString, \ - } \ - } - -#define PROXY_CLASS_DEF(name, flags) \ - PROXY_CLASS_WITH_EXT(name, flags, \ - PROXY_MAKE_EXT( \ - false, /* isWrappedNative */ \ - js::proxy_ObjectMoved \ - )) + extPtr, \ + &js::ProxyObjectOps \ + } + +#define PROXY_CLASS_DEF(name, flags) \ + PROXY_CLASS_WITH_EXT(name, flags, &js::ProxyClassExtension) /* * Proxy stubs, similar to JS_*Stub, for embedder proxy class definitions. @@ -367,7 +375,7 @@ JS::MutableHandle propp); extern JS_FRIEND_API(bool) proxy_DefineProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result); extern JS_FRIEND_API(bool) proxy_HasProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); @@ -379,7 +387,7 @@ JS::HandleValue receiver, JS::ObjectOpResult& result); extern JS_FRIEND_API(bool) proxy_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); extern JS_FRIEND_API(bool) proxy_DeleteProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::ObjectOpResult& result); @@ -436,17 +444,17 @@ }; /** - * Have |rt| use |hook| to retrieve lazily-retrieved source code. See the - * comments for SourceHook. The runtime takes ownership of the hook, and - * will delete it when the runtime itself is deleted, or when a new hook is + * Have |cx| use |hook| to retrieve lazily-retrieved source code. See the + * comments for SourceHook. The context takes ownership of the hook, and + * will delete it when the context itself is deleted, or when a new hook is * set. */ extern JS_FRIEND_API(void) -SetSourceHook(JSRuntime* rt, mozilla::UniquePtr hook); +SetSourceHook(JSContext* cx, mozilla::UniquePtr hook); -/** Remove |rt|'s source hook, and return it. The caller now owns the hook. */ +/** Remove |cx|'s source hook, and return it. The caller now owns the hook. */ extern JS_FRIEND_API(mozilla::UniquePtr) -ForgetSourceHook(JSRuntime* rt); +ForgetSourceHook(JSContext* cx); extern JS_FRIEND_API(JS::Zone*) GetCompartmentZone(JSCompartment* comp); @@ -464,7 +472,7 @@ * fp is the file for the dump output. */ extern JS_FRIEND_API(void) -DumpHeap(JSRuntime* rt, FILE* fp, DumpHeapNurseryBehaviour nurseryBehaviour); +DumpHeap(JSContext* cx, FILE* fp, DumpHeapNurseryBehaviour nurseryBehaviour); #ifdef JS_OLD_GETTER_SETTER_METHODS JS_FRIEND_API(bool) obj_defineGetter(JSContext* cx, unsigned argc, JS::Value* vp); @@ -485,9 +493,9 @@ struct WeakMapTracer { - JSRuntime* runtime; + JSContext* context; - explicit WeakMapTracer(JSRuntime* rt) : runtime(rt) {} + explicit WeakMapTracer(JSContext* cx) : context(cx) {} // Weak map tracer callback, called once for every binding of every // weak map that was live at the time of the last garbage collection. @@ -502,7 +510,7 @@ TraceWeakMaps(WeakMapTracer* trc); extern JS_FRIEND_API(bool) -AreGCGrayBitsValid(JSRuntime* rt); +AreGCGrayBitsValid(JSContext* cx); extern JS_FRIEND_API(bool) ZoneGlobalsAreAllGray(JS::Zone* zone); @@ -516,15 +524,19 @@ extern JS_FRIEND_API(JSObject*) GetWeakmapKeyDelegate(JSObject* key); -JS_FRIEND_API(JS::TraceKind) -GCThingTraceKind(void* thing); - /** - * Invoke cellCallback on every gray JS_OBJECT in the given zone. + * Invoke cellCallback on every gray JSObject in the given zone. */ extern JS_FRIEND_API(void) IterateGrayObjects(JS::Zone* zone, GCThingCallback cellCallback, void* data); +/** + * Invoke cellCallback on every gray JSObject in the given zone while cycle + * collection is in progress. + */ +extern JS_FRIEND_API(void) +IterateGrayObjectsUnderCC(JS::Zone* zone, GCThingCallback cellCallback, void* data); + #ifdef JS_HAS_CTYPES extern JS_FRIEND_API(size_t) SizeOfDataIfCDataObject(mozilla::MallocSizeOf mallocSizeOf, JSObject* obj); @@ -632,17 +644,6 @@ JS_FRIEND_API(const Class*) ProtoKeyToClass(JSProtoKey key); -// Returns true if the standard class identified by |key| inherits from -// another standard class (in addition to Object) along its proto chain. -// -// In practice, this only returns true for Error subtypes. -inline bool -StandardClassIsDependent(JSProtoKey key) -{ - const Class* clasp = ProtoKeyToClass(key); - return clasp && clasp->spec.defined() && clasp->spec.dependent(); -} - // Returns the key for the class inherited by a given standard class (that // is to say, the prototype of this standard class's prototype). // @@ -651,15 +652,15 @@ // cached proto key, except in cases where multiple JSProtoKeys share a // JSClass. inline JSProtoKey -ParentKeyForStandardClass(JSProtoKey key) +InheritanceProtoKeyForStandardClass(JSProtoKey key) { // [Object] has nothing to inherit from. if (key == JSProto_Object) return JSProto_Null; - // If we're dependent, return the key of the class we depend on. - if (StandardClassIsDependent(key)) - return ProtoKeyToClass(key)->spec.parentKey(); + // If we're ClassSpec defined return the proto key from that + if (ProtoKeyToClass(key)->specDefined()) + return ProtoKeyToClass(key)->specInheritanceProtoKey(); // Otherwise, we inherit [Object]. return JSProto_Object; @@ -729,6 +730,9 @@ JS_FRIEND_API(bool) GetObjectProto(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject proto); +extern JS_FRIEND_API(JSObject*) +GetStaticPrototype(JSObject* obj); + JS_FRIEND_API(bool) GetOriginalEval(JSContext* cx, JS::HandleObject scope, JS::MutableHandleObject eval); @@ -884,28 +888,50 @@ return reinterpret_cast(str); } +template +MOZ_ALWAYS_INLINE void +CopyLinearStringChars(CharType* dest, JSLinearString* s, size_t len, size_t start = 0); + MOZ_ALWAYS_INLINE void -CopyLinearStringChars(char16_t* dest, JSLinearString* s, size_t len) +CopyLinearStringChars(char16_t* dest, JSLinearString* s, size_t len, size_t start = 0) { + MOZ_ASSERT(start + len <= GetLinearStringLength(s)); JS::AutoCheckCannotGC nogc; if (LinearStringHasLatin1Chars(s)) { const JS::Latin1Char* src = GetLatin1LinearStringChars(nogc, s); for (size_t i = 0; i < len; i++) - dest[i] = src[i]; + dest[i] = src[start + i]; } else { const char16_t* src = GetTwoByteLinearStringChars(nogc, s); - mozilla::PodCopy(dest, src, len); + mozilla::PodCopy(dest, src + start, len); + } +} + +MOZ_ALWAYS_INLINE void +CopyLinearStringChars(char* dest, JSLinearString* s, size_t len, size_t start = 0) +{ + MOZ_ASSERT(start + len <= GetLinearStringLength(s)); + JS::AutoCheckCannotGC nogc; + if (LinearStringHasLatin1Chars(s)) { + const JS::Latin1Char* src = GetLatin1LinearStringChars(nogc, s); + for (size_t i = 0; i < len; i++) + dest[i] = char(src[start + i]); + } else { + const char16_t* src = GetTwoByteLinearStringChars(nogc, s); + for (size_t i = 0; i < len; i++) + dest[i] = char(src[start + i]); } } +template inline bool -CopyStringChars(JSContext* cx, char16_t* dest, JSString* s, size_t len) +CopyStringChars(JSContext* cx, CharType* dest, JSString* s, size_t len, size_t start = 0) { JSLinearString* linear = StringToLinearString(cx, s); if (!linear) return false; - CopyLinearStringChars(dest, linear, len); + CopyLinearStringChars(dest, linear, len, start); return true; } @@ -946,15 +972,12 @@ StringIsArrayIndex(JSLinearString* str, uint32_t* indexp); JS_FRIEND_API(void) -SetPreserveWrapperCallback(JSRuntime* rt, PreserveWrapperCallback callback); +SetPreserveWrapperCallback(JSContext* cx, PreserveWrapperCallback callback); JS_FRIEND_API(bool) IsObjectInContextCompartment(JSObject* obj, const JSContext* cx); /* - * NB: these flag bits are encoded into the bytecode stream in the immediate - * operand of JSOP_ITER, so don't change them without advancing vm/Xdr.h's - * XDR_BYTECODE_VERSION. * NB: keep these in sync with the copy in builtin/SelfHostingDefines.h. * The first three are omitted because they shouldn't be used in new code. */ @@ -972,9 +995,7 @@ inline uintptr_t GetNativeStackLimit(JSContext* cx, StackKind kind, int extraAllowance = 0) { - PerThreadDataFriendFields* mainThread = - PerThreadDataFriendFields::getMainThread(GetRuntime(cx)); - uintptr_t limit = mainThread->nativeStackLimit[kind]; + uintptr_t limit = ContextFriendFields::get(cx)->nativeStackLimit[kind]; #if JS_STACK_GROWTH_DIRECTION > 0 limit += extraAllowance; #else @@ -1080,9 +1101,6 @@ JS_FRIEND_API(char*) GetCodeCoverageSummary(JSContext* cx, size_t* length); -JS_FRIEND_API(bool) -ContextHasOutstandingRequests(const JSContext* cx); - typedef void (* ActivityCallback)(void* arg, bool active); @@ -1092,7 +1110,7 @@ * idle and a request begins. */ JS_FRIEND_API(void) -SetActivityCallback(JSRuntime* rt, ActivityCallback cb, void* arg); +SetActivityCallback(JSContext* cx, ActivityCallback cb, void* arg); typedef bool (* DOMInstanceClassHasProtoAtDepth)(const Class* instanceClass, @@ -1103,10 +1121,10 @@ typedef struct JSDOMCallbacks DOMCallbacks; extern JS_FRIEND_API(void) -SetDOMCallbacks(JSRuntime* rt, const DOMCallbacks* callbacks); +SetDOMCallbacks(JSContext* cx, const DOMCallbacks* callbacks); extern JS_FRIEND_API(const DOMCallbacks*) -GetDOMCallbacks(JSRuntime* rt); +GetDOMCallbacks(JSContext* cx); extern JS_FRIEND_API(JSObject*) GetTestingFunctions(JSContext* cx); @@ -1129,7 +1147,7 @@ * Returns nullptr for invalid arguments and JSEXN_INTERNALERR */ extern JS_FRIEND_API(JSFlatString*) -GetErrorTypeName(JSRuntime* rt, int16_t exnType); +GetErrorTypeName(JSContext* cx, int16_t exnType); #ifdef JS_DEBUG extern JS_FRIEND_API(unsigned) @@ -1221,10 +1239,9 @@ generation(0) {} - void Unlink() + void OwnerUnlinked() { ++generation; - expando.setUndefined(); } static size_t offsetOfExpando() @@ -1306,29 +1323,35 @@ * JSString methods and often the code can be rewritten so that only indexes * instead of char pointers are used in parts of the code that can GC. */ -class MOZ_STACK_CLASS AutoStableStringChars +class MOZ_STACK_CLASS JS_FRIEND_API(AutoStableStringChars) { + /* + * When copying string char, use this many bytes of inline storage. This is + * chosen to allow the inline string types to be copied without allocating. + * This is asserted in AutoStableStringChars::allocOwnChars. + */ + static const size_t InlineCapacity = 24; + /* Ensure the string is kept alive while we're using its chars. */ JS::RootedString s_; union { const char16_t* twoByteChars_; const JS::Latin1Char* latin1Chars_; }; + mozilla::Maybe> ownChars_; enum State { Uninitialized, Latin1, TwoByte }; State state_; - bool ownsChars_; public: explicit AutoStableStringChars(JSContext* cx) - : s_(cx), state_(Uninitialized), ownsChars_(false) + : s_(cx), state_(Uninitialized) {} - ~AutoStableStringChars(); - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool init(JSContext* cx, JSString* s); /* Like init(), but Latin1 chars are inflated to TwoByte. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool initTwoByte(JSContext* cx, JSString* s); bool isLatin1() const { return state_ == Latin1; } @@ -1348,46 +1371,79 @@ mozilla::Range twoByteRange() const { MOZ_ASSERT(state_ == TwoByte); return mozilla::Range(twoByteChars_, - GetStringLength(s_)); + GetStringLength(s_)); } /* If we own the chars, transfer ownership to the caller. */ bool maybeGiveOwnershipToCaller() { MOZ_ASSERT(state_ != Uninitialized); - if (!ownsChars_) + if (!ownChars_.isSome() || !ownChars_->extractRawBuffer()) return false; state_ = Uninitialized; - ownsChars_ = false; + ownChars_.reset(); return true; } private: AutoStableStringChars(const AutoStableStringChars& other) = delete; void operator=(const AutoStableStringChars& other) = delete; -}; -/** - * Creates a string of the form |ErrorType: ErrorMessage| for a JSErrorReport, - * which generally matches the toString() behavior of an ErrorObject. - */ -extern JS_FRIEND_API(JSString*) -ErrorReportToString(JSContext* cx, JSErrorReport* reportp); + bool baseIsInline(JS::Handle linearString); + template T* allocOwnChars(JSContext* cx, size_t count); + bool copyLatin1Chars(JSContext* cx, JS::Handle linearString); + bool copyTwoByteChars(JSContext* cx, JS::Handle linearString); + bool copyAndInflateLatin1Chars(JSContext*, JS::Handle linearString); +}; struct MOZ_STACK_CLASS JS_FRIEND_API(ErrorReport) { explicit ErrorReport(JSContext* cx); ~ErrorReport(); - bool init(JSContext* cx, JS::HandleValue exn); + enum SniffingBehavior { + WithSideEffects, + NoSideEffects + }; + + /** + * Generate a JSErrorReport from the provided thrown value. + * + * If the value is a (possibly wrapped) Error object, the JSErrorReport will + * be exactly initialized from the Error object's information, without + * observable side effects. (The Error object's JSErrorReport is reused, if + * it has one.) + * + * Otherwise various attempts are made to derive JSErrorReport information + * from |exn| and from the current execution state. This process is + * *definitely* inconsistent with any standard, and particulars of the + * behavior implemented here generally shouldn't be relied upon. + * + * If the value of |sniffingBehavior| is |WithSideEffects|, some of these + * attempts *may* invoke user-configurable behavior when |exn| is an object: + * converting |exn| to a string, detecting and getting properties on |exn|, + * accessing |exn|'s prototype chain, and others are possible. Users *must* + * tolerate |ErrorReport::init| potentially having arbitrary effects. Any + * exceptions thrown by these operations will be caught and silently + * ignored, and "default" values will be substituted into the JSErrorReport. + * + * But if the value of |sniffingBehavior| is |NoSideEffects|, these attempts + * *will not* invoke any observable side effects. The JSErrorReport will + * simply contain fewer, less precise details. + * + * Unlike some functions involved in error handling, this function adheres + * to the usual JSAPI return value error behavior. + */ + bool init(JSContext* cx, JS::HandleValue exn, + SniffingBehavior sniffingBehavior); JSErrorReport* report() { return reportp; } - const char* message() + const JS::ConstUTF8CharsZ toStringResult() { - return message_; + return toStringResult_; } private: @@ -1397,8 +1453,8 @@ // // Returns false if we fail to actually populate the ErrorReport // for some reason (probably out of memory). - bool populateUncaughtExceptionReport(JSContext* cx, ...); - bool populateUncaughtExceptionReportVA(JSContext* cx, va_list ap); + bool populateUncaughtExceptionReportUTF8(JSContext* cx, ...); + bool populateUncaughtExceptionReportUTF8VA(JSContext* cx, va_list ap); // Reports exceptions from add-on scopes to telementry. void ReportAddonExceptionToTelementry(JSContext* cx); @@ -1406,16 +1462,9 @@ // We may have a provided JSErrorReport, so need a way to represent that. JSErrorReport* reportp; - // And we may have a message. - const char* message_; - // Or we may need to synthesize a JSErrorReport one of our own. JSErrorReport ownedReport; - // Or a message of our own. If this is non-null, we need to clean up both - // it and ownedReport. - char* ownedMessage; - // And we have a string to maybe keep alive that has pointers into // it from ownedReport. JS::RootedString str; @@ -1426,14 +1475,14 @@ // And we need to root our exception value. JS::RootedObject exnObject; - // And possibly some byte storage for our message_. - JSAutoByteString bytesStorage; - // And for our filename. JSAutoByteString filename; - // True if we need to free message_ and the stuff in ownedReport - bool ownsMessageAndReport; + // We may have a result of error.toString(). + // FIXME: We should not call error.toString(), since it could have side + // effect (see bug 633623). + JS::ConstUTF8CharsZ toStringResult_; + JSAutoByteString toStringResultBytesStorage; }; /* Implemented in vm/StructuredClone.cpp. */ @@ -1465,11 +1514,14 @@ Uint8Clamped, /** - * SIMD types don't have their own TypedArray equivalent, for now. + * Types that don't have their own TypedArray equivalent, for now. */ MaxTypedArrayViewType, + Int64, Float32x4, + Int8x16, + Int16x8, Int32x4 }; @@ -1488,8 +1540,11 @@ case Uint32: case Float32: return 4; + case Int64: case Float64: return 8; + case Int8x16: + case Int16x8: case Int32x4: case Float32x4: return 16; @@ -1504,6 +1559,9 @@ case Int8: case Int16: case Int32: + case Int64: + case Int8x16: + case Int16x8: case Int32x4: return true; case Uint8: @@ -1529,9 +1587,12 @@ case Uint16: case Int32: case Uint32: + case Int64: case Float32: case Float64: return false; + case Int8x16: + case Int16x8: case Int32x4: case Float32x4: return true; @@ -1544,6 +1605,10 @@ static inline size_t scalarByteSize(Type atype) { switch (atype) { + case Int8x16: + return 1; + case Int16x8: + return 2; case Int32x4: case Float32x4: return 4; @@ -1554,6 +1619,7 @@ case Uint16: case Int32: case Uint32: + case Int64: case Float32: case Float64: case MaxTypedArrayViewType: @@ -1653,7 +1719,10 @@ uint32_t byteOffset, int32_t length); /** - * Create a new SharedArrayBuffer with the given byte length. + * Create a new SharedArrayBuffer with the given byte length. This + * may only be called if + * JS::CompartmentCreationOptionsRef(cx).getSharedMemoryAndAtomicsEnabled() is + * true. */ extern JS_FRIEND_API(JSObject*) JS_NewSharedArrayBuffer(JSContext* cx, uint32_t nbytes); @@ -1889,7 +1958,7 @@ /** * Return true if the arrayBuffer contains any data. This will return false for - * ArrayBuffer.prototype and neutered ArrayBuffers. + * ArrayBuffer.prototype and detached ArrayBuffers. * * |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 @@ -2010,39 +2079,29 @@ JS_GetArrayBufferViewData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); /** - * Return the ArrayBuffer or SharedArrayBuffer underlying an - * ArrayBufferView. If the buffer has been neutered, this will still - * return the neutered buffer. |obj| must be an object that would + * Return the ArrayBuffer or SharedArrayBuffer underlying an ArrayBufferView. + * This may return a detached buffer. |obj| must be an object that would * return true for JS_IsArrayBufferViewObject(). */ extern JS_FRIEND_API(JSObject*) JS_GetArrayBufferViewBuffer(JSContext* cx, JS::HandleObject obj, bool* isSharedMemory); -typedef enum { - ChangeData, - KeepData -} NeuterDataDisposition; - /** - * Set an ArrayBuffer's length to 0 and neuter all of its views. + * Detach an ArrayBuffer, causing all associated views to no longer refer to + * the ArrayBuffer's original attached memory. * - * The |changeData| argument is a hint to inform internal behavior with respect - * to the internal pointer to the ArrayBuffer's data after being neutered. - * There is no guarantee it will be respected. But if it is respected, the - * ArrayBuffer's internal data pointer will, or will not, have changed - * accordingly. + * The |changeData| argument is obsolete and ignored. */ extern JS_FRIEND_API(bool) -JS_NeuterArrayBuffer(JSContext* cx, JS::HandleObject obj, - NeuterDataDisposition changeData); +JS_DetachArrayBuffer(JSContext* cx, JS::HandleObject obj); /** - * Check whether the obj is ArrayBufferObject and neutered. Note that this - * may return false if a security wrapper is encountered that denies the + * 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_FRIEND_API(bool) -JS_IsNeuteredArrayBufferObject(JSObject* obj); +JS_IsDetachedArrayBufferObject(JSObject* obj); /** * Check whether obj supports JS_GetDataView* APIs. @@ -2336,7 +2395,12 @@ js::jit::InlinableNative inlinableNative; }; - uint16_t depth; + union { + uint16_t depth; + + // Additional opcode for some InlinableNative functions. + uint16_t nativeOp; + }; // These fields are carefully packed to take up 4 bytes. If you need more // bits for whatever reason, please see if you can steal bits from existing @@ -2602,22 +2666,7 @@ ScriptEnvironmentPreparer::Closure& closure); JS_FRIEND_API(void) -SetScriptEnvironmentPreparer(JSRuntime* rt, ScriptEnvironmentPreparer* -preparer); - -/** - * To help embedders enforce their invariants, we allow them to specify in - * advance which JSContext should be passed to JSAPI calls. If this is set - * to a non-null value, the assertSameCompartment machinery does double- - * duty (in debug builds) to verify that it matches the cx being used. - */ -#ifdef DEBUG -JS_FRIEND_API(void) -Debug_SetActiveJSContext(JSRuntime* rt, JSContext* cx); -#else -inline void -Debug_SetActiveJSContext(JSRuntime* rt, JSContext* cx) {} -#endif +SetScriptEnvironmentPreparer(JSContext* cx, ScriptEnvironmentPreparer* preparer); enum CTypesActivityType { CTYPES_CALL_BEGIN, @@ -2634,7 +2683,7 @@ * calling into C. */ JS_FRIEND_API(void) -SetCTypesActivityCallback(JSRuntime* rt, CTypesActivityCallback cb); +SetCTypesActivityCallback(JSContext* cx, CTypesActivityCallback cb); class MOZ_RAII JS_FRIEND_API(AutoCTypesActivityCallback) { private: @@ -2658,8 +2707,23 @@ } }; -typedef JSObject* -(* ObjectMetadataCallback)(JSContext* cx, JSObject* obj); +// Abstract base class for objects that build allocation metadata for JavaScript +// values. +struct AllocationMetadataBuilder { + AllocationMetadataBuilder() { } + + // Return a metadata object for the newly constructed object |obj|, or + // nullptr if there's no metadata to attach. + // + // Implementations should treat all errors as fatal; there is no way to + // report errors from this callback. In particular, the caller provides an + // oomUnsafe for overriding implementations to use. + virtual JSObject* build(JSContext* cx, JS::HandleObject obj, + AutoEnterOOMUnsafeRegion& oomUnsafe) const + { + return nullptr; + } +}; /** * Specify a callback to invoke when creating each JS object in the current @@ -2667,11 +2731,11 @@ * object. */ JS_FRIEND_API(void) -SetObjectMetadataCallback(JSContext* cx, ObjectMetadataCallback callback); +SetAllocationMetadataBuilder(JSContext* cx, const AllocationMetadataBuilder *callback); /** Get the metadata associated with an object. */ JS_FRIEND_API(JSObject*) -GetObjectMetadata(JSObject* obj); +GetAllocationMetadata(JSObject* obj); JS_FRIEND_API(bool) GetElementsWithAdder(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver, @@ -2703,11 +2767,11 @@ JS_FRIEND_API(bool) SetPropertyIgnoringNamedGetter(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, JS::HandleValue receiver, - JS::Handle ownDesc, + JS::Handle ownDesc, JS::ObjectOpResult& result); JS_FRIEND_API(void) -ReportErrorWithId(JSContext* cx, const char* msg, JS::HandleId id); +ReportASCIIErrorWithId(JSContext* cx, const char* msg, JS::HandleId id); // This function is for one specific use case, please don't use this for anything else! extern JS_FRIEND_API(bool) @@ -2745,12 +2809,12 @@ #endif /** - * Get the nearest enclosing with scope object for a given function. If the - * function is not scripted or is not enclosed by a with scope, returns the - * global. + * Get the nearest enclosing with environment object for a given function. If + * the function is not scripted or is not enclosed by a with scope, returns + * the global. */ extern JS_FRIEND_API(JSObject*) -GetNearestEnclosingWithScopeObjectForFunction(JSFunction* fun); +GetNearestEnclosingWithEnvironmentObjectForFunction(JSFunction* fun); /** * Get the first SavedFrame object in this SavedFrame stack whose principals are @@ -2776,7 +2840,7 @@ * invariant that actual Window objects (the global objects of web pages) are * never directly exposed to script. Instead we often substitute a WindowProxy. * - * The scope chain, on the other hand, contains the Window and never its + * The environment chain, on the other hand, contains the Window and never its * WindowProxy. * * As a result, we have calls to these "substitute-this-object-for-that-object" @@ -2790,7 +2854,7 @@ * functions below. */ extern JS_FRIEND_API(void) -SetWindowProxyClass(JSRuntime* rt, const Class* clasp); +SetWindowProxyClass(JSContext* cx, const Class* clasp); /** * Associates a WindowProxy with a Window (global object). `windowProxy` must @@ -2842,26 +2906,6 @@ } /* namespace js */ -extern JS_FRIEND_API(void) -JS_StoreObjectPostBarrierCallback(JSContext* cx, - void (*callback)(JSTracer* trc, JSObject* key, void* data), - JSObject* key, void* data); - -extern JS_FRIEND_API(void) -JS_StoreStringPostBarrierCallback(JSContext* cx, - void (*callback)(JSTracer* trc, JSString* key, void* data), - JSString* key, void* data); - -/** - * Forcibly clear postbarrier callbacks queued by the previous two methods. - * This should be used when the object owning the postbarriered pointers is - * being destroyed outside of a garbage collection. - * - * This currently works by performing a minor GC. - */ -extern JS_FRIEND_API(void) -JS_ClearAllPostBarrierCallbacks(JSRuntime *rt); - class NativeProfiler { public: @@ -2888,7 +2932,7 @@ class MemProfiler { static mozilla::Atomic sActiveProfilerCount; - static NativeProfiler* sNativeProfiler; + static JS_FRIEND_DATA(NativeProfiler*) sNativeProfiler; static GCHeapProfiler* GetGCHeapProfiler(void* addr); static GCHeapProfiler* GetGCHeapProfiler(JSRuntime* runtime); @@ -2903,8 +2947,8 @@ public: explicit MemProfiler(JSRuntime* aRuntime) : mGCHeapProfiler(nullptr), mRuntime(aRuntime) {} - void start(GCHeapProfiler* aGCHeapProfiler); - void stop(); + JS_FRIEND_API(void) start(GCHeapProfiler* aGCHeapProfiler); + JS_FRIEND_API(void) stop(); GCHeapProfiler* getGCHeapProfiler() const { return mGCHeapProfiler; @@ -2914,7 +2958,7 @@ return sActiveProfilerCount > 0; } - static MemProfiler* GetMemProfiler(JSRuntime* runtime); + static JS_FRIEND_API(MemProfiler*) GetMemProfiler(JSContext* context); static void SetNativeProfiler(NativeProfiler* aProfiler) { sNativeProfiler = aProfiler; Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsperf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsperf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsperf.h @@ -126,7 +126,7 @@ * Value is not an instance of the wrapper. */ extern JS_FRIEND_API(PerfMeasurement*) - ExtractPerfMeasurement(Value wrapper); + ExtractPerfMeasurement(const Value& wrapper); } // namespace JS Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsprf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsprf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsprf.h @@ -14,34 +14,33 @@ ** %x - unsigned hex ** %X - unsigned uppercase hex ** %o - unsigned octal -** %hd, %hu, %hx, %hX, %ho - 16-bit versions of above -** %ld, %lu, %lx, %lX, %lo - 32-bit versions of above -** %lld, %llu, %llx, %llX, %llo - 64 bit versions of above -** %s - ascii string -** %hs - ucs2 string +** %hd, %hu, %hx, %hX, %ho - "short" versions of above +** %ld, %lu, %lx, %lX, %lo - "long" versions of above +** %lld, %llu, %llx, %llX, %llo - "long long" versions of above +** %zd, %zo, %zu, %zx, %zX - size_t versions of above +** %Id, %Io, %Iu, %Ix, %IX - size_t versions of above (for Windows compat) +** You should use PRI*SIZE macros instead +** %s - string ** %c - character ** %p - pointer (deals with machine dependent pointer size) ** %f - float ** %g - float */ +#include "mozilla/IntegerPrintfMacros.h" +#include "mozilla/SizePrintfMacros.h" + #include #include "jstypes.h" /* -** sprintf into a fixed size buffer. Guarantees that a NUL is at the end -** of the buffer. Returns the length of the written output, NOT including -** the NUL, or (uint32_t)-1 if an error occurs. -*/ -extern JS_PUBLIC_API(uint32_t) JS_snprintf(char* out, uint32_t outlen, const char* fmt, ...); - -/* ** sprintf into a malloc'd buffer. Return a pointer to the malloc'd ** buffer on success, nullptr on failure. Call "JS_smprintf_free" to release ** the memory returned. */ -extern JS_PUBLIC_API(char*) JS_smprintf(const char* fmt, ...); +extern JS_PUBLIC_API(char*) JS_smprintf(const char* fmt, ...) + MOZ_FORMAT_PRINTF(1, 2); /* ** Free the memory allocated, for the caller, by JS_smprintf @@ -55,12 +54,12 @@ ** will allocate the initial string. The return value is the new value of ** last for subsequent calls, or nullptr if there is a malloc failure. */ -extern JS_PUBLIC_API(char*) JS_sprintf_append(char* last, const char* fmt, ...); +extern JS_PUBLIC_API(char*) JS_sprintf_append(char* last, const char* fmt, ...) + MOZ_FORMAT_PRINTF(2, 3); /* ** va_list forms of the above. */ -extern JS_PUBLIC_API(uint32_t) JS_vsnprintf(char* out, uint32_t outlen, const char* fmt, va_list ap); extern JS_PUBLIC_API(char*) JS_vsmprintf(const char* fmt, va_list ap); extern JS_PUBLIC_API(char*) JS_vsprintf_append(char* last, const char* fmt, va_list ap); Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsprototypes.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsprototypes.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsprototypes.h @@ -49,12 +49,24 @@ #define IF_BDATA(real,imaginary) imaginary #endif +#ifdef ENABLE_SIMD +# define IF_SIMD(real,imaginary) real +#else +# define IF_SIMD(real,imaginary) imaginary +#endif + #ifdef ENABLE_SHARED_ARRAY_BUFFER #define IF_SAB(real,imaginary) real #else #define IF_SAB(real,imaginary) imaginary #endif +#ifdef SPIDERMONKEY_PROMISE +#define IF_PROMISE(real,imaginary) real +#else +#define IF_PROMISE(real,imaginary) imaginary +#endif + #define JS_FOR_PROTOTYPES(real,imaginary) \ imaginary(Null, 0, InitNullClass, dummy) \ real(Object, 1, InitViaClassSpec, OCLASP(Plain)) \ @@ -75,33 +87,42 @@ real(SyntaxError, 16, InitViaClassSpec, ERROR_CLASP(JSEXN_SYNTAXERR)) \ real(TypeError, 17, InitViaClassSpec, ERROR_CLASP(JSEXN_TYPEERR)) \ real(URIError, 18, InitViaClassSpec, ERROR_CLASP(JSEXN_URIERR)) \ - real(Iterator, 19, InitLegacyIteratorClass,OCLASP(PropertyIterator)) \ - real(StopIteration, 20, InitStopIterationClass, OCLASP(StopIteration)) \ - real(ArrayBuffer, 21, InitArrayBufferClass, &js::ArrayBufferObject::protoClass) \ - real(Int8Array, 22, InitViaClassSpec, TYPED_ARRAY_CLASP(Int8)) \ - real(Uint8Array, 23, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8)) \ - real(Int16Array, 24, InitViaClassSpec, TYPED_ARRAY_CLASP(Int16)) \ - real(Uint16Array, 25, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint16)) \ - real(Int32Array, 26, InitViaClassSpec, TYPED_ARRAY_CLASP(Int32)) \ - real(Uint32Array, 27, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint32)) \ - real(Float32Array, 28, InitViaClassSpec, TYPED_ARRAY_CLASP(Float32)) \ - real(Float64Array, 29, InitViaClassSpec, TYPED_ARRAY_CLASP(Float64)) \ - real(Uint8ClampedArray, 30, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8Clamped)) \ - real(Proxy, 31, InitProxyClass, js::ProxyClassPtr) \ - real(WeakMap, 32, InitWeakMapClass, OCLASP(WeakMap)) \ - real(Map, 33, InitMapClass, OCLASP(Map)) \ - real(Set, 34, InitSetClass, OCLASP(Set)) \ - real(DataView, 35, InitDataViewClass, OCLASP(DataView)) \ - real(Symbol, 36, InitSymbolClass, OCLASP(Symbol)) \ -IF_SAB(real,imaginary)(SharedArrayBuffer, 37, InitSharedArrayBufferClass, &js::SharedArrayBufferObject::protoClass) \ -IF_INTL(real,imaginary) (Intl, 38, InitIntlClass, CLASP(Intl)) \ -IF_BDATA(real,imaginary)(TypedObject, 39, InitTypedObjectModuleObject, OCLASP(TypedObjectModule)) \ - real(Reflect, 40, InitReflect, nullptr) \ -IF_BDATA(real,imaginary)(SIMD, 41, InitSIMDClass, OCLASP(SIMD)) \ - real(WeakSet, 42, InitWeakSetClass, OCLASP(WeakSet)) \ - real(TypedArray, 43, InitViaClassSpec, &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \ -IF_SAB(real,imaginary)(Atomics, 44, InitAtomicsClass, OCLASP(Atomics)) \ - real(SavedFrame, 45, InitViaClassSpec, &js::SavedFrame::class_) \ + real(DebuggeeWouldRun, 19, InitViaClassSpec, ERROR_CLASP(JSEXN_DEBUGGEEWOULDRUN)) \ + real(CompileError, 20, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMCOMPILEERROR)) \ + real(RuntimeError, 21, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMRUNTIMEERROR)) \ + real(Iterator, 22, InitLegacyIteratorClass,OCLASP(PropertyIterator)) \ + real(StopIteration, 23, InitStopIterationClass, OCLASP(StopIteration)) \ + real(ArrayBuffer, 24, InitViaClassSpec, OCLASP(ArrayBuffer)) \ + real(Int8Array, 25, InitViaClassSpec, TYPED_ARRAY_CLASP(Int8)) \ + real(Uint8Array, 26, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8)) \ + real(Int16Array, 27, InitViaClassSpec, TYPED_ARRAY_CLASP(Int16)) \ + real(Uint16Array, 28, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint16)) \ + real(Int32Array, 29, InitViaClassSpec, TYPED_ARRAY_CLASP(Int32)) \ + real(Uint32Array, 30, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint32)) \ + real(Float32Array, 31, InitViaClassSpec, TYPED_ARRAY_CLASP(Float32)) \ + real(Float64Array, 32, InitViaClassSpec, TYPED_ARRAY_CLASP(Float64)) \ + real(Uint8ClampedArray, 33, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8Clamped)) \ + real(Proxy, 34, InitProxyClass, js::ProxyClassPtr) \ + real(WeakMap, 35, InitWeakMapClass, OCLASP(WeakMap)) \ + real(Map, 36, InitMapClass, OCLASP(Map)) \ + real(Set, 37, InitSetClass, OCLASP(Set)) \ + real(DataView, 38, InitDataViewClass, OCLASP(DataView)) \ + real(Symbol, 39, InitSymbolClass, OCLASP(Symbol)) \ +IF_SAB(real,imaginary)(SharedArrayBuffer, 40, InitViaClassSpec, OCLASP(SharedArrayBuffer)) \ +IF_INTL(real,imaginary) (Intl, 41, InitIntlClass, CLASP(Intl)) \ +IF_BDATA(real,imaginary)(TypedObject, 42, InitTypedObjectModuleObject, OCLASP(TypedObjectModule)) \ + real(Reflect, 43, InitReflect, nullptr) \ +IF_SIMD(real,imaginary)(SIMD, 44, InitSimdClass, OCLASP(Simd)) \ + real(WeakSet, 45, InitWeakSetClass, OCLASP(WeakSet)) \ + real(TypedArray, 46, InitViaClassSpec, &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \ +IF_SAB(real,imaginary)(Atomics, 47, InitAtomicsClass, OCLASP(Atomics)) \ + real(SavedFrame, 48, InitViaClassSpec, &js::SavedFrame::class_) \ + real(WebAssembly, 49, InitWebAssemblyClass, CLASP(WebAssembly)) \ + imaginary(WasmModule, 50, dummy, dummy) \ + imaginary(WasmInstance, 51, dummy, dummy) \ + imaginary(WasmMemory, 52, dummy, dummy) \ + imaginary(WasmTable, 53, dummy, dummy) \ +IF_PROMISE(real,imaginary)(Promise, 54, InitViaClassSpec, OCLASP(Promise)) \ #define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro) Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/jspubtd.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/jspubtd.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/jspubtd.h @@ -12,12 +12,14 @@ */ #include "mozilla/Assertions.h" +#include "mozilla/EnumeratedArray.h" #include "mozilla/LinkedList.h" #include "mozilla/PodOperations.h" #include "jsprototypes.h" #include "jstypes.h" +#include "js/TraceKind.h" #include "js/TypeDecls.h" #if defined(JS_GC_ZEAL) || defined(DEBUG) @@ -26,9 +28,7 @@ namespace JS { -template -class AutoVectorRooter; -typedef AutoVectorRooter AutoIdVector; +class AutoIdVector; class CallArgs; template @@ -40,13 +40,17 @@ class JS_FRIEND_API(TransitiveCompileOptions); class JS_PUBLIC_API(CompartmentOptions); +struct RootingContext; class Value; struct Zone; -} /* namespace JS */ +namespace shadow { +struct Runtime; +} // namespace shadow + +} // namespace JS namespace js { -struct ContextFriendFields; class RootLists; } // namespace js @@ -97,7 +101,6 @@ struct JSLocaleCallbacks; struct JSObjectMap; struct JSPrincipals; -struct JSPropertyDescriptor; struct JSPropertyName; struct JSPropertySpec; struct JSRuntime; @@ -109,7 +112,6 @@ class JSFlatString; -typedef struct PRCallOnceType JSCallOnceType; typedef bool (*JSInitCallback)(void); template struct JSConstScalarSpec; @@ -117,60 +119,105 @@ typedef JSConstScalarSpec JSConstIntegerSpec; /* - * Generic trace operation that calls JS_CallTracer on each traceable thing - * stored in data. + * Generic trace operation that calls JS::TraceEdge on each traceable thing's + * location reachable from data. */ typedef void (* JSTraceDataOp)(JSTracer* trc, void* data); namespace js { - -void FinishGC(JSRuntime* rt); - namespace gc { class AutoTraceSession; class StoreBuffer; -void MarkPersistentRootedChains(JSTracer*); -void MarkPersistentRootedChainsInLists(js::RootLists&, JSTracer*); -void FinishPersistentRootedChains(js::RootLists&); } // namespace gc + +// Whether the current thread is permitted access to any part of the specified +// runtime or zone. +JS_FRIEND_API(bool) +CurrentThreadCanAccessRuntime(const JSRuntime* rt); + +#ifdef DEBUG +JS_FRIEND_API(bool) +CurrentThreadIsPerformingGC(); +#endif + } // namespace js namespace JS { +class JS_PUBLIC_API(AutoEnterCycleCollection); +class JS_PUBLIC_API(AutoAssertOnBarrier); +struct JS_PUBLIC_API(PropertyDescriptor); + typedef void (*OffThreadCompileCallback)(void* token, void* callbackData); enum class HeapState { Idle, // doing nothing with the GC heap Tracing, // tracing the GC heap without collecting, e.g. IterateCompartments() MajorCollecting, // doing a GC of the major heap - MinorCollecting // doing a GC of the minor heap (nursery) + MinorCollecting, // doing a GC of the minor heap (nursery) + CycleCollecting // in the "Unlink" phase of cycle collection }; namespace shadow { struct Runtime { - protected: - // Allow inlining of heapState checks. - friend class js::gc::AutoTraceSession; + private: JS::HeapState heapState_; + protected: + void setHeapState(JS::HeapState newState) { + MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(asRuntime())); + MOZ_ASSERT(heapState_ != newState); + heapState_ = newState; + } + + JS::HeapState heapState() const { + MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(asRuntime()) || + js::CurrentThreadIsPerformingGC()); + return heapState_; + } + + // In some cases, invoking GC barriers (incremental or otherwise) will break + // things. These barriers assert if this flag is set. + bool allowGCBarriers_; + friend class JS::AutoAssertOnBarrier; + js::gc::StoreBuffer* gcStoreBufferPtr_; + // The gray bits can become invalid if UnmarkGray overflows the stack. A + // full GC will reset this bit, since it fills in all the gray bits. + bool gcGrayBitsValid_; + public: Runtime() : heapState_(JS::HeapState::Idle) + , allowGCBarriers_(true) , gcStoreBufferPtr_(nullptr) + , gcGrayBitsValid_(false) {} - bool isHeapBusy() const { return heapState_ != JS::HeapState::Idle; } - bool isHeapMajorCollecting() const { return heapState_ == JS::HeapState::MajorCollecting; } - bool isHeapMinorCollecting() const { return heapState_ == JS::HeapState::MinorCollecting; } + bool isHeapBusy() const { return heapState() != JS::HeapState::Idle; } + bool isHeapTracing() const { return heapState() == JS::HeapState::Tracing; } + bool isHeapMajorCollecting() const { return heapState() == JS::HeapState::MajorCollecting; } + bool isHeapMinorCollecting() const { return heapState() == JS::HeapState::MinorCollecting; } bool isHeapCollecting() const { return isHeapMinorCollecting() || isHeapMajorCollecting(); } + bool isCycleCollecting() const { + return heapState() == JS::HeapState::CycleCollecting; + } + + bool allowGCBarriers() const { return allowGCBarriers_; } js::gc::StoreBuffer* gcStoreBufferPtr() { return gcStoreBufferPtr_; } + bool areGCGrayBitsValid() const { return gcGrayBitsValid_; } + void setGCGrayBitsValid(bool valid) { gcGrayBitsValid_ = valid; } + + const JSRuntime* asRuntime() const { + return reinterpret_cast(this); + } + static JS::shadow::Runtime* asShadowRuntime(JSRuntime* rt) { return reinterpret_cast(rt); } @@ -183,11 +230,28 @@ } /* namespace shadow */ +// Decorates the Unlinking phase of CycleCollection so that accidental use +// of barriered accessors results in assertions instead of leaks. +class MOZ_STACK_CLASS JS_PUBLIC_API(AutoEnterCycleCollection) +{ +#ifdef DEBUG + JSRuntime* runtime; + + public: + explicit AutoEnterCycleCollection(JSContext* cx); + ~AutoEnterCycleCollection(); +#else + public: + explicit AutoEnterCycleCollection(JSContext* cx) {} + ~AutoEnterCycleCollection() {} +#endif +}; + class JS_PUBLIC_API(AutoGCRooter) { public: AutoGCRooter(JSContext* cx, ptrdiff_t tag); - AutoGCRooter(js::ContextFriendFields* cx, ptrdiff_t tag); + AutoGCRooter(JS::RootingContext* cx, ptrdiff_t tag); ~AutoGCRooter() { MOZ_ASSERT(this == *stackTop); @@ -199,13 +263,6 @@ static void traceAll(JSTracer* trc); static void traceAllWrappers(JSTracer* trc); - /* T must be a context type */ - template - static void traceAllInContext(T* cx, JSTracer* trc) { - for (AutoGCRooter* gcr = cx->roots.autoGCRooters_; gcr; gcr = gcr->down) - gcr->trace(trc); - } - protected: AutoGCRooter * const down; @@ -242,6 +299,13 @@ void operator=(AutoGCRooter& ida) = delete; }; +// Our instantiations of Rooted and PersistentRooted require an +// instantiation of MapTypeToRootKind. +template <> +struct MapTypeToRootKind { + static const RootKind kind = RootKind::Traceable; +}; + } /* namespace JS */ namespace js { @@ -261,132 +325,98 @@ StackKindCount }; -enum ThingRootKind -{ - THING_ROOT_OBJECT, - THING_ROOT_SHAPE, - THING_ROOT_BASE_SHAPE, - THING_ROOT_OBJECT_GROUP, - THING_ROOT_STRING, - THING_ROOT_SYMBOL, - THING_ROOT_JIT_CODE, - THING_ROOT_SCRIPT, - THING_ROOT_LAZY_SCRIPT, - THING_ROOT_ID, - THING_ROOT_VALUE, - THING_ROOT_TRACEABLE, - THING_ROOT_LIMIT -}; - -template -struct RootKind; - -/* - * Specifically mark the ThingRootKind of externally visible types, so that - * JSAPI users may use JSRooted... types without having the class definition - * available. - */ -template -struct SpecificRootKind -{ - static ThingRootKind rootKind() { return Kind; } -}; - -template <> struct RootKind : SpecificRootKind {}; -template <> struct RootKind : SpecificRootKind {}; -template <> struct RootKind : SpecificRootKind {}; -template <> struct RootKind : SpecificRootKind {}; -template <> struct RootKind : SpecificRootKind {}; -template <> struct RootKind : SpecificRootKind {}; -template <> struct RootKind : SpecificRootKind {}; -template <> struct RootKind : SpecificRootKind {}; +using RootedListHeads = mozilla::EnumeratedArray*>; // Abstracts JS rooting mechanisms so they can be shared between the JSContext // and JSRuntime. class RootLists { - // Stack GC roots for stack-allocated GC heap pointers. - JS::Rooted* stackRoots_[THING_ROOT_LIMIT]; + // Stack GC roots for Rooted GC heap pointers. + RootedListHeads stackRoots_; template friend class JS::Rooted; - // Stack GC roots for stack-allocated AutoFooRooter classes. + // Stack GC roots for AutoFooRooter classes. JS::AutoGCRooter* autoGCRooters_; friend class JS::AutoGCRooter; + // Heap GC roots for PersistentRooted pointers. + mozilla::EnumeratedArray>> heapRoots_; + template friend class JS::PersistentRooted; + public: RootLists() : autoGCRooters_(nullptr) { - mozilla::PodArrayZero(stackRoots_); + for (auto& stackRootPtr : stackRoots_) + stackRootPtr = nullptr; } - template - inline JS::Rooted* gcRooters() { - js::ThingRootKind kind = RootKind::rootKind(); - return reinterpret_cast*>(stackRoots_[kind]); + ~RootLists() { + // The semantics of PersistentRooted containing pointers and tagged + // pointers are somewhat different from those of PersistentRooted + // containing a structure with a trace method. PersistentRooted + // containing pointers are allowed to outlive the owning RootLists, + // whereas those containing a traceable structure are not. + // + // The purpose of this feature is to support lazy initialization of + // global references for the several places in Gecko that do not have + // access to a tighter context, but that still need to refer to GC + // pointers. For such pointers, FinishPersistentRootedChains ensures + // that the contained references are nulled out when the owning + // RootLists dies to prevent UAF errors. + // + // However, for RootKind::Traceable, we do not know the concrete type + // of the held thing, so we simply cannot do this without accruing + // extra overhead and complexity for all users for a case that is + // unlikely to ever be used in practice. For this reason, the following + // assertion disallows usage of PersistentRooted that + // outlives the RootLists. + MOZ_ASSERT(heapRoots_[JS::RootKind::Traceable].isEmpty()); } + void traceStackRoots(JSTracer* trc); void checkNoGCRooters(); - /* Allow inlining of PersistentRooted constructors and destructors. */ - private: - template friend class JS::PersistentRooted; - friend void js::gc::MarkPersistentRootedChains(JSTracer*); - friend void js::gc::MarkPersistentRootedChainsInLists(RootLists&, JSTracer*); - friend void js::gc::FinishPersistentRootedChains(RootLists&); - - mozilla::LinkedList> heapRoots_[THING_ROOT_LIMIT]; - - /* Specializations of this return references to the appropriate list. */ - template - inline mozilla::LinkedList>& getPersistentRootedList(); -}; - -template<> -inline mozilla::LinkedList& -RootLists::getPersistentRootedList() { - return reinterpret_cast>&>( - heapRoots_[THING_ROOT_OBJECT]); -} + void tracePersistentRoots(JSTracer* trc); + void finishPersistentRoots(); +}; -template<> -inline mozilla::LinkedList& -RootLists::getPersistentRootedList() { - return reinterpret_cast>&>( - heapRoots_[THING_ROOT_OBJECT]); -} +} // namespace js -template<> -inline mozilla::LinkedList& -RootLists::getPersistentRootedList() { - return reinterpret_cast>&>( - heapRoots_[THING_ROOT_ID]); -} +namespace JS { -template<> -inline mozilla::LinkedList& -RootLists::getPersistentRootedList() { - return reinterpret_cast>&>( - heapRoots_[THING_ROOT_SCRIPT]); -} +/* + * JS::RootingContext is a base class of ContextFriendFields and JSContext. + * This class can be used to let code construct a Rooted<> or PersistentRooted<> + * instance, without giving it full access to the JSContext. + */ +struct RootingContext +{ + js::RootLists roots; -template<> -inline mozilla::LinkedList& -RootLists::getPersistentRootedList() { - return reinterpret_cast>&>( - heapRoots_[THING_ROOT_STRING]); -} +#ifdef DEBUG + // Whether the derived class is a JSContext or an ExclusiveContext. + bool isJSContext; +#endif -template<> -inline mozilla::LinkedList& -RootLists::getPersistentRootedList() { - return reinterpret_cast>&>( - heapRoots_[THING_ROOT_VALUE]); -} + explicit RootingContext(bool isJSContextArg) +#ifdef DEBUG + : isJSContext(isJSContextArg) +#endif + {} -struct ContextFriendFields + static RootingContext* get(JSContext* cx) { + return reinterpret_cast(cx); + } +}; + +} // namespace JS + +namespace js { + +struct ContextFriendFields : public JS::RootingContext { protected: - JSRuntime* const runtime_; - /* The current compartment. */ JSCompartment* compartment_; @@ -394,12 +424,10 @@ JS::Zone* zone_; public: - /* Rooting structures. */ - RootLists roots; + /* Limit pointer for checking native stack consumption. */ + uintptr_t nativeStackLimit[js::StackKindCount]; - explicit ContextFriendFields(JSRuntime* rt) - : runtime_(rt), compartment_(nullptr), zone_(nullptr) - {} + explicit ContextFriendFields(bool isJSContext); static const ContextFriendFields* get(const JSContext* cx) { return reinterpret_cast(cx); @@ -409,7 +437,6 @@ return reinterpret_cast(cx); } - friend JSRuntime* GetRuntime(const JSContext* cx); friend JSCompartment* GetContextCompartment(const JSContext* cx); friend JS::Zone* GetContextZone(const JSContext* cx); template friend class JS::Rooted; @@ -425,12 +452,6 @@ * usable without resorting to jsfriendapi.h, and when JSContext is an * incomplete type. */ -inline JSRuntime* -GetRuntime(const JSContext* cx) -{ - return ContextFriendFields::get(cx)->runtime_; -} - inline JSCompartment* GetContextCompartment(const JSContext* cx) { @@ -443,57 +464,13 @@ return ContextFriendFields::get(cx)->zone_; } -class PerThreadData; - -struct PerThreadDataFriendFields -{ - private: - // Note: this type only exists to permit us to derive the offset of - // the perThread data within the real JSRuntime* type in a portable - // way. - struct RuntimeDummy : JS::shadow::Runtime - { - struct PerThreadDummy { - void* field1; - uintptr_t field2; -#ifdef JS_DEBUG - uint64_t field3; -#endif - } mainThread; - }; - - public: - /* Rooting structures. */ - RootLists roots; - - PerThreadDataFriendFields(); - - /* Limit pointer for checking native stack consumption. */ - uintptr_t nativeStackLimit[js::StackKindCount]; - - static const size_t RuntimeMainThreadOffset = offsetof(RuntimeDummy, mainThread); - - static inline PerThreadDataFriendFields* get(js::PerThreadData* pt) { - return reinterpret_cast(pt); - } - - static inline PerThreadDataFriendFields* getMainThread(JSRuntime* rt) { - // mainThread must always appear directly after |JS::shadow::Runtime|. - // Tested by a JS_STATIC_ASSERT in |jsfriendapi.cpp| - return reinterpret_cast( - reinterpret_cast(rt) + RuntimeMainThreadOffset); - } +} /* namespace js */ - static inline const PerThreadDataFriendFields* getMainThread(const JSRuntime* rt) { - // mainThread must always appear directly after |JS::shadow::Runtime|. - // Tested by a JS_STATIC_ASSERT in |jsfriendapi.cpp| - return reinterpret_cast( - reinterpret_cast(rt) + RuntimeMainThreadOffset); - } +MOZ_BEGIN_EXTERN_C - template friend class JS::Rooted; -}; +// Defined in NSPR prio.h. +typedef struct PRFileDesc PRFileDesc; -} /* namespace js */ +MOZ_END_EXTERN_C #endif /* jspubtd_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/jstypes.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/jstypes.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/jstypes.h @@ -70,18 +70,16 @@ #if defined(STATIC_JS_API) # define JS_PUBLIC_API(t) t # define JS_PUBLIC_DATA(t) t +# define JS_FRIEND_API(t) t +# define JS_FRIEND_DATA(t) t #elif defined(EXPORT_JS_API) || defined(STATIC_EXPORTABLE_JS_API) # define JS_PUBLIC_API(t) MOZ_EXPORT t # define JS_PUBLIC_DATA(t) MOZ_EXPORT t -#else -# define JS_PUBLIC_API(t) MOZ_IMPORT_API t -# define JS_PUBLIC_DATA(t) MOZ_IMPORT_DATA t -#endif - -#if defined(STATIC_JS_API) || defined(EXPORT_JS_API) || defined(STATIC_EXPORTABLE_JS_API) # define JS_FRIEND_API(t) MOZ_EXPORT t # define JS_FRIEND_DATA(t) MOZ_EXPORT t #else +# define JS_PUBLIC_API(t) MOZ_IMPORT_API t +# define JS_PUBLIC_DATA(t) MOZ_IMPORT_DATA t # define JS_FRIEND_API(t) MOZ_IMPORT_API t # define JS_FRIEND_DATA(t) MOZ_IMPORT_DATA t #endif @@ -95,6 +93,14 @@ #define JS_NO_FASTCALL #endif +// gcc is buggy and warns on our attempts to JS_PUBLIC_API our +// forward-declarations or explicit template instantiations. See +// . Add a way to detect +// that so we can locally disable that warning. +#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 6 || (__GNUC__ == 6 && __GNUC_MINOR__ <= 4)) +#define JS_BROKEN_GCC_ATTRIBUTE_WARNING +#endif + /*********************************************************************** ** MACROS: JS_BEGIN_MACRO ** JS_END_MACRO Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsversion.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsversion.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsversion.h @@ -22,7 +22,7 @@ #define JS_HAS_GENERATORS 1 /* (no longer used) */ #define JS_HAS_BLOCK_SCOPE 1 /* (no longer used) */ #define JS_HAS_DESTRUCTURING 2 /* (no longer used) */ -#define JS_HAS_GENERATOR_EXPRS 1 /* has (expr for (lhs in iterable)) */ +#define JS_HAS_GENERATOR_EXPRS 1 /* (no longer used) */ #define JS_HAS_EXPR_CLOSURES 1 /* has function (formals) listexpr */ /* (no longer used) */ @@ -37,11 +37,4 @@ */ #define JS_OLD_GETTER_SETTER_METHODS 1 -#ifdef NIGHTLY_BUILD - -/* Support for ES7 Exponentiation proposal. */ -#define JS_HAS_EXPONENTIATION 1 - -#endif // NIGHTLY_BUILD - #endif /* jsversion_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/jswrapper.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/jswrapper.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/jswrapper.h @@ -44,19 +44,88 @@ /* * A wrapper is a proxy with a target object to which it generally forwards - * operations, but may restrict access to certain operations or instrument the - * methods in various ways. A wrapper is distinct from a Direct Proxy Handler - * in the sense that it can be "unwrapped" in C++, exposing the underlying - * object (Direct Proxy Handlers have an underlying target object, but don't - * expect to expose this object via any kind of unwrapping operation). Callers - * should be careful to avoid unwrapping security wrappers in the wrong + * operations, but may restrict access to certain operations or augment those + * operations in various ways. + * + * A wrapper can be "unwrapped" in C++, exposing the underlying object. + * Callers should be careful to avoid unwrapping security wrappers in the wrong * context. + * + * Important: If you add a method implementation here, you probably also need + * to add an override in CrossCompartmentWrapper. If you don't, you risk + * compartment mismatches. See bug 945826 comment 0. */ -class JS_FRIEND_API(Wrapper) : public DirectProxyHandler +class JS_FRIEND_API(Wrapper) : public BaseProxyHandler { unsigned mFlags; public: + explicit constexpr Wrapper(unsigned aFlags, bool aHasPrototype = false, + bool aHasSecurityPolicy = false) + : BaseProxyHandler(&family, aHasPrototype, aHasSecurityPolicy), + mFlags(aFlags) + { } + + virtual bool finalizeInBackground(const Value& priv) const override; + + /* Standard internal methods. */ + virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, + MutableHandle desc) const override; + virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, + Handle desc, + ObjectOpResult& result) const override; + virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy, + AutoIdVector& props) const override; + virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id, + ObjectOpResult& result) const override; + virtual bool enumerate(JSContext* cx, HandleObject proxy, + MutableHandleObject objp) const override; + virtual bool getPrototype(JSContext* cx, HandleObject proxy, + MutableHandleObject protop) const override; + virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, + ObjectOpResult& result) const override; + virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const override; + virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, + bool* succeeded) const override; + virtual bool preventExtensions(JSContext* cx, HandleObject proxy, + ObjectOpResult& result) const override; + virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override; + virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, + bool* bp) const override; + virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, + HandleId id, MutableHandleValue vp) const override; + virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, + HandleValue receiver, ObjectOpResult& result) const override; + virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const override; + virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override; + + /* SpiderMonkey extensions. */ + virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, + MutableHandle desc) const override; + virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, + bool* bp) const override; + virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, + AutoIdVector& props) const override; + virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, + const CallArgs& args) const override; + virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, + bool* bp) const override; + virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override; + virtual bool isArray(JSContext* cx, HandleObject proxy, + JS::IsArrayAnswer* answer) const override; + virtual const char* className(JSContext* cx, HandleObject proxy) const override; + virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, + unsigned indent) const override; + virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, + RegExpGuard* g) const override; + virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, + MutableHandleValue vp) const override; + virtual bool isCallable(JSObject* obj) const override; + virtual bool isConstructor(JSObject* obj) const override; + virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const override; + + public: using BaseProxyHandler::Action; enum Flags { @@ -77,15 +146,6 @@ return mFlags; } - explicit MOZ_CONSTEXPR Wrapper(unsigned aFlags, bool aHasPrototype = false, - bool aHasSecurityPolicy = false) - : DirectProxyHandler(&family, aHasPrototype, aHasSecurityPolicy), - mFlags(aFlags) - { } - - virtual bool finalizeInBackground(Value priv) const override; - virtual bool isConstructor(JSObject* obj) const override; - static const char family; static const Wrapper singleton; static const Wrapper singletonWithPrototype; @@ -103,16 +163,16 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper { public: - explicit MOZ_CONSTEXPR CrossCompartmentWrapper(unsigned aFlags, bool aHasPrototype = false, + explicit constexpr CrossCompartmentWrapper(unsigned aFlags, bool aHasPrototype = false, bool aHasSecurityPolicy = false) : Wrapper(CROSS_COMPARTMENT | aFlags, aHasPrototype, aHasSecurityPolicy) { } /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const override; virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper, AutoIdVector& props) const override; @@ -124,6 +184,8 @@ virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result) const override; + virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const override; virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const override; virtual bool preventExtensions(JSContext* cx, HandleObject wrapper, @@ -139,7 +201,7 @@ /* SpiderMonkey extensions. */ virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override; virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper, AutoIdVector& props) const override; @@ -153,6 +215,9 @@ virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const override; virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override; + // Allocate CrossCompartmentWrappers in the nursery. + virtual bool canNurseryAllocate() const override { return true; } + static const CrossCompartmentWrapper singleton; static const CrossCompartmentWrapper singletonWithPrototype; }; @@ -160,14 +225,14 @@ class JS_FRIEND_API(OpaqueCrossCompartmentWrapper) : public CrossCompartmentWrapper { public: - explicit MOZ_CONSTEXPR OpaqueCrossCompartmentWrapper() : CrossCompartmentWrapper(0) + explicit constexpr OpaqueCrossCompartmentWrapper() : CrossCompartmentWrapper(0) { } /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const override; virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper, AutoIdVector& props) const override; @@ -179,6 +244,8 @@ MutableHandleObject protop) const override; virtual bool setPrototype(JSContext* cx, HandleObject wrapper, HandleObject proto, ObjectOpResult& result) const override; + virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject wrapper, bool* isOrdinary, + MutableHandleObject protop) const override; virtual bool setImmutablePrototype(JSContext* cx, HandleObject wrapper, bool* succeeded) const override; virtual bool preventExtensions(JSContext* cx, HandleObject wrapper, @@ -195,13 +262,12 @@ /* SpiderMonkey extensions. */ virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override; virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper, AutoIdVector& props) const override; - virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, - ESClassValue* classValue) const override; + virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override; virtual bool isArray(JSContext* cx, HandleObject obj, JS::IsArrayAnswer* answer) const override; virtual const char* className(JSContext* cx, HandleObject wrapper) const override; @@ -223,7 +289,7 @@ class JS_FRIEND_API(SecurityWrapper) : public Base { public: - explicit MOZ_CONSTEXPR SecurityWrapper(unsigned flags, bool hasPrototype = false) + explicit constexpr SecurityWrapper(unsigned flags, bool hasPrototype = false) : Base(flags, hasPrototype, /* hasSecurityPolicy = */ true) { } @@ -231,7 +297,7 @@ bool* bp) const override; virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const override; virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override; virtual bool preventExtensions(JSContext* cx, HandleObject wrapper, @@ -242,8 +308,7 @@ virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, const CallArgs& args) const override; - virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, - ESClassValue* classValue) const override; + virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override; virtual bool isArray(JSContext* cx, HandleObject wrapper, JS::IsArrayAnswer* answer) const override; virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const override; virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override; @@ -263,7 +328,6 @@ typedef SecurityWrapper Restrictive; }; -typedef SecurityWrapper SameCompartmentSecurityWrapper; typedef SecurityWrapper CrossCompartmentSecurityWrapper; extern JSObject* @@ -297,10 +361,10 @@ JS_FRIEND_API(bool) IsCrossCompartmentWrapper(JSObject* obj); -void +JS_FRIEND_API(void) NukeCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper); -bool +void RemapWrapper(JSContext* cx, JSObject* wobj, JSObject* newTarget); JS_FRIEND_API(bool) Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Alignment.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Alignment.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Alignment.h @@ -120,6 +120,13 @@ const void* addr() const { return u.mBytes; } void* addr() { return u.mBytes; } + + AlignedStorage() = default; + + // AlignedStorage is non-copyable: the default copy constructor violates + // strict aliasing rules, per bug 1269319. + AlignedStorage(const AlignedStorage&) = delete; + void operator=(const AlignedStorage&) = delete; }; template @@ -133,6 +140,13 @@ const T* addr() const { return reinterpret_cast(u.mBytes); } T* addr() { return static_cast(static_cast(u.mBytes)); } + + AlignedStorage2() = default; + + // AlignedStorage2 is non-copyable: the default copy constructor violates + // strict aliasing rules, per bug 1269319. + AlignedStorage2(const AlignedStorage2&) = delete; + void operator=(const AlignedStorage2&) = delete; }; } /* namespace mozilla */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/AllocPolicy.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/AllocPolicy.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/AllocPolicy.h @@ -12,6 +12,7 @@ #ifndef mozilla_AllocPolicy_h #define mozilla_AllocPolicy_h +#include "mozilla/Attributes.h" #include "mozilla/TemplateLib.h" #include @@ -121,7 +122,7 @@ { } - bool checkSimulatedOOM() const + MOZ_MUST_USE bool checkSimulatedOOM() const { return true; } Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/AlreadyAddRefed.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/AlreadyAddRefed.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/AlreadyAddRefed.h @@ -29,7 +29,7 @@ * because of the sheer number of usages of already_AddRefed. */ template -struct MOZ_MUST_USE MOZ_NON_AUTOABLE already_AddRefed +struct MOZ_MUST_USE_TYPE MOZ_NON_AUTOABLE already_AddRefed { /* * We want to allow returning nullptr from functions returning @@ -111,7 +111,7 @@ aUnused << mutableAlreadyAddRefed->take(); } - MOZ_WARN_UNUSED_RESULT T* take() + MOZ_MUST_USE T* take() { T* rawPtr = mRawPtr; mRawPtr = nullptr; Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Array.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Array.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Array.h @@ -11,6 +11,7 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" +#include "mozilla/Move.h" #include "mozilla/ReverseIterator.h" #include @@ -23,6 +24,16 @@ T mArr[Length]; public: + Array() {} + + template + MOZ_IMPLICIT Array(Args&&... aArgs) + : mArr{mozilla::Forward(aArgs)...} + { + static_assert(sizeof...(aArgs) == Length, + "The number of arguments should be equal to the template parameter Length"); + } + T& operator[](size_t aIndex) { MOZ_ASSERT(aIndex < Length); Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ArrayUtils.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ArrayUtils.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ArrayUtils.h @@ -52,21 +52,21 @@ * Beware of the implicit trailing '\0' when using this with string constants. */ template -MOZ_CONSTEXPR size_t +constexpr size_t ArrayLength(T (&aArr)[N]) { return N; } template -MOZ_CONSTEXPR size_t +constexpr size_t ArrayLength(const Array& aArr) { return N; } template -MOZ_CONSTEXPR size_t +constexpr size_t ArrayLength(const EnumeratedArray& aArr) { return size_t(N); @@ -78,21 +78,21 @@ * Beware of the implicit trailing '\0' when using this with string constants. */ template -MOZ_CONSTEXPR T* +constexpr T* ArrayEnd(T (&aArr)[N]) { return aArr + ArrayLength(aArr); } template -MOZ_CONSTEXPR T* +constexpr T* ArrayEnd(Array& aArr) { return &aArr[0] + ArrayLength(aArr); } template -MOZ_CONSTEXPR const T* +constexpr const T* ArrayEnd(const Array& aArr) { return &aArr[0] + ArrayLength(aArr); Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Assertions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Assertions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Assertions.h @@ -17,23 +17,29 @@ #include "mozilla/Compiler.h" #include "mozilla/Likely.h" #include "mozilla/MacroArgs.h" +#include "mozilla/StaticAnalysisFunctions.h" +#include "mozilla/Types.h" #ifdef MOZ_DUMP_ASSERTION_STACK #include "nsTraceRefcnt.h" #endif -#if defined(MOZ_CRASHREPORTER) && defined(MOZILLA_INTERNAL_API) && \ - !defined(MOZILLA_EXTERNAL_LINKAGE) && defined(__cplusplus) -namespace CrashReporter { -// This declaration is present here as well as in nsExceptionHandler.h -// nsExceptionHandler.h is not directly included in this file as it includes -// windows.h, which can cause problems when it is imported into some files due -// to the number of macros defined. -// XXX If you change this definition - also change the definition in -// nsExceptionHandler.h -void AnnotateMozCrashReason(const char* aReason); -} // namespace CrashReporter +#if defined(MOZ_HAS_MOZGLUE) || defined(MOZILLA_INTERNAL_API) +/* + * The crash reason set by MOZ_CRASH_ANNOTATE is consumed by the crash reporter + * if present. It is declared here (and defined in Assertions.cpp) to make it + * available to all code, even libraries that don't link with the crash reporter + * directly. + */ +MOZ_BEGIN_EXTERN_C +extern MFBT_DATA const char* gMozCrashReason; +MOZ_END_EXTERN_C -# define MOZ_CRASH_ANNOTATE(...) CrashReporter::AnnotateMozCrashReason("" __VA_ARGS__) +static inline void +AnnotateMozCrashReason(const char* reason) +{ + gMozCrashReason = reason; +} +# define MOZ_CRASH_ANNOTATE(...) AnnotateMozCrashReason(__VA_ARGS__) #else # define MOZ_CRASH_ANNOTATE(...) do { /* nothing */ } while (0) #endif @@ -158,7 +164,7 @@ aStr, aFilename, aLine); #else fprintf(stderr, "Assertion failure: %s, at %s:%d\n", aStr, aFilename, aLine); -#if defined (MOZ_DUMP_ASSERTION_STACK) && !defined(MOZILLA_XPCOMRT_API) +#if defined (MOZ_DUMP_ASSERTION_STACK) nsTraceRefcnt::WalkTheStack(stderr); #endif fflush(stderr); @@ -174,7 +180,7 @@ "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine); #else fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine); -#if defined(MOZ_DUMP_ASSERTION_STACK) && !defined(MOZILLA_XPCOMRT_API) +#if defined(MOZ_DUMP_ASSERTION_STACK) nsTraceRefcnt::WalkTheStack(stderr); #endif fflush(stderr); @@ -212,33 +218,33 @@ __declspec(noreturn) __inline void MOZ_NoReturn() {} # ifdef __cplusplus -# define MOZ_REALLY_CRASH() \ +# define MOZ_REALLY_CRASH(line) \ do { \ ::__debugbreak(); \ - *((volatile int*) NULL) = __LINE__; \ + *((volatile int*) NULL) = line; \ ::TerminateProcess(::GetCurrentProcess(), 3); \ ::MOZ_NoReturn(); \ } while (0) # else -# define MOZ_REALLY_CRASH() \ +# define MOZ_REALLY_CRASH(line) \ do { \ __debugbreak(); \ - *((volatile int*) NULL) = __LINE__; \ + *((volatile int*) NULL) = line; \ TerminateProcess(GetCurrentProcess(), 3); \ MOZ_NoReturn(); \ } while (0) # endif #else # ifdef __cplusplus -# define MOZ_REALLY_CRASH() \ +# define MOZ_REALLY_CRASH(line) \ do { \ - *((volatile int*) NULL) = __LINE__; \ + *((volatile int*) NULL) = line; \ ::abort(); \ } while (0) # else -# define MOZ_REALLY_CRASH() \ +# define MOZ_REALLY_CRASH(line) \ do { \ - *((volatile int*) NULL) = __LINE__; \ + *((volatile int*) NULL) = line; \ abort(); \ } while (0) # endif @@ -269,17 +275,69 @@ # define MOZ_CRASH(...) \ do { \ MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \ - MOZ_REALLY_CRASH(); \ + MOZ_REALLY_CRASH(__LINE__); \ } while (0) #else # define MOZ_CRASH(...) \ do { \ MOZ_ReportCrash("" __VA_ARGS__, __FILE__, __LINE__); \ MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \ - MOZ_REALLY_CRASH(); \ + MOZ_REALLY_CRASH(__LINE__); \ } while (0) #endif +/* + * MOZ_CRASH_UNSAFE_OOL(explanation-string) can be used if the explanation + * string cannot be a string literal (but no other processing needs to be done + * on it). A regular MOZ_CRASH() is preferred wherever possible, as passing + * arbitrary strings from a potentially compromised process is not without risk. + * If the string being passed is the result of a printf-style function, + * consider using MOZ_CRASH_UNSAFE_PRINTF instead. + */ +#ifndef DEBUG +MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void +MOZ_CrashOOL(int aLine, const char* aReason); +# define MOZ_CRASH_UNSAFE_OOL(reason) MOZ_CrashOOL(__LINE__, reason) +#else +MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void +MOZ_CrashOOL(const char* aFilename, int aLine, const char* aReason); +# define MOZ_CRASH_UNSAFE_OOL(reason) MOZ_CrashOOL(__FILE__, __LINE__, reason) +#endif + +static const size_t sPrintfMaxArgs = 4; +static const size_t sPrintfCrashReasonSize = 1024; + +#ifndef DEBUG +MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE MOZ_FORMAT_PRINTF(2, 3) void +MOZ_CrashPrintf(int aLine, const char* aFormat, ...); +# define MOZ_CALL_CRASH_PRINTF(format, ...) \ + MOZ_CrashPrintf(__LINE__, format, __VA_ARGS__) +#else +MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE MOZ_FORMAT_PRINTF(3, 4) void +MOZ_CrashPrintf(const char* aFilename, int aLine, const char* aFormat, ...); +# define MOZ_CALL_CRASH_PRINTF(format, ...) \ + MOZ_CrashPrintf(__FILE__, __LINE__, format, __VA_ARGS__) +#endif + +/* + * MOZ_CRASH_UNSAFE_PRINTF(format, arg1 [, args]) can be used when more + * information is desired than a string literal can supply. The caller provides + * a printf-style format string, which must be a string literal and between + * 1 and 4 additional arguments. A regular MOZ_CRASH() is preferred wherever + * possible, as passing arbitrary strings to printf from a potentially + * compromised process is not without risk. + */ +#define MOZ_CRASH_UNSAFE_PRINTF(format, ...) \ + do { \ + MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \ + static_assert( \ + MOZ_PASTE_PREFIX_AND_ARG_COUNT(, __VA_ARGS__) <= sPrintfMaxArgs, \ + "Only up to 4 additional arguments are allowed!"); \ + static_assert(sizeof(format) <= sPrintfCrashReasonSize, \ + "The supplied format string is too long!"); \ + MOZ_CALL_CRASH_PRINTF("" format, __VA_ARGS__); \ + } while (0) + #ifdef __cplusplus } /* extern "C" */ #endif @@ -368,20 +426,20 @@ #define MOZ_ASSERT_HELPER1(expr) \ do { \ MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ - if (MOZ_UNLIKELY(!(expr))) { \ + if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \ MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ")"); \ - MOZ_REALLY_CRASH(); \ + MOZ_REALLY_CRASH(__LINE__); \ } \ } while (0) /* Now the two-argument form. */ #define MOZ_ASSERT_HELPER2(expr, explain) \ do { \ MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ - if (MOZ_UNLIKELY(!(expr))) { \ + if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \ MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ") (" explain ")"); \ - MOZ_REALLY_CRASH(); \ + MOZ_REALLY_CRASH(__LINE__); \ } \ } while (0) @@ -397,7 +455,7 @@ # define MOZ_ASSERT(...) do { } while (0) #endif /* DEBUG */ -#ifdef RELEASE_BUILD +#ifdef RELEASE_OR_BETA # define MOZ_DIAGNOSTIC_ASSERT MOZ_ASSERT #else # define MOZ_DIAGNOSTIC_ASSERT MOZ_RELEASE_ASSERT @@ -496,6 +554,45 @@ MOZ_ASSUME_UNREACHABLE_MARKER(); \ } while (0) +/** + * MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about + * switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in + * debug builds, but intentionally fall through in release builds to handle + * unexpected values. + * + * Why do we need MOZ_FALLTHROUGH_ASSERT in addition to MOZ_FALLTHROUGH? In + * release builds, the MOZ_ASSERT(false) will expand to `do { } while (0)`, + * requiring a MOZ_FALLTHROUGH annotation to suppress a -Wimplicit-fallthrough + * warning. In debug builds, the MOZ_ASSERT(false) will expand to something like + * `if (true) { MOZ_CRASH(); }` and the MOZ_FALLTHROUGH annotation will cause + * a -Wunreachable-code warning. The MOZ_FALLTHROUGH_ASSERT macro breaks this + * warning stalemate. + * + * // Example before MOZ_FALLTHROUGH_ASSERT: + * switch (foo) { + * default: + * // This case wants to assert in debug builds, fall through in release. + * MOZ_ASSERT(false); // -Wimplicit-fallthrough warning in release builds! + * MOZ_FALLTHROUGH; // but -Wunreachable-code warning in debug builds! + * case 5: + * return 5; + * } + * + * // Example with MOZ_FALLTHROUGH_ASSERT: + * switch (foo) { + * default: + * // This case asserts in debug builds, falls through in release. + * MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!"); + * case 5: + * return 5; + * } + */ +#ifdef DEBUG +# define MOZ_FALLTHROUGH_ASSERT(reason) MOZ_CRASH("MOZ_FALLTHROUGH_ASSERT: " reason) +#else +# define MOZ_FALLTHROUGH_ASSERT(...) MOZ_FALLTHROUGH +#endif + /* * MOZ_ALWAYS_TRUE(expr) and MOZ_ALWAYS_FALSE(expr) always evaluate the provided * expression, in debug builds and in release builds both. Then, in debug @@ -503,21 +600,35 @@ * using MOZ_ASSERT. */ #ifdef DEBUG -# define MOZ_ALWAYS_TRUE(expr) MOZ_ASSERT((expr)) -# define MOZ_ALWAYS_FALSE(expr) MOZ_ASSERT(!(expr)) +# define MOZ_ALWAYS_TRUE(expr) \ + do { \ + if ((expr)) { \ + /* Do nothing. */ \ + } else { \ + MOZ_ASSERT(false, #expr); \ + } \ + } while (0) +# define MOZ_ALWAYS_FALSE(expr) \ + do { \ + if ((expr)) { \ + MOZ_ASSERT(false, #expr); \ + } else { \ + /* Do nothing. */ \ + } \ + } while (0) #else # define MOZ_ALWAYS_TRUE(expr) \ - do { \ - if ( ( expr ) ) { \ - /* Silence MOZ_WARN_UNUSED_RESULT. */ \ - } \ - } while (0) + do { \ + if ((expr)) { \ + /* Silence MOZ_MUST_USE. */ \ + } \ + } while (0) # define MOZ_ALWAYS_FALSE(expr) \ - do { \ - if ( ( expr ) ) { \ - /* Silence MOZ_WARN_UNUSED_RESULT. */ \ - } \ - } while (0) + do { \ + if ((expr)) { \ + /* Silence MOZ_MUST_USE. */ \ + } \ + } while (0) #endif #undef MOZ_DUMP_ASSERTION_STACK Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Atomics.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Atomics.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Atomics.h @@ -323,7 +323,7 @@ template struct ToStorageTypeArgument { - static T convert (T aT) { return aT; } + static constexpr T convert (T aT) { return aT; } }; } // namespace detail @@ -514,13 +514,13 @@ { typedef typename AtomicStorageType::Type ResultType; - static ResultType convert (T aT) { return ResultType(aT); } + static constexpr ResultType convert (T aT) { return ResultType(aT); } }; template struct ToStorageTypeArgument { - static T convert (T aT) { return aT; } + static constexpr T convert (T aT) { return aT; } }; } // namespace detail @@ -546,8 +546,8 @@ ValueType mValue; public: - MOZ_CONSTEXPR AtomicBase() : mValue() {} - explicit MOZ_CONSTEXPR AtomicBase(T aInit) + constexpr AtomicBase() : mValue() {} + explicit constexpr AtomicBase(T aInit) : mValue(ToStorageTypeArgument::convert(aInit)) {} @@ -598,8 +598,8 @@ typedef typename detail::AtomicBase Base; public: - MOZ_CONSTEXPR AtomicBaseIncDec() : Base() {} - explicit MOZ_CONSTEXPR AtomicBaseIncDec(T aInit) : Base(aInit) {} + constexpr AtomicBaseIncDec() : Base() {} + explicit constexpr AtomicBaseIncDec(T aInit) : Base(aInit) {} using Base::operator=; @@ -654,8 +654,8 @@ typedef typename detail::AtomicBaseIncDec Base; public: - MOZ_CONSTEXPR Atomic() : Base() {} - explicit MOZ_CONSTEXPR Atomic(T aInit) : Base(aInit) {} + constexpr Atomic() : Base() {} + explicit constexpr Atomic(T aInit) : Base(aInit) {} using Base::operator=; @@ -702,8 +702,8 @@ typedef typename detail::AtomicBaseIncDec Base; public: - MOZ_CONSTEXPR Atomic() : Base() {} - explicit MOZ_CONSTEXPR Atomic(T* aInit) : Base(aInit) {} + constexpr Atomic() : Base() {} + explicit constexpr Atomic(T* aInit) : Base(aInit) {} using Base::operator=; @@ -733,8 +733,8 @@ typedef typename detail::AtomicBase Base; public: - MOZ_CONSTEXPR Atomic() : Base() {} - explicit MOZ_CONSTEXPR Atomic(T aInit) : Base(aInit) {} + constexpr Atomic() : Base() {} + explicit constexpr Atomic(T aInit) : Base(aInit) {} operator T() const { return T(Base::Intrinsics::load(Base::mValue)); } @@ -767,8 +767,8 @@ typedef typename detail::AtomicBase Base; public: - MOZ_CONSTEXPR Atomic() : Base() {} - explicit MOZ_CONSTEXPR Atomic(bool aInit) : Base(aInit) {} + constexpr Atomic() : Base() {} + explicit constexpr Atomic(bool aInit) : Base(aInit) {} // We provide boolean wrappers for the underlying AtomicBase methods. MOZ_IMPLICIT operator bool() const Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Attributes.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Attributes.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Attributes.h @@ -45,27 +45,9 @@ * standardly, by checking whether __cplusplus has a C++11 or greater value. * Current versions of g++ do not correctly set __cplusplus, so we check both * for forward compatibility. - * - * Even though some versions of MSVC support explicit conversion operators, we - * don't indicate support for them here, due to - * http://stackoverflow.com/questions/20498142/visual-studio-2013-explicit-keyword-bug */ # define MOZ_HAVE_NEVER_INLINE __declspec(noinline) # define MOZ_HAVE_NORETURN __declspec(noreturn) -# if _MSC_VER >= 1900 -# define MOZ_HAVE_CXX11_CONSTEXPR -# define MOZ_HAVE_CXX11_CONSTEXPR_IN_TEMPLATES -# define MOZ_HAVE_EXPLICIT_CONVERSION -# endif -# ifdef __clang__ - /* clang-cl probably supports constexpr and explicit conversions. */ -# if __has_extension(cxx_constexpr) -# define MOZ_HAVE_CXX11_CONSTEXPR -# endif -# if __has_extension(cxx_explicit_conversions) -# define MOZ_HAVE_EXPLICIT_CONVERSION -# endif -# endif #elif defined(__clang__) /* * Per Clang documentation, "Note that marketing version numbers should not @@ -75,12 +57,6 @@ # ifndef __has_extension # define __has_extension __has_feature /* compatibility, for older versions of clang */ # endif -# if __has_extension(cxx_constexpr) -# define MOZ_HAVE_CXX11_CONSTEXPR -# endif -# if __has_extension(cxx_explicit_conversions) -# define MOZ_HAVE_EXPLICIT_CONVERSION -# endif # if __has_attribute(noinline) # define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) # endif @@ -88,13 +64,6 @@ # define MOZ_HAVE_NORETURN __attribute__((noreturn)) # endif #elif defined(__GNUC__) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L -# define MOZ_HAVE_CXX11_CONSTEXPR -# if MOZ_GCC_VERSION_AT_LEAST(4, 8, 0) -# define MOZ_HAVE_CXX11_CONSTEXPR_IN_TEMPLATES -# endif -# define MOZ_HAVE_EXPLICIT_CONVERSION -# endif # define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) # define MOZ_HAVE_NORETURN __attribute__((noreturn)) #endif @@ -110,55 +79,6 @@ #endif /* - * The MOZ_CONSTEXPR specifier declares that a C++11 compiler can evaluate a - * function at compile time. A constexpr function cannot examine any values - * except its arguments and can have no side effects except its return value. - * The MOZ_CONSTEXPR_VAR specifier tells a C++11 compiler that a variable's - * value may be computed at compile time. It should be prefered to just - * marking variables as MOZ_CONSTEXPR because if the compiler does not support - * constexpr it will fall back to making the variable const, and some compilers - * do not accept variables being marked both const and constexpr. - */ -#ifdef MOZ_HAVE_CXX11_CONSTEXPR -# define MOZ_CONSTEXPR constexpr -# define MOZ_CONSTEXPR_VAR constexpr -# ifdef MOZ_HAVE_CXX11_CONSTEXPR_IN_TEMPLATES -# define MOZ_CONSTEXPR_TMPL constexpr -# else -# define MOZ_CONSTEXPR_TMPL -# endif -#else -# define MOZ_CONSTEXPR /* no support */ -# define MOZ_CONSTEXPR_VAR const -# define MOZ_CONSTEXPR_TMPL -#endif - -/* - * MOZ_EXPLICIT_CONVERSION is a specifier on a type conversion - * overloaded operator that declares that a C++11 compiler should restrict - * this operator to allow only explicit type conversions, disallowing - * implicit conversions. - * - * Example: - * - * template - * class Ptr - * { - * T* mPtr; - * MOZ_EXPLICIT_CONVERSION operator bool() const - * { - * return mPtr != nullptr; - * } - * }; - * - */ -#ifdef MOZ_HAVE_EXPLICIT_CONVERSION -# define MOZ_EXPLICIT_CONVERSION explicit -#else -# define MOZ_EXPLICIT_CONVERSION /* no support */ -#endif - -/* * MOZ_NEVER_INLINE is a macro which expands to tell the compiler that the * method decorated with it must never be inlined, even if the compiler would * otherwise choose to inline the method. Compilers aren't absolutely @@ -318,37 +238,48 @@ #endif /** - * MOZ_WARN_UNUSED_RESULT tells the compiler to emit a warning if a function's + * MOZ_MUST_USE tells the compiler to emit a warning if a function's * return value is not used by the caller. * - * Place this attribute at the very beginning of a function definition. For + * Place this attribute at the very beginning of a function declaration. For * example, write * - * MOZ_WARN_UNUSED_RESULT int foo(); + * MOZ_MUST_USE int foo(); * * or * - * MOZ_WARN_UNUSED_RESULT int foo() { return 42; } + * MOZ_MUST_USE int foo() { return 42; } */ #if defined(__GNUC__) || defined(__clang__) -# define MOZ_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) +# define MOZ_MUST_USE __attribute__ ((warn_unused_result)) #else -# define MOZ_WARN_UNUSED_RESULT +# define MOZ_MUST_USE #endif /** * MOZ_FALLTHROUGH is an annotation to suppress compiler warnings about switch * cases that fall through without a break or return statement. MOZ_FALLTHROUGH - * is only needed on cases that have code: + * is only needed on cases that have code. + * + * MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about + * switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in + * debug builds, but intentionally fall through in release builds. See comment + * in Assertions.h for more details. * * switch (foo) { * case 1: // These cases have no code. No fallthrough annotations are needed. * case 2: - * case 3: - * foo = 4; // This case has code, so a fallthrough annotation is needed: + * case 3: // This case has code, so a fallthrough annotation is needed! + * foo++; * MOZ_FALLTHROUGH; - * default: + * case 4: * return foo; + * + * default: + * // This case asserts in debug builds, falls through in release. + * MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!"); + * case 5: + * return 5; * } */ #if defined(__clang__) && __cplusplus >= 201103L @@ -451,10 +382,12 @@ * intended to prevent introducing static initializers. This attribute * currently makes it a compile-time error to instantiate these classes * anywhere other than at the global scope, or as a static member of a class. + * In non-debug mode, it also prohibits non-trivial constructors and + * destructors. * MOZ_TRIVIAL_CTOR_DTOR: Applies to all classes that must have both a trivial - * constructor and a trivial destructor. Setting this attribute on a class - * makes it a compile-time error for that class to get a non-trivial - * constructor or destructor for any reason. + * or constexpr constructor and a trivial destructor. Setting this attribute + * on a class makes it a compile-time error for that class to get a + * non-trivial constructor or destructor for any reason. * MOZ_HEAP_ALLOCATOR: Applies to any function. This indicates that the return * value is allocated on the heap, and will as a result check such allocations * during MOZ_STACK_CLASS and MOZ_NONHEAP_CLASS annotation checking. @@ -500,9 +433,9 @@ * function. This is intended to be used with operator->() of our smart * pointer classes to ensure that the refcount of an object wrapped in a * smart pointer is not manipulated directly. - * MOZ_MUST_USE: Applies to type declarations. Makes it a compile time error to not - * use the return value of a function which has this type. This is intended to be - * used with types which it is an error to not use. + * MOZ_MUST_USE_TYPE: Applies to type declarations. Makes it a compile time + * error to not use the return value of a function which has this type. This + * is intended to be used with types which it is an error to not use. * MOZ_NEEDS_NO_VTABLE_TYPE: Applies to template class declarations. Makes it * a compile time error to instantiate this template with a type parameter which * has a VTable. @@ -512,14 +445,35 @@ * template arguments are required to be safe to move in memory using * memmove(). Passing MOZ_NON_MEMMOVABLE types to these templates is a * compile time error. + * MOZ_NEEDS_MEMMOVABLE_MEMBERS: Applies to class declarations where each member + * must be safe to move in memory using memmove(). MOZ_NON_MEMMOVABLE types + * used in members of these classes are compile time errors. * MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS: Applies to template class * declarations where an instance of the template should be considered, for * static analysis purposes, to inherit any type annotations (such as - * MOZ_MUST_USE and MOZ_STACK_CLASS) from its template arguments. + * MOZ_MUST_USE_TYPE and MOZ_STACK_CLASS) from its template arguments. + * MOZ_INIT_OUTSIDE_CTOR: Applies to class member declarations. Occasionally + * there are class members that are not initialized in the constructor, + * but logic elsewhere in the class ensures they are initialized prior to use. + * Using this attribute on a member disables the check that this member must be + * initialized in constructors via list-initialization, in the constructor body, + * or via functions called from the constructor body. + * MOZ_IS_CLASS_INIT: Applies to class method declarations. Occasionally the + * constructor doesn't initialize all of the member variables and another function + * is used to initialize the rest. This marker is used to make the static analysis + * tool aware that the marked function is part of the initialization process + * and to include the marked function in the scan mechanism that determines witch + * member variables still remain uninitialized. + * MOZ_NON_PARAM: Applies to types. Makes it compile time error to use the type + * in parameter without pointer or reference. * MOZ_NON_AUTOABLE: Applies to class declarations. Makes it a compile time error to * use `auto` in place of this type in variable declarations. This is intended to * be used with types which are intended to be implicitly constructed into other * other types before being assigned to variables. + * MOZ_REQUIRED_BASE_METHOD: Applies to virtual class method declarations. + * Sometimes derived classes override methods that need to be called by their + * overridden counterparts. This marker indicates that the marked method must + * be called by the method that it overrides. */ #ifdef MOZ_CLANG_PLUGIN # define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override"))) @@ -541,13 +495,22 @@ # define MOZ_NON_OWNING_REF __attribute__((annotate("moz_weak_ref"))) # define MOZ_UNSAFE_REF(reason) __attribute__((annotate("moz_weak_ref"))) # define MOZ_NO_ADDREF_RELEASE_ON_RETURN __attribute__((annotate("moz_no_addref_release_on_return"))) -# define MOZ_MUST_USE __attribute__((annotate("moz_must_use"))) +# define MOZ_MUST_USE_TYPE __attribute__((annotate("moz_must_use_type"))) # define MOZ_NEEDS_NO_VTABLE_TYPE __attribute__((annotate("moz_needs_no_vtable_type"))) # define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable"))) # define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type"))) +# define MOZ_NEEDS_MEMMOVABLE_MEMBERS __attribute__((annotate("moz_needs_memmovable_members"))) # define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS \ __attribute__((annotate("moz_inherit_type_annotations_from_template_args"))) # define MOZ_NON_AUTOABLE __attribute__((annotate("moz_non_autoable"))) +# define MOZ_INIT_OUTSIDE_CTOR \ + __attribute__((annotate("moz_ignore_ctor_initialization"))) +# define MOZ_IS_CLASS_INIT \ + __attribute__((annotate("moz_is_class_init"))) +# define MOZ_NON_PARAM \ + __attribute__((annotate("moz_non_param"))) +# define MOZ_REQUIRED_BASE_METHOD \ + __attribute__((annotate("moz_required_base_method"))) /* * It turns out that clang doesn't like void func() __attribute__ {} without a * warning, so use pragmas to disable the warning. This code won't work on GCC @@ -573,12 +536,17 @@ # define MOZ_NON_OWNING_REF /* nothing */ # define MOZ_UNSAFE_REF(reason) /* nothing */ # define MOZ_NO_ADDREF_RELEASE_ON_RETURN /* nothing */ -# define MOZ_MUST_USE /* nothing */ +# define MOZ_MUST_USE_TYPE /* nothing */ # define MOZ_NEEDS_NO_VTABLE_TYPE /* nothing */ # define MOZ_NON_MEMMOVABLE /* nothing */ # define MOZ_NEEDS_MEMMOVABLE_TYPE /* nothing */ +# define MOZ_NEEDS_MEMMOVABLE_MEMBERS /* nothing */ # define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS /* nothing */ +# define MOZ_INIT_OUTSIDE_CTOR /* nothing */ +# define MOZ_IS_CLASS_INIT /* nothing */ +# define MOZ_NON_PARAM /* nothing */ # define MOZ_NON_AUTOABLE /* nothing */ +# define MOZ_REQUIRED_BASE_METHOD /* nothing */ #endif /* MOZ_CLANG_PLUGIN */ #define MOZ_RAII MOZ_NON_TEMPORARY_CLASS MOZ_STACK_CLASS @@ -601,4 +569,36 @@ #endif /* __cplusplus */ +/** + * Printf style formats. MOZ_FORMAT_PRINTF can be used to annotate a + * function or method that is "printf-like"; this will let (some) + * compilers check that the arguments match the template string. + * + * This macro takes two arguments. The first argument is the argument + * number of the template string. The second argument is the argument + * number of the '...' argument holding the arguments. + * + * Argument numbers start at 1. Note that the implicit "this" + * argument of a non-static member function counts as an argument. + * + * So, for a simple case like: + * void print_something (int whatever, const char *fmt, ...); + * The corresponding annotation would be + * MOZ_FORMAT_PRINTF(2, 3) + * However, if "print_something" were a non-static member function, + * then the annotation would be: + * MOZ_FORMAT_PRINTF(3, 4) + * + * Note that the checking is limited to standards-conforming + * printf-likes, and in particular this should not be used for + * PR_snprintf and friends, which are "printf-like" but which assign + * different meanings to the various formats. + */ +#ifdef __GNUC__ +#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) \ + __attribute__ ((format (printf, stringIndex, firstToCheck))) +#else +#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) +#endif + #endif /* mozilla_Attributes_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/BinarySearch.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/BinarySearch.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/BinarySearch.h @@ -31,7 +31,7 @@ * printf("found 13 at %lu\n", match); * } * - * The BinarySearchIf() version behaves similar, but takes |aComparator|, a + * The BinarySearchIf() version behaves similarly, but takes |aComparator|, a * functor to compare the values with, instead of a value to find. * That functor should take one argument - the value to compare - and return an * |int| with the comparison result: @@ -45,13 +45,13 @@ * Example: * * struct Comparator { - * int operator()(int val) const { - * if (mTarget < val) return -1; - * if (mValue > val) return 1; + * int operator()(int aVal) const { + * if (mTarget < aVal) { return -1; } + * if (mTarget > aVal) { return 1; } * return 0; * } - * Comparator(int target) : mTarget(target) {} - const int mTarget; + * explicit Comparator(int aTarget) : mTarget(aTarget) {} + * const int mTarget; * }; * * Vector sortedInts = ... @@ -106,12 +106,12 @@ {} template - int operator()(const U& val) const { - if (mTarget == val) { + int operator()(const U& aVal) const { + if (mTarget == aVal) { return 0; } - if (mTarget < val) { + if (mTarget < aVal) { return -1; } Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/BufferList.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/BufferList.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/BufferList.h @@ -0,0 +1,568 @@ +/* -*- 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/. */ + +#ifndef mozilla_BufferList_h +#define mozilla_BufferList_h + +#include +#include "mozilla/AllocPolicy.h" +#include "mozilla/Maybe.h" +#include "mozilla/Move.h" +#include "mozilla/ScopeExit.h" +#include "mozilla/Types.h" +#include "mozilla/TypeTraits.h" +#include "mozilla/Vector.h" +#include + +// Undo potential #include damage to be able to use std::min. +#undef min + +// BufferList represents a sequence of buffers of data. A BufferList can choose +// to own its buffers or not. The class handles writing to the buffers, +// iterating over them, and reading data out. Unlike SegmentedVector, the +// buffers may be of unequal size. Like SegmentedVector, BufferList is a nice +// way to avoid large contiguous allocations (which can trigger OOMs). + +namespace mozilla { + +template +class BufferList : private AllocPolicy +{ + // Each buffer in a BufferList has a size and a capacity. The first mSize + // bytes are initialized and the remaining |mCapacity - mSize| bytes are free. + struct Segment + { + char* mData; + size_t mSize; + size_t mCapacity; + + Segment(char* aData, size_t aSize, size_t aCapacity) + : mData(aData), + mSize(aSize), + mCapacity(aCapacity) + { + } + + Segment(const Segment&) = delete; + Segment& operator=(const Segment&) = delete; + + Segment(Segment&&) = default; + Segment& operator=(Segment&&) = default; + + char* Start() const { return mData; } + char* End() const { return mData + mSize; } + }; + + template + friend class BufferList; + + public: + // For the convenience of callers, all segments are required to be a multiple + // of 8 bytes in capacity. Also, every buffer except the last one is required + // to be full (i.e., size == capacity). Therefore, a byte at offset N within + // the BufferList and stored in memory at an address A will satisfy + // (N % Align == A % Align) if Align == 2, 4, or 8. + static const size_t kSegmentAlignment = 8; + + // Allocate a BufferList. The BufferList will free all its buffers when it is + // destroyed. An initial buffer of size aInitialSize and capacity + // aInitialCapacity is allocated automatically. This data will be contiguous + // an can be accessed via |Start()|. Subsequent buffers will be allocated with + // capacity aStandardCapacity. + BufferList(size_t aInitialSize, + size_t aInitialCapacity, + size_t aStandardCapacity, + AllocPolicy aAP = AllocPolicy()) + : AllocPolicy(aAP), + mOwning(true), + mSegments(aAP), + mSize(0), + mStandardCapacity(aStandardCapacity) + { + MOZ_ASSERT(aInitialCapacity % kSegmentAlignment == 0); + MOZ_ASSERT(aStandardCapacity % kSegmentAlignment == 0); + + if (aInitialCapacity) { + AllocateSegment(aInitialSize, aInitialCapacity); + } + } + + BufferList(const BufferList& aOther) = delete; + + BufferList(BufferList&& aOther) + : mOwning(aOther.mOwning), + mSegments(Move(aOther.mSegments)), + mSize(aOther.mSize), + mStandardCapacity(aOther.mStandardCapacity) + { + aOther.mSegments.clear(); + aOther.mSize = 0; + } + + BufferList& operator=(const BufferList& aOther) = delete; + + BufferList& operator=(BufferList&& aOther) + { + Clear(); + + mOwning = aOther.mOwning; + mSegments = Move(aOther.mSegments); + mSize = aOther.mSize; + aOther.mSegments.clear(); + aOther.mSize = 0; + return *this; + } + + ~BufferList() { Clear(); } + + // Returns the sum of the sizes of all the buffers. + size_t Size() const { return mSize; } + + void Clear() + { + if (mOwning) { + for (Segment& segment : mSegments) { + this->free_(segment.mData); + } + } + mSegments.clear(); + + mSize = 0; + } + + // Iterates over bytes in the segments. You can advance it by as many bytes as + // you choose. + class IterImpl + { + // Invariants: + // (0) mSegment <= bufferList.mSegments.size() + // (1) mData <= mDataEnd + // (2) If mSegment is not the last segment, mData < mDataEnd + uintptr_t mSegment; + char* mData; + char* mDataEnd; + + friend class BufferList; + + public: + explicit IterImpl(const BufferList& aBuffers) + : mSegment(0), + mData(nullptr), + mDataEnd(nullptr) + { + if (!aBuffers.mSegments.empty()) { + mData = aBuffers.mSegments[0].Start(); + mDataEnd = aBuffers.mSegments[0].End(); + } + } + + // Returns a pointer to the raw data. It is valid to access up to + // RemainingInSegment bytes of this buffer. + char* Data() const + { + MOZ_RELEASE_ASSERT(!Done()); + return mData; + } + + // Returns true if the memory in the range [Data(), Data() + aBytes) is all + // part of one contiguous buffer. + bool HasRoomFor(size_t aBytes) const + { + MOZ_RELEASE_ASSERT(mData <= mDataEnd); + return size_t(mDataEnd - mData) >= aBytes; + } + + // Returns the maximum value aBytes for which HasRoomFor(aBytes) will be + // true. + size_t RemainingInSegment() const + { + MOZ_RELEASE_ASSERT(mData <= mDataEnd); + return mDataEnd - mData; + } + + // Advances the iterator by aBytes bytes. aBytes must be less than + // RemainingInSegment(). If advancing by aBytes takes the iterator to the + // end of a buffer, it will be moved to the beginning of the next buffer + // unless it is the last buffer. + void Advance(const BufferList& aBuffers, size_t aBytes) + { + const Segment& segment = aBuffers.mSegments[mSegment]; + MOZ_RELEASE_ASSERT(segment.Start() <= mData); + MOZ_RELEASE_ASSERT(mData <= mDataEnd); + MOZ_RELEASE_ASSERT(mDataEnd == segment.End()); + + MOZ_RELEASE_ASSERT(HasRoomFor(aBytes)); + mData += aBytes; + + if (mData == mDataEnd && mSegment + 1 < aBuffers.mSegments.length()) { + mSegment++; + const Segment& nextSegment = aBuffers.mSegments[mSegment]; + mData = nextSegment.Start(); + mDataEnd = nextSegment.End(); + MOZ_RELEASE_ASSERT(mData < mDataEnd); + } + } + + // Advance the iterator by aBytes, possibly crossing segments. This function + // returns false if it runs out of buffers to advance through. Otherwise it + // returns true. + bool AdvanceAcrossSegments(const BufferList& aBuffers, size_t aBytes) + { + size_t bytes = aBytes; + while (bytes) { + size_t toAdvance = std::min(bytes, RemainingInSegment()); + if (!toAdvance) { + return false; + } + Advance(aBuffers, toAdvance); + bytes -= toAdvance; + } + return true; + } + + // Returns true when the iterator reaches the end of the BufferList. + bool Done() const + { + return mData == mDataEnd; + } + + private: + + // Count the bytes we would need to advance in order to reach aTarget. + size_t BytesUntil(const BufferList& aBuffers, const IterImpl& aTarget) const { + size_t offset = 0; + + MOZ_ASSERT(aTarget.IsIn(aBuffers)); + + char* data = mData; + for (uintptr_t segment = mSegment; segment < aTarget.mSegment; segment++) { + offset += aBuffers.mSegments[segment].End() - data; + data = aBuffers.mSegments[segment].mData; + } + + MOZ_RELEASE_ASSERT(IsIn(aBuffers)); + MOZ_RELEASE_ASSERT(aTarget.mData >= data); + + offset += aTarget.mData - data; + return offset; + } + + bool IsIn(const BufferList& aBuffers) const { + return mSegment < aBuffers.mSegments.length() && + mData >= aBuffers.mSegments[mSegment].mData && + mData < aBuffers.mSegments[mSegment].End(); + } + }; + + // Special convenience method that returns Iter().Data(). + char* Start() { return mSegments[0].mData; } + const char* Start() const { return mSegments[0].mData; } + + IterImpl Iter() const { return IterImpl(*this); } + + // Copies aSize bytes from aData into the BufferList. The storage for these + // bytes may be split across multiple buffers. Size() is increased by aSize. + inline bool WriteBytes(const char* aData, size_t aSize); + + // Copies possibly non-contiguous byte range starting at aIter into + // aData. aIter is advanced by aSize bytes. Returns false if it runs out of + // data before aSize. + inline bool ReadBytes(IterImpl& aIter, char* aData, size_t aSize) const; + + // Return a new BufferList that shares storage with this BufferList. The new + // BufferList is read-only. It allows iteration over aSize bytes starting at + // aIter. Borrow can fail, in which case *aSuccess will be false upon + // return. The borrowed BufferList can use a different AllocPolicy than the + // original one. However, it is not responsible for freeing buffers, so the + // AllocPolicy is only used for the buffer vector. + template + BufferList Borrow(IterImpl& aIter, size_t aSize, bool* aSuccess, + BorrowingAllocPolicy aAP = BorrowingAllocPolicy()) const; + + // Return a new BufferList and move storage from this BufferList to it. The + // new BufferList owns the buffers. Move can fail, in which case *aSuccess + // will be false upon return. The new BufferList can use a different + // AllocPolicy than the original one. The new OtherAllocPolicy is responsible + // for freeing buffers, so the OtherAllocPolicy must use freeing method + // compatible to the original one. + template + BufferList MoveFallible(bool* aSuccess, OtherAllocPolicy aAP = OtherAllocPolicy()); + + // Return a new BufferList that adopts the byte range starting at Iter so that + // range [aIter, aIter + aSize) is transplanted to the returned BufferList. + // Contents of the buffer before aIter + aSize is left undefined. + // Extract can fail, in which case *aSuccess will be false upon return. The + // moved buffers are erased from the original BufferList. In case of extract + // fails, the original BufferList is intact. All other iterators except aIter + // are invalidated. + // This method requires aIter and aSize to be 8-byte aligned. + BufferList Extract(IterImpl& aIter, size_t aSize, bool* aSuccess); + + // Return the number of bytes from 'start' to 'end', two iterators within + // this BufferList. + size_t RangeLength(const IterImpl& start, const IterImpl& end) const { + MOZ_ASSERT(start.IsIn(*this) && end.IsIn(*this)); + return start.BytesUntil(*this, end); + } + +private: + explicit BufferList(AllocPolicy aAP) + : AllocPolicy(aAP), + mOwning(false), + mSize(0), + mStandardCapacity(0) + { + } + + void* AllocateSegment(size_t aSize, size_t aCapacity) + { + MOZ_RELEASE_ASSERT(mOwning); + + char* data = this->template pod_malloc(aCapacity); + if (!data) { + return nullptr; + } + if (!mSegments.append(Segment(data, aSize, aCapacity))) { + this->free_(data); + return nullptr; + } + mSize += aSize; + return data; + } + + bool mOwning; + Vector mSegments; + size_t mSize; + size_t mStandardCapacity; +}; + +template +bool +BufferList::WriteBytes(const char* aData, size_t aSize) +{ + MOZ_RELEASE_ASSERT(mOwning); + MOZ_RELEASE_ASSERT(mStandardCapacity); + + size_t copied = 0; + size_t remaining = aSize; + + if (!mSegments.empty()) { + Segment& lastSegment = mSegments.back(); + + size_t toCopy = std::min(aSize, lastSegment.mCapacity - lastSegment.mSize); + memcpy(lastSegment.mData + lastSegment.mSize, aData, toCopy); + lastSegment.mSize += toCopy; + mSize += toCopy; + + copied += toCopy; + remaining -= toCopy; + } + + while (remaining) { + size_t toCopy = std::min(remaining, mStandardCapacity); + + void* data = AllocateSegment(toCopy, mStandardCapacity); + if (!data) { + return false; + } + memcpy(data, aData + copied, toCopy); + + copied += toCopy; + remaining -= toCopy; + } + + return true; +} + +template +bool +BufferList::ReadBytes(IterImpl& aIter, char* aData, size_t aSize) const +{ + size_t copied = 0; + size_t remaining = aSize; + while (remaining) { + size_t toCopy = std::min(aIter.RemainingInSegment(), remaining); + if (!toCopy) { + // We've run out of data in the last segment. + return false; + } + memcpy(aData + copied, aIter.Data(), toCopy); + copied += toCopy; + remaining -= toCopy; + + aIter.Advance(*this, toCopy); + } + + return true; +} + +template template +BufferList +BufferList::Borrow(IterImpl& aIter, size_t aSize, bool* aSuccess, + BorrowingAllocPolicy aAP) const +{ + BufferList result(aAP); + + size_t size = aSize; + while (size) { + size_t toAdvance = std::min(size, aIter.RemainingInSegment()); + + if (!toAdvance || !result.mSegments.append(typename BufferList::Segment(aIter.mData, toAdvance, toAdvance))) { + *aSuccess = false; + return result; + } + aIter.Advance(*this, toAdvance); + size -= toAdvance; + } + + result.mSize = aSize; + *aSuccess = true; + return result; +} + +template template +BufferList +BufferList::MoveFallible(bool* aSuccess, OtherAllocPolicy aAP) +{ + BufferList result(0, 0, mStandardCapacity, aAP); + + IterImpl iter = Iter(); + while (!iter.Done()) { + size_t toAdvance = iter.RemainingInSegment(); + + if (!toAdvance || !result.mSegments.append(typename BufferList::Segment(iter.mData, toAdvance, toAdvance))) { + *aSuccess = false; + result.mSegments.clear(); + return result; + } + iter.Advance(*this, toAdvance); + } + + result.mSize = mSize; + mSegments.clear(); + mSize = 0; + *aSuccess = true; + return result; +} + +template +BufferList +BufferList::Extract(IterImpl& aIter, size_t aSize, bool* aSuccess) +{ + MOZ_RELEASE_ASSERT(aSize); + MOZ_RELEASE_ASSERT(mOwning); + MOZ_ASSERT(aSize % kSegmentAlignment == 0); + MOZ_ASSERT(intptr_t(aIter.mData) % kSegmentAlignment == 0); + + auto failure = [this, aSuccess]() { + *aSuccess = false; + return BufferList(0, 0, mStandardCapacity); + }; + + // Number of segments we'll need to copy data from to satisfy the request. + size_t segmentsNeeded = 0; + // If this is None then the last segment is a full segment, otherwise we need + // to copy this many bytes. + Maybe lastSegmentSize; + { + // Copy of the iterator to walk the BufferList and see how many segments we + // need to copy. + IterImpl iter = aIter; + size_t remaining = aSize; + while (!iter.Done() && remaining && + remaining >= iter.RemainingInSegment()) { + remaining -= iter.RemainingInSegment(); + iter.Advance(*this, iter.RemainingInSegment()); + segmentsNeeded++; + } + + if (remaining) { + if (iter.Done()) { + // We reached the end of the BufferList and there wasn't enough data to + // satisfy the request. + return failure(); + } + lastSegmentSize.emplace(remaining); + // The last block also counts as a segment. This makes the conditionals + // on segmentsNeeded work in the rest of the function. + segmentsNeeded++; + } + } + + BufferList result(0, 0, mStandardCapacity); + if (!result.mSegments.reserve(segmentsNeeded + lastSegmentSize.isSome())) { + return failure(); + } + + // Copy the first segment, it's special because we can't just steal the + // entire Segment struct from this->mSegments. + size_t firstSegmentSize = std::min(aSize, aIter.RemainingInSegment()); + if (!result.WriteBytes(aIter.Data(), firstSegmentSize)) { + return failure(); + } + aIter.Advance(*this, firstSegmentSize); + segmentsNeeded--; + + // The entirety of the request wasn't in the first segment, now copy the + // rest. + if (segmentsNeeded) { + char* finalSegment = nullptr; + // Pre-allocate the final segment so that if this fails, we return before + // we delete the elements from |this->mSegments|. + if (lastSegmentSize.isSome()) { + MOZ_RELEASE_ASSERT(mStandardCapacity >= *lastSegmentSize); + finalSegment = this->template pod_malloc(mStandardCapacity); + if (!finalSegment) { + return failure(); + } + } + + size_t copyStart = aIter.mSegment; + // Copy segments from this over to the result and remove them from our + // storage. Not needed if the only segment we need to copy is the last + // partial one. + size_t segmentsToCopy = segmentsNeeded - lastSegmentSize.isSome(); + for (size_t i = 0; i < segmentsToCopy; ++i) { + result.mSegments.infallibleAppend( + Segment(mSegments[aIter.mSegment].mData, + mSegments[aIter.mSegment].mSize, + mSegments[aIter.mSegment].mCapacity)); + aIter.Advance(*this, aIter.RemainingInSegment()); + } + // Due to the way IterImpl works, there are two cases here: (1) if we've + // consumed the entirety of the BufferList, then the iterator is pointed at + // the end of the final segment, (2) otherwise it is pointed at the start + // of the next segment. We want to verify that we really consumed all + // |segmentsToCopy| segments. + MOZ_RELEASE_ASSERT( + (aIter.mSegment == copyStart + segmentsToCopy) || + (aIter.Done() && aIter.mSegment == copyStart + segmentsToCopy - 1)); + mSegments.erase(mSegments.begin() + copyStart, + mSegments.begin() + copyStart + segmentsToCopy); + + // Reset the iter's position for what we just deleted. + aIter.mSegment -= segmentsToCopy; + + if (lastSegmentSize.isSome()) { + // We called reserve() on result.mSegments so infallibleAppend is safe. + result.mSegments.infallibleAppend( + Segment(finalSegment, 0, mStandardCapacity)); + bool r = result.WriteBytes(aIter.Data(), *lastSegmentSize); + MOZ_RELEASE_ASSERT(r); + aIter.Advance(*this, *lastSegmentSize); + } + } + + mSize -= aSize; + result.mSize = aSize; + + *aSuccess = true; + return result; +} + +} // namespace mozilla + +#endif /* mozilla_BufferList_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Casting.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Casting.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Casting.h @@ -17,16 +17,29 @@ namespace mozilla { /** - * Return a value of type |To|, containing the underlying bit pattern of + * Sets the outparam value of type |To| with the same underlying bit pattern of * |aFrom|. * * |To| and |From| must be types of the same size; be careful of cross-platform * size differences, or this might fail to compile on some but not all * platforms. + * + * There is also a variant that returns the value directly. In most cases, the + * two variants should be identical. However, in the specific case of x86 + * chips, the behavior differs: returning floating-point values directly is done + * through the x87 stack, and x87 loads and stores turn signaling NaNs into + * quiet NaNs... silently. Returning floating-point values via outparam, + * however, is done entirely within the SSE registers when SSE2 floating-point + * is enabled in the compiler, which has semantics-preserving behavior you would + * expect. + * + * If preserving the distinction between signaling NaNs and quiet NaNs is + * important to you, you should use the outparam version. In all other cases, + * you should use the direct return version. */ template -inline To -BitwiseCast(const From aFrom) +inline void +BitwiseCast(const From aFrom, To* aResult) { static_assert(sizeof(From) == sizeof(To), "To and From must have the same size"); @@ -36,7 +49,16 @@ To mTo; } u; u.mFrom = aFrom; - return u.mTo; + *aResult = u.mTo; +} + +template +inline To +BitwiseCast(const From aFrom) +{ + To temp; + BitwiseCast(aFrom, &temp); + return temp; } namespace detail { Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ChaosMode.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ChaosMode.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ChaosMode.h @@ -27,6 +27,8 @@ IOAmounts = 0x8, // Iterate over hash tables in random order. HashTableIteration = 0x10, + // Randomly refuse to use cached version of image (when allowed by spec). + ImageCache = 0x20, Any = 0xffffffff, }; Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Char16.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Char16.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Char16.h @@ -17,38 +17,8 @@ * is a 16-bit code unit of a Unicode code point, not a "character". */ -#if defined(_MSC_VER) && _MSC_VER < 1900 - /* - * C++11 says char16_t is a distinct builtin type, but Windows's yvals.h - * typedefs char16_t as an unsigned short prior to MSVC 2015, which - * implemented C++11's distinct char16_t type. We would like to alias - * char16_t to Windows's 16-bit wchar_t so we can declare UTF-16 literals as - * constant expressions (and pass char16_t pointers to Windows APIs). We - * #define _CHAR16T here in order to prevent yvals.h from overriding our - * char16_t typedefs, which we set to wchar_t for C++ code. - * - * In addition, #defining _CHAR16T will prevent yvals.h from defining a - * char32_t type, so we have to undo that damage here and provide our own, - * which is identical to the yvals.h type. - */ -# define MOZ_UTF16_HELPER(s) L##s -# define _CHAR16T -typedef wchar_t char16_t; -typedef unsigned int char32_t; -#else - /* C++11 has a builtin char16_t type. */ -# define MOZ_UTF16_HELPER(s) u##s - /** - * This macro is used to distinguish when char16_t would be a distinct - * typedef from wchar_t. - */ -# define MOZ_CHAR16_IS_NOT_WCHAR -# ifdef WIN32 -# define MOZ_USE_CHAR16_WRAPPER -# endif -#endif - -#ifdef MOZ_USE_CHAR16_WRAPPER +#ifdef WIN32 +# define MOZ_USE_CHAR16_WRAPPER # include /** * Win32 API extensively uses wchar_t, which is represented by a separated @@ -214,20 +184,10 @@ #endif -/* - * Macro arguments used in concatenation or stringification won't be expanded. - * Therefore, in order for |MOZ_UTF16(FOO)| to work as expected (which is to - * expand |FOO| before doing whatever |MOZ_UTF16| needs to do to it) a helper - * macro, |MOZ_UTF16_HELPER| needs to be inserted in between to allow the macro - * argument to expand. See "3.10.6 Separate Expansion of Macro Arguments" of the - * CPP manual for a more accurate and precise explanation. - */ -#define MOZ_UTF16(s) MOZ_UTF16_HELPER(s) - static_assert(sizeof(char16_t) == 2, "Is char16_t type 16 bits?"); static_assert(char16_t(-1) > char16_t(0), "Is char16_t type unsigned?"); -static_assert(sizeof(MOZ_UTF16('A')) == 2, "Is char literal 16 bits?"); -static_assert(sizeof(MOZ_UTF16("")[0]) == 2, "Is string char 16 bits?"); +static_assert(sizeof(u'A') == 2, "Is unicode char literal 16 bits?"); +static_assert(sizeof(u""[0]) == 2, "Is unicode string char 16 bits?"); #endif Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Compiler.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Compiler.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Compiler.h @@ -10,21 +10,24 @@ #define mozilla_Compiler_h #define MOZ_IS_GCC 0 -#define MOS_IS_MSVC 0 +#define MOZ_IS_MSVC 0 #if !defined(__clang__) && defined(__GNUC__) # undef MOZ_IS_GCC # define MOZ_IS_GCC 1 /* - * This macro should simplify gcc version checking. For example, to check + * These macros should simplify gcc version checking. For example, to check * for gcc 4.7.1 or later, check `#if MOZ_GCC_VERSION_AT_LEAST(4, 7, 1)`. */ # define MOZ_GCC_VERSION_AT_LEAST(major, minor, patchlevel) \ ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) \ >= ((major) * 10000 + (minor) * 100 + (patchlevel))) -# if !MOZ_GCC_VERSION_AT_LEAST(4, 7, 0) -# error "mfbt (and Gecko) require at least gcc 4.7 to build." +# define MOZ_GCC_VERSION_AT_MOST(major, minor, patchlevel) \ + ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) \ + <= ((major) * 10000 + (minor) * 100 + (patchlevel))) +# if !MOZ_GCC_VERSION_AT_LEAST(4, 8, 0) +# error "mfbt (and Gecko) require at least gcc 4.8 to build." # endif #elif defined(_MSC_VER) Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Compression.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Compression.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Compression.h @@ -61,8 +61,7 @@ /** * If the source stream is malformed, the function will stop decoding - * and return a negative result, indicating the byte position of the - * faulty instruction + * and return false. * * This function never writes outside of provided buffers, and never * modifies input buffer. @@ -71,9 +70,9 @@ * minimum of |aOutputSize| bytes. * * @param aOutputSize is the output size, therefore the original size - * @return the number of bytes read in the source buffer + * @return true on success, false on failure */ - static MFBT_API bool + static MFBT_API MOZ_MUST_USE bool decompress(const char* aSource, char* aDest, size_t aOutputSize); /** @@ -91,8 +90,9 @@ * already allocated) * @param aOutputSize the actual number of bytes decoded in the destination * buffer (necessarily <= aMaxOutputSize) + * @return true on success, false on failure */ - static MFBT_API bool + static MFBT_API MOZ_MUST_USE bool decompress(const char* aSource, size_t aInputSize, char* aDest, size_t aMaxOutputSize, size_t* aOutputSize); Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/DebugOnly.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/DebugOnly.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/DebugOnly.h @@ -24,17 +24,19 @@ * DebugOnly check = func(); * MOZ_ASSERT(check); * - * more concisely than declaring |check| conditional on #ifdef DEBUG, but also - * without allocating storage space for |check| in release builds. + * more concisely than declaring |check| conditional on #ifdef DEBUG. * * DebugOnly instances can only be coerced to T in debug builds. In release * builds they don't have a value, so type coercion is not well defined. * - * Note that DebugOnly instances still take up one byte of space, plus padding, - * when used as members of structs. + * NOTE: DebugOnly instances still take up one byte of space, plus padding, even + * in optimized, non-DEBUG builds (see bug 1253094 comment 37 for more info). + * For this reason the class is MOZ_STACK_CLASS to prevent consumers using + * DebugOnly for struct/class members and unwittingly inflating the size of + * their objects in release builds. */ template -class DebugOnly +class MOZ_STACK_CLASS DebugOnly { public: #ifdef DEBUG Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Decimal.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Decimal.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Decimal.h @@ -30,8 +30,8 @@ /** * Imported from: - * http://src.chromium.org/viewvc/blink/trunk/Source/core/platform/Decimal.h - * Check hg log for the svn rev of the last update from Blink core. + * https://chromium.googlesource.com/chromium/src.git/+/master/third_party/WebKit/Source/platform/Decimal.h + * Check UPSTREAM-GIT-SHA for the commit ID of the last update from Blink core. */ #ifndef Decimal_h @@ -48,25 +48,33 @@ #define ASSERT MOZ_ASSERT #endif -// To use WTF_MAKE_FAST_ALLOCATED we'd need: -// http://src.chromium.org/viewvc/blink/trunk/Source/wtf/FastMalloc.h +#define PLATFORM_EXPORT + +// To use USING_FAST_MALLOC we'd need: +// https://chromium.googlesource.com/chromium/src.git/+/master/third_party/WebKit/Source/wtf/Allocator.h // Since we don't allocate Decimal objects, no need. -#define WTF_MAKE_FAST_ALLOCATED \ +#define USING_FAST_MALLOC(type) \ void ignore_this_dummy_method() = delete -namespace WebCore { +#define DISALLOW_NEW() \ + private: \ + void* operator new(size_t) = delete; \ + void* operator new(size_t, void*) = delete; \ + public: + +namespace blink { namespace DecimalPrivate { class SpecialValueHandler; -} // namespace DecimalPrivate +} // This class represents decimal base floating point number. // // FIXME: Once all C++ compiler support decimal type, we should replace this // class to compiler supported one. See below URI for current status of decimal // type for C++: // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1977.html -class Decimal { - WTF_MAKE_FAST_ALLOCATED; +class PLATFORM_EXPORT Decimal { + USING_FAST_MALLOC(Decimal); public: enum Sign { Positive, @@ -75,6 +83,7 @@ // You should not use EncodedData other than unit testing. class EncodedData { + DISALLOW_NEW(); // For accessing FormatClass. friend class Decimal; friend class DecimalPrivate::SpecialValueHandler; @@ -93,7 +102,7 @@ bool isSpecial() const { return m_formatClass == ClassInfinity || m_formatClass == ClassNaN; } bool isZero() const { return m_formatClass == ClassZero; } Sign sign() const { return m_sign; } - void setSign(Sign aSign) { m_sign = aSign; } + void setSign(Sign sign) { m_sign = sign; } private: enum FormatClass { @@ -151,7 +160,7 @@ bool isZero() const { return m_data.isZero(); } MFBT_API Decimal abs() const; - MFBT_API Decimal ceiling() const; + MFBT_API Decimal ceil() const; MFBT_API Decimal floor() const; MFBT_API Decimal remainder(const Decimal&) const; MFBT_API Decimal round() const; @@ -196,13 +205,13 @@ EncodedData m_data; }; -} // namespace WebCore +} // namespace blink namespace mozilla { - typedef WebCore::Decimal Decimal; +typedef blink::Decimal Decimal; } // namespace mozilla -#undef WTF_MAKE_FAST_ALLOCATED +#undef USING_FAST_MALLOC #ifdef DEFINED_ASSERT_FOR_DECIMAL_H #undef DEFINED_ASSERT_FOR_DECIMAL_H @@ -210,4 +219,3 @@ #endif #endif // Decimal_h - Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Endian.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Endian.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Endian.h @@ -1,697 +0,0 @@ -/* -*- 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/. */ - -/* Functions for reading and writing integers in various endiannesses. */ - -/* - * The classes LittleEndian and BigEndian expose static methods for - * reading and writing 16-, 32-, and 64-bit signed and unsigned integers - * in their respective endianness. The naming scheme is: - * - * {Little,Big}Endian::{read,write}{Uint,Int} - * - * For instance, LittleEndian::readInt32 will read a 32-bit signed - * integer from memory in little endian format. Similarly, - * BigEndian::writeUint16 will write a 16-bit unsigned integer to memory - * in big-endian format. - * - * The class NativeEndian exposes methods for conversion of existing - * data to and from the native endianness. These methods are intended - * for cases where data needs to be transferred, serialized, etc. - * swap{To,From}{Little,Big}Endian byteswap a single value if necessary. - * Bulk conversion functions are also provided which optimize the - * no-conversion-needed case: - * - * - copyAndSwap{To,From}{Little,Big}Endian; - * - swap{To,From}{Little,Big}EndianInPlace. - * - * The *From* variants are intended to be used for reading data and the - * *To* variants for writing data. - * - * Methods on NativeEndian work with integer data of any type. - * Floating-point data is not supported. - * - * For clarity in networking code, "Network" may be used as a synonym - * for "Big" in any of the above methods or class names. - * - * As an example, reading a file format header whose fields are stored - * in big-endian format might look like: - * - * class ExampleHeader - * { - * private: - * uint32_t mMagic; - * uint32_t mLength; - * uint32_t mTotalRecords; - * uint64_t mChecksum; - * - * public: - * ExampleHeader(const void* data) - * { - * const uint8_t* ptr = static_cast(data); - * mMagic = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); - * mLength = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); - * mTotalRecords = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); - * mChecksum = BigEndian::readUint64(ptr); - * } - * ... - * }; - */ - -#ifndef mozilla_Endian_h -#define mozilla_Endian_h - -#include "mozilla/Assertions.h" -#include "mozilla/Attributes.h" -#include "mozilla/Compiler.h" -#include "mozilla/DebugOnly.h" -#include "mozilla/TypeTraits.h" - -#include -#include - -#if defined(_MSC_VER) -# include -# pragma intrinsic(_byteswap_ushort) -# pragma intrinsic(_byteswap_ulong) -# pragma intrinsic(_byteswap_uint64) -#endif - -#if defined(_WIN64) -# if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_) -# define MOZ_LITTLE_ENDIAN 1 -# else -# error "CPU type is unknown" -# endif -#elif defined(_WIN32) -# if defined(_M_IX86) -# define MOZ_LITTLE_ENDIAN 1 -# elif defined(_M_ARM) -# define MOZ_LITTLE_ENDIAN 1 -# else -# error "CPU type is unknown" -# endif -#elif defined(__APPLE__) || defined(__powerpc__) || defined(__ppc__) -# if __LITTLE_ENDIAN__ -# define MOZ_LITTLE_ENDIAN 1 -# elif __BIG_ENDIAN__ -# define MOZ_BIG_ENDIAN 1 -# endif -#elif defined(__GNUC__) && \ - defined(__BYTE_ORDER__) && \ - defined(__ORDER_LITTLE_ENDIAN__) && \ - defined(__ORDER_BIG_ENDIAN__) - /* - * Some versions of GCC provide architecture-independent macros for - * this. Yes, there are more than two values for __BYTE_ORDER__. - */ -# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define MOZ_LITTLE_ENDIAN 1 -# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -# define MOZ_BIG_ENDIAN 1 -# else -# error "Can't handle mixed-endian architectures" -# endif -/* - * We can't include useful headers like or - * here because they're not present on all platforms. Instead we have - * this big conditional that ideally will catch all the interesting - * cases. - */ -#elif defined(__sparc) || defined(__sparc__) || \ - defined(_POWER) || defined(__hppa) || \ - defined(_MIPSEB) || defined(__ARMEB__) || \ - defined(__s390__) || defined(__AARCH64EB__) || \ - (defined(__sh__) && defined(__LITTLE_ENDIAN__)) || \ - (defined(__ia64) && defined(__BIG_ENDIAN__)) -# define MOZ_BIG_ENDIAN 1 -#elif defined(__i386) || defined(__i386__) || \ - defined(__x86_64) || defined(__x86_64__) || \ - defined(_MIPSEL) || defined(__ARMEL__) || \ - defined(__alpha__) || defined(__AARCH64EL__) || \ - (defined(__sh__) && defined(__BIG_ENDIAN__)) || \ - (defined(__ia64) && !defined(__BIG_ENDIAN__)) -# define MOZ_LITTLE_ENDIAN 1 -#endif - -#if MOZ_BIG_ENDIAN -# define MOZ_LITTLE_ENDIAN 0 -#elif MOZ_LITTLE_ENDIAN -# define MOZ_BIG_ENDIAN 0 -#else -# error "Cannot determine endianness" -#endif - -#if defined(__clang__) -# if __has_builtin(__builtin_bswap16) -# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 -# endif -#elif defined(__GNUC__) -# if MOZ_GCC_VERSION_AT_LEAST(4, 8, 0) -# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 -# endif -#elif defined(_MSC_VER) -# define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort -#endif - -namespace mozilla { - -namespace detail { - -/* - * We need wrappers here because free functions with default template - * arguments and/or partial specialization of function templates are not - * supported by all the compilers we use. - */ -template -struct Swapper; - -template -struct Swapper -{ - static T swap(T aValue) - { -#if defined(MOZ_HAVE_BUILTIN_BYTESWAP16) - return MOZ_HAVE_BUILTIN_BYTESWAP16(aValue); -#else - return T(((aValue & 0x00ff) << 8) | ((aValue & 0xff00) >> 8)); -#endif - } -}; - -template -struct Swapper -{ - static T swap(T aValue) - { -#if defined(__clang__) || defined(__GNUC__) - return T(__builtin_bswap32(aValue)); -#elif defined(_MSC_VER) - return T(_byteswap_ulong(aValue)); -#else - return T(((aValue & 0x000000ffU) << 24) | - ((aValue & 0x0000ff00U) << 8) | - ((aValue & 0x00ff0000U) >> 8) | - ((aValue & 0xff000000U) >> 24)); -#endif - } -}; - -template -struct Swapper -{ - static inline T swap(T aValue) - { -#if defined(__clang__) || defined(__GNUC__) - return T(__builtin_bswap64(aValue)); -#elif defined(_MSC_VER) - return T(_byteswap_uint64(aValue)); -#else - return T(((aValue & 0x00000000000000ffULL) << 56) | - ((aValue & 0x000000000000ff00ULL) << 40) | - ((aValue & 0x0000000000ff0000ULL) << 24) | - ((aValue & 0x00000000ff000000ULL) << 8) | - ((aValue & 0x000000ff00000000ULL) >> 8) | - ((aValue & 0x0000ff0000000000ULL) >> 24) | - ((aValue & 0x00ff000000000000ULL) >> 40) | - ((aValue & 0xff00000000000000ULL) >> 56)); -#endif - } -}; - -enum Endianness { Little, Big }; - -#if MOZ_BIG_ENDIAN -# define MOZ_NATIVE_ENDIANNESS detail::Big -#else -# define MOZ_NATIVE_ENDIANNESS detail::Little -#endif - -class EndianUtils -{ - /** - * Assert that the memory regions [aDest, aDest+aCount) and - * [aSrc, aSrc+aCount] do not overlap. aCount is given in bytes. - */ - static void assertNoOverlap(const void* aDest, const void* aSrc, - size_t aCount) - { - DebugOnly byteDestPtr = static_cast(aDest); - DebugOnly byteSrcPtr = static_cast(aSrc); - MOZ_ASSERT((byteDestPtr <= byteSrcPtr && - byteDestPtr + aCount <= byteSrcPtr) || - (byteSrcPtr <= byteDestPtr && - byteSrcPtr + aCount <= byteDestPtr)); - } - - template - static void assertAligned(T* aPtr) - { - MOZ_ASSERT((uintptr_t(aPtr) % sizeof(T)) == 0, "Unaligned pointer!"); - } - -protected: - /** - * Return |aValue| converted from SourceEndian encoding to DestEndian - * encoding. - */ - template - static inline T maybeSwap(T aValue) - { - if (SourceEndian == DestEndian) { - return aValue; - } - return Swapper::swap(aValue); - } - - /** - * Convert |aCount| elements at |aPtr| from SourceEndian encoding to - * DestEndian encoding. - */ - template - static inline void maybeSwapInPlace(T* aPtr, size_t aCount) - { - assertAligned(aPtr); - - if (SourceEndian == DestEndian) { - return; - } - for (size_t i = 0; i < aCount; i++) { - aPtr[i] = Swapper::swap(aPtr[i]); - } - } - - /** - * Write |aCount| elements to the unaligned address |aDest| in DestEndian - * format, using elements found at |aSrc| in SourceEndian format. - */ - template - static void copyAndSwapTo(void* aDest, const T* aSrc, size_t aCount) - { - assertNoOverlap(aDest, aSrc, aCount * sizeof(T)); - assertAligned(aSrc); - - if (SourceEndian == DestEndian) { - memcpy(aDest, aSrc, aCount * sizeof(T)); - return; - } - - uint8_t* byteDestPtr = static_cast(aDest); - for (size_t i = 0; i < aCount; ++i) { - union - { - T mVal; - uint8_t mBuffer[sizeof(T)]; - } u; - u.mVal = maybeSwap(aSrc[i]); - memcpy(byteDestPtr, u.mBuffer, sizeof(T)); - byteDestPtr += sizeof(T); - } - } - - /** - * Write |aCount| elements to |aDest| in DestEndian format, using elements - * found at the unaligned address |aSrc| in SourceEndian format. - */ - template - static void copyAndSwapFrom(T* aDest, const void* aSrc, size_t aCount) - { - assertNoOverlap(aDest, aSrc, aCount * sizeof(T)); - assertAligned(aDest); - - if (SourceEndian == DestEndian) { - memcpy(aDest, aSrc, aCount * sizeof(T)); - return; - } - - const uint8_t* byteSrcPtr = static_cast(aSrc); - for (size_t i = 0; i < aCount; ++i) { - union - { - T mVal; - uint8_t mBuffer[sizeof(T)]; - } u; - memcpy(u.mBuffer, byteSrcPtr, sizeof(T)); - aDest[i] = maybeSwap(u.mVal); - byteSrcPtr += sizeof(T); - } - } -}; - -template -class Endian : private EndianUtils -{ -protected: - /** Read a uint16_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT uint16_t readUint16(const void* aPtr) - { - return read(aPtr); - } - - /** Read a uint32_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT uint32_t readUint32(const void* aPtr) - { - return read(aPtr); - } - - /** Read a uint64_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT uint64_t readUint64(const void* aPtr) - { - return read(aPtr); - } - - /** Read an int16_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT int16_t readInt16(const void* aPtr) - { - return read(aPtr); - } - - /** Read an int32_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT int32_t readInt32(const void* aPtr) - { - return read(aPtr); - } - - /** Read an int64_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT int64_t readInt64(const void* aPtr) - { - return read(aPtr); - } - - /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeUint16(void* aPtr, uint16_t aValue) - { - write(aPtr, aValue); - } - - /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeUint32(void* aPtr, uint32_t aValue) - { - write(aPtr, aValue); - } - - /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeUint64(void* aPtr, uint64_t aValue) - { - write(aPtr, aValue); - } - - /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeInt16(void* aPtr, int16_t aValue) - { - write(aPtr, aValue); - } - - /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeInt32(void* aPtr, int32_t aValue) - { - write(aPtr, aValue); - } - - /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeInt64(void* aPtr, int64_t aValue) - { - write(aPtr, aValue); - } - - /* - * Converts a value of type T to little-endian format. - * - * This function is intended for cases where you have data in your - * native-endian format and you need it to appear in little-endian - * format for transmission. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapToLittleEndian(T aValue) - { - return maybeSwap(aValue); - } - - /* - * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting - * them to little-endian format if ThisEndian is Big. - * As with memcpy, |aDest| and |aSrc| must not overlap. - */ - template - static void copyAndSwapToLittleEndian(void* aDest, const T* aSrc, - size_t aCount) - { - copyAndSwapTo(aDest, aSrc, aCount); - } - - /* - * Likewise, but converts values in place. - */ - template - static void swapToLittleEndianInPlace(T* aPtr, size_t aCount) - { - maybeSwapInPlace(aPtr, aCount); - } - - /* - * Converts a value of type T to big-endian format. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapToBigEndian(T aValue) - { - return maybeSwap(aValue); - } - - /* - * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting - * them to big-endian format if ThisEndian is Little. - * As with memcpy, |aDest| and |aSrc| must not overlap. - */ - template - static void copyAndSwapToBigEndian(void* aDest, const T* aSrc, - size_t aCount) - { - copyAndSwapTo(aDest, aSrc, aCount); - } - - /* - * Likewise, but converts values in place. - */ - template - static void swapToBigEndianInPlace(T* aPtr, size_t aCount) - { - maybeSwapInPlace(aPtr, aCount); - } - - /* - * Synonyms for the big-endian functions, for better readability - * in network code. - */ - - template - MOZ_WARN_UNUSED_RESULT static T swapToNetworkOrder(T aValue) - { - return swapToBigEndian(aValue); - } - - template - static void - copyAndSwapToNetworkOrder(void* aDest, const T* aSrc, size_t aCount) - { - copyAndSwapToBigEndian(aDest, aSrc, aCount); - } - - template - static void - swapToNetworkOrderInPlace(T* aPtr, size_t aCount) - { - swapToBigEndianInPlace(aPtr, aCount); - } - - /* - * Converts a value of type T from little-endian format. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapFromLittleEndian(T aValue) - { - return maybeSwap(aValue); - } - - /* - * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting - * them to little-endian format if ThisEndian is Big. - * As with memcpy, |aDest| and |aSrc| must not overlap. - */ - template - static void copyAndSwapFromLittleEndian(T* aDest, const void* aSrc, - size_t aCount) - { - copyAndSwapFrom(aDest, aSrc, aCount); - } - - /* - * Likewise, but converts values in place. - */ - template - static void swapFromLittleEndianInPlace(T* aPtr, size_t aCount) - { - maybeSwapInPlace(aPtr, aCount); - } - - /* - * Converts a value of type T from big-endian format. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapFromBigEndian(T aValue) - { - return maybeSwap(aValue); - } - - /* - * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting - * them to big-endian format if ThisEndian is Little. - * As with memcpy, |aDest| and |aSrc| must not overlap. - */ - template - static void copyAndSwapFromBigEndian(T* aDest, const void* aSrc, - size_t aCount) - { - copyAndSwapFrom(aDest, aSrc, aCount); - } - - /* - * Likewise, but converts values in place. - */ - template - static void swapFromBigEndianInPlace(T* aPtr, size_t aCount) - { - maybeSwapInPlace(aPtr, aCount); - } - - /* - * Synonyms for the big-endian functions, for better readability - * in network code. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapFromNetworkOrder(T aValue) - { - return swapFromBigEndian(aValue); - } - - template - static void copyAndSwapFromNetworkOrder(T* aDest, const void* aSrc, - size_t aCount) - { - copyAndSwapFromBigEndian(aDest, aSrc, aCount); - } - - template - static void swapFromNetworkOrderInPlace(T* aPtr, size_t aCount) - { - swapFromBigEndianInPlace(aPtr, aCount); - } - -private: - /** - * Read a value of type T, encoded in endianness ThisEndian from |aPtr|. - * Return that value encoded in native endianness. - */ - template - static T read(const void* aPtr) - { - union - { - T mVal; - uint8_t mBuffer[sizeof(T)]; - } u; - memcpy(u.mBuffer, aPtr, sizeof(T)); - return maybeSwap(u.mVal); - } - - /** - * Write a value of type T, in native endianness, to |aPtr|, in ThisEndian - * endianness. - */ - template - static void write(void* aPtr, T aValue) - { - T tmp = maybeSwap(aValue); - memcpy(aPtr, &tmp, sizeof(T)); - } - - Endian() = delete; - Endian(const Endian& aTther) = delete; - void operator=(const Endian& aOther) = delete; -}; - -template -class EndianReadWrite : public Endian -{ -private: - typedef Endian super; - -public: - using super::readUint16; - using super::readUint32; - using super::readUint64; - using super::readInt16; - using super::readInt32; - using super::readInt64; - using super::writeUint16; - using super::writeUint32; - using super::writeUint64; - using super::writeInt16; - using super::writeInt32; - using super::writeInt64; -}; - -} /* namespace detail */ - -class LittleEndian final : public detail::EndianReadWrite -{}; - -class BigEndian final : public detail::EndianReadWrite -{}; - -typedef BigEndian NetworkEndian; - -class NativeEndian final : public detail::Endian -{ -private: - typedef detail::Endian super; - -public: - /* - * These functions are intended for cases where you have data in your - * native-endian format and you need the data to appear in the appropriate - * endianness for transmission, serialization, etc. - */ - using super::swapToLittleEndian; - using super::copyAndSwapToLittleEndian; - using super::swapToLittleEndianInPlace; - using super::swapToBigEndian; - using super::copyAndSwapToBigEndian; - using super::swapToBigEndianInPlace; - using super::swapToNetworkOrder; - using super::copyAndSwapToNetworkOrder; - using super::swapToNetworkOrderInPlace; - - /* - * These functions are intended for cases where you have data in the - * given endianness (e.g. reading from disk or a file-format) and you - * need the data to appear in native-endian format for processing. - */ - using super::swapFromLittleEndian; - using super::copyAndSwapFromLittleEndian; - using super::swapFromLittleEndianInPlace; - using super::swapFromBigEndian; - using super::copyAndSwapFromBigEndian; - using super::swapFromBigEndianInPlace; - using super::swapFromNetworkOrder; - using super::copyAndSwapFromNetworkOrder; - using super::swapFromNetworkOrderInPlace; -}; - -#undef MOZ_NATIVE_ENDIANNESS - -} /* namespace mozilla */ - -#endif /* mozilla_Endian_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/EndianUtils.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/EndianUtils.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/EndianUtils.h @@ -0,0 +1,695 @@ +/* -*- 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/. */ + +/* Functions for reading and writing integers in various endiannesses. */ + +/* + * The classes LittleEndian and BigEndian expose static methods for + * reading and writing 16-, 32-, and 64-bit signed and unsigned integers + * in their respective endianness. The naming scheme is: + * + * {Little,Big}Endian::{read,write}{Uint,Int} + * + * For instance, LittleEndian::readInt32 will read a 32-bit signed + * integer from memory in little endian format. Similarly, + * BigEndian::writeUint16 will write a 16-bit unsigned integer to memory + * in big-endian format. + * + * The class NativeEndian exposes methods for conversion of existing + * data to and from the native endianness. These methods are intended + * for cases where data needs to be transferred, serialized, etc. + * swap{To,From}{Little,Big}Endian byteswap a single value if necessary. + * Bulk conversion functions are also provided which optimize the + * no-conversion-needed case: + * + * - copyAndSwap{To,From}{Little,Big}Endian; + * - swap{To,From}{Little,Big}EndianInPlace. + * + * The *From* variants are intended to be used for reading data and the + * *To* variants for writing data. + * + * Methods on NativeEndian work with integer data of any type. + * Floating-point data is not supported. + * + * For clarity in networking code, "Network" may be used as a synonym + * for "Big" in any of the above methods or class names. + * + * As an example, reading a file format header whose fields are stored + * in big-endian format might look like: + * + * class ExampleHeader + * { + * private: + * uint32_t mMagic; + * uint32_t mLength; + * uint32_t mTotalRecords; + * uint64_t mChecksum; + * + * public: + * ExampleHeader(const void* data) + * { + * const uint8_t* ptr = static_cast(data); + * mMagic = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); + * mLength = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); + * mTotalRecords = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); + * mChecksum = BigEndian::readUint64(ptr); + * } + * ... + * }; + */ + +#ifndef mozilla_EndianUtils_h +#define mozilla_EndianUtils_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Compiler.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/TypeTraits.h" + +#include +#include + +#if defined(_MSC_VER) +# include +# pragma intrinsic(_byteswap_ushort) +# pragma intrinsic(_byteswap_ulong) +# pragma intrinsic(_byteswap_uint64) +#endif + +#if defined(_WIN64) +# if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_) +# define MOZ_LITTLE_ENDIAN 1 +# else +# error "CPU type is unknown" +# endif +#elif defined(_WIN32) +# if defined(_M_IX86) +# define MOZ_LITTLE_ENDIAN 1 +# elif defined(_M_ARM) +# define MOZ_LITTLE_ENDIAN 1 +# else +# error "CPU type is unknown" +# endif +#elif defined(__APPLE__) || defined(__powerpc__) || defined(__ppc__) +# if __LITTLE_ENDIAN__ +# define MOZ_LITTLE_ENDIAN 1 +# elif __BIG_ENDIAN__ +# define MOZ_BIG_ENDIAN 1 +# endif +#elif defined(__GNUC__) && \ + defined(__BYTE_ORDER__) && \ + defined(__ORDER_LITTLE_ENDIAN__) && \ + defined(__ORDER_BIG_ENDIAN__) + /* + * Some versions of GCC provide architecture-independent macros for + * this. Yes, there are more than two values for __BYTE_ORDER__. + */ +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define MOZ_LITTLE_ENDIAN 1 +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define MOZ_BIG_ENDIAN 1 +# else +# error "Can't handle mixed-endian architectures" +# endif +/* + * We can't include useful headers like or + * here because they're not present on all platforms. Instead we have + * this big conditional that ideally will catch all the interesting + * cases. + */ +#elif defined(__sparc) || defined(__sparc__) || \ + defined(_POWER) || defined(__hppa) || \ + defined(_MIPSEB) || defined(__ARMEB__) || \ + defined(__s390__) || defined(__AARCH64EB__) || \ + (defined(__sh__) && defined(__LITTLE_ENDIAN__)) || \ + (defined(__ia64) && defined(__BIG_ENDIAN__)) +# define MOZ_BIG_ENDIAN 1 +#elif defined(__i386) || defined(__i386__) || \ + defined(__x86_64) || defined(__x86_64__) || \ + defined(_MIPSEL) || defined(__ARMEL__) || \ + defined(__alpha__) || defined(__AARCH64EL__) || \ + (defined(__sh__) && defined(__BIG_ENDIAN__)) || \ + (defined(__ia64) && !defined(__BIG_ENDIAN__)) +# define MOZ_LITTLE_ENDIAN 1 +#endif + +#if MOZ_BIG_ENDIAN +# define MOZ_LITTLE_ENDIAN 0 +#elif MOZ_LITTLE_ENDIAN +# define MOZ_BIG_ENDIAN 0 +#else +# error "Cannot determine endianness" +#endif + +#if defined(__clang__) +# if __has_builtin(__builtin_bswap16) +# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 +# endif +#elif defined(__GNUC__) +# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 +#elif defined(_MSC_VER) +# define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort +#endif + +namespace mozilla { + +namespace detail { + +/* + * We need wrappers here because free functions with default template + * arguments and/or partial specialization of function templates are not + * supported by all the compilers we use. + */ +template +struct Swapper; + +template +struct Swapper +{ + static T swap(T aValue) + { +#if defined(MOZ_HAVE_BUILTIN_BYTESWAP16) + return MOZ_HAVE_BUILTIN_BYTESWAP16(aValue); +#else + return T(((aValue & 0x00ff) << 8) | ((aValue & 0xff00) >> 8)); +#endif + } +}; + +template +struct Swapper +{ + static T swap(T aValue) + { +#if defined(__clang__) || defined(__GNUC__) + return T(__builtin_bswap32(aValue)); +#elif defined(_MSC_VER) + return T(_byteswap_ulong(aValue)); +#else + return T(((aValue & 0x000000ffU) << 24) | + ((aValue & 0x0000ff00U) << 8) | + ((aValue & 0x00ff0000U) >> 8) | + ((aValue & 0xff000000U) >> 24)); +#endif + } +}; + +template +struct Swapper +{ + static inline T swap(T aValue) + { +#if defined(__clang__) || defined(__GNUC__) + return T(__builtin_bswap64(aValue)); +#elif defined(_MSC_VER) + return T(_byteswap_uint64(aValue)); +#else + return T(((aValue & 0x00000000000000ffULL) << 56) | + ((aValue & 0x000000000000ff00ULL) << 40) | + ((aValue & 0x0000000000ff0000ULL) << 24) | + ((aValue & 0x00000000ff000000ULL) << 8) | + ((aValue & 0x000000ff00000000ULL) >> 8) | + ((aValue & 0x0000ff0000000000ULL) >> 24) | + ((aValue & 0x00ff000000000000ULL) >> 40) | + ((aValue & 0xff00000000000000ULL) >> 56)); +#endif + } +}; + +enum Endianness { Little, Big }; + +#if MOZ_BIG_ENDIAN +# define MOZ_NATIVE_ENDIANNESS detail::Big +#else +# define MOZ_NATIVE_ENDIANNESS detail::Little +#endif + +class EndianUtils +{ + /** + * Assert that the memory regions [aDest, aDest+aCount) and + * [aSrc, aSrc+aCount] do not overlap. aCount is given in bytes. + */ + static void assertNoOverlap(const void* aDest, const void* aSrc, + size_t aCount) + { + DebugOnly byteDestPtr = static_cast(aDest); + DebugOnly byteSrcPtr = static_cast(aSrc); + MOZ_ASSERT((byteDestPtr <= byteSrcPtr && + byteDestPtr + aCount <= byteSrcPtr) || + (byteSrcPtr <= byteDestPtr && + byteSrcPtr + aCount <= byteDestPtr)); + } + + template + static void assertAligned(T* aPtr) + { + MOZ_ASSERT((uintptr_t(aPtr) % sizeof(T)) == 0, "Unaligned pointer!"); + } + +protected: + /** + * Return |aValue| converted from SourceEndian encoding to DestEndian + * encoding. + */ + template + static inline T maybeSwap(T aValue) + { + if (SourceEndian == DestEndian) { + return aValue; + } + return Swapper::swap(aValue); + } + + /** + * Convert |aCount| elements at |aPtr| from SourceEndian encoding to + * DestEndian encoding. + */ + template + static inline void maybeSwapInPlace(T* aPtr, size_t aCount) + { + assertAligned(aPtr); + + if (SourceEndian == DestEndian) { + return; + } + for (size_t i = 0; i < aCount; i++) { + aPtr[i] = Swapper::swap(aPtr[i]); + } + } + + /** + * Write |aCount| elements to the unaligned address |aDest| in DestEndian + * format, using elements found at |aSrc| in SourceEndian format. + */ + template + static void copyAndSwapTo(void* aDest, const T* aSrc, size_t aCount) + { + assertNoOverlap(aDest, aSrc, aCount * sizeof(T)); + assertAligned(aSrc); + + if (SourceEndian == DestEndian) { + memcpy(aDest, aSrc, aCount * sizeof(T)); + return; + } + + uint8_t* byteDestPtr = static_cast(aDest); + for (size_t i = 0; i < aCount; ++i) { + union + { + T mVal; + uint8_t mBuffer[sizeof(T)]; + } u; + u.mVal = maybeSwap(aSrc[i]); + memcpy(byteDestPtr, u.mBuffer, sizeof(T)); + byteDestPtr += sizeof(T); + } + } + + /** + * Write |aCount| elements to |aDest| in DestEndian format, using elements + * found at the unaligned address |aSrc| in SourceEndian format. + */ + template + static void copyAndSwapFrom(T* aDest, const void* aSrc, size_t aCount) + { + assertNoOverlap(aDest, aSrc, aCount * sizeof(T)); + assertAligned(aDest); + + if (SourceEndian == DestEndian) { + memcpy(aDest, aSrc, aCount * sizeof(T)); + return; + } + + const uint8_t* byteSrcPtr = static_cast(aSrc); + for (size_t i = 0; i < aCount; ++i) { + union + { + T mVal; + uint8_t mBuffer[sizeof(T)]; + } u; + memcpy(u.mBuffer, byteSrcPtr, sizeof(T)); + aDest[i] = maybeSwap(u.mVal); + byteSrcPtr += sizeof(T); + } + } +}; + +template +class Endian : private EndianUtils +{ +protected: + /** Read a uint16_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE uint16_t readUint16(const void* aPtr) + { + return read(aPtr); + } + + /** Read a uint32_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE uint32_t readUint32(const void* aPtr) + { + return read(aPtr); + } + + /** Read a uint64_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE uint64_t readUint64(const void* aPtr) + { + return read(aPtr); + } + + /** Read an int16_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE int16_t readInt16(const void* aPtr) + { + return read(aPtr); + } + + /** Read an int32_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE int32_t readInt32(const void* aPtr) + { + return read(aPtr); + } + + /** Read an int64_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE int64_t readInt64(const void* aPtr) + { + return read(aPtr); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeUint16(void* aPtr, uint16_t aValue) + { + write(aPtr, aValue); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeUint32(void* aPtr, uint32_t aValue) + { + write(aPtr, aValue); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeUint64(void* aPtr, uint64_t aValue) + { + write(aPtr, aValue); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeInt16(void* aPtr, int16_t aValue) + { + write(aPtr, aValue); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeInt32(void* aPtr, int32_t aValue) + { + write(aPtr, aValue); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeInt64(void* aPtr, int64_t aValue) + { + write(aPtr, aValue); + } + + /* + * Converts a value of type T to little-endian format. + * + * This function is intended for cases where you have data in your + * native-endian format and you need it to appear in little-endian + * format for transmission. + */ + template + MOZ_MUST_USE static T swapToLittleEndian(T aValue) + { + return maybeSwap(aValue); + } + + /* + * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting + * them to little-endian format if ThisEndian is Big. + * As with memcpy, |aDest| and |aSrc| must not overlap. + */ + template + static void copyAndSwapToLittleEndian(void* aDest, const T* aSrc, + size_t aCount) + { + copyAndSwapTo(aDest, aSrc, aCount); + } + + /* + * Likewise, but converts values in place. + */ + template + static void swapToLittleEndianInPlace(T* aPtr, size_t aCount) + { + maybeSwapInPlace(aPtr, aCount); + } + + /* + * Converts a value of type T to big-endian format. + */ + template + MOZ_MUST_USE static T swapToBigEndian(T aValue) + { + return maybeSwap(aValue); + } + + /* + * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting + * them to big-endian format if ThisEndian is Little. + * As with memcpy, |aDest| and |aSrc| must not overlap. + */ + template + static void copyAndSwapToBigEndian(void* aDest, const T* aSrc, + size_t aCount) + { + copyAndSwapTo(aDest, aSrc, aCount); + } + + /* + * Likewise, but converts values in place. + */ + template + static void swapToBigEndianInPlace(T* aPtr, size_t aCount) + { + maybeSwapInPlace(aPtr, aCount); + } + + /* + * Synonyms for the big-endian functions, for better readability + * in network code. + */ + + template + MOZ_MUST_USE static T swapToNetworkOrder(T aValue) + { + return swapToBigEndian(aValue); + } + + template + static void + copyAndSwapToNetworkOrder(void* aDest, const T* aSrc, size_t aCount) + { + copyAndSwapToBigEndian(aDest, aSrc, aCount); + } + + template + static void + swapToNetworkOrderInPlace(T* aPtr, size_t aCount) + { + swapToBigEndianInPlace(aPtr, aCount); + } + + /* + * Converts a value of type T from little-endian format. + */ + template + MOZ_MUST_USE static T swapFromLittleEndian(T aValue) + { + return maybeSwap(aValue); + } + + /* + * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting + * them to little-endian format if ThisEndian is Big. + * As with memcpy, |aDest| and |aSrc| must not overlap. + */ + template + static void copyAndSwapFromLittleEndian(T* aDest, const void* aSrc, + size_t aCount) + { + copyAndSwapFrom(aDest, aSrc, aCount); + } + + /* + * Likewise, but converts values in place. + */ + template + static void swapFromLittleEndianInPlace(T* aPtr, size_t aCount) + { + maybeSwapInPlace(aPtr, aCount); + } + + /* + * Converts a value of type T from big-endian format. + */ + template + MOZ_MUST_USE static T swapFromBigEndian(T aValue) + { + return maybeSwap(aValue); + } + + /* + * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting + * them to big-endian format if ThisEndian is Little. + * As with memcpy, |aDest| and |aSrc| must not overlap. + */ + template + static void copyAndSwapFromBigEndian(T* aDest, const void* aSrc, + size_t aCount) + { + copyAndSwapFrom(aDest, aSrc, aCount); + } + + /* + * Likewise, but converts values in place. + */ + template + static void swapFromBigEndianInPlace(T* aPtr, size_t aCount) + { + maybeSwapInPlace(aPtr, aCount); + } + + /* + * Synonyms for the big-endian functions, for better readability + * in network code. + */ + template + MOZ_MUST_USE static T swapFromNetworkOrder(T aValue) + { + return swapFromBigEndian(aValue); + } + + template + static void copyAndSwapFromNetworkOrder(T* aDest, const void* aSrc, + size_t aCount) + { + copyAndSwapFromBigEndian(aDest, aSrc, aCount); + } + + template + static void swapFromNetworkOrderInPlace(T* aPtr, size_t aCount) + { + swapFromBigEndianInPlace(aPtr, aCount); + } + +private: + /** + * Read a value of type T, encoded in endianness ThisEndian from |aPtr|. + * Return that value encoded in native endianness. + */ + template + static T read(const void* aPtr) + { + union + { + T mVal; + uint8_t mBuffer[sizeof(T)]; + } u; + memcpy(u.mBuffer, aPtr, sizeof(T)); + return maybeSwap(u.mVal); + } + + /** + * Write a value of type T, in native endianness, to |aPtr|, in ThisEndian + * endianness. + */ + template + static void write(void* aPtr, T aValue) + { + T tmp = maybeSwap(aValue); + memcpy(aPtr, &tmp, sizeof(T)); + } + + Endian() = delete; + Endian(const Endian& aTther) = delete; + void operator=(const Endian& aOther) = delete; +}; + +template +class EndianReadWrite : public Endian +{ +private: + typedef Endian super; + +public: + using super::readUint16; + using super::readUint32; + using super::readUint64; + using super::readInt16; + using super::readInt32; + using super::readInt64; + using super::writeUint16; + using super::writeUint32; + using super::writeUint64; + using super::writeInt16; + using super::writeInt32; + using super::writeInt64; +}; + +} /* namespace detail */ + +class LittleEndian final : public detail::EndianReadWrite +{}; + +class BigEndian final : public detail::EndianReadWrite +{}; + +typedef BigEndian NetworkEndian; + +class NativeEndian final : public detail::Endian +{ +private: + typedef detail::Endian super; + +public: + /* + * These functions are intended for cases where you have data in your + * native-endian format and you need the data to appear in the appropriate + * endianness for transmission, serialization, etc. + */ + using super::swapToLittleEndian; + using super::copyAndSwapToLittleEndian; + using super::swapToLittleEndianInPlace; + using super::swapToBigEndian; + using super::copyAndSwapToBigEndian; + using super::swapToBigEndianInPlace; + using super::swapToNetworkOrder; + using super::copyAndSwapToNetworkOrder; + using super::swapToNetworkOrderInPlace; + + /* + * These functions are intended for cases where you have data in the + * given endianness (e.g. reading from disk or a file-format) and you + * need the data to appear in native-endian format for processing. + */ + using super::swapFromLittleEndian; + using super::copyAndSwapFromLittleEndian; + using super::swapFromLittleEndianInPlace; + using super::swapFromBigEndian; + using super::copyAndSwapFromBigEndian; + using super::swapFromBigEndianInPlace; + using super::swapFromNetworkOrder; + using super::copyAndSwapFromNetworkOrder; + using super::swapFromNetworkOrderInPlace; +}; + +#undef MOZ_NATIVE_ENDIANNESS + +} /* namespace mozilla */ + +#endif /* mozilla_EndianUtils_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/EnumSet.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/EnumSet.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/EnumSet.h @@ -12,6 +12,8 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" +#include + #include namespace mozilla { @@ -27,7 +29,9 @@ public: EnumSet() : mBitField(0) - { } + { + initVersion(); + } MOZ_IMPLICIT EnumSet(T aEnum) : mBitField(bitFor(aEnum)) @@ -36,30 +40,48 @@ EnumSet(T aEnum1, T aEnum2) : mBitField(bitFor(aEnum1) | bitFor(aEnum2)) - { } + { + initVersion(); + } EnumSet(T aEnum1, T aEnum2, T aEnum3) : mBitField(bitFor(aEnum1) | bitFor(aEnum2) | bitFor(aEnum3)) - { } + { + initVersion(); + } EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4) - : mBitField(bitFor(aEnum1) | - bitFor(aEnum2) | - bitFor(aEnum3) | - bitFor(aEnum4)) - { } + : mBitField(bitFor(aEnum1) | + bitFor(aEnum2) | + bitFor(aEnum3) | + bitFor(aEnum4)) + { + initVersion(); + } + + MOZ_IMPLICIT EnumSet(std::initializer_list list) + : mBitField(0) + { + for (auto value : list) { + (*this) += value; + } + initVersion(); + } EnumSet(const EnumSet& aEnumSet) - : mBitField(aEnumSet.mBitField) - { } + : mBitField(aEnumSet.mBitField) + { + initVersion(); + } /** * Add an element */ void operator+=(T aEnum) { + incVersion(); mBitField |= bitFor(aEnum); } @@ -78,6 +100,7 @@ */ void operator+=(const EnumSet aEnumSet) { + incVersion(); mBitField |= aEnumSet.mBitField; } @@ -96,6 +119,7 @@ */ void operator-=(T aEnum) { + incVersion(); mBitField &= ~(bitFor(aEnum)); } @@ -114,6 +138,7 @@ */ void operator-=(const EnumSet aEnumSet) { + incVersion(); mBitField &= ~(aEnumSet.mBitField); } @@ -132,6 +157,7 @@ */ void clear() { + incVersion(); mBitField = 0; } @@ -140,6 +166,7 @@ */ void operator&=(const EnumSet aEnumSet) { + incVersion(); mBitField &= aEnumSet.mBitField; } @@ -172,7 +199,7 @@ /** * Return the number of elements in the set. */ - uint8_t size() + uint8_t size() const { uint8_t count = 0; for (uint32_t bitField = mBitField; bitField; bitField >>= 1) { @@ -195,18 +222,121 @@ void deserialize(uint32_t aValue) { + incVersion(); mBitField = aValue; } + class ConstIterator + { + const EnumSet* mSet; + uint32_t mPos; +#ifdef DEBUG + uint64_t mVersion; +#endif + + void checkVersion() { + // Check that the set has not been modified while being iterated. + MOZ_ASSERT_IF(mSet, mSet->mVersion == mVersion); + } + + public: + ConstIterator(const EnumSet& aSet, uint32_t aPos) + : mSet(&aSet), mPos(aPos) + { +#ifdef DEBUG + mVersion = mSet->mVersion; +#endif + MOZ_ASSERT(aPos <= kMaxBits); + if (aPos != kMaxBits && !mSet->contains(T(mPos))) + ++*this; + } + + ConstIterator(const ConstIterator& aOther) + : mSet(aOther.mSet), mPos(aOther.mPos) + { +#ifdef DEBUG + mVersion = aOther.mVersion; + checkVersion(); +#endif + } + + ConstIterator(ConstIterator&& aOther) + : mSet(aOther.mSet), mPos(aOther.mPos) + { +#ifdef DEBUG + mVersion = aOther.mVersion; + checkVersion(); +#endif + aOther.mSet = nullptr; + } + + ~ConstIterator() { + checkVersion(); + } + + bool operator==(const ConstIterator& other) { + MOZ_ASSERT(mSet == other.mSet); + checkVersion(); + return mPos == other.mPos; + } + + bool operator!=(const ConstIterator& other) { + return !(*this == other); + } + + T operator*() { + MOZ_ASSERT(mSet); + MOZ_ASSERT(mPos < kMaxBits); + MOZ_ASSERT(mSet->contains(T(mPos))); + checkVersion(); + return T(mPos); + } + + ConstIterator& operator++() { + MOZ_ASSERT(mSet); + MOZ_ASSERT(mPos < kMaxBits); + checkVersion(); + do { + mPos++; + } while (mPos < kMaxBits && !mSet->contains(T(mPos))); + return *this; + } + }; + + ConstIterator begin() const { + return ConstIterator(*this, 0); + } + + ConstIterator end() const { + return ConstIterator(*this, kMaxBits); + } + private: static uint32_t bitFor(T aEnum) { uint32_t bitNumber = (uint32_t)aEnum; - MOZ_ASSERT(bitNumber < 32); + MOZ_ASSERT(bitNumber < kMaxBits); return 1U << bitNumber; } + void initVersion() { +#ifdef DEBUG + mVersion = 0; +#endif + } + + void incVersion() { +#ifdef DEBUG + mVersion++; +#endif + } + + static const size_t kMaxBits = 32; uint32_t mBitField; + +#ifdef DEBUG + uint64_t mVersion; +#endif }; } // namespace mozilla Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/EnumTypeTraits.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/EnumTypeTraits.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/EnumTypeTraits.h @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +/* Type traits for enums. */ + +#ifndef mozilla_EnumTypeTraits_h +#define mozilla_EnumTypeTraits_h + +#include + +namespace mozilla { + +namespace detail { + +template +struct EnumFitsWithinHelper; + +// Signed enum, signed storage. +template +struct EnumFitsWithinHelper + : public std::integral_constant +{}; + +// Signed enum, unsigned storage. +template +struct EnumFitsWithinHelper + : public std::integral_constant +{}; + +// Unsigned enum, signed storage. +template +struct EnumFitsWithinHelper + : public std::integral_constant +{}; + +// Unsigned enum, unsigned storage. +template +struct EnumFitsWithinHelper + : public std::integral_constant +{}; + +} // namespace detail + +/* + * Type trait that determines whether the enum type T can fit within the + * integral type Storage without data loss. This trait should be used with + * caution with an enum type whose underlying type has not been explicitly + * specified: for such enums, the C++ implementation is free to choose a type + * no smaller than int whose range encompasses all possible values of the enum. + * So for an enum with only small non-negative values, the underlying type may + * be either int or unsigned int, depending on the whims of the implementation. + */ +template +struct EnumTypeFitsWithin + : public detail::EnumFitsWithinHelper< + sizeof(T), + std::is_signed::type>::value, + sizeof(Storage), + std::is_signed::value + > +{ + static_assert(std::is_enum::value, "must provide an enum type"); + static_assert(std::is_integral::value, "must provide an integral type"); +}; + +} // namespace mozilla + +#endif /* mozilla_EnumTypeTraits_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/EnumeratedArray.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/EnumeratedArray.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/EnumeratedArray.h @@ -10,6 +10,7 @@ #define mozilla_EnumeratedArray_h #include "mozilla/Array.h" +#include "mozilla/Move.h" namespace mozilla { @@ -53,6 +54,11 @@ public: EnumeratedArray() {} + template + MOZ_IMPLICIT EnumeratedArray(Args&&... aArgs) + : mArray{mozilla::Forward(aArgs)...} + {} + explicit EnumeratedArray(const EnumeratedArray& aOther) { for (size_t i = 0; i < kSize; i++) { @@ -60,6 +66,13 @@ } } + EnumeratedArray(EnumeratedArray&& aOther) + { + for (size_t i = 0; i < kSize; i++) { + mArray[i] = Move(aOther.mArray[i]); + } + } + ValueType& operator[](IndexType aIndex) { return mArray[size_t(aIndex)]; Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/EnumeratedRange.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/EnumeratedRange.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/EnumeratedRange.h @@ -20,23 +20,26 @@ #ifndef mozilla_EnumeratedRange_h #define mozilla_EnumeratedRange_h -#include "mozilla/IntegerTypeTraits.h" +#include + #include "mozilla/ReverseIterator.h" namespace mozilla { namespace detail { -template +template class EnumeratedIterator { public: + typedef typename std::underlying_type::type IntTypeT; + template explicit EnumeratedIterator(EnumType aCurrent) : mCurrent(aCurrent) { } - template - explicit EnumeratedIterator(const EnumeratedIterator& aOther) + template + explicit EnumeratedIterator(const EnumeratedIterator& aOther) : mCurrent(aOther.mCurrent) { } EnumTypeT operator*() const { return mCurrent; } @@ -68,77 +71,77 @@ /* Comparison operators */ - template - friend bool operator==(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); - template - friend bool operator!=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); - template - friend bool operator<(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); - template - friend bool operator<=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); - template - friend bool operator>(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); - template - friend bool operator>=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); + template + friend bool operator==(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); + template + friend bool operator!=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); + template + friend bool operator<(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); + template + friend bool operator<=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); + template + friend bool operator>(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); + template + friend bool operator>=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); private: EnumTypeT mCurrent; }; -template -bool operator==(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator==(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent == aIter2.mCurrent; } -template -bool operator!=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator!=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent != aIter2.mCurrent; } -template -bool operator<(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator<(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent < aIter2.mCurrent; } -template -bool operator<=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator<=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent <= aIter2.mCurrent; } -template -bool operator>(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator>(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent > aIter2.mCurrent; } -template -bool operator>=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator>=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent >= aIter2.mCurrent; } -template +template class EnumeratedRange { public: - typedef EnumeratedIterator iterator; - typedef EnumeratedIterator const_iterator; + typedef EnumeratedIterator iterator; + typedef EnumeratedIterator const_iterator; typedef ReverseIterator reverse_iterator; typedef ReverseIterator const_reverse_iterator; @@ -171,38 +174,21 @@ #endif // Create a range to iterate from aBegin to aEnd, exclusive. -// -// (Once we can rely on std::underlying_type, we can remove the IntType -// template parameter.) -template -inline detail::EnumeratedRange +template +inline detail::EnumeratedRange MakeEnumeratedRange(EnumType aBegin, EnumType aEnd) { -#ifdef DEBUG - typedef typename MakeUnsigned::Type UnsignedType; -#endif - static_assert(sizeof(IntType) >= sizeof(EnumType), - "IntType should be at least as big as EnumType!"); MOZ_ASSERT(aBegin <= aEnd, "Cannot generate invalid, unbounded range!"); - MOZ_ASSERT_IF(aBegin < EnumType(0), IsSigned::value); - MOZ_ASSERT_IF(aBegin >= EnumType(0) && IsSigned::value, - UnsignedType(aEnd) <= UnsignedType(MaxValue::value)); - return detail::EnumeratedRange(aBegin, aEnd); + return detail::EnumeratedRange(aBegin, aEnd); } // Create a range to iterate from EnumType(0) to aEnd, exclusive. EnumType(0) // should exist, but note that there is no way for us to ensure that it does! -// Since the enumeration starts at EnumType(0), we know for sure that the values -// will be in range of our deduced IntType. template -inline detail::EnumeratedRange< - typename UnsignedStdintTypeForSize::Type, - EnumType> +inline detail::EnumeratedRange MakeEnumeratedRange(EnumType aEnd) { - return MakeEnumeratedRange< - typename UnsignedStdintTypeForSize::Type>(EnumType(0), - aEnd); + return MakeEnumeratedRange(EnumType(0), aEnd); } #ifdef __GNUC__ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/FastBernoulliTrial.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/FastBernoulliTrial.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/FastBernoulliTrial.h @@ -177,7 +177,10 @@ * random number generator; both may not be zero. */ FastBernoulliTrial(double aProbability, uint64_t aState0, uint64_t aState1) - : mGenerator(aState0, aState1) + : mProbability(0) + , mInvLogNotProbability(0) + , mGenerator(aState0, aState1) + , mSkipCount(0) { setProbability(aProbability); } Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/FloatingPoint.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/FloatingPoint.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/FloatingPoint.h @@ -117,7 +117,7 @@ /** Determines whether a float/double is NaN. */ template -static MOZ_ALWAYS_INLINE MOZ_CONSTEXPR bool +static MOZ_ALWAYS_INLINE bool IsNaN(T aValue) { /* @@ -186,6 +186,18 @@ return bits == Traits::kSignBit; } +/** Determines wether a float/double represents +0. */ +template +static MOZ_ALWAYS_INLINE bool +IsPositiveZero(T aValue) +{ + /* All bits are zero if the value is +0. */ + typedef FloatingPoint Traits; + typedef typename Traits::Bits Bits; + Bits bits = BitwiseCast(aValue); + return bits == 0; +} + /** * Returns 0 if a float/double is NaN or infinite; * otherwise, the float/double is returned. @@ -244,21 +256,65 @@ return BitwiseCast(Traits::kSignBit | Traits::kExponentBits); } +/** + * Computes the bit pattern for a NaN with the specified sign bit and + * significand bits. + */ +template::Bits Significand> +struct SpecificNaNBits +{ + using Traits = FloatingPoint; + + static_assert(SignBit == 0 || SignBit == 1, "bad sign bit"); + static_assert((Significand & ~Traits::kSignificandBits) == 0, + "significand must only have significand bits set"); + static_assert(Significand & Traits::kSignificandBits, + "significand must be nonzero"); -/** Constructs a NaN value with the specified sign bit and significand bits. */ + static constexpr typename Traits::Bits value = + (SignBit * Traits::kSignBit) | Traits::kExponentBits | Significand; +}; + +/** + * Constructs a NaN value with the specified sign bit and significand bits. + * + * There is also a variant that returns the value directly. In most cases, the + * two variants should be identical. However, in the specific case of x86 + * chips, the behavior differs: returning floating-point values directly is done + * through the x87 stack, and x87 loads and stores turn signaling NaNs into + * quiet NaNs... silently. Returning floating-point values via outparam, + * however, is done entirely within the SSE registers when SSE2 floating-point + * is enabled in the compiler, which has semantics-preserving behavior you would + * expect. + * + * If preserving the distinction between signaling NaNs and quiet NaNs is + * important to you, you should use the outparam version. In all other cases, + * you should use the direct return version. + */ template -static MOZ_ALWAYS_INLINE T -SpecificNaN(int signbit, typename FloatingPoint::Bits significand) +static MOZ_ALWAYS_INLINE void +SpecificNaN(int signbit, typename FloatingPoint::Bits significand, T* result) { typedef FloatingPoint Traits; MOZ_ASSERT(signbit == 0 || signbit == 1); MOZ_ASSERT((significand & ~Traits::kSignificandBits) == 0); MOZ_ASSERT(significand & Traits::kSignificandBits); - T t = BitwiseCast((signbit ? Traits::kSignBit : 0) | - Traits::kExponentBits | - significand); - MOZ_ASSERT(IsNaN(t)); + BitwiseCast((signbit ? Traits::kSignBit : 0) | + Traits::kExponentBits | + significand, + result); + MOZ_ASSERT(IsNaN(*result)); +} + +template +static MOZ_ALWAYS_INLINE T +SpecificNaN(int signbit, typename FloatingPoint::Bits significand) +{ + T t; + SpecificNaN(signbit, significand, &t); return t; } @@ -401,13 +457,6 @@ T aEpsilon = detail::FuzzyEqualsEpsilon::value()) { static_assert(IsFloatingPoint::value, "floating point type required"); - - // Short-circuit the common case in order to avoid the expensive operations - // below. - if (aValue1 == aValue2) { - return true; - } - // can't use std::min because of bug 965340 T smaller = Abs(aValue1) < Abs(aValue2) ? Abs(aValue1) : Abs(aValue2); return Abs(aValue1 - aValue2) <= aEpsilon * smaller; @@ -421,7 +470,7 @@ * * This function isn't inlined to avoid buggy optimizations by MSVC. */ -MOZ_WARN_UNUSED_RESULT +MOZ_MUST_USE extern MFBT_API bool IsFloat32Representable(double aFloat32); Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Function.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Function.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Function.h @@ -11,9 +11,10 @@ #include "mozilla/Attributes.h" // for MOZ_IMPLICIT #include "mozilla/Move.h" -#include "mozilla/UniquePtr.h" +#include "mozilla/RefCounted.h" +#include "mozilla/RefPtr.h" -// |Function| is a wrapper that can hold any type of callable +// |function| is a wrapper that can hold any type of callable // object that can be invoked in a way that's compatible with |Signature|. // The standard "type erasure" technique is used to avoid the type of the // wrapper depending on the concrete type of the wrapped callable. @@ -28,7 +29,7 @@ // this is a function type; it's not used in any way other than serving as a // vehicle to encode the return and argument types into a single type. // -// |Function| is default-constructible. A default-constructed instance is +// |function| is default-constructible. A default-constructed instance is // considered "empty". Invoking an empty instance is undefined behaviour. // An empty instance can be populated with a callable by assigning to it. // @@ -40,9 +41,11 @@ namespace detail { template -class FunctionImplBase +class FunctionImplBase : public mozilla::RefCounted> { public: + MOZ_DECLARE_REFCOUNTED_TYPENAME(FunctionImplBase) + virtual ~FunctionImplBase() {} virtual ReturnType call(Arguments... aArguments) = 0; }; @@ -126,32 +129,47 @@ // and |Arguments| in the definition of the specialization without having to // introspect |Signature|. template -class Function; +class function; template -class Function +class function { public: - Function() {} + function() {} // This constructor is implicit to match the interface of |std::function|. template - MOZ_IMPLICIT Function(const Callable& aCallable) - : mImpl(MakeUnique>(aCallable)) + MOZ_IMPLICIT function(const Callable& aCallable) + : mImpl(new detail::FunctionImpl(aCallable)) + {} + MOZ_IMPLICIT function(const function& aFunction) + : mImpl(aFunction.mImpl) + {} + MOZ_IMPLICIT function(decltype(nullptr)) {} // Move constructor and move assingment operator. // These should be generated automatically, but MSVC doesn't do that yet. - Function(Function&& aOther) : mImpl(Move(aOther.mImpl)) {} - Function& operator=(Function&& aOther) { + function(function&& aOther) : mImpl(Move(aOther.mImpl)) {} + function& operator=(function&& aOther) { mImpl = Move(aOther.mImpl); return *this; } template - Function& operator=(const Callable& aCallable) + function& operator=(const Callable& aCallable) { - mImpl = MakeUnique>(aCallable); + mImpl = new detail::FunctionImpl(aCallable); + return *this; + } + function& operator=(const function& aFunction) + { + mImpl = aFunction.mImpl; + return *this; + } + function& operator=(decltype(nullptr)) + { + mImpl = nullptr; return *this; } @@ -161,11 +179,45 @@ MOZ_ASSERT(mImpl); return mImpl->call(Forward(aArguments)...); } + + explicit operator bool() const + { + return bool(mImpl); + } + private: // TODO: Consider implementing a small object optimization. - UniquePtr> mImpl; + RefPtr> mImpl; }; +template +bool +operator==(const function& aX, decltype(nullptr)) +{ + return !aX; +} + +template +bool +operator==(decltype(nullptr), const function& aX) +{ + return !aX; +} + +template +bool +operator!=(const function& aX, decltype(nullptr)) +{ + return bool(aX); +} + +template +bool +operator!=(decltype(nullptr), const function& aX) +{ + return bool(aX); +} + } // namespace mozilla #endif /* mozilla_Function_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/HashFunctions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/HashFunctions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/HashFunctions.h @@ -10,7 +10,7 @@ * This file exports functions for hashing data down to a 32-bit value, * including: * - * - HashString Hash a char* or uint16_t/wchar_t* of known or unknown + * - HashString Hash a char* or char16_t/wchar_t* of known or unknown * length. * * - HashBytes Hash a byte array of known length. @@ -50,6 +50,7 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/Char16.h" +#include "mozilla/MathAlgorithms.h" #include "mozilla/Types.h" #include @@ -156,7 +157,7 @@ * convert to uint32_t, data pointers, and function pointers. */ template -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, A aA) { /* @@ -167,7 +168,7 @@ } template -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, A* aA) { /* @@ -181,14 +182,14 @@ } template<> -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, uintptr_t aA) { return detail::AddUintptrToHash(aHash, aA); } template -MOZ_WARN_UNUSED_RESULT uint32_t +MOZ_MUST_USE uint32_t AddToHash(uint32_t aHash, A aArg, Args... aArgs) { return AddToHash(AddToHash(aHash, aArg), aArgs...); @@ -202,7 +203,7 @@ * that x has already been hashed. */ template -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashGeneric(Args... aArgs) { return AddToHash(0, aArgs...); @@ -240,63 +241,49 @@ * If you have the string's length, you might as well call the overload which * includes the length. It may be marginally faster. */ -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const char* aStr) { return detail::HashUntilZero(reinterpret_cast(aStr)); } -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const char* aStr, size_t aLength) { return detail::HashKnownLength(reinterpret_cast(aStr), aLength); } -MOZ_WARN_UNUSED_RESULT +MOZ_MUST_USE inline uint32_t HashString(const unsigned char* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); } -MOZ_WARN_UNUSED_RESULT inline uint32_t -HashString(const uint16_t* aStr) -{ - return detail::HashUntilZero(aStr); -} - -MOZ_WARN_UNUSED_RESULT inline uint32_t -HashString(const uint16_t* aStr, size_t aLength) -{ - return detail::HashKnownLength(aStr, aLength); -} - -#ifdef MOZ_CHAR16_IS_NOT_WCHAR -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const char16_t* aStr) { return detail::HashUntilZero(aStr); } -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const char16_t* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); } -#endif /* - * On Windows, wchar_t (char16_t) is not the same as uint16_t, even though it's + * On Windows, wchar_t is not the same as char16_t, even though it's * the same width! */ #ifdef WIN32 -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const wchar_t* aStr) { return detail::HashUntilZero(aStr); } -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const wchar_t* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); @@ -309,9 +296,93 @@ * This hash walks word-by-word, rather than byte-by-byte, so you won't get the * same result out of HashBytes as you would out of HashString. */ -MOZ_WARN_UNUSED_RESULT extern MFBT_API uint32_t +MOZ_MUST_USE extern MFBT_API uint32_t HashBytes(const void* bytes, size_t aLength); +/** + * A pseudorandom function mapping 32-bit integers to 32-bit integers. + * + * This is for when you're feeding private data (like pointer values or credit + * card numbers) to a non-crypto hash function (like HashBytes) and then using + * the hash code for something that untrusted parties could observe (like a JS + * Map). Plug in a HashCodeScrambler before that last step to avoid leaking the + * private data. + * + * By itself, this does not prevent hash-flooding DoS attacks, because an + * attacker can still generate many values with exactly equal hash codes by + * attacking the non-crypto hash function alone. Equal hash codes will, of + * course, still be equal however much you scramble them. + * + * The algorithm is SipHash-1-3. See . + */ +class HashCodeScrambler +{ + struct SipHasher; + + uint64_t mK0, mK1; + +public: + /** Creates a new scrambler with the given 128-bit key. */ + constexpr HashCodeScrambler(uint64_t aK0, uint64_t aK1) : mK0(aK0), mK1(aK1) {} + + /** + * Scramble a hash code. Always produces the same result for the same + * combination of key and hash code. + */ + uint32_t scramble(uint32_t aHashCode) const + { + SipHasher hasher(mK0, mK1); + return uint32_t(hasher.sipHash(aHashCode)); + } + +private: + struct SipHasher + { + SipHasher(uint64_t aK0, uint64_t aK1) + { + // 1. Initialization. + mV0 = aK0 ^ UINT64_C(0x736f6d6570736575); + mV1 = aK1 ^ UINT64_C(0x646f72616e646f6d); + mV2 = aK0 ^ UINT64_C(0x6c7967656e657261); + mV3 = aK1 ^ UINT64_C(0x7465646279746573); + } + + uint64_t sipHash(uint64_t aM) + { + // 2. Compression. + mV3 ^= aM; + sipRound(); + mV0 ^= aM; + + // 3. Finalization. + mV2 ^= 0xff; + for (int i = 0; i < 3; i++) + sipRound(); + return mV0 ^ mV1 ^ mV2 ^ mV3; + } + + void sipRound() + { + mV0 += mV1; + mV1 = RotateLeft(mV1, 13); + mV1 ^= mV0; + mV0 = RotateLeft(mV0, 32); + mV2 += mV3; + mV3 = RotateLeft(mV3, 16); + mV3 ^= mV2; + mV0 += mV3; + mV3 = RotateLeft(mV3, 21); + mV3 ^= mV0; + mV2 += mV1; + mV1 = RotateLeft(mV1, 17); + mV1 ^= mV2; + mV2 = RotateLeft(mV2, 32); + } + + uint64_t mV0, mV1, mV2, mV3; + }; +}; + } /* namespace mozilla */ #endif /* __cplusplus */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/IndexSequence.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/IndexSequence.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/IndexSequence.h @@ -74,7 +74,7 @@ template struct IndexSequence { - static MOZ_CONSTEXPR size_t Size() { return sizeof...(Indices); } + static constexpr size_t Size() { return sizeof...(Indices); } }; namespace detail { Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/JSONWriter.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/JSONWriter.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/JSONWriter.h @@ -95,7 +95,7 @@ #include "mozilla/double-conversion.h" #include "mozilla/IntegerPrintfMacros.h" #include "mozilla/PodOperations.h" -#include "mozilla/Snprintf.h" +#include "mozilla/Sprintf.h" #include "mozilla/UniquePtr.h" #include "mozilla/Vector.h" @@ -389,7 +389,7 @@ void IntProperty(const char* aName, int64_t aInt) { char buf[64]; - snprintf_literal(buf, "%" PRId64, aInt); + SprintfLiteral(buf, "%" PRId64, aInt); Scalar(aName, buf); } Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/LinkedList.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/LinkedList.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/LinkedList.h @@ -68,17 +68,65 @@ #include "mozilla/Attributes.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Move.h" +#include "mozilla/RefPtr.h" #ifdef __cplusplus namespace mozilla { template +class LinkedListElement; + +namespace detail { + +/** + * LinkedList supports refcounted elements using this adapter class. Clients + * using LinkedList> will get a data structure that holds a strong + * reference to T as long as T is in the list. + */ +template +struct LinkedListElementTraits +{ + typedef T* RawType; + typedef const T* ConstRawType; + typedef T* ClientType; + typedef const T* ConstClientType; + + // These static methods are called when an element is added to or removed from + // a linked list. It can be used to keep track ownership in lists that are + // supposed to own their elements. If elements are transferred from one list + // to another, no enter or exit calls happen since the elements still belong + // to a list. + static void enterList(LinkedListElement* elt) {} + static void exitList(LinkedListElement* elt) {} +}; + +template +struct LinkedListElementTraits> +{ + typedef T* RawType; + typedef const T* ConstRawType; + typedef RefPtr ClientType; + typedef RefPtr ConstClientType; + + static void enterList(LinkedListElement>* elt) { elt->asT()->AddRef(); } + static void exitList(LinkedListElement>* elt) { elt->asT()->Release(); } +}; + +} /* namespace detail */ + +template class LinkedList; template class LinkedListElement { + typedef typename detail::LinkedListElementTraits Traits; + typedef typename Traits::RawType RawType; + typedef typename Traits::ConstRawType ConstRawType; + typedef typename Traits::ClientType ClientType; + typedef typename Traits::ConstClientType ConstClientType; + /* * It's convenient that we return nullptr when getNext() or getPrevious() * hits the end of the list, but doing so costs an extra word of storage in @@ -125,34 +173,23 @@ mIsSentinel(false) { } - LinkedListElement(LinkedListElement&& other) - : mIsSentinel(other.mIsSentinel) + /* + * Moves |aOther| into |*this|. If |aOther| is already in a list, then + * |aOther| is removed from the list and replaced by |*this|. + */ + LinkedListElement(LinkedListElement&& aOther) + : mIsSentinel(aOther.mIsSentinel) { - if (!other.isInList()) { - mNext = this; - mPrev = this; - return; - } - - MOZ_ASSERT(other.mNext->mPrev == &other); - MOZ_ASSERT(other.mPrev->mNext == &other); - - /* - * Initialize |this| with |other|'s mPrev/mNext pointers, and adjust those - * element to point to this one. - */ - mNext = other.mNext; - mPrev = other.mPrev; - - mNext->mPrev = this; - mPrev->mNext = this; + adjustLinkForMove(Move(aOther)); + } - /* - * Adjust |other| so it doesn't think it's in a list. This makes it - * safely destructable. - */ - other.mNext = &other; - other.mPrev = &other; + LinkedListElement& operator=(LinkedListElement&& aOther) + { + MOZ_ASSERT(mIsSentinel == aOther.mIsSentinel, "Mismatch NodeKind!"); + MOZ_ASSERT(!isInList(), + "Assigning to an element in a list messes up that list!"); + adjustLinkForMove(Move(aOther)); + return *this; } ~LinkedListElement() @@ -166,21 +203,21 @@ * Get the next element in the list, or nullptr if this is the last element * in the list. */ - T* getNext() { return mNext->asT(); } - const T* getNext() const { return mNext->asT(); } + RawType getNext() { return mNext->asT(); } + ConstRawType getNext() const { return mNext->asT(); } /* * Get the previous element in the list, or nullptr if this is the first * element in the list. */ - T* getPrevious() { return mPrev->asT(); } - const T* getPrevious() const { return mPrev->asT(); } + RawType getPrevious() { return mPrev->asT(); } + ConstRawType getPrevious() const { return mPrev->asT(); } /* * Insert aElem after this element in the list. |this| must be part of a * linked list when you call setNext(); otherwise, this method will assert. */ - void setNext(T* aElem) + void setNext(RawType aElem) { MOZ_ASSERT(isInList()); setNextUnsafe(aElem); @@ -191,7 +228,7 @@ * linked list when you call setPrevious(); otherwise, this method will * assert. */ - void setPrevious(T* aElem) + void setPrevious(RawType aElem) { MOZ_ASSERT(isInList()); setPreviousUnsafe(aElem); @@ -209,6 +246,32 @@ mNext->mPrev = mPrev; mNext = this; mPrev = this; + + Traits::exitList(this); + } + + /* + * Remove this element from the list containing it. Returns a pointer to the + * element that follows this element (before it was removed). This method + * asserts if the element does not belong to a list. + */ + ClientType removeAndGetNext() + { + ClientType r = getNext(); + remove(); + return r; + } + + /* + * Remove this element from the list containing it. Returns a pointer to the + * previous element in the containing list (before the removal). This method + * asserts if the element does not belong to a list. + */ + ClientType removeAndGetPrevious() + { + ClientType r = getPrevious(); + remove(); + return r; } /* @@ -232,36 +295,37 @@ private: friend class LinkedList; + friend struct detail::LinkedListElementTraits; - enum NodeKind { - NODE_KIND_NORMAL, - NODE_KIND_SENTINEL + enum class NodeKind { + Normal, + Sentinel }; explicit LinkedListElement(NodeKind nodeKind) : mNext(this), mPrev(this), - mIsSentinel(nodeKind == NODE_KIND_SENTINEL) + mIsSentinel(nodeKind == NodeKind::Sentinel) { } /* * Return |this| cast to T* if we're a normal node, or return nullptr if * we're a sentinel node. */ - T* asT() + RawType asT() { - return mIsSentinel ? nullptr : static_cast(this); + return mIsSentinel ? nullptr : static_cast(this); } - const T* asT() const + ConstRawType asT() const { - return mIsSentinel ? nullptr : static_cast(this); + return mIsSentinel ? nullptr : static_cast(this); } /* * Insert aElem after this element, but don't check that this element is in * the list. This is called by LinkedList::insertFront(). */ - void setNextUnsafe(T* aElem) + void setNextUnsafe(RawType aElem) { LinkedListElement *listElem = static_cast(aElem); MOZ_ASSERT(!listElem->isInList()); @@ -270,13 +334,15 @@ listElem->mPrev = this; this->mNext->mPrev = listElem; this->mNext = listElem; + + Traits::enterList(aElem); } /* * Insert aElem before this element, but don't check that this element is in * the list. This is called by LinkedList::insertBack(). */ - void setPreviousUnsafe(T* aElem) + void setPreviousUnsafe(RawType aElem) { LinkedListElement* listElem = static_cast*>(aElem); MOZ_ASSERT(!listElem->isInList()); @@ -285,9 +351,51 @@ listElem->mPrev = this->mPrev; this->mPrev->mNext = listElem; this->mPrev = listElem; + + Traits::enterList(aElem); + } + + /* + * Adjust mNext and mPrev for implementing move constructor and move + * assignment. + */ + void adjustLinkForMove(LinkedListElement&& aOther) + { + if (!aOther.isInList()) { + mNext = this; + mPrev = this; + return; + } + + if (!mIsSentinel) { + Traits::enterList(this); + } + + MOZ_ASSERT(aOther.mNext->mPrev == &aOther); + MOZ_ASSERT(aOther.mPrev->mNext == &aOther); + + /* + * Initialize |this| with |aOther|'s mPrev/mNext pointers, and adjust those + * element to point to this one. + */ + mNext = aOther.mNext; + mPrev = aOther.mPrev; + + mNext->mPrev = this; + mPrev->mNext = this; + + /* + * Adjust |aOther| so it doesn't think it's in a list. This makes it + * safely destructable. + */ + aOther.mNext = &aOther; + aOther.mPrev = &aOther; + + if (!mIsSentinel) { + Traits::exitList(&aOther); + } } -private: LinkedListElement& operator=(const LinkedListElement& aOther) = delete; LinkedListElement(const LinkedListElement& aOther) = delete; }; @@ -296,16 +404,22 @@ class LinkedList { private: + typedef typename detail::LinkedListElementTraits Traits; + typedef typename Traits::RawType RawType; + typedef typename Traits::ConstRawType ConstRawType; + typedef typename Traits::ClientType ClientType; + typedef typename Traits::ConstClientType ConstClientType; + LinkedListElement sentinel; public: class Iterator { - T* mCurrent; + RawType mCurrent; public: - explicit Iterator(T* aCurrent) : mCurrent(aCurrent) {} + explicit Iterator(RawType aCurrent) : mCurrent(aCurrent) {} - T* operator *() const { + RawType operator *() const { return mCurrent; } @@ -319,18 +433,30 @@ } }; - LinkedList() : sentinel(LinkedListElement::NODE_KIND_SENTINEL) { } + LinkedList() : sentinel(LinkedListElement::NodeKind::Sentinel) { } LinkedList(LinkedList&& aOther) : sentinel(mozilla::Move(aOther.sentinel)) { } - ~LinkedList() { MOZ_ASSERT(isEmpty()); } + LinkedList& operator=(LinkedList&& aOther) + { + MOZ_ASSERT(isEmpty(), "Assigning to a non-empty list leaks elements in that list!"); + sentinel = mozilla::Move(aOther.sentinel); + return *this; + } + + ~LinkedList() { + MOZ_ASSERT(isEmpty(), + "failing this assertion means this LinkedList's creator is " + "buggy: it should have removed all this list's elements before " + "the list's destruction"); + } /* * Add aElem to the front of the list. */ - void insertFront(T* aElem) + void insertFront(RawType aElem) { /* Bypass setNext()'s this->isInList() assertion. */ sentinel.setNextUnsafe(aElem); @@ -339,7 +465,7 @@ /* * Add aElem to the back of the list. */ - void insertBack(T* aElem) + void insertBack(RawType aElem) { sentinel.setPreviousUnsafe(aElem); } @@ -347,24 +473,24 @@ /* * Get the first element of the list, or nullptr if the list is empty. */ - T* getFirst() { return sentinel.getNext(); } - const T* getFirst() const { return sentinel.getNext(); } + RawType getFirst() { return sentinel.getNext(); } + ConstRawType getFirst() const { return sentinel.getNext(); } /* * Get the last element of the list, or nullptr if the list is empty. */ - T* getLast() { return sentinel.getPrevious(); } - const T* getLast() const { return sentinel.getPrevious(); } + RawType getLast() { return sentinel.getPrevious(); } + ConstRawType getLast() const { return sentinel.getPrevious(); } /* * Get and remove the first element of the list. If the list is empty, * return nullptr. */ - T* popFirst() + ClientType popFirst() { - T* ret = sentinel.getNext(); + ClientType ret = sentinel.getNext(); if (ret) { - static_cast*>(ret)->remove(); + static_cast*>(RawType(ret))->remove(); } return ret; } @@ -373,11 +499,11 @@ * Get and remove the last element of the list. If the list is empty, * return nullptr. */ - T* popLast() + ClientType popLast() { - T* ret = sentinel.getPrevious(); + ClientType ret = sentinel.getPrevious(); if (ret) { - static_cast*>(ret)->remove(); + static_cast*>(RawType(ret))->remove(); } return ret; } @@ -498,10 +624,10 @@ private: friend class LinkedListElement; - void assertContains(const T* aValue) const + void assertContains(const RawType aValue) const { #ifdef DEBUG - for (const T* elem = getFirst(); elem; elem = elem->getNext()) { + for (ConstRawType elem = getFirst(); elem; elem = elem->getNext()) { if (elem == aValue) { return; } Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/MacroArgs.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/MacroArgs.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/MacroArgs.h @@ -11,6 +11,10 @@ #ifndef mozilla_MacroArgs_h #define mozilla_MacroArgs_h +// Concatenates pre-processor tokens in a way that can be used with __LINE__. +#define MOZ_CONCAT2(x, y) x ## y +#define MOZ_CONCAT(x, y) MOZ_CONCAT2(x, y) + /* * MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) counts the number of variadic * arguments and prefixes it with |aPrefix|. For example: Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/MathAlgorithms.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/MathAlgorithms.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/MathAlgorithms.h @@ -340,7 +340,7 @@ return detail::CountPopulation32(aValue); } -/** Analogous to CoutPopulation32, but for 64-bit numbers */ +/** Analogous to CountPopulation32, but for 64-bit numbers */ inline uint_fast8_t CountPopulation64(uint64_t aValue) { @@ -515,7 +515,7 @@ * Zero is not an integer power of two. (-Inf is not an integer) */ template -inline bool +constexpr bool IsPowerOfTwo(T x) { static_assert(IsUnsigned::value, Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Maybe.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Maybe.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Maybe.h @@ -16,6 +16,7 @@ #include "mozilla/TypeTraits.h" #include // for placement new +#include namespace mozilla { @@ -101,6 +102,26 @@ } } + /** + * Maybe can be copy-constructed from a Maybe if U* and T* are + * compatible, or from Maybe. + */ + template::value && + (std::is_same::value || + (std::is_pointer::value && + std::is_base_of::type, + typename std::remove_pointer::type>::value))>::type> + MOZ_IMPLICIT + Maybe(const Maybe& aOther) + : mIsSome(false) + { + if (aOther.isSome()) { + emplace(*aOther); + } + } + Maybe(Maybe&& aOther) : mIsSome(false) { @@ -110,6 +131,27 @@ } } + /** + * Maybe can be move-constructed from a Maybe if U* and T* are + * compatible, or from Maybe. + */ + template::value && + (std::is_same::value || + (std::is_pointer::value && + std::is_base_of::type, + typename std::remove_pointer::type>::value))>::type> + MOZ_IMPLICIT + Maybe(Maybe&& aOther) + : mIsSome(false) + { + if (aOther.isSome()) { + emplace(Move(*aOther)); + aOther.reset(); + } + } + Maybe& operator=(const Maybe& aOther) { if (&aOther != this) { @@ -324,53 +366,57 @@ /* If |isSome()|, runs the provided function or functor on the contents of * this Maybe. */ - template - void apply(F&& aFunc, Args&&... aArgs) + template + Maybe& apply(Func aFunc) { if (isSome()) { - aFunc(ref(), Forward(aArgs)...); + aFunc(ref()); } + return *this; } - template - void apply(F&& aFunc, Args&&... aArgs) const + template + const Maybe& apply(Func aFunc) const { if (isSome()) { - aFunc(ref(), Forward(aArgs)...); + aFunc(ref()); } + return *this; } /* * If |isSome()|, runs the provided function and returns the result wrapped * in a Maybe. If |isNothing()|, returns an empty Maybe value. */ - template - Maybe map(R (*aFunc)(T&, FArgs...), Args&&... aArgs) + template + auto map(Func aFunc) -> Maybe>().ref()))> { + using ReturnType = decltype(aFunc(ref())); if (isSome()) { - Maybe val; - val.emplace(aFunc(ref(), Forward(aArgs)...)); + Maybe val; + val.emplace(aFunc(ref())); return val; } - return Maybe(); + return Maybe(); } - template - Maybe map(R (*aFunc)(const T&, FArgs...), Args&&... aArgs) const + template + auto map(Func aFunc) const -> Maybe>().ref()))> { + using ReturnType = decltype(aFunc(ref())); if (isSome()) { - Maybe val; - val.emplace(aFunc(ref(), Forward(aArgs)...)); + Maybe val; + val.emplace(aFunc(ref())); return val; } - return Maybe(); + return Maybe(); } /* If |isSome()|, empties this Maybe and destroys its contents. */ void reset() { if (isSome()) { - ref().~T(); + ref().T::~T(); mIsSome = false; } } Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/NotNull.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/NotNull.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/NotNull.h @@ -0,0 +1,209 @@ +/* -*- 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/. */ + +#ifndef mozilla_NotNull_h +#define mozilla_NotNull_h + +// It's often unclear if a particular pointer, be it raw (T*) or smart +// (RefPtr, nsCOMPtr, etc.) can be null. This leads to missing null +// checks (which can cause crashes) and unnecessary null checks (which clutter +// the code). +// +// C++ has a built-in alternative that avoids these problems: references. This +// module defines another alternative, NotNull, which can be used in cases +// where references are not suitable. +// +// In the comments below we use the word "handle" to cover all varieties of +// pointers and references. +// +// References +// ---------- +// References are always non-null. (You can do |T& r = *p;| where |p| is null, +// but that's undefined behaviour. C++ doesn't provide any built-in, ironclad +// guarantee of non-nullness.) +// +// A reference works well when you need a temporary handle to an existing +// single object, e.g. for passing a handle to a function, or as a local handle +// within another object. (In Rust parlance, this is a "borrow".) +// +// A reference is less appropriate in the following cases. +// +// - As a primary handle to an object. E.g. code such as this is possible but +// strange: |T& t = *new T(); ...; delete &t;| +// +// - As a handle to an array. It's common for |T*| to refer to either a single +// |T| or an array of |T|, but |T&| cannot refer to an array of |T| because +// you can't index off a reference (at least, not without first converting it +// to a pointer). +// +// - When the handle identity is meaningful, e.g. if you have a hashtable of +// handles, because you have to use |&| on the reference to convert it to a +// pointer. +// +// - Some people don't like using non-const references as function parameters, +// because it is not clear at the call site that the argument might be +// modified. +// +// - When you need "smart" behaviour. E.g. we lack reference equivalents to +// RefPtr and nsCOMPtr. +// +// - When interfacing with code that uses pointers a lot, sometimes using a +// reference just feels like an odd fit. +// +// Furthermore, a reference is impossible in the following cases. +// +// - When the handle is rebound to another object. References don't allow this. +// +// - When the handle has type |void|. |void&| is not allowed. +// +// NotNull is an alternative that can be used in any of the above cases except +// for the last one, where the handle type is |void|. See below. + +#include "mozilla/Assertions.h" + +namespace mozilla { + +// NotNull can be used to wrap a "base" pointer (raw or smart) to indicate it +// is not null. Some examples: +// +// - NotNull +// - NotNull> +// - NotNull> +// +// NotNull has the following notable properties. +// +// - It has zero space overhead. +// +// - It must be initialized explicitly. There is no default initialization. +// +// - It auto-converts to the base pointer type. +// +// - It does not auto-convert from a base pointer. Implicit conversion from a +// less-constrained type (e.g. T*) to a more-constrained type (e.g. +// NotNull) is dangerous. Creation and assignment from a base pointer can +// only be done with WrapNotNull(), which makes them impossible to overlook, +// both when writing and reading code. +// +// - When initialized (or assigned) it is checked, and if it is null we abort. +// This guarantees that it cannot be null. +// +// - |operator bool()| is deleted. This means you cannot check a NotNull in a +// boolean context, which eliminates the possibility of unnecessary null +// checks. +// +// NotNull currently doesn't work with UniquePtr. See +// https://github.com/Microsoft/GSL/issues/89 for some discussion. +// +template +class NotNull +{ + template friend NotNull WrapNotNull(U aBasePtr); + + T mBasePtr; + + // This constructor is only used by WrapNotNull(). + template + explicit NotNull(U aBasePtr) : mBasePtr(aBasePtr) {} + +public: + // Disallow default construction. + NotNull() = delete; + + // Construct/assign from another NotNull with a compatible base pointer type. + template + MOZ_IMPLICIT NotNull(const NotNull& aOther) : mBasePtr(aOther.get()) {} + + // Default copy/move construction and assignment. + NotNull(const NotNull&) = default; + NotNull& operator=(const NotNull&) = default; + NotNull(NotNull&&) = default; + NotNull& operator=(NotNull&&) = default; + + // Disallow null checks, which are unnecessary for this type. + explicit operator bool() const = delete; + + // Explicit conversion to a base pointer. Use only to resolve ambiguity or to + // get a castable pointer. + const T& get() const { return mBasePtr; } + + // Implicit conversion to a base pointer. Preferable to get(). + operator const T&() const { return get(); } + + // Dereference operators. + const T& operator->() const { return get(); } + decltype(*mBasePtr) operator*() const { return *mBasePtr; } +}; + +template +NotNull +WrapNotNull(const T aBasePtr) +{ + NotNull notNull(aBasePtr); + MOZ_RELEASE_ASSERT(aBasePtr); + return notNull; +} + +// Compare two NotNulls. +template +inline bool +operator==(const NotNull& aLhs, const NotNull& aRhs) +{ + return aLhs.get() == aRhs.get(); +} +template +inline bool +operator!=(const NotNull& aLhs, const NotNull& aRhs) +{ + return aLhs.get() != aRhs.get(); +} + +// Compare a NotNull to a base pointer. +template +inline bool +operator==(const NotNull& aLhs, const U& aRhs) +{ + return aLhs.get() == aRhs; +} +template +inline bool +operator!=(const NotNull& aLhs, const U& aRhs) +{ + return aLhs.get() != aRhs; +} + +// Compare a base pointer to a NotNull. +template +inline bool +operator==(const T& aLhs, const NotNull& aRhs) +{ + return aLhs == aRhs.get(); +} +template +inline bool +operator!=(const T& aLhs, const NotNull& aRhs) +{ + return aLhs != aRhs.get(); +} + +// Disallow comparing a NotNull to a nullptr. +template +bool +operator==(const NotNull&, decltype(nullptr)) = delete; +template +bool +operator!=(const NotNull&, decltype(nullptr)) = delete; + +// Disallow comparing a nullptr to a NotNull. +template +bool +operator==(decltype(nullptr), const NotNull&) = delete; +template +bool +operator!=(decltype(nullptr), const NotNull&) = delete; + +} // namespace mozilla + +#endif /* mozilla_NotNull_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/NumericLimits.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/NumericLimits.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/NumericLimits.h @@ -1,40 +0,0 @@ -/* -*- 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/. */ - -/* Compatibility with std::numeric_limits. */ - -#ifndef mozilla_NumericLimits_h -#define mozilla_NumericLimits_h - -#include "mozilla/Char16.h" - -#include -#include - -namespace mozilla { - -/** - * The NumericLimits class provides a compatibility layer with - * std::numeric_limits for char16_t, otherwise it is exactly the same as - * std::numeric_limits. Code which does not need std::numeric_limits - * should avoid using NumericLimits. - */ -template -class NumericLimits : public std::numeric_limits -{ -}; - -#ifdef MOZ_CHAR16_IS_NOT_WCHAR -template<> -class NumericLimits : public std::numeric_limits -{ - // char16_t and uint16_t numeric limits should be exactly the same. -}; -#endif - -} // namespace mozilla - -#endif /* mozilla_NumericLimits_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/OperatorNewExtensions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/OperatorNewExtensions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/OperatorNewExtensions.h @@ -0,0 +1,52 @@ +/* -*- 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 version of |operator new| that eschews mandatory null-checks. */ + +#ifndef mozilla_OperatorNewExtensions_h +#define mozilla_OperatorNewExtensions_h + +#include "mozilla/Assertions.h" + +// Credit goes to WebKit for this implementation, cf. +// https://bugs.webkit.org/show_bug.cgi?id=74676 +namespace mozilla { +enum NotNullTag { + KnownNotNull, +}; +} // namespace mozilla + +/* + * The logic here is a little subtle. [expr.new] states that if the allocation + * function being called returns null, then object initialization must not be + * done, and the entirety of the new expression must return null. Non-throwing + * (noexcept) functions are defined to return null to indicate failure. The + * standard placement operator new is defined in such a way, and so it requires + * a null check, even when that null check would be extraneous. Functions + * declared without such a specification are defined to throw std::bad_alloc if + * they fail, and return a non-null pointer otherwise. We compile without + * exceptions, so any placement new overload we define that doesn't declare + * itself as noexcept must therefore avoid generating a null check. Below is + * just such an overload. + * + * You might think that MOZ_NONNULL might perform the same function, but + * MOZ_NONNULL isn't supported on all of our compilers, and even when it is + * supported, doesn't work on all the versions we support. And even keeping + * those limitations in mind, we can't put MOZ_NONNULL on the global, + * standardized placement new function in any event. + * + * We deliberately don't add MOZ_NONNULL(3) to tag |p| as non-null, to benefit + * hypothetical static analyzers. Doing so makes |MOZ_ASSERT(p)|'s internal + * test vacuous, and some compilers warn about such vacuous tests. + */ +inline void* +operator new(size_t, mozilla::NotNullTag, void* p) +{ + MOZ_ASSERT(p); + return p; +} + +#endif // mozilla_OperatorNewExtensions_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Poison.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Poison.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Poison.h @@ -59,4 +59,50 @@ MOZ_END_EXTERN_C +#if defined(__cplusplus) + +namespace mozilla { + +/** + * This class is designed to cause crashes when various kinds of memory + * corruption are observed. For instance, let's say we have a class C where we + * suspect out-of-bounds writes to some members. We can insert a member of type + * Poison near the members we suspect are being corrupted by out-of-bounds + * writes. Or perhaps we have a class K we suspect is subject to use-after-free + * violations, in which case it doesn't particularly matter where in the class + * we add the member of type Poison. + * + * In either case, we then insert calls to Check() throughout the code. Doing + * so enables us to narrow down the location where the corruption is occurring. + * A pleasant side-effect of these additional Check() calls is that crash + * signatures may become more regular, as crashes will ideally occur + * consolidated at the point of a Check(), rather than scattered about at + * various uses of the corrupted memory. + */ +class CorruptionCanary { +public: + CorruptionCanary() { + mValue = kCanarySet; + } + + ~CorruptionCanary() { + Check(); + mValue = mozPoisonValue(); + } + + void Check() const { + if (mValue != kCanarySet) { + MOZ_CRASH("Canary check failed, check lifetime"); + } + } + +private: + static const uintptr_t kCanarySet = 0x0f0b0f0b; + uintptr_t mValue; +}; + +} // mozilla + +#endif + #endif /* mozilla_Poison_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Range.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Range.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Range.h @@ -8,6 +8,7 @@ #define mozilla_Range_h #include "mozilla/RangedPtr.h" +#include "mozilla/TypeTraits.h" #include @@ -26,8 +27,24 @@ : mStart(aPtr, aPtr, aPtr + aLength), mEnd(aPtr + aLength, aPtr, aPtr + aLength) {} + Range(const RangedPtr& aStart, const RangedPtr& aEnd) + : mStart(aStart.get(), aStart.get(), aEnd.get()), + mEnd(aEnd.get(), aStart.get(), aEnd.get()) + { + // Only accept two RangedPtrs within the same range. + aStart.checkIdenticalRange(aEnd); + MOZ_ASSERT(aStart <= aEnd); + } + + template::value, + int>::Type> + MOZ_IMPLICIT Range(const Range& aOther) + : mStart(aOther.mStart), + mEnd(aOther.mEnd) + {} - RangedPtr start() const { return mStart; } + RangedPtr begin() const { return mStart; } RangedPtr end() const { return mEnd; } size_t length() const { return mEnd - mStart; } Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/RangedPtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/RangedPtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/RangedPtr.h @@ -117,6 +117,12 @@ explicit operator bool() const { return mPtr != nullptr; } + void checkIdenticalRange(const RangedPtr& aOther) const + { + MOZ_ASSERT(mRangeStart == aOther.mRangeStart); + MOZ_ASSERT(mRangeEnd == aOther.mRangeEnd); + } + /* * You can only assign one RangedPtr into another if the two pointers have * the same valid range: @@ -129,21 +135,20 @@ */ RangedPtr& operator=(const RangedPtr& aOther) { - MOZ_ASSERT(mRangeStart == aOther.mRangeStart); - MOZ_ASSERT(mRangeEnd == aOther.mRangeEnd); + checkIdenticalRange(aOther); mPtr = aOther.mPtr; checkSanity(); return *this; } - RangedPtr operator+(size_t aInc) + RangedPtr operator+(size_t aInc) const { MOZ_ASSERT(aInc <= size_t(-1) / sizeof(T)); MOZ_ASSERT(asUintptr() + aInc * sizeof(T) >= asUintptr()); return create(mPtr + aInc); } - RangedPtr operator-(size_t aDec) + RangedPtr operator-(size_t aDec) const { MOZ_ASSERT(aDec <= size_t(-1) / sizeof(T)); MOZ_ASSERT(asUintptr() - aDec * sizeof(T) <= asUintptr()); @@ -220,6 +225,13 @@ return *mPtr; } + T* operator->() const + { + MOZ_ASSERT(mPtr >= mRangeStart); + MOZ_ASSERT(mPtr < mRangeEnd); + return mPtr; + } + template bool operator==(const RangedPtr& aOther) const { Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/RefCounted.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/RefCounted.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/RefCounted.h @@ -22,7 +22,6 @@ #endif #if defined(MOZILLA_INTERNAL_API) && \ - !defined(MOZILLA_XPCOMRT_API) && \ (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING)) #define MOZ_REFCOUNTED_LEAK_CHECKING #endif Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/RefPtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/RefPtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/RefPtr.h @@ -19,6 +19,28 @@ namespace mozilla { template class OwningNonNull; +template class StaticRefPtr; + +// Traditionally, RefPtr supports automatic refcounting of any pointer type +// with AddRef() and Release() methods that follow the traditional semantics. +// +// This traits class can be specialized to operate on other pointer types. For +// example, we specialize this trait for opaque FFI types that represent +// refcounted objects in Rust. +// +// Given the use of ConstRemovingRefPtrTraits below, U should not be a const- +// qualified type. +template +struct RefPtrTraits +{ + static void AddRef(U* aPtr) { + aPtr->AddRef(); + } + static void Release(U* aPtr) { + aPtr->Release(); + } +}; + } // namespace mozilla template @@ -29,7 +51,7 @@ assign_with_AddRef(T* aRawPtr) { if (aRawPtr) { - AddRefTraits::AddRef(aRawPtr); + ConstRemovingRefPtrTraits::AddRef(aRawPtr); } assign_assuming_AddRef(aRawPtr); } @@ -40,7 +62,7 @@ T* oldPtr = mRawPtr; mRawPtr = aNewPtr; if (oldPtr) { - AddRefTraits::Release(oldPtr); + ConstRemovingRefPtrTraits::Release(oldPtr); } } @@ -53,14 +75,14 @@ ~RefPtr() { if (mRawPtr) { - AddRefTraits::Release(mRawPtr); + ConstRemovingRefPtrTraits::Release(mRawPtr); } } // Constructors RefPtr() - : mRawPtr(0) + : mRawPtr(nullptr) // default constructor { } @@ -70,7 +92,7 @@ // copy-constructor { if (mRawPtr) { - AddRefTraits::AddRef(mRawPtr); + ConstRemovingRefPtrTraits::AddRef(mRawPtr); } } @@ -86,10 +108,15 @@ : mRawPtr(aRawPtr) { if (mRawPtr) { - AddRefTraits::AddRef(mRawPtr); + ConstRemovingRefPtrTraits::AddRef(mRawPtr); } } + MOZ_IMPLICIT RefPtr(decltype(nullptr)) + : mRawPtr(nullptr) + { + } + template MOZ_IMPLICIT RefPtr(already_AddRefed& aSmartPtr) : mRawPtr(aSmartPtr.take()) @@ -110,7 +137,7 @@ // copy-construct from a smart pointer with a related pointer type { if (mRawPtr) { - AddRefTraits::AddRef(mRawPtr); + ConstRemovingRefPtrTraits::AddRef(mRawPtr); } } @@ -127,9 +154,20 @@ template MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull& aOther); + // Defined in StaticPtr.h + template + MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr& aOther); + // Assignment operators RefPtr& + operator=(decltype(nullptr)) + { + assign_assuming_AddRef(nullptr); + return *this; + } + + RefPtr& operator=(const RefPtr& aRhs) // copy assignment operator { @@ -187,6 +225,11 @@ RefPtr& operator=(const mozilla::OwningNonNull& aOther); + // Defined in StaticPtr.h + template + RefPtr& + operator=(const mozilla::StaticRefPtr& aOther); + // Other pointer operators void @@ -212,7 +255,7 @@ // return the value of mRawPtr and null out mRawPtr. Useful for // already_AddRefed return values. { - T* temp = 0; + T* temp = nullptr; swap(temp); return already_AddRefed(temp); } @@ -227,7 +270,7 @@ { MOZ_ASSERT(aRhs, "Null pointer passed to forget!"); *aRhs = mRawPtr; - mRawPtr = 0; + mRawPtr = nullptr; } T* @@ -272,7 +315,7 @@ T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { - MOZ_ASSERT(mRawPtr != 0, + MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL RefPtr with operator->()."); return get(); } @@ -299,7 +342,7 @@ template Proxy operator->*(R (T::*aFptr)(Args...)) const { - MOZ_ASSERT(mRawPtr != 0, + MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL RefPtr with operator->*()."); return Proxy(get(), aFptr); } @@ -324,7 +367,7 @@ T& operator*() const { - MOZ_ASSERT(mRawPtr != 0, + MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL RefPtr with operator*()."); return *get(); } @@ -332,7 +375,7 @@ T** StartAssignment() { - assign_assuming_AddRef(0); + assign_assuming_AddRef(nullptr); return reinterpret_cast(&mRawPtr); } private: @@ -346,40 +389,24 @@ // This should be sound because while |RefPtr| provides a // const view of an object, the object itself should not be const (it // would have to be allocated as |new const T| or similar to be const). - - // Because some classes make their AddRef/Release implementations private - // and then friend RefPtr to make them visible, we redirect AddRefTraits's - // calls to static helper functions in RefPtr so we don't have to figure - // out how to make AddRefTraits visible to *those* classes. - static MOZ_ALWAYS_INLINE void - AddRefTraitsAddRefHelper(typename mozilla::RemoveConst::Type* aPtr) - { - aPtr->AddRef(); - } - static MOZ_ALWAYS_INLINE void - AddRefTraitsReleaseHelper(typename mozilla::RemoveConst::Type* aPtr) - { - aPtr->Release(); - } - template - struct AddRefTraits + struct ConstRemovingRefPtrTraits { static void AddRef(U* aPtr) { - RefPtr::AddRefTraitsAddRefHelper(aPtr); + mozilla::RefPtrTraits::AddRef(aPtr); } static void Release(U* aPtr) { - RefPtr::AddRefTraitsReleaseHelper(aPtr); + mozilla::RefPtrTraits::Release(aPtr); } }; template - struct AddRefTraits + struct ConstRemovingRefPtrTraits { static void AddRef(const U* aPtr) { - RefPtr::AddRefTraitsAddRefHelper(const_cast(aPtr)); + mozilla::RefPtrTraits::AddRef(const_cast(aPtr)); } static void Release(const U* aPtr) { - RefPtr::AddRefTraitsReleaseHelper(const_cast(aPtr)); + mozilla::RefPtrTraits::Release(const_cast(aPtr)); } }; }; @@ -591,7 +618,15 @@ template inline already_AddRefed -do_AddRef(T*&& aObj) +do_AddRef(T* aObj) +{ + RefPtr ref(aObj); + return ref.forget(); +} + +template +inline already_AddRefed +do_AddRef(const RefPtr& aObj) { RefPtr ref(aObj); return ref.forget(); Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Saturate.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Saturate.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Saturate.h @@ -0,0 +1,288 @@ +/* -*- 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/. */ + +/* Provides saturation arithmetics for scalar types. */ + +#ifndef mozilla_Saturate_h +#define mozilla_Saturate_h + +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" +#include "mozilla/TypeTraits.h" + +#include + +namespace mozilla { +namespace detail { + +/** + * |SaturateOp| wraps scalar values for saturation arithmetics. Usage: + * + * uint32_t value = 1; + * + * ++SaturateOp(value); // value is 2 + * --SaturateOp(value); // value is 1 + * --SaturateOp(value); // value is 0 + * --SaturateOp(value); // value is still 0 + * + * Please add new operators when required. + * + * |SaturateOp| will saturate at the minimum and maximum values of + * type T. If you need other bounds, implement a clamped-type class and + * specialize the type traits accordingly. + */ +template +class SaturateOp +{ +public: + explicit SaturateOp(T& aValue) + : mValue(aValue) + { + // We should actually check for |std::is_scalar::value| to be + // true, but this type trait is not available everywhere. Relax + // this assertion if you want to use floating point values as well. + static_assert(IsIntegral::value, + "Integral type required in instantiation"); + } + + // Add and subtract operators + + T operator+(const T& aRhs) const + { + return T(mValue) += aRhs; + } + + T operator-(const T& aRhs) const + { + return T(mValue) -= aRhs; + } + + // Compound operators + + const T& operator+=(const T& aRhs) const + { + const T min = std::numeric_limits::min(); + const T max = std::numeric_limits::max(); + + if (aRhs > static_cast(0)) { + mValue = (max - aRhs) < mValue ? max : mValue + aRhs; + } else { + mValue = (min - aRhs) > mValue ? min : mValue + aRhs; + } + return mValue; + } + + const T& operator-=(const T& aRhs) const + { + const T min = std::numeric_limits::min(); + const T max = std::numeric_limits::max(); + + if (aRhs > static_cast(0)) { + mValue = (min + aRhs) > mValue ? min : mValue - aRhs; + } else { + mValue = (max + aRhs) < mValue ? max : mValue - aRhs; + } + return mValue; + } + + // Increment and decrement operators + + const T& operator++() const // prefix + { + return operator+=(static_cast(1)); + } + + T operator++(int) const // postfix + { + const T value(mValue); + operator++(); + return value; + } + + const T& operator--() const // prefix + { + return operator-=(static_cast(1)); + } + + T operator--(int) const // postfix + { + const T value(mValue); + operator--(); + return value; + } + +private: + SaturateOp(const SaturateOp&) = delete; + SaturateOp(SaturateOp&&) = delete; + SaturateOp& operator=(const SaturateOp&) = delete; + SaturateOp& operator=(SaturateOp&&) = delete; + + T& mValue; +}; + +/** + * |Saturate| is a value type for saturation arithmetics. It's + * build on top of |SaturateOp|. + */ +template +class Saturate +{ +public: + Saturate() = default; + MOZ_IMPLICIT Saturate(const Saturate&) = default; + + MOZ_IMPLICIT Saturate(Saturate&& aValue) + { + mValue = Move(aValue.mValue); + } + + explicit Saturate(const T& aValue) + : mValue(aValue) + { } + + const T& value() const + { + return mValue; + } + + // Compare operators + + bool operator==(const Saturate& aRhs) const + { + return mValue == aRhs.mValue; + } + + bool operator!=(const Saturate& aRhs) const + { + return !operator==(aRhs); + } + + bool operator==(const T& aRhs) const + { + return mValue == aRhs; + } + + bool operator!=(const T& aRhs) const + { + return !operator==(aRhs); + } + + // Assignment operators + + Saturate& operator=(const Saturate&) = default; + + Saturate& operator=(Saturate&& aRhs) + { + mValue = Move(aRhs.mValue); + return *this; + } + + // Add and subtract operators + + Saturate operator+(const Saturate& aRhs) const + { + Saturate lhs(mValue); + return lhs += aRhs.mValue; + } + + Saturate operator+(const T& aRhs) const + { + Saturate lhs(mValue); + return lhs += aRhs; + } + + Saturate operator-(const Saturate& aRhs) const + { + Saturate lhs(mValue); + return lhs -= aRhs.mValue; + } + + Saturate operator-(const T& aRhs) const + { + Saturate lhs(mValue); + return lhs -= aRhs; + } + + // Compound operators + + Saturate& operator+=(const Saturate& aRhs) + { + SaturateOp(mValue) += aRhs.mValue; + return *this; + } + + Saturate& operator+=(const T& aRhs) + { + SaturateOp(mValue) += aRhs; + return *this; + } + + Saturate& operator-=(const Saturate& aRhs) + { + SaturateOp(mValue) -= aRhs.mValue; + return *this; + } + + Saturate& operator-=(const T& aRhs) + { + SaturateOp(mValue) -= aRhs; + return *this; + } + + // Increment and decrement operators + + Saturate& operator++() // prefix + { + ++SaturateOp(mValue); + return *this; + } + + Saturate operator++(int) // postfix + { + return Saturate(SaturateOp(mValue)++); + } + + Saturate& operator--() // prefix + { + --SaturateOp(mValue); + return *this; + } + + Saturate operator--(int) // postfix + { + return Saturate(SaturateOp(mValue)--); + } + +private: + T mValue; +}; + +} // namespace detail + +typedef detail::Saturate SaturateInt8; +typedef detail::Saturate SaturateInt16; +typedef detail::Saturate SaturateInt32; +typedef detail::Saturate SaturateUint8; +typedef detail::Saturate SaturateUint16; +typedef detail::Saturate SaturateUint32; + +} // namespace mozilla + +template +bool +operator==(LhsT aLhs, const mozilla::detail::Saturate& aRhs) +{ + return aRhs.operator==(static_cast(aLhs)); +} + +template +bool +operator!=(LhsT aLhs, const mozilla::detail::Saturate& aRhs) +{ + return !(aLhs == aRhs); +} + +#endif // mozilla_Saturate_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Scoped.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Scoped.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Scoped.h @@ -15,20 +15,16 @@ * Resource Acquisition Is Initialization is a programming idiom used * to write robust code that is able to deallocate resources properly, * even in presence of execution errors or exceptions that need to be - * propagated. The Scoped* classes defined in this header perform the + * propagated. The Scoped* classes defined via the |SCOPED_TEMPLATE| + * and |MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLTE| macros perform the * deallocation of the resource they hold once program execution * reaches the end of the scope for which they have been defined. + * These macros have been used to automatically close file + * descriptors/file handles when reaching the end of the scope, + * graphics contexts, etc. * - * This header provides the following RAII classes: - * - * - |ScopedFreePtr| - a container for a pointer, that automatically calls - * |free()| at the end of the scope; - * - |ScopedDeletePtr| - a container for a pointer, that automatically calls - * |delete| at the end of the scope; - * - * |ScopedDeleteArray| is removed in favor of |UniquePtr|. - * - * The general scenario for each of the RAII classes is the following: + * The general scenario for RAII classes created by the above macros + * is the following: * * ScopedClass foo(create_value()); * // ... In this scope, |foo| is defined. Use |foo.get()| or |foo.rwget()| @@ -44,14 +40,6 @@ * the end of the scope; * - if |forget()| has been called, any control on the resource is unbound * and the resource is not deallocated by the class. - * - * Extension: - * - * In addition, this header provides class |Scoped| and macros |SCOPED_TEMPLATE| - * and |MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE| to simplify the definition - * of RAII classes for other scenarios. These macros have been used to - * automatically close file descriptors/file handles when reaching the end of - * the scope, graphics contexts, etc. */ #include "mozilla/Assertions.h" @@ -220,35 +208,6 @@ }; /* - * ScopedFreePtr is a RAII wrapper for pointers that need to be free()d. - * - * struct S { ... }; - * ScopedFreePtr foo = malloc(sizeof(S)); - * ScopedFreePtr bar = strdup(str); - */ -template -struct ScopedFreePtrTraits -{ - typedef T* type; - static T* empty() { return nullptr; } - static void release(T* aPtr) { free(aPtr); } -}; -SCOPED_TEMPLATE(ScopedFreePtr, ScopedFreePtrTraits) - -/* - * ScopedDeletePtr is a RAII wrapper for pointers that need to be deleted. - * - * struct S { ... }; - * ScopedDeletePtr foo = new S(); - */ -template -struct ScopedDeletePtrTraits : public ScopedFreePtrTraits -{ - static void release(T* aPtr) { delete aPtr; } -}; -SCOPED_TEMPLATE(ScopedDeletePtr, ScopedDeletePtrTraits) - -/* * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE makes it easy to create scoped * pointers for types with custom deleters; just overload * TypeSpecificDelete(T*) in the same namespace as T to call the deleter for Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/SegmentedVector.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/SegmentedVector.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/SegmentedVector.h @@ -159,7 +159,7 @@ // Returns false if the allocation failed. (If you are using an infallible // allocation policy, use InfallibleAppend() instead.) template - MOZ_WARN_UNUSED_RESULT bool Append(U&& aU) + MOZ_MUST_USE bool Append(U&& aU) { Segment* last = mSegments.getLast(); if (!last || last->Length() == kSegmentCapacity) { @@ -218,6 +218,56 @@ } } + // Equivalent to calling |PopLast| |aNumElements| times, but potentially + // more efficient. + void PopLastN(uint32_t aNumElements) + { + MOZ_ASSERT(aNumElements <= Length()); + + Segment* last; + + // Pop full segments for as long as we can. Note that this loop + // cleanly handles the case when the initial last segment is not + // full and we are popping more elements than said segment contains. + do { + last = mSegments.getLast(); + + // The list is empty. We're all done. + if (!last) { + return; + } + + // Check to see if the list contains too many elements. Handle + // that in the epilogue. + uint32_t segmentLen = last->Length(); + if (segmentLen > aNumElements) { + break; + } + + // Destroying the segment destroys all elements contained therein. + mSegments.popLast(); + last->~Segment(); + this->free_(last); + + MOZ_ASSERT(aNumElements >= segmentLen); + aNumElements -= segmentLen; + if (aNumElements == 0) { + return; + } + } while (true); + + // Handle the case where the last segment contains more elements + // than we want to pop. + MOZ_ASSERT(last); + MOZ_ASSERT(last == mSegments.getLast()); + MOZ_ASSERT(aNumElements != 0); + MOZ_ASSERT(aNumElements < last->Length()); + for (uint32_t i = 0; i < aNumElements; ++i) { + last->PopLast(); + } + MOZ_ASSERT(last->Length() != 0); + } + // Use this class to iterate over a SegmentedVector, like so: // // for (auto iter = v.Iter(); !iter.Done(); iter.Next()) { Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Snprintf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Snprintf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Snprintf.h @@ -1,50 +0,0 @@ -/* -*- 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/. */ - -/* Polyfills snprintf() on platforms that don't provide it, and provides - * related utilities. */ - -#ifndef mozilla_Snprintf_h_ -#define mozilla_Snprintf_h_ - -#include -#include -#include - -// Older MSVC versions do not provide snprintf(), but they do provide -// vsnprintf(), which has the same semantics except that if the number of -// characters written equals the buffer size, it does not write a null -// terminator, so we wrap it to do so. -#if defined(_MSC_VER) && _MSC_VER < 1900 -#include "mozilla/Attributes.h" -MOZ_ALWAYS_INLINE int snprintf(char* buffer, size_t n, const char* format, ...) -{ - va_list args; - va_start(args, format); - int result = vsnprintf(buffer, n, format, args); - va_end(args); - buffer[n - 1] = '\0'; - return result; -} -#endif - -// In addition, in C++ code, on all platforms, provide an snprintf_literal() -// function which uses template argument deduction to deduce the size of the -// buffer, avoiding the need for the user to pass it in explicitly. -#ifdef __cplusplus -template -int snprintf_literal(char (&buffer)[N], const char* format, ...) -{ - va_list args; - va_start(args, format); - int result = vsnprintf(buffer, N, format, args); - va_end(args); - buffer[N - 1] = '\0'; - return result; -} -#endif - -#endif /* mozilla_Snprintf_h_ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/SplayTree.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/SplayTree.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/SplayTree.h @@ -56,7 +56,7 @@ T* mRoot; public: - MOZ_CONSTEXPR SplayTree() + constexpr SplayTree() : mRoot(nullptr) {} @@ -76,19 +76,19 @@ return Comparator::compare(aValue, *last) == 0 ? last : nullptr; } - bool insert(T* aValue) + void insert(T* aValue) { MOZ_ASSERT(!find(*aValue), "Duplicate elements are not allowed."); if (!mRoot) { mRoot = aValue; - return true; + return; } T* last = lookup(*aValue); int cmp = Comparator::compare(*aValue, *last); finishInsertion(last, cmp, aValue); - return true; + return; } T* findOrInsert(const T& aValue); @@ -194,7 +194,7 @@ return parent; } - T* finishInsertion(T* aLast, int32_t aCmp, T* aNew) + void finishInsertion(T* aLast, int32_t aCmp, T* aNew) { MOZ_ASSERT(aCmp, "Nodes shouldn't be equal!"); @@ -204,7 +204,6 @@ aNew->mParent = aLast; splay(aNew); - return aNew; } /** @@ -321,7 +320,9 @@ return last; } - return finishInsertion(last, cmp, new T(aValue)); + T* t = new T(aValue); + finishInsertion(last, cmp, t); + return t; } } /* namespace mozilla */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Sprintf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Sprintf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Sprintf.h @@ -0,0 +1,41 @@ +/* -*- 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/. */ + +/* Provides a safer sprintf for printing to fixed-size character arrays. */ + +#ifndef mozilla_Sprintf_h_ +#define mozilla_Sprintf_h_ + +#include +#include + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" + +#ifdef __cplusplus + +template +int VsprintfLiteral(char (&buffer)[N], const char* format, va_list args) +{ + MOZ_ASSERT(format != buffer); + int result = vsnprintf(buffer, N, format, args); + buffer[N - 1] = '\0'; + return result; +} + +template +MOZ_FORMAT_PRINTF(2, 3) +int SprintfLiteral(char (&buffer)[N], const char* format, ...) +{ + va_list args; + va_start(args, format); + int result = VsprintfLiteral(buffer, format, args); + va_end(args); + return result; +} + +#endif +#endif /* mozilla_Sprintf_h_ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/StackWalk.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/StackWalk.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/StackWalk.h @@ -52,8 +52,6 @@ * May skip some stack frames due to compiler optimizations or code * generation. * - * Note: this (and other helper methods) will only be available when - * MOZ_STACKWALKING is defined, so any new consumers must #if based on that. */ MFBT_API bool MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames, Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/StackWalk_windows.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/StackWalk_windows.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/StackWalk_windows.h @@ -0,0 +1,21 @@ +#ifndef mozilla_StackWalk_windows_h +#define mozilla_StackWalk_windows_h + +#include "mozilla/Types.h" + +/** + * Allow stack walkers to work around the egregious win64 dynamic lookup table + * list API by locking around SuspendThread to avoid deadlock. + * + * See comment in StackWalk.cpp + */ +MFBT_API void +AcquireStackWalkWorkaroundLock(); + +MFBT_API bool +TryAcquireStackWalkWorkaroundLock(); + +MFBT_API void +ReleaseStackWalkWorkaroundLock(); + +#endif // mozilla_StackWalk_windows_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/StaticAnalysisFunctions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/StaticAnalysisFunctions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/StaticAnalysisFunctions.h @@ -0,0 +1,49 @@ +/* -*- 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/. */ + +#ifndef mozilla_StaticAnalysisFunctions_h +#define mozilla_StaticAnalysisFunctions_h + +#ifndef __cplusplus +#ifndef bool +#include +#endif +#endif +/* + * Functions that are used as markers in Gecko code for static analysis. Their + * purpose is to have different AST nodes generated during compile time and to + * match them based on different checkers implemented in build/clang-plugin + */ + +#ifdef MOZ_CLANG_PLUGIN + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * MOZ_AssertAssignmentTest - used in MOZ_ASSERT in order to test the possible + * presence of assignment instead of logical comparisons. + * + * Example: + * MOZ_ASSERT(retVal = true); + */ +static MOZ_ALWAYS_INLINE bool MOZ_AssertAssignmentTest(bool exprResult) { + return exprResult; +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#define MOZ_CHECK_ASSERT_ASSIGNMENT(expr) MOZ_AssertAssignmentTest(!!(expr)) + +#else + +#define MOZ_CHECK_ASSERT_ASSIGNMENT(expr) (!!(expr)) + +#endif /* MOZ_CLANG_PLUGIN */ +#endif /* StaticAnalysisFunctions_h */ \ No newline at end of file Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TextUtils.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TextUtils.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TextUtils.h @@ -0,0 +1,58 @@ +/* -*- 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/. */ + +/* Character/text operations. */ + +#ifndef mozilla_TextUtils_h +#define mozilla_TextUtils_h + +#include "mozilla/TypeTraits.h" + +namespace mozilla { + +namespace detail { + +template +class MakeUnsignedChar + : public MakeUnsigned +{}; + +template<> +class MakeUnsignedChar +{ +public: + using Type = char16_t; +}; + +template<> +class MakeUnsignedChar +{ +public: + using Type = char32_t; +}; + +} // namespace detail + +/** + * Returns true iff |aChar| matches [a-zA-Z]. + * + * This function is basically what you thought isalpha was, except its behavior + * doesn't depend on the user's current locale. + */ +template +constexpr bool +IsAsciiAlpha(Char aChar) +{ + using UnsignedChar = typename detail::MakeUnsignedChar::Type; + return ('a' <= static_cast(aChar) && + static_cast(aChar) <= 'z') || + ('A' <= static_cast(aChar) && + static_cast(aChar) <= 'Z'); +} + +} // namespace mozilla + +#endif /* mozilla_TextUtils_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ThreadLocal.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ThreadLocal.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ThreadLocal.h @@ -42,11 +42,28 @@ typedef sig_atomic_t sig_safe_t; #endif +namespace detail { + +#if defined(HAVE_THREAD_TLS_KEYWORD) +#define MOZ_HAS_THREAD_LOCAL +#endif + /* * Thread Local Storage helpers. * * Usage: * + * Do not directly instantiate this class. Instead, use the + * MOZ_THREAD_LOCAL macro to declare or define instances. The macro + * takes a type name as its argument. + * + * Declare like this: + * extern MOZ_THREAD_LOCAL(int) tlsInt; + * Define like this: + * MOZ_THREAD_LOCAL(int) tlsInt; + * or: + * static MOZ_THREAD_LOCAL(int) tlsInt; + * * Only static-storage-duration (e.g. global variables, or static class members) * objects of this class should be instantiated. This class relies on * zero-initialization, which is implicit for static-storage-duration objects. @@ -56,9 +73,10 @@ * * // Create a TLS item. * // - * // Note that init() should be invoked exactly once, before any usage of set() - * // or get(). - * mozilla::ThreadLocal tlsKey; + * // Note that init() should be invoked before the first use of set() + * // or get(). It is ok to call it multiple times. This must be + * // called in a way that avoids possible races with other threads. + * MOZ_THREAD_LOCAL(int) tlsKey; * if (!tlsKey.init()) { * // deal with the error * } @@ -72,6 +90,7 @@ template class ThreadLocal { +#ifndef MOZ_HAS_THREAD_LOCAL #if defined(XP_WIN) typedef unsigned long key_t; #else @@ -93,19 +112,38 @@ { typedef S *Type; }; +#endif + + bool initialized() const { +#ifdef MOZ_HAS_THREAD_LOCAL + return true; +#else + return mInited; +#endif + } public: - MOZ_WARN_UNUSED_RESULT inline bool init(); + // __thread does not allow non-trivial constructors, but we can + // instead rely on zero-initialization. +#ifndef MOZ_HAS_THREAD_LOCAL + ThreadLocal() + : mKey(0), mInited(false) + {} +#endif + + MOZ_MUST_USE inline bool init(); inline T get() const; inline void set(const T aValue); - bool initialized() const { return mInited; } - private: +#ifdef MOZ_HAS_THREAD_LOCAL + T mValue; +#else key_t mKey; bool mInited; +#endif }; template @@ -118,20 +156,29 @@ static_assert(sizeof(T) <= sizeof(void*), "mozilla::ThreadLocal can't be used for types larger than " "a pointer"); - MOZ_ASSERT(!initialized()); + +#ifdef MOZ_HAS_THREAD_LOCAL + return true; +#else + if (!initialized()) { #ifdef XP_WIN - mKey = TlsAlloc(); - mInited = mKey != 0xFFFFFFFFUL; // TLS_OUT_OF_INDEXES + mKey = TlsAlloc(); + mInited = mKey != 0xFFFFFFFFUL; // TLS_OUT_OF_INDEXES #else - mInited = !pthread_key_create(&mKey, nullptr); + mInited = !pthread_key_create(&mKey, nullptr); #endif + } return mInited; +#endif } template inline T ThreadLocal::get() const { +#ifdef MOZ_HAS_THREAD_LOCAL + return mValue; +#else MOZ_ASSERT(initialized()); void* h; #ifdef XP_WIN @@ -140,12 +187,16 @@ h = pthread_getspecific(mKey); #endif return static_cast(reinterpret_cast::Type>(h)); +#endif } template inline void ThreadLocal::set(const T aValue) { +#ifdef MOZ_HAS_THREAD_LOCAL + mValue = aValue; +#else MOZ_ASSERT(initialized()); void* h = reinterpret_cast(static_cast::Type>(aValue)); #ifdef XP_WIN @@ -156,8 +207,16 @@ if (!succeeded) { MOZ_CRASH(); } +#endif } +#ifdef MOZ_HAS_THREAD_LOCAL +#define MOZ_THREAD_LOCAL(TYPE) __thread mozilla::detail::ThreadLocal +#else +#define MOZ_THREAD_LOCAL(TYPE) mozilla::detail::ThreadLocal +#endif + +} // namespace detail } // namespace mozilla #endif /* mozilla_ThreadLocal_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TimeStamp.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TimeStamp.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TimeStamp.h @@ -62,7 +62,7 @@ { public: // The default duration is 0. - MOZ_CONSTEXPR BaseTimeDuration() : mValue(0) {} + constexpr BaseTimeDuration() : mValue(0) {} // Allow construction using '0' as the initial value, for readability, // but no other numbers (so we don't have any implicit unit conversions). struct _SomethingVeryRandomHere; @@ -395,7 +395,7 @@ /** * Initialize to the "null" moment */ - MOZ_CONSTEXPR TimeStamp() : mValue(0) {} + constexpr TimeStamp() : mValue(0) {} // Default copy-constructor and assignment are OK /** Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TimeStamp_windows.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TimeStamp_windows.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TimeStamp_windows.h @@ -30,7 +30,7 @@ MFBT_API uint64_t CheckQPC(const TimeStampValue& aOther) const; struct _SomethingVeryRandomHere; - MOZ_CONSTEXPR TimeStampValue(_SomethingVeryRandomHere* aNullValue) + constexpr TimeStampValue(_SomethingVeryRandomHere* aNullValue) : mGTC(0) , mQPC(0) , mHasQPC(false) Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Tuple.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Tuple.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Tuple.h @@ -95,7 +95,12 @@ * of an empty tuple). */ template -struct TupleImpl {}; +struct TupleImpl { + bool operator==(const TupleImpl& aOther) const + { + return true; + } +}; /* * One node of the recursive inheritance hierarchy. It stores the element at @@ -182,6 +187,10 @@ Tail(*this) = Move(Tail(aOther)); return *this; } + bool operator==(const TupleImpl& aOther) const + { + return Head(*this) == Head(aOther) && Tail(*this) == Tail(aOther); + } private: HeadT mHead; // The element stored at this index in the tuple. }; @@ -246,6 +255,10 @@ static_cast(*this) = Move(aOther); return *this; } + bool operator==(const Tuple& aOther) const + { + return static_cast(*this) == static_cast(aOther); + } }; /** Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TypeTraits.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TypeTraits.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TypeTraits.h @@ -98,9 +98,7 @@ template<> struct IsIntegralHelper : TrueType {}; template<> struct IsIntegralHelper : TrueType {}; template<> struct IsIntegralHelper : TrueType {}; -#ifdef MOZ_CHAR16_IS_NOT_WCHAR template<> struct IsIntegralHelper : TrueType {}; -#endif } /* namespace detail */ @@ -112,9 +110,6 @@ * mozilla::IsIntegral::value is true; * mozilla::IsIntegral::value is false; * mozilla::IsIntegral::value is false; - * - * Note that the behavior of IsIntegral on char16_t and char32_t is - * unspecified. */ template struct IsIntegral : detail::IsIntegralHelper::Type> @@ -355,6 +350,41 @@ : IntegralConstant::value || IsFloatingPoint::value> {}; +namespace detail { + +template +struct IsMemberPointerHelper : FalseType {}; + +template +struct IsMemberPointerHelper : TrueType {}; + +} // namespace detail + +/** + * IsMemberPointer determines whether a type is pointer to non-static member + * object or a pointer to non-static member function. + * + * mozilla::IsMemberPointer::value is true + * mozilla::IsMemberPointer::value is false + */ +template +struct IsMemberPointer + : detail::IsMemberPointerHelper::Type> +{}; + +/** + * IsScalar determines whether a type is a scalar type. + * + * mozilla::IsScalar::value is true + * mozilla::IsScalar::value is true + * mozilla::IsScalar::value is false + */ +template +struct IsScalar + : IntegralConstant::value || IsEnum::value || + IsPointer::value || IsMemberPointer::value> +{}; + /* 20.9.4.3 Type properties [meta.unary.prop] */ /** @@ -409,9 +439,7 @@ template<> struct IsPod : TrueType {}; template<> struct IsPod : TrueType {}; template<> struct IsPod : TrueType {}; -#ifdef MOZ_CHAR16_IS_NOT_WCHAR template<> struct IsPod : TrueType {}; -#endif template struct IsPod : TrueType {}; namespace detail { @@ -544,6 +572,27 @@ template struct IsUnsigned : detail::IsUnsignedHelper {}; +namespace detail { + +struct DoIsDestructibleImpl +{ + template().~T())> + static TrueType test(int); + template + static FalseType test(...); +}; + +template +struct IsDestructibleImpl : public DoIsDestructibleImpl +{ + typedef decltype(test(0)) Type; +}; + +} // namespace detail + +template +struct IsDestructible : public detail::IsDestructibleImpl::Type {}; + /* 20.9.5 Type property queries [meta.unary.prop.query] */ /* 20.9.6 Relationships between types [meta.rel] */ @@ -644,18 +693,15 @@ namespace detail { -// This belongs inside ConvertibleTester, but it's pulled out to -// work around a bug in the compiler used for hazard builds. -template -static void ConvertibleTestHelper(To); - template struct ConvertibleTester { private: - template(DeclVal()))> - static char test(int); + template + static char test_helper(To1); + + template + static decltype(test_helper(DeclVal())) test(int); template static int test(...); Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TypedEnumBits.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TypedEnumBits.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TypedEnumBits.h @@ -47,34 +47,34 @@ const E mValue; public: - explicit MOZ_CONSTEXPR CastableTypedEnumResult(E aValue) + explicit constexpr CastableTypedEnumResult(E aValue) : mValue(aValue) {} - MOZ_CONSTEXPR operator E() const { return mValue; } + constexpr operator E() const { return mValue; } template - MOZ_EXPLICIT_CONVERSION MOZ_CONSTEXPR + explicit constexpr operator DestinationType() const { return DestinationType(mValue); } - MOZ_CONSTEXPR bool operator !() const { return !bool(mValue); } + constexpr bool operator !() const { return !bool(mValue); } }; #define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType) \ template \ -MOZ_CONSTEXPR ReturnType \ +constexpr ReturnType \ operator Op(const OtherType& aE, const CastableTypedEnumResult& aR) \ { \ return ReturnType(aE Op OtherType(aR)); \ } \ template \ -MOZ_CONSTEXPR ReturnType \ +constexpr ReturnType \ operator Op(const CastableTypedEnumResult& aR, const OtherType& aE) \ { \ return ReturnType(OtherType(aR) Op aE); \ } \ template \ -MOZ_CONSTEXPR ReturnType \ +constexpr ReturnType \ operator Op(const CastableTypedEnumResult& aR1, \ const CastableTypedEnumResult& aR2) \ { \ @@ -90,7 +90,7 @@ MOZ_CASTABLETYPEDENUMRESULT_BINOP(&&, bool, bool) template -MOZ_CONSTEXPR CastableTypedEnumResult +constexpr CastableTypedEnumResult operator ~(const CastableTypedEnumResult& aR) { return CastableTypedEnumResult(~(E(aR))); @@ -123,7 +123,7 @@ } // namespace mozilla #define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op) \ - inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult \ + inline constexpr mozilla::CastableTypedEnumResult \ operator Op(Name a, Name b) \ { \ typedef mozilla::CastableTypedEnumResult Result; \ @@ -145,7 +145,7 @@ MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |) \ MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &) \ MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^) \ - inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult \ + inline constexpr mozilla::CastableTypedEnumResult \ operator~(Name a) \ { \ typedef mozilla::CastableTypedEnumResult Result; \ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Types.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Types.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Types.h @@ -89,7 +89,7 @@ * symbols. We add the weak attribute to the import version of the MFBT API * macros to exploit this. */ -# if defined(MOZ_GLUE_IN_PROGRAM) && !defined(MOZILLA_XPCOMRT_API) +# if defined(MOZ_GLUE_IN_PROGRAM) # define MFBT_API __attribute__((weak)) MOZ_IMPORT_API # define MFBT_DATA __attribute__((weak)) MOZ_IMPORT_DATA # else Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/UniquePtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/UniquePtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/UniquePtr.h @@ -25,6 +25,39 @@ namespace mozilla { +namespace detail { + +struct HasPointerTypeHelper +{ + template static double Test(...); + template static char Test(typename U::pointer* = 0); +}; + +template +class HasPointerType : public IntegralConstant(0)) == 1> +{ +}; + +template ::value> +struct PointerTypeImpl +{ + typedef typename D::pointer Type; +}; + +template +struct PointerTypeImpl +{ + typedef T* Type; +}; + +template +struct PointerType +{ + typedef typename PointerTypeImpl::Type>::Type Type; +}; + +} // namespace detail + /** * UniquePtr is a smart pointer that wholly owns a resource. Ownership may be * transferred out of a UniquePtr through explicit action, but otherwise the @@ -127,10 +160,11 @@ * The constructors and mutating methods only accept array pointers (not T*, U* * that converts to T*, or UniquePtr or UniquePtr) or |nullptr|. * - * It's perfectly okay to return a UniquePtr from a method to assure the related - * resource is properly deleted. You'll need to use |Move()| when returning a - * local UniquePtr. Otherwise you can return |nullptr|, or you can return - * |UniquePtr(ptr)|. + * It's perfectly okay for a function to return a UniquePtr. This transfers + * the UniquePtr's sole ownership of the data, to the fresh UniquePtr created + * in the calling function, that will then solely own that data. Such functions + * can return a local variable UniquePtr, |nullptr|, |UniquePtr(ptr)| where + * |ptr| is a |T*|, or a UniquePtr |Move()|'d from elsewhere. * * UniquePtr will commonly be a member of a class, with lifetime equivalent to * that of that class. If you want to expose the related resource, you could @@ -154,9 +188,9 @@ class UniquePtr { public: - typedef T* Pointer; typedef T ElementType; typedef D DeleterType; + typedef typename detail::PointerType::Type Pointer; private: Pair mTuple; @@ -171,7 +205,7 @@ /** * Construct a UniquePtr containing |nullptr|. */ - MOZ_CONSTEXPR UniquePtr() + constexpr UniquePtr() : mTuple(static_cast(nullptr), DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); @@ -226,7 +260,7 @@ } UniquePtr(UniquePtr&& aOther) - : mTuple(aOther.release(), Forward(aOther.getDeleter())) + : mTuple(aOther.release(), Forward(aOther.get_deleter())) {} MOZ_IMPLICIT @@ -247,7 +281,7 @@ ? IsSame::value : IsConvertible::value), int>::Type aDummy = 0) - : mTuple(aOther.release(), Forward(aOther.getDeleter())) + : mTuple(aOther.release(), Forward(aOther.get_deleter())) { } @@ -256,7 +290,7 @@ UniquePtr& operator=(UniquePtr&& aOther) { reset(aOther.release()); - getDeleter() = Forward(aOther.getDeleter()); + get_deleter() = Forward(aOther.get_deleter()); return *this; } @@ -270,7 +304,7 @@ "can't assign from UniquePtr holding an array"); reset(aOther.release()); - getDeleter() = Forward(aOther.getDeleter()); + get_deleter() = Forward(aOther.get_deleter()); return *this; } @@ -291,10 +325,10 @@ Pointer get() const { return ptr(); } - DeleterType& getDeleter() { return del(); } - const DeleterType& getDeleter() const { return del(); } + DeleterType& get_deleter() { return del(); } + const DeleterType& get_deleter() const { return del(); } - Pointer release() + MOZ_MUST_USE Pointer release() { Pointer p = ptr(); ptr() = nullptr; @@ -306,7 +340,7 @@ Pointer old = ptr(); ptr() = aPtr; if (old != nullptr) { - getDeleter()(old); + get_deleter()(old); } } @@ -338,7 +372,7 @@ /** * Construct a UniquePtr containing nullptr. */ - MOZ_CONSTEXPR UniquePtr() + constexpr UniquePtr() : mTuple(static_cast(nullptr), DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); @@ -395,7 +429,7 @@ = delete; UniquePtr(UniquePtr&& aOther) - : mTuple(aOther.release(), Forward(aOther.getDeleter())) + : mTuple(aOther.release(), Forward(aOther.get_deleter())) {} MOZ_IMPLICIT @@ -411,7 +445,7 @@ UniquePtr& operator=(UniquePtr&& aOther) { reset(aOther.release()); - getDeleter() = Forward(aOther.getDeleter()); + get_deleter() = Forward(aOther.get_deleter()); return *this; } @@ -426,10 +460,10 @@ T& operator[](decltype(sizeof(int)) aIndex) const { return get()[aIndex]; } Pointer get() const { return mTuple.first(); } - DeleterType& getDeleter() { return mTuple.second(); } - const DeleterType& getDeleter() const { return mTuple.second(); } + DeleterType& get_deleter() { return mTuple.second(); } + const DeleterType& get_deleter() const { return mTuple.second(); } - Pointer release() + MOZ_MUST_USE Pointer release() { Pointer p = mTuple.first(); mTuple.first() = nullptr; @@ -463,12 +497,24 @@ void operator=(const UniquePtr& aOther) = delete; // assign using Move()! }; -/** A default deletion policy using plain old operator delete. */ +/** + * A default deletion policy using plain old operator delete. + * + * Note that this type can be specialized, but authors should beware of the risk + * that the specialization may at some point cease to match (either because it + * gets moved to a different compilation unit or the signature changes). If the + * non-specialized (|delete|-based) version compiles for that type but does the + * wrong thing, bad things could happen. + * + * This is a non-issue for types which are always incomplete (i.e. opaque handle + * types), since |delete|-ing such a type will always trigger a compilation + * error. + */ template class DefaultDelete { public: - MOZ_CONSTEXPR DefaultDelete() {} + constexpr DefaultDelete() {} template MOZ_IMPLICIT DefaultDelete(const DefaultDelete& aOther, @@ -488,7 +534,7 @@ class DefaultDelete { public: - MOZ_CONSTEXPR DefaultDelete() {} + constexpr DefaultDelete() {} void operator()(T* aPtr) const { Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/UniquePtrExtensions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/UniquePtrExtensions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/UniquePtrExtensions.h @@ -37,6 +37,21 @@ typename detail::UniqueSelector::KnownBound MakeUniqueFallible(Args&&... aArgs) = delete; +namespace detail { + +template +struct FreePolicy +{ + void operator()(const void* ptr) { + free(const_cast(ptr)); + } +}; + +} // namespace detail + +template +using UniqueFreePtr = UniquePtr>; + } // namespace mozilla #endif // mozilla_UniquePtrExtensions_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Variant.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Variant.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Variant.h @@ -7,10 +7,12 @@ /* A template class for tagged unions. */ #include +#include #include "mozilla/Alignment.h" #include "mozilla/Assertions.h" #include "mozilla/Move.h" +#include "mozilla/TypeTraits.h" #ifndef mozilla_Variant_h #define mozilla_Variant_h @@ -61,43 +63,112 @@ template struct IsVariant : public IsVariant { }; +/// SelectVariantTypeHelper is used in the implementation of SelectVariantType. +template +struct SelectVariantTypeHelper; + +template +struct SelectVariantTypeHelper +{ }; + +template +struct SelectVariantTypeHelper +{ + typedef T Type; +}; + +template +struct SelectVariantTypeHelper +{ + typedef const T Type; +}; + +template +struct SelectVariantTypeHelper +{ + typedef const T& Type; +}; + +template +struct SelectVariantTypeHelper +{ + typedef T&& Type; +}; + +template +struct SelectVariantTypeHelper + : public SelectVariantTypeHelper +{ }; + +/** + * SelectVariantType takes a type T and a list of variant types Variants and + * yields a type Type, selected from Variants, that can store a value of type T + * or a reference to type T. If no such type was found, Type is not defined. + */ +template +struct SelectVariantType + : public SelectVariantTypeHelper::Type>::Type, + Variants...> +{ }; + +// Compute a fast, compact type that can be used to hold integral values that +// distinctly map to every type in Ts. +template +struct VariantTag +{ +private: + static const size_t TypeCount = sizeof...(Ts); + +public: + using Type = + typename Conditional::Type + >::Type; +}; + // TagHelper gets the given sentinel tag value for the given type T. This has to -// be split out from VariantImplementation because you can't nest a partial template -// specialization within a template class. +// be split out from VariantImplementation because you can't nest a partial +// template specialization within a template class. -template +template struct TagHelper; // In the case where T != U, we continue recursion. -template -struct TagHelper +template +struct TagHelper { - static size_t tag() { return Next::template tag(); } + static Tag tag() { return Next::template tag(); } }; // In the case where T == U, return the tag number. -template -struct TagHelper +template +struct TagHelper { - static size_t tag() { return N; } + static Tag tag() { return Tag(N); } }; -// The VariantImplementation template provides the guts of mozilla::Variant. We create -// an VariantImplementation for each T in Ts... which handles construction, -// destruction, etc for when the Variant's type is T. If the Variant's type is -// not T, it punts the request on to the next VariantImplementation. +// The VariantImplementation template provides the guts of mozilla::Variant. We +// create a VariantImplementation for each T in Ts... which handles +// construction, destruction, etc for when the Variant's type is T. If the +// Variant's type isn't T, it punts the request on to the next +// VariantImplementation. -template +template struct VariantImplementation; // The singly typed Variant / recursion base case. -template -struct VariantImplementation { +template +struct VariantImplementation +{ template - static size_t tag() { + static Tag tag() { static_assert(mozilla::IsSame::value, "mozilla::Variant: tag: bad type!"); - return N; + return Tag(N); } template @@ -122,22 +193,24 @@ } template - static typename Matcher::ReturnType - match(Matcher& aMatcher, ConcreteVariant& aV) { + static auto + match(Matcher&& aMatcher, ConcreteVariant& aV) + -> decltype(aMatcher.match(aV.template as())) + { return aMatcher.match(aV.template as()); } }; // VariantImplementation for some variant type T. -template -struct VariantImplementation +template +struct VariantImplementation { // The next recursive VariantImplementation. - using Next = VariantImplementation; + using Next = VariantImplementation; template - static size_t tag() { - return TagHelper::value>::tag(); + static Tag tag() { + return TagHelper::value>::tag(); } template @@ -178,8 +251,9 @@ } template - static typename Matcher::ReturnType - match(Matcher& aMatcher, ConcreteVariant& aV) + static auto + match(Matcher&& aMatcher, ConcreteVariant& aV) + -> decltype(aMatcher.match(aV.template as())) { if (aV.template is()) { return aMatcher.match(aV.template as()); @@ -199,6 +273,39 @@ } }; +/** + * AsVariantTemporary stores a value of type T to allow construction of a + * Variant value via type inference. Because T is copied and there's no + * guarantee that the copy can be elided, AsVariantTemporary is best used with + * primitive or very small types. + */ +template +struct AsVariantTemporary +{ + explicit AsVariantTemporary(const T& aValue) + : mValue(aValue) + {} + + template + explicit AsVariantTemporary(U&& aValue) + : mValue(Forward(aValue)) + {} + + AsVariantTemporary(const AsVariantTemporary& aOther) + : mValue(aOther.mValue) + {} + + AsVariantTemporary(AsVariantTemporary&& aOther) + : mValue(Move(aOther.mValue)) + {} + + AsVariantTemporary() = delete; + void operator=(const AsVariantTemporary&) = delete; + void operator=(AsVariantTemporary&&) = delete; + + typename RemoveConst::Type>::Type mValue; +}; + } // namespace detail /** @@ -222,6 +329,18 @@ * Variant v1('a'); * Variant, B, C> v2(MakeUnique()); * + * Because specifying the full type of a Variant value is often verbose, + * AsVariant() can be used to construct a Variant value using type inference in + * contexts such as expressions or when returning values from functions. Because + * AsVariant() must copy or move the value into a temporary and this cannot + * necessarily be elided by the compiler, it's mostly appropriate only for use + * with primitive or very small types. + * + * + * Variant Foo() { return AsVariant('x'); } + * // ... + * Variant v1 = Foo(); // v1 holds char('x'). + * * All access to the contained value goes through type-safe accessors. * * void @@ -275,11 +394,11 @@ * // Good! * struct FooMatcher * { - * using ReturnType = char*; - * ReturnType match(A& a) { ... } - * ReturnType match(B& b) { ... } - * ReturnType match(C& c) { ... } - * ReturnType match(D& d) { ... } // Compile-time error to forget D! + * // The return type of all matchers must be identical. + * char* match(A& a) { ... } + * char* match(B& b) { ... } + * char* match(C& c) { ... } + * char* match(D& d) { ... } // Compile-time error to forget D! * } * char* foo(Variant& v) { * return v.match(FooMatcher()); @@ -313,18 +432,19 @@ * }; */ template -class Variant +class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Variant { - using Impl = detail::VariantImplementation<0, Ts...>; + using Tag = typename detail::VariantTag::Type; + using Impl = detail::VariantImplementation; using RawData = AlignedStorage::size>; - // Each type is given a unique size_t sentinel. This tag lets us keep track of - // the contained variant value's type. - size_t tag; - // Raw storage for the contained variant value. RawData raw; + // Each type is given a unique tag value that lets us keep track of the + // contained variant value's type. + Tag tag; + void* ptr() { return reinterpret_cast(&raw); } @@ -336,12 +456,24 @@ // perfect forwarding), so we have to remove those qualifiers here // when ensuring that T is a variant of this type, and getting T's // tag, etc. - typename T = typename RemoveReference::Type>::Type, - typename = typename EnableIf::value, void>::Type> + typename T = typename detail::SelectVariantType::Type> explicit Variant(RefT&& aT) : tag(Impl::template tag()) { - new (ptr()) T(Forward(aT)); + new (ptr()) T(Forward(aT)); + } + + /** + * Constructs this Variant from an AsVariantTemporary such that T can be + * stored in one of the types allowable in this Variant. This is used in the + * implementation of AsVariant(). + */ + template::Type> + MOZ_IMPLICIT Variant(detail::AsVariantTemporary&& aValue) + : tag(Impl::template tag()) + { + new (ptr()) T(Move(aValue.mValue)); } /** Copy construction. */ @@ -374,6 +506,15 @@ return *this; } + /** Move assignment from AsVariant(). */ + template + Variant& operator=(detail::AsVariantTemporary&& aValue) + { + this->~Variant(); + new (this) Variant(Move(aValue)); + return *this; + } + ~Variant() { Impl::destroy(*this); @@ -438,23 +579,47 @@ return T(Move(as())); } - // Exhaustive matching of all variant types no the contained value. + // Exhaustive matching of all variant types on the contained value. /** Match on an immutable const reference. */ template - typename Matcher::ReturnType - match(Matcher& aMatcher) const { + auto + match(Matcher&& aMatcher) const + -> decltype(Impl::match(aMatcher, *this)) + { return Impl::match(aMatcher, *this); } - /** Match on a mutable non-const reference. */ + /** Match on a mutable non-const reference. */ template - typename Matcher::ReturnType - match(Matcher& aMatcher) { + auto + match(Matcher&& aMatcher) + -> decltype(Impl::match(aMatcher, *this)) + { return Impl::match(aMatcher, *this); } }; +/* + * AsVariant() is used to construct a Variant value containing the + * provided T value using type inference. It can be used to construct Variant + * values in expressions or return them from functions without specifying the + * entire Variant type. + * + * Because AsVariant() must copy or move the value into a temporary and this + * cannot necessarily be elided by the compiler, it's mostly appropriate only + * for use with primitive or very small types. + * + * AsVariant() returns a AsVariantTemporary value which is implicitly + * convertible to any Variant that can hold a value of type T. + */ +template +detail::AsVariantTemporary +AsVariant(T&& aValue) +{ + return detail::AsVariantTemporary(Forward(aValue)); +} + } // namespace mozilla #endif /* mozilla_Variant_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Vector.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Vector.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Vector.h @@ -17,6 +17,7 @@ #include "mozilla/MathAlgorithms.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Move.h" +#include "mozilla/OperatorNewExtensions.h" #include "mozilla/ReentrancyGuard.h" #include "mozilla/TemplateLib.h" #include "mozilla/TypeTraits.h" @@ -56,22 +57,13 @@ struct VectorImpl { /* - * Constructs a default object in the uninitialized memory at *aDst. + * Constructs an object in the uninitialized memory at *aDst with aArgs. */ + template MOZ_NONNULL(1) - static inline void new_(T* aDst) - { - new(aDst) T(); - } - - /* - * Constructs an object in the uninitialized memory at *aDst from aSrc. - */ - template - MOZ_NONNULL(1) - static inline void new_(T* aDst, U&& aU) + static inline void new_(T* aDst, Args&&... aArgs) { - new(aDst) T(Forward(aU)); + new(KnownNotNull, aDst) T(Forward(aArgs)...); } /* Destroys constructed objects in the range [aBegin, aEnd). */ @@ -137,7 +129,7 @@ * aNewCap has not overflowed, and (2) multiplying aNewCap by sizeof(T) will * not overflow. */ - static inline bool + static inline MOZ_MUST_USE bool growTo(Vector& aV, size_t aNewCap) { MOZ_ASSERT(!aV.usingInlineStorage()); @@ -168,15 +160,16 @@ template struct VectorImpl { - static inline void new_(T* aDst) - { - *aDst = T(); - } - - template - static inline void new_(T* aDst, U&& aU) + template + MOZ_NONNULL(1) + static inline void new_(T* aDst, Args&&... aArgs) { - *aDst = Forward(aU); + // Explicitly construct a local object instead of using a temporary since + // T(args...) will be treated like a C-style cast in the unary case and + // allow unsafe conversions. Both forms should be equivalent to an + // optimizing compiler. + T temp(Forward(aArgs)...); + *aDst = temp; } static inline void destroy(T*, T*) {} @@ -228,7 +221,7 @@ } } - static inline bool + static inline MOZ_MUST_USE bool growTo(Vector& aV, size_t aNewCap) { MOZ_ASSERT(!aV.usingInlineStorage()); @@ -242,6 +235,20 @@ aV.mCapacity = aNewCap; return true; } + + static inline void + podResizeToFit(Vector& aV) + { + if (aV.usingInlineStorage() || aV.mLength == aV.mCapacity) { + return; + } + T* newbuf = aV.template pod_realloc(aV.mBegin, aV.mCapacity, aV.mLength); + if (MOZ_UNLIKELY(!newbuf)) { + return; + } + aV.mBegin = newbuf; + aV.mCapacity = aV.mLength; + } }; // A struct for TestVector.cpp to access private internal fields. @@ -281,8 +288,9 @@ friend struct detail::VectorTesting; - bool growStorageBy(size_t aIncr); - bool convertToHeapStorage(size_t aNewCap); + MOZ_MUST_USE bool growStorageBy(size_t aIncr); + MOZ_MUST_USE bool convertToHeapStorage(size_t aNewCap); + MOZ_MUST_USE bool maybeCheckSimulatedOOM(size_t aRequestedSize); /* magic constants */ @@ -519,10 +527,24 @@ /* mutators */ /** - * Given that the vector is empty and has no inline storage, grow to - * |capacity|. + * Reverse the order of the elements in the vector in place. + */ + void reverse(); + + /** + * Given that the vector is empty, grow the internal capacity to |aRequest|, + * keeping the length 0. + */ + MOZ_MUST_USE bool initCapacity(size_t aRequest); + + /** + * Given that the vector is empty, grow the internal capacity and length to + * |aRequest| leaving the elements' memory completely uninitialized (with all + * the associated hazards and caveats). This avoids the usual allocation-size + * rounding that happens in resize and overhead of initialization for elements + * that are about to be overwritten. */ - bool initCapacity(size_t aRequest); + MOZ_MUST_USE bool initLengthUninitialized(size_t aRequest); /** * If reserve(aRequest) succeeds and |aRequest >= length()|, then appending @@ -532,7 +554,7 @@ * A request to reserve an amount less than the current length does not affect * reserved space. */ - bool reserve(size_t aRequest); + MOZ_MUST_USE bool reserve(size_t aRequest); /** * Destroy elements in the range [end() - aIncr, end()). Does not deallocate @@ -540,19 +562,25 @@ */ void shrinkBy(size_t aIncr); + /** + * Destroy elements in the range [aNewLength, end()). Does not deallocate + * or unreserve storage for those elements. + */ + void shrinkTo(size_t aNewLength); + /** Grow the vector by aIncr elements. */ - bool growBy(size_t aIncr); + MOZ_MUST_USE bool growBy(size_t aIncr); /** Call shrinkBy or growBy based on whether newSize > length(). */ - bool resize(size_t aNewLength); + MOZ_MUST_USE bool resize(size_t aNewLength); /** * Increase the length of the vector, but don't initialize the new elements * -- leave them as uninitialized memory. */ - bool growByUninitialized(size_t aIncr); + MOZ_MUST_USE bool growByUninitialized(size_t aIncr); void infallibleGrowByUninitialized(size_t aIncr); - bool resizeUninitialized(size_t aNewLength); + MOZ_MUST_USE bool resizeUninitialized(size_t aNewLength); /** Shorthand for shrinkBy(length()). */ void clear(); @@ -561,6 +589,13 @@ void clearAndFree(); /** + * Calls the AllocPolicy's pod_realloc to release excess capacity. Since + * realloc is only safe on PODs, this method fails to compile if IsPod + * is false. + */ + void podResizeToFit(); + + /** * If true, appending |aNeeded| elements won't reallocate elements storage. * This *doesn't* mean that infallibleAppend may be used! You still must * reserve the extra space, even if this method indicates that appends won't @@ -575,25 +610,25 @@ * vector, instead of copying it. If it fails, |aU| is left unmoved. ("We are * not amused.") */ - template bool append(U&& aU); + template MOZ_MUST_USE bool append(U&& aU); /** * Construct a T in-place as a new entry at the end of this vector. */ template - bool emplaceBack(Args&&... aArgs) + MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) { if (!growByUninitialized(1)) return false; - new (&back()) T(Forward(aArgs)...); + Impl::new_(&back(), Forward(aArgs)...); return true; } template - bool appendAll(const Vector& aU); - bool appendN(const T& aT, size_t aN); - template bool append(const U* aBegin, const U* aEnd); - template bool append(const U* aBegin, size_t aLength); + MOZ_MUST_USE bool appendAll(const Vector& aU); + MOZ_MUST_USE bool appendN(const T& aT, size_t aN); + template MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd); + template MOZ_MUST_USE bool append(const U* aBegin, size_t aLength); /* * Guaranteed-infallible append operations for use upon vectors whose @@ -620,7 +655,7 @@ void infallibleEmplaceBack(Args&&... aArgs) { infallibleGrowByUninitialized(1); - new (&back()) T(Forward(aArgs)...); + Impl::new_(&back(), Forward(aArgs)...); } void popBack(); @@ -628,16 +663,34 @@ T popCopy(); /** - * Transfers ownership of the internal buffer used by this vector to the - * caller. (It's the caller's responsibility to properly deallocate this - * buffer, in accordance with this vector's AllocPolicy.) After this call, - * the vector is empty. Since the returned buffer may need to be allocated - * (if the elements are currently stored in-place), the call can fail, - * returning nullptr. + * If elements are stored in-place, return nullptr and leave this vector + * unmodified. + * + * Otherwise return this vector's elements buffer, and clear this vector as if + * by clearAndFree(). The caller now owns the buffer and is responsible for + * deallocating it consistent with this vector's AllocPolicy. * * N.B. Although a T*, only the range [0, length()) is constructed. */ - T* extractRawBuffer(); + MOZ_MUST_USE T* extractRawBuffer(); + + /** + * If elements are stored in-place, allocate a new buffer, move this vector's + * elements into it, and return that buffer. + * + * Otherwise return this vector's elements buffer. The caller now owns the + * buffer and is responsible for deallocating it consistent with this vector's + * AllocPolicy. + * + * This vector is cleared, as if by clearAndFree(), when this method + * succeeds. This method fails and returns nullptr only if new elements buffer + * allocation fails. + * + * N.B. Only the range [0, length()) of the returned buffer is constructed. + * If any of these elements are uninitialized (as growByUninitialized + * enables), behavior is undefined. + */ + MOZ_MUST_USE T* extractOrCopyRawBuffer(); /** * Transfer ownership of an array of objects into the vector. The caller @@ -665,7 +718,7 @@ * This is inherently a linear-time operation. Be careful! */ template - T* insert(T* aP, U&& aVal); + MOZ_MUST_USE T* insert(T* aP, U&& aVal); /** * Removes the element |aT|, which must fall in the bounds [begin, end), @@ -767,7 +820,7 @@ { MOZ_ASSERT(this != &aRhs, "self-move assignment is prohibited"); this->~Vector(); - new(this) Vector(Move(aRhs)); + new(KnownNotNull, this) Vector(Move(aRhs)); return *this; } @@ -782,6 +835,18 @@ } } +template +MOZ_ALWAYS_INLINE void +Vector::reverse() { + MOZ_REENTRANCY_GUARD_ET_AL; + T* elems = mBegin; + size_t len = mLength; + size_t mid = len / 2; + for (size_t i = 0; i < mid; i++) { + Swap(elems[i], elems[len - i - 1]); + } +} + /* * This function will create a new heap buffer with capacity aNewCap, * move all elements in the inline buffer to this new buffer, @@ -916,6 +981,34 @@ template inline bool +Vector::initLengthUninitialized(size_t aRequest) +{ + if (!initCapacity(aRequest)) { + return false; + } + infallibleGrowByUninitialized(aRequest); + return true; +} + +template +inline bool +Vector::maybeCheckSimulatedOOM(size_t aRequestedSize) +{ + if (aRequestedSize <= N) { + return true; + } + +#ifdef DEBUG + if (aRequestedSize <= mReserved) { + return true; + } +#endif + + return allocPolicy().checkSimulatedOOM(); +} + +template +inline bool Vector::reserve(size_t aRequest) { MOZ_REENTRANCY_GUARD_ET_AL; @@ -923,10 +1016,8 @@ if (MOZ_UNLIKELY(!growStorageBy(aRequest - mLength))) { return false; } - } else if (aRequest > N) { - if (!allocPolicy().checkSimulatedOOM()) { - return false; - } + } else if (!maybeCheckSimulatedOOM(aRequest)) { + return false; } #ifdef DEBUG if (aRequest > mReserved) { @@ -949,6 +1040,14 @@ } template +MOZ_ALWAYS_INLINE void +Vector::shrinkTo(size_t aNewLength) +{ + MOZ_ASSERT(aNewLength <= mLength); + shrinkBy(mLength - aNewLength); +} + +template MOZ_ALWAYS_INLINE bool Vector::growBy(size_t aIncr) { @@ -957,10 +1056,8 @@ if (MOZ_UNLIKELY(!growStorageBy(aIncr))) { return false; } - } else if (aIncr + mLength > N) { - if (!allocPolicy().checkSimulatedOOM()) { - return false; - } + } else if (!maybeCheckSimulatedOOM(mLength + aIncr)) { + return false; } MOZ_ASSERT(mLength + aIncr <= mCapacity); T* newend = endNoCheck() + aIncr; @@ -983,11 +1080,14 @@ if (MOZ_UNLIKELY(!growStorageBy(aIncr))) { return false; } - } else if (aIncr + mLength > N) { - if (!allocPolicy().checkSimulatedOOM()) { - return false; - } + } else if (!maybeCheckSimulatedOOM(mLength + aIncr)) { + return false; } +#ifdef DEBUG + if (mLength + aIncr > mReserved) { + mReserved = mLength + aIncr; + } +#endif infallibleGrowByUninitialized(aIncr); return true; } @@ -996,13 +1096,8 @@ MOZ_ALWAYS_INLINE void Vector::infallibleGrowByUninitialized(size_t aIncr) { - MOZ_ASSERT(mLength + aIncr <= mCapacity); + MOZ_ASSERT(mLength + aIncr <= reserved()); mLength += aIncr; -#ifdef DEBUG - if (mLength > mReserved) { - mReserved = mLength; - } -#endif } template @@ -1056,6 +1151,15 @@ } template +inline void +Vector::podResizeToFit() +{ + // This function is only defined if IsPod is true and will fail to compile + // otherwise. + Impl::podResizeToFit(*this); +} + +template inline bool Vector::canAppendWithoutRealloc(size_t aNeeded) const { @@ -1090,9 +1194,8 @@ if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) { return false; } - } else if (mLength + aNeeded > N) { - if (!allocPolicy().checkSimulatedOOM()) - return false; + } else if (!maybeCheckSimulatedOOM(mLength + aNeeded)) { + return false; } #ifdef DEBUG if (mLength + aNeeded > mReserved) { @@ -1177,8 +1280,7 @@ if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) { return false; } - } else if (mLength + aNeeded > N) { - if (!allocPolicy().checkSimulatedOOM()) + } else if (!maybeCheckSimulatedOOM(mLength + aNeeded)) { return false; } #ifdef DEBUG @@ -1211,8 +1313,7 @@ if (MOZ_UNLIKELY(!growStorageBy(1))) { return false; } - } else if (mLength + 1 > N) { - if (!allocPolicy().checkSimulatedOOM()) + } else if (!maybeCheckSimulatedOOM(mLength + 1)) { return false; } #ifdef DEBUG @@ -1263,29 +1364,49 @@ inline T* Vector::extractRawBuffer() { - T* ret; + MOZ_REENTRANCY_GUARD_ET_AL; + if (usingInlineStorage()) { - ret = this->template pod_malloc(mLength); - if (!ret) { - return nullptr; - } - Impl::copyConstruct(ret, beginNoCheck(), endNoCheck()); - Impl::destroy(beginNoCheck(), endNoCheck()); - /* mBegin, mCapacity are unchanged. */ - mLength = 0; - } else { - ret = mBegin; - mBegin = static_cast(mStorage.addr()); - mLength = 0; - mCapacity = kInlineCapacity; + return nullptr; + } + + T* ret = mBegin; + mBegin = static_cast(mStorage.addr()); + mLength = 0; + mCapacity = kInlineCapacity; #ifdef DEBUG - mReserved = 0; + mReserved = 0; #endif - } return ret; } template +inline T* +Vector::extractOrCopyRawBuffer() +{ + if (T* ret = extractRawBuffer()) { + return ret; + } + + MOZ_REENTRANCY_GUARD_ET_AL; + + T* copy = this->template pod_malloc(mLength); + if (!copy) { + return nullptr; + } + + Impl::moveConstruct(copy, beginNoCheck(), endNoCheck()); + Impl::destroy(beginNoCheck(), endNoCheck()); + mBegin = static_cast(mStorage.addr()); + mLength = 0; + mCapacity = kInlineCapacity; +#ifdef DEBUG + mReserved = 0; +#endif + return copy; +} + +template inline void Vector::replaceRawBuffer(T* aP, size_t aLength) { Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/WeakPtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/WeakPtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/WeakPtr.h @@ -76,6 +76,58 @@ #include +// Weak referencing is not implemeted as thread safe. When a WeakPtr +// is created or dereferenced on thread A but the real object is just +// being Released() on thread B, there is a possibility of a race +// when the proxy object (detail::WeakReference) is notified about +// the real object destruction just between when thread A is storing +// the object pointer locally and is about to add a reference to it. +// +// Hence, a non-null weak proxy object is considered to have a single +// "owning thread". It means that each query for a weak reference, +// its dereference, and destruction of the real object must all happen +// on a single thread. The following macros implement assertions for +// checking these conditions. +// +// We disable this on MinGW. MinGW has two threading models: win32 +// API based, which disables std::thread; and POSIX based which +// enables it but requires an emulation library (winpthreads). +// Rather than attempting to switch to pthread emulation at this point, +// we are disabling the std::thread based assertion checking. +// +// In the future, to enable it we could +// a. have libgcc/stdc++ support win32 threads natively +// b. switch to POSIX-based threading in MinGW with pthread emulation +// c. refactor it to not use std::thread + +#if !defined(__MINGW32__) && (defined(DEBUG) || (defined(NIGHTLY_BUILD) && !defined(MOZ_PROFILING))) + +#include +#define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK \ + std::thread::id _owningThread; \ + bool _empty; // If it was initialized as a placeholder with mPtr = nullptr. +#define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \ + do { \ + _owningThread = std::this_thread::get_id(); \ + _empty = !p; \ + } while (false) +#define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \ + MOZ_DIAGNOSTIC_ASSERT(_empty || _owningThread == std::this_thread::get_id(), \ + "WeakPtr used on multiple threads") +#define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \ + (that)->AssertThreadSafety(); + +#define MOZ_WEAKPTR_THREAD_SAFETY_CHECKING 1 + +#else + +#define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK +#define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() do { } while (false) +#define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() do { } while (false) +#define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) do { } while (false) + +#endif + namespace mozilla { template class WeakPtr; @@ -96,9 +148,15 @@ class WeakReference : public ::mozilla::RefCounted > { public: - explicit WeakReference(T* p) : mPtr(p) {} + explicit WeakReference(T* p) : mPtr(p) + { + MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK(); + } - T* get() const { return mPtr; } + T* get() const { + MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); + return mPtr; + } #ifdef MOZ_REFCOUNTED_LEAK_CHECKING const char* typeName() const @@ -110,12 +168,20 @@ size_t typeSize() const { return sizeof(*this); } #endif +#ifdef MOZ_WEAKPTR_THREAD_SAFETY_CHECKING + void AssertThreadSafety() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); } +#endif + private: friend class mozilla::SupportsWeakPtr; - void detach() { mPtr = nullptr; } + void detach() { + MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); + mPtr = nullptr; + } T* MOZ_NON_OWNING_REF mPtr; + MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK }; } // namespace detail @@ -138,6 +204,8 @@ { if (!mSelfReferencingWeakPtr) { mSelfReferencingWeakPtr.mRef = new detail::WeakReference(static_cast(this)); + } else { + MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mSelfReferencingWeakPtr.mRef); } return mSelfReferencingWeakPtr; } @@ -163,11 +231,13 @@ WeakPtr& operator=(const WeakPtr& aOther) { mRef = aOther.mRef; + MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef); return *this; } WeakPtr(const WeakPtr& aOther) { + // The thread safety check is performed inside of the operator= method. *this = aOther; } @@ -179,12 +249,15 @@ // Ensure that mRef is dereferenceable in the uninitialized state. mRef = new WeakReference(nullptr); } + // The thread safety check happens inside SelfReferencingWeakPtr + // or is initialized in the WeakReference constructor. return *this; } MOZ_IMPLICIT WeakPtr(T* aOther) { *this = aOther; + MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef); } // Ensure that mRef is dereferenceable in the uninitialized state. Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/WindowsVersion.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/WindowsVersion.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/WindowsVersion.h @@ -172,6 +172,12 @@ } MOZ_ALWAYS_INLINE bool +IsWin8Point1OrLater() +{ + return IsWindowsVersionOrLater(0x06030000ul); +} + +MOZ_ALWAYS_INLINE bool IsWin10OrLater() { return IsWindowsVersionOrLater(0x0a000000ul); @@ -184,6 +190,41 @@ IsWindowsBuildOrLater(7600); } +MOZ_ALWAYS_INLINE bool +IsWin7AndPre2000Compatible() { + /* + * See Bug 1279171. + * We'd like to avoid using WMF on specific OS version when compatibility + * mode is in effect. The purpose of this function is to check if FF runs on + * Win7 OS with application compatibility mode being set to 95/98/ME. + * Those compatibility mode options (95/98/ME) can only display and + * be selected for 32-bit application. + * If the compatibility mode is in effect, the GetVersionEx function will + * report the OS as it identifies itself, which may not be the OS that is + * installed. + * Note : 1) We only target for Win7 build number greater than 7600. + * 2) GetVersionEx may be altered or unavailable for release after + * Win8.1. Set pragma to avoid build warning as error. + */ + bool isWin7 = IsNotWin7PreRTM() && !IsWin8OrLater(); + if (!isWin7) { + return false; + } + + OSVERSIONINFOEX info; + ZeroMemory(&info, sizeof(OSVERSIONINFOEX)); + + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); +#pragma warning(push) +#pragma warning(disable:4996) + bool success = GetVersionEx((LPOSVERSIONINFO) &info); +#pragma warning(pop) + if (!success) { + return false; + } + return info.dwMajorVersion < 5; +} + } // namespace mozilla #endif /* mozilla_WindowsVersion_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/XorShift128PlusRNG.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/XorShift128PlusRNG.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/XorShift128PlusRNG.h @@ -33,6 +33,11 @@ * Intel(R) Core(TM) i7-4770 CPU @3.40GHz (Haswell). It is the fastest * generator we are aware of with such empirical statistical properties. * + * The stream of numbers produced by this method repeats every 2**128 - 1 calls + * (i.e. never, for all practical purposes). Zero appears 2**64 - 1 times in + * this period; all other numbers appear 2**64 times. Additionally, each *bit* + * in the produced numbers repeats every 2**128 - 1 calls. + * * This generator is not suitable as a cryptographically secure random number * generator. */ @@ -42,14 +47,20 @@ public: /* * Construct a xorshift128+ pseudo-random number stream using |aInitial0| and - * |aInitial1| as the initial state. These may not both be zero; ideally, they - * should have an almost even mix of zero and one bits. + * |aInitial1| as the initial state. These MUST NOT both be zero. + * + * If the initial states contain many zeros, for a few iterations you'll see + * many zeroes in the generated numbers. It's suggested to seed a SplitMix64 + * generator and use its first two + * outputs to seed xorshift128+. */ XorShift128PlusRNG(uint64_t aInitial0, uint64_t aInitial1) { setState(aInitial0, aInitial1); } - /* Return a pseudo-random 64-bit number. */ + /** + * Return a pseudo-random 64-bit number. + */ uint64_t next() { /* * The offsetOfState*() methods below are provided so that exceedingly-rare @@ -66,9 +77,10 @@ } /* - * Return a pseudo-random floating-point value in the range [0, 1). - * More precisely, choose an integer in the range [0, 2**53) and - * divide it by 2**53. + * Return a pseudo-random floating-point value in the range [0, 1). More + * precisely, choose an integer in the range [0, 2**53) and divide it by + * 2**53. Given the 2**128 - 1 period noted above, the produced doubles are + * all but uniformly distributed in this range. */ double nextDouble() { /* @@ -78,7 +90,7 @@ * is the width of the bitfield in the in-memory format, so we must add one * to get the mantissa's range. */ - static MOZ_CONSTEXPR_VAR int kMantissaBits = + static constexpr int kMantissaBits = mozilla::FloatingPoint::kExponentShift + 1; uint64_t mantissa = next() & ((UINT64_C(1) << kMantissaBits) - 1); return double(mantissa) / (UINT64_C(1) << kMantissaBits); Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/mozalloc.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/mozalloc.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/mozalloc.h @@ -12,14 +12,22 @@ * https://bugzilla.mozilla.org/show_bug.cgi?id=427099 */ -#include -#include #if defined(__cplusplus) # include +// Since libstdc++ 6, including the C headers (e.g. stdlib.h) instead of the +// corresponding C++ header (e.g. cstdlib) can cause confusion in C++ code +// using things defined there. Specifically, with stdlib.h, the use of abs() +// in gfx/graphite2/src/inc/UtfCodec.h somehow ends up picking the wrong abs() +# include +# include +#else +# include +# include #endif #if defined(__cplusplus) #include "mozilla/fallible.h" +#include "mozilla/mozalloc_abort.h" #include "mozilla/TemplateLib.h" #endif #include "mozilla/Attributes.h" @@ -37,8 +45,8 @@ /* Workaround build problem with Sun Studio 12 */ #if defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# undef MOZ_WARN_UNUSED_RESULT -# define MOZ_WARN_UNUSED_RESULT +# undef MOZ_MUST_USE +# define MOZ_MUST_USE # undef MOZ_ALLOCATOR # define MOZ_ALLOCATOR #endif @@ -97,10 +105,10 @@ #if defined(HAVE_POSIX_MEMALIGN) -MFBT_API MOZ_WARN_UNUSED_RESULT +MFBT_API MOZ_MUST_USE int moz_xposix_memalign(void **ptr, size_t alignment, size_t size); -MFBT_API MOZ_WARN_UNUSED_RESULT +MFBT_API MOZ_MUST_USE int moz_posix_memalign(void **ptr, size_t alignment, size_t size); #endif /* if defined(HAVE_POSIX_MEMALIGN) */ @@ -282,10 +290,28 @@ { public: template + T* maybe_pod_malloc(size_t aNumElems) + { + return pod_malloc(aNumElems); + } + + template + T* maybe_pod_calloc(size_t aNumElems) + { + return pod_calloc(aNumElems); + } + + template + T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) + { + return pod_realloc(aPtr, aOldSize, aNewSize); + } + + template T* pod_malloc(size_t aNumElems) { if (aNumElems & mozilla::tl::MulOverflowMask::value) { - return nullptr; + reportAllocOverflow(); } return static_cast(moz_xmalloc(aNumElems * sizeof(T))); } @@ -300,7 +326,7 @@ T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { if (aNewSize & mozilla::tl::MulOverflowMask::value) { - return nullptr; + reportAllocOverflow(); } return static_cast(moz_xrealloc(aPtr, aNewSize * sizeof(T))); } @@ -312,6 +338,12 @@ void reportAllocOverflow() const { + mozalloc_abort("alloc overflow"); + } + + bool checkSimulatedOOM() const + { + return true; } }; Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/fdlibm.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/fdlibm.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/fdlibm.h @@ -0,0 +1,65 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * from: @(#)fdlibm.h 5.1 93/09/24 + * $FreeBSD$ + */ + +#ifndef mozilla_imported_fdlibm_h +#define mozilla_imported_fdlibm_h + +namespace fdlibm { + +double acos(double); +double asin(double); +double atan(double); +double atan2(double, double); + +double cosh(double); +double sinh(double); +double tanh(double); + +double exp(double); +double log(double); +double log10(double); + +double pow(double, double); +double sqrt(double); +double fabs(double); + +double floor(double); +double trunc(double); +double ceil(double); + +double acosh(double); +double asinh(double); +double atanh(double); +double cbrt(double); +double expm1(double); +double hypot(double, double); +double log1p(double); +double log2(double); +double rint(double); +double copysign(double, double); +double nearbyint(double); +double scalbn(double, int); + +float ceilf(float); +float floorf(float); + +float nearbyintf(float); +float rintf(float); +float truncf(float); + +} /* namespace fdlibm */ + +#endif /* mozilla_imported_fdlibm_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js-config.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js-config.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js-config.h @@ -15,6 +15,20 @@ /* Define to 1 if SpiderMonkey is in debug mode. */ /* #undef JS_DEBUG */ +/* + * NB: We have a special case for rust-bindgen, which wants to be able to + * generate both debug and release bindings on a single objdir. + */ +#ifdef JS_DEBUG +#if !defined(DEBUG) && !defined(RUST_BINDGEN) +# error "SpiderMonkey was configured with --enable-debug, so DEBUG must be defined when including this header" +# endif +#else +# if defined(DEBUG) && !defined(RUST_BINDGEN) +# error "SpiderMonkey was configured with --disable-debug, so DEBUG must be not defined when including this header" +# endif +#endif + /* Define to 1 if SpiderMonkey should not use struct types in debug builds. */ /* #undef JS_NO_JSVAL_JSID_STRUCT_TYPES */ @@ -34,18 +48,6 @@ /* Define to 1 to perform extra assertions and heap poisoning. */ /* #undef JS_CRASH_DIAGNOSTICS */ -/* Define to 1 if the header is present and - useable. See jscpucfg.h. */ -/* #undef JS_HAVE_ENDIAN_H */ - -/* Define to 1 if the header is present and - useable. See jscpucfg.h. */ -/* #undef JS_HAVE_MACHINE_ENDIAN_H */ - -/* Define to 1 if the header is present and - useable. See jscpucfg.h. */ -/* #undef JS_HAVE_SYS_ISA_DEFS_H */ - /* Define to 1 if SpiderMonkey is in NUNBOX32 mode. */ #define JS_NUNBOX32 1 @@ -53,7 +55,7 @@ /* #undef JS_PUNBOX64 */ /* MOZILLA JSAPI version number components */ -#define MOZJS_MAJOR_VERSION 45 -#define MOZJS_MINOR_VERSION 0 +#define MOZJS_MAJOR_VERSION 52 +#define MOZJS_MINOR_VERSION 9 #endif /* js_config_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js.msg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js.msg +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js.msg @@ -34,14 +34,14 @@ * * can be used: * - * JS_ReportErrorNumber(JSMSG_NOT_A_SUBSPECIES, "Rhino", "Monkey"); + * JS_ReportErrorNumberASCII(JSMSG_NOT_A_SUBSPECIES, "Rhino", "Monkey"); * * to report: * * "Rhino is not a member of the Monkey family" */ -MSG_DEF(JSMSG_NOT_AN_ERROR, 0, JSEXN_NONE, "") +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_INCOMPATIBLE_PROTO, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}") @@ -63,7 +63,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_REDECLARED_VAR, 2, JSEXN_TYPEERR, "redeclaration of {0} {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}") MSG_DEF(JSMSG_GETTER_ONLY, 0, JSEXN_TYPEERR, "setting a property that has only a getter") MSG_DEF(JSMSG_OVERWRITING_ACCESSOR, 1, JSEXN_TYPEERR, "can't overwrite accessor property {0}") @@ -71,14 +71,12 @@ MSG_DEF(JSMSG_INVALID_MAP_ITERABLE, 1, JSEXN_TYPEERR, "iterable for {0} should have array-like objects") MSG_DEF(JSMSG_NESTING_GENERATOR, 0, JSEXN_TYPEERR, "already executing generator") MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}") -MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED, 0, JSEXN_NONE, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead") -MSG_DEF(JSMSG_TYPE_ERR_BAD_ARGS, 0, JSEXN_TYPEERR, "invalid arguments") +MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED, 0, JSEXN_WARN, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead") +MSG_DEF(JSMSG_ARRAYBUFFER_SLICE_DEPRECATED, 0, JSEXN_WARN, "ArrayBuffer.slice is deprecated; use ArrayBuffer.prototype.slice instead") MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 1, JSEXN_TYPEERR, "bad surrogate character {0}") MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large") MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR, 1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}") -MSG_DEF(JSMSG_WRONG_CONSTRUCTOR, 1, JSEXN_TYPEERR, "wrong constructor called for {0}") MSG_DEF(JSMSG_BUILTIN_CTOR_NO_NEW, 1, JSEXN_TYPEERR, "calling a builtin {0} constructor without new is forbidden") -MSG_DEF(JSMSG_PROTO_SETTING_SLOW, 0, JSEXN_NONE, "mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create") MSG_DEF(JSMSG_BAD_GENERATOR_YIELD, 1, JSEXN_TYPEERR, "yield from closing generator {0}") MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value") MSG_DEF(JSMSG_UNEXPECTED_TYPE, 2, JSEXN_TYPEERR, "{0} is {1}") @@ -89,14 +87,15 @@ MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE, 1, JSEXN_TYPEERR, "{0}: Object is not extensible") MSG_DEF(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE, 2, JSEXN_TYPEERR, "can't define property {1}: {0} is not extensible") MSG_DEF(JSMSG_CANT_REDEFINE_PROP, 1, JSEXN_TYPEERR, "can't redefine non-configurable property {0}") -MSG_DEF(JSMSG_CANT_APPEND_TO_ARRAY, 0, JSEXN_TYPEERR, "can't add elements past the end of an array if its length property is unwritable") MSG_DEF(JSMSG_CANT_REDEFINE_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't redefine array length") MSG_DEF(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't define array index property past the end of an array with non-writable length") MSG_DEF(JSMSG_BAD_GET_SET_FIELD, 1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function") MSG_DEF(JSMSG_THROW_TYPE_ERROR, 0, JSEXN_TYPEERR, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them") MSG_DEF(JSMSG_NOT_EXPECTED_TYPE, 3, JSEXN_TYPEERR, "{0}: expected {1}, got {2}") MSG_DEF(JSMSG_NOT_ITERABLE, 1, JSEXN_TYPEERR, "{0} is not iterable") -MSG_DEF(JSMSG_ALREADY_HAS_PRAGMA, 2, JSEXN_NONE, "{0} is being assigned a {1}, but already has one") +MSG_DEF(JSMSG_NOT_ITERATOR, 1, JSEXN_TYPEERR, "{0} is not iterator") +MSG_DEF(JSMSG_ALREADY_HAS_PRAGMA, 2, JSEXN_WARN, "{0} is being assigned a {1}, but already has one") +MSG_DEF(JSMSG_GET_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.iterator]() returned a non-object value") MSG_DEF(JSMSG_NEXT_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "iterator.next() returned a non-object value") MSG_DEF(JSMSG_CANT_SET_PROTO, 0, JSEXN_TYPEERR, "can't set prototype of this object") MSG_DEF(JSMSG_CANT_SET_PROTO_OF, 1, JSEXN_TYPEERR, "can't set prototype of {0}") @@ -106,11 +105,12 @@ MSG_DEF(JSMSG_PROTO_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0}.prototype is not an object or null") 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, "|this| used uninitialized in {0} class constructor") +MSG_DEF(JSMSG_UNINITIALIZED_THIS_ARROW, 0, JSEXN_REFERENCEERR, "|this| used uninitialized in arrow function in class constructor") MSG_DEF(JSMSG_BAD_DERIVED_RETURN, 1, JSEXN_TYPEERR, "derived class constructor returned invalid value {0}") // JSON MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data") -MSG_DEF(JSMSG_JSON_CYCLIC_VALUE, 1, JSEXN_TYPEERR, "cyclic {0} value") +MSG_DEF(JSMSG_JSON_CYCLIC_VALUE, 0, JSEXN_TYPEERR, "cyclic object value") // Runtime errors MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS, 1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}") @@ -121,6 +121,7 @@ MSG_DEF(JSMSG_TOO_MANY_FUN_SPREADARGS, 0, JSEXN_RANGEERR, "too many function arguments") MSG_DEF(JSMSG_UNINITIALIZED_LEXICAL, 1, JSEXN_REFERENCEERR, "can't access lexical declaration `{0}' before initialization") MSG_DEF(JSMSG_BAD_CONST_ASSIGN, 1, JSEXN_TYPEERR, "invalid assignment to const `{0}'") +MSG_DEF(JSMSG_CANT_DECLARE_GLOBAL_BINDING, 2, JSEXN_TYPEERR, "cannot declare global binding `{0}': {1}") // Date MSG_DEF(JSMSG_INVALID_DATE, 0, JSEXN_RANGEERR, "invalid date") @@ -132,7 +133,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_CONTAINS, 0, JSEXN_NONE, "String.prototype.contains() is deprecated and will be removed in a future release; use String.prototype.includes() instead") // Number MSG_DEF(JSMSG_BAD_RADIX, 0, JSEXN_RANGEERR, "radix must be an integer at least 2 and no greater than 36") @@ -146,7 +146,7 @@ MSG_DEF(JSMSG_NOT_SCRIPTED_FUNCTION, 1, JSEXN_TYPEERR, "{0} is not a scripted function") MSG_DEF(JSMSG_NO_REST_NAME, 0, JSEXN_SYNTAXERR, "no parameter name after ...") MSG_DEF(JSMSG_PARAMETER_AFTER_REST, 0, JSEXN_SYNTAXERR, "parameter after rest parameter") -MSG_DEF(JSMSG_TOO_MANY_FUN_APPLY_ARGS, 0, JSEXN_RANGEERR, "arguments array passed to Function.prototype.apply is too large") +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") @@ -158,10 +158,7 @@ MSG_DEF(JSMSG_UNWRAP_DENIED, 0, JSEXN_ERR, "permission denied to unwrap object") // JSAPI-only (Not thrown as JS exceptions) -MSG_DEF(JSMSG_BAD_CHAR, 1, JSEXN_INTERNALERR, "invalid format character {0}") MSG_DEF(JSMSG_BAD_CLONE_FUNOBJ_SCOPE, 0, JSEXN_TYPEERR, "bad cloned function scope chain") -MSG_DEF(JSMSG_BAD_NEW_RESULT, 1, JSEXN_TYPEERR, "invalid new expression result {0}") -MSG_DEF(JSMSG_BAD_TYPE, 1, JSEXN_TYPEERR, "unknown type {0}") MSG_DEF(JSMSG_CANT_CLONE_OBJECT, 0, JSEXN_TYPEERR, "can't clone object") MSG_DEF(JSMSG_CANT_OPEN, 2, JSEXN_ERR, "can't open {0}: {1}") MSG_DEF(JSMSG_USER_DEFINED_ERROR, 0, JSEXN_ERR, "JS_ReportError was called") @@ -169,11 +166,10 @@ // Internal errors MSG_DEF(JSMSG_ALLOC_OVERFLOW, 0, JSEXN_INTERNALERR, "allocation size overflow") MSG_DEF(JSMSG_BAD_BYTECODE, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}") -MSG_DEF(JSMSG_BAD_SCRIPT_MAGIC, 0, JSEXN_INTERNALERR, "bad script XDR magic number") MSG_DEF(JSMSG_BUFFER_TOO_SMALL, 0, JSEXN_INTERNALERR, "buffer too small") +MSG_DEF(JSMSG_BUILD_ID_NOT_AVAILABLE, 0, JSEXN_INTERNALERR, "build ID is not available") MSG_DEF(JSMSG_BYTECODE_TOO_BIG, 2, JSEXN_INTERNALERR, "bytecode {0} too large (limit {1})") -MSG_DEF(JSMSG_CANT_SET_ARRAY_ATTRS, 0, JSEXN_INTERNALERR, "can't set attributes on indexed array properties") -MSG_DEF(JSMSG_INACTIVE, 0, JSEXN_INTERNALERR, "nothing active on context") +MSG_DEF(JSMSG_ERR_DURING_THROW, 0, JSEXN_INTERNALERR, "an internal error occurred while throwing an exception") MSG_DEF(JSMSG_NEED_DIET, 1, JSEXN_INTERNALERR, "{0} too large") MSG_DEF(JSMSG_OUT_OF_MEMORY, 0, JSEXN_INTERNALERR, "out of memory") MSG_DEF(JSMSG_OVER_RECURSED, 0, JSEXN_INTERNALERR, "too much recursion") @@ -185,9 +181,11 @@ // Frontend MSG_DEF(JSMSG_ACCESSOR_WRONG_ARGS, 3, JSEXN_SYNTAXERR, "{0} functions must have {1} argument{2}") MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid array comprehension left-hand side") -MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 0, JSEXN_INTERNALERR, "array initialiser too large") +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_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method can't be async") +MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await can't be used in default expression") MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "anonymous generator function returns a value") 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") @@ -199,18 +197,19 @@ MSG_DEF(JSMSG_BAD_DESTRUCT_DECL, 0, JSEXN_SYNTAXERR, "missing = in destructuring declaration") MSG_DEF(JSMSG_BAD_DUP_ARGS, 0, JSEXN_SYNTAXERR, "duplicate argument names not allowed in this context") MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 0, JSEXN_SYNTAXERR, "invalid for each loop") -MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for/in left-hand side") -MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 1, JSEXN_TYPEERR, "generator function {0} returns a value") -MSG_DEF(JSMSG_BAD_YIELD_SYNTAX, 0, JSEXN_SYNTAXERR, "yield expression must be parenthesized") -MSG_DEF(JSMSG_BAD_GENERATOR_SYNTAX, 0, JSEXN_SYNTAXERR, "generator expression must be parenthesized") +MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for-in/of left-hand side") +MSG_DEF(JSMSG_LEXICAL_DECL_DEFINES_LET,0, JSEXN_SYNTAXERR, "a lexical declaration can't define a 'let' binding") +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_GENERATOR_RETURN, 1, JSEXN_TYPEERR, "generator function {0} returns a value") MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression") MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_REFERENCEERR, "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_OPERAND, 1, JSEXN_SYNTAXERR, "invalid {0} operand") +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") -MSG_DEF(JSMSG_BAD_STRICT_ASSIGN, 1, JSEXN_SYNTAXERR, "can't assign to {0} in strict mode") +MSG_DEF(JSMSG_BAD_STRICT_ASSIGN, 1, JSEXN_SYNTAXERR, "'{0}' can't be defined or assigned to in strict mode code") MSG_DEF(JSMSG_BAD_SWITCH, 0, JSEXN_SYNTAXERR, "invalid switch statement") 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") @@ -230,13 +229,11 @@ MSG_DEF(JSMSG_CURLY_AFTER_BODY, 0, JSEXN_SYNTAXERR, "missing } after function body") MSG_DEF(JSMSG_CURLY_AFTER_CATCH, 0, JSEXN_SYNTAXERR, "missing } after catch block") MSG_DEF(JSMSG_CURLY_AFTER_FINALLY, 0, JSEXN_SYNTAXERR, "missing } after finally block") -MSG_DEF(JSMSG_CURLY_AFTER_LET, 0, JSEXN_SYNTAXERR, "missing } after let block") MSG_DEF(JSMSG_CURLY_AFTER_LIST, 0, JSEXN_SYNTAXERR, "missing } after property list") MSG_DEF(JSMSG_CURLY_AFTER_TRY, 0, JSEXN_SYNTAXERR, "missing } after try block") MSG_DEF(JSMSG_CURLY_BEFORE_BODY, 0, JSEXN_SYNTAXERR, "missing { before function body") MSG_DEF(JSMSG_CURLY_BEFORE_CATCH, 0, JSEXN_SYNTAXERR, "missing { before catch block") MSG_DEF(JSMSG_CURLY_BEFORE_CLASS, 0, JSEXN_SYNTAXERR, "missing { before class body") -MSG_DEF(JSMSG_CURLY_BEFORE_LET, 0, JSEXN_SYNTAXERR, "missing { before let block") MSG_DEF(JSMSG_CURLY_BEFORE_FINALLY, 0, JSEXN_SYNTAXERR, "missing { before finally block") MSG_DEF(JSMSG_CURLY_BEFORE_SWITCH, 0, JSEXN_SYNTAXERR, "missing { before switch body") MSG_DEF(JSMSG_CURLY_BEFORE_TRY, 0, JSEXN_SYNTAXERR, "missing { before try block") @@ -244,32 +241,37 @@ 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_NONE, "expression closures are deprecated") -MSG_DEF(JSMSG_DEPRECATED_FLAGS_ARG, 0, JSEXN_NONE, "flags argument of String.prototype.{search,match,replace} is deprecated") -MSG_DEF(JSMSG_DEPRECATED_FOR_EACH, 0, JSEXN_NONE, "JavaScript 1.6's for-each-in loops are deprecated; consider using ES6 for-of instead") -MSG_DEF(JSMSG_DEPRECATED_OCTAL, 0, JSEXN_SYNTAXERR, "octal literals and octal escape sequences are deprecated") -MSG_DEF(JSMSG_DEPRECATED_PRAGMA, 1, JSEXN_NONE, "Using //@ to indicate {0} pragmas is deprecated. Use //# instead") +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") MSG_DEF(JSMSG_DUPLICATE_PROPERTY, 1, JSEXN_SYNTAXERR, "property name {0} appears more than once in object literal") +MSG_DEF(JSMSG_DUPLICATE_PROTO_PROPERTY, 0, JSEXN_SYNTAXERR, "property name __proto__ appears more than once in object literal") MSG_DEF(JSMSG_EMPTY_CONSEQUENT, 0, JSEXN_SYNTAXERR, "mistyped ; after conditional?") MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 0, JSEXN_SYNTAXERR, "test for equality (==) mistyped as assignment (=)?") MSG_DEF(JSMSG_EXPORT_DECL_AT_TOP_LEVEL,0, JSEXN_SYNTAXERR, "export declarations may only appear at top level of a module") MSG_DEF(JSMSG_FINALLY_WITHOUT_TRY, 0, JSEXN_SYNTAXERR, "finally without try") +MSG_DEF(JSMSG_FORBIDDEN_AS_STATEMENT, 1, JSEXN_SYNTAXERR, "{0} can't appear in single-statement context") MSG_DEF(JSMSG_FROM_AFTER_IMPORT_CLAUSE, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after import clause") MSG_DEF(JSMSG_FROM_AFTER_EXPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after export *") 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_ILLEGAL_CHARACTER, 0, JSEXN_SYNTAXERR, "illegal character") 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_INVALID_FOR_INOF_DECL_WITH_INIT,1,JSEXN_SYNTAXERR,"for-{0} loop head declarations may not have initializers") -MSG_DEF(JSMSG_IN_AFTER_FOR_NAME, 0, JSEXN_SYNTAXERR, "missing 'in' or 'of' after for") +MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers") MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found") -MSG_DEF(JSMSG_LET_CLASS_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a class") MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable") 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") +MSG_DEF(JSMSG_GENERATOR_LABEL, 0, JSEXN_SYNTAXERR, "generator functions cannot be labelled") +MSG_DEF(JSMSG_FUNCTION_LABEL, 0, JSEXN_SYNTAXERR, "functions cannot be labelled") +MSG_DEF(JSMSG_SLOPPY_FUNCTION_LABEL, 0, JSEXN_SYNTAXERR, "functions can only be labelled inside blocks") MSG_DEF(JSMSG_LINE_BREAK_AFTER_THROW, 0, JSEXN_SYNTAXERR, "no line break is allowed between 'throw' and its expression") +MSG_DEF(JSMSG_LINE_BREAK_BEFORE_ARROW, 0, JSEXN_SYNTAXERR, "no line break is allowed before '=>'") MSG_DEF(JSMSG_MALFORMED_ESCAPE, 1, JSEXN_SYNTAXERR, "malformed {0} character escape sequence") MSG_DEF(JSMSG_MISSING_BINARY_DIGITS, 0, JSEXN_SYNTAXERR, "missing binary digits after '0b'") MSG_DEF(JSMSG_MISSING_EXPONENT, 0, JSEXN_SYNTAXERR, "missing exponent") @@ -279,11 +281,8 @@ MSG_DEF(JSMSG_MISSING_OCTAL_DIGITS, 0, JSEXN_SYNTAXERR, "missing octal digits after '0o'") 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_NAME_AFTER_IMPORT_STAR_AS, 0, JSEXN_SYNTAXERR, "missing name after import * as") MSG_DEF(JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT, 0, JSEXN_SYNTAXERR, "expected named imports or namespace import after comma") -MSG_DEF(JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT, 0, JSEXN_SYNTAXERR, "parameter(s) with default followed by parameter without default") MSG_DEF(JSMSG_NO_BINDING_NAME, 0, JSEXN_SYNTAXERR, "missing binding name") -MSG_DEF(JSMSG_NO_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class default constructors not yet implemented") MSG_DEF(JSMSG_NO_EXPORT_NAME, 0, JSEXN_SYNTAXERR, "missing export name") MSG_DEF(JSMSG_NO_IMPORT_NAME, 0, JSEXN_SYNTAXERR, "missing import name") MSG_DEF(JSMSG_NO_VARIABLE_NAME, 0, JSEXN_SYNTAXERR, "missing variable name") @@ -295,32 +294,30 @@ MSG_DEF(JSMSG_PAREN_AFTER_FORMAL, 0, JSEXN_SYNTAXERR, "missing ) after formal parameters") MSG_DEF(JSMSG_PAREN_AFTER_FOR_CTRL, 0, JSEXN_SYNTAXERR, "missing ) after for-loop control") MSG_DEF(JSMSG_PAREN_AFTER_FOR_OF_ITERABLE, 0, JSEXN_SYNTAXERR, "missing ) after for-of iterable") -MSG_DEF(JSMSG_PAREN_AFTER_LET, 0, JSEXN_SYNTAXERR, "missing ) after let head") MSG_DEF(JSMSG_PAREN_AFTER_SWITCH, 0, JSEXN_SYNTAXERR, "missing ) after switch expression") MSG_DEF(JSMSG_PAREN_AFTER_WITH, 0, JSEXN_SYNTAXERR, "missing ) after with-statement object") MSG_DEF(JSMSG_PAREN_BEFORE_CATCH, 0, JSEXN_SYNTAXERR, "missing ( before catch") MSG_DEF(JSMSG_PAREN_BEFORE_COND, 0, JSEXN_SYNTAXERR, "missing ( before condition") MSG_DEF(JSMSG_PAREN_BEFORE_FORMAL, 0, JSEXN_SYNTAXERR, "missing ( before formal parameters") -MSG_DEF(JSMSG_PAREN_BEFORE_LET, 0, JSEXN_SYNTAXERR, "missing ( before let head") MSG_DEF(JSMSG_PAREN_BEFORE_SWITCH, 0, JSEXN_SYNTAXERR, "missing ( before switch expression") MSG_DEF(JSMSG_PAREN_BEFORE_WITH, 0, JSEXN_SYNTAXERR, "missing ( before with-statement object") MSG_DEF(JSMSG_PAREN_IN_PAREN, 0, JSEXN_SYNTAXERR, "missing ) in parenthetical") MSG_DEF(JSMSG_RC_AFTER_EXPORT_SPEC_LIST, 0, JSEXN_SYNTAXERR, "missing '}' after export specifier list") MSG_DEF(JSMSG_RC_AFTER_IMPORT_SPEC_LIST, 0, JSEXN_SYNTAXERR, "missing '}' after module specifier list") -MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 1, JSEXN_TYPEERR, "redeclaration of identifier '{0}' in catch") -MSG_DEF(JSMSG_REDECLARED_PARAM, 1, JSEXN_TYPEERR, "redeclaration of formal parameter {0}") +MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 1, JSEXN_SYNTAXERR, "redeclaration of identifier '{0}' in catch") MSG_DEF(JSMSG_RESERVED_ID, 1, JSEXN_SYNTAXERR, "{0} is a reserved identifier") +MSG_DEF(JSMSG_REST_WITH_COMMA, 0, JSEXN_SYNTAXERR, "rest element may not have a trailing comma") MSG_DEF(JSMSG_REST_WITH_DEFAULT, 0, JSEXN_SYNTAXERR, "rest parameter may not have a default") MSG_DEF(JSMSG_SELFHOSTED_TOP_LEVEL_LEXICAL, 1, JSEXN_SYNTAXERR, "self-hosted code cannot contain top-level {0} declarations") +MSG_DEF(JSMSG_SELFHOSTED_METHOD_CALL, 0, JSEXN_SYNTAXERR, "self-hosted code may not contain direct method calls. Use callFunction() or callContentFunction()") MSG_DEF(JSMSG_SELFHOSTED_UNBOUND_NAME, 0, JSEXN_TYPEERR, "self-hosted code may not contain unbound name lookups") -MSG_DEF(JSMSG_SELFHOSTED_METHOD_CALL, 0, JSEXN_SYNTAXERR, "self-hosted code may not contain direct method calls") MSG_DEF(JSMSG_SEMI_AFTER_FOR_COND, 0, JSEXN_SYNTAXERR, "missing ; after for-loop condition") MSG_DEF(JSMSG_SEMI_AFTER_FOR_INIT, 0, JSEXN_SYNTAXERR, "missing ; after for-loop initializer") MSG_DEF(JSMSG_SEMI_BEFORE_STMNT, 0, JSEXN_SYNTAXERR, "missing ; before statement") MSG_DEF(JSMSG_SOURCE_TOO_LONG, 0, JSEXN_RANGEERR, "source is too long") -MSG_DEF(JSMSG_STMT_AFTER_RETURN, 0, JSEXN_NONE, "unreachable code after return statement") +MSG_DEF(JSMSG_STMT_AFTER_RETURN, 0, JSEXN_WARN, "unreachable code after return statement") MSG_DEF(JSMSG_STRICT_CODE_WITH, 0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements") -MSG_DEF(JSMSG_STRICT_FUNCTION_STATEMENT, 0, JSEXN_SYNTAXERR, "in strict mode code, functions may be declared only at top level or immediately within another function") +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") @@ -343,19 +340,53 @@ MSG_DEF(JSMSG_WHILE_AFTER_DO, 0, JSEXN_SYNTAXERR, "missing while after do-loop body") MSG_DEF(JSMSG_YIELD_IN_ARROW, 0, JSEXN_SYNTAXERR, "arrow function may not contain yield") MSG_DEF(JSMSG_YIELD_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "yield in default expression") +MSG_DEF(JSMSG_YIELD_IN_METHOD, 0, JSEXN_SYNTAXERR, "non-generator method definitions may not contain yield") 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 in non-exotic functions") +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") // 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_NONE, "Successfully compiled asm.js code ({0})") +MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 1, JSEXN_WARN, "Successfully compiled asm.js code ({0})") + +// wasm +MSG_DEF(JSMSG_WASM_COMPILE_ERROR, 1, JSEXN_WASMCOMPILEERROR, "{0}") +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") +MSG_DEF(JSMSG_WASM_INTEGER_OVERFLOW, 0, JSEXN_WASMRUNTIMEERROR, "integer overflow") +MSG_DEF(JSMSG_WASM_INVALID_CONVERSION, 0, JSEXN_WASMRUNTIMEERROR, "invalid conversion to integer") +MSG_DEF(JSMSG_WASM_INT_DIVIDE_BY_ZERO, 0, JSEXN_WASMRUNTIMEERROR, "integer divide by zero") +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_BAD_UINT32, 2, JSEXN_RANGEERR, "bad {0} {1}") +MSG_DEF(JSMSG_WASM_BAD_GROW, 1, JSEXN_RANGEERR, "failed to grow {0}") +MSG_DEF(JSMSG_WASM_BAD_FIT, 2, JSEXN_RANGEERR, "{0} segment does not fit in {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_IMP_SIZE, 1, JSEXN_TYPEERR, "imported {0} with incompatible size") +MSG_DEF(JSMSG_WASM_BAD_IMP_MAX, 1, JSEXN_TYPEERR, "imported {0} with incompatible maximum size") +MSG_DEF(JSMSG_WASM_BAD_ELEMENT, 0, JSEXN_TYPEERR, "\"element\" property of table descriptor must be \"anyfunc\"") +MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG, 0, JSEXN_TYPEERR, "second argument must be an object") +MSG_DEF(JSMSG_WASM_BAD_IMPORT_FIELD, 2, JSEXN_TYPEERR, "import object field '{0}' is not {1}") +MSG_DEF(JSMSG_WASM_BAD_IMPORT_SIG, 0, JSEXN_TYPEERR, "imported function signature mismatch") +MSG_DEF(JSMSG_WASM_BAD_TABLE_VALUE, 0, JSEXN_TYPEERR, "can only assign WebAssembly exported functions to Table") +MSG_DEF(JSMSG_WASM_BAD_I64, 0, JSEXN_TYPEERR, "cannot pass i64 to or from JS") +MSG_DEF(JSMSG_WASM_NO_TRANSFER, 0, JSEXN_TYPEERR, "cannot transfer WebAssembly/asm.js ArrayBuffer") +MSG_DEF(JSMSG_WASM_TEXT_FAIL, 1, JSEXN_SYNTAXERR, "wasm text error: {0}") // Proxy MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE, 2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value") +MSG_DEF(JSMSG_BAD_GETPROTOTYPEOF_TRAP_RETURN,0,JSEXN_TYPEERR,"proxy getPrototypeOf handler returned a non-object, non-null value") +MSG_DEF(JSMSG_INCONSISTENT_GETPROTOTYPEOF_TRAP,0,JSEXN_TYPEERR,"proxy getPrototypeOf handler didn't return the target object's prototype") +MSG_DEF(JSMSG_PROXY_SETPROTOTYPEOF_RETURNED_FALSE, 0, JSEXN_TYPEERR, "proxy setPrototypeOf handler returned false") +MSG_DEF(JSMSG_PROXY_ISEXTENSIBLE_RETURNED_FALSE,0,JSEXN_TYPEERR,"proxy isExtensible handler must return the same extensibility as target") +MSG_DEF(JSMSG_INCONSISTENT_SETPROTOTYPEOF_TRAP,0,JSEXN_TYPEERR,"proxy setPrototypeOf handler returned true, even though the target's prototype is immutable because the target is non-extensible") MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 0, JSEXN_TYPEERR, "can't change object's extensibility") MSG_DEF(JSMSG_CANT_DEFINE_INVALID, 0, JSEXN_TYPEERR, "proxy can't define an incompatible property descriptor") MSG_DEF(JSMSG_CANT_DEFINE_NEW, 0, JSEXN_TYPEERR, "proxy can't define a new property on a non-extensible object") @@ -374,7 +405,6 @@ MSG_DEF(JSMSG_CANT_SET_NW_NC, 0, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property") MSG_DEF(JSMSG_CANT_SET_WO_SETTER, 0, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property without a setter") MSG_DEF(JSMSG_CANT_SKIP_NC, 0, JSEXN_TYPEERR, "proxy can't skip a non-configurable property") -MSG_DEF(JSMSG_INVALID_TRAP_RESULT, 2, JSEXN_TYPEERR, "trap {1} for {0} returned an invalid result") MSG_DEF(JSMSG_ONWKEYS_STR_SYM, 0, JSEXN_TYPEERR, "proxy [[OwnPropertyKeys]] must return an array with only string and symbol elements") MSG_DEF(JSMSG_MUST_REPORT_SAME_VALUE, 0, JSEXN_TYPEERR, "proxy must report the same value for a non-writable, non-configurable property") MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED, 0, JSEXN_TYPEERR, "proxy must report undefined for a non-configurable accessor property without a getter") @@ -385,6 +415,7 @@ MSG_DEF(JSMSG_PROXY_GETOWN_OBJORUNDEF, 0, JSEXN_TYPEERR, "proxy [[GetOwnProperty]] must return an object or undefined") MSG_DEF(JSMSG_PROXY_REVOKED, 0, JSEXN_TYPEERR, "illegal operation attempted on a revoked proxy") MSG_DEF(JSMSG_PROXY_ARG_REVOKED, 1, JSEXN_TYPEERR, "argument {0} cannot be a revoked proxy") +MSG_DEF(JSMSG_BAD_TRAP, 1, JSEXN_TYPEERR, "proxy handler's {0} trap wasn't undefined, null, or callable") // Structured cloning MSG_DEF(JSMSG_SC_BAD_CLONE_VERSION, 0, JSEXN_ERR, "unsupported structured clone version") @@ -392,14 +423,18 @@ MSG_DEF(JSMSG_SC_DUP_TRANSFERABLE, 0, JSEXN_TYPEERR, "duplicate transferable for structured clone") MSG_DEF(JSMSG_SC_NOT_TRANSFERABLE, 0, JSEXN_TYPEERR, "invalid transferable array for structured clone") MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE, 0, JSEXN_TYPEERR, "unsupported type for structured data") -MSG_DEF(JSMSG_SC_SHMEM_MUST_TRANSFER, 0, JSEXN_TYPEERR, "SharedArrayBuffer must be explicitly transfered during structured cloning") +MSG_DEF(JSMSG_SC_NOT_CLONABLE, 1, JSEXN_TYPEERR, "{0} cannot be cloned in this context") +MSG_DEF(JSMSG_SC_SAB_TRANSFER, 0, JSEXN_WARN, "SharedArrayBuffer must not be in the transfer list") +MSG_DEF(JSMSG_SC_SAB_DISABLED, 0, JSEXN_TYPEERR, "SharedArrayBuffer not cloned - shared memory disabled in receiver") // Debugger MSG_DEF(JSMSG_ASSIGN_FUNCTION_OR_NULL, 1, JSEXN_TYPEERR, "value assigned to {0} must be a function or null") +MSG_DEF(JSMSG_DEBUG_BAD_AWAIT, 0, JSEXN_TYPEERR, "await expression received invalid value") MSG_DEF(JSMSG_DEBUG_BAD_LINE, 0, JSEXN_TYPEERR, "invalid line number") MSG_DEF(JSMSG_DEBUG_BAD_OFFSET, 0, JSEXN_TYPEERR, "invalid script offset") MSG_DEF(JSMSG_DEBUG_BAD_REFERENT, 2, JSEXN_TYPEERR, "{0} does not refer to {1}") 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_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") @@ -408,22 +443,25 @@ MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGING, 0, JSEXN_ERR, "can't set breakpoint: script global is not a debuggee") MSG_DEF(JSMSG_DEBUG_NOT_IDLE, 0, JSEXN_ERR, "can't start debugging: a debuggee script is on the stack") MSG_DEF(JSMSG_DEBUG_NOT_LIVE, 1, JSEXN_ERR, "{0} is not live") -MSG_DEF(JSMSG_DEBUG_NO_SCOPE_OBJECT, 0, JSEXN_TYPEERR, "declarative Environments don't have binding objects") -MSG_DEF(JSMSG_DEBUG_OBJECT_PROTO, 0, JSEXN_TYPEERR, "Debugger.Object.prototype is not a valid Debugger.Object") -MSG_DEF(JSMSG_DEBUG_OBJECT_WRONG_OWNER,0, JSEXN_TYPEERR, "Debugger.Object belongs to a different Debugger") -MSG_DEF(JSMSG_DEBUG_OPTIMIZED_OUT, 0, JSEXN_ERR, "variable has been optimized out") +MSG_DEF(JSMSG_DEBUG_NO_ENV_OBJECT, 0, JSEXN_TYPEERR, "declarative Environments don't have binding objects") +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_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") +MSG_DEF(JSMSG_DEBUGGEE_WOULD_RUN, 2, JSEXN_DEBUGGEEWOULDRUN, "debuggee `{0}:{1}' would run") MSG_DEF(JSMSG_NOT_CALLABLE_OR_UNDEFINED, 0, JSEXN_TYPEERR, "value is not a function or undefined") MSG_DEF(JSMSG_NOT_TRACKING_ALLOCATIONS, 1, JSEXN_ERR, "Cannot call {0} without setting trackingAllocationSites to true") -MSG_DEF(JSMSG_NOT_TRACKING_TENURINGS, 1, JSEXN_ERR, "Cannot call {0} without setting trackingTenurePromotions to true") MSG_DEF(JSMSG_OBJECT_METADATA_CALLBACK_ALREADY_SET, 0, JSEXN_ERR, "Cannot track object allocation, because other tools are already doing so") MSG_DEF(JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL, 0, JSEXN_TYPEERR, "findScripts query object with 'innermost' property must have 'line' and either 'displayURL', 'url', or 'source'") MSG_DEF(JSMSG_QUERY_LINE_WITHOUT_URL, 0, JSEXN_TYPEERR, "findScripts query object has 'line' property, but no 'displayURL', 'url', or 'source' property") MSG_DEF(JSMSG_DEBUG_CANT_SET_OPT_ENV, 1, JSEXN_REFERENCEERR, "can't set `{0}' in an optimized-out environment") MSG_DEF(JSMSG_DEBUG_INVISIBLE_COMPARTMENT, 0, JSEXN_TYPEERR, "object in compartment marked as invisible to Debugger") MSG_DEF(JSMSG_DEBUG_CENSUS_BREAKDOWN, 1, JSEXN_TYPEERR, "unrecognized 'by' value in takeCensus breakdown: {0}") +MSG_DEF(JSMSG_DEBUG_PROMISE_NOT_RESOLVED, 0, JSEXN_TYPEERR, "Promise hasn't been resolved") +MSG_DEF(JSMSG_DEBUG_PROMISE_NOT_FULFILLED, 0, JSEXN_TYPEERR, "Promise hasn't been fulfilled") +MSG_DEF(JSMSG_DEBUG_PROMISE_NOT_REJECTED, 0, JSEXN_TYPEERR, "Promise hasn't been rejected") // Tracelogger MSG_DEF(JSMSG_TRACELOGGER_ENABLE_FAIL, 1, JSEXN_ERR, "enabling tracelogger failed: {0}") @@ -443,14 +481,23 @@ MSG_DEF(JSMSG_UNDEFINED_CURRENCY, 0, JSEXN_TYPEERR, "undefined currency in NumberFormat() with currency style") // RegExp +MSG_DEF(JSMSG_BACK_REF_OUT_OF_RANGE, 0, JSEXN_SYNTAXERR, "back reference out of range in regular expression") MSG_DEF(JSMSG_BAD_CLASS_RANGE, 0, JSEXN_SYNTAXERR, "invalid range in character class") MSG_DEF(JSMSG_ESCAPE_AT_END_OF_REGEXP, 0, JSEXN_SYNTAXERR, "\\ at end of pattern") +MSG_DEF(JSMSG_EXEC_NOT_OBJORNULL, 0, JSEXN_TYPEERR, "RegExp exec method should return object or null") +MSG_DEF(JSMSG_INVALID_DECIMAL_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid decimal escape in regular expression") MSG_DEF(JSMSG_INVALID_GROUP, 0, JSEXN_SYNTAXERR, "invalid regexp group") +MSG_DEF(JSMSG_INVALID_IDENTITY_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid identity escape in regular expression") +MSG_DEF(JSMSG_INVALID_UNICODE_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid unicode escape in regular expression") MSG_DEF(JSMSG_MISSING_PAREN, 0, JSEXN_SYNTAXERR, "unterminated parenthetical") MSG_DEF(JSMSG_NEWREGEXP_FLAGGED, 0, JSEXN_TYPEERR, "can't supply flags when constructing one RegExp from another") 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_TOO_MANY_PARENS, 0, JSEXN_INTERNALERR, "too many parentheses in regular expression") +MSG_DEF(JSMSG_UNICODE_OVERFLOW, 0, JSEXN_SYNTAXERR, "unicode codepoint should not be greater than 0x10FFFF in regular expression") MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression") MSG_DEF(JSMSG_UNTERM_CLASS, 0, JSEXN_SYNTAXERR, "unterminated character class") @@ -466,30 +513,34 @@ MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_ARGS, 0, JSEXN_RANGEERR, "invalid field descriptor") 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") + +// Array +MSG_DEF(JSMSG_TOO_LONG_ARRAY, 0, JSEXN_TYPEERR, "Too long array") // Typed array MSG_DEF(JSMSG_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index") +MSG_DEF(JSMSG_NON_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected ArrayBuffer, but species constructor returned non-ArrayBuffer") +MSG_DEF(JSMSG_SAME_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected different ArrayBuffer, but species constructor returned same ArrayBuffer") +MSG_DEF(JSMSG_SHORT_ARRAY_BUFFER_RETURNED, 2, JSEXN_TYPEERR, "expected ArrayBuffer with at least {0} bytes, but species constructor returns ArrayBuffer with {1} bytes") MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS, 0, JSEXN_TYPEERR, "invalid arguments") -MSG_DEF(JSMSG_TYPED_ARRAY_BAD_OBJECT, 0, JSEXN_TYPEERR, "invalid object argument") -MSG_DEF(JSMSG_TYPED_ARRAY_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index") MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG,1, JSEXN_RANGEERR, "argument {0} must be >= 0") MSG_DEF(JSMSG_TYPED_ARRAY_DETACHED, 0, JSEXN_TYPEERR, "attempting to access detached ArrayBuffer") +MSG_DEF(JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS, 0, JSEXN_RANGEERR, "attempting to construct out-of-bounds TypedArray on ArrayBuffer") +MSG_DEF(JSMSG_TYPED_ARRAY_CALL_OR_CONSTRUCT, 1, JSEXN_TYPEERR, "cannot directly {0} builtin %TypedArray%") +MSG_DEF(JSMSG_NON_TYPED_ARRAY_RETURNED, 0, JSEXN_TYPEERR, "constructor didn't return TypedArray object") +MSG_DEF(JSMSG_SHORT_TYPED_ARRAY_RETURNED, 2, JSEXN_TYPEERR, "expected TypedArray of at least length {0}, but constructor returned TypedArray of length {1}") // Shared array buffer -MSG_DEF(JSMSG_SHARED_ARRAY_BAD_OBJECT, 0, JSEXN_TYPEERR, "invalid object argument") MSG_DEF(JSMSG_SHARED_ARRAY_BAD_LENGTH, 0, JSEXN_RANGEERR, "length argument out of range") - -// Shared typed array -MSG_DEF(JSMSG_SHARED_TYPED_ARRAY_BAD_OBJECT, 0, JSEXN_TYPEERR, "invalid object argument") -MSG_DEF(JSMSG_SHARED_TYPED_ARRAY_BAD_ARGS, 0, JSEXN_RANGEERR, "bad combination of offset, length, and element size") -MSG_DEF(JSMSG_SHARED_TYPED_ARRAY_ARG_RANGE, 1, JSEXN_RANGEERR, "argument {0} out of range") -MSG_DEF(JSMSG_SHARED_TYPED_ARRAY_BAD_LENGTH, 0, JSEXN_TYPEERR, "length argument must not be an object") +MSG_DEF(JSMSG_NON_SHARED_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected SharedArrayBuffer, but species constructor returned non-SharedArrayBuffer") +MSG_DEF(JSMSG_SAME_SHARED_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected different SharedArrayBuffer, but species constructor returned same SharedArrayBuffer") +MSG_DEF(JSMSG_SHORT_SHARED_ARRAY_BUFFER_RETURNED, 2, JSEXN_TYPEERR, "expected SharedArrayBuffer with at least {0} bytes, but species constructor returns SharedArrayBuffer with {1} bytes") // Reflect MSG_DEF(JSMSG_BAD_PARSE_NODE, 0, JSEXN_INTERNALERR, "bad parse node") // Symbol -MSG_DEF(JSMSG_BAD_SYMBOL, 1, JSEXN_TYPEERR, "{0} is not a well-known @@-symbol") MSG_DEF(JSMSG_SYMBOL_TO_STRING, 0, JSEXN_TYPEERR, "can't convert symbol to string") MSG_DEF(JSMSG_SYMBOL_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert symbol to number") @@ -497,7 +548,6 @@ MSG_DEF(JSMSG_ATOMICS_BAD_ARRAY, 0, JSEXN_TYPEERR, "invalid array type for the operation") MSG_DEF(JSMSG_ATOMICS_TOO_LONG, 0, JSEXN_RANGEERR, "timeout value too large") MSG_DEF(JSMSG_ATOMICS_WAIT_NOT_ALLOWED, 0, JSEXN_ERR, "waiting is not allowed on this thread") -MSG_DEF(JSMSG_ATOMICS_BAD_INDEX, 0, JSEXN_RANGEERR, "out-of-range index for atomic access") // XPConnect wrappers and DOM bindings MSG_DEF(JSMSG_CANT_SET_INTERPOSED, 1, JSEXN_TYPEERR, "unable to set interposed data property '{0}'") @@ -520,3 +570,12 @@ MSG_DEF(JSMSG_AMBIGUOUS_IMPORT, 1, JSEXN_SYNTAXERR, "ambiguous import '{0}'") 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_MODULE_INSTANTIATE_FAILED, 0, JSEXN_INTERNALERR, "attempt to re-instantiate module after failure") +MSG_DEF(JSMSG_BAD_MODULE_STATE, 0, JSEXN_INTERNALERR, "module record in unexpected state") + +// Promise +MSG_DEF(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself.") +MSG_DEF(JSMSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY, 0, JSEXN_TYPEERR, "GetCapabilitiesExecutor function already invoked with non-undefined values.") +MSG_DEF(JSMSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the resolve function.") +MSG_DEF(JSMSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the reject function.") +MSG_DEF(JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON,0, JSEXN_INTERNALERR, "Promise rejection value is a non-unwrappable cross-compartment wrapper.") Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/CallArgs.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/CallArgs.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/CallArgs.h @@ -6,16 +6,51 @@ /* * Helper classes encapsulating access to the callee, |this| value, arguments, - * and argument count for a function call. + * and argument count for a call/construct operation. * - * The intent of JS::CallArgs and JS::CallReceiver is that they be used to - * encapsulate access to the un-abstracted |unsigned argc, Value* vp| arguments - * to a function. 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 or CallReceiver. - * New code should use CallArgs and CallReceiver instead whenever possible. + * JS::CallArgs encapsulates access to a JSNative's un-abstracted + * |unsigned argc, Value* vp| arguments. The principal way to create a + * JS::CallArgs is using JS::CallArgsFromVp: + * + * // If provided no arguments or a non-numeric first argument, return zero. + * // Otherwise return |this| exactly as given, without boxing. + * static bool + * Func(JSContext* cx, unsigned argc, JS::Value* vp) + * { + * JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + * + * // Guard against no arguments or a non-numeric arg0. + * if (args.length() == 0 || !args[0].isNumber()) { + * args.rval().setInt32(0); + * return true; + * } + * + * // Access to the callee must occur before accessing/setting + * // the return value. + * JSObject& callee = args.callee(); + * args.rval().setObject(callee); + * + * // callee() and calleev() will now assert. + * + * // It's always fine to access thisv(). + * HandleValue thisv = args.thisv(); + * args.rval().set(thisv); + * + * // As the return value was last set to |this|, returns |this|. + * return true; + * } + * + * CallArgs is exposed publicly and used internally. Not all parts of its + * public interface are meant to be used by embedders! See inline comments to + * for details. + * + * 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. + * New code should use CallArgs instead whenever possible. * * The eventual plan is to change JSNative to take |const CallArgs&| directly, * for automatic assertion of correct use and to make calling functions more @@ -42,118 +77,99 @@ typedef bool (* JSNative)(JSContext* cx, unsigned argc, JS::Value* vp); -/* - * Compute |this| for the |vp| inside a JSNative, either boxing primitives or - * replacing with the global object as necessary. - * - * This method will go away at some point: instead use |args.thisv()|. If the - * value is an object, no further work is required. If that value is |null| or - * |undefined|, use |JS_GetGlobalForObject| to compute the global object. If - * the value is some other primitive, use |JS_ValueToObject| to box it. - */ -extern JS_PUBLIC_API(JS::Value) -JS_ComputeThis(JSContext* cx, JS::Value* vp); - namespace JS { extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue; +namespace detail { + /* - * JS::CallReceiver encapsulates access to the callee, |this|, and eventual - * return value for a function call. The principal way to create a - * CallReceiver is using JS::CallReceiverFromVp: - * - * static bool - * FunctionReturningThis(JSContext* cx, unsigned argc, JS::Value* vp) - * { - * JS::CallReceiver rec = JS::CallReceiverFromVp(vp); - * - * // Access to the callee must occur before accessing/setting - * // the return value. - * JSObject& callee = rec.callee(); - * rec.rval().set(JS::ObjectValue(callee)); - * - * // callee() and calleev() will now assert. - * - * // It's always fine to access thisv(). - * HandleValue thisv = rec.thisv(); - * rec.rval().set(thisv); - * - * // As the return value was last set to |this|, returns |this|. - * return true; - * } - * - * A note on JS_ComputeThis and JS_THIS_OBJECT: these methods currently aren't - * part of the CallReceiver interface. We will likely add them at some point. - * Until then, you should probably continue using |vp| directly for these two - * cases. - * - * CallReceiver is exposed publicly and used internally. Not all parts of its - * public interface are meant to be used by embedders! See inline comments to - * for details. + * Compute |this| for the |vp| inside a JSNative, either boxing primitives or + * replacing with the global object as necessary. */ - -namespace detail { +extern JS_PUBLIC_API(Value) +ComputeThis(JSContext* cx, JS::Value* vp); #ifdef JS_DEBUG extern JS_PUBLIC_API(void) -CheckIsValidConstructible(Value v); +CheckIsValidConstructible(const Value& v); #endif -enum UsedRval { IncludeUsedRval, NoUsedRval }; - -template -class MOZ_STACK_CLASS UsedRvalBase; - -template<> -class MOZ_STACK_CLASS UsedRvalBase +class MOZ_STACK_CLASS IncludeUsedRval { protected: +#ifdef JS_DEBUG mutable bool usedRval_; void setUsedRval() const { usedRval_ = true; } void clearUsedRval() const { usedRval_ = false; } + void assertUnusedRval() const { MOZ_ASSERT(!usedRval_); } +#else + void setUsedRval() const {} + void clearUsedRval() const {} + void assertUnusedRval() const {} +#endif }; -template<> -class MOZ_STACK_CLASS UsedRvalBase +class MOZ_STACK_CLASS NoUsedRval { protected: void setUsedRval() const {} void clearUsedRval() const {} + void assertUnusedRval() const {} }; -template -class MOZ_STACK_CLASS CallReceiverBase : public UsedRvalBase< -#ifdef JS_DEBUG - WantUsedRval -#else - NoUsedRval -#endif - > +template +class MOZ_STACK_CLASS CallArgsBase : public WantUsedRval { + static_assert(mozilla::IsSame::value || + mozilla::IsSame::value, + "WantUsedRval can only be IncludeUsedRval or NoUsedRval"); + protected: Value* argv_; + unsigned argc_; + bool constructing_; public: - /* - * Returns the function being called, as an object. Must not be called - * after rval() has been used! - */ - JSObject& callee() const { - MOZ_ASSERT(!this->usedRval_); - return argv_[-2].toObject(); - } + // CALLEE ACCESS /* * Returns the function being called, as a value. Must not be called after * rval() has been used! */ HandleValue calleev() const { - MOZ_ASSERT(!this->usedRval_); + this->assertUnusedRval(); return HandleValue::fromMarkedLocation(&argv_[-2]); } /* + * Returns the function being called, as an object. Must not be called + * after rval() has been used! + */ + JSObject& callee() const { + return calleev().toObject(); + } + + // CALLING/CONSTRUCTING-DIFFERENTIATIONS + + bool isConstructing() const { + if (!argv_[-1].isMagic()) + return false; + +#ifdef JS_DEBUG + if (!this->usedRval_) + CheckIsValidConstructible(calleev()); +#endif + + return true; + } + + MutableHandleValue newTarget() const { + MOZ_ASSERT(constructing_); + return MutableHandleValue::fromMarkedLocation(&this->argv_[argc_]); + } + + /* * Returns the |this| value passed to the function. This method must not * be called when the function is being called as a constructor via |new|. * The value may or may not be an object: it is the individual function's @@ -170,17 +186,40 @@ if (thisv().isObject()) return thisv(); - return JS_ComputeThis(cx, base()); + return ComputeThis(cx, base()); } - bool isConstructing() const { -#ifdef JS_DEBUG - if (this->usedRval_) - CheckIsValidConstructible(calleev()); -#endif - return argv_[-1].isMagic(); + // ARGUMENTS + + /* Returns the number of arguments. */ + unsigned length() const { return argc_; } + + /* Returns the i-th zero-indexed argument. */ + MutableHandleValue operator[](unsigned i) const { + MOZ_ASSERT(i < argc_); + return MutableHandleValue::fromMarkedLocation(&this->argv_[i]); + } + + /* + * Returns the i-th zero-indexed argument, or |undefined| if there's no + * such argument. + */ + HandleValue get(unsigned i) const { + return i < length() + ? HandleValue::fromMarkedLocation(&this->argv_[i]) + : UndefinedHandleValue; + } + + /* + * Returns true if the i-th zero-indexed argument is present and is not + * |undefined|. + */ + bool hasDefined(unsigned i) const { + return i < argc_ && !this->argv_[i].isUndefined(); } + // RETURN VALUE + /* * Returns the currently-set return value. The initial contents of this * value are unspecified. Once this method has been called, callee() and @@ -198,135 +237,41 @@ } public: - // These methods are only intended for internal use. Embedders shouldn't - // use them! - - Value* base() const { return argv_ - 2; } - - Value* spAfterCall() const { - this->setUsedRval(); - return argv_ - 1; - } - - public: // These methods are publicly exposed, but they are *not* to be used when // implementing a JSNative method and encapsulating access to |vp| within // it. You probably don't want to use these! - void setCallee(Value aCalleev) const { + void setCallee(const Value& aCalleev) const { this->clearUsedRval(); argv_[-2] = aCalleev; } - void setThis(Value aThisv) const { + void setThis(const Value& aThisv) const { argv_[-1] = aThisv; } MutableHandleValue mutableThisv() const { return MutableHandleValue::fromMarkedLocation(&argv_[-1]); } -}; - -} // namespace detail - -class MOZ_STACK_CLASS CallReceiver : public detail::CallReceiverBase -{ - private: - friend CallReceiver CallReceiverFromVp(Value* vp); - friend CallReceiver CallReceiverFromArgv(Value* argv); -}; - -MOZ_ALWAYS_INLINE CallReceiver -CallReceiverFromArgv(Value* argv) -{ - CallReceiver receiver; - receiver.clearUsedRval(); - receiver.argv_ = argv; - return receiver; -} - -MOZ_ALWAYS_INLINE CallReceiver -CallReceiverFromVp(Value* vp) -{ - return CallReceiverFromArgv(vp + 2); -} - -/* - * JS::CallArgs encapsulates everything JS::CallReceiver does, plus access to - * the function call's arguments. The principal way to create a CallArgs is - * like so, using JS::CallArgsFromVp: - * - * static bool - * FunctionReturningArgcTimesArg0(JSContext* cx, unsigned argc, JS::Value* vp) - * { - * JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - * - * // Guard against no arguments or a non-numeric arg0. - * if (args.length() == 0 || !args[0].isNumber()) { - * args.rval().setInt32(0); - * return true; - * } - * - * args.rval().set(JS::NumberValue(args.length() * args[0].toNumber())); - * return true; - * } - * - * CallArgs is exposed publicly and used internally. Not all parts of its - * public interface are meant to be used by embedders! See inline comments to - * for details. - */ -namespace detail { - -template -class MOZ_STACK_CLASS CallArgsBase : - public mozilla::Conditional >::Type -{ - protected: - unsigned argc_; - bool constructing_; public: - /* Returns the number of arguments. */ - unsigned length() const { return argc_; } + // These methods are publicly exposed, but we're unsure of the interfaces + // (because they're hackish and drop assertions). Avoid using these if you + // can. - /* Returns the i-th zero-indexed argument. */ - MutableHandleValue operator[](unsigned i) const { - MOZ_ASSERT(i < argc_); - return MutableHandleValue::fromMarkedLocation(&this->argv_[i]); - } + Value* array() const { return argv_; } + Value* end() const { return argv_ + argc_ + constructing_; } - /* - * Returns the i-th zero-indexed argument, or |undefined| if there's no - * such argument. - */ - HandleValue get(unsigned i) const { - return i < length() - ? HandleValue::fromMarkedLocation(&this->argv_[i]) - : UndefinedHandleValue; - } + public: + // These methods are only intended for internal use. Embedders shouldn't + // use them! - /* - * Returns true if the i-th zero-indexed argument is present and is not - * |undefined|. - */ - bool hasDefined(unsigned i) const { - return i < argc_ && !this->argv_[i].isUndefined(); - } + Value* base() const { return argv_ - 2; } - MutableHandleValue newTarget() const { - MOZ_ASSERT(constructing_); - return MutableHandleValue::fromMarkedLocation(&this->argv_[argc_]); + Value* spAfterCall() const { + this->setUsedRval(); + return argv_ - 1; } - - public: - // These methods are publicly exposed, but we're less sure of the interface - // here than we'd like (because they're hackish and drop assertions). Try - // to avoid using these if you can. - - Value* array() const { return this->argv_; } - Value* end() const { return this->argv_ + argc_ + constructing_; } }; } // namespace detail @@ -343,6 +288,10 @@ args.argv_ = argv; args.argc_ = argc; args.constructing_ = constructing; +#ifdef DEBUG + for (unsigned i = 0; i < argc; ++i) + MOZ_ASSERT_IF(argv[i].isMarkable(), !GCThingIsMarkedGray(GCCellPtr(argv[i]))); +#endif return args; } @@ -351,7 +300,7 @@ * Returns true if there are at least |required| arguments passed in. If * false, it reports an error message on the context. */ - bool requireAtLeast(JSContext* cx, const char* fnname, unsigned required) const; + JS_PUBLIC_API(bool) requireAtLeast(JSContext* cx, const char* fnname, unsigned required) const; }; @@ -379,19 +328,30 @@ * take a const JS::CallArgs&. */ -#define JS_THIS_OBJECT(cx,vp) (JS_THIS(cx,vp).toObjectOrNull()) - /* + * 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_ComputeThis(cx, vp) : vp[1]; + 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. Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/CharacterEncoding.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/CharacterEncoding.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/CharacterEncoding.h @@ -31,6 +31,8 @@ typedef mozilla::Range Base; public: + using CharT = Latin1Char; + Latin1Chars() : Base() {} Latin1Chars(char* aBytes, size_t aLength) : Base(reinterpret_cast(aBytes), aLength) {} Latin1Chars(const Latin1Char* aBytes, size_t aLength) @@ -49,6 +51,8 @@ typedef mozilla::RangedPtr Base; public: + using CharT = Latin1Char; + Latin1CharsZ() : Base(nullptr, 0) {} Latin1CharsZ(char* aBytes, size_t aLength) @@ -73,6 +77,8 @@ typedef mozilla::Range Base; public: + using CharT = unsigned char; + UTF8Chars() : Base() {} UTF8Chars(char* aBytes, size_t aLength) : Base(reinterpret_cast(aBytes), aLength) @@ -90,6 +96,8 @@ typedef mozilla::RangedPtr Base; public: + using CharT = unsigned char; + UTF8CharsZ() : Base(nullptr, 0) {} UTF8CharsZ(char* aBytes, size_t aLength) @@ -110,6 +118,43 @@ }; /* + * 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. + */ +class JS_PUBLIC_API(ConstUTF8CharsZ) +{ + const char* data_; + + public: + using CharT = unsigned char; + + ConstUTF8CharsZ() : data_(nullptr) + {} + + ConstUTF8CharsZ(const char* aBytes, size_t aLength) + : data_(aBytes) + { + MOZ_ASSERT(aBytes[aLength] == '\0'); +#ifdef DEBUG + validate(aLength); +#endif + } + + const void* get() const { return data_; } + + const char* c_str() const { return data_; } + + explicit operator bool() const { return data_ != nullptr; } + + private: +#ifdef DEBUG + void validate(size_t aLength); +#endif +}; + +/* * SpiderMonkey uses a 2-byte character representation: it is a * 2-byte-at-a-time view of a UTF-16 byte stream. This is similar to UCS-2, * but unlike UCS-2, we do not strip UTF-16 extension bytes. This allows a @@ -122,6 +167,8 @@ typedef mozilla::Range Base; public: + using CharT = char16_t; + TwoByteChars() : Base() {} TwoByteChars(char16_t* aChars, size_t aLength) : Base(aChars, aLength) {} TwoByteChars(const char16_t* aChars, size_t aLength) : Base(const_cast(aChars), aLength) {} @@ -135,6 +182,8 @@ typedef mozilla::RangedPtr Base; public: + using CharT = char16_t; + TwoByteCharsZ() : Base(nullptr, 0) {} TwoByteCharsZ(char16_t* chars, size_t length) @@ -156,6 +205,8 @@ typedef mozilla::Range Base; public: + using CharT = char16_t; + ConstTwoByteChars() : Base() {} ConstTwoByteChars(const char16_t* aChars, size_t aLength) : Base(aChars, aLength) {} }; @@ -174,11 +225,18 @@ LossyTwoByteCharsToNewLatin1CharsZ(js::ExclusiveContext* cx, const mozilla::Range tbchars); +inline Latin1CharsZ +LossyTwoByteCharsToNewLatin1CharsZ(js::ExclusiveContext* cx, const char16_t* begin, size_t length) +{ + const mozilla::Range tbchars(begin, length); + return JS::LossyTwoByteCharsToNewLatin1CharsZ(cx, tbchars); +} + template extern UTF8CharsZ -CharsToNewUTF8CharsZ(js::ExclusiveContext* maybeCx, const mozilla::Range chars); +CharsToNewUTF8CharsZ(js::ExclusiveContext* maybeCx, const mozilla::Range chars); -uint32_t +JS_PUBLIC_API(uint32_t) Utf8ToOneUcs4Char(const uint8_t* utf8Buffer, int utf8Length); /* @@ -187,17 +245,26 @@ * - On success, returns a malloc'd TwoByteCharsZ, and updates |outlen| to hold * its length; the length value excludes the trailing null. */ -extern TwoByteCharsZ +extern JS_PUBLIC_API(TwoByteCharsZ) UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); /* + * Like UTF8CharsToNewTwoByteCharsZ, but for ConstUTF8CharsZ. + */ +extern JS_PUBLIC_API(TwoByteCharsZ) +UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen); + +/* * 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 TwoByteCharsZ +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); + /* * Returns the length of the char buffer required to encode |s| as UTF8. * Does not include the null-terminator. @@ -206,11 +273,62 @@ GetDeflatedUTF8StringLength(JSFlatString* s); /* - * Encode |src| as UTF8. The caller must ensure |dst| has enough space. - * Does not write the null terminator. + * Encode |src| as UTF8. The caller must either ensure |dst| has enough space + * to encode the entire string or pass the length of the buffer as |dstlenp|, + * in which case the function will encode characters from the string until + * the buffer is exhausted. Does not write the null terminator. + * + * If |dstlenp| is provided, it will be updated to hold the number of bytes + * written to the buffer. If |numcharsp| is provided, it will be updated to hold + * the number of Unicode characters written to the buffer (which can be less + * than the length of the string, if the buffer is exhausted before the string + * is fully encoded). */ JS_PUBLIC_API(void) -DeflateStringToUTF8Buffer(JSFlatString* src, mozilla::RangedPtr dst); +DeflateStringToUTF8Buffer(JSFlatString* src, mozilla::RangedPtr dst, + size_t* dstlenp = nullptr, size_t* numcharsp = nullptr); + +/* + * The smallest character encoding capable of fully representing a particular + * string. + */ +enum class SmallestEncoding { + ASCII, + Latin1, + UTF16 +}; + +/* + * Returns the smallest encoding possible for the given string: if all + * codepoints are <128 then ASCII, otherwise if all codepoints are <256 + * Latin-1, else UTF16. + */ +JS_PUBLIC_API(SmallestEncoding) +FindSmallestEncoding(UTF8Chars utf8); + +/* + * Return a null-terminated Latin-1 string copied from the input string, + * storing its length (excluding null terminator) in |*outlen|. Fail and + * report an error if the string contains non-Latin-1 codepoints. Returns + * Latin1CharsZ() on failure. + */ +extern JS_PUBLIC_API(Latin1CharsZ) +UTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); + +/* + * 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); + +/* + * Returns true if all characters in the given null-terminated string are + * ASCII, i.e. < 0x80, false otherwise. + */ +extern JS_PUBLIC_API(bool) +StringIsASCII(const char* s); } // namespace JS Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Class.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Class.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Class.h @@ -9,8 +9,6 @@ #ifndef js_Class_h #define js_Class_h -#include "mozilla/DebugOnly.h" - #include "jstypes.h" #include "js/CallArgs.h" @@ -42,9 +40,7 @@ namespace JS { -template -class AutoVectorRooter; -typedef AutoVectorRooter AutoIdVector; +class AutoIdVector; /** * The answer to a successful query as to whether an object is an Array per @@ -337,8 +333,8 @@ * (e.g., the DOM attributes for a given node reflected as obj) on demand. * * JS looks for a property in an object, and if not found, tries to resolve - * the given id. *resolvedp should be set to true iff the property was - * was defined on |obj|. + * the given id. *resolvedp should be set to true iff the property was defined + * on |obj|. */ typedef bool (* JSResolveOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, @@ -368,7 +364,7 @@ /** Finalizes external strings created by JS_NewExternalString. */ struct JSStringFinalizer { - void (*finalize)(const JSStringFinalizer* fin, char16_t* chars); + void (*finalize)(JS::Zone* zone, const JSStringFinalizer* fin, char16_t* chars); }; /** @@ -383,8 +379,8 @@ /** * Function type for trace operation of the class called to enumerate all * traceable things reachable from obj's private data structure. For each such - * thing, a trace implementation must call one of the JS_Call*Tracer variants - * on the thing. + * thing, a trace implementation must call JS::TraceEdge on the thing's + * location. * * JSTraceOp implementation can assume that no other threads mutates object * state. It must not change state of the object or corresponding native @@ -412,7 +408,7 @@ JS::MutableHandleObject objp, JS::MutableHandle propp); typedef bool (* DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result); typedef bool (* HasPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); @@ -424,7 +420,7 @@ JS::HandleValue receiver, JS::ObjectOpResult& result); typedef bool (* GetOwnPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); typedef bool (* DeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::ObjectOpResult& result); @@ -453,15 +449,25 @@ JS::Value* vp_; uint32_t index_; - mozilla::DebugOnly length_; +#ifdef DEBUG + uint32_t length_; +#endif GetBehavior getBehavior_; public: ElementAdder(JSContext* cx, JSObject* obj, uint32_t length, GetBehavior behavior) - : resObj_(cx, obj), vp_(nullptr), index_(0), length_(length), getBehavior_(behavior) + : resObj_(cx, obj), vp_(nullptr), index_(0), +#ifdef DEBUG + length_(length), +#endif + getBehavior_(behavior) {} ElementAdder(JSContext* cx, JS::Value* vp, uint32_t length, GetBehavior behavior) - : resObj_(cx), vp_(vp), index_(0), length_(length), getBehavior_(behavior) + : resObj_(cx), vp_(vp), index_(0), +#ifdef DEBUG + length_(length), +#endif + getBehavior_(behavior) {} GetBehavior getBehavior() const { return getBehavior_; } @@ -477,23 +483,55 @@ typedef void (* FinalizeOp)(FreeOp* fop, JSObject* obj); -#define JS_CLASS_MEMBERS(FinalizeOpType) \ - const char* name; \ - uint32_t flags; \ - \ - /* Function pointer members (may be null). */ \ - JSAddPropertyOp addProperty; \ - JSDeletePropertyOp delProperty; \ - JSGetterOp getProperty; \ - JSSetterOp setProperty; \ - JSEnumerateOp enumerate; \ - JSResolveOp resolve; \ - JSMayResolveOp mayResolve; \ - FinalizeOpType finalize; \ - JSNative call; \ - JSHasInstanceOp hasInstance; \ - JSNative construct; \ - JSTraceOp trace +// The special treatment of |finalize| and |trace| is necessary because if we +// assign either of those hooks to a local variable and then call it -- as is +// done with the other hooks -- the GC hazard analysis gets confused. +#define JS_CLASS_MEMBERS(ClassOpsType, FreeOpType) \ + const char* name; \ + uint32_t flags; \ + const ClassOpsType* cOps; \ + \ + JSAddPropertyOp getAddProperty() const { return cOps ? cOps->addProperty : nullptr; } \ + JSDeletePropertyOp getDelProperty() const { return cOps ? cOps->delProperty : nullptr; } \ + JSGetterOp getGetProperty() const { return cOps ? cOps->getProperty : nullptr; } \ + JSSetterOp getSetProperty() const { return cOps ? cOps->setProperty : nullptr; } \ + JSEnumerateOp getEnumerate() const { return cOps ? cOps->enumerate : nullptr; } \ + JSResolveOp getResolve() const { return cOps ? cOps->resolve : nullptr; } \ + JSMayResolveOp getMayResolve() const { return cOps ? cOps->mayResolve : nullptr; } \ + JSNative getCall() const { return cOps ? cOps->call : nullptr; } \ + JSHasInstanceOp getHasInstance() const { return cOps ? cOps->hasInstance : nullptr; } \ + JSNative getConstruct() const { return cOps ? cOps->construct : nullptr; } \ + \ + bool hasFinalize() const { return cOps && cOps->finalize; } \ + bool hasTrace() const { return cOps && cOps->trace; } \ + \ + bool isTrace(JSTraceOp trace) const { return cOps && cOps->trace == trace; } \ + \ + void doFinalize(FreeOpType* fop, JSObject* obj) const { \ + MOZ_ASSERT(cOps && cOps->finalize); \ + cOps->finalize(fop, obj); \ + } \ + void doTrace(JSTracer* trc, JSObject* obj) const { \ + MOZ_ASSERT(cOps && cOps->trace); \ + cOps->trace(trc, obj); \ + } + +struct ClassOps +{ + /* Function pointer members (may be null). */ + JSAddPropertyOp addProperty; + JSDeletePropertyOp delProperty; + JSGetterOp getProperty; + JSSetterOp setProperty; + JSEnumerateOp enumerate; + JSResolveOp resolve; + JSMayResolveOp mayResolve; + FinalizeOp finalize; + JSNative call; + JSHasInstanceOp hasInstance; + JSNative construct; + JSTraceOp trace; +}; /** Callback for the creation of constructor and prototype objects. */ typedef JSObject* (*ClassObjectCreationOp)(JSContext* cx, JSProtoKey key); @@ -516,11 +554,11 @@ FinishClassInitOp finishInit_; uintptr_t flags; - static const size_t ParentKeyWidth = JSCLASS_CACHED_PROTO_WIDTH; + static const size_t ProtoKeyWidth = JSCLASS_CACHED_PROTO_WIDTH; - static const uintptr_t ParentKeyMask = (1 << ParentKeyWidth) - 1; - static const uintptr_t DontDefineConstructor = 1 << ParentKeyWidth; - static const uintptr_t IsDelegated = 1 << (ParentKeyWidth + 1); + static const uintptr_t ProtoKeyMask = (1 << ProtoKeyWidth) - 1; + static const uintptr_t DontDefineConstructor = 1 << ProtoKeyWidth; + static const uintptr_t IsDelegated = 1 << (ProtoKeyWidth + 1); bool defined() const { return !!createConstructor_; } @@ -528,14 +566,16 @@ return (flags & IsDelegated); } - bool dependent() const { + // The ProtoKey this class inherits from. + JSProtoKey inheritanceProtoKey() const { MOZ_ASSERT(defined()); - return (flags & ParentKeyMask); - } - - JSProtoKey parentKey() const { static_assert(JSProto_Null == 0, "zeroed key must be null"); - return JSProtoKey(flags & ParentKeyMask); + + // Default: Inherit from Object. + if (!(flags & ProtoKeyMask)) + return JSProto_Object; + + return JSProtoKey(flags & ProtoKeyMask); } bool shouldDefineConstructor() const { @@ -588,12 +628,6 @@ struct ClassExtension { /** - * isWrappedNative is true only if the class is an XPCWrappedNative. - * WeakMaps use this to override the wrapper disposal optimization. - */ - bool isWrappedNative; - - /** * 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 @@ -624,28 +658,26 @@ return reinterpret_cast(const_cast(spec)); } -#define JS_NULL_CLASS_SPEC {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr} -#define JS_NULL_CLASS_EXT {false,nullptr} +#define JS_NULL_CLASS_SPEC nullptr +#define JS_NULL_CLASS_EXT nullptr struct ObjectOps { - LookupPropertyOp lookupProperty; - DefinePropertyOp defineProperty; - HasPropertyOp hasProperty; - GetPropertyOp getProperty; - SetPropertyOp setProperty; - GetOwnPropertyOp getOwnPropertyDescriptor; - DeletePropertyOp deleteProperty; - WatchOp watch; - UnwatchOp unwatch; - GetElementsOp getElements; - JSNewEnumerateOp enumerate; - JSFunToStringOp funToString; -}; - -#define JS_NULL_OBJECT_OPS \ - {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, \ - nullptr, nullptr, nullptr, nullptr} + LookupPropertyOp lookupProperty; + DefinePropertyOp defineProperty; + HasPropertyOp hasProperty; + GetPropertyOp getProperty; + SetPropertyOp setProperty; + GetOwnPropertyOp getOwnPropertyDescriptor; + DeletePropertyOp deleteProperty; + WatchOp watch; + UnwatchOp unwatch; + GetElementsOp getElements; + JSNewEnumerateOp enumerate; + JSFunToStringOp funToString; +}; + +#define JS_NULL_OBJECT_OPS nullptr } // namespace js @@ -653,19 +685,54 @@ typedef void (*JSClassInternal)(); +struct JSClassOps +{ + /* Function pointer members (may be null). */ + JSAddPropertyOp addProperty; + JSDeletePropertyOp delProperty; + JSGetterOp getProperty; + JSSetterOp setProperty; + JSEnumerateOp enumerate; + JSResolveOp resolve; + JSMayResolveOp mayResolve; + JSFinalizeOp finalize; + JSNative call; + JSHasInstanceOp hasInstance; + JSNative construct; + JSTraceOp trace; +}; + +#define JS_NULL_CLASS_OPS nullptr + struct JSClass { - JS_CLASS_MEMBERS(JSFinalizeOp); + JS_CLASS_MEMBERS(JSClassOps, JSFreeOp); - void* reserved[23]; + void* reserved[3]; }; #define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot -#define JSCLASS_DELAY_METADATA_CALLBACK (1<<1) // class's initialization code +#define JSCLASS_DELAY_METADATA_BUILDER (1<<1) // class's initialization code // will call // SetNewObjectMetadata itself +#define JSCLASS_IS_WRAPPED_NATIVE (1<<2) // class is an XPCWrappedNative. + // WeakMaps use this to override + // the wrapper disposal + // mechanism. #define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) // private is (nsISupports*) #define JSCLASS_IS_DOMJSCLASS (1<<4) // objects are DOM -// Bit 5 is unused. +#define JSCLASS_HAS_XRAYED_CONSTRUCTOR (1<<5) // if wrapped by an xray + // wrapper, the builtin + // class's constructor won't + // be unwrapped and invoked. + // Instead, the constructor is + // resolved in the caller's + // compartment and invoked + // with a wrapped newTarget. + // The constructor has to + // detect and handle this + // situation. + // See PromiseConstructor for + // details. #define JSCLASS_EMULATES_UNDEFINED (1<<6) // objects of this class act // like the value undefined, // in some contexts @@ -700,6 +767,7 @@ #define JSCLASS_USERBIT3 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+7)) #define JSCLASS_BACKGROUND_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+8)) +#define JSCLASS_FOREGROUND_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+9)) // Bits 26 through 31 are reserved for the CACHED_PROTO_KEY mechanism, see // below. @@ -719,7 +787,7 @@ // application. #define JSCLASS_GLOBAL_APPLICATION_SLOTS 5 #define JSCLASS_GLOBAL_SLOT_COUNT \ - (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 36) + (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 39) #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \ (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n))) #define JSCLASS_GLOBAL_FLAGS \ @@ -745,10 +813,10 @@ struct Class { - JS_CLASS_MEMBERS(FinalizeOp); - ClassSpec spec; - ClassExtension ext; - ObjectOps ops; + JS_CLASS_MEMBERS(js::ClassOps, FreeOp); + const ClassSpec* spec; + const ClassExtension* ext; + const ObjectOps* oOps; /* * Objects of this class aren't native objects. They don't have Shapes that @@ -777,7 +845,7 @@ bool nonProxyCallable() const { MOZ_ASSERT(!isProxy()); - return isJSFunction() || call; + return isJSFunction() || getCall(); } bool isProxy() const { @@ -788,40 +856,89 @@ return flags & JSCLASS_IS_DOMJSCLASS; } - bool shouldDelayMetadataCallback() const { - return flags & JSCLASS_DELAY_METADATA_CALLBACK; + bool shouldDelayMetadataBuilder() const { + return flags & JSCLASS_DELAY_METADATA_BUILDER; + } + + bool isWrappedNative() const { + return flags & JSCLASS_IS_WRAPPED_NATIVE; } static size_t offsetOfFlags() { return offsetof(Class, flags); } + + bool specDefined() const { return spec ? spec->defined() : false; } + JSProtoKey specInheritanceProtoKey() + const { return spec ? spec->inheritanceProtoKey() : JSProto_Null; } + bool specShouldDefineConstructor() + const { return spec ? spec->shouldDefineConstructor() : true; } + ClassObjectCreationOp specCreateConstructorHook() + const { return spec ? spec->createConstructorHook() : nullptr; } + ClassObjectCreationOp specCreatePrototypeHook() + const { return spec ? spec->createPrototypeHook() : nullptr; } + const JSFunctionSpec* specConstructorFunctions() + const { return spec ? spec->constructorFunctions() : nullptr; } + const JSPropertySpec* specConstructorProperties() + const { return spec ? spec->constructorProperties() : nullptr; } + const JSFunctionSpec* specPrototypeFunctions() + const { return spec ? spec->prototypeFunctions() : nullptr; } + const JSPropertySpec* specPrototypeProperties() + const { return spec ? spec->prototypeProperties() : nullptr; } + FinishClassInitOp specFinishInitHook() + const { return spec ? spec->finishInitHook() : nullptr; } + + JSWeakmapKeyDelegateOp extWeakmapKeyDelegateOp() + const { return ext ? ext->weakmapKeyDelegateOp : nullptr; } + JSObjectMovedOp extObjectMovedOp() + const { return ext ? ext->objectMovedOp : nullptr; } + + LookupPropertyOp getOpsLookupProperty() const { return oOps ? oOps->lookupProperty : nullptr; } + DefinePropertyOp getOpsDefineProperty() const { return oOps ? oOps->defineProperty : nullptr; } + HasPropertyOp getOpsHasProperty() const { return oOps ? oOps->hasProperty : nullptr; } + GetPropertyOp getOpsGetProperty() const { return oOps ? oOps->getProperty : nullptr; } + SetPropertyOp getOpsSetProperty() const { return oOps ? oOps->setProperty : nullptr; } + GetOwnPropertyOp getOpsGetOwnPropertyDescriptor() + const { return oOps ? oOps->getOwnPropertyDescriptor + : nullptr; } + DeletePropertyOp getOpsDeleteProperty() const { return oOps ? oOps->deleteProperty : nullptr; } + WatchOp getOpsWatch() const { return oOps ? oOps->watch : nullptr; } + UnwatchOp getOpsUnwatch() const { return oOps ? oOps->unwatch : nullptr; } + GetElementsOp getOpsGetElements() const { return oOps ? oOps->getElements : nullptr; } + JSNewEnumerateOp getOpsEnumerate() const { return oOps ? oOps->enumerate : nullptr; } + JSFunToStringOp getOpsFunToString() const { return oOps ? oOps->funToString : nullptr; } }; +static_assert(offsetof(JSClassOps, addProperty) == offsetof(ClassOps, addProperty), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, delProperty) == offsetof(ClassOps, delProperty), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, getProperty) == offsetof(ClassOps, getProperty), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, setProperty) == offsetof(ClassOps, setProperty), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, enumerate) == offsetof(ClassOps, enumerate), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, resolve) == offsetof(ClassOps, resolve), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, mayResolve) == offsetof(ClassOps, mayResolve), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, finalize) == offsetof(ClassOps, finalize), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, call) == offsetof(ClassOps, call), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, construct) == offsetof(ClassOps, construct), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, hasInstance) == offsetof(ClassOps, hasInstance), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, trace) == offsetof(ClassOps, trace), + "ClassOps and JSClassOps must be consistent"); +static_assert(sizeof(JSClassOps) == sizeof(ClassOps), + "ClassOps and JSClassOps must be consistent"); + static_assert(offsetof(JSClass, name) == offsetof(Class, name), "Class and JSClass must be consistent"); static_assert(offsetof(JSClass, flags) == offsetof(Class, flags), "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, addProperty) == offsetof(Class, addProperty), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, delProperty) == offsetof(Class, delProperty), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, getProperty) == offsetof(Class, getProperty), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, setProperty) == offsetof(Class, setProperty), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, enumerate) == offsetof(Class, enumerate), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, resolve) == offsetof(Class, resolve), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, mayResolve) == offsetof(Class, mayResolve), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, finalize) == offsetof(Class, finalize), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, call) == offsetof(Class, call), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, construct) == offsetof(Class, construct), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, hasInstance) == offsetof(Class, hasInstance), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, trace) == offsetof(Class, trace), +static_assert(offsetof(JSClass, cOps) == offsetof(Class, cOps), "Class and JSClass must be consistent"); static_assert(sizeof(JSClass) == sizeof(Class), "Class and JSClass must be consistent"); @@ -842,17 +959,30 @@ * Enumeration describing possible values of the [[Class]] internal property * value of objects. */ -enum ESClassValue { - ESClass_Object, ESClass_Array, ESClass_Number, ESClass_String, - ESClass_Boolean, ESClass_RegExp, ESClass_ArrayBuffer, ESClass_SharedArrayBuffer, - ESClass_Date, ESClass_Set, ESClass_Map, +enum class ESClass { + Object, + Array, + Number, + String, + Boolean, + RegExp, + ArrayBuffer, + SharedArrayBuffer, + Date, + Set, + Map, + Promise, + MapIterator, + SetIterator, + Arguments, + Error, /** None of the above. */ - ESClass_Other + Other }; /* Fills |vp| with the unboxed value for boxed types, or undefined otherwise. */ -inline bool +bool Unbox(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp); #ifdef DEBUG Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Conversions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Conversions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Conversions.h @@ -30,12 +30,16 @@ /* DO NOT CALL THIS. Use JS::ToNumber. */ extern JS_PUBLIC_API(bool) -ToNumberSlow(JSContext* cx, JS::Value v, double* dp); +ToNumberSlow(JSContext* cx, JS::HandleValue v, double* dp); /* DO NOT CALL THIS. Use JS::ToInt8. */ extern JS_PUBLIC_API(bool) ToInt8Slow(JSContext *cx, JS::HandleValue v, int8_t *out); +/* DO NOT CALL THIS. Use JS::ToUint8. */ +extern JS_PUBLIC_API(bool) +ToUint8Slow(JSContext *cx, JS::HandleValue v, uint8_t *out); + /* DO NOT CALL THIS. Use JS::ToInt16. */ extern JS_PUBLIC_API(bool) ToInt16Slow(JSContext *cx, JS::HandleValue v, int16_t *out); @@ -215,6 +219,19 @@ return js::ToInt8Slow(cx, v, out); } +/* ES6 ECMA-262, 7.1.10 */ +MOZ_ALWAYS_INLINE bool +ToUint8(JSContext *cx, JS::HandleValue v, uint8_t *out) +{ + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = uint8_t(v.toInt32()); + return true; + } + return js::ToUint8Slow(cx, v, out); +} + /* * Non-standard, with behavior similar to that of ToInt32, except in its * producing an int64_t. @@ -383,9 +400,9 @@ inline int32_t ToInt32(double d) { - // clang crashes compiling this when targeting arm-darwin: + // clang crashes compiling this when targeting arm: // https://llvm.org/bugs/show_bug.cgi?id=22974 -#if defined (__arm__) && defined (__GNUC__) && !defined(__APPLE__) +#if defined (__arm__) && defined (__GNUC__) && !defined(__clang__) int32_t i; uint32_t tmp0; uint32_t tmp1; @@ -525,6 +542,13 @@ return detail::ToIntWidth(d); } +/* ECMA-262 7.1.10 ToUInt8() specialized for doubles. */ +inline int8_t +ToUint8(double d) +{ + return detail::ToUintWidth(d); +} + /* WEBIDL 4.2.6 */ inline int16_t ToInt16(double d) @@ -532,6 +556,12 @@ return detail::ToIntWidth(d); } +inline uint16_t +ToUint16(double d) +{ + return detail::ToUintWidth(d); +} + /* WEBIDL 4.2.10 */ inline int64_t ToInt64(double d) Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Date.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Date.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Date.h @@ -149,6 +149,22 @@ JS_PUBLIC_API(double) DayFromTime(double time); +// Takes an integer year and returns the number of days from epoch to the given +// year. +// NOTE: The calculation performed by this function is literally that given in +// the ECMAScript specification. Nonfinite years, years containing fractional +// components, and years outside ECMAScript's date range are not handled with +// any particular intelligence. Garbage in, garbage out. +JS_PUBLIC_API(double) +DayFromYear(double year); + +// Takes an integer number of milliseconds since the epoch and an integer year, +// returns the number of days in that year. If |time| is nonfinite, returns NaN. +// Otherwise |time| *must* correspond to a time within the valid year |year|. +// This should usually be ensured by computing |year| as |JS::DayFromYear(time)|. +JS_PUBLIC_API(double) +DayWithinYear(double time, double year); + } // namespace JS #endif /* js_Date_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Debug.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Debug.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Debug.h @@ -12,7 +12,6 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/MemoryReporting.h" -#include "mozilla/UniquePtr.h" #include "jsapi.h" #include "jspubtd.h" @@ -26,9 +25,6 @@ } // namespace js namespace JS { - -using mozilla::UniquePtr; - namespace dbg { // Helping embedding code build objects for Debugger @@ -154,7 +150,7 @@ // A rooted reference to our value. PersistentRooted value; - BuiltThing(JSContext* cx, Builder& owner_, T value_ = js::GCMethods::initial()) + BuiltThing(JSContext* cx, Builder& owner_, T value_ = GCPolicy::initial()) : owner(owner_), value(cx, value_) { owner.assertBuilt(value_); @@ -261,15 +257,15 @@ // and returns the number of bytes allocated to that block. SpiderMonkey itself // doesn't know which function is appropriate to use, but the embedding does. -// Tell Debuggers in |runtime| to use |mallocSizeOf| to find the size of +// Tell Debuggers in |cx| to use |mallocSizeOf| to find the size of // malloc'd blocks. JS_PUBLIC_API(void) -SetDebuggerMallocSizeOf(JSRuntime* runtime, mozilla::MallocSizeOf mallocSizeOf); +SetDebuggerMallocSizeOf(JSContext* cx, mozilla::MallocSizeOf mallocSizeOf); -// Get the MallocSizeOf function that the given runtime is using to find the +// Get the MallocSizeOf function that the given context is using to find the // size of malloc'd blocks. JS_PUBLIC_API(mozilla::MallocSizeOf) -GetDebuggerMallocSizeOf(JSRuntime* runtime); +GetDebuggerMallocSizeOf(JSContext* cx); @@ -344,7 +340,7 @@ // call the appropriate |Entry| member function to indicate where we've begun // execution. -class MOZ_STACK_CLASS AutoEntryMonitor { +class MOZ_STACK_CLASS JS_PUBLIC_API(AutoEntryMonitor) { JSRuntime* runtime_; AutoEntryMonitor* savedMonitor_; @@ -355,20 +351,25 @@ // SpiderMonkey reports the JavaScript entry points occuring within this // AutoEntryMonitor's scope to the following member functions, which the // embedding is expected to override. + // + // It is important to note that |asyncCause| is owned by the caller and its + // lifetime must outlive the lifetime of the AutoEntryMonitor object. It is + // strongly encouraged that |asyncCause| be a string constant or similar + // statically allocated string. // We have begun executing |function|. Note that |function| may not be the // actual closure we are running, but only the canonical function object to // which the script refers. virtual void Entry(JSContext* cx, JSFunction* function, HandleValue asyncStack, - HandleString asyncCause) = 0; + const char* asyncCause) = 0; // Execution has begun at the entry point of |script|, which is not a // function body. (This is probably being executed by 'eval' or some // JSAPI equivalent.) virtual void Entry(JSContext* cx, JSScript* script, HandleValue asyncStack, - HandleString asyncCause) = 0; + const char* asyncCause) = 0; // Execution of the function or script has ended. virtual void Exit(JSContext* cx) { } Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCAPI.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCAPI.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCAPI.h @@ -7,10 +7,11 @@ #ifndef js_GCAPI_h #define js_GCAPI_h -#include "mozilla/UniquePtr.h" #include "mozilla/Vector.h" +#include "js/GCAnnotations.h" #include "js/HeapAPI.h" +#include "js/UniquePtr.h" namespace js { namespace gc { @@ -25,12 +26,12 @@ /** Perform only global GCs. */ JSGC_MODE_GLOBAL = 0, - /** Perform per-compartment GCs until too much garbage has accumulated. */ - JSGC_MODE_COMPARTMENT = 1, + /** 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_COMPARTMENT. + * JSGC_MODE_ZONE. */ JSGC_MODE_INCREMENTAL = 2 } JSGCMode; @@ -48,14 +49,12 @@ namespace JS { -using mozilla::UniquePtr; - #define GCREASONS(D) \ /* Reasons internal to the JS engine */ \ D(API) \ D(EAGER_ALLOC_TRIGGER) \ D(DESTROY_RUNTIME) \ - D(DESTROY_CONTEXT) \ + D(UNUSED0) \ D(LAST_DITCH) \ D(TOO_MUCH_MALLOC) \ D(ALLOC_TRIGGER) \ @@ -66,7 +65,7 @@ D(EVICT_NURSERY) \ D(FULL_STORE_BUFFER) \ D(SHARED_MEMORY_LIMIT) \ - D(PERIODIC_FULL_GC) \ + D(UNUSED1) \ D(INCREMENTAL_TOO_SLOW) \ D(ABORT_GC) \ \ @@ -130,6 +129,12 @@ NUM_TELEMETRY_REASONS = 100 }; +/** + * Get a statically allocated C string explaining the given GC reason. + */ +extern JS_PUBLIC_API(const char*) +ExplainReason(JS::gcreason::Reason reason); + } /* namespace gcreason */ /* @@ -156,7 +161,7 @@ * Schedule all zones to be collected in the next GC. */ extern JS_PUBLIC_API(void) -PrepareForFullGC(JSRuntime* rt); +PrepareForFullGC(JSContext* cx); /** * When performing an incremental GC, the zones that were selected for the @@ -164,14 +169,14 @@ * This function selects those slices automatically. */ extern JS_PUBLIC_API(void) -PrepareForIncrementalGC(JSRuntime* rt); +PrepareForIncrementalGC(JSContext* cx); /** * Returns true if any zone in the system has been scheduled for GC with one of * the functions above or by the JS engine. */ extern JS_PUBLIC_API(bool) -IsGCScheduled(JSRuntime* rt); +IsGCScheduled(JSContext* cx); /** * Undoes the effect of the Prepare methods above. The given zone will not be @@ -196,7 +201,7 @@ * the system. */ extern JS_PUBLIC_API(void) -GCForReason(JSRuntime* rt, JSGCInvocationKind gckind, gcreason::Reason reason); +GCForReason(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason); /* * Incremental GC: @@ -222,43 +227,43 @@ * Begin an incremental collection and perform one slice worth of work. When * this function returns, the collection may not be complete. * IncrementalGCSlice() must be called repeatedly until - * !IsIncrementalGCInProgress(rt). + * !IsIncrementalGCInProgress(cx). * * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or * shorter than the requested interval. */ extern JS_PUBLIC_API(void) -StartIncrementalGC(JSRuntime* rt, JSGCInvocationKind gckind, gcreason::Reason reason, +StartIncrementalGC(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason, int64_t millis = 0); /** * Perform a slice of an ongoing incremental collection. When this function * returns, the collection may not be complete. It must be called repeatedly - * until !IsIncrementalGCInProgress(rt). + * until !IsIncrementalGCInProgress(cx). * * 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(JSRuntime* rt, gcreason::Reason reason, int64_t millis = 0); +IncrementalGCSlice(JSContext* cx, gcreason::Reason reason, int64_t millis = 0); /** - * If IsIncrementalGCInProgress(rt), this call finishes the ongoing collection - * by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(rt), + * 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, - * IsIncrementalGCInProgress(rt) will always be false. + * IsIncrementalGCInProgress(cx) will always be false. */ extern JS_PUBLIC_API(void) -FinishIncrementalGC(JSRuntime* rt, gcreason::Reason reason); +FinishIncrementalGC(JSContext* cx, gcreason::Reason reason); /** - * If IsIncrementalGCInProgress(rt), this call aborts the ongoing collection and + * If IsIncrementalGCInProgress(cx), this call aborts the ongoing collection and * performs whatever work needs to be done to return the collector to its idle * state. This may take an arbitrarily long time. When this function returns, - * IsIncrementalGCInProgress(rt) will always be false. + * IsIncrementalGCInProgress(cx) will always be false. */ extern JS_PUBLIC_API(void) -AbortIncrementalGC(JSRuntime* rt); +AbortIncrementalGC(JSContext* cx); namespace dbg { @@ -300,7 +305,7 @@ , collections() { } - using Ptr = UniquePtr>; + using Ptr = js::UniquePtr; static Ptr Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t majorGCNumber); JSObject* toJSObject(JSContext* cx) const; @@ -328,22 +333,22 @@ }; struct JS_PUBLIC_API(GCDescription) { - bool isCompartment_; + bool isZone_; JSGCInvocationKind invocationKind_; gcreason::Reason reason_; - GCDescription(bool isCompartment, JSGCInvocationKind kind, gcreason::Reason reason) - : isCompartment_(isCompartment), invocationKind_(kind), reason_(reason) {} + GCDescription(bool isZone, JSGCInvocationKind kind, gcreason::Reason reason) + : isZone_(isZone), invocationKind_(kind), reason_(reason) {} - char16_t* formatSliceMessage(JSRuntime* rt) const; - char16_t* formatSummaryMessage(JSRuntime* rt) const; - char16_t* formatJSON(JSRuntime* rt, uint64_t timestamp) const; + char16_t* formatSliceMessage(JSContext* cx) const; + char16_t* formatSummaryMessage(JSContext* cx) const; + char16_t* formatJSON(JSContext* cx, uint64_t timestamp) const; - JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSRuntime* rt) const; + JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSContext* cx) const; }; typedef void -(* GCSliceCallback)(JSRuntime* rt, GCProgress progress, const GCDescription& desc); +(* GCSliceCallback)(JSContext* cx, GCProgress progress, const GCDescription& desc); /** * The GC slice callback is called at the beginning and end of each slice. This @@ -351,7 +356,45 @@ * marking. */ extern JS_PUBLIC_API(GCSliceCallback) -SetGCSliceCallback(JSRuntime* rt, GCSliceCallback callback); +SetGCSliceCallback(JSContext* cx, GCSliceCallback callback); + +/** + * Describes the progress of an observed nursery collection. + */ +enum class GCNurseryProgress { + /** + * The nursery collection is starting. + */ + GC_NURSERY_COLLECTION_START, + /** + * The nursery collection is ending. + */ + GC_NURSERY_COLLECTION_END +}; + +/** + * A nursery collection callback receives the progress of the nursery collection + * and the reason for the collection. + */ +using GCNurseryCollectionCallback = void(*)(JSContext* cx, GCNurseryProgress progress, + gcreason::Reason reason); + +/** + * Set the nursery collection callback for the given runtime. When set, it will + * be called at the start and end of every nursery collection. + */ +extern JS_PUBLIC_API(GCNurseryCollectionCallback) +SetGCNurseryCollectionCallback(JSContext* cx, GCNurseryCollectionCallback callback); + +typedef void +(* DoCycleCollectionCallback)(JSContext* cx); + +/** + * The purge gray callback is called after any COMPARTMENT_REVIVED GC in which + * the majority of compartments have been marked gray. + */ +extern JS_PUBLIC_API(DoCycleCollectionCallback) +SetDoCycleCollectionCallback(JSContext* cx, DoCycleCollectionCallback callback); /** * Incremental GC defaults to enabled, but may be disabled for testing or in @@ -360,7 +403,7 @@ * disabled on the runtime. */ extern JS_PUBLIC_API(void) -DisableIncrementalGC(JSRuntime* rt); +DisableIncrementalGC(JSContext* cx); /** * Returns true if incremental GC is enabled. Simply having incremental GC @@ -371,14 +414,14 @@ * collections are not happening incrementally when expected. */ extern JS_PUBLIC_API(bool) -IsIncrementalGCEnabled(JSRuntime* rt); +IsIncrementalGCEnabled(JSContext* cx); /** * Returns true while an incremental GC is ongoing, both when actively * collecting and between slices. */ extern JS_PUBLIC_API(bool) -IsIncrementalGCInProgress(JSRuntime* rt); +IsIncrementalGCInProgress(JSContext* cx); /* * Returns true when writes to GC things must call an incremental (pre) barrier. @@ -386,9 +429,6 @@ * At other times, the barrier may be elided for performance. */ extern JS_PUBLIC_API(bool) -IsIncrementalBarrierNeeded(JSRuntime* rt); - -extern JS_PUBLIC_API(bool) IsIncrementalBarrierNeeded(JSContext* cx); /* @@ -408,7 +448,7 @@ * Returns true if the most recent GC ran incrementally. */ extern JS_PUBLIC_API(bool) -WasIncrementalGC(JSRuntime* rt); +WasIncrementalGC(JSContext* cx); /* * Generational GC: @@ -444,37 +484,35 @@ GetGCNumber(); /** - * The GC does not immediately return the unused memory freed by a collection - * back to the system incase it is needed soon afterwards. This call forces the - * GC to return this memory immediately. - */ -extern JS_PUBLIC_API(void) -ShrinkGCBuffers(JSRuntime* rt); + * 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. + */ +class JS_PUBLIC_API(AutoRequireNoGC) +{ + protected: + AutoRequireNoGC() {} + ~AutoRequireNoGC() {} +}; /** - * Assert if a GC occurs while this class is live. This class does not disable - * the static rooting hazard analysis. + * Diagnostic assert (see MOZ_DIAGNOSTIC_ASSERT) that GC cannot occur while this + * class is live. This class does not disable the static rooting hazard + * analysis. + * + * This works by entering a GC unsafe region, which is checked on allocation and + * on GC. */ -class JS_PUBLIC_API(AutoAssertOnGC) +class JS_PUBLIC_API(AutoAssertNoGC) : public AutoRequireNoGC { -#ifdef DEBUG js::gc::GCRuntime* gc; size_t gcNumber; public: - AutoAssertOnGC(); - explicit AutoAssertOnGC(JSRuntime* rt); - ~AutoAssertOnGC(); - - static void VerifyIsSafeToGC(JSRuntime* rt); -#else - public: - AutoAssertOnGC() {} - explicit AutoAssertOnGC(JSRuntime* rt) {} - ~AutoAssertOnGC() {} - - static void VerifyIsSafeToGC(JSRuntime* rt) {} -#endif + AutoAssertNoGC(); + explicit AutoAssertNoGC(JSRuntime* rt); + explicit AutoAssertNoGC(JSContext* cx); + ~AutoAssertNoGC(); }; /** @@ -488,18 +526,32 @@ public: AutoAssertNoAlloc() : gc(nullptr) {} - explicit AutoAssertNoAlloc(JSRuntime* rt); + explicit AutoAssertNoAlloc(JSContext* cx); void disallowAlloc(JSRuntime* rt); ~AutoAssertNoAlloc(); #else public: AutoAssertNoAlloc() {} - explicit AutoAssertNoAlloc(JSRuntime* rt) {} + explicit AutoAssertNoAlloc(JSContext* cx) {} void disallowAlloc(JSRuntime* rt) {} #endif }; /** + * Assert if a GC barrier is invoked while this class is live. This class does + * not disable the static rooting hazard analysis. + */ +class JS_PUBLIC_API(AutoAssertOnBarrier) +{ + JSContext* context; + bool prev; + + public: + explicit AutoAssertOnBarrier(JSContext* cx); + ~AutoAssertOnBarrier(); +}; + +/** * Disable the static rooting hazard analysis in the live region and assert if * any allocation that could potentially trigger a GC occurs while this guard * object is live. This is most useful to help the exact rooting hazard analysis @@ -517,8 +569,8 @@ { public: AutoSuppressGCAnalysis() : AutoAssertNoAlloc() {} - explicit AutoSuppressGCAnalysis(JSRuntime* rt) : AutoAssertNoAlloc(rt) {} -}; + explicit AutoSuppressGCAnalysis(JSContext* cx) : AutoAssertNoAlloc(cx) {} +} JS_HAZ_GC_SUPPRESSED; /** * Assert that code is only ever called from a GC callback, disable the static @@ -536,24 +588,36 @@ /** * Place AutoCheckCannotGC in scopes that you believe can never GC. These - * annotations will be verified both dynamically via AutoAssertOnGC, and + * annotations will be verified both dynamically via AutoAssertNoGC, and * statically with the rooting hazard analysis (implemented by making the * analysis consider AutoCheckCannotGC to be a GC pointer, and therefore * complain if it is live across a GC call.) It is useful when dealing with * internal pointers to GC things where the GC thing itself may not be present * for the static analysis: e.g. acquiring inline chars from a JSString* on the * heap. + * + * We only do the assertion checking in DEBUG builds. */ -class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertOnGC +#ifdef DEBUG +class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertNoGC { public: - AutoCheckCannotGC() : AutoAssertOnGC() {} - explicit AutoCheckCannotGC(JSRuntime* rt) : AutoAssertOnGC(rt) {} -}; + AutoCheckCannotGC() : AutoAssertNoGC() {} + explicit AutoCheckCannotGC(JSContext* cx) : AutoAssertNoGC(cx) {} +} JS_HAZ_GC_INVALIDATED; +#else +class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoRequireNoGC +{ + public: + AutoCheckCannotGC() {} + explicit AutoCheckCannotGC(JSContext* cx) {} +} JS_HAZ_GC_INVALIDATED; +#endif /** * Unsets the gray bit for anything reachable from |thing|. |kind| should not be - * JS::TraceKind::Shape. |thing| should be non-null. + * JS::TraceKind::Shape. |thing| should be non-null. The return value indicates + * if anything was unmarked. */ extern JS_FRIEND_API(bool) UnmarkGrayGCThingRecursively(GCCellPtr thing); @@ -566,31 +630,42 @@ static MOZ_ALWAYS_INLINE void ExposeGCThingToActiveJS(JS::GCCellPtr thing) { - MOZ_ASSERT(thing.kind() != JS::TraceKind::Shape); - - /* - * 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. - */ + // 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; - JS::shadow::Runtime* rt = detail::GetGCThingRuntime(thing.unsafeAsUIntPtr()); + + // There's nothing to do for permanent GC things that might be owned by + // another runtime. + if (thing.mayBeOwnedByOtherRuntime()) + return; + + JS::shadow::Runtime* rt = detail::GetCellRuntime(thing.asCell()); + MOZ_DIAGNOSTIC_ASSERT(rt->allowGCBarriers()); + if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing)) JS::IncrementalReferenceBarrier(thing); - else if (JS::GCThingIsMarkedGray(thing)) + else if (!thing.mayBeOwnedByOtherRuntime() && js::gc::detail::CellIsMarkedGray(thing.asCell())) JS::UnmarkGrayGCThingRecursively(thing); } static MOZ_ALWAYS_INLINE void MarkGCThingAsLive(JSRuntime* aRt, JS::GCCellPtr thing) { - JS::shadow::Runtime* rt = JS::shadow::Runtime::asShadowRuntime(aRt); - /* - * Any object in the nursery will not be freed during any GC running at that time. - */ + // Any object in the nursery will not be freed during any GC running at that + // time. 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; + + JS::shadow::Runtime* rt = JS::shadow::Runtime::asShadowRuntime(aRt); + MOZ_DIAGNOSTIC_ASSERT(rt->allowGCBarriers()); + if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing)) JS::IncrementalReferenceBarrier(thing); } @@ -609,6 +684,7 @@ static MOZ_ALWAYS_INLINE void ExposeObjectToActiveJS(JSObject* obj) { + MOZ_ASSERT(obj); js::gc::ExposeGCThingToActiveJS(GCCellPtr(obj)); } @@ -634,13 +710,13 @@ * Note: this is not related to the PokeGC in nsJSEnvironment. */ extern JS_FRIEND_API(void) -PokeGC(JSRuntime* rt); +PokeGC(JSContext* cx); /* * Internal to Firefox. */ extern JS_FRIEND_API(void) -NotifyDidPaint(JSRuntime* rt); +NotifyDidPaint(JSContext* cx); } /* namespace JS */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCAnnotations.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCAnnotations.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCAnnotations.h @@ -0,0 +1,57 @@ +/* -*- 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_GCAnnotations_h +#define js_GCAnnotations_h + +// Set of annotations for the rooting hazard analysis, used to categorize types +// and functions. +#ifdef XGILL_PLUGIN + +// Mark a type as being a GC thing (eg js::gc::Cell has this annotation). +# define JS_HAZ_GC_THING __attribute__((tag("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"))) + +// 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"))) + +// 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"))) + +// 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 +// same in the analysis as a rooted pointer, except it will not be reported as +// an unnecessary root if used across a GC call. This should rarely be used, +// 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"))) + +// Mark a function as something that runs a garbage collection, potentially +// invalidating GC pointers. +# define JS_HAZ_GC_CALL __attribute__((tag("GC Call"))) + +// Mark an RAII class as suppressing GC within its scope. +# define JS_HAZ_GC_SUPPRESSED __attribute__((tag("Suppress GC"))) + +#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 + +#endif + +#endif /* js_GCAnnotations_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCHashTable.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCHashTable.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCHashTable.h @@ -7,54 +7,54 @@ #ifndef GCHashTable_h #define GCHashTable_h +#include "js/GCPolicyAPI.h" #include "js/HashTable.h" #include "js/RootingAPI.h" +#include "js/SweepingAPI.h" #include "js/TracingAPI.h" -namespace js { +namespace JS { // Define a reasonable default GC policy for GC-aware Maps. template -struct DefaultMapGCPolicy { - using KeyPolicy = DefaultGCPolicy; - using ValuePolicy = DefaultGCPolicy; - +struct DefaultMapSweepPolicy { static bool needsSweep(Key* key, Value* value) { - return KeyPolicy::needsSweep(key) || ValuePolicy::needsSweep(value); + return GCPolicy::needsSweep(key) || GCPolicy::needsSweep(value); } }; // A GCHashMap is a GC-aware HashMap, meaning that it has additional trace and // sweep methods that know how to visit all keys and values in the table. // HashMaps that contain GC pointers will generally want to use this GCHashMap -// specialization in lieu of HashMap, either because those pointers must be -// traced to be kept alive -- in which case, KeyPolicy and/or ValuePolicy -// should do the appropriate tracing -- or because those pointers are weak and -// must be swept during a GC -- in which case needsSweep should be set -// appropriately. +// specialization instead of HashMap, because this conveniently supports tracing +// keys and values, and cleaning up weak entries. // -// Most types of GC pointers as keys and values can be traced with no extra -// infrastructure. For structs, the DefaultGCPolicy will call a trace() -// method on the struct. For other structs and non-gc-pointer members, ensure -// that there is a specialization of DefaultGCPolicy with an appropriate -// trace() static method available to handle the custom type. Generic helpers -// can be found in js/public/TracingAPI.h. +// GCHashMap::trace applies GCPolicy::trace to each entry's key and value. +// Most types of GC pointers already have appropriate specializations of +// GCPolicy, so they should just work as keys and values. Any struct type with a +// default constructor and trace and sweep functions should work as well. If you +// need to define your own GCPolicy specialization, generic helpers can be found +// in js/public/TracingAPI.h. // -// Note that this HashMap only knows *how* to trace and sweep (and the tracing -// can handle keys that move), but it does not itself cause tracing or sweeping -// to be invoked. For tracing, it must be used with Rooted or PersistentRooted, -// or barriered and traced manually. For sweeping, currently it requires an -// explicit call to .sweep(). +// The MapSweepPolicy template parameter controls how the table drops entries +// when swept. GCHashMap::sweep applies MapSweepPolicy::needsSweep to each table +// entry; if it returns true, the entry is dropped. The default MapSweepPolicy +// drops the entry if either the key or value is about to be finalized, +// according to its GCPolicy::needsSweep method. (This default is almost +// always fine: it's hard to imagine keeping such an entry around anyway.) // +// Note that this HashMap only knows *how* to trace and sweep, but it does not +// itself cause tracing or sweeping to be invoked. For tracing, it must be used +// with Rooted or PersistentRooted, or barriered and traced manually. For +// sweeping, currently it requires an explicit call to .sweep(). template , - typename AllocPolicy = TempAllocPolicy, - typename GCPolicy = DefaultMapGCPolicy> -class GCHashMap : public HashMap, - public JS::Traceable + typename HashPolicy = js::DefaultHasher, + typename AllocPolicy = js::TempAllocPolicy, + typename MapSweepPolicy = DefaultMapSweepPolicy> +class GCHashMap : public js::HashMap { - using Base = HashMap; + using Base = js::HashMap; public: explicit GCHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {} @@ -64,8 +64,8 @@ if (!this->initialized()) return; for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { - GCPolicy::ValuePolicy::trace(trc, &e.front().value(), "hashmap value"); - GCPolicy::KeyPolicy::trace(trc, &e.front().mutableKey(), "hashmap key"); + GCPolicy::trace(trc, &e.front().value(), "hashmap value"); + GCPolicy::trace(trc, &e.front().mutableKey(), "hashmap key"); } } @@ -74,16 +74,16 @@ return; for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { - if (GCPolicy::needsSweep(&e.front().mutableKey(), &e.front().value())) + if (MapSweepPolicy::needsSweep(&e.front().mutableKey(), &e.front().value())) e.removeFront(); } } // GCHashMap is movable - GCHashMap(GCHashMap&& rhs) : Base(mozilla::Forward(rhs)) {} + GCHashMap(GCHashMap&& rhs) : Base(mozilla::Move(rhs)) {} void operator=(GCHashMap&& rhs) { MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - Base::operator=(mozilla::Forward(rhs)); + Base::operator=(mozilla::Move(rhs)); } private: @@ -92,19 +92,61 @@ GCHashMap& operator=(const GCHashMap& hm) = delete; }; +} // namespace JS + +namespace js { + +// HashMap that supports rekeying. +// +// If your keys are pointers to something like JSObject that can be tenured or +// compacted, prefer to use GCHashMap with MovableCellHasher, which takes +// advantage of the Zone's stable id table to make rekeying unnecessary. +template , + typename AllocPolicy = TempAllocPolicy, + typename MapSweepPolicy = JS::DefaultMapSweepPolicy> +class GCRekeyableHashMap : public JS::GCHashMap +{ + using Base = JS::GCHashMap; + + public: + explicit GCRekeyableHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {} + + 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())) + e.removeFront(); + else if (!HashPolicy::match(key, e.front().key())) + e.rekeyFront(key); + } + } + + // GCRekeyableHashMap is movable + GCRekeyableHashMap(GCRekeyableHashMap&& rhs) : Base(mozilla::Move(rhs)) {} + void operator=(GCRekeyableHashMap&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); + Base::operator=(mozilla::Move(rhs)); + } +}; + template class GCHashMapOperations { - using Map = GCHashMap; + using Map = JS::GCHashMap; using Lookup = typename Map::Lookup; - using Ptr = typename Map::Ptr; - using AddPtr = typename Map::AddPtr; - using Range = typename Map::Range; - using Enum = typename Map::Enum; const Map& map() const { return static_cast(this)->get(); } public: + using AddPtr = typename Map::AddPtr; + 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); } @@ -113,22 +155,29 @@ uint32_t count() const { return map().count(); } size_t capacity() const { return map().capacity(); } bool has(const Lookup& l) const { return map().lookup(l).found(); } + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return map().sizeOfExcludingThis(mallocSizeOf); + } + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return mallocSizeOf(this) + map().sizeOfExcludingThis(mallocSizeOf); + } }; template class MutableGCHashMapOperations : public GCHashMapOperations { - using Map = GCHashMap; + using Map = JS::GCHashMap; using Lookup = typename Map::Lookup; - using Ptr = typename Map::Ptr; - using AddPtr = typename Map::AddPtr; - using Range = typename Map::Range; - using Enum = typename Map::Enum; Map& map() { return static_cast(this)->get(); } public: + using AddPtr = typename Map::AddPtr; + struct Enum : public Map::Enum { explicit Enum(Outer& o) : Map::Enum(o.map()) {} }; + 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(); } @@ -163,41 +212,48 @@ }; template -class RootedBase> - : public MutableGCHashMapOperations>, A,B,C,D,E> +class RootedBase> + : public MutableGCHashMapOperations>, A,B,C,D,E> +{}; + +template +class MutableHandleBase> + : public MutableGCHashMapOperations>, A,B,C,D,E> {}; template -class MutableHandleBase> - : public MutableGCHashMapOperations>, A,B,C,D,E> +class HandleBase> + : public GCHashMapOperations>, A,B,C,D,E> {}; template -class HandleBase> - : public GCHashMapOperations>, A,B,C,D,E> +class WeakCacheBase> + : public MutableGCHashMapOperations>, A,B,C,D,E> {}; +} // namespace js + +namespace JS { + // A GCHashSet is a HashSet with an additional trace method that knows // be traced to be kept alive will generally want to use this GCHashSet -// specializeation in lieu of HashSet. +// specialization in lieu of HashSet. // // Most types of GC pointers can be traced with no extra infrastructure. For // structs and non-gc-pointer members, ensure that there is a specialization of -// DefaultGCPolicy with an appropriate trace method available to handle the -// custom type. Generic helpers can be found in js/public/TracingAPI.h. +// GCPolicy with an appropriate trace method available to handle the custom +// type. Generic helpers can be found in js/public/TracingAPI.h. // // Note that although this HashSet's trace will deal correctly with moved // elements, it does not itself know when to barrier or trace elements. To // function properly it must either be used with Rooted or barriered and traced // manually. template , - typename AllocPolicy = TempAllocPolicy, - typename GCPolicy = DefaultGCPolicy> -class GCHashSet : public HashSet, - public JS::Traceable + typename HashPolicy = js::DefaultHasher, + typename AllocPolicy = js::TempAllocPolicy> +class GCHashSet : public js::HashSet { - using Base = HashSet; + using Base = js::HashSet; public: explicit GCHashSet(AllocPolicy a = AllocPolicy()) : Base(a) {} @@ -207,23 +263,23 @@ if (!this->initialized()) return; for (typename Base::Enum e(*this); !e.empty(); e.popFront()) - GCPolicy::trace(trc, &e.mutableFront(), "hashset element"); + GCPolicy::trace(trc, &e.mutableFront(), "hashset element"); } void sweep() { if (!this->initialized()) return; for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { - if (GCPolicy::needsSweep(&e.mutableFront())) + if (GCPolicy::needsSweep(&e.mutableFront())) e.removeFront(); } } // GCHashSet is movable - GCHashSet(GCHashSet&& rhs) : Base(mozilla::Forward(rhs)) {} + GCHashSet(GCHashSet&& rhs) : Base(mozilla::Move(rhs)) {} void operator=(GCHashSet&& rhs) { MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - Base::operator=(mozilla::Forward(rhs)); + Base::operator=(mozilla::Move(rhs)); } private: @@ -232,19 +288,24 @@ GCHashSet& operator=(const GCHashSet& hs) = delete; }; +} // namespace JS + +namespace js { + template class GCHashSetOperations { - using Set = GCHashSet; + using Set = JS::GCHashSet; using Lookup = typename Set::Lookup; - using Ptr = typename Set::Ptr; - using AddPtr = typename Set::AddPtr; - using Range = typename Set::Range; - using Enum = typename Set::Enum; - const Set& set() const { return static_cast(this)->extract(); } + const Set& set() const { return static_cast(this)->get(); } public: + using AddPtr = typename Set::AddPtr; + using Entry = typename Set::Entry; + 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); } @@ -253,25 +314,34 @@ uint32_t count() const { return set().count(); } size_t capacity() const { return set().capacity(); } bool has(const Lookup& l) const { return set().lookup(l).found(); } + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return set().sizeOfExcludingThis(mallocSizeOf); + } + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return mallocSizeOf(this) + set().sizeOfExcludingThis(mallocSizeOf); + } }; template class MutableGCHashSetOperations : public GCHashSetOperations { - using Set = GCHashSet; + using Set = JS::GCHashSet; using Lookup = typename Set::Lookup; - using Ptr = typename Set::Ptr; - using AddPtr = typename Set::AddPtr; - using Range = typename Set::Range; - using Enum = typename Set::Enum; - Set& set() { return static_cast(this)->extract(); } + Set& set() { return static_cast(this)->get(); } public: + using AddPtr = typename Set::AddPtr; + using Entry = typename Set::Entry; + struct Enum : public Set::Enum { explicit Enum(Outer& o) : Set::Enum(o.set()) {} }; + 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 remove(Ptr p) { set().remove(p); } void remove(const Lookup& l) { set().remove(l); } template @@ -300,41 +370,28 @@ } }; -template -class RootedBase> - : public MutableGCHashSetOperations>, T, HP, AP, GP> +template +class RootedBase> + : public MutableGCHashSetOperations>, T, HP, AP> { - using Set = GCHashSet; - - friend class GCHashSetOperations, T, HP, AP, GP>; - const Set& extract() const { return *static_cast*>(this)->address(); } - - friend class MutableGCHashSetOperations, T, HP, AP, GP>; - Set& extract() { return *static_cast*>(this)->address(); } }; -template -class MutableHandleBase> - : public MutableGCHashSetOperations>, T, HP, AP, GP> +template +class MutableHandleBase> + : public MutableGCHashSetOperations>, T, HP, AP> { - using Set = GCHashSet; - - friend class GCHashSetOperations, T, HP, AP, GP>; - const Set& extract() const { - return *static_cast*>(this)->address(); - } +}; - friend class MutableGCHashSetOperations, T, HP, AP, GP>; - Set& extract() { return *static_cast*>(this)->address(); } +template +class HandleBase> + : public GCHashSetOperations>, T, HP, AP> +{ }; -template -class HandleBase> - : public GCHashSetOperations>, T, HP, AP, GP> +template +class WeakCacheBase> + : public MutableGCHashSetOperations>, T, HP, AP> { - using Set = GCHashSet; - friend class GCHashSetOperations, T, HP, AP, GP>; - const Set& extract() const { return *static_cast*>(this)->address(); } }; } /* namespace js */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCPolicyAPI.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCPolicyAPI.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCPolicyAPI.h @@ -0,0 +1,164 @@ +/* -*- 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/. */ + +// GC Policy Mechanism + +// A GCPolicy controls how the GC interacts with both direct pointers to GC +// things (e.g. JSObject* or JSString*), tagged and/or optional pointers to GC +// things (e.g. Value or jsid), and C++ container types (e.g. +// JSPropertyDescriptor or GCHashMap). +// +// 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. +// +// static bool needsSweep(T* tp) +// - Return true if |*tp| is about to be finalized. Otherwise, update the +// edge for moving GC, and return false. Containers like GCHashMap and +// GCHashSet use this method to decide when to remove an entry: if this +// function returns true on a key/value/member/etc, its entry is dropped +// from the container. Specializing this method is the standard way to +// get custom weak behavior from a container type. +// +// 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 +// JS::Heap and mozilla::UniquePtr. +// +// There are some stock structs your specializations can inherit from. +// IgnoreGCPolicy does nothing. StructGCPolicy forwards the methods to the +// referent type T. + +#ifndef GCPolicyAPI_h +#define GCPolicyAPI_h + +#include "mozilla/UniquePtr.h" + +#include "js/TraceKind.h" +#include "js/TracingAPI.h" + +// Expand the given macro D for each public GC pointer. +#define FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \ + D(JS::Symbol*) \ + D(JSAtom*) \ + D(JSFunction*) \ + D(JSObject*) \ + D(JSScript*) \ + D(JSString*) + +// Expand the given macro D for each public tagged GC pointer type. +#define FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(D) \ + D(JS::Value) \ + D(jsid) + +#define FOR_EACH_PUBLIC_AGGREGATE_GC_POINTER_TYPE(D) \ + D(JSPropertyDescriptor) + +class JSAtom; +class JSFunction; +class JSObject; +class JSScript; +class JSString; +namespace JS { +class Symbol; +} + +namespace JS { + +// Defines a policy for container types with non-GC, i.e. C storage. This +// policy dispatches to the underlying struct for GC interactions. +template +struct StructGCPolicy +{ + static T initial() { + return T(); + } + + static void trace(JSTracer* trc, T* tp, const char* name) { + tp->trace(trc); + } + + static void sweep(T* tp) { + return tp->sweep(); + } + + static bool needsSweep(T* tp) { + return tp->needsSweep(); + } +}; + +// The default GC policy attempts to defer to methods on the underlying type. +// Most C++ structures that contain a default constructor, a trace function and +// a sweep function will work out of the box with Rooted, Handle, GCVector, +// and GCHash{Set,Map}. +template struct GCPolicy : public StructGCPolicy {}; + +// 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; } +}; +template <> struct GCPolicy : public IgnoreGCPolicy {}; +template <> struct GCPolicy : public IgnoreGCPolicy {}; + +template +struct GCPointerPolicy +{ + static T initial() { return nullptr; } + static void trace(JSTracer* trc, T* vp, const char* name) { + if (*vp) + js::UnsafeTraceManuallyBarrieredEdge(trc, vp, name); + } + static bool needsSweep(T* vp) { + if (*vp) + return js::gc::IsAboutToBeFinalizedUnbarriered(vp); + return false; + } +}; +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 {}; + +template +struct GCPolicy> +{ + static void trace(JSTracer* trc, JS::Heap* thingp, const char* name) { + TraceEdge(trc, thingp, name); + } + static bool needsSweep(JS::Heap* thingp) { + return js::gc::EdgeNeedsSweep(thingp); + } +}; + +// 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); + } + static bool needsSweep(mozilla::UniquePtr* tp) { + if (tp->get()) + return GCPolicy::needsSweep(tp->get()); + return false; + } +}; + +} // namespace JS + +#endif // GCPolicyAPI_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCVariant.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCVariant.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCVariant.h @@ -0,0 +1,198 @@ +/* -*- 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_GCVariant_h +#define js_GCVariant_h + +#include "mozilla/Variant.h" + +#include "js/GCPolicyAPI.h" +#include "js/RootingAPI.h" +#include "js/TracingAPI.h" + +namespace JS { + +// These template specializations allow Variant to be used inside GC wrappers. +// +// When matching on GC wrappers around Variants, matching should be done on +// the wrapper itself. The matcher class's methods should take Handles or +// MutableHandles. For example, +// +// struct MyMatcher +// { +// using ReturnType = const char*; +// ReturnType match(HandleObject o) { return "object"; } +// ReturnType match(HandleScript s) { return "script"; } +// }; +// +// Rooted> v(cx, someScript); +// MyMatcher mm; +// v.match(mm); +// +// If you get compile errors about inability to upcast subclasses (e.g., from +// NativeObject* to JSObject*) and are inside js/src, be sure to also include +// "gc/Policy.h". + +namespace detail { + +template +struct GCVariantImplementation; + +// The base case. +template +struct GCVariantImplementation +{ + 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); + } + + template + static typename Matcher::ReturnType + match(Matcher& matcher, Handle v) { + const T& thing = v.get().template as(); + return matcher.match(Handle::fromMarkedLocation(&thing)); + } + + template + static typename Matcher::ReturnType + match(Matcher& matcher, MutableHandle v) { + T& thing = v.get().template as(); + return matcher.match(MutableHandle::fromMarkedLocation(&thing)); + } +}; + +// The inductive case. +template +struct GCVariantImplementation +{ + using Next = GCVariantImplementation; + + template + 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); + } else { + Next::trace(trc, v, name); + } + } + + template + static typename Matcher::ReturnType + match(Matcher& matcher, Handle v) { + if (v.get().template is()) { + const T& thing = v.get().template as(); + return matcher.match(Handle::fromMarkedLocation(&thing)); + } + return Next::match(matcher, v); + } + + template + static typename Matcher::ReturnType + match(Matcher& matcher, MutableHandle v) { + if (v.get().template is()) { + T& thing = v.get().template as(); + return matcher.match(MutableHandle::fromMarkedLocation(&thing)); + } + return Next::match(matcher, v); + } +}; + +} // namespace detail + +template +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); + } +}; + +} // namespace JS + +namespace js { + +template +class GCVariantOperations +{ + using Impl = JS::detail::GCVariantImplementation; + using Variant = mozilla::Variant; + + const Variant& variant() const { return static_cast(this)->get(); } + + public: + template + bool is() const { + return variant().template is(); + } + + template + JS::Handle as() const { + return Handle::fromMarkedLocation(&variant().template as()); + } + + template + typename Matcher::ReturnType + match(Matcher& matcher) const { + return Impl::match(matcher, JS::Handle::fromMarkedLocation(&variant())); + } +}; + +template +class MutableGCVariantOperations + : public GCVariantOperations +{ + using Impl = JS::detail::GCVariantImplementation; + using Variant = mozilla::Variant; + + const Variant& variant() const { return static_cast(this)->get(); } + Variant& variant() { return static_cast(this)->get(); } + + public: + template + JS::MutableHandle as() { + return JS::MutableHandle::fromMarkedLocation(&variant().template as()); + } + + template + typename Matcher::ReturnType + match(Matcher& matcher) { + return Impl::match(matcher, JS::MutableHandle::fromMarkedLocation(&variant())); + } +}; + +template +class RootedBase> + : public MutableGCVariantOperations>, Ts...> +{ }; + +template +class MutableHandleBase> + : public MutableGCVariantOperations>, Ts...> +{ }; + +template +class HandleBase> + : public GCVariantOperations>, Ts...> +{ }; + +template +class PersistentRootedBase> + : public MutableGCVariantOperations>, Ts...> +{ }; + +} // namespace js + +#endif // js_GCVariant_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCVector.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCVector.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/GCVector.h @@ -0,0 +1,249 @@ +/* -*- 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_GCVector_h +#define js_GCVector_h + +#include "mozilla/Vector.h" + +#include "js/GCPolicyAPI.h" +#include "js/RootingAPI.h" +#include "js/TracingAPI.h" +#include "js/Vector.h" + +namespace JS { + +// A GCVector is a Vector with an additional trace method that knows how +// to visit all of the items stored in the Vector. For vectors that contain GC +// things, this is usually more convenient than manually iterating and marking +// the contents. +// +// Most types of GC pointers as keys and values can be traced with no extra +// infrastructure. For structs and non-gc-pointer members, ensure that there is +// a specialization of GCPolicy with an appropriate trace method available +// to handle the custom type. Generic helpers can be found in +// js/public/TracingAPI.h. +// +// Note that although this Vector's trace will deal correctly with moved items, +// it does not itself know when to barrier or trace items. To function properly +// it must either be used with Rooted, or barriered and traced manually. +template +class GCVector +{ + mozilla::Vector vector; + + public: + explicit GCVector(AllocPolicy alloc = AllocPolicy()) + : vector(alloc) + {} + + GCVector(GCVector&& vec) + : vector(mozilla::Move(vec.vector)) + {} + + GCVector& operator=(GCVector&& vec) { + vector = mozilla::Move(vec.vector); + return *this; + } + + size_t length() const { return vector.length(); } + bool empty() const { return vector.empty(); } + size_t capacity() const { return vector.capacity(); } + + T* begin() { return vector.begin(); } + const T* begin() const { return vector.begin(); } + + T* end() { return vector.end(); } + const T* end() const { return vector.end(); } + + T& operator[](size_t i) { return vector[i]; } + const T& operator[](size_t i) const { return vector[i]; } + + T& back() { return vector.back(); } + const T& back() const { return vector.back(); } + + bool initCapacity(size_t cap) { return vector.initCapacity(cap); } + bool reserve(size_t req) { return vector.reserve(req); } + void shrinkBy(size_t amount) { return vector.shrinkBy(amount); } + bool growBy(size_t amount) { return vector.growBy(amount); } + bool resize(size_t newLen) { return vector.resize(newLen); } + + void clear() { return vector.clear(); } + + template bool append(U&& item) { return vector.append(mozilla::Forward(item)); } + + template + bool + emplaceBack(Args&&... args) { + return vector.emplaceBack(mozilla::Forward(args)...); + } + + template + void infallibleAppend(U&& aU) { + return vector.infallibleAppend(mozilla::Forward(aU)); + } + void infallibleAppendN(const T& aT, size_t aN) { + return vector.infallibleAppendN(aT, aN); + } + template void + infallibleAppend(const U* aBegin, const U* aEnd) { + return vector.infallibleAppend(aBegin, aEnd); + } + template void infallibleAppend(const U* aBegin, size_t aLength) { + return vector.infallibleAppend(aBegin, aLength); + } + + template + bool appendAll(const mozilla::Vector& aU) { return vector.appendAll(aU); } + template + bool appendAll(const GCVector& aU) { return vector.append(aU.begin(), aU.length()); } + + bool appendN(const T& val, size_t count) { return vector.appendN(val, count); } + + template bool append(const U* aBegin, const U* aEnd) { + return vector.append(aBegin, aEnd); + } + template bool append(const U* aBegin, size_t aLength) { + return vector.append(aBegin, aLength); + } + + void popBack() { return vector.popBack(); } + T popCopy() { return vector.popCopy(); } + + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return vector.sizeOfExcludingThis(mallocSizeOf); + } + + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return vector.sizeOfIncludingThis(mallocSizeOf); + } + + static void trace(GCVector* vec, JSTracer* trc) { vec->trace(trc); } + + void trace(JSTracer* trc) { + for (auto& elem : vector) + GCPolicy::trace(trc, &elem, "vector element"); + } +}; + +} // namespace JS + +namespace js { + +template +class GCVectorOperations +{ + using Vec = JS::GCVector; + const Vec& vec() const { return static_cast(this)->get(); } + + public: + const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); } + size_t length() const { return vec().length(); } + bool empty() const { return vec().empty(); } + size_t capacity() const { return vec().capacity(); } + const T* begin() const { return vec().begin(); } + const T* end() const { return vec().end(); } + const T& back() const { return vec().back(); } + + JS::Handle operator[](size_t aIndex) const { + return JS::Handle::fromMarkedLocation(&vec().operator[](aIndex)); + } +}; + +template +class MutableGCVectorOperations + : public GCVectorOperations +{ + using Vec = JS::GCVector; + const Vec& vec() const { return static_cast(this)->get(); } + Vec& vec() { return static_cast(this)->get(); } + + public: + const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); } + AllocPolicy& allocPolicy() { return vec().allocPolicy(); } + const T* begin() const { return vec().begin(); } + T* begin() { return vec().begin(); } + const T* end() const { return vec().end(); } + T* end() { return vec().end(); } + const T& back() const { return vec().back(); } + T& back() { return vec().back(); } + + JS::Handle operator[](size_t aIndex) const { + return JS::Handle::fromMarkedLocation(&vec().operator[](aIndex)); + } + JS::MutableHandle operator[](size_t aIndex) { + return JS::MutableHandle::fromMarkedLocation(&vec().operator[](aIndex)); + } + + bool initCapacity(size_t aRequest) { return vec().initCapacity(aRequest); } + bool reserve(size_t aRequest) { return vec().reserve(aRequest); } + void shrinkBy(size_t aIncr) { vec().shrinkBy(aIncr); } + bool growBy(size_t aIncr) { return vec().growBy(aIncr); } + bool resize(size_t aNewLength) { return vec().resize(aNewLength); } + bool growByUninitialized(size_t aIncr) { return vec().growByUninitialized(aIncr); } + void infallibleGrowByUninitialized(size_t aIncr) { vec().infallibleGrowByUninitialized(aIncr); } + bool resizeUninitialized(size_t aNewLength) { return vec().resizeUninitialized(aNewLength); } + void clear() { vec().clear(); } + void clearAndFree() { vec().clearAndFree(); } + template bool append(U&& aU) { return vec().append(mozilla::Forward(aU)); } + template bool emplaceBack(Args&&... aArgs) { + return vec().emplaceBack(mozilla::Forward(aArgs...)); + } + template + bool appendAll(const mozilla::Vector& aU) { return vec().appendAll(aU); } + template + bool appendAll(const JS::GCVector& aU) { return vec().appendAll(aU); } + bool appendN(const T& aT, size_t aN) { return vec().appendN(aT, aN); } + template bool append(const U* aBegin, const U* aEnd) { + return vec().append(aBegin, aEnd); + } + template bool append(const U* aBegin, size_t aLength) { + return vec().append(aBegin, aLength); + } + template void infallibleAppend(U&& aU) { + vec().infallibleAppend(mozilla::Forward(aU)); + } + void infallibleAppendN(const T& aT, size_t aN) { vec().infallibleAppendN(aT, aN); } + template void infallibleAppend(const U* aBegin, const U* aEnd) { + vec().infallibleAppend(aBegin, aEnd); + } + template void infallibleAppend(const U* aBegin, size_t aLength) { + vec().infallibleAppend(aBegin, aLength); + } + void popBack() { vec().popBack(); } + T popCopy() { return vec().popCopy(); } + template T* insert(T* aP, U&& aVal) { + return vec().insert(aP, mozilla::Forward(aVal)); + } + void erase(T* aT) { vec().erase(aT); } + void erase(T* aBegin, T* aEnd) { vec().erase(aBegin, aEnd); } +}; + +template +class RootedBase> + : public MutableGCVectorOperations>, T,N,AP> +{}; + +template +class MutableHandleBase> + : public MutableGCVectorOperations>, T,N,AP> +{}; + +template +class HandleBase> + : public GCVectorOperations>, T,N,AP> +{}; + +template +class PersistentRootedBase> + : public MutableGCVectorOperations>, T,N,AP> +{}; + +} // namespace js + +#endif // js_GCVector_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/HashTable.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/HashTable.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/HashTable.h @@ -11,6 +11,7 @@ #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" @@ -34,6 +35,16 @@ /*****************************************************************************/ +// 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 @@ -61,6 +72,7 @@ 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); } @@ -76,8 +88,8 @@ // 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) {} - bool init(uint32_t len = 16) { return impl.init(len); } - bool initialized() const { return impl.initialized(); } + 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.: // @@ -139,19 +151,19 @@ } template - bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { + MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { return impl.add(p, mozilla::Forward(k), mozilla::Forward(v)); } template - bool add(AddPtr& p, KeyInput&& k) { + MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k) { return impl.add(p, mozilla::Forward(k), Value()); } template - bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { + MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { return impl.relookupOrAdd(p, k, mozilla::Forward(k), mozilla::Forward(v)); @@ -208,8 +220,6 @@ return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); } - // If |generation()| is the same before and after a HashMap operation, - // pointers into the table remain valid. Generation generation() const { return impl.generation(); } @@ -222,7 +232,7 @@ // Overwrite existing value with v. Return false on oom. template - bool put(KeyInput&& k, ValueInput&& v) { + MOZ_MUST_USE bool put(KeyInput&& k, ValueInput&& v) { AddPtr p = lookupForAdd(k); if (p) { p->value() = mozilla::Forward(v); @@ -233,7 +243,7 @@ // Like put, but assert that the given key is not already present. template - bool putNew(KeyInput&& k, ValueInput&& v) { + MOZ_MUST_USE bool putNew(KeyInput&& k, ValueInput&& v) { return impl.putNew(k, mozilla::Forward(k), mozilla::Forward(v)); } @@ -248,7 +258,9 @@ AddPtr p = lookupForAdd(k); if (p) return p; - (void)add(p, k, defaultValue); // p is left false-y on oom. + bool ok = add(p, k, defaultValue); + MOZ_ASSERT_IF(!ok, !p); // p is left false-y on oom. + (void)ok; return p; } @@ -313,6 +325,7 @@ { 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); } @@ -328,8 +341,8 @@ // 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) {} - bool init(uint32_t len = 16) { return impl.init(len); } - bool initialized() const { return impl.initialized(); } + 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.: // @@ -386,12 +399,12 @@ AddPtr lookupForAdd(const Lookup& l) const { return impl.lookupForAdd(l); } template - bool add(AddPtr& p, U&& u) { + MOZ_MUST_USE bool add(AddPtr& p, U&& u) { return impl.add(p, mozilla::Forward(u)); } template - bool relookupOrAdd(AddPtr& p, const Lookup& l, U&& u) { + MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, U&& u) { return impl.relookupOrAdd(p, l, mozilla::Forward(u)); } @@ -446,8 +459,6 @@ return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); } - // If |generation()| is the same before and after a HashSet operation, - // pointers into the table remain valid. Generation generation() const { return impl.generation(); } @@ -460,19 +471,19 @@ // Add |u| if it is not present already. Return false on oom. template - bool put(U&& u) { + 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 - bool putNew(U&& u) { + MOZ_MUST_USE bool putNew(U&& u) { return impl.putNew(u, mozilla::Forward(u)); } template - bool putNew(const Lookup& l, U&& u) { + MOZ_MUST_USE bool putNew(const Lookup& l, U&& u) { return impl.putNew(l, mozilla::Forward(u)); } @@ -503,11 +514,16 @@ return false; } - // Infallibly rekey one entry with a new key that is equivalent. - void rekeyInPlace(Ptr p, const T& new_value) - { + // 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)); - impl.rekeyInPlace(p, new_value); + const_cast(*p) = new_value; } // HashSet is movable @@ -606,21 +622,21 @@ struct DefaultHasher : PointerHasher::value> {}; -// Specialize hashing policy for mozilla::UniquePtr to proxy the UniquePtr's +// Specialize hashing policy for mozilla::UniquePtr to proxy the UniquePtr's // raw pointer to PointerHasher. -template -struct DefaultHasher> +template +struct DefaultHasher> { - using Lookup = mozilla::UniquePtr; + using Lookup = mozilla::UniquePtr; using PtrHasher = PointerHasher::value>; static HashNumber hash(const Lookup& l) { return PtrHasher::hash(l.get()); } - static bool match(const mozilla::UniquePtr& k, const Lookup& l) { + 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) { + static void rekey(mozilla::UniquePtr& k, mozilla::UniquePtr&& newKey) { k = mozilla::Move(newKey); } }; @@ -655,6 +671,50 @@ } }; +// 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 @@ -684,6 +744,11 @@ 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; @@ -754,8 +819,16 @@ } 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); - mozilla::Swap(mem, other->mem); } T& get() { MOZ_ASSERT(isLive()); return *mem.addr(); } @@ -819,14 +892,21 @@ {} public: - // Leaves Ptr uninitialized. - Ptr() { + Ptr() + : entry_(nullptr) #ifdef JS_DEBUG - entry_ = (Entry*)0xbad; + , 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 @@ -851,6 +931,7 @@ T& operator*() const { #ifdef JS_DEBUG + MOZ_ASSERT(found()); MOZ_ASSERT(generation == table_->generation()); #endif return entry_->get(); @@ -858,6 +939,7 @@ T* operator->() const { #ifdef JS_DEBUG + MOZ_ASSERT(found()); MOZ_ASSERT(generation == table_->generation()); #endif return &entry_->get(); @@ -882,8 +964,7 @@ {} public: - // Leaves AddPtr uninitialized. - AddPtr() {} + AddPtr() : keyHash(0) {} }; // A collection of hash table entries. The collection is enumerated by @@ -1173,7 +1254,7 @@ #endif {} - MOZ_WARN_UNUSED_RESULT bool init(uint32_t length) + MOZ_MUST_USE bool init(uint32_t length) { MOZ_ASSERT(!initialized()); @@ -1543,6 +1624,33 @@ // 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() { @@ -1622,12 +1730,16 @@ 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); } Ptr readonlyThreadsafeLookup(const Lookup& l) const { + if (!HasHash(l)) + return Ptr(); HashNumber keyHash = prepareHash(l); return Ptr(lookup(l, keyHash, 0), *this); } @@ -1635,6 +1747,8 @@ AddPtr lookupForAdd(const Lookup& l) const { mozilla::ReentrancyGuard g(*this); + if (!EnsureHash(l)) + return AddPtr(); HashNumber keyHash = prepareHash(l); Entry& entry = lookup(l, keyHash, sCollisionBit); AddPtr p(entry, *this, keyHash); @@ -1642,13 +1756,17 @@ } template - bool add(AddPtr& p, Args&&... args) + MOZ_MUST_USE bool add(AddPtr& p, Args&&... args) { mozilla::ReentrancyGuard g(*this); MOZ_ASSERT(table); MOZ_ASSERT(!p.found()); MOZ_ASSERT(!(p.keyHash & sCollisionBit)); + // Check for error from ensureHash() here. + if (p.isValid()) + return false; + // Changing an entry from removed to live does not affect whether we // are overloaded and can be handled separately. if (p.entry_->isRemoved()) { @@ -1662,7 +1780,7 @@ RebuildStatus status = checkOverloaded(); if (status == RehashFailed) return false; - if (!this->checkSimulatedOOM()) + if (status == NotOverloaded && !this->checkSimulatedOOM()) return false; if (status == Rehashed) p.entry_ = &findFreeEntry(p.keyHash); @@ -1683,33 +1801,22 @@ template void putNewInfallible(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 + 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 - bool putNew(const Lookup& l, Args&&... args) + 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; @@ -1720,8 +1827,12 @@ // 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 - bool relookupOrAdd(AddPtr& p, const Lookup& l, Args&&... args) + 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; @@ -1751,7 +1862,7 @@ typename HashTableEntry::NonConstT t(mozilla::Move(*p)); HashPolicy::setKey(t, const_cast(k)); remove(*p.entry_); - putNewInfallible(l, mozilla::Move(t)); + putNewInfallibleInternal(l, mozilla::Move(t)); } void rekeyAndMaybeRehash(Ptr p, const Lookup& l, const Key& k) @@ -1760,14 +1871,6 @@ checkOverRemoved(); } - void rekeyInPlace(Ptr p, const Key& k) - { - MOZ_ASSERT(table); - mozilla::ReentrancyGuard g(*this); - MOZ_ASSERT(p.found()); - HashPolicy::rekey(const_cast(*p), const_cast(k)); - } - #undef METER }; Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/HeapAPI.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/HeapAPI.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/HeapAPI.h @@ -17,11 +17,6 @@ /* These values are private to the JS engine. */ namespace js { -// Whether the current thread is permitted access to any part of the specified -// runtime or zone. -JS_FRIEND_API(bool) -CurrentThreadCanAccessRuntime(JSRuntime* rt); - JS_FRIEND_API(bool) CurrentThreadCanAccessZone(JS::Zone* zone); @@ -56,7 +51,9 @@ const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*); const size_t ChunkTrailerSize = 2 * sizeof(uintptr_t) + sizeof(uint64_t); const size_t ChunkLocationOffset = ChunkSize - ChunkTrailerSize; -const size_t ArenaZoneOffset = 0; +const size_t ArenaZoneOffset = sizeof(size_t); +const size_t ArenaHeaderSize = sizeof(size_t) + 2 * sizeof(uintptr_t) + + sizeof(size_t) + sizeof(uintptr_t); /* * Live objects are marked black. How many other additional colors are available @@ -67,19 +64,15 @@ static const uint32_t GRAY = 1; /* - * The "location" field in the Chunk trailer is a bit vector indicting various - * roles of the chunk. - * - * The value 0 for the "location" field is invalid, at least one bit must be - * set. - * - * Some bits preclude others, for example, any "nursery" bit precludes any - * "tenured" or "middle generation" bit. + * The "location" field in the Chunk trailer is a enum indicating various roles + * of the chunk. */ -const uintptr_t ChunkLocationBitNursery = 1; // Standard GGC nursery -const uintptr_t ChunkLocationBitTenuredHeap = 2; // Standard GGC tenured generation - -const uintptr_t ChunkLocationAnyNursery = ChunkLocationBitNursery; +enum class ChunkLocation : uint32_t +{ + Invalid = 0, + Nursery = 1, + TenuredHeap = 2 +}; #ifdef JS_DEBUG /* When downcasting, ensure we are actually the right type. */ @@ -113,13 +106,20 @@ JSTracer* const barrierTracer_; // A pointer to the JSRuntime's |gcMarker|. public: + // Stack GC roots for Rooted GC pointers. + js::RootedListHeads stackRoots_; + template friend class JS::Rooted; + bool needsIncrementalBarrier_; Zone(JSRuntime* runtime, JSTracer* barrierTracerArg) : runtime_(runtime), barrierTracer_(barrierTracerArg), needsIncrementalBarrier_(false) - {} + { + for (auto& stackRootPtr : stackRoots_) + stackRootPtr = nullptr; + } bool needsIncrementalBarrier() const { return needsIncrementalBarrier_; @@ -142,7 +142,7 @@ return runtime_; } - static JS::shadow::Zone* asShadowZone(JS::Zone* zone) { + static MOZ_ALWAYS_INLINE JS::shadow::Zone* asShadowZone(JS::Zone* zone) { return reinterpret_cast(zone); } }; @@ -280,14 +280,6 @@ return reinterpret_cast(bmap_addr); } -static MOZ_ALWAYS_INLINE JS::shadow::Runtime* -GetGCThingRuntime(const uintptr_t addr) -{ - MOZ_ASSERT(addr); - const uintptr_t rt_addr = (addr & ~ChunkMask) | ChunkRuntimeOffset; - return *reinterpret_cast(rt_addr); -} - static MOZ_ALWAYS_INLINE void GetGCThingMarkWordAndMask(const uintptr_t addr, uint32_t color, uintptr_t** wordp, uintptr_t* maskp) @@ -310,16 +302,30 @@ } +static MOZ_ALWAYS_INLINE JS::shadow::Runtime* +GetCellRuntime(const Cell* cell) +{ + MOZ_ASSERT(cell); + const uintptr_t addr = uintptr_t(cell); + const uintptr_t rt_addr = (addr & ~ChunkMask) | ChunkRuntimeOffset; + return *reinterpret_cast(rt_addr); +} + static MOZ_ALWAYS_INLINE bool CellIsMarkedGray(const Cell* cell) { MOZ_ASSERT(cell); - MOZ_ASSERT(!js::gc::IsInsideNursery(cell)); + if (js::gc::IsInsideNursery(cell)) + return false; + uintptr_t* word, mask; js::gc::detail::GetGCThingMarkWordAndMask(uintptr_t(cell), js::gc::GRAY, &word, &mask); return *word & mask; } +extern JS_PUBLIC_API(bool) +CellIsMarkedGrayIfKnown(const Cell* cell); + } /* namespace detail */ MOZ_ALWAYS_INLINE bool @@ -330,9 +336,9 @@ uintptr_t addr = uintptr_t(cell); addr &= ~js::gc::ChunkMask; addr |= js::gc::ChunkLocationOffset; - uint32_t location = *reinterpret_cast(addr); - MOZ_ASSERT(location != 0); - return location & ChunkLocationAnyNursery; + auto location = *reinterpret_cast(addr); + MOZ_ASSERT(location == ChunkLocation::Nursery || location == ChunkLocation::TenuredHeap); + return location == ChunkLocation::Nursery; } } /* namespace gc */ @@ -357,40 +363,16 @@ GetObjectZone(JSObject* obj); static MOZ_ALWAYS_INLINE bool -ObjectIsTenured(JSObject* obj) -{ - return !js::gc::IsInsideNursery(reinterpret_cast(obj)); -} - -static MOZ_ALWAYS_INLINE bool -ObjectIsMarkedGray(JSObject* obj) -{ - /* - * 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 (js::gc::IsInsideNursery(reinterpret_cast(obj))) - return false; - return js::gc::detail::CellIsMarkedGray(reinterpret_cast(obj)); -} - -static MOZ_ALWAYS_INLINE bool -ScriptIsMarkedGray(JSScript* script) -{ - return js::gc::detail::CellIsMarkedGray(reinterpret_cast(script)); -} - -static MOZ_ALWAYS_INLINE bool GCThingIsMarkedGray(GCCellPtr thing) { - if (js::gc::IsInsideNursery(thing.asCell())) - return false; if (thing.mayBeOwnedByOtherRuntime()) return false; - return js::gc::detail::CellIsMarkedGray(thing.asCell()); + return js::gc::detail::CellIsMarkedGrayIfKnown(thing.asCell()); } +extern JS_PUBLIC_API(JS::TraceKind) +GCThingTraceKind(void* thing); + } /* namespace JS */ namespace js { @@ -401,8 +383,11 @@ { MOZ_ASSERT(thing); MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell())); - if (rt->isHeapBusy()) - return false; + + // TODO: I'd like to assert !isHeapBusy() here but this gets called while we + // are tracing the heap, e.g. during memory reporting (see bug 1313318). + MOZ_ASSERT(!rt->isHeapCollecting()); + JS::Zone* zone = JS::GetTenuredGCThingZone(thing); return JS::shadow::Zone::asShadowZone(zone)->needsIncrementalBarrier(); } Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Id.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Id.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Id.h @@ -30,9 +30,9 @@ struct jsid { size_t asBits; - bool operator==(jsid rhs) const { return asBits == rhs.asBits; } - bool operator!=(jsid rhs) const { return asBits != rhs.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) #define JSID_TYPE_STRING 0x0 @@ -69,12 +69,6 @@ INTERNED_STRING_TO_JSID(JSContext* cx, JSString* str); static MOZ_ALWAYS_INLINE bool -JSID_IS_ZERO(jsid id) -{ - return JSID_BITS(id) == 0; -} - -static MOZ_ALWAYS_INLINE bool JSID_IS_INT(jsid id) { return !!(JSID_BITS(id) & JSID_TYPE_INT); @@ -166,20 +160,36 @@ extern JS_PUBLIC_DATA(const JS::HandleId) JSID_VOIDHANDLE; extern JS_PUBLIC_DATA(const JS::HandleId) JSID_EMPTYHANDLE; -namespace js { +namespace JS { template <> -struct GCMethods +struct GCPolicy { static jsid initial() { return JSID_VOID; } + static void trace(JSTracer* trc, jsid* idp, const char* name) { + js::UnsafeTraceManuallyBarrieredEdge(trc, idp, name); + } +}; + +} // namespace JS + +namespace js { + +template <> +struct BarrierMethods +{ static void postBarrier(jsid* idp, jsid prev, jsid next) {} + static void exposeToJS(jsid 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, jsid& id, Args&&... args) +DispatchTyped(F f, const jsid& id, Args&&... args) -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) { if (JSID_IS_STRING(id)) Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Initialization.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Initialization.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Initialization.h @@ -25,6 +25,9 @@ extern JS_PUBLIC_DATA(InitState) libraryInitState; +extern JS_PUBLIC_API(const char*) +InitWithFailureDiagnostic(bool isDebugBuild); + } // namespace detail } // namespace JS @@ -58,8 +61,46 @@ * is, calling JS_Init/JSAPI methods/JS_ShutDown in that order, then doing so * again). This restriction may eventually be lifted. */ -extern JS_PUBLIC_API(bool) -JS_Init(void); +inline bool +JS_Init(void) +{ +#ifdef DEBUG + return !JS::detail::InitWithFailureDiagnostic(true); +#else + return !JS::detail::InitWithFailureDiagnostic(false); +#endif +} + +/** + * A variant of JS_Init. On success it returns nullptr. On failure it returns a + * pointer to a string literal that describes how initialization failed, which + * can be useful for debugging purposes. + */ +inline const char* +JS_InitWithFailureDiagnostic(void) +{ +#ifdef DEBUG + return JS::detail::InitWithFailureDiagnostic(true); +#else + return JS::detail::InitWithFailureDiagnostic(false); +#endif +} + +/* + * Returns true if SpiderMonkey has been initialized successfully, even if it has + * possibly been shut down. + * + * Note that it is the responsibility of the embedder to call JS_Init() and + * JS_ShutDown() at the correct times, and therefore this API should ideally not + * be necessary to use. This is only intended to be used in cases where the + * embedder isn't in full control of deciding whether to initialize SpiderMonkey + * or hand off the task to another consumer. + */ +inline bool +JS_IsInitialized(void) +{ + return JS::detail::libraryInitState != JS::detail::InitState::Uninitialized; +} /** * Destroy free-standing resources allocated by SpiderMonkey, not associated Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/MemoryMetrics.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/MemoryMetrics.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/MemoryMetrics.h @@ -166,23 +166,17 @@ #define FOR_EACH_SIZE(macro) \ macro(Objects, GCHeapUsed, objectsGCHeap) \ macro(Objects, MallocHeap, objectsMallocHeapSlots) \ - macro(Objects, MallocHeap, objectsMallocHeapElementsNonAsmJS) \ + macro(Objects, MallocHeap, objectsMallocHeapElementsNormal) \ macro(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \ - macro(Objects, NonHeap, objectsNonHeapElementsAsmJS) \ - macro(Objects, NonHeap, objectsNonHeapElementsMapped) \ - macro(Objects, NonHeap, objectsNonHeapCodeAsmJS) \ macro(Objects, MallocHeap, objectsMallocHeapMisc) \ - \ - macro(Other, GCHeapUsed, shapesGCHeapTree) \ - macro(Other, GCHeapUsed, shapesGCHeapDict) \ - macro(Other, GCHeapUsed, shapesGCHeapBase) \ - macro(Other, MallocHeap, shapesMallocHeapTreeTables) \ - macro(Other, MallocHeap, shapesMallocHeapDictTables) \ - macro(Other, MallocHeap, shapesMallocHeapTreeKids) + macro(Objects, NonHeap, objectsNonHeapElementsNormal) \ + macro(Objects, NonHeap, objectsNonHeapElementsShared) \ + macro(Objects, NonHeap, objectsNonHeapElementsWasm) \ + macro(Objects, NonHeap, objectsNonHeapCodeWasm) ClassInfo() : FOR_EACH_SIZE(ZERO_SIZE) - dummy() + wasmGuardPages(0) {} void add(const ClassInfo& other) { @@ -219,6 +213,55 @@ } FOR_EACH_SIZE(DECL_SIZE) + size_t wasmGuardPages; + +#undef FOR_EACH_SIZE +}; + +struct ShapeInfo +{ +#define FOR_EACH_SIZE(macro) \ + macro(Other, GCHeapUsed, shapesGCHeapTree) \ + macro(Other, GCHeapUsed, shapesGCHeapDict) \ + macro(Other, GCHeapUsed, shapesGCHeapBase) \ + macro(Other, MallocHeap, shapesMallocHeapTreeTables) \ + macro(Other, MallocHeap, shapesMallocHeapDictTables) \ + macro(Other, MallocHeap, shapesMallocHeapTreeKids) + + ShapeInfo() + : FOR_EACH_SIZE(ZERO_SIZE) + dummy() + {} + + void add(const ShapeInfo& other) { + FOR_EACH_SIZE(ADD_OTHER_SIZE) + } + + void subtract(const ShapeInfo& other) { + FOR_EACH_SIZE(SUB_OTHER_SIZE) + } + + size_t sizeOfAllThings() const { + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N) + return n; + } + + size_t sizeOfLiveGCThings() const { + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) + return n; + } + + void addToTabSizes(TabSizes* sizes) const { + FOR_EACH_SIZE(ADD_TO_TAB_SIZES) + } + + void addToServoSizes(ServoSizes *sizes) const { + FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) + } + + FOR_EACH_SIZE(DECL_SIZE) int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE) #undef FOR_EACH_SIZE @@ -282,7 +325,6 @@ #define FOR_EACH_SIZE(macro) \ macro(_, MallocHeap, marker) \ macro(_, NonHeap, nurseryCommitted) \ - macro(_, NonHeap, nurseryDecommitted) \ macro(_, MallocHeap, nurseryMallocedBuffers) \ macro(_, MallocHeap, storeBufferVals) \ macro(_, MallocHeap, storeBufferCells) \ @@ -396,8 +438,6 @@ struct ScriptSourceInfo { #define FOR_EACH_SIZE(macro) \ - macro(_, MallocHeap, compressed) \ - macro(_, MallocHeap, uncompressed) \ macro(_, MallocHeap, misc) ScriptSourceInfo() @@ -468,12 +508,12 @@ macro(_, MallocHeap, object) \ macro(_, MallocHeap, atomsTable) \ macro(_, MallocHeap, contexts) \ - macro(_, MallocHeap, dtoa) \ macro(_, MallocHeap, temporary) \ macro(_, MallocHeap, interpreterStack) \ macro(_, MallocHeap, mathCache) \ + macro(_, MallocHeap, sharedImmutableStringsCache) \ + macro(_, MallocHeap, sharedIntlData) \ macro(_, MallocHeap, uncompressedSourceCache) \ - macro(_, MallocHeap, compressedSourceSet) \ macro(_, MallocHeap, scriptData) RuntimeSizes() @@ -537,6 +577,7 @@ macro(Other, GCHeapUnused, string) \ macro(Other, GCHeapUnused, symbol) \ macro(Other, GCHeapUnused, jitcode) \ + macro(Other, GCHeapUnused, scope) UnusedGCThingSizes() : FOR_EACH_SIZE(ZERO_SIZE) @@ -559,6 +600,7 @@ case JS::TraceKind::JitCode: jitcode += n; break; case JS::TraceKind::LazyScript: lazyScript += n; break; case JS::TraceKind::ObjectGroup: objectGroup += n; break; + case JS::TraceKind::Scope: scope += n; break; default: MOZ_CRASH("Bad trace kind for UnusedGCThingSizes"); } @@ -598,14 +640,18 @@ macro(Other, GCHeapUsed, jitCodesGCHeap) \ macro(Other, GCHeapUsed, objectGroupsGCHeap) \ macro(Other, MallocHeap, objectGroupsMallocHeap) \ + macro(Other, GCHeapUsed, scopesGCHeap) \ + macro(Other, MallocHeap, scopesMallocHeap) \ macro(Other, MallocHeap, typePool) \ macro(Other, MallocHeap, baselineStubsOptimized) \ - macro(Other, MallocHeap, uniqueIdMap) + macro(Other, MallocHeap, uniqueIdMap) \ + macro(Other, MallocHeap, shapeTables) ZoneStats() : FOR_EACH_SIZE(ZERO_SIZE) unusedGCThings(), stringInfo(), + shapeInfo(), extra(), allStrings(nullptr), notableStrings(), @@ -616,6 +662,7 @@ : FOR_EACH_SIZE(COPY_OTHER_SIZE) unusedGCThings(mozilla::Move(other.unusedGCThings)), stringInfo(mozilla::Move(other.stringInfo)), + shapeInfo(mozilla::Move(other.shapeInfo)), extra(other.extra), allStrings(other.allStrings), notableStrings(mozilla::Move(other.notableStrings)), @@ -639,6 +686,7 @@ FOR_EACH_SIZE(ADD_OTHER_SIZE) unusedGCThings.addSizes(other.unusedGCThings); stringInfo.add(other.stringInfo); + shapeInfo.add(other.shapeInfo); } size_t sizeOfLiveGCThings() const { @@ -646,6 +694,7 @@ size_t n = 0; FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) n += stringInfo.sizeOfLiveGCThings(); + n += shapeInfo.sizeOfLiveGCThings(); return n; } @@ -654,6 +703,7 @@ FOR_EACH_SIZE(ADD_TO_TAB_SIZES) unusedGCThings.addToTabSizes(sizes); stringInfo.addToTabSizes(sizes); + shapeInfo.addToTabSizes(sizes); } void addToServoSizes(JS::ServoSizes *sizes) const { @@ -661,6 +711,7 @@ FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) unusedGCThings.addToServoSizes(sizes); stringInfo.addToServoSizes(sizes); + shapeInfo.addToServoSizes(sizes); } // These string measurements are initially for all strings. At the end, @@ -670,6 +721,7 @@ FOR_EACH_SIZE(DECL_SIZE) UnusedGCThingSizes unusedGCThings; StringInfo stringInfo; + ShapeInfo shapeInfo; void* extra; // This field can be used by embedders. typedef js::HashMap storage_; - js::AsmJSProfilingFrameIterator& asmJSIter() { + js::wasm::ProfilingFrameIterator& wasmIter() { MOZ_ASSERT(!done()); - MOZ_ASSERT(isAsmJS()); - return *reinterpret_cast(storage_.addr()); + MOZ_ASSERT(isWasm()); + return *reinterpret_cast(storage_.addr()); } - const js::AsmJSProfilingFrameIterator& asmJSIter() const { + const js::wasm::ProfilingFrameIterator& wasmIter() const { MOZ_ASSERT(!done()); - MOZ_ASSERT(isAsmJS()); - return *reinterpret_cast(storage_.addr()); + MOZ_ASSERT(isWasm()); + return *reinterpret_cast(storage_.addr()); } js::jit::JitProfilingFrameIterator& jitIter() { @@ -87,7 +97,7 @@ void* lr; }; - ProfilingFrameIterator(JSRuntime* rt, const RegisterState& state, + ProfilingFrameIterator(JSContext* cx, const RegisterState& state, uint32_t sampleBufferGen = UINT32_MAX); ~ProfilingFrameIterator(); void operator++(); @@ -104,7 +114,7 @@ { Frame_Baseline, Frame_Ion, - Frame_AsmJS + Frame_Wasm }; struct Frame @@ -113,10 +123,10 @@ void* stackAddress; void* returnAddress; void* activation; - const char* label; + UniqueChars label; }; - bool isAsmJS() const; + bool isWasm() const; bool isJit() const; uint32_t extractStack(Frame* frames, uint32_t offset, uint32_t end) const; @@ -133,7 +143,7 @@ }; JS_FRIEND_API(bool) -IsProfilingEnabledForRuntime(JSRuntime* runtime); +IsProfilingEnabledForContext(JSContext* cx); /** * After each sample run, this method should be called with the latest sample @@ -144,7 +154,7 @@ * JSRuntime for documentation about what these values are used for. */ JS_FRIEND_API(void) -UpdateJSRuntimeProfilerSampleBufferGen(JSRuntime* runtime, uint32_t generation, +UpdateJSContextProfilerSampleBufferGen(JSContext* cx, uint32_t generation, uint32_t lapCount); struct ForEachProfiledFrameOp @@ -153,7 +163,7 @@ // lookups on JitcodeGlobalTable. class MOZ_STACK_CLASS FrameHandle { - friend JS_PUBLIC_API(void) ForEachProfiledFrame(JSRuntime* rt, void* addr, + friend JS_PUBLIC_API(void) ForEachProfiledFrame(JSContext* cx, void* addr, ForEachProfiledFrameOp& op); JSRuntime* rt_; @@ -175,10 +185,13 @@ bool hasTrackedOptimizations() const { return optsIndex_.isSome(); } void* canonicalAddress() const { return canonicalAddr_; } - ProfilingFrameIterator::FrameKind frameKind() const; - void forEachOptimizationAttempt(ForEachTrackedOptimizationAttemptOp& op, - JSScript** scriptOut, jsbytecode** pcOut) const; - void forEachOptimizationTypeInfo(ForEachTrackedOptimizationTypeInfoOp& op) const; + JS_PUBLIC_API(ProfilingFrameIterator::FrameKind) frameKind() const; + JS_PUBLIC_API(void) forEachOptimizationAttempt(ForEachTrackedOptimizationAttemptOp& op, + JSScript** scriptOut, + jsbytecode** pcOut) const; + + JS_PUBLIC_API(void) + forEachOptimizationTypeInfo(ForEachTrackedOptimizationTypeInfoOp& op) const; }; // Called once per frame. @@ -186,7 +199,7 @@ }; JS_PUBLIC_API(void) -ForEachProfiledFrame(JSRuntime* rt, void* addr, ForEachProfiledFrameOp& op); +ForEachProfiledFrame(JSContext* cx, void* addr, ForEachProfiledFrameOp& op); } // namespace JS Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/ProfilingStack.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/ProfilingStack.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/ProfilingStack.h @@ -14,6 +14,7 @@ #include "js/Utility.h" struct JSRuntime; +class JSTracer; namespace js { @@ -42,14 +43,14 @@ void * volatile spOrScript; // Line number for non-JS entries, the bytecode offset otherwise. - int32_t volatile lineOrPc; + int32_t volatile lineOrPcOffset; // General purpose storage describing this frame. uint32_t volatile flags_; public: // These traits are bit masks. Make sure they're powers of 2. - enum Flags { + enum Flags : uint32_t { // Indicate whether a profile entry represents a CPP frame. If not set, // a JS frame is assumed by default. You're not allowed to publicly // change the frame type. Instead, initialize the ProfileEntry as either @@ -75,7 +76,7 @@ CATEGORY_MASK = ~ALL }; - // Keep these in sync with devtools/client/performance/modules/global.js + // Keep these in sync with devtools/client/performance/modules/categories.js enum class Category : uint32_t { OTHER = 0x10, CSS = 0x20, @@ -115,7 +116,7 @@ void initCppFrame(void* aSp, uint32_t aLine) volatile { flags_ = IS_CPP_ENTRY; spOrScript = aSp; - lineOrPc = static_cast(aLine); + lineOrPcOffset = static_cast(aLine); } void setFlag(uint32_t flag) volatile { @@ -160,19 +161,24 @@ MOZ_ASSERT(!isJs()); return spOrScript; } - JSScript* script() const volatile { - MOZ_ASSERT(isJs()); - return (JSScript*)spOrScript; - } + JS_PUBLIC_API(JSScript*) script() const volatile; uint32_t line() const volatile { MOZ_ASSERT(!isJs()); - return static_cast(lineOrPc); + return static_cast(lineOrPcOffset); + } + + // Note that the pointer returned might be invalid. + JSScript* rawScript() const volatile { + MOZ_ASSERT(isJs()); + return (JSScript*)spOrScript; } // We can't know the layout of JSScript, so look in vm/SPSProfiler.cpp. JS_FRIEND_API(jsbytecode*) pc() const volatile; JS_FRIEND_API(void) setPC(jsbytecode* pc) volatile; + void trace(JSTracer* trc); + // The offset of a pc into a script's code can actually be 0, so to // signify a nullptr pc, use a -1 index. This is checked against in // pc() and setPC() to set/get the right pc. @@ -180,22 +186,22 @@ static size_t offsetOfLabel() { return offsetof(ProfileEntry, string); } static size_t offsetOfSpOrScript() { return offsetof(ProfileEntry, spOrScript); } - static size_t offsetOfLineOrPc() { return offsetof(ProfileEntry, lineOrPc); } + static size_t offsetOfLineOrPcOffset() { return offsetof(ProfileEntry, lineOrPcOffset); } static size_t offsetOfFlags() { return offsetof(ProfileEntry, flags_); } }; JS_FRIEND_API(void) -SetRuntimeProfilingStack(JSRuntime* rt, ProfileEntry* stack, uint32_t* size, +SetContextProfilingStack(JSContext* cx, ProfileEntry* stack, uint32_t* size, uint32_t max); JS_FRIEND_API(void) -EnableRuntimeProfilingStack(JSRuntime* rt, bool enabled); +EnableContextProfilingStack(JSContext* cx, bool enabled); JS_FRIEND_API(void) -RegisterRuntimeProfilingEventMarker(JSRuntime* rt, void (*fn)(const char*)); +RegisterContextProfilingEventMarker(JSContext* cx, void (*fn)(const char*)); JS_FRIEND_API(jsbytecode*) -ProfilingGetPC(JSRuntime* rt, JSScript* script, void* ip); +ProfilingGetPC(JSContext* cx, JSScript* script, void* ip); } // namespace js Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Proxy.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Proxy.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Proxy.h @@ -29,6 +29,7 @@ using JS::NativeImpl; using JS::ObjectOpResult; using JS::PrivateValue; +using JS::PropertyDescriptor; using JS::Value; class RegExpGuard; @@ -58,16 +59,15 @@ * * ### Proxies and internal methods * - * ES6 draft rev 27 (24 August 2014) specifies 14 internal methods. The runtime - * semantics of just about everything a script can do to an object is specified - * in terms of these internal methods. For example: + * ES2016 specifies 13 internal methods. The runtime semantics of just + * about everything a script can do to an object is specified in terms + * of these internal methods. For example: * * JS code ES6 internal method that gets called * --------------------------- -------------------------------- * obj.prop obj.[[Get]](obj, "prop") * "prop" in obj obj.[[HasProperty]]("prop") * new obj() obj.[[Construct]]() - * for (k in obj) {} obj.[[Enumerate]]() * * With regard to the implementation of these internal methods, there are three * very different kinds of object in SpiderMonkey. @@ -101,10 +101,8 @@ * * BaseProxyHandler * | - * DirectProxyHandler // has a target - * | - * Wrapper // can be unwrapped, revealing target - * | // (see js::CheckedUnwrap) + * Wrapper // has a target, can be unwrapped to reveal + * | // target (see js::CheckedUnwrap) * | * CrossCompartmentWrapper // target is in another compartment; * // implements membrane between compartments @@ -191,7 +189,7 @@ bool mHasSecurityPolicy; public: - explicit MOZ_CONSTEXPR BaseProxyHandler(const void* aFamily, bool aHasPrototype = false, + explicit constexpr BaseProxyHandler(const void* aFamily, bool aHasPrototype = false, bool aHasSecurityPolicy = false) : mFamily(aFamily), mHasPrototype(aHasPrototype), @@ -213,7 +211,7 @@ return offsetof(BaseProxyHandler, mFamily); } - virtual bool finalizeInBackground(Value priv) const { + virtual bool finalizeInBackground(const Value& priv) const { /* * Called on creation of a proxy to determine whether its finalize * method can be finalized on the background thread. @@ -221,6 +219,14 @@ return true; } + virtual bool canNurseryAllocate() const { + /* + * Nursery allocation is allowed if and only if it is safe to not + * run |finalize| when the ProxyObject dies. + */ + return false; + } + /* Policy enforcement methods. * * enter() allows the policy to specify whether the caller may perform |act| @@ -251,9 +257,9 @@ /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const = 0; + MutableHandle desc) const = 0; virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const = 0; virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const = 0; @@ -261,14 +267,6 @@ ObjectOpResult& result) const = 0; /* - * Because [[Enumerate]] is one of the standard traps it should be overridden. - * However for convenience BaseProxyHandler includes a pure virtual implementation, - * that turns the properties returned by getOwnEnumerablePropertyKeys (and proto walking) - * into an Iterator object. - */ - virtual bool enumerate(JSContext* cx, HandleObject proxy, MutableHandleObject objp) const = 0; - - /* * These methods are standard, but the engine does not normally call them. * They're opt-in. See "Proxy prototype chains" above. * @@ -278,7 +276,9 @@ virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result) const; - /* Non-standard but conceptual kin to {g,s}etPrototype, so lives here. */ + /* Non-standard but conceptual kin to {g,s}etPrototype, so these live here. */ + virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const = 0; virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const; virtual bool preventExtensions(JSContext* cx, HandleObject proxy, @@ -314,8 +314,9 @@ virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const; /* SpiderMonkey extensions. */ + virtual bool enumerate(JSContext* cx, HandleObject proxy, MutableHandleObject objp) const; virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const; + MutableHandle desc) const; virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const; virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const; @@ -323,7 +324,7 @@ const CallArgs& args) const; virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp) const; virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, - ESClassValue* classValue) const; + ESClass* cls) const; virtual bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const; virtual const char* className(JSContext* cx, HandleObject proxy) const; virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const; @@ -354,79 +355,6 @@ virtual bool isScripted() const { return false; } }; -/* - * DirectProxyHandler includes a notion of a target object. All methods are - * reimplemented such that they forward their behavior to the target. This - * allows consumers of this class to forward to another object as transparently - * and efficiently as possible. - * - * Important: If you add a method implementation here, you probably also need - * to add an override in CrossCompartmentWrapper. If you don't, you risk - * compartment mismatches. See bug 945826 comment 0. - */ -class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler -{ - public: - explicit MOZ_CONSTEXPR DirectProxyHandler(const void* aFamily, bool aHasPrototype = false, - bool aHasSecurityPolicy = false) - : BaseProxyHandler(aFamily, aHasPrototype, aHasSecurityPolicy) - { } - - /* Standard internal methods. */ - virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const override; - virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, - ObjectOpResult& result) const override; - virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy, - AutoIdVector& props) const override; - virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id, - ObjectOpResult& result) const override; - virtual bool enumerate(JSContext* cx, HandleObject proxy, - MutableHandleObject objp) const override; - virtual bool getPrototype(JSContext* cx, HandleObject proxy, - MutableHandleObject protop) const override; - virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, - ObjectOpResult& result) const override; - virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, - bool* succeeded) const override; - virtual bool preventExtensions(JSContext* cx, HandleObject proxy, - ObjectOpResult& result) const override; - virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override; - virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, - bool* bp) const override; - virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, - HandleId id, MutableHandleValue vp) const override; - virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result) const override; - virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const override; - virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override; - - /* SpiderMonkey extensions. */ - virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const override; - virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, - bool* bp) const override; - virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, - AutoIdVector& props) const override; - virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, - const CallArgs& args) const override; - virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, - bool* bp) const override; - virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, - ESClassValue* classValue) const override; - virtual bool isArray(JSContext* cx, HandleObject proxy, - JS::IsArrayAnswer* answer) const override; - virtual const char* className(JSContext* cx, HandleObject proxy) const override; - virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, - unsigned indent) const override; - virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, - RegExpGuard* g) const override; - virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override; - virtual bool isCallable(JSObject* obj) const override; - virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const override; -}; - extern JS_FRIEND_DATA(const js::Class* const) ProxyClassPtr; inline bool IsProxy(const JSObject* obj) @@ -434,6 +362,7 @@ return GetObjectClass(obj)->isProxy(); } +namespace detail { const uint32_t PROXY_EXTRA_SLOTS = 2; // Layout of the values stored by a proxy. Note that API clients require the @@ -470,7 +399,6 @@ const uint32_t ProxyDataOffset = 2 * sizeof(void*); -// This method should only be used internally and by the accessors below. inline ProxyDataLayout* GetProxyDataLayout(JSObject* obj) { @@ -478,16 +406,25 @@ return reinterpret_cast(reinterpret_cast(obj) + ProxyDataOffset); } +inline const ProxyDataLayout* +GetProxyDataLayout(const JSObject* obj) +{ + MOZ_ASSERT(IsProxy(obj)); + return reinterpret_cast(reinterpret_cast(obj) + + ProxyDataOffset); +} +} // namespace detail + inline const BaseProxyHandler* -GetProxyHandler(JSObject* obj) +GetProxyHandler(const JSObject* obj) { - return GetProxyDataLayout(obj)->handler; + return detail::GetProxyDataLayout(obj)->handler; } inline const Value& -GetProxyPrivate(JSObject* obj) +GetProxyPrivate(const JSObject* obj) { - return GetProxyDataLayout(obj)->values->privateSlot; + return detail::GetProxyDataLayout(obj)->values->privateSlot; } inline JSObject* @@ -497,16 +434,16 @@ } inline const Value& -GetProxyExtra(JSObject* obj, size_t n) +GetProxyExtra(const JSObject* obj, size_t n) { - MOZ_ASSERT(n < PROXY_EXTRA_SLOTS); - return GetProxyDataLayout(obj)->values->extraSlots[n]; + MOZ_ASSERT(n < detail::PROXY_EXTRA_SLOTS); + return detail::GetProxyDataLayout(obj)->values->extraSlots[n]; } inline void SetProxyHandler(JSObject* obj, const BaseProxyHandler* handler) { - GetProxyDataLayout(obj)->handler = handler; + detail::GetProxyDataLayout(obj)->handler = handler; } JS_FRIEND_API(void) @@ -515,8 +452,8 @@ inline void SetProxyExtra(JSObject* obj, size_t n, const Value& extra) { - MOZ_ASSERT(n < PROXY_EXTRA_SLOTS); - Value* vp = &GetProxyDataLayout(obj)->values->extraSlots[n]; + MOZ_ASSERT(n < detail::PROXY_EXTRA_SLOTS); + Value* vp = &detail::GetProxyDataLayout(obj)->values->extraSlots[n]; // Trigger a barrier before writing the slot. if (vp->isMarkable() || extra.isMarkable()) @@ -526,13 +463,13 @@ } inline bool -IsScriptedProxy(JSObject* obj) +IsScriptedProxy(const JSObject* obj) { return IsProxy(obj) && GetProxyHandler(obj)->isScripted(); } inline const Value& -GetReservedOrProxyPrivateSlot(JSObject* obj, size_t slot) +GetReservedOrProxyPrivateSlot(const JSObject* obj, size_t slot) { MOZ_ASSERT(slot == 0); MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)) || IsProxy(obj)); @@ -597,7 +534,7 @@ JSObject* proto, const ProxyOptions& options = ProxyOptions()); JSObject* -RenewProxyObject(JSContext* cx, JSObject* obj, BaseProxyHandler* handler, Value priv); +RenewProxyObject(JSContext* cx, JSObject* obj, BaseProxyHandler* handler, const Value& priv); class JS_FRIEND_API(AutoEnterPolicy) { Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Realm.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Realm.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Realm.h @@ -0,0 +1,42 @@ +/* -*- 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/. */ + +/* + * Ways to get various per-Realm objects. All the getters declared in this + * header operate on the Realm corresponding to the current compartment on the + * JSContext. + */ + +#ifndef js_Realm_h +#define js_Realm_h + +#include "jstypes.h" + +struct JSContext; +class JSObject; + +namespace JS { + +extern JS_PUBLIC_API(JSObject*) +GetRealmObjectPrototype(JSContext* cx); + +extern JS_PUBLIC_API(JSObject*) +GetRealmFunctionPrototype(JSContext* cx); + +extern JS_PUBLIC_API(JSObject*) +GetRealmArrayPrototype(JSContext* cx); + +extern JS_PUBLIC_API(JSObject*) +GetRealmErrorPrototype(JSContext* cx); + +extern JS_PUBLIC_API(JSObject*) +GetRealmIteratorPrototype(JSContext* cx); + +} // namespace JS + +#endif // js_Realm_h + + Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/RootingAPI.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/RootingAPI.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/RootingAPI.h @@ -14,11 +14,16 @@ #include "mozilla/Move.h" #include "mozilla/TypeTraits.h" +#include + #include "jspubtd.h" +#include "js/GCAnnotations.h" #include "js/GCAPI.h" +#include "js/GCPolicyAPI.h" #include "js/HeapAPI.h" #include "js/TypeDecls.h" +#include "js/UniquePtr.h" #include "js/Utility.h" /* @@ -105,8 +110,7 @@ namespace js { template -struct GCMethods { - static T initial() { return T(); } +struct BarrierMethods { }; template @@ -121,6 +125,14 @@ template class HeapBase {}; +// Cannot use FOR_EACH_HEAP_ABLE_GC_POINTER_TYPE, as this would import too many macros into scope +template struct IsHeapConstructibleType { static constexpr bool value = false; }; +#define DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE(T) \ + template <> struct IsHeapConstructibleType { static constexpr bool value = true; }; +FOR_EACH_PUBLIC_GC_POINTER_TYPE(DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE) +FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE) +#undef DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE + template class PersistentRootedBase {}; @@ -132,14 +144,14 @@ struct PersistentRootedMarker; } /* namespace gc */ -#define DECLARE_POINTER_COMPARISON_OPS(T) \ +#define DECLARE_POINTER_COMPARISON_OPS(T) \ bool operator==(const T& other) const { return get() == other; } \ bool operator!=(const T& other) const { return get() != other; } // Important: Return a reference so passing a Rooted, etc. to // something that takes a |const T&| is not a GC hazard. -#define DECLARE_POINTER_CONSTREF_OPS(T) \ - operator const T&() const { return get(); } \ +#define DECLARE_POINTER_CONSTREF_OPS(T) \ + operator const T&() const { return get(); } \ const T& operator->() const { return get(); } // Assignment operators on a base class are hidden by the implicitly defined @@ -150,12 +162,16 @@ set(p); \ return *this; \ } \ + Wrapper& operator=(T&& p) { \ + set(mozilla::Move(p)); \ + return *this; \ + } \ Wrapper& operator=(const Wrapper& other) { \ set(other.get()); \ return *this; \ } \ -#define DELETE_ASSIGNMENT_OPS(Wrapper, T) \ +#define DELETE_ASSIGNMENT_OPS(Wrapper, T) \ template Wrapper& operator=(S) = delete; \ Wrapper& operator=(const Wrapper&) = delete; @@ -212,18 +228,21 @@ * Heap objects should only be used on the heap. GC references stored on the * C/C++ stack must use Rooted/Handle/MutableHandle instead. * - * Type T must be one of: JS::Value, jsid, JSObject*, JSString*, JSScript* + * Type T must be a public GC pointer type. */ template -class Heap : public js::HeapBase +class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase { + // Please note: this can actually also be used by nsXBLMaybeCompiled, for legacy reasons. + static_assert(js::IsHeapConstructibleType::value, + "Type T must be a public GC pointer type"); public: Heap() { static_assert(sizeof(T) == sizeof(Heap), "Heap must be binary compatible with T."); - init(js::GCMethods::initial()); + init(GCPolicy::initial()); } - explicit Heap(T p) { init(p); } + explicit Heap(const T& p) { init(p); } /* * For Heap, move semantics are equivalent to copy semantics. In C++, a @@ -234,50 +253,91 @@ explicit Heap(const Heap& p) { init(p.ptr); } ~Heap() { - post(ptr, js::GCMethods::initial()); + post(ptr, GCPolicy::initial()); } DECLARE_POINTER_CONSTREF_OPS(T); DECLARE_POINTER_ASSIGN_OPS(Heap, T); - DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); - T* unsafeGet() { return &ptr; } + const T* address() const { return &ptr; } - /* - * Set the pointer to a value which will cause a crash if it is - * dereferenced. - */ - void setToCrashOnTouch() { - ptr = reinterpret_cast(crashOnTouchPointer); + void exposeToActiveJS() const { + js::BarrierMethods::exposeToJS(ptr); + } + const T& get() const { + exposeToActiveJS(); + return ptr; + } + const T& unbarrieredGet() const { + return ptr; } - bool isSetToCrashOnTouch() { - return ptr == crashOnTouchPointer; + T* unsafeGet() { return &ptr; } + + explicit operator bool() const { + return bool(js::BarrierMethods::asGCThingOrNull(ptr)); + } + explicit operator bool() { + return bool(js::BarrierMethods::asGCThingOrNull(ptr)); } private: - void init(T newPtr) { + void init(const T& newPtr) { ptr = newPtr; - post(js::GCMethods::initial(), ptr); + post(GCPolicy::initial(), ptr); } - void set(T newPtr) { + void set(const T& newPtr) { T tmp = ptr; ptr = newPtr; post(tmp, ptr); } void post(const T& prev, const T& next) { - js::GCMethods::postBarrier(&ptr, prev, next); + js::BarrierMethods::postBarrier(&ptr, prev, next); } - enum { - crashOnTouchPointer = 1 - }; - T ptr; }; +static MOZ_ALWAYS_INLINE bool +ObjectIsTenured(JSObject* obj) +{ + return !js::gc::IsInsideNursery(reinterpret_cast(obj)); +} + +static MOZ_ALWAYS_INLINE bool +ObjectIsTenured(const Heap& obj) +{ + return ObjectIsTenured(obj.unbarrieredGet()); +} + +static MOZ_ALWAYS_INLINE bool +ObjectIsMarkedGray(JSObject* obj) +{ + auto cell = reinterpret_cast(obj); + return js::gc::detail::CellIsMarkedGrayIfKnown(cell); +} + +static MOZ_ALWAYS_INLINE bool +ObjectIsMarkedGray(const JS::Heap& obj) +{ + return ObjectIsMarkedGray(obj.unbarrieredGet()); +} + +static MOZ_ALWAYS_INLINE bool +ScriptIsMarkedGray(JSScript* script) +{ + auto cell = reinterpret_cast(script); + return js::gc::detail::CellIsMarkedGrayIfKnown(cell); +} + +static MOZ_ALWAYS_INLINE bool +ScriptIsMarkedGray(const Heap& script) +{ + return ScriptIsMarkedGray(script.unbarrieredGet()); +} + /** * The TenuredHeap class is similar to the Heap class above in that it * encapsulates the GC concerns of an on-heap reference to a JS object. However, @@ -343,12 +403,27 @@ return (bits & flag) != 0; } - T getPtr() const { return reinterpret_cast(bits & ~flagsMask); } + T unbarrieredGetPtr() const { return reinterpret_cast(bits & ~flagsMask); } uintptr_t getFlags() const { return bits & flagsMask; } + void exposeToActiveJS() const { + js::BarrierMethods::exposeToJS(unbarrieredGetPtr()); + } + T getPtr() const { + exposeToActiveJS(); + return unbarrieredGetPtr(); + } + operator T() const { return getPtr(); } T operator->() const { return getPtr(); } + explicit operator bool() const { + return bool(js::BarrierMethods::asGCThingOrNull(unbarrieredGetPtr())); + } + explicit operator bool() { + return bool(js::BarrierMethods::asGCThingOrNull(unbarrieredGetPtr())); + } + TenuredHeap& operator=(T p) { setPtr(p); return *this; @@ -417,7 +492,7 @@ * for the lifetime of the handle, as its users may not expect its value * to change underneath them. */ - static MOZ_CONSTEXPR Handle fromMarkedLocation(const T* p) { + static constexpr Handle fromMarkedLocation(const T* p) { return Handle(p, DeliberatelyChoosingThisOverload, ImUsingThisOnlyInFromFromMarkedLocation); } @@ -452,7 +527,7 @@ enum Disambiguator { DeliberatelyChoosingThisOverload = 42 }; enum CallerIdentity { ImUsingThisOnlyInFromFromMarkedLocation = 17 }; - MOZ_CONSTEXPR Handle(const T* p, Disambiguator, CallerIdentity) : ptr(p) {} + constexpr Handle(const T* p, Disambiguator, CallerIdentity) : ptr(p) {} const T* ptr; }; @@ -477,9 +552,12 @@ MutableHandle(decltype(nullptr)) = delete; public: - void set(T v) { + void set(const T& v) { *ptr = v; } + void set(T&& v) { + *ptr = mozilla::Move(v); + } /* * This may be called only if the location of the T is guaranteed @@ -509,36 +587,28 @@ namespace js { -/** - * By default, things should use the inheritance hierarchy to find their - * ThingRootKind. Some pointer types are explicitly set in jspubtd.h so that - * Rooted may be used without the class definition being available. - */ -template -struct RootKind -{ - static ThingRootKind rootKind() { return T::rootKind(); } -}; - -template -struct RootKind -{ - static ThingRootKind rootKind() { return T::rootKind(); } -}; - template -struct GCMethods +struct BarrierMethods { static T* initial() { return nullptr; } + static gc::Cell* asGCThingOrNull(T* v) { + if (!v) + return nullptr; + MOZ_ASSERT(uintptr_t(v) > 32); + return reinterpret_cast(v); + } static void postBarrier(T** vp, T* prev, T* next) { if (next) JS::AssertGCThingIsNotAnObjectSubclass(reinterpret_cast(next)); } - static void relocate(T** vp) {} + static void exposeToJS(T* t) { + if (t) + js::gc::ExposeGCThingToActiveJS(JS::GCCellPtr(t)); + } }; template <> -struct GCMethods +struct BarrierMethods { static JSObject* initial() { return nullptr; } static gc::Cell* asGCThingOrNull(JSObject* v) { @@ -550,17 +620,31 @@ static void postBarrier(JSObject** vp, JSObject* prev, JSObject* next) { JS::HeapObjectPostBarrier(vp, prev, next); } + static void exposeToJS(JSObject* obj) { + if (obj) + JS::ExposeObjectToActiveJS(obj); + } }; template <> -struct GCMethods +struct BarrierMethods { static JSFunction* initial() { return nullptr; } + static gc::Cell* asGCThingOrNull(JSFunction* v) { + if (!v) + return nullptr; + MOZ_ASSERT(uintptr_t(v) > 32); + return reinterpret_cast(v); + } static void postBarrier(JSFunction** vp, JSFunction* prev, JSFunction* next) { JS::HeapObjectPostBarrier(reinterpret_cast(vp), reinterpret_cast(prev), reinterpret_cast(next)); } + static void exposeToJS(JSFunction* fun) { + if (fun) + JS::ExposeObjectToActiveJS(reinterpret_cast(fun)); + } }; // Provide hash codes for Cell kinds that may be relocated and, thus, not have @@ -580,6 +664,8 @@ using Key = T; using Lookup = T; + static bool hasHash(const Lookup& l); + static bool ensureHash(const Lookup& l); static HashNumber hash(const Lookup& l); static bool match(const Key& k, const Lookup& l); static void rekey(Key& k, const Key& newKey) { k = newKey; } @@ -591,47 +677,52 @@ using Key = JS::Heap; using Lookup = T; + static bool hasHash(const Lookup& l) { return MovableCellHasher::hasHash(l); } + static bool ensureHash(const Lookup& l) { return MovableCellHasher::ensureHash(l); } static HashNumber hash(const Lookup& l) { return MovableCellHasher::hash(l); } - static bool match(const Key& k, const Lookup& l) { return MovableCellHasher::match(k, l); } + static bool match(const Key& k, const Lookup& l) { + return MovableCellHasher::match(k.unbarrieredGet(), l); + } static void rekey(Key& k, const Key& newKey) { k.unsafeSet(newKey); } }; -} /* namespace js */ - -namespace JS { - -// Non pointer types -- structs or classes that contain GC pointers, either as -// a member or in a more complex container layout -- can also be stored in a -// [Persistent]Rooted if it derives from JS::Traceable. A JS::Traceable stored -// in a [Persistent]Rooted must implement the method: -// |static void trace(T*, JSTracer*)| -class Traceable +template +struct FallibleHashMethods> { - public: - static js::ThingRootKind rootKind() { return js::THING_ROOT_TRACEABLE; } + template static bool hasHash(Lookup&& l) { + return MovableCellHasher::hasHash(mozilla::Forward(l)); + } + template static bool ensureHash(Lookup&& l) { + return MovableCellHasher::ensureHash(mozilla::Forward(l)); + } }; -} /* namespace JS */ +} /* namespace js */ namespace js { +// The alignment must be set because the Rooted and PersistentRooted ptr fields +// may be accessed through reinterpret_cast*>, and +// the compiler may choose a different alignment for the ptr field when it +// knows the actual type stored in DispatchWrapper. +// +// It would make more sense to align only those specific fields of type +// DispatchWrapper, rather than DispatchWrapper itself, but that causes MSVC to +// fail when Rooted is used in an IsConvertible test. template -class DispatchWrapper +class alignas(8) DispatchWrapper { - static_assert(mozilla::IsBaseOf::value, + static_assert(JS::MapTypeToRootKind::kind == JS::RootKind::Traceable, "DispatchWrapper is intended only for usage with a Traceable"); - using TraceFn = void (*)(T*, JSTracer*); + using TraceFn = void (*)(JSTracer*, T*, const char*); TraceFn tracer; -#if JS_BITS_PER_WORD == 32 - uint32_t padding; // Ensure the storage fields have CellSize alignment. -#endif - T storage; + alignas(gc::CellSize) T storage; public: template MOZ_IMPLICIT DispatchWrapper(U&& initial) - : tracer(&T::trace), + : tracer(&JS::GCPolicy::trace), storage(mozilla::Forward(initial)) { } @@ -643,37 +734,13 @@ // Trace the contained storage (of unknown type) using the trace function // we set aside when we did know the type. - static void TraceWrapped(JSTracer* trc, JS::Traceable* thingp, const char* name) { + static void TraceWrapped(JSTracer* trc, T* thingp, const char* name) { auto wrapper = reinterpret_cast( uintptr_t(thingp) - offsetof(DispatchWrapper, storage)); - wrapper->tracer(&wrapper->storage, trc); + wrapper->tracer(trc, &wrapper->storage, name); } }; -inline RootLists& -RootListsForRootingContext(JSContext* cx) -{ - return ContextFriendFields::get(cx)->roots; -} - -inline RootLists& -RootListsForRootingContext(js::ContextFriendFields* cx) -{ - return cx->roots; -} - -inline RootLists& -RootListsForRootingContext(JSRuntime* rt) -{ - return PerThreadDataFriendFields::getMainThread(rt)->roots; -} - -inline RootLists& -RootListsForRootingContext(js::PerThreadDataFriendFields* pt) -{ - return pt->roots; -} - } /* namespace js */ namespace JS { @@ -689,30 +756,38 @@ template class MOZ_RAII Rooted : public js::RootedBase { - static_assert(!mozilla::IsConvertible::value, - "Rooted takes pointer or Traceable types but not Traceable* type"); - - /* Note: CX is a subclass of either ContextFriendFields or PerThreadDataFriendFields. */ - void registerWithRootLists(js::RootLists& roots) { - js::ThingRootKind kind = js::RootKind::rootKind(); - this->stack = &roots.stackRoots_[kind]; + inline void registerWithRootLists(js::RootedListHeads& roots) { + this->stack = &roots[JS::MapTypeToRootKind::kind]; this->prev = *stack; *stack = reinterpret_cast*>(this); } + inline js::RootedListHeads& rootLists(JS::RootingContext* cx) { + return rootLists(static_cast(cx)); + } + inline js::RootedListHeads& rootLists(js::ContextFriendFields* cx) { + if (JS::Zone* zone = cx->zone_) + return JS::shadow::Zone::asShadowZone(zone)->stackRoots_; + MOZ_ASSERT(cx->isJSContext); + return cx->roots.stackRoots_; + } + inline js::RootedListHeads& rootLists(JSContext* cx) { + return rootLists(js::ContextFriendFields::get(cx)); + } + public: template explicit Rooted(const RootingContext& cx) - : ptr(js::GCMethods::initial()) + : ptr(GCPolicy::initial()) { - registerWithRootLists(js::RootListsForRootingContext(cx)); + registerWithRootLists(rootLists(cx)); } template Rooted(const RootingContext& cx, S&& initial) : ptr(mozilla::Forward(initial)) { - registerWithRootLists(js::RootListsForRootingContext(cx)); + registerWithRootLists(rootLists(cx)); } ~Rooted() { @@ -726,9 +801,12 @@ * This method is public for Rooted so that Codegen.py can use a Rooted * interchangeably with a MutableHandleValue. */ - void set(T value) { + void set(const T& value) { ptr = value; } + void set(T&& value) { + ptr = mozilla::Move(value); + } DECLARE_POINTER_COMPARISON_OPS(T); DECLARE_POINTER_CONSTREF_OPS(T); @@ -747,20 +825,20 @@ /* * For pointer types, the TraceKind for tracing is based on the list it is - * in (selected via rootKind), so no additional storage is required here. - * All Traceable, however, share the same list, so the function to - * call for tracing is stored adjacent to the struct. Since C++ cannot - * templatize on storage class, this is implemented via the wrapper class - * DispatchWrapper. + * in (selected via MapTypeToRootKind), so no additional storage is + * required here. Non-pointer types, however, share the same list, so the + * function to call for tracing is stored adjacent to the struct. Since C++ + * cannot templatize on storage class, this is implemented via the wrapper + * class DispatchWrapper. */ using MaybeWrapped = typename mozilla::Conditional< - mozilla::IsBaseOf::value, + MapTypeToRootKind::kind == JS::RootKind::Traceable, js::DispatchWrapper, T>::Type; MaybeWrapped ptr; Rooted(const Rooted&) = delete; -}; +} JS_HAZ_ROOTED; } /* namespace JS */ @@ -808,7 +886,7 @@ { public: template - explicit FakeRooted(CX* cx) : ptr(GCMethods::initial()) {} + explicit FakeRooted(CX* cx) : ptr(JS::GCPolicy::initial()) {} template FakeRooted(CX* cx, T initial) : ptr(initial) {} @@ -842,7 +920,7 @@ ptr = root->address(); } - void set(T v) { + void set(const T& v) { *ptr = v; } @@ -899,7 +977,7 @@ template class MaybeRooted { public: - typedef T HandleType; + typedef const T& HandleType; typedef FakeRooted RootType; typedef FakeMutableHandle MutableHandleType; @@ -970,7 +1048,7 @@ * These roots can be used in heap-allocated data structures, so they are not * associated with any particular JSContext or stack. They are registered with * the JSRuntime itself, without locking, so they require a full JSContext to be - * initialized, not one of its more restricted superclasses. Initialization may + * initialized, not one of its more restricted superclasses. Initialization may * take place on construction, or in two phases if the no-argument constructor * is called followed by init(). * @@ -1001,45 +1079,43 @@ class PersistentRooted : public js::PersistentRootedBase, private mozilla::LinkedListElement> { - typedef mozilla::LinkedListElement> ListBase; + using ListBase = mozilla::LinkedListElement>; friend class mozilla::LinkedList; friend class mozilla::LinkedListElement; - friend struct js::gc::PersistentRootedMarker; - - friend void js::gc::FinishPersistentRootedChains(js::RootLists&); - void registerWithRootLists(js::RootLists& roots) { MOZ_ASSERT(!initialized()); - js::ThingRootKind kind = js::RootKind::rootKind(); + JS::RootKind kind = JS::MapTypeToRootKind::kind; roots.heapRoots_[kind].insertBack(reinterpret_cast*>(this)); - // Until marking and destruction support the full set, we assert that - // we don't try to add any unsupported types. - MOZ_ASSERT(kind == js::THING_ROOT_OBJECT || - kind == js::THING_ROOT_SCRIPT || - kind == js::THING_ROOT_STRING || - kind == js::THING_ROOT_SYMBOL || - kind == js::THING_ROOT_ID || - kind == js::THING_ROOT_VALUE || - kind == js::THING_ROOT_TRACEABLE); } + js::RootLists& rootLists(JSContext* cx) { + return rootLists(JS::RootingContext::get(cx)); + } + js::RootLists& rootLists(JS::RootingContext* cx) { + MOZ_ASSERT(cx->isJSContext); + return cx->roots; + } + + // Disallow ExclusiveContext*. + js::RootLists& rootLists(js::ContextFriendFields* cx) = delete; + public: - PersistentRooted() : ptr(js::GCMethods::initial()) {} + PersistentRooted() : ptr(GCPolicy::initial()) {} template explicit PersistentRooted(const RootingContext& cx) - : ptr(js::GCMethods::initial()) + : ptr(GCPolicy::initial()) { - registerWithRootLists(js::RootListsForRootingContext(cx)); + registerWithRootLists(rootLists(cx)); } template PersistentRooted(const RootingContext& cx, U&& initial) : ptr(mozilla::Forward(initial)) { - registerWithRootLists(js::RootListsForRootingContext(cx)); + registerWithRootLists(rootLists(cx)); } PersistentRooted(const PersistentRooted& rhs) @@ -1063,18 +1139,18 @@ template void init(const RootingContext& cx) { - init(cx, js::GCMethods::initial()); + init(cx, GCPolicy::initial()); } template void init(const RootingContext& cx, U&& initial) { ptr = mozilla::Forward(initial); - registerWithRootLists(js::RootListsForRootingContext(cx)); + registerWithRootLists(rootLists(cx)); } void reset() { if (initialized()) { - set(js::GCMethods::initial()); + set(GCPolicy::initial()); ListBase::remove(); } } @@ -1097,19 +1173,19 @@ } private: - void set(T value) { + template + void set(U&& value) { MOZ_ASSERT(initialized()); - ptr = value; + ptr = mozilla::Forward(value); } // See the comment above Rooted::ptr. using MaybeWrapped = typename mozilla::Conditional< - mozilla::IsBaseOf::value, + MapTypeToRootKind::kind == JS::RootKind::Traceable, js::DispatchWrapper, T>::Type; - MaybeWrapped ptr; -}; +} JS_HAZ_ROOTED; class JS_PUBLIC_API(ObjectPtr) { @@ -1120,20 +1196,26 @@ explicit ObjectPtr(JSObject* obj) : value(obj) {} + ObjectPtr(const ObjectPtr& other) : value(other.value) {} + + ObjectPtr(ObjectPtr&& other) + : value(other.value) + { + other.value = nullptr; + } + /* Always call finalize before the destructor. */ ~ObjectPtr() { MOZ_ASSERT(!value); } - void finalize(JSRuntime* rt) { - if (IsIncrementalBarrierNeeded(rt)) - IncrementalObjectBarrier(value); - value = nullptr; - } + void finalize(JSRuntime* rt); + void finalize(JSContext* cx); void init(JSObject* obj) { value = obj; } JSObject* get() const { return value; } + JSObject* unbarrieredGet() const { return value.unbarrieredGet(); } - void writeBarrierPre(JSRuntime* rt) { + void writeBarrierPre(JSContext* cx) { IncrementalObjectBarrier(value); } @@ -1150,11 +1232,57 @@ JSObject& operator*() const { return *value; } JSObject* operator->() const { return value; } operator JSObject*() const { return value; } + + explicit operator bool() const { return value.unbarrieredGet(); } + explicit operator bool() { return value.unbarrieredGet(); } }; } /* namespace JS */ namespace js { + +template +class UniquePtrOperations +{ + const UniquePtr& uniquePtr() const { return static_cast(this)->get(); } + + public: + explicit operator bool() const { return !!uniquePtr(); } + T* get() const { return uniquePtr().get(); } + T* operator->() const { return get(); } + T& operator*() const { return *uniquePtr(); } +}; + +template +class MutableUniquePtrOperations : public UniquePtrOperations +{ + UniquePtr& uniquePtr() { return static_cast(this)->get(); } + + public: + MOZ_MUST_USE typename UniquePtr::Pointer release() { return uniquePtr().release(); } + void reset(T* ptr = T()) { uniquePtr().reset(ptr); } +}; + +template +class RootedBase> + : public MutableUniquePtrOperations>, T, D> +{ }; + +template +class MutableHandleBase> + : public MutableUniquePtrOperations>, T, D> +{ }; + +template +class HandleBase> + : public UniquePtrOperations>, T, D> +{ }; + +template +class PersistentRootedBase> + : public MutableUniquePtrOperations>, T, D> +{ }; + namespace gc { template @@ -1163,7 +1291,7 @@ { static_assert(sizeof(T) == sizeof(JS::Heap), "T and Heap must be compatible."); MOZ_ASSERT(v); - mozilla::DebugOnly cell = GCMethods::asGCThingOrNull(*v); + mozilla::DebugOnly cell = BarrierMethods::asGCThingOrNull(*v); MOZ_ASSERT(cell); MOZ_ASSERT(!IsInsideNursery(cell)); JS::Heap* asHeapT = reinterpret_cast*>(v); Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/StructuredClone.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/StructuredClone.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/StructuredClone.h @@ -7,6 +7,10 @@ #ifndef js_StructuredClone_h #define js_StructuredClone_h +#include "mozilla/Attributes.h" +#include "mozilla/BufferList.h" +#include "mozilla/Move.h" + #include #include "jstypes.h" @@ -22,6 +26,41 @@ // API for the HTML5 internal structured cloning algorithm. namespace JS { + +enum class StructuredCloneScope : uint32_t { + SameProcessSameThread, + SameProcessDifferentThread, + + /** + * When writing, this means we're writing for an audience in a different + * process. Produce serialized data that can be sent to other processes, + * bitwise copied, or even stored as bytes in a database and read by later + * versions of Firefox years from now. The HTML5 spec refers to this as + * "ForStorage" as in StructuredSerializeForStorage, though we use + * DifferentProcess for IPC as well as storage. + * + * Transferable objects are limited to ArrayBuffers, whose contents are + * copied into the serialized data (rather than just writing a pointer). + */ + DifferentProcess, + + /** + * Handle a backwards-compatibility case with IndexedDB (bug 1434308): when + * reading, this means to treat legacy SameProcessSameThread data as if it + * were DifferentProcess. + * + * Do not use this for writing; use DifferentProcess instead. + */ + DifferentProcessForIndexedDB, + + /** + * Existing code wants to be able to create an uninitialized + * JSStructuredCloneData without knowing the scope, then populate it with + * data (at which point the scope *is* known.) + */ + Unassigned +}; + enum TransferableOwnership { /** Transferable data has not been filled in yet */ SCTAG_TMO_UNFILLED = 0, @@ -35,23 +74,54 @@ /** Data is a pointer that can be freed */ SCTAG_TMO_ALLOC_DATA = 2, - /** Data is a SharedArrayBufferObject's buffer */ - SCTAG_TMO_SHARED_BUFFER = 3, - /** Data is a memory mapped pointer */ - SCTAG_TMO_MAPPED_DATA = 4, + SCTAG_TMO_MAPPED_DATA = 3, /** * Data is embedding-specific. The engine can free it by calling the * freeTransfer op. The embedding can also use SCTAG_TMO_USER_MIN and * greater, up to 32 bits, to distinguish specific ownership variants. */ - SCTAG_TMO_CUSTOM = 5, + SCTAG_TMO_CUSTOM = 4, SCTAG_TMO_USER_MIN }; + +class CloneDataPolicy +{ + bool sharedArrayBuffer_; + + public: + // The default is to allow all policy-controlled aspects. + + CloneDataPolicy() : + sharedArrayBuffer_(true) + {} + + // In the JS engine, SharedArrayBuffers can only be cloned intra-process + // because the shared memory areas are allocated in process-private memory. + // Clients should therefore deny SharedArrayBuffers when cloning data that + // are to be transmitted inter-process. + // + // Clients should also deny SharedArrayBuffers when cloning data that are to + // be transmitted intra-process if policy needs dictate such denial. + + CloneDataPolicy& denySharedArrayBuffer() { + sharedArrayBuffer_ = false; + return *this; + } + + bool isSharedArrayBufferAllowed() const { + return sharedArrayBuffer_; + } +}; + } /* namespace JS */ +namespace js { +template struct BufferIterator; +} + /** * Read structured data from the reader r. This hook is used to read a value * previously serialized by a call to the WriteStructuredCloneOp hook. @@ -123,9 +193,9 @@ uint64_t* extraData); /** - * Called when JS_ClearStructuredClone has to free an unknown transferable - * object. Note that it should never trigger a garbage collection (and will - * assert in a debug build if it does.) + * Called when freeing an unknown transferable object. Note that it + * should never trigger a garbage collection (and will assert in a + * debug build if it does.) */ typedef void (*FreeTransferStructuredCloneOp)(uint32_t tag, JS::TransferableOwnership ownership, void* content, uint64_t extraData, void* closure); @@ -134,7 +204,7 @@ // Increment this when anything at all changes in the serialization format. // (Note that this does not need to be bumped for Transferable-only changes, // since they are never saved to persistent storage.) -#define JS_STRUCTURED_CLONE_VERSION 6 +#define JS_STRUCTURED_CLONE_VERSION 8 struct JSStructuredCloneCallbacks { ReadStructuredCloneOp read; @@ -145,97 +215,239 @@ FreeTransferStructuredCloneOp freeTransfer; }; +enum OwnTransferablePolicy { + OwnsTransferablesIfAny, + IgnoreTransferablesIfAny, + NoTransferables +}; + +/** + * JSStructuredCloneData represents structured clone data together with the + * information needed to read/write/transfer/free the records within it, in the + * form of a set of callbacks. + */ +class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(JSStructuredCloneData) { + public: + using BufferList = mozilla::BufferList; + using Iterator = BufferList::IterImpl; + + private: + static const size_t kStandardCapacity = 4096; + + BufferList bufList_; + + // The (address space, thread) scope within which this clone is valid. Note + // that this must be either set during construction, or start out as + // Unassigned and transition once to something else. + JS::StructuredCloneScope scope_; + + const JSStructuredCloneCallbacks* callbacks_; + void* closure_; + OwnTransferablePolicy ownTransferables_; + + friend struct JSStructuredCloneWriter; + friend class JS_PUBLIC_API(JSAutoStructuredCloneBuffer); + template friend struct js::BufferIterator; + + public: + // The constructor must be infallible but SystemAllocPolicy is not, so both + // the initial size and initial capacity of the BufferList must be zero. + explicit JSStructuredCloneData(JS::StructuredCloneScope aScope) + : bufList_(0, 0, kStandardCapacity, js::SystemAllocPolicy()) + , scope_(aScope) + , callbacks_(nullptr) + , closure_(nullptr) + , ownTransferables_(OwnTransferablePolicy::NoTransferables) + {} + + // Steal the raw data from a BufferList. In this case, we don't know the + // scope and none of the callback info is assigned yet. + JSStructuredCloneData(BufferList&& buffers, JS::StructuredCloneScope aScope) + : bufList_(mozilla::Move(buffers)) + , scope_(aScope) + , callbacks_(nullptr) + , closure_(nullptr) + , ownTransferables_(OwnTransferablePolicy::NoTransferables) + {} + MOZ_IMPLICIT JSStructuredCloneData(BufferList&& buffers) + : JSStructuredCloneData(mozilla::Move(buffers), JS::StructuredCloneScope::Unassigned) + {} + JSStructuredCloneData(JSStructuredCloneData&& other) = default; + JSStructuredCloneData& operator=(JSStructuredCloneData&& other) = default; + ~JSStructuredCloneData() { discardTransferables(); } + + void setCallbacks(const JSStructuredCloneCallbacks* callbacks, + void* closure, + OwnTransferablePolicy policy) + { + callbacks_ = callbacks; + closure_ = closure; + ownTransferables_ = policy; + } + + JS::StructuredCloneScope scope() const { return scope_; } + + void initScope(JS::StructuredCloneScope aScope) { + MOZ_ASSERT(Size() == 0, "initScope() of nonempty JSStructuredCloneData"); + if (scope_ != JS::StructuredCloneScope::Unassigned) + MOZ_ASSERT(scope_ == aScope, "Cannot change scope after it has been initialized"); + scope_ = aScope; + } + + size_t Size() const { return bufList_.Size(); } + + const Iterator Start() const { return bufList_.Iter(); } + + bool Advance(Iterator& iter, size_t distance) const { + return iter.AdvanceAcrossSegments(bufList_, distance); + } + + bool ReadBytes(Iterator& iter, char* buffer, size_t size) const { + return bufList_.ReadBytes(iter, buffer, size); + } + + // Append new data to the end of the buffer. + bool AppendBytes(const char* data, size_t size) { + MOZ_ASSERT(scope_ != JS::StructuredCloneScope::Unassigned); + return bufList_.WriteBytes(data, size); + } + + // Update data stored within the existing buffer. There must be at least + // 'size' bytes between the position of 'iter' and the end of the buffer. + bool UpdateBytes(Iterator& iter, const char* data, size_t size) const { + MOZ_ASSERT(scope_ != JS::StructuredCloneScope::Unassigned); + while (size > 0) { + size_t remaining = iter.RemainingInSegment(); + size_t nbytes = std::min(remaining, size); + memcpy(iter.Data(), data, nbytes); + data += nbytes; + size -= nbytes; + iter.Advance(bufList_, nbytes); + } + return true; + } + + void Clear() { + discardTransferables(); + bufList_.Clear(); + } + + // Return a new read-only JSStructuredCloneData that "borrows" the contents + // of |this|. Its lifetime should not exceed the donor's. This is only + // allowed for DifferentProcess clones, so finalization of the borrowing + // clone will do nothing. + JSStructuredCloneData Borrow(Iterator& iter, size_t size, bool* success) const + { + MOZ_ASSERT(scope_ == JS::StructuredCloneScope::DifferentProcess); + return JSStructuredCloneData(bufList_.Borrow(iter, size, success), + scope_); + } + + // Iterate over all contained data, one BufferList segment's worth at a + // time, and invoke the given FunctionToApply with the data pointer and + // size. The function should return a bool value, and this loop will exit + // with false if the function ever returns false. + template + bool ForEachDataChunk(FunctionToApply&& function) const { + Iterator iter = bufList_.Iter(); + while (!iter.Done()) { + if (!function(iter.Data(), iter.RemainingInSegment())) + return false; + iter.Advance(bufList_, iter.RemainingInSegment()); + } + return true; + } + + // Append the entire contents of other's bufList_ to our own. + bool Append(const JSStructuredCloneData& other) { + MOZ_ASSERT(scope_ == other.scope_); + return other.ForEachDataChunk([&](const char* data, size_t size) { + return AppendBytes(data, size); + }); + } + + void discardTransferables(); +}; + /** Note: if the *data contains transferable objects, it can be read only once. */ JS_PUBLIC_API(bool) -JS_ReadStructuredClone(JSContext* cx, uint64_t* data, size_t nbytes, uint32_t version, +JS_ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data, uint32_t version, + JS::StructuredCloneScope scope, JS::MutableHandleValue vp, const JSStructuredCloneCallbacks* optionalCallbacks, void* closure); -/** - * Note: On success, the caller is responsible for calling - * JS_ClearStructuredClone(*datap, nbytes, optionalCallbacks, closure). - */ JS_PUBLIC_API(bool) -JS_WriteStructuredClone(JSContext* cx, JS::HandleValue v, uint64_t** datap, size_t* nbytesp, +JS_WriteStructuredClone(JSContext* cx, JS::HandleValue v, JSStructuredCloneData* data, + JS::StructuredCloneScope scope, + JS::CloneDataPolicy cloneDataPolicy, const JSStructuredCloneCallbacks* optionalCallbacks, void* closure, JS::HandleValue transferable); JS_PUBLIC_API(bool) -JS_ClearStructuredClone(uint64_t* data, size_t nbytes, - const JSStructuredCloneCallbacks* optionalCallbacks, - void *closure, bool freeData = true); - -JS_PUBLIC_API(bool) -JS_StructuredCloneHasTransferables(const uint64_t* data, size_t nbytes, bool* hasTransferable); +JS_StructuredCloneHasTransferables(JSStructuredCloneData& data, bool* hasTransferable); JS_PUBLIC_API(bool) JS_StructuredClone(JSContext* cx, JS::HandleValue v, JS::MutableHandleValue vp, const JSStructuredCloneCallbacks* optionalCallbacks, void* closure); -/** RAII sugar for JS_WriteStructuredClone. */ +/** + * The C-style API calls to read and write structured clones are fragile -- + * they rely on the caller to properly handle ownership of the clone data, and + * the handling of the input data as well as the interpretation of the contents + * of the clone buffer are dependent on the callbacks passed in. If you + * serialize and deserialize with different callbacks, the results are + * questionable. + * + * JSAutoStructuredCloneBuffer wraps things up in an RAII class for data + * management, and uses the same callbacks for both writing and reading + * (serializing and deserializing). + */ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) { - uint64_t* data_; - size_t nbytes_; + const JS::StructuredCloneScope scope_; + JSStructuredCloneData data_; uint32_t version_; - enum { - OwnsTransferablesIfAny, - IgnoreTransferablesIfAny, - NoTransferables - } ownTransferables_; - - const JSStructuredCloneCallbacks* callbacks_; - void* closure_; public: - JSAutoStructuredCloneBuffer() - : data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION), - ownTransferables_(NoTransferables), - callbacks_(nullptr), closure_(nullptr) - {} - - JSAutoStructuredCloneBuffer(const JSStructuredCloneCallbacks* callbacks, void* closure) - : data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION), - ownTransferables_(NoTransferables), - callbacks_(callbacks), closure_(closure) - {} + JSAutoStructuredCloneBuffer(JS::StructuredCloneScope aScope, + const JSStructuredCloneCallbacks* callbacks, void* closure) + : scope_(aScope), data_(aScope), version_(JS_STRUCTURED_CLONE_VERSION) + { + data_.setCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables); + } JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other); JSAutoStructuredCloneBuffer& operator=(JSAutoStructuredCloneBuffer&& other); ~JSAutoStructuredCloneBuffer() { clear(); } - uint64_t* data() const { return data_; } - size_t nbytes() const { return nbytes_; } + JSStructuredCloneData& data() { return data_; } + bool empty() const { return !data_.Size(); } - void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr); + void clear(); - /** Copy some memory. It will be automatically freed by the destructor. */ - bool copy(const uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION, - const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr); + JS::StructuredCloneScope scope() const { return scope_; } /** * Adopt some memory. It will be automatically freed by the destructor. * data must have been allocated by the JS engine (e.g., extracted via * JSAutoStructuredCloneBuffer::steal). */ - void adopt(uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION, + void adopt(JSStructuredCloneData&& data, uint32_t version=JS_STRUCTURED_CLONE_VERSION, const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr); /** - * Release the buffer and transfer ownership to the caller. The caller is - * responsible for calling JS_ClearStructuredClone or feeding the memory - * back to JSAutoStructuredCloneBuffer::adopt. + * Release the buffer and transfer ownership to the caller. */ - void steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp=nullptr, + void steal(JSStructuredCloneData* data, uint32_t* versionp=nullptr, const JSStructuredCloneCallbacks** callbacks=nullptr, void** closure=nullptr); /** * Abandon ownership of any transferable objects stored in the buffer, * without freeing the buffer itself. Useful when copying the data out into - * an external container, though note that you will need to use adopt() or - * JS_ClearStructuredClone to properly release that data eventually. + * an external container, though note that you will need to use adopt() to + * properly release that data eventually. */ - void abandon() { ownTransferables_ = IgnoreTransferablesIfAny; } + void abandon() { data_.ownTransferables_ = OwnTransferablePolicy::IgnoreTransferablesIfAny; } bool read(JSContext* cx, JS::MutableHandleValue vp, const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr); @@ -244,6 +456,7 @@ const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr); bool write(JSContext* cx, JS::HandleValue v, JS::HandleValue transferable, + JS::CloneDataPolicy cloneDataPolicy, const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr); private: @@ -259,6 +472,7 @@ #define JS_SCERR_RECURSION 0 #define JS_SCERR_TRANSFERABLE 1 #define JS_SCERR_DUP_TRANSFERABLE 2 +#define JS_SCERR_UNSUPPORTED_TYPE 3 JS_PUBLIC_API(bool) JS_ReadUint32Pair(JSStructuredCloneReader* r, uint32_t* p1, uint32_t* p2); @@ -281,4 +495,10 @@ JS_PUBLIC_API(bool) JS_WriteTypedArray(JSStructuredCloneWriter* w, JS::HandleValue v); +JS_PUBLIC_API(bool) +JS_ObjectNotWritten(JSStructuredCloneWriter* w, JS::HandleObject obj); + +JS_PUBLIC_API(JS::StructuredCloneScope) +JS_GetStructuredCloneScope(JSStructuredCloneWriter* w); + #endif /* js_StructuredClone_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/SweepingAPI.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/SweepingAPI.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/SweepingAPI.h @@ -0,0 +1,65 @@ +/* -*- 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_SweepingAPI_h +#define js_SweepingAPI_h + +#include "js/HeapAPI.h" + +namespace js { +template +class WeakCacheBase {}; +} // namespace js + +namespace JS { +template class WeakCache; + +namespace shadow { +JS_PUBLIC_API(void) +RegisterWeakCache(JS::Zone* zone, JS::WeakCache* cachep); +} // namespace shadow + +// A WeakCache stores the given Sweepable container and links itself into a +// list of such caches that are swept during each GC. +template +class WeakCache : public js::WeakCacheBase, + private mozilla::LinkedListElement> +{ + friend class mozilla::LinkedListElement>; + friend class mozilla::LinkedList>; + + WeakCache() = delete; + WeakCache(const WeakCache&) = delete; + + using SweepFn = void (*)(T*); + SweepFn sweeper; + T cache; + + public: + using Type = T; + + template + WeakCache(Zone* zone, U&& initial) + : cache(mozilla::Forward(initial)) + { + sweeper = GCPolicy::sweep; + shadow::RegisterWeakCache(zone, reinterpret_cast*>(this)); + } + WeakCache(WeakCache&& other) + : sweeper(other.sweeper), + cache(mozilla::Move(other.cache)) + { + } + + const T& get() const { return cache; } + T& get() { return cache; } + + void sweep() { sweeper(&cache); } +}; + +} // namespace JS + +#endif // js_SweepingAPI_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/TraceKind.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/TraceKind.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/TraceKind.h @@ -7,6 +7,8 @@ #ifndef js_TraceKind_h #define js_TraceKind_h +#include "mozilla/UniquePtr.h" + #include "js/TypeDecls.h" // Forward declarations of all the types a TraceKind can denote. @@ -15,6 +17,7 @@ class LazyScript; class ObjectGroup; class Shape; +class Scope; namespace jit { class JitCode; } // namespace jit @@ -53,18 +56,31 @@ // The following kinds do not have an exposed C++ idiom. BaseShape = 0x0F, JitCode = 0x1F, - LazyScript = 0x2F + LazyScript = 0x2F, + Scope = 0x3F }; const static uintptr_t OutOfLineTraceKindMask = 0x07; static_assert(uintptr_t(JS::TraceKind::BaseShape) & OutOfLineTraceKindMask, "mask bits are set"); static_assert(uintptr_t(JS::TraceKind::JitCode) & OutOfLineTraceKindMask, "mask bits are set"); static_assert(uintptr_t(JS::TraceKind::LazyScript) & OutOfLineTraceKindMask, "mask bits are set"); +static_assert(uintptr_t(JS::TraceKind::Scope) & OutOfLineTraceKindMask, "mask bits are set"); + +// When this header is imported inside SpiderMonkey, the class definitions are +// available and we can query those definitions to find the correct kind +// directly from the class hierarchy. +template +struct MapTypeToTraceKind { + static const JS::TraceKind kind = T::TraceKind; +}; +// When this header is used outside SpiderMonkey, the class definitions are not +// available, so the following table containing all public GC types is used. #define JS_FOR_EACH_TRACEKIND(D) \ /* PrettyName TypeName AddToCCKind */ \ D(BaseShape, js::BaseShape, true) \ D(JitCode, js::jit::JitCode, true) \ D(LazyScript, js::LazyScript, true) \ + D(Scope, js::Scope, true) \ D(Object, JSObject, true) \ D(ObjectGroup, js::ObjectGroup, true) \ D(Script, JSScript, true) \ @@ -72,8 +88,7 @@ D(String, JSString, false) \ D(Symbol, JS::Symbol, false) -// Map from base trace type to the trace kind. -template struct MapTypeToTraceKind {}; +// Map from all public types to their trace kind. #define JS_EXPAND_DEF(name, type, _) \ template <> struct MapTypeToTraceKind { \ static const JS::TraceKind kind = JS::TraceKind::name; \ @@ -81,6 +96,60 @@ JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); #undef JS_EXPAND_DEF +// RootKind is closely related to TraceKind. Whereas TraceKind's indices are +// laid out for convenient embedding as a pointer tag, the indicies of RootKind +// are designed for use as array keys via EnumeratedArray. +enum class RootKind : int8_t +{ + // These map 1:1 with trace kinds. +#define EXPAND_ROOT_KIND(name, _0, _1) \ + name, +JS_FOR_EACH_TRACEKIND(EXPAND_ROOT_KIND) +#undef EXPAND_ROOT_KIND + + // These tagged pointers are special-cased for performance. + Id, + Value, + + // Everything else. + Traceable, + + Limit +}; + +// Most RootKind correspond directly to a trace kind. +template struct MapTraceKindToRootKind {}; +#define JS_EXPAND_DEF(name, _0, _1) \ + template <> struct MapTraceKindToRootKind { \ + static const JS::RootKind kind = JS::RootKind::name; \ + }; +JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF) +#undef JS_EXPAND_DEF + +// Specify the RootKind for all types. Value and jsid map to special cases; +// pointer types we can derive directly from the TraceKind; everything else +// should go in the Traceable list and use GCPolicy::trace for tracing. +template +struct MapTypeToRootKind { + static const JS::RootKind kind = JS::RootKind::Traceable; +}; +template +struct MapTypeToRootKind { + static const JS::RootKind kind = + JS::MapTraceKindToRootKind::kind>::kind; +}; +template +struct MapTypeToRootKind> { + static const JS::RootKind kind = JS::MapTypeToRootKind::kind; +}; +template <> struct MapTypeToRootKind { + static const JS::RootKind kind = JS::RootKind::Value; +}; +template <> struct MapTypeToRootKind { + static const JS::RootKind kind = JS::RootKind::Id; +}; +template <> struct MapTypeToRootKind : public MapTypeToRootKind {}; + // Fortunately, few places in the system need to deal with fully abstract // cells. In those places that do, we generally want to move to a layout // templated function as soon as possible. This template wraps the upcast Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/TraceableVector.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/TraceableVector.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/TraceableVector.h @@ -1,239 +0,0 @@ -/* -*- 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_TraceableVector_h -#define js_TraceableVector_h - -#include "mozilla/Vector.h" - -#include "js/RootingAPI.h" -#include "js/TracingAPI.h" -#include "js/Vector.h" - -namespace js { - -// A TraceableVector is a Vector with an additional trace method that knows how -// to visit all of the items stored in the Vector. For vectors that contain GC -// things, this is usually more convenient than manually iterating and marking -// the contents. -// -// Most types of GC pointers as keys and values can be traced with no extra -// infrastructure. For structs and non-gc-pointer members, ensure that there -// is a specialization of DefaultGCPolicy with an appropriate trace method -// available to handle the custom type. Generic helpers can be found in -// js/public/TracingAPI.h. -// -// Note that although this Vector's trace will deal correctly with moved items, -// it does not itself know when to barrier or trace items. To function properly -// it must either be used with Rooted, or barriered and traced manually. -template > -class TraceableVector : public JS::Traceable -{ - mozilla::Vector vector; - - public: - explicit TraceableVector(AllocPolicy alloc = AllocPolicy()) - : vector(alloc) - {} - - TraceableVector(TraceableVector&& vec) - : vector(mozilla::Move(vec.vector)) - {} - - TraceableVector& operator=(TraceableVector&& vec) { - vector = mozilla::Move(vec.vector); - return *this; - } - - size_t length() const { return vector.length(); } - bool empty() const { return vector.empty(); } - size_t capacity() const { return vector.capacity(); } - - T* begin() { return vector.begin(); } - const T* begin() const { return vector.begin(); } - - T* end() { return vector.end(); } - const T* end() const { return vector.end(); } - - T& operator[](size_t i) { return vector[i]; } - const T& operator[](size_t i) const { return vector[i]; } - - T& back() { return vector.back(); } - const T& back() const { return vector.back(); } - - bool initCapacity(size_t cap) { return vector.initCapacity(cap); } - bool reserve(size_t req) { return vector.reserve(req); } - void shrinkBy(size_t amount) { return vector.shrinkBy(amount); } - bool growBy(size_t amount) { return vector.growBy(amount); } - bool resize(size_t newLen) { return vector.resize(newLen); } - - void clear() { return vector.clear(); } - - template bool append(U&& item) { return vector.append(mozilla::Forward(item)); } - - template - bool - emplaceBack(Args&&... args) { - return vector.emplaceBack(mozilla::Forward(args)...); - } - - template - void infallibleAppend(U&& aU) { - return vector.infallibleAppend(mozilla::Forward(aU)); - } - void infallibleAppendN(const T& aT, size_t aN) { - return vector.infallibleAppendN(aT, aN); - } - template void - infallibleAppend(const U* aBegin, const U* aEnd) { - return vector.infallibleAppend(aBegin, aEnd); - } - template void infallibleAppend(const U* aBegin, size_t aLength) { - return vector.infallibleAppend(aBegin, aLength); - } - - bool appendN(const T& val, size_t count) { return vector.appendN(val, count); } - - template bool append(const U* aBegin, const U* aEnd) { - return vector.append(aBegin, aEnd); - } - template bool append(const U* aBegin, size_t aLength) { - return vector.append(aBegin, aLength); - } - - void popBack() { return vector.popBack(); } - T popCopy() { return vector.popCopy(); } - - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return vector.sizeOfExcludingThis(mallocSizeOf); - } - - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return vector.sizeOfIncludingThis(mallocSizeOf); - } - - static void trace(TraceableVector* vec, JSTracer* trc) { vec->trace(trc); } - - void trace(JSTracer* trc) { - for (auto& elem : vector) - GCPolicy::trace(trc, &elem, "vector element"); - } -}; - -template -class TraceableVectorOperations -{ - using Vec = TraceableVector; - const Vec& vec() const { return static_cast(this)->get(); } - - public: - const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); } - size_t length() const { return vec().length(); } - bool empty() const { return vec().empty(); } - size_t capacity() const { return vec().capacity(); } - const T* begin() const { return vec().begin(); } - const T* end() const { return vec().end(); } - const T& back() const { return vec().back(); } - bool canAppendWithoutRealloc(size_t aNeeded) const { return vec().canAppendWithoutRealloc(); } - - JS::Handle operator[](size_t aIndex) const { - return JS::Handle::fromMarkedLocation(&vec().operator[](aIndex)); - } -}; - -template -class MutableTraceableVectorOperations - : public TraceableVectorOperations -{ - using Vec = TraceableVector; - const Vec& vec() const { return static_cast(this)->get(); } - Vec& vec() { return static_cast(this)->get(); } - - public: - const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); } - AllocPolicy& allocPolicy() { return vec().allocPolicy(); } - const T* begin() const { return vec().begin(); } - T* begin() { return vec().begin(); } - const T* end() const { return vec().end(); } - T* end() { return vec().end(); } - const T& operator[](size_t aIndex) const { return vec().operator[](aIndex); } - const T& back() const { return vec().back(); } - T& back() { return vec().back(); } - - JS::MutableHandle operator[](size_t aIndex) { - return JS::MutableHandle::fromMarkedLocation(&vec().operator[](aIndex)); - } - - bool initCapacity(size_t aRequest) { return vec().initCapacity(aRequest); } - bool reserve(size_t aRequest) { return vec().reserve(aRequest); } - void shrinkBy(size_t aIncr) { vec().shrinkBy(aIncr); } - bool growBy(size_t aIncr) { return vec().growBy(aIncr); } - bool resize(size_t aNewLength) { return vec().resize(aNewLength); } - bool growByUninitialized(size_t aIncr) { return vec().growByUninitialized(aIncr); } - void infallibleGrowByUninitialized(size_t aIncr) { vec().infallibleGrowByUninitialized(aIncr); } - bool resizeUninitialized(size_t aNewLength) { return vec().resizeUninitialized(aNewLength); } - void clear() { vec().clear(); } - void clearAndFree() { vec().clearAndFree(); } - template bool append(U&& aU) { return vec().append(mozilla::Forward(aU)); } - template bool emplaceBack(Args&&... aArgs) { - return vec().emplaceBack(mozilla::Forward(aArgs...)); - } - template - bool appendAll(const mozilla::Vector& aU) { return vec().appendAll(aU); } - bool appendN(const T& aT, size_t aN) { return vec().appendN(aT, aN); } - template bool append(const U* aBegin, const U* aEnd) { - return vec().append(aBegin, aEnd); - } - template bool append(const U* aBegin, size_t aLength) { - return vec().append(aBegin, aLength); - } - template void infallibleAppend(U&& aU) { - vec().infallibleAppend(mozilla::Forward(aU)); - } - void infallibleAppendN(const T& aT, size_t aN) { vec().infallibleAppendN(aT, aN); } - template void infallibleAppend(const U* aBegin, const U* aEnd) { - vec().infallibleAppend(aBegin, aEnd); - } - template void infallibleAppend(const U* aBegin, size_t aLength) { - vec().infallibleAppend(aBegin, aLength); - } - void popBack() { vec().popBack(); } - T popCopy() { return vec().popCopy(); } - template T* insert(T* aP, U&& aVal) { - return vec().insert(aP, mozilla::Forward(aVal)); - } - void erase(T* aT) { vec().erase(aT); } - void erase(T* aBegin, T* aEnd) { vec().erase(aBegin, aEnd); } -}; - -template -class RootedBase> - : public MutableTraceableVectorOperations>, T,N,AP,GP> -{}; - -template -class MutableHandleBase> - : public MutableTraceableVectorOperations>, - T,N,AP,GP> -{}; - -template -class HandleBase> - : public TraceableVectorOperations>, T,N,AP,GP> -{}; - -template -class PersistentRootedBase> - : public MutableTraceableVectorOperations>, - T,N,AP,GP> -{}; - -} // namespace js - -#endif // js_TraceableVector_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/TracingAPI.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/TracingAPI.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/TracingAPI.h @@ -27,13 +27,15 @@ } // namespace JS enum WeakMapTraceKind { - /** Do true ephemeron marking with an iterative weak marking phase. */ + /** + * Do not trace into weak map keys or values during traversal. Users must + * handle weak maps manually. + */ DoNotTraceWeakMaps, /** * Do true ephemeron marking with a weak key lookup marking phase. This is - * expected to be constant for the lifetime of a JSTracer; it does not - * change when switching from "plain" marking to weak marking. + * the default for GCMarker. */ ExpandWeakMaps, @@ -59,11 +61,24 @@ // Return the weak map tracing behavior currently set on this tracer. WeakMapTraceKind weakMapAction() const { return weakMapAction_; } - // An intermediate state on the road from C to C++ style dispatch. enum class TracerKindTag { + // Marking path: a tracer used only for marking liveness of cells, not + // for moving them. The kind will transition to WeakMarking after + // everything reachable by regular edges has been marked. Marking, - WeakMarking, // In weak marking phase: looking up every marked obj/script. + + // Same as Marking, except we have now moved on to the "weak marking + // phase", in which every marked obj/script is immediately looked up to + // see if it is a weak map key (and therefore might require marking its + // weak map value). + WeakMarking, + + // A tracer that traverses the graph for the purposes of moving objects + // from the nursery to the tenured area. Tenuring, + + // General-purpose traversal that invokes a callback on each cell. + // Traversing children is the responsibility of the callback. Callback }; bool isMarkingTracer() const { return tag_ == TracerKindTag::Marking || tag_ == TracerKindTag::WeakMarking; } @@ -71,19 +86,37 @@ bool isTenuringTracer() const { return tag_ == TracerKindTag::Tenuring; } bool isCallbackTracer() const { return tag_ == TracerKindTag::Callback; } inline JS::CallbackTracer* asCallbackTracer(); +#ifdef DEBUG + bool checkEdges() { return checkEdges_; } +#endif protected: JSTracer(JSRuntime* rt, TracerKindTag tag, WeakMapTraceKind weakTraceKind = TraceWeakMapValues) - : runtime_(rt), weakMapAction_(weakTraceKind), tag_(tag) + : runtime_(rt) + , weakMapAction_(weakTraceKind) +#ifdef DEBUG + , checkEdges_(true) +#endif + , tag_(tag) {} +#ifdef DEBUG + // Set whether to check edges are valid in debug builds. + void setCheckEdges(bool check) { + checkEdges_ = check; + } +#endif + private: - JSRuntime* runtime_; - WeakMapTraceKind weakMapAction_; + JSRuntime* runtime_; + WeakMapTraceKind weakMapAction_; +#ifdef DEBUG + bool checkEdges_; +#endif protected: - TracerKindTag tag_; + TracerKindTag tag_; }; namespace JS { @@ -99,6 +132,7 @@ : JSTracer(rt, JSTracer::TracerKindTag::Callback, weakTraceKind), contextName_(nullptr), contextIndex_(InvalidIndex), contextFunctor_(nullptr) {} + CallbackTracer(JSContext* cx, WeakMapTraceKind weakTraceKind = TraceWeakMapValues); // Override these methods to receive notification when an edge is visited // with the type contained in the callback. The default implementation @@ -124,6 +158,9 @@ virtual void onLazyScriptEdge(js::LazyScript** lazyp) { onChild(JS::GCCellPtr(*lazyp, JS::TraceKind::LazyScript)); } + virtual void onScopeEdge(js::Scope** scopep) { + onChild(JS::GCCellPtr(*scopep, JS::TraceKind::Scope)); + } // Override this method to receive notification when a node in the GC // heap graph is visited. @@ -193,6 +230,7 @@ void dispatchToOnEdge(js::BaseShape** basep) { onBaseShapeEdge(basep); } void dispatchToOnEdge(js::jit::JitCode** codep) { onJitCodeEdge(codep); } void dispatchToOnEdge(js::LazyScript** lazyp) { onLazyScriptEdge(lazyp); } + void dispatchToOnEdge(js::Scope** scopep) { onScopeEdge(scopep); } private: friend class AutoTracingName; @@ -281,151 +319,85 @@ return static_cast(this); } -// The JS_Call*Tracer family of functions traces the given GC thing reference. -// This performs the tracing action configured on the given JSTracer: -// typically calling the JSTracer::callback or marking the thing as live. +namespace JS { + +// The JS::TraceEdge family of functions traces the given GC thing reference. +// This performs the tracing action configured on the given JSTracer: typically +// calling the JSTracer::callback or marking the thing as live. // -// The argument to JS_Call*Tracer is an in-out param: when the function -// returns, the garbage collector might have moved the GC thing. In this case, -// the reference passed to JS_Call*Tracer will be updated to the object's new -// location. Callers of this method are responsible for updating any state -// that is dependent on the object's address. For example, if the object's -// address is used as a key in a hashtable, then the object must be removed -// and re-inserted with the correct hash. +// The argument to JS::TraceEdge is an in-out param: when the function returns, +// the garbage collector might have moved the GC thing. In this case, the +// reference passed to JS::TraceEdge will be updated to the thing's new +// location. Callers of this method are responsible for updating any state that +// is dependent on the object's address. For example, if the object's address +// is used as a key in a hashtable, then the object must be removed and +// re-inserted with the correct hash. // -extern JS_PUBLIC_API(void) -JS_CallValueTracer(JSTracer* trc, JS::Heap* valuep, const char* name); - -extern JS_PUBLIC_API(void) -JS_CallIdTracer(JSTracer* trc, JS::Heap* idp, const char* name); - -extern JS_PUBLIC_API(void) -JS_CallObjectTracer(JSTracer* trc, JS::Heap* objp, const char* name); - -extern JS_PUBLIC_API(void) -JS_CallStringTracer(JSTracer* trc, JS::Heap* strp, const char* name); - -extern JS_PUBLIC_API(void) -JS_CallScriptTracer(JSTracer* trc, JS::Heap* scriptp, const char* name); - -extern JS_PUBLIC_API(void) -JS_CallFunctionTracer(JSTracer* trc, JS::Heap* funp, const char* name); - -namespace JS { +// Note that while |edgep| must never be null, it is fine for |*edgep| to be +// nullptr. template extern JS_PUBLIC_API(void) TraceEdge(JSTracer* trc, JS::Heap* edgep, const char* name); -} // namespace JS - -// The following JS_CallUnbarriered*Tracer functions should only be called where -// you know for sure that a heap post barrier is not required. Use with extreme -// caution! -extern JS_PUBLIC_API(void) -JS_CallUnbarrieredValueTracer(JSTracer* trc, JS::Value* valuep, const char* name); extern JS_PUBLIC_API(void) -JS_CallUnbarrieredIdTracer(JSTracer* trc, jsid* idp, const char* name); +TraceEdge(JSTracer* trc, JS::TenuredHeap* edgep, const char* name); +// Edges that are always traced as part of root marking do not require +// incremental barriers. This function allows for marking non-barriered +// pointers, but asserts that this happens during root marking. +// +// Note that while |edgep| must never be null, it is fine for |*edgep| to be +// nullptr. +template extern JS_PUBLIC_API(void) -JS_CallUnbarrieredObjectTracer(JSTracer* trc, JSObject** objp, const char* name); +UnsafeTraceRoot(JSTracer* trc, T* edgep, const char* name); extern JS_PUBLIC_API(void) -JS_CallUnbarrieredStringTracer(JSTracer* trc, JSString** strp, const char* name); +TraceChildren(JSTracer* trc, GCCellPtr thing); -extern JS_PUBLIC_API(void) -JS_CallUnbarrieredScriptTracer(JSTracer* trc, JSScript** scriptp, const char* name); +using ZoneSet = js::HashSet, js::SystemAllocPolicy>; +using CompartmentSet = js::HashSet, + js::SystemAllocPolicy>; /** - * Trace an object that is known to always be tenured. No post barriers are - * required in this case. + * Trace every value within |compartments| that is wrapped by a + * cross-compartment wrapper from a compartment that is not an element of + * |compartments|. */ extern JS_PUBLIC_API(void) -JS_CallTenuredObjectTracer(JSTracer* trc, JS::TenuredHeap* objp, const char* name); +TraceIncomingCCWs(JSTracer* trc, const JS::CompartmentSet& compartments); -extern JS_PUBLIC_API(void) -JS_TraceRuntime(JSTracer* trc); - -namespace JS { -extern JS_PUBLIC_API(void) -TraceChildren(JSTracer* trc, GCCellPtr thing); - -typedef js::HashSet, js::SystemAllocPolicy> ZoneSet; } // namespace JS -/** - * Trace every value within |zones| that is wrapped by a cross-compartment - * wrapper from a zone that is not an element of |zones|. - */ -extern JS_PUBLIC_API(void) -JS_TraceIncomingCCWs(JSTracer* trc, const JS::ZoneSet& zones); - extern JS_PUBLIC_API(void) JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, void* thing, JS::TraceKind kind, bool includeDetails); namespace js { -namespace gc { -template -extern JS_PUBLIC_API(bool) -EdgeNeedsSweep(JS::Heap* edgep); -} // namespace gc -// Automates static dispatch for GC interaction with TraceableContainers. -template -struct DefaultGCPolicy; - -// This policy dispatches GC methods to a method on the type. +// Trace an edge that is not a GC root and is not wrapped in a barriered +// wrapper for some reason. +// +// This method does not check if |*edgep| is non-null before tracing through +// it, so callers must check any nullable pointer before calling this method. template -struct StructGCPolicy { - static void trace(JSTracer* trc, T* t, const char* name) { - // This is the default GC policy for storing GC things in containers. - // If your build is failing here, it means you either need an - // implementation of DefaultGCPolicy for your type or, if this is - // the right policy for you, your struct or container is missing a - // trace method. - t->trace(trc); - } - - static bool needsSweep(T* t) { - return t->needsSweep(); - } -}; +extern JS_PUBLIC_API(void) +UnsafeTraceManuallyBarrieredEdge(JSTracer* trc, T* edgep, const char* name); -// This policy ignores any GC interaction, e.g. for non-GC types. -template -struct IgnoreGCPolicy { - static void trace(JSTracer* trc, T* t, const char* name) {} - static bool needsSweep(T* v) { return false; } -}; +namespace gc { -// The default policy when no other more specific policy fits (e.g. for a -// direct GC pointer), is to assume a struct type that implements the needed -// methods. +// Return true if the given edge is not live and is about to be swept. template -struct DefaultGCPolicy : public StructGCPolicy {}; - -template <> -struct DefaultGCPolicy -{ - static void trace(JSTracer* trc, jsid* id, const char* name) { - JS_CallUnbarrieredIdTracer(trc, id, name); - } -}; - -template <> struct DefaultGCPolicy : public IgnoreGCPolicy {}; -template <> struct DefaultGCPolicy : public IgnoreGCPolicy {}; +extern JS_PUBLIC_API(bool) +EdgeNeedsSweep(JS::Heap* edgep); +// Not part of the public API, but declared here so we can use it in GCPolicy +// which is. template -struct DefaultGCPolicy> -{ - static void trace(JSTracer* trc, JS::Heap* thingp, const char* name) { - JS::TraceEdge(trc, thingp, name); - } - static bool needsSweep(JS::Heap* thingp) { - return gc::EdgeNeedsSweep(thingp); - } -}; +bool +IsAboutToBeFinalizedUnbarriered(T* thingp); +} // namespace gc } // namespace js #endif /* js_TracingAPI_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/TrackedOptimizationInfo.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/TrackedOptimizationInfo.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/TrackedOptimizationInfo.h @@ -16,6 +16,7 @@ _(GetProp_ArgumentsCallee) \ _(GetProp_InferredConstant) \ _(GetProp_Constant) \ + _(GetProp_NotDefined) \ _(GetProp_StaticName) \ _(GetProp_SimdGetter) \ _(GetProp_TypedObject) \ @@ -51,6 +52,12 @@ _(SetElem_Arguments) \ _(SetElem_InlineCache) \ \ + _(BinaryArith_Concat) \ + _(BinaryArith_SpecializedTypes) \ + _(BinaryArith_SpecializedOnBaselineTypes) \ + _(BinaryArith_SharedCache) \ + _(BinaryArith_Call) \ + \ _(InlineCache_OptimizedStub) \ \ _(Call_Inline) @@ -74,6 +81,7 @@ _(NotObject) \ _(NotStruct) \ _(NotUnboxed) \ + _(NotUndefined) \ _(UnboxedConvertedToNative) \ _(StructNoField) \ _(InconsistentFieldType) \ @@ -88,13 +96,17 @@ _(ArrayDoubleConversion) \ _(ArrayRange) \ _(ArraySeenNegativeIndex) \ - _(TypedObjectNeutered) \ + _(TypedObjectHasDetachedBuffer) \ _(TypedObjectArrayRange) \ _(AccessNotDense) \ _(AccessNotSimdObject) \ _(AccessNotTypedObject) \ _(AccessNotTypedArray) \ _(AccessNotString) \ + _(OperandNotString) \ + _(OperandNotNumber) \ + _(OperandNotStringOrNumber) \ + _(OperandNotSimpleArith) \ _(StaticTypedArrayUint32) \ _(StaticTypedArrayCantComputeMask) \ _(OutOfBounds) \ @@ -144,6 +156,7 @@ \ _(ICNameStub_ReadSlot) \ _(ICNameStub_CallGetter) \ + _(ICNameStub_TypeOfNoProperty) \ \ _(CantInlineGeneric) \ _(CantInlineNoTarget) \ @@ -180,6 +193,7 @@ #define TRACKED_TYPESITE_LIST(_) \ _(Receiver) \ + _(Operand) \ _(Index) \ _(Value) \ _(Call_Target) \ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNode.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNode.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNode.h @@ -15,7 +15,6 @@ #include "mozilla/Move.h" #include "mozilla/RangedPtr.h" #include "mozilla/TypeTraits.h" -#include "mozilla/UniquePtr.h" #include "mozilla/Variant.h" #include "jspubtd.h" @@ -25,6 +24,7 @@ #include "js/RootingAPI.h" #include "js/TracingAPI.h" #include "js/TypeDecls.h" +#include "js/UniquePtr.h" #include "js/Value.h" #include "js/Vector.h" @@ -71,7 +71,7 @@ // One can construct a ubi::Node value given a pointer to a type that ubi::Node // supports. In the other direction, one can convert a ubi::Node back to a // pointer; these downcasts are checked dynamically. In particular, one can -// convert a 'JSRuntime*' to a ubi::Node, yielding a node with an outgoing edge +// convert a 'JSContext*' to a ubi::Node, yielding a node with an outgoing edge // for every root registered with the runtime; starting from this, one can walk // the entire heap. (Of course, one could also start traversal at any other kind // of type to which one has a pointer.) @@ -174,16 +174,6 @@ } // namespace ubi } // namespace JS -namespace mozilla { - -template<> -class DefaultDelete : public JS::DeletePolicy { }; - -template<> -class DefaultDelete : public JS::DeletePolicy { }; - -} // namespace mozilla - namespace JS { namespace ubi { @@ -191,9 +181,11 @@ using mozilla::Maybe; using mozilla::Move; using mozilla::RangedPtr; -using mozilla::UniquePtr; using mozilla::Variant; +template +using Vector = mozilla::Vector; + /*** ubi::StackFrame ******************************************************************************/ // Concrete JS::ubi::StackFrame instances backed by a live SavedFrame object @@ -201,7 +193,7 @@ // heap snapshots store their strings as const char16_t*. In order to provide // zero-cost accessors to these strings in a single interface that works with // both cases, we use this variant type. -class AtomOrTwoByteChars : public Variant { +class JS_PUBLIC_API(AtomOrTwoByteChars) : public Variant { using Base = Variant; public: @@ -267,7 +259,7 @@ // Return true if this frame's function is a self-hosted JavaScript builtin, // false otherwise. - virtual bool isSelfHosted() const = 0; + virtual bool isSelfHosted(JSContext* cx) const = 0; // Construct a SavedFrame stack for the stack starting with this frame and // containing all of its parents. The SavedFrame objects will be placed into @@ -294,8 +286,9 @@ // simplifies the principals check into the boolean isSystem() state. This // is fine because we only expose JS::ubi::Stack to devtools and chrome // code, and not to the web platform. - virtual bool constructSavedFrameStack(JSContext* cx, - MutableHandleObject outSavedFrameStack) const = 0; + virtual MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx, + MutableHandleObject outSavedFrameStack) + const = 0; // Trace the concrete implementation of JS::ubi::StackFrame. virtual void trace(JSTracer* trc) = 0; @@ -319,7 +312,7 @@ // valid within the scope of an AutoCheckCannotGC; if the graph being analyzed // is an offline heap snapshot, the JS::ubi::StackFrame is valid as long as the // offline heap snapshot is alive. -class StackFrame : public JS::Traceable { +class StackFrame { // Storage in which we allocate BaseStackFrame subclasses. mozilla::AlignedStorage2 storage; @@ -409,12 +402,6 @@ size_t sourceLength(); size_t functionDisplayNameLength(); - // JS::Traceable implementation just forwards to our virtual trace method. - static void trace(StackFrame* frame, JSTracer* trc) { - if (frame) - frame->trace(trc); - } - // Methods that forward to virtual calls through BaseStackFrame. void trace(JSTracer* trc) { base()->trace(trc); } @@ -429,9 +416,9 @@ AtomOrTwoByteChars functionDisplayName() const { return base()->functionDisplayName(); } StackFrame parent() const { return base()->parent(); } bool isSystem() const { return base()->isSystem(); } - bool isSelfHosted() const { return base()->isSelfHosted(); } - bool constructSavedFrameStack(JSContext* cx, - MutableHandleObject outSavedFrameStack) const { + bool isSelfHosted(JSContext* cx) const { return base()->isSelfHosted(cx); } + MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx, + MutableHandleObject outSavedFrameStack) const { return base()->constructSavedFrameStack(cx, outSavedFrameStack); } @@ -463,7 +450,9 @@ uint64_t identifier() const override { return 0; } void trace(JSTracer* trc) override { } - bool constructSavedFrameStack(JSContext* cx, MutableHandleObject out) const override { + MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx, MutableHandleObject out) + const override + { out.set(nullptr); return true; } @@ -474,11 +463,13 @@ AtomOrTwoByteChars functionDisplayName() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } StackFrame parent() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } bool isSystem() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } - bool isSelfHosted() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } + bool isSelfHosted(JSContext* cx) const override { MOZ_CRASH("null JS::ubi::StackFrame"); } }; -bool ConstructSavedFrameStackSlow(JSContext* cx, JS::ubi::StackFrame& frame, - MutableHandleObject outSavedFrameStack); +MOZ_MUST_USE JS_PUBLIC_API(bool) +ConstructSavedFrameStackSlow(JSContext* cx, + JS::ubi::StackFrame& frame, + MutableHandleObject outSavedFrameStack); /*** ubi::Node ************************************************************************************/ @@ -529,7 +520,7 @@ // The base class implemented by each ubi::Node referent type. Subclasses must // not add data members to this class. -class Base { +class JS_PUBLIC_API(Base) { friend class Node; // For performance's sake, we'd prefer to avoid a virtual destructor; and @@ -579,7 +570,7 @@ virtual CoarseType coarseType() const { return CoarseType::Other; } // Return a human-readable name for the referent's type. The result should - // be statically allocated. (You can use MOZ_UTF16("strings") for this.) + // be statically allocated. (You can use u"strings" for this.) // // This must always return Concrete::concreteTypeName; we use that // pointer as a tag for this particular referent type. @@ -589,6 +580,11 @@ // node owns exclusively that are not exposed as their own ubi::Nodes. // |mallocSizeOf| should be a malloc block sizing function; see // |mfbt/MemoryReporting.h|. + // + // Because we can use |JS::ubi::Node|s backed by a snapshot that was taken + // on a 64-bit platform when we are currently on a 32-bit platform, we + // cannot rely on |size_t| for node sizes. Instead, |Size| is uint64_t on + // all platforms. using Size = uint64_t; virtual Size size(mozilla::MallocSizeOf mallocSizeof) const { return 1; } @@ -597,7 +593,7 @@ // // If wantNames is true, compute names for edges. Doing so can be expensive // in time and memory. - virtual UniquePtr edges(JSRuntime* rt, bool wantNames) const = 0; + virtual js::UniquePtr edges(JSContext* cx, bool wantNames) const = 0; // Return the Zone to which this node's referent belongs, or nullptr if the // referent is not of a type allocated in SpiderMonkey Zones. @@ -633,8 +629,9 @@ // Otherwise, place nullptr in the out parameter. Caller maintains ownership // of the out parameter. True is returned on success, false is returned on // OOM. - virtual bool jsObjectConstructorName(JSContext* cx, - UniquePtr& outName) const { + virtual MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) + const + { outName.reset(nullptr); return true; } @@ -651,28 +648,28 @@ }; // A traits template with a specialization for each referent type that -// ubi::Node supports. The specialization must be the concrete subclass of -// Base that represents a pointer to the referent type. It must also -// include the members described here. +// ubi::Node supports. The specialization must be the concrete subclass of Base +// that represents a pointer to the referent type. It must include these +// members: +// +// // The specific char16_t array returned by Concrete::typeName(). +// static const char16_t concreteTypeName[]; +// +// // Construct an instance of this concrete class in |storage| referring +// // to |referent|. Implementations typically use a placement 'new'. +// // +// // In some cases, |referent| will contain dynamic type information that +// // identifies it a some more specific subclass of |Referent|. For +// // example, when |Referent| is |JSObject|, then |referent->getClass()| +// // could tell us that it's actually a JSFunction. Similarly, if +// // |Referent| is |nsISupports|, we would like a ubi::Node that knows its +// // final implementation type. +// // +// // So we delegate the actual construction to this specialization, which +// // knows Referent's details. +// static void construct(void* storage, Referent* referent); template -struct Concrete { - // The specific char16_t array returned by Concrete::typeName. - static const char16_t concreteTypeName[]; - - // Construct an instance of this concrete class in |storage| referring - // to |referent|. Implementations typically use a placement 'new'. - // - // In some cases, |referent| will contain dynamic type information that - // identifies it a some more specific subclass of |Referent|. For example, - // when |Referent| is |JSObject|, then |referent->getClass()| could tell us - // that it's actually a JSFunction. Similarly, if |Referent| is - // |nsISupports|, we would like a ubi::Node that knows its final - // implementation type. - // - // So, we delegate the actual construction to this specialization, which - // knows Referent's details. - static void construct(void* storage, Referent* referent); -}; +class Concrete; // A container for a Base instance; all members simply forward to the contained // instance. This container allows us to pass ubi::Node instances by value. @@ -686,6 +683,8 @@ void construct(T* ptr) { static_assert(sizeof(Concrete) == sizeof(*base()), "ubi::Base specializations must be the same size as ubi::Base"); + static_assert(mozilla::IsBaseOf>::value, + "ubi::Concrete must inherit from ubi::Base"); Concrete::construct(base(), ptr); } struct ConstructFunctor; @@ -780,8 +779,7 @@ JS::Zone* zone() const { return base()->zone(); } JSCompartment* compartment() const { return base()->compartment(); } const char* jsObjectClassName() const { return base()->jsObjectClassName(); } - bool jsObjectConstructorName(JSContext* cx, - UniquePtr& outName) const { + MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) const { return base()->jsObjectConstructorName(cx, outName); } @@ -796,8 +794,8 @@ return size; } - UniquePtr edges(JSRuntime* rt, bool wantNames = true) const { - return base()->edges(rt, wantNames); + js::UniquePtr edges(JSContext* cx, bool wantNames = true) const { + return base()->edges(cx, wantNames); } bool hasAllocationStack() const { return base()->hasAllocationStack(); } @@ -827,10 +825,12 @@ }; }; +using NodeSet = js::HashSet, js::SystemAllocPolicy>; +using NodeSetPtr = mozilla::UniquePtr>; /*** Edge and EdgeRange ***************************************************************************/ -using EdgeName = UniquePtr; +using EdgeName = UniqueTwoByteChars; // An outgoing edge to a referent node. class Edge { @@ -863,7 +863,8 @@ // false as the wantNames parameter. // // The storage is owned by this Edge, and will be freed when this Edge is - // destructed. + // destructed. You may take ownership of the name by `mozilla::Move`ing it + // out of the edge; it is just a UniquePtr. // // (In real life we'll want a better representation for names, to avoid // creating tons of strings when the names follow a pattern; and we'll need @@ -959,7 +960,7 @@ // // { // mozilla::Maybe maybeNoGC; -// JS::ubi::RootList rootList(rt, maybeNoGC); +// JS::ubi::RootList rootList(cx, maybeNoGC); // if (!rootList.init()) // return false; // @@ -970,22 +971,23 @@ // // ... // } -class MOZ_STACK_CLASS RootList { +class MOZ_STACK_CLASS JS_PUBLIC_API(RootList) { Maybe& noGC; public: - JSRuntime* rt; + JSContext* cx; EdgeVector edges; bool wantNames; - RootList(JSRuntime* rt, Maybe& noGC, bool wantNames = false); + RootList(JSContext* cx, Maybe& noGC, bool wantNames = false); // Find all GC roots. - bool init(); - // Find only GC roots in the provided set of |Zone|s. - bool init(ZoneSet& debuggees); - // Find only GC roots in the given Debugger object's set of debuggee zones. - bool init(HandleObject debuggees); + MOZ_MUST_USE bool init(); + // Find only GC roots in the provided set of |JSCompartment|s. + MOZ_MUST_USE bool init(CompartmentSet& debuggees); + // Find only GC roots in the given Debugger object's set of debuggee + // compartments. + MOZ_MUST_USE bool init(HandleObject debuggees); // Returns true if the RootList has been initialized successfully, false // otherwise. @@ -994,64 +996,53 @@ // Explicitly add the given Node as a root in this RootList. If wantNames is // true, you must pass an edgeName. The RootList does not take ownership of // edgeName. - bool addRoot(Node node, const char16_t* edgeName = nullptr); + MOZ_MUST_USE bool addRoot(Node node, const char16_t* edgeName = nullptr); }; /*** Concrete classes for ubi::Node referent types ************************************************/ template<> -struct Concrete : public Base { - UniquePtr edges(JSRuntime* rt, bool wantNames) const override; - const char16_t* typeName() const override { return concreteTypeName; } - +class JS_PUBLIC_API(Concrete) : public Base { protected: explicit Concrete(RootList* ptr) : Base(ptr) { } RootList& get() const { return *static_cast(ptr); } public: - static const char16_t concreteTypeName[]; static void construct(void* storage, RootList* ptr) { new (storage) Concrete(ptr); } + + js::UniquePtr edges(JSContext* cx, bool wantNames) const override; + + const char16_t* typeName() const override { return concreteTypeName; } + static const char16_t concreteTypeName[]; }; // A reusable ubi::Concrete specialization base class for types supported by // JS::TraceChildren. template -class TracerConcrete : public Base { - const char16_t* typeName() const override { return concreteTypeName; } - UniquePtr edges(JSRuntime* rt, bool wantNames) const override; +class JS_PUBLIC_API(TracerConcrete) : public Base { + js::UniquePtr edges(JSContext* cx, bool wantNames) const override; JS::Zone* zone() const override; protected: explicit TracerConcrete(Referent* ptr) : Base(ptr) { } Referent& get() const { return *static_cast(ptr); } - - public: - static const char16_t concreteTypeName[]; - static void construct(void* storage, Referent* ptr) { new (storage) TracerConcrete(ptr); } }; // For JS::TraceChildren-based types that have a 'compartment' method. template -class TracerConcreteWithCompartment : public TracerConcrete { +class JS_PUBLIC_API(TracerConcreteWithCompartment) : public TracerConcrete { typedef TracerConcrete TracerBase; JSCompartment* compartment() const override; protected: explicit TracerConcreteWithCompartment(Referent* ptr) : TracerBase(ptr) { } - - public: - static void construct(void* storage, Referent* ptr) { - new (storage) TracerConcreteWithCompartment(ptr); - } }; // Define specializations for some commonly-used public JSAPI types. // These can use the generic templates above. template<> -struct Concrete : TracerConcrete { - Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - +class JS_PUBLIC_API(Concrete) : TracerConcrete { protected: explicit Concrete(JS::Symbol* ptr) : TracerConcrete(ptr) { } @@ -1059,33 +1050,32 @@ static void construct(void* storage, JS::Symbol* ptr) { new (storage) Concrete(ptr); } -}; -template<> struct Concrete : TracerConcreteWithCompartment { - CoarseType coarseType() const final { return CoarseType::Script; } Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - const char* scriptFilename() const final; + const char16_t* typeName() const override { return concreteTypeName; } + static const char16_t concreteTypeName[]; +}; + +template<> +class JS_PUBLIC_API(Concrete) : TracerConcreteWithCompartment { protected: explicit Concrete(JSScript *ptr) : TracerConcreteWithCompartment(ptr) { } public: static void construct(void *storage, JSScript *ptr) { new (storage) Concrete(ptr); } -}; -// The JSObject specialization. -template<> -class Concrete : public TracerConcreteWithCompartment { - const char* jsObjectClassName() const override; - bool jsObjectConstructorName(JSContext* cx, - UniquePtr& outName) const override; + CoarseType coarseType() const final { return CoarseType::Script; } Size size(mozilla::MallocSizeOf mallocSizeOf) const override; + const char* scriptFilename() const final; - bool hasAllocationStack() const override; - StackFrame allocationStack() const override; - - CoarseType coarseType() const final { return CoarseType::Object; } + const char16_t* typeName() const override { return concreteTypeName; } + static const char16_t concreteTypeName[]; +}; +// The JSObject specialization. +template<> +class JS_PUBLIC_API(Concrete) : public TracerConcreteWithCompartment { protected: explicit Concrete(JSObject* ptr) : TracerConcreteWithCompartment(ptr) { } @@ -1093,27 +1083,44 @@ static void construct(void* storage, JSObject* ptr) { new (storage) Concrete(ptr); } -}; -// For JSString, we extend the generic template with a 'size' implementation. -template<> struct Concrete : TracerConcrete { + const char* jsObjectClassName() const override; + MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) + const override; Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - CoarseType coarseType() const final { return CoarseType::String; } + bool hasAllocationStack() const override; + StackFrame allocationStack() const override; + + CoarseType coarseType() const final { return CoarseType::Object; } + const char16_t* typeName() const override { return concreteTypeName; } + static const char16_t concreteTypeName[]; +}; + +// For JSString, we extend the generic template with a 'size' implementation. +template<> +class JS_PUBLIC_API(Concrete) : TracerConcrete { protected: explicit Concrete(JSString *ptr) : TracerConcrete(ptr) { } public: static void construct(void *storage, JSString *ptr) { new (storage) Concrete(ptr); } + + Size size(mozilla::MallocSizeOf mallocSizeOf) const override; + + CoarseType coarseType() const final { return CoarseType::String; } + + const char16_t* typeName() const override { return concreteTypeName; } + static const char16_t concreteTypeName[]; }; // The ubi::Node null pointer. Any attempt to operate on a null ubi::Node asserts. template<> -class Concrete : public Base { +class JS_PUBLIC_API(Concrete) : public Base { const char16_t* typeName() const override; Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - UniquePtr edges(JSRuntime* rt, bool wantNames) const override; + js::UniquePtr edges(JSContext* cx, bool wantNames) const override; JS::Zone* zone() const override; JSCompartment* compartment() const override; CoarseType coarseType() const final; @@ -1122,7 +1129,6 @@ public: static void construct(void* storage, void* ptr) { new (storage) Concrete(ptr); } - static const char16_t concreteTypeName[]; }; Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNodeBreadthFirst.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNodeBreadthFirst.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNodeBreadthFirst.h @@ -83,8 +83,8 @@ // // We do nothing with noGC, other than require it to exist, with a lifetime // that encloses our own. - BreadthFirst(JSRuntime* rt, Handler& handler, const JS::AutoCheckCannotGC& noGC) - : wantNames(true), rt(rt), visited(), handler(handler), pending(), + BreadthFirst(JSContext* cx, Handler& handler, const JS::AutoCheckCannotGC& noGC) + : wantNames(true), cx(cx), visited(), handler(handler), pending(), traversalBegun(false), stopRequested(false), abandonRequested(false) { } @@ -126,7 +126,7 @@ pending.popFront(); // Get a range containing all origin's outgoing edges. - auto range = origin.edges(rt, wantNames); + auto range = origin.edges(cx, wantNames); if (!range) return false; @@ -134,7 +134,7 @@ for (; !range->empty(); range->popFront()) { MOZ_ASSERT(!stopRequested); - const Edge& edge = range->front(); + Edge& edge = range->front(); typename NodeMap::AddPtr a = visited.lookupForAdd(edge.referent); bool first = !a; @@ -181,8 +181,8 @@ // Other edges *to* that referent will still be traversed. void abandonReferent() { abandonRequested = true; } - // The runtime with which we were constructed. - JSRuntime* rt; + // The context with which we were constructed. + JSContext* cx; // A map associating each node N that we have reached with a // Handler::NodeData, for |handler|'s use. This is public, so that Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNodeCensus.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNodeCensus.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNodeCensus.h @@ -7,8 +7,11 @@ #ifndef js_UbiNodeCensus_h #define js_UbiNodeCensus_h +#include "mozilla/Attributes.h" #include "mozilla/Move.h" +#include + #include "jsapi.h" #include "js/UbiNode.h" @@ -80,14 +83,14 @@ class CountBase; struct CountDeleter { - void operator()(CountBase*); + JS_PUBLIC_API(void) operator()(CountBase*); }; -using CountBasePtr = UniquePtr; +using CountBasePtr = js::UniquePtr; // Abstract base class for CountType nodes. struct CountType { - explicit CountType(Census& census) : census(census) { } + explicit CountType() { } virtual ~CountType() { } // Destruct a count tree node that this type instance constructed. @@ -102,17 +105,17 @@ // Implement the 'count' method for counts returned by this CountType // instance's 'newCount' method. - virtual bool count(CountBase& count, const Node& node) = 0; + virtual MOZ_MUST_USE bool count(CountBase& count, + mozilla::MallocSizeOf mallocSizeOf, + const Node& node) = 0; // Implement the 'report' method for counts returned by this CountType // instance's 'newCount' method. - virtual bool report(CountBase& count, MutableHandleValue report) = 0; - - protected: - Census& census; + virtual MOZ_MUST_USE bool report(JSContext* cx, CountBase& count, + MutableHandleValue report) = 0; }; -using CountTypePtr = UniquePtr>; +using CountTypePtr = js::UniquePtr; // An abstract base class for count tree nodes. class CountBase { @@ -126,15 +129,39 @@ ~CountBase() { } public: - explicit CountBase(CountType& type) : type(type), total_(0) { } + explicit CountBase(CountType& type) + : type(type) + , total_(0) + , smallestNodeIdCounted_(SIZE_MAX) + { } // Categorize and count |node| as appropriate for this count's type. - bool count(const Node& node) { return type.count(*this, node); } + MOZ_MUST_USE bool count(mozilla::MallocSizeOf mallocSizeOf, const Node& node) { + total_++; + + auto id = node.identifier(); + if (id < smallestNodeIdCounted_) { + smallestNodeIdCounted_ = id; + } + +#ifdef DEBUG + size_t oldTotal = total_; +#endif + + bool ret = type.count(*this, mallocSizeOf, node); + + MOZ_ASSERT(total_ == oldTotal, + "CountType::count should not increment total_, CountBase::count handles that"); + + return ret; + } // Construct a JavaScript object reporting the counts recorded in this // count, and store it in |report|. Return true on success, or false on // failure. - bool report(MutableHandleValue report) { return type.report(*this, report); } + MOZ_MUST_USE bool report(JSContext* cx, MutableHandleValue report) { + return type.report(cx, *this, report); + } // Down-cast this CountBase to its true type, based on its 'type' member, // and run its destructor. @@ -144,6 +171,10 @@ void trace(JSTracer* trc) { type.traceCount(*this, trc); } size_t total_; + + // The smallest JS::ubi::Node::identifier() passed to this instance's + // count() method. This provides a stable way to sort sets. + Node::Id smallestNodeIdCounted_; }; class RootedCount : JS::CustomAutoRooter { @@ -172,19 +203,7 @@ explicit Census(JSContext* cx) : cx(cx), atomsZone(nullptr) { } - bool init(); - - // A 'new' work-alike that behaves like TempAllocPolicy: report OOM on this - // census's context, but don't charge the memory allocated to our context's - // GC pressure counters. - template - T* new_(Args&&... args) MOZ_HEAP_ALLOCATOR { - void* memory = js_malloc(sizeof(T)); - if (MOZ_UNLIKELY(!memory)) { - return nullptr; - } - return new(memory) T(mozilla::Forward(args)...); - } + MOZ_MUST_USE JS_PUBLIC_API(bool) init(); }; // A BreadthFirst handler type that conducts a census, using a CountBase to @@ -192,31 +211,40 @@ class CensusHandler { Census& census; CountBasePtr& rootCount; + mozilla::MallocSizeOf mallocSizeOf; public: - CensusHandler(Census& census, CountBasePtr& rootCount) + CensusHandler(Census& census, CountBasePtr& rootCount, mozilla::MallocSizeOf mallocSizeOf) : census(census), - rootCount(rootCount) + rootCount(rootCount), + mallocSizeOf(mallocSizeOf) { } - bool report(MutableHandleValue report) { - return rootCount->report(report); + MOZ_MUST_USE bool report(JSContext* cx, MutableHandleValue report) { + return rootCount->report(cx, report); } // This class needs to retain no per-node data. class NodeData { }; - bool operator() (BreadthFirst& traversal, - Node origin, const Edge& edge, - NodeData* referentData, bool first); + MOZ_MUST_USE JS_PUBLIC_API(bool) operator() (BreadthFirst& traversal, + Node origin, const Edge& edge, + NodeData* referentData, bool first); }; using CensusTraversal = BreadthFirst; -// Examine the census options supplied by the API consumer, and use that to -// build a CountType tree. -bool ParseCensusOptions(JSContext* cx, Census& census, HandleObject options, - CountTypePtr& outResult); +// Examine the census options supplied by the API consumer, and (among other +// things) use that to build a CountType tree. +MOZ_MUST_USE JS_PUBLIC_API(bool) ParseCensusOptions(JSContext* cx, + Census& census, HandleObject options, + CountTypePtr& outResult); + +// Parse the breakdown language (as described in +// js/src/doc/Debugger/Debugger.Memory.md) into a CountTypePtr. A null pointer +// is returned on error and is reported to the cx. +JS_PUBLIC_API(CountTypePtr) ParseBreakdown(JSContext* cx, HandleValue breakdownValue); + } // namespace ubi } // namespace JS Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNodeDominatorTree.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNodeDominatorTree.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNodeDominatorTree.h @@ -7,6 +7,7 @@ #ifndef js_UbiNodeDominatorTree_h #define js_UbiNodeDominatorTree_h +#include "mozilla/Attributes.h" #include "mozilla/DebugOnly.h" #include "mozilla/Maybe.h" #include "mozilla/Move.h" @@ -71,8 +72,6 @@ private: // Types. - using NodeSet = js::HashSet, js::SystemAllocPolicy>; - using NodeSetPtr = mozilla::UniquePtr>; using PredecessorSets = js::HashMap, js::SystemAllocPolicy>; using NodeToIndexMap = js::HashMap, @@ -95,10 +94,10 @@ { friend class DominatedSetRange; - const mozilla::Vector& postOrder; + const JS::ubi::Vector& postOrder; const uint32_t* ptr; - DominatedNodePtr(const mozilla::Vector& postOrder, const uint32_t* ptr) + DominatedNodePtr(const JS::ubi::Vector& postOrder, const uint32_t* ptr) : postOrder(postOrder) , ptr(ptr) { } @@ -119,11 +118,11 @@ { friend class DominatedSets; - const mozilla::Vector& postOrder; + const JS::ubi::Vector& postOrder; const uint32_t* beginPtr; const uint32_t* endPtr; - DominatedSetRange(mozilla::Vector& postOrder, const uint32_t* begin, const uint32_t* end) + DominatedSetRange(JS::ubi::Vector& postOrder, const uint32_t* begin, const uint32_t* end) : postOrder(postOrder) , beginPtr(begin) , endPtr(end) @@ -180,10 +179,10 @@ */ class DominatedSets { - mozilla::Vector dominated; - mozilla::Vector indices; + JS::ubi::Vector dominated; + JS::ubi::Vector indices; - DominatedSets(mozilla::Vector&& dominated, mozilla::Vector&& indices) + DominatedSets(JS::ubi::Vector&& dominated, JS::ubi::Vector&& indices) : dominated(mozilla::Move(dominated)) , indices(mozilla::Move(indices)) { } @@ -211,7 +210,7 @@ * immediate dominator. Returns `Some` on success, `Nothing` on OOM * failure. */ - static mozilla::Maybe Create(const mozilla::Vector& doms) { + static mozilla::Maybe Create(const JS::ubi::Vector& doms) { auto length = doms.length(); MOZ_ASSERT(length < UINT32_MAX); @@ -236,8 +235,8 @@ // filled in. After having filled in all of a bucket's entries, // the index points to the start of the bucket. - mozilla::Vector dominated; - mozilla::Vector indices; + JS::ubi::Vector dominated; + JS::ubi::Vector indices; if (!dominated.growBy(length) || !indices.growBy(length)) return mozilla::Nothing(); @@ -279,7 +278,7 @@ * Get the set of nodes immediately dominated by the node at * `postOrder[nodeIndex]`. */ - DominatedSetRange dominatedSet(mozilla::Vector& postOrder, uint32_t nodeIndex) const { + DominatedSetRange dominatedSet(JS::ubi::Vector& postOrder, uint32_t nodeIndex) const { MOZ_ASSERT(postOrder.length() == indices.length()); MOZ_ASSERT(nodeIndex < indices.length()); auto end = nodeIndex == indices.length() - 1 @@ -291,11 +290,11 @@ private: // Data members. - mozilla::Vector postOrder; + JS::ubi::Vector postOrder; NodeToIndexMap nodeToPostOrderIndex; - mozilla::Vector doms; + JS::ubi::Vector doms; DominatedSets dominatedSets; - mozilla::Maybe> retainedSizes; + mozilla::Maybe> retainedSizes; private: // We use `UNDEFINED` as a sentinel value in the `doms` vector to signal @@ -303,8 +302,8 @@ // index in `postOrder` yet. static const uint32_t UNDEFINED = UINT32_MAX; - DominatorTree(mozilla::Vector&& postOrder, NodeToIndexMap&& nodeToPostOrderIndex, - mozilla::Vector&& doms, DominatedSets&& dominatedSets) + DominatorTree(JS::ubi::Vector&& postOrder, NodeToIndexMap&& nodeToPostOrderIndex, + JS::ubi::Vector&& doms, DominatedSets&& dominatedSets) : postOrder(mozilla::Move(postOrder)) , nodeToPostOrderIndex(mozilla::Move(nodeToPostOrderIndex)) , doms(mozilla::Move(doms)) @@ -312,7 +311,7 @@ , retainedSizes(mozilla::Nothing()) { } - static uint32_t intersect(mozilla::Vector& doms, uint32_t finger1, uint32_t finger2) { + static uint32_t intersect(JS::ubi::Vector& doms, uint32_t finger1, uint32_t finger2) { while (finger1 != finger2) { if (finger1 < finger2) finger1 = doms[finger1]; @@ -324,8 +323,9 @@ // Do the post order traversal of the heap graph and populate our // predecessor sets. - static bool doTraversal(JSRuntime* rt, AutoCheckCannotGC& noGC, const Node& root, - mozilla::Vector& postOrder, PredecessorSets& predecessorSets) { + static MOZ_MUST_USE bool doTraversal(JSContext* cx, AutoCheckCannotGC& noGC, const Node& root, + JS::ubi::Vector& postOrder, + PredecessorSets& predecessorSets) { uint32_t nodeCount = 0; auto onNode = [&](const Node& node) { nodeCount++; @@ -349,7 +349,7 @@ return p->value()->put(origin); }; - PostOrder traversal(rt, noGC); + PostOrder traversal(cx, noGC); return traversal.init() && traversal.addStart(root) && traversal.traverse(onNode, onEdge); @@ -357,7 +357,8 @@ // Populates the given `map` with an entry for each node to its index in // `postOrder`. - static bool mapNodesToTheirIndices(mozilla::Vector& postOrder, NodeToIndexMap& map) { + static MOZ_MUST_USE bool mapNodesToTheirIndices(JS::ubi::Vector& postOrder, + NodeToIndexMap& map) { MOZ_ASSERT(!map.initialized()); MOZ_ASSERT(postOrder.length() < UINT32_MAX); uint32_t length = postOrder.length(); @@ -370,12 +371,12 @@ // Convert the Node -> NodeSet predecessorSets to a index -> Vector // form. - static bool convertPredecessorSetsToVectors( + static MOZ_MUST_USE bool convertPredecessorSetsToVectors( const Node& root, - mozilla::Vector& postOrder, + JS::ubi::Vector& postOrder, PredecessorSets& predecessorSets, NodeToIndexMap& nodeToPostOrderIndex, - mozilla::Vector>& predecessorVectors) + JS::ubi::Vector>& predecessorVectors) { MOZ_ASSERT(postOrder.length() < UINT32_MAX); uint32_t length = postOrder.length(); @@ -409,7 +410,8 @@ // Initialize `doms` such that the immediate dominator of the `root` is the // `root` itself and all others are `UNDEFINED`. - static bool initializeDominators(mozilla::Vector& doms, uint32_t length) { + static MOZ_MUST_USE bool initializeDominators(JS::ubi::Vector& doms, + uint32_t length) { MOZ_ASSERT(doms.length() == 0); if (!doms.growByUninitialized(length)) return false; @@ -425,7 +427,7 @@ MOZ_ASSERT_IF(retainedSizes.isSome(), postOrder.length() == retainedSizes->length()); } - bool computeRetainedSizes(mozilla::MallocSizeOf mallocSizeOf) { + MOZ_MUST_USE bool computeRetainedSizes(mozilla::MallocSizeOf mallocSizeOf) { MOZ_ASSERT(retainedSizes.isNothing()); auto length = postOrder.length(); @@ -511,10 +513,10 @@ * responsibility to handle and report the OOM. */ static mozilla::Maybe - Create(JSRuntime* rt, AutoCheckCannotGC& noGC, const Node& root) { - mozilla::Vector postOrder; + Create(JSContext* cx, AutoCheckCannotGC& noGC, const Node& root) { + JS::ubi::Vector postOrder; PredecessorSets predecessorSets; - if (!predecessorSets.init() || !doTraversal(rt, noGC, root, postOrder, predecessorSets)) + if (!predecessorSets.init() || !doTraversal(cx, noGC, root, postOrder, predecessorSets)) return mozilla::Nothing(); MOZ_ASSERT(postOrder.length() < UINT32_MAX); @@ -531,12 +533,12 @@ if (!mapNodesToTheirIndices(postOrder, nodeToPostOrderIndex)) return mozilla::Nothing(); - mozilla::Vector> predecessorVectors; + JS::ubi::Vector> predecessorVectors; if (!convertPredecessorSetsToVectors(root, postOrder, predecessorSets, nodeToPostOrderIndex, predecessorVectors)) return mozilla::Nothing(); - mozilla::Vector doms; + JS::ubi::Vector doms; if (!initializeDominators(doms, length)) return mozilla::Nothing(); @@ -650,8 +652,8 @@ * `outSize`, or 0 if `node` is not a member of the dominator tree. Returns * false on OOM failure, leaving `outSize` unchanged. */ - bool getRetainedSize(const Node& node, mozilla::MallocSizeOf mallocSizeOf, - Node::Size& outSize) { + MOZ_MUST_USE bool getRetainedSize(const Node& node, mozilla::MallocSizeOf mallocSizeOf, + Node::Size& outSize) { assertSanity(); auto ptr = nodeToPostOrderIndex.lookup(node); if (!ptr) { Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNodePostOrder.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNodePostOrder.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNodePostOrder.h @@ -7,7 +7,7 @@ #ifndef js_UbiNodePostOrder_h #define js_UbiNodePostOrder_h -#include "mozilla/DebugOnly.h" +#include "mozilla/Attributes.h" #include "mozilla/Maybe.h" #include "mozilla/Move.h" @@ -83,13 +83,15 @@ using Stack = js::Vector; using Set = js::HashSet, js::SystemAllocPolicy>; - JSRuntime* rt; + JSContext* cx; Set seen; Stack stack; - mozilla::DebugOnly traversed; +#ifdef DEBUG + bool traversed; +#endif private: - bool fillEdgesFromRange(EdgeVector& edges, UniquePtr& range) { + MOZ_MUST_USE bool fillEdgesFromRange(EdgeVector& edges, js::UniquePtr& range) { MOZ_ASSERT(range); for ( ; !range->empty(); range->popFront()) { if (!edges.append(mozilla::Move(range->front()))) @@ -98,9 +100,9 @@ return true; } - bool pushForTraversing(const Node& node) { + MOZ_MUST_USE bool pushForTraversing(const Node& node) { EdgeVector edges; - auto range = node.edges(rt, /* wantNames */ false); + auto range = node.edges(cx, /* wantNames */ false); return range && fillEdgesFromRange(edges, range) && stack.append(OriginAndEdges(node, mozilla::Move(edges))); @@ -113,19 +115,21 @@ // The traversal asserts that no GC happens in its runtime during its // lifetime via the `AutoCheckCannotGC&` parameter. We do nothing with it, // other than require it to exist with a lifetime that encloses our own. - PostOrder(JSRuntime* rt, AutoCheckCannotGC&) - : rt(rt) + PostOrder(JSContext* cx, AutoCheckCannotGC&) + : cx(cx) , seen() , stack() +#ifdef DEBUG , traversed(false) +#endif { } // Initialize this traversal object. Return false on OOM. - bool init() { return seen.init(); } + MOZ_MUST_USE bool init() { return seen.init(); } // Add `node` as a starting point for the traversal. You may add // as many starting points as you like. Returns false on OOM. - bool addStart(const Node& node) { + MOZ_MUST_USE bool addStart(const Node& node) { if (!seen.put(node)) return false; return pushForTraversing(node); @@ -141,9 +145,11 @@ // Return false on OOM or error return from `onNode::operator()` or // `onEdge::operator()`. template - bool traverse(NodeVisitor onNode, EdgeVisitor onEdge) { + MOZ_MUST_USE bool traverse(NodeVisitor onNode, EdgeVisitor onEdge) { +#ifdef DEBUG MOZ_ASSERT(!traversed, "Can only traverse() once!"); traversed = true; +#endif while (!stack.empty()) { auto& origin = stack.back().origin; Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNodeShortestPaths.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNodeShortestPaths.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UbiNodeShortestPaths.h @@ -0,0 +1,350 @@ +/* -*- 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_UbiNodeShortestPaths_h +#define js_UbiNodeShortestPaths_h + +#include "mozilla/Attributes.h" +#include "mozilla/Maybe.h" +#include "mozilla/Move.h" + +#include "jsalloc.h" + +#include "js/UbiNodeBreadthFirst.h" +#include "js/Vector.h" + +namespace JS { +namespace ubi { + +/** + * A back edge along a path in the heap graph. + */ +struct JS_PUBLIC_API(BackEdge) +{ + private: + Node predecessor_; + EdgeName name_; + + public: + using Ptr = mozilla::UniquePtr>; + + BackEdge() : predecessor_(), name_(nullptr) { } + + MOZ_MUST_USE bool init(const Node& predecessor, Edge& edge) { + MOZ_ASSERT(!predecessor_); + MOZ_ASSERT(!name_); + + predecessor_ = predecessor; + name_ = mozilla::Move(edge.name); + return true; + } + + BackEdge(const BackEdge&) = delete; + BackEdge& operator=(const BackEdge&) = delete; + + BackEdge(BackEdge&& rhs) + : predecessor_(rhs.predecessor_) + , name_(mozilla::Move(rhs.name_)) + { + MOZ_ASSERT(&rhs != this); + } + + BackEdge& operator=(BackEdge&& rhs) { + this->~BackEdge(); + new(this) BackEdge(Move(rhs)); + return *this; + } + + Ptr clone() const; + + const EdgeName& name() const { return name_; } + EdgeName& name() { return name_; } + + const JS::ubi::Node& predecessor() const { return predecessor_; } +}; + +/** + * A path is a series of back edges from which we discovered a target node. + */ +using Path = JS::ubi::Vector; + +/** + * The `JS::ubi::ShortestPaths` type represents a collection of up to N shortest + * retaining paths for each of a target set of nodes, starting from the same + * root node. + */ +struct JS_PUBLIC_API(ShortestPaths) +{ + private: + // Types, type aliases, and data members. + + using BackEdgeVector = JS::ubi::Vector; + using NodeToBackEdgeVectorMap = js::HashMap, + js::SystemAllocPolicy>; + + struct Handler; + using Traversal = BreadthFirst; + + /** + * A `JS::ubi::BreadthFirst` traversal handler that records back edges for + * how we reached each node, allowing us to reconstruct the shortest + * retaining paths after the traversal. + */ + struct Handler + { + using NodeData = BackEdge; + + ShortestPaths& shortestPaths; + size_t totalMaxPathsToRecord; + size_t totalPathsRecorded; + + explicit Handler(ShortestPaths& shortestPaths) + : shortestPaths(shortestPaths) + , totalMaxPathsToRecord(shortestPaths.targets_.count() * shortestPaths.maxNumPaths_) + , totalPathsRecorded(0) + { + } + + bool + operator()(Traversal& traversal, JS::ubi::Node origin, JS::ubi::Edge& edge, + BackEdge* back, bool first) + { + MOZ_ASSERT(back); + MOZ_ASSERT(origin == shortestPaths.root_ || traversal.visited.has(origin)); + MOZ_ASSERT(totalPathsRecorded < totalMaxPathsToRecord); + + if (first && !back->init(origin, edge)) + return false; + + if (!shortestPaths.targets_.has(edge.referent)) + return true; + + // If `first` is true, then we moved the edge's name into `back` in + // the above call to `init`. So clone that back edge to get the + // correct edge name. If `first` is not true, then our edge name is + // still in `edge`. This accounts for the asymmetry between + // `back->clone()` in the first branch, and the `init` call in the + // second branch. + + if (first) { + BackEdgeVector paths; + if (!paths.reserve(shortestPaths.maxNumPaths_)) + return false; + auto cloned = back->clone(); + if (!cloned) + return false; + paths.infallibleAppend(mozilla::Move(cloned)); + if (!shortestPaths.paths_.putNew(edge.referent, mozilla::Move(paths))) + return false; + totalPathsRecorded++; + } else { + auto ptr = shortestPaths.paths_.lookup(edge.referent); + MOZ_ASSERT(ptr, + "This isn't the first time we have seen the target node `edge.referent`. " + "We should have inserted it into shortestPaths.paths_ the first time we " + "saw it."); + + if (ptr->value().length() < shortestPaths.maxNumPaths_) { + BackEdge::Ptr thisBackEdge(js_new()); + if (!thisBackEdge || !thisBackEdge->init(origin, edge)) + return false; + ptr->value().infallibleAppend(mozilla::Move(thisBackEdge)); + totalPathsRecorded++; + } + } + + MOZ_ASSERT(totalPathsRecorded <= totalMaxPathsToRecord); + if (totalPathsRecorded == totalMaxPathsToRecord) + traversal.stop(); + + return true; + } + + }; + + // The maximum number of paths to record for each node. + uint32_t maxNumPaths_; + + // The root node we are starting the search from. + Node root_; + + // The set of nodes we are searching for paths to. + NodeSet targets_; + + // The resulting paths. + NodeToBackEdgeVectorMap paths_; + + // Need to keep alive the traversal's back edges so we can walk them later + // when the traversal is over when recreating the shortest paths. + Traversal::NodeMap backEdges_; + + private: + // Private methods. + + ShortestPaths(uint32_t maxNumPaths, const Node& root, NodeSet&& targets) + : maxNumPaths_(maxNumPaths) + , root_(root) + , targets_(mozilla::Move(targets)) + , paths_() + , backEdges_() + { + MOZ_ASSERT(maxNumPaths_ > 0); + MOZ_ASSERT(root_); + MOZ_ASSERT(targets_.initialized()); + } + + bool initialized() const { + return targets_.initialized() && + paths_.initialized() && + backEdges_.initialized(); + } + + public: + // Public methods. + + ShortestPaths(ShortestPaths&& rhs) + : maxNumPaths_(rhs.maxNumPaths_) + , root_(rhs.root_) + , targets_(mozilla::Move(rhs.targets_)) + , paths_(mozilla::Move(rhs.paths_)) + , backEdges_(mozilla::Move(rhs.backEdges_)) + { + MOZ_ASSERT(this != &rhs, "self-move is not allowed"); + } + + ShortestPaths& operator=(ShortestPaths&& rhs) { + this->~ShortestPaths(); + new (this) ShortestPaths(mozilla::Move(rhs)); + return *this; + } + + ShortestPaths(const ShortestPaths&) = delete; + ShortestPaths& operator=(const ShortestPaths&) = delete; + + /** + * Construct a new `JS::ubi::ShortestPaths`, finding up to `maxNumPaths` + * shortest retaining paths for each target node in `targets` starting from + * `root`. + * + * The resulting `ShortestPaths` instance must not outlive the + * `JS::ubi::Node` graph it was constructed from. + * + * - For `JS::ubi::Node` graphs backed by the live heap graph, this means + * that the `ShortestPaths`'s lifetime _must_ be contained within the + * scope of the provided `AutoCheckCannotGC` reference because a GC will + * invalidate the nodes. + * + * - For `JS::ubi::Node` graphs backed by some other offline structure + * provided by the embedder, the resulting `ShortestPaths`'s lifetime is + * bounded by that offline structure's lifetime. + * + * Returns `mozilla::Nothing()` on OOM failure. It is the caller's + * responsibility to handle and report the OOM. + */ + static mozilla::Maybe + Create(JSContext* cx, AutoCheckCannotGC& noGC, uint32_t maxNumPaths, const Node& root, NodeSet&& targets) { + MOZ_ASSERT(targets.count() > 0); + MOZ_ASSERT(maxNumPaths > 0); + + size_t count = targets.count(); + ShortestPaths paths(maxNumPaths, root, mozilla::Move(targets)); + if (!paths.paths_.init(count)) + return mozilla::Nothing(); + + Handler handler(paths); + Traversal traversal(cx, handler, noGC); + traversal.wantNames = true; + if (!traversal.init() || !traversal.addStart(root) || !traversal.traverse()) + return mozilla::Nothing(); + + // Take ownership of the back edges we created while traversing the + // graph so that we can follow them from `paths_` and don't + // use-after-free. + paths.backEdges_ = mozilla::Move(traversal.visited); + + MOZ_ASSERT(paths.initialized()); + return mozilla::Some(mozilla::Move(paths)); + } + + /** + * Get a range that iterates over each target node we searched for retaining + * paths for. The returned range must not outlive the `ShortestPaths` + * instance. + */ + NodeSet::Range eachTarget() const { + MOZ_ASSERT(initialized()); + return targets_.all(); + } + + /** + * Invoke the provided functor/lambda/callable once for each retaining path + * discovered for `target`. The `func` is passed a single `JS::ubi::Path&` + * argument, which contains each edge along the path ordered starting from + * the root and ending at the target, and must not outlive the scope of the + * call. + * + * Note that it is possible that we did not find any paths from the root to + * the given target, in which case `func` will not be invoked. + */ + template + MOZ_MUST_USE bool forEachPath(const Node& target, Func func) { + MOZ_ASSERT(initialized()); + MOZ_ASSERT(targets_.has(target)); + + auto ptr = paths_.lookup(target); + + // We didn't find any paths to this target, so nothing to do here. + if (!ptr) + return true; + + MOZ_ASSERT(ptr->value().length() <= maxNumPaths_); + + Path path; + for (const auto& backEdge : ptr->value()) { + path.clear(); + + if (!path.append(backEdge.get())) + return false; + + Node here = backEdge->predecessor(); + MOZ_ASSERT(here); + + while (here != root_) { + auto p = backEdges_.lookup(here); + MOZ_ASSERT(p); + if (!path.append(&p->value())) + return false; + here = p->value().predecessor(); + MOZ_ASSERT(here); + } + + path.reverse(); + + if (!func(path)) + return false; + } + + return true; + } +}; + +#ifdef DEBUG +// A helper function to dump the first `maxNumPaths` shortest retaining paths to +// `node` from the GC roots. Useful when GC things you expect to have been +// reclaimed by the collector haven't been! +// +// Usage: +// +// JSObject* foo = ...; +// JS::ubi::dumpPaths(rt, JS::ubi::Node(foo)); +JS_PUBLIC_API(void) +dumpPaths(JSRuntime* rt, Node node, uint32_t maxNumPaths = 10); +#endif + +} // namespace ubi +} // namespace JS + +#endif // js_UbiNodeShortestPaths_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UniquePtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UniquePtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/UniquePtr.h @@ -0,0 +1,61 @@ +/* -*- 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_UniquePtr_h +#define js_UniquePtr_h + +#include "mozilla/UniquePtr.h" + +#include "js/Utility.h" + +namespace js { + +// Replacement for mozilla::UniquePtr that defaults to js::DefaultDelete. +template > +using UniquePtr = mozilla::UniquePtr; + +namespace detail { + +template +struct UniqueSelector +{ + typedef UniquePtr SingleObject; +}; + +template +struct UniqueSelector +{ + typedef UniquePtr UnknownBound; +}; + +template +struct UniqueSelector +{ + typedef UniquePtr KnownBound; +}; + +} // namespace detail + +// Replacement for mozilla::MakeUnique that correctly calls js_new and produces +// a js::UniquePtr. +template +typename detail::UniqueSelector::SingleObject +MakeUnique(Args&&... aArgs) +{ + return UniquePtr(js_new(mozilla::Forward(aArgs)...)); +} + +template +typename detail::UniqueSelector::UnknownBound +MakeUnique(decltype(sizeof(int)) aN) = delete; + +template +typename detail::UniqueSelector::KnownBound +MakeUnique(Args&&... aArgs) = delete; + +} // namespace js + +#endif /* js_UniquePtr_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Utility.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Utility.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Utility.h @@ -8,6 +8,7 @@ #define js_Utility_h #include "mozilla/Assertions.h" +#include "mozilla/Atomics.h" #include "mozilla/Attributes.h" #include "mozilla/Compiler.h" #include "mozilla/Move.h" @@ -34,22 +35,6 @@ /* The private JS engine namespace. */ namespace js {} -/* - * Patterns used by SpiderMonkey to overwrite unused memory. If you are - * accessing an object with one of these pattern, you probably have a dangling - * pointer. - */ -#define JS_FRESH_NURSERY_PATTERN 0x2F -#define JS_SWEPT_NURSERY_PATTERN 0x2B -#define JS_ALLOCATED_NURSERY_PATTERN 0x2D -#define JS_FRESH_TENURED_PATTERN 0x4F -#define JS_MOVED_TENURED_PATTERN 0x49 -#define JS_SWEPT_TENURED_PATTERN 0x4B -#define JS_ALLOCATED_TENURED_PATTERN 0x4D -#define JS_EMPTY_STOREBUFFER_PATTERN 0x1B -#define JS_SWEPT_CODE_PATTERN 0x3B -#define JS_SWEPT_FRAME_PATTERN 0x5B - #define JS_STATIC_ASSERT(cond) static_assert(cond, "JS_STATIC_ASSERT") #define JS_STATIC_ASSERT_IF(cond, expr) MOZ_STATIC_ASSERT_IF(cond, expr, "JS_STATIC_ASSERT_IF") @@ -81,6 +66,7 @@ THREAD_TYPE_COMPRESS, // 5 THREAD_TYPE_GCHELPER, // 6 THREAD_TYPE_GCPARALLEL, // 7 + THREAD_TYPE_PROMISE_TASK, // 8 THREAD_TYPE_MAX // Used to check shell function arguments }; @@ -103,15 +89,6 @@ # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) -/* - * In order to test OOM conditions, when the testing function - * oomAfterAllocations COUNT is passed, we fail continuously after the NUM'th - * allocation from now. - */ -extern JS_PUBLIC_DATA(uint32_t) OOM_maxAllocations; /* set in builtin/TestingFunctions.cpp */ -extern JS_PUBLIC_DATA(uint32_t) OOM_counter; /* data race, who cares. */ -extern JS_PUBLIC_DATA(bool) OOM_failAlways; - #ifdef JS_OOM_BREAKPOINT static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); } #define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint() @@ -122,28 +99,42 @@ namespace js { namespace oom { +/* + * Out of memory testing support. We provide various testing functions to + * simulate OOM conditions and so we can test that they are handled correctly. + */ + extern JS_PUBLIC_DATA(uint32_t) targetThread; +extern JS_PUBLIC_DATA(uint64_t) maxAllocations; +extern JS_PUBLIC_DATA(uint64_t) counter; +extern JS_PUBLIC_DATA(bool) failAlways; -static inline bool +extern void +SimulateOOMAfter(uint64_t allocations, uint32_t thread, bool always); + +extern void +ResetSimulatedOOM(); + +inline bool IsThreadSimulatingOOM() { return js::oom::targetThread && js::oom::targetThread == js::oom::GetThreadType(); } -static inline bool +inline bool IsSimulatedOOMAllocation() { - return IsThreadSimulatingOOM() && (OOM_counter == OOM_maxAllocations || - (OOM_counter > OOM_maxAllocations && OOM_failAlways)); + return IsThreadSimulatingOOM() && + (counter == maxAllocations || (counter > maxAllocations && failAlways)); } -static inline bool +inline bool ShouldFailWithOOM() { if (!IsThreadSimulatingOOM()) return false; - OOM_counter++; + counter++; if (IsSimulatedOOMAllocation()) { JS_OOM_CALL_BP_FUNC(); return true; @@ -151,6 +142,11 @@ return false; } +inline bool +HadSimulatedOOM() { + return counter >= maxAllocations; +} + } /* namespace oom */ } /* namespace js */ @@ -182,32 +178,44 @@ namespace js { /* Disable OOM testing in sections which are not OOM safe. */ -struct MOZ_RAII AutoEnterOOMUnsafeRegion +struct MOZ_RAII JS_PUBLIC_DATA(AutoEnterOOMUnsafeRegion) { MOZ_NORETURN MOZ_COLD void crash(const char* reason); + MOZ_NORETURN MOZ_COLD void crash(size_t size, const char* reason); + + using AnnotateOOMAllocationSizeCallback = void(*)(size_t); + static AnnotateOOMAllocationSizeCallback annotateOOMSizeCallback; + static void setAnnotateOOMAllocationSizeCallback(AnnotateOOMAllocationSizeCallback callback) { + annotateOOMSizeCallback = callback; + } #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) AutoEnterOOMUnsafeRegion() - : oomEnabled_(oom::IsThreadSimulatingOOM() && OOM_maxAllocations != UINT32_MAX), + : oomEnabled_(oom::IsThreadSimulatingOOM() && oom::maxAllocations != UINT64_MAX), oomAfter_(0) { if (oomEnabled_) { - oomAfter_ = int64_t(OOM_maxAllocations) - OOM_counter; - OOM_maxAllocations = UINT32_MAX; + MOZ_ALWAYS_TRUE(owner_.compareExchange(nullptr, this)); + oomAfter_ = int64_t(oom::maxAllocations) - int64_t(oom::counter); + oom::maxAllocations = UINT64_MAX; } } ~AutoEnterOOMUnsafeRegion() { if (oomEnabled_) { - MOZ_ASSERT(OOM_maxAllocations == UINT32_MAX); - int64_t maxAllocations = OOM_counter + oomAfter_; - MOZ_ASSERT(maxAllocations >= 0 && maxAllocations < UINT32_MAX, + MOZ_ASSERT(oom::maxAllocations == UINT64_MAX); + int64_t maxAllocations = int64_t(oom::counter) + oomAfter_; + MOZ_ASSERT(maxAllocations >= 0, "alloc count + oom limit exceeds range, your oom limit is probably too large"); - OOM_maxAllocations = uint32_t(maxAllocations); + oom::maxAllocations = uint64_t(maxAllocations); + MOZ_ALWAYS_TRUE(owner_.compareExchange(this, nullptr)); } } private: + // Used to catch concurrent use from other threads. + static mozilla::Atomic owner_; + bool oomEnabled_; int64_t oomAfter_; #endif @@ -235,6 +243,11 @@ static inline void* js_realloc(void* p, size_t bytes) { + // realloc() with zero size is not portable, as some implementations may + // return nullptr on success and free |p| for this. We assume nullptr + // indicates failure and that |p| is still valid. + MOZ_ASSERT(bytes != 0); + JS_OOM_POSSIBLY_FAIL(); return realloc(p, bytes); } @@ -302,14 +315,14 @@ * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS, * or the build will break. */ -#define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS)\ +#define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \ template \ QUALIFIERS T * \ NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \ void* memory = ALLOCATOR(sizeof(T)); \ - return memory \ - ? new(memory) T(mozilla::Forward(args)...) \ - : nullptr; \ + return MOZ_LIKELY(memory) \ + ? new(memory) T(mozilla::Forward(args)...) \ + : nullptr; \ } /* @@ -339,7 +352,7 @@ * instances of type |T|. Return false if the calculation overflowed. */ template -MOZ_WARN_UNUSED_RESULT inline bool +MOZ_MUST_USE inline bool CalculateAllocSize(size_t numElems, size_t* bytesOut) { *bytesOut = numElems * sizeof(T); @@ -352,7 +365,7 @@ * false if the calculation overflowed. */ template -MOZ_WARN_UNUSED_RESULT inline bool +MOZ_MUST_USE inline bool CalculateAllocSizeWithExtra(size_t numExtra, size_t* bytesOut) { *bytesOut = sizeof(T) + numExtra * sizeof(Extra); @@ -460,6 +473,14 @@ template struct DeletePolicy { + constexpr DeletePolicy() {} + + template + MOZ_IMPLICIT DeletePolicy(DeletePolicy other, + typename mozilla::EnableIf::value, + int>::Type dummy = 0) + {} + void operator()(const T* ptr) { js_delete(const_cast(ptr)); } @@ -472,6 +493,9 @@ } }; +typedef mozilla::UniquePtr UniqueChars; +typedef mozilla::UniquePtr UniqueTwoByteChars; + } // namespace JS namespace js { @@ -480,13 +504,6 @@ typedef uint32_t HashNumber; const unsigned HashNumberSizeBits = 32; -typedef mozilla::UniquePtr UniqueChars; - -static inline UniqueChars make_string_copy(const char* str) -{ - return UniqueChars(js_strdup(str)); -} - namespace detail { /* Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Value.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Value.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Value.h @@ -10,6 +10,7 @@ #define js_Value_h #include "mozilla/Attributes.h" +#include "mozilla/Casting.h" #include "mozilla/FloatingPoint.h" #include "mozilla/Likely.h" @@ -29,34 +30,12 @@ #define JSVAL_INT_MIN ((int32_t)0x80000000) #define JSVAL_INT_MAX ((int32_t)0x7fffffff) -/* - * Try to get jsvals 64-bit aligned. We could almost assert that all values are - * aligned, but MSVC and GCC occasionally break alignment. - */ -#if defined(__GNUC__) || defined(__xlc__) || defined(__xlC__) -# define JSVAL_ALIGNMENT __attribute__((aligned (8))) -#elif defined(_MSC_VER) - /* - * Structs can be aligned with MSVC, but not if they are used as parameters, - * so we just don't try to align. - */ -# define JSVAL_ALIGNMENT -#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# define JSVAL_ALIGNMENT -#elif defined(__HP_cc) || defined(__HP_aCC) -# define JSVAL_ALIGNMENT -#endif - #if defined(JS_PUNBOX64) # define JSVAL_TAG_SHIFT 47 #endif -/* - * We try to use enums so that printing a jsval_layout in the debugger shows - * nice symbolic type tags, however we can only do this when we can force the - * underlying type of the enum to be the desired size. - */ -#if !defined(__SUNPRO_CC) && !defined(__xlC__) +// Use enums so that printing a JS::Value in the debugger shows nice +// symbolic type tags. #if defined(_MSC_VER) # define JS_ENUM_HEADER(id, type) enum id : type @@ -76,8 +55,9 @@ JSVAL_TYPE_MAGIC = 0x04, JSVAL_TYPE_STRING = 0x05, JSVAL_TYPE_SYMBOL = 0x06, - JSVAL_TYPE_NULL = 0x07, - JSVAL_TYPE_OBJECT = 0x08, + JSVAL_TYPE_PRIVATE_GCTHING = 0x07, + JSVAL_TYPE_NULL = 0x08, + JSVAL_TYPE_OBJECT = 0x0c, /* These never appear in a jsval; they are only provided as an out-of-band value. */ JSVAL_TYPE_UNKNOWN = 0x20, @@ -100,7 +80,8 @@ JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN, JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC, JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL, - JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT + JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT, + JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING } JS_ENUM_FOOTER(JSValueTag); static_assert(sizeof(JSValueTag) == sizeof(uint32_t), @@ -119,7 +100,8 @@ JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN, JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC, JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL, - JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT + JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT, + JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING } JS_ENUM_FOOTER(JSValueTag); static_assert(sizeof(JSValueTag) == sizeof(uint32_t), @@ -127,15 +109,16 @@ JS_ENUM_HEADER(JSValueShiftedTag, uint64_t) { - JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF), - JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) + JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF), + JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT) } JS_ENUM_FOOTER(JSValueShiftedTag); static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t), @@ -153,64 +136,12 @@ #undef JS_ENUM_HEADER #undef JS_ENUM_FOOTER -#else /* !defined(__SUNPRO_CC) && !defined(__xlC__) */ - -typedef uint8_t JSValueType; -#define JSVAL_TYPE_DOUBLE ((uint8_t)0x00) -#define JSVAL_TYPE_INT32 ((uint8_t)0x01) -#define JSVAL_TYPE_UNDEFINED ((uint8_t)0x02) -#define JSVAL_TYPE_BOOLEAN ((uint8_t)0x03) -#define JSVAL_TYPE_MAGIC ((uint8_t)0x04) -#define JSVAL_TYPE_STRING ((uint8_t)0x05) -#define JSVAL_TYPE_SYMBOL ((uint8_t)0x06) -#define JSVAL_TYPE_NULL ((uint8_t)0x07) -#define JSVAL_TYPE_OBJECT ((uint8_t)0x08) -#define JSVAL_TYPE_UNKNOWN ((uint8_t)0x20) - -#if defined(JS_NUNBOX32) - -typedef uint32_t JSValueTag; -#define JSVAL_TAG_CLEAR ((uint32_t)(0xFFFFFF80)) -#define JSVAL_TAG_INT32 ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32)) -#define JSVAL_TAG_UNDEFINED ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED)) -#define JSVAL_TAG_STRING ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING)) -#define JSVAL_TAG_SYMBOL ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL)) -#define JSVAL_TAG_BOOLEAN ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN)) -#define JSVAL_TAG_MAGIC ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC)) -#define JSVAL_TAG_NULL ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL)) -#define JSVAL_TAG_OBJECT ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT)) - -#elif defined(JS_PUNBOX64) - -typedef uint32_t JSValueTag; -#define JSVAL_TAG_MAX_DOUBLE ((uint32_t)(0x1FFF0)) -#define JSVAL_TAG_INT32 (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32) -#define JSVAL_TAG_UNDEFINED (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED) -#define JSVAL_TAG_STRING (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING) -#define JSVAL_TAG_SYMBOL (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL) -#define JSVAL_TAG_BOOLEAN (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN) -#define JSVAL_TAG_MAGIC (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC) -#define JSVAL_TAG_NULL (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL) -#define JSVAL_TAG_OBJECT (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT) - -typedef uint64_t JSValueShiftedTag; -#define JSVAL_SHIFTED_TAG_MAX_DOUBLE ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF) -#define JSVAL_SHIFTED_TAG_INT32 (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_UNDEFINED (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_STRING (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_SYMBOL (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_BOOLEAN (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_MAGIC (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_NULL (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT) -#define JSVAL_SHIFTED_TAG_OBJECT (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) - -#endif /* JS_PUNBOX64 */ -#endif /* !defined(__SUNPRO_CC) && !defined(__xlC__) */ - #if defined(JS_NUNBOX32) #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) +#define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << 32) + #define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 @@ -218,6 +149,8 @@ #elif defined(JS_PUNBOX64) +#define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) + #define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL #define JSVAL_TAG_MASK 0xFFFF800000000000LL #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type))) @@ -267,9 +200,6 @@ /** magic value passed to natives to indicate construction */ JS_IS_CONSTRUCTING, - /** arguments.callee has been overwritten */ - JS_OVERWRITTEN_CALLEE, - /** value of static block object slot */ JS_BLOCK_NEEDS_CLONE, @@ -294,686 +224,22 @@ JS_WHY_MAGIC_COUNT } JSWhyMagic; -#if defined(IS_LITTLE_ENDIAN) -# if defined(JS_NUNBOX32) -typedef union jsval_layout -{ - uint64_t asBits; - struct { - union { - int32_t i32; - uint32_t u32; - uint32_t boo; // Don't use |bool| -- it must be four bytes. - JSString* str; - JS::Symbol* sym; - JSObject* obj; - js::gc::Cell* cell; - void* ptr; - JSWhyMagic why; - size_t word; - uintptr_t uintptr; - } payload; - JSValueTag tag; - } s; - double asDouble; - void* asPtr; -} JSVAL_ALIGNMENT jsval_layout; -# elif defined(JS_PUNBOX64) -typedef union jsval_layout -{ - uint64_t asBits; -#if !defined(_WIN64) - /* MSVC does not pack these correctly :-( */ - struct { - uint64_t payload47 : 47; - JSValueTag tag : 17; - } debugView; -#endif - struct { - union { - int32_t i32; - uint32_t u32; - JSWhyMagic why; - } payload; - } s; - double asDouble; - void* asPtr; - size_t asWord; - uintptr_t asUIntPtr; -} JSVAL_ALIGNMENT jsval_layout; -# endif /* JS_PUNBOX64 */ -#else /* defined(IS_LITTLE_ENDIAN) */ -# if defined(JS_NUNBOX32) -typedef union jsval_layout -{ - uint64_t asBits; - struct { - JSValueTag tag; - union { - int32_t i32; - uint32_t u32; - uint32_t boo; // Don't use |bool| -- it must be four bytes. - JSString* str; - JS::Symbol* sym; - JSObject* obj; - js::gc::Cell* cell; - void* ptr; - JSWhyMagic why; - size_t word; - uintptr_t uintptr; - } payload; - } s; - double asDouble; - void* asPtr; -} JSVAL_ALIGNMENT jsval_layout; -# elif defined(JS_PUNBOX64) -typedef union jsval_layout -{ - uint64_t asBits; - struct { - JSValueTag tag : 17; - uint64_t payload47 : 47; - } debugView; - struct { - uint32_t padding; - union { - int32_t i32; - uint32_t u32; - JSWhyMagic why; - } payload; - } s; - double asDouble; - void* asPtr; - size_t asWord; - uintptr_t asUIntPtr; -} JSVAL_ALIGNMENT jsval_layout; -# endif /* JS_PUNBOX64 */ -#endif /* defined(IS_LITTLE_ENDIAN) */ - -JS_STATIC_ASSERT(sizeof(jsval_layout) == 8); - -/* - * For codesize purposes on some platforms, it's important that the - * compiler know that JS::Values constructed from constant values can be - * folded to constant bit patterns at compile time, rather than - * constructed at runtime. Doing this requires a fair amount of C++11 - * features, which are not supported on all of our compilers. Set up - * some defines and helper macros in an attempt to confine the ugliness - * here, rather than scattering it all about the file. The important - * features are: - * - * - constexpr; - * - defaulted functions; - * - C99-style designated initializers. - */ -#if defined(__clang__) -# if __has_feature(cxx_constexpr) && __has_feature(cxx_defaulted_functions) -# define JS_VALUE_IS_CONSTEXPR -# endif -#elif defined(__GNUC__) -/* - * We need 4.5 for defaulted functions, 4.6 for constexpr, 4.7 because 4.6 - * doesn't understand |(X) { .field = ... }| syntax, and 4.7.3 because - * versions prior to that have bugs in the C++ front-end that cause crashes. - */ -# if MOZ_GCC_VERSION_AT_LEAST(4, 7, 3) -# define JS_VALUE_IS_CONSTEXPR -# endif -#endif - -#if defined(JS_VALUE_IS_CONSTEXPR) -# define JS_RETURN_LAYOUT_FROM_BITS(BITS) \ - return (jsval_layout) { .asBits = (BITS) } -# define JS_VALUE_CONSTEXPR MOZ_CONSTEXPR -# define JS_VALUE_CONSTEXPR_VAR MOZ_CONSTEXPR_VAR -#else -# define JS_RETURN_LAYOUT_FROM_BITS(BITS) \ - jsval_layout l; \ - l.asBits = (BITS); \ - return l; -# define JS_VALUE_CONSTEXPR -# define JS_VALUE_CONSTEXPR_VAR const -#endif - -#if defined(JS_NUNBOX32) - -/* - * N.B. GCC, in some but not all cases, chooses to emit signed comparison of - * JSValueTag even though its underlying type has been forced to be uint32_t. - * Thus, all comparisons should explicitly cast operands to uint32_t. - */ - -static inline JS_VALUE_CONSTEXPR jsval_layout -BUILD_JSVAL(JSValueTag tag, uint32_t payload) -{ - JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << 32) | payload); -} - -static inline bool -JSVAL_IS_DOUBLE_IMPL(jsval_layout l) -{ - return (uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_CLEAR; -} - -static inline jsval_layout -DOUBLE_TO_JSVAL_IMPL(double d) -{ - jsval_layout l; - l.asDouble = d; - MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); - return l; -} - -static inline bool -JSVAL_IS_INT32_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_INT32; -} - -static inline int32_t -JSVAL_TO_INT32_IMPL(jsval_layout l) -{ - return l.s.payload.i32; -} - -static inline JS_VALUE_CONSTEXPR jsval_layout -INT32_TO_JSVAL_IMPL(int32_t i) -{ -#if defined(JS_VALUE_IS_CONSTEXPR) - return BUILD_JSVAL(JSVAL_TAG_INT32, i); -#else - jsval_layout l; - l.s.tag = JSVAL_TAG_INT32; - l.s.payload.i32 = i; - return l; -#endif -} - -static inline bool -JSVAL_IS_NUMBER_IMPL(jsval_layout l) -{ - JSValueTag tag = l.s.tag; - MOZ_ASSERT(tag != JSVAL_TAG_CLEAR); - return (uint32_t)tag <= (uint32_t)JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET; -} - -static inline bool -JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_UNDEFINED; -} - -static inline bool -JSVAL_IS_STRING_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_STRING; -} - -static inline jsval_layout -STRING_TO_JSVAL_IMPL(JSString* str) -{ - jsval_layout l; - MOZ_ASSERT(uintptr_t(str) > 0x1000); - l.s.tag = JSVAL_TAG_STRING; - l.s.payload.str = str; - return l; -} - -static inline JSString* -JSVAL_TO_STRING_IMPL(jsval_layout l) -{ - return l.s.payload.str; -} - -static inline bool -JSVAL_IS_SYMBOL_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_SYMBOL; -} - -static inline jsval_layout -SYMBOL_TO_JSVAL_IMPL(JS::Symbol* sym) -{ - jsval_layout l; - MOZ_ASSERT(uintptr_t(sym) > 0x1000); - l.s.tag = JSVAL_TAG_SYMBOL; - l.s.payload.sym = sym; - return l; -} - -static inline JS::Symbol* -JSVAL_TO_SYMBOL_IMPL(jsval_layout l) -{ - return l.s.payload.sym; -} - -static inline bool -JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_BOOLEAN; -} - -static inline bool -JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) -{ - return l.s.payload.boo; -} - -static inline jsval_layout -BOOLEAN_TO_JSVAL_IMPL(bool b) -{ - jsval_layout l; - l.s.tag = JSVAL_TAG_BOOLEAN; - l.s.payload.boo = b; - return l; -} - -static inline bool -JSVAL_IS_MAGIC_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_MAGIC; -} - -static inline bool -JSVAL_IS_OBJECT_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_OBJECT; -} - -static inline bool -JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) -{ - return (uint32_t)l.s.tag < (uint32_t)JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET; -} - -static inline bool -JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) -{ - MOZ_ASSERT((uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_OBJECT); - return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET; -} - -static inline JSObject* -JSVAL_TO_OBJECT_IMPL(jsval_layout l) -{ - return l.s.payload.obj; -} - -static inline jsval_layout -OBJECT_TO_JSVAL_IMPL(JSObject* obj) -{ - jsval_layout l; - MOZ_ASSERT(uintptr_t(obj) > 0x1000 || uintptr_t(obj) == 0x42); - l.s.tag = JSVAL_TAG_OBJECT; - l.s.payload.obj = obj; - return l; -} - -static inline bool -JSVAL_IS_NULL_IMPL(jsval_layout l) -{ - return l.s.tag == JSVAL_TAG_NULL; -} - -static inline jsval_layout -PRIVATE_PTR_TO_JSVAL_IMPL(void* ptr) -{ - jsval_layout l; - MOZ_ASSERT(((uint32_t)ptr & 1) == 0); - l.s.tag = (JSValueTag)0; - l.s.payload.ptr = ptr; - MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); - return l; -} - -static inline void* -JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) -{ - return l.s.payload.ptr; -} - -static inline bool -JSVAL_IS_GCTHING_IMPL(jsval_layout l) -{ - /* gcc sometimes generates signed < without explicit casts. */ - return (uint32_t)l.s.tag >= (uint32_t)JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET; -} - -static inline js::gc::Cell* -JSVAL_TO_GCTHING_IMPL(jsval_layout l) -{ - return l.s.payload.cell; -} - -static inline uint32_t -JSVAL_TRACE_KIND_IMPL(jsval_layout l) -{ - static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String), - "Value type tags must correspond with JS::TraceKinds."); - static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol), - "Value type tags must correspond with JS::TraceKinds."); - static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object), - "Value type tags must correspond with JS::TraceKinds."); - return l.s.tag & 0x03; -} - -static inline bool -JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32) -{ - return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32; -} - -static inline bool -JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(jsval_layout l, bool b) -{ - return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == uint32_t(b)); -} - -static inline jsval_layout -MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) -{ - jsval_layout l; - l.s.tag = JSVAL_TAG_MAGIC; - l.s.payload.why = why; - return l; -} - -static inline jsval_layout -MAGIC_UINT32_TO_JSVAL_IMPL(uint32_t payload) -{ - jsval_layout l; - l.s.tag = JSVAL_TAG_MAGIC; - l.s.payload.u32 = payload; - return l; -} - -static inline bool -JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) -{ - JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag; - return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR); -} - -static inline JSValueType -JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) -{ - uint32_t type = l.s.tag & 0xF; - MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); - return (JSValueType)type; -} - -#elif defined(JS_PUNBOX64) - -static inline JS_VALUE_CONSTEXPR jsval_layout -BUILD_JSVAL(JSValueTag tag, uint64_t payload) -{ - JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << JSVAL_TAG_SHIFT) | payload); -} - -static inline bool -JSVAL_IS_DOUBLE_IMPL(jsval_layout l) -{ - return l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE; -} - -static inline jsval_layout -DOUBLE_TO_JSVAL_IMPL(double d) -{ - jsval_layout l; - l.asDouble = d; - MOZ_ASSERT(l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE); - return l; -} - -static inline bool -JSVAL_IS_INT32_IMPL(jsval_layout l) -{ - return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_INT32; -} - -static inline int32_t -JSVAL_TO_INT32_IMPL(jsval_layout l) -{ - return (int32_t)l.asBits; -} - -static inline JS_VALUE_CONSTEXPR jsval_layout -INT32_TO_JSVAL_IMPL(int32_t i32) -{ - JS_RETURN_LAYOUT_FROM_BITS(((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32); -} - -static inline bool -JSVAL_IS_NUMBER_IMPL(jsval_layout l) -{ - return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET; -} - -static inline bool -JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) -{ - return l.asBits == JSVAL_SHIFTED_TAG_UNDEFINED; -} - -static inline bool -JSVAL_IS_STRING_IMPL(jsval_layout l) -{ - return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING; -} - -static inline jsval_layout -STRING_TO_JSVAL_IMPL(JSString* str) -{ - jsval_layout l; - uint64_t strBits = (uint64_t)str; - MOZ_ASSERT(uintptr_t(str) > 0x1000); - MOZ_ASSERT((strBits >> JSVAL_TAG_SHIFT) == 0); - l.asBits = strBits | JSVAL_SHIFTED_TAG_STRING; - return l; -} - -static inline JSString* -JSVAL_TO_STRING_IMPL(jsval_layout l) -{ - return (JSString*)(l.asBits & JSVAL_PAYLOAD_MASK); -} - -static inline bool -JSVAL_IS_SYMBOL_IMPL(jsval_layout l) -{ - return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_SYMBOL; -} - -static inline jsval_layout -SYMBOL_TO_JSVAL_IMPL(JS::Symbol* sym) -{ - jsval_layout l; - uint64_t symBits = (uint64_t)sym; - MOZ_ASSERT(uintptr_t(sym) > 0x1000); - MOZ_ASSERT((symBits >> JSVAL_TAG_SHIFT) == 0); - l.asBits = symBits | JSVAL_SHIFTED_TAG_SYMBOL; - return l; -} - -static inline JS::Symbol* -JSVAL_TO_SYMBOL_IMPL(jsval_layout l) -{ - return (JS::Symbol*)(l.asBits & JSVAL_PAYLOAD_MASK); -} - -static inline bool -JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) -{ - return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_BOOLEAN; -} - -static inline bool -JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) -{ - return (bool)(l.asBits & JSVAL_PAYLOAD_MASK); -} - -static inline jsval_layout -BOOLEAN_TO_JSVAL_IMPL(bool b) -{ - jsval_layout l; - l.asBits = ((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN; - return l; -} - -static inline bool -JSVAL_IS_MAGIC_IMPL(jsval_layout l) -{ - return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC; -} - -static inline bool -JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) -{ - return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET; -} - -static inline bool -JSVAL_IS_OBJECT_IMPL(jsval_layout l) -{ - MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); - return l.asBits >= JSVAL_SHIFTED_TAG_OBJECT; -} - -static inline bool -JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) -{ - MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); - return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET; -} - -static inline JSObject* -JSVAL_TO_OBJECT_IMPL(jsval_layout l) -{ - uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; - MOZ_ASSERT((ptrBits & 0x7) == 0); - return (JSObject*)ptrBits; -} - -static inline jsval_layout -OBJECT_TO_JSVAL_IMPL(JSObject* obj) -{ - jsval_layout l; - uint64_t objBits = (uint64_t)obj; - MOZ_ASSERT(uintptr_t(obj) > 0x1000 || uintptr_t(obj) == 0x42); - MOZ_ASSERT((objBits >> JSVAL_TAG_SHIFT) == 0); - l.asBits = objBits | JSVAL_SHIFTED_TAG_OBJECT; - return l; -} - -static inline bool -JSVAL_IS_NULL_IMPL(jsval_layout l) -{ - return l.asBits == JSVAL_SHIFTED_TAG_NULL; -} - -static inline bool -JSVAL_IS_GCTHING_IMPL(jsval_layout l) -{ - return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET; -} - -static inline js::gc::Cell* -JSVAL_TO_GCTHING_IMPL(jsval_layout l) -{ - uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; - MOZ_ASSERT((ptrBits & 0x7) == 0); - return reinterpret_cast(ptrBits); -} - -static inline uint32_t -JSVAL_TRACE_KIND_IMPL(jsval_layout l) -{ - static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String), - "Value type tags must correspond with JS::TraceKinds."); - static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol), - "Value type tags must correspond with JS::TraceKinds."); - static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object), - "Value type tags must correspond with JS::TraceKinds."); - return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) & 0x03; -} - -static inline jsval_layout -PRIVATE_PTR_TO_JSVAL_IMPL(void* ptr) -{ - jsval_layout l; - uint64_t ptrBits = (uint64_t)ptr; - MOZ_ASSERT((ptrBits & 1) == 0); - l.asBits = ptrBits >> 1; - MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); - return l; -} - -static inline void* -JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) -{ - MOZ_ASSERT((l.asBits & 0x8000000000000000LL) == 0); - return (void*)(l.asBits << 1); -} - -static inline bool -JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32) -{ - return l.asBits == (((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32); -} - -static inline bool -JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(jsval_layout l, bool b) -{ - return l.asBits == (((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN); -} - -static inline jsval_layout -MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) -{ - jsval_layout l; - l.asBits = ((uint64_t)(uint32_t)why) | JSVAL_SHIFTED_TAG_MAGIC; - return l; -} - -static inline jsval_layout -MAGIC_UINT32_TO_JSVAL_IMPL(uint32_t payload) -{ - jsval_layout l; - l.asBits = ((uint64_t)payload) | JSVAL_SHIFTED_TAG_MAGIC; - return l; -} - -static inline bool -JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) -{ - uint64_t lbits = lhs.asBits, rbits = rhs.asBits; - return (lbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE && rbits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE) || - (((lbits ^ rbits) & 0xFFFF800000000000LL) == 0); -} - -static inline JSValueType -JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) -{ - uint64_t type = (l.asBits >> JSVAL_TAG_SHIFT) & 0xF; - MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); - return (JSValueType)type; -} +namespace JS { -#endif /* JS_PUNBOX64 */ +static inline constexpr JS::Value UndefinedValue(); +static inline JS::Value PoisonedObjectValue(JSObject* obj); -static inline bool -JSVAL_IS_TRACEABLE_IMPL(jsval_layout l) -{ - return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l); -} +namespace detail { -static inline jsval_layout JSVAL_TO_IMPL(JS::Value v); -static inline JS_VALUE_CONSTEXPR JS::Value IMPL_TO_JSVAL(jsval_layout l); +constexpr int CanonicalizedNaNSignBit = 0; +constexpr uint64_t CanonicalizedNaNSignificand = 0x8000000000000ULL; -namespace JS { +constexpr uint64_t CanonicalizedNaNBits = + mozilla::SpecificNaNBits::value; -static inline JS_VALUE_CONSTEXPR JS::Value UndefinedValue(); +} // namespace detail /** * Returns a generic quiet NaN value, with all payload bits set to zero. @@ -984,7 +250,8 @@ static MOZ_ALWAYS_INLINE double GenericNaN() { - return mozilla::SpecificNaN(0, 0x8000000000000ULL); + return mozilla::SpecificNaN(detail::CanonicalizedNaNSignBit, + detail::CanonicalizedNaNSignificand); } /* MSVC with PGO miscompiles this function. */ @@ -1033,17 +300,21 @@ * 32-bit user code should avoid copying jsval/JS::Value as much as possible, * preferring to pass by const Value&. */ -class Value +class MOZ_NON_PARAM alignas(8) Value { public: +#if defined(JS_NUNBOX32) + using PayloadType = uint32_t; +#elif defined(JS_PUNBOX64) + using PayloadType = uint64_t; +#endif + /* * N.B. the default constructor leaves Value unitialized. Adding a default * constructor prevents Value from being stored in a union. */ -#if defined(JS_VALUE_IS_CONSTEXPR) Value() = default; Value(const Value& v) = default; -#endif /** * Returns false if creating a NumberValue containing the given type would @@ -1057,15 +328,15 @@ /*** Mutators ***/ void setNull() { - data.asBits = BUILD_JSVAL(JSVAL_TAG_NULL, 0).asBits; + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_NULL, 0); } void setUndefined() { - data.asBits = BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0).asBits; + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0); } void setInt32(int32_t i) { - data = INT32_TO_JSVAL_IMPL(i); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i)); } int32_t& getInt32Ref() { @@ -1074,7 +345,10 @@ } void setDouble(double d) { - data = DOUBLE_TO_JSVAL_IMPL(d); + // Don't assign to data.asDouble to fix a miscompilation with + // GCC 5.2.1 and 5.3.1. See bug 1312488. + data = layout(d); + MOZ_ASSERT(isDouble()); } void setNaN() { @@ -1087,27 +361,45 @@ } void setString(JSString* str) { - data = STRING_TO_JSVAL_IMPL(str); + MOZ_ASSERT(uintptr_t(str) > 0x1000); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_STRING, PayloadType(str)); } void setSymbol(JS::Symbol* sym) { - data = SYMBOL_TO_JSVAL_IMPL(sym); + MOZ_ASSERT(uintptr_t(sym) > 0x1000); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym)); } void setObject(JSObject& obj) { - data = OBJECT_TO_JSVAL_IMPL(&obj); + MOZ_ASSERT(uintptr_t(&obj) > 0x1000 || uintptr_t(&obj) == 0x48); +#if defined(JS_PUNBOX64) + // VisualStudio cannot contain parenthesized C++ style cast and shift + // inside decltype in template parameter: + // AssertionConditionType> 1))> + // It throws syntax error. + MOZ_ASSERT((((uintptr_t)&obj) >> JSVAL_TAG_SHIFT) == 0); +#endif + setObjectNoCheck(&obj); + } + + private: + void setObjectNoCheck(JSObject* obj) { + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_OBJECT, PayloadType(obj)); } + friend inline Value PoisonedObjectValue(JSObject* obj); + + public: void setBoolean(bool b) { - data = BOOLEAN_TO_JSVAL_IMPL(b); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(b)); } void setMagic(JSWhyMagic why) { - data = MAGIC_TO_JSVAL_IMPL(why); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, uint32_t(why)); } void setMagicUint32(uint32_t payload) { - data = MAGIC_UINT32_TO_JSVAL_IMPL(payload); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, payload); } bool setNumber(uint32_t ui) { @@ -1144,14 +436,54 @@ data.asBits = tmp; } + private: + JSValueTag toTag() const { +#if defined(JS_NUNBOX32) + return data.s.tag; +#elif defined(JS_PUNBOX64) + return JSValueTag(data.asBits >> JSVAL_TAG_SHIFT); +#endif + } + + public: + /*** JIT-only interfaces to interact with and create raw Values ***/ +#if defined(JS_NUNBOX32) + PayloadType toNunboxPayload() const { + return data.s.payload.i32; + } + + JSValueTag toNunboxTag() const { + return data.s.tag; + } +#elif defined(JS_PUNBOX64) + const void* bitsAsPunboxPointer() const { + return reinterpret_cast(data.asBits); + } +#endif + /*** Value type queries ***/ + /* + * N.B. GCC, in some but not all cases, chooses to emit signed comparison + * of JSValueTag even though its underlying type has been forced to be + * uint32_t. Thus, all comparisons should explicitly cast operands to + * uint32_t. + */ + bool isUndefined() const { - return JSVAL_IS_UNDEFINED_IMPL(data); +#if defined(JS_NUNBOX32) + return toTag() == JSVAL_TAG_UNDEFINED; +#elif defined(JS_PUNBOX64) + return data.asBits == JSVAL_SHIFTED_TAG_UNDEFINED; +#endif } bool isNull() const { - return JSVAL_IS_NULL_IMPL(data); +#if defined(JS_NUNBOX32) + return toTag() == JSVAL_TAG_NULL; +#elif defined(JS_PUNBOX64) + return data.asBits == JSVAL_SHIFTED_TAG_NULL; +#endif } bool isNullOrUndefined() const { @@ -1159,73 +491,109 @@ } bool isInt32() const { - return JSVAL_IS_INT32_IMPL(data); + return toTag() == JSVAL_TAG_INT32; } bool isInt32(int32_t i32) const { - return JSVAL_IS_SPECIFIC_INT32_IMPL(data, i32); + return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i32)); } bool isDouble() const { - return JSVAL_IS_DOUBLE_IMPL(data); +#if defined(JS_NUNBOX32) + return uint32_t(toTag()) <= uint32_t(JSVAL_TAG_CLEAR); +#elif defined(JS_PUNBOX64) + return (data.asBits | mozilla::DoubleTypeTraits::kSignBit) <= JSVAL_SHIFTED_TAG_MAX_DOUBLE; +#endif } bool isNumber() const { - return JSVAL_IS_NUMBER_IMPL(data); +#if defined(JS_NUNBOX32) + MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR); + return uint32_t(toTag()) <= uint32_t(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET); +#elif defined(JS_PUNBOX64) + return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET; +#endif } bool isString() const { - return JSVAL_IS_STRING_IMPL(data); + return toTag() == JSVAL_TAG_STRING; } bool isSymbol() const { - return JSVAL_IS_SYMBOL_IMPL(data); + return toTag() == JSVAL_TAG_SYMBOL; } bool isObject() const { - return JSVAL_IS_OBJECT_IMPL(data); +#if defined(JS_NUNBOX32) + return toTag() == JSVAL_TAG_OBJECT; +#elif defined(JS_PUNBOX64) + MOZ_ASSERT((data.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); + return data.asBits >= JSVAL_SHIFTED_TAG_OBJECT; +#endif } bool isPrimitive() const { - return JSVAL_IS_PRIMITIVE_IMPL(data); +#if defined(JS_NUNBOX32) + return uint32_t(toTag()) < uint32_t(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET); +#elif defined(JS_PUNBOX64) + return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET; +#endif } bool isObjectOrNull() const { - return JSVAL_IS_OBJECT_OR_NULL_IMPL(data); + MOZ_ASSERT(uint32_t(toTag()) <= uint32_t(JSVAL_TAG_OBJECT)); +#if defined(JS_NUNBOX32) + return uint32_t(toTag()) >= uint32_t(JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET); +#elif defined(JS_PUNBOX64) + return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET; +#endif } bool isGCThing() const { - return JSVAL_IS_GCTHING_IMPL(data); +#if defined(JS_NUNBOX32) + /* gcc sometimes generates signed < without explicit casts. */ + return uint32_t(toTag()) >= uint32_t(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET); +#elif defined(JS_PUNBOX64) + return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET; +#endif } bool isBoolean() const { - return JSVAL_IS_BOOLEAN_IMPL(data); + return toTag() == JSVAL_TAG_BOOLEAN; } bool isTrue() const { - return JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(data, true); + return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(true)); } bool isFalse() const { - return JSVAL_IS_SPECIFIC_BOOLEAN_IMPL(data, false); + return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(false)); } bool isMagic() const { - return JSVAL_IS_MAGIC_IMPL(data); + return toTag() == JSVAL_TAG_MAGIC; } bool isMagic(JSWhyMagic why) const { MOZ_ASSERT_IF(isMagic(), data.s.payload.why == why); - return JSVAL_IS_MAGIC_IMPL(data); + return isMagic(); } bool isMarkable() const { - return JSVAL_IS_TRACEABLE_IMPL(data); + return isGCThing() && !isNull(); } JS::TraceKind traceKind() const { MOZ_ASSERT(isMarkable()); - return JS::TraceKind(JSVAL_TRACE_KIND_IMPL(data)); + static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String), + "Value type tags must correspond with JS::TraceKinds."); + static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol), + "Value type tags must correspond with JS::TraceKinds."); + static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object), + "Value type tags must correspond with JS::TraceKinds."); + if (MOZ_UNLIKELY(isPrivateGCThing())) + return JS::GCThingTraceKind(toGCThing()); + return JS::TraceKind(toTag() & 0x03); } JSWhyMagic whyMagic() const { @@ -1254,7 +622,11 @@ int32_t toInt32() const { MOZ_ASSERT(isInt32()); - return JSVAL_TO_INT32_IMPL(data); +#if defined(JS_NUNBOX32) + return data.s.payload.i32; +#elif defined(JS_PUNBOX64) + return int32_t(data.asBits); +#endif } double toDouble() const { @@ -1269,27 +641,56 @@ JSString* toString() const { MOZ_ASSERT(isString()); - return JSVAL_TO_STRING_IMPL(data); +#if defined(JS_NUNBOX32) + return data.s.payload.str; +#elif defined(JS_PUNBOX64) + return reinterpret_cast(data.asBits & JSVAL_PAYLOAD_MASK); +#endif } JS::Symbol* toSymbol() const { MOZ_ASSERT(isSymbol()); - return JSVAL_TO_SYMBOL_IMPL(data); +#if defined(JS_NUNBOX32) + return data.s.payload.sym; +#elif defined(JS_PUNBOX64) + return reinterpret_cast(data.asBits & JSVAL_PAYLOAD_MASK); +#endif } JSObject& toObject() const { MOZ_ASSERT(isObject()); - return *JSVAL_TO_OBJECT_IMPL(data); +#if defined(JS_NUNBOX32) + return *data.s.payload.obj; +#elif defined(JS_PUNBOX64) + return *toObjectOrNull(); +#endif } JSObject* toObjectOrNull() const { MOZ_ASSERT(isObjectOrNull()); - return JSVAL_TO_OBJECT_IMPL(data); +#if defined(JS_NUNBOX32) + return data.s.payload.obj; +#elif defined(JS_PUNBOX64) + uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK; + MOZ_ASSERT((ptrBits & 0x7) == 0); + return reinterpret_cast(ptrBits); +#endif } js::gc::Cell* toGCThing() const { MOZ_ASSERT(isGCThing()); - return JSVAL_TO_GCTHING_IMPL(data); +#if defined(JS_NUNBOX32) + return data.s.payload.cell; +#elif defined(JS_PUNBOX64) + uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK; + MOZ_ASSERT((ptrBits & 0x7) == 0); + return reinterpret_cast(ptrBits); +#endif + } + + js::gc::Cell* toMarkablePointer() const { + MOZ_ASSERT(isMarkable()); + return toGCThing(); } GCCellPtr toGCCellPtr() const { @@ -1298,7 +699,11 @@ bool toBoolean() const { MOZ_ASSERT(isBoolean()); - return JSVAL_TO_BOOLEAN_IMPL(data); +#if defined(JS_NUNBOX32) + return bool(data.s.payload.boo); +#elif defined(JS_PUNBOX64) + return bool(data.asBits & JSVAL_PAYLOAD_MASK); +#endif } uint32_t payloadAsRawUint32() const { @@ -1311,7 +716,9 @@ } JSValueType extractNonDoubleType() const { - return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data); + uint32_t type = toTag() & 0xF; + MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); + return JSValueType(type); } /* @@ -1324,12 +731,24 @@ */ void setPrivate(void* ptr) { - data = PRIVATE_PTR_TO_JSVAL_IMPL(ptr); + MOZ_ASSERT((uintptr_t(ptr) & 1) == 0); +#if defined(JS_NUNBOX32) + data.s.tag = JSValueTag(0); + data.s.payload.ptr = ptr; +#elif defined(JS_PUNBOX64) + data.asBits = uintptr_t(ptr) >> 1; +#endif + MOZ_ASSERT(isDouble()); } void* toPrivate() const { - MOZ_ASSERT(JSVAL_IS_DOUBLE_IMPL(data)); - return JSVAL_TO_PRIVATE_PTR_IMPL(data); + MOZ_ASSERT(isDouble()); +#if defined(JS_NUNBOX32) + return data.s.payload.ptr; +#elif defined(JS_PUNBOX64) + MOZ_ASSERT((data.asBits & 0x8000000000000000ULL) == 0); + return reinterpret_cast(data.asBits << 1); +#endif } void setPrivateUint32(uint32_t ui) { @@ -1342,17 +761,35 @@ } /* - * An unmarked value is just a void* cast as a Value. Thus, the Value is - * not safe for GC and must not be marked. This API avoids raw casts - * and the ensuing strict-aliasing warnings. + * Private GC Thing API + * + * Non-JSObject, JSString, and JS::Symbol cells may be put into the 64-bit + * payload as private GC things. Such Values are considered isMarkable() + * and isGCThing(), and as such, automatically marked. Their traceKind() + * is gotten via their cells. */ - void setUnmarkedPtr(void* ptr) { - data.asPtr = ptr; + void setPrivateGCThing(js::gc::Cell* cell) { + MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String, + "Private GC thing Values must not be strings. Make a StringValue instead."); + MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol, + "Private GC thing Values must not be symbols. Make a SymbolValue instead."); + MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object, + "Private GC thing Values must not be objects. Make an ObjectValue instead."); + + MOZ_ASSERT(uintptr_t(cell) > 0x1000); +#if defined(JS_PUNBOX64) + // VisualStudio cannot contain parenthesized C++ style cast and shift + // inside decltype in template parameter: + // AssertionConditionType> 1))> + // It throws syntax error. + MOZ_ASSERT((((uintptr_t)cell) >> JSVAL_TAG_SHIFT) == 0); +#endif + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_PRIVATE_GCTHING, PayloadType(cell)); } - void* toUnmarkedPtr() const { - return data.asPtr; + bool isPrivateGCThing() const { + return toTag() == JSVAL_TAG_PRIVATE_GCTHING; } const size_t* payloadWord() const { @@ -1378,12 +815,117 @@ private: #endif - jsval_layout data; +#if MOZ_LITTLE_ENDIAN +# if defined(JS_NUNBOX32) + union layout { + uint64_t asBits; + struct { + union { + int32_t i32; + uint32_t u32; + uint32_t boo; // Don't use |bool| -- it must be four bytes. + JSString* str; + JS::Symbol* sym; + JSObject* obj; + js::gc::Cell* cell; + void* ptr; + JSWhyMagic why; + size_t word; + uintptr_t uintptr; + } payload; + JSValueTag tag; + } s; + double asDouble; + void* asPtr; + + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} + explicit constexpr layout(uint64_t bits) : asBits(bits) {} + explicit constexpr layout(double d) : asDouble(d) {} + } data; +# elif defined(JS_PUNBOX64) + union layout { + uint64_t asBits; +#if !defined(_WIN64) + /* MSVC does not pack these correctly :-( */ + struct { + uint64_t payload47 : 47; + JSValueTag tag : 17; + } debugView; +#endif + struct { + union { + int32_t i32; + uint32_t u32; + JSWhyMagic why; + } payload; + } s; + double asDouble; + void* asPtr; + size_t asWord; + uintptr_t asUIntPtr; + + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} + explicit constexpr layout(uint64_t bits) : asBits(bits) {} + explicit constexpr layout(double d) : asDouble(d) {} + } data; +# endif /* JS_PUNBOX64 */ +#else /* MOZ_LITTLE_ENDIAN */ +# if defined(JS_NUNBOX32) + union layout { + uint64_t asBits; + struct { + JSValueTag tag; + union { + int32_t i32; + uint32_t u32; + uint32_t boo; // Don't use |bool| -- it must be four bytes. + JSString* str; + JS::Symbol* sym; + JSObject* obj; + js::gc::Cell* cell; + void* ptr; + JSWhyMagic why; + size_t word; + uintptr_t uintptr; + } payload; + } s; + double asDouble; + void* asPtr; + + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} + explicit constexpr layout(uint64_t bits) : asBits(bits) {} + explicit constexpr layout(double d) : asDouble(d) {} + } data; +# elif defined(JS_PUNBOX64) + union layout { + uint64_t asBits; + struct { + JSValueTag tag : 17; + uint64_t payload47 : 47; + } debugView; + struct { + uint32_t padding; + union { + int32_t i32; + uint32_t u32; + JSWhyMagic why; + } payload; + } s; + double asDouble; + void* asPtr; + size_t asWord; + uintptr_t asUIntPtr; + + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} + explicit constexpr layout(uint64_t bits) : asBits(bits) {} + explicit constexpr layout(double d) : asDouble(d) {} + } data; +# endif /* JS_PUNBOX64 */ +#endif /* MOZ_LITTLE_ENDIAN */ private: -#if defined(JS_VALUE_IS_CONSTEXPR) - MOZ_IMPLICIT JS_VALUE_CONSTEXPR Value(jsval_layout layout) : data(layout) {} -#endif + explicit constexpr Value(uint64_t asBits) : data(asBits) {} + explicit constexpr Value(double d) : data(d) {} void staticAssertions() { JS_STATIC_ASSERT(sizeof(JSValueType) == 1); @@ -1392,11 +934,86 @@ JS_STATIC_ASSERT(sizeof(Value) == 8); } - friend jsval_layout (::JSVAL_TO_IMPL)(Value); - friend Value JS_VALUE_CONSTEXPR (::IMPL_TO_JSVAL)(jsval_layout l); - friend Value JS_VALUE_CONSTEXPR (JS::UndefinedValue)(); + friend constexpr Value JS::UndefinedValue(); + + public: + static constexpr uint64_t + bitsFromTagAndPayload(JSValueTag tag, PayloadType payload) + { +#if defined(JS_NUNBOX32) + return (uint64_t(uint32_t(tag)) << 32) | payload; +#elif defined(JS_PUNBOX64) + return (uint64_t(uint32_t(tag)) << JSVAL_TAG_SHIFT) | payload; +#endif + } + + static constexpr Value + fromTagAndPayload(JSValueTag tag, PayloadType payload) + { + return fromRawBits(bitsFromTagAndPayload(tag, payload)); + } + + static constexpr Value + fromRawBits(uint64_t asBits) { + return Value(asBits); + } + + static constexpr Value + fromInt32(int32_t i) { + return fromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i)); + } + + static constexpr Value + fromDouble(double d) { + return Value(d); + } +} JS_HAZ_GC_POINTER; + +/** + * This is a null-constructible structure that can convert to and from + * a Value, allowing UninitializedValue to be stored in unions. + */ +struct MOZ_NON_PARAM alignas(8) UninitializedValue +{ + private: + uint64_t bits; + + public: + UninitializedValue() = default; + UninitializedValue(const UninitializedValue&) = default; + MOZ_IMPLICIT UninitializedValue(const Value& val) : bits(val.asRawBits()) {} + + inline uint64_t asRawBits() const { + return bits; + } + + inline Value& asValueRef() { + return *reinterpret_cast(this); + } + inline const Value& asValueRef() const { + return *reinterpret_cast(this); + } + + inline operator Value&() { + return asValueRef(); + } + inline operator Value const&() const { + return asValueRef(); + } + inline operator Value() const { + return asValueRef(); + } + + inline void operator=(Value const& other) { + asValueRef() = other; + } }; +static_assert(sizeof(Value) == 8, "Value size must leave three tag bits, be a binary power, and is ubiquitously depended upon everywhere"); + +static_assert(sizeof(UninitializedValue) == sizeof(Value), "Value and UninitializedValue must be the same size"); +static_assert(alignof(UninitializedValue) == alignof(Value), "Value and UninitializedValue must have same alignment"); + inline bool IsOptimizedPlaceholderMagicValue(const Value& v) { @@ -1424,22 +1041,16 @@ return v; } -static inline JS_VALUE_CONSTEXPR Value +static inline constexpr Value UndefinedValue() { -#if defined(JS_VALUE_IS_CONSTEXPR) - return Value(BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0)); -#else - JS::Value v; - v.setUndefined(); - return v; -#endif + return Value::fromTagAndPayload(JSVAL_TAG_UNDEFINED, 0); } -static inline JS_VALUE_CONSTEXPR Value +static inline constexpr Value Int32Value(int32_t i32) { - return IMPL_TO_JSVAL(INT32_TO_JSVAL_IMPL(i32)); + return Value::fromInt32(i32); } static inline Value @@ -1450,27 +1061,23 @@ return v; } -static inline JS_VALUE_CONSTEXPR Value +static inline Value CanonicalizedDoubleValue(double d) { - /* - * This is a manually inlined version of: - * d = JS_CANONICALIZE_NAN(d); - * return IMPL_TO_JSVAL(DOUBLE_TO_JSVAL_IMPL(d)); - * because GCC from XCode 3.1.4 miscompiles the above code. - */ -#if defined(JS_VALUE_IS_CONSTEXPR) - return IMPL_TO_JSVAL(MOZ_UNLIKELY(mozilla::IsNaN(d)) - ? (jsval_layout) { .asBits = 0x7FF8000000000000LL } - : (jsval_layout) { .asDouble = d }); -#else - jsval_layout l; - if (MOZ_UNLIKELY(d != d)) - l.asBits = 0x7FF8000000000000LL; - else - l.asDouble = d; - return IMPL_TO_JSVAL(l); -#endif + return MOZ_UNLIKELY(mozilla::IsNaN(d)) + ? Value::fromRawBits(detail::CanonicalizedNaNBits) + : Value::fromDouble(d); +} + +static inline bool +IsCanonicalized(double d) +{ + if (mozilla::IsInfinite(d) || mozilla::IsFinite(d)) + return true; + + uint64_t bits; + mozilla::BitwiseCast(d, &bits); + return (bits & ~mozilla::DoubleTypeTraits::kSignBit) == detail::CanonicalizedNaNBits; } static inline Value @@ -1541,7 +1148,7 @@ ObjectValueCrashOnTouch() { Value v; - v.setObject(*reinterpret_cast(0x42)); + v.setObject(*reinterpret_cast(0x48)); return v; } @@ -1607,12 +1214,12 @@ return Int32Value(i); } -static inline JS_VALUE_CONSTEXPR Value +static inline constexpr Value NumberValue(uint32_t i) { return i <= JSVAL_INT_MAX ? Int32Value(int32_t(i)) - : CanonicalizedDoubleValue(double(i)); + : Value::fromDouble(double(i)); } namespace detail { @@ -1683,10 +1290,32 @@ return v; } +static inline Value +PrivateGCThingValue(js::gc::Cell* cell) +{ + Value v; + v.setPrivateGCThing(cell); + return v; +} + +static inline Value +PoisonedObjectValue(JSObject* obj) +{ + Value v; + v.setObjectNoCheck(obj); + return v; +} + inline bool SameType(const Value& lhs, const Value& rhs) { - return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data); +#if defined(JS_NUNBOX32) + JSValueTag ltag = lhs.toTag(), rtag = rhs.toTag(); + return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR); +#elif defined(JS_PUNBOX64) + return (lhs.isDouble() && rhs.isDouble()) || + (((lhs.data.asBits ^ rhs.data.asBits) & 0xFFFF800000000000ULL) == 0); +#endif } } // namespace JS @@ -1695,24 +1324,35 @@ namespace JS { JS_PUBLIC_API(void) HeapValuePostBarrier(Value* valuep, const Value& prev, const Value& next); -} // namespace JS -namespace js { - -template <> struct GCMethods +template <> +struct GCPolicy { - static JS::Value initial() { return JS::UndefinedValue(); } + static Value initial() { return UndefinedValue(); } + static void trace(JSTracer* trc, Value* v, const char* name) { + js::UnsafeTraceManuallyBarrieredEdge(trc, v, name); + } + static bool isTenured(const Value& thing) { + return !thing.isGCThing() || !IsInsideNursery(thing.toGCThing()); + } }; -template <> struct GCMethods +} // namespace JS + +namespace js { + +template <> +struct BarrierMethods { - static JS::Value initial() { return JS::UndefinedValue(); } static gc::Cell* asGCThingOrNull(const JS::Value& v) { return v.isMarkable() ? v.toGCThing() : nullptr; } static void postBarrier(JS::Value* v, const JS::Value& prev, const JS::Value& next) { JS::HeapValuePostBarrier(v, prev, next); } + static void exposeToJS(const JS::Value& v) { + JS::ExposeValueToActiveJS(v); + } }; template class MutableValueOperations; @@ -1762,10 +1402,11 @@ JSObject* toObjectOrNull() const { return value().toObjectOrNull(); } gc::Cell* toGCThing() const { return value().toGCThing(); } JS::TraceKind traceKind() const { return value().traceKind(); } - uint64_t asRawBits() const { return value().asRawBits(); } + void* toPrivate() const { return value().toPrivate(); } + uint32_t toPrivateUint32() const { return value().toPrivateUint32(); } + uint64_t asRawBits() const { return value().asRawBits(); } JSValueType extractNonDoubleType() const { return value().extractNonDoubleType(); } - uint32_t toPrivateUint32() const { return value().toPrivateUint32(); } JSWhyMagic whyMagic() const { return value().whyMagic(); } uint32_t magicUint32() const { return value().magicUint32(); } @@ -1796,6 +1437,9 @@ void setSymbol(JS::Symbol* sym) { this->value().setSymbol(sym); } void setObject(JSObject& obj) { this->value().setObject(obj); } void setObjectOrNull(JSObject* arg) { this->value().setObjectOrNull(arg); } + void setPrivate(void* ptr) { this->value().setPrivate(ptr); } + void setPrivateUint32(uint32_t ui) { this->value().setPrivateUint32(ui); } + void setPrivateGCThing(js::gc::Cell* cell) { this->value().setPrivateGCThing(cell); } }; /* @@ -1824,6 +1468,7 @@ void setString(JSString* str) { setBarriered(JS::StringValue(str)); } void setSymbol(JS::Symbol* sym) { setBarriered(JS::SymbolValue(sym)); } void setObject(JSObject& obj) { setBarriered(JS::ObjectValue(obj)); } + void setPrivateGCThing(js::gc::Cell* cell) { setBarriered(JS::PrivateGCThingValue(cell)); } bool setNumber(uint32_t ui) { if (ui > JSVAL_INT_MAX) { @@ -1885,55 +1530,18 @@ return f(&val.toObject(), mozilla::Forward(args)...); if (val.isSymbol()) return f(val.toSymbol(), mozilla::Forward(args)...); + if (MOZ_UNLIKELY(val.isPrivateGCThing())) + return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward(args)...); MOZ_ASSERT(!val.isMarkable()); return F::defaultValue(val); } -template struct VoidDefaultAdaptor { static void defaultValue(S) {} }; +template struct VoidDefaultAdaptor { static void defaultValue(const S&) {} }; template struct IdentityDefaultAdaptor { static S defaultValue(const S& v) {return v;} }; -template struct BoolDefaultAdaptor { static bool defaultValue(S) { return v; } }; +template struct BoolDefaultAdaptor { static bool defaultValue(const S&) { return v; } }; } // namespace js -inline jsval_layout -JSVAL_TO_IMPL(JS::Value v) -{ - return v.data; -} - -inline JS_VALUE_CONSTEXPR JS::Value -IMPL_TO_JSVAL(jsval_layout l) -{ -#if defined(JS_VALUE_IS_CONSTEXPR) - return JS::Value(l); -#else - JS::Value v; - v.data = l; - return v; -#endif -} - -namespace JS { - -#ifdef JS_DEBUG -namespace detail { - -struct ValueAlignmentTester { char c; JS::Value v; }; -static_assert(sizeof(ValueAlignmentTester) == 16, - "JS::Value must be 16-byte-aligned"); - -struct LayoutAlignmentTester { char c; jsval_layout l; }; -static_assert(sizeof(LayoutAlignmentTester) == 16, - "jsval_layout must be 16-byte-aligned"); - -} // namespace detail -#endif /* JS_DEBUG */ - -} // namespace JS - -static_assert(sizeof(jsval_layout) == sizeof(JS::Value), - "jsval_layout and JS::Value must have identical layouts"); - /************************************************************************/ namespace JS { @@ -1945,7 +1553,4 @@ } // namespace JS -#undef JS_VALUE_IS_CONSTEXPR -#undef JS_RETURN_LAYOUT_FROM_BITS - #endif /* js_Value_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Vector.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Vector.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Vector.h @@ -34,15 +34,9 @@ template ::value>::Type -#endif + typename = typename mozilla::EnableIf::value>::Type > using Vector = mozilla::Vector; Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/jsalloc.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/jsalloc.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/jsalloc.h @@ -51,7 +51,7 @@ }; class ExclusiveContext; -void ReportOutOfMemory(ExclusiveContext* cxArg); +JS_FRIEND_API(void) ReportOutOfMemory(ExclusiveContext* cxArg); /* * Allocation policy that calls the system memory functions and reports errors @@ -132,7 +132,7 @@ bool checkSimulatedOOM() const { if (js::oom::ShouldFailWithOOM()) { - JS_ReportOutOfMemory(reinterpret_cast(cx_)); + js::ReportOutOfMemory(reinterpret_cast(cx_)); return false; } Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/jsapi.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/jsapi.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/jsapi.h @@ -14,7 +14,9 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/Range.h" #include "mozilla/RangedPtr.h" +#include "mozilla/RefCounted.h" #include "mozilla/RefPtr.h" +#include "mozilla/Variant.h" #include #include @@ -25,12 +27,14 @@ #include "jspubtd.h" #include "js/CallArgs.h" +#include "js/CharacterEncoding.h" #include "js/Class.h" +#include "js/GCVector.h" #include "js/HashTable.h" #include "js/Id.h" #include "js/Principals.h" +#include "js/Realm.h" #include "js/RootingAPI.h" -#include "js/TraceableVector.h" #include "js/TracingAPI.h" #include "js/Utility.h" #include "js/Value.h" @@ -123,14 +127,14 @@ size_t length() const { return vector.length(); } bool empty() const { return vector.empty(); } - bool append(const T& v) { return vector.append(v); } - bool appendN(const T& v, size_t len) { return vector.appendN(v, len); } - bool append(const T* ptr, size_t len) { return vector.append(ptr, len); } - bool appendAll(const AutoVectorRooterBase& other) { + MOZ_MUST_USE bool append(const T& v) { return vector.append(v); } + MOZ_MUST_USE bool appendN(const T& v, size_t len) { return vector.appendN(v, len); } + MOZ_MUST_USE bool append(const T* ptr, size_t len) { return vector.append(ptr, len); } + MOZ_MUST_USE bool appendAll(const AutoVectorRooterBase& other) { return vector.appendAll(other.vector); } - bool insert(T* p, const T& val) { return vector.insert(p, val); } + MOZ_MUST_USE bool insert(T* p, const T& val) { return vector.insert(p, val); } /* For use when space has already been reserved. */ void infallibleAppend(const T& v) { vector.infallibleAppend(v); } @@ -138,7 +142,7 @@ void popBack() { vector.popBack(); } T popCopy() { return vector.popCopy(); } - bool growBy(size_t inc) { + MOZ_MUST_USE bool growBy(size_t inc) { size_t oldLength = vector.length(); if (!vector.growByUninitialized(inc)) return false; @@ -146,7 +150,7 @@ return true; } - bool resize(size_t newLength) { + MOZ_MUST_USE bool resize(size_t newLength) { size_t oldLength = vector.length(); if (newLength <= oldLength) { vector.shrinkBy(oldLength - newLength); @@ -160,7 +164,7 @@ void clear() { vector.clear(); } - bool reserve(size_t newLength) { + MOZ_MUST_USE bool reserve(size_t newLength) { return vector.reserve(newLength); } @@ -214,13 +218,36 @@ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; -typedef AutoVectorRooter AutoValueVector; -typedef AutoVectorRooter AutoIdVector; -typedef AutoVectorRooter AutoObjectVector; - -using ValueVector = js::TraceableVector; -using IdVector = js::TraceableVector; -using ScriptVector = js::TraceableVector; +class AutoValueVector : public Rooted> { + using Vec = GCVector; + using Base = Rooted; + public: + explicit AutoValueVector(JSContext* cx) : Base(cx, Vec(cx)) {} + explicit AutoValueVector(js::ContextFriendFields* cx) : Base(cx, Vec(cx)) {} +}; + +class AutoIdVector : public Rooted> { + using Vec = GCVector; + using Base = Rooted; + public: + explicit AutoIdVector(JSContext* cx) : Base(cx, Vec(cx)) {} + explicit AutoIdVector(js::ContextFriendFields* cx) : Base(cx, Vec(cx)) {} + + bool appendAll(const AutoIdVector& other) { return this->Base::appendAll(other.get()); } +}; + +class AutoObjectVector : public Rooted> { + using Vec = GCVector; + using Base = Rooted; + public: + explicit AutoObjectVector(JSContext* cx) : Base(cx, Vec(cx)) {} + explicit AutoObjectVector(js::ContextFriendFields* cx) : Base(cx, Vec(cx)) {} +}; + +using ValueVector = JS::GCVector; +using IdVector = JS::GCVector; +using ScriptVector = JS::GCVector; +using StringVector = JS::GCVector; template class MOZ_RAII AutoHashMapRooter : protected AutoGCRooter @@ -454,7 +481,7 @@ { public: template - explicit CustomAutoRooter(CX* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + explicit CustomAutoRooter(const CX& cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : AutoGCRooter(cx, CUSTOM) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; @@ -463,6 +490,8 @@ friend void AutoGCRooter::trace(JSTracer* trc); protected: + virtual ~CustomAutoRooter() {} + /** Supplied by derived class to trace roots. */ virtual void trace(JSTracer* trc) = 0; @@ -518,15 +547,15 @@ /************************************************************************/ struct JSFreeOp { - private: + protected: JSRuntime* runtime_; - protected: explicit JSFreeOp(JSRuntime* rt) : runtime_(rt) { } public: JSRuntime* runtime() const { + MOZ_ASSERT(runtime_); return runtime_; } }; @@ -535,46 +564,28 @@ /************************************************************************/ -typedef enum JSContextOp { - JSCONTEXT_NEW, - JSCONTEXT_DESTROY -} JSContextOp; - -/** - * The possible values for contextOp when the runtime calls the callback are: - * JSCONTEXT_NEW JS_NewContext successfully created a new JSContext - * instance. The callback can initialize the instance as - * required. If the callback returns false, the instance - * will be destroyed and JS_NewContext returns null. In - * this case the callback is not called again. - * JSCONTEXT_DESTROY One of JS_DestroyContext* methods is called. The - * callback may perform its own cleanup and must always - * return true. - * Any other value For future compatibility the callback must do nothing - * and return true in this case. - */ -typedef bool -(* JSContextCallback)(JSContext* cx, unsigned contextOp, void* data); - typedef enum JSGCStatus { JSGC_BEGIN, JSGC_END } JSGCStatus; typedef void -(* JSGCCallback)(JSRuntime* rt, JSGCStatus status, void* data); +(* JSGCCallback)(JSContext* cx, JSGCStatus status, void* data); + +typedef void +(* JSObjectsTenuredCallback)(JSContext* cx, void* data); typedef enum JSFinalizeStatus { /** - * Called when preparing to sweep a group of compartments, before anything - * has been swept. The collector will not yield to the mutator before - * calling the callback with JSFINALIZE_GROUP_END status. + * Called when preparing to sweep a group of zones, before anything has been + * swept. The collector will not yield to the mutator before calling the + * callback with JSFINALIZE_GROUP_END status. */ JSFINALIZE_GROUP_START, /** - * Called when preparing to sweep a group of compartments. Weak references - * to unmarked things have been removed and things that are not swept + * Called when preparing to sweep a group of zones. Weak references to + * unmarked things have been removed and things that are not swept * incrementally have been finalized at this point. The collector may yield * to the mutator after this point. */ @@ -587,28 +598,48 @@ } JSFinalizeStatus; typedef void -(* JSFinalizeCallback)(JSFreeOp* fop, JSFinalizeStatus status, bool isCompartment, void* data); +(* JSFinalizeCallback)(JSFreeOp* fop, JSFinalizeStatus status, bool isZoneGC, void* data); typedef void -(* JSWeakPointerZoneGroupCallback)(JSRuntime* rt, void* data); +(* JSWeakPointerZoneGroupCallback)(JSContext* cx, void* data); typedef void -(* JSWeakPointerCompartmentCallback)(JSRuntime* rt, JSCompartment* comp, void* data); +(* JSWeakPointerCompartmentCallback)(JSContext* cx, JSCompartment* comp, void* data); typedef bool (* JSInterruptCallback)(JSContext* cx); +typedef JSObject* +(* JSGetIncumbentGlobalCallback)(JSContext* cx); + +typedef bool +(* JSEnqueuePromiseJobCallback)(JSContext* cx, JS::HandleObject job, + JS::HandleObject allocationSite, JS::HandleObject incumbentGlobal, + void* data); + +enum class PromiseRejectionHandlingState { + Unhandled, + Handled +}; + typedef void -(* JSErrorReporter)(JSContext* cx, const char* message, JSErrorReport* report); +(* JSPromiseRejectionTrackerCallback)(JSContext* cx, JS::HandleObject promise, + PromiseRejectionHandlingState state, void* data); + +typedef void +(* JSProcessPromiseCallback)(JSContext* cx, JS::HandleObject promise); /** * Possible exception types. These types are part of a JSErrorFormatString * structure. They define which error to throw in case of a runtime error. - * JSEXN_NONE marks an unthrowable 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. */ typedef enum JSExnType { - JSEXN_NONE = -1, - JSEXN_ERR, + JSEXN_ERR, + JSEXN_FIRST = JSEXN_ERR, JSEXN_INTERNALERR, JSEXN_EVALERR, JSEXN_RANGEERR, @@ -616,10 +647,17 @@ JSEXN_SYNTAXERR, JSEXN_TYPEERR, JSEXN_URIERR, - JSEXN_LIMIT + JSEXN_DEBUGGEEWOULDRUN, + JSEXN_WASMCOMPILEERROR, + JSEXN_WASMRUNTIMEERROR, + JSEXN_WARN, + JSEXN_LIMIT } JSExnType; typedef struct JSErrorFormatString { + /** The error message name in ASCII. */ + const char* name; + /** The error format string in ASCII. */ const char* format; @@ -663,9 +701,10 @@ * for wrapping in a context. This might include unwrapping other wrappers * or even finding a more suitable object for the new compartment. */ -typedef JSObject* +typedef void (* JSPreWrapCallback)(JSContext* cx, JS::HandleObject scope, JS::HandleObject obj, - JS::HandleObject objectPassedToWrap); + JS::HandleObject objectPassedToWrap, + JS::MutableHandleObject retObj); struct JSWrapObjectCallbacks { @@ -676,11 +715,15 @@ typedef void (* JSDestroyCompartmentCallback)(JSFreeOp* fop, JSCompartment* compartment); +typedef size_t +(* JSSizeOfIncludingThisCompartmentCallback)(mozilla::MallocSizeOf mallocSizeOf, + JSCompartment* compartment); + typedef void (* JSZoneCallback)(JS::Zone* zone); typedef void -(* JSCompartmentNameCallback)(JSRuntime* rt, JSCompartment* compartment, +(* JSCompartmentNameCallback)(JSContext* cx, JSCompartment* compartment, char* buf, size_t bufsize); /************************************************************************/ @@ -746,6 +789,16 @@ } } + SourceBufferHolder(SourceBufferHolder&& other) + : data_(other.data_), + length_(other.length_), + ownsChars_(other.ownsChars_) + { + other.data_ = nullptr; + other.length_ = 0; + other.ownsChars_ = false; + } + ~SourceBufferHolder() { if (ownsChars_) js_free(const_cast(data_)); @@ -815,29 +868,17 @@ object that delegates to a prototype containing this property */ #define JSPROP_INTERNAL_USE_BIT 0x80 /* internal JS engine use only */ -#define JSPROP_DEFINE_LATE 0x100 /* Don't define property when initially creating - the constructor. Some objects like Function/Object - have self-hosted functions that can only be defined - after the initialization is already finished. */ #define JSFUN_STUB_GSOPS 0x200 /* use JS_PropertyStub getter/setter instead of defaulting to class gsops for property holding function */ #define JSFUN_CONSTRUCTOR 0x400 /* native that can be called as a ctor */ -/* - * Specify a generic native prototype methods, i.e., methods of a class - * prototype that are exposed as static methods taking an extra leading - * argument: the generic |this| parameter. - * - * If you set this flag in a JSFunctionSpec struct's flags initializer, then - * that struct must live at least as long as the native static method object - * created due to this flag by JS_DefineFunctions or JS_InitClass. Typically - * JSFunctionSpec structs are allocated in static arrays. - */ -#define JSFUN_GENERIC_NATIVE 0x800 +// 0x800 /* Unused */ + +#define JSFUN_HAS_REST 0x1000 /* function has ...rest parameter. */ -#define JSFUN_FLAGS_MASK 0xe00 /* | of all the JSFUN_* flags */ +#define JSFUN_FLAGS_MASK 0x1e00 /* | of all the JSFUN_* flags */ /* * If set, will allow redefining a non-configurable property, but only on a @@ -873,17 +914,6 @@ specified when passed to Object.defineProperty from script. */ -/** - * The first call to JS_CallOnce by any thread in a process will call 'func'. - * Later calls to JS_CallOnce with the same JSCallOnceType object will be - * suppressed. - * - * Equivalently: each distinct JSCallOnceType object will allow one JS_CallOnce - * to invoke its JSInitCallback. - */ -extern JS_PUBLIC_API(bool) -JS_CallOnce(JSCallOnceType* once, JSInitCallback func); - /** Microseconds since the epoch, midnight, January 1, 1970 UTC. */ extern JS_PUBLIC_API(int64_t) JS_Now(void); @@ -902,7 +932,7 @@ JS_GetEmptyStringValue(JSContext* cx); extern JS_PUBLIC_API(JSString*) -JS_GetEmptyString(JSRuntime* rt); +JS_GetEmptyString(JSContext* cx); extern JS_PUBLIC_API(bool) JS_ValueToObject(JSContext* cx, JS::HandleValue v, JS::MutableHandleObject objp); @@ -922,6 +952,13 @@ extern JS_PUBLIC_API(JSType) JS_TypeOfValue(JSContext* cx, JS::Handle v); +namespace JS { + +extern JS_PUBLIC_API(const char*) +InformalValueTypeName(const JS::Value& v); + +} /* namespace JS */ + extern JS_PUBLIC_API(bool) JS_StrictlyEqual(JSContext* cx, JS::Handle v1, JS::Handle v2, bool* equal); @@ -944,19 +981,19 @@ /* * Locking, contexts, and memory allocation. * - * It is important that SpiderMonkey be initialized, and the first runtime and - * first context be created, in a single-threaded fashion. Otherwise the - * behavior of the library is undefined. + * It is important that SpiderMonkey be initialized, and the first context + * be created, in a single-threaded fashion. Otherwise the behavior of the + * library is undefined. * See: http://developer.mozilla.org/en/docs/Category:JSAPI_Reference */ -extern JS_PUBLIC_API(JSRuntime*) -JS_NewRuntime(uint32_t maxbytes, +extern JS_PUBLIC_API(JSContext*) +JS_NewContext(uint32_t maxbytes, uint32_t maxNurseryBytes = JS::DefaultNurseryBytes, - JSRuntime* parentRuntime = nullptr); + JSContext* parentContext = nullptr); extern JS_PUBLIC_API(void) -JS_DestroyRuntime(JSRuntime* rt); +JS_DestroyContext(JSContext* cx); typedef double (*JS_CurrentEmbedderTimeFunction)(); @@ -978,16 +1015,13 @@ JS_GetCurrentEmbedderTime(); JS_PUBLIC_API(void*) -JS_GetRuntimePrivate(JSRuntime* rt); - -extern JS_PUBLIC_API(JSRuntime*) -JS_GetRuntime(JSContext* cx); - -extern JS_PUBLIC_API(JSRuntime*) -JS_GetParentRuntime(JSContext* cx); +JS_GetContextPrivate(JSContext* cx); JS_PUBLIC_API(void) -JS_SetRuntimePrivate(JSRuntime* rt, void* data); +JS_SetContextPrivate(JSContext* cx, void* data); + +extern JS_PUBLIC_API(JSContext*) +JS_GetParentContext(JSContext* cx); extern JS_PUBLIC_API(void) JS_BeginRequest(JSContext* cx); @@ -995,14 +1029,14 @@ extern JS_PUBLIC_API(void) JS_EndRequest(JSContext* cx); +extern JS_PUBLIC_API(void) +JS_SetFutexCanWait(JSContext* cx); + namespace js { void AssertHeapIsIdle(JSRuntime* rt); -void -AssertHeapIsIdle(JSContext* cx); - } /* namespace js */ class MOZ_RAII JSAutoRequest @@ -1030,36 +1064,6 @@ #endif }; -extern JS_PUBLIC_API(void) -JS_SetContextCallback(JSRuntime* rt, JSContextCallback cxCallback, void* data); - -extern JS_PUBLIC_API(JSContext*) -JS_NewContext(JSRuntime* rt, size_t stackChunkSize); - -extern JS_PUBLIC_API(void) -JS_DestroyContext(JSContext* cx); - -extern JS_PUBLIC_API(void) -JS_DestroyContextNoGC(JSContext* cx); - -extern JS_PUBLIC_API(void*) -JS_GetContextPrivate(JSContext* cx); - -extern JS_PUBLIC_API(void) -JS_SetContextPrivate(JSContext* cx, void* data); - -extern JS_PUBLIC_API(void*) -JS_GetSecondContextPrivate(JSContext* cx); - -extern JS_PUBLIC_API(void) -JS_SetSecondContextPrivate(JSContext* cx, void* data); - -extern JS_PUBLIC_API(JSRuntime*) -JS_GetRuntime(JSContext* cx); - -extern JS_PUBLIC_API(JSContext*) -JS_ContextIterator(JSRuntime* rt, JSContext** iterp); - extern JS_PUBLIC_API(JSVersion) JS_GetVersion(JSContext* cx); @@ -1082,16 +1086,20 @@ namespace JS { -class JS_PUBLIC_API(RuntimeOptions) { +class JS_PUBLIC_API(ContextOptions) { public: - RuntimeOptions() + ContextOptions() : baseline_(true), ion_(true), asmJS_(true), + wasm_(false), + wasmAlwaysBaseline_(false), throwOnAsmJSValidationFailure_(false), nativeRegExp_(true), unboxedArrays_(false), asyncStack_(true), + throwOnDebuggeeWouldRun_(true), + dumpStackOnDebuggeeWouldRun_(false), werror_(false), strictMode_(false), extraWarnings_(false) @@ -1099,89 +1107,121 @@ } bool baseline() const { return baseline_; } - RuntimeOptions& setBaseline(bool flag) { + ContextOptions& setBaseline(bool flag) { baseline_ = flag; return *this; } - RuntimeOptions& toggleBaseline() { + ContextOptions& toggleBaseline() { baseline_ = !baseline_; return *this; } bool ion() const { return ion_; } - RuntimeOptions& setIon(bool flag) { + ContextOptions& setIon(bool flag) { ion_ = flag; return *this; } - RuntimeOptions& toggleIon() { + ContextOptions& toggleIon() { ion_ = !ion_; return *this; } bool asmJS() const { return asmJS_; } - RuntimeOptions& setAsmJS(bool flag) { + ContextOptions& setAsmJS(bool flag) { asmJS_ = flag; return *this; } - RuntimeOptions& toggleAsmJS() { + 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 wasmAlwaysBaseline() const { return wasmAlwaysBaseline_; } + ContextOptions& setWasmAlwaysBaseline(bool flag) { + wasmAlwaysBaseline_ = flag; + return *this; + } + ContextOptions& toggleWasmAlwaysBaseline() { + wasmAlwaysBaseline_ = !wasmAlwaysBaseline_; + return *this; + } + bool throwOnAsmJSValidationFailure() const { return throwOnAsmJSValidationFailure_; } - RuntimeOptions& setThrowOnAsmJSValidationFailure(bool flag) { + ContextOptions& setThrowOnAsmJSValidationFailure(bool flag) { throwOnAsmJSValidationFailure_ = flag; return *this; } - RuntimeOptions& toggleThrowOnAsmJSValidationFailure() { + ContextOptions& toggleThrowOnAsmJSValidationFailure() { throwOnAsmJSValidationFailure_ = !throwOnAsmJSValidationFailure_; return *this; } bool nativeRegExp() const { return nativeRegExp_; } - RuntimeOptions& setNativeRegExp(bool flag) { + ContextOptions& setNativeRegExp(bool flag) { nativeRegExp_ = flag; return *this; } bool unboxedArrays() const { return unboxedArrays_; } - RuntimeOptions& setUnboxedArrays(bool flag) { + ContextOptions& setUnboxedArrays(bool flag) { unboxedArrays_ = flag; return *this; } bool asyncStack() const { return asyncStack_; } - RuntimeOptions& setAsyncStack(bool flag) { + 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_; } - RuntimeOptions& setWerror(bool flag) { + ContextOptions& setWerror(bool flag) { werror_ = flag; return *this; } - RuntimeOptions& toggleWerror() { + ContextOptions& toggleWerror() { werror_ = !werror_; return *this; } bool strictMode() const { return strictMode_; } - RuntimeOptions& setStrictMode(bool flag) { + ContextOptions& setStrictMode(bool flag) { strictMode_ = flag; return *this; } - RuntimeOptions& toggleStrictMode() { + ContextOptions& toggleStrictMode() { strictMode_ = !strictMode_; return *this; } bool extraWarnings() const { return extraWarnings_; } - RuntimeOptions& setExtraWarnings(bool flag) { + ContextOptions& setExtraWarnings(bool flag) { extraWarnings_ = flag; return *this; } - RuntimeOptions& toggleExtraWarnings() { + ContextOptions& toggleExtraWarnings() { extraWarnings_ = !extraWarnings_; return *this; } @@ -1190,94 +1230,36 @@ bool baseline_ : 1; bool ion_ : 1; bool asmJS_ : 1; + bool wasm_ : 1; + bool wasmAlwaysBaseline_ : 1; bool throwOnAsmJSValidationFailure_ : 1; bool nativeRegExp_ : 1; bool unboxedArrays_ : 1; bool asyncStack_ : 1; + bool throwOnDebuggeeWouldRun_ : 1; + bool dumpStackOnDebuggeeWouldRun_ : 1; bool werror_ : 1; bool strictMode_ : 1; bool extraWarnings_ : 1; }; -JS_PUBLIC_API(RuntimeOptions&) -RuntimeOptionsRef(JSRuntime* rt); - -JS_PUBLIC_API(RuntimeOptions&) -RuntimeOptionsRef(JSContext* cx); - -class JS_PUBLIC_API(ContextOptions) { - public: - ContextOptions() - : privateIsNSISupports_(false), - dontReportUncaught_(false), - autoJSAPIOwnsErrorReporting_(false) - { - } - - bool privateIsNSISupports() const { return privateIsNSISupports_; } - ContextOptions& setPrivateIsNSISupports(bool flag) { - privateIsNSISupports_ = flag; - return *this; - } - ContextOptions& togglePrivateIsNSISupports() { - privateIsNSISupports_ = !privateIsNSISupports_; - return *this; - } - - bool dontReportUncaught() const { return dontReportUncaught_; } - ContextOptions& setDontReportUncaught(bool flag) { - dontReportUncaught_ = flag; - return *this; - } - ContextOptions& toggleDontReportUncaught() { - dontReportUncaught_ = !dontReportUncaught_; - return *this; - } - - bool autoJSAPIOwnsErrorReporting() const { return autoJSAPIOwnsErrorReporting_; } - ContextOptions& setAutoJSAPIOwnsErrorReporting(bool flag) { - autoJSAPIOwnsErrorReporting_ = flag; - return *this; - } - ContextOptions& toggleAutoJSAPIOwnsErrorReporting() { - autoJSAPIOwnsErrorReporting_ = !autoJSAPIOwnsErrorReporting_; - return *this; - } - - - private: - bool privateIsNSISupports_ : 1; - bool dontReportUncaught_ : 1; - // dontReportUncaught isn't respected by all JSAPI codepaths, particularly the - // JS_ReportError* functions that eventually report the error even when dontReportUncaught is - // set, if script is not running. We want a way to indicate that the embedder will always - // handle any exceptions, and that SpiderMonkey should just leave them on the context. This is - // the way we want to do all future error handling in Gecko - stealing the exception explicitly - // from the context and handling it as per the situation. This will eventually become the - // default and these 2 flags should go away. - bool autoJSAPIOwnsErrorReporting_ : 1; -}; - JS_PUBLIC_API(ContextOptions&) ContextOptionsRef(JSContext* cx); -class JS_PUBLIC_API(AutoSaveContextOptions) { - public: - explicit AutoSaveContextOptions(JSContext* cx) - : cx_(cx), - oldOptions_(ContextOptionsRef(cx_)) - { - } - - ~AutoSaveContextOptions() - { - ContextOptionsRef(cx_) = oldOptions_; - } +/** + * Initialize the runtime's self-hosted code. Embeddings should call this + * exactly once per runtime/context, before the first JS_NewGlobalObject + * call. + */ +JS_PUBLIC_API(bool) +InitSelfHostedCode(JSContext* cx); - private: - JSContext* cx_; - JS::ContextOptions oldOptions_; -}; +/** + * Asserts (in debug and release builds) that `obj` belongs to the current + * thread's context. + */ +JS_PUBLIC_API(void) +AssertObjectBelongsToCurrentThread(JSObject* obj); } /* namespace JS */ @@ -1285,19 +1267,23 @@ JS_GetImplementationVersion(void); extern JS_PUBLIC_API(void) -JS_SetDestroyCompartmentCallback(JSRuntime* rt, JSDestroyCompartmentCallback callback); +JS_SetDestroyCompartmentCallback(JSContext* cx, JSDestroyCompartmentCallback callback); + +extern JS_PUBLIC_API(void) +JS_SetSizeOfIncludingThisCompartmentCallback(JSContext* cx, + JSSizeOfIncludingThisCompartmentCallback callback); extern JS_PUBLIC_API(void) -JS_SetDestroyZoneCallback(JSRuntime* rt, JSZoneCallback callback); +JS_SetDestroyZoneCallback(JSContext* cx, JSZoneCallback callback); extern JS_PUBLIC_API(void) -JS_SetSweepZoneCallback(JSRuntime* rt, JSZoneCallback callback); +JS_SetSweepZoneCallback(JSContext* cx, JSZoneCallback callback); extern JS_PUBLIC_API(void) -JS_SetCompartmentNameCallback(JSRuntime* rt, JSCompartmentNameCallback callback); +JS_SetCompartmentNameCallback(JSContext* cx, JSCompartmentNameCallback callback); extern JS_PUBLIC_API(void) -JS_SetWrapObjectCallbacks(JSRuntime* rt, const JSWrapObjectCallbacks* callbacks); +JS_SetWrapObjectCallbacks(JSContext* cx, const JSWrapObjectCallbacks* callbacks); extern JS_PUBLIC_API(void) JS_SetCompartmentPrivate(JSCompartment* compartment, void* data); @@ -1391,7 +1377,7 @@ extern JS_PUBLIC_API(void) JS_LeaveCompartment(JSContext* cx, JSCompartment* oldCompartment); -typedef void (*JSIterateCompartmentCallback)(JSRuntime* rt, void* data, JSCompartment* compartment); +typedef void (*JSIterateCompartmentCallback)(JSContext* cx, void* data, JSCompartment* compartment); /** * This function calls |compartmentCallback| on every compartment. Beware that @@ -1399,7 +1385,7 @@ * returns. Also, barriers are disabled via the TraceSession. */ extern JS_PUBLIC_API(void) -JS_IterateCompartments(JSRuntime* rt, void* data, +JS_IterateCompartments(JSContext* cx, void* data, JSIterateCompartmentCallback compartmentCallback); /** @@ -1509,13 +1495,13 @@ JS_IsGlobalObject(JSObject* obj); extern JS_PUBLIC_API(JSObject*) -JS_GlobalLexicalScope(JSObject* obj); +JS_GlobalLexicalEnvironment(JSObject* obj); extern JS_PUBLIC_API(bool) -JS_HasExtensibleLexicalScope(JSObject* obj); +JS_HasExtensibleLexicalEnvironment(JSObject* obj); extern JS_PUBLIC_API(JSObject*) -JS_ExtensibleLexicalScope(JSObject* obj); +JS_ExtensibleLexicalEnvironment(JSObject* obj); /** * May return nullptr, if |c| never had a global (e.g. the atoms compartment), @@ -1607,50 +1593,47 @@ extern JS_PUBLIC_API(void) JS_freeop(JSFreeOp* fop, void* p); -extern JS_PUBLIC_API(JSFreeOp*) -JS_GetDefaultFreeOp(JSRuntime* rt); - extern JS_PUBLIC_API(void) JS_updateMallocCounter(JSContext* cx, size_t nbytes); extern JS_PUBLIC_API(char*) JS_strdup(JSContext* cx, const char* s); -/** Duplicate a string. Does not report an error on failure. */ -extern JS_PUBLIC_API(char*) -JS_strdup(JSRuntime* rt, const char* s); - /** * Register externally maintained GC roots. * * traceOp: the trace operation. For each root the implementation should call - * JS_CallTracer whenever the root contains a traceable thing. + * JS::TraceEdge whenever the root contains a traceable thing. * data: the data argument to pass to each invocation of traceOp. */ extern JS_PUBLIC_API(bool) -JS_AddExtraGCRootsTracer(JSRuntime* rt, JSTraceDataOp traceOp, void* data); +JS_AddExtraGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp, void* data); /** Undo a call to JS_AddExtraGCRootsTracer. */ extern JS_PUBLIC_API(void) -JS_RemoveExtraGCRootsTracer(JSRuntime* rt, JSTraceDataOp traceOp, void* data); +JS_RemoveExtraGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp, void* data); /* * Garbage collector API. */ extern JS_PUBLIC_API(void) -JS_GC(JSRuntime* rt); +JS_GC(JSContext* cx); extern JS_PUBLIC_API(void) JS_MaybeGC(JSContext* cx); extern JS_PUBLIC_API(void) -JS_SetGCCallback(JSRuntime* rt, JSGCCallback cb, void* data); +JS_SetGCCallback(JSContext* cx, JSGCCallback cb, void* data); + +extern JS_PUBLIC_API(void) +JS_SetObjectsTenuredCallback(JSContext* cx, JSObjectsTenuredCallback cb, + void* data); extern JS_PUBLIC_API(bool) -JS_AddFinalizeCallback(JSRuntime* rt, JSFinalizeCallback cb, void* data); +JS_AddFinalizeCallback(JSContext* cx, JSFinalizeCallback cb, void* data); extern JS_PUBLIC_API(void) -JS_RemoveFinalizeCallback(JSRuntime* rt, JSFinalizeCallback cb); +JS_RemoveFinalizeCallback(JSContext* cx, JSFinalizeCallback cb); /* * Weak pointers and garbage collection @@ -1687,17 +1670,17 @@ */ extern JS_PUBLIC_API(bool) -JS_AddWeakPointerZoneGroupCallback(JSRuntime* rt, JSWeakPointerZoneGroupCallback cb, void* data); +JS_AddWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb, void* data); extern JS_PUBLIC_API(void) -JS_RemoveWeakPointerZoneGroupCallback(JSRuntime* rt, JSWeakPointerZoneGroupCallback cb); +JS_RemoveWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb); extern JS_PUBLIC_API(bool) -JS_AddWeakPointerCompartmentCallback(JSRuntime* rt, JSWeakPointerCompartmentCallback cb, +JS_AddWeakPointerCompartmentCallback(JSContext* cx, JSWeakPointerCompartmentCallback cb, void* data); extern JS_PUBLIC_API(void) -JS_RemoveWeakPointerCompartmentCallback(JSRuntime* rt, JSWeakPointerCompartmentCallback cb); +JS_RemoveWeakPointerCompartmentCallback(JSContext* cx, JSWeakPointerCompartmentCallback cb); extern JS_PUBLIC_API(void) JS_UpdateWeakPointerAfterGC(JS::Heap* objp); @@ -1718,9 +1701,6 @@ /** Number of times GC has been invoked. Includes both major and minor GC. */ JSGC_NUMBER = 4, - /** Max size of the code cache in bytes. */ - JSGC_MAX_CODE_CACHE_BYTES = 5, - /** Select GC mode. */ JSGC_MODE = 6, @@ -1770,13 +1750,6 @@ JSGC_ALLOCATION_THRESHOLD = 19, /** - * We decommit memory lazily. If more than this number of megabytes is - * available to be decommitted, then JS_MaybeGC will trigger a shrinking GC - * to decommit it. - */ - JSGC_DECOMMIT_THRESHOLD = 20, - - /** * We try to keep at least this many unused chunks in the free chunk pool at * all times, even after a shrinking GC. */ @@ -1786,23 +1759,20 @@ JSGC_MAX_EMPTY_CHUNK_COUNT = 22, /** Whether compacting GC is enabled. */ - JSGC_COMPACTING_ENABLED = 23 -} JSGCParamKey; - -extern JS_PUBLIC_API(void) -JS_SetGCParameter(JSRuntime* rt, JSGCParamKey key, uint32_t value); + JSGC_COMPACTING_ENABLED = 23, -extern JS_PUBLIC_API(uint32_t) -JS_GetGCParameter(JSRuntime* rt, JSGCParamKey key); + /** If true, painting can trigger IGC slices. */ + JSGC_REFRESH_FRAME_SLICES_ENABLED = 24, +} JSGCParamKey; extern JS_PUBLIC_API(void) -JS_SetGCParameterForThread(JSContext* cx, JSGCParamKey key, uint32_t value); +JS_SetGCParameter(JSContext* cx, JSGCParamKey key, uint32_t value); extern JS_PUBLIC_API(uint32_t) -JS_GetGCParameterForThread(JSContext* cx, JSGCParamKey key); +JS_GetGCParameter(JSContext* cx, JSGCParamKey key); extern JS_PUBLIC_API(void) -JS_SetGCParametersBasedOnAvailableMemory(JSRuntime* rt, uint32_t availMem); +JS_SetGCParametersBasedOnAvailableMemory(JSContext* cx, uint32_t availMem); /** * Create a new JSString whose chars member refers to external memory, i.e., @@ -1844,7 +1814,7 @@ * and before any code is executed and/or interrupts requested. */ extern JS_PUBLIC_API(void) -JS_SetNativeStackQuota(JSRuntime* cx, size_t systemCodeStackSize, +JS_SetNativeStackQuota(JSContext* cx, size_t systemCodeStackSize, size_t trustedScriptStackSize = 0, size_t untrustedScriptStackSize = 0); @@ -1927,22 +1897,42 @@ */ struct JSPropertySpec { struct SelfHostedWrapper { - void* unused; + void* unused; const char* funname; }; + struct ValueWrapper { + uintptr_t type; + union { + const char* string; + int32_t int32; + }; + }; + const char* name; uint8_t flags; union { - JSNativeWrapper native; - SelfHostedWrapper selfHosted; - } getter; - union { - JSNativeWrapper native; - SelfHostedWrapper selfHosted; - } setter; + struct { + union { + JSNativeWrapper native; + SelfHostedWrapper selfHosted; + } getter; + union { + JSNativeWrapper native; + SelfHostedWrapper selfHosted; + } setter; + } accessors; + ValueWrapper value; + }; + + bool isAccessor() const { + return !(flags & JSPROP_INTERNAL_USE_BIT); + } + JS_PUBLIC_API(bool) getValue(JSContext* cx, JS::MutableHandleValue value) const; bool isSelfHosted() const { + MOZ_ASSERT(isAccessor()); + #ifdef DEBUG // Verify that our accessors match our JSPROP_GETTER flag. if (flags & JSPROP_GETTER) @@ -1961,17 +1951,17 @@ "JSNativeWrapper::info"); private: void checkAccessorsAreNative() const { - MOZ_ASSERT(getter.native.op); + MOZ_ASSERT(accessors.getter.native.op); // We may not have a setter at all. So all we can assert here, for the // native case is that if we have a jitinfo for the setter then we have // a setter op too. This is good enough to make sure we don't have a // SelfHostedWrapper for the setter. - MOZ_ASSERT_IF(setter.native.info, setter.native.op); + MOZ_ASSERT_IF(accessors.setter.native.info, accessors.setter.native.op); } void checkAccessorsAreSelfHosted() const { - MOZ_ASSERT(!getter.selfHosted.unused); - MOZ_ASSERT(!setter.selfHosted.unused); + MOZ_ASSERT(!accessors.getter.selfHosted.unused); + MOZ_ASSERT(!accessors.setter.selfHosted.unused); } }; @@ -1986,13 +1976,15 @@ inline int CheckIsCharacterLiteral(const char (&arr)[N]); +/* NEVER DEFINED, DON'T USE. For use by JS_CAST_INT32_TO only. */ +inline int CheckIsInt32(int32_t value); + /* NEVER DEFINED, DON'T USE. For use by JS_PROPERTYOP_GETTER only. */ inline int CheckIsGetterOp(JSGetterOp op); /* NEVER DEFINED, DON'T USE. For use by JS_PROPERTYOP_SETTER only. */ inline int CheckIsSetterOp(JSSetterOp op); - } // namespace detail } // namespace JS @@ -2004,6 +1996,10 @@ (static_cast(sizeof(JS::detail::CheckIsCharacterLiteral(s))), \ reinterpret_cast(s)) +#define JS_CAST_INT32_TO(s, To) \ + (static_cast(sizeof(JS::detail::CheckIsInt32(s))), \ + reinterpret_cast(s)) + #define JS_CHECK_ACCESSOR_FLAGS(flags) \ (static_cast::Type>(0), \ (flags)) @@ -2020,37 +2016,50 @@ #define JS_STUBSETTER JS_PROPERTYOP_SETTER(JS_StrictPropertyStub) +#define JS_PS_ACCESSOR_SPEC(name, getter, setter, flags, extraFlags) \ + { name, uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | extraFlags), \ + { { getter, setter } } } +#define JS_PS_VALUE_SPEC(name, value, flags) \ + { name, uint8_t(flags | JSPROP_INTERNAL_USE_BIT), \ + { { value, JSNATIVE_WRAPPER(nullptr) } } } + +#define SELFHOSTED_WRAPPER(name) \ + { { nullptr, JS_CAST_STRING_TO(name, const JSJitInfo*) } } +#define STRINGVALUE_WRAPPER(value) \ + { { reinterpret_cast(JSVAL_TYPE_STRING), JS_CAST_STRING_TO(value, const JSJitInfo*) } } +#define INT32VALUE_WRAPPER(value) \ + { { reinterpret_cast(JSVAL_TYPE_INT32), JS_CAST_INT32_TO(value, const JSJitInfo*) } } + /* * JSPropertySpec uses JSNativeWrapper. These macros encapsulate the definition * of JSNative-backed JSPropertySpecs, by defining the JSNativeWrappers for * them. */ #define JS_PSG(name, getter, flags) \ - {name, \ - uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED), \ - JSNATIVE_WRAPPER(getter), \ - JSNATIVE_WRAPPER(nullptr)} + JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(nullptr), flags, \ + JSPROP_SHARED) #define JS_PSGS(name, getter, setter, flags) \ - {name, \ - uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED), \ - JSNATIVE_WRAPPER(getter), \ - JSNATIVE_WRAPPER(setter)} + JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(setter), flags, \ + JSPROP_SHARED) #define JS_SELF_HOSTED_GET(name, getterName, flags) \ - {name, \ - uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_GETTER), \ - { { nullptr, JS_CAST_STRING_TO(getterName, const JSJitInfo*) } }, \ - JSNATIVE_WRAPPER(nullptr) } + JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), JSNATIVE_WRAPPER(nullptr), flags, \ + JSPROP_SHARED | JSPROP_GETTER) #define JS_SELF_HOSTED_GETSET(name, getterName, setterName, flags) \ - {name, \ - uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_GETTER | JSPROP_SETTER), \ - { nullptr, JS_CAST_STRING_TO(getterName, const JSJitInfo*) }, \ - { nullptr, JS_CAST_STRING_TO(setterName, const JSJitInfo*) } } -#define JS_PS_END { nullptr, 0, JSNATIVE_WRAPPER(nullptr), JSNATIVE_WRAPPER(nullptr) } + JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), SELFHOSTED_WRAPPER(setterName), \ + flags, JSPROP_SHARED | JSPROP_GETTER | JSPROP_SETTER) #define JS_SELF_HOSTED_SYM_GET(symbol, getterName, flags) \ - {reinterpret_cast(uint32_t(::JS::SymbolCode::symbol) + 1), \ - uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_GETTER), \ - { { nullptr, JS_CAST_STRING_TO(getterName, const JSJitInfo*) } }, \ - JSNATIVE_WRAPPER(nullptr) } + JS_PS_ACCESSOR_SPEC(reinterpret_cast(uint32_t(::JS::SymbolCode::symbol) + 1), \ + SELFHOSTED_WRAPPER(getterName), JSNATIVE_WRAPPER(nullptr), flags, \ + JSPROP_SHARED | JSPROP_GETTER) +#define JS_STRING_PS(name, string, flags) \ + JS_PS_VALUE_SPEC(name, STRINGVALUE_WRAPPER(string), flags) +#define JS_STRING_SYM_PS(symbol, string, flags) \ + JS_PS_VALUE_SPEC(reinterpret_cast(uint32_t(::JS::SymbolCode::symbol) + 1), \ + STRINGVALUE_WRAPPER(string), flags) +#define JS_INT32_PS(name, value, flags) \ + JS_PS_VALUE_SPEC(name, INT32VALUE_WRAPPER(value), flags) +#define JS_PS_END \ + JS_PS_ACCESSOR_SPEC(nullptr, JSNATIVE_WRAPPER(nullptr), JSNATIVE_WRAPPER(nullptr), 0, 0) /** * To define a native function, set call to a JSNativeWrapper. To define a @@ -2128,6 +2137,17 @@ extern JS_PUBLIC_API(bool) JS_HasInstance(JSContext* cx, JS::Handle obj, JS::Handle v, bool* bp); +namespace JS { + +// Implementation of +// http://www.ecma-international.org/ecma-262/6.0/#sec-ordinaryhasinstance. If +// you're looking for the equivalent of "instanceof", you want JS_HasInstance, +// not this function. +extern JS_PUBLIC_API(bool) +OrdinaryHasInstance(JSContext* cx, HandleObject objArg, HandleValue v, bool* bp); + +} // namespace JS + extern JS_PUBLIC_API(void*) JS_GetPrivate(JSObject* obj); @@ -2148,7 +2168,121 @@ SystemZone = 1 }; -class JS_PUBLIC_API(CompartmentOptions) +/** + * CompartmentCreationOptions specifies options relevant to creating a new + * compartment, that are either immutable characteristics of that compartment + * or that are discarded after the compartment has been created. + * + * Access to these options on an existing compartment is read-only: if you + * need particular selections, make them before you create the compartment. + */ +class JS_PUBLIC_API(CompartmentCreationOptions) +{ + public: + CompartmentCreationOptions() + : addonId_(nullptr), + traceGlobal_(nullptr), + invisibleToDebugger_(false), + mergeable_(false), + preserveJitCode_(false), + cloneSingletons_(false), + sharedMemoryAndAtomics_(false), + secureContext_(false) + { + zone_.spec = JS::FreshZone; + } + + // A null add-on ID means that the compartment is not associated with an + // add-on. + JSAddonId* addonIdOrNull() const { return addonId_; } + CompartmentCreationOptions& setAddonId(JSAddonId* id) { + addonId_ = id; + return *this; + } + + JSTraceOp getTrace() const { + return traceGlobal_; + } + CompartmentCreationOptions& setTrace(JSTraceOp op) { + traceGlobal_ = op; + return *this; + } + + void* zonePointer() const { + MOZ_ASSERT(uintptr_t(zone_.pointer) > uintptr_t(JS::SystemZone)); + return zone_.pointer; + } + ZoneSpecifier zoneSpecifier() const { return zone_.spec; } + CompartmentCreationOptions& setZone(ZoneSpecifier spec); + CompartmentCreationOptions& setSameZoneAs(JSObject* obj); + + // Certain scopes (i.e. XBL compilation scopes) are implementation details + // of the embedding, and references to them should never leak out to script. + // This flag causes the this compartment to skip firing onNewGlobalObject + // and makes addDebuggee a no-op for this global. + bool invisibleToDebugger() const { return invisibleToDebugger_; } + CompartmentCreationOptions& setInvisibleToDebugger(bool flag) { + invisibleToDebugger_ = flag; + return *this; + } + + // Compartments used for off-thread compilation have their contents merged + // into a target compartment when the compilation is finished. This is only + // allowed if this flag is set. The invisibleToDebugger flag must also be + // set for such compartments. + bool mergeable() const { return mergeable_; } + CompartmentCreationOptions& setMergeable(bool flag) { + mergeable_ = flag; + return *this; + } + + // Determines whether this compartment should preserve JIT code on + // non-shrinking GCs. + bool preserveJitCode() const { return preserveJitCode_; } + CompartmentCreationOptions& setPreserveJitCode(bool flag) { + preserveJitCode_ = flag; + return *this; + } + + bool cloneSingletons() const { return cloneSingletons_; } + CompartmentCreationOptions& setCloneSingletons(bool flag) { + cloneSingletons_ = flag; + return *this; + } + + bool getSharedMemoryAndAtomicsEnabled() const; + CompartmentCreationOptions& setSharedMemoryAndAtomicsEnabled(bool flag); + + // This flag doesn't affect JS engine behavior. It is used by Gecko to + // mark whether content windows and workers are "Secure Context"s. See + // https://w3c.github.io/webappsec-secure-contexts/ + // https://bugzilla.mozilla.org/show_bug.cgi?id=1162772#c34 + bool secureContext() const { return secureContext_; } + CompartmentCreationOptions& setSecureContext(bool flag) { + secureContext_ = flag; + return *this; + } + + private: + JSAddonId* addonId_; + JSTraceOp traceGlobal_; + union { + ZoneSpecifier spec; + void* pointer; // js::Zone* is not exposed in the API. + } zone_; + bool invisibleToDebugger_; + bool mergeable_; + bool preserveJitCode_; + bool cloneSingletons_; + bool sharedMemoryAndAtomics_; + bool secureContext_; +}; + +/** + * CompartmentBehaviors specifies behaviors of a compartment that can be + * changed after the compartment's been created. + */ +class JS_PUBLIC_API(CompartmentBehaviors) { public: class Override { @@ -2179,140 +2313,119 @@ Mode mode_; }; - explicit CompartmentOptions() + CompartmentBehaviors() : version_(JSVERSION_UNKNOWN) - , invisibleToDebugger_(false) - , mergeable_(false) , discardSource_(false) , disableLazyParsing_(false) - , cloneSingletons_(false) - , traceGlobal_(nullptr) , singletonsAsTemplates_(true) - , addonId_(nullptr) - , preserveJitCode_(false) { - zone_.spec = JS::FreshZone; } JSVersion version() const { return version_; } - CompartmentOptions& setVersion(JSVersion aVersion) { + CompartmentBehaviors& setVersion(JSVersion aVersion) { MOZ_ASSERT(aVersion != JSVERSION_UNKNOWN); version_ = aVersion; return *this; } - // Certain scopes (i.e. XBL compilation scopes) are implementation details - // of the embedding, and references to them should never leak out to script. - // This flag causes the this compartment to skip firing onNewGlobalObject - // and makes addDebuggee a no-op for this global. - bool invisibleToDebugger() const { return invisibleToDebugger_; } - CompartmentOptions& setInvisibleToDebugger(bool flag) { - invisibleToDebugger_ = flag; - return *this; - } - - // Compartments used for off-thread compilation have their contents merged - // into a target compartment when the compilation is finished. This is only - // allowed if this flag is set. The invisibleToDebugger flag must also be - // set for such compartments. - bool mergeable() const { return mergeable_; } - CompartmentOptions& setMergeable(bool flag) { - mergeable_ = flag; - return *this; - } - // For certain globals, we know enough about the code that will run in them // that we can discard script source entirely. bool discardSource() const { return discardSource_; } - CompartmentOptions& setDiscardSource(bool flag) { + CompartmentBehaviors& setDiscardSource(bool flag) { discardSource_ = flag; return *this; } bool disableLazyParsing() const { return disableLazyParsing_; } - CompartmentOptions& setDisableLazyParsing(bool flag) { + CompartmentBehaviors& setDisableLazyParsing(bool flag) { disableLazyParsing_ = flag; return *this; } - bool cloneSingletons() const { return cloneSingletons_; } - CompartmentOptions& setCloneSingletons(bool flag) { - cloneSingletons_ = flag; - return *this; - } - - bool extraWarnings(JSRuntime* rt) const; bool extraWarnings(JSContext* cx) const; Override& extraWarningsOverride() { return extraWarningsOverride_; } - void* zonePointer() const { - MOZ_ASSERT(uintptr_t(zone_.pointer) > uintptr_t(JS::SystemZone)); - return zone_.pointer; - } - ZoneSpecifier zoneSpecifier() const { return zone_.spec; } - CompartmentOptions& setZone(ZoneSpecifier spec); - CompartmentOptions& setSameZoneAs(JSObject* obj); - - void setSingletonsAsValues() { - singletonsAsTemplates_ = false; - } bool getSingletonsAsTemplates() const { return singletonsAsTemplates_; } - - // A null add-on ID means that the compartment is not associated with an - // add-on. - JSAddonId* addonIdOrNull() const { return addonId_; } - CompartmentOptions& setAddonId(JSAddonId* id) { - addonId_ = id; - return *this; - } - - CompartmentOptions& setTrace(JSTraceOp op) { - traceGlobal_ = op; - return *this; - } - JSTraceOp getTrace() const { - return traceGlobal_; - } - - bool preserveJitCode() const { return preserveJitCode_; } - CompartmentOptions& setPreserveJitCode(bool flag) { - preserveJitCode_ = flag; + CompartmentBehaviors& setSingletonsAsValues() { + singletonsAsTemplates_ = false; return *this; } private: JSVersion version_; - bool invisibleToDebugger_; - bool mergeable_; bool discardSource_; bool disableLazyParsing_; - bool cloneSingletons_; Override extraWarningsOverride_; - union { - ZoneSpecifier spec; - void* pointer; // js::Zone* is not exposed in the API. - } zone_; - JSTraceOp traceGlobal_; // To XDR singletons, we need to ensure that all singletons are all used as // templates, by making JSOP_OBJECT return a clone of the JSScript // singleton, instead of returning the value which is baked in the JSScript. bool singletonsAsTemplates_; +}; - JSAddonId* addonId_; - bool preserveJitCode_; +/** + * CompartmentOptions specifies compartment characteristics: both those that + * can't be changed on a compartment once it's been created + * (CompartmentCreationOptions), and those that can be changed on an existing + * compartment (CompartmentBehaviors). + */ +class JS_PUBLIC_API(CompartmentOptions) +{ + public: + explicit CompartmentOptions() + : creationOptions_(), + behaviors_() + {} + + CompartmentOptions(const CompartmentCreationOptions& compartmentCreation, + const CompartmentBehaviors& compartmentBehaviors) + : creationOptions_(compartmentCreation), + behaviors_(compartmentBehaviors) + {} + + // CompartmentCreationOptions specify fundamental compartment + // characteristics that must be specified when the compartment is created, + // that can't be changed after the compartment is created. + CompartmentCreationOptions& creationOptions() { + return creationOptions_; + } + const CompartmentCreationOptions& creationOptions() const { + return creationOptions_; + } + + // CompartmentBehaviors specify compartment characteristics that can be + // changed after the compartment is created. + CompartmentBehaviors& behaviors() { + return behaviors_; + } + const CompartmentBehaviors& behaviors() const { + return behaviors_; + } + + private: + CompartmentCreationOptions creationOptions_; + CompartmentBehaviors behaviors_; }; -JS_PUBLIC_API(CompartmentOptions&) -CompartmentOptionsRef(JSCompartment* compartment); +JS_PUBLIC_API(const CompartmentCreationOptions&) +CompartmentCreationOptionsRef(JSCompartment* compartment); + +JS_PUBLIC_API(const CompartmentCreationOptions&) +CompartmentCreationOptionsRef(JSObject* obj); -JS_PUBLIC_API(CompartmentOptions&) -CompartmentOptionsRef(JSObject* obj); +JS_PUBLIC_API(const CompartmentCreationOptions&) +CompartmentCreationOptionsRef(JSContext* cx); -JS_PUBLIC_API(CompartmentOptions&) -CompartmentOptionsRef(JSContext* cx); +JS_PUBLIC_API(CompartmentBehaviors&) +CompartmentBehaviorsRef(JSCompartment* compartment); + +JS_PUBLIC_API(CompartmentBehaviors&) +CompartmentBehaviorsRef(JSObject* obj); + +JS_PUBLIC_API(CompartmentBehaviors&) +CompartmentBehaviorsRef(JSContext* cx); /** * During global creation, we fire notifications to callbacks registered @@ -2346,7 +2459,7 @@ extern JS_PUBLIC_API(JSObject*) JS_NewGlobalObject(JSContext* cx, const JSClass* clasp, JSPrincipals* principals, JS::OnNewGlobalHookOption hookOption, - const JS::CompartmentOptions& options = JS::CompartmentOptions()); + const JS::CompartmentOptions& options); /** * Spidermonkey does not have a good way of keeping track of what compartments should be marked on * their own. We can mark the roots unconditionally, but marking GC things only relevant in live @@ -2368,9 +2481,6 @@ extern JS_PUBLIC_API(bool) JS_IsNative(JSObject* obj); -extern JS_PUBLIC_API(JSRuntime*) -JS_GetObjectRuntime(JSObject* obj); - /** * Unlike JS_NewObject, JS_NewObjectWithGivenProto does not compute a default * proto. If proto is nullptr, the JS object will have `null` as [[Prototype]]. @@ -2399,27 +2509,27 @@ /*** Property descriptors ************************************************************************/ -struct JS_PUBLIC_API(JSPropertyDescriptor) : public JS::Traceable { +namespace JS { + +struct JS_PUBLIC_API(PropertyDescriptor) { JSObject* obj; unsigned attrs; JSGetterOp getter; JSSetterOp setter; JS::Value value; - JSPropertyDescriptor() + PropertyDescriptor() : obj(nullptr), attrs(0), getter(nullptr), setter(nullptr), value(JS::UndefinedValue()) {} - static void trace(JSPropertyDescriptor* self, JSTracer* trc) { self->trace(trc); } + static void trace(PropertyDescriptor* self, JSTracer* trc) { self->trace(trc); } void trace(JSTracer* trc); }; -namespace JS { - template class PropertyDescriptorOperations { - const JSPropertyDescriptor& desc() const { return static_cast(this)->get(); } + const PropertyDescriptor& desc() const { return static_cast(this)->get(); } bool has(unsigned bit) const { MOZ_ASSERT(bit != 0); @@ -2551,7 +2661,7 @@ template class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations { - JSPropertyDescriptor& desc() { return static_cast(this)->get(); } + PropertyDescriptor& desc() { return static_cast(this)->get(); } public: void clear() { @@ -2574,7 +2684,7 @@ setSetter(setterOp); } - void assign(JSPropertyDescriptor& other) { + void assign(PropertyDescriptor& other) { object().set(other.obj); setAttributes(other.attrs); setGetter(other.getter); @@ -2662,18 +2772,18 @@ namespace js { template <> -class RootedBase - : public JS::MutablePropertyDescriptorOperations> +class RootedBase + : public JS::MutablePropertyDescriptorOperations> {}; template <> -class HandleBase - : public JS::PropertyDescriptorOperations> +class HandleBase + : public JS::PropertyDescriptorOperations> {}; template <> -class MutableHandleBase - : public JS::MutablePropertyDescriptorOperations> +class MutableHandleBase + : public JS::MutablePropertyDescriptorOperations> {}; } /* namespace js */ @@ -2684,7 +2794,17 @@ ObjectToCompletePropertyDescriptor(JSContext* cx, JS::HandleObject obj, JS::HandleValue descriptor, - JS::MutableHandle desc); + JS::MutableHandle desc); + +/* + * ES6 draft rev 32 (2015 Feb 2) 6.2.4.4 FromPropertyDescriptor(Desc). + * + * If desc.object() is null, then vp is set to undefined. + */ +extern JS_PUBLIC_API(bool) +FromPropertyDescriptor(JSContext* cx, + JS::Handle desc, + JS::MutableHandleValue vp); } // namespace JS @@ -2715,6 +2835,17 @@ JS_GetPrototype(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject result); /** + * If |obj| (underneath any functionally-transparent wrapper proxies) has as + * its [[GetPrototypeOf]] trap the ordinary [[GetPrototypeOf]] behavior defined + * for ordinary objects, set |*isOrdinary = true| and store |obj|'s prototype + * in |result|. Otherwise set |*isOrdinary = false|. In case of error, both + * outparams have unspecified value. + */ +extern JS_PUBLIC_API(bool) +JS_GetPrototypeIfOrdinary(JSContext* cx, JS::HandleObject obj, bool* isOrdinary, + JS::MutableHandleObject result); + +/** * Change the prototype of obj. * * Implements: ES6 [[SetPrototypeOf]] internal method. @@ -2771,15 +2902,15 @@ */ extern JS_PUBLIC_API(bool) JS_GetOwnPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); extern JS_PUBLIC_API(bool) JS_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, - JS::MutableHandle desc); + JS::MutableHandle desc); extern JS_PUBLIC_API(bool) JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, - JS::MutableHandle desc); + JS::MutableHandle desc); /** * Like JS_GetOwnPropertyDescriptorById, but also searches the prototype chain @@ -2789,11 +2920,11 @@ */ extern JS_PUBLIC_API(bool) JS_GetPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); extern JS_PUBLIC_API(bool) JS_GetPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, - JS::MutableHandle desc); + JS::MutableHandle desc); /** * Define a property on obj. @@ -2808,7 +2939,7 @@ */ extern JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result); /** @@ -2817,7 +2948,7 @@ */ extern JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc); + JS::Handle desc); extern JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value, @@ -2869,12 +3000,12 @@ extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result); extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::Handle desc); + JS::Handle desc); extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, @@ -3099,8 +3230,8 @@ * This is the closest thing we currently have to the ES6 [[Enumerate]] * internal method. * - * The JSIdArray returned by JS_Enumerate must be rooted to protect its - * contents from garbage collection. Use JS::AutoIdArray. + * The array of ids returned by JS_Enumerate must be rooted to protect its + * contents from garbage collection. Use JS::Rooted. */ extern JS_PUBLIC_API(bool) JS_Enumerate(JSContext* cx, JS::HandleObject obj, JS::MutableHandle props); @@ -3213,21 +3344,18 @@ */ extern JS_PUBLIC_API(bool) Construct(JSContext* cx, JS::HandleValue fun, HandleObject newTarget, - const JS::HandleValueArray &args, MutableHandleValue rval); + const JS::HandleValueArray &args, MutableHandleObject objp); /** * Invoke a constructor. This is the C++ equivalent of * `rval = new fun(...args)`. * - * The value left in rval on success is always an object in practice, - * though at the moment this is not enforced by the C++ type system. - * * Implements: ES6 7.3.13 Construct(F, [argumentsList], [newTarget]), when * newTarget is omitted. */ extern JS_PUBLIC_API(bool) Construct(JSContext* cx, JS::HandleValue fun, const JS::HandleValueArray& args, - MutableHandleValue rval); + MutableHandleObject objp); } /* namespace JS */ @@ -3304,6 +3432,30 @@ extern JS_PUBLIC_API(bool) JS_SetArrayLength(JSContext* cx, JS::Handle obj, uint32_t length); +namespace JS { + +/** + * Returns true and sets |*isMap| indicating whether |obj| is an Map object + * or a wrapper around one, otherwise returns false on failure. + * + * This method returns true with |*isMap == false| when passed a proxy whose + * target is an Map, or when passed a revoked proxy. + */ +extern JS_PUBLIC_API(bool) +IsMapObject(JSContext* cx, JS::HandleObject obj, bool* isMap); + +/** + * Returns true and sets |*isSet| indicating whether |obj| is an Set object + * or a wrapper around one, otherwise returns false on failure. + * + * This method returns true with |*isSet == false| when passed a proxy whose + * target is an Set, or when passed a revoked proxy. + */ +extern JS_PUBLIC_API(bool) +IsSetObject(JSContext* cx, JS::HandleObject obj, bool* isSet); + +} /* namespace JS */ + /** * Assign 'undefined' to all of the object's non-reserved slots. Note: this is * done for all slots, regardless of the associated property descriptor. @@ -3320,6 +3472,13 @@ JS_NewArrayBufferWithContents(JSContext* cx, size_t nbytes, void* contents); /** + * Create a new array buffer with the given contents. The array buffer does not take ownership of + * contents, and JS_DetachArrayBuffer must be called before the contents are disposed of. + */ +extern JS_PUBLIC_API(JSObject*) +JS_NewArrayBufferWithExternalContents(JSContext* cx, size_t nbytes, void* contents); + +/** * Steal the contents of the given array buffer. The array buffer 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 @@ -3329,6 +3488,25 @@ JS_StealArrayBufferContents(JSContext* cx, JS::HandleObject obj); /** + * Returns a pointer to the ArrayBuffer |obj|'s data. |obj| and its views will store and expose + * the data in the returned pointer: assigning into the returned pointer will affect values exposed + * by views of |obj| and vice versa. + * + * The caller must ultimately deallocate the returned pointer to avoid leaking. The memory is + * *not* garbage-collected with |obj|. These steps must be followed to deallocate: + * + * 1. The ArrayBuffer |obj| must be detached using JS_DetachArrayBuffer. + * 2. The returned pointer must be freed using JS_free. + * + * To perform step 1, callers *must* hold a reference to |obj| until they finish using the returned + * pointer. They *must not* attempt to let |obj| be GC'd, then JS_free the pointer. + * + * If |obj| isn't an ArrayBuffer, this function returns null and reports an error. + */ +extern JS_PUBLIC_API(void*) +JS_ExternalizeArrayBufferContents(JSContext* cx, JS::HandleObject obj); + +/** * Create a new mapped array buffer 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 array buffer. @@ -3347,7 +3525,7 @@ * Release the allocated resource of mapped array buffer contents before the * object is created. * If a new object has been created by JS_NewMappedArrayBufferWithContents() - * with this content, then JS_NeuterArrayBuffer() should be used instead to + * with this content, then JS_DetachArrayBuffer() should be used instead to * release the resource used by the object. */ extern JS_PUBLIC_API(void) @@ -3357,7 +3535,7 @@ JS_GetReservedSlot(JSObject* obj, uint32_t index); extern JS_PUBLIC_API(void) -JS_SetReservedSlot(JSObject* obj, uint32_t index, JS::Value v); +JS_SetReservedSlot(JSObject* obj, uint32_t index, const JS::Value& v); /************************************************************************/ @@ -3432,20 +3610,8 @@ extern JS_PUBLIC_API(bool) JS_IsConstructor(JSFunction* fun); -/** - * This enum is used to select if properties with JSPROP_DEFINE_LATE flag - * should be defined on the object. - * Normal JSAPI consumers probably always want DefineAllProperties here. - */ -enum PropertyDefinitionBehavior { - DefineAllProperties, - OnlyDefineLateProperties, - DontDefineLateProperties -}; - extern JS_PUBLIC_API(bool) -JS_DefineFunctions(JSContext* cx, JS::Handle obj, const JSFunctionSpec* fs, - PropertyDefinitionBehavior behavior = DefineAllProperties); +JS_DefineFunctions(JSContext* cx, JS::Handle obj, const JSFunctionSpec* fs); extern JS_PUBLIC_API(JSFunction*) JS_DefineFunction(JSContext* cx, JS::Handle obj, const char* name, JSNative call, @@ -3460,6 +3626,12 @@ JS_DefineFunctionById(JSContext* cx, JS::Handle obj, JS::Handle id, JSNative call, unsigned nargs, unsigned attrs); +extern JS_PUBLIC_API(bool) +JS_IsFunctionBound(JSFunction* fun); + +extern JS_PUBLIC_API(JSObject*) +JS_GetBoundFunctionTarget(JSFunction* fun); + namespace JS { /** @@ -3680,7 +3852,6 @@ lineno(1), column(0), isRunOnce(false), - forEval(false), noScriptRval(false) { } @@ -3704,7 +3875,6 @@ unsigned column; // isRunOnce only applies to non-function scripts. bool isRunOnce; - bool forEval; bool noScriptRval; private: @@ -3726,7 +3896,6 @@ */ class JS_FRIEND_API(OwningCompileOptions) : public ReadOnlyCompileOptions { - JSRuntime* runtime; PersistentRootedObject elementRoot; PersistentRootedString elementAttributeNameRoot; PersistentRootedScript introductionScriptRoot; @@ -3778,7 +3947,6 @@ OwningCompileOptions& setUTF8(bool u) { utf8 = u; return *this; } OwningCompileOptions& setColumn(unsigned c) { column = c; return *this; } OwningCompileOptions& setIsRunOnce(bool once) { isRunOnce = once; return *this; } - OwningCompileOptions& setForEval(bool eval) { forEval = eval; 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; } @@ -3808,7 +3976,7 @@ * 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_FRIEND_API(CompileOptions) : public ReadOnlyCompileOptions +class MOZ_STACK_CLASS JS_FRIEND_API(CompileOptions) final : public ReadOnlyCompileOptions { RootedObject elementRoot; RootedString elementAttributeNameRoot; @@ -3875,7 +4043,6 @@ CompileOptions& setUTF8(bool u) { utf8 = u; return *this; } CompileOptions& setColumn(unsigned c) { column = c; return *this; } CompileOptions& setIsRunOnce(bool once) { isRunOnce = once; return *this; } - CompileOptions& setForEval(bool eval) { forEval = eval; 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; } @@ -3953,10 +4120,11 @@ * 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 the main thread, - * so must ensure that its operations are thread safe. Afterwards, - * FinishOffThreadScript must be invoked on the main thread to get the result - * script or nullptr. If maybecx is not specified, the resources will be freed, - * but no script will be returned. + * so must ensure that its operations are thread safe. Afterwards, one of the + * following functions must be invoked on the 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 @@ -3969,17 +4137,31 @@ OffThreadCompileCallback callback, void* callbackData); extern JS_PUBLIC_API(JSScript*) -FinishOffThreadScript(JSContext* maybecx, JSRuntime* rt, void* token); +FinishOffThreadScript(JSContext* cx, void* token); + +extern JS_PUBLIC_API(void) +CancelOffThreadScript(JSContext* cx, void* token); + +extern JS_PUBLIC_API(bool) +CompileOffThreadModule(JSContext* cx, const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + OffThreadCompileCallback callback, void* callbackData); + +extern JS_PUBLIC_API(JSObject*) +FinishOffThreadModule(JSContext* cx, void* token); + +extern JS_PUBLIC_API(void) +CancelOffThreadModule(JSContext* cx, void* token); /** - * Compile a function with scopeChain plus the global as its scope chain. - * scopeChain must contain objects in the current compartment of cx. The actual + * 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(bool) -CompileFunction(JSContext* cx, AutoObjectVector& scopeChain, +CompileFunction(JSContext* cx, AutoObjectVector& envChain, const ReadOnlyCompileOptions& options, const char* name, unsigned nargs, const char* const* argnames, const char16_t* chars, size_t length, JS::MutableHandleFunction fun); @@ -3988,7 +4170,7 @@ * Same as above, but taking a SourceBufferHolder for the function body. */ extern JS_PUBLIC_API(bool) -CompileFunction(JSContext* cx, AutoObjectVector& scopeChain, +CompileFunction(JSContext* cx, AutoObjectVector& envChain, const ReadOnlyCompileOptions& options, const char* name, unsigned nargs, const char* const* argnames, SourceBufferHolder& srcBuf, JS::MutableHandleFunction fun); @@ -3997,7 +4179,7 @@ * Same as above, but taking a const char * for the function body. */ extern JS_PUBLIC_API(bool) -CompileFunction(JSContext* cx, AutoObjectVector& scopeChain, +CompileFunction(JSContext* cx, AutoObjectVector& envChain, const ReadOnlyCompileOptions& options, const char* name, unsigned nargs, const char* const* argnames, const char* bytes, size_t length, JS::MutableHandleFunction fun); @@ -4029,7 +4211,7 @@ * 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 RuntimeOptionsRef adjustment, OTOH, can be + * 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. */ @@ -4044,16 +4226,16 @@ JS_ExecuteScript(JSContext* cx, JS::HandleScript script); /** - * As above, but providing an explicit scope chain. scopeChain must not include + * 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::AutoObjectVector& scopeChain, +JS_ExecuteScript(JSContext* cx, JS::AutoObjectVector& envChain, JS::HandleScript script, JS::MutableHandleValue rval); extern JS_PUBLIC_API(bool) -JS_ExecuteScript(JSContext* cx, JS::AutoObjectVector& scopeChain, JS::HandleScript script); +JS_ExecuteScript(JSContext* cx, JS::AutoObjectVector& envChain, JS::HandleScript script); namespace JS { @@ -4062,7 +4244,8 @@ * cross-compartment, it is cloned into the current compartment before executing. */ extern JS_PUBLIC_API(bool) -CloneAndExecuteScript(JSContext* cx, JS::Handle script); +CloneAndExecuteScript(JSContext* cx, JS::Handle script, + JS::MutableHandleValue rval); } /* namespace JS */ @@ -4076,12 +4259,12 @@ SourceBufferHolder& srcBuf, JS::MutableHandleValue rval); /** - * As above, but providing an explicit scope chain. scopeChain must not include + * 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, AutoObjectVector& scopeChain, const ReadOnlyCompileOptions& options, +Evaluate(JSContext* cx, AutoObjectVector& envChain, const ReadOnlyCompileOptions& options, SourceBufferHolder& srcBuf, JS::MutableHandleValue rval); /** @@ -4092,12 +4275,12 @@ const char16_t* chars, size_t length, JS::MutableHandleValue rval); /** - * As above, but providing an explicit scope chain. scopeChain must not include + * 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, AutoObjectVector& scopeChain, const ReadOnlyCompileOptions& options, +Evaluate(JSContext* cx, AutoObjectVector& envChain, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, JS::MutableHandleValue rval); /** @@ -4114,6 +4297,80 @@ Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, const char* filename, JS::MutableHandleValue rval); +/** + * Get the HostResolveImportedModule hook for a global. + */ +extern JS_PUBLIC_API(JSFunction*) +GetModuleResolveHook(JSContext* cx); + +/** + * Set the HostResolveImportedModule hook for a global to the given function. + */ +extern JS_PUBLIC_API(void) +SetModuleResolveHook(JSContext* cx, JS::HandleFunction func); + +/** + * Parse the given source buffer as a module in the scope of the current global + * of cx and return a source text module record. + */ +extern JS_PUBLIC_API(bool) +CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options, + SourceBufferHolder& srcBuf, JS::MutableHandleObject moduleRecord); + +/** + * Set the [[HostDefined]] field of a source text module record to the given + * value. + */ +extern JS_PUBLIC_API(void) +SetModuleHostDefinedField(JSObject* module, const JS::Value& value); + +/** + * Get the [[HostDefined]] field of a source text module record. + */ +extern JS_PUBLIC_API(JS::Value) +GetModuleHostDefinedField(JSObject* module); + +/* + * Perform the ModuleDeclarationInstantiation operation on on the give source + * text module record. + * + * This transitively resolves all module dependencies (calling the + * HostResolveImportedModule hook) and initializes the environment record for + * the module. + */ +extern JS_PUBLIC_API(bool) +ModuleDeclarationInstantiation(JSContext* cx, JS::HandleObject moduleRecord); + +/* + * Perform the ModuleEvaluation operation on on the give source text module + * record. + * + * This does nothing if this module has already been evaluated. Otherwise, it + * transitively evaluates all dependences of this module and then evaluates this + * module. + * + * ModuleDeclarationInstantiation must have completed prior to calling this. + */ +extern JS_PUBLIC_API(bool) +ModuleEvaluation(JSContext* cx, JS::HandleObject moduleRecord); + +/* + * Get a list of the module specifiers used by a source text module + * record to request importation of modules. + * + * The result is a JavaScript array of string values. To extract the individual + * values use only JS_GetArrayLength and JS_GetElement with indices 0 to + * length - 1. + */ +extern JS_PUBLIC_API(JSObject*) +GetRequestedModules(JSContext* cx, JS::HandleObject moduleRecord); + +/* + * Get the script associated with a module. + */ +extern JS_PUBLIC_API(JSScript*) +GetModuleScript(JSContext* cx, JS::HandleObject moduleRecord); + } /* namespace JS */ extern JS_PUBLIC_API(bool) @@ -4122,7 +4379,7 @@ /* * These functions allow setting an interrupt callback that will be called * from the JS thread some time after any thread triggered the callback using - * JS_RequestInterruptCallback(rt). + * JS_RequestInterruptCallback(cx). * * To schedule the GC and for other activities the engine internally triggers * interrupt callbacks. The embedding should thus not rely on callbacks being @@ -4132,34 +4389,257 @@ * if it re-enters the JS engine. The embedding must ensure that the callback * is disconnected before attempting such re-entry. */ -extern JS_PUBLIC_API(JSInterruptCallback) -JS_SetInterruptCallback(JSRuntime* rt, JSInterruptCallback callback); +extern JS_PUBLIC_API(bool) +JS_AddInterruptCallback(JSContext* cx, JSInterruptCallback callback); + +extern JS_PUBLIC_API(bool) +JS_DisableInterruptCallback(JSContext* cx); + +extern JS_PUBLIC_API(void) +JS_ResetInterruptCallback(JSContext* cx, bool enable); + +extern JS_PUBLIC_API(void) +JS_RequestInterruptCallback(JSContext* cx); + +namespace JS { + +/** + * Sets the callback that's invoked whenever an incumbent global is required. + * + * SpiderMonkey doesn't itself have a notion of incumbent globals as defined + * by the html spec, so we need the embedding to provide this. + * See dom/base/ScriptSettings.h for details. + */ +extern JS_PUBLIC_API(void) +SetGetIncumbentGlobalCallback(JSContext* cx, JSGetIncumbentGlobalCallback callback); -extern JS_PUBLIC_API(JSInterruptCallback) -JS_GetInterruptCallback(JSRuntime* rt); +/** + * Sets the callback that's invoked whenever a Promise job should be enqeued. + * + * SpiderMonkey doesn't schedule Promise resolution jobs itself; instead, + * using this function the embedding can provide a callback to do that + * scheduling. The provided `callback` is invoked with the promise job, + * the corresponding Promise's allocation stack, and the `data` pointer + * passed here as arguments. + */ +extern JS_PUBLIC_API(void) +SetEnqueuePromiseJobCallback(JSContext* cx, JSEnqueuePromiseJobCallback callback, + void* data = nullptr); +/** + * Sets the callback that's invoked whenever a Promise is rejected without + * a rejection handler, and when a Promise that was previously rejected + * without a handler gets a handler attached. + */ extern JS_PUBLIC_API(void) -JS_RequestInterruptCallback(JSRuntime* rt); +SetPromiseRejectionTrackerCallback(JSContext* cx, JSPromiseRejectionTrackerCallback callback, + void* data = nullptr); +/** + * Returns a new instance of the Promise builtin class in the current + * compartment, with the right slot layout. If a `proto` is passed, that gets + * set as the instance's [[Prototype]] instead of the original value of + * `Promise.prototype`. + */ +extern JS_PUBLIC_API(JSObject*) +NewPromiseObject(JSContext* cx, JS::HandleObject executor, JS::HandleObject proto = nullptr); + +/** + * Returns true if the given object is an unwrapped PromiseObject, false + * otherwise. + */ extern JS_PUBLIC_API(bool) -JS_IsRunning(JSContext* cx); +IsPromiseObject(JS::HandleObject obj); -/* - * Saving and restoring frame chains. +/** + * Returns the current compartment's original Promise constructor. + */ +extern JS_PUBLIC_API(JSObject*) +GetPromiseConstructor(JSContext* cx); + +/** + * Returns the current compartment's original Promise.prototype. + */ +extern JS_PUBLIC_API(JSObject*) +GetPromisePrototype(JSContext* cx); + +// Keep this in sync with the PROMISE_STATE defines in SelfHostingDefines.h. +enum class PromiseState { + Pending, + Fulfilled, + Rejected +}; + +/** + * Returns the given Promise's state as a JS::PromiseState enum value. + * + * Returns JS::PromiseState::Pending if the given object is a wrapper that + * can't safely be unwrapped. + */ +extern JS_PUBLIC_API(PromiseState) +GetPromiseState(JS::HandleObject promise); + +/** + * Returns the given Promise's process-unique ID. + */ +JS_PUBLIC_API(uint64_t) +GetPromiseID(JS::HandleObject promise); + +/** + * Returns the given Promise's result: either the resolution value for + * fulfilled promises, or the rejection reason for rejected ones. + */ +extern JS_PUBLIC_API(JS::Value) +GetPromiseResult(JS::HandleObject promise); + +/** + * Returns a js::SavedFrame linked list of the stack that lead to the given + * Promise's allocation. + */ +extern JS_PUBLIC_API(JSObject*) +GetPromiseAllocationSite(JS::HandleObject promise); + +extern JS_PUBLIC_API(JSObject*) +GetPromiseResolutionSite(JS::HandleObject promise); + +#ifdef DEBUG +extern JS_PUBLIC_API(void) +DumpPromiseAllocationSite(JSContext* cx, JS::HandleObject promise); + +extern JS_PUBLIC_API(void) +DumpPromiseResolutionSite(JSContext* cx, JS::HandleObject promise); +#endif + +/** + * Calls the current compartment's original Promise.resolve on the original + * Promise constructor, with `resolutionValue` passed as an argument. + */ +extern JS_PUBLIC_API(JSObject*) +CallOriginalPromiseResolve(JSContext* cx, JS::HandleValue resolutionValue); + +/** + * Calls the current compartment's original Promise.reject on the original + * Promise constructor, with `resolutionValue` passed as an argument. + */ +extern JS_PUBLIC_API(JSObject*) +CallOriginalPromiseReject(JSContext* cx, JS::HandleValue rejectionValue); + +/** + * Resolves the given Promise with the given `resolutionValue`. + * + * Calls the `resolve` function that was passed to the executor function when + * the Promise was created. + */ +extern JS_PUBLIC_API(bool) +ResolvePromise(JSContext* cx, JS::HandleObject promise, JS::HandleValue resolutionValue); + +/** + * Rejects the given `promise` with the given `rejectionValue`. + * + * Calls the `reject` function that was passed to the executor function when + * the Promise was created. + */ +extern JS_PUBLIC_API(bool) +RejectPromise(JSContext* cx, JS::HandleObject promise, JS::HandleValue rejectionValue); + +/** + * Calls the current compartment's original Promise.prototype.then on the + * given `promise`, with `onResolve` and `onReject` passed as arguments. + * + * Asserts if the passed-in `promise` object isn't an unwrapped instance of + * `Promise` or a subclass or `onResolve` and `onReject` aren't both either + * `nullptr` or callable objects. + */ +extern JS_PUBLIC_API(JSObject*) +CallOriginalPromiseThen(JSContext* cx, JS::HandleObject promise, + JS::HandleObject onResolve, JS::HandleObject onReject); + +/** + * Unforgeable, optimized version of the JS builtin Promise.prototype.then. * - * These two functions are used to set aside cx's call stack while that stack - * is inactive. After a call to JS_SaveFrameChain, it looks as if there is no - * code running on cx. Before calling JS_RestoreFrameChain, cx's call stack - * must be balanced and all nested calls to JS_SaveFrameChain must have had - * matching JS_RestoreFrameChain calls. + * Takes a Promise instance and `onResolve`, `onReject` callables to enqueue + * as reactions for that promise. In difference to Promise.prototype.then, + * this doesn't create and return a new Promise instance. * - * JS_SaveFrameChain deals with cx not having any code running on it. + * Asserts if the passed-in `promise` object isn't an unwrapped instance of + * `Promise` or a subclass or `onResolve` and `onReject` aren't both callable + * objects. */ extern JS_PUBLIC_API(bool) -JS_SaveFrameChain(JSContext* cx); +AddPromiseReactions(JSContext* cx, JS::HandleObject promise, + JS::HandleObject onResolve, JS::HandleObject onReject); + +/** + * Unforgeable version of the JS builtin Promise.all. + * + * Takes an AutoObjectVector of Promise objects and returns a promise that's + * resolved with an array of resolution values when all those promises have + * been resolved, or rejected with the rejection value of the first rejected + * promise. + * + * Asserts that all objects in the `promises` vector are, maybe wrapped, + * instances of `Promise` or a subclass of `Promise`. + */ +extern JS_PUBLIC_API(JSObject*) +GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises); + +/** + * An AsyncTask represents a SpiderMonkey-internal operation that starts on a + * JSContext's owner thread, possibly executes on other threads, completes, and + * then needs to be scheduled to run again on the JSContext's owner thread. The + * embedding provides for this final dispatch back to the JSContext's owner + * thread by calling methods on this interface when requested. + */ +struct JS_PUBLIC_API(AsyncTask) +{ + AsyncTask() : user(nullptr) {} + virtual ~AsyncTask() {} + + /** + * After the FinishAsyncTaskCallback is called and succeeds, one of these + * two functions will be called on the original JSContext's owner thread. + */ + virtual void finish(JSContext* cx) = 0; + virtual void cancel(JSContext* cx) = 0; + + /* The embedding may use this field to attach arbitrary data to a task. */ + void* user; +}; + +/** + * A new AsyncTask object, created inside SpiderMonkey on the JSContext's owner + * thread, will be passed to the StartAsyncTaskCallback before it is dispatched + * to another thread. The embedding may use the AsyncTask::user field to attach + * additional task state. + * + * If this function succeeds, SpiderMonkey will call the FinishAsyncTaskCallback + * at some point in the future. Otherwise, FinishAsyncTaskCallback will *not* + * be called. SpiderMonkey assumes that, if StartAsyncTaskCallback fails, it is + * because the JSContext is being shut down. + */ +typedef bool +(*StartAsyncTaskCallback)(JSContext* cx, AsyncTask* task); +/** + * The FinishAsyncTaskCallback may be called from any thread and will only be + * passed AsyncTasks that have already been started via StartAsyncTaskCallback. + * If the embedding returns 'true', indicating success, the embedding must call + * either task->finish() or task->cancel() on the JSContext's owner thread at + * some point in the future. + */ +typedef bool +(*FinishAsyncTaskCallback)(AsyncTask* task); + +/** + * Set the above callbacks for the given context. + */ extern JS_PUBLIC_API(void) -JS_RestoreFrameChain(JSContext* cx); +SetAsyncTaskCallbacks(JSContext* cx, StartAsyncTaskCallback start, FinishAsyncTaskCallback finish); + +} // namespace JS + +extern JS_PUBLIC_API(bool) +JS_IsRunning(JSContext* cx); namespace JS { @@ -4184,7 +4664,7 @@ { JSContext* cx; RootedObject oldAsyncStack; - RootedString oldAsyncCause; + const char* oldAsyncCause; bool oldAsyncCallIsExplicit; public: @@ -4201,8 +4681,13 @@ // ambiguous whether that would clear any scheduled async stack and make the // normal stack reappear in the new call, or just keep the async stack // already scheduled for the new call, if any. + // + // asyncCause is owned by the caller and its lifetime must outlive the + // lifetime of the AutoSetAsyncStackForNewCalls object. It is strongly + // encouraged that asyncCause be a string constant or similar statically + // allocated string. AutoSetAsyncStackForNewCalls(JSContext* cx, HandleObject stack, - HandleString asyncCause, + const char* asyncCause, AsyncCallKind kind = AsyncCallKind::IMPLICIT); ~AutoSetAsyncStackForNewCalls(); }; @@ -4227,9 +4712,21 @@ JS_NewStringCopyZ(JSContext* cx, const char* s); extern JS_PUBLIC_API(JSString*) +JS_NewStringCopyUTF8Z(JSContext* cx, const JS::ConstUTF8CharsZ s); + +extern JS_PUBLIC_API(JSString*) +JS_NewStringCopyUTF8N(JSContext* cx, const JS::UTF8Chars s); + +extern JS_PUBLIC_API(JSString*) JS_AtomizeAndPinJSString(JSContext* cx, JS::HandleString str); extern JS_PUBLIC_API(JSString*) +JS_AtomizeStringN(JSContext* cx, const char* s, size_t length); + +extern JS_PUBLIC_API(JSString*) +JS_AtomizeString(JSContext* cx, const char* s); + +extern JS_PUBLIC_API(JSString*) JS_AtomizeAndPinStringN(JSContext* cx, const char* s, size_t length); extern JS_PUBLIC_API(JSString*) @@ -4245,6 +4742,12 @@ JS_NewUCStringCopyZ(JSContext* cx, const char16_t* s); extern JS_PUBLIC_API(JSString*) +JS_AtomizeUCStringN(JSContext* cx, const char16_t* s, size_t length); + +extern JS_PUBLIC_API(JSString*) +JS_AtomizeUCString(JSContext* cx, const char16_t* s); + +extern JS_PUBLIC_API(JSString*) JS_AtomizeAndPinUCStringN(JSContext* cx, const char16_t* s, size_t length); extern JS_PUBLIC_API(JSString*) @@ -4453,7 +4956,7 @@ } ~JSAutoByteString() { - js_free(mBytes); + JS_free(nullptr, mBytes); } /* Take ownership of the given byte array. */ @@ -4498,7 +5001,7 @@ } private: - char* mBytes; + char* mBytes; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER /* Copy and assignment are not supported. */ @@ -4556,17 +5059,31 @@ GetSymbolDescription(HandleSymbol symbol); /* Well-known symbols. */ +#define JS_FOR_EACH_WELL_KNOWN_SYMBOL(macro) \ + macro(isConcatSpreadable) \ + macro(iterator) \ + macro(match) \ + macro(replace) \ + macro(search) \ + macro(species) \ + macro(hasInstance) \ + macro(split) \ + macro(toPrimitive) \ + macro(toStringTag) \ + macro(unscopables) + enum class SymbolCode : uint32_t { - iterator, // well-known symbols - match, - species, - toPrimitive, + // There is one SymbolCode for each well-known symbol. +#define JS_DEFINE_SYMBOL_ENUM(name) name, + JS_FOR_EACH_WELL_KNOWN_SYMBOL(JS_DEFINE_SYMBOL_ENUM) // SymbolCode::iterator, etc. +#undef JS_DEFINE_SYMBOL_ENUM + Limit, InSymbolRegistry = 0xfffffffe, // created by Symbol.for() or JS::GetSymbolFor() UniqueSymbol = 0xffffffff // created by Symbol() or JS::NewSymbol() }; /* For use in loops that iterate over the well-known symbols. */ -const size_t WellKnownSymbolLimit = 4; +const size_t WellKnownSymbolLimit = size_t(SymbolCode::Limit); /** * Return the SymbolCode telling what sort of symbol `symbol` is. @@ -4625,6 +5142,31 @@ JS_Stringify(JSContext* cx, JS::MutableHandleValue value, JS::HandleObject replacer, JS::HandleValue 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. + */ +JS_PUBLIC_API(bool) +ToJSONMaybeSafely(JSContext* cx, JS::HandleObject input, + JSONWriteCallback callback, void* data); + +} /* namespace JS */ + /** * JSON.parse as specified by ES5. */ @@ -4652,13 +5194,19 @@ * The locale string remains owned by the caller. */ extern JS_PUBLIC_API(bool) -JS_SetDefaultLocale(JSRuntime* rt, const char* locale); +JS_SetDefaultLocale(JSContext* cx, const char* locale); + +/** + * Look up the default locale for the ECMAScript Internationalization API. + */ +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); +JS_ResetDefaultLocale(JSContext* cx); /** * Locale specific string conversion and error message callbacks. @@ -4672,17 +5220,17 @@ /** * Establish locale callbacks. The pointer must persist as long as the - * JSRuntime. Passing nullptr restores the default behaviour. + * JSContext. Passing nullptr restores the default behaviour. */ extern JS_PUBLIC_API(void) -JS_SetLocaleCallbacks(JSRuntime* rt, const JSLocaleCallbacks* callbacks); +JS_SetLocaleCallbacks(JSContext* cx, const JSLocaleCallbacks* callbacks); /** * Return the address of the current locale callbacks struct, which may * be nullptr. */ extern JS_PUBLIC_API(const JSLocaleCallbacks*) -JS_GetLocaleCallbacks(JSRuntime* rt); +JS_GetLocaleCallbacks(JSContext* cx); /************************************************************************/ @@ -4696,23 +5244,49 @@ /** * Report an exception represented by the sprintf-like conversion of format - * and its arguments. This exception message string is passed to a pre-set - * JSErrorReporter function (set by JS_SetErrorReporter). + * and its arguments. */ extern JS_PUBLIC_API(void) -JS_ReportError(JSContext* cx, const char* format, ...); +JS_ReportErrorASCII(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API(void) +JS_ReportErrorLatin1(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API(void) +JS_ReportErrorUTF8(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); /* * Use an errorNumber to retrieve the format string, args are char* */ extern JS_PUBLIC_API(void) -JS_ReportErrorNumber(JSContext* cx, JSErrorCallback errorCallback, - void* userRef, const unsigned errorNumber, ...); +JS_ReportErrorNumberASCII(JSContext* cx, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, ...); + +extern JS_PUBLIC_API(void) +JS_ReportErrorNumberASCIIVA(JSContext* cx, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, va_list ap); + +extern JS_PUBLIC_API(void) +JS_ReportErrorNumberLatin1(JSContext* cx, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, ...); #ifdef va_start extern JS_PUBLIC_API(void) -JS_ReportErrorNumberVA(JSContext* cx, JSErrorCallback errorCallback, - void* userRef, const unsigned errorNumber, va_list ap); +JS_ReportErrorNumberLatin1VA(JSContext* cx, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, va_list ap); +#endif + +extern JS_PUBLIC_API(void) +JS_ReportErrorNumberUTF8(JSContext* cx, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, ...); + +#ifdef va_start +extern JS_PUBLIC_API(void) +JS_ReportErrorNumberUTF8VA(JSContext* cx, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, va_list ap); #endif /* @@ -4734,12 +5308,31 @@ * being set, false otherwise. */ extern JS_PUBLIC_API(bool) -JS_ReportWarning(JSContext* cx, const char* format, ...); +JS_ReportWarningASCII(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API(bool) +JS_ReportWarningLatin1(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API(bool) +JS_ReportWarningUTF8(JSContext* cx, const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API(bool) +JS_ReportErrorFlagsAndNumberASCII(JSContext* cx, unsigned flags, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + +extern JS_PUBLIC_API(bool) +JS_ReportErrorFlagsAndNumberLatin1(JSContext* cx, unsigned flags, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); extern JS_PUBLIC_API(bool) -JS_ReportErrorFlagsAndNumber(JSContext* cx, unsigned flags, - JSErrorCallback errorCallback, void* userRef, - const unsigned errorNumber, ...); +JS_ReportErrorFlagsAndNumberUTF8(JSContext* cx, unsigned flags, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); extern JS_PUBLIC_API(bool) JS_ReportErrorFlagsAndNumberUC(JSContext* cx, unsigned flags, @@ -4760,7 +5353,12 @@ class JSErrorReport { + // The (default) error message. + // If ownsMessage_ is true, the it is freed in destructor. + JS::ConstUTF8CharsZ message_; + // 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'. @@ -4772,21 +5370,30 @@ public: JSErrorReport() : linebuf_(nullptr), linebufLength_(0), tokenOffset_(0), - filename(nullptr), lineno(0), column(0), isMuted(false), - flags(0), errorNumber(0), ucmessage(nullptr), - messageArgs(nullptr), exnType(0) + filename(nullptr), lineno(0), column(0), + flags(0), errorNumber(0), + exnType(0), isMuted(false), + ownsLinebuf_(false), ownsMessage_(false) {} + ~JSErrorReport() { + freeLinebuf(); + freeMessage(); + } + const char* filename; /* source file name, URL, etc., or null */ unsigned lineno; /* source line number */ unsigned column; /* zero-based column index in line */ - bool isMuted; /* See the comment in ReadOnlyCompileOptions. */ unsigned flags; /* error/warning, etc. */ unsigned errorNumber; /* the error number, e.g. see js.msg */ - const char16_t* ucmessage; /* the (default) error message */ - const char16_t** messageArgs; /* arguments for the error message */ int16_t exnType; /* One of the JSExnType constants */ + bool isMuted : 1; /* See the comment in ReadOnlyCompileOptions. */ + private: + bool ownsLinebuf_ : 1; + bool ownsMessage_ : 1; + + public: const char16_t* linebuf() const { return linebuf_; } @@ -4796,7 +5403,29 @@ size_t tokenOffset() const { return tokenOffset_; } - void initLinebuf(const char16_t* linebuf, size_t linebufLength, size_t 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); + void freeLinebuf(); + + 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); + + void freeMessage(); }; /* @@ -4807,14 +5436,7 @@ #define JSREPORT_EXCEPTION 0x2 /* exception was thrown */ #define JSREPORT_STRICT 0x4 /* error or warning due to strict option */ -/* - * This condition is an error in strict mode code, a warning if - * JS_HAS_STRICT_OPTION(cx), and otherwise should not be reported at - * all. We check the strictness of the context's top frame's script; - * where that isn't appropriate, the caller should do the right checks - * itself instead of using this flag. - */ -#define JSREPORT_STRICT_MODE_ERROR 0x8 +#define JSREPORT_USER_1 0x8 /* user-defined flag */ /* * If JSREPORT_EXCEPTION is set, then a JavaScript-catchable exception @@ -4826,16 +5448,17 @@ #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) -#define JSREPORT_IS_STRICT_MODE_ERROR(flags) (((flags) & \ - JSREPORT_STRICT_MODE_ERROR) != 0) -extern JS_PUBLIC_API(JSErrorReporter) -JS_GetErrorReporter(JSRuntime* rt); - -extern JS_PUBLIC_API(JSErrorReporter) -JS_SetErrorReporter(JSRuntime* rt, JSErrorReporter er); namespace JS { +using WarningReporter = void (*)(JSContext* cx, JSErrorReport* report); + +extern JS_PUBLIC_API(WarningReporter) +SetWarningReporter(JSContext* cx, WarningReporter reporter); + +extern JS_PUBLIC_API(WarningReporter) +GetWarningReporter(JSContext* cx); + extern JS_PUBLIC_API(bool) CreateError(JSContext* cx, JSExnType type, HandleObject stack, HandleString fileName, uint32_t lineNumber, uint32_t columnNumber, @@ -4959,18 +5582,16 @@ #define JSREG_GLOB 0x02u /* global exec, creates array of matches */ #define JSREG_MULTILINE 0x04u /* treat ^ and $ as begin and end of line */ #define JSREG_STICKY 0x08u /* only match starting at lastIndex */ +#define JSREG_UNICODE 0x10u /* unicode */ extern JS_PUBLIC_API(JSObject*) -JS_NewRegExpObject(JSContext* cx, JS::HandleObject obj, const char* bytes, size_t length, - unsigned flags); +JS_NewRegExpObject(JSContext* cx, const char* bytes, size_t length, unsigned flags); extern JS_PUBLIC_API(JSObject*) -JS_NewUCRegExpObject(JSContext* cx, JS::HandleObject obj, const char16_t* chars, size_t length, - unsigned flags); +JS_NewUCRegExpObject(JSContext* cx, const char16_t* chars, size_t length, unsigned flags); extern JS_PUBLIC_API(bool) -JS_SetRegExpInput(JSContext* cx, JS::HandleObject obj, JS::HandleString input, - bool multiline); +JS_SetRegExpInput(JSContext* cx, JS::HandleObject obj, JS::HandleString input); extern JS_PUBLIC_API(bool) JS_ClearRegExpStatics(JSContext* cx, JS::HandleObject obj); @@ -4982,12 +5603,6 @@ /* RegExp interface for clients without a global object. */ -extern JS_PUBLIC_API(JSObject*) -JS_NewRegExpObjectNoStatics(JSContext* cx, char* bytes, size_t length, unsigned flags); - -extern JS_PUBLIC_API(JSObject*) -JS_NewUCRegExpObjectNoStatics(JSContext* cx, char16_t* chars, size_t length, unsigned flags); - extern JS_PUBLIC_API(bool) JS_ExecuteRegExpNoStatics(JSContext* cx, JS::HandleObject reobj, char16_t* chars, size_t length, size_t* indexp, bool test, JS::MutableHandleValue rval); @@ -5022,9 +5637,6 @@ extern JS_PUBLIC_API(void) JS_ClearPendingException(JSContext* cx); -extern JS_PUBLIC_API(bool) -JS_ReportPendingException(JSContext* cx); - namespace JS { /** @@ -5102,8 +5714,15 @@ extern JS_PUBLIC_API(JSErrorReport*) JS_ErrorFromException(JSContext* cx, JS::HandleObject obj); +/** + * If the given object is an exception object (or an unwrappable + * cross-compartment wrapper for one), return the stack for that exception, if + * any. Will return null if the given object is not an exception object + * (including if it's null or a security wrapper that can't be unwrapped) or if + * the exception has no stack. + */ extern JS_PUBLIC_API(JSObject*) -ExceptionStackOrNull(JSContext* cx, JS::HandleObject obj); +ExceptionStackOrNull(JS::HandleObject obj); /* * Throws a StopIteration exception on cx. @@ -5112,23 +5731,20 @@ JS_ThrowStopIteration(JSContext* cx); extern JS_PUBLIC_API(bool) -JS_IsStopIteration(JS::Value v); - -extern JS_PUBLIC_API(intptr_t) -JS_GetCurrentThread(); +JS_IsStopIteration(const JS::Value& v); /** - * A JS runtime always has an "owner thread". The owner thread is set when the - * runtime is created (to the current thread) and practically all entry points - * into the JS engine check that a runtime (or anything contained in the - * runtime: context, compartment, object, etc) is only touched by its owner + * A JS context always has an "owner thread". The owner thread is set when the + * context is created (to the current thread) and practically all entry points + * into the JS engine check that a context (or anything contained in the + * context: runtime, compartment, object, etc) is only touched by its owner * thread. Embeddings may check this invariant outside the JS engine by calling * JS_AbortIfWrongThread (which will abort if not on the owner thread, even for * non-debug builds). */ extern JS_PUBLIC_API(void) -JS_AbortIfWrongThread(JSRuntime* rt); +JS_AbortIfWrongThread(JSContext* cx); /************************************************************************/ @@ -5146,7 +5762,7 @@ #define JS_DEFAULT_ZEAL_FREQ 100 extern JS_PUBLIC_API(void) -JS_GetGCZeal(JSContext* cx, uint8_t* zeal, uint32_t* frequency, uint32_t* nextScheduled); +JS_GetGCZealBits(JSContext* cx, uint32_t* zealBits, uint32_t* frequency, uint32_t* nextScheduled); extern JS_PUBLIC_API(void) JS_SetGCZeal(JSContext* cx, uint8_t zeal, uint32_t frequency); @@ -5156,10 +5772,10 @@ #endif extern JS_PUBLIC_API(void) -JS_SetParallelParsingEnabled(JSRuntime* rt, bool enabled); +JS_SetParallelParsingEnabled(JSContext* cx, bool enabled); extern JS_PUBLIC_API(void) -JS_SetOffthreadIonCompilationEnabled(JSRuntime* rt, bool enabled); +JS_SetOffthreadIonCompilationEnabled(JSContext* cx, bool enabled); #define JIT_COMPILER_OPTIONS(Register) \ Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \ @@ -5167,9 +5783,14 @@ Register(ION_GVN_ENABLE, "ion.gvn.enable") \ Register(ION_FORCE_IC, "ion.forceinlineCaches") \ Register(ION_ENABLE, "ion.enable") \ + Register(ION_INTERRUPT_WITHOUT_SIGNAL, "ion.interrupt-without-signals") \ + Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \ Register(BASELINE_ENABLE, "baseline.enable") \ Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \ - Register(SIGNALS_ENABLE, "signals.enable") + Register(JUMP_THRESHOLD, "jump-threshold") \ + Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \ + Register(WASM_TEST_MODE, "wasm.test-mode") \ + Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets") typedef enum JSJitCompilerOption { #define JIT_COMPILER_DECLARE(key, str) \ @@ -5182,9 +5803,9 @@ } JSJitCompilerOption; extern JS_PUBLIC_API(void) -JS_SetGlobalJitCompilerOption(JSRuntime* rt, JSJitCompilerOption opt, uint32_t value); -extern JS_PUBLIC_API(int) -JS_GetGlobalJitCompilerOption(JSRuntime* rt, JSJitCompilerOption opt); +JS_SetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t value); +extern JS_PUBLIC_API(bool) +JS_GetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t* valueOut); /** * Convert a uint32_t index into a jsid. @@ -5214,26 +5835,38 @@ extern JS_PUBLIC_API(bool) JS_IsIdentifier(const char16_t* chars, size_t length); +namespace js { +class ScriptSource; +} // namespace js + namespace JS { -/** - * AutoFilename encapsulates a pointer to a C-string and keeps the C-string - * alive for as long as the associated AutoFilename object is alive. - */ -class MOZ_STACK_CLASS JS_PUBLIC_API(AutoFilename) +class MOZ_RAII JS_PUBLIC_API(AutoFilename) { - void* scriptSource_; + private: + js::ScriptSource* ss_; + mozilla::Variant filename_; AutoFilename(const AutoFilename&) = delete; - void operator=(const AutoFilename&) = delete; + AutoFilename& operator=(const AutoFilename&) = delete; public: - AutoFilename() : scriptSource_(nullptr) {} - ~AutoFilename() { reset(nullptr); } + AutoFilename() + : ss_(nullptr), + filename_(mozilla::AsVariant(nullptr)) + {} - const char* get() const; + ~AutoFilename() { + reset(); + } - void reset(void* newScriptSource); + void reset(); + + void setOwned(UniqueChars&& filename); + void setUnowned(const char* filename); + void setScriptSource(js::ScriptSource* ss); + + const char* get() const; }; /** @@ -5288,23 +5921,62 @@ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; -} /* namespace JS */ - /* * Encode/Decode interpreted scripts and functions to/from memory. */ -extern JS_PUBLIC_API(void*) -JS_EncodeScript(JSContext* cx, JS::HandleScript script, uint32_t* lengthp); +typedef mozilla::Vector TranscodeBuffer; -extern JS_PUBLIC_API(void*) -JS_EncodeInterpretedFunction(JSContext* cx, JS::HandleObject funobj, uint32_t* lengthp); +enum TranscodeResult +{ + // Successful encoding / decoding. + TranscodeResult_Ok = 0, -extern JS_PUBLIC_API(JSScript*) -JS_DecodeScript(JSContext* cx, const void* data, uint32_t length); + // A warning message, is set to the message out-param. + TranscodeResult_Failure = 0x100, + TranscodeResult_Failure_BadBuildId = TranscodeResult_Failure | 0x1, + TranscodeResult_Failure_RunOnceNotSupported = TranscodeResult_Failure | 0x2, + TranscodeResult_Failure_AsmJSNotSupported = TranscodeResult_Failure | 0x3, + TranscodeResult_Failure_UnknownClassKind = TranscodeResult_Failure | 0x4, -extern JS_PUBLIC_API(JSObject*) -JS_DecodeInterpretedFunction(JSContext* cx, const void* data, uint32_t length); + // A error, the JSContext has a pending exception. + TranscodeResult_Throw = 0x200 +}; + +extern JS_PUBLIC_API(TranscodeResult) +EncodeScript(JSContext* cx, TranscodeBuffer& buffer, JS::HandleScript script); + +extern JS_PUBLIC_API(TranscodeResult) +EncodeInterpretedFunction(JSContext* cx, TranscodeBuffer& buffer, JS::HandleObject funobj); + +extern JS_PUBLIC_API(TranscodeResult) +DecodeScript(JSContext* cx, TranscodeBuffer& buffer, JS::MutableHandleScript scriptp, + size_t cursorIndex = 0); + +extern JS_PUBLIC_API(TranscodeResult) +DecodeInterpretedFunction(JSContext* cx, TranscodeBuffer& buffer, JS::MutableHandleFunction funp, + size_t cursorIndex = 0); + +} /* namespace JS */ + +namespace js { + +enum class StackFormat { SpiderMonkey, V8, Default }; + +/* + * Sets the format used for stringifying Error stacks. + * + * The default format is StackFormat::SpiderMonkey. Use StackFormat::V8 + * in order to emulate V8's stack formatting. StackFormat::Default can't be + * used here. + */ +extern JS_PUBLIC_API(void) +SetStackFormat(JSContext* cx, StackFormat format); + +extern JS_PUBLIC_API(StackFormat) +GetStackFormat(JSContext* cx); + +} namespace JS { @@ -5326,8 +5998,8 @@ /** The list of reasons why an asm.js module may not be stored in the cache. */ enum AsmJSCacheResult { - AsmJSCache_MIN, - AsmJSCache_Success = AsmJSCache_MIN, + AsmJSCache_Success, + AsmJSCache_MIN = AsmJSCache_Success, AsmJSCache_ModuleTooSmall, AsmJSCache_SynchronousScript, AsmJSCache_QuotaExceeded, @@ -5336,6 +6008,8 @@ AsmJSCache_Disabled_ShellFlags, AsmJSCache_Disabled_JitInspector, AsmJSCache_InternalError, + AsmJSCache_Disabled_PrivateBrowsing, + AsmJSCache_ESR52, AsmJSCache_LIMIT }; @@ -5361,7 +6035,16 @@ typedef void (* CloseAsmJSCacheEntryForWriteOp)(size_t size, uint8_t* memory, intptr_t handle); -typedef js::Vector BuildIdCharVector; +struct AsmJSCacheOps +{ + OpenAsmJSCacheEntryForReadOp openEntryForRead; + CloseAsmJSCacheEntryForReadOp closeEntryForRead; + OpenAsmJSCacheEntryForWriteOp openEntryForWrite; + CloseAsmJSCacheEntryForWriteOp closeEntryForWrite; +}; + +extern JS_PUBLIC_API(void) +SetAsmJSCacheOps(JSContext* cx, const AsmJSCacheOps* callbacks); /** * Return the buildId (represented as a sequence of characters) associated with @@ -5370,20 +6053,64 @@ * engine, it is critical that the buildId shall change for each new build of * the JS engine. */ +typedef js::Vector BuildIdCharVector; + typedef bool (* BuildIdOp)(BuildIdCharVector* buildId); -struct AsmJSCacheOps +extern JS_PUBLIC_API(void) +SetBuildIdOp(JSContext* cx, BuildIdOp buildIdOp); + +/** + * The WasmModule interface allows the embedding to hold a reference to the + * underying C++ implementation of a JS WebAssembly.Module object for purposes + * of (de)serialization off the object's JSRuntime's thread. + * + * - Serialization starts when WebAssembly.Module is passed to the + * structured-clone algorithm. JS::GetWasmModule is called on the JSRuntime + * thread that initiated the structured clone to get the JS::WasmModule. + * This interface is then taken to a background thread where serializedSize() + * and serialize() are called to write the object to two files: a bytecode file + * that always allows successful deserialization and a compiled-code file keyed + * on cpu- and build-id that may become invalid if either of these change between + * serialization and deserialization. After serialization, the reference is + * dropped from the background thread. + * + * - Deserialization starts when the structured clone algorithm encounters a + * serialized WebAssembly.Module. On a background thread, the compiled-code file + * is opened and CompiledWasmModuleAssumptionsMatch is called to see if it is + * still valid (as described above). DeserializeWasmModule is then called to + * construct a JS::WasmModule (also on the background thread), passing the + * bytecode file descriptor and, if valid, the compiled-code file descriptor. + * The JS::WasmObject is then transported to the JSRuntime thread (which + * originated the request) and the wrapping WebAssembly.Module object is created + * by calling createObject(). + */ + +struct WasmModule : mozilla::external::AtomicRefCounted { - OpenAsmJSCacheEntryForReadOp openEntryForRead; - CloseAsmJSCacheEntryForReadOp closeEntryForRead; - OpenAsmJSCacheEntryForWriteOp openEntryForWrite; - CloseAsmJSCacheEntryForWriteOp closeEntryForWrite; - BuildIdOp buildId; + MOZ_DECLARE_REFCOUNTED_TYPENAME(WasmModule) + virtual ~WasmModule() {} + + virtual void serializedSize(size_t* maybeBytecodeSize, size_t* maybeCompiledSize) const = 0; + virtual void serialize(uint8_t* maybeBytecodeBegin, size_t maybeBytecodeSize, + uint8_t* maybeCompiledBegin, size_t maybeCompiledSize) const = 0; + + virtual JSObject* createObject(JSContext* cx) = 0; }; -extern JS_PUBLIC_API(void) -SetAsmJSCacheOps(JSRuntime* rt, const AsmJSCacheOps* callbacks); +extern JS_PUBLIC_API(bool) +IsWasmModuleObject(HandleObject obj); + +extern JS_PUBLIC_API(RefPtr) +GetWasmModule(HandleObject obj); + +extern JS_PUBLIC_API(bool) +CompiledWasmModuleAssumptionsMatch(PRFileDesc* compiled, BuildIdCharVector&& buildId); + +extern JS_PUBLIC_API(RefPtr) +DeserializeWasmModule(PRFileDesc* bytecode, PRFileDesc* maybeCompiled, BuildIdCharVector&& buildId, + JS::UniqueChars filename, unsigned line, unsigned column); /** * Convenience class for imitating a JS level for-of loop. Typical usage: @@ -5475,7 +6202,7 @@ (* LargeAllocationFailureCallback)(void* data); extern JS_PUBLIC_API(void) -SetLargeAllocationFailureCallback(JSRuntime* rt, LargeAllocationFailureCallback afc, void* data); +SetLargeAllocationFailureCallback(JSContext* cx, LargeAllocationFailureCallback afc, void* data); /** * Unlike the error reporter, which is only called if the exception for an OOM @@ -5492,17 +6219,99 @@ (* OutOfMemoryCallback)(JSContext* cx, void* data); extern JS_PUBLIC_API(void) -SetOutOfMemoryCallback(JSRuntime* rt, OutOfMemoryCallback cb, void* data); +SetOutOfMemoryCallback(JSContext* cx, OutOfMemoryCallback cb, void* data); + +/** + * Capture all frames. + */ +struct AllFrames { }; + +/** + * Capture at most this many frames. + */ +struct MaxFrames +{ + uint32_t maxFrames; + + explicit MaxFrames(uint32_t max) + : maxFrames(max) + { + MOZ_ASSERT(max > 0); + } +}; + +/** + * Capture the first frame with the given principals. By default, do not + * consider self-hosted frames with the given principals as satisfying the stack + * capture. + */ +struct JS_PUBLIC_API(FirstSubsumedFrame) +{ + JSContext* cx; + JSPrincipals* principals; + bool ignoreSelfHosted; + + /** + * Use the cx's current compartment's principals. + */ + explicit FirstSubsumedFrame(JSContext* cx, bool ignoreSelfHostedFrames = true); + explicit FirstSubsumedFrame(JSContext* ctx, JSPrincipals* p, bool ignoreSelfHostedFrames = true) + : cx(ctx) + , principals(p) + , ignoreSelfHosted(ignoreSelfHostedFrames) + { + if (principals) + JS_HoldPrincipals(principals); + } + + // No copying because we want to avoid holding and dropping principals + // unnecessarily. + FirstSubsumedFrame(const FirstSubsumedFrame&) = delete; + FirstSubsumedFrame& operator=(const FirstSubsumedFrame&) = delete; + + FirstSubsumedFrame(FirstSubsumedFrame&& rhs) + : principals(rhs.principals) + , ignoreSelfHosted(rhs.ignoreSelfHosted) + { + MOZ_ASSERT(this != &rhs, "self move disallowed"); + rhs.principals = nullptr; + } + + FirstSubsumedFrame& operator=(FirstSubsumedFrame&& rhs) { + new (this) FirstSubsumedFrame(mozilla::Move(rhs)); + return *this; + } + + ~FirstSubsumedFrame() { + if (principals) + JS_DropPrincipals(cx, principals); + } +}; + +using StackCapture = mozilla::Variant; /** * Capture the current call stack as a chain of SavedFrame JSObjects, and set * |stackp| to the SavedFrame for the youngest stack frame, or nullptr if there - * are no JS frames on the stack. If |maxFrameCount| is non-zero, capture at - * most the youngest |maxFrameCount| frames. + * are no JS frames on the stack. + * + * The |capture| parameter describes the portion of the JS stack to capture: + * + * * |JS::AllFrames|: Capture all frames on the stack. + * + * * |JS::MaxFrames|: Capture no more than |JS::MaxFrames::maxFrames| from the + * stack. + * + * * |JS::FirstSubsumedFrame|: Capture the first frame whose principals are + * subsumed by |JS::FirstSubsumedFrame::principals|. By default, do not + * consider self-hosted frames; this can be controlled via the + * |JS::FirstSubsumedFrame::ignoreSelfHosted| flag. Do not capture any async + * stack. */ extern JS_PUBLIC_API(bool) -CaptureCurrentStack(JSContext* cx, MutableHandleObject stackp, unsigned maxFrameCount = 0); +CaptureCurrentStack(JSContext* cx, MutableHandleObject stackp, + StackCapture&& capture = StackCapture(AllFrames())); /* * This is a utility function for preparing an async stack to be used @@ -5632,7 +6441,15 @@ * each line. */ extern JS_PUBLIC_API(bool) -BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp, size_t indent = 0); +BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp, + size_t indent = 0, js::StackFormat stackFormat = js::StackFormat::Default); + +/** + * Return true iff the given object is either a SavedFrame object or wrapper + * around a SavedFrame object, and it is not the SavedFrame.prototype object. + */ +extern JS_PUBLIC_API(bool) +IsSavedFrame(JSObject* obj); } /* namespace JS */ @@ -5649,7 +6466,7 @@ * provide a concrete implementation of this class, as well as the * relevant callbacks (see below). */ -struct PerformanceGroup { +struct JS_PUBLIC_API(PerformanceGroup) { PerformanceGroup(); // The current iteration of the event loop. @@ -5745,6 +6562,8 @@ uint64_t refCount_; }; +using PerformanceGroupVector = mozilla::Vector, 0, SystemAllocPolicy>; + /** * Commit any Performance Monitoring data. * @@ -5752,19 +6571,19 @@ * to the outside world and can cancelled with a call to `ResetMonitoring`. */ extern JS_PUBLIC_API(bool) -FlushPerformanceMonitoring(JSRuntime*); +FlushPerformanceMonitoring(JSContext*); /** * Cancel any measurement that hasn't been committed. */ extern JS_PUBLIC_API(void) -ResetPerformanceMonitoring(JSRuntime*); +ResetPerformanceMonitoring(JSContext*); /** * Cleanup any memory used by performance monitoring. */ extern JS_PUBLIC_API(void) -DisposePerformanceMonitoring(JSRuntime*); +DisposePerformanceMonitoring(JSContext*); /** * Turn on/off stopwatch-based CPU monitoring. @@ -5774,20 +6593,17 @@ * happen if we are out of memory. */ extern JS_PUBLIC_API(bool) -SetStopwatchIsMonitoringCPOW(JSRuntime*, bool); +SetStopwatchIsMonitoringCPOW(JSContext*, bool); extern JS_PUBLIC_API(bool) -GetStopwatchIsMonitoringCPOW(JSRuntime*); +GetStopwatchIsMonitoringCPOW(JSContext*); extern JS_PUBLIC_API(bool) -SetStopwatchIsMonitoringJank(JSRuntime*, bool); -extern JS_PUBLIC_API(bool) -GetStopwatchIsMonitoringJank(JSRuntime*); - +SetStopwatchIsMonitoringJank(JSContext*, bool); extern JS_PUBLIC_API(bool) -IsStopwatchActive(JSRuntime*); +GetStopwatchIsMonitoringJank(JSContext*); // Extract the CPU rescheduling data. extern JS_PUBLIC_API(void) -GetPerfMonitoringTestCpuRescheduling(JSRuntime*, uint64_t* stayed, uint64_t* moved); +GetPerfMonitoringTestCpuRescheduling(JSContext*, uint64_t* stayed, uint64_t* moved); /** @@ -5795,22 +6611,22 @@ * since process start. */ extern JS_PUBLIC_API(void) -AddCPOWPerformanceDelta(JSRuntime*, uint64_t delta); +AddCPOWPerformanceDelta(JSContext*, uint64_t delta); typedef bool (*StopwatchStartCallback)(uint64_t, void*); extern JS_PUBLIC_API(bool) -SetStopwatchStartCallback(JSRuntime*, StopwatchStartCallback, void*); +SetStopwatchStartCallback(JSContext*, StopwatchStartCallback, void*); typedef bool -(*StopwatchCommitCallback)(uint64_t, mozilla::Vector>&, void*); +(*StopwatchCommitCallback)(uint64_t, PerformanceGroupVector&, void*); extern JS_PUBLIC_API(bool) -SetStopwatchCommitCallback(JSRuntime*, StopwatchCommitCallback, void*); +SetStopwatchCommitCallback(JSContext*, StopwatchCommitCallback, void*); typedef bool -(*GetGroupsCallback)(JSContext*, mozilla::Vector>&, void*); +(*GetGroupsCallback)(JSContext*, PerformanceGroupVector&, void*); extern JS_PUBLIC_API(bool) -SetGetPerformanceGroupsCallback(JSRuntime*, GetGroupsCallback, void*); +SetGetPerformanceGroupsCallback(JSContext*, GetGroupsCallback, void*); } /* namespace js */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/jscpucfg.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/jscpucfg.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/jscpucfg.h @@ -7,119 +7,7 @@ #ifndef jscpucfg_h #define jscpucfg_h -#define JS_HAVE_LONG_LONG - -#if defined(_WIN64) - -# if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_) -# define IS_LITTLE_ENDIAN 1 -# undef IS_BIG_ENDIAN -# else /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */ -# error "CPU type is unknown" -# endif /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */ - -#elif defined(_WIN32) - -# ifdef __WATCOMC__ -# define HAVE_VA_LIST_AS_ARRAY 1 -# endif - -# define IS_LITTLE_ENDIAN 1 -# undef IS_BIG_ENDIAN - -#elif defined(__APPLE__) || defined(__powerpc__) || defined(__ppc__) -# if __LITTLE_ENDIAN__ -# define IS_LITTLE_ENDIAN 1 -# undef IS_BIG_ENDIAN -# elif __BIG_ENDIAN__ -# undef IS_LITTLE_ENDIAN -# define IS_BIG_ENDIAN 1 -# endif - -#elif defined(JS_HAVE_ENDIAN_H) -# include - -/* - * Historically, OSes providing only defined - * __BYTE_ORDER to either __LITTLE_ENDIAN or __BIG_ENDIAN. - * The Austin group decided to standardise in - * POSIX around 2011, expecting it to provide a BYTE_ORDER - * #define set to either LITTLE_ENDIAN or BIG_ENDIAN. We - * should try to cope with both possibilities here. - */ - -# if defined(__BYTE_ORDER) || defined(BYTE_ORDER) -# if defined(__BYTE_ORDER) -# if __BYTE_ORDER == __LITTLE_ENDIAN -# define IS_LITTLE_ENDIAN 1 -# undef IS_BIG_ENDIAN -# elif __BYTE_ORDER == __BIG_ENDIAN -# undef IS_LITTLE_ENDIAN -# define IS_BIG_ENDIAN 1 -# endif -# endif -# if defined(BYTE_ORDER) -# if BYTE_ORDER == LITTLE_ENDIAN -# define IS_LITTLE_ENDIAN 1 -# undef IS_BIG_ENDIAN -# elif BYTE_ORDER == BIG_ENDIAN -# undef IS_LITTLE_ENDIAN -# define IS_BIG_ENDIAN 1 -# endif -# endif -# else /* !defined(__BYTE_ORDER) */ -# error "endian.h does not define __BYTE_ORDER nor BYTE_ORDER. Cannot determine endianness." -# endif - -/* BSDs */ -#elif defined(JS_HAVE_MACHINE_ENDIAN_H) -# include -# include - -# if defined(_BYTE_ORDER) -# if _BYTE_ORDER == _LITTLE_ENDIAN -# define IS_LITTLE_ENDIAN 1 -# undef IS_BIG_ENDIAN -# elif _BYTE_ORDER == _BIG_ENDIAN -# undef IS_LITTLE_ENDIAN -# define IS_BIG_ENDIAN 1 -# endif -# else /* !defined(_BYTE_ORDER) */ -# error "machine/endian.h does not define _BYTE_ORDER. Cannot determine endianness." -# endif - -#elif defined(JS_HAVE_SYS_ISA_DEFS_H) -# include - -# if defined(_BIG_ENDIAN) -# undef IS_LITTLE_ENDIAN -# define IS_BIG_ENDIAN 1 -# elif defined(_LITTLE_ENDIAN) -# define IS_LITTLE_ENDIAN 1 -# undef IS_BIG_ENDIAN -# else /* !defined(_LITTLE_ENDIAN) */ -# error "sys/isa_defs.h does not define _BIG_ENDIAN or _LITTLE_ENDIAN. Cannot determine endianness." -# endif -# if !defined(JS_STACK_GROWTH_DIRECTION) -# if defined(_STACK_GROWS_UPWARD) -# define JS_STACK_GROWTH_DIRECTION (1) -# elif defined(_STACK_GROWS_DOWNWARD) -# define JS_STACK_GROWTH_DIRECTION (-1) -# endif -# endif - -#elif defined(__sparc) || defined(__sparc__) || \ - defined(_POWER) || defined(__hppa) || \ - defined(_MIPSEB) || defined(_BIG_ENDIAN) -/* IA64 running HP-UX will have _BIG_ENDIAN defined. - * IA64 running Linux will have endian.h and be handled above. - */ -# undef IS_LITTLE_ENDIAN -# define IS_BIG_ENDIAN 1 - -#else /* !defined(__sparc) && !defined(__sparc__) && ... */ -# error "Cannot determine endianness of your platform. Please add support to jscpucfg.h." -#endif +#include "mozilla/EndianUtils.h" #ifndef JS_STACK_GROWTH_DIRECTION # ifdef __hppa Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/jsfriendapi.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/jsfriendapi.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/jsfriendapi.h @@ -9,6 +9,7 @@ #include "mozilla/Atomics.h" #include "mozilla/Casting.h" +#include "mozilla/Maybe.h" #include "mozilla/MemoryReporting.h" #include "mozilla/UniquePtr.h" @@ -19,6 +20,7 @@ #include "js/CallArgs.h" #include "js/CallNonGenericMethod.h" #include "js/Class.h" +#include "js/Utility.h" #if JS_STACK_GROWTH_DIRECTION > 0 # define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) < (limit))) @@ -43,7 +45,7 @@ } /* namespace js */ extern JS_FRIEND_API(void) -JS_SetGrayGCRootsTracer(JSRuntime* rt, JSTraceDataOp traceOp, void* data); +JS_SetGrayGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp, void* data); extern JS_FRIEND_API(JSObject*) JS_FindCompilationScope(JSContext* cx, JS::HandleObject obj); @@ -72,9 +74,6 @@ extern JS_FRIEND_API(size_t) JS_SetProtoCalled(JSContext* cx); -extern JS_FRIEND_API(bool) -JS_ImmutablePrototypesEnabled(); - extern JS_FRIEND_API(size_t) JS_GetCustomIteratorCount(JSContext* cx); @@ -108,36 +107,46 @@ enum { JS_TELEMETRY_GC_REASON, - JS_TELEMETRY_GC_IS_COMPARTMENTAL, + JS_TELEMETRY_GC_IS_ZONE_GC, JS_TELEMETRY_GC_MS, JS_TELEMETRY_GC_BUDGET_MS, JS_TELEMETRY_GC_ANIMATION_MS, JS_TELEMETRY_GC_MAX_PAUSE_MS, JS_TELEMETRY_GC_MARK_MS, JS_TELEMETRY_GC_SWEEP_MS, + JS_TELEMETRY_GC_COMPACT_MS, JS_TELEMETRY_GC_MARK_ROOTS_MS, JS_TELEMETRY_GC_MARK_GRAY_MS, JS_TELEMETRY_GC_SLICE_MS, JS_TELEMETRY_GC_SLOW_PHASE, JS_TELEMETRY_GC_MMU_50, JS_TELEMETRY_GC_RESET, + JS_TELEMETRY_GC_RESET_REASON, JS_TELEMETRY_GC_INCREMENTAL_DISABLED, JS_TELEMETRY_GC_NON_INCREMENTAL, + JS_TELEMETRY_GC_NON_INCREMENTAL_REASON, JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, JS_TELEMETRY_GC_MINOR_REASON, JS_TELEMETRY_GC_MINOR_REASON_LONG, JS_TELEMETRY_GC_MINOR_US, + JS_TELEMETRY_GC_NURSERY_BYTES, + JS_TELEMETRY_GC_PRETENURE_COUNT, JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT, JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_ADDONS, - JS_TELEMETRY_ADDON_EXCEPTIONS + JS_TELEMETRY_ADDON_EXCEPTIONS, + JS_TELEMETRY_AOT_USAGE, + JS_TELEMETRY_END }; typedef void (*JSAccumulateTelemetryDataCallback)(int id, uint32_t sample, const char* key); extern JS_FRIEND_API(void) -JS_SetAccumulateTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback); +JS_SetAccumulateTelemetryCallback(JSContext* cx, JSAccumulateTelemetryDataCallback callback); + +extern JS_FRIEND_API(bool) +JS_GetIsSecureContext(JSCompartment* compartment); extern JS_FRIEND_API(JSPrincipals*) JS_GetCompartmentPrincipals(JSCompartment* compartment); @@ -178,7 +187,7 @@ namespace js { JS_FRIEND_API(bool) -GetBuiltinClass(JSContext* cx, JS::HandleObject obj, ESClassValue* classValue); +GetBuiltinClass(JSContext* cx, JS::HandleObject obj, ESClass* cls); JS_FRIEND_API(const char*) ObjectClassName(JSContext* cx, JS::HandleObject obj); @@ -198,41 +207,57 @@ #ifdef JS_DEBUG /* - * Routines to print out values during debugging. These are FRIEND_API to help + * Routines to print out values during debugging. These are FRIEND_API to help * the debugger find them and to support temporarily hacking js::Dump* calls - * into other code. + * into other code. Note that there are overloads that do not require the FILE* + * parameter, which will default to stderr. */ extern JS_FRIEND_API(void) -DumpString(JSString* str); +DumpString(JSString* str, FILE* fp); extern JS_FRIEND_API(void) -DumpAtom(JSAtom* atom); +DumpAtom(JSAtom* atom, FILE* fp); extern JS_FRIEND_API(void) -DumpObject(JSObject* obj); +DumpObject(JSObject* obj, FILE* fp); extern JS_FRIEND_API(void) -DumpChars(const char16_t* s, size_t n); +DumpChars(const char16_t* s, size_t n, FILE* fp); extern JS_FRIEND_API(void) -DumpValue(const JS::Value& val); +DumpValue(const JS::Value& val, FILE* fp); extern JS_FRIEND_API(void) -DumpId(jsid id); +DumpId(jsid id, FILE* fp); extern JS_FRIEND_API(void) -DumpInterpreterFrame(JSContext* cx, InterpreterFrame* start = nullptr); +DumpInterpreterFrame(JSContext* cx, FILE* fp, InterpreterFrame* start = nullptr); extern JS_FRIEND_API(bool) -DumpPC(JSContext* cx); +DumpPC(JSContext* cx, FILE* fp); extern JS_FRIEND_API(bool) -DumpScript(JSContext* cx, JSScript* scriptArg); +DumpScript(JSContext* cx, JSScript* scriptArg, FILE* fp); + +// Versions for use directly in a debugger (default parameters are not handled +// well in gdb; built-in handles like stderr are not handled well in lldb.) +extern JS_FRIEND_API(void) DumpString(JSString* str); +extern JS_FRIEND_API(void) DumpAtom(JSAtom* atom); +extern JS_FRIEND_API(void) DumpObject(JSObject* obj); +extern JS_FRIEND_API(void) DumpChars(const char16_t* s, size_t n); +extern JS_FRIEND_API(void) DumpValue(const JS::Value& val); +extern JS_FRIEND_API(void) DumpId(jsid id); +extern JS_FRIEND_API(void) DumpInterpreterFrame(JSContext* cx, InterpreterFrame* start = nullptr); +extern JS_FRIEND_API(bool) DumpPC(JSContext* cx); +extern JS_FRIEND_API(bool) DumpScript(JSContext* cx, JSScript* scriptArg); #endif extern JS_FRIEND_API(void) +DumpBacktrace(JSContext* cx, FILE* fp); + +extern JS_FRIEND_API(void) DumpBacktrace(JSContext* cx); } // namespace js @@ -243,6 +268,13 @@ extern JS_FRIEND_API(char*) FormatStackDump(JSContext* cx, char* buf, bool showArgs, bool showLocals, bool showThisProps); +/** + * Set all of the uninitialized lexicals on an object to undefined. Return + * true if any lexicals were initialized and false otherwise. + * */ +extern JS_FRIEND_API(bool) +ForceLexicalInitialization(JSContext *cx, HandleObject obj); + } // namespace JS /** @@ -275,7 +307,7 @@ PropertyCopyBehavior copyBehavior = CopyNonConfigurableAsIs); extern JS_FRIEND_API(bool) -JS_WrapPropertyDescriptor(JSContext* cx, JS::MutableHandle desc); +JS_WrapPropertyDescriptor(JSContext* cx, JS::MutableHandle desc); struct JSFunctionSpecWithHelp { const char* name; @@ -300,61 +332,37 @@ namespace js { +extern JS_FRIEND_DATA(const js::ClassOps) ProxyClassOps; +extern JS_FRIEND_DATA(const js::ClassExtension) ProxyClassExtension; +extern JS_FRIEND_DATA(const js::ObjectOps) ProxyObjectOps; + /* * Helper Macros for creating JSClasses that function as proxies. * * NB: The macro invocation must be surrounded by braces, so as to * allow for potential JSClass extensions. */ -#define PROXY_MAKE_EXT(isWrappedNative, objectMoved) \ +#define PROXY_MAKE_EXT(objectMoved) \ { \ - isWrappedNative, \ js::proxy_WeakmapKeyDelegate, \ objectMoved \ } -#define PROXY_CLASS_WITH_EXT(name, flags, ext) \ +#define PROXY_CLASS_WITH_EXT(name, flags, extPtr) \ { \ name, \ js::Class::NON_NATIVE | \ JSCLASS_IS_PROXY | \ - JSCLASS_DELAY_METADATA_CALLBACK | \ + JSCLASS_DELAY_METADATA_BUILDER | \ flags, \ - nullptr, /* addProperty */ \ - nullptr, /* delProperty */ \ - nullptr, /* getProperty */ \ - nullptr, /* setProperty */ \ - nullptr, /* enumerate */ \ - nullptr, /* resolve */ \ - nullptr, /* mayResolve */ \ - js::proxy_Finalize, /* finalize */ \ - nullptr, /* call */ \ - js::proxy_HasInstance, /* hasInstance */ \ - nullptr, /* construct */ \ - js::proxy_Trace, /* trace */ \ + &js::ProxyClassOps, \ JS_NULL_CLASS_SPEC, \ - ext, \ - { \ - js::proxy_LookupProperty, \ - js::proxy_DefineProperty, \ - js::proxy_HasProperty, \ - js::proxy_GetProperty, \ - js::proxy_SetProperty, \ - js::proxy_GetOwnPropertyDescriptor, \ - js::proxy_DeleteProperty, \ - js::proxy_Watch, js::proxy_Unwatch, \ - js::proxy_GetElements, \ - nullptr, /* enumerate */ \ - js::proxy_FunToString, \ - } \ - } - -#define PROXY_CLASS_DEF(name, flags) \ - PROXY_CLASS_WITH_EXT(name, flags, \ - PROXY_MAKE_EXT( \ - false, /* isWrappedNative */ \ - js::proxy_ObjectMoved \ - )) + extPtr, \ + &js::ProxyObjectOps \ + } + +#define PROXY_CLASS_DEF(name, flags) \ + PROXY_CLASS_WITH_EXT(name, flags, &js::ProxyClassExtension) /* * Proxy stubs, similar to JS_*Stub, for embedder proxy class definitions. @@ -367,7 +375,7 @@ JS::MutableHandle propp); extern JS_FRIEND_API(bool) proxy_DefineProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result); extern JS_FRIEND_API(bool) proxy_HasProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); @@ -379,7 +387,7 @@ JS::HandleValue receiver, JS::ObjectOpResult& result); extern JS_FRIEND_API(bool) proxy_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); extern JS_FRIEND_API(bool) proxy_DeleteProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::ObjectOpResult& result); @@ -436,17 +444,17 @@ }; /** - * Have |rt| use |hook| to retrieve lazily-retrieved source code. See the - * comments for SourceHook. The runtime takes ownership of the hook, and - * will delete it when the runtime itself is deleted, or when a new hook is + * Have |cx| use |hook| to retrieve lazily-retrieved source code. See the + * comments for SourceHook. The context takes ownership of the hook, and + * will delete it when the context itself is deleted, or when a new hook is * set. */ extern JS_FRIEND_API(void) -SetSourceHook(JSRuntime* rt, mozilla::UniquePtr hook); +SetSourceHook(JSContext* cx, mozilla::UniquePtr hook); -/** Remove |rt|'s source hook, and return it. The caller now owns the hook. */ +/** Remove |cx|'s source hook, and return it. The caller now owns the hook. */ extern JS_FRIEND_API(mozilla::UniquePtr) -ForgetSourceHook(JSRuntime* rt); +ForgetSourceHook(JSContext* cx); extern JS_FRIEND_API(JS::Zone*) GetCompartmentZone(JSCompartment* comp); @@ -464,7 +472,7 @@ * fp is the file for the dump output. */ extern JS_FRIEND_API(void) -DumpHeap(JSRuntime* rt, FILE* fp, DumpHeapNurseryBehaviour nurseryBehaviour); +DumpHeap(JSContext* cx, FILE* fp, DumpHeapNurseryBehaviour nurseryBehaviour); #ifdef JS_OLD_GETTER_SETTER_METHODS JS_FRIEND_API(bool) obj_defineGetter(JSContext* cx, unsigned argc, JS::Value* vp); @@ -485,9 +493,9 @@ struct WeakMapTracer { - JSRuntime* runtime; + JSContext* context; - explicit WeakMapTracer(JSRuntime* rt) : runtime(rt) {} + explicit WeakMapTracer(JSContext* cx) : context(cx) {} // Weak map tracer callback, called once for every binding of every // weak map that was live at the time of the last garbage collection. @@ -502,7 +510,7 @@ TraceWeakMaps(WeakMapTracer* trc); extern JS_FRIEND_API(bool) -AreGCGrayBitsValid(JSRuntime* rt); +AreGCGrayBitsValid(JSContext* cx); extern JS_FRIEND_API(bool) ZoneGlobalsAreAllGray(JS::Zone* zone); @@ -516,15 +524,19 @@ extern JS_FRIEND_API(JSObject*) GetWeakmapKeyDelegate(JSObject* key); -JS_FRIEND_API(JS::TraceKind) -GCThingTraceKind(void* thing); - /** - * Invoke cellCallback on every gray JS_OBJECT in the given zone. + * Invoke cellCallback on every gray JSObject in the given zone. */ extern JS_FRIEND_API(void) IterateGrayObjects(JS::Zone* zone, GCThingCallback cellCallback, void* data); +/** + * Invoke cellCallback on every gray JSObject in the given zone while cycle + * collection is in progress. + */ +extern JS_FRIEND_API(void) +IterateGrayObjectsUnderCC(JS::Zone* zone, GCThingCallback cellCallback, void* data); + #ifdef JS_HAS_CTYPES extern JS_FRIEND_API(size_t) SizeOfDataIfCDataObject(mozilla::MallocSizeOf mallocSizeOf, JSObject* obj); @@ -632,17 +644,6 @@ JS_FRIEND_API(const Class*) ProtoKeyToClass(JSProtoKey key); -// Returns true if the standard class identified by |key| inherits from -// another standard class (in addition to Object) along its proto chain. -// -// In practice, this only returns true for Error subtypes. -inline bool -StandardClassIsDependent(JSProtoKey key) -{ - const Class* clasp = ProtoKeyToClass(key); - return clasp && clasp->spec.defined() && clasp->spec.dependent(); -} - // Returns the key for the class inherited by a given standard class (that // is to say, the prototype of this standard class's prototype). // @@ -651,15 +652,15 @@ // cached proto key, except in cases where multiple JSProtoKeys share a // JSClass. inline JSProtoKey -ParentKeyForStandardClass(JSProtoKey key) +InheritanceProtoKeyForStandardClass(JSProtoKey key) { // [Object] has nothing to inherit from. if (key == JSProto_Object) return JSProto_Null; - // If we're dependent, return the key of the class we depend on. - if (StandardClassIsDependent(key)) - return ProtoKeyToClass(key)->spec.parentKey(); + // If we're ClassSpec defined return the proto key from that + if (ProtoKeyToClass(key)->specDefined()) + return ProtoKeyToClass(key)->specInheritanceProtoKey(); // Otherwise, we inherit [Object]. return JSProto_Object; @@ -729,6 +730,9 @@ JS_FRIEND_API(bool) GetObjectProto(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject proto); +extern JS_FRIEND_API(JSObject*) +GetStaticPrototype(JSObject* obj); + JS_FRIEND_API(bool) GetOriginalEval(JSContext* cx, JS::HandleObject scope, JS::MutableHandleObject eval); @@ -884,28 +888,50 @@ return reinterpret_cast(str); } +template +MOZ_ALWAYS_INLINE void +CopyLinearStringChars(CharType* dest, JSLinearString* s, size_t len, size_t start = 0); + MOZ_ALWAYS_INLINE void -CopyLinearStringChars(char16_t* dest, JSLinearString* s, size_t len) +CopyLinearStringChars(char16_t* dest, JSLinearString* s, size_t len, size_t start = 0) { + MOZ_ASSERT(start + len <= GetLinearStringLength(s)); JS::AutoCheckCannotGC nogc; if (LinearStringHasLatin1Chars(s)) { const JS::Latin1Char* src = GetLatin1LinearStringChars(nogc, s); for (size_t i = 0; i < len; i++) - dest[i] = src[i]; + dest[i] = src[start + i]; } else { const char16_t* src = GetTwoByteLinearStringChars(nogc, s); - mozilla::PodCopy(dest, src, len); + mozilla::PodCopy(dest, src + start, len); + } +} + +MOZ_ALWAYS_INLINE void +CopyLinearStringChars(char* dest, JSLinearString* s, size_t len, size_t start = 0) +{ + MOZ_ASSERT(start + len <= GetLinearStringLength(s)); + JS::AutoCheckCannotGC nogc; + if (LinearStringHasLatin1Chars(s)) { + const JS::Latin1Char* src = GetLatin1LinearStringChars(nogc, s); + for (size_t i = 0; i < len; i++) + dest[i] = char(src[start + i]); + } else { + const char16_t* src = GetTwoByteLinearStringChars(nogc, s); + for (size_t i = 0; i < len; i++) + dest[i] = char(src[start + i]); } } +template inline bool -CopyStringChars(JSContext* cx, char16_t* dest, JSString* s, size_t len) +CopyStringChars(JSContext* cx, CharType* dest, JSString* s, size_t len, size_t start = 0) { JSLinearString* linear = StringToLinearString(cx, s); if (!linear) return false; - CopyLinearStringChars(dest, linear, len); + CopyLinearStringChars(dest, linear, len, start); return true; } @@ -946,15 +972,12 @@ StringIsArrayIndex(JSLinearString* str, uint32_t* indexp); JS_FRIEND_API(void) -SetPreserveWrapperCallback(JSRuntime* rt, PreserveWrapperCallback callback); +SetPreserveWrapperCallback(JSContext* cx, PreserveWrapperCallback callback); JS_FRIEND_API(bool) IsObjectInContextCompartment(JSObject* obj, const JSContext* cx); /* - * NB: these flag bits are encoded into the bytecode stream in the immediate - * operand of JSOP_ITER, so don't change them without advancing vm/Xdr.h's - * XDR_BYTECODE_VERSION. * NB: keep these in sync with the copy in builtin/SelfHostingDefines.h. * The first three are omitted because they shouldn't be used in new code. */ @@ -972,9 +995,7 @@ inline uintptr_t GetNativeStackLimit(JSContext* cx, StackKind kind, int extraAllowance = 0) { - PerThreadDataFriendFields* mainThread = - PerThreadDataFriendFields::getMainThread(GetRuntime(cx)); - uintptr_t limit = mainThread->nativeStackLimit[kind]; + uintptr_t limit = ContextFriendFields::get(cx)->nativeStackLimit[kind]; #if JS_STACK_GROWTH_DIRECTION > 0 limit += extraAllowance; #else @@ -1080,9 +1101,6 @@ JS_FRIEND_API(char*) GetCodeCoverageSummary(JSContext* cx, size_t* length); -JS_FRIEND_API(bool) -ContextHasOutstandingRequests(const JSContext* cx); - typedef void (* ActivityCallback)(void* arg, bool active); @@ -1092,7 +1110,7 @@ * idle and a request begins. */ JS_FRIEND_API(void) -SetActivityCallback(JSRuntime* rt, ActivityCallback cb, void* arg); +SetActivityCallback(JSContext* cx, ActivityCallback cb, void* arg); typedef bool (* DOMInstanceClassHasProtoAtDepth)(const Class* instanceClass, @@ -1103,10 +1121,10 @@ typedef struct JSDOMCallbacks DOMCallbacks; extern JS_FRIEND_API(void) -SetDOMCallbacks(JSRuntime* rt, const DOMCallbacks* callbacks); +SetDOMCallbacks(JSContext* cx, const DOMCallbacks* callbacks); extern JS_FRIEND_API(const DOMCallbacks*) -GetDOMCallbacks(JSRuntime* rt); +GetDOMCallbacks(JSContext* cx); extern JS_FRIEND_API(JSObject*) GetTestingFunctions(JSContext* cx); @@ -1129,7 +1147,7 @@ * Returns nullptr for invalid arguments and JSEXN_INTERNALERR */ extern JS_FRIEND_API(JSFlatString*) -GetErrorTypeName(JSRuntime* rt, int16_t exnType); +GetErrorTypeName(JSContext* cx, int16_t exnType); #ifdef JS_DEBUG extern JS_FRIEND_API(unsigned) @@ -1221,10 +1239,9 @@ generation(0) {} - void Unlink() + void OwnerUnlinked() { ++generation; - expando.setUndefined(); } static size_t offsetOfExpando() @@ -1306,29 +1323,35 @@ * JSString methods and often the code can be rewritten so that only indexes * instead of char pointers are used in parts of the code that can GC. */ -class MOZ_STACK_CLASS AutoStableStringChars +class MOZ_STACK_CLASS JS_FRIEND_API(AutoStableStringChars) { + /* + * When copying string char, use this many bytes of inline storage. This is + * chosen to allow the inline string types to be copied without allocating. + * This is asserted in AutoStableStringChars::allocOwnChars. + */ + static const size_t InlineCapacity = 24; + /* Ensure the string is kept alive while we're using its chars. */ JS::RootedString s_; union { const char16_t* twoByteChars_; const JS::Latin1Char* latin1Chars_; }; + mozilla::Maybe> ownChars_; enum State { Uninitialized, Latin1, TwoByte }; State state_; - bool ownsChars_; public: explicit AutoStableStringChars(JSContext* cx) - : s_(cx), state_(Uninitialized), ownsChars_(false) + : s_(cx), state_(Uninitialized) {} - ~AutoStableStringChars(); - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool init(JSContext* cx, JSString* s); /* Like init(), but Latin1 chars are inflated to TwoByte. */ - MOZ_WARN_UNUSED_RESULT + MOZ_MUST_USE bool initTwoByte(JSContext* cx, JSString* s); bool isLatin1() const { return state_ == Latin1; } @@ -1348,46 +1371,79 @@ mozilla::Range twoByteRange() const { MOZ_ASSERT(state_ == TwoByte); return mozilla::Range(twoByteChars_, - GetStringLength(s_)); + GetStringLength(s_)); } /* If we own the chars, transfer ownership to the caller. */ bool maybeGiveOwnershipToCaller() { MOZ_ASSERT(state_ != Uninitialized); - if (!ownsChars_) + if (!ownChars_.isSome() || !ownChars_->extractRawBuffer()) return false; state_ = Uninitialized; - ownsChars_ = false; + ownChars_.reset(); return true; } private: AutoStableStringChars(const AutoStableStringChars& other) = delete; void operator=(const AutoStableStringChars& other) = delete; -}; -/** - * Creates a string of the form |ErrorType: ErrorMessage| for a JSErrorReport, - * which generally matches the toString() behavior of an ErrorObject. - */ -extern JS_FRIEND_API(JSString*) -ErrorReportToString(JSContext* cx, JSErrorReport* reportp); + bool baseIsInline(JS::Handle linearString); + template T* allocOwnChars(JSContext* cx, size_t count); + bool copyLatin1Chars(JSContext* cx, JS::Handle linearString); + bool copyTwoByteChars(JSContext* cx, JS::Handle linearString); + bool copyAndInflateLatin1Chars(JSContext*, JS::Handle linearString); +}; struct MOZ_STACK_CLASS JS_FRIEND_API(ErrorReport) { explicit ErrorReport(JSContext* cx); ~ErrorReport(); - bool init(JSContext* cx, JS::HandleValue exn); + enum SniffingBehavior { + WithSideEffects, + NoSideEffects + }; + + /** + * Generate a JSErrorReport from the provided thrown value. + * + * If the value is a (possibly wrapped) Error object, the JSErrorReport will + * be exactly initialized from the Error object's information, without + * observable side effects. (The Error object's JSErrorReport is reused, if + * it has one.) + * + * Otherwise various attempts are made to derive JSErrorReport information + * from |exn| and from the current execution state. This process is + * *definitely* inconsistent with any standard, and particulars of the + * behavior implemented here generally shouldn't be relied upon. + * + * If the value of |sniffingBehavior| is |WithSideEffects|, some of these + * attempts *may* invoke user-configurable behavior when |exn| is an object: + * converting |exn| to a string, detecting and getting properties on |exn|, + * accessing |exn|'s prototype chain, and others are possible. Users *must* + * tolerate |ErrorReport::init| potentially having arbitrary effects. Any + * exceptions thrown by these operations will be caught and silently + * ignored, and "default" values will be substituted into the JSErrorReport. + * + * But if the value of |sniffingBehavior| is |NoSideEffects|, these attempts + * *will not* invoke any observable side effects. The JSErrorReport will + * simply contain fewer, less precise details. + * + * Unlike some functions involved in error handling, this function adheres + * to the usual JSAPI return value error behavior. + */ + bool init(JSContext* cx, JS::HandleValue exn, + SniffingBehavior sniffingBehavior); JSErrorReport* report() { return reportp; } - const char* message() + const JS::ConstUTF8CharsZ toStringResult() { - return message_; + return toStringResult_; } private: @@ -1397,8 +1453,8 @@ // // Returns false if we fail to actually populate the ErrorReport // for some reason (probably out of memory). - bool populateUncaughtExceptionReport(JSContext* cx, ...); - bool populateUncaughtExceptionReportVA(JSContext* cx, va_list ap); + bool populateUncaughtExceptionReportUTF8(JSContext* cx, ...); + bool populateUncaughtExceptionReportUTF8VA(JSContext* cx, va_list ap); // Reports exceptions from add-on scopes to telementry. void ReportAddonExceptionToTelementry(JSContext* cx); @@ -1406,16 +1462,9 @@ // We may have a provided JSErrorReport, so need a way to represent that. JSErrorReport* reportp; - // And we may have a message. - const char* message_; - // Or we may need to synthesize a JSErrorReport one of our own. JSErrorReport ownedReport; - // Or a message of our own. If this is non-null, we need to clean up both - // it and ownedReport. - char* ownedMessage; - // And we have a string to maybe keep alive that has pointers into // it from ownedReport. JS::RootedString str; @@ -1426,14 +1475,14 @@ // And we need to root our exception value. JS::RootedObject exnObject; - // And possibly some byte storage for our message_. - JSAutoByteString bytesStorage; - // And for our filename. JSAutoByteString filename; - // True if we need to free message_ and the stuff in ownedReport - bool ownsMessageAndReport; + // We may have a result of error.toString(). + // FIXME: We should not call error.toString(), since it could have side + // effect (see bug 633623). + JS::ConstUTF8CharsZ toStringResult_; + JSAutoByteString toStringResultBytesStorage; }; /* Implemented in vm/StructuredClone.cpp. */ @@ -1465,11 +1514,14 @@ Uint8Clamped, /** - * SIMD types don't have their own TypedArray equivalent, for now. + * Types that don't have their own TypedArray equivalent, for now. */ MaxTypedArrayViewType, + Int64, Float32x4, + Int8x16, + Int16x8, Int32x4 }; @@ -1488,8 +1540,11 @@ case Uint32: case Float32: return 4; + case Int64: case Float64: return 8; + case Int8x16: + case Int16x8: case Int32x4: case Float32x4: return 16; @@ -1504,6 +1559,9 @@ case Int8: case Int16: case Int32: + case Int64: + case Int8x16: + case Int16x8: case Int32x4: return true; case Uint8: @@ -1529,9 +1587,12 @@ case Uint16: case Int32: case Uint32: + case Int64: case Float32: case Float64: return false; + case Int8x16: + case Int16x8: case Int32x4: case Float32x4: return true; @@ -1544,6 +1605,10 @@ static inline size_t scalarByteSize(Type atype) { switch (atype) { + case Int8x16: + return 1; + case Int16x8: + return 2; case Int32x4: case Float32x4: return 4; @@ -1554,6 +1619,7 @@ case Uint16: case Int32: case Uint32: + case Int64: case Float32: case Float64: case MaxTypedArrayViewType: @@ -1653,7 +1719,10 @@ uint32_t byteOffset, int32_t length); /** - * Create a new SharedArrayBuffer with the given byte length. + * Create a new SharedArrayBuffer with the given byte length. This + * may only be called if + * JS::CompartmentCreationOptionsRef(cx).getSharedMemoryAndAtomicsEnabled() is + * true. */ extern JS_FRIEND_API(JSObject*) JS_NewSharedArrayBuffer(JSContext* cx, uint32_t nbytes); @@ -1889,7 +1958,7 @@ /** * Return true if the arrayBuffer contains any data. This will return false for - * ArrayBuffer.prototype and neutered ArrayBuffers. + * ArrayBuffer.prototype and detached ArrayBuffers. * * |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 @@ -2010,39 +2079,29 @@ JS_GetArrayBufferViewData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); /** - * Return the ArrayBuffer or SharedArrayBuffer underlying an - * ArrayBufferView. If the buffer has been neutered, this will still - * return the neutered buffer. |obj| must be an object that would + * Return the ArrayBuffer or SharedArrayBuffer underlying an ArrayBufferView. + * This may return a detached buffer. |obj| must be an object that would * return true for JS_IsArrayBufferViewObject(). */ extern JS_FRIEND_API(JSObject*) JS_GetArrayBufferViewBuffer(JSContext* cx, JS::HandleObject obj, bool* isSharedMemory); -typedef enum { - ChangeData, - KeepData -} NeuterDataDisposition; - /** - * Set an ArrayBuffer's length to 0 and neuter all of its views. + * Detach an ArrayBuffer, causing all associated views to no longer refer to + * the ArrayBuffer's original attached memory. * - * The |changeData| argument is a hint to inform internal behavior with respect - * to the internal pointer to the ArrayBuffer's data after being neutered. - * There is no guarantee it will be respected. But if it is respected, the - * ArrayBuffer's internal data pointer will, or will not, have changed - * accordingly. + * The |changeData| argument is obsolete and ignored. */ extern JS_FRIEND_API(bool) -JS_NeuterArrayBuffer(JSContext* cx, JS::HandleObject obj, - NeuterDataDisposition changeData); +JS_DetachArrayBuffer(JSContext* cx, JS::HandleObject obj); /** - * Check whether the obj is ArrayBufferObject and neutered. Note that this - * may return false if a security wrapper is encountered that denies the + * 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_FRIEND_API(bool) -JS_IsNeuteredArrayBufferObject(JSObject* obj); +JS_IsDetachedArrayBufferObject(JSObject* obj); /** * Check whether obj supports JS_GetDataView* APIs. @@ -2336,7 +2395,12 @@ js::jit::InlinableNative inlinableNative; }; - uint16_t depth; + union { + uint16_t depth; + + // Additional opcode for some InlinableNative functions. + uint16_t nativeOp; + }; // These fields are carefully packed to take up 4 bytes. If you need more // bits for whatever reason, please see if you can steal bits from existing @@ -2602,22 +2666,7 @@ ScriptEnvironmentPreparer::Closure& closure); JS_FRIEND_API(void) -SetScriptEnvironmentPreparer(JSRuntime* rt, ScriptEnvironmentPreparer* -preparer); - -/** - * To help embedders enforce their invariants, we allow them to specify in - * advance which JSContext should be passed to JSAPI calls. If this is set - * to a non-null value, the assertSameCompartment machinery does double- - * duty (in debug builds) to verify that it matches the cx being used. - */ -#ifdef DEBUG -JS_FRIEND_API(void) -Debug_SetActiveJSContext(JSRuntime* rt, JSContext* cx); -#else -inline void -Debug_SetActiveJSContext(JSRuntime* rt, JSContext* cx) {} -#endif +SetScriptEnvironmentPreparer(JSContext* cx, ScriptEnvironmentPreparer* preparer); enum CTypesActivityType { CTYPES_CALL_BEGIN, @@ -2634,7 +2683,7 @@ * calling into C. */ JS_FRIEND_API(void) -SetCTypesActivityCallback(JSRuntime* rt, CTypesActivityCallback cb); +SetCTypesActivityCallback(JSContext* cx, CTypesActivityCallback cb); class MOZ_RAII JS_FRIEND_API(AutoCTypesActivityCallback) { private: @@ -2658,8 +2707,23 @@ } }; -typedef JSObject* -(* ObjectMetadataCallback)(JSContext* cx, JSObject* obj); +// Abstract base class for objects that build allocation metadata for JavaScript +// values. +struct AllocationMetadataBuilder { + AllocationMetadataBuilder() { } + + // Return a metadata object for the newly constructed object |obj|, or + // nullptr if there's no metadata to attach. + // + // Implementations should treat all errors as fatal; there is no way to + // report errors from this callback. In particular, the caller provides an + // oomUnsafe for overriding implementations to use. + virtual JSObject* build(JSContext* cx, JS::HandleObject obj, + AutoEnterOOMUnsafeRegion& oomUnsafe) const + { + return nullptr; + } +}; /** * Specify a callback to invoke when creating each JS object in the current @@ -2667,11 +2731,11 @@ * object. */ JS_FRIEND_API(void) -SetObjectMetadataCallback(JSContext* cx, ObjectMetadataCallback callback); +SetAllocationMetadataBuilder(JSContext* cx, const AllocationMetadataBuilder *callback); /** Get the metadata associated with an object. */ JS_FRIEND_API(JSObject*) -GetObjectMetadata(JSObject* obj); +GetAllocationMetadata(JSObject* obj); JS_FRIEND_API(bool) GetElementsWithAdder(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver, @@ -2703,11 +2767,11 @@ JS_FRIEND_API(bool) SetPropertyIgnoringNamedGetter(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, JS::HandleValue receiver, - JS::Handle ownDesc, + JS::Handle ownDesc, JS::ObjectOpResult& result); JS_FRIEND_API(void) -ReportErrorWithId(JSContext* cx, const char* msg, JS::HandleId id); +ReportASCIIErrorWithId(JSContext* cx, const char* msg, JS::HandleId id); // This function is for one specific use case, please don't use this for anything else! extern JS_FRIEND_API(bool) @@ -2745,12 +2809,12 @@ #endif /** - * Get the nearest enclosing with scope object for a given function. If the - * function is not scripted or is not enclosed by a with scope, returns the - * global. + * Get the nearest enclosing with environment object for a given function. If + * the function is not scripted or is not enclosed by a with scope, returns + * the global. */ extern JS_FRIEND_API(JSObject*) -GetNearestEnclosingWithScopeObjectForFunction(JSFunction* fun); +GetNearestEnclosingWithEnvironmentObjectForFunction(JSFunction* fun); /** * Get the first SavedFrame object in this SavedFrame stack whose principals are @@ -2776,7 +2840,7 @@ * invariant that actual Window objects (the global objects of web pages) are * never directly exposed to script. Instead we often substitute a WindowProxy. * - * The scope chain, on the other hand, contains the Window and never its + * The environment chain, on the other hand, contains the Window and never its * WindowProxy. * * As a result, we have calls to these "substitute-this-object-for-that-object" @@ -2790,7 +2854,7 @@ * functions below. */ extern JS_FRIEND_API(void) -SetWindowProxyClass(JSRuntime* rt, const Class* clasp); +SetWindowProxyClass(JSContext* cx, const Class* clasp); /** * Associates a WindowProxy with a Window (global object). `windowProxy` must @@ -2842,26 +2906,6 @@ } /* namespace js */ -extern JS_FRIEND_API(void) -JS_StoreObjectPostBarrierCallback(JSContext* cx, - void (*callback)(JSTracer* trc, JSObject* key, void* data), - JSObject* key, void* data); - -extern JS_FRIEND_API(void) -JS_StoreStringPostBarrierCallback(JSContext* cx, - void (*callback)(JSTracer* trc, JSString* key, void* data), - JSString* key, void* data); - -/** - * Forcibly clear postbarrier callbacks queued by the previous two methods. - * This should be used when the object owning the postbarriered pointers is - * being destroyed outside of a garbage collection. - * - * This currently works by performing a minor GC. - */ -extern JS_FRIEND_API(void) -JS_ClearAllPostBarrierCallbacks(JSRuntime *rt); - class NativeProfiler { public: @@ -2888,7 +2932,7 @@ class MemProfiler { static mozilla::Atomic sActiveProfilerCount; - static NativeProfiler* sNativeProfiler; + static JS_FRIEND_DATA(NativeProfiler*) sNativeProfiler; static GCHeapProfiler* GetGCHeapProfiler(void* addr); static GCHeapProfiler* GetGCHeapProfiler(JSRuntime* runtime); @@ -2903,8 +2947,8 @@ public: explicit MemProfiler(JSRuntime* aRuntime) : mGCHeapProfiler(nullptr), mRuntime(aRuntime) {} - void start(GCHeapProfiler* aGCHeapProfiler); - void stop(); + JS_FRIEND_API(void) start(GCHeapProfiler* aGCHeapProfiler); + JS_FRIEND_API(void) stop(); GCHeapProfiler* getGCHeapProfiler() const { return mGCHeapProfiler; @@ -2914,7 +2958,7 @@ return sActiveProfilerCount > 0; } - static MemProfiler* GetMemProfiler(JSRuntime* runtime); + static JS_FRIEND_API(MemProfiler*) GetMemProfiler(JSContext* context); static void SetNativeProfiler(NativeProfiler* aProfiler) { sNativeProfiler = aProfiler; Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/jsperf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/jsperf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/jsperf.h @@ -126,7 +126,7 @@ * Value is not an instance of the wrapper. */ extern JS_FRIEND_API(PerfMeasurement*) - ExtractPerfMeasurement(Value wrapper); + ExtractPerfMeasurement(const Value& wrapper); } // namespace JS Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/jsprf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/jsprf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/jsprf.h @@ -14,34 +14,33 @@ ** %x - unsigned hex ** %X - unsigned uppercase hex ** %o - unsigned octal -** %hd, %hu, %hx, %hX, %ho - 16-bit versions of above -** %ld, %lu, %lx, %lX, %lo - 32-bit versions of above -** %lld, %llu, %llx, %llX, %llo - 64 bit versions of above -** %s - ascii string -** %hs - ucs2 string +** %hd, %hu, %hx, %hX, %ho - "short" versions of above +** %ld, %lu, %lx, %lX, %lo - "long" versions of above +** %lld, %llu, %llx, %llX, %llo - "long long" versions of above +** %zd, %zo, %zu, %zx, %zX - size_t versions of above +** %Id, %Io, %Iu, %Ix, %IX - size_t versions of above (for Windows compat) +** You should use PRI*SIZE macros instead +** %s - string ** %c - character ** %p - pointer (deals with machine dependent pointer size) ** %f - float ** %g - float */ +#include "mozilla/IntegerPrintfMacros.h" +#include "mozilla/SizePrintfMacros.h" + #include #include "jstypes.h" /* -** sprintf into a fixed size buffer. Guarantees that a NUL is at the end -** of the buffer. Returns the length of the written output, NOT including -** the NUL, or (uint32_t)-1 if an error occurs. -*/ -extern JS_PUBLIC_API(uint32_t) JS_snprintf(char* out, uint32_t outlen, const char* fmt, ...); - -/* ** sprintf into a malloc'd buffer. Return a pointer to the malloc'd ** buffer on success, nullptr on failure. Call "JS_smprintf_free" to release ** the memory returned. */ -extern JS_PUBLIC_API(char*) JS_smprintf(const char* fmt, ...); +extern JS_PUBLIC_API(char*) JS_smprintf(const char* fmt, ...) + MOZ_FORMAT_PRINTF(1, 2); /* ** Free the memory allocated, for the caller, by JS_smprintf @@ -55,12 +54,12 @@ ** will allocate the initial string. The return value is the new value of ** last for subsequent calls, or nullptr if there is a malloc failure. */ -extern JS_PUBLIC_API(char*) JS_sprintf_append(char* last, const char* fmt, ...); +extern JS_PUBLIC_API(char*) JS_sprintf_append(char* last, const char* fmt, ...) + MOZ_FORMAT_PRINTF(2, 3); /* ** va_list forms of the above. */ -extern JS_PUBLIC_API(uint32_t) JS_vsnprintf(char* out, uint32_t outlen, const char* fmt, va_list ap); extern JS_PUBLIC_API(char*) JS_vsmprintf(const char* fmt, va_list ap); extern JS_PUBLIC_API(char*) JS_vsprintf_append(char* last, const char* fmt, va_list ap); Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/jsprototypes.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/jsprototypes.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/jsprototypes.h @@ -49,12 +49,24 @@ #define IF_BDATA(real,imaginary) imaginary #endif +#ifdef ENABLE_SIMD +# define IF_SIMD(real,imaginary) real +#else +# define IF_SIMD(real,imaginary) imaginary +#endif + #ifdef ENABLE_SHARED_ARRAY_BUFFER #define IF_SAB(real,imaginary) real #else #define IF_SAB(real,imaginary) imaginary #endif +#ifdef SPIDERMONKEY_PROMISE +#define IF_PROMISE(real,imaginary) real +#else +#define IF_PROMISE(real,imaginary) imaginary +#endif + #define JS_FOR_PROTOTYPES(real,imaginary) \ imaginary(Null, 0, InitNullClass, dummy) \ real(Object, 1, InitViaClassSpec, OCLASP(Plain)) \ @@ -75,33 +87,42 @@ real(SyntaxError, 16, InitViaClassSpec, ERROR_CLASP(JSEXN_SYNTAXERR)) \ real(TypeError, 17, InitViaClassSpec, ERROR_CLASP(JSEXN_TYPEERR)) \ real(URIError, 18, InitViaClassSpec, ERROR_CLASP(JSEXN_URIERR)) \ - real(Iterator, 19, InitLegacyIteratorClass,OCLASP(PropertyIterator)) \ - real(StopIteration, 20, InitStopIterationClass, OCLASP(StopIteration)) \ - real(ArrayBuffer, 21, InitArrayBufferClass, &js::ArrayBufferObject::protoClass) \ - real(Int8Array, 22, InitViaClassSpec, TYPED_ARRAY_CLASP(Int8)) \ - real(Uint8Array, 23, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8)) \ - real(Int16Array, 24, InitViaClassSpec, TYPED_ARRAY_CLASP(Int16)) \ - real(Uint16Array, 25, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint16)) \ - real(Int32Array, 26, InitViaClassSpec, TYPED_ARRAY_CLASP(Int32)) \ - real(Uint32Array, 27, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint32)) \ - real(Float32Array, 28, InitViaClassSpec, TYPED_ARRAY_CLASP(Float32)) \ - real(Float64Array, 29, InitViaClassSpec, TYPED_ARRAY_CLASP(Float64)) \ - real(Uint8ClampedArray, 30, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8Clamped)) \ - real(Proxy, 31, InitProxyClass, js::ProxyClassPtr) \ - real(WeakMap, 32, InitWeakMapClass, OCLASP(WeakMap)) \ - real(Map, 33, InitMapClass, OCLASP(Map)) \ - real(Set, 34, InitSetClass, OCLASP(Set)) \ - real(DataView, 35, InitDataViewClass, OCLASP(DataView)) \ - real(Symbol, 36, InitSymbolClass, OCLASP(Symbol)) \ -IF_SAB(real,imaginary)(SharedArrayBuffer, 37, InitSharedArrayBufferClass, &js::SharedArrayBufferObject::protoClass) \ -IF_INTL(real,imaginary) (Intl, 38, InitIntlClass, CLASP(Intl)) \ -IF_BDATA(real,imaginary)(TypedObject, 39, InitTypedObjectModuleObject, OCLASP(TypedObjectModule)) \ - real(Reflect, 40, InitReflect, nullptr) \ -IF_BDATA(real,imaginary)(SIMD, 41, InitSIMDClass, OCLASP(SIMD)) \ - real(WeakSet, 42, InitWeakSetClass, OCLASP(WeakSet)) \ - real(TypedArray, 43, InitViaClassSpec, &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \ -IF_SAB(real,imaginary)(Atomics, 44, InitAtomicsClass, OCLASP(Atomics)) \ - real(SavedFrame, 45, InitViaClassSpec, &js::SavedFrame::class_) \ + real(DebuggeeWouldRun, 19, InitViaClassSpec, ERROR_CLASP(JSEXN_DEBUGGEEWOULDRUN)) \ + real(CompileError, 20, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMCOMPILEERROR)) \ + real(RuntimeError, 21, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMRUNTIMEERROR)) \ + real(Iterator, 22, InitLegacyIteratorClass,OCLASP(PropertyIterator)) \ + real(StopIteration, 23, InitStopIterationClass, OCLASP(StopIteration)) \ + real(ArrayBuffer, 24, InitViaClassSpec, OCLASP(ArrayBuffer)) \ + real(Int8Array, 25, InitViaClassSpec, TYPED_ARRAY_CLASP(Int8)) \ + real(Uint8Array, 26, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8)) \ + real(Int16Array, 27, InitViaClassSpec, TYPED_ARRAY_CLASP(Int16)) \ + real(Uint16Array, 28, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint16)) \ + real(Int32Array, 29, InitViaClassSpec, TYPED_ARRAY_CLASP(Int32)) \ + real(Uint32Array, 30, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint32)) \ + real(Float32Array, 31, InitViaClassSpec, TYPED_ARRAY_CLASP(Float32)) \ + real(Float64Array, 32, InitViaClassSpec, TYPED_ARRAY_CLASP(Float64)) \ + real(Uint8ClampedArray, 33, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8Clamped)) \ + real(Proxy, 34, InitProxyClass, js::ProxyClassPtr) \ + real(WeakMap, 35, InitWeakMapClass, OCLASP(WeakMap)) \ + real(Map, 36, InitMapClass, OCLASP(Map)) \ + real(Set, 37, InitSetClass, OCLASP(Set)) \ + real(DataView, 38, InitDataViewClass, OCLASP(DataView)) \ + real(Symbol, 39, InitSymbolClass, OCLASP(Symbol)) \ +IF_SAB(real,imaginary)(SharedArrayBuffer, 40, InitViaClassSpec, OCLASP(SharedArrayBuffer)) \ +IF_INTL(real,imaginary) (Intl, 41, InitIntlClass, CLASP(Intl)) \ +IF_BDATA(real,imaginary)(TypedObject, 42, InitTypedObjectModuleObject, OCLASP(TypedObjectModule)) \ + real(Reflect, 43, InitReflect, nullptr) \ +IF_SIMD(real,imaginary)(SIMD, 44, InitSimdClass, OCLASP(Simd)) \ + real(WeakSet, 45, InitWeakSetClass, OCLASP(WeakSet)) \ + real(TypedArray, 46, InitViaClassSpec, &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \ +IF_SAB(real,imaginary)(Atomics, 47, InitAtomicsClass, OCLASP(Atomics)) \ + real(SavedFrame, 48, InitViaClassSpec, &js::SavedFrame::class_) \ + real(WebAssembly, 49, InitWebAssemblyClass, CLASP(WebAssembly)) \ + imaginary(WasmModule, 50, dummy, dummy) \ + imaginary(WasmInstance, 51, dummy, dummy) \ + imaginary(WasmMemory, 52, dummy, dummy) \ + imaginary(WasmTable, 53, dummy, dummy) \ +IF_PROMISE(real,imaginary)(Promise, 54, InitViaClassSpec, OCLASP(Promise)) \ #define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro) Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/jspubtd.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/jspubtd.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/jspubtd.h @@ -12,12 +12,14 @@ */ #include "mozilla/Assertions.h" +#include "mozilla/EnumeratedArray.h" #include "mozilla/LinkedList.h" #include "mozilla/PodOperations.h" #include "jsprototypes.h" #include "jstypes.h" +#include "js/TraceKind.h" #include "js/TypeDecls.h" #if defined(JS_GC_ZEAL) || defined(DEBUG) @@ -26,9 +28,7 @@ namespace JS { -template -class AutoVectorRooter; -typedef AutoVectorRooter AutoIdVector; +class AutoIdVector; class CallArgs; template @@ -40,13 +40,17 @@ class JS_FRIEND_API(TransitiveCompileOptions); class JS_PUBLIC_API(CompartmentOptions); +struct RootingContext; class Value; struct Zone; -} /* namespace JS */ +namespace shadow { +struct Runtime; +} // namespace shadow + +} // namespace JS namespace js { -struct ContextFriendFields; class RootLists; } // namespace js @@ -97,7 +101,6 @@ struct JSLocaleCallbacks; struct JSObjectMap; struct JSPrincipals; -struct JSPropertyDescriptor; struct JSPropertyName; struct JSPropertySpec; struct JSRuntime; @@ -109,7 +112,6 @@ class JSFlatString; -typedef struct PRCallOnceType JSCallOnceType; typedef bool (*JSInitCallback)(void); template struct JSConstScalarSpec; @@ -117,60 +119,105 @@ typedef JSConstScalarSpec JSConstIntegerSpec; /* - * Generic trace operation that calls JS_CallTracer on each traceable thing - * stored in data. + * Generic trace operation that calls JS::TraceEdge on each traceable thing's + * location reachable from data. */ typedef void (* JSTraceDataOp)(JSTracer* trc, void* data); namespace js { - -void FinishGC(JSRuntime* rt); - namespace gc { class AutoTraceSession; class StoreBuffer; -void MarkPersistentRootedChains(JSTracer*); -void MarkPersistentRootedChainsInLists(js::RootLists&, JSTracer*); -void FinishPersistentRootedChains(js::RootLists&); } // namespace gc + +// Whether the current thread is permitted access to any part of the specified +// runtime or zone. +JS_FRIEND_API(bool) +CurrentThreadCanAccessRuntime(const JSRuntime* rt); + +#ifdef DEBUG +JS_FRIEND_API(bool) +CurrentThreadIsPerformingGC(); +#endif + } // namespace js namespace JS { +class JS_PUBLIC_API(AutoEnterCycleCollection); +class JS_PUBLIC_API(AutoAssertOnBarrier); +struct JS_PUBLIC_API(PropertyDescriptor); + typedef void (*OffThreadCompileCallback)(void* token, void* callbackData); enum class HeapState { Idle, // doing nothing with the GC heap Tracing, // tracing the GC heap without collecting, e.g. IterateCompartments() MajorCollecting, // doing a GC of the major heap - MinorCollecting // doing a GC of the minor heap (nursery) + MinorCollecting, // doing a GC of the minor heap (nursery) + CycleCollecting // in the "Unlink" phase of cycle collection }; namespace shadow { struct Runtime { - protected: - // Allow inlining of heapState checks. - friend class js::gc::AutoTraceSession; + private: JS::HeapState heapState_; + protected: + void setHeapState(JS::HeapState newState) { + MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(asRuntime())); + MOZ_ASSERT(heapState_ != newState); + heapState_ = newState; + } + + JS::HeapState heapState() const { + MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(asRuntime()) || + js::CurrentThreadIsPerformingGC()); + return heapState_; + } + + // In some cases, invoking GC barriers (incremental or otherwise) will break + // things. These barriers assert if this flag is set. + bool allowGCBarriers_; + friend class JS::AutoAssertOnBarrier; + js::gc::StoreBuffer* gcStoreBufferPtr_; + // The gray bits can become invalid if UnmarkGray overflows the stack. A + // full GC will reset this bit, since it fills in all the gray bits. + bool gcGrayBitsValid_; + public: Runtime() : heapState_(JS::HeapState::Idle) + , allowGCBarriers_(true) , gcStoreBufferPtr_(nullptr) + , gcGrayBitsValid_(false) {} - bool isHeapBusy() const { return heapState_ != JS::HeapState::Idle; } - bool isHeapMajorCollecting() const { return heapState_ == JS::HeapState::MajorCollecting; } - bool isHeapMinorCollecting() const { return heapState_ == JS::HeapState::MinorCollecting; } + bool isHeapBusy() const { return heapState() != JS::HeapState::Idle; } + bool isHeapTracing() const { return heapState() == JS::HeapState::Tracing; } + bool isHeapMajorCollecting() const { return heapState() == JS::HeapState::MajorCollecting; } + bool isHeapMinorCollecting() const { return heapState() == JS::HeapState::MinorCollecting; } bool isHeapCollecting() const { return isHeapMinorCollecting() || isHeapMajorCollecting(); } + bool isCycleCollecting() const { + return heapState() == JS::HeapState::CycleCollecting; + } + + bool allowGCBarriers() const { return allowGCBarriers_; } js::gc::StoreBuffer* gcStoreBufferPtr() { return gcStoreBufferPtr_; } + bool areGCGrayBitsValid() const { return gcGrayBitsValid_; } + void setGCGrayBitsValid(bool valid) { gcGrayBitsValid_ = valid; } + + const JSRuntime* asRuntime() const { + return reinterpret_cast(this); + } + static JS::shadow::Runtime* asShadowRuntime(JSRuntime* rt) { return reinterpret_cast(rt); } @@ -183,11 +230,28 @@ } /* namespace shadow */ +// Decorates the Unlinking phase of CycleCollection so that accidental use +// of barriered accessors results in assertions instead of leaks. +class MOZ_STACK_CLASS JS_PUBLIC_API(AutoEnterCycleCollection) +{ +#ifdef DEBUG + JSRuntime* runtime; + + public: + explicit AutoEnterCycleCollection(JSContext* cx); + ~AutoEnterCycleCollection(); +#else + public: + explicit AutoEnterCycleCollection(JSContext* cx) {} + ~AutoEnterCycleCollection() {} +#endif +}; + class JS_PUBLIC_API(AutoGCRooter) { public: AutoGCRooter(JSContext* cx, ptrdiff_t tag); - AutoGCRooter(js::ContextFriendFields* cx, ptrdiff_t tag); + AutoGCRooter(JS::RootingContext* cx, ptrdiff_t tag); ~AutoGCRooter() { MOZ_ASSERT(this == *stackTop); @@ -199,13 +263,6 @@ static void traceAll(JSTracer* trc); static void traceAllWrappers(JSTracer* trc); - /* T must be a context type */ - template - static void traceAllInContext(T* cx, JSTracer* trc) { - for (AutoGCRooter* gcr = cx->roots.autoGCRooters_; gcr; gcr = gcr->down) - gcr->trace(trc); - } - protected: AutoGCRooter * const down; @@ -242,6 +299,13 @@ void operator=(AutoGCRooter& ida) = delete; }; +// Our instantiations of Rooted and PersistentRooted require an +// instantiation of MapTypeToRootKind. +template <> +struct MapTypeToRootKind { + static const RootKind kind = RootKind::Traceable; +}; + } /* namespace JS */ namespace js { @@ -261,132 +325,98 @@ StackKindCount }; -enum ThingRootKind -{ - THING_ROOT_OBJECT, - THING_ROOT_SHAPE, - THING_ROOT_BASE_SHAPE, - THING_ROOT_OBJECT_GROUP, - THING_ROOT_STRING, - THING_ROOT_SYMBOL, - THING_ROOT_JIT_CODE, - THING_ROOT_SCRIPT, - THING_ROOT_LAZY_SCRIPT, - THING_ROOT_ID, - THING_ROOT_VALUE, - THING_ROOT_TRACEABLE, - THING_ROOT_LIMIT -}; - -template -struct RootKind; - -/* - * Specifically mark the ThingRootKind of externally visible types, so that - * JSAPI users may use JSRooted... types without having the class definition - * available. - */ -template -struct SpecificRootKind -{ - static ThingRootKind rootKind() { return Kind; } -}; - -template <> struct RootKind : SpecificRootKind {}; -template <> struct RootKind : SpecificRootKind {}; -template <> struct RootKind : SpecificRootKind {}; -template <> struct RootKind : SpecificRootKind {}; -template <> struct RootKind : SpecificRootKind {}; -template <> struct RootKind : SpecificRootKind {}; -template <> struct RootKind : SpecificRootKind {}; -template <> struct RootKind : SpecificRootKind {}; +using RootedListHeads = mozilla::EnumeratedArray*>; // Abstracts JS rooting mechanisms so they can be shared between the JSContext // and JSRuntime. class RootLists { - // Stack GC roots for stack-allocated GC heap pointers. - JS::Rooted* stackRoots_[THING_ROOT_LIMIT]; + // Stack GC roots for Rooted GC heap pointers. + RootedListHeads stackRoots_; template friend class JS::Rooted; - // Stack GC roots for stack-allocated AutoFooRooter classes. + // Stack GC roots for AutoFooRooter classes. JS::AutoGCRooter* autoGCRooters_; friend class JS::AutoGCRooter; + // Heap GC roots for PersistentRooted pointers. + mozilla::EnumeratedArray>> heapRoots_; + template friend class JS::PersistentRooted; + public: RootLists() : autoGCRooters_(nullptr) { - mozilla::PodArrayZero(stackRoots_); + for (auto& stackRootPtr : stackRoots_) + stackRootPtr = nullptr; } - template - inline JS::Rooted* gcRooters() { - js::ThingRootKind kind = RootKind::rootKind(); - return reinterpret_cast*>(stackRoots_[kind]); + ~RootLists() { + // The semantics of PersistentRooted containing pointers and tagged + // pointers are somewhat different from those of PersistentRooted + // containing a structure with a trace method. PersistentRooted + // containing pointers are allowed to outlive the owning RootLists, + // whereas those containing a traceable structure are not. + // + // The purpose of this feature is to support lazy initialization of + // global references for the several places in Gecko that do not have + // access to a tighter context, but that still need to refer to GC + // pointers. For such pointers, FinishPersistentRootedChains ensures + // that the contained references are nulled out when the owning + // RootLists dies to prevent UAF errors. + // + // However, for RootKind::Traceable, we do not know the concrete type + // of the held thing, so we simply cannot do this without accruing + // extra overhead and complexity for all users for a case that is + // unlikely to ever be used in practice. For this reason, the following + // assertion disallows usage of PersistentRooted that + // outlives the RootLists. + MOZ_ASSERT(heapRoots_[JS::RootKind::Traceable].isEmpty()); } + void traceStackRoots(JSTracer* trc); void checkNoGCRooters(); - /* Allow inlining of PersistentRooted constructors and destructors. */ - private: - template friend class JS::PersistentRooted; - friend void js::gc::MarkPersistentRootedChains(JSTracer*); - friend void js::gc::MarkPersistentRootedChainsInLists(RootLists&, JSTracer*); - friend void js::gc::FinishPersistentRootedChains(RootLists&); - - mozilla::LinkedList> heapRoots_[THING_ROOT_LIMIT]; - - /* Specializations of this return references to the appropriate list. */ - template - inline mozilla::LinkedList>& getPersistentRootedList(); -}; - -template<> -inline mozilla::LinkedList& -RootLists::getPersistentRootedList() { - return reinterpret_cast>&>( - heapRoots_[THING_ROOT_OBJECT]); -} + void tracePersistentRoots(JSTracer* trc); + void finishPersistentRoots(); +}; -template<> -inline mozilla::LinkedList& -RootLists::getPersistentRootedList() { - return reinterpret_cast>&>( - heapRoots_[THING_ROOT_OBJECT]); -} +} // namespace js -template<> -inline mozilla::LinkedList& -RootLists::getPersistentRootedList() { - return reinterpret_cast>&>( - heapRoots_[THING_ROOT_ID]); -} +namespace JS { -template<> -inline mozilla::LinkedList& -RootLists::getPersistentRootedList() { - return reinterpret_cast>&>( - heapRoots_[THING_ROOT_SCRIPT]); -} +/* + * JS::RootingContext is a base class of ContextFriendFields and JSContext. + * This class can be used to let code construct a Rooted<> or PersistentRooted<> + * instance, without giving it full access to the JSContext. + */ +struct RootingContext +{ + js::RootLists roots; -template<> -inline mozilla::LinkedList& -RootLists::getPersistentRootedList() { - return reinterpret_cast>&>( - heapRoots_[THING_ROOT_STRING]); -} +#ifdef DEBUG + // Whether the derived class is a JSContext or an ExclusiveContext. + bool isJSContext; +#endif -template<> -inline mozilla::LinkedList& -RootLists::getPersistentRootedList() { - return reinterpret_cast>&>( - heapRoots_[THING_ROOT_VALUE]); -} + explicit RootingContext(bool isJSContextArg) +#ifdef DEBUG + : isJSContext(isJSContextArg) +#endif + {} -struct ContextFriendFields + static RootingContext* get(JSContext* cx) { + return reinterpret_cast(cx); + } +}; + +} // namespace JS + +namespace js { + +struct ContextFriendFields : public JS::RootingContext { protected: - JSRuntime* const runtime_; - /* The current compartment. */ JSCompartment* compartment_; @@ -394,12 +424,10 @@ JS::Zone* zone_; public: - /* Rooting structures. */ - RootLists roots; + /* Limit pointer for checking native stack consumption. */ + uintptr_t nativeStackLimit[js::StackKindCount]; - explicit ContextFriendFields(JSRuntime* rt) - : runtime_(rt), compartment_(nullptr), zone_(nullptr) - {} + explicit ContextFriendFields(bool isJSContext); static const ContextFriendFields* get(const JSContext* cx) { return reinterpret_cast(cx); @@ -409,7 +437,6 @@ return reinterpret_cast(cx); } - friend JSRuntime* GetRuntime(const JSContext* cx); friend JSCompartment* GetContextCompartment(const JSContext* cx); friend JS::Zone* GetContextZone(const JSContext* cx); template friend class JS::Rooted; @@ -425,12 +452,6 @@ * usable without resorting to jsfriendapi.h, and when JSContext is an * incomplete type. */ -inline JSRuntime* -GetRuntime(const JSContext* cx) -{ - return ContextFriendFields::get(cx)->runtime_; -} - inline JSCompartment* GetContextCompartment(const JSContext* cx) { @@ -443,57 +464,13 @@ return ContextFriendFields::get(cx)->zone_; } -class PerThreadData; - -struct PerThreadDataFriendFields -{ - private: - // Note: this type only exists to permit us to derive the offset of - // the perThread data within the real JSRuntime* type in a portable - // way. - struct RuntimeDummy : JS::shadow::Runtime - { - struct PerThreadDummy { - void* field1; - uintptr_t field2; -#ifdef JS_DEBUG - uint64_t field3; -#endif - } mainThread; - }; - - public: - /* Rooting structures. */ - RootLists roots; - - PerThreadDataFriendFields(); - - /* Limit pointer for checking native stack consumption. */ - uintptr_t nativeStackLimit[js::StackKindCount]; - - static const size_t RuntimeMainThreadOffset = offsetof(RuntimeDummy, mainThread); - - static inline PerThreadDataFriendFields* get(js::PerThreadData* pt) { - return reinterpret_cast(pt); - } - - static inline PerThreadDataFriendFields* getMainThread(JSRuntime* rt) { - // mainThread must always appear directly after |JS::shadow::Runtime|. - // Tested by a JS_STATIC_ASSERT in |jsfriendapi.cpp| - return reinterpret_cast( - reinterpret_cast(rt) + RuntimeMainThreadOffset); - } +} /* namespace js */ - static inline const PerThreadDataFriendFields* getMainThread(const JSRuntime* rt) { - // mainThread must always appear directly after |JS::shadow::Runtime|. - // Tested by a JS_STATIC_ASSERT in |jsfriendapi.cpp| - return reinterpret_cast( - reinterpret_cast(rt) + RuntimeMainThreadOffset); - } +MOZ_BEGIN_EXTERN_C - template friend class JS::Rooted; -}; +// Defined in NSPR prio.h. +typedef struct PRFileDesc PRFileDesc; -} /* namespace js */ +MOZ_END_EXTERN_C #endif /* jspubtd_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/jstypes.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/jstypes.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/jstypes.h @@ -70,18 +70,16 @@ #if defined(STATIC_JS_API) # define JS_PUBLIC_API(t) t # define JS_PUBLIC_DATA(t) t +# define JS_FRIEND_API(t) t +# define JS_FRIEND_DATA(t) t #elif defined(EXPORT_JS_API) || defined(STATIC_EXPORTABLE_JS_API) # define JS_PUBLIC_API(t) MOZ_EXPORT t # define JS_PUBLIC_DATA(t) MOZ_EXPORT t -#else -# define JS_PUBLIC_API(t) MOZ_IMPORT_API t -# define JS_PUBLIC_DATA(t) MOZ_IMPORT_DATA t -#endif - -#if defined(STATIC_JS_API) || defined(EXPORT_JS_API) || defined(STATIC_EXPORTABLE_JS_API) # define JS_FRIEND_API(t) MOZ_EXPORT t # define JS_FRIEND_DATA(t) MOZ_EXPORT t #else +# define JS_PUBLIC_API(t) MOZ_IMPORT_API t +# define JS_PUBLIC_DATA(t) MOZ_IMPORT_DATA t # define JS_FRIEND_API(t) MOZ_IMPORT_API t # define JS_FRIEND_DATA(t) MOZ_IMPORT_DATA t #endif @@ -95,6 +93,14 @@ #define JS_NO_FASTCALL #endif +// gcc is buggy and warns on our attempts to JS_PUBLIC_API our +// forward-declarations or explicit template instantiations. See +// . Add a way to detect +// that so we can locally disable that warning. +#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 6 || (__GNUC__ == 6 && __GNUC_MINOR__ <= 4)) +#define JS_BROKEN_GCC_ATTRIBUTE_WARNING +#endif + /*********************************************************************** ** MACROS: JS_BEGIN_MACRO ** JS_END_MACRO Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/jsversion.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/jsversion.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/jsversion.h @@ -22,7 +22,7 @@ #define JS_HAS_GENERATORS 1 /* (no longer used) */ #define JS_HAS_BLOCK_SCOPE 1 /* (no longer used) */ #define JS_HAS_DESTRUCTURING 2 /* (no longer used) */ -#define JS_HAS_GENERATOR_EXPRS 1 /* has (expr for (lhs in iterable)) */ +#define JS_HAS_GENERATOR_EXPRS 1 /* (no longer used) */ #define JS_HAS_EXPR_CLOSURES 1 /* has function (formals) listexpr */ /* (no longer used) */ @@ -37,11 +37,4 @@ */ #define JS_OLD_GETTER_SETTER_METHODS 1 -#ifdef NIGHTLY_BUILD - -/* Support for ES7 Exponentiation proposal. */ -#define JS_HAS_EXPONENTIATION 1 - -#endif // NIGHTLY_BUILD - #endif /* jsversion_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/jswrapper.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/jswrapper.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/jswrapper.h @@ -44,19 +44,88 @@ /* * A wrapper is a proxy with a target object to which it generally forwards - * operations, but may restrict access to certain operations or instrument the - * methods in various ways. A wrapper is distinct from a Direct Proxy Handler - * in the sense that it can be "unwrapped" in C++, exposing the underlying - * object (Direct Proxy Handlers have an underlying target object, but don't - * expect to expose this object via any kind of unwrapping operation). Callers - * should be careful to avoid unwrapping security wrappers in the wrong + * operations, but may restrict access to certain operations or augment those + * operations in various ways. + * + * A wrapper can be "unwrapped" in C++, exposing the underlying object. + * Callers should be careful to avoid unwrapping security wrappers in the wrong * context. + * + * Important: If you add a method implementation here, you probably also need + * to add an override in CrossCompartmentWrapper. If you don't, you risk + * compartment mismatches. See bug 945826 comment 0. */ -class JS_FRIEND_API(Wrapper) : public DirectProxyHandler +class JS_FRIEND_API(Wrapper) : public BaseProxyHandler { unsigned mFlags; public: + explicit constexpr Wrapper(unsigned aFlags, bool aHasPrototype = false, + bool aHasSecurityPolicy = false) + : BaseProxyHandler(&family, aHasPrototype, aHasSecurityPolicy), + mFlags(aFlags) + { } + + virtual bool finalizeInBackground(const Value& priv) const override; + + /* Standard internal methods. */ + virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, + MutableHandle desc) const override; + virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, + Handle desc, + ObjectOpResult& result) const override; + virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy, + AutoIdVector& props) const override; + virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id, + ObjectOpResult& result) const override; + virtual bool enumerate(JSContext* cx, HandleObject proxy, + MutableHandleObject objp) const override; + virtual bool getPrototype(JSContext* cx, HandleObject proxy, + MutableHandleObject protop) const override; + virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, + ObjectOpResult& result) const override; + virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const override; + virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, + bool* succeeded) const override; + virtual bool preventExtensions(JSContext* cx, HandleObject proxy, + ObjectOpResult& result) const override; + virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override; + virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, + bool* bp) const override; + virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, + HandleId id, MutableHandleValue vp) const override; + virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, + HandleValue receiver, ObjectOpResult& result) const override; + virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const override; + virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override; + + /* SpiderMonkey extensions. */ + virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, + MutableHandle desc) const override; + virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, + bool* bp) const override; + virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, + AutoIdVector& props) const override; + virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, + const CallArgs& args) const override; + virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, + bool* bp) const override; + virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override; + virtual bool isArray(JSContext* cx, HandleObject proxy, + JS::IsArrayAnswer* answer) const override; + virtual const char* className(JSContext* cx, HandleObject proxy) const override; + virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, + unsigned indent) const override; + virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, + RegExpGuard* g) const override; + virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, + MutableHandleValue vp) const override; + virtual bool isCallable(JSObject* obj) const override; + virtual bool isConstructor(JSObject* obj) const override; + virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const override; + + public: using BaseProxyHandler::Action; enum Flags { @@ -77,15 +146,6 @@ return mFlags; } - explicit MOZ_CONSTEXPR Wrapper(unsigned aFlags, bool aHasPrototype = false, - bool aHasSecurityPolicy = false) - : DirectProxyHandler(&family, aHasPrototype, aHasSecurityPolicy), - mFlags(aFlags) - { } - - virtual bool finalizeInBackground(Value priv) const override; - virtual bool isConstructor(JSObject* obj) const override; - static const char family; static const Wrapper singleton; static const Wrapper singletonWithPrototype; @@ -103,16 +163,16 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper { public: - explicit MOZ_CONSTEXPR CrossCompartmentWrapper(unsigned aFlags, bool aHasPrototype = false, + explicit constexpr CrossCompartmentWrapper(unsigned aFlags, bool aHasPrototype = false, bool aHasSecurityPolicy = false) : Wrapper(CROSS_COMPARTMENT | aFlags, aHasPrototype, aHasSecurityPolicy) { } /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const override; virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper, AutoIdVector& props) const override; @@ -124,6 +184,8 @@ virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result) const override; + virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const override; virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const override; virtual bool preventExtensions(JSContext* cx, HandleObject wrapper, @@ -139,7 +201,7 @@ /* SpiderMonkey extensions. */ virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override; virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper, AutoIdVector& props) const override; @@ -153,6 +215,9 @@ virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const override; virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override; + // Allocate CrossCompartmentWrappers in the nursery. + virtual bool canNurseryAllocate() const override { return true; } + static const CrossCompartmentWrapper singleton; static const CrossCompartmentWrapper singletonWithPrototype; }; @@ -160,14 +225,14 @@ class JS_FRIEND_API(OpaqueCrossCompartmentWrapper) : public CrossCompartmentWrapper { public: - explicit MOZ_CONSTEXPR OpaqueCrossCompartmentWrapper() : CrossCompartmentWrapper(0) + explicit constexpr OpaqueCrossCompartmentWrapper() : CrossCompartmentWrapper(0) { } /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const override; virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper, AutoIdVector& props) const override; @@ -179,6 +244,8 @@ MutableHandleObject protop) const override; virtual bool setPrototype(JSContext* cx, HandleObject wrapper, HandleObject proto, ObjectOpResult& result) const override; + virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject wrapper, bool* isOrdinary, + MutableHandleObject protop) const override; virtual bool setImmutablePrototype(JSContext* cx, HandleObject wrapper, bool* succeeded) const override; virtual bool preventExtensions(JSContext* cx, HandleObject wrapper, @@ -195,13 +262,12 @@ /* SpiderMonkey extensions. */ virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override; virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper, AutoIdVector& props) const override; - virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, - ESClassValue* classValue) const override; + virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override; virtual bool isArray(JSContext* cx, HandleObject obj, JS::IsArrayAnswer* answer) const override; virtual const char* className(JSContext* cx, HandleObject wrapper) const override; @@ -223,7 +289,7 @@ class JS_FRIEND_API(SecurityWrapper) : public Base { public: - explicit MOZ_CONSTEXPR SecurityWrapper(unsigned flags, bool hasPrototype = false) + explicit constexpr SecurityWrapper(unsigned flags, bool hasPrototype = false) : Base(flags, hasPrototype, /* hasSecurityPolicy = */ true) { } @@ -231,7 +297,7 @@ bool* bp) const override; virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const override; virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override; virtual bool preventExtensions(JSContext* cx, HandleObject wrapper, @@ -242,8 +308,7 @@ virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, const CallArgs& args) const override; - virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, - ESClassValue* classValue) const override; + virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper, ESClass* cls) const override; virtual bool isArray(JSContext* cx, HandleObject wrapper, JS::IsArrayAnswer* answer) const override; virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const override; virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const override; @@ -263,7 +328,6 @@ typedef SecurityWrapper Restrictive; }; -typedef SecurityWrapper SameCompartmentSecurityWrapper; typedef SecurityWrapper CrossCompartmentSecurityWrapper; extern JSObject* @@ -297,10 +361,10 @@ JS_FRIEND_API(bool) IsCrossCompartmentWrapper(JSObject* obj); -void +JS_FRIEND_API(void) NukeCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper); -bool +void RemapWrapper(JSContext* cx, JSObject* wobj, JSObject* newTarget); JS_FRIEND_API(bool) Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Alignment.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Alignment.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Alignment.h @@ -120,6 +120,13 @@ const void* addr() const { return u.mBytes; } void* addr() { return u.mBytes; } + + AlignedStorage() = default; + + // AlignedStorage is non-copyable: the default copy constructor violates + // strict aliasing rules, per bug 1269319. + AlignedStorage(const AlignedStorage&) = delete; + void operator=(const AlignedStorage&) = delete; }; template @@ -133,6 +140,13 @@ const T* addr() const { return reinterpret_cast(u.mBytes); } T* addr() { return static_cast(static_cast(u.mBytes)); } + + AlignedStorage2() = default; + + // AlignedStorage2 is non-copyable: the default copy constructor violates + // strict aliasing rules, per bug 1269319. + AlignedStorage2(const AlignedStorage2&) = delete; + void operator=(const AlignedStorage2&) = delete; }; } /* namespace mozilla */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/AllocPolicy.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/AllocPolicy.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/AllocPolicy.h @@ -12,6 +12,7 @@ #ifndef mozilla_AllocPolicy_h #define mozilla_AllocPolicy_h +#include "mozilla/Attributes.h" #include "mozilla/TemplateLib.h" #include @@ -121,7 +122,7 @@ { } - bool checkSimulatedOOM() const + MOZ_MUST_USE bool checkSimulatedOOM() const { return true; } Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/AlreadyAddRefed.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/AlreadyAddRefed.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/AlreadyAddRefed.h @@ -29,7 +29,7 @@ * because of the sheer number of usages of already_AddRefed. */ template -struct MOZ_MUST_USE MOZ_NON_AUTOABLE already_AddRefed +struct MOZ_MUST_USE_TYPE MOZ_NON_AUTOABLE already_AddRefed { /* * We want to allow returning nullptr from functions returning @@ -111,7 +111,7 @@ aUnused << mutableAlreadyAddRefed->take(); } - MOZ_WARN_UNUSED_RESULT T* take() + MOZ_MUST_USE T* take() { T* rawPtr = mRawPtr; mRawPtr = nullptr; Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Array.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Array.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Array.h @@ -11,6 +11,7 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" +#include "mozilla/Move.h" #include "mozilla/ReverseIterator.h" #include @@ -23,6 +24,16 @@ T mArr[Length]; public: + Array() {} + + template + MOZ_IMPLICIT Array(Args&&... aArgs) + : mArr{mozilla::Forward(aArgs)...} + { + static_assert(sizeof...(aArgs) == Length, + "The number of arguments should be equal to the template parameter Length"); + } + T& operator[](size_t aIndex) { MOZ_ASSERT(aIndex < Length); Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ArrayUtils.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ArrayUtils.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ArrayUtils.h @@ -52,21 +52,21 @@ * Beware of the implicit trailing '\0' when using this with string constants. */ template -MOZ_CONSTEXPR size_t +constexpr size_t ArrayLength(T (&aArr)[N]) { return N; } template -MOZ_CONSTEXPR size_t +constexpr size_t ArrayLength(const Array& aArr) { return N; } template -MOZ_CONSTEXPR size_t +constexpr size_t ArrayLength(const EnumeratedArray& aArr) { return size_t(N); @@ -78,21 +78,21 @@ * Beware of the implicit trailing '\0' when using this with string constants. */ template -MOZ_CONSTEXPR T* +constexpr T* ArrayEnd(T (&aArr)[N]) { return aArr + ArrayLength(aArr); } template -MOZ_CONSTEXPR T* +constexpr T* ArrayEnd(Array& aArr) { return &aArr[0] + ArrayLength(aArr); } template -MOZ_CONSTEXPR const T* +constexpr const T* ArrayEnd(const Array& aArr) { return &aArr[0] + ArrayLength(aArr); Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Assertions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Assertions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Assertions.h @@ -17,23 +17,29 @@ #include "mozilla/Compiler.h" #include "mozilla/Likely.h" #include "mozilla/MacroArgs.h" +#include "mozilla/StaticAnalysisFunctions.h" +#include "mozilla/Types.h" #ifdef MOZ_DUMP_ASSERTION_STACK #include "nsTraceRefcnt.h" #endif -#if defined(MOZ_CRASHREPORTER) && defined(MOZILLA_INTERNAL_API) && \ - !defined(MOZILLA_EXTERNAL_LINKAGE) && defined(__cplusplus) -namespace CrashReporter { -// This declaration is present here as well as in nsExceptionHandler.h -// nsExceptionHandler.h is not directly included in this file as it includes -// windows.h, which can cause problems when it is imported into some files due -// to the number of macros defined. -// XXX If you change this definition - also change the definition in -// nsExceptionHandler.h -void AnnotateMozCrashReason(const char* aReason); -} // namespace CrashReporter +#if defined(MOZ_HAS_MOZGLUE) || defined(MOZILLA_INTERNAL_API) +/* + * The crash reason set by MOZ_CRASH_ANNOTATE is consumed by the crash reporter + * if present. It is declared here (and defined in Assertions.cpp) to make it + * available to all code, even libraries that don't link with the crash reporter + * directly. + */ +MOZ_BEGIN_EXTERN_C +extern MFBT_DATA const char* gMozCrashReason; +MOZ_END_EXTERN_C -# define MOZ_CRASH_ANNOTATE(...) CrashReporter::AnnotateMozCrashReason("" __VA_ARGS__) +static inline void +AnnotateMozCrashReason(const char* reason) +{ + gMozCrashReason = reason; +} +# define MOZ_CRASH_ANNOTATE(...) AnnotateMozCrashReason(__VA_ARGS__) #else # define MOZ_CRASH_ANNOTATE(...) do { /* nothing */ } while (0) #endif @@ -158,7 +164,7 @@ aStr, aFilename, aLine); #else fprintf(stderr, "Assertion failure: %s, at %s:%d\n", aStr, aFilename, aLine); -#if defined (MOZ_DUMP_ASSERTION_STACK) && !defined(MOZILLA_XPCOMRT_API) +#if defined (MOZ_DUMP_ASSERTION_STACK) nsTraceRefcnt::WalkTheStack(stderr); #endif fflush(stderr); @@ -174,7 +180,7 @@ "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine); #else fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine); -#if defined(MOZ_DUMP_ASSERTION_STACK) && !defined(MOZILLA_XPCOMRT_API) +#if defined(MOZ_DUMP_ASSERTION_STACK) nsTraceRefcnt::WalkTheStack(stderr); #endif fflush(stderr); @@ -212,33 +218,33 @@ __declspec(noreturn) __inline void MOZ_NoReturn() {} # ifdef __cplusplus -# define MOZ_REALLY_CRASH() \ +# define MOZ_REALLY_CRASH(line) \ do { \ ::__debugbreak(); \ - *((volatile int*) NULL) = __LINE__; \ + *((volatile int*) NULL) = line; \ ::TerminateProcess(::GetCurrentProcess(), 3); \ ::MOZ_NoReturn(); \ } while (0) # else -# define MOZ_REALLY_CRASH() \ +# define MOZ_REALLY_CRASH(line) \ do { \ __debugbreak(); \ - *((volatile int*) NULL) = __LINE__; \ + *((volatile int*) NULL) = line; \ TerminateProcess(GetCurrentProcess(), 3); \ MOZ_NoReturn(); \ } while (0) # endif #else # ifdef __cplusplus -# define MOZ_REALLY_CRASH() \ +# define MOZ_REALLY_CRASH(line) \ do { \ - *((volatile int*) NULL) = __LINE__; \ + *((volatile int*) NULL) = line; \ ::abort(); \ } while (0) # else -# define MOZ_REALLY_CRASH() \ +# define MOZ_REALLY_CRASH(line) \ do { \ - *((volatile int*) NULL) = __LINE__; \ + *((volatile int*) NULL) = line; \ abort(); \ } while (0) # endif @@ -269,17 +275,69 @@ # define MOZ_CRASH(...) \ do { \ MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \ - MOZ_REALLY_CRASH(); \ + MOZ_REALLY_CRASH(__LINE__); \ } while (0) #else # define MOZ_CRASH(...) \ do { \ MOZ_ReportCrash("" __VA_ARGS__, __FILE__, __LINE__); \ MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \ - MOZ_REALLY_CRASH(); \ + MOZ_REALLY_CRASH(__LINE__); \ } while (0) #endif +/* + * MOZ_CRASH_UNSAFE_OOL(explanation-string) can be used if the explanation + * string cannot be a string literal (but no other processing needs to be done + * on it). A regular MOZ_CRASH() is preferred wherever possible, as passing + * arbitrary strings from a potentially compromised process is not without risk. + * If the string being passed is the result of a printf-style function, + * consider using MOZ_CRASH_UNSAFE_PRINTF instead. + */ +#ifndef DEBUG +MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void +MOZ_CrashOOL(int aLine, const char* aReason); +# define MOZ_CRASH_UNSAFE_OOL(reason) MOZ_CrashOOL(__LINE__, reason) +#else +MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void +MOZ_CrashOOL(const char* aFilename, int aLine, const char* aReason); +# define MOZ_CRASH_UNSAFE_OOL(reason) MOZ_CrashOOL(__FILE__, __LINE__, reason) +#endif + +static const size_t sPrintfMaxArgs = 4; +static const size_t sPrintfCrashReasonSize = 1024; + +#ifndef DEBUG +MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE MOZ_FORMAT_PRINTF(2, 3) void +MOZ_CrashPrintf(int aLine, const char* aFormat, ...); +# define MOZ_CALL_CRASH_PRINTF(format, ...) \ + MOZ_CrashPrintf(__LINE__, format, __VA_ARGS__) +#else +MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE MOZ_FORMAT_PRINTF(3, 4) void +MOZ_CrashPrintf(const char* aFilename, int aLine, const char* aFormat, ...); +# define MOZ_CALL_CRASH_PRINTF(format, ...) \ + MOZ_CrashPrintf(__FILE__, __LINE__, format, __VA_ARGS__) +#endif + +/* + * MOZ_CRASH_UNSAFE_PRINTF(format, arg1 [, args]) can be used when more + * information is desired than a string literal can supply. The caller provides + * a printf-style format string, which must be a string literal and between + * 1 and 4 additional arguments. A regular MOZ_CRASH() is preferred wherever + * possible, as passing arbitrary strings to printf from a potentially + * compromised process is not without risk. + */ +#define MOZ_CRASH_UNSAFE_PRINTF(format, ...) \ + do { \ + MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \ + static_assert( \ + MOZ_PASTE_PREFIX_AND_ARG_COUNT(, __VA_ARGS__) <= sPrintfMaxArgs, \ + "Only up to 4 additional arguments are allowed!"); \ + static_assert(sizeof(format) <= sPrintfCrashReasonSize, \ + "The supplied format string is too long!"); \ + MOZ_CALL_CRASH_PRINTF("" format, __VA_ARGS__); \ + } while (0) + #ifdef __cplusplus } /* extern "C" */ #endif @@ -368,20 +426,20 @@ #define MOZ_ASSERT_HELPER1(expr) \ do { \ MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ - if (MOZ_UNLIKELY(!(expr))) { \ + if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \ MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ")"); \ - MOZ_REALLY_CRASH(); \ + MOZ_REALLY_CRASH(__LINE__); \ } \ } while (0) /* Now the two-argument form. */ #define MOZ_ASSERT_HELPER2(expr, explain) \ do { \ MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ - if (MOZ_UNLIKELY(!(expr))) { \ + if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \ MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ") (" explain ")"); \ - MOZ_REALLY_CRASH(); \ + MOZ_REALLY_CRASH(__LINE__); \ } \ } while (0) @@ -397,7 +455,7 @@ # define MOZ_ASSERT(...) do { } while (0) #endif /* DEBUG */ -#ifdef RELEASE_BUILD +#ifdef RELEASE_OR_BETA # define MOZ_DIAGNOSTIC_ASSERT MOZ_ASSERT #else # define MOZ_DIAGNOSTIC_ASSERT MOZ_RELEASE_ASSERT @@ -496,6 +554,45 @@ MOZ_ASSUME_UNREACHABLE_MARKER(); \ } while (0) +/** + * MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about + * switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in + * debug builds, but intentionally fall through in release builds to handle + * unexpected values. + * + * Why do we need MOZ_FALLTHROUGH_ASSERT in addition to MOZ_FALLTHROUGH? In + * release builds, the MOZ_ASSERT(false) will expand to `do { } while (0)`, + * requiring a MOZ_FALLTHROUGH annotation to suppress a -Wimplicit-fallthrough + * warning. In debug builds, the MOZ_ASSERT(false) will expand to something like + * `if (true) { MOZ_CRASH(); }` and the MOZ_FALLTHROUGH annotation will cause + * a -Wunreachable-code warning. The MOZ_FALLTHROUGH_ASSERT macro breaks this + * warning stalemate. + * + * // Example before MOZ_FALLTHROUGH_ASSERT: + * switch (foo) { + * default: + * // This case wants to assert in debug builds, fall through in release. + * MOZ_ASSERT(false); // -Wimplicit-fallthrough warning in release builds! + * MOZ_FALLTHROUGH; // but -Wunreachable-code warning in debug builds! + * case 5: + * return 5; + * } + * + * // Example with MOZ_FALLTHROUGH_ASSERT: + * switch (foo) { + * default: + * // This case asserts in debug builds, falls through in release. + * MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!"); + * case 5: + * return 5; + * } + */ +#ifdef DEBUG +# define MOZ_FALLTHROUGH_ASSERT(reason) MOZ_CRASH("MOZ_FALLTHROUGH_ASSERT: " reason) +#else +# define MOZ_FALLTHROUGH_ASSERT(...) MOZ_FALLTHROUGH +#endif + /* * MOZ_ALWAYS_TRUE(expr) and MOZ_ALWAYS_FALSE(expr) always evaluate the provided * expression, in debug builds and in release builds both. Then, in debug @@ -503,21 +600,35 @@ * using MOZ_ASSERT. */ #ifdef DEBUG -# define MOZ_ALWAYS_TRUE(expr) MOZ_ASSERT((expr)) -# define MOZ_ALWAYS_FALSE(expr) MOZ_ASSERT(!(expr)) +# define MOZ_ALWAYS_TRUE(expr) \ + do { \ + if ((expr)) { \ + /* Do nothing. */ \ + } else { \ + MOZ_ASSERT(false, #expr); \ + } \ + } while (0) +# define MOZ_ALWAYS_FALSE(expr) \ + do { \ + if ((expr)) { \ + MOZ_ASSERT(false, #expr); \ + } else { \ + /* Do nothing. */ \ + } \ + } while (0) #else # define MOZ_ALWAYS_TRUE(expr) \ - do { \ - if ( ( expr ) ) { \ - /* Silence MOZ_WARN_UNUSED_RESULT. */ \ - } \ - } while (0) + do { \ + if ((expr)) { \ + /* Silence MOZ_MUST_USE. */ \ + } \ + } while (0) # define MOZ_ALWAYS_FALSE(expr) \ - do { \ - if ( ( expr ) ) { \ - /* Silence MOZ_WARN_UNUSED_RESULT. */ \ - } \ - } while (0) + do { \ + if ((expr)) { \ + /* Silence MOZ_MUST_USE. */ \ + } \ + } while (0) #endif #undef MOZ_DUMP_ASSERTION_STACK Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Atomics.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Atomics.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Atomics.h @@ -323,7 +323,7 @@ template struct ToStorageTypeArgument { - static T convert (T aT) { return aT; } + static constexpr T convert (T aT) { return aT; } }; } // namespace detail @@ -514,13 +514,13 @@ { typedef typename AtomicStorageType::Type ResultType; - static ResultType convert (T aT) { return ResultType(aT); } + static constexpr ResultType convert (T aT) { return ResultType(aT); } }; template struct ToStorageTypeArgument { - static T convert (T aT) { return aT; } + static constexpr T convert (T aT) { return aT; } }; } // namespace detail @@ -546,8 +546,8 @@ ValueType mValue; public: - MOZ_CONSTEXPR AtomicBase() : mValue() {} - explicit MOZ_CONSTEXPR AtomicBase(T aInit) + constexpr AtomicBase() : mValue() {} + explicit constexpr AtomicBase(T aInit) : mValue(ToStorageTypeArgument::convert(aInit)) {} @@ -598,8 +598,8 @@ typedef typename detail::AtomicBase Base; public: - MOZ_CONSTEXPR AtomicBaseIncDec() : Base() {} - explicit MOZ_CONSTEXPR AtomicBaseIncDec(T aInit) : Base(aInit) {} + constexpr AtomicBaseIncDec() : Base() {} + explicit constexpr AtomicBaseIncDec(T aInit) : Base(aInit) {} using Base::operator=; @@ -654,8 +654,8 @@ typedef typename detail::AtomicBaseIncDec Base; public: - MOZ_CONSTEXPR Atomic() : Base() {} - explicit MOZ_CONSTEXPR Atomic(T aInit) : Base(aInit) {} + constexpr Atomic() : Base() {} + explicit constexpr Atomic(T aInit) : Base(aInit) {} using Base::operator=; @@ -702,8 +702,8 @@ typedef typename detail::AtomicBaseIncDec Base; public: - MOZ_CONSTEXPR Atomic() : Base() {} - explicit MOZ_CONSTEXPR Atomic(T* aInit) : Base(aInit) {} + constexpr Atomic() : Base() {} + explicit constexpr Atomic(T* aInit) : Base(aInit) {} using Base::operator=; @@ -733,8 +733,8 @@ typedef typename detail::AtomicBase Base; public: - MOZ_CONSTEXPR Atomic() : Base() {} - explicit MOZ_CONSTEXPR Atomic(T aInit) : Base(aInit) {} + constexpr Atomic() : Base() {} + explicit constexpr Atomic(T aInit) : Base(aInit) {} operator T() const { return T(Base::Intrinsics::load(Base::mValue)); } @@ -767,8 +767,8 @@ typedef typename detail::AtomicBase Base; public: - MOZ_CONSTEXPR Atomic() : Base() {} - explicit MOZ_CONSTEXPR Atomic(bool aInit) : Base(aInit) {} + constexpr Atomic() : Base() {} + explicit constexpr Atomic(bool aInit) : Base(aInit) {} // We provide boolean wrappers for the underlying AtomicBase methods. MOZ_IMPLICIT operator bool() const Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Attributes.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Attributes.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Attributes.h @@ -45,27 +45,9 @@ * standardly, by checking whether __cplusplus has a C++11 or greater value. * Current versions of g++ do not correctly set __cplusplus, so we check both * for forward compatibility. - * - * Even though some versions of MSVC support explicit conversion operators, we - * don't indicate support for them here, due to - * http://stackoverflow.com/questions/20498142/visual-studio-2013-explicit-keyword-bug */ # define MOZ_HAVE_NEVER_INLINE __declspec(noinline) # define MOZ_HAVE_NORETURN __declspec(noreturn) -# if _MSC_VER >= 1900 -# define MOZ_HAVE_CXX11_CONSTEXPR -# define MOZ_HAVE_CXX11_CONSTEXPR_IN_TEMPLATES -# define MOZ_HAVE_EXPLICIT_CONVERSION -# endif -# ifdef __clang__ - /* clang-cl probably supports constexpr and explicit conversions. */ -# if __has_extension(cxx_constexpr) -# define MOZ_HAVE_CXX11_CONSTEXPR -# endif -# if __has_extension(cxx_explicit_conversions) -# define MOZ_HAVE_EXPLICIT_CONVERSION -# endif -# endif #elif defined(__clang__) /* * Per Clang documentation, "Note that marketing version numbers should not @@ -75,12 +57,6 @@ # ifndef __has_extension # define __has_extension __has_feature /* compatibility, for older versions of clang */ # endif -# if __has_extension(cxx_constexpr) -# define MOZ_HAVE_CXX11_CONSTEXPR -# endif -# if __has_extension(cxx_explicit_conversions) -# define MOZ_HAVE_EXPLICIT_CONVERSION -# endif # if __has_attribute(noinline) # define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) # endif @@ -88,13 +64,6 @@ # define MOZ_HAVE_NORETURN __attribute__((noreturn)) # endif #elif defined(__GNUC__) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L -# define MOZ_HAVE_CXX11_CONSTEXPR -# if MOZ_GCC_VERSION_AT_LEAST(4, 8, 0) -# define MOZ_HAVE_CXX11_CONSTEXPR_IN_TEMPLATES -# endif -# define MOZ_HAVE_EXPLICIT_CONVERSION -# endif # define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) # define MOZ_HAVE_NORETURN __attribute__((noreturn)) #endif @@ -110,55 +79,6 @@ #endif /* - * The MOZ_CONSTEXPR specifier declares that a C++11 compiler can evaluate a - * function at compile time. A constexpr function cannot examine any values - * except its arguments and can have no side effects except its return value. - * The MOZ_CONSTEXPR_VAR specifier tells a C++11 compiler that a variable's - * value may be computed at compile time. It should be prefered to just - * marking variables as MOZ_CONSTEXPR because if the compiler does not support - * constexpr it will fall back to making the variable const, and some compilers - * do not accept variables being marked both const and constexpr. - */ -#ifdef MOZ_HAVE_CXX11_CONSTEXPR -# define MOZ_CONSTEXPR constexpr -# define MOZ_CONSTEXPR_VAR constexpr -# ifdef MOZ_HAVE_CXX11_CONSTEXPR_IN_TEMPLATES -# define MOZ_CONSTEXPR_TMPL constexpr -# else -# define MOZ_CONSTEXPR_TMPL -# endif -#else -# define MOZ_CONSTEXPR /* no support */ -# define MOZ_CONSTEXPR_VAR const -# define MOZ_CONSTEXPR_TMPL -#endif - -/* - * MOZ_EXPLICIT_CONVERSION is a specifier on a type conversion - * overloaded operator that declares that a C++11 compiler should restrict - * this operator to allow only explicit type conversions, disallowing - * implicit conversions. - * - * Example: - * - * template - * class Ptr - * { - * T* mPtr; - * MOZ_EXPLICIT_CONVERSION operator bool() const - * { - * return mPtr != nullptr; - * } - * }; - * - */ -#ifdef MOZ_HAVE_EXPLICIT_CONVERSION -# define MOZ_EXPLICIT_CONVERSION explicit -#else -# define MOZ_EXPLICIT_CONVERSION /* no support */ -#endif - -/* * MOZ_NEVER_INLINE is a macro which expands to tell the compiler that the * method decorated with it must never be inlined, even if the compiler would * otherwise choose to inline the method. Compilers aren't absolutely @@ -318,37 +238,48 @@ #endif /** - * MOZ_WARN_UNUSED_RESULT tells the compiler to emit a warning if a function's + * MOZ_MUST_USE tells the compiler to emit a warning if a function's * return value is not used by the caller. * - * Place this attribute at the very beginning of a function definition. For + * Place this attribute at the very beginning of a function declaration. For * example, write * - * MOZ_WARN_UNUSED_RESULT int foo(); + * MOZ_MUST_USE int foo(); * * or * - * MOZ_WARN_UNUSED_RESULT int foo() { return 42; } + * MOZ_MUST_USE int foo() { return 42; } */ #if defined(__GNUC__) || defined(__clang__) -# define MOZ_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) +# define MOZ_MUST_USE __attribute__ ((warn_unused_result)) #else -# define MOZ_WARN_UNUSED_RESULT +# define MOZ_MUST_USE #endif /** * MOZ_FALLTHROUGH is an annotation to suppress compiler warnings about switch * cases that fall through without a break or return statement. MOZ_FALLTHROUGH - * is only needed on cases that have code: + * is only needed on cases that have code. + * + * MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about + * switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in + * debug builds, but intentionally fall through in release builds. See comment + * in Assertions.h for more details. * * switch (foo) { * case 1: // These cases have no code. No fallthrough annotations are needed. * case 2: - * case 3: - * foo = 4; // This case has code, so a fallthrough annotation is needed: + * case 3: // This case has code, so a fallthrough annotation is needed! + * foo++; * MOZ_FALLTHROUGH; - * default: + * case 4: * return foo; + * + * default: + * // This case asserts in debug builds, falls through in release. + * MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!"); + * case 5: + * return 5; * } */ #if defined(__clang__) && __cplusplus >= 201103L @@ -451,10 +382,12 @@ * intended to prevent introducing static initializers. This attribute * currently makes it a compile-time error to instantiate these classes * anywhere other than at the global scope, or as a static member of a class. + * In non-debug mode, it also prohibits non-trivial constructors and + * destructors. * MOZ_TRIVIAL_CTOR_DTOR: Applies to all classes that must have both a trivial - * constructor and a trivial destructor. Setting this attribute on a class - * makes it a compile-time error for that class to get a non-trivial - * constructor or destructor for any reason. + * or constexpr constructor and a trivial destructor. Setting this attribute + * on a class makes it a compile-time error for that class to get a + * non-trivial constructor or destructor for any reason. * MOZ_HEAP_ALLOCATOR: Applies to any function. This indicates that the return * value is allocated on the heap, and will as a result check such allocations * during MOZ_STACK_CLASS and MOZ_NONHEAP_CLASS annotation checking. @@ -500,9 +433,9 @@ * function. This is intended to be used with operator->() of our smart * pointer classes to ensure that the refcount of an object wrapped in a * smart pointer is not manipulated directly. - * MOZ_MUST_USE: Applies to type declarations. Makes it a compile time error to not - * use the return value of a function which has this type. This is intended to be - * used with types which it is an error to not use. + * MOZ_MUST_USE_TYPE: Applies to type declarations. Makes it a compile time + * error to not use the return value of a function which has this type. This + * is intended to be used with types which it is an error to not use. * MOZ_NEEDS_NO_VTABLE_TYPE: Applies to template class declarations. Makes it * a compile time error to instantiate this template with a type parameter which * has a VTable. @@ -512,14 +445,35 @@ * template arguments are required to be safe to move in memory using * memmove(). Passing MOZ_NON_MEMMOVABLE types to these templates is a * compile time error. + * MOZ_NEEDS_MEMMOVABLE_MEMBERS: Applies to class declarations where each member + * must be safe to move in memory using memmove(). MOZ_NON_MEMMOVABLE types + * used in members of these classes are compile time errors. * MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS: Applies to template class * declarations where an instance of the template should be considered, for * static analysis purposes, to inherit any type annotations (such as - * MOZ_MUST_USE and MOZ_STACK_CLASS) from its template arguments. + * MOZ_MUST_USE_TYPE and MOZ_STACK_CLASS) from its template arguments. + * MOZ_INIT_OUTSIDE_CTOR: Applies to class member declarations. Occasionally + * there are class members that are not initialized in the constructor, + * but logic elsewhere in the class ensures they are initialized prior to use. + * Using this attribute on a member disables the check that this member must be + * initialized in constructors via list-initialization, in the constructor body, + * or via functions called from the constructor body. + * MOZ_IS_CLASS_INIT: Applies to class method declarations. Occasionally the + * constructor doesn't initialize all of the member variables and another function + * is used to initialize the rest. This marker is used to make the static analysis + * tool aware that the marked function is part of the initialization process + * and to include the marked function in the scan mechanism that determines witch + * member variables still remain uninitialized. + * MOZ_NON_PARAM: Applies to types. Makes it compile time error to use the type + * in parameter without pointer or reference. * MOZ_NON_AUTOABLE: Applies to class declarations. Makes it a compile time error to * use `auto` in place of this type in variable declarations. This is intended to * be used with types which are intended to be implicitly constructed into other * other types before being assigned to variables. + * MOZ_REQUIRED_BASE_METHOD: Applies to virtual class method declarations. + * Sometimes derived classes override methods that need to be called by their + * overridden counterparts. This marker indicates that the marked method must + * be called by the method that it overrides. */ #ifdef MOZ_CLANG_PLUGIN # define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override"))) @@ -541,13 +495,22 @@ # define MOZ_NON_OWNING_REF __attribute__((annotate("moz_weak_ref"))) # define MOZ_UNSAFE_REF(reason) __attribute__((annotate("moz_weak_ref"))) # define MOZ_NO_ADDREF_RELEASE_ON_RETURN __attribute__((annotate("moz_no_addref_release_on_return"))) -# define MOZ_MUST_USE __attribute__((annotate("moz_must_use"))) +# define MOZ_MUST_USE_TYPE __attribute__((annotate("moz_must_use_type"))) # define MOZ_NEEDS_NO_VTABLE_TYPE __attribute__((annotate("moz_needs_no_vtable_type"))) # define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable"))) # define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type"))) +# define MOZ_NEEDS_MEMMOVABLE_MEMBERS __attribute__((annotate("moz_needs_memmovable_members"))) # define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS \ __attribute__((annotate("moz_inherit_type_annotations_from_template_args"))) # define MOZ_NON_AUTOABLE __attribute__((annotate("moz_non_autoable"))) +# define MOZ_INIT_OUTSIDE_CTOR \ + __attribute__((annotate("moz_ignore_ctor_initialization"))) +# define MOZ_IS_CLASS_INIT \ + __attribute__((annotate("moz_is_class_init"))) +# define MOZ_NON_PARAM \ + __attribute__((annotate("moz_non_param"))) +# define MOZ_REQUIRED_BASE_METHOD \ + __attribute__((annotate("moz_required_base_method"))) /* * It turns out that clang doesn't like void func() __attribute__ {} without a * warning, so use pragmas to disable the warning. This code won't work on GCC @@ -573,12 +536,17 @@ # define MOZ_NON_OWNING_REF /* nothing */ # define MOZ_UNSAFE_REF(reason) /* nothing */ # define MOZ_NO_ADDREF_RELEASE_ON_RETURN /* nothing */ -# define MOZ_MUST_USE /* nothing */ +# define MOZ_MUST_USE_TYPE /* nothing */ # define MOZ_NEEDS_NO_VTABLE_TYPE /* nothing */ # define MOZ_NON_MEMMOVABLE /* nothing */ # define MOZ_NEEDS_MEMMOVABLE_TYPE /* nothing */ +# define MOZ_NEEDS_MEMMOVABLE_MEMBERS /* nothing */ # define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS /* nothing */ +# define MOZ_INIT_OUTSIDE_CTOR /* nothing */ +# define MOZ_IS_CLASS_INIT /* nothing */ +# define MOZ_NON_PARAM /* nothing */ # define MOZ_NON_AUTOABLE /* nothing */ +# define MOZ_REQUIRED_BASE_METHOD /* nothing */ #endif /* MOZ_CLANG_PLUGIN */ #define MOZ_RAII MOZ_NON_TEMPORARY_CLASS MOZ_STACK_CLASS @@ -601,4 +569,36 @@ #endif /* __cplusplus */ +/** + * Printf style formats. MOZ_FORMAT_PRINTF can be used to annotate a + * function or method that is "printf-like"; this will let (some) + * compilers check that the arguments match the template string. + * + * This macro takes two arguments. The first argument is the argument + * number of the template string. The second argument is the argument + * number of the '...' argument holding the arguments. + * + * Argument numbers start at 1. Note that the implicit "this" + * argument of a non-static member function counts as an argument. + * + * So, for a simple case like: + * void print_something (int whatever, const char *fmt, ...); + * The corresponding annotation would be + * MOZ_FORMAT_PRINTF(2, 3) + * However, if "print_something" were a non-static member function, + * then the annotation would be: + * MOZ_FORMAT_PRINTF(3, 4) + * + * Note that the checking is limited to standards-conforming + * printf-likes, and in particular this should not be used for + * PR_snprintf and friends, which are "printf-like" but which assign + * different meanings to the various formats. + */ +#ifdef __GNUC__ +#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) \ + __attribute__ ((format (printf, stringIndex, firstToCheck))) +#else +#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) +#endif + #endif /* mozilla_Attributes_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/BinarySearch.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/BinarySearch.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/BinarySearch.h @@ -31,7 +31,7 @@ * printf("found 13 at %lu\n", match); * } * - * The BinarySearchIf() version behaves similar, but takes |aComparator|, a + * The BinarySearchIf() version behaves similarly, but takes |aComparator|, a * functor to compare the values with, instead of a value to find. * That functor should take one argument - the value to compare - and return an * |int| with the comparison result: @@ -45,13 +45,13 @@ * Example: * * struct Comparator { - * int operator()(int val) const { - * if (mTarget < val) return -1; - * if (mValue > val) return 1; + * int operator()(int aVal) const { + * if (mTarget < aVal) { return -1; } + * if (mTarget > aVal) { return 1; } * return 0; * } - * Comparator(int target) : mTarget(target) {} - const int mTarget; + * explicit Comparator(int aTarget) : mTarget(aTarget) {} + * const int mTarget; * }; * * Vector sortedInts = ... @@ -106,12 +106,12 @@ {} template - int operator()(const U& val) const { - if (mTarget == val) { + int operator()(const U& aVal) const { + if (mTarget == aVal) { return 0; } - if (mTarget < val) { + if (mTarget < aVal) { return -1; } Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/BufferList.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/BufferList.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/BufferList.h @@ -0,0 +1,568 @@ +/* -*- 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/. */ + +#ifndef mozilla_BufferList_h +#define mozilla_BufferList_h + +#include +#include "mozilla/AllocPolicy.h" +#include "mozilla/Maybe.h" +#include "mozilla/Move.h" +#include "mozilla/ScopeExit.h" +#include "mozilla/Types.h" +#include "mozilla/TypeTraits.h" +#include "mozilla/Vector.h" +#include + +// Undo potential #include damage to be able to use std::min. +#undef min + +// BufferList represents a sequence of buffers of data. A BufferList can choose +// to own its buffers or not. The class handles writing to the buffers, +// iterating over them, and reading data out. Unlike SegmentedVector, the +// buffers may be of unequal size. Like SegmentedVector, BufferList is a nice +// way to avoid large contiguous allocations (which can trigger OOMs). + +namespace mozilla { + +template +class BufferList : private AllocPolicy +{ + // Each buffer in a BufferList has a size and a capacity. The first mSize + // bytes are initialized and the remaining |mCapacity - mSize| bytes are free. + struct Segment + { + char* mData; + size_t mSize; + size_t mCapacity; + + Segment(char* aData, size_t aSize, size_t aCapacity) + : mData(aData), + mSize(aSize), + mCapacity(aCapacity) + { + } + + Segment(const Segment&) = delete; + Segment& operator=(const Segment&) = delete; + + Segment(Segment&&) = default; + Segment& operator=(Segment&&) = default; + + char* Start() const { return mData; } + char* End() const { return mData + mSize; } + }; + + template + friend class BufferList; + + public: + // For the convenience of callers, all segments are required to be a multiple + // of 8 bytes in capacity. Also, every buffer except the last one is required + // to be full (i.e., size == capacity). Therefore, a byte at offset N within + // the BufferList and stored in memory at an address A will satisfy + // (N % Align == A % Align) if Align == 2, 4, or 8. + static const size_t kSegmentAlignment = 8; + + // Allocate a BufferList. The BufferList will free all its buffers when it is + // destroyed. An initial buffer of size aInitialSize and capacity + // aInitialCapacity is allocated automatically. This data will be contiguous + // an can be accessed via |Start()|. Subsequent buffers will be allocated with + // capacity aStandardCapacity. + BufferList(size_t aInitialSize, + size_t aInitialCapacity, + size_t aStandardCapacity, + AllocPolicy aAP = AllocPolicy()) + : AllocPolicy(aAP), + mOwning(true), + mSegments(aAP), + mSize(0), + mStandardCapacity(aStandardCapacity) + { + MOZ_ASSERT(aInitialCapacity % kSegmentAlignment == 0); + MOZ_ASSERT(aStandardCapacity % kSegmentAlignment == 0); + + if (aInitialCapacity) { + AllocateSegment(aInitialSize, aInitialCapacity); + } + } + + BufferList(const BufferList& aOther) = delete; + + BufferList(BufferList&& aOther) + : mOwning(aOther.mOwning), + mSegments(Move(aOther.mSegments)), + mSize(aOther.mSize), + mStandardCapacity(aOther.mStandardCapacity) + { + aOther.mSegments.clear(); + aOther.mSize = 0; + } + + BufferList& operator=(const BufferList& aOther) = delete; + + BufferList& operator=(BufferList&& aOther) + { + Clear(); + + mOwning = aOther.mOwning; + mSegments = Move(aOther.mSegments); + mSize = aOther.mSize; + aOther.mSegments.clear(); + aOther.mSize = 0; + return *this; + } + + ~BufferList() { Clear(); } + + // Returns the sum of the sizes of all the buffers. + size_t Size() const { return mSize; } + + void Clear() + { + if (mOwning) { + for (Segment& segment : mSegments) { + this->free_(segment.mData); + } + } + mSegments.clear(); + + mSize = 0; + } + + // Iterates over bytes in the segments. You can advance it by as many bytes as + // you choose. + class IterImpl + { + // Invariants: + // (0) mSegment <= bufferList.mSegments.size() + // (1) mData <= mDataEnd + // (2) If mSegment is not the last segment, mData < mDataEnd + uintptr_t mSegment; + char* mData; + char* mDataEnd; + + friend class BufferList; + + public: + explicit IterImpl(const BufferList& aBuffers) + : mSegment(0), + mData(nullptr), + mDataEnd(nullptr) + { + if (!aBuffers.mSegments.empty()) { + mData = aBuffers.mSegments[0].Start(); + mDataEnd = aBuffers.mSegments[0].End(); + } + } + + // Returns a pointer to the raw data. It is valid to access up to + // RemainingInSegment bytes of this buffer. + char* Data() const + { + MOZ_RELEASE_ASSERT(!Done()); + return mData; + } + + // Returns true if the memory in the range [Data(), Data() + aBytes) is all + // part of one contiguous buffer. + bool HasRoomFor(size_t aBytes) const + { + MOZ_RELEASE_ASSERT(mData <= mDataEnd); + return size_t(mDataEnd - mData) >= aBytes; + } + + // Returns the maximum value aBytes for which HasRoomFor(aBytes) will be + // true. + size_t RemainingInSegment() const + { + MOZ_RELEASE_ASSERT(mData <= mDataEnd); + return mDataEnd - mData; + } + + // Advances the iterator by aBytes bytes. aBytes must be less than + // RemainingInSegment(). If advancing by aBytes takes the iterator to the + // end of a buffer, it will be moved to the beginning of the next buffer + // unless it is the last buffer. + void Advance(const BufferList& aBuffers, size_t aBytes) + { + const Segment& segment = aBuffers.mSegments[mSegment]; + MOZ_RELEASE_ASSERT(segment.Start() <= mData); + MOZ_RELEASE_ASSERT(mData <= mDataEnd); + MOZ_RELEASE_ASSERT(mDataEnd == segment.End()); + + MOZ_RELEASE_ASSERT(HasRoomFor(aBytes)); + mData += aBytes; + + if (mData == mDataEnd && mSegment + 1 < aBuffers.mSegments.length()) { + mSegment++; + const Segment& nextSegment = aBuffers.mSegments[mSegment]; + mData = nextSegment.Start(); + mDataEnd = nextSegment.End(); + MOZ_RELEASE_ASSERT(mData < mDataEnd); + } + } + + // Advance the iterator by aBytes, possibly crossing segments. This function + // returns false if it runs out of buffers to advance through. Otherwise it + // returns true. + bool AdvanceAcrossSegments(const BufferList& aBuffers, size_t aBytes) + { + size_t bytes = aBytes; + while (bytes) { + size_t toAdvance = std::min(bytes, RemainingInSegment()); + if (!toAdvance) { + return false; + } + Advance(aBuffers, toAdvance); + bytes -= toAdvance; + } + return true; + } + + // Returns true when the iterator reaches the end of the BufferList. + bool Done() const + { + return mData == mDataEnd; + } + + private: + + // Count the bytes we would need to advance in order to reach aTarget. + size_t BytesUntil(const BufferList& aBuffers, const IterImpl& aTarget) const { + size_t offset = 0; + + MOZ_ASSERT(aTarget.IsIn(aBuffers)); + + char* data = mData; + for (uintptr_t segment = mSegment; segment < aTarget.mSegment; segment++) { + offset += aBuffers.mSegments[segment].End() - data; + data = aBuffers.mSegments[segment].mData; + } + + MOZ_RELEASE_ASSERT(IsIn(aBuffers)); + MOZ_RELEASE_ASSERT(aTarget.mData >= data); + + offset += aTarget.mData - data; + return offset; + } + + bool IsIn(const BufferList& aBuffers) const { + return mSegment < aBuffers.mSegments.length() && + mData >= aBuffers.mSegments[mSegment].mData && + mData < aBuffers.mSegments[mSegment].End(); + } + }; + + // Special convenience method that returns Iter().Data(). + char* Start() { return mSegments[0].mData; } + const char* Start() const { return mSegments[0].mData; } + + IterImpl Iter() const { return IterImpl(*this); } + + // Copies aSize bytes from aData into the BufferList. The storage for these + // bytes may be split across multiple buffers. Size() is increased by aSize. + inline bool WriteBytes(const char* aData, size_t aSize); + + // Copies possibly non-contiguous byte range starting at aIter into + // aData. aIter is advanced by aSize bytes. Returns false if it runs out of + // data before aSize. + inline bool ReadBytes(IterImpl& aIter, char* aData, size_t aSize) const; + + // Return a new BufferList that shares storage with this BufferList. The new + // BufferList is read-only. It allows iteration over aSize bytes starting at + // aIter. Borrow can fail, in which case *aSuccess will be false upon + // return. The borrowed BufferList can use a different AllocPolicy than the + // original one. However, it is not responsible for freeing buffers, so the + // AllocPolicy is only used for the buffer vector. + template + BufferList Borrow(IterImpl& aIter, size_t aSize, bool* aSuccess, + BorrowingAllocPolicy aAP = BorrowingAllocPolicy()) const; + + // Return a new BufferList and move storage from this BufferList to it. The + // new BufferList owns the buffers. Move can fail, in which case *aSuccess + // will be false upon return. The new BufferList can use a different + // AllocPolicy than the original one. The new OtherAllocPolicy is responsible + // for freeing buffers, so the OtherAllocPolicy must use freeing method + // compatible to the original one. + template + BufferList MoveFallible(bool* aSuccess, OtherAllocPolicy aAP = OtherAllocPolicy()); + + // Return a new BufferList that adopts the byte range starting at Iter so that + // range [aIter, aIter + aSize) is transplanted to the returned BufferList. + // Contents of the buffer before aIter + aSize is left undefined. + // Extract can fail, in which case *aSuccess will be false upon return. The + // moved buffers are erased from the original BufferList. In case of extract + // fails, the original BufferList is intact. All other iterators except aIter + // are invalidated. + // This method requires aIter and aSize to be 8-byte aligned. + BufferList Extract(IterImpl& aIter, size_t aSize, bool* aSuccess); + + // Return the number of bytes from 'start' to 'end', two iterators within + // this BufferList. + size_t RangeLength(const IterImpl& start, const IterImpl& end) const { + MOZ_ASSERT(start.IsIn(*this) && end.IsIn(*this)); + return start.BytesUntil(*this, end); + } + +private: + explicit BufferList(AllocPolicy aAP) + : AllocPolicy(aAP), + mOwning(false), + mSize(0), + mStandardCapacity(0) + { + } + + void* AllocateSegment(size_t aSize, size_t aCapacity) + { + MOZ_RELEASE_ASSERT(mOwning); + + char* data = this->template pod_malloc(aCapacity); + if (!data) { + return nullptr; + } + if (!mSegments.append(Segment(data, aSize, aCapacity))) { + this->free_(data); + return nullptr; + } + mSize += aSize; + return data; + } + + bool mOwning; + Vector mSegments; + size_t mSize; + size_t mStandardCapacity; +}; + +template +bool +BufferList::WriteBytes(const char* aData, size_t aSize) +{ + MOZ_RELEASE_ASSERT(mOwning); + MOZ_RELEASE_ASSERT(mStandardCapacity); + + size_t copied = 0; + size_t remaining = aSize; + + if (!mSegments.empty()) { + Segment& lastSegment = mSegments.back(); + + size_t toCopy = std::min(aSize, lastSegment.mCapacity - lastSegment.mSize); + memcpy(lastSegment.mData + lastSegment.mSize, aData, toCopy); + lastSegment.mSize += toCopy; + mSize += toCopy; + + copied += toCopy; + remaining -= toCopy; + } + + while (remaining) { + size_t toCopy = std::min(remaining, mStandardCapacity); + + void* data = AllocateSegment(toCopy, mStandardCapacity); + if (!data) { + return false; + } + memcpy(data, aData + copied, toCopy); + + copied += toCopy; + remaining -= toCopy; + } + + return true; +} + +template +bool +BufferList::ReadBytes(IterImpl& aIter, char* aData, size_t aSize) const +{ + size_t copied = 0; + size_t remaining = aSize; + while (remaining) { + size_t toCopy = std::min(aIter.RemainingInSegment(), remaining); + if (!toCopy) { + // We've run out of data in the last segment. + return false; + } + memcpy(aData + copied, aIter.Data(), toCopy); + copied += toCopy; + remaining -= toCopy; + + aIter.Advance(*this, toCopy); + } + + return true; +} + +template template +BufferList +BufferList::Borrow(IterImpl& aIter, size_t aSize, bool* aSuccess, + BorrowingAllocPolicy aAP) const +{ + BufferList result(aAP); + + size_t size = aSize; + while (size) { + size_t toAdvance = std::min(size, aIter.RemainingInSegment()); + + if (!toAdvance || !result.mSegments.append(typename BufferList::Segment(aIter.mData, toAdvance, toAdvance))) { + *aSuccess = false; + return result; + } + aIter.Advance(*this, toAdvance); + size -= toAdvance; + } + + result.mSize = aSize; + *aSuccess = true; + return result; +} + +template template +BufferList +BufferList::MoveFallible(bool* aSuccess, OtherAllocPolicy aAP) +{ + BufferList result(0, 0, mStandardCapacity, aAP); + + IterImpl iter = Iter(); + while (!iter.Done()) { + size_t toAdvance = iter.RemainingInSegment(); + + if (!toAdvance || !result.mSegments.append(typename BufferList::Segment(iter.mData, toAdvance, toAdvance))) { + *aSuccess = false; + result.mSegments.clear(); + return result; + } + iter.Advance(*this, toAdvance); + } + + result.mSize = mSize; + mSegments.clear(); + mSize = 0; + *aSuccess = true; + return result; +} + +template +BufferList +BufferList::Extract(IterImpl& aIter, size_t aSize, bool* aSuccess) +{ + MOZ_RELEASE_ASSERT(aSize); + MOZ_RELEASE_ASSERT(mOwning); + MOZ_ASSERT(aSize % kSegmentAlignment == 0); + MOZ_ASSERT(intptr_t(aIter.mData) % kSegmentAlignment == 0); + + auto failure = [this, aSuccess]() { + *aSuccess = false; + return BufferList(0, 0, mStandardCapacity); + }; + + // Number of segments we'll need to copy data from to satisfy the request. + size_t segmentsNeeded = 0; + // If this is None then the last segment is a full segment, otherwise we need + // to copy this many bytes. + Maybe lastSegmentSize; + { + // Copy of the iterator to walk the BufferList and see how many segments we + // need to copy. + IterImpl iter = aIter; + size_t remaining = aSize; + while (!iter.Done() && remaining && + remaining >= iter.RemainingInSegment()) { + remaining -= iter.RemainingInSegment(); + iter.Advance(*this, iter.RemainingInSegment()); + segmentsNeeded++; + } + + if (remaining) { + if (iter.Done()) { + // We reached the end of the BufferList and there wasn't enough data to + // satisfy the request. + return failure(); + } + lastSegmentSize.emplace(remaining); + // The last block also counts as a segment. This makes the conditionals + // on segmentsNeeded work in the rest of the function. + segmentsNeeded++; + } + } + + BufferList result(0, 0, mStandardCapacity); + if (!result.mSegments.reserve(segmentsNeeded + lastSegmentSize.isSome())) { + return failure(); + } + + // Copy the first segment, it's special because we can't just steal the + // entire Segment struct from this->mSegments. + size_t firstSegmentSize = std::min(aSize, aIter.RemainingInSegment()); + if (!result.WriteBytes(aIter.Data(), firstSegmentSize)) { + return failure(); + } + aIter.Advance(*this, firstSegmentSize); + segmentsNeeded--; + + // The entirety of the request wasn't in the first segment, now copy the + // rest. + if (segmentsNeeded) { + char* finalSegment = nullptr; + // Pre-allocate the final segment so that if this fails, we return before + // we delete the elements from |this->mSegments|. + if (lastSegmentSize.isSome()) { + MOZ_RELEASE_ASSERT(mStandardCapacity >= *lastSegmentSize); + finalSegment = this->template pod_malloc(mStandardCapacity); + if (!finalSegment) { + return failure(); + } + } + + size_t copyStart = aIter.mSegment; + // Copy segments from this over to the result and remove them from our + // storage. Not needed if the only segment we need to copy is the last + // partial one. + size_t segmentsToCopy = segmentsNeeded - lastSegmentSize.isSome(); + for (size_t i = 0; i < segmentsToCopy; ++i) { + result.mSegments.infallibleAppend( + Segment(mSegments[aIter.mSegment].mData, + mSegments[aIter.mSegment].mSize, + mSegments[aIter.mSegment].mCapacity)); + aIter.Advance(*this, aIter.RemainingInSegment()); + } + // Due to the way IterImpl works, there are two cases here: (1) if we've + // consumed the entirety of the BufferList, then the iterator is pointed at + // the end of the final segment, (2) otherwise it is pointed at the start + // of the next segment. We want to verify that we really consumed all + // |segmentsToCopy| segments. + MOZ_RELEASE_ASSERT( + (aIter.mSegment == copyStart + segmentsToCopy) || + (aIter.Done() && aIter.mSegment == copyStart + segmentsToCopy - 1)); + mSegments.erase(mSegments.begin() + copyStart, + mSegments.begin() + copyStart + segmentsToCopy); + + // Reset the iter's position for what we just deleted. + aIter.mSegment -= segmentsToCopy; + + if (lastSegmentSize.isSome()) { + // We called reserve() on result.mSegments so infallibleAppend is safe. + result.mSegments.infallibleAppend( + Segment(finalSegment, 0, mStandardCapacity)); + bool r = result.WriteBytes(aIter.Data(), *lastSegmentSize); + MOZ_RELEASE_ASSERT(r); + aIter.Advance(*this, *lastSegmentSize); + } + } + + mSize -= aSize; + result.mSize = aSize; + + *aSuccess = true; + return result; +} + +} // namespace mozilla + +#endif /* mozilla_BufferList_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Casting.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Casting.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Casting.h @@ -17,16 +17,29 @@ namespace mozilla { /** - * Return a value of type |To|, containing the underlying bit pattern of + * Sets the outparam value of type |To| with the same underlying bit pattern of * |aFrom|. * * |To| and |From| must be types of the same size; be careful of cross-platform * size differences, or this might fail to compile on some but not all * platforms. + * + * There is also a variant that returns the value directly. In most cases, the + * two variants should be identical. However, in the specific case of x86 + * chips, the behavior differs: returning floating-point values directly is done + * through the x87 stack, and x87 loads and stores turn signaling NaNs into + * quiet NaNs... silently. Returning floating-point values via outparam, + * however, is done entirely within the SSE registers when SSE2 floating-point + * is enabled in the compiler, which has semantics-preserving behavior you would + * expect. + * + * If preserving the distinction between signaling NaNs and quiet NaNs is + * important to you, you should use the outparam version. In all other cases, + * you should use the direct return version. */ template -inline To -BitwiseCast(const From aFrom) +inline void +BitwiseCast(const From aFrom, To* aResult) { static_assert(sizeof(From) == sizeof(To), "To and From must have the same size"); @@ -36,7 +49,16 @@ To mTo; } u; u.mFrom = aFrom; - return u.mTo; + *aResult = u.mTo; +} + +template +inline To +BitwiseCast(const From aFrom) +{ + To temp; + BitwiseCast(aFrom, &temp); + return temp; } namespace detail { Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ChaosMode.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ChaosMode.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ChaosMode.h @@ -27,6 +27,8 @@ IOAmounts = 0x8, // Iterate over hash tables in random order. HashTableIteration = 0x10, + // Randomly refuse to use cached version of image (when allowed by spec). + ImageCache = 0x20, Any = 0xffffffff, }; Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Char16.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Char16.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Char16.h @@ -17,38 +17,8 @@ * is a 16-bit code unit of a Unicode code point, not a "character". */ -#if defined(_MSC_VER) && _MSC_VER < 1900 - /* - * C++11 says char16_t is a distinct builtin type, but Windows's yvals.h - * typedefs char16_t as an unsigned short prior to MSVC 2015, which - * implemented C++11's distinct char16_t type. We would like to alias - * char16_t to Windows's 16-bit wchar_t so we can declare UTF-16 literals as - * constant expressions (and pass char16_t pointers to Windows APIs). We - * #define _CHAR16T here in order to prevent yvals.h from overriding our - * char16_t typedefs, which we set to wchar_t for C++ code. - * - * In addition, #defining _CHAR16T will prevent yvals.h from defining a - * char32_t type, so we have to undo that damage here and provide our own, - * which is identical to the yvals.h type. - */ -# define MOZ_UTF16_HELPER(s) L##s -# define _CHAR16T -typedef wchar_t char16_t; -typedef unsigned int char32_t; -#else - /* C++11 has a builtin char16_t type. */ -# define MOZ_UTF16_HELPER(s) u##s - /** - * This macro is used to distinguish when char16_t would be a distinct - * typedef from wchar_t. - */ -# define MOZ_CHAR16_IS_NOT_WCHAR -# ifdef WIN32 -# define MOZ_USE_CHAR16_WRAPPER -# endif -#endif - -#ifdef MOZ_USE_CHAR16_WRAPPER +#ifdef WIN32 +# define MOZ_USE_CHAR16_WRAPPER # include /** * Win32 API extensively uses wchar_t, which is represented by a separated @@ -214,20 +184,10 @@ #endif -/* - * Macro arguments used in concatenation or stringification won't be expanded. - * Therefore, in order for |MOZ_UTF16(FOO)| to work as expected (which is to - * expand |FOO| before doing whatever |MOZ_UTF16| needs to do to it) a helper - * macro, |MOZ_UTF16_HELPER| needs to be inserted in between to allow the macro - * argument to expand. See "3.10.6 Separate Expansion of Macro Arguments" of the - * CPP manual for a more accurate and precise explanation. - */ -#define MOZ_UTF16(s) MOZ_UTF16_HELPER(s) - static_assert(sizeof(char16_t) == 2, "Is char16_t type 16 bits?"); static_assert(char16_t(-1) > char16_t(0), "Is char16_t type unsigned?"); -static_assert(sizeof(MOZ_UTF16('A')) == 2, "Is char literal 16 bits?"); -static_assert(sizeof(MOZ_UTF16("")[0]) == 2, "Is string char 16 bits?"); +static_assert(sizeof(u'A') == 2, "Is unicode char literal 16 bits?"); +static_assert(sizeof(u""[0]) == 2, "Is unicode string char 16 bits?"); #endif Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Compiler.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Compiler.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Compiler.h @@ -10,21 +10,24 @@ #define mozilla_Compiler_h #define MOZ_IS_GCC 0 -#define MOS_IS_MSVC 0 +#define MOZ_IS_MSVC 0 #if !defined(__clang__) && defined(__GNUC__) # undef MOZ_IS_GCC # define MOZ_IS_GCC 1 /* - * This macro should simplify gcc version checking. For example, to check + * These macros should simplify gcc version checking. For example, to check * for gcc 4.7.1 or later, check `#if MOZ_GCC_VERSION_AT_LEAST(4, 7, 1)`. */ # define MOZ_GCC_VERSION_AT_LEAST(major, minor, patchlevel) \ ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) \ >= ((major) * 10000 + (minor) * 100 + (patchlevel))) -# if !MOZ_GCC_VERSION_AT_LEAST(4, 7, 0) -# error "mfbt (and Gecko) require at least gcc 4.7 to build." +# define MOZ_GCC_VERSION_AT_MOST(major, minor, patchlevel) \ + ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) \ + <= ((major) * 10000 + (minor) * 100 + (patchlevel))) +# if !MOZ_GCC_VERSION_AT_LEAST(4, 8, 0) +# error "mfbt (and Gecko) require at least gcc 4.8 to build." # endif #elif defined(_MSC_VER) Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Compression.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Compression.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Compression.h @@ -61,8 +61,7 @@ /** * If the source stream is malformed, the function will stop decoding - * and return a negative result, indicating the byte position of the - * faulty instruction + * and return false. * * This function never writes outside of provided buffers, and never * modifies input buffer. @@ -71,9 +70,9 @@ * minimum of |aOutputSize| bytes. * * @param aOutputSize is the output size, therefore the original size - * @return the number of bytes read in the source buffer + * @return true on success, false on failure */ - static MFBT_API bool + static MFBT_API MOZ_MUST_USE bool decompress(const char* aSource, char* aDest, size_t aOutputSize); /** @@ -91,8 +90,9 @@ * already allocated) * @param aOutputSize the actual number of bytes decoded in the destination * buffer (necessarily <= aMaxOutputSize) + * @return true on success, false on failure */ - static MFBT_API bool + static MFBT_API MOZ_MUST_USE bool decompress(const char* aSource, size_t aInputSize, char* aDest, size_t aMaxOutputSize, size_t* aOutputSize); Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/DebugOnly.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/DebugOnly.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/DebugOnly.h @@ -24,17 +24,19 @@ * DebugOnly check = func(); * MOZ_ASSERT(check); * - * more concisely than declaring |check| conditional on #ifdef DEBUG, but also - * without allocating storage space for |check| in release builds. + * more concisely than declaring |check| conditional on #ifdef DEBUG. * * DebugOnly instances can only be coerced to T in debug builds. In release * builds they don't have a value, so type coercion is not well defined. * - * Note that DebugOnly instances still take up one byte of space, plus padding, - * when used as members of structs. + * NOTE: DebugOnly instances still take up one byte of space, plus padding, even + * in optimized, non-DEBUG builds (see bug 1253094 comment 37 for more info). + * For this reason the class is MOZ_STACK_CLASS to prevent consumers using + * DebugOnly for struct/class members and unwittingly inflating the size of + * their objects in release builds. */ template -class DebugOnly +class MOZ_STACK_CLASS DebugOnly { public: #ifdef DEBUG Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Decimal.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Decimal.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Decimal.h @@ -30,8 +30,8 @@ /** * Imported from: - * http://src.chromium.org/viewvc/blink/trunk/Source/core/platform/Decimal.h - * Check hg log for the svn rev of the last update from Blink core. + * https://chromium.googlesource.com/chromium/src.git/+/master/third_party/WebKit/Source/platform/Decimal.h + * Check UPSTREAM-GIT-SHA for the commit ID of the last update from Blink core. */ #ifndef Decimal_h @@ -48,25 +48,33 @@ #define ASSERT MOZ_ASSERT #endif -// To use WTF_MAKE_FAST_ALLOCATED we'd need: -// http://src.chromium.org/viewvc/blink/trunk/Source/wtf/FastMalloc.h +#define PLATFORM_EXPORT + +// To use USING_FAST_MALLOC we'd need: +// https://chromium.googlesource.com/chromium/src.git/+/master/third_party/WebKit/Source/wtf/Allocator.h // Since we don't allocate Decimal objects, no need. -#define WTF_MAKE_FAST_ALLOCATED \ +#define USING_FAST_MALLOC(type) \ void ignore_this_dummy_method() = delete -namespace WebCore { +#define DISALLOW_NEW() \ + private: \ + void* operator new(size_t) = delete; \ + void* operator new(size_t, void*) = delete; \ + public: + +namespace blink { namespace DecimalPrivate { class SpecialValueHandler; -} // namespace DecimalPrivate +} // This class represents decimal base floating point number. // // FIXME: Once all C++ compiler support decimal type, we should replace this // class to compiler supported one. See below URI for current status of decimal // type for C++: // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1977.html -class Decimal { - WTF_MAKE_FAST_ALLOCATED; +class PLATFORM_EXPORT Decimal { + USING_FAST_MALLOC(Decimal); public: enum Sign { Positive, @@ -75,6 +83,7 @@ // You should not use EncodedData other than unit testing. class EncodedData { + DISALLOW_NEW(); // For accessing FormatClass. friend class Decimal; friend class DecimalPrivate::SpecialValueHandler; @@ -93,7 +102,7 @@ bool isSpecial() const { return m_formatClass == ClassInfinity || m_formatClass == ClassNaN; } bool isZero() const { return m_formatClass == ClassZero; } Sign sign() const { return m_sign; } - void setSign(Sign aSign) { m_sign = aSign; } + void setSign(Sign sign) { m_sign = sign; } private: enum FormatClass { @@ -151,7 +160,7 @@ bool isZero() const { return m_data.isZero(); } MFBT_API Decimal abs() const; - MFBT_API Decimal ceiling() const; + MFBT_API Decimal ceil() const; MFBT_API Decimal floor() const; MFBT_API Decimal remainder(const Decimal&) const; MFBT_API Decimal round() const; @@ -196,13 +205,13 @@ EncodedData m_data; }; -} // namespace WebCore +} // namespace blink namespace mozilla { - typedef WebCore::Decimal Decimal; +typedef blink::Decimal Decimal; } // namespace mozilla -#undef WTF_MAKE_FAST_ALLOCATED +#undef USING_FAST_MALLOC #ifdef DEFINED_ASSERT_FOR_DECIMAL_H #undef DEFINED_ASSERT_FOR_DECIMAL_H @@ -210,4 +219,3 @@ #endif #endif // Decimal_h - Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Endian.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Endian.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Endian.h @@ -1,697 +0,0 @@ -/* -*- 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/. */ - -/* Functions for reading and writing integers in various endiannesses. */ - -/* - * The classes LittleEndian and BigEndian expose static methods for - * reading and writing 16-, 32-, and 64-bit signed and unsigned integers - * in their respective endianness. The naming scheme is: - * - * {Little,Big}Endian::{read,write}{Uint,Int} - * - * For instance, LittleEndian::readInt32 will read a 32-bit signed - * integer from memory in little endian format. Similarly, - * BigEndian::writeUint16 will write a 16-bit unsigned integer to memory - * in big-endian format. - * - * The class NativeEndian exposes methods for conversion of existing - * data to and from the native endianness. These methods are intended - * for cases where data needs to be transferred, serialized, etc. - * swap{To,From}{Little,Big}Endian byteswap a single value if necessary. - * Bulk conversion functions are also provided which optimize the - * no-conversion-needed case: - * - * - copyAndSwap{To,From}{Little,Big}Endian; - * - swap{To,From}{Little,Big}EndianInPlace. - * - * The *From* variants are intended to be used for reading data and the - * *To* variants for writing data. - * - * Methods on NativeEndian work with integer data of any type. - * Floating-point data is not supported. - * - * For clarity in networking code, "Network" may be used as a synonym - * for "Big" in any of the above methods or class names. - * - * As an example, reading a file format header whose fields are stored - * in big-endian format might look like: - * - * class ExampleHeader - * { - * private: - * uint32_t mMagic; - * uint32_t mLength; - * uint32_t mTotalRecords; - * uint64_t mChecksum; - * - * public: - * ExampleHeader(const void* data) - * { - * const uint8_t* ptr = static_cast(data); - * mMagic = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); - * mLength = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); - * mTotalRecords = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); - * mChecksum = BigEndian::readUint64(ptr); - * } - * ... - * }; - */ - -#ifndef mozilla_Endian_h -#define mozilla_Endian_h - -#include "mozilla/Assertions.h" -#include "mozilla/Attributes.h" -#include "mozilla/Compiler.h" -#include "mozilla/DebugOnly.h" -#include "mozilla/TypeTraits.h" - -#include -#include - -#if defined(_MSC_VER) -# include -# pragma intrinsic(_byteswap_ushort) -# pragma intrinsic(_byteswap_ulong) -# pragma intrinsic(_byteswap_uint64) -#endif - -#if defined(_WIN64) -# if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_) -# define MOZ_LITTLE_ENDIAN 1 -# else -# error "CPU type is unknown" -# endif -#elif defined(_WIN32) -# if defined(_M_IX86) -# define MOZ_LITTLE_ENDIAN 1 -# elif defined(_M_ARM) -# define MOZ_LITTLE_ENDIAN 1 -# else -# error "CPU type is unknown" -# endif -#elif defined(__APPLE__) || defined(__powerpc__) || defined(__ppc__) -# if __LITTLE_ENDIAN__ -# define MOZ_LITTLE_ENDIAN 1 -# elif __BIG_ENDIAN__ -# define MOZ_BIG_ENDIAN 1 -# endif -#elif defined(__GNUC__) && \ - defined(__BYTE_ORDER__) && \ - defined(__ORDER_LITTLE_ENDIAN__) && \ - defined(__ORDER_BIG_ENDIAN__) - /* - * Some versions of GCC provide architecture-independent macros for - * this. Yes, there are more than two values for __BYTE_ORDER__. - */ -# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define MOZ_LITTLE_ENDIAN 1 -# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -# define MOZ_BIG_ENDIAN 1 -# else -# error "Can't handle mixed-endian architectures" -# endif -/* - * We can't include useful headers like or - * here because they're not present on all platforms. Instead we have - * this big conditional that ideally will catch all the interesting - * cases. - */ -#elif defined(__sparc) || defined(__sparc__) || \ - defined(_POWER) || defined(__hppa) || \ - defined(_MIPSEB) || defined(__ARMEB__) || \ - defined(__s390__) || defined(__AARCH64EB__) || \ - (defined(__sh__) && defined(__LITTLE_ENDIAN__)) || \ - (defined(__ia64) && defined(__BIG_ENDIAN__)) -# define MOZ_BIG_ENDIAN 1 -#elif defined(__i386) || defined(__i386__) || \ - defined(__x86_64) || defined(__x86_64__) || \ - defined(_MIPSEL) || defined(__ARMEL__) || \ - defined(__alpha__) || defined(__AARCH64EL__) || \ - (defined(__sh__) && defined(__BIG_ENDIAN__)) || \ - (defined(__ia64) && !defined(__BIG_ENDIAN__)) -# define MOZ_LITTLE_ENDIAN 1 -#endif - -#if MOZ_BIG_ENDIAN -# define MOZ_LITTLE_ENDIAN 0 -#elif MOZ_LITTLE_ENDIAN -# define MOZ_BIG_ENDIAN 0 -#else -# error "Cannot determine endianness" -#endif - -#if defined(__clang__) -# if __has_builtin(__builtin_bswap16) -# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 -# endif -#elif defined(__GNUC__) -# if MOZ_GCC_VERSION_AT_LEAST(4, 8, 0) -# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 -# endif -#elif defined(_MSC_VER) -# define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort -#endif - -namespace mozilla { - -namespace detail { - -/* - * We need wrappers here because free functions with default template - * arguments and/or partial specialization of function templates are not - * supported by all the compilers we use. - */ -template -struct Swapper; - -template -struct Swapper -{ - static T swap(T aValue) - { -#if defined(MOZ_HAVE_BUILTIN_BYTESWAP16) - return MOZ_HAVE_BUILTIN_BYTESWAP16(aValue); -#else - return T(((aValue & 0x00ff) << 8) | ((aValue & 0xff00) >> 8)); -#endif - } -}; - -template -struct Swapper -{ - static T swap(T aValue) - { -#if defined(__clang__) || defined(__GNUC__) - return T(__builtin_bswap32(aValue)); -#elif defined(_MSC_VER) - return T(_byteswap_ulong(aValue)); -#else - return T(((aValue & 0x000000ffU) << 24) | - ((aValue & 0x0000ff00U) << 8) | - ((aValue & 0x00ff0000U) >> 8) | - ((aValue & 0xff000000U) >> 24)); -#endif - } -}; - -template -struct Swapper -{ - static inline T swap(T aValue) - { -#if defined(__clang__) || defined(__GNUC__) - return T(__builtin_bswap64(aValue)); -#elif defined(_MSC_VER) - return T(_byteswap_uint64(aValue)); -#else - return T(((aValue & 0x00000000000000ffULL) << 56) | - ((aValue & 0x000000000000ff00ULL) << 40) | - ((aValue & 0x0000000000ff0000ULL) << 24) | - ((aValue & 0x00000000ff000000ULL) << 8) | - ((aValue & 0x000000ff00000000ULL) >> 8) | - ((aValue & 0x0000ff0000000000ULL) >> 24) | - ((aValue & 0x00ff000000000000ULL) >> 40) | - ((aValue & 0xff00000000000000ULL) >> 56)); -#endif - } -}; - -enum Endianness { Little, Big }; - -#if MOZ_BIG_ENDIAN -# define MOZ_NATIVE_ENDIANNESS detail::Big -#else -# define MOZ_NATIVE_ENDIANNESS detail::Little -#endif - -class EndianUtils -{ - /** - * Assert that the memory regions [aDest, aDest+aCount) and - * [aSrc, aSrc+aCount] do not overlap. aCount is given in bytes. - */ - static void assertNoOverlap(const void* aDest, const void* aSrc, - size_t aCount) - { - DebugOnly byteDestPtr = static_cast(aDest); - DebugOnly byteSrcPtr = static_cast(aSrc); - MOZ_ASSERT((byteDestPtr <= byteSrcPtr && - byteDestPtr + aCount <= byteSrcPtr) || - (byteSrcPtr <= byteDestPtr && - byteSrcPtr + aCount <= byteDestPtr)); - } - - template - static void assertAligned(T* aPtr) - { - MOZ_ASSERT((uintptr_t(aPtr) % sizeof(T)) == 0, "Unaligned pointer!"); - } - -protected: - /** - * Return |aValue| converted from SourceEndian encoding to DestEndian - * encoding. - */ - template - static inline T maybeSwap(T aValue) - { - if (SourceEndian == DestEndian) { - return aValue; - } - return Swapper::swap(aValue); - } - - /** - * Convert |aCount| elements at |aPtr| from SourceEndian encoding to - * DestEndian encoding. - */ - template - static inline void maybeSwapInPlace(T* aPtr, size_t aCount) - { - assertAligned(aPtr); - - if (SourceEndian == DestEndian) { - return; - } - for (size_t i = 0; i < aCount; i++) { - aPtr[i] = Swapper::swap(aPtr[i]); - } - } - - /** - * Write |aCount| elements to the unaligned address |aDest| in DestEndian - * format, using elements found at |aSrc| in SourceEndian format. - */ - template - static void copyAndSwapTo(void* aDest, const T* aSrc, size_t aCount) - { - assertNoOverlap(aDest, aSrc, aCount * sizeof(T)); - assertAligned(aSrc); - - if (SourceEndian == DestEndian) { - memcpy(aDest, aSrc, aCount * sizeof(T)); - return; - } - - uint8_t* byteDestPtr = static_cast(aDest); - for (size_t i = 0; i < aCount; ++i) { - union - { - T mVal; - uint8_t mBuffer[sizeof(T)]; - } u; - u.mVal = maybeSwap(aSrc[i]); - memcpy(byteDestPtr, u.mBuffer, sizeof(T)); - byteDestPtr += sizeof(T); - } - } - - /** - * Write |aCount| elements to |aDest| in DestEndian format, using elements - * found at the unaligned address |aSrc| in SourceEndian format. - */ - template - static void copyAndSwapFrom(T* aDest, const void* aSrc, size_t aCount) - { - assertNoOverlap(aDest, aSrc, aCount * sizeof(T)); - assertAligned(aDest); - - if (SourceEndian == DestEndian) { - memcpy(aDest, aSrc, aCount * sizeof(T)); - return; - } - - const uint8_t* byteSrcPtr = static_cast(aSrc); - for (size_t i = 0; i < aCount; ++i) { - union - { - T mVal; - uint8_t mBuffer[sizeof(T)]; - } u; - memcpy(u.mBuffer, byteSrcPtr, sizeof(T)); - aDest[i] = maybeSwap(u.mVal); - byteSrcPtr += sizeof(T); - } - } -}; - -template -class Endian : private EndianUtils -{ -protected: - /** Read a uint16_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT uint16_t readUint16(const void* aPtr) - { - return read(aPtr); - } - - /** Read a uint32_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT uint32_t readUint32(const void* aPtr) - { - return read(aPtr); - } - - /** Read a uint64_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT uint64_t readUint64(const void* aPtr) - { - return read(aPtr); - } - - /** Read an int16_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT int16_t readInt16(const void* aPtr) - { - return read(aPtr); - } - - /** Read an int32_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT int32_t readInt32(const void* aPtr) - { - return read(aPtr); - } - - /** Read an int64_t in ThisEndian endianness from |aPtr| and return it. */ - static MOZ_WARN_UNUSED_RESULT int64_t readInt64(const void* aPtr) - { - return read(aPtr); - } - - /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeUint16(void* aPtr, uint16_t aValue) - { - write(aPtr, aValue); - } - - /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeUint32(void* aPtr, uint32_t aValue) - { - write(aPtr, aValue); - } - - /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeUint64(void* aPtr, uint64_t aValue) - { - write(aPtr, aValue); - } - - /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeInt16(void* aPtr, int16_t aValue) - { - write(aPtr, aValue); - } - - /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeInt32(void* aPtr, int32_t aValue) - { - write(aPtr, aValue); - } - - /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeInt64(void* aPtr, int64_t aValue) - { - write(aPtr, aValue); - } - - /* - * Converts a value of type T to little-endian format. - * - * This function is intended for cases where you have data in your - * native-endian format and you need it to appear in little-endian - * format for transmission. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapToLittleEndian(T aValue) - { - return maybeSwap(aValue); - } - - /* - * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting - * them to little-endian format if ThisEndian is Big. - * As with memcpy, |aDest| and |aSrc| must not overlap. - */ - template - static void copyAndSwapToLittleEndian(void* aDest, const T* aSrc, - size_t aCount) - { - copyAndSwapTo(aDest, aSrc, aCount); - } - - /* - * Likewise, but converts values in place. - */ - template - static void swapToLittleEndianInPlace(T* aPtr, size_t aCount) - { - maybeSwapInPlace(aPtr, aCount); - } - - /* - * Converts a value of type T to big-endian format. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapToBigEndian(T aValue) - { - return maybeSwap(aValue); - } - - /* - * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting - * them to big-endian format if ThisEndian is Little. - * As with memcpy, |aDest| and |aSrc| must not overlap. - */ - template - static void copyAndSwapToBigEndian(void* aDest, const T* aSrc, - size_t aCount) - { - copyAndSwapTo(aDest, aSrc, aCount); - } - - /* - * Likewise, but converts values in place. - */ - template - static void swapToBigEndianInPlace(T* aPtr, size_t aCount) - { - maybeSwapInPlace(aPtr, aCount); - } - - /* - * Synonyms for the big-endian functions, for better readability - * in network code. - */ - - template - MOZ_WARN_UNUSED_RESULT static T swapToNetworkOrder(T aValue) - { - return swapToBigEndian(aValue); - } - - template - static void - copyAndSwapToNetworkOrder(void* aDest, const T* aSrc, size_t aCount) - { - copyAndSwapToBigEndian(aDest, aSrc, aCount); - } - - template - static void - swapToNetworkOrderInPlace(T* aPtr, size_t aCount) - { - swapToBigEndianInPlace(aPtr, aCount); - } - - /* - * Converts a value of type T from little-endian format. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapFromLittleEndian(T aValue) - { - return maybeSwap(aValue); - } - - /* - * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting - * them to little-endian format if ThisEndian is Big. - * As with memcpy, |aDest| and |aSrc| must not overlap. - */ - template - static void copyAndSwapFromLittleEndian(T* aDest, const void* aSrc, - size_t aCount) - { - copyAndSwapFrom(aDest, aSrc, aCount); - } - - /* - * Likewise, but converts values in place. - */ - template - static void swapFromLittleEndianInPlace(T* aPtr, size_t aCount) - { - maybeSwapInPlace(aPtr, aCount); - } - - /* - * Converts a value of type T from big-endian format. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapFromBigEndian(T aValue) - { - return maybeSwap(aValue); - } - - /* - * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting - * them to big-endian format if ThisEndian is Little. - * As with memcpy, |aDest| and |aSrc| must not overlap. - */ - template - static void copyAndSwapFromBigEndian(T* aDest, const void* aSrc, - size_t aCount) - { - copyAndSwapFrom(aDest, aSrc, aCount); - } - - /* - * Likewise, but converts values in place. - */ - template - static void swapFromBigEndianInPlace(T* aPtr, size_t aCount) - { - maybeSwapInPlace(aPtr, aCount); - } - - /* - * Synonyms for the big-endian functions, for better readability - * in network code. - */ - template - MOZ_WARN_UNUSED_RESULT static T swapFromNetworkOrder(T aValue) - { - return swapFromBigEndian(aValue); - } - - template - static void copyAndSwapFromNetworkOrder(T* aDest, const void* aSrc, - size_t aCount) - { - copyAndSwapFromBigEndian(aDest, aSrc, aCount); - } - - template - static void swapFromNetworkOrderInPlace(T* aPtr, size_t aCount) - { - swapFromBigEndianInPlace(aPtr, aCount); - } - -private: - /** - * Read a value of type T, encoded in endianness ThisEndian from |aPtr|. - * Return that value encoded in native endianness. - */ - template - static T read(const void* aPtr) - { - union - { - T mVal; - uint8_t mBuffer[sizeof(T)]; - } u; - memcpy(u.mBuffer, aPtr, sizeof(T)); - return maybeSwap(u.mVal); - } - - /** - * Write a value of type T, in native endianness, to |aPtr|, in ThisEndian - * endianness. - */ - template - static void write(void* aPtr, T aValue) - { - T tmp = maybeSwap(aValue); - memcpy(aPtr, &tmp, sizeof(T)); - } - - Endian() = delete; - Endian(const Endian& aTther) = delete; - void operator=(const Endian& aOther) = delete; -}; - -template -class EndianReadWrite : public Endian -{ -private: - typedef Endian super; - -public: - using super::readUint16; - using super::readUint32; - using super::readUint64; - using super::readInt16; - using super::readInt32; - using super::readInt64; - using super::writeUint16; - using super::writeUint32; - using super::writeUint64; - using super::writeInt16; - using super::writeInt32; - using super::writeInt64; -}; - -} /* namespace detail */ - -class LittleEndian final : public detail::EndianReadWrite -{}; - -class BigEndian final : public detail::EndianReadWrite -{}; - -typedef BigEndian NetworkEndian; - -class NativeEndian final : public detail::Endian -{ -private: - typedef detail::Endian super; - -public: - /* - * These functions are intended for cases where you have data in your - * native-endian format and you need the data to appear in the appropriate - * endianness for transmission, serialization, etc. - */ - using super::swapToLittleEndian; - using super::copyAndSwapToLittleEndian; - using super::swapToLittleEndianInPlace; - using super::swapToBigEndian; - using super::copyAndSwapToBigEndian; - using super::swapToBigEndianInPlace; - using super::swapToNetworkOrder; - using super::copyAndSwapToNetworkOrder; - using super::swapToNetworkOrderInPlace; - - /* - * These functions are intended for cases where you have data in the - * given endianness (e.g. reading from disk or a file-format) and you - * need the data to appear in native-endian format for processing. - */ - using super::swapFromLittleEndian; - using super::copyAndSwapFromLittleEndian; - using super::swapFromLittleEndianInPlace; - using super::swapFromBigEndian; - using super::copyAndSwapFromBigEndian; - using super::swapFromBigEndianInPlace; - using super::swapFromNetworkOrder; - using super::copyAndSwapFromNetworkOrder; - using super::swapFromNetworkOrderInPlace; -}; - -#undef MOZ_NATIVE_ENDIANNESS - -} /* namespace mozilla */ - -#endif /* mozilla_Endian_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/EndianUtils.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/EndianUtils.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/EndianUtils.h @@ -0,0 +1,695 @@ +/* -*- 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/. */ + +/* Functions for reading and writing integers in various endiannesses. */ + +/* + * The classes LittleEndian and BigEndian expose static methods for + * reading and writing 16-, 32-, and 64-bit signed and unsigned integers + * in their respective endianness. The naming scheme is: + * + * {Little,Big}Endian::{read,write}{Uint,Int} + * + * For instance, LittleEndian::readInt32 will read a 32-bit signed + * integer from memory in little endian format. Similarly, + * BigEndian::writeUint16 will write a 16-bit unsigned integer to memory + * in big-endian format. + * + * The class NativeEndian exposes methods for conversion of existing + * data to and from the native endianness. These methods are intended + * for cases where data needs to be transferred, serialized, etc. + * swap{To,From}{Little,Big}Endian byteswap a single value if necessary. + * Bulk conversion functions are also provided which optimize the + * no-conversion-needed case: + * + * - copyAndSwap{To,From}{Little,Big}Endian; + * - swap{To,From}{Little,Big}EndianInPlace. + * + * The *From* variants are intended to be used for reading data and the + * *To* variants for writing data. + * + * Methods on NativeEndian work with integer data of any type. + * Floating-point data is not supported. + * + * For clarity in networking code, "Network" may be used as a synonym + * for "Big" in any of the above methods or class names. + * + * As an example, reading a file format header whose fields are stored + * in big-endian format might look like: + * + * class ExampleHeader + * { + * private: + * uint32_t mMagic; + * uint32_t mLength; + * uint32_t mTotalRecords; + * uint64_t mChecksum; + * + * public: + * ExampleHeader(const void* data) + * { + * const uint8_t* ptr = static_cast(data); + * mMagic = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); + * mLength = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); + * mTotalRecords = BigEndian::readUint32(ptr); ptr += sizeof(uint32_t); + * mChecksum = BigEndian::readUint64(ptr); + * } + * ... + * }; + */ + +#ifndef mozilla_EndianUtils_h +#define mozilla_EndianUtils_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Compiler.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/TypeTraits.h" + +#include +#include + +#if defined(_MSC_VER) +# include +# pragma intrinsic(_byteswap_ushort) +# pragma intrinsic(_byteswap_ulong) +# pragma intrinsic(_byteswap_uint64) +#endif + +#if defined(_WIN64) +# if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_) +# define MOZ_LITTLE_ENDIAN 1 +# else +# error "CPU type is unknown" +# endif +#elif defined(_WIN32) +# if defined(_M_IX86) +# define MOZ_LITTLE_ENDIAN 1 +# elif defined(_M_ARM) +# define MOZ_LITTLE_ENDIAN 1 +# else +# error "CPU type is unknown" +# endif +#elif defined(__APPLE__) || defined(__powerpc__) || defined(__ppc__) +# if __LITTLE_ENDIAN__ +# define MOZ_LITTLE_ENDIAN 1 +# elif __BIG_ENDIAN__ +# define MOZ_BIG_ENDIAN 1 +# endif +#elif defined(__GNUC__) && \ + defined(__BYTE_ORDER__) && \ + defined(__ORDER_LITTLE_ENDIAN__) && \ + defined(__ORDER_BIG_ENDIAN__) + /* + * Some versions of GCC provide architecture-independent macros for + * this. Yes, there are more than two values for __BYTE_ORDER__. + */ +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define MOZ_LITTLE_ENDIAN 1 +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define MOZ_BIG_ENDIAN 1 +# else +# error "Can't handle mixed-endian architectures" +# endif +/* + * We can't include useful headers like or + * here because they're not present on all platforms. Instead we have + * this big conditional that ideally will catch all the interesting + * cases. + */ +#elif defined(__sparc) || defined(__sparc__) || \ + defined(_POWER) || defined(__hppa) || \ + defined(_MIPSEB) || defined(__ARMEB__) || \ + defined(__s390__) || defined(__AARCH64EB__) || \ + (defined(__sh__) && defined(__LITTLE_ENDIAN__)) || \ + (defined(__ia64) && defined(__BIG_ENDIAN__)) +# define MOZ_BIG_ENDIAN 1 +#elif defined(__i386) || defined(__i386__) || \ + defined(__x86_64) || defined(__x86_64__) || \ + defined(_MIPSEL) || defined(__ARMEL__) || \ + defined(__alpha__) || defined(__AARCH64EL__) || \ + (defined(__sh__) && defined(__BIG_ENDIAN__)) || \ + (defined(__ia64) && !defined(__BIG_ENDIAN__)) +# define MOZ_LITTLE_ENDIAN 1 +#endif + +#if MOZ_BIG_ENDIAN +# define MOZ_LITTLE_ENDIAN 0 +#elif MOZ_LITTLE_ENDIAN +# define MOZ_BIG_ENDIAN 0 +#else +# error "Cannot determine endianness" +#endif + +#if defined(__clang__) +# if __has_builtin(__builtin_bswap16) +# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 +# endif +#elif defined(__GNUC__) +# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 +#elif defined(_MSC_VER) +# define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort +#endif + +namespace mozilla { + +namespace detail { + +/* + * We need wrappers here because free functions with default template + * arguments and/or partial specialization of function templates are not + * supported by all the compilers we use. + */ +template +struct Swapper; + +template +struct Swapper +{ + static T swap(T aValue) + { +#if defined(MOZ_HAVE_BUILTIN_BYTESWAP16) + return MOZ_HAVE_BUILTIN_BYTESWAP16(aValue); +#else + return T(((aValue & 0x00ff) << 8) | ((aValue & 0xff00) >> 8)); +#endif + } +}; + +template +struct Swapper +{ + static T swap(T aValue) + { +#if defined(__clang__) || defined(__GNUC__) + return T(__builtin_bswap32(aValue)); +#elif defined(_MSC_VER) + return T(_byteswap_ulong(aValue)); +#else + return T(((aValue & 0x000000ffU) << 24) | + ((aValue & 0x0000ff00U) << 8) | + ((aValue & 0x00ff0000U) >> 8) | + ((aValue & 0xff000000U) >> 24)); +#endif + } +}; + +template +struct Swapper +{ + static inline T swap(T aValue) + { +#if defined(__clang__) || defined(__GNUC__) + return T(__builtin_bswap64(aValue)); +#elif defined(_MSC_VER) + return T(_byteswap_uint64(aValue)); +#else + return T(((aValue & 0x00000000000000ffULL) << 56) | + ((aValue & 0x000000000000ff00ULL) << 40) | + ((aValue & 0x0000000000ff0000ULL) << 24) | + ((aValue & 0x00000000ff000000ULL) << 8) | + ((aValue & 0x000000ff00000000ULL) >> 8) | + ((aValue & 0x0000ff0000000000ULL) >> 24) | + ((aValue & 0x00ff000000000000ULL) >> 40) | + ((aValue & 0xff00000000000000ULL) >> 56)); +#endif + } +}; + +enum Endianness { Little, Big }; + +#if MOZ_BIG_ENDIAN +# define MOZ_NATIVE_ENDIANNESS detail::Big +#else +# define MOZ_NATIVE_ENDIANNESS detail::Little +#endif + +class EndianUtils +{ + /** + * Assert that the memory regions [aDest, aDest+aCount) and + * [aSrc, aSrc+aCount] do not overlap. aCount is given in bytes. + */ + static void assertNoOverlap(const void* aDest, const void* aSrc, + size_t aCount) + { + DebugOnly byteDestPtr = static_cast(aDest); + DebugOnly byteSrcPtr = static_cast(aSrc); + MOZ_ASSERT((byteDestPtr <= byteSrcPtr && + byteDestPtr + aCount <= byteSrcPtr) || + (byteSrcPtr <= byteDestPtr && + byteSrcPtr + aCount <= byteDestPtr)); + } + + template + static void assertAligned(T* aPtr) + { + MOZ_ASSERT((uintptr_t(aPtr) % sizeof(T)) == 0, "Unaligned pointer!"); + } + +protected: + /** + * Return |aValue| converted from SourceEndian encoding to DestEndian + * encoding. + */ + template + static inline T maybeSwap(T aValue) + { + if (SourceEndian == DestEndian) { + return aValue; + } + return Swapper::swap(aValue); + } + + /** + * Convert |aCount| elements at |aPtr| from SourceEndian encoding to + * DestEndian encoding. + */ + template + static inline void maybeSwapInPlace(T* aPtr, size_t aCount) + { + assertAligned(aPtr); + + if (SourceEndian == DestEndian) { + return; + } + for (size_t i = 0; i < aCount; i++) { + aPtr[i] = Swapper::swap(aPtr[i]); + } + } + + /** + * Write |aCount| elements to the unaligned address |aDest| in DestEndian + * format, using elements found at |aSrc| in SourceEndian format. + */ + template + static void copyAndSwapTo(void* aDest, const T* aSrc, size_t aCount) + { + assertNoOverlap(aDest, aSrc, aCount * sizeof(T)); + assertAligned(aSrc); + + if (SourceEndian == DestEndian) { + memcpy(aDest, aSrc, aCount * sizeof(T)); + return; + } + + uint8_t* byteDestPtr = static_cast(aDest); + for (size_t i = 0; i < aCount; ++i) { + union + { + T mVal; + uint8_t mBuffer[sizeof(T)]; + } u; + u.mVal = maybeSwap(aSrc[i]); + memcpy(byteDestPtr, u.mBuffer, sizeof(T)); + byteDestPtr += sizeof(T); + } + } + + /** + * Write |aCount| elements to |aDest| in DestEndian format, using elements + * found at the unaligned address |aSrc| in SourceEndian format. + */ + template + static void copyAndSwapFrom(T* aDest, const void* aSrc, size_t aCount) + { + assertNoOverlap(aDest, aSrc, aCount * sizeof(T)); + assertAligned(aDest); + + if (SourceEndian == DestEndian) { + memcpy(aDest, aSrc, aCount * sizeof(T)); + return; + } + + const uint8_t* byteSrcPtr = static_cast(aSrc); + for (size_t i = 0; i < aCount; ++i) { + union + { + T mVal; + uint8_t mBuffer[sizeof(T)]; + } u; + memcpy(u.mBuffer, byteSrcPtr, sizeof(T)); + aDest[i] = maybeSwap(u.mVal); + byteSrcPtr += sizeof(T); + } + } +}; + +template +class Endian : private EndianUtils +{ +protected: + /** Read a uint16_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE uint16_t readUint16(const void* aPtr) + { + return read(aPtr); + } + + /** Read a uint32_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE uint32_t readUint32(const void* aPtr) + { + return read(aPtr); + } + + /** Read a uint64_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE uint64_t readUint64(const void* aPtr) + { + return read(aPtr); + } + + /** Read an int16_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE int16_t readInt16(const void* aPtr) + { + return read(aPtr); + } + + /** Read an int32_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE int32_t readInt32(const void* aPtr) + { + return read(aPtr); + } + + /** Read an int64_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE int64_t readInt64(const void* aPtr) + { + return read(aPtr); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeUint16(void* aPtr, uint16_t aValue) + { + write(aPtr, aValue); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeUint32(void* aPtr, uint32_t aValue) + { + write(aPtr, aValue); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeUint64(void* aPtr, uint64_t aValue) + { + write(aPtr, aValue); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeInt16(void* aPtr, int16_t aValue) + { + write(aPtr, aValue); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeInt32(void* aPtr, int32_t aValue) + { + write(aPtr, aValue); + } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeInt64(void* aPtr, int64_t aValue) + { + write(aPtr, aValue); + } + + /* + * Converts a value of type T to little-endian format. + * + * This function is intended for cases where you have data in your + * native-endian format and you need it to appear in little-endian + * format for transmission. + */ + template + MOZ_MUST_USE static T swapToLittleEndian(T aValue) + { + return maybeSwap(aValue); + } + + /* + * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting + * them to little-endian format if ThisEndian is Big. + * As with memcpy, |aDest| and |aSrc| must not overlap. + */ + template + static void copyAndSwapToLittleEndian(void* aDest, const T* aSrc, + size_t aCount) + { + copyAndSwapTo(aDest, aSrc, aCount); + } + + /* + * Likewise, but converts values in place. + */ + template + static void swapToLittleEndianInPlace(T* aPtr, size_t aCount) + { + maybeSwapInPlace(aPtr, aCount); + } + + /* + * Converts a value of type T to big-endian format. + */ + template + MOZ_MUST_USE static T swapToBigEndian(T aValue) + { + return maybeSwap(aValue); + } + + /* + * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting + * them to big-endian format if ThisEndian is Little. + * As with memcpy, |aDest| and |aSrc| must not overlap. + */ + template + static void copyAndSwapToBigEndian(void* aDest, const T* aSrc, + size_t aCount) + { + copyAndSwapTo(aDest, aSrc, aCount); + } + + /* + * Likewise, but converts values in place. + */ + template + static void swapToBigEndianInPlace(T* aPtr, size_t aCount) + { + maybeSwapInPlace(aPtr, aCount); + } + + /* + * Synonyms for the big-endian functions, for better readability + * in network code. + */ + + template + MOZ_MUST_USE static T swapToNetworkOrder(T aValue) + { + return swapToBigEndian(aValue); + } + + template + static void + copyAndSwapToNetworkOrder(void* aDest, const T* aSrc, size_t aCount) + { + copyAndSwapToBigEndian(aDest, aSrc, aCount); + } + + template + static void + swapToNetworkOrderInPlace(T* aPtr, size_t aCount) + { + swapToBigEndianInPlace(aPtr, aCount); + } + + /* + * Converts a value of type T from little-endian format. + */ + template + MOZ_MUST_USE static T swapFromLittleEndian(T aValue) + { + return maybeSwap(aValue); + } + + /* + * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting + * them to little-endian format if ThisEndian is Big. + * As with memcpy, |aDest| and |aSrc| must not overlap. + */ + template + static void copyAndSwapFromLittleEndian(T* aDest, const void* aSrc, + size_t aCount) + { + copyAndSwapFrom(aDest, aSrc, aCount); + } + + /* + * Likewise, but converts values in place. + */ + template + static void swapFromLittleEndianInPlace(T* aPtr, size_t aCount) + { + maybeSwapInPlace(aPtr, aCount); + } + + /* + * Converts a value of type T from big-endian format. + */ + template + MOZ_MUST_USE static T swapFromBigEndian(T aValue) + { + return maybeSwap(aValue); + } + + /* + * Copies |aCount| values of type T starting at |aSrc| to |aDest|, converting + * them to big-endian format if ThisEndian is Little. + * As with memcpy, |aDest| and |aSrc| must not overlap. + */ + template + static void copyAndSwapFromBigEndian(T* aDest, const void* aSrc, + size_t aCount) + { + copyAndSwapFrom(aDest, aSrc, aCount); + } + + /* + * Likewise, but converts values in place. + */ + template + static void swapFromBigEndianInPlace(T* aPtr, size_t aCount) + { + maybeSwapInPlace(aPtr, aCount); + } + + /* + * Synonyms for the big-endian functions, for better readability + * in network code. + */ + template + MOZ_MUST_USE static T swapFromNetworkOrder(T aValue) + { + return swapFromBigEndian(aValue); + } + + template + static void copyAndSwapFromNetworkOrder(T* aDest, const void* aSrc, + size_t aCount) + { + copyAndSwapFromBigEndian(aDest, aSrc, aCount); + } + + template + static void swapFromNetworkOrderInPlace(T* aPtr, size_t aCount) + { + swapFromBigEndianInPlace(aPtr, aCount); + } + +private: + /** + * Read a value of type T, encoded in endianness ThisEndian from |aPtr|. + * Return that value encoded in native endianness. + */ + template + static T read(const void* aPtr) + { + union + { + T mVal; + uint8_t mBuffer[sizeof(T)]; + } u; + memcpy(u.mBuffer, aPtr, sizeof(T)); + return maybeSwap(u.mVal); + } + + /** + * Write a value of type T, in native endianness, to |aPtr|, in ThisEndian + * endianness. + */ + template + static void write(void* aPtr, T aValue) + { + T tmp = maybeSwap(aValue); + memcpy(aPtr, &tmp, sizeof(T)); + } + + Endian() = delete; + Endian(const Endian& aTther) = delete; + void operator=(const Endian& aOther) = delete; +}; + +template +class EndianReadWrite : public Endian +{ +private: + typedef Endian super; + +public: + using super::readUint16; + using super::readUint32; + using super::readUint64; + using super::readInt16; + using super::readInt32; + using super::readInt64; + using super::writeUint16; + using super::writeUint32; + using super::writeUint64; + using super::writeInt16; + using super::writeInt32; + using super::writeInt64; +}; + +} /* namespace detail */ + +class LittleEndian final : public detail::EndianReadWrite +{}; + +class BigEndian final : public detail::EndianReadWrite +{}; + +typedef BigEndian NetworkEndian; + +class NativeEndian final : public detail::Endian +{ +private: + typedef detail::Endian super; + +public: + /* + * These functions are intended for cases where you have data in your + * native-endian format and you need the data to appear in the appropriate + * endianness for transmission, serialization, etc. + */ + using super::swapToLittleEndian; + using super::copyAndSwapToLittleEndian; + using super::swapToLittleEndianInPlace; + using super::swapToBigEndian; + using super::copyAndSwapToBigEndian; + using super::swapToBigEndianInPlace; + using super::swapToNetworkOrder; + using super::copyAndSwapToNetworkOrder; + using super::swapToNetworkOrderInPlace; + + /* + * These functions are intended for cases where you have data in the + * given endianness (e.g. reading from disk or a file-format) and you + * need the data to appear in native-endian format for processing. + */ + using super::swapFromLittleEndian; + using super::copyAndSwapFromLittleEndian; + using super::swapFromLittleEndianInPlace; + using super::swapFromBigEndian; + using super::copyAndSwapFromBigEndian; + using super::swapFromBigEndianInPlace; + using super::swapFromNetworkOrder; + using super::copyAndSwapFromNetworkOrder; + using super::swapFromNetworkOrderInPlace; +}; + +#undef MOZ_NATIVE_ENDIANNESS + +} /* namespace mozilla */ + +#endif /* mozilla_EndianUtils_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/EnumSet.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/EnumSet.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/EnumSet.h @@ -12,6 +12,8 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" +#include + #include namespace mozilla { @@ -27,7 +29,9 @@ public: EnumSet() : mBitField(0) - { } + { + initVersion(); + } MOZ_IMPLICIT EnumSet(T aEnum) : mBitField(bitFor(aEnum)) @@ -36,30 +40,48 @@ EnumSet(T aEnum1, T aEnum2) : mBitField(bitFor(aEnum1) | bitFor(aEnum2)) - { } + { + initVersion(); + } EnumSet(T aEnum1, T aEnum2, T aEnum3) : mBitField(bitFor(aEnum1) | bitFor(aEnum2) | bitFor(aEnum3)) - { } + { + initVersion(); + } EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4) - : mBitField(bitFor(aEnum1) | - bitFor(aEnum2) | - bitFor(aEnum3) | - bitFor(aEnum4)) - { } + : mBitField(bitFor(aEnum1) | + bitFor(aEnum2) | + bitFor(aEnum3) | + bitFor(aEnum4)) + { + initVersion(); + } + + MOZ_IMPLICIT EnumSet(std::initializer_list list) + : mBitField(0) + { + for (auto value : list) { + (*this) += value; + } + initVersion(); + } EnumSet(const EnumSet& aEnumSet) - : mBitField(aEnumSet.mBitField) - { } + : mBitField(aEnumSet.mBitField) + { + initVersion(); + } /** * Add an element */ void operator+=(T aEnum) { + incVersion(); mBitField |= bitFor(aEnum); } @@ -78,6 +100,7 @@ */ void operator+=(const EnumSet aEnumSet) { + incVersion(); mBitField |= aEnumSet.mBitField; } @@ -96,6 +119,7 @@ */ void operator-=(T aEnum) { + incVersion(); mBitField &= ~(bitFor(aEnum)); } @@ -114,6 +138,7 @@ */ void operator-=(const EnumSet aEnumSet) { + incVersion(); mBitField &= ~(aEnumSet.mBitField); } @@ -132,6 +157,7 @@ */ void clear() { + incVersion(); mBitField = 0; } @@ -140,6 +166,7 @@ */ void operator&=(const EnumSet aEnumSet) { + incVersion(); mBitField &= aEnumSet.mBitField; } @@ -172,7 +199,7 @@ /** * Return the number of elements in the set. */ - uint8_t size() + uint8_t size() const { uint8_t count = 0; for (uint32_t bitField = mBitField; bitField; bitField >>= 1) { @@ -195,18 +222,121 @@ void deserialize(uint32_t aValue) { + incVersion(); mBitField = aValue; } + class ConstIterator + { + const EnumSet* mSet; + uint32_t mPos; +#ifdef DEBUG + uint64_t mVersion; +#endif + + void checkVersion() { + // Check that the set has not been modified while being iterated. + MOZ_ASSERT_IF(mSet, mSet->mVersion == mVersion); + } + + public: + ConstIterator(const EnumSet& aSet, uint32_t aPos) + : mSet(&aSet), mPos(aPos) + { +#ifdef DEBUG + mVersion = mSet->mVersion; +#endif + MOZ_ASSERT(aPos <= kMaxBits); + if (aPos != kMaxBits && !mSet->contains(T(mPos))) + ++*this; + } + + ConstIterator(const ConstIterator& aOther) + : mSet(aOther.mSet), mPos(aOther.mPos) + { +#ifdef DEBUG + mVersion = aOther.mVersion; + checkVersion(); +#endif + } + + ConstIterator(ConstIterator&& aOther) + : mSet(aOther.mSet), mPos(aOther.mPos) + { +#ifdef DEBUG + mVersion = aOther.mVersion; + checkVersion(); +#endif + aOther.mSet = nullptr; + } + + ~ConstIterator() { + checkVersion(); + } + + bool operator==(const ConstIterator& other) { + MOZ_ASSERT(mSet == other.mSet); + checkVersion(); + return mPos == other.mPos; + } + + bool operator!=(const ConstIterator& other) { + return !(*this == other); + } + + T operator*() { + MOZ_ASSERT(mSet); + MOZ_ASSERT(mPos < kMaxBits); + MOZ_ASSERT(mSet->contains(T(mPos))); + checkVersion(); + return T(mPos); + } + + ConstIterator& operator++() { + MOZ_ASSERT(mSet); + MOZ_ASSERT(mPos < kMaxBits); + checkVersion(); + do { + mPos++; + } while (mPos < kMaxBits && !mSet->contains(T(mPos))); + return *this; + } + }; + + ConstIterator begin() const { + return ConstIterator(*this, 0); + } + + ConstIterator end() const { + return ConstIterator(*this, kMaxBits); + } + private: static uint32_t bitFor(T aEnum) { uint32_t bitNumber = (uint32_t)aEnum; - MOZ_ASSERT(bitNumber < 32); + MOZ_ASSERT(bitNumber < kMaxBits); return 1U << bitNumber; } + void initVersion() { +#ifdef DEBUG + mVersion = 0; +#endif + } + + void incVersion() { +#ifdef DEBUG + mVersion++; +#endif + } + + static const size_t kMaxBits = 32; uint32_t mBitField; + +#ifdef DEBUG + uint64_t mVersion; +#endif }; } // namespace mozilla Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/EnumTypeTraits.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/EnumTypeTraits.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/EnumTypeTraits.h @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +/* Type traits for enums. */ + +#ifndef mozilla_EnumTypeTraits_h +#define mozilla_EnumTypeTraits_h + +#include + +namespace mozilla { + +namespace detail { + +template +struct EnumFitsWithinHelper; + +// Signed enum, signed storage. +template +struct EnumFitsWithinHelper + : public std::integral_constant +{}; + +// Signed enum, unsigned storage. +template +struct EnumFitsWithinHelper + : public std::integral_constant +{}; + +// Unsigned enum, signed storage. +template +struct EnumFitsWithinHelper + : public std::integral_constant +{}; + +// Unsigned enum, unsigned storage. +template +struct EnumFitsWithinHelper + : public std::integral_constant +{}; + +} // namespace detail + +/* + * Type trait that determines whether the enum type T can fit within the + * integral type Storage without data loss. This trait should be used with + * caution with an enum type whose underlying type has not been explicitly + * specified: for such enums, the C++ implementation is free to choose a type + * no smaller than int whose range encompasses all possible values of the enum. + * So for an enum with only small non-negative values, the underlying type may + * be either int or unsigned int, depending on the whims of the implementation. + */ +template +struct EnumTypeFitsWithin + : public detail::EnumFitsWithinHelper< + sizeof(T), + std::is_signed::type>::value, + sizeof(Storage), + std::is_signed::value + > +{ + static_assert(std::is_enum::value, "must provide an enum type"); + static_assert(std::is_integral::value, "must provide an integral type"); +}; + +} // namespace mozilla + +#endif /* mozilla_EnumTypeTraits_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/EnumeratedArray.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/EnumeratedArray.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/EnumeratedArray.h @@ -10,6 +10,7 @@ #define mozilla_EnumeratedArray_h #include "mozilla/Array.h" +#include "mozilla/Move.h" namespace mozilla { @@ -53,6 +54,11 @@ public: EnumeratedArray() {} + template + MOZ_IMPLICIT EnumeratedArray(Args&&... aArgs) + : mArray{mozilla::Forward(aArgs)...} + {} + explicit EnumeratedArray(const EnumeratedArray& aOther) { for (size_t i = 0; i < kSize; i++) { @@ -60,6 +66,13 @@ } } + EnumeratedArray(EnumeratedArray&& aOther) + { + for (size_t i = 0; i < kSize; i++) { + mArray[i] = Move(aOther.mArray[i]); + } + } + ValueType& operator[](IndexType aIndex) { return mArray[size_t(aIndex)]; Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/EnumeratedRange.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/EnumeratedRange.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/EnumeratedRange.h @@ -20,23 +20,26 @@ #ifndef mozilla_EnumeratedRange_h #define mozilla_EnumeratedRange_h -#include "mozilla/IntegerTypeTraits.h" +#include + #include "mozilla/ReverseIterator.h" namespace mozilla { namespace detail { -template +template class EnumeratedIterator { public: + typedef typename std::underlying_type::type IntTypeT; + template explicit EnumeratedIterator(EnumType aCurrent) : mCurrent(aCurrent) { } - template - explicit EnumeratedIterator(const EnumeratedIterator& aOther) + template + explicit EnumeratedIterator(const EnumeratedIterator& aOther) : mCurrent(aOther.mCurrent) { } EnumTypeT operator*() const { return mCurrent; } @@ -68,77 +71,77 @@ /* Comparison operators */ - template - friend bool operator==(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); - template - friend bool operator!=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); - template - friend bool operator<(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); - template - friend bool operator<=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); - template - friend bool operator>(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); - template - friend bool operator>=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); + template + friend bool operator==(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); + template + friend bool operator!=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); + template + friend bool operator<(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); + template + friend bool operator<=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); + template + friend bool operator>(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); + template + friend bool operator>=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); private: EnumTypeT mCurrent; }; -template -bool operator==(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator==(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent == aIter2.mCurrent; } -template -bool operator!=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator!=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent != aIter2.mCurrent; } -template -bool operator<(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator<(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent < aIter2.mCurrent; } -template -bool operator<=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator<=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent <= aIter2.mCurrent; } -template -bool operator>(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator>(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent > aIter2.mCurrent; } -template -bool operator>=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator>=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent >= aIter2.mCurrent; } -template +template class EnumeratedRange { public: - typedef EnumeratedIterator iterator; - typedef EnumeratedIterator const_iterator; + typedef EnumeratedIterator iterator; + typedef EnumeratedIterator const_iterator; typedef ReverseIterator reverse_iterator; typedef ReverseIterator const_reverse_iterator; @@ -171,38 +174,21 @@ #endif // Create a range to iterate from aBegin to aEnd, exclusive. -// -// (Once we can rely on std::underlying_type, we can remove the IntType -// template parameter.) -template -inline detail::EnumeratedRange +template +inline detail::EnumeratedRange MakeEnumeratedRange(EnumType aBegin, EnumType aEnd) { -#ifdef DEBUG - typedef typename MakeUnsigned::Type UnsignedType; -#endif - static_assert(sizeof(IntType) >= sizeof(EnumType), - "IntType should be at least as big as EnumType!"); MOZ_ASSERT(aBegin <= aEnd, "Cannot generate invalid, unbounded range!"); - MOZ_ASSERT_IF(aBegin < EnumType(0), IsSigned::value); - MOZ_ASSERT_IF(aBegin >= EnumType(0) && IsSigned::value, - UnsignedType(aEnd) <= UnsignedType(MaxValue::value)); - return detail::EnumeratedRange(aBegin, aEnd); + return detail::EnumeratedRange(aBegin, aEnd); } // Create a range to iterate from EnumType(0) to aEnd, exclusive. EnumType(0) // should exist, but note that there is no way for us to ensure that it does! -// Since the enumeration starts at EnumType(0), we know for sure that the values -// will be in range of our deduced IntType. template -inline detail::EnumeratedRange< - typename UnsignedStdintTypeForSize::Type, - EnumType> +inline detail::EnumeratedRange MakeEnumeratedRange(EnumType aEnd) { - return MakeEnumeratedRange< - typename UnsignedStdintTypeForSize::Type>(EnumType(0), - aEnd); + return MakeEnumeratedRange(EnumType(0), aEnd); } #ifdef __GNUC__ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/FastBernoulliTrial.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/FastBernoulliTrial.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/FastBernoulliTrial.h @@ -177,7 +177,10 @@ * random number generator; both may not be zero. */ FastBernoulliTrial(double aProbability, uint64_t aState0, uint64_t aState1) - : mGenerator(aState0, aState1) + : mProbability(0) + , mInvLogNotProbability(0) + , mGenerator(aState0, aState1) + , mSkipCount(0) { setProbability(aProbability); } Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/FloatingPoint.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/FloatingPoint.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/FloatingPoint.h @@ -117,7 +117,7 @@ /** Determines whether a float/double is NaN. */ template -static MOZ_ALWAYS_INLINE MOZ_CONSTEXPR bool +static MOZ_ALWAYS_INLINE bool IsNaN(T aValue) { /* @@ -186,6 +186,18 @@ return bits == Traits::kSignBit; } +/** Determines wether a float/double represents +0. */ +template +static MOZ_ALWAYS_INLINE bool +IsPositiveZero(T aValue) +{ + /* All bits are zero if the value is +0. */ + typedef FloatingPoint Traits; + typedef typename Traits::Bits Bits; + Bits bits = BitwiseCast(aValue); + return bits == 0; +} + /** * Returns 0 if a float/double is NaN or infinite; * otherwise, the float/double is returned. @@ -244,21 +256,65 @@ return BitwiseCast(Traits::kSignBit | Traits::kExponentBits); } +/** + * Computes the bit pattern for a NaN with the specified sign bit and + * significand bits. + */ +template::Bits Significand> +struct SpecificNaNBits +{ + using Traits = FloatingPoint; + + static_assert(SignBit == 0 || SignBit == 1, "bad sign bit"); + static_assert((Significand & ~Traits::kSignificandBits) == 0, + "significand must only have significand bits set"); + static_assert(Significand & Traits::kSignificandBits, + "significand must be nonzero"); -/** Constructs a NaN value with the specified sign bit and significand bits. */ + static constexpr typename Traits::Bits value = + (SignBit * Traits::kSignBit) | Traits::kExponentBits | Significand; +}; + +/** + * Constructs a NaN value with the specified sign bit and significand bits. + * + * There is also a variant that returns the value directly. In most cases, the + * two variants should be identical. However, in the specific case of x86 + * chips, the behavior differs: returning floating-point values directly is done + * through the x87 stack, and x87 loads and stores turn signaling NaNs into + * quiet NaNs... silently. Returning floating-point values via outparam, + * however, is done entirely within the SSE registers when SSE2 floating-point + * is enabled in the compiler, which has semantics-preserving behavior you would + * expect. + * + * If preserving the distinction between signaling NaNs and quiet NaNs is + * important to you, you should use the outparam version. In all other cases, + * you should use the direct return version. + */ template -static MOZ_ALWAYS_INLINE T -SpecificNaN(int signbit, typename FloatingPoint::Bits significand) +static MOZ_ALWAYS_INLINE void +SpecificNaN(int signbit, typename FloatingPoint::Bits significand, T* result) { typedef FloatingPoint Traits; MOZ_ASSERT(signbit == 0 || signbit == 1); MOZ_ASSERT((significand & ~Traits::kSignificandBits) == 0); MOZ_ASSERT(significand & Traits::kSignificandBits); - T t = BitwiseCast((signbit ? Traits::kSignBit : 0) | - Traits::kExponentBits | - significand); - MOZ_ASSERT(IsNaN(t)); + BitwiseCast((signbit ? Traits::kSignBit : 0) | + Traits::kExponentBits | + significand, + result); + MOZ_ASSERT(IsNaN(*result)); +} + +template +static MOZ_ALWAYS_INLINE T +SpecificNaN(int signbit, typename FloatingPoint::Bits significand) +{ + T t; + SpecificNaN(signbit, significand, &t); return t; } @@ -401,13 +457,6 @@ T aEpsilon = detail::FuzzyEqualsEpsilon::value()) { static_assert(IsFloatingPoint::value, "floating point type required"); - - // Short-circuit the common case in order to avoid the expensive operations - // below. - if (aValue1 == aValue2) { - return true; - } - // can't use std::min because of bug 965340 T smaller = Abs(aValue1) < Abs(aValue2) ? Abs(aValue1) : Abs(aValue2); return Abs(aValue1 - aValue2) <= aEpsilon * smaller; @@ -421,7 +470,7 @@ * * This function isn't inlined to avoid buggy optimizations by MSVC. */ -MOZ_WARN_UNUSED_RESULT +MOZ_MUST_USE extern MFBT_API bool IsFloat32Representable(double aFloat32); Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Function.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Function.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Function.h @@ -11,9 +11,10 @@ #include "mozilla/Attributes.h" // for MOZ_IMPLICIT #include "mozilla/Move.h" -#include "mozilla/UniquePtr.h" +#include "mozilla/RefCounted.h" +#include "mozilla/RefPtr.h" -// |Function| is a wrapper that can hold any type of callable +// |function| is a wrapper that can hold any type of callable // object that can be invoked in a way that's compatible with |Signature|. // The standard "type erasure" technique is used to avoid the type of the // wrapper depending on the concrete type of the wrapped callable. @@ -28,7 +29,7 @@ // this is a function type; it's not used in any way other than serving as a // vehicle to encode the return and argument types into a single type. // -// |Function| is default-constructible. A default-constructed instance is +// |function| is default-constructible. A default-constructed instance is // considered "empty". Invoking an empty instance is undefined behaviour. // An empty instance can be populated with a callable by assigning to it. // @@ -40,9 +41,11 @@ namespace detail { template -class FunctionImplBase +class FunctionImplBase : public mozilla::RefCounted> { public: + MOZ_DECLARE_REFCOUNTED_TYPENAME(FunctionImplBase) + virtual ~FunctionImplBase() {} virtual ReturnType call(Arguments... aArguments) = 0; }; @@ -126,32 +129,47 @@ // and |Arguments| in the definition of the specialization without having to // introspect |Signature|. template -class Function; +class function; template -class Function +class function { public: - Function() {} + function() {} // This constructor is implicit to match the interface of |std::function|. template - MOZ_IMPLICIT Function(const Callable& aCallable) - : mImpl(MakeUnique>(aCallable)) + MOZ_IMPLICIT function(const Callable& aCallable) + : mImpl(new detail::FunctionImpl(aCallable)) + {} + MOZ_IMPLICIT function(const function& aFunction) + : mImpl(aFunction.mImpl) + {} + MOZ_IMPLICIT function(decltype(nullptr)) {} // Move constructor and move assingment operator. // These should be generated automatically, but MSVC doesn't do that yet. - Function(Function&& aOther) : mImpl(Move(aOther.mImpl)) {} - Function& operator=(Function&& aOther) { + function(function&& aOther) : mImpl(Move(aOther.mImpl)) {} + function& operator=(function&& aOther) { mImpl = Move(aOther.mImpl); return *this; } template - Function& operator=(const Callable& aCallable) + function& operator=(const Callable& aCallable) { - mImpl = MakeUnique>(aCallable); + mImpl = new detail::FunctionImpl(aCallable); + return *this; + } + function& operator=(const function& aFunction) + { + mImpl = aFunction.mImpl; + return *this; + } + function& operator=(decltype(nullptr)) + { + mImpl = nullptr; return *this; } @@ -161,11 +179,45 @@ MOZ_ASSERT(mImpl); return mImpl->call(Forward(aArguments)...); } + + explicit operator bool() const + { + return bool(mImpl); + } + private: // TODO: Consider implementing a small object optimization. - UniquePtr> mImpl; + RefPtr> mImpl; }; +template +bool +operator==(const function& aX, decltype(nullptr)) +{ + return !aX; +} + +template +bool +operator==(decltype(nullptr), const function& aX) +{ + return !aX; +} + +template +bool +operator!=(const function& aX, decltype(nullptr)) +{ + return bool(aX); +} + +template +bool +operator!=(decltype(nullptr), const function& aX) +{ + return bool(aX); +} + } // namespace mozilla #endif /* mozilla_Function_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/HashFunctions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/HashFunctions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/HashFunctions.h @@ -10,7 +10,7 @@ * This file exports functions for hashing data down to a 32-bit value, * including: * - * - HashString Hash a char* or uint16_t/wchar_t* of known or unknown + * - HashString Hash a char* or char16_t/wchar_t* of known or unknown * length. * * - HashBytes Hash a byte array of known length. @@ -50,6 +50,7 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/Char16.h" +#include "mozilla/MathAlgorithms.h" #include "mozilla/Types.h" #include @@ -156,7 +157,7 @@ * convert to uint32_t, data pointers, and function pointers. */ template -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, A aA) { /* @@ -167,7 +168,7 @@ } template -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, A* aA) { /* @@ -181,14 +182,14 @@ } template<> -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, uintptr_t aA) { return detail::AddUintptrToHash(aHash, aA); } template -MOZ_WARN_UNUSED_RESULT uint32_t +MOZ_MUST_USE uint32_t AddToHash(uint32_t aHash, A aArg, Args... aArgs) { return AddToHash(AddToHash(aHash, aArg), aArgs...); @@ -202,7 +203,7 @@ * that x has already been hashed. */ template -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashGeneric(Args... aArgs) { return AddToHash(0, aArgs...); @@ -240,63 +241,49 @@ * If you have the string's length, you might as well call the overload which * includes the length. It may be marginally faster. */ -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const char* aStr) { return detail::HashUntilZero(reinterpret_cast(aStr)); } -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const char* aStr, size_t aLength) { return detail::HashKnownLength(reinterpret_cast(aStr), aLength); } -MOZ_WARN_UNUSED_RESULT +MOZ_MUST_USE inline uint32_t HashString(const unsigned char* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); } -MOZ_WARN_UNUSED_RESULT inline uint32_t -HashString(const uint16_t* aStr) -{ - return detail::HashUntilZero(aStr); -} - -MOZ_WARN_UNUSED_RESULT inline uint32_t -HashString(const uint16_t* aStr, size_t aLength) -{ - return detail::HashKnownLength(aStr, aLength); -} - -#ifdef MOZ_CHAR16_IS_NOT_WCHAR -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const char16_t* aStr) { return detail::HashUntilZero(aStr); } -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const char16_t* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); } -#endif /* - * On Windows, wchar_t (char16_t) is not the same as uint16_t, even though it's + * On Windows, wchar_t is not the same as char16_t, even though it's * the same width! */ #ifdef WIN32 -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const wchar_t* aStr) { return detail::HashUntilZero(aStr); } -MOZ_WARN_UNUSED_RESULT inline uint32_t +MOZ_MUST_USE inline uint32_t HashString(const wchar_t* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); @@ -309,9 +296,93 @@ * This hash walks word-by-word, rather than byte-by-byte, so you won't get the * same result out of HashBytes as you would out of HashString. */ -MOZ_WARN_UNUSED_RESULT extern MFBT_API uint32_t +MOZ_MUST_USE extern MFBT_API uint32_t HashBytes(const void* bytes, size_t aLength); +/** + * A pseudorandom function mapping 32-bit integers to 32-bit integers. + * + * This is for when you're feeding private data (like pointer values or credit + * card numbers) to a non-crypto hash function (like HashBytes) and then using + * the hash code for something that untrusted parties could observe (like a JS + * Map). Plug in a HashCodeScrambler before that last step to avoid leaking the + * private data. + * + * By itself, this does not prevent hash-flooding DoS attacks, because an + * attacker can still generate many values with exactly equal hash codes by + * attacking the non-crypto hash function alone. Equal hash codes will, of + * course, still be equal however much you scramble them. + * + * The algorithm is SipHash-1-3. See . + */ +class HashCodeScrambler +{ + struct SipHasher; + + uint64_t mK0, mK1; + +public: + /** Creates a new scrambler with the given 128-bit key. */ + constexpr HashCodeScrambler(uint64_t aK0, uint64_t aK1) : mK0(aK0), mK1(aK1) {} + + /** + * Scramble a hash code. Always produces the same result for the same + * combination of key and hash code. + */ + uint32_t scramble(uint32_t aHashCode) const + { + SipHasher hasher(mK0, mK1); + return uint32_t(hasher.sipHash(aHashCode)); + } + +private: + struct SipHasher + { + SipHasher(uint64_t aK0, uint64_t aK1) + { + // 1. Initialization. + mV0 = aK0 ^ UINT64_C(0x736f6d6570736575); + mV1 = aK1 ^ UINT64_C(0x646f72616e646f6d); + mV2 = aK0 ^ UINT64_C(0x6c7967656e657261); + mV3 = aK1 ^ UINT64_C(0x7465646279746573); + } + + uint64_t sipHash(uint64_t aM) + { + // 2. Compression. + mV3 ^= aM; + sipRound(); + mV0 ^= aM; + + // 3. Finalization. + mV2 ^= 0xff; + for (int i = 0; i < 3; i++) + sipRound(); + return mV0 ^ mV1 ^ mV2 ^ mV3; + } + + void sipRound() + { + mV0 += mV1; + mV1 = RotateLeft(mV1, 13); + mV1 ^= mV0; + mV0 = RotateLeft(mV0, 32); + mV2 += mV3; + mV3 = RotateLeft(mV3, 16); + mV3 ^= mV2; + mV0 += mV3; + mV3 = RotateLeft(mV3, 21); + mV3 ^= mV0; + mV2 += mV1; + mV1 = RotateLeft(mV1, 17); + mV1 ^= mV2; + mV2 = RotateLeft(mV2, 32); + } + + uint64_t mV0, mV1, mV2, mV3; + }; +}; + } /* namespace mozilla */ #endif /* __cplusplus */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/IndexSequence.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/IndexSequence.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/IndexSequence.h @@ -74,7 +74,7 @@ template struct IndexSequence { - static MOZ_CONSTEXPR size_t Size() { return sizeof...(Indices); } + static constexpr size_t Size() { return sizeof...(Indices); } }; namespace detail { Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/JSONWriter.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/JSONWriter.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/JSONWriter.h @@ -95,7 +95,7 @@ #include "mozilla/double-conversion.h" #include "mozilla/IntegerPrintfMacros.h" #include "mozilla/PodOperations.h" -#include "mozilla/Snprintf.h" +#include "mozilla/Sprintf.h" #include "mozilla/UniquePtr.h" #include "mozilla/Vector.h" @@ -389,7 +389,7 @@ void IntProperty(const char* aName, int64_t aInt) { char buf[64]; - snprintf_literal(buf, "%" PRId64, aInt); + SprintfLiteral(buf, "%" PRId64, aInt); Scalar(aName, buf); } Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/LinkedList.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/LinkedList.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/LinkedList.h @@ -68,17 +68,65 @@ #include "mozilla/Attributes.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Move.h" +#include "mozilla/RefPtr.h" #ifdef __cplusplus namespace mozilla { template +class LinkedListElement; + +namespace detail { + +/** + * LinkedList supports refcounted elements using this adapter class. Clients + * using LinkedList> will get a data structure that holds a strong + * reference to T as long as T is in the list. + */ +template +struct LinkedListElementTraits +{ + typedef T* RawType; + typedef const T* ConstRawType; + typedef T* ClientType; + typedef const T* ConstClientType; + + // These static methods are called when an element is added to or removed from + // a linked list. It can be used to keep track ownership in lists that are + // supposed to own their elements. If elements are transferred from one list + // to another, no enter or exit calls happen since the elements still belong + // to a list. + static void enterList(LinkedListElement* elt) {} + static void exitList(LinkedListElement* elt) {} +}; + +template +struct LinkedListElementTraits> +{ + typedef T* RawType; + typedef const T* ConstRawType; + typedef RefPtr ClientType; + typedef RefPtr ConstClientType; + + static void enterList(LinkedListElement>* elt) { elt->asT()->AddRef(); } + static void exitList(LinkedListElement>* elt) { elt->asT()->Release(); } +}; + +} /* namespace detail */ + +template class LinkedList; template class LinkedListElement { + typedef typename detail::LinkedListElementTraits Traits; + typedef typename Traits::RawType RawType; + typedef typename Traits::ConstRawType ConstRawType; + typedef typename Traits::ClientType ClientType; + typedef typename Traits::ConstClientType ConstClientType; + /* * It's convenient that we return nullptr when getNext() or getPrevious() * hits the end of the list, but doing so costs an extra word of storage in @@ -125,34 +173,23 @@ mIsSentinel(false) { } - LinkedListElement(LinkedListElement&& other) - : mIsSentinel(other.mIsSentinel) + /* + * Moves |aOther| into |*this|. If |aOther| is already in a list, then + * |aOther| is removed from the list and replaced by |*this|. + */ + LinkedListElement(LinkedListElement&& aOther) + : mIsSentinel(aOther.mIsSentinel) { - if (!other.isInList()) { - mNext = this; - mPrev = this; - return; - } - - MOZ_ASSERT(other.mNext->mPrev == &other); - MOZ_ASSERT(other.mPrev->mNext == &other); - - /* - * Initialize |this| with |other|'s mPrev/mNext pointers, and adjust those - * element to point to this one. - */ - mNext = other.mNext; - mPrev = other.mPrev; - - mNext->mPrev = this; - mPrev->mNext = this; + adjustLinkForMove(Move(aOther)); + } - /* - * Adjust |other| so it doesn't think it's in a list. This makes it - * safely destructable. - */ - other.mNext = &other; - other.mPrev = &other; + LinkedListElement& operator=(LinkedListElement&& aOther) + { + MOZ_ASSERT(mIsSentinel == aOther.mIsSentinel, "Mismatch NodeKind!"); + MOZ_ASSERT(!isInList(), + "Assigning to an element in a list messes up that list!"); + adjustLinkForMove(Move(aOther)); + return *this; } ~LinkedListElement() @@ -166,21 +203,21 @@ * Get the next element in the list, or nullptr if this is the last element * in the list. */ - T* getNext() { return mNext->asT(); } - const T* getNext() const { return mNext->asT(); } + RawType getNext() { return mNext->asT(); } + ConstRawType getNext() const { return mNext->asT(); } /* * Get the previous element in the list, or nullptr if this is the first * element in the list. */ - T* getPrevious() { return mPrev->asT(); } - const T* getPrevious() const { return mPrev->asT(); } + RawType getPrevious() { return mPrev->asT(); } + ConstRawType getPrevious() const { return mPrev->asT(); } /* * Insert aElem after this element in the list. |this| must be part of a * linked list when you call setNext(); otherwise, this method will assert. */ - void setNext(T* aElem) + void setNext(RawType aElem) { MOZ_ASSERT(isInList()); setNextUnsafe(aElem); @@ -191,7 +228,7 @@ * linked list when you call setPrevious(); otherwise, this method will * assert. */ - void setPrevious(T* aElem) + void setPrevious(RawType aElem) { MOZ_ASSERT(isInList()); setPreviousUnsafe(aElem); @@ -209,6 +246,32 @@ mNext->mPrev = mPrev; mNext = this; mPrev = this; + + Traits::exitList(this); + } + + /* + * Remove this element from the list containing it. Returns a pointer to the + * element that follows this element (before it was removed). This method + * asserts if the element does not belong to a list. + */ + ClientType removeAndGetNext() + { + ClientType r = getNext(); + remove(); + return r; + } + + /* + * Remove this element from the list containing it. Returns a pointer to the + * previous element in the containing list (before the removal). This method + * asserts if the element does not belong to a list. + */ + ClientType removeAndGetPrevious() + { + ClientType r = getPrevious(); + remove(); + return r; } /* @@ -232,36 +295,37 @@ private: friend class LinkedList; + friend struct detail::LinkedListElementTraits; - enum NodeKind { - NODE_KIND_NORMAL, - NODE_KIND_SENTINEL + enum class NodeKind { + Normal, + Sentinel }; explicit LinkedListElement(NodeKind nodeKind) : mNext(this), mPrev(this), - mIsSentinel(nodeKind == NODE_KIND_SENTINEL) + mIsSentinel(nodeKind == NodeKind::Sentinel) { } /* * Return |this| cast to T* if we're a normal node, or return nullptr if * we're a sentinel node. */ - T* asT() + RawType asT() { - return mIsSentinel ? nullptr : static_cast(this); + return mIsSentinel ? nullptr : static_cast(this); } - const T* asT() const + ConstRawType asT() const { - return mIsSentinel ? nullptr : static_cast(this); + return mIsSentinel ? nullptr : static_cast(this); } /* * Insert aElem after this element, but don't check that this element is in * the list. This is called by LinkedList::insertFront(). */ - void setNextUnsafe(T* aElem) + void setNextUnsafe(RawType aElem) { LinkedListElement *listElem = static_cast(aElem); MOZ_ASSERT(!listElem->isInList()); @@ -270,13 +334,15 @@ listElem->mPrev = this; this->mNext->mPrev = listElem; this->mNext = listElem; + + Traits::enterList(aElem); } /* * Insert aElem before this element, but don't check that this element is in * the list. This is called by LinkedList::insertBack(). */ - void setPreviousUnsafe(T* aElem) + void setPreviousUnsafe(RawType aElem) { LinkedListElement* listElem = static_cast*>(aElem); MOZ_ASSERT(!listElem->isInList()); @@ -285,9 +351,51 @@ listElem->mPrev = this->mPrev; this->mPrev->mNext = listElem; this->mPrev = listElem; + + Traits::enterList(aElem); + } + + /* + * Adjust mNext and mPrev for implementing move constructor and move + * assignment. + */ + void adjustLinkForMove(LinkedListElement&& aOther) + { + if (!aOther.isInList()) { + mNext = this; + mPrev = this; + return; + } + + if (!mIsSentinel) { + Traits::enterList(this); + } + + MOZ_ASSERT(aOther.mNext->mPrev == &aOther); + MOZ_ASSERT(aOther.mPrev->mNext == &aOther); + + /* + * Initialize |this| with |aOther|'s mPrev/mNext pointers, and adjust those + * element to point to this one. + */ + mNext = aOther.mNext; + mPrev = aOther.mPrev; + + mNext->mPrev = this; + mPrev->mNext = this; + + /* + * Adjust |aOther| so it doesn't think it's in a list. This makes it + * safely destructable. + */ + aOther.mNext = &aOther; + aOther.mPrev = &aOther; + + if (!mIsSentinel) { + Traits::exitList(&aOther); + } } -private: LinkedListElement& operator=(const LinkedListElement& aOther) = delete; LinkedListElement(const LinkedListElement& aOther) = delete; }; @@ -296,16 +404,22 @@ class LinkedList { private: + typedef typename detail::LinkedListElementTraits Traits; + typedef typename Traits::RawType RawType; + typedef typename Traits::ConstRawType ConstRawType; + typedef typename Traits::ClientType ClientType; + typedef typename Traits::ConstClientType ConstClientType; + LinkedListElement sentinel; public: class Iterator { - T* mCurrent; + RawType mCurrent; public: - explicit Iterator(T* aCurrent) : mCurrent(aCurrent) {} + explicit Iterator(RawType aCurrent) : mCurrent(aCurrent) {} - T* operator *() const { + RawType operator *() const { return mCurrent; } @@ -319,18 +433,30 @@ } }; - LinkedList() : sentinel(LinkedListElement::NODE_KIND_SENTINEL) { } + LinkedList() : sentinel(LinkedListElement::NodeKind::Sentinel) { } LinkedList(LinkedList&& aOther) : sentinel(mozilla::Move(aOther.sentinel)) { } - ~LinkedList() { MOZ_ASSERT(isEmpty()); } + LinkedList& operator=(LinkedList&& aOther) + { + MOZ_ASSERT(isEmpty(), "Assigning to a non-empty list leaks elements in that list!"); + sentinel = mozilla::Move(aOther.sentinel); + return *this; + } + + ~LinkedList() { + MOZ_ASSERT(isEmpty(), + "failing this assertion means this LinkedList's creator is " + "buggy: it should have removed all this list's elements before " + "the list's destruction"); + } /* * Add aElem to the front of the list. */ - void insertFront(T* aElem) + void insertFront(RawType aElem) { /* Bypass setNext()'s this->isInList() assertion. */ sentinel.setNextUnsafe(aElem); @@ -339,7 +465,7 @@ /* * Add aElem to the back of the list. */ - void insertBack(T* aElem) + void insertBack(RawType aElem) { sentinel.setPreviousUnsafe(aElem); } @@ -347,24 +473,24 @@ /* * Get the first element of the list, or nullptr if the list is empty. */ - T* getFirst() { return sentinel.getNext(); } - const T* getFirst() const { return sentinel.getNext(); } + RawType getFirst() { return sentinel.getNext(); } + ConstRawType getFirst() const { return sentinel.getNext(); } /* * Get the last element of the list, or nullptr if the list is empty. */ - T* getLast() { return sentinel.getPrevious(); } - const T* getLast() const { return sentinel.getPrevious(); } + RawType getLast() { return sentinel.getPrevious(); } + ConstRawType getLast() const { return sentinel.getPrevious(); } /* * Get and remove the first element of the list. If the list is empty, * return nullptr. */ - T* popFirst() + ClientType popFirst() { - T* ret = sentinel.getNext(); + ClientType ret = sentinel.getNext(); if (ret) { - static_cast*>(ret)->remove(); + static_cast*>(RawType(ret))->remove(); } return ret; } @@ -373,11 +499,11 @@ * Get and remove the last element of the list. If the list is empty, * return nullptr. */ - T* popLast() + ClientType popLast() { - T* ret = sentinel.getPrevious(); + ClientType ret = sentinel.getPrevious(); if (ret) { - static_cast*>(ret)->remove(); + static_cast*>(RawType(ret))->remove(); } return ret; } @@ -498,10 +624,10 @@ private: friend class LinkedListElement; - void assertContains(const T* aValue) const + void assertContains(const RawType aValue) const { #ifdef DEBUG - for (const T* elem = getFirst(); elem; elem = elem->getNext()) { + for (ConstRawType elem = getFirst(); elem; elem = elem->getNext()) { if (elem == aValue) { return; } Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/MacroArgs.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/MacroArgs.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/MacroArgs.h @@ -11,6 +11,10 @@ #ifndef mozilla_MacroArgs_h #define mozilla_MacroArgs_h +// Concatenates pre-processor tokens in a way that can be used with __LINE__. +#define MOZ_CONCAT2(x, y) x ## y +#define MOZ_CONCAT(x, y) MOZ_CONCAT2(x, y) + /* * MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) counts the number of variadic * arguments and prefixes it with |aPrefix|. For example: Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/MathAlgorithms.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/MathAlgorithms.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/MathAlgorithms.h @@ -340,7 +340,7 @@ return detail::CountPopulation32(aValue); } -/** Analogous to CoutPopulation32, but for 64-bit numbers */ +/** Analogous to CountPopulation32, but for 64-bit numbers */ inline uint_fast8_t CountPopulation64(uint64_t aValue) { @@ -515,7 +515,7 @@ * Zero is not an integer power of two. (-Inf is not an integer) */ template -inline bool +constexpr bool IsPowerOfTwo(T x) { static_assert(IsUnsigned::value, Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Maybe.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Maybe.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Maybe.h @@ -16,6 +16,7 @@ #include "mozilla/TypeTraits.h" #include // for placement new +#include namespace mozilla { @@ -101,6 +102,26 @@ } } + /** + * Maybe can be copy-constructed from a Maybe if U* and T* are + * compatible, or from Maybe. + */ + template::value && + (std::is_same::value || + (std::is_pointer::value && + std::is_base_of::type, + typename std::remove_pointer::type>::value))>::type> + MOZ_IMPLICIT + Maybe(const Maybe& aOther) + : mIsSome(false) + { + if (aOther.isSome()) { + emplace(*aOther); + } + } + Maybe(Maybe&& aOther) : mIsSome(false) { @@ -110,6 +131,27 @@ } } + /** + * Maybe can be move-constructed from a Maybe if U* and T* are + * compatible, or from Maybe. + */ + template::value && + (std::is_same::value || + (std::is_pointer::value && + std::is_base_of::type, + typename std::remove_pointer::type>::value))>::type> + MOZ_IMPLICIT + Maybe(Maybe&& aOther) + : mIsSome(false) + { + if (aOther.isSome()) { + emplace(Move(*aOther)); + aOther.reset(); + } + } + Maybe& operator=(const Maybe& aOther) { if (&aOther != this) { @@ -324,53 +366,57 @@ /* If |isSome()|, runs the provided function or functor on the contents of * this Maybe. */ - template - void apply(F&& aFunc, Args&&... aArgs) + template + Maybe& apply(Func aFunc) { if (isSome()) { - aFunc(ref(), Forward(aArgs)...); + aFunc(ref()); } + return *this; } - template - void apply(F&& aFunc, Args&&... aArgs) const + template + const Maybe& apply(Func aFunc) const { if (isSome()) { - aFunc(ref(), Forward(aArgs)...); + aFunc(ref()); } + return *this; } /* * If |isSome()|, runs the provided function and returns the result wrapped * in a Maybe. If |isNothing()|, returns an empty Maybe value. */ - template - Maybe map(R (*aFunc)(T&, FArgs...), Args&&... aArgs) + template + auto map(Func aFunc) -> Maybe>().ref()))> { + using ReturnType = decltype(aFunc(ref())); if (isSome()) { - Maybe val; - val.emplace(aFunc(ref(), Forward(aArgs)...)); + Maybe val; + val.emplace(aFunc(ref())); return val; } - return Maybe(); + return Maybe(); } - template - Maybe map(R (*aFunc)(const T&, FArgs...), Args&&... aArgs) const + template + auto map(Func aFunc) const -> Maybe>().ref()))> { + using ReturnType = decltype(aFunc(ref())); if (isSome()) { - Maybe val; - val.emplace(aFunc(ref(), Forward(aArgs)...)); + Maybe val; + val.emplace(aFunc(ref())); return val; } - return Maybe(); + return Maybe(); } /* If |isSome()|, empties this Maybe and destroys its contents. */ void reset() { if (isSome()) { - ref().~T(); + ref().T::~T(); mIsSome = false; } } Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/NotNull.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/NotNull.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/NotNull.h @@ -0,0 +1,209 @@ +/* -*- 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/. */ + +#ifndef mozilla_NotNull_h +#define mozilla_NotNull_h + +// It's often unclear if a particular pointer, be it raw (T*) or smart +// (RefPtr, nsCOMPtr, etc.) can be null. This leads to missing null +// checks (which can cause crashes) and unnecessary null checks (which clutter +// the code). +// +// C++ has a built-in alternative that avoids these problems: references. This +// module defines another alternative, NotNull, which can be used in cases +// where references are not suitable. +// +// In the comments below we use the word "handle" to cover all varieties of +// pointers and references. +// +// References +// ---------- +// References are always non-null. (You can do |T& r = *p;| where |p| is null, +// but that's undefined behaviour. C++ doesn't provide any built-in, ironclad +// guarantee of non-nullness.) +// +// A reference works well when you need a temporary handle to an existing +// single object, e.g. for passing a handle to a function, or as a local handle +// within another object. (In Rust parlance, this is a "borrow".) +// +// A reference is less appropriate in the following cases. +// +// - As a primary handle to an object. E.g. code such as this is possible but +// strange: |T& t = *new T(); ...; delete &t;| +// +// - As a handle to an array. It's common for |T*| to refer to either a single +// |T| or an array of |T|, but |T&| cannot refer to an array of |T| because +// you can't index off a reference (at least, not without first converting it +// to a pointer). +// +// - When the handle identity is meaningful, e.g. if you have a hashtable of +// handles, because you have to use |&| on the reference to convert it to a +// pointer. +// +// - Some people don't like using non-const references as function parameters, +// because it is not clear at the call site that the argument might be +// modified. +// +// - When you need "smart" behaviour. E.g. we lack reference equivalents to +// RefPtr and nsCOMPtr. +// +// - When interfacing with code that uses pointers a lot, sometimes using a +// reference just feels like an odd fit. +// +// Furthermore, a reference is impossible in the following cases. +// +// - When the handle is rebound to another object. References don't allow this. +// +// - When the handle has type |void|. |void&| is not allowed. +// +// NotNull is an alternative that can be used in any of the above cases except +// for the last one, where the handle type is |void|. See below. + +#include "mozilla/Assertions.h" + +namespace mozilla { + +// NotNull can be used to wrap a "base" pointer (raw or smart) to indicate it +// is not null. Some examples: +// +// - NotNull +// - NotNull> +// - NotNull> +// +// NotNull has the following notable properties. +// +// - It has zero space overhead. +// +// - It must be initialized explicitly. There is no default initialization. +// +// - It auto-converts to the base pointer type. +// +// - It does not auto-convert from a base pointer. Implicit conversion from a +// less-constrained type (e.g. T*) to a more-constrained type (e.g. +// NotNull) is dangerous. Creation and assignment from a base pointer can +// only be done with WrapNotNull(), which makes them impossible to overlook, +// both when writing and reading code. +// +// - When initialized (or assigned) it is checked, and if it is null we abort. +// This guarantees that it cannot be null. +// +// - |operator bool()| is deleted. This means you cannot check a NotNull in a +// boolean context, which eliminates the possibility of unnecessary null +// checks. +// +// NotNull currently doesn't work with UniquePtr. See +// https://github.com/Microsoft/GSL/issues/89 for some discussion. +// +template +class NotNull +{ + template friend NotNull WrapNotNull(U aBasePtr); + + T mBasePtr; + + // This constructor is only used by WrapNotNull(). + template + explicit NotNull(U aBasePtr) : mBasePtr(aBasePtr) {} + +public: + // Disallow default construction. + NotNull() = delete; + + // Construct/assign from another NotNull with a compatible base pointer type. + template + MOZ_IMPLICIT NotNull(const NotNull& aOther) : mBasePtr(aOther.get()) {} + + // Default copy/move construction and assignment. + NotNull(const NotNull&) = default; + NotNull& operator=(const NotNull&) = default; + NotNull(NotNull&&) = default; + NotNull& operator=(NotNull&&) = default; + + // Disallow null checks, which are unnecessary for this type. + explicit operator bool() const = delete; + + // Explicit conversion to a base pointer. Use only to resolve ambiguity or to + // get a castable pointer. + const T& get() const { return mBasePtr; } + + // Implicit conversion to a base pointer. Preferable to get(). + operator const T&() const { return get(); } + + // Dereference operators. + const T& operator->() const { return get(); } + decltype(*mBasePtr) operator*() const { return *mBasePtr; } +}; + +template +NotNull +WrapNotNull(const T aBasePtr) +{ + NotNull notNull(aBasePtr); + MOZ_RELEASE_ASSERT(aBasePtr); + return notNull; +} + +// Compare two NotNulls. +template +inline bool +operator==(const NotNull& aLhs, const NotNull& aRhs) +{ + return aLhs.get() == aRhs.get(); +} +template +inline bool +operator!=(const NotNull& aLhs, const NotNull& aRhs) +{ + return aLhs.get() != aRhs.get(); +} + +// Compare a NotNull to a base pointer. +template +inline bool +operator==(const NotNull& aLhs, const U& aRhs) +{ + return aLhs.get() == aRhs; +} +template +inline bool +operator!=(const NotNull& aLhs, const U& aRhs) +{ + return aLhs.get() != aRhs; +} + +// Compare a base pointer to a NotNull. +template +inline bool +operator==(const T& aLhs, const NotNull& aRhs) +{ + return aLhs == aRhs.get(); +} +template +inline bool +operator!=(const T& aLhs, const NotNull& aRhs) +{ + return aLhs != aRhs.get(); +} + +// Disallow comparing a NotNull to a nullptr. +template +bool +operator==(const NotNull&, decltype(nullptr)) = delete; +template +bool +operator!=(const NotNull&, decltype(nullptr)) = delete; + +// Disallow comparing a nullptr to a NotNull. +template +bool +operator==(decltype(nullptr), const NotNull&) = delete; +template +bool +operator!=(decltype(nullptr), const NotNull&) = delete; + +} // namespace mozilla + +#endif /* mozilla_NotNull_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/NumericLimits.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/NumericLimits.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/NumericLimits.h @@ -1,40 +0,0 @@ -/* -*- 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/. */ - -/* Compatibility with std::numeric_limits. */ - -#ifndef mozilla_NumericLimits_h -#define mozilla_NumericLimits_h - -#include "mozilla/Char16.h" - -#include -#include - -namespace mozilla { - -/** - * The NumericLimits class provides a compatibility layer with - * std::numeric_limits for char16_t, otherwise it is exactly the same as - * std::numeric_limits. Code which does not need std::numeric_limits - * should avoid using NumericLimits. - */ -template -class NumericLimits : public std::numeric_limits -{ -}; - -#ifdef MOZ_CHAR16_IS_NOT_WCHAR -template<> -class NumericLimits : public std::numeric_limits -{ - // char16_t and uint16_t numeric limits should be exactly the same. -}; -#endif - -} // namespace mozilla - -#endif /* mozilla_NumericLimits_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/OperatorNewExtensions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/OperatorNewExtensions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/OperatorNewExtensions.h @@ -0,0 +1,52 @@ +/* -*- 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 version of |operator new| that eschews mandatory null-checks. */ + +#ifndef mozilla_OperatorNewExtensions_h +#define mozilla_OperatorNewExtensions_h + +#include "mozilla/Assertions.h" + +// Credit goes to WebKit for this implementation, cf. +// https://bugs.webkit.org/show_bug.cgi?id=74676 +namespace mozilla { +enum NotNullTag { + KnownNotNull, +}; +} // namespace mozilla + +/* + * The logic here is a little subtle. [expr.new] states that if the allocation + * function being called returns null, then object initialization must not be + * done, and the entirety of the new expression must return null. Non-throwing + * (noexcept) functions are defined to return null to indicate failure. The + * standard placement operator new is defined in such a way, and so it requires + * a null check, even when that null check would be extraneous. Functions + * declared without such a specification are defined to throw std::bad_alloc if + * they fail, and return a non-null pointer otherwise. We compile without + * exceptions, so any placement new overload we define that doesn't declare + * itself as noexcept must therefore avoid generating a null check. Below is + * just such an overload. + * + * You might think that MOZ_NONNULL might perform the same function, but + * MOZ_NONNULL isn't supported on all of our compilers, and even when it is + * supported, doesn't work on all the versions we support. And even keeping + * those limitations in mind, we can't put MOZ_NONNULL on the global, + * standardized placement new function in any event. + * + * We deliberately don't add MOZ_NONNULL(3) to tag |p| as non-null, to benefit + * hypothetical static analyzers. Doing so makes |MOZ_ASSERT(p)|'s internal + * test vacuous, and some compilers warn about such vacuous tests. + */ +inline void* +operator new(size_t, mozilla::NotNullTag, void* p) +{ + MOZ_ASSERT(p); + return p; +} + +#endif // mozilla_OperatorNewExtensions_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Poison.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Poison.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Poison.h @@ -59,4 +59,50 @@ MOZ_END_EXTERN_C +#if defined(__cplusplus) + +namespace mozilla { + +/** + * This class is designed to cause crashes when various kinds of memory + * corruption are observed. For instance, let's say we have a class C where we + * suspect out-of-bounds writes to some members. We can insert a member of type + * Poison near the members we suspect are being corrupted by out-of-bounds + * writes. Or perhaps we have a class K we suspect is subject to use-after-free + * violations, in which case it doesn't particularly matter where in the class + * we add the member of type Poison. + * + * In either case, we then insert calls to Check() throughout the code. Doing + * so enables us to narrow down the location where the corruption is occurring. + * A pleasant side-effect of these additional Check() calls is that crash + * signatures may become more regular, as crashes will ideally occur + * consolidated at the point of a Check(), rather than scattered about at + * various uses of the corrupted memory. + */ +class CorruptionCanary { +public: + CorruptionCanary() { + mValue = kCanarySet; + } + + ~CorruptionCanary() { + Check(); + mValue = mozPoisonValue(); + } + + void Check() const { + if (mValue != kCanarySet) { + MOZ_CRASH("Canary check failed, check lifetime"); + } + } + +private: + static const uintptr_t kCanarySet = 0x0f0b0f0b; + uintptr_t mValue; +}; + +} // mozilla + +#endif + #endif /* mozilla_Poison_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Range.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Range.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Range.h @@ -8,6 +8,7 @@ #define mozilla_Range_h #include "mozilla/RangedPtr.h" +#include "mozilla/TypeTraits.h" #include @@ -26,8 +27,24 @@ : mStart(aPtr, aPtr, aPtr + aLength), mEnd(aPtr + aLength, aPtr, aPtr + aLength) {} + Range(const RangedPtr& aStart, const RangedPtr& aEnd) + : mStart(aStart.get(), aStart.get(), aEnd.get()), + mEnd(aEnd.get(), aStart.get(), aEnd.get()) + { + // Only accept two RangedPtrs within the same range. + aStart.checkIdenticalRange(aEnd); + MOZ_ASSERT(aStart <= aEnd); + } + + template::value, + int>::Type> + MOZ_IMPLICIT Range(const Range& aOther) + : mStart(aOther.mStart), + mEnd(aOther.mEnd) + {} - RangedPtr start() const { return mStart; } + RangedPtr begin() const { return mStart; } RangedPtr end() const { return mEnd; } size_t length() const { return mEnd - mStart; } Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/RangedPtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/RangedPtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/RangedPtr.h @@ -117,6 +117,12 @@ explicit operator bool() const { return mPtr != nullptr; } + void checkIdenticalRange(const RangedPtr& aOther) const + { + MOZ_ASSERT(mRangeStart == aOther.mRangeStart); + MOZ_ASSERT(mRangeEnd == aOther.mRangeEnd); + } + /* * You can only assign one RangedPtr into another if the two pointers have * the same valid range: @@ -129,21 +135,20 @@ */ RangedPtr& operator=(const RangedPtr& aOther) { - MOZ_ASSERT(mRangeStart == aOther.mRangeStart); - MOZ_ASSERT(mRangeEnd == aOther.mRangeEnd); + checkIdenticalRange(aOther); mPtr = aOther.mPtr; checkSanity(); return *this; } - RangedPtr operator+(size_t aInc) + RangedPtr operator+(size_t aInc) const { MOZ_ASSERT(aInc <= size_t(-1) / sizeof(T)); MOZ_ASSERT(asUintptr() + aInc * sizeof(T) >= asUintptr()); return create(mPtr + aInc); } - RangedPtr operator-(size_t aDec) + RangedPtr operator-(size_t aDec) const { MOZ_ASSERT(aDec <= size_t(-1) / sizeof(T)); MOZ_ASSERT(asUintptr() - aDec * sizeof(T) <= asUintptr()); @@ -220,6 +225,13 @@ return *mPtr; } + T* operator->() const + { + MOZ_ASSERT(mPtr >= mRangeStart); + MOZ_ASSERT(mPtr < mRangeEnd); + return mPtr; + } + template bool operator==(const RangedPtr& aOther) const { Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/RefCounted.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/RefCounted.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/RefCounted.h @@ -22,7 +22,6 @@ #endif #if defined(MOZILLA_INTERNAL_API) && \ - !defined(MOZILLA_XPCOMRT_API) && \ (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING)) #define MOZ_REFCOUNTED_LEAK_CHECKING #endif Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/RefPtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/RefPtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/RefPtr.h @@ -19,6 +19,28 @@ namespace mozilla { template class OwningNonNull; +template class StaticRefPtr; + +// Traditionally, RefPtr supports automatic refcounting of any pointer type +// with AddRef() and Release() methods that follow the traditional semantics. +// +// This traits class can be specialized to operate on other pointer types. For +// example, we specialize this trait for opaque FFI types that represent +// refcounted objects in Rust. +// +// Given the use of ConstRemovingRefPtrTraits below, U should not be a const- +// qualified type. +template +struct RefPtrTraits +{ + static void AddRef(U* aPtr) { + aPtr->AddRef(); + } + static void Release(U* aPtr) { + aPtr->Release(); + } +}; + } // namespace mozilla template @@ -29,7 +51,7 @@ assign_with_AddRef(T* aRawPtr) { if (aRawPtr) { - AddRefTraits::AddRef(aRawPtr); + ConstRemovingRefPtrTraits::AddRef(aRawPtr); } assign_assuming_AddRef(aRawPtr); } @@ -40,7 +62,7 @@ T* oldPtr = mRawPtr; mRawPtr = aNewPtr; if (oldPtr) { - AddRefTraits::Release(oldPtr); + ConstRemovingRefPtrTraits::Release(oldPtr); } } @@ -53,14 +75,14 @@ ~RefPtr() { if (mRawPtr) { - AddRefTraits::Release(mRawPtr); + ConstRemovingRefPtrTraits::Release(mRawPtr); } } // Constructors RefPtr() - : mRawPtr(0) + : mRawPtr(nullptr) // default constructor { } @@ -70,7 +92,7 @@ // copy-constructor { if (mRawPtr) { - AddRefTraits::AddRef(mRawPtr); + ConstRemovingRefPtrTraits::AddRef(mRawPtr); } } @@ -86,10 +108,15 @@ : mRawPtr(aRawPtr) { if (mRawPtr) { - AddRefTraits::AddRef(mRawPtr); + ConstRemovingRefPtrTraits::AddRef(mRawPtr); } } + MOZ_IMPLICIT RefPtr(decltype(nullptr)) + : mRawPtr(nullptr) + { + } + template MOZ_IMPLICIT RefPtr(already_AddRefed& aSmartPtr) : mRawPtr(aSmartPtr.take()) @@ -110,7 +137,7 @@ // copy-construct from a smart pointer with a related pointer type { if (mRawPtr) { - AddRefTraits::AddRef(mRawPtr); + ConstRemovingRefPtrTraits::AddRef(mRawPtr); } } @@ -127,9 +154,20 @@ template MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull& aOther); + // Defined in StaticPtr.h + template + MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr& aOther); + // Assignment operators RefPtr& + operator=(decltype(nullptr)) + { + assign_assuming_AddRef(nullptr); + return *this; + } + + RefPtr& operator=(const RefPtr& aRhs) // copy assignment operator { @@ -187,6 +225,11 @@ RefPtr& operator=(const mozilla::OwningNonNull& aOther); + // Defined in StaticPtr.h + template + RefPtr& + operator=(const mozilla::StaticRefPtr& aOther); + // Other pointer operators void @@ -212,7 +255,7 @@ // return the value of mRawPtr and null out mRawPtr. Useful for // already_AddRefed return values. { - T* temp = 0; + T* temp = nullptr; swap(temp); return already_AddRefed(temp); } @@ -227,7 +270,7 @@ { MOZ_ASSERT(aRhs, "Null pointer passed to forget!"); *aRhs = mRawPtr; - mRawPtr = 0; + mRawPtr = nullptr; } T* @@ -272,7 +315,7 @@ T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { - MOZ_ASSERT(mRawPtr != 0, + MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL RefPtr with operator->()."); return get(); } @@ -299,7 +342,7 @@ template Proxy operator->*(R (T::*aFptr)(Args...)) const { - MOZ_ASSERT(mRawPtr != 0, + MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL RefPtr with operator->*()."); return Proxy(get(), aFptr); } @@ -324,7 +367,7 @@ T& operator*() const { - MOZ_ASSERT(mRawPtr != 0, + MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL RefPtr with operator*()."); return *get(); } @@ -332,7 +375,7 @@ T** StartAssignment() { - assign_assuming_AddRef(0); + assign_assuming_AddRef(nullptr); return reinterpret_cast(&mRawPtr); } private: @@ -346,40 +389,24 @@ // This should be sound because while |RefPtr| provides a // const view of an object, the object itself should not be const (it // would have to be allocated as |new const T| or similar to be const). - - // Because some classes make their AddRef/Release implementations private - // and then friend RefPtr to make them visible, we redirect AddRefTraits's - // calls to static helper functions in RefPtr so we don't have to figure - // out how to make AddRefTraits visible to *those* classes. - static MOZ_ALWAYS_INLINE void - AddRefTraitsAddRefHelper(typename mozilla::RemoveConst::Type* aPtr) - { - aPtr->AddRef(); - } - static MOZ_ALWAYS_INLINE void - AddRefTraitsReleaseHelper(typename mozilla::RemoveConst::Type* aPtr) - { - aPtr->Release(); - } - template - struct AddRefTraits + struct ConstRemovingRefPtrTraits { static void AddRef(U* aPtr) { - RefPtr::AddRefTraitsAddRefHelper(aPtr); + mozilla::RefPtrTraits::AddRef(aPtr); } static void Release(U* aPtr) { - RefPtr::AddRefTraitsReleaseHelper(aPtr); + mozilla::RefPtrTraits::Release(aPtr); } }; template - struct AddRefTraits + struct ConstRemovingRefPtrTraits { static void AddRef(const U* aPtr) { - RefPtr::AddRefTraitsAddRefHelper(const_cast(aPtr)); + mozilla::RefPtrTraits::AddRef(const_cast(aPtr)); } static void Release(const U* aPtr) { - RefPtr::AddRefTraitsReleaseHelper(const_cast(aPtr)); + mozilla::RefPtrTraits::Release(const_cast(aPtr)); } }; }; @@ -591,7 +618,15 @@ template inline already_AddRefed -do_AddRef(T*&& aObj) +do_AddRef(T* aObj) +{ + RefPtr ref(aObj); + return ref.forget(); +} + +template +inline already_AddRefed +do_AddRef(const RefPtr& aObj) { RefPtr ref(aObj); return ref.forget(); Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Saturate.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Saturate.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Saturate.h @@ -0,0 +1,288 @@ +/* -*- 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/. */ + +/* Provides saturation arithmetics for scalar types. */ + +#ifndef mozilla_Saturate_h +#define mozilla_Saturate_h + +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" +#include "mozilla/TypeTraits.h" + +#include + +namespace mozilla { +namespace detail { + +/** + * |SaturateOp| wraps scalar values for saturation arithmetics. Usage: + * + * uint32_t value = 1; + * + * ++SaturateOp(value); // value is 2 + * --SaturateOp(value); // value is 1 + * --SaturateOp(value); // value is 0 + * --SaturateOp(value); // value is still 0 + * + * Please add new operators when required. + * + * |SaturateOp| will saturate at the minimum and maximum values of + * type T. If you need other bounds, implement a clamped-type class and + * specialize the type traits accordingly. + */ +template +class SaturateOp +{ +public: + explicit SaturateOp(T& aValue) + : mValue(aValue) + { + // We should actually check for |std::is_scalar::value| to be + // true, but this type trait is not available everywhere. Relax + // this assertion if you want to use floating point values as well. + static_assert(IsIntegral::value, + "Integral type required in instantiation"); + } + + // Add and subtract operators + + T operator+(const T& aRhs) const + { + return T(mValue) += aRhs; + } + + T operator-(const T& aRhs) const + { + return T(mValue) -= aRhs; + } + + // Compound operators + + const T& operator+=(const T& aRhs) const + { + const T min = std::numeric_limits::min(); + const T max = std::numeric_limits::max(); + + if (aRhs > static_cast(0)) { + mValue = (max - aRhs) < mValue ? max : mValue + aRhs; + } else { + mValue = (min - aRhs) > mValue ? min : mValue + aRhs; + } + return mValue; + } + + const T& operator-=(const T& aRhs) const + { + const T min = std::numeric_limits::min(); + const T max = std::numeric_limits::max(); + + if (aRhs > static_cast(0)) { + mValue = (min + aRhs) > mValue ? min : mValue - aRhs; + } else { + mValue = (max + aRhs) < mValue ? max : mValue - aRhs; + } + return mValue; + } + + // Increment and decrement operators + + const T& operator++() const // prefix + { + return operator+=(static_cast(1)); + } + + T operator++(int) const // postfix + { + const T value(mValue); + operator++(); + return value; + } + + const T& operator--() const // prefix + { + return operator-=(static_cast(1)); + } + + T operator--(int) const // postfix + { + const T value(mValue); + operator--(); + return value; + } + +private: + SaturateOp(const SaturateOp&) = delete; + SaturateOp(SaturateOp&&) = delete; + SaturateOp& operator=(const SaturateOp&) = delete; + SaturateOp& operator=(SaturateOp&&) = delete; + + T& mValue; +}; + +/** + * |Saturate| is a value type for saturation arithmetics. It's + * build on top of |SaturateOp|. + */ +template +class Saturate +{ +public: + Saturate() = default; + MOZ_IMPLICIT Saturate(const Saturate&) = default; + + MOZ_IMPLICIT Saturate(Saturate&& aValue) + { + mValue = Move(aValue.mValue); + } + + explicit Saturate(const T& aValue) + : mValue(aValue) + { } + + const T& value() const + { + return mValue; + } + + // Compare operators + + bool operator==(const Saturate& aRhs) const + { + return mValue == aRhs.mValue; + } + + bool operator!=(const Saturate& aRhs) const + { + return !operator==(aRhs); + } + + bool operator==(const T& aRhs) const + { + return mValue == aRhs; + } + + bool operator!=(const T& aRhs) const + { + return !operator==(aRhs); + } + + // Assignment operators + + Saturate& operator=(const Saturate&) = default; + + Saturate& operator=(Saturate&& aRhs) + { + mValue = Move(aRhs.mValue); + return *this; + } + + // Add and subtract operators + + Saturate operator+(const Saturate& aRhs) const + { + Saturate lhs(mValue); + return lhs += aRhs.mValue; + } + + Saturate operator+(const T& aRhs) const + { + Saturate lhs(mValue); + return lhs += aRhs; + } + + Saturate operator-(const Saturate& aRhs) const + { + Saturate lhs(mValue); + return lhs -= aRhs.mValue; + } + + Saturate operator-(const T& aRhs) const + { + Saturate lhs(mValue); + return lhs -= aRhs; + } + + // Compound operators + + Saturate& operator+=(const Saturate& aRhs) + { + SaturateOp(mValue) += aRhs.mValue; + return *this; + } + + Saturate& operator+=(const T& aRhs) + { + SaturateOp(mValue) += aRhs; + return *this; + } + + Saturate& operator-=(const Saturate& aRhs) + { + SaturateOp(mValue) -= aRhs.mValue; + return *this; + } + + Saturate& operator-=(const T& aRhs) + { + SaturateOp(mValue) -= aRhs; + return *this; + } + + // Increment and decrement operators + + Saturate& operator++() // prefix + { + ++SaturateOp(mValue); + return *this; + } + + Saturate operator++(int) // postfix + { + return Saturate(SaturateOp(mValue)++); + } + + Saturate& operator--() // prefix + { + --SaturateOp(mValue); + return *this; + } + + Saturate operator--(int) // postfix + { + return Saturate(SaturateOp(mValue)--); + } + +private: + T mValue; +}; + +} // namespace detail + +typedef detail::Saturate SaturateInt8; +typedef detail::Saturate SaturateInt16; +typedef detail::Saturate SaturateInt32; +typedef detail::Saturate SaturateUint8; +typedef detail::Saturate SaturateUint16; +typedef detail::Saturate SaturateUint32; + +} // namespace mozilla + +template +bool +operator==(LhsT aLhs, const mozilla::detail::Saturate& aRhs) +{ + return aRhs.operator==(static_cast(aLhs)); +} + +template +bool +operator!=(LhsT aLhs, const mozilla::detail::Saturate& aRhs) +{ + return !(aLhs == aRhs); +} + +#endif // mozilla_Saturate_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Scoped.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Scoped.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Scoped.h @@ -15,20 +15,16 @@ * Resource Acquisition Is Initialization is a programming idiom used * to write robust code that is able to deallocate resources properly, * even in presence of execution errors or exceptions that need to be - * propagated. The Scoped* classes defined in this header perform the + * propagated. The Scoped* classes defined via the |SCOPED_TEMPLATE| + * and |MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLTE| macros perform the * deallocation of the resource they hold once program execution * reaches the end of the scope for which they have been defined. + * These macros have been used to automatically close file + * descriptors/file handles when reaching the end of the scope, + * graphics contexts, etc. * - * This header provides the following RAII classes: - * - * - |ScopedFreePtr| - a container for a pointer, that automatically calls - * |free()| at the end of the scope; - * - |ScopedDeletePtr| - a container for a pointer, that automatically calls - * |delete| at the end of the scope; - * - * |ScopedDeleteArray| is removed in favor of |UniquePtr|. - * - * The general scenario for each of the RAII classes is the following: + * The general scenario for RAII classes created by the above macros + * is the following: * * ScopedClass foo(create_value()); * // ... In this scope, |foo| is defined. Use |foo.get()| or |foo.rwget()| @@ -44,14 +40,6 @@ * the end of the scope; * - if |forget()| has been called, any control on the resource is unbound * and the resource is not deallocated by the class. - * - * Extension: - * - * In addition, this header provides class |Scoped| and macros |SCOPED_TEMPLATE| - * and |MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE| to simplify the definition - * of RAII classes for other scenarios. These macros have been used to - * automatically close file descriptors/file handles when reaching the end of - * the scope, graphics contexts, etc. */ #include "mozilla/Assertions.h" @@ -220,35 +208,6 @@ }; /* - * ScopedFreePtr is a RAII wrapper for pointers that need to be free()d. - * - * struct S { ... }; - * ScopedFreePtr foo = malloc(sizeof(S)); - * ScopedFreePtr bar = strdup(str); - */ -template -struct ScopedFreePtrTraits -{ - typedef T* type; - static T* empty() { return nullptr; } - static void release(T* aPtr) { free(aPtr); } -}; -SCOPED_TEMPLATE(ScopedFreePtr, ScopedFreePtrTraits) - -/* - * ScopedDeletePtr is a RAII wrapper for pointers that need to be deleted. - * - * struct S { ... }; - * ScopedDeletePtr foo = new S(); - */ -template -struct ScopedDeletePtrTraits : public ScopedFreePtrTraits -{ - static void release(T* aPtr) { delete aPtr; } -}; -SCOPED_TEMPLATE(ScopedDeletePtr, ScopedDeletePtrTraits) - -/* * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE makes it easy to create scoped * pointers for types with custom deleters; just overload * TypeSpecificDelete(T*) in the same namespace as T to call the deleter for Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/SegmentedVector.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/SegmentedVector.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/SegmentedVector.h @@ -159,7 +159,7 @@ // Returns false if the allocation failed. (If you are using an infallible // allocation policy, use InfallibleAppend() instead.) template - MOZ_WARN_UNUSED_RESULT bool Append(U&& aU) + MOZ_MUST_USE bool Append(U&& aU) { Segment* last = mSegments.getLast(); if (!last || last->Length() == kSegmentCapacity) { @@ -218,6 +218,56 @@ } } + // Equivalent to calling |PopLast| |aNumElements| times, but potentially + // more efficient. + void PopLastN(uint32_t aNumElements) + { + MOZ_ASSERT(aNumElements <= Length()); + + Segment* last; + + // Pop full segments for as long as we can. Note that this loop + // cleanly handles the case when the initial last segment is not + // full and we are popping more elements than said segment contains. + do { + last = mSegments.getLast(); + + // The list is empty. We're all done. + if (!last) { + return; + } + + // Check to see if the list contains too many elements. Handle + // that in the epilogue. + uint32_t segmentLen = last->Length(); + if (segmentLen > aNumElements) { + break; + } + + // Destroying the segment destroys all elements contained therein. + mSegments.popLast(); + last->~Segment(); + this->free_(last); + + MOZ_ASSERT(aNumElements >= segmentLen); + aNumElements -= segmentLen; + if (aNumElements == 0) { + return; + } + } while (true); + + // Handle the case where the last segment contains more elements + // than we want to pop. + MOZ_ASSERT(last); + MOZ_ASSERT(last == mSegments.getLast()); + MOZ_ASSERT(aNumElements != 0); + MOZ_ASSERT(aNumElements < last->Length()); + for (uint32_t i = 0; i < aNumElements; ++i) { + last->PopLast(); + } + MOZ_ASSERT(last->Length() != 0); + } + // Use this class to iterate over a SegmentedVector, like so: // // for (auto iter = v.Iter(); !iter.Done(); iter.Next()) { Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Snprintf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Snprintf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Snprintf.h @@ -1,50 +0,0 @@ -/* -*- 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/. */ - -/* Polyfills snprintf() on platforms that don't provide it, and provides - * related utilities. */ - -#ifndef mozilla_Snprintf_h_ -#define mozilla_Snprintf_h_ - -#include -#include -#include - -// Older MSVC versions do not provide snprintf(), but they do provide -// vsnprintf(), which has the same semantics except that if the number of -// characters written equals the buffer size, it does not write a null -// terminator, so we wrap it to do so. -#if defined(_MSC_VER) && _MSC_VER < 1900 -#include "mozilla/Attributes.h" -MOZ_ALWAYS_INLINE int snprintf(char* buffer, size_t n, const char* format, ...) -{ - va_list args; - va_start(args, format); - int result = vsnprintf(buffer, n, format, args); - va_end(args); - buffer[n - 1] = '\0'; - return result; -} -#endif - -// In addition, in C++ code, on all platforms, provide an snprintf_literal() -// function which uses template argument deduction to deduce the size of the -// buffer, avoiding the need for the user to pass it in explicitly. -#ifdef __cplusplus -template -int snprintf_literal(char (&buffer)[N], const char* format, ...) -{ - va_list args; - va_start(args, format); - int result = vsnprintf(buffer, N, format, args); - va_end(args); - buffer[N - 1] = '\0'; - return result; -} -#endif - -#endif /* mozilla_Snprintf_h_ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/SplayTree.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/SplayTree.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/SplayTree.h @@ -56,7 +56,7 @@ T* mRoot; public: - MOZ_CONSTEXPR SplayTree() + constexpr SplayTree() : mRoot(nullptr) {} @@ -76,19 +76,19 @@ return Comparator::compare(aValue, *last) == 0 ? last : nullptr; } - bool insert(T* aValue) + void insert(T* aValue) { MOZ_ASSERT(!find(*aValue), "Duplicate elements are not allowed."); if (!mRoot) { mRoot = aValue; - return true; + return; } T* last = lookup(*aValue); int cmp = Comparator::compare(*aValue, *last); finishInsertion(last, cmp, aValue); - return true; + return; } T* findOrInsert(const T& aValue); @@ -194,7 +194,7 @@ return parent; } - T* finishInsertion(T* aLast, int32_t aCmp, T* aNew) + void finishInsertion(T* aLast, int32_t aCmp, T* aNew) { MOZ_ASSERT(aCmp, "Nodes shouldn't be equal!"); @@ -204,7 +204,6 @@ aNew->mParent = aLast; splay(aNew); - return aNew; } /** @@ -321,7 +320,9 @@ return last; } - return finishInsertion(last, cmp, new T(aValue)); + T* t = new T(aValue); + finishInsertion(last, cmp, t); + return t; } } /* namespace mozilla */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Sprintf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Sprintf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Sprintf.h @@ -0,0 +1,41 @@ +/* -*- 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/. */ + +/* Provides a safer sprintf for printing to fixed-size character arrays. */ + +#ifndef mozilla_Sprintf_h_ +#define mozilla_Sprintf_h_ + +#include +#include + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" + +#ifdef __cplusplus + +template +int VsprintfLiteral(char (&buffer)[N], const char* format, va_list args) +{ + MOZ_ASSERT(format != buffer); + int result = vsnprintf(buffer, N, format, args); + buffer[N - 1] = '\0'; + return result; +} + +template +MOZ_FORMAT_PRINTF(2, 3) +int SprintfLiteral(char (&buffer)[N], const char* format, ...) +{ + va_list args; + va_start(args, format); + int result = VsprintfLiteral(buffer, format, args); + va_end(args); + return result; +} + +#endif +#endif /* mozilla_Sprintf_h_ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/StackWalk.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/StackWalk.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/StackWalk.h @@ -52,8 +52,6 @@ * May skip some stack frames due to compiler optimizations or code * generation. * - * Note: this (and other helper methods) will only be available when - * MOZ_STACKWALKING is defined, so any new consumers must #if based on that. */ MFBT_API bool MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames, Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/StackWalk_windows.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/StackWalk_windows.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/StackWalk_windows.h @@ -0,0 +1,21 @@ +#ifndef mozilla_StackWalk_windows_h +#define mozilla_StackWalk_windows_h + +#include "mozilla/Types.h" + +/** + * Allow stack walkers to work around the egregious win64 dynamic lookup table + * list API by locking around SuspendThread to avoid deadlock. + * + * See comment in StackWalk.cpp + */ +MFBT_API void +AcquireStackWalkWorkaroundLock(); + +MFBT_API bool +TryAcquireStackWalkWorkaroundLock(); + +MFBT_API void +ReleaseStackWalkWorkaroundLock(); + +#endif // mozilla_StackWalk_windows_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/StaticAnalysisFunctions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/StaticAnalysisFunctions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/StaticAnalysisFunctions.h @@ -0,0 +1,49 @@ +/* -*- 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/. */ + +#ifndef mozilla_StaticAnalysisFunctions_h +#define mozilla_StaticAnalysisFunctions_h + +#ifndef __cplusplus +#ifndef bool +#include +#endif +#endif +/* + * Functions that are used as markers in Gecko code for static analysis. Their + * purpose is to have different AST nodes generated during compile time and to + * match them based on different checkers implemented in build/clang-plugin + */ + +#ifdef MOZ_CLANG_PLUGIN + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * MOZ_AssertAssignmentTest - used in MOZ_ASSERT in order to test the possible + * presence of assignment instead of logical comparisons. + * + * Example: + * MOZ_ASSERT(retVal = true); + */ +static MOZ_ALWAYS_INLINE bool MOZ_AssertAssignmentTest(bool exprResult) { + return exprResult; +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#define MOZ_CHECK_ASSERT_ASSIGNMENT(expr) MOZ_AssertAssignmentTest(!!(expr)) + +#else + +#define MOZ_CHECK_ASSERT_ASSIGNMENT(expr) (!!(expr)) + +#endif /* MOZ_CLANG_PLUGIN */ +#endif /* StaticAnalysisFunctions_h */ \ No newline at end of file Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TextUtils.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TextUtils.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TextUtils.h @@ -0,0 +1,58 @@ +/* -*- 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/. */ + +/* Character/text operations. */ + +#ifndef mozilla_TextUtils_h +#define mozilla_TextUtils_h + +#include "mozilla/TypeTraits.h" + +namespace mozilla { + +namespace detail { + +template +class MakeUnsignedChar + : public MakeUnsigned +{}; + +template<> +class MakeUnsignedChar +{ +public: + using Type = char16_t; +}; + +template<> +class MakeUnsignedChar +{ +public: + using Type = char32_t; +}; + +} // namespace detail + +/** + * Returns true iff |aChar| matches [a-zA-Z]. + * + * This function is basically what you thought isalpha was, except its behavior + * doesn't depend on the user's current locale. + */ +template +constexpr bool +IsAsciiAlpha(Char aChar) +{ + using UnsignedChar = typename detail::MakeUnsignedChar::Type; + return ('a' <= static_cast(aChar) && + static_cast(aChar) <= 'z') || + ('A' <= static_cast(aChar) && + static_cast(aChar) <= 'Z'); +} + +} // namespace mozilla + +#endif /* mozilla_TextUtils_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ThreadLocal.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ThreadLocal.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ThreadLocal.h @@ -42,11 +42,28 @@ typedef sig_atomic_t sig_safe_t; #endif +namespace detail { + +#if defined(HAVE_THREAD_TLS_KEYWORD) +#define MOZ_HAS_THREAD_LOCAL +#endif + /* * Thread Local Storage helpers. * * Usage: * + * Do not directly instantiate this class. Instead, use the + * MOZ_THREAD_LOCAL macro to declare or define instances. The macro + * takes a type name as its argument. + * + * Declare like this: + * extern MOZ_THREAD_LOCAL(int) tlsInt; + * Define like this: + * MOZ_THREAD_LOCAL(int) tlsInt; + * or: + * static MOZ_THREAD_LOCAL(int) tlsInt; + * * Only static-storage-duration (e.g. global variables, or static class members) * objects of this class should be instantiated. This class relies on * zero-initialization, which is implicit for static-storage-duration objects. @@ -56,9 +73,10 @@ * * // Create a TLS item. * // - * // Note that init() should be invoked exactly once, before any usage of set() - * // or get(). - * mozilla::ThreadLocal tlsKey; + * // Note that init() should be invoked before the first use of set() + * // or get(). It is ok to call it multiple times. This must be + * // called in a way that avoids possible races with other threads. + * MOZ_THREAD_LOCAL(int) tlsKey; * if (!tlsKey.init()) { * // deal with the error * } @@ -72,6 +90,7 @@ template class ThreadLocal { +#ifndef MOZ_HAS_THREAD_LOCAL #if defined(XP_WIN) typedef unsigned long key_t; #else @@ -93,19 +112,38 @@ { typedef S *Type; }; +#endif + + bool initialized() const { +#ifdef MOZ_HAS_THREAD_LOCAL + return true; +#else + return mInited; +#endif + } public: - MOZ_WARN_UNUSED_RESULT inline bool init(); + // __thread does not allow non-trivial constructors, but we can + // instead rely on zero-initialization. +#ifndef MOZ_HAS_THREAD_LOCAL + ThreadLocal() + : mKey(0), mInited(false) + {} +#endif + + MOZ_MUST_USE inline bool init(); inline T get() const; inline void set(const T aValue); - bool initialized() const { return mInited; } - private: +#ifdef MOZ_HAS_THREAD_LOCAL + T mValue; +#else key_t mKey; bool mInited; +#endif }; template @@ -118,20 +156,29 @@ static_assert(sizeof(T) <= sizeof(void*), "mozilla::ThreadLocal can't be used for types larger than " "a pointer"); - MOZ_ASSERT(!initialized()); + +#ifdef MOZ_HAS_THREAD_LOCAL + return true; +#else + if (!initialized()) { #ifdef XP_WIN - mKey = TlsAlloc(); - mInited = mKey != 0xFFFFFFFFUL; // TLS_OUT_OF_INDEXES + mKey = TlsAlloc(); + mInited = mKey != 0xFFFFFFFFUL; // TLS_OUT_OF_INDEXES #else - mInited = !pthread_key_create(&mKey, nullptr); + mInited = !pthread_key_create(&mKey, nullptr); #endif + } return mInited; +#endif } template inline T ThreadLocal::get() const { +#ifdef MOZ_HAS_THREAD_LOCAL + return mValue; +#else MOZ_ASSERT(initialized()); void* h; #ifdef XP_WIN @@ -140,12 +187,16 @@ h = pthread_getspecific(mKey); #endif return static_cast(reinterpret_cast::Type>(h)); +#endif } template inline void ThreadLocal::set(const T aValue) { +#ifdef MOZ_HAS_THREAD_LOCAL + mValue = aValue; +#else MOZ_ASSERT(initialized()); void* h = reinterpret_cast(static_cast::Type>(aValue)); #ifdef XP_WIN @@ -156,8 +207,16 @@ if (!succeeded) { MOZ_CRASH(); } +#endif } +#ifdef MOZ_HAS_THREAD_LOCAL +#define MOZ_THREAD_LOCAL(TYPE) __thread mozilla::detail::ThreadLocal +#else +#define MOZ_THREAD_LOCAL(TYPE) mozilla::detail::ThreadLocal +#endif + +} // namespace detail } // namespace mozilla #endif /* mozilla_ThreadLocal_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TimeStamp.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TimeStamp.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TimeStamp.h @@ -62,7 +62,7 @@ { public: // The default duration is 0. - MOZ_CONSTEXPR BaseTimeDuration() : mValue(0) {} + constexpr BaseTimeDuration() : mValue(0) {} // Allow construction using '0' as the initial value, for readability, // but no other numbers (so we don't have any implicit unit conversions). struct _SomethingVeryRandomHere; @@ -395,7 +395,7 @@ /** * Initialize to the "null" moment */ - MOZ_CONSTEXPR TimeStamp() : mValue(0) {} + constexpr TimeStamp() : mValue(0) {} // Default copy-constructor and assignment are OK /** Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TimeStamp_windows.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TimeStamp_windows.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TimeStamp_windows.h @@ -30,7 +30,7 @@ MFBT_API uint64_t CheckQPC(const TimeStampValue& aOther) const; struct _SomethingVeryRandomHere; - MOZ_CONSTEXPR TimeStampValue(_SomethingVeryRandomHere* aNullValue) + constexpr TimeStampValue(_SomethingVeryRandomHere* aNullValue) : mGTC(0) , mQPC(0) , mHasQPC(false) Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Tuple.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Tuple.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Tuple.h @@ -95,7 +95,12 @@ * of an empty tuple). */ template -struct TupleImpl {}; +struct TupleImpl { + bool operator==(const TupleImpl& aOther) const + { + return true; + } +}; /* * One node of the recursive inheritance hierarchy. It stores the element at @@ -182,6 +187,10 @@ Tail(*this) = Move(Tail(aOther)); return *this; } + bool operator==(const TupleImpl& aOther) const + { + return Head(*this) == Head(aOther) && Tail(*this) == Tail(aOther); + } private: HeadT mHead; // The element stored at this index in the tuple. }; @@ -246,6 +255,10 @@ static_cast(*this) = Move(aOther); return *this; } + bool operator==(const Tuple& aOther) const + { + return static_cast(*this) == static_cast(aOther); + } }; /** Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TypeTraits.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TypeTraits.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TypeTraits.h @@ -98,9 +98,7 @@ template<> struct IsIntegralHelper : TrueType {}; template<> struct IsIntegralHelper : TrueType {}; template<> struct IsIntegralHelper : TrueType {}; -#ifdef MOZ_CHAR16_IS_NOT_WCHAR template<> struct IsIntegralHelper : TrueType {}; -#endif } /* namespace detail */ @@ -112,9 +110,6 @@ * mozilla::IsIntegral::value is true; * mozilla::IsIntegral::value is false; * mozilla::IsIntegral::value is false; - * - * Note that the behavior of IsIntegral on char16_t and char32_t is - * unspecified. */ template struct IsIntegral : detail::IsIntegralHelper::Type> @@ -355,6 +350,41 @@ : IntegralConstant::value || IsFloatingPoint::value> {}; +namespace detail { + +template +struct IsMemberPointerHelper : FalseType {}; + +template +struct IsMemberPointerHelper : TrueType {}; + +} // namespace detail + +/** + * IsMemberPointer determines whether a type is pointer to non-static member + * object or a pointer to non-static member function. + * + * mozilla::IsMemberPointer::value is true + * mozilla::IsMemberPointer::value is false + */ +template +struct IsMemberPointer + : detail::IsMemberPointerHelper::Type> +{}; + +/** + * IsScalar determines whether a type is a scalar type. + * + * mozilla::IsScalar::value is true + * mozilla::IsScalar::value is true + * mozilla::IsScalar::value is false + */ +template +struct IsScalar + : IntegralConstant::value || IsEnum::value || + IsPointer::value || IsMemberPointer::value> +{}; + /* 20.9.4.3 Type properties [meta.unary.prop] */ /** @@ -409,9 +439,7 @@ template<> struct IsPod : TrueType {}; template<> struct IsPod : TrueType {}; template<> struct IsPod : TrueType {}; -#ifdef MOZ_CHAR16_IS_NOT_WCHAR template<> struct IsPod : TrueType {}; -#endif template struct IsPod : TrueType {}; namespace detail { @@ -544,6 +572,27 @@ template struct IsUnsigned : detail::IsUnsignedHelper {}; +namespace detail { + +struct DoIsDestructibleImpl +{ + template().~T())> + static TrueType test(int); + template + static FalseType test(...); +}; + +template +struct IsDestructibleImpl : public DoIsDestructibleImpl +{ + typedef decltype(test(0)) Type; +}; + +} // namespace detail + +template +struct IsDestructible : public detail::IsDestructibleImpl::Type {}; + /* 20.9.5 Type property queries [meta.unary.prop.query] */ /* 20.9.6 Relationships between types [meta.rel] */ @@ -644,18 +693,15 @@ namespace detail { -// This belongs inside ConvertibleTester, but it's pulled out to -// work around a bug in the compiler used for hazard builds. -template -static void ConvertibleTestHelper(To); - template struct ConvertibleTester { private: - template(DeclVal()))> - static char test(int); + template + static char test_helper(To1); + + template + static decltype(test_helper(DeclVal())) test(int); template static int test(...); Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TypedEnumBits.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TypedEnumBits.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TypedEnumBits.h @@ -47,34 +47,34 @@ const E mValue; public: - explicit MOZ_CONSTEXPR CastableTypedEnumResult(E aValue) + explicit constexpr CastableTypedEnumResult(E aValue) : mValue(aValue) {} - MOZ_CONSTEXPR operator E() const { return mValue; } + constexpr operator E() const { return mValue; } template - MOZ_EXPLICIT_CONVERSION MOZ_CONSTEXPR + explicit constexpr operator DestinationType() const { return DestinationType(mValue); } - MOZ_CONSTEXPR bool operator !() const { return !bool(mValue); } + constexpr bool operator !() const { return !bool(mValue); } }; #define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType) \ template \ -MOZ_CONSTEXPR ReturnType \ +constexpr ReturnType \ operator Op(const OtherType& aE, const CastableTypedEnumResult& aR) \ { \ return ReturnType(aE Op OtherType(aR)); \ } \ template \ -MOZ_CONSTEXPR ReturnType \ +constexpr ReturnType \ operator Op(const CastableTypedEnumResult& aR, const OtherType& aE) \ { \ return ReturnType(OtherType(aR) Op aE); \ } \ template \ -MOZ_CONSTEXPR ReturnType \ +constexpr ReturnType \ operator Op(const CastableTypedEnumResult& aR1, \ const CastableTypedEnumResult& aR2) \ { \ @@ -90,7 +90,7 @@ MOZ_CASTABLETYPEDENUMRESULT_BINOP(&&, bool, bool) template -MOZ_CONSTEXPR CastableTypedEnumResult +constexpr CastableTypedEnumResult operator ~(const CastableTypedEnumResult& aR) { return CastableTypedEnumResult(~(E(aR))); @@ -123,7 +123,7 @@ } // namespace mozilla #define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op) \ - inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult \ + inline constexpr mozilla::CastableTypedEnumResult \ operator Op(Name a, Name b) \ { \ typedef mozilla::CastableTypedEnumResult Result; \ @@ -145,7 +145,7 @@ MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |) \ MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &) \ MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^) \ - inline MOZ_CONSTEXPR mozilla::CastableTypedEnumResult \ + inline constexpr mozilla::CastableTypedEnumResult \ operator~(Name a) \ { \ typedef mozilla::CastableTypedEnumResult Result; \ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Types.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Types.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Types.h @@ -89,7 +89,7 @@ * symbols. We add the weak attribute to the import version of the MFBT API * macros to exploit this. */ -# if defined(MOZ_GLUE_IN_PROGRAM) && !defined(MOZILLA_XPCOMRT_API) +# if defined(MOZ_GLUE_IN_PROGRAM) # define MFBT_API __attribute__((weak)) MOZ_IMPORT_API # define MFBT_DATA __attribute__((weak)) MOZ_IMPORT_DATA # else Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/UniquePtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/UniquePtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/UniquePtr.h @@ -25,6 +25,39 @@ namespace mozilla { +namespace detail { + +struct HasPointerTypeHelper +{ + template static double Test(...); + template static char Test(typename U::pointer* = 0); +}; + +template +class HasPointerType : public IntegralConstant(0)) == 1> +{ +}; + +template ::value> +struct PointerTypeImpl +{ + typedef typename D::pointer Type; +}; + +template +struct PointerTypeImpl +{ + typedef T* Type; +}; + +template +struct PointerType +{ + typedef typename PointerTypeImpl::Type>::Type Type; +}; + +} // namespace detail + /** * UniquePtr is a smart pointer that wholly owns a resource. Ownership may be * transferred out of a UniquePtr through explicit action, but otherwise the @@ -127,10 +160,11 @@ * The constructors and mutating methods only accept array pointers (not T*, U* * that converts to T*, or UniquePtr or UniquePtr) or |nullptr|. * - * It's perfectly okay to return a UniquePtr from a method to assure the related - * resource is properly deleted. You'll need to use |Move()| when returning a - * local UniquePtr. Otherwise you can return |nullptr|, or you can return - * |UniquePtr(ptr)|. + * It's perfectly okay for a function to return a UniquePtr. This transfers + * the UniquePtr's sole ownership of the data, to the fresh UniquePtr created + * in the calling function, that will then solely own that data. Such functions + * can return a local variable UniquePtr, |nullptr|, |UniquePtr(ptr)| where + * |ptr| is a |T*|, or a UniquePtr |Move()|'d from elsewhere. * * UniquePtr will commonly be a member of a class, with lifetime equivalent to * that of that class. If you want to expose the related resource, you could @@ -154,9 +188,9 @@ class UniquePtr { public: - typedef T* Pointer; typedef T ElementType; typedef D DeleterType; + typedef typename detail::PointerType::Type Pointer; private: Pair mTuple; @@ -171,7 +205,7 @@ /** * Construct a UniquePtr containing |nullptr|. */ - MOZ_CONSTEXPR UniquePtr() + constexpr UniquePtr() : mTuple(static_cast(nullptr), DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); @@ -226,7 +260,7 @@ } UniquePtr(UniquePtr&& aOther) - : mTuple(aOther.release(), Forward(aOther.getDeleter())) + : mTuple(aOther.release(), Forward(aOther.get_deleter())) {} MOZ_IMPLICIT @@ -247,7 +281,7 @@ ? IsSame::value : IsConvertible::value), int>::Type aDummy = 0) - : mTuple(aOther.release(), Forward(aOther.getDeleter())) + : mTuple(aOther.release(), Forward(aOther.get_deleter())) { } @@ -256,7 +290,7 @@ UniquePtr& operator=(UniquePtr&& aOther) { reset(aOther.release()); - getDeleter() = Forward(aOther.getDeleter()); + get_deleter() = Forward(aOther.get_deleter()); return *this; } @@ -270,7 +304,7 @@ "can't assign from UniquePtr holding an array"); reset(aOther.release()); - getDeleter() = Forward(aOther.getDeleter()); + get_deleter() = Forward(aOther.get_deleter()); return *this; } @@ -291,10 +325,10 @@ Pointer get() const { return ptr(); } - DeleterType& getDeleter() { return del(); } - const DeleterType& getDeleter() const { return del(); } + DeleterType& get_deleter() { return del(); } + const DeleterType& get_deleter() const { return del(); } - Pointer release() + MOZ_MUST_USE Pointer release() { Pointer p = ptr(); ptr() = nullptr; @@ -306,7 +340,7 @@ Pointer old = ptr(); ptr() = aPtr; if (old != nullptr) { - getDeleter()(old); + get_deleter()(old); } } @@ -338,7 +372,7 @@ /** * Construct a UniquePtr containing nullptr. */ - MOZ_CONSTEXPR UniquePtr() + constexpr UniquePtr() : mTuple(static_cast(nullptr), DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); @@ -395,7 +429,7 @@ = delete; UniquePtr(UniquePtr&& aOther) - : mTuple(aOther.release(), Forward(aOther.getDeleter())) + : mTuple(aOther.release(), Forward(aOther.get_deleter())) {} MOZ_IMPLICIT @@ -411,7 +445,7 @@ UniquePtr& operator=(UniquePtr&& aOther) { reset(aOther.release()); - getDeleter() = Forward(aOther.getDeleter()); + get_deleter() = Forward(aOther.get_deleter()); return *this; } @@ -426,10 +460,10 @@ T& operator[](decltype(sizeof(int)) aIndex) const { return get()[aIndex]; } Pointer get() const { return mTuple.first(); } - DeleterType& getDeleter() { return mTuple.second(); } - const DeleterType& getDeleter() const { return mTuple.second(); } + DeleterType& get_deleter() { return mTuple.second(); } + const DeleterType& get_deleter() const { return mTuple.second(); } - Pointer release() + MOZ_MUST_USE Pointer release() { Pointer p = mTuple.first(); mTuple.first() = nullptr; @@ -463,12 +497,24 @@ void operator=(const UniquePtr& aOther) = delete; // assign using Move()! }; -/** A default deletion policy using plain old operator delete. */ +/** + * A default deletion policy using plain old operator delete. + * + * Note that this type can be specialized, but authors should beware of the risk + * that the specialization may at some point cease to match (either because it + * gets moved to a different compilation unit or the signature changes). If the + * non-specialized (|delete|-based) version compiles for that type but does the + * wrong thing, bad things could happen. + * + * This is a non-issue for types which are always incomplete (i.e. opaque handle + * types), since |delete|-ing such a type will always trigger a compilation + * error. + */ template class DefaultDelete { public: - MOZ_CONSTEXPR DefaultDelete() {} + constexpr DefaultDelete() {} template MOZ_IMPLICIT DefaultDelete(const DefaultDelete& aOther, @@ -488,7 +534,7 @@ class DefaultDelete { public: - MOZ_CONSTEXPR DefaultDelete() {} + constexpr DefaultDelete() {} void operator()(T* aPtr) const { Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/UniquePtrExtensions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/UniquePtrExtensions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/UniquePtrExtensions.h @@ -37,6 +37,21 @@ typename detail::UniqueSelector::KnownBound MakeUniqueFallible(Args&&... aArgs) = delete; +namespace detail { + +template +struct FreePolicy +{ + void operator()(const void* ptr) { + free(const_cast(ptr)); + } +}; + +} // namespace detail + +template +using UniqueFreePtr = UniquePtr>; + } // namespace mozilla #endif // mozilla_UniquePtrExtensions_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Variant.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Variant.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Variant.h @@ -7,10 +7,12 @@ /* A template class for tagged unions. */ #include +#include #include "mozilla/Alignment.h" #include "mozilla/Assertions.h" #include "mozilla/Move.h" +#include "mozilla/TypeTraits.h" #ifndef mozilla_Variant_h #define mozilla_Variant_h @@ -61,43 +63,112 @@ template struct IsVariant : public IsVariant { }; +/// SelectVariantTypeHelper is used in the implementation of SelectVariantType. +template +struct SelectVariantTypeHelper; + +template +struct SelectVariantTypeHelper +{ }; + +template +struct SelectVariantTypeHelper +{ + typedef T Type; +}; + +template +struct SelectVariantTypeHelper +{ + typedef const T Type; +}; + +template +struct SelectVariantTypeHelper +{ + typedef const T& Type; +}; + +template +struct SelectVariantTypeHelper +{ + typedef T&& Type; +}; + +template +struct SelectVariantTypeHelper + : public SelectVariantTypeHelper +{ }; + +/** + * SelectVariantType takes a type T and a list of variant types Variants and + * yields a type Type, selected from Variants, that can store a value of type T + * or a reference to type T. If no such type was found, Type is not defined. + */ +template +struct SelectVariantType + : public SelectVariantTypeHelper::Type>::Type, + Variants...> +{ }; + +// Compute a fast, compact type that can be used to hold integral values that +// distinctly map to every type in Ts. +template +struct VariantTag +{ +private: + static const size_t TypeCount = sizeof...(Ts); + +public: + using Type = + typename Conditional::Type + >::Type; +}; + // TagHelper gets the given sentinel tag value for the given type T. This has to -// be split out from VariantImplementation because you can't nest a partial template -// specialization within a template class. +// be split out from VariantImplementation because you can't nest a partial +// template specialization within a template class. -template +template struct TagHelper; // In the case where T != U, we continue recursion. -template -struct TagHelper +template +struct TagHelper { - static size_t tag() { return Next::template tag(); } + static Tag tag() { return Next::template tag(); } }; // In the case where T == U, return the tag number. -template -struct TagHelper +template +struct TagHelper { - static size_t tag() { return N; } + static Tag tag() { return Tag(N); } }; -// The VariantImplementation template provides the guts of mozilla::Variant. We create -// an VariantImplementation for each T in Ts... which handles construction, -// destruction, etc for when the Variant's type is T. If the Variant's type is -// not T, it punts the request on to the next VariantImplementation. +// The VariantImplementation template provides the guts of mozilla::Variant. We +// create a VariantImplementation for each T in Ts... which handles +// construction, destruction, etc for when the Variant's type is T. If the +// Variant's type isn't T, it punts the request on to the next +// VariantImplementation. -template +template struct VariantImplementation; // The singly typed Variant / recursion base case. -template -struct VariantImplementation { +template +struct VariantImplementation +{ template - static size_t tag() { + static Tag tag() { static_assert(mozilla::IsSame::value, "mozilla::Variant: tag: bad type!"); - return N; + return Tag(N); } template @@ -122,22 +193,24 @@ } template - static typename Matcher::ReturnType - match(Matcher& aMatcher, ConcreteVariant& aV) { + static auto + match(Matcher&& aMatcher, ConcreteVariant& aV) + -> decltype(aMatcher.match(aV.template as())) + { return aMatcher.match(aV.template as()); } }; // VariantImplementation for some variant type T. -template -struct VariantImplementation +template +struct VariantImplementation { // The next recursive VariantImplementation. - using Next = VariantImplementation; + using Next = VariantImplementation; template - static size_t tag() { - return TagHelper::value>::tag(); + static Tag tag() { + return TagHelper::value>::tag(); } template @@ -178,8 +251,9 @@ } template - static typename Matcher::ReturnType - match(Matcher& aMatcher, ConcreteVariant& aV) + static auto + match(Matcher&& aMatcher, ConcreteVariant& aV) + -> decltype(aMatcher.match(aV.template as())) { if (aV.template is()) { return aMatcher.match(aV.template as()); @@ -199,6 +273,39 @@ } }; +/** + * AsVariantTemporary stores a value of type T to allow construction of a + * Variant value via type inference. Because T is copied and there's no + * guarantee that the copy can be elided, AsVariantTemporary is best used with + * primitive or very small types. + */ +template +struct AsVariantTemporary +{ + explicit AsVariantTemporary(const T& aValue) + : mValue(aValue) + {} + + template + explicit AsVariantTemporary(U&& aValue) + : mValue(Forward(aValue)) + {} + + AsVariantTemporary(const AsVariantTemporary& aOther) + : mValue(aOther.mValue) + {} + + AsVariantTemporary(AsVariantTemporary&& aOther) + : mValue(Move(aOther.mValue)) + {} + + AsVariantTemporary() = delete; + void operator=(const AsVariantTemporary&) = delete; + void operator=(AsVariantTemporary&&) = delete; + + typename RemoveConst::Type>::Type mValue; +}; + } // namespace detail /** @@ -222,6 +329,18 @@ * Variant v1('a'); * Variant, B, C> v2(MakeUnique()); * + * Because specifying the full type of a Variant value is often verbose, + * AsVariant() can be used to construct a Variant value using type inference in + * contexts such as expressions or when returning values from functions. Because + * AsVariant() must copy or move the value into a temporary and this cannot + * necessarily be elided by the compiler, it's mostly appropriate only for use + * with primitive or very small types. + * + * + * Variant Foo() { return AsVariant('x'); } + * // ... + * Variant v1 = Foo(); // v1 holds char('x'). + * * All access to the contained value goes through type-safe accessors. * * void @@ -275,11 +394,11 @@ * // Good! * struct FooMatcher * { - * using ReturnType = char*; - * ReturnType match(A& a) { ... } - * ReturnType match(B& b) { ... } - * ReturnType match(C& c) { ... } - * ReturnType match(D& d) { ... } // Compile-time error to forget D! + * // The return type of all matchers must be identical. + * char* match(A& a) { ... } + * char* match(B& b) { ... } + * char* match(C& c) { ... } + * char* match(D& d) { ... } // Compile-time error to forget D! * } * char* foo(Variant& v) { * return v.match(FooMatcher()); @@ -313,18 +432,19 @@ * }; */ template -class Variant +class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Variant { - using Impl = detail::VariantImplementation<0, Ts...>; + using Tag = typename detail::VariantTag::Type; + using Impl = detail::VariantImplementation; using RawData = AlignedStorage::size>; - // Each type is given a unique size_t sentinel. This tag lets us keep track of - // the contained variant value's type. - size_t tag; - // Raw storage for the contained variant value. RawData raw; + // Each type is given a unique tag value that lets us keep track of the + // contained variant value's type. + Tag tag; + void* ptr() { return reinterpret_cast(&raw); } @@ -336,12 +456,24 @@ // perfect forwarding), so we have to remove those qualifiers here // when ensuring that T is a variant of this type, and getting T's // tag, etc. - typename T = typename RemoveReference::Type>::Type, - typename = typename EnableIf::value, void>::Type> + typename T = typename detail::SelectVariantType::Type> explicit Variant(RefT&& aT) : tag(Impl::template tag()) { - new (ptr()) T(Forward(aT)); + new (ptr()) T(Forward(aT)); + } + + /** + * Constructs this Variant from an AsVariantTemporary such that T can be + * stored in one of the types allowable in this Variant. This is used in the + * implementation of AsVariant(). + */ + template::Type> + MOZ_IMPLICIT Variant(detail::AsVariantTemporary&& aValue) + : tag(Impl::template tag()) + { + new (ptr()) T(Move(aValue.mValue)); } /** Copy construction. */ @@ -374,6 +506,15 @@ return *this; } + /** Move assignment from AsVariant(). */ + template + Variant& operator=(detail::AsVariantTemporary&& aValue) + { + this->~Variant(); + new (this) Variant(Move(aValue)); + return *this; + } + ~Variant() { Impl::destroy(*this); @@ -438,23 +579,47 @@ return T(Move(as())); } - // Exhaustive matching of all variant types no the contained value. + // Exhaustive matching of all variant types on the contained value. /** Match on an immutable const reference. */ template - typename Matcher::ReturnType - match(Matcher& aMatcher) const { + auto + match(Matcher&& aMatcher) const + -> decltype(Impl::match(aMatcher, *this)) + { return Impl::match(aMatcher, *this); } - /** Match on a mutable non-const reference. */ + /** Match on a mutable non-const reference. */ template - typename Matcher::ReturnType - match(Matcher& aMatcher) { + auto + match(Matcher&& aMatcher) + -> decltype(Impl::match(aMatcher, *this)) + { return Impl::match(aMatcher, *this); } }; +/* + * AsVariant() is used to construct a Variant value containing the + * provided T value using type inference. It can be used to construct Variant + * values in expressions or return them from functions without specifying the + * entire Variant type. + * + * Because AsVariant() must copy or move the value into a temporary and this + * cannot necessarily be elided by the compiler, it's mostly appropriate only + * for use with primitive or very small types. + * + * AsVariant() returns a AsVariantTemporary value which is implicitly + * convertible to any Variant that can hold a value of type T. + */ +template +detail::AsVariantTemporary +AsVariant(T&& aValue) +{ + return detail::AsVariantTemporary(Forward(aValue)); +} + } // namespace mozilla #endif /* mozilla_Variant_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Vector.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Vector.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Vector.h @@ -17,6 +17,7 @@ #include "mozilla/MathAlgorithms.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Move.h" +#include "mozilla/OperatorNewExtensions.h" #include "mozilla/ReentrancyGuard.h" #include "mozilla/TemplateLib.h" #include "mozilla/TypeTraits.h" @@ -56,22 +57,13 @@ struct VectorImpl { /* - * Constructs a default object in the uninitialized memory at *aDst. + * Constructs an object in the uninitialized memory at *aDst with aArgs. */ + template MOZ_NONNULL(1) - static inline void new_(T* aDst) - { - new(aDst) T(); - } - - /* - * Constructs an object in the uninitialized memory at *aDst from aSrc. - */ - template - MOZ_NONNULL(1) - static inline void new_(T* aDst, U&& aU) + static inline void new_(T* aDst, Args&&... aArgs) { - new(aDst) T(Forward(aU)); + new(KnownNotNull, aDst) T(Forward(aArgs)...); } /* Destroys constructed objects in the range [aBegin, aEnd). */ @@ -137,7 +129,7 @@ * aNewCap has not overflowed, and (2) multiplying aNewCap by sizeof(T) will * not overflow. */ - static inline bool + static inline MOZ_MUST_USE bool growTo(Vector& aV, size_t aNewCap) { MOZ_ASSERT(!aV.usingInlineStorage()); @@ -168,15 +160,16 @@ template struct VectorImpl { - static inline void new_(T* aDst) - { - *aDst = T(); - } - - template - static inline void new_(T* aDst, U&& aU) + template + MOZ_NONNULL(1) + static inline void new_(T* aDst, Args&&... aArgs) { - *aDst = Forward(aU); + // Explicitly construct a local object instead of using a temporary since + // T(args...) will be treated like a C-style cast in the unary case and + // allow unsafe conversions. Both forms should be equivalent to an + // optimizing compiler. + T temp(Forward(aArgs)...); + *aDst = temp; } static inline void destroy(T*, T*) {} @@ -228,7 +221,7 @@ } } - static inline bool + static inline MOZ_MUST_USE bool growTo(Vector& aV, size_t aNewCap) { MOZ_ASSERT(!aV.usingInlineStorage()); @@ -242,6 +235,20 @@ aV.mCapacity = aNewCap; return true; } + + static inline void + podResizeToFit(Vector& aV) + { + if (aV.usingInlineStorage() || aV.mLength == aV.mCapacity) { + return; + } + T* newbuf = aV.template pod_realloc(aV.mBegin, aV.mCapacity, aV.mLength); + if (MOZ_UNLIKELY(!newbuf)) { + return; + } + aV.mBegin = newbuf; + aV.mCapacity = aV.mLength; + } }; // A struct for TestVector.cpp to access private internal fields. @@ -281,8 +288,9 @@ friend struct detail::VectorTesting; - bool growStorageBy(size_t aIncr); - bool convertToHeapStorage(size_t aNewCap); + MOZ_MUST_USE bool growStorageBy(size_t aIncr); + MOZ_MUST_USE bool convertToHeapStorage(size_t aNewCap); + MOZ_MUST_USE bool maybeCheckSimulatedOOM(size_t aRequestedSize); /* magic constants */ @@ -519,10 +527,24 @@ /* mutators */ /** - * Given that the vector is empty and has no inline storage, grow to - * |capacity|. + * Reverse the order of the elements in the vector in place. + */ + void reverse(); + + /** + * Given that the vector is empty, grow the internal capacity to |aRequest|, + * keeping the length 0. + */ + MOZ_MUST_USE bool initCapacity(size_t aRequest); + + /** + * Given that the vector is empty, grow the internal capacity and length to + * |aRequest| leaving the elements' memory completely uninitialized (with all + * the associated hazards and caveats). This avoids the usual allocation-size + * rounding that happens in resize and overhead of initialization for elements + * that are about to be overwritten. */ - bool initCapacity(size_t aRequest); + MOZ_MUST_USE bool initLengthUninitialized(size_t aRequest); /** * If reserve(aRequest) succeeds and |aRequest >= length()|, then appending @@ -532,7 +554,7 @@ * A request to reserve an amount less than the current length does not affect * reserved space. */ - bool reserve(size_t aRequest); + MOZ_MUST_USE bool reserve(size_t aRequest); /** * Destroy elements in the range [end() - aIncr, end()). Does not deallocate @@ -540,19 +562,25 @@ */ void shrinkBy(size_t aIncr); + /** + * Destroy elements in the range [aNewLength, end()). Does not deallocate + * or unreserve storage for those elements. + */ + void shrinkTo(size_t aNewLength); + /** Grow the vector by aIncr elements. */ - bool growBy(size_t aIncr); + MOZ_MUST_USE bool growBy(size_t aIncr); /** Call shrinkBy or growBy based on whether newSize > length(). */ - bool resize(size_t aNewLength); + MOZ_MUST_USE bool resize(size_t aNewLength); /** * Increase the length of the vector, but don't initialize the new elements * -- leave them as uninitialized memory. */ - bool growByUninitialized(size_t aIncr); + MOZ_MUST_USE bool growByUninitialized(size_t aIncr); void infallibleGrowByUninitialized(size_t aIncr); - bool resizeUninitialized(size_t aNewLength); + MOZ_MUST_USE bool resizeUninitialized(size_t aNewLength); /** Shorthand for shrinkBy(length()). */ void clear(); @@ -561,6 +589,13 @@ void clearAndFree(); /** + * Calls the AllocPolicy's pod_realloc to release excess capacity. Since + * realloc is only safe on PODs, this method fails to compile if IsPod + * is false. + */ + void podResizeToFit(); + + /** * If true, appending |aNeeded| elements won't reallocate elements storage. * This *doesn't* mean that infallibleAppend may be used! You still must * reserve the extra space, even if this method indicates that appends won't @@ -575,25 +610,25 @@ * vector, instead of copying it. If it fails, |aU| is left unmoved. ("We are * not amused.") */ - template bool append(U&& aU); + template MOZ_MUST_USE bool append(U&& aU); /** * Construct a T in-place as a new entry at the end of this vector. */ template - bool emplaceBack(Args&&... aArgs) + MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) { if (!growByUninitialized(1)) return false; - new (&back()) T(Forward(aArgs)...); + Impl::new_(&back(), Forward(aArgs)...); return true; } template - bool appendAll(const Vector& aU); - bool appendN(const T& aT, size_t aN); - template bool append(const U* aBegin, const U* aEnd); - template bool append(const U* aBegin, size_t aLength); + MOZ_MUST_USE bool appendAll(const Vector& aU); + MOZ_MUST_USE bool appendN(const T& aT, size_t aN); + template MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd); + template MOZ_MUST_USE bool append(const U* aBegin, size_t aLength); /* * Guaranteed-infallible append operations for use upon vectors whose @@ -620,7 +655,7 @@ void infallibleEmplaceBack(Args&&... aArgs) { infallibleGrowByUninitialized(1); - new (&back()) T(Forward(aArgs)...); + Impl::new_(&back(), Forward(aArgs)...); } void popBack(); @@ -628,16 +663,34 @@ T popCopy(); /** - * Transfers ownership of the internal buffer used by this vector to the - * caller. (It's the caller's responsibility to properly deallocate this - * buffer, in accordance with this vector's AllocPolicy.) After this call, - * the vector is empty. Since the returned buffer may need to be allocated - * (if the elements are currently stored in-place), the call can fail, - * returning nullptr. + * If elements are stored in-place, return nullptr and leave this vector + * unmodified. + * + * Otherwise return this vector's elements buffer, and clear this vector as if + * by clearAndFree(). The caller now owns the buffer and is responsible for + * deallocating it consistent with this vector's AllocPolicy. * * N.B. Although a T*, only the range [0, length()) is constructed. */ - T* extractRawBuffer(); + MOZ_MUST_USE T* extractRawBuffer(); + + /** + * If elements are stored in-place, allocate a new buffer, move this vector's + * elements into it, and return that buffer. + * + * Otherwise return this vector's elements buffer. The caller now owns the + * buffer and is responsible for deallocating it consistent with this vector's + * AllocPolicy. + * + * This vector is cleared, as if by clearAndFree(), when this method + * succeeds. This method fails and returns nullptr only if new elements buffer + * allocation fails. + * + * N.B. Only the range [0, length()) of the returned buffer is constructed. + * If any of these elements are uninitialized (as growByUninitialized + * enables), behavior is undefined. + */ + MOZ_MUST_USE T* extractOrCopyRawBuffer(); /** * Transfer ownership of an array of objects into the vector. The caller @@ -665,7 +718,7 @@ * This is inherently a linear-time operation. Be careful! */ template - T* insert(T* aP, U&& aVal); + MOZ_MUST_USE T* insert(T* aP, U&& aVal); /** * Removes the element |aT|, which must fall in the bounds [begin, end), @@ -767,7 +820,7 @@ { MOZ_ASSERT(this != &aRhs, "self-move assignment is prohibited"); this->~Vector(); - new(this) Vector(Move(aRhs)); + new(KnownNotNull, this) Vector(Move(aRhs)); return *this; } @@ -782,6 +835,18 @@ } } +template +MOZ_ALWAYS_INLINE void +Vector::reverse() { + MOZ_REENTRANCY_GUARD_ET_AL; + T* elems = mBegin; + size_t len = mLength; + size_t mid = len / 2; + for (size_t i = 0; i < mid; i++) { + Swap(elems[i], elems[len - i - 1]); + } +} + /* * This function will create a new heap buffer with capacity aNewCap, * move all elements in the inline buffer to this new buffer, @@ -916,6 +981,34 @@ template inline bool +Vector::initLengthUninitialized(size_t aRequest) +{ + if (!initCapacity(aRequest)) { + return false; + } + infallibleGrowByUninitialized(aRequest); + return true; +} + +template +inline bool +Vector::maybeCheckSimulatedOOM(size_t aRequestedSize) +{ + if (aRequestedSize <= N) { + return true; + } + +#ifdef DEBUG + if (aRequestedSize <= mReserved) { + return true; + } +#endif + + return allocPolicy().checkSimulatedOOM(); +} + +template +inline bool Vector::reserve(size_t aRequest) { MOZ_REENTRANCY_GUARD_ET_AL; @@ -923,10 +1016,8 @@ if (MOZ_UNLIKELY(!growStorageBy(aRequest - mLength))) { return false; } - } else if (aRequest > N) { - if (!allocPolicy().checkSimulatedOOM()) { - return false; - } + } else if (!maybeCheckSimulatedOOM(aRequest)) { + return false; } #ifdef DEBUG if (aRequest > mReserved) { @@ -949,6 +1040,14 @@ } template +MOZ_ALWAYS_INLINE void +Vector::shrinkTo(size_t aNewLength) +{ + MOZ_ASSERT(aNewLength <= mLength); + shrinkBy(mLength - aNewLength); +} + +template MOZ_ALWAYS_INLINE bool Vector::growBy(size_t aIncr) { @@ -957,10 +1056,8 @@ if (MOZ_UNLIKELY(!growStorageBy(aIncr))) { return false; } - } else if (aIncr + mLength > N) { - if (!allocPolicy().checkSimulatedOOM()) { - return false; - } + } else if (!maybeCheckSimulatedOOM(mLength + aIncr)) { + return false; } MOZ_ASSERT(mLength + aIncr <= mCapacity); T* newend = endNoCheck() + aIncr; @@ -983,11 +1080,14 @@ if (MOZ_UNLIKELY(!growStorageBy(aIncr))) { return false; } - } else if (aIncr + mLength > N) { - if (!allocPolicy().checkSimulatedOOM()) { - return false; - } + } else if (!maybeCheckSimulatedOOM(mLength + aIncr)) { + return false; } +#ifdef DEBUG + if (mLength + aIncr > mReserved) { + mReserved = mLength + aIncr; + } +#endif infallibleGrowByUninitialized(aIncr); return true; } @@ -996,13 +1096,8 @@ MOZ_ALWAYS_INLINE void Vector::infallibleGrowByUninitialized(size_t aIncr) { - MOZ_ASSERT(mLength + aIncr <= mCapacity); + MOZ_ASSERT(mLength + aIncr <= reserved()); mLength += aIncr; -#ifdef DEBUG - if (mLength > mReserved) { - mReserved = mLength; - } -#endif } template @@ -1056,6 +1151,15 @@ } template +inline void +Vector::podResizeToFit() +{ + // This function is only defined if IsPod is true and will fail to compile + // otherwise. + Impl::podResizeToFit(*this); +} + +template inline bool Vector::canAppendWithoutRealloc(size_t aNeeded) const { @@ -1090,9 +1194,8 @@ if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) { return false; } - } else if (mLength + aNeeded > N) { - if (!allocPolicy().checkSimulatedOOM()) - return false; + } else if (!maybeCheckSimulatedOOM(mLength + aNeeded)) { + return false; } #ifdef DEBUG if (mLength + aNeeded > mReserved) { @@ -1177,8 +1280,7 @@ if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) { return false; } - } else if (mLength + aNeeded > N) { - if (!allocPolicy().checkSimulatedOOM()) + } else if (!maybeCheckSimulatedOOM(mLength + aNeeded)) { return false; } #ifdef DEBUG @@ -1211,8 +1313,7 @@ if (MOZ_UNLIKELY(!growStorageBy(1))) { return false; } - } else if (mLength + 1 > N) { - if (!allocPolicy().checkSimulatedOOM()) + } else if (!maybeCheckSimulatedOOM(mLength + 1)) { return false; } #ifdef DEBUG @@ -1263,29 +1364,49 @@ inline T* Vector::extractRawBuffer() { - T* ret; + MOZ_REENTRANCY_GUARD_ET_AL; + if (usingInlineStorage()) { - ret = this->template pod_malloc(mLength); - if (!ret) { - return nullptr; - } - Impl::copyConstruct(ret, beginNoCheck(), endNoCheck()); - Impl::destroy(beginNoCheck(), endNoCheck()); - /* mBegin, mCapacity are unchanged. */ - mLength = 0; - } else { - ret = mBegin; - mBegin = static_cast(mStorage.addr()); - mLength = 0; - mCapacity = kInlineCapacity; + return nullptr; + } + + T* ret = mBegin; + mBegin = static_cast(mStorage.addr()); + mLength = 0; + mCapacity = kInlineCapacity; #ifdef DEBUG - mReserved = 0; + mReserved = 0; #endif - } return ret; } template +inline T* +Vector::extractOrCopyRawBuffer() +{ + if (T* ret = extractRawBuffer()) { + return ret; + } + + MOZ_REENTRANCY_GUARD_ET_AL; + + T* copy = this->template pod_malloc(mLength); + if (!copy) { + return nullptr; + } + + Impl::moveConstruct(copy, beginNoCheck(), endNoCheck()); + Impl::destroy(beginNoCheck(), endNoCheck()); + mBegin = static_cast(mStorage.addr()); + mLength = 0; + mCapacity = kInlineCapacity; +#ifdef DEBUG + mReserved = 0; +#endif + return copy; +} + +template inline void Vector::replaceRawBuffer(T* aP, size_t aLength) { Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/WeakPtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/WeakPtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/WeakPtr.h @@ -76,6 +76,58 @@ #include +// Weak referencing is not implemeted as thread safe. When a WeakPtr +// is created or dereferenced on thread A but the real object is just +// being Released() on thread B, there is a possibility of a race +// when the proxy object (detail::WeakReference) is notified about +// the real object destruction just between when thread A is storing +// the object pointer locally and is about to add a reference to it. +// +// Hence, a non-null weak proxy object is considered to have a single +// "owning thread". It means that each query for a weak reference, +// its dereference, and destruction of the real object must all happen +// on a single thread. The following macros implement assertions for +// checking these conditions. +// +// We disable this on MinGW. MinGW has two threading models: win32 +// API based, which disables std::thread; and POSIX based which +// enables it but requires an emulation library (winpthreads). +// Rather than attempting to switch to pthread emulation at this point, +// we are disabling the std::thread based assertion checking. +// +// In the future, to enable it we could +// a. have libgcc/stdc++ support win32 threads natively +// b. switch to POSIX-based threading in MinGW with pthread emulation +// c. refactor it to not use std::thread + +#if !defined(__MINGW32__) && (defined(DEBUG) || (defined(NIGHTLY_BUILD) && !defined(MOZ_PROFILING))) + +#include +#define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK \ + std::thread::id _owningThread; \ + bool _empty; // If it was initialized as a placeholder with mPtr = nullptr. +#define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \ + do { \ + _owningThread = std::this_thread::get_id(); \ + _empty = !p; \ + } while (false) +#define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \ + MOZ_DIAGNOSTIC_ASSERT(_empty || _owningThread == std::this_thread::get_id(), \ + "WeakPtr used on multiple threads") +#define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \ + (that)->AssertThreadSafety(); + +#define MOZ_WEAKPTR_THREAD_SAFETY_CHECKING 1 + +#else + +#define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK +#define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() do { } while (false) +#define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() do { } while (false) +#define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) do { } while (false) + +#endif + namespace mozilla { template class WeakPtr; @@ -96,9 +148,15 @@ class WeakReference : public ::mozilla::RefCounted > { public: - explicit WeakReference(T* p) : mPtr(p) {} + explicit WeakReference(T* p) : mPtr(p) + { + MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK(); + } - T* get() const { return mPtr; } + T* get() const { + MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); + return mPtr; + } #ifdef MOZ_REFCOUNTED_LEAK_CHECKING const char* typeName() const @@ -110,12 +168,20 @@ size_t typeSize() const { return sizeof(*this); } #endif +#ifdef MOZ_WEAKPTR_THREAD_SAFETY_CHECKING + void AssertThreadSafety() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); } +#endif + private: friend class mozilla::SupportsWeakPtr; - void detach() { mPtr = nullptr; } + void detach() { + MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); + mPtr = nullptr; + } T* MOZ_NON_OWNING_REF mPtr; + MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK }; } // namespace detail @@ -138,6 +204,8 @@ { if (!mSelfReferencingWeakPtr) { mSelfReferencingWeakPtr.mRef = new detail::WeakReference(static_cast(this)); + } else { + MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mSelfReferencingWeakPtr.mRef); } return mSelfReferencingWeakPtr; } @@ -163,11 +231,13 @@ WeakPtr& operator=(const WeakPtr& aOther) { mRef = aOther.mRef; + MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef); return *this; } WeakPtr(const WeakPtr& aOther) { + // The thread safety check is performed inside of the operator= method. *this = aOther; } @@ -179,12 +249,15 @@ // Ensure that mRef is dereferenceable in the uninitialized state. mRef = new WeakReference(nullptr); } + // The thread safety check happens inside SelfReferencingWeakPtr + // or is initialized in the WeakReference constructor. return *this; } MOZ_IMPLICIT WeakPtr(T* aOther) { *this = aOther; + MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef); } // Ensure that mRef is dereferenceable in the uninitialized state. Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/WindowsVersion.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/WindowsVersion.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/WindowsVersion.h @@ -172,6 +172,12 @@ } MOZ_ALWAYS_INLINE bool +IsWin8Point1OrLater() +{ + return IsWindowsVersionOrLater(0x06030000ul); +} + +MOZ_ALWAYS_INLINE bool IsWin10OrLater() { return IsWindowsVersionOrLater(0x0a000000ul); @@ -184,6 +190,41 @@ IsWindowsBuildOrLater(7600); } +MOZ_ALWAYS_INLINE bool +IsWin7AndPre2000Compatible() { + /* + * See Bug 1279171. + * We'd like to avoid using WMF on specific OS version when compatibility + * mode is in effect. The purpose of this function is to check if FF runs on + * Win7 OS with application compatibility mode being set to 95/98/ME. + * Those compatibility mode options (95/98/ME) can only display and + * be selected for 32-bit application. + * If the compatibility mode is in effect, the GetVersionEx function will + * report the OS as it identifies itself, which may not be the OS that is + * installed. + * Note : 1) We only target for Win7 build number greater than 7600. + * 2) GetVersionEx may be altered or unavailable for release after + * Win8.1. Set pragma to avoid build warning as error. + */ + bool isWin7 = IsNotWin7PreRTM() && !IsWin8OrLater(); + if (!isWin7) { + return false; + } + + OSVERSIONINFOEX info; + ZeroMemory(&info, sizeof(OSVERSIONINFOEX)); + + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); +#pragma warning(push) +#pragma warning(disable:4996) + bool success = GetVersionEx((LPOSVERSIONINFO) &info); +#pragma warning(pop) + if (!success) { + return false; + } + return info.dwMajorVersion < 5; +} + } // namespace mozilla #endif /* mozilla_WindowsVersion_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/XorShift128PlusRNG.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/XorShift128PlusRNG.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/XorShift128PlusRNG.h @@ -33,6 +33,11 @@ * Intel(R) Core(TM) i7-4770 CPU @3.40GHz (Haswell). It is the fastest * generator we are aware of with such empirical statistical properties. * + * The stream of numbers produced by this method repeats every 2**128 - 1 calls + * (i.e. never, for all practical purposes). Zero appears 2**64 - 1 times in + * this period; all other numbers appear 2**64 times. Additionally, each *bit* + * in the produced numbers repeats every 2**128 - 1 calls. + * * This generator is not suitable as a cryptographically secure random number * generator. */ @@ -42,14 +47,20 @@ public: /* * Construct a xorshift128+ pseudo-random number stream using |aInitial0| and - * |aInitial1| as the initial state. These may not both be zero; ideally, they - * should have an almost even mix of zero and one bits. + * |aInitial1| as the initial state. These MUST NOT both be zero. + * + * If the initial states contain many zeros, for a few iterations you'll see + * many zeroes in the generated numbers. It's suggested to seed a SplitMix64 + * generator and use its first two + * outputs to seed xorshift128+. */ XorShift128PlusRNG(uint64_t aInitial0, uint64_t aInitial1) { setState(aInitial0, aInitial1); } - /* Return a pseudo-random 64-bit number. */ + /** + * Return a pseudo-random 64-bit number. + */ uint64_t next() { /* * The offsetOfState*() methods below are provided so that exceedingly-rare @@ -66,9 +77,10 @@ } /* - * Return a pseudo-random floating-point value in the range [0, 1). - * More precisely, choose an integer in the range [0, 2**53) and - * divide it by 2**53. + * Return a pseudo-random floating-point value in the range [0, 1). More + * precisely, choose an integer in the range [0, 2**53) and divide it by + * 2**53. Given the 2**128 - 1 period noted above, the produced doubles are + * all but uniformly distributed in this range. */ double nextDouble() { /* @@ -78,7 +90,7 @@ * is the width of the bitfield in the in-memory format, so we must add one * to get the mantissa's range. */ - static MOZ_CONSTEXPR_VAR int kMantissaBits = + static constexpr int kMantissaBits = mozilla::FloatingPoint::kExponentShift + 1; uint64_t mantissa = next() & ((UINT64_C(1) << kMantissaBits) - 1); return double(mantissa) / (UINT64_C(1) << kMantissaBits); Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/mozalloc.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/mozalloc.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/mozalloc.h @@ -12,14 +12,22 @@ * https://bugzilla.mozilla.org/show_bug.cgi?id=427099 */ -#include -#include #if defined(__cplusplus) # include +// Since libstdc++ 6, including the C headers (e.g. stdlib.h) instead of the +// corresponding C++ header (e.g. cstdlib) can cause confusion in C++ code +// using things defined there. Specifically, with stdlib.h, the use of abs() +// in gfx/graphite2/src/inc/UtfCodec.h somehow ends up picking the wrong abs() +# include +# include +#else +# include +# include #endif #if defined(__cplusplus) #include "mozilla/fallible.h" +#include "mozilla/mozalloc_abort.h" #include "mozilla/TemplateLib.h" #endif #include "mozilla/Attributes.h" @@ -37,8 +45,8 @@ /* Workaround build problem with Sun Studio 12 */ #if defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# undef MOZ_WARN_UNUSED_RESULT -# define MOZ_WARN_UNUSED_RESULT +# undef MOZ_MUST_USE +# define MOZ_MUST_USE # undef MOZ_ALLOCATOR # define MOZ_ALLOCATOR #endif @@ -97,10 +105,10 @@ #if defined(HAVE_POSIX_MEMALIGN) -MFBT_API MOZ_WARN_UNUSED_RESULT +MFBT_API MOZ_MUST_USE int moz_xposix_memalign(void **ptr, size_t alignment, size_t size); -MFBT_API MOZ_WARN_UNUSED_RESULT +MFBT_API MOZ_MUST_USE int moz_posix_memalign(void **ptr, size_t alignment, size_t size); #endif /* if defined(HAVE_POSIX_MEMALIGN) */ @@ -282,10 +290,28 @@ { public: template + T* maybe_pod_malloc(size_t aNumElems) + { + return pod_malloc(aNumElems); + } + + template + T* maybe_pod_calloc(size_t aNumElems) + { + return pod_calloc(aNumElems); + } + + template + T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) + { + return pod_realloc(aPtr, aOldSize, aNewSize); + } + + template T* pod_malloc(size_t aNumElems) { if (aNumElems & mozilla::tl::MulOverflowMask::value) { - return nullptr; + reportAllocOverflow(); } return static_cast(moz_xmalloc(aNumElems * sizeof(T))); } @@ -300,7 +326,7 @@ T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { if (aNewSize & mozilla::tl::MulOverflowMask::value) { - return nullptr; + reportAllocOverflow(); } return static_cast(moz_xrealloc(aPtr, aNewSize * sizeof(T))); } @@ -312,6 +338,12 @@ void reportAllocOverflow() const { + mozalloc_abort("alloc overflow"); + } + + bool checkSimulatedOOM() const + { + return true; } }; Index: ps/trunk/libraries/source/spidermonkey/patch.sh =================================================================== --- ps/trunk/libraries/source/spidermonkey/patch.sh +++ ps/trunk/libraries/source/spidermonkey/patch.sh @@ -2,59 +2,30 @@ # Apply patches if needed # This script gets called from build-osx-libs.sh and build.sh. -# Remove the unnecessary NSPR dependency. -# Will be included in SM52. -# https://bugzilla.mozilla.org/show_bug.cgi?id=1379539 -patch -p1 < ../RemoveNSPRDependency.diff - -# Fix the path to the moz.build file in the zlib module -patch -p1 < ../FixZLibMozBuild.diff - -# === Fix the SM45 tracelogger === -# This patch is a squashed version of several patches that were adapted -# to fix failing hunks. -# -# Applied in the following order, they are: -# * https://bugzilla.mozilla.org/show_bug.cgi?id=1266649 -# Handle failing to add to pointermap gracefully. -# * https://bugzilla.mozilla.org/show_bug.cgi?id=1280648 -# Don't cache based on pointers to movable GC things. -# * https://bugzilla.mozilla.org/show_bug.cgi?id=1255766 -# Also mark resizing of memory. -# * https://bugzilla.mozilla.org/show_bug.cgi?id=1259403 -# Only increase capacity by multiples of 2. -# Always make sure there are 3 free slots for events. -# === -patch -p1 < ../FixTracelogger.diff - # Patch embedded python psutil to work with FreeBSD 12 after revision 315662 # Based on: https://svnweb.freebsd.org/ports/head/sysutils/py-psutil121/files/patch-_psutil_bsd.c?revision=436575&view=markup # psutil will be upgraded in SM60: https://bugzilla.mozilla.org/show_bug.cgi?id=1436857 patch -p0 < ../FixpsutilFreeBSD.diff -# Patch some parts of the code to support extra processor architectures -# Includes: -# * https://bugzilla.mozilla.org/show_bug.cgi?id=1143022 (for arm64) -# * https://bugzilla.mozilla.org/show_bug.cgi?id=1277742 (for aarch64) -# * https://bugzilla.mozilla.org/show_bug.cgi?id=1266366 (for ppc64) -patch -p1 < ../FixNonx86.diff - -# Always link mozglue into the shared library when building standalone. -# Will be included in SM60. Custom version of the patch for SM45, which doesn't have the same build system. -# https://bugzilla.mozilla.org/show_bug.cgi?id=1176787 -patch -p1 < ../FixMozglueStatic.diff - -# JSPropertyDescriptor is not public in SM45. -# Will be fixed in SM52. -# https://bugzilla.mozilla.org/show_bug.cgi?id=1316079 -patch -p1 < ../ExportJSPropertyDescriptor.diff - -# When trying to link pyrogenesis, js::oom::GetThreadType() and js::ReportOutOfMemory() -# are marked as unresolved symbols. -# Will be included in SM52. -# https://bugzilla.mozilla.org/show_bug.cgi?id=1379538 -patch -p1 < ../FixLinking.diff - -# Allow the use of JS::PersistentRootedSymbol in debug builds. -# This check will be removed in SM52. -patch -p1 < ../FixPersistentRootedSymbol.diff +# Static builds have a few issues. +# First, mozglue symbols need to be linked against. This is partly fixed in SM60+, party still there in SM78. +# (see https://bugzilla.mozilla.org/show_bug.cgi?id=1176787 ). +# Secondly, the SDK_LIBRARY flag isn't set. This is still an issue in SM78. +# https://bugzilla.mozilla.org/show_bug.cgi?id=1588340 +patch -p1 < ../FixMozglue.diff + +# Update library names to have separate debug/release libraries. +patch -p1 < ../RenameLibs.diff + +# After https://bugzilla.mozilla.org/show_bug.cgi?id=1289934 landed in +# Firefox 51, MSVC compilation has been broken due to bug +# https://developercommunity.visualstudio.com/content/problem/25334/error-code-c2971-when-specifying-a-function-as-the.html +# (resolved in Visual Studio 2017). The following fix was applied +# to not drop compiler support and will be included in SM 60. +# https://bugzilla.mozilla.org/show_bug.cgi?id=1300925 +patch -p1 < ../FixMSVCBuild.diff + +# GCC 9 and 10 fail to build with -Werror=format, so disable it. +# https://bugs.gentoo.org/693556 +patch -p1 < ../DisableGCC9WerrorFormat.diff + Index: ps/trunk/source/scriptinterface/ScriptTypes.h =================================================================== --- ps/trunk/source/scriptinterface/ScriptTypes.h +++ ps/trunk/source/scriptinterface/ScriptTypes.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -71,7 +71,7 @@ # pragma GCC diagnostic pop #endif -#if MOZJS_MAJOR_VERSION != 45 +#if MOZJS_MAJOR_VERSION != 52 #error Your compiler is trying to use an incorrect major version of the \ SpiderMonkey library. The only version that works is the one in the \ libraries/spidermonkey/ directory, and it will not work with a typical \ @@ -79,7 +79,7 @@ include paths. #endif -#if MOZJS_MINOR_VERSION != 0 +#if MOZJS_MINOR_VERSION != 9 #error Your compiler is trying to use an untested minor version of the \ SpiderMonkey library. If you are a package maintainer, please make sure \ to check very carefully that this version does not change the behaviour \ Index: ps/trunk/source/tools/tracelogger/tracelogger_options.sh =================================================================== --- ps/trunk/source/tools/tracelogger/tracelogger_options.sh +++ ps/trunk/source/tools/tracelogger/tracelogger_options.sh @@ -9,13 +9,15 @@ # The last tested version of the tool is 1c67e97e794b5039d0cae95f72ea0c76e4aa4696, # it can be used if more recent versions cause trouble. +export TLDIR="$(dirname $(realpath $0))" + # Use semicolons to separate values on Windows. # If that produces bogus output, you can try with commas instead. if [ "${OS}" = "Windows_NT" ] then - export TLLOG="Defaults;IonCompiler" + export TLLOG="Default;IonCompiler" export TLOPTIONS="EnableMainThread;EnableOffThread;EnableGraph" else - export TLLOG=Defaults,IonCompiler + export TLLOG=Default,IonCompiler export TLOPTIONS=EnableMainThread,EnableOffThread,EnableGraph fi