Index: ps/trunk/build/premake/extern_libs5.lua =================================================================== --- ps/trunk/build/premake/extern_libs5.lua +++ ps/trunk/build/premake/extern_libs5.lua @@ -538,9 +538,9 @@ }, spidermonkey = { compile_settings = function() - if _OPTIONS["with-system-mozjs52"] then + if _OPTIONS["with-system-mozjs"] then if not _OPTIONS["android"] then - pkgconfig.add_includes("mozjs-52") + pkgconfig.add_includes("mozjs-60") end else if os.istarget("windows") then @@ -558,21 +558,17 @@ end end, link_settings = function() - if _OPTIONS["with-system-mozjs52"] then + if _OPTIONS["with-system-mozjs"] then if _OPTIONS["android"] then - links { "mozjs-52" } + links { "mozjs-60" } else - pkgconfig.add_links("mozjs-52") + pkgconfig.add_links("mozjs-60") end else - filter { "Debug", "action:vs*" } - links { "mozjs52-ps-debug-vc140" } - filter { "Release", "action:vs*" } - links { "mozjs52-ps-release-vc140" } - filter { "Debug", "action:not vs*" } - links { "mozjs52-ps-debug" } - filter { "Release", "action:not vs*" } - links { "mozjs52-ps-release" } + filter { "Debug" } + links { "mozjs60-ps-debug" } + filter { "Release" } + links { "mozjs60-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-mozjs52", description = "Search standard paths for libmozjs52, instead of using bundled copy" } +newoption { trigger = "with-system-mozjs", description = "Search standard paths for libmozjs60, 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/build/workspaces/clean-workspaces.sh =================================================================== --- ps/trunk/build/workspaces/clean-workspaces.sh +++ ps/trunk/build/workspaces/clean-workspaces.sh @@ -33,11 +33,17 @@ (cd ../../libraries/source/fcollada/src && rm -rf ./output) (cd ../../libraries/source/nvtt/src && rm -rf ./build) (cd ../../libraries/source/spidermonkey && rm -f .already-built) - (cd ../../libraries/source/spidermonkey && rm -rf ./mozjs-45.0.2) + (cd ../../libraries/source/spidermonkey && rm -rf ./lib) + (cd ../../libraries/source/spidermonkey && rm -rf ./include-unix-debug) + (cd ../../libraries/source/spidermonkey && rm -rf ./include-unix-release) + (cd ../../libraries/source/spidermonkey && rm -rf ./mozjs-62.9.1) fi # Still delete the directory of previous SpiderMonkey versions to # avoid wasting disk space if people clean workspaces after updating. +(cd ../../libraries/source/spidermonkey && rm -rf ./mozjs-52.9.1pre1) +(cd ../../libraries/source/spidermonkey && rm -rf ./mozjs-45.0.2) +(cd ../../libraries/source/spidermonkey && rm -rf ./mozjs-38.0.0) (cd ../../libraries/source/spidermonkey && rm -rf ./mozjs-38.0.0) (cd ../../libraries/source/spidermonkey && rm -rf ./mozjs31) (cd ../../libraries/source/spidermonkey && rm -rf ./mozjs24) Index: ps/trunk/build/workspaces/update-workspaces.sh =================================================================== --- ps/trunk/build/workspaces/update-workspaces.sh +++ ps/trunk/build/workspaces/update-workspaces.sh @@ -41,7 +41,7 @@ with_system_premake5=false without_nvtt=false with_system_nvtt=false -with_system_mozjs52=false +with_system_mozjs=false enable_atlas=true for i in "$@" @@ -50,7 +50,7 @@ --with-system-premake5 ) with_system_premake5=true ;; --without-nvtt ) without_nvtt=true; premake_args="${premake_args} --without-nvtt" ;; --with-system-nvtt ) with_system_nvtt=true; premake_args="${premake_args} --with-system-nvtt" ;; - --with-system-mozjs52 ) with_system_mozjs52=true; premake_args="${premake_args} --with-system-mozjs52" ;; + --with-system-mozjs ) with_system_mozjs=true; premake_args="${premake_args} --with-system-mozjs" ;; --enable-atlas ) enable_atlas=true ;; --disable-atlas ) enable_atlas=false ;; -j* ) JOBS=$i ;; @@ -87,7 +87,7 @@ # Build/update bundled external libraries (cd ../../libraries/source/fcollada/src && ${MAKE} ${JOBS}) || die "FCollada build failed" echo - if [ "$with_system_mozjs52" = "false" ]; then + if [ "$with_system_mozjs" = "false" ]; then (cd ../../libraries/source/spidermonkey && MAKE=${MAKE} JOBS=${JOBS} ./build.sh) || die "SpiderMonkey build failed" fi echo Index: ps/trunk/libraries/source/spidermonkey/FixMSVCBuild.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/FixMSVCBuild.diff +++ ps/trunk/libraries/source/spidermonkey/FixMSVCBuild.diff @@ -1,447 +0,0 @@ - -# 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 @@ -1,70 +1,12 @@ -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 +index 53758485ac3d..3b5ce063ebb4 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. +@@ -9,6 +9,7 @@ # 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'): + if CONFIG['JS_STANDALONE'] and not CONFIG['MOZ_MEMORY']: + Library('mozglue') ++ FINAL_LIBRARY = 'js' + elif CONFIG['OS_TARGET'] in ('WINNT', 'Darwin', 'Android'): SharedLibrary('mozglue') else: - Library('mozglue') Index: ps/trunk/libraries/source/spidermonkey/FixPersistentRootedSymbol.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/FixPersistentRootedSymbol.diff +++ ps/trunk/libraries/source/spidermonkey/FixPersistentRootedSymbol.diff @@ -1,13 +0,0 @@ -diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h -index 4e925cba04..06d2a95440 100644 ---- a/js/public/RootingAPI.h -+++ b/js/public/RootingAPI.h -@@ -1019,6 +1019,7 @@ class PersistentRooted : public js::PersistentRootedBase, - 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); - Index: ps/trunk/libraries/source/spidermonkey/FixSharedArray.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/FixSharedArray.diff +++ ps/trunk/libraries/source/spidermonkey/FixSharedArray.diff @@ -0,0 +1,11 @@ +--- a/js/public/StructuredClone.h ++++ b/js/public/StructuredClone.h +@@ -328,7 +328,7 @@ + namespace js { + class SharedArrayRawBuffer; + +-class SharedArrayRawBufferRefs { ++class JS_PUBLIC_API SharedArrayRawBufferRefs { + public: + SharedArrayRawBufferRefs() = default; + SharedArrayRawBufferRefs(SharedArrayRawBufferRefs&& other) = default; \ No newline at end of file Index: ps/trunk/libraries/source/spidermonkey/FixpsutilFreeBSD.diff =================================================================== --- ps/trunk/libraries/source/spidermonkey/FixpsutilFreeBSD.diff +++ ps/trunk/libraries/source/spidermonkey/FixpsutilFreeBSD.diff @@ -1,50 +0,0 @@ ---- python/psutil/psutil/_psutil_bsd.c -+++ python/psutil/psutil/_psutil_bsd.c -@@ -957,11 +957,19 @@ psutil_sockaddr_matches(int family, int port, void *pc - psutil_sockaddr_addrlen(family)) == 0); - } - -+#if __FreeBSD_version >= 1200026 -+static struct xtcpcb * -+psutil_search_tcplist(char *buf, struct kinfo_file *kif) -+{ -+ struct xtcpcb *tp; -+ struct xinpcb *inp; -+#else - static struct tcpcb * - psutil_search_tcplist(char *buf, struct kinfo_file *kif) - { - struct tcpcb *tp; - struct inpcb *inp; -+#endif - struct xinpgen *xig, *oxig; - struct xsocket *so; - -@@ -969,9 +977,15 @@ psutil_search_tcplist(char *buf, struct kinfo_file *ki - for (xig = (struct xinpgen *)((char *)xig + xig->xig_len); - xig->xig_len > sizeof(struct xinpgen); - xig = (struct xinpgen *)((char *)xig + xig->xig_len)) { -+#if __FreeBSD_version >= 1200026 -+ tp = (struct xtcpcb *)xig; -+ inp = &tp->xt_inp; -+ so = &inp->xi_socket; -+#else - tp = &((struct xtcpcb *)xig)->xt_tp; - inp = &((struct xtcpcb *)xig)->xt_inp; - so = &((struct xtcpcb *)xig)->xt_socket; -+#endif - - if (so->so_type != kif->kf_sock_type || - so->xso_family != kif->kf_sock_domain || -@@ -1019,7 +1033,11 @@ psutil_proc_connections(PyObject *self, PyObject *args - struct kinfo_file *freep = NULL; - struct kinfo_file *kif; - char *tcplist = NULL; -+#if __FreeBSD_version >= 1200026 -+ struct xtcpcb *tcp; -+#else - struct tcpcb *tcp; -+#endif - - PyObject *retList = PyList_New(0); - PyObject *tuple = NULL; Index: ps/trunk/libraries/source/spidermonkey/README.txt =================================================================== --- ps/trunk/libraries/source/spidermonkey/README.txt +++ ps/trunk/libraries/source/spidermonkey/README.txt @@ -1,8 +1,5 @@ Important notice: ----------------- -This version of SpiderMonkey comes from -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 cause subtle bugs or network out-of-sync errors. @@ -32,26 +29,7 @@ If you still need to build on Windows, here's a short guide. 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.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 2.x (start-shell-msvc2015.bat) -3. Extract nspr to libraries/source/spidermonkey - 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#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 3.x (start-shell.bat) and run ./build.sh. - - +1. Go to https://firefox-source-docs.mozilla.org/setup/windows_build.html#mozillabuild +2. Download the latest mozbuild package and install it to C:/mozilla-build (default). +3. Run MozillaBuild 3.x (start-shell.bat) +4. cd to the build.sh directory and run ./build.sh Index: ps/trunk/libraries/source/spidermonkey/build.sh =================================================================== --- ps/trunk/libraries/source/spidermonkey/build.sh +++ ps/trunk/libraries/source/spidermonkey/build.sh @@ -3,10 +3,10 @@ set -e # This should match the version in config/milestone.txt -FOLDER="mozjs-52.9.1pre1" +FOLDER="mozjs-60.9.1" # If same-version changes are needed, increment this. -LIB_VERSION="52.9.1pre1+2" -LIB_NAME="mozjs52-ps" +LIB_VERSION="60.9.1+0" +LIB_NAME="mozjs60-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. @@ -36,14 +36,14 @@ --disable-jemalloc --disable-js-shell --without-intl-api - --enable-shared-js" # We're linking statically but JS has quirks with static-only compilation. + --enable-shared-js" # NSPR is needed on Windows for POSIX emulation. # If you want to build on Windows, check README.txt and edit the absolute paths # to match your environment. if [ "${OS}" = "Windows_NT" ] then - CONF_OPTS="${CONF_OPTS} --with-nspr-prefix="D:/nspr-4.21/nspr/"" + CONF_OPTS="${CONF_OPTS} --enable-nspr-build --with-visual-studio-version=2015" else CONF_OPTS="${CONF_OPTS} --enable-posix-nspr-emulation" fi @@ -86,7 +86,7 @@ then # The tarball is committed to svn, but it's useful to let jenkins download it (when testing upgrade scripts). download="$(command -v wget || echo "curl -L -o "${FOLDER}.tar.bz2"")" - $download "https://github.com/wraitii/spidermonkey-tarballs/releases/download/v52.9.1/${FOLDER}.tar.bz2" + $download "https://github.com/wraitii/spidermonkey-tarballs/releases/download/v60.9.1/${FOLDER}.tar.bz2" fi tar xjf "${FOLDER}.tar.bz2" @@ -148,10 +148,10 @@ # 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}/build-release/dist/include" - rm mozzconf.h zconf.h zlib.h + rm -f mozzconf.h zconf.h zlib.h popd pushd "${FOLDER}/build-debug/dist/include" - rm mozzconf.h zconf.h zlib.h + rm -f mozzconf.h zconf.h zlib.h popd fi @@ -163,29 +163,36 @@ cp -R -L "${FOLDER}"/build-release/dist/include/* "${INCLUDE_DIR_RELEASE}/" cp -R -L "${FOLDER}"/build-debug/dist/include/* "${INCLUDE_DIR_DEBUG}/" +# These align the ligns below, making it easier to check for mistakes. +DEB="debug" +REL="release" + mkdir -p lib/ if [ "`uname -s`" = "Darwin" ] then - # On MacOS, copy the static library. - 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 MacOS, copy the static libraries only. + cp -L "${FOLDER}/build-${DEB}/js/src/build/${LIB_PREFIX}js_static${LIB_SUFFIX}" "lib/${LIB_PREFIX}${LIB_NAME}-${DEB}${LIB_SUFFIX}" + cp -L "${FOLDER}/build-${REL}/js/src/build/${LIB_PREFIX}js_static${LIB_SUFFIX}" "lib/${LIB_PREFIX}${LIB_NAME}-${REL}${LIB_SUFFIX}" +elif [ "${OS}" = "Windows_NT" ] +then + # Windows needs DLLs to binaries/, static stubs to lib/ and debug symbols + cp -L "${FOLDER}/build-${DEB}/js/src/build/${LIB_PREFIX}${LIB_NAME}-${DEB}${LIB_SUFFIX}" "../../../binaries/system/${LIB_PREFIX}${LIB_NAME}-${DEB}${LIB_SUFFIX}" + cp -L "${FOLDER}/build-${REL}/js/src/build/${LIB_PREFIX}${LIB_NAME}-${REL}${LIB_SUFFIX}" "../../../binaries/system/${LIB_PREFIX}${LIB_NAME}-${REL}${LIB_SUFFIX}" + cp -L "${FOLDER}/build-${DEB}/js/src/build/${LIB_PREFIX}${LIB_NAME}-${DEB}.lib" "lib/${LIB_PREFIX}${LIB_NAME}-${DEB}.lib" + cp -L "${FOLDER}/build-${REL}/js/src/build/${LIB_PREFIX}${LIB_NAME}-${REL}.lib" "lib/${LIB_PREFIX}${LIB_NAME}-${REL}.lib" + # Copy debug symbols as well. + cp -L "${FOLDER}/build-${DEB}/js/src/build/${LIB_PREFIX}${LIB_NAME}-${DEB}.pdb" "../../../binaries/system/${LIB_PREFIX}${LIB_NAME}-${DEB}.pdb" + cp -L "${FOLDER}/build-${REL}/js/src/build/${LIB_PREFIX}${LIB_NAME}-${REL}.pdb" "../../../binaries/system/${LIB_PREFIX}${LIB_NAME}-${REL}.pdb" + # Windows need some additional libraries for posix emulation. + cp -L "${FOLDER}/build-release/dist/bin/${LIB_PREFIX}nspr4.dll" "../../../binaries/system/${LIB_PREFIX}nspr4.dll" + cp -L "${FOLDER}/build-release/dist/bin/${LIB_PREFIX}plc4.dll" "../../../binaries/system/${LIB_PREFIX}plc4.dll" + cp -L "${FOLDER}/build-release/dist/bin/${LIB_PREFIX}plds4.dll" "../../../binaries/system/${LIB_PREFIX}plds4.dll" else - cp -L "${FOLDER}/build-debug/js/src/${LIB_PREFIX}${LIB_NAME}-debug${LIB_SUFFIX}" "lib/${LIB_PREFIX}${LIB_NAME}-debug${LIB_SUFFIX}" - cp -L "${FOLDER}/build-debug/js/src/${LIB_PREFIX}${LIB_NAME}-debug${LIB_SUFFIX}" "../../../binaries/system/${LIB_PREFIX}${LIB_NAME}-debug${LIB_SUFFIX}" - cp -L "${FOLDER}/build-release/js/src/${LIB_PREFIX}${LIB_NAME}-release${LIB_SUFFIX}" "lib/${LIB_PREFIX}${LIB_NAME}-release${LIB_SUFFIX}" - cp -L "${FOLDER}/build-release/js/src/${LIB_PREFIX}${LIB_NAME}-release${LIB_SUFFIX}" "../../../binaries/system/${LIB_PREFIX}${LIB_NAME}-release${LIB_SUFFIX}" -fi - -if [ "${OS}" = "Windows_NT" ] -then - # On Windows, copy also auxiliary libraries. - 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" "../../../binaries/system/${LIB_PREFIX}${LIB_NAME}-debug.dll" - cp -L "${FOLDER}/build-release/js/src/${LIB_PREFIX}mozjs-52-release.dll" "../../../binaries/system/${LIB_PREFIX}${LIB_NAME}-release.dll" - cp -L "${FOLDER}/build-debug/js/src/${LIB_PREFIX}mozjs-52-debug.pdb" "../../../binaries/system/${LIB_PREFIX}${LIB_NAME}-debug.pdb" - cp -L "${FOLDER}/build-release/js/src/${LIB_PREFIX}mozjs-52-release.pdb" "../../../binaries/system/${LIB_PREFIX}${LIB_NAME}-release.pdb" + # Copy shared libs to both lib/ and binaries/ so the compiler and executable (resp.) can find them. + cp -L "${FOLDER}/build-${DEB}/js/src/build/${LIB_PREFIX}${LIB_NAME}-${DEB}${LIB_SUFFIX}" "lib/${LIB_PREFIX}${LIB_NAME}-${DEB}${LIB_SUFFIX}" + cp -L "${FOLDER}/build-${REL}/js/src/build/${LIB_PREFIX}${LIB_NAME}-${REL}${LIB_SUFFIX}" "lib/${LIB_PREFIX}${LIB_NAME}-${REL}${LIB_SUFFIX}" + cp -L "${FOLDER}/build-${DEB}/js/src/build/${LIB_PREFIX}${LIB_NAME}-${DEB}${LIB_SUFFIX}" "../../../binaries/system/${LIB_PREFIX}${LIB_NAME}-${DEB}${LIB_SUFFIX}" + cp -L "${FOLDER}/build-${REL}/js/src/build/${LIB_PREFIX}${LIB_NAME}-${REL}${LIB_SUFFIX}" "../../../binaries/system/${LIB_PREFIX}${LIB_NAME}-${REL}${LIB_SUFFIX}" fi # Flag that it's already been built successfully so we can skip it next time Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/double-conversion/double-conversion.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/double-conversion/double-conversion.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/double-conversion/double-conversion.h @@ -0,0 +1,548 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ +#define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ + +#include "mozilla/Types.h" +#include + +namespace double_conversion { + +class DoubleToStringConverter { + public: + // When calling ToFixed with a double > 10^kMaxFixedDigitsBeforePoint + // or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the + // function returns false. + static const int kMaxFixedDigitsBeforePoint = 60; + static const int kMaxFixedDigitsAfterPoint = 60; + + // When calling ToExponential with a requested_digits + // parameter > kMaxExponentialDigits then the function returns false. + static const int kMaxExponentialDigits = 120; + + // When calling ToPrecision with a requested_digits + // parameter < kMinPrecisionDigits or requested_digits > kMaxPrecisionDigits + // then the function returns false. + static const int kMinPrecisionDigits = 1; + static const int kMaxPrecisionDigits = 120; + + enum Flags { + NO_FLAGS = 0, + EMIT_POSITIVE_EXPONENT_SIGN = 1, + EMIT_TRAILING_DECIMAL_POINT = 2, + EMIT_TRAILING_ZERO_AFTER_POINT = 4, + UNIQUE_ZERO = 8 + }; + + // Flags should be a bit-or combination of the possible Flags-enum. + // - NO_FLAGS: no special flags. + // - EMIT_POSITIVE_EXPONENT_SIGN: when the number is converted into exponent + // form, emits a '+' for positive exponents. Example: 1.2e+2. + // - EMIT_TRAILING_DECIMAL_POINT: when the input number is an integer and is + // converted into decimal format then a trailing decimal point is appended. + // Example: 2345.0 is converted to "2345.". + // - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point + // emits a trailing '0'-character. This flag requires the + // EXMIT_TRAILING_DECIMAL_POINT flag. + // Example: 2345.0 is converted to "2345.0". + // - UNIQUE_ZERO: "-0.0" is converted to "0.0". + // + // Infinity symbol and nan_symbol provide the string representation for these + // special values. If the string is NULL and the special value is encountered + // then the conversion functions return false. + // + // The exponent_character is used in exponential representations. It is + // usually 'e' or 'E'. + // + // When converting to the shortest representation the converter will + // represent input numbers in decimal format if they are in the interval + // [10^decimal_in_shortest_low; 10^decimal_in_shortest_high[ + // (lower boundary included, greater boundary excluded). + // Example: with decimal_in_shortest_low = -6 and + // decimal_in_shortest_high = 21: + // ToShortest(0.000001) -> "0.000001" + // ToShortest(0.0000001) -> "1e-7" + // ToShortest(111111111111111111111.0) -> "111111111111111110000" + // ToShortest(100000000000000000000.0) -> "100000000000000000000" + // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21" + // + // When converting to precision mode the converter may add + // max_leading_padding_zeroes before returning the number in exponential + // format. + // Example with max_leading_padding_zeroes_in_precision_mode = 6. + // ToPrecision(0.0000012345, 2) -> "0.0000012" + // ToPrecision(0.00000012345, 2) -> "1.2e-7" + // Similarily the converter may add up to + // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid + // returning an exponential representation. A zero added by the + // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit. + // Examples for max_trailing_padding_zeroes_in_precision_mode = 1: + // ToPrecision(230.0, 2) -> "230" + // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT. + // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT. + DoubleToStringConverter(int flags, + const char* infinity_symbol, + const char* nan_symbol, + char exponent_character, + int decimal_in_shortest_low, + int decimal_in_shortest_high, + int max_leading_padding_zeroes_in_precision_mode, + int max_trailing_padding_zeroes_in_precision_mode) + : flags_(flags), + infinity_symbol_(infinity_symbol), + nan_symbol_(nan_symbol), + exponent_character_(exponent_character), + decimal_in_shortest_low_(decimal_in_shortest_low), + decimal_in_shortest_high_(decimal_in_shortest_high), + max_leading_padding_zeroes_in_precision_mode_( + max_leading_padding_zeroes_in_precision_mode), + max_trailing_padding_zeroes_in_precision_mode_( + max_trailing_padding_zeroes_in_precision_mode) { + // When 'trailing zero after the point' is set, then 'trailing point' + // must be set too. + ASSERT(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) || + !((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0)); + } + + // Returns a converter following the EcmaScript specification. + static MFBT_API const DoubleToStringConverter& EcmaScriptConverter(); + + // Computes the shortest string of digits that correctly represent the input + // number. Depending on decimal_in_shortest_low and decimal_in_shortest_high + // (see constructor) it then either returns a decimal representation, or an + // exponential representation. + // Example with decimal_in_shortest_low = -6, + // decimal_in_shortest_high = 21, + // EMIT_POSITIVE_EXPONENT_SIGN activated, and + // EMIT_TRAILING_DECIMAL_POINT deactived: + // ToShortest(0.000001) -> "0.000001" + // ToShortest(0.0000001) -> "1e-7" + // ToShortest(111111111111111111111.0) -> "111111111111111110000" + // ToShortest(100000000000000000000.0) -> "100000000000000000000" + // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21" + // + // Note: the conversion may round the output if the returned string + // is accurate enough to uniquely identify the input-number. + // For example the most precise representation of the double 9e59 equals + // "899999999999999918767229449717619953810131273674690656206848", but + // the converter will return the shorter (but still correct) "9e59". + // + // Returns true if the conversion succeeds. The conversion always succeeds + // except when the input value is special and no infinity_symbol or + // nan_symbol has been given to the constructor. + bool ToShortest(double value, StringBuilder* result_builder) const { + return ToShortestIeeeNumber(value, result_builder, SHORTEST); + } + + // Same as ToShortest, but for single-precision floats. + bool ToShortestSingle(float value, StringBuilder* result_builder) const { + return ToShortestIeeeNumber(value, result_builder, SHORTEST_SINGLE); + } + + + // Computes a decimal representation with a fixed number of digits after the + // decimal point. The last emitted digit is rounded. + // + // Examples: + // ToFixed(3.12, 1) -> "3.1" + // ToFixed(3.1415, 3) -> "3.142" + // ToFixed(1234.56789, 4) -> "1234.5679" + // ToFixed(1.23, 5) -> "1.23000" + // ToFixed(0.1, 4) -> "0.1000" + // ToFixed(1e30, 2) -> "1000000000000000019884624838656.00" + // ToFixed(0.1, 30) -> "0.100000000000000005551115123126" + // ToFixed(0.1, 17) -> "0.10000000000000001" + // + // If requested_digits equals 0, then the tail of the result depends on + // the EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT. + // Examples, for requested_digits == 0, + // let EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT be + // - false and false: then 123.45 -> 123 + // 0.678 -> 1 + // - true and false: then 123.45 -> 123. + // 0.678 -> 1. + // - true and true: then 123.45 -> 123.0 + // 0.678 -> 1.0 + // + // Returns true if the conversion succeeds. The conversion always succeeds + // except for the following cases: + // - the input value is special and no infinity_symbol or nan_symbol has + // been provided to the constructor, + // - 'value' > 10^kMaxFixedDigitsBeforePoint, or + // - 'requested_digits' > kMaxFixedDigitsAfterPoint. + // The last two conditions imply that the result will never contain more than + // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters + // (one additional character for the sign, and one for the decimal point). + MFBT_API bool ToFixed(double value, + int requested_digits, + StringBuilder* result_builder) const; + + // Computes a representation in exponential format with requested_digits + // after the decimal point. The last emitted digit is rounded. + // If requested_digits equals -1, then the shortest exponential representation + // is computed. + // + // Examples with EMIT_POSITIVE_EXPONENT_SIGN deactivated, and + // exponent_character set to 'e'. + // ToExponential(3.12, 1) -> "3.1e0" + // ToExponential(5.0, 3) -> "5.000e0" + // ToExponential(0.001, 2) -> "1.00e-3" + // ToExponential(3.1415, -1) -> "3.1415e0" + // ToExponential(3.1415, 4) -> "3.1415e0" + // ToExponential(3.1415, 3) -> "3.142e0" + // ToExponential(123456789000000, 3) -> "1.235e14" + // ToExponential(1000000000000000019884624838656.0, -1) -> "1e30" + // ToExponential(1000000000000000019884624838656.0, 32) -> + // "1.00000000000000001988462483865600e30" + // ToExponential(1234, 0) -> "1e3" + // + // Returns true if the conversion succeeds. The conversion always succeeds + // except for the following cases: + // - the input value is special and no infinity_symbol or nan_symbol has + // been provided to the constructor, + // - 'requested_digits' > kMaxExponentialDigits. + // The last condition implies that the result will never contain more than + // kMaxExponentialDigits + 8 characters (the sign, the digit before the + // decimal point, the decimal point, the exponent character, the + // exponent's sign, and at most 3 exponent digits). + MFBT_API bool ToExponential(double value, + int requested_digits, + StringBuilder* result_builder) const; + + // Computes 'precision' leading digits of the given 'value' and returns them + // either in exponential or decimal format, depending on + // max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the + // constructor). + // The last computed digit is rounded. + // + // Example with max_leading_padding_zeroes_in_precision_mode = 6. + // ToPrecision(0.0000012345, 2) -> "0.0000012" + // ToPrecision(0.00000012345, 2) -> "1.2e-7" + // Similarily the converter may add up to + // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid + // returning an exponential representation. A zero added by the + // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit. + // Examples for max_trailing_padding_zeroes_in_precision_mode = 1: + // ToPrecision(230.0, 2) -> "230" + // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT. + // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT. + // Examples for max_trailing_padding_zeroes_in_precision_mode = 3, and no + // EMIT_TRAILING_ZERO_AFTER_POINT: + // ToPrecision(123450.0, 6) -> "123450" + // ToPrecision(123450.0, 5) -> "123450" + // ToPrecision(123450.0, 4) -> "123500" + // ToPrecision(123450.0, 3) -> "123000" + // ToPrecision(123450.0, 2) -> "1.2e5" + // + // Returns true if the conversion succeeds. The conversion always succeeds + // except for the following cases: + // - the input value is special and no infinity_symbol or nan_symbol has + // been provided to the constructor, + // - precision < kMinPericisionDigits + // - precision > kMaxPrecisionDigits + // The last condition implies that the result will never contain more than + // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the + // exponent character, the exponent's sign, and at most 3 exponent digits). + MFBT_API bool ToPrecision(double value, + int precision, + bool* used_exponential_notation, + StringBuilder* result_builder) const; + + enum DtoaMode { + // Produce the shortest correct representation. + // For example the output of 0.299999999999999988897 is (the less accurate + // but correct) 0.3. + SHORTEST, + // Same as SHORTEST, but for single-precision floats. + SHORTEST_SINGLE, + // Produce a fixed number of digits after the decimal point. + // For instance fixed(0.1, 4) becomes 0.1000 + // If the input number is big, the output will be big. + FIXED, + // Fixed number of digits (independent of the decimal point). + PRECISION + }; + + // The maximal number of digits that are needed to emit a double in base 10. + // A higher precision can be achieved by using more digits, but the shortest + // accurate representation of any double will never use more digits than + // kBase10MaximalLength. + // Note that DoubleToAscii null-terminates its input. So the given buffer + // should be at least kBase10MaximalLength + 1 characters long. + static const MFBT_DATA int kBase10MaximalLength = 17; + + // Converts the given double 'v' to ascii. 'v' must not be NaN, +Infinity, or + // -Infinity. In SHORTEST_SINGLE-mode this restriction also applies to 'v' + // after it has been casted to a single-precision float. That is, in this + // mode static_cast(v) must not be NaN, +Infinity or -Infinity. + // + // The result should be interpreted as buffer * 10^(point-length). + // + // The output depends on the given mode: + // - SHORTEST: produce the least amount of digits for which the internal + // identity requirement is still satisfied. If the digits are printed + // (together with the correct exponent) then reading this number will give + // 'v' again. The buffer will choose the representation that is closest to + // 'v'. If there are two at the same distance, than the one farther away + // from 0 is chosen (halfway cases - ending with 5 - are rounded up). + // In this mode the 'requested_digits' parameter is ignored. + // - SHORTEST_SINGLE: same as SHORTEST but with single-precision. + // - FIXED: produces digits necessary to print a given number with + // 'requested_digits' digits after the decimal point. The produced digits + // might be too short in which case the caller has to fill the remainder + // with '0's. + // Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2. + // Halfway cases are rounded towards +/-Infinity (away from 0). The call + // toFixed(0.15, 2) thus returns buffer="2", point=0. + // The returned buffer may contain digits that would be truncated from the + // shortest representation of the input. + // - PRECISION: produces 'requested_digits' where the first digit is not '0'. + // Even though the length of produced digits usually equals + // 'requested_digits', the function is allowed to return fewer digits, in + // which case the caller has to fill the missing digits with '0's. + // Halfway cases are again rounded away from 0. + // DoubleToAscii expects the given buffer to be big enough to hold all + // digits and a terminating null-character. In SHORTEST-mode it expects a + // buffer of at least kBase10MaximalLength + 1. In all other modes the + // requested_digits parameter and the padding-zeroes limit the size of the + // output. Don't forget the decimal point, the exponent character and the + // terminating null-character when computing the maximal output size. + // The given length is only used in debug mode to ensure the buffer is big + // enough. + static MFBT_API void DoubleToAscii(double v, + DtoaMode mode, + int requested_digits, + char* buffer, + int buffer_length, + bool* sign, + int* length, + int* point); + + private: + // Implementation for ToShortest and ToShortestSingle. + MFBT_API bool ToShortestIeeeNumber(double value, + StringBuilder* result_builder, + DtoaMode mode) const; + + // If the value is a special value (NaN or Infinity) constructs the + // corresponding string using the configured infinity/nan-symbol. + // If either of them is NULL or the value is not special then the + // function returns false. + MFBT_API bool HandleSpecialValues(double value, StringBuilder* result_builder) const; + // Constructs an exponential representation (i.e. 1.234e56). + // The given exponent assumes a decimal point after the first decimal digit. + MFBT_API void CreateExponentialRepresentation(const char* decimal_digits, + int length, + int exponent, + StringBuilder* result_builder) const; + // Creates a decimal representation (i.e 1234.5678). + MFBT_API void CreateDecimalRepresentation(const char* decimal_digits, + int length, + int decimal_point, + int digits_after_point, + StringBuilder* result_builder) const; + + const int flags_; + const char* const infinity_symbol_; + const char* const nan_symbol_; + const char exponent_character_; + const int decimal_in_shortest_low_; + const int decimal_in_shortest_high_; + const int max_leading_padding_zeroes_in_precision_mode_; + const int max_trailing_padding_zeroes_in_precision_mode_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter); +}; + + +class StringToDoubleConverter { + public: + // Enumeration for allowing octals and ignoring junk when converting + // strings to numbers. + enum Flags { + NO_FLAGS = 0, + ALLOW_HEX = 1, + ALLOW_OCTALS = 2, + ALLOW_TRAILING_JUNK = 4, + ALLOW_LEADING_SPACES = 8, + ALLOW_TRAILING_SPACES = 16, + ALLOW_SPACES_AFTER_SIGN = 32, + ALLOW_CASE_INSENSIBILITY = 64, + }; + + // Flags should be a bit-or combination of the possible Flags-enum. + // - NO_FLAGS: no special flags. + // - ALLOW_HEX: recognizes the prefix "0x". Hex numbers may only be integers. + // Ex: StringToDouble("0x1234") -> 4660.0 + // In StringToDouble("0x1234.56") the characters ".56" are trailing + // junk. The result of the call is hence dependent on + // the ALLOW_TRAILING_JUNK flag and/or the junk value. + // With this flag "0x" is a junk-string. Even with ALLOW_TRAILING_JUNK, + // the string will not be parsed as "0" followed by junk. + // + // - ALLOW_OCTALS: recognizes the prefix "0" for octals: + // If a sequence of octal digits starts with '0', then the number is + // read as octal integer. Octal numbers may only be integers. + // Ex: StringToDouble("01234") -> 668.0 + // StringToDouble("012349") -> 12349.0 // Not a sequence of octal + // // digits. + // In StringToDouble("01234.56") the characters ".56" are trailing + // junk. The result of the call is hence dependent on + // the ALLOW_TRAILING_JUNK flag and/or the junk value. + // In StringToDouble("01234e56") the characters "e56" are trailing + // junk, too. + // - ALLOW_TRAILING_JUNK: ignore trailing characters that are not part of + // a double literal. + // - ALLOW_LEADING_SPACES: skip over leading whitespace, including spaces, + // new-lines, and tabs. + // - ALLOW_TRAILING_SPACES: ignore trailing whitespace. + // - ALLOW_SPACES_AFTER_SIGN: ignore whitespace after the sign. + // Ex: StringToDouble("- 123.2") -> -123.2. + // StringToDouble("+ 123.2") -> 123.2 + // - ALLOW_CASE_INSENSIBILITY: ignore case of characters for special values: + // infinity and nan. + // + // empty_string_value is returned when an empty string is given as input. + // If ALLOW_LEADING_SPACES or ALLOW_TRAILING_SPACES are set, then a string + // containing only spaces is converted to the 'empty_string_value', too. + // + // junk_string_value is returned when + // a) ALLOW_TRAILING_JUNK is not set, and a junk character (a character not + // part of a double-literal) is found. + // b) ALLOW_TRAILING_JUNK is set, but the string does not start with a + // double literal. + // + // infinity_symbol and nan_symbol are strings that are used to detect + // inputs that represent infinity and NaN. They can be null, in which case + // they are ignored. + // The conversion routine first reads any possible signs. Then it compares the + // following character of the input-string with the first character of + // the infinity, and nan-symbol. If either matches, the function assumes, that + // a match has been found, and expects the following input characters to match + // the remaining characters of the special-value symbol. + // This means that the following restrictions apply to special-value symbols: + // - they must not start with signs ('+', or '-'), + // - they must not have the same first character. + // - they must not start with digits. + // + // Examples: + // flags = ALLOW_HEX | ALLOW_TRAILING_JUNK, + // empty_string_value = 0.0, + // junk_string_value = NaN, + // infinity_symbol = "infinity", + // nan_symbol = "nan": + // StringToDouble("0x1234") -> 4660.0. + // StringToDouble("0x1234K") -> 4660.0. + // StringToDouble("") -> 0.0 // empty_string_value. + // StringToDouble(" ") -> NaN // junk_string_value. + // StringToDouble(" 1") -> NaN // junk_string_value. + // StringToDouble("0x") -> NaN // junk_string_value. + // StringToDouble("-123.45") -> -123.45. + // StringToDouble("--123.45") -> NaN // junk_string_value. + // StringToDouble("123e45") -> 123e45. + // StringToDouble("123E45") -> 123e45. + // StringToDouble("123e+45") -> 123e45. + // StringToDouble("123E-45") -> 123e-45. + // StringToDouble("123e") -> 123.0 // trailing junk ignored. + // StringToDouble("123e-") -> 123.0 // trailing junk ignored. + // StringToDouble("+NaN") -> NaN // NaN string literal. + // StringToDouble("-infinity") -> -inf. // infinity literal. + // StringToDouble("Infinity") -> NaN // junk_string_value. + // + // flags = ALLOW_OCTAL | ALLOW_LEADING_SPACES, + // empty_string_value = 0.0, + // junk_string_value = NaN, + // infinity_symbol = NULL, + // nan_symbol = NULL: + // StringToDouble("0x1234") -> NaN // junk_string_value. + // StringToDouble("01234") -> 668.0. + // StringToDouble("") -> 0.0 // empty_string_value. + // StringToDouble(" ") -> 0.0 // empty_string_value. + // StringToDouble(" 1") -> 1.0 + // StringToDouble("0x") -> NaN // junk_string_value. + // StringToDouble("0123e45") -> NaN // junk_string_value. + // StringToDouble("01239E45") -> 1239e45. + // StringToDouble("-infinity") -> NaN // junk_string_value. + // StringToDouble("NaN") -> NaN // junk_string_value. + StringToDoubleConverter(int flags, + double empty_string_value, + double junk_string_value, + const char* infinity_symbol, + const char* nan_symbol) + : flags_(flags), + empty_string_value_(empty_string_value), + junk_string_value_(junk_string_value), + infinity_symbol_(infinity_symbol), + nan_symbol_(nan_symbol) { + } + + // Performs the conversion. + // The output parameter 'processed_characters_count' is set to the number + // of characters that have been processed to read the number. + // Spaces than are processed with ALLOW_{LEADING|TRAILING}_SPACES are included + // in the 'processed_characters_count'. Trailing junk is never included. + double StringToDouble(const char* buffer, + int length, + int* processed_characters_count) const; + + // Same as StringToDouble above but for 16 bit characters. + double StringToDouble(const uc16* buffer, + int length, + int* processed_characters_count) const; + + // Same as StringToDouble but reads a float. + // Note that this is not equivalent to static_cast(StringToDouble(...)) + // due to potential double-rounding. + float StringToFloat(const char* buffer, + int length, + int* processed_characters_count) const; + + // Same as StringToFloat above but for 16 bit characters. + float StringToFloat(const uc16* buffer, + int length, + int* processed_characters_count) const; + + private: + const int flags_; + const double empty_string_value_; + const double junk_string_value_; + const char* const infinity_symbol_; + const char* const nan_symbol_; + + template + double StringToIeee(Iterator start_pointer, + int length, + bool read_as_double, + int* processed_characters_count) const; + + DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter); +}; + +} // namespace double_conversion + +#endif // DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/double-conversion/utils.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/double-conversion/utils.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/double-conversion/utils.h @@ -0,0 +1,326 @@ +// Copyright 2010 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef DOUBLE_CONVERSION_UTILS_H_ +#define DOUBLE_CONVERSION_UTILS_H_ + +#include +#include + +#include "mozilla/Assertions.h" +#ifndef ASSERT +#define ASSERT(condition) \ + MOZ_ASSERT(condition) +#endif +#ifndef UNIMPLEMENTED +#define UNIMPLEMENTED() MOZ_CRASH() +#endif +#ifndef DOUBLE_CONVERSION_NO_RETURN +#ifdef _MSC_VER +#define DOUBLE_CONVERSION_NO_RETURN __declspec(noreturn) +#else +#define DOUBLE_CONVERSION_NO_RETURN __attribute__((noreturn)) +#endif +#endif +#ifndef UNREACHABLE +#ifdef _MSC_VER +void DOUBLE_CONVERSION_NO_RETURN abort_noreturn(); +inline void abort_noreturn() { MOZ_CRASH(); } +#define UNREACHABLE() (abort_noreturn()) +#else +#define UNREACHABLE() MOZ_CRASH() +#endif +#endif + + +// Double operations detection based on target architecture. +// Linux uses a 80bit wide floating point stack on x86. This induces double +// rounding, which in turn leads to wrong results. +// An easy way to test if the floating-point operations are correct is to +// evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then +// the result is equal to 89255e-22. +// The best way to test this, is to create a division-function and to compare +// the output of the division with the expected result. (Inlining must be +// disabled.) +// On Linux,x86 89255e-22 != Div_double(89255.0/1e22) +#if defined(_M_X64) || defined(__x86_64__) || \ + defined(__ARMEL__) || defined(__avr32__) || \ + defined(__hppa__) || defined(__ia64__) || \ + defined(__mips__) || \ + defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \ + defined(_POWER) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \ + defined(__sparc__) || defined(__sparc) || defined(__s390__) || \ + defined(__SH4__) || defined(__alpha__) || \ + defined(_MIPS_ARCH_MIPS32R2) || \ + defined(__AARCH64EL__) || defined(__aarch64__) || \ + defined(__riscv) +#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 +#elif defined(__mc68000__) +#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS +#elif defined(_M_IX86) || defined(__i386__) || defined(__i386) +#if defined(_WIN32) +// Windows uses a 64bit wide floating point stack. +#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 +#else +#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS +#endif // _WIN32 +#else +#error Target architecture was not detected as supported by Double-Conversion. +#endif + +#if defined(__GNUC__) +#define DOUBLE_CONVERSION_UNUSED __attribute__((unused)) +#else +#define DOUBLE_CONVERSION_UNUSED +#endif + +#include + +typedef uint16_t uc16; + +// The following macro works on both 32 and 64-bit platforms. +// Usage: instead of writing 0x1234567890123456 +// write UINT64_2PART_C(0x12345678,90123456); +#define UINT64_2PART_C(a, b) (((static_cast(a) << 32) + 0x##b##u)) + + +// The expression ARRAY_SIZE(a) is a compile-time constant of type +// size_t which represents the number of elements of the given +// array. You should only use ARRAY_SIZE on statically allocated +// arrays. +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) \ + ((sizeof(a) / sizeof(*(a))) / \ + static_cast(!(sizeof(a) % sizeof(*(a))))) +#endif + +// A macro to disallow the evil copy constructor and operator= functions +// This should be used in the private: declarations for a class +#ifndef DISALLOW_COPY_AND_ASSIGN +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) +#endif + +// A macro to disallow all the implicit constructors, namely the +// default constructor, copy constructor and operator= functions. +// +// This should be used in the private: declarations for a class +// that wants to prevent anyone from instantiating it. This is +// especially useful for classes containing only static methods. +#ifndef DISALLOW_IMPLICIT_CONSTRUCTORS +#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ + TypeName(); \ + DISALLOW_COPY_AND_ASSIGN(TypeName) +#endif + +namespace double_conversion { + +static const int kCharSize = sizeof(char); + +// Returns the maximum of the two parameters. +template +static T Max(T a, T b) { + return a < b ? b : a; +} + + +// Returns the minimum of the two parameters. +template +static T Min(T a, T b) { + return a < b ? a : b; +} + + +inline int StrLength(const char* string) { + size_t length = strlen(string); + ASSERT(length == static_cast(static_cast(length))); + return static_cast(length); +} + +// This is a simplified version of V8's Vector class. +template +class Vector { + public: + Vector() : start_(NULL), length_(0) {} + Vector(T* data, int len) : start_(data), length_(len) { + ASSERT(len == 0 || (len > 0 && data != NULL)); + } + + // Returns a vector using the same backing storage as this one, + // spanning from and including 'from', to but not including 'to'. + Vector SubVector(int from, int to) { + ASSERT(to <= length_); + ASSERT(from < to); + ASSERT(0 <= from); + return Vector(start() + from, to - from); + } + + // Returns the length of the vector. + int length() const { return length_; } + + // Returns whether or not the vector is empty. + bool is_empty() const { return length_ == 0; } + + // Returns the pointer to the start of the data in the vector. + T* start() const { return start_; } + + // Access individual vector elements - checks bounds in debug mode. + T& operator[](int index) const { + ASSERT(0 <= index && index < length_); + return start_[index]; + } + + T& first() { return start_[0]; } + + T& last() { return start_[length_ - 1]; } + + private: + T* start_; + int length_; +}; + + +// Helper class for building result strings in a character buffer. The +// purpose of the class is to use safe operations that checks the +// buffer bounds on all operations in debug mode. +class StringBuilder { + public: + StringBuilder(char* buffer, int buffer_size) + : buffer_(buffer, buffer_size), position_(0) { } + + ~StringBuilder() { if (!is_finalized()) Finalize(); } + + int size() const { return buffer_.length(); } + + // Get the current position in the builder. + int position() const { + ASSERT(!is_finalized()); + return position_; + } + + // Reset the position. + void Reset() { position_ = 0; } + + // Add a single character to the builder. It is not allowed to add + // 0-characters; use the Finalize() method to terminate the string + // instead. + void AddCharacter(char c) { + ASSERT(c != '\0'); + ASSERT(!is_finalized() && position_ < buffer_.length()); + buffer_[position_++] = c; + } + + // Add an entire string to the builder. Uses strlen() internally to + // compute the length of the input string. + void AddString(const char* s) { + AddSubstring(s, StrLength(s)); + } + + // Add the first 'n' characters of the given string 's' to the + // builder. The input string must have enough characters. + void AddSubstring(const char* s, int n) { + ASSERT(!is_finalized() && position_ + n < buffer_.length()); + ASSERT(static_cast(n) <= strlen(s)); + memmove(&buffer_[position_], s, n * kCharSize); + position_ += n; + } + + + // Add character padding to the builder. If count is non-positive, + // nothing is added to the builder. + void AddPadding(char c, int count) { + for (int i = 0; i < count; i++) { + AddCharacter(c); + } + } + + // Finalize the string by 0-terminating it and returning the buffer. + char* Finalize() { + ASSERT(!is_finalized() && position_ < buffer_.length()); + buffer_[position_] = '\0'; + // Make sure nobody managed to add a 0-character to the + // buffer while building the string. + ASSERT(strlen(buffer_.start()) == static_cast(position_)); + position_ = -1; + ASSERT(is_finalized()); + return buffer_.start(); + } + + private: + Vector buffer_; + int position_; + + bool is_finalized() const { return position_ < 0; } + + DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder); +}; + +// The type-based aliasing rule allows the compiler to assume that pointers of +// different types (for some definition of different) never alias each other. +// Thus the following code does not work: +// +// float f = foo(); +// int fbits = *(int*)(&f); +// +// The compiler 'knows' that the int pointer can't refer to f since the types +// don't match, so the compiler may cache f in a register, leaving random data +// in fbits. Using C++ style casts makes no difference, however a pointer to +// char data is assumed to alias any other pointer. This is the 'memcpy +// exception'. +// +// Bit_cast uses the memcpy exception to move the bits from a variable of one +// type of a variable of another type. Of course the end result is likely to +// be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005) +// will completely optimize BitCast away. +// +// There is an additional use for BitCast. +// Recent gccs will warn when they see casts that may result in breakage due to +// the type-based aliasing rule. If you have checked that there is no breakage +// you can use BitCast to cast one pointer type to another. This confuses gcc +// enough that it can no longer see that you have cast one pointer type to +// another thus avoiding the warning. +template +inline Dest BitCast(const Source& source) { + // Compile time assertion: sizeof(Dest) == sizeof(Source) + // A compile error here means your Dest and Source have different sizes. + DOUBLE_CONVERSION_UNUSED + typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1]; + + Dest dest; + memmove(&dest, &source, sizeof(dest)); + return dest; +} + +template +inline Dest BitCast(Source* source) { + return BitCast(reinterpret_cast(source)); +} + +} // namespace double_conversion + +#endif // DOUBLE_CONVERSION_UTILS_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 @@ -1,61 +1,61 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=78: - * - * 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_config_h -#define js_config_h - -/* Definitions set at build time that affect SpiderMonkey's public API. - This header file is generated by the SpiderMonkey configure script, - and installed along with jsapi.h. */ - -/* 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 */ - -/* Define to 1 if SpiderMonkey should support multi-threaded clients. */ -/* #undef JS_THREADSAFE */ - -/* Define to 1 if SpiderMonkey should include ctypes support. */ -/* #undef JS_HAS_CTYPES */ - -/* Define to 1 if SpiderMonkey should support the ability to perform - entirely too much GC. */ -#define JS_GC_ZEAL 1 - -/* Define to 1 if SpiderMonkey should use small chunks. */ -/* #undef JS_GC_SMALL_CHUNK_SIZE */ - -/* Define to 1 to perform extra assertions and heap poisoning. */ -/* #undef JS_CRASH_DIAGNOSTICS */ - -/* Define to 1 if SpiderMonkey is in NUNBOX32 mode. */ -#define JS_NUNBOX32 1 - -/* Define to 1 if SpiderMonkey is in PUNBOX64 mode. */ -/* #undef JS_PUNBOX64 */ - -/* MOZILLA JSAPI version number components */ -#define MOZJS_MAJOR_VERSION 52 -#define MOZJS_MINOR_VERSION 9 - -#endif /* js_config_h */ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * 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_config_h +#define js_config_h + +/* Definitions set at build time that affect SpiderMonkey's public API. + This header file is generated by the SpiderMonkey configure script, + and installed along with jsapi.h. */ + +/* 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 */ + +/* Define to 1 if SpiderMonkey should support multi-threaded clients. */ +/* #undef JS_THREADSAFE */ + +/* Define to 1 if SpiderMonkey should include ctypes support. */ +/* #undef JS_HAS_CTYPES */ + +/* Define to 1 if SpiderMonkey should support the ability to perform + entirely too much GC. */ +#define JS_GC_ZEAL 1 + +/* Define to 1 if SpiderMonkey should use small chunks. */ +/* #undef JS_GC_SMALL_CHUNK_SIZE */ + +/* Define to 1 to perform extra assertions and heap poisoning. */ +/* #undef JS_CRASH_DIAGNOSTICS */ + +/* Define to 1 if SpiderMonkey is in NUNBOX32 mode. */ +#define JS_NUNBOX32 1 + +/* Define to 1 if SpiderMonkey is in PUNBOX64 mode. */ +/* #undef JS_PUNBOX64 */ + +/* MOZILLA JSAPI version number components */ +#define MOZJS_MAJOR_VERSION 60 +#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 @@ -19,9 +19,7 @@ * is an integer literal specifying the total number of * replaceable arguments in the following format string. * - * is an exception index from the enum in jsexn.c; - * JSEXN_NONE for none. The given exception index will be raised by the - * engine when the corresponding error occurs. + * is an enum JSExnType value, defined in jsapi.h. * * is a string literal, optionally containing sequences * {X} where X is an integer representing the argument number that will @@ -29,7 +27,7 @@ * * e.g. * - * MSG_DEF(JSMSG_NOT_A_SUBSPECIES, 2, JSEXN_NONE, + * MSG_DEF(JSMSG_NOT_A_SUBSPECIES, 2, JSEXN_TYPEERROR, * "{0} is not a member of the {1} family") * * can be used: @@ -38,7 +36,7 @@ * * to report: * - * "Rhino is not a member of the Monkey family" + * "TypeError: Rhino is not a member of the Monkey family" */ MSG_DEF(JSMSG_NOT_AN_ERROR, 0, JSEXN_ERR, "") @@ -47,7 +45,6 @@ MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}") MSG_DEF(JSMSG_NO_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} has no constructor") MSG_DEF(JSMSG_BAD_SORT_ARG, 0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument") -MSG_DEF(JSMSG_CANT_WATCH, 1, JSEXN_TYPEERR, "can't watch non-native objects of class {0}") MSG_DEF(JSMSG_READ_ONLY, 1, JSEXN_TYPEERR, "{0} is read-only") MSG_DEF(JSMSG_CANT_DELETE, 1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted") MSG_DEF(JSMSG_CANT_TRUNCATE_ARRAY, 0, JSEXN_TYPEERR, "can't delete non-configurable array element") @@ -58,31 +55,34 @@ MSG_DEF(JSMSG_TOPRIMITIVE_RETURNED_OBJECT, 2, JSEXN_TYPEERR, "can't convert {0} to {1}: its [Symbol.toPrimitive] method returned an object") MSG_DEF(JSMSG_NO_PROPERTIES, 1, JSEXN_TYPEERR, "{0} has no properties") MSG_DEF(JSMSG_BAD_REGEXP_FLAG, 1, JSEXN_SYNTAXERR, "invalid regular expression flag {0}") -MSG_DEF(JSMSG_ARG_INDEX_OUT_OF_RANGE, 1, JSEXN_RANGEERR, "argument {0} accesses an index that is out of range") +MSG_DEF(JSMSG_INVALID_DATA_VIEW_LENGTH, 0, JSEXN_RANGEERR, "invalid data view length") +MSG_DEF(JSMSG_OFFSET_LARGER_THAN_FILESIZE, 0, JSEXN_RANGEERR, "offset is larger than filesize") +MSG_DEF(JSMSG_OFFSET_OUT_OF_BUFFER, 0, JSEXN_RANGEERR, "start offset is outside the bounds of the buffer") +MSG_DEF(JSMSG_OFFSET_OUT_OF_DATAVIEW, 0, JSEXN_RANGEERR, "offset is outside the bounds of the DataView") MSG_DEF(JSMSG_SPREAD_TOO_LARGE, 0, JSEXN_RANGEERR, "array too large due to spread operand(s)") 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_PREV, 2, JSEXN_NOTE, "Previously declared at line {0}, column {1}") MSG_DEF(JSMSG_REDECLARED_VAR, 2, JSEXN_SYNTAXERR, "redeclaration of {0} {1}") MSG_DEF(JSMSG_UNDECLARED_VAR, 1, JSEXN_REFERENCEERR, "assignment to undeclared variable {0}") -MSG_DEF(JSMSG_GETTER_ONLY, 0, JSEXN_TYPEERR, "setting a property that has only a getter") +MSG_DEF(JSMSG_GETTER_ONLY, 1, JSEXN_TYPEERR, "setting getter-only property {0}") MSG_DEF(JSMSG_OVERWRITING_ACCESSOR, 1, JSEXN_TYPEERR, "can't overwrite accessor property {0}") MSG_DEF(JSMSG_UNDEFINED_PROP, 1, JSEXN_REFERENCEERR, "reference to undefined property {0}") 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_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_BUILTIN_CTOR_NO_NEW, 1, JSEXN_TYPEERR, "calling a builtin {0} constructor without new is forbidden") -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}") MSG_DEF(JSMSG_MISSING_FUN_ARG, 2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}") MSG_DEF(JSMSG_NOT_NONNULL_OBJECT, 1, JSEXN_TYPEERR, "{0} is not a non-null object") -MSG_DEF(JSMSG_SET_NON_OBJECT_RECEIVER, 1, JSEXN_TYPEERR, "can't assign to properties of {0}: not an object") +MSG_DEF(JSMSG_NOT_NONNULL_OBJECT_NAME, 2, JSEXN_TYPEERR, "{0} must be an object, got {1}") +MSG_DEF(JSMSG_NOT_NONNULL_OBJECT_ARG, 3, JSEXN_TYPEERR, "{0} argument of {1} must be an object, got {2}") +MSG_DEF(JSMSG_SET_NON_OBJECT_RECEIVER, 2, JSEXN_TYPEERR, "can't assign to property {1} on {0}: not an object") MSG_DEF(JSMSG_INVALID_DESCRIPTOR, 0, JSEXN_TYPEERR, "property descriptors must not specify a value or be writable when a getter or setter has been specified") MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE, 1, JSEXN_TYPEERR, "{0}: Object is not extensible") MSG_DEF(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE, 2, JSEXN_TYPEERR, "can't define property {1}: {0} is not extensible") @@ -93,20 +93,20 @@ 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_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_ITER_METHOD_RETURNED_PRIMITIVE, 1, JSEXN_TYPEERR, "iterator.{0}() 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}") MSG_DEF(JSMSG_CANT_SET_PROTO_CYCLE, 0, JSEXN_TYPEERR, "can't set prototype: it would cause a prototype chain cycle") MSG_DEF(JSMSG_INVALID_ARG_TYPE, 3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}") MSG_DEF(JSMSG_TERMINATED, 1, JSEXN_ERR, "Script terminated by timeout at:\n{0}") -MSG_DEF(JSMSG_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_UNINITIALIZED_THIS, 1, JSEXN_REFERENCEERR, "must call super constructor before using |this| in {0} class constructor") +MSG_DEF(JSMSG_UNINITIALIZED_THIS_ARROW, 0, JSEXN_REFERENCEERR, "must call super constructor before using |this| in arrow function in derived class constructor") MSG_DEF(JSMSG_BAD_DERIVED_RETURN, 1, JSEXN_TYPEERR, "derived class constructor returned invalid value {0}") +MSG_DEF(JSMSG_BAD_HERITAGE, 2, JSEXN_TYPEERR, "class heritage {0} is {1}") +MSG_DEF(JSMSG_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0} is not an object or null") // JSON MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data") @@ -116,7 +116,8 @@ MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS, 1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}") MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS, 0, JSEXN_REFERENCEERR, "invalid assignment left-hand side") MSG_DEF(JSMSG_BAD_PROTOTYPE, 1, JSEXN_TYPEERR, "'prototype' property of {0} is not an object") -MSG_DEF(JSMSG_IN_NOT_OBJECT, 1, JSEXN_TYPEERR, "invalid 'in' operand {0}") +MSG_DEF(JSMSG_IN_NOT_OBJECT, 1, JSEXN_TYPEERR, "right-hand side of 'in' should be an object, got {0}") +MSG_DEF(JSMSG_IN_STRING, 2, JSEXN_TYPEERR, "cannot use 'in' operator to search for '{0}' in '{1}'") MSG_DEF(JSMSG_TOO_MANY_CON_SPREADARGS, 0, JSEXN_RANGEERR, "too many constructor arguments") 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") @@ -133,6 +134,7 @@ MSG_DEF(JSMSG_NEGATIVE_REPETITION_COUNT, 0, JSEXN_RANGEERR, "repeat count must be non-negative") MSG_DEF(JSMSG_NOT_A_CODEPOINT, 1, JSEXN_RANGEERR, "{0} is not a valid code point") MSG_DEF(JSMSG_RESULTING_STRING_TOO_LARGE, 0, JSEXN_RANGEERR, "repeat count must be less than infinity and not overflow maximum string size") +MSG_DEF(JSMSG_DEPRECATED_STRING_METHOD, 2, JSEXN_WARN, "String.{0} is deprecated; use String.prototype.{1} instead") // Number MSG_DEF(JSMSG_BAD_RADIX, 0, JSEXN_RANGEERR, "radix must be an integer at least 2 and no greater than 36") @@ -155,7 +157,8 @@ // Wrappers MSG_DEF(JSMSG_ACCESSOR_DEF_DENIED, 1, JSEXN_ERR, "Permission denied to define accessor property {0}") MSG_DEF(JSMSG_DEAD_OBJECT, 0, JSEXN_TYPEERR, "can't access dead object") -MSG_DEF(JSMSG_UNWRAP_DENIED, 0, JSEXN_ERR, "permission denied to unwrap object") +MSG_DEF(JSMSG_OBJECT_ACCESS_DENIED, 0, JSEXN_ERR, "Permission denied to access object") +MSG_DEF(JSMSG_PROPERTY_ACCESS_DENIED, 1, JSEXN_ERR, "Permission denied to access property {0}") // JSAPI-only (Not thrown as JS exceptions) MSG_DEF(JSMSG_BAD_CLONE_FUNOBJ_SCOPE, 0, JSEXN_TYPEERR, "bad cloned function scope chain") @@ -180,13 +183,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 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_AWAIT_OUTSIDE_ASYNC, 0, JSEXN_SYNTAXERR, "await is only valid in async functions and async generators") MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)") MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated") MSG_DEF(JSMSG_BAD_CONST_DECL, 0, JSEXN_SYNTAXERR, "missing = in const declaration") @@ -200,23 +201,22 @@ 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_INCOP_OPERAND, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand") MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition") MSG_DEF(JSMSG_BAD_OCTAL, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant") -MSG_DEF(JSMSG_BAD_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, "'{0}' can't be defined or assigned to in strict mode code") +MSG_DEF(JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS, 0, JSEXN_SYNTAXERR, "'arguments' can't be defined or assigned to in strict mode code") +MSG_DEF(JSMSG_BAD_STRICT_ASSIGN_EVAL, 0, JSEXN_SYNTAXERR, "'eval' 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") MSG_DEF(JSMSG_BAD_SUPERCALL, 0, JSEXN_SYNTAXERR, "super() is only valid in derived class constructors") -MSG_DEF(JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION, 0, JSEXN_SYNTAXERR, "missing ] after array comprehension") MSG_DEF(JSMSG_BRACKET_AFTER_LIST, 0, JSEXN_SYNTAXERR, "missing ] after element list") MSG_DEF(JSMSG_BRACKET_IN_INDEX, 0, JSEXN_SYNTAXERR, "missing ] in index expression") +MSG_DEF(JSMSG_BRACKET_OPENED, 2, JSEXN_NOTE, "[ opened at line {0}, column {1}") MSG_DEF(JSMSG_CATCH_AFTER_GENERAL, 0, JSEXN_SYNTAXERR, "catch after unconditional catch") MSG_DEF(JSMSG_CATCH_IDENTIFIER, 0, JSEXN_SYNTAXERR, "missing identifier in catch") MSG_DEF(JSMSG_CATCH_OR_FINALLY, 0, JSEXN_SYNTAXERR, "missing catch or finally after try") @@ -227,6 +227,7 @@ MSG_DEF(JSMSG_COMP_PROP_UNTERM_EXPR, 0, JSEXN_SYNTAXERR, "missing ] in computed property name") MSG_DEF(JSMSG_CONTRARY_NONDIRECTIVE, 1, JSEXN_SYNTAXERR, "'{0}' statement won't be enforced as a directive because it isn't in directive prologue position") MSG_DEF(JSMSG_CURLY_AFTER_BODY, 0, JSEXN_SYNTAXERR, "missing } after function body") +MSG_DEF(JSMSG_CURLY_OPENED, 2, JSEXN_NOTE, "{ opened at line {0}, column {1}") 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_LIST, 0, JSEXN_SYNTAXERR, "missing } after property list") @@ -256,15 +257,19 @@ 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_FOR_AWAIT_OUTSIDE_ASYNC, 0, JSEXN_SYNTAXERR, "for await (... of ...) is only valid in async functions and async generators") 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_BAD_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid escape sequence") 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_OF_AFTER_FOR_LOOP_DECL, 0, JSEXN_SYNTAXERR, "a declaration in the head of a for-of loop can't have an initializer") +MSG_DEF(JSMSG_IN_AFTER_LEXICAL_FOR_DECL,0,JSEXN_SYNTAXERR, "a lexical declaration in the head of a for-in loop can't have an initializer") MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers") +MSG_DEF(JSMSG_INVALID_ID, 1, JSEXN_SYNTAXERR, "{0} is an invalid identifier") MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found") -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") @@ -313,7 +318,6 @@ MSG_DEF(JSMSG_SELFHOSTED_UNBOUND_NAME, 0, JSEXN_TYPEERR, "self-hosted code may not contain unbound name lookups") 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_WARN, "unreachable code after return statement") MSG_DEF(JSMSG_STRICT_CODE_WITH, 0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements") @@ -329,18 +333,21 @@ MSG_DEF(JSMSG_TOO_MANY_YIELDS, 0, JSEXN_SYNTAXERR, "too many yield expressions") MSG_DEF(JSMSG_TOUGH_BREAK, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch") MSG_DEF(JSMSG_UNEXPECTED_TOKEN, 2, JSEXN_SYNTAXERR, "expected {0}, got {1}") +MSG_DEF(JSMSG_UNEXPECTED_TOKEN_NO_EXPECT, 1, JSEXN_SYNTAXERR, "unexpected token: {0}") +MSG_DEF(JSMSG_UNEXPECTED_PARAMLIST_END,0, JSEXN_SYNTAXERR, "unexpected end of function parameter list") MSG_DEF(JSMSG_UNNAMED_CLASS_STMT, 0, JSEXN_SYNTAXERR, "class statement requires a name") MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT, 0, JSEXN_SYNTAXERR, "function statement requires a name") MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 0, JSEXN_SYNTAXERR, "unterminated comment") MSG_DEF(JSMSG_UNTERMINATED_REGEXP, 0, JSEXN_SYNTAXERR, "unterminated regular expression literal") -MSG_DEF(JSMSG_UNTERMINATED_STRING, 0, JSEXN_SYNTAXERR, "unterminated string literal") +MSG_DEF(JSMSG_EOF_BEFORE_END_OF_LITERAL,1,JSEXN_SYNTAXERR, "{0} literal not terminated before end of script") +MSG_DEF(JSMSG_EOL_BEFORE_END_OF_STRING,1, JSEXN_SYNTAXERR, "{0} string literal contains an unescaped line break") +MSG_DEF(JSMSG_EOF_IN_ESCAPE_IN_LITERAL,1, JSEXN_SYNTAXERR, "reached end of script in the middle of an escape sequence in a {0} literal") MSG_DEF(JSMSG_USELESS_EXPR, 0, JSEXN_TYPEERR, "useless expression") MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL, 0, JSEXN_SYNTAXERR, "\"use asm\" is only meaningful in the Directive Prologue of a function body") MSG_DEF(JSMSG_VAR_HIDES_ARG, 1, JSEXN_TYPEERR, "variable {0} redeclares argument") MSG_DEF(JSMSG_WHILE_AFTER_DO, 0, JSEXN_SYNTAXERR, "missing while after do-loop body") -MSG_DEF(JSMSG_YIELD_IN_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_YIELD_OUTSIDE_GENERATOR, 0, JSEXN_SYNTAXERR, "yield expression is only valid in generators") MSG_DEF(JSMSG_BAD_COLUMN_NUMBER, 0, JSEXN_RANGEERR, "column number out of range") MSG_DEF(JSMSG_COMPUTED_NAME_IN_PATTERN,0, JSEXN_SYNTAXERR, "computed property names aren't supported in this destructuring declaration") MSG_DEF(JSMSG_DEFAULT_IN_PATTERN, 0, JSEXN_SYNTAXERR, "destructuring defaults aren't supported in this destructuring declaration") @@ -354,6 +361,16 @@ // wasm MSG_DEF(JSMSG_WASM_COMPILE_ERROR, 1, JSEXN_WASMCOMPILEERROR, "{0}") +MSG_DEF(JSMSG_WASM_NO_SHMEM_COMPILE, 0, JSEXN_WASMCOMPILEERROR, "shared memory is disabled") +MSG_DEF(JSMSG_WASM_BAD_IMPORT_TYPE, 2, JSEXN_WASMLINKERROR, "import object field '{0}' is not a {1}") +MSG_DEF(JSMSG_WASM_BAD_IMPORT_SIG, 2, JSEXN_WASMLINKERROR, "imported function '{0}.{1}' signature mismatch") +MSG_DEF(JSMSG_WASM_BAD_IMP_SIZE, 1, JSEXN_WASMLINKERROR, "imported {0} with incompatible size") +MSG_DEF(JSMSG_WASM_BAD_IMP_MAX, 1, JSEXN_WASMLINKERROR, "imported {0} with incompatible maximum size") +MSG_DEF(JSMSG_WASM_IMP_SHARED_REQD, 0, JSEXN_WASMLINKERROR, "imported unshared memory but shared required") +MSG_DEF(JSMSG_WASM_IMP_SHARED_BANNED, 0, JSEXN_WASMLINKERROR, "imported shared memory but unshared required") +MSG_DEF(JSMSG_WASM_BAD_FIT, 2, JSEXN_WASMLINKERROR, "{0} segment does not fit in {1}") +MSG_DEF(JSMSG_WASM_BAD_I64_LINK, 0, JSEXN_WASMLINKERROR, "cannot pass i64 to or from JS") +MSG_DEF(JSMSG_WASM_NO_SHMEM_LINK, 0, JSEXN_WASMLINKERROR, "shared memory is disabled") MSG_DEF(JSMSG_WASM_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") @@ -362,23 +379,24 @@ 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_WAKE_OVERFLOW, 0, JSEXN_WASMRUNTIMEERROR, "too many woken agents") MSG_DEF(JSMSG_WASM_BAD_UINT32, 2, JSEXN_RANGEERR, "bad {0} {1}") MSG_DEF(JSMSG_WASM_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_IMPORT_FIELD, 1, JSEXN_TYPEERR, "import object field '{0}' is not an Object") MSG_DEF(JSMSG_WASM_BAD_TABLE_VALUE, 0, JSEXN_TYPEERR, "can only assign WebAssembly exported functions to Table") -MSG_DEF(JSMSG_WASM_BAD_I64, 0, JSEXN_TYPEERR, "cannot pass i64 to or from JS") +MSG_DEF(JSMSG_WASM_BAD_I64_TYPE, 0, JSEXN_TYPEERR, "cannot pass i64 to or from JS") +MSG_DEF(JSMSG_WASM_BAD_GLOBAL_TYPE, 0, JSEXN_TYPEERR, "bad type for a WebAssembly.Global") MSG_DEF(JSMSG_WASM_NO_TRANSFER, 0, JSEXN_TYPEERR, "cannot transfer WebAssembly/asm.js ArrayBuffer") +MSG_DEF(JSMSG_WASM_STREAM_ERROR, 0, JSEXN_TYPEERR, "stream error during WebAssembly compilation") MSG_DEF(JSMSG_WASM_TEXT_FAIL, 1, JSEXN_SYNTAXERR, "wasm text error: {0}") +MSG_DEF(JSMSG_WASM_MISSING_MAXIMUM, 0, JSEXN_TYPEERR, "'shared' is true but maximum is not specified") +MSG_DEF(JSMSG_WASM_GLOBAL_IMMUTABLE, 0, JSEXN_TYPEERR, "can't set value of immutable global") // Proxy MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE, 2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value") @@ -388,31 +406,30 @@ 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") -MSG_DEF(JSMSG_CANT_DEFINE_NE_AS_NC, 0, JSEXN_TYPEERR, "proxy can't define a non-existent property as non-configurable") +MSG_DEF(JSMSG_CANT_DEFINE_INVALID, 2, JSEXN_TYPEERR, "proxy can't define an incompatible property descriptor ('{0}', {1})") +MSG_DEF(JSMSG_CANT_DEFINE_NEW, 1, JSEXN_TYPEERR, "proxy can't define a new property '{0}' on a non-extensible object") +MSG_DEF(JSMSG_CANT_DEFINE_NE_AS_NC, 1, JSEXN_TYPEERR, "proxy can't define a non-existent '{0}' property as non-configurable") MSG_DEF(JSMSG_PROXY_DEFINE_RETURNED_FALSE, 1, JSEXN_TYPEERR, "proxy defineProperty handler returned false for property '{0}'") MSG_DEF(JSMSG_PROXY_DELETE_RETURNED_FALSE, 1, JSEXN_TYPEERR, "can't delete property '{0}': proxy deleteProperty handler returned false") MSG_DEF(JSMSG_PROXY_PREVENTEXTENSIONS_RETURNED_FALSE, 0, JSEXN_TYPEERR, "proxy preventExtensions handler returned false") MSG_DEF(JSMSG_PROXY_SET_RETURNED_FALSE, 1, JSEXN_TYPEERR, "proxy set handler returned false for property '{0}'") MSG_DEF(JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE, 0, JSEXN_TYPEERR, "proxy can't report an extensible object as non-extensible") -MSG_DEF(JSMSG_CANT_REPORT_C_AS_NC, 0, JSEXN_TYPEERR, "proxy can't report existing configurable property as non-configurable") -MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE, 0, JSEXN_TYPEERR, "proxy can't report an existing own property as non-existent on a non-extensible object") -MSG_DEF(JSMSG_CANT_REPORT_INVALID, 0, JSEXN_TYPEERR, "proxy can't report an incompatible property descriptor") -MSG_DEF(JSMSG_CANT_REPORT_NC_AS_NE, 0, JSEXN_TYPEERR, "proxy can't report a non-configurable own property as non-existent") -MSG_DEF(JSMSG_CANT_REPORT_NEW, 0, JSEXN_TYPEERR, "proxy can't report a new property on a non-extensible object") -MSG_DEF(JSMSG_CANT_REPORT_NE_AS_NC, 0, JSEXN_TYPEERR, "proxy can't report a non-existent property as non-configurable") -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_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") -MSG_DEF(JSMSG_OBJECT_ACCESS_DENIED, 0, JSEXN_ERR, "Permission denied to access object") -MSG_DEF(JSMSG_PROPERTY_ACCESS_DENIED, 1, JSEXN_ERR, "Permission denied to access property {0}") +MSG_DEF(JSMSG_CANT_REPORT_C_AS_NC, 1, JSEXN_TYPEERR, "proxy can't report existing configurable property '{0}' as non-configurable") +MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE, 1, JSEXN_TYPEERR, "proxy can't report an existing own property '{0}' as non-existent on a non-extensible object") +MSG_DEF(JSMSG_CANT_REPORT_INVALID, 2, JSEXN_TYPEERR, "proxy can't report an incompatible property descriptor ('{0}', {1})") +MSG_DEF(JSMSG_CANT_REPORT_NC_AS_NE, 1, JSEXN_TYPEERR, "proxy can't report a non-configurable own property '{0}' as non-existent") +MSG_DEF(JSMSG_CANT_REPORT_NEW, 1, JSEXN_TYPEERR, "proxy can't report a new property '{0}' on a non-extensible object") +MSG_DEF(JSMSG_CANT_REPORT_NE_AS_NC, 1, JSEXN_TYPEERR, "proxy can't report a non-existent property '{0}' as non-configurable") +MSG_DEF(JSMSG_CANT_SET_NW_NC, 1, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property '{0}'") +MSG_DEF(JSMSG_CANT_SET_WO_SETTER, 1, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property '{0}' without a setter") +MSG_DEF(JSMSG_CANT_SKIP_NC, 1, JSEXN_TYPEERR, "proxy can't skip a non-configurable property '{0}'") +MSG_DEF(JSMSG_OWNKEYS_STR_SYM, 0, JSEXN_TYPEERR, "proxy [[OwnPropertyKeys]] must return an array with only string and symbol elements") +MSG_DEF(JSMSG_OWNKEYS_DUPLICATE, 1, JSEXN_TYPEERR, "proxy [[OwnPropertyKeys]] can't report property '{0}' more than once") +MSG_DEF(JSMSG_MUST_REPORT_SAME_VALUE, 1, JSEXN_TYPEERR, "proxy must report the same value for the non-writable, non-configurable property '{0}'") +MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED, 1, JSEXN_TYPEERR, "proxy must report undefined for a non-configurable accessor property '{0}' without a getter") MSG_DEF(JSMSG_PROXY_CONSTRUCT_OBJECT, 0, JSEXN_TYPEERR, "proxy [[Construct]] must return an object") MSG_DEF(JSMSG_PROXY_EXTENSIBILITY, 0, JSEXN_TYPEERR, "proxy must report same extensiblitity as target") -MSG_DEF(JSMSG_PROXY_GETOWN_OBJORUNDEF, 0, JSEXN_TYPEERR, "proxy [[GetOwnProperty]] must return an object or undefined") +MSG_DEF(JSMSG_PROXY_GETOWN_OBJORUNDEF, 1, JSEXN_TYPEERR, "proxy [[GetOwnProperty]] must return an object or undefined for property '{0}'") 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") @@ -424,12 +441,13 @@ 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_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") +MSG_DEF(JSMSG_SC_SAB_REFCNT_OFLO, 0, JSEXN_TYPEERR, "SharedArrayBuffer has too many references") +MSG_DEF(JSMSG_SC_SHMEM_TRANSFERABLE, 0, JSEXN_TYPEERR, "Shared memory objects must not be in the transfer list") +MSG_DEF(JSMSG_SC_SHMEM_POLICY, 0, JSEXN_TYPEERR, "Policy object must forbid cloning shared memory objects cross-process") // 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}") @@ -462,6 +480,10 @@ 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") +MSG_DEF(JSMSG_DEBUG_NO_BINARY_SOURCE, 0, JSEXN_ERR, "WebAssembly binary source is not available") + +// Testing functions +MSG_DEF(JSMSG_TESTING_SCRIPTS_ONLY, 0, JSEXN_TYPEERR, "only works on scripts") // Tracelogger MSG_DEF(JSMSG_TRACELOGGER_ENABLE_FAIL, 1, JSEXN_ERR, "enabling tracelogger failed: {0}") @@ -470,9 +492,10 @@ MSG_DEF(JSMSG_DATE_NOT_FINITE, 0, JSEXN_RANGEERR, "date value is not finite in DateTimeFormat.format()") MSG_DEF(JSMSG_INTERNAL_INTL_ERROR, 0, JSEXN_ERR, "internal error while computing Intl data") MSG_DEF(JSMSG_INTL_OBJECT_NOT_INITED, 3, JSEXN_TYPEERR, "Intl.{0}.prototype.{1} called on value that's not an object initialized as a {2}") -MSG_DEF(JSMSG_INTL_OBJECT_REINITED, 0, JSEXN_TYPEERR, "can't initialize object twice as an object of an Intl constructor") MSG_DEF(JSMSG_INVALID_CURRENCY_CODE, 1, JSEXN_RANGEERR, "invalid currency code in NumberFormat(): {0}") MSG_DEF(JSMSG_INVALID_DIGITS_VALUE, 1, JSEXN_RANGEERR, "invalid digits value: {0}") +MSG_DEF(JSMSG_INVALID_KEYS_TYPE, 0, JSEXN_TYPEERR, "calendar info keys must be an object or undefined") +MSG_DEF(JSMSG_INVALID_KEY, 1, JSEXN_RANGEERR, "invalid key: {0}") MSG_DEF(JSMSG_INVALID_LANGUAGE_TAG, 1, JSEXN_RANGEERR, "invalid language tag: {0}") MSG_DEF(JSMSG_INVALID_LOCALES_ELEMENT, 0, JSEXN_TYPEERR, "invalid element in locales argument") MSG_DEF(JSMSG_INVALID_LOCALE_MATCHER, 1, JSEXN_RANGEERR, "invalid locale matcher in supportedLocalesOf(): {0}") @@ -497,7 +520,7 @@ 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_UNICODE_OVERFLOW, 1, JSEXN_SYNTAXERR, "Unicode codepoint must not be greater than 0x10FFFF in {0}") MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression") MSG_DEF(JSMSG_UNTERM_CLASS, 0, JSEXN_SYNTAXERR, "unterminated character class") @@ -547,7 +570,7 @@ // Atomics and futexes 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_WAIT_NOT_ALLOWED, 0, JSEXN_TYPEERR, "waiting is not allowed on this thread") // XPConnect wrappers and DOM bindings MSG_DEF(JSMSG_CANT_SET_INTERPOSED, 1, JSEXN_TYPEERR, "unable to set interposed data property '{0}'") @@ -564,14 +587,13 @@ // Modules MSG_DEF(JSMSG_BAD_DEFAULT_EXPORT, 0, JSEXN_SYNTAXERR, "default export cannot be provided by export *") -MSG_DEF(JSMSG_MISSING_INDIRECT_EXPORT, 1, JSEXN_SYNTAXERR, "indirect export '{0}' not found") -MSG_DEF(JSMSG_AMBIGUOUS_INDIRECT_EXPORT, 1, JSEXN_SYNTAXERR, "ambiguous indirect export '{0}'") -MSG_DEF(JSMSG_MISSING_IMPORT, 1, JSEXN_SYNTAXERR, "import '{0}' not found") -MSG_DEF(JSMSG_AMBIGUOUS_IMPORT, 1, JSEXN_SYNTAXERR, "ambiguous import '{0}'") +MSG_DEF(JSMSG_MISSING_INDIRECT_EXPORT, 0, JSEXN_SYNTAXERR, "indirect export not found") +MSG_DEF(JSMSG_AMBIGUOUS_INDIRECT_EXPORT, 0, JSEXN_SYNTAXERR, "ambiguous indirect export") +MSG_DEF(JSMSG_MISSING_IMPORT, 0, JSEXN_SYNTAXERR, "import not found") +MSG_DEF(JSMSG_AMBIGUOUS_IMPORT, 0, JSEXN_SYNTAXERR, "ambiguous import") 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") +MSG_DEF(JSMSG_BAD_MODULE_STATUS, 0, JSEXN_INTERNALERR, "module record has unexpected status") // Promise MSG_DEF(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself.") @@ -579,3 +601,49 @@ 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.") + +// Iterator +MSG_DEF(JSMSG_RETURN_NOT_CALLABLE, 0, JSEXN_TYPEERR, "property 'return' of iterator is not callable") +MSG_DEF(JSMSG_ITERATOR_NO_THROW, 0, JSEXN_TYPEERR, "iterator does not have a 'throw' method") + +// Async Iteration +MSG_DEF(JSMSG_FOR_AWAIT_NOT_OF, 0, JSEXN_SYNTAXERR, "'for await' loop should be used with 'of'") +MSG_DEF(JSMSG_NOT_AN_ASYNC_GENERATOR, 0, JSEXN_TYPEERR, "Not an async generator") +MSG_DEF(JSMSG_NOT_AN_ASYNC_ITERATOR, 0, JSEXN_TYPEERR, "Not an async from sync iterator") +MSG_DEF(JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.asyncIterator]() returned a non-object value") + +// ReadableStream +MSG_DEF(JSMSG_READABLESTREAM_UNDERLYINGSOURCE_TYPE_WRONG,0, JSEXN_RANGEERR,"'underlyingSource.type' must be \"bytes\" or undefined.") +MSG_DEF(JSMSG_READABLESTREAM_INVALID_READER_MODE, 0, JSEXN_RANGEERR,"'mode' must be \"byob\" or undefined.") +MSG_DEF(JSMSG_NUMBER_MUST_BE_FINITE_NON_NEGATIVE, 1, JSEXN_RANGEERR, "'{0}' must be a finite, non-negative number.") +MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_BYTESWRITTEN, 0, JSEXN_RANGEERR, "'bytesWritten' exceeds remaining length.") +MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_VIEW_SIZE, 0, JSEXN_RANGEERR, "view size does not match requested data.") +MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_VIEW_OFFSET, 0, JSEXN_RANGEERR, "view offset does not match requested position.") +MSG_DEF(JSMSG_READABLESTREAM_NOT_LOCKED, 1, JSEXN_TYPEERR, "'{0}' may only be called on a locked stream.") +MSG_DEF(JSMSG_READABLESTREAM_LOCKED, 0, JSEXN_TYPEERR, "A Reader may only be created for an unlocked ReadableStream.") +MSG_DEF(JSMSG_READABLESTREAM_NOT_BYTE_STREAM_CONTROLLER, 1, JSEXN_TYPEERR, "{0} requires a ReadableByteStreamController.") +MSG_DEF(JSMSG_READABLESTREAM_NOT_DEFAULT_CONTROLLER, 1, JSEXN_TYPEERR, "{0} requires a ReadableStreamDefaultController.") +MSG_DEF(JSMSG_READABLESTREAM_CONTROLLER_SET, 0, JSEXN_TYPEERR, "The ReadableStream already has a controller defined.") +MSG_DEF(JSMSG_READABLESTREAMREADER_NOT_OWNED, 1, JSEXN_TYPEERR, "The ReadableStream reader method '{0}' may only be called on a reader owned by a stream.") +MSG_DEF(JSMSG_READABLESTREAMREADER_NOT_EMPTY, 1, JSEXN_TYPEERR, "The ReadableStream reader method '{0}' may not be called on a reader with read requests.") +MSG_DEF(JSMSG_READABLESTREAMBYOBREADER_READ_EMPTY_VIEW, 0, JSEXN_TYPEERR, "ReadableStreamBYOBReader.read() was passed an empty TypedArrayBuffer view.") +MSG_DEF(JSMSG_READABLESTREAMREADER_RELEASED, 0, JSEXN_TYPEERR, "The ReadableStream reader was released.") +MSG_DEF(JSMSG_READABLESTREAMCONTROLLER_CLOSED, 1, JSEXN_TYPEERR, "'{0}' called on a stream already closing.") +MSG_DEF(JSMSG_READABLESTREAMCONTROLLER_NOT_READABLE, 1, JSEXN_TYPEERR, "'{0}' may only be called on a stream in the 'readable' state.") +MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_BAD_CHUNKSIZE,0, JSEXN_RANGEERR, "ReadableByteStreamController requires a positive integer or undefined for 'autoAllocateChunkSize'.") +MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_BAD_CHUNK, 1, JSEXN_TYPEERR, "{0} passed a bad chunk.") +MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_CLOSE_PENDING_PULL, 0, JSEXN_TYPEERR, "The ReadableByteStreamController cannot be closed while the buffer is being filled.") +MSG_DEF(JSMSG_READABLESTREAMBYOBREQUEST_NO_CONTROLLER, 1, JSEXN_TYPEERR, "ReadableStreamBYOBRequest method '{0}' called on a request with no controller.") +MSG_DEF(JSMSG_READABLESTREAMBYOBREQUEST_RESPOND_CLOSED, 0, JSEXN_TYPEERR, "ReadableStreamBYOBRequest method 'respond' called with non-zero number of bytes with a closed controller.") +MSG_DEF(JSMSG_READABLESTREAM_METHOD_NOT_IMPLEMENTED, 1, JSEXN_TYPEERR, "ReadableStream method {0} not yet implemented") + +// Other Stream-related +MSG_DEF(JSMSG_STREAM_INVALID_HIGHWATERMARK, 0, JSEXN_RANGEERR, "'highWaterMark' must be a non-negative, non-NaN number.") + +// Response-related +MSG_DEF(JSMSG_ERROR_CONSUMING_RESPONSE, 0, JSEXN_TYPEERR, "there was an error consuming the Response") +MSG_DEF(JSMSG_BAD_RESPONSE_VALUE, 0, JSEXN_TYPEERR, "expected Response or Promise resolving to Response") +MSG_DEF(JSMSG_BAD_RESPONSE_MIME_TYPE, 0, JSEXN_TYPEERR, "Response has unsupported MIME type") +MSG_DEF(JSMSG_BAD_RESPONSE_CORS_SAME_ORIGIN, 0, JSEXN_TYPEERR, "Response.type must be 'basic', 'cors' or 'default'") +MSG_DEF(JSMSG_BAD_RESPONSE_STATUS, 0, JSEXN_TYPEERR, "Response does not have ok status") +MSG_DEF(JSMSG_RESPONSE_ALREADY_CONSUMED, 0, JSEXN_TYPEERR, "Response already consumed") Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/AllocPolicy.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/AllocPolicy.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/AllocPolicy.h @@ -0,0 +1,183 @@ +/* -*- 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/. */ + +/* + * JS allocation policies. + * + * The allocators here are for system memory with lifetimes which are not + * managed by the GC. See the comment at the top of vm/MallocProvider.h. + */ + +#ifndef js_AllocPolicy_h +#define js_AllocPolicy_h + +#include "js/TypeDecls.h" +#include "js/Utility.h" + +extern JS_PUBLIC_API void JS_ReportOutOfMemory(JSContext* cx); + +namespace js { + +enum class AllocFunction { Malloc, Calloc, Realloc }; +/* Policy for using system memory functions and doing no error reporting. */ +class SystemAllocPolicy { + public: + template + T* maybe_pod_malloc(size_t numElems) { + return js_pod_malloc(numElems); + } + template + T* maybe_pod_calloc(size_t numElems) { + return js_pod_calloc(numElems); + } + template + T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) { + return js_pod_realloc(p, oldSize, newSize); + } + template + T* pod_malloc(size_t numElems) { + return maybe_pod_malloc(numElems); + } + template + T* pod_calloc(size_t numElems) { + return maybe_pod_calloc(numElems); + } + template + T* pod_realloc(T* p, size_t oldSize, size_t newSize) { + return maybe_pod_realloc(p, oldSize, newSize); + } + void free_(void* p) { js_free(p); } + void reportAllocOverflow() const {} + bool checkSimulatedOOM() const { return !js::oom::ShouldFailWithOOM(); } +}; + +JS_FRIEND_API void ReportOutOfMemory(JSContext* cx); + +/* + * Allocation policy that calls the system memory functions and reports errors + * to the context. Since the JSContext given on construction is stored for + * the lifetime of the container, this policy may only be used for containers + * whose lifetime is a shorter than the given JSContext. + * + * FIXME bug 647103 - rewrite this in terms of temporary allocation functions, + * not the system ones. + */ +class TempAllocPolicy { + JSContext* const cx_; + + /* + * Non-inline helper to call JSRuntime::onOutOfMemory with minimal + * code bloat. + */ + JS_FRIEND_API void* onOutOfMemory(AllocFunction allocFunc, size_t nbytes, + void* reallocPtr = nullptr); + + template + T* onOutOfMemoryTyped(AllocFunction allocFunc, size_t numElems, + void* reallocPtr = nullptr) { + size_t bytes; + if (MOZ_UNLIKELY(!CalculateAllocSize(numElems, &bytes))) return nullptr; + return static_cast(onOutOfMemory(allocFunc, bytes, reallocPtr)); + } + + public: + MOZ_IMPLICIT TempAllocPolicy(JSContext* cx) : cx_(cx) {} + + template + T* maybe_pod_malloc(size_t numElems) { + return js_pod_malloc(numElems); + } + + template + T* maybe_pod_calloc(size_t numElems) { + return js_pod_calloc(numElems); + } + + template + T* maybe_pod_realloc(T* prior, size_t oldSize, size_t newSize) { + return js_pod_realloc(prior, oldSize, newSize); + } + + template + T* pod_malloc(size_t numElems) { + T* p = maybe_pod_malloc(numElems); + if (MOZ_UNLIKELY(!p)) + p = onOutOfMemoryTyped(AllocFunction::Malloc, numElems); + return p; + } + + template + T* pod_calloc(size_t numElems) { + T* p = maybe_pod_calloc(numElems); + if (MOZ_UNLIKELY(!p)) + p = onOutOfMemoryTyped(AllocFunction::Calloc, numElems); + return p; + } + + template + T* pod_realloc(T* prior, size_t oldSize, size_t newSize) { + T* p2 = maybe_pod_realloc(prior, oldSize, newSize); + if (MOZ_UNLIKELY(!p2)) + p2 = onOutOfMemoryTyped(AllocFunction::Realloc, newSize, prior); + return p2; + } + + void free_(void* p) { js_free(p); } + + JS_FRIEND_API void reportAllocOverflow() const; + + bool checkSimulatedOOM() const { + if (js::oom::ShouldFailWithOOM()) { + ReportOutOfMemory(cx_); + return false; + } + + return true; + } +}; + +/* + * Allocation policy that uses Zone::pod_malloc and friends, so that memory + * pressure is accounted for on the zone. This is suitable for memory associated + * with GC things allocated in the zone. + * + * Since it doesn't hold a JSContext (those may not live long enough), it can't + * report out-of-memory conditions itself; the caller must check for OOM and + * take the appropriate action. + * + * FIXME bug 647103 - replace these *AllocPolicy names. + */ +class ZoneAllocPolicy { + JS::Zone* const zone; + + public: + MOZ_IMPLICIT ZoneAllocPolicy(JS::Zone* z) : zone(z) {} + + // These methods are defined in gc/Zone.h. + template + inline T* maybe_pod_malloc(size_t numElems); + template + inline T* maybe_pod_calloc(size_t numElems); + template + inline T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize); + template + inline T* pod_malloc(size_t numElems); + template + inline T* pod_calloc(size_t numElems); + template + inline T* pod_realloc(T* p, size_t oldSize, size_t newSize); + + void free_(void* p) { js_free(p); } + void reportAllocOverflow() const {} + + MOZ_MUST_USE bool checkSimulatedOOM() const { + return !js::oom::ShouldFailWithOOM(); + } +}; + +} /* namespace js */ + +#endif /* js_AllocPolicy_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CallArgs.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CallArgs.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CallArgs.h @@ -74,12 +74,11 @@ #include "js/Value.h" /* Typedef for native functions called by the JS VM. */ -typedef bool -(* JSNative)(JSContext* cx, unsigned argc, JS::Value* vp); +typedef bool (*JSNative)(JSContext* cx, unsigned argc, JS::Value* vp); namespace JS { -extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue; +extern JS_PUBLIC_DATA const HandleValue UndefinedHandleValue; namespace detail { @@ -87,239 +86,244 @@ * Compute |this| for the |vp| inside a JSNative, either boxing primitives or * replacing with the global object as necessary. */ -extern JS_PUBLIC_API(Value) -ComputeThis(JSContext* cx, JS::Value* vp); +extern JS_PUBLIC_API Value ComputeThis(JSContext* cx, JS::Value* vp); #ifdef JS_DEBUG -extern JS_PUBLIC_API(void) -CheckIsValidConstructible(const Value& v); +extern JS_PUBLIC_API void CheckIsValidConstructible(const Value& v); #endif -class MOZ_STACK_CLASS IncludeUsedRval -{ - protected: +class MOZ_STACK_CLASS IncludeUsedRval { + mutable bool usedRval_; + + public: + bool usedRval() const { return usedRval_; } + void setUsedRval() const { usedRval_ = true; } + void clearUsedRval() const { usedRval_ = false; } + void assertUnusedRval() const { MOZ_ASSERT(!usedRval_); } +}; + +class MOZ_STACK_CLASS NoUsedRval { + public: + bool usedRval() const { return false; } + void setUsedRval() const {} + void clearUsedRval() const {} + void assertUnusedRval() const {} +}; + +template +class MOZ_STACK_CLASS CallArgsBase { + static_assert(mozilla::IsSame::value || + mozilla::IsSame::value, + "WantUsedRval can only be IncludeUsedRval or NoUsedRval"); + + protected: + Value* argv_; + unsigned argc_; + bool constructing_ : 1; + + // True if the caller does not use the return value. + bool ignoresReturnValue_ : 1; + #ifdef JS_DEBUG - mutable bool usedRval_; - void setUsedRval() const { usedRval_ = true; } - void clearUsedRval() const { usedRval_ = false; } - void assertUnusedRval() const { MOZ_ASSERT(!usedRval_); } + WantUsedRval wantUsedRval_; + bool usedRval() const { return wantUsedRval_.usedRval(); } + void setUsedRval() const { wantUsedRval_.setUsedRval(); } + void clearUsedRval() const { wantUsedRval_.clearUsedRval(); } + void assertUnusedRval() const { wantUsedRval_.assertUnusedRval(); } #else - void setUsedRval() const {} - void clearUsedRval() const {} - void assertUnusedRval() const {} + bool usedRval() const { return false; } + void setUsedRval() const {} + void clearUsedRval() const {} + void assertUnusedRval() const {} #endif -}; -class MOZ_STACK_CLASS NoUsedRval -{ - protected: - void setUsedRval() const {} - void clearUsedRval() const {} - void assertUnusedRval() const {} -}; + public: + // CALLEE ACCESS + + /* + * Returns the function being called, as a value. Must not be called after + * rval() has been used! + */ + HandleValue calleev() const { + 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(); } -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: - // CALLEE ACCESS - - /* - * Returns the function being called, as a value. Must not be called after - * rval() has been used! - */ - HandleValue calleev() const { - 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; + // CALLING/CONSTRUCTING-DIFFERENTIATIONS + + bool isConstructing() const { + if (!argv_[-1].isMagic()) return false; #ifdef JS_DEBUG - if (!this->usedRval_) - CheckIsValidConstructible(calleev()); + if (!this->usedRval()) CheckIsValidConstructible(calleev()); #endif - return true; - } + return true; + } + + bool ignoresReturnValue() const { return ignoresReturnValue_; } - 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 - * responsibility to box the value if needed. - */ - HandleValue thisv() const { - // Some internal code uses thisv() in constructing cases, so don't do - // this yet. - // MOZ_ASSERT(!argv_[-1].isMagic(JS_IS_CONSTRUCTING)); - return HandleValue::fromMarkedLocation(&argv_[-1]); - } - - Value computeThis(JSContext* cx) const { - if (thisv().isObject()) - return thisv(); - - return ComputeThis(cx, base()); - } - - // 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 - * calleev() can no longer be used. (If you're compiling against a debug - * build of SpiderMonkey, these methods will assert to aid debugging.) - * - * If the method you're implementing succeeds by returning true, you *must* - * set this. (SpiderMonkey doesn't currently assert this, but it will do - * so eventually.) You don't need to use or change this if your method - * fails. - */ - MutableHandleValue rval() const { - this->setUsedRval(); - return MutableHandleValue::fromMarkedLocation(&argv_[-2]); - } - - 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(const Value& aCalleev) const { - this->clearUsedRval(); - argv_[-2] = aCalleev; - } - - void setThis(const Value& aThisv) const { - argv_[-1] = aThisv; - } - - MutableHandleValue mutableThisv() const { - return MutableHandleValue::fromMarkedLocation(&argv_[-1]); - } - - public: - // 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. - - Value* array() const { return argv_; } - Value* end() const { return argv_ + argc_ + constructing_; } - - 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; - } + 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 + * responsibility to box the value if needed. + */ + HandleValue thisv() const { + // Some internal code uses thisv() in constructing cases, so don't do + // this yet. + // MOZ_ASSERT(!argv_[-1].isMagic(JS_IS_CONSTRUCTING)); + return HandleValue::fromMarkedLocation(&argv_[-1]); + } + + Value computeThis(JSContext* cx) const { + if (thisv().isObject()) return thisv(); + + return ComputeThis(cx, base()); + } + + // 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 + * calleev() can no longer be used. (If you're compiling against a debug + * build of SpiderMonkey, these methods will assert to aid debugging.) + * + * If the method you're implementing succeeds by returning true, you *must* + * set this. (SpiderMonkey doesn't currently assert this, but it will do + * so eventually.) You don't need to use or change this if your method + * fails. + */ + MutableHandleValue rval() const { + this->setUsedRval(); + return MutableHandleValue::fromMarkedLocation(&argv_[-2]); + } + + 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(const Value& aCalleev) const { + this->clearUsedRval(); + argv_[-2] = aCalleev; + } + + void setThis(const Value& aThisv) const { argv_[-1] = aThisv; } + + MutableHandleValue mutableThisv() const { + return MutableHandleValue::fromMarkedLocation(&argv_[-1]); + } + + public: + // 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. + + Value* array() const { return argv_; } + Value* end() const { return argv_ + argc_ + constructing_; } + + 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; + } }; -} // namespace detail +} // namespace detail -class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase -{ - private: - friend CallArgs CallArgsFromVp(unsigned argc, Value* vp); - friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing); - - static CallArgs create(unsigned argc, Value* argv, bool constructing) { - CallArgs args; - args.clearUsedRval(); - args.argv_ = argv; - args.argc_ = argc; - args.constructing_ = constructing; +class MOZ_STACK_CLASS CallArgs + : public detail::CallArgsBase { + private: + friend CallArgs CallArgsFromVp(unsigned argc, Value* vp); + friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, + bool constructing, bool ignoresReturnValue); + + static CallArgs create(unsigned argc, Value* argv, bool constructing, + bool ignoresReturnValue = false) { + CallArgs args; + args.clearUsedRval(); + args.argv_ = argv; + args.argc_ = argc; + args.constructing_ = constructing; + args.ignoresReturnValue_ = ignoresReturnValue; #ifdef DEBUG - for (unsigned i = 0; i < argc; ++i) - MOZ_ASSERT_IF(argv[i].isMarkable(), !GCThingIsMarkedGray(GCCellPtr(argv[i]))); + MOZ_ASSERT(ValueIsNotGray(args.thisv())); + MOZ_ASSERT(ValueIsNotGray(args.calleev())); + for (unsigned i = 0; i < argc; ++i) MOZ_ASSERT(ValueIsNotGray(argv[i])); #endif - return args; - } - - public: - /* - * Returns true if there are at least |required| arguments passed in. If - * false, it reports an error message on the context. - */ - JS_PUBLIC_API(bool) requireAtLeast(JSContext* cx, const char* fnname, unsigned required) const; + return args; + } + public: + /* + * Returns true if there are at least |required| arguments passed in. If + * false, it reports an error message on the context. + */ + JS_PUBLIC_API bool requireAtLeast(JSContext* cx, const char* fnname, + unsigned required) const; }; -MOZ_ALWAYS_INLINE CallArgs -CallArgsFromVp(unsigned argc, Value* vp) -{ - return CallArgs::create(argc, vp + 2, vp[1].isMagic(JS_IS_CONSTRUCTING)); +MOZ_ALWAYS_INLINE CallArgs CallArgsFromVp(unsigned argc, Value* vp) { + return CallArgs::create(argc, vp + 2, vp[1].isMagic(JS_IS_CONSTRUCTING)); } // This method is only intended for internal use in SpiderMonkey. We may // eventually move it to an internal header. Embedders should use // JS::CallArgsFromVp! -MOZ_ALWAYS_INLINE CallArgs -CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing = false) -{ - return CallArgs::create(stackSlots - constructing, sp - stackSlots, constructing); +MOZ_ALWAYS_INLINE CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, + bool constructing = false, + bool ignoresReturnValue = false) { + return CallArgs::create(stackSlots - constructing, sp - stackSlots, + constructing, ignoresReturnValue); } -} // namespace JS +} // namespace JS /* * Macros to hide interpreter stack layout details from a JSNative using its @@ -336,10 +340,8 @@ * Note: if this method returns null, an error has occurred and must be * propagated or caught. */ -MOZ_ALWAYS_INLINE JS::Value -JS_THIS(JSContext* cx, JS::Value* vp) -{ - return vp[1].isPrimitive() ? JS::detail::ComputeThis(cx, vp) : vp[1]; +MOZ_ALWAYS_INLINE JS::Value JS_THIS(JSContext* cx, JS::Value* vp) { + return vp[1].isPrimitive() ? JS::detail::ComputeThis(cx, vp) : vp[1]; } /* @@ -349,7 +351,7 @@ * 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()) +#define JS_THIS_OBJECT(cx, vp) (JS_THIS(cx, vp).toObjectOrNull()) /* * |this| is passed to functions in ES5 without change. Functions themselves @@ -364,6 +366,6 @@ * But: DO NOT USE THIS! Instead use JS::CallArgs::thisv(), above. * */ -#define JS_THIS_VALUE(cx,vp) ((vp)[1]) +#define JS_THIS_VALUE(cx, vp) ((vp)[1]) #endif /* js_CallArgs_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CallNonGenericMethod.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CallNonGenericMethod.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/CallNonGenericMethod.h @@ -23,10 +23,12 @@ namespace detail { // DON'T CALL THIS DIRECTLY. It's for use only by CallNonGenericMethod! -extern JS_PUBLIC_API(bool) -CallMethodIfWrapped(JSContext* cx, IsAcceptableThis test, NativeImpl impl, const CallArgs& args); +extern JS_PUBLIC_API bool CallMethodIfWrapped(JSContext* cx, + IsAcceptableThis test, + NativeImpl impl, + const CallArgs& args); -} // namespace detail +} // namespace detail // Methods usually act upon |this| objects only from a single global object and // compartment. Sometimes, however, a method must act upon |this| values from @@ -73,7 +75,8 @@ // answer_getAnswer(JSContext* cx, unsigned argc, JS::Value* vp) // { // JS::CallArgs args = JS::CallArgsFromVp(argc, vp); -// return JS::CallNonGenericMethod(cx, args); +// return JS::CallNonGenericMethod(cx, args); // } // // Note that, because they are used as template arguments, the predicate @@ -91,27 +94,25 @@ // Note: JS::CallNonGenericMethod will only work correctly if it's called in // tail position in a JSNative. Do not call it from any other place. // -template -MOZ_ALWAYS_INLINE bool -CallNonGenericMethod(JSContext* cx, const CallArgs& args) -{ - HandleValue thisv = args.thisv(); - if (Test(thisv)) - return Impl(cx, args); +template +MOZ_ALWAYS_INLINE bool CallNonGenericMethod(JSContext* cx, + const CallArgs& args) { + HandleValue thisv = args.thisv(); + if (Test(thisv)) return Impl(cx, args); - return detail::CallMethodIfWrapped(cx, Test, Impl, args); + return detail::CallMethodIfWrapped(cx, Test, Impl, args); } -MOZ_ALWAYS_INLINE bool -CallNonGenericMethod(JSContext* cx, IsAcceptableThis Test, NativeImpl Impl, const CallArgs& args) -{ - HandleValue thisv = args.thisv(); - if (Test(thisv)) - return Impl(cx, args); +MOZ_ALWAYS_INLINE bool CallNonGenericMethod(JSContext* cx, + IsAcceptableThis Test, + NativeImpl Impl, + const CallArgs& args) { + HandleValue thisv = args.thisv(); + if (Test(thisv)) return Impl(cx, args); - return detail::CallMethodIfWrapped(cx, Test, Impl, args); + return detail::CallMethodIfWrapped(cx, Test, Impl, args); } -} // namespace JS +} // namespace JS #endif /* js_CallNonGenericMethod_h */ 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 @@ -12,10 +12,6 @@ #include "js/TypeDecls.h" #include "js/Utility.h" -namespace js { -class ExclusiveContext; -} // namespace js - class JSFlatString; namespace JS { @@ -26,95 +22,84 @@ * byte is treated as a 2-byte character, and there is no way to pass in a * string containing characters beyond U+00FF. */ -class Latin1Chars : public mozilla::Range -{ - 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) - : Base(const_cast(aBytes), aLength) - {} - Latin1Chars(const char* aBytes, size_t aLength) - : Base(reinterpret_cast(const_cast(aBytes)), aLength) - {} +class Latin1Chars : public mozilla::Range { + 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) + : Base(const_cast(aBytes), aLength) {} + Latin1Chars(const char* aBytes, size_t aLength) + : Base(reinterpret_cast(const_cast(aBytes)), + aLength) {} }; /* * A Latin1Chars, but with \0 termination for C compatibility. */ -class Latin1CharsZ : public mozilla::RangedPtr -{ - typedef mozilla::RangedPtr Base; - - public: - using CharT = Latin1Char; - - Latin1CharsZ() : Base(nullptr, 0) {} - - Latin1CharsZ(char* aBytes, size_t aLength) - : Base(reinterpret_cast(aBytes), aLength) - { - MOZ_ASSERT(aBytes[aLength] == '\0'); - } - - Latin1CharsZ(Latin1Char* aBytes, size_t aLength) - : Base(aBytes, aLength) - { - MOZ_ASSERT(aBytes[aLength] == '\0'); - } +class Latin1CharsZ : public mozilla::RangedPtr { + typedef mozilla::RangedPtr Base; + + public: + using CharT = Latin1Char; + + Latin1CharsZ() : Base(nullptr, 0) {} + + Latin1CharsZ(char* aBytes, size_t aLength) + : Base(reinterpret_cast(aBytes), aLength) { + MOZ_ASSERT(aBytes[aLength] == '\0'); + } + + Latin1CharsZ(Latin1Char* aBytes, size_t aLength) : Base(aBytes, aLength) { + MOZ_ASSERT(aBytes[aLength] == '\0'); + } - using Base::operator=; + using Base::operator=; - char* c_str() { return reinterpret_cast(get()); } + char* c_str() { return reinterpret_cast(get()); } }; -class UTF8Chars : public mozilla::Range -{ - typedef mozilla::Range Base; - - public: - using CharT = unsigned char; - - UTF8Chars() : Base() {} - UTF8Chars(char* aBytes, size_t aLength) - : Base(reinterpret_cast(aBytes), aLength) - {} - UTF8Chars(const char* aBytes, size_t aLength) - : Base(reinterpret_cast(const_cast(aBytes)), aLength) - {} +class UTF8Chars : public mozilla::Range { + typedef mozilla::Range Base; + + public: + using CharT = unsigned char; + + UTF8Chars() : Base() {} + UTF8Chars(char* aBytes, size_t aLength) + : Base(reinterpret_cast(aBytes), aLength) {} + UTF8Chars(const char* aBytes, size_t aLength) + : Base(reinterpret_cast(const_cast(aBytes)), + aLength) {} }; /* * SpiderMonkey also deals directly with UTF-8 encoded text in some places. */ -class UTF8CharsZ : public mozilla::RangedPtr -{ - typedef mozilla::RangedPtr Base; - - public: - using CharT = unsigned char; - - UTF8CharsZ() : Base(nullptr, 0) {} - - UTF8CharsZ(char* aBytes, size_t aLength) - : Base(reinterpret_cast(aBytes), aLength) - { - MOZ_ASSERT(aBytes[aLength] == '\0'); - } - - UTF8CharsZ(unsigned char* aBytes, size_t aLength) - : Base(aBytes, aLength) - { - MOZ_ASSERT(aBytes[aLength] == '\0'); - } +class UTF8CharsZ : public mozilla::RangedPtr { + typedef mozilla::RangedPtr Base; + + public: + using CharT = unsigned char; + + UTF8CharsZ() : Base(nullptr, 0) {} - using Base::operator=; + UTF8CharsZ(char* aBytes, size_t aLength) + : Base(reinterpret_cast(aBytes), aLength) { + MOZ_ASSERT(aBytes[aLength] == '\0'); + } - char* c_str() { return reinterpret_cast(get()); } + UTF8CharsZ(unsigned char* aBytes, size_t aLength) : Base(aBytes, aLength) { + MOZ_ASSERT(aBytes[aLength] == '\0'); + } + + using Base::operator=; + + char* c_str() { return reinterpret_cast(get()); } }; /* @@ -123,34 +108,30 @@ * 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'); +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); + validate(aLength); #endif - } + } - const void* get() const { return data_; } + const void* get() const { return data_; } - const char* c_str() const { return data_; } + const char* c_str() const { return data_; } - explicit operator bool() const { return data_ != nullptr; } + explicit operator bool() const { return data_ != nullptr; } - private: + private: #ifdef DEBUG - void validate(size_t aLength); + void validate(size_t aLength); #endif }; @@ -162,37 +143,34 @@ * manually interpreting UTF-16 extension characters embedded in the JS * string. */ -class TwoByteChars : public mozilla::Range -{ - 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) {} +class TwoByteChars : public mozilla::Range { + 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) {} }; /* * A TwoByteChars, but \0 terminated for compatibility with JSFlatString. */ -class TwoByteCharsZ : public mozilla::RangedPtr -{ - typedef mozilla::RangedPtr Base; - - public: - using CharT = char16_t; - - TwoByteCharsZ() : Base(nullptr, 0) {} - - TwoByteCharsZ(char16_t* chars, size_t length) - : Base(chars, length) - { - MOZ_ASSERT(chars[length] == '\0'); - } +class TwoByteCharsZ : public mozilla::RangedPtr { + typedef mozilla::RangedPtr Base; + + public: + using CharT = char16_t; + + TwoByteCharsZ() : Base(nullptr, 0) {} + + TwoByteCharsZ(char16_t* chars, size_t length) : Base(chars, length) { + MOZ_ASSERT(chars[length] == '\0'); + } - using Base::operator=; + using Base::operator=; }; typedef mozilla::RangedPtr ConstCharPtr; @@ -200,15 +178,15 @@ /* * Like TwoByteChars, but the chars are const. */ -class ConstTwoByteChars : public mozilla::Range -{ - typedef mozilla::Range Base; +class ConstTwoByteChars : public mozilla::Range { + typedef mozilla::Range Base; - public: - using CharT = char16_t; + public: + using CharT = char16_t; - ConstTwoByteChars() : Base() {} - ConstTwoByteChars(const char16_t* aChars, size_t aLength) : Base(aChars, aLength) {} + ConstTwoByteChars() : Base() {} + ConstTwoByteChars(const char16_t* aChars, size_t aLength) + : Base(aChars, aLength) {} }; /* @@ -221,23 +199,22 @@ * will return a nullptr chars (which can be tested for with the ! operator). * This method cannot trigger GC. */ -extern Latin1CharsZ -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); +extern Latin1CharsZ LossyTwoByteCharsToNewLatin1CharsZ( + JSContext* cx, const mozilla::Range tbchars); + +inline Latin1CharsZ LossyTwoByteCharsToNewLatin1CharsZ(JSContext* 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); +extern UTF8CharsZ CharsToNewUTF8CharsZ(JSContext* maybeCx, + const mozilla::Range chars); -JS_PUBLIC_API(uint32_t) -Utf8ToOneUcs4Char(const uint8_t* utf8Buffer, int utf8Length); +JS_PUBLIC_API uint32_t Utf8ToOneUcs4Char(const uint8_t* utf8Buffer, + int utf8Length); /* * Inflate bytes in UTF-8 encoding to char16_t. @@ -245,32 +222,31 @@ * - On success, returns a malloc'd TwoByteCharsZ, and updates |outlen| to hold * its length; the length value excludes the trailing null. */ -extern JS_PUBLIC_API(TwoByteCharsZ) -UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); +extern JS_PUBLIC_API TwoByteCharsZ UTF8CharsToNewTwoByteCharsZ( + JSContext* cx, const UTF8Chars utf8, size_t* outlen); /* * Like UTF8CharsToNewTwoByteCharsZ, but for ConstUTF8CharsZ. */ -extern JS_PUBLIC_API(TwoByteCharsZ) -UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen); +extern JS_PUBLIC_API TwoByteCharsZ UTF8CharsToNewTwoByteCharsZ( + JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen); /* - * 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. + * The same as UTF8CharsToNewTwoByteCharsZ(), except that any malformed UTF-8 + * characters will be replaced by \uFFFD. No exception will be thrown for + * malformed UTF-8 input. */ -extern JS_PUBLIC_API(TwoByteCharsZ) -LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); +extern JS_PUBLIC_API TwoByteCharsZ LossyUTF8CharsToNewTwoByteCharsZ( + JSContext* cx, const UTF8Chars utf8, size_t* outlen); -extern JS_PUBLIC_API(TwoByteCharsZ) -LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen); +extern JS_PUBLIC_API TwoByteCharsZ LossyUTF8CharsToNewTwoByteCharsZ( + JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen); /* * Returns the length of the char buffer required to encode |s| as UTF8. * Does not include the null-terminator. */ -JS_PUBLIC_API(size_t) -GetDeflatedUTF8StringLength(JSFlatString* s); +JS_PUBLIC_API size_t GetDeflatedUTF8StringLength(JSFlatString* s); /* * Encode |src| as UTF8. The caller must either ensure |dst| has enough space @@ -284,35 +260,31 @@ * 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, - size_t* dstlenp = nullptr, size_t* numcharsp = nullptr); +JS_PUBLIC_API void 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 -}; +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); +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. + * 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) +extern JS_PUBLIC_API Latin1CharsZ UTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); /* @@ -320,17 +292,22 @@ * storing its length (excluding null terminator) in |*outlen|. Non-Latin-1 * codepoints are replaced by '?'. Returns Latin1CharsZ() on failure. */ -extern JS_PUBLIC_API(Latin1CharsZ) -LossyUTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); +extern JS_PUBLIC_API Latin1CharsZ LossyUTF8CharsToNewLatin1CharsZ( + JSContext* cx, const UTF8Chars utf8, size_t* outlen); /* * 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); +extern JS_PUBLIC_API bool StringIsASCII(const char* s); + +/* + * Returns true if the given length-delimited string is a valid UTF-8 string, + * false otherwise. + */ +extern JS_PUBLIC_API bool StringIsUTF8(const uint8_t* s, uint32_t length); -} // namespace JS +} // namespace JS inline void JS_free(JS::Latin1CharsZ& ptr) { js_free((void*)ptr.get()); } inline void JS_free(JS::UTF8CharsZ& ptr) { js_free((void*)ptr.get()); } 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 @@ -34,24 +34,17 @@ // This is equal to JSFunction::class_. Use it in places where you don't want // to #include jsfun.h. -extern JS_FRIEND_DATA(const js::Class* const) FunctionClassPtr; +extern JS_FRIEND_DATA const js::Class* const FunctionClassPtr; -} // namespace js +} // namespace js namespace JS { -class AutoIdVector; - /** * The answer to a successful query as to whether an object is an Array per * ES6's internal |IsArray| operation (as exposed by |Array.isArray|). */ -enum class IsArrayAnswer -{ - Array, - NotArray, - RevokedProxy -}; +enum class IsArrayAnswer { Array, NotArray, RevokedProxy }; /** * ES6 7.2.2. @@ -65,8 +58,8 @@ * revoked, or if |obj| is a proxy whose target (at any number of hops) is a * revoked proxy, this method throws a TypeError and returns false. */ -extern JS_PUBLIC_API(bool) -IsArray(JSContext* cx, HandleObject obj, bool* isArray); +extern JS_PUBLIC_API bool IsArray(JSContext* cx, HandleObject obj, + bool* isArray); /** * Identical to IsArray above, but the nature of the object (if successfully @@ -76,8 +69,8 @@ * * Most users will want the overload above, not this one. */ -extern JS_PUBLIC_API(bool) -IsArray(JSContext* cx, HandleObject obj, IsArrayAnswer* answer); +extern JS_PUBLIC_API bool IsArray(JSContext* cx, HandleObject obj, + IsArrayAnswer* answer); /** * Per ES6, the [[DefineOwnProperty]] internal method has three different @@ -112,143 +105,229 @@ * argv.rval().setBoolean(bool(result)); * return true; */ -class ObjectOpResult -{ - private: - /** - * code_ is either one of the special codes OkCode or Uninitialized, or - * an error code. For now the error codes are private to the JS engine; - * they're defined in js/src/js.msg. - * - * code_ is uintptr_t (rather than uint32_t) for the convenience of the - * JITs, which would otherwise have to deal with either padding or stack - * alignment on 64-bit platforms. - */ - uintptr_t code_; - - public: - enum SpecialCodes : uintptr_t { - OkCode = 0, - Uninitialized = uintptr_t(-1) - }; - - ObjectOpResult() : code_(Uninitialized) {} - - /* Return true if succeed() was called. */ - bool ok() const { - MOZ_ASSERT(code_ != Uninitialized); - return code_ == OkCode; - } - - explicit operator bool() const { return ok(); } - - /* Set this ObjectOpResult to true and return true. */ - bool succeed() { - code_ = OkCode; - return true; - } - - /* - * Set this ObjectOpResult to false with an error code. - * - * Always returns true, as a convenience. Typical usage will be: - * - * if (funny condition) - * return result.fail(JSMSG_CANT_DO_THE_THINGS); - * - * The true return value indicates that no exception is pending, and it - * would be OK to ignore the failure and continue. - */ - bool fail(uint32_t msg) { - MOZ_ASSERT(msg != OkCode); - code_ = msg; - return true; - } - - JS_PUBLIC_API(bool) failCantRedefineProp(); - JS_PUBLIC_API(bool) failReadOnly(); - JS_PUBLIC_API(bool) failGetterOnly(); - JS_PUBLIC_API(bool) failCantDelete(); - - JS_PUBLIC_API(bool) failCantSetInterposed(); - JS_PUBLIC_API(bool) failCantDefineWindowElement(); - JS_PUBLIC_API(bool) failCantDeleteWindowElement(); - JS_PUBLIC_API(bool) failCantDeleteWindowNamedProperty(); - JS_PUBLIC_API(bool) failCantPreventExtensions(); - JS_PUBLIC_API(bool) failCantSetProto(); - JS_PUBLIC_API(bool) failNoNamedSetter(); - JS_PUBLIC_API(bool) failNoIndexedSetter(); - - uint32_t failureCode() const { - MOZ_ASSERT(!ok()); - return uint32_t(code_); - } - - /* - * Report an error or warning if necessary; return true to proceed and - * false if an error was reported. Call this when failure should cause - * a warning if extraWarnings are enabled. - * - * The precise rules are like this: - * - * - If ok(), then we succeeded. Do nothing and return true. - * - Otherwise, if |strict| is true, or if cx has both extraWarnings and - * werrorOption enabled, throw a TypeError and return false. - * - Otherwise, if cx has extraWarnings enabled, emit a warning and - * return true. - * - Otherwise, do nothing and return true. - */ - bool checkStrictErrorOrWarning(JSContext* cx, HandleObject obj, HandleId id, bool strict) { - if (ok()) - return true; - return reportStrictErrorOrWarning(cx, obj, id, strict); - } - - /* - * The same as checkStrictErrorOrWarning(cx, id, strict), except the - * operation is not associated with a particular property id. This is - * used for [[PreventExtensions]] and [[SetPrototypeOf]]. failureCode() - * must not be an error that has "{0}" in the error message. - */ - bool checkStrictErrorOrWarning(JSContext* cx, HandleObject obj, bool strict) { - return ok() || reportStrictErrorOrWarning(cx, obj, strict); - } - - /* Throw a TypeError. Call this only if !ok(). */ - bool reportError(JSContext* cx, HandleObject obj, HandleId id) { - return reportStrictErrorOrWarning(cx, obj, id, true); - } - - /* - * The same as reportError(cx, obj, id), except the operation is not - * associated with a particular property id. - */ - bool reportError(JSContext* cx, HandleObject obj) { - return reportStrictErrorOrWarning(cx, obj, true); - } - - /* Helper function for checkStrictErrorOrWarning's slow path. */ - JS_PUBLIC_API(bool) reportStrictErrorOrWarning(JSContext* cx, HandleObject obj, HandleId id, bool strict); - JS_PUBLIC_API(bool) reportStrictErrorOrWarning(JSContext* cx, HandleObject obj, bool strict); - - /* - * Convenience method. Return true if ok() or if strict is false; otherwise - * throw a TypeError and return false. - */ - bool checkStrict(JSContext* cx, HandleObject obj, HandleId id) { - return checkStrictErrorOrWarning(cx, obj, id, true); - } - - /* - * Convenience method. The same as checkStrict(cx, id), except the - * operation is not associated with a particular property id. - */ - bool checkStrict(JSContext* cx, HandleObject obj) { - return checkStrictErrorOrWarning(cx, obj, true); - } +class ObjectOpResult { + private: + /** + * code_ is either one of the special codes OkCode or Uninitialized, or + * an error code. For now the error codes are private to the JS engine; + * they're defined in js/src/js.msg. + * + * code_ is uintptr_t (rather than uint32_t) for the convenience of the + * JITs, which would otherwise have to deal with either padding or stack + * alignment on 64-bit platforms. + */ + uintptr_t code_; + + public: + enum SpecialCodes : uintptr_t { OkCode = 0, Uninitialized = uintptr_t(-1) }; + + ObjectOpResult() : code_(Uninitialized) {} + + /* Return true if succeed() was called. */ + bool ok() const { + MOZ_ASSERT(code_ != Uninitialized); + return code_ == OkCode; + } + + explicit operator bool() const { return ok(); } + + /* Set this ObjectOpResult to true and return true. */ + bool succeed() { + code_ = OkCode; + return true; + } + + /* + * Set this ObjectOpResult to false with an error code. + * + * Always returns true, as a convenience. Typical usage will be: + * + * if (funny condition) + * return result.fail(JSMSG_CANT_DO_THE_THINGS); + * + * The true return value indicates that no exception is pending, and it + * would be OK to ignore the failure and continue. + */ + bool fail(uint32_t msg) { + MOZ_ASSERT(msg != OkCode); + code_ = msg; + return true; + } + + JS_PUBLIC_API bool failCantRedefineProp(); + JS_PUBLIC_API bool failReadOnly(); + JS_PUBLIC_API bool failGetterOnly(); + JS_PUBLIC_API bool failCantDelete(); + + JS_PUBLIC_API bool failCantSetInterposed(); + JS_PUBLIC_API bool failCantDefineWindowElement(); + JS_PUBLIC_API bool failCantDeleteWindowElement(); + JS_PUBLIC_API bool failCantDeleteWindowNamedProperty(); + JS_PUBLIC_API bool failCantPreventExtensions(); + JS_PUBLIC_API bool failCantSetProto(); + JS_PUBLIC_API bool failNoNamedSetter(); + JS_PUBLIC_API bool failNoIndexedSetter(); + + uint32_t failureCode() const { + MOZ_ASSERT(!ok()); + return uint32_t(code_); + } + + /* + * Report an error or warning if necessary; return true to proceed and + * false if an error was reported. Call this when failure should cause + * a warning if extraWarnings are enabled. + * + * The precise rules are like this: + * + * - If ok(), then we succeeded. Do nothing and return true. + * - Otherwise, if |strict| is true, or if cx has both extraWarnings and + * werrorOption enabled, throw a TypeError and return false. + * - Otherwise, if cx has extraWarnings enabled, emit a warning and + * return true. + * - Otherwise, do nothing and return true. + */ + bool checkStrictErrorOrWarning(JSContext* cx, HandleObject obj, HandleId id, + bool strict) { + if (ok()) return true; + return reportStrictErrorOrWarning(cx, obj, id, strict); + } + + /* + * The same as checkStrictErrorOrWarning(cx, id, strict), except the + * operation is not associated with a particular property id. This is + * used for [[PreventExtensions]] and [[SetPrototypeOf]]. failureCode() + * must not be an error that has "{0}" in the error message. + */ + bool checkStrictErrorOrWarning(JSContext* cx, HandleObject obj, bool strict) { + return ok() || reportStrictErrorOrWarning(cx, obj, strict); + } + + /* Throw a TypeError. Call this only if !ok(). */ + bool reportError(JSContext* cx, HandleObject obj, HandleId id) { + return reportStrictErrorOrWarning(cx, obj, id, true); + } + + /* + * The same as reportError(cx, obj, id), except the operation is not + * associated with a particular property id. + */ + bool reportError(JSContext* cx, HandleObject obj) { + return reportStrictErrorOrWarning(cx, obj, true); + } + + /* Helper function for checkStrictErrorOrWarning's slow path. */ + JS_PUBLIC_API bool reportStrictErrorOrWarning(JSContext* cx, HandleObject obj, + HandleId id, bool strict); + JS_PUBLIC_API bool reportStrictErrorOrWarning(JSContext* cx, HandleObject obj, + bool strict); + + /* + * Convenience method. Return true if ok() or if strict is false; otherwise + * throw a TypeError and return false. + */ + bool checkStrict(JSContext* cx, HandleObject obj, HandleId id) { + return checkStrictErrorOrWarning(cx, obj, id, true); + } + + /* + * Convenience method. The same as checkStrict(cx, id), except the + * operation is not associated with a particular property id. + */ + bool checkStrict(JSContext* cx, HandleObject obj) { + return checkStrictErrorOrWarning(cx, obj, true); + } +}; + +class PropertyResult { + union { + js::Shape* shape_; + uintptr_t bits_; + }; + + static const uintptr_t NotFound = 0; + static const uintptr_t NonNativeProperty = 1; + static const uintptr_t DenseOrTypedArrayElement = 1; + + public: + PropertyResult() : bits_(NotFound) {} + + explicit PropertyResult(js::Shape* propertyShape) : shape_(propertyShape) { + MOZ_ASSERT(!isFound() || isNativeProperty()); + } + + explicit operator bool() const { return isFound(); } + + bool isFound() const { return bits_ != NotFound; } + + bool isNonNativeProperty() const { return bits_ == NonNativeProperty; } + + bool isDenseOrTypedArrayElement() const { + return bits_ == DenseOrTypedArrayElement; + } + + bool isNativeProperty() const { return isFound() && !isNonNativeProperty(); } + + js::Shape* maybeShape() const { + MOZ_ASSERT(!isNonNativeProperty()); + return isFound() ? shape_ : nullptr; + } + + js::Shape* shape() const { + MOZ_ASSERT(isNativeProperty()); + return shape_; + } + + void setNotFound() { bits_ = NotFound; } + + void setNativeProperty(js::Shape* propertyShape) { + shape_ = propertyShape; + MOZ_ASSERT(isNativeProperty()); + } + + void setNonNativeProperty() { bits_ = NonNativeProperty; } + + void setDenseOrTypedArrayElement() { bits_ = DenseOrTypedArrayElement; } + + void trace(JSTracer* trc); +}; + +} // namespace JS + +namespace js { + +template +class WrappedPtrOperations { + const JS::PropertyResult& value() const { + return static_cast(this)->get(); + } + + public: + bool isFound() const { return value().isFound(); } + explicit operator bool() const { return bool(value()); } + js::Shape* maybeShape() const { return value().maybeShape(); } + js::Shape* shape() const { return value().shape(); } + bool isNativeProperty() const { return value().isNativeProperty(); } + bool isNonNativeProperty() const { return value().isNonNativeProperty(); } + bool isDenseOrTypedArrayElement() const { + return value().isDenseOrTypedArrayElement(); + } + js::Shape* asTaggedShape() const { return value().asTaggedShape(); } }; -} // namespace JS +template +class MutableWrappedPtrOperations + : public WrappedPtrOperations { + JS::PropertyResult& value() { return static_cast(this)->get(); } + + public: + void setNotFound() { value().setNotFound(); } + void setNativeProperty(js::Shape* shape) { value().setNativeProperty(shape); } + void setNonNativeProperty() { value().setNonNativeProperty(); } + void setDenseOrTypedArrayElement() { value().setDenseOrTypedArrayElement(); } +}; + +} // namespace js // JSClass operation signatures. @@ -257,24 +336,20 @@ * be a string (Unicode property identifier) or an int (element index). The * *vp out parameter, on success, is the new property value after the action. */ -typedef bool -(* JSGetterOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleValue vp); +typedef bool (*JSGetterOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::MutableHandleValue vp); /** Add a property named by id to obj. */ -typedef bool -(* JSAddPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v); +typedef bool (*JSAddPropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, JS::HandleValue v); /** * Set a property named by id in obj, treating the assignment as strict * mode code if strict is true. Note the jsid id type -- id may be a string - * (Unicode property identifier) or an int (element index). The *vp out - * parameter, on success, is the new property value after the - * set. - */ -typedef bool -(* JSSetterOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleValue vp, JS::ObjectOpResult& result); + * (Unicode property identifier) or an int (element index). + */ +typedef bool (*JSSetterOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::HandleValue v, JS::ObjectOpResult& result); /** * Delete a property named by id in obj. @@ -291,9 +366,8 @@ * property, or an inherited property, is allowed -- it's just pointless), * call result.succeed() and return true. */ -typedef bool -(* JSDeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::ObjectOpResult& result); +typedef bool (*JSDeletePropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, JS::ObjectOpResult& result); /** * The type of ObjectOps::enumerate. This callback overrides a portion of @@ -308,24 +382,23 @@ * object's property keys. If `enumerableOnly` is true, the callback should only * add enumerable properties. */ -typedef bool -(* JSNewEnumerateOp)(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties, - bool enumerableOnly); +typedef bool (*JSNewEnumerateOp)(JSContext* cx, JS::HandleObject obj, + JS::AutoIdVector& properties, + bool enumerableOnly); /** * The old-style JSClass.enumerate op should define all lazy properties not * yet reflected in obj. */ -typedef bool -(* JSEnumerateOp)(JSContext* cx, JS::HandleObject obj); +typedef bool (*JSEnumerateOp)(JSContext* cx, JS::HandleObject obj); /** * The type of ObjectOps::funToString. This callback allows an object to * provide a custom string to use when Function.prototype.toString is invoked on * that object. A null return value means OOM. */ -typedef JSString* -(* JSFunToStringOp)(JSContext* cx, JS::HandleObject obj, unsigned indent); +typedef JSString* (*JSFunToStringOp)(JSContext* cx, JS::HandleObject obj, + bool isToSource); /** * Resolve a lazy property named by id in obj by defining it directly in obj. @@ -336,9 +409,8 @@ * 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, - bool* resolvedp); +typedef bool (*JSResolveOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, bool* resolvedp); /** * A class with a resolve hook can optionally have a mayResolve hook. This hook @@ -351,30 +423,23 @@ * can be nullptr: during JIT compilation we sometimes know the Class but not * the object. */ -typedef bool -(* JSMayResolveOp)(const JSAtomState& names, jsid id, JSObject* maybeObj); +typedef bool (*JSMayResolveOp)(const JSAtomState& names, jsid id, + JSObject* maybeObj); /** * Finalize obj, which the garbage collector has determined to be unreachable * from other live objects or from GC roots. Obviously, finalizers must never * store a reference to obj. */ -typedef void -(* JSFinalizeOp)(JSFreeOp* fop, JSObject* obj); - -/** Finalizes external strings created by JS_NewExternalString. */ -struct JSStringFinalizer { - void (*finalize)(JS::Zone* zone, const JSStringFinalizer* fin, char16_t* chars); -}; +typedef void (*JSFinalizeOp)(JSFreeOp* fop, JSObject* obj); /** * Check whether v is an instance of obj. Return false on error or exception, * true on success with true in *bp if v is an instance of obj, false in * *bp otherwise. */ -typedef bool -(* JSHasInstanceOp)(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp, - bool* bp); +typedef bool (*JSHasInstanceOp)(JSContext* cx, JS::HandleObject obj, + JS::MutableHandleValue vp, bool* bp); /** * Function type for trace operation of the class called to enumerate all @@ -390,384 +455,353 @@ * JS_IsGCMarkingTracer and apply a special code like emptying caches or * marking its native structures. */ -typedef void -(* JSTraceOp)(JSTracer* trc, JSObject* obj); +typedef void (*JSTraceOp)(JSTracer* trc, JSObject* obj); -typedef JSObject* -(* JSWeakmapKeyDelegateOp)(JSObject* obj); +typedef JSObject* (*JSWeakmapKeyDelegateOp)(JSObject* obj); -typedef void -(* JSObjectMovedOp)(JSObject* obj, const JSObject* old); +typedef size_t (*JSObjectMovedOp)(JSObject* obj, JSObject* old); /* js::Class operation signatures. */ namespace js { -typedef bool -(* LookupPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleObject objp, JS::MutableHandle propp); -typedef bool -(* DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc, - JS::ObjectOpResult& result); -typedef bool -(* HasPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); -typedef bool -(* GetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleValue receiver, JS::HandleId id, - JS::MutableHandleValue vp); -typedef bool -(* SetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, - JS::HandleValue receiver, JS::ObjectOpResult& result); -typedef bool -(* GetOwnPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); -typedef bool -(* DeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::ObjectOpResult& result); - -typedef bool -(* WatchOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); - -typedef bool -(* UnwatchOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id); - -class JS_FRIEND_API(ElementAdder) -{ - public: - enum GetBehavior { - // Check if the element exists before performing the Get and preserve - // holes. - CheckHasElemPreserveHoles, - - // Perform a Get operation, like obj[index] in JS. - GetElement - }; - - private: - // Only one of these is used. - JS::RootedObject resObj_; - JS::Value* vp_; +typedef bool (*LookupPropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, JS::MutableHandleObject objp, + JS::MutableHandle propp); +typedef bool (*DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, + JS::Handle desc, + JS::ObjectOpResult& result); +typedef bool (*HasPropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, bool* foundp); +typedef bool (*GetPropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleValue receiver, JS::HandleId id, + JS::MutableHandleValue vp); +typedef bool (*SetPropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, JS::HandleValue v, + JS::HandleValue receiver, + JS::ObjectOpResult& result); +typedef bool (*GetOwnPropertyOp)( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::MutableHandle desc); +typedef bool (*DeletePropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, JS::ObjectOpResult& result); + +class JS_FRIEND_API ElementAdder { + public: + enum GetBehavior { + // Check if the element exists before performing the Get and preserve + // holes. + CheckHasElemPreserveHoles, + + // Perform a Get operation, like obj[index] in JS. + GetElement + }; + + private: + // Only one of these is used. + JS::RootedObject resObj_; + JS::Value* vp_; - uint32_t index_; + uint32_t index_; #ifdef DEBUG - uint32_t length_; + uint32_t length_; #endif - GetBehavior getBehavior_; + GetBehavior getBehavior_; - public: - ElementAdder(JSContext* cx, JSObject* obj, uint32_t length, GetBehavior behavior) - : resObj_(cx, obj), vp_(nullptr), index_(0), + public: + ElementAdder(JSContext* cx, JSObject* obj, uint32_t 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), + getBehavior_(behavior) { + } + ElementAdder(JSContext* cx, JS::Value* vp, uint32_t length, + GetBehavior behavior) + : resObj_(cx), + vp_(vp), + index_(0), #ifdef DEBUG length_(length), #endif - getBehavior_(behavior) - {} + getBehavior_(behavior) { + } - GetBehavior getBehavior() const { return getBehavior_; } + GetBehavior getBehavior() const { return getBehavior_; } - bool append(JSContext* cx, JS::HandleValue v); - void appendHole(); + bool append(JSContext* cx, JS::HandleValue v); + void appendHole(); }; -typedef bool -(* GetElementsOp)(JSContext* cx, JS::HandleObject obj, uint32_t begin, uint32_t end, - ElementAdder* adder); +typedef bool (*GetElementsOp)(JSContext* cx, JS::HandleObject obj, + uint32_t begin, uint32_t end, + ElementAdder* adder); -typedef void -(* FinalizeOp)(FreeOp* fop, JSObject* obj); +typedef void (*FinalizeOp)(FreeOp* fop, JSObject* obj); // 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; +#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; \ + } \ + JSEnumerateOp getEnumerate() const { \ + return cOps ? cOps->enumerate : nullptr; \ + } \ + JSNewEnumerateOp getNewEnumerate() const { \ + return cOps ? cOps->newEnumerate : 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); \ + } + +// XXX: MOZ_NONHEAP_CLASS allows objects to be created statically or on the +// stack. We actually want to ban stack objects too, but that's currently not +// possible. So we define JS_STATIC_CLASS to make the intention clearer. +#define JS_STATIC_CLASS MOZ_NONHEAP_CLASS + +struct JS_STATIC_CLASS ClassOps { + /* Function pointer members (may be null). */ + JSAddPropertyOp addProperty; + JSDeletePropertyOp delProperty; + JSEnumerateOp enumerate; + JSNewEnumerateOp newEnumerate; + 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); -/** Callback for custom post-processing after class initialization via ClassSpec. */ +/** + * Callback for custom post-processing after class initialization via + * ClassSpec. + */ typedef bool (*FinishClassInitOp)(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto); const size_t JSCLASS_CACHED_PROTO_WIDTH = 6; -struct ClassSpec -{ - // All properties except flags should be accessed through accessor. - ClassObjectCreationOp createConstructor_; - ClassObjectCreationOp createPrototype_; - const JSFunctionSpec* constructorFunctions_; - const JSPropertySpec* constructorProperties_; - const JSFunctionSpec* prototypeFunctions_; - const JSPropertySpec* prototypeProperties_; - FinishClassInitOp finishInit_; - uintptr_t flags; - - static const size_t ProtoKeyWidth = JSCLASS_CACHED_PROTO_WIDTH; - - 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_; } - - bool delegated() const { - return (flags & IsDelegated); - } - - // The ProtoKey this class inherits from. - JSProtoKey inheritanceProtoKey() const { - MOZ_ASSERT(defined()); - static_assert(JSProto_Null == 0, "zeroed key must be null"); - - // Default: Inherit from Object. - if (!(flags & ProtoKeyMask)) - return JSProto_Object; - - return JSProtoKey(flags & ProtoKeyMask); - } - - bool shouldDefineConstructor() const { - MOZ_ASSERT(defined()); - return !(flags & DontDefineConstructor); - } - - const ClassSpec* delegatedClassSpec() const { - MOZ_ASSERT(delegated()); - return reinterpret_cast(createConstructor_); - } - - ClassObjectCreationOp createConstructorHook() const { - if (delegated()) - return delegatedClassSpec()->createConstructorHook(); - return createConstructor_; - } - ClassObjectCreationOp createPrototypeHook() const { - if (delegated()) - return delegatedClassSpec()->createPrototypeHook(); - return createPrototype_; - } - const JSFunctionSpec* constructorFunctions() const { - if (delegated()) - return delegatedClassSpec()->constructorFunctions(); - return constructorFunctions_; - } - const JSPropertySpec* constructorProperties() const { - if (delegated()) - return delegatedClassSpec()->constructorProperties(); - return constructorProperties_; - } - const JSFunctionSpec* prototypeFunctions() const { - if (delegated()) - return delegatedClassSpec()->prototypeFunctions(); - return prototypeFunctions_; - } - const JSPropertySpec* prototypeProperties() const { - if (delegated()) - return delegatedClassSpec()->prototypeProperties(); - return prototypeProperties_; - } - FinishClassInitOp finishInitHook() const { - if (delegated()) - return delegatedClassSpec()->finishInitHook(); - return finishInit_; - } -}; - -struct ClassExtension -{ - /** - * If an object is used as a key in a weakmap, it may be desirable for the - * garbage collector to keep that object around longer than it otherwise - * would. A common case is when the key is a wrapper around an object in - * another compartment, and we want to avoid collecting the wrapper (and - * removing the weakmap entry) as long as the wrapped object is alive. In - * that case, the wrapped object is returned by the wrapper's - * weakmapKeyDelegateOp hook. As long as the wrapper is used as a weakmap - * key, it will not be collected (and remain in the weakmap) until the - * wrapped object is collected. - */ - JSWeakmapKeyDelegateOp weakmapKeyDelegateOp; - - /** - * Optional hook called when an object is moved by a compacting GC. - * - * There may exist weak pointers to an object that are not traced through - * when the normal trace APIs are used, for example objects in the wrapper - * cache. This hook allows these pointers to be updated. - * - * Note that this hook can be called before JS_NewObject() returns if a GC - * is triggered during construction of the object. This can happen for - * global objects for example. - */ - JSObjectMovedOp objectMovedOp; +struct JS_STATIC_CLASS ClassSpec { + ClassObjectCreationOp createConstructor; + ClassObjectCreationOp createPrototype; + const JSFunctionSpec* constructorFunctions; + const JSPropertySpec* constructorProperties; + const JSFunctionSpec* prototypeFunctions; + const JSPropertySpec* prototypeProperties; + FinishClassInitOp finishInit; + uintptr_t flags; + + static const size_t ProtoKeyWidth = JSCLASS_CACHED_PROTO_WIDTH; + + static const uintptr_t ProtoKeyMask = (1 << ProtoKeyWidth) - 1; + static const uintptr_t DontDefineConstructor = 1 << ProtoKeyWidth; + + bool defined() const { return !!createConstructor; } + + // The ProtoKey this class inherits from. + JSProtoKey inheritanceProtoKey() const { + MOZ_ASSERT(defined()); + static_assert(JSProto_Null == 0, "zeroed key must be null"); + + // Default: Inherit from Object. + if (!(flags & ProtoKeyMask)) return JSProto_Object; + + return JSProtoKey(flags & ProtoKeyMask); + } + + bool shouldDefineConstructor() const { + MOZ_ASSERT(defined()); + return !(flags & DontDefineConstructor); + } }; -inline ClassObjectCreationOp DELEGATED_CLASSSPEC(const ClassSpec* spec) { - return reinterpret_cast(const_cast(spec)); -} +struct JS_STATIC_CLASS ClassExtension { + /** + * If an object is used as a key in a weakmap, it may be desirable for the + * garbage collector to keep that object around longer than it otherwise + * would. A common case is when the key is a wrapper around an object in + * another compartment, and we want to avoid collecting the wrapper (and + * removing the weakmap entry) as long as the wrapped object is alive. In + * that case, the wrapped object is returned by the wrapper's + * weakmapKeyDelegateOp hook. As long as the wrapper is used as a weakmap + * key, it will not be collected (and remain in the weakmap) until the + * wrapped object is collected. + */ + JSWeakmapKeyDelegateOp weakmapKeyDelegateOp; + + /** + * Optional hook called when an object is moved by generational or + * compacting GC. + * + * There may exist weak pointers to an object that are not traced through + * when the normal trace APIs are used, for example objects in the wrapper + * cache. This hook allows these pointers to be updated. + * + * Note that this hook can be called before JS_NewObject() returns if a GC + * is triggered during construction of the object. This can happen for + * global objects for example. + * + * The function should return the difference between nursery bytes used and + * tenured bytes used, which may be nonzero e.g. if some nursery-allocated + * data beyond the actual GC thing is moved into malloced memory. + * + * This is used to compute the nursery promotion rate. + */ + JSObjectMovedOp objectMovedOp; +}; -#define JS_NULL_CLASS_SPEC nullptr -#define JS_NULL_CLASS_EXT 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; +struct JS_STATIC_CLASS ObjectOps { + LookupPropertyOp lookupProperty; + DefinePropertyOp defineProperty; + HasPropertyOp hasProperty; + GetPropertyOp getProperty; + SetPropertyOp setProperty; + GetOwnPropertyOp getOwnPropertyDescriptor; + DeletePropertyOp deleteProperty; + GetElementsOp getElements; + JSFunToStringOp funToString; }; #define JS_NULL_OBJECT_OPS nullptr -} // namespace js +} // namespace js // Classes, objects, and properties. 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; +struct JS_STATIC_CLASS JSClassOps { + /* Function pointer members (may be null). */ + JSAddPropertyOp addProperty; + JSDeletePropertyOp delProperty; + JSEnumerateOp enumerate; + JSNewEnumerateOp newEnumerate; + 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(JSClassOps, JSFreeOp); + JS_CLASS_MEMBERS(JSClassOps, JSFreeOp); - void* reserved[3]; + void* reserved[3]; }; -#define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot -#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 -#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 -#define JSCLASS_USERBIT1 (1<<7) // Reserved for embeddings. +// Objects have private slot. +static const uint32_t JSCLASS_HAS_PRIVATE = 1 << 0; -// To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or -// JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where -// n is a constant in [1, 255]. Reserved slots are indexed from 0 to n-1. -#define JSCLASS_RESERVED_SLOTS_SHIFT 8 // room for 8 flags below */ -#define JSCLASS_RESERVED_SLOTS_WIDTH 8 // and 16 above this field */ -#define JSCLASS_RESERVED_SLOTS_MASK JS_BITMASK(JSCLASS_RESERVED_SLOTS_WIDTH) -#define JSCLASS_HAS_RESERVED_SLOTS(n) (((n) & JSCLASS_RESERVED_SLOTS_MASK) \ - << JSCLASS_RESERVED_SLOTS_SHIFT) -#define JSCLASS_RESERVED_SLOTS(clasp) (((clasp)->flags \ - >> JSCLASS_RESERVED_SLOTS_SHIFT) \ - & JSCLASS_RESERVED_SLOTS_MASK) - -#define JSCLASS_HIGH_FLAGS_SHIFT (JSCLASS_RESERVED_SLOTS_SHIFT + \ - JSCLASS_RESERVED_SLOTS_WIDTH) - -#define JSCLASS_IS_ANONYMOUS (1<<(JSCLASS_HIGH_FLAGS_SHIFT+0)) -#define JSCLASS_IS_GLOBAL (1<<(JSCLASS_HIGH_FLAGS_SHIFT+1)) -#define JSCLASS_INTERNAL_FLAG2 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+2)) -#define JSCLASS_INTERNAL_FLAG3 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+3)) +// Class's initialization code will call `SetNewObjectMetadata` itself. +static const uint32_t JSCLASS_DELAY_METADATA_BUILDER = 1 << 1; + +// Class is an XPCWrappedNative. WeakMaps use this to override the wrapper +// disposal mechanism. +static const uint32_t JSCLASS_IS_WRAPPED_NATIVE = 1 << 2; + +// Private is `nsISupports*`. +static const uint32_t JSCLASS_PRIVATE_IS_NSISUPPORTS = 1 << 3; + +// Objects are DOM. +static const uint32_t JSCLASS_IS_DOMJSCLASS = 1 << 4; + +// 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. +static const uint32_t JSCLASS_HAS_XRAYED_CONSTRUCTOR = 1 << 5; + +// Objects of this class act like the value undefined, in some contexts. +static const uint32_t JSCLASS_EMULATES_UNDEFINED = 1 << 6; + +// Reserved for embeddings. +static const uint32_t JSCLASS_USERBIT1 = 1 << 7; -#define JSCLASS_IS_PROXY (1<<(JSCLASS_HIGH_FLAGS_SHIFT+4)) +// To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or +// JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where n +// is a constant in [1, 255]. Reserved slots are indexed from 0 to n-1. -#define JSCLASS_SKIP_NURSERY_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+5)) +// Room for 8 flags below ... +static const uintptr_t JSCLASS_RESERVED_SLOTS_SHIFT = 8; +// ... and 16 above this field. +static const uint32_t JSCLASS_RESERVED_SLOTS_WIDTH = 8; + +static const uint32_t JSCLASS_RESERVED_SLOTS_MASK = + JS_BITMASK(JSCLASS_RESERVED_SLOTS_WIDTH); + +#define JSCLASS_HAS_RESERVED_SLOTS(n) \ + (((n)&JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT) +#define JSCLASS_RESERVED_SLOTS(clasp) \ + (((clasp)->flags >> JSCLASS_RESERVED_SLOTS_SHIFT) & \ + JSCLASS_RESERVED_SLOTS_MASK) + +#define JSCLASS_HIGH_FLAGS_SHIFT \ + (JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH) + +static const uint32_t JSCLASS_IS_ANONYMOUS = 1 + << (JSCLASS_HIGH_FLAGS_SHIFT + 0); +static const uint32_t JSCLASS_IS_GLOBAL = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 1); +static const uint32_t JSCLASS_INTERNAL_FLAG2 = + 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 2); +static const uint32_t JSCLASS_INTERNAL_FLAG3 = + 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 3); +static const uint32_t JSCLASS_IS_PROXY = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 4); +static const uint32_t JSCLASS_SKIP_NURSERY_FINALIZE = + 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 5); // Reserved for embeddings. -#define JSCLASS_USERBIT2 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+6)) -#define JSCLASS_USERBIT3 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+7)) +static const uint32_t JSCLASS_USERBIT2 = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 6); +static const uint32_t 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)) +static const uint32_t JSCLASS_BACKGROUND_FINALIZE = + 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 8); +static const uint32_t JSCLASS_FOREGROUND_FINALIZE = + 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 9); // Bits 26 through 31 are reserved for the CACHED_PROTO_KEY mechanism, see // below. @@ -785,141 +819,157 @@ // JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at // the beginning of every global object's slots for use by the // application. -#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5 -#define JSCLASS_GLOBAL_SLOT_COUNT \ - (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 \ - JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0) -#define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp) \ - (((clasp)->flags & JSCLASS_IS_GLOBAL) \ - && JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT) +static const uint32_t JSCLASS_GLOBAL_APPLICATION_SLOTS = 5; +static const uint32_t JSCLASS_GLOBAL_SLOT_COUNT = + JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 37; + +#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \ + (JSCLASS_IS_GLOBAL | \ + JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n))) +#define JSCLASS_GLOBAL_FLAGS JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0) +#define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp) \ + (((clasp)->flags & JSCLASS_IS_GLOBAL) && \ + JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT) // Fast access to the original value of each standard class's prototype. -#define JSCLASS_CACHED_PROTO_SHIFT (JSCLASS_HIGH_FLAGS_SHIFT + 10) -#define JSCLASS_CACHED_PROTO_MASK JS_BITMASK(js::JSCLASS_CACHED_PROTO_WIDTH) -#define JSCLASS_HAS_CACHED_PROTO(key) (uint32_t(key) << JSCLASS_CACHED_PROTO_SHIFT) -#define JSCLASS_CACHED_PROTO_KEY(clasp) ((JSProtoKey) \ - (((clasp)->flags \ - >> JSCLASS_CACHED_PROTO_SHIFT) \ - & JSCLASS_CACHED_PROTO_MASK)) +static const uint32_t JSCLASS_CACHED_PROTO_SHIFT = + JSCLASS_HIGH_FLAGS_SHIFT + 10; +static const uint32_t JSCLASS_CACHED_PROTO_MASK = + JS_BITMASK(js::JSCLASS_CACHED_PROTO_WIDTH); + +#define JSCLASS_HAS_CACHED_PROTO(key) \ + (uint32_t(key) << JSCLASS_CACHED_PROTO_SHIFT) +#define JSCLASS_CACHED_PROTO_KEY(clasp) \ + ((JSProtoKey)(((clasp)->flags >> JSCLASS_CACHED_PROTO_SHIFT) & \ + JSCLASS_CACHED_PROTO_MASK)) // Initializer for unused members of statically initialized JSClass structs. -#define JSCLASS_NO_INTERNAL_MEMBERS {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} -#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,JSCLASS_NO_INTERNAL_MEMBERS +#define JSCLASS_NO_INTERNAL_MEMBERS \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +#define JSCLASS_NO_OPTIONAL_MEMBERS 0, 0, 0, 0, 0, JSCLASS_NO_INTERNAL_MEMBERS namespace js { -struct Class -{ - 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 - * describe their properties and layout. Classes using this flag must - * provide their own property behavior, either by being proxy classes (do - * this) or by overriding all the ObjectOps except getElements, watch and - * unwatch (don't do this). - */ - static const uint32_t NON_NATIVE = JSCLASS_INTERNAL_FLAG2; - - bool isNative() const { - return !(flags & NON_NATIVE); - } - - bool hasPrivate() const { - return !!(flags & JSCLASS_HAS_PRIVATE); - } - - bool emulatesUndefined() const { - return flags & JSCLASS_EMULATES_UNDEFINED; - } - - bool isJSFunction() const { - return this == js::FunctionClassPtr; - } - - bool nonProxyCallable() const { - MOZ_ASSERT(!isProxy()); - return isJSFunction() || getCall(); - } - - bool isProxy() const { - return flags & JSCLASS_IS_PROXY; - } - - bool isDOMClass() const { - return flags & JSCLASS_IS_DOMJSCLASS; - } - - 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; } +struct JS_STATIC_CLASS Class { + 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 + * describe their properties and layout. Classes using this flag must + * provide their own property behavior, either by being proxy classes (do + * this) or by overriding all the ObjectOps except getElements + * (don't do this). + */ + static const uint32_t NON_NATIVE = JSCLASS_INTERNAL_FLAG2; + + bool isNative() const { return !(flags & NON_NATIVE); } + + bool hasPrivate() const { return !!(flags & JSCLASS_HAS_PRIVATE); } + + bool emulatesUndefined() const { return flags & JSCLASS_EMULATES_UNDEFINED; } + + bool isJSFunction() const { return this == js::FunctionClassPtr; } + + bool nonProxyCallable() const { + MOZ_ASSERT(!isProxy()); + return isJSFunction() || getCall(); + } + + bool isProxy() const { return flags & JSCLASS_IS_PROXY; } + + bool isDOMClass() const { return flags & JSCLASS_IS_DOMJSCLASS; } + + 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->createConstructor : nullptr; + } + ClassObjectCreationOp specCreatePrototypeHook() const { + return spec ? spec->createPrototype : 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->finishInit : 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; + } + GetElementsOp getOpsGetElements() const { + return oOps ? oOps->getElements : 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), +static_assert(offsetof(JSClassOps, addProperty) == + offsetof(ClassOps, addProperty), "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), +static_assert(offsetof(JSClassOps, delProperty) == + offsetof(ClassOps, delProperty), "ClassOps and JSClassOps must be consistent"); static_assert(offsetof(JSClassOps, enumerate) == offsetof(ClassOps, enumerate), "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, newEnumerate) == + offsetof(ClassOps, newEnumerate), + "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), +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"); @@ -927,7 +977,8 @@ "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), +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"); @@ -943,16 +994,12 @@ static_assert(sizeof(JSClass) == sizeof(Class), "Class and JSClass must be consistent"); -static MOZ_ALWAYS_INLINE const JSClass* -Jsvalify(const Class* c) -{ - return (const JSClass*)c; +static MOZ_ALWAYS_INLINE const JSClass* Jsvalify(const Class* c) { + return (const JSClass*)c; } -static MOZ_ALWAYS_INLINE const Class* -Valueify(const JSClass* c) -{ - return (const Class*)c; +static MOZ_ALWAYS_INLINE const Class* Valueify(const JSClass* c) { + return (const Class*)c; } /** @@ -960,36 +1007,34 @@ * value of objects. */ enum class ESClass { - Object, - Array, - Number, - String, - Boolean, - RegExp, - ArrayBuffer, - SharedArrayBuffer, - Date, - Set, - Map, - Promise, - MapIterator, - SetIterator, - Arguments, - Error, + Object, + Array, + Number, + String, + Boolean, + RegExp, + ArrayBuffer, + SharedArrayBuffer, + Date, + Set, + Map, + Promise, + MapIterator, + SetIterator, + Arguments, + Error, - /** None of the above. */ - Other + /** None of the above. */ + Other }; /* Fills |vp| with the unboxed value for boxed types, or undefined otherwise. */ -bool -Unbox(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp); +bool Unbox(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp); #ifdef DEBUG -JS_FRIEND_API(bool) -HasObjectMovedOp(JSObject* obj); +JS_FRIEND_API bool HasObjectMovedOp(JSObject* obj); #endif -} /* namespace js */ +} /* namespace js */ -#endif /* js_Class_h */ +#endif /* js_Class_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Conversions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Conversions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Conversions.h @@ -11,7 +11,9 @@ #include "mozilla/Casting.h" #include "mozilla/FloatingPoint.h" +#include "mozilla/MathAlgorithms.h" #include "mozilla/TypeTraits.h" +#include "mozilla/WrappingOperations.h" #include @@ -20,59 +22,55 @@ #include "js/RootingAPI.h" #include "js/Value.h" -struct JSContext; - namespace js { /* DO NOT CALL THIS. Use JS::ToBoolean. */ -extern JS_PUBLIC_API(bool) -ToBooleanSlow(JS::HandleValue v); +extern JS_PUBLIC_API bool ToBooleanSlow(JS::HandleValue v); /* DO NOT CALL THIS. Use JS::ToNumber. */ -extern JS_PUBLIC_API(bool) -ToNumberSlow(JSContext* cx, JS::HandleValue v, double* dp); +extern JS_PUBLIC_API bool 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); +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); +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); +extern JS_PUBLIC_API bool ToInt16Slow(JSContext* cx, JS::HandleValue v, + int16_t* out); /* DO NOT CALL THIS. Use JS::ToInt32. */ -extern JS_PUBLIC_API(bool) -ToInt32Slow(JSContext* cx, JS::HandleValue v, int32_t* out); +extern JS_PUBLIC_API bool ToInt32Slow(JSContext* cx, JS::HandleValue v, + int32_t* out); /* DO NOT CALL THIS. Use JS::ToUint32. */ -extern JS_PUBLIC_API(bool) -ToUint32Slow(JSContext* cx, JS::HandleValue v, uint32_t* out); +extern JS_PUBLIC_API bool ToUint32Slow(JSContext* cx, JS::HandleValue v, + uint32_t* out); /* DO NOT CALL THIS. Use JS::ToUint16. */ -extern JS_PUBLIC_API(bool) -ToUint16Slow(JSContext* cx, JS::HandleValue v, uint16_t* out); +extern JS_PUBLIC_API bool ToUint16Slow(JSContext* cx, JS::HandleValue v, + uint16_t* out); /* DO NOT CALL THIS. Use JS::ToInt64. */ -extern JS_PUBLIC_API(bool) -ToInt64Slow(JSContext* cx, JS::HandleValue v, int64_t* out); +extern JS_PUBLIC_API bool ToInt64Slow(JSContext* cx, JS::HandleValue v, + int64_t* out); /* DO NOT CALL THIS. Use JS::ToUint64. */ -extern JS_PUBLIC_API(bool) -ToUint64Slow(JSContext* cx, JS::HandleValue v, uint64_t* out); +extern JS_PUBLIC_API bool ToUint64Slow(JSContext* cx, JS::HandleValue v, + uint64_t* out); /* DO NOT CALL THIS. Use JS::ToString. */ -extern JS_PUBLIC_API(JSString*) -ToStringSlow(JSContext* cx, JS::HandleValue v); +extern JS_PUBLIC_API JSString* ToStringSlow(JSContext* cx, JS::HandleValue v); /* DO NOT CALL THIS. Use JS::ToObject. */ -extern JS_PUBLIC_API(JSObject*) -ToObjectSlow(JSContext* cx, JS::HandleValue v, bool reportScanStack); +extern JS_PUBLIC_API JSObject* ToObjectSlow(JSContext* cx, JS::HandleValue v, + bool reportScanStack); -} // namespace js +} // namespace js namespace JS { @@ -84,14 +82,12 @@ * needed, and that the compartments for cx and v are correct. * Also check that GC would be safe at this point. */ -extern JS_PUBLIC_API(void) -AssertArgumentsAreSane(JSContext* cx, HandleValue v); +extern JS_PUBLIC_API void AssertArgumentsAreSane(JSContext* cx, HandleValue v); #else -inline void AssertArgumentsAreSane(JSContext* cx, HandleValue v) -{} +inline void AssertArgumentsAreSane(JSContext* cx, HandleValue v) {} #endif /* JS_DEBUG */ -} // namespace detail +} // namespace detail /** * ES6 draft 20141224, 7.1.1, second algorithm. @@ -101,189 +97,156 @@ * wish to fall back to the ES6 default conversion behavior shared by most * objects in JS, codified as OrdinaryToPrimitive. */ -extern JS_PUBLIC_API(bool) -OrdinaryToPrimitive(JSContext* cx, HandleObject obj, JSType type, MutableHandleValue vp); +extern JS_PUBLIC_API bool OrdinaryToPrimitive(JSContext* cx, HandleObject obj, + JSType type, + MutableHandleValue vp); /* ES6 draft 20141224, 7.1.2. */ -MOZ_ALWAYS_INLINE bool -ToBoolean(HandleValue v) -{ - if (v.isBoolean()) - return v.toBoolean(); - if (v.isInt32()) - return v.toInt32() != 0; - if (v.isNullOrUndefined()) - return false; - if (v.isDouble()) { - double d = v.toDouble(); - return !mozilla::IsNaN(d) && d != 0; - } - if (v.isSymbol()) - return true; +MOZ_ALWAYS_INLINE bool ToBoolean(HandleValue v) { + if (v.isBoolean()) return v.toBoolean(); + if (v.isInt32()) return v.toInt32() != 0; + if (v.isNullOrUndefined()) return false; + if (v.isDouble()) { + double d = v.toDouble(); + return !mozilla::IsNaN(d) && d != 0; + } + if (v.isSymbol()) return true; - /* The slow path handles strings and objects. */ - return js::ToBooleanSlow(v); + /* The slow path handles strings and objects. */ + return js::ToBooleanSlow(v); } /* ES6 draft 20141224, 7.1.3. */ -MOZ_ALWAYS_INLINE bool -ToNumber(JSContext* cx, HandleValue v, double* out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isNumber()) { - *out = v.toNumber(); - return true; - } - return js::ToNumberSlow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToNumber(JSContext* cx, HandleValue v, double* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isNumber()) { + *out = v.toNumber(); + return true; + } + return js::ToNumberSlow(cx, v, out); } /* ES6 draft 20141224, ToInteger (specialized for doubles). */ -inline double -ToInteger(double d) -{ - if (d == 0) - return d; - - if (!mozilla::IsFinite(d)) { - if (mozilla::IsNaN(d)) - return 0; - return d; - } +inline double ToInteger(double d) { + if (d == 0) return d; + + if (!mozilla::IsFinite(d)) { + if (mozilla::IsNaN(d)) return 0; + return d; + } - return d < 0 ? ceil(d) : floor(d); + return d < 0 ? ceil(d) : floor(d); } /* ES6 draft 20141224, 7.1.5. */ -MOZ_ALWAYS_INLINE bool -ToInt32(JSContext* cx, JS::HandleValue v, int32_t* out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isInt32()) { - *out = v.toInt32(); - return true; - } - return js::ToInt32Slow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToInt32(JSContext* cx, JS::HandleValue v, int32_t* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = v.toInt32(); + return true; + } + return js::ToInt32Slow(cx, v, out); } /* ES6 draft 20141224, 7.1.6. */ -MOZ_ALWAYS_INLINE bool -ToUint32(JSContext* cx, HandleValue v, uint32_t* out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isInt32()) { - *out = uint32_t(v.toInt32()); - return true; - } - return js::ToUint32Slow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToUint32(JSContext* cx, HandleValue v, uint32_t* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = uint32_t(v.toInt32()); + return true; + } + return js::ToUint32Slow(cx, v, out); } /* ES6 draft 20141224, 7.1.7. */ -MOZ_ALWAYS_INLINE bool -ToInt16(JSContext *cx, JS::HandleValue v, int16_t *out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isInt32()) { - *out = int16_t(v.toInt32()); - return true; - } - return js::ToInt16Slow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToInt16(JSContext* cx, JS::HandleValue v, int16_t* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = int16_t(v.toInt32()); + return true; + } + return js::ToInt16Slow(cx, v, out); } /* ES6 draft 20141224, 7.1.8. */ -MOZ_ALWAYS_INLINE bool -ToUint16(JSContext* cx, HandleValue v, uint16_t* out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isInt32()) { - *out = uint16_t(v.toInt32()); - return true; - } - return js::ToUint16Slow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToUint16(JSContext* cx, HandleValue v, uint16_t* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = uint16_t(v.toInt32()); + return true; + } + return js::ToUint16Slow(cx, v, out); } /* ES6 draft 20141224, 7.1.9 */ -MOZ_ALWAYS_INLINE bool -ToInt8(JSContext *cx, JS::HandleValue v, int8_t *out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isInt32()) { - *out = int8_t(v.toInt32()); - return true; - } - return js::ToInt8Slow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToInt8(JSContext* cx, JS::HandleValue v, int8_t* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = int8_t(v.toInt32()); + return true; + } + 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); +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. */ -MOZ_ALWAYS_INLINE bool -ToInt64(JSContext* cx, HandleValue v, int64_t* out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isInt32()) { - *out = int64_t(v.toInt32()); - return true; - } - return js::ToInt64Slow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToInt64(JSContext* cx, HandleValue v, int64_t* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = int64_t(v.toInt32()); + return true; + } + return js::ToInt64Slow(cx, v, out); } /* * Non-standard, with behavior similar to that of ToUint32, except in its * producing a uint64_t. */ -MOZ_ALWAYS_INLINE bool -ToUint64(JSContext* cx, HandleValue v, uint64_t* out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isInt32()) { - *out = uint64_t(v.toInt32()); - return true; - } - return js::ToUint64Slow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToUint64(JSContext* cx, HandleValue v, uint64_t* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = uint64_t(v.toInt32()); + return true; + } + return js::ToUint64Slow(cx, v, out); } /* ES6 draft 20141224, 7.1.12. */ -MOZ_ALWAYS_INLINE JSString* -ToString(JSContext* cx, HandleValue v) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isString()) - return v.toString(); - return js::ToStringSlow(cx, v); +MOZ_ALWAYS_INLINE JSString* ToString(JSContext* cx, HandleValue v) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isString()) return v.toString(); + return js::ToStringSlow(cx, v); } /* ES6 draft 20141224, 7.1.13. */ -inline JSObject* -ToObject(JSContext* cx, HandleValue v) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isObject()) - return &v.toObject(); - return js::ToObjectSlow(cx, v, false); +inline JSObject* ToObject(JSContext* cx, HandleValue v) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isObject()) return &v.toObject(); + return js::ToObjectSlow(cx, v, false); } namespace detail { @@ -301,281 +264,248 @@ * * but has been generalized to all integer widths. */ -template -inline ResultType -ToUintWidth(double d) -{ - static_assert(mozilla::IsUnsigned::value, - "ResultType must be an unsigned type"); - - uint64_t bits = mozilla::BitwiseCast(d); - unsigned DoubleExponentShift = mozilla::FloatingPoint::kExponentShift; - - // Extract the exponent component. (Be careful here! It's not technically - // the exponent in NaN, infinities, and subnormals.) - int_fast16_t exp = - int_fast16_t((bits & mozilla::FloatingPoint::kExponentBits) >> DoubleExponentShift) - - int_fast16_t(mozilla::FloatingPoint::kExponentBias); - - // If the exponent's less than zero, abs(d) < 1, so the result is 0. (This - // also handles subnormals.) - if (exp < 0) - return 0; - - uint_fast16_t exponent = mozilla::AssertedCast(exp); - - // If the exponent is greater than or equal to the bits of precision of a - // double plus ResultType's width, the number is either infinite, NaN, or - // too large to have lower-order bits in the congruent value. (Example: - // 2**84 is exactly representable as a double. The next exact double is - // 2**84 + 2**32. Thus if ResultType is int32_t, an exponent >= 84 implies - // floor(abs(d)) == 0 mod 2**32.) Return 0 in all these cases. - const size_t ResultWidth = CHAR_BIT * sizeof(ResultType); - if (exponent >= DoubleExponentShift + ResultWidth) - return 0; - - // The significand contains the bits that will determine the final result. - // Shift those bits left or right, according to the exponent, to their - // locations in the unsigned binary representation of floor(abs(d)). - static_assert(sizeof(ResultType) <= sizeof(uint64_t), - "Left-shifting below would lose upper bits"); - ResultType result = (exponent > DoubleExponentShift) - ? ResultType(bits << (exponent - DoubleExponentShift)) - : ResultType(bits >> (DoubleExponentShift - exponent)); - - // Two further complications remain. First, |result| may contain bogus - // sign/exponent bits. Second, IEEE-754 numbers' significands (excluding - // subnormals, but we already handled those) have an implicit leading 1 - // which may affect the final result. - // - // It may appear that there's complexity here depending on how ResultWidth - // and DoubleExponentShift relate, but it turns out there's not. - // - // Assume ResultWidth < DoubleExponentShift: - // Only right-shifts leave bogus bits in |result|. For this to happen, - // we must right-shift by > |DoubleExponentShift - ResultWidth|, implying - // |exponent < ResultWidth|. - // The implicit leading bit only matters if it appears in the final - // result -- if |2**exponent mod 2**ResultWidth != 0|. This implies - // |exponent < ResultWidth|. - // Otherwise assume ResultWidth >= DoubleExponentShift: - // Any left-shift less than |ResultWidth - DoubleExponentShift| leaves - // bogus bits in |result|. This implies |exponent < ResultWidth|. Any - // right-shift less than |ResultWidth| does too, which implies - // |DoubleExponentShift - ResultWidth < exponent|. By assumption, then, - // |exponent| is negative, but we excluded that above. So bogus bits - // need only |exponent < ResultWidth|. - // The implicit leading bit matters identically to the other case, so - // again, |exponent < ResultWidth|. - if (exponent < ResultWidth) { - ResultType implicitOne = ResultType(1) << exponent; - result &= implicitOne - 1; // remove bogus bits - result += implicitOne; // add the implicit bit - } - - // Compute the congruent value in the signed range. - return (bits & mozilla::FloatingPoint::kSignBit) ? ~result + 1 : result; -} - -template -inline ResultType -ToIntWidth(double d) -{ - static_assert(mozilla::IsSigned::value, - "ResultType must be a signed type"); - - const ResultType MaxValue = (1ULL << (CHAR_BIT * sizeof(ResultType) - 1)) - 1; - const ResultType MinValue = -MaxValue - 1; - - typedef typename mozilla::MakeUnsigned::Type UnsignedResult; - UnsignedResult u = ToUintWidth(d); - if (u <= UnsignedResult(MaxValue)) - return static_cast(u); - return (MinValue + static_cast(u - MaxValue)) - 1; +template +inline ResultType ToUintWidth(double d) { + static_assert(mozilla::IsUnsigned::value, + "ResultType must be an unsigned type"); + + uint64_t bits = mozilla::BitwiseCast(d); + unsigned DoubleExponentShift = mozilla::FloatingPoint::kExponentShift; + + // Extract the exponent component. (Be careful here! It's not technically + // the exponent in NaN, infinities, and subnormals.) + int_fast16_t exp = + int_fast16_t((bits & mozilla::FloatingPoint::kExponentBits) >> + DoubleExponentShift) - + int_fast16_t(mozilla::FloatingPoint::kExponentBias); + + // If the exponent's less than zero, abs(d) < 1, so the result is 0. (This + // also handles subnormals.) + if (exp < 0) return 0; + + uint_fast16_t exponent = mozilla::AssertedCast(exp); + + // If the exponent is greater than or equal to the bits of precision of a + // double plus ResultType's width, the number is either infinite, NaN, or + // too large to have lower-order bits in the congruent value. (Example: + // 2**84 is exactly representable as a double. The next exact double is + // 2**84 + 2**32. Thus if ResultType is int32_t, an exponent >= 84 implies + // floor(abs(d)) == 0 mod 2**32.) Return 0 in all these cases. + const size_t ResultWidth = CHAR_BIT * sizeof(ResultType); + if (exponent >= DoubleExponentShift + ResultWidth) return 0; + + // The significand contains the bits that will determine the final result. + // Shift those bits left or right, according to the exponent, to their + // locations in the unsigned binary representation of floor(abs(d)). + static_assert(sizeof(ResultType) <= sizeof(uint64_t), + "Left-shifting below would lose upper bits"); + ResultType result = + (exponent > DoubleExponentShift) + ? ResultType(bits << (exponent - DoubleExponentShift)) + : ResultType(bits >> (DoubleExponentShift - exponent)); + + // Two further complications remain. First, |result| may contain bogus + // sign/exponent bits. Second, IEEE-754 numbers' significands (excluding + // subnormals, but we already handled those) have an implicit leading 1 + // which may affect the final result. + // + // It may appear that there's complexity here depending on how ResultWidth + // and DoubleExponentShift relate, but it turns out there's not. + // + // Assume ResultWidth < DoubleExponentShift: + // Only right-shifts leave bogus bits in |result|. For this to happen, + // we must right-shift by > |DoubleExponentShift - ResultWidth|, implying + // |exponent < ResultWidth|. + // The implicit leading bit only matters if it appears in the final + // result -- if |2**exponent mod 2**ResultWidth != 0|. This implies + // |exponent < ResultWidth|. + // Otherwise assume ResultWidth >= DoubleExponentShift: + // Any left-shift less than |ResultWidth - DoubleExponentShift| leaves + // bogus bits in |result|. This implies |exponent < ResultWidth|. Any + // right-shift less than |ResultWidth| does too, which implies + // |DoubleExponentShift - ResultWidth < exponent|. By assumption, then, + // |exponent| is negative, but we excluded that above. So bogus bits + // need only |exponent < ResultWidth|. + // The implicit leading bit matters identically to the other case, so + // again, |exponent < ResultWidth|. + if (exponent < ResultWidth) { + ResultType implicitOne = ResultType(1) << exponent; + result &= implicitOne - 1; // remove bogus bits + result += implicitOne; // add the implicit bit + } + + // Compute the congruent value in the signed range. + return (bits & mozilla::FloatingPoint::kSignBit) ? ~result + 1 + : result; +} + +template +inline ResultType ToIntWidth(double d) { + static_assert(mozilla::IsSigned::value, + "ResultType must be a signed type"); + + using UnsignedResult = typename mozilla::MakeUnsigned::Type; + UnsignedResult u = ToUintWidth(d); + + return mozilla::WrapToSigned(u); } -} // namespace detail +} // namespace detail /* ES5 9.5 ToInt32 (specialized for doubles). */ -inline int32_t -ToInt32(double d) -{ - // clang crashes compiling this when targeting arm: - // https://llvm.org/bugs/show_bug.cgi?id=22974 -#if defined (__arm__) && defined (__GNUC__) && !defined(__clang__) - int32_t i; - uint32_t tmp0; - uint32_t tmp1; - uint32_t tmp2; - asm ( - // We use a pure integer solution here. In the 'softfp' ABI, the argument - // will start in r0 and r1, and VFP can't do all of the necessary ECMA - // conversions by itself so some integer code will be required anyway. A - // hybrid solution is faster on A9, but this pure integer solution is - // notably faster for A8. - - // %0 is the result register, and may alias either of the %[QR]1 registers. - // %Q4 holds the lower part of the mantissa. - // %R4 holds the sign, exponent, and the upper part of the mantissa. - // %1, %2 and %3 are used as temporary values. - - // Extract the exponent. -" mov %1, %R4, LSR #20\n" -" bic %1, %1, #(1 << 11)\n" // Clear the sign. - - // Set the implicit top bit of the mantissa. This clobbers a bit of the - // exponent, but we have already extracted that. -" orr %R4, %R4, #(1 << 20)\n" - - // Special Cases - // We should return zero in the following special cases: - // - Exponent is 0x000 - 1023: +/-0 or subnormal. - // - Exponent is 0x7ff - 1023: +/-INFINITY or NaN - // - This case is implicitly handled by the standard code path anyway, - // as shifting the mantissa up by the exponent will result in '0'. - // - // The result is composed of the mantissa, prepended with '1' and - // bit-shifted left by the (decoded) exponent. Note that because the r1[20] - // is the bit with value '1', r1 is effectively already shifted (left) by - // 20 bits, and r0 is already shifted by 52 bits. - - // Adjust the exponent to remove the encoding offset. If the decoded - // exponent is negative, quickly bail out with '0' as such values round to - // zero anyway. This also catches +/-0 and subnormals. -" sub %1, %1, #0xff\n" -" subs %1, %1, #0x300\n" -" bmi 8f\n" - - // %1 = (decoded) exponent >= 0 - // %R4 = upper mantissa and sign - - // ---- Lower Mantissa ---- -" subs %3, %1, #52\n" // Calculate exp-52 -" bmi 1f\n" - - // Shift r0 left by exp-52. - // Ensure that we don't overflow ARM's 8-bit shift operand range. - // We need to handle anything up to an 11-bit value here as we know that - // 52 <= exp <= 1024 (0x400). Any shift beyond 31 bits results in zero - // anyway, so as long as we don't touch the bottom 5 bits, we can use - // a logical OR to push long shifts into the 32 <= (exp&0xff) <= 255 range. -" bic %2, %3, #0xff\n" -" orr %3, %3, %2, LSR #3\n" - // We can now perform a straight shift, avoiding the need for any - // conditional instructions or extra branches. -" mov %Q4, %Q4, LSL %3\n" -" b 2f\n" -"1:\n" // Shift r0 right by 52-exp. - // We know that 0 <= exp < 52, and we can shift up to 255 bits so 52-exp - // will always be a valid shift and we can sk%3 the range check for this case. -" rsb %3, %1, #52\n" -" mov %Q4, %Q4, LSR %3\n" - - // %1 = (decoded) exponent - // %R4 = upper mantissa and sign - // %Q4 = partially-converted integer - -"2:\n" - // ---- Upper Mantissa ---- - // This is much the same as the lower mantissa, with a few different - // boundary checks and some masking to hide the exponent & sign bit in the - // upper word. - // Note that the upper mantissa is pre-shifted by 20 in %R4, but we shift - // it left more to remove the sign and exponent so it is effectively - // pre-shifted by 31 bits. -" subs %3, %1, #31\n" // Calculate exp-31 -" mov %1, %R4, LSL #11\n" // Re-use %1 as a temporary register. -" bmi 3f\n" - - // Shift %R4 left by exp-31. - // Avoid overflowing the 8-bit shift range, as before. -" bic %2, %3, #0xff\n" -" orr %3, %3, %2, LSR #3\n" - // Perform the shift. -" mov %2, %1, LSL %3\n" -" b 4f\n" -"3:\n" // Shift r1 right by 31-exp. - // We know that 0 <= exp < 31, and we can shift up to 255 bits so 31-exp - // will always be a valid shift and we can skip the range check for this case. -" rsb %3, %3, #0\n" // Calculate 31-exp from -(exp-31) -" mov %2, %1, LSR %3\n" // Thumb-2 can't do "LSR %3" in "orr". - - // %Q4 = partially-converted integer (lower) - // %R4 = upper mantissa and sign - // %2 = partially-converted integer (upper) - -"4:\n" - // Combine the converted parts. -" orr %Q4, %Q4, %2\n" - // Negate the result if we have to, and move it to %0 in the process. To - // avoid conditionals, we can do this by inverting on %R4[31], then adding - // %R4[31]>>31. -" eor %Q4, %Q4, %R4, ASR #31\n" -" add %0, %Q4, %R4, LSR #31\n" -" b 9f\n" -"8:\n" - // +/-INFINITY, +/-0, subnormals, NaNs, and anything else out-of-range that - // will result in a conversion of '0'. -" mov %0, #0\n" -"9:\n" - : "=r" (i), "=&r" (tmp0), "=&r" (tmp1), "=&r" (tmp2), "=&r" (d) - : "4" (d) - : "cc" - ); - return i; +inline int32_t ToInt32(double d) { +// clang crashes compiling this when targeting arm: +// https://llvm.org/bugs/show_bug.cgi?id=22974 +#if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) + int32_t i; + uint32_t tmp0; + uint32_t tmp1; + uint32_t tmp2; + asm( + // We use a pure integer solution here. In the 'softfp' ABI, the argument + // will start in r0 and r1, and VFP can't do all of the necessary ECMA + // conversions by itself so some integer code will be required anyway. A + // hybrid solution is faster on A9, but this pure integer solution is + // notably faster for A8. + + // %0 is the result register, and may alias either of the %[QR]1 + // registers. + // %Q4 holds the lower part of the mantissa. + // %R4 holds the sign, exponent, and the upper part of the mantissa. + // %1, %2 and %3 are used as temporary values. + + // Extract the exponent. + " mov %1, %R4, LSR #20\n" + " bic %1, %1, #(1 << 11)\n" // Clear the sign. + + // Set the implicit top bit of the mantissa. This clobbers a bit of the + // exponent, but we have already extracted that. + " orr %R4, %R4, #(1 << 20)\n" + + // Special Cases + // We should return zero in the following special cases: + // - Exponent is 0x000 - 1023: +/-0 or subnormal. + // - Exponent is 0x7ff - 1023: +/-INFINITY or NaN + // - This case is implicitly handled by the standard code path + // anyway, as shifting the mantissa up by the exponent will + // result in '0'. + // + // The result is composed of the mantissa, prepended with '1' and + // bit-shifted left by the (decoded) exponent. Note that because the + // r1[20] is the bit with value '1', r1 is effectively already shifted + // (left) by 20 bits, and r0 is already shifted by 52 bits. + + // Adjust the exponent to remove the encoding offset. If the decoded + // exponent is negative, quickly bail out with '0' as such values round to + // zero anyway. This also catches +/-0 and subnormals. + " sub %1, %1, #0xff\n" + " subs %1, %1, #0x300\n" + " bmi 8f\n" + + // %1 = (decoded) exponent >= 0 + // %R4 = upper mantissa and sign + + // ---- Lower Mantissa ---- + " subs %3, %1, #52\n" // Calculate exp-52 + " bmi 1f\n" + + // Shift r0 left by exp-52. + // Ensure that we don't overflow ARM's 8-bit shift operand range. + // We need to handle anything up to an 11-bit value here as we know that + // 52 <= exp <= 1024 (0x400). Any shift beyond 31 bits results in zero + // anyway, so as long as we don't touch the bottom 5 bits, we can use + // a logical OR to push long shifts into the 32 <= (exp&0xff) <= 255 + // range. + " bic %2, %3, #0xff\n" + " orr %3, %3, %2, LSR #3\n" + // We can now perform a straight shift, avoiding the need for any + // conditional instructions or extra branches. + " mov %Q4, %Q4, LSL %3\n" + " b 2f\n" + "1:\n" // Shift r0 right by 52-exp. + // We know that 0 <= exp < 52, and we can shift up to 255 bits so + // 52-exp will always be a valid shift and we can sk%3 the range + // check for this case. + " rsb %3, %1, #52\n" + " mov %Q4, %Q4, LSR %3\n" + + // %1 = (decoded) exponent + // %R4 = upper mantissa and sign + // %Q4 = partially-converted integer + + "2:\n" + // ---- Upper Mantissa ---- + // This is much the same as the lower mantissa, with a few different + // boundary checks and some masking to hide the exponent & sign bit in the + // upper word. + // Note that the upper mantissa is pre-shifted by 20 in %R4, but we shift + // it left more to remove the sign and exponent so it is effectively + // pre-shifted by 31 bits. + " subs %3, %1, #31\n" // Calculate exp-31 + " mov %1, %R4, LSL #11\n" // Re-use %1 as a temporary register. + " bmi 3f\n" + + // Shift %R4 left by exp-31. + // Avoid overflowing the 8-bit shift range, as before. + " bic %2, %3, #0xff\n" + " orr %3, %3, %2, LSR #3\n" + // Perform the shift. + " mov %2, %1, LSL %3\n" + " b 4f\n" + "3:\n" // Shift r1 right by 31-exp. + // We know that 0 <= exp < 31, and we can shift up to 255 bits so + // 31-exp will always be a valid shift and we can skip the range + // check for this case. + " rsb %3, %3, #0\n" // Calculate 31-exp from -(exp-31) + " mov %2, %1, LSR %3\n" // Thumb-2 can't do "LSR %3" in "orr". + + // %Q4 = partially-converted integer (lower) + // %R4 = upper mantissa and sign + // %2 = partially-converted integer (upper) + + "4:\n" + // Combine the converted parts. + " orr %Q4, %Q4, %2\n" + // Negate the result if we have to, and move it to %0 in the process. To + // avoid conditionals, we can do this by inverting on %R4[31], then adding + // %R4[31]>>31. + " eor %Q4, %Q4, %R4, ASR #31\n" + " add %0, %Q4, %R4, LSR #31\n" + " b 9f\n" + "8:\n" + // +/-INFINITY, +/-0, subnormals, NaNs, and anything else out-of-range + // that will result in a conversion of '0'. + " mov %0, #0\n" + "9:\n" + : "=r"(i), "=&r"(tmp0), "=&r"(tmp1), "=&r"(tmp2), "=&r"(d) + : "4"(d) + : "cc"); + return i; #else - return detail::ToIntWidth(d); + return detail::ToIntWidth(d); #endif } /* ES5 9.6 (specialized for doubles). */ -inline uint32_t -ToUint32(double d) -{ - return detail::ToUintWidth(d); -} +inline uint32_t ToUint32(double d) { return detail::ToUintWidth(d); } /* WEBIDL 4.2.4 */ -inline int8_t -ToInt8(double d) -{ - return detail::ToIntWidth(d); -} +inline int8_t ToInt8(double d) { return detail::ToIntWidth(d); } /* ECMA-262 7.1.10 ToUInt8() specialized for doubles. */ -inline int8_t -ToUint8(double d) -{ - return detail::ToUintWidth(d); -} +inline int8_t ToUint8(double d) { return detail::ToUintWidth(d); } /* WEBIDL 4.2.6 */ -inline int16_t -ToInt16(double d) -{ - return detail::ToIntWidth(d); -} +inline int16_t ToInt16(double d) { return detail::ToIntWidth(d); } -inline uint16_t -ToUint16(double d) -{ - return detail::ToUintWidth(d); -} +inline uint16_t ToUint16(double d) { return detail::ToUintWidth(d); } /* WEBIDL 4.2.10 */ -inline int64_t -ToInt64(double d) -{ - return detail::ToIntWidth(d); -} +inline int64_t ToInt64(double d) { return detail::ToIntWidth(d); } /* WEBIDL 4.2.11 */ -inline uint64_t -ToUint64(double d) -{ - return detail::ToUintWidth(d); -} +inline uint64_t ToUint64(double d) { return detail::ToUintWidth(d); } -} // namespace JS +} // namespace JS #endif /* js_Conversions_h */ 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 @@ -35,8 +35,6 @@ #include "js/Conversions.h" #include "js/Value.h" -struct JSContext; - namespace JS { /** @@ -52,8 +50,7 @@ * changes, or immediately before operations requiring instantaneous * correctness, to guarantee correct behavior. */ -extern JS_PUBLIC_API(void) -ResetTimeZone(); +extern JS_PUBLIC_API void ResetTimeZone(); class ClippedTime; inline ClippedTime TimeClip(double time); @@ -76,78 +73,76 @@ * JavaScript dates. This also forces users to perform any desired clipping, * as only the user knows what behavior is desired when clipping occurs. */ -class ClippedTime -{ - double t; +class ClippedTime { + double t; - explicit ClippedTime(double time) : t(time) {} - friend ClippedTime TimeClip(double time); + explicit ClippedTime(double time) : t(time) {} + friend ClippedTime TimeClip(double time); - public: - // Create an invalid date. - ClippedTime() : t(mozilla::UnspecifiedNaN()) {} + public: + // Create an invalid date. + ClippedTime() : t(mozilla::UnspecifiedNaN()) {} - // Create an invalid date/time, more explicitly; prefer this to the default - // constructor. - static ClippedTime invalid() { return ClippedTime(); } + // Create an invalid date/time, more explicitly; prefer this to the default + // constructor. + static ClippedTime invalid() { return ClippedTime(); } - double toDouble() const { return t; } + double toDouble() const { return t; } - bool isValid() const { return !mozilla::IsNaN(t); } + bool isValid() const { return !mozilla::IsNaN(t); } }; // ES6 20.3.1.15. // // Clip a double to JavaScript's date range (or to an invalid date) using the // ECMAScript TimeClip algorithm. -inline ClippedTime -TimeClip(double time) -{ - // Steps 1-2. - const double MaxTimeMagnitude = 8.64e15; - if (!mozilla::IsFinite(time) || mozilla::Abs(time) > MaxTimeMagnitude) - return ClippedTime(mozilla::UnspecifiedNaN()); +inline ClippedTime TimeClip(double time) { + // Steps 1-2. + const double MaxTimeMagnitude = 8.64e15; + if (!mozilla::IsFinite(time) || mozilla::Abs(time) > MaxTimeMagnitude) + return ClippedTime(mozilla::UnspecifiedNaN()); - // Step 3. - return ClippedTime(ToInteger(time) + (+0.0)); + // Step 3. + return ClippedTime(ToInteger(time) + (+0.0)); } // Produce a double Value from the given time. Because times may be NaN, // prefer using this to manual canonicalization. -inline Value -TimeValue(ClippedTime time) -{ - return DoubleValue(JS::CanonicalizeNaN(time.toDouble())); +inline Value TimeValue(ClippedTime time) { + return DoubleValue(JS::CanonicalizeNaN(time.toDouble())); } // Create a new Date object whose [[DateValue]] internal slot contains the // clipped |time|. (Users who must represent times outside that range must use // another representation.) -extern JS_PUBLIC_API(JSObject*) -NewDateObject(JSContext* cx, ClippedTime time); +extern JS_PUBLIC_API JSObject* NewDateObject(JSContext* cx, ClippedTime time); // Year is a year, month is 0-11, day is 1-based. The return value is a number // of milliseconds since the epoch. // // Consistent with the MakeDate algorithm defined in ECMAScript, this value is // *not* clipped! Use JS::TimeClip if you need a clipped date. -JS_PUBLIC_API(double) -MakeDate(double year, unsigned month, unsigned day); +JS_PUBLIC_API double MakeDate(double year, unsigned month, unsigned day); + +// Year is a year, month is 0-11, day is 1-based, and time is in milliseconds. +// The return value is a number of milliseconds since the epoch. +// +// Consistent with the MakeDate algorithm defined in ECMAScript, this value is +// *not* clipped! Use JS::TimeClip if you need a clipped date. +JS_PUBLIC_API double MakeDate(double year, unsigned month, unsigned day, + double time); // Takes an integer number of milliseconds since the epoch and returns the // year. Can return NaN, and will do so if NaN is passed in. -JS_PUBLIC_API(double) -YearFromTime(double time); +JS_PUBLIC_API double YearFromTime(double time); // Takes an integer number of milliseconds since the epoch and returns the // month (0-11). Can return NaN, and will do so if NaN is passed in. -JS_PUBLIC_API(double) -MonthFromTime(double time); +JS_PUBLIC_API double MonthFromTime(double time); // Takes an integer number of milliseconds since the epoch and returns the // day (1-based). Can return NaN, and will do so if NaN is passed in. -JS_PUBLIC_API(double) -DayFromTime(double time); +JS_PUBLIC_API double DayFromTime(double time); // Takes an integer year and returns the number of days from epoch to the given // year. @@ -155,16 +150,30 @@ // 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); +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); +// This should usually be ensured by computing |year| as +// |JS::DayFromYear(time)|. +JS_PUBLIC_API double DayWithinYear(double time, double year); + +// The callback will be a wrapper function that accepts a single double (the +// time to clamp and jitter.) Inside the JS Engine, other parameters that may be +// needed are all constant, so they are handled inside the wrapper function +using ReduceMicrosecondTimePrecisionCallback = double (*)(double); + +// Set a callback into the toolkit/components/resistfingerprinting function that +// will centralize time resolution and jitter into one place. +JS_PUBLIC_API void SetReduceMicrosecondTimePrecisionCallback( + ReduceMicrosecondTimePrecisionCallback callback); + +// Sets the time resolution for fingerprinting protection, and whether jitter +// should occur. If resolution is set to zero, then no rounding or jitter will +// occur. This is used if the callback above is not specified. +JS_PUBLIC_API void SetTimeResolutionUsec(uint32_t resolution, bool jitter); -} // namespace JS +} // 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 @@ -22,7 +22,7 @@ namespace js { class Debugger; -} // namespace js +} // namespace js namespace JS { namespace dbg { @@ -99,7 +99,8 @@ // return false; // result = builder.newObject(cx); // return result && -// result.defineProperty(cx, "eventType", SafelyFetchType(eventObject)) && +// result.defineProperty(cx, "eventType", +// SafelyFetchType(eventObject)) && // result.defineProperty(cx, "event", eventObject); // } // @@ -120,135 +121,134 @@ class BuilderOrigin; class Builder { - // The Debugger instance whose client we are building a value for. We build - // objects in this object's compartment. - PersistentRootedObject debuggerObject; - - // debuggerObject's Debugger structure, for convenience. - js::Debugger* debugger; - - // Check that |thing| is in the same compartment as our debuggerObject. Used - // for assertions when constructing BuiltThings. We can overload this as we - // add more instantiations of BuiltThing. + // The Debugger instance whose client we are building a value for. We build + // objects in this object's compartment. + PersistentRootedObject debuggerObject; + + // debuggerObject's Debugger structure, for convenience. + js::Debugger* debugger; + + // Check that |thing| is in the same compartment as our debuggerObject. Used + // for assertions when constructing BuiltThings. We can overload this as we + // add more instantiations of BuiltThing. #if DEBUG - void assertBuilt(JSObject* obj); + void assertBuilt(JSObject* obj); #else - void assertBuilt(JSObject* obj) { } + void assertBuilt(JSObject* obj) {} #endif - protected: - // A reference to a trusted object or value. At the moment, we only use it - // with JSObject*. - template - class BuiltThing { - friend class BuilderOrigin; - - protected: - // The Builder to which this trusted thing belongs. - Builder& owner; - - // A rooted reference to our value. - PersistentRooted value; - - BuiltThing(JSContext* cx, Builder& owner_, T value_ = GCPolicy::initial()) - : owner(owner_), value(cx, value_) - { - owner.assertBuilt(value_); - } - - // Forward some things from our owner, for convenience. - js::Debugger* debugger() const { return owner.debugger; } - JSObject* debuggerObject() const { return owner.debuggerObject; } - - public: - BuiltThing(const BuiltThing& rhs) : owner(rhs.owner), value(rhs.value) { } - BuiltThing& operator=(const BuiltThing& rhs) { - MOZ_ASSERT(&owner == &rhs.owner); - owner.assertBuilt(rhs.value); - value = rhs.value; - return *this; - } - - explicit operator bool() const { - // If we ever instantiate BuiltThing, this might not suffice. - return value; - } - - private: - BuiltThing() = delete; - }; - - public: - // A reference to a trusted object, possibly null. Instances of Object are - // always properly rooted. They can be copied and assigned, as if they were - // pointers. - class Object: private BuiltThing { - friend class Builder; // for construction - friend class BuilderOrigin; // for unwrapping - - typedef BuiltThing Base; - - // This is private, because only Builders can create Objects that - // actually point to something (hence the 'friend' declaration). - Object(JSContext* cx, Builder& owner_, HandleObject obj) : Base(cx, owner_, obj.get()) { } - - bool definePropertyToTrusted(JSContext* cx, const char* name, - JS::MutableHandleValue value); - - public: - Object(JSContext* cx, Builder& owner_) : Base(cx, owner_, nullptr) { } - Object(const Object& rhs) : Base(rhs) { } - - // Our automatically-generated assignment operator can see our base - // class's assignment operator, so we don't need to write one out here. - - // Set the property named |name| on this object to |value|. - // - // If |value| is a string or primitive, re-wrap it for the debugger's - // compartment. - // - // If |value| is an object, assume it is a debuggee object and make a - // Debugger.Object instance referring to it. Set that as the propery's - // value. - // - // If |value| is another trusted object, store it directly as the - // property's value. - // - // On error, report the problem on cx and return false. - bool defineProperty(JSContext* cx, const char* name, JS::HandleValue value); - bool defineProperty(JSContext* cx, const char* name, JS::HandleObject value); - bool defineProperty(JSContext* cx, const char* name, Object& value); - - using Base::operator bool; - }; - - // Build an empty object for direct use by debugger code, owned by this - // Builder. If an error occurs, report it on cx and return a false Object. - Object newObject(JSContext* cx); + protected: + // A reference to a trusted object or value. At the moment, we only use it + // with JSObject*. + template + class BuiltThing { + friend class BuilderOrigin; + + protected: + // The Builder to which this trusted thing belongs. + Builder& owner; + + // A rooted reference to our value. + PersistentRooted value; + + BuiltThing(JSContext* cx, Builder& owner_, + T value_ = GCPolicy::initial()) + : owner(owner_), value(cx, value_) { + owner.assertBuilt(value_); + } + + // Forward some things from our owner, for convenience. + js::Debugger* debugger() const { return owner.debugger; } + JSObject* debuggerObject() const { return owner.debuggerObject; } + + public: + BuiltThing(const BuiltThing& rhs) : owner(rhs.owner), value(rhs.value) {} + BuiltThing& operator=(const BuiltThing& rhs) { + MOZ_ASSERT(&owner == &rhs.owner); + owner.assertBuilt(rhs.value); + value = rhs.value; + return *this; + } + + explicit operator bool() const { + // If we ever instantiate BuiltThing, this might not suffice. + return value; + } + + private: + BuiltThing() = delete; + }; + + public: + // A reference to a trusted object, possibly null. Instances of Object are + // always properly rooted. They can be copied and assigned, as if they were + // pointers. + class Object : private BuiltThing { + friend class Builder; // for construction + friend class BuilderOrigin; // for unwrapping + + typedef BuiltThing Base; + + // This is private, because only Builders can create Objects that + // actually point to something (hence the 'friend' declaration). + Object(JSContext* cx, Builder& owner_, HandleObject obj) + : Base(cx, owner_, obj.get()) {} + + bool definePropertyToTrusted(JSContext* cx, const char* name, + JS::MutableHandleValue value); + + public: + Object(JSContext* cx, Builder& owner_) : Base(cx, owner_, nullptr) {} + Object(const Object& rhs) : Base(rhs) {} + + // Our automatically-generated assignment operator can see our base + // class's assignment operator, so we don't need to write one out here. + + // Set the property named |name| on this object to |value|. + // + // If |value| is a string or primitive, re-wrap it for the debugger's + // compartment. + // + // If |value| is an object, assume it is a debuggee object and make a + // Debugger.Object instance referring to it. Set that as the propery's + // value. + // + // If |value| is another trusted object, store it directly as the + // property's value. + // + // On error, report the problem on cx and return false. + bool defineProperty(JSContext* cx, const char* name, JS::HandleValue value); + bool defineProperty(JSContext* cx, const char* name, + JS::HandleObject value); + bool defineProperty(JSContext* cx, const char* name, Object& value); + + using Base::operator bool; + }; + + // Build an empty object for direct use by debugger code, owned by this + // Builder. If an error occurs, report it on cx and return a false Object. + Object newObject(JSContext* cx); - protected: - Builder(JSContext* cx, js::Debugger* debugger); + protected: + Builder(JSContext* cx, js::Debugger* debugger); }; // Debugger itself instantiates this subclass of Builder, which can unwrap // BuiltThings that belong to it. class BuilderOrigin : public Builder { - template - T unwrapAny(const BuiltThing& thing) { - MOZ_ASSERT(&thing.owner == this); - return thing.value.get(); - } - - public: - BuilderOrigin(JSContext* cx, js::Debugger* debugger_) - : Builder(cx, debugger_) - { } + template + T unwrapAny(const BuiltThing& thing) { + MOZ_ASSERT(&thing.owner == this); + return thing.value.get(); + } + + public: + BuilderOrigin(JSContext* cx, js::Debugger* debugger_) + : Builder(cx, debugger_) {} - JSObject* unwrap(Object& object) { return unwrapAny(object); } + JSObject* unwrap(Object& object) { return unwrapAny(object); } }; - - // Finding the size of blocks allocated with malloc // ------------------------------------------------ // @@ -259,16 +259,13 @@ // Tell Debuggers in |cx| to use |mallocSizeOf| to find the size of // malloc'd blocks. -JS_PUBLIC_API(void) -SetDebuggerMallocSizeOf(JSContext* cx, mozilla::MallocSizeOf mallocSizeOf); +JS_PUBLIC_API void SetDebuggerMallocSizeOf(JSContext* cx, + mozilla::MallocSizeOf mallocSizeOf); // Get the MallocSizeOf function that the given context is using to find the // size of malloc'd blocks. -JS_PUBLIC_API(mozilla::MallocSizeOf) -GetDebuggerMallocSizeOf(JSContext* cx); +JS_PUBLIC_API mozilla::MallocSizeOf GetDebuggerMallocSizeOf(JSContext* cx); - - // Debugger and Garbage Collection Events // -------------------------------------- // @@ -279,54 +276,24 @@ // empty. Instead, we rely on embedders to call back into SpiderMonkey after a // GC and notify Debuggers to call their onGarbageCollection hook. +// Determine whether it's necessary to call FireOnGarbageCollectionHook() after +// a GC. This is only required if there are debuggers with an +// onGarbageCollection hook observing a global in the set of collected zones. +JS_PUBLIC_API bool FireOnGarbageCollectionHookRequired(JSContext* cx); // For each Debugger that observed a debuggee involved in the given GC event, // call its `onGarbageCollection` hook. -JS_PUBLIC_API(bool) -FireOnGarbageCollectionHook(JSContext* cx, GarbageCollectionEvent::Ptr&& data); - - - -// Handlers for observing Promises -// ------------------------------- -// -// The Debugger wants to observe behavior of promises, which are implemented by -// Gecko with webidl and which SpiderMonkey knows nothing about. On the other -// hand, Gecko knows nothing about which (if any) debuggers are observing a -// promise's global. The compromise is that Gecko is responsible for calling -// these handlers at the appropriate times, and SpiderMonkey will handle -// notifying any Debugger instances that are observing the given promise's -// global. - -// Notify any Debugger instances observing this promise's global that a new -// promise was allocated. -JS_PUBLIC_API(void) -onNewPromise(JSContext* cx, HandleObject promise); - -// Notify any Debugger instances observing this promise's global that the -// promise has settled (ie, it has either been fulfilled or rejected). Note that -// this is *not* equivalent to the promise resolution (ie, the promise's fate -// getting locked in) because you can resolve a promise with another pending -// promise, in which case neither promise has settled yet. -// -// It is Gecko's responsibility to ensure that this is never called on the same -// promise more than once (because a promise can only make the transition from -// unsettled to settled once). -JS_PUBLIC_API(void) -onPromiseSettled(JSContext* cx, HandleObject promise); +JS_PUBLIC_API bool FireOnGarbageCollectionHook( + JSContext* cx, GarbageCollectionEvent::Ptr&& data); - - // Return true if the given value is a Debugger object, false otherwise. -JS_PUBLIC_API(bool) -IsDebugger(JSObject& obj); +JS_PUBLIC_API bool IsDebugger(JSObject& obj); // Append each of the debuggee global objects observed by the Debugger object // |dbgObj| to |vector|. Returns true on success, false on failure. -JS_PUBLIC_API(bool) -GetDebuggeeGlobals(JSContext* cx, JSObject& dbgObj, AutoObjectVector& vector); +JS_PUBLIC_API bool GetDebuggeeGlobals(JSContext* cx, JSObject& dbgObj, + AutoObjectVector& vector); - // Hooks for reporting where JavaScript execution began. // // Our performance tools would like to be able to label blocks of JavaScript @@ -340,45 +307,40 @@ // call the appropriate |Entry| member function to indicate where we've begun // execution. -class MOZ_STACK_CLASS JS_PUBLIC_API(AutoEntryMonitor) { - JSRuntime* runtime_; - AutoEntryMonitor* savedMonitor_; - - public: - explicit AutoEntryMonitor(JSContext* cx); - ~AutoEntryMonitor(); - - // 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, - 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, - const char* asyncCause) = 0; +class MOZ_STACK_CLASS JS_PUBLIC_API AutoEntryMonitor { + JSContext* cx_; + AutoEntryMonitor* savedMonitor_; + + public: + explicit AutoEntryMonitor(JSContext* cx); + ~AutoEntryMonitor(); + + // 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, 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, + const char* asyncCause) = 0; - // Execution of the function or script has ended. - virtual void Exit(JSContext* cx) { } + // Execution of the function or script has ended. + virtual void Exit(JSContext* cx) {} }; - - -} // namespace dbg -} // namespace JS - +} // namespace dbg +} // namespace JS #endif /* js_Debug_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCAPI.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCAPI.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/GCAPI.h @@ -4,136 +4,404 @@ * 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/. */ +/* + * High-level interface to the JS garbage collector. + */ + #ifndef js_GCAPI_h #define js_GCAPI_h +#include "mozilla/TimeStamp.h" #include "mozilla/Vector.h" #include "js/GCAnnotations.h" -#include "js/HeapAPI.h" +#include "js/TypeDecls.h" #include "js/UniquePtr.h" +#include "js/Utility.h" + +struct JSFreeOp; + +#ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattributes" +#endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING + +class JS_PUBLIC_API JSTracer; + +#ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING +#pragma GCC diagnostic pop +#endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING namespace js { namespace gc { class GCRuntime; -} // namespace gc +} // namespace gc namespace gcstats { struct Statistics; -} // namespace gcstats -} // namespace js +} // namespace gcstats +} // namespace js typedef enum JSGCMode { - /** Perform only global GCs. */ - JSGC_MODE_GLOBAL = 0, + /** Perform only global GCs. */ + JSGC_MODE_GLOBAL = 0, - /** Perform per-zone GCs until too much garbage has accumulated. */ - JSGC_MODE_ZONE = 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_ZONE. - */ - JSGC_MODE_INCREMENTAL = 2 + /** + * Collect in short time slices rather than all at once. Implies + * JSGC_MODE_ZONE. + */ + JSGC_MODE_INCREMENTAL = 2 } JSGCMode; /** * Kinds of js_GC invocation. */ typedef enum JSGCInvocationKind { - /* Normal invocation. */ - GC_NORMAL = 0, + /* Normal invocation. */ + GC_NORMAL = 0, - /* Minimize GC triggers and release empty GC chunks right away. */ - GC_SHRINK = 1 + /* Minimize GC triggers and release empty GC chunks right away. */ + GC_SHRINK = 1 } JSGCInvocationKind; +typedef enum JSGCParamKey { + /** + * Maximum nominal heap before last ditch GC. + * + * Soft limit on the number of bytes we are allowed to allocate in the GC + * heap. Attempts to allocate gcthings over this limit will return null and + * subsequently invoke the standard OOM machinery, independent of available + * physical memory. + * + * Pref: javascript.options.mem.max + * Default: 0xffffffff + */ + JSGC_MAX_BYTES = 0, + + /** + * Initial value for the malloc bytes threshold. + * + * Pref: javascript.options.mem.high_water_mark + * Default: TuningDefaults::MaxMallocBytes + */ + JSGC_MAX_MALLOC_BYTES = 1, + + /** + * Maximum size of the generational GC nurseries. + * + * Pref: javascript.options.mem.nursery.max_kb + * Default: JS::DefaultNurseryBytes + */ + JSGC_MAX_NURSERY_BYTES = 2, + + /** Amount of bytes allocated by the GC. */ + JSGC_BYTES = 3, + + /** Number of times GC has been invoked. Includes both major and minor GC. */ + JSGC_NUMBER = 4, + + /** + * Select GC mode. + * + * See: JSGCMode in GCAPI.h + * prefs: javascript.options.mem.gc_per_zone and + * javascript.options.mem.gc_incremental. + * Default: JSGC_MODE_INCREMENTAL + */ + JSGC_MODE = 6, + + /** Number of cached empty GC chunks. */ + JSGC_UNUSED_CHUNKS = 7, + + /** Total number of allocated GC chunks. */ + JSGC_TOTAL_CHUNKS = 8, + + /** + * Max milliseconds to spend in an incremental GC slice. + * + * Pref: javascript.options.mem.gc_incremental_slice_ms + * Default: DefaultTimeBudget. + */ + JSGC_SLICE_TIME_BUDGET = 9, + + /** + * Maximum size the GC mark stack can grow to. + * + * Pref: none + * Default: MarkStack::DefaultCapacity + */ + JSGC_MARK_STACK_LIMIT = 10, + + /** + * GCs less than this far apart in time will be considered 'high-frequency + * GCs'. + * + * See setGCLastBytes in jsgc.cpp. + * + * Pref: javascript.options.mem.gc_high_frequency_time_limit_ms + * Default: HighFrequencyThresholdUsec + */ + JSGC_HIGH_FREQUENCY_TIME_LIMIT = 11, + + /** + * Start of dynamic heap growth. + * + * Pref: javascript.options.mem.gc_high_frequency_low_limit_mb + * Default: HighFrequencyLowLimitBytes + */ + JSGC_HIGH_FREQUENCY_LOW_LIMIT = 12, + + /** + * End of dynamic heap growth. + * + * Pref: javascript.options.mem.gc_high_frequency_high_limit_mb + * Default: HighFrequencyHighLimitBytes + */ + JSGC_HIGH_FREQUENCY_HIGH_LIMIT = 13, + + /** + * Upper bound of heap growth. + * + * Pref: javascript.options.mem.gc_high_frequency_heap_growth_max + * Default: HighFrequencyHeapGrowthMax + */ + JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX = 14, + + /** + * Lower bound of heap growth. + * + * Pref: javascript.options.mem.gc_high_frequency_heap_growth_min + * Default: HighFrequencyHeapGrowthMin + */ + JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN = 15, + + /** + * Heap growth for low frequency GCs. + * + * Pref: javascript.options.mem.gc_low_frequency_heap_growth + * Default: LowFrequencyHeapGrowth + */ + JSGC_LOW_FREQUENCY_HEAP_GROWTH = 16, + + /** + * If false, the heap growth factor is fixed at 3. If true, it is determined + * based on whether GCs are high- or low- frequency. + * + * Pref: javascript.options.mem.gc_dynamic_heap_growth + * Default: DynamicHeapGrowthEnabled + */ + JSGC_DYNAMIC_HEAP_GROWTH = 17, + + /** + * If true, high-frequency GCs will use a longer mark slice. + * + * Pref: javascript.options.mem.gc_dynamic_mark_slice + * Default: DynamicMarkSliceEnabled + */ + JSGC_DYNAMIC_MARK_SLICE = 18, + + /** + * Lower limit after which we limit the heap growth. + * + * The base value used to compute zone->threshold.gcTriggerBytes(). When + * usage.gcBytes() surpasses threshold.gcTriggerBytes() for a zone, the + * zone may be scheduled for a GC, depending on the exact circumstances. + * + * Pref: javascript.options.mem.gc_allocation_threshold_mb + * Default GCZoneAllocThresholdBase + */ + JSGC_ALLOCATION_THRESHOLD = 19, + + /** + * We try to keep at least this many unused chunks in the free chunk pool at + * all times, even after a shrinking GC. + * + * Pref: javascript.options.mem.gc_min_empty_chunk_count + * Default: MinEmptyChunkCount + */ + JSGC_MIN_EMPTY_CHUNK_COUNT = 21, + + /** + * We never keep more than this many unused chunks in the free chunk + * pool. + * + * Pref: javascript.options.mem.gc_min_empty_chunk_count + * Default: MinEmptyChunkCount + */ + JSGC_MAX_EMPTY_CHUNK_COUNT = 22, + + /** + * Whether compacting GC is enabled. + * + * Pref: javascript.options.mem.gc_compacting + * Default: CompactingEnabled + */ + JSGC_COMPACTING_ENABLED = 23, + + /** + * Factor for triggering a GC based on JSGC_ALLOCATION_THRESHOLD + * + * Default: ZoneAllocThresholdFactorDefault + * Pref: None + */ + JSGC_ALLOCATION_THRESHOLD_FACTOR = 25, + + /** + * Factor for triggering a GC based on JSGC_ALLOCATION_THRESHOLD. + * Used if another GC (in different zones) is already running. + * + * Default: ZoneAllocThresholdFactorAvoidInterruptDefault + * Pref: None + */ + JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT = 26, +} JSGCParamKey; + +/* + * Generic trace operation that calls JS::TraceEdge on each traceable thing's + * location reachable from data. + */ +typedef void (*JSTraceDataOp)(JSTracer* trc, void* data); + +typedef enum JSGCStatus { JSGC_BEGIN, JSGC_END } JSGCStatus; + +typedef void (*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 zones, before anything has been + * swept. The collector will not yield to the mutator before calling the + * callback with JSFINALIZE_GROUP_START status. + */ + JSFINALIZE_GROUP_PREPARE, + + /** + * Called after preparing to sweep a group of zones. Weak references to + * unmarked things have been removed at this point, but no GC things have + * been swept. The collector may yield to the mutator after this point. + */ + JSFINALIZE_GROUP_START, + + /** + * Called after sweeping a group of zones. All dead GC things have been + * swept at this point. + */ + JSFINALIZE_GROUP_END, + + /** + * Called at the end of collection when everything has been swept. + */ + JSFINALIZE_COLLECTION_END +} JSFinalizeStatus; + +typedef void (*JSFinalizeCallback)(JSFreeOp* fop, JSFinalizeStatus status, + void* data); + +typedef void (*JSWeakPointerZonesCallback)(JSContext* cx, void* data); + +typedef void (*JSWeakPointerCompartmentCallback)(JSContext* cx, + JSCompartment* comp, + void* data); + +/** + * Finalizes external strings created by JS_NewExternalString. The finalizer + * can be called off the main thread. + */ +struct JSStringFinalizer { + void (*finalize)(const JSStringFinalizer* fin, char16_t* chars); +}; + namespace JS { -#define GCREASONS(D) \ - /* Reasons internal to the JS engine */ \ - D(API) \ - D(EAGER_ALLOC_TRIGGER) \ - D(DESTROY_RUNTIME) \ - D(UNUSED0) \ - D(LAST_DITCH) \ - D(TOO_MUCH_MALLOC) \ - D(ALLOC_TRIGGER) \ - D(DEBUG_GC) \ - D(COMPARTMENT_REVIVED) \ - D(RESET) \ - D(OUT_OF_NURSERY) \ - D(EVICT_NURSERY) \ - D(FULL_STORE_BUFFER) \ - D(SHARED_MEMORY_LIMIT) \ - D(UNUSED1) \ - D(INCREMENTAL_TOO_SLOW) \ - D(ABORT_GC) \ - \ - /* These are reserved for future use. */ \ - D(RESERVED0) \ - D(RESERVED1) \ - D(RESERVED2) \ - D(RESERVED3) \ - D(RESERVED4) \ - D(RESERVED5) \ - D(RESERVED6) \ - D(RESERVED7) \ - D(RESERVED8) \ - D(RESERVED9) \ - D(RESERVED10) \ - D(RESERVED11) \ - D(RESERVED12) \ - D(RESERVED13) \ - D(RESERVED14) \ - D(RESERVED15) \ - \ - /* Reasons from Firefox */ \ - D(DOM_WINDOW_UTILS) \ - D(COMPONENT_UTILS) \ - D(MEM_PRESSURE) \ - D(CC_WAITING) \ - D(CC_FORCED) \ - D(LOAD_END) \ - D(POST_COMPARTMENT) \ - D(PAGE_HIDE) \ - D(NSJSCONTEXT_DESTROY) \ - D(SET_NEW_DOCUMENT) \ - D(SET_DOC_SHELL) \ - D(DOM_UTILS) \ - D(DOM_IPC) \ - D(DOM_WORKER) \ - D(INTER_SLICE_GC) \ - D(REFRESH_FRAME) \ - D(FULL_GC_TIMER) \ - D(SHUTDOWN_CC) \ - D(FINISH_LARGE_EVALUATE) \ - D(USER_INACTIVE) \ - D(XPCONNECT_SHUTDOWN) +#define GCREASONS(D) \ + /* Reasons internal to the JS engine */ \ + D(API) \ + D(EAGER_ALLOC_TRIGGER) \ + D(DESTROY_RUNTIME) \ + D(ROOTS_REMOVED) \ + D(LAST_DITCH) \ + D(TOO_MUCH_MALLOC) \ + D(ALLOC_TRIGGER) \ + D(DEBUG_GC) \ + D(COMPARTMENT_REVIVED) \ + D(RESET) \ + D(OUT_OF_NURSERY) \ + D(EVICT_NURSERY) \ + D(DELAYED_ATOMS_GC) \ + D(SHARED_MEMORY_LIMIT) \ + D(IDLE_TIME_COLLECTION) \ + D(INCREMENTAL_TOO_SLOW) \ + D(ABORT_GC) \ + D(FULL_WHOLE_CELL_BUFFER) \ + D(FULL_GENERIC_BUFFER) \ + D(FULL_VALUE_BUFFER) \ + D(FULL_CELL_PTR_BUFFER) \ + D(FULL_SLOT_BUFFER) \ + D(FULL_SHAPE_BUFFER) \ + \ + /* These are reserved for future use. */ \ + D(RESERVED0) \ + D(RESERVED1) \ + D(RESERVED2) \ + D(RESERVED3) \ + D(RESERVED4) \ + D(RESERVED5) \ + D(RESERVED6) \ + D(RESERVED7) \ + D(RESERVED8) \ + D(RESERVED9) \ + \ + /* Reasons from Firefox */ \ + D(DOM_WINDOW_UTILS) \ + D(COMPONENT_UTILS) \ + D(MEM_PRESSURE) \ + D(CC_WAITING) \ + D(CC_FORCED) \ + D(LOAD_END) \ + D(POST_COMPARTMENT) \ + D(PAGE_HIDE) \ + D(NSJSCONTEXT_DESTROY) \ + D(SET_NEW_DOCUMENT) \ + D(SET_DOC_SHELL) \ + D(DOM_UTILS) \ + D(DOM_IPC) \ + D(DOM_WORKER) \ + D(INTER_SLICE_GC) \ + D(UNUSED1) \ + D(FULL_GC_TIMER) \ + D(SHUTDOWN_CC) \ + D(UNUSED2) \ + D(USER_INACTIVE) \ + D(XPCONNECT_SHUTDOWN) \ + D(DOCSHELL) \ + D(HTML_PARSER) namespace gcreason { /* GCReasons will end up looking like JSGC_MAYBEGC */ enum Reason { #define MAKE_REASON(name) name, - GCREASONS(MAKE_REASON) + GCREASONS(MAKE_REASON) #undef MAKE_REASON - NO_REASON, - NUM_REASONS, + NO_REASON, + NUM_REASONS, - /* - * For telemetry, we want to keep a fixed max bucket size over time so we - * don't have to switch histograms. 100 is conservative; as of this writing - * there are 52. But the cost of extra buckets seems to be low while the - * cost of switching histograms is high. - */ - NUM_TELEMETRY_REASONS = 100 + /* + * For telemetry, we want to keep a fixed max bucket size over time so we + * don't have to switch histograms. 100 is conservative; as of this writing + * there are 52. But the cost of extra buckets seems to be low while the + * cost of switching histograms is high. + */ + 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); +extern JS_PUBLIC_API const char* ExplainReason(JS::gcreason::Reason reason); } /* namespace gcreason */ @@ -154,36 +422,31 @@ /** * Schedule the given zone to be collected as part of the next GC. */ -extern JS_PUBLIC_API(void) -PrepareZoneForGC(Zone* zone); +extern JS_PUBLIC_API void PrepareZoneForGC(Zone* zone); /** * Schedule all zones to be collected in the next GC. */ -extern JS_PUBLIC_API(void) -PrepareForFullGC(JSContext* cx); +extern JS_PUBLIC_API void PrepareForFullGC(JSContext* cx); /** * When performing an incremental GC, the zones that were selected for the * previous incremental slice must be selected in subsequent slices as well. * This function selects those slices automatically. */ -extern JS_PUBLIC_API(void) -PrepareForIncrementalGC(JSContext* cx); +extern JS_PUBLIC_API void 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(JSContext* cx); +extern JS_PUBLIC_API bool IsGCScheduled(JSContext* cx); /** * Undoes the effect of the Prepare methods above. The given zone will not be * collected in the next GC. */ -extern JS_PUBLIC_API(void) -SkipZoneForGC(Zone* zone); +extern JS_PUBLIC_API void SkipZoneForGC(Zone* zone); /* * Non-Incremental GC: @@ -200,8 +463,8 @@ * to objects will be cleared and all unreferenced objects will be removed from * the system. */ -extern JS_PUBLIC_API(void) -GCForReason(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason); +extern JS_PUBLIC_API void GCForReason(JSContext* cx, JSGCInvocationKind gckind, + gcreason::Reason reason); /* * Incremental GC: @@ -232,9 +495,10 @@ * 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(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason, - int64_t millis = 0); +extern JS_PUBLIC_API void StartIncrementalGC(JSContext* cx, + JSGCInvocationKind gckind, + gcreason::Reason reason, + int64_t millis = 0); /** * Perform a slice of an ongoing incremental collection. When this function @@ -244,8 +508,9 @@ * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or * shorter than the requested interval. */ -extern JS_PUBLIC_API(void) -IncrementalGCSlice(JSContext* cx, gcreason::Reason reason, int64_t millis = 0); +extern JS_PUBLIC_API void IncrementalGCSlice(JSContext* cx, + gcreason::Reason reason, + int64_t millis = 0); /** * If IsIncrementalGCInProgress(cx), this call finishes the ongoing collection @@ -253,8 +518,8 @@ * this is equivalent to GCForReason. When this function returns, * IsIncrementalGCInProgress(cx) will always be false. */ -extern JS_PUBLIC_API(void) -FinishIncrementalGC(JSContext* cx, gcreason::Reason reason); +extern JS_PUBLIC_API void FinishIncrementalGC(JSContext* cx, + gcreason::Reason reason); /** * If IsIncrementalGCInProgress(cx), this call aborts the ongoing collection and @@ -262,138 +527,147 @@ * state. This may take an arbitrarily long time. When this function returns, * IsIncrementalGCInProgress(cx) will always be false. */ -extern JS_PUBLIC_API(void) -AbortIncrementalGC(JSContext* cx); +extern JS_PUBLIC_API void AbortIncrementalGC(JSContext* cx); namespace dbg { // The `JS::dbg::GarbageCollectionEvent` class is essentially a view of the // `js::gcstats::Statistics` data without the uber implementation-specific bits. // It should generally be palatable for web developers. -class GarbageCollectionEvent -{ - // The major GC number of the GC cycle this data pertains to. - uint64_t majorGCNumber_; - - // Reference to a non-owned, statically allocated C string. This is a very - // short reason explaining why a GC was triggered. - const char* reason; - - // Reference to a nullable, non-owned, statically allocated C string. If the - // collection was forced to be non-incremental, this is a short reason of - // why the GC could not perform an incremental collection. - const char* nonincrementalReason; - - // Represents a single slice of a possibly multi-slice incremental garbage - // collection. - struct Collection { - double startTimestamp; - double endTimestamp; - }; - - // The set of garbage collection slices that made up this GC cycle. - mozilla::Vector collections; - - GarbageCollectionEvent(const GarbageCollectionEvent& rhs) = delete; - GarbageCollectionEvent& operator=(const GarbageCollectionEvent& rhs) = delete; - - public: - explicit GarbageCollectionEvent(uint64_t majorGCNum) - : majorGCNumber_(majorGCNum) - , reason(nullptr) - , nonincrementalReason(nullptr) - , collections() - { } +class GarbageCollectionEvent { + // The major GC number of the GC cycle this data pertains to. + uint64_t majorGCNumber_; - using Ptr = js::UniquePtr; - static Ptr Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t majorGCNumber); + // Reference to a non-owned, statically allocated C string. This is a very + // short reason explaining why a GC was triggered. + const char* reason; - JSObject* toJSObject(JSContext* cx) const; + // Reference to a nullable, non-owned, statically allocated C string. If the + // collection was forced to be non-incremental, this is a short reason of + // why the GC could not perform an incremental collection. + const char* nonincrementalReason; - uint64_t majorGCNumber() const { return majorGCNumber_; } -}; + // Represents a single slice of a possibly multi-slice incremental garbage + // collection. + struct Collection { + mozilla::TimeStamp startTimestamp; + mozilla::TimeStamp endTimestamp; + }; -} // namespace dbg + // The set of garbage collection slices that made up this GC cycle. + mozilla::Vector collections; -enum GCProgress { - /* - * During non-incremental GC, the GC is bracketed by JSGC_CYCLE_BEGIN/END - * callbacks. During an incremental GC, the sequence of callbacks is as - * follows: - * JSGC_CYCLE_BEGIN, JSGC_SLICE_END (first slice) - * JSGC_SLICE_BEGIN, JSGC_SLICE_END (second slice) - * ... - * JSGC_SLICE_BEGIN, JSGC_CYCLE_END (last slice) - */ - - GC_CYCLE_BEGIN, - GC_SLICE_BEGIN, - GC_SLICE_END, - GC_CYCLE_END + GarbageCollectionEvent(const GarbageCollectionEvent& rhs) = delete; + GarbageCollectionEvent& operator=(const GarbageCollectionEvent& rhs) = delete; + + public: + explicit GarbageCollectionEvent(uint64_t majorGCNum) + : majorGCNumber_(majorGCNum), + reason(nullptr), + nonincrementalReason(nullptr), + collections() {} + + using Ptr = js::UniquePtr; + static Ptr Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, + uint64_t majorGCNumber); + + JSObject* toJSObject(JSContext* cx) const; + + uint64_t majorGCNumber() const { return majorGCNumber_; } }; -struct JS_PUBLIC_API(GCDescription) { - bool isZone_; - JSGCInvocationKind invocationKind_; - gcreason::Reason reason_; - - GCDescription(bool isZone, JSGCInvocationKind kind, gcreason::Reason reason) - : isZone_(isZone), invocationKind_(kind), reason_(reason) {} - - char16_t* formatSliceMessage(JSContext* cx) const; - char16_t* formatSummaryMessage(JSContext* cx) const; - char16_t* formatJSON(JSContext* cx, uint64_t timestamp) const; +} // namespace dbg + +enum GCProgress { + /* + * During GC, the GC is bracketed by GC_CYCLE_BEGIN/END callbacks. Each + * slice between those (whether an incremental or the sole non-incremental + * slice) is bracketed by GC_SLICE_BEGIN/GC_SLICE_END. + */ + + GC_CYCLE_BEGIN, + GC_SLICE_BEGIN, + GC_SLICE_END, + GC_CYCLE_END +}; + +struct JS_PUBLIC_API GCDescription { + bool isZone_; + bool isComplete_; + JSGCInvocationKind invocationKind_; + gcreason::Reason reason_; + + GCDescription(bool isZone, bool isComplete, JSGCInvocationKind kind, + gcreason::Reason reason) + : isZone_(isZone), + isComplete_(isComplete), + invocationKind_(kind), + reason_(reason) {} + + char16_t* formatSliceMessage(JSContext* cx) const; + char16_t* formatSummaryMessage(JSContext* cx) const; + char16_t* formatJSON(JSContext* cx, uint64_t timestamp) const; + + mozilla::TimeStamp startTime(JSContext* cx) const; + mozilla::TimeStamp endTime(JSContext* cx) const; + mozilla::TimeStamp lastSliceStart(JSContext* cx) const; + mozilla::TimeStamp lastSliceEnd(JSContext* cx) const; + + JS::UniqueChars sliceToJSON(JSContext* cx) const; + JS::UniqueChars summaryToJSON(JSContext* cx) const; - JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSContext* cx) const; + JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSContext* cx) const; }; -typedef void -(* GCSliceCallback)(JSContext* cx, GCProgress progress, const GCDescription& desc); +extern JS_PUBLIC_API UniqueChars MinorGcToJSON(JSContext* cx); + +typedef void (*GCSliceCallback)(JSContext* cx, GCProgress progress, + const GCDescription& desc); /** * The GC slice callback is called at the beginning and end of each slice. This * callback may be used for GC notifications as well as to perform additional * marking. */ -extern JS_PUBLIC_API(GCSliceCallback) +extern JS_PUBLIC_API GCSliceCallback 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 + /** + * 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); +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); +extern JS_PUBLIC_API GCNurseryCollectionCallback SetGCNurseryCollectionCallback( + JSContext* cx, GCNurseryCollectionCallback callback); -typedef void -(* DoCycleCollectionCallback)(JSContext* cx); +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) +extern JS_PUBLIC_API DoCycleCollectionCallback SetDoCycleCollectionCallback(JSContext* cx, DoCycleCollectionCallback callback); /** @@ -402,8 +676,7 @@ * There is not currently a way to re-enable incremental GC once it has been * disabled on the runtime. */ -extern JS_PUBLIC_API(void) -DisableIncrementalGC(JSContext* cx); +extern JS_PUBLIC_API void DisableIncrementalGC(JSContext* cx); /** * Returns true if incremental GC is enabled. Simply having incremental GC @@ -413,42 +686,24 @@ * GCDescription returned by GCSliceCallback may help narrow down the cause if * collections are not happening incrementally when expected. */ -extern JS_PUBLIC_API(bool) -IsIncrementalGCEnabled(JSContext* cx); +extern JS_PUBLIC_API bool IsIncrementalGCEnabled(JSContext* cx); /** * Returns true while an incremental GC is ongoing, both when actively * collecting and between slices. */ -extern JS_PUBLIC_API(bool) -IsIncrementalGCInProgress(JSContext* cx); - -/* - * Returns true when writes to GC things must call an incremental (pre) barrier. - * This is generally only true when running mutator code in-between GC slices. - * At other times, the barrier may be elided for performance. - */ -extern JS_PUBLIC_API(bool) -IsIncrementalBarrierNeeded(JSContext* cx); +extern JS_PUBLIC_API bool IsIncrementalGCInProgress(JSContext* cx); -/* - * Notify the GC that a reference to a GC thing is about to be overwritten. - * These methods must be called if IsIncrementalBarrierNeeded. +/** + * Returns true while an incremental GC is ongoing, both when actively + * collecting and between slices. */ -extern JS_PUBLIC_API(void) -IncrementalReferenceBarrier(GCCellPtr thing); - -extern JS_PUBLIC_API(void) -IncrementalValueBarrier(const Value& v); - -extern JS_PUBLIC_API(void) -IncrementalObjectBarrier(JSObject* obj); +extern JS_PUBLIC_API bool IsIncrementalGCInProgress(JSRuntime* rt); /** * Returns true if the most recent GC ran incrementally. */ -extern JS_PUBLIC_API(bool) -WasIncrementalGC(JSContext* cx); +extern JS_PUBLIC_API bool WasIncrementalGC(JSRuntime* rt); /* * Generational GC: @@ -459,40 +714,36 @@ */ /** Ensure that generational GC is disabled within some scope. */ -class JS_PUBLIC_API(AutoDisableGenerationalGC) -{ - js::gc::GCRuntime* gc; - - public: - explicit AutoDisableGenerationalGC(JSRuntime* rt); - ~AutoDisableGenerationalGC(); +class JS_PUBLIC_API AutoDisableGenerationalGC { + JSContext* cx; + + public: + explicit AutoDisableGenerationalGC(JSContext* cx); + ~AutoDisableGenerationalGC(); }; /** * Returns true if generational allocation and collection is currently enabled * on the given runtime. */ -extern JS_PUBLIC_API(bool) -IsGenerationalGCEnabled(JSRuntime* rt); +extern JS_PUBLIC_API bool IsGenerationalGCEnabled(JSRuntime* rt); /** * Returns the GC's "number". This does not correspond directly to the number * of GCs that have been run, but is guaranteed to be monotonically increasing * with GC activity. */ -extern JS_PUBLIC_API(size_t) -GetGCNumber(); +extern JS_PUBLIC_API size_t GetGCNumber(); /** * Pass a subclass of this "abstract" class to callees to require that they * never GC. Subclasses can use assertions or the hazard analysis to ensure no * GC happens. */ -class JS_PUBLIC_API(AutoRequireNoGC) -{ - protected: - AutoRequireNoGC() {} - ~AutoRequireNoGC() {} +class JS_PUBLIC_API AutoRequireNoGC { + protected: + AutoRequireNoGC() {} + ~AutoRequireNoGC() {} }; /** @@ -503,59 +754,27 @@ * This works by entering a GC unsafe region, which is checked on allocation and * on GC. */ -class JS_PUBLIC_API(AutoAssertNoGC) : public AutoRequireNoGC -{ - js::gc::GCRuntime* gc; - size_t gcNumber; - - public: - AutoAssertNoGC(); - explicit AutoAssertNoGC(JSRuntime* rt); - explicit AutoAssertNoGC(JSContext* cx); - ~AutoAssertNoGC(); -}; - -/** - * Assert if an allocation of a GC thing occurs while this class is live. This - * class does not disable the static rooting hazard analysis. - */ -class JS_PUBLIC_API(AutoAssertNoAlloc) -{ -#ifdef JS_DEBUG - js::gc::GCRuntime* gc; - - public: - AutoAssertNoAlloc() : gc(nullptr) {} - explicit AutoAssertNoAlloc(JSContext* cx); - void disallowAlloc(JSRuntime* rt); - ~AutoAssertNoAlloc(); +class JS_PUBLIC_API AutoAssertNoGC : public AutoRequireNoGC { +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + JSContext* cx_; + + public: + // This gets the context from TLS if it is not passed in. + explicit AutoAssertNoGC(JSContext* cx = nullptr); + ~AutoAssertNoGC(); #else - public: - AutoAssertNoAlloc() {} - explicit AutoAssertNoAlloc(JSContext* cx) {} - void disallowAlloc(JSRuntime* rt) {} + public: + explicit AutoAssertNoGC(JSContext* cx = nullptr) {} + ~AutoAssertNoGC() {} #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 - * in complex regions, since it cannot understand dataflow. + * Disable the static rooting hazard analysis in the live region and assert in + * debug builds 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 in complex regions, since it cannot understand + * dataflow. * * Note: GC behavior is unpredictable even when deterministic and is generally * non-deterministic in practice. The fact that this guard has not @@ -565,12 +784,18 @@ * that the hazard analysis is correct for that code, rather than relying * on this class. */ -class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertNoAlloc -{ - public: - AutoSuppressGCAnalysis() : AutoAssertNoAlloc() {} - explicit AutoSuppressGCAnalysis(JSContext* cx) : AutoAssertNoAlloc(cx) {} +#ifdef DEBUG +class JS_PUBLIC_API AutoSuppressGCAnalysis : public AutoAssertNoGC { + public: + explicit AutoSuppressGCAnalysis(JSContext* cx = nullptr) + : AutoAssertNoGC(cx) {} } JS_HAZ_GC_SUPPRESSED; +#else +class JS_PUBLIC_API AutoSuppressGCAnalysis : public AutoRequireNoGC { + public: + explicit AutoSuppressGCAnalysis(JSContext* cx = nullptr) {} +} JS_HAZ_GC_SUPPRESSED; +#endif /** * Assert that code is only ever called from a GC callback, disable the static @@ -580,10 +805,13 @@ * This is useful to make the static analysis ignore code that runs in GC * callbacks. */ -class JS_PUBLIC_API(AutoAssertGCCallback) : public AutoSuppressGCAnalysis -{ - public: - explicit AutoAssertGCCallback(JSObject* obj); +class JS_PUBLIC_API AutoAssertGCCallback : public AutoSuppressGCAnalysis { + public: +#ifdef DEBUG + AutoAssertGCCallback(); +#else + AutoAssertGCCallback() {} +#endif }; /** @@ -599,125 +827,175 @@ * We only do the assertion checking in DEBUG builds. */ #ifdef DEBUG -class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertNoGC -{ - public: - AutoCheckCannotGC() : AutoAssertNoGC() {} - explicit AutoCheckCannotGC(JSContext* cx) : AutoAssertNoGC(cx) {} +class JS_PUBLIC_API AutoCheckCannotGC : public AutoAssertNoGC { + public: + explicit AutoCheckCannotGC(JSContext* cx = nullptr) : AutoAssertNoGC(cx) {} } JS_HAZ_GC_INVALIDATED; #else -class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoRequireNoGC -{ - public: - AutoCheckCannotGC() {} - explicit AutoCheckCannotGC(JSContext* cx) {} +class JS_PUBLIC_API AutoCheckCannotGC : public AutoRequireNoGC { + public: + explicit AutoCheckCannotGC(JSContext* cx = nullptr) {} } 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. The return value indicates - * if anything was unmarked. +/* + * Internal to Firefox. */ -extern JS_FRIEND_API(bool) -UnmarkGrayGCThingRecursively(GCCellPtr thing); +extern JS_FRIEND_API void NotifyGCRootsRemoved(JSContext* cx); } /* namespace JS */ -namespace js { -namespace gc { +/** + * Register externally maintained GC roots. + * + * traceOp: the trace operation. For each root the implementation should call + * 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(JSContext* cx, + JSTraceDataOp traceOp, + void* data); -static MOZ_ALWAYS_INLINE void -ExposeGCThingToActiveJS(JS::GCCellPtr thing) -{ - // 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; - - // 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 (!thing.mayBeOwnedByOtherRuntime() && js::gc::detail::CellIsMarkedGray(thing.asCell())) - JS::UnmarkGrayGCThingRecursively(thing); -} +/** Undo a call to JS_AddExtraGCRootsTracer. */ +extern JS_PUBLIC_API void JS_RemoveExtraGCRootsTracer(JSContext* cx, + JSTraceDataOp traceOp, + void* data); -static MOZ_ALWAYS_INLINE void -MarkGCThingAsLive(JSRuntime* aRt, JS::GCCellPtr thing) -{ - // 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; +extern JS_PUBLIC_API void JS_GC(JSContext* cx); - JS::shadow::Runtime* rt = JS::shadow::Runtime::asShadowRuntime(aRt); - MOZ_DIAGNOSTIC_ASSERT(rt->allowGCBarriers()); +extern JS_PUBLIC_API void JS_MaybeGC(JSContext* cx); - if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing)) - JS::IncrementalReferenceBarrier(thing); -} +extern JS_PUBLIC_API void JS_SetGCCallback(JSContext* cx, JSGCCallback cb, + void* data); -} /* namespace gc */ -} /* namespace js */ +extern JS_PUBLIC_API void JS_SetObjectsTenuredCallback( + JSContext* cx, JSObjectsTenuredCallback cb, void* data); -namespace JS { +extern JS_PUBLIC_API bool JS_AddFinalizeCallback(JSContext* cx, + JSFinalizeCallback cb, + void* data); + +extern JS_PUBLIC_API void JS_RemoveFinalizeCallback(JSContext* cx, + JSFinalizeCallback cb); /* - * This should be called when an object that is marked gray is exposed to the JS - * engine (by handing it to running JS code or writing it into live JS - * data). During incremental GC, since the gray bits haven't been computed yet, - * we conservatively mark the object black. - */ -static MOZ_ALWAYS_INLINE void -ExposeObjectToActiveJS(JSObject* obj) -{ - MOZ_ASSERT(obj); - js::gc::ExposeGCThingToActiveJS(GCCellPtr(obj)); -} + * Weak pointers and garbage collection + * + * Weak pointers are by their nature not marked as part of garbage collection, + * but they may need to be updated in two cases after a GC: + * + * 1) Their referent was found not to be live and is about to be finalized + * 2) Their referent has been moved by a compacting GC + * + * To handle this, any part of the system that maintain weak pointers to + * JavaScript GC things must register a callback with + * JS_(Add,Remove)WeakPointer{ZoneGroup,Compartment}Callback(). This callback + * must then call JS_UpdateWeakPointerAfterGC() on all weak pointers it knows + * about. + * + * Since sweeping is incremental, we have several callbacks to avoid repeatedly + * having to visit all embedder structures. The WeakPointerZonesCallback is + * called once for each strongly connected group of zones, whereas the + * WeakPointerCompartmentCallback is called once for each compartment that is + * visited while sweeping. Structures that cannot contain references in more + * than one compartment should sweep the relevant per-compartment structures + * using the latter callback to minimizer per-slice overhead. + * + * The argument to JS_UpdateWeakPointerAfterGC() is an in-out param. If the + * referent is about to be finalized the pointer will be set to null. If the + * referent has been moved then the pointer will be updated to point to the 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 bool JS_AddWeakPointerZonesCallback( + JSContext* cx, JSWeakPointerZonesCallback cb, void* data); + +extern JS_PUBLIC_API void JS_RemoveWeakPointerZonesCallback( + JSContext* cx, JSWeakPointerZonesCallback cb); + +extern JS_PUBLIC_API bool JS_AddWeakPointerCompartmentCallback( + JSContext* cx, JSWeakPointerCompartmentCallback cb, void* data); -static MOZ_ALWAYS_INLINE void -ExposeScriptToActiveJS(JSScript* script) -{ - js::gc::ExposeGCThingToActiveJS(GCCellPtr(script)); +extern JS_PUBLIC_API void JS_RemoveWeakPointerCompartmentCallback( + JSContext* cx, JSWeakPointerCompartmentCallback cb); + +namespace JS { +template +class Heap; } -/* - * If a GC is currently marking, mark the string black. +extern JS_PUBLIC_API void JS_UpdateWeakPointerAfterGC( + JS::Heap* objp); + +extern JS_PUBLIC_API void JS_UpdateWeakPointerAfterGCUnbarriered( + JSObject** objp); + +extern JS_PUBLIC_API void JS_SetGCParameter(JSContext* cx, JSGCParamKey key, + uint32_t value); + +extern JS_PUBLIC_API void JS_ResetGCParameter(JSContext* cx, JSGCParamKey key); + +extern JS_PUBLIC_API uint32_t JS_GetGCParameter(JSContext* cx, + JSGCParamKey key); + +extern JS_PUBLIC_API void JS_SetGCParametersBasedOnAvailableMemory( + JSContext* cx, uint32_t availMem); + +/** + * Create a new JSString whose chars member refers to external memory, i.e., + * memory requiring application-specific finalization. */ -static MOZ_ALWAYS_INLINE void -MarkStringAsLive(Zone* zone, JSString* string) -{ - JSRuntime* rt = JS::shadow::Zone::asShadowZone(zone)->runtimeFromMainThread(); - js::gc::MarkGCThingAsLive(rt, GCCellPtr(string)); -} +extern JS_PUBLIC_API JSString* JS_NewExternalString( + JSContext* cx, const char16_t* chars, size_t length, + const JSStringFinalizer* fin); -/* - * Internal to Firefox. - * - * Note: this is not related to the PokeGC in nsJSEnvironment. +/** + * Create a new JSString whose chars member may refer to external memory. + * If a new external string is allocated, |*allocatedExternal| is set to true. + * Otherwise the returned string is either not an external string or an + * external string allocated by a previous call and |*allocatedExternal| is set + * to false. If |*allocatedExternal| is false, |fin| won't be called. */ -extern JS_FRIEND_API(void) -PokeGC(JSContext* cx); +extern JS_PUBLIC_API JSString* JS_NewMaybeExternalString( + JSContext* cx, const char16_t* chars, size_t length, + const JSStringFinalizer* fin, bool* allocatedExternal); -/* - * Internal to Firefox. +/** + * Return whether 'str' was created with JS_NewExternalString or + * JS_NewExternalStringWithClosure. */ -extern JS_FRIEND_API(void) -NotifyDidPaint(JSContext* cx); +extern JS_PUBLIC_API bool JS_IsExternalString(JSString* str); -} /* namespace JS */ +/** + * Return the 'fin' arg passed to JS_NewExternalString. + */ +extern JS_PUBLIC_API const JSStringFinalizer* JS_GetExternalStringFinalizer( + JSString* str); + +namespace JS { + +extern JS_PUBLIC_API bool IsIdleGCTaskNeeded(JSRuntime* rt); + +extern JS_PUBLIC_API void RunIdleTimeGCTask(JSRuntime* rt); + +} // namespace JS + +namespace js { +namespace gc { + +/** + * Create an object providing access to the garbage collector's internal notion + * of the current state of memory (both GC heap memory and GCthing-controlled + * malloc memory. + */ +extern JS_PUBLIC_API JSObject* NewMemoryInfoObject(JSContext* cx); + +} /* namespace gc */ +} /* namespace js */ #endif /* js_GCAPI_h */ 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 @@ -12,19 +12,19 @@ #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"))) +#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"))) +#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"))) +#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"))) +#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 @@ -33,24 +33,24 @@ // but makes sense for something like ErrorResult, which only contains a GC // pointer when it holds an exception (and it does its own rooting, // conditionally.) -# define JS_HAZ_NON_GC_POINTER __attribute__((tag("Suppressed GC Pointer"))) +#define JS_HAZ_NON_GC_POINTER __attribute__((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"))) +#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"))) +#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 +#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 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,6 +7,8 @@ #ifndef GCHashTable_h #define GCHashTable_h +#include "mozilla/Maybe.h" + #include "js/GCPolicyAPI.h" #include "js/HashTable.h" #include "js/RootingAPI.h" @@ -18,9 +20,9 @@ // Define a reasonable default GC policy for GC-aware Maps. template struct DefaultMapSweepPolicy { - static bool needsSweep(Key* key, Value* value) { - return GCPolicy::needsSweep(key) || GCPolicy::needsSweep(value); - } + static bool needsSweep(Key* key, Value* value) { + return GCPolicy::needsSweep(key) || GCPolicy::needsSweep(value); + } }; // A GCHashMap is a GC-aware HashMap, meaning that it has additional trace and @@ -47,52 +49,51 @@ // 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 = js::TempAllocPolicy, typename MapSweepPolicy = DefaultMapSweepPolicy> -class GCHashMap : public js::HashMap -{ - using Base = js::HashMap; - - public: - explicit GCHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {} - - static void trace(GCHashMap* map, JSTracer* trc) { map->trace(trc); } - void trace(JSTracer* trc) { - if (!this->initialized()) - return; - for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { - GCPolicy::trace(trc, &e.front().value(), "hashmap value"); - GCPolicy::trace(trc, &e.front().mutableKey(), "hashmap key"); - } - } - - void sweep() { - if (!this->initialized()) - return; - - for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { - if (MapSweepPolicy::needsSweep(&e.front().mutableKey(), &e.front().value())) - e.removeFront(); - } - } - - // GCHashMap is movable - GCHashMap(GCHashMap&& rhs) : Base(mozilla::Move(rhs)) {} - void operator=(GCHashMap&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - Base::operator=(mozilla::Move(rhs)); - } - - private: - // GCHashMap is not copyable or assignable - GCHashMap(const GCHashMap& hm) = delete; - GCHashMap& operator=(const GCHashMap& hm) = delete; +class GCHashMap : public js::HashMap { + using Base = js::HashMap; + + public: + explicit GCHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {} + + static void trace(GCHashMap* map, JSTracer* trc) { map->trace(trc); } + void trace(JSTracer* trc) { + if (!this->initialized()) return; + for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { + GCPolicy::trace(trc, &e.front().value(), "hashmap value"); + GCPolicy::trace(trc, &e.front().mutableKey(), "hashmap key"); + } + } + + bool needsSweep() const { return this->initialized() && !this->empty(); } + + void sweep() { + if (!this->initialized()) return; + + for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { + if (MapSweepPolicy::needsSweep(&e.front().mutableKey(), + &e.front().value())) + e.removeFront(); + } + } + + // GCHashMap is movable + GCHashMap(GCHashMap&& rhs) : Base(mozilla::Move(rhs)) {} + void operator=(GCHashMap&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); + Base::operator=(mozilla::Move(rhs)); + } + + private: + // GCHashMap is not copyable or assignable + GCHashMap(const GCHashMap& hm) = delete; + GCHashMap& operator=(const GCHashMap& hm) = delete; }; -} // namespace JS +} // namespace JS namespace js { @@ -101,137 +102,117 @@ // 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 = JS::GCHashMap; - using Lookup = typename Map::Lookup; - - 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); } - Range all() const { return map().all(); } - bool empty() const { return map().empty(); } - 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 = JS::GCHashMap; - using Lookup = typename Map::Lookup; - - 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(); } - void remove(Ptr p) { map().remove(p); } - - template - bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { - return map().add(p, mozilla::Forward(k), mozilla::Forward(v)); - } - - template - bool add(AddPtr& p, KeyInput&& k) { - return map().add(p, mozilla::Forward(k), Map::Value()); - } - - template - bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { - return map().relookupOrAdd(p, k, - mozilla::Forward(k), - mozilla::Forward(v)); - } - - template - bool put(KeyInput&& k, ValueInput&& v) { - return map().put(mozilla::Forward(k), mozilla::Forward(v)); - } - - template - bool putNew(KeyInput&& k, ValueInput&& v) { - return map().putNew(mozilla::Forward(k), mozilla::Forward(v)); - } +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 WrappedPtrOperations, Wrapper> { + using Map = JS::GCHashMap; + using Lookup = typename Map::Lookup; + + 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); } + Range all() const { return map().all(); } + bool empty() const { return map().empty(); } + 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 MutableWrappedPtrOperations, Wrapper> + : public WrappedPtrOperations, Wrapper> { + using Map = JS::GCHashMap; + using Lookup = typename Map::Lookup; + + Map& map() { return static_cast(this)->get(); } + + public: + using AddPtr = typename Map::AddPtr; + struct Enum : public Map::Enum { + explicit Enum(Wrapper& 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(); } + void remove(Ptr p) { map().remove(p); } + + template + bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { + return map().add(p, mozilla::Forward(k), + mozilla::Forward(v)); + } + + template + bool add(AddPtr& p, KeyInput&& k) { + return map().add(p, mozilla::Forward(k), Map::Value()); + } + + template + bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { + return map().relookupOrAdd(p, k, mozilla::Forward(k), + mozilla::Forward(v)); + } + + template + bool put(KeyInput&& k, ValueInput&& v) { + return map().put(mozilla::Forward(k), + mozilla::Forward(v)); + } + + template + bool putNew(KeyInput&& k, ValueInput&& v) { + return map().putNew(mozilla::Forward(k), + mozilla::Forward(v)); + } }; -template -class RootedBase> - : public MutableGCHashMapOperations>, A,B,C,D,E> -{}; - -template -class MutableHandleBase> - : public MutableGCHashMapOperations>, A,B,C,D,E> -{}; - -template -class HandleBase> - : public GCHashMapOperations>, A,B,C,D,E> -{}; - -template -class WeakCacheBase> - : public MutableGCHashMapOperations>, A,B,C,D,E> -{}; - -} // namespace js +} // namespace js namespace JS { @@ -248,152 +229,518 @@ // 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 , +template , typename AllocPolicy = js::TempAllocPolicy> -class GCHashSet : public js::HashSet -{ - using Base = js::HashSet; - - public: - explicit GCHashSet(AllocPolicy a = AllocPolicy()) : Base(a) {} - - static void trace(GCHashSet* set, JSTracer* trc) { set->trace(trc); } - void trace(JSTracer* trc) { - if (!this->initialized()) - return; - for (typename Base::Enum e(*this); !e.empty(); e.popFront()) - 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())) - e.removeFront(); - } - } - - // GCHashSet is movable - GCHashSet(GCHashSet&& rhs) : Base(mozilla::Move(rhs)) {} - void operator=(GCHashSet&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - Base::operator=(mozilla::Move(rhs)); - } - - private: - // GCHashSet is not copyable or assignable - GCHashSet(const GCHashSet& hs) = delete; - GCHashSet& operator=(const GCHashSet& hs) = delete; -}; - -} // namespace JS +class GCHashSet : public js::HashSet { + using Base = js::HashSet; -namespace js { + public: + explicit GCHashSet(AllocPolicy a = AllocPolicy()) : Base(a) {} -template -class GCHashSetOperations -{ - using Set = JS::GCHashSet; - using Lookup = typename Set::Lookup; - - 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); } - Range all() const { return set().all(); } - bool empty() const { return set().empty(); } - 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); - } + static void trace(GCHashSet* set, JSTracer* trc) { set->trace(trc); } + void trace(JSTracer* trc) { + if (!this->initialized()) return; + for (typename Base::Enum e(*this); !e.empty(); e.popFront()) + GCPolicy::trace(trc, &e.mutableFront(), "hashset element"); + } + + bool needsSweep() const { return this->initialized() && !this->empty(); } + + void sweep() { + if (!this->initialized()) return; + for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { + if (GCPolicy::needsSweep(&e.mutableFront())) e.removeFront(); + } + } + + // GCHashSet is movable + GCHashSet(GCHashSet&& rhs) : Base(mozilla::Move(rhs)) {} + void operator=(GCHashSet&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); + Base::operator=(mozilla::Move(rhs)); + } + + private: + // GCHashSet is not copyable or assignable + GCHashSet(const GCHashSet& hs) = delete; + GCHashSet& operator=(const GCHashSet& hs) = delete; }; -template -class MutableGCHashSetOperations - : public GCHashSetOperations -{ - using Set = JS::GCHashSet; - using Lookup = typename Set::Lookup; - - 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 - bool add(AddPtr& p, TInput&& t) { - return set().add(p, mozilla::Forward(t)); - } - - template - bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) { - return set().relookupOrAdd(p, l, mozilla::Forward(t)); - } - - template - bool put(TInput&& t) { - return set().put(mozilla::Forward(t)); - } +} // namespace JS - template - bool putNew(TInput&& t) { - return set().putNew(mozilla::Forward(t)); - } - - template - bool putNew(const Lookup& l, TInput&& t) { - return set().putNew(l, mozilla::Forward(t)); - } -}; +namespace js { -template -class RootedBase> - : public MutableGCHashSetOperations>, T, HP, AP> -{ +template +class WrappedPtrOperations, Wrapper> { + using Set = JS::GCHashSet; + + const Set& set() const { return static_cast(this)->get(); } + + public: + using Lookup = typename Set::Lookup; + 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); } + Range all() const { return set().all(); } + bool empty() const { return set().empty(); } + 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 MutableWrappedPtrOperations, Wrapper> + : public WrappedPtrOperations, Wrapper> { + using Set = JS::GCHashSet; + using Lookup = typename Set::Lookup; + + 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(Wrapper& 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 + bool add(AddPtr& p, TInput&& t) { + return set().add(p, mozilla::Forward(t)); + } + + template + bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) { + return set().relookupOrAdd(p, l, mozilla::Forward(t)); + } + + template + bool put(TInput&& t) { + return set().put(mozilla::Forward(t)); + } + + template + bool putNew(TInput&& t) { + return set().putNew(mozilla::Forward(t)); + } + + template + bool putNew(const Lookup& l, TInput&& t) { + return set().putNew(l, mozilla::Forward(t)); + } }; -template -class MutableHandleBase> - : public MutableGCHashSetOperations>, T, HP, AP> -{ -}; +} /* namespace js */ -template -class HandleBase> - : public GCHashSetOperations>, T, HP, AP> -{ -}; +namespace JS { -template -class WeakCacheBase> - : public MutableGCHashSetOperations>, T, HP, AP> -{ +// Specialize WeakCache for GCHashMap to provide a barriered map that does not +// need to be swept immediately. +template +class WeakCache> + : protected detail::WeakCacheBase { + using Map = GCHashMap; + using Self = WeakCache; + + Map map; + bool needsBarrier; + + public: + template + explicit WeakCache(Zone* zone, Args&&... args) + : WeakCacheBase(zone), + map(mozilla::Forward(args)...), + needsBarrier(false) {} + template + explicit WeakCache(JSRuntime* rt, Args&&... args) + : WeakCacheBase(rt), + map(mozilla::Forward(args)...), + needsBarrier(false) {} + ~WeakCache() { MOZ_ASSERT(!needsBarrier); } + + bool needsSweep() override { return map.needsSweep(); } + + size_t sweep() override { + if (!this->initialized()) return 0; + + size_t steps = map.count(); + map.sweep(); + return steps; + } + + bool setNeedsIncrementalBarrier(bool needs) override { + MOZ_ASSERT(needsBarrier != needs); + needsBarrier = needs; + return true; + } + + bool needsIncrementalBarrier() const override { return needsBarrier; } + + private: + using Entry = typename Map::Entry; + + static bool entryNeedsSweep(const Entry& prior) { + Key key(prior.key()); + Value value(prior.value()); + bool result = MapSweepPolicy::needsSweep(&key, &value); + MOZ_ASSERT(prior.key() == key); // We shouldn't update here. + MOZ_ASSERT(prior.value() == value); // We shouldn't update here. + return result; + } + + public: + using Lookup = typename Map::Lookup; + using Ptr = typename Map::Ptr; + using AddPtr = typename Map::AddPtr; + + struct Range { + explicit Range(const typename Map::Range& r) : range(r) { settle(); } + Range() {} + + bool empty() const { return range.empty(); } + const Entry& front() const { return range.front(); } + + void popFront() { + range.popFront(); + settle(); + } + + private: + typename Map::Range range; + + void settle() { + while (!empty() && entryNeedsSweep(front())) popFront(); + } + }; + + struct Enum : public Map::Enum { + explicit Enum(Self& cache) : Map::Enum(cache.map) { + // This operation is not allowed while barriers are in place as we + // may also need to enumerate the set for sweeping. + MOZ_ASSERT(!cache.needsBarrier); + } + }; + + bool initialized() const { return map.initialized(); } + + Ptr lookup(const Lookup& l) const { + Ptr ptr = map.lookup(l); + if (needsBarrier && ptr && entryNeedsSweep(*ptr)) { + const_cast(map).remove(ptr); + return Ptr(); + } + return ptr; + } + + AddPtr lookupForAdd(const Lookup& l) const { + AddPtr ptr = map.lookupForAdd(l); + if (needsBarrier && ptr && entryNeedsSweep(*ptr)) { + const_cast(map).remove(ptr); + return map.lookupForAdd(l); + } + return ptr; + } + + Range all() const { return Range(map.all()); } + + bool empty() const { + // This operation is not currently allowed while barriers are in place + // as it would require iterating the map and the caller expects a + // constant time operation. + MOZ_ASSERT(!needsBarrier); + return map.empty(); + } + + uint32_t count() const { + // This operation is not currently allowed while barriers are in place + // as it would require iterating the set and the caller expects a + // constant time operation. + MOZ_ASSERT(!needsBarrier); + return map.count(); + } + + size_t capacity() const { return map.capacity(); } + + bool has(const Lookup& l) const { return 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); + } + + bool init(uint32_t len = 16) { + MOZ_ASSERT(!needsBarrier); + return map.init(len); + } + + void clear() { + // This operation is not currently allowed while barriers are in place + // since it doesn't make sense to clear a cache while it is being swept. + MOZ_ASSERT(!needsBarrier); + map.clear(); + } + + void finish() { + // This operation is not currently allowed while barriers are in place + // since it doesn't make sense to destroy a cache while it is being swept. + MOZ_ASSERT(!needsBarrier); + map.finish(); + } + + void remove(Ptr p) { + // This currently supports removing entries during incremental + // sweeping. If we allow these tables to be swept incrementally this may + // no longer be possible. + map.remove(p); + } + + void remove(const Lookup& l) { + Ptr p = lookup(l); + if (p) remove(p); + } + + template + bool add(AddPtr& p, KeyInput&& k) { + using mozilla::Forward; + return map.add(p, Forward(k)); + } + + template + bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { + using mozilla::Forward; + return map.add(p, Forward(k), Forward(v)); + } + + template + bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { + using mozilla::Forward; + return map.relookupOrAdd(p, Forward(k), Forward(v)); + } + + template + bool put(KeyInput&& k, ValueInput&& v) { + using mozilla::Forward; + return map.put(Forward(k), Forward(v)); + } + + template + bool putNew(KeyInput&& k, ValueInput&& v) { + using mozilla::Forward; + return map.putNew(Forward(k), Forward(v)); + } +}; + +// Specialize WeakCache for GCHashSet to provide a barriered set that does not +// need to be swept immediately. +template +class WeakCache> + : protected detail::WeakCacheBase { + using Set = GCHashSet; + using Self = WeakCache; + + Set set; + bool needsBarrier; + + public: + using Entry = typename Set::Entry; + + template + explicit WeakCache(Zone* zone, Args&&... args) + : WeakCacheBase(zone), + set(mozilla::Forward(args)...), + needsBarrier(false) {} + template + explicit WeakCache(JSRuntime* rt, Args&&... args) + : WeakCacheBase(rt), + set(mozilla::Forward(args)...), + needsBarrier(false) {} + + size_t sweep() override { + if (!this->initialized()) return 0; + + size_t steps = set.count(); + set.sweep(); + return steps; + } + + bool needsSweep() override { return set.needsSweep(); } + + bool setNeedsIncrementalBarrier(bool needs) override { + MOZ_ASSERT(needsBarrier != needs); + needsBarrier = needs; + return true; + } + + bool needsIncrementalBarrier() const override { return needsBarrier; } + + private: + static bool entryNeedsSweep(const Entry& prior) { + Entry entry(prior); + bool result = GCPolicy::needsSweep(&entry); + MOZ_ASSERT(prior == entry); // We shouldn't update here. + return result; + } + + public: + using Lookup = typename Set::Lookup; + using Ptr = typename Set::Ptr; + using AddPtr = typename Set::AddPtr; + + struct Range { + explicit Range(const typename Set::Range& r) : range(r) { settle(); } + Range() {} + + bool empty() const { return range.empty(); } + const Entry& front() const { return range.front(); } + + void popFront() { + range.popFront(); + settle(); + } + + private: + typename Set::Range range; + + void settle() { + while (!empty() && entryNeedsSweep(front())) popFront(); + } + }; + + struct Enum : public Set::Enum { + explicit Enum(Self& cache) : Set::Enum(cache.set) { + // This operation is not allowed while barriers are in place as we + // may also need to enumerate the set for sweeping. + MOZ_ASSERT(!cache.needsBarrier); + } + }; + + bool initialized() const { return set.initialized(); } + + Ptr lookup(const Lookup& l) const { + Ptr ptr = set.lookup(l); + if (needsBarrier && ptr && entryNeedsSweep(*ptr)) { + const_cast(set).remove(ptr); + return Ptr(); + } + return ptr; + } + + AddPtr lookupForAdd(const Lookup& l) const { + AddPtr ptr = set.lookupForAdd(l); + if (needsBarrier && ptr && entryNeedsSweep(*ptr)) { + const_cast(set).remove(ptr); + return set.lookupForAdd(l); + } + return ptr; + } + + Range all() const { return Range(set.all()); } + + bool empty() const { + // This operation is not currently allowed while barriers are in place + // as it would require iterating the set and the caller expects a + // constant time operation. + MOZ_ASSERT(!needsBarrier); + return set.empty(); + } + + uint32_t count() const { + // This operation is not currently allowed while barriers are in place + // as it would require iterating the set and the caller expects a + // constant time operation. + MOZ_ASSERT(!needsBarrier); + return set.count(); + } + + size_t capacity() const { return set.capacity(); } + + bool has(const Lookup& l) const { return 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); + } + + bool init(uint32_t len = 16) { + MOZ_ASSERT(!needsBarrier); + return set.init(len); + } + + void clear() { + // This operation is not currently allowed while barriers are in place + // since it doesn't make sense to clear a cache while it is being swept. + MOZ_ASSERT(!needsBarrier); + set.clear(); + } + + void finish() { + // This operation is not currently allowed while barriers are in place + // since it doesn't make sense to destroy a cache while it is being swept. + MOZ_ASSERT(!needsBarrier); + set.finish(); + } + + void remove(Ptr p) { + // This currently supports removing entries during incremental + // sweeping. If we allow these tables to be swept incrementally this may + // no longer be possible. + set.remove(p); + } + + void remove(const Lookup& l) { + Ptr p = lookup(l); + if (p) remove(p); + } + + template + bool add(AddPtr& p, TInput&& t) { + return set.add(p, mozilla::Forward(t)); + } + + template + bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) { + return set.relookupOrAdd(p, l, mozilla::Forward(t)); + } + + template + bool put(TInput&& t) { + return set.put(mozilla::Forward(t)); + } + + template + bool putNew(TInput&& t) { + return set.putNew(mozilla::Forward(t)); + } + + template + bool putNew(const Lookup& l, TInput&& t) { + return set.putNew(l, mozilla::Forward(t)); + } }; -} /* namespace js */ +} // namespace JS #endif /* GCHashTable_h */ 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 @@ -40,125 +40,155 @@ #ifndef GCPolicyAPI_h #define GCPolicyAPI_h +#include "mozilla/Maybe.h" #include "mozilla/UniquePtr.h" #include "js/TraceKind.h" #include "js/TracingAPI.h" +#include "js/TypeDecls.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*) + 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) + 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; -} +#define FOR_EACH_PUBLIC_AGGREGATE_GC_POINTER_TYPE(D) D(JSPropertyDescriptor) 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(); - } +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(); } + + static bool isValid(const T& tp) { return true; } }; // 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 {}; +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); - } + static T initial() { return T(); } + static void trace(JSTracer* trc, T* t, const char* name) {} + static bool needsSweep(T* v) { return false; } + static bool isValid(const T& v) { return true; } +}; +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; + } + static bool isValid(T v) { return js::gc::IsCellPointerValidOrNull(v); } +}; +template <> +struct GCPolicy : public GCPointerPolicy {}; +template <> +struct GCPolicy : public GCPointerPolicy {}; +template <> +struct GCPolicy : public GCPointerPolicy {}; +template <> +struct GCPolicy : public GCPointerPolicy {}; +template <> +struct GCPolicy : public GCPointerPolicy {}; +template <> +struct GCPolicy : public GCPointerPolicy {}; + +template +struct NonGCPointerPolicy { + static T initial() { return nullptr; } + static void trace(JSTracer* trc, T* vp, const char* name) { + if (*vp) (*vp)->trace(trc); + } + static bool needsSweep(T* vp) { + if (*vp) return (*vp)->needsSweep(); + return false; + } + static bool isValid(T v) { return true; } +}; + +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 *thingp && 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; - } +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; + } + static bool isValid(const mozilla::UniquePtr& t) { + if (t.get()) return GCPolicy::isValid(*t.get()); + return true; + } }; -} // namespace JS +// GCPolicy> forwards tracing/sweeping to GCPolicy if +// when the Maybe is full. +template +struct GCPolicy> { + static mozilla::Maybe initial() { return mozilla::Maybe(); } + static void trace(JSTracer* trc, mozilla::Maybe* tp, const char* name) { + if (tp->isSome()) GCPolicy::trace(trc, tp->ptr(), name); + } + static bool needsSweep(mozilla::Maybe* tp) { + if (tp->isSome()) return GCPolicy::needsSweep(tp->ptr()); + return false; + } + static bool isValid(const mozilla::Maybe& t) { + if (t.isSome()) return GCPolicy::isValid(t.ref()); + return true; + } +}; + +template <> +struct GCPolicy; // see Realm.h + +} // namespace JS -#endif // GCPolicyAPI_h +#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 @@ -43,156 +43,149 @@ // 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)); - } +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); - } +struct GCVariantImplementation { + using Next = GCVariantImplementation; - 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); + 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 +} // namespace detail template -struct GCPolicy> -{ - using Impl = detail::GCVariantImplementation; +struct GCPolicy> { + using Impl = detail::GCVariantImplementation; - // Variants do not provide initial(). They do not have a default initial - // value and one must be provided. + // 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 { + static void trace(JSTracer* trc, mozilla::Variant* v, + const char* name) { + Impl::trace(trc, v, name); + } -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(); - } + static bool isValid(const mozilla::Variant& v) { + return v.match(IsValidMatcher()); + } + private: + struct IsValidMatcher { 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())); - } + bool match(T& v) { + return GCPolicy::isValid(v); + }; + }; }; -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(); } +} // namespace JS - public: - template - JS::MutableHandle as() { - return JS::MutableHandle::fromMarkedLocation(&variant().template as()); - } +namespace js { - template - typename Matcher::ReturnType - match(Matcher& matcher) { - return Impl::match(matcher, JS::MutableHandle::fromMarkedLocation(&variant())); - } +template +class WrappedPtrOperations, Wrapper> { + 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 RootedBase> - : public MutableGCVariantOperations>, Ts...> -{ }; - -template -class MutableHandleBase> - : public MutableGCVariantOperations>, Ts...> -{ }; - -template -class HandleBase> - : public GCVariantOperations>, Ts...> -{ }; - -template -class PersistentRootedBase> - : public MutableGCVariantOperations>, Ts...> -{ }; +template +class MutableWrappedPtrOperations, Wrapper> + : public WrappedPtrOperations, Wrapper> { + 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())); + } +}; -} // namespace js +} // namespace js -#endif // js_GCVariant_h +#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 @@ -30,220 +30,253 @@ // 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); - } +class GCVector { + mozilla::Vector vector; - void popBack() { return vector.popBack(); } - T popCopy() { return vector.popCopy(); } + public: + explicit GCVector(AllocPolicy alloc = AllocPolicy()) : vector(alloc) {} - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return vector.sizeOfExcludingThis(mallocSizeOf); - } + GCVector(GCVector&& vec) : vector(mozilla::Move(vec.vector)) {} - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return vector.sizeOfIncludingThis(mallocSizeOf); + 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); } + MOZ_MUST_USE bool reserve(size_t req) { return vector.reserve(req); } + void shrinkBy(size_t amount) { return vector.shrinkBy(amount); } + MOZ_MUST_USE bool growBy(size_t amount) { return vector.growBy(amount); } + MOZ_MUST_USE bool resize(size_t newLen) { return vector.resize(newLen); } + + void clear() { return vector.clear(); } + void clearAndFree() { return vector.clearAndFree(); } + + template + bool append(U&& item) { + return vector.append(mozilla::Forward(item)); + } + + template + MOZ_MUST_USE 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 + MOZ_MUST_USE bool appendAll(const U& aU) { + return vector.append(aU.begin(), aU.end()); + } + + MOZ_MUST_USE bool appendN(const T& val, size_t count) { + return vector.appendN(val, count); + } + + template + MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd) { + return vector.append(aBegin, aEnd); + } + template + MOZ_MUST_USE 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"); + } + + bool needsSweep() const { return !this->empty(); } + + void sweep() { + uint32_t src, dst = 0; + for (src = 0; src < length(); src++) { + if (!GCPolicy::needsSweep(&vector[src])) { + if (dst != src) vector[dst] = vector[src].unbarrieredGet(); + dst++; + } } - static void trace(GCVector* vec, JSTracer* trc) { vec->trace(trc); } - - void trace(JSTracer* trc) { - for (auto& elem : vector) - GCPolicy::trace(trc, &elem, "vector element"); - } + if (dst != length()) vector.shrinkTo(dst); + } }; -} // namespace JS +} // 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(); } +template +class WrappedPtrOperations, Wrapper> { + 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)); + } +}; - JS::Handle operator[](size_t aIndex) const { - return JS::Handle::fromMarkedLocation(&vec().operator[](aIndex)); - } +template +class MutableWrappedPtrOperations, + Wrapper> + : public WrappedPtrOperations, + Wrapper> { + 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)); + } + + MOZ_MUST_USE bool initCapacity(size_t aRequest) { + return vec().initCapacity(aRequest); + } + MOZ_MUST_USE bool reserve(size_t aRequest) { return vec().reserve(aRequest); } + void shrinkBy(size_t aIncr) { vec().shrinkBy(aIncr); } + MOZ_MUST_USE bool growBy(size_t aIncr) { return vec().growBy(aIncr); } + MOZ_MUST_USE bool resize(size_t aNewLength) { + return vec().resize(aNewLength); + } + MOZ_MUST_USE bool growByUninitialized(size_t aIncr) { + return vec().growByUninitialized(aIncr); + } + void infallibleGrowByUninitialized(size_t aIncr) { + vec().infallibleGrowByUninitialized(aIncr); + } + MOZ_MUST_USE bool resizeUninitialized(size_t aNewLength) { + return vec().resizeUninitialized(aNewLength); + } + void clear() { vec().clear(); } + void clearAndFree() { vec().clearAndFree(); } + template + MOZ_MUST_USE bool append(U&& aU) { + return vec().append(mozilla::Forward(aU)); + } + template + MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) { + return vec().emplaceBack(mozilla::Forward(aArgs...)); + } + template + MOZ_MUST_USE bool appendAll(const U& aU) { + return vec().appendAll(aU); + } + MOZ_MUST_USE bool appendN(const T& aT, size_t aN) { + return vec().appendN(aT, aN); + } + template + MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd) { + return vec().append(aBegin, aEnd); + } + template + MOZ_MUST_USE 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 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(); } +} // namespace js - 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)); - } +namespace JS { - 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); } -}; +// An automatically rooted vector for stack use. +template +class AutoVector : public Rooted> { + using Vec = GCVector; + using Base = Rooted; -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> -{}; + public: + explicit AutoVector(JSContext* cx) : Base(cx, Vec(cx)) {} +}; -} // namespace js +} // namespace JS -#endif // js_GCVector_h +#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 @@ -26,12 +26,16 @@ namespace js { class TempAllocPolicy; -template struct DefaultHasher; -template class HashMapEntry; +template +struct DefaultHasher; +template +class HashMapEntry; namespace detail { - template class HashTableEntry; - template class HashTable; -} // namespace detail +template +class HashTableEntry; +template +class HashTable; +} // namespace detail /*****************************************************************************/ @@ -56,249 +60,249 @@ // HashPolicy requirements: // - see Hash Policy section below // AllocPolicy: -// - see jsalloc.h +// - see AllocPolicy.h // // Note: // - HashMap is not reentrant: Key/Value/HashPolicy/AllocPolicy members // called by HashMap must not call back into the same HashMap object. // - Due to the lack of exception handling, the user must call |init()|. -template , +template , class AllocPolicy = TempAllocPolicy> -class HashMap -{ - typedef HashMapEntry TableEntry; - - struct MapHashPolicy : HashPolicy - { - using Base = HashPolicy; - typedef Key KeyType; - static const Key& getKey(TableEntry& e) { return e.key(); } - static void setKey(TableEntry& e, Key& k) { HashPolicy::rekey(e.mutableKey(), k); } - }; - - typedef detail::HashTable Impl; - Impl impl; - - public: - typedef typename HashPolicy::Lookup Lookup; - typedef TableEntry Entry; - - // HashMap construction is fallible (due to OOM); thus the user must call - // init after constructing a HashMap and check the return value. - explicit HashMap(AllocPolicy a = AllocPolicy()) : impl(a) {} - MOZ_MUST_USE bool init(uint32_t len = 16) { return impl.init(len); } - bool initialized() const { return impl.initialized(); } - - // Return whether the given lookup value is present in the map. E.g.: - // - // typedef HashMap HM; - // HM h; - // if (HM::Ptr p = h.lookup(3)) { - // const HM::Entry& e = *p; // p acts like a pointer to Entry - // assert(p->key == 3); // Entry contains the key - // char val = p->value; // and value - // } - // - // Also see the definition of Ptr in HashTable above (with T = Entry). - typedef typename Impl::Ptr Ptr; - Ptr lookup(const Lookup& l) const { return impl.lookup(l); } - - // Like lookup, but does not assert if two threads call lookup at the same - // time. Only use this method when none of the threads will modify the map. - Ptr readonlyThreadsafeLookup(const Lookup& l) const { return impl.readonlyThreadsafeLookup(l); } - - // Assuming |p.found()|, remove |*p|. - void remove(Ptr p) { impl.remove(p); } - - // Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient - // insertion of Key |k| (where |HashPolicy::match(k,l) == true|) using - // |add(p,k,v)|. After |add(p,k,v)|, |p| points to the new Entry. E.g.: - // - // typedef HashMap HM; - // HM h; - // HM::AddPtr p = h.lookupForAdd(3); - // if (!p) { - // if (!h.add(p, 3, 'a')) - // return false; - // } - // const HM::Entry& e = *p; // p acts like a pointer to Entry - // assert(p->key == 3); // Entry contains the key - // char val = p->value; // and value - // - // Also see the definition of AddPtr in HashTable above (with T = Entry). - // - // N.B. The caller must ensure that no mutating hash table operations - // occur between a pair of |lookupForAdd| and |add| calls. To avoid - // looking up the key a second time, the caller may use the more efficient - // relookupOrAdd method. This method reuses part of the hashing computation - // to more efficiently insert the key if it has not been added. For - // example, a mutation-handling version of the previous example: - // - // HM::AddPtr p = h.lookupForAdd(3); - // if (!p) { - // call_that_may_mutate_h(); - // if (!h.relookupOrAdd(p, 3, 'a')) - // return false; - // } - // const HM::Entry& e = *p; - // assert(p->key == 3); - // char val = p->value; - typedef typename Impl::AddPtr AddPtr; - AddPtr lookupForAdd(const Lookup& l) const { - return impl.lookupForAdd(l); - } - - template - MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { - return impl.add(p, - mozilla::Forward(k), - mozilla::Forward(v)); - } - - template - MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k) { - return impl.add(p, mozilla::Forward(k), Value()); - } - - template - MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { - return impl.relookupOrAdd(p, k, - mozilla::Forward(k), - mozilla::Forward(v)); - } - - // |all()| returns a Range containing |count()| elements. E.g.: - // - // typedef HashMap HM; - // HM h; - // for (HM::Range r = h.all(); !r.empty(); r.popFront()) - // char c = r.front().value(); - // - // Also see the definition of Range in HashTable above (with T = Entry). - typedef typename Impl::Range Range; - Range all() const { return impl.all(); } - - // Typedef for the enumeration class. An Enum may be used to examine and - // remove table entries: - // - // typedef HashMap HM; - // HM s; - // for (HM::Enum e(s); !e.empty(); e.popFront()) - // if (e.front().value() == 'l') - // e.removeFront(); - // - // Table resize may occur in Enum's destructor. Also see the definition of - // Enum in HashTable above (with T = Entry). - typedef typename Impl::Enum Enum; - - // Remove all entries. This does not shrink the table. For that consider - // using the finish() method. - void clear() { impl.clear(); } - - // Remove all the entries and release all internal buffers. The map must - // be initialized again before any use. - void finish() { impl.finish(); } - - // Does the table contain any entries? - bool empty() const { return impl.empty(); } - - // Number of live elements in the map. - uint32_t count() const { return impl.count(); } +class HashMap { + typedef HashMapEntry TableEntry; - // Total number of allocation in the dynamic table. Note: resize will - // happen well before count() == capacity(). - size_t capacity() const { return impl.capacity(); } - - // Don't just call |impl.sizeOfExcludingThis()| because there's no - // guarantee that |impl| is the first field in HashMap. - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return impl.sizeOfExcludingThis(mallocSizeOf); - } - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); - } - - Generation generation() const { - return impl.generation(); - } - - /************************************************** Shorthand operations */ - - bool has(const Lookup& l) const { - return impl.lookup(l).found(); - } - - // Overwrite existing value with v. Return false on oom. - template - MOZ_MUST_USE bool put(KeyInput&& k, ValueInput&& v) { - AddPtr p = lookupForAdd(k); - if (p) { - p->value() = mozilla::Forward(v); - return true; - } - return add(p, mozilla::Forward(k), mozilla::Forward(v)); - } - - // Like put, but assert that the given key is not already present. - template - MOZ_MUST_USE bool putNew(KeyInput&& k, ValueInput&& v) { - return impl.putNew(k, mozilla::Forward(k), mozilla::Forward(v)); - } - - // Only call this to populate an empty map after reserving space with init(). - template - void putNewInfallible(KeyInput&& k, ValueInput&& v) { - impl.putNewInfallible(k, mozilla::Forward(k), mozilla::Forward(v)); - } - - // Add (k,defaultValue) if |k| is not found. Return a false-y Ptr on oom. - Ptr lookupWithDefault(const Key& k, const Value& defaultValue) { - AddPtr p = lookupForAdd(k); - if (p) - return p; - bool ok = add(p, k, defaultValue); - MOZ_ASSERT_IF(!ok, !p); // p is left false-y on oom. - (void)ok; - return p; - } - - // Remove if present. - void remove(const Lookup& l) { - if (Ptr p = lookup(l)) - remove(p); - } - - // Infallibly rekey one entry, if necessary. - // Requires template parameters Key and HashPolicy::Lookup to be the same type. - void rekeyIfMoved(const Key& old_key, const Key& new_key) { - if (old_key != new_key) - rekeyAs(old_key, new_key, new_key); - } - - // Infallibly rekey one entry if present, and return whether that happened. - bool rekeyAs(const Lookup& old_lookup, const Lookup& new_lookup, const Key& new_key) { - if (Ptr p = lookup(old_lookup)) { - impl.rekeyAndMaybeRehash(p, new_lookup, new_key); - return true; - } - return false; - } - - // HashMap is movable - HashMap(HashMap&& rhs) : impl(mozilla::Move(rhs.impl)) {} - void operator=(HashMap&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - impl = mozilla::Move(rhs.impl); - } - - private: - // HashMap is not copyable or assignable - HashMap(const HashMap& hm) = delete; - HashMap& operator=(const HashMap& hm) = delete; + struct MapHashPolicy : HashPolicy { + using Base = HashPolicy; + typedef Key KeyType; + static const Key& getKey(TableEntry& e) { return e.key(); } + static void setKey(TableEntry& e, Key& k) { + HashPolicy::rekey(e.mutableKey(), k); + } + }; + + typedef detail::HashTable Impl; + Impl impl; + + public: + typedef typename HashPolicy::Lookup Lookup; + typedef TableEntry Entry; + + // HashMap construction is fallible (due to OOM); thus the user must call + // init after constructing a HashMap and check the return value. + explicit HashMap(AllocPolicy a = AllocPolicy()) : impl(a) {} + MOZ_MUST_USE bool init(uint32_t len = 16) { return impl.init(len); } + bool initialized() const { return impl.initialized(); } + + // Return whether the given lookup value is present in the map. E.g.: + // + // typedef HashMap HM; + // HM h; + // if (HM::Ptr p = h.lookup(3)) { + // const HM::Entry& e = *p; // p acts like a pointer to Entry + // assert(p->key == 3); // Entry contains the key + // char val = p->value; // and value + // } + // + // Also see the definition of Ptr in HashTable above (with T = Entry). + typedef typename Impl::Ptr Ptr; + MOZ_ALWAYS_INLINE Ptr lookup(const Lookup& l) const { return impl.lookup(l); } + + // Like lookup, but does not assert if two threads call lookup at the same + // time. Only use this method when none of the threads will modify the map. + MOZ_ALWAYS_INLINE Ptr readonlyThreadsafeLookup(const Lookup& l) const { + return impl.readonlyThreadsafeLookup(l); + } + + // Assuming |p.found()|, remove |*p|. + void remove(Ptr p) { impl.remove(p); } + + // Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient + // insertion of Key |k| (where |HashPolicy::match(k,l) == true|) using + // |add(p,k,v)|. After |add(p,k,v)|, |p| points to the new Entry. E.g.: + // + // typedef HashMap HM; + // HM h; + // HM::AddPtr p = h.lookupForAdd(3); + // if (!p) { + // if (!h.add(p, 3, 'a')) + // return false; + // } + // const HM::Entry& e = *p; // p acts like a pointer to Entry + // assert(p->key == 3); // Entry contains the key + // char val = p->value; // and value + // + // Also see the definition of AddPtr in HashTable above (with T = Entry). + // + // N.B. The caller must ensure that no mutating hash table operations + // occur between a pair of |lookupForAdd| and |add| calls. To avoid + // looking up the key a second time, the caller may use the more efficient + // relookupOrAdd method. This method reuses part of the hashing computation + // to more efficiently insert the key if it has not been added. For + // example, a mutation-handling version of the previous example: + // + // HM::AddPtr p = h.lookupForAdd(3); + // if (!p) { + // call_that_may_mutate_h(); + // if (!h.relookupOrAdd(p, 3, 'a')) + // return false; + // } + // const HM::Entry& e = *p; + // assert(p->key == 3); + // char val = p->value; + typedef typename Impl::AddPtr AddPtr; + MOZ_ALWAYS_INLINE AddPtr lookupForAdd(const Lookup& l) const { + return impl.lookupForAdd(l); + } + + template + MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { + return impl.add(p, mozilla::Forward(k), + mozilla::Forward(v)); + } + + template + MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k) { + return impl.add(p, mozilla::Forward(k), Value()); + } + + template + MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { + return impl.relookupOrAdd(p, k, mozilla::Forward(k), + mozilla::Forward(v)); + } + + // |all()| returns a Range containing |count()| elements. E.g.: + // + // typedef HashMap HM; + // HM h; + // for (HM::Range r = h.all(); !r.empty(); r.popFront()) + // char c = r.front().value(); + // + // Also see the definition of Range in HashTable above (with T = Entry). + typedef typename Impl::Range Range; + Range all() const { return impl.all(); } + + // Typedef for the enumeration class. An Enum may be used to examine and + // remove table entries: + // + // typedef HashMap HM; + // HM s; + // for (HM::Enum e(s); !e.empty(); e.popFront()) + // if (e.front().value() == 'l') + // e.removeFront(); + // + // Table resize may occur in Enum's destructor. Also see the definition of + // Enum in HashTable above (with T = Entry). + typedef typename Impl::Enum Enum; + + // Remove all entries. This does not shrink the table. For that consider + // using the finish() method. + void clear() { impl.clear(); } + + // Remove all entries. Unlike clear() this method tries to shrink the table. + // Unlike finish() it does not require the map to be initialized again. + void clearAndShrink() { impl.clearAndShrink(); } + + // Remove all the entries and release all internal buffers. The map must + // be initialized again before any use. + void finish() { impl.finish(); } + + // Does the table contain any entries? + bool empty() const { return impl.empty(); } + + // Number of live elements in the map. + uint32_t count() const { return impl.count(); } + + // Total number of allocation in the dynamic table. Note: resize will + // happen well before count() == capacity(). + size_t capacity() const { return impl.capacity(); } + + // Don't just call |impl.sizeOfExcludingThis()| because there's no + // guarantee that |impl| is the first field in HashMap. + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return impl.sizeOfExcludingThis(mallocSizeOf); + } + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); + } + + Generation generation() const { return impl.generation(); } + + /************************************************** Shorthand operations */ + + bool has(const Lookup& l) const { return impl.lookup(l).found(); } + + // Overwrite existing value with v. Return false on oom. + template + MOZ_MUST_USE bool put(KeyInput&& k, ValueInput&& v) { + AddPtr p = lookupForAdd(k); + if (p) { + p->value() = mozilla::Forward(v); + return true; + } + return add(p, mozilla::Forward(k), + mozilla::Forward(v)); + } + + // Like put, but assert that the given key is not already present. + template + MOZ_MUST_USE bool putNew(KeyInput&& k, ValueInput&& v) { + return impl.putNew(k, mozilla::Forward(k), + mozilla::Forward(v)); + } + + // Only call this to populate an empty map after reserving space with init(). + template + void putNewInfallible(KeyInput&& k, ValueInput&& v) { + impl.putNewInfallible(k, mozilla::Forward(k), + mozilla::Forward(v)); + } + + // Add (k,defaultValue) if |k| is not found. Return a false-y Ptr on oom. + Ptr lookupWithDefault(const Key& k, const Value& defaultValue) { + AddPtr p = lookupForAdd(k); + if (p) return p; + bool ok = add(p, k, defaultValue); + MOZ_ASSERT_IF(!ok, !p); // p is left false-y on oom. + (void)ok; + return p; + } + + // Remove if present. + void remove(const Lookup& l) { + if (Ptr p = lookup(l)) remove(p); + } + + // Infallibly rekey one entry, if necessary. + // Requires template parameters Key and HashPolicy::Lookup to be the same + // type. + void rekeyIfMoved(const Key& old_key, const Key& new_key) { + if (old_key != new_key) rekeyAs(old_key, new_key, new_key); + } + + // Infallibly rekey one entry if present, and return whether that happened. + bool rekeyAs(const Lookup& old_lookup, const Lookup& new_lookup, + const Key& new_key) { + if (Ptr p = lookup(old_lookup)) { + impl.rekeyAndMaybeRehash(p, new_lookup, new_key); + return true; + } + return false; + } + + // HashMap is movable + HashMap(HashMap&& rhs) : impl(mozilla::Move(rhs.impl)) {} + void operator=(HashMap&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); + impl = mozilla::Move(rhs.impl); + } + + private: + // HashMap is not copyable or assignable + HashMap(const HashMap& hm) = delete; + HashMap& operator=(const HashMap& hm) = delete; - friend class Impl::Enum; + friend class Impl::Enum; }; /*****************************************************************************/ @@ -312,233 +316,233 @@ // HashPolicy requirements: // - see Hash Policy section below // AllocPolicy: -// - see jsalloc.h +// - see AllocPolicy.h // // Note: // - HashSet is not reentrant: T/HashPolicy/AllocPolicy members called by // HashSet must not call back into the same HashSet object. // - Due to the lack of exception handling, the user must call |init()|. -template , +template , class AllocPolicy = TempAllocPolicy> -class HashSet -{ - struct SetOps : HashPolicy - { - using Base = HashPolicy; - typedef T KeyType; - static const KeyType& getKey(const T& t) { return t; } - static void setKey(T& t, KeyType& k) { HashPolicy::rekey(t, k); } - }; - - typedef detail::HashTable Impl; - Impl impl; - - public: - typedef typename HashPolicy::Lookup Lookup; - typedef T Entry; - - // HashSet construction is fallible (due to OOM); thus the user must call - // init after constructing a HashSet and check the return value. - explicit HashSet(AllocPolicy a = AllocPolicy()) : impl(a) {} - MOZ_MUST_USE bool init(uint32_t len = 16) { return impl.init(len); } - bool initialized() const { return impl.initialized(); } - - // Return whether the given lookup value is present in the map. E.g.: - // - // typedef HashSet HS; - // HS h; - // if (HS::Ptr p = h.lookup(3)) { - // assert(*p == 3); // p acts like a pointer to int - // } - // - // Also see the definition of Ptr in HashTable above. - typedef typename Impl::Ptr Ptr; - Ptr lookup(const Lookup& l) const { return impl.lookup(l); } - - // Like lookup, but does not assert if two threads call lookup at the same - // time. Only use this method when none of the threads will modify the map. - Ptr readonlyThreadsafeLookup(const Lookup& l) const { return impl.readonlyThreadsafeLookup(l); } - - // Assuming |p.found()|, remove |*p|. - void remove(Ptr p) { impl.remove(p); } - - // Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient - // insertion of T value |t| (where |HashPolicy::match(t,l) == true|) using - // |add(p,t)|. After |add(p,t)|, |p| points to the new element. E.g.: - // - // typedef HashSet HS; - // HS h; - // HS::AddPtr p = h.lookupForAdd(3); - // if (!p) { - // if (!h.add(p, 3)) - // return false; - // } - // assert(*p == 3); // p acts like a pointer to int - // - // Also see the definition of AddPtr in HashTable above. - // - // N.B. The caller must ensure that no mutating hash table operations - // occur between a pair of |lookupForAdd| and |add| calls. To avoid - // looking up the key a second time, the caller may use the more efficient - // relookupOrAdd method. This method reuses part of the hashing computation - // to more efficiently insert the key if it has not been added. For - // example, a mutation-handling version of the previous example: - // - // HS::AddPtr p = h.lookupForAdd(3); - // if (!p) { - // call_that_may_mutate_h(); - // if (!h.relookupOrAdd(p, 3, 3)) - // return false; - // } - // assert(*p == 3); - // - // Note that relookupOrAdd(p,l,t) performs Lookup using |l| and adds the - // entry |t|, where the caller ensures match(l,t). - typedef typename Impl::AddPtr AddPtr; - AddPtr lookupForAdd(const Lookup& l) const { return impl.lookupForAdd(l); } - - template - MOZ_MUST_USE bool add(AddPtr& p, U&& u) { - return impl.add(p, mozilla::Forward(u)); - } - - template - MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, U&& u) { - return impl.relookupOrAdd(p, l, mozilla::Forward(u)); - } - - // |all()| returns a Range containing |count()| elements: - // - // typedef HashSet HS; - // HS h; - // for (HS::Range r = h.all(); !r.empty(); r.popFront()) - // int i = r.front(); - // - // Also see the definition of Range in HashTable above. - typedef typename Impl::Range Range; - Range all() const { return impl.all(); } +class HashSet { + struct SetOps : HashPolicy { + using Base = HashPolicy; + typedef T KeyType; + static const KeyType& getKey(const T& t) { return t; } + static void setKey(T& t, KeyType& k) { HashPolicy::rekey(t, k); } + }; + + typedef detail::HashTable Impl; + Impl impl; + + public: + typedef typename HashPolicy::Lookup Lookup; + typedef T Entry; + + // HashSet construction is fallible (due to OOM); thus the user must call + // init after constructing a HashSet and check the return value. + explicit HashSet(AllocPolicy a = AllocPolicy()) : impl(a) {} + MOZ_MUST_USE bool init(uint32_t len = 16) { return impl.init(len); } + bool initialized() const { return impl.initialized(); } + + // Return whether the given lookup value is present in the map. E.g.: + // + // typedef HashSet HS; + // HS h; + // if (HS::Ptr p = h.lookup(3)) { + // assert(*p == 3); // p acts like a pointer to int + // } + // + // Also see the definition of Ptr in HashTable above. + typedef typename Impl::Ptr Ptr; + MOZ_ALWAYS_INLINE Ptr lookup(const Lookup& l) const { return impl.lookup(l); } + + // Like lookup, but does not assert if two threads call lookup at the same + // time. Only use this method when none of the threads will modify the map. + MOZ_ALWAYS_INLINE Ptr readonlyThreadsafeLookup(const Lookup& l) const { + return impl.readonlyThreadsafeLookup(l); + } + + // Assuming |p.found()|, remove |*p|. + void remove(Ptr p) { impl.remove(p); } + + // Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient + // insertion of T value |t| (where |HashPolicy::match(t,l) == true|) using + // |add(p,t)|. After |add(p,t)|, |p| points to the new element. E.g.: + // + // typedef HashSet HS; + // HS h; + // HS::AddPtr p = h.lookupForAdd(3); + // if (!p) { + // if (!h.add(p, 3)) + // return false; + // } + // assert(*p == 3); // p acts like a pointer to int + // + // Also see the definition of AddPtr in HashTable above. + // + // N.B. The caller must ensure that no mutating hash table operations + // occur between a pair of |lookupForAdd| and |add| calls. To avoid + // looking up the key a second time, the caller may use the more efficient + // relookupOrAdd method. This method reuses part of the hashing computation + // to more efficiently insert the key if it has not been added. For + // example, a mutation-handling version of the previous example: + // + // HS::AddPtr p = h.lookupForAdd(3); + // if (!p) { + // call_that_may_mutate_h(); + // if (!h.relookupOrAdd(p, 3, 3)) + // return false; + // } + // assert(*p == 3); + // + // Note that relookupOrAdd(p,l,t) performs Lookup using |l| and adds the + // entry |t|, where the caller ensures match(l,t). + typedef typename Impl::AddPtr AddPtr; + MOZ_ALWAYS_INLINE AddPtr lookupForAdd(const Lookup& l) const { + return impl.lookupForAdd(l); + } + + template + MOZ_MUST_USE bool add(AddPtr& p, U&& u) { + return impl.add(p, mozilla::Forward(u)); + } + + template + MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, U&& u) { + return impl.relookupOrAdd(p, l, mozilla::Forward(u)); + } + + // |all()| returns a Range containing |count()| elements: + // + // typedef HashSet HS; + // HS h; + // for (HS::Range r = h.all(); !r.empty(); r.popFront()) + // int i = r.front(); + // + // Also see the definition of Range in HashTable above. + typedef typename Impl::Range Range; + Range all() const { return impl.all(); } + + // Typedef for the enumeration class. An Enum may be used to examine and + // remove table entries: + // + // typedef HashSet HS; + // HS s; + // for (HS::Enum e(s); !e.empty(); e.popFront()) + // if (e.front() == 42) + // e.removeFront(); + // + // Table resize may occur in Enum's destructor. Also see the definition of + // Enum in HashTable above. + typedef typename Impl::Enum Enum; + + // Remove all entries. This does not shrink the table. For that consider + // using the finish() method. + void clear() { impl.clear(); } + + // Remove all entries. Unlike clear() this method tries to shrink the table. + // Unlike finish() it does not require the set to be initialized again. + void clearAndShrink() { impl.clearAndShrink(); } + + // Remove all the entries and release all internal buffers. The set must + // be initialized again before any use. + void finish() { impl.finish(); } + + // Does the table contain any entries? + bool empty() const { return impl.empty(); } + + // Number of live elements in the map. + uint32_t count() const { return impl.count(); } + + // Total number of allocation in the dynamic table. Note: resize will + // happen well before count() == capacity(). + size_t capacity() const { return impl.capacity(); } + + // Don't just call |impl.sizeOfExcludingThis()| because there's no + // guarantee that |impl| is the first field in HashSet. + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return impl.sizeOfExcludingThis(mallocSizeOf); + } + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); + } + + Generation generation() const { return impl.generation(); } + + /************************************************** Shorthand operations */ + + bool has(const Lookup& l) const { return impl.lookup(l).found(); } + + // Add |u| if it is not present already. Return false on oom. + template + MOZ_MUST_USE bool put(U&& u) { + AddPtr p = lookupForAdd(u); + return p ? true : add(p, mozilla::Forward(u)); + } + + // Like put, but assert that the given key is not already present. + template + MOZ_MUST_USE bool putNew(U&& u) { + return impl.putNew(u, mozilla::Forward(u)); + } + + template + MOZ_MUST_USE bool putNew(const Lookup& l, U&& u) { + return impl.putNew(l, mozilla::Forward(u)); + } + + // Only call this to populate an empty set after reserving space with init(). + template + void putNewInfallible(const Lookup& l, U&& u) { + impl.putNewInfallible(l, mozilla::Forward(u)); + } + + void remove(const Lookup& l) { + if (Ptr p = lookup(l)) remove(p); + } + + // Infallibly rekey one entry, if present. + // Requires template parameters T and HashPolicy::Lookup to be the same type. + void rekeyIfMoved(const Lookup& old_value, const T& new_value) { + if (old_value != new_value) rekeyAs(old_value, new_value, new_value); + } + + // Infallibly rekey one entry if present, and return whether that happened. + bool rekeyAs(const Lookup& old_lookup, const Lookup& new_lookup, + const T& new_value) { + if (Ptr p = lookup(old_lookup)) { + impl.rekeyAndMaybeRehash(p, new_lookup, new_value); + return true; + } + return false; + } + + // Infallibly replace the current key at |p| with an equivalent key. + // Specifically, both HashPolicy::hash and HashPolicy::match must return + // identical results for the new and old key when applied against all + // possible matching values. + void replaceKey(Ptr p, const T& new_value) { + MOZ_ASSERT(p.found()); + MOZ_ASSERT(*p != new_value); + MOZ_ASSERT(HashPolicy::hash(*p) == HashPolicy::hash(new_value)); + MOZ_ASSERT(HashPolicy::match(*p, new_value)); + const_cast(*p) = new_value; + } + + // HashSet is movable + HashSet(HashSet&& rhs) : impl(mozilla::Move(rhs.impl)) {} + void operator=(HashSet&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); + impl = mozilla::Move(rhs.impl); + } + + private: + // HashSet is not copyable or assignable + HashSet(const HashSet& hs) = delete; + HashSet& operator=(const HashSet& hs) = delete; - // Typedef for the enumeration class. An Enum may be used to examine and - // remove table entries: - // - // typedef HashSet HS; - // HS s; - // for (HS::Enum e(s); !e.empty(); e.popFront()) - // if (e.front() == 42) - // e.removeFront(); - // - // Table resize may occur in Enum's destructor. Also see the definition of - // Enum in HashTable above. - typedef typename Impl::Enum Enum; - - // Remove all entries. This does not shrink the table. For that consider - // using the finish() method. - void clear() { impl.clear(); } - - // Remove all the entries and release all internal buffers. The set must - // be initialized again before any use. - void finish() { impl.finish(); } - - // Does the table contain any entries? - bool empty() const { return impl.empty(); } - - // Number of live elements in the map. - uint32_t count() const { return impl.count(); } - - // Total number of allocation in the dynamic table. Note: resize will - // happen well before count() == capacity(). - size_t capacity() const { return impl.capacity(); } - - // Don't just call |impl.sizeOfExcludingThis()| because there's no - // guarantee that |impl| is the first field in HashSet. - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return impl.sizeOfExcludingThis(mallocSizeOf); - } - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); - } - - Generation generation() const { - return impl.generation(); - } - - /************************************************** Shorthand operations */ - - bool has(const Lookup& l) const { - return impl.lookup(l).found(); - } - - // Add |u| if it is not present already. Return false on oom. - template - MOZ_MUST_USE bool put(U&& u) { - AddPtr p = lookupForAdd(u); - return p ? true : add(p, mozilla::Forward(u)); - } - - // Like put, but assert that the given key is not already present. - template - MOZ_MUST_USE bool putNew(U&& u) { - return impl.putNew(u, mozilla::Forward(u)); - } - - template - MOZ_MUST_USE bool putNew(const Lookup& l, U&& u) { - return impl.putNew(l, mozilla::Forward(u)); - } - - // Only call this to populate an empty set after reserving space with init(). - template - void putNewInfallible(const Lookup& l, U&& u) { - impl.putNewInfallible(l, mozilla::Forward(u)); - } - - void remove(const Lookup& l) { - if (Ptr p = lookup(l)) - remove(p); - } - - // Infallibly rekey one entry, if present. - // Requires template parameters T and HashPolicy::Lookup to be the same type. - void rekeyIfMoved(const Lookup& old_value, const T& new_value) { - if (old_value != new_value) - rekeyAs(old_value, new_value, new_value); - } - - // Infallibly rekey one entry if present, and return whether that happened. - bool rekeyAs(const Lookup& old_lookup, const Lookup& new_lookup, const T& new_value) { - if (Ptr p = lookup(old_lookup)) { - impl.rekeyAndMaybeRehash(p, new_lookup, new_value); - return true; - } - return false; - } - - // Infallibly replace the current key at |p| with an equivalent key. - // Specifically, both HashPolicy::hash and HashPolicy::match must return - // identical results for the new and old key when applied against all - // possible matching values. - void replaceKey(Ptr p, const T& new_value) { - MOZ_ASSERT(p.found()); - MOZ_ASSERT(*p != new_value); - MOZ_ASSERT(HashPolicy::hash(*p) == HashPolicy::hash(new_value)); - MOZ_ASSERT(HashPolicy::match(*p, new_value)); - const_cast(*p) = new_value; - } - - // HashSet is movable - HashSet(HashSet&& rhs) : impl(mozilla::Move(rhs.impl)) {} - void operator=(HashSet&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - impl = mozilla::Move(rhs.impl); - } - - private: - // HashSet is not copyable or assignable - HashSet(const HashSet& hs) = delete; - HashSet& operator=(const HashSet& hs) = delete; - - friend class Impl::Enum; + friend class Impl::Enum; }; /*****************************************************************************/ @@ -568,31 +572,18 @@ // h.add(p, k); // } -// Pointer hashing policy that strips the lowest zeroBits when calculating the -// hash to improve key distribution. -template -struct PointerHasher -{ - typedef Key Lookup; - static HashNumber hash(const Lookup& l) { - size_t word = reinterpret_cast(l) >> zeroBits; - static_assert(sizeof(HashNumber) == 4, - "subsequent code assumes a four-byte hash"); -#if JS_BITS_PER_WORD == 32 - return HashNumber(word); -#else - static_assert(sizeof(word) == 8, - "unexpected word size, new hashing strategy required to " - "properly incorporate all bits"); - return HashNumber((word >> 32) ^ word); -#endif - } - static bool match(const Key& k, const Lookup& l) { - return k == l; - } - static void rekey(Key& k, const Key& newKey) { - k = newKey; - } +// Pointer hashing policy that uses HashGeneric() to create good hashes for +// pointers. Note that we don't shift out the lowest k bits to generate a +// good distribution for arena allocated pointers. +template +struct PointerHasher { + typedef Key Lookup; + static HashNumber hash(const Lookup& l) { + size_t word = reinterpret_cast(l); + return mozilla::HashGeneric(word); + } + static bool match(const Key& k, const Lookup& l) { return k == l; } + static void rekey(Key& k, const Key& newKey) { k = newKey; } }; // Default hash policy: just use the 'lookup' value. This of course only @@ -600,87 +591,78 @@ // the result of the 'hash' which means that it is 'ok' if the lookup value is // not well distributed over the HashNumber domain. template -struct DefaultHasher -{ - typedef Key Lookup; - static HashNumber hash(const Lookup& l) { - // Hash if can implicitly cast to hash number type. - return l; - } - static bool match(const Key& k, const Lookup& l) { - // Use builtin or overloaded operator==. - return k == l; - } - static void rekey(Key& k, const Key& newKey) { - k = newKey; - } +struct DefaultHasher { + typedef Key Lookup; + static HashNumber hash(const Lookup& l) { + // Hash if can implicitly cast to hash number type. + return l; + } + static bool match(const Key& k, const Lookup& l) { + // Use builtin or overloaded operator==. + return k == l; + } + static void rekey(Key& k, const Key& newKey) { k = newKey; } }; // Specialize hashing policy for pointer types. It assumes that the type is // at least word-aligned. For types with smaller size use PointerHasher. template -struct DefaultHasher : PointerHasher::value> -{}; +struct DefaultHasher : PointerHasher {}; // Specialize hashing policy for mozilla::UniquePtr to proxy the UniquePtr's // raw pointer to PointerHasher. template -struct DefaultHasher> -{ - using Lookup = mozilla::UniquePtr; - using PtrHasher = PointerHasher::value>; - - static HashNumber hash(const Lookup& l) { - return PtrHasher::hash(l.get()); - } - static bool match(const mozilla::UniquePtr& k, const Lookup& l) { - return PtrHasher::match(k.get(), l.get()); - } - static void rekey(mozilla::UniquePtr& k, mozilla::UniquePtr&& newKey) { - k = mozilla::Move(newKey); - } +struct DefaultHasher> { + using Lookup = mozilla::UniquePtr; + using PtrHasher = PointerHasher; + + static HashNumber hash(const Lookup& l) { return PtrHasher::hash(l.get()); } + static bool match(const mozilla::UniquePtr& k, const Lookup& l) { + return PtrHasher::match(k.get(), l.get()); + } + static void rekey(mozilla::UniquePtr& k, + mozilla::UniquePtr&& newKey) { + k = mozilla::Move(newKey); + } }; // For doubles, we can xor the two uint32s. template <> -struct DefaultHasher -{ - typedef double Lookup; - static HashNumber hash(double d) { - static_assert(sizeof(HashNumber) == 4, - "subsequent code assumes a four-byte hash"); - uint64_t u = mozilla::BitwiseCast(d); - return HashNumber(u ^ (u >> 32)); - } - static bool match(double lhs, double rhs) { - return mozilla::BitwiseCast(lhs) == mozilla::BitwiseCast(rhs); - } +struct DefaultHasher { + typedef double Lookup; + static HashNumber hash(double d) { + static_assert(sizeof(HashNumber) == 4, + "subsequent code assumes a four-byte hash"); + uint64_t u = mozilla::BitwiseCast(d); + return HashNumber(u ^ (u >> 32)); + } + static bool match(double lhs, double rhs) { + return mozilla::BitwiseCast(lhs) == + mozilla::BitwiseCast(rhs); + } }; template <> -struct DefaultHasher -{ - typedef float Lookup; - static HashNumber hash(float f) { - static_assert(sizeof(HashNumber) == 4, - "subsequent code assumes a four-byte hash"); - return HashNumber(mozilla::BitwiseCast(f)); - } - static bool match(float lhs, float rhs) { - return mozilla::BitwiseCast(lhs) == mozilla::BitwiseCast(rhs); - } +struct DefaultHasher { + typedef float Lookup; + static HashNumber hash(float f) { + static_assert(sizeof(HashNumber) == 4, + "subsequent code assumes a four-byte hash"); + return HashNumber(mozilla::BitwiseCast(f)); + } + static bool match(float lhs, float rhs) { + return mozilla::BitwiseCast(lhs) == + mozilla::BitwiseCast(rhs); + } }; // A hash policy that compares C strings. -struct CStringHasher -{ - typedef const char* Lookup; - static js::HashNumber hash(Lookup l) { - return mozilla::HashString(l); - } - static bool match(const char* key, Lookup lookup) { - return strcmp(key, lookup) == 0; - } +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. @@ -692,27 +674,32 @@ // 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; } +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)); +static bool HasHash(Lookup&& l) { + return FallibleHashMethods::hasHash( + mozilla::Forward(l)); } template -static bool -EnsureHash(Lookup&& l) { - return FallibleHashMethods::ensureHash(mozilla::Forward(l)); +static bool EnsureHash(Lookup&& l) { + return FallibleHashMethods::ensureHash( + mozilla::Forward(l)); } /*****************************************************************************/ @@ -723,58 +710,56 @@ // HashTable directly. template -class HashMapEntry -{ - Key key_; - Value value_; - - template friend class detail::HashTable; - template friend class detail::HashTableEntry; - template friend class HashMap; - - public: - template - HashMapEntry(KeyInput&& k, ValueInput&& v) +class HashMapEntry { + Key key_; + Value value_; + + template + friend class detail::HashTable; + template + friend class detail::HashTableEntry; + template + friend class HashMap; + + public: + template + HashMapEntry(KeyInput&& k, ValueInput&& v) : key_(mozilla::Forward(k)), - value_(mozilla::Forward(v)) - {} + value_(mozilla::Forward(v)) {} - HashMapEntry(HashMapEntry&& rhs) - : key_(mozilla::Move(rhs.key_)), - value_(mozilla::Move(rhs.value_)) - {} - - void operator=(HashMapEntry&& rhs) { - key_ = mozilla::Move(rhs.key_); - value_ = mozilla::Move(rhs.value_); - } - - typedef Key KeyType; - typedef Value ValueType; + HashMapEntry(HashMapEntry&& rhs) + : key_(mozilla::Move(rhs.key_)), value_(mozilla::Move(rhs.value_)) {} - const Key& key() const { return key_; } - Key& mutableKey() { return key_; } - const Value& value() const { return value_; } - Value& value() { return value_; } - - private: - HashMapEntry(const HashMapEntry&) = delete; - void operator=(const HashMapEntry&) = delete; + void operator=(HashMapEntry&& rhs) { + key_ = mozilla::Move(rhs.key_); + value_ = mozilla::Move(rhs.value_); + } + + typedef Key KeyType; + typedef Value ValueType; + + const Key& key() const { return key_; } + Key& mutableKey() { return key_; } + const Value& value() const { return value_; } + Value& value() { return value_; } + + private: + HashMapEntry(const HashMapEntry&) = delete; + void operator=(const HashMapEntry&) = delete; }; -} // namespace js +} // namespace js namespace mozilla { template -struct IsPod > : IsPod {}; +struct IsPod> : IsPod {}; template -struct IsPod > - : IntegralConstant::value && IsPod::value> -{}; +struct IsPod> + : IntegralConstant::value && IsPod::value> {}; -} // namespace mozilla +} // namespace mozilla namespace js { @@ -784,1097 +769,1054 @@ class HashTable; template -class HashTableEntry -{ - template friend class HashTable; - typedef typename mozilla::RemoveConst::Type NonConstT; - - HashNumber keyHash; - mozilla::AlignedStorage2 mem; - - static const HashNumber sFreeKey = 0; - static const HashNumber sRemovedKey = 1; - static const HashNumber sCollisionBit = 1; - - static bool isLiveHash(HashNumber hash) - { - return hash > sRemovedKey; - } - - HashTableEntry(const HashTableEntry&) = delete; - void operator=(const HashTableEntry&) = delete; - ~HashTableEntry() = delete; - - public: - // NB: HashTableEntry is treated as a POD: no constructor or destructor calls. - - void destroyIfLive() { - if (isLive()) - mem.addr()->~T(); - } - - void destroy() { - MOZ_ASSERT(isLive()); - mem.addr()->~T(); - } - - void swap(HashTableEntry* other) { - if (this == other) - return; - MOZ_ASSERT(isLive()); - if (other->isLive()) { - mozilla::Swap(*mem.addr(), *other->mem.addr()); - } else { - *other->mem.addr() = mozilla::Move(*mem.addr()); - destroy(); - } - mozilla::Swap(keyHash, other->keyHash); - } - - T& get() { MOZ_ASSERT(isLive()); return *mem.addr(); } - NonConstT& getMutable() { MOZ_ASSERT(isLive()); return *mem.addr(); } - - bool isFree() const { return keyHash == sFreeKey; } - void clearLive() { MOZ_ASSERT(isLive()); keyHash = sFreeKey; mem.addr()->~T(); } - void clear() { if (isLive()) mem.addr()->~T(); keyHash = sFreeKey; } - bool isRemoved() const { return keyHash == sRemovedKey; } - void removeLive() { MOZ_ASSERT(isLive()); keyHash = sRemovedKey; mem.addr()->~T(); } - bool isLive() const { return isLiveHash(keyHash); } - void setCollision() { MOZ_ASSERT(isLive()); keyHash |= sCollisionBit; } - void unsetCollision() { keyHash &= ~sCollisionBit; } - bool hasCollision() const { return keyHash & sCollisionBit; } - bool matchHash(HashNumber hn) { return (keyHash & ~sCollisionBit) == hn; } - HashNumber getKeyHash() const { return keyHash & ~sCollisionBit; } - - template - void setLive(HashNumber hn, Args&&... args) - { - MOZ_ASSERT(!isLive()); - keyHash = hn; - new(mem.addr()) T(mozilla::Forward(args)...); - MOZ_ASSERT(isLive()); - } +class HashTableEntry { + template + friend class HashTable; + typedef typename mozilla::RemoveConst::Type NonConstT; + + HashNumber keyHash; + mozilla::AlignedStorage2 mem; + + static const HashNumber sFreeKey = 0; + static const HashNumber sRemovedKey = 1; + static const HashNumber sCollisionBit = 1; + + static bool isLiveHash(HashNumber hash) { return hash > sRemovedKey; } + + HashTableEntry(const HashTableEntry&) = delete; + void operator=(const HashTableEntry&) = delete; + ~HashTableEntry() = delete; + + public: + // NB: HashTableEntry is treated as a POD: no constructor or destructor calls. + + void destroyIfLive() { + if (isLive()) mem.addr()->~T(); + } + + void destroy() { + MOZ_ASSERT(isLive()); + mem.addr()->~T(); + } + + void swap(HashTableEntry* other) { + if (this == other) return; + MOZ_ASSERT(isLive()); + if (other->isLive()) { + mozilla::Swap(*mem.addr(), *other->mem.addr()); + } else { + *other->mem.addr() = mozilla::Move(*mem.addr()); + destroy(); + } + mozilla::Swap(keyHash, other->keyHash); + } + + T& get() { + MOZ_ASSERT(isLive()); + return *mem.addr(); + } + NonConstT& getMutable() { + MOZ_ASSERT(isLive()); + return *mem.addr(); + } + + bool isFree() const { return keyHash == sFreeKey; } + void clearLive() { + MOZ_ASSERT(isLive()); + keyHash = sFreeKey; + mem.addr()->~T(); + } + void clear() { + if (isLive()) mem.addr()->~T(); + keyHash = sFreeKey; + } + bool isRemoved() const { return keyHash == sRemovedKey; } + void removeLive() { + MOZ_ASSERT(isLive()); + keyHash = sRemovedKey; + mem.addr()->~T(); + } + bool isLive() const { return isLiveHash(keyHash); } + void setCollision() { + MOZ_ASSERT(isLive()); + keyHash |= sCollisionBit; + } + void unsetCollision() { keyHash &= ~sCollisionBit; } + bool hasCollision() const { return keyHash & sCollisionBit; } + bool matchHash(HashNumber hn) { return (keyHash & ~sCollisionBit) == hn; } + HashNumber getKeyHash() const { return keyHash & ~sCollisionBit; } + + template + void setLive(HashNumber hn, Args&&... args) { + MOZ_ASSERT(!isLive()); + keyHash = hn; + new (mem.addr()) T(mozilla::Forward(args)...); + MOZ_ASSERT(isLive()); + } }; template -class HashTable : private AllocPolicy -{ - friend class mozilla::ReentrancyGuard; - - typedef typename mozilla::RemoveConst::Type NonConstT; - typedef typename HashPolicy::KeyType Key; - typedef typename HashPolicy::Lookup Lookup; - - public: - typedef HashTableEntry Entry; - - // A nullable pointer to a hash table element. A Ptr |p| can be tested - // either explicitly |if (p.found()) p->...| or using boolean conversion - // |if (p) p->...|. Ptr objects must not be used after any mutating hash - // table operations unless |generation()| is tested. - class Ptr - { - friend class HashTable; - - Entry* entry_; -#ifdef JS_DEBUG - const HashTable* table_; - Generation generation; -#endif - - protected: - Ptr(Entry& entry, const HashTable& tableArg) - : entry_(&entry) -#ifdef JS_DEBUG - , table_(&tableArg) - , generation(tableArg.generation()) -#endif - {} - - public: - Ptr() - : entry_(nullptr) -#ifdef JS_DEBUG - , table_(nullptr) - , generation(0) -#endif - {} - - bool isValid() const { - return !entry_; - } +class HashTable : private AllocPolicy { + friend class mozilla::ReentrancyGuard; - bool found() const { - if (isValid()) - return false; -#ifdef JS_DEBUG - MOZ_ASSERT(generation == table_->generation()); -#endif - return entry_->isLive(); - } + typedef typename mozilla::RemoveConst::Type NonConstT; + typedef typename HashPolicy::KeyType Key; + typedef typename HashPolicy::Lookup Lookup; - explicit operator bool() const { - return found(); - } - - bool operator==(const Ptr& rhs) const { - MOZ_ASSERT(found() && rhs.found()); - return entry_ == rhs.entry_; - } + public: + typedef HashTableEntry Entry; - bool operator!=(const Ptr& rhs) const { -#ifdef JS_DEBUG - MOZ_ASSERT(generation == table_->generation()); -#endif - return !(*this == rhs); - } + // A nullable pointer to a hash table element. A Ptr |p| can be tested + // either explicitly |if (p.found()) p->...| or using boolean conversion + // |if (p) p->...|. Ptr objects must not be used after any mutating hash + // table operations unless |generation()| is tested. + class Ptr { + friend class HashTable; - T& operator*() const { + Entry* entry_; #ifdef JS_DEBUG - MOZ_ASSERT(found()); - MOZ_ASSERT(generation == table_->generation()); + const HashTable* table_; + Generation generation; #endif - return entry_->get(); - } - T* operator->() const { + protected: + Ptr(Entry& entry, const HashTable& tableArg) + : entry_(&entry) #ifdef JS_DEBUG - MOZ_ASSERT(found()); - MOZ_ASSERT(generation == table_->generation()); + , + table_(&tableArg), + generation(tableArg.generation()) #endif - return &entry_->get(); - } - }; - - // A Ptr that can be used to add a key after a failed lookup. - class AddPtr : public Ptr { - friend class HashTable; - HashNumber keyHash; -#ifdef JS_DEBUG - uint64_t mutationCount; -#endif + } - AddPtr(Entry& entry, const HashTable& tableArg, HashNumber hn) - : Ptr(entry, tableArg) - , keyHash(hn) + public: + Ptr() + : entry_(nullptr) #ifdef JS_DEBUG - , mutationCount(tableArg.mutationCount) + , + table_(nullptr), + generation(0) #endif - {} - - public: - AddPtr() : keyHash(0) {} - }; - - // A collection of hash table entries. The collection is enumerated by - // calling |front()| followed by |popFront()| as long as |!empty()|. As - // with Ptr/AddPtr, Range objects must not be used after any mutating hash - // table operation unless the |generation()| is tested. - class Range { - protected: - friend class HashTable; + } - Range(const HashTable& tableArg, Entry* c, Entry* e) - : cur(c) - , end(e) -#ifdef JS_DEBUG - , table_(&tableArg) - , mutationCount(tableArg.mutationCount) - , generation(tableArg.generation()) - , validEntry(true) -#endif - { - while (cur < end && !cur->isLive()) - ++cur; - } + bool isValid() const { return !!entry_; } - Entry* cur; - Entry* end; + bool found() const { + if (!isValid()) return false; #ifdef JS_DEBUG - const HashTable* table_; - uint64_t mutationCount; - Generation generation; - bool validEntry; + MOZ_ASSERT(generation == table_->generation()); #endif + return entry_->isLive(); + } - public: - Range() - : cur(nullptr) - , end(nullptr) -#ifdef JS_DEBUG - , table_(nullptr) - , mutationCount(0) - , generation(0) - , validEntry(false) -#endif - {} + explicit operator bool() const { return found(); } - bool empty() const { -#ifdef JS_DEBUG - MOZ_ASSERT(generation == table_->generation()); - MOZ_ASSERT(mutationCount == table_->mutationCount); -#endif - return cur == end; - } + bool operator==(const Ptr& rhs) const { + MOZ_ASSERT(found() && rhs.found()); + return entry_ == rhs.entry_; + } - T& front() const { - MOZ_ASSERT(!empty()); + bool operator!=(const Ptr& rhs) const { #ifdef JS_DEBUG - MOZ_ASSERT(validEntry); - MOZ_ASSERT(generation == table_->generation()); - MOZ_ASSERT(mutationCount == table_->mutationCount); + MOZ_ASSERT(generation == table_->generation()); #endif - return cur->get(); - } + return !(*this == rhs); + } - void popFront() { - MOZ_ASSERT(!empty()); -#ifdef JS_DEBUG - MOZ_ASSERT(generation == table_->generation()); - MOZ_ASSERT(mutationCount == table_->mutationCount); -#endif - while (++cur < end && !cur->isLive()) - continue; + T& operator*() const { #ifdef JS_DEBUG - validEntry = true; + MOZ_ASSERT(found()); + MOZ_ASSERT(generation == table_->generation()); #endif - } - }; - - // A Range whose lifetime delimits a mutating enumeration of a hash table. - // Since rehashing when elements were removed during enumeration would be - // bad, it is postponed until the Enum is destructed. Since the Enum's - // destructor touches the hash table, the user must ensure that the hash - // table is still alive when the destructor runs. - class Enum : public Range - { - friend class HashTable; + return entry_->get(); + } - HashTable& table_; - bool rekeyed; - bool removed; - - /* Not copyable. */ - Enum(const Enum&) = delete; - void operator=(const Enum&) = delete; - - public: - template explicit - Enum(Map& map) : Range(map.all()), table_(map.impl), rekeyed(false), removed(false) {} - - // Removes the |front()| element from the table, leaving |front()| - // invalid until the next call to |popFront()|. For example: - // - // HashSet s; - // for (HashSet::Enum e(s); !e.empty(); e.popFront()) - // if (e.front() == 42) - // e.removeFront(); - void removeFront() { - table_.remove(*this->cur); - removed = true; + T* operator->() const { #ifdef JS_DEBUG - this->validEntry = false; - this->mutationCount = table_.mutationCount; + MOZ_ASSERT(found()); + MOZ_ASSERT(generation == table_->generation()); #endif - } + return &entry_->get(); + } + }; - NonConstT& mutableFront() { - MOZ_ASSERT(!this->empty()); + // A Ptr that can be used to add a key after a failed lookup. + class AddPtr : public Ptr { + friend class HashTable; + HashNumber keyHash; #ifdef JS_DEBUG - MOZ_ASSERT(this->validEntry); - MOZ_ASSERT(this->generation == this->Range::table_->generation()); - MOZ_ASSERT(this->mutationCount == this->Range::table_->mutationCount); + uint64_t mutationCount; #endif - return this->cur->getMutable(); - } - // Removes the |front()| element and re-inserts it into the table with - // a new key at the new Lookup position. |front()| is invalid after - // this operation until the next call to |popFront()|. - void rekeyFront(const Lookup& l, const Key& k) { - MOZ_ASSERT(&k != &HashPolicy::getKey(this->cur->get())); - Ptr p(*this->cur, table_); - table_.rekeyWithoutRehash(p, l, k); - rekeyed = true; + AddPtr(Entry& entry, const HashTable& tableArg, HashNumber hn) + : Ptr(entry, tableArg), + keyHash(hn) #ifdef JS_DEBUG - this->validEntry = false; - this->mutationCount = table_.mutationCount; -#endif - } - - void rekeyFront(const Key& k) { - rekeyFront(k, k); - } - - // Potentially rehashes the table. - ~Enum() { - if (rekeyed) { - table_.gen++; - table_.checkOverRemoved(); - } - - if (removed) - table_.compactIfUnderloaded(); - } - }; - - // HashTable is movable - HashTable(HashTable&& rhs) - : AllocPolicy(rhs) - { - mozilla::PodAssign(this, &rhs); - rhs.table = nullptr; - } - void operator=(HashTable&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - if (table) - destroyTable(*this, table, capacity()); - mozilla::PodAssign(this, &rhs); - rhs.table = nullptr; - } - - private: - // HashTable is not copyable or assignable - HashTable(const HashTable&) = delete; - void operator=(const HashTable&) = delete; - - private: - static const size_t CAP_BITS = 30; - - public: - uint64_t gen:56; // entry storage generation number - uint64_t hashShift:8; // multiplicative hash shift - Entry* table; // entry storage - uint32_t entryCount; // number of entries in table - uint32_t removedCount; // removed entry sentinels in table - -#ifdef JS_DEBUG - uint64_t mutationCount; - mutable bool mEntered; - // Note that some updates to these stats are not thread-safe. See the - // comment on the three-argument overloading of HashTable::lookup(). - mutable struct Stats - { - uint32_t searches; // total number of table searches - uint32_t steps; // hash chain links traversed - uint32_t hits; // searches that found key - uint32_t misses; // searches that didn't find key - uint32_t addOverRemoved; // adds that recycled a removed entry - uint32_t removes; // calls to remove - uint32_t removeFrees; // calls to remove that freed the entry - uint32_t grows; // table expansions - uint32_t shrinks; // table contractions - uint32_t compresses; // table compressions - uint32_t rehashes; // tombstone decontaminations - } stats; -# define METER(x) x -#else -# define METER(x) + , + mutationCount(tableArg.mutationCount) #endif - - // The default initial capacity is 32 (enough to hold 16 elements), but it - // can be as low as 4. - static const unsigned sMinCapacityLog2 = 2; - static const unsigned sMinCapacity = 1 << sMinCapacityLog2; - static const unsigned sMaxInit = JS_BIT(CAP_BITS - 1); - static const unsigned sMaxCapacity = JS_BIT(CAP_BITS); - static const unsigned sHashBits = mozilla::tl::BitSize::value; - - // Hash-table alpha is conceptually a fraction, but to avoid floating-point - // math we implement it as a ratio of integers. - static const uint8_t sAlphaDenominator = 4; - static const uint8_t sMinAlphaNumerator = 1; // min alpha: 1/4 - static const uint8_t sMaxAlphaNumerator = 3; // max alpha: 3/4 - - static const HashNumber sFreeKey = Entry::sFreeKey; - static const HashNumber sRemovedKey = Entry::sRemovedKey; - static const HashNumber sCollisionBit = Entry::sCollisionBit; - - void setTableSizeLog2(unsigned sizeLog2) - { - hashShift = sHashBits - sizeLog2; - } - - static bool isLiveHash(HashNumber hash) - { - return Entry::isLiveHash(hash); - } - - static HashNumber prepareHash(const Lookup& l) { - HashNumber keyHash = ScrambleHashCode(HashPolicy::hash(l)); - - // Avoid reserved hash codes. - if (!isLiveHash(keyHash)) - keyHash -= (sRemovedKey + 1); - return keyHash & ~sCollisionBit; } - enum FailureBehavior { DontReportFailure = false, ReportFailure = true }; + public: + AddPtr() : keyHash(0) {} + }; - static Entry* createTable(AllocPolicy& alloc, uint32_t capacity, - FailureBehavior reportFailure = ReportFailure) - { - static_assert(sFreeKey == 0, - "newly-calloc'd tables have to be considered empty"); - if (reportFailure) - return alloc.template pod_calloc(capacity); - - return alloc.template maybe_pod_calloc(capacity); - } - - static Entry* maybeCreateTable(AllocPolicy& alloc, uint32_t capacity) - { - static_assert(sFreeKey == 0, - "newly-calloc'd tables have to be considered empty"); - return alloc.template maybe_pod_calloc(capacity); - } + // A collection of hash table entries. The collection is enumerated by + // calling |front()| followed by |popFront()| as long as |!empty()|. As + // with Ptr/AddPtr, Range objects must not be used after any mutating hash + // table operation unless the |generation()| is tested. + class Range { + protected: + friend class HashTable; - static void destroyTable(AllocPolicy& alloc, Entry* oldTable, uint32_t capacity) - { - Entry* end = oldTable + capacity; - for (Entry* e = oldTable; e < end; ++e) - e->destroyIfLive(); - alloc.free_(oldTable); - } - - public: - explicit HashTable(AllocPolicy ap) - : AllocPolicy(ap) - , gen(0) - , hashShift(sHashBits) - , table(nullptr) - , entryCount(0) - , removedCount(0) + Range(const HashTable& tableArg, Entry* c, Entry* e) + : cur(c), + end(e) #ifdef JS_DEBUG - , mutationCount(0) - , mEntered(false) + , + table_(&tableArg), + mutationCount(tableArg.mutationCount), + generation(tableArg.generation()), + validEntry(true) #endif - {} - - MOZ_MUST_USE bool init(uint32_t length) - { - MOZ_ASSERT(!initialized()); - - // Reject all lengths whose initial computed capacity would exceed - // sMaxCapacity. Round that maximum length down to the nearest power - // of two for speedier code. - if (MOZ_UNLIKELY(length > sMaxInit)) { - this->reportAllocOverflow(); - return false; - } - - static_assert((sMaxInit * sAlphaDenominator) / sAlphaDenominator == sMaxInit, - "multiplication in numerator below could overflow"); - static_assert(sMaxInit * sAlphaDenominator <= UINT32_MAX - sMaxAlphaNumerator, - "numerator calculation below could potentially overflow"); - - // Compute the smallest capacity allowing |length| elements to be - // inserted without rehashing: ceil(length / max-alpha). (Ceiling - // integral division: .) - uint32_t newCapacity = - (length * sAlphaDenominator + sMaxAlphaNumerator - 1) / sMaxAlphaNumerator; - if (newCapacity < sMinCapacity) - newCapacity = sMinCapacity; - - // FIXME: use JS_CEILING_LOG2 when PGO stops crashing (bug 543034). - uint32_t roundUp = sMinCapacity, roundUpLog2 = sMinCapacityLog2; - while (roundUp < newCapacity) { - roundUp <<= 1; - ++roundUpLog2; - } - - newCapacity = roundUp; - MOZ_ASSERT(newCapacity >= length); - MOZ_ASSERT(newCapacity <= sMaxCapacity); - - table = createTable(*this, newCapacity); - if (!table) - return false; - - setTableSizeLog2(roundUpLog2); - METER(memset(&stats, 0, sizeof(stats))); - return true; - } - - bool initialized() const - { - return !!table; - } - - ~HashTable() - { - if (table) - destroyTable(*this, table, capacity()); - } - - private: - HashNumber hash1(HashNumber hash0) const { - return hash0 >> hashShift; + while (cur < end && !cur->isLive()) ++cur; } - struct DoubleHash - { - HashNumber h2; - HashNumber sizeMask; - }; - - DoubleHash hash2(HashNumber curKeyHash) const - { - unsigned sizeLog2 = sHashBits - hashShift; - DoubleHash dh = { - ((curKeyHash << sizeLog2) >> hashShift) | 1, - (HashNumber(1) << sizeLog2) - 1 - }; - return dh; - } - - static HashNumber applyDoubleHash(HashNumber h1, const DoubleHash& dh) - { - return (h1 - dh.h2) & dh.sizeMask; - } - - bool overloaded() - { - static_assert(sMaxCapacity <= UINT32_MAX / sMaxAlphaNumerator, - "multiplication below could overflow"); - return entryCount + removedCount >= - capacity() * sMaxAlphaNumerator / sAlphaDenominator; - } - - // Would the table be underloaded if it had the given capacity and entryCount? - static bool wouldBeUnderloaded(uint32_t capacity, uint32_t entryCount) - { - static_assert(sMaxCapacity <= UINT32_MAX / sMinAlphaNumerator, - "multiplication below could overflow"); - return capacity > sMinCapacity && - entryCount <= capacity * sMinAlphaNumerator / sAlphaDenominator; - } - - bool underloaded() - { - return wouldBeUnderloaded(capacity(), entryCount); - } - - static bool match(Entry& e, const Lookup& l) - { - return HashPolicy::match(HashPolicy::getKey(e.get()), l); - } - - // Warning: in order for readonlyThreadsafeLookup() to be safe this - // function must not modify the table in any way when |collisionBit| is 0. - // (The use of the METER() macro to increment stats violates this - // restriction but we will live with that for now because it's enabled so - // rarely.) - Entry& lookup(const Lookup& l, HashNumber keyHash, unsigned collisionBit) const - { - MOZ_ASSERT(isLiveHash(keyHash)); - MOZ_ASSERT(!(keyHash & sCollisionBit)); - MOZ_ASSERT(collisionBit == 0 || collisionBit == sCollisionBit); - MOZ_ASSERT(table); - METER(stats.searches++); - - // Compute the primary hash address. - HashNumber h1 = hash1(keyHash); - Entry* entry = &table[h1]; - - // Miss: return space for a new entry. - if (entry->isFree()) { - METER(stats.misses++); - return *entry; - } - - // Hit: return entry. - if (entry->matchHash(keyHash) && match(*entry, l)) { - METER(stats.hits++); - return *entry; - } - - // Collision: double hash. - DoubleHash dh = hash2(keyHash); - - // Save the first removed entry pointer so we can recycle later. - Entry* firstRemoved = nullptr; - - while (true) { - if (MOZ_UNLIKELY(entry->isRemoved())) { - if (!firstRemoved) - firstRemoved = entry; - } else { - if (collisionBit == sCollisionBit) - entry->setCollision(); - } - - METER(stats.steps++); - h1 = applyDoubleHash(h1, dh); - - entry = &table[h1]; - if (entry->isFree()) { - METER(stats.misses++); - return firstRemoved ? *firstRemoved : *entry; - } - - if (entry->matchHash(keyHash) && match(*entry, l)) { - METER(stats.hits++); - return *entry; - } - } - } - - // This is a copy of lookup hardcoded to the assumptions: - // 1. the lookup is a lookupForAdd - // 2. the key, whose |keyHash| has been passed is not in the table, - // 3. no entries have been removed from the table. - // This specialized search avoids the need for recovering lookup values - // from entries, which allows more flexible Lookup/Key types. - Entry& findFreeEntry(HashNumber keyHash) - { - MOZ_ASSERT(!(keyHash & sCollisionBit)); - MOZ_ASSERT(table); - METER(stats.searches++); - - // We assume 'keyHash' has already been distributed. - - // Compute the primary hash address. - HashNumber h1 = hash1(keyHash); - Entry* entry = &table[h1]; - - // Miss: return space for a new entry. - if (!entry->isLive()) { - METER(stats.misses++); - return *entry; - } - - // Collision: double hash. - DoubleHash dh = hash2(keyHash); - - while (true) { - MOZ_ASSERT(!entry->isRemoved()); - entry->setCollision(); - - METER(stats.steps++); - h1 = applyDoubleHash(h1, dh); - - entry = &table[h1]; - if (!entry->isLive()) { - METER(stats.misses++); - return *entry; - } - } - } - - enum RebuildStatus { NotOverloaded, Rehashed, RehashFailed }; - - RebuildStatus changeTableSize(int deltaLog2, FailureBehavior reportFailure = ReportFailure) - { - // Look, but don't touch, until we succeed in getting new entry store. - Entry* oldTable = table; - uint32_t oldCap = capacity(); - uint32_t newLog2 = sHashBits - hashShift + deltaLog2; - uint32_t newCapacity = JS_BIT(newLog2); - if (MOZ_UNLIKELY(newCapacity > sMaxCapacity)) { - if (reportFailure) - this->reportAllocOverflow(); - return RehashFailed; - } - - Entry* newTable = createTable(*this, newCapacity, reportFailure); - if (!newTable) - return RehashFailed; - - // We can't fail from here on, so update table parameters. - setTableSizeLog2(newLog2); - removedCount = 0; - gen++; - table = newTable; - - // Copy only live entries, leaving removed ones behind. - Entry* end = oldTable + oldCap; - for (Entry* src = oldTable; src < end; ++src) { - if (src->isLive()) { - HashNumber hn = src->getKeyHash(); - findFreeEntry(hn).setLive( - hn, mozilla::Move(const_cast(src->get()))); - src->destroy(); - } - } - - // All entries have been destroyed, no need to destroyTable. - this->free_(oldTable); - return Rehashed; - } - - bool shouldCompressTable() - { - // Compress if a quarter or more of all entries are removed. - return removedCount >= (capacity() >> 2); - } - - RebuildStatus checkOverloaded(FailureBehavior reportFailure = ReportFailure) - { - if (!overloaded()) - return NotOverloaded; - - int deltaLog2; - if (shouldCompressTable()) { - METER(stats.compresses++); - deltaLog2 = 0; - } else { - METER(stats.grows++); - deltaLog2 = 1; - } - - return changeTableSize(deltaLog2, reportFailure); - } - - // Infallibly rehash the table if we are overloaded with removals. - void checkOverRemoved() - { - if (overloaded()) { - if (checkOverloaded(DontReportFailure) == RehashFailed) - rehashTableInPlace(); - } - } - - void remove(Entry& e) - { - MOZ_ASSERT(table); - METER(stats.removes++); - - if (e.hasCollision()) { - e.removeLive(); - removedCount++; - } else { - METER(stats.removeFrees++); - e.clearLive(); - } - entryCount--; + Entry* cur; + Entry* end; #ifdef JS_DEBUG - mutationCount++; + const HashTable* table_; + uint64_t mutationCount; + Generation generation; + bool validEntry; #endif - } - - void checkUnderloaded() - { - if (underloaded()) { - METER(stats.shrinks++); - (void) changeTableSize(-1, DontReportFailure); - } - } - - // Resize the table down to the largest capacity which doesn't underload the - // table. Since we call checkUnderloaded() on every remove, you only need - // to call this after a bulk removal of items done without calling remove(). - void compactIfUnderloaded() - { - int32_t resizeLog2 = 0; - uint32_t newCapacity = capacity(); - while (wouldBeUnderloaded(newCapacity, entryCount)) { - newCapacity = newCapacity >> 1; - resizeLog2--; - } - - if (resizeLog2 != 0) - (void) changeTableSize(resizeLog2, DontReportFailure); - } - // This is identical to changeTableSize(currentSize), but without requiring - // a second table. We do this by recycling the collision bits to tell us if - // the element is already inserted or still waiting to be inserted. Since - // already-inserted elements win any conflicts, we get the same table as we - // would have gotten through random insertion order. - void rehashTableInPlace() + public: + Range() + : cur(nullptr), + end(nullptr) +#ifdef JS_DEBUG + , + table_(nullptr), + mutationCount(0), + generation(0), + validEntry(false) +#endif { - METER(stats.rehashes++); - removedCount = 0; - for (size_t i = 0; i < capacity(); ++i) - table[i].unsetCollision(); - - for (size_t i = 0; i < capacity();) { - Entry* src = &table[i]; - - if (!src->isLive() || src->hasCollision()) { - ++i; - continue; - } - - HashNumber keyHash = src->getKeyHash(); - HashNumber h1 = hash1(keyHash); - DoubleHash dh = hash2(keyHash); - Entry* tgt = &table[h1]; - while (true) { - if (!tgt->hasCollision()) { - src->swap(tgt); - tgt->setCollision(); - break; - } - - h1 = applyDoubleHash(h1, dh); - tgt = &table[h1]; - } - } - - // TODO: this algorithm leaves collision bits on *all* elements, even if - // they are on no collision path. We have the option of setting the - // collision bits correctly on a subsequent pass or skipping the rehash - // unless we are totally filled with tombstones: benchmark to find out - // which approach is best. } - // Note: |l| may be a reference to a piece of |u|, so this function - // must take care not to use |l| after moving |u|. - // - // Prefer to use putNewInfallible; this function does not check - // invariants. - template - void putNewInfallibleInternal(const Lookup& l, Args&&... args) - { - MOZ_ASSERT(table); - - HashNumber keyHash = prepareHash(l); - Entry* entry = &findFreeEntry(keyHash); - MOZ_ASSERT(entry); - - if (entry->isRemoved()) { - METER(stats.addOverRemoved++); - removedCount--; - keyHash |= sCollisionBit; - } - - entry->setLive(keyHash, mozilla::Forward(args)...); - entryCount++; + bool empty() const { #ifdef JS_DEBUG - mutationCount++; + MOZ_ASSERT(generation == table_->generation()); + MOZ_ASSERT(mutationCount == table_->mutationCount); #endif + return cur == end; } - public: - void clear() - { - if (mozilla::IsPod::value) { - memset(table, 0, sizeof(*table) * capacity()); - } else { - uint32_t tableCapacity = capacity(); - Entry* end = table + tableCapacity; - for (Entry* e = table; e < end; ++e) - e->clear(); - } - removedCount = 0; - entryCount = 0; + T& front() const { + MOZ_ASSERT(!empty()); #ifdef JS_DEBUG - mutationCount++; + MOZ_ASSERT(validEntry); + MOZ_ASSERT(generation == table_->generation()); + MOZ_ASSERT(mutationCount == table_->mutationCount); #endif + return cur->get(); } - void finish() - { + void popFront() { + MOZ_ASSERT(!empty()); #ifdef JS_DEBUG - MOZ_ASSERT(!mEntered); + MOZ_ASSERT(generation == table_->generation()); + MOZ_ASSERT(mutationCount == table_->mutationCount); #endif - if (!table) - return; - - destroyTable(*this, table, capacity()); - table = nullptr; - gen++; - entryCount = 0; - removedCount = 0; + while (++cur < end && !cur->isLive()) continue; #ifdef JS_DEBUG - mutationCount++; + validEntry = true; #endif } + }; - Range all() const - { - MOZ_ASSERT(table); - return Range(*this, table, table + capacity()); - } - - bool empty() const - { - MOZ_ASSERT(table); - return !entryCount; - } - - uint32_t count() const - { - MOZ_ASSERT(table); - return entryCount; - } - - uint32_t capacity() const - { - MOZ_ASSERT(table); - return JS_BIT(sHashBits - hashShift); - } - - Generation generation() const - { - MOZ_ASSERT(table); - return Generation(gen); - } - - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const - { - return mallocSizeOf(table); - } + // A Range whose lifetime delimits a mutating enumeration of a hash table. + // Since rehashing when elements were removed during enumeration would be + // bad, it is postponed until the Enum is destructed. Since the Enum's + // destructor touches the hash table, the user must ensure that the hash + // table is still alive when the destructor runs. + class Enum : public Range { + friend class HashTable; - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const - { - return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf); - } + HashTable& table_; + bool rekeyed; + bool removed; - 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); - } + // Enum is movable but not copyable. + Enum(const Enum&) = delete; + void operator=(const Enum&) = delete; - Ptr readonlyThreadsafeLookup(const Lookup& l) const - { - if (!HasHash(l)) - return Ptr(); - HashNumber keyHash = prepareHash(l); - return Ptr(lookup(l, keyHash, 0), *this); - } + public: + template + explicit Enum(Map& map) + : Range(map.all()), table_(map.impl), rekeyed(false), removed(false) {} - 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); - return p; + MOZ_IMPLICIT Enum(Enum&& other) + : Range(other), + table_(other.table_), + rekeyed(other.rekeyed), + removed(other.removed) { + other.rekeyed = false; + other.removed = false; } - template - 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()) { - if (!this->checkSimulatedOOM()) - return false; - METER(stats.addOverRemoved++); - removedCount--; - p.keyHash |= sCollisionBit; - } else { - // Preserve the validity of |p.entry_|. - RebuildStatus status = checkOverloaded(); - if (status == RehashFailed) - return false; - if (status == NotOverloaded && !this->checkSimulatedOOM()) - return false; - if (status == Rehashed) - p.entry_ = &findFreeEntry(p.keyHash); - } - - p.entry_->setLive(p.keyHash, mozilla::Forward(args)...); - entryCount++; -#ifdef JS_DEBUG - mutationCount++; - p.generation = generation(); - p.mutationCount = mutationCount; + // Removes the |front()| element from the table, leaving |front()| + // invalid until the next call to |popFront()|. For example: + // + // HashSet s; + // for (HashSet::Enum e(s); !e.empty(); e.popFront()) + // if (e.front() == 42) + // e.removeFront(); + void removeFront() { + table_.remove(*this->cur); + removed = true; +#ifdef JS_DEBUG + this->validEntry = false; + this->mutationCount = table_.mutationCount; +#endif + } + + NonConstT& mutableFront() { + MOZ_ASSERT(!this->empty()); +#ifdef JS_DEBUG + MOZ_ASSERT(this->validEntry); + MOZ_ASSERT(this->generation == this->Range::table_->generation()); + MOZ_ASSERT(this->mutationCount == this->Range::table_->mutationCount); +#endif + return this->cur->getMutable(); + } + + // Removes the |front()| element and re-inserts it into the table with + // a new key at the new Lookup position. |front()| is invalid after + // this operation until the next call to |popFront()|. + void rekeyFront(const Lookup& l, const Key& k) { + MOZ_ASSERT(&k != &HashPolicy::getKey(this->cur->get())); + Ptr p(*this->cur, table_); + table_.rekeyWithoutRehash(p, l, k); + rekeyed = true; +#ifdef JS_DEBUG + this->validEntry = false; + this->mutationCount = table_.mutationCount; +#endif + } + + void rekeyFront(const Key& k) { rekeyFront(k, k); } + + // Potentially rehashes the table. + ~Enum() { + if (rekeyed) { + table_.gen++; + table_.checkOverRemoved(); + } + + if (removed) table_.compactIfUnderloaded(); + } + }; + + // HashTable is movable + HashTable(HashTable&& rhs) : AllocPolicy(rhs) { + mozilla::PodAssign(this, &rhs); + rhs.table = nullptr; + } + void operator=(HashTable&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); + if (table) destroyTable(*this, table, capacity()); + mozilla::PodAssign(this, &rhs); + rhs.table = nullptr; + } + + private: + // HashTable is not copyable or assignable + HashTable(const HashTable&) = delete; + void operator=(const HashTable&) = delete; + + private: + static const size_t CAP_BITS = 30; + + public: + uint64_t gen : 56; // entry storage generation number + uint64_t hashShift : 8; // multiplicative hash shift + Entry* table; // entry storage + uint32_t entryCount; // number of entries in table + uint32_t removedCount; // removed entry sentinels in table + +#ifdef JS_DEBUG + uint64_t mutationCount; + mutable bool mEntered; + // Note that some updates to these stats are not thread-safe. See the + // comment on the three-argument overloading of HashTable::lookup(). + mutable struct Stats { + uint32_t searches; // total number of table searches + uint32_t steps; // hash chain links traversed + uint32_t hits; // searches that found key + uint32_t misses; // searches that didn't find key + uint32_t addOverRemoved; // adds that recycled a removed entry + uint32_t removes; // calls to remove + uint32_t removeFrees; // calls to remove that freed the entry + uint32_t grows; // table expansions + uint32_t shrinks; // table contractions + uint32_t compresses; // table compressions + uint32_t rehashes; // tombstone decontaminations + } stats; +#define METER(x) x +#else +#define METER(x) #endif - return true; - } - // Note: |l| may be a reference to a piece of |u|, so this function - // must take care not to use |l| after moving |u|. - template - void putNewInfallible(const Lookup& l, Args&&... args) - { - MOZ_ASSERT(!lookup(l).found()); - mozilla::ReentrancyGuard g(*this); - putNewInfallibleInternal(l, mozilla::Forward(args)...); - } - - // Note: |l| may be alias arguments in |args|, so this function must take - // care not to use |l| after moving |args|. - template - MOZ_MUST_USE bool putNew(const Lookup& l, Args&&... args) - { - if (!this->checkSimulatedOOM()) - return false; - - if (!EnsureHash(l)) - return false; - - if (checkOverloaded() == RehashFailed) - return false; - - putNewInfallible(l, mozilla::Forward(args)...); - return true; - } - - // Note: |l| may be a reference to a piece of |u|, so this function - // must take care not to use |l| after moving |u|. - template - MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, Args&&... args) - { - // Check for error from ensureHash() here. - if (p.isValid()) - return false; - -#ifdef JS_DEBUG - p.generation = generation(); - p.mutationCount = mutationCount; -#endif - { - mozilla::ReentrancyGuard g(*this); - MOZ_ASSERT(prepareHash(l) == p.keyHash); // l has not been destroyed - p.entry_ = &lookup(l, p.keyHash, sCollisionBit); - } - return p.found() || add(p, mozilla::Forward(args)...); - } - - void remove(Ptr p) - { - MOZ_ASSERT(table); - mozilla::ReentrancyGuard g(*this); - MOZ_ASSERT(p.found()); - remove(*p.entry_); - checkUnderloaded(); - } - - void rekeyWithoutRehash(Ptr p, const Lookup& l, const Key& k) - { - MOZ_ASSERT(table); - mozilla::ReentrancyGuard g(*this); - MOZ_ASSERT(p.found()); - typename HashTableEntry::NonConstT t(mozilla::Move(*p)); - HashPolicy::setKey(t, const_cast(k)); - remove(*p.entry_); - putNewInfallibleInternal(l, mozilla::Move(t)); - } + // The default initial capacity is 32 (enough to hold 16 elements), but it + // can be as low as 4. + static const unsigned sMinCapacityLog2 = 2; + static const unsigned sMinCapacity = 1 << sMinCapacityLog2; + static const unsigned sMaxInit = JS_BIT(CAP_BITS - 1); + static const unsigned sMaxCapacity = JS_BIT(CAP_BITS); + static const unsigned sHashBits = mozilla::tl::BitSize::value; + + // Hash-table alpha is conceptually a fraction, but to avoid floating-point + // math we implement it as a ratio of integers. + static const uint8_t sAlphaDenominator = 4; + static const uint8_t sMinAlphaNumerator = 1; // min alpha: 1/4 + static const uint8_t sMaxAlphaNumerator = 3; // max alpha: 3/4 + + static const HashNumber sFreeKey = Entry::sFreeKey; + static const HashNumber sRemovedKey = Entry::sRemovedKey; + static const HashNumber sCollisionBit = Entry::sCollisionBit; + + void setTableSizeLog2(unsigned sizeLog2) { hashShift = sHashBits - sizeLog2; } + + static bool isLiveHash(HashNumber hash) { return Entry::isLiveHash(hash); } + + static HashNumber prepareHash(const Lookup& l) { + HashNumber keyHash = ScrambleHashCode(HashPolicy::hash(l)); + + // Avoid reserved hash codes. + if (!isLiveHash(keyHash)) keyHash -= (sRemovedKey + 1); + return keyHash & ~sCollisionBit; + } + + enum FailureBehavior { DontReportFailure = false, ReportFailure = true }; + + static Entry* createTable(AllocPolicy& alloc, uint32_t capacity, + FailureBehavior reportFailure = ReportFailure) { + static_assert(sFreeKey == 0, + "newly-calloc'd tables have to be considered empty"); + if (reportFailure) return alloc.template pod_calloc(capacity); + + return alloc.template maybe_pod_calloc(capacity); + } + + static Entry* maybeCreateTable(AllocPolicy& alloc, uint32_t capacity) { + static_assert(sFreeKey == 0, + "newly-calloc'd tables have to be considered empty"); + return alloc.template maybe_pod_calloc(capacity); + } + + static void destroyTable(AllocPolicy& alloc, Entry* oldTable, + uint32_t capacity) { + Entry* end = oldTable + capacity; + for (Entry* e = oldTable; e < end; ++e) e->destroyIfLive(); + alloc.free_(oldTable); + } + + public: + explicit HashTable(AllocPolicy ap) + : AllocPolicy(ap), + gen(0), + hashShift(sHashBits), + table(nullptr), + entryCount(0), + removedCount(0) +#ifdef JS_DEBUG + , + mutationCount(0), + mEntered(false) +#endif + { + } + + MOZ_MUST_USE bool init(uint32_t length) { + MOZ_ASSERT(!initialized()); + + // Reject all lengths whose initial computed capacity would exceed + // sMaxCapacity. Round that maximum length down to the nearest power + // of two for speedier code. + if (MOZ_UNLIKELY(length > sMaxInit)) { + this->reportAllocOverflow(); + return false; + } + + static_assert( + (sMaxInit * sAlphaDenominator) / sAlphaDenominator == sMaxInit, + "multiplication in numerator below could overflow"); + static_assert( + sMaxInit * sAlphaDenominator <= UINT32_MAX - sMaxAlphaNumerator, + "numerator calculation below could potentially overflow"); + + // Compute the smallest capacity allowing |length| elements to be + // inserted without rehashing: ceil(length / max-alpha). (Ceiling + // integral division: .) + uint32_t newCapacity = + (length * sAlphaDenominator + sMaxAlphaNumerator - 1) / + sMaxAlphaNumerator; + if (newCapacity < sMinCapacity) newCapacity = sMinCapacity; + + // FIXME: use JS_CEILING_LOG2 when PGO stops crashing (bug 543034). + uint32_t roundUp = sMinCapacity, roundUpLog2 = sMinCapacityLog2; + while (roundUp < newCapacity) { + roundUp <<= 1; + ++roundUpLog2; + } + + newCapacity = roundUp; + MOZ_ASSERT(newCapacity >= length); + MOZ_ASSERT(newCapacity <= sMaxCapacity); + + table = createTable(*this, newCapacity); + if (!table) return false; + + setTableSizeLog2(roundUpLog2); + METER(memset(&stats, 0, sizeof(stats))); + return true; + } + + bool initialized() const { return !!table; } + + ~HashTable() { + if (table) destroyTable(*this, table, capacity()); + } + + private: + HashNumber hash1(HashNumber hash0) const { return hash0 >> hashShift; } + + struct DoubleHash { + HashNumber h2; + HashNumber sizeMask; + }; + + DoubleHash hash2(HashNumber curKeyHash) const { + unsigned sizeLog2 = sHashBits - hashShift; + DoubleHash dh = {((curKeyHash << sizeLog2) >> hashShift) | 1, + (HashNumber(1) << sizeLog2) - 1}; + return dh; + } + + static HashNumber applyDoubleHash(HashNumber h1, const DoubleHash& dh) { + return (h1 - dh.h2) & dh.sizeMask; + } + + bool overloaded() { + static_assert(sMaxCapacity <= UINT32_MAX / sMaxAlphaNumerator, + "multiplication below could overflow"); + return entryCount + removedCount >= + capacity() * sMaxAlphaNumerator / sAlphaDenominator; + } + + // Would the table be underloaded if it had the given capacity and entryCount? + static bool wouldBeUnderloaded(uint32_t capacity, uint32_t entryCount) { + static_assert(sMaxCapacity <= UINT32_MAX / sMinAlphaNumerator, + "multiplication below could overflow"); + return capacity > sMinCapacity && + entryCount <= capacity * sMinAlphaNumerator / sAlphaDenominator; + } + + bool underloaded() { return wouldBeUnderloaded(capacity(), entryCount); } + + static MOZ_ALWAYS_INLINE bool match(Entry& e, const Lookup& l) { + return HashPolicy::match(HashPolicy::getKey(e.get()), l); + } + + // Warning: in order for readonlyThreadsafeLookup() to be safe this + // function must not modify the table in any way when |collisionBit| is 0. + // (The use of the METER() macro to increment stats violates this + // restriction but we will live with that for now because it's enabled so + // rarely.) + MOZ_ALWAYS_INLINE Entry& lookup(const Lookup& l, HashNumber keyHash, + unsigned collisionBit) const { + MOZ_ASSERT(isLiveHash(keyHash)); + MOZ_ASSERT(!(keyHash & sCollisionBit)); + MOZ_ASSERT(collisionBit == 0 || collisionBit == sCollisionBit); + MOZ_ASSERT(table); + METER(stats.searches++); + + // Compute the primary hash address. + HashNumber h1 = hash1(keyHash); + Entry* entry = &table[h1]; + + // Miss: return space for a new entry. + if (entry->isFree()) { + METER(stats.misses++); + return *entry; + } + + // Hit: return entry. + if (entry->matchHash(keyHash) && match(*entry, l)) { + METER(stats.hits++); + return *entry; + } + + // Collision: double hash. + DoubleHash dh = hash2(keyHash); + + // Save the first removed entry pointer so we can recycle later. + Entry* firstRemoved = nullptr; + + while (true) { + if (MOZ_UNLIKELY(entry->isRemoved())) { + if (!firstRemoved) firstRemoved = entry; + } else { + if (collisionBit == sCollisionBit) entry->setCollision(); + } + + METER(stats.steps++); + h1 = applyDoubleHash(h1, dh); + + entry = &table[h1]; + if (entry->isFree()) { + METER(stats.misses++); + return firstRemoved ? *firstRemoved : *entry; + } + + if (entry->matchHash(keyHash) && match(*entry, l)) { + METER(stats.hits++); + return *entry; + } + } + } + + // This is a copy of lookup hardcoded to the assumptions: + // 1. the lookup is a lookupForAdd + // 2. the key, whose |keyHash| has been passed is not in the table, + // 3. no entries have been removed from the table. + // This specialized search avoids the need for recovering lookup values + // from entries, which allows more flexible Lookup/Key types. + Entry& findFreeEntry(HashNumber keyHash) { + MOZ_ASSERT(!(keyHash & sCollisionBit)); + MOZ_ASSERT(table); + METER(stats.searches++); + + // We assume 'keyHash' has already been distributed. + + // Compute the primary hash address. + HashNumber h1 = hash1(keyHash); + Entry* entry = &table[h1]; + + // Miss: return space for a new entry. + if (!entry->isLive()) { + METER(stats.misses++); + return *entry; + } + + // Collision: double hash. + DoubleHash dh = hash2(keyHash); + + while (true) { + MOZ_ASSERT(!entry->isRemoved()); + entry->setCollision(); + + METER(stats.steps++); + h1 = applyDoubleHash(h1, dh); + + entry = &table[h1]; + if (!entry->isLive()) { + METER(stats.misses++); + return *entry; + } + } + } + + enum RebuildStatus { NotOverloaded, Rehashed, RehashFailed }; + + RebuildStatus changeTableSize(int deltaLog2, + FailureBehavior reportFailure = ReportFailure) { + // Look, but don't touch, until we succeed in getting new entry store. + Entry* oldTable = table; + uint32_t oldCap = capacity(); + uint32_t newLog2 = sHashBits - hashShift + deltaLog2; + uint32_t newCapacity = JS_BIT(newLog2); + if (MOZ_UNLIKELY(newCapacity > sMaxCapacity)) { + if (reportFailure) this->reportAllocOverflow(); + return RehashFailed; + } + + Entry* newTable = createTable(*this, newCapacity, reportFailure); + if (!newTable) return RehashFailed; + + // We can't fail from here on, so update table parameters. + setTableSizeLog2(newLog2); + removedCount = 0; + gen++; + table = newTable; + + // Copy only live entries, leaving removed ones behind. + Entry* end = oldTable + oldCap; + for (Entry* src = oldTable; src < end; ++src) { + if (src->isLive()) { + HashNumber hn = src->getKeyHash(); + findFreeEntry(hn).setLive( + hn, + mozilla::Move(const_cast(src->get()))); + src->destroy(); + } + } + + // All entries have been destroyed, no need to destroyTable. + this->free_(oldTable); + return Rehashed; + } + + bool shouldCompressTable() { + // Compress if a quarter or more of all entries are removed. + return removedCount >= (capacity() >> 2); + } + + RebuildStatus checkOverloaded(FailureBehavior reportFailure = ReportFailure) { + if (!overloaded()) return NotOverloaded; + + int deltaLog2; + if (shouldCompressTable()) { + METER(stats.compresses++); + deltaLog2 = 0; + } else { + METER(stats.grows++); + deltaLog2 = 1; + } + + return changeTableSize(deltaLog2, reportFailure); + } + + // Infallibly rehash the table if we are overloaded with removals. + void checkOverRemoved() { + if (overloaded()) { + if (checkOverloaded(DontReportFailure) == RehashFailed) + rehashTableInPlace(); + } + } + + void remove(Entry& e) { + MOZ_ASSERT(table); + METER(stats.removes++); + + if (e.hasCollision()) { + e.removeLive(); + removedCount++; + } else { + METER(stats.removeFrees++); + e.clearLive(); + } + entryCount--; +#ifdef JS_DEBUG + mutationCount++; +#endif + } + + void checkUnderloaded() { + if (underloaded()) { + METER(stats.shrinks++); + (void)changeTableSize(-1, DontReportFailure); + } + } + + // Resize the table down to the largest capacity which doesn't underload the + // table. Since we call checkUnderloaded() on every remove, you only need + // to call this after a bulk removal of items done without calling remove(). + void compactIfUnderloaded() { + int32_t resizeLog2 = 0; + uint32_t newCapacity = capacity(); + while (wouldBeUnderloaded(newCapacity, entryCount)) { + newCapacity = newCapacity >> 1; + resizeLog2--; + } + + if (resizeLog2 != 0) (void)changeTableSize(resizeLog2, DontReportFailure); + } + + // This is identical to changeTableSize(currentSize), but without requiring + // a second table. We do this by recycling the collision bits to tell us if + // the element is already inserted or still waiting to be inserted. Since + // already-inserted elements win any conflicts, we get the same table as we + // would have gotten through random insertion order. + void rehashTableInPlace() { + METER(stats.rehashes++); + removedCount = 0; + gen++; + for (size_t i = 0; i < capacity(); ++i) table[i].unsetCollision(); + + for (size_t i = 0; i < capacity();) { + Entry* src = &table[i]; + + if (!src->isLive() || src->hasCollision()) { + ++i; + continue; + } + + HashNumber keyHash = src->getKeyHash(); + HashNumber h1 = hash1(keyHash); + DoubleHash dh = hash2(keyHash); + Entry* tgt = &table[h1]; + while (true) { + if (!tgt->hasCollision()) { + src->swap(tgt); + tgt->setCollision(); + break; + } + + h1 = applyDoubleHash(h1, dh); + tgt = &table[h1]; + } + } + + // TODO: this algorithm leaves collision bits on *all* elements, even if + // they are on no collision path. We have the option of setting the + // collision bits correctly on a subsequent pass or skipping the rehash + // unless we are totally filled with tombstones: benchmark to find out + // which approach is best. + } + + // Note: |l| may be a reference to a piece of |u|, so this function + // must take care not to use |l| after moving |u|. + // + // Prefer to use putNewInfallible; this function does not check + // invariants. + template + void putNewInfallibleInternal(const Lookup& l, Args&&... args) { + MOZ_ASSERT(table); + + HashNumber keyHash = prepareHash(l); + Entry* entry = &findFreeEntry(keyHash); + MOZ_ASSERT(entry); + + if (entry->isRemoved()) { + METER(stats.addOverRemoved++); + removedCount--; + keyHash |= sCollisionBit; + } + + entry->setLive(keyHash, mozilla::Forward(args)...); + entryCount++; +#ifdef JS_DEBUG + mutationCount++; +#endif + } + + public: + void clear() { + if (mozilla::IsPod::value) { + memset(table, 0, sizeof(*table) * capacity()); + } else { + uint32_t tableCapacity = capacity(); + Entry* end = table + tableCapacity; + for (Entry* e = table; e < end; ++e) e->clear(); + } + removedCount = 0; + entryCount = 0; +#ifdef JS_DEBUG + mutationCount++; +#endif + } + + void clearAndShrink() { + clear(); + compactIfUnderloaded(); + } + + void finish() { +#ifdef JS_DEBUG + MOZ_ASSERT(!mEntered); +#endif + if (!table) return; + + destroyTable(*this, table, capacity()); + table = nullptr; + gen++; + entryCount = 0; + removedCount = 0; +#ifdef JS_DEBUG + mutationCount++; +#endif + } + + Range all() const { + MOZ_ASSERT(table); + return Range(*this, table, table + capacity()); + } + + bool empty() const { + MOZ_ASSERT(table); + return !entryCount; + } + + uint32_t count() const { + MOZ_ASSERT(table); + return entryCount; + } + + uint32_t capacity() const { + MOZ_ASSERT(table); + return JS_BIT(sHashBits - hashShift); + } + + Generation generation() const { + MOZ_ASSERT(table); + return Generation(gen); + } + + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return mallocSizeOf(table); + } + + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf); + } + + MOZ_ALWAYS_INLINE Ptr lookup(const Lookup& l) const { + mozilla::ReentrancyGuard g(*this); + if (!HasHash(l)) return Ptr(); + HashNumber keyHash = prepareHash(l); + return Ptr(lookup(l, keyHash, 0), *this); + } + + MOZ_ALWAYS_INLINE Ptr readonlyThreadsafeLookup(const Lookup& l) const { + if (!HasHash(l)) return Ptr(); + HashNumber keyHash = prepareHash(l); + return Ptr(lookup(l, keyHash, 0), *this); + } + + MOZ_ALWAYS_INLINE AddPtr lookupForAdd(const Lookup& l) const { + mozilla::ReentrancyGuard g(*this); + if (!EnsureHash(l)) return AddPtr(); + HashNumber keyHash = prepareHash(l); + // Calling constructor in return statement here avoid excess copying + // when build with Visual Studio 2015 and 2017, but it triggers a bug in + // gcc which is fixed in gcc-6. See bug 1385181. +#if MOZ_IS_GCC && __GNUC__ < 6 + AddPtr p(lookup(l, keyHash, sCollisionBit), *this, keyHash); + return p; +#else + return AddPtr(lookup(l, keyHash, sCollisionBit), *this, keyHash); +#endif + } - void rekeyAndMaybeRehash(Ptr p, const Lookup& l, const Key& k) - { - rekeyWithoutRehash(p, l, k); - checkOverRemoved(); - } + template + MOZ_MUST_USE bool add(AddPtr& p, Args&&... args) { + mozilla::ReentrancyGuard g(*this); + MOZ_ASSERT(table); + MOZ_ASSERT_IF(p.isValid(), p.table_ == this); + MOZ_ASSERT(!p.found()); + MOZ_ASSERT(!(p.keyHash & sCollisionBit)); + + // Check for error from ensureHash() here. + if (!p.isValid()) return false; + + MOZ_ASSERT(p.generation == generation()); +#ifdef JS_DEBUG + MOZ_ASSERT(p.mutationCount == mutationCount); +#endif + + // Changing an entry from removed to live does not affect whether we + // are overloaded and can be handled separately. + if (p.entry_->isRemoved()) { + if (!this->checkSimulatedOOM()) return false; + METER(stats.addOverRemoved++); + removedCount--; + p.keyHash |= sCollisionBit; + } else { + // Preserve the validity of |p.entry_|. + RebuildStatus status = checkOverloaded(); + if (status == RehashFailed) return false; + if (status == NotOverloaded && !this->checkSimulatedOOM()) return false; + if (status == Rehashed) p.entry_ = &findFreeEntry(p.keyHash); + } + + p.entry_->setLive(p.keyHash, mozilla::Forward(args)...); + entryCount++; +#ifdef JS_DEBUG + mutationCount++; + p.generation = generation(); + p.mutationCount = mutationCount; +#endif + return true; + } + + // Note: |l| may be a reference to a piece of |u|, so this function + // must take care not to use |l| after moving |u|. + template + void putNewInfallible(const Lookup& l, Args&&... args) { + MOZ_ASSERT(!lookup(l).found()); + mozilla::ReentrancyGuard g(*this); + putNewInfallibleInternal(l, mozilla::Forward(args)...); + } + + // Note: |l| may be alias arguments in |args|, so this function must take + // care not to use |l| after moving |args|. + template + MOZ_MUST_USE bool putNew(const Lookup& l, Args&&... args) { + if (!this->checkSimulatedOOM()) return false; + + if (!EnsureHash(l)) return false; + + if (checkOverloaded() == RehashFailed) return false; + + putNewInfallible(l, mozilla::Forward(args)...); + return true; + } + + // Note: |l| may be a reference to a piece of |u|, so this function + // must take care not to use |l| after moving |u|. + template + MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, Args&&... args) { + // Check for error from ensureHash() here. + if (!p.isValid()) return false; + +#ifdef JS_DEBUG + p.generation = generation(); + p.mutationCount = mutationCount; +#endif + { + mozilla::ReentrancyGuard g(*this); + MOZ_ASSERT(prepareHash(l) == p.keyHash); // l has not been destroyed + p.entry_ = &lookup(l, p.keyHash, sCollisionBit); + } + return p.found() || add(p, mozilla::Forward(args)...); + } + + void remove(Ptr p) { + MOZ_ASSERT(table); + mozilla::ReentrancyGuard g(*this); + MOZ_ASSERT(p.found()); + MOZ_ASSERT(p.generation == generation()); + remove(*p.entry_); + checkUnderloaded(); + } + + void rekeyWithoutRehash(Ptr p, const Lookup& l, const Key& k) { + MOZ_ASSERT(table); + mozilla::ReentrancyGuard g(*this); + MOZ_ASSERT(p.found()); + MOZ_ASSERT(p.generation == generation()); + typename HashTableEntry::NonConstT t(mozilla::Move(*p)); + HashPolicy::setKey(t, const_cast(k)); + remove(*p.entry_); + putNewInfallibleInternal(l, mozilla::Move(t)); + } + + void rekeyAndMaybeRehash(Ptr p, const Lookup& l, const Key& k) { + rekeyWithoutRehash(p, l, k); + checkOverRemoved(); + } #undef METER }; -} // namespace detail -} // namespace js +} // namespace detail +} // namespace js -#endif /* js_HashTable_h */ +#endif /* js_HashTable_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/HeapAPI.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/HeapAPI.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/HeapAPI.h @@ -17,13 +17,18 @@ /* These values are private to the JS engine. */ namespace js { -JS_FRIEND_API(bool) -CurrentThreadCanAccessZone(JS::Zone* zone); +JS_FRIEND_API bool CurrentThreadCanAccessZone(JS::Zone* zone); namespace gc { struct Cell; +/* + * The low bit is set so this should never equal a normal pointer, and the high + * bit is set so this should never equal the upper 32 bits of a 64-bit pointer. + */ +const uint32_t Relocated = uintptr_t(0xbad0bad1); + const size_t ArenaShift = 12; const size_t ArenaSize = size_t(1) << ArenaShift; const size_t ArenaMask = ArenaSize - 1; @@ -36,9 +41,19 @@ const size_t ChunkSize = size_t(1) << ChunkShift; const size_t ChunkMask = ChunkSize - 1; -const size_t CellShift = 3; -const size_t CellSize = size_t(1) << CellShift; -const size_t CellMask = CellSize - 1; +const size_t CellAlignShift = 3; +const size_t CellAlignBytes = size_t(1) << CellAlignShift; +const size_t CellAlignMask = CellAlignBytes - 1; + +const size_t CellBytesPerMarkBit = CellAlignBytes; + +/* + * We sometimes use an index to refer to a cell in an arena. The index for a + * cell is found by dividing by the cell alignment so not all indicies refer to + * valid cells. + */ +const size_t ArenaCellIndexBytes = CellAlignBytes; +const size_t MaxArenaCellIndex = ArenaSize / CellAlignBytes; /* These are magic constants derived from actual offsets in gc/Heap.h. */ #ifdef JS_GC_SMALL_CHUNK_SIZE @@ -51,36 +66,40 @@ 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 ChunkStoreBufferOffset = + ChunkSize - ChunkTrailerSize + sizeof(uint64_t); const size_t ArenaZoneOffset = sizeof(size_t); -const size_t ArenaHeaderSize = sizeof(size_t) + 2 * sizeof(uintptr_t) + - sizeof(size_t) + sizeof(uintptr_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 - * depends on the size of the GCThing. Objects marked gray are eligible for - * cycle collection. + * Live objects are marked black or gray. Everything reachable from a JS root is + * marked black. Objects marked gray are eligible for cycle collection. + * + * BlackBit: GrayOrBlackBit: Color: + * 0 0 white + * 0 1 gray + * 1 0 black + * 1 1 black */ -static const uint32_t BLACK = 0; -static const uint32_t GRAY = 1; +enum class ColorBit : uint32_t { BlackBit = 0, GrayOrBlackBit = 1 }; /* * The "location" field in the Chunk trailer is a enum indicating various roles * of the chunk. */ -enum class ChunkLocation : uint32_t -{ - Invalid = 0, - Nursery = 1, - TenuredHeap = 2 +enum class ChunkLocation : uint32_t { + Invalid = 0, + Nursery = 1, + TenuredHeap = 2 }; #ifdef JS_DEBUG /* When downcasting, ensure we are actually the right type. */ -extern JS_FRIEND_API(void) -AssertGCThingHasType(js::gc::Cell* cell, JS::TraceKind kind); +extern JS_FRIEND_API void AssertGCThingHasType(js::gc::Cell* cell, + JS::TraceKind kind); #else -inline void -AssertGCThingHasType(js::gc::Cell* cell, JS::TraceKind kind) {} +inline void AssertGCThingHasType(js::gc::Cell* cell, JS::TraceKind kind) {} #endif MOZ_ALWAYS_INLINE bool IsInsideNursery(const js::gc::Cell* cell); @@ -89,62 +108,79 @@ } /* namespace js */ namespace JS { -struct Zone; -/* Default size for the generational nursery in bytes. */ +/* + * This list enumerates the different types of conceptual stacks we have in + * SpiderMonkey. In reality, they all share the C stack, but we allow different + * stack limits depending on the type of code running. + */ +enum StackKind { + StackForSystemCode, // C++, such as the GC, running on behalf of the VM. + StackForTrustedScript, // Script running with trusted principals. + StackForUntrustedScript, // Script running with untrusted principals. + StackKindCount +}; + +/* + * Default size for the generational nursery in bytes. + * This is the initial nursery size, when running in the browser this is + * updated by JS_SetGCParameter(). + */ const uint32_t DefaultNurseryBytes = 16 * js::gc::ChunkSize; -/* Default maximum heap size in bytes to pass to JS_NewRuntime(). */ +/* Default maximum heap size in bytes to pass to JS_NewContext(). */ const uint32_t DefaultHeapMaxBytes = 32 * 1024 * 1024; namespace shadow { -struct Zone -{ - protected: - JSRuntime* const runtime_; - 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; +struct Zone { + enum GCState : uint8_t { NoGC, Mark, MarkGray, Sweep, Finished, Compact }; - bool needsIncrementalBarrier_; + protected: + JSRuntime* const runtime_; + JSTracer* const barrierTracer_; // A pointer to the JSRuntime's |gcMarker|. + uint32_t needsIncrementalBarrier_; + GCState gcState_; - Zone(JSRuntime* runtime, JSTracer* barrierTracerArg) + Zone(JSRuntime* runtime, JSTracer* barrierTracerArg) : runtime_(runtime), barrierTracer_(barrierTracerArg), - needsIncrementalBarrier_(false) - { - for (auto& stackRootPtr : stackRoots_) - stackRootPtr = nullptr; - } - - bool needsIncrementalBarrier() const { - return needsIncrementalBarrier_; - } - - JSTracer* barrierTracer() { - MOZ_ASSERT(needsIncrementalBarrier_); - MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); - return barrierTracer_; - } - - JSRuntime* runtimeFromMainThread() const { - MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); - return runtime_; - } - - // Note: Unrestricted access to the zone's runtime from an arbitrary - // thread can easily lead to races. Use this method very carefully. - JSRuntime* runtimeFromAnyThread() const { - return runtime_; - } - - static MOZ_ALWAYS_INLINE JS::shadow::Zone* asShadowZone(JS::Zone* zone) { - return reinterpret_cast(zone); - } + needsIncrementalBarrier_(0), + gcState_(NoGC) {} + + public: + bool needsIncrementalBarrier() const { return needsIncrementalBarrier_; } + + JSTracer* barrierTracer() { + MOZ_ASSERT(needsIncrementalBarrier_); + MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); + return barrierTracer_; + } + + JSRuntime* runtimeFromActiveCooperatingThread() const { + MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); + return runtime_; + } + + // Note: Unrestricted access to the zone's runtime from an arbitrary + // thread can easily lead to races. Use this method very carefully. + JSRuntime* runtimeFromAnyThread() const { return runtime_; } + + GCState gcState() const { return gcState_; } + bool wasGCStarted() const { return gcState_ != NoGC; } + bool isGCMarkingBlack() const { return gcState_ == Mark; } + bool isGCMarkingGray() const { return gcState_ == MarkGray; } + bool isGCSweeping() const { return gcState_ == Sweep; } + bool isGCFinished() const { return gcState_ == Finished; } + bool isGCCompacting() const { return gcState_ == Compact; } + bool isGCMarking() const { return gcState_ == Mark || gcState_ == MarkGray; } + bool isGCSweepingOrCompacting() const { + return gcState_ == Sweep || gcState_ == Compact; + } + + static MOZ_ALWAYS_INLINE JS::shadow::Zone* asShadowZone(JS::Zone* zone) { + return reinterpret_cast(zone); + } }; } /* namespace shadow */ @@ -156,114 +192,121 @@ * is for use when that is not possible because a single pointer must point * to several kinds of GC thing. */ -class JS_FRIEND_API(GCCellPtr) -{ - public: - // Construction from a void* and trace kind. - GCCellPtr(void* gcthing, JS::TraceKind traceKind) : ptr(checkedCast(gcthing, traceKind)) {} - - // Automatically construct a null GCCellPtr from nullptr. - MOZ_IMPLICIT GCCellPtr(decltype(nullptr)) : ptr(checkedCast(nullptr, JS::TraceKind::Null)) {} - - // Construction from an explicit type. - template - explicit GCCellPtr(T* p) : ptr(checkedCast(p, JS::MapTypeToTraceKind::kind)) { } - explicit GCCellPtr(JSFunction* p) : ptr(checkedCast(p, JS::TraceKind::Object)) { } - explicit GCCellPtr(JSFlatString* str) : ptr(checkedCast(str, JS::TraceKind::String)) { } - explicit GCCellPtr(const Value& v); - - JS::TraceKind kind() const { - JS::TraceKind traceKind = JS::TraceKind(ptr & OutOfLineTraceKindMask); - if (uintptr_t(traceKind) != OutOfLineTraceKindMask) - return traceKind; - return outOfLineKind(); - } - - // Allow GCCellPtr to be used in a boolean context. - explicit operator bool() const { - MOZ_ASSERT(bool(asCell()) == (kind() != JS::TraceKind::Null)); - return asCell(); - } - - // Simplify checks to the kind. - template - bool is() const { return kind() == JS::MapTypeToTraceKind::kind; } - - // Conversions to more specific types must match the kind. Access to - // further refined types is not allowed directly from a GCCellPtr. - template - T& as() const { - MOZ_ASSERT(kind() == JS::MapTypeToTraceKind::kind); - // We can't use static_cast here, because the fact that JSObject - // inherits from js::gc::Cell is not part of the public API. - return *reinterpret_cast(asCell()); - } - - // Return a pointer to the cell this |GCCellPtr| refers to, or |nullptr|. - // (It would be more symmetrical with |to| for this to return a |Cell&|, but - // the result can be |nullptr|, and null references are undefined behavior.) - js::gc::Cell* asCell() const { - return reinterpret_cast(ptr & ~OutOfLineTraceKindMask); - } - - // The CC's trace logger needs an identity that is XPIDL serializable. - uint64_t unsafeAsInteger() const { - return static_cast(unsafeAsUIntPtr()); - } - // Inline mark bitmap access requires direct pointer arithmetic. - uintptr_t unsafeAsUIntPtr() const { - MOZ_ASSERT(asCell()); - MOZ_ASSERT(!js::gc::IsInsideNursery(asCell())); - return reinterpret_cast(asCell()); - } - - bool mayBeOwnedByOtherRuntime() const; - - private: - static uintptr_t checkedCast(void* p, JS::TraceKind traceKind) { - js::gc::Cell* cell = static_cast(p); - MOZ_ASSERT((uintptr_t(p) & OutOfLineTraceKindMask) == 0); - AssertGCThingHasType(cell, traceKind); - // Note: the OutOfLineTraceKindMask bits are set on all out-of-line kinds - // so that we can mask instead of branching. - MOZ_ASSERT_IF(uintptr_t(traceKind) >= OutOfLineTraceKindMask, - (uintptr_t(traceKind) & OutOfLineTraceKindMask) == OutOfLineTraceKindMask); - return uintptr_t(p) | (uintptr_t(traceKind) & OutOfLineTraceKindMask); - } +class JS_FRIEND_API GCCellPtr { + public: + // Construction from a void* and trace kind. + GCCellPtr(void* gcthing, JS::TraceKind traceKind) + : ptr(checkedCast(gcthing, traceKind)) {} + + // Automatically construct a null GCCellPtr from nullptr. + MOZ_IMPLICIT GCCellPtr(decltype(nullptr)) + : ptr(checkedCast(nullptr, JS::TraceKind::Null)) {} + + // Construction from an explicit type. + template + explicit GCCellPtr(T* p) + : ptr(checkedCast(p, JS::MapTypeToTraceKind::kind)) {} + explicit GCCellPtr(JSFunction* p) + : ptr(checkedCast(p, JS::TraceKind::Object)) {} + explicit GCCellPtr(JSFlatString* str) + : ptr(checkedCast(str, JS::TraceKind::String)) {} + explicit GCCellPtr(const Value& v); + + JS::TraceKind kind() const { + JS::TraceKind traceKind = JS::TraceKind(ptr & OutOfLineTraceKindMask); + if (uintptr_t(traceKind) != OutOfLineTraceKindMask) return traceKind; + return outOfLineKind(); + } + + // Allow GCCellPtr to be used in a boolean context. + explicit operator bool() const { + MOZ_ASSERT(bool(asCell()) == (kind() != JS::TraceKind::Null)); + return asCell(); + } + + // Simplify checks to the kind. + template + bool is() const { + return kind() == JS::MapTypeToTraceKind::kind; + } + + // Conversions to more specific types must match the kind. Access to + // further refined types is not allowed directly from a GCCellPtr. + template + T& as() const { + MOZ_ASSERT(kind() == JS::MapTypeToTraceKind::kind); + // We can't use static_cast here, because the fact that JSObject + // inherits from js::gc::Cell is not part of the public API. + return *reinterpret_cast(asCell()); + } + + // Return a pointer to the cell this |GCCellPtr| refers to, or |nullptr|. + // (It would be more symmetrical with |to| for this to return a |Cell&|, but + // the result can be |nullptr|, and null references are undefined behavior.) + js::gc::Cell* asCell() const { + return reinterpret_cast(ptr & ~OutOfLineTraceKindMask); + } + + // The CC's trace logger needs an identity that is XPIDL serializable. + uint64_t unsafeAsInteger() const { + return static_cast(unsafeAsUIntPtr()); + } + // Inline mark bitmap access requires direct pointer arithmetic. + uintptr_t unsafeAsUIntPtr() const { + MOZ_ASSERT(asCell()); + MOZ_ASSERT(!js::gc::IsInsideNursery(asCell())); + return reinterpret_cast(asCell()); + } + + MOZ_ALWAYS_INLINE bool mayBeOwnedByOtherRuntime() const { + if (is() || is()) + return mayBeOwnedByOtherRuntimeSlow(); + return false; + } + + private: + static uintptr_t checkedCast(void* p, JS::TraceKind traceKind) { + js::gc::Cell* cell = static_cast(p); + MOZ_ASSERT((uintptr_t(p) & OutOfLineTraceKindMask) == 0); + AssertGCThingHasType(cell, traceKind); + // Note: the OutOfLineTraceKindMask bits are set on all out-of-line kinds + // so that we can mask instead of branching. + MOZ_ASSERT_IF(uintptr_t(traceKind) >= OutOfLineTraceKindMask, + (uintptr_t(traceKind) & OutOfLineTraceKindMask) == + OutOfLineTraceKindMask); + return uintptr_t(p) | (uintptr_t(traceKind) & OutOfLineTraceKindMask); + } - JS::TraceKind outOfLineKind() const; + bool mayBeOwnedByOtherRuntimeSlow() const; - uintptr_t ptr; + JS::TraceKind outOfLineKind() const; + + uintptr_t ptr; }; -inline bool -operator==(const GCCellPtr& ptr1, const GCCellPtr& ptr2) -{ - return ptr1.asCell() == ptr2.asCell(); +inline bool operator==(const GCCellPtr& ptr1, const GCCellPtr& ptr2) { + return ptr1.asCell() == ptr2.asCell(); } -inline bool -operator!=(const GCCellPtr& ptr1, const GCCellPtr& ptr2) -{ - return !(ptr1 == ptr2); +inline bool operator!=(const GCCellPtr& ptr1, const GCCellPtr& ptr2) { + return !(ptr1 == ptr2); } // Unwraps the given GCCellPtr and calls the given functor with a template // argument of the actual type of the pointer. template -auto -DispatchTyped(F f, GCCellPtr thing, Args&&... args) - -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) -{ - switch (thing.kind()) { +auto DispatchTyped(F f, GCCellPtr thing, Args&&... args) + -> decltype(f(static_cast(nullptr), + mozilla::Forward(args)...)) { + switch (thing.kind()) { #define JS_EXPAND_DEF(name, type, _) \ - case JS::TraceKind::name: \ - return f(&thing.as(), mozilla::Forward(args)...); - JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); + case JS::TraceKind::name: \ + return f(&thing.as(), mozilla::Forward(args)...); + JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); #undef JS_EXPAND_DEF - default: - MOZ_CRASH("Invalid trace kind in DispatchTyped for GCCellPtr."); - } + default: + MOZ_CRASH("Invalid trace kind in DispatchTyped for GCCellPtr."); + } } } /* namespace JS */ @@ -272,73 +315,104 @@ namespace gc { namespace detail { -static MOZ_ALWAYS_INLINE uintptr_t* -GetGCThingMarkBitmap(const uintptr_t addr) -{ - MOZ_ASSERT(addr); - const uintptr_t bmap_addr = (addr & ~ChunkMask) | ChunkMarkBitmapOffset; - return reinterpret_cast(bmap_addr); -} - -static MOZ_ALWAYS_INLINE void -GetGCThingMarkWordAndMask(const uintptr_t addr, uint32_t color, - uintptr_t** wordp, uintptr_t* maskp) -{ - MOZ_ASSERT(addr); - const size_t bit = (addr & js::gc::ChunkMask) / js::gc::CellSize + color; - MOZ_ASSERT(bit < js::gc::ChunkMarkBitmapBits); - uintptr_t* bitmap = GetGCThingMarkBitmap(addr); - const uintptr_t nbits = sizeof(*bitmap) * CHAR_BIT; - *maskp = uintptr_t(1) << (bit % nbits); - *wordp = &bitmap[bit / nbits]; -} - -static MOZ_ALWAYS_INLINE JS::Zone* -GetGCThingZone(const uintptr_t addr) -{ - MOZ_ASSERT(addr); - const uintptr_t zone_addr = (addr & ~ArenaMask) | ArenaZoneOffset; - return *reinterpret_cast(zone_addr); - +static MOZ_ALWAYS_INLINE uintptr_t* GetGCThingMarkBitmap(const uintptr_t addr) { + // Note: the JIT pre-barrier trampolines inline this code. Update that + // code too when making changes here! + MOZ_ASSERT(addr); + const uintptr_t bmap_addr = (addr & ~ChunkMask) | ChunkMarkBitmapOffset; + return reinterpret_cast(bmap_addr); +} + +static MOZ_ALWAYS_INLINE void GetGCThingMarkWordAndMask(const uintptr_t addr, + ColorBit colorBit, + uintptr_t** wordp, + uintptr_t* maskp) { + // Note: the JIT pre-barrier trampolines inline this code. Update that + // code too when making changes here! + MOZ_ASSERT(addr); + const size_t bit = (addr & js::gc::ChunkMask) / js::gc::CellBytesPerMarkBit + + static_cast(colorBit); + MOZ_ASSERT(bit < js::gc::ChunkMarkBitmapBits); + uintptr_t* bitmap = GetGCThingMarkBitmap(addr); + const uintptr_t nbits = sizeof(*bitmap) * CHAR_BIT; + *maskp = uintptr_t(1) << (bit % nbits); + *wordp = &bitmap[bit / nbits]; +} + +static MOZ_ALWAYS_INLINE JS::Zone* GetGCThingZone(const uintptr_t addr) { + MOZ_ASSERT(addr); + const uintptr_t zone_addr = (addr & ~ArenaMask) | ArenaZoneOffset; + return *reinterpret_cast(zone_addr); +} + +static MOZ_ALWAYS_INLINE bool TenuredCellIsMarkedGray(const Cell* cell) { + // Return true if GrayOrBlackBit is set and BlackBit is not set. + MOZ_ASSERT(cell); + MOZ_ASSERT(!js::gc::IsInsideNursery(cell)); + + uintptr_t *grayWord, grayMask; + js::gc::detail::GetGCThingMarkWordAndMask( + uintptr_t(cell), js::gc::ColorBit::GrayOrBlackBit, &grayWord, &grayMask); + if (!(*grayWord & grayMask)) return false; + + uintptr_t *blackWord, blackMask; + js::gc::detail::GetGCThingMarkWordAndMask( + uintptr_t(cell), js::gc::ColorBit::BlackBit, &blackWord, &blackMask); + return !(*blackWord & blackMask); +} + +static MOZ_ALWAYS_INLINE bool CellIsMarkedGray(const Cell* cell) { + MOZ_ASSERT(cell); + if (js::gc::IsInsideNursery(cell)) return false; + return TenuredCellIsMarkedGray(cell); } -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); - 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); + +#ifdef DEBUG +extern JS_PUBLIC_API bool CellIsNotGray(const Cell* cell); + +extern JS_PUBLIC_API bool ObjectIsMarkedBlack(const JSObject* obj); +#endif + +MOZ_ALWAYS_INLINE ChunkLocation GetCellLocation(const void* cell) { + uintptr_t addr = uintptr_t(cell); + addr &= ~js::gc::ChunkMask; + addr |= js::gc::ChunkLocationOffset; + return *reinterpret_cast(addr); } -extern JS_PUBLIC_API(bool) -CellIsMarkedGrayIfKnown(const Cell* cell); +MOZ_ALWAYS_INLINE bool NurseryCellHasStoreBuffer(const void* cell) { + uintptr_t addr = uintptr_t(cell); + addr &= ~js::gc::ChunkMask; + addr |= js::gc::ChunkStoreBufferOffset; + return *reinterpret_cast(addr) != nullptr; +} } /* namespace detail */ -MOZ_ALWAYS_INLINE bool -IsInsideNursery(const js::gc::Cell* cell) -{ - if (!cell) - return false; - uintptr_t addr = uintptr_t(cell); - addr &= ~js::gc::ChunkMask; - addr |= js::gc::ChunkLocationOffset; - auto location = *reinterpret_cast(addr); - MOZ_ASSERT(location == ChunkLocation::Nursery || location == ChunkLocation::TenuredHeap); - return location == ChunkLocation::Nursery; +MOZ_ALWAYS_INLINE bool IsInsideNursery(const js::gc::Cell* cell) { + if (!cell) return false; + auto location = detail::GetCellLocation(cell); + MOZ_ASSERT(location == ChunkLocation::Nursery || + location == ChunkLocation::TenuredHeap); + return location == ChunkLocation::Nursery; +} + +MOZ_ALWAYS_INLINE bool IsCellPointerValid(const void* cell) { + auto addr = uintptr_t(cell); + if (addr < ChunkSize || addr % CellAlignBytes != 0) return false; + auto location = detail::GetCellLocation(cell); + if (location == ChunkLocation::TenuredHeap) + return !!detail::GetGCThingZone(addr); + if (location == ChunkLocation::Nursery) + return detail::NurseryCellHasStoreBuffer(cell); + return false; +} + +MOZ_ALWAYS_INLINE bool IsCellPointerValidOrNull(const void* cell) { + if (!cell) return true; + return IsCellPointerValid(cell); } } /* namespace gc */ @@ -346,61 +420,137 @@ namespace JS { -static MOZ_ALWAYS_INLINE Zone* -GetTenuredGCThingZone(GCCellPtr thing) -{ - MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell())); - return js::gc::detail::GetGCThingZone(thing.unsafeAsUIntPtr()); +static MOZ_ALWAYS_INLINE Zone* GetTenuredGCThingZone(GCCellPtr thing) { + MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell())); + return js::gc::detail::GetGCThingZone(thing.unsafeAsUIntPtr()); } -static MOZ_ALWAYS_INLINE Zone* -GetStringZone(JSString* str) -{ - return js::gc::detail::GetGCThingZone(uintptr_t(str)); +extern JS_PUBLIC_API Zone* GetNurseryStringZone(JSString* str); + +static MOZ_ALWAYS_INLINE Zone* GetStringZone(JSString* str) { + if (!js::gc::IsInsideNursery(reinterpret_cast(str))) + return js::gc::detail::GetGCThingZone(reinterpret_cast(str)); + return GetNurseryStringZone(str); } -extern JS_PUBLIC_API(Zone*) -GetObjectZone(JSObject* obj); +extern JS_PUBLIC_API Zone* GetObjectZone(JSObject* obj); -static MOZ_ALWAYS_INLINE bool -GCThingIsMarkedGray(GCCellPtr thing) -{ - if (thing.mayBeOwnedByOtherRuntime()) - return false; - return js::gc::detail::CellIsMarkedGrayIfKnown(thing.asCell()); +extern JS_PUBLIC_API Zone* GetValueZone(const Value& value); + +static MOZ_ALWAYS_INLINE bool GCThingIsMarkedGray(GCCellPtr thing) { + if (thing.mayBeOwnedByOtherRuntime()) return false; + return js::gc::detail::CellIsMarkedGrayIfKnown(thing.asCell()); } -extern JS_PUBLIC_API(JS::TraceKind) -GCThingTraceKind(void* thing); +extern JS_PUBLIC_API JS::TraceKind GCThingTraceKind(void* thing); -} /* namespace JS */ +extern JS_PUBLIC_API void EnableNurseryStrings(JSContext* cx); + +extern JS_PUBLIC_API void DisableNurseryStrings(JSContext* cx); + +/* + * Returns true when writes to GC thing pointers (and reads from weak pointers) + * must call an incremental barrier. This is generally only true when running + * mutator code in-between GC slices. At other times, the barrier may be elided + * for performance. + */ +extern JS_PUBLIC_API bool IsIncrementalBarrierNeeded(JSContext* cx); + +/* + * Notify the GC that a reference to a JSObject is about to be overwritten. + * This method must be called if IsIncrementalBarrierNeeded. + */ +extern JS_PUBLIC_API void IncrementalPreWriteBarrier(JSObject* obj); + +/* + * Notify the GC that a weak reference to a GC thing has been read. + * This method must be called if IsIncrementalBarrierNeeded. + */ +extern JS_PUBLIC_API void IncrementalReadBarrier(GCCellPtr thing); + +/** + * Unsets the gray bit for anything reachable from |thing|. |kind| should not be + * JS::TraceKind::Shape. |thing| should be non-null. The return value indicates + * if anything was unmarked. + */ +extern JS_FRIEND_API bool UnmarkGrayGCThingRecursively(GCCellPtr thing); + +} // namespace JS namespace js { namespace gc { -static MOZ_ALWAYS_INLINE bool -IsIncrementalBarrierNeededOnTenuredGCThing(JS::shadow::Runtime* rt, const JS::GCCellPtr thing) -{ - MOZ_ASSERT(thing); - MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell())); - - // 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()); +static MOZ_ALWAYS_INLINE bool IsIncrementalBarrierNeededOnTenuredGCThing( + const JS::GCCellPtr thing) { + MOZ_ASSERT(thing); + MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell())); + + // TODO: I'd like to assert !CurrentThreadIsHeapBusy() here but this gets + // called while we are tracing the heap, e.g. during memory reporting + // (see bug 1313318). + MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting()); - JS::Zone* zone = JS::GetTenuredGCThingZone(thing); - return JS::shadow::Zone::asShadowZone(zone)->needsIncrementalBarrier(); + JS::Zone* zone = JS::GetTenuredGCThingZone(thing); + return JS::shadow::Zone::asShadowZone(zone)->needsIncrementalBarrier(); } -/** - * Create an object providing access to the garbage collector's internal notion - * of the current state of memory (both GC heap memory and GCthing-controlled - * malloc memory. +static MOZ_ALWAYS_INLINE void ExposeGCThingToActiveJS(JS::GCCellPtr thing) { + // 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; + + // There's nothing to do for permanent GC things that might be owned by + // another runtime. + if (thing.mayBeOwnedByOtherRuntime()) return; + + if (IsIncrementalBarrierNeededOnTenuredGCThing(thing)) + JS::IncrementalReadBarrier(thing); + else if (js::gc::detail::TenuredCellIsMarkedGray(thing.asCell())) + JS::UnmarkGrayGCThingRecursively(thing); + + MOZ_ASSERT(!js::gc::detail::TenuredCellIsMarkedGray(thing.asCell())); +} + +template +extern JS_PUBLIC_API bool EdgeNeedsSweepUnbarrieredSlow(T* thingp); + +static MOZ_ALWAYS_INLINE bool EdgeNeedsSweepUnbarriered(JSObject** objp) { + // This function does not handle updating nursery pointers. Raw JSObject + // pointers should be updated separately or replaced with + // JS::Heap which handles this automatically. + MOZ_ASSERT(!JS::CurrentThreadIsHeapMinorCollecting()); + if (IsInsideNursery(reinterpret_cast(*objp))) return false; + + auto zone = + JS::shadow::Zone::asShadowZone(detail::GetGCThingZone(uintptr_t(*objp))); + if (!zone->isGCSweepingOrCompacting()) return false; + + return EdgeNeedsSweepUnbarrieredSlow(objp); +} + +} // namespace gc +} // namespace js + +namespace JS { + +/* + * This should be called when an object that is marked gray is exposed to the JS + * engine (by handing it to running JS code or writing it into live JS + * data). During incremental GC, since the gray bits haven't been computed yet, + * we conservatively mark the object black. */ -extern JS_PUBLIC_API(JSObject*) -NewMemoryInfoObject(JSContext* cx); +static MOZ_ALWAYS_INLINE void ExposeObjectToActiveJS(JSObject* obj) { + MOZ_ASSERT(obj); + MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&obj)); + js::gc::ExposeGCThingToActiveJS(GCCellPtr(obj)); +} -} /* namespace gc */ -} /* namespace js */ +static MOZ_ALWAYS_INLINE void ExposeScriptToActiveJS(JSScript* script) { + MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&script)); + js::gc::ExposeGCThingToActiveJS(GCCellPtr(script)); +} + +} /* namespace JS */ #endif /* js_HeapAPI_h */ 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 @@ -27,35 +27,30 @@ #include "js/TypeDecls.h" #include "js/Utility.h" -struct jsid -{ - size_t asBits; - bool operator==(const jsid& rhs) const { return asBits == rhs.asBits; } - bool operator!=(const jsid& rhs) const { return asBits != rhs.asBits; } +struct jsid { + size_t asBits; + bool operator==(const jsid& rhs) const { return asBits == rhs.asBits; } + bool operator!=(const jsid& rhs) const { return asBits != rhs.asBits; } } JS_HAZ_GC_POINTER; #define JSID_BITS(id) (id.asBits) -#define JSID_TYPE_STRING 0x0 -#define JSID_TYPE_INT 0x1 -#define JSID_TYPE_VOID 0x2 -#define JSID_TYPE_SYMBOL 0x4 -#define JSID_TYPE_MASK 0x7 +#define JSID_TYPE_STRING 0x0 +#define JSID_TYPE_INT 0x1 +#define JSID_TYPE_VOID 0x2 +#define JSID_TYPE_SYMBOL 0x4 +#define JSID_TYPE_MASK 0x7 // Avoid using canonical 'id' for jsid parameters since this is a magic word in // Objective-C++ which, apparently, wants to be able to #include jsapi.h. #define id iden -static MOZ_ALWAYS_INLINE bool -JSID_IS_STRING(jsid id) -{ - return (JSID_BITS(id) & JSID_TYPE_MASK) == 0; +static MOZ_ALWAYS_INLINE bool JSID_IS_STRING(jsid id) { + return (JSID_BITS(id) & JSID_TYPE_MASK) == 0; } -static MOZ_ALWAYS_INLINE JSString* -JSID_TO_STRING(jsid id) -{ - MOZ_ASSERT(JSID_IS_STRING(id)); - return (JSString*)JSID_BITS(id); +static MOZ_ALWAYS_INLINE JSString* JSID_TO_STRING(jsid id) { + MOZ_ASSERT(JSID_IS_STRING(id)); + return (JSString*)JSID_BITS(id); } /** @@ -65,143 +60,135 @@ * N.B. if a jsid is backed by a string which has not been interned, that * string must be appropriately rooted to avoid being collected by the GC. */ -JS_PUBLIC_API(jsid) -INTERNED_STRING_TO_JSID(JSContext* cx, JSString* str); +JS_PUBLIC_API jsid INTERNED_STRING_TO_JSID(JSContext* cx, JSString* str); -static MOZ_ALWAYS_INLINE bool -JSID_IS_INT(jsid id) -{ - return !!(JSID_BITS(id) & JSID_TYPE_INT); +static MOZ_ALWAYS_INLINE bool JSID_IS_INT(jsid id) { + return !!(JSID_BITS(id) & JSID_TYPE_INT); } -static MOZ_ALWAYS_INLINE int32_t -JSID_TO_INT(jsid id) -{ - MOZ_ASSERT(JSID_IS_INT(id)); - return ((uint32_t)JSID_BITS(id)) >> 1; +static MOZ_ALWAYS_INLINE int32_t JSID_TO_INT(jsid id) { + MOZ_ASSERT(JSID_IS_INT(id)); + uint32_t bits = static_cast(JSID_BITS(id)) >> 1; + return static_cast(bits); } -#define JSID_INT_MIN 0 -#define JSID_INT_MAX INT32_MAX +#define JSID_INT_MIN 0 +#define JSID_INT_MAX INT32_MAX -static MOZ_ALWAYS_INLINE bool -INT_FITS_IN_JSID(int32_t i) -{ - return i >= 0; -} +static MOZ_ALWAYS_INLINE bool INT_FITS_IN_JSID(int32_t i) { return i >= 0; } -static MOZ_ALWAYS_INLINE jsid -INT_TO_JSID(int32_t i) -{ - jsid id; - MOZ_ASSERT(INT_FITS_IN_JSID(i)); - JSID_BITS(id) = ((i << 1) | JSID_TYPE_INT); - return id; +static MOZ_ALWAYS_INLINE jsid INT_TO_JSID(int32_t i) { + jsid id; + MOZ_ASSERT(INT_FITS_IN_JSID(i)); + uint32_t bits = (static_cast(i) << 1) | JSID_TYPE_INT; + JSID_BITS(id) = static_cast(bits); + return id; } -static MOZ_ALWAYS_INLINE bool -JSID_IS_SYMBOL(jsid id) -{ - return (JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_SYMBOL && - JSID_BITS(id) != JSID_TYPE_SYMBOL; +static MOZ_ALWAYS_INLINE bool JSID_IS_SYMBOL(jsid id) { + return (JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_SYMBOL && + JSID_BITS(id) != JSID_TYPE_SYMBOL; } -static MOZ_ALWAYS_INLINE JS::Symbol* -JSID_TO_SYMBOL(jsid id) -{ - MOZ_ASSERT(JSID_IS_SYMBOL(id)); - return (JS::Symbol*)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); +static MOZ_ALWAYS_INLINE JS::Symbol* JSID_TO_SYMBOL(jsid id) { + MOZ_ASSERT(JSID_IS_SYMBOL(id)); + return (JS::Symbol*)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); } -static MOZ_ALWAYS_INLINE jsid -SYMBOL_TO_JSID(JS::Symbol* sym) -{ - jsid id; - MOZ_ASSERT(sym != nullptr); - MOZ_ASSERT((size_t(sym) & JSID_TYPE_MASK) == 0); - MOZ_ASSERT(!js::gc::IsInsideNursery(reinterpret_cast(sym))); - JSID_BITS(id) = (size_t(sym) | JSID_TYPE_SYMBOL); - return id; +static MOZ_ALWAYS_INLINE jsid SYMBOL_TO_JSID(JS::Symbol* sym) { + jsid id; + MOZ_ASSERT(sym != nullptr); + MOZ_ASSERT((size_t(sym) & JSID_TYPE_MASK) == 0); + MOZ_ASSERT(!js::gc::IsInsideNursery(reinterpret_cast(sym))); + JSID_BITS(id) = (size_t(sym) | JSID_TYPE_SYMBOL); + return id; } -static MOZ_ALWAYS_INLINE bool -JSID_IS_GCTHING(jsid id) -{ - return JSID_IS_STRING(id) || JSID_IS_SYMBOL(id); +static MOZ_ALWAYS_INLINE bool JSID_IS_GCTHING(jsid id) { + return JSID_IS_STRING(id) || JSID_IS_SYMBOL(id); } -static MOZ_ALWAYS_INLINE JS::GCCellPtr -JSID_TO_GCTHING(jsid id) -{ - void* thing = (void*)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); - if (JSID_IS_STRING(id)) - return JS::GCCellPtr(thing, JS::TraceKind::String); - MOZ_ASSERT(JSID_IS_SYMBOL(id)); - return JS::GCCellPtr(thing, JS::TraceKind::Symbol); +static MOZ_ALWAYS_INLINE JS::GCCellPtr JSID_TO_GCTHING(jsid id) { + void* thing = (void*)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); + if (JSID_IS_STRING(id)) return JS::GCCellPtr(thing, JS::TraceKind::String); + MOZ_ASSERT(JSID_IS_SYMBOL(id)); + return JS::GCCellPtr(thing, JS::TraceKind::Symbol); } -static MOZ_ALWAYS_INLINE bool -JSID_IS_VOID(const jsid id) -{ - MOZ_ASSERT_IF(((size_t)JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_VOID, - JSID_BITS(id) == JSID_TYPE_VOID); - return (size_t)JSID_BITS(id) == JSID_TYPE_VOID; +static MOZ_ALWAYS_INLINE bool JSID_IS_VOID(const jsid id) { + MOZ_ASSERT_IF(((size_t)JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_VOID, + JSID_BITS(id) == JSID_TYPE_VOID); + return (size_t)JSID_BITS(id) == JSID_TYPE_VOID; } -static MOZ_ALWAYS_INLINE bool -JSID_IS_EMPTY(const jsid id) -{ - return (size_t)JSID_BITS(id) == JSID_TYPE_SYMBOL; +static MOZ_ALWAYS_INLINE bool JSID_IS_EMPTY(const jsid id) { + return (size_t)JSID_BITS(id) == JSID_TYPE_SYMBOL; } -extern JS_PUBLIC_DATA(const jsid) JSID_VOID; -extern JS_PUBLIC_DATA(const jsid) JSID_EMPTY; +extern JS_PUBLIC_DATA const jsid JSID_VOID; +extern JS_PUBLIC_DATA const jsid JSID_EMPTY; -extern JS_PUBLIC_DATA(const JS::HandleId) JSID_VOIDHANDLE; -extern JS_PUBLIC_DATA(const JS::HandleId) JSID_EMPTYHANDLE; +extern JS_PUBLIC_DATA const JS::HandleId JSID_VOIDHANDLE; +extern JS_PUBLIC_DATA const JS::HandleId JSID_EMPTYHANDLE; namespace JS { template <> -struct GCPolicy -{ - static jsid initial() { return JSID_VOID; } - static void trace(JSTracer* trc, jsid* idp, const char* name) { - js::UnsafeTraceManuallyBarrieredEdge(trc, idp, name); - } +struct GCPolicy { + static jsid initial() { return JSID_VOID; } + static void trace(JSTracer* trc, jsid* idp, const char* name) { + js::UnsafeTraceManuallyBarrieredEdge(trc, idp, name); + } + static bool isValid(jsid id) { + return !JSID_IS_GCTHING(id) || + js::gc::IsCellPointerValid(JSID_TO_GCTHING(id).asCell()); + } }; -} // namespace JS +#ifdef DEBUG +MOZ_ALWAYS_INLINE bool IdIsNotGray(jsid id) { + if (!JSID_IS_GCTHING(id)) return true; + + return CellIsNotGray(JSID_TO_GCTHING(id).asCell()); +} +#endif + +} // 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)); - } +struct BarrierMethods { + static gc::Cell* asGCThingOrNull(jsid id) { + if (JSID_IS_STRING(id)) + return reinterpret_cast(JSID_TO_STRING(id)); + if (JSID_IS_SYMBOL(id)) + return reinterpret_cast(JSID_TO_SYMBOL(id)); + return nullptr; + } + static void postBarrier(jsid* idp, jsid prev, jsid next) {} + static void 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, const jsid& id, Args&&... args) - -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) -{ - if (JSID_IS_STRING(id)) - return f(JSID_TO_STRING(id), mozilla::Forward(args)...); - if (JSID_IS_SYMBOL(id)) - return f(JSID_TO_SYMBOL(id), mozilla::Forward(args)...); - MOZ_ASSERT(!JSID_IS_GCTHING(id)); - return F::defaultValue(id); +auto DispatchTyped(F f, const jsid& id, Args&&... args) + -> decltype(f(static_cast(nullptr), + mozilla::Forward(args)...)) { + if (JSID_IS_STRING(id)) + return f(JSID_TO_STRING(id), mozilla::Forward(args)...); + if (JSID_IS_SYMBOL(id)) + return f(JSID_TO_SYMBOL(id), mozilla::Forward(args)...); + MOZ_ASSERT(!JSID_IS_GCTHING(id)); + return F::defaultValue(id); } #undef id -} // namespace js +} // namespace js #endif /* js_Id_h */ 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 @@ -13,7 +13,7 @@ namespace JS { namespace detail { -enum class InitState { Uninitialized = 0, Running, ShutDown }; +enum class InitState { Uninitialized = 0, Initializing, Running, ShutDown }; /** * SpiderMonkey's initialization status is tracked here, and it controls things @@ -22,14 +22,12 @@ * manner, so this (internal -- embedders, don't use!) variable doesn't need to * be atomic. */ -extern JS_PUBLIC_DATA(InitState) -libraryInitState; +extern JS_PUBLIC_DATA InitState libraryInitState; -extern JS_PUBLIC_API(const char*) -InitWithFailureDiagnostic(bool isDebugBuild); +extern JS_PUBLIC_API const char* InitWithFailureDiagnostic(bool isDebugBuild); -} // namespace detail -} // namespace JS +} // namespace detail +} // namespace JS // These are equivalent to ICU's |UMemAllocFn|, |UMemReallocFn|, and // |UMemFreeFn| types. The first argument (called |context| in the ICU docs) @@ -43,14 +41,13 @@ * *must* be called before JS_Init. Don't use it unless you know what you're * doing! */ -extern JS_PUBLIC_API(bool) -JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, - JS_ICUReallocFn reallocFn, - JS_ICUFreeFn freeFn); +extern JS_PUBLIC_API bool JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, + JS_ICUReallocFn reallocFn, + JS_ICUFreeFn freeFn); /** * Initialize SpiderMonkey, returning true only if initialization succeeded. - * Once this method has succeeded, it is safe to call JS_NewRuntime and other + * Once this method has succeeded, it is safe to call JS_NewContext and other * JSAPI methods. * * This method must be called before any other JSAPI method is used on any @@ -61,13 +58,11 @@ * is, calling JS_Init/JSAPI methods/JS_ShutDown in that order, then doing so * again). This restriction may eventually be lifted. */ -inline bool -JS_Init(void) -{ +inline bool JS_Init(void) { #ifdef DEBUG - return !JS::detail::InitWithFailureDiagnostic(true); + return !JS::detail::InitWithFailureDiagnostic(true); #else - return !JS::detail::InitWithFailureDiagnostic(false); + return !JS::detail::InitWithFailureDiagnostic(false); #endif } @@ -76,19 +71,17 @@ * pointer to a string literal that describes how initialization failed, which * can be useful for debugging purposes. */ -inline const char* -JS_InitWithFailureDiagnostic(void) -{ +inline const char* JS_InitWithFailureDiagnostic(void) { #ifdef DEBUG - return JS::detail::InitWithFailureDiagnostic(true); + return JS::detail::InitWithFailureDiagnostic(true); #else - return JS::detail::InitWithFailureDiagnostic(false); + return JS::detail::InitWithFailureDiagnostic(false); #endif } /* - * Returns true if SpiderMonkey has been initialized successfully, even if it has - * possibly been shut down. + * 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 @@ -96,10 +89,8 @@ * 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; +inline bool JS_IsInitialized(void) { + return JS::detail::libraryInitState >= JS::detail::InitState::Running; } /** @@ -119,7 +110,6 @@ * 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(void) -JS_ShutDown(void); +extern JS_PUBLIC_API void JS_ShutDown(void); #endif /* js_Initialization_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/LegacyIntTypes.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/LegacyIntTypes.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/LegacyIntTypes.h @@ -1,59 +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/. */ - -/* - * This section typedefs the old 'native' types to the new types. - * These redefinitions are provided solely to allow JSAPI users to more easily - * transition to types. They are not to be used in the JSAPI, and - * new JSAPI user code should not use them. This mapping file may eventually - * be removed from SpiderMonkey, so don't depend on it in the long run. - */ - -/* - * BEWARE: Comity with other implementers of these types is not guaranteed. - * Indeed, if you use this header and third-party code defining these - * types, *expect* to encounter either compile errors or link errors, - * depending how these types are used and on the order of inclusion. - * It is safest to use only the types. - */ -#ifndef js_LegacyIntTypes_h -#define js_LegacyIntTypes_h - -#include - -#include "js-config.h" - -typedef uint8_t uint8; -typedef uint16_t uint16; -typedef uint32_t uint32; -typedef uint64_t uint64; - -/* - * On AIX 4.3, sys/inttypes.h (which is included by sys/types.h, a very - * common header file) defines the types int8, int16, int32, and int64. - * So we don't define these four types here to avoid conflicts in case - * the code also includes sys/types.h. - */ -#if defined(AIX) && defined(HAVE_SYS_INTTYPES_H) -#include -#else -typedef int8_t int8; -typedef int16_t int16; -typedef int32_t int32; -typedef int64_t int64; -#endif /* AIX && HAVE_SYS_INTTYPES_H */ - -typedef uint8_t JSUint8; -typedef uint16_t JSUint16; -typedef uint32_t JSUint32; -typedef uint64_t JSUint64; - -typedef int8_t JSInt8; -typedef int16_t JSInt16; -typedef int32_t JSInt32; -typedef int64_t JSInt64; - -#endif /* js_LegacyIntTypes_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/MemoryMetrics.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/MemoryMetrics.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/MemoryMetrics.h @@ -16,82 +16,98 @@ #include -#include "jsalloc.h" #include "jspubtd.h" +#include "js/AllocPolicy.h" #include "js/HashTable.h" #include "js/TracingAPI.h" #include "js/Utility.h" #include "js/Vector.h" -class nsISupports; // Needed for ObjectPrivateVisitor. +class nsISupports; // Needed for ObjectPrivateVisitor. namespace JS { -struct TabSizes -{ - enum Kind { - Objects, - Strings, - Private, - Other - }; - - TabSizes() { mozilla::PodZero(this); } - - void add(Kind kind, size_t n) { - switch (kind) { - case Objects: objects += n; break; - case Strings: strings += n; break; - case Private: private_ += n; break; - case Other: other += n; break; - default: MOZ_CRASH("bad TabSizes kind"); - } - } +struct TabSizes { + enum Kind { Objects, Strings, Private, Other }; + + TabSizes() { mozilla::PodZero(this); } - size_t objects; - size_t strings; - size_t private_; - size_t other; + void add(Kind kind, size_t n) { + switch (kind) { + case Objects: + objects += n; + break; + case Strings: + strings += n; + break; + case Private: + private_ += n; + break; + case Other: + other += n; + break; + default: + MOZ_CRASH("bad TabSizes kind"); + } + } + + size_t objects; + size_t strings; + size_t private_; + size_t other; }; /** These are the measurements used by Servo. */ -struct ServoSizes -{ - enum Kind { - GCHeapUsed, - GCHeapUnused, - GCHeapAdmin, - GCHeapDecommitted, - MallocHeap, - NonHeap, - Ignore - }; - - ServoSizes() { mozilla::PodZero(this); } - - void add(Kind kind, size_t n) { - switch (kind) { - case GCHeapUsed: gcHeapUsed += n; break; - case GCHeapUnused: gcHeapUnused += n; break; - case GCHeapAdmin: gcHeapAdmin += n; break; - case GCHeapDecommitted: gcHeapDecommitted += n; break; - case MallocHeap: mallocHeap += n; break; - case NonHeap: nonHeap += n; break; - case Ignore: /* do nothing */ break; - default: MOZ_CRASH("bad ServoSizes kind"); - } - } - - size_t gcHeapUsed; - size_t gcHeapUnused; - size_t gcHeapAdmin; - size_t gcHeapDecommitted; - size_t mallocHeap; - size_t nonHeap; +struct ServoSizes { + enum Kind { + GCHeapUsed, + GCHeapUnused, + GCHeapAdmin, + GCHeapDecommitted, + MallocHeap, + NonHeap, + Ignore + }; + + ServoSizes() { mozilla::PodZero(this); } + + void add(Kind kind, size_t n) { + switch (kind) { + case GCHeapUsed: + gcHeapUsed += n; + break; + case GCHeapUnused: + gcHeapUnused += n; + break; + case GCHeapAdmin: + gcHeapAdmin += n; + break; + case GCHeapDecommitted: + gcHeapDecommitted += n; + break; + case MallocHeap: + mallocHeap += n; + break; + case NonHeap: + nonHeap += n; + break; + case Ignore: /* do nothing */ + break; + default: + MOZ_CRASH("bad ServoSizes kind"); + } + } + + size_t gcHeapUsed; + size_t gcHeapUnused; + size_t gcHeapAdmin; + size_t gcHeapDecommitted; + size_t mallocHeap; + size_t nonHeap; }; -} // namespace JS +} // namespace JS namespace js { @@ -104,25 +120,23 @@ * We need to define this value here, rather than in the code which actually * generates the memory reports, because NotableStringInfo uses this value. */ -JS_FRIEND_API(size_t) MemoryReportingSundriesThreshold(); +JS_FRIEND_API size_t MemoryReportingSundriesThreshold(); /** * This hash policy avoids flattening ropes (which perturbs the site being * measured and requires a JSContext) at the expense of doing a FULL ROPE COPY * on every hash and match! Beware. */ -struct InefficientNonFlatteningStringHashPolicy -{ - typedef JSString* Lookup; - static HashNumber hash(const Lookup& l); - static bool match(const JSString* const& k, const Lookup& l); +struct InefficientNonFlatteningStringHashPolicy { + typedef JSString* Lookup; + static HashNumber hash(const Lookup& l); + static bool match(const JSString* const& k, const Lookup& l); }; -struct CStringHashPolicy -{ - typedef const char* Lookup; - static HashNumber hash(const Lookup& l); - static bool match(const char* const& k, const Lookup& l); +struct CStringHashPolicy { + typedef const char* Lookup; + static HashNumber hash(const Lookup& l); + static bool match(const char* const& k, const Lookup& l); }; // This file features many classes with numerous size_t fields, and each such @@ -141,128 +155,108 @@ // In some classes, one or more of the macro arguments aren't used. We use '_' // for those. // -#define DECL_SIZE(tabKind, servoKind, mSize) size_t mSize; -#define ZERO_SIZE(tabKind, servoKind, mSize) mSize(0), -#define COPY_OTHER_SIZE(tabKind, servoKind, mSize) mSize(other.mSize), -#define ADD_OTHER_SIZE(tabKind, servoKind, mSize) mSize += other.mSize; +#define DECL_SIZE(tabKind, servoKind, mSize) size_t mSize; +#define ZERO_SIZE(tabKind, servoKind, mSize) mSize(0), +#define COPY_OTHER_SIZE(tabKind, servoKind, mSize) mSize(other.mSize), +#define ADD_OTHER_SIZE(tabKind, servoKind, mSize) mSize += other.mSize; #define SUB_OTHER_SIZE(tabKind, servoKind, mSize) \ - MOZ_ASSERT(mSize >= other.mSize); \ - mSize -= other.mSize; -#define ADD_SIZE_TO_N(tabKind, servoKind, mSize) n += mSize; -#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(tabKind, servoKind, mSize) \ - /* Avoid self-comparison warnings by comparing enums indirectly. */ \ - n += (mozilla::IsSame::value) \ - ? mSize \ - : 0; -#define ADD_TO_TAB_SIZES(tabKind, servoKind, mSize) sizes->add(JS::TabSizes::tabKind, mSize); -#define ADD_TO_SERVO_SIZES(tabKind, servoKind, mSize) sizes->add(JS::ServoSizes::servoKind, mSize); + MOZ_ASSERT(mSize >= other.mSize); \ + mSize -= other.mSize; +#define ADD_SIZE_TO_N(tabKind, servoKind, mSize) n += mSize; +#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(tabKind, servoKind, mSize) \ + /* Avoid self-comparison warnings by comparing enums indirectly. */ \ + n += (mozilla::IsSame::value) \ + ? mSize \ + : 0; +#define ADD_TO_TAB_SIZES(tabKind, servoKind, mSize) \ + sizes->add(JS::TabSizes::tabKind, mSize); +#define ADD_TO_SERVO_SIZES(tabKind, servoKind, mSize) \ + sizes->add(JS::ServoSizes::servoKind, mSize); -} // namespace js +} // namespace js namespace JS { -struct ClassInfo -{ -#define FOR_EACH_SIZE(macro) \ - macro(Objects, GCHeapUsed, objectsGCHeap) \ - macro(Objects, MallocHeap, objectsMallocHeapSlots) \ - macro(Objects, MallocHeap, objectsMallocHeapElementsNormal) \ - macro(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \ - macro(Objects, MallocHeap, objectsMallocHeapMisc) \ - macro(Objects, NonHeap, objectsNonHeapElementsNormal) \ - macro(Objects, NonHeap, objectsNonHeapElementsShared) \ - macro(Objects, NonHeap, objectsNonHeapElementsWasm) \ - macro(Objects, NonHeap, objectsNonHeapCodeWasm) - - ClassInfo() - : FOR_EACH_SIZE(ZERO_SIZE) - wasmGuardPages(0) - {} +struct ClassInfo { +#define FOR_EACH_SIZE(MACRO) \ + MACRO(Objects, GCHeapUsed, objectsGCHeap) \ + MACRO(Objects, MallocHeap, objectsMallocHeapSlots) \ + MACRO(Objects, MallocHeap, objectsMallocHeapElementsNormal) \ + MACRO(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \ + MACRO(Objects, MallocHeap, objectsMallocHeapMisc) \ + MACRO(Objects, NonHeap, objectsNonHeapElementsNormal) \ + MACRO(Objects, NonHeap, objectsNonHeapElementsShared) \ + MACRO(Objects, NonHeap, objectsNonHeapElementsWasm) \ + MACRO(Objects, NonHeap, objectsNonHeapCodeWasm) - void add(const ClassInfo& other) { - FOR_EACH_SIZE(ADD_OTHER_SIZE) - } + ClassInfo() : FOR_EACH_SIZE(ZERO_SIZE) wasmGuardPages(0) {} - void subtract(const ClassInfo& other) { - FOR_EACH_SIZE(SUB_OTHER_SIZE) - } + void add(const ClassInfo& other) { FOR_EACH_SIZE(ADD_OTHER_SIZE) } - size_t sizeOfAllThings() const { - size_t n = 0; - FOR_EACH_SIZE(ADD_SIZE_TO_N) - return n; - } + void subtract(const ClassInfo& other){FOR_EACH_SIZE(SUB_OTHER_SIZE)} - bool isNotable() const { - static const size_t NotabilityThreshold = 16 * 1024; - return sizeOfAllThings() >= NotabilityThreshold; - } + 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; - } + bool isNotable() const { + static const size_t NotabilityThreshold = 16 * 1024; + return sizeOfAllThings() >= NotabilityThreshold; + } - void addToTabSizes(TabSizes* sizes) const { - FOR_EACH_SIZE(ADD_TO_TAB_SIZES) - } + size_t sizeOfLiveGCThings() const { + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) + return n; + } - void addToServoSizes(ServoSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) - } + 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) - size_t wasmGuardPages; + 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) +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() - {} + ShapeInfo() : FOR_EACH_SIZE(ZERO_SIZE) dummy() {} - void add(const ShapeInfo& other) { - FOR_EACH_SIZE(ADD_OTHER_SIZE) - } + void add(const ShapeInfo& other) { FOR_EACH_SIZE(ADD_OTHER_SIZE) } - void subtract(const ShapeInfo& other) { - FOR_EACH_SIZE(SUB_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 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; - } + 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 addToTabSizes(TabSizes* sizes) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES) } - void addToServoSizes(ServoSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_SERVO_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) + FOR_EACH_SIZE(DECL_SIZE) int dummy; // present just to absorb the trailing + // comma from FOR_EACH_SIZE(ZERO_SIZE) #undef FOR_EACH_SIZE }; @@ -275,74 +269,61 @@ * The only difference between this class and ClassInfo is that this class * holds a copy of the filename. */ -struct NotableClassInfo : public ClassInfo -{ - NotableClassInfo(); - NotableClassInfo(const char* className, const ClassInfo& info); - NotableClassInfo(NotableClassInfo&& info); - NotableClassInfo& operator=(NotableClassInfo&& info); +struct NotableClassInfo : public ClassInfo { + NotableClassInfo(); + NotableClassInfo(const char* className, const ClassInfo& info); + NotableClassInfo(NotableClassInfo&& info); + NotableClassInfo& operator=(NotableClassInfo&& info); - ~NotableClassInfo() { - js_free(className_); - } + ~NotableClassInfo() { js_free(className_); } - char* className_; + char* className_; - private: - NotableClassInfo(const NotableClassInfo& info) = delete; + private: + NotableClassInfo(const NotableClassInfo& info) = delete; }; /** Data for tracking JIT-code memory usage. */ -struct CodeSizes -{ -#define FOR_EACH_SIZE(macro) \ - macro(_, NonHeap, ion) \ - macro(_, NonHeap, baseline) \ - macro(_, NonHeap, regexp) \ - macro(_, NonHeap, other) \ - macro(_, NonHeap, unused) - - CodeSizes() - : FOR_EACH_SIZE(ZERO_SIZE) - dummy() - {} +struct CodeSizes { +#define FOR_EACH_SIZE(MACRO) \ + MACRO(_, NonHeap, ion) \ + MACRO(_, NonHeap, baseline) \ + MACRO(_, NonHeap, regexp) \ + MACRO(_, NonHeap, other) \ + MACRO(_, NonHeap, unused) - void addToServoSizes(ServoSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) - } + CodeSizes() : FOR_EACH_SIZE(ZERO_SIZE) dummy() {} - FOR_EACH_SIZE(DECL_SIZE) - int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE) + 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 }; /** Data for tracking GC memory usage. */ -struct GCSizes -{ - // |nurseryDecommitted| is marked as NonHeap rather than GCHeapDecommitted - // because we don't consider the nursery to be part of the GC heap. -#define FOR_EACH_SIZE(macro) \ - macro(_, MallocHeap, marker) \ - macro(_, NonHeap, nurseryCommitted) \ - macro(_, MallocHeap, nurseryMallocedBuffers) \ - macro(_, MallocHeap, storeBufferVals) \ - macro(_, MallocHeap, storeBufferCells) \ - macro(_, MallocHeap, storeBufferSlots) \ - macro(_, MallocHeap, storeBufferWholeCells) \ - macro(_, MallocHeap, storeBufferGenerics) - - GCSizes() - : FOR_EACH_SIZE(ZERO_SIZE) - dummy() - {} +struct GCSizes { +// |nurseryDecommitted| is marked as NonHeap rather than GCHeapDecommitted +// because we don't consider the nursery to be part of the GC heap. +#define FOR_EACH_SIZE(MACRO) \ + MACRO(_, MallocHeap, marker) \ + MACRO(_, NonHeap, nurseryCommitted) \ + MACRO(_, MallocHeap, nurseryMallocedBuffers) \ + MACRO(_, MallocHeap, storeBufferVals) \ + MACRO(_, MallocHeap, storeBufferCells) \ + MACRO(_, MallocHeap, storeBufferSlots) \ + MACRO(_, MallocHeap, storeBufferWholeCells) \ + MACRO(_, MallocHeap, storeBufferGenerics) - void addToServoSizes(ServoSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) - } + GCSizes() : FOR_EACH_SIZE(ZERO_SIZE) dummy() {} + + 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) + FOR_EACH_SIZE(DECL_SIZE) int dummy; // present just to absorb the trailing + // comma from FOR_EACH_SIZE(ZERO_SIZE) #undef FOR_EACH_SIZE }; @@ -354,52 +335,45 @@ * chars will not be aggregated together if one is a short string and the other * is not. */ -struct StringInfo -{ -#define FOR_EACH_SIZE(macro) \ - macro(Strings, GCHeapUsed, gcHeapLatin1) \ - macro(Strings, GCHeapUsed, gcHeapTwoByte) \ - macro(Strings, MallocHeap, mallocHeapLatin1) \ - macro(Strings, MallocHeap, mallocHeapTwoByte) - - StringInfo() - : FOR_EACH_SIZE(ZERO_SIZE) - numCopies(0) - {} - - void add(const StringInfo& other) { - FOR_EACH_SIZE(ADD_OTHER_SIZE); - numCopies++; - } - - void subtract(const StringInfo& other) { - FOR_EACH_SIZE(SUB_OTHER_SIZE); - numCopies--; - } +struct StringInfo { +#define FOR_EACH_SIZE(MACRO) \ + MACRO(Strings, GCHeapUsed, gcHeapLatin1) \ + MACRO(Strings, GCHeapUsed, gcHeapTwoByte) \ + MACRO(Strings, MallocHeap, mallocHeapLatin1) \ + MACRO(Strings, MallocHeap, mallocHeapTwoByte) + + StringInfo() : FOR_EACH_SIZE(ZERO_SIZE) numCopies(0) {} + + void add(const StringInfo& other) { + FOR_EACH_SIZE(ADD_OTHER_SIZE); + numCopies++; + } + + void subtract(const StringInfo& other) { + FOR_EACH_SIZE(SUB_OTHER_SIZE); + numCopies--; + } + + bool isNotable() const { + static const size_t NotabilityThreshold = 16 * 1024; + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N) + return n >= NotabilityThreshold; + } + + size_t sizeOfLiveGCThings() const { + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) + return n; + } - bool isNotable() const { - static const size_t NotabilityThreshold = 16 * 1024; - size_t n = 0; - FOR_EACH_SIZE(ADD_SIZE_TO_N) - return n >= NotabilityThreshold; - } + void addToTabSizes(TabSizes* sizes) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES) } - size_t sizeOfLiveGCThings() const { - size_t n = 0; - FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) - return n; - } + void addToServoSizes(ServoSizes* sizes) const { + FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)} - 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) - uint32_t numCopies; // How many copies of the string have we seen? + FOR_EACH_SIZE(DECL_SIZE) + uint32_t numCopies; // How many copies of the string have we seen? #undef FOR_EACH_SIZE }; @@ -411,65 +385,57 @@ * The only difference between this class and StringInfo is that * NotableStringInfo holds a copy of some or all of the string's chars. */ -struct NotableStringInfo : public StringInfo -{ - static const size_t MAX_SAVED_CHARS = 1024; - - NotableStringInfo(); - NotableStringInfo(JSString* str, const StringInfo& info); - NotableStringInfo(NotableStringInfo&& info); - NotableStringInfo& operator=(NotableStringInfo&& info); +struct NotableStringInfo : public StringInfo { + static const size_t MAX_SAVED_CHARS = 1024; - ~NotableStringInfo() { - js_free(buffer); - } + NotableStringInfo(); + NotableStringInfo(JSString* str, const StringInfo& info); + NotableStringInfo(NotableStringInfo&& info); + NotableStringInfo& operator=(NotableStringInfo&& info); - char* buffer; - size_t length; + ~NotableStringInfo() { js_free(buffer); } - private: - NotableStringInfo(const NotableStringInfo& info) = delete; + char* buffer; + size_t length; + + private: + NotableStringInfo(const NotableStringInfo& info) = delete; }; /** * This class holds information about the memory taken up by script sources * from a particular file. */ -struct ScriptSourceInfo -{ -#define FOR_EACH_SIZE(macro) \ - macro(_, MallocHeap, misc) - - ScriptSourceInfo() - : FOR_EACH_SIZE(ZERO_SIZE) - numScripts(0) - {} - - void add(const ScriptSourceInfo& other) { - FOR_EACH_SIZE(ADD_OTHER_SIZE) - numScripts++; - } - - void subtract(const ScriptSourceInfo& other) { - FOR_EACH_SIZE(SUB_OTHER_SIZE) - numScripts--; - } - - void addToServoSizes(ServoSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) - } +struct ScriptSourceInfo { +#define FOR_EACH_SIZE(MACRO) MACRO(_, MallocHeap, misc) - bool isNotable() const { - static const size_t NotabilityThreshold = 16 * 1024; - size_t n = 0; - FOR_EACH_SIZE(ADD_SIZE_TO_N) - return n >= NotabilityThreshold; - } + ScriptSourceInfo() : FOR_EACH_SIZE(ZERO_SIZE) numScripts(0) {} - FOR_EACH_SIZE(DECL_SIZE) - uint32_t numScripts; // How many ScriptSources come from this file? (It - // can be more than one in XML files that have - // multiple scripts in CDATA sections.) + void add(const ScriptSourceInfo& other) { + FOR_EACH_SIZE(ADD_OTHER_SIZE) + numScripts++; + } + + void subtract(const ScriptSourceInfo& other) { + FOR_EACH_SIZE(SUB_OTHER_SIZE) + numScripts--; + } + + void addToServoSizes(ServoSizes* sizes) const { + FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) + } + + bool isNotable() const { + static const size_t NotabilityThreshold = 16 * 1024; + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N) + return n >= NotabilityThreshold; + } + + FOR_EACH_SIZE(DECL_SIZE) + uint32_t numScripts; // How many ScriptSources come from this file? (It + // can be more than one in XML files that have + // multiple scripts in CDATA sections.) #undef FOR_EACH_SIZE }; @@ -481,483 +447,496 @@ * The only difference between this class and ScriptSourceInfo is that this * class holds a copy of the filename. */ -struct NotableScriptSourceInfo : public ScriptSourceInfo -{ - NotableScriptSourceInfo(); - NotableScriptSourceInfo(const char* filename, const ScriptSourceInfo& info); - NotableScriptSourceInfo(NotableScriptSourceInfo&& info); - NotableScriptSourceInfo& operator=(NotableScriptSourceInfo&& info); +struct NotableScriptSourceInfo : public ScriptSourceInfo { + NotableScriptSourceInfo(); + NotableScriptSourceInfo(const char* filename, const ScriptSourceInfo& info); + NotableScriptSourceInfo(NotableScriptSourceInfo&& info); + NotableScriptSourceInfo& operator=(NotableScriptSourceInfo&& info); - ~NotableScriptSourceInfo() { - js_free(filename_); - } + ~NotableScriptSourceInfo() { js_free(filename_); } - char* filename_; + char* filename_; - private: - NotableScriptSourceInfo(const NotableScriptSourceInfo& info) = delete; + private: + NotableScriptSourceInfo(const NotableScriptSourceInfo& info) = delete; }; /** - * These measurements relate directly to the JSRuntime, and not to zones and - * compartments within it. + * These measurements relate directly to the JSRuntime, and not to zones, + * compartments, and realms within it. */ -struct RuntimeSizes -{ -#define FOR_EACH_SIZE(macro) \ - macro(_, MallocHeap, object) \ - macro(_, MallocHeap, atomsTable) \ - macro(_, MallocHeap, contexts) \ - macro(_, MallocHeap, temporary) \ - macro(_, MallocHeap, interpreterStack) \ - macro(_, MallocHeap, mathCache) \ - macro(_, MallocHeap, sharedImmutableStringsCache) \ - macro(_, MallocHeap, sharedIntlData) \ - macro(_, MallocHeap, uncompressedSourceCache) \ - macro(_, MallocHeap, scriptData) - - RuntimeSizes() - : FOR_EACH_SIZE(ZERO_SIZE) - scriptSourceInfo(), +struct RuntimeSizes { +#define FOR_EACH_SIZE(MACRO) \ + MACRO(_, MallocHeap, object) \ + MACRO(_, MallocHeap, atomsTable) \ + MACRO(_, MallocHeap, atomsMarkBitmaps) \ + MACRO(_, MallocHeap, contexts) \ + MACRO(_, MallocHeap, temporary) \ + MACRO(_, MallocHeap, interpreterStack) \ + MACRO(_, MallocHeap, mathCache) \ + MACRO(_, MallocHeap, sharedImmutableStringsCache) \ + MACRO(_, MallocHeap, sharedIntlData) \ + MACRO(_, MallocHeap, uncompressedSourceCache) \ + MACRO(_, MallocHeap, scriptData) \ + MACRO(_, MallocHeap, tracelogger) + + RuntimeSizes() + : FOR_EACH_SIZE(ZERO_SIZE) scriptSourceInfo(), code(), gc(), - notableScriptSources() - { - allScriptSources = js_new(); - if (!allScriptSources || !allScriptSources->init()) - MOZ_CRASH("oom"); - } - - ~RuntimeSizes() { - // |allScriptSources| is usually deleted and set to nullptr before this - // destructor runs. But there are failure cases due to OOMs that may - // prevent that, so it doesn't hurt to try again here. - js_delete(allScriptSources); - } - - void addToServoSizes(ServoSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) - scriptSourceInfo.addToServoSizes(sizes); - code.addToServoSizes(sizes); - gc.addToServoSizes(sizes); - } - - // The script source measurements in |scriptSourceInfo| are initially for - // all script sources. At the end, if the measurement granularity is - // FineGrained, we subtract the measurements of the notable script sources - // and move them into |notableScriptSources|. - FOR_EACH_SIZE(DECL_SIZE) - ScriptSourceInfo scriptSourceInfo; - CodeSizes code; - GCSizes gc; - - typedef js::HashMap ScriptSourcesHashMap; - - // |allScriptSources| is only used transiently. During the reporting phase - // it is filled with info about every script source in the runtime. It's - // then used to fill in |notableScriptSources| (which actually gets - // reported), and immediately discarded afterwards. - ScriptSourcesHashMap* allScriptSources; - js::Vector notableScriptSources; - -#undef FOR_EACH_SIZE -}; - -struct UnusedGCThingSizes -{ -#define FOR_EACH_SIZE(macro) \ - macro(Other, GCHeapUnused, object) \ - macro(Other, GCHeapUnused, script) \ - macro(Other, GCHeapUnused, lazyScript) \ - macro(Other, GCHeapUnused, shape) \ - macro(Other, GCHeapUnused, baseShape) \ - macro(Other, GCHeapUnused, objectGroup) \ - macro(Other, GCHeapUnused, string) \ - macro(Other, GCHeapUnused, symbol) \ - macro(Other, GCHeapUnused, jitcode) \ - macro(Other, GCHeapUnused, scope) - - UnusedGCThingSizes() - : FOR_EACH_SIZE(ZERO_SIZE) - dummy() - {} + notableScriptSources() { + allScriptSources = js_new(); + if (!allScriptSources || !allScriptSources->init()) MOZ_CRASH("oom"); + } + + ~RuntimeSizes() { + // |allScriptSources| is usually deleted and set to nullptr before this + // destructor runs. But there are failure cases due to OOMs that may + // prevent that, so it doesn't hurt to try again here. + js_delete(allScriptSources); + } + + void addToServoSizes(ServoSizes* sizes) const { + FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) + scriptSourceInfo.addToServoSizes(sizes); + code.addToServoSizes(sizes); + gc.addToServoSizes(sizes); + } + + // The script source measurements in |scriptSourceInfo| are initially for + // all script sources. At the end, if the measurement granularity is + // FineGrained, we subtract the measurements of the notable script sources + // and move them into |notableScriptSources|. + FOR_EACH_SIZE(DECL_SIZE) + ScriptSourceInfo scriptSourceInfo; + CodeSizes code; + GCSizes gc; + + typedef js::HashMap + ScriptSourcesHashMap; + + // |allScriptSources| is only used transiently. During the reporting phase + // it is filled with info about every script source in the runtime. It's + // then used to fill in |notableScriptSources| (which actually gets + // reported), and immediately discarded afterwards. + ScriptSourcesHashMap* allScriptSources; + js::Vector + notableScriptSources; + +#undef FOR_EACH_SIZE +}; + +struct UnusedGCThingSizes { +#define FOR_EACH_SIZE(MACRO) \ + MACRO(Other, GCHeapUnused, object) \ + MACRO(Other, GCHeapUnused, script) \ + MACRO(Other, GCHeapUnused, lazyScript) \ + MACRO(Other, GCHeapUnused, shape) \ + MACRO(Other, GCHeapUnused, baseShape) \ + MACRO(Other, GCHeapUnused, objectGroup) \ + MACRO(Other, GCHeapUnused, string) \ + MACRO(Other, GCHeapUnused, symbol) \ + MACRO(Other, GCHeapUnused, jitcode) \ + MACRO(Other, GCHeapUnused, scope) \ + MACRO(Other, GCHeapUnused, regExpShared) + + UnusedGCThingSizes() : FOR_EACH_SIZE(ZERO_SIZE) dummy() {} + + UnusedGCThingSizes(UnusedGCThingSizes&& other) + : FOR_EACH_SIZE(COPY_OTHER_SIZE) dummy() {} + + void addToKind(JS::TraceKind kind, intptr_t n) { + switch (kind) { + case JS::TraceKind::Object: + object += n; + break; + case JS::TraceKind::String: + string += n; + break; + case JS::TraceKind::Symbol: + symbol += n; + break; + case JS::TraceKind::Script: + script += n; + break; + case JS::TraceKind::Shape: + shape += n; + break; + case JS::TraceKind::BaseShape: + baseShape += n; + break; + 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; + case JS::TraceKind::RegExpShared: + regExpShared += n; + break; + default: + MOZ_CRASH("Bad trace kind for UnusedGCThingSizes"); + } + } + + void addSizes(const UnusedGCThingSizes& other){FOR_EACH_SIZE(ADD_OTHER_SIZE)} + + size_t totalSize() const { + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N) + return n; + } + + void addToTabSizes(JS::TabSizes* sizes) const { + FOR_EACH_SIZE(ADD_TO_TAB_SIZES) + } + + void addToServoSizes(JS::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 +}; + +struct ZoneStats { +#define FOR_EACH_SIZE(MACRO) \ + MACRO(Other, GCHeapUsed, symbolsGCHeap) \ + MACRO(Other, GCHeapAdmin, gcHeapArenaAdmin) \ + MACRO(Other, GCHeapUsed, lazyScriptsGCHeap) \ + MACRO(Other, MallocHeap, lazyScriptsMallocHeap) \ + MACRO(Other, GCHeapUsed, jitCodesGCHeap) \ + MACRO(Other, GCHeapUsed, objectGroupsGCHeap) \ + MACRO(Other, MallocHeap, objectGroupsMallocHeap) \ + MACRO(Other, GCHeapUsed, scopesGCHeap) \ + MACRO(Other, MallocHeap, scopesMallocHeap) \ + MACRO(Other, GCHeapUsed, regExpSharedsGCHeap) \ + MACRO(Other, MallocHeap, regExpSharedsMallocHeap) \ + MACRO(Other, MallocHeap, typePool) \ + MACRO(Other, MallocHeap, regexpZone) \ + MACRO(Other, MallocHeap, jitZone) \ + MACRO(Other, MallocHeap, baselineStubsOptimized) \ + MACRO(Other, MallocHeap, cachedCFG) \ + MACRO(Other, MallocHeap, uniqueIdMap) \ + MACRO(Other, MallocHeap, shapeTables) - UnusedGCThingSizes(UnusedGCThingSizes&& other) - : FOR_EACH_SIZE(COPY_OTHER_SIZE) - dummy() - {} - - void addToKind(JS::TraceKind kind, intptr_t n) { - switch (kind) { - case JS::TraceKind::Object: object += n; break; - case JS::TraceKind::String: string += n; break; - case JS::TraceKind::Symbol: symbol += n; break; - case JS::TraceKind::Script: script += n; break; - case JS::TraceKind::Shape: shape += n; break; - case JS::TraceKind::BaseShape: baseShape += n; break; - 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"); - } - } - - void addSizes(const UnusedGCThingSizes& other) { - FOR_EACH_SIZE(ADD_OTHER_SIZE) - } - - size_t totalSize() const { - size_t n = 0; - FOR_EACH_SIZE(ADD_SIZE_TO_N) - return n; - } - - void addToTabSizes(JS::TabSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_TAB_SIZES) - } - - void addToServoSizes(JS::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 -}; - -struct ZoneStats -{ -#define FOR_EACH_SIZE(macro) \ - macro(Other, GCHeapUsed, symbolsGCHeap) \ - macro(Other, GCHeapAdmin, gcHeapArenaAdmin) \ - macro(Other, GCHeapUsed, lazyScriptsGCHeap) \ - macro(Other, MallocHeap, lazyScriptsMallocHeap) \ - macro(Other, GCHeapUsed, jitCodesGCHeap) \ - macro(Other, GCHeapUsed, objectGroupsGCHeap) \ - macro(Other, MallocHeap, objectGroupsMallocHeap) \ - macro(Other, GCHeapUsed, scopesGCHeap) \ - macro(Other, MallocHeap, scopesMallocHeap) \ - macro(Other, MallocHeap, typePool) \ - macro(Other, MallocHeap, baselineStubsOptimized) \ - macro(Other, MallocHeap, uniqueIdMap) \ - macro(Other, MallocHeap, shapeTables) - - ZoneStats() - : FOR_EACH_SIZE(ZERO_SIZE) - unusedGCThings(), + ZoneStats() + : FOR_EACH_SIZE(ZERO_SIZE) unusedGCThings(), stringInfo(), shapeInfo(), extra(), allStrings(nullptr), notableStrings(), - isTotals(true) - {} + isTotals(true) {} - ZoneStats(ZoneStats&& other) + ZoneStats(ZoneStats&& other) : FOR_EACH_SIZE(COPY_OTHER_SIZE) - unusedGCThings(mozilla::Move(other.unusedGCThings)), + 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)), - isTotals(other.isTotals) - { - other.allStrings = nullptr; - MOZ_ASSERT(!other.isTotals); - } - - ~ZoneStats() { - // |allStrings| is usually deleted and set to nullptr before this - // destructor runs. But there are failure cases due to OOMs that may - // prevent that, so it doesn't hurt to try again here. - js_delete(allStrings); - } - - bool initStrings(JSRuntime* rt); - - void addSizes(const ZoneStats& other) { - MOZ_ASSERT(isTotals); - FOR_EACH_SIZE(ADD_OTHER_SIZE) - unusedGCThings.addSizes(other.unusedGCThings); - stringInfo.add(other.stringInfo); - shapeInfo.add(other.shapeInfo); - } - - size_t sizeOfLiveGCThings() const { - MOZ_ASSERT(isTotals); - size_t n = 0; - FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) - n += stringInfo.sizeOfLiveGCThings(); - n += shapeInfo.sizeOfLiveGCThings(); - return n; - } - - void addToTabSizes(JS::TabSizes* sizes) const { - MOZ_ASSERT(isTotals); - FOR_EACH_SIZE(ADD_TO_TAB_SIZES) - unusedGCThings.addToTabSizes(sizes); - stringInfo.addToTabSizes(sizes); - shapeInfo.addToTabSizes(sizes); - } + isTotals(other.isTotals) { + other.allStrings = nullptr; + MOZ_ASSERT(!other.isTotals); + } + + ~ZoneStats() { + // |allStrings| is usually deleted and set to nullptr before this + // destructor runs. But there are failure cases due to OOMs that may + // prevent that, so it doesn't hurt to try again here. + js_delete(allStrings); + } + + bool initStrings(); + + void addSizes(const ZoneStats& other) { + MOZ_ASSERT(isTotals); + FOR_EACH_SIZE(ADD_OTHER_SIZE) + unusedGCThings.addSizes(other.unusedGCThings); + stringInfo.add(other.stringInfo); + shapeInfo.add(other.shapeInfo); + } + + size_t sizeOfLiveGCThings() const { + MOZ_ASSERT(isTotals); + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) + n += stringInfo.sizeOfLiveGCThings(); + n += shapeInfo.sizeOfLiveGCThings(); + return n; + } + + void addToTabSizes(JS::TabSizes* sizes) const { + MOZ_ASSERT(isTotals); + FOR_EACH_SIZE(ADD_TO_TAB_SIZES) + unusedGCThings.addToTabSizes(sizes); + stringInfo.addToTabSizes(sizes); + shapeInfo.addToTabSizes(sizes); + } + + void addToServoSizes(JS::ServoSizes* sizes) const { + MOZ_ASSERT(isTotals); + 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, + // if the measurement granularity is FineGrained, we subtract the + // measurements of the notable script sources and move them into + // |notableStrings|. + FOR_EACH_SIZE(DECL_SIZE) + UnusedGCThingSizes unusedGCThings; + StringInfo stringInfo; + ShapeInfo shapeInfo; + void* extra; // This field can be used by embedders. + + typedef js::HashMap + StringsHashMap; + + // |allStrings| is only used transiently. During the zone traversal it is + // filled with info about every string in the zone. It's then used to fill + // in |notableStrings| (which actually gets reported), and immediately + // discarded afterwards. + StringsHashMap* allStrings; + js::Vector notableStrings; + bool isTotals; + +#undef FOR_EACH_SIZE +}; + +struct CompartmentStats { +// We assume that |objectsPrivate| is on the malloc heap, but it's not +// actually guaranteed. But for Servo, at least, it's a moot point because +// it doesn't provide an ObjectPrivateVisitor so the value will always be +// zero. +#define FOR_EACH_SIZE(MACRO) \ + MACRO(Private, MallocHeap, objectsPrivate) \ + MACRO(Other, GCHeapUsed, scriptsGCHeap) \ + MACRO(Other, MallocHeap, scriptsMallocHeapData) \ + MACRO(Other, MallocHeap, baselineData) \ + MACRO(Other, MallocHeap, baselineStubsFallback) \ + MACRO(Other, MallocHeap, ionData) \ + MACRO(Other, MallocHeap, typeInferenceTypeScripts) \ + MACRO(Other, MallocHeap, typeInferenceAllocationSiteTables) \ + MACRO(Other, MallocHeap, typeInferenceArrayTypeTables) \ + MACRO(Other, MallocHeap, typeInferenceObjectTypeTables) \ + MACRO(Other, MallocHeap, compartmentObject) \ + MACRO(Other, MallocHeap, compartmentTables) \ + MACRO(Other, MallocHeap, innerViewsTable) \ + MACRO(Other, MallocHeap, lazyArrayBuffersTable) \ + MACRO(Other, MallocHeap, objectMetadataTable) \ + MACRO(Other, MallocHeap, crossCompartmentWrappersTable) \ + MACRO(Other, MallocHeap, savedStacksSet) \ + MACRO(Other, MallocHeap, varNamesSet) \ + MACRO(Other, MallocHeap, nonSyntacticLexicalScopesTable) \ + MACRO(Other, MallocHeap, jitCompartment) \ + MACRO(Other, MallocHeap, privateData) \ + MACRO(Other, MallocHeap, scriptCountsMap) - void addToServoSizes(JS::ServoSizes *sizes) const { - MOZ_ASSERT(isTotals); - 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, - // if the measurement granularity is FineGrained, we subtract the - // measurements of the notable script sources and move them into - // |notableStrings|. - FOR_EACH_SIZE(DECL_SIZE) - UnusedGCThingSizes unusedGCThings; - StringInfo stringInfo; - ShapeInfo shapeInfo; - void* extra; // This field can be used by embedders. - - typedef js::HashMap StringsHashMap; - - // |allStrings| is only used transiently. During the zone traversal it is - // filled with info about every string in the zone. It's then used to fill - // in |notableStrings| (which actually gets reported), and immediately - // discarded afterwards. - StringsHashMap* allStrings; - js::Vector notableStrings; - bool isTotals; - -#undef FOR_EACH_SIZE -}; - -struct CompartmentStats -{ - // We assume that |objectsPrivate| is on the malloc heap, but it's not - // actually guaranteed. But for Servo, at least, it's a moot point because - // it doesn't provide an ObjectPrivateVisitor so the value will always be - // zero. -#define FOR_EACH_SIZE(macro) \ - macro(Private, MallocHeap, objectsPrivate) \ - macro(Other, GCHeapUsed, scriptsGCHeap) \ - macro(Other, MallocHeap, scriptsMallocHeapData) \ - macro(Other, MallocHeap, baselineData) \ - macro(Other, MallocHeap, baselineStubsFallback) \ - macro(Other, MallocHeap, ionData) \ - macro(Other, MallocHeap, typeInferenceTypeScripts) \ - macro(Other, MallocHeap, typeInferenceAllocationSiteTables) \ - macro(Other, MallocHeap, typeInferenceArrayTypeTables) \ - macro(Other, MallocHeap, typeInferenceObjectTypeTables) \ - macro(Other, MallocHeap, compartmentObject) \ - macro(Other, MallocHeap, compartmentTables) \ - macro(Other, MallocHeap, innerViewsTable) \ - macro(Other, MallocHeap, lazyArrayBuffersTable) \ - macro(Other, MallocHeap, objectMetadataTable) \ - macro(Other, MallocHeap, crossCompartmentWrappersTable) \ - macro(Other, MallocHeap, regexpCompartment) \ - macro(Other, MallocHeap, savedStacksSet) \ - macro(Other, MallocHeap, varNamesSet) \ - macro(Other, MallocHeap, nonSyntacticLexicalScopesTable) \ - macro(Other, MallocHeap, jitCompartment) \ - macro(Other, MallocHeap, privateData) - - CompartmentStats() - : FOR_EACH_SIZE(ZERO_SIZE) - classInfo(), + CompartmentStats() + : FOR_EACH_SIZE(ZERO_SIZE) classInfo(), extra(), allClasses(nullptr), notableClasses(), - isTotals(true) - {} + isTotals(true) {} - CompartmentStats(CompartmentStats&& other) + CompartmentStats(CompartmentStats&& other) : FOR_EACH_SIZE(COPY_OTHER_SIZE) - classInfo(mozilla::Move(other.classInfo)), + classInfo(mozilla::Move(other.classInfo)), extra(other.extra), allClasses(other.allClasses), notableClasses(mozilla::Move(other.notableClasses)), - isTotals(other.isTotals) - { - other.allClasses = nullptr; - MOZ_ASSERT(!other.isTotals); - } - - CompartmentStats(const CompartmentStats&) = delete; // disallow copying - - ~CompartmentStats() { - // |allClasses| is usually deleted and set to nullptr before this - // destructor runs. But there are failure cases due to OOMs that may - // prevent that, so it doesn't hurt to try again here. - js_delete(allClasses); - } - - bool initClasses(JSRuntime* rt); - - void addSizes(const CompartmentStats& other) { - MOZ_ASSERT(isTotals); - FOR_EACH_SIZE(ADD_OTHER_SIZE) - classInfo.add(other.classInfo); - } - - size_t sizeOfLiveGCThings() const { - MOZ_ASSERT(isTotals); - size_t n = 0; - FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) - n += classInfo.sizeOfLiveGCThings(); - return n; - } - - void addToTabSizes(TabSizes* sizes) const { - MOZ_ASSERT(isTotals); - FOR_EACH_SIZE(ADD_TO_TAB_SIZES); - classInfo.addToTabSizes(sizes); - } - - void addToServoSizes(ServoSizes *sizes) const { - MOZ_ASSERT(isTotals); - FOR_EACH_SIZE(ADD_TO_SERVO_SIZES); - classInfo.addToServoSizes(sizes); - } - - // The class measurements in |classInfo| are initially for all classes. At - // the end, if the measurement granularity is FineGrained, we subtract the - // measurements of the notable classes and move them into |notableClasses|. - FOR_EACH_SIZE(DECL_SIZE) - ClassInfo classInfo; - void* extra; // This field can be used by embedders. - - typedef js::HashMap ClassesHashMap; - - // These are similar to |allStrings| and |notableStrings| in ZoneStats. - ClassesHashMap* allClasses; - js::Vector notableClasses; - bool isTotals; + isTotals(other.isTotals) { + other.allClasses = nullptr; + MOZ_ASSERT(!other.isTotals); + } + + CompartmentStats(const CompartmentStats&) = delete; // disallow copying + + ~CompartmentStats() { + // |allClasses| is usually deleted and set to nullptr before this + // destructor runs. But there are failure cases due to OOMs that may + // prevent that, so it doesn't hurt to try again here. + js_delete(allClasses); + } + + bool initClasses(); + + void addSizes(const CompartmentStats& other) { + MOZ_ASSERT(isTotals); + FOR_EACH_SIZE(ADD_OTHER_SIZE) + classInfo.add(other.classInfo); + } + + size_t sizeOfLiveGCThings() const { + MOZ_ASSERT(isTotals); + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) + n += classInfo.sizeOfLiveGCThings(); + return n; + } + + void addToTabSizes(TabSizes* sizes) const { + MOZ_ASSERT(isTotals); + FOR_EACH_SIZE(ADD_TO_TAB_SIZES); + classInfo.addToTabSizes(sizes); + } + + void addToServoSizes(ServoSizes* sizes) const { + MOZ_ASSERT(isTotals); + FOR_EACH_SIZE(ADD_TO_SERVO_SIZES); + classInfo.addToServoSizes(sizes); + } + + // The class measurements in |classInfo| are initially for all classes. At + // the end, if the measurement granularity is FineGrained, we subtract the + // measurements of the notable classes and move them into |notableClasses|. + FOR_EACH_SIZE(DECL_SIZE) + ClassInfo classInfo; + void* extra; // This field can be used by embedders. + + typedef js::HashMap + ClassesHashMap; + + // These are similar to |allStrings| and |notableStrings| in ZoneStats. + ClassesHashMap* allClasses; + js::Vector notableClasses; + bool isTotals; #undef FOR_EACH_SIZE }; -typedef js::Vector CompartmentStatsVector; +typedef js::Vector + CompartmentStatsVector; typedef js::Vector ZoneStatsVector; -struct RuntimeStats -{ - // |gcHeapChunkTotal| is ignored because it's the sum of all the other - // values. |gcHeapGCThings| is ignored because it's the sum of some of the - // values from the zones and compartments. Both of those values are not - // reported directly, but are just present for sanity-checking other - // values. -#define FOR_EACH_SIZE(macro) \ - macro(_, Ignore, gcHeapChunkTotal) \ - macro(_, GCHeapDecommitted, gcHeapDecommittedArenas) \ - macro(_, GCHeapUnused, gcHeapUnusedChunks) \ - macro(_, GCHeapUnused, gcHeapUnusedArenas) \ - macro(_, GCHeapAdmin, gcHeapChunkAdmin) \ - macro(_, Ignore, gcHeapGCThings) - - explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf) - : FOR_EACH_SIZE(ZERO_SIZE) - runtime(), +struct RuntimeStats { +// |gcHeapChunkTotal| is ignored because it's the sum of all the other +// values. |gcHeapGCThings| is ignored because it's the sum of some of the +// values from the zones and compartments. Both of those values are not +// reported directly, but are just present for sanity-checking other +// values. +#define FOR_EACH_SIZE(MACRO) \ + MACRO(_, Ignore, gcHeapChunkTotal) \ + MACRO(_, GCHeapDecommitted, gcHeapDecommittedArenas) \ + MACRO(_, GCHeapUnused, gcHeapUnusedChunks) \ + MACRO(_, GCHeapUnused, gcHeapUnusedArenas) \ + MACRO(_, GCHeapAdmin, gcHeapChunkAdmin) \ + MACRO(_, Ignore, gcHeapGCThings) + + explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf) + : FOR_EACH_SIZE(ZERO_SIZE) runtime(), cTotals(), zTotals(), compartmentStatsVector(), zoneStatsVector(), currZoneStats(nullptr), - mallocSizeOf_(mallocSizeOf) - {} + mallocSizeOf_(mallocSizeOf) {} - // Here's a useful breakdown of the GC heap. - // - // - rtStats.gcHeapChunkTotal - // - decommitted bytes - // - rtStats.gcHeapDecommittedArenas (decommitted arenas in non-empty chunks) - // - unused bytes - // - rtStats.gcHeapUnusedChunks (empty chunks) - // - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks) - // - rtStats.zTotals.unusedGCThings.totalSize() (empty GC thing slots within non-empty arenas) - // - used bytes - // - rtStats.gcHeapChunkAdmin - // - rtStats.zTotals.gcHeapArenaAdmin - // - rtStats.gcHeapGCThings (in-use GC things) - // == rtStats.zTotals.sizeOfLiveGCThings() + rtStats.cTotals.sizeOfLiveGCThings() - // - // It's possible that some arenas in empty chunks may be decommitted, but - // we don't count those under rtStats.gcHeapDecommittedArenas because (a) - // it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a - // multiple of the chunk size, which is good. - - void addToServoSizes(ServoSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) - runtime.addToServoSizes(sizes); - } + // Here's a useful breakdown of the GC heap. + // + // - rtStats.gcHeapChunkTotal + // - decommitted bytes + // - rtStats.gcHeapDecommittedArenas + // (decommitted arenas in non-empty chunks) + // - unused bytes + // - rtStats.gcHeapUnusedChunks (empty chunks) + // - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks) + // - rtStats.zTotals.unusedGCThings.totalSize() + // (empty GC thing slots within non-empty arenas) + // - used bytes + // - rtStats.gcHeapChunkAdmin + // - rtStats.zTotals.gcHeapArenaAdmin + // - rtStats.gcHeapGCThings (in-use GC things) + // == (rtStats.zTotals.sizeOfLiveGCThings() + + // rtStats.cTotals.sizeOfLiveGCThings()) + // + // It's possible that some arenas in empty chunks may be decommitted, but + // we don't count those under rtStats.gcHeapDecommittedArenas because (a) + // it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a + // multiple of the chunk size, which is good. + + void addToServoSizes(ServoSizes* sizes) const { + FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) + runtime.addToServoSizes(sizes); + } - FOR_EACH_SIZE(DECL_SIZE) + FOR_EACH_SIZE(DECL_SIZE) - RuntimeSizes runtime; + RuntimeSizes runtime; - CompartmentStats cTotals; // The sum of this runtime's compartments' measurements. - ZoneStats zTotals; // The sum of this runtime's zones' measurements. + CompartmentStats + cTotals; // The sum of this runtime's compartments' measurements. + ZoneStats zTotals; // The sum of this runtime's zones' measurements. - CompartmentStatsVector compartmentStatsVector; - ZoneStatsVector zoneStatsVector; + CompartmentStatsVector compartmentStatsVector; + ZoneStatsVector zoneStatsVector; - ZoneStats* currZoneStats; + ZoneStats* currZoneStats; - mozilla::MallocSizeOf mallocSizeOf_; + mozilla::MallocSizeOf mallocSizeOf_; - virtual void initExtraCompartmentStats(JSCompartment* c, CompartmentStats* cstats) = 0; - virtual void initExtraZoneStats(JS::Zone* zone, ZoneStats* zstats) = 0; + virtual void initExtraCompartmentStats(JSCompartment* c, + CompartmentStats* cstats) = 0; + virtual void initExtraZoneStats(JS::Zone* zone, ZoneStats* zstats) = 0; #undef FOR_EACH_SIZE }; -class ObjectPrivateVisitor -{ - public: - // Within CollectRuntimeStats, this method is called for each JS object - // that has an nsISupports pointer. - virtual size_t sizeOfIncludingThis(nsISupports* aSupports) = 0; +class ObjectPrivateVisitor { + public: + // Within CollectRuntimeStats, this method is called for each JS object + // that has an nsISupports pointer. + virtual size_t sizeOfIncludingThis(nsISupports* aSupports) = 0; - // A callback that gets a JSObject's nsISupports pointer, if it has one. - // Note: this function does *not* addref |iface|. - typedef bool(*GetISupportsFun)(JSObject* obj, nsISupports** iface); - GetISupportsFun getISupports_; + // A callback that gets a JSObject's nsISupports pointer, if it has one. + // Note: this function does *not* addref |iface|. + typedef bool (*GetISupportsFun)(JSObject* obj, nsISupports** iface); + GetISupportsFun getISupports_; - explicit ObjectPrivateVisitor(GetISupportsFun getISupports) - : getISupports_(getISupports) - {} + explicit ObjectPrivateVisitor(GetISupportsFun getISupports) + : getISupports_(getISupports) {} }; -extern JS_PUBLIC_API(bool) -CollectRuntimeStats(JSContext* cx, RuntimeStats* rtStats, ObjectPrivateVisitor* opv, bool anonymize); +extern JS_PUBLIC_API bool CollectRuntimeStats(JSContext* cx, + RuntimeStats* rtStats, + ObjectPrivateVisitor* opv, + bool anonymize); + +extern JS_PUBLIC_API size_t SystemCompartmentCount(JSContext* cx); -extern JS_PUBLIC_API(size_t) -SystemCompartmentCount(JSContext* cx); +extern JS_PUBLIC_API size_t UserCompartmentCount(JSContext* cx); -extern JS_PUBLIC_API(size_t) -UserCompartmentCount(JSContext* cx); +extern JS_PUBLIC_API size_t PeakSizeOfTemporary(const JSContext* cx); -extern JS_PUBLIC_API(size_t) -PeakSizeOfTemporary(const JSContext* cx); +extern JS_PUBLIC_API bool AddSizeOfTab(JSContext* cx, JS::HandleObject obj, + mozilla::MallocSizeOf mallocSizeOf, + ObjectPrivateVisitor* opv, + TabSizes* sizes); -extern JS_PUBLIC_API(bool) -AddSizeOfTab(JSContext* cx, JS::HandleObject obj, mozilla::MallocSizeOf mallocSizeOf, - ObjectPrivateVisitor* opv, TabSizes* sizes); +extern JS_PUBLIC_API bool AddServoSizeOf(JSContext* cx, + mozilla::MallocSizeOf mallocSizeOf, + ObjectPrivateVisitor* opv, + ServoSizes* sizes); -extern JS_PUBLIC_API(bool) -AddServoSizeOf(JSContext* cx, mozilla::MallocSizeOf mallocSizeOf, - ObjectPrivateVisitor *opv, ServoSizes *sizes); +extern JS_PUBLIC_API void CollectTraceLoggerStateStats(RuntimeStats* rtStats); -} // namespace JS +} // namespace JS #undef DECL_SIZE #undef ZERO_SIZE Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Principals.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Principals.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Principals.h @@ -18,68 +18,65 @@ #include "js/StructuredClone.h" namespace js { - struct JS_PUBLIC_API(PerformanceGroup); -} // namespace js +struct JS_PUBLIC_API PerformanceGroup; +} // namespace js struct JSPrincipals { - /* Don't call "destroy"; use reference counting macros below. */ - mozilla::Atomic refcount; + /* Don't call "destroy"; use reference counting macros below. */ + mozilla::Atomic refcount; #ifdef JS_DEBUG - /* A helper to facilitate principals debugging. */ - uint32_t debugToken; + /* A helper to facilitate principals debugging. */ + uint32_t debugToken; #endif - JSPrincipals() : refcount(0) {} + JSPrincipals() : refcount(0) {} - void setDebugToken(uint32_t token) { -# ifdef JS_DEBUG - debugToken = token; -# endif - } - - /* - * Write the principals with the given |writer|. Return false on failure, - * true on success. - */ - virtual bool write(JSContext* cx, JSStructuredCloneWriter* writer) = 0; - - /* - * This is not defined by the JS engine but should be provided by the - * embedding. - */ - JS_PUBLIC_API(void) dump(); + void setDebugToken(uint32_t token) { +#ifdef JS_DEBUG + debugToken = token; +#endif + } + + /* + * Write the principals with the given |writer|. Return false on failure, + * true on success. + */ + virtual bool write(JSContext* cx, JSStructuredCloneWriter* writer) = 0; + + /* + * This is not defined by the JS engine but should be provided by the + * embedding. + */ + JS_PUBLIC_API void dump(); }; -extern JS_PUBLIC_API(void) -JS_HoldPrincipals(JSPrincipals* principals); +extern JS_PUBLIC_API void JS_HoldPrincipals(JSPrincipals* principals); -extern JS_PUBLIC_API(void) -JS_DropPrincipals(JSContext* cx, JSPrincipals* principals); +extern JS_PUBLIC_API void JS_DropPrincipals(JSContext* cx, + JSPrincipals* principals); // Return whether the first principal subsumes the second. The exact meaning of // 'subsumes' is left up to the browser. Subsumption is checked inside the JS // engine when determining, e.g., which stack frames to display in a backtrace. -typedef bool -(* JSSubsumesOp)(JSPrincipals* first, JSPrincipals* second); +typedef bool (*JSSubsumesOp)(JSPrincipals* first, JSPrincipals* second); /* * Used to check if a CSP instance wants to disable eval() and friends. * See js_CheckCSPPermitsJSAction() in jsobj. */ -typedef bool -(* JSCSPEvalChecker)(JSContext* cx); +typedef bool (*JSCSPEvalChecker)(JSContext* cx); struct JSSecurityCallbacks { - JSCSPEvalChecker contentSecurityPolicyAllows; - JSSubsumesOp subsumes; + JSCSPEvalChecker contentSecurityPolicyAllows; + JSSubsumesOp subsumes; }; -extern JS_PUBLIC_API(void) -JS_SetSecurityCallbacks(JSContext* cx, const JSSecurityCallbacks* callbacks); +extern JS_PUBLIC_API void JS_SetSecurityCallbacks( + JSContext* cx, const JSSecurityCallbacks* callbacks); -extern JS_PUBLIC_API(const JSSecurityCallbacks*) -JS_GetSecurityCallbacks(JSContext* cx); +extern JS_PUBLIC_API const JSSecurityCallbacks* JS_GetSecurityCallbacks( + JSContext* cx); /* * Code running with "trusted" principals will be given a deeper stack @@ -93,19 +90,18 @@ * 'cx', JS_SetTrustedPrincipals must be called again, passing nullptr for * 'prin'. */ -extern JS_PUBLIC_API(void) -JS_SetTrustedPrincipals(JSContext* cx, JSPrincipals* prin); +extern JS_PUBLIC_API void JS_SetTrustedPrincipals(JSContext* cx, + JSPrincipals* prin); -typedef void -(* JSDestroyPrincipalsOp)(JSPrincipals* principals); +typedef void (*JSDestroyPrincipalsOp)(JSPrincipals* principals); /* * Initialize the callback that is called to destroy JSPrincipals instance * when its reference counter drops to zero. The initialization can be done * only once per JS runtime. */ -extern JS_PUBLIC_API(void) -JS_InitDestroyPrincipalsCallback(JSContext* cx, JSDestroyPrincipalsOp destroyPrincipals); +extern JS_PUBLIC_API void JS_InitDestroyPrincipalsCallback( + JSContext* cx, JSDestroyPrincipalsOp destroyPrincipals); /* * Read a JSPrincipals instance from the given |reader| and initialize the out @@ -118,15 +114,15 @@ * JSPrincipals instance, the JSReadPrincipalsOp must increment the refcount of * the resulting JSPrincipals on behalf of the caller. */ -using JSReadPrincipalsOp = bool (*)(JSContext* cx, JSStructuredCloneReader* reader, +using JSReadPrincipalsOp = bool (*)(JSContext* cx, + JSStructuredCloneReader* reader, JSPrincipals** outPrincipals); /* * Initialize the callback that is called to read JSPrincipals instances from a * buffer. The initialization can be done only once per JS runtime. */ -extern JS_PUBLIC_API(void) -JS_InitReadPrincipalsCallback(JSContext* cx, JSReadPrincipalsOp read); - +extern JS_PUBLIC_API void JS_InitReadPrincipalsCallback( + JSContext* cx, JSReadPrincipalsOp read); -#endif /* js_Principals_h */ +#endif /* js_Principals_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Printf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Printf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Printf.h @@ -0,0 +1,34 @@ +/* -*- 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_Printf_h +#define js_Printf_h + +#include "mozilla/Printf.h" + +#include + +#include "jstypes.h" +#include "js/Utility.h" + +/* Wrappers for mozilla::Smprintf and friends that are used throughout + JS. */ + +extern JS_PUBLIC_API JS::UniqueChars JS_smprintf(const char* fmt, ...) + MOZ_FORMAT_PRINTF(1, 2); + +extern JS_PUBLIC_API JS::UniqueChars JS_sprintf_append(JS::UniqueChars&& last, + const char* fmt, ...) + MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API JS::UniqueChars JS_vsmprintf(const char* fmt, va_list ap) + MOZ_FORMAT_PRINTF(1, 0); +extern JS_PUBLIC_API JS::UniqueChars JS_vsprintf_append(JS::UniqueChars&& last, + const char* fmt, + va_list ap) + MOZ_FORMAT_PRINTF(2, 0); + +#endif /* js_Printf_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ProfilingFrameIterator.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ProfilingFrameIterator.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ProfilingFrameIterator.h @@ -7,29 +7,24 @@ #ifndef js_ProfilingFrameIterator_h #define js_ProfilingFrameIterator_h -#include "mozilla/Alignment.h" +#include "mozilla/Attributes.h" #include "mozilla/Maybe.h" -#include "jsbytecode.h" #include "js/GCAPI.h" #include "js/TypeDecls.h" #include "js/Utility.h" -struct JSContext; -struct JSRuntime; -class JSScript; - namespace js { - class Activation; - namespace jit { - class JitActivation; - class JitProfilingFrameIterator; - class JitcodeGlobalEntry; - } // namespace jit - namespace wasm { - class ProfilingFrameIterator; - } // namespace wasm -} // namespace js +class Activation; +namespace jit { +class JitActivation; +class JSJitProfilingFrameIterator; +class JitcodeGlobalEntry; +} // namespace jit +namespace wasm { +class ProfilingFrameIterator; +} // namespace wasm +} // namespace js namespace JS { @@ -37,170 +32,199 @@ struct ForEachTrackedOptimizationTypeInfoOp; // This iterator can be used to walk the stack of a thread suspended at an -// arbitrary pc. To provide acurate results, profiling must have been enabled +// arbitrary pc. To provide accurate results, profiling must have been enabled // (via EnableRuntimeProfilingStack) before executing the callstack being // unwound. // // Note that the caller must not do anything that could cause GC to happen while // the iterator is alive, since this could invalidate Ion code and cause its // contents to become out of date. -class JS_PUBLIC_API(ProfilingFrameIterator) -{ - JSRuntime* rt_; - uint32_t sampleBufferGen_; - js::Activation* activation_; - - // When moving past a JitActivation, we need to save the prevJitTop - // from it to use as the exit-frame pointer when the next caller jit - // activation (if any) comes around. - void* savedPrevJitTop_; - - JS::AutoCheckCannotGC nogc_; - - static const unsigned StorageSpace = 8 * sizeof(void*); - mozilla::AlignedStorage storage_; - js::wasm::ProfilingFrameIterator& wasmIter() { - MOZ_ASSERT(!done()); - MOZ_ASSERT(isWasm()); - return *reinterpret_cast(storage_.addr()); - } - const js::wasm::ProfilingFrameIterator& wasmIter() const { - MOZ_ASSERT(!done()); - MOZ_ASSERT(isWasm()); - return *reinterpret_cast(storage_.addr()); - } +class MOZ_NON_PARAM JS_PUBLIC_API ProfilingFrameIterator { + public: + enum class Kind : bool { JSJit, Wasm }; + + private: + JSContext* cx_; + mozilla::Maybe samplePositionInProfilerBuffer_; + js::Activation* activation_; + Kind kind_; + + static const unsigned StorageSpace = 8 * sizeof(void*); + alignas(void*) unsigned char storage_[StorageSpace]; + + void* storage() { return storage_; } + const void* storage() const { return storage_; } + + js::wasm::ProfilingFrameIterator& wasmIter() { + MOZ_ASSERT(!done()); + MOZ_ASSERT(isWasm()); + return *static_cast(storage()); + } + const js::wasm::ProfilingFrameIterator& wasmIter() const { + MOZ_ASSERT(!done()); + MOZ_ASSERT(isWasm()); + return *static_cast(storage()); + } + + js::jit::JSJitProfilingFrameIterator& jsJitIter() { + MOZ_ASSERT(!done()); + MOZ_ASSERT(isJSJit()); + return *static_cast(storage()); + } + + const js::jit::JSJitProfilingFrameIterator& jsJitIter() const { + MOZ_ASSERT(!done()); + MOZ_ASSERT(isJSJit()); + return *static_cast(storage()); + } + + void settleFrames(); + void settle(); + + public: + struct RegisterState { + RegisterState() : pc(nullptr), sp(nullptr), fp(nullptr), lr(nullptr) {} + void* pc; + void* sp; + void* fp; + void* lr; + }; + + ProfilingFrameIterator( + JSContext* cx, const RegisterState& state, + const mozilla::Maybe& samplePositionInProfilerBuffer = + mozilla::Nothing()); + ~ProfilingFrameIterator(); + void operator++(); + bool done() const { return !activation_; } + + // Assuming the stack grows down (we do), the return value: + // - always points into the stack + // - is weakly monotonically increasing (may be equal for successive frames) + // - will compare greater than newer native and psuedo-stack frame addresses + // and less than older native and psuedo-stack frame addresses + void* stackAddress() const; + + enum FrameKind { Frame_Baseline, Frame_Ion, Frame_Wasm }; + + struct Frame { + FrameKind kind; + void* stackAddress; + void* returnAddress; + void* activation; + const char* label; + } JS_HAZ_GC_INVALIDATED; + + bool isWasm() const; + bool isJSJit() const; + + uint32_t extractStack(Frame* frames, uint32_t offset, uint32_t end) const; + + mozilla::Maybe getPhysicalFrameWithoutLabel() const; + + private: + mozilla::Maybe getPhysicalFrameAndEntry( + js::jit::JitcodeGlobalEntry* entry) const; + + void iteratorConstruct(const RegisterState& state); + void iteratorConstruct(); + void iteratorDestroy(); + bool iteratorDone(); +} JS_HAZ_GC_INVALIDATED; - js::jit::JitProfilingFrameIterator& jitIter() { - MOZ_ASSERT(!done()); - MOZ_ASSERT(isJit()); - return *reinterpret_cast(storage_.addr()); - } +JS_FRIEND_API bool IsProfilingEnabledForContext(JSContext* cx); - const js::jit::JitProfilingFrameIterator& jitIter() const { - MOZ_ASSERT(!done()); - MOZ_ASSERT(isJit()); - return *reinterpret_cast(storage_.addr()); - } +/** + * After each sample run, this method should be called with the current buffer + * position at which the buffer contents start. This will update the + * corresponding field on the JSRuntime. + * + * See the field |profilerSampleBufferRangeStart| on JSRuntime for documentation + * about what this value is used for. + */ +JS_FRIEND_API void SetJSContextProfilerSampleBufferRangeStart( + JSContext* cx, uint64_t rangeStart); - void settle(); +class ProfiledFrameRange; - bool hasSampleBufferGen() const { - return sampleBufferGen_ != UINT32_MAX; - } +// A handle to the underlying JitcodeGlobalEntry, so as to avoid repeated +// lookups on JitcodeGlobalTable. +class MOZ_STACK_CLASS ProfiledFrameHandle { + friend class ProfiledFrameRange; + + JSRuntime* rt_; + js::jit::JitcodeGlobalEntry& entry_; + void* addr_; + void* canonicalAddr_; + const char* label_; + uint32_t depth_; + mozilla::Maybe optsIndex_; + + ProfiledFrameHandle(JSRuntime* rt, js::jit::JitcodeGlobalEntry& entry, + void* addr, const char* label, uint32_t depth); + + void updateHasTrackedOptimizations(); + + public: + const char* label() const { return label_; } + uint32_t depth() const { return depth_; } + bool hasTrackedOptimizations() const { return optsIndex_.isSome(); } + void* canonicalAddress() const { return canonicalAddr_; } + + JS_PUBLIC_API ProfilingFrameIterator::FrameKind frameKind() const; + JS_PUBLIC_API void forEachOptimizationAttempt( + ForEachTrackedOptimizationAttemptOp& op, JSScript** scriptOut, + jsbytecode** pcOut) const; - public: - struct RegisterState - { - RegisterState() : pc(nullptr), sp(nullptr), lr(nullptr) {} - void* pc; - void* sp; - void* lr; - }; - - ProfilingFrameIterator(JSContext* cx, const RegisterState& state, - uint32_t sampleBufferGen = UINT32_MAX); - ~ProfilingFrameIterator(); - void operator++(); - bool done() const { return !activation_; } - - // Assuming the stack grows down (we do), the return value: - // - always points into the stack - // - is weakly monotonically increasing (may be equal for successive frames) - // - will compare greater than newer native and psuedo-stack frame addresses - // and less than older native and psuedo-stack frame addresses - void* stackAddress() const; - - enum FrameKind - { - Frame_Baseline, - Frame_Ion, - Frame_Wasm - }; - - struct Frame - { - FrameKind kind; - void* stackAddress; - void* returnAddress; - void* activation; - UniqueChars label; - }; - - bool isWasm() const; - bool isJit() const; - - uint32_t extractStack(Frame* frames, uint32_t offset, uint32_t end) const; - - mozilla::Maybe getPhysicalFrameWithoutLabel() const; - - private: - mozilla::Maybe getPhysicalFrameAndEntry(js::jit::JitcodeGlobalEntry* entry) const; - - void iteratorConstruct(const RegisterState& state); - void iteratorConstruct(); - void iteratorDestroy(); - bool iteratorDone(); + JS_PUBLIC_API void forEachOptimizationTypeInfo( + ForEachTrackedOptimizationTypeInfoOp& op) const; }; -JS_FRIEND_API(bool) -IsProfilingEnabledForContext(JSContext* cx); - -/** - * After each sample run, this method should be called with the latest sample - * buffer generation, and the lapCount. It will update corresponding fields on - * JSRuntime. - * - * See fields |profilerSampleBufferGen|, |profilerSampleBufferLapCount| on - * JSRuntime for documentation about what these values are used for. - */ -JS_FRIEND_API(void) -UpdateJSContextProfilerSampleBufferGen(JSContext* cx, uint32_t generation, - uint32_t lapCount); - -struct ForEachProfiledFrameOp -{ - // A handle to the underlying JitcodeGlobalEntry, so as to avoid repeated - // lookups on JitcodeGlobalTable. - class MOZ_STACK_CLASS FrameHandle - { - friend JS_PUBLIC_API(void) ForEachProfiledFrame(JSContext* cx, void* addr, - ForEachProfiledFrameOp& op); - - JSRuntime* rt_; - js::jit::JitcodeGlobalEntry& entry_; - void* addr_; - void* canonicalAddr_; - const char* label_; - uint32_t depth_; - mozilla::Maybe optsIndex_; - - FrameHandle(JSRuntime* rt, js::jit::JitcodeGlobalEntry& entry, void* addr, - const char* label, uint32_t depth); - - void updateHasTrackedOptimizations(); - - public: - const char* label() const { return label_; } - uint32_t depth() const { return depth_; } - bool hasTrackedOptimizations() const { return optsIndex_.isSome(); } - void* canonicalAddress() const { return canonicalAddr_; } - - 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; - }; +class ProfiledFrameRange { + public: + class Iter final { + public: + Iter(const ProfiledFrameRange& range, uint32_t index) + : range_(range), index_(index) {} + + JS_PUBLIC_API ProfiledFrameHandle operator*() const; + + // Provide the bare minimum of iterator methods that are needed for + // C++ ranged for loops. + Iter& operator++() { + ++index_; + return *this; + } + bool operator==(const Iter& rhs) { return index_ == rhs.index_; } + bool operator!=(const Iter& rhs) { return !(*this == rhs); } - // Called once per frame. - virtual void operator()(const FrameHandle& frame) = 0; + private: + const ProfiledFrameRange& range_; + uint32_t index_; + }; + + Iter begin() const { return Iter(*this, 0); } + Iter end() const { return Iter(*this, depth_); } + + private: + friend JS_PUBLIC_API ProfiledFrameRange GetProfiledFrames(JSContext* cx, + void* addr); + + ProfiledFrameRange(JSRuntime* rt, void* addr, + js::jit::JitcodeGlobalEntry* entry) + : rt_(rt), addr_(addr), entry_(entry), depth_(0) {} + + JSRuntime* rt_; + void* addr_; + js::jit::JitcodeGlobalEntry* entry_; + // Assume maximum inlining depth is <64 + const char* labels_[64]; + uint32_t depth_; }; -JS_PUBLIC_API(void) -ForEachProfiledFrame(JSContext* cx, void* addr, ForEachProfiledFrameOp& op); +// Returns a range that can be iterated over using C++ ranged for loops. +JS_PUBLIC_API ProfiledFrameRange GetProfiledFrames(JSContext* cx, void* addr); -} // namespace JS +} // namespace JS -#endif /* js_ProfilingFrameIterator_h */ +#endif /* js_ProfilingFrameIterator_h */ 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 @@ -7,202 +7,419 @@ #ifndef js_ProfilingStack_h #define js_ProfilingStack_h -#include "jsbytecode.h" +#include +#include + #include "jstypes.h" -#include "js/TypeDecls.h" +#include "js/TypeDecls.h" #include "js/Utility.h" -struct JSRuntime; class JSTracer; +class PseudoStack; + +// This file defines the classes PseudoStack and ProfileEntry. +// The PseudoStack manages an array of ProfileEntries. +// Usage: +// +// PseudoStack* pseudoStack = ...; +// +// // For CPP stack frames: +// pseudoStack->pushCppFrame(...); +// // Execute some code. When finished, pop the entry: +// pseudoStack->pop(); +// +// // For JS stack frames: +// pseudoStack->pushJSFrame(...); +// // Execute some code. When finished, pop the entry: +// pseudoStack->pop(); +// +// +// Concurrency considerations +// +// A thread's pseudo stack (and the entries inside it) is only modified by +// that thread. However, the pseudo stack can be *read* by a different thread, +// the sampler thread: Whenever the profiler wants to sample a given thread A, +// the following happens: +// (1) Thread A is suspended. +// (2) The sampler thread (thread S) reads the PseudoStack of thread A, +// including all ProfileEntries that are currently in that stack +// (pseudoStack->entries[0..pseudoStack->stackSize()]). +// (3) Thread A is resumed. +// +// Thread suspension is achieved using platform-specific APIs; refer to each +// platform's Sampler::SuspendAndSampleAndResumeThread implementation in +// platform-*.cpp for details. +// +// When the thread is suspended, the values in pseudoStack->stackPointer and in +// the entry range pseudoStack->entries[0..pseudoStack->stackPointer] need to +// be in a consistent state, so that thread S does not read partially- +// constructed profile entries. More specifically, we have two requirements: +// (1) When adding a new entry at the top of the stack, its ProfileEntry data +// needs to be put in place *before* the stackPointer is incremented, and +// the compiler + CPU need to know that this order matters. +// (2) When popping an entry from the stack and then preparing the +// ProfileEntry data for the next frame that is about to be pushed, the +// decrement of the stackPointer in pop() needs to happen *before* the +// ProfileEntry for the new frame is being popuplated, and the compiler + +// CPU need to know that this order matters. +// +// We can express the relevance of these orderings in multiple ways. +// Option A is to make stackPointer an atomic with SequentiallyConsistent +// memory ordering. This would ensure that no writes in thread A would be +// reordered across any writes to stackPointer, which satisfies requirements +// (1) and (2) at the same time. Option A is the simplest. +// Option B is to use ReleaseAcquire memory ordering both for writes to +// stackPointer *and* for writes to ProfileEntry fields. Release-stores ensure +// that all writes that happened *before this write in program order* are not +// reordered to happen after this write. ReleaseAcquire ordering places no +// requirements on the ordering of writes that happen *after* this write in +// program order. +// Using release-stores for writes to stackPointer expresses requirement (1), +// and using release-stores for writes to the ProfileEntry fields expresses +// requirement (2). +// +// Option B is more complicated than option A, but has much better performance +// on x86/64: In a microbenchmark run on a Macbook Pro from 2017, switching +// from option A to option B reduced the overhead of pushing+popping a +// ProfileEntry by 10 nanoseconds. +// On x86/64, release-stores require no explicit hardware barriers or lock +// instructions. +// On ARM/64, option B may be slower than option A, because the compiler will +// generate hardware barriers for every single release-store instead of just +// for the writes to stackPointer. However, the actual performance impact of +// this has not yet been measured on ARM, so we're currently using option B +// everywhere. This is something that we may want to change in the future once +// we've done measurements. namespace js { // A call stack can be specified to the JS engine such that all JS entry/exits // to functions push/pop an entry to/from the specified stack. // -// For more detailed information, see vm/SPSProfiler.h. +// For more detailed information, see vm/GeckoProfiler.h. // -class ProfileEntry -{ - // All fields are marked volatile to prevent the compiler from re-ordering - // instructions. Namely this sequence: - // - // entry[size] = ...; - // size++; - // - // If the size modification were somehow reordered before the stores, then - // if a sample were taken it would be examining bogus information. - // - // A ProfileEntry represents both a C++ profile entry and a JS one. - - // Descriptive string of this entry. - const char * volatile string; - - // Stack pointer for non-JS entries, the script pointer otherwise. - void * volatile spOrScript; - - // Line number for non-JS entries, the bytecode offset otherwise. - 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 : 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 - // a JS or CPP frame with `initJsFrame` or `initCppFrame` respectively. - IS_CPP_ENTRY = 0x01, - - // Indicate that copying the frame label is not necessary when taking a - // sample of the pseudostack. - FRAME_LABEL_COPY = 0x02, - - // This ProfileEntry is a dummy entry indicating the start of a run - // of JS pseudostack entries. - BEGIN_PSEUDO_JS = 0x04, - - // This flag is used to indicate that an interpreter JS entry has OSR-ed - // into baseline. - OSR = 0x08, - - // Union of all flags. - ALL = IS_CPP_ENTRY|FRAME_LABEL_COPY|BEGIN_PSEUDO_JS|OSR, - - // Mask for removing all flags except the category information. - CATEGORY_MASK = ~ALL - }; - - // Keep these in sync with devtools/client/performance/modules/categories.js - enum class Category : uint32_t { - OTHER = 0x10, - CSS = 0x20, - JS = 0x40, - GC = 0x80, - CC = 0x100, - NETWORK = 0x200, - GRAPHICS = 0x400, - STORAGE = 0x800, - EVENTS = 0x1000, - - FIRST = OTHER, - LAST = EVENTS - }; - - static_assert((static_cast(Category::FIRST) & Flags::ALL) == 0, - "The category bitflags should not intersect with the other flags!"); - - // All of these methods are marked with the 'volatile' keyword because SPS's - // representation of the stack is stored such that all ProfileEntry - // instances are volatile. These methods would not be available unless they - // were marked as volatile as well. - - bool isCpp() const volatile { return hasFlag(IS_CPP_ENTRY); } - bool isJs() const volatile { return !isCpp(); } - - bool isCopyLabel() const volatile { return hasFlag(FRAME_LABEL_COPY); } - - void setLabel(const char* aString) volatile { string = aString; } - const char* label() const volatile { return string; } - - void initJsFrame(JSScript* aScript, jsbytecode* aPc) volatile { - flags_ = 0; - spOrScript = aScript; - setPC(aPc); - } - void initCppFrame(void* aSp, uint32_t aLine) volatile { - flags_ = IS_CPP_ENTRY; - spOrScript = aSp; - lineOrPcOffset = static_cast(aLine); - } +class ProfileEntry { + // A ProfileEntry represents either a C++ profile entry or a JS one. - void setFlag(uint32_t flag) volatile { - MOZ_ASSERT(flag != IS_CPP_ENTRY); - flags_ |= flag; - } - void unsetFlag(uint32_t flag) volatile { - MOZ_ASSERT(flag != IS_CPP_ENTRY); - flags_ &= ~flag; - } - bool hasFlag(uint32_t flag) const volatile { - return bool(flags_ & flag); - } + // WARNING WARNING WARNING + // + // All the fields below are Atomic<...,ReleaseAcquire>. This is needed so + // that writes to these fields are release-writes, which ensures that + // earlier writes in this thread don't get reordered after the writes to + // these fields. In particular, the decrement of the stack pointer in + // PseudoStack::pop() is a write that *must* happen before the values in + // this ProfileEntry are changed. Otherwise, the sampler thread might see + // an inconsistent state where the stack pointer still points to a + // ProfileEntry which has already been popped off the stack and whose + // fields have now been partially repopulated with new values. + // See the "Concurrency considerations" paragraph at the top of this file + // for more details. + + // Descriptive label for this entry. Must be a static string! Can be an + // empty string, but not a null pointer. + mozilla::Atomic label_; + + // An additional descriptive string of this entry which is combined with + // |label_| in profiler output. Need not be (and usually isn't) static. Can + // be null. + mozilla::Atomic dynamicString_; + + // Stack pointer for non-JS entries, the script pointer otherwise. + mozilla::Atomic spOrScript; + + // Line number for non-JS entries, the bytecode offset otherwise. + mozilla::Atomic lineOrPcOffset; + + // Bits 0...1 hold the Kind. Bits 2...3 are unused. Bits 4...12 hold the + // Category. + mozilla::Atomic kindAndCategory_; + + static int32_t pcToOffset(JSScript* aScript, jsbytecode* aPc); + + public: + enum class Kind : uint32_t { + // A normal C++ frame. + CPP_NORMAL = 0, + + // A special C++ frame indicating the start of a run of JS pseudostack + // entries. CPP_MARKER_FOR_JS frames are ignored, except for the sp + // field. + CPP_MARKER_FOR_JS = 1, + + // A normal JS frame. + JS_NORMAL = 2, + + // An interpreter JS frame that has OSR-ed into baseline. JS_NORMAL + // frames can be converted to JS_OSR and back. JS_OSR frames are + // ignored. + JS_OSR = 3, + + KIND_MASK = 0x3, + }; + + // Keep these in sync with devtools/client/performance/modules/categories.js + enum class Category : uint32_t { + OTHER = 1u << 4, + CSS = 1u << 5, + JS = 1u << 6, + GC = 1u << 7, + CC = 1u << 8, + NETWORK = 1u << 9, + GRAPHICS = 1u << 10, + STORAGE = 1u << 11, + EVENTS = 1u << 12, + + FIRST = OTHER, + LAST = EVENTS, + + CATEGORY_MASK = ~uint32_t(Kind::KIND_MASK), + }; + + static_assert((uint32_t(Category::FIRST) & uint32_t(Kind::KIND_MASK)) == 0, + "Category overlaps with Kind"); + + bool isCpp() const { + Kind k = kind(); + return k == Kind::CPP_NORMAL || k == Kind::CPP_MARKER_FOR_JS; + } + + bool isJs() const { + Kind k = kind(); + return k == Kind::JS_NORMAL || k == Kind::JS_OSR; + } + + void setLabel(const char* aLabel) { label_ = aLabel; } + const char* label() const { return label_; } + + const char* dynamicString() const { return dynamicString_; } + + void initCppFrame(const char* aLabel, const char* aDynamicString, void* sp, + uint32_t aLine, Kind aKind, Category aCategory) { + label_ = aLabel; + dynamicString_ = aDynamicString; + spOrScript = sp; + lineOrPcOffset = static_cast(aLine); + kindAndCategory_ = uint32_t(aKind) | uint32_t(aCategory); + MOZ_ASSERT(isCpp()); + } + + void initJsFrame(const char* aLabel, const char* aDynamicString, + JSScript* aScript, jsbytecode* aPc) { + label_ = aLabel; + dynamicString_ = aDynamicString; + spOrScript = aScript; + lineOrPcOffset = pcToOffset(aScript, aPc); + kindAndCategory_ = uint32_t(Kind::JS_NORMAL) | uint32_t(Category::JS); + MOZ_ASSERT(isJs()); + } + + void setKind(Kind aKind) { + kindAndCategory_ = uint32_t(aKind) | uint32_t(category()); + } + + Kind kind() const { + return Kind(kindAndCategory_ & uint32_t(Kind::KIND_MASK)); + } + + Category category() const { + return Category(kindAndCategory_ & uint32_t(Category::CATEGORY_MASK)); + } + + void* stackAddress() const { + MOZ_ASSERT(!isJs()); + return spOrScript; + } + + JS_PUBLIC_API JSScript* script() const; + + uint32_t line() const { + MOZ_ASSERT(!isJs()); + return static_cast(lineOrPcOffset); + } + + // Note that the pointer returned might be invalid. + JSScript* rawScript() const { + MOZ_ASSERT(isJs()); + void* script = spOrScript; + return static_cast(script); + } + + // We can't know the layout of JSScript, so look in vm/GeckoProfiler.cpp. + JS_FRIEND_API jsbytecode* pc() const; + void setPC(jsbytecode* pc); + + 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. + static const int32_t NullPCOffset = -1; +}; - uint32_t flags() const volatile { - return flags_; - } +JS_FRIEND_API void SetContextProfilingStack(JSContext* cx, + PseudoStack* pseudoStack); - uint32_t category() const volatile { - return flags_ & CATEGORY_MASK; - } - void setCategory(Category c) volatile { - MOZ_ASSERT(c >= Category::FIRST); - MOZ_ASSERT(c <= Category::LAST); - flags_ &= ~CATEGORY_MASK; - setFlag(static_cast(c)); - } +// GetContextProfilingStack also exists, but it's defined in RootingAPI.h. - void setOSR() volatile { - MOZ_ASSERT(isJs()); - setFlag(OSR); - } - void unsetOSR() volatile { - MOZ_ASSERT(isJs()); - unsetFlag(OSR); - } - bool isOSR() const volatile { - return hasFlag(OSR); - } +JS_FRIEND_API void EnableContextProfilingStack(JSContext* cx, bool enabled); - void* stackAddress() const volatile { - MOZ_ASSERT(!isJs()); - return spOrScript; - } - JS_PUBLIC_API(JSScript*) script() const volatile; - uint32_t line() const volatile { - MOZ_ASSERT(!isJs()); - return static_cast(lineOrPcOffset); - } +JS_FRIEND_API void RegisterContextProfilingEventMarker(JSContext* cx, + void (*fn)(const char*)); - // Note that the pointer returned might be invalid. - JSScript* rawScript() const volatile { - MOZ_ASSERT(isJs()); - return (JSScript*)spOrScript; - } +} // namespace js - // 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. - static const int32_t NullPCOffset = -1; - - static size_t offsetOfLabel() { return offsetof(ProfileEntry, string); } - static size_t offsetOfSpOrScript() { return offsetof(ProfileEntry, spOrScript); } - static size_t offsetOfLineOrPcOffset() { return offsetof(ProfileEntry, lineOrPcOffset); } - static size_t offsetOfFlags() { return offsetof(ProfileEntry, flags_); } +// Each thread has its own PseudoStack. That thread modifies the PseudoStack, +// pushing and popping elements as necessary. +// +// The PseudoStack is also read periodically by the profiler's sampler thread. +// This happens only when the thread that owns the PseudoStack is suspended. So +// there are no genuine parallel accesses. +// +// However, it is possible for pushing/popping to be interrupted by a periodic +// sample. Because of this, we need pushing/popping to be effectively atomic. +// +// - When pushing a new entry, we increment the stack pointer -- making the new +// entry visible to the sampler thread -- only after the new entry has been +// fully written. The stack pointer is Atomic, so +// the increment is a release-store, which ensures that this store is not +// reordered before the writes of the entry. +// +// - When popping an old entry, the only operation is the decrementing of the +// stack pointer, which is obviously atomic. +// +class PseudoStack final { + public: + PseudoStack() : stackPointer(0) {} + + ~PseudoStack() { + // The label macros keep a reference to the PseudoStack to avoid a TLS + // access. If these are somehow not all cleared we will get a + // use-after-free so better to crash now. + MOZ_RELEASE_ASSERT(stackPointer == 0); + } + + void pushCppFrame(const char* label, const char* dynamicString, void* sp, + uint32_t line, js::ProfileEntry::Kind kind, + js::ProfileEntry::Category category) { + if (stackPointer < MaxEntries) { + entries[stackPointer].initCppFrame(label, dynamicString, sp, line, kind, + category); + } + + // This must happen at the end! The compiler will not reorder this + // update because stackPointer is Atomic<..., ReleaseAcquire>, so any + // the writes above will not be reordered below the stackPointer store. + // Do the read and the write as two separate statements, in order to + // make it clear that we don't need an atomic increment, which would be + // more expensive on x86 than the separate operations done here. + // This thread is the only one that ever changes the value of + // stackPointer. + uint32_t oldStackPointer = stackPointer; + stackPointer = oldStackPointer + 1; + } + + void pushJsFrame(const char* label, const char* dynamicString, + JSScript* script, jsbytecode* pc) { + if (stackPointer < MaxEntries) { + entries[stackPointer].initJsFrame(label, dynamicString, script, pc); + } + + // This must happen at the end! The compiler will not reorder this + // update because stackPointer is Atomic<..., ReleaseAcquire>, which + // makes this assignment a release-store, so the writes above will not + // be reordered to occur after the stackPointer store. + // Do the read and the write as two separate statements, in order to + // make it clear that we don't need an atomic increment, which would be + // more expensive on x86 than the separate operations done here. + // This thread is the only one that ever changes the value of + // stackPointer. + uint32_t oldStackPointer = stackPointer; + stackPointer = oldStackPointer + 1; + } + + void pop() { + MOZ_ASSERT(stackPointer > 0); + // Do the read and the write as two separate statements, in order to + // make it clear that we don't need an atomic decrement, which would be + // more expensive on x86 than the separate operations done here. + // This thread is the only one that ever changes the value of + // stackPointer. + uint32_t oldStackPointer = stackPointer; + stackPointer = oldStackPointer - 1; + } + + uint32_t stackSize() const { + return std::min(uint32_t(stackPointer), uint32_t(MaxEntries)); + } + + private: + // No copying. + PseudoStack(const PseudoStack&) = delete; + void operator=(const PseudoStack&) = delete; + + public: + static const uint32_t MaxEntries = 1024; + + // The stack entries. + js::ProfileEntry entries[MaxEntries]; + + // This may exceed MaxEntries, so instead use the stackSize() method to + // determine the number of valid samples in entries. When this is less + // than MaxEntries, it refers to the first free entry past the top of the + // in-use stack (i.e. entries[stackPointer - 1] is the top stack entry). + // + // WARNING WARNING WARNING + // + // This is an atomic variable that uses ReleaseAcquire memory ordering. + // See the "Concurrency considerations" paragraph at the top of this file + // for more details. + mozilla::Atomic stackPointer; }; -JS_FRIEND_API(void) -SetContextProfilingStack(JSContext* cx, ProfileEntry* stack, uint32_t* size, - uint32_t max); - -JS_FRIEND_API(void) -EnableContextProfilingStack(JSContext* cx, bool enabled); - -JS_FRIEND_API(void) -RegisterContextProfilingEventMarker(JSContext* cx, void (*fn)(const char*)); +namespace js { -JS_FRIEND_API(jsbytecode*) -ProfilingGetPC(JSContext* cx, JSScript* script, void* ip); +class AutoGeckoProfilerEntry; +class GeckoProfilerEntryMarker; +class GeckoProfilerBaselineOSRMarker; + +class GeckoProfilerThread { + friend class AutoGeckoProfilerEntry; + friend class GeckoProfilerEntryMarker; + friend class GeckoProfilerBaselineOSRMarker; + + PseudoStack* pseudoStack_; + + public: + GeckoProfilerThread(); + + uint32_t stackPointer() { + MOZ_ASSERT(installed()); + return pseudoStack_->stackPointer; + } + ProfileEntry* stack() { return pseudoStack_->entries; } + PseudoStack* getPseudoStack() { return pseudoStack_; } + + /* management of whether instrumentation is on or off */ + bool installed() { return pseudoStack_ != nullptr; } + + void setProfilingStack(PseudoStack* pseudoStack); + void trace(JSTracer* trc); + + /* + * Functions which are the actual instrumentation to track run information + * + * - enter: a function has started to execute + * - updatePC: updates the pc information about where a function + * is currently executing + * - exit: this function has ceased execution, and no further + * entries/exits will be made + */ + bool enter(JSContext* cx, JSScript* script, JSFunction* maybeFun); + void exit(JSScript* script, JSFunction* maybeFun); + inline void updatePC(JSContext* cx, JSScript* script, jsbytecode* pc); +}; -} // namespace js +} // namespace js -#endif /* js_ProfilingStack_h */ +#endif /* js_ProfilingStack_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ProtoKey.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ProtoKey.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/ProtoKey.h @@ -0,0 +1,150 @@ +/* -*- 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_ProtoKey_h +#define js_ProtoKey_h + +/* A higher-order macro for enumerating all JSProtoKey values. */ +/* + * Consumers define macros as follows: + * macro(name, init, clasp) + * name: The canonical name of the class. + * init: Initialization function. These are |extern "C";|, and clients + * should use |extern "C" {}| as appropriate when using this macro. + * clasp: The JSClass for this object, or "dummy" if it doesn't exist. + * + * + * Consumers wishing to iterate over all the JSProtoKey values, can use + * JS_FOR_EACH_PROTOTYPE. However, there are certain values that don't + * correspond to real constructors, like Null or constructors that are disabled + * via preprocessor directives. We still need to include these in the JSProtoKey + * list in order to maintain binary XDR compatibility, but we need to provide a + * tool to handle them differently. JS_FOR_PROTOTYPES fills this niche. + * + * Consumers pass two macros to JS_FOR_PROTOTYPES - |real| and |imaginary|. The + * former is invoked for entries that have real client-exposed constructors, and + * the latter is called for the rest. Consumers that don't care about this + * distinction can simply pass the same macro to both, which is exactly what + * JS_FOR_EACH_PROTOTYPE does. + */ + +#define CLASP(NAME) (&NAME##Class) +#define OCLASP(NAME) (&NAME##Object::class_) +#define TYPED_ARRAY_CLASP(TYPE) (&TypedArrayObject::classes[Scalar::TYPE]) +#define ERROR_CLASP(TYPE) (&ErrorObject::classes[TYPE]) + +#ifdef EXPOSE_INTL_API +#define IF_INTL(REAL, IMAGINARY) REAL +#else +#define IF_INTL(REAL, IMAGINARY) IMAGINARY +#endif + +#ifdef ENABLE_BINARYDATA +#define IF_BDATA(real, imaginary) real +#else +#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 + +#define JS_FOR_PROTOTYPES_(REAL, IMAGINARY, REAL_IF_INTL, REAL_IF_BDATA, \ + REAL_IF_SAB, REAL_IF_SIMD) \ + IMAGINARY(Null, InitNullClass, dummy) \ + REAL(Object, InitViaClassSpec, OCLASP(Plain)) \ + REAL(Function, InitViaClassSpec, &JSFunction::class_) \ + REAL(Array, InitViaClassSpec, OCLASP(Array)) \ + REAL(Boolean, InitBooleanClass, OCLASP(Boolean)) \ + REAL(JSON, InitJSONClass, CLASP(JSON)) \ + REAL(Date, InitViaClassSpec, OCLASP(Date)) \ + REAL(Math, InitMathClass, CLASP(Math)) \ + REAL(Number, InitNumberClass, OCLASP(Number)) \ + REAL(String, InitStringClass, OCLASP(String)) \ + REAL(RegExp, InitViaClassSpec, OCLASP(RegExp)) \ + REAL(Error, InitViaClassSpec, ERROR_CLASP(JSEXN_ERR)) \ + REAL(InternalError, InitViaClassSpec, ERROR_CLASP(JSEXN_INTERNALERR)) \ + REAL(EvalError, InitViaClassSpec, ERROR_CLASP(JSEXN_EVALERR)) \ + REAL(RangeError, InitViaClassSpec, ERROR_CLASP(JSEXN_RANGEERR)) \ + REAL(ReferenceError, InitViaClassSpec, ERROR_CLASP(JSEXN_REFERENCEERR)) \ + REAL(SyntaxError, InitViaClassSpec, ERROR_CLASP(JSEXN_SYNTAXERR)) \ + REAL(TypeError, InitViaClassSpec, ERROR_CLASP(JSEXN_TYPEERR)) \ + REAL(URIError, InitViaClassSpec, ERROR_CLASP(JSEXN_URIERR)) \ + REAL(DebuggeeWouldRun, InitViaClassSpec, \ + ERROR_CLASP(JSEXN_DEBUGGEEWOULDRUN)) \ + REAL(CompileError, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMCOMPILEERROR)) \ + REAL(LinkError, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMLINKERROR)) \ + REAL(RuntimeError, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMRUNTIMEERROR)) \ + IMAGINARY(Iterator, dummy, dummy) \ + REAL(ArrayBuffer, InitViaClassSpec, OCLASP(ArrayBuffer)) \ + REAL(Int8Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Int8)) \ + REAL(Uint8Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8)) \ + REAL(Int16Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Int16)) \ + REAL(Uint16Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint16)) \ + REAL(Int32Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Int32)) \ + REAL(Uint32Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint32)) \ + REAL(Float32Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Float32)) \ + REAL(Float64Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Float64)) \ + REAL(Uint8ClampedArray, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8Clamped)) \ + REAL(Proxy, InitProxyClass, js::ProxyClassPtr) \ + REAL(WeakMap, InitWeakMapClass, OCLASP(WeakMap)) \ + REAL(Map, InitViaClassSpec, OCLASP(Map)) \ + REAL(Set, InitViaClassSpec, OCLASP(Set)) \ + REAL(DataView, InitViaClassSpec, OCLASP(DataView)) \ + REAL(Symbol, InitSymbolClass, OCLASP(Symbol)) \ + REAL_IF_SAB(SharedArrayBuffer, InitViaClassSpec, OCLASP(SharedArrayBuffer)) \ + REAL_IF_INTL(Intl, InitIntlClass, CLASP(Intl)) \ + REAL_IF_BDATA(TypedObject, InitTypedObjectModuleObject, \ + OCLASP(TypedObjectModule)) \ + REAL(Reflect, InitReflect, nullptr) \ + REAL_IF_SIMD(SIMD, InitSimdClass, OCLASP(Simd)) \ + REAL(WeakSet, InitWeakSetClass, OCLASP(WeakSet)) \ + REAL(TypedArray, InitViaClassSpec, \ + &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \ + REAL_IF_SAB(Atomics, InitAtomicsClass, OCLASP(Atomics)) \ + REAL(SavedFrame, InitViaClassSpec, &js::SavedFrame::class_) \ + REAL(Promise, InitViaClassSpec, OCLASP(Promise)) \ + REAL(ReadableStream, InitViaClassSpec, &js::ReadableStream::class_) \ + REAL(ReadableStreamDefaultReader, InitViaClassSpec, \ + &js::ReadableStreamDefaultReader::class_) \ + REAL(ReadableStreamBYOBReader, InitViaClassSpec, \ + &js::ReadableStreamBYOBReader::class_) \ + REAL(ReadableStreamDefaultController, InitViaClassSpec, \ + &js::ReadableStreamDefaultController::class_) \ + REAL(ReadableByteStreamController, InitViaClassSpec, \ + &js::ReadableByteStreamController::class_) \ + REAL(ReadableStreamBYOBRequest, InitViaClassSpec, \ + &js::ReadableStreamBYOBRequest::class_) \ + IMAGINARY(WritableStream, dummy, dummy) \ + IMAGINARY(WritableStreamDefaultWriter, dummy, dummy) \ + IMAGINARY(WritableStreamDefaultController, dummy, dummy) \ + REAL(ByteLengthQueuingStrategy, InitViaClassSpec, \ + &js::ByteLengthQueuingStrategy::class_) \ + REAL(CountQueuingStrategy, InitViaClassSpec, \ + &js::CountQueuingStrategy::class_) \ + REAL(WebAssembly, InitWebAssemblyClass, CLASP(WebAssembly)) \ + IMAGINARY(WasmModule, dummy, dummy) \ + IMAGINARY(WasmInstance, dummy, dummy) \ + IMAGINARY(WasmMemory, dummy, dummy) \ + IMAGINARY(WasmTable, dummy, dummy) \ + IMAGINARY(WasmGlobal, dummy, dummy) + +#define JS_FOR_PROTOTYPES(REAL, IMAGINARY) \ + JS_FOR_PROTOTYPES_(REAL, IMAGINARY, IF_INTL(REAL, IMAGINARY), \ + IF_BDATA(REAL, IMAGINARY), IF_SAB(REAL, IMAGINARY), \ + IF_SIMD(REAL, IMAGINARY)) + +#define JS_FOR_EACH_PROTOTYPE(MACRO) JS_FOR_PROTOTYPES(MACRO, MACRO) + +#endif /* js_ProtoKey_h */ 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 @@ -32,8 +32,9 @@ using JS::PropertyDescriptor; using JS::Value; -class RegExpGuard; -class JS_FRIEND_API(Wrapper); +class RegExpShared; + +class JS_FRIEND_API Wrapper; /* * A proxy is a JSObject with highly customizable behavior. ES6 specifies a @@ -146,243 +147,293 @@ * * Important: If you add a method here, you should probably also add a * Proxy::foo entry point with an AutoEnterPolicy. If you don't, you need an - * explicit override for the method in SecurityWrapper. See bug 945826 comment 0. + * explicit override for the method in SecurityWrapper. See bug 945826 comment + * 0. */ -class JS_FRIEND_API(BaseProxyHandler) -{ - /* - * Sometimes it's desirable to designate groups of proxy handlers as "similar". - * For this, we use the notion of a "family": A consumer-provided opaque pointer - * that designates the larger group to which this proxy belongs. - * - * If it will never be important to differentiate this proxy from others as - * part of a distinct group, nullptr may be used instead. - */ - const void* mFamily; - - /* - * Proxy handlers can use mHasPrototype to request the following special - * treatment from the JS engine: - * - * - When mHasPrototype is true, the engine never calls these methods: - * getPropertyDescriptor, has, set, enumerate, iterate. Instead, for - * these operations, it calls the "own" methods like - * getOwnPropertyDescriptor, hasOwn, defineProperty, - * getOwnEnumerablePropertyKeys, etc., and consults the prototype chain - * if needed. - * - * - When mHasPrototype is true, the engine calls handler->get() only if - * handler->hasOwn() says an own property exists on the proxy. If not, - * it consults the prototype chain. - * - * This is useful because it frees the ProxyHandler from having to implement - * any behavior having to do with the prototype chain. - */ - bool mHasPrototype; - - /* - * All proxies indicate whether they have any sort of interesting security - * policy that might prevent the caller from doing something it wants to - * the object. In the case of wrappers, this distinction is used to - * determine whether the caller may strip off the wrapper if it so desires. - */ - bool mHasSecurityPolicy; - - public: - explicit constexpr BaseProxyHandler(const void* aFamily, bool aHasPrototype = false, - bool aHasSecurityPolicy = false) +class JS_FRIEND_API BaseProxyHandler { + /* + * Sometimes it's desirable to designate groups of proxy handlers as + * "similar". For this, we use the notion of a "family": A consumer-provided + * opaque pointer that designates the larger group to which this proxy + * belongs. + * + * If it will never be important to differentiate this proxy from others as + * part of a distinct group, nullptr may be used instead. + */ + const void* mFamily; + + /* + * Proxy handlers can use mHasPrototype to request the following special + * treatment from the JS engine: + * + * - When mHasPrototype is true, the engine never calls these methods: + * getPropertyDescriptor, has, set, enumerate, iterate. Instead, for + * these operations, it calls the "own" methods like + * getOwnPropertyDescriptor, hasOwn, defineProperty, + * getOwnEnumerablePropertyKeys, etc., and consults the prototype chain + * if needed. + * + * - When mHasPrototype is true, the engine calls handler->get() only if + * handler->hasOwn() says an own property exists on the proxy. If not, + * it consults the prototype chain. + * + * This is useful because it frees the ProxyHandler from having to implement + * any behavior having to do with the prototype chain. + */ + bool mHasPrototype; + + /* + * All proxies indicate whether they have any sort of interesting security + * policy that might prevent the caller from doing something it wants to + * the object. In the case of wrappers, this distinction is used to + * determine whether the caller may strip off the wrapper if it so desires. + */ + bool mHasSecurityPolicy; + + public: + explicit constexpr BaseProxyHandler(const void* aFamily, + bool aHasPrototype = false, + bool aHasSecurityPolicy = false) : mFamily(aFamily), mHasPrototype(aHasPrototype), - mHasSecurityPolicy(aHasSecurityPolicy) - { } + mHasSecurityPolicy(aHasSecurityPolicy) {} - bool hasPrototype() const { - return mHasPrototype; - } - - bool hasSecurityPolicy() const { - return mHasSecurityPolicy; - } - - inline const void* family() const { - return mFamily; - } - static size_t offsetOfFamily() { - return offsetof(BaseProxyHandler, mFamily); - } - - 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. - */ - 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| - * on the proxy's |id| property. In the case when |act| is CALL, |id| is - * generally JSID_VOID. - * - * The |act| parameter to enter() specifies the action being performed. - * If |bp| is false, the method suggests that the caller throw (though it - * may still decide to squelch the error). - * - * We make these OR-able so that assertEnteredPolicy can pass a union of them. - * For example, get{,Own}PropertyDescriptor is invoked by calls to ::get() - * ::set(), in addition to being invoked on its own, so there are several - * valid Actions that could have been entered. - */ - typedef uint32_t Action; - enum { - NONE = 0x00, - GET = 0x01, - SET = 0x02, - CALL = 0x04, - ENUMERATE = 0x08, - GET_PROPERTY_DESCRIPTOR = 0x10 - }; - - virtual bool enter(JSContext* cx, HandleObject wrapper, HandleId id, Action act, - bool* bp) const; - - /* Standard internal methods. */ - virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const = 0; - virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, - ObjectOpResult& result) const = 0; - virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy, - AutoIdVector& props) const = 0; - virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id, - ObjectOpResult& result) const = 0; + bool hasPrototype() const { return mHasPrototype; } - /* - * These methods are standard, but the engine does not normally call them. - * They're opt-in. See "Proxy prototype chains" above. - * - * getPrototype() crashes if called. setPrototype() throws a TypeError. - */ - virtual bool getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const; - virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, - ObjectOpResult& result) const; - - /* 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, - ObjectOpResult& result) const = 0; - virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const = 0; + bool hasSecurityPolicy() const { return mHasSecurityPolicy; } + + inline const void* family() const { return mFamily; } + static size_t offsetOfFamily() { return offsetof(BaseProxyHandler, mFamily); } + virtual bool finalizeInBackground(const Value& priv) const { /* - * These standard internal methods are implemented, as a convenience, so - * that ProxyHandler subclasses don't have to provide every single method. - * - * The base-class implementations work by calling getPropertyDescriptor(). - * They do not follow any standard. When in doubt, override them. + * Called on creation of a proxy to determine whether its finalize + * method can be finalized on the background thread. */ - virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const; - virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, - HandleId id, MutableHandleValue vp) const; - virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result) const; + return true; + } + virtual bool canNurseryAllocate() const { /* - * [[Call]] and [[Construct]] are standard internal methods but according - * to the spec, they are not present on every object. - * - * SpiderMonkey never calls a proxy's call()/construct() internal method - * unless isCallable()/isConstructor() returns true for that proxy. - * - * BaseProxyHandler::isCallable()/isConstructor() always return false, and - * BaseProxyHandler::call()/construct() crash if called. So if you're - * creating a kind of that is never callable, you don't have to override - * anything, but otherwise you probably want to override all four. + * Nursery allocation is allowed if and only if it is safe to not + * run |finalize| when the ProxyObject dies. */ - virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const; - virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const; + return false; + } - /* SpiderMonkey extensions. */ - virtual bool enumerate(JSContext* cx, HandleObject proxy, MutableHandleObject objp) const; - virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - 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; - virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, - const CallArgs& args) const; - virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp) const; - virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, - 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; - virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const; - virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const; - virtual void trace(JSTracer* trc, JSObject* proxy) const; - virtual void finalize(JSFreeOp* fop, JSObject* proxy) const; - virtual void objectMoved(JSObject* proxy, const JSObject* old) const; - - // Allow proxies, wrappers in particular, to specify callability at runtime. - // Note: These do not take const JSObject*, but they do in spirit. - // We are not prepared to do this, as there's little const correctness - // in the external APIs that handle proxies. - virtual bool isCallable(JSObject* obj) const; - virtual bool isConstructor(JSObject* obj) const; - - // These two hooks must be overridden, or not overridden, in tandem -- no - // overriding just one! - virtual bool watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, - JS::HandleObject callable) const; - virtual bool unwatch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id) const; - - virtual bool getElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end, - ElementAdder* adder) const; - - /* See comment for weakmapKeyDelegateOp in js/Class.h. */ - virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const; - virtual bool isScripted() const { return false; } + /* Policy enforcement methods. + * + * enter() allows the policy to specify whether the caller may perform |act| + * on the proxy's |id| property. In the case when |act| is CALL, |id| is + * generally JSID_VOID. The |mayThrow| parameter indicates whether a + * handler that wants to throw custom exceptions when denying should do so + * or not. + * + * The |act| parameter to enter() specifies the action being performed. + * If |bp| is false, the method suggests that the caller throw (though it + * may still decide to squelch the error). + * + * We make these OR-able so that assertEnteredPolicy can pass a union of them. + * For example, get{,Own}PropertyDescriptor is invoked by calls to ::get() + * ::set(), in addition to being invoked on its own, so there are several + * valid Actions that could have been entered. + */ + typedef uint32_t Action; + enum { + NONE = 0x00, + GET = 0x01, + SET = 0x02, + CALL = 0x04, + ENUMERATE = 0x08, + GET_PROPERTY_DESCRIPTOR = 0x10 + }; + + virtual bool enter(JSContext* cx, HandleObject wrapper, HandleId id, + Action act, bool mayThrow, bool* bp) const; + + /* Standard internal methods. */ + virtual bool getOwnPropertyDescriptor( + JSContext* cx, HandleObject proxy, HandleId id, + MutableHandle desc) const = 0; + virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, + Handle desc, + ObjectOpResult& result) const = 0; + virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy, + AutoIdVector& props) const = 0; + virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id, + ObjectOpResult& result) const = 0; + + /* + * These methods are standard, but the engine does not normally call them. + * They're opt-in. See "Proxy prototype chains" above. + * + * getPrototype() crashes if called. setPrototype() throws a TypeError. + */ + virtual bool getPrototype(JSContext* cx, HandleObject proxy, + MutableHandleObject protop) const; + virtual bool setPrototype(JSContext* cx, HandleObject proxy, + HandleObject proto, ObjectOpResult& result) const; + + /* 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, + ObjectOpResult& result) const = 0; + virtual bool isExtensible(JSContext* cx, HandleObject proxy, + bool* extensible) const = 0; + + /* + * These standard internal methods are implemented, as a convenience, so + * that ProxyHandler subclasses don't have to provide every single method. + * + * The base-class implementations work by calling getPropertyDescriptor(). + * They do not follow any standard. When in doubt, override them. + */ + virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, + bool* bp) const; + virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, + HandleId id, MutableHandleValue vp) const; + virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, + HandleValue v, HandleValue receiver, + ObjectOpResult& result) const; + + /* + * [[Call]] and [[Construct]] are standard internal methods but according + * to the spec, they are not present on every object. + * + * SpiderMonkey never calls a proxy's call()/construct() internal method + * unless isCallable()/isConstructor() returns true for that proxy. + * + * BaseProxyHandler::isCallable()/isConstructor() always return false, and + * BaseProxyHandler::call()/construct() crash if called. So if you're + * creating a kind of that is never callable, you don't have to override + * anything, but otherwise you probably want to override all four. + */ + virtual bool call(JSContext* cx, HandleObject proxy, + const CallArgs& args) const; + virtual bool construct(JSContext* cx, HandleObject proxy, + const CallArgs& args) const; + + /* SpiderMonkey extensions. */ + virtual JSObject* enumerate(JSContext* cx, HandleObject proxy) const; + virtual bool getPropertyDescriptor( + JSContext* cx, HandleObject proxy, HandleId id, + 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; + virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, + const CallArgs& args) const; + virtual bool hasInstance(JSContext* cx, HandleObject proxy, + MutableHandleValue v, bool* bp) const; + virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, + 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, + bool isToSource) const; + virtual RegExpShared* regexp_toShared(JSContext* cx, + HandleObject proxy) const; + virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, + MutableHandleValue vp) const; + virtual void trace(JSTracer* trc, JSObject* proxy) const; + virtual void finalize(JSFreeOp* fop, JSObject* proxy) const; + virtual size_t objectMoved(JSObject* proxy, JSObject* old) const; + + // Allow proxies, wrappers in particular, to specify callability at runtime. + // Note: These do not take const JSObject*, but they do in spirit. + // We are not prepared to do this, as there's little const correctness + // in the external APIs that handle proxies. + virtual bool isCallable(JSObject* obj) const; + virtual bool isConstructor(JSObject* obj) const; + + virtual bool getElements(JSContext* cx, HandleObject proxy, uint32_t begin, + uint32_t end, ElementAdder* adder) const; + + /* See comment for weakmapKeyDelegateOp in js/Class.h. */ + virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const; + virtual bool isScripted() const { return false; } }; -extern JS_FRIEND_DATA(const js::Class* const) ProxyClassPtr; +extern JS_FRIEND_DATA const js::Class* const ProxyClassPtr; -inline bool IsProxy(const JSObject* obj) -{ - return GetObjectClass(obj)->isProxy(); +inline bool IsProxy(const JSObject* obj) { + 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 -// private slot to be the first slot in the proxy's values, so that the private -// slot can be accessed in the same fashion as the first reserved slot, via -// {Get,Set}ReservedOrProxyPrivateSlot. - -struct ProxyValueArray -{ - Value privateSlot; - Value extraSlots[PROXY_EXTRA_SLOTS]; - - ProxyValueArray() - : privateSlot(JS::UndefinedValue()) - { - for (size_t i = 0; i < PROXY_EXTRA_SLOTS; i++) - extraSlots[i] = JS::UndefinedValue(); - } +// Proxy slot layout +// ----------------- +// +// Every proxy has a ProxyValueArray that contains the following Values: +// +// - The private slot. +// - The reserved slots. The number of slots is determined by the proxy's Class. +// +// Proxy objects store a pointer to the reserved slots (ProxyReservedSlots*). +// The ProxyValueArray and the private slot can be accessed using +// ProxyValueArray::fromReservedSlots or ProxyDataLayout::values. +// +// Storing a pointer to ProxyReservedSlots instead of ProxyValueArray has a +// number of advantages. In particular, it means js::GetReservedSlot and +// js::SetReservedSlot can be used with both proxies and native objects. This +// works because the ProxyReservedSlots* pointer is stored where native objects +// store their dynamic slots pointer. + +struct ProxyReservedSlots { + Value slots[1]; + + static inline int offsetOfPrivateSlot(); + + static inline int offsetOfSlot(size_t slot) { + return offsetof(ProxyReservedSlots, slots[0]) + slot * sizeof(Value); + } + + void init(size_t nreserved) { + for (size_t i = 0; i < nreserved; i++) slots[i] = JS::UndefinedValue(); + } + + ProxyReservedSlots(const ProxyReservedSlots&) = delete; + void operator=(const ProxyReservedSlots&) = delete; +}; + +struct ProxyValueArray { + Value privateSlot; + ProxyReservedSlots reservedSlots; + + void init(size_t nreserved) { + privateSlot = JS::UndefinedValue(); + reservedSlots.init(nreserved); + } + + static size_t sizeOf(size_t nreserved) { + return offsetOfReservedSlots() + nreserved * sizeof(Value); + } + static MOZ_ALWAYS_INLINE ProxyValueArray* fromReservedSlots( + ProxyReservedSlots* slots) { + uintptr_t p = reinterpret_cast(slots); + return reinterpret_cast(p - offsetOfReservedSlots()); + } + static size_t offsetOfReservedSlots() { + return offsetof(ProxyValueArray, reservedSlots); + } + + ProxyValueArray(const ProxyValueArray&) = delete; + void operator=(const ProxyValueArray&) = delete; }; +/* static */ inline int ProxyReservedSlots::offsetOfPrivateSlot() { + return -int(ProxyValueArray::offsetOfReservedSlots()) + + offsetof(ProxyValueArray, privateSlot); +} + // All proxies share the same data layout. Following the object's shape and // type, the proxy has a ProxyDataLayout structure with a pointer to an array // of values and the proxy's handler. This is designed both so that proxies can @@ -391,241 +442,268 @@ // that common code can access either type of object. // // See GetReservedOrProxyPrivateSlot below. -struct ProxyDataLayout -{ - ProxyValueArray* values; - const BaseProxyHandler* handler; +struct ProxyDataLayout { + ProxyReservedSlots* reservedSlots; + const BaseProxyHandler* handler; + + MOZ_ALWAYS_INLINE ProxyValueArray* values() const { + return ProxyValueArray::fromReservedSlots(reservedSlots); + } }; const uint32_t ProxyDataOffset = 2 * sizeof(void*); -inline ProxyDataLayout* -GetProxyDataLayout(JSObject* obj) -{ - MOZ_ASSERT(IsProxy(obj)); - return reinterpret_cast(reinterpret_cast(obj) + ProxyDataOffset); +inline ProxyDataLayout* GetProxyDataLayout(JSObject* obj) { + MOZ_ASSERT(IsProxy(obj)); + 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); +inline const ProxyDataLayout* GetProxyDataLayout(const JSObject* obj) { + MOZ_ASSERT(IsProxy(obj)); + return reinterpret_cast( + reinterpret_cast(obj) + ProxyDataOffset); } -} // namespace detail +} // namespace detail -inline const BaseProxyHandler* -GetProxyHandler(const JSObject* obj) -{ - return detail::GetProxyDataLayout(obj)->handler; +inline const BaseProxyHandler* GetProxyHandler(const JSObject* obj) { + return detail::GetProxyDataLayout(obj)->handler; } -inline const Value& -GetProxyPrivate(const JSObject* obj) -{ - return detail::GetProxyDataLayout(obj)->values->privateSlot; +inline const Value& GetProxyPrivate(const JSObject* obj) { + return detail::GetProxyDataLayout(obj)->values()->privateSlot; } -inline JSObject* -GetProxyTargetObject(JSObject* obj) -{ - return GetProxyPrivate(obj).toObjectOrNull(); +inline JSObject* GetProxyTargetObject(JSObject* obj) { + return GetProxyPrivate(obj).toObjectOrNull(); } -inline const Value& -GetProxyExtra(const JSObject* obj, size_t n) -{ - MOZ_ASSERT(n < detail::PROXY_EXTRA_SLOTS); - return detail::GetProxyDataLayout(obj)->values->extraSlots[n]; +inline const Value& GetProxyReservedSlot(const JSObject* obj, size_t n) { + MOZ_ASSERT(n < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); + return detail::GetProxyDataLayout(obj)->reservedSlots->slots[n]; } -inline void -SetProxyHandler(JSObject* obj, const BaseProxyHandler* handler) -{ - detail::GetProxyDataLayout(obj)->handler = handler; +inline void SetProxyHandler(JSObject* obj, const BaseProxyHandler* handler) { + detail::GetProxyDataLayout(obj)->handler = handler; } -JS_FRIEND_API(void) -SetValueInProxy(Value* slot, const Value& value); +JS_FRIEND_API void SetValueInProxy(Value* slot, const Value& value); -inline void -SetProxyExtra(JSObject* obj, size_t n, const Value& extra) -{ - MOZ_ASSERT(n < detail::PROXY_EXTRA_SLOTS); - Value* vp = &detail::GetProxyDataLayout(obj)->values->extraSlots[n]; +inline void SetProxyReservedSlot(JSObject* obj, size_t n, const Value& extra) { + MOZ_ASSERT(n < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); + MOZ_ASSERT_IF(gc::detail::ObjectIsMarkedBlack(obj), + JS::ValueIsNotGray(extra)); - // Trigger a barrier before writing the slot. - if (vp->isMarkable() || extra.isMarkable()) - SetValueInProxy(vp, extra); - else - *vp = extra; -} + Value* vp = &detail::GetProxyDataLayout(obj)->reservedSlots->slots[n]; -inline bool -IsScriptedProxy(const JSObject* obj) -{ - return IsProxy(obj) && GetProxyHandler(obj)->isScripted(); + // Trigger a barrier before writing the slot. + if (vp->isGCThing() || extra.isGCThing()) + SetValueInProxy(vp, extra); + else + *vp = extra; } -inline const Value& -GetReservedOrProxyPrivateSlot(const JSObject* obj, size_t slot) -{ - MOZ_ASSERT(slot == 0); - MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)) || IsProxy(obj)); - return reinterpret_cast(obj)->slotRef(slot); +inline void SetProxyPrivate(JSObject* obj, const Value& value) { + MOZ_ASSERT_IF(gc::detail::ObjectIsMarkedBlack(obj), + JS::ValueIsNotGray(value)); + + Value* vp = &detail::GetProxyDataLayout(obj)->values()->privateSlot; + + // Trigger a barrier before writing the slot. + if (vp->isGCThing() || value.isGCThing()) + SetValueInProxy(vp, value); + else + *vp = value; } -inline void -SetReservedOrProxyPrivateSlot(JSObject* obj, size_t slot, const Value& value) -{ - MOZ_ASSERT(slot == 0); - MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)) || IsProxy(obj)); - shadow::Object* sobj = reinterpret_cast(obj); - if (sobj->slotRef(slot).isMarkable() || value.isMarkable()) - SetReservedOrProxyPrivateSlotWithBarrier(obj, slot, value); - else - sobj->slotRef(slot) = value; +inline bool IsScriptedProxy(const JSObject* obj) { + return IsProxy(obj) && GetProxyHandler(obj)->isScripted(); } class MOZ_STACK_CLASS ProxyOptions { - protected: - /* protected constructor for subclass */ - explicit ProxyOptions(bool singletonArg, bool lazyProtoArg = false) + protected: + /* protected constructor for subclass */ + explicit ProxyOptions(bool singletonArg, bool lazyProtoArg = false) : singleton_(singletonArg), lazyProto_(lazyProtoArg), - clasp_(ProxyClassPtr) - {} + clasp_(ProxyClassPtr) {} - public: - ProxyOptions() : singleton_(false), - lazyProto_(false), - clasp_(ProxyClassPtr) - {} - - bool singleton() const { return singleton_; } - ProxyOptions& setSingleton(bool flag) { - singleton_ = flag; - return *this; - } - - bool lazyProto() const { return lazyProto_; } - ProxyOptions& setLazyProto(bool flag) { - lazyProto_ = flag; - return *this; - } - - const Class* clasp() const { - return clasp_; - } - ProxyOptions& setClass(const Class* claspArg) { - clasp_ = claspArg; - return *this; - } - - private: - bool singleton_; - bool lazyProto_; - const Class* clasp_; + public: + ProxyOptions() + : singleton_(false), lazyProto_(false), clasp_(ProxyClassPtr) {} + + bool singleton() const { return singleton_; } + ProxyOptions& setSingleton(bool flag) { + singleton_ = flag; + return *this; + } + + bool lazyProto() const { return lazyProto_; } + ProxyOptions& setLazyProto(bool flag) { + lazyProto_ = flag; + return *this; + } + + const Class* clasp() const { return clasp_; } + ProxyOptions& setClass(const Class* claspArg) { + clasp_ = claspArg; + return *this; + } + + private: + bool singleton_; + bool lazyProto_; + const Class* clasp_; }; -JS_FRIEND_API(JSObject*) -NewProxyObject(JSContext* cx, const BaseProxyHandler* handler, HandleValue priv, - JSObject* proto, const ProxyOptions& options = ProxyOptions()); - -JSObject* -RenewProxyObject(JSContext* cx, JSObject* obj, BaseProxyHandler* handler, const Value& priv); - -class JS_FRIEND_API(AutoEnterPolicy) -{ - public: - typedef BaseProxyHandler::Action Action; - AutoEnterPolicy(JSContext* cx, const BaseProxyHandler* handler, - HandleObject wrapper, HandleId id, Action act, bool mayThrow) +JS_FRIEND_API JSObject* NewProxyObject( + JSContext* cx, const BaseProxyHandler* handler, HandleValue priv, + JSObject* proto, const ProxyOptions& options = ProxyOptions()); + +JSObject* RenewProxyObject(JSContext* cx, JSObject* obj, + BaseProxyHandler* handler, const Value& priv); + +class JS_FRIEND_API AutoEnterPolicy { + public: + typedef BaseProxyHandler::Action Action; + AutoEnterPolicy(JSContext* cx, const BaseProxyHandler* handler, + HandleObject wrapper, HandleId id, Action act, bool mayThrow) #ifdef JS_DEBUG - : context(nullptr) + : context(nullptr) #endif - { - allow = handler->hasSecurityPolicy() ? handler->enter(cx, wrapper, id, act, &rv) - : true; - recordEnter(cx, wrapper, id, act); - // We want to throw an exception if all of the following are true: - // * The policy disallowed access. - // * The policy set rv to false, indicating that we should throw. - // * The caller did not instruct us to ignore exceptions. - // * The policy did not throw itself. - if (!allow && !rv && mayThrow) - reportErrorIfExceptionIsNotPending(cx, id); - } - - virtual ~AutoEnterPolicy() { recordLeave(); } - inline bool allowed() { return allow; } - inline bool returnValue() { MOZ_ASSERT(!allowed()); return rv; } - - protected: - // no-op constructor for subclass - AutoEnterPolicy() + { + allow = handler->hasSecurityPolicy() + ? handler->enter(cx, wrapper, id, act, mayThrow, &rv) + : true; + recordEnter(cx, wrapper, id, act); + // We want to throw an exception if all of the following are true: + // * The policy disallowed access. + // * The policy set rv to false, indicating that we should throw. + // * The caller did not instruct us to ignore exceptions. + // * The policy did not throw itself. + if (!allow && !rv && mayThrow) reportErrorIfExceptionIsNotPending(cx, id); + } + + virtual ~AutoEnterPolicy() { recordLeave(); } + inline bool allowed() { return allow; } + inline bool returnValue() { + MOZ_ASSERT(!allowed()); + return rv; + } + + protected: + // no-op constructor for subclass + AutoEnterPolicy() #ifdef JS_DEBUG - : context(nullptr) - , enteredAction(BaseProxyHandler::NONE) + : context(nullptr), + enteredAction(BaseProxyHandler::NONE) #endif - {} - void reportErrorIfExceptionIsNotPending(JSContext* cx, jsid id); - bool allow; - bool rv; + { + } + void reportErrorIfExceptionIsNotPending(JSContext* cx, jsid id); + bool allow; + bool rv; #ifdef JS_DEBUG - JSContext* context; - mozilla::Maybe enteredProxy; - mozilla::Maybe enteredId; - Action enteredAction; - - // NB: We explicitly don't track the entered action here, because sometimes - // set() methods do an implicit get() during their implementation, leading - // to spurious assertions. - AutoEnterPolicy* prev; - void recordEnter(JSContext* cx, HandleObject proxy, HandleId id, Action act); - void recordLeave(); + JSContext* context; + mozilla::Maybe enteredProxy; + mozilla::Maybe enteredId; + Action enteredAction; + + // NB: We explicitly don't track the entered action here, because sometimes + // set() methods do an implicit get() during their implementation, leading + // to spurious assertions. + AutoEnterPolicy* prev; + void recordEnter(JSContext* cx, HandleObject proxy, HandleId id, Action act); + void recordLeave(); - friend JS_FRIEND_API(void) assertEnteredPolicy(JSContext* cx, JSObject* proxy, jsid id, Action act); + friend JS_FRIEND_API void assertEnteredPolicy(JSContext* cx, JSObject* proxy, + jsid id, Action act); #else - inline void recordEnter(JSContext* cx, JSObject* proxy, jsid id, Action act) {} - inline void recordLeave() {} + inline void recordEnter(JSContext* cx, JSObject* proxy, jsid id, Action act) { + } + inline void recordLeave() {} #endif + private: + // This operator needs to be deleted explicitly, otherwise Visual C++ will + // create it automatically when it is part of the export JS API. In that + // case, compile would fail because HandleId is not allowed to be assigned + // and consequently instantiation of assign operator of mozilla::Maybe + // would fail. See bug 1325351 comment 16. Copy constructor is removed at + // the same time for consistency. + AutoEnterPolicy(const AutoEnterPolicy&) = delete; + AutoEnterPolicy& operator=(const AutoEnterPolicy&) = delete; }; #ifdef JS_DEBUG -class JS_FRIEND_API(AutoWaivePolicy) : public AutoEnterPolicy { -public: - AutoWaivePolicy(JSContext* cx, HandleObject proxy, HandleId id, - BaseProxyHandler::Action act) - { - allow = true; - recordEnter(cx, proxy, id, act); - } +class JS_FRIEND_API AutoWaivePolicy : public AutoEnterPolicy { + public: + AutoWaivePolicy(JSContext* cx, HandleObject proxy, HandleId id, + BaseProxyHandler::Action act) { + allow = true; + recordEnter(cx, proxy, id, act); + } }; #else -class JS_FRIEND_API(AutoWaivePolicy) { - public: - AutoWaivePolicy(JSContext* cx, HandleObject proxy, HandleId id, - BaseProxyHandler::Action act) - {} +class JS_FRIEND_API AutoWaivePolicy { + public: + AutoWaivePolicy(JSContext* cx, HandleObject proxy, HandleId id, + BaseProxyHandler::Action act) {} }; #endif #ifdef JS_DEBUG -extern JS_FRIEND_API(void) -assertEnteredPolicy(JSContext* cx, JSObject* obj, jsid id, - BaseProxyHandler::Action act); +extern JS_FRIEND_API void assertEnteredPolicy(JSContext* cx, JSObject* obj, + jsid id, + BaseProxyHandler::Action act); #else inline void assertEnteredPolicy(JSContext* cx, JSObject* obj, jsid id, - BaseProxyHandler::Action act) -{} + BaseProxyHandler::Action act) {} #endif -extern JS_FRIEND_API(JSObject*) -InitProxyClass(JSContext* cx, JS::HandleObject obj); +extern JS_FRIEND_API JSObject* InitProxyClass(JSContext* cx, + JS::HandleObject obj); + +extern JS_FRIEND_DATA const js::ClassOps ProxyClassOps; +extern JS_FRIEND_DATA const js::ClassExtension ProxyClassExtension; +extern JS_FRIEND_DATA const js::ObjectOps ProxyObjectOps; + +template +constexpr unsigned CheckProxyFlags() { + // For now assert each Proxy Class has at least 1 reserved slot. This is + // not a hard requirement, but helps catch Classes that need an explicit + // JSCLASS_HAS_RESERVED_SLOTS since bug 1360523. + static_assert(((Flags >> JSCLASS_RESERVED_SLOTS_SHIFT) & + JSCLASS_RESERVED_SLOTS_MASK) > 0, + "Proxy Classes must have at least 1 reserved slot"); + + // ProxyValueArray must fit inline in the object, so assert the number of + // slots does not exceed MAX_FIXED_SLOTS. + static_assert( + (offsetof(js::detail::ProxyValueArray, reservedSlots) / sizeof(Value)) + + ((Flags >> JSCLASS_RESERVED_SLOTS_SHIFT) & + JSCLASS_RESERVED_SLOTS_MASK) <= + shadow::Object::MAX_FIXED_SLOTS, + "ProxyValueArray size must not exceed max JSObject size"); + + // Proxies must not have the JSCLASS_SKIP_NURSERY_FINALIZE flag set: they + // always have finalizers, and whether they can be nursery allocated is + // controlled by the canNurseryAllocate() method on the proxy handler. + static_assert(!(Flags & JSCLASS_SKIP_NURSERY_FINALIZE), + "Proxies must not use JSCLASS_SKIP_NURSERY_FINALIZE; use " + "the canNurseryAllocate() proxy handler method instead."); + return Flags; +} + +#define PROXY_CLASS_DEF(name, flags) \ + { \ + name, \ + js::Class::NON_NATIVE | JSCLASS_IS_PROXY | \ + JSCLASS_DELAY_METADATA_BUILDER | js::CheckProxyFlags(), \ + &js::ProxyClassOps, JS_NULL_CLASS_SPEC, &js::ProxyClassExtension, \ + &js::ProxyObjectOps \ + } } /* namespace js */ 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 @@ -13,30 +13,96 @@ #ifndef js_Realm_h #define js_Realm_h -#include "jstypes.h" - -struct JSContext; -class JSObject; +#include "jspubtd.h" +#include "js/GCPolicyAPI.h" +#include "js/TypeDecls.h" // forward-declaration of JS::Realm + +namespace js { +namespace gc { +JS_PUBLIC_API void TraceRealm(JSTracer* trc, JS::Realm* realm, + const char* name); +JS_PUBLIC_API bool RealmNeedsSweep(JS::Realm* realm); +} // namespace gc +} // namespace js 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); +// Each Realm holds a strong reference to its GlobalObject, and vice versa. +template <> +struct GCPolicy : public NonGCPointerPolicy { + static void trace(JSTracer* trc, Realm** vp, const char* name) { + if (*vp) ::js::gc::TraceRealm(trc, *vp, name); + } + static bool needsSweep(Realm** vp) { + return *vp && ::js::gc::RealmNeedsSweep(*vp); + } +}; + +// Get the current realm, if any. The ECMAScript spec calls this "the current +// Realm Record". +extern JS_PUBLIC_API Realm* GetCurrentRealmOrNull(JSContext* cx); + +// Return the compartment that contains a given realm. +inline JSCompartment* GetCompartmentForRealm(Realm* realm) { + // Implementation note: For now, realms are a fiction; we treat realms and + // compartments as being one-to-one, but they are actually identical. + return reinterpret_cast(realm); +} + +// Return the realm in a given compartment. +// +// Deprecated. There is currently exactly one realm per compartment, but this +// will change. +inline Realm* GetRealmForCompartment(JSCompartment* compartment) { + return reinterpret_cast(compartment); +} + +// Return an object's realm. All objects except cross-compartment wrappers are +// created in a particular realm, which never changes. Returns null if obj is +// a cross-compartment wrapper. +extern JS_PUBLIC_API Realm* GetObjectRealmOrNull(JSObject* obj); + +// Get the value of the "private data" internal field of the given Realm. +// This field is initially null and is set using SetRealmPrivate. +// It's a pointer to embeddding-specific data that SpiderMonkey never uses. +extern JS_PUBLIC_API void* GetRealmPrivate(Realm* realm); + +// Set the "private data" internal field of the given Realm. +extern JS_PUBLIC_API void SetRealmPrivate(Realm* realm, void* data); + +typedef void (*DestroyRealmCallback)(JSFreeOp* fop, Realm* realm); + +// Set the callback SpiderMonkey calls just before garbage-collecting a realm. +// Embeddings can use this callback to free private data associated with the +// realm via SetRealmPrivate. +// +// By the time this is called, the global object for the realm has already been +// collected. +extern JS_PUBLIC_API void SetDestroyRealmCallback( + JSContext* cx, DestroyRealmCallback callback); + +typedef void (*RealmNameCallback)(JSContext* cx, Handle realm, + char* buf, size_t bufsize); + +// Set the callback SpiderMonkey calls to get the name of a realm, for +// diagnostic output. +extern JS_PUBLIC_API void SetRealmNameCallback(JSContext* cx, + RealmNameCallback callback); + +// Get the global object for the given realm. Returns null only if `realm` is +// in the atoms compartment. +extern JS_PUBLIC_API JSObject* GetRealmGlobalOrNull(Handle realm); + +extern JS_PUBLIC_API JSObject* GetRealmObjectPrototype(JSContext* cx); + +extern JS_PUBLIC_API JSObject* GetRealmFunctionPrototype(JSContext* cx); + +extern JS_PUBLIC_API JSObject* GetRealmArrayPrototype(JSContext* cx); -} // namespace JS +extern JS_PUBLIC_API JSObject* GetRealmErrorPrototype(JSContext* cx); -#endif // js_Realm_h +extern JS_PUBLIC_API JSObject* GetRealmIteratorPrototype(JSContext* cx); +} // namespace JS +#endif // js_Realm_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/RefCounted.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/RefCounted.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/RefCounted.h @@ -0,0 +1,85 @@ +/* -*- 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_RefCounted_h +#define js_RefCounted_h + +#include "mozilla/Atomics.h" +#include "mozilla/RefCountType.h" + +#include "js/Utility.h" + +// These types implement the same interface as mozilla::(Atomic)RefCounted and +// must be used instead of mozilla::(Atomic)RefCounted for everything in +// SpiderMonkey. There are two reasons: +// - Release() needs to call js_delete, not delete +// - SpiderMonkey does not have MOZILLA_INTERNAL_API defined which can lead +// to ODR violations that show up as spurious leak reports when ref-counted +// types are allocated by SpiderMonkey and released by Gecko (or vice versa). + +namespace js { + +template +class RefCounted { + static const MozRefCountType DEAD = 0xffffdead; + + protected: + RefCounted() : mRefCnt(0) {} + ~RefCounted() { MOZ_ASSERT(mRefCnt == DEAD); } + + public: + void AddRef() const { + MOZ_ASSERT(int32_t(mRefCnt) >= 0); + ++mRefCnt; + } + + void Release() const { + MOZ_ASSERT(int32_t(mRefCnt) > 0); + MozRefCountType cnt = --mRefCnt; + if (0 == cnt) { +#ifdef DEBUG + mRefCnt = DEAD; +#endif + js_delete(const_cast(static_cast(this))); + } + } + + private: + mutable MozRefCountType mRefCnt; +}; + +template +class AtomicRefCounted { + static const MozRefCountType DEAD = 0xffffdead; + + protected: + AtomicRefCounted() : mRefCnt(0) {} + ~AtomicRefCounted() { MOZ_ASSERT(mRefCnt == DEAD); } + + public: + void AddRef() const { + MOZ_ASSERT(int32_t(mRefCnt) >= 0); + ++mRefCnt; + } + + void Release() const { + MOZ_ASSERT(int32_t(mRefCnt) > 0); + MozRefCountType cnt = --mRefCnt; + if (0 == cnt) { +#ifdef DEBUG + mRefCnt = DEAD; +#endif + js_delete(const_cast(static_cast(this))); + } + } + + private: + mutable mozilla::Atomic mRefCnt; +}; + +} // namespace js + +#endif /* js_RefCounted_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Result.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Result.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Result.h @@ -0,0 +1,216 @@ +/* -*- 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/. */ + +/* + * `Result` is used as the return type of many SpiderMonkey functions that + * can either succeed or fail. See "/mfbt/Result.h". + * + * + * ## Which return type to use + * + * `Result` is for return values. Obviously, if you're writing a function that + * can't fail, don't use Result. Otherwise: + * + * JS::Result<> - function can fail, doesn't return anything on success + * (defaults to `JS::Result`) + * JS::Result - like JS::Result<>, but fails only on OOM + * + * JS::Result - function can fail, returns Data on success + * JS::Result - returns Data, fails only on OOM + * + * mozilla::GenericErrorResult - always fails + * + * That last type is like a Result with no success type. It's used for + * functions like `js::ReportNotFunction` that always return an error + * result. `GenericErrorResult` implicitly converts to `Result`, + * regardless of V. + * + * + * ## Checking Results when your return type is Result + * + * When you call a function that returns a `Result`, use the `MOZ_TRY` macro to + * check for errors: + * + * MOZ_TRY(DefenestrateObject(cx, obj)); + * + * If `DefenestrateObject` returns a success result, `MOZ_TRY` is done, and + * control flows to the next statement. If `DefenestrateObject` returns an + * error result, `MOZ_TRY` will immediately return it, propagating the error to + * your caller. It's kind of like exceptions, but more explicit -- you can see + * in the code exactly where errors can happen. + * + * You can do a tail call instead of using `MOZ_TRY`: + * + * return DefenestrateObject(cx, obj); + * + * Indicate success with `return Ok();`. + * + * If the function returns a value on success, use `MOZ_TRY_VAR` to get it: + * + * RootedValue thrug(cx); + * MOZ_TRY_VAR(thrug, GetObjectThrug(cx, obj)); + * + * This behaves the same as `MOZ_TRY` on error. On success, the success + * value of `GetObjectThrug(cx, obj)` is assigned to the variable `thrug`. + * + * + * ## Checking Results when your return type is not Result + * + * This header defines alternatives to MOZ_TRY and MOZ_TRY_VAR for when you + * need to call a `Result` function from a function that uses false or nullptr + * to indicate errors: + * + * JS_TRY_OR_RETURN_FALSE(cx, DefenestrateObject(cx, obj)); + * JS_TRY_VAR_OR_RETURN_FALSE(cx, v, GetObjectThrug(cx, obj)); + * + * JS_TRY_OR_RETURN_NULL(cx, DefenestrateObject(cx, obj)); + * JS_TRY_VAR_OR_RETURN_NULL(cx, v, GetObjectThrug(cx, obj)); + * + * When TRY is not what you want, because you need to do some cleanup or + * recovery on error, use this idiom: + * + * if (!cx->resultToBool(expr_that_is_a_Result)) { + * ... your recovery code here ... + * } + * + * In place of a tail call, you can use one of these methods: + * + * return cx->resultToBool(expr); // false on error + * return cx->resultToPtr(expr); // null on error + * + * Once we are using `Result` everywhere, including in public APIs, all of + * these will go away. + * + * + * ## GC safety + * + * When a function returns a `JS::Result`, it is the program's + * responsibility to check for errors and root the object before continuing: + * + * RootedObject wrapper(cx); + * MOZ_TRY_VAR(wrapper, Enwrapify(cx, thing)); + * + * This is ideal. On error, there is no object to root; on success, the + * assignment to wrapper roots it. GC safety is ensured. + * + * `Result` has methods .isOk(), .isErr(), .unwrap(), and .unwrapErr(), but if + * you're actually using them, it's possible to create a GC hazard. The static + * analysis will catch it if so, but that's hardly convenient. So try to stick + * to the idioms shown above. + * + * + * ## Future directions + * + * At present, JS::Error and JS::OOM are empty structs. The plan is to make them + * GC things that contain the actual error information (including the exception + * value and a saved stack). + * + * The long-term plan is to remove JS_IsExceptionPending and + * JS_GetPendingException in favor of JS::Error. Exception state will no longer + * exist. + */ + +#ifndef js_Result_h +#define js_Result_h + +#include "mozilla/Result.h" + +/** + * Evaluate the boolean expression expr. If it's true, do nothing. + * If it's false, return an error result. + */ +#define JS_TRY_BOOL_TO_RESULT(cx, expr) \ + do { \ + bool ok_ = (expr); \ + if (!ok_) return (cx)->boolToResult(ok_); \ + } while (0) + +/** + * JS_TRY_OR_RETURN_FALSE(cx, expr) runs expr to compute a Result value. + * On success, nothing happens; on error, it returns false immediately. + * + * Implementation note: this involves cx because this may eventually + * do the work of setting a pending exception or reporting OOM. + */ +#define JS_TRY_OR_RETURN_FALSE(cx, expr) \ + do { \ + auto tmpResult_ = (expr); \ + if (tmpResult_.isErr()) return (cx)->resultToBool(tmpResult_); \ + } while (0) + +/** + * Like JS_TRY_OR_RETURN_FALSE, but returning nullptr on error, + * rather than false. + */ +#define JS_TRY_OR_RETURN_NULL(cx, expr) \ + do { \ + auto tmpResult_ = (expr); \ + if (tmpResult_.isErr()) { \ + JS_ALWAYS_FALSE((cx)->resultToBool(tmpResult_)); \ + return nullptr; \ + } \ + } while (0) + +#define JS_TRY_VAR_OR_RETURN_FALSE(cx, target, expr) \ + do { \ + auto tmpResult_ = (expr); \ + if (tmpResult_.isErr()) return (cx)->resultToBool(tmpResult_); \ + (target) = tmpResult_.unwrap(); \ + } while (0) + +#define JS_TRY_VAR_OR_RETURN_NULL(cx, target, expr) \ + do { \ + auto tmpResult_ = (expr); \ + if (tmpResult_.isErr()) { \ + JS_ALWAYS_FALSE((cx)->resultToBool(tmpResult_)); \ + return nullptr; \ + } \ + (target) = tmpResult_.unwrap(); \ + } while (0) + +namespace JS { + +using mozilla::Ok; + +/** + * Type representing a JS error or exception. At the moment this only + * "represents" an error in a rather abstract way. + */ +struct Error { + // Ensure sizeof(Error) > 1 so that Result can use pointer + // tagging. + int dummy; +}; + +struct OOM : public Error {}; + +/** + * `Result` is intended to be the return type of JSAPI calls and internal + * functions that can run JS code or allocate memory from the JS GC heap. Such + * functions can: + * + * - succeed, possibly returning a value; + * + * - fail with a JS exception (out-of-memory falls in this category); or + * + * - fail because JS execution was terminated, which occurs when e.g. a + * user kills a script from the "slow script" UI. This is also how we + * unwind the stack when the debugger forces the current function to + * return. JS `catch` blocks can't catch this kind of failure, + * and JS `finally` blocks don't execute. + */ +template +using Result = mozilla::Result; + +static_assert(sizeof(Result<>) == sizeof(uintptr_t), + "Result<> should be pointer-sized"); + +static_assert(sizeof(Result) == sizeof(uintptr_t), + "Result should be pointer-sized"); + +} // namespace JS + +#endif // js_Result_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 @@ -19,9 +19,9 @@ #include "jspubtd.h" #include "js/GCAnnotations.h" -#include "js/GCAPI.h" #include "js/GCPolicyAPI.h" #include "js/HeapAPI.h" +#include "js/ProfilingStack.h" #include "js/TypeDecls.h" #include "js/UniquePtr.h" #include "js/Utility.h" @@ -110,105 +110,121 @@ namespace js { template -struct BarrierMethods { -}; +struct BarrierMethods {}; -template -class RootedBase {}; +template +class WrappedPtrOperations {}; -template -class HandleBase {}; +template +class MutableWrappedPtrOperations + : public WrappedPtrOperations {}; -template -class MutableHandleBase {}; +template +class RootedBase : public MutableWrappedPtrOperations {}; -template -class HeapBase {}; +template +class HandleBase : public WrappedPtrOperations {}; -// 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; }; +template +class MutableHandleBase : public MutableWrappedPtrOperations {}; + +template +class HeapBase : public MutableWrappedPtrOperations {}; + +// 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; }; + 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 : public MutableWrappedPtrOperations {}; + template -class PersistentRootedBase {}; +class FakeRooted; -static void* const ConstNullValue = nullptr; +template +class FakeMutableHandle; namespace gc { struct Cell; -template +template struct PersistentRootedMarker; } /* namespace gc */ -#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(); } \ - const T& operator->() 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 // operator= on the derived class. Thus, define the operator= directly on the // class as we would need to manually pass it through anyway. -#define DECLARE_POINTER_ASSIGN_OPS(Wrapper, T) \ - Wrapper& operator=(const T& p) { \ - 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) \ - template Wrapper& operator=(S) = delete; \ - Wrapper& operator=(const Wrapper&) = delete; - -#define DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr) \ - const T* address() const { return &(ptr); } \ - const T& get() const { return (ptr); } \ - -#define DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr) \ - T* address() { return &(ptr); } \ - T& get() { return (ptr); } \ +#define DECLARE_POINTER_ASSIGN_OPS(Wrapper, T) \ + Wrapper& operator=(const T& p) { \ + 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) \ + template \ + Wrapper& operator=(S) = delete; \ + Wrapper& operator=(const Wrapper&) = delete; + +#define DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr) \ + const T* address() const { return &(ptr); } \ + const T& get() const { return (ptr); } + +#define DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr) \ + T* address() { return &(ptr); } \ + T& get() { return (ptr); } } /* namespace js */ namespace JS { -template class Rooted; -template class PersistentRooted; +template +class Rooted; +template +class PersistentRooted; /* This is exposing internal state of the GC for inlining purposes. */ -JS_FRIEND_API(bool) isGCEnabled(); +JS_FRIEND_API bool isGCEnabled(); -JS_FRIEND_API(void) HeapObjectPostBarrier(JSObject** objp, JSObject* prev, JSObject* next); +JS_FRIEND_API void HeapObjectPostBarrier(JSObject** objp, JSObject* prev, + JSObject* next); +JS_FRIEND_API void HeapStringPostBarrier(JSString** objp, JSString* prev, + JSString* next); #ifdef JS_DEBUG /** * For generational GC, assert that an object is in the tenured generation as * opposed to being in the nursery. */ -extern JS_FRIEND_API(void) -AssertGCThingMustBeTenured(JSObject* obj); -extern JS_FRIEND_API(void) -AssertGCThingIsNotAnObjectSubclass(js::gc::Cell* cell); +extern JS_FRIEND_API void AssertGCThingMustBeTenured(JSObject* obj); +extern JS_FRIEND_API void AssertGCThingIsNotNurseryAllocable( + js::gc::Cell* cell); #else -inline void -AssertGCThingMustBeTenured(JSObject* obj) {} -inline void -AssertGCThingIsNotAnObjectSubclass(js::gc::Cell* cell) {} +inline void AssertGCThingMustBeTenured(JSObject* obj) {} +inline void AssertGCThingIsNotNurseryAllocable(js::gc::Cell* cell) {} #endif /** @@ -231,113 +247,108 @@ * Type T must be a public GC pointer type. */ template -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(GCPolicy::initial()); - } - explicit Heap(const T& p) { init(p); } - - /* - * For Heap, move semantics are equivalent to copy semantics. In C++, a - * copy constructor taking const-ref is the way to get a single function - * that will be used for both lvalue and rvalue copies, so we can simply - * omit the rvalue variant. - */ - explicit Heap(const Heap& p) { init(p.ptr); } +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: + using ElementType = T; + + Heap() { + static_assert(sizeof(T) == sizeof(Heap), + "Heap must be binary compatible with T."); + init(GCPolicy::initial()); + } + explicit Heap(const T& p) { init(p); } + + /* + * For Heap, move semantics are equivalent to copy semantics. In C++, a + * copy constructor taking const-ref is the way to get a single function + * that will be used for both lvalue and rvalue copies, so we can simply + * omit the rvalue variant. + */ + explicit Heap(const Heap& p) { init(p.ptr); } + + ~Heap() { post(ptr, GCPolicy::initial()); } + + DECLARE_POINTER_CONSTREF_OPS(T); + DECLARE_POINTER_ASSIGN_OPS(Heap, T); + + const T* address() const { return &ptr; } + + void exposeToActiveJS() const { js::BarrierMethods::exposeToJS(ptr); } + const T& get() const { + exposeToActiveJS(); + return ptr; + } + const T& unbarrieredGet() const { return ptr; } + + 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(const T& newPtr) { + ptr = newPtr; + post(GCPolicy::initial(), ptr); + } + + void set(const T& newPtr) { + T tmp = ptr; + ptr = newPtr; + post(tmp, ptr); + } + + void post(const T& prev, const T& next) { + js::BarrierMethods::postBarrier(&ptr, prev, next); + } - ~Heap() { - post(ptr, GCPolicy::initial()); - } - - DECLARE_POINTER_CONSTREF_OPS(T); - DECLARE_POINTER_ASSIGN_OPS(Heap, T); - - const T* address() const { return &ptr; } - - void exposeToActiveJS() const { - js::BarrierMethods::exposeToJS(ptr); - } - const T& get() const { - exposeToActiveJS(); - return ptr; - } - const T& unbarrieredGet() const { - return ptr; - } - - 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(const T& newPtr) { - ptr = newPtr; - post(GCPolicy::initial(), ptr); - } - - void set(const T& newPtr) { - T tmp = ptr; - ptr = newPtr; - post(tmp, ptr); - } - - void post(const T& prev, const T& next) { - js::BarrierMethods::postBarrier(&ptr, prev, next); - } - - T ptr; + T ptr; }; -static MOZ_ALWAYS_INLINE bool -ObjectIsTenured(JSObject* obj) -{ - return !js::gc::IsInsideNursery(reinterpret_cast(obj)); +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 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(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 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); +// The following *IsNotGray functions are for use in assertions and take account +// of the eventual gray marking state at the end of any ongoing incremental GC. +#ifdef DEBUG +inline bool CellIsNotGray(js::gc::Cell* maybeCell) { + if (!maybeCell) return true; + + return js::gc::detail::CellIsNotGray(maybeCell); } -static MOZ_ALWAYS_INLINE bool -ScriptIsMarkedGray(const Heap& script) -{ - return ScriptIsMarkedGray(script.unbarrieredGet()); +inline bool ObjectIsNotGray(JSObject* maybeObj) { + return CellIsNotGray(reinterpret_cast(maybeObj)); } +inline bool ObjectIsNotGray(const JS::Heap& obj) { + return ObjectIsNotGray(obj.unbarrieredGet()); +} +#endif + /** * 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, @@ -368,79 +379,79 @@ * - It is not possible to store flag bits in a Heap. */ template -class TenuredHeap : public js::HeapBase -{ - public: - TenuredHeap() : bits(0) { - static_assert(sizeof(T) == sizeof(TenuredHeap), - "TenuredHeap must be binary compatible with T."); - } - explicit TenuredHeap(T p) : bits(0) { setPtr(p); } - explicit TenuredHeap(const TenuredHeap& p) : bits(0) { setPtr(p.getPtr()); } - - bool operator==(const TenuredHeap& other) { return bits == other.bits; } - bool operator!=(const TenuredHeap& other) { return bits != other.bits; } +class TenuredHeap : public js::HeapBase> { + public: + using ElementType = T; + + TenuredHeap() : bits(0) { + static_assert(sizeof(T) == sizeof(TenuredHeap), + "TenuredHeap must be binary compatible with T."); + } + explicit TenuredHeap(T p) : bits(0) { setPtr(p); } + explicit TenuredHeap(const TenuredHeap& p) : bits(0) { + setPtr(p.getPtr()); + } + + void setPtr(T newPtr) { + MOZ_ASSERT((reinterpret_cast(newPtr) & flagsMask) == 0); + MOZ_ASSERT(js::gc::IsCellPointerValidOrNull(newPtr)); + if (newPtr) AssertGCThingMustBeTenured(newPtr); + bits = (bits & flagsMask) | reinterpret_cast(newPtr); + } + + void setFlags(uintptr_t flagsToSet) { + MOZ_ASSERT((flagsToSet & ~flagsMask) == 0); + bits |= flagsToSet; + } + + void unsetFlags(uintptr_t flagsToUnset) { + MOZ_ASSERT((flagsToUnset & ~flagsMask) == 0); + bits &= ~flagsToUnset; + } + + bool hasFlag(uintptr_t flag) const { + MOZ_ASSERT((flag & ~flagsMask) == 0); + return (bits & flag) != 0; + } + + 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; + } + + TenuredHeap& operator=(const TenuredHeap& other) { + bits = other.bits; + return *this; + } + + private: + enum { + maskBits = 3, + flagsMask = (1 << maskBits) - 1, + }; - void setPtr(T newPtr) { - MOZ_ASSERT((reinterpret_cast(newPtr) & flagsMask) == 0); - if (newPtr) - AssertGCThingMustBeTenured(newPtr); - bits = (bits & flagsMask) | reinterpret_cast(newPtr); - } - - void setFlags(uintptr_t flagsToSet) { - MOZ_ASSERT((flagsToSet & ~flagsMask) == 0); - bits |= flagsToSet; - } - - void unsetFlags(uintptr_t flagsToUnset) { - MOZ_ASSERT((flagsToUnset & ~flagsMask) == 0); - bits &= ~flagsToUnset; - } - - bool hasFlag(uintptr_t flag) const { - MOZ_ASSERT((flag & ~flagsMask) == 0); - return (bits & flag) != 0; - } - - 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; - } - - TenuredHeap& operator=(const TenuredHeap& other) { - bits = other.bits; - return *this; - } - - private: - enum { - maskBits = 3, - flagsMask = (1 << maskBits) - 1, - }; - - uintptr_t bits; + uintptr_t bits; }; /** @@ -452,84 +463,87 @@ * specialization, define a HandleBase specialization containing them. */ template -class MOZ_NONHEAP_CLASS Handle : public js::HandleBase -{ - friend class JS::MutableHandle; - - public: - /* Creates a handle from a handle of a type convertible to T. */ - template - MOZ_IMPLICIT Handle(Handle handle, - typename mozilla::EnableIf::value, int>::Type dummy = 0) - { - static_assert(sizeof(Handle) == sizeof(T*), - "Handle must be binary compatible with T*."); - ptr = reinterpret_cast(handle.address()); - } - - MOZ_IMPLICIT Handle(decltype(nullptr)) { - static_assert(mozilla::IsPointer::value, - "nullptr_t overload not valid for non-pointer types"); - ptr = reinterpret_cast(&js::ConstNullValue); - } +class MOZ_NONHEAP_CLASS Handle : public js::HandleBase> { + friend class JS::MutableHandle; - MOZ_IMPLICIT Handle(MutableHandle handle) { - ptr = handle.address(); - } + public: + using ElementType = T; - /* - * Take care when calling this method! - * - * This creates a Handle from the raw location of a T. - * - * It should be called only if the following conditions hold: - * - * 1) the location of the T is guaranteed to be marked (for some reason - * other than being a Rooted), e.g., if it is guaranteed to be reachable - * from an implicit root. - * - * 2) the contents of the location are immutable, or at least cannot change - * for the lifetime of the handle, as its users may not expect its value - * to change underneath them. - */ - static constexpr Handle fromMarkedLocation(const T* p) { - return Handle(p, DeliberatelyChoosingThisOverload, - ImUsingThisOnlyInFromFromMarkedLocation); - } + /* Creates a handle from a handle of a type convertible to T. */ + template + MOZ_IMPLICIT Handle( + Handle handle, + typename mozilla::EnableIf::value, int>::Type + dummy = 0) { + static_assert(sizeof(Handle) == sizeof(T*), + "Handle must be binary compatible with T*."); + ptr = reinterpret_cast(handle.address()); + } + + MOZ_IMPLICIT Handle(decltype(nullptr)) { + static_assert(mozilla::IsPointer::value, + "nullptr_t overload not valid for non-pointer types"); + static void* const ConstNullValue = nullptr; + ptr = reinterpret_cast(&ConstNullValue); + } + + MOZ_IMPLICIT Handle(MutableHandle handle) { ptr = handle.address(); } + + /* + * Take care when calling this method! + * + * This creates a Handle from the raw location of a T. + * + * It should be called only if the following conditions hold: + * + * 1) the location of the T is guaranteed to be marked (for some reason + * other than being a Rooted), e.g., if it is guaranteed to be reachable + * from an implicit root. + * + * 2) the contents of the location are immutable, or at least cannot change + * for the lifetime of the handle, as its users may not expect its value + * to change underneath them. + */ + static constexpr Handle fromMarkedLocation(const T* p) { + return Handle(p, DeliberatelyChoosingThisOverload, + ImUsingThisOnlyInFromFromMarkedLocation); + } + + /* + * Construct a handle from an explicitly rooted location. This is the + * normal way to create a handle, and normally happens implicitly. + */ + template + inline MOZ_IMPLICIT Handle( + const Rooted& root, + typename mozilla::EnableIf::value, int>::Type + dummy = 0); + + template + inline MOZ_IMPLICIT Handle( + const PersistentRooted& root, + typename mozilla::EnableIf::value, int>::Type + dummy = 0); + + /* Construct a read only handle from a mutable handle. */ + template + inline MOZ_IMPLICIT Handle( + MutableHandle& root, + typename mozilla::EnableIf::value, int>::Type + dummy = 0); + + DECLARE_POINTER_CONSTREF_OPS(T); + DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr); + + private: + Handle() {} + DELETE_ASSIGNMENT_OPS(Handle, T); + + enum Disambiguator { DeliberatelyChoosingThisOverload = 42 }; + enum CallerIdentity { ImUsingThisOnlyInFromFromMarkedLocation = 17 }; + constexpr Handle(const T* p, Disambiguator, CallerIdentity) : ptr(p) {} - /* - * Construct a handle from an explicitly rooted location. This is the - * normal way to create a handle, and normally happens implicitly. - */ - template - inline - MOZ_IMPLICIT Handle(const Rooted& root, - typename mozilla::EnableIf::value, int>::Type dummy = 0); - - template - inline - MOZ_IMPLICIT Handle(const PersistentRooted& root, - typename mozilla::EnableIf::value, int>::Type dummy = 0); - - /* Construct a read only handle from a mutable handle. */ - template - inline - MOZ_IMPLICIT Handle(MutableHandle& root, - typename mozilla::EnableIf::value, int>::Type dummy = 0); - - DECLARE_POINTER_COMPARISON_OPS(T); - DECLARE_POINTER_CONSTREF_OPS(T); - DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr); - - private: - Handle() {} - DELETE_ASSIGNMENT_OPS(Handle, T); - - enum Disambiguator { DeliberatelyChoosingThisOverload = 42 }; - enum CallerIdentity { ImUsingThisOnlyInFromFromMarkedLocation = 17 }; - constexpr Handle(const T* p, Disambiguator, CallerIdentity) : ptr(p) {} - - const T* ptr; + const T* ptr; }; /** @@ -541,46 +555,50 @@ * them. */ template -class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase -{ - public: - inline MOZ_IMPLICIT MutableHandle(Rooted* root); - inline MOZ_IMPLICIT MutableHandle(PersistentRooted* root); - - private: - // Disallow nullptr for overloading purposes. - MutableHandle(decltype(nullptr)) = delete; - - public: - 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 - * to be marked (for some reason other than being a Rooted), - * e.g., if it is guaranteed to be reachable from an implicit root. - * - * Create a MutableHandle from a raw location of a T. - */ - static MutableHandle fromMarkedLocation(T* p) { - MutableHandle h; - h.ptr = p; - return h; - } +class MOZ_STACK_CLASS MutableHandle + : public js::MutableHandleBase> { + public: + using ElementType = T; + + inline MOZ_IMPLICIT MutableHandle(Rooted* root); + inline MOZ_IMPLICIT MutableHandle(PersistentRooted* root); + + private: + // Disallow nullptr for overloading purposes. + MutableHandle(decltype(nullptr)) = delete; + + public: + void set(const T& v) { + *ptr = v; + MOZ_ASSERT(GCPolicy::isValid(*ptr)); + } + void set(T&& v) { + *ptr = mozilla::Move(v); + MOZ_ASSERT(GCPolicy::isValid(*ptr)); + } + + /* + * This may be called only if the location of the T is guaranteed + * to be marked (for some reason other than being a Rooted), + * e.g., if it is guaranteed to be reachable from an implicit root. + * + * Create a MutableHandle from a raw location of a T. + */ + static MutableHandle fromMarkedLocation(T* p) { + MutableHandle h; + h.ptr = p; + return h; + } + + DECLARE_POINTER_CONSTREF_OPS(T); + DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr); + DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr); + + private: + MutableHandle() {} + DELETE_ASSIGNMENT_OPS(MutableHandle, T); - DECLARE_POINTER_CONSTREF_OPS(T); - DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr); - DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr); - - private: - MutableHandle() {} - DELETE_ASSIGNMENT_OPS(MutableHandle, T); - - T* ptr; + T* ptr; }; } /* namespace JS */ @@ -588,63 +606,71 @@ namespace js { template -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 exposeToJS(T* t) { - if (t) - js::gc::ExposeGCThingToActiveJS(JS::GCCellPtr(t)); - } +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::AssertGCThingIsNotNurseryAllocable( + reinterpret_cast(next)); + } + static void exposeToJS(T* t) { + if (t) js::gc::ExposeGCThingToActiveJS(JS::GCCellPtr(t)); + } }; template <> -struct BarrierMethods -{ - static JSObject* initial() { return nullptr; } - static gc::Cell* asGCThingOrNull(JSObject* v) { - if (!v) - return nullptr; - MOZ_ASSERT(uintptr_t(v) > 32); - return reinterpret_cast(v); - } - static void postBarrier(JSObject** vp, JSObject* prev, JSObject* next) { - JS::HeapObjectPostBarrier(vp, prev, next); - } - static void exposeToJS(JSObject* obj) { - if (obj) - JS::ExposeObjectToActiveJS(obj); - } +struct BarrierMethods { + static JSObject* initial() { return nullptr; } + static gc::Cell* asGCThingOrNull(JSObject* v) { + if (!v) return nullptr; + MOZ_ASSERT(uintptr_t(v) > 32); + return reinterpret_cast(v); + } + 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 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)); - } +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)); + } +}; + +template <> +struct BarrierMethods { + static JSString* initial() { return nullptr; } + static gc::Cell* asGCThingOrNull(JSString* v) { + if (!v) return nullptr; + MOZ_ASSERT(uintptr_t(v) > 32); + return reinterpret_cast(v); + } + static void postBarrier(JSString** vp, JSString* prev, JSString* next) { + JS::HeapStringPostBarrier(vp, prev, next); + } + static void exposeToJS(JSString* v) { + if (v) js::gc::ExposeGCThingToActiveJS(JS::GCCellPtr(v)); + } }; // Provide hash codes for Cell kinds that may be relocated and, thus, not have @@ -659,42 +685,47 @@ // aggregate Lookup kinds embed a JSObject* that is frequently null and do not // null test before dispatching to the hasher. template -struct JS_PUBLIC_API(MovableCellHasher) -{ - 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; } +struct JS_PUBLIC_API MovableCellHasher { + 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; } }; template -struct JS_PUBLIC_API(MovableCellHasher>) -{ - 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.unbarrieredGet(), l); - } - static void rekey(Key& k, const Key& newKey) { k.unsafeSet(newKey); } +struct JS_PUBLIC_API MovableCellHasher> { + 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.unbarrieredGet(), l); + } + static void rekey(Key& k, const Key& newKey) { k.unsafeSet(newKey); } }; template -struct FallibleHashMethods> -{ - template static bool hasHash(Lookup&& l) { - return MovableCellHasher::hasHash(mozilla::Forward(l)); - } - template static bool ensureHash(Lookup&& l) { - return MovableCellHasher::ensureHash(mozilla::Forward(l)); - } +struct FallibleHashMethods> { + 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 */ @@ -710,41 +741,175 @@ // DispatchWrapper, rather than DispatchWrapper itself, but that causes MSVC to // fail when Rooted is used in an IsConvertible test. template -class alignas(8) DispatchWrapper -{ - static_assert(JS::MapTypeToRootKind::kind == JS::RootKind::Traceable, - "DispatchWrapper is intended only for usage with a Traceable"); - - using TraceFn = void (*)(JSTracer*, T*, const char*); - TraceFn tracer; - alignas(gc::CellSize) T storage; - - public: - template - MOZ_IMPLICIT DispatchWrapper(U&& initial) +class alignas(8) DispatchWrapper { + static_assert(JS::MapTypeToRootKind::kind == JS::RootKind::Traceable, + "DispatchWrapper is intended only for usage with a Traceable"); + + using TraceFn = void (*)(JSTracer*, T*, const char*); + TraceFn tracer; + alignas(gc::CellAlignBytes) T storage; + + public: + template + MOZ_IMPLICIT DispatchWrapper(U&& initial) : tracer(&JS::GCPolicy::trace), - storage(mozilla::Forward(initial)) - { } + storage(mozilla::Forward(initial)) {} - // Mimic a pointer type, so that we can drop into Rooted. - T* operator &() { return &storage; } - const T* operator &() const { return &storage; } - operator T&() { return storage; } - operator const T&() const { return storage; } - - // 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, T* thingp, const char* name) { - auto wrapper = reinterpret_cast( - uintptr_t(thingp) - offsetof(DispatchWrapper, storage)); - wrapper->tracer(trc, &wrapper->storage, name); - } + // Mimic a pointer type, so that we can drop into Rooted. + T* operator&() { return &storage; } + const T* operator&() const { return &storage; } + operator T&() { return storage; } + operator const T&() const { return storage; } + + // 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, T* thingp, const char* name) { + auto wrapper = reinterpret_cast( + uintptr_t(thingp) - offsetof(DispatchWrapper, storage)); + wrapper->tracer(trc, &wrapper->storage, name); + } }; } /* namespace js */ namespace JS { +class JS_PUBLIC_API AutoGCRooter; + +// Our instantiations of Rooted and PersistentRooted require an +// instantiation of MapTypeToRootKind. +template <> +struct MapTypeToRootKind { + static const RootKind kind = RootKind::Traceable; +}; + +using RootedListHeads = + mozilla::EnumeratedArray*>; + +// Superclass of JSContext which can be used for rooting data in use by the +// current thread but that does not provide all the functions of a JSContext. +class RootingContext { + // Stack GC roots for Rooted GC heap pointers. + RootedListHeads stackRoots_; + template + friend class JS::Rooted; + + // Stack GC roots for AutoFooRooter classes. + JS::AutoGCRooter* autoGCRooters_; + friend class JS::AutoGCRooter; + + // Gecko profiling metadata. + // This isn't really rooting related. It's only here because we want + // GetContextProfilingStack to be inlineable into non-JS code, and we + // didn't want to add another superclass of JSContext just for this. + js::GeckoProfilerThread geckoProfiler_; + + public: + RootingContext(); + + void traceStackRoots(JSTracer* trc); + void checkNoGCRooters(); + + js::GeckoProfilerThread& geckoProfiler() { return geckoProfiler_; } + + protected: + // The remaining members in this class should only be accessed through + // JSContext pointers. They are unrelated to rooting and are in place so + // that inlined API functions can directly access the data. + + /* The current compartment. */ + JSCompartment* compartment_; + + /* The current zone. */ + JS::Zone* zone_; + + public: + /* Limit pointer for checking native stack consumption. */ + uintptr_t nativeStackLimit[StackKindCount]; + + static const RootingContext* get(const JSContext* cx) { + return reinterpret_cast(cx); + } + + static RootingContext* get(JSContext* cx) { + return reinterpret_cast(cx); + } + + friend JSCompartment* js::GetContextCompartment(const JSContext* cx); + friend JS::Zone* js::GetContextZone(const JSContext* cx); +}; + +class JS_PUBLIC_API AutoGCRooter { + public: + AutoGCRooter(JSContext* cx, ptrdiff_t tag) + : AutoGCRooter(JS::RootingContext::get(cx), tag) {} + AutoGCRooter(JS::RootingContext* cx, ptrdiff_t tag) + : down(cx->autoGCRooters_), tag_(tag), stackTop(&cx->autoGCRooters_) { + MOZ_ASSERT(this != *stackTop); + *stackTop = this; + } + + ~AutoGCRooter() { + MOZ_ASSERT(this == *stackTop); + *stackTop = down; + } + + /* Implemented in gc/RootMarking.cpp. */ + inline void trace(JSTracer* trc); + static void traceAll(const js::CooperatingContext& target, JSTracer* trc); + static void traceAllWrappers(const js::CooperatingContext& target, + JSTracer* trc); + + protected: + AutoGCRooter* const down; + + /* + * Discriminates actual subclass of this being used. If non-negative, the + * subclass roots an array of values of the length stored in this field. + * If negative, meaning is indicated by the corresponding value in the enum + * below. Any other negative value indicates some deeper problem such as + * memory corruption. + */ + ptrdiff_t tag_; + + enum { + VALARRAY = -2, /* js::AutoValueArray */ + PARSER = -3, /* js::frontend::Parser */ +#if defined(JS_BUILD_BINAST) + BINPARSER = -4, /* js::frontend::BinSource */ +#endif // defined(JS_BUILD_BINAST) + IONMASM = -19, /* js::jit::MacroAssembler */ + WRAPVECTOR = -20, /* js::AutoWrapperVector */ + WRAPPER = -21, /* js::AutoWrapperRooter */ + CUSTOM = -26 /* js::CustomAutoRooter */ + }; + + private: + AutoGCRooter** const stackTop; + + /* No copy or assignment semantics. */ + AutoGCRooter(AutoGCRooter& ida) = delete; + void operator=(AutoGCRooter& ida) = delete; +}; + +namespace detail { + +/* + * For pointer types, the TraceKind for tracing is based on the list it is + * 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. + */ +template +using MaybeWrapped = + typename mozilla::Conditional::kind == + JS::RootKind::Traceable, + js::DispatchWrapper, T>::Type; + +} /* namespace detail */ + /** * Local variable of type T whose value is always rooted. This is typically * used for local variables, or for non-rooted values being passed to a @@ -754,96 +919,100 @@ * specialization, define a RootedBase specialization containing them. */ template -class MOZ_RAII Rooted : public js::RootedBase -{ - 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(GCPolicy::initial()) - { - registerWithRootLists(rootLists(cx)); - } +class MOZ_RAII Rooted : public js::RootedBase> { + inline void registerWithRootLists(RootedListHeads& roots) { + this->stack = &roots[JS::MapTypeToRootKind::kind]; + this->prev = *stack; + *stack = reinterpret_cast*>(this); + } + + inline RootedListHeads& rootLists(RootingContext* cx) { + return cx->stackRoots_; + } + inline RootedListHeads& rootLists(JSContext* cx) { + return rootLists(RootingContext::get(cx)); + } + + public: + using ElementType = T; + + template + explicit Rooted(const RootingContext& cx) : ptr(GCPolicy::initial()) { + registerWithRootLists(rootLists(cx)); + } + + template + Rooted(const RootingContext& cx, S&& initial) + : ptr(mozilla::Forward(initial)) { + MOZ_ASSERT(GCPolicy::isValid(ptr)); + registerWithRootLists(rootLists(cx)); + } + + ~Rooted() { + MOZ_ASSERT(*stack == reinterpret_cast*>(this)); + *stack = prev; + } + + Rooted* previous() { return reinterpret_cast*>(prev); } + + /* + * This method is public for Rooted so that Codegen.py can use a Rooted + * interchangeably with a MutableHandleValue. + */ + void set(const T& value) { + ptr = value; + MOZ_ASSERT(GCPolicy::isValid(ptr)); + } + void set(T&& value) { + ptr = mozilla::Move(value); + MOZ_ASSERT(GCPolicy::isValid(ptr)); + } + + DECLARE_POINTER_CONSTREF_OPS(T); + DECLARE_POINTER_ASSIGN_OPS(Rooted, T); + DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); + DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr); + + private: + /* + * These need to be templated on void* to avoid aliasing issues between, for + * example, Rooted and Rooted, which use the same + * stack head pointer for different classes. + */ + Rooted** stack; + Rooted* prev; - template - Rooted(const RootingContext& cx, S&& initial) - : ptr(mozilla::Forward(initial)) - { - registerWithRootLists(rootLists(cx)); - } - - ~Rooted() { - MOZ_ASSERT(*stack == reinterpret_cast*>(this)); - *stack = prev; - } - - Rooted* previous() { return reinterpret_cast*>(prev); } - - /* - * This method is public for Rooted so that Codegen.py can use a Rooted - * interchangeably with a MutableHandleValue. - */ - void set(const T& value) { - ptr = value; - } - void set(T&& value) { - ptr = mozilla::Move(value); - } + detail::MaybeWrapped ptr; - DECLARE_POINTER_COMPARISON_OPS(T); - DECLARE_POINTER_CONSTREF_OPS(T); - DECLARE_POINTER_ASSIGN_OPS(Rooted, T); - DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); - DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr); - - private: - /* - * These need to be templated on void* to avoid aliasing issues between, for - * example, Rooted and Rooted, which use the same - * stack head pointer for different classes. - */ - Rooted** stack; - Rooted* prev; - - /* - * For pointer types, the TraceKind for tracing is based on the list it is - * 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< - MapTypeToRootKind::kind == JS::RootKind::Traceable, - js::DispatchWrapper, - T>::Type; - MaybeWrapped ptr; - - Rooted(const Rooted&) = delete; + Rooted(const Rooted&) = delete; } JS_HAZ_ROOTED; } /* namespace JS */ namespace js { +/* + * Inlinable accessors for JSContext. + * + * - These must not be available on the more restricted superclasses of + * JSContext, so we can't simply define them on RootingContext. + * + * - They're perfectly ordinary JSContext functionality, so ought to be + * usable without resorting to jsfriendapi.h, and when JSContext is an + * incomplete type. + */ +inline JSCompartment* GetContextCompartment(const JSContext* cx) { + return JS::RootingContext::get(cx)->compartment_; +} + +inline JS::Zone* GetContextZone(const JSContext* cx) { + return JS::RootingContext::get(cx)->zone_; +} + +inline PseudoStack* GetContextProfilingStack(JSContext* cx) { + return JS::RootingContext::get(cx)->geckoProfiler().getPseudoStack(); +} + /** * Augment the generic Rooted interface when T = JSObject* with * class-querying and downcasting operations. @@ -854,12 +1023,12 @@ * Rooted rooted(cx, &obj->as()); * Handle h = rooted; */ -template <> -class RootedBase -{ - public: - template - JS::Handle as() const; +template +class RootedBase + : public MutableWrappedPtrOperations { + public: + template + JS::Handle as() const; }; /** @@ -872,67 +1041,12 @@ * Rooted rooted(cx, &obj->as()); * Handle h = rooted; */ -template <> -class HandleBase -{ - public: - template - JS::Handle as() const; -}; - -/** Interface substitute for Rooted which does not root the variable's memory. */ -template -class MOZ_RAII FakeRooted : public RootedBase -{ - public: - template - explicit FakeRooted(CX* cx) : ptr(JS::GCPolicy::initial()) {} - - template - FakeRooted(CX* cx, T initial) : ptr(initial) {} - - DECLARE_POINTER_COMPARISON_OPS(T); - DECLARE_POINTER_CONSTREF_OPS(T); - DECLARE_POINTER_ASSIGN_OPS(FakeRooted, T); - DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); - DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr); - - private: - T ptr; - - void set(const T& value) { - ptr = value; - } - - FakeRooted(const FakeRooted&) = delete; -}; - -/** Interface substitute for MutableHandle which is not required to point to rooted memory. */ -template -class FakeMutableHandle : public js::MutableHandleBase -{ - public: - MOZ_IMPLICIT FakeMutableHandle(T* t) { - ptr = t; - } - - MOZ_IMPLICIT FakeMutableHandle(FakeRooted* root) { - ptr = root->address(); - } - - void set(const T& v) { - *ptr = v; - } - - DECLARE_POINTER_CONSTREF_OPS(T); - DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr); - DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr); - - private: - FakeMutableHandle() {} - DELETE_ASSIGNMENT_OPS(FakeMutableHandle, T); - - T* ptr; +template +class HandleBase + : public WrappedPtrOperations { + public: + template + JS::Handle as() const; }; /** @@ -944,103 +1058,80 @@ * which require handle types and are only called in the CanGC case. These * allow the calling code to type check. */ -enum AllowGC { - NoGC = 0, - CanGC = 1 -}; +enum AllowGC { NoGC = 0, CanGC = 1 }; template -class MaybeRooted -{ -}; +class MaybeRooted {}; -template class MaybeRooted -{ - public: - typedef JS::Handle HandleType; - typedef JS::Rooted RootType; - typedef JS::MutableHandle MutableHandleType; - - static inline JS::Handle toHandle(HandleType v) { - return v; - } - - static inline JS::MutableHandle toMutableHandle(MutableHandleType v) { - return v; - } - - template - static inline JS::Handle downcastHandle(HandleType v) { - return v.template as(); - } -}; - -template class MaybeRooted -{ - public: - typedef const T& HandleType; - typedef FakeRooted RootType; - typedef FakeMutableHandle MutableHandleType; +template +class MaybeRooted { + public: + typedef JS::Handle HandleType; + typedef JS::Rooted RootType; + typedef JS::MutableHandle MutableHandleType; - static JS::Handle toHandle(HandleType v) { - MOZ_CRASH("Bad conversion"); - } + static inline JS::Handle toHandle(HandleType v) { return v; } - static JS::MutableHandle toMutableHandle(MutableHandleType v) { - MOZ_CRASH("Bad conversion"); - } + static inline JS::MutableHandle toMutableHandle(MutableHandleType v) { + return v; + } - template - static inline T2* downcastHandle(HandleType v) { - return &v->template as(); - } + template + static inline JS::Handle downcastHandle(HandleType v) { + return v.template as(); + } }; } /* namespace js */ namespace JS { -template template -inline -Handle::Handle(const Rooted& root, - typename mozilla::EnableIf::value, int>::Type dummy) -{ - ptr = reinterpret_cast(root.address()); -} - -template template -inline -Handle::Handle(const PersistentRooted& root, - typename mozilla::EnableIf::value, int>::Type dummy) -{ - ptr = reinterpret_cast(root.address()); -} - -template template -inline -Handle::Handle(MutableHandle& root, - typename mozilla::EnableIf::value, int>::Type dummy) -{ - ptr = reinterpret_cast(root.address()); +template +template +inline Handle::Handle( + const Rooted& root, + typename mozilla::EnableIf::value, int>::Type + dummy) { + ptr = reinterpret_cast(root.address()); +} + +template +template +inline Handle::Handle( + const PersistentRooted& root, + typename mozilla::EnableIf::value, int>::Type + dummy) { + ptr = reinterpret_cast(root.address()); } template -inline -MutableHandle::MutableHandle(Rooted* root) -{ - static_assert(sizeof(MutableHandle) == sizeof(T*), - "MutableHandle must be binary compatible with T*."); - ptr = root->address(); +template +inline Handle::Handle( + MutableHandle& root, + typename mozilla::EnableIf::value, int>::Type + dummy) { + ptr = reinterpret_cast(root.address()); } template -inline -MutableHandle::MutableHandle(PersistentRooted* root) -{ - static_assert(sizeof(MutableHandle) == sizeof(T*), - "MutableHandle must be binary compatible with T*."); - ptr = root->address(); +inline MutableHandle::MutableHandle(Rooted* root) { + static_assert(sizeof(MutableHandle) == sizeof(T*), + "MutableHandle must be binary compatible with T*."); + ptr = root->address(); } +template +inline MutableHandle::MutableHandle(PersistentRooted* root) { + static_assert(sizeof(MutableHandle) == sizeof(T*), + "MutableHandle must be binary compatible with T*."); + ptr = root->address(); +} + +JS_PUBLIC_API void AddPersistentRoot(RootingContext* cx, RootKind kind, + PersistentRooted* root); + +JS_PUBLIC_API void AddPersistentRoot(JSRuntime* rt, RootKind kind, + PersistentRooted* root); + /** * A copyable, assignable global GC root type with arbitrary lifetime, an * infallible constructor, and automatic unrooting on destruction. @@ -1075,227 +1166,207 @@ * containing Heap or TenuredHeap members to make sure their referents get * marked when the object itself is marked. */ -template -class PersistentRooted : public js::PersistentRootedBase, - private mozilla::LinkedListElement> -{ - using ListBase = mozilla::LinkedListElement>; - - friend class mozilla::LinkedList; - friend class mozilla::LinkedListElement; - - void registerWithRootLists(js::RootLists& roots) { - MOZ_ASSERT(!initialized()); - JS::RootKind kind = JS::MapTypeToRootKind::kind; - roots.heapRoots_[kind].insertBack(reinterpret_cast*>(this)); - } - - 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(GCPolicy::initial()) {} - - template - explicit PersistentRooted(const RootingContext& cx) - : ptr(GCPolicy::initial()) - { - registerWithRootLists(rootLists(cx)); - } - - template - PersistentRooted(const RootingContext& cx, U&& initial) - : ptr(mozilla::Forward(initial)) - { - registerWithRootLists(rootLists(cx)); - } - - PersistentRooted(const PersistentRooted& rhs) - : mozilla::LinkedListElement>(), - ptr(rhs.ptr) - { - /* - * Copy construction takes advantage of the fact that the original - * is already inserted, and simply adds itself to whatever list the - * original was on - no JSRuntime pointer needed. - * - * This requires mutating rhs's links, but those should be 'mutable' - * anyway. C++ doesn't let us declare mutable base classes. - */ - const_cast(rhs).setNext(this); - } - - bool initialized() { - return ListBase::isInList(); - } - - template - void init(const RootingContext& cx) { - init(cx, GCPolicy::initial()); - } +template +class PersistentRooted + : public js::RootedBase>, + private mozilla::LinkedListElement> { + using ListBase = mozilla::LinkedListElement>; + + friend class mozilla::LinkedList; + friend class mozilla::LinkedListElement; + + void registerWithRootLists(RootingContext* cx) { + MOZ_ASSERT(!initialized()); + JS::RootKind kind = JS::MapTypeToRootKind::kind; + AddPersistentRoot(cx, kind, + reinterpret_cast*>(this)); + } + + void registerWithRootLists(JSRuntime* rt) { + MOZ_ASSERT(!initialized()); + JS::RootKind kind = JS::MapTypeToRootKind::kind; + AddPersistentRoot(rt, kind, + reinterpret_cast*>(this)); + } + + public: + using ElementType = T; + + PersistentRooted() : ptr(GCPolicy::initial()) {} + + explicit PersistentRooted(RootingContext* cx) : ptr(GCPolicy::initial()) { + registerWithRootLists(cx); + } + + explicit PersistentRooted(JSContext* cx) : ptr(GCPolicy::initial()) { + registerWithRootLists(RootingContext::get(cx)); + } + + template + PersistentRooted(RootingContext* cx, U&& initial) + : ptr(mozilla::Forward(initial)) { + registerWithRootLists(cx); + } + + template + PersistentRooted(JSContext* cx, U&& initial) + : ptr(mozilla::Forward(initial)) { + registerWithRootLists(RootingContext::get(cx)); + } + + explicit PersistentRooted(JSRuntime* rt) : ptr(GCPolicy::initial()) { + registerWithRootLists(rt); + } + + template + PersistentRooted(JSRuntime* rt, U&& initial) + : ptr(mozilla::Forward(initial)) { + registerWithRootLists(rt); + } - template - void init(const RootingContext& cx, U&& initial) { - ptr = mozilla::Forward(initial); - registerWithRootLists(rootLists(cx)); - } + PersistentRooted(const PersistentRooted& rhs) + : mozilla::LinkedListElement>(), ptr(rhs.ptr) { + /* + * Copy construction takes advantage of the fact that the original + * is already inserted, and simply adds itself to whatever list the + * original was on - no JSRuntime pointer needed. + * + * This requires mutating rhs's links, but those should be 'mutable' + * anyway. C++ doesn't let us declare mutable base classes. + */ + const_cast(rhs).setNext(this); + } - void reset() { - if (initialized()) { - set(GCPolicy::initial()); - ListBase::remove(); - } - } + bool initialized() { return ListBase::isInList(); } - DECLARE_POINTER_COMPARISON_OPS(T); - DECLARE_POINTER_CONSTREF_OPS(T); - DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T); - DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); - - // These are the same as DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS, except - // they check that |this| is initialized in case the caller later stores - // something in |ptr|. - T* address() { - MOZ_ASSERT(initialized()); - return &ptr; - } - T& get() { - MOZ_ASSERT(initialized()); - return ptr; - } + void init(JSContext* cx) { init(cx, GCPolicy::initial()); } - private: - template - void set(U&& value) { - MOZ_ASSERT(initialized()); - ptr = mozilla::Forward(value); - } + template + void init(JSContext* cx, U&& initial) { + ptr = mozilla::Forward(initial); + registerWithRootLists(RootingContext::get(cx)); + } + + void reset() { + if (initialized()) { + set(GCPolicy::initial()); + ListBase::remove(); + } + } + + DECLARE_POINTER_CONSTREF_OPS(T); + DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T); + DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); + + // These are the same as DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS, except + // they check that |this| is initialized in case the caller later stores + // something in |ptr|. + T* address() { + MOZ_ASSERT(initialized()); + return &ptr; + } + T& get() { + MOZ_ASSERT(initialized()); + return ptr; + } + + private: + template + void set(U&& value) { + MOZ_ASSERT(initialized()); + ptr = mozilla::Forward(value); + } - // See the comment above Rooted::ptr. - using MaybeWrapped = typename mozilla::Conditional< - MapTypeToRootKind::kind == JS::RootKind::Traceable, - js::DispatchWrapper, - T>::Type; - MaybeWrapped ptr; + detail::MaybeWrapped ptr; } JS_HAZ_ROOTED; -class JS_PUBLIC_API(ObjectPtr) -{ - Heap value; +class JS_PUBLIC_API ObjectPtr { + Heap value; - public: - ObjectPtr() : value(nullptr) {} + public: + using ElementType = JSObject*; - explicit ObjectPtr(JSObject* obj) : value(obj) {} + ObjectPtr() : value(nullptr) {} - ObjectPtr(const ObjectPtr& other) : value(other.value) {} + explicit ObjectPtr(JSObject* obj) : value(obj) {} - ObjectPtr(ObjectPtr&& other) - : value(other.value) - { - other.value = nullptr; - } + ObjectPtr(const ObjectPtr& other) : value(other.value) {} - /* Always call finalize before the destructor. */ - ~ObjectPtr() { MOZ_ASSERT(!value); } + ObjectPtr(ObjectPtr&& other) : value(other.value) { other.value = nullptr; } - void finalize(JSRuntime* rt); - void finalize(JSContext* cx); + /* Always call finalize before the destructor. */ + ~ObjectPtr() { MOZ_ASSERT(!value); } - void init(JSObject* obj) { value = obj; } + void finalize(JSRuntime* rt); + void finalize(JSContext* cx); - JSObject* get() const { return value; } - JSObject* unbarrieredGet() const { return value.unbarrieredGet(); } + void init(JSObject* obj) { value = obj; } - void writeBarrierPre(JSContext* cx) { - IncrementalObjectBarrier(value); - } + JSObject* get() const { return value; } + JSObject* unbarrieredGet() const { return value.unbarrieredGet(); } - void updateWeakPointerAfterGC(); + void writeBarrierPre(JSContext* cx) { IncrementalPreWriteBarrier(value); } - ObjectPtr& operator=(JSObject* obj) { - IncrementalObjectBarrier(value); - value = obj; - return *this; - } + void updateWeakPointerAfterGC(); + + ObjectPtr& operator=(JSObject* obj) { + IncrementalPreWriteBarrier(value); + value = obj; + return *this; + } - void trace(JSTracer* trc, const char* name); + void trace(JSTracer* trc, const char* name); - JSObject& operator*() const { return *value; } - JSObject* operator->() const { return value; } - operator JSObject*() const { return value; } + 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(); } + 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> -{ }; +template +class WrappedPtrOperations, Container> { + 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 MutableWrappedPtrOperations, Container> + : public WrappedPtrOperations, Container> { + 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); } +}; namespace gc { template -void -CallTraceCallbackOnNonHeap(T* v, const TraceCallbacks& aCallbacks, const char* aName, void* aClosure) -{ - static_assert(sizeof(T) == sizeof(JS::Heap), "T and Heap must be compatible."); - MOZ_ASSERT(v); - mozilla::DebugOnly cell = BarrierMethods::asGCThingOrNull(*v); - MOZ_ASSERT(cell); - MOZ_ASSERT(!IsInsideNursery(cell)); - JS::Heap* asHeapT = reinterpret_cast*>(v); - aCallbacks.Trace(asHeapT, aName, aClosure); +void CallTraceCallbackOnNonHeap(T* v, const TraceCallbacks& aCallbacks, + const char* aName, void* aClosure) { + static_assert(sizeof(T) == sizeof(JS::Heap), + "T and Heap must be compatible."); + MOZ_ASSERT(v); + mozilla::DebugOnly cell = BarrierMethods::asGCThingOrNull(*v); + MOZ_ASSERT(cell); + MOZ_ASSERT(!IsInsideNursery(cell)); + JS::Heap* asHeapT = reinterpret_cast*>(v); + aCallbacks.Trace(asHeapT, aName, aClosure); } } /* namespace gc */ @@ -1306,25 +1377,225 @@ namespace mozilla { template -inline void -Swap(JS::Heap& aX, JS::Heap& aY) -{ - T tmp = aX; - aX = aY; - aY = tmp; +inline void Swap(JS::Heap& aX, JS::Heap& aY) { + T tmp = aX; + aX = aY; + aY = tmp; } template -inline void -Swap(JS::TenuredHeap& aX, JS::TenuredHeap& aY) -{ - T tmp = aX; - aX = aY; - aY = tmp; +inline void Swap(JS::TenuredHeap& aX, JS::TenuredHeap& aY) { + T tmp = aX; + aX = aY; + aY = tmp; } } /* namespace mozilla */ -#undef DELETE_ASSIGNMENT_OPS +namespace js { +namespace detail { + +// DefineComparisonOps is a trait which selects which wrapper classes to define +// operator== and operator!= for. It supplies a getter function to extract the +// value to compare. This is used to avoid triggering the automatic read +// barriers where appropriate. +// +// If DefineComparisonOps is not specialized for a particular wrapper you may +// get errors such as 'invalid operands to binary expression' or 'no match for +// operator==' when trying to compare against instances of the wrapper. + +template +struct DefineComparisonOps : mozilla::FalseType {}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const JS::Heap& v) { return v.unbarrieredGet(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T get(const JS::TenuredHeap& v) { + return v.unbarrieredGetPtr(); + } +}; + +template <> +struct DefineComparisonOps : mozilla::TrueType { + static const JSObject* get(const JS::ObjectPtr& v) { + return v.unbarrieredGet(); + } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const JS::Rooted& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const JS::Handle& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const JS::MutableHandle& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const JS::PersistentRooted& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const js::FakeRooted& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const js::FakeMutableHandle& v) { return v.get(); } +}; + +} /* namespace detail */ +} /* namespace js */ + +// Overload operator== and operator!= for all types with the DefineComparisonOps +// trait using the supplied getter. +// +// There are four cases: + +// Case 1: comparison between two wrapper objects. + +template +typename mozilla::EnableIf::value && + js::detail::DefineComparisonOps::value, + bool>::Type +operator==(const T& a, const U& b) { + return js::detail::DefineComparisonOps::get(a) == + js::detail::DefineComparisonOps::get(b); +} + +template +typename mozilla::EnableIf::value && + js::detail::DefineComparisonOps::value, + bool>::Type +operator!=(const T& a, const U& b) { + return !(a == b); +} + +// Case 2: comparison between a wrapper object and its unwrapped element type. + +template +typename mozilla::EnableIf::value, + bool>::Type +operator==(const T& a, const typename T::ElementType& b) { + return js::detail::DefineComparisonOps::get(a) == b; +} + +template +typename mozilla::EnableIf::value, + bool>::Type +operator!=(const T& a, const typename T::ElementType& b) { + return !(a == b); +} + +template +typename mozilla::EnableIf::value, + bool>::Type +operator==(const typename T::ElementType& a, const T& b) { + return a == js::detail::DefineComparisonOps::get(b); +} + +template +typename mozilla::EnableIf::value, + bool>::Type +operator!=(const typename T::ElementType& a, const T& b) { + return !(a == b); +} + +// Case 3: For pointer wrappers, comparison between the wrapper and a const +// element pointer. + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator==( + const typename mozilla::RemovePointer::Type* a, + const T& b) { + return a == js::detail::DefineComparisonOps::get(b); +} + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator!=( + const typename mozilla::RemovePointer::Type* a, + const T& b) { + return !(a == b); +} + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator==( + const T& a, + const typename mozilla::RemovePointer::Type* b) { + return js::detail::DefineComparisonOps::get(a) == b; +} + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator!=( + const T& a, + const typename mozilla::RemovePointer::Type* b) { + return !(a == b); +} + +// Case 4: For pointer wrappers, comparison between the wrapper and nullptr. + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator==(std::nullptr_t a, const T& b) { + return a == js::detail::DefineComparisonOps::get(b); +} + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator!=(std::nullptr_t a, const T& b) { + return !(a == b); +} + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator==(const T& a, std::nullptr_t b) { + return js::detail::DefineComparisonOps::get(a) == b; +} + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator!=(const T& a, std::nullptr_t b) { + return !(a == b); +} -#endif /* js_RootingAPI_h */ +#endif /* js_RootingAPI_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/SliceBudget.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/SliceBudget.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/SliceBudget.h @@ -9,20 +9,20 @@ #include +#include "jstypes.h" + namespace js { -struct JS_PUBLIC_API(TimeBudget) -{ - int64_t budget; +struct JS_PUBLIC_API TimeBudget { + int64_t budget; - explicit TimeBudget(int64_t milliseconds) { budget = milliseconds; } + explicit TimeBudget(int64_t milliseconds) { budget = milliseconds; } }; -struct JS_PUBLIC_API(WorkBudget) -{ - int64_t budget; +struct JS_PUBLIC_API WorkBudget { + int64_t budget; - explicit WorkBudget(int64_t work) { budget = work; } + explicit WorkBudget(int64_t work) { budget = work; } }; /* @@ -31,61 +31,57 @@ * to run for unlimited time, and others are bounded. To reduce the number of * gettimeofday calls, we only check the time every 1000 operations. */ -class JS_PUBLIC_API(SliceBudget) -{ - static const int64_t unlimitedDeadline = INT64_MAX; - static const intptr_t unlimitedStartCounter = INTPTR_MAX; +class JS_PUBLIC_API SliceBudget { + static const int64_t unlimitedDeadline = INT64_MAX; + static const intptr_t unlimitedStartCounter = INTPTR_MAX; - bool checkOverBudget(); + bool checkOverBudget(); - SliceBudget(); + SliceBudget(); - public: - // Memory of the originally requested budget. If isUnlimited, neither of - // these are in use. If deadline==0, then workBudget is valid. Otherwise - // timeBudget is valid. - TimeBudget timeBudget; - WorkBudget workBudget; + public: + // Memory of the originally requested budget. If isUnlimited, neither of + // these are in use. If deadline==0, then workBudget is valid. Otherwise + // timeBudget is valid. + TimeBudget timeBudget; + WorkBudget workBudget; - int64_t deadline; /* in microseconds */ - intptr_t counter; + int64_t deadline; /* in microseconds */ + intptr_t counter; - static const intptr_t CounterReset = 1000; + static const intptr_t CounterReset = 1000; - static const int64_t UnlimitedTimeBudget = -1; - static const int64_t UnlimitedWorkBudget = -1; + static const int64_t UnlimitedTimeBudget = -1; + static const int64_t UnlimitedWorkBudget = -1; - /* Use to create an unlimited budget. */ - static SliceBudget unlimited() { return SliceBudget(); } + /* Use to create an unlimited budget. */ + static SliceBudget unlimited() { return SliceBudget(); } - /* Instantiate as SliceBudget(TimeBudget(n)). */ - explicit SliceBudget(TimeBudget time); + /* Instantiate as SliceBudget(TimeBudget(n)). */ + explicit SliceBudget(TimeBudget time); - /* Instantiate as SliceBudget(WorkBudget(n)). */ - explicit SliceBudget(WorkBudget work); + /* Instantiate as SliceBudget(WorkBudget(n)). */ + explicit SliceBudget(WorkBudget work); - void makeUnlimited() { - deadline = unlimitedDeadline; - counter = unlimitedStartCounter; - } + void makeUnlimited() { + deadline = unlimitedDeadline; + counter = unlimitedStartCounter; + } - void step(intptr_t amt = 1) { - counter -= amt; - } + void step(intptr_t amt = 1) { counter -= amt; } - bool isOverBudget() { - if (counter > 0) - return false; - return checkOverBudget(); - } + bool isOverBudget() { + if (counter > 0) return false; + return checkOverBudget(); + } - bool isWorkBudget() const { return deadline == 0; } - bool isTimeBudget() const { return deadline > 0 && !isUnlimited(); } - bool isUnlimited() const { return deadline == unlimitedDeadline; } + bool isWorkBudget() const { return deadline == 0; } + bool isTimeBudget() const { return deadline > 0 && !isUnlimited(); } + bool isUnlimited() const { return deadline == unlimitedDeadline; } - int describe(char* buffer, size_t maxlen) const; + int describe(char* buffer, size_t maxlen) const; }; -} // namespace js +} // namespace js #endif /* js_SliceBudget_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Stream.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Stream.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Stream.h @@ -0,0 +1,516 @@ +/* -*- 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/. */ + +/* + * JSAPI functions and callbacks related to WHATWG Stream objects. + * + * Much of the API here mirrors the JS API of ReadableStream and associated + * classes, e.g. ReadableStreamDefaultReader, ReadableStreamBYOBReader, + * ReadableStreamDefaultController, ReadableByteStreamController, and + * ReadableStreamBYOBRequest. + * + * There are some crucial differences, though: Functionality that's exposed + * as methods/accessors on controllers in JS is exposed as functions taking + * ReadableStream instances instead. This is because an analysis of how + * the API would be used showed that all functions that'd take controllers + * would do so by first getting the controller from the stream instance it's + * associated with and then call the function taking it. I.e., it would purely + * add boilerplate without any gains in ease of use of the API. + * + * It would probably still make sense to factor the API the same as the JS API + * if we had to keep any API stability guarantees: the JS API won't change, so + * we could be sure that the C++ API could stay the same, too. Given that we + * don't guarantee API stability, this concern isn't too pressing. + * + * Some functions exposed here deal with ReadableStream instances that have an + * embedding-provided underlying source. These instances are largely similar + * to byte streams as created using |new ReadableStream({type: "bytes"})|: + * They enable users to acquire ReadableStreamBYOBReaders and only vend chunks + * that're typed array instances. + * + * When creating an "external readable stream" using + * JS::NewReadableExternalSourceStreamObject, an underlying source and a set + * of flags can be passed to be stored on the stream. The underlying source is + * treated as an opaque void* pointer by the JS engine: it's purely meant as + * a reference to be used by the embedding to identify whatever actual source + * it uses to supply data for the stream. Similarly, the flags aren't + * interpreted by the JS engine, but are passed to some of the callbacks below + * and can be retrieved using JS::ReadableStreamGetEmbeddingFlags. + * + * External readable streams are optimized to allow the embedding to interact + * with them with a minimum of overhead: chunks aren't enqueued as individual + * typed array instances; instead, the embedding only updates the amount of + * data available using ReadableStreamUpdateDataAvailableFromSource. + * When content requests data by reading from a reader, + * WriteIntoReadRequestBufferCallback is invoked, asking the embedding to + * write data directly into the buffer we're about to hand to content. + * + * Additionally, ReadableStreamGetExternalUnderlyingSource can be used to + * get the void* pointer to the underlying source. This is equivalent to + * acquiring a reader for the stream in that it locks the stream until it + * is released again using JS::ReadableStreamReleaseExternalUnderlyingSource. + * + * Embeddings are expected to detect situations where an API exposed to JS + * takes a ReadableStream to read from that has an external underlying source. + * In those situations, it might be preferable to directly perform data + * transfers from the stream's underlying source to whatever sink the + * embedding uses, assuming that such direct transfers can be performed + * more efficiently. + * + * An example of such an optimized operation might be a ServiceWorker piping a + * fetch Response body to a TextDecoder: instead of writing chunks of data + * into JS typed array buffers only to immediately read from them again, the + * embedding can presumably directly feed the incoming data to the + * TextDecoder's underlying implementation. + */ + +#ifndef js_Stream_h +#define js_Stream_h + +#include "jstypes.h" + +#include "js/TypeDecls.h" + +namespace JS { + +/** + * Invoked whenever a reader desires more data from a ReadableStream's + * embedding-provided underlying source. + * + * The given |desiredSize| is the absolute size, not a delta from the previous + * desired size. + */ +typedef void (*RequestReadableStreamDataCallback)(JSContext* cx, + HandleObject stream, + void* underlyingSource, + uint8_t flags, + size_t desiredSize); + +/** + * Invoked to cause the embedding to fill the given |buffer| with data from + * the given embedding-provided underlying source. + * + * This can only happen after the embedding has updated the amount of data + * available using JS::ReadableStreamUpdateDataAvailableFromSource. If at + * least one read request is pending when + * JS::ReadableStreamUpdateDataAvailableFromSource is called, + * the WriteIntoReadRequestBufferCallback is invoked immediately from under + * the call to JS::WriteIntoReadRequestBufferCallback. If not, it is invoked + * if and when a new read request is made. + * + * Note: This callback *must not cause GC*, because that could potentially + * invalidate the |buffer| pointer. + */ +typedef void (*WriteIntoReadRequestBufferCallback)( + JSContext* cx, HandleObject stream, void* underlyingSource, uint8_t flags, + void* buffer, size_t length, size_t* bytesWritten); + +/** + * Invoked in reaction to the ReadableStream being canceled to allow the + * embedding to free the underlying source. + * + * This is equivalent to calling |cancel| on non-external underlying sources + * provided to the ReadableStream constructor in JavaScript. + * + * The given |reason| is the JS::Value that was passed as an argument to + * ReadableStream#cancel(). + * + * The returned JS::Value will be used to resolve the Promise returned by + * ReadableStream#cancel(). + */ +typedef Value (*CancelReadableStreamCallback)(JSContext* cx, + HandleObject stream, + void* underlyingSource, + uint8_t flags, + HandleValue reason); + +/** + * Invoked in reaction to a ReadableStream with an embedding-provided + * underlying source being closed. + */ +typedef void (*ReadableStreamClosedCallback)(JSContext* cx, HandleObject stream, + void* underlyingSource, + uint8_t flags); + +/** + * Invoked in reaction to a ReadableStream with an embedding-provided + * underlying source being errored with the + * given reason. + */ +typedef void (*ReadableStreamErroredCallback)(JSContext* cx, + HandleObject stream, + void* underlyingSource, + uint8_t flags, + HandleValue reason); + +/** + * Invoked in reaction to a ReadableStream with an embedding-provided + * underlying source being finalized. Only the underlying source is passed + * as an argument, while the ReadableStream itself is not to prevent the + * embedding from operating on a JSObject that might not be in a valid state + * anymore. + * + * Note: the ReadableStream might be finalized on a background thread. That + * means this callback might be invoked from an arbitrary thread, which the + * embedding must be able to handle. + */ +typedef void (*ReadableStreamFinalizeCallback)(void* underlyingSource, + uint8_t flags); + +/** + * Sets runtime-wide callbacks to use for interacting with embedding-provided + * hooks for operating on ReadableStream instances. + * + * See the documentation for the individual callback types for details. + */ +extern JS_PUBLIC_API void SetReadableStreamCallbacks( + JSContext* cx, RequestReadableStreamDataCallback dataRequestCallback, + WriteIntoReadRequestBufferCallback writeIntoReadRequestCallback, + CancelReadableStreamCallback cancelCallback, + ReadableStreamClosedCallback closedCallback, + ReadableStreamErroredCallback erroredCallback, + ReadableStreamFinalizeCallback finalizeCallback); + +extern JS_PUBLIC_API bool HasReadableStreamCallbacks(JSContext* cx); + +/** + * Returns a new instance of the ReadableStream builtin class in the current + * compartment, configured as a default stream. + * If a |proto| is passed, that gets set as the instance's [[Prototype]] + * instead of the original value of |ReadableStream.prototype|. + */ +extern JS_PUBLIC_API JSObject* NewReadableDefaultStreamObject( + JSContext* cx, HandleObject underlyingSource = nullptr, + HandleFunction size = nullptr, double highWaterMark = 1, + HandleObject proto = nullptr); + +/** + * Returns a new instance of the ReadableStream builtin class in the current + * compartment, configured as a byte stream. + * If a |proto| is passed, that gets set as the instance's [[Prototype]] + * instead of the original value of |ReadableStream.prototype|. + */ +extern JS_PUBLIC_API JSObject* NewReadableByteStreamObject( + JSContext* cx, HandleObject underlyingSource = nullptr, + double highWaterMark = 0, HandleObject proto = nullptr); + +/** + * Returns a new instance of the ReadableStream 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 + * |ReadableStream.prototype|. + * + * The instance is optimized for operating as a byte stream backed by an + * embedding-provided underlying source, using the callbacks set via + * |JS::SetReadableStreamCallbacks|. + * + * The given |flags| will be passed to all applicable callbacks and can be + * used to disambiguate between different types of stream sources the + * embedding might support. + * + * Note: the embedding is responsible for ensuring that the pointer to the + * underlying source stays valid as long as the stream can be read from. + * The underlying source can be freed if the tree is canceled or errored. + * It can also be freed if the stream is destroyed. The embedding is notified + * of that using ReadableStreamFinalizeCallback. + */ +extern JS_PUBLIC_API JSObject* NewReadableExternalSourceStreamObject( + JSContext* cx, void* underlyingSource, uint8_t flags = 0, + HandleObject proto = nullptr); + +/** + * Returns the flags that were passed to NewReadableExternalSourceStreamObject + * when creating the given stream. + * + * Asserts that the given stream has an embedding-provided underlying source. + */ +extern JS_PUBLIC_API uint8_t +ReadableStreamGetEmbeddingFlags(const JSObject* stream); + +/** + * Returns the embedding-provided underlying source of the given |stream|. + * + * Can be used to optimize operations if both the underlying source and the + * intended sink are embedding-provided. In that case it might be + * preferrable to pipe data directly from source to sink without interacting + * with the stream at all. + * + * Locks the stream until ReadableStreamReleaseExternalUnderlyingSource is + * called. + * + * Throws an exception if the stream is locked, i.e. if a reader has been + * acquired for the stream, or if ReadableStreamGetExternalUnderlyingSource + * has been used previously without releasing the external source again. + * + * Throws an exception if the stream isn't readable, i.e if it is errored or + * closed. This is different from ReadableStreamGetReader because we don't + * have a Promise to resolve/reject, which a reader provides. + * + * Asserts that the stream has an embedding-provided underlying source. + */ +extern JS_PUBLIC_API bool ReadableStreamGetExternalUnderlyingSource( + JSContext* cx, HandleObject stream, void** source); + +/** + * Releases the embedding-provided underlying source of the given |stream|, + * returning the stream into an unlocked state. + * + * Asserts that the stream was locked through + * ReadableStreamGetExternalUnderlyingSource. + * + * Asserts that the stream has an embedding-provided underlying source. + */ +extern JS_PUBLIC_API void ReadableStreamReleaseExternalUnderlyingSource( + JSObject* stream); + +/** + * Update the amount of data available at the underlying source of the given + * |stream|. + * + * Can only be used for streams with an embedding-provided underlying source. + * The JS engine will use the given value to satisfy read requests for the + * stream by invoking the JS::WriteIntoReadRequestBuffer callback. + */ +extern JS_PUBLIC_API bool ReadableStreamUpdateDataAvailableFromSource( + JSContext* cx, HandleObject stream, uint32_t availableData); + +/** + * Returns true if the given object is an unwrapped ReadableStream object, + * false otherwise. + */ +extern JS_PUBLIC_API bool IsReadableStream(const JSObject* obj); + +/** + * Returns true if the given object is an unwrapped + * ReadableStreamDefaultReader or ReadableStreamBYOBReader object, + * false otherwise. + */ +extern JS_PUBLIC_API bool IsReadableStreamReader(const JSObject* obj); + +/** + * Returns true if the given object is an unwrapped + * ReadableStreamDefaultReader object, false otherwise. + */ +extern JS_PUBLIC_API bool IsReadableStreamDefaultReader(const JSObject* obj); + +/** + * Returns true if the given object is an unwrapped + * ReadableStreamBYOBReader object, false otherwise. + */ +extern JS_PUBLIC_API bool IsReadableStreamBYOBReader(const JSObject* obj); + +enum class ReadableStreamMode { Default, Byte, ExternalSource }; + +/** + * Returns the stream's ReadableStreamMode. If the mode is |Byte| or + * |ExternalSource|, it's possible to acquire a BYOB reader for more optimized + * operations. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API ReadableStreamMode +ReadableStreamGetMode(const JSObject* stream); + +enum class ReadableStreamReaderMode { Default, BYOB }; + +/** + * Returns true if the given ReadableStream is readable, false if not. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API bool ReadableStreamIsReadable(const JSObject* stream); + +/** + * Returns true if the given ReadableStream is locked, false if not. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API bool ReadableStreamIsLocked(const JSObject* stream); + +/** + * Returns true if the given ReadableStream is disturbed, false if not. + * + * Asserts that |stream| is an ReadableStream instance. + */ +extern JS_PUBLIC_API bool ReadableStreamIsDisturbed(const JSObject* stream); + +/** + * Cancels the given ReadableStream with the given reason and returns a + * Promise resolved according to the result. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API JSObject* ReadableStreamCancel(JSContext* cx, + HandleObject stream, + HandleValue reason); + +/** + * Creates a reader of the type specified by the mode option and locks the + * stream to the new reader. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API JSObject* ReadableStreamGetReader( + JSContext* cx, HandleObject stream, ReadableStreamReaderMode mode); + +/** + * Tees the given ReadableStream and stores the two resulting streams in + * outparams. Returns false if the operation fails, e.g. because the stream is + * locked. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API bool ReadableStreamTee(JSContext* cx, HandleObject stream, + MutableHandleObject branch1Stream, + MutableHandleObject branch2Stream); + +/** + * Retrieves the desired combined size of additional chunks to fill the given + * ReadableStream's queue. Stores the result in |value| and sets |hasValue| to + * true on success, returns false on failure. + * + * If the stream is errored, the call will succeed but no value will be stored + * in |value| and |hasValue| will be set to false. + * + * Note: This is semantically equivalent to the |desiredSize| getter on + * the stream controller's prototype in JS. We expose it with the stream + * itself as a target for simplicity. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API void ReadableStreamGetDesiredSize(JSObject* stream, + bool* hasValue, + double* value); + +/** + * Closes the given ReadableStream. + * + * Throws a TypeError and returns false if the closing operation fails. + * + * Note: This is semantically equivalent to the |close| method on + * the stream controller's prototype in JS. We expose it with the stream + * itself as a target for simplicity. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API bool ReadableStreamClose(JSContext* cx, + HandleObject stream); + +/** + * Returns true if the given ReadableStream reader is locked, false otherwise. + * + * Asserts that |reader| is an unwrapped ReadableStreamDefaultReader or + * ReadableStreamBYOBReader instance. + */ +extern JS_PUBLIC_API bool ReadableStreamReaderIsClosed(const JSObject* reader); + +/** + * Enqueues the given chunk in the given ReadableStream. + * + * Throws a TypeError and returns false if the enqueing operation fails. + * + * Note: This is semantically equivalent to the |enqueue| method on + * the stream controller's prototype in JS. We expose it with the stream + * itself as a target for simplicity. + * + * If the ReadableStream has an underlying byte source, the given chunk must + * be a typed array or a DataView. Consider using + * ReadableByteStreamEnqueueBuffer. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API bool ReadableStreamEnqueue(JSContext* cx, + HandleObject stream, + HandleValue chunk); + +/** + * Enqueues the given buffer as a chunk in the given ReadableStream. + * + * Throws a TypeError and returns false if the enqueing operation fails. + * + * Note: This is semantically equivalent to the |enqueue| method on + * the stream controller's prototype in JS. We expose it with the stream + * itself as a target for simplicity. Additionally, the JS version only + * takes typed arrays and ArrayBufferView instances as arguments, whereas + * this takes an ArrayBuffer, obviating the need to wrap it into a typed + * array. + * + * Asserts that |stream| is an unwrapped ReadableStream instance and |buffer| + * an unwrapped ArrayBuffer instance. + */ +extern JS_PUBLIC_API bool ReadableByteStreamEnqueueBuffer(JSContext* cx, + HandleObject stream, + HandleObject buffer); + +/** + * Errors the given ReadableStream, causing all future interactions to fail + * with the given error value. + * + * Throws a TypeError and returns false if the erroring operation fails. + * + * Note: This is semantically equivalent to the |error| method on + * the stream controller's prototype in JS. We expose it with the stream + * itself as a target for simplicity. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API bool ReadableStreamError(JSContext* cx, + HandleObject stream, + HandleValue error); + +/** + * Cancels the given ReadableStream reader's associated stream. + * + * Throws a TypeError and returns false if the given reader isn't active. + * + * Asserts that |reader| is an unwrapped ReadableStreamDefaultReader or + * ReadableStreamBYOBReader instance. + */ +extern JS_PUBLIC_API bool ReadableStreamReaderCancel(JSContext* cx, + HandleObject reader, + HandleValue reason); + +/** + * Cancels the given ReadableStream reader's associated stream. + * + * Throws a TypeError and returns false if the given reader has pending + * read or readInto (for default or byob readers, respectively) requests. + * + * Asserts that |reader| is an unwrapped ReadableStreamDefaultReader or + * ReadableStreamBYOBReader instance. + */ +extern JS_PUBLIC_API bool ReadableStreamReaderReleaseLock(JSContext* cx, + HandleObject reader); + +/** + * Requests a read from the reader's associated ReadableStream and returns the + * resulting PromiseObject. + * + * Returns a Promise that's resolved with the read result once available or + * rejected immediately if the stream is errored or the operation failed. + * + * Asserts that |reader| is an unwrapped ReadableStreamDefaultReader instance. + */ +extern JS_PUBLIC_API JSObject* ReadableStreamDefaultReaderRead( + JSContext* cx, HandleObject reader); + +/** + * Requests a read from the reader's associated ReadableStream into the given + * ArrayBufferView and returns the resulting PromiseObject. + * + * Returns a Promise that's resolved with the read result once available or + * rejected immediately if the stream is errored or the operation failed. + * + * Asserts that |reader| is an unwrapped ReadableStreamDefaultReader and + * |view| an unwrapped typed array or DataView instance. + */ +extern JS_PUBLIC_API JSObject* ReadableStreamBYOBReaderRead(JSContext* cx, + HandleObject reader, + HandleObject view); + +} // namespace JS + +#endif // js_Realm_h 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 @@ -9,6 +9,7 @@ #include "mozilla/Attributes.h" #include "mozilla/BufferList.h" +#include "mozilla/MemoryReporting.h" #include "mozilla/Move.h" #include @@ -18,110 +19,217 @@ #include "js/RootingAPI.h" #include "js/TypeDecls.h" #include "js/Value.h" +#include "js/Vector.h" + +/* + * API for safe passing of structured data, HTML 2018 Feb 21 section 2.7. + * + * + * This is a serialization scheme for JS values, somewhat like JSON. It + * preserves some aspects of JS objects (strings, numbers, own data properties + * with string keys, array elements) but not others (methods, getters and + * setters, prototype chains). Unlike JSON, structured data: + * + * - can contain cyclic references. + * + * - handles Maps, Sets, and some other object types. + * + * - supports *transferring* objects of certain types from one realm to + * another, rather than cloning them. + * + * - is specified by a living standard, and continues to evolve. + * + * - is encoded in a nonstandard binary format, and is never exposed to Web + * content in its serialized form. It's used internally by the browser to + * send data from one thread/realm/domain to another, not across the + * network. + */ -struct JSRuntime; struct JSStructuredCloneReader; struct JSStructuredCloneWriter; -// API for the HTML5 internal structured cloning algorithm. +/** + * The structured-clone serialization format version number. + * + * When serialized data is stored as bytes, e.g. in your Firefox profile, later + * versions of the engine may have to read it. When you upgrade Firefox, we + * don't crawl through your whole profile converting all saved data from the + * previous version of the serialization format to the latest version. So it is + * normal to have data in old formats stored in your profile. + * + * The JS engine can *write* data only in the current format version. + * + * It can *read* any data written in the current version, and data written for + * DifferentProcess scope in earlier versions. + * + * + * ## When to bump this version number + * + * When making a change so drastic that the JS engine needs to know whether + * it's reading old or new serialized data in order to handle both correctly, + * increment this version number. Make sure the engine can still read all + * old data written with previous versions. + * + * If StructuredClone.cpp doesn't contain code that distinguishes between + * version 8 and version 9, there should not be a version 9. + * + * Do not increment for changes that only affect SameProcess encoding. + * + * Increment only for changes that would otherwise break old serialized data. + * Do not increment for new data types. (Rationale: Modulo bugs, older versions + * of the JS engine can already correctly throw errors when they encounter new, + * unrecognized features. A version number bump does not actually help them.) + */ +#define JS_STRUCTURED_CLONE_VERSION 8 namespace JS { +/** + * Indicates the "scope of validity" of serialized data. + * + * Writing plain JS data produces an array of bytes that can be copied and + * read in another process or whatever. The serialized data is Plain Old Data. + * However, HTML also supports `Transferable` objects, which, when cloned, can + * be moved from the source object into the clone, like when you take a + * photograph of someone and it steals their soul. + * See . + * We support cloning and transferring objects of many types. + * + * For example, when we transfer an ArrayBuffer (within a process), we "detach" + * the ArrayBuffer, embed the raw buffer pointer in the serialized data, and + * later install it in a new ArrayBuffer in the destination realm. Ownership + * of that buffer memory is transferred from the original ArrayBuffer to the + * serialized data and then to the clone. + * + * This only makes sense within a single address space. When we transfer an + * ArrayBuffer to another process, the contents of the buffer must be copied + * into the serialized data. (The original ArrayBuffer is still detached, + * though, for consistency; in some cases the caller shouldn't know or care if + * the recipient is in the same process.) + * + * ArrayBuffers are actually a lucky case; some objects (like MessagePorts) + * can't reasonably be stored by value in serialized data -- it's pointers or + * nothing. + * + * So there is a tradeoff between scope of validity -- how far away the + * serialized data may be sent and still make sense -- and efficiency or + * features. The read and write algorithms therefore take an argument of this + * type, allowing the user to control those trade-offs. + */ 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 + /** + * The most restrictive scope, with greatest efficiency and features. + * + * When writing, this means we're writing for an audience in the same + * process and same thread. The caller promises that the serialized data + * will **not** be shipped off to a different thread/process or stored in a + * database. It's OK to produce serialized data that contains pointers. In + * Rust terms, the serialized data will be treated as `!Send`. + * + * When reading, this means: Accept transferred objects and buffers + * (pointers). The caller promises that the serialized data was written + * using this API (otherwise, the serialized data may contain bogus + * pointers, leading to undefined behavior). + */ + SameProcessSameThread, + + /** + * When writing, this means: The caller promises that the serialized data + * will **not** be shipped off to a different process or stored in a + * database. However, it may be shipped to another thread. It's OK to + * produce serialized data that contains pointers to data that is safe to + * send across threads, such as array buffers. In Rust terms, the + * serialized data will be treated as `Send` but not `Copy`. + * + * When reading, this means the same thing as SameProcessSameThread; + * the distinction only matters when writing. + */ + 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). + * + * When reading, this means: Do not accept pointers. + */ + 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, + /** Transferable data has not been filled in yet */ + SCTAG_TMO_UNFILLED = 0, - /** Structured clone buffer does not yet own the data */ - SCTAG_TMO_UNOWNED = 1, + /** Structured clone buffer does not yet own the data */ + SCTAG_TMO_UNOWNED = 1, - /** All values at least this large are owned by the clone buffer */ - SCTAG_TMO_FIRST_OWNED = 2, + /** All values at least this large are owned by the clone buffer */ + SCTAG_TMO_FIRST_OWNED = 2, - /** Data is a pointer that can be freed */ - SCTAG_TMO_ALLOC_DATA = 2, + /** Data is a pointer that can be freed */ + SCTAG_TMO_ALLOC_DATA = 2, - /** Data is a memory mapped pointer */ - SCTAG_TMO_MAPPED_DATA = 3, + /** Data is a memory mapped pointer */ + 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 = 4, + /** + * 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 = 4, - SCTAG_TMO_USER_MIN + 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; - } +class CloneDataPolicy { + bool sharedArrayBuffer_; - bool isSharedArrayBufferAllowed() const { - return 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. @@ -131,8 +239,10 @@ * from the reader r. closure is any value passed to the JS_ReadStructuredClone * function. Return the new object on success, nullptr on error/exception. */ -typedef JSObject* (*ReadStructuredCloneOp)(JSContext* cx, JSStructuredCloneReader* r, - uint32_t tag, uint32_t data, void* closure); +typedef JSObject* (*ReadStructuredCloneOp)(JSContext* cx, + JSStructuredCloneReader* r, + uint32_t tag, uint32_t data, + void* closure); /** * Structured data serialization hook. The engine can write primitive values, @@ -146,7 +256,8 @@ * * Return true on success, false on error/exception. */ -typedef bool (*WriteStructuredCloneOp)(JSContext* cx, JSStructuredCloneWriter* w, +typedef bool (*WriteStructuredCloneOp)(JSContext* cx, + JSStructuredCloneWriter* w, JS::HandleObject obj, void* closure); /** @@ -163,10 +274,9 @@ * DATA_CLONE_ERR DOM Exception. This method is called before any other * callback and must return a non-null object in returnObject on success. */ -typedef bool (*ReadTransferStructuredCloneOp)(JSContext* cx, JSStructuredCloneReader* r, - uint32_t tag, void* content, uint64_t extraData, - void* closure, - JS::MutableHandleObject returnObject); +typedef bool (*ReadTransferStructuredCloneOp)( + JSContext* cx, JSStructuredCloneReader* r, uint32_t tag, void* content, + uint64_t extraData, void* closure, JS::MutableHandleObject returnObject); /** * Called when JS_WriteStructuredClone receives a transferable object not @@ -189,206 +299,244 @@ // Output: uint32_t* tag, JS::TransferableOwnership* ownership, - void** content, - uint64_t* extraData); + void** content, uint64_t* extraData); /** * 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); - -// The maximum supported structured-clone serialization format version. -// 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 8 +typedef void (*FreeTransferStructuredCloneOp)( + uint32_t tag, JS::TransferableOwnership ownership, void* content, + uint64_t extraData, void* closure); struct JSStructuredCloneCallbacks { - ReadStructuredCloneOp read; - WriteStructuredCloneOp write; - StructuredCloneErrorOp reportError; - ReadTransferStructuredCloneOp readTransfer; - TransferStructuredCloneOp writeTransfer; - FreeTransferStructuredCloneOp freeTransfer; + ReadStructuredCloneOp read; + WriteStructuredCloneOp write; + StructuredCloneErrorOp reportError; + ReadTransferStructuredCloneOp readTransfer; + TransferStructuredCloneOp writeTransfer; + FreeTransferStructuredCloneOp freeTransfer; }; enum OwnTransferablePolicy { - OwnsTransferablesIfAny, - IgnoreTransferablesIfAny, - NoTransferables + OwnsTransferablesIfAny, + IgnoreTransferablesIfAny, + NoTransferables }; +namespace js { +class SharedArrayRawBuffer; + +class JS_PUBLIC_API SharedArrayRawBufferRefs { + public: + SharedArrayRawBufferRefs() = default; + SharedArrayRawBufferRefs(SharedArrayRawBufferRefs&& other) = default; + SharedArrayRawBufferRefs& operator=(SharedArrayRawBufferRefs&& other); + ~SharedArrayRawBufferRefs(); + + MOZ_MUST_USE bool acquire(JSContext* cx, SharedArrayRawBuffer* rawbuf); + MOZ_MUST_USE bool acquireAll(JSContext* cx, + const SharedArrayRawBufferRefs& that); + void takeOwnership(SharedArrayRawBufferRefs&&); + void releaseAll(); + + private: + js::Vector refs_; +}; + +template +struct BufferIterator; +} // namespace js + /** * 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; - } +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_ = nullptr; + void* closure_ = nullptr; + OwnTransferablePolicy ownTransferables_ = + OwnTransferablePolicy::NoTransferables; + js::SharedArrayRawBufferRefs refsHeld_; + + 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 scope) + : bufList_(0, 0, kStandardCapacity, js::SystemAllocPolicy()), + scope_(scope), + 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 scope) + : bufList_(mozilla::Move(buffers)), + scope_(scope), + 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; + } + + bool Init(size_t initialCapacity = 0) { + return bufList_.Init(0, initialCapacity); + } + + JS::StructuredCloneScope scope() const { return scope_; } + + void initScope(JS::StructuredCloneScope scope) { + MOZ_ASSERT(Size() == 0, "initScope() of nonempty JSStructuredCloneData"); + if (scope_ != JS::StructuredCloneScope::Unassigned) + MOZ_ASSERT(scope_ == scope, + "Cannot change scope after it has been initialized"); + scope_ = scope; + } + + 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; + } + + char* AllocateBytes(size_t maxSize, size_t* size) { + return bufList_.AllocateBytes(maxSize, size); + } + + 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); }); + } + + size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) { + return bufList_.SizeOfExcludingThis(mallocSizeOf); + } - // 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(); + void discardTransferables(); }; -/** Note: if the *data contains transferable objects, it can be read only once. */ -JS_PUBLIC_API(bool) -JS_ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data, uint32_t version, - JS::StructuredCloneScope scope, - JS::MutableHandleValue vp, - const JSStructuredCloneCallbacks* optionalCallbacks, void* closure); - -JS_PUBLIC_API(bool) -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_StructuredCloneHasTransferables(JSStructuredCloneData& data, bool* hasTransferable); - -JS_PUBLIC_API(bool) -JS_StructuredClone(JSContext* cx, JS::HandleValue v, JS::MutableHandleValue vp, - const JSStructuredCloneCallbacks* optionalCallbacks, void* closure); +/** + * Implements StructuredDeserialize and StructuredDeserializeWithTransfer. + * + * Note: If `data` contains transferable objects, it can be read only once. + */ +JS_PUBLIC_API bool JS_ReadStructuredClone( + JSContext* cx, JSStructuredCloneData& data, uint32_t version, + JS::StructuredCloneScope scope, JS::MutableHandleValue vp, + const JSStructuredCloneCallbacks* optionalCallbacks, void* closure); + +/** + * Implements StructuredSerialize, StructuredSerializeForStorage, and + * StructuredSerializeWithTransfer. + * + * Note: If the scope is DifferentProcess then the cloneDataPolicy must deny + * shared-memory objects, or an error will be signaled if a shared memory object + * is seen. + */ +JS_PUBLIC_API bool 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_StructuredCloneHasTransferables( + JSStructuredCloneData& data, bool* hasTransferable); + +JS_PUBLIC_API bool JS_StructuredClone( + JSContext* cx, JS::HandleValue v, JS::MutableHandleValue vp, + const JSStructuredCloneCallbacks* optionalCallbacks, void* closure); /** * The C-style API calls to read and write structured clones are fragile -- @@ -402,103 +550,124 @@ * management, and uses the same callbacks for both writing and reading * (serializing and deserializing). */ -class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) { - const JS::StructuredCloneScope scope_; - JSStructuredCloneData data_; - uint32_t version_; - - public: - 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(); } - - JSStructuredCloneData& data() { return data_; } - bool empty() const { return !data_.Size(); } - - void clear(); - - 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(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. - */ - 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() to - * properly release that data eventually. - */ - void abandon() { data_.ownTransferables_ = OwnTransferablePolicy::IgnoreTransferablesIfAny; } - - bool read(JSContext* cx, JS::MutableHandleValue vp, - const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr); - - bool write(JSContext* cx, JS::HandleValue v, - 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: - // Copy and assignment are not supported. - JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer& other) = delete; - JSAutoStructuredCloneBuffer& operator=(const JSAutoStructuredCloneBuffer& other) = delete; +class JS_PUBLIC_API JSAutoStructuredCloneBuffer { + const JS::StructuredCloneScope scope_; + JSStructuredCloneData data_; + uint32_t version_; + + public: + JSAutoStructuredCloneBuffer(JS::StructuredCloneScope scope, + const JSStructuredCloneCallbacks* callbacks, + void* closure) + : scope_(scope), data_(scope), version_(JS_STRUCTURED_CLONE_VERSION) { + data_.setCallbacks(callbacks, closure, + OwnTransferablePolicy::NoTransferables); + } + + JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other); + JSAutoStructuredCloneBuffer& operator=(JSAutoStructuredCloneBuffer&& other); + + ~JSAutoStructuredCloneBuffer() { clear(); } + + JSStructuredCloneData& data() { return data_; } + bool empty() const { return !data_.Size(); } + + void clear(); + + 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(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. + */ + 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() to + * properly release that data eventually. + */ + void abandon() { + data_.ownTransferables_ = OwnTransferablePolicy::IgnoreTransferablesIfAny; + } + + bool read(JSContext* cx, JS::MutableHandleValue vp, + const JSStructuredCloneCallbacks* optionalCallbacks = nullptr, + void* closure = nullptr); + + bool write(JSContext* cx, JS::HandleValue v, + 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); + + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) { + return data_.SizeOfExcludingThis(mallocSizeOf); + } + + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) { + return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf); + } + + private: + // Copy and assignment are not supported. + JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer& other) = + delete; + JSAutoStructuredCloneBuffer& operator=( + const JSAutoStructuredCloneBuffer& other) = delete; }; -// The range of tag values the application may use for its own custom object types. -#define JS_SCTAG_USER_MIN ((uint32_t) 0xFFFF8000) -#define JS_SCTAG_USER_MAX ((uint32_t) 0xFFFFFFFF) +// The range of tag values the application may use for its own custom object +// types. +#define JS_SCTAG_USER_MIN ((uint32_t)0xFFFF8000) +#define JS_SCTAG_USER_MAX ((uint32_t)0xFFFFFFFF) #define JS_SCERR_RECURSION 0 #define JS_SCERR_TRANSFERABLE 1 #define JS_SCERR_DUP_TRANSFERABLE 2 #define JS_SCERR_UNSUPPORTED_TYPE 3 +#define JS_SCERR_SHMEM_TRANSFERABLE 4 -JS_PUBLIC_API(bool) -JS_ReadUint32Pair(JSStructuredCloneReader* r, uint32_t* p1, uint32_t* p2); +JS_PUBLIC_API bool JS_ReadUint32Pair(JSStructuredCloneReader* r, uint32_t* p1, + uint32_t* p2); -JS_PUBLIC_API(bool) -JS_ReadBytes(JSStructuredCloneReader* r, void* p, size_t len); +JS_PUBLIC_API bool JS_ReadBytes(JSStructuredCloneReader* r, void* p, + size_t len); -JS_PUBLIC_API(bool) -JS_ReadTypedArray(JSStructuredCloneReader* r, JS::MutableHandleValue vp); +JS_PUBLIC_API bool JS_ReadTypedArray(JSStructuredCloneReader* r, + JS::MutableHandleValue vp); -JS_PUBLIC_API(bool) -JS_WriteUint32Pair(JSStructuredCloneWriter* w, uint32_t tag, uint32_t data); +JS_PUBLIC_API bool JS_WriteUint32Pair(JSStructuredCloneWriter* w, uint32_t tag, + uint32_t data); -JS_PUBLIC_API(bool) -JS_WriteBytes(JSStructuredCloneWriter* w, const void* p, size_t len); +JS_PUBLIC_API bool JS_WriteBytes(JSStructuredCloneWriter* w, const void* p, + size_t len); -JS_PUBLIC_API(bool) -JS_WriteString(JSStructuredCloneWriter* w, JS::HandleString str); +JS_PUBLIC_API bool JS_WriteString(JSStructuredCloneWriter* w, + JS::HandleString str); -JS_PUBLIC_API(bool) -JS_WriteTypedArray(JSStructuredCloneWriter* w, JS::HandleValue v); +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 bool JS_ObjectNotWritten(JSStructuredCloneWriter* w, + JS::HandleObject obj); -JS_PUBLIC_API(JS::StructuredCloneScope) -JS_GetStructuredCloneScope(JSStructuredCloneWriter* w); +JS_PUBLIC_API JS::StructuredCloneScope JS_GetStructuredCloneScope( + JSStructuredCloneWriter* w); -#endif /* js_StructuredClone_h */ +#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 @@ -9,57 +9,73 @@ #include "js/HeapAPI.h" -namespace js { -template -class WeakCacheBase {}; -} // namespace js - namespace JS { -template class WeakCache; +namespace detail { +class WeakCacheBase; +} // namespace detail namespace shadow { -JS_PUBLIC_API(void) -RegisterWeakCache(JS::Zone* zone, JS::WeakCache* cachep); -} // namespace shadow +JS_PUBLIC_API void RegisterWeakCache(JS::Zone* zone, + JS::detail::WeakCacheBase* cachep); +JS_PUBLIC_API void RegisterWeakCache(JSRuntime* rt, + JS::detail::WeakCacheBase* cachep); +} // namespace shadow + +namespace detail { +class WeakCacheBase : public mozilla::LinkedListElement { + WeakCacheBase() = delete; + explicit WeakCacheBase(const WeakCacheBase&) = delete; + + public: + explicit WeakCacheBase(Zone* zone) { shadow::RegisterWeakCache(zone, this); } + explicit WeakCacheBase(JSRuntime* rt) { shadow::RegisterWeakCache(rt, this); } + WeakCacheBase(WeakCacheBase&& other) = default; + virtual ~WeakCacheBase() {} + + virtual size_t sweep() = 0; + virtual bool needsSweep() = 0; + + virtual bool setNeedsIncrementalBarrier(bool needs) { + // Derived classes do not support incremental barriers by default. + return false; + } + virtual bool needsIncrementalBarrier() const { + // Derived classes do not support incremental barriers by default. + return false; + } +}; +} // namespace detail // A WeakCache stores the given Sweepable container and links itself into a -// list of such caches that are swept during each GC. +// list of such caches that are swept during each GC. A WeakCache can be +// specific to a zone, or across a whole runtime, depending on which +// constructor is used. 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; } +class WeakCache : protected detail::WeakCacheBase, + public js::MutableWrappedPtrOperations> { + T cache; + + public: + using Type = T; + + template + explicit WeakCache(Zone* zone, Args&&... args) + : WeakCacheBase(zone), cache(mozilla::Forward(args)...) {} + template + explicit WeakCache(JSRuntime* rt, Args&&... args) + : WeakCacheBase(rt), cache(mozilla::Forward(args)...) {} + + const T& get() const { return cache; } + T& get() { return cache; } + + size_t sweep() override { + GCPolicy::sweep(&cache); + return 0; + } - void sweep() { sweeper(&cache); } + bool needsSweep() override { return cache.needsSweep(); } }; -} // namespace JS +} // namespace JS -#endif // js_SweepingAPI_h +#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 @@ -16,12 +16,13 @@ class BaseShape; class LazyScript; class ObjectGroup; +class RegExpShared; class Shape; class Scope; namespace jit { class JitCode; -} // namespace jit -} // namespace js +} // namespace jit +} // namespace js namespace JS { @@ -34,121 +35,141 @@ // the matching C++ types are exposed, and those that are, are opaque. // // See Value::gcKind() and JSTraceCallback in Tracer.h for more details. -enum class TraceKind -{ - // These trace kinds have a publicly exposed, although opaque, C++ type. - // Note: The order here is determined by our Value packing. Other users - // should sort alphabetically, for consistency. - Object = 0x00, - String = 0x01, - Symbol = 0x02, - Script = 0x03, - - // Shape details are exposed through JS_TraceShapeCycleCollectorChildren. - Shape = 0x04, - - // ObjectGroup details are exposed through JS_TraceObjectGroupCycleCollectorChildren. - ObjectGroup = 0x05, - - // The kind associated with a nullptr. - Null = 0x06, - - // The following kinds do not have an exposed C++ idiom. - BaseShape = 0x0F, - JitCode = 0x1F, - LazyScript = 0x2F, - Scope = 0x3F +enum class TraceKind { + // These trace kinds have a publicly exposed, although opaque, C++ type. + // Note: The order here is determined by our Value packing. Other users + // should sort alphabetically, for consistency. + Object = 0x00, + String = 0x02, + Symbol = 0x03, + + // 0x1 is not used for any GCThing Value tag, so we use it for Script. + Script = 0x01, + + // Shape details are exposed through JS_TraceShapeCycleCollectorChildren. + Shape = 0x04, + + // ObjectGroup details are exposed through + // JS_TraceObjectGroupCycleCollectorChildren. + ObjectGroup = 0x05, + + // The kind associated with a nullptr. + Null = 0x06, + + // The following kinds do not have an exposed C++ idiom. + BaseShape = 0x0F, + JitCode = 0x1F, + LazyScript = 0x2F, + Scope = 0x3F, + RegExpShared = 0x4F }; 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"); + +#define ASSERT_TRACE_KIND(tk) \ + static_assert( \ + (uintptr_t(tk) & OutOfLineTraceKindMask) == OutOfLineTraceKindMask, \ + "mask bits are set") +ASSERT_TRACE_KIND(JS::TraceKind::BaseShape); +ASSERT_TRACE_KIND(JS::TraceKind::JitCode); +ASSERT_TRACE_KIND(JS::TraceKind::LazyScript); +ASSERT_TRACE_KIND(JS::TraceKind::Scope); +ASSERT_TRACE_KIND(JS::TraceKind::RegExpShared); +#undef ASSERT_TRACE_KIND // 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; + 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) \ - D(Shape, js::Shape, true) \ - D(String, JSString, false) \ - D(Symbol, JS::Symbol, false) +#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) \ + D(Shape, js::Shape, true) \ + D(String, JSString, false) \ + D(Symbol, JS::Symbol, false) \ + D(RegExpShared, js::RegExpShared, true) // 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; \ - }; +#define JS_EXPAND_DEF(name, type, _) \ + template <> \ + struct MapTypeToTraceKind { \ + static const JS::TraceKind kind = JS::TraceKind::name; \ + }; 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) +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, + // These tagged pointers are special-cased for performance. + Id, + Value, - // Everything else. - Traceable, + // Everything else. + Traceable, - Limit + 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; \ - }; +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 +// Cell 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; + static const JS::RootKind kind = JS::RootKind::Traceable; }; template struct MapTypeToRootKind { - static const JS::RootKind kind = - JS::MapTraceKindToRootKind::kind>::kind; + static const JS::RootKind kind = + JS::MapTraceKindToRootKind::kind>::kind; +}; +template <> +struct MapTypeToRootKind { + // Not a pointer to a GC cell. Use GCPolicy. + static const JS::RootKind kind = JS::RootKind::Traceable; }; template struct MapTypeToRootKind> { - static const JS::RootKind kind = JS::MapTypeToRootKind::kind; + 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::Value; +}; +template <> +struct MapTypeToRootKind { + static const JS::RootKind kind = JS::RootKind::Id; }; -template <> struct MapTypeToRootKind { - static const JS::RootKind kind = JS::RootKind::Id; -}; -template <> struct MapTypeToRootKind : public MapTypeToRootKind {}; +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 @@ -164,49 +185,49 @@ // type designated by |traceKind| as the functor's template argument. The // |thing| parameter is optional; without it, we simply pass through |... args|. -// GCC and Clang require an explicit template declaration in front of the -// specialization of operator() because it is a dependent template. MSVC, on -// the other hand, gets very confused if we have a |template| token there. +// VS2017+, GCC and Clang require an explicit template declaration in front of +// the specialization of operator() because it is a dependent template. VS2015, +// on the other hand, gets very confused if we have a |template| token there. // The clang-cl front end defines _MSC_VER, but still requires the explicit // template declaration, so we must test for __clang__ here as well. -#if defined(_MSC_VER) && !defined(__clang__) -# define JS_DEPENDENT_TEMPLATE_HINT +#if (defined(_MSC_VER) && _MSC_VER < 1910) && !defined(__clang__) +#define JS_DEPENDENT_TEMPLATE_HINT #else -# define JS_DEPENDENT_TEMPLATE_HINT template +#define JS_DEPENDENT_TEMPLATE_HINT template #endif template -auto -DispatchTraceKindTyped(F f, JS::TraceKind traceKind, Args&&... args) - -> decltype(f. JS_DEPENDENT_TEMPLATE_HINT operator()(mozilla::Forward(args)...)) -{ - switch (traceKind) { -#define JS_EXPAND_DEF(name, type, _) \ - case JS::TraceKind::name: \ - return f. JS_DEPENDENT_TEMPLATE_HINT operator()(mozilla::Forward(args)...); - JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); +auto DispatchTraceKindTyped(F f, JS::TraceKind traceKind, Args&&... args) + -> decltype(f.JS_DEPENDENT_TEMPLATE_HINT operator()( + mozilla::Forward(args)...)) { + switch (traceKind) { +#define JS_EXPAND_DEF(name, type, _) \ + case JS::TraceKind::name: \ + return f.JS_DEPENDENT_TEMPLATE_HINT operator()( \ + mozilla::Forward(args)...); + JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); #undef JS_EXPAND_DEF - default: - MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped."); - } + default: + MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped."); + } } #undef JS_DEPENDENT_TEMPLATE_HINT template -auto -DispatchTraceKindTyped(F f, void* thing, JS::TraceKind traceKind, Args&&... args) - -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) -{ - switch (traceKind) { +auto DispatchTraceKindTyped(F f, void* thing, JS::TraceKind traceKind, + Args&&... args) + -> decltype(f(static_cast(nullptr), + mozilla::Forward(args)...)) { + switch (traceKind) { #define JS_EXPAND_DEF(name, type, _) \ - case JS::TraceKind::name: \ - return f(static_cast(thing), mozilla::Forward(args)...); - JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); + case JS::TraceKind::name: \ + return f(static_cast(thing), mozilla::Forward(args)...); + JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); #undef JS_EXPAND_DEF - default: - MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped."); - } + default: + MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped."); + } } -} // namespace JS +} // namespace JS -#endif // js_TraceKind_h +#endif // js_TraceKind_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 @@ -7,116 +7,126 @@ #ifndef js_TracingAPI_h #define js_TracingAPI_h -#include "jsalloc.h" - +#include "js/AllocPolicy.h" #include "js/HashTable.h" #include "js/HeapAPI.h" #include "js/TraceKind.h" -class JS_PUBLIC_API(JSTracer); +class JS_PUBLIC_API JSTracer; namespace JS { -class JS_PUBLIC_API(CallbackTracer); -template class Heap; -template class TenuredHeap; +class JS_PUBLIC_API CallbackTracer; +template +class Heap; +template +class TenuredHeap; /** Returns a static string equivalent of |kind|. */ -JS_FRIEND_API(const char*) -GCTraceKindToAscii(JS::TraceKind kind); +JS_FRIEND_API const char* GCTraceKindToAscii(JS::TraceKind kind); -} // namespace JS +} // namespace JS enum WeakMapTraceKind { - /** - * 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 - * the default for GCMarker. - */ - ExpandWeakMaps, - - /** - * Trace through to all values, irrespective of whether the keys are live - * or not. Used for non-marking tracers. - */ - TraceWeakMapValues, - - /** - * Trace through to all keys and values, irrespective of whether the keys - * are live or not. Used for non-marking tracers. - */ - TraceWeakMapKeysValues + /** + * 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 + * the default for GCMarker. + */ + ExpandWeakMaps, + + /** + * Trace through to all values, irrespective of whether the keys are live + * or not. Used for non-marking tracers. + */ + TraceWeakMapValues, + + /** + * Trace through to all keys and values, irrespective of whether the keys + * are live or not. Used for non-marking tracers. + */ + TraceWeakMapKeysValues }; -class JS_PUBLIC_API(JSTracer) -{ - public: - // Return the runtime set on the tracer. - JSRuntime* runtime() const { return runtime_; } - - // Return the weak map tracing behavior currently set on this tracer. - WeakMapTraceKind weakMapAction() const { return weakMapAction_; } - - 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, - - // 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; } - bool isWeakMarkingTracer() const { return tag_ == TracerKindTag::WeakMarking; } - bool isTenuringTracer() const { return tag_ == TracerKindTag::Tenuring; } - bool isCallbackTracer() const { return tag_ == TracerKindTag::Callback; } - inline JS::CallbackTracer* asCallbackTracer(); +class JS_PUBLIC_API JSTracer { + public: + // Return the runtime set on the tracer. + JSRuntime* runtime() const { return runtime_; } + + // Return the weak map tracing behavior currently set on this tracer. + WeakMapTraceKind weakMapAction() const { return weakMapAction_; } + + 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, + + // 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; + } + bool isWeakMarkingTracer() const { + return tag_ == TracerKindTag::WeakMarking; + } + bool isTenuringTracer() const { return tag_ == TracerKindTag::Tenuring; } + bool isCallbackTracer() const { return tag_ == TracerKindTag::Callback; } + inline JS::CallbackTracer* asCallbackTracer(); + bool traceWeakEdges() const { return traceWeakEdges_; } #ifdef DEBUG - bool checkEdges() { return checkEdges_; } + bool checkEdges() { return checkEdges_; } #endif - protected: - JSTracer(JSRuntime* rt, TracerKindTag tag, - WeakMapTraceKind weakTraceKind = TraceWeakMapValues) - : runtime_(rt) - , weakMapAction_(weakTraceKind) + // Get the current GC number. Only call this method if |isMarkingTracer()| + // is true. + uint32_t gcNumberForMarking() const; + + protected: + JSTracer(JSRuntime* rt, TracerKindTag tag, + WeakMapTraceKind weakTraceKind = TraceWeakMapValues) + : runtime_(rt), + weakMapAction_(weakTraceKind) #ifdef DEBUG - , checkEdges_(true) + , + checkEdges_(true) #endif - , tag_(tag) - {} + , + tag_(tag), + traceWeakEdges_(true) { + } #ifdef DEBUG - // Set whether to check edges are valid in debug builds. - void setCheckEdges(bool check) { - checkEdges_ = check; - } + // Set whether to check edges are valid in debug builds. + void setCheckEdges(bool check) { checkEdges_ = check; } #endif - private: - JSRuntime* runtime_; - WeakMapTraceKind weakMapAction_; + private: + JSRuntime* runtime_; + WeakMapTraceKind weakMapAction_; #ifdef DEBUG - bool checkEdges_; + bool checkEdges_; #endif - protected: - TracerKindTag tag_; + protected: + TracerKindTag tag_; + bool traceWeakEdges_; }; namespace JS { @@ -125,200 +135,230 @@ class AutoTracingIndex; class AutoTracingCallback; -class JS_PUBLIC_API(CallbackTracer) : public JSTracer -{ - public: - CallbackTracer(JSRuntime* rt, WeakMapTraceKind weakTraceKind = TraceWeakMapValues) +class JS_PUBLIC_API CallbackTracer : public JSTracer { + public: + CallbackTracer(JSRuntime* rt, + WeakMapTraceKind weakTraceKind = TraceWeakMapValues) : 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 - // dispatches to the fully-generic onChild implementation, so for cases that - // do not care about boxing overhead and do not need the actual edges, - // just override the generic onChild. - virtual void onObjectEdge(JSObject** objp) { onChild(JS::GCCellPtr(*objp)); } - virtual void onStringEdge(JSString** strp) { onChild(JS::GCCellPtr(*strp)); } - virtual void onSymbolEdge(JS::Symbol** symp) { onChild(JS::GCCellPtr(*symp)); } - virtual void onScriptEdge(JSScript** scriptp) { onChild(JS::GCCellPtr(*scriptp)); } - virtual void onShapeEdge(js::Shape** shapep) { - onChild(JS::GCCellPtr(*shapep, JS::TraceKind::Shape)); - } - virtual void onObjectGroupEdge(js::ObjectGroup** groupp) { - onChild(JS::GCCellPtr(*groupp, JS::TraceKind::ObjectGroup)); - } - virtual void onBaseShapeEdge(js::BaseShape** basep) { - onChild(JS::GCCellPtr(*basep, JS::TraceKind::BaseShape)); - } - virtual void onJitCodeEdge(js::jit::JitCode** codep) { - onChild(JS::GCCellPtr(*codep, JS::TraceKind::JitCode)); - } - 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. - virtual void onChild(const JS::GCCellPtr& thing) = 0; - - // Access to the tracing context: - // When tracing with a JS::CallbackTracer, we invoke the callback with the - // edge location and the type of target. This is useful for operating on - // the edge in the abstract or on the target thing, satisfying most common - // use cases. However, some tracers need additional detail about the - // specific edge that is being traced in order to be useful. Unfortunately, - // the raw pointer to the edge that we provide is not enough information to - // infer much of anything useful about that edge. - // - // In order to better support use cases that care in particular about edges - // -- as opposed to the target thing -- tracing implementations are - // responsible for providing extra context information about each edge they - // trace, as it is traced. This contains, at a minimum, an edge name and, - // when tracing an array, the index. Further specialization can be achived - // (with some complexity), by associating a functor with the tracer so - // that, when requested, the user can generate totally custom edge - // descriptions. - - // Returns the current edge's name. It is only valid to call this when - // inside the trace callback, however, the edge name will always be set. - const char* contextName() const { MOZ_ASSERT(contextName_); return contextName_; } - - // Returns the current edge's index, if marked as part of an array of edges. - // This must be called only inside the trace callback. When not tracing an - // array, the value will be InvalidIndex. - const static size_t InvalidIndex = size_t(-1); - size_t contextIndex() const { return contextIndex_; } - - // Build a description of this edge in the heap graph. This call may invoke - // the context functor, if set, which may inspect arbitrary areas of the - // heap. On the other hand, the description provided by this method may be - // substantially more accurate and useful than those provided by only the - // contextName and contextIndex. - void getTracingEdgeName(char* buffer, size_t bufferSize); - - // The trace implementation may associate a callback with one or more edges - // using AutoTracingDetails. This functor is called by getTracingEdgeName - // and is responsible for providing a textual representation of the - // currently being traced edge. The callback has access to the full heap, - // including the currently set tracing context. - class ContextFunctor { - public: - virtual void operator()(CallbackTracer* trc, char* buf, size_t bufsize) = 0; - }; + 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 + // dispatches to the fully-generic onChild implementation, so for cases that + // do not care about boxing overhead and do not need the actual edges, + // just override the generic onChild. + virtual void onObjectEdge(JSObject** objp) { onChild(JS::GCCellPtr(*objp)); } + virtual void onStringEdge(JSString** strp) { onChild(JS::GCCellPtr(*strp)); } + virtual void onSymbolEdge(JS::Symbol** symp) { + onChild(JS::GCCellPtr(*symp)); + } + virtual void onScriptEdge(JSScript** scriptp) { + onChild(JS::GCCellPtr(*scriptp)); + } + virtual void onShapeEdge(js::Shape** shapep) { + onChild(JS::GCCellPtr(*shapep, JS::TraceKind::Shape)); + } + virtual void onObjectGroupEdge(js::ObjectGroup** groupp) { + onChild(JS::GCCellPtr(*groupp, JS::TraceKind::ObjectGroup)); + } + virtual void onBaseShapeEdge(js::BaseShape** basep) { + onChild(JS::GCCellPtr(*basep, JS::TraceKind::BaseShape)); + } + virtual void onJitCodeEdge(js::jit::JitCode** codep) { + onChild(JS::GCCellPtr(*codep, JS::TraceKind::JitCode)); + } + 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)); + } + virtual void onRegExpSharedEdge(js::RegExpShared** sharedp) { + onChild(JS::GCCellPtr(*sharedp, JS::TraceKind::RegExpShared)); + } + + // Override this method to receive notification when a node in the GC + // heap graph is visited. + virtual void onChild(const JS::GCCellPtr& thing) = 0; + + // Access to the tracing context: + // When tracing with a JS::CallbackTracer, we invoke the callback with the + // edge location and the type of target. This is useful for operating on + // the edge in the abstract or on the target thing, satisfying most common + // use cases. However, some tracers need additional detail about the + // specific edge that is being traced in order to be useful. Unfortunately, + // the raw pointer to the edge that we provide is not enough information to + // infer much of anything useful about that edge. + // + // In order to better support use cases that care in particular about edges + // -- as opposed to the target thing -- tracing implementations are + // responsible for providing extra context information about each edge they + // trace, as it is traced. This contains, at a minimum, an edge name and, + // when tracing an array, the index. Further specialization can be achived + // (with some complexity), by associating a functor with the tracer so + // that, when requested, the user can generate totally custom edge + // descriptions. + + // Returns the current edge's name. It is only valid to call this when + // inside the trace callback, however, the edge name will always be set. + const char* contextName() const { + MOZ_ASSERT(contextName_); + return contextName_; + } + + // Returns the current edge's index, if marked as part of an array of edges. + // This must be called only inside the trace callback. When not tracing an + // array, the value will be InvalidIndex. + const static size_t InvalidIndex = size_t(-1); + size_t contextIndex() const { return contextIndex_; } + + // Build a description of this edge in the heap graph. This call may invoke + // the context functor, if set, which may inspect arbitrary areas of the + // heap. On the other hand, the description provided by this method may be + // substantially more accurate and useful than those provided by only the + // contextName and contextIndex. + void getTracingEdgeName(char* buffer, size_t bufferSize); + + // The trace implementation may associate a callback with one or more edges + // using AutoTracingDetails. This functor is called by getTracingEdgeName + // and is responsible for providing a textual representation of the + // currently being traced edge. The callback has access to the full heap, + // including the currently set tracing context. + class ContextFunctor { + public: + virtual void operator()(CallbackTracer* trc, char* buf, size_t bufsize) = 0; + }; #ifdef DEBUG - enum class TracerKind { DoNotCare, Moving, GrayBuffering, VerifyTraceProtoAndIface }; - virtual TracerKind getTracerKind() const { return TracerKind::DoNotCare; } + enum class TracerKind { + DoNotCare, + Moving, + GrayBuffering, + VerifyTraceProtoAndIface, + ClearEdges, + UnmarkGray + }; + virtual TracerKind getTracerKind() const { return TracerKind::DoNotCare; } #endif - // In C++, overriding a method hides all methods in the base class with - // that name, not just methods with that signature. Thus, the typed edge - // methods have to have distinct names to allow us to override them - // individually, which is freqently useful if, for example, we only want to - // process only one type of edge. - void dispatchToOnEdge(JSObject** objp) { onObjectEdge(objp); } - void dispatchToOnEdge(JSString** strp) { onStringEdge(strp); } - void dispatchToOnEdge(JS::Symbol** symp) { onSymbolEdge(symp); } - void dispatchToOnEdge(JSScript** scriptp) { onScriptEdge(scriptp); } - void dispatchToOnEdge(js::Shape** shapep) { onShapeEdge(shapep); } - void dispatchToOnEdge(js::ObjectGroup** groupp) { onObjectGroupEdge(groupp); } - 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; - const char* contextName_; + // In C++, overriding a method hides all methods in the base class with + // that name, not just methods with that signature. Thus, the typed edge + // methods have to have distinct names to allow us to override them + // individually, which is freqently useful if, for example, we only want to + // process only one type of edge. + void dispatchToOnEdge(JSObject** objp) { onObjectEdge(objp); } + void dispatchToOnEdge(JSString** strp) { onStringEdge(strp); } + void dispatchToOnEdge(JS::Symbol** symp) { onSymbolEdge(symp); } + void dispatchToOnEdge(JSScript** scriptp) { onScriptEdge(scriptp); } + void dispatchToOnEdge(js::Shape** shapep) { onShapeEdge(shapep); } + void dispatchToOnEdge(js::ObjectGroup** groupp) { onObjectGroupEdge(groupp); } + 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); } + void dispatchToOnEdge(js::RegExpShared** sharedp) { + onRegExpSharedEdge(sharedp); + } + + protected: + void setTraceWeakEdges(bool value) { traceWeakEdges_ = value; } + + private: + friend class AutoTracingName; + const char* contextName_; - friend class AutoTracingIndex; - size_t contextIndex_; + friend class AutoTracingIndex; + size_t contextIndex_; - friend class AutoTracingDetails; - ContextFunctor* contextFunctor_; + friend class AutoTracingDetails; + ContextFunctor* contextFunctor_; }; // Set the name portion of the tracer's context for the current edge. -class MOZ_RAII AutoTracingName -{ - CallbackTracer* trc_; - const char* prior_; - - public: - AutoTracingName(CallbackTracer* trc, const char* name) : trc_(trc), prior_(trc->contextName_) { - MOZ_ASSERT(name); - trc->contextName_ = name; - } - ~AutoTracingName() { - MOZ_ASSERT(trc_->contextName_); - trc_->contextName_ = prior_; - } +class MOZ_RAII AutoTracingName { + CallbackTracer* trc_; + const char* prior_; + + public: + AutoTracingName(CallbackTracer* trc, const char* name) + : trc_(trc), prior_(trc->contextName_) { + MOZ_ASSERT(name); + trc->contextName_ = name; + } + ~AutoTracingName() { + MOZ_ASSERT(trc_->contextName_); + trc_->contextName_ = prior_; + } }; // Set the index portion of the tracer's context for the current range. -class MOZ_RAII AutoTracingIndex -{ - CallbackTracer* trc_; - - public: - explicit AutoTracingIndex(JSTracer* trc, size_t initial = 0) : trc_(nullptr) { - if (trc->isCallbackTracer()) { - trc_ = trc->asCallbackTracer(); - MOZ_ASSERT(trc_->contextIndex_ == CallbackTracer::InvalidIndex); - trc_->contextIndex_ = initial; - } - } - ~AutoTracingIndex() { - if (trc_) { - MOZ_ASSERT(trc_->contextIndex_ != CallbackTracer::InvalidIndex); - trc_->contextIndex_ = CallbackTracer::InvalidIndex; - } - } +class MOZ_RAII AutoTracingIndex { + CallbackTracer* trc_; - void operator++() { - if (trc_) { - MOZ_ASSERT(trc_->contextIndex_ != CallbackTracer::InvalidIndex); - ++trc_->contextIndex_; - } + public: + explicit AutoTracingIndex(JSTracer* trc, size_t initial = 0) : trc_(nullptr) { + if (trc->isCallbackTracer()) { + trc_ = trc->asCallbackTracer(); + MOZ_ASSERT(trc_->contextIndex_ == CallbackTracer::InvalidIndex); + trc_->contextIndex_ = initial; + } + } + ~AutoTracingIndex() { + if (trc_) { + MOZ_ASSERT(trc_->contextIndex_ != CallbackTracer::InvalidIndex); + trc_->contextIndex_ = CallbackTracer::InvalidIndex; + } + } + + void operator++() { + if (trc_) { + MOZ_ASSERT(trc_->contextIndex_ != CallbackTracer::InvalidIndex); + ++trc_->contextIndex_; } + } }; // Set a context callback for the trace callback to use, if it needs a detailed // edge description. -class MOZ_RAII AutoTracingDetails -{ - CallbackTracer* trc_; - - public: - AutoTracingDetails(JSTracer* trc, CallbackTracer::ContextFunctor& func) : trc_(nullptr) { - if (trc->isCallbackTracer()) { - trc_ = trc->asCallbackTracer(); - MOZ_ASSERT(trc_->contextFunctor_ == nullptr); - trc_->contextFunctor_ = &func; - } - } - ~AutoTracingDetails() { - if (trc_) { - MOZ_ASSERT(trc_->contextFunctor_); - trc_->contextFunctor_ = nullptr; - } +class MOZ_RAII AutoTracingDetails { + CallbackTracer* trc_; + + public: + AutoTracingDetails(JSTracer* trc, CallbackTracer::ContextFunctor& func) + : trc_(nullptr) { + if (trc->isCallbackTracer()) { + trc_ = trc->asCallbackTracer(); + MOZ_ASSERT(trc_->contextFunctor_ == nullptr); + trc_->contextFunctor_ = &func; + } + } + ~AutoTracingDetails() { + if (trc_) { + MOZ_ASSERT(trc_->contextFunctor_); + trc_->contextFunctor_ = nullptr; } + } }; -} // namespace JS +} // namespace JS -JS::CallbackTracer* -JSTracer::asCallbackTracer() -{ - MOZ_ASSERT(isCallbackTracer()); - return static_cast(this); +JS::CallbackTracer* JSTracer::asCallbackTracer() { + MOZ_ASSERT(isCallbackTracer()); + return static_cast(this); } +namespace js { +namespace gc { +template +JS_PUBLIC_API void TraceExternalEdge(JSTracer* trc, T* thingp, + const char* name); +} // namespace gc +} // namespace js + namespace JS { // The JS::TraceEdge family of functions traces the given GC thing reference. @@ -335,12 +375,22 @@ // // 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); +inline void TraceEdge(JSTracer* trc, JS::Heap* thingp, const char* name) { + MOZ_ASSERT(thingp); + if (*thingp) js::gc::TraceExternalEdge(trc, thingp->unsafeGet(), name); +} -extern JS_PUBLIC_API(void) -TraceEdge(JSTracer* trc, JS::TenuredHeap* edgep, const char* name); +template +inline void TraceEdge(JSTracer* trc, JS::TenuredHeap* thingp, + const char* name) { + MOZ_ASSERT(thingp); + if (T ptr = thingp->unbarrieredGetPtr()) { + js::gc::TraceExternalEdge(trc, &ptr, name); + thingp->setPtr(ptr); + } +} // Edges that are always traced as part of root marking do not require // incremental barriers. This function allows for marking non-barriered @@ -349,29 +399,31 @@ // Note that while |edgep| must never be null, it is fine for |*edgep| to be // nullptr. template -extern JS_PUBLIC_API(void) -UnsafeTraceRoot(JSTracer* trc, T* edgep, const char* name); +extern JS_PUBLIC_API void UnsafeTraceRoot(JSTracer* trc, T* edgep, + const char* name); -extern JS_PUBLIC_API(void) -TraceChildren(JSTracer* trc, GCCellPtr thing); +extern JS_PUBLIC_API void TraceChildren(JSTracer* trc, GCCellPtr thing); -using ZoneSet = js::HashSet, js::SystemAllocPolicy>; -using CompartmentSet = js::HashSet, - js::SystemAllocPolicy>; +using ZoneSet = + js::HashSet, js::SystemAllocPolicy>; +using CompartmentSet = + js::HashSet, + js::SystemAllocPolicy>; /** * 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) -TraceIncomingCCWs(JSTracer* trc, const JS::CompartmentSet& compartments); +extern JS_PUBLIC_API void TraceIncomingCCWs( + JSTracer* trc, const JS::CompartmentSet& compartments); -} // namespace JS +} // namespace JS -extern JS_PUBLIC_API(void) -JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, - void* thing, JS::TraceKind kind, bool includeDetails); +extern JS_PUBLIC_API void JS_GetTraceThingInfo(char* buf, size_t bufsize, + JSTracer* trc, void* thing, + JS::TraceKind kind, + bool includeDetails); namespace js { @@ -381,23 +433,22 @@ // 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 -extern JS_PUBLIC_API(void) -UnsafeTraceManuallyBarrieredEdge(JSTracer* trc, T* edgep, const char* name); +extern JS_PUBLIC_API void UnsafeTraceManuallyBarrieredEdge(JSTracer* trc, + T* edgep, + const char* name); namespace gc { // Return true if the given edge is not live and is about to be swept. template -extern JS_PUBLIC_API(bool) -EdgeNeedsSweep(JS::Heap* edgep); +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 -bool -IsAboutToBeFinalizedUnbarriered(T* thingp); +bool IsAboutToBeFinalizedUnbarriered(T* thingp); -} // namespace gc -} // namespace js +} // 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 @@ -11,275 +11,294 @@ namespace JS { -#define TRACKED_STRATEGY_LIST(_) \ - _(GetProp_ArgumentsLength) \ - _(GetProp_ArgumentsCallee) \ - _(GetProp_InferredConstant) \ - _(GetProp_Constant) \ - _(GetProp_NotDefined) \ - _(GetProp_StaticName) \ - _(GetProp_SimdGetter) \ - _(GetProp_TypedObject) \ - _(GetProp_DefiniteSlot) \ - _(GetProp_Unboxed) \ - _(GetProp_CommonGetter) \ - _(GetProp_InlineAccess) \ - _(GetProp_Innerize) \ - _(GetProp_InlineCache) \ - _(GetProp_SharedCache) \ - _(GetProp_ModuleNamespace) \ - \ - _(SetProp_CommonSetter) \ - _(SetProp_TypedObject) \ - _(SetProp_DefiniteSlot) \ - _(SetProp_Unboxed) \ - _(SetProp_InlineAccess) \ - _(SetProp_InlineCache) \ - \ - _(GetElem_TypedObject) \ - _(GetElem_Dense) \ - _(GetElem_TypedStatic) \ - _(GetElem_TypedArray) \ - _(GetElem_String) \ - _(GetElem_Arguments) \ - _(GetElem_ArgumentsInlined) \ - _(GetElem_InlineCache) \ - \ - _(SetElem_TypedObject) \ - _(SetElem_TypedStatic) \ - _(SetElem_TypedArray) \ - _(SetElem_Dense) \ - _(SetElem_Arguments) \ - _(SetElem_InlineCache) \ - \ - _(BinaryArith_Concat) \ - _(BinaryArith_SpecializedTypes) \ - _(BinaryArith_SpecializedOnBaselineTypes) \ - _(BinaryArith_SharedCache) \ - _(BinaryArith_Call) \ - \ - _(InlineCache_OptimizedStub) \ - \ - _(Call_Inline) - +#define TRACKED_STRATEGY_LIST(_) \ + _(GetProp_ArgumentsLength) \ + _(GetProp_ArgumentsCallee) \ + _(GetProp_InferredConstant) \ + _(GetProp_Constant) \ + _(GetProp_NotDefined) \ + _(GetProp_StaticName) \ + _(GetProp_SimdGetter) \ + _(GetProp_TypedObject) \ + _(GetProp_DefiniteSlot) \ + _(GetProp_Unboxed) \ + _(GetProp_CommonGetter) \ + _(GetProp_InlineAccess) \ + _(GetProp_InlineProtoAccess) \ + _(GetProp_Innerize) \ + _(GetProp_InlineCache) \ + _(GetProp_ModuleNamespace) \ + \ + _(SetProp_CommonSetter) \ + _(SetProp_TypedObject) \ + _(SetProp_DefiniteSlot) \ + _(SetProp_Unboxed) \ + _(SetProp_InlineAccess) \ + _(SetProp_InlineCache) \ + \ + _(GetElem_TypedObject) \ + _(GetElem_Dense) \ + _(GetElem_TypedArray) \ + _(GetElem_String) \ + _(GetElem_Arguments) \ + _(GetElem_ArgumentsInlinedConstant) \ + _(GetElem_ArgumentsInlinedSwitch) \ + _(GetElem_InlineCache) \ + \ + _(SetElem_TypedObject) \ + _(SetElem_TypedArray) \ + _(SetElem_Dense) \ + _(SetElem_Arguments) \ + _(SetElem_InlineCache) \ + \ + _(BinaryArith_Concat) \ + _(BinaryArith_SpecializedTypes) \ + _(BinaryArith_SpecializedOnBaselineTypes) \ + _(BinaryArith_SharedCache) \ + _(BinaryArith_Call) \ + \ + _(InlineCache_OptimizedStub) \ + \ + _(NewArray_TemplateObject) \ + _(NewArray_SharedCache) \ + _(NewArray_Call) \ + \ + _(NewObject_TemplateObject) \ + _(NewObject_SharedCache) \ + _(NewObject_Call) \ + \ + _(Compare_SpecializedTypes) \ + _(Compare_Bitwise) \ + _(Compare_SpecializedOnBaselineTypes) \ + _(Compare_SharedCache) \ + _(Compare_Call) \ + \ + _(Call_Inline) // Ordering is important below. All outcomes before GenericSuccess will be // considered failures, and all outcomes after GenericSuccess will be // considered successes. -#define TRACKED_OUTCOME_LIST(_) \ - _(GenericFailure) \ - _(Disabled) \ - _(NoTypeInfo) \ - _(NoAnalysisInfo) \ - _(NoShapeInfo) \ - _(UnknownObject) \ - _(UnknownProperties) \ - _(Singleton) \ - _(NotSingleton) \ - _(NotFixedSlot) \ - _(InconsistentFixedSlot) \ - _(NotObject) \ - _(NotStruct) \ - _(NotUnboxed) \ - _(NotUndefined) \ - _(UnboxedConvertedToNative) \ - _(StructNoField) \ - _(InconsistentFieldType) \ - _(InconsistentFieldOffset) \ - _(NeedsTypeBarrier) \ - _(InDictionaryMode) \ - _(NoProtoFound) \ - _(MultiProtoPaths) \ - _(NonWritableProperty) \ - _(ProtoIndexedProps) \ - _(ArrayBadFlags) \ - _(ArrayDoubleConversion) \ - _(ArrayRange) \ - _(ArraySeenNegativeIndex) \ - _(TypedObjectHasDetachedBuffer) \ - _(TypedObjectArrayRange) \ - _(AccessNotDense) \ - _(AccessNotSimdObject) \ - _(AccessNotTypedObject) \ - _(AccessNotTypedArray) \ - _(AccessNotString) \ - _(OperandNotString) \ - _(OperandNotNumber) \ - _(OperandNotStringOrNumber) \ - _(OperandNotSimpleArith) \ - _(StaticTypedArrayUint32) \ - _(StaticTypedArrayCantComputeMask) \ - _(OutOfBounds) \ - _(GetElemStringNotCached) \ - _(NonNativeReceiver) \ - _(IndexType) \ - _(SetElemNonDenseNonTANotCached) \ - _(NoSimdJitSupport) \ - _(SimdTypeNotOptimized) \ - _(UnknownSimdProperty) \ - _(NotModuleNamespace) \ - _(UnknownProperty) \ - \ - _(ICOptStub_GenericSuccess) \ - \ - _(ICGetPropStub_ReadSlot) \ - _(ICGetPropStub_CallGetter) \ - _(ICGetPropStub_ArrayLength) \ - _(ICGetPropStub_UnboxedRead) \ - _(ICGetPropStub_UnboxedReadExpando) \ - _(ICGetPropStub_UnboxedArrayLength) \ - _(ICGetPropStub_TypedArrayLength) \ - _(ICGetPropStub_DOMProxyShadowed) \ - _(ICGetPropStub_DOMProxyUnshadowed) \ - _(ICGetPropStub_GenericProxy) \ - _(ICGetPropStub_ArgumentsLength) \ - \ - _(ICSetPropStub_Slot) \ - _(ICSetPropStub_GenericProxy) \ - _(ICSetPropStub_DOMProxyShadowed) \ - _(ICSetPropStub_DOMProxyUnshadowed) \ - _(ICSetPropStub_CallSetter) \ - _(ICSetPropStub_AddSlot) \ - _(ICSetPropStub_SetUnboxed) \ - \ - _(ICGetElemStub_ReadSlot) \ - _(ICGetElemStub_CallGetter) \ - _(ICGetElemStub_ReadUnboxed) \ - _(ICGetElemStub_Dense) \ - _(ICGetElemStub_DenseHole) \ - _(ICGetElemStub_TypedArray) \ - _(ICGetElemStub_ArgsElementMapped) \ - _(ICGetElemStub_ArgsElementUnmapped) \ - \ - _(ICSetElemStub_Dense) \ - _(ICSetElemStub_TypedArray) \ - \ - _(ICNameStub_ReadSlot) \ - _(ICNameStub_CallGetter) \ - _(ICNameStub_TypeOfNoProperty) \ - \ - _(CantInlineGeneric) \ - _(CantInlineNoTarget) \ - _(CantInlineNotInterpreted) \ - _(CantInlineNoBaseline) \ - _(CantInlineLazy) \ - _(CantInlineNotConstructor) \ - _(CantInlineClassConstructor) \ - _(CantInlineDisabledIon) \ - _(CantInlineTooManyArgs) \ - _(CantInlineNeedsArgsObj) \ - _(CantInlineDebuggee) \ - _(CantInlineUnknownProps) \ - _(CantInlineExceededDepth) \ - _(CantInlineExceededTotalBytecodeLength) \ - _(CantInlineBigCaller) \ - _(CantInlineBigCallee) \ - _(CantInlineBigCalleeInlinedBytecodeLength) \ - _(CantInlineNotHot) \ - _(CantInlineNotInDispatch) \ - _(CantInlineUnreachable) \ - _(CantInlineNativeBadForm) \ - _(CantInlineNativeBadType) \ - _(CantInlineNativeNoTemplateObj) \ - _(CantInlineBound) \ - _(CantInlineNativeNoSpecialization) \ - _(HasCommonInliningPath) \ - \ - _(GenericSuccess) \ - _(Inlined) \ - _(DOM) \ - _(Monomorphic) \ - _(Polymorphic) - -#define TRACKED_TYPESITE_LIST(_) \ - _(Receiver) \ - _(Operand) \ - _(Index) \ - _(Value) \ - _(Call_Target) \ - _(Call_This) \ - _(Call_Arg) \ - _(Call_Return) +#define TRACKED_OUTCOME_LIST(_) \ + _(GenericFailure) \ + _(Disabled) \ + _(NoTypeInfo) \ + _(NoAnalysisInfo) \ + _(NoShapeInfo) \ + _(UnknownObject) \ + _(UnknownProperties) \ + _(Singleton) \ + _(NotSingleton) \ + _(NotFixedSlot) \ + _(InconsistentFixedSlot) \ + _(NotObject) \ + _(NotStruct) \ + _(NotUnboxed) \ + _(NotUndefined) \ + _(UnboxedConvertedToNative) \ + _(StructNoField) \ + _(InconsistentFieldType) \ + _(InconsistentFieldOffset) \ + _(NeedsTypeBarrier) \ + _(InDictionaryMode) \ + _(NoProtoFound) \ + _(MultiProtoPaths) \ + _(NonWritableProperty) \ + _(ProtoIndexedProps) \ + _(ArrayBadFlags) \ + _(ArrayDoubleConversion) \ + _(ArrayRange) \ + _(ArraySeenNegativeIndex) \ + _(TypedObjectHasDetachedBuffer) \ + _(TypedObjectArrayRange) \ + _(AccessNotDense) \ + _(AccessNotSimdObject) \ + _(AccessNotTypedObject) \ + _(AccessNotTypedArray) \ + _(AccessNotString) \ + _(OperandNotString) \ + _(OperandNotNumber) \ + _(OperandNotStringOrNumber) \ + _(OperandNotSimpleArith) \ + _(OperandNotEasilyCoercibleToString) \ + _(OutOfBounds) \ + _(GetElemStringNotCached) \ + _(NonNativeReceiver) \ + _(IndexType) \ + _(SetElemNonDenseNonTANotCached) \ + _(NoSimdJitSupport) \ + _(SimdTypeNotOptimized) \ + _(UnknownSimdProperty) \ + _(NotModuleNamespace) \ + _(UnknownProperty) \ + _(NoTemplateObject) \ + _(TemplateObjectIsUnboxedWithoutInlineElements) \ + _(TemplateObjectIsPlainObjectWithDynamicSlots) \ + _(LengthTooBig) \ + _(SpeculationOnInputTypesFailed) \ + _(RelationalCompare) \ + _(OperandTypeNotBitwiseComparable) \ + _(OperandMaybeEmulatesUndefined) \ + _(LoosyUndefinedNullCompare) \ + _(LoosyInt32BooleanCompare) \ + _(CallsValueOf) \ + _(StrictCompare) \ + _(InitHole) \ + \ + _(ICOptStub_GenericSuccess) \ + \ + _(ICGetPropStub_ReadSlot) \ + _(ICGetPropStub_CallGetter) \ + _(ICGetPropStub_ArrayLength) \ + _(ICGetPropStub_UnboxedRead) \ + _(ICGetPropStub_UnboxedReadExpando) \ + _(ICGetPropStub_UnboxedArrayLength) \ + _(ICGetPropStub_TypedArrayLength) \ + _(ICGetPropStub_DOMProxyShadowed) \ + _(ICGetPropStub_DOMProxyUnshadowed) \ + _(ICGetPropStub_GenericProxy) \ + _(ICGetPropStub_ArgumentsLength) \ + \ + _(ICSetPropStub_Slot) \ + _(ICSetPropStub_GenericProxy) \ + _(ICSetPropStub_DOMProxyShadowed) \ + _(ICSetPropStub_DOMProxyUnshadowed) \ + _(ICSetPropStub_CallSetter) \ + _(ICSetPropStub_AddSlot) \ + _(ICSetPropStub_SetUnboxed) \ + \ + _(ICGetElemStub_ReadSlot) \ + _(ICGetElemStub_CallGetter) \ + _(ICGetElemStub_ReadUnboxed) \ + _(ICGetElemStub_Dense) \ + _(ICGetElemStub_DenseHole) \ + _(ICGetElemStub_TypedArray) \ + _(ICGetElemStub_ArgsElementMapped) \ + _(ICGetElemStub_ArgsElementUnmapped) \ + \ + _(ICSetElemStub_Dense) \ + _(ICSetElemStub_TypedArray) \ + \ + _(ICNameStub_ReadSlot) \ + _(ICNameStub_CallGetter) \ + _(ICNameStub_TypeOfNoProperty) \ + \ + _(CantInlineGeneric) \ + _(CantInlineNoTarget) \ + _(CantInlineNotInterpreted) \ + _(CantInlineNoBaseline) \ + _(CantInlineLazy) \ + _(CantInlineNotConstructor) \ + _(CantInlineClassConstructor) \ + _(CantInlineDisabledIon) \ + _(CantInlineTooManyArgs) \ + _(CantInlineNeedsArgsObj) \ + _(CantInlineDebuggee) \ + _(CantInlineExceededDepth) \ + _(CantInlineExceededTotalBytecodeLength) \ + _(CantInlineBigCaller) \ + _(CantInlineBigCallee) \ + _(CantInlineBigCalleeInlinedBytecodeLength) \ + _(CantInlineNotHot) \ + _(CantInlineNotInDispatch) \ + _(CantInlineUnreachable) \ + _(CantInlineNativeBadForm) \ + _(CantInlineNativeBadType) \ + _(CantInlineNativeNoTemplateObj) \ + _(CantInlineBound) \ + _(CantInlineNativeNoSpecialization) \ + _(HasCommonInliningPath) \ + \ + _(GenericSuccess) \ + _(Inlined) \ + _(DOM) \ + _(Monomorphic) \ + _(Polymorphic) + +#define TRACKED_TYPESITE_LIST(_) \ + _(Receiver) \ + _(Operand) \ + _(Index) \ + _(Value) \ + _(Call_Target) \ + _(Call_This) \ + _(Call_Arg) \ + _(Call_Return) enum class TrackedStrategy : uint32_t { #define STRATEGY_OP(name) name, - TRACKED_STRATEGY_LIST(STRATEGY_OP) + TRACKED_STRATEGY_LIST(STRATEGY_OP) #undef STRATEGY_OPT - Count + Count }; enum class TrackedOutcome : uint32_t { #define OUTCOME_OP(name) name, - TRACKED_OUTCOME_LIST(OUTCOME_OP) + TRACKED_OUTCOME_LIST(OUTCOME_OP) #undef OUTCOME_OP - Count + Count }; enum class TrackedTypeSite : uint32_t { #define TYPESITE_OP(name) name, - TRACKED_TYPESITE_LIST(TYPESITE_OP) + TRACKED_TYPESITE_LIST(TYPESITE_OP) #undef TYPESITE_OP - Count + Count }; -JS_PUBLIC_API(const char*) -TrackedStrategyString(TrackedStrategy strategy); +JS_PUBLIC_API const char* TrackedStrategyString(TrackedStrategy strategy); -JS_PUBLIC_API(const char*) -TrackedOutcomeString(TrackedOutcome outcome); +JS_PUBLIC_API const char* TrackedOutcomeString(TrackedOutcome outcome); -JS_PUBLIC_API(const char*) -TrackedTypeSiteString(TrackedTypeSite site); +JS_PUBLIC_API const char* TrackedTypeSiteString(TrackedTypeSite site); -struct ForEachTrackedOptimizationAttemptOp -{ - virtual void operator()(TrackedStrategy strategy, TrackedOutcome outcome) = 0; +struct ForEachTrackedOptimizationAttemptOp { + virtual void operator()(TrackedStrategy strategy, TrackedOutcome outcome) = 0; }; -struct ForEachTrackedOptimizationTypeInfoOp -{ - // Called 0+ times per entry, once for each type in the type set that Ion - // saw during MIR construction. readType is always called _before_ - // operator() on the same entry. - // - // The keyedBy parameter describes how the type is keyed: - // - "primitive" for primitive types - // - "constructor" for object types tied to a scripted constructor - // function. - // - "alloc site" for object types tied to an allocation site. - // - "prototype" for object types tied neither to a constructor nor - // to an allocation site, but to a prototype. - // - "singleton" for object types which only has a single value. - // - "function" for object types referring to scripted functions. - // - "native" for object types referring to native functions. - // - // The name parameter is the string representation of the type. If the - // type is keyed by "constructor", or if the type itself refers to a - // scripted function, the name is the function's displayAtom. If the type - // is keyed by "native", this is nullptr. - // - // The location parameter is the filename if the type is keyed by - // "constructor", "alloc site", or if the type itself refers to a scripted - // function. If the type is keyed by "native", it is the offset of the - // native function, suitable for use with addr2line on Linux or atos on OS - // X. Otherwise it is nullptr. - // - // The lineno parameter is the line number if the type is keyed by - // "constructor", "alloc site", or if the type itself refers to a scripted - // function. Otherwise it is Nothing(). - // - // The location parameter is the only one that may need escaping if being - // quoted. - virtual void readType(const char* keyedBy, const char* name, - const char* location, mozilla::Maybe lineno) = 0; +struct ForEachTrackedOptimizationTypeInfoOp { + // Called 0+ times per entry, once for each type in the type set that Ion + // saw during MIR construction. readType is always called _before_ + // operator() on the same entry. + // + // The keyedBy parameter describes how the type is keyed: + // - "primitive" for primitive types + // - "constructor" for object types tied to a scripted constructor + // function. + // - "alloc site" for object types tied to an allocation site. + // - "prototype" for object types tied neither to a constructor nor + // to an allocation site, but to a prototype. + // - "singleton" for object types which only has a single value. + // - "function" for object types referring to scripted functions. + // - "native" for object types referring to native functions. + // + // The name parameter is the string representation of the type. If the + // type is keyed by "constructor", or if the type itself refers to a + // scripted function, the name is the function's displayAtom. If the type + // is keyed by "native", this is nullptr. + // + // The location parameter is the filename if the type is keyed by + // "constructor", "alloc site", or if the type itself refers to a scripted + // function. If the type is keyed by "native", it is the offset of the + // native function, suitable for use with addr2line on Linux or atos on OS + // X. Otherwise it is nullptr. + // + // The lineno parameter is the line number if the type is keyed by + // "constructor", "alloc site", or if the type itself refers to a scripted + // function. Otherwise it is Nothing(). + // + // The location parameter is the only one that may need escaping if being + // quoted. + virtual void readType(const char* keyedBy, const char* name, + const char* location, + const mozilla::Maybe& lineno) = 0; - // Called once per entry. - virtual void operator()(TrackedTypeSite site, const char* mirType) = 0; + // Called once per entry. + virtual void operator()(TrackedTypeSite site, const char* mirType) = 0; }; -} // namespace JS +} // namespace JS -#endif // js_TrackedOptimizationInfo_h +#endif // js_TrackedOptimizationInfo_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/TypeDecls.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/TypeDecls.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/TypeDecls.h @@ -22,12 +22,18 @@ #include "js-config.h" +typedef uint8_t jsbytecode; + +class JSAtom; +struct JSCompartment; struct JSContext; class JSFunction; class JSObject; +struct JSRuntime; class JSScript; class JSString; class JSAddonId; +struct JSFreeOp; struct jsid; @@ -37,43 +43,51 @@ class Symbol; class Value; -template class Handle; -template class MutableHandle; -template class Rooted; -template class PersistentRooted; +class Realm; +struct Runtime; +struct Zone; + +template +class Handle; +template +class MutableHandle; +template +class Rooted; +template +class PersistentRooted; typedef Handle HandleFunction; -typedef Handle HandleId; -typedef Handle HandleObject; -typedef Handle HandleScript; -typedef Handle HandleString; +typedef Handle HandleId; +typedef Handle HandleObject; +typedef Handle HandleScript; +typedef Handle HandleString; typedef Handle HandleSymbol; -typedef Handle HandleValue; +typedef Handle HandleValue; typedef MutableHandle MutableHandleFunction; -typedef MutableHandle MutableHandleId; -typedef MutableHandle MutableHandleObject; -typedef MutableHandle MutableHandleScript; -typedef MutableHandle MutableHandleString; +typedef MutableHandle MutableHandleId; +typedef MutableHandle MutableHandleObject; +typedef MutableHandle MutableHandleScript; +typedef MutableHandle MutableHandleString; typedef MutableHandle MutableHandleSymbol; -typedef MutableHandle MutableHandleValue; +typedef MutableHandle MutableHandleValue; -typedef Rooted RootedObject; -typedef Rooted RootedFunction; -typedef Rooted RootedScript; -typedef Rooted RootedString; -typedef Rooted RootedSymbol; -typedef Rooted RootedId; -typedef Rooted RootedValue; +typedef Rooted RootedObject; +typedef Rooted RootedFunction; +typedef Rooted RootedScript; +typedef Rooted RootedString; +typedef Rooted RootedSymbol; +typedef Rooted RootedId; +typedef Rooted RootedValue; typedef PersistentRooted PersistentRootedFunction; -typedef PersistentRooted PersistentRootedId; -typedef PersistentRooted PersistentRootedObject; -typedef PersistentRooted PersistentRootedScript; -typedef PersistentRooted PersistentRootedString; +typedef PersistentRooted PersistentRootedId; +typedef PersistentRooted PersistentRootedObject; +typedef PersistentRooted PersistentRootedScript; +typedef PersistentRooted PersistentRootedString; typedef PersistentRooted PersistentRootedSymbol; -typedef PersistentRooted PersistentRootedValue; +typedef PersistentRooted PersistentRootedValue; -} // namespace JS +} // namespace JS #endif /* js_TypeDecls_h */ 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 @@ -10,6 +10,7 @@ #include "mozilla/Alignment.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" +#include "mozilla/HashFunctions.h" #include "mozilla/Maybe.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Move.h" @@ -162,8 +163,6 @@ // structure of the snapshot file, the analyses should be prepared for ubi::Node // graphs constructed from snapshots to be even more bizarre. -class JSAtom; - namespace JS { namespace ubi { @@ -171,8 +170,8 @@ class EdgeRange; class StackFrame; -} // namespace ubi -} // namespace JS +} // namespace ubi +} // namespace JS namespace JS { namespace ubi { @@ -186,118 +185,119 @@ template using Vector = mozilla::Vector; -/*** ubi::StackFrame ******************************************************************************/ +/*** ubi::StackFrame **********************************************************/ // Concrete JS::ubi::StackFrame instances backed by a live SavedFrame object // store their strings as JSAtom*, while deserialized stack frames from offline // 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 JS_PUBLIC_API(AtomOrTwoByteChars) : public Variant { - using Base = Variant; - - public: - template - MOZ_IMPLICIT AtomOrTwoByteChars(T&& rhs) : Base(Forward(rhs)) { } - - template - AtomOrTwoByteChars& operator=(T&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move disallowed"); - this->~AtomOrTwoByteChars(); - new (this) AtomOrTwoByteChars(Forward(rhs)); - return *this; - } - - // Return the length of the given AtomOrTwoByteChars string. - size_t length(); - - // Copy the given AtomOrTwoByteChars string into the destination buffer, - // inflating if necessary. Does NOT null terminate. Returns the number of - // characters written to destination. - size_t copyToBuffer(RangedPtr destination, size_t length); +class JS_PUBLIC_API AtomOrTwoByteChars + : public Variant { + using Base = Variant; + + public: + template + MOZ_IMPLICIT AtomOrTwoByteChars(T&& rhs) : Base(Forward(rhs)) {} + + template + AtomOrTwoByteChars& operator=(T&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move disallowed"); + this->~AtomOrTwoByteChars(); + new (this) AtomOrTwoByteChars(Forward(rhs)); + return *this; + } + + // Return the length of the given AtomOrTwoByteChars string. + size_t length(); + + // Copy the given AtomOrTwoByteChars string into the destination buffer, + // inflating if necessary. Does NOT null terminate. Returns the number of + // characters written to destination. + size_t copyToBuffer(RangedPtr destination, size_t length); }; // The base class implemented by each ConcreteStackFrame type. Subclasses // must not add data members to this class. class BaseStackFrame { - friend class StackFrame; + friend class StackFrame; - BaseStackFrame(const StackFrame&) = delete; - BaseStackFrame& operator=(const StackFrame&) = delete; + BaseStackFrame(const StackFrame&) = delete; + BaseStackFrame& operator=(const StackFrame&) = delete; - protected: - void* ptr; - explicit BaseStackFrame(void* ptr) : ptr(ptr) { } - - public: - // This is a value type that should not have a virtual destructor. Don't add - // destructors in subclasses! - - // Get a unique identifier for this StackFrame. The identifier is not valid - // across garbage collections. - virtual uint64_t identifier() const { return uint64_t(uintptr_t(ptr)); } - - // Get this frame's parent frame. - virtual StackFrame parent() const = 0; - - // Get this frame's line number. - virtual uint32_t line() const = 0; - - // Get this frame's column number. - virtual uint32_t column() const = 0; - - // Get this frame's source name. Never null. - virtual AtomOrTwoByteChars source() const = 0; - - // Return this frame's function name if named, otherwise the inferred - // display name. Can be null. - virtual AtomOrTwoByteChars functionDisplayName() const = 0; - - // Returns true if this frame's function is system JavaScript running with - // trusted principals, false otherwise. - virtual bool isSystem() const = 0; - - // Return true if this frame's function is a self-hosted JavaScript builtin, - // false otherwise. - 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 - // cx's current compartment. - // - // Note that the process of - // - // SavedFrame - // | - // V - // JS::ubi::StackFrame - // | - // V - // offline heap snapshot - // | - // V - // JS::ubi::StackFrame - // | - // V - // SavedFrame - // - // is lossy because we cannot serialize and deserialize the SavedFrame's - // principals in the offline heap snapshot, so JS::ubi::StackFrame - // 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 MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx, - MutableHandleObject outSavedFrameStack) - const = 0; + protected: + void* ptr; + explicit BaseStackFrame(void* ptr) : ptr(ptr) {} + + public: + // This is a value type that should not have a virtual destructor. Don't add + // destructors in subclasses! + + // Get a unique identifier for this StackFrame. The identifier is not valid + // across garbage collections. + virtual uint64_t identifier() const { return uint64_t(uintptr_t(ptr)); } + + // Get this frame's parent frame. + virtual StackFrame parent() const = 0; + + // Get this frame's line number. + virtual uint32_t line() const = 0; + + // Get this frame's column number. + virtual uint32_t column() const = 0; + + // Get this frame's source name. Never null. + virtual AtomOrTwoByteChars source() const = 0; + + // Return this frame's function name if named, otherwise the inferred + // display name. Can be null. + virtual AtomOrTwoByteChars functionDisplayName() const = 0; + + // Returns true if this frame's function is system JavaScript running with + // trusted principals, false otherwise. + virtual bool isSystem() const = 0; + + // Return true if this frame's function is a self-hosted JavaScript builtin, + // false otherwise. + 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 + // cx's current compartment. + // + // Note that the process of + // + // SavedFrame + // | + // V + // JS::ubi::StackFrame + // | + // V + // offline heap snapshot + // | + // V + // JS::ubi::StackFrame + // | + // V + // SavedFrame + // + // is lossy because we cannot serialize and deserialize the SavedFrame's + // principals in the offline heap snapshot, so JS::ubi::StackFrame + // 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 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; + // Trace the concrete implementation of JS::ubi::StackFrame. + virtual void trace(JSTracer* trc) = 0; }; // A traits template with a specialization for each backing type that implements // the ubi::BaseStackFrame interface. Each specialization must be the a subclass // of ubi::BaseStackFrame. -template class ConcreteStackFrame; +template +class ConcreteStackFrame; // A JS::ubi::StackFrame represents a frame in a recorded stack. It can be // backed either by a live SavedFrame object or by a structure deserialized from @@ -313,166 +313,175 @@ // is an offline heap snapshot, the JS::ubi::StackFrame is valid as long as the // offline heap snapshot is alive. class StackFrame { - // Storage in which we allocate BaseStackFrame subclasses. - mozilla::AlignedStorage2 storage; + // Storage in which we allocate BaseStackFrame subclasses. + mozilla::AlignedStorage2 storage; - BaseStackFrame* base() { return storage.addr(); } - const BaseStackFrame* base() const { return storage.addr(); } + BaseStackFrame* base() { return storage.addr(); } + const BaseStackFrame* base() const { return storage.addr(); } - template - void construct(T* ptr) { - static_assert(mozilla::IsBaseOf>::value, - "ConcreteStackFrame must inherit from BaseStackFrame"); - static_assert(sizeof(ConcreteStackFrame) == sizeof(*base()), - "ubi::ConcreteStackFrame specializations must be the same size as " - "ubi::BaseStackFrame"); - ConcreteStackFrame::construct(base(), ptr); + template + void construct(T* ptr) { + static_assert( + mozilla::IsBaseOf>::value, + "ConcreteStackFrame must inherit from BaseStackFrame"); + static_assert( + sizeof(ConcreteStackFrame) == sizeof(*base()), + "ubi::ConcreteStackFrame specializations must be the same size as " + "ubi::BaseStackFrame"); + ConcreteStackFrame::construct(base(), ptr); + } + struct ConstructFunctor; + + public: + StackFrame() { construct(nullptr); } + + template + MOZ_IMPLICIT StackFrame(T* ptr) { + construct(ptr); + } + + template + StackFrame& operator=(T* ptr) { + construct(ptr); + return *this; + } + + // Constructors accepting SpiderMonkey's generic-pointer-ish types. + + template + explicit StackFrame(const JS::Handle& handle) { + construct(handle.get()); + } + + template + StackFrame& operator=(const JS::Handle& handle) { + construct(handle.get()); + return *this; + } + + template + explicit StackFrame(const JS::Rooted& root) { + construct(root.get()); + } + + template + StackFrame& operator=(const JS::Rooted& root) { + construct(root.get()); + return *this; + } + + // Because StackFrame is just a vtable pointer and an instance pointer, we + // can memcpy everything around instead of making concrete classes define + // virtual constructors. See the comment above Node's copy constructor for + // more details; that comment applies here as well. + StackFrame(const StackFrame& rhs) { + memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); + } + + StackFrame& operator=(const StackFrame& rhs) { + memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); + return *this; + } + + bool operator==(const StackFrame& rhs) const { + return base()->ptr == rhs.base()->ptr; + } + bool operator!=(const StackFrame& rhs) const { return !(*this == rhs); } + + explicit operator bool() const { return base()->ptr != nullptr; } + + // Copy this StackFrame's source name into the given |destination| + // buffer. Copy no more than |length| characters. The result is *not* null + // terminated. Returns how many characters were written into the buffer. + size_t source(RangedPtr destination, size_t length) const; + + // Copy this StackFrame's function display name into the given |destination| + // buffer. Copy no more than |length| characters. The result is *not* null + // terminated. Returns how many characters were written into the buffer. + size_t functionDisplayName(RangedPtr destination, + size_t length) const; + + // Get the size of the respective strings. 0 is returned for null strings. + size_t sourceLength(); + size_t functionDisplayNameLength(); + + // Methods that forward to virtual calls through BaseStackFrame. + + void trace(JSTracer* trc) { base()->trace(trc); } + uint64_t identifier() const { + auto id = base()->identifier(); + MOZ_ASSERT(JS::Value::isNumberRepresentable(id)); + return id; + } + uint32_t line() const { return base()->line(); } + uint32_t column() const { return base()->column(); } + AtomOrTwoByteChars source() const { return base()->source(); } + AtomOrTwoByteChars functionDisplayName() const { + return base()->functionDisplayName(); + } + StackFrame parent() const { return base()->parent(); } + bool isSystem() const { return base()->isSystem(); } + bool isSelfHosted(JSContext* cx) const { return base()->isSelfHosted(cx); } + MOZ_MUST_USE bool constructSavedFrameStack( + JSContext* cx, MutableHandleObject outSavedFrameStack) const { + return base()->constructSavedFrameStack(cx, outSavedFrameStack); + } + + struct HashPolicy { + using Lookup = JS::ubi::StackFrame; + + static js::HashNumber hash(const Lookup& lookup) { + return mozilla::HashGeneric(lookup.identifier()); } - struct ConstructFunctor; - - public: - StackFrame() { construct(nullptr); } - - template - MOZ_IMPLICIT StackFrame(T* ptr) { - construct(ptr); - } - - template - StackFrame& operator=(T* ptr) { - construct(ptr); - return *this; - } - - // Constructors accepting SpiderMonkey's generic-pointer-ish types. - template - explicit StackFrame(const JS::Handle& handle) { - construct(handle.get()); + static bool match(const StackFrame& key, const Lookup& lookup) { + return key == lookup; } - template - StackFrame& operator=(const JS::Handle& handle) { - construct(handle.get()); - return *this; - } - - template - explicit StackFrame(const JS::Rooted& root) { - construct(root.get()); - } - - template - StackFrame& operator=(const JS::Rooted& root) { - construct(root.get()); - return *this; - } - - // Because StackFrame is just a vtable pointer and an instance pointer, we - // can memcpy everything around instead of making concrete classes define - // virtual constructors. See the comment above Node's copy constructor for - // more details; that comment applies here as well. - StackFrame(const StackFrame& rhs) { - memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); - } - - StackFrame& operator=(const StackFrame& rhs) { - memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); - return *this; - } - - bool operator==(const StackFrame& rhs) const { return base()->ptr == rhs.base()->ptr; } - bool operator!=(const StackFrame& rhs) const { return !(*this == rhs); } - - explicit operator bool() const { - return base()->ptr != nullptr; - } - - // Copy this StackFrame's source name into the given |destination| - // buffer. Copy no more than |length| characters. The result is *not* null - // terminated. Returns how many characters were written into the buffer. - size_t source(RangedPtr destination, size_t length) const; - - // Copy this StackFrame's function display name into the given |destination| - // buffer. Copy no more than |length| characters. The result is *not* null - // terminated. Returns how many characters were written into the buffer. - size_t functionDisplayName(RangedPtr destination, size_t length) const; - - // Get the size of the respective strings. 0 is returned for null strings. - size_t sourceLength(); - size_t functionDisplayNameLength(); - - // Methods that forward to virtual calls through BaseStackFrame. - - void trace(JSTracer* trc) { base()->trace(trc); } - uint64_t identifier() const { - auto id = base()->identifier(); - MOZ_ASSERT(JS::Value::isNumberRepresentable(id)); - return id; - } - uint32_t line() const { return base()->line(); } - uint32_t column() const { return base()->column(); } - AtomOrTwoByteChars source() const { return base()->source(); } - AtomOrTwoByteChars functionDisplayName() const { return base()->functionDisplayName(); } - StackFrame parent() const { return base()->parent(); } - bool isSystem() const { return base()->isSystem(); } - bool isSelfHosted(JSContext* cx) const { return base()->isSelfHosted(cx); } - MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx, - MutableHandleObject outSavedFrameStack) const { - return base()->constructSavedFrameStack(cx, outSavedFrameStack); - } - - struct HashPolicy { - using Lookup = JS::ubi::StackFrame; - - static js::HashNumber hash(const Lookup& lookup) { - return lookup.identifier(); - } - - static bool match(const StackFrame& key, const Lookup& lookup) { - return key == lookup; - } - - static void rekey(StackFrame& k, const StackFrame& newKey) { - k = newKey; - } - }; + static void rekey(StackFrame& k, const StackFrame& newKey) { k = newKey; } + }; }; // The ubi::StackFrame null pointer. Any attempt to operate on a null // ubi::StackFrame crashes. -template<> +template <> class ConcreteStackFrame : public BaseStackFrame { - explicit ConcreteStackFrame(void* ptr) : BaseStackFrame(ptr) { } + explicit ConcreteStackFrame(void* ptr) : BaseStackFrame(ptr) {} - public: - static void construct(void* storage, void*) { new (storage) ConcreteStackFrame(nullptr); } - - uint64_t identifier() const override { return 0; } - void trace(JSTracer* trc) override { } - MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx, MutableHandleObject out) - const override - { - out.set(nullptr); - return true; - } - - uint32_t line() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } - uint32_t column() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } - AtomOrTwoByteChars source() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } - 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(JSContext* cx) const override { MOZ_CRASH("null JS::ubi::StackFrame"); } + public: + static void construct(void* storage, void*) { + new (storage) ConcreteStackFrame(nullptr); + } + + uint64_t identifier() const override { return 0; } + void trace(JSTracer* trc) override {} + MOZ_MUST_USE bool constructSavedFrameStack( + JSContext* cx, MutableHandleObject out) const override { + out.set(nullptr); + return true; + } + + uint32_t line() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } + uint32_t column() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } + AtomOrTwoByteChars source() const override { + MOZ_CRASH("null JS::ubi::StackFrame"); + } + 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(JSContext* cx) const override { + MOZ_CRASH("null JS::ubi::StackFrame"); + } }; -MOZ_MUST_USE JS_PUBLIC_API(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 ************************************************************************************/ +/*** ubi::Node + * ************************************************************************************/ // A concrete node specialization can claim its referent is a member of a // particular "coarse type" which is less specific than the actual @@ -486,165 +495,160 @@ // be reused for new variants. Doing so will cause inspecting ubi::Nodes backed // by an offline heap snapshot from an older SpiderMonkey/Firefox version to // break. Consider this enum append only. -enum class CoarseType: uint32_t { - Other = 0, - Object = 1, - Script = 2, - String = 3, +enum class CoarseType : uint32_t { + Other = 0, + Object = 1, + Script = 2, + String = 3, - FIRST = Other, - LAST = String + FIRST = Other, + LAST = String }; -inline uint32_t -CoarseTypeToUint32(CoarseType type) -{ - return static_cast(type); +inline uint32_t CoarseTypeToUint32(CoarseType type) { + return static_cast(type); } -inline bool -Uint32IsValidCoarseType(uint32_t n) -{ - auto first = static_cast(CoarseType::FIRST); - auto last = static_cast(CoarseType::LAST); - MOZ_ASSERT(first < last); - return first <= n && n <= last; +inline bool Uint32IsValidCoarseType(uint32_t n) { + auto first = static_cast(CoarseType::FIRST); + auto last = static_cast(CoarseType::LAST); + MOZ_ASSERT(first < last); + return first <= n && n <= last; } -inline CoarseType -Uint32ToCoarseType(uint32_t n) -{ - MOZ_ASSERT(Uint32IsValidCoarseType(n)); - return static_cast(n); +inline CoarseType Uint32ToCoarseType(uint32_t n) { + MOZ_ASSERT(Uint32IsValidCoarseType(n)); + return static_cast(n); } // The base class implemented by each ubi::Node referent type. Subclasses must // not add data members to this class. -class JS_PUBLIC_API(Base) { - friend class Node; - - // For performance's sake, we'd prefer to avoid a virtual destructor; and - // an empty constructor seems consistent with the 'lightweight value type' - // visible behavior we're trying to achieve. But if the destructor isn't - // virtual, and a subclass overrides it, the subclass's destructor will be - // ignored. Is there a way to make the compiler catch that error? - - protected: - // Space for the actual pointer. Concrete subclasses should define a - // properly typed 'get' member function to access this. - void* ptr; - - explicit Base(void* ptr) : ptr(ptr) { } - - public: - bool operator==(const Base& rhs) const { - // Some compilers will indeed place objects of different types at - // the same address, so technically, we should include the vtable - // in this comparison. But it seems unlikely to cause problems in - // practice. - return ptr == rhs.ptr; - } - bool operator!=(const Base& rhs) const { return !(*this == rhs); } - - // An identifier for this node, guaranteed to be stable and unique for as - // long as this ubi::Node's referent is alive and at the same address. - // - // This is probably suitable for use in serializations, as it is an integral - // type. It may also help save memory when constructing HashSets of - // ubi::Nodes: since a uint64_t will always be smaller-or-equal-to the size - // of a ubi::Node, a HashSet may use less space per element - // than a HashSet. - // - // (Note that 'unique' only means 'up to equality on ubi::Node'; see the - // caveats about multiple objects allocated at the same address for - // 'ubi::Node::operator=='.) - using Id = uint64_t; - virtual Id identifier() const { return Id(uintptr_t(ptr)); } - - // Returns true if this node is pointing to something on the live heap, as - // opposed to something from a deserialized core dump. Returns false, - // otherwise. - virtual bool isLive() const { return true; }; - - // Return the coarse-grained type-of-thing that this node represents. - 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 u"strings" for this.) - // - // This must always return Concrete::concreteTypeName; we use that - // pointer as a tag for this particular referent type. - virtual const char16_t* typeName() const = 0; - - // Return the size of this node, in bytes. Include any structures that this - // 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; } - - // Return an EdgeRange that initially contains all the referent's outgoing - // edges. The caller takes ownership of the EdgeRange. - // - // If wantNames is true, compute names for edges. Doing so can be expensive - // in time and memory. - 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. - virtual JS::Zone* zone() const { return nullptr; } - - // Return the compartment for this node. Some ubi::Node referents are not - // associated with JSCompartments, such as JSStrings (which are associated - // with Zones). When the referent is not associated with a compartment, - // nullptr is returned. - virtual JSCompartment* compartment() const { return nullptr; } - - // Return whether this node's referent's allocation stack was captured. - virtual bool hasAllocationStack() const { return false; } - - // Get the stack recorded at the time this node's referent was - // allocated. This must only be called when hasAllocationStack() is true. - virtual StackFrame allocationStack() const { - MOZ_CRASH("Concrete classes that have an allocation stack must override both " - "hasAllocationStack and allocationStack."); - } - - // Methods for JSObject Referents - // - // These methods are only semantically valid if the referent is either a - // JSObject in the live heap, or represents a previously existing JSObject - // from some deserialized heap snapshot. - - // Return the object's [[Class]]'s name. - virtual const char* jsObjectClassName() const { return nullptr; } - - // If this object was constructed with `new` and we have the data available, - // place the contructor function's display name in the out parameter. - // 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 MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) - const - { - outName.reset(nullptr); - return true; - } - - // Methods for CoarseType::Script referents +class JS_PUBLIC_API Base { + friend class Node; - // Return the script's source's filename if available. If unavailable, - // return nullptr. - virtual const char* scriptFilename() const { return nullptr; } - - private: - Base(const Base& rhs) = delete; - Base& operator=(const Base& rhs) = delete; + // For performance's sake, we'd prefer to avoid a virtual destructor; and + // an empty constructor seems consistent with the 'lightweight value type' + // visible behavior we're trying to achieve. But if the destructor isn't + // virtual, and a subclass overrides it, the subclass's destructor will be + // ignored. Is there a way to make the compiler catch that error? + + protected: + // Space for the actual pointer. Concrete subclasses should define a + // properly typed 'get' member function to access this. + void* ptr; + + explicit Base(void* ptr) : ptr(ptr) {} + + public: + bool operator==(const Base& rhs) const { + // Some compilers will indeed place objects of different types at + // the same address, so technically, we should include the vtable + // in this comparison. But it seems unlikely to cause problems in + // practice. + return ptr == rhs.ptr; + } + bool operator!=(const Base& rhs) const { return !(*this == rhs); } + + // An identifier for this node, guaranteed to be stable and unique for as + // long as this ubi::Node's referent is alive and at the same address. + // + // This is probably suitable for use in serializations, as it is an integral + // type. It may also help save memory when constructing HashSets of + // ubi::Nodes: since a uint64_t will always be smaller-or-equal-to the size + // of a ubi::Node, a HashSet may use less space per element + // than a HashSet. + // + // (Note that 'unique' only means 'up to equality on ubi::Node'; see the + // caveats about multiple objects allocated at the same address for + // 'ubi::Node::operator=='.) + using Id = uint64_t; + virtual Id identifier() const { return Id(uintptr_t(ptr)); } + + // Returns true if this node is pointing to something on the live heap, as + // opposed to something from a deserialized core dump. Returns false, + // otherwise. + virtual bool isLive() const { return true; }; + + // Return the coarse-grained type-of-thing that this node represents. + 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 u"strings" for this.) + // + // This must always return Concrete::concreteTypeName; we use that + // pointer as a tag for this particular referent type. + virtual const char16_t* typeName() const = 0; + + // Return the size of this node, in bytes. Include any structures that this + // 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; } + + // Return an EdgeRange that initially contains all the referent's outgoing + // edges. The caller takes ownership of the EdgeRange. + // + // If wantNames is true, compute names for edges. Doing so can be expensive + // in time and memory. + 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. + virtual JS::Zone* zone() const { return nullptr; } + + // Return the compartment for this node. Some ubi::Node referents are not + // associated with JSCompartments, such as JSStrings (which are associated + // with Zones). When the referent is not associated with a compartment, + // nullptr is returned. + virtual JSCompartment* compartment() const { return nullptr; } + + // Return whether this node's referent's allocation stack was captured. + virtual bool hasAllocationStack() const { return false; } + + // Get the stack recorded at the time this node's referent was + // allocated. This must only be called when hasAllocationStack() is true. + virtual StackFrame allocationStack() const { + MOZ_CRASH( + "Concrete classes that have an allocation stack must override both " + "hasAllocationStack and allocationStack."); + } + + // Methods for JSObject Referents + // + // These methods are only semantically valid if the referent is either a + // JSObject in the live heap, or represents a previously existing JSObject + // from some deserialized heap snapshot. + + // Return the object's [[Class]]'s name. + virtual const char* jsObjectClassName() const { return nullptr; } + + // If this object was constructed with `new` and we have the data available, + // place the contructor function's display name in the out parameter. + // 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 MOZ_MUST_USE bool jsObjectConstructorName( + JSContext* cx, UniqueTwoByteChars& outName) const { + outName.reset(nullptr); + return true; + } + + // Methods for CoarseType::Script referents + + // Return the script's source's filename if available. If unavailable, + // return nullptr. + virtual const char* scriptFilename() const { return nullptr; } + + private: + Base(const Base& rhs) = delete; + Base& operator=(const Base& rhs) = delete; }; // A traits template with a specialization for each referent type that @@ -668,211 +672,209 @@ // // So we delegate the actual construction to this specialization, which // // knows Referent's details. // static void construct(void* storage, Referent* referent); -template +template 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. class Node { - // Storage in which we allocate Base subclasses. - mozilla::AlignedStorage2 storage; - Base* base() { return storage.addr(); } - const Base* base() const { return storage.addr(); } - - template - 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; - - public: - Node() { construct(nullptr); } - - template - MOZ_IMPLICIT Node(T* ptr) { - construct(ptr); - } - template - Node& operator=(T* ptr) { - construct(ptr); - return *this; - } - - // We can construct and assign from rooted forms of pointers. - template - MOZ_IMPLICIT Node(const Rooted& root) { - construct(root.get()); - } - template - Node& operator=(const Rooted& root) { - construct(root.get()); - return *this; - } - - // Constructors accepting SpiderMonkey's other generic-pointer-ish types. - // Note that we *do* want an implicit constructor here: JS::Value and - // JS::ubi::Node are both essentially tagged references to other sorts of - // objects, so letting conversions happen automatically is appropriate. - MOZ_IMPLICIT Node(JS::HandleValue value); - explicit Node(const JS::GCCellPtr& thing); - - // copy construction and copy assignment just use memcpy, since we know - // instances contain nothing but a vtable pointer and a data pointer. - // - // To be completely correct, concrete classes could provide a virtual - // 'construct' member function, which we could invoke on rhs to construct an - // instance in our storage. But this is good enough; there's no need to jump - // through vtables for copying and assignment that are just going to move - // two words around. The compiler knows how to optimize memcpy. - Node(const Node& rhs) { - memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); - } - - Node& operator=(const Node& rhs) { - memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); - return *this; - } - - bool operator==(const Node& rhs) const { return *base() == *rhs.base(); } - bool operator!=(const Node& rhs) const { return *base() != *rhs.base(); } - - explicit operator bool() const { - return base()->ptr != nullptr; - } - - bool isLive() const { return base()->isLive(); } - - // Get the canonical type name for the given type T. - template - static const char16_t* canonicalTypeName() { return Concrete::concreteTypeName; } - - template - bool is() const { - return base()->typeName() == canonicalTypeName(); - } - - template - T* as() const { - MOZ_ASSERT(isLive()); - MOZ_ASSERT(is()); - return static_cast(base()->ptr); - } - - template - T* asOrNull() const { - MOZ_ASSERT(isLive()); - return is() ? static_cast(base()->ptr) : nullptr; - } - - // If this node refers to something that can be represented as a JavaScript - // value that is safe to expose to JavaScript code, return that value. - // Otherwise return UndefinedValue(). JSStrings, JS::Symbols, and some (but - // not all!) JSObjects can be exposed. - JS::Value exposeToJS() const; - - CoarseType coarseType() const { return base()->coarseType(); } - const char16_t* typeName() const { return base()->typeName(); } - JS::Zone* zone() const { return base()->zone(); } - JSCompartment* compartment() const { return base()->compartment(); } - const char* jsObjectClassName() const { return base()->jsObjectClassName(); } - MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) const { - return base()->jsObjectConstructorName(cx, outName); - } - - const char* scriptFilename() const { return base()->scriptFilename(); } - - using Size = Base::Size; - Size size(mozilla::MallocSizeOf mallocSizeof) const { - auto size = base()->size(mallocSizeof); - MOZ_ASSERT(size > 0, - "C++ does not have zero-sized types! Choose 1 if you just need a " - "conservative default."); - return size; - } - - js::UniquePtr edges(JSContext* cx, bool wantNames = true) const { - return base()->edges(cx, wantNames); - } - - bool hasAllocationStack() const { return base()->hasAllocationStack(); } - StackFrame allocationStack() const { - return base()->allocationStack(); - } - - using Id = Base::Id; - Id identifier() const { - auto id = base()->identifier(); - MOZ_ASSERT(JS::Value::isNumberRepresentable(id)); - return id; - } - - // A hash policy for ubi::Nodes. - // This simply uses the stock PointerHasher on the ubi::Node's pointer. - // We specialize DefaultHasher below to make this the default. - class HashPolicy { - typedef js::PointerHasher::value> PtrHash; - - public: - typedef Node Lookup; - - static js::HashNumber hash(const Lookup& l) { return PtrHash::hash(l.base()->ptr); } - static bool match(const Node& k, const Lookup& l) { return k == l; } - static void rekey(Node& k, const Node& newKey) { k = newKey; } - }; + // Storage in which we allocate Base subclasses. + mozilla::AlignedStorage2 storage; + Base* base() { return storage.addr(); } + const Base* base() const { return storage.addr(); } + + template + 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; + + public: + Node() { construct(nullptr); } + + template + MOZ_IMPLICIT Node(T* ptr) { + construct(ptr); + } + template + Node& operator=(T* ptr) { + construct(ptr); + return *this; + } + + // We can construct and assign from rooted forms of pointers. + template + MOZ_IMPLICIT Node(const Rooted& root) { + construct(root.get()); + } + template + Node& operator=(const Rooted& root) { + construct(root.get()); + return *this; + } + + // Constructors accepting SpiderMonkey's other generic-pointer-ish types. + // Note that we *do* want an implicit constructor here: JS::Value and + // JS::ubi::Node are both essentially tagged references to other sorts of + // objects, so letting conversions happen automatically is appropriate. + MOZ_IMPLICIT Node(JS::HandleValue value); + explicit Node(const JS::GCCellPtr& thing); + + // copy construction and copy assignment just use memcpy, since we know + // instances contain nothing but a vtable pointer and a data pointer. + // + // To be completely correct, concrete classes could provide a virtual + // 'construct' member function, which we could invoke on rhs to construct an + // instance in our storage. But this is good enough; there's no need to jump + // through vtables for copying and assignment that are just going to move + // two words around. The compiler knows how to optimize memcpy. + Node(const Node& rhs) { + memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); + } + + Node& operator=(const Node& rhs) { + memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); + return *this; + } + + bool operator==(const Node& rhs) const { return *base() == *rhs.base(); } + bool operator!=(const Node& rhs) const { return *base() != *rhs.base(); } + + explicit operator bool() const { return base()->ptr != nullptr; } + + bool isLive() const { return base()->isLive(); } + + // Get the canonical type name for the given type T. + template + static const char16_t* canonicalTypeName() { + return Concrete::concreteTypeName; + } + + template + bool is() const { + return base()->typeName() == canonicalTypeName(); + } + + template + T* as() const { + MOZ_ASSERT(isLive()); + MOZ_ASSERT(is()); + return static_cast(base()->ptr); + } + + template + T* asOrNull() const { + MOZ_ASSERT(isLive()); + return is() ? static_cast(base()->ptr) : nullptr; + } + + // If this node refers to something that can be represented as a JavaScript + // value that is safe to expose to JavaScript code, return that value. + // Otherwise return UndefinedValue(). JSStrings, JS::Symbols, and some (but + // not all!) JSObjects can be exposed. + JS::Value exposeToJS() const; + + CoarseType coarseType() const { return base()->coarseType(); } + const char16_t* typeName() const { return base()->typeName(); } + JS::Zone* zone() const { return base()->zone(); } + JSCompartment* compartment() const { return base()->compartment(); } + const char* jsObjectClassName() const { return base()->jsObjectClassName(); } + MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, + UniqueTwoByteChars& outName) const { + return base()->jsObjectConstructorName(cx, outName); + } + + const char* scriptFilename() const { return base()->scriptFilename(); } + + using Size = Base::Size; + Size size(mozilla::MallocSizeOf mallocSizeof) const { + auto size = base()->size(mallocSizeof); + MOZ_ASSERT( + size > 0, + "C++ does not have zero-sized types! Choose 1 if you just need a " + "conservative default."); + return size; + } + + js::UniquePtr edges(JSContext* cx, bool wantNames = true) const { + return base()->edges(cx, wantNames); + } + + bool hasAllocationStack() const { return base()->hasAllocationStack(); } + StackFrame allocationStack() const { return base()->allocationStack(); } + + using Id = Base::Id; + Id identifier() const { + auto id = base()->identifier(); + MOZ_ASSERT(JS::Value::isNumberRepresentable(id)); + return id; + } + + // A hash policy for ubi::Nodes. + // This simply uses the stock PointerHasher on the ubi::Node's pointer. + // We specialize DefaultHasher below to make this the default. + class HashPolicy { + typedef js::PointerHasher PtrHash; + + public: + typedef Node Lookup; + + static js::HashNumber hash(const Lookup& l) { + return PtrHash::hash(l.base()->ptr); + } + static bool match(const Node& k, const Lookup& l) { return k == l; } + static void rekey(Node& k, const Node& newKey) { k = newKey; } + }; }; -using NodeSet = js::HashSet, js::SystemAllocPolicy>; +using NodeSet = + js::HashSet, js::SystemAllocPolicy>; using NodeSetPtr = mozilla::UniquePtr>; -/*** Edge and EdgeRange ***************************************************************************/ +/*** Edge and EdgeRange *******************************************************/ using EdgeName = UniqueTwoByteChars; // An outgoing edge to a referent node. class Edge { - public: - Edge() : name(nullptr), referent() { } + public: + Edge() : name(nullptr), referent() {} - // Construct an initialized Edge, taking ownership of |name|. - Edge(char16_t* name, const Node& referent) - : name(name) - , referent(referent) - { } - - // Move construction and assignment. - Edge(Edge&& rhs) - : name(mozilla::Move(rhs.name)) - , referent(rhs.referent) - { } - - Edge& operator=(Edge&& rhs) { - MOZ_ASSERT(&rhs != this); - this->~Edge(); - new (this) Edge(mozilla::Move(rhs)); - return *this; - } + // Construct an initialized Edge, taking ownership of |name|. + Edge(char16_t* name, const Node& referent) : name(name), referent(referent) {} - Edge(const Edge&) = delete; - Edge& operator=(const Edge&) = delete; + // Move construction and assignment. + Edge(Edge&& rhs) : name(mozilla::Move(rhs.name)), referent(rhs.referent) {} - // This edge's name. This may be nullptr, if Node::edges was called with - // false as the wantNames parameter. - // - // The storage is owned by this Edge, and will be freed when this Edge is - // 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 - // to think about lifetimes carefully to ensure traversal stays cheap.) - EdgeName name; + Edge& operator=(Edge&& rhs) { + MOZ_ASSERT(&rhs != this); + this->~Edge(); + new (this) Edge(mozilla::Move(rhs)); + return *this; + } + + Edge(const Edge&) = delete; + Edge& operator=(const Edge&) = delete; + + // This edge's name. This may be nullptr, if Node::edges was called with + // false as the wantNames parameter. + // + // The storage is owned by this Edge, and will be freed when this Edge is + // 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 + // to think about lifetimes carefully to ensure traversal stays cheap.) + EdgeName name; - // This edge's referent. - Node referent; + // This edge's referent. + Node referent; }; // EdgeRange is an abstract base class for iterating over a node's outgoing @@ -884,34 +886,33 @@ // JS::TraceChildren to to get the outgoing edges, and then store them in an // array internal to the EdgeRange. class EdgeRange { - protected: - // The current front edge of this range, or nullptr if this range is empty. - Edge* front_; - - EdgeRange() : front_(nullptr) { } - - public: - virtual ~EdgeRange() { } - - // True if there are no more edges in this range. - bool empty() const { return !front_; } - - // The front edge of this range. This is owned by the EdgeRange, and is - // only guaranteed to live until the next call to popFront, or until - // the EdgeRange is destructed. - const Edge& front() const { return *front_; } - Edge& front() { return *front_; } - - // Remove the front edge from this range. This should only be called if - // !empty(). - virtual void popFront() = 0; - - private: - EdgeRange(const EdgeRange&) = delete; - EdgeRange& operator=(const EdgeRange&) = delete; + protected: + // The current front edge of this range, or nullptr if this range is empty. + Edge* front_; + + EdgeRange() : front_(nullptr) {} + + public: + virtual ~EdgeRange() {} + + // True if there are no more edges in this range. + bool empty() const { return !front_; } + + // The front edge of this range. This is owned by the EdgeRange, and is + // only guaranteed to live until the next call to popFront, or until + // the EdgeRange is destructed. + const Edge& front() const { return *front_; } + Edge& front() { return *front_; } + + // Remove the front edge from this range. This should only be called if + // !empty(). + virtual void popFront() = 0; + + private: + EdgeRange(const EdgeRange&) = delete; + EdgeRange& operator=(const EdgeRange&) = delete; }; - typedef mozilla::Vector EdgeVector; // An EdgeRange concrete class that holds a pre-existing vector of @@ -919,29 +920,24 @@ // EdgeVector; it is up to the PreComputedEdgeRange's consumer to manage // that lifetime. class PreComputedEdgeRange : public EdgeRange { - EdgeVector& edges; - size_t i; - - void settle() { - front_ = i < edges.length() ? &edges[i] : nullptr; - } + EdgeVector& edges; + size_t i; - public: - explicit PreComputedEdgeRange(EdgeVector& edges) - : edges(edges), - i(0) - { - settle(); - } + void settle() { front_ = i < edges.length() ? &edges[i] : nullptr; } - void popFront() override { - MOZ_ASSERT(!empty()); - i++; - settle(); - } + public: + explicit PreComputedEdgeRange(EdgeVector& edges) : edges(edges), i(0) { + settle(); + } + + void popFront() override { + MOZ_ASSERT(!empty()); + i++; + settle(); + } }; -/*** RootList *************************************************************************************/ +/*** RootList *****************************************************************/ // RootList is a class that can be pointed to by a |ubi::Node|, creating a // fictional root-of-roots which has edges to every GC root in the JS @@ -971,176 +967,190 @@ // // ... // } -class MOZ_STACK_CLASS JS_PUBLIC_API(RootList) { - Maybe& noGC; +class MOZ_STACK_CLASS JS_PUBLIC_API RootList { + Maybe& noGC; - public: - JSContext* cx; - EdgeVector edges; - bool wantNames; - - RootList(JSContext* cx, Maybe& noGC, bool wantNames = false); - - // Find all GC roots. - 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. - bool initialized() { return noGC.isSome(); } - - // 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. - MOZ_MUST_USE bool addRoot(Node node, const char16_t* edgeName = nullptr); + public: + JSContext* cx; + EdgeVector edges; + bool wantNames; + + RootList(JSContext* cx, Maybe& noGC, + bool wantNames = false); + + // Find all GC roots. + 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. + bool initialized() { return noGC.isSome(); } + + // 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. + MOZ_MUST_USE bool addRoot(Node node, const char16_t* edgeName = nullptr); }; +/*** Concrete classes for ubi::Node referent types ****************************/ -/*** Concrete classes for ubi::Node referent types ************************************************/ - -template<> -class JS_PUBLIC_API(Concrete) : public Base { - protected: - explicit Concrete(RootList* ptr) : Base(ptr) { } - RootList& get() const { return *static_cast(ptr); } +template <> +class JS_PUBLIC_API Concrete : public Base { + protected: + explicit Concrete(RootList* ptr) : Base(ptr) {} + RootList& get() const { return *static_cast(ptr); } + + public: + static void construct(void* storage, RootList* ptr) { + new (storage) Concrete(ptr); + } - public: - static void construct(void* storage, RootList* ptr) { new (storage) Concrete(ptr); } + js::UniquePtr edges(JSContext* cx, bool wantNames) const override; - js::UniquePtr edges(JSContext* cx, bool wantNames) const override; - - const char16_t* typeName() const override { return concreteTypeName; } - static const char16_t concreteTypeName[]; + 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 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); } +template +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); } }; // For JS::TraceChildren-based types that have a 'compartment' method. -template -class JS_PUBLIC_API(TracerConcreteWithCompartment) : public TracerConcrete { - typedef TracerConcrete TracerBase; - JSCompartment* compartment() const override; +template +class JS_PUBLIC_API TracerConcreteWithCompartment + : public TracerConcrete { + typedef TracerConcrete TracerBase; + JSCompartment* compartment() const override; - protected: - explicit TracerConcreteWithCompartment(Referent* ptr) : TracerBase(ptr) { } + protected: + explicit TracerConcreteWithCompartment(Referent* ptr) : TracerBase(ptr) {} }; // Define specializations for some commonly-used public JSAPI types. // These can use the generic templates above. -template<> -class JS_PUBLIC_API(Concrete) : TracerConcrete { - protected: - explicit Concrete(JS::Symbol* ptr) : TracerConcrete(ptr) { } - - public: - static void construct(void* storage, JS::Symbol* ptr) { - new (storage) Concrete(ptr); - } +template <> +class JS_PUBLIC_API Concrete : TracerConcrete { + protected: + explicit Concrete(JS::Symbol* ptr) : TracerConcrete(ptr) {} + + public: + static void construct(void* storage, JS::Symbol* ptr) { + new (storage) Concrete(ptr); + } - Size size(mozilla::MallocSizeOf mallocSizeOf) const override; + Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - const char16_t* typeName() const override { return concreteTypeName; } - static const char16_t concreteTypeName[]; + 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); } - - CoarseType coarseType() const final { return CoarseType::Script; } - Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - const char* scriptFilename() const final; +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); + } + + 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[]; + 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) { } - - public: - static void construct(void* storage, JSObject* ptr) { - new (storage) Concrete(ptr); - } +template <> +class JS_PUBLIC_API Concrete + : public TracerConcreteWithCompartment { + protected: + explicit Concrete(JSObject* ptr) : TracerConcreteWithCompartment(ptr) {} + + public: + static void construct(void* storage, JSObject* ptr) { + new (storage) Concrete(ptr); + } + + const char* jsObjectClassName() const override; + MOZ_MUST_USE bool jsObjectConstructorName( + JSContext* cx, UniqueTwoByteChars& outName) const override; + Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - const char* jsObjectClassName() const override; - MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) - const override; - Size size(mozilla::MallocSizeOf mallocSizeOf) const override; + bool hasAllocationStack() const override; + StackFrame allocationStack() const override; - bool hasAllocationStack() const override; - StackFrame allocationStack() const override; + CoarseType coarseType() const final { return CoarseType::Object; } - CoarseType coarseType() const final { return CoarseType::Object; } - - const char16_t* typeName() const override { return concreteTypeName; } - static const char16_t concreteTypeName[]; + 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); } +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; + Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - CoarseType coarseType() const final { return CoarseType::String; } + CoarseType coarseType() const final { return CoarseType::String; } - const char16_t* typeName() const override { return concreteTypeName; } - static const char16_t concreteTypeName[]; + 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 JS_PUBLIC_API(Concrete) : public Base { - const char16_t* typeName() const override; - Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - js::UniquePtr edges(JSContext* cx, bool wantNames) const override; - JS::Zone* zone() const override; - JSCompartment* compartment() const override; - CoarseType coarseType() const final; - - explicit Concrete(void* ptr) : Base(ptr) { } - - public: - static void construct(void* storage, void* ptr) { new (storage) Concrete(ptr); } +// The ubi::Node null pointer. Any attempt to operate on a null ubi::Node +// asserts. +template <> +class JS_PUBLIC_API Concrete : public Base { + const char16_t* typeName() const override; + Size size(mozilla::MallocSizeOf mallocSizeOf) const override; + js::UniquePtr edges(JSContext* cx, bool wantNames) const override; + JS::Zone* zone() const override; + JSCompartment* compartment() const override; + CoarseType coarseType() const final; + + explicit Concrete(void* ptr) : Base(ptr) {} + + public: + static void construct(void* storage, void* ptr) { + new (storage) Concrete(ptr); + } }; - -} // namespace ubi -} // namespace JS +} // namespace ubi +} // namespace JS namespace js { // Make ubi::Node::HashPolicy the default hash policy for ubi::Node. -template<> struct DefaultHasher : JS::ubi::Node::HashPolicy { }; -template<> struct DefaultHasher : JS::ubi::StackFrame::HashPolicy { }; +template <> +struct DefaultHasher : JS::ubi::Node::HashPolicy {}; +template <> +struct DefaultHasher : JS::ubi::StackFrame::HashPolicy {}; -} // namespace js +} // namespace js -#endif // js_UbiNode_h +#endif // js_UbiNode_h 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 @@ -43,8 +43,9 @@ // // The visitor function, called to report that we have traversed // |edge| from |origin|. This is called once for each edge we traverse. -// As this is a breadth-first search, any prior calls to the visitor function -// were for origin nodes not further from the start nodes than |origin|. +// As this is a breadth-first search, any prior calls to the visitor +// function were for origin nodes not further from the start nodes than +// |origin|. // // |traversal| is this traversal object, passed along for convenience. // @@ -74,171 +75,171 @@ // error occurs. A false return value terminates the traversal // immediately, and causes BreadthFirst::traverse to return // false. -template +template struct BreadthFirst { - - // Construct a breadth-first traversal object that reports the nodes it - // reaches to |handler|. The traversal asserts that no GC happens in its - // runtime during its lifetime. - // - // We do nothing with noGC, other than require it to exist, with a lifetime - // that encloses our own. - BreadthFirst(JSContext* cx, Handler& handler, const JS::AutoCheckCannotGC& noGC) - : wantNames(true), cx(cx), visited(), handler(handler), pending(), - traversalBegun(false), stopRequested(false), abandonRequested(false) - { } - - // Initialize this traversal object. Return false on OOM. - bool init() { return visited.init(); } - - // Add |node| as a starting point for the traversal. You may add - // as many starting points as you like. Return false on OOM. - bool addStart(Node node) { return pending.append(node); } - - // Add |node| as a starting point for the traversal (see addStart) and also - // add it to the |visited| set. Return false on OOM. - bool addStartVisited(Node node) { - typename NodeMap::AddPtr ptr = visited.lookupForAdd(node); - if (!ptr && !visited.add(ptr, node, typename Handler::NodeData())) + // Construct a breadth-first traversal object that reports the nodes it + // reaches to |handler|. The traversal asserts that no GC happens in its + // runtime during its lifetime. + // + // We do nothing with noGC, other than require it to exist, with a lifetime + // that encloses our own. + BreadthFirst(JSContext* cx, Handler& handler, const JS::AutoRequireNoGC& noGC) + : wantNames(true), + cx(cx), + visited(), + handler(handler), + pending(), + traversalBegun(false), + stopRequested(false), + abandonRequested(false) {} + + // Initialize this traversal object. Return false on OOM. + bool init() { return visited.init(); } + + // Add |node| as a starting point for the traversal. You may add + // as many starting points as you like. Return false on OOM. + bool addStart(Node node) { return pending.append(node); } + + // Add |node| as a starting point for the traversal (see addStart) and also + // add it to the |visited| set. Return false on OOM. + bool addStartVisited(Node node) { + typename NodeMap::AddPtr ptr = visited.lookupForAdd(node); + if (!ptr && !visited.add(ptr, node, typename Handler::NodeData())) + return false; + return addStart(node); + } + + // True if the handler wants us to compute edge names; doing so can be + // expensive in time and memory. True by default. + bool wantNames; + + // Traverse the graph in breadth-first order, starting at the given + // start nodes, applying |handler::operator()| for each edge traversed + // as described above. + // + // This should be called only once per instance of this class. + // + // Return false on OOM or error return from |handler::operator()|. + bool traverse() { + MOZ_ASSERT(!traversalBegun); + traversalBegun = true; + + // While there are pending nodes, visit them. + while (!pending.empty()) { + Node origin = pending.front(); + pending.popFront(); + + // Get a range containing all origin's outgoing edges. + auto range = origin.edges(cx, wantNames); + if (!range) return false; + + // Traverse each edge. + for (; !range->empty(); range->popFront()) { + MOZ_ASSERT(!stopRequested); + + Edge& edge = range->front(); + typename NodeMap::AddPtr a = visited.lookupForAdd(edge.referent); + bool first = !a; + + if (first) { + // This is the first time we've reached |edge.referent|. + // Mark it as visited. + if (!visited.add(a, edge.referent, typename Handler::NodeData())) return false; - return addStart(node); - } - - // True if the handler wants us to compute edge names; doing so can be - // expensive in time and memory. True by default. - bool wantNames; - - // Traverse the graph in breadth-first order, starting at the given - // start nodes, applying |handler::operator()| for each edge traversed - // as described above. - // - // This should be called only once per instance of this class. - // - // Return false on OOM or error return from |handler::operator()|. - bool traverse() - { - MOZ_ASSERT(!traversalBegun); - traversalBegun = true; - - // While there are pending nodes, visit them. - while (!pending.empty()) { - Node origin = pending.front(); - pending.popFront(); - - // Get a range containing all origin's outgoing edges. - auto range = origin.edges(cx, wantNames); - if (!range) - return false; - - // Traverse each edge. - for (; !range->empty(); range->popFront()) { - MOZ_ASSERT(!stopRequested); - - Edge& edge = range->front(); - typename NodeMap::AddPtr a = visited.lookupForAdd(edge.referent); - bool first = !a; - - if (first) { - // This is the first time we've reached |edge.referent|. - // Mark it as visited. - if (!visited.add(a, edge.referent, typename Handler::NodeData())) - return false; - } - - MOZ_ASSERT(a); - - // Report this edge to the visitor function. - if (!handler(*this, origin, edge, &a->value(), first)) - return false; - - if (stopRequested) - return true; - - // Arrange to traverse this edge's referent's outgoing edges - // later --- unless |handler| asked us not to. - if (abandonRequested) { - // Skip the enqueue; reset flag for future iterations. - abandonRequested = false; - } else if (first) { - if (!pending.append(edge.referent)) - return false; - } - } } - return true; - } + MOZ_ASSERT(a); - // Stop traversal, and return true from |traverse| without visiting any - // more nodes. Only |handler::operator()| should call this function; it - // may do so to stop the traversal early, without returning false and - // then making |traverse|'s caller disambiguate that result from a real - // error. - void stop() { stopRequested = true; } - - // Request that the current edge's referent's outgoing edges not be - // traversed. This must be called the first time that referent is reached. - // Other edges *to* that referent will still be traversed. - void abandonReferent() { abandonRequested = true; } - - // 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 - // |handler| can access it to see the traversal thus far. - using NodeMap = js::HashMap, - js::SystemAllocPolicy>; - NodeMap visited; - - private: - // Our handler object. - Handler& handler; - - // A queue template. Appending and popping the front are constant time. - // Wasted space is never more than some recent actual population plus the - // current population. - template - class Queue { - js::Vector head, tail; - size_t frontIndex; - public: - Queue() : head(), tail(), frontIndex(0) { } - bool empty() { return frontIndex >= head.length(); } - T& front() { - MOZ_ASSERT(!empty()); - return head[frontIndex]; - } - void popFront() { - MOZ_ASSERT(!empty()); - frontIndex++; - if (frontIndex >= head.length()) { - head.clearAndFree(); - head.swap(tail); - frontIndex = 0; - } - } - bool append(const T& elt) { - return frontIndex == 0 ? head.append(elt) : tail.append(elt); + // Report this edge to the visitor function. + if (!handler(*this, origin, edge, &a->value(), first)) return false; + + if (stopRequested) return true; + + // Arrange to traverse this edge's referent's outgoing edges + // later --- unless |handler| asked us not to. + if (abandonRequested) { + // Skip the enqueue; reset flag for future iterations. + abandonRequested = false; + } else if (first) { + if (!pending.append(edge.referent)) return false; } - }; + } + } + + return true; + } + + // Stop traversal, and return true from |traverse| without visiting any + // more nodes. Only |handler::operator()| should call this function; it + // may do so to stop the traversal early, without returning false and + // then making |traverse|'s caller disambiguate that result from a real + // error. + void stop() { stopRequested = true; } + + // Request that the current edge's referent's outgoing edges not be + // traversed. This must be called the first time that referent is reached. + // Other edges *to* that referent will still be traversed. + void abandonReferent() { abandonRequested = true; } + + // 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 + // |handler| can access it to see the traversal thus far. + using NodeMap = js::HashMap, js::SystemAllocPolicy>; + NodeMap visited; + + private: + // Our handler object. + Handler& handler; + + // A queue template. Appending and popping the front are constant time. + // Wasted space is never more than some recent actual population plus the + // current population. + template + class Queue { + js::Vector head, tail; + size_t frontIndex; + + public: + Queue() : head(), tail(), frontIndex(0) {} + bool empty() { return frontIndex >= head.length(); } + T& front() { + MOZ_ASSERT(!empty()); + return head[frontIndex]; + } + void popFront() { + MOZ_ASSERT(!empty()); + frontIndex++; + if (frontIndex >= head.length()) { + head.clearAndFree(); + head.swap(tail); + frontIndex = 0; + } + } + bool append(const T& elt) { + return frontIndex == 0 ? head.append(elt) : tail.append(elt); + } + }; - // A queue of nodes that we have reached, but whose outgoing edges we - // have not yet traversed. Nodes reachable in fewer edges are enqueued - // earlier. - Queue pending; + // A queue of nodes that we have reached, but whose outgoing edges we + // have not yet traversed. Nodes reachable in fewer edges are enqueued + // earlier. + Queue pending; - // True if our traverse function has been called. - bool traversalBegun; + // True if our traverse function has been called. + bool traversalBegun; - // True if we've been asked to stop the traversal. - bool stopRequested; + // True if we've been asked to stop the traversal. + bool stopRequested; - // True if we've been asked to abandon the current edge's referent. - bool abandonRequested; + // True if we've been asked to abandon the current edge's referent. + bool abandonRequested; }; -} // namespace ubi -} // namespace JS +} // namespace ubi +} // namespace JS -#endif // js_UbiNodeBreadthFirst_h +#endif // js_UbiNodeBreadthFirst_h 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 @@ -74,7 +74,6 @@ // visit them; build a JS object reporting the results; and destruct count // nodes. - namespace JS { namespace ubi { @@ -83,170 +82,166 @@ class CountBase; struct CountDeleter { - JS_PUBLIC_API(void) operator()(CountBase*); + JS_PUBLIC_API void operator()(CountBase*); }; using CountBasePtr = js::UniquePtr; // Abstract base class for CountType nodes. struct CountType { - explicit CountType() { } - virtual ~CountType() { } + explicit CountType() {} + virtual ~CountType() {} - // Destruct a count tree node that this type instance constructed. - virtual void destructCount(CountBase& count) = 0; + // Destruct a count tree node that this type instance constructed. + virtual void destructCount(CountBase& count) = 0; - // Return a fresh node for the count tree that categorizes nodes according - // to this type. Return a nullptr on OOM. - virtual CountBasePtr makeCount() = 0; - - // Trace |count| and all its children, for garbage collection. - virtual void traceCount(CountBase& count, JSTracer* trc) = 0; - - // Implement the 'count' method for counts returned by this CountType - // instance's 'newCount' method. - 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 MOZ_MUST_USE bool report(JSContext* cx, CountBase& count, - MutableHandleValue report) = 0; + // Return a fresh node for the count tree that categorizes nodes according + // to this type. Return a nullptr on OOM. + virtual CountBasePtr makeCount() = 0; + + // Trace |count| and all its children, for garbage collection. + virtual void traceCount(CountBase& count, JSTracer* trc) = 0; + + // Implement the 'count' method for counts returned by this CountType + // instance's 'newCount' method. + 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 MOZ_MUST_USE bool report(JSContext* cx, CountBase& count, + MutableHandleValue report) = 0; }; using CountTypePtr = js::UniquePtr; // An abstract base class for count tree nodes. class CountBase { - // In lieu of a vtable, each CountBase points to its type, which - // carries not only the implementations of the CountBase methods, but also - // additional parameters for the type's behavior, as specified in the - // breakdown argument passed to takeCensus. - CountType& type; - - protected: - ~CountBase() { } - - public: - explicit CountBase(CountType& type) - : type(type) - , total_(0) - , smallestNodeIdCounted_(SIZE_MAX) - { } - - // Categorize and count |node| as appropriate for this count's type. - MOZ_MUST_USE bool count(mozilla::MallocSizeOf mallocSizeOf, const Node& node) { - total_++; - - auto id = node.identifier(); - if (id < smallestNodeIdCounted_) { - smallestNodeIdCounted_ = id; - } + // In lieu of a vtable, each CountBase points to its type, which + // carries not only the implementations of the CountBase methods, but also + // additional parameters for the type's behavior, as specified in the + // breakdown argument passed to takeCensus. + CountType& type; + + protected: + ~CountBase() {} + + public: + explicit CountBase(CountType& type) + : type(type), total_(0), smallestNodeIdCounted_(SIZE_MAX) {} + + // Categorize and count |node| as appropriate for this count's type. + 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_; + 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. - MOZ_MUST_USE bool report(JSContext* cx, MutableHandleValue report) { - return type.report(cx, *this, report); - } + bool ret = type.count(*this, mallocSizeOf, node); - // Down-cast this CountBase to its true type, based on its 'type' member, - // and run its destructor. - void destruct() { return type.destructCount(*this); } - - // Trace this count for garbage collection. - 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_; + 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. + 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. + void destruct() { return type.destructCount(*this); } + + // Trace this count for garbage collection. + 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 { - CountBasePtr count; + CountBasePtr count; - void trace(JSTracer* trc) override { count->trace(trc); } + void trace(JSTracer* trc) override { count->trace(trc); } - public: - RootedCount(JSContext* cx, CountBasePtr&& count) - : CustomAutoRooter(cx), - count(Move(count)) - { } - CountBase* operator->() const { return count.get(); } - explicit operator bool() const { return count.get(); } - operator CountBasePtr&() { return count; } + public: + RootedCount(JSContext* cx, CountBasePtr&& count) + : CustomAutoRooter(cx), count(Move(count)) {} + CountBase* operator->() const { return count.get(); } + explicit operator bool() const { return count.get(); } + operator CountBasePtr&() { return count; } }; // Common data for a census traversal, shared across all CountType nodes. struct Census { - JSContext* const cx; - // If the targetZones set is non-empty, then only consider nodes whose zone - // is an element of the set. If the targetZones set is empty, then nodes in - // all zones are considered. - JS::ZoneSet targetZones; - Zone* atomsZone; + JSContext* const cx; + // If the targetZones set is non-empty, then only consider nodes whose zone + // is an element of the set. If the targetZones set is empty, then nodes in + // all zones are considered. + JS::ZoneSet targetZones; + Zone* atomsZone; - explicit Census(JSContext* cx) : cx(cx), atomsZone(nullptr) { } + explicit Census(JSContext* cx) : cx(cx), atomsZone(nullptr) {} - MOZ_MUST_USE JS_PUBLIC_API(bool) init(); + MOZ_MUST_USE JS_PUBLIC_API bool init(); }; // A BreadthFirst handler type that conducts a census, using a CountBase to // categorize and count each node. class CensusHandler { - Census& census; - CountBasePtr& rootCount; - mozilla::MallocSizeOf mallocSizeOf; - - public: - CensusHandler(Census& census, CountBasePtr& rootCount, mozilla::MallocSizeOf mallocSizeOf) - : census(census), - rootCount(rootCount), - mallocSizeOf(mallocSizeOf) - { } - - 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 { }; - - MOZ_MUST_USE JS_PUBLIC_API(bool) operator() (BreadthFirst& traversal, - Node origin, const Edge& edge, - NodeData* referentData, bool first); + Census& census; + CountBasePtr& rootCount; + mozilla::MallocSizeOf mallocSizeOf; + + public: + CensusHandler(Census& census, CountBasePtr& rootCount, + mozilla::MallocSizeOf mallocSizeOf) + : census(census), rootCount(rootCount), mallocSizeOf(mallocSizeOf) {} + + 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 {}; + + 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 (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); +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); - +JS_PUBLIC_API CountTypePtr ParseBreakdown(JSContext* cx, + HandleValue breakdownValue); -} // namespace ubi -} // namespace JS +} // namespace ubi +} // namespace JS -#endif // js_UbiNodeCensus_h +#endif // js_UbiNodeCensus_h 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 @@ -13,8 +13,7 @@ #include "mozilla/Move.h" #include "mozilla/UniquePtr.h" -#include "jsalloc.h" - +#include "js/AllocPolicy.h" #include "js/UbiNode.h" #include "js/UbiNodePostOrder.h" #include "js/Utility.h" @@ -67,611 +66,598 @@ * * [0]: http://www.cs.rice.edu/~keith/EMBED/dom.pdf */ -class JS_PUBLIC_API(DominatorTree) -{ - private: - // Types. - - using PredecessorSets = js::HashMap, - js::SystemAllocPolicy>; - using NodeToIndexMap = js::HashMap, - js::SystemAllocPolicy>; - class DominatedSets; - - public: - class DominatedSetRange; +class JS_PUBLIC_API DominatorTree { + private: + // Types. + + using PredecessorSets = js::HashMap, + js::SystemAllocPolicy>; + using NodeToIndexMap = js::HashMap, + js::SystemAllocPolicy>; + class DominatedSets; + + public: + class DominatedSetRange; + + /** + * A pointer to an immediately dominated node. + * + * Don't use this type directly; it is no safer than regular pointers. This + * is only for use indirectly with range-based for loops and + * `DominatedSetRange`. + * + * @see JS::ubi::DominatorTree::getDominatedSet + */ + class DominatedNodePtr { + friend class DominatedSetRange; + + const JS::ubi::Vector& postOrder; + const uint32_t* ptr; + + DominatedNodePtr(const JS::ubi::Vector& postOrder, + const uint32_t* ptr) + : postOrder(postOrder), ptr(ptr) {} + + public: + bool operator!=(const DominatedNodePtr& rhs) const { + return ptr != rhs.ptr; + } + void operator++() { ptr++; } + const Node& operator*() const { return postOrder[*ptr]; } + }; + + /** + * A range of immediately dominated `JS::ubi::Node`s for use with + * range-based for loops. + * + * @see JS::ubi::DominatorTree::getDominatedSet + */ + class DominatedSetRange { + friend class DominatedSets; + + const JS::ubi::Vector& postOrder; + const uint32_t* beginPtr; + const uint32_t* endPtr; + + DominatedSetRange(JS::ubi::Vector& postOrder, const uint32_t* begin, + const uint32_t* end) + : postOrder(postOrder), beginPtr(begin), endPtr(end) { + MOZ_ASSERT(begin <= end); + } + + public: + DominatedNodePtr begin() const { + MOZ_ASSERT(beginPtr <= endPtr); + return DominatedNodePtr(postOrder, beginPtr); + } + + DominatedNodePtr end() const { return DominatedNodePtr(postOrder, endPtr); } + + size_t length() const { + MOZ_ASSERT(beginPtr <= endPtr); + return endPtr - beginPtr; + } /** - * A pointer to an immediately dominated node. + * Safely skip ahead `n` dominators in the range, in O(1) time. * - * Don't use this type directly; it is no safer than regular pointers. This - * is only for use indirectly with range-based for loops and - * `DominatedSetRange`. + * Example usage: * - * @see JS::ubi::DominatorTree::getDominatedSet - */ - class DominatedNodePtr - { - friend class DominatedSetRange; - - const JS::ubi::Vector& postOrder; - const uint32_t* ptr; - - DominatedNodePtr(const JS::ubi::Vector& postOrder, const uint32_t* ptr) - : postOrder(postOrder) - , ptr(ptr) - { } - - public: - bool operator!=(const DominatedNodePtr& rhs) const { return ptr != rhs.ptr; } - void operator++() { ptr++; } - const Node& operator*() const { return postOrder[*ptr]; } - }; - - /** - * A range of immediately dominated `JS::ubi::Node`s for use with - * range-based for loops. + * mozilla::Maybe range = + * myDominatorTree.getDominatedSet(myNode); + * if (range.isNothing()) { + * // Handle unknown nodes however you see fit... + * return false; + * } * - * @see JS::ubi::DominatorTree::getDominatedSet + * // Don't care about the first ten, for whatever reason. + * range->skip(10); + * for (const JS::ubi::Node& dominatedNode : *range) { + * // ... + * } */ - class DominatedSetRange - { - friend class DominatedSets; - - const JS::ubi::Vector& postOrder; - const uint32_t* beginPtr; - const uint32_t* endPtr; - - DominatedSetRange(JS::ubi::Vector& postOrder, const uint32_t* begin, const uint32_t* end) - : postOrder(postOrder) - , beginPtr(begin) - , endPtr(end) - { - MOZ_ASSERT(begin <= end); - } - - public: - DominatedNodePtr begin() const { - MOZ_ASSERT(beginPtr <= endPtr); - return DominatedNodePtr(postOrder, beginPtr); - } - - DominatedNodePtr end() const { - return DominatedNodePtr(postOrder, endPtr); - } - - size_t length() const { - MOZ_ASSERT(beginPtr <= endPtr); - return endPtr - beginPtr; - } - - /** - * Safely skip ahead `n` dominators in the range, in O(1) time. - * - * Example usage: - * - * mozilla::Maybe range = myDominatorTree.getDominatedSet(myNode); - * if (range.isNothing()) { - * // Handle unknown nodes however you see fit... - * return false; - * } - * - * // Don't care about the first ten, for whatever reason. - * range->skip(10); - * for (const JS::ubi::Node& dominatedNode : *range) { - * // ... - * } - */ - void skip(size_t n) { - beginPtr += n; - if (beginPtr > endPtr) - beginPtr = endPtr; - } - }; + void skip(size_t n) { + beginPtr += n; + if (beginPtr > endPtr) beginPtr = endPtr; + } + }; + + private: + /** + * The set of all dominated sets in a dominator tree. + * + * Internally stores the sets in a contiguous array, with a side table of + * indices into that contiguous array to denote the start index of each + * individual set. + */ + class DominatedSets { + JS::ubi::Vector dominated; + JS::ubi::Vector indices; + + DominatedSets(JS::ubi::Vector&& dominated, + JS::ubi::Vector&& indices) + : dominated(mozilla::Move(dominated)), + indices(mozilla::Move(indices)) {} + + public: + // DominatedSets is not copy-able. + DominatedSets(const DominatedSets& rhs) = delete; + DominatedSets& operator=(const DominatedSets& rhs) = delete; + + // DominatedSets is move-able. + DominatedSets(DominatedSets&& rhs) + : dominated(mozilla::Move(rhs.dominated)), + indices(mozilla::Move(rhs.indices)) { + MOZ_ASSERT(this != &rhs, "self-move not allowed"); + } + DominatedSets& operator=(DominatedSets&& rhs) { + this->~DominatedSets(); + new (this) DominatedSets(mozilla::Move(rhs)); + return *this; + } - private: /** - * The set of all dominated sets in a dominator tree. - * - * Internally stores the sets in a contiguous array, with a side table of - * indices into that contiguous array to denote the start index of each - * individual set. + * Create the DominatedSets given the mapping of a node index to its + * immediate dominator. Returns `Some` on success, `Nothing` on OOM + * failure. */ - class DominatedSets - { - JS::ubi::Vector dominated; - JS::ubi::Vector indices; - - DominatedSets(JS::ubi::Vector&& dominated, JS::ubi::Vector&& indices) - : dominated(mozilla::Move(dominated)) - , indices(mozilla::Move(indices)) - { } - - public: - // DominatedSets is not copy-able. - DominatedSets(const DominatedSets& rhs) = delete; - DominatedSets& operator=(const DominatedSets& rhs) = delete; - - // DominatedSets is move-able. - DominatedSets(DominatedSets&& rhs) - : dominated(mozilla::Move(rhs.dominated)) - , indices(mozilla::Move(rhs.indices)) - { - MOZ_ASSERT(this != &rhs, "self-move not allowed"); - } - DominatedSets& operator=(DominatedSets&& rhs) { - this->~DominatedSets(); - new (this) DominatedSets(mozilla::Move(rhs)); - return *this; - } - - /** - * Create the DominatedSets given the mapping of a node index to its - * immediate dominator. Returns `Some` on success, `Nothing` on OOM - * failure. - */ - static mozilla::Maybe Create(const JS::ubi::Vector& doms) { - auto length = doms.length(); - MOZ_ASSERT(length < UINT32_MAX); - - // Create a vector `dominated` holding a flattened set of buckets of - // immediately dominated children nodes, with a lookup table - // `indices` mapping from each node to the beginning of its bucket. - // - // This has three phases: - // - // 1. Iterate over the full set of nodes and count up the size of - // each bucket. These bucket sizes are temporarily stored in the - // `indices` vector. - // - // 2. Convert the `indices` vector to store the cumulative sum of - // the sizes of all buckets before each index, resulting in a - // mapping from node index to one past the end of that node's - // bucket. - // - // 3. Iterate over the full set of nodes again, filling in bucket - // entries from the end of the bucket's range to its - // beginning. This decrements each index as a bucket entry is - // filled in. After having filled in all of a bucket's entries, - // the index points to the start of the bucket. - - JS::ubi::Vector dominated; - JS::ubi::Vector indices; - if (!dominated.growBy(length) || !indices.growBy(length)) - return mozilla::Nothing(); - - // 1 - memset(indices.begin(), 0, length * sizeof(uint32_t)); - for (uint32_t i = 0; i < length; i++) - indices[doms[i]]++; - - // 2 - uint32_t sumOfSizes = 0; - for (uint32_t i = 0; i < length; i++) { - sumOfSizes += indices[i]; - MOZ_ASSERT(sumOfSizes <= length); - indices[i] = sumOfSizes; - } - - // 3 - for (uint32_t i = 0; i < length; i++) { - auto idxOfDom = doms[i]; - indices[idxOfDom]--; - dominated[indices[idxOfDom]] = i; - } + static mozilla::Maybe Create( + const JS::ubi::Vector& doms) { + auto length = doms.length(); + MOZ_ASSERT(length < UINT32_MAX); + + // Create a vector `dominated` holding a flattened set of buckets of + // immediately dominated children nodes, with a lookup table + // `indices` mapping from each node to the beginning of its bucket. + // + // This has three phases: + // + // 1. Iterate over the full set of nodes and count up the size of + // each bucket. These bucket sizes are temporarily stored in the + // `indices` vector. + // + // 2. Convert the `indices` vector to store the cumulative sum of + // the sizes of all buckets before each index, resulting in a + // mapping from node index to one past the end of that node's + // bucket. + // + // 3. Iterate over the full set of nodes again, filling in bucket + // entries from the end of the bucket's range to its + // beginning. This decrements each index as a bucket entry is + // filled in. After having filled in all of a bucket's entries, + // the index points to the start of the bucket. + + JS::ubi::Vector dominated; + JS::ubi::Vector indices; + if (!dominated.growBy(length) || !indices.growBy(length)) + return mozilla::Nothing(); + + // 1 + memset(indices.begin(), 0, length * sizeof(uint32_t)); + for (uint32_t i = 0; i < length; i++) indices[doms[i]]++; + + // 2 + uint32_t sumOfSizes = 0; + for (uint32_t i = 0; i < length; i++) { + sumOfSizes += indices[i]; + MOZ_ASSERT(sumOfSizes <= length); + indices[i] = sumOfSizes; + } + + // 3 + for (uint32_t i = 0; i < length; i++) { + auto idxOfDom = doms[i]; + indices[idxOfDom]--; + dominated[indices[idxOfDom]] = i; + } #ifdef DEBUG - // Assert that our buckets are non-overlapping and don't run off the - // end of the vector. - uint32_t lastIndex = 0; - for (uint32_t i = 0; i < length; i++) { - MOZ_ASSERT(indices[i] >= lastIndex); - MOZ_ASSERT(indices[i] < length); - lastIndex = indices[i]; - } + // Assert that our buckets are non-overlapping and don't run off the + // end of the vector. + uint32_t lastIndex = 0; + for (uint32_t i = 0; i < length; i++) { + MOZ_ASSERT(indices[i] >= lastIndex); + MOZ_ASSERT(indices[i] < length); + lastIndex = indices[i]; + } #endif - return mozilla::Some(DominatedSets(mozilla::Move(dominated), mozilla::Move(indices))); - } - - /** - * Get the set of nodes immediately dominated by the node at - * `postOrder[nodeIndex]`. - */ - 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 - ? dominated.end() - : &dominated[indices[nodeIndex + 1]]; - return DominatedSetRange(postOrder, &dominated[indices[nodeIndex]], end); - } - }; - - private: - // Data members. - JS::ubi::Vector postOrder; - NodeToIndexMap nodeToPostOrderIndex; - JS::ubi::Vector doms; - DominatedSets dominatedSets; - mozilla::Maybe> retainedSizes; - - private: - // We use `UNDEFINED` as a sentinel value in the `doms` vector to signal - // that we haven't found any dominators for the node at the corresponding - // index in `postOrder` yet. - static const uint32_t UNDEFINED = UINT32_MAX; - - 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)) - , dominatedSets(mozilla::Move(dominatedSets)) - , retainedSizes(mozilla::Nothing()) - { } - - static uint32_t intersect(JS::ubi::Vector& doms, uint32_t finger1, uint32_t finger2) { - while (finger1 != finger2) { - if (finger1 < finger2) - finger1 = doms[finger1]; - else if (finger2 < finger1) - finger2 = doms[finger2]; - } - return finger1; - } - - // Do the post order traversal of the heap graph and populate our - // predecessor sets. - 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++; - if (MOZ_UNLIKELY(nodeCount == UINT32_MAX)) - return false; - return postOrder.append(node); - }; - - auto onEdge = [&](const Node& origin, const Edge& edge) { - auto p = predecessorSets.lookupForAdd(edge.referent); - if (!p) { - mozilla::UniquePtr> set(js_new()); - if (!set || - !set->init() || - !predecessorSets.add(p, edge.referent, mozilla::Move(set))) - { - return false; - } - } - MOZ_ASSERT(p && p->value()); - return p->value()->put(origin); - }; - - PostOrder traversal(cx, noGC); - return traversal.init() && - traversal.addStart(root) && - traversal.traverse(onNode, onEdge); - } - - // Populates the given `map` with an entry for each node to its index in - // `postOrder`. - 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(); - if (!map.init(length)) - return false; - for (uint32_t i = 0; i < length; i++) - map.putNewInfallible(postOrder[i], i); - return true; - } - - // Convert the Node -> NodeSet predecessorSets to a index -> Vector - // form. - static MOZ_MUST_USE bool convertPredecessorSetsToVectors( - const Node& root, - JS::ubi::Vector& postOrder, - PredecessorSets& predecessorSets, - NodeToIndexMap& nodeToPostOrderIndex, - JS::ubi::Vector>& predecessorVectors) - { - MOZ_ASSERT(postOrder.length() < UINT32_MAX); - uint32_t length = postOrder.length(); - - MOZ_ASSERT(predecessorVectors.length() == 0); - if (!predecessorVectors.growBy(length)) - return false; - - for (uint32_t i = 0; i < length - 1; i++) { - auto& node = postOrder[i]; - MOZ_ASSERT(node != root, - "Only the last node should be root, since this was a post order traversal."); - - auto ptr = predecessorSets.lookup(node); - MOZ_ASSERT(ptr, - "Because this isn't the root, it had better have predecessors, or else how " - "did we even find it."); - - auto& predecessors = ptr->value(); - if (!predecessorVectors[i].reserve(predecessors->count())) - return false; - for (auto range = predecessors->all(); !range.empty(); range.popFront()) { - auto ptr = nodeToPostOrderIndex.lookup(range.front()); - MOZ_ASSERT(ptr); - predecessorVectors[i].infallibleAppend(ptr->value()); - } - } - predecessorSets.finish(); - return true; - } - - // Initialize `doms` such that the immediate dominator of the `root` is the - // `root` itself and all others are `UNDEFINED`. - static MOZ_MUST_USE bool initializeDominators(JS::ubi::Vector& doms, - uint32_t length) { - MOZ_ASSERT(doms.length() == 0); - if (!doms.growByUninitialized(length)) - return false; - doms[length - 1] = length - 1; - for (uint32_t i = 0; i < length - 1; i++) - doms[i] = UNDEFINED; - return true; - } - - void assertSanity() const { - MOZ_ASSERT(postOrder.length() == doms.length()); - MOZ_ASSERT(postOrder.length() == nodeToPostOrderIndex.count()); - MOZ_ASSERT_IF(retainedSizes.isSome(), postOrder.length() == retainedSizes->length()); - } - - MOZ_MUST_USE bool computeRetainedSizes(mozilla::MallocSizeOf mallocSizeOf) { - MOZ_ASSERT(retainedSizes.isNothing()); - auto length = postOrder.length(); - - retainedSizes.emplace(); - if (!retainedSizes->growBy(length)) { - retainedSizes = mozilla::Nothing(); - return false; - } - - // Iterate in forward order so that we know all of a node's children in - // the dominator tree have already had their retained size - // computed. Then we can simply say that the retained size of a node is - // its shallow size (JS::ubi::Node::size) plus the retained sizes of its - // immediate children in the tree. - - for (uint32_t i = 0; i < length; i++) { - auto size = postOrder[i].size(mallocSizeOf); - - for (const auto& dominated : dominatedSets.dominatedSet(postOrder, i)) { - // The root node dominates itself, but shouldn't contribute to - // its own retained size. - if (dominated == postOrder[length - 1]) { - MOZ_ASSERT(i == length - 1); - continue; - } - - auto ptr = nodeToPostOrderIndex.lookup(dominated); - MOZ_ASSERT(ptr); - auto idxOfDominated = ptr->value(); - MOZ_ASSERT(idxOfDominated < i); - size += retainedSizes.ref()[idxOfDominated]; - } - - retainedSizes.ref()[i] = size; - } - - return true; - } - - public: - // DominatorTree is not copy-able. - DominatorTree(const DominatorTree&) = delete; - DominatorTree& operator=(const DominatorTree&) = delete; - - // DominatorTree is move-able. - DominatorTree(DominatorTree&& rhs) - : postOrder(mozilla::Move(rhs.postOrder)) - , nodeToPostOrderIndex(mozilla::Move(rhs.nodeToPostOrderIndex)) - , doms(mozilla::Move(rhs.doms)) - , dominatedSets(mozilla::Move(rhs.dominatedSets)) - , retainedSizes(mozilla::Move(rhs.retainedSizes)) - { - MOZ_ASSERT(this != &rhs, "self-move is not allowed"); - } - DominatorTree& operator=(DominatorTree&& rhs) { - this->~DominatorTree(); - new (this) DominatorTree(mozilla::Move(rhs)); - return *this; + return mozilla::Some( + DominatedSets(mozilla::Move(dominated), mozilla::Move(indices))); } /** - * Construct a `DominatorTree` of the heap graph visible from `root`. The - * `root` is also used as the root of the resulting dominator tree. - * - * The resulting `DominatorTree` 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 `DominatorTree`'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 `DominatorTree`'s lifetime is - * bounded by that offline structure's lifetime. - * - * In practice, this means that within SpiderMonkey we must treat - * `DominatorTree` as if it were backed by the live heap graph and trust - * that embedders with knowledge of the graph's implementation will do the - * Right Thing. - * - * Returns `mozilla::Nothing()` on OOM failure. It is the caller's - * responsibility to handle and report the OOM. + * Get the set of nodes immediately dominated by the node at + * `postOrder[nodeIndex]`. */ - static mozilla::Maybe - Create(JSContext* cx, AutoCheckCannotGC& noGC, const Node& root) { - JS::ubi::Vector postOrder; - PredecessorSets predecessorSets; - if (!predecessorSets.init() || !doTraversal(cx, noGC, root, postOrder, predecessorSets)) - return mozilla::Nothing(); - - MOZ_ASSERT(postOrder.length() < UINT32_MAX); - uint32_t length = postOrder.length(); - MOZ_ASSERT(postOrder[length - 1] == root); - - // From here on out we wish to avoid hash table lookups, and we use - // indices into `postOrder` instead of actual nodes wherever - // possible. This greatly improves the performance of this - // implementation, but we have to pay a little bit of upfront cost to - // convert our data structures to play along first. - - NodeToIndexMap nodeToPostOrderIndex; - if (!mapNodesToTheirIndices(postOrder, nodeToPostOrderIndex)) - return mozilla::Nothing(); - - JS::ubi::Vector> predecessorVectors; - if (!convertPredecessorSetsToVectors(root, postOrder, predecessorSets, nodeToPostOrderIndex, - predecessorVectors)) - return mozilla::Nothing(); - - JS::ubi::Vector doms; - if (!initializeDominators(doms, length)) - return mozilla::Nothing(); - - bool changed = true; - while (changed) { - changed = false; - - // Iterate over the non-root nodes in reverse post order. - for (uint32_t indexPlusOne = length - 1; indexPlusOne > 0; indexPlusOne--) { - MOZ_ASSERT(postOrder[indexPlusOne - 1] != root); - - // Take the intersection of every predecessor's dominator set; - // that is the current best guess at the immediate dominator for - // this node. - - uint32_t newIDomIdx = UNDEFINED; - - auto& predecessors = predecessorVectors[indexPlusOne - 1]; - auto range = predecessors.all(); - for ( ; !range.empty(); range.popFront()) { - auto idx = range.front(); - if (doms[idx] != UNDEFINED) { - newIDomIdx = idx; - break; - } - } - - MOZ_ASSERT(newIDomIdx != UNDEFINED, - "Because the root is initialized to dominate itself and is the first " - "node in every path, there must exist a predecessor to this node that " - "also has a dominator."); - - for ( ; !range.empty(); range.popFront()) { - auto idx = range.front(); - if (doms[idx] != UNDEFINED) - newIDomIdx = intersect(doms, newIDomIdx, idx); - } - - // If the immediate dominator changed, we will have to do - // another pass of the outer while loop to continue the forward - // dataflow. - if (newIDomIdx != doms[indexPlusOne - 1]) { - doms[indexPlusOne - 1] = newIDomIdx; - changed = true; - } - } - } - - auto maybeDominatedSets = DominatedSets::Create(doms); - if (maybeDominatedSets.isNothing()) - return mozilla::Nothing(); - - return mozilla::Some(DominatorTree(mozilla::Move(postOrder), - mozilla::Move(nodeToPostOrderIndex), - mozilla::Move(doms), - mozilla::Move(*maybeDominatedSets))); - } + 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 + ? dominated.end() + : &dominated[indices[nodeIndex + 1]]; + return DominatedSetRange(postOrder, &dominated[indices[nodeIndex]], end); + } + }; + + private: + // Data members. + JS::ubi::Vector postOrder; + NodeToIndexMap nodeToPostOrderIndex; + JS::ubi::Vector doms; + DominatedSets dominatedSets; + mozilla::Maybe> retainedSizes; + + private: + // We use `UNDEFINED` as a sentinel value in the `doms` vector to signal + // that we haven't found any dominators for the node at the corresponding + // index in `postOrder` yet. + static const uint32_t UNDEFINED = UINT32_MAX; + + 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)), + dominatedSets(mozilla::Move(dominatedSets)), + retainedSizes(mozilla::Nothing()) {} + + static uint32_t intersect(JS::ubi::Vector& doms, uint32_t finger1, + uint32_t finger2) { + while (finger1 != finger2) { + if (finger1 < finger2) + finger1 = doms[finger1]; + else if (finger2 < finger1) + finger2 = doms[finger2]; + } + return finger1; + } + + // Do the post order traversal of the heap graph and populate our + // predecessor sets. + 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++; + if (MOZ_UNLIKELY(nodeCount == UINT32_MAX)) return false; + return postOrder.append(node); + }; - /** - * Get the root node for this dominator tree. - */ - const Node& root() const { - return postOrder[postOrder.length() - 1]; - } + auto onEdge = [&](const Node& origin, const Edge& edge) { + auto p = predecessorSets.lookupForAdd(edge.referent); + if (!p) { + mozilla::UniquePtr> set( + js_new()); + if (!set || !set->init() || + !predecessorSets.add(p, edge.referent, mozilla::Move(set))) { + return false; + } + } + MOZ_ASSERT(p && p->value()); + return p->value()->put(origin); + }; - /** - * Return the immediate dominator of the given `node`. If `node` was not - * reachable from the `root` that this dominator tree was constructed from, - * then return the null `JS::ubi::Node`. - */ - Node getImmediateDominator(const Node& node) const { - assertSanity(); - auto ptr = nodeToPostOrderIndex.lookup(node); - if (!ptr) - return Node(); - - auto idx = ptr->value(); - MOZ_ASSERT(idx < postOrder.length()); - return postOrder[doms[idx]]; - } + PostOrder traversal(cx, noGC); + return traversal.init() && traversal.addStart(root) && + traversal.traverse(onNode, onEdge); + } + + // Populates the given `map` with an entry for each node to its index in + // `postOrder`. + 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(); + if (!map.init(length)) return false; + for (uint32_t i = 0; i < length; i++) map.putNewInfallible(postOrder[i], i); + return true; + } + + // Convert the Node -> NodeSet predecessorSets to a index -> Vector + // form. + static MOZ_MUST_USE bool convertPredecessorSetsToVectors( + const Node& root, JS::ubi::Vector& postOrder, + PredecessorSets& predecessorSets, NodeToIndexMap& nodeToPostOrderIndex, + JS::ubi::Vector>& predecessorVectors) { + MOZ_ASSERT(postOrder.length() < UINT32_MAX); + uint32_t length = postOrder.length(); + + MOZ_ASSERT(predecessorVectors.length() == 0); + if (!predecessorVectors.growBy(length)) return false; + + for (uint32_t i = 0; i < length - 1; i++) { + auto& node = postOrder[i]; + MOZ_ASSERT(node != root, + "Only the last node should be root, since this was a post " + "order traversal."); + + auto ptr = predecessorSets.lookup(node); + MOZ_ASSERT(ptr, + "Because this isn't the root, it had better have " + "predecessors, or else how " + "did we even find it."); + + auto& predecessors = ptr->value(); + if (!predecessorVectors[i].reserve(predecessors->count())) return false; + for (auto range = predecessors->all(); !range.empty(); range.popFront()) { + auto ptr = nodeToPostOrderIndex.lookup(range.front()); + MOZ_ASSERT(ptr); + predecessorVectors[i].infallibleAppend(ptr->value()); + } + } + predecessorSets.finish(); + return true; + } + + // Initialize `doms` such that the immediate dominator of the `root` is the + // `root` itself and all others are `UNDEFINED`. + static MOZ_MUST_USE bool initializeDominators(JS::ubi::Vector& doms, + uint32_t length) { + MOZ_ASSERT(doms.length() == 0); + if (!doms.growByUninitialized(length)) return false; + doms[length - 1] = length - 1; + for (uint32_t i = 0; i < length - 1; i++) doms[i] = UNDEFINED; + return true; + } + + void assertSanity() const { + MOZ_ASSERT(postOrder.length() == doms.length()); + MOZ_ASSERT(postOrder.length() == nodeToPostOrderIndex.count()); + MOZ_ASSERT_IF(retainedSizes.isSome(), + postOrder.length() == retainedSizes->length()); + } + + MOZ_MUST_USE bool computeRetainedSizes(mozilla::MallocSizeOf mallocSizeOf) { + MOZ_ASSERT(retainedSizes.isNothing()); + auto length = postOrder.length(); + + retainedSizes.emplace(); + if (!retainedSizes->growBy(length)) { + retainedSizes = mozilla::Nothing(); + return false; + } + + // Iterate in forward order so that we know all of a node's children in + // the dominator tree have already had their retained size + // computed. Then we can simply say that the retained size of a node is + // its shallow size (JS::ubi::Node::size) plus the retained sizes of its + // immediate children in the tree. + + for (uint32_t i = 0; i < length; i++) { + auto size = postOrder[i].size(mallocSizeOf); + + for (const auto& dominated : dominatedSets.dominatedSet(postOrder, i)) { + // The root node dominates itself, but shouldn't contribute to + // its own retained size. + if (dominated == postOrder[length - 1]) { + MOZ_ASSERT(i == length - 1); + continue; + } + + auto ptr = nodeToPostOrderIndex.lookup(dominated); + MOZ_ASSERT(ptr); + auto idxOfDominated = ptr->value(); + MOZ_ASSERT(idxOfDominated < i); + size += retainedSizes.ref()[idxOfDominated]; + } + + retainedSizes.ref()[i] = size; + } + + return true; + } + + public: + // DominatorTree is not copy-able. + DominatorTree(const DominatorTree&) = delete; + DominatorTree& operator=(const DominatorTree&) = delete; + + // DominatorTree is move-able. + DominatorTree(DominatorTree&& rhs) + : postOrder(mozilla::Move(rhs.postOrder)), + nodeToPostOrderIndex(mozilla::Move(rhs.nodeToPostOrderIndex)), + doms(mozilla::Move(rhs.doms)), + dominatedSets(mozilla::Move(rhs.dominatedSets)), + retainedSizes(mozilla::Move(rhs.retainedSizes)) { + MOZ_ASSERT(this != &rhs, "self-move is not allowed"); + } + DominatorTree& operator=(DominatorTree&& rhs) { + this->~DominatorTree(); + new (this) DominatorTree(mozilla::Move(rhs)); + return *this; + } + + /** + * Construct a `DominatorTree` of the heap graph visible from `root`. The + * `root` is also used as the root of the resulting dominator tree. + * + * The resulting `DominatorTree` 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 `DominatorTree`'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 `DominatorTree`'s lifetime is + * bounded by that offline structure's lifetime. + * + * In practice, this means that within SpiderMonkey we must treat + * `DominatorTree` as if it were backed by the live heap graph and trust + * that embedders with knowledge of the graph's implementation will do the + * Right Thing. + * + * 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, + const Node& root) { + JS::ubi::Vector postOrder; + PredecessorSets predecessorSets; + if (!predecessorSets.init() || + !doTraversal(cx, noGC, root, postOrder, predecessorSets)) + return mozilla::Nothing(); + + MOZ_ASSERT(postOrder.length() < UINT32_MAX); + uint32_t length = postOrder.length(); + MOZ_ASSERT(postOrder[length - 1] == root); + + // From here on out we wish to avoid hash table lookups, and we use + // indices into `postOrder` instead of actual nodes wherever + // possible. This greatly improves the performance of this + // implementation, but we have to pay a little bit of upfront cost to + // convert our data structures to play along first. - /** - * Get the set of nodes immediately dominated by the given `node`. If `node` - * is not a member of this dominator tree, return `Nothing`. - * - * Example usage: - * - * mozilla::Maybe range = myDominatorTree.getDominatedSet(myNode); - * if (range.isNothing()) { - * // Handle unknown node however you see fit... - * return false; - * } - * - * for (const JS::ubi::Node& dominatedNode : *range) { - * // Do something with each immediately dominated node... - * } - */ - mozilla::Maybe getDominatedSet(const Node& node) { - assertSanity(); - auto ptr = nodeToPostOrderIndex.lookup(node); - if (!ptr) - return mozilla::Nothing(); - - auto idx = ptr->value(); - MOZ_ASSERT(idx < postOrder.length()); - return mozilla::Some(dominatedSets.dominatedSet(postOrder, idx)); - } + NodeToIndexMap nodeToPostOrderIndex; + if (!mapNodesToTheirIndices(postOrder, nodeToPostOrderIndex)) + return mozilla::Nothing(); - /** - * Get the retained size of the given `node`. The size is placed in - * `outSize`, or 0 if `node` is not a member of the dominator tree. Returns - * false on OOM failure, leaving `outSize` unchanged. - */ - MOZ_MUST_USE bool getRetainedSize(const Node& node, mozilla::MallocSizeOf mallocSizeOf, - Node::Size& outSize) { - assertSanity(); - auto ptr = nodeToPostOrderIndex.lookup(node); - if (!ptr) { - outSize = 0; - return true; - } + JS::ubi::Vector> predecessorVectors; + if (!convertPredecessorSetsToVectors(root, postOrder, predecessorSets, + nodeToPostOrderIndex, + predecessorVectors)) + return mozilla::Nothing(); - if (retainedSizes.isNothing() && !computeRetainedSizes(mallocSizeOf)) - return false; + JS::ubi::Vector doms; + if (!initializeDominators(doms, length)) return mozilla::Nothing(); - auto idx = ptr->value(); - MOZ_ASSERT(idx < postOrder.length()); - outSize = retainedSizes.ref()[idx]; - return true; - } + bool changed = true; + while (changed) { + changed = false; + + // Iterate over the non-root nodes in reverse post order. + for (uint32_t indexPlusOne = length - 1; indexPlusOne > 0; + indexPlusOne--) { + MOZ_ASSERT(postOrder[indexPlusOne - 1] != root); + + // Take the intersection of every predecessor's dominator set; + // that is the current best guess at the immediate dominator for + // this node. + + uint32_t newIDomIdx = UNDEFINED; + + auto& predecessors = predecessorVectors[indexPlusOne - 1]; + auto range = predecessors.all(); + for (; !range.empty(); range.popFront()) { + auto idx = range.front(); + if (doms[idx] != UNDEFINED) { + newIDomIdx = idx; + break; + } + } + + MOZ_ASSERT(newIDomIdx != UNDEFINED, + "Because the root is initialized to dominate itself and is " + "the first " + "node in every path, there must exist a predecessor to this " + "node that " + "also has a dominator."); + + for (; !range.empty(); range.popFront()) { + auto idx = range.front(); + if (doms[idx] != UNDEFINED) + newIDomIdx = intersect(doms, newIDomIdx, idx); + } + + // If the immediate dominator changed, we will have to do + // another pass of the outer while loop to continue the forward + // dataflow. + if (newIDomIdx != doms[indexPlusOne - 1]) { + doms[indexPlusOne - 1] = newIDomIdx; + changed = true; + } + } + } + + auto maybeDominatedSets = DominatedSets::Create(doms); + if (maybeDominatedSets.isNothing()) return mozilla::Nothing(); + + return mozilla::Some(DominatorTree( + mozilla::Move(postOrder), mozilla::Move(nodeToPostOrderIndex), + mozilla::Move(doms), mozilla::Move(*maybeDominatedSets))); + } + + /** + * Get the root node for this dominator tree. + */ + const Node& root() const { return postOrder[postOrder.length() - 1]; } + + /** + * Return the immediate dominator of the given `node`. If `node` was not + * reachable from the `root` that this dominator tree was constructed from, + * then return the null `JS::ubi::Node`. + */ + Node getImmediateDominator(const Node& node) const { + assertSanity(); + auto ptr = nodeToPostOrderIndex.lookup(node); + if (!ptr) return Node(); + + auto idx = ptr->value(); + MOZ_ASSERT(idx < postOrder.length()); + return postOrder[doms[idx]]; + } + + /** + * Get the set of nodes immediately dominated by the given `node`. If `node` + * is not a member of this dominator tree, return `Nothing`. + * + * Example usage: + * + * mozilla::Maybe range = + * myDominatorTree.getDominatedSet(myNode); + * if (range.isNothing()) { + * // Handle unknown node however you see fit... + * return false; + * } + * + * for (const JS::ubi::Node& dominatedNode : *range) { + * // Do something with each immediately dominated node... + * } + */ + mozilla::Maybe getDominatedSet(const Node& node) { + assertSanity(); + auto ptr = nodeToPostOrderIndex.lookup(node); + if (!ptr) return mozilla::Nothing(); + + auto idx = ptr->value(); + MOZ_ASSERT(idx < postOrder.length()); + return mozilla::Some(dominatedSets.dominatedSet(postOrder, idx)); + } + + /** + * Get the retained size of the given `node`. The size is placed in + * `outSize`, or 0 if `node` is not a member of the dominator tree. Returns + * false on OOM failure, leaving `outSize` unchanged. + */ + MOZ_MUST_USE bool getRetainedSize(const Node& node, + mozilla::MallocSizeOf mallocSizeOf, + Node::Size& outSize) { + assertSanity(); + auto ptr = nodeToPostOrderIndex.lookup(node); + if (!ptr) { + outSize = 0; + return true; + } + + if (retainedSizes.isNothing() && !computeRetainedSizes(mallocSizeOf)) + return false; + + auto idx = ptr->value(); + MOZ_ASSERT(idx < postOrder.length()); + outSize = retainedSizes.ref()[idx]; + return true; + } }; -} // namespace ubi -} // namespace JS +} // namespace ubi +} // namespace JS -#endif // js_UbiNodeDominatorTree_h +#endif // js_UbiNodeDominatorTree_h 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 @@ -11,8 +11,7 @@ #include "mozilla/Maybe.h" #include "mozilla/Move.h" -#include "jsalloc.h" - +#include "js/AllocPolicy.h" #include "js/UbiNode.h" #include "js/Utility.h" #include "js/Vector.h" @@ -53,139 +52,129 @@ * causes `PostOrder::traverse` to return false. */ struct PostOrder { - private: - struct OriginAndEdges { - Node origin; - EdgeVector edges; - - OriginAndEdges(const Node& node, EdgeVector&& edges) - : origin(node) - , edges(mozilla::Move(edges)) - { } - - OriginAndEdges(const OriginAndEdges& rhs) = delete; - OriginAndEdges& operator=(const OriginAndEdges& rhs) = delete; - - OriginAndEdges(OriginAndEdges&& rhs) - : origin(rhs.origin) - , edges(mozilla::Move(rhs.edges)) - { - MOZ_ASSERT(&rhs != this, "self-move disallowed"); - } - - OriginAndEdges& operator=(OriginAndEdges&& rhs) { - this->~OriginAndEdges(); - new (this) OriginAndEdges(mozilla::Move(rhs)); - return *this; - } - }; - - using Stack = js::Vector; - using Set = js::HashSet, js::SystemAllocPolicy>; - - JSContext* cx; - Set seen; - Stack stack; -#ifdef DEBUG - bool traversed; -#endif - - private: - 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()))) - return false; - } - return true; + private: + struct OriginAndEdges { + Node origin; + EdgeVector edges; + + OriginAndEdges(const Node& node, EdgeVector&& edges) + : origin(node), edges(mozilla::Move(edges)) {} + + OriginAndEdges(const OriginAndEdges& rhs) = delete; + OriginAndEdges& operator=(const OriginAndEdges& rhs) = delete; + + OriginAndEdges(OriginAndEdges&& rhs) + : origin(rhs.origin), edges(mozilla::Move(rhs.edges)) { + MOZ_ASSERT(&rhs != this, "self-move disallowed"); } - MOZ_MUST_USE bool pushForTraversing(const Node& node) { - EdgeVector edges; - auto range = node.edges(cx, /* wantNames */ false); - return range && - fillEdgesFromRange(edges, range) && - stack.append(OriginAndEdges(node, mozilla::Move(edges))); + OriginAndEdges& operator=(OriginAndEdges&& rhs) { + this->~OriginAndEdges(); + new (this) OriginAndEdges(mozilla::Move(rhs)); + return *this; } + }; + using Stack = js::Vector; + using Set = js::HashSet, js::SystemAllocPolicy>; - public: - // Construct a post-order traversal object. - // - // 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(JSContext* cx, AutoCheckCannotGC&) - : cx(cx) - , seen() - , stack() + JSContext* cx; + Set seen; + Stack stack; #ifdef DEBUG - , traversed(false) + bool traversed; #endif - { } - - // Initialize this traversal object. Return false on OOM. - 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. - MOZ_MUST_USE bool addStart(const Node& node) { - if (!seen.put(node)) - return false; - return pushForTraversing(node); + private: + 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()))) return false; } + return true; + } - // Traverse the graph in post-order, starting with the set of nodes passed - // to `addStart` and applying `onNode::operator()` for each node in the - // graph and `onEdge::operator()` for each edge in the graph, as described - // above. - // - // This should be called only once per instance of this class. - // - // Return false on OOM or error return from `onNode::operator()` or - // `onEdge::operator()`. - template - MOZ_MUST_USE bool traverse(NodeVisitor onNode, EdgeVisitor onEdge) { + MOZ_MUST_USE bool pushForTraversing(const Node& node) { + EdgeVector edges; + auto range = node.edges(cx, /* wantNames */ false); + return range && fillEdgesFromRange(edges, range) && + stack.append(OriginAndEdges(node, mozilla::Move(edges))); + } + + public: + // Construct a post-order traversal object. + // + // 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(JSContext* cx, AutoCheckCannotGC&) + : cx(cx), + seen(), + stack() #ifdef DEBUG - MOZ_ASSERT(!traversed, "Can only traverse() once!"); - traversed = true; + , + traversed(false) #endif + { + } - while (!stack.empty()) { - auto& origin = stack.back().origin; - auto& edges = stack.back().edges; - - if (edges.empty()) { - if (!onNode(origin)) - return false; - stack.popBack(); - continue; - } - - Edge edge = mozilla::Move(edges.back()); - edges.popBack(); - - if (!onEdge(origin, edge)) - return false; - - auto ptr = seen.lookupForAdd(edge.referent); - // We've already seen this node, don't follow its edges. - if (ptr) - continue; - - // Mark the referent as seen and follow its edges. - if (!seen.add(ptr, edge.referent) || - !pushForTraversing(edge.referent)) - { - return false; - } - } + // Initialize this traversal object. Return false on OOM. + MOZ_MUST_USE bool init() { return seen.init(); } - return true; + // Add `node` as a starting point for the traversal. You may add + // as many starting points as you like. Returns false on OOM. + MOZ_MUST_USE bool addStart(const Node& node) { + if (!seen.put(node)) return false; + return pushForTraversing(node); + } + + // Traverse the graph in post-order, starting with the set of nodes passed + // to `addStart` and applying `onNode::operator()` for each node in the + // graph and `onEdge::operator()` for each edge in the graph, as described + // above. + // + // This should be called only once per instance of this class. + // + // Return false on OOM or error return from `onNode::operator()` or + // `onEdge::operator()`. + template + 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; + auto& edges = stack.back().edges; + + if (edges.empty()) { + if (!onNode(origin)) return false; + stack.popBack(); + continue; + } + + Edge edge = mozilla::Move(edges.back()); + edges.popBack(); + + if (!onEdge(origin, edge)) return false; + + auto ptr = seen.lookupForAdd(edge.referent); + // We've already seen this node, don't follow its edges. + if (ptr) continue; + + // Mark the referent as seen and follow its edges. + if (!seen.add(ptr, edge.referent) || !pushForTraversing(edge.referent)) { + return false; + } } + + return true; + } }; -} // namespace ubi -} // namespace JS +} // namespace ubi +} // namespace JS -#endif // js_UbiNodePostOrder_h +#endif // js_UbiNodePostOrder_h 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 @@ -11,8 +11,7 @@ #include "mozilla/Maybe.h" #include "mozilla/Move.h" -#include "jsalloc.h" - +#include "js/AllocPolicy.h" #include "js/UbiNodeBreadthFirst.h" #include "js/Vector.h" @@ -22,48 +21,45 @@ /** * 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; - } +struct JS_PUBLIC_API BackEdge { + private: + Node predecessor_; + EdgeName name_; - BackEdge(const BackEdge&) = delete; - BackEdge& operator=(const BackEdge&) = delete; + public: + using Ptr = mozilla::UniquePtr>; - BackEdge(BackEdge&& rhs) - : predecessor_(rhs.predecessor_) - , name_(mozilla::Move(rhs.name_)) - { - MOZ_ASSERT(&rhs != this); - } + BackEdge() : predecessor_(), name_(nullptr) {} - BackEdge& operator=(BackEdge&& rhs) { - this->~BackEdge(); - new(this) BackEdge(Move(rhs)); - return *this; - } + 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); + } - Ptr clone() const; + BackEdge& operator=(BackEdge&& rhs) { + this->~BackEdge(); + new (this) BackEdge(Move(rhs)); + return *this; + } - const EdgeName& name() const { return name_; } - EdgeName& name() { return name_; } + Ptr clone() const; - const JS::ubi::Node& predecessor() const { return predecessor_; } + const EdgeName& name() const { return name_; } + EdgeName& name() { return name_; } + + const JS::ubi::Node& predecessor() const { return predecessor_; } }; /** @@ -76,259 +72,246 @@ * 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; +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, const 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++; } + } - }; - - // The maximum number of paths to record for each node. - uint32_t maxNumPaths_; - - // The root node we are starting the search from. - Node root_; + MOZ_ASSERT(totalPathsRecorded <= totalMaxPathsToRecord); + if (totalPathsRecorded == totalMaxPathsToRecord) traversal.stop(); - // 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()); + return true; } + }; - 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; - } + // The maximum number of paths to record for each node. + uint32_t maxNumPaths_; - ShortestPaths(const ShortestPaths&) = delete; - ShortestPaths& operator=(const ShortestPaths&) = delete; + // The root node we are starting the search from. + Node root_; - /** - * 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); + // 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); + } - MOZ_ASSERT(paths.initialized()); - return mozilla::Some(mozilla::Move(paths)); - } + path.reverse(); - /** - * 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(); + if (!func(path)) return false; } - /** - * 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; - } + return true; + } }; #ifdef DEBUG @@ -340,11 +323,11 @@ // // JSObject* foo = ...; // JS::ubi::dumpPaths(rt, JS::ubi::Node(foo)); -JS_PUBLIC_API(void) -dumpPaths(JSRuntime* rt, Node node, uint32_t maxNumPaths = 10); +JS_PUBLIC_API void dumpPaths(JSRuntime* rt, Node node, + uint32_t maxNumPaths = 10); #endif -} // namespace ubi -} // namespace JS +} // namespace ubi +} // namespace JS -#endif // js_UbiNodeShortestPaths_h +#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 @@ -13,49 +13,44 @@ namespace js { -// Replacement for mozilla::UniquePtr that defaults to js::DefaultDelete. +// Replacement for mozilla::UniquePtr that defaults to JS::DeletePolicy. template > using UniquePtr = mozilla::UniquePtr; namespace detail { -template -struct UniqueSelector -{ +template +struct UniqueSelector { typedef UniquePtr SingleObject; }; -template -struct UniqueSelector -{ +template +struct UniqueSelector { typedef UniquePtr UnknownBound; }; -template -struct UniqueSelector -{ +template +struct UniqueSelector { typedef UniquePtr KnownBound; }; -} // namespace detail +} // namespace detail // Replacement for mozilla::MakeUnique that correctly calls js_new and produces // a js::UniquePtr. -template -typename detail::UniqueSelector::SingleObject -MakeUnique(Args&&... aArgs) -{ +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; +template +typename detail::UniqueSelector::UnknownBound MakeUnique( + decltype(sizeof(int)) aN) = delete; + +template +typename detail::UniqueSelector::KnownBound MakeUnique(Args&&... aArgs) = + delete; -} // namespace js +} // 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 @@ -15,6 +15,7 @@ #include "mozilla/Scoped.h" #include "mozilla/TemplateLib.h" #include "mozilla/UniquePtr.h" +#include "mozilla/WrappingOperations.h" #include #include @@ -26,6 +27,8 @@ #include "jstypes.h" +#include "mozmemory.h" + /* The public JS engine namespace. */ namespace JS {} @@ -35,65 +38,96 @@ /* The private JS engine namespace. */ namespace js {} -#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") - -extern MOZ_NORETURN MOZ_COLD JS_PUBLIC_API(void) -JS_Assert(const char* s, const char* file, int ln); +#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") + +extern MOZ_NORETURN MOZ_COLD JS_PUBLIC_API void JS_Assert(const char* s, + const char* file, + int ln); /* * Custom allocator support for SpiderMonkey */ #if defined JS_USE_CUSTOM_ALLOCATOR -# include "jscustomallocator.h" +#include "jscustomallocator.h" #else namespace js { -namespace oom { /* - * To make testing OOM in certain helper threads more effective, - * allow restricting the OOM testing to a certain helper thread - * type. This allows us to fail e.g. in off-thread script parsing - * without causing an OOM in the main thread first. + * Thread types are used to tag threads for certain kinds of testing (see + * below), and also used to characterize threads in the thread scheduler (see + * js/src/vm/HelperThreads.cpp). + * + * Please update oom::FirstThreadTypeToTest and oom::LastThreadTypeToTest when + * adding new thread types. */ enum ThreadType { - THREAD_TYPE_NONE = 0, // 0 - THREAD_TYPE_MAIN, // 1 - THREAD_TYPE_ASMJS, // 2 - THREAD_TYPE_ION, // 3 - THREAD_TYPE_PARSE, // 4 - 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 + THREAD_TYPE_NONE = 0, // 0 + THREAD_TYPE_COOPERATING, // 1 + THREAD_TYPE_WASM, // 2 + THREAD_TYPE_ION, // 3 + THREAD_TYPE_PARSE, // 4 + THREAD_TYPE_COMPRESS, // 5 + THREAD_TYPE_GCHELPER, // 6 + THREAD_TYPE_GCPARALLEL, // 7 + THREAD_TYPE_PROMISE_TASK, // 8 + THREAD_TYPE_ION_FREE, // 9 + THREAD_TYPE_WASM_TIER2, // 10 + THREAD_TYPE_WORKER, // 11 + THREAD_TYPE_MAX // Used to check shell function arguments }; +namespace oom { + /* - * Getter/Setter functions to encapsulate mozilla::ThreadLocal, - * implementation is in jsutil.cpp. + * Theads are tagged only in certain debug contexts. Notably, to make testing + * OOM in certain helper threads more effective, we allow restricting the OOM + * testing to a certain helper thread type. This allows us to fail e.g. in + * off-thread script parsing without causing an OOM in the active thread first. + * + * Getter/Setter functions to encapsulate mozilla::ThreadLocal, implementation + * is in jsutil.cpp. */ -# if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) +#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) + +// Define the range of threads tested by simulated OOM testing and the +// like. Testing worker threads is not supported. +const ThreadType FirstThreadTypeToTest = THREAD_TYPE_COOPERATING; +const ThreadType LastThreadTypeToTest = THREAD_TYPE_WASM_TIER2; + extern bool InitThreadType(void); extern void SetThreadType(ThreadType); -extern JS_FRIEND_API(uint32_t) GetThreadType(void); -# else +extern JS_FRIEND_API uint32_t GetThreadType(void); + +#else + inline bool InitThreadType(void) { return true; } -inline void SetThreadType(ThreadType t) {}; +inline void SetThreadType(ThreadType t){}; inline uint32_t GetThreadType(void) { return 0; } -# endif + +#endif } /* namespace oom */ } /* namespace js */ -# if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) +#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) #ifdef JS_OOM_BREAKPOINT +#if defined(_MSC_VER) +static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { + __asm {} + ; +} +#else static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); } +#endif #define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint() #else -#define JS_OOM_CALL_BP_FUNC() do {} while(0) +#define JS_OOM_CALL_BP_FUNC() \ + do { \ + } while (0) #endif namespace js { @@ -104,68 +138,171 @@ * 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; - -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(); -} - -inline bool -IsSimulatedOOMAllocation() -{ - return IsThreadSimulatingOOM() && - (counter == maxAllocations || (counter > maxAllocations && failAlways)); -} - -inline bool -ShouldFailWithOOM() -{ - if (!IsThreadSimulatingOOM()) - return false; - - counter++; - if (IsSimulatedOOMAllocation()) { - JS_OOM_CALL_BP_FUNC(); - return true; - } - return false; +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; + +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(); +} + +inline bool IsSimulatedOOMAllocation() { + return IsThreadSimulatingOOM() && (counter == maxAllocations || + (counter > maxAllocations && failAlways)); +} + +inline bool ShouldFailWithOOM() { + if (!IsThreadSimulatingOOM()) return false; + + counter++; + if (IsSimulatedOOMAllocation()) { + JS_OOM_CALL_BP_FUNC(); + return true; + } + return false; +} + +inline bool HadSimulatedOOM() { return counter >= maxAllocations; } + +/* + * Out of stack space testing support, similar to OOM testing functions. + */ + +extern JS_PUBLIC_DATA uint32_t stackTargetThread; +extern JS_PUBLIC_DATA uint64_t maxStackChecks; +extern JS_PUBLIC_DATA uint64_t stackCheckCounter; +extern JS_PUBLIC_DATA bool stackCheckFailAlways; + +extern void SimulateStackOOMAfter(uint64_t checks, uint32_t thread, + bool always); + +extern void ResetSimulatedStackOOM(); + +inline bool IsThreadSimulatingStackOOM() { + return js::oom::stackTargetThread && + js::oom::stackTargetThread == js::oom::GetThreadType(); +} + +inline bool IsSimulatedStackOOMCheck() { + return IsThreadSimulatingStackOOM() && + (stackCheckCounter == maxStackChecks || + (stackCheckCounter > maxStackChecks && stackCheckFailAlways)); } -inline bool -HadSimulatedOOM() { - return counter >= maxAllocations; +inline bool ShouldFailWithStackOOM() { + if (!IsThreadSimulatingStackOOM()) return false; + + stackCheckCounter++; + if (IsSimulatedStackOOMCheck()) { + JS_OOM_CALL_BP_FUNC(); + return true; + } + return false; +} + +inline bool HadSimulatedStackOOM() { + return stackCheckCounter >= maxStackChecks; +} + +/* + * Interrupt testing support, similar to OOM testing functions. + */ + +extern JS_PUBLIC_DATA uint32_t interruptTargetThread; +extern JS_PUBLIC_DATA uint64_t maxInterruptChecks; +extern JS_PUBLIC_DATA uint64_t interruptCheckCounter; +extern JS_PUBLIC_DATA bool interruptCheckFailAlways; + +extern void SimulateInterruptAfter(uint64_t checks, uint32_t thread, + bool always); + +extern void ResetSimulatedInterrupt(); + +inline bool IsThreadSimulatingInterrupt() { + return js::oom::interruptTargetThread && + js::oom::interruptTargetThread == js::oom::GetThreadType(); +} + +inline bool IsSimulatedInterruptCheck() { + return IsThreadSimulatingInterrupt() && + (interruptCheckCounter == maxInterruptChecks || + (interruptCheckCounter > maxInterruptChecks && + interruptCheckFailAlways)); +} + +inline bool ShouldFailWithInterrupt() { + if (!IsThreadSimulatingInterrupt()) return false; + + interruptCheckCounter++; + if (IsSimulatedInterruptCheck()) { + JS_OOM_CALL_BP_FUNC(); + return true; + } + return false; +} + +inline bool HadSimulatedInterrupt() { + return interruptCheckCounter >= maxInterruptChecks; } } /* namespace oom */ } /* namespace js */ -# define JS_OOM_POSSIBLY_FAIL() \ - do { \ - if (js::oom::ShouldFailWithOOM()) \ - return nullptr; \ - } while (0) - -# define JS_OOM_POSSIBLY_FAIL_BOOL() \ - do { \ - if (js::oom::ShouldFailWithOOM()) \ - return false; \ - } while (0) +#define JS_OOM_POSSIBLY_FAIL() \ + do { \ + if (js::oom::ShouldFailWithOOM()) return nullptr; \ + } while (0) + +#define JS_OOM_POSSIBLY_FAIL_BOOL() \ + do { \ + if (js::oom::ShouldFailWithOOM()) return false; \ + } while (0) + +#define JS_STACK_OOM_POSSIBLY_FAIL() \ + do { \ + if (js::oom::ShouldFailWithStackOOM()) return false; \ + } while (0) + +#define JS_STACK_OOM_POSSIBLY_FAIL_REPORT() \ + do { \ + if (js::oom::ShouldFailWithStackOOM()) { \ + ReportOverRecursed(cx); \ + return false; \ + } \ + } while (0) + +#define JS_INTERRUPT_POSSIBLY_FAIL() \ + do { \ + if (MOZ_UNLIKELY(js::oom::ShouldFailWithInterrupt())) { \ + cx->interrupt_ = true; \ + return cx->handleInterrupt(); \ + } \ + } while (0) -# else +#else -# define JS_OOM_POSSIBLY_FAIL() do {} while(0) -# define JS_OOM_POSSIBLY_FAIL_BOOL() do {} while(0) +#define JS_OOM_POSSIBLY_FAIL() \ + do { \ + } while (0) +#define JS_OOM_POSSIBLY_FAIL_BOOL() \ + do { \ + } while (0) +#define JS_STACK_OOM_POSSIBLY_FAIL() \ + do { \ + } while (0) +#define JS_STACK_OOM_POSSIBLY_FAIL_REPORT() \ + do { \ + } while (0) +#define JS_INTERRUPT_POSSIBLY_FAIL() \ + do { \ + } while (0) namespace js { namespace oom { static inline bool IsSimulatedOOMAllocation() { return false; } @@ -173,96 +310,102 @@ } /* namespace oom */ } /* namespace js */ -# endif /* DEBUG || JS_OOM_BREAKPOINT */ +#endif /* DEBUG || JS_OOM_BREAKPOINT */ namespace js { /* Disable OOM testing in sections which are not OOM safe. */ -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; - } +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 != UINT64_MAX), - oomAfter_(0) - { - if (oomEnabled_) { - MOZ_ALWAYS_TRUE(owner_.compareExchange(nullptr, this)); - oomAfter_ = int64_t(oom::maxAllocations) - int64_t(oom::counter); - oom::maxAllocations = UINT64_MAX; - } + AutoEnterOOMUnsafeRegion() + : oomEnabled_(oom::IsThreadSimulatingOOM() && + oom::maxAllocations != UINT64_MAX), + oomAfter_(0) { + if (oomEnabled_) { + 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 == 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 = uint64_t(maxAllocations); - MOZ_ALWAYS_TRUE(owner_.compareExchange(this, nullptr)); - } + ~AutoEnterOOMUnsafeRegion() { + if (oomEnabled_) { + 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 = uint64_t(maxAllocations); + MOZ_ALWAYS_TRUE(owner_.compareExchange(this, nullptr)); } + } - private: - // Used to catch concurrent use from other threads. - static mozilla::Atomic owner_; + private: + // Used to catch concurrent use from other threads. + static mozilla::Atomic owner_; - bool oomEnabled_; - int64_t oomAfter_; + bool oomEnabled_; + int64_t oomAfter_; #endif }; } /* namespace js */ -static inline void* js_malloc(size_t bytes) -{ - JS_OOM_POSSIBLY_FAIL(); - return malloc(bytes); +// Malloc allocation. + +namespace js { + +extern JS_PUBLIC_DATA arena_id_t MallocArena; + +extern void InitMallocAllocator(); +extern void ShutDownMallocAllocator(); + +} /* namespace js */ + +static inline void* js_malloc(size_t bytes) { + JS_OOM_POSSIBLY_FAIL(); + return moz_arena_malloc(js::MallocArena, bytes); } -static inline void* js_calloc(size_t bytes) -{ - JS_OOM_POSSIBLY_FAIL(); - return calloc(bytes, 1); +static inline void* js_calloc(size_t bytes) { + JS_OOM_POSSIBLY_FAIL(); + return moz_arena_calloc(js::MallocArena, bytes, 1); } -static inline void* js_calloc(size_t nmemb, size_t size) -{ - JS_OOM_POSSIBLY_FAIL(); - return calloc(nmemb, size); +static inline void* js_calloc(size_t nmemb, size_t size) { + JS_OOM_POSSIBLY_FAIL(); + return moz_arena_calloc(js::MallocArena, nmemb, size); } -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); +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); + JS_OOM_POSSIBLY_FAIL(); + return moz_arena_realloc(js::MallocArena, p, bytes); } -static inline void js_free(void* p) -{ - free(p); +static inline void js_free(void* p) { + // TODO: This should call |moz_arena_free(js::MallocArena, p)| but we + // currently can't enforce that all memory freed here was allocated by + // js_malloc(). + free(p); } -static inline char* js_strdup(const char* s) -{ - JS_OOM_POSSIBLY_FAIL(); - return strdup(s); -} -#endif/* JS_USE_CUSTOM_ALLOCATOR */ +JS_PUBLIC_API char* js_strdup(const char* s); +#endif /* JS_USE_CUSTOM_ALLOCATOR */ #include @@ -315,15 +458,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) \ - template \ - QUALIFIERS T * \ - NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \ - void* memory = ALLOCATOR(sizeof(T)); \ - return MOZ_LIKELY(memory) \ - ? new(memory) T(mozilla::Forward(args)...) \ - : nullptr; \ - } +#define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \ + template \ + QUALIFIERS T* NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \ + void* memory = ALLOCATOR(sizeof(T)); \ + return MOZ_LIKELY(memory) ? new (memory) \ + T(mozilla::Forward(args)...) \ + : nullptr; \ + } /* * Given a class which should provide 'make' methods, add @@ -335,13 +477,13 @@ * Note: Do not add a ; at the end of a use of JS_DECLARE_MAKE_METHODS, * or the build will break. */ -#define JS_DECLARE_MAKE_METHODS(MAKENAME, NEWNAME, QUALIFIERS)\ - template \ - QUALIFIERS mozilla::UniquePtr> \ - MAKENAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \ - T* ptr = NEWNAME(mozilla::Forward(args)...); \ - return mozilla::UniquePtr>(ptr); \ - } +#define JS_DECLARE_MAKE_METHODS(MAKENAME, NEWNAME, QUALIFIERS) \ + template \ + QUALIFIERS mozilla::UniquePtr> MAKENAME( \ + Args&&... args) MOZ_HEAP_ALLOCATOR { \ + T* ptr = NEWNAME(mozilla::Forward(args)...); \ + return mozilla::UniquePtr>(ptr); \ + } JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE) @@ -352,11 +494,9 @@ * instances of type |T|. Return false if the calculation overflowed. */ template -MOZ_MUST_USE inline bool -CalculateAllocSize(size_t numElems, size_t* bytesOut) -{ - *bytesOut = numElems * sizeof(T); - return (numElems & mozilla::tl::MulOverflowMask::value) == 0; +MOZ_MUST_USE inline bool CalculateAllocSize(size_t numElems, size_t* bytesOut) { + *bytesOut = numElems * sizeof(T); + return (numElems & mozilla::tl::MulOverflowMask::value) == 0; } /* @@ -365,104 +505,88 @@ * false if the calculation overflowed. */ template -MOZ_MUST_USE inline bool -CalculateAllocSizeWithExtra(size_t numExtra, size_t* bytesOut) -{ - *bytesOut = sizeof(T) + numExtra * sizeof(Extra); - return (numExtra & mozilla::tl::MulOverflowMask::value) == 0 && - *bytesOut >= sizeof(T); +MOZ_MUST_USE inline bool CalculateAllocSizeWithExtra(size_t numExtra, + size_t* bytesOut) { + *bytesOut = sizeof(T) + numExtra * sizeof(Extra); + return (numExtra & mozilla::tl::MulOverflowMask::value) == 0 && + *bytesOut >= sizeof(T); } } /* namespace js */ template -static MOZ_ALWAYS_INLINE void -js_delete(const T* p) -{ - if (p) { - p->~T(); - js_free(const_cast(p)); - } +static MOZ_ALWAYS_INLINE void js_delete(const T* p) { + if (p) { + p->~T(); + js_free(const_cast(p)); + } } -template -static MOZ_ALWAYS_INLINE void -js_delete_poison(const T* p) -{ - if (p) { - p->~T(); - memset(const_cast(p), 0x3B, sizeof(T)); - js_free(const_cast(p)); - } +template +static MOZ_ALWAYS_INLINE void js_delete_poison(const T* p) { + if (p) { + p->~T(); + memset(const_cast(p), 0x3B, sizeof(T)); + js_free(const_cast(p)); + } } template -static MOZ_ALWAYS_INLINE T* -js_pod_malloc() -{ - return static_cast(js_malloc(sizeof(T))); +static MOZ_ALWAYS_INLINE T* js_pod_malloc() { + return static_cast(js_malloc(sizeof(T))); } template -static MOZ_ALWAYS_INLINE T* -js_pod_calloc() -{ - return static_cast(js_calloc(sizeof(T))); +static MOZ_ALWAYS_INLINE T* js_pod_calloc() { + return static_cast(js_calloc(sizeof(T))); } template -static MOZ_ALWAYS_INLINE T* -js_pod_malloc(size_t numElems) -{ - size_t bytes; - if (MOZ_UNLIKELY(!js::CalculateAllocSize(numElems, &bytes))) - return nullptr; - return static_cast(js_malloc(bytes)); +static MOZ_ALWAYS_INLINE T* js_pod_malloc(size_t numElems) { + size_t bytes; + if (MOZ_UNLIKELY(!js::CalculateAllocSize(numElems, &bytes))) + return nullptr; + return static_cast(js_malloc(bytes)); } template -static MOZ_ALWAYS_INLINE T* -js_pod_calloc(size_t numElems) -{ - size_t bytes; - if (MOZ_UNLIKELY(!js::CalculateAllocSize(numElems, &bytes))) - return nullptr; - return static_cast(js_calloc(bytes)); +static MOZ_ALWAYS_INLINE T* js_pod_calloc(size_t numElems) { + size_t bytes; + if (MOZ_UNLIKELY(!js::CalculateAllocSize(numElems, &bytes))) + return nullptr; + return static_cast(js_calloc(bytes)); } template -static MOZ_ALWAYS_INLINE T* -js_pod_realloc(T* prior, size_t oldSize, size_t newSize) -{ - MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask::value)); - size_t bytes; - if (MOZ_UNLIKELY(!js::CalculateAllocSize(newSize, &bytes))) - return nullptr; - return static_cast(js_realloc(prior, bytes)); +static MOZ_ALWAYS_INLINE T* js_pod_realloc(T* prior, size_t oldSize, + size_t newSize) { + MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask::value)); + size_t bytes; + if (MOZ_UNLIKELY(!js::CalculateAllocSize(newSize, &bytes))) return nullptr; + return static_cast(js_realloc(prior, bytes)); } namespace js { -template -struct ScopedFreePtrTraits -{ - typedef T* type; - static T* empty() { return nullptr; } - static void release(T* ptr) { js_free(ptr); } +template +struct ScopedFreePtrTraits { + typedef T* type; + static T* empty() { return nullptr; } + static void release(T* ptr) { js_free(ptr); } }; SCOPED_TEMPLATE(ScopedJSFreePtr, ScopedFreePtrTraits) template -struct ScopedDeletePtrTraits : public ScopedFreePtrTraits -{ - static void release(T* ptr) { js_delete(ptr); } +struct ScopedDeletePtrTraits : public ScopedFreePtrTraits { + static void release(T* ptr) { js_delete(ptr); } }; SCOPED_TEMPLATE(ScopedJSDeletePtr, ScopedDeletePtrTraits) template -struct ScopedReleasePtrTraits : public ScopedFreePtrTraits -{ - static void release(T* ptr) { if (ptr) ptr->release(); } +struct ScopedReleasePtrTraits : public ScopedFreePtrTraits { + static void release(T* ptr) { + if (ptr) ptr->release(); + } }; SCOPED_TEMPLATE(ScopedReleasePtr, ScopedReleasePtrTraits) @@ -470,33 +594,27 @@ namespace JS { -template -struct DeletePolicy -{ - constexpr DeletePolicy() {} - - template - MOZ_IMPLICIT DeletePolicy(DeletePolicy other, - typename mozilla::EnableIf::value, - int>::Type dummy = 0) - {} +template +struct DeletePolicy { + constexpr DeletePolicy() {} - void operator()(const T* ptr) { - js_delete(const_cast(ptr)); - } + template + MOZ_IMPLICIT DeletePolicy( + DeletePolicy other, + typename mozilla::EnableIf::value, + int>::Type dummy = 0) {} + + void operator()(const T* ptr) { js_delete(const_cast(ptr)); } }; -struct FreePolicy -{ - void operator()(const void* ptr) { - js_free(const_cast(ptr)); - } +struct FreePolicy { + void operator()(const void* ptr) { js_free(const_cast(ptr)); } }; typedef mozilla::UniquePtr UniqueChars; typedef mozilla::UniquePtr UniqueTwoByteChars; -} // namespace JS +} // namespace JS namespace js { @@ -521,26 +639,24 @@ * * FIXME: OrderedHashTable uses a bit-mask; see bug 775896. */ -inline HashNumber -ScrambleHashCode(HashNumber h) -{ - /* - * Simply returning h would not cause any hash tables to produce wrong - * answers. But it can produce pathologically bad performance: The caller - * right-shifts the result, keeping only the highest bits. The high bits of - * hash codes are very often completely entropy-free. (So are the lowest - * bits.) - * - * So we use Fibonacci hashing, as described in Knuth, The Art of Computer - * Programming, 6.4. This mixes all the bits of the input hash code h. - * - * The value of goldenRatio is taken from the hex - * expansion of the golden ratio, which starts 1.9E3779B9.... - * This value is especially good if values with consecutive hash codes - * are stored in a hash table; see Knuth for details. - */ - static const HashNumber goldenRatio = 0x9E3779B9U; - return h * goldenRatio; +inline HashNumber ScrambleHashCode(HashNumber h) { + /* + * Simply returning h would not cause any hash tables to produce wrong + * answers. But it can produce pathologically bad performance: The caller + * right-shifts the result, keeping only the highest bits. The high bits of + * hash codes are very often completely entropy-free. (So are the lowest + * bits.) + * + * So we use Fibonacci hashing, as described in Knuth, The Art of Computer + * Programming, 6.4. This mixes all the bits of the input hash code h. + * + * The value of goldenRatio is taken from the hex + * expansion of the golden ratio, which starts 1.9E3779B9.... + * This value is especially good if values with consecutive hash codes + * are stored in a hash table; see Knuth for details. + */ + static const HashNumber goldenRatio = 0x9E3779B9U; + return mozilla::WrappingMultiply(h, goldenRatio); } } /* namespace detail */ @@ -549,29 +665,33 @@ /* sixgill annotation defines */ #ifndef HAVE_STATIC_ANNOTATIONS -# define HAVE_STATIC_ANNOTATIONS -# ifdef XGILL_PLUGIN -# define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND))) -# define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND))) -# define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND))) -# define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND))) -# define STATIC_INVARIANT(COND) __attribute__((invariant(#COND))) -# define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND))) -# define STATIC_ASSUME(COND) \ - JS_BEGIN_MACRO \ - __attribute__((assume_static(#COND), unused)) \ - int STATIC_PASTE1(assume_static_, __COUNTER__); \ +#define HAVE_STATIC_ANNOTATIONS +#ifdef XGILL_PLUGIN +#define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND))) +#define STATIC_PRECONDITION_ASSUME(COND) \ + __attribute__((precondition_assume(#COND))) +#define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND))) +#define STATIC_POSTCONDITION_ASSUME(COND) \ + __attribute__((postcondition_assume(#COND))) +#define STATIC_INVARIANT(COND) __attribute__((invariant(#COND))) +#define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND))) +#define STATIC_ASSUME(COND) \ + JS_BEGIN_MACRO \ + __attribute__((assume_static(#COND), unused)) int STATIC_PASTE1( \ + assume_static_, __COUNTER__); \ + JS_END_MACRO +#else /* XGILL_PLUGIN */ +#define STATIC_PRECONDITION(COND) /* nothing */ +#define STATIC_PRECONDITION_ASSUME(COND) /* nothing */ +#define STATIC_POSTCONDITION(COND) /* nothing */ +#define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */ +#define STATIC_INVARIANT(COND) /* nothing */ +#define STATIC_INVARIANT_ASSUME(COND) /* nothing */ +#define STATIC_ASSUME(COND) \ + JS_BEGIN_MACRO /* nothing */ \ JS_END_MACRO -# else /* XGILL_PLUGIN */ -# define STATIC_PRECONDITION(COND) /* nothing */ -# define STATIC_PRECONDITION_ASSUME(COND) /* nothing */ -# define STATIC_POSTCONDITION(COND) /* nothing */ -# define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */ -# define STATIC_INVARIANT(COND) /* nothing */ -# define STATIC_INVARIANT_ASSUME(COND) /* nothing */ -# define STATIC_ASSUME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO -# endif /* XGILL_PLUGIN */ -# define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference()) +#endif /* XGILL_PLUGIN */ +#define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference()) #endif /* HAVE_STATIC_ANNOTATIONS */ #endif /* js_Utility_h */ 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 @@ -11,6 +11,7 @@ #include "mozilla/Attributes.h" #include "mozilla/Casting.h" +#include "mozilla/EndianUtils.h" #include "mozilla/FloatingPoint.h" #include "mozilla/Likely.h" @@ -23,103 +24,101 @@ #include "js/RootingAPI.h" #include "js/Utility.h" -namespace JS { class Value; } +namespace JS { +class Value; +} /* JS::Value can store a full int32_t. */ -#define JSVAL_INT_BITS 32 -#define JSVAL_INT_MIN ((int32_t)0x80000000) -#define JSVAL_INT_MAX ((int32_t)0x7fffffff) +#define JSVAL_INT_BITS 32 +#define JSVAL_INT_MIN ((int32_t)0x80000000) +#define JSVAL_INT_MAX ((int32_t)0x7fffffff) #if defined(JS_PUNBOX64) -# define JSVAL_TAG_SHIFT 47 +#define JSVAL_TAG_SHIFT 47 #endif // 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 -# define JS_ENUM_FOOTER(id) +#define JS_ENUM_HEADER(id, type) enum id : type +#define JS_ENUM_FOOTER(id) #else -# define JS_ENUM_HEADER(id, type) enum id -# define JS_ENUM_FOOTER(id) __attribute__((packed)) +#define JS_ENUM_HEADER(id, type) enum id +#define JS_ENUM_FOOTER(id) __attribute__((packed)) #endif -/* Remember to propagate changes to the C defines below. */ -JS_ENUM_HEADER(JSValueType, uint8_t) -{ - JSVAL_TYPE_DOUBLE = 0x00, - JSVAL_TYPE_INT32 = 0x01, - JSVAL_TYPE_UNDEFINED = 0x02, - JSVAL_TYPE_BOOLEAN = 0x03, - JSVAL_TYPE_MAGIC = 0x04, - JSVAL_TYPE_STRING = 0x05, - JSVAL_TYPE_SYMBOL = 0x06, - 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, - JSVAL_TYPE_MISSING = 0x21 -} JS_ENUM_FOOTER(JSValueType); +JS_ENUM_HEADER(JSValueType, uint8_t){ + JSVAL_TYPE_DOUBLE = 0x00, JSVAL_TYPE_INT32 = 0x01, + JSVAL_TYPE_BOOLEAN = 0x02, JSVAL_TYPE_UNDEFINED = 0x03, + JSVAL_TYPE_NULL = 0x04, JSVAL_TYPE_MAGIC = 0x05, JSVAL_TYPE_STRING = 0x06, + JSVAL_TYPE_SYMBOL = 0x07, JSVAL_TYPE_PRIVATE_GCTHING = 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, + JSVAL_TYPE_MISSING = 0x21} JS_ENUM_FOOTER(JSValueType); static_assert(sizeof(JSValueType) == 1, "compiler typed enum support is apparently buggy"); #if defined(JS_NUNBOX32) -/* Remember to propagate changes to the C defines below. */ -JS_ENUM_HEADER(JSValueTag, uint32_t) -{ - JSVAL_TAG_CLEAR = 0xFFFFFF80, - JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32, - JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED, - JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING, - JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL, - 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_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING -} JS_ENUM_FOOTER(JSValueTag); +JS_ENUM_HEADER(JSValueTag, uint32_t){ + JSVAL_TAG_CLEAR = 0xFFFFFF80, + JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32, + JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED, + JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL, + JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN, + JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC, + JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING, + JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL, + JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING, + JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | + JSVAL_TYPE_OBJECT} JS_ENUM_FOOTER(JSValueTag); static_assert(sizeof(JSValueTag) == sizeof(uint32_t), "compiler typed enum support is apparently buggy"); #elif defined(JS_PUNBOX64) -/* Remember to propagate changes to the C defines below. */ -JS_ENUM_HEADER(JSValueTag, uint32_t) -{ - JSVAL_TAG_MAX_DOUBLE = 0x1FFF0, - JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32, - JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED, - JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING, - JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL, - 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_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING -} JS_ENUM_FOOTER(JSValueTag); +JS_ENUM_HEADER(JSValueTag, uint32_t){ + JSVAL_TAG_MAX_DOUBLE = 0x1FFF0, + JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32, + JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED, + JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL, + JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN, + JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC, + JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING, + JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL, + JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | + JSVAL_TYPE_PRIVATE_GCTHING, + JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | + JSVAL_TYPE_OBJECT} JS_ENUM_FOOTER(JSValueTag); static_assert(sizeof(JSValueTag) == sizeof(uint32_t), "compiler typed enum support is apparently buggy"); -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_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT) -} JS_ENUM_FOOTER(JSValueShiftedTag); +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_NULL = (((uint64_t)JSVAL_TAG_NULL) << 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_STRING = (((uint64_t)JSVAL_TAG_STRING) + << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) + << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) + << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_OBJECT = + (((uint64_t)JSVAL_TAG_OBJECT) + << JSVAL_TAG_SHIFT)} JS_ENUM_FOOTER(JSValueShiftedTag); static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t), "compiler typed enum support is apparently buggy"); @@ -138,96 +137,109 @@ #if defined(JS_NUNBOX32) -#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) +#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) -#define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << 32) +#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 -#define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING +#define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT +#define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 +#define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING #elif defined(JS_PUNBOX64) -#define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) +#define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) + +// This should only be used in toGCThing, see the 'Spectre mitigations' comment. +#define JSVAL_PAYLOAD_MASK_GCTHING 0x00007FFFFFFFFFFFLL + +#define JSVAL_TAG_MASK 0xFFFF800000000000LL +#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type))) +#define JSVAL_TYPE_TO_SHIFTED_TAG(type) \ + (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << 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))) -#define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT) +#define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT +#define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 +#define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING -#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 -#define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING +#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT +#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_BOOLEAN +#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING -#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET JSVAL_SHIFTED_TAG_NULL -#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT -#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED -#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING +// JSVAL_TYPE_OBJECT and JSVAL_TYPE_NULL differ by one bit. We can use this to +// implement toObjectOrNull more efficiently. +#define JSVAL_OBJECT_OR_NULL_BIT (uint64_t(0x8) << JSVAL_TAG_SHIFT) +static_assert( + (JSVAL_SHIFTED_TAG_NULL ^ JSVAL_SHIFTED_TAG_OBJECT) == + JSVAL_OBJECT_OR_NULL_BIT, + "JSVAL_OBJECT_OR_NULL_BIT must be consistent with object and null tags"); #endif /* JS_PUNBOX64 */ -typedef enum JSWhyMagic -{ - /** a hole in a native object's elements */ - JS_ELEMENTS_HOLE, +typedef enum JSWhyMagic { + /** a hole in a native object's elements */ + JS_ELEMENTS_HOLE, - /** there is not a pending iterator value */ - JS_NO_ITER_VALUE, + /** there is not a pending iterator value */ + JS_NO_ITER_VALUE, - /** exception value thrown when closing a generator */ - JS_GENERATOR_CLOSING, + /** exception value thrown when closing a generator */ + JS_GENERATOR_CLOSING, - /** compiler sentinel value */ - JS_NO_CONSTANT, + /** compiler sentinel value */ + JS_NO_CONSTANT, - /** used in debug builds to catch tracing errors */ - JS_THIS_POISON, + /** used in debug builds to catch tracing errors */ + JS_THIS_POISON, - /** used in debug builds to catch tracing errors */ - JS_ARG_POISON, + /** used in debug builds to catch tracing errors */ + JS_ARG_POISON, - /** an empty subnode in the AST serializer */ - JS_SERIALIZE_NO_NODE, + /** an empty subnode in the AST serializer */ + JS_SERIALIZE_NO_NODE, - /** lazy arguments value on the stack */ - JS_LAZY_ARGUMENTS, + /** lazy arguments value on the stack */ + JS_LAZY_ARGUMENTS, - /** optimized-away 'arguments' value */ - JS_OPTIMIZED_ARGUMENTS, + /** optimized-away 'arguments' value */ + JS_OPTIMIZED_ARGUMENTS, - /** magic value passed to natives to indicate construction */ - JS_IS_CONSTRUCTING, + /** magic value passed to natives to indicate construction */ + JS_IS_CONSTRUCTING, - /** value of static block object slot */ - JS_BLOCK_NEEDS_CLONE, + /** value of static block object slot */ + JS_BLOCK_NEEDS_CLONE, - /** see class js::HashableValue */ - JS_HASH_KEY_EMPTY, + /** see class js::HashableValue */ + JS_HASH_KEY_EMPTY, - /** error while running Ion code */ - JS_ION_ERROR, + /** error while running Ion code */ + JS_ION_ERROR, - /** missing recover instruction result */ - JS_ION_BAILOUT, + /** missing recover instruction result */ + JS_ION_BAILOUT, - /** optimized out slot */ - JS_OPTIMIZED_OUT, + /** optimized out slot */ + JS_OPTIMIZED_OUT, - /** uninitialized lexical bindings that produce ReferenceError on touch. */ - JS_UNINITIALIZED_LEXICAL, + /** uninitialized lexical bindings that produce ReferenceError on touch. */ + JS_UNINITIALIZED_LEXICAL, - /** for local use */ - JS_GENERIC_MAGIC, + /** standard constructors are not created for off-thread parsing. */ + JS_OFF_THREAD_CONSTRUCTOR, - JS_WHY_MAGIC_COUNT + /** for local use */ + JS_GENERIC_MAGIC, + + JS_WHY_MAGIC_COUNT } JSWhyMagic; +namespace js { +static inline JS::Value PoisonedObjectValue(uintptr_t poison); +} // namespace js + namespace JS { static inline constexpr JS::Value UndefinedValue(); -static inline JS::Value PoisonedObjectValue(JSObject* obj); namespace detail { @@ -235,11 +247,10 @@ constexpr uint64_t CanonicalizedNaNSignificand = 0x8000000000000ULL; constexpr uint64_t CanonicalizedNaNBits = - mozilla::SpecificNaNBits::value; -} // namespace detail +} // namespace detail /** * Returns a generic quiet NaN value, with all payload bits set to zero. @@ -247,26 +258,21 @@ * Among other properties, this NaN's bit pattern conforms to JS::Value's * bit pattern restrictions. */ -static MOZ_ALWAYS_INLINE double -GenericNaN() -{ +static MOZ_ALWAYS_INLINE double GenericNaN() { return mozilla::SpecificNaN(detail::CanonicalizedNaNSignBit, detail::CanonicalizedNaNSignificand); } /* MSVC with PGO miscompiles this function. */ #if defined(_MSC_VER) -# pragma optimize("g", off) +#pragma optimize("g", off) #endif -static inline double -CanonicalizeNaN(double d) -{ - if (MOZ_UNLIKELY(mozilla::IsNaN(d))) - return GenericNaN(); - return d; +static inline double CanonicalizeNaN(double d) { + if (MOZ_UNLIKELY(mozilla::IsNaN(d))) return GenericNaN(); + return d; } #if defined(_MSC_VER) -# pragma optimize("", on) +#pragma optimize("", on) #endif /** @@ -275,16 +281,17 @@ * * - JS::Value has setX() and isX() members for X in * - * { Int32, Double, String, Symbol, Boolean, Undefined, Null, Object, Magic } + * { Int32, Double, String, Symbol, Boolean, Undefined, Null, + * Object, Magic } * * JS::Value also contains toX() for each of the non-singleton types. * - * - Magic is a singleton type whose payload contains either a JSWhyMagic "reason" for - * the magic value or a uint32_t value. By providing JSWhyMagic values when - * creating and checking for magic values, it is possible to assert, at - * runtime, that only magic values with the expected reason flow through a - * particular value. For example, if cx->exception has a magic value, the - * reason must be JS_GENERATOR_CLOSING. + * - Magic is a singleton type whose payload contains either a JSWhyMagic + * "reason" for the magic value or a uint32_t value. By providing JSWhyMagic + * values when creating and checking for magic values, it is possible to + * assert, at runtime, that only magic values with the expected reason flow + * through a particular value. For example, if cx->exception has a magic + * value, the reason must be JS_GENERATOR_CLOSING. * * - The JS::Value operations are preferred. The JSVAL_* operations remain for * compatibility; they may be removed at some point. These operations mostly @@ -294,1263 +301,1180 @@ * Value::setObject takes a JSObject&. (Conversely, Value::toObject returns a * JSObject&.) A convenience member Value::setObjectOrNull is provided. * - * - JSVAL_VOID is the same as the singleton value of the Undefined type. - * * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on * 32-bit user code should avoid copying jsval/JS::Value as much as possible, * preferring to pass by const Value&. + * + * Spectre mitigations + * =================== + * To mitigate Spectre attacks, we do the following: + * + * - On 64-bit platforms, when unboxing a Value, we XOR the bits with the + * expected type tag (instead of masking the payload bits). This guarantees + * that toString, toObject, toSymbol will return an invalid pointer (because + * some high bits will be set) when called on a Value with a different type + * tag. + * + * - On 32-bit platforms,when unboxing an object/string/symbol Value, we use a + * conditional move (not speculated) to zero the payload register if the type + * doesn't match. */ -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. - */ - Value() = default; - Value(const Value& v) = default; - - /** - * Returns false if creating a NumberValue containing the given type would - * be lossy, true otherwise. - */ - template - static bool isNumberRepresentable(const T t) { - return T(double(t)) == t; - } - - /*** Mutators ***/ - - void setNull() { - data.asBits = bitsFromTagAndPayload(JSVAL_TAG_NULL, 0); - } - - void setUndefined() { - data.asBits = bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0); - } - - void setInt32(int32_t i) { - data.asBits = bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i)); - } - - int32_t& getInt32Ref() { - MOZ_ASSERT(isInt32()); - return data.s.payload.i32; - } - - void setDouble(double 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() { - setDouble(GenericNaN()); - } - - double& getDoubleRef() { - MOZ_ASSERT(isDouble()); - return data.asDouble; - } - - void setString(JSString* str) { - MOZ_ASSERT(uintptr_t(str) > 0x1000); - data.asBits = bitsFromTagAndPayload(JSVAL_TAG_STRING, PayloadType(str)); - } - - void setSymbol(JS::Symbol* sym) { - MOZ_ASSERT(uintptr_t(sym) > 0x1000); - data.asBits = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym)); - } - - void setObject(JSObject& 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); +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 - 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.asBits = bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(b)); - } - - void setMagic(JSWhyMagic why) { - data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, uint32_t(why)); - } + /* + * N.B. the default constructor leaves Value unitialized. Adding a default + * constructor prevents Value from being stored in a union. + */ + Value() = default; + Value(const Value& v) = default; + + /** + * Returns false if creating a NumberValue containing the given type would + * be lossy, true otherwise. + */ + template + static bool isNumberRepresentable(const T t) { + return T(double(t)) == t; + } + + /*** Mutators ***/ + + void setNull() { data.asBits = bitsFromTagAndPayload(JSVAL_TAG_NULL, 0); } + + void setUndefined() { + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0); + } + + void setInt32(int32_t i) { + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i)); + } + + int32_t& getInt32Ref() { + MOZ_ASSERT(isInt32()); + return data.s.payload.i32; + } + + void setDouble(double 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() { setDouble(GenericNaN()); } + + double& getDoubleRef() { + MOZ_ASSERT(isDouble()); + return data.asDouble; + } + + void setString(JSString* str) { + MOZ_ASSERT(js::gc::IsCellPointerValid(str)); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_STRING, PayloadType(str)); + } + + void setSymbol(JS::Symbol* sym) { + MOZ_ASSERT(js::gc::IsCellPointerValid(sym)); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym)); + } + + void setObject(JSObject& obj) { + MOZ_ASSERT(js::gc::IsCellPointerValid(&obj)); + + // This should not be possible and is undefined behavior, but some + // ObjectValue(nullptr) are sneaking in. Try to catch them here, if + // indeed they are going through this code. I tested gcc, and it at + // least will *not* elide the null check even though it would be + // permitted according to the spec. The temporary is necessary to + // prevent gcc from helpfully pointing out that this code makes no + // sense. +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + JSObject* testObj = &obj; + MOZ_DIAGNOSTIC_ASSERT(testObj != nullptr); +#endif - void setMagicUint32(uint32_t payload) { - data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, payload); +#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 js::PoisonedObjectValue(uintptr_t poison); + + public: + void setBoolean(bool b) { + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(b)); + } + + void setMagic(JSWhyMagic why) { + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, uint32_t(why)); + } + + void setMagicUint32(uint32_t payload) { + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, payload); + } + + bool setNumber(uint32_t ui) { + if (ui > JSVAL_INT_MAX) { + setDouble((double)ui); + return false; + } else { + setInt32((int32_t)ui); + return true; } + } - bool setNumber(uint32_t ui) { - if (ui > JSVAL_INT_MAX) { - setDouble((double)ui); - return false; - } else { - setInt32((int32_t)ui); - return true; - } + bool setNumber(double d) { + int32_t i; + if (mozilla::NumberIsInt32(d, &i)) { + setInt32(i); + return true; } - bool setNumber(double d) { - int32_t i; - if (mozilla::NumberIsInt32(d, &i)) { - setInt32(i); - return true; - } - - setDouble(d); - return false; - } + setDouble(d); + return false; + } - void setObjectOrNull(JSObject* arg) { - if (arg) - setObject(*arg); - else - setNull(); - } + void setObjectOrNull(JSObject* arg) { + if (arg) + setObject(*arg); + else + setNull(); + } - void swap(Value& rhs) { - uint64_t tmp = rhs.data.asBits; - rhs.data.asBits = data.asBits; - data.asBits = tmp; - } + void swap(Value& rhs) { + uint64_t tmp = rhs.data.asBits; + rhs.data.asBits = data.asBits; + data.asBits = tmp; + } - private: - JSValueTag toTag() const { + private: + JSValueTag toTag() const { #if defined(JS_NUNBOX32) - return data.s.tag; + return data.s.tag; #elif defined(JS_PUNBOX64) - return JSValueTag(data.asBits >> JSVAL_TAG_SHIFT); + return JSValueTag(data.asBits >> JSVAL_TAG_SHIFT); #endif - } + } - public: - /*** JIT-only interfaces to interact with and create raw Values ***/ + public: + /*** JIT-only interfaces to interact with and create raw Values ***/ #if defined(JS_NUNBOX32) - PayloadType toNunboxPayload() const { - return data.s.payload.i32; - } + PayloadType toNunboxPayload() const { + return static_cast(data.s.payload.i32); + } - JSValueTag toNunboxTag() const { - return data.s.tag; - } + JSValueTag toNunboxTag() const { return data.s.tag; } #elif defined(JS_PUNBOX64) - const void* bitsAsPunboxPointer() const { - return reinterpret_cast(data.asBits); - } + const void* bitsAsPunboxPointer() const { + return reinterpret_cast(data.asBits); + } #endif - /*** Value type queries ***/ + /*** 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. - */ + /* + * 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 { + bool isUndefined() const { #if defined(JS_NUNBOX32) - return toTag() == JSVAL_TAG_UNDEFINED; + return toTag() == JSVAL_TAG_UNDEFINED; #elif defined(JS_PUNBOX64) - return data.asBits == JSVAL_SHIFTED_TAG_UNDEFINED; + return data.asBits == JSVAL_SHIFTED_TAG_UNDEFINED; #endif - } + } - bool isNull() const { + bool isNull() const { #if defined(JS_NUNBOX32) - return toTag() == JSVAL_TAG_NULL; + return toTag() == JSVAL_TAG_NULL; #elif defined(JS_PUNBOX64) - return data.asBits == JSVAL_SHIFTED_TAG_NULL; + return data.asBits == JSVAL_SHIFTED_TAG_NULL; #endif - } + } - bool isNullOrUndefined() const { - return isNull() || isUndefined(); - } + bool isNullOrUndefined() const { return isNull() || isUndefined(); } - bool isInt32() const { - return toTag() == JSVAL_TAG_INT32; - } + bool isInt32() const { return toTag() == JSVAL_TAG_INT32; } - bool isInt32(int32_t i32) const { - return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i32)); - } + bool isInt32(int32_t i32) const { + return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i32)); + } - bool isDouble() const { + bool isDouble() const { #if defined(JS_NUNBOX32) - return uint32_t(toTag()) <= uint32_t(JSVAL_TAG_CLEAR); + return uint32_t(toTag()) <= uint32_t(JSVAL_TAG_CLEAR); #elif defined(JS_PUNBOX64) - return (data.asBits | mozilla::DoubleTypeTraits::kSignBit) <= JSVAL_SHIFTED_TAG_MAX_DOUBLE; + return (data.asBits | mozilla::DoubleTypeTraits::kSignBit) <= + JSVAL_SHIFTED_TAG_MAX_DOUBLE; #endif - } + } - bool isNumber() const { + bool isNumber() const { #if defined(JS_NUNBOX32) - MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR); - return uint32_t(toTag()) <= uint32_t(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET); + 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; + return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET; #endif - } + } - bool isString() const { - return toTag() == JSVAL_TAG_STRING; - } + bool isString() const { return toTag() == JSVAL_TAG_STRING; } - bool isSymbol() const { - return toTag() == JSVAL_TAG_SYMBOL; - } + bool isSymbol() const { return toTag() == JSVAL_TAG_SYMBOL; } - bool isObject() const { + bool isObject() const { #if defined(JS_NUNBOX32) - return toTag() == JSVAL_TAG_OBJECT; + 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; + MOZ_ASSERT((data.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); + return data.asBits >= JSVAL_SHIFTED_TAG_OBJECT; #endif - } + } - bool isPrimitive() const { + bool isPrimitive() const { #if defined(JS_NUNBOX32) - return uint32_t(toTag()) < uint32_t(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET); + 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; + return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET; #endif - } + } - bool isObjectOrNull() const { - 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 isObjectOrNull() const { return isObject() || isNull(); } - bool isGCThing() const { + bool isGCThing() const { #if defined(JS_NUNBOX32) - /* gcc sometimes generates signed < without explicit casts. */ - return uint32_t(toTag()) >= uint32_t(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET); + /* 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; + return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET; #endif - } + } - bool isBoolean() const { - return toTag() == JSVAL_TAG_BOOLEAN; - } + bool isBoolean() const { return toTag() == JSVAL_TAG_BOOLEAN; } - bool isTrue() const { - return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(true)); - } + bool isTrue() const { + return data.asBits == + bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(true)); + } - bool isFalse() const { - return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(false)); - } + bool isFalse() const { + return data.asBits == + bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(false)); + } - bool isMagic() const { - return toTag() == JSVAL_TAG_MAGIC; - } + bool isMagic() const { return toTag() == JSVAL_TAG_MAGIC; } - bool isMagic(JSWhyMagic why) const { - MOZ_ASSERT_IF(isMagic(), data.s.payload.why == why); - return isMagic(); + bool isMagic(JSWhyMagic why) const { + if (!isMagic()) { + return false; } + MOZ_RELEASE_ASSERT(data.s.payload.why == why); + return true; + } - bool isMarkable() const { - return isGCThing() && !isNull(); - } + JS::TraceKind traceKind() const { + MOZ_ASSERT(isGCThing()); + 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); + } - JS::TraceKind traceKind() const { - MOZ_ASSERT(isMarkable()); - 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 { + MOZ_ASSERT(isMagic()); + return data.s.payload.why; + } - JSWhyMagic whyMagic() const { - MOZ_ASSERT(isMagic()); - return data.s.payload.why; - } - - uint32_t magicUint32() const { - MOZ_ASSERT(isMagic()); - return data.s.payload.u32; - } + uint32_t magicUint32() const { + MOZ_ASSERT(isMagic()); + return data.s.payload.u32; + } - /*** Comparison ***/ + /*** Comparison ***/ - bool operator==(const Value& rhs) const { - return data.asBits == rhs.data.asBits; - } + bool operator==(const Value& rhs) const { + return data.asBits == rhs.data.asBits; + } - bool operator!=(const Value& rhs) const { - return data.asBits != rhs.data.asBits; - } + bool operator!=(const Value& rhs) const { + return data.asBits != rhs.data.asBits; + } - friend inline bool SameType(const Value& lhs, const Value& rhs); + friend inline bool SameType(const Value& lhs, const Value& rhs); - /*** Extract the value's typed payload ***/ + /*** Extract the value's typed payload ***/ - int32_t toInt32() const { - MOZ_ASSERT(isInt32()); + int32_t toInt32() const { + MOZ_ASSERT(isInt32()); #if defined(JS_NUNBOX32) - return data.s.payload.i32; + return data.s.payload.i32; #elif defined(JS_PUNBOX64) - return int32_t(data.asBits); + return int32_t(data.asBits); #endif - } + } - double toDouble() const { - MOZ_ASSERT(isDouble()); - return data.asDouble; - } + double toDouble() const { + MOZ_ASSERT(isDouble()); + return data.asDouble; + } - double toNumber() const { - MOZ_ASSERT(isNumber()); - return isDouble() ? toDouble() : double(toInt32()); - } + double toNumber() const { + MOZ_ASSERT(isNumber()); + return isDouble() ? toDouble() : double(toInt32()); + } - JSString* toString() const { - MOZ_ASSERT(isString()); + JSString* toString() const { + MOZ_ASSERT(isString()); #if defined(JS_NUNBOX32) - return data.s.payload.str; + return data.s.payload.str; #elif defined(JS_PUNBOX64) - return reinterpret_cast(data.asBits & JSVAL_PAYLOAD_MASK); + return reinterpret_cast(data.asBits ^ JSVAL_SHIFTED_TAG_STRING); #endif - } + } - JS::Symbol* toSymbol() const { - MOZ_ASSERT(isSymbol()); + JS::Symbol* toSymbol() const { + MOZ_ASSERT(isSymbol()); #if defined(JS_NUNBOX32) - return data.s.payload.sym; + return data.s.payload.sym; #elif defined(JS_PUNBOX64) - return reinterpret_cast(data.asBits & JSVAL_PAYLOAD_MASK); + return reinterpret_cast(data.asBits ^ + JSVAL_SHIFTED_TAG_SYMBOL); #endif - } + } - JSObject& toObject() const { - MOZ_ASSERT(isObject()); + JSObject& toObject() const { + MOZ_ASSERT(isObject()); #if defined(JS_NUNBOX32) - return *data.s.payload.obj; + return *data.s.payload.obj; #elif defined(JS_PUNBOX64) - return *toObjectOrNull(); + uint64_t ptrBits = data.asBits ^ JSVAL_SHIFTED_TAG_OBJECT; + MOZ_ASSERT(ptrBits); + MOZ_ASSERT((ptrBits & 0x7) == 0); + return *reinterpret_cast(ptrBits); #endif - } + } - JSObject* toObjectOrNull() const { - MOZ_ASSERT(isObjectOrNull()); + JSObject* toObjectOrNull() const { + MOZ_ASSERT(isObjectOrNull()); #if defined(JS_NUNBOX32) - return data.s.payload.obj; + 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); + // Note: the 'Spectre mitigations' comment at the top of this class + // explains why we use XOR here and in other to* methods. + uint64_t ptrBits = + (data.asBits ^ JSVAL_SHIFTED_TAG_OBJECT) & ~JSVAL_OBJECT_OR_NULL_BIT; + MOZ_ASSERT((ptrBits & 0x7) == 0); + return reinterpret_cast(ptrBits); #endif - } + } - js::gc::Cell* toGCThing() const { - MOZ_ASSERT(isGCThing()); + js::gc::Cell* toGCThing() const { + MOZ_ASSERT(isGCThing()); #if defined(JS_NUNBOX32) - return data.s.payload.cell; + 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); + uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK_GCTHING; + MOZ_ASSERT((ptrBits & 0x7) == 0); + return reinterpret_cast(ptrBits); #endif - } + } - js::gc::Cell* toMarkablePointer() const { - MOZ_ASSERT(isMarkable()); - return toGCThing(); - } + GCCellPtr toGCCellPtr() const { return GCCellPtr(toGCThing(), traceKind()); } - GCCellPtr toGCCellPtr() const { - return GCCellPtr(toGCThing(), traceKind()); - } - - bool toBoolean() const { - MOZ_ASSERT(isBoolean()); + bool toBoolean() const { + MOZ_ASSERT(isBoolean()); #if defined(JS_NUNBOX32) - return bool(data.s.payload.boo); + return bool(data.s.payload.boo); #elif defined(JS_PUNBOX64) - return bool(data.asBits & JSVAL_PAYLOAD_MASK); + return bool(int32_t(data.asBits)); #endif - } + } - uint32_t payloadAsRawUint32() const { - MOZ_ASSERT(!isDouble()); - return data.s.payload.u32; - } + uint32_t payloadAsRawUint32() const { + MOZ_ASSERT(!isDouble()); + return data.s.payload.u32; + } - uint64_t asRawBits() const { - return data.asBits; - } + uint64_t asRawBits() const { return data.asBits; } - JSValueType extractNonDoubleType() const { - uint32_t type = toTag() & 0xF; - MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); - return JSValueType(type); - } + JSValueType extractNonDoubleType() const { + uint32_t type = toTag() & 0xF; + MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); + return JSValueType(type); + } + + /* + * Private API + * + * Private setters/getters allow the caller to read/write arbitrary types + * that fit in the 64-bit payload. It is the caller's responsibility, after + * storing to a value with setPrivateX to read only using getPrivateX. + * Privates values are given a type which ensures they are not marked. + */ - /* - * Private API - * - * Private setters/getters allow the caller to read/write arbitrary types - * that fit in the 64-bit payload. It is the caller's responsibility, after - * storing to a value with setPrivateX to read only using getPrivateX. - * Privates values are given a type which ensures they are not marked. - */ - - void setPrivate(void* ptr) { - MOZ_ASSERT((uintptr_t(ptr) & 1) == 0); + void setPrivate(void* ptr) { + MOZ_ASSERT((uintptr_t(ptr) & 1) == 0); #if defined(JS_NUNBOX32) - data.s.tag = JSValueTag(0); - data.s.payload.ptr = ptr; + data.s.tag = JSValueTag(0); + data.s.payload.ptr = ptr; #elif defined(JS_PUNBOX64) - data.asBits = uintptr_t(ptr) >> 1; + data.asBits = uintptr_t(ptr) >> 1; #endif - MOZ_ASSERT(isDouble()); - } + MOZ_ASSERT(isDouble()); + } - void* toPrivate() const { - MOZ_ASSERT(isDouble()); + void* toPrivate() const { + MOZ_ASSERT(isDouble()); #if defined(JS_NUNBOX32) - return data.s.payload.ptr; + return data.s.payload.ptr; #elif defined(JS_PUNBOX64) - MOZ_ASSERT((data.asBits & 0x8000000000000000ULL) == 0); - return reinterpret_cast(data.asBits << 1); + MOZ_ASSERT((data.asBits & 0x8000000000000000ULL) == 0); + return reinterpret_cast(data.asBits << 1); #endif - } + } - void setPrivateUint32(uint32_t ui) { - MOZ_ASSERT(uint32_t(int32_t(ui)) == ui); - setInt32(int32_t(ui)); - } + void setPrivateUint32(uint32_t ui) { + MOZ_ASSERT(uint32_t(int32_t(ui)) == ui); + setInt32(int32_t(ui)); + } - uint32_t toPrivateUint32() const { - return uint32_t(toInt32()); - } + uint32_t toPrivateUint32() const { return uint32_t(toInt32()); } + + /* + * 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 isGCThing(), and + * as such, automatically marked. Their traceKind() is gotten via their + * cells. + */ - /* - * 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 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."); + 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); + MOZ_ASSERT(js::gc::IsCellPointerValid(cell)); #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); + // 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)); - } + data.asBits = + bitsFromTagAndPayload(JSVAL_TAG_PRIVATE_GCTHING, PayloadType(cell)); + } - bool isPrivateGCThing() const { - return toTag() == JSVAL_TAG_PRIVATE_GCTHING; - } + bool isPrivateGCThing() const { return toTag() == JSVAL_TAG_PRIVATE_GCTHING; } - const size_t* payloadWord() const { + const size_t* payloadWord() const { #if defined(JS_NUNBOX32) - return &data.s.payload.word; + return &data.s.payload.word; #elif defined(JS_PUNBOX64) - return &data.asWord; + return &data.asWord; #endif - } + } - const uintptr_t* payloadUIntPtr() const { + const uintptr_t* payloadUIntPtr() const { #if defined(JS_NUNBOX32) - return &data.s.payload.uintptr; + return &data.s.payload.uintptr; #elif defined(JS_PUNBOX64) - return &data.asUIntPtr; + return &data.asUIntPtr; #endif - } + } #if !defined(_MSC_VER) && !defined(__sparc) // Value must be POD so that MSVC will pass it by value and not in memory // (bug 689101); the same is true for SPARC as well (bug 737344). More // precisely, we don't want Value return values compiled as out params. - private: + private: #endif #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(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: - explicit constexpr Value(uint64_t asBits) : data(asBits) {} - explicit constexpr Value(double d) : data(d) {} - - void staticAssertions() { - JS_STATIC_ASSERT(sizeof(JSValueType) == 1); - JS_STATIC_ASSERT(sizeof(JSValueTag) == 4); - JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4); - JS_STATIC_ASSERT(sizeof(Value) == 8); - } + /* 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: + explicit constexpr Value(uint64_t asBits) : data(asBits) {} + explicit constexpr Value(double d) : data(d) {} + + void staticAssertions() { + JS_STATIC_ASSERT(sizeof(JSValueType) == 1); + JS_STATIC_ASSERT(sizeof(JSValueTag) == 4); + JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4); + JS_STATIC_ASSERT(sizeof(Value) == 8); + } - friend constexpr Value JS::UndefinedValue(); + friend constexpr Value JS::UndefinedValue(); - public: - static constexpr uint64_t - bitsFromTagAndPayload(JSValueTag tag, PayloadType payload) - { + public: + static constexpr uint64_t bitsFromTagAndPayload(JSValueTag tag, + PayloadType payload) { #if defined(JS_NUNBOX32) - return (uint64_t(uint32_t(tag)) << 32) | payload; + return (uint64_t(uint32_t(tag)) << 32) | payload; #elif defined(JS_PUNBOX64) - return (uint64_t(uint32_t(tag)) << JSVAL_TAG_SHIFT) | payload; + 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 fromTagAndPayload(JSValueTag tag, + PayloadType payload) { + return fromRawBits(bitsFromTagAndPayload(tag, payload)); + } - static constexpr Value - fromRawBits(uint64_t asBits) { - return Value(asBits); - } + 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 fromInt32(int32_t i) { + return fromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i)); + } - static constexpr Value - fromDouble(double d) { - return Value(d); - } + 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); - } +struct MOZ_NON_PARAM alignas(8) UninitializedValue { + private: + uint64_t bits; - inline operator Value&() { - return asValueRef(); - } - inline operator Value const&() const { - return asValueRef(); - } - inline operator Value() const { - return asValueRef(); - } + 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; - } + 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) -{ - if (v.isMagic()) { - MOZ_ASSERT(v.whyMagic() == JS_OPTIMIZED_ARGUMENTS || v.whyMagic() == JS_OPTIMIZED_OUT); - return true; - } - return false; -} - -static MOZ_ALWAYS_INLINE void -ExposeValueToActiveJS(const Value& v) -{ - if (v.isMarkable()) - js::gc::ExposeGCThingToActiveJS(GCCellPtr(v)); +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) { + if (v.isMagic()) { + MOZ_ASSERT(v.whyMagic() == JS_OPTIMIZED_ARGUMENTS || + v.whyMagic() == JS_OPTIMIZED_OUT); + return true; + } + return false; +} + +static MOZ_ALWAYS_INLINE void ExposeValueToActiveJS(const Value& v) { +#ifdef DEBUG + Value tmp = v; + MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&tmp)); +#endif + if (v.isGCThing()) js::gc::ExposeGCThingToActiveJS(GCCellPtr(v)); } /************************************************************************/ -static inline Value -NullValue() -{ - Value v; - v.setNull(); - return v; +static inline MOZ_MAY_CALL_AFTER_MUST_RETURN Value NullValue() { + Value v; + v.setNull(); + return v; } -static inline constexpr Value -UndefinedValue() -{ - return Value::fromTagAndPayload(JSVAL_TAG_UNDEFINED, 0); +static inline constexpr Value UndefinedValue() { + return Value::fromTagAndPayload(JSVAL_TAG_UNDEFINED, 0); } -static inline constexpr Value -Int32Value(int32_t i32) -{ - return Value::fromInt32(i32); +static inline constexpr Value Int32Value(int32_t i32) { + return Value::fromInt32(i32); } -static inline Value -DoubleValue(double dbl) -{ - Value v; - v.setDouble(dbl); - return v; +static inline Value DoubleValue(double dbl) { + Value v; + v.setDouble(dbl); + return v; } -static inline Value -CanonicalizedDoubleValue(double d) -{ - return MOZ_UNLIKELY(mozilla::IsNaN(d)) - ? Value::fromRawBits(detail::CanonicalizedNaNBits) - : Value::fromDouble(d); +static inline Value CanonicalizedDoubleValue(double d) { + 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; +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; + return (bits & ~mozilla::DoubleTypeTraits::kSignBit) == + detail::CanonicalizedNaNBits; } -static inline Value -DoubleNaNValue() -{ - Value v; - v.setNaN(); - return v; +static inline Value DoubleNaNValue() { + Value v; + v.setNaN(); + return v; } -static inline Value -Float32Value(float f) -{ - Value v; - v.setDouble(f); - return v; +static inline Value Float32Value(float f) { + Value v; + v.setDouble(f); + return v; } -static inline Value -StringValue(JSString* str) -{ - Value v; - v.setString(str); - return v; +static inline Value StringValue(JSString* str) { + Value v; + v.setString(str); + return v; } -static inline Value -SymbolValue(JS::Symbol* sym) -{ - Value v; - v.setSymbol(sym); - return v; +static inline Value SymbolValue(JS::Symbol* sym) { + Value v; + v.setSymbol(sym); + return v; } -static inline Value -BooleanValue(bool boo) -{ - Value v; - v.setBoolean(boo); - return v; +static inline Value BooleanValue(bool boo) { + Value v; + v.setBoolean(boo); + return v; } -static inline Value -TrueValue() -{ - Value v; - v.setBoolean(true); - return v; +static inline Value TrueValue() { + Value v; + v.setBoolean(true); + return v; } -static inline Value -FalseValue() -{ - Value v; - v.setBoolean(false); - return v; +static inline Value FalseValue() { + Value v; + v.setBoolean(false); + return v; } -static inline Value -ObjectValue(JSObject& obj) -{ - Value v; - v.setObject(obj); - return v; +static inline Value ObjectValue(JSObject& obj) { + Value v; + v.setObject(obj); + return v; } -static inline Value -ObjectValueCrashOnTouch() -{ - Value v; - v.setObject(*reinterpret_cast(0x48)); - return v; +static inline Value MagicValue(JSWhyMagic why) { + Value v; + v.setMagic(why); + return v; } -static inline Value -MagicValue(JSWhyMagic why) -{ - Value v; - v.setMagic(why); - return v; +static inline Value MagicValueUint32(uint32_t payload) { + Value v; + v.setMagicUint32(payload); + return v; } -static inline Value -MagicValueUint32(uint32_t payload) -{ - Value v; - v.setMagicUint32(payload); - return v; +static inline Value NumberValue(float f) { + Value v; + v.setNumber(f); + return v; } -static inline Value -NumberValue(float f) -{ - Value v; - v.setNumber(f); - return v; +static inline Value NumberValue(double dbl) { + Value v; + v.setNumber(dbl); + return v; } -static inline Value -NumberValue(double dbl) -{ - Value v; - v.setNumber(dbl); - return v; -} +static inline Value NumberValue(int8_t i) { return Int32Value(i); } -static inline Value -NumberValue(int8_t i) -{ - return Int32Value(i); -} +static inline Value NumberValue(uint8_t i) { return Int32Value(i); } -static inline Value -NumberValue(uint8_t i) -{ - return Int32Value(i); -} +static inline Value NumberValue(int16_t i) { return Int32Value(i); } -static inline Value -NumberValue(int16_t i) -{ - return Int32Value(i); -} +static inline Value NumberValue(uint16_t i) { return Int32Value(i); } -static inline Value -NumberValue(uint16_t i) -{ - return Int32Value(i); -} +static inline Value NumberValue(int32_t i) { return Int32Value(i); } -static inline Value -NumberValue(int32_t i) -{ - return Int32Value(i); -} - -static inline constexpr Value -NumberValue(uint32_t i) -{ - return i <= JSVAL_INT_MAX - ? Int32Value(int32_t(i)) - : Value::fromDouble(double(i)); +static inline constexpr Value NumberValue(uint32_t i) { + return i <= JSVAL_INT_MAX ? Int32Value(int32_t(i)) + : Value::fromDouble(double(i)); } namespace detail { template -class MakeNumberValue -{ - public: - template - static inline Value create(const T t) - { - Value v; - if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX) - v.setInt32(int32_t(t)); - else - v.setDouble(double(t)); - return v; - } +class MakeNumberValue { + public: + template + static inline Value create(const T t) { + Value v; + if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX) + v.setInt32(int32_t(t)); + else + v.setDouble(double(t)); + return v; + } }; template <> -class MakeNumberValue -{ - public: - template - static inline Value create(const T t) - { - Value v; - if (t <= JSVAL_INT_MAX) - v.setInt32(int32_t(t)); - else - v.setDouble(double(t)); - return v; - } +class MakeNumberValue { + public: + template + static inline Value create(const T t) { + Value v; + if (t <= JSVAL_INT_MAX) + v.setInt32(int32_t(t)); + else + v.setDouble(double(t)); + return v; + } }; -} // namespace detail +} // namespace detail template -static inline Value -NumberValue(const T t) -{ - MOZ_ASSERT(Value::isNumberRepresentable(t), "value creation would be lossy"); - return detail::MakeNumberValue::is_signed>::create(t); +static inline Value NumberValue(const T t) { + MOZ_ASSERT(Value::isNumberRepresentable(t), "value creation would be lossy"); + return detail::MakeNumberValue::is_signed>::create(t); } -static inline Value -ObjectOrNullValue(JSObject* obj) -{ - Value v; - v.setObjectOrNull(obj); - return v; +static inline Value ObjectOrNullValue(JSObject* obj) { + Value v; + v.setObjectOrNull(obj); + return v; } -static inline Value -PrivateValue(void* ptr) -{ - Value v; - v.setPrivate(ptr); - return v; +static inline Value PrivateValue(void* ptr) { + Value v; + v.setPrivate(ptr); + return v; } -static inline Value -PrivateUint32Value(uint32_t ui) -{ - Value v; - v.setPrivateUint32(ui); - return v; +static inline Value PrivateUint32Value(uint32_t ui) { + Value v; + v.setPrivateUint32(ui); + return v; } -static inline Value -PrivateGCThingValue(js::gc::Cell* cell) -{ - Value v; - v.setPrivateGCThing(cell); - 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) -{ +inline bool SameType(const Value& lhs, const Value& rhs) { #if defined(JS_NUNBOX32) - JSValueTag ltag = lhs.toTag(), rtag = rhs.toTag(); - return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR); + 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); + return (lhs.isDouble() && rhs.isDouble()) || + (((lhs.data.asBits ^ rhs.data.asBits) & 0xFFFF800000000000ULL) == 0); #endif } -} // namespace JS +} // namespace JS /************************************************************************/ namespace JS { -JS_PUBLIC_API(void) HeapValuePostBarrier(Value* valuep, const Value& prev, const Value& next); +JS_PUBLIC_API void HeapValuePostBarrier(Value* valuep, const Value& prev, + const Value& next); template <> -struct GCPolicy -{ - 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()); - } +struct GCPolicy { + 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()); + } + static bool isValid(const Value& value) { + return !value.isGCThing() || js::gc::IsCellPointerValid(value.toGCThing()); + } }; -} // namespace JS +} // namespace JS namespace js { template <> -struct BarrierMethods -{ - 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); - } +struct BarrierMethods { + static gc::Cell* asGCThingOrNull(const JS::Value& v) { + return v.isGCThing() ? 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; +template +class MutableValueOperations; /** * A class designed for CRTP use in implementing the non-mutating parts of the - * Value interface in Value-like classes. Outer must be a class inheriting - * ValueOperations with a visible get() method returning a const - * reference to the Value abstracted by Outer. + * Value interface in Value-like classes. Wrapper must be a class inheriting + * ValueOperations with a visible get() method returning a const + * reference to the Value abstracted by Wrapper. */ -template -class ValueOperations -{ - friend class MutableValueOperations; - - const JS::Value& value() const { return static_cast(this)->get(); } - - public: - bool isUndefined() const { return value().isUndefined(); } - bool isNull() const { return value().isNull(); } - bool isBoolean() const { return value().isBoolean(); } - bool isTrue() const { return value().isTrue(); } - bool isFalse() const { return value().isFalse(); } - bool isNumber() const { return value().isNumber(); } - bool isInt32() const { return value().isInt32(); } - bool isInt32(int32_t i32) const { return value().isInt32(i32); } - bool isDouble() const { return value().isDouble(); } - bool isString() const { return value().isString(); } - bool isSymbol() const { return value().isSymbol(); } - bool isObject() const { return value().isObject(); } - bool isMagic() const { return value().isMagic(); } - bool isMagic(JSWhyMagic why) const { return value().isMagic(why); } - bool isMarkable() const { return value().isMarkable(); } - bool isPrimitive() const { return value().isPrimitive(); } - bool isGCThing() const { return value().isGCThing(); } - - bool isNullOrUndefined() const { return value().isNullOrUndefined(); } - bool isObjectOrNull() const { return value().isObjectOrNull(); } - - bool toBoolean() const { return value().toBoolean(); } - double toNumber() const { return value().toNumber(); } - int32_t toInt32() const { return value().toInt32(); } - double toDouble() const { return value().toDouble(); } - JSString* toString() const { return value().toString(); } - JS::Symbol* toSymbol() const { return value().toSymbol(); } - JSObject& toObject() const { return value().toObject(); } - JSObject* toObjectOrNull() const { return value().toObjectOrNull(); } - gc::Cell* toGCThing() const { return value().toGCThing(); } - JS::TraceKind traceKind() const { return value().traceKind(); } - 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(); } +template +class WrappedPtrOperations { + const JS::Value& value() const { + return static_cast(this)->get(); + } + + public: + bool isUndefined() const { return value().isUndefined(); } + bool isNull() const { return value().isNull(); } + bool isBoolean() const { return value().isBoolean(); } + bool isTrue() const { return value().isTrue(); } + bool isFalse() const { return value().isFalse(); } + bool isNumber() const { return value().isNumber(); } + bool isInt32() const { return value().isInt32(); } + bool isInt32(int32_t i32) const { return value().isInt32(i32); } + bool isDouble() const { return value().isDouble(); } + bool isString() const { return value().isString(); } + bool isSymbol() const { return value().isSymbol(); } + bool isObject() const { return value().isObject(); } + bool isMagic() const { return value().isMagic(); } + bool isMagic(JSWhyMagic why) const { return value().isMagic(why); } + bool isGCThing() const { return value().isGCThing(); } + bool isPrimitive() const { return value().isPrimitive(); } + + bool isNullOrUndefined() const { return value().isNullOrUndefined(); } + bool isObjectOrNull() const { return value().isObjectOrNull(); } + + bool toBoolean() const { return value().toBoolean(); } + double toNumber() const { return value().toNumber(); } + int32_t toInt32() const { return value().toInt32(); } + double toDouble() const { return value().toDouble(); } + JSString* toString() const { return value().toString(); } + JS::Symbol* toSymbol() const { return value().toSymbol(); } + JSObject& toObject() const { return value().toObject(); } + JSObject* toObjectOrNull() const { return value().toObjectOrNull(); } + gc::Cell* toGCThing() const { return value().toGCThing(); } + JS::TraceKind traceKind() const { return value().traceKind(); } + 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(); + } - JSWhyMagic whyMagic() const { return value().whyMagic(); } - uint32_t magicUint32() const { return value().magicUint32(); } + JSWhyMagic whyMagic() const { return value().whyMagic(); } + uint32_t magicUint32() const { return value().magicUint32(); } }; /** * A class designed for CRTP use in implementing all the mutating parts of the - * Value interface in Value-like classes. Outer must be a class inheriting - * MutableValueOperations with visible get() methods returning const and - * non-const references to the Value abstracted by Outer. + * Value interface in Value-like classes. Wrapper must be a class inheriting + * MutableWrappedPtrOperations with visible get() methods returning + * const and non-const references to the Value abstracted by Wrapper. */ -template -class MutableValueOperations : public ValueOperations -{ - JS::Value& value() { return static_cast(this)->get(); } - - public: - void setNull() { value().setNull(); } - void setUndefined() { value().setUndefined(); } - void setInt32(int32_t i) { value().setInt32(i); } - void setDouble(double d) { value().setDouble(d); } - void setNaN() { setDouble(JS::GenericNaN()); } - void setBoolean(bool b) { value().setBoolean(b); } - void setMagic(JSWhyMagic why) { value().setMagic(why); } - bool setNumber(uint32_t ui) { return value().setNumber(ui); } - bool setNumber(double d) { return value().setNumber(d); } - void setString(JSString* str) { this->value().setString(str); } - 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); } +template +class MutableWrappedPtrOperations + : public WrappedPtrOperations { + JS::Value& value() { return static_cast(this)->get(); } + + public: + void setNull() { value().setNull(); } + void setUndefined() { value().setUndefined(); } + void setInt32(int32_t i) { value().setInt32(i); } + void setDouble(double d) { value().setDouble(d); } + void setNaN() { setDouble(JS::GenericNaN()); } + void setBoolean(bool b) { value().setBoolean(b); } + void setMagic(JSWhyMagic why) { value().setMagic(why); } + bool setNumber(uint32_t ui) { return value().setNumber(ui); } + bool setNumber(double d) { return value().setNumber(d); } + void setString(JSString* str) { this->value().setString(str); } + 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); + } }; /* * Augment the generic Heap interface when T = Value with * type-querying, value-extracting, and mutating operations. */ -template <> -class HeapBase : public ValueOperations > -{ - typedef JS::Heap Outer; - - friend class ValueOperations; - - void setBarriered(const JS::Value& v) { - *static_cast*>(this) = v; +template +class HeapBase + : public WrappedPtrOperations { + void setBarriered(const JS::Value& v) { + *static_cast*>(this) = v; + } + + public: + void setNull() { setBarriered(JS::NullValue()); } + void setUndefined() { setBarriered(JS::UndefinedValue()); } + void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); } + void setDouble(double d) { setBarriered(JS::DoubleValue(d)); } + void setNaN() { setDouble(JS::GenericNaN()); } + void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); } + void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); } + 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) { + setDouble((double)ui); + return false; + } else { + setInt32((int32_t)ui); + return true; } + } - public: - void setNull() { setBarriered(JS::NullValue()); } - void setUndefined() { setBarriered(JS::UndefinedValue()); } - void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); } - void setDouble(double d) { setBarriered(JS::DoubleValue(d)); } - void setNaN() { setDouble(JS::GenericNaN()); } - void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); } - void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); } - 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) { - setDouble((double)ui); - return false; - } else { - setInt32((int32_t)ui); - return true; - } + bool setNumber(double d) { + int32_t i; + if (mozilla::NumberIsInt32(d, &i)) { + setInt32(i); + return true; } - bool setNumber(double d) { - int32_t i; - if (mozilla::NumberIsInt32(d, &i)) { - setInt32(i); - return true; - } - - setDouble(d); - return false; - } + setDouble(d); + return false; + } - void setObjectOrNull(JSObject* arg) { - if (arg) - setObject(*arg); - else - setNull(); - } + void setObjectOrNull(JSObject* arg) { + if (arg) + setObject(*arg); + else + setNull(); + } }; -template <> -class HandleBase : public ValueOperations > -{}; - -template <> -class MutableHandleBase : public MutableValueOperations > -{}; - -template <> -class RootedBase : public MutableValueOperations > -{}; - -template <> -class PersistentRootedBase : public MutableValueOperations> -{}; - /* * If the Value is a GC pointer type, convert to that type and call |f| with * the pointer. If the Value is not a GC type, calls F::defaultValue. */ template -auto -DispatchTyped(F f, const JS::Value& val, Args&&... args) - -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) -{ - if (val.isString()) - return f(val.toString(), mozilla::Forward(args)...); - if (val.isObject()) - 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(const S&) {} }; -template struct IdentityDefaultAdaptor { static S defaultValue(const S& v) {return v;} }; -template struct BoolDefaultAdaptor { static bool defaultValue(const S&) { return v; } }; +auto DispatchTyped(F f, const JS::Value& val, Args&&... args) + -> decltype(f(static_cast(nullptr), + mozilla::Forward(args)...)) { + if (val.isString()) { + JSString* str = val.toString(); + MOZ_ASSERT(gc::IsCellPointerValid(str)); + return f(str, mozilla::Forward(args)...); + } + if (val.isObject()) { + JSObject* obj = &val.toObject(); + MOZ_ASSERT(gc::IsCellPointerValid(obj)); + return f(obj, mozilla::Forward(args)...); + } + if (val.isSymbol()) { + JS::Symbol* sym = val.toSymbol(); + MOZ_ASSERT(gc::IsCellPointerValid(sym)); + return f(sym, mozilla::Forward(args)...); + } + if (MOZ_UNLIKELY(val.isPrivateGCThing())) { + MOZ_ASSERT(gc::IsCellPointerValid(val.toGCThing())); + return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward(args)...); + } + MOZ_ASSERT(!val.isGCThing()); + return F::defaultValue(val); +} + +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(const S&) { return v; } +}; + +static inline JS::Value PoisonedObjectValue(uintptr_t poison) { + JS::Value v; + v.setObjectNoCheck(reinterpret_cast(poison)); + return v; +} + +} // namespace js + +#ifdef DEBUG +namespace JS { + +MOZ_ALWAYS_INLINE bool ValueIsNotGray(const Value& value) { + if (!value.isGCThing()) return true; + + return CellIsNotGray(value.toGCThing()); +} -} // namespace js +MOZ_ALWAYS_INLINE bool ValueIsNotGray(const Heap& value) { + return ValueIsNotGray(value.unbarrieredGet()); +} + +} // namespace JS +#endif /************************************************************************/ namespace JS { -extern JS_PUBLIC_DATA(const HandleValue) NullHandleValue; -extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue; -extern JS_PUBLIC_DATA(const HandleValue) TrueHandleValue; -extern JS_PUBLIC_DATA(const HandleValue) FalseHandleValue; +extern JS_PUBLIC_DATA const HandleValue NullHandleValue; +extern JS_PUBLIC_DATA const HandleValue UndefinedHandleValue; +extern JS_PUBLIC_DATA const HandleValue TrueHandleValue; +extern JS_PUBLIC_DATA const HandleValue FalseHandleValue; -} // namespace JS +} // namespace JS #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 @@ -9,12 +9,6 @@ #include "mozilla/Vector.h" -/* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */ -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4345) -#endif - namespace js { class TempAllocPolicy; @@ -22,24 +16,22 @@ namespace detail { template -struct TypeIsGCThing : mozilla::FalseType -{}; +struct TypeIsGCThing : mozilla::FalseType {}; // Uncomment this once we actually can assert it: -//template <> -//struct TypeIsGCThing : mozilla::TrueType +// template <> +// struct TypeIsGCThing : mozilla::TrueType //{}; -} // namespace detail +} // namespace detail -template ::value>::Type - > + // Don't use this with JS::Value! Use JS::AutoValueVector instead. + typename = typename mozilla::EnableIf< + !detail::TypeIsGCThing::value>::Type> using Vector = mozilla::Vector; -} // namespace js +} // namespace js #endif /* js_Vector_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/WeakMapPtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/WeakMapPtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/WeakMapPtr.h @@ -16,31 +16,31 @@ // A wrapper around the internal C++ representation of SpiderMonkey WeakMaps, // usable outside the engine. // -// The supported template specializations are enumerated in WeakMapPtr.cpp. If -// you want to use this class for a different key/value combination, add it to -// the list and the compiler will generate the relevant machinery. +// The supported template specializations are enumerated in gc/WeakMapPtr.cpp. +// If you want to use this class for a different key/value combination, add it +// to the list and the compiler will generate the relevant machinery. template -class JS_PUBLIC_API(WeakMapPtr) -{ - public: - WeakMapPtr() : ptr(nullptr) {} - bool init(JSContext* cx); - bool initialized() { return ptr != nullptr; } - void destroy(); - virtual ~WeakMapPtr() { MOZ_ASSERT(!initialized()); } - void trace(JSTracer* tracer); - - V lookup(const K& key); - bool put(JSContext* cx, const K& key, const V& value); - - private: - void* ptr; - - // WeakMapPtr is neither copyable nor assignable. - WeakMapPtr(const WeakMapPtr& wmp) = delete; - WeakMapPtr& operator=(const WeakMapPtr& wmp) = delete; +class JS_PUBLIC_API WeakMapPtr { + public: + WeakMapPtr() : ptr(nullptr) {} + bool init(JSContext* cx); + bool initialized() { return ptr != nullptr; } + void destroy(); + virtual ~WeakMapPtr() { MOZ_ASSERT(!initialized()); } + void trace(JSTracer* tracer); + + V lookup(const K& key); + bool put(JSContext* cx, const K& key, const V& value); + V removeValue(const K& key); + + private: + void* ptr; + + // WeakMapPtr is neither copyable nor assignable. + WeakMapPtr(const WeakMapPtr& wmp) = delete; + WeakMapPtr& operator=(const WeakMapPtr& wmp) = delete; }; } /* namespace JS */ -#endif /* js_WeakMapPtr_h */ +#endif /* js_WeakMapPtr_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Wrapper.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Wrapper.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/Wrapper.h @@ -0,0 +1,426 @@ +/* -*- 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_Wrapper_h +#define js_Wrapper_h + +#include "mozilla/Attributes.h" + +#include "js/Proxy.h" + +namespace js { + +/* + * Helper for Wrapper::New default options. + * + * Callers of Wrapper::New() who wish to specify a prototype for the created + * Wrapper, *MUST* construct a WrapperOptions with a JSContext. + */ +class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions { + public: + WrapperOptions() : ProxyOptions(false), proto_() {} + + explicit WrapperOptions(JSContext* cx) : ProxyOptions(false), proto_() { + proto_.emplace(cx); + } + + inline JSObject* proto() const; + WrapperOptions& setProto(JSObject* protoArg) { + MOZ_ASSERT(proto_); + *proto_ = protoArg; + return *this; + } + + private: + mozilla::Maybe proto_; +}; + +// Base class for proxy handlers that want to forward all operations to an +// object stored in the proxy's private slot. +class JS_FRIEND_API ForwardingProxyHandler : public BaseProxyHandler { + public: + using BaseProxyHandler::BaseProxyHandler; + + /* 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 JSObject* enumerate(JSContext* cx, HandleObject proxy) 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, + bool isToSource) const override; + virtual RegExpShared* regexp_toShared(JSContext* cx, + HandleObject proxy) 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; +}; + +/* + * A wrapper is a proxy with a target object to which it generally forwards + * 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 ForwardingProxyHandler { + unsigned mFlags; + + public: + explicit constexpr Wrapper(unsigned aFlags, bool aHasPrototype = false, + bool aHasSecurityPolicy = false) + : ForwardingProxyHandler(&family, aHasPrototype, aHasSecurityPolicy), + mFlags(aFlags) {} + + virtual bool finalizeInBackground(const Value& priv) const override; + virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const override; + + using BaseProxyHandler::Action; + + enum Flags { CROSS_COMPARTMENT = 1 << 0, LAST_USED_FLAG = CROSS_COMPARTMENT }; + + static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler, + const WrapperOptions& options = WrapperOptions()); + + static JSObject* Renew(JSObject* existing, JSObject* obj, + const Wrapper* handler); + + static const Wrapper* wrapperHandler(JSObject* wrapper); + + static JSObject* wrappedObject(JSObject* wrapper); + + unsigned flags() const { return mFlags; } + + static const char family; + static const Wrapper singleton; + static const Wrapper singletonWithPrototype; + + static JSObject* defaultProto; +}; + +inline JSObject* WrapperOptions::proto() const { + return proto_ ? *proto_ : Wrapper::defaultProto; +} + +/* Base class for all cross compartment wrapper handlers. */ +class JS_FRIEND_API CrossCompartmentWrapper : public Wrapper { + public: + 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; + virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, + Handle desc, + ObjectOpResult& result) const override; + virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper, + AutoIdVector& props) const override; + virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id, + ObjectOpResult& result) const override; + virtual JSObject* enumerate(JSContext* cx, + HandleObject wrapper) 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 wrapper, + ObjectOpResult& result) const override; + virtual bool isExtensible(JSContext* cx, HandleObject wrapper, + bool* extensible) const override; + virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id, + bool* bp) const override; + virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver, + HandleId id, MutableHandleValue vp) const override; + virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, + HandleValue v, HandleValue receiver, + ObjectOpResult& result) const override; + virtual bool call(JSContext* cx, HandleObject wrapper, + const CallArgs& args) const override; + virtual bool construct(JSContext* cx, HandleObject wrapper, + const CallArgs& args) const override; + + /* SpiderMonkey extensions. */ + virtual bool getPropertyDescriptor( + JSContext* cx, HandleObject wrapper, HandleId id, + 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 nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, + const CallArgs& args) const override; + virtual bool hasInstance(JSContext* cx, HandleObject wrapper, + MutableHandleValue v, bool* bp) const override; + virtual const char* className(JSContext* cx, + HandleObject proxy) const override; + virtual JSString* fun_toString(JSContext* cx, HandleObject wrapper, + bool isToSource) const override; + virtual RegExpShared* regexp_toShared(JSContext* cx, + HandleObject proxy) 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; +}; + +class JS_FRIEND_API OpaqueCrossCompartmentWrapper + : public CrossCompartmentWrapper { + public: + explicit constexpr OpaqueCrossCompartmentWrapper() + : CrossCompartmentWrapper(0) {} + + /* Standard internal methods. */ + virtual bool getOwnPropertyDescriptor( + JSContext* cx, HandleObject wrapper, HandleId id, + MutableHandle desc) const override; + virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, + Handle desc, + ObjectOpResult& result) const override; + virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper, + AutoIdVector& props) const override; + virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id, + ObjectOpResult& result) const override; + virtual JSObject* enumerate(JSContext* cx, + HandleObject wrapper) const override; + virtual bool getPrototype(JSContext* cx, HandleObject wrapper, + 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, + ObjectOpResult& result) const override; + virtual bool isExtensible(JSContext* cx, HandleObject wrapper, + bool* extensible) const override; + virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id, + bool* bp) const override; + virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver, + HandleId id, MutableHandleValue vp) const override; + virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, + HandleValue v, HandleValue receiver, + ObjectOpResult& result) const override; + virtual bool call(JSContext* cx, HandleObject wrapper, + const CallArgs& args) const override; + virtual bool construct(JSContext* cx, HandleObject wrapper, + const CallArgs& args) const override; + + /* SpiderMonkey extensions. */ + virtual bool getPropertyDescriptor( + JSContext* cx, HandleObject wrapper, HandleId id, + 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, + 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; + virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, + bool isToSource) const override; + + static const OpaqueCrossCompartmentWrapper singleton; +}; + +/* + * Base class for security wrappers. A security wrapper is potentially hiding + * all or part of some wrapped object thus SecurityWrapper defaults to denying + * access to the wrappee. This is the opposite of Wrapper which tries to be + * completely transparent. + * + * NB: Currently, only a few ProxyHandler operations are overridden to deny + * access, relying on derived SecurityWrapper to block access when necessary. + */ +template +class JS_FRIEND_API SecurityWrapper : public Base { + public: + explicit constexpr SecurityWrapper(unsigned flags, bool hasPrototype = false) + : Base(flags, hasPrototype, /* hasSecurityPolicy = */ true) {} + + virtual bool enter(JSContext* cx, HandleObject wrapper, HandleId id, + Wrapper::Action act, bool mayThrow, + bool* bp) const override; + + virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, + Handle desc, + ObjectOpResult& result) const override; + virtual bool isExtensible(JSContext* cx, HandleObject wrapper, + bool* extensible) const override; + virtual bool preventExtensions(JSContext* cx, HandleObject wrapper, + ObjectOpResult& result) 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 nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, + const CallArgs& args) 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 RegExpShared* regexp_toShared(JSContext* cx, + HandleObject proxy) const override; + virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, + MutableHandleValue vp) const override; + + // Allow isCallable and isConstructor. They used to be class-level, and so + // could not be guarded against. + + /* + * Allow our subclasses to select the superclass behavior they want without + * needing to specify an exact superclass. + */ + typedef Base Permissive; + typedef SecurityWrapper Restrictive; +}; + +typedef SecurityWrapper + CrossCompartmentSecurityWrapper; + +extern JSObject* TransparentObjectWrapper(JSContext* cx, HandleObject existing, + HandleObject obj); + +inline bool IsWrapper(JSObject* obj) { + return IsProxy(obj) && GetProxyHandler(obj)->family() == &Wrapper::family; +} + +// Given a JSObject, returns that object stripped of wrappers. If +// stopAtWindowProxy is true, then this returns the WindowProxy if it was +// previously wrapped. Otherwise, this returns the first object for which +// JSObject::isWrapper returns false. +// +// ExposeToActiveJS is called on wrapper targets to allow gray marking +// assertions to work while an incremental GC is in progress, but this means +// that this cannot be called from the GC or off the main thread. +JS_FRIEND_API JSObject* UncheckedUnwrap(JSObject* obj, + bool stopAtWindowProxy = true, + unsigned* flagsp = nullptr); + +// Given a JSObject, returns that object stripped of wrappers. At each stage, +// the security wrapper has the opportunity to veto the unwrap. If +// stopAtWindowProxy is true, then this returns the WindowProxy if it was +// previously wrapped. +// +// ExposeToActiveJS is called on wrapper targets to allow gray marking +// assertions to work while an incremental GC is in progress, but this means +// that this cannot be called from the GC or off the main thread. +JS_FRIEND_API JSObject* CheckedUnwrap(JSObject* obj, + bool stopAtWindowProxy = true); + +// Unwrap only the outermost security wrapper, with the same semantics as +// above. This is the checked version of Wrapper::wrappedObject. +JS_FRIEND_API JSObject* UnwrapOneChecked(JSObject* obj, + bool stopAtWindowProxy = true); + +// Given a JSObject, returns that object stripped of wrappers. This returns the +// WindowProxy if it was previously wrapped. +// +// ExposeToActiveJS is not called on wrapper targets so this can be called from +// the GC or off the main thread. +JS_FRIEND_API JSObject* UncheckedUnwrapWithoutExpose(JSObject* obj); + +void ReportAccessDenied(JSContext* cx); + +JS_FRIEND_API bool IsCrossCompartmentWrapper(JSObject* obj); + +JS_FRIEND_API void NukeCrossCompartmentWrapper(JSContext* cx, + JSObject* wrapper); + +void RemapWrapper(JSContext* cx, JSObject* wobj, JSObject* newTarget); + +JS_FRIEND_API bool RemapAllWrappersForObject(JSContext* cx, JSObject* oldTarget, + JSObject* newTarget); + +// API to recompute all cross-compartment wrappers whose source and target +// match the given filters. +JS_FRIEND_API bool RecomputeWrappers(JSContext* cx, + const CompartmentFilter& sourceFilter, + const CompartmentFilter& targetFilter); + +} /* namespace js */ + +#endif /* js_Wrapper_h */ 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 @@ -1,145 +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/. */ - -/* - * JS allocation policies. - * - * The allocators here are for system memory with lifetimes which are not - * managed by the GC. See the comment at the top of vm/MallocProvider.h. - */ - -#ifndef jsalloc_h -#define jsalloc_h - -#include "js/TypeDecls.h" -#include "js/Utility.h" - -extern JS_PUBLIC_API(void) JS_ReportOutOfMemory(JSContext* cx); - -namespace js { - -enum class AllocFunction { - Malloc, - Calloc, - Realloc -}; - -struct ContextFriendFields; - -/* Policy for using system memory functions and doing no error reporting. */ -class SystemAllocPolicy -{ - public: - template T* maybe_pod_malloc(size_t numElems) { return js_pod_malloc(numElems); } - template T* maybe_pod_calloc(size_t numElems) { return js_pod_calloc(numElems); } - template T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) { - return js_pod_realloc(p, oldSize, newSize); - } - template T* pod_malloc(size_t numElems) { return maybe_pod_malloc(numElems); } - template T* pod_calloc(size_t numElems) { return maybe_pod_calloc(numElems); } - template T* pod_realloc(T* p, size_t oldSize, size_t newSize) { - return maybe_pod_realloc(p, oldSize, newSize); - } - void free_(void* p) { js_free(p); } - void reportAllocOverflow() const {} - bool checkSimulatedOOM() const { - return !js::oom::ShouldFailWithOOM(); - } -}; - -class ExclusiveContext; -JS_FRIEND_API(void) ReportOutOfMemory(ExclusiveContext* cxArg); - -/* - * Allocation policy that calls the system memory functions and reports errors - * to the context. Since the JSContext given on construction is stored for - * the lifetime of the container, this policy may only be used for containers - * whose lifetime is a shorter than the given JSContext. - * - * FIXME bug 647103 - rewrite this in terms of temporary allocation functions, - * not the system ones. - */ -class TempAllocPolicy -{ - ContextFriendFields* const cx_; - - /* - * Non-inline helper to call JSRuntime::onOutOfMemory with minimal - * code bloat. - */ - JS_FRIEND_API(void*) onOutOfMemory(AllocFunction allocFunc, size_t nbytes, - void* reallocPtr = nullptr); - - template - T* onOutOfMemoryTyped(AllocFunction allocFunc, size_t numElems, void* reallocPtr = nullptr) { - size_t bytes; - if (MOZ_UNLIKELY(!CalculateAllocSize(numElems, &bytes))) - return nullptr; - return static_cast(onOutOfMemory(allocFunc, bytes, reallocPtr)); - } - - public: - MOZ_IMPLICIT TempAllocPolicy(JSContext* cx) : cx_((ContextFriendFields*) cx) {} // :( - MOZ_IMPLICIT TempAllocPolicy(ContextFriendFields* cx) : cx_(cx) {} - - template - T* maybe_pod_malloc(size_t numElems) { - return js_pod_malloc(numElems); - } - - template - T* maybe_pod_calloc(size_t numElems) { - return js_pod_calloc(numElems); - } - - template - T* maybe_pod_realloc(T* prior, size_t oldSize, size_t newSize) { - return js_pod_realloc(prior, oldSize, newSize); - } - - template - T* pod_malloc(size_t numElems) { - T* p = maybe_pod_malloc(numElems); - if (MOZ_UNLIKELY(!p)) - p = onOutOfMemoryTyped(AllocFunction::Malloc, numElems); - return p; - } - - template - T* pod_calloc(size_t numElems) { - T* p = maybe_pod_calloc(numElems); - if (MOZ_UNLIKELY(!p)) - p = onOutOfMemoryTyped(AllocFunction::Calloc, numElems); - return p; - } - - template - T* pod_realloc(T* prior, size_t oldSize, size_t newSize) { - T* p2 = maybe_pod_realloc(prior, oldSize, newSize); - if (MOZ_UNLIKELY(!p2)) - p2 = onOutOfMemoryTyped(AllocFunction::Realloc, newSize, prior); - return p2; - } - - void free_(void* p) { - js_free(p); - } - - JS_FRIEND_API(void) reportAllocOverflow() const; - - bool checkSimulatedOOM() const { - if (js::oom::ShouldFailWithOOM()) { - js::ReportOutOfMemory(reinterpret_cast(cx_)); - return false; - } - - return true; - } -}; - -} /* namespace js */ - -#endif /* jsalloc_h */ 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,18 +14,18 @@ #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 #include #include #include -#include "jsalloc.h" #include "jspubtd.h" +#include "js/AllocPolicy.h" #include "js/CallArgs.h" #include "js/CharacterEncoding.h" #include "js/Class.h" @@ -34,8 +34,11 @@ #include "js/Id.h" #include "js/Principals.h" #include "js/Realm.h" +#include "js/RefCounted.h" #include "js/RootingAPI.h" +#include "js/Stream.h" #include "js/TracingAPI.h" +#include "js/UniquePtr.h" #include "js/Utility.h" #include "js/Value.h" #include "js/Vector.h" @@ -48,200 +51,50 @@ #ifdef JS_DEBUG -class JS_PUBLIC_API(AutoCheckRequestDepth) -{ - JSContext* cx; - public: - explicit AutoCheckRequestDepth(JSContext* cx); - explicit AutoCheckRequestDepth(js::ContextFriendFields* cx); - ~AutoCheckRequestDepth(); +class JS_PUBLIC_API AutoCheckRequestDepth { + JSContext* cx; + + public: + explicit AutoCheckRequestDepth(JSContext* cx); + ~AutoCheckRequestDepth(); }; -# define CHECK_REQUEST(cx) \ - JS::AutoCheckRequestDepth _autoCheckRequestDepth(cx) +#define CHECK_REQUEST(cx) JS::AutoCheckRequestDepth _autoCheckRequestDepth(cx) #else -# define CHECK_REQUEST(cx) \ - ((void) 0) +#define CHECK_REQUEST(cx) ((void)0) #endif /* JS_DEBUG */ /** AutoValueArray roots an internal fixed-size array of Values. */ template -class MOZ_RAII AutoValueArray : public AutoGCRooter -{ - const size_t length_; - Value elements_[N]; - - public: - explicit AutoValueArray(JSContext* cx - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, VALARRAY), length_(N) - { - /* Always initialize in case we GC before assignment. */ - mozilla::PodArrayZero(elements_); - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - unsigned length() const { return length_; } - const Value* begin() const { return elements_; } - Value* begin() { return elements_; } - - HandleValue operator[](unsigned i) const { - MOZ_ASSERT(i < N); - return HandleValue::fromMarkedLocation(&elements_[i]); - } - MutableHandleValue operator[](unsigned i) { - MOZ_ASSERT(i < N); - return MutableHandleValue::fromMarkedLocation(&elements_[i]); - } - - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -template -class MOZ_RAII AutoVectorRooterBase : protected AutoGCRooter -{ - typedef js::Vector VectorImpl; - VectorImpl vector; - - public: - explicit AutoVectorRooterBase(JSContext* cx, ptrdiff_t tag - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, tag), vector(cx) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - explicit AutoVectorRooterBase(js::ContextFriendFields* cx, ptrdiff_t tag - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, tag), vector(cx) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - typedef T ElementType; - typedef typename VectorImpl::Range Range; - - size_t length() const { return vector.length(); } - bool empty() const { return vector.empty(); } - - 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); - } - - 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); } - - void popBack() { vector.popBack(); } - T popCopy() { return vector.popCopy(); } - - MOZ_MUST_USE bool growBy(size_t inc) { - size_t oldLength = vector.length(); - if (!vector.growByUninitialized(inc)) - return false; - makeRangeGCSafe(oldLength); - return true; - } - - MOZ_MUST_USE bool resize(size_t newLength) { - size_t oldLength = vector.length(); - if (newLength <= oldLength) { - vector.shrinkBy(oldLength - newLength); - return true; - } - if (!vector.growByUninitialized(newLength - oldLength)) - return false; - makeRangeGCSafe(oldLength); - return true; - } - - void clear() { vector.clear(); } - - MOZ_MUST_USE bool reserve(size_t newLength) { - return vector.reserve(newLength); - } - - JS::MutableHandle operator[](size_t i) { - return JS::MutableHandle::fromMarkedLocation(&vector[i]); - } - JS::Handle operator[](size_t i) const { - return JS::Handle::fromMarkedLocation(&vector[i]); - } - - const T* begin() const { return vector.begin(); } - T* begin() { return vector.begin(); } - - const T* end() const { return vector.end(); } - T* end() { return vector.end(); } - - Range all() { return vector.all(); } - - const T& back() const { return vector.back(); } - - friend void AutoGCRooter::trace(JSTracer* trc); - - private: - void makeRangeGCSafe(size_t oldLength) { - T* t = vector.begin() + oldLength; - for (size_t i = oldLength; i < vector.length(); ++i, ++t) - memset(t, 0, sizeof(T)); - } - - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -template -class MOZ_RAII AutoVectorRooter : public AutoVectorRooterBase -{ - public: - explicit AutoVectorRooter(JSContext* cx - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoVectorRooterBase(cx, this->GetTag(T())) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - explicit AutoVectorRooter(js::ContextFriendFields* cx - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoVectorRooterBase(cx, this->GetTag(T())) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -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 MOZ_RAII AutoValueArray : public AutoGCRooter { + const size_t length_; + Value elements_[N]; + + public: + explicit AutoValueArray(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, VALARRAY), length_(N) { + /* Always initialize in case we GC before assignment. */ + mozilla::PodArrayZero(elements_); + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + + unsigned length() const { return length_; } + const Value* begin() const { return elements_; } + Value* begin() { return elements_; } + + HandleValue operator[](unsigned i) const { + MOZ_ASSERT(i < N); + return HandleValue::fromMarkedLocation(&elements_[i]); + } + MutableHandleValue operator[](unsigned i) { + MOZ_ASSERT(i < N); + return MutableHandleValue::fromMarkedLocation(&elements_[i]); + } -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)) {} + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; using ValueVector = JS::GCVector; @@ -249,385 +102,278 @@ using ScriptVector = JS::GCVector; using StringVector = JS::GCVector; -template -class MOZ_RAII AutoHashMapRooter : protected AutoGCRooter -{ - private: - typedef js::HashMap HashMapImpl; +template +class MOZ_RAII AutoHashMapRooter : protected AutoGCRooter { + private: + typedef js::HashMap HashMapImpl; - public: - explicit AutoHashMapRooter(JSContext* cx, ptrdiff_t tag - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, tag), map(cx) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } + public: + explicit AutoHashMapRooter(JSContext* cx, + ptrdiff_t tag MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, tag), map(cx) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } - typedef Key KeyType; - typedef Value ValueType; - typedef typename HashMapImpl::Entry Entry; - typedef typename HashMapImpl::Lookup Lookup; - typedef typename HashMapImpl::Ptr Ptr; - typedef typename HashMapImpl::AddPtr AddPtr; + typedef Key KeyType; + typedef Value ValueType; + typedef typename HashMapImpl::Entry Entry; + typedef typename HashMapImpl::Lookup Lookup; + typedef typename HashMapImpl::Ptr Ptr; + typedef typename HashMapImpl::AddPtr AddPtr; - bool init(uint32_t len = 16) { - return map.init(len); - } - bool initialized() const { - return map.initialized(); - } - Ptr lookup(const Lookup& l) const { - return map.lookup(l); - } - void remove(Ptr p) { - map.remove(p); - } - AddPtr lookupForAdd(const Lookup& l) const { - return map.lookupForAdd(l); - } + bool init(uint32_t len = 16) { return map.init(len); } + bool initialized() const { return map.initialized(); } + Ptr lookup(const Lookup& l) const { return map.lookup(l); } + void remove(Ptr p) { map.remove(p); } + AddPtr lookupForAdd(const Lookup& l) const { return map.lookupForAdd(l); } - template - bool add(AddPtr& p, const KeyInput& k, const ValueInput& v) { - return map.add(p, k, v); - } + template + bool add(AddPtr& p, const KeyInput& k, const ValueInput& v) { + return map.add(p, k, v); + } - bool add(AddPtr& p, const Key& k) { - return map.add(p, k); - } + bool add(AddPtr& p, const Key& k) { return map.add(p, k); } - template - bool relookupOrAdd(AddPtr& p, const KeyInput& k, const ValueInput& v) { - return map.relookupOrAdd(p, k, v); - } + template + bool relookupOrAdd(AddPtr& p, const KeyInput& k, const ValueInput& v) { + return map.relookupOrAdd(p, k, v); + } - typedef typename HashMapImpl::Range Range; - Range all() const { - return map.all(); - } + typedef typename HashMapImpl::Range Range; + Range all() const { return map.all(); } - typedef typename HashMapImpl::Enum Enum; + typedef typename HashMapImpl::Enum Enum; - void clear() { - map.clear(); - } + void clear() { map.clear(); } - void finish() { - map.finish(); - } + void finish() { map.finish(); } - bool empty() const { - return map.empty(); - } + bool empty() const { return map.empty(); } - uint32_t count() const { - return map.count(); - } + uint32_t count() const { return map.count(); } - size_t capacity() const { - return map.capacity(); - } + size_t capacity() const { return map.capacity(); } - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return map.sizeOfExcludingThis(mallocSizeOf); - } - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return map.sizeOfIncludingThis(mallocSizeOf); - } + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return map.sizeOfExcludingThis(mallocSizeOf); + } + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return map.sizeOfIncludingThis(mallocSizeOf); + } - /************************************************** Shorthand operations */ + /************************************************** Shorthand operations */ - bool has(const Lookup& l) const { - return map.has(l); - } + bool has(const Lookup& l) const { return map.has(l); } - template - bool put(const KeyInput& k, const ValueInput& v) { - return map.put(k, v); - } + template + bool put(const KeyInput& k, const ValueInput& v) { + return map.put(k, v); + } - template - bool putNew(const KeyInput& k, const ValueInput& v) { - return map.putNew(k, v); - } + template + bool putNew(const KeyInput& k, const ValueInput& v) { + return map.putNew(k, v); + } - Ptr lookupWithDefault(const Key& k, const Value& defaultValue) { - return map.lookupWithDefault(k, defaultValue); - } + Ptr lookupWithDefault(const Key& k, const Value& defaultValue) { + return map.lookupWithDefault(k, defaultValue); + } - void remove(const Lookup& l) { - map.remove(l); - } + void remove(const Lookup& l) { map.remove(l); } - friend void AutoGCRooter::trace(JSTracer* trc); + friend void AutoGCRooter::trace(JSTracer* trc); - private: - AutoHashMapRooter(const AutoHashMapRooter& hmr) = delete; - AutoHashMapRooter& operator=(const AutoHashMapRooter& hmr) = delete; + private: + AutoHashMapRooter(const AutoHashMapRooter& hmr) = delete; + AutoHashMapRooter& operator=(const AutoHashMapRooter& hmr) = delete; - HashMapImpl map; + HashMapImpl map; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; -template -class MOZ_RAII AutoHashSetRooter : protected AutoGCRooter -{ - private: - typedef js::HashSet HashSetImpl; +template +class MOZ_RAII AutoHashSetRooter : protected AutoGCRooter { + private: + typedef js::HashSet HashSetImpl; - public: - explicit AutoHashSetRooter(JSContext* cx, ptrdiff_t tag - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, tag), set(cx) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } + public: + explicit AutoHashSetRooter(JSContext* cx, + ptrdiff_t tag MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, tag), set(cx) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } - typedef typename HashSetImpl::Lookup Lookup; - typedef typename HashSetImpl::Ptr Ptr; - typedef typename HashSetImpl::AddPtr AddPtr; + typedef typename HashSetImpl::Lookup Lookup; + typedef typename HashSetImpl::Ptr Ptr; + typedef typename HashSetImpl::AddPtr AddPtr; - bool init(uint32_t len = 16) { - return set.init(len); - } - bool initialized() const { - return set.initialized(); - } - Ptr lookup(const Lookup& l) const { - return set.lookup(l); - } - void remove(Ptr p) { - set.remove(p); - } - AddPtr lookupForAdd(const Lookup& l) const { - return set.lookupForAdd(l); - } + bool init(uint32_t len = 16) { return set.init(len); } + bool initialized() const { return set.initialized(); } + Ptr lookup(const Lookup& l) const { return set.lookup(l); } + void remove(Ptr p) { set.remove(p); } + AddPtr lookupForAdd(const Lookup& l) const { return set.lookupForAdd(l); } - bool add(AddPtr& p, const T& t) { - return set.add(p, t); - } + bool add(AddPtr& p, const T& t) { return set.add(p, t); } - bool relookupOrAdd(AddPtr& p, const Lookup& l, const T& t) { - return set.relookupOrAdd(p, l, t); - } + bool relookupOrAdd(AddPtr& p, const Lookup& l, const T& t) { + return set.relookupOrAdd(p, l, t); + } - typedef typename HashSetImpl::Range Range; - Range all() const { - return set.all(); - } + typedef typename HashSetImpl::Range Range; + Range all() const { return set.all(); } - typedef typename HashSetImpl::Enum Enum; + typedef typename HashSetImpl::Enum Enum; - void clear() { - set.clear(); - } + void clear() { set.clear(); } - void finish() { - set.finish(); - } + void finish() { set.finish(); } - bool empty() const { - return set.empty(); - } + bool empty() const { return set.empty(); } - uint32_t count() const { - return set.count(); - } + uint32_t count() const { return set.count(); } - size_t capacity() const { - return set.capacity(); - } + size_t capacity() const { return set.capacity(); } - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return set.sizeOfExcludingThis(mallocSizeOf); - } - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return set.sizeOfIncludingThis(mallocSizeOf); - } + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return set.sizeOfExcludingThis(mallocSizeOf); + } + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return set.sizeOfIncludingThis(mallocSizeOf); + } - /************************************************** Shorthand operations */ + /************************************************** Shorthand operations */ - bool has(const Lookup& l) const { - return set.has(l); - } + bool has(const Lookup& l) const { return set.has(l); } - bool put(const T& t) { - return set.put(t); - } + bool put(const T& t) { return set.put(t); } - bool putNew(const T& t) { - return set.putNew(t); - } + bool putNew(const T& t) { return set.putNew(t); } - void remove(const Lookup& l) { - set.remove(l); - } + void remove(const Lookup& l) { set.remove(l); } - friend void AutoGCRooter::trace(JSTracer* trc); + friend void AutoGCRooter::trace(JSTracer* trc); - private: - AutoHashSetRooter(const AutoHashSetRooter& hmr) = delete; - AutoHashSetRooter& operator=(const AutoHashSetRooter& hmr) = delete; + private: + AutoHashSetRooter(const AutoHashSetRooter& hmr) = delete; + AutoHashSetRooter& operator=(const AutoHashSetRooter& hmr) = delete; - HashSetImpl set; + HashSetImpl set; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; /** * Custom rooting behavior for internal and external clients. */ -class MOZ_RAII JS_PUBLIC_API(CustomAutoRooter) : private AutoGCRooter -{ - public: - template - explicit CustomAutoRooter(const CX& cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, CUSTOM) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - friend void AutoGCRooter::trace(JSTracer* trc); +class MOZ_RAII JS_PUBLIC_API CustomAutoRooter : private AutoGCRooter { + public: + template + explicit CustomAutoRooter(const CX& cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, CUSTOM) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + + friend void AutoGCRooter::trace(JSTracer* trc); - protected: - virtual ~CustomAutoRooter() {} + protected: + virtual ~CustomAutoRooter() {} - /** Supplied by derived class to trace roots. */ - virtual void trace(JSTracer* trc) = 0; + /** Supplied by derived class to trace roots. */ + virtual void trace(JSTracer* trc) = 0; - private: - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + private: + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; /** A handle to an array of rooted values. */ -class HandleValueArray -{ - const size_t length_; - const Value * const elements_; - - HandleValueArray(size_t len, const Value* elements) : length_(len), elements_(elements) {} - - public: - explicit HandleValueArray(const RootedValue& value) : length_(1), elements_(value.address()) {} +class HandleValueArray { + const size_t length_; + const Value* const elements_; + + HandleValueArray(size_t len, const Value* elements) + : length_(len), elements_(elements) {} + + public: + explicit HandleValueArray(HandleValue value) + : length_(1), elements_(value.address()) {} - MOZ_IMPLICIT HandleValueArray(const AutoValueVector& values) + MOZ_IMPLICIT HandleValueArray(const AutoValueVector& values) : length_(values.length()), elements_(values.begin()) {} - template - MOZ_IMPLICIT HandleValueArray(const AutoValueArray& values) : length_(N), elements_(values.begin()) {} - - /** CallArgs must already be rooted somewhere up the stack. */ - MOZ_IMPLICIT HandleValueArray(const JS::CallArgs& args) : length_(args.length()), elements_(args.array()) {} + template + MOZ_IMPLICIT HandleValueArray(const AutoValueArray& values) + : length_(N), elements_(values.begin()) {} + + /** CallArgs must already be rooted somewhere up the stack. */ + MOZ_IMPLICIT HandleValueArray(const JS::CallArgs& args) + : length_(args.length()), elements_(args.array()) {} + + /** Use with care! Only call this if the data is guaranteed to be marked. */ + static HandleValueArray fromMarkedLocation(size_t len, + const Value* elements) { + return HandleValueArray(len, elements); + } + + static HandleValueArray subarray(const HandleValueArray& values, + size_t startIndex, size_t len) { + MOZ_ASSERT(startIndex + len <= values.length()); + return HandleValueArray(len, values.begin() + startIndex); + } + + static HandleValueArray empty() { return HandleValueArray(0, nullptr); } + + size_t length() const { return length_; } + const Value* begin() const { return elements_; } + + HandleValue operator[](size_t i) const { + MOZ_ASSERT(i < length_); + return HandleValue::fromMarkedLocation(&elements_[i]); + } +}; - /** Use with care! Only call this if the data is guaranteed to be marked. */ - static HandleValueArray fromMarkedLocation(size_t len, const Value* elements) { - return HandleValueArray(len, elements); - } +} /* namespace JS */ - static HandleValueArray subarray(const HandleValueArray& values, size_t startIndex, size_t len) { - MOZ_ASSERT(startIndex + len <= values.length()); - return HandleValueArray(len, values.begin() + startIndex); - } +/************************************************************************/ - static HandleValueArray empty() { - return HandleValueArray(0, nullptr); - } +struct JSFreeOp { + protected: + JSRuntime* runtime_; - size_t length() const { return length_; } - const Value* begin() const { return elements_; } + explicit JSFreeOp(JSRuntime* rt) : runtime_(rt) {} - HandleValue operator[](size_t i) const { - MOZ_ASSERT(i < length_); - return HandleValue::fromMarkedLocation(&elements_[i]); - } + public: + JSRuntime* runtime() const { + MOZ_ASSERT(runtime_); + return runtime_; + } }; -} /* namespace JS */ +/* Callbacks and their arguments. */ /************************************************************************/ -struct JSFreeOp { - protected: - JSRuntime* runtime_; +typedef bool (*JSInterruptCallback)(JSContext* cx); - explicit JSFreeOp(JSRuntime* rt) - : runtime_(rt) { } +typedef JSObject* (*JSGetIncumbentGlobalCallback)(JSContext* cx); - public: - JSRuntime* runtime() const { - MOZ_ASSERT(runtime_); - return runtime_; - } -}; +typedef bool (*JSEnqueuePromiseJobCallback)(JSContext* cx, JS::HandleObject job, + JS::HandleObject allocationSite, + JS::HandleObject incumbentGlobal, + void* data); -/* Callbacks and their arguments. */ +namespace JS { -/************************************************************************/ +enum class PromiseRejectionHandlingState { Unhandled, Handled }; -typedef enum JSGCStatus { - JSGC_BEGIN, - JSGC_END -} JSGCStatus; - -typedef void -(* 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 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 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. - */ - JSFINALIZE_GROUP_END, - - /** - * Called at the end of collection when everything has been swept. - */ - JSFINALIZE_COLLECTION_END -} JSFinalizeStatus; - -typedef void -(* JSFinalizeCallback)(JSFreeOp* fop, JSFinalizeStatus status, bool isZoneGC, void* data); - -typedef void -(* JSWeakPointerZoneGroupCallback)(JSContext* cx, void* data); - -typedef void -(* 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 -(* JSPromiseRejectionTrackerCallback)(JSContext* cx, JS::HandleObject promise, - PromiseRejectionHandlingState state, void* data); +} /* namespace JS */ + +typedef void (*JSPromiseRejectionTrackerCallback)( + JSContext* cx, JS::HandleObject promise, + JS::PromiseRejectionHandlingState state, void* data); -typedef void -(* JSProcessPromiseCallback)(JSContext* cx, JS::HandleObject promise); +typedef void (*JSProcessPromiseCallback)(JSContext* cx, + JS::HandleObject promise); /** * Possible exception types. These types are part of a JSErrorFormatString @@ -638,51 +384,54 @@ * if we ever decide to use an entirely separate mechanism for warnings. */ typedef enum JSExnType { - JSEXN_ERR, - JSEXN_FIRST = JSEXN_ERR, - JSEXN_INTERNALERR, - JSEXN_EVALERR, - JSEXN_RANGEERR, - JSEXN_REFERENCEERR, - JSEXN_SYNTAXERR, - JSEXN_TYPEERR, - JSEXN_URIERR, - JSEXN_DEBUGGEEWOULDRUN, - JSEXN_WASMCOMPILEERROR, - JSEXN_WASMRUNTIMEERROR, - JSEXN_WARN, - JSEXN_LIMIT + JSEXN_ERR, + JSEXN_FIRST = JSEXN_ERR, + JSEXN_INTERNALERR, + JSEXN_EVALERR, + JSEXN_RANGEERR, + JSEXN_REFERENCEERR, + JSEXN_SYNTAXERR, + JSEXN_TYPEERR, + JSEXN_URIERR, + JSEXN_DEBUGGEEWOULDRUN, + JSEXN_WASMCOMPILEERROR, + JSEXN_WASMLINKERROR, + JSEXN_WASMRUNTIMEERROR, + JSEXN_ERROR_LIMIT, + JSEXN_WARN = JSEXN_ERROR_LIMIT, + JSEXN_NOTE, + JSEXN_LIMIT } JSExnType; -typedef struct JSErrorFormatString { - /** The error message name in ASCII. */ - const char* name; +struct JSErrorFormatString { + /** The error message name in ASCII. */ + const char* name; - /** The error format string in ASCII. */ - const char* format; + /** The error format string in ASCII. */ + const char* format; - /** The number of arguments to expand in the formatted error message. */ - uint16_t argCount; + /** The number of arguments to expand in the formatted error message. */ + uint16_t argCount; - /** One of the JSExnType constants above. */ - int16_t exnType; -} JSErrorFormatString; + /** One of the JSExnType constants above. */ + int16_t exnType; +}; -typedef const JSErrorFormatString* -(* JSErrorCallback)(void* userRef, const unsigned errorNumber); +typedef const JSErrorFormatString* (*JSErrorCallback)( + void* userRef, const unsigned errorNumber); -typedef bool -(* JSLocaleToUpperCase)(JSContext* cx, JS::HandleString src, JS::MutableHandleValue rval); +typedef bool (*JSLocaleToUpperCase)(JSContext* cx, JS::HandleString src, + JS::MutableHandleValue rval); -typedef bool -(* JSLocaleToLowerCase)(JSContext* cx, JS::HandleString src, JS::MutableHandleValue rval); +typedef bool (*JSLocaleToLowerCase)(JSContext* cx, JS::HandleString src, + JS::MutableHandleValue rval); -typedef bool -(* JSLocaleCompare)(JSContext* cx, JS::HandleString src1, JS::HandleString src2, - JS::MutableHandleValue rval); +typedef bool (*JSLocaleCompare)(JSContext* cx, JS::HandleString src1, + JS::HandleString src2, + JS::MutableHandleValue rval); -typedef bool -(* JSLocaleToUnicode)(JSContext* cx, const char* src, JS::MutableHandleValue rval); +typedef bool (*JSLocaleToUnicode)(JSContext* cx, const char* src, + JS::MutableHandleValue rval); /** * Callback used to ask the embedding for the cross compartment wrapper handler @@ -693,55 +442,70 @@ * wrapper with a lazily-defined prototype and the correct global. It is * guaranteed not to wrap a function. */ -typedef JSObject* -(* JSWrapObjectCallback)(JSContext* cx, JS::HandleObject existing, JS::HandleObject obj); +typedef JSObject* (*JSWrapObjectCallback)(JSContext* cx, + JS::HandleObject existing, + JS::HandleObject obj); /** * Callback used by the wrap hook to ask the embedding to prepare an object * for wrapping in a context. This might include unwrapping other wrappers * or even finding a more suitable object for the new compartment. */ -typedef void -(* JSPreWrapCallback)(JSContext* cx, JS::HandleObject scope, JS::HandleObject obj, - JS::HandleObject objectPassedToWrap, - JS::MutableHandleObject retObj); - -struct JSWrapObjectCallbacks -{ - JSWrapObjectCallback wrap; - JSPreWrapCallback preWrap; -}; +typedef void (*JSPreWrapCallback)(JSContext* cx, JS::HandleObject scope, + JS::HandleObject obj, + JS::HandleObject objectPassedToWrap, + JS::MutableHandleObject retObj); -typedef void -(* JSDestroyCompartmentCallback)(JSFreeOp* fop, JSCompartment* compartment); +struct JSWrapObjectCallbacks { + JSWrapObjectCallback wrap; + JSPreWrapCallback preWrap; +}; -typedef size_t -(* JSSizeOfIncludingThisCompartmentCallback)(mozilla::MallocSizeOf mallocSizeOf, +typedef void (*JSDestroyCompartmentCallback)(JSFreeOp* fop, JSCompartment* compartment); -typedef void -(* JSZoneCallback)(JS::Zone* zone); +typedef size_t (*JSSizeOfIncludingThisCompartmentCallback)( + mozilla::MallocSizeOf mallocSizeOf, JSCompartment* compartment); -typedef void -(* JSCompartmentNameCallback)(JSContext* cx, JSCompartment* compartment, - char* buf, size_t bufsize); +typedef void (*JSCompartmentNameCallback)(JSContext* cx, + JSCompartment* compartment, char* buf, + size_t bufsize); + +/** + * Callback used by memory reporting to ask the embedder how much memory an + * external string is keeping alive. The embedder is expected to return a value + * that corresponds to the size of the allocation that will be released by the + * JSStringFinalizer passed to JS_NewExternalString for this string. + * + * Implementations of this callback MUST NOT do anything that can cause GC. + */ +using JSExternalStringSizeofCallback = + size_t (*)(JSString* str, mozilla::MallocSizeOf mallocSizeOf); + +/** + * Callback used to intercept JavaScript errors. + */ +struct JSErrorInterceptor { + /** + * This method is called whenever an error has been raised from JS code. + * + * This method MUST be infallible. + */ + virtual void interceptError(JSContext* cx, const JS::Value& error) = 0; +}; /************************************************************************/ -static MOZ_ALWAYS_INLINE JS::Value -JS_NumberValue(double d) -{ - int32_t i; - d = JS::CanonicalizeNaN(d); - if (mozilla::NumberIsInt32(d, &i)) - return JS::Int32Value(i); - return JS::DoubleValue(d); +static MOZ_ALWAYS_INLINE JS::Value JS_NumberValue(double d) { + int32_t i; + d = JS::CanonicalizeNaN(d); + if (mozilla::NumberIsInt32(d, &i)) return JS::Int32Value(i); + return JS::DoubleValue(d); } /************************************************************************/ -JS_PUBLIC_API(bool) -JS_StringHasBeenPinned(JSContext* cx, JSString* str); +JS_PUBLIC_API bool JS_StringHasBeenPinned(JSContext* cx, JSString* str); namespace JS { @@ -762,85 +526,81 @@ * Example use: * * size_t length = 512; - * char16_t* chars = static_cast(js_malloc(sizeof(char16_t) * length)); - * JS::SourceBufferHolder srcBuf(chars, length, JS::SourceBufferHolder::GiveOwnership); - * JS::Compile(cx, options, srcBuf); - */ -class MOZ_STACK_CLASS SourceBufferHolder final -{ - public: - enum Ownership { - NoOwnership, - GiveOwnership - }; + * char16_t* chars = static_cast(js_malloc(sizeof(char16_t) * + * length)); JS::SourceBufferHolder srcBuf(chars, length, + * JS::SourceBufferHolder::GiveOwnership); JS::Compile(cx, options, srcBuf); + */ +class MOZ_STACK_CLASS SourceBufferHolder final { + public: + enum Ownership { NoOwnership, GiveOwnership }; - SourceBufferHolder(const char16_t* data, size_t dataLength, Ownership ownership) + SourceBufferHolder(const char16_t* data, size_t dataLength, + Ownership ownership) : data_(data), length_(dataLength), - ownsChars_(ownership == GiveOwnership) - { - // Ensure that null buffers properly return an unowned, empty, - // null-terminated string. - static const char16_t NullChar_ = 0; - if (!get()) { - data_ = &NullChar_; - length_ = 0; - ownsChars_ = false; - } + ownsChars_(ownership == GiveOwnership) { + // Ensure that null buffers properly return an unowned, empty, + // null-terminated string. + static const char16_t NullChar_ = 0; + if (!get()) { + data_ = &NullChar_; + length_ = 0; + ownsChars_ = false; } + } - SourceBufferHolder(SourceBufferHolder&& other) + 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_)); - } - - // Access the underlying source buffer without affecting ownership. - const char16_t* get() const { return data_; } - - // Length of the source buffer in char16_t code units (not bytes) - size_t length() const { return length_; } - - // Returns true if the SourceBufferHolder owns the buffer and will free - // it upon destruction. If true, it is legal to call take(). - bool ownsChars() const { return ownsChars_; } - - // Retrieve and take ownership of the underlying data buffer. The caller - // is now responsible for calling js_free() on the returned value, *but only - // after JS script compilation has completed*. - // - // After the buffer has been taken the SourceBufferHolder functions as if - // it had been constructed on an unowned buffer; get() and length() still - // work. In order for this to be safe the taken buffer must be kept alive - // until after JS script compilation completes as noted above. - // - // Note, it's the caller's responsibility to check ownsChars() before taking - // the buffer. Taking and then free'ing an unowned buffer will have dire - // consequences. - char16_t* take() { - MOZ_ASSERT(ownsChars_); - ownsChars_ = false; - return const_cast(data_); - } - - private: - SourceBufferHolder(SourceBufferHolder&) = delete; - SourceBufferHolder& operator=(SourceBufferHolder&) = delete; - - const char16_t* data_; - size_t length_; - bool ownsChars_; + ownsChars_(other.ownsChars_) { + other.data_ = nullptr; + other.length_ = 0; + other.ownsChars_ = false; + } + + ~SourceBufferHolder() { + if (ownsChars_) js_free(const_cast(data_)); + } + + // Access the underlying source buffer without affecting ownership. + const char16_t* get() const { return data_; } + + // Length of the source buffer in char16_t code units (not bytes) + size_t length() const { return length_; } + + // Returns true if the SourceBufferHolder owns the buffer and will free + // it upon destruction. If true, it is legal to call take(). + bool ownsChars() const { return ownsChars_; } + + // Retrieve and take ownership of the underlying data buffer. The caller + // is now responsible for calling js_free() on the returned value, *but only + // after JS script compilation has completed*. + // + // After the buffer has been taken the SourceBufferHolder functions as if + // it had been constructed on an unowned buffer; get() and length() still + // work. In order for this to be safe the taken buffer must be kept alive + // until after JS script compilation completes as noted above. + // + // Note, it's the caller's responsibility to check ownsChars() before taking + // the buffer. Taking and then free'ing an unowned buffer will have dire + // consequences. + char16_t* take() { + MOZ_ASSERT(ownsChars_); + ownsChars_ = false; + return const_cast(data_); + } + + private: + SourceBufferHolder(SourceBufferHolder&) = delete; + SourceBufferHolder& operator=(SourceBufferHolder&) = delete; + + const char16_t* data_; + size_t length_; + bool ownsChars_; }; +struct TranscodeSource; + } /* namespace JS */ /************************************************************************/ @@ -851,41 +611,42 @@ * a uint8_t to store the relevant information. Proceed with caution if * trying to reorder or change the the first byte worth of flags. */ -#define JSPROP_ENUMERATE 0x01 /* property is visible to for/in loop */ -#define JSPROP_READONLY 0x02 /* not settable: assignment is no-op. - This flag is only valid when neither - JSPROP_GETTER nor JSPROP_SETTER is - set. */ -#define JSPROP_PERMANENT 0x04 /* property cannot be deleted */ -#define JSPROP_PROPOP_ACCESSORS 0x08 /* Passed to JS_Define(UC)Property* and - JS_DefineElement if getters/setters - are JSGetterOp/JSSetterOp */ -#define JSPROP_GETTER 0x10 /* property holds getter function */ -#define JSPROP_SETTER 0x20 /* property holds setter function */ -#define JSPROP_SHARED 0x40 /* don't allocate a value slot for this - property; don't copy the property on - set of the same-named property in an - object that delegates to a prototype - containing this property */ -#define JSPROP_INTERNAL_USE_BIT 0x80 /* internal JS engine use only */ -#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 */ +/* property is visible to for/in loop */ +static const uint8_t JSPROP_ENUMERATE = 0x01; + +/* not settable: assignment is no-op. This flag is only valid when neither + JSPROP_GETTER nor JSPROP_SETTER is set. */ +static const uint8_t JSPROP_READONLY = 0x02; + +/* property cannot be deleted */ +static const uint8_t JSPROP_PERMANENT = 0x04; + +/* Passed to JS_Define(UC)Property* and JS_DefineElement if getters/setters are + JSGetterOp/JSSetterOp */ +static const uint8_t JSPROP_PROPOP_ACCESSORS = 0x08; + +/* property holds getter function */ +static const uint8_t JSPROP_GETTER = 0x10; -// 0x800 /* Unused */ +/* property holds setter function */ +static const uint8_t JSPROP_SETTER = 0x20; -#define JSFUN_HAS_REST 0x1000 /* function has ...rest parameter. */ +/* internal JS engine use only */ +static const uint8_t JSPROP_INTERNAL_USE_BIT = 0x80; -#define JSFUN_FLAGS_MASK 0x1e00 /* | of all the JSFUN_* flags */ +/* native that can be called as a ctor */ +static const unsigned JSFUN_CONSTRUCTOR = 0x400; + +/* | of all the JSFUN_* flags */ +static const unsigned JSFUN_FLAGS_MASK = 0x400; /* * If set, will allow redefining a non-configurable property, but only on a * non-DOM global. This is a temporary hack that will need to go away in bug * 1105518. */ -#define JSPROP_REDEFINE_NONCONFIGURABLE 0x1000 +static const unsigned JSPROP_REDEFINE_NONCONFIGURABLE = 0x1000; /* * Resolve hooks and enumerate hooks must pass this flag when calling @@ -899,82 +660,79 @@ * For enumerate hooks, triggering the resolve hook would be merely silly, not * fatal, except in some cases involving non-configurable properties. */ -#define JSPROP_RESOLVING 0x2000 +static const unsigned JSPROP_RESOLVING = 0x2000; -#define JSPROP_IGNORE_ENUMERATE 0x4000 /* ignore the value in JSPROP_ENUMERATE. - This flag only valid when defining over - an existing property. */ -#define JSPROP_IGNORE_READONLY 0x8000 /* ignore the value in JSPROP_READONLY. - This flag only valid when defining over - an existing property. */ -#define JSPROP_IGNORE_PERMANENT 0x10000 /* ignore the value in JSPROP_PERMANENT. - This flag only valid when defining over - an existing property. */ -#define JSPROP_IGNORE_VALUE 0x20000 /* ignore the Value in the descriptor. Nothing was - specified when passed to Object.defineProperty - from script. */ +/* ignore the value in JSPROP_ENUMERATE. This flag only valid when defining + over an existing property. */ +static const unsigned JSPROP_IGNORE_ENUMERATE = 0x4000; + +/* ignore the value in JSPROP_READONLY. This flag only valid when defining over + an existing property. */ +static const unsigned JSPROP_IGNORE_READONLY = 0x8000; + +/* ignore the value in JSPROP_PERMANENT. This flag only valid when defining + over an existing property. */ +static const unsigned JSPROP_IGNORE_PERMANENT = 0x10000; + +/* ignore the Value in the descriptor. Nothing was specified when passed to + Object.defineProperty from script. */ +static const unsigned JSPROP_IGNORE_VALUE = 0x20000; /** Microseconds since the epoch, midnight, January 1, 1970 UTC. */ -extern JS_PUBLIC_API(int64_t) -JS_Now(void); +extern JS_PUBLIC_API int64_t JS_Now(void); /** Don't want to export data, so provide accessors for non-inline Values. */ -extern JS_PUBLIC_API(JS::Value) -JS_GetNaNValue(JSContext* cx); +extern JS_PUBLIC_API JS::Value JS_GetNaNValue(JSContext* cx); -extern JS_PUBLIC_API(JS::Value) -JS_GetNegativeInfinityValue(JSContext* cx); +extern JS_PUBLIC_API JS::Value JS_GetNegativeInfinityValue(JSContext* cx); -extern JS_PUBLIC_API(JS::Value) -JS_GetPositiveInfinityValue(JSContext* cx); +extern JS_PUBLIC_API JS::Value JS_GetPositiveInfinityValue(JSContext* cx); -extern JS_PUBLIC_API(JS::Value) -JS_GetEmptyStringValue(JSContext* cx); +extern JS_PUBLIC_API JS::Value JS_GetEmptyStringValue(JSContext* cx); -extern JS_PUBLIC_API(JSString*) -JS_GetEmptyString(JSContext* cx); +extern JS_PUBLIC_API JSString* JS_GetEmptyString(JSContext* cx); -extern JS_PUBLIC_API(bool) -JS_ValueToObject(JSContext* cx, JS::HandleValue v, JS::MutableHandleObject objp); +extern JS_PUBLIC_API bool JS_ValueToObject(JSContext* cx, JS::HandleValue v, + JS::MutableHandleObject objp); -extern JS_PUBLIC_API(JSFunction*) -JS_ValueToFunction(JSContext* cx, JS::HandleValue v); +extern JS_PUBLIC_API JSFunction* JS_ValueToFunction(JSContext* cx, + JS::HandleValue v); -extern JS_PUBLIC_API(JSFunction*) -JS_ValueToConstructor(JSContext* cx, JS::HandleValue v); +extern JS_PUBLIC_API JSFunction* JS_ValueToConstructor(JSContext* cx, + JS::HandleValue v); -extern JS_PUBLIC_API(JSString*) -JS_ValueToSource(JSContext* cx, JS::Handle v); +extern JS_PUBLIC_API JSString* JS_ValueToSource(JSContext* cx, + JS::Handle v); -extern JS_PUBLIC_API(bool) -JS_DoubleIsInt32(double d, int32_t* ip); +extern JS_PUBLIC_API bool JS_DoubleIsInt32(double d, int32_t* ip); -extern JS_PUBLIC_API(JSType) -JS_TypeOfValue(JSContext* cx, JS::Handle v); +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); +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); - -extern JS_PUBLIC_API(bool) -JS_LooselyEqual(JSContext* cx, JS::Handle v1, JS::Handle v2, bool* equal); +extern JS_PUBLIC_API bool JS_StrictlyEqual(JSContext* cx, + JS::Handle v1, + JS::Handle v2, + bool* equal); + +extern JS_PUBLIC_API bool JS_LooselyEqual(JSContext* cx, + JS::Handle v1, + JS::Handle v2, + bool* equal); -extern JS_PUBLIC_API(bool) -JS_SameValue(JSContext* cx, JS::Handle v1, JS::Handle v2, bool* same); +extern JS_PUBLIC_API bool JS_SameValue(JSContext* cx, JS::Handle v1, + JS::Handle v2, bool* same); /** True iff fun is the global eval function. */ -extern JS_PUBLIC_API(bool) -JS_IsBuiltinEvalFunction(JSFunction* fun); +extern JS_PUBLIC_API bool JS_IsBuiltinEvalFunction(JSFunction* fun); /** True iff fun is the Function constructor. */ -extern JS_PUBLIC_API(bool) -JS_IsBuiltinFunctionConstructor(JSFunction* fun); +extern JS_PUBLIC_API bool JS_IsBuiltinFunctionConstructor(JSFunction* fun); /************************************************************************/ @@ -984,78 +742,112 @@ * 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 + * See: + * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference */ -extern JS_PUBLIC_API(JSContext*) -JS_NewContext(uint32_t maxbytes, - uint32_t maxNurseryBytes = JS::DefaultNurseryBytes, - JSContext* parentContext = nullptr); +// Create a new runtime, with a single cooperative context for this thread. +// On success, the new context will be the active context for the runtime. +extern JS_PUBLIC_API JSContext* JS_NewContext( + uint32_t maxbytes, uint32_t maxNurseryBytes = JS::DefaultNurseryBytes, + JSRuntime* parentRuntime = nullptr); + +// The methods below for controlling the active context in a cooperatively +// multithreaded runtime are not threadsafe, and the caller must ensure they +// are called serially if there is a chance for contention between threads. + +// Called from the active context for a runtime, yield execution so that +// this context is no longer active and can no longer use the API. +extern JS_PUBLIC_API void JS_YieldCooperativeContext(JSContext* cx); + +// Called from a context whose runtime has no active context, this thread +// becomes the active context for that runtime and may use the API. +extern JS_PUBLIC_API void JS_ResumeCooperativeContext(JSContext* cx); + +// Create a new context on this thread for cooperative multithreading in the +// same runtime as siblingContext. Called on a runtime (as indicated by +// siblingContet) which has no active context, on success the new context will +// become the runtime's active context. +extern JS_PUBLIC_API JSContext* JS_NewCooperativeContext( + JSContext* siblingContext); -extern JS_PUBLIC_API(void) -JS_DestroyContext(JSContext* cx); +namespace JS { -typedef double (*JS_CurrentEmbedderTimeFunction)(); +// Class to relinquish exclusive access to all zone groups in use by this +// thread. This allows other cooperative threads to enter the zone groups +// and modify their contents. +struct AutoRelinquishZoneGroups { + explicit AutoRelinquishZoneGroups(JSContext* cx); + ~AutoRelinquishZoneGroups(); -/** - * The embedding can specify a time function that will be used in some - * situations. The function can return the time however it likes; but - * the norm is to return times in units of milliseconds since an - * arbitrary, but consistent, epoch. If the time function is not set, - * a built-in default will be used. - */ -JS_PUBLIC_API(void) -JS_SetCurrentEmbedderTimeFunction(JS_CurrentEmbedderTimeFunction timeFn); + private: + JSContext* cx; + mozilla::Vector enterList; +}; -/** - * Return the time as computed using the current time function, or a - * suitable default if one has not been set. - */ -JS_PUBLIC_API(double) -JS_GetCurrentEmbedderTime(); +} // namespace JS + +// Destroy a context allocated with JS_NewContext or JS_NewCooperativeContext. +// The context must be the current active context in the runtime, and after +// this call the runtime will have no active context. +extern JS_PUBLIC_API void JS_DestroyContext(JSContext* cx); -JS_PUBLIC_API(void*) -JS_GetContextPrivate(JSContext* cx); +JS_PUBLIC_API void* JS_GetContextPrivate(JSContext* cx); -JS_PUBLIC_API(void) -JS_SetContextPrivate(JSContext* cx, void* data); +JS_PUBLIC_API void JS_SetContextPrivate(JSContext* cx, void* data); -extern JS_PUBLIC_API(JSContext*) -JS_GetParentContext(JSContext* cx); +extern JS_PUBLIC_API JSRuntime* JS_GetParentRuntime(JSContext* cx); -extern JS_PUBLIC_API(void) -JS_BeginRequest(JSContext* cx); +extern JS_PUBLIC_API JSRuntime* JS_GetRuntime(JSContext* cx); -extern JS_PUBLIC_API(void) -JS_EndRequest(JSContext* cx); +extern JS_PUBLIC_API void JS_BeginRequest(JSContext* cx); -extern JS_PUBLIC_API(void) -JS_SetFutexCanWait(JSContext* cx); +extern JS_PUBLIC_API void JS_EndRequest(JSContext* cx); + +extern JS_PUBLIC_API void JS_SetFutexCanWait(JSContext* cx); + +namespace JS { + +// Single threaded execution callbacks are used to notify API clients that a +// feature is in use on a context's runtime that is not yet compatible with +// cooperatively multithreaded execution. +// +// Between a call to BeginSingleThreadedExecutionCallback and a corresponding +// call to EndSingleThreadedExecutionCallback, only one thread at a time may +// enter compartments in the runtime. The begin callback may yield as necessary +// to permit other threads to finish up what they're doing, while the end +// callback may not yield or otherwise operate on the runtime (it may be called +// during GC). +// +// These callbacks may be left unspecified for runtimes which only ever have a +// single context. +typedef void (*BeginSingleThreadedExecutionCallback)(JSContext* cx); +typedef void (*EndSingleThreadedExecutionCallback)(JSContext* cx); + +extern JS_PUBLIC_API void SetSingleThreadedExecutionCallbacks( + JSContext* cx, BeginSingleThreadedExecutionCallback begin, + EndSingleThreadedExecutionCallback end); + +} // namespace JS namespace js { -void -AssertHeapIsIdle(JSRuntime* rt); +void AssertHeapIsIdle(); } /* namespace js */ -class MOZ_RAII JSAutoRequest -{ - public: - explicit JSAutoRequest(JSContext* cx - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - JS_BeginRequest(mContext); - } - ~JSAutoRequest() { - JS_EndRequest(mContext); - } - - protected: - JSContext* mContext; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +class MOZ_RAII JSAutoRequest { + public: + explicit JSAutoRequest(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + JS_BeginRequest(mContext); + } + ~JSAutoRequest() { JS_EndRequest(mContext); } + + protected: + JSContext* mContext; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER #if 0 private: @@ -1064,250 +856,320 @@ #endif }; -extern JS_PUBLIC_API(JSVersion) -JS_GetVersion(JSContext* cx); - -/** - * Mutate the version on the compartment. This is generally discouraged, but - * necessary to support the version mutation in the js and xpc shell command - * set. - * - * It would be nice to put this in jsfriendapi, but the linkage requirements - * of the shells make that impossible. - */ -JS_PUBLIC_API(void) -JS_SetVersionForCompartment(JSCompartment* compartment, JSVersion version); - -extern JS_PUBLIC_API(const char*) -JS_VersionToString(JSVersion version); - -extern JS_PUBLIC_API(JSVersion) -JS_StringToVersion(const char* string); - namespace JS { -class JS_PUBLIC_API(ContextOptions) { - public: - ContextOptions() +class JS_PUBLIC_API ContextOptions { + public: + ContextOptions() : baseline_(true), ion_(true), asmJS_(true), - wasm_(false), - wasmAlwaysBaseline_(false), + wasm_(true), + wasmBaseline_(true), + wasmIon_(true), + testWasmAwaitTier2_(false), throwOnAsmJSValidationFailure_(false), nativeRegExp_(true), - unboxedArrays_(false), asyncStack_(true), throwOnDebuggeeWouldRun_(true), dumpStackOnDebuggeeWouldRun_(false), werror_(false), strictMode_(false), - extraWarnings_(false) - { - } - - bool baseline() const { return baseline_; } - ContextOptions& setBaseline(bool flag) { - baseline_ = flag; - return *this; - } - ContextOptions& toggleBaseline() { - baseline_ = !baseline_; - return *this; - } - - bool ion() const { return ion_; } - ContextOptions& setIon(bool flag) { - ion_ = flag; - return *this; - } - ContextOptions& toggleIon() { - ion_ = !ion_; - return *this; - } - - bool asmJS() const { return asmJS_; } - ContextOptions& setAsmJS(bool flag) { - asmJS_ = flag; - return *this; - } - ContextOptions& toggleAsmJS() { - asmJS_ = !asmJS_; - return *this; - } - - bool wasm() const { return wasm_; } - ContextOptions& setWasm(bool flag) { - wasm_ = flag; - return *this; - } - ContextOptions& toggleWasm() { - wasm_ = !wasm_; - return *this; - } - - bool wasmAlwaysBaseline() const { return wasmAlwaysBaseline_; } - ContextOptions& setWasmAlwaysBaseline(bool flag) { - wasmAlwaysBaseline_ = flag; - return *this; - } - ContextOptions& toggleWasmAlwaysBaseline() { - wasmAlwaysBaseline_ = !wasmAlwaysBaseline_; - return *this; - } - - bool throwOnAsmJSValidationFailure() const { return throwOnAsmJSValidationFailure_; } - ContextOptions& setThrowOnAsmJSValidationFailure(bool flag) { - throwOnAsmJSValidationFailure_ = flag; - return *this; - } - ContextOptions& toggleThrowOnAsmJSValidationFailure() { - throwOnAsmJSValidationFailure_ = !throwOnAsmJSValidationFailure_; - return *this; - } - - bool nativeRegExp() const { return nativeRegExp_; } - ContextOptions& setNativeRegExp(bool flag) { - nativeRegExp_ = flag; - return *this; - } - - bool unboxedArrays() const { return unboxedArrays_; } - ContextOptions& setUnboxedArrays(bool flag) { - unboxedArrays_ = flag; - return *this; - } - - bool asyncStack() const { return asyncStack_; } - ContextOptions& setAsyncStack(bool flag) { - asyncStack_ = flag; - return *this; - } - - bool throwOnDebuggeeWouldRun() const { return throwOnDebuggeeWouldRun_; } - ContextOptions& setThrowOnDebuggeeWouldRun(bool flag) { - throwOnDebuggeeWouldRun_ = flag; - return *this; - } - - bool dumpStackOnDebuggeeWouldRun() const { return dumpStackOnDebuggeeWouldRun_; } - ContextOptions& setDumpStackOnDebuggeeWouldRun(bool flag) { - dumpStackOnDebuggeeWouldRun_ = flag; - return *this; - } - - bool werror() const { return werror_; } - ContextOptions& setWerror(bool flag) { - werror_ = flag; - return *this; - } - ContextOptions& toggleWerror() { - werror_ = !werror_; - return *this; - } - - bool strictMode() const { return strictMode_; } - ContextOptions& setStrictMode(bool flag) { - strictMode_ = flag; - return *this; - } - ContextOptions& toggleStrictMode() { - strictMode_ = !strictMode_; - return *this; - } - - bool extraWarnings() const { return extraWarnings_; } - ContextOptions& setExtraWarnings(bool flag) { - extraWarnings_ = flag; - return *this; - } - ContextOptions& toggleExtraWarnings() { - extraWarnings_ = !extraWarnings_; - return *this; - } + extraWarnings_(false), + streams_(false) +#ifdef FUZZING + , + fuzzing_(false) +#endif + , + expressionClosures_(false), + arrayProtoValues_(true) { + } + + bool baseline() const { return baseline_; } + ContextOptions& setBaseline(bool flag) { + baseline_ = flag; + return *this; + } + ContextOptions& toggleBaseline() { + baseline_ = !baseline_; + return *this; + } + + bool ion() const { return ion_; } + ContextOptions& setIon(bool flag) { + ion_ = flag; + return *this; + } + ContextOptions& toggleIon() { + ion_ = !ion_; + return *this; + } + + bool asmJS() const { return asmJS_; } + ContextOptions& setAsmJS(bool flag) { + asmJS_ = flag; + return *this; + } + ContextOptions& toggleAsmJS() { + asmJS_ = !asmJS_; + return *this; + } + + bool wasm() const { return wasm_; } + ContextOptions& setWasm(bool flag) { + wasm_ = flag; + return *this; + } + ContextOptions& toggleWasm() { + wasm_ = !wasm_; + return *this; + } + + bool streams() const { return streams_; } + ContextOptions& setStreams(bool flag) { + streams_ = flag; + return *this; + } + ContextOptions& toggleStreams() { + streams_ = !streams_; + return *this; + } + + bool wasmBaseline() const { return wasmBaseline_; } + ContextOptions& setWasmBaseline(bool flag) { + wasmBaseline_ = flag; + return *this; + } + ContextOptions& toggleWasmBaseline() { + wasmBaseline_ = !wasmBaseline_; + return *this; + } + + bool wasmIon() const { return wasmIon_; } + ContextOptions& setWasmIon(bool flag) { + wasmIon_ = flag; + return *this; + } + ContextOptions& toggleWasmIon() { + wasmIon_ = !wasmIon_; + return *this; + } + + bool testWasmAwaitTier2() const { return testWasmAwaitTier2_; } + ContextOptions& setTestWasmAwaitTier2(bool flag) { + testWasmAwaitTier2_ = flag; + return *this; + } + ContextOptions& toggleTestWasmAwaitTier2() { + testWasmAwaitTier2_ = !testWasmAwaitTier2_; + return *this; + } + + bool throwOnAsmJSValidationFailure() const { + return throwOnAsmJSValidationFailure_; + } + ContextOptions& setThrowOnAsmJSValidationFailure(bool flag) { + throwOnAsmJSValidationFailure_ = flag; + return *this; + } + ContextOptions& toggleThrowOnAsmJSValidationFailure() { + throwOnAsmJSValidationFailure_ = !throwOnAsmJSValidationFailure_; + return *this; + } + + bool nativeRegExp() const { return nativeRegExp_; } + ContextOptions& setNativeRegExp(bool flag) { + nativeRegExp_ = flag; + return *this; + } + + bool asyncStack() const { return asyncStack_; } + ContextOptions& setAsyncStack(bool flag) { + asyncStack_ = flag; + return *this; + } + + bool throwOnDebuggeeWouldRun() const { return throwOnDebuggeeWouldRun_; } + ContextOptions& setThrowOnDebuggeeWouldRun(bool flag) { + throwOnDebuggeeWouldRun_ = flag; + return *this; + } + + bool dumpStackOnDebuggeeWouldRun() const { + return dumpStackOnDebuggeeWouldRun_; + } + ContextOptions& setDumpStackOnDebuggeeWouldRun(bool flag) { + dumpStackOnDebuggeeWouldRun_ = flag; + return *this; + } + + bool werror() const { return werror_; } + ContextOptions& setWerror(bool flag) { + werror_ = flag; + return *this; + } + ContextOptions& toggleWerror() { + werror_ = !werror_; + return *this; + } + + bool strictMode() const { return strictMode_; } + ContextOptions& setStrictMode(bool flag) { + strictMode_ = flag; + return *this; + } + ContextOptions& toggleStrictMode() { + strictMode_ = !strictMode_; + return *this; + } + + bool extraWarnings() const { return extraWarnings_; } + ContextOptions& setExtraWarnings(bool flag) { + extraWarnings_ = flag; + return *this; + } + ContextOptions& toggleExtraWarnings() { + extraWarnings_ = !extraWarnings_; + return *this; + } + +#ifdef FUZZING + bool fuzzing() const { return fuzzing_; } + ContextOptions& setFuzzing(bool flag) { + fuzzing_ = flag; + return *this; + } +#endif - private: - 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; + bool expressionClosures() const { return expressionClosures_; } + ContextOptions& setExpressionClosures(bool flag) { + expressionClosures_ = flag; + return *this; + } + + bool arrayProtoValues() const { return arrayProtoValues_; } + ContextOptions& setArrayProtoValues(bool flag) { + arrayProtoValues_ = flag; + return *this; + } + + void disableOptionsForSafeMode() { + setBaseline(false); + setIon(false); + setAsmJS(false); + setWasm(false); + setWasmBaseline(false); + setWasmIon(false); + setNativeRegExp(false); + } + + private: + bool baseline_ : 1; + bool ion_ : 1; + bool asmJS_ : 1; + bool wasm_ : 1; + bool wasmBaseline_ : 1; + bool wasmIon_ : 1; + bool testWasmAwaitTier2_ : 1; + bool throwOnAsmJSValidationFailure_ : 1; + bool nativeRegExp_ : 1; + bool asyncStack_ : 1; + bool throwOnDebuggeeWouldRun_ : 1; + bool dumpStackOnDebuggeeWouldRun_ : 1; + bool werror_ : 1; + bool strictMode_ : 1; + bool extraWarnings_ : 1; + bool streams_ : 1; +#ifdef FUZZING + bool fuzzing_ : 1; +#endif + bool expressionClosures_ : 1; + bool arrayProtoValues_ : 1; }; -JS_PUBLIC_API(ContextOptions&) -ContextOptionsRef(JSContext* cx); +JS_PUBLIC_API ContextOptions& ContextOptionsRef(JSContext* cx); /** * 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); +JS_PUBLIC_API bool InitSelfHostedCode(JSContext* cx); /** * Asserts (in debug and release builds) that `obj` belongs to the current * thread's context. */ -JS_PUBLIC_API(void) -AssertObjectBelongsToCurrentThread(JSObject* obj); +JS_PUBLIC_API void AssertObjectBelongsToCurrentThread(JSObject* obj); } /* namespace JS */ -extern JS_PUBLIC_API(const char*) -JS_GetImplementationVersion(void); +extern JS_PUBLIC_API const char* JS_GetImplementationVersion(void); + +extern JS_PUBLIC_API void JS_SetDestroyCompartmentCallback( + JSContext* cx, JSDestroyCompartmentCallback callback); + +extern JS_PUBLIC_API void JS_SetSizeOfIncludingThisCompartmentCallback( + JSContext* cx, JSSizeOfIncludingThisCompartmentCallback callback); -extern JS_PUBLIC_API(void) -JS_SetDestroyCompartmentCallback(JSContext* cx, JSDestroyCompartmentCallback callback); +extern JS_PUBLIC_API void JS_SetCompartmentNameCallback( + JSContext* cx, JSCompartmentNameCallback callback); -extern JS_PUBLIC_API(void) -JS_SetSizeOfIncludingThisCompartmentCallback(JSContext* cx, - JSSizeOfIncludingThisCompartmentCallback callback); +extern JS_PUBLIC_API void JS_SetWrapObjectCallbacks( + JSContext* cx, const JSWrapObjectCallbacks* callbacks); -extern JS_PUBLIC_API(void) -JS_SetDestroyZoneCallback(JSContext* cx, JSZoneCallback callback); +extern JS_PUBLIC_API void JS_SetExternalStringSizeofCallback( + JSContext* cx, JSExternalStringSizeofCallback callback); -extern JS_PUBLIC_API(void) -JS_SetSweepZoneCallback(JSContext* cx, JSZoneCallback callback); +#if defined(NIGHTLY_BUILD) -extern JS_PUBLIC_API(void) -JS_SetCompartmentNameCallback(JSContext* cx, JSCompartmentNameCallback callback); +// Set a callback that will be called whenever an error +// is thrown in this runtime. This is designed as a mechanism +// for logging errors. Note that the VM makes no attempt to sanitize +// the contents of the error (so it may contain private data) +// or to sort out among errors (so it may not be the error you +// are interested in or for the component in which you are +// interested). +// +// If the callback sets a new error, this new error +// will replace the original error. +// +// May be `nullptr`. +extern JS_PUBLIC_API void JS_SetErrorInterceptorCallback( + JSRuntime*, JSErrorInterceptor* callback); -extern JS_PUBLIC_API(void) -JS_SetWrapObjectCallbacks(JSContext* cx, const JSWrapObjectCallbacks* callbacks); +extern JS_PUBLIC_API JSErrorInterceptor* JS_GetErrorInterceptorCallback( + JSRuntime*); -extern JS_PUBLIC_API(void) -JS_SetCompartmentPrivate(JSCompartment* compartment, void* data); +// Examine a value to determine if it is one of the built-in Error types. +// If so, return the error type. +extern JS_PUBLIC_API mozilla::Maybe JS_GetErrorType( + const JS::Value& val); -extern JS_PUBLIC_API(void*) -JS_GetCompartmentPrivate(JSCompartment* compartment); +#endif // defined(NIGHTLY_BUILD) -extern JS_PUBLIC_API(void) -JS_SetZoneUserData(JS::Zone* zone, void* data); +extern JS_PUBLIC_API void JS_SetCompartmentPrivate(JSCompartment* compartment, + void* data); -extern JS_PUBLIC_API(void*) -JS_GetZoneUserData(JS::Zone* zone); +extern JS_PUBLIC_API void* JS_GetCompartmentPrivate(JSCompartment* compartment); -extern JS_PUBLIC_API(bool) -JS_WrapObject(JSContext* cx, JS::MutableHandleObject objp); +extern JS_PUBLIC_API void JS_SetZoneUserData(JS::Zone* zone, void* data); -extern JS_PUBLIC_API(bool) -JS_WrapValue(JSContext* cx, JS::MutableHandleValue vp); +extern JS_PUBLIC_API void* JS_GetZoneUserData(JS::Zone* zone); -extern JS_PUBLIC_API(JSObject*) -JS_TransplantObject(JSContext* cx, JS::HandleObject origobj, JS::HandleObject target); +extern JS_PUBLIC_API bool JS_WrapObject(JSContext* cx, + JS::MutableHandleObject objp); -extern JS_PUBLIC_API(bool) -JS_RefreshCrossCompartmentWrappers(JSContext* cx, JS::Handle obj); +extern JS_PUBLIC_API bool JS_WrapValue(JSContext* cx, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API JSObject* JS_TransplantObject(JSContext* cx, + JS::HandleObject origobj, + JS::HandleObject target); + +extern JS_PUBLIC_API bool JS_RefreshCrossCompartmentWrappers( + JSContext* cx, JS::Handle obj); /* * At any time, a JSContext has a current (possibly-nullptr) compartment. @@ -1342,51 +1204,74 @@ * enter/leave calls on the context. Furthermore, only the return value of a * JS_EnterCompartment call may be passed as the 'oldCompartment' argument of * the corresponding JS_LeaveCompartment call. + * + * Entering a compartment roots the compartment and its global object for the + * lifetime of the JSAutoCompartment. */ -class MOZ_RAII JS_PUBLIC_API(JSAutoCompartment) -{ - JSContext* cx_; - JSCompartment* oldCompartment_; - public: - JSAutoCompartment(JSContext* cx, JSObject* target - MOZ_GUARD_OBJECT_NOTIFIER_PARAM); - JSAutoCompartment(JSContext* cx, JSScript* target - MOZ_GUARD_OBJECT_NOTIFIER_PARAM); - ~JSAutoCompartment(); - - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class MOZ_RAII JS_PUBLIC_API(JSAutoNullableCompartment) -{ - JSContext* cx_; - JSCompartment* oldCompartment_; - public: - explicit JSAutoNullableCompartment(JSContext* cx, JSObject* targetOrNull - MOZ_GUARD_OBJECT_NOTIFIER_PARAM); - ~JSAutoNullableCompartment(); - - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -/** NB: This API is infallible; a nullptr return value does not indicate error. */ -extern JS_PUBLIC_API(JSCompartment*) -JS_EnterCompartment(JSContext* cx, JSObject* target); +class MOZ_RAII JS_PUBLIC_API JSAutoCompartment { + JSContext* cx_; + JSCompartment* oldCompartment_; + + public: + JSAutoCompartment(JSContext* cx, + JSObject* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + JSAutoCompartment(JSContext* cx, + JSScript* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + ~JSAutoCompartment(); + + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class MOZ_RAII JS_PUBLIC_API JSAutoNullableCompartment { + JSContext* cx_; + JSCompartment* oldCompartment_; -extern JS_PUBLIC_API(void) -JS_LeaveCompartment(JSContext* cx, JSCompartment* oldCompartment); + public: + explicit JSAutoNullableCompartment( + JSContext* cx, JSObject* targetOrNull MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + ~JSAutoNullableCompartment(); -typedef void (*JSIterateCompartmentCallback)(JSContext* cx, void* data, JSCompartment* compartment); + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +/** NB: This API is infallible; a nullptr return value does not indicate error. + * + * Entering a compartment roots the compartment and its global object until the + * matching JS_LeaveCompartment() call. + */ +extern JS_PUBLIC_API JSCompartment* JS_EnterCompartment(JSContext* cx, + JSObject* target); + +extern JS_PUBLIC_API void JS_LeaveCompartment(JSContext* cx, + JSCompartment* oldCompartment); + +typedef void (*JSIterateCompartmentCallback)(JSContext* cx, void* data, + JSCompartment* compartment); /** * This function calls |compartmentCallback| on every compartment. Beware that * there is no guarantee that the compartment will survive after the callback * returns. Also, barriers are disabled via the TraceSession. */ -extern JS_PUBLIC_API(void) -JS_IterateCompartments(JSContext* cx, void* data, - JSIterateCompartmentCallback compartmentCallback); +extern JS_PUBLIC_API void JS_IterateCompartments( + JSContext* cx, void* data, + JSIterateCompartmentCallback compartmentCallback); + +/** + * Mark a jsid after entering a new compartment. Different zones separately + * mark the ids in a runtime, and this must be used any time an id is obtained + * from one compartment and then used in another compartment, unless the two + * compartments are guaranteed to be in the same zone. + */ +extern JS_PUBLIC_API void JS_MarkCrossZoneId(JSContext* cx, jsid id); + +/** + * If value stores a jsid (an atomized string or symbol), mark that id as for + * JS_MarkCrossZoneId. + */ +extern JS_PUBLIC_API void JS_MarkCrossZoneIdValue(JSContext* cx, + const JS::Value& value); /** * Initialize standard JS class constructors, prototypes, and any top-level @@ -1395,8 +1280,8 @@ * * NB: This sets cx's global object to obj if it was null. */ -extern JS_PUBLIC_API(bool) -JS_InitStandardClasses(JSContext* cx, JS::Handle obj); +extern JS_PUBLIC_API bool JS_InitStandardClasses(JSContext* cx, + JS::Handle obj); /** * Resolve id, which must contain either a string or an int, to a standard @@ -1407,149 +1292,148 @@ * as usual for bool result-typed API entry points. * * This API can be called directly from a global object class's resolve op, - * to define standard classes lazily. The class's enumerate op should call - * JS_EnumerateStandardClasses(cx, obj), to define eagerly during for..in - * loops any classes not yet resolved lazily. - */ -extern JS_PUBLIC_API(bool) -JS_ResolveStandardClass(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolved); - -extern JS_PUBLIC_API(bool) -JS_MayResolveStandardClass(const JSAtomState& names, jsid id, JSObject* maybeObj); + * to define standard classes lazily. The class should either have an enumerate + * hook that calls JS_EnumerateStandardClasses, or a newEnumerate hook that + * calls JS_NewEnumerateStandardClasses. newEnumerate is preferred because it's + * faster (does not define all standard classes). + */ +extern JS_PUBLIC_API bool JS_ResolveStandardClass(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + bool* resolved); + +extern JS_PUBLIC_API bool JS_MayResolveStandardClass(const JSAtomState& names, + jsid id, + JSObject* maybeObj); + +extern JS_PUBLIC_API bool JS_EnumerateStandardClasses(JSContext* cx, + JS::HandleObject obj); + +extern JS_PUBLIC_API bool JS_NewEnumerateStandardClasses( + JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties, + bool enumerableOnly); -extern JS_PUBLIC_API(bool) -JS_EnumerateStandardClasses(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API bool JS_GetClassObject(JSContext* cx, JSProtoKey key, + JS::MutableHandle objp); -extern JS_PUBLIC_API(bool) -JS_GetClassObject(JSContext* cx, JSProtoKey key, JS::MutableHandle objp); - -extern JS_PUBLIC_API(bool) -JS_GetClassPrototype(JSContext* cx, JSProtoKey key, JS::MutableHandle objp); +extern JS_PUBLIC_API bool JS_GetClassPrototype( + JSContext* cx, JSProtoKey key, JS::MutableHandle objp); namespace JS { /* - * Determine if the given object is an instance/prototype/constructor for a standard - * class. If so, return the associated JSProtoKey. If not, return JSProto_Null. + * Determine if the given object is an instance/prototype/constructor for a + * standard class. If so, return the associated JSProtoKey. If not, return + * JSProto_Null. */ -extern JS_PUBLIC_API(JSProtoKey) -IdentifyStandardInstance(JSObject* obj); +extern JS_PUBLIC_API JSProtoKey IdentifyStandardInstance(JSObject* obj); -extern JS_PUBLIC_API(JSProtoKey) -IdentifyStandardPrototype(JSObject* obj); +extern JS_PUBLIC_API JSProtoKey IdentifyStandardPrototype(JSObject* obj); -extern JS_PUBLIC_API(JSProtoKey) +extern JS_PUBLIC_API JSProtoKey IdentifyStandardInstanceOrPrototype(JSObject* obj); -extern JS_PUBLIC_API(JSProtoKey) -IdentifyStandardConstructor(JSObject* obj); +extern JS_PUBLIC_API JSProtoKey IdentifyStandardConstructor(JSObject* obj); -extern JS_PUBLIC_API(void) -ProtoKeyToId(JSContext* cx, JSProtoKey key, JS::MutableHandleId idp); +extern JS_PUBLIC_API void ProtoKeyToId(JSContext* cx, JSProtoKey key, + JS::MutableHandleId idp); } /* namespace JS */ -extern JS_PUBLIC_API(JSProtoKey) -JS_IdToProtoKey(JSContext* cx, JS::HandleId id); +extern JS_PUBLIC_API JSProtoKey JS_IdToProtoKey(JSContext* cx, JS::HandleId id); /** * Returns the original value of |Function.prototype| from the global object in * which |forObj| was created. */ -extern JS_PUBLIC_API(JSObject*) -JS_GetFunctionPrototype(JSContext* cx, JS::HandleObject forObj); +extern JS_PUBLIC_API JSObject* JS_GetFunctionPrototype(JSContext* cx, + JS::HandleObject forObj); /** * Returns the original value of |Object.prototype| from the global object in * which |forObj| was created. */ -extern JS_PUBLIC_API(JSObject*) -JS_GetObjectPrototype(JSContext* cx, JS::HandleObject forObj); +extern JS_PUBLIC_API JSObject* JS_GetObjectPrototype(JSContext* cx, + JS::HandleObject forObj); /** * Returns the original value of |Array.prototype| from the global object in * which |forObj| was created. */ -extern JS_PUBLIC_API(JSObject*) -JS_GetArrayPrototype(JSContext* cx, JS::HandleObject forObj); +extern JS_PUBLIC_API JSObject* JS_GetArrayPrototype(JSContext* cx, + JS::HandleObject forObj); /** * Returns the original value of |Error.prototype| from the global * object of the current compartment of cx. */ -extern JS_PUBLIC_API(JSObject*) -JS_GetErrorPrototype(JSContext* cx); +extern JS_PUBLIC_API JSObject* JS_GetErrorPrototype(JSContext* cx); /** * Returns the %IteratorPrototype% object that all built-in iterator prototype * chains go through for the global object of the current compartment of cx. */ -extern JS_PUBLIC_API(JSObject*) -JS_GetIteratorPrototype(JSContext* cx); +extern JS_PUBLIC_API JSObject* JS_GetIteratorPrototype(JSContext* cx); -extern JS_PUBLIC_API(JSObject*) -JS_GetGlobalForObject(JSContext* cx, JSObject* obj); +extern JS_PUBLIC_API JSObject* JS_GetGlobalForObject(JSContext* cx, + JSObject* obj); -extern JS_PUBLIC_API(bool) -JS_IsGlobalObject(JSObject* obj); +extern JS_PUBLIC_API bool JS_IsGlobalObject(JSObject* obj); -extern JS_PUBLIC_API(JSObject*) -JS_GlobalLexicalEnvironment(JSObject* obj); +extern JS_PUBLIC_API JSObject* JS_GlobalLexicalEnvironment(JSObject* obj); -extern JS_PUBLIC_API(bool) -JS_HasExtensibleLexicalEnvironment(JSObject* obj); +extern JS_PUBLIC_API bool JS_HasExtensibleLexicalEnvironment(JSObject* obj); -extern JS_PUBLIC_API(JSObject*) -JS_ExtensibleLexicalEnvironment(JSObject* obj); +extern JS_PUBLIC_API JSObject* JS_ExtensibleLexicalEnvironment(JSObject* obj); /** * May return nullptr, if |c| never had a global (e.g. the atoms compartment), * or if |c|'s global has been collected. */ -extern JS_PUBLIC_API(JSObject*) -JS_GetGlobalForCompartmentOrNull(JSContext* cx, JSCompartment* c); +extern JS_PUBLIC_API JSObject* JS_GetGlobalForCompartmentOrNull( + JSContext* cx, JSCompartment* c); namespace JS { -extern JS_PUBLIC_API(JSObject*) -CurrentGlobalOrNull(JSContext* cx); +extern JS_PUBLIC_API JSObject* CurrentGlobalOrNull(JSContext* cx); -} // namespace JS +} // namespace JS /** * Add 'Reflect.parse', a SpiderMonkey extension, to the Reflect object on the * given global. */ -extern JS_PUBLIC_API(bool) -JS_InitReflectParse(JSContext* cx, JS::HandleObject global); +extern JS_PUBLIC_API bool JS_InitReflectParse(JSContext* cx, + JS::HandleObject global); /** * Add various profiling-related functions as properties of the given object. * Defined in builtin/Profilers.cpp. */ -extern JS_PUBLIC_API(bool) -JS_DefineProfilingFunctions(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API bool JS_DefineProfilingFunctions(JSContext* cx, + JS::HandleObject obj); /* Defined in vm/Debugger.cpp. */ -extern JS_PUBLIC_API(bool) -JS_DefineDebuggerObject(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API bool JS_DefineDebuggerObject(JSContext* cx, + JS::HandleObject obj); #ifdef JS_HAS_CTYPES /** * Initialize the 'ctypes' object on a global variable 'obj'. The 'ctypes' * object will be sealed. */ -extern JS_PUBLIC_API(bool) -JS_InitCTypesClass(JSContext* cx, JS::HandleObject global); +extern JS_PUBLIC_API bool JS_InitCTypesClass(JSContext* cx, + JS::HandleObject global); /** * Convert a unicode string 'source' of length 'slen' to the platform native * charset, returning a null-terminated string allocated with JS_malloc. On * failure, this function should report an error. */ -typedef char* -(* JSCTypesUnicodeToNativeFun)(JSContext* cx, const char16_t* source, size_t slen); +typedef char* (*JSCTypesUnicodeToNativeFun)(JSContext* cx, + const char16_t* source, + size_t slen); /** * Set of function pointers that ctypes can use for various internal functions. @@ -1557,243 +1441,40 @@ * and will result in the applicable ctypes functionality not being available. */ struct JSCTypesCallbacks { - JSCTypesUnicodeToNativeFun unicodeToNative; + JSCTypesUnicodeToNativeFun unicodeToNative; }; -typedef struct JSCTypesCallbacks JSCTypesCallbacks; - /** * Set the callbacks on the provided 'ctypesObj' object. 'callbacks' should be a * pointer to static data that exists for the lifetime of 'ctypesObj', but it * may safely be altered after calling this function and without having * to call this function again. */ -extern JS_PUBLIC_API(void) -JS_SetCTypesCallbacks(JSObject* ctypesObj, const JSCTypesCallbacks* callbacks); +extern JS_PUBLIC_API void JS_SetCTypesCallbacks( + JSObject* ctypesObj, const JSCTypesCallbacks* callbacks); #endif -extern JS_PUBLIC_API(void*) -JS_malloc(JSContext* cx, size_t nbytes); +extern JS_PUBLIC_API void* JS_malloc(JSContext* cx, size_t nbytes); -extern JS_PUBLIC_API(void*) -JS_realloc(JSContext* cx, void* p, size_t oldBytes, size_t newBytes); +extern JS_PUBLIC_API void* JS_realloc(JSContext* cx, void* p, size_t oldBytes, + size_t newBytes); /** * A wrapper for js_free(p) that may delay js_free(p) invocation as a * performance optimization. * cx may be nullptr. */ -extern JS_PUBLIC_API(void) -JS_free(JSContext* cx, void* p); +extern JS_PUBLIC_API void JS_free(JSContext* cx, void* p); /** * A wrapper for js_free(p) that may delay js_free(p) invocation as a * performance optimization as specified by the given JSFreeOp instance. */ -extern JS_PUBLIC_API(void) -JS_freeop(JSFreeOp* fop, void* p); +extern JS_PUBLIC_API void JS_freeop(JSFreeOp* fop, void* p); -extern JS_PUBLIC_API(void) -JS_updateMallocCounter(JSContext* cx, size_t nbytes); +extern JS_PUBLIC_API void JS_updateMallocCounter(JSContext* cx, size_t nbytes); -extern JS_PUBLIC_API(char*) -JS_strdup(JSContext* cx, const char* s); - -/** - * Register externally maintained GC roots. - * - * traceOp: the trace operation. For each root the implementation should call - * 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(JSContext* cx, JSTraceDataOp traceOp, void* data); - -/** Undo a call to JS_AddExtraGCRootsTracer. */ -extern JS_PUBLIC_API(void) -JS_RemoveExtraGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp, void* data); - -/* - * Garbage collector API. - */ -extern JS_PUBLIC_API(void) -JS_GC(JSContext* cx); - -extern JS_PUBLIC_API(void) -JS_MaybeGC(JSContext* cx); - -extern JS_PUBLIC_API(void) -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(JSContext* cx, JSFinalizeCallback cb, void* data); - -extern JS_PUBLIC_API(void) -JS_RemoveFinalizeCallback(JSContext* cx, JSFinalizeCallback cb); - -/* - * Weak pointers and garbage collection - * - * Weak pointers are by their nature not marked as part of garbage collection, - * but they may need to be updated in two cases after a GC: - * - * 1) Their referent was found not to be live and is about to be finalized - * 2) Their referent has been moved by a compacting GC - * - * To handle this, any part of the system that maintain weak pointers to - * JavaScript GC things must register a callback with - * JS_(Add,Remove)WeakPointer{ZoneGroup,Compartment}Callback(). This callback - * must then call JS_UpdateWeakPointerAfterGC() on all weak pointers it knows - * about. - * - * Since sweeping is incremental, we have several callbacks to avoid repeatedly - * having to visit all embedder structures. The WeakPointerZoneGroupCallback is - * called once for each strongly connected group of zones, whereas the - * WeakPointerCompartmentCallback is called once for each compartment that is - * visited while sweeping. Structures that cannot contain references in more - * than one compartment should sweep the relevant per-compartment structures - * using the latter callback to minimizer per-slice overhead. - * - * The argument to JS_UpdateWeakPointerAfterGC() is an in-out param. If the - * referent is about to be finalized the pointer will be set to null. If the - * referent has been moved then the pointer will be updated to point to the 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(bool) -JS_AddWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb, void* data); - -extern JS_PUBLIC_API(void) -JS_RemoveWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb); - -extern JS_PUBLIC_API(bool) -JS_AddWeakPointerCompartmentCallback(JSContext* cx, JSWeakPointerCompartmentCallback cb, - void* data); - -extern JS_PUBLIC_API(void) -JS_RemoveWeakPointerCompartmentCallback(JSContext* cx, JSWeakPointerCompartmentCallback cb); - -extern JS_PUBLIC_API(void) -JS_UpdateWeakPointerAfterGC(JS::Heap* objp); - -extern JS_PUBLIC_API(void) -JS_UpdateWeakPointerAfterGCUnbarriered(JSObject** objp); - -typedef enum JSGCParamKey { - /** Maximum nominal heap before last ditch GC. */ - JSGC_MAX_BYTES = 0, - - /** Number of JS_malloc bytes before last ditch GC. */ - JSGC_MAX_MALLOC_BYTES = 1, - - /** Amount of bytes allocated by the GC. */ - JSGC_BYTES = 3, - - /** Number of times GC has been invoked. Includes both major and minor GC. */ - JSGC_NUMBER = 4, - - /** Select GC mode. */ - JSGC_MODE = 6, - - /** Number of cached empty GC chunks. */ - JSGC_UNUSED_CHUNKS = 7, - - /** Total number of allocated GC chunks. */ - JSGC_TOTAL_CHUNKS = 8, - - /** Max milliseconds to spend in an incremental GC slice. */ - JSGC_SLICE_TIME_BUDGET = 9, - - /** Maximum size the GC mark stack can grow to. */ - JSGC_MARK_STACK_LIMIT = 10, - - /** - * GCs less than this far apart in time will be considered 'high-frequency GCs'. - * See setGCLastBytes in jsgc.cpp. - */ - JSGC_HIGH_FREQUENCY_TIME_LIMIT = 11, - - /** Start of dynamic heap growth. */ - JSGC_HIGH_FREQUENCY_LOW_LIMIT = 12, - - /** End of dynamic heap growth. */ - JSGC_HIGH_FREQUENCY_HIGH_LIMIT = 13, - - /** Upper bound of heap growth. */ - JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX = 14, - - /** Lower bound of heap growth. */ - JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN = 15, - - /** Heap growth for low frequency GCs. */ - JSGC_LOW_FREQUENCY_HEAP_GROWTH = 16, - - /** - * If false, the heap growth factor is fixed at 3. If true, it is determined - * based on whether GCs are high- or low- frequency. - */ - JSGC_DYNAMIC_HEAP_GROWTH = 17, - - /** If true, high-frequency GCs will use a longer mark slice. */ - JSGC_DYNAMIC_MARK_SLICE = 18, - - /** Lower limit after which we limit the heap growth. */ - JSGC_ALLOCATION_THRESHOLD = 19, - - /** - * We try to keep at least this many unused chunks in the free chunk pool at - * all times, even after a shrinking GC. - */ - JSGC_MIN_EMPTY_CHUNK_COUNT = 21, - - /** We never keep more than this many unused chunks in the free chunk pool. */ - JSGC_MAX_EMPTY_CHUNK_COUNT = 22, - - /** Whether compacting GC is enabled. */ - JSGC_COMPACTING_ENABLED = 23, - - /** If true, painting can trigger IGC slices. */ - JSGC_REFRESH_FRAME_SLICES_ENABLED = 24, -} JSGCParamKey; - -extern JS_PUBLIC_API(void) -JS_SetGCParameter(JSContext* cx, JSGCParamKey key, uint32_t value); - -extern JS_PUBLIC_API(uint32_t) -JS_GetGCParameter(JSContext* cx, JSGCParamKey key); - -extern JS_PUBLIC_API(void) -JS_SetGCParametersBasedOnAvailableMemory(JSContext* cx, uint32_t availMem); - -/** - * Create a new JSString whose chars member refers to external memory, i.e., - * memory requiring application-specific finalization. - */ -extern JS_PUBLIC_API(JSString*) -JS_NewExternalString(JSContext* cx, const char16_t* chars, size_t length, - const JSStringFinalizer* fin); - -/** - * Return whether 'str' was created with JS_NewExternalString or - * JS_NewExternalStringWithClosure. - */ -extern JS_PUBLIC_API(bool) -JS_IsExternalString(JSString* str); - -/** - * Return the 'fin' arg passed to JS_NewExternalString. - */ -extern JS_PUBLIC_API(const JSStringFinalizer*) -JS_GetExternalStringFinalizer(JSString* str); +extern JS_PUBLIC_API char* JS_strdup(JSContext* cx, const char* s); /** * Set the size of the native stack that should not be exceed. To disable @@ -1801,10 +1482,10 @@ * * SpiderMonkey allows for a distinction between system code (such as GCs, which * may incidentally be triggered by script but are not strictly performed on - * behalf of such script), trusted script (as determined by JS_SetTrustedPrincipals), - * and untrusted script. Each kind of code may have a different stack quota, - * allowing embedders to keep higher-priority machinery running in the face of - * scripted stack exhaustion by something else. + * behalf of such script), trusted script (as determined by + * JS_SetTrustedPrincipals), and untrusted script. Each kind of code may have a + * different stack quota, allowing embedders to keep higher-priority machinery + * running in the face of scripted stack exhaustion by something else. * * The stack quotas for each kind of code should be monotonically descending, * and may be specified with this function. If 0 is passed for a given kind @@ -1813,21 +1494,20 @@ * This function may only be called immediately after the runtime is initialized * and before any code is executed and/or interrupts requested. */ -extern JS_PUBLIC_API(void) -JS_SetNativeStackQuota(JSContext* cx, size_t systemCodeStackSize, - size_t trustedScriptStackSize = 0, - size_t untrustedScriptStackSize = 0); +extern JS_PUBLIC_API void JS_SetNativeStackQuota( + JSContext* cx, size_t systemCodeStackSize, + size_t trustedScriptStackSize = 0, size_t untrustedScriptStackSize = 0); /************************************************************************/ -extern JS_PUBLIC_API(bool) -JS_ValueToId(JSContext* cx, JS::HandleValue v, JS::MutableHandleId idp); +extern JS_PUBLIC_API bool JS_ValueToId(JSContext* cx, JS::HandleValue v, + JS::MutableHandleId idp); -extern JS_PUBLIC_API(bool) -JS_StringToId(JSContext* cx, JS::HandleString s, JS::MutableHandleId idp); +extern JS_PUBLIC_API bool JS_StringToId(JSContext* cx, JS::HandleString s, + JS::MutableHandleId idp); -extern JS_PUBLIC_API(bool) -JS_IdToValue(JSContext* cx, jsid id, JS::MutableHandle vp); +extern JS_PUBLIC_API bool JS_IdToValue(JSContext* cx, jsid id, + JS::MutableHandle vp); namespace JS { @@ -1835,38 +1515,31 @@ * Convert obj to a primitive value. On success, store the result in vp and * return true. * - * The hint argument must be JSTYPE_STRING, JSTYPE_NUMBER, or JSTYPE_VOID (no - * hint). + * The hint argument must be JSTYPE_STRING, JSTYPE_NUMBER, or + * JSTYPE_UNDEFINED (no hint). * * Implements: ES6 7.1.1 ToPrimitive(input, [PreferredType]). */ -extern JS_PUBLIC_API(bool) -ToPrimitive(JSContext* cx, JS::HandleObject obj, JSType hint, JS::MutableHandleValue vp); +extern JS_PUBLIC_API bool ToPrimitive(JSContext* cx, JS::HandleObject obj, + JSType hint, JS::MutableHandleValue vp); /** * If args.get(0) is one of the strings "string", "number", or "default", set - * *result to JSTYPE_STRING, JSTYPE_NUMBER, or JSTYPE_VOID accordingly and + * result to JSTYPE_STRING, JSTYPE_NUMBER, or JSTYPE_UNDEFINED accordingly and * return true. Otherwise, return false with a TypeError pending. * * This can be useful in implementing a @@toPrimitive method. */ -extern JS_PUBLIC_API(bool) -GetFirstArgumentAsTypeHint(JSContext* cx, CallArgs args, JSType *result); +extern JS_PUBLIC_API bool GetFirstArgumentAsTypeHint(JSContext* cx, + CallArgs args, + JSType* result); } /* namespace JS */ -extern JS_PUBLIC_API(bool) -JS_PropertyStub(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_StrictPropertyStub(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleValue vp, JS::ObjectOpResult& result); - -template +template struct JSConstScalarSpec { - const char* name; - T val; + const char* name; + T val; }; typedef JSConstScalarSpec JSConstDoubleSpec; @@ -1879,16 +1552,19 @@ * allow us to pass one JSJitInfo per function with the property/function spec, * without additional field overhead. */ -typedef struct JSNativeWrapper { - JSNative op; - const JSJitInfo* info; -} JSNativeWrapper; +struct JSNativeWrapper { + JSNative op; + const JSJitInfo* info; +}; /* - * Macro static initializers which make it easy to pass no JSJitInfo as part of a - * JSPropertySpec or JSFunctionSpec. + * Macro static initializers which make it easy to pass no JSJitInfo as part of + * a JSPropertySpec or JSFunctionSpec. */ -#define JSNATIVE_WRAPPER(native) { {native, nullptr} } +#define JSNATIVE_WRAPPER(native) \ + { \ + { native, nullptr } \ + } /** * Description of a property. JS_DefineProperties and JS_InitClass take arrays @@ -1896,73 +1572,74 @@ * are helper macros for defining such arrays. */ struct JSPropertySpec { - struct SelfHostedWrapper { - void* unused; - const char* funname; - }; - - struct ValueWrapper { - uintptr_t type; - union { - const char* string; - int32_t int32; - }; - }; + struct SelfHostedWrapper { + void* unused; + const char* funname; + }; - const char* name; - uint8_t flags; + struct ValueWrapper { + uintptr_t type; union { - struct { - union { - JSNativeWrapper native; - SelfHostedWrapper selfHosted; - } getter; - union { - JSNativeWrapper native; - SelfHostedWrapper selfHosted; - } setter; - } accessors; - ValueWrapper value; + const char* string; + int32_t int32; }; + }; - bool isAccessor() const { - return !(flags & JSPROP_INTERNAL_USE_BIT); - } - JS_PUBLIC_API(bool) getValue(JSContext* cx, JS::MutableHandleValue value) const; + const char* name; + uint8_t flags; + union { + 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()); + bool isSelfHosted() const { + MOZ_ASSERT(isAccessor()); #ifdef DEBUG - // Verify that our accessors match our JSPROP_GETTER flag. - if (flags & JSPROP_GETTER) - checkAccessorsAreSelfHosted(); - else - checkAccessorsAreNative(); + // Verify that our accessors match our JSPROP_GETTER flag. + if (flags & JSPROP_GETTER) + checkAccessorsAreSelfHosted(); + else + checkAccessorsAreNative(); #endif - return (flags & JSPROP_GETTER); - } - - static_assert(sizeof(SelfHostedWrapper) == sizeof(JSNativeWrapper), - "JSPropertySpec::getter/setter must be compact"); - static_assert(offsetof(SelfHostedWrapper, funname) == offsetof(JSNativeWrapper, info), - "JS_SELF_HOSTED* macros below require that " - "SelfHostedWrapper::funname overlay " - "JSNativeWrapper::info"); -private: - void checkAccessorsAreNative() const { - 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(accessors.setter.native.info, accessors.setter.native.op); - } + return (flags & JSPROP_GETTER); + } - void checkAccessorsAreSelfHosted() const { - MOZ_ASSERT(!accessors.getter.selfHosted.unused); - MOZ_ASSERT(!accessors.setter.selfHosted.unused); - } + static_assert(sizeof(SelfHostedWrapper) == sizeof(JSNativeWrapper), + "JSPropertySpec::getter/setter must be compact"); + static_assert(offsetof(SelfHostedWrapper, funname) == + offsetof(JSNativeWrapper, info), + "JS_SELF_HOSTED* macros below require that " + "SelfHostedWrapper::funname overlay " + "JSNativeWrapper::info"); + + private: + void checkAccessorsAreNative() const { + 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(accessors.setter.native.info, accessors.setter.native.op); + } + + void checkAccessorsAreSelfHosted() const { + MOZ_ASSERT(!accessors.getter.selfHosted.unused); + MOZ_ASSERT(!accessors.setter.selfHosted.unused); + } }; namespace JS { @@ -1972,9 +1649,8 @@ inline int CheckIsNative(JSNative native); /* NEVER DEFINED, DON'T USE. For use by JS_CAST_STRING_TO only. */ -template -inline int -CheckIsCharacterLiteral(const char (&arr)[N]); +template +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); @@ -1985,81 +1661,104 @@ /* NEVER DEFINED, DON'T USE. For use by JS_PROPERTYOP_SETTER only. */ inline int CheckIsSetterOp(JSSetterOp op); -} // namespace detail -} // namespace JS +} // namespace detail +} // namespace JS -#define JS_CAST_NATIVE_TO(v, To) \ +#define JS_CAST_NATIVE_TO(v, To) \ (static_cast(sizeof(JS::detail::CheckIsNative(v))), \ reinterpret_cast(v)) -#define JS_CAST_STRING_TO(s, To) \ +#define JS_CAST_STRING_TO(s, To) \ (static_cast(sizeof(JS::detail::CheckIsCharacterLiteral(s))), \ reinterpret_cast(s)) -#define JS_CAST_INT32_TO(s, To) \ +#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), \ +#define JS_CHECK_ACCESSOR_FLAGS(flags) \ + (static_cast::Type>(0), \ (flags)) -#define JS_PROPERTYOP_GETTER(v) \ +#define JS_PROPERTYOP_GETTER(v) \ (static_cast(sizeof(JS::detail::CheckIsGetterOp(v))), \ reinterpret_cast(v)) -#define JS_PROPERTYOP_SETTER(v) \ +#define JS_PROPERTYOP_SETTER(v) \ (static_cast(sizeof(JS::detail::CheckIsSetterOp(v))), \ reinterpret_cast(v)) -#define JS_STUBGETTER JS_PROPERTYOP_GETTER(JS_PropertyStub) - -#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*) } } + { \ + 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) \ - JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(nullptr), flags, \ - JSPROP_SHARED) -#define JS_PSGS(name, getter, setter, flags) \ - JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(setter), flags, \ - JSPROP_SHARED) -#define JS_SELF_HOSTED_GET(name, getterName, flags) \ - JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), JSNATIVE_WRAPPER(nullptr), flags, \ - JSPROP_SHARED | JSPROP_GETTER) +#define JS_PSG(name, getter, flags) \ + JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), \ + JSNATIVE_WRAPPER(nullptr), flags, 0) +#define JS_PSGS(name, getter, setter, flags) \ + JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), \ + JSNATIVE_WRAPPER(setter), flags, 0) +#define JS_SYM_GET(symbol, getter, flags) \ + JS_PS_ACCESSOR_SPEC( \ + reinterpret_cast(uint32_t(::JS::SymbolCode::symbol) + 1), \ + JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(nullptr), flags, 0) +#define JS_SELF_HOSTED_GET(name, getterName, flags) \ + JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), \ + JSNATIVE_WRAPPER(nullptr), flags, JSPROP_GETTER) #define JS_SELF_HOSTED_GETSET(name, getterName, setterName, flags) \ - 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) \ - JS_PS_ACCESSOR_SPEC(reinterpret_cast(uint32_t(::JS::SymbolCode::symbol) + 1), \ - SELFHOSTED_WRAPPER(getterName), JSNATIVE_WRAPPER(nullptr), flags, \ - JSPROP_SHARED | JSPROP_GETTER) + JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), \ + SELFHOSTED_WRAPPER(setterName), flags, \ + JSPROP_GETTER | JSPROP_SETTER) +#define JS_SELF_HOSTED_SYM_GET(symbol, getterName, flags) \ + JS_PS_ACCESSOR_SPEC( \ + reinterpret_cast(uint32_t(::JS::SymbolCode::symbol) + 1), \ + SELFHOSTED_WRAPPER(getterName), JSNATIVE_WRAPPER(nullptr), flags, \ + 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) + 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) + 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 @@ -2067,75 +1766,72 @@ * compiled during JSRuntime::initSelfHosting. */ struct JSFunctionSpec { - const char* name; - JSNativeWrapper call; - uint16_t nargs; - uint16_t flags; - const char* selfHostedName; + const char* name; + JSNativeWrapper call; + uint16_t nargs; + uint16_t flags; + const char* selfHostedName; }; /* * Terminating sentinel initializer to put at the end of a JSFunctionSpec array * that's passed to JS_DefineFunctions or JS_InitClass. */ -#define JS_FS_END JS_FS(nullptr,nullptr,0,0) +#define JS_FS_END JS_FN(nullptr, nullptr, 0, 0) /* - * Initializer macros for a JSFunctionSpec array element. JS_FN (whose name pays - * homage to the old JSNative/JSFastNative split) simply adds the flag - * JSFUN_STUB_GSOPS. JS_FNINFO allows the simple adding of - * JSJitInfos. JS_SELF_HOSTED_FN declares a self-hosted function. - * JS_INLINABLE_FN allows specifying an InlinableNative enum value for natives - * inlined or specialized by the JIT. Finally JS_FNSPEC has slots for all the - * fields. + * Initializer macros for a JSFunctionSpec array element. JS_FNINFO allows the + * simple adding of JSJitInfos. JS_SELF_HOSTED_FN declares a self-hosted + * function. JS_INLINABLE_FN allows specifying an InlinableNative enum value for + * natives inlined or specialized by the JIT. Finally JS_FNSPEC has slots for + * all the fields. * * The _SYM variants allow defining a function with a symbol key rather than a * string key. For example, use JS_SYM_FN(iterator, ...) to define an * @@iterator method. */ -#define JS_FS(name,call,nargs,flags) \ - JS_FNSPEC(name, call, nullptr, nargs, flags, nullptr) -#define JS_FN(name,call,nargs,flags) \ - JS_FNSPEC(name, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr) -#define JS_INLINABLE_FN(name,call,nargs,flags,native) \ - JS_FNSPEC(name, call, &js::jit::JitInfo_##native, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr) -#define JS_SYM_FN(symbol,call,nargs,flags) \ - JS_SYM_FNSPEC(symbol, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr) -#define JS_FNINFO(name,call,info,nargs,flags) \ - JS_FNSPEC(name, call, info, nargs, flags, nullptr) -#define JS_SELF_HOSTED_FN(name,selfHostedName,nargs,flags) \ - JS_FNSPEC(name, nullptr, nullptr, nargs, flags, selfHostedName) -#define JS_SELF_HOSTED_SYM_FN(symbol, selfHostedName, nargs, flags) \ - JS_SYM_FNSPEC(symbol, nullptr, nullptr, nargs, flags, selfHostedName) -#define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \ - JS_FNSPEC(reinterpret_cast( \ - uint32_t(::JS::SymbolCode::symbol) + 1), \ - call, info, nargs, flags, selfHostedName) -#define JS_FNSPEC(name,call,info,nargs,flags,selfHostedName) \ - {name, {call, info}, nargs, flags, selfHostedName} - -extern JS_PUBLIC_API(JSObject*) -JS_InitClass(JSContext* cx, JS::HandleObject obj, JS::HandleObject parent_proto, - const JSClass* clasp, JSNative constructor, unsigned nargs, - const JSPropertySpec* ps, const JSFunctionSpec* fs, - const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs); +#define JS_FN(name, call, nargs, flags) \ + JS_FNSPEC(name, call, nullptr, nargs, flags, nullptr) +#define JS_INLINABLE_FN(name, call, nargs, flags, native) \ + JS_FNSPEC(name, call, &js::jit::JitInfo_##native, nargs, flags, nullptr) +#define JS_SYM_FN(symbol, call, nargs, flags) \ + JS_SYM_FNSPEC(symbol, call, nullptr, nargs, flags, nullptr) +#define JS_FNINFO(name, call, info, nargs, flags) \ + JS_FNSPEC(name, call, info, nargs, flags, nullptr) +#define JS_SELF_HOSTED_FN(name, selfHostedName, nargs, flags) \ + JS_FNSPEC(name, nullptr, nullptr, nargs, flags, selfHostedName) +#define JS_SELF_HOSTED_SYM_FN(symbol, selfHostedName, nargs, flags) \ + JS_SYM_FNSPEC(symbol, nullptr, nullptr, nargs, flags, selfHostedName) +#define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \ + JS_FNSPEC( \ + reinterpret_cast(uint32_t(::JS::SymbolCode::symbol) + 1), \ + call, info, nargs, flags, selfHostedName) +#define JS_FNSPEC(name, call, info, nargs, flags, selfHostedName) \ + { name, {call, info}, nargs, flags, selfHostedName } + +extern JS_PUBLIC_API JSObject* JS_InitClass( + JSContext* cx, JS::HandleObject obj, JS::HandleObject parent_proto, + const JSClass* clasp, JSNative constructor, unsigned nargs, + const JSPropertySpec* ps, const JSFunctionSpec* fs, + const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs); /** * Set up ctor.prototype = proto and proto.constructor = ctor with the * right property flags. */ -extern JS_PUBLIC_API(bool) -JS_LinkConstructorAndPrototype(JSContext* cx, JS::Handle ctor, - JS::Handle proto); - -extern JS_PUBLIC_API(const JSClass*) -JS_GetClass(JSObject* obj); +extern JS_PUBLIC_API bool JS_LinkConstructorAndPrototype( + JSContext* cx, JS::Handle ctor, JS::Handle proto); -extern JS_PUBLIC_API(bool) -JS_InstanceOf(JSContext* cx, JS::Handle obj, const JSClass* clasp, JS::CallArgs* args); +extern JS_PUBLIC_API const JSClass* JS_GetClass(JSObject* obj); -extern JS_PUBLIC_API(bool) -JS_HasInstance(JSContext* cx, JS::Handle obj, JS::Handle v, bool* bp); +extern JS_PUBLIC_API bool JS_InstanceOf(JSContext* cx, + JS::Handle obj, + const JSClass* clasp, + JS::CallArgs* args); + +extern JS_PUBLIC_API bool JS_HasInstance(JSContext* cx, + JS::Handle obj, + JS::Handle v, bool* bp); namespace JS { @@ -2143,29 +1839,43 @@ // 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); +extern JS_PUBLIC_API bool OrdinaryHasInstance(JSContext* cx, + HandleObject objArg, + HandleValue v, bool* bp); -} // namespace JS +} // namespace JS -extern JS_PUBLIC_API(void*) -JS_GetPrivate(JSObject* obj); +extern JS_PUBLIC_API void* JS_GetPrivate(JSObject* obj); -extern JS_PUBLIC_API(void) -JS_SetPrivate(JSObject* obj, void* data); +extern JS_PUBLIC_API void JS_SetPrivate(JSObject* obj, void* data); -extern JS_PUBLIC_API(void*) -JS_GetInstancePrivate(JSContext* cx, JS::Handle obj, const JSClass* clasp, - JS::CallArgs* args); +extern JS_PUBLIC_API void* JS_GetInstancePrivate(JSContext* cx, + JS::Handle obj, + const JSClass* clasp, + JS::CallArgs* args); -extern JS_PUBLIC_API(JSObject*) -JS_GetConstructor(JSContext* cx, JS::Handle proto); +extern JS_PUBLIC_API JSObject* JS_GetConstructor(JSContext* cx, + JS::Handle proto); namespace JS { +// Specification for which zone a newly created compartment should use. enum ZoneSpecifier { - FreshZone = 0, - SystemZone = 1 + // Use the single runtime wide system zone. The meaning of this zone is + // left to the embedder. + SystemZone, + + // Use a particular existing zone. + ExistingZone, + + // Create a new zone with its own new zone group. + NewZoneInNewZoneGroup, + + // Create a new zone in the same zone group as the system zone. + NewZoneInSystemZoneGroup, + + // Create a new zone in the same zone group as another existing zone. + NewZoneInExistingZoneGroup }; /** @@ -2176,193 +1886,176 @@ * 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() +class JS_PUBLIC_API CompartmentCreationOptions { + public: + CompartmentCreationOptions() : addonId_(nullptr), traceGlobal_(nullptr), + zoneSpec_(NewZoneInSystemZoneGroup), + zonePointer_(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; - } + secureContext_(false), + clampAndJitterTime_(true) {} - // 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_; + // 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 { return zonePointer_; } + ZoneSpecifier zoneSpecifier() const { return zoneSpec_; } + + // Set the zone to use for the compartment. See ZoneSpecifier above. + CompartmentCreationOptions& setSystemZone(); + CompartmentCreationOptions& setExistingZone(JSObject* obj); + CompartmentCreationOptions& setNewZoneInNewZoneGroup(); + CompartmentCreationOptions& setNewZoneInSystemZoneGroup(); + CompartmentCreationOptions& setNewZoneInExistingZoneGroup(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; + } + + bool clampAndJitterTime() const { return clampAndJitterTime_; } + CompartmentCreationOptions& setClampAndJitterTime(bool flag) { + clampAndJitterTime_ = flag; + return *this; + } + + private: + JSAddonId* addonId_; + JSTraceOp traceGlobal_; + ZoneSpecifier zoneSpec_; + void* zonePointer_; // Per zoneSpec_, either a Zone, ZoneGroup, or null. + bool invisibleToDebugger_; + bool mergeable_; + bool preserveJitCode_; + bool cloneSingletons_; + bool sharedMemoryAndAtomics_; + bool secureContext_; + bool clampAndJitterTime_; }; /** * CompartmentBehaviors specifies behaviors of a compartment that can be * changed after the compartment's been created. */ -class JS_PUBLIC_API(CompartmentBehaviors) -{ - public: - class Override { - public: - Override() : mode_(Default) {} - - bool get(bool defaultValue) const { - if (mode_ == Default) - return defaultValue; - return mode_ == ForceTrue; - } - - void set(bool overrideValue) { - mode_ = overrideValue ? ForceTrue : ForceFalse; - } - - void reset() { - mode_ = Default; - } - - private: - enum Mode { - Default, - ForceTrue, - ForceFalse - }; - - Mode mode_; - }; - - CompartmentBehaviors() - : version_(JSVERSION_UNKNOWN) - , discardSource_(false) - , disableLazyParsing_(false) - , singletonsAsTemplates_(true) - { - } - - JSVersion version() const { return version_; } - CompartmentBehaviors& setVersion(JSVersion aVersion) { - MOZ_ASSERT(aVersion != JSVERSION_UNKNOWN); - version_ = aVersion; - 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_; } - CompartmentBehaviors& setDiscardSource(bool flag) { - discardSource_ = flag; - return *this; - } - - bool disableLazyParsing() const { return disableLazyParsing_; } - CompartmentBehaviors& setDisableLazyParsing(bool flag) { - disableLazyParsing_ = flag; - return *this; - } - - bool extraWarnings(JSContext* cx) const; - Override& extraWarningsOverride() { return extraWarningsOverride_; } - - bool getSingletonsAsTemplates() const { - return singletonsAsTemplates_; - } - CompartmentBehaviors& setSingletonsAsValues() { - singletonsAsTemplates_ = false; - return *this; - } - - private: - JSVersion version_; - bool discardSource_; - bool disableLazyParsing_; - Override extraWarningsOverride_; - - // 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_; +class JS_PUBLIC_API CompartmentBehaviors { + public: + class Override { + public: + Override() : mode_(Default) {} + + bool get(bool defaultValue) const { + if (mode_ == Default) return defaultValue; + return mode_ == ForceTrue; + } + + void set(bool overrideValue) { + mode_ = overrideValue ? ForceTrue : ForceFalse; + } + + void reset() { mode_ = Default; } + + private: + enum Mode { Default, ForceTrue, ForceFalse }; + + Mode mode_; + }; + + CompartmentBehaviors() + : discardSource_(false), + disableLazyParsing_(false), + singletonsAsTemplates_(true) {} + + // 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_; } + CompartmentBehaviors& setDiscardSource(bool flag) { + discardSource_ = flag; + return *this; + } + + bool disableLazyParsing() const { return disableLazyParsing_; } + CompartmentBehaviors& setDisableLazyParsing(bool flag) { + disableLazyParsing_ = flag; + return *this; + } + + bool extraWarnings(JSContext* cx) const; + Override& extraWarningsOverride() { return extraWarningsOverride_; } + + bool getSingletonsAsTemplates() const { return singletonsAsTemplates_; } + CompartmentBehaviors& setSingletonsAsValues() { + singletonsAsTemplates_ = false; + return *this; + } + + private: + bool discardSource_; + bool disableLazyParsing_; + Override extraWarningsOverride_; + + // 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_; }; /** @@ -2371,61 +2064,48 @@ * (CompartmentCreationOptions), and those that can be changed on an existing * compartment (CompartmentBehaviors). */ -class JS_PUBLIC_API(CompartmentOptions) -{ - public: - explicit CompartmentOptions() - : creationOptions_(), - behaviors_() - {} +class JS_PUBLIC_API CompartmentOptions { + public: + explicit CompartmentOptions() : creationOptions_(), behaviors_() {} - CompartmentOptions(const CompartmentCreationOptions& compartmentCreation, - const CompartmentBehaviors& compartmentBehaviors) + CompartmentOptions(const CompartmentCreationOptions& compartmentCreation, + const CompartmentBehaviors& compartmentBehaviors) : creationOptions_(compartmentCreation), - behaviors_(compartmentBehaviors) - {} + 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_; - } + // 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_; - } + // 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_; + private: + CompartmentCreationOptions creationOptions_; + CompartmentBehaviors behaviors_; }; -JS_PUBLIC_API(const CompartmentCreationOptions&) -CompartmentCreationOptionsRef(JSCompartment* compartment); +JS_PUBLIC_API const CompartmentCreationOptions& CompartmentCreationOptionsRef( + JSCompartment* compartment); -JS_PUBLIC_API(const CompartmentCreationOptions&) -CompartmentCreationOptionsRef(JSObject* obj); +JS_PUBLIC_API const CompartmentCreationOptions& CompartmentCreationOptionsRef( + JSObject* obj); -JS_PUBLIC_API(const CompartmentCreationOptions&) -CompartmentCreationOptionsRef(JSContext* cx); +JS_PUBLIC_API const CompartmentCreationOptions& CompartmentCreationOptionsRef( + JSContext* cx); -JS_PUBLIC_API(CompartmentBehaviors&) -CompartmentBehaviorsRef(JSCompartment* compartment); +JS_PUBLIC_API CompartmentBehaviors& CompartmentBehaviorsRef( + JSCompartment* compartment); -JS_PUBLIC_API(CompartmentBehaviors&) -CompartmentBehaviorsRef(JSObject* obj); +JS_PUBLIC_API CompartmentBehaviors& CompartmentBehaviorsRef(JSObject* obj); -JS_PUBLIC_API(CompartmentBehaviors&) -CompartmentBehaviorsRef(JSContext* cx); +JS_PUBLIC_API CompartmentBehaviors& CompartmentBehaviorsRef(JSContext* cx); /** * During global creation, we fire notifications to callbacks registered @@ -2449,367 +2129,344 @@ * place to enforce this). This lets us be sure that debugger clients never miss * breakpoints. */ -enum OnNewGlobalHookOption { - FireOnNewGlobalHook, - DontFireOnNewGlobalHook -}; +enum OnNewGlobalHookOption { FireOnNewGlobalHook, DontFireOnNewGlobalHook }; } /* namespace JS */ -extern JS_PUBLIC_API(JSObject*) -JS_NewGlobalObject(JSContext* cx, const JSClass* clasp, JSPrincipals* principals, - JS::OnNewGlobalHookOption hookOption, - 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 - * compartments is hard. To mitigate this, we create a static trace hook, installed on each global - * object, from which we can be sure the compartment is relevant, and mark it. - * - * It is still possible to specify custom trace hooks for global object classes. They can be - * provided via the CompartmentOptions passed to JS_NewGlobalObject. - */ -extern JS_PUBLIC_API(void) -JS_GlobalObjectTraceHook(JSTracer* trc, JSObject* global); +extern JS_PUBLIC_API JSObject* JS_NewGlobalObject( + JSContext* cx, const JSClass* clasp, JSPrincipals* principals, + JS::OnNewGlobalHookOption hookOption, + 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 compartments is hard. To mitigate + * this, we create a static trace hook, installed on each global object, from + * which we can be sure the compartment is relevant, and mark it. + * + * It is still possible to specify custom trace hooks for global object classes. + * They can be provided via the CompartmentOptions passed to JS_NewGlobalObject. + */ +extern JS_PUBLIC_API void JS_GlobalObjectTraceHook(JSTracer* trc, + JSObject* global); -extern JS_PUBLIC_API(void) -JS_FireOnNewGlobalObject(JSContext* cx, JS::HandleObject global); +extern JS_PUBLIC_API void JS_FireOnNewGlobalObject(JSContext* cx, + JS::HandleObject global); -extern JS_PUBLIC_API(JSObject*) -JS_NewObject(JSContext* cx, const JSClass* clasp); +extern JS_PUBLIC_API JSObject* JS_NewObject(JSContext* cx, + const JSClass* clasp); -extern JS_PUBLIC_API(bool) -JS_IsNative(JSObject* obj); +extern JS_PUBLIC_API bool JS_IsNative(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]]. */ -extern JS_PUBLIC_API(JSObject*) -JS_NewObjectWithGivenProto(JSContext* cx, const JSClass* clasp, JS::Handle proto); +extern JS_PUBLIC_API JSObject* JS_NewObjectWithGivenProto( + JSContext* cx, const JSClass* clasp, JS::Handle proto); -/** Creates a new plain object, like `new Object()`, with Object.prototype as [[Prototype]]. */ -extern JS_PUBLIC_API(JSObject*) -JS_NewPlainObject(JSContext* cx); +/** Creates a new plain object, like `new Object()`, with Object.prototype as + * [[Prototype]]. */ +extern JS_PUBLIC_API JSObject* JS_NewPlainObject(JSContext* cx); /** * Freeze obj, and all objects it refers to, recursively. This will not recurse * through non-extensible objects, on the assumption that those are already * deep-frozen. */ -extern JS_PUBLIC_API(bool) -JS_DeepFreezeObject(JSContext* cx, JS::Handle obj); +extern JS_PUBLIC_API bool JS_DeepFreezeObject(JSContext* cx, + JS::Handle obj); /** * Freezes an object; see ES5's Object.freeze(obj) method. */ -extern JS_PUBLIC_API(bool) -JS_FreezeObject(JSContext* cx, JS::Handle obj); - +extern JS_PUBLIC_API bool JS_FreezeObject(JSContext* cx, + JS::Handle obj); -/*** Property descriptors ************************************************************************/ +/*** Property descriptors ***************************************************/ namespace JS { -struct JS_PUBLIC_API(PropertyDescriptor) { - JSObject* obj; - unsigned attrs; - JSGetterOp getter; - JSSetterOp setter; - JS::Value value; - - PropertyDescriptor() - : obj(nullptr), attrs(0), getter(nullptr), setter(nullptr), value(JS::UndefinedValue()) - {} - - static void trace(PropertyDescriptor* self, JSTracer* trc) { self->trace(trc); } - void trace(JSTracer* trc); -}; - -template -class PropertyDescriptorOperations -{ - const PropertyDescriptor& desc() const { return static_cast(this)->get(); } - - bool has(unsigned bit) const { - MOZ_ASSERT(bit != 0); - MOZ_ASSERT((bit & (bit - 1)) == 0); // only a single bit - return (desc().attrs & bit) != 0; - } - - bool hasAny(unsigned bits) const { - return (desc().attrs & bits) != 0; - } - - bool hasAll(unsigned bits) const { - return (desc().attrs & bits) == bits; - } - - // Non-API attributes bit used internally for arguments objects. - enum { SHADOWABLE = JSPROP_INTERNAL_USE_BIT }; - - public: - // Descriptors with JSGetterOp/JSSetterOp are considered data - // descriptors. It's complicated. - bool isAccessorDescriptor() const { return hasAny(JSPROP_GETTER | JSPROP_SETTER); } - bool isGenericDescriptor() const { - return (desc().attrs& - (JSPROP_GETTER | JSPROP_SETTER | JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE)) == - (JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE); - } - bool isDataDescriptor() const { return !isAccessorDescriptor() && !isGenericDescriptor(); } - - bool hasConfigurable() const { return !has(JSPROP_IGNORE_PERMANENT); } - bool configurable() const { MOZ_ASSERT(hasConfigurable()); return !has(JSPROP_PERMANENT); } - - bool hasEnumerable() const { return !has(JSPROP_IGNORE_ENUMERATE); } - bool enumerable() const { MOZ_ASSERT(hasEnumerable()); return has(JSPROP_ENUMERATE); } - - bool hasValue() const { return !isAccessorDescriptor() && !has(JSPROP_IGNORE_VALUE); } - JS::HandleValue value() const { - return JS::HandleValue::fromMarkedLocation(&desc().value); - } +struct JS_PUBLIC_API PropertyDescriptor { + JSObject* obj; + unsigned attrs; + JSGetterOp getter; + JSSetterOp setter; + JS::Value value; + + PropertyDescriptor() + : obj(nullptr), + attrs(0), + getter(nullptr), + setter(nullptr), + value(JS::UndefinedValue()) {} + + static void trace(PropertyDescriptor* self, JSTracer* trc) { + self->trace(trc); + } + void trace(JSTracer* trc); +}; - bool hasWritable() const { return !isAccessorDescriptor() && !has(JSPROP_IGNORE_READONLY); } - bool writable() const { MOZ_ASSERT(hasWritable()); return !has(JSPROP_READONLY); } +} // namespace JS - bool hasGetterObject() const { return has(JSPROP_GETTER); } - JS::HandleObject getterObject() const { - MOZ_ASSERT(hasGetterObject()); - return JS::HandleObject::fromMarkedLocation( - reinterpret_cast(&desc().getter)); - } - bool hasSetterObject() const { return has(JSPROP_SETTER); } - JS::HandleObject setterObject() const { - MOZ_ASSERT(hasSetterObject()); - return JS::HandleObject::fromMarkedLocation( - reinterpret_cast(&desc().setter)); - } +namespace js { - bool hasGetterOrSetter() const { return desc().getter || desc().setter; } - bool isShared() const { return has(JSPROP_SHARED); } +template +class WrappedPtrOperations { + const JS::PropertyDescriptor& desc() const { + return static_cast(this)->get(); + } + + bool has(unsigned bit) const { + MOZ_ASSERT(bit != 0); + MOZ_ASSERT((bit & (bit - 1)) == 0); // only a single bit + return (desc().attrs & bit) != 0; + } + + bool hasAny(unsigned bits) const { return (desc().attrs & bits) != 0; } + + bool hasAll(unsigned bits) const { return (desc().attrs & bits) == bits; } + + // Non-API attributes bit used internally for arguments objects. + enum { SHADOWABLE = JSPROP_INTERNAL_USE_BIT }; + + public: + // Descriptors with JSGetterOp/JSSetterOp are considered data + // descriptors. It's complicated. + bool isAccessorDescriptor() const { + return hasAny(JSPROP_GETTER | JSPROP_SETTER); + } + bool isGenericDescriptor() const { + return (desc().attrs & (JSPROP_GETTER | JSPROP_SETTER | + JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE)) == + (JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE); + } + bool isDataDescriptor() const { + return !isAccessorDescriptor() && !isGenericDescriptor(); + } + + bool hasConfigurable() const { return !has(JSPROP_IGNORE_PERMANENT); } + bool configurable() const { + MOZ_ASSERT(hasConfigurable()); + return !has(JSPROP_PERMANENT); + } + + bool hasEnumerable() const { return !has(JSPROP_IGNORE_ENUMERATE); } + bool enumerable() const { + MOZ_ASSERT(hasEnumerable()); + return has(JSPROP_ENUMERATE); + } + + bool hasValue() const { + return !isAccessorDescriptor() && !has(JSPROP_IGNORE_VALUE); + } + JS::HandleValue value() const { + return JS::HandleValue::fromMarkedLocation(&desc().value); + } + + bool hasWritable() const { + return !isAccessorDescriptor() && !has(JSPROP_IGNORE_READONLY); + } + bool writable() const { + MOZ_ASSERT(hasWritable()); + return !has(JSPROP_READONLY); + } + + bool hasGetterObject() const { return has(JSPROP_GETTER); } + JS::HandleObject getterObject() const { + MOZ_ASSERT(hasGetterObject()); + return JS::HandleObject::fromMarkedLocation( + reinterpret_cast(&desc().getter)); + } + bool hasSetterObject() const { return has(JSPROP_SETTER); } + JS::HandleObject setterObject() const { + MOZ_ASSERT(hasSetterObject()); + return JS::HandleObject::fromMarkedLocation( + reinterpret_cast(&desc().setter)); + } + + bool hasGetterOrSetter() const { return desc().getter || desc().setter; } + + JS::HandleObject object() const { + return JS::HandleObject::fromMarkedLocation(&desc().obj); + } + unsigned attributes() const { return desc().attrs; } + JSGetterOp getter() const { return desc().getter; } + JSSetterOp setter() const { return desc().setter; } - JS::HandleObject object() const { - return JS::HandleObject::fromMarkedLocation(&desc().obj); - } - unsigned attributes() const { return desc().attrs; } - JSGetterOp getter() const { return desc().getter; } - JSSetterOp setter() const { return desc().setter; } - - void assertValid() const { + void assertValid() const { #ifdef DEBUG - MOZ_ASSERT((attributes() & ~(JSPROP_ENUMERATE | JSPROP_IGNORE_ENUMERATE | - JSPROP_PERMANENT | JSPROP_IGNORE_PERMANENT | - JSPROP_READONLY | JSPROP_IGNORE_READONLY | - JSPROP_IGNORE_VALUE | - JSPROP_GETTER | - JSPROP_SETTER | - JSPROP_SHARED | - JSPROP_REDEFINE_NONCONFIGURABLE | - JSPROP_RESOLVING | - SHADOWABLE)) == 0); - MOZ_ASSERT(!hasAll(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE)); - MOZ_ASSERT(!hasAll(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT)); - if (isAccessorDescriptor()) { - MOZ_ASSERT(has(JSPROP_SHARED)); - MOZ_ASSERT(!has(JSPROP_READONLY)); - MOZ_ASSERT(!has(JSPROP_IGNORE_READONLY)); - MOZ_ASSERT(!has(JSPROP_IGNORE_VALUE)); - MOZ_ASSERT(!has(SHADOWABLE)); - MOZ_ASSERT(value().isUndefined()); - MOZ_ASSERT_IF(!has(JSPROP_GETTER), !getter()); - MOZ_ASSERT_IF(!has(JSPROP_SETTER), !setter()); - } else { - MOZ_ASSERT(!hasAll(JSPROP_IGNORE_READONLY | JSPROP_READONLY)); - MOZ_ASSERT_IF(has(JSPROP_IGNORE_VALUE), value().isUndefined()); - } - MOZ_ASSERT(getter() != JS_PropertyStub); - MOZ_ASSERT(setter() != JS_StrictPropertyStub); - - MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_ENUMERATE)); - MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_PERMANENT)); - MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_READONLY)); - MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_VALUE)); - MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_REDEFINE_NONCONFIGURABLE)); + MOZ_ASSERT((attributes() & + ~(JSPROP_ENUMERATE | JSPROP_IGNORE_ENUMERATE | + JSPROP_PERMANENT | JSPROP_IGNORE_PERMANENT | JSPROP_READONLY | + JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE | JSPROP_GETTER | + JSPROP_SETTER | JSPROP_REDEFINE_NONCONFIGURABLE | + JSPROP_RESOLVING | SHADOWABLE)) == 0); + MOZ_ASSERT(!hasAll(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE)); + MOZ_ASSERT(!hasAll(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT)); + if (isAccessorDescriptor()) { + MOZ_ASSERT(!has(JSPROP_READONLY)); + MOZ_ASSERT(!has(JSPROP_IGNORE_READONLY)); + MOZ_ASSERT(!has(JSPROP_IGNORE_VALUE)); + MOZ_ASSERT(!has(SHADOWABLE)); + MOZ_ASSERT(value().isUndefined()); + MOZ_ASSERT_IF(!has(JSPROP_GETTER), !getter()); + MOZ_ASSERT_IF(!has(JSPROP_SETTER), !setter()); + } else { + MOZ_ASSERT(!hasAll(JSPROP_IGNORE_READONLY | JSPROP_READONLY)); + MOZ_ASSERT_IF(has(JSPROP_IGNORE_VALUE), value().isUndefined()); + } + + MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_ENUMERATE)); + MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_PERMANENT)); + MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_READONLY)); + MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_VALUE)); + MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_REDEFINE_NONCONFIGURABLE)); #endif - } + } - void assertComplete() const { + void assertComplete() const { #ifdef DEBUG - assertValid(); - MOZ_ASSERT((attributes() & ~(JSPROP_ENUMERATE | - JSPROP_PERMANENT | - JSPROP_READONLY | - JSPROP_GETTER | - JSPROP_SETTER | - JSPROP_SHARED | - JSPROP_REDEFINE_NONCONFIGURABLE | - JSPROP_RESOLVING | - SHADOWABLE)) == 0); - MOZ_ASSERT_IF(isAccessorDescriptor(), has(JSPROP_GETTER) && has(JSPROP_SETTER)); + assertValid(); + MOZ_ASSERT( + (attributes() & + ~(JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY | + JSPROP_GETTER | JSPROP_SETTER | JSPROP_REDEFINE_NONCONFIGURABLE | + JSPROP_RESOLVING | SHADOWABLE)) == 0); + MOZ_ASSERT_IF(isAccessorDescriptor(), + has(JSPROP_GETTER) && has(JSPROP_SETTER)); #endif - } + } - void assertCompleteIfFound() const { + void assertCompleteIfFound() const { #ifdef DEBUG - if (object()) - assertComplete(); + if (object()) assertComplete(); #endif - } + } }; -template -class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations -{ - PropertyDescriptor& desc() { return static_cast(this)->get(); } - - public: - void clear() { - object().set(nullptr); - setAttributes(0); - setGetter(nullptr); - setSetter(nullptr); - value().setUndefined(); - } - - void initFields(HandleObject obj, HandleValue v, unsigned attrs, - JSGetterOp getterOp, JSSetterOp setterOp) { - MOZ_ASSERT(getterOp != JS_PropertyStub); - MOZ_ASSERT(setterOp != JS_StrictPropertyStub); - - object().set(obj); - value().set(v); - setAttributes(attrs); - setGetter(getterOp); - setSetter(setterOp); - } - - void assign(PropertyDescriptor& other) { - object().set(other.obj); - setAttributes(other.attrs); - setGetter(other.getter); - setSetter(other.setter); - value().set(other.value); - } - - void setDataDescriptor(HandleValue v, unsigned attrs) { - MOZ_ASSERT((attrs & ~(JSPROP_ENUMERATE | - JSPROP_PERMANENT | - JSPROP_READONLY | - JSPROP_IGNORE_ENUMERATE | - JSPROP_IGNORE_PERMANENT | - JSPROP_IGNORE_READONLY)) == 0); - object().set(nullptr); - setAttributes(attrs); - setGetter(nullptr); - setSetter(nullptr); - value().set(v); - } - - JS::MutableHandleObject object() { - return JS::MutableHandleObject::fromMarkedLocation(&desc().obj); - } - unsigned& attributesRef() { return desc().attrs; } - JSGetterOp& getter() { return desc().getter; } - JSSetterOp& setter() { return desc().setter; } - JS::MutableHandleValue value() { - return JS::MutableHandleValue::fromMarkedLocation(&desc().value); - } - void setValue(JS::HandleValue v) { - MOZ_ASSERT(!(desc().attrs & (JSPROP_GETTER | JSPROP_SETTER))); - attributesRef() &= ~JSPROP_IGNORE_VALUE; - value().set(v); - } - - void setConfigurable(bool configurable) { - setAttributes((desc().attrs & ~(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT)) | - (configurable ? 0 : JSPROP_PERMANENT)); - } - void setEnumerable(bool enumerable) { - setAttributes((desc().attrs & ~(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE)) | - (enumerable ? JSPROP_ENUMERATE : 0)); - } - void setWritable(bool writable) { - MOZ_ASSERT(!(desc().attrs & (JSPROP_GETTER | JSPROP_SETTER))); - setAttributes((desc().attrs & ~(JSPROP_IGNORE_READONLY | JSPROP_READONLY)) | - (writable ? 0 : JSPROP_READONLY)); - } - void setAttributes(unsigned attrs) { desc().attrs = attrs; } - - void setGetter(JSGetterOp op) { - MOZ_ASSERT(op != JS_PropertyStub); - desc().getter = op; - } - void setSetter(JSSetterOp op) { - MOZ_ASSERT(op != JS_StrictPropertyStub); - desc().setter = op; - } - void setGetterObject(JSObject* obj) { - desc().getter = reinterpret_cast(obj); - desc().attrs &= ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY); - desc().attrs |= JSPROP_GETTER | JSPROP_SHARED; - } - void setSetterObject(JSObject* obj) { - desc().setter = reinterpret_cast(obj); - desc().attrs &= ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY); - desc().attrs |= JSPROP_SETTER | JSPROP_SHARED; - } - - JS::MutableHandleObject getterObject() { - MOZ_ASSERT(this->hasGetterObject()); - return JS::MutableHandleObject::fromMarkedLocation( - reinterpret_cast(&desc().getter)); - } - JS::MutableHandleObject setterObject() { - MOZ_ASSERT(this->hasSetterObject()); - return JS::MutableHandleObject::fromMarkedLocation( - reinterpret_cast(&desc().setter)); - } +template +class MutableWrappedPtrOperations + : public js::WrappedPtrOperations { + JS::PropertyDescriptor& desc() { return static_cast(this)->get(); } + + public: + void clear() { + object().set(nullptr); + setAttributes(0); + setGetter(nullptr); + setSetter(nullptr); + value().setUndefined(); + } + + void initFields(JS::HandleObject obj, JS::HandleValue v, unsigned attrs, + JSGetterOp getterOp, JSSetterOp setterOp) { + object().set(obj); + value().set(v); + setAttributes(attrs); + setGetter(getterOp); + setSetter(setterOp); + } + + void assign(JS::PropertyDescriptor& other) { + object().set(other.obj); + setAttributes(other.attrs); + setGetter(other.getter); + setSetter(other.setter); + value().set(other.value); + } + + void setDataDescriptor(JS::HandleValue v, unsigned attrs) { + MOZ_ASSERT((attrs & ~(JSPROP_ENUMERATE | JSPROP_PERMANENT | + JSPROP_READONLY | JSPROP_IGNORE_ENUMERATE | + JSPROP_IGNORE_PERMANENT | JSPROP_IGNORE_READONLY)) == + 0); + object().set(nullptr); + setAttributes(attrs); + setGetter(nullptr); + setSetter(nullptr); + value().set(v); + } + + JS::MutableHandleObject object() { + return JS::MutableHandleObject::fromMarkedLocation(&desc().obj); + } + unsigned& attributesRef() { return desc().attrs; } + JSGetterOp& getter() { return desc().getter; } + JSSetterOp& setter() { return desc().setter; } + JS::MutableHandleValue value() { + return JS::MutableHandleValue::fromMarkedLocation(&desc().value); + } + void setValue(JS::HandleValue v) { + MOZ_ASSERT(!(desc().attrs & (JSPROP_GETTER | JSPROP_SETTER))); + attributesRef() &= ~JSPROP_IGNORE_VALUE; + value().set(v); + } + + void setConfigurable(bool configurable) { + setAttributes( + (desc().attrs & ~(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT)) | + (configurable ? 0 : JSPROP_PERMANENT)); + } + void setEnumerable(bool enumerable) { + setAttributes( + (desc().attrs & ~(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE)) | + (enumerable ? JSPROP_ENUMERATE : 0)); + } + void setWritable(bool writable) { + MOZ_ASSERT(!(desc().attrs & (JSPROP_GETTER | JSPROP_SETTER))); + setAttributes((desc().attrs & ~(JSPROP_IGNORE_READONLY | JSPROP_READONLY)) | + (writable ? 0 : JSPROP_READONLY)); + } + void setAttributes(unsigned attrs) { desc().attrs = attrs; } + + void setGetter(JSGetterOp op) { desc().getter = op; } + void setSetter(JSSetterOp op) { desc().setter = op; } + void setGetterObject(JSObject* obj) { + desc().getter = reinterpret_cast(obj); + desc().attrs &= + ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY); + desc().attrs |= JSPROP_GETTER; + } + void setSetterObject(JSObject* obj) { + desc().setter = reinterpret_cast(obj); + desc().attrs &= + ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY); + desc().attrs |= JSPROP_SETTER; + } + + JS::MutableHandleObject getterObject() { + MOZ_ASSERT(this->hasGetterObject()); + return JS::MutableHandleObject::fromMarkedLocation( + reinterpret_cast(&desc().getter)); + } + JS::MutableHandleObject setterObject() { + MOZ_ASSERT(this->hasSetterObject()); + return JS::MutableHandleObject::fromMarkedLocation( + reinterpret_cast(&desc().setter)); + } }; -} /* namespace JS */ - -namespace js { - -template <> -class RootedBase - : public JS::MutablePropertyDescriptorOperations> -{}; - -template <> -class HandleBase - : public JS::PropertyDescriptorOperations> -{}; - -template <> -class MutableHandleBase - : public JS::MutablePropertyDescriptorOperations> -{}; - -} /* namespace js */ +} // namespace js namespace JS { -extern JS_PUBLIC_API(bool) -ObjectToCompletePropertyDescriptor(JSContext* cx, - JS::HandleObject obj, - JS::HandleValue descriptor, - JS::MutableHandle desc); +extern JS_PUBLIC_API bool ObjectToCompletePropertyDescriptor( + JSContext* cx, JS::HandleObject obj, JS::HandleValue descriptor, + 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 +extern JS_PUBLIC_API bool FromPropertyDescriptor( + JSContext* cx, JS::Handle desc, + JS::MutableHandleValue vp); +} // namespace JS -/*** Standard internal methods ******************************************************************** +/*** Standard internal methods ********************************************** * * The functions below are the fundamental operations on objects. * @@ -2831,8 +2488,8 @@ * * Implements: ES6 [[GetPrototypeOf]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_GetPrototype(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject result); +extern JS_PUBLIC_API bool JS_GetPrototype(JSContext* cx, JS::HandleObject obj, + JS::MutableHandleObject result); /** * If |obj| (underneath any functionally-transparent wrapper proxies) has as @@ -2841,9 +2498,9 @@ * 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); +extern JS_PUBLIC_API bool JS_GetPrototypeIfOrdinary( + JSContext* cx, JS::HandleObject obj, bool* isOrdinary, + JS::MutableHandleObject result); /** * Change the prototype of obj. @@ -2858,8 +2515,8 @@ * all other objects in the same "group" as obj to be permanently deoptimized. * It's better to create the object with the right prototype from the start. */ -extern JS_PUBLIC_API(bool) -JS_SetPrototype(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto); +extern JS_PUBLIC_API bool JS_SetPrototype(JSContext* cx, JS::HandleObject obj, + JS::HandleObject proto); /** * Determine whether obj is extensible. Extensible objects can have new @@ -2868,8 +2525,8 @@ * * Implements: ES6 [[IsExtensible]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_IsExtensible(JSContext* cx, JS::HandleObject obj, bool* extensible); +extern JS_PUBLIC_API bool JS_IsExtensible(JSContext* cx, JS::HandleObject obj, + bool* extensible); /** * Attempt to make |obj| non-extensible. @@ -2879,8 +2536,9 @@ * * Implements: ES6 [[PreventExtensions]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result); +extern JS_PUBLIC_API bool JS_PreventExtensions(JSContext* cx, + JS::HandleObject obj, + JS::ObjectOpResult& result); /** * Attempt to make the [[Prototype]] of |obj| immutable, such that any attempt @@ -2891,8 +2549,9 @@ * * This is a nonstandard internal method. */ -extern JS_PUBLIC_API(bool) -JS_SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded); +extern JS_PUBLIC_API bool JS_SetImmutablePrototype(JSContext* cx, + JS::HandleObject obj, + bool* succeeded); /** * Get a description of one of obj's own properties. If no such property exists @@ -2900,17 +2559,17 @@ * * Implements: ES6 [[GetOwnProperty]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_GetOwnPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); - -extern JS_PUBLIC_API(bool) -JS_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, - JS::MutableHandle desc); - -extern JS_PUBLIC_API(bool) -JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, - JS::MutableHandle desc); +extern JS_PUBLIC_API bool JS_GetOwnPropertyDescriptorById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::MutableHandle desc); + +extern JS_PUBLIC_API bool JS_GetOwnPropertyDescriptor( + JSContext* cx, JS::HandleObject obj, const char* name, + JS::MutableHandle desc); + +extern JS_PUBLIC_API bool JS_GetOwnUCPropertyDescriptor( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::MutableHandle desc); /** * Like JS_GetOwnPropertyDescriptorById, but also searches the prototype chain @@ -2918,13 +2577,17 @@ * property is found is returned in desc.object(). If the property is not found * on the prototype chain, this returns true with desc.object() set to null. */ -extern JS_PUBLIC_API(bool) -JS_GetPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); - -extern JS_PUBLIC_API(bool) -JS_GetPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, - JS::MutableHandle desc); +extern JS_PUBLIC_API bool JS_GetPropertyDescriptorById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::MutableHandle desc); + +extern JS_PUBLIC_API bool JS_GetPropertyDescriptor( + JSContext* cx, JS::HandleObject obj, const char* name, + JS::MutableHandle desc); + +extern JS_PUBLIC_API bool JS_GetUCPropertyDescriptor( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::MutableHandle desc); /** * Define a property on obj. @@ -2937,129 +2600,160 @@ * * Implements: ES6 [[DefineOwnProperty]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc, - JS::ObjectOpResult& result); +extern JS_PUBLIC_API bool JS_DefinePropertyById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::Handle desc, JS::ObjectOpResult& result); /** * Define a property on obj, throwing a TypeError if the attempt fails. * This is the C++ equivalent of `Object.defineProperty(obj, id, desc)`. */ -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleString value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, int32_t value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, uint32_t value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, double value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleValue value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleObject value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleString value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, int32_t value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, uint32_t value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, double value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - 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); - -extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::HandleValue value, unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::HandleObject value, unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::HandleString value, unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - int32_t value, unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - uint32_t value, unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - double value, unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleObject value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleString value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, int32_t value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, uint32_t value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, double value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); +extern JS_PUBLIC_API bool JS_DefinePropertyById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::Handle desc); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::HandleValue value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, JSNative getter, + JSNative setter, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::HandleObject value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::HandleString value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, int32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, uint32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, double value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::HandleValue value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, JSNative getter, + JSNative setter, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::HandleObject value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::HandleString value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, int32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, uint32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, double value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + 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); + +extern JS_PUBLIC_API bool JS_DefineUCProperty( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::HandleValue value, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, JSNative getter, + JSNative setter, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::HandleObject value, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::HandleString value, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, int32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, uint32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, double value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::HandleValue value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, JSNative getter, + JSNative setter, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::HandleObject value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::HandleString value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, int32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, uint32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, double value, + unsigned attrs); /** * Compute the expression `id in obj`. @@ -3070,29 +2764,31 @@ * * Implements: ES6 [[Has]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_HasPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); +extern JS_PUBLIC_API bool JS_HasPropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, bool* foundp); + +extern JS_PUBLIC_API bool JS_HasProperty(JSContext* cx, JS::HandleObject obj, + const char* name, bool* foundp); + +extern JS_PUBLIC_API bool JS_HasUCProperty(JSContext* cx, JS::HandleObject obj, + const char16_t* name, size_t namelen, + bool* vp); -extern JS_PUBLIC_API(bool) -JS_HasProperty(JSContext* cx, JS::HandleObject obj, const char* name, bool* foundp); - -extern JS_PUBLIC_API(bool) -JS_HasUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - bool* vp); - -extern JS_PUBLIC_API(bool) -JS_HasElement(JSContext* cx, JS::HandleObject obj, uint32_t index, bool* foundp); +extern JS_PUBLIC_API bool JS_HasElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, bool* foundp); /** * Determine whether obj has an own property with the key `id`. * * Implements: ES6 7.3.11 HasOwnProperty(O, P). */ -extern JS_PUBLIC_API(bool) -JS_HasOwnPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); +extern JS_PUBLIC_API bool JS_HasOwnPropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, bool* foundp); -extern JS_PUBLIC_API(bool) -JS_HasOwnProperty(JSContext* cx, JS::HandleObject obj, const char* name, bool* foundp); +extern JS_PUBLIC_API bool JS_HasOwnProperty(JSContext* cx, JS::HandleObject obj, + const char* name, bool* foundp); /** * Get the value of the property `obj[id]`, or undefined if no such property @@ -3105,13 +2801,17 @@ * * Implements: ES6 [[Get]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_ForwardGetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::HandleValue receiver, JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_ForwardGetElementTo(JSContext* cx, JS::HandleObject obj, uint32_t index, - JS::HandleObject receiver, JS::MutableHandleValue vp); +extern JS_PUBLIC_API bool JS_ForwardGetPropertyTo(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::HandleValue receiver, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API bool JS_ForwardGetElementTo(JSContext* cx, + JS::HandleObject obj, + uint32_t index, + JS::HandleObject receiver, + JS::MutableHandleValue vp); /** * Get the value of the property `obj[id]`, or undefined if no such property @@ -3119,19 +2819,22 @@ * * Implements: ES6 7.3.1 Get(O, P). */ -extern JS_PUBLIC_API(bool) -JS_GetPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_GetProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_GetUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_GetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp); +extern JS_PUBLIC_API bool JS_GetPropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API bool JS_GetProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API bool JS_GetUCProperty(JSContext* cx, JS::HandleObject obj, + const char16_t* name, size_t namelen, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API bool JS_GetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::MutableHandleValue vp); /** * Perform the same property assignment as `Reflect.set(obj, id, v, receiver)`. @@ -3141,9 +2844,9 @@ * * Implements: ES6 [[Set]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_ForwardSetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, - JS::HandleValue receiver, JS::ObjectOpResult& result); +extern JS_PUBLIC_API bool JS_ForwardSetPropertyTo( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, + JS::HandleValue receiver, JS::ObjectOpResult& result); /** * Perform the assignment `obj[id] = v`. @@ -3151,33 +2854,35 @@ * This function performs non-strict assignment, so if the property is * read-only, nothing happens and no error is thrown. */ -extern JS_PUBLIC_API(bool) -JS_SetPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v); +extern JS_PUBLIC_API bool JS_SetPropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::HandleValue v); -extern JS_PUBLIC_API(bool) -JS_SetProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleValue v); +extern JS_PUBLIC_API bool JS_SetProperty(JSContext* cx, JS::HandleObject obj, + const char* name, JS::HandleValue v); -extern JS_PUBLIC_API(bool) -JS_SetUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::HandleValue v); +extern JS_PUBLIC_API bool JS_SetUCProperty(JSContext* cx, JS::HandleObject obj, + const char16_t* name, size_t namelen, + JS::HandleValue v); -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleValue v); +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, JS::HandleValue v); -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleObject v); +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, JS::HandleObject v); -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleString v); +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, JS::HandleString v); -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, int32_t v); +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, int32_t v); -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, uint32_t v); +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, uint32_t v); -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, double v); +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, double v); /** * Delete a property. This is the C++ equivalent of @@ -3190,33 +2895,37 @@ * * Implements: ES6 [[Delete]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_DeletePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::ObjectOpResult& result); - -extern JS_PUBLIC_API(bool) -JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, const char* name, - JS::ObjectOpResult& result); - -extern JS_PUBLIC_API(bool) -JS_DeleteUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::ObjectOpResult& result); - -extern JS_PUBLIC_API(bool) -JS_DeleteElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::ObjectOpResult& result); +extern JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::ObjectOpResult& result); + +extern JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::ObjectOpResult& result); + +extern JS_PUBLIC_API bool JS_DeleteUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, + JS::ObjectOpResult& result); + +extern JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::ObjectOpResult& result); /** * Delete a property, ignoring strict failures. This is the C++ equivalent of * the JS `delete obj[id]` in non-strict mode code. */ -extern JS_PUBLIC_API(bool) -JS_DeletePropertyById(JSContext* cx, JS::HandleObject obj, jsid id); +extern JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx, + JS::HandleObject obj, jsid id); -extern JS_PUBLIC_API(bool) -JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, const char* name); +extern JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, + const char* name); -extern JS_PUBLIC_API(bool) -JS_DeleteElement(JSContext* cx, JS::HandleObject obj, uint32_t index); +extern JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, JS::HandleObject obj, + uint32_t index); /** * Get an array of the non-symbol enumerable properties of obj. @@ -3233,8 +2942,8 @@ * 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); +extern JS_PUBLIC_API bool JS_Enumerate(JSContext* cx, JS::HandleObject obj, + JS::MutableHandle props); /* * API for determining callability and constructability. [[Call]] and @@ -3253,8 +2962,7 @@ * Functions are callable. A scripted proxy or wrapper is callable if its * target is callable. Most other objects aren't callable. */ -extern JS_PUBLIC_API(bool) -IsCallable(JSObject* obj); +extern JS_PUBLIC_API bool IsCallable(JSObject* obj); /** * Return true if the given object is a constructor. In ES6 terms, an object is @@ -3267,8 +2975,7 @@ * functions are not. A scripted proxy or wrapper is a constructor if its * target is a constructor. */ -extern JS_PUBLIC_API(bool) -IsConstructor(JSObject* obj); +extern JS_PUBLIC_API bool IsConstructor(JSObject* obj); } /* namespace JS */ @@ -3279,55 +2986,59 @@ * Implements: ES6 7.3.12 Call(F, V, [argumentsList]). * Use this function to invoke the [[Call]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_CallFunctionValue(JSContext* cx, JS::HandleObject obj, JS::HandleValue fval, - const JS::HandleValueArray& args, JS::MutableHandleValue rval); - -extern JS_PUBLIC_API(bool) -JS_CallFunction(JSContext* cx, JS::HandleObject obj, JS::HandleFunction fun, - const JS::HandleValueArray& args, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool JS_CallFunctionValue(JSContext* cx, + JS::HandleObject obj, + JS::HandleValue fval, + const JS::HandleValueArray& args, + JS::MutableHandleValue rval); + +extern JS_PUBLIC_API bool JS_CallFunction(JSContext* cx, JS::HandleObject obj, + JS::HandleFunction fun, + const JS::HandleValueArray& args, + JS::MutableHandleValue rval); /** * Perform the method call `rval = obj[name](args)`. */ -extern JS_PUBLIC_API(bool) -JS_CallFunctionName(JSContext* cx, JS::HandleObject obj, const char* name, - const JS::HandleValueArray& args, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool JS_CallFunctionName(JSContext* cx, + JS::HandleObject obj, + const char* name, + const JS::HandleValueArray& args, + JS::MutableHandleValue rval); namespace JS { -static inline bool -Call(JSContext* cx, JS::HandleObject thisObj, JS::HandleFunction fun, - const JS::HandleValueArray& args, MutableHandleValue rval) -{ - return !!JS_CallFunction(cx, thisObj, fun, args, rval); +static inline bool Call(JSContext* cx, JS::HandleObject thisObj, + JS::HandleFunction fun, + const JS::HandleValueArray& args, + MutableHandleValue rval) { + return !!JS_CallFunction(cx, thisObj, fun, args, rval); } -static inline bool -Call(JSContext* cx, JS::HandleObject thisObj, JS::HandleValue fun, const JS::HandleValueArray& args, - MutableHandleValue rval) -{ - return !!JS_CallFunctionValue(cx, thisObj, fun, args, rval); +static inline bool Call(JSContext* cx, JS::HandleObject thisObj, + JS::HandleValue fun, const JS::HandleValueArray& args, + MutableHandleValue rval) { + return !!JS_CallFunctionValue(cx, thisObj, fun, args, rval); } -static inline bool -Call(JSContext* cx, JS::HandleObject thisObj, const char* name, const JS::HandleValueArray& args, - MutableHandleValue rval) -{ - return !!JS_CallFunctionName(cx, thisObj, name, args, rval); +static inline bool Call(JSContext* cx, JS::HandleObject thisObj, + const char* name, const JS::HandleValueArray& args, + MutableHandleValue rval) { + return !!JS_CallFunctionName(cx, thisObj, name, args, rval); } -extern JS_PUBLIC_API(bool) -Call(JSContext* cx, JS::HandleValue thisv, JS::HandleValue fun, const JS::HandleValueArray& args, - MutableHandleValue rval); - -static inline bool -Call(JSContext* cx, JS::HandleValue thisv, JS::HandleObject funObj, const JS::HandleValueArray& args, - MutableHandleValue rval) -{ - MOZ_ASSERT(funObj); - JS::RootedValue fun(cx, JS::ObjectValue(*funObj)); - return Call(cx, thisv, fun, args, rval); +extern JS_PUBLIC_API bool Call(JSContext* cx, JS::HandleValue thisv, + JS::HandleValue fun, + const JS::HandleValueArray& args, + MutableHandleValue rval); + +static inline bool Call(JSContext* cx, JS::HandleValue thisv, + JS::HandleObject funObj, + const JS::HandleValueArray& args, + MutableHandleValue rval) { + MOZ_ASSERT(funObj); + JS::RootedValue fun(cx, JS::ObjectValue(*funObj)); + return Call(cx, thisv, fun, args, rval); } /** @@ -3342,9 +3053,10 @@ * Implements: ES6 7.3.13 Construct(F, [argumentsList], [newTarget]). * Use this function to invoke the [[Construct]] internal method. */ -extern JS_PUBLIC_API(bool) -Construct(JSContext* cx, JS::HandleValue fun, HandleObject newTarget, - const JS::HandleValueArray &args, MutableHandleObject objp); +extern JS_PUBLIC_API bool Construct(JSContext* cx, JS::HandleValue fun, + HandleObject newTarget, + const JS::HandleValueArray& args, + MutableHandleObject objp); /** * Invoke a constructor. This is the C++ equivalent of @@ -3353,9 +3065,9 @@ * 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, - MutableHandleObject objp); +extern JS_PUBLIC_API bool Construct(JSContext* cx, JS::HandleValue fun, + const JS::HandleValueArray& args, + MutableHandleObject objp); } /* namespace JS */ @@ -3363,48 +3075,55 @@ * Invoke a constructor, like the JS expression `new ctor(...args)`. Returns * the new object, or null on error. */ -extern JS_PUBLIC_API(JSObject*) -JS_New(JSContext* cx, JS::HandleObject ctor, const JS::HandleValueArray& args); - +extern JS_PUBLIC_API JSObject* JS_New(JSContext* cx, JS::HandleObject ctor, + const JS::HandleValueArray& args); -/*** Other property-defining functions ***********************************************************/ - -extern JS_PUBLIC_API(JSObject*) -JS_DefineObject(JSContext* cx, JS::HandleObject obj, const char* name, - const JSClass* clasp = nullptr, unsigned attrs = 0); - -extern JS_PUBLIC_API(bool) -JS_DefineConstDoubles(JSContext* cx, JS::HandleObject obj, const JSConstDoubleSpec* cds); - -extern JS_PUBLIC_API(bool) -JS_DefineConstIntegers(JSContext* cx, JS::HandleObject obj, const JSConstIntegerSpec* cis); - -extern JS_PUBLIC_API(bool) -JS_DefineProperties(JSContext* cx, JS::HandleObject obj, const JSPropertySpec* ps); +/*** Other property-defining functions **************************************/ +extern JS_PUBLIC_API JSObject* JS_DefineObject(JSContext* cx, + JS::HandleObject obj, + const char* name, + const JSClass* clasp = nullptr, + unsigned attrs = 0); + +extern JS_PUBLIC_API bool JS_DefineConstDoubles(JSContext* cx, + JS::HandleObject obj, + const JSConstDoubleSpec* cds); + +extern JS_PUBLIC_API bool JS_DefineConstIntegers(JSContext* cx, + JS::HandleObject obj, + const JSConstIntegerSpec* cis); + +extern JS_PUBLIC_API bool JS_DefineProperties(JSContext* cx, + JS::HandleObject obj, + const JSPropertySpec* ps); /* * */ -extern JS_PUBLIC_API(bool) -JS_AlreadyHasOwnPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - bool* foundp); - -extern JS_PUBLIC_API(bool) -JS_AlreadyHasOwnProperty(JSContext* cx, JS::HandleObject obj, const char* name, - bool* foundp); - -extern JS_PUBLIC_API(bool) -JS_AlreadyHasOwnUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, - size_t namelen, bool* foundp); - -extern JS_PUBLIC_API(bool) -JS_AlreadyHasOwnElement(JSContext* cx, JS::HandleObject obj, uint32_t index, bool* foundp); +extern JS_PUBLIC_API bool JS_AlreadyHasOwnPropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + bool* foundp); + +extern JS_PUBLIC_API bool JS_AlreadyHasOwnProperty(JSContext* cx, + JS::HandleObject obj, + const char* name, + bool* foundp); + +extern JS_PUBLIC_API bool JS_AlreadyHasOwnUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, + bool* foundp); + +extern JS_PUBLIC_API bool JS_AlreadyHasOwnElement(JSContext* cx, + JS::HandleObject obj, + uint32_t index, bool* foundp); -extern JS_PUBLIC_API(JSObject*) -JS_NewArrayObject(JSContext* cx, const JS::HandleValueArray& contents); +extern JS_PUBLIC_API JSObject* JS_NewArrayObject( + JSContext* cx, const JS::HandleValueArray& contents); -extern JS_PUBLIC_API(JSObject*) -JS_NewArrayObject(JSContext* cx, size_t length); +extern JS_PUBLIC_API JSObject* JS_NewArrayObject(JSContext* cx, size_t length); /** * Returns true and sets |*isArray| indicating whether |value| is an Array @@ -3413,8 +3132,8 @@ * This method returns true with |*isArray == false| when passed a proxy whose * target is an Array, or when passed a revoked proxy. */ -extern JS_PUBLIC_API(bool) -JS_IsArrayObject(JSContext* cx, JS::HandleValue value, bool* isArray); +extern JS_PUBLIC_API bool JS_IsArrayObject(JSContext* cx, JS::HandleValue value, + bool* isArray); /** * Returns true and sets |*isArray| indicating whether |obj| is an Array object @@ -3423,14 +3142,16 @@ * This method returns true with |*isArray == false| when passed a proxy whose * target is an Array, or when passed a revoked proxy. */ -extern JS_PUBLIC_API(bool) -JS_IsArrayObject(JSContext* cx, JS::HandleObject obj, bool* isArray); +extern JS_PUBLIC_API bool JS_IsArrayObject(JSContext* cx, JS::HandleObject obj, + bool* isArray); -extern JS_PUBLIC_API(bool) -JS_GetArrayLength(JSContext* cx, JS::Handle obj, uint32_t* lengthp); - -extern JS_PUBLIC_API(bool) -JS_SetArrayLength(JSContext* cx, JS::Handle obj, uint32_t length); +extern JS_PUBLIC_API bool JS_GetArrayLength(JSContext* cx, + JS::Handle obj, + uint32_t* lengthp); + +extern JS_PUBLIC_API bool JS_SetArrayLength(JSContext* cx, + JS::Handle obj, + uint32_t length); namespace JS { @@ -3441,8 +3162,8 @@ * 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); +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 @@ -3451,8 +3172,8 @@ * 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); +extern JS_PUBLIC_API bool IsSetObject(JSContext* cx, JS::HandleObject obj, + bool* isSet); } /* namespace JS */ @@ -3460,23 +3181,60 @@ * Assign 'undefined' to all of the object's non-reserved slots. Note: this is * done for all slots, regardless of the associated property descriptor. */ -JS_PUBLIC_API(void) -JS_SetAllNonReservedSlotsToUndefined(JSContext* cx, JSObject* objArg); +JS_PUBLIC_API void JS_SetAllNonReservedSlotsToUndefined(JSContext* cx, + JSObject* objArg); /** * Create a new array buffer with the given contents. It must be legal to pass * these contents to free(). On success, the ownership is transferred to the * new array buffer. */ -extern JS_PUBLIC_API(JSObject*) -JS_NewArrayBufferWithContents(JSContext* cx, size_t nbytes, void* contents); +extern JS_PUBLIC_API JSObject* JS_NewArrayBufferWithContents(JSContext* cx, + size_t nbytes, + void* contents); + +namespace JS { + +using BufferContentsRefFunc = void (*)(void* contents, void* userData); + +} /* namespace JS */ /** - * 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. + * Create a new array buffer with the given contents. The ref and unref + * functions should increment or decrement the reference count of the contents. + * These functions allow array buffers to be used with embedder objects that + * use reference counting, for example. The contents must not be modified by + * any reference holders, internal or external. + * + * On success, the new array buffer takes a reference, and |ref(contents, + * refUserData)| will be called. When the array buffer is ready to be disposed + * of, |unref(contents, refUserData)| will be called to release the array + * buffer's reference on the contents. + * + * The ref and unref functions must not call any JSAPI functions that could + * cause a garbage collection. + * + * The ref function is optional. If it is nullptr, the caller is responsible + * for incrementing the reference count before passing the contents to this + * function. This also allows using non-reference-counted contents that must be + * freed with some function other than free(). + * + * The ref function may also be called in case the buffer is cloned in some + * way. Currently this is not used, but it may be in the future. If the ref + * function is nullptr, any operation where an extra reference would otherwise + * be taken, will either copy the data, or throw an exception. + */ +extern JS_PUBLIC_API JSObject* JS_NewExternalArrayBuffer( + JSContext* cx, size_t nbytes, void* contents, JS::BufferContentsRefFunc ref, + JS::BufferContentsRefFunc unref, void* refUserData = nullptr); + +/** + * 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); +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 @@ -3484,42 +3242,46 @@ * of the return value and must free it or transfer ownership via * JS_NewArrayBufferWithContents when done using it. */ -extern JS_PUBLIC_API(void*) -JS_StealArrayBufferContents(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API void* 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. + * 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: + * 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. + * 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. + * 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); +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. */ -extern JS_PUBLIC_API(JSObject*) -JS_NewMappedArrayBufferWithContents(JSContext* cx, size_t nbytes, void* contents); +extern JS_PUBLIC_API JSObject* JS_NewMappedArrayBufferWithContents( + JSContext* cx, size_t nbytes, void* contents); /** * Create memory mapped array buffer contents. * Caller must take care of closing fd after calling this function. */ -extern JS_PUBLIC_API(void*) -JS_CreateMappedArrayBufferContents(int fd, size_t offset, size_t length); +extern JS_PUBLIC_API void* JS_CreateMappedArrayBufferContents(int fd, + size_t offset, + size_t length); /** * Release the allocated resource of mapped array buffer contents before the @@ -3528,30 +3290,28 @@ * with this content, then JS_DetachArrayBuffer() should be used instead to * release the resource used by the object. */ -extern JS_PUBLIC_API(void) -JS_ReleaseMappedArrayBufferContents(void* contents, size_t length); - -extern JS_PUBLIC_API(JS::Value) -JS_GetReservedSlot(JSObject* obj, uint32_t index); +extern JS_PUBLIC_API void JS_ReleaseMappedArrayBufferContents(void* contents, + size_t length); -extern JS_PUBLIC_API(void) -JS_SetReservedSlot(JSObject* obj, uint32_t index, const JS::Value& v); +extern JS_PUBLIC_API JS::Value JS_GetReservedSlot(JSObject* obj, + uint32_t index); +extern JS_PUBLIC_API void JS_SetReservedSlot(JSObject* obj, uint32_t index, + const JS::Value& v); /************************************************************************/ /* * Functions and scripts. */ -extern JS_PUBLIC_API(JSFunction*) -JS_NewFunction(JSContext* cx, JSNative call, unsigned nargs, unsigned flags, - const char* name); +extern JS_PUBLIC_API JSFunction* JS_NewFunction(JSContext* cx, JSNative call, + unsigned nargs, unsigned flags, + const char* name); namespace JS { -extern JS_PUBLIC_API(JSFunction*) -GetSelfHostedFunction(JSContext* cx, const char* selfHostedName, HandleId id, - unsigned nargs); +extern JS_PUBLIC_API JSFunction* GetSelfHostedFunction( + JSContext* cx, const char* selfHostedName, HandleId id, unsigned nargs); /** * Create a new function based on the given JSFunctionSpec, *fs. @@ -3561,13 +3321,13 @@ * Unlike JS_DefineFunctions, this does not treat fs as an array. * *fs must not be JS_FS_END. */ -extern JS_PUBLIC_API(JSFunction*) -NewFunctionFromSpec(JSContext* cx, const JSFunctionSpec* fs, HandleId id); +extern JS_PUBLIC_API JSFunction* NewFunctionFromSpec(JSContext* cx, + const JSFunctionSpec* fs, + HandleId id); } /* namespace JS */ -extern JS_PUBLIC_API(JSObject*) -JS_GetFunctionObject(JSFunction* fun); +extern JS_PUBLIC_API JSObject* JS_GetFunctionObject(JSFunction* fun); /** * Return the function's identifier as a JSString, or null if fun is unnamed. @@ -3575,8 +3335,7 @@ * reference to it if fun is well-connected or rooted, and provided you bound * the use of the saved reference by fun's lifetime. */ -extern JS_PUBLIC_API(JSString*) -JS_GetFunctionId(JSFunction* fun); +extern JS_PUBLIC_API JSString* JS_GetFunctionId(JSFunction* fun); /** * Return a function's display name. This is the defined name if one was given @@ -3585,14 +3344,12 @@ * still return nullptr if a useful display name could not be inferred. The * same restrictions on rooting as those in JS_GetFunctionId apply. */ -extern JS_PUBLIC_API(JSString*) -JS_GetFunctionDisplayId(JSFunction* fun); +extern JS_PUBLIC_API JSString* JS_GetFunctionDisplayId(JSFunction* fun); /* * Return the arity (length) of fun. */ -extern JS_PUBLIC_API(uint16_t) -JS_GetFunctionArity(JSFunction* fun); +extern JS_PUBLIC_API uint16_t JS_GetFunctionArity(JSFunction* fun); /** * Infallible predicate to test whether obj is a function object (faster than @@ -3600,37 +3357,32 @@ * overwritten the "Function" identifier with a different constructor and then * created instances using that constructor that might be passed in as obj). */ -extern JS_PUBLIC_API(bool) -JS_ObjectIsFunction(JSContext* cx, JSObject* obj); +extern JS_PUBLIC_API bool JS_ObjectIsFunction(JSContext* cx, JSObject* obj); -extern JS_PUBLIC_API(bool) -JS_IsNativeFunction(JSObject* funobj, JSNative call); +extern JS_PUBLIC_API bool JS_IsNativeFunction(JSObject* funobj, JSNative call); /** Return whether the given function is a valid constructor. */ -extern JS_PUBLIC_API(bool) -JS_IsConstructor(JSFunction* fun); +extern JS_PUBLIC_API bool JS_IsConstructor(JSFunction* fun); + +extern JS_PUBLIC_API bool 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, + unsigned nargs, unsigned attrs); -extern JS_PUBLIC_API(bool) -JS_DefineFunctions(JSContext* cx, JS::Handle obj, const JSFunctionSpec* fs); +extern JS_PUBLIC_API JSFunction* JS_DefineUCFunction( + JSContext* cx, JS::Handle obj, const char16_t* name, + size_t namelen, JSNative call, unsigned nargs, unsigned attrs); -extern JS_PUBLIC_API(JSFunction*) -JS_DefineFunction(JSContext* cx, JS::Handle obj, const char* name, JSNative call, - unsigned nargs, unsigned attrs); - -extern JS_PUBLIC_API(JSFunction*) -JS_DefineUCFunction(JSContext* cx, JS::Handle obj, - const char16_t* name, size_t namelen, JSNative call, - unsigned nargs, unsigned attrs); - -extern JS_PUBLIC_API(JSFunction*) -JS_DefineFunctionById(JSContext* cx, JS::Handle obj, JS::Handle id, JSNative call, - unsigned nargs, unsigned attrs); +extern JS_PUBLIC_API JSFunction* 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 bool JS_IsFunctionBound(JSFunction* fun); -extern JS_PUBLIC_API(JSObject*) -JS_GetBoundFunctionTarget(JSFunction* fun); +extern JS_PUBLIC_API JSObject* JS_GetBoundFunctionTarget(JSFunction* fun); namespace JS { @@ -3638,18 +3390,18 @@ * Clone a top-level function into cx's global. This function will dynamically * fail if funobj was lexically nested inside some other function. */ -extern JS_PUBLIC_API(JSObject*) -CloneFunctionObject(JSContext* cx, HandleObject funobj); +extern JS_PUBLIC_API JSObject* CloneFunctionObject(JSContext* cx, + HandleObject funobj); /** * As above, but providing an explicit scope chain. scopeChain must not include * the global object on it; that's implicit. It needs to contain the other * objects that should end up on the clone's scope chain. */ -extern JS_PUBLIC_API(JSObject*) -CloneFunctionObject(JSContext* cx, HandleObject funobj, AutoObjectVector& scopeChain); +extern JS_PUBLIC_API JSObject* CloneFunctionObject( + JSContext* cx, HandleObject funobj, AutoObjectVector& scopeChain); -} // namespace JS +} // namespace JS /** * Given a buffer, return false if the buffer might become a valid @@ -3658,37 +3410,37 @@ * lines in a buffer until JS_BufferIsCompilableUnit is true, then pass it to * the compiler. */ -extern JS_PUBLIC_API(bool) -JS_BufferIsCompilableUnit(JSContext* cx, JS::Handle obj, const char* utf8, - size_t length); +extern JS_PUBLIC_API bool JS_BufferIsCompilableUnit(JSContext* cx, + JS::Handle obj, + const char* utf8, + size_t length); /** * |script| will always be set. On failure, it will be set to nullptr. */ -extern JS_PUBLIC_API(bool) -JS_CompileScript(JSContext* cx, const char* ascii, size_t length, - const JS::CompileOptions& options, - JS::MutableHandleScript script); +extern JS_PUBLIC_API bool JS_CompileScript(JSContext* cx, const char* ascii, + size_t length, + const JS::CompileOptions& options, + JS::MutableHandleScript script); /** * |script| will always be set. On failure, it will be set to nullptr. */ -extern JS_PUBLIC_API(bool) -JS_CompileUCScript(JSContext* cx, const char16_t* chars, size_t length, - const JS::CompileOptions& options, - JS::MutableHandleScript script); - -extern JS_PUBLIC_API(JSObject*) -JS_GetGlobalFromScript(JSScript* script); +extern JS_PUBLIC_API bool JS_CompileUCScript(JSContext* cx, + const char16_t* chars, + size_t length, + const JS::CompileOptions& options, + JS::MutableHandleScript script); -extern JS_PUBLIC_API(const char*) -JS_GetScriptFilename(JSScript* script); +extern JS_PUBLIC_API JSObject* JS_GetGlobalFromScript(JSScript* script); -extern JS_PUBLIC_API(unsigned) -JS_GetScriptBaseLineNumber(JSContext* cx, JSScript* script); +extern JS_PUBLIC_API const char* JS_GetScriptFilename(JSScript* script); -extern JS_PUBLIC_API(JSScript*) -JS_GetFunctionScript(JSContext* cx, JS::HandleFunction fun); +extern JS_PUBLIC_API unsigned JS_GetScriptBaseLineNumber(JSContext* cx, + JSScript* script); + +extern JS_PUBLIC_API JSScript* JS_GetFunctionScript(JSContext* cx, + JS::HandleFunction fun); namespace JS { @@ -3715,7 +3467,7 @@ * addrefs/copies/tracing/etc. * * Furthermore, in some cases compile options are propagated from one entity to - * another (e.g. from a scriipt to a function defined in that script). This + * another (e.g. from a script to a function defined in that script). This * involves copying over some, but not all, of the options. * * So, we have a class hierarchy that reflects these four use cases: @@ -3746,92 +3498,88 @@ * Use this in code that needs to propagate compile options from one compilation * unit to another. */ -class JS_FRIEND_API(TransitiveCompileOptions) -{ - protected: - // The Web Platform allows scripts to be loaded from arbitrary cross-origin - // sources. This allows an attack by which a malicious website loads a - // sensitive file (say, a bank statement) cross-origin (using the user's - // cookies), and sniffs the generated syntax errors (via a window.onerror - // handler) for juicy morsels of its contents. - // - // To counter this attack, HTML5 specifies that script errors should be - // sanitized ("muted") when the script is not same-origin with the global - // for which it is loaded. Callers should set this flag for cross-origin - // scripts, and it will be propagated appropriately to child scripts and - // passed back in JSErrorReports. - bool mutedErrors_; - const char* filename_; - const char* introducerFilename_; - const char16_t* sourceMapURL_; - - // This constructor leaves 'version' set to JSVERSION_UNKNOWN. The structure - // is unusable until that's set to something more specific; the derived - // classes' constructors take care of that, in ways appropriate to their - // purpose. - TransitiveCompileOptions() +class JS_FRIEND_API TransitiveCompileOptions { + protected: + // The Web Platform allows scripts to be loaded from arbitrary cross-origin + // sources. This allows an attack by which a malicious website loads a + // sensitive file (say, a bank statement) cross-origin (using the user's + // cookies), and sniffs the generated syntax errors (via a window.onerror + // handler) for juicy morsels of its contents. + // + // To counter this attack, HTML5 specifies that script errors should be + // sanitized ("muted") when the script is not same-origin with the global + // for which it is loaded. Callers should set this flag for cross-origin + // scripts, and it will be propagated appropriately to child scripts and + // passed back in JSErrorReports. + bool mutedErrors_; + const char* filename_; + const char* introducerFilename_; + const char16_t* sourceMapURL_; + + TransitiveCompileOptions() : mutedErrors_(false), filename_(nullptr), introducerFilename_(nullptr), sourceMapURL_(nullptr), - version(JSVERSION_UNKNOWN), - versionSet(false), utf8(false), selfHostingMode(false), canLazilyParse(true), strictOption(false), extraWarningsOption(false), + expressionClosuresOption(false), werrorOption(false), asmJSOption(AsmJSOption::Disabled), throwOnAsmJSValidationFailureOption(false), forceAsync(false), - installedFile(false), sourceIsLazy(false), + allowHTMLComments(true), + isProbablySystemOrAddonCode(false), + hideScriptFromDebugger(false), introductionType(nullptr), introductionLineno(0), introductionOffset(0), - hasIntroductionInfo(false) - { } + hasIntroductionInfo(false) {} - // Set all POD options (those not requiring reference counts, copies, - // rooting, or other hand-holding) to their values in |rhs|. - void copyPODTransitiveOptions(const TransitiveCompileOptions& rhs); - - public: - // Read-only accessors for non-POD options. The proper way to set these - // depends on the derived type. - bool mutedErrors() const { return mutedErrors_; } - const char* filename() const { return filename_; } - const char* introducerFilename() const { return introducerFilename_; } - const char16_t* sourceMapURL() const { return sourceMapURL_; } - virtual JSObject* element() const = 0; - virtual JSString* elementAttributeName() const = 0; - virtual JSScript* introductionScript() const = 0; - - // POD options. - JSVersion version; - bool versionSet; - bool utf8; - bool selfHostingMode; - bool canLazilyParse; - bool strictOption; - bool extraWarningsOption; - bool werrorOption; - AsmJSOption asmJSOption; - bool throwOnAsmJSValidationFailureOption; - bool forceAsync; - bool installedFile; // 'true' iff pre-compiling js file in packaged app - bool sourceIsLazy; - - // |introductionType| is a statically allocated C string: - // one of "eval", "Function", or "GeneratorFunction". - const char* introductionType; - unsigned introductionLineno; - uint32_t introductionOffset; - bool hasIntroductionInfo; + // Set all POD options (those not requiring reference counts, copies, + // rooting, or other hand-holding) to their values in |rhs|. + void copyPODTransitiveOptions(const TransitiveCompileOptions& rhs); + + public: + // Read-only accessors for non-POD options. The proper way to set these + // depends on the derived type. + bool mutedErrors() const { return mutedErrors_; } + const char* filename() const { return filename_; } + const char* introducerFilename() const { return introducerFilename_; } + const char16_t* sourceMapURL() const { return sourceMapURL_; } + virtual JSObject* element() const = 0; + virtual JSString* elementAttributeName() const = 0; + virtual JSScript* introductionScript() const = 0; + + // POD options. + bool utf8; + bool selfHostingMode; + bool canLazilyParse; + bool strictOption; + bool extraWarningsOption; + bool expressionClosuresOption; + bool werrorOption; + AsmJSOption asmJSOption; + bool throwOnAsmJSValidationFailureOption; + bool forceAsync; + bool sourceIsLazy; + bool allowHTMLComments; + bool isProbablySystemOrAddonCode; + bool hideScriptFromDebugger; + + // |introductionType| is a statically allocated C string: + // one of "eval", "Function", or "GeneratorFunction". + const char* introductionType; + unsigned introductionLineno; + uint32_t introductionOffset; + bool hasIntroductionInfo; - private: - void operator=(const TransitiveCompileOptions&) = delete; + private: + void operator=(const TransitiveCompileOptions&) = delete; }; /** @@ -3842,43 +3590,56 @@ * is protected anyway); instead, create instances only of the derived classes: * CompileOptions and OwningCompileOptions. */ -class JS_FRIEND_API(ReadOnlyCompileOptions) : public TransitiveCompileOptions -{ - friend class CompileOptions; +class JS_FRIEND_API ReadOnlyCompileOptions : public TransitiveCompileOptions { + friend class CompileOptions; - protected: - ReadOnlyCompileOptions() + protected: + ReadOnlyCompileOptions() : TransitiveCompileOptions(), lineno(1), column(0), + scriptSourceOffset(0), isRunOnce(false), - noScriptRval(false) - { } + nonSyntacticScope(false), + noScriptRval(false) {} - // Set all POD options (those not requiring reference counts, copies, - // rooting, or other hand-holding) to their values in |rhs|. - void copyPODOptions(const ReadOnlyCompileOptions& rhs); - - public: - // Read-only accessors for non-POD options. The proper way to set these - // depends on the derived type. - bool mutedErrors() const { return mutedErrors_; } - const char* filename() const { return filename_; } - const char* introducerFilename() const { return introducerFilename_; } - const char16_t* sourceMapURL() const { return sourceMapURL_; } - virtual JSObject* element() const = 0; - virtual JSString* elementAttributeName() const = 0; - virtual JSScript* introductionScript() const = 0; - - // POD options. - unsigned lineno; - unsigned column; - // isRunOnce only applies to non-function scripts. - bool isRunOnce; - bool noScriptRval; + // Set all POD options (those not requiring reference counts, copies, + // rooting, or other hand-holding) to their values in |rhs|. + void copyPODOptions(const ReadOnlyCompileOptions& rhs); + + public: + // Read-only accessors for non-POD options. The proper way to set these + // depends on the derived type. + bool mutedErrors() const { return mutedErrors_; } + const char* filename() const { return filename_; } + const char* introducerFilename() const { return introducerFilename_; } + const char16_t* sourceMapURL() const { return sourceMapURL_; } + virtual JSObject* element() const override = 0; + virtual JSString* elementAttributeName() const override = 0; + virtual JSScript* introductionScript() const override = 0; + + // POD options. + unsigned lineno; + unsigned column; + // The offset within the ScriptSource's full uncompressed text of the first + // character we're presenting for compilation with this CompileOptions. + // + // When we compile a LazyScript, we pass the compiler only the substring of + // the source the lazy function occupies. With chunked decompression, we + // may not even have the complete uncompressed source present in memory. But + // parse node positions are offsets within the ScriptSource's full text, + // and LazyScripts indicate their substring of the full source by its + // starting and ending offsets within the full text. This + // scriptSourceOffset field lets the frontend convert between these + // offsets and offsets within the substring presented for compilation. + unsigned scriptSourceOffset; + // isRunOnce only applies to non-function scripts. + bool isRunOnce; + bool nonSyntacticScope; + bool noScriptRval; - private: - void operator=(const ReadOnlyCompileOptions&) = delete; + private: + void operator=(const ReadOnlyCompileOptions&) = delete; }; /** @@ -3894,79 +3655,108 @@ * comes to refer to the object that owns this, then the whole cycle, and * anything else it entrains, will never be freed. */ -class JS_FRIEND_API(OwningCompileOptions) : public ReadOnlyCompileOptions -{ - PersistentRootedObject elementRoot; - PersistentRootedString elementAttributeNameRoot; - PersistentRootedScript introductionScriptRoot; - - public: - // A minimal constructor, for use with OwningCompileOptions::copy. This - // leaves |this.version| set to JSVERSION_UNKNOWN; the instance - // shouldn't be used until we've set that to something real (as |copy| - // will). - explicit OwningCompileOptions(JSContext* cx); - ~OwningCompileOptions(); - - JSObject* element() const override { return elementRoot; } - JSString* elementAttributeName() const override { return elementAttributeNameRoot; } - JSScript* introductionScript() const override { return introductionScriptRoot; } - - // Set this to a copy of |rhs|. Return false on OOM. - bool copy(JSContext* cx, const ReadOnlyCompileOptions& rhs); - - /* These setters make copies of their string arguments, and are fallible. */ - bool setFile(JSContext* cx, const char* f); - bool setFileAndLine(JSContext* cx, const char* f, unsigned l); - bool setSourceMapURL(JSContext* cx, const char16_t* s); - bool setIntroducerFilename(JSContext* cx, const char* s); - - /* These setters are infallible, and can be chained. */ - OwningCompileOptions& setLine(unsigned l) { lineno = l; return *this; } - OwningCompileOptions& setElement(JSObject* e) { - elementRoot = e; - return *this; - } - OwningCompileOptions& setElementAttributeName(JSString* p) { - elementAttributeNameRoot = p; - return *this; - } - OwningCompileOptions& setIntroductionScript(JSScript* s) { - introductionScriptRoot = s; - return *this; - } - OwningCompileOptions& setMutedErrors(bool mute) { - mutedErrors_ = mute; - return *this; - } - OwningCompileOptions& setVersion(JSVersion v) { - version = v; - versionSet = true; - return *this; - } - 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& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } - OwningCompileOptions& setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; } - OwningCompileOptions& setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; } - OwningCompileOptions& setSourceIsLazy(bool l) { sourceIsLazy = l; return *this; } - OwningCompileOptions& setIntroductionType(const char* t) { introductionType = t; return *this; } - bool setIntroductionInfo(JSContext* cx, const char* introducerFn, const char* intro, - unsigned line, JSScript* script, uint32_t offset) - { - if (!setIntroducerFilename(cx, introducerFn)) - return false; - introductionType = intro; - introductionLineno = line; - introductionScriptRoot = script; - introductionOffset = offset; - hasIntroductionInfo = true; - return true; - } +class JS_FRIEND_API OwningCompileOptions : public ReadOnlyCompileOptions { + PersistentRootedObject elementRoot; + PersistentRootedString elementAttributeNameRoot; + PersistentRootedScript introductionScriptRoot; + + public: + // A minimal constructor, for use with OwningCompileOptions::copy. + explicit OwningCompileOptions(JSContext* cx); + ~OwningCompileOptions(); + + JSObject* element() const override { return elementRoot; } + JSString* elementAttributeName() const override { + return elementAttributeNameRoot; + } + JSScript* introductionScript() const override { + return introductionScriptRoot; + } + + // Set this to a copy of |rhs|. Return false on OOM. + bool copy(JSContext* cx, const ReadOnlyCompileOptions& rhs); + + /* These setters make copies of their string arguments, and are fallible. */ + bool setFile(JSContext* cx, const char* f); + bool setFileAndLine(JSContext* cx, const char* f, unsigned l); + bool setSourceMapURL(JSContext* cx, const char16_t* s); + bool setIntroducerFilename(JSContext* cx, const char* s); + + /* These setters are infallible, and can be chained. */ + OwningCompileOptions& setLine(unsigned l) { + lineno = l; + return *this; + } + OwningCompileOptions& setElement(JSObject* e) { + elementRoot = e; + return *this; + } + OwningCompileOptions& setElementAttributeName(JSString* p) { + elementAttributeNameRoot = p; + return *this; + } + OwningCompileOptions& setIntroductionScript(JSScript* s) { + introductionScriptRoot = s; + return *this; + } + OwningCompileOptions& setMutedErrors(bool mute) { + mutedErrors_ = mute; + return *this; + } + OwningCompileOptions& setUTF8(bool u) { + utf8 = u; + return *this; + } + OwningCompileOptions& setColumn(unsigned c) { + column = c; + return *this; + } + OwningCompileOptions& setScriptSourceOffset(unsigned o) { + scriptSourceOffset = o; + return *this; + } + OwningCompileOptions& setIsRunOnce(bool once) { + isRunOnce = once; + return *this; + } + OwningCompileOptions& setNoScriptRval(bool nsr) { + noScriptRval = nsr; + return *this; + } + OwningCompileOptions& setSelfHostingMode(bool shm) { + selfHostingMode = shm; + return *this; + } + OwningCompileOptions& setCanLazilyParse(bool clp) { + canLazilyParse = clp; + return *this; + } + OwningCompileOptions& setSourceIsLazy(bool l) { + sourceIsLazy = l; + return *this; + } + OwningCompileOptions& setNonSyntacticScope(bool n) { + nonSyntacticScope = n; + return *this; + } + OwningCompileOptions& setIntroductionType(const char* t) { + introductionType = t; + return *this; + } + bool setIntroductionInfo(JSContext* cx, const char* introducerFn, + const char* intro, unsigned line, JSScript* script, + uint32_t offset) { + if (!setIntroducerFilename(cx, introducerFn)) return false; + introductionType = intro; + introductionLineno = line; + introductionScriptRoot = script; + introductionOffset = offset; + hasIntroductionInfo = true; + return true; + } - private: - void operator=(const CompileOptions& rhs) = delete; + private: + void operator=(const CompileOptions& rhs) = delete; }; /** @@ -3976,152 +3766,206 @@ * 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) final : public ReadOnlyCompileOptions -{ - RootedObject elementRoot; - RootedString elementAttributeNameRoot; - RootedScript introductionScriptRoot; - - public: - explicit CompileOptions(JSContext* cx, JSVersion version = JSVERSION_UNKNOWN); - CompileOptions(js::ContextFriendFields* cx, const ReadOnlyCompileOptions& rhs) - : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx), - introductionScriptRoot(cx) - { - copyPODOptions(rhs); - - filename_ = rhs.filename(); - introducerFilename_ = rhs.introducerFilename(); - sourceMapURL_ = rhs.sourceMapURL(); - elementRoot = rhs.element(); - elementAttributeNameRoot = rhs.elementAttributeName(); - introductionScriptRoot = rhs.introductionScript(); - } - - CompileOptions(js::ContextFriendFields* cx, const TransitiveCompileOptions& rhs) - : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx), - introductionScriptRoot(cx) - { - copyPODTransitiveOptions(rhs); - - filename_ = rhs.filename(); - introducerFilename_ = rhs.introducerFilename(); - sourceMapURL_ = rhs.sourceMapURL(); - elementRoot = rhs.element(); - elementAttributeNameRoot = rhs.elementAttributeName(); - introductionScriptRoot = rhs.introductionScript(); - } +class MOZ_STACK_CLASS JS_FRIEND_API CompileOptions final + : public ReadOnlyCompileOptions { + RootedObject elementRoot; + RootedString elementAttributeNameRoot; + RootedScript introductionScriptRoot; + + public: + explicit CompileOptions(JSContext* cx); + CompileOptions(JSContext* cx, const ReadOnlyCompileOptions& rhs) + : ReadOnlyCompileOptions(), + elementRoot(cx), + elementAttributeNameRoot(cx), + introductionScriptRoot(cx) { + copyPODOptions(rhs); + + filename_ = rhs.filename(); + introducerFilename_ = rhs.introducerFilename(); + sourceMapURL_ = rhs.sourceMapURL(); + elementRoot = rhs.element(); + elementAttributeNameRoot = rhs.elementAttributeName(); + introductionScriptRoot = rhs.introductionScript(); + } + + CompileOptions(JSContext* cx, const TransitiveCompileOptions& rhs) + : ReadOnlyCompileOptions(), + elementRoot(cx), + elementAttributeNameRoot(cx), + introductionScriptRoot(cx) { + copyPODTransitiveOptions(rhs); + + filename_ = rhs.filename(); + introducerFilename_ = rhs.introducerFilename(); + sourceMapURL_ = rhs.sourceMapURL(); + elementRoot = rhs.element(); + elementAttributeNameRoot = rhs.elementAttributeName(); + introductionScriptRoot = rhs.introductionScript(); + } + + JSObject* element() const override { return elementRoot; } + JSString* elementAttributeName() const override { + return elementAttributeNameRoot; + } + JSScript* introductionScript() const override { + return introductionScriptRoot; + } + + CompileOptions& setFile(const char* f) { + filename_ = f; + return *this; + } + CompileOptions& setLine(unsigned l) { + lineno = l; + return *this; + } + CompileOptions& setFileAndLine(const char* f, unsigned l) { + filename_ = f; + lineno = l; + return *this; + } + CompileOptions& setSourceMapURL(const char16_t* s) { + sourceMapURL_ = s; + return *this; + } + CompileOptions& setElement(JSObject* e) { + elementRoot = e; + return *this; + } + CompileOptions& setElementAttributeName(JSString* p) { + elementAttributeNameRoot = p; + return *this; + } + CompileOptions& setIntroductionScript(JSScript* s) { + introductionScriptRoot = s; + return *this; + } + CompileOptions& setMutedErrors(bool mute) { + mutedErrors_ = mute; + return *this; + } + CompileOptions& setUTF8(bool u) { + utf8 = u; + return *this; + } + CompileOptions& setColumn(unsigned c) { + column = c; + return *this; + } + CompileOptions& setScriptSourceOffset(unsigned o) { + scriptSourceOffset = o; + return *this; + } + CompileOptions& setIsRunOnce(bool once) { + isRunOnce = once; + return *this; + } + CompileOptions& setNoScriptRval(bool nsr) { + noScriptRval = nsr; + return *this; + } + CompileOptions& setSelfHostingMode(bool shm) { + selfHostingMode = shm; + return *this; + } + CompileOptions& setCanLazilyParse(bool clp) { + canLazilyParse = clp; + return *this; + } + CompileOptions& setSourceIsLazy(bool l) { + sourceIsLazy = l; + return *this; + } + CompileOptions& setNonSyntacticScope(bool n) { + nonSyntacticScope = n; + return *this; + } + CompileOptions& setIntroductionType(const char* t) { + introductionType = t; + return *this; + } + CompileOptions& setIntroductionInfo(const char* introducerFn, + const char* intro, unsigned line, + JSScript* script, uint32_t offset) { + introducerFilename_ = introducerFn; + introductionType = intro; + introductionLineno = line; + introductionScriptRoot = script; + introductionOffset = offset; + hasIntroductionInfo = true; + return *this; + } + CompileOptions& maybeMakeStrictMode(bool strict) { + strictOption = strictOption || strict; + return *this; + } - JSObject* element() const override { return elementRoot; } - JSString* elementAttributeName() const override { return elementAttributeNameRoot; } - JSScript* introductionScript() const override { return introductionScriptRoot; } - - CompileOptions& setFile(const char* f) { filename_ = f; return *this; } - CompileOptions& setLine(unsigned l) { lineno = l; return *this; } - CompileOptions& setFileAndLine(const char* f, unsigned l) { - filename_ = f; lineno = l; return *this; - } - CompileOptions& setSourceMapURL(const char16_t* s) { sourceMapURL_ = s; return *this; } - CompileOptions& setElement(JSObject* e) { elementRoot = e; return *this; } - CompileOptions& setElementAttributeName(JSString* p) { - elementAttributeNameRoot = p; - return *this; - } - CompileOptions& setIntroductionScript(JSScript* s) { - introductionScriptRoot = s; - return *this; - } - CompileOptions& setMutedErrors(bool mute) { - mutedErrors_ = mute; - return *this; - } - CompileOptions& setVersion(JSVersion v) { - version = v; - versionSet = true; - return *this; - } - 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& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } - CompileOptions& setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; } - CompileOptions& setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; } - CompileOptions& setSourceIsLazy(bool l) { sourceIsLazy = l; return *this; } - CompileOptions& setIntroductionType(const char* t) { introductionType = t; return *this; } - CompileOptions& setIntroductionInfo(const char* introducerFn, const char* intro, - unsigned line, JSScript* script, uint32_t offset) - { - introducerFilename_ = introducerFn; - introductionType = intro; - introductionLineno = line; - introductionScriptRoot = script; - introductionOffset = offset; - hasIntroductionInfo = true; - return *this; - } - CompileOptions& maybeMakeStrictMode(bool strict) { - strictOption = strictOption || strict; - return *this; - } - - private: - void operator=(const CompileOptions& rhs) = delete; + private: + void operator=(const CompileOptions& rhs) = delete; }; /** * |script| will always be set. On failure, it will be set to nullptr. */ -extern JS_PUBLIC_API(bool) -Compile(JSContext* cx, const ReadOnlyCompileOptions& options, - SourceBufferHolder& srcBuf, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -Compile(JSContext* cx, const ReadOnlyCompileOptions& options, - const char* bytes, size_t length, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -Compile(JSContext* cx, const ReadOnlyCompileOptions& options, - const char16_t* chars, size_t length, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -Compile(JSContext* cx, const ReadOnlyCompileOptions& options, - FILE* file, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -Compile(JSContext* cx, const ReadOnlyCompileOptions& options, - const char* filename, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, - SourceBufferHolder& srcBuf, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, - const char* bytes, size_t length, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, - const char16_t* chars, size_t length, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, - FILE* file, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, - const char* filename, JS::MutableHandleScript script); +extern JS_PUBLIC_API bool Compile(JSContext* cx, + const ReadOnlyCompileOptions& options, + SourceBufferHolder& srcBuf, + JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool Compile(JSContext* cx, + const ReadOnlyCompileOptions& options, + const char* bytes, size_t length, + JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool Compile(JSContext* cx, + const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool Compile(JSContext* cx, + const ReadOnlyCompileOptions& options, + FILE* file, JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool Compile(JSContext* cx, + const ReadOnlyCompileOptions& options, + const char* filename, + JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool CompileForNonSyntacticScope( + JSContext* cx, const ReadOnlyCompileOptions& options, + SourceBufferHolder& srcBuf, JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool CompileForNonSyntacticScope( + JSContext* cx, const ReadOnlyCompileOptions& options, const char* bytes, + size_t length, JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool CompileForNonSyntacticScope( + JSContext* cx, const ReadOnlyCompileOptions& options, const char16_t* chars, + size_t length, JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool CompileForNonSyntacticScope( + JSContext* cx, const ReadOnlyCompileOptions& options, FILE* file, + JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool CompileForNonSyntacticScope( + JSContext* cx, const ReadOnlyCompileOptions& options, const char* filename, + JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool CanCompileOffThread( + JSContext* cx, const ReadOnlyCompileOptions& options, size_t length); -extern JS_PUBLIC_API(bool) -CanCompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, size_t length); +extern JS_PUBLIC_API bool CanDecodeOffThread( + JSContext* cx, const ReadOnlyCompileOptions& options, size_t length); /* * Off thread compilation control flow. * * After successfully triggering an off thread compile of a script, the * callback will eventually be invoked with the specified data and a token - * for the compilation. The callback will be invoked while off the main thread, + * for the compilation. The callback will be invoked while off thread, * so must ensure that its operations are thread safe. Afterwards, one of the - * following functions must be invoked on the main thread: + * following functions must be invoked on the runtime's active thread: * * - FinishOffThreadScript, to get the result script (or nullptr on failure). * - CancelOffThreadScript, to free the resources without creating a script. @@ -4131,27 +3975,50 @@ * to FinishOffThreadScript. */ -extern JS_PUBLIC_API(bool) -CompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, - const char16_t* chars, size_t length, - OffThreadCompileCallback callback, void* callbackData); - -extern JS_PUBLIC_API(JSScript*) -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 bool CompileOffThread( + JSContext* cx, const ReadOnlyCompileOptions& options, const char16_t* chars, + size_t length, OffThreadCompileCallback callback, void* callbackData); + +extern JS_PUBLIC_API JSScript* 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); + +extern JS_PUBLIC_API bool DecodeOffThreadScript( + JSContext* cx, const ReadOnlyCompileOptions& options, + mozilla::Vector& buffer /* TranscodeBuffer& */, size_t cursor, + OffThreadCompileCallback callback, void* callbackData); + +extern JS_PUBLIC_API bool DecodeOffThreadScript( + JSContext* cx, const ReadOnlyCompileOptions& options, + const mozilla::Range& range /* TranscodeRange& */, + OffThreadCompileCallback callback, void* callbackData); + +extern JS_PUBLIC_API JSScript* FinishOffThreadScriptDecoder(JSContext* cx, + void* token); + +extern JS_PUBLIC_API void CancelOffThreadScriptDecoder(JSContext* cx, + void* token); -extern JS_PUBLIC_API(JSObject*) -FinishOffThreadModule(JSContext* cx, void* token); +extern JS_PUBLIC_API bool DecodeMultiOffThreadScripts( + JSContext* cx, const ReadOnlyCompileOptions& options, + mozilla::Vector& sources, + OffThreadCompileCallback callback, void* callbackData); -extern JS_PUBLIC_API(void) -CancelOffThreadModule(JSContext* cx, void* token); +extern JS_PUBLIC_API bool FinishMultiOffThreadScriptsDecoder( + JSContext* cx, void* token, JS::MutableHandle scripts); + +extern JS_PUBLIC_API void CancelMultiOffThreadScriptsDecoder(JSContext* cx, + void* token); /** * Compile a function with envChain plus the global as its scope chain. @@ -4160,44 +4027,59 @@ * 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& envChain, - const ReadOnlyCompileOptions& options, - const char* name, unsigned nargs, const char* const* argnames, - const char16_t* chars, size_t length, JS::MutableHandleFunction fun); +extern JS_PUBLIC_API bool 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); /** * Same as above, but taking a SourceBufferHolder for the function body. */ -extern JS_PUBLIC_API(bool) -CompileFunction(JSContext* cx, AutoObjectVector& envChain, - const ReadOnlyCompileOptions& options, - const char* name, unsigned nargs, const char* const* argnames, - SourceBufferHolder& srcBuf, JS::MutableHandleFunction fun); +extern JS_PUBLIC_API bool CompileFunction(JSContext* cx, + AutoObjectVector& envChain, + const ReadOnlyCompileOptions& options, + const char* name, unsigned nargs, + const char* const* argnames, + SourceBufferHolder& srcBuf, + JS::MutableHandleFunction fun); /** * Same as above, but taking a const char * for the function body. */ -extern JS_PUBLIC_API(bool) -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); - -} /* namespace JS */ +extern JS_PUBLIC_API bool 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); -extern JS_PUBLIC_API(JSString*) -JS_DecompileScript(JSContext* cx, JS::Handle script, const char* name, unsigned indent); +/* + * Associate an element wrapper and attribute name with a previously compiled + * script, for debugging purposes. Calling this function is optional, but should + * be done before script execution if it is required. + */ +extern JS_PUBLIC_API bool InitScriptSourceElement( + JSContext* cx, HandleScript script, HandleObject element, + HandleString elementAttrName = nullptr); /* - * API extension: OR this into indent to avoid pretty-printing the decompiled - * source resulting from JS_DecompileFunction. + * For a script compiled with the hideScriptFromDebugger option, expose the + * script to the debugger by calling the debugger's onNewScript hook. */ -#define JS_DONT_PRETTY_PRINT ((unsigned)0x8000) +extern JS_PUBLIC_API void ExposeScriptToDebugger(JSContext* cx, + HandleScript script); -extern JS_PUBLIC_API(JSString*) -JS_DecompileFunction(JSContext* cx, JS::Handle fun, unsigned indent); +} /* namespace JS */ + +extern JS_PUBLIC_API JSString* JS_DecompileScript(JSContext* cx, + JS::Handle script); +extern JS_PUBLIC_API JSString* JS_DecompileFunction( + JSContext* cx, JS::Handle fun); /* * NB: JS_ExecuteScript and the JS::Evaluate APIs come in two flavors: either @@ -4219,33 +4101,46 @@ /** * Evaluate a script in the scope of the current global of cx. */ -extern JS_PUBLIC_API(bool) -JS_ExecuteScript(JSContext* cx, JS::HandleScript script, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx, + JS::HandleScript script, + JS::MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -JS_ExecuteScript(JSContext* cx, JS::HandleScript script); +extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx, + JS::HandleScript script); /** * As above, but providing an explicit scope chain. envChain must not include * the global object on it; that's implicit. It needs to contain the other * objects that should end up on the script's scope chain. */ -extern JS_PUBLIC_API(bool) -JS_ExecuteScript(JSContext* cx, JS::AutoObjectVector& envChain, - JS::HandleScript script, JS::MutableHandleValue rval); - -extern JS_PUBLIC_API(bool) -JS_ExecuteScript(JSContext* cx, JS::AutoObjectVector& envChain, JS::HandleScript script); +extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx, + JS::AutoObjectVector& envChain, + JS::HandleScript script, + JS::MutableHandleValue rval); + +extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx, + JS::AutoObjectVector& envChain, + JS::HandleScript script); namespace JS { /** * Like the above, but handles a cross-compartment script. If the script is - * cross-compartment, it is cloned into the current compartment before executing. + * cross-compartment, it is cloned into the current compartment before + * executing. + */ +extern JS_PUBLIC_API bool CloneAndExecuteScript(JSContext* cx, + JS::Handle script, + JS::MutableHandleValue rval); + +/** + * Like CloneAndExecuteScript above, but allows executing under a non-syntactic + * environment chain. */ -extern JS_PUBLIC_API(bool) -CloneAndExecuteScript(JSContext* cx, JS::Handle script, - JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool CloneAndExecuteScript(JSContext* cx, + JS::AutoObjectVector& envChain, + JS::Handle script, + JS::MutableHandleValue rval); } /* namespace JS */ @@ -4254,127 +4149,141 @@ /** * Evaluate the given source buffer in the scope of the current global of cx. */ -extern JS_PUBLIC_API(bool) -Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, - SourceBufferHolder& srcBuf, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool Evaluate(JSContext* cx, + const ReadOnlyCompileOptions& options, + SourceBufferHolder& srcBuf, + JS::MutableHandleValue rval); /** * As above, but providing an explicit scope chain. envChain must not include * the global object on it; that's implicit. It needs to contain the other * objects that should end up on the script's scope chain. */ -extern JS_PUBLIC_API(bool) -Evaluate(JSContext* cx, AutoObjectVector& envChain, const ReadOnlyCompileOptions& options, - SourceBufferHolder& srcBuf, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool Evaluate(JSContext* cx, AutoObjectVector& envChain, + const ReadOnlyCompileOptions& options, + SourceBufferHolder& srcBuf, + JS::MutableHandleValue rval); /** * Evaluate the given character buffer in the scope of the current global of cx. */ -extern JS_PUBLIC_API(bool) -Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, - const char16_t* chars, size_t length, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool Evaluate(JSContext* cx, + const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + JS::MutableHandleValue rval); /** * As above, but providing an explicit scope chain. envChain must not include * the global object on it; that's implicit. It needs to contain the other * objects that should end up on the script's scope chain. */ -extern JS_PUBLIC_API(bool) -Evaluate(JSContext* cx, AutoObjectVector& envChain, const ReadOnlyCompileOptions& options, - const char16_t* chars, size_t length, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool Evaluate(JSContext* cx, AutoObjectVector& envChain, + const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + JS::MutableHandleValue rval); /** * Evaluate the given byte buffer in the scope of the current global of cx. */ -extern JS_PUBLIC_API(bool) -Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, - const char* bytes, size_t length, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool Evaluate(JSContext* cx, + const ReadOnlyCompileOptions& options, + const char* bytes, size_t length, + JS::MutableHandleValue rval); /** * Evaluate the given file in the scope of the current global of cx. */ -extern JS_PUBLIC_API(bool) -Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, - const char* filename, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool 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); +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); +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); +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); +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); +extern JS_PUBLIC_API JS::Value GetModuleHostDefinedField(JSObject* module); /* - * Perform the ModuleDeclarationInstantiation operation on on the give source - * text module record. + * Perform the ModuleInstantiate operation on the given 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); +extern JS_PUBLIC_API bool ModuleInstantiate(JSContext* cx, + JS::HandleObject moduleRecord); /* - * Perform the ModuleEvaluation operation on on the give source text module - * record. + * Perform the ModuleEvaluate operation on the given 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. + * ModuleInstantiate must have completed prior to calling this. */ -extern JS_PUBLIC_API(bool) -ModuleEvaluation(JSContext* cx, JS::HandleObject moduleRecord); +extern JS_PUBLIC_API bool ModuleEvaluate(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. + * The result is a JavaScript array of object values. To extract the individual + * values use only JS_GetArrayLength and JS_GetElement with indices 0 to length + * - 1. + * + * The element values are objects with the following properties: + * - moduleSpecifier: the module specifier string + * - lineNumber: the line number of the import in the source text + * - columnNumber: the column number of the import in the source text + * + * These property values can be extracted with GetRequestedModuleSpecifier() and + * GetRequestedModuleSourcePos() */ -extern JS_PUBLIC_API(JSObject*) -GetRequestedModules(JSContext* cx, JS::HandleObject moduleRecord); +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); +extern JS_PUBLIC_API JSString* GetRequestedModuleSpecifier( + JSContext* cx, JS::HandleValue requestedModuleObject); + +extern JS_PUBLIC_API void GetRequestedModuleSourcePos( + JSContext* cx, JS::HandleValue requestedModuleObject, uint32_t* lineNumber, + uint32_t* columnNumber); + +extern JS_PUBLIC_API JSScript* GetModuleScript(JS::HandleObject moduleRecord); } /* namespace JS */ -extern JS_PUBLIC_API(bool) -JS_CheckForInterrupt(JSContext* cx); +extern JS_PUBLIC_API bool JS_CheckForInterrupt(JSContext* cx); /* * These functions allow setting an interrupt callback that will be called @@ -4389,17 +4298,16 @@ * 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(bool) -JS_AddInterruptCallback(JSContext* cx, 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(bool) -JS_DisableInterruptCallback(JSContext* cx); +extern JS_PUBLIC_API void JS_ResetInterruptCallback(JSContext* cx, bool enable); -extern JS_PUBLIC_API(void) -JS_ResetInterruptCallback(JSContext* cx, bool enable); +extern JS_PUBLIC_API void JS_RequestInterruptCallback(JSContext* cx); -extern JS_PUBLIC_API(void) -JS_RequestInterruptCallback(JSContext* cx); +extern JS_PUBLIC_API void JS_RequestInterruptCallbackCanWait(JSContext* cx); namespace JS { @@ -4410,8 +4318,8 @@ * 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 void SetGetIncumbentGlobalCallback( + JSContext* cx, JSGetIncumbentGlobalCallback callback); /** * Sets the callback that's invoked whenever a Promise job should be enqeued. @@ -4422,53 +4330,50 @@ * 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); +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) -SetPromiseRejectionTrackerCallback(JSContext* cx, JSPromiseRejectionTrackerCallback callback, - void* data = nullptr); +extern JS_PUBLIC_API void 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`. + * compartment, with the right slot layout. + * + * The `executor` can be a `nullptr`. In that case, the only way to resolve or + * reject the returned promise is via the `JS::ResolvePromise` and + * `JS::RejectPromise` JSAPI functions. + * + * 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); +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) -IsPromiseObject(JS::HandleObject obj); +extern JS_PUBLIC_API bool IsPromiseObject(JS::HandleObject obj); /** * Returns the current compartment's original Promise constructor. */ -extern JS_PUBLIC_API(JSObject*) -GetPromiseConstructor(JSContext* cx); +extern JS_PUBLIC_API JSObject* GetPromiseConstructor(JSContext* cx); /** * Returns the current compartment's original Promise.prototype. */ -extern JS_PUBLIC_API(JSObject*) -GetPromisePrototype(JSContext* cx); +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 -}; +enum class PromiseState { Pending, Fulfilled, Rejected }; /** * Returns the given Promise's state as a JS::PromiseState enum value. @@ -4476,53 +4381,50 @@ * 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); +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); +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); +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* GetPromiseAllocationSite( + JS::HandleObject promise); -extern JS_PUBLIC_API(JSObject*) -GetPromiseResolutionSite(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 DumpPromiseAllocationSite(JSContext* cx, + JS::HandleObject promise); -extern JS_PUBLIC_API(void) -DumpPromiseResolutionSite(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); +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); +extern JS_PUBLIC_API JSObject* CallOriginalPromiseReject( + JSContext* cx, JS::HandleValue rejectionValue); /** * Resolves the given Promise with the given `resolutionValue`. @@ -4530,8 +4432,9 @@ * 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); +extern JS_PUBLIC_API bool ResolvePromise(JSContext* cx, + JS::HandleObject promiseObj, + JS::HandleValue resolutionValue); /** * Rejects the given `promise` with the given `rejectionValue`. @@ -4539,8 +4442,9 @@ * 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); +extern JS_PUBLIC_API bool RejectPromise(JSContext* cx, + JS::HandleObject promiseObj, + JS::HandleValue rejectionValue); /** * Calls the current compartment's original Promise.prototype.then on the @@ -4550,9 +4454,9 @@ * `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); +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. @@ -4565,9 +4469,10 @@ * `Promise` or a subclass or `onResolve` and `onReject` aren't both callable * objects. */ -extern JS_PUBLIC_API(bool) -AddPromiseReactions(JSContext* cx, JS::HandleObject promise, - JS::HandleObject onResolve, JS::HandleObject onReject); +extern JS_PUBLIC_API bool AddPromiseReactions(JSContext* cx, + JS::HandleObject promise, + JS::HandleObject onResolve, + JS::HandleObject onReject); /** * Unforgeable version of the JS builtin Promise.all. @@ -4580,119 +4485,203 @@ * 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); +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. + * The Dispatchable interface allows the embedding to call SpiderMonkey + * on a JSContext thread when requested via DispatchToEventLoopCallback. */ -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) -SetAsyncTaskCallbacks(JSContext* cx, StartAsyncTaskCallback start, FinishAsyncTaskCallback finish); - -} // namespace JS - -extern JS_PUBLIC_API(bool) -JS_IsRunning(JSContext* cx); - -namespace JS { - -/** - * This class can be used to store a pointer to the youngest frame of a saved - * stack in the specified JSContext. This reference will be picked up by any new - * calls performed until the class is destroyed, with the specified asyncCause, - * that must not be empty. - * - * Any stack capture initiated during these new calls will go through the async - * stack instead of the current stack. - * - * Capturing the stack before a new call is performed will not be affected. - * - * The provided chain of SavedFrame objects can live in any compartment, - * although it will be copied to the compartment where the stack is captured. +class JS_PUBLIC_API Dispatchable { + protected: + // Dispatchables are created and destroyed by SpiderMonkey. + Dispatchable() = default; + virtual ~Dispatchable() = default; + + public: + // ShuttingDown indicates that SpiderMonkey should abort async tasks to + // expedite shutdown. + enum MaybeShuttingDown { NotShuttingDown, ShuttingDown }; + + // Called by the embedding after DispatchToEventLoopCallback succeeds. + virtual void run(JSContext* cx, MaybeShuttingDown maybeShuttingDown) = 0; +}; + +/** + * DispatchToEventLoopCallback may be called from any thread, being passed the + * same 'closure' passed to InitDispatchToEventLoop() and Dispatchable from the + * same JSRuntime. If the embedding returns 'true', the embedding must call + * Dispatchable::run() on an active JSContext thread for the same JSRuntime on + * which 'closure' was registered. If DispatchToEventLoopCallback returns + * 'false', SpiderMonkey will assume a shutdown of the JSRuntime is in progress. + * This contract implies that, by the time the final JSContext is destroyed in + * the JSRuntime, the embedding must have (1) run all Dispatchables for which + * DispatchToEventLoopCallback returned true, (2) already started returning + * false from calls to DispatchToEventLoopCallback. + */ + +typedef bool (*DispatchToEventLoopCallback)(void* closure, + Dispatchable* dispatchable); + +extern JS_PUBLIC_API void InitDispatchToEventLoop( + JSContext* cx, DispatchToEventLoopCallback callback, void* closure); + +/** + * The ConsumeStreamCallback is called from an active JSContext, passing a + * StreamConsumer that wishes to consume the given host object as a stream of + * bytes with the given MIME type. On failure, the embedding must report the + * appropriate error on 'cx'. On success, the embedding must call + * consumer->consumeChunk() repeatedly on any thread until exactly one of: + * - consumeChunk() returns false + * - the embedding calls consumer->streamClosed() + * before JS_DestroyContext(cx) or JS::ShutdownAsyncTasks(cx) is called. + * + * Note: consumeChunk() and streamClosed() may be called synchronously by + * ConsumeStreamCallback. + */ + +class JS_PUBLIC_API StreamConsumer { + protected: + // AsyncStreamConsumers are created and destroyed by SpiderMonkey. + StreamConsumer() = default; + virtual ~StreamConsumer() = default; + + public: + // Called by the embedding as each chunk of bytes becomes available. + // If this function returns 'false', the stream must drop all pointers to + // this StreamConsumer. + virtual bool consumeChunk(const uint8_t* begin, size_t length) = 0; + + // Called by the embedding when the stream is closed according to the + // contract described above. + enum CloseReason { EndOfFile, Error }; + virtual void streamClosed(CloseReason reason) = 0; + + // Provides optional stream attributes such as base or source mapping URLs. + // Necessarily called before consumeChunk() or streamClosed(). The caller + // retains ownership of the given strings. + virtual void noteResponseURLs(const char* maybeUrl, + const char* maybeSourceMapUrl) = 0; +}; + +enum class MimeType { Wasm }; + +typedef bool (*ConsumeStreamCallback)(JSContext* cx, JS::HandleObject obj, + MimeType mimeType, + StreamConsumer* consumer); + +extern JS_PUBLIC_API void InitConsumeStreamCallback( + JSContext* cx, ConsumeStreamCallback callback); + +/** + * When a JSRuntime is destroyed it implicitly cancels all async tasks in + * progress, releasing any roots held by the task. However, this is not soon + * enough for cycle collection, which needs to have roots dropped earlier so + * that the cycle collector can transitively remove roots for a future GC. For + * these and other cases, the set of pending async tasks can be canceled + * with this call earlier than JSRuntime destruction. + */ + +extern JS_PUBLIC_API void ShutdownAsyncTasks(JSContext* cx); + +/** + * Supply an alternative stack to incorporate into captured SavedFrame + * backtraces as the imputed caller of asynchronous JavaScript calls, like async + * function resumptions and DOM callbacks. + * + * When one async function awaits the result of another, it's natural to think + * of that as a sort of function call: just as execution resumes from an + * ordinary call expression when the callee returns, with the return value + * providing the value of the call expression, execution resumes from an 'await' + * expression after the awaited asynchronous function call returns, passing the + * return value along. + * + * Call the two async functions in such a situation the 'awaiter' and the + * 'awaitee'. + * + * As an async function, the awaitee contains 'await' expressions of its own. + * Whenever it executes after its first 'await', there are never any actual + * frames on the JavaScript stack under it; its awaiter is certainly not there. + * An await expression's continuation is invoked as a promise callback, and + * those are always called directly from the event loop in their own microtick. + * (Ignore unusual cases like nested event loops.) + * + * But because await expressions bear such a strong resemblance to calls (and + * deliberately so!), it would be unhelpful for stacks captured within the + * awaitee to be empty; instead, they should present the awaiter as the caller. + * + * The AutoSetAsyncStackForNewCalls RAII class supplies a SavedFrame stack to + * treat as the caller of any JavaScript invocations that occur within its + * lifetime. Any SavedFrame stack captured during such an invocation uses the + * SavedFrame passed to the constructor's 'stack' parameter as the 'asyncParent' + * property of the SavedFrame for the invocation's oldest frame. Its 'parent' + * property will be null, so stack-walking code can distinguish this + * awaiter/awaitee transition from an ordinary caller/callee transition. + * + * The constructor's 'asyncCause' parameter supplies a string explaining what + * sort of asynchronous call caused 'stack' to be spliced into the backtrace; + * for example, async function resumptions use the string "async". This appears + * as the 'asyncCause' property of the 'asyncParent' SavedFrame. + * + * Async callers are distinguished in the string form of a SavedFrame chain by + * including the 'asyncCause' string in the frame. It appears before the + * function name, with the two separated by a '*'. + * + * Note that, as each compartment has its own set of SavedFrames, the + * 'asyncParent' may actually point to a copy of 'stack', rather than the exact + * SavedFrame object passed. + * + * The youngest frame of 'stack' is not mutated to take the asyncCause string as + * its 'asyncCause' property; SavedFrame objects are immutable. Rather, a fresh + * clone of the frame is created with the needed 'asyncCause' property. + * + * The 'kind' argument specifies how aggressively 'stack' supplants any + * JavaScript frames older than this AutoSetAsyncStackForNewCalls object. If + * 'kind' is 'EXPLICIT', then all captured SavedFrame chains take on 'stack' as + * their 'asyncParent' where the chain crosses this object's scope. If 'kind' is + * 'IMPLICIT', then 'stack' is only included in captured chains if there are no + * other JavaScript frames on the stack --- that is, only if the stack would + * otherwise end at that point. + * + * AutoSetAsyncStackForNewCalls affects only SavedFrame chains; it does not + * affect Debugger.Frame or js::FrameIter. SavedFrame chains are used for + * Error.stack, allocation profiling, Promise debugging, and so on. * * See also `js/src/doc/SavedFrame/SavedFrame.md` for documentation on async * stack frames. */ -class MOZ_STACK_CLASS JS_PUBLIC_API(AutoSetAsyncStackForNewCalls) -{ - JSContext* cx; - RootedObject oldAsyncStack; - const char* oldAsyncCause; - bool oldAsyncCallIsExplicit; - - public: - enum class AsyncCallKind { - // The ordinary kind of call, where we may apply an async - // parent if there is no ordinary parent. - IMPLICIT, - // An explicit async parent, e.g., callFunctionWithAsyncStack, - // where we always want to override any ordinary parent. - EXPLICIT - }; - - // The stack parameter cannot be null by design, because it would be - // 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, - const char* asyncCause, - AsyncCallKind kind = AsyncCallKind::IMPLICIT); - ~AutoSetAsyncStackForNewCalls(); +class MOZ_STACK_CLASS JS_PUBLIC_API AutoSetAsyncStackForNewCalls { + JSContext* cx; + RootedObject oldAsyncStack; + const char* oldAsyncCause; + bool oldAsyncCallIsExplicit; + + public: + enum class AsyncCallKind { + // The ordinary kind of call, where we may apply an async + // parent if there is no ordinary parent. + IMPLICIT, + // An explicit async parent, e.g., callFunctionWithAsyncStack, + // where we always want to override any ordinary parent. + EXPLICIT + }; + + // The stack parameter cannot be null by design, because it would be + // 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, + const char* asyncCause, + AsyncCallKind kind = AsyncCallKind::IMPLICIT); + ~AutoSetAsyncStackForNewCalls(); }; -} // namespace JS +} // namespace JS /************************************************************************/ @@ -4705,65 +4694,72 @@ * for them. In contrast, all the JS_New*StringCopy* functions do not take * ownership of the character memory passed to them -- they copy it. */ -extern JS_PUBLIC_API(JSString*) -JS_NewStringCopyN(JSContext* cx, const char* s, size_t n); +extern JS_PUBLIC_API JSString* JS_NewStringCopyN(JSContext* cx, const char* s, + size_t n); -extern JS_PUBLIC_API(JSString*) -JS_NewStringCopyZ(JSContext* cx, const char* s); +extern JS_PUBLIC_API JSString* 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_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_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_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_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_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* JS_AtomizeAndPinStringN(JSContext* cx, + const char* s, + size_t length); -extern JS_PUBLIC_API(JSString*) -JS_AtomizeAndPinString(JSContext* cx, const char* s); +extern JS_PUBLIC_API JSString* JS_AtomizeAndPinString(JSContext* cx, + const char* s); -extern JS_PUBLIC_API(JSString*) -JS_NewUCString(JSContext* cx, char16_t* chars, size_t length); +extern JS_PUBLIC_API JSString* JS_NewLatin1String(JSContext* cx, + JS::Latin1Char* chars, + size_t length); -extern JS_PUBLIC_API(JSString*) -JS_NewUCStringCopyN(JSContext* cx, const char16_t* s, size_t n); +extern JS_PUBLIC_API JSString* JS_NewUCString(JSContext* cx, char16_t* chars, + size_t length); -extern JS_PUBLIC_API(JSString*) -JS_NewUCStringCopyZ(JSContext* cx, const char16_t* s); +extern JS_PUBLIC_API JSString* JS_NewUCStringCopyN(JSContext* cx, + const char16_t* s, size_t n); -extern JS_PUBLIC_API(JSString*) -JS_AtomizeUCStringN(JSContext* cx, const char16_t* s, size_t length); +extern JS_PUBLIC_API JSString* JS_NewUCStringCopyZ(JSContext* cx, + const char16_t* s); -extern JS_PUBLIC_API(JSString*) -JS_AtomizeUCString(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_AtomizeAndPinUCStringN(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_AtomizeAndPinUCString(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(bool) -JS_CompareStrings(JSContext* cx, JSString* str1, JSString* str2, int32_t* result); +extern JS_PUBLIC_API JSString* JS_AtomizeAndPinUCString(JSContext* cx, + const char16_t* s); -extern JS_PUBLIC_API(bool) -JS_StringEqualsAscii(JSContext* cx, JSString* str, const char* asciiBytes, bool* match); +extern JS_PUBLIC_API bool JS_CompareStrings(JSContext* cx, JSString* str1, + JSString* str2, int32_t* result); -extern JS_PUBLIC_API(size_t) -JS_PutEscapedString(JSContext* cx, char* buffer, size_t size, JSString* str, char quote); +extern JS_PUBLIC_API bool JS_StringEqualsAscii(JSContext* cx, JSString* str, + const char* asciiBytes, + bool* match); -extern JS_PUBLIC_API(bool) -JS_FileEscapedString(FILE* fp, JSString* str, char quote); +extern JS_PUBLIC_API size_t JS_PutEscapedString(JSContext* cx, char* buffer, + size_t size, JSString* str, + char quote); + +extern JS_PUBLIC_API bool JS_FileEscapedString(FILE* fp, JSString* str, + char quote); /* * Extracting string characters and length. @@ -4804,90 +4800,86 @@ * strings. */ -extern JS_PUBLIC_API(size_t) -JS_GetStringLength(JSString* str); +extern JS_PUBLIC_API size_t JS_GetStringLength(JSString* str); -extern JS_PUBLIC_API(bool) -JS_StringIsFlat(JSString* str); +extern JS_PUBLIC_API bool JS_StringIsFlat(JSString* str); /** Returns true iff the string's characters are stored as Latin1. */ -extern JS_PUBLIC_API(bool) -JS_StringHasLatin1Chars(JSString* str); +extern JS_PUBLIC_API bool JS_StringHasLatin1Chars(JSString* str); -extern JS_PUBLIC_API(const JS::Latin1Char*) -JS_GetLatin1StringCharsAndLength(JSContext* cx, const JS::AutoCheckCannotGC& nogc, JSString* str, - size_t* length); +extern JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1StringCharsAndLength( + JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str, + size_t* length); -extern JS_PUBLIC_API(const char16_t*) -JS_GetTwoByteStringCharsAndLength(JSContext* cx, const JS::AutoCheckCannotGC& nogc, JSString* str, - size_t* length); +extern JS_PUBLIC_API const char16_t* JS_GetTwoByteStringCharsAndLength( + JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str, + size_t* length); -extern JS_PUBLIC_API(bool) -JS_GetStringCharAt(JSContext* cx, JSString* str, size_t index, char16_t* res); +extern JS_PUBLIC_API bool JS_GetStringCharAt(JSContext* cx, JSString* str, + size_t index, char16_t* res); -extern JS_PUBLIC_API(char16_t) -JS_GetFlatStringCharAt(JSFlatString* str, size_t index); +extern JS_PUBLIC_API char16_t JS_GetFlatStringCharAt(JSFlatString* str, + size_t index); -extern JS_PUBLIC_API(const char16_t*) -JS_GetTwoByteExternalStringChars(JSString* str); +extern JS_PUBLIC_API const char16_t* JS_GetTwoByteExternalStringChars( + JSString* str); -extern JS_PUBLIC_API(bool) -JS_CopyStringChars(JSContext* cx, mozilla::Range dest, JSString* str); +extern JS_PUBLIC_API bool JS_CopyStringChars(JSContext* cx, + mozilla::Range dest, + JSString* str); -extern JS_PUBLIC_API(JSFlatString*) -JS_FlattenString(JSContext* cx, JSString* str); +extern JS_PUBLIC_API JSFlatString* JS_FlattenString(JSContext* cx, + JSString* str); -extern JS_PUBLIC_API(const JS::Latin1Char*) -JS_GetLatin1FlatStringChars(const JS::AutoCheckCannotGC& nogc, JSFlatString* str); +extern JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1FlatStringChars( + const JS::AutoRequireNoGC& nogc, JSFlatString* str); -extern JS_PUBLIC_API(const char16_t*) -JS_GetTwoByteFlatStringChars(const JS::AutoCheckCannotGC& nogc, JSFlatString* str); +extern JS_PUBLIC_API const char16_t* JS_GetTwoByteFlatStringChars( + const JS::AutoRequireNoGC& nogc, JSFlatString* str); -static MOZ_ALWAYS_INLINE JSFlatString* -JSID_TO_FLAT_STRING(jsid id) -{ - MOZ_ASSERT(JSID_IS_STRING(id)); - return (JSFlatString*)(JSID_BITS(id)); +static MOZ_ALWAYS_INLINE JSFlatString* JSID_TO_FLAT_STRING(jsid id) { + MOZ_ASSERT(JSID_IS_STRING(id)); + return (JSFlatString*)(JSID_BITS(id)); } -static MOZ_ALWAYS_INLINE JSFlatString* -JS_ASSERT_STRING_IS_FLAT(JSString* str) -{ - MOZ_ASSERT(JS_StringIsFlat(str)); - return (JSFlatString*)str; +static MOZ_ALWAYS_INLINE JSFlatString* JS_ASSERT_STRING_IS_FLAT(JSString* str) { + MOZ_ASSERT(JS_StringIsFlat(str)); + return (JSFlatString*)str; } -static MOZ_ALWAYS_INLINE JSString* -JS_FORGET_STRING_FLATNESS(JSFlatString* fstr) -{ - return (JSString*)fstr; +static MOZ_ALWAYS_INLINE JSString* JS_FORGET_STRING_FLATNESS( + JSFlatString* fstr) { + return (JSString*)fstr; } /* * Additional APIs that avoid fallibility when given a flat string. */ -extern JS_PUBLIC_API(bool) -JS_FlatStringEqualsAscii(JSFlatString* str, const char* asciiBytes); +extern JS_PUBLIC_API bool JS_FlatStringEqualsAscii(JSFlatString* str, + const char* asciiBytes); -extern JS_PUBLIC_API(size_t) -JS_PutEscapedFlatString(char* buffer, size_t size, JSFlatString* str, char quote); +extern JS_PUBLIC_API size_t JS_PutEscapedFlatString(char* buffer, size_t size, + JSFlatString* str, + char quote); /** * Create a dependent string, i.e., a string that owns no character storage, * but that refers to a slice of another string's chars. Dependent strings * are mutable by definition, so the thread safety comments above apply. */ -extern JS_PUBLIC_API(JSString*) -JS_NewDependentString(JSContext* cx, JS::HandleString str, size_t start, - size_t length); +extern JS_PUBLIC_API JSString* JS_NewDependentString(JSContext* cx, + JS::HandleString str, + size_t start, + size_t length); /** * Concatenate two strings, possibly resulting in a rope. * See above for thread safety comments. */ -extern JS_PUBLIC_API(JSString*) -JS_ConcatStrings(JSContext* cx, JS::HandleString left, JS::HandleString right); +extern JS_PUBLIC_API JSString* JS_ConcatStrings(JSContext* cx, + JS::HandleString left, + JS::HandleString right); /** * For JS_DecodeBytes, set *dstlenp to the size of the destination buffer before @@ -4899,33 +4891,29 @@ * the number of characters or bytes transferred so far. If cx is nullptr, no * error is reported on failure, and the functions simply return false. * - * NB: This function does not store an additional zero byte or char16_t after the - * transcoded string. + * NB: This function does not store an additional zero byte or char16_t after + * the transcoded string. */ -JS_PUBLIC_API(bool) -JS_DecodeBytes(JSContext* cx, const char* src, size_t srclen, char16_t* dst, - size_t* dstlenp); +JS_PUBLIC_API bool JS_DecodeBytes(JSContext* cx, const char* src, size_t srclen, + char16_t* dst, size_t* dstlenp); /** * A variation on JS_EncodeCharacters where a null terminated string is * returned that you are expected to call JS_free on when done. */ -JS_PUBLIC_API(char*) -JS_EncodeString(JSContext* cx, JSString* str); +JS_PUBLIC_API char* JS_EncodeString(JSContext* cx, JSString* str); /** * Same behavior as JS_EncodeString(), but encode into UTF-8 string */ -JS_PUBLIC_API(char*) -JS_EncodeStringToUTF8(JSContext* cx, JS::HandleString str); +JS_PUBLIC_API char* JS_EncodeStringToUTF8(JSContext* cx, JS::HandleString str); /** * Get number of bytes in the string encoding (without accounting for a * terminating zero bytes. The function returns (size_t) -1 if the string * can not be encoded into bytes and reports an error using cx accordingly. */ -JS_PUBLIC_API(size_t) -JS_GetStringEncodingLength(JSContext* cx, JSString* str); +JS_PUBLIC_API size_t JS_GetStringEncodingLength(JSContext* cx, JSString* str); /** * Encode string into a buffer. The function does not stores an additional @@ -4935,92 +4923,76 @@ * length parameter, the string will be cut and only length bytes will be * written into the buffer. */ -JS_PUBLIC_API(size_t) -JS_EncodeStringToBuffer(JSContext* cx, JSString* str, char* buffer, size_t length); - -class MOZ_RAII JSAutoByteString -{ - public: - JSAutoByteString(JSContext* cx, JSString* str - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mBytes(JS_EncodeString(cx, str)) - { - MOZ_ASSERT(cx); - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - explicit JSAutoByteString(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) - : mBytes(nullptr) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - ~JSAutoByteString() { - JS_free(nullptr, mBytes); - } - - /* Take ownership of the given byte array. */ - void initBytes(char* bytes) { - MOZ_ASSERT(!mBytes); - mBytes = bytes; - } - - char* encodeLatin1(JSContext* cx, JSString* str) { - MOZ_ASSERT(!mBytes); - MOZ_ASSERT(cx); - mBytes = JS_EncodeString(cx, str); - return mBytes; - } +JS_PUBLIC_API size_t JS_EncodeStringToBuffer(JSContext* cx, JSString* str, + char* buffer, size_t length); - char* encodeLatin1(js::ExclusiveContext* cx, JSString* str); - - char* encodeUtf8(JSContext* cx, JS::HandleString str) { - MOZ_ASSERT(!mBytes); - MOZ_ASSERT(cx); - mBytes = JS_EncodeStringToUTF8(cx, str); - return mBytes; - } - - void clear() { - js_free(mBytes); - mBytes = nullptr; - } - - char* ptr() const { - return mBytes; - } - - bool operator!() const { - return !mBytes; - } - - size_t length() const { - if (!mBytes) - return 0; - return strlen(mBytes); - } - - private: - char* mBytes; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER - - /* Copy and assignment are not supported. */ - JSAutoByteString(const JSAutoByteString& another); - JSAutoByteString& operator=(const JSAutoByteString& another); +class MOZ_RAII JSAutoByteString { + public: + JSAutoByteString(JSContext* cx, JSString* str MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mBytes(JS_EncodeString(cx, str)) { + MOZ_ASSERT(cx); + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + + explicit JSAutoByteString(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) + : mBytes(nullptr) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + + ~JSAutoByteString() { JS_free(nullptr, mBytes); } + + /* Take ownership of the given byte array. */ + void initBytes(JS::UniqueChars&& bytes) { + MOZ_ASSERT(!mBytes); + mBytes = bytes.release(); + } + + char* encodeLatin1(JSContext* cx, JSString* str) { + MOZ_ASSERT(!mBytes); + MOZ_ASSERT(cx); + mBytes = JS_EncodeString(cx, str); + return mBytes; + } + + char* encodeUtf8(JSContext* cx, JS::HandleString str) { + MOZ_ASSERT(!mBytes); + MOZ_ASSERT(cx); + mBytes = JS_EncodeStringToUTF8(cx, str); + return mBytes; + } + + void clear() { + js_free(mBytes); + mBytes = nullptr; + } + + char* ptr() const { return mBytes; } + + bool operator!() const { return !mBytes; } + + size_t length() const { + if (!mBytes) return 0; + return strlen(mBytes); + } + + private: + char* mBytes; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + + /* Copy and assignment are not supported. */ + JSAutoByteString(const JSAutoByteString& another); + JSAutoByteString& operator=(const JSAutoByteString& another); }; namespace JS { -extern JS_PUBLIC_API(JSAddonId*) -NewAddonId(JSContext* cx, JS::HandleString str); +extern JS_PUBLIC_API JSAddonId* NewAddonId(JSContext* cx, JS::HandleString str); -extern JS_PUBLIC_API(JSString*) -StringOfAddonId(JSAddonId* id); +extern JS_PUBLIC_API JSString* StringOfAddonId(JSAddonId* id); -extern JS_PUBLIC_API(JSAddonId*) -AddonIdOfObject(JSObject* obj); +extern JS_PUBLIC_API JSAddonId* AddonIdOfObject(JSObject* obj); -} // namespace JS +} // namespace JS /************************************************************************/ /* @@ -5036,18 +5008,16 @@ * If description is null, the new Symbol's [[Description]] attribute is * undefined. */ -JS_PUBLIC_API(Symbol*) -NewSymbol(JSContext* cx, HandleString description); +JS_PUBLIC_API Symbol* NewSymbol(JSContext* cx, HandleString description); /** * Symbol.for as specified in ES6. * - * Get a Symbol with the description 'key' from the Runtime-wide symbol registry. - * If there is not already a Symbol with that description in the registry, a new - * Symbol is created and registered. 'key' must not be null. + * Get a Symbol with the description 'key' from the Runtime-wide symbol + * registry. If there is not already a Symbol with that description in the + * registry, a new Symbol is created and registered. 'key' must not be null. */ -JS_PUBLIC_API(Symbol*) -GetSymbolFor(JSContext* cx, HandleString key); +JS_PUBLIC_API Symbol* GetSymbolFor(JSContext* cx, HandleString key); /** * Get the [[Description]] attribute of the given symbol. @@ -5055,31 +5025,33 @@ * This function is infallible. If it returns null, that means the symbol's * [[Description]] is undefined. */ -JS_PUBLIC_API(JSString*) -GetSymbolDescription(HandleSymbol symbol); +JS_PUBLIC_API JSString* 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) +#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) \ + MACRO(asyncIterator) enum class SymbolCode : uint32_t { - // There is one SymbolCode for each well-known symbol. +// 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. + 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() + 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. */ @@ -5090,8 +5062,7 @@ * * A symbol's SymbolCode never changes once it is created. */ -JS_PUBLIC_API(SymbolCode) -GetSymbolCode(Handle symbol); +JS_PUBLIC_API SymbolCode GetSymbolCode(Handle symbol); /** * Get one of the well-known symbols defined by ES6. A single set of well-known @@ -5099,22 +5070,18 @@ * * `which` must be in the range [0, WellKnownSymbolLimit). */ -JS_PUBLIC_API(Symbol*) -GetWellKnownSymbol(JSContext* cx, SymbolCode which); +JS_PUBLIC_API Symbol* GetWellKnownSymbol(JSContext* cx, SymbolCode which); /** * Return true if the given JSPropertySpec::name or JSFunctionSpec::name value * is actually a symbol code and not a string. See JS_SYM_FN. */ -inline bool -PropertySpecNameIsSymbol(const char* name) -{ - uintptr_t u = reinterpret_cast(name); - return u != 0 && u - 1 < WellKnownSymbolLimit; +inline bool PropertySpecNameIsSymbol(const char* name) { + uintptr_t u = reinterpret_cast(name); + return u != 0 && u - 1 < WellKnownSymbolLimit; } -JS_PUBLIC_API(bool) -PropertySpecNameEqualsId(const char* name, HandleId id); +JS_PUBLIC_API bool PropertySpecNameEqualsId(const char* name, HandleId id); /** * Create a jsid that does not need to be marked for GC. @@ -5124,8 +5091,8 @@ * symbol; either way it is immune to GC so there is no need to visit *idp * during GC marking. */ -JS_PUBLIC_API(bool) -PropertySpecNameToPermanentId(JSContext* cx, const char* name, jsid* idp); +JS_PUBLIC_API bool PropertySpecNameToPermanentId(JSContext* cx, + const char* name, jsid* idp); } /* namespace JS */ @@ -5133,14 +5100,16 @@ /* * JSON functions */ -typedef bool (* JSONWriteCallback)(const char16_t* buf, uint32_t len, void* data); +typedef bool (*JSONWriteCallback)(const char16_t* buf, uint32_t len, + void* data); /** * JSON.stringify as specified by ES5. */ -JS_PUBLIC_API(bool) -JS_Stringify(JSContext* cx, JS::MutableHandleValue value, JS::HandleObject replacer, - JS::HandleValue space, JSONWriteCallback callback, void* data); +JS_PUBLIC_API bool JS_Stringify(JSContext* cx, JS::MutableHandleValue value, + JS::HandleObject replacer, + JS::HandleValue space, + JSONWriteCallback callback, void* data); namespace JS { @@ -5161,28 +5130,28 @@ * 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); +JS_PUBLIC_API bool ToJSONMaybeSafely(JSContext* cx, JS::HandleObject input, + JSONWriteCallback callback, void* data); } /* namespace JS */ /** * JSON.parse as specified by ES5. */ -JS_PUBLIC_API(bool) -JS_ParseJSON(JSContext* cx, const char16_t* chars, uint32_t len, JS::MutableHandleValue vp); +JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, const char16_t* chars, + uint32_t len, JS::MutableHandleValue vp); -JS_PUBLIC_API(bool) -JS_ParseJSON(JSContext* cx, JS::HandleString str, JS::MutableHandleValue vp); +JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, JS::HandleString str, + JS::MutableHandleValue vp); -JS_PUBLIC_API(bool) -JS_ParseJSONWithReviver(JSContext* cx, const char16_t* chars, uint32_t len, JS::HandleValue reviver, - JS::MutableHandleValue vp); - -JS_PUBLIC_API(bool) -JS_ParseJSONWithReviver(JSContext* cx, JS::HandleString str, JS::HandleValue reviver, - JS::MutableHandleValue vp); +JS_PUBLIC_API bool JS_ParseJSONWithReviver(JSContext* cx, const char16_t* chars, + uint32_t len, + JS::HandleValue reviver, + JS::MutableHandleValue vp); + +JS_PUBLIC_API bool JS_ParseJSONWithReviver(JSContext* cx, JS::HandleString str, + JS::HandleValue reviver, + JS::MutableHandleValue vp); /************************************************************************/ @@ -5193,49 +5162,70 @@ * specify their own locales. * The locale string remains owned by the caller. */ -extern JS_PUBLIC_API(bool) -JS_SetDefaultLocale(JSContext* cx, const char* locale); +extern JS_PUBLIC_API bool JS_SetDefaultLocale(JSRuntime* rt, + const char* locale); /** * Look up the default locale for the ECMAScript Internationalization API. + * NB: The locale information is retrieved from cx's runtime. */ -extern JS_PUBLIC_API(JS::UniqueChars) -JS_GetDefaultLocale(JSContext* cx); +extern JS_PUBLIC_API JS::UniqueChars JS_GetDefaultLocale(JSContext* cx); /** * Reset the default locale to OS defaults. */ -extern JS_PUBLIC_API(void) -JS_ResetDefaultLocale(JSContext* cx); +extern JS_PUBLIC_API void JS_ResetDefaultLocale(JSRuntime* rt); /** * Locale specific string conversion and error message callbacks. */ struct JSLocaleCallbacks { - JSLocaleToUpperCase localeToUpperCase; - JSLocaleToLowerCase localeToLowerCase; - JSLocaleCompare localeCompare; // not used #if EXPOSE_INTL_API - JSLocaleToUnicode localeToUnicode; + JSLocaleToUpperCase localeToUpperCase; // not used #if EXPOSE_INTL_API + JSLocaleToLowerCase localeToLowerCase; // not used #if EXPOSE_INTL_API + JSLocaleCompare localeCompare; // not used #if EXPOSE_INTL_API + JSLocaleToUnicode localeToUnicode; }; /** * Establish locale callbacks. The pointer must persist as long as the * JSContext. Passing nullptr restores the default behaviour. */ -extern JS_PUBLIC_API(void) -JS_SetLocaleCallbacks(JSContext* cx, const JSLocaleCallbacks* callbacks); +extern JS_PUBLIC_API void JS_SetLocaleCallbacks( + JSRuntime* rt, const JSLocaleCallbacks* callbacks); /** * Return the address of the current locale callbacks struct, which may * be nullptr. */ -extern JS_PUBLIC_API(const JSLocaleCallbacks*) -JS_GetLocaleCallbacks(JSContext* cx); +extern JS_PUBLIC_API const JSLocaleCallbacks* JS_GetLocaleCallbacks( + JSRuntime* rt); /************************************************************************/ /* * Error reporting. + * + * There are four encoding variants for the error reporting API: + * UTF-8 + * JSAPI's default encoding for error handling. Use this when the encoding + * of the error message, format string, and arguments is UTF-8. + * ASCII + * Equivalent to UTF-8, but also asserts that the error message, format + * string, and arguments are all ASCII. Because ASCII is a subset of UTF-8, + * any use of this encoding variant *could* be replaced with use of the + * UTF-8 variant. This variant exists solely to double-check the + * developer's assumption that all these strings truly are ASCII, given that + * UTF-8 and ASCII strings regrettably have the same C++ type. + * UC = UTF-16 + * Use this when arguments are UTF-16. The format string must be UTF-8. + * Latin1 (planned to be removed) + * In this variant, all strings are interpreted byte-for-byte as the + * corresponding Unicode codepoint. This encoding may *safely* be used on + * any null-terminated string, regardless of its encoding. (You shouldn't + * *actually* be uncertain, but in the real world, a string's encoding -- if + * promised at all -- may be more...aspirational...than reality.) This + * encoding variant will eventually be removed -- work to convert your uses + * to UTF-8 as you're able. */ namespace JS { @@ -5246,60 +5236,59 @@ * Report an exception represented by the sprintf-like conversion of format * and its arguments. */ -extern JS_PUBLIC_API(void) -JS_ReportErrorASCII(JSContext* cx, const char* format, ...) - MOZ_FORMAT_PRINTF(2, 3); +extern JS_PUBLIC_API void JS_ReportErrorASCII(JSContext* cx, const char* format, + ...) MOZ_FORMAT_PRINTF(2, 3); -extern JS_PUBLIC_API(void) -JS_ReportErrorLatin1(JSContext* cx, const char* format, ...) +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); +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_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, ...); +extern JS_PUBLIC_API void 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_ReportErrorNumberLatin1VA(JSContext* cx, JSErrorCallback errorCallback, - void* userRef, const unsigned errorNumber, va_list ap); +extern JS_PUBLIC_API void 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, ...); +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); +extern JS_PUBLIC_API void JS_ReportErrorNumberUTF8VA( + JSContext* cx, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, va_list ap); #endif /* * Use an errorNumber to retrieve the format string, args are char16_t* */ -extern JS_PUBLIC_API(void) -JS_ReportErrorNumberUC(JSContext* cx, JSErrorCallback errorCallback, - void* userRef, const unsigned errorNumber, ...); - -extern JS_PUBLIC_API(void) -JS_ReportErrorNumberUCArray(JSContext* cx, JSErrorCallback errorCallback, - void* userRef, const unsigned errorNumber, - const char16_t** args); +extern JS_PUBLIC_API void JS_ReportErrorNumberUC(JSContext* cx, + JSErrorCallback errorCallback, + void* userRef, + const unsigned errorNumber, + ...); + +extern JS_PUBLIC_API void JS_ReportErrorNumberUCArray( + JSContext* cx, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, const char16_t** args); /** * As above, but report a warning instead (JSREPORT_IS_WARNING(report.flags)). @@ -5307,136 +5296,213 @@ * warning was not converted into an error due to the JSOPTION_WERROR option * being set, false otherwise. */ -extern JS_PUBLIC_API(bool) -JS_ReportWarningASCII(JSContext* cx, const char* format, ...) +extern JS_PUBLIC_API bool JS_ReportWarningASCII(JSContext* cx, + const char* format, ...) MOZ_FORMAT_PRINTF(2, 3); -extern JS_PUBLIC_API(bool) -JS_ReportWarningLatin1(JSContext* cx, const char* format, ...) +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, ...) +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_ReportErrorFlagsAndNumberUTF8(JSContext* cx, unsigned flags, - JSErrorCallback errorCallback, void* userRef, - const unsigned errorNumber, ...); - -extern JS_PUBLIC_API(bool) -JS_ReportErrorFlagsAndNumberUC(JSContext* cx, unsigned flags, - JSErrorCallback errorCallback, void* userRef, - const unsigned errorNumber, ...); +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_ReportErrorFlagsAndNumberUTF8( + JSContext* cx, unsigned flags, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + +extern JS_PUBLIC_API bool JS_ReportErrorFlagsAndNumberUC( + JSContext* cx, unsigned flags, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); /** * Complain when out of memory. */ -extern JS_PUBLIC_API(void) -JS_ReportOutOfMemory(JSContext* cx); +extern JS_PUBLIC_API void JS_ReportOutOfMemory(JSContext* cx); /** * Complain when an allocation size overflows the maximum supported limit. */ -extern JS_PUBLIC_API(void) -JS_ReportAllocationOverflow(JSContext* cx); +extern JS_PUBLIC_API void JS_ReportAllocationOverflow(JSContext* cx); -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'. - size_t linebufLength_; - - // The 0-based offset of error token in linebuf_. - size_t tokenOffset_; - - public: - JSErrorReport() - : linebuf_(nullptr), linebufLength_(0), tokenOffset_(0), - filename(nullptr), lineno(0), column(0), - flags(0), errorNumber(0), - exnType(0), isMuted(false), - ownsLinebuf_(false), ownsMessage_(false) - {} - - ~JSErrorReport() { - freeLinebuf(); - freeMessage(); - } +/** + * Base class that implements parts shared by JSErrorReport and + * JSErrorNotes::Note. + */ +class JSErrorBase { + // The (default) error message. + // If ownsMessage_ is true, the it is freed in destructor. + JS::ConstUTF8CharsZ message_; - const char* filename; /* source file name, URL, etc., or null */ - unsigned lineno; /* source line number */ - unsigned column; /* zero-based column index in line */ - unsigned flags; /* error/warning, etc. */ - unsigned errorNumber; /* the error number, e.g. see js.msg */ - int16_t exnType; /* One of the JSExnType constants */ - bool isMuted : 1; /* See the comment in ReadOnlyCompileOptions. */ + public: + JSErrorBase() + : filename(nullptr), + lineno(0), + column(0), + errorNumber(0), + ownsMessage_(false) {} - private: - bool ownsLinebuf_ : 1; - bool ownsMessage_ : 1; + ~JSErrorBase() { freeMessage(); } - public: - const char16_t* linebuf() const { - return linebuf_; - } - size_t linebufLength() const { - return linebufLength_; - } - size_t tokenOffset() const { - return tokenOffset_; - } - void initOwnedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, size_t tokenOffsetArg) { - initBorrowedLinebuf(linebufArg, linebufLengthArg, tokenOffsetArg); - ownsLinebuf_ = true; - } - void initBorrowedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, size_t tokenOffsetArg); - void freeLinebuf(); + // Source file name, URL, etc., or null. + const char* filename; - const JS::ConstUTF8CharsZ message() const { - return message_; - } + // Source line number. + unsigned lineno; - void initOwnedMessage(const char* messageArg) { - initBorrowedMessage(messageArg); - ownsMessage_ = true; - } - void initBorrowedMessage(const char* messageArg) { - MOZ_ASSERT(!message_); - message_ = JS::ConstUTF8CharsZ(messageArg, strlen(messageArg)); - } + // Zero-based column index in line. + unsigned column; + + // the error number, e.g. see js.msg. + unsigned errorNumber; + + private: + bool ownsMessage_ : 1; + + public: + const JS::ConstUTF8CharsZ message() const { return message_; } + + void initOwnedMessage(const char* messageArg) { + initBorrowedMessage(messageArg); + ownsMessage_ = true; + } + void initBorrowedMessage(const char* messageArg) { + MOZ_ASSERT(!message_); + message_ = JS::ConstUTF8CharsZ(messageArg, strlen(messageArg)); + } - JSString* newMessageString(JSContext* cx); + JSString* newMessageString(JSContext* cx); - void freeMessage(); + private: + void freeMessage(); +}; + +/** + * Notes associated with JSErrorReport. + */ +class JSErrorNotes { + public: + class Note : public JSErrorBase {}; + + private: + // Stores pointers to each note. + js::Vector, 1, js::SystemAllocPolicy> notes_; + + public: + JSErrorNotes(); + ~JSErrorNotes(); + + // Add an note to the given position. + bool addNoteASCII(JSContext* cx, const char* filename, unsigned lineno, + unsigned column, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, ...); + bool addNoteLatin1(JSContext* cx, const char* filename, unsigned lineno, + unsigned column, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, ...); + bool addNoteUTF8(JSContext* cx, const char* filename, unsigned lineno, + unsigned column, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, ...); + + JS_PUBLIC_API size_t length(); + + // Create a deep copy of notes. + js::UniquePtr copy(JSContext* cx); + + class iterator + : public std::iterator> { + js::UniquePtr* note_; + + public: + explicit iterator(js::UniquePtr* note = nullptr) : note_(note) {} + + bool operator==(iterator other) const { return note_ == other.note_; } + bool operator!=(iterator other) const { return !(*this == other); } + iterator& operator++() { + note_++; + return *this; + } + reference operator*() { return *note_; } + }; + JS_PUBLIC_API iterator begin(); + JS_PUBLIC_API iterator end(); +}; + +/** + * Describes a single error or warning that occurs in the execution of script. + */ +class JSErrorReport : public JSErrorBase { + // Offending source line without final '\n'. + // If ownsLinebuf_ is true, the buffer is freed in destructor. + const char16_t* linebuf_; + + // Number of chars in linebuf_. Does not include trailing '\0'. + size_t linebufLength_; + + // The 0-based offset of error token in linebuf_. + size_t tokenOffset_; + + public: + JSErrorReport() + : linebuf_(nullptr), + linebufLength_(0), + tokenOffset_(0), + notes(nullptr), + flags(0), + exnType(0), + isMuted(false), + ownsLinebuf_(false) {} + + ~JSErrorReport() { freeLinebuf(); } + + // Associated notes, or nullptr if there's no note. + js::UniquePtr notes; + + // error/warning, etc. + unsigned flags; + + // One of the JSExnType constants. + int16_t exnType; + + // See the comment in TransitiveCompileOptions. + bool isMuted : 1; + + private: + bool ownsLinebuf_ : 1; + + public: + const char16_t* linebuf() const { return linebuf_; } + size_t linebufLength() const { return linebufLength_; } + size_t tokenOffset() const { return tokenOffset_; } + void initOwnedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, + size_t tokenOffsetArg) { + initBorrowedLinebuf(linebufArg, linebufLengthArg, tokenOffsetArg); + ownsLinebuf_ = true; + } + void initBorrowedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, + size_t tokenOffsetArg); + + private: + void freeLinebuf(); }; /* * JSErrorReport flag values. These may be freely composed. */ -#define JSREPORT_ERROR 0x0 /* pseudo-flag for default case */ -#define JSREPORT_WARNING 0x1 /* reported via JS_ReportWarning */ -#define JSREPORT_EXCEPTION 0x2 /* exception was thrown */ -#define JSREPORT_STRICT 0x4 /* error or warning due to strict option */ +#define JSREPORT_ERROR 0x0 /* pseudo-flag for default case */ +#define JSREPORT_WARNING 0x1 /* reported via JS_ReportWarning */ +#define JSREPORT_EXCEPTION 0x2 /* exception was thrown */ +#define JSREPORT_STRICT 0x4 /* error or warning due to strict option */ -#define JSREPORT_USER_1 0x8 /* user-defined flag */ +#define JSREPORT_USER_1 0x8 /* user-defined flag */ /* * If JSREPORT_EXCEPTION is set, then a JavaScript-catchable exception @@ -5445,24 +5511,23 @@ * JS_ExecuteScript returns failure, and signal or propagate the exception, as * appropriate. */ -#define JSREPORT_IS_WARNING(flags) (((flags) & JSREPORT_WARNING) != 0) -#define JSREPORT_IS_EXCEPTION(flags) (((flags) & JSREPORT_EXCEPTION) != 0) -#define JSREPORT_IS_STRICT(flags) (((flags) & JSREPORT_STRICT) != 0) +#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) namespace JS { using WarningReporter = void (*)(JSContext* cx, JSErrorReport* report); -extern JS_PUBLIC_API(WarningReporter) +extern JS_PUBLIC_API WarningReporter SetWarningReporter(JSContext* cx, WarningReporter reporter); -extern JS_PUBLIC_API(WarningReporter) -GetWarningReporter(JSContext* cx); +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, - JSErrorReport* report, HandleString message, MutableHandleValue rval); +extern JS_PUBLIC_API bool CreateError( + JSContext* cx, JSExnType type, HandleObject stack, HandleString fileName, + uint32_t lineNumber, uint32_t columnNumber, JSErrorReport* report, + HandleString message, MutableHandleValue rval); /************************************************************************/ @@ -5470,89 +5535,84 @@ * Weak Maps. */ -extern JS_PUBLIC_API(JSObject*) -NewWeakMapObject(JSContext* cx); +extern JS_PUBLIC_API JSObject* NewWeakMapObject(JSContext* cx); -extern JS_PUBLIC_API(bool) -IsWeakMapObject(JSObject* obj); +extern JS_PUBLIC_API bool IsWeakMapObject(JSObject* obj); -extern JS_PUBLIC_API(bool) -GetWeakMapEntry(JSContext* cx, JS::HandleObject mapObj, JS::HandleObject key, - JS::MutableHandleValue val); - -extern JS_PUBLIC_API(bool) -SetWeakMapEntry(JSContext* cx, JS::HandleObject mapObj, JS::HandleObject key, - JS::HandleValue val); +extern JS_PUBLIC_API bool GetWeakMapEntry(JSContext* cx, + JS::HandleObject mapObj, + JS::HandleObject key, + JS::MutableHandleValue val); + +extern JS_PUBLIC_API bool SetWeakMapEntry(JSContext* cx, + JS::HandleObject mapObj, + JS::HandleObject key, + JS::HandleValue val); /* * Map */ -extern JS_PUBLIC_API(JSObject*) -NewMapObject(JSContext* cx); +extern JS_PUBLIC_API JSObject* NewMapObject(JSContext* cx); -extern JS_PUBLIC_API(uint32_t) -MapSize(JSContext* cx, HandleObject obj); +extern JS_PUBLIC_API uint32_t MapSize(JSContext* cx, HandleObject obj); -extern JS_PUBLIC_API(bool) -MapGet(JSContext* cx, HandleObject obj, - HandleValue key, MutableHandleValue rval); +extern JS_PUBLIC_API bool MapGet(JSContext* cx, HandleObject obj, + HandleValue key, MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -MapHas(JSContext* cx, HandleObject obj, HandleValue key, bool* rval); +extern JS_PUBLIC_API bool MapHas(JSContext* cx, HandleObject obj, + HandleValue key, bool* rval); -extern JS_PUBLIC_API(bool) -MapSet(JSContext* cx, HandleObject obj, HandleValue key, HandleValue val); +extern JS_PUBLIC_API bool MapSet(JSContext* cx, HandleObject obj, + HandleValue key, HandleValue val); -extern JS_PUBLIC_API(bool) -MapDelete(JSContext *cx, HandleObject obj, HandleValue key, bool *rval); +extern JS_PUBLIC_API bool MapDelete(JSContext* cx, HandleObject obj, + HandleValue key, bool* rval); -extern JS_PUBLIC_API(bool) -MapClear(JSContext* cx, HandleObject obj); +extern JS_PUBLIC_API bool MapClear(JSContext* cx, HandleObject obj); -extern JS_PUBLIC_API(bool) -MapKeys(JSContext* cx, HandleObject obj, MutableHandleValue rval); +extern JS_PUBLIC_API bool MapKeys(JSContext* cx, HandleObject obj, + MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -MapValues(JSContext* cx, HandleObject obj, MutableHandleValue rval); +extern JS_PUBLIC_API bool MapValues(JSContext* cx, HandleObject obj, + MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -MapEntries(JSContext* cx, HandleObject obj, MutableHandleValue rval); +extern JS_PUBLIC_API bool MapEntries(JSContext* cx, HandleObject obj, + MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -MapForEach(JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisVal); +extern JS_PUBLIC_API bool MapForEach(JSContext* cx, HandleObject obj, + HandleValue callbackFn, + HandleValue thisVal); /* * Set */ -extern JS_PUBLIC_API(JSObject *) -NewSetObject(JSContext *cx); +extern JS_PUBLIC_API JSObject* NewSetObject(JSContext* cx); -extern JS_PUBLIC_API(uint32_t) -SetSize(JSContext *cx, HandleObject obj); +extern JS_PUBLIC_API uint32_t SetSize(JSContext* cx, HandleObject obj); -extern JS_PUBLIC_API(bool) -SetHas(JSContext *cx, HandleObject obj, HandleValue key, bool *rval); +extern JS_PUBLIC_API bool SetHas(JSContext* cx, HandleObject obj, + HandleValue key, bool* rval); -extern JS_PUBLIC_API(bool) -SetDelete(JSContext *cx, HandleObject obj, HandleValue key, bool *rval); +extern JS_PUBLIC_API bool SetDelete(JSContext* cx, HandleObject obj, + HandleValue key, bool* rval); -extern JS_PUBLIC_API(bool) -SetAdd(JSContext *cx, HandleObject obj, HandleValue key); +extern JS_PUBLIC_API bool SetAdd(JSContext* cx, HandleObject obj, + HandleValue key); -extern JS_PUBLIC_API(bool) -SetClear(JSContext *cx, HandleObject obj); +extern JS_PUBLIC_API bool SetClear(JSContext* cx, HandleObject obj); -extern JS_PUBLIC_API(bool) -SetKeys(JSContext *cx, HandleObject obj, MutableHandleValue rval); +extern JS_PUBLIC_API bool SetKeys(JSContext* cx, HandleObject obj, + MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -SetValues(JSContext *cx, HandleObject obj, MutableHandleValue rval); +extern JS_PUBLIC_API bool SetValues(JSContext* cx, HandleObject obj, + MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -SetEntries(JSContext *cx, HandleObject obj, MutableHandleValue rval); +extern JS_PUBLIC_API bool SetEntries(JSContext* cx, HandleObject obj, + MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -SetForEach(JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisVal); +extern JS_PUBLIC_API bool SetForEach(JSContext* cx, HandleObject obj, + HandleValue callbackFn, + HandleValue thisVal); } /* namespace JS */ @@ -5560,8 +5620,9 @@ * Dates. */ -extern JS_PUBLIC_API(JSObject*) -JS_NewDateObject(JSContext* cx, int year, int mon, int mday, int hour, int min, int sec); +extern JS_PUBLIC_API JSObject* JS_NewDateObject(JSContext* cx, int year, + int mon, int mday, int hour, + int min, int sec); /** * Returns true and sets |*isDate| indicating whether |obj| is a Date object or @@ -5570,42 +5631,47 @@ * This method returns true with |*isDate == false| when passed a proxy whose * target is a Date, or when passed a revoked proxy. */ -extern JS_PUBLIC_API(bool) -JS_ObjectIsDate(JSContext* cx, JS::HandleObject obj, bool* isDate); +extern JS_PUBLIC_API bool JS_ObjectIsDate(JSContext* cx, JS::HandleObject obj, + bool* isDate); /************************************************************************/ /* * Regular Expressions. */ -#define JSREG_FOLD 0x01u /* fold uppercase to lowercase */ -#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, const char* bytes, size_t length, unsigned flags); - -extern JS_PUBLIC_API(JSObject*) -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); - -extern JS_PUBLIC_API(bool) -JS_ClearRegExpStatics(JSContext* cx, JS::HandleObject obj); - -extern JS_PUBLIC_API(bool) -JS_ExecuteRegExp(JSContext* cx, JS::HandleObject obj, JS::HandleObject reobj, - char16_t* chars, size_t length, size_t* indexp, bool test, - JS::MutableHandleValue rval); +#define JSREG_FOLD 0x01u /* fold uppercase to lowercase */ +#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, + const char* bytes, + size_t length, + unsigned flags); + +extern JS_PUBLIC_API JSObject* 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); + +extern JS_PUBLIC_API bool JS_ClearRegExpStatics(JSContext* cx, + JS::HandleObject obj); + +extern JS_PUBLIC_API bool JS_ExecuteRegExp(JSContext* cx, JS::HandleObject obj, + JS::HandleObject reobj, + char16_t* chars, size_t length, + size_t* indexp, bool test, + JS::MutableHandleValue rval); /* RegExp interface for clients without a global object. */ -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); +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); /** * Returns true and sets |*isRegExp| indicating whether |obj| is a RegExp @@ -5614,28 +5680,26 @@ * This method returns true with |*isRegExp == false| when passed a proxy whose * target is a RegExp, or when passed a revoked proxy. */ -extern JS_PUBLIC_API(bool) -JS_ObjectIsRegExp(JSContext* cx, JS::HandleObject obj, bool* isRegExp); +extern JS_PUBLIC_API bool JS_ObjectIsRegExp(JSContext* cx, JS::HandleObject obj, + bool* isRegExp); -extern JS_PUBLIC_API(unsigned) -JS_GetRegExpFlags(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API unsigned JS_GetRegExpFlags(JSContext* cx, + JS::HandleObject obj); -extern JS_PUBLIC_API(JSString*) -JS_GetRegExpSource(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API JSString* JS_GetRegExpSource(JSContext* cx, + JS::HandleObject obj); /************************************************************************/ -extern JS_PUBLIC_API(bool) -JS_IsExceptionPending(JSContext* cx); +extern JS_PUBLIC_API bool JS_IsExceptionPending(JSContext* cx); -extern JS_PUBLIC_API(bool) -JS_GetPendingException(JSContext* cx, JS::MutableHandleValue vp); +extern JS_PUBLIC_API bool JS_GetPendingException(JSContext* cx, + JS::MutableHandleValue vp); -extern JS_PUBLIC_API(void) -JS_SetPendingException(JSContext* cx, JS::HandleValue v); +extern JS_PUBLIC_API void JS_SetPendingException(JSContext* cx, + JS::HandleValue v); -extern JS_PUBLIC_API(void) -JS_ClearPendingException(JSContext* cx); +extern JS_PUBLIC_API void JS_ClearPendingException(JSContext* cx); namespace JS { @@ -5651,58 +5715,56 @@ * ... cleanup that might re-enter JS ... * return ok; */ -class JS_PUBLIC_API(AutoSaveExceptionState) -{ - private: - JSContext* context; - bool wasPropagatingForcedReturn; - bool wasOverRecursed; - bool wasThrowing; - RootedValue exceptionValue; - - public: - /* - * Take a snapshot of cx's current exception state. Then clear any current - * pending exception in cx. - */ - explicit AutoSaveExceptionState(JSContext* cx); - - /* - * If neither drop() nor restore() was called, restore the exception - * state only if no exception is currently pending on cx. - */ - ~AutoSaveExceptionState(); - - /* - * Discard any stored exception state. - * If this is called, the destructor is a no-op. - */ - void drop() { - wasPropagatingForcedReturn = false; - wasOverRecursed = false; - wasThrowing = false; - exceptionValue.setUndefined(); - } - - /* - * Replace cx's exception state with the stored exception state. Then - * discard the stored exception state. If this is called, the - * destructor is a no-op. - */ - void restore(); +class JS_PUBLIC_API AutoSaveExceptionState { + private: + JSContext* context; + bool wasPropagatingForcedReturn; + bool wasOverRecursed; + bool wasThrowing; + RootedValue exceptionValue; + + public: + /* + * Take a snapshot of cx's current exception state. Then clear any current + * pending exception in cx. + */ + explicit AutoSaveExceptionState(JSContext* cx); + + /* + * If neither drop() nor restore() was called, restore the exception + * state only if no exception is currently pending on cx. + */ + ~AutoSaveExceptionState(); + + /* + * Discard any stored exception state. + * If this is called, the destructor is a no-op. + */ + void drop() { + wasPropagatingForcedReturn = false; + wasOverRecursed = false; + wasThrowing = false; + exceptionValue.setUndefined(); + } + + /* + * Replace cx's exception state with the stored exception state. Then + * discard the stored exception state. If this is called, the + * destructor is a no-op. + */ + void restore(); }; } /* namespace JS */ /* Deprecated API. Use AutoSaveExceptionState instead. */ -extern JS_PUBLIC_API(JSExceptionState*) -JS_SaveExceptionState(JSContext* cx); +extern JS_PUBLIC_API JSExceptionState* JS_SaveExceptionState(JSContext* cx); -extern JS_PUBLIC_API(void) -JS_RestoreExceptionState(JSContext* cx, JSExceptionState* state); +extern JS_PUBLIC_API void JS_RestoreExceptionState(JSContext* cx, + JSExceptionState* state); -extern JS_PUBLIC_API(void) -JS_DropExceptionState(JSContext* cx, JSExceptionState* state); +extern JS_PUBLIC_API void JS_DropExceptionState(JSContext* cx, + JSExceptionState* state); /** * If the given object is an exception object, the exception will have (or be @@ -5711,9 +5773,10 @@ * of the error report struct that might be returned is the same as the * lifetime of the exception object. */ -extern JS_PUBLIC_API(JSErrorReport*) -JS_ErrorFromException(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API JSErrorReport* JS_ErrorFromException(JSContext* cx, + JS::HandleObject obj); +namespace JS { /** * If the given object is an exception object (or an unwrappable * cross-compartment wrapper for one), return the stack for that exception, if @@ -5721,17 +5784,9 @@ * (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(JS::HandleObject obj); +extern JS_PUBLIC_API JSObject* ExceptionStackOrNull(JS::HandleObject obj); -/* - * Throws a StopIteration exception on cx. - */ -extern JS_PUBLIC_API(bool) -JS_ThrowStopIteration(JSContext* cx); - -extern JS_PUBLIC_API(bool) -JS_IsStopIteration(const JS::Value& v); +} /* namespace JS */ /** * A JS context always has an "owner thread". The owner thread is set when the @@ -5743,8 +5798,7 @@ * non-debug builds). */ -extern JS_PUBLIC_API(void) -JS_AbortIfWrongThread(JSContext* cx); +extern JS_PUBLIC_API void JS_AbortIfWrongThread(JSContext* cx); /************************************************************************/ @@ -5753,120 +5807,126 @@ * object of the given class, using the callee to determine parentage and * [[Prototype]]. */ -extern JS_PUBLIC_API(JSObject*) -JS_NewObjectForConstructor(JSContext* cx, const JSClass* clasp, const JS::CallArgs& args); +extern JS_PUBLIC_API JSObject* JS_NewObjectForConstructor( + JSContext* cx, const JSClass* clasp, const JS::CallArgs& args); /************************************************************************/ #ifdef JS_GC_ZEAL #define JS_DEFAULT_ZEAL_FREQ 100 -extern JS_PUBLIC_API(void) -JS_GetGCZealBits(JSContext* cx, uint32_t* zealBits, uint32_t* frequency, uint32_t* nextScheduled); +extern JS_PUBLIC_API void 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); +extern JS_PUBLIC_API void JS_SetGCZeal(JSContext* cx, uint8_t zeal, + uint32_t frequency); -extern JS_PUBLIC_API(void) -JS_ScheduleGC(JSContext* cx, uint32_t count); +extern JS_PUBLIC_API void JS_ScheduleGC(JSContext* cx, uint32_t count); #endif -extern JS_PUBLIC_API(void) -JS_SetParallelParsingEnabled(JSContext* cx, bool enabled); +extern JS_PUBLIC_API void JS_SetParallelParsingEnabled(JSContext* cx, + bool enabled); -extern JS_PUBLIC_API(void) -JS_SetOffthreadIonCompilationEnabled(JSContext* cx, bool enabled); +extern JS_PUBLIC_API void JS_SetOffthreadIonCompilationEnabled(JSContext* cx, + bool enabled); -#define JIT_COMPILER_OPTIONS(Register) \ - Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \ - Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \ - 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(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") +//clang-format off +#define JIT_COMPILER_OPTIONS(Register) \ + Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \ + Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \ + 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(FULL_DEBUG_CHECKS, "jit.full-debug-checks") \ + Register(JUMP_THRESHOLD, "jump-threshold") \ + Register(UNBOXED_OBJECTS, "unboxed_objects") \ + Register(SIMULATOR_ALWAYS_INTERRUPT, "simulator.always-interrupt") \ + Register(SPECTRE_INDEX_MASKING, "spectre.index-masking") \ + Register(SPECTRE_OBJECT_MITIGATIONS_BARRIERS, "spectre.object-mitigations.barriers") \ + Register(SPECTRE_OBJECT_MITIGATIONS_MISC, "spectre.object-mitigations.misc") \ + Register(SPECTRE_STRING_MITIGATIONS, "spectre.string-mitigations") \ + Register(SPECTRE_VALUE_MASKING, "spectre.value-masking") \ + Register(SPECTRE_JIT_TO_CXX_CALLS, "spectre.jit-to-C++-calls") \ + Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \ + Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets") \ + Register(WASM_DELAY_TIER2, "wasm.delay-tier2") +//clang-format on typedef enum JSJitCompilerOption { -#define JIT_COMPILER_DECLARE(key, str) \ - JSJITCOMPILER_ ## key, +#define JIT_COMPILER_DECLARE(key, str) JSJITCOMPILER_##key, - JIT_COMPILER_OPTIONS(JIT_COMPILER_DECLARE) + JIT_COMPILER_OPTIONS(JIT_COMPILER_DECLARE) #undef JIT_COMPILER_DECLARE - JSJITCOMPILER_NOT_AN_OPTION + JSJITCOMPILER_NOT_AN_OPTION } JSJitCompilerOption; -extern JS_PUBLIC_API(void) -JS_SetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t value); -extern JS_PUBLIC_API(bool) -JS_GetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t* valueOut); +extern JS_PUBLIC_API void 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. */ -extern JS_PUBLIC_API(bool) -JS_IndexToId(JSContext* cx, uint32_t index, JS::MutableHandleId); +extern JS_PUBLIC_API bool JS_IndexToId(JSContext* cx, uint32_t index, + JS::MutableHandleId); /** * Convert chars into a jsid. * * |chars| may not be an index. */ -extern JS_PUBLIC_API(bool) -JS_CharsToId(JSContext* cx, JS::TwoByteChars chars, JS::MutableHandleId); +extern JS_PUBLIC_API bool JS_CharsToId(JSContext* cx, JS::TwoByteChars chars, + JS::MutableHandleId); /** * Test if the given string is a valid ECMAScript identifier */ -extern JS_PUBLIC_API(bool) -JS_IsIdentifier(JSContext* cx, JS::HandleString str, bool* isIdentifier); +extern JS_PUBLIC_API bool JS_IsIdentifier(JSContext* cx, JS::HandleString str, + bool* isIdentifier); /** * Test whether the given chars + length are a valid ECMAScript identifier. * This version is infallible, so just returns whether the chars are an * identifier. */ -extern JS_PUBLIC_API(bool) -JS_IsIdentifier(const char16_t* chars, size_t length); +extern JS_PUBLIC_API bool JS_IsIdentifier(const char16_t* chars, size_t length); namespace js { class ScriptSource; -} // namespace js +} // namespace js namespace JS { -class MOZ_RAII JS_PUBLIC_API(AutoFilename) -{ - private: - js::ScriptSource* ss_; - mozilla::Variant filename_; +class MOZ_RAII JS_PUBLIC_API AutoFilename { + private: + js::ScriptSource* ss_; + mozilla::Variant filename_; - AutoFilename(const AutoFilename&) = delete; - AutoFilename& operator=(const AutoFilename&) = delete; + AutoFilename(const AutoFilename&) = delete; + AutoFilename& operator=(const AutoFilename&) = delete; - public: - AutoFilename() - : ss_(nullptr), - filename_(mozilla::AsVariant(nullptr)) - {} + public: + AutoFilename() + : ss_(nullptr), filename_(mozilla::AsVariant(nullptr)) {} - ~AutoFilename() { - reset(); - } + ~AutoFilename() { reset(); } - void reset(); + void reset(); - void setOwned(UniqueChars&& filename); - void setUnowned(const char* filename); - void setScriptSource(js::ScriptSource* ss); + void setOwned(UniqueChars&& filename); + void setUnowned(const char* filename); + void setScriptSource(js::ScriptSource* ss); - const char* get() const; + const char* get() const; }; /** @@ -5877,12 +5937,11 @@ * If a the embedding has hidden the scripted caller for the topmost activation * record, this will also return false. */ -extern JS_PUBLIC_API(bool) -DescribeScriptedCaller(JSContext* cx, AutoFilename* filename = nullptr, - unsigned* lineno = nullptr, unsigned* column = nullptr); +extern JS_PUBLIC_API bool DescribeScriptedCaller( + JSContext* cx, AutoFilename* filename = nullptr, unsigned* lineno = nullptr, + unsigned* column = nullptr); -extern JS_PUBLIC_API(JSObject*) -GetScriptedCallerGlobal(JSContext* cx); +extern JS_PUBLIC_API JSObject* GetScriptedCallerGlobal(JSContext* cx); /** * Informs the JS engine that the scripted caller should be hidden. This can be @@ -5896,29 +5955,22 @@ * drop below zero, and must always be exactly zero when the activation is * popped from the stack. */ -extern JS_PUBLIC_API(void) -HideScriptedCaller(JSContext* cx); +extern JS_PUBLIC_API void HideScriptedCaller(JSContext* cx); -extern JS_PUBLIC_API(void) -UnhideScriptedCaller(JSContext* cx); +extern JS_PUBLIC_API void UnhideScriptedCaller(JSContext* cx); -class MOZ_RAII AutoHideScriptedCaller -{ - public: - explicit AutoHideScriptedCaller(JSContext* cx - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - HideScriptedCaller(mContext); - } - ~AutoHideScriptedCaller() { - UnhideScriptedCaller(mContext); - } - - protected: - JSContext* mContext; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +class MOZ_RAII AutoHideScriptedCaller { + public: + explicit AutoHideScriptedCaller(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + HideScriptedCaller(mContext); + } + ~AutoHideScriptedCaller() { UnhideScriptedCaller(mContext); } + + protected: + JSContext* mContext; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; /* @@ -5926,36 +5978,73 @@ */ typedef mozilla::Vector TranscodeBuffer; +typedef mozilla::Range TranscodeRange; -enum TranscodeResult -{ - // Successful encoding / decoding. - TranscodeResult_Ok = 0, - - // 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, - - // 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); +struct TranscodeSource { + TranscodeSource(const TranscodeRange& range_, const char* file, uint32_t line) + : range(range_), filename(file), lineno(line) {} + + const TranscodeRange range; + const char* filename; + const uint32_t lineno; +}; + +typedef mozilla::Vector TranscodeSources; + +enum TranscodeResult { + // Successful encoding / decoding. + TranscodeResult_Ok = 0, + + // 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_BadDecode = TranscodeResult_Failure | 0x4, + TranscodeResult_Failure_WrongCompileOption = TranscodeResult_Failure | 0x5, + TranscodeResult_Failure_NotInterpretedFun = TranscodeResult_Failure | 0x6, + + // There is a pending exception on the context. + 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 +DecodeScript(JSContext* cx, const TranscodeRange& range, + JS::MutableHandleScript scriptp); + +extern JS_PUBLIC_API TranscodeResult DecodeInterpretedFunction( + JSContext* cx, TranscodeBuffer& buffer, JS::MutableHandleFunction funp, + size_t cursorIndex = 0); + +// Register an encoder on the given script source, such that all functions can +// be encoded as they are parsed. This strategy is used to avoid blocking the +// active thread in a non-interruptible way. +// +// The |script| argument of |StartIncrementalEncoding| and +// |FinishIncrementalEncoding| should be the top-level script returned either as +// an out-param of any of the |Compile| functions, or the result of +// |FinishOffThreadScript|. +// +// The |buffer| argument of |FinishIncrementalEncoding| is used for appending +// the encoded bytecode into the buffer. If any of these functions failed, the +// content of |buffer| would be undefined. +extern JS_PUBLIC_API bool StartIncrementalEncoding(JSContext* cx, + JS::HandleScript script); + +extern JS_PUBLIC_API bool FinishIncrementalEncoding(JSContext* cx, + JS::HandleScript script, + TranscodeBuffer& buffer); } /* namespace JS */ @@ -5970,13 +6059,11 @@ * 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 void SetStackFormat(JSContext* cx, StackFormat format); -extern JS_PUBLIC_API(StackFormat) -GetStackFormat(JSContext* cx); +extern JS_PUBLIC_API StackFormat GetStackFormat(JSContext* cx); -} +} // namespace js namespace JS { @@ -5989,28 +6076,27 @@ * CloseAsmJSCacheEntryForReadOp, passing the same base address, size and * handle. */ -typedef bool -(* OpenAsmJSCacheEntryForReadOp)(HandleObject global, const char16_t* begin, const char16_t* limit, - size_t* size, const uint8_t** memory, intptr_t* handle); -typedef void -(* CloseAsmJSCacheEntryForReadOp)(size_t size, const uint8_t* memory, intptr_t handle); +typedef bool (*OpenAsmJSCacheEntryForReadOp)( + HandleObject global, const char16_t* begin, const char16_t* limit, + size_t* size, const uint8_t** memory, intptr_t* handle); +typedef void (*CloseAsmJSCacheEntryForReadOp)(size_t size, + const uint8_t* memory, + intptr_t handle); /** The list of reasons why an asm.js module may not be stored in the cache. */ -enum AsmJSCacheResult -{ - AsmJSCache_Success, - AsmJSCache_MIN = AsmJSCache_Success, - AsmJSCache_ModuleTooSmall, - AsmJSCache_SynchronousScript, - AsmJSCache_QuotaExceeded, - AsmJSCache_StorageInitFailure, - AsmJSCache_Disabled_Internal, - AsmJSCache_Disabled_ShellFlags, - AsmJSCache_Disabled_JitInspector, - AsmJSCache_InternalError, - AsmJSCache_Disabled_PrivateBrowsing, - AsmJSCache_ESR52, - AsmJSCache_LIMIT +enum AsmJSCacheResult { + AsmJSCache_Success, + AsmJSCache_MIN = AsmJSCache_Success, + AsmJSCache_ModuleTooSmall, + AsmJSCache_SynchronousScript, + AsmJSCache_QuotaExceeded, + AsmJSCache_StorageInitFailure, + AsmJSCache_Disabled_Internal, + AsmJSCache_Disabled_ShellFlags, + AsmJSCache_Disabled_JitInspector, + AsmJSCache_InternalError, + AsmJSCache_Disabled_PrivateBrowsing, + AsmJSCache_LIMIT }; /* @@ -6021,30 +6107,22 @@ * outparams. If the callback returns 'true', the JS engine guarantees a call * to CloseAsmJSCacheEntryForWriteOp passing the same base address, size and * handle. - * - * If 'installed' is true, then the cache entry is associated with a permanently - * installed JS file (e.g., in a packaged webapp). This information allows the - * embedding to store the cache entry in a installed location associated with - * the principal of 'global' where it will not be evicted until the associated - * installed JS file is removed. - */ -typedef AsmJSCacheResult -(* OpenAsmJSCacheEntryForWriteOp)(HandleObject global, bool installed, - const char16_t* begin, const char16_t* end, - size_t size, uint8_t** memory, intptr_t* handle); -typedef void -(* CloseAsmJSCacheEntryForWriteOp)(size_t size, uint8_t* memory, intptr_t handle); - -struct AsmJSCacheOps -{ - OpenAsmJSCacheEntryForReadOp openEntryForRead; - CloseAsmJSCacheEntryForReadOp closeEntryForRead; - OpenAsmJSCacheEntryForWriteOp openEntryForWrite; - CloseAsmJSCacheEntryForWriteOp closeEntryForWrite; + */ +typedef AsmJSCacheResult (*OpenAsmJSCacheEntryForWriteOp)( + HandleObject global, const char16_t* begin, const char16_t* end, + size_t size, uint8_t** memory, intptr_t* handle); +typedef void (*CloseAsmJSCacheEntryForWriteOp)(size_t size, uint8_t* memory, + intptr_t handle); + +struct AsmJSCacheOps { + OpenAsmJSCacheEntryForReadOp openEntryForRead; + CloseAsmJSCacheEntryForReadOp closeEntryForRead; + OpenAsmJSCacheEntryForWriteOp openEntryForWrite; + CloseAsmJSCacheEntryForWriteOp closeEntryForWrite; }; -extern JS_PUBLIC_API(void) -SetAsmJSCacheOps(JSContext* cx, const AsmJSCacheOps* callbacks); +extern JS_PUBLIC_API void SetAsmJSCacheOps(JSContext* cx, + const AsmJSCacheOps* callbacks); /** * Return the buildId (represented as a sequence of characters) associated with @@ -6055,26 +6133,38 @@ */ typedef js::Vector BuildIdCharVector; -typedef bool -(* BuildIdOp)(BuildIdCharVector* buildId); +typedef bool (*BuildIdOp)(BuildIdCharVector* buildId); -extern JS_PUBLIC_API(void) -SetBuildIdOp(JSContext* cx, BuildIdOp buildIdOp); +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. + * of efficient postMessage() and (de)serialization from a random thread. + * + * For postMessage() sharing: + * + * - GetWasmModule() is called when making a structured clone of payload + * containing a WebAssembly.Module object. The structured clone buffer holds a + * refcount of the JS::WasmModule until createObject() is called in the target + * agent's JSContext. The new WebAssembly.Module object continues to hold the + * JS::WasmModule and thus the final reference of a JS::WasmModule may be + * dropped from any thread and so the virtual destructor (and all internal + * methods of the C++ module) must be thread-safe. + * + * For (de)serialization: * * - 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. + * This interface is then taken to a background thread where the bytecode and + * compiled code are written into separate 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. Due to tiering, the serialization must + * asynchronously wait for compilation to complete before requesting the + * module's compiled code. After serialization, a reference is dropped from a + * separate thread so the virtual destructor must be thread-safe. * * - Deserialization starts when the structured clone algorithm encounters a * serialized WebAssembly.Module. On a background thread, the compiled-code file @@ -6082,35 +6172,56 @@ * 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(). + * The JS::WasmObject is then transported to a JSContext thread and the wrapping + * WebAssembly.Module object is created by calling createObject(). */ -struct WasmModule : mozilla::external::AtomicRefCounted -{ - MOZ_DECLARE_REFCOUNTED_TYPENAME(WasmModule) - virtual ~WasmModule() {} +class WasmModuleListener { + protected: + virtual ~WasmModuleListener() {} + + public: + // These method signatures are chosen to exactly match nsISupports so that a + // plain nsISupports-implementing class can trivially implement this + // interface too. We can't simply #include "nsISupports.h" so we use MFBT + // equivalents for all the platform-dependent types. + virtual MozExternalRefCountType MOZ_XPCOM_ABI AddRef() = 0; + virtual MozExternalRefCountType MOZ_XPCOM_ABI Release() = 0; - 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 void onCompilationComplete() = 0; +}; + +struct WasmModule : js::AtomicRefCounted { + virtual ~WasmModule() {} + + virtual size_t bytecodeSerializedSize() const = 0; + virtual void bytecodeSerialize(uint8_t* bytecodeBegin, + size_t bytecodeSize) const = 0; - virtual JSObject* createObject(JSContext* cx) = 0; + // Compilation must complete before the serialized code is requested. If + // compilation is not complete, the embedding must wait until notified by + // implementing WasmModuleListener. SpiderMonkey will hold a RefPtr to + // 'listener' until onCompilationComplete() is called. + virtual bool compilationComplete() const = 0; + virtual bool notifyWhenCompilationComplete(WasmModuleListener* listener) = 0; + virtual size_t compiledSerializedSize() const = 0; + virtual void compiledSerialize(uint8_t* compiledBegin, + size_t compiledSize) const = 0; + + virtual JSObject* createObject(JSContext* cx) = 0; }; -extern JS_PUBLIC_API(bool) -IsWasmModuleObject(HandleObject obj); +extern JS_PUBLIC_API bool IsWasmModuleObject(HandleObject obj); -extern JS_PUBLIC_API(RefPtr) -GetWasmModule(HandleObject obj); +extern JS_PUBLIC_API RefPtr GetWasmModule(HandleObject obj); -extern JS_PUBLIC_API(bool) -CompiledWasmModuleAssumptionsMatch(PRFileDesc* compiled, BuildIdCharVector&& buildId); +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); +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: @@ -6129,80 +6240,84 @@ * return false; * } */ -class MOZ_STACK_CLASS JS_PUBLIC_API(ForOfIterator) { - protected: - JSContext* cx_; - /* - * Use the ForOfPIC on the global object (see vm/GlobalObject.h) to try - * to optimize iteration across arrays. - * - * Case 1: Regular Iteration - * iterator - pointer to the iterator object. - * index - fixed to NOT_ARRAY (== UINT32_MAX) - * - * Case 2: Optimized Array Iteration - * iterator - pointer to the array object. - * index - current position in array. - * - * The cases are distinguished by whether or not |index| is equal to NOT_ARRAY. - */ - JS::RootedObject iterator; - uint32_t index; - - static const uint32_t NOT_ARRAY = UINT32_MAX; - - ForOfIterator(const ForOfIterator&) = delete; - ForOfIterator& operator=(const ForOfIterator&) = delete; - - public: - explicit ForOfIterator(JSContext* cx) : cx_(cx), iterator(cx_), index(NOT_ARRAY) { } - - enum NonIterableBehavior { - ThrowOnNonIterable, - AllowNonIterable - }; +class MOZ_STACK_CLASS JS_PUBLIC_API ForOfIterator { + protected: + JSContext* cx_; + /* + * Use the ForOfPIC on the global object (see vm/GlobalObject.h) to try + * to optimize iteration across arrays. + * + * Case 1: Regular Iteration + * iterator - pointer to the iterator object. + * nextMethod - value of |iterator|.next. + * index - fixed to NOT_ARRAY (== UINT32_MAX) + * + * Case 2: Optimized Array Iteration + * iterator - pointer to the array object. + * nextMethod - the undefined value. + * index - current position in array. + * + * The cases are distinguished by whether or not |index| is equal to + * NOT_ARRAY. + */ + JS::RootedObject iterator; + JS::RootedValue nextMethod; + uint32_t index; + + static const uint32_t NOT_ARRAY = UINT32_MAX; + + ForOfIterator(const ForOfIterator&) = delete; + ForOfIterator& operator=(const ForOfIterator&) = delete; + + public: + explicit ForOfIterator(JSContext* cx) + : cx_(cx), iterator(cx_), nextMethod(cx), index(NOT_ARRAY) {} + + enum NonIterableBehavior { ThrowOnNonIterable, AllowNonIterable }; + + /** + * Initialize the iterator. If AllowNonIterable is passed then if getting + * the @@iterator property from iterable returns undefined init() will just + * return true instead of throwing. Callers must then check + * valueIsIterable() before continuing with the iteration. + */ + bool init(JS::HandleValue iterable, + NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable); + + /** + * Get the next value from the iterator. If false *done is true + * after this call, do not examine val. + */ + bool next(JS::MutableHandleValue val, bool* done); + + /** + * Close the iterator. + * For the case that completion type is throw. + */ + void closeThrow(); + + /** + * If initialized with throwOnNonCallable = false, check whether + * the value is iterable. + */ + bool valueIsIterable() const { return iterator; } - /** - * Initialize the iterator. If AllowNonIterable is passed then if getting - * the @@iterator property from iterable returns undefined init() will just - * return true instead of throwing. Callers must then check - * valueIsIterable() before continuing with the iteration. - */ - bool init(JS::HandleValue iterable, - NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable); - - /** - * Get the next value from the iterator. If false *done is true - * after this call, do not examine val. - */ - bool next(JS::MutableHandleValue val, bool* done); - - /** - * If initialized with throwOnNonCallable = false, check whether - * the value is iterable. - */ - bool valueIsIterable() const { - return iterator; - } - - private: - inline bool nextFromOptimizedArray(MutableHandleValue val, bool* done); - bool materializeArrayIterator(); + private: + inline bool nextFromOptimizedArray(MutableHandleValue val, bool* done); }; - /** * If a large allocation fails when calling pod_{calloc,realloc}CanGC, the JS - * engine may call the large-allocation- failure callback, if set, to allow the + * engine may call the large-allocation-failure callback, if set, to allow the * embedding to flush caches, possibly perform shrinking GCs, etc. to make some - * room. The allocation will then be retried (and may still fail.) + * room. The allocation will then be retried (and may still fail.) This callback + * can be called on any thread and must be set at most once in a process. */ -typedef void -(* LargeAllocationFailureCallback)(void* data); +typedef void (*LargeAllocationFailureCallback)(); -extern JS_PUBLIC_API(void) -SetLargeAllocationFailureCallback(JSContext* cx, LargeAllocationFailureCallback afc, void* data); +extern JS_PUBLIC_API void SetProcessLargeAllocationFailureCallback( + LargeAllocationFailureCallback afc); /** * Unlike the error reporter, which is only called if the exception for an OOM @@ -6215,29 +6330,24 @@ * large-allocation-failure callback has returned. */ -typedef void -(* OutOfMemoryCallback)(JSContext* cx, void* data); +typedef void (*OutOfMemoryCallback)(JSContext* cx, void* data); -extern JS_PUBLIC_API(void) -SetOutOfMemoryCallback(JSContext* cx, OutOfMemoryCallback cb, void* data); +extern JS_PUBLIC_API void SetOutOfMemoryCallback(JSContext* cx, + OutOfMemoryCallback cb, + void* data); /** * Capture all frames. */ -struct AllFrames { }; +struct AllFrames {}; /** * Capture at most this many frames. */ -struct MaxFrames -{ - uint32_t maxFrames; - - explicit MaxFrames(uint32_t max) - : maxFrames(max) - { - MOZ_ASSERT(max > 0); - } +struct MaxFrames { + uint32_t maxFrames; + + explicit MaxFrames(uint32_t max) : maxFrames(max) { MOZ_ASSERT(max > 0); } }; /** @@ -6245,48 +6355,42 @@ * 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); - } +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; @@ -6309,9 +6413,9 @@ * |JS::FirstSubsumedFrame::ignoreSelfHosted| flag. Do not capture any async * stack. */ -extern JS_PUBLIC_API(bool) -CaptureCurrentStack(JSContext* cx, MutableHandleObject stackp, - StackCapture&& capture = StackCapture(AllFrames())); +extern JS_PUBLIC_API bool CaptureCurrentStack( + JSContext* cx, MutableHandleObject stackp, + StackCapture&& capture = StackCapture(AllFrames())); /* * This is a utility function for preparing an async stack to be used @@ -6323,14 +6427,13 @@ * Here |asyncStack| is the async stack to prepare. It is copied into * |cx|'s current compartment, and the newest frame is given * |asyncCause| as its asynchronous cause. If |maxFrameCount| is - * non-zero, capture at most the youngest |maxFrameCount| frames. The + * |Some(n)|, capture at most the youngest |n| frames. The * new stack object is written to |stackp|. Returns true on success, * or sets an exception and returns |false| on error. */ -extern JS_PUBLIC_API(bool) -CopyAsyncStack(JSContext* cx, HandleObject asyncStack, - HandleString asyncCause, MutableHandleObject stackp, - unsigned maxFrameCount); +extern JS_PUBLIC_API bool CopyAsyncStack( + JSContext* cx, HandleObject asyncStack, HandleString asyncCause, + MutableHandleObject stackp, const mozilla::Maybe& maxFrameCount); /* * Accessors for working with SavedFrame JSObjects @@ -6362,71 +6465,65 @@ * See also `js/src/doc/SavedFrame/SavedFrame.md`. */ -enum class SavedFrameResult { - Ok, - AccessDenied -}; +enum class SavedFrameResult { Ok, AccessDenied }; -enum class SavedFrameSelfHosted { - Include, - Exclude -}; +enum class SavedFrameSelfHosted { Include, Exclude }; /** * Given a SavedFrame JSObject, get its source property. Defaults to the empty * string. */ -extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString sourcep, - SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); +extern JS_PUBLIC_API SavedFrameResult GetSavedFrameSource( + JSContext* cx, HandleObject savedFrame, MutableHandleString sourcep, + SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its line property. Defaults to 0. */ -extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep, - SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); +extern JS_PUBLIC_API SavedFrameResult GetSavedFrameLine( + JSContext* cx, HandleObject savedFrame, uint32_t* linep, + SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its column property. Defaults to 0. */ -extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp, - SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); +extern JS_PUBLIC_API SavedFrameResult GetSavedFrameColumn( + JSContext* cx, HandleObject savedFrame, uint32_t* columnp, + SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its functionDisplayName string, or nullptr * if SpiderMonkey was unable to infer a name for the captured frame's * function. Defaults to nullptr. */ -extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, MutableHandleString namep, - SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); +extern JS_PUBLIC_API SavedFrameResult GetSavedFrameFunctionDisplayName( + JSContext* cx, HandleObject savedFrame, MutableHandleString namep, + SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its asyncCause string. Defaults to nullptr. */ -extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleString asyncCausep, - SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); +extern JS_PUBLIC_API SavedFrameResult GetSavedFrameAsyncCause( + JSContext* cx, HandleObject savedFrame, MutableHandleString asyncCausep, + SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its asyncParent SavedFrame object or nullptr * if there is no asyncParent. The `asyncParentp` out parameter is _NOT_ * guaranteed to be in the cx's compartment. Defaults to nullptr. */ -extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject asyncParentp, - SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); +extern JS_PUBLIC_API SavedFrameResult GetSavedFrameAsyncParent( + JSContext* cx, HandleObject savedFrame, MutableHandleObject asyncParentp, + SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its parent SavedFrame object or nullptr if * it is the oldest frame in the stack. The `parentp` out parameter is _NOT_ * guaranteed to be in the cx's compartment. Defaults to nullptr. */ -extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject parentp, - SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); +extern JS_PUBLIC_API SavedFrameResult GetSavedFrameParent( + JSContext* cx, HandleObject savedFrame, MutableHandleObject parentp, + SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject stack, stringify it in the same format as @@ -6440,20 +6537,18 @@ * Optional indent parameter specifies the number of white spaces to indent * each line. */ -extern JS_PUBLIC_API(bool) -BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp, - size_t indent = 0, js::StackFormat stackFormat = js::StackFormat::Default); +extern JS_PUBLIC_API bool 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); +extern JS_PUBLIC_API bool IsSavedFrame(JSObject* obj); } /* namespace JS */ - /* Stopwatch-based performance monitoring. */ namespace js { @@ -6466,124 +6561,124 @@ * provide a concrete implementation of this class, as well as the * relevant callbacks (see below). */ -struct JS_PUBLIC_API(PerformanceGroup) { - PerformanceGroup(); - - // The current iteration of the event loop. - uint64_t iteration() const; +struct JS_PUBLIC_API PerformanceGroup { + PerformanceGroup(); - // `true` if an instance of `AutoStopwatch` is already monitoring - // the performance of this performance group for this iteration - // of the event loop, `false` otherwise. - bool isAcquired(uint64_t it) const; - - // `true` if a specific instance of `AutoStopwatch` is already monitoring - // the performance of this performance group for this iteration - // of the event loop, `false` otherwise. - bool isAcquired(uint64_t it, const AutoStopwatch* owner) const; - - // Mark that an instance of `AutoStopwatch` is monitoring - // the performance of this group for a given iteration. - void acquire(uint64_t it, const AutoStopwatch* owner); - - // Mark that no `AutoStopwatch` is monitoring the - // performance of this group for the iteration. - void release(uint64_t it, const AutoStopwatch* owner); - - // The number of cycles spent in this group during this iteration - // of the event loop. Note that cycles are not a reliable measure, - // especially over short intervals. See Stopwatch.* for a more - // complete discussion on the imprecision of cycle measurement. - uint64_t recentCycles(uint64_t iteration) const; - void addRecentCycles(uint64_t iteration, uint64_t cycles); - - // The number of times this group has been activated during this - // iteration of the event loop. - uint64_t recentTicks(uint64_t iteration) const; - void addRecentTicks(uint64_t iteration, uint64_t ticks); - - // The number of microseconds spent doing CPOW during this - // iteration of the event loop. - uint64_t recentCPOW(uint64_t iteration) const; - void addRecentCPOW(uint64_t iteration, uint64_t CPOW); - - // Get rid of any data that pretends to be recent. - void resetRecentData(); - - // `true` if new measures should be added to this group, `false` - // otherwise. - bool isActive() const; - void setIsActive(bool); - - // `true` if this group has been used in the current iteration, - // `false` otherwise. - bool isUsedInThisIteration() const; - void setIsUsedInThisIteration(bool); - protected: - // An implementation of `delete` for this object. Must be provided - // by the embedding. - virtual void Delete() = 0; + // The current iteration of the event loop. + uint64_t iteration() const; - private: - // The number of cycles spent in this group during this iteration - // of the event loop. Note that cycles are not a reliable measure, - // especially over short intervals. See Runtime.cpp for a more - // complete discussion on the imprecision of cycle measurement. - uint64_t recentCycles_; - - // The number of times this group has been activated during this - // iteration of the event loop. - uint64_t recentTicks_; - - // The number of microseconds spent doing CPOW during this - // iteration of the event loop. - uint64_t recentCPOW_; - - // The current iteration of the event loop. If necessary, - // may safely overflow. - uint64_t iteration_; - - // `true` if new measures should be added to this group, `false` - // otherwise. - bool isActive_; - - // `true` if this group has been used in the current iteration, - // `false` otherwise. - bool isUsedInThisIteration_; - - // The stopwatch currently monitoring the group, - // or `nullptr` if none. Used ony for comparison. - const AutoStopwatch* owner_; - - public: - // Compatibility with RefPtr<> - void AddRef(); - void Release(); - uint64_t refCount_; + // `true` if an instance of `AutoStopwatch` is already monitoring + // the performance of this performance group for this iteration + // of the event loop, `false` otherwise. + bool isAcquired(uint64_t it) const; + + // `true` if a specific instance of `AutoStopwatch` is already monitoring + // the performance of this performance group for this iteration + // of the event loop, `false` otherwise. + bool isAcquired(uint64_t it, const AutoStopwatch* owner) const; + + // Mark that an instance of `AutoStopwatch` is monitoring + // the performance of this group for a given iteration. + void acquire(uint64_t it, const AutoStopwatch* owner); + + // Mark that no `AutoStopwatch` is monitoring the + // performance of this group for the iteration. + void release(uint64_t it, const AutoStopwatch* owner); + + // The number of cycles spent in this group during this iteration + // of the event loop. Note that cycles are not a reliable measure, + // especially over short intervals. See Stopwatch.* for a more + // complete discussion on the imprecision of cycle measurement. + uint64_t recentCycles(uint64_t iteration) const; + void addRecentCycles(uint64_t iteration, uint64_t cycles); + + // The number of times this group has been activated during this + // iteration of the event loop. + uint64_t recentTicks(uint64_t iteration) const; + void addRecentTicks(uint64_t iteration, uint64_t ticks); + + // The number of microseconds spent doing CPOW during this + // iteration of the event loop. + uint64_t recentCPOW(uint64_t iteration) const; + void addRecentCPOW(uint64_t iteration, uint64_t CPOW); + + // Get rid of any data that pretends to be recent. + void resetRecentData(); + + // `true` if new measures should be added to this group, `false` + // otherwise. + bool isActive() const; + void setIsActive(bool); + + // `true` if this group has been used in the current iteration, + // `false` otherwise. + bool isUsedInThisIteration() const; + void setIsUsedInThisIteration(bool); + + protected: + // An implementation of `delete` for this object. Must be provided + // by the embedding. + virtual void Delete() = 0; + + private: + // The number of cycles spent in this group during this iteration + // of the event loop. Note that cycles are not a reliable measure, + // especially over short intervals. See Runtime.cpp for a more + // complete discussion on the imprecision of cycle measurement. + uint64_t recentCycles_; + + // The number of times this group has been activated during this + // iteration of the event loop. + uint64_t recentTicks_; + + // The number of microseconds spent doing CPOW during this + // iteration of the event loop. + uint64_t recentCPOW_; + + // The current iteration of the event loop. If necessary, + // may safely overflow. + uint64_t iteration_; + + // `true` if new measures should be added to this group, `false` + // otherwise. + bool isActive_; + + // `true` if this group has been used in the current iteration, + // `false` otherwise. + bool isUsedInThisIteration_; + + // The stopwatch currently monitoring the group, + // or `nullptr` if none. Used ony for comparison. + const AutoStopwatch* owner_; + + public: + // Compatibility with RefPtr<> + void AddRef(); + void Release(); + uint64_t refCount_; }; -using PerformanceGroupVector = mozilla::Vector, 0, SystemAllocPolicy>; +using PerformanceGroupVector = + mozilla::Vector, 8, SystemAllocPolicy>; /** * Commit any Performance Monitoring data. * - * Until `FlushMonitoring` has been called, all PerformanceMonitoring data is invisible - * to the outside world and can cancelled with a call to `ResetMonitoring`. + * Until `FlushMonitoring` has been called, all PerformanceMonitoring data is + * invisible to the outside world and can cancelled with a call to + * `ResetMonitoring`. */ -extern JS_PUBLIC_API(bool) -FlushPerformanceMonitoring(JSContext*); +extern JS_PUBLIC_API bool FlushPerformanceMonitoring(JSContext*); /** * Cancel any measurement that hasn't been committed. */ -extern JS_PUBLIC_API(void) -ResetPerformanceMonitoring(JSContext*); +extern JS_PUBLIC_API void ResetPerformanceMonitoring(JSContext*); /** * Cleanup any memory used by performance monitoring. */ -extern JS_PUBLIC_API(void) -DisposePerformanceMonitoring(JSContext*); +extern JS_PUBLIC_API void DisposePerformanceMonitoring(JSContext*); /** * Turn on/off stopwatch-based CPU monitoring. @@ -6592,43 +6687,50 @@ * may return `false` if monitoring could not be activated, which may * happen if we are out of memory. */ -extern JS_PUBLIC_API(bool) -SetStopwatchIsMonitoringCPOW(JSContext*, bool); -extern JS_PUBLIC_API(bool) -GetStopwatchIsMonitoringCPOW(JSContext*); -extern JS_PUBLIC_API(bool) -SetStopwatchIsMonitoringJank(JSContext*, bool); -extern JS_PUBLIC_API(bool) -GetStopwatchIsMonitoringJank(JSContext*); +extern JS_PUBLIC_API bool SetStopwatchIsMonitoringCPOW(JSContext*, bool); +extern JS_PUBLIC_API bool GetStopwatchIsMonitoringCPOW(JSContext*); +extern JS_PUBLIC_API bool SetStopwatchIsMonitoringJank(JSContext*, bool); +extern JS_PUBLIC_API bool GetStopwatchIsMonitoringJank(JSContext*); // Extract the CPU rescheduling data. -extern JS_PUBLIC_API(void) -GetPerfMonitoringTestCpuRescheduling(JSContext*, uint64_t* stayed, uint64_t* moved); - +extern JS_PUBLIC_API void GetPerfMonitoringTestCpuRescheduling(JSContext*, + uint64_t* stayed, + uint64_t* moved); /** * Add a number of microseconds to the time spent waiting on CPOWs * since process start. */ -extern JS_PUBLIC_API(void) -AddCPOWPerformanceDelta(JSContext*, uint64_t delta); +extern JS_PUBLIC_API void AddCPOWPerformanceDelta(JSContext*, uint64_t delta); -typedef bool -(*StopwatchStartCallback)(uint64_t, void*); -extern JS_PUBLIC_API(bool) -SetStopwatchStartCallback(JSContext*, StopwatchStartCallback, void*); - -typedef bool -(*StopwatchCommitCallback)(uint64_t, PerformanceGroupVector&, void*); -extern JS_PUBLIC_API(bool) -SetStopwatchCommitCallback(JSContext*, StopwatchCommitCallback, void*); - -typedef bool -(*GetGroupsCallback)(JSContext*, PerformanceGroupVector&, void*); -extern JS_PUBLIC_API(bool) -SetGetPerformanceGroupsCallback(JSContext*, GetGroupsCallback, void*); +typedef bool (*StopwatchStartCallback)(uint64_t, void*); +extern JS_PUBLIC_API bool SetStopwatchStartCallback(JSContext*, + StopwatchStartCallback, + void*); + +typedef bool (*StopwatchCommitCallback)(uint64_t, PerformanceGroupVector&, + void*); +extern JS_PUBLIC_API bool SetStopwatchCommitCallback(JSContext*, + StopwatchCommitCallback, + void*); + +typedef bool (*GetGroupsCallback)(JSContext*, PerformanceGroupVector&, void*); +extern JS_PUBLIC_API bool SetGetPerformanceGroupsCallback(JSContext*, + GetGroupsCallback, + void*); + +/** + * Hint that we expect a crash. Currently, the only thing that cares is the + * breakpad injector, which (if loaded) will suppress minidump generation. + */ +extern JS_PUBLIC_API void NoteIntentionalCrash(); } /* namespace js */ +namespace js { + +enum class CompletionKind { Normal, Return, Throw }; + +} /* namespace js */ #endif /* jsapi_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsbytecode.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsbytecode.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsbytecode.h @@ -1,14 +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 jsbytecode_h -#define jsbytecode_h - -#include - -typedef uint8_t jsbytecode; - -#endif /* jsbytecode_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsclist.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsclist.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/jsclist.h @@ -1,107 +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 jsclist_h -#define jsclist_h - -#include "jstypes.h" - -/* -** Circular linked list -*/ -typedef struct JSCListStr { - struct JSCListStr* next; - struct JSCListStr* prev; -} JSCList; - -/* -** Insert element "_e" into the list, before "_l". -*/ -#define JS_INSERT_BEFORE(_e,_l) \ - JS_BEGIN_MACRO \ - (_e)->next = (_l); \ - (_e)->prev = (_l)->prev; \ - (_l)->prev->next = (_e); \ - (_l)->prev = (_e); \ - JS_END_MACRO - -/* -** Insert element "_e" into the list, after "_l". -*/ -#define JS_INSERT_AFTER(_e,_l) \ - JS_BEGIN_MACRO \ - (_e)->next = (_l)->next; \ - (_e)->prev = (_l); \ - (_l)->next->prev = (_e); \ - (_l)->next = (_e); \ - JS_END_MACRO - -/* -** Return the element following element "_e" -*/ -#define JS_NEXT_LINK(_e) \ - ((_e)->next) -/* -** Return the element preceding element "_e" -*/ -#define JS_PREV_LINK(_e) \ - ((_e)->prev) - -/* -** Append an element "_e" to the end of the list "_l" -*/ -#define JS_APPEND_LINK(_e,_l) JS_INSERT_BEFORE(_e,_l) - -/* -** Insert an element "_e" at the head of the list "_l" -*/ -#define JS_INSERT_LINK(_e,_l) JS_INSERT_AFTER(_e,_l) - -/* Return the head/tail of the list */ -#define JS_LIST_HEAD(_l) (_l)->next -#define JS_LIST_TAIL(_l) (_l)->prev - -/* -** Remove the element "_e" from it's circular list. -*/ -#define JS_REMOVE_LINK(_e) \ - JS_BEGIN_MACRO \ - (_e)->prev->next = (_e)->next; \ - (_e)->next->prev = (_e)->prev; \ - JS_END_MACRO - -/* -** Remove the element "_e" from it's circular list. Also initializes the -** linkage. -*/ -#define JS_REMOVE_AND_INIT_LINK(_e) \ - JS_BEGIN_MACRO \ - (_e)->prev->next = (_e)->next; \ - (_e)->next->prev = (_e)->prev; \ - (_e)->next = (_e); \ - (_e)->prev = (_e); \ - JS_END_MACRO - -/* -** Return non-zero if the given circular list "_l" is empty, zero if the -** circular list is not empty -*/ -#define JS_CLIST_IS_EMPTY(_l) \ - bool((_l)->next == (_l)) - -/* -** Initialize a circular list -*/ -#define JS_INIT_CLIST(_l) \ - JS_BEGIN_MACRO \ - (_l)->next = (_l); \ - (_l)->prev = (_l); \ - JS_END_MACRO - -#define JS_INIT_STATIC_CLIST(_l) \ - {(_l), (_l)} - -#endif /* jsclist_h */ 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 @@ -1,20 +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 jscpucfg_h -#define jscpucfg_h - -#include "mozilla/EndianUtils.h" - -#ifndef JS_STACK_GROWTH_DIRECTION -# ifdef __hppa -# define JS_STACK_GROWTH_DIRECTION (1) -# else -# define JS_STACK_GROWTH_DIRECTION (-1) -# endif -#endif - -#endif /* jscpucfg_h */ 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 @@ -13,22 +13,30 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/UniquePtr.h" -#include "jsapi.h" // For JSAutoByteString. See bug 1033916. -#include "jsbytecode.h" +#include "jsapi.h" // For JSAutoByteString. See bug 1033916. #include "jspubtd.h" #include "js/CallArgs.h" #include "js/CallNonGenericMethod.h" #include "js/Class.h" +#include "js/HeapAPI.h" +#include "js/TypeDecls.h" #include "js/Utility.h" +#ifndef JS_STACK_GROWTH_DIRECTION +#ifdef __hppa +#define JS_STACK_GROWTH_DIRECTION (1) +#else +#define JS_STACK_GROWTH_DIRECTION (-1) +#endif +#endif + #if JS_STACK_GROWTH_DIRECTION > 0 -# define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) < (limit))) +#define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) < (limit))) #else -# define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) > (limit))) +#define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) > (limit))) #endif -class JSAtom; struct JSErrorFormatString; class JSLinearString; struct JSJitInfo; @@ -40,24 +48,25 @@ } /* namespace JS */ namespace js { -class JS_FRIEND_API(BaseProxyHandler); +class JS_FRIEND_API BaseProxyHandler; class InterpreterFrame; } /* namespace js */ -extern JS_FRIEND_API(void) -JS_SetGrayGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp, void* data); +extern JS_FRIEND_API void JS_SetGrayGCRootsTracer(JSContext* cx, + JSTraceDataOp traceOp, + void* data); -extern JS_FRIEND_API(JSObject*) -JS_FindCompilationScope(JSContext* cx, JS::HandleObject obj); +extern JS_FRIEND_API JSObject* JS_FindCompilationScope(JSContext* cx, + JS::HandleObject obj); -extern JS_FRIEND_API(JSFunction*) -JS_GetObjectFunction(JSObject* obj); +extern JS_FRIEND_API JSFunction* JS_GetObjectFunction(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_SplicePrototype(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto); +extern JS_FRIEND_API bool JS_SplicePrototype(JSContext* cx, + JS::HandleObject obj, + JS::HandleObject proto); -extern JS_FRIEND_API(JSObject*) -JS_NewObjectWithUniqueType(JSContext* cx, const JSClass* clasp, JS::HandleObject proto); +extern JS_FRIEND_API JSObject* JS_NewObjectWithUniqueType( + JSContext* cx, const JSClass* clasp, JS::HandleObject proto); /** * Allocate an object in exactly the same way as JS_NewObjectWithGivenProto, but @@ -65,27 +74,21 @@ * internal bookkeeping objects that are guaranteed to not have metadata * attached to them. */ -extern JS_FRIEND_API(JSObject*) -JS_NewObjectWithoutMetadata(JSContext* cx, const JSClass* clasp, JS::Handle proto); - -extern JS_FRIEND_API(uint32_t) -JS_ObjectCountDynamicSlots(JS::HandleObject obj); - -extern JS_FRIEND_API(size_t) -JS_SetProtoCalled(JSContext* cx); +extern JS_FRIEND_API JSObject* JS_NewObjectWithoutMetadata( + JSContext* cx, const JSClass* clasp, JS::Handle proto); -extern JS_FRIEND_API(size_t) -JS_GetCustomIteratorCount(JSContext* cx); +extern JS_FRIEND_API uint32_t JS_ObjectCountDynamicSlots(JS::HandleObject obj); -extern JS_FRIEND_API(bool) -JS_NondeterministicGetWeakMapKeys(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret); +extern JS_FRIEND_API bool JS_NondeterministicGetWeakMapKeys( + JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret); -extern JS_FRIEND_API(bool) -JS_NondeterministicGetWeakSetKeys(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret); +extern JS_FRIEND_API bool JS_NondeterministicGetWeakSetKeys( + JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret); // Raw JSScript* because this needs to be callable from a signal handler. -extern JS_FRIEND_API(unsigned) -JS_PCToLineNumber(JSScript* script, jsbytecode* pc, unsigned* columnp = nullptr); +extern JS_FRIEND_API unsigned JS_PCToLineNumber(JSScript* script, + jsbytecode* pc, + unsigned* columnp = nullptr); /** * Determine whether the given object is backed by a DeadObjectProxy. @@ -93,75 +96,113 @@ * Such objects hold no other objects (they have no outgoing reference edges) * and will throw if you touch them (e.g. by reading/writing a property). */ -extern JS_FRIEND_API(bool) -JS_IsDeadWrapper(JSObject* obj); +extern JS_FRIEND_API bool JS_IsDeadWrapper(JSObject* obj); + +/** + * Creates a new dead wrapper object in the given scope. To be used when + * attempting to wrap objects from scopes which are already dead. + * + * If origObject is passed, it must be an proxy object, and will be + * used to determine the characteristics of the new dead wrapper. + */ +extern JS_FRIEND_API JSObject* JS_NewDeadWrapper( + JSContext* cx, JSObject* origObject = nullptr); + +/** + * Determine whether the given object is a ScriptSourceObject. + */ +extern JS_FRIEND_API bool JS_IsScriptSourceObject(JSObject* obj); /* * Used by the cycle collector to trace through a shape or object group and * all cycle-participating data it reaches, using bounded stack space. */ -extern JS_FRIEND_API(void) -JS_TraceShapeCycleCollectorChildren(JS::CallbackTracer* trc, JS::GCCellPtr shape); -extern JS_FRIEND_API(void) -JS_TraceObjectGroupCycleCollectorChildren(JS::CallbackTracer* trc, JS::GCCellPtr group); +extern JS_FRIEND_API void JS_TraceShapeCycleCollectorChildren( + JS::CallbackTracer* trc, JS::GCCellPtr shape); +extern JS_FRIEND_API void JS_TraceObjectGroupCycleCollectorChildren( + JS::CallbackTracer* trc, JS::GCCellPtr group); +/* + * Telemetry reasons passed to the accumulate telemetry callback. + * + * It's OK for these enum values to change as they will be mapped to a fixed + * member of the mozilla::Telemetry::HistogramID enum by the callback. + */ enum { - JS_TELEMETRY_GC_REASON, - 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_AOT_USAGE, - JS_TELEMETRY_END -}; - -typedef void -(*JSAccumulateTelemetryDataCallback)(int id, uint32_t sample, const char* key); - -extern JS_FRIEND_API(void) -JS_SetAccumulateTelemetryCallback(JSContext* cx, JSAccumulateTelemetryDataCallback callback); - -extern JS_FRIEND_API(bool) -JS_GetIsSecureContext(JSCompartment* compartment); - -extern JS_FRIEND_API(JSPrincipals*) -JS_GetCompartmentPrincipals(JSCompartment* compartment); - -extern JS_FRIEND_API(void) -JS_SetCompartmentPrincipals(JSCompartment* compartment, JSPrincipals* principals); + JS_TELEMETRY_GC_REASON, + JS_TELEMETRY_GC_IS_ZONE_GC, + JS_TELEMETRY_GC_MS, + JS_TELEMETRY_GC_BUDGET_MS, + JS_TELEMETRY_GC_BUDGET_OVERRUN, + JS_TELEMETRY_GC_ANIMATION_MS, + JS_TELEMETRY_GC_MAX_PAUSE_MS_2, + 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_SLOW_TASK, + 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_ADDON_EXCEPTIONS, + JS_TELEMETRY_PRIVILEGED_PARSER_COMPILE_LAZY_AFTER_MS, + JS_TELEMETRY_WEB_PARSER_COMPILE_LAZY_AFTER_MS, + JS_TELEMETRY_END +}; + +typedef void (*JSAccumulateTelemetryDataCallback)(int id, uint32_t sample, + const char* key); + +extern JS_FRIEND_API void JS_SetAccumulateTelemetryCallback( + JSContext* cx, JSAccumulateTelemetryDataCallback callback); + +/* + * Use counter names passed to the accumulate use counter callback. + * + * It's OK to for these enum values to change as they will be mapped to a + * fixed member of the mozilla::UseCounter enum by the callback. + */ + +enum class JSUseCounter { ASMJS, WASM }; + +typedef void (*JSSetUseCounterCallback)(JSObject* obj, JSUseCounter counter); + +extern JS_FRIEND_API void JS_SetSetUseCounterCallback( + JSContext* cx, JSSetUseCounterCallback callback); + +extern JS_FRIEND_API bool JS_GetIsSecureContext(JSCompartment* compartment); -extern JS_FRIEND_API(JSPrincipals*) -JS_GetScriptPrincipals(JSScript* script); +extern JS_FRIEND_API JSPrincipals* JS_GetCompartmentPrincipals( + JSCompartment* compartment); -extern JS_FRIEND_API(bool) -JS_ScriptHasMutedErrors(JSScript* script); +extern JS_FRIEND_API void JS_SetCompartmentPrincipals( + JSCompartment* compartment, JSPrincipals* principals); -extern JS_FRIEND_API(JSObject*) -JS_CloneObject(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto); +extern JS_FRIEND_API JSPrincipals* JS_GetScriptPrincipals(JSScript* script); + +namespace js { +extern JS_FRIEND_API JSCompartment* GetScriptCompartment(JSScript* script); +} /* namespace js */ + +extern JS_FRIEND_API bool JS_ScriptHasMutedErrors(JSScript* script); + +extern JS_FRIEND_API JSObject* JS_CloneObject(JSContext* cx, + JS::HandleObject obj, + JS::HandleObject proto); /** * Copy the own properties of src to dst in a fast way. src and dst must both @@ -176,33 +217,27 @@ * dst needs to have the compartment global as its parent. This function will * preserve the existing metadata on dst, if any. */ -extern JS_FRIEND_API(bool) -JS_InitializePropertiesFromCompatibleNativeObject(JSContext* cx, - JS::HandleObject dst, - JS::HandleObject src); +extern JS_FRIEND_API bool JS_InitializePropertiesFromCompatibleNativeObject( + JSContext* cx, JS::HandleObject dst, JS::HandleObject src); -extern JS_FRIEND_API(JSString*) -JS_BasicObjectToString(JSContext* cx, JS::HandleObject obj); +extern JS_FRIEND_API JSString* JS_BasicObjectToString(JSContext* cx, + JS::HandleObject obj); namespace js { -JS_FRIEND_API(bool) -GetBuiltinClass(JSContext* cx, JS::HandleObject obj, ESClass* cls); +JS_FRIEND_API bool GetBuiltinClass(JSContext* cx, JS::HandleObject obj, + ESClass* cls); -JS_FRIEND_API(const char*) -ObjectClassName(JSContext* cx, JS::HandleObject obj); +JS_FRIEND_API const char* ObjectClassName(JSContext* cx, JS::HandleObject obj); -JS_FRIEND_API(void) -ReportOverRecursed(JSContext* maybecx); +JS_FRIEND_API void ReportOverRecursed(JSContext* maybecx); -JS_FRIEND_API(bool) -AddRawValueRoot(JSContext* cx, JS::Value* vp, const char* name); +JS_FRIEND_API bool AddRawValueRoot(JSContext* cx, JS::Value* vp, + const char* name); -JS_FRIEND_API(void) -RemoveRawValueRoot(JSContext* cx, JS::Value* vp); +JS_FRIEND_API void RemoveRawValueRoot(JSContext* cx, JS::Value* vp); -JS_FRIEND_API(JSAtom*) -GetPropertyNameFromPC(JSScript* script, jsbytecode* pc); +JS_FRIEND_API JSAtom* GetPropertyNameFromPC(JSScript* script, jsbytecode* pc); #ifdef JS_DEBUG @@ -213,69 +248,71 @@ * parameter, which will default to stderr. */ -extern JS_FRIEND_API(void) -DumpString(JSString* str, FILE* fp); +extern JS_FRIEND_API void DumpString(JSString* str, FILE* fp); -extern JS_FRIEND_API(void) -DumpAtom(JSAtom* atom, FILE* fp); +extern JS_FRIEND_API void DumpAtom(JSAtom* atom, FILE* fp); -extern JS_FRIEND_API(void) -DumpObject(JSObject* obj, FILE* fp); +extern JS_FRIEND_API void DumpObject(JSObject* obj, FILE* fp); -extern JS_FRIEND_API(void) -DumpChars(const char16_t* s, size_t n, FILE* fp); +extern JS_FRIEND_API void DumpChars(const char16_t* s, size_t n, FILE* fp); -extern JS_FRIEND_API(void) -DumpValue(const JS::Value& val, FILE* fp); +extern JS_FRIEND_API void DumpValue(const JS::Value& val, FILE* fp); -extern JS_FRIEND_API(void) -DumpId(jsid id, FILE* fp); +extern JS_FRIEND_API void DumpId(jsid id, FILE* fp); -extern JS_FRIEND_API(void) -DumpInterpreterFrame(JSContext* cx, FILE* fp, InterpreterFrame* start = nullptr); +extern JS_FRIEND_API void DumpInterpreterFrame( + JSContext* cx, FILE* fp, InterpreterFrame* start = nullptr); -extern JS_FRIEND_API(bool) -DumpPC(JSContext* cx, FILE* fp); +extern JS_FRIEND_API bool DumpPC(JSContext* cx, FILE* fp); -extern JS_FRIEND_API(bool) -DumpScript(JSContext* cx, JSScript* scriptArg, FILE* fp); +extern JS_FRIEND_API bool 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); +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, FILE* fp); -extern JS_FRIEND_API(void) -DumpBacktrace(JSContext* cx); +extern JS_FRIEND_API void DumpBacktrace(JSContext* cx); -} // namespace js +} // namespace js namespace JS { /** Exposed for DumpJSStack */ -extern JS_FRIEND_API(char*) -FormatStackDump(JSContext* cx, char* buf, bool showArgs, bool showLocals, bool showThisProps); +extern JS_FRIEND_API JS::UniqueChars FormatStackDump(JSContext* cx, + JS::UniqueChars&& 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); +extern JS_FRIEND_API bool ForceLexicalInitialization(JSContext* cx, + HandleObject obj); -} // namespace JS +/** + * Whether we are poisoning unused/released data for error detection. Governed + * by the JS_GC_POISONING #ifdef as well as the $JSGC_DISABLE_POISONING + * environment variable. + */ +extern JS_FRIEND_API int IsGCPoisoning(); + +} // namespace JS /** * Copies all own properties from |obj| to |target|. |obj| must be a "native" @@ -284,8 +321,9 @@ * This function immediately enters a compartment, and does not impose any * restrictions on the compartment of |cx|. */ -extern JS_FRIEND_API(bool) -JS_CopyPropertiesFrom(JSContext* cx, JS::HandleObject target, JS::HandleObject obj); +extern JS_FRIEND_API bool JS_CopyPropertiesFrom(JSContext* cx, + JS::HandleObject target, + JS::HandleObject obj); /* * Single-property version of the above. This function asserts that an |own| @@ -296,129 +334,45 @@ * The copyBehavior argument controls what happens with * non-configurable properties. */ -typedef enum { - MakeNonConfigurableIntoConfigurable, - CopyNonConfigurableAsIs +typedef enum { + MakeNonConfigurableIntoConfigurable, + CopyNonConfigurableAsIs } PropertyCopyBehavior; -extern JS_FRIEND_API(bool) -JS_CopyPropertyFrom(JSContext* cx, JS::HandleId id, JS::HandleObject target, - JS::HandleObject obj, - PropertyCopyBehavior copyBehavior = CopyNonConfigurableAsIs); +extern JS_FRIEND_API bool JS_CopyPropertyFrom( + JSContext* cx, JS::HandleId id, JS::HandleObject target, + JS::HandleObject obj, + PropertyCopyBehavior copyBehavior = CopyNonConfigurableAsIs); -extern JS_FRIEND_API(bool) -JS_WrapPropertyDescriptor(JSContext* cx, JS::MutableHandle desc); +extern JS_FRIEND_API bool JS_WrapPropertyDescriptor( + JSContext* cx, JS::MutableHandle desc); struct JSFunctionSpecWithHelp { - const char* name; - JSNative call; - uint16_t nargs; - uint16_t flags; - const JSJitInfo* jitInfo; - const char* usage; - const char* help; -}; - -#define JS_FN_HELP(name,call,nargs,flags,usage,help) \ - {name, call, nargs, (flags) | JSPROP_ENUMERATE | JSFUN_STUB_GSOPS, nullptr, usage, help} -#define JS_INLINABLE_FN_HELP(name,call,nargs,flags,native,usage,help) \ - {name, call, nargs, (flags) | JSPROP_ENUMERATE | JSFUN_STUB_GSOPS, &js::jit::JitInfo_##native,\ - usage, help} -#define JS_FS_HELP_END \ - {nullptr, nullptr, 0, 0, nullptr, nullptr} - -extern JS_FRIEND_API(bool) -JS_DefineFunctionsWithHelp(JSContext* cx, JS::HandleObject obj, const JSFunctionSpecWithHelp* fs); - -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(objectMoved) \ - { \ - js::proxy_WeakmapKeyDelegate, \ - objectMoved \ - } + const char* name; + JSNative call; + uint16_t nargs; + uint16_t flags; + const JSJitInfo* jitInfo; + const char* usage; + const char* help; +}; -#define PROXY_CLASS_WITH_EXT(name, flags, extPtr) \ - { \ - name, \ - js::Class::NON_NATIVE | \ - JSCLASS_IS_PROXY | \ - JSCLASS_DELAY_METADATA_BUILDER | \ - flags, \ - &js::ProxyClassOps, \ - JS_NULL_CLASS_SPEC, \ - extPtr, \ - &js::ProxyObjectOps \ - } +#define JS_FN_HELP(name, call, nargs, flags, usage, help) \ + { name, call, nargs, (flags) | JSPROP_ENUMERATE, nullptr, usage, help } +#define JS_INLINABLE_FN_HELP(name, call, nargs, flags, native, usage, help) \ + { \ + name, call, nargs, (flags) | JSPROP_ENUMERATE, &js::jit::JitInfo_##native, \ + usage, help \ + } +#define JS_FS_HELP_END \ + { nullptr, nullptr, 0, 0, nullptr, nullptr } -#define PROXY_CLASS_DEF(name, flags) \ - PROXY_CLASS_WITH_EXT(name, flags, &js::ProxyClassExtension) +extern JS_FRIEND_API bool JS_DefineFunctionsWithHelp( + JSContext* cx, JS::HandleObject obj, const JSFunctionSpecWithHelp* fs); -/* - * Proxy stubs, similar to JS_*Stub, for embedder proxy class definitions. - * - * NB: Should not be called directly. - */ +namespace js { -extern JS_FRIEND_API(bool) -proxy_LookupProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp, - JS::MutableHandle propp); -extern JS_FRIEND_API(bool) -proxy_DefineProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc, - JS::ObjectOpResult& result); -extern JS_FRIEND_API(bool) -proxy_HasProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); -extern JS_FRIEND_API(bool) -proxy_GetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleValue receiver, JS::HandleId id, - JS::MutableHandleValue vp); -extern JS_FRIEND_API(bool) -proxy_SetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue bp, - JS::HandleValue receiver, JS::ObjectOpResult& result); -extern JS_FRIEND_API(bool) -proxy_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); -extern JS_FRIEND_API(bool) -proxy_DeleteProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::ObjectOpResult& result); - -extern JS_FRIEND_API(void) -proxy_Trace(JSTracer* trc, JSObject* obj); -extern JS_FRIEND_API(JSObject*) -proxy_WeakmapKeyDelegate(JSObject* obj); -extern JS_FRIEND_API(bool) -proxy_Convert(JSContext* cx, JS::HandleObject proxy, JSType hint, JS::MutableHandleValue vp); -extern JS_FRIEND_API(void) -proxy_Finalize(FreeOp* fop, JSObject* obj); -extern JS_FRIEND_API(void) -proxy_ObjectMoved(JSObject* obj, const JSObject* old); -extern JS_FRIEND_API(bool) -proxy_HasInstance(JSContext* cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool* bp); -extern JS_FRIEND_API(bool) -proxy_Call(JSContext* cx, unsigned argc, JS::Value* vp); -extern JS_FRIEND_API(bool) -proxy_Construct(JSContext* cx, unsigned argc, JS::Value* vp); -extern JS_FRIEND_API(JSObject*) -proxy_innerObject(JSObject* obj); -extern JS_FRIEND_API(bool) -proxy_Watch(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); -extern JS_FRIEND_API(bool) -proxy_Unwatch(JSContext* cx, JS::HandleObject obj, JS::HandleId id); -extern JS_FRIEND_API(bool) -proxy_GetElements(JSContext* cx, JS::HandleObject proxy, uint32_t begin, uint32_t end, - ElementAdder* adder); -extern JS_FRIEND_API(JSString*) -proxy_FunToString(JSContext* cx, JS::HandleObject proxy, unsigned indent); +extern JS_FRIEND_API JSObject* proxy_WeakmapKeyDelegate(JSObject* obj); /** * A class of objects that return source code on demand. @@ -432,15 +386,16 @@ * find the source. */ class SourceHook { - public: - virtual ~SourceHook() { } + public: + virtual ~SourceHook() {} - /** - * Set |*src| and |*length| to refer to the source code for |filename|. - * On success, the caller owns the buffer to which |*src| points, and - * should use JS_free to free it. - */ - virtual bool load(JSContext* cx, const char* filename, char16_t** src, size_t* length) = 0; + /** + * Set |*src| and |*length| to refer to the source code for |filename|. + * On success, the caller owns the buffer to which |*src| points, and + * should use JS_free to free it. + */ + virtual bool load(JSContext* cx, const char* filename, char16_t** src, + size_t* length) = 0; }; /** @@ -449,101 +404,137 @@ * will delete it when the context itself is deleted, or when a new hook is * set. */ -extern JS_FRIEND_API(void) -SetSourceHook(JSContext* cx, mozilla::UniquePtr hook); +extern JS_FRIEND_API void SetSourceHook(JSContext* cx, + mozilla::UniquePtr hook); /** Remove |cx|'s source hook, and return it. The caller now owns the hook. */ -extern JS_FRIEND_API(mozilla::UniquePtr) -ForgetSourceHook(JSContext* cx); +extern JS_FRIEND_API mozilla::UniquePtr ForgetSourceHook( + JSContext* cx); -extern JS_FRIEND_API(JS::Zone*) -GetCompartmentZone(JSCompartment* comp); +/** + * Use the runtime's internal handling of job queues for Promise jobs. + * + * Most embeddings, notably web browsers, will have their own task scheduling + * systems and need to integrate handling of Promise jobs into that, so they + * will want to manage job queues themselves. For basic embeddings such as the + * JS shell that don't have an event loop of their own, it's easier to have + * SpiderMonkey handle job queues internally. + * + * Note that the embedding still has to trigger processing of job queues at + * right time(s), such as after evaluation of a script has run to completion. + */ +extern JS_FRIEND_API bool UseInternalJobQueues(JSContext* cx, + bool cooperative = false); + +/** + * Enqueue |job| on the internal job queue. + * + * This is useful in tests for creating situations where a call occurs with no + * other JavaScript on the stack. + */ +extern JS_FRIEND_API bool EnqueueJob(JSContext* cx, JS::HandleObject job); + +/** + * Instruct the runtime to stop draining the internal job queue. + * + * Useful if the embedding is in the process of quitting in reaction to a + * builtin being called, or if it wants to resume executing jobs later on. + */ +extern JS_FRIEND_API void StopDrainingJobQueue(JSContext* cx); -typedef bool -(* PreserveWrapperCallback)(JSContext* cx, JSObject* obj); +extern JS_FRIEND_API void RunJobs(JSContext* cx); -typedef enum { - CollectNurseryBeforeDump, - IgnoreNurseryObjects +extern JS_FRIEND_API JS::Zone* GetCompartmentZone(JSCompartment* comp); + +typedef bool (*PreserveWrapperCallback)(JSContext* cx, JSObject* obj); + +typedef enum { + CollectNurseryBeforeDump, + IgnoreNurseryObjects } DumpHeapNurseryBehaviour; - /** - * Dump the complete object graph of heap-allocated things. - * fp is the file for the dump output. - */ -extern JS_FRIEND_API(void) -DumpHeap(JSContext* cx, FILE* fp, DumpHeapNurseryBehaviour nurseryBehaviour); +/** + * Dump the complete object graph of heap-allocated things. + * fp is the file for the dump output. + */ +extern JS_FRIEND_API void 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); -JS_FRIEND_API(bool) obj_defineSetter(JSContext* cx, unsigned argc, JS::Value* vp); +JS_FRIEND_API bool obj_defineGetter(JSContext* cx, unsigned argc, + JS::Value* vp); +JS_FRIEND_API bool obj_defineSetter(JSContext* cx, unsigned argc, + JS::Value* vp); #endif -extern JS_FRIEND_API(bool) -IsSystemCompartment(JSCompartment* comp); +extern JS_FRIEND_API bool IsSystemCompartment(JSCompartment* comp); -extern JS_FRIEND_API(bool) -IsSystemZone(JS::Zone* zone); +extern JS_FRIEND_API bool IsSystemZone(JS::Zone* zone); -extern JS_FRIEND_API(bool) -IsAtomsCompartment(JSCompartment* comp); +extern JS_FRIEND_API bool IsAtomsCompartment(JSCompartment* comp); -extern JS_FRIEND_API(bool) -IsAtomsZone(JS::Zone* zone); +extern JS_FRIEND_API bool IsAtomsZone(JS::Zone* zone); -struct WeakMapTracer -{ - JSContext* context; +struct WeakMapTracer { + JSRuntime* runtime; - explicit WeakMapTracer(JSContext* cx) : context(cx) {} + explicit WeakMapTracer(JSRuntime* rt) : runtime(rt) {} - // Weak map tracer callback, called once for every binding of every - // weak map that was live at the time of the last garbage collection. - // - // m will be nullptr if the weak map is not contained in a JS Object. - // - // The callback should not GC (and will assert in a debug build if it does so.) - virtual void trace(JSObject* m, JS::GCCellPtr key, JS::GCCellPtr value) = 0; + // Weak map tracer callback, called once for every binding of every + // weak map that was live at the time of the last garbage collection. + // + // m will be nullptr if the weak map is not contained in a JS Object. + // + // The callback should not GC (and will assert in a debug build if it does + // so.) + virtual void trace(JSObject* m, JS::GCCellPtr key, JS::GCCellPtr value) = 0; }; -extern JS_FRIEND_API(void) -TraceWeakMaps(WeakMapTracer* trc); +extern JS_FRIEND_API void TraceWeakMaps(WeakMapTracer* trc); + +extern JS_FRIEND_API bool AreGCGrayBitsValid(JSRuntime* rt); -extern JS_FRIEND_API(bool) -AreGCGrayBitsValid(JSContext* cx); +extern JS_FRIEND_API bool ZoneGlobalsAreAllGray(JS::Zone* zone); -extern JS_FRIEND_API(bool) -ZoneGlobalsAreAllGray(JS::Zone* zone); +extern JS_FRIEND_API bool IsObjectZoneSweepingOrCompacting(JSObject* obj); -typedef void -(*GCThingCallback)(void* closure, JS::GCCellPtr thing); +typedef void (*GCThingCallback)(void* closure, JS::GCCellPtr thing); -extern JS_FRIEND_API(void) -VisitGrayWrapperTargets(JS::Zone* zone, GCThingCallback callback, void* closure); +extern JS_FRIEND_API void VisitGrayWrapperTargets(JS::Zone* zone, + GCThingCallback callback, + void* closure); -extern JS_FRIEND_API(JSObject*) -GetWeakmapKeyDelegate(JSObject* key); +extern JS_FRIEND_API JSObject* GetWeakmapKeyDelegate(JSObject* key); /** * Invoke cellCallback on every gray JSObject in the given zone. */ -extern JS_FRIEND_API(void) -IterateGrayObjects(JS::Zone* zone, GCThingCallback cellCallback, void* data); +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); +extern JS_FRIEND_API void IterateGrayObjectsUnderCC( + JS::Zone* zone, GCThingCallback cellCallback, void* data); + +#if defined(JS_GC_ZEAL) || defined(DEBUG) +// Trace the heap and check there are no black to gray edges. These are +// not allowed since the cycle collector could throw away the gray thing and +// leave a dangling pointer. +// +// This doesn't trace weak maps as these are handled separately. +extern JS_FRIEND_API bool CheckGrayMarkingState(JSRuntime* rt); +#endif #ifdef JS_HAS_CTYPES -extern JS_FRIEND_API(size_t) +extern JS_FRIEND_API size_t SizeOfDataIfCDataObject(mozilla::MallocSizeOf mallocSizeOf, JSObject* obj); #endif -extern JS_FRIEND_API(JSCompartment*) -GetAnyCompartmentInZone(JS::Zone* zone); +extern JS_FRIEND_API JSCompartment* GetAnyCompartmentInZone(JS::Zone* zone); /* * Shadow declarations of JS internal structures, for access by inline access @@ -554,23 +545,24 @@ namespace shadow { struct ObjectGroup { - const Class* clasp; - JSObject* proto; - JSCompartment* compartment; + const Class* clasp; + JSObject* proto; + JSCompartment* compartment; }; struct BaseShape { - const js::Class* clasp_; - JSObject* parent; + const js::Class* clasp_; + JSObject* parent; }; class Shape { -public: - shadow::BaseShape* base; - jsid _1; - uint32_t slotInfo; + public: + shadow::BaseShape* base; + void* _1; + jsid _2; + uint32_t slotInfo; - static const uint32_t FIXED_SLOTS_SHIFT = 27; + static const uint32_t FIXED_SLOTS_SHIFT = 27; }; /** @@ -579,70 +571,75 @@ * depending on the object's specific layout. */ struct Object { - shadow::ObjectGroup* group; - shadow::Shape* shape; - JS::Value* slots; - void* _1; - - size_t numFixedSlots() const { return shape->slotInfo >> Shape::FIXED_SLOTS_SHIFT; } - JS::Value* fixedSlots() const { - return (JS::Value*)(uintptr_t(this) + sizeof(shadow::Object)); - } + shadow::ObjectGroup* group; + shadow::Shape* shape; + JS::Value* slots; + void* _1; - JS::Value& slotRef(size_t slot) const { - size_t nfixed = numFixedSlots(); - if (slot < nfixed) - return fixedSlots()[slot]; - return slots[slot - nfixed]; - } + static const size_t MAX_FIXED_SLOTS = 16; + + size_t numFixedSlots() const { + return shape->slotInfo >> Shape::FIXED_SLOTS_SHIFT; + } + JS::Value* fixedSlots() const { + return (JS::Value*)(uintptr_t(this) + sizeof(shadow::Object)); + } + + JS::Value& slotRef(size_t slot) const { + size_t nfixed = numFixedSlots(); + if (slot < nfixed) return fixedSlots()[slot]; + return slots[slot - nfixed]; + } }; struct Function { - Object base; - uint16_t nargs; - uint16_t flags; - /* Used only for natives */ - JSNative native; - const JSJitInfo* jitinfo; - void* _1; -}; - -struct String -{ - static const uint32_t INLINE_CHARS_BIT = JS_BIT(2); - static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6); - static const uint32_t ROPE_FLAGS = 0; - static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1; - uint32_t flags; - uint32_t length; - union { - const JS::Latin1Char* nonInlineCharsLatin1; - const char16_t* nonInlineCharsTwoByte; - JS::Latin1Char inlineStorageLatin1[1]; - char16_t inlineStorageTwoByte[1]; - }; + Object base; + uint16_t nargs; + uint16_t flags; + /* Used only for natives */ + JSNative native; + const JSJitInfo* jitinfo; + void* _1; +}; + +struct String { + static const uint32_t NON_ATOM_BIT = JS_BIT(0); + static const uint32_t LINEAR_BIT = JS_BIT(1); + static const uint32_t INLINE_CHARS_BIT = JS_BIT(3); + static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6); + static const uint32_t EXTERNAL_FLAGS = LINEAR_BIT | NON_ATOM_BIT | JS_BIT(5); + static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1; + uint32_t flags; + uint32_t length; + union { + const JS::Latin1Char* nonInlineCharsLatin1; + const char16_t* nonInlineCharsTwoByte; + JS::Latin1Char inlineStorageLatin1[1]; + char16_t inlineStorageTwoByte[1]; + }; + const JSStringFinalizer* externalFinalizer; + + static bool nurseryCellIsString(const js::gc::Cell* cell) { + MOZ_ASSERT(IsInsideNursery(cell)); + return reinterpret_cast(cell)->flags & NON_ATOM_BIT; + } }; } /* namespace shadow */ // This is equal to |&JSObject::class_|. Use it in places where you don't want -// to #include jsobj.h. -extern JS_FRIEND_DATA(const js::Class* const) ObjectClassPtr; +// to #include vm/JSObject.h. +extern JS_FRIEND_DATA const js::Class* const ObjectClassPtr; -inline const js::Class* -GetObjectClass(const JSObject* obj) -{ - return reinterpret_cast(obj)->group->clasp; +inline const js::Class* GetObjectClass(const JSObject* obj) { + return reinterpret_cast(obj)->group->clasp; } -inline const JSClass* -GetObjectJSClass(JSObject* obj) -{ - return js::Jsvalify(GetObjectClass(obj)); +inline const JSClass* GetObjectJSClass(JSObject* obj) { + return js::Jsvalify(GetObjectClass(obj)); } -JS_FRIEND_API(const Class*) -ProtoKeyToClass(JSProtoKey key); +JS_FRIEND_API const Class* ProtoKeyToClass(JSProtoKey key); // 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,294 +648,257 @@ // JSProtoKey before calling this function. In general |key| will match the // cached proto key, except in cases where multiple JSProtoKeys share a // JSClass. -inline JSProtoKey -InheritanceProtoKeyForStandardClass(JSProtoKey key) -{ - // [Object] has nothing to inherit from. - if (key == JSProto_Object) - return JSProto_Null; +inline JSProtoKey InheritanceProtoKeyForStandardClass(JSProtoKey key) { + // [Object] has nothing to inherit from. + if (key == JSProto_Object) return JSProto_Null; - // If we're ClassSpec defined return the proto key from that - if (ProtoKeyToClass(key)->specDefined()) - return ProtoKeyToClass(key)->specInheritanceProtoKey(); + // 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; + // Otherwise, we inherit [Object]. + return JSProto_Object; } -JS_FRIEND_API(bool) -IsFunctionObject(JSObject* obj); +JS_FRIEND_API bool IsFunctionObject(JSObject* obj); -static MOZ_ALWAYS_INLINE JSCompartment* -GetObjectCompartment(JSObject* obj) -{ - return reinterpret_cast(obj)->group->compartment; +static MOZ_ALWAYS_INLINE JSCompartment* GetObjectCompartment(JSObject* obj) { + return reinterpret_cast(obj)->group->compartment; } -JS_FRIEND_API(JSObject*) -GetGlobalForObjectCrossCompartment(JSObject* obj); +JS_FRIEND_API JSObject* GetGlobalForObjectCrossCompartment(JSObject* obj); -JS_FRIEND_API(JSObject*) -GetPrototypeNoProxy(JSObject* obj); +JS_FRIEND_API JSObject* GetPrototypeNoProxy(JSObject* obj); -JS_FRIEND_API(void) -AssertSameCompartment(JSContext* cx, JSObject* obj); +JS_FRIEND_API void AssertSameCompartment(JSContext* cx, JSObject* obj); + +JS_FRIEND_API void AssertSameCompartment(JSContext* cx, JS::HandleValue v); #ifdef JS_DEBUG -JS_FRIEND_API(void) -AssertSameCompartment(JSObject* objA, JSObject* objB); +JS_FRIEND_API void AssertSameCompartment(JSObject* objA, JSObject* objB); #else inline void AssertSameCompartment(JSObject* objA, JSObject* objB) {} #endif -JS_FRIEND_API(void) -NotifyAnimationActivity(JSObject* obj); +JS_FRIEND_API void NotifyAnimationActivity(JSObject* obj); -/** - * Return the outermost enclosing function (script) of the scripted caller. - * This function returns nullptr in several cases: - * - no script is running on the context - * - the caller is in global or eval code - * In particular, this function will "stop" its outermost search at eval() and - * thus it will really return the outermost enclosing function *since the - * innermost eval*. - */ -JS_FRIEND_API(JSFunction*) -GetOutermostEnclosingFunctionOfScriptedCaller(JSContext* cx); +JS_FRIEND_API JSFunction* DefineFunctionWithReserved( + JSContext* cx, JSObject* obj, const char* name, JSNative call, + unsigned nargs, unsigned attrs); -JS_FRIEND_API(JSFunction*) -DefineFunctionWithReserved(JSContext* cx, JSObject* obj, const char* name, JSNative call, - unsigned nargs, unsigned attrs); +JS_FRIEND_API JSFunction* NewFunctionWithReserved(JSContext* cx, JSNative call, + unsigned nargs, + unsigned flags, + const char* name); -JS_FRIEND_API(JSFunction*) -NewFunctionWithReserved(JSContext* cx, JSNative call, unsigned nargs, unsigned flags, - const char* name); +JS_FRIEND_API JSFunction* NewFunctionByIdWithReserved(JSContext* cx, + JSNative native, + unsigned nargs, + unsigned flags, jsid id); -JS_FRIEND_API(JSFunction*) -NewFunctionByIdWithReserved(JSContext* cx, JSNative native, unsigned nargs, unsigned flags, - jsid id); +JS_FRIEND_API const JS::Value& GetFunctionNativeReserved(JSObject* fun, + size_t which); -JS_FRIEND_API(const JS::Value&) -GetFunctionNativeReserved(JSObject* fun, size_t which); +JS_FRIEND_API void SetFunctionNativeReserved(JSObject* fun, size_t which, + const JS::Value& val); -JS_FRIEND_API(void) -SetFunctionNativeReserved(JSObject* fun, size_t which, const JS::Value& val); +JS_FRIEND_API bool FunctionHasNativeReserved(JSObject* fun); -JS_FRIEND_API(bool) -FunctionHasNativeReserved(JSObject* fun); +JS_FRIEND_API bool GetObjectProto(JSContext* cx, JS::HandleObject obj, + JS::MutableHandleObject proto); -JS_FRIEND_API(bool) -GetObjectProto(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject proto); +extern JS_FRIEND_API JSObject* GetStaticPrototype(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -GetStaticPrototype(JSObject* obj); +JS_FRIEND_API bool GetOriginalEval(JSContext* cx, JS::HandleObject scope, + JS::MutableHandleObject eval); -JS_FRIEND_API(bool) -GetOriginalEval(JSContext* cx, JS::HandleObject scope, - JS::MutableHandleObject eval); - -inline void* -GetObjectPrivate(JSObject* obj) -{ - MOZ_ASSERT(GetObjectClass(obj)->flags & JSCLASS_HAS_PRIVATE); - const shadow::Object* nobj = reinterpret_cast(obj); - void** addr = reinterpret_cast(&nobj->fixedSlots()[nobj->numFixedSlots()]); - return *addr; +inline void* GetObjectPrivate(JSObject* obj) { + MOZ_ASSERT(GetObjectClass(obj)->flags & JSCLASS_HAS_PRIVATE); + const shadow::Object* nobj = reinterpret_cast(obj); + void** addr = + reinterpret_cast(&nobj->fixedSlots()[nobj->numFixedSlots()]); + return *addr; } -inline const JS::Value& -GetReservedSlot(JSObject* obj, size_t slot) -{ - MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); - return reinterpret_cast(obj)->slotRef(slot); +/** + * Get the value stored in an object's reserved slot. This can be used with + * both native objects and proxies, but if |obj| is known to be a proxy + * GetProxyReservedSlot is a bit more efficient. + */ +inline const JS::Value& GetReservedSlot(JSObject* obj, size_t slot) { + MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); + return reinterpret_cast(obj)->slotRef(slot); } -JS_FRIEND_API(void) -SetReservedOrProxyPrivateSlotWithBarrier(JSObject* obj, size_t slot, const JS::Value& value); +JS_FRIEND_API void SetReservedSlotWithBarrier(JSObject* obj, size_t slot, + const JS::Value& value); -inline void -SetReservedSlot(JSObject* obj, size_t slot, const JS::Value& value) -{ - MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); - shadow::Object* sobj = reinterpret_cast(obj); - if (sobj->slotRef(slot).isMarkable() || value.isMarkable()) - SetReservedOrProxyPrivateSlotWithBarrier(obj, slot, value); - else - sobj->slotRef(slot) = value; +/** + * Store a value in an object's reserved slot. This can be used with + * both native objects and proxies, but if |obj| is known to be a proxy + * SetProxyReservedSlot is a bit more efficient. + */ +inline void SetReservedSlot(JSObject* obj, size_t slot, + const JS::Value& value) { + MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); + shadow::Object* sobj = reinterpret_cast(obj); + if (sobj->slotRef(slot).isGCThing() || value.isGCThing()) + SetReservedSlotWithBarrier(obj, slot, value); + else + sobj->slotRef(slot) = value; } -JS_FRIEND_API(uint32_t) -GetObjectSlotSpan(JSObject* obj); +JS_FRIEND_API uint32_t GetObjectSlotSpan(JSObject* obj); -inline const JS::Value& -GetObjectSlot(JSObject* obj, size_t slot) -{ - MOZ_ASSERT(slot < GetObjectSlotSpan(obj)); - return reinterpret_cast(obj)->slotRef(slot); +inline const JS::Value& GetObjectSlot(JSObject* obj, size_t slot) { + MOZ_ASSERT(slot < GetObjectSlotSpan(obj)); + return reinterpret_cast(obj)->slotRef(slot); } -MOZ_ALWAYS_INLINE size_t -GetAtomLength(JSAtom* atom) -{ - return reinterpret_cast(atom)->length; +MOZ_ALWAYS_INLINE size_t GetAtomLength(JSAtom* atom) { + return reinterpret_cast(atom)->length; } static const uint32_t MaxStringLength = (1 << 28) - 1; -MOZ_ALWAYS_INLINE size_t -GetStringLength(JSString* s) -{ - return reinterpret_cast(s)->length; +MOZ_ALWAYS_INLINE size_t GetStringLength(JSString* s) { + return reinterpret_cast(s)->length; } -MOZ_ALWAYS_INLINE size_t -GetFlatStringLength(JSFlatString* s) -{ - return reinterpret_cast(s)->length; +MOZ_ALWAYS_INLINE size_t GetFlatStringLength(JSFlatString* s) { + return reinterpret_cast(s)->length; } -MOZ_ALWAYS_INLINE size_t -GetLinearStringLength(JSLinearString* s) -{ - return reinterpret_cast(s)->length; +MOZ_ALWAYS_INLINE size_t GetLinearStringLength(JSLinearString* s) { + return reinterpret_cast(s)->length; } -MOZ_ALWAYS_INLINE bool -LinearStringHasLatin1Chars(JSLinearString* s) -{ - return reinterpret_cast(s)->flags & shadow::String::LATIN1_CHARS_BIT; +MOZ_ALWAYS_INLINE bool LinearStringHasLatin1Chars(JSLinearString* s) { + return reinterpret_cast(s)->flags & + shadow::String::LATIN1_CHARS_BIT; } -MOZ_ALWAYS_INLINE bool -AtomHasLatin1Chars(JSAtom* atom) -{ - return reinterpret_cast(atom)->flags & shadow::String::LATIN1_CHARS_BIT; +MOZ_ALWAYS_INLINE bool AtomHasLatin1Chars(JSAtom* atom) { + return reinterpret_cast(atom)->flags & + shadow::String::LATIN1_CHARS_BIT; } -MOZ_ALWAYS_INLINE bool -StringHasLatin1Chars(JSString* s) -{ - return reinterpret_cast(s)->flags & shadow::String::LATIN1_CHARS_BIT; +MOZ_ALWAYS_INLINE bool StringHasLatin1Chars(JSString* s) { + return reinterpret_cast(s)->flags & + shadow::String::LATIN1_CHARS_BIT; } -MOZ_ALWAYS_INLINE const JS::Latin1Char* -GetLatin1LinearStringChars(const JS::AutoCheckCannotGC& nogc, JSLinearString* linear) -{ - MOZ_ASSERT(LinearStringHasLatin1Chars(linear)); +MOZ_ALWAYS_INLINE const JS::Latin1Char* GetLatin1LinearStringChars( + const JS::AutoRequireNoGC& nogc, JSLinearString* linear) { + MOZ_ASSERT(LinearStringHasLatin1Chars(linear)); - using shadow::String; - String* s = reinterpret_cast(linear); - if (s->flags & String::INLINE_CHARS_BIT) - return s->inlineStorageLatin1; - return s->nonInlineCharsLatin1; + using shadow::String; + String* s = reinterpret_cast(linear); + if (s->flags & String::INLINE_CHARS_BIT) return s->inlineStorageLatin1; + return s->nonInlineCharsLatin1; } -MOZ_ALWAYS_INLINE const char16_t* -GetTwoByteLinearStringChars(const JS::AutoCheckCannotGC& nogc, JSLinearString* linear) -{ - MOZ_ASSERT(!LinearStringHasLatin1Chars(linear)); +MOZ_ALWAYS_INLINE const char16_t* GetTwoByteLinearStringChars( + const JS::AutoRequireNoGC& nogc, JSLinearString* linear) { + MOZ_ASSERT(!LinearStringHasLatin1Chars(linear)); - using shadow::String; - String* s = reinterpret_cast(linear); - if (s->flags & String::INLINE_CHARS_BIT) - return s->inlineStorageTwoByte; - return s->nonInlineCharsTwoByte; + using shadow::String; + String* s = reinterpret_cast(linear); + if (s->flags & String::INLINE_CHARS_BIT) return s->inlineStorageTwoByte; + return s->nonInlineCharsTwoByte; } -MOZ_ALWAYS_INLINE JSLinearString* -AtomToLinearString(JSAtom* atom) -{ - return reinterpret_cast(atom); +MOZ_ALWAYS_INLINE JSLinearString* AtomToLinearString(JSAtom* atom) { + return reinterpret_cast(atom); } -MOZ_ALWAYS_INLINE JSFlatString* -AtomToFlatString(JSAtom* atom) -{ - return reinterpret_cast(atom); +MOZ_ALWAYS_INLINE JSFlatString* AtomToFlatString(JSAtom* atom) { + return reinterpret_cast(atom); } -MOZ_ALWAYS_INLINE JSLinearString* -FlatStringToLinearString(JSFlatString* s) -{ - return reinterpret_cast(s); +MOZ_ALWAYS_INLINE JSLinearString* FlatStringToLinearString(JSFlatString* s) { + return reinterpret_cast(s); } -MOZ_ALWAYS_INLINE const JS::Latin1Char* -GetLatin1AtomChars(const JS::AutoCheckCannotGC& nogc, JSAtom* atom) -{ - return GetLatin1LinearStringChars(nogc, AtomToLinearString(atom)); +MOZ_ALWAYS_INLINE const JS::Latin1Char* GetLatin1AtomChars( + const JS::AutoRequireNoGC& nogc, JSAtom* atom) { + return GetLatin1LinearStringChars(nogc, AtomToLinearString(atom)); } -MOZ_ALWAYS_INLINE const char16_t* -GetTwoByteAtomChars(const JS::AutoCheckCannotGC& nogc, JSAtom* atom) -{ - return GetTwoByteLinearStringChars(nogc, AtomToLinearString(atom)); +MOZ_ALWAYS_INLINE const char16_t* GetTwoByteAtomChars( + const JS::AutoRequireNoGC& nogc, JSAtom* atom) { + return GetTwoByteLinearStringChars(nogc, AtomToLinearString(atom)); } -JS_FRIEND_API(JSLinearString*) -StringToLinearStringSlow(JSContext* cx, JSString* str); - -MOZ_ALWAYS_INLINE JSLinearString* -StringToLinearString(JSContext* cx, JSString* str) -{ - using shadow::String; - String* s = reinterpret_cast(str); - if (MOZ_UNLIKELY((s->flags & String::TYPE_FLAGS_MASK) == String::ROPE_FLAGS)) - return StringToLinearStringSlow(cx, str); - return reinterpret_cast(str); -} +MOZ_ALWAYS_INLINE bool IsExternalString(JSString* str, + const JSStringFinalizer** fin, + const char16_t** chars) { + using shadow::String; + String* s = reinterpret_cast(str); -template -MOZ_ALWAYS_INLINE void -CopyLinearStringChars(CharType* dest, JSLinearString* s, size_t len, size_t start = 0); + if ((s->flags & String::TYPE_FLAGS_MASK) != String::EXTERNAL_FLAGS) + return false; -MOZ_ALWAYS_INLINE void -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[start + i]; - } else { - const char16_t* src = GetTwoByteLinearStringChars(nogc, s); - mozilla::PodCopy(dest, src + start, len); - } + MOZ_ASSERT(JS_IsExternalString(str)); + *fin = s->externalFinalizer; + *chars = s->nonInlineCharsTwoByte; + return true; +} + +JS_FRIEND_API JSLinearString* StringToLinearStringSlow(JSContext* cx, + JSString* str); + +MOZ_ALWAYS_INLINE JSLinearString* StringToLinearString(JSContext* cx, + JSString* str) { + using shadow::String; + String* s = reinterpret_cast(str); + if (MOZ_UNLIKELY(!(s->flags & String::LINEAR_BIT))) + return StringToLinearStringSlow(cx, str); + 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, 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[start + i]; + } else { + const char16_t* src = GetTwoByteLinearStringChars(nogc, s); + 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]); - } +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, CharType* dest, JSString* s, size_t len, size_t start = 0) -{ - JSLinearString* linear = StringToLinearString(cx, s); - if (!linear) - return false; +template +inline bool 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, start); - return true; + CopyLinearStringChars(dest, linear, len, start); + return true; } -inline void -CopyFlatStringChars(char16_t* dest, JSFlatString* s, size_t len) -{ - CopyLinearStringChars(dest, FlatStringToLinearString(s), len); +inline void CopyFlatStringChars(char16_t* dest, JSFlatString* s, size_t len) { + CopyLinearStringChars(dest, FlatStringToLinearString(s), len); } /** @@ -962,133 +922,146 @@ * `JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS` as flags to get * results that match the output of Reflect.ownKeys. */ -JS_FRIEND_API(bool) -GetPropertyKeys(JSContext* cx, JS::HandleObject obj, unsigned flags, JS::AutoIdVector* props); +JS_FRIEND_API bool GetPropertyKeys(JSContext* cx, JS::HandleObject obj, + unsigned flags, JS::AutoIdVector* props); -JS_FRIEND_API(bool) -AppendUnique(JSContext* cx, JS::AutoIdVector& base, JS::AutoIdVector& others); +JS_FRIEND_API bool AppendUnique(JSContext* cx, JS::AutoIdVector& base, + JS::AutoIdVector& others); -JS_FRIEND_API(bool) -StringIsArrayIndex(JSLinearString* str, uint32_t* indexp); +JS_FRIEND_API bool StringIsArrayIndex(JSLinearString* str, uint32_t* indexp); -JS_FRIEND_API(void) -SetPreserveWrapperCallback(JSContext* cx, PreserveWrapperCallback callback); +JS_FRIEND_API void SetPreserveWrapperCallback(JSContext* cx, + PreserveWrapperCallback callback); -JS_FRIEND_API(bool) -IsObjectInContextCompartment(JSObject* obj, const JSContext* cx); +JS_FRIEND_API bool IsObjectInContextCompartment(JSObject* obj, + const JSContext* cx); /* * 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. */ -#define JSITER_ENUMERATE 0x1 /* for-in compatible hidden default iterator */ -#define JSITER_FOREACH 0x2 /* get obj[key] for each property */ -#define JSITER_KEYVALUE 0x4 /* obsolete destructuring for-in wants [key, value] */ -#define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */ -#define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */ -#define JSITER_SYMBOLS 0x20 /* also include symbol property keys */ +/* 0x1 is no longer used */ +/* 0x2 is no longer used */ +/* 0x4 is no longer used */ +#define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */ +#define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */ +#define JSITER_SYMBOLS 0x20 /* also include symbol property keys */ #define JSITER_SYMBOLSONLY 0x40 /* exclude string property keys */ +#define JSITER_FORAWAITOF 0x80 /* for-await-of */ -JS_FRIEND_API(bool) -RunningWithTrustedPrincipals(JSContext* cx); +JS_FRIEND_API bool RunningWithTrustedPrincipals(JSContext* cx); -inline uintptr_t -GetNativeStackLimit(JSContext* cx, StackKind kind, int extraAllowance = 0) -{ - uintptr_t limit = ContextFriendFields::get(cx)->nativeStackLimit[kind]; +MOZ_ALWAYS_INLINE uintptr_t GetNativeStackLimit(JSContext* cx, + JS::StackKind kind, + int extraAllowance = 0) { + uintptr_t limit = JS::RootingContext::get(cx)->nativeStackLimit[kind]; #if JS_STACK_GROWTH_DIRECTION > 0 - limit += extraAllowance; + limit += extraAllowance; #else - limit -= extraAllowance; + limit -= extraAllowance; #endif - return limit; + return limit; +} + +MOZ_ALWAYS_INLINE uintptr_t GetNativeStackLimit(JSContext* cx, + int extraAllowance = 0) { + JS::StackKind kind = RunningWithTrustedPrincipals(cx) + ? JS::StackForTrustedScript + : JS::StackForUntrustedScript; + return GetNativeStackLimit(cx, kind, extraAllowance); +} + +/* + * These functions return |false| if we are close to using up the C++ stack. + * They also report an overrecursion error, except for the DontReport variants. + * The CheckSystemRecursionLimit variant gives us a little extra space so we + * can ensure that crucial code is able to run. CheckRecursionLimitConservative + * allows less space than any other check, including a safety buffer (as in, it + * uses the untrusted limit and subtracts a little more from it). + */ + +MOZ_ALWAYS_INLINE bool CheckRecursionLimit(JSContext* cx, uintptr_t limit) { + int stackDummy; + + JS_STACK_OOM_POSSIBLY_FAIL_REPORT(); + + if (!JS_CHECK_STACK_SIZE(limit, &stackDummy)) { + ReportOverRecursed(cx); + return false; + } + return true; +} + +MOZ_ALWAYS_INLINE bool CheckRecursionLimitDontReport(uintptr_t limit) { + int stackDummy; + + JS_STACK_OOM_POSSIBLY_FAIL(); + + return JS_CHECK_STACK_SIZE(limit, &stackDummy); +} + +MOZ_ALWAYS_INLINE bool CheckRecursionLimit(JSContext* cx) { + JS_STACK_OOM_POSSIBLY_FAIL_REPORT(); + + // GetNativeStackLimit(cx) is pretty slow because it has to do an uninlined + // call to RunningWithTrustedPrincipals to determine which stack limit to + // use. To work around this, check the untrusted limit first to avoid the + // overhead in most cases. + uintptr_t untrustedLimit = + GetNativeStackLimit(cx, JS::StackForUntrustedScript); + if (MOZ_LIKELY(CheckRecursionLimitDontReport(untrustedLimit))) return true; + return CheckRecursionLimit(cx, GetNativeStackLimit(cx)); +} + +MOZ_ALWAYS_INLINE bool CheckRecursionLimitDontReport(JSContext* cx) { + return CheckRecursionLimitDontReport(GetNativeStackLimit(cx)); } -inline uintptr_t -GetNativeStackLimit(JSContext* cx, int extraAllowance = 0) -{ - StackKind kind = RunningWithTrustedPrincipals(cx) ? StackForTrustedScript - : StackForUntrustedScript; - return GetNativeStackLimit(cx, kind, extraAllowance); -} - -/* - * These macros report a stack overflow and run |onerror| if we are close to - * using up the C stack. The JS_CHECK_CHROME_RECURSION variant gives us a - * little extra space so that we can ensure that crucial code is able to run. - * JS_CHECK_RECURSION_CONSERVATIVE allows less space than any other check, - * including a safety buffer (as in, it uses the untrusted limit and subtracts - * a little more from it). - */ - -#define JS_CHECK_RECURSION_LIMIT(cx, limit, onerror) \ - JS_BEGIN_MACRO \ - int stackDummy_; \ - if (!JS_CHECK_STACK_SIZE(limit, &stackDummy_)) { \ - js::ReportOverRecursed(cx); \ - onerror; \ - } \ - JS_END_MACRO - -#define JS_CHECK_RECURSION(cx, onerror) \ - JS_CHECK_RECURSION_LIMIT(cx, js::GetNativeStackLimit(cx), onerror) - -#define JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, limit, onerror) \ - JS_BEGIN_MACRO \ - int stackDummy_; \ - if (!JS_CHECK_STACK_SIZE(limit, &stackDummy_)) { \ - onerror; \ - } \ - JS_END_MACRO - -#define JS_CHECK_RECURSION_DONT_REPORT(cx, onerror) \ - JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, js::GetNativeStackLimit(cx), onerror) - -#define JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, sp, onerror) \ - JS_BEGIN_MACRO \ - if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp)) { \ - onerror; \ - } \ - JS_END_MACRO - -#define JS_CHECK_RECURSION_WITH_SP(cx, sp, onerror) \ - JS_BEGIN_MACRO \ - if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp)) { \ - js::ReportOverRecursed(cx); \ - onerror; \ - } \ - JS_END_MACRO - -#define JS_CHECK_SYSTEM_RECURSION(cx, onerror) \ - JS_CHECK_RECURSION_LIMIT(cx, js::GetNativeStackLimit(cx, js::StackForSystemCode), onerror) - -#define JS_CHECK_RECURSION_CONSERVATIVE(cx, onerror) \ - JS_CHECK_RECURSION_LIMIT(cx, \ - js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \ - onerror) - -#define JS_CHECK_RECURSION_CONSERVATIVE_DONT_REPORT(cx, onerror) \ - JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, \ - js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \ - onerror) - -JS_FRIEND_API(void) -StartPCCountProfiling(JSContext* cx); - -JS_FRIEND_API(void) -StopPCCountProfiling(JSContext* cx); - -JS_FRIEND_API(void) -PurgePCCounts(JSContext* cx); +MOZ_ALWAYS_INLINE bool CheckRecursionLimitWithStackPointerDontReport( + JSContext* cx, void* sp) { + JS_STACK_OOM_POSSIBLY_FAIL(); -JS_FRIEND_API(size_t) -GetPCCountScriptCount(JSContext* cx); + return JS_CHECK_STACK_SIZE(GetNativeStackLimit(cx), sp); +} + +MOZ_ALWAYS_INLINE bool CheckRecursionLimitWithStackPointer(JSContext* cx, + void* sp) { + JS_STACK_OOM_POSSIBLY_FAIL_REPORT(); + + if (!JS_CHECK_STACK_SIZE(GetNativeStackLimit(cx), sp)) { + ReportOverRecursed(cx); + return false; + } + return true; +} -JS_FRIEND_API(JSString*) -GetPCCountScriptSummary(JSContext* cx, size_t script); +MOZ_ALWAYS_INLINE bool CheckSystemRecursionLimit(JSContext* cx) { + return CheckRecursionLimit(cx, + GetNativeStackLimit(cx, JS::StackForSystemCode)); +} + +MOZ_ALWAYS_INLINE bool CheckRecursionLimitConservative(JSContext* cx) { + return CheckRecursionLimit( + cx, GetNativeStackLimit(cx, JS::StackForUntrustedScript, + -1024 * int(sizeof(size_t)))); +} + +MOZ_ALWAYS_INLINE bool CheckRecursionLimitConservativeDontReport( + JSContext* cx) { + return CheckRecursionLimitDontReport(GetNativeStackLimit( + cx, JS::StackForUntrustedScript, -1024 * int(sizeof(size_t)))); +} -JS_FRIEND_API(JSString*) -GetPCCountScriptContents(JSContext* cx, size_t script); +JS_FRIEND_API void StartPCCountProfiling(JSContext* cx); + +JS_FRIEND_API void StopPCCountProfiling(JSContext* cx); + +JS_FRIEND_API void PurgePCCounts(JSContext* cx); + +JS_FRIEND_API size_t GetPCCountScriptCount(JSContext* cx); + +JS_FRIEND_API JSString* GetPCCountScriptSummary(JSContext* cx, size_t script); + +JS_FRIEND_API JSString* GetPCCountScriptContents(JSContext* cx, size_t script); /** * Generate lcov trace file content for the current compartment, and allocate a @@ -1098,46 +1071,40 @@ * In case of out-of-memory, this function returns nullptr and does not set any * value to the length out-param. */ -JS_FRIEND_API(char*) -GetCodeCoverageSummary(JSContext* cx, size_t* length); +JS_FRIEND_API char* GetCodeCoverageSummary(JSContext* cx, size_t* length); -typedef void -(* ActivityCallback)(void* arg, bool active); +typedef void (*ActivityCallback)(void* arg, bool active); /** * Sets a callback that is run whenever the runtime goes idle - the * last active request ceases - and begins activity - when it was * idle and a request begins. */ -JS_FRIEND_API(void) -SetActivityCallback(JSContext* cx, ActivityCallback cb, void* arg); +JS_FRIEND_API void SetActivityCallback(JSContext* cx, ActivityCallback cb, + void* arg); -typedef bool -(* DOMInstanceClassHasProtoAtDepth)(const Class* instanceClass, - uint32_t protoID, uint32_t depth); +typedef bool (*DOMInstanceClassHasProtoAtDepth)(const Class* instanceClass, + uint32_t protoID, + uint32_t depth); struct JSDOMCallbacks { - DOMInstanceClassHasProtoAtDepth instanceClassMatchesProto; + DOMInstanceClassHasProtoAtDepth instanceClassMatchesProto; }; typedef struct JSDOMCallbacks DOMCallbacks; -extern JS_FRIEND_API(void) -SetDOMCallbacks(JSContext* cx, const DOMCallbacks* callbacks); +extern JS_FRIEND_API void SetDOMCallbacks(JSContext* cx, + const DOMCallbacks* callbacks); -extern JS_FRIEND_API(const DOMCallbacks*) -GetDOMCallbacks(JSContext* cx); +extern JS_FRIEND_API const DOMCallbacks* GetDOMCallbacks(JSContext* cx); -extern JS_FRIEND_API(JSObject*) -GetTestingFunctions(JSContext* cx); +extern JS_FRIEND_API JSObject* GetTestingFunctions(JSContext* cx); /** * Helper to convert FreeOp to JSFreeOp when the definition of FreeOp is not * available and the compiler does not know that FreeOp inherits from * JSFreeOp. */ -inline JSFreeOp* -CastToJSFreeOp(FreeOp* fop) -{ - return reinterpret_cast(fop); +inline JSFreeOp* CastToJSFreeOp(FreeOp* fop) { + return reinterpret_cast(fop); } /* Implemented in jsexn.cpp. */ @@ -1146,67 +1113,69 @@ * Get an error type name from a JSExnType constant. * Returns nullptr for invalid arguments and JSEXN_INTERNALERR */ -extern JS_FRIEND_API(JSFlatString*) -GetErrorTypeName(JSContext* cx, int16_t exnType); +extern JS_FRIEND_API JSFlatString* GetErrorTypeName(JSContext* cx, + int16_t exnType); #ifdef JS_DEBUG -extern JS_FRIEND_API(unsigned) -GetEnterCompartmentDepth(JSContext* cx); +extern JS_FRIEND_API unsigned GetEnterCompartmentDepth(JSContext* cx); #endif -class RegExpGuard; -extern JS_FRIEND_API(bool) -RegExpToSharedNonInline(JSContext* cx, JS::HandleObject regexp, RegExpGuard* shared); +extern JS_FRIEND_API RegExpShared* RegExpToSharedNonInline( + JSContext* cx, JS::HandleObject regexp); -/* Implemented in jswrapper.cpp. */ +/* Implemented in CrossCompartmentWrapper.cpp. */ typedef enum NukeReferencesToWindow { - NukeWindowReferences, - DontNukeWindowReferences + NukeWindowReferences, + DontNukeWindowReferences } NukeReferencesToWindow; +typedef enum NukeReferencesFromTarget { + NukeAllReferences, + NukeIncomingReferences, +} NukeReferencesFromTarget; + /* * These filters are designed to be ephemeral stack classes, and thus don't * do any rooting or holding of their members. */ struct CompartmentFilter { - virtual bool match(JSCompartment* c) const = 0; + virtual bool match(JSCompartment* c) const = 0; }; struct AllCompartments : public CompartmentFilter { - virtual bool match(JSCompartment* c) const override { return true; } + virtual bool match(JSCompartment* c) const override { return true; } }; struct ContentCompartmentsOnly : public CompartmentFilter { - virtual bool match(JSCompartment* c) const override { - return !IsSystemCompartment(c); - } + virtual bool match(JSCompartment* c) const override { + return !IsSystemCompartment(c); + } }; struct ChromeCompartmentsOnly : public CompartmentFilter { - virtual bool match(JSCompartment* c) const override { - return IsSystemCompartment(c); - } + virtual bool match(JSCompartment* c) const override { + return IsSystemCompartment(c); + } }; struct SingleCompartment : public CompartmentFilter { - JSCompartment* ours; - explicit SingleCompartment(JSCompartment* c) : ours(c) {} - virtual bool match(JSCompartment* c) const override { return c == ours; } + JSCompartment* ours; + explicit SingleCompartment(JSCompartment* c) : ours(c) {} + virtual bool match(JSCompartment* c) const override { return c == ours; } }; struct CompartmentsWithPrincipals : public CompartmentFilter { - JSPrincipals* principals; - explicit CompartmentsWithPrincipals(JSPrincipals* p) : principals(p) {} - virtual bool match(JSCompartment* c) const override { - return JS_GetCompartmentPrincipals(c) == principals; - } + JSPrincipals* principals; + explicit CompartmentsWithPrincipals(JSPrincipals* p) : principals(p) {} + virtual bool match(JSCompartment* c) const override { + return JS_GetCompartmentPrincipals(c) == principals; + } }; -extern JS_FRIEND_API(bool) -NukeCrossCompartmentWrappers(JSContext* cx, - const CompartmentFilter& sourceFilter, - const CompartmentFilter& targetFilter, - NukeReferencesToWindow nukeReferencesToWindow); +extern JS_FRIEND_API bool NukeCrossCompartmentWrappers( + JSContext* cx, const CompartmentFilter& sourceFilter, JSCompartment* target, + NukeReferencesToWindow nukeReferencesToWindow, + NukeReferencesFromTarget nukeReferencesFromTarget); /* Specify information about DOMProxy proxies in the DOM, for use by ICs. */ @@ -1234,24 +1203,16 @@ */ struct ExpandoAndGeneration { - ExpandoAndGeneration() - : expando(JS::UndefinedValue()), - generation(0) - {} + ExpandoAndGeneration() : expando(JS::UndefinedValue()), generation(0) {} - void OwnerUnlinked() - { - ++generation; - } + void OwnerUnlinked() { ++generation; } - static size_t offsetOfExpando() - { - return offsetof(ExpandoAndGeneration, expando); + static size_t offsetOfExpando() { + return offsetof(ExpandoAndGeneration, expando); } - static size_t offsetOfGeneration() - { - return offsetof(ExpandoAndGeneration, generation); + static size_t offsetOfGeneration() { + return offsetof(ExpandoAndGeneration, generation); } JS::Heap expando; @@ -1266,50 +1227,71 @@ ShadowsViaDirectExpando, ShadowsViaIndirectExpando } DOMProxyShadowsResult; -typedef DOMProxyShadowsResult -(* DOMProxyShadowsCheck)(JSContext* cx, JS::HandleObject object, JS::HandleId id); -JS_FRIEND_API(void) -SetDOMProxyInformation(const void* domProxyHandlerFamily, uint32_t domProxyExpandoSlot, - DOMProxyShadowsCheck domProxyShadowsCheck); +typedef DOMProxyShadowsResult (*DOMProxyShadowsCheck)(JSContext* cx, + JS::HandleObject object, + JS::HandleId id); +JS_FRIEND_API void SetDOMProxyInformation( + const void* domProxyHandlerFamily, + DOMProxyShadowsCheck domProxyShadowsCheck); const void* GetDOMProxyHandlerFamily(); -uint32_t GetDOMProxyExpandoSlot(); DOMProxyShadowsCheck GetDOMProxyShadowsCheck(); inline bool DOMProxyIsShadowing(DOMProxyShadowsResult result) { - return result == Shadows || - result == ShadowsViaDirectExpando || - result == ShadowsViaIndirectExpando; + return result == Shadows || result == ShadowsViaDirectExpando || + result == ShadowsViaIndirectExpando; } +// Callbacks and other information for use by the JITs when optimizing accesses +// on xray wrappers. +struct XrayJitInfo { + // Test whether a proxy handler is a cross compartment xray with no + // security checks. + bool (*isCrossCompartmentXray)(const BaseProxyHandler* handler); + + // Test whether xrays with a global object's compartment have expandos of + // their own, instead of sharing them with Xrays from other compartments. + bool (*globalHasExclusiveExpandos)(JSObject* obj); + + // Proxy reserved slot used by xrays in sandboxes to store their holder + // object. + size_t xrayHolderSlot; + + // Reserved slot used by xray holders to store the xray's expando object. + size_t holderExpandoSlot; + + // Reserved slot used by xray expandos to store a custom prototype. + size_t expandoProtoSlot; +}; + +JS_FRIEND_API void SetXrayJitInfo(XrayJitInfo* info); + +XrayJitInfo* GetXrayJitInfo(); + /* Implemented in jsdate.cpp. */ /** Detect whether the internal date value is NaN. */ -extern JS_FRIEND_API(bool) -DateIsValid(JSContext* cx, JS::HandleObject obj, bool* isValid); +extern JS_FRIEND_API bool DateIsValid(JSContext* cx, JS::HandleObject obj, + bool* isValid); -extern JS_FRIEND_API(bool) -DateGetMsecSinceEpoch(JSContext* cx, JS::HandleObject obj, double* msecSinceEpoch); +extern JS_FRIEND_API bool DateGetMsecSinceEpoch(JSContext* cx, + JS::HandleObject obj, + double* msecSinceEpoch); } /* namespace js */ -/* Implemented in jscntxt.cpp. */ - -/** - * Report an exception, which is currently realized as a printf-style format - * string and its arguments. - */ typedef enum JSErrNum { -#define MSG_DEF(name, count, exception, format) \ - name, +#define MSG_DEF(name, count, exception, format) name, #include "js.msg" #undef MSG_DEF - JSErr_Limit + JSErr_Limit } JSErrNum; namespace js { -extern JS_FRIEND_API(const JSErrorFormatString*) -GetErrorMessage(void* userRef, const unsigned errorNumber); +/* Implemented in vm/JSContext.cpp. */ + +extern JS_FRIEND_API const JSErrorFormatString* GetErrorMessage( + void* userRef, const unsigned errorNumber); // AutoStableStringChars is here so we can use it in ErrorReport. It // should get moved out of here if we can manage it. See bug 1040316. @@ -1323,171 +1305,163 @@ * 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 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_; - - public: - explicit AutoStableStringChars(JSContext* cx) - : s_(cx), state_(Uninitialized) - {} - - MOZ_MUST_USE - bool init(JSContext* cx, JSString* s); - - /* Like init(), but Latin1 chars are inflated to TwoByte. */ - MOZ_MUST_USE - bool initTwoByte(JSContext* cx, JSString* s); - - bool isLatin1() const { return state_ == Latin1; } - bool isTwoByte() const { return state_ == TwoByte; } - - const char16_t* twoByteChars() const { - MOZ_ASSERT(state_ == TwoByte); - return twoByteChars_; - } - - mozilla::Range latin1Range() const { - MOZ_ASSERT(state_ == Latin1); - return mozilla::Range(latin1Chars_, - GetStringLength(s_)); - } - - mozilla::Range twoByteRange() const { - MOZ_ASSERT(state_ == TwoByte); - return mozilla::Range(twoByteChars_, - GetStringLength(s_)); - } - - /* If we own the chars, transfer ownership to the caller. */ - bool maybeGiveOwnershipToCaller() { - MOZ_ASSERT(state_ != Uninitialized); - if (!ownChars_.isSome() || !ownChars_->extractRawBuffer()) - return false; - state_ = Uninitialized; - ownChars_.reset(); - return true; - } - - private: - AutoStableStringChars(const AutoStableStringChars& other) = delete; - void operator=(const AutoStableStringChars& other) = delete; - - 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(); - - enum SniffingBehavior { - WithSideEffects, - NoSideEffects - }; +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_; + + public: + explicit AutoStableStringChars(JSContext* cx) + : s_(cx), state_(Uninitialized) {} + + MOZ_MUST_USE + bool init(JSContext* cx, JSString* s); + + /* Like init(), but Latin1 chars are inflated to TwoByte. */ + MOZ_MUST_USE + bool initTwoByte(JSContext* cx, JSString* s); + + bool isLatin1() const { return state_ == Latin1; } + bool isTwoByte() const { return state_ == TwoByte; } + + const JS::Latin1Char* latin1Chars() const { + MOZ_ASSERT(state_ == Latin1); + return latin1Chars_; + } + const char16_t* twoByteChars() const { + MOZ_ASSERT(state_ == TwoByte); + return twoByteChars_; + } - /** - * 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); + mozilla::Range latin1Range() const { + MOZ_ASSERT(state_ == Latin1); + return mozilla::Range(latin1Chars_, + GetStringLength(s_)); + } - JSErrorReport* report() - { - return reportp; - } + mozilla::Range twoByteRange() const { + MOZ_ASSERT(state_ == TwoByte); + return mozilla::Range(twoByteChars_, GetStringLength(s_)); + } - const JS::ConstUTF8CharsZ toStringResult() - { - return toStringResult_; - } + /* If we own the chars, transfer ownership to the caller. */ + bool maybeGiveOwnershipToCaller() { + MOZ_ASSERT(state_ != Uninitialized); + if (!ownChars_.isSome() || !ownChars_->extractRawBuffer()) return false; + state_ = Uninitialized; + ownChars_.reset(); + return true; + } - private: - // More or less an equivalent of JS_ReportErrorNumber/js::ReportErrorNumberVA - // but fills in an ErrorReport instead of reporting it. Uses varargs to - // make it simpler to call js::ExpandErrorArgumentsVA. - // - // Returns false if we fail to actually populate the ErrorReport - // for some reason (probably out of memory). - bool populateUncaughtExceptionReportUTF8(JSContext* cx, ...); - bool populateUncaughtExceptionReportUTF8VA(JSContext* cx, va_list ap); - - // Reports exceptions from add-on scopes to telementry. - void ReportAddonExceptionToTelementry(JSContext* cx); - - // We may have a provided JSErrorReport, so need a way to represent that. - JSErrorReport* reportp; - - // Or we may need to synthesize a JSErrorReport one of our own. - JSErrorReport ownedReport; - - // And we have a string to maybe keep alive that has pointers into - // it from ownedReport. - JS::RootedString str; - - // And keep its chars alive too. - AutoStableStringChars strChars; - - // And we need to root our exception value. - JS::RootedObject exnObject; - - // And for our filename. - JSAutoByteString filename; - - // 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; + private: + AutoStableStringChars(const AutoStableStringChars& other) = delete; + void operator=(const AutoStableStringChars& other) = delete; + + 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(); + + 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 JS::ConstUTF8CharsZ toStringResult() { return toStringResult_; } + + private: + // More or less an equivalent of JS_ReportErrorNumber/js::ReportErrorNumberVA + // but fills in an ErrorReport instead of reporting it. Uses varargs to + // make it simpler to call js::ExpandErrorArgumentsVA. + // + // Returns false if we fail to actually populate the ErrorReport + // for some reason (probably out of memory). + bool populateUncaughtExceptionReportUTF8(JSContext* cx, ...); + bool populateUncaughtExceptionReportUTF8VA(JSContext* cx, va_list ap); + + // Reports exceptions from add-on scopes to telemetry. + void ReportAddonExceptionToTelemetry(JSContext* cx); + + // We may have a provided JSErrorReport, so need a way to represent that. + JSErrorReport* reportp; + + // Or we may need to synthesize a JSErrorReport one of our own. + JSErrorReport ownedReport; + + // And we have a string to maybe keep alive that has pointers into + // it from ownedReport. + JS::RootedString str; + + // And keep its chars alive too. + AutoStableStringChars strChars; + + // And we need to root our exception value. + JS::RootedObject exnObject; + + // And for our filename. + JSAutoByteString filename; + + // 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. */ -extern JS_FRIEND_API(uint64_t) -GetSCOffset(JSStructuredCloneWriter* writer); +extern JS_FRIEND_API uint64_t GetSCOffset(JSStructuredCloneWriter* writer); namespace Scalar { @@ -1498,134 +1472,129 @@ * definitions. */ enum Type { - Int8 = 0, - Uint8, - Int16, - Uint16, - Int32, - Uint32, - Float32, - Float64, - - /** - * Special type that is a uint8_t, but assignments are clamped to [0, 256). - * Treat the raw data type as a uint8_t. - */ - Uint8Clamped, - - /** - * Types that don't have their own TypedArray equivalent, for now. - */ - MaxTypedArrayViewType, - - Int64, - Float32x4, - Int8x16, - Int16x8, - Int32x4 -}; - -static inline size_t -byteSize(Type atype) -{ - switch (atype) { - case Int8: - case Uint8: - case Uint8Clamped: - return 1; - case Int16: - case Uint16: - return 2; - case Int32: - case Uint32: - case Float32: - return 4; - case Int64: - case Float64: - return 8; - case Int8x16: - case Int16x8: - case Int32x4: - case Float32x4: - return 16; - default: - MOZ_CRASH("invalid scalar type"); - } + Int8 = 0, + Uint8, + Int16, + Uint16, + Int32, + Uint32, + Float32, + Float64, + + /** + * Special type that is a uint8_t, but assignments are clamped to [0, 256). + * Treat the raw data type as a uint8_t. + */ + Uint8Clamped, + + /** + * Types that don't have their own TypedArray equivalent, for now. + */ + MaxTypedArrayViewType, + + Int64, + Float32x4, + Int8x16, + Int16x8, + Int32x4 +}; + +static inline size_t byteSize(Type atype) { + switch (atype) { + case Int8: + case Uint8: + case Uint8Clamped: + return 1; + case Int16: + case Uint16: + return 2; + case Int32: + case Uint32: + case Float32: + return 4; + case Int64: + case Float64: + return 8; + case Int8x16: + case Int16x8: + case Int32x4: + case Float32x4: + return 16; + default: + MOZ_CRASH("invalid scalar type"); + } } -static inline bool -isSignedIntType(Type atype) { - switch (atype) { - case Int8: - case Int16: - case Int32: - case Int64: - case Int8x16: - case Int16x8: - case Int32x4: - return true; - case Uint8: - case Uint8Clamped: - case Uint16: - case Uint32: - case Float32: - case Float64: - case Float32x4: - return false; - default: - MOZ_CRASH("invalid scalar type"); - } +static inline bool isSignedIntType(Type atype) { + switch (atype) { + case Int8: + case Int16: + case Int32: + case Int64: + case Int8x16: + case Int16x8: + case Int32x4: + return true; + case Uint8: + case Uint8Clamped: + case Uint16: + case Uint32: + case Float32: + case Float64: + case Float32x4: + return false; + default: + MOZ_CRASH("invalid scalar type"); + } } -static inline bool -isSimdType(Type atype) { - switch (atype) { - case Int8: - case Uint8: - case Uint8Clamped: - case Int16: - case Uint16: - case Int32: - case Uint32: - case Int64: - case Float32: - case Float64: - return false; - case Int8x16: - case Int16x8: - case Int32x4: - case Float32x4: - return true; - case MaxTypedArrayViewType: - break; - } - MOZ_CRASH("invalid scalar type"); +static inline bool isSimdType(Type atype) { + switch (atype) { + case Int8: + case Uint8: + case Uint8Clamped: + case Int16: + case Uint16: + case Int32: + case Uint32: + case Int64: + case Float32: + case Float64: + return false; + case Int8x16: + case Int16x8: + case Int32x4: + case Float32x4: + return true; + case MaxTypedArrayViewType: + break; + } + MOZ_CRASH("invalid scalar type"); } -static inline size_t -scalarByteSize(Type atype) { - switch (atype) { - case Int8x16: - return 1; - case Int16x8: - return 2; - case Int32x4: - case Float32x4: - return 4; - case Int8: - case Uint8: - case Uint8Clamped: - case Int16: - case Uint16: - case Int32: - case Uint32: - case Int64: - case Float32: - case Float64: - case MaxTypedArrayViewType: - break; - } - MOZ_CRASH("invalid simd type"); +static inline size_t scalarByteSize(Type atype) { + switch (atype) { + case Int8x16: + return 1; + case Int16x8: + return 2; + case Int32x4: + case Float32x4: + return 4; + case Int8: + case Uint8: + case Uint8Clamped: + case Int16: + case Uint16: + case Int32: + case Uint32: + case Int64: + case Float32: + case Float64: + case MaxTypedArrayViewType: + break; + } + MOZ_CRASH("invalid simd type"); } } /* namespace Scalar */ @@ -1634,27 +1603,28 @@ /* * Create a new typed array with nelements elements. * - * These functions (except the WithBuffer variants) fill in the array with zeros. + * These functions (except the WithBuffer variants) fill in the array with + * zeros. */ -extern JS_FRIEND_API(JSObject*) -JS_NewInt8Array(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewUint8Array(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewUint8ClampedArray(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewInt16Array(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewUint16Array(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewInt32Array(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewUint32Array(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewFloat32Array(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewFloat64Array(JSContext* cx, uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewInt8Array(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewUint8Array(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewUint8ClampedArray(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewInt16Array(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewUint16Array(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewInt32Array(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewUint32Array(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewFloat32Array(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewFloat64Array(JSContext* cx, + uint32_t nelements); /* * Create a new typed array and copy in values from the given object. The @@ -1664,24 +1634,24 @@ * conversion to the typed array element type. */ -extern JS_FRIEND_API(JSObject*) -JS_NewInt8ArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewUint8ArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewUint8ClampedArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewInt16ArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewUint16ArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewInt32ArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewUint32ArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewFloat32ArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewFloat64ArrayFromArray(JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewInt8ArrayFromArray(JSContext* cx, + JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewUint8ArrayFromArray( + JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewUint8ClampedArrayFromArray( + JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewInt16ArrayFromArray( + JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewUint16ArrayFromArray( + JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewInt32ArrayFromArray( + JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewUint32ArrayFromArray( + JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewFloat32ArrayFromArray( + JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewFloat64ArrayFromArray( + JSContext* cx, JS::HandleObject array); /* * Create a new typed array using the given ArrayBuffer or @@ -1690,33 +1660,33 @@ * array is used as the default value. */ -extern JS_FRIEND_API(JSObject*) -JS_NewInt8ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewUint8ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewUint8ClampedArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewInt16ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewUint16ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewInt32ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewUint32ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewFloat32ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewFloat64ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); +extern JS_FRIEND_API JSObject* JS_NewInt8ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewUint8ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewUint8ClampedArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewInt16ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewUint16ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewInt32ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewUint32ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewFloat32ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewFloat64ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); /** * Create a new SharedArrayBuffer with the given byte length. This @@ -1724,14 +1694,14 @@ * JS::CompartmentCreationOptionsRef(cx).getSharedMemoryAndAtomicsEnabled() is * true. */ -extern JS_FRIEND_API(JSObject*) -JS_NewSharedArrayBuffer(JSContext* cx, uint32_t nbytes); +extern JS_FRIEND_API JSObject* JS_NewSharedArrayBuffer(JSContext* cx, + uint32_t nbytes); /** * Create a new ArrayBuffer with the given byte length. */ -extern JS_FRIEND_API(JSObject*) -JS_NewArrayBuffer(JSContext* cx, uint32_t nbytes); +extern JS_FRIEND_API JSObject* JS_NewArrayBuffer(JSContext* cx, + uint32_t nbytes); /** * Check whether obj supports JS_GetTypedArray* APIs. Note that this may return @@ -1739,8 +1709,7 @@ * this test or one of the JS_Is*Array tests succeeds, then it is safe to call * the various accessor JSAPI calls defined below. */ -extern JS_FRIEND_API(bool) -JS_IsTypedArrayObject(JSObject* obj); +extern JS_FRIEND_API bool JS_IsTypedArrayObject(JSObject* obj); /** * Check whether obj supports JS_GetArrayBufferView* APIs. Note that this may @@ -1749,31 +1718,21 @@ * is safe to call the various ArrayBufferView accessor JSAPI calls defined * below. */ -extern JS_FRIEND_API(bool) -JS_IsArrayBufferViewObject(JSObject* obj); +extern JS_FRIEND_API bool JS_IsArrayBufferViewObject(JSObject* obj); /* * Test for specific typed array types (ArrayBufferView subtypes) */ -extern JS_FRIEND_API(bool) -JS_IsInt8Array(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsUint8Array(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsUint8ClampedArray(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsInt16Array(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsUint16Array(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsInt32Array(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsUint32Array(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsFloat32Array(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsFloat64Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsInt8Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsUint8Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsUint8ClampedArray(JSObject* obj); +extern JS_FRIEND_API bool JS_IsInt16Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsUint16Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsInt32Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsUint32Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsFloat32Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsFloat64Array(JSObject* obj); /** * Return the isShared flag of a typed array, which denotes whether @@ -1783,8 +1742,7 @@ * be known that it would pass such a test: it is a typed array or a wrapper of * a typed array, and the unwrapping will succeed. */ -extern JS_FRIEND_API(bool) -JS_GetTypedArraySharedness(JSObject* obj); +extern JS_FRIEND_API bool JS_GetTypedArraySharedness(JSObject* obj); /* * Test for specific typed array types (ArrayBufferView subtypes) and return @@ -1793,61 +1751,50 @@ namespace js { -extern JS_FRIEND_API(JSObject*) -UnwrapInt8Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapUint8Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapUint8ClampedArray(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapInt16Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapUint16Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapInt32Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapUint32Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapFloat32Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapFloat64Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapInt8Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapUint8Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapUint8ClampedArray(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapInt16Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapUint16Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapInt32Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapUint32Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapFloat32Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapFloat64Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapArrayBuffer(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapArrayBuffer(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapArrayBufferView(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapArrayBufferView(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapSharedArrayBuffer(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapSharedArrayBuffer(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapReadableStream(JSObject* obj); namespace detail { -extern JS_FRIEND_DATA(const Class* const) Int8ArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Uint8ArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Uint8ClampedArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Int16ArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Uint16ArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Int32ArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Uint32ArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Float32ArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Float64ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Int8ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Uint8ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Uint8ClampedArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Int16ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Uint16ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Int32ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Uint32ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Float32ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Float64ArrayClassPtr; const size_t TypedArrayLengthSlot = 1; -} // namespace detail +} // namespace detail -#define JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Type, type) \ -inline void \ -Get ## Type ## ArrayLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, type** data) \ -{ \ - MOZ_ASSERT(GetObjectClass(obj) == detail::Type ## ArrayClassPtr); \ - const JS::Value& lenSlot = GetReservedSlot(obj, detail::TypedArrayLengthSlot); \ - *length = mozilla::AssertedCast(lenSlot.toInt32()); \ - *isSharedMemory = JS_GetTypedArraySharedness(obj); \ - *data = static_cast(GetObjectPrivate(obj)); \ -} +#define JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Type, type) \ + inline void Get##Type##ArrayLengthAndData( \ + JSObject* obj, uint32_t* length, bool* isSharedMemory, type** data) { \ + MOZ_ASSERT(GetObjectClass(obj) == detail::Type##ArrayClassPtr); \ + const JS::Value& lenSlot = \ + GetReservedSlot(obj, detail::TypedArrayLengthSlot); \ + *length = mozilla::AssertedCast(lenSlot.toInt32()); \ + *isSharedMemory = JS_GetTypedArraySharedness(obj); \ + *data = static_cast(GetObjectPrivate(obj)); \ + } JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int8, int8_t) JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8, uint8_t) @@ -1863,73 +1810,95 @@ // This one isn't inlined because it's rather tricky (by dint of having to deal // with a dozen-plus classes and varying slot layouts. -extern JS_FRIEND_API(void) -GetArrayBufferViewLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); +extern JS_FRIEND_API void GetArrayBufferViewLengthAndData(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + uint8_t** data); // This one isn't inlined because there are a bunch of different ArrayBuffer // classes that would have to be individually handled here. // // There is an isShared out argument for API consistency (eases use from DOM). // It will always be set to false. -extern JS_FRIEND_API(void) -GetArrayBufferLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); +extern JS_FRIEND_API void GetArrayBufferLengthAndData(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + uint8_t** data); // Ditto for SharedArrayBuffer. // // There is an isShared out argument for API consistency (eases use from DOM). // It will always be set to true. -extern JS_FRIEND_API(void) -GetSharedArrayBufferLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); +extern JS_FRIEND_API void GetSharedArrayBufferLengthAndData( + JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); -} // namespace js +} // namespace js -JS_FRIEND_API(uint8_t*) -JS_GetSharedArrayBufferData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); +JS_FRIEND_API uint8_t* JS_GetSharedArrayBufferData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); /* * Unwrap Typed arrays all at once. Return nullptr without throwing if the * object cannot be viewed as the correct typed array, or the typed array * object on success, filling both outparameters. */ -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsInt8Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, int8_t** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsUint8Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsUint8ClampedArray(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsInt16Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, int16_t** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsUint16Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint16_t** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsInt32Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, int32_t** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsUint32Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint32_t** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsFloat32Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, float** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsFloat64Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, double** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsArrayBufferView(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsInt8Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + int8_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsUint8Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + uint8_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsUint8ClampedArray( + JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsInt16Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + int16_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsUint16Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + uint16_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsInt32Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + int32_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsUint32Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + uint32_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsFloat32Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + float** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsFloat64Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + double** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsArrayBufferView( + JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); /* * Unwrap an ArrayBuffer, return nullptr if it's a different type. */ -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsArrayBuffer(JSObject* obj, uint32_t* length, uint8_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsArrayBuffer(JSObject* obj, + uint32_t* length, + uint8_t** data); /* - * Get the type of elements in a typed array, or MaxTypedArrayViewType if a DataView. + * Get the type of elements in a typed array, or MaxTypedArrayViewType if a + * DataView. * * |obj| must have passed a JS_IsArrayBufferView/JS_Is*Array test, or somehow * be known that it would pass such a test: it is an ArrayBufferView or a * wrapper of an ArrayBufferView, and the unwrapping will succeed. */ -extern JS_FRIEND_API(js::Scalar::Type) -JS_GetArrayBufferViewType(JSObject* obj); +extern JS_FRIEND_API js::Scalar::Type JS_GetArrayBufferViewType(JSObject* obj); -extern JS_FRIEND_API(js::Scalar::Type) -JS_GetSharedArrayBufferViewType(JSObject* obj); +extern JS_FRIEND_API js::Scalar::Type JS_GetSharedArrayBufferViewType( + JSObject* obj); /* * Check whether obj supports the JS_GetArrayBuffer* APIs. Note that this may @@ -1937,11 +1906,9 @@ * unwrapping. If this test succeeds, then it is safe to call the various * accessor JSAPI calls defined below. */ -extern JS_FRIEND_API(bool) -JS_IsArrayBufferObject(JSObject* obj); +extern JS_FRIEND_API bool JS_IsArrayBufferObject(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsSharedArrayBufferObject(JSObject* obj); +extern JS_FRIEND_API bool JS_IsSharedArrayBufferObject(JSObject* obj); /** * Return the available byte length of an array buffer. @@ -1950,11 +1917,9 @@ * that it would pass such a test: it is an ArrayBuffer or a wrapper of an * ArrayBuffer, and the unwrapping will succeed. */ -extern JS_FRIEND_API(uint32_t) -JS_GetArrayBufferByteLength(JSObject* obj); +extern JS_FRIEND_API uint32_t JS_GetArrayBufferByteLength(JSObject* obj); -extern JS_FRIEND_API(uint32_t) -JS_GetSharedArrayBufferByteLength(JSObject* obj); +extern JS_FRIEND_API uint32_t JS_GetSharedArrayBufferByteLength(JSObject* obj); /** * Return true if the arrayBuffer contains any data. This will return false for @@ -1964,8 +1929,7 @@ * that it would pass such a test: it is an ArrayBuffer or a wrapper of an * ArrayBuffer, and the unwrapping will succeed. */ -extern JS_FRIEND_API(bool) -JS_ArrayBufferHasData(JSObject* obj); +extern JS_FRIEND_API bool JS_ArrayBufferHasData(JSObject* obj); /** * Return a pointer to the start of the data referenced by a typed array. The @@ -1978,19 +1942,19 @@ * that it would pass such a test: it is an ArrayBuffer or a wrapper of an * ArrayBuffer, and the unwrapping will succeed. * - * *isSharedMemory will be set to false, the argument is present to simplify + * |*isSharedMemory| will be set to false, the argument is present to simplify * its use from code that also interacts with SharedArrayBuffer. */ -extern JS_FRIEND_API(uint8_t*) -JS_GetArrayBufferData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API uint8_t* JS_GetArrayBufferData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); /** * Check whether the obj is ArrayBufferObject and memory mapped. Note that this * may return false if a security wrapper is encountered that denies the * unwrapping. */ -extern JS_FRIEND_API(bool) -JS_IsMappedArrayBufferObject(JSObject* obj); +extern JS_FRIEND_API bool JS_IsMappedArrayBufferObject(JSObject* obj); /** * Return the number of elements in a typed array. @@ -1999,8 +1963,7 @@ * be known that it would pass such a test: it is a typed array or a wrapper of * a typed array, and the unwrapping will succeed. */ -extern JS_FRIEND_API(uint32_t) -JS_GetTypedArrayLength(JSObject* obj); +extern JS_FRIEND_API uint32_t JS_GetTypedArrayLength(JSObject* obj); /** * Return the byte offset from the start of an array buffer to the start of a @@ -2010,8 +1973,7 @@ * be known that it would pass such a test: it is a typed array or a wrapper of * a typed array, and the unwrapping will succeed. */ -extern JS_FRIEND_API(uint32_t) -JS_GetTypedArrayByteOffset(JSObject* obj); +extern JS_FRIEND_API uint32_t JS_GetTypedArrayByteOffset(JSObject* obj); /** * Return the byte length of a typed array. @@ -2020,22 +1982,24 @@ * be known that it would pass such a test: it is a typed array or a wrapper of * a typed array, and the unwrapping will succeed. */ -extern JS_FRIEND_API(uint32_t) -JS_GetTypedArrayByteLength(JSObject* obj); +extern JS_FRIEND_API uint32_t JS_GetTypedArrayByteLength(JSObject* obj); /** * Check whether obj supports JS_ArrayBufferView* APIs. Note that this may * return false if a security wrapper is encountered that denies the * unwrapping. */ -extern JS_FRIEND_API(bool) -JS_IsArrayBufferViewObject(JSObject* obj); +extern JS_FRIEND_API bool JS_IsArrayBufferViewObject(JSObject* obj); /** * More generic name for JS_GetTypedArrayByteLength to cover DataViews as well */ -extern JS_FRIEND_API(uint32_t) -JS_GetArrayBufferViewByteLength(JSObject* obj); +extern JS_FRIEND_API uint32_t JS_GetArrayBufferViewByteLength(JSObject* obj); + +/** + * More generic name for JS_GetTypedArrayByteOffset to cover DataViews as well + */ +extern JS_FRIEND_API uint32_t JS_GetArrayBufferViewByteOffset(JSObject* obj); /* * Return a pointer to the start of the data referenced by a typed array. The @@ -2048,43 +2012,49 @@ * pass such a test: it is a typed array or a wrapper of a typed array, and the * unwrapping will succeed. * - * *isSharedMemory will be set to true if the typed array maps a + * |*isSharedMemory| will be set to true if the typed array maps a * SharedArrayBuffer, otherwise to false. */ -extern JS_FRIEND_API(int8_t*) -JS_GetInt8ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(uint8_t*) -JS_GetUint8ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(uint8_t*) -JS_GetUint8ClampedArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(int16_t*) -JS_GetInt16ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(uint16_t*) -JS_GetUint16ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(int32_t*) -JS_GetInt32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(uint32_t*) -JS_GetUint32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(float*) -JS_GetFloat32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(double*) -JS_GetFloat64ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API int8_t* JS_GetInt8ArrayData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); +extern JS_FRIEND_API uint8_t* JS_GetUint8ArrayData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); +extern JS_FRIEND_API uint8_t* JS_GetUint8ClampedArrayData( + JSObject* obj, bool* isSharedMemory, const JS::AutoRequireNoGC&); +extern JS_FRIEND_API int16_t* JS_GetInt16ArrayData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); +extern JS_FRIEND_API uint16_t* JS_GetUint16ArrayData( + JSObject* obj, bool* isSharedMemory, const JS::AutoRequireNoGC&); +extern JS_FRIEND_API int32_t* JS_GetInt32ArrayData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); +extern JS_FRIEND_API uint32_t* JS_GetUint32ArrayData( + JSObject* obj, bool* isSharedMemory, const JS::AutoRequireNoGC&); +extern JS_FRIEND_API float* JS_GetFloat32ArrayData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); +extern JS_FRIEND_API double* JS_GetFloat64ArrayData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); /** * Same as above, but for any kind of ArrayBufferView. Prefer the type-specific * versions when possible. */ -extern JS_FRIEND_API(void*) -JS_GetArrayBufferViewData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API void* JS_GetArrayBufferViewData( + JSObject* obj, bool* isSharedMemory, const JS::AutoRequireNoGC&); /** * 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); +extern JS_FRIEND_API JSObject* JS_GetArrayBufferViewBuffer( + JSContext* cx, JS::HandleObject obj, bool* isSharedMemory); /** * Detach an ArrayBuffer, causing all associated views to no longer refer to @@ -2092,32 +2062,30 @@ * * The |changeData| argument is obsolete and ignored. */ -extern JS_FRIEND_API(bool) -JS_DetachArrayBuffer(JSContext* cx, JS::HandleObject obj); +extern JS_FRIEND_API bool JS_DetachArrayBuffer(JSContext* cx, + JS::HandleObject obj); /** * 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_IsDetachedArrayBufferObject(JSObject* obj); +extern JS_FRIEND_API bool JS_IsDetachedArrayBufferObject(JSObject* obj); /** * Check whether obj supports JS_GetDataView* APIs. */ -JS_FRIEND_API(bool) -JS_IsDataViewObject(JSObject* obj); +JS_FRIEND_API bool JS_IsDataViewObject(JSObject* obj); /** - * Create a new DataView using the given ArrayBuffer for storage. The given - * buffer must be an ArrayBuffer (or a cross-compartment wrapper of an - * ArrayBuffer), and the offset and length must fit within the bounds of the - * arrayBuffer. Currently, nullptr will be returned and an exception will be - * thrown if these conditions do not hold, but do not depend on that behavior. + * Create a new DataView using the given buffer for storage. The given buffer + * must be an ArrayBuffer or SharedArrayBuffer (or a cross-compartment wrapper + * of either type), and the offset and length must fit within the bounds of the + * buffer. Currently, nullptr will be returned and an exception will be thrown + * if these conditions do not hold, but do not depend on that behavior. */ -JS_FRIEND_API(JSObject*) -JS_NewDataView(JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, int32_t byteLength); +JS_FRIEND_API JSObject* JS_NewDataView(JSContext* cx, JS::HandleObject buffer, + uint32_t byteOffset, int32_t byteLength); /** * Return the byte offset of a data view into its array buffer. |obj| must be a @@ -2127,8 +2095,7 @@ * it would pass such a test: it is a data view or a wrapper of a data view, * and the unwrapping will succeed. */ -JS_FRIEND_API(uint32_t) -JS_GetDataViewByteOffset(JSObject* obj); +JS_FRIEND_API uint32_t JS_GetDataViewByteOffset(JSObject* obj); /** * Return the byte length of a data view. @@ -2138,8 +2105,7 @@ * and the unwrapping will succeed. If cx is nullptr, then DEBUG builds may be * unable to assert when unwrapping should be disallowed. */ -JS_FRIEND_API(uint32_t) -JS_GetDataViewByteLength(JSObject* obj); +JS_FRIEND_API uint32_t JS_GetDataViewByteLength(JSObject* obj); /** * Return a pointer to the beginning of the data referenced by a DataView. @@ -2148,82 +2114,53 @@ * it would pass such a test: it is a data view or a wrapper of a data view, * and the unwrapping will succeed. If cx is nullptr, then DEBUG builds may be * unable to assert when unwrapping should be disallowed. - */ -JS_FRIEND_API(void*) -JS_GetDataViewData(JSObject* obj, const JS::AutoCheckCannotGC&); - -namespace js { - -/** - * Add a watchpoint -- in the Object.prototype.watch sense -- to |obj| for the - * property |id|, using the callable object |callable| as the function to be - * called for notifications. - * - * This is an internal function exposed -- temporarily -- only so that DOM - * proxies can be watchable. Don't use it! We'll soon kill off the - * Object.prototype.{,un}watch functions, at which point this will go too. - */ -extern JS_FRIEND_API(bool) -WatchGuts(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); - -/** - * Remove a watchpoint -- in the Object.prototype.watch sense -- from |obj| for - * the property |id|. * - * This is an internal function exposed -- temporarily -- only so that DOM - * proxies can be watchable. Don't use it! We'll soon kill off the - * Object.prototype.{,un}watch functions, at which point this will go too. + * |*isSharedMemory| will be set to true if the DataView maps a + * SharedArrayBuffer, otherwise to false. */ -extern JS_FRIEND_API(bool) -UnwatchGuts(JSContext* cx, JS::HandleObject obj, JS::HandleId id); +JS_FRIEND_API void* JS_GetDataViewData(JSObject* obj, bool* isSharedMemory, + const JS::AutoRequireNoGC&); +namespace js { namespace jit { enum class InlinableNative : uint16_t; -} // namespace jit - -} // namespace js +} // namespace jit +} // namespace js /** * A class, expected to be passed by value, which represents the CallArgs for a * JSJitGetterOp. */ -class JSJitGetterCallArgs : protected JS::MutableHandleValue -{ - public: - explicit JSJitGetterCallArgs(const JS::CallArgs& args) - : JS::MutableHandleValue(args.rval()) - {} - - explicit JSJitGetterCallArgs(JS::RootedValue* rooted) - : JS::MutableHandleValue(rooted) - {} +class JSJitGetterCallArgs : protected JS::MutableHandleValue { + public: + explicit JSJitGetterCallArgs(const JS::CallArgs& args) + : JS::MutableHandleValue(args.rval()) {} - JS::MutableHandleValue rval() { - return *this; - } + explicit JSJitGetterCallArgs(JS::RootedValue* rooted) + : JS::MutableHandleValue(rooted) {} + + JS::MutableHandleValue rval() { return *this; } }; /** * A class, expected to be passed by value, which represents the CallArgs for a * JSJitSetterOp. */ -class JSJitSetterCallArgs : protected JS::MutableHandleValue -{ - public: - explicit JSJitSetterCallArgs(const JS::CallArgs& args) - : JS::MutableHandleValue(args[0]) - {} - - JS::MutableHandleValue operator[](unsigned i) { - MOZ_ASSERT(i == 0); - return *this; - } +class JSJitSetterCallArgs : protected JS::MutableHandleValue { + public: + explicit JSJitSetterCallArgs(const JS::CallArgs& args) + : JS::MutableHandleValue(args[0]) {} + + JS::MutableHandleValue operator[](unsigned i) { + MOZ_ASSERT(i == 0); + return *this; + } - unsigned length() const { return 1; } + unsigned length() const { return 1; } - // Add get() or maybe hasDefined() as needed + // Add get() or maybe hasDefined() as needed }; struct JSJitMethodCallArgsTraits; @@ -2232,58 +2169,49 @@ * A class, expected to be passed by reference, which represents the CallArgs * for a JSJitMethodOp. */ -class JSJitMethodCallArgs : protected JS::detail::CallArgsBase -{ - private: - typedef JS::detail::CallArgsBase Base; - friend struct JSJitMethodCallArgsTraits; - - public: - explicit JSJitMethodCallArgs(const JS::CallArgs& args) { - argv_ = args.array(); - argc_ = args.length(); - } +class JSJitMethodCallArgs + : protected JS::detail::CallArgsBase { + private: + typedef JS::detail::CallArgsBase Base; + friend struct JSJitMethodCallArgsTraits; + + public: + explicit JSJitMethodCallArgs(const JS::CallArgs& args) { + argv_ = args.array(); + argc_ = args.length(); + } - JS::MutableHandleValue rval() const { - return Base::rval(); - } + JS::MutableHandleValue rval() const { return Base::rval(); } - unsigned length() const { return Base::length(); } + unsigned length() const { return Base::length(); } - JS::MutableHandleValue operator[](unsigned i) const { - return Base::operator[](i); - } + JS::MutableHandleValue operator[](unsigned i) const { + return Base::operator[](i); + } - bool hasDefined(unsigned i) const { - return Base::hasDefined(i); - } + bool hasDefined(unsigned i) const { return Base::hasDefined(i); } - JSObject& callee() const { - // We can't use Base::callee() because that will try to poke at - // this->usedRval_, which we don't have. - return argv_[-2].toObject(); - } + JSObject& callee() const { + // We can't use Base::callee() because that will try to poke at + // this->usedRval_, which we don't have. + return argv_[-2].toObject(); + } - JS::HandleValue get(unsigned i) const { - return Base::get(i); - } + JS::HandleValue get(unsigned i) const { return Base::get(i); } }; -struct JSJitMethodCallArgsTraits -{ - static const size_t offsetOfArgv = offsetof(JSJitMethodCallArgs, argv_); - static const size_t offsetOfArgc = offsetof(JSJitMethodCallArgs, argc_); +struct JSJitMethodCallArgsTraits { + static const size_t offsetOfArgv = offsetof(JSJitMethodCallArgs, argv_); + static const size_t offsetOfArgc = offsetof(JSJitMethodCallArgs, argc_); }; -typedef bool -(* JSJitGetterOp)(JSContext* cx, JS::HandleObject thisObj, - void* specializedThis, JSJitGetterCallArgs args); -typedef bool -(* JSJitSetterOp)(JSContext* cx, JS::HandleObject thisObj, - void* specializedThis, JSJitSetterCallArgs args); -typedef bool -(* JSJitMethodOp)(JSContext* cx, JS::HandleObject thisObj, - void* specializedThis, const JSJitMethodCallArgs& args); +typedef bool (*JSJitGetterOp)(JSContext* cx, JS::HandleObject thisObj, + void* specializedThis, JSJitGetterCallArgs args); +typedef bool (*JSJitSetterOp)(JSContext* cx, JS::HandleObject thisObj, + void* specializedThis, JSJitSetterCallArgs args); +typedef bool (*JSJitMethodOp)(JSContext* cx, JS::HandleObject thisObj, + void* specializedThis, + const JSJitMethodCallArgs& args); /** * This struct contains metadata passed from the DOM to the JS Engine for JIT @@ -2291,193 +2219,186 @@ * available to general JSAPI users, but we are not currently ready to do so. */ struct JSJitInfo { - enum OpType { - Getter, - Setter, - Method, - StaticMethod, - InlinableNative, - // Must be last - OpTypeCount - }; - - enum ArgType { - // Basic types - String = (1 << 0), - Integer = (1 << 1), // Only 32-bit or less - Double = (1 << 2), // Maybe we want to add Float sometime too - Boolean = (1 << 3), - Object = (1 << 4), - Null = (1 << 5), - - // And derived types - Numeric = Integer | Double, - // Should "Primitive" use the WebIDL definition, which - // excludes string and null, or the typical JS one that includes them? - Primitive = Numeric | Boolean | Null | String, - ObjectOrNull = Object | Null, - Any = ObjectOrNull | Primitive, - - // Our sentinel value. - ArgTypeListEnd = (1 << 31) - }; - - static_assert(Any & String, "Any must include String."); - static_assert(Any & Integer, "Any must include Integer."); - static_assert(Any & Double, "Any must include Double."); - static_assert(Any & Boolean, "Any must include Boolean."); - static_assert(Any & Object, "Any must include Object."); - static_assert(Any & Null, "Any must include Null."); + enum OpType { + Getter, + Setter, + Method, + StaticMethod, + InlinableNative, + IgnoresReturnValueNative, + // Must be last + OpTypeCount + }; + + enum ArgType { + // Basic types + String = (1 << 0), + Integer = (1 << 1), // Only 32-bit or less + Double = (1 << 2), // Maybe we want to add Float sometime too + Boolean = (1 << 3), + Object = (1 << 4), + Null = (1 << 5), + + // And derived types + Numeric = Integer | Double, + // Should "Primitive" use the WebIDL definition, which + // excludes string and null, or the typical JS one that includes them? + Primitive = Numeric | Boolean | Null | String, + ObjectOrNull = Object | Null, + Any = ObjectOrNull | Primitive, + + // Our sentinel value. + ArgTypeListEnd = (1 << 31) + }; + + static_assert(Any & String, "Any must include String."); + static_assert(Any & Integer, "Any must include Integer."); + static_assert(Any & Double, "Any must include Double."); + static_assert(Any & Boolean, "Any must include Boolean."); + static_assert(Any & Object, "Any must include Object."); + static_assert(Any & Null, "Any must include Null."); + + /** + * An enum that describes what this getter/setter/method aliases. This + * determines what things can be hoisted past this call, and if this + * call is movable what it can be hoisted past. + */ + enum AliasSet { + /** + * Alias nothing: a constant value, getting it can't affect any other + * values, nothing can affect it. + */ + AliasNone, /** - * An enum that describes what this getter/setter/method aliases. This - * determines what things can be hoisted past this call, and if this - * call is movable what it can be hoisted past. + * Alias things that can modify the DOM but nothing else. Doing the + * call can't affect the behavior of any other function. */ - enum AliasSet { - /** - * Alias nothing: a constant value, getting it can't affect any other - * values, nothing can affect it. - */ - AliasNone, - - /** - * Alias things that can modify the DOM but nothing else. Doing the - * call can't affect the behavior of any other function. - */ - AliasDOMSets, - - /** - * Alias the world. Calling this can change arbitrary values anywhere - * in the system. Most things fall in this bucket. - */ - AliasEverything, - - /** Must be last. */ - AliasSetCount - }; - - bool needsOuterizedThisObject() const - { - return type() != Getter && type() != Setter; - } + AliasDOMSets, - bool isTypedMethodJitInfo() const - { - return isTypedMethod; - } + /** + * Alias the world. Calling this can change arbitrary values anywhere + * in the system. Most things fall in this bucket. + */ + AliasEverything, - OpType type() const - { - return OpType(type_); - } + /** Must be last. */ + AliasSetCount + }; - AliasSet aliasSet() const - { - return AliasSet(aliasSet_); - } + bool needsOuterizedThisObject() const { + return type() != Getter && type() != Setter; + } - JSValueType returnType() const - { - return JSValueType(returnType_); - } + bool isTypedMethodJitInfo() const { return isTypedMethod; } + + OpType type() const { return OpType(type_); } + + AliasSet aliasSet() const { return AliasSet(aliasSet_); } - union { - JSJitGetterOp getter; - JSJitSetterOp setter; - JSJitMethodOp method; - /** A DOM static method, used for Promise wrappers */ - JSNative staticMethod; - }; - - union { - uint16_t protoID; - js::jit::InlinableNative inlinableNative; - }; - - 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 - // fields before adding more members to this structure. + JSValueType returnType() const { return JSValueType(returnType_); } + + union { + JSJitGetterOp getter; + JSJitSetterOp setter; + JSJitMethodOp method; + /** A DOM static method, used for Promise wrappers */ + JSNative staticMethod; + JSNative ignoresReturnValueMethod; + }; + + static unsigned offsetOfIgnoresReturnValueNative() { + return offsetof(JSJitInfo, ignoresReturnValueMethod); + } + + union { + uint16_t protoID; + js::jit::InlinableNative inlinableNative; + }; + + 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 + // fields before adding more members to this structure. #define JITINFO_OP_TYPE_BITS 4 #define JITINFO_ALIAS_SET_BITS 4 #define JITINFO_RETURN_TYPE_BITS 8 #define JITINFO_SLOT_INDEX_BITS 10 - /** The OpType that says what sort of function we are. */ - uint32_t type_ : JITINFO_OP_TYPE_BITS; - - /** - * The alias set for this op. This is a _minimal_ alias set; in - * particular for a method it does not include whatever argument - * conversions might do. That's covered by argTypes and runtime - * analysis of the actual argument types being passed in. - */ - uint32_t aliasSet_ : JITINFO_ALIAS_SET_BITS; - - /** The return type tag. Might be JSVAL_TYPE_UNKNOWN. */ - uint32_t returnType_ : JITINFO_RETURN_TYPE_BITS; + /** The OpType that says what sort of function we are. */ + uint32_t type_ : JITINFO_OP_TYPE_BITS; - static_assert(OpTypeCount <= (1 << JITINFO_OP_TYPE_BITS), - "Not enough space for OpType"); - static_assert(AliasSetCount <= (1 << JITINFO_ALIAS_SET_BITS), - "Not enough space for AliasSet"); - static_assert((sizeof(JSValueType) * 8) <= JITINFO_RETURN_TYPE_BITS, - "Not enough space for JSValueType"); + /** + * The alias set for this op. This is a _minimal_ alias set; in + * particular for a method it does not include whatever argument + * conversions might do. That's covered by argTypes and runtime + * analysis of the actual argument types being passed in. + */ + uint32_t aliasSet_ : JITINFO_ALIAS_SET_BITS; + + /** The return type tag. Might be JSVAL_TYPE_UNKNOWN. */ + uint32_t returnType_ : JITINFO_RETURN_TYPE_BITS; + + static_assert(OpTypeCount <= (1 << JITINFO_OP_TYPE_BITS), + "Not enough space for OpType"); + static_assert(AliasSetCount <= (1 << JITINFO_ALIAS_SET_BITS), + "Not enough space for AliasSet"); + static_assert((sizeof(JSValueType) * 8) <= JITINFO_RETURN_TYPE_BITS, + "Not enough space for JSValueType"); #undef JITINFO_RETURN_TYPE_BITS #undef JITINFO_ALIAS_SET_BITS #undef JITINFO_OP_TYPE_BITS - /** Is op fallible? False in setters. */ - uint32_t isInfallible : 1; - - /** - * Is op movable? To be movable the op must - * not AliasEverything, but even that might - * not be enough (e.g. in cases when it can - * throw or is explicitly not movable). - */ - uint32_t isMovable : 1; - - /** - * Can op be dead-code eliminated? Again, this - * depends on whether the op can throw, in - * addition to the alias set. - */ - uint32_t isEliminatable : 1; - - // XXXbz should we have a JSValueType for the type of the member? - /** - * True if this is a getter that can always - * get the value from a slot of the "this" object. - */ - uint32_t isAlwaysInSlot : 1; + /** Is op fallible? False in setters. */ + uint32_t isInfallible : 1; - /** - * True if this is a getter that can sometimes (if the slot doesn't contain - * UndefinedValue()) get the value from a slot of the "this" object. - */ - uint32_t isLazilyCachedInSlot : 1; - - /** True if this is an instance of JSTypedMethodJitInfo. */ - uint32_t isTypedMethod : 1; - - /** - * If isAlwaysInSlot or isSometimesInSlot is true, - * the index of the slot to get the value from. - * Otherwise 0. - */ - uint32_t slotIndex : JITINFO_SLOT_INDEX_BITS; + /** + * Is op movable? To be movable the op must + * not AliasEverything, but even that might + * not be enough (e.g. in cases when it can + * throw or is explicitly not movable). + */ + uint32_t isMovable : 1; + + /** + * Can op be dead-code eliminated? Again, this + * depends on whether the op can throw, in + * addition to the alias set. + */ + uint32_t isEliminatable : 1; + + // XXXbz should we have a JSValueType for the type of the member? + /** + * True if this is a getter that can always + * get the value from a slot of the "this" object. + */ + uint32_t isAlwaysInSlot : 1; + + /** + * True if this is a getter that can sometimes (if the slot doesn't contain + * UndefinedValue()) get the value from a slot of the "this" object. + */ + uint32_t isLazilyCachedInSlot : 1; + + /** True if this is an instance of JSTypedMethodJitInfo. */ + uint32_t isTypedMethod : 1; + + /** + * If isAlwaysInSlot or isSometimesInSlot is true, + * the index of the slot to get the value from. + * Otherwise 0. + */ + uint32_t slotIndex : JITINFO_SLOT_INDEX_BITS; - static const size_t maxSlotIndex = (1 << JITINFO_SLOT_INDEX_BITS) - 1; + static const size_t maxSlotIndex = (1 << JITINFO_SLOT_INDEX_BITS) - 1; #undef JITINFO_SLOT_INDEX_BITS }; @@ -2488,67 +2409,60 @@ "verifying that there is no other way forward (better packing, " "smaller datatypes for fields, subclassing, etc.)."); -struct JSTypedMethodJitInfo -{ - // We use C-style inheritance here, rather than C++ style inheritance - // because not all compilers support brace-initialization for non-aggregate - // classes. Using C++ style inheritance and constructors instead of - // brace-initialization would also force the creation of static - // constructors (on some compilers) when JSJitInfo and JSTypedMethodJitInfo - // structures are declared. Since there can be several thousand of these - // structures present and we want to have roughly equivalent performance - // across a range of compilers, we do things manually. - JSJitInfo base; - - const JSJitInfo::ArgType* const argTypes; /* For a method, a list of sets of - types that the function - expects. This can be used, - for example, to figure out - when argument coercions can - have side-effects. */ +struct JSTypedMethodJitInfo { + // We use C-style inheritance here, rather than C++ style inheritance + // because not all compilers support brace-initialization for non-aggregate + // classes. Using C++ style inheritance and constructors instead of + // brace-initialization would also force the creation of static + // constructors (on some compilers) when JSJitInfo and JSTypedMethodJitInfo + // structures are declared. Since there can be several thousand of these + // structures present and we want to have roughly equivalent performance + // across a range of compilers, we do things manually. + JSJitInfo base; + + const JSJitInfo::ArgType* const argTypes; /* For a method, a list of sets of + types that the function + expects. This can be used, + for example, to figure out + when argument coercions can + have side-effects. */ }; namespace js { -static MOZ_ALWAYS_INLINE shadow::Function* -FunctionObjectToShadowFunction(JSObject* fun) -{ - MOZ_ASSERT(GetObjectClass(fun) == FunctionClassPtr); - return reinterpret_cast(fun); +static MOZ_ALWAYS_INLINE shadow::Function* FunctionObjectToShadowFunction( + JSObject* fun) { + MOZ_ASSERT(GetObjectClass(fun) == FunctionClassPtr); + return reinterpret_cast(fun); } -/* Statically asserted in jsfun.h. */ +/* Statically asserted in JSFunction.h. */ static const unsigned JS_FUNCTION_INTERPRETED_BITS = 0x0201; // Return whether the given function object is native. -static MOZ_ALWAYS_INLINE bool -FunctionObjectIsNative(JSObject* fun) -{ - return !(FunctionObjectToShadowFunction(fun)->flags & JS_FUNCTION_INTERPRETED_BITS); -} - -static MOZ_ALWAYS_INLINE JSNative -GetFunctionObjectNative(JSObject* fun) -{ - MOZ_ASSERT(FunctionObjectIsNative(fun)); - return FunctionObjectToShadowFunction(fun)->native; -} - -} // namespace js - -static MOZ_ALWAYS_INLINE const JSJitInfo* -FUNCTION_VALUE_TO_JITINFO(const JS::Value& v) -{ - MOZ_ASSERT(js::FunctionObjectIsNative(&v.toObject())); - return js::FunctionObjectToShadowFunction(&v.toObject())->jitinfo; -} - -static MOZ_ALWAYS_INLINE void -SET_JITINFO(JSFunction * func, const JSJitInfo* info) -{ - js::shadow::Function* fun = reinterpret_cast(func); - MOZ_ASSERT(!(fun->flags & js::JS_FUNCTION_INTERPRETED_BITS)); - fun->jitinfo = info; +static MOZ_ALWAYS_INLINE bool FunctionObjectIsNative(JSObject* fun) { + return !(FunctionObjectToShadowFunction(fun)->flags & + JS_FUNCTION_INTERPRETED_BITS); +} + +static MOZ_ALWAYS_INLINE JSNative GetFunctionObjectNative(JSObject* fun) { + MOZ_ASSERT(FunctionObjectIsNative(fun)); + return FunctionObjectToShadowFunction(fun)->native; +} + +} // namespace js + +static MOZ_ALWAYS_INLINE const JSJitInfo* FUNCTION_VALUE_TO_JITINFO( + const JS::Value& v) { + MOZ_ASSERT(js::FunctionObjectIsNative(&v.toObject())); + return js::FunctionObjectToShadowFunction(&v.toObject())->jitinfo; +} + +static MOZ_ALWAYS_INLINE void SET_JITINFO(JSFunction* func, + const JSJitInfo* info) { + js::shadow::Function* fun = reinterpret_cast(func); + MOZ_ASSERT(!(fun->flags & js::JS_FUNCTION_INTERPRETED_BITS)); + fun->jitinfo = info; } /* @@ -2556,19 +2470,18 @@ * eliminate Gecko's dependencies on it! */ -static MOZ_ALWAYS_INLINE jsid -JSID_FROM_BITS(size_t bits) -{ - jsid id; - JSID_BITS(id) = bits; - return id; +static MOZ_ALWAYS_INLINE jsid JSID_FROM_BITS(size_t bits) { + jsid id; + JSID_BITS(id) = bits; + return id; } namespace js { namespace detail { bool IdMatchesAtom(jsid id, JSAtom* atom); -} // namespace detail -} // namespace js +bool IdMatchesAtom(jsid id, JSString* atom); +} // namespace detail +} // namespace js /** * Must not be used on atoms that are representable as integer jsids. @@ -2591,49 +2504,44 @@ * Thus, it is only the rare third case which needs this function, which * handles any JSAtom* that is known not to be representable with an int jsid. */ -static MOZ_ALWAYS_INLINE jsid -NON_INTEGER_ATOM_TO_JSID(JSAtom* atom) -{ - MOZ_ASSERT(((size_t)atom & 0x7) == 0); - jsid id = JSID_FROM_BITS((size_t)atom); - MOZ_ASSERT(js::detail::IdMatchesAtom(id, atom)); - return id; -} - -/* All strings stored in jsids are atomized, but are not necessarily property names. */ -static MOZ_ALWAYS_INLINE bool -JSID_IS_ATOM(jsid id) -{ - return JSID_IS_STRING(id); -} - -static MOZ_ALWAYS_INLINE bool -JSID_IS_ATOM(jsid id, JSAtom* atom) -{ - return id == JSID_FROM_BITS((size_t)atom); -} - -static MOZ_ALWAYS_INLINE JSAtom* -JSID_TO_ATOM(jsid id) -{ - return (JSAtom*)JSID_TO_STRING(id); +static MOZ_ALWAYS_INLINE jsid NON_INTEGER_ATOM_TO_JSID(JSAtom* atom) { + MOZ_ASSERT(((size_t)atom & 0x7) == 0); + jsid id = JSID_FROM_BITS((size_t)atom); + MOZ_ASSERT(js::detail::IdMatchesAtom(id, atom)); + return id; +} + +static MOZ_ALWAYS_INLINE jsid NON_INTEGER_ATOM_TO_JSID(JSString* atom) { + MOZ_ASSERT(((size_t)atom & 0x7) == 0); + jsid id = JSID_FROM_BITS((size_t)atom); + MOZ_ASSERT(js::detail::IdMatchesAtom(id, atom)); + return id; +} + +/* All strings stored in jsids are atomized, but are not necessarily property + * names. */ +static MOZ_ALWAYS_INLINE bool JSID_IS_ATOM(jsid id) { + return JSID_IS_STRING(id); +} + +static MOZ_ALWAYS_INLINE bool JSID_IS_ATOM(jsid id, JSAtom* atom) { + return id == JSID_FROM_BITS((size_t)atom); +} + +static MOZ_ALWAYS_INLINE JSAtom* JSID_TO_ATOM(jsid id) { + return (JSAtom*)JSID_TO_STRING(id); } JS_STATIC_ASSERT(sizeof(jsid) == sizeof(void*)); namespace js { -static MOZ_ALWAYS_INLINE JS::Value -IdToValue(jsid id) -{ - if (JSID_IS_STRING(id)) - return JS::StringValue(JSID_TO_STRING(id)); - if (JSID_IS_INT(id)) - return JS::Int32Value(JSID_TO_INT(id)); - if (JSID_IS_SYMBOL(id)) - return JS::SymbolValue(JSID_TO_SYMBOL(id)); - MOZ_ASSERT(JSID_IS_VOID(id)); - return JS::UndefinedValue(); +static MOZ_ALWAYS_INLINE JS::Value IdToValue(jsid id) { + if (JSID_IS_STRING(id)) return JS::StringValue(JSID_TO_STRING(id)); + if (JSID_IS_INT(id)) return JS::Int32Value(JSID_TO_INT(id)); + if (JSID_IS_SYMBOL(id)) return JS::SymbolValue(JSID_TO_SYMBOL(id)); + MOZ_ASSERT(JSID_IS_VOID(id)); + return JS::UndefinedValue(); } /** @@ -2654,75 +2562,71 @@ */ struct ScriptEnvironmentPreparer { - struct Closure { - virtual bool operator()(JSContext* cx) = 0; - }; + struct Closure { + virtual bool operator()(JSContext* cx) = 0; + }; - virtual void invoke(JS::HandleObject scope, Closure& closure) = 0; + virtual void invoke(JS::HandleObject scope, Closure& closure) = 0; }; -extern JS_FRIEND_API(void) -PrepareScriptEnvironmentAndInvoke(JSContext* cx, JS::HandleObject scope, - ScriptEnvironmentPreparer::Closure& closure); +extern JS_FRIEND_API void PrepareScriptEnvironmentAndInvoke( + JSContext* cx, JS::HandleObject scope, + ScriptEnvironmentPreparer::Closure& closure); -JS_FRIEND_API(void) -SetScriptEnvironmentPreparer(JSContext* cx, ScriptEnvironmentPreparer* preparer); +JS_FRIEND_API void SetScriptEnvironmentPreparer( + JSContext* cx, ScriptEnvironmentPreparer* preparer); enum CTypesActivityType { - CTYPES_CALL_BEGIN, - CTYPES_CALL_END, - CTYPES_CALLBACK_BEGIN, - CTYPES_CALLBACK_END + CTYPES_CALL_BEGIN, + CTYPES_CALL_END, + CTYPES_CALLBACK_BEGIN, + CTYPES_CALLBACK_END }; -typedef void -(* CTypesActivityCallback)(JSContext* cx, CTypesActivityType type); +typedef void (*CTypesActivityCallback)(JSContext* cx, CTypesActivityType type); /** * Sets a callback that is run whenever js-ctypes is about to be used when * calling into C. */ -JS_FRIEND_API(void) -SetCTypesActivityCallback(JSContext* cx, CTypesActivityCallback cb); +JS_FRIEND_API void SetCTypesActivityCallback(JSContext* cx, + CTypesActivityCallback cb); -class MOZ_RAII JS_FRIEND_API(AutoCTypesActivityCallback) { - private: - JSContext* cx; - CTypesActivityCallback callback; - CTypesActivityType endType; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER - - public: - AutoCTypesActivityCallback(JSContext* cx, CTypesActivityType beginType, - CTypesActivityType endType - MOZ_GUARD_OBJECT_NOTIFIER_PARAM); - ~AutoCTypesActivityCallback() { - DoEndCallback(); - } - void DoEndCallback() { - if (callback) { - callback(cx, endType); - callback = nullptr; - } +class MOZ_RAII JS_FRIEND_API AutoCTypesActivityCallback { + private: + JSContext* cx; + CTypesActivityCallback callback; + CTypesActivityType endType; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + + public: + AutoCTypesActivityCallback(JSContext* cx, CTypesActivityType beginType, + CTypesActivityType endType + MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + ~AutoCTypesActivityCallback() { DoEndCallback(); } + void DoEndCallback() { + if (callback) { + callback(cx, endType); + callback = nullptr; } + } }; // Abstract base class for objects that build allocation metadata for JavaScript // values. struct AllocationMetadataBuilder { - 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; - } + // 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; + } }; /** @@ -2730,19 +2634,19 @@ * compartment, which may return a metadata object to associate with the * object. */ -JS_FRIEND_API(void) -SetAllocationMetadataBuilder(JSContext* cx, const AllocationMetadataBuilder *callback); +JS_FRIEND_API void SetAllocationMetadataBuilder( + JSContext* cx, const AllocationMetadataBuilder* callback); /** Get the metadata associated with an object. */ -JS_FRIEND_API(JSObject*) -GetAllocationMetadata(JSObject* obj); +JS_FRIEND_API JSObject* GetAllocationMetadata(JSObject* obj); -JS_FRIEND_API(bool) -GetElementsWithAdder(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver, - uint32_t begin, uint32_t end, js::ElementAdder* adder); +JS_FRIEND_API bool GetElementsWithAdder(JSContext* cx, JS::HandleObject obj, + JS::HandleObject receiver, + uint32_t begin, uint32_t end, + js::ElementAdder* adder); -JS_FRIEND_API(bool) -ForwardToNative(JSContext* cx, JSNative native, const JS::CallArgs& args); +JS_FRIEND_API bool ForwardToNative(JSContext* cx, JSNative native, + const JS::CallArgs& args); /** * Helper function for HTMLDocument and HTMLFormElement. @@ -2764,26 +2668,83 @@ * * Implemented in proxy/BaseProxyHandler.cpp. */ -JS_FRIEND_API(bool) -SetPropertyIgnoringNamedGetter(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::HandleValue v, JS::HandleValue receiver, - JS::Handle ownDesc, - JS::ObjectOpResult& result); - -JS_FRIEND_API(void) -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) -ExecuteInGlobalAndReturnScope(JSContext* cx, JS::HandleObject obj, JS::HandleScript script, - JS::MutableHandleObject scope); +JS_FRIEND_API bool SetPropertyIgnoringNamedGetter( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, + JS::HandleValue receiver, JS::Handle ownDesc, + JS::ObjectOpResult& result); + +// This function is for one specific use case, please don't use this for +// anything else! +extern JS_FRIEND_API bool ExecuteInGlobalAndReturnScope( + JSContext* cx, JS::HandleObject obj, JS::HandleScript script, + JS::MutableHandleObject scope); + +// These functions are provided for the JSM component loader in Gecko. +// +// A 'JSMEnvironment' refers to an environment chain constructed for JSM loading +// in a shared global. Internally it is a NonSyntacticVariablesObject with a +// corresponding extensible LexicalEnvironmentObject that is accessible by +// JS_ExtensibleLexicalEnvironment. The |this| value of that lexical environment +// is the NSVO itself. +// +// Normal global environment (ES6): JSM "global" environment: +// +// * - extensible lexical environment +// | (code runs in this environment; +// | `let/const` bindings go here) +// | +// * - JSMEnvironment (=== `this`) +// | (`var` bindings go here) +// | +// * - extensible lexical environment * - extensible lexical environment +// | (code runs in this environment; | (empty) +// | `let/const` bindings go here) | +// | | +// * - actual global (=== `this`) * - shared JSM global +// (var bindings go here; and (Object, Math, etc. live here) +// Object, Math, etc. live here) + +// Allocate a new environment in current compartment that is compatible with JSM +// shared loading. +extern JS_FRIEND_API JSObject* NewJSMEnvironment(JSContext* cx); + +// Execute the given script (copied into compartment if necessary) in the given +// JSMEnvironment. The script must have been compiled for hasNonSyntacticScope. +// The |jsmEnv| must have been previously allocated by NewJSMEnvironment. +// +// NOTE: The associated extensible lexical environment is reused. +extern JS_FRIEND_API bool ExecuteInJSMEnvironment(JSContext* cx, + JS::HandleScript script, + JS::HandleObject jsmEnv); + +// Additionally, target objects may be specified as required by the Gecko +// subscript loader. These are wrapped in non-syntactic WithEnvironments and +// temporarily placed on environment chain. +// +// See also: JS::CloneAndExecuteScript(...) +extern JS_FRIEND_API bool ExecuteInJSMEnvironment( + JSContext* cx, JS::HandleScript script, JS::HandleObject jsmEnv, + JS::AutoObjectVector& targetObj); + +// Used by native methods to determine the JSMEnvironment of caller if possible +// by looking at stack frames. Returns nullptr if top frame isn't a scripted +// caller in a JSM. +// +// NOTE: This may find NonSyntacticVariablesObject generated by other embedding +// such as a Gecko FrameScript. Caller can check the compartment if needed. +extern JS_FRIEND_API JSObject* GetJSMEnvironmentOfScriptedCaller(JSContext* cx); + +// Determine if obj is a JSMEnvironment +// +// NOTE: This may return true for an NonSyntacticVariablesObject generated by +// other embedding such as a Gecko FrameScript. Caller can check compartment. +extern JS_FRIEND_API bool IsJSMEnvironment(JSObject* obj); #if defined(XP_WIN) && defined(_WIN64) // Parameters use void* types to avoid #including windows.h. The return value of // this function is returned from the exception handler. -typedef long -(*JitExceptionHandler)(void* exceptionRecord, // PEXECTION_RECORD - void* context); // PCONTEXT +typedef long (*JitExceptionHandler)(void* exceptionRecord, // PEXECTION_RECORD + void* context); // PCONTEXT /** * Windows uses "structured exception handling" to handle faults. When a fault @@ -2804,19 +2765,10 @@ * Gecko must call SetJitExceptionFilter before any JIT code is compiled and * only once per process. */ -extern JS_FRIEND_API(void) -SetJitExceptionHandler(JitExceptionHandler handler); +extern JS_FRIEND_API void SetJitExceptionHandler(JitExceptionHandler handler); #endif /** - * 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*) -GetNearestEnclosingWithEnvironmentObjectForFunction(JSFunction* fun); - -/** * Get the first SavedFrame object in this SavedFrame stack whose principals are * subsumed by the cx's principals. If there is no such frame, return nullptr. * @@ -2824,14 +2776,25 @@ * * The savedFrame and cx do not need to be in the same compartment. */ -extern JS_FRIEND_API(JSObject*) -GetFirstSubsumedSavedFrame(JSContext* cx, JS::HandleObject savedFrame, JS::SavedFrameSelfHosted selfHosted); +extern JS_FRIEND_API JSObject* GetFirstSubsumedSavedFrame( + JSContext* cx, JS::HandleObject savedFrame, + JS::SavedFrameSelfHosted selfHosted); -extern JS_FRIEND_API(bool) -ReportIsNotFunction(JSContext* cx, JS::HandleValue v); +/** + * Get the first SavedFrame object in this SavedFrame stack whose principals are + * subsumed by the given |principals|. If there is no such frame, return + * nullptr. + * + * Do NOT pass a non-SavedFrame object here. + */ +extern JS_FRIEND_API JSObject* GetFirstSubsumedSavedFrame( + JSContext* cx, JSPrincipals* principals, JS::HandleObject savedFrame, + JS::SavedFrameSelfHosted selfHosted); -extern JS_FRIEND_API(JSObject*) -ConvertArgsToArray(JSContext* cx, const JS::CallArgs& args); +extern JS_FRIEND_API bool ReportIsNotFunction(JSContext* cx, JS::HandleValue v); + +extern JS_FRIEND_API JSObject* ConvertArgsToArray(JSContext* cx, + const JS::CallArgs& args); /** * Window and WindowProxy @@ -2853,215 +2816,114 @@ * Tell the JS engine which Class is used for WindowProxy objects. Used by the * functions below. */ -extern JS_FRIEND_API(void) -SetWindowProxyClass(JSContext* cx, const Class* clasp); +extern JS_FRIEND_API void SetWindowProxyClass(JSContext* cx, + const Class* clasp); /** * Associates a WindowProxy with a Window (global object). `windowProxy` must * have the Class set by SetWindowProxyClass. */ -extern JS_FRIEND_API(void) -SetWindowProxy(JSContext* cx, JS::HandleObject global, JS::HandleObject windowProxy); +extern JS_FRIEND_API void SetWindowProxy(JSContext* cx, JS::HandleObject global, + JS::HandleObject windowProxy); namespace detail { -JS_FRIEND_API(bool) -IsWindowSlow(JSObject* obj); +JS_FRIEND_API bool IsWindowSlow(JSObject* obj); + +JS_FRIEND_API JSObject* ToWindowProxyIfWindowSlow(JSObject* obj); -} // namespace detail +} // namespace detail /** * Returns true iff `obj` is a global object with an associated WindowProxy, * see SetWindowProxy. */ -inline bool -IsWindow(JSObject* obj) -{ - if (GetObjectClass(obj)->flags & JSCLASS_IS_GLOBAL) - return detail::IsWindowSlow(obj); - return false; +inline bool IsWindow(JSObject* obj) { + if (GetObjectClass(obj)->flags & JSCLASS_IS_GLOBAL) + return detail::IsWindowSlow(obj); + return false; } /** * Returns true iff `obj` has the WindowProxy Class (see SetWindowProxyClass). */ -JS_FRIEND_API(bool) -IsWindowProxy(JSObject* obj); +JS_FRIEND_API bool IsWindowProxy(JSObject* obj); /** * If `obj` is a Window, get its associated WindowProxy (or a CCW or dead * wrapper if the page was navigated away from), else return `obj`. This * function is infallible and never returns nullptr. */ -extern JS_FRIEND_API(JSObject*) -ToWindowProxyIfWindow(JSObject* obj); +MOZ_ALWAYS_INLINE JSObject* ToWindowProxyIfWindow(JSObject* obj) { + if (GetObjectClass(obj)->flags & JSCLASS_IS_GLOBAL) + return detail::ToWindowProxyIfWindowSlow(obj); + return obj; +} /** * If `obj` is a WindowProxy, get its associated Window (the compartment's * global), else return `obj`. This function is infallible and never returns * nullptr. */ -extern JS_FRIEND_API(JSObject*) -ToWindowIfWindowProxy(JSObject* obj); - -} /* namespace js */ - -class NativeProfiler -{ - public: - virtual ~NativeProfiler() {}; - virtual void sampleNative(void* addr, uint32_t size) = 0; - virtual void removeNative(void* addr) = 0; - virtual void reset() = 0; -}; - -class GCHeapProfiler -{ - public: - virtual ~GCHeapProfiler() {}; - virtual void sampleTenured(void* addr, uint32_t size) = 0; - virtual void sampleNursery(void* addr, uint32_t size) = 0; - virtual void markTenuredStart() = 0; - virtual void markTenured(void* addr) = 0; - virtual void sweepTenured() = 0; - virtual void sweepNursery() = 0; - virtual void moveNurseryToTenured(void* addrOld, void* addrNew) = 0; - virtual void reset() = 0; -}; - -class MemProfiler -{ - static mozilla::Atomic sActiveProfilerCount; - static JS_FRIEND_DATA(NativeProfiler*) sNativeProfiler; - - static GCHeapProfiler* GetGCHeapProfiler(void* addr); - static GCHeapProfiler* GetGCHeapProfiler(JSRuntime* runtime); - - static NativeProfiler* GetNativeProfiler() { - return sNativeProfiler; - } - - GCHeapProfiler* mGCHeapProfiler; - JSRuntime* mRuntime; - - public: - explicit MemProfiler(JSRuntime* aRuntime) : mGCHeapProfiler(nullptr), mRuntime(aRuntime) {} - - JS_FRIEND_API(void) start(GCHeapProfiler* aGCHeapProfiler); - JS_FRIEND_API(void) stop(); - - GCHeapProfiler* getGCHeapProfiler() const { - return mGCHeapProfiler; - } +extern JS_FRIEND_API JSObject* ToWindowIfWindowProxy(JSObject* obj); - static MOZ_ALWAYS_INLINE bool enabled() { - return sActiveProfilerCount > 0; - } - - static JS_FRIEND_API(MemProfiler*) GetMemProfiler(JSContext* context); - - static void SetNativeProfiler(NativeProfiler* aProfiler) { - sNativeProfiler = aProfiler; - } - - static MOZ_ALWAYS_INLINE void SampleNative(void* addr, uint32_t size) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - NativeProfiler* profiler = GetNativeProfiler(); - if (profiler) - profiler->sampleNative(addr, size); - } - - static MOZ_ALWAYS_INLINE void SampleTenured(void* addr, uint32_t size) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - GCHeapProfiler* profiler = GetGCHeapProfiler(addr); - if (profiler) - profiler->sampleTenured(addr, size); - } - - static MOZ_ALWAYS_INLINE void SampleNursery(void* addr, uint32_t size) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - GCHeapProfiler* profiler = GetGCHeapProfiler(addr); - if (profiler) - profiler->sampleNursery(addr, size); - } - - static MOZ_ALWAYS_INLINE void RemoveNative(void* addr) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - NativeProfiler* profiler = GetNativeProfiler(); - if (profiler) - profiler->removeNative(addr); - } - - static MOZ_ALWAYS_INLINE void MarkTenuredStart(JSRuntime* runtime) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - GCHeapProfiler* profiler = GetGCHeapProfiler(runtime); - if (profiler) - profiler->markTenuredStart(); - } - - static MOZ_ALWAYS_INLINE void MarkTenured(void* addr) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - GCHeapProfiler* profiler = GetGCHeapProfiler(addr); - if (profiler) - profiler->markTenured(addr); - } - - static MOZ_ALWAYS_INLINE void SweepTenured(JSRuntime* runtime) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - GCHeapProfiler* profiler = GetGCHeapProfiler(runtime); - if (profiler) - profiler->sweepTenured(); - } - - static MOZ_ALWAYS_INLINE void SweepNursery(JSRuntime* runtime) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - GCHeapProfiler* profiler = GetGCHeapProfiler(runtime); - if (profiler) - profiler->sweepNursery(); - } - - static MOZ_ALWAYS_INLINE void MoveNurseryToTenured(void* addrOld, void* addrNew) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; +// Create and add the Intl.MozDateTimeFormat constructor function to the +// provided object. +// +// This custom date/time formatter constructor gives users the ability +// to specify a custom format pattern. This pattern is passed *directly* +// to ICU with NO SYNTAX PARSING OR VALIDATION WHATSOEVER. ICU appears to +// have a a modicum of testing of this, and it won't fall over completely +// if passed bad input. But the current behavior is entirely under-specified +// and emphatically not shippable on the web, and it *must* be fixed before +// this functionality can be exposed in the real world. (There are also some +// questions about whether the format exposed here is the *right* one to +// standardize, that will also need to be resolved to ship this.) +extern bool AddMozDateTimeFormatConstructor(JSContext* cx, + JS::Handle intl); + +// Create and add the Intl.RelativeTimeFormat constructor function to the +// provided object. This function throws if called more than once per +// realm/global object. +extern bool AddRelativeTimeFormatConstructor(JSContext* cx, + JS::Handle intl); + +class MOZ_STACK_CLASS JS_FRIEND_API AutoAssertNoContentJS { + public: + explicit AutoAssertNoContentJS(JSContext* cx); + ~AutoAssertNoContentJS(); + + private: + JSContext* context_; + bool prevAllowContentJS_; +}; + +// Turn on assertions so that we assert that +// !comp->validAccessPtr || *comp->validAccessPtr +// is true for every |comp| that we run JS code in. The compartment's +// validAccessPtr is set via SetCompartmentValidAccessPtr. +extern JS_FRIEND_API void EnableAccessValidation(JSContext* cx, bool enabled); + +// See EnableAccessValidation above. The caller must guarantee that accessp will +// live at least as long as |global| is alive. The JS engine reads accessp from +// threads that are allowed to run code on |global|, so all changes to *accessp +// should be made from whichever thread owns |global| at a given time. +extern JS_FRIEND_API void SetCompartmentValidAccessPtr(JSContext* cx, + JS::HandleObject global, + bool* accessp); + +// If the JS engine wants to block so that other cooperative threads can run, it +// will call the yield callback. It may do this if it needs to access a +// ZoneGroup that is held by another thread (such as the system zone group). +typedef void (*YieldCallback)(JSContext* cx); + +extern JS_FRIEND_API void SetCooperativeYieldCallback(JSContext* cx, + YieldCallback callback); + +// Returns true if the system zone is available (i.e., if no cooperative +// contexts are using it now). +extern JS_FRIEND_API bool SystemZoneAvailable(JSContext* cx); - GCHeapProfiler* profiler = GetGCHeapProfiler(addrOld); - if (profiler) - profiler->moveNurseryToTenured(addrOld, addrNew); - } -}; +} /* namespace js */ #endif /* jsfriendapi_h */ 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 @@ -27,107 +27,106 @@ * requested are available as data values after calling Stop(). The * object may be reused for many measurements. */ -class JS_FRIEND_API(PerfMeasurement) -{ - protected: - // Implementation-specific data, if any. - void* impl; - - public: - /* - * Events that may be measured. Taken directly from the list of - * "generalized hardware performance event types" in the Linux - * perf_event API, plus some of the "software events". - */ - enum EventMask { - CPU_CYCLES = 0x00000001, - INSTRUCTIONS = 0x00000002, - CACHE_REFERENCES = 0x00000004, - CACHE_MISSES = 0x00000008, - BRANCH_INSTRUCTIONS = 0x00000010, - BRANCH_MISSES = 0x00000020, - BUS_CYCLES = 0x00000040, - PAGE_FAULTS = 0x00000080, - MAJOR_PAGE_FAULTS = 0x00000100, - CONTEXT_SWITCHES = 0x00000200, - CPU_MIGRATIONS = 0x00000400, - - ALL = 0x000007ff, - NUM_MEASURABLE_EVENTS = 11 - }; - - /* - * Bitmask of events that will be measured when this object is - * active (between Start() and Stop()). This may differ from the - * bitmask passed to the constructor if the platform does not - * support measuring all of the requested events. - */ - const EventMask eventsMeasured; - - /* - * Counters for each measurable event. - * Immediately after one of these objects is created, all of the - * counters for enabled events will be zero, and all of the - * counters for disabled events will be uint64_t(-1). - */ - uint64_t cpu_cycles; - uint64_t instructions; - uint64_t cache_references; - uint64_t cache_misses; - uint64_t branch_instructions; - uint64_t branch_misses; - uint64_t bus_cycles; - uint64_t page_faults; - uint64_t major_page_faults; - uint64_t context_switches; - uint64_t cpu_migrations; - - /* - * Prepare to measure the indicated set of events. If not all of - * the requested events can be measured on the current platform, - * then the eventsMeasured bitmask will only include the subset of - * |toMeasure| corresponding to the events that can be measured. - */ - explicit PerfMeasurement(EventMask toMeasure); - - /* Done with this set of measurements, tear down OS-level state. */ - ~PerfMeasurement(); - - /* Start a measurement cycle. */ - void start(); - - /* - * End a measurement cycle, and for each enabled counter, add the - * number of measured events of that type to the appropriate - * visible variable. - */ - void stop(); - - /* Reset all enabled counters to zero. */ - void reset(); - - /* - * True if this platform supports measuring _something_, i.e. it's - * not using the stub implementation. - */ - static bool canMeasureSomething(); +class JS_FRIEND_API PerfMeasurement { + protected: + // Implementation-specific data, if any. + void* impl; + + public: + /* + * Events that may be measured. Taken directly from the list of + * "generalized hardware performance event types" in the Linux + * perf_event API, plus some of the "software events". + */ + enum EventMask { + CPU_CYCLES = 0x00000001, + INSTRUCTIONS = 0x00000002, + CACHE_REFERENCES = 0x00000004, + CACHE_MISSES = 0x00000008, + BRANCH_INSTRUCTIONS = 0x00000010, + BRANCH_MISSES = 0x00000020, + BUS_CYCLES = 0x00000040, + PAGE_FAULTS = 0x00000080, + MAJOR_PAGE_FAULTS = 0x00000100, + CONTEXT_SWITCHES = 0x00000200, + CPU_MIGRATIONS = 0x00000400, + + ALL = 0x000007ff, + NUM_MEASURABLE_EVENTS = 11 + }; + + /* + * Bitmask of events that will be measured when this object is + * active (between Start() and Stop()). This may differ from the + * bitmask passed to the constructor if the platform does not + * support measuring all of the requested events. + */ + const EventMask eventsMeasured; + + /* + * Counters for each measurable event. + * Immediately after one of these objects is created, all of the + * counters for enabled events will be zero, and all of the + * counters for disabled events will be uint64_t(-1). + */ + uint64_t cpu_cycles; + uint64_t instructions; + uint64_t cache_references; + uint64_t cache_misses; + uint64_t branch_instructions; + uint64_t branch_misses; + uint64_t bus_cycles; + uint64_t page_faults; + uint64_t major_page_faults; + uint64_t context_switches; + uint64_t cpu_migrations; + + /* + * Prepare to measure the indicated set of events. If not all of + * the requested events can be measured on the current platform, + * then the eventsMeasured bitmask will only include the subset of + * |toMeasure| corresponding to the events that can be measured. + */ + explicit PerfMeasurement(EventMask toMeasure); + + /* Done with this set of measurements, tear down OS-level state. */ + ~PerfMeasurement(); + + /* Start a measurement cycle. */ + void start(); + + /* + * End a measurement cycle, and for each enabled counter, add the + * number of measured events of that type to the appropriate + * visible variable. + */ + void stop(); + + /* Reset all enabled counters to zero. */ + void reset(); + + /* + * True if this platform supports measuring _something_, i.e. it's + * not using the stub implementation. + */ + static bool canMeasureSomething(); }; /* Inject a Javascript wrapper around the above C++ class into the * Javascript object passed as an argument (this will normally be a * global object). The JS-visible API is identical to the C++ API. */ -extern JS_FRIEND_API(JSObject*) - RegisterPerfMeasurement(JSContext* cx, JS::HandleObject global); +extern JS_FRIEND_API JSObject* RegisterPerfMeasurement(JSContext* cx, + JS::HandleObject global); /* * Given a Value which contains an instance of the aforementioned * wrapper class, extract the C++ object. Returns nullptr if the * Value is not an instance of the wrapper. */ -extern JS_FRIEND_API(PerfMeasurement*) - ExtractPerfMeasurement(const Value& wrapper); +extern JS_FRIEND_API PerfMeasurement* ExtractPerfMeasurement( + const Value& wrapper); -} // namespace JS +} // namespace JS #endif /* perf_jsperf_h */ 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 @@ -1,66 +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 jsprf_h -#define jsprf_h - -/* -** API for PR printf like routines. Supports the following formats -** %d - decimal -** %u - unsigned decimal -** %x - unsigned hex -** %X - unsigned uppercase hex -** %o - unsigned octal -** %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 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, ...) - MOZ_FORMAT_PRINTF(1, 2); - -/* -** Free the memory allocated, for the caller, by JS_smprintf -*/ -extern JS_PUBLIC_API(void) JS_smprintf_free(char* mem); - -/* -** "append" sprintf into a malloc'd buffer. "last" is the last value of -** the malloc'd buffer. sprintf will append data to the end of last, -** growing it as necessary using realloc. If last is nullptr, JS_sprintf_append -** 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, ...) - MOZ_FORMAT_PRINTF(2, 3); - -/* -** va_list forms of the above. -*/ -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); - -#endif /* jsprf_h */ 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 @@ -1,129 +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 jsprototypes_h -#define jsprototypes_h - -/* A higher-order macro for enumerating all JSProtoKey values. */ -/* - * Consumers define macros as follows: - * macro(name, code, init, clasp) - * name: The canonical name of the class. - * code: The enumerator code. There are part of the XDR API, and must not change. - * init: Initialization function. These are |extern "C";|, and clients should use - * |extern "C" {}| as appropriate when using this macro. - * clasp: The JSClass for this object, or "dummy" if it doesn't exist. - * - * - * Consumers wishing to iterate over all the JSProtoKey values, can use - * JS_FOR_EACH_PROTOTYPE. However, there are certain values that don't correspond - * to real constructors, like Null or constructors that are disabled via - * preprocessor directives. We still need to include these in the JSProtoKey list - * in order to maintain binary XDR compatibility, but we need to provide a tool - * to handle them differently. JS_FOR_PROTOTYPES fills this niche. - * - * Consumers pass two macros to JS_FOR_PROTOTYPES - |real| and |imaginary|. The - * former is invoked for entries that have real client-exposed constructors, and - * the latter is called for the rest. Consumers that don't care about this - * distinction can simply pass the same macro to both, which is exactly what - * JS_FOR_EACH_PROTOTYPE does. - */ - -#define CLASP(name) (&name##Class) -#define OCLASP(name) (&name##Object::class_) -#define TYPED_ARRAY_CLASP(type) (&TypedArrayObject::classes[Scalar::type]) -#define ERROR_CLASP(type) (&ErrorObject::classes[type]) - -#ifdef EXPOSE_INTL_API -#define IF_INTL(real,imaginary) real -#else -#define IF_INTL(real,imaginary) imaginary -#endif - -#ifdef ENABLE_BINARYDATA -#define IF_BDATA(real,imaginary) real -#else -#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)) \ - real(Function, 2, InitViaClassSpec, &JSFunction::class_) \ - real(Array, 3, InitViaClassSpec, OCLASP(Array)) \ - real(Boolean, 4, InitBooleanClass, OCLASP(Boolean)) \ - real(JSON, 5, InitJSONClass, CLASP(JSON)) \ - real(Date, 6, InitViaClassSpec, OCLASP(Date)) \ - real(Math, 7, InitMathClass, CLASP(Math)) \ - real(Number, 8, InitNumberClass, OCLASP(Number)) \ - real(String, 9, InitStringClass, OCLASP(String)) \ - real(RegExp, 10, InitViaClassSpec, OCLASP(RegExp)) \ - real(Error, 11, InitViaClassSpec, ERROR_CLASP(JSEXN_ERR)) \ - real(InternalError, 12, InitViaClassSpec, ERROR_CLASP(JSEXN_INTERNALERR)) \ - real(EvalError, 13, InitViaClassSpec, ERROR_CLASP(JSEXN_EVALERR)) \ - real(RangeError, 14, InitViaClassSpec, ERROR_CLASP(JSEXN_RANGEERR)) \ - real(ReferenceError, 15, InitViaClassSpec, ERROR_CLASP(JSEXN_REFERENCEERR)) \ - 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(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) - -#endif /* jsprototypes_h */ 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 @@ -16,455 +16,160 @@ #include "mozilla/LinkedList.h" #include "mozilla/PodOperations.h" -#include "jsprototypes.h" #include "jstypes.h" +#include "js/ProtoKey.h" +#include "js/Result.h" #include "js/TraceKind.h" #include "js/TypeDecls.h" #if defined(JS_GC_ZEAL) || defined(DEBUG) -# define JSGC_HASH_TABLE_CHECKS +#define JSGC_HASH_TABLE_CHECKS #endif namespace JS { -class AutoIdVector; -class CallArgs; - template -class Rooted; +class AutoVector; +using AutoIdVector = AutoVector; +using AutoValueVector = AutoVector; +using AutoObjectVector = AutoVector; -class JS_FRIEND_API(CompileOptions); -class JS_FRIEND_API(ReadOnlyCompileOptions); -class JS_FRIEND_API(OwningCompileOptions); -class JS_FRIEND_API(TransitiveCompileOptions); -class JS_PUBLIC_API(CompartmentOptions); - -struct RootingContext; -class Value; -struct Zone; - -namespace shadow { -struct Runtime; -} // namespace shadow +class CallArgs; -} // namespace JS +class JS_FRIEND_API CompileOptions; +class JS_FRIEND_API ReadOnlyCompileOptions; +class JS_FRIEND_API OwningCompileOptions; +class JS_FRIEND_API TransitiveCompileOptions; +class JS_PUBLIC_API CompartmentOptions; -namespace js { -class RootLists; -} // namespace js - -/* - * Run-time version enumeration. For compile-time version checking, please use - * the JS_HAS_* macros in jsversion.h, or use MOZJS_MAJOR_VERSION, - * MOZJS_MINOR_VERSION, MOZJS_PATCH_VERSION, and MOZJS_ALPHA definitions. - */ -enum JSVersion { - JSVERSION_ECMA_3 = 148, - JSVERSION_1_6 = 160, - JSVERSION_1_7 = 170, - JSVERSION_1_8 = 180, - JSVERSION_ECMA_5 = 185, - JSVERSION_DEFAULT = 0, - JSVERSION_UNKNOWN = -1, - JSVERSION_LATEST = JSVERSION_ECMA_5 -}; +} // namespace JS /* Result of typeof operator enumeration. */ enum JSType { - JSTYPE_VOID, /* undefined */ - JSTYPE_OBJECT, /* object */ - JSTYPE_FUNCTION, /* function */ - JSTYPE_STRING, /* string */ - JSTYPE_NUMBER, /* number */ - JSTYPE_BOOLEAN, /* boolean */ - JSTYPE_NULL, /* null */ - JSTYPE_SYMBOL, /* symbol */ - JSTYPE_LIMIT + JSTYPE_UNDEFINED, /* undefined */ + JSTYPE_OBJECT, /* object */ + JSTYPE_FUNCTION, /* function */ + JSTYPE_STRING, /* string */ + JSTYPE_NUMBER, /* number */ + JSTYPE_BOOLEAN, /* boolean */ + JSTYPE_NULL, /* null */ + JSTYPE_SYMBOL, /* symbol */ + JSTYPE_LIMIT }; /* Dense index into cached prototypes and class atoms for standard objects. */ enum JSProtoKey { -#define PROTOKEY_AND_INITIALIZER(name,code,init,clasp) JSProto_##name = code, - JS_FOR_EACH_PROTOTYPE(PROTOKEY_AND_INITIALIZER) +#define PROTOKEY_AND_INITIALIZER(name, init, clasp) JSProto_##name, + JS_FOR_EACH_PROTOTYPE(PROTOKEY_AND_INITIALIZER) #undef PROTOKEY_AND_INITIALIZER - JSProto_LIMIT + JSProto_LIMIT }; /* Struct forward declarations. */ struct JSClass; -struct JSCompartment; -struct JSCrossCompartmentCall; class JSErrorReport; struct JSExceptionState; struct JSFunctionSpec; struct JSLocaleCallbacks; -struct JSObjectMap; struct JSPrincipals; -struct JSPropertyName; struct JSPropertySpec; -struct JSRuntime; struct JSSecurityCallbacks; struct JSStructuredCloneCallbacks; struct JSStructuredCloneReader; struct JSStructuredCloneWriter; -class JS_PUBLIC_API(JSTracer); +class JS_PUBLIC_API JSTracer; class JSFlatString; -typedef bool (*JSInitCallback)(void); +typedef bool (*JSInitCallback)(void); -template struct JSConstScalarSpec; +template +struct JSConstScalarSpec; typedef JSConstScalarSpec JSConstDoubleSpec; typedef JSConstScalarSpec JSConstIntegerSpec; -/* - * 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 { namespace gc { class AutoTraceSession; class StoreBuffer; -} // namespace gc +} // namespace gc + +class CooperatingContext; + +inline JSCompartment* GetContextCompartment(const JSContext* cx); +inline JS::Zone* GetContextZone(const JSContext* cx); // Whether the current thread is permitted access to any part of the specified // runtime or zone. -JS_FRIEND_API(bool) -CurrentThreadCanAccessRuntime(const JSRuntime* rt); +JS_FRIEND_API bool CurrentThreadCanAccessRuntime(const JSRuntime* rt); #ifdef DEBUG -JS_FRIEND_API(bool) -CurrentThreadIsPerformingGC(); +JS_FRIEND_API bool CurrentThreadIsPerformingGC(); #endif -} // namespace js +} // namespace js namespace JS { -class JS_PUBLIC_API(AutoEnterCycleCollection); -class JS_PUBLIC_API(AutoAssertOnBarrier); -struct JS_PUBLIC_API(PropertyDescriptor); +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) - CycleCollecting // in the "Unlink" phase of cycle collection -}; - -namespace shadow { - -struct Runtime -{ - 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 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); - } - - protected: - void setGCStoreBufferPtr(js::gc::StoreBuffer* storeBuffer) { - gcStoreBufferPtr_ = storeBuffer; - } -}; - -} /* 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::RootingContext* cx, ptrdiff_t tag); - - ~AutoGCRooter() { - MOZ_ASSERT(this == *stackTop); - *stackTop = down; - } - - /* Implemented in gc/RootMarking.cpp. */ - inline void trace(JSTracer* trc); - static void traceAll(JSTracer* trc); - static void traceAllWrappers(JSTracer* trc); - - protected: - AutoGCRooter * const down; - - /* - * Discriminates actual subclass of this being used. If non-negative, the - * subclass roots an array of values of the length stored in this field. - * If negative, meaning is indicated by the corresponding value in the enum - * below. Any other negative value indicates some deeper problem such as - * memory corruption. - */ - ptrdiff_t tag_; - - enum { - VALARRAY = -2, /* js::AutoValueArray */ - PARSER = -3, /* js::frontend::Parser */ - VALVECTOR = -10, /* js::AutoValueVector */ - IDVECTOR = -11, /* js::AutoIdVector */ - OBJVECTOR = -14, /* js::AutoObjectVector */ - IONMASM = -19, /* js::jit::MacroAssembler */ - WRAPVECTOR = -20, /* js::AutoWrapperVector */ - WRAPPER = -21, /* js::AutoWrapperRooter */ - CUSTOM = -26 /* js::CustomAutoRooter */ - }; - - static ptrdiff_t GetTag(const Value& value) { return VALVECTOR; } - static ptrdiff_t GetTag(const jsid& id) { return IDVECTOR; } - static ptrdiff_t GetTag(JSObject* obj) { return OBJVECTOR; } - - private: - AutoGCRooter ** const stackTop; - - /* No copy or assignment semantics. */ - AutoGCRooter(AutoGCRooter& ida) = delete; - 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 { - -class ExclusiveContext; - -/* - * This list enumerates the different types of conceptual stacks we have in - * SpiderMonkey. In reality, they all share the C stack, but we allow different - * stack limits depending on the type of code running. - */ -enum StackKind -{ - StackForSystemCode, // C++, such as the GC, running on behalf of the VM. - StackForTrustedScript, // Script running with trusted principals. - StackForUntrustedScript, // Script running with untrusted principals. - StackKindCount + 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) + CycleCollecting // in the "Unlink" phase of cycle collection }; -using RootedListHeads = mozilla::EnumeratedArray*>; +JS_PUBLIC_API HeapState CurrentThreadHeapState(); -// Abstracts JS rooting mechanisms so they can be shared between the JSContext -// and JSRuntime. -class RootLists -{ - // Stack GC roots for Rooted GC heap pointers. - RootedListHeads stackRoots_; - template friend class JS::Rooted; - - // 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) { - for (auto& stackRootPtr : stackRoots_) - stackRootPtr = nullptr; - } - - ~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(); +static inline bool CurrentThreadIsHeapBusy() { + return CurrentThreadHeapState() != HeapState::Idle; +} - void tracePersistentRoots(JSTracer* trc); - void finishPersistentRoots(); -}; +static inline bool CurrentThreadIsHeapTracing() { + return CurrentThreadHeapState() == HeapState::Tracing; +} -} // namespace js +static inline bool CurrentThreadIsHeapMajorCollecting() { + return CurrentThreadHeapState() == HeapState::MajorCollecting; +} -namespace JS { +static inline bool CurrentThreadIsHeapMinorCollecting() { + return CurrentThreadHeapState() == HeapState::MinorCollecting; +} -/* - * 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; +static inline bool CurrentThreadIsHeapCollecting() { + HeapState state = CurrentThreadHeapState(); + return state == HeapState::MajorCollecting || + state == HeapState::MinorCollecting; +} -#ifdef DEBUG - // Whether the derived class is a JSContext or an ExclusiveContext. - bool isJSContext; -#endif +static inline bool CurrentThreadIsHeapCycleCollecting() { + return CurrentThreadHeapState() == HeapState::CycleCollecting; +} - explicit RootingContext(bool isJSContextArg) +// 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 - : isJSContext(isJSContextArg) + public: + explicit AutoEnterCycleCollection(JSRuntime* rt); + ~AutoEnterCycleCollection(); +#else + public: + explicit AutoEnterCycleCollection(JSRuntime* rt) {} + ~AutoEnterCycleCollection() {} #endif - {} - - static RootingContext* get(JSContext* cx) { - return reinterpret_cast(cx); - } }; -} // namespace JS - -namespace js { - -struct ContextFriendFields : public JS::RootingContext -{ - protected: - /* The current compartment. */ - JSCompartment* compartment_; - - /* The current zone. */ - JS::Zone* zone_; - - public: - /* Limit pointer for checking native stack consumption. */ - uintptr_t nativeStackLimit[js::StackKindCount]; - - explicit ContextFriendFields(bool isJSContext); - - static const ContextFriendFields* get(const JSContext* cx) { - return reinterpret_cast(cx); - } - - static ContextFriendFields* get(JSContext* cx) { - return reinterpret_cast(cx); - } - - friend JSCompartment* GetContextCompartment(const JSContext* cx); - friend JS::Zone* GetContextZone(const JSContext* cx); - template friend class JS::Rooted; -}; - -/* - * Inlinable accessors for JSContext. - * - * - These must not be available on the more restricted superclasses of - * JSContext, so we can't simply define them on ContextFriendFields. - * - * - They're perfectly ordinary JSContext functionality, so ought to be - * usable without resorting to jsfriendapi.h, and when JSContext is an - * incomplete type. - */ -inline JSCompartment* -GetContextCompartment(const JSContext* cx) -{ - return ContextFriendFields::get(cx)->compartment_; -} - -inline JS::Zone* -GetContextZone(const JSContext* cx) -{ - return ContextFriendFields::get(cx)->zone_; -} - -} /* namespace js */ +} /* namespace JS */ MOZ_BEGIN_EXTERN_C 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 @@ -26,13 +26,11 @@ #include "mozilla/Types.h" // jstypes.h is (or should be!) included by every file in SpiderMonkey. -// js-config.h and jsversion.h also should be included by every file. -// So include them here. -// XXX: including them in js/RequiredDefines.h should be a better option, since +// js-config.h also should be included by every file. So include it here. +// XXX: including it in js/RequiredDefines.h should be a better option, since // that is by definition the header file that should be included in all // SpiderMonkey code. However, Gecko doesn't do this! See bug 909576. #include "js-config.h" -#include "jsversion.h" /*********************************************************************** ** MACROS: JS_EXTERN_API @@ -55,10 +53,10 @@ ** ***********************************************************************/ -#define JS_EXTERN_API(type) extern MOZ_EXPORT type -#define JS_EXPORT_API(type) MOZ_EXPORT type +#define JS_EXTERN_API(type) extern MOZ_EXPORT type +#define JS_EXPORT_API(type) MOZ_EXPORT type #define JS_EXPORT_DATA(type) MOZ_EXPORT type -#define JS_IMPORT_API(type) MOZ_IMPORT_API type +#define JS_IMPORT_API(type) MOZ_IMPORT_API type #define JS_IMPORT_DATA(type) MOZ_IMPORT_DATA type /* @@ -68,20 +66,20 @@ * should not. STATIC_JS_API is used to build JS as a static library. */ #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 +#define JS_PUBLIC_API +#define JS_PUBLIC_DATA +#define JS_FRIEND_API +#define JS_FRIEND_DATA #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 -# 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 +#define JS_PUBLIC_API MOZ_EXPORT +#define JS_PUBLIC_DATA MOZ_EXPORT +#define JS_FRIEND_API MOZ_EXPORT +#define JS_FRIEND_DATA MOZ_EXPORT +#else +#define JS_PUBLIC_API MOZ_IMPORT_API +#define JS_PUBLIC_DATA MOZ_IMPORT_DATA +#define JS_FRIEND_API MOZ_IMPORT_API +#define JS_FRIEND_DATA MOZ_IMPORT_DATA #endif #if defined(_MSC_VER) && defined(_M_IX86) @@ -97,9 +95,11 @@ // 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)) +#if MOZ_IS_GCC +#if MOZ_GCC_VERSION_AT_MOST(8, 0, 0) #define JS_BROKEN_GCC_ATTRIBUTE_WARNING #endif +#endif /*********************************************************************** ** MACROS: JS_BEGIN_MACRO @@ -108,14 +108,16 @@ ** Macro body brackets so that macros with compound statement definitions ** behave syntactically more like functions when called. ***********************************************************************/ -#define JS_BEGIN_MACRO do { - +#define JS_BEGIN_MACRO do { #if defined(_MSC_VER) -# define JS_END_MACRO \ - } __pragma(warning(push)) __pragma(warning(disable:4127)) \ - while (0) __pragma(warning(pop)) -#else -# define JS_END_MACRO } while (0) +#define JS_END_MACRO \ + } \ + __pragma(warning(push)) __pragma(warning(disable : 4127)) while (0) \ + __pragma(warning(pop)) +#else +#define JS_END_MACRO \ + } \ + while (0) #endif /*********************************************************************** @@ -124,8 +126,8 @@ ** DESCRIPTION: ** Bit masking macros. XXX n must be <= 31 to be portable ***********************************************************************/ -#define JS_BIT(n) ((uint32_t)1 << (n)) -#define JS_BITMASK(n) (JS_BIT(n) - 1) +#define JS_BIT(n) ((uint32_t)1 << (n)) +#define JS_BITMASK(n) (JS_BIT(n) - 1) /*********************************************************************** ** MACROS: JS_HOWMANY @@ -133,68 +135,16 @@ ** DESCRIPTION: ** Commonly used macros for operations on compatible types. ***********************************************************************/ -#define JS_HOWMANY(x,y) (((x)+(y)-1)/(y)) -#define JS_ROUNDUP(x,y) (JS_HOWMANY(x,y)*(y)) - -#include "jscpucfg.h" - -/* - * Define JS_64BIT iff we are building in an environment with 64-bit - * addresses. - */ -#ifdef _MSC_VER -# if defined(_M_X64) || defined(_M_AMD64) -# define JS_64BIT -# endif -#elif defined(__GNUC__) -/* Additional GCC defines are when running on Solaris, AIX, and HPUX */ -# if defined(__x86_64__) || defined(__sparcv9) || \ - defined(__64BIT__) || defined(__LP64__) -# define JS_64BIT -# endif -#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* Sun Studio C/C++ */ -# if defined(__x86_64) || defined(__sparcv9) -# define JS_64BIT -# endif -#elif defined(__xlc__) || defined(__xlC__) /* IBM XL C/C++ */ -# if defined(__64BIT__) -# define JS_64BIT -# endif -#elif defined(__HP_cc) || defined(__HP_aCC) /* HP-UX cc/aCC */ -# if defined(__LP64__) -# define JS_64BIT -# endif -#else -# error "Implement me" -#endif - -/*********************************************************************** -** MACROS: JS_ARRAY_LENGTH -** JS_ARRAY_END -** DESCRIPTION: -** Macros to get the number of elements and the pointer to one past the -** last element of a C array. Use them like this: -** -** char16_t buf[10]; -** JSString* str; -** ... -** for (char16_t* s = buf; s != JS_ARRAY_END(buf); ++s) *s = ...; -** ... -** str = JS_NewStringCopyN(cx, buf, JS_ARRAY_LENGTH(buf)); -** ... -** -***********************************************************************/ - -#define JS_ARRAY_LENGTH(array) (sizeof (array) / sizeof (array)[0]) -#define JS_ARRAY_END(array) ((array) + JS_ARRAY_LENGTH(array)) +#define JS_HOWMANY(x, y) (((x) + (y)-1) / (y)) +#define JS_ROUNDUP(x, y) (JS_HOWMANY(x, y) * (y)) #define JS_BITS_PER_BYTE 8 #define JS_BITS_PER_BYTE_LOG2 3 #if defined(JS_64BIT) -# define JS_BITS_PER_WORD 64 +#define JS_BITS_PER_WORD 64 #else -# define JS_BITS_PER_WORD 32 +#define JS_BITS_PER_WORD 32 #endif /*********************************************************************** @@ -213,15 +163,15 @@ ** ***********************************************************************/ -#define JS_FUNC_TO_DATA_PTR(type, fun) (mozilla::BitwiseCast(fun)) -#define JS_DATA_TO_FUNC_PTR(type, ptr) (mozilla::BitwiseCast(ptr)) +#define JS_FUNC_TO_DATA_PTR(type, fun) (mozilla::BitwiseCast(fun)) +#define JS_DATA_TO_FUNC_PTR(type, ptr) (mozilla::BitwiseCast(ptr)) #ifdef __GNUC__ -# define JS_EXTENSION __extension__ -# define JS_EXTENSION_(s) __extension__ ({ s; }) +#define JS_EXTENSION __extension__ +#define JS_EXTENSION_(s) __extension__({ s; }) #else -# define JS_EXTENSION -# define JS_EXTENSION_(s) s +#define JS_EXTENSION +#define JS_EXTENSION_(s) s #endif #endif /* jstypes_h */ 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 @@ -1,40 +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 jsversion_h -#define jsversion_h - -/* - * JS Capability Macros. - */ -#define JS_HAS_STR_HTML_HELPERS 1 /* (no longer used) */ -#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */ -#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */ -#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */ -#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */ -#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */ -#define JS_HAS_CONST 1 /* (no longer used) */ -#define JS_HAS_FUN_EXPR_STMT 1 /* (no longer used) */ -#define JS_HAS_FOR_EACH_IN 1 /* has for each (lhs in iterable) */ -#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 /* (no longer used) */ -#define JS_HAS_EXPR_CLOSURES 1 /* has function (formals) listexpr */ - -/* (no longer used) */ -#define JS_HAS_NEW_GLOBAL_OBJECT 1 - -/* (no longer used) */ -#define JS_HAS_DESTRUCTURING_SHORTHAND (JS_HAS_DESTRUCTURING == 2) - -/* - * Feature for Object.prototype.__{define,lookup}{G,S}etter__ legacy support; - * support likely to be made opt-in at some future time. - */ -#define JS_OLD_GETTER_SETTER_METHODS 1 - -#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 @@ -1,382 +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 jswrapper_h -#define jswrapper_h - -#include "mozilla/Attributes.h" - -#include "js/Proxy.h" - -namespace js { - -/* - * Helper for Wrapper::New default options. - * - * Callers of Wrapper::New() who wish to specify a prototype for the created - * Wrapper, *MUST* construct a WrapperOptions with a JSContext. - */ -class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions { - public: - WrapperOptions() : ProxyOptions(false), - proto_() - {} - - explicit WrapperOptions(JSContext* cx) : ProxyOptions(false), - proto_() - { - proto_.emplace(cx); - } - - inline JSObject* proto() const; - WrapperOptions& setProto(JSObject* protoArg) { - MOZ_ASSERT(proto_); - *proto_ = protoArg; - return *this; - } - - private: - mozilla::Maybe proto_; -}; - -/* - * A wrapper is a proxy with a target object to which it generally forwards - * 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 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 { - CROSS_COMPARTMENT = 1 << 0, - LAST_USED_FLAG = CROSS_COMPARTMENT - }; - - static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler, - const WrapperOptions& options = WrapperOptions()); - - static JSObject* Renew(JSContext* cx, JSObject* existing, JSObject* obj, const Wrapper* handler); - - static const Wrapper* wrapperHandler(JSObject* wrapper); - - static JSObject* wrappedObject(JSObject* wrapper); - - unsigned flags() const { - return mFlags; - } - - static const char family; - static const Wrapper singleton; - static const Wrapper singletonWithPrototype; - - static JSObject* defaultProto; -}; - -inline JSObject* -WrapperOptions::proto() const -{ - return proto_ ? *proto_ : Wrapper::defaultProto; -} - -/* Base class for all cross compartment wrapper handlers. */ -class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper -{ - public: - 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; - virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, - ObjectOpResult& result) const override; - virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper, - AutoIdVector& props) const override; - virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id, - ObjectOpResult& result) const override; - virtual bool enumerate(JSContext* cx, HandleObject wrapper, 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 wrapper, - ObjectOpResult& result) const override; - virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override; - virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override; - virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver, - HandleId id, MutableHandleValue vp) const override; - virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result) const override; - virtual bool call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override; - virtual bool construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override; - - /* SpiderMonkey extensions. */ - virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - 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 nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, - const CallArgs& args) const override; - virtual bool hasInstance(JSContext* cx, HandleObject wrapper, MutableHandleValue v, - bool* bp) const override; - virtual const char* className(JSContext* cx, HandleObject proxy) const override; - virtual JSString* fun_toString(JSContext* cx, HandleObject wrapper, - 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; - - // Allocate CrossCompartmentWrappers in the nursery. - virtual bool canNurseryAllocate() const override { return true; } - - static const CrossCompartmentWrapper singleton; - static const CrossCompartmentWrapper singletonWithPrototype; -}; - -class JS_FRIEND_API(OpaqueCrossCompartmentWrapper) : public CrossCompartmentWrapper -{ - public: - explicit constexpr OpaqueCrossCompartmentWrapper() : CrossCompartmentWrapper(0) - { } - - /* Standard internal methods. */ - virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const override; - virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, - ObjectOpResult& result) const override; - virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper, - AutoIdVector& props) const override; - virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id, - ObjectOpResult& result) const override; - virtual bool enumerate(JSContext* cx, HandleObject wrapper, - MutableHandleObject objp) const override; - virtual bool getPrototype(JSContext* cx, HandleObject wrapper, - 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, - ObjectOpResult& result) const override; - virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override; - virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id, - bool* bp) const override; - virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver, - HandleId id, MutableHandleValue vp) const override; - virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result) const override; - virtual bool call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override; - virtual bool construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override; - - /* SpiderMonkey extensions. */ - virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - 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, 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; - virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const override; - - static const OpaqueCrossCompartmentWrapper singleton; -}; - -/* - * Base class for security wrappers. A security wrapper is potentially hiding - * all or part of some wrapped object thus SecurityWrapper defaults to denying - * access to the wrappee. This is the opposite of Wrapper which tries to be - * completely transparent. - * - * NB: Currently, only a few ProxyHandler operations are overridden to deny - * access, relying on derived SecurityWrapper to block access when necessary. - */ -template -class JS_FRIEND_API(SecurityWrapper) : public Base -{ - public: - explicit constexpr SecurityWrapper(unsigned flags, bool hasPrototype = false) - : Base(flags, hasPrototype, /* hasSecurityPolicy = */ true) - { } - - virtual bool enter(JSContext* cx, HandleObject wrapper, HandleId id, Wrapper::Action act, - bool* bp) const override; - - virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, - ObjectOpResult& result) const override; - virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override; - virtual bool preventExtensions(JSContext* cx, HandleObject wrapper, - ObjectOpResult& result) 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 nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, - const CallArgs& args) 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; - - // Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded - // against. - - virtual bool watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, - JS::HandleObject callable) const override; - virtual bool unwatch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id) const override; - - /* - * Allow our subclasses to select the superclass behavior they want without - * needing to specify an exact superclass. - */ - typedef Base Permissive; - typedef SecurityWrapper Restrictive; -}; - -typedef SecurityWrapper CrossCompartmentSecurityWrapper; - -extern JSObject* -TransparentObjectWrapper(JSContext* cx, HandleObject existing, HandleObject obj); - -inline bool -IsWrapper(JSObject* obj) -{ - return IsProxy(obj) && GetProxyHandler(obj)->family() == &Wrapper::family; -} - -// Given a JSObject, returns that object stripped of wrappers. If -// stopAtWindowProxy is true, then this returns the WindowProxy if it was -// previously wrapped. Otherwise, this returns the first object for -// which JSObject::isWrapper returns false. -JS_FRIEND_API(JSObject*) -UncheckedUnwrap(JSObject* obj, bool stopAtWindowProxy = true, unsigned* flagsp = nullptr); - -// Given a JSObject, returns that object stripped of wrappers. At each stage, -// the security wrapper has the opportunity to veto the unwrap. If -// stopAtWindowProxy is true, then this returns the WindowProxy if it was -// previously wrapped. -JS_FRIEND_API(JSObject*) -CheckedUnwrap(JSObject* obj, bool stopAtWindowProxy = true); - -// Unwrap only the outermost security wrapper, with the same semantics as -// above. This is the checked version of Wrapper::wrappedObject. -JS_FRIEND_API(JSObject*) -UnwrapOneChecked(JSObject* obj, bool stopAtWindowProxy = true); - -JS_FRIEND_API(bool) -IsCrossCompartmentWrapper(JSObject* obj); - -JS_FRIEND_API(void) -NukeCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper); - -void -RemapWrapper(JSContext* cx, JSObject* wobj, JSObject* newTarget); - -JS_FRIEND_API(bool) -RemapAllWrappersForObject(JSContext* cx, JSObject* oldTarget, - JSObject* newTarget); - -// API to recompute all cross-compartment wrappers whose source and target -// match the given filters. -JS_FRIEND_API(bool) -RecomputeWrappers(JSContext* cx, const CompartmentFilter& sourceFilter, - const CompartmentFilter& targetFilter); - -} /* namespace js */ - -#endif /* jswrapper_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/malloc_decls.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/malloc_decls.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/malloc_decls.h @@ -0,0 +1,125 @@ +/* -*- 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/. */ + +// Helper header to declare all the supported malloc functions. +// MALLOC_DECL arguments are: +// - function name +// - return type +// - argument types + +#ifndef malloc_decls_h +#define malloc_decls_h + +#include "mozjemalloc_types.h" + +#define MALLOC_FUNCS_MALLOC_BASE 1 +#define MALLOC_FUNCS_MALLOC_EXTRA 2 +#define MALLOC_FUNCS_MALLOC \ + (MALLOC_FUNCS_MALLOC_BASE | MALLOC_FUNCS_MALLOC_EXTRA) +#define MALLOC_FUNCS_JEMALLOC 4 +#define MALLOC_FUNCS_ARENA_BASE 8 +#define MALLOC_FUNCS_ARENA_ALLOC 16 +#define MALLOC_FUNCS_ARENA (MALLOC_FUNCS_ARENA_BASE | MALLOC_FUNCS_ARENA_ALLOC) +#define MALLOC_FUNCS_ALL \ + (MALLOC_FUNCS_MALLOC | MALLOC_FUNCS_JEMALLOC | MALLOC_FUNCS_ARENA) + +#endif // malloc_decls_h + +#ifndef MALLOC_FUNCS +#define MALLOC_FUNCS MALLOC_FUNCS_ALL +#endif + +#ifdef MALLOC_DECL +#if MALLOC_FUNCS & MALLOC_FUNCS_MALLOC_BASE +MALLOC_DECL(malloc, void*, size_t) +MALLOC_DECL(calloc, void*, size_t, size_t) +MALLOC_DECL(realloc, void*, void*, size_t) +MALLOC_DECL(free, void, void*) +MALLOC_DECL(memalign, void*, size_t, size_t) +#endif +#if MALLOC_FUNCS & MALLOC_FUNCS_MALLOC_EXTRA +MALLOC_DECL(posix_memalign, int, void**, size_t, size_t) +MALLOC_DECL(aligned_alloc, void*, size_t, size_t) +MALLOC_DECL(valloc, void*, size_t) +MALLOC_DECL(malloc_usable_size, size_t, usable_ptr_t) +MALLOC_DECL(malloc_good_size, size_t, size_t) +#endif +#if MALLOC_FUNCS & MALLOC_FUNCS_JEMALLOC +MALLOC_DECL(jemalloc_stats, void, jemalloc_stats_t*) + +// On some operating systems (Mac), we use madvise(MADV_FREE) to hand pages +// back to the operating system. On Mac, the operating system doesn't take +// this memory back immediately; instead, the OS takes it back only when the +// machine is running out of physical memory. +// +// This is great from the standpoint of efficiency, but it makes measuring our +// actual RSS difficult, because pages which we've MADV_FREE'd shouldn't count +// against our RSS. +// +// This function explicitly purges any MADV_FREE'd pages from physical memory, +// causing our reported RSS match the amount of memory we're actually using. +// +// Note that this call is expensive in two ways. First, it may be slow to +// execute, because it may make a number of slow syscalls to free memory. This +// function holds the big jemalloc locks, so basically all threads are blocked +// while this function runs. +// +// This function is also expensive in that the next time we go to access a page +// which we've just explicitly decommitted, the operating system has to attach +// to it a physical page! If we hadn't run this function, the OS would have +// less work to do. +// +// If MALLOC_DOUBLE_PURGE is not defined, this function does nothing. +MALLOC_DECL(jemalloc_purge_freed_pages, void) + +// Free all unused dirty pages in all arenas. Calling this function will slow +// down subsequent allocations so it is recommended to use it only when +// memory needs to be reclaimed at all costs (see bug 805855). This function +// provides functionality similar to mallctl("arenas.purge") in jemalloc 3. +MALLOC_DECL(jemalloc_free_dirty_pages, void) + +// Opt in or out of a thread local arena (bool argument is whether to opt-in +// (true) or out (false)). +MALLOC_DECL(jemalloc_thread_local_arena, void, bool) + +// Provide information about any allocation enclosing the given address. +MALLOC_DECL(jemalloc_ptr_info, void, const void*, jemalloc_ptr_info_t*) +#endif + +#if MALLOC_FUNCS & MALLOC_FUNCS_ARENA_BASE + +// Creates a separate arena, and returns its id, valid to use with moz_arena_* +// functions. A helper is provided in mozmemory.h that doesn't take any +// arena_params_t: moz_create_arena. +MALLOC_DECL(moz_create_arena_with_params, arena_id_t, arena_params_t*) + +// Dispose of the given arena. Subsequent uses of the arena will crash. +// Passing an invalid id (inexistent or already disposed) to this function +// will crash. +MALLOC_DECL(moz_dispose_arena, void, arena_id_t) +#endif + +#if MALLOC_FUNCS & MALLOC_FUNCS_ARENA_ALLOC +// Same as the functions without the moz_arena_ prefix, but using arenas +// created with moz_create_arena. +// The contract, even if not enforced at runtime in some configurations, +// is that moz_arena_realloc and moz_arena_free will crash if the given +// arena doesn't own the given pointer. All functions will crash if the +// arena id is invalid. +// Although discouraged, plain realloc and free can still be used on +// pointers allocated with these functions. Realloc will properly keep +// new pointers in the same arena as the original. +MALLOC_DECL(moz_arena_malloc, void*, arena_id_t, size_t) +MALLOC_DECL(moz_arena_calloc, void*, arena_id_t, size_t, size_t) +MALLOC_DECL(moz_arena_realloc, void*, arena_id_t, void*, size_t) +MALLOC_DECL(moz_arena_free, void, arena_id_t, void*) +MALLOC_DECL(moz_arena_memalign, void*, arena_id_t, size_t, size_t) +#endif + +#endif // MALLOC_DECL + +#undef MALLOC_DECL +#undef MALLOC_FUNCS 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 @@ -19,21 +19,38 @@ * This class, and the corresponding macro MOZ_ALIGNOF, figures out how many * bytes of alignment a given type needs. */ -template -class AlignmentFinder -{ - struct Aligner - { +template +class AlignmentFinder { + struct Aligner { char mChar; T mT; }; -public: + public: static const size_t alignment = sizeof(Aligner) - sizeof(T); }; #define MOZ_ALIGNOF(T) mozilla::AlignmentFinder::alignment +namespace detail { +template +struct AlignasHelper { + T mT; +}; +} // namespace detail + +/* + * Use this instead of alignof to align struct field as if it is inside + * a struct. On some platforms, there exist types which have different + * alignment between when it is used on its own and when it is used on + * a struct field. + * + * Known examples are 64bit types (uint64_t, double) on 32bit Linux, + * where they have 8byte alignment on their own, and 4byte alignment + * when in struct. + */ +#define MOZ_ALIGNAS_IN_STRUCT(T) alignas(mozilla::detail::AlignasHelper) + /* * Declare the MOZ_ALIGNED_DECL macro for declaring aligned types. * @@ -45,23 +62,21 @@ */ #if defined(__GNUC__) -# define MOZ_ALIGNED_DECL(_type, _align) \ - _type __attribute__((aligned(_align))) +#define MOZ_ALIGNED_DECL(_type, _align) _type __attribute__((aligned(_align))) #elif defined(_MSC_VER) -# define MOZ_ALIGNED_DECL(_type, _align) \ - __declspec(align(_align)) _type +#define MOZ_ALIGNED_DECL(_type, _align) __declspec(align(_align)) _type #else -# warning "We don't know how to align variables on this compiler." -# define MOZ_ALIGNED_DECL(_type, _align) _type +#warning "We don't know how to align variables on this compiler." +#define MOZ_ALIGNED_DECL(_type, _align) _type #endif /* * AlignedElem is a structure whose alignment is guaranteed to be at least N * bytes. * - * We support 1, 2, 4, 8, and 16-bit alignment. + * We support 1, 2, 4, 8, and 16-byte alignment. */ -template +template struct AlignedElem; /* @@ -69,71 +84,34 @@ * __attribute__((aligned(foo))) where foo is a template parameter. */ -template<> -struct AlignedElem<1> -{ +template <> +struct AlignedElem<1> { MOZ_ALIGNED_DECL(uint8_t elem, 1); }; -template<> -struct AlignedElem<2> -{ +template <> +struct AlignedElem<2> { MOZ_ALIGNED_DECL(uint8_t elem, 2); }; -template<> -struct AlignedElem<4> -{ +template <> +struct AlignedElem<4> { MOZ_ALIGNED_DECL(uint8_t elem, 4); }; -template<> -struct AlignedElem<8> -{ +template <> +struct AlignedElem<8> { MOZ_ALIGNED_DECL(uint8_t elem, 8); }; -template<> -struct AlignedElem<16> -{ +template <> +struct AlignedElem<16> { MOZ_ALIGNED_DECL(uint8_t elem, 16); }; -/* - * This utility pales in comparison to Boost's aligned_storage. The utility - * simply assumes that uint64_t is enough alignment for anyone. This may need - * to be extended one day... - * - * As an important side effect, pulling the storage into this template is - * enough obfuscation to confuse gcc's strict-aliasing analysis into not giving - * false negatives when we cast from the char buffer to whatever type we've - * constructed using the bytes. - */ -template -struct AlignedStorage -{ - union U - { - char mBytes[Nbytes]; - uint64_t mDummy; - } u; - - 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 -struct MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS AlignedStorage2 -{ - union U - { +template +struct MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS AlignedStorage2 { + union U { char mBytes[sizeof(T)]; uint64_t mDummy; } u; 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 @@ -13,6 +13,7 @@ #define mozilla_AllocPolicy_h #include "mozilla/Attributes.h" +#include "mozilla/Assertions.h" #include "mozilla/TemplateLib.h" #include @@ -68,12 +69,10 @@ * A policy that straightforwardly uses malloc/calloc/realloc/free and adds no * extra behaviors. */ -class MallocAllocPolicy -{ -public: +class MallocAllocPolicy { + public: template - T* maybe_pod_malloc(size_t aNumElems) - { + T* maybe_pod_malloc(size_t aNumElems) { if (aNumElems & mozilla::tl::MulOverflowMask::value) { return nullptr; } @@ -81,14 +80,12 @@ } template - T* maybe_pod_calloc(size_t aNumElems) - { + T* maybe_pod_calloc(size_t aNumElems) { return static_cast(calloc(aNumElems, sizeof(T))); } template - T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) - { + T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { if (aNewSize & mozilla::tl::MulOverflowMask::value) { return nullptr; } @@ -96,38 +93,73 @@ } template - T* pod_malloc(size_t aNumElems) - { + T* pod_malloc(size_t aNumElems) { return maybe_pod_malloc(aNumElems); } template - T* pod_calloc(size_t aNumElems) - { + T* pod_calloc(size_t aNumElems) { return maybe_pod_calloc(aNumElems); } template - T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) - { + T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { return maybe_pod_realloc(aPtr, aOldSize, aNewSize); } - void free_(void* aPtr) - { - free(aPtr); + void free_(void* aPtr) { free(aPtr); } + + void reportAllocOverflow() const {} + + MOZ_MUST_USE bool checkSimulatedOOM() const { return true; } +}; + +/* + * A policy which always fails to allocate memory, returning nullptr. Methods + * which expect an existing allocation assert. + * + * This type should be used in situations where you want to use a MFBT type with + * inline storage, and don't want to allow it to allocate on the heap. + */ +class NeverAllocPolicy { + public: + template + T* maybe_pod_malloc(size_t aNumElems) { + return nullptr; + } + + template + T* maybe_pod_calloc(size_t aNumElems) { + return nullptr; } - void reportAllocOverflow() const - { + template + T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { + MOZ_CRASH("NeverAllocPolicy::maybe_pod_realloc"); + } + + template + T* pod_malloc(size_t aNumElems) { + return nullptr; } - MOZ_MUST_USE bool checkSimulatedOOM() const - { - return true; + template + T* pod_calloc(size_t aNumElems) { + return nullptr; } + + template + T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { + MOZ_CRASH("NeverAllocPolicy::pod_realloc"); + } + + void free_(void* aPtr) { MOZ_CRASH("NeverAllocPolicy::free_"); } + + void reportAllocOverflow() const {} + + MOZ_MUST_USE bool checkSimulatedOOM() const { return true; } }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_AllocPolicy_h */ 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 @@ -17,7 +17,7 @@ struct unused_t; -} // namespace mozilla +} // namespace mozilla /** * already_AddRefed cooperates with reference counting smart pointers to enable @@ -27,10 +27,17 @@ * * TODO Move already_AddRefed to namespace mozilla. This has not yet been done * because of the sheer number of usages of already_AddRefed. + * + * When should you use already_AddRefed<>? + * * Ensure a consumer takes ownership of a reference + * * Pass ownership without calling AddRef/Release (sometimes required in + * off-main-thread code) + * * The ref pointer type you're using doesn't support move construction + * + * Otherwise, use Move(RefPtr/nsCOMPtr/etc). */ -template -struct MOZ_MUST_USE_TYPE MOZ_NON_AUTOABLE already_AddRefed -{ +template +struct MOZ_TEMPORARY_CLASS MOZ_MUST_USE_TYPE MOZ_NON_AUTOABLE already_AddRefed { /* * We want to allow returning nullptr from functions returning * already_AddRefed, for simplicity. But we also don't want to allow @@ -59,21 +66,61 @@ */ already_AddRefed() : mRawPtr(nullptr) {} - // The return and argument types here are arbitrarily selected so no - // corresponding member function exists. - typedef void (already_AddRefed::* MatchNullptr)(double, float); - MOZ_IMPLICIT already_AddRefed(MatchNullptr aRawPtr) : mRawPtr(nullptr) {} + MOZ_IMPLICIT already_AddRefed(decltype(nullptr)) : mRawPtr(nullptr) {} explicit already_AddRefed(T* aRawPtr) : mRawPtr(aRawPtr) {} - // Disallow copy constructor and copy assignment operator: move semantics used instead. + // Disallow copy constructor and copy assignment operator: move semantics used + // instead. already_AddRefed(const already_AddRefed& aOther) = delete; already_AddRefed& operator=(const already_AddRefed& aOther) = delete; - already_AddRefed(already_AddRefed&& aOther) : mRawPtr(aOther.take()) {} + // WARNING: sketchiness ahead. + // + // The x86-64 ABI for Unix-like operating systems requires structures to be + // returned via invisible reference if they are non-trivial for the purposes + // of calls according to the C++ ABI[1]. For our consideration here, that + // means that if we have a non-trivial move constructor or destructor, + // already_AddRefed must be returned by invisible reference. But + // already_AddRefed is small enough and so commonly used that it would be + // beneficial to return it via registers instead. So we need to figure out + // a way to make the move constructor and the destructor trivial. + // + // Our destructor is normally non-trivial, because it asserts that the + // stored pointer has been taken by somebody else prior to destruction. + // However, since the assert in question is compiled only for DEBUG builds, + // we can make the destructor trivial in non-DEBUG builds by simply defining + // it with `= default`. + // + // We now have to make the move constructor trivial as well. It is normally + // non-trivial, because the incoming object has its pointer null-ed during + // the move. This null-ing is done to satisfy the assert in the destructor. + // But since that destructor has no assert in non-DEBUG builds, the clearing + // is unnecessary in such builds; all we really need to perform is a copy of + // the pointer from the incoming object. So we can let the compiler define + // a trivial move constructor for us, and already_AddRefed can now be + // returned in registers rather than needing to allocate a stack slot for + // an invisible reference. + // + // The above considerations apply to Unix-like operating systems only; the + // conditions for the same optimization to apply on x86-64 Windows are much + // more strigent and are basically impossible for already_AddRefed to + // satisfy[2]. But we do get some benefit from this optimization on Windows + // because we removed the nulling of the pointer during the move, so that's + // a codesize win. + // + // [1] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#non-trivial + // [2] https://docs.microsoft.com/en-us/cpp/build/return-values-cpp + + already_AddRefed(already_AddRefed&& aOther) +#ifdef DEBUG + : mRawPtr(aOther.take()) { + } +#else + = default; +#endif - already_AddRefed& operator=(already_AddRefed&& aOther) - { + already_AddRefed& operator=(already_AddRefed&& aOther) { mRawPtr = aOther.take(); return *this; } @@ -96,23 +143,29 @@ * Note that nsRefPtr is the XPCOM reference counting smart pointer class. */ template - MOZ_IMPLICIT already_AddRefed(already_AddRefed&& aOther) : mRawPtr(aOther.take()) {} + MOZ_IMPLICIT already_AddRefed(already_AddRefed&& aOther) + : mRawPtr(aOther.take()) {} - ~already_AddRefed() { MOZ_ASSERT(!mRawPtr); } + ~already_AddRefed() +#ifdef DEBUG + { + MOZ_ASSERT(!mRawPtr); + } +#else + = default; +#endif // Specialize the unused operator<< for already_AddRefed, to allow // nsCOMPtr foo; // Unused << foo.forget(); // Note that nsCOMPtr is the XPCOM reference counting smart pointer class. friend void operator<<(const mozilla::unused_t& aUnused, - const already_AddRefed& aRhs) - { + const already_AddRefed& aRhs) { auto mutableAlreadyAddRefed = const_cast*>(&aRhs); aUnused << mutableAlreadyAddRefed->take(); } - MOZ_MUST_USE T* take() - { + MOZ_MUST_USE T* take() { T* rawPtr = mRawPtr; mRawPtr = nullptr; return rawPtr; @@ -132,16 +185,15 @@ * return F().downcast(); * } */ - template - already_AddRefed downcast() - { + template + already_AddRefed downcast() { U* tmp = static_cast(mRawPtr); mRawPtr = nullptr; return already_AddRefed(tmp); } -private: + private: T* MOZ_OWNING_REF mRawPtr; }; -#endif // AlreadyAddRefed_h +#endif // AlreadyAddRefed_h 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 @@ -18,37 +18,42 @@ namespace mozilla { -template -class Array -{ +template +class Array { T mArr[Length]; -public: + public: Array() {} template - MOZ_IMPLICIT Array(Args&&... aArgs) - : mArr{mozilla::Forward(aArgs)...} - { + 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"); + "The number of arguments should be equal to the template " + "parameter Length"); } - T& operator[](size_t aIndex) - { + T& operator[](size_t aIndex) { MOZ_ASSERT(aIndex < Length); return mArr[aIndex]; } - const T& operator[](size_t aIndex) const - { + const T& operator[](size_t aIndex) const { MOZ_ASSERT(aIndex < Length); return mArr[aIndex]; } - typedef T* iterator; - typedef const T* const_iterator; - typedef ReverseIterator reverse_iterator; + bool operator==(const Array& aOther) const { + for (size_t i = 0; i < Length; i++) { + if (mArr[i] != aOther[i]) { + return false; + } + } + return true; + } + + typedef T* iterator; + typedef const T* const_iterator; + typedef ReverseIterator reverse_iterator; typedef ReverseIterator const_reverse_iterator; // Methods for range-based for loops. @@ -61,28 +66,27 @@ // Methods for reverse iterating. reverse_iterator rbegin() { return reverse_iterator(end()); } - const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } const_reverse_iterator crbegin() const { return rbegin(); } reverse_iterator rend() { return reverse_iterator(begin()); } - const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } const_reverse_iterator crend() const { return rend(); } }; -template -class Array -{ -public: - T& operator[](size_t aIndex) - { - MOZ_CRASH("indexing into zero-length array"); - } +template +class Array { + public: + T& operator[](size_t aIndex) { MOZ_CRASH("indexing into zero-length array"); } - const T& operator[](size_t aIndex) const - { + const T& operator[](size_t aIndex) const { MOZ_CRASH("indexing into zero-length array"); } }; -} /* namespace mozilla */ +} /* namespace mozilla */ #endif /* mozilla_Array_h */ 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 @@ -37,10 +37,8 @@ * with the wrong sign even when the correct scaled distance would fit in a * ptrdiff_t. */ -template -MOZ_ALWAYS_INLINE size_t -PointerRangeSize(T* aBegin, T* aEnd) -{ +template +MOZ_ALWAYS_INLINE size_t PointerRangeSize(T* aBegin, T* aEnd) { MOZ_ASSERT(aEnd >= aBegin); return (size_t(aEnd) - size_t(aBegin)) / sizeof(T); } @@ -51,24 +49,18 @@ * * Beware of the implicit trailing '\0' when using this with string constants. */ -template -constexpr size_t -ArrayLength(T (&aArr)[N]) -{ +template +constexpr size_t ArrayLength(T (&aArr)[N]) { return N; } -template -constexpr size_t -ArrayLength(const Array& aArr) -{ +template +constexpr size_t ArrayLength(const Array& aArr) { return N; } -template -constexpr size_t -ArrayLength(const EnumeratedArray& aArr) -{ +template +constexpr size_t ArrayLength(const EnumeratedArray& aArr) { return size_t(N); } @@ -77,51 +69,38 @@ * * Beware of the implicit trailing '\0' when using this with string constants. */ -template -constexpr T* -ArrayEnd(T (&aArr)[N]) -{ +template +constexpr T* ArrayEnd(T (&aArr)[N]) { return aArr + ArrayLength(aArr); } -template -constexpr T* -ArrayEnd(Array& aArr) -{ +template +constexpr T* ArrayEnd(Array& aArr) { return &aArr[0] + ArrayLength(aArr); } -template -constexpr const T* -ArrayEnd(const Array& aArr) -{ +template +constexpr const T* ArrayEnd(const Array& aArr) { return &aArr[0] + ArrayLength(aArr); } namespace detail { -template::value>> -struct AlignedChecker -{ - static void - test(const Pointee* aPtr) - { +template ::value>> +struct AlignedChecker { + static void test(const Pointee* aPtr) { MOZ_ASSERT((uintptr_t(aPtr) % MOZ_ALIGNOF(AlignType)) == 0, "performing a range-check with a misaligned pointer"); } }; -template -struct AlignedChecker -{ - static void - test(const Pointee* aPtr) - { - } +template +struct AlignedChecker { + static void test(const Pointee* aPtr) {} }; -} // namespace detail +} // namespace detail /** * Determines whether |aPtr| points at an object in the range [aBegin, aEnd). @@ -136,13 +115,11 @@ * case no argument is required to be aligned (obviously, as void* implies no * particular alignment). */ -template -inline typename EnableIf::value || - IsBaseOf::value || - IsVoid::value, +template +inline typename EnableIf::value || IsBaseOf::value || + IsVoid::value, bool>::Type -IsInRange(const T* aPtr, const U* aBegin, const U* aEnd) -{ +IsInRange(const T* aPtr, const U* aBegin, const U* aEnd) { MOZ_ASSERT(aBegin <= aEnd); detail::AlignedChecker::test(aPtr); detail::AlignedChecker::test(aBegin); @@ -156,12 +133,9 @@ * uintptr_t values. As above, |aPtr| must be aligned, and |aBegin| and |aEnd| * must be aligned with respect to |T|. */ -template -inline bool -IsInRange(const T* aPtr, uintptr_t aBegin, uintptr_t aEnd) -{ - return IsInRange(aPtr, - reinterpret_cast(aBegin), +template +inline bool IsInRange(const T* aPtr, uintptr_t aBegin, uintptr_t aEnd) { + return IsInRange(aPtr, reinterpret_cast(aBegin), reinterpret_cast(aEnd)); } @@ -186,9 +160,10 @@ * can't call ArrayLength() when it is not a C++11 constexpr function. */ #ifdef __cplusplus -# define MOZ_ARRAY_LENGTH(array) sizeof(mozilla::detail::ArrayLengthHelper(array)) +#define MOZ_ARRAY_LENGTH(array) \ + sizeof(mozilla::detail::ArrayLengthHelper(array)) #else -# define MOZ_ARRAY_LENGTH(array) (sizeof(array)/sizeof((array)[0])) +#define MOZ_ARRAY_LENGTH(array) (sizeof(array) / sizeof((array)[0])) #endif #endif /* mozilla_ArrayUtils_h */ 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 @@ -23,7 +23,6 @@ #include "nsTraceRefcnt.h" #endif -#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 @@ -34,40 +33,38 @@ extern MFBT_DATA const char* gMozCrashReason; MOZ_END_EXTERN_C -static inline void -AnnotateMozCrashReason(const char* reason) -{ +#if !defined(DEBUG) && \ + (defined(MOZ_HAS_MOZGLUE) || defined(MOZILLA_INTERNAL_API)) +static inline void AnnotateMozCrashReason(const char* reason) { gMozCrashReason = reason; } -# define MOZ_CRASH_ANNOTATE(...) AnnotateMozCrashReason(__VA_ARGS__) +#define MOZ_CRASH_ANNOTATE(...) AnnotateMozCrashReason(__VA_ARGS__) #else -# define MOZ_CRASH_ANNOTATE(...) do { /* nothing */ } while (0) +#define MOZ_CRASH_ANNOTATE(...) \ + do { /* nothing */ \ + } while (false) #endif #include #include #include -#ifdef WIN32 - /* - * TerminateProcess and GetCurrentProcess are defined in , which - * further depends on . We hardcode these few definitions manually - * because those headers clutter the global namespace with a significant - * number of undesired macros and symbols. - */ -# ifdef __cplusplus -extern "C" { -# endif -__declspec(dllimport) int __stdcall -TerminateProcess(void* hProcess, unsigned int uExitCode); +#ifdef _MSC_VER +/* + * TerminateProcess and GetCurrentProcess are defined in , which + * further depends on . We hardcode these few definitions manually + * because those headers clutter the global namespace with a significant + * number of undesired macros and symbols. + */ +MOZ_BEGIN_EXTERN_C +__declspec(dllimport) int __stdcall TerminateProcess(void* hProcess, + unsigned int uExitCode); __declspec(dllimport) void* __stdcall GetCurrentProcess(void); -# ifdef __cplusplus -} -# endif +MOZ_END_EXTERN_C #else -# include +#include #endif #ifdef ANDROID -# include +#include #endif /* @@ -89,62 +86,66 @@ * typedef could be used. */ #ifndef __cplusplus - /* - * Some of the definitions below create an otherwise-unused typedef. This - * triggers compiler warnings with some versions of gcc, so mark the typedefs - * as permissibly-unused to disable the warnings. - */ -# if defined(__GNUC__) -# define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) -# else -# define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE /* nothing */ -# endif -# define MOZ_STATIC_ASSERT_GLUE1(x, y) x##y -# define MOZ_STATIC_ASSERT_GLUE(x, y) MOZ_STATIC_ASSERT_GLUE1(x, y) -# if defined(__SUNPRO_CC) - /* - * The Sun Studio C++ compiler is buggy when declaring, inside a function, - * another extern'd function with an array argument whose length contains a - * sizeof, triggering the error message "sizeof expression not accepted as - * size of array parameter". This bug (6688515, not public yet) would hit - * defining moz_static_assert as a function, so we always define an extern - * array for Sun Studio. - * - * We include the line number in the symbol name in a best-effort attempt - * to avoid conflicts (see below). - */ -# define MOZ_STATIC_ASSERT(cond, reason) \ - extern char MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)[(cond) ? 1 : -1] -# elif defined(__COUNTER__) - /* - * If there was no preferred alternative, use a compiler-agnostic version. - * - * Note that the non-__COUNTER__ version has a bug in C++: it can't be used - * in both |extern "C"| and normal C++ in the same translation unit. (Alas - * |extern "C"| isn't allowed in a function.) The only affected compiler - * we really care about is gcc 4.2. For that compiler and others like it, - * we include the line number in the function name to do the best we can to - * avoid conflicts. These should be rare: a conflict would require use of - * MOZ_STATIC_ASSERT on the same line in separate files in the same - * translation unit, *and* the uses would have to be in code with - * different linkage, *and* the first observed use must be in C++-linkage - * code. - */ -# define MOZ_STATIC_ASSERT(cond, reason) \ - typedef int MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __COUNTER__)[(cond) ? 1 : -1] MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE -# else -# define MOZ_STATIC_ASSERT(cond, reason) \ - extern void MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)(int arg[(cond) ? 1 : -1]) MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE -# endif +/* + * Some of the definitions below create an otherwise-unused typedef. This + * triggers compiler warnings with some versions of gcc, so mark the typedefs + * as permissibly-unused to disable the warnings. + */ +#if defined(__GNUC__) +#define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) +#else +#define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE /* nothing */ +#endif +#define MOZ_STATIC_ASSERT_GLUE1(x, y) x##y +#define MOZ_STATIC_ASSERT_GLUE(x, y) MOZ_STATIC_ASSERT_GLUE1(x, y) +#if defined(__SUNPRO_CC) +/* + * The Sun Studio C++ compiler is buggy when declaring, inside a function, + * another extern'd function with an array argument whose length contains a + * sizeof, triggering the error message "sizeof expression not accepted as + * size of array parameter". This bug (6688515, not public yet) would hit + * defining moz_static_assert as a function, so we always define an extern + * array for Sun Studio. + * + * We include the line number in the symbol name in a best-effort attempt + * to avoid conflicts (see below). + */ +#define MOZ_STATIC_ASSERT(cond, reason) \ + extern char MOZ_STATIC_ASSERT_GLUE(moz_static_assert, \ + __LINE__)[(cond) ? 1 : -1] +#elif defined(__COUNTER__) +/* + * If there was no preferred alternative, use a compiler-agnostic version. + * + * Note that the non-__COUNTER__ version has a bug in C++: it can't be used + * in both |extern "C"| and normal C++ in the same translation unit. (Alas + * |extern "C"| isn't allowed in a function.) The only affected compiler + * we really care about is gcc 4.2. For that compiler and others like it, + * we include the line number in the function name to do the best we can to + * avoid conflicts. These should be rare: a conflict would require use of + * MOZ_STATIC_ASSERT on the same line in separate files in the same + * translation unit, *and* the uses would have to be in code with + * different linkage, *and* the first observed use must be in C++-linkage + * code. + */ +#define MOZ_STATIC_ASSERT(cond, reason) \ + typedef int MOZ_STATIC_ASSERT_GLUE( \ + moz_static_assert, \ + __COUNTER__)[(cond) ? 1 : -1] MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE +#else +#define MOZ_STATIC_ASSERT(cond, reason) \ + extern void MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)( \ + int arg[(cond) ? 1 : -1]) MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE +#endif -#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) MOZ_STATIC_ASSERT(!(cond) || (expr), reason) +#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) \ + MOZ_STATIC_ASSERT(!(cond) || (expr), reason) #else -#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) static_assert(!(cond) || (expr), reason) +#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) \ + static_assert(!(cond) || (expr), reason) #endif -#ifdef __cplusplus -extern "C" { -#endif +MOZ_BEGIN_EXTERN_C /* * Prints |aStr| as an assertion failure (using aFilename and aLine as the @@ -154,27 +155,25 @@ * method is primarily for internal use in this header, and only secondarily * for use in implementing release-build assertions. */ -static MOZ_COLD MOZ_ALWAYS_INLINE void -MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, int aLine) - MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS -{ +MOZ_MAYBE_UNUSED static MOZ_COLD MOZ_NEVER_INLINE void +MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, + int aLine) MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS { #ifdef ANDROID __android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert", - "Assertion failure: %s, at %s:%d\n", - aStr, aFilename, aLine); + "Assertion failure: %s, at %s:%d\n", aStr, aFilename, + aLine); #else fprintf(stderr, "Assertion failure: %s, at %s:%d\n", aStr, aFilename, aLine); -#if defined (MOZ_DUMP_ASSERTION_STACK) +#if defined(MOZ_DUMP_ASSERTION_STACK) nsTraceRefcnt::WalkTheStack(stderr); #endif fflush(stderr); #endif } -static MOZ_COLD MOZ_ALWAYS_INLINE void -MOZ_ReportCrash(const char* aStr, const char* aFilename, int aLine) - MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS -{ +MOZ_MAYBE_UNUSED static MOZ_COLD MOZ_NEVER_INLINE void MOZ_ReportCrash( + const char* aStr, const char* aFilename, + int aLine) MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS { #ifdef ANDROID __android_log_print(ANDROID_LOG_FATAL, "MOZ_CRASH", "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine); @@ -192,62 +191,53 @@ * call MOZ_CRASH instead. */ #if defined(_MSC_VER) - /* - * On MSVC use the __debugbreak compiler intrinsic, which produces an inline - * (not nested in a system function) breakpoint. This distinctively invokes - * Breakpad without requiring system library symbols on all stack-processing - * machines, as a nested breakpoint would require. - * - * We use TerminateProcess with the exit code aborting would generate - * because we don't want to invoke atexit handlers, destructors, library - * unload handlers, and so on when our process might be in a compromised - * state. - * - * We don't use abort() because it'd cause Windows to annoyingly pop up the - * process error dialog multiple times. See bug 345118 and bug 426163. - * - * We follow TerminateProcess() with a call to MOZ_NoReturn() so that the - * compiler doesn't hassle us to provide a return statement after a - * MOZ_REALLY_CRASH() call. - * - * (Technically these are Windows requirements, not MSVC requirements. But - * practically you need MSVC for debugging, and we only ship builds created - * by MSVC, so doing it this way reduces complexity.) - */ - -__declspec(noreturn) __inline void MOZ_NoReturn() {} - -# ifdef __cplusplus -# define MOZ_REALLY_CRASH(line) \ - do { \ - ::__debugbreak(); \ - *((volatile int*) NULL) = line; \ - ::TerminateProcess(::GetCurrentProcess(), 3); \ - ::MOZ_NoReturn(); \ - } while (0) -# else -# define MOZ_REALLY_CRASH(line) \ - do { \ - __debugbreak(); \ - *((volatile int*) NULL) = line; \ - TerminateProcess(GetCurrentProcess(), 3); \ - MOZ_NoReturn(); \ - } while (0) -# endif -#else -# ifdef __cplusplus -# define MOZ_REALLY_CRASH(line) \ - do { \ - *((volatile int*) NULL) = line; \ - ::abort(); \ - } while (0) -# else -# define MOZ_REALLY_CRASH(line) \ - do { \ - *((volatile int*) NULL) = line; \ - abort(); \ - } while (0) -# endif +/* + * On MSVC use the __debugbreak compiler intrinsic, which produces an inline + * (not nested in a system function) breakpoint. This distinctively invokes + * Breakpad without requiring system library symbols on all stack-processing + * machines, as a nested breakpoint would require. + * + * We use __LINE__ to prevent the compiler from folding multiple crash sites + * together, which would make crash reports hard to understand. + * + * We use TerminateProcess with the exit code aborting would generate + * because we don't want to invoke atexit handlers, destructors, library + * unload handlers, and so on when our process might be in a compromised + * state. + * + * We don't use abort() because it'd cause Windows to annoyingly pop up the + * process error dialog multiple times. See bug 345118 and bug 426163. + * + * (Technically these are Windows requirements, not MSVC requirements. But + * practically you need MSVC for debugging, and we only ship builds created + * by MSVC, so doing it this way reduces complexity.) + */ + +MOZ_MAYBE_UNUSED static MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void +MOZ_NoReturn(int aLine) { + *((volatile int*)NULL) = aLine; + TerminateProcess(GetCurrentProcess(), 3); +} + +#define MOZ_REALLY_CRASH(line) \ + do { \ + __debugbreak(); \ + MOZ_NoReturn(line); \ + } while (false) +#else +#ifdef __cplusplus +#define MOZ_REALLY_CRASH(line) \ + do { \ + *((volatile int*)NULL) = line; \ + ::abort(); \ + } while (false) +#else +#define MOZ_REALLY_CRASH(line) \ + do { \ + *((volatile int*)NULL) = line; \ + abort(); \ + } while (false) +#endif #endif /* @@ -272,18 +262,18 @@ * corrupted. */ #ifndef DEBUG -# define MOZ_CRASH(...) \ - do { \ - MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \ - 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(__LINE__); \ - } while (0) +#define MOZ_CRASH(...) \ + do { \ + MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \ + MOZ_REALLY_CRASH(__LINE__); \ + } while (false) +#else +#define MOZ_CRASH(...) \ + do { \ + MOZ_ReportCrash("" __VA_ARGS__, __FILE__, __LINE__); \ + MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \ + MOZ_REALLY_CRASH(__LINE__); \ + } while (false) #endif /* @@ -293,30 +283,35 @@ * 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. + * + * @note This macro causes data collection because crash strings are annotated + * to crash-stats and are publicly visible. Firefox data stewards must do data + * review on usages of this macro. */ #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) +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__) +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 /* @@ -326,21 +321,24 @@ * 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) + * + * @note This macro causes data collection because crash strings are annotated + * to crash-stats and are publicly visible. Firefox data stewards must do data + * review on usages of this macro. + */ +#define MOZ_CRASH_UNSAFE_PRINTF(format, ...) \ + do { \ + static_assert(MOZ_ARG_COUNT(__VA_ARGS__) > 0, \ + "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " \ + "Or maybe you want MOZ_CRASH instead?"); \ + static_assert(MOZ_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 (false) -#ifdef __cplusplus -} /* extern "C" */ -#endif +MOZ_END_EXTERN_C /* * MOZ_ASSERT(expr [, explanation-string]) asserts that |expr| must be truthy in @@ -381,6 +379,9 @@ * This can cause user pain, so use it sparingly. If a MOZ_DIAGNOSTIC_ASSERT * is firing, it should promptly be converted to a MOZ_ASSERT while the failure * is being investigated, rather than letting users suffer. + * + * MOZ_DIAGNOSTIC_ASSERT_ENABLED is defined when MOZ_DIAGNOSTIC_ASSERT is like + * MOZ_RELEASE_ASSERT rather than MOZ_ASSERT. */ /* @@ -389,13 +390,12 @@ */ #ifdef __cplusplus -# include "mozilla/TypeTraits.h" +#include "mozilla/TypeTraits.h" namespace mozilla { namespace detail { -template -struct AssertionConditionType -{ +template +struct AssertionConditionType { typedef typename RemoveReference::Type ValueT; static_assert(!IsArray::value, "Expected boolean assertion condition, got an array or a " @@ -413,52 +413,68 @@ static const bool isValid = true; }; -} // namespace detail -} // namespace mozilla -# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) \ - static_assert(mozilla::detail::AssertionConditionType::isValid, \ - "invalid assertion condition") -#else -# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) +} // namespace detail +} // namespace mozilla +#define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) \ + static_assert(mozilla::detail::AssertionConditionType::isValid, \ + "invalid assertion condition") +#else +#define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) +#endif + +#if defined(DEBUG) || defined(MOZ_ASAN) +#define MOZ_REPORT_ASSERTION_FAILURE(...) \ + MOZ_ReportAssertionFailure(__VA_ARGS__) +#else +#define MOZ_REPORT_ASSERTION_FAILURE(...) \ + do { /* nothing */ \ + } while (false) #endif /* First the single-argument form. */ -#define MOZ_ASSERT_HELPER1(expr) \ - do { \ - MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ - if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ - MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \ - MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ")"); \ - MOZ_REALLY_CRASH(__LINE__); \ - } \ - } while (0) +#define MOZ_ASSERT_HELPER1(expr) \ + do { \ + MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ + if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ + MOZ_REPORT_ASSERTION_FAILURE(#expr, __FILE__, __LINE__); \ + MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ")"); \ + MOZ_REALLY_CRASH(__LINE__); \ + } \ + } while (false) /* Now the two-argument form. */ -#define MOZ_ASSERT_HELPER2(expr, explain) \ - do { \ - MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ - if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ - MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \ +#define MOZ_ASSERT_HELPER2(expr, explain) \ + do { \ + MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ + if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ + MOZ_REPORT_ASSERTION_FAILURE(#expr " (" explain ")", __FILE__, \ + __LINE__); \ MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ") (" explain ")"); \ - MOZ_REALLY_CRASH(__LINE__); \ - } \ - } while (0) + MOZ_REALLY_CRASH(__LINE__); \ + } \ + } while (false) #define MOZ_RELEASE_ASSERT_GLUE(a, b) a b -#define MOZ_RELEASE_ASSERT(...) \ - MOZ_RELEASE_ASSERT_GLUE( \ - MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \ - (__VA_ARGS__)) +#define MOZ_RELEASE_ASSERT(...) \ + MOZ_RELEASE_ASSERT_GLUE( \ + MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \ + (__VA_ARGS__)) #ifdef DEBUG -# define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__) +#define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__) #else -# define MOZ_ASSERT(...) do { } while (0) +#define MOZ_ASSERT(...) \ + do { \ + } while (false) #endif /* DEBUG */ -#ifdef RELEASE_OR_BETA -# define MOZ_DIAGNOSTIC_ASSERT MOZ_ASSERT +#if defined(NIGHTLY_BUILD) || defined(MOZ_DEV_EDITION) +#define MOZ_DIAGNOSTIC_ASSERT MOZ_RELEASE_ASSERT +#define MOZ_DIAGNOSTIC_ASSERT_ENABLED 1 #else -# define MOZ_DIAGNOSTIC_ASSERT MOZ_RELEASE_ASSERT +#define MOZ_DIAGNOSTIC_ASSERT MOZ_ASSERT +#ifdef DEBUG +#define MOZ_DIAGNOSTIC_ASSERT_ENABLED 1 +#endif #endif /* @@ -471,14 +487,16 @@ * designed to catch bugs during debugging, not "in the field". */ #ifdef DEBUG -# define MOZ_ASSERT_IF(cond, expr) \ - do { \ - if (cond) { \ - MOZ_ASSERT(expr); \ - } \ - } while (0) -#else -# define MOZ_ASSERT_IF(cond, expr) do { } while (0) +#define MOZ_ASSERT_IF(cond, expr) \ + do { \ + if (cond) { \ + MOZ_ASSERT(expr); \ + } \ + } while (false) +#else +#define MOZ_ASSERT_IF(cond, expr) \ + do { \ + } while (false) #endif /* @@ -489,15 +507,15 @@ * asserts. */ #if defined(__clang__) || defined(__GNUC__) -# define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable() +#define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable() #elif defined(_MSC_VER) -# define MOZ_ASSUME_UNREACHABLE_MARKER() __assume(0) +#define MOZ_ASSUME_UNREACHABLE_MARKER() __assume(0) #else -# ifdef __cplusplus -# define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort() -# else -# define MOZ_ASSUME_UNREACHABLE_MARKER() abort() -# endif +#ifdef __cplusplus +#define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort() +#else +#define MOZ_ASSUME_UNREACHABLE_MARKER() abort() +#endif #endif /* @@ -546,13 +564,13 @@ * that have a safe return without crashing in release builds. */ #define MOZ_ASSERT_UNREACHABLE(reason) \ - MOZ_ASSERT(false, "MOZ_ASSERT_UNREACHABLE: " reason) + MOZ_ASSERT(false, "MOZ_ASSERT_UNREACHABLE: " reason) #define MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(reason) \ - do { \ - MOZ_ASSERT_UNREACHABLE(reason); \ - MOZ_ASSUME_UNREACHABLE_MARKER(); \ - } while (0) + do { \ + MOZ_ASSERT_UNREACHABLE(reason); \ + MOZ_ASSUME_UNREACHABLE_MARKER(); \ + } while (false) /** * MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about @@ -561,7 +579,7 @@ * 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)`, + * release builds, the MOZ_ASSERT(false) will expand to `do { } while (false)`, * 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 @@ -588,9 +606,10 @@ * } */ #ifdef DEBUG -# define MOZ_FALLTHROUGH_ASSERT(reason) MOZ_CRASH("MOZ_FALLTHROUGH_ASSERT: " reason) +#define MOZ_FALLTHROUGH_ASSERT(reason) \ + MOZ_CRASH("MOZ_FALLTHROUGH_ASSERT: " reason) #else -# define MOZ_FALLTHROUGH_ASSERT(...) MOZ_FALLTHROUGH +#define MOZ_FALLTHROUGH_ASSERT(...) MOZ_FALLTHROUGH #endif /* @@ -600,35 +619,49 @@ * using MOZ_ASSERT. */ #ifdef DEBUG -# 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_MUST_USE. */ \ - } \ - } while (0) -# define MOZ_ALWAYS_FALSE(expr) \ - do { \ - if ((expr)) { \ - /* Silence MOZ_MUST_USE. */ \ - } \ - } while (0) +#define MOZ_ALWAYS_TRUE(expr) \ + do { \ + if ((expr)) { \ + /* Do nothing. */ \ + } else { \ + MOZ_ASSERT(false, #expr); \ + } \ + } while (false) +#define MOZ_ALWAYS_FALSE(expr) \ + do { \ + if ((expr)) { \ + MOZ_ASSERT(false, #expr); \ + } else { \ + /* Do nothing. */ \ + } \ + } while (false) +#define MOZ_ALWAYS_OK(expr) MOZ_ASSERT((expr).isOk()) +#define MOZ_ALWAYS_ERR(expr) MOZ_ASSERT((expr).isErr()) +#else +#define MOZ_ALWAYS_TRUE(expr) \ + do { \ + if ((expr)) { \ + /* Silence MOZ_MUST_USE. */ \ + } \ + } while (false) +#define MOZ_ALWAYS_FALSE(expr) \ + do { \ + if ((expr)) { \ + /* Silence MOZ_MUST_USE. */ \ + } \ + } while (false) +#define MOZ_ALWAYS_OK(expr) \ + do { \ + if ((expr).isOk()) { \ + /* Silence MOZ_MUST_USE. */ \ + } \ + } while (false) +#define MOZ_ALWAYS_ERR(expr) \ + do { \ + if ((expr).isErr()) { \ + /* Silence MOZ_MUST_USE. */ \ + } \ + } while (false) #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 @@ -21,30 +21,9 @@ #include "mozilla/Compiler.h" #include "mozilla/TypeTraits.h" -#include +#include -/* - * Our minimum deployment target on clang/OS X is OS X 10.6, whose SDK - * does not have . So be sure to check for support - * along with C++0x support. - */ -#if defined(_MSC_VER) -# define MOZ_HAVE_CXX11_ATOMICS -#elif defined(__clang__) || defined(__GNUC__) - /* - * Clang doesn't like from libstdc++ before 4.7 due to the - * loose typing of the atomic builtins. GCC 4.5 and 4.6 lacks inline - * definitions for unspecialized std::atomic and causes linking errors. - * Therefore, we require at least 4.7.0 for using libstdc++. - * - * libc++ is only functional with clang. - */ -# if MOZ_USING_LIBSTDCXX && MOZ_LIBSTDCXX_VERSION_AT_LEAST(4, 7, 0) -# define MOZ_HAVE_CXX11_ATOMICS -# elif MOZ_USING_LIBCXX && defined(__clang__) -# define MOZ_HAVE_CXX11_ATOMICS -# endif -#endif +#include namespace mozilla { @@ -162,402 +141,159 @@ SequentiallyConsistent, }; -} // namespace mozilla - -// Build up the underlying intrinsics. -#ifdef MOZ_HAVE_CXX11_ATOMICS - -# include - -namespace mozilla { namespace detail { /* * We provide CompareExchangeFailureOrder to work around a bug in some * versions of GCC's header. See bug 898491. */ -template struct AtomicOrderConstraints; +template +struct AtomicOrderConstraints; -template<> -struct AtomicOrderConstraints -{ +template <> +struct AtomicOrderConstraints { static const std::memory_order AtomicRMWOrder = std::memory_order_relaxed; static const std::memory_order LoadOrder = std::memory_order_relaxed; static const std::memory_order StoreOrder = std::memory_order_relaxed; static const std::memory_order CompareExchangeFailureOrder = - std::memory_order_relaxed; + std::memory_order_relaxed; }; -template<> -struct AtomicOrderConstraints -{ +template <> +struct AtomicOrderConstraints { static const std::memory_order AtomicRMWOrder = std::memory_order_acq_rel; static const std::memory_order LoadOrder = std::memory_order_acquire; static const std::memory_order StoreOrder = std::memory_order_release; static const std::memory_order CompareExchangeFailureOrder = - std::memory_order_acquire; + std::memory_order_acquire; }; -template<> -struct AtomicOrderConstraints -{ +template <> +struct AtomicOrderConstraints { static const std::memory_order AtomicRMWOrder = std::memory_order_seq_cst; static const std::memory_order LoadOrder = std::memory_order_seq_cst; static const std::memory_order StoreOrder = std::memory_order_seq_cst; static const std::memory_order CompareExchangeFailureOrder = - std::memory_order_seq_cst; + std::memory_order_seq_cst; }; -template -struct IntrinsicBase -{ +template +struct IntrinsicBase { typedef std::atomic ValueType; typedef AtomicOrderConstraints OrderedOp; }; -template -struct IntrinsicMemoryOps : public IntrinsicBase -{ +template +struct IntrinsicMemoryOps : public IntrinsicBase { typedef IntrinsicBase Base; - static T load(const typename Base::ValueType& aPtr) - { + static T load(const typename Base::ValueType& aPtr) { return aPtr.load(Base::OrderedOp::LoadOrder); } - static void store(typename Base::ValueType& aPtr, T aVal) - { + static void store(typename Base::ValueType& aPtr, T aVal) { aPtr.store(aVal, Base::OrderedOp::StoreOrder); } - static T exchange(typename Base::ValueType& aPtr, T aVal) - { + static T exchange(typename Base::ValueType& aPtr, T aVal) { return aPtr.exchange(aVal, Base::OrderedOp::AtomicRMWOrder); } - static bool compareExchange(typename Base::ValueType& aPtr, - T aOldVal, T aNewVal) - { - return aPtr.compare_exchange_strong(aOldVal, aNewVal, - Base::OrderedOp::AtomicRMWOrder, - Base::OrderedOp::CompareExchangeFailureOrder); + static bool compareExchange(typename Base::ValueType& aPtr, T aOldVal, + T aNewVal) { + return aPtr.compare_exchange_strong( + aOldVal, aNewVal, Base::OrderedOp::AtomicRMWOrder, + Base::OrderedOp::CompareExchangeFailureOrder); } }; -template -struct IntrinsicAddSub : public IntrinsicBase -{ +template +struct IntrinsicAddSub : public IntrinsicBase { typedef IntrinsicBase Base; - static T add(typename Base::ValueType& aPtr, T aVal) - { + static T add(typename Base::ValueType& aPtr, T aVal) { return aPtr.fetch_add(aVal, Base::OrderedOp::AtomicRMWOrder); } - static T sub(typename Base::ValueType& aPtr, T aVal) - { + static T sub(typename Base::ValueType& aPtr, T aVal) { return aPtr.fetch_sub(aVal, Base::OrderedOp::AtomicRMWOrder); } }; -template -struct IntrinsicAddSub : public IntrinsicBase -{ +template +struct IntrinsicAddSub : public IntrinsicBase { typedef IntrinsicBase Base; - static T* add(typename Base::ValueType& aPtr, ptrdiff_t aVal) - { + static T* add(typename Base::ValueType& aPtr, ptrdiff_t aVal) { return aPtr.fetch_add(aVal, Base::OrderedOp::AtomicRMWOrder); } - static T* sub(typename Base::ValueType& aPtr, ptrdiff_t aVal) - { + static T* sub(typename Base::ValueType& aPtr, ptrdiff_t aVal) { return aPtr.fetch_sub(aVal, Base::OrderedOp::AtomicRMWOrder); } }; -template -struct IntrinsicIncDec : public IntrinsicAddSub -{ +template +struct IntrinsicIncDec : public IntrinsicAddSub { typedef IntrinsicBase Base; - static T inc(typename Base::ValueType& aPtr) - { + static T inc(typename Base::ValueType& aPtr) { return IntrinsicAddSub::add(aPtr, 1); } - static T dec(typename Base::ValueType& aPtr) - { + static T dec(typename Base::ValueType& aPtr) { return IntrinsicAddSub::sub(aPtr, 1); } }; -template +template struct AtomicIntrinsics : public IntrinsicMemoryOps, - public IntrinsicIncDec -{ + public IntrinsicIncDec { typedef IntrinsicBase Base; - static T or_(typename Base::ValueType& aPtr, T aVal) - { + static T or_(typename Base::ValueType& aPtr, T aVal) { return aPtr.fetch_or(aVal, Base::OrderedOp::AtomicRMWOrder); } - static T xor_(typename Base::ValueType& aPtr, T aVal) - { + static T xor_(typename Base::ValueType& aPtr, T aVal) { return aPtr.fetch_xor(aVal, Base::OrderedOp::AtomicRMWOrder); } - static T and_(typename Base::ValueType& aPtr, T aVal) - { + static T and_(typename Base::ValueType& aPtr, T aVal) { return aPtr.fetch_and(aVal, Base::OrderedOp::AtomicRMWOrder); } }; -template -struct AtomicIntrinsics - : public IntrinsicMemoryOps, public IntrinsicIncDec -{ -}; - -template -struct ToStorageTypeArgument -{ - static constexpr T convert (T aT) { return aT; } -}; - -} // namespace detail -} // namespace mozilla - -#elif defined(__GNUC__) - -namespace mozilla { -namespace detail { - -/* - * The __sync_* family of intrinsics is documented here: - * - * http://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/Atomic-Builtins.html - * - * While these intrinsics are deprecated in favor of the newer __atomic_* - * family of intrincs: - * - * http://gcc.gnu.org/onlinedocs/gcc-4.7.3/gcc/_005f_005fatomic-Builtins.html - * - * any GCC version that supports the __atomic_* intrinsics will also support - * the header and so will be handled above. We provide a version of - * atomics using the __sync_* intrinsics to support older versions of GCC. - * - * All __sync_* intrinsics that we use below act as full memory barriers, for - * both compiler and hardware reordering, except for __sync_lock_test_and_set, - * which is a only an acquire barrier. When we call __sync_lock_test_and_set, - * we add a barrier above it as appropriate. - */ - -template struct Barrier; - -/* - * Some processors (in particular, x86) don't require quite so many calls to - * __sync_sychronize as our specializations of Barrier produce. If - * performance turns out to be an issue, defining these specializations - * on a per-processor basis would be a good first tuning step. - */ - -template<> -struct Barrier -{ - static void beforeLoad() {} - static void afterLoad() {} - static void beforeStore() {} - static void afterStore() {} -}; - -template<> -struct Barrier -{ - static void beforeLoad() {} - static void afterLoad() { __sync_synchronize(); } - static void beforeStore() { __sync_synchronize(); } - static void afterStore() {} -}; - -template<> -struct Barrier -{ - static void beforeLoad() { __sync_synchronize(); } - static void afterLoad() { __sync_synchronize(); } - static void beforeStore() { __sync_synchronize(); } - static void afterStore() { __sync_synchronize(); } -}; - -template::value> -struct AtomicStorageType -{ - // For non-enums, just use the type directly. - typedef T Type; -}; - -template -struct AtomicStorageType - : Conditional -{ - static_assert(sizeof(T) == 4 || sizeof(T) == 8, - "wrong type computed in conditional above"); -}; - -template -struct IntrinsicMemoryOps -{ - typedef typename AtomicStorageType::Type ValueType; - - static T load(const ValueType& aPtr) - { - Barrier::beforeLoad(); - T val = T(aPtr); - Barrier::afterLoad(); - return val; - } - - static void store(ValueType& aPtr, T aVal) - { - Barrier::beforeStore(); - aPtr = ValueType(aVal); - Barrier::afterStore(); - } - - static T exchange(ValueType& aPtr, T aVal) - { - // __sync_lock_test_and_set is only an acquire barrier; loads and stores - // can't be moved up from after to before it, but they can be moved down - // from before to after it. We may want a stricter ordering, so we need - // an explicit barrier. - Barrier::beforeStore(); - return T(__sync_lock_test_and_set(&aPtr, ValueType(aVal))); - } - - static bool compareExchange(ValueType& aPtr, T aOldVal, T aNewVal) - { - return __sync_bool_compare_and_swap(&aPtr, ValueType(aOldVal), ValueType(aNewVal)); - } -}; - -template -struct IntrinsicAddSub - : public IntrinsicMemoryOps -{ - typedef IntrinsicMemoryOps Base; - typedef typename Base::ValueType ValueType; - - static T add(ValueType& aPtr, T aVal) - { - return T(__sync_fetch_and_add(&aPtr, ValueType(aVal))); - } - - static T sub(ValueType& aPtr, T aVal) - { - return T(__sync_fetch_and_sub(&aPtr, ValueType(aVal))); - } -}; - -template -struct IntrinsicAddSub - : public IntrinsicMemoryOps -{ - typedef IntrinsicMemoryOps Base; - typedef typename Base::ValueType ValueType; - - /* - * The reinterpret_casts are needed so that - * __sync_fetch_and_{add,sub} will properly type-check. - * - * Also, these functions do not provide standard semantics for - * pointer types, so we need to adjust the addend. - */ - static ValueType add(ValueType& aPtr, ptrdiff_t aVal) - { - ValueType amount = reinterpret_cast(aVal * sizeof(T)); - return __sync_fetch_and_add(&aPtr, amount); - } - - static ValueType sub(ValueType& aPtr, ptrdiff_t aVal) - { - ValueType amount = reinterpret_cast(aVal * sizeof(T)); - return __sync_fetch_and_sub(&aPtr, amount); - } -}; - -template -struct IntrinsicIncDec : public IntrinsicAddSub -{ - typedef IntrinsicAddSub Base; - typedef typename Base::ValueType ValueType; +template +struct AtomicIntrinsics : public IntrinsicMemoryOps, + public IntrinsicIncDec {}; - static T inc(ValueType& aPtr) { return Base::add(aPtr, 1); } - static T dec(ValueType& aPtr) { return Base::sub(aPtr, 1); } +template +struct ToStorageTypeArgument { + static constexpr T convert(T aT) { return aT; } }; -template -struct AtomicIntrinsics : public IntrinsicIncDec -{ - static T or_( T& aPtr, T aVal) { return __sync_fetch_and_or(&aPtr, aVal); } - static T xor_(T& aPtr, T aVal) { return __sync_fetch_and_xor(&aPtr, aVal); } - static T and_(T& aPtr, T aVal) { return __sync_fetch_and_and(&aPtr, aVal); } -}; - -template -struct AtomicIntrinsics : public IntrinsicIncDec -{ -}; - -template::value> -struct ToStorageTypeArgument -{ - typedef typename AtomicStorageType::Type ResultType; - - static constexpr ResultType convert (T aT) { return ResultType(aT); } -}; - -template -struct ToStorageTypeArgument -{ - static constexpr T convert (T aT) { return aT; } -}; - -} // namespace detail -} // namespace mozilla - -#else -# error "Atomic compiler intrinsics are not supported on your platform" -#endif - -namespace mozilla { - -namespace detail { - -template -class AtomicBase -{ +template +class AtomicBase { static_assert(sizeof(T) == 4 || sizeof(T) == 8, "mozilla/Atomics.h only supports 32-bit and 64-bit types"); -protected: + protected: typedef typename detail::AtomicIntrinsics Intrinsics; typedef typename Intrinsics::ValueType ValueType; ValueType mValue; -public: + public: constexpr AtomicBase() : mValue() {} explicit constexpr AtomicBase(T aInit) - : mValue(ToStorageTypeArgument::convert(aInit)) - {} + : mValue(ToStorageTypeArgument::convert(aInit)) {} // Note: we can't provide operator T() here because Atomic inherits // from AtomcBase with T=uint32_t and not T=bool. If we implemented // operator T() here, it would cause errors when comparing Atomic with // a regular bool. - T operator=(T aVal) - { + T operator=(T aVal) { Intrinsics::store(mValue, aVal); return aVal; } @@ -566,10 +302,7 @@ * Performs an atomic swap operation. aVal is stored and the previous * value of this variable is returned. */ - T exchange(T aVal) - { - return Intrinsics::exchange(mValue, aVal); - } + T exchange(T aVal) { return Intrinsics::exchange(mValue, aVal); } /** * Performs an atomic compare-and-swap operation and returns true if it @@ -582,22 +315,20 @@ * return false; * } */ - bool compareExchange(T aOldValue, T aNewValue) - { + bool compareExchange(T aOldValue, T aNewValue) { return Intrinsics::compareExchange(mValue, aOldValue, aNewValue); } -private: - template + private: + template AtomicBase(const AtomicBase& aCopy) = delete; }; -template -class AtomicBaseIncDec : public AtomicBase -{ +template +class AtomicBaseIncDec : public AtomicBase { typedef typename detail::AtomicBase Base; -public: + public: constexpr AtomicBaseIncDec() : Base() {} explicit constexpr AtomicBaseIncDec(T aInit) : Base(aInit) {} @@ -609,12 +340,12 @@ T operator++() { return Base::Intrinsics::inc(Base::mValue) + 1; } T operator--() { return Base::Intrinsics::dec(Base::mValue) - 1; } -private: - template + private: + template AtomicBaseIncDec(const AtomicBaseIncDec& aCopy) = delete; }; -} // namespace detail +} // namespace detail /** * A wrapper for a type that enforces that all memory accesses are atomic. @@ -633,9 +364,8 @@ * deliberate design choice that enables static atomic variables to be declared * without introducing extra static constructors. */ -template +template class Atomic; /** @@ -646,45 +376,40 @@ * corresponding read-modify-write operation atomically. Finally, an atomic * swap method is provided. */ -template -class Atomic::value && - !IsSame::value>::Type> - : public detail::AtomicBaseIncDec -{ +template +class Atomic< + T, Order, + typename EnableIf::value && !IsSame::value>::Type> + : public detail::AtomicBaseIncDec { typedef typename detail::AtomicBaseIncDec Base; -public: + public: constexpr Atomic() : Base() {} explicit constexpr Atomic(T aInit) : Base(aInit) {} using Base::operator=; - T operator+=(T aDelta) - { + T operator+=(T aDelta) { return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta; } - T operator-=(T aDelta) - { + T operator-=(T aDelta) { return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta; } - T operator|=(T aVal) - { + T operator|=(T aVal) { return Base::Intrinsics::or_(Base::mValue, aVal) | aVal; } - T operator^=(T aVal) - { + T operator^=(T aVal) { return Base::Intrinsics::xor_(Base::mValue, aVal) ^ aVal; } - T operator&=(T aVal) - { + T operator&=(T aVal) { return Base::Intrinsics::and_(Base::mValue, aVal) & aVal; } -private: + private: Atomic(Atomic& aOther) = delete; }; @@ -696,28 +421,25 @@ * assignment operators for addition and subtraction. Atomic swap (via * exchange()) is included as well. */ -template -class Atomic : public detail::AtomicBaseIncDec -{ +template +class Atomic : public detail::AtomicBaseIncDec { typedef typename detail::AtomicBaseIncDec Base; -public: + public: constexpr Atomic() : Base() {} explicit constexpr Atomic(T* aInit) : Base(aInit) {} using Base::operator=; - T* operator+=(ptrdiff_t aDelta) - { + T* operator+=(ptrdiff_t aDelta) { return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta; } - T* operator-=(ptrdiff_t aDelta) - { + T* operator-=(ptrdiff_t aDelta) { return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta; } -private: + private: Atomic(Atomic& aOther) = delete; }; @@ -726,13 +448,12 @@ * * The atomic store and load operations and the atomic swap method is provided. */ -template +template class Atomic::value>::Type> - : public detail::AtomicBase -{ + : public detail::AtomicBase { typedef typename detail::AtomicBase Base; -public: + public: constexpr Atomic() : Base() {} explicit constexpr Atomic(T aInit) : Base(aInit) {} @@ -740,7 +461,7 @@ using Base::operator=; -private: + private: Atomic(Atomic& aOther) = delete; }; @@ -760,41 +481,35 @@ * runtime library are not available on Windows XP. This is why we implement * Atomic with an underlying type of uint32_t. */ -template -class Atomic - : protected detail::AtomicBase -{ +template +class Atomic : protected detail::AtomicBase { typedef typename detail::AtomicBase Base; -public: + public: constexpr Atomic() : Base() {} explicit constexpr Atomic(bool aInit) : Base(aInit) {} // We provide boolean wrappers for the underlying AtomicBase methods. - MOZ_IMPLICIT operator bool() const - { + MOZ_IMPLICIT operator bool() const { return Base::Intrinsics::load(Base::mValue); } - bool operator=(bool aVal) - { - return Base::operator=(aVal); - } + bool operator=(bool aVal) { return Base::operator=(aVal); } - bool exchange(bool aVal) - { - return Base::exchange(aVal); - } + bool exchange(bool aVal) { return Base::exchange(aVal); } - bool compareExchange(bool aOldValue, bool aNewValue) - { + bool compareExchange(bool aOldValue, bool aNewValue) { return Base::compareExchange(aOldValue, aNewValue); } -private: + private: Atomic(Atomic& aOther) = delete; }; -} // namespace mozilla +// If you want to atomically swap two atomic values, use exchange(). +template +void Swap(Atomic&, Atomic&) = delete; + +} // namespace mozilla #endif /* mozilla_Atomics_h */ 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 @@ -22,19 +22,19 @@ * compiler to inline even in DEBUG builds. It should be used very rarely. */ #if defined(_MSC_VER) -# define MOZ_ALWAYS_INLINE_EVEN_DEBUG __forceinline +#define MOZ_ALWAYS_INLINE_EVEN_DEBUG __forceinline #elif defined(__GNUC__) -# define MOZ_ALWAYS_INLINE_EVEN_DEBUG __attribute__((always_inline)) inline +#define MOZ_ALWAYS_INLINE_EVEN_DEBUG __attribute__((always_inline)) inline #else -# define MOZ_ALWAYS_INLINE_EVEN_DEBUG inline +#define MOZ_ALWAYS_INLINE_EVEN_DEBUG inline #endif #if !defined(DEBUG) -# define MOZ_ALWAYS_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG +#define MOZ_ALWAYS_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG #elif defined(_MSC_VER) && !defined(__cplusplus) -# define MOZ_ALWAYS_INLINE __inline +#define MOZ_ALWAYS_INLINE __inline #else -# define MOZ_ALWAYS_INLINE inline +#define MOZ_ALWAYS_INLINE inline #endif #if defined(_MSC_VER) @@ -46,26 +46,28 @@ * Current versions of g++ do not correctly set __cplusplus, so we check both * for forward compatibility. */ -# define MOZ_HAVE_NEVER_INLINE __declspec(noinline) -# define MOZ_HAVE_NORETURN __declspec(noreturn) +#define MOZ_HAVE_NEVER_INLINE __declspec(noinline) +#define MOZ_HAVE_NORETURN __declspec(noreturn) #elif defined(__clang__) - /* - * Per Clang documentation, "Note that marketing version numbers should not - * be used to check for language features, as different vendors use different - * numbering schemes. Instead, use the feature checking macros." - */ -# ifndef __has_extension -# define __has_extension __has_feature /* compatibility, for older versions of clang */ -# endif -# if __has_attribute(noinline) -# define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) -# endif -# if __has_attribute(noreturn) -# define MOZ_HAVE_NORETURN __attribute__((noreturn)) -# endif +/* + * Per Clang documentation, "Note that marketing version numbers should not + * be used to check for language features, as different vendors use different + * numbering schemes. Instead, use the feature checking macros." + */ +#ifndef __has_extension +#define __has_extension \ + __has_feature /* compatibility, for older versions of clang */ +#endif +#if __has_attribute(noinline) +#define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) +#endif +#if __has_attribute(noreturn) +#define MOZ_HAVE_NORETURN __attribute__((noreturn)) +#endif #elif defined(__GNUC__) -# define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) -# define MOZ_HAVE_NORETURN __attribute__((noreturn)) +#define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) +#define MOZ_HAVE_NORETURN __attribute__((noreturn)) +#define MOZ_HAVE_NORETURN_PTR __attribute__((noreturn)) #endif /* @@ -73,9 +75,9 @@ * to mark some false positives */ #ifdef __clang_analyzer__ -# if __has_extension(attribute_analyzer_noreturn) -# define MOZ_HAVE_ANALYZER_NORETURN __attribute__((analyzer_noreturn)) -# endif +#if __has_extension(attribute_analyzer_noreturn) +#define MOZ_HAVE_ANALYZER_NORETURN __attribute__((analyzer_noreturn)) +#endif #endif /* @@ -85,9 +87,9 @@ * guaranteed to support this, but most do. */ #if defined(MOZ_HAVE_NEVER_INLINE) -# define MOZ_NEVER_INLINE MOZ_HAVE_NEVER_INLINE +#define MOZ_NEVER_INLINE MOZ_HAVE_NEVER_INLINE #else -# define MOZ_NEVER_INLINE /* no support */ +#define MOZ_NEVER_INLINE /* no support */ #endif /* @@ -102,12 +104,20 @@ * warnings about not initializing variables, or about any other seemingly-dodgy * operations performed after the function returns. * + * There are two variants. The GCC version of NORETURN may be applied to a + * function pointer, while for MSVC it may not. + * * This modifier does not affect the corresponding function's linking behavior. */ #if defined(MOZ_HAVE_NORETURN) -# define MOZ_NORETURN MOZ_HAVE_NORETURN +#define MOZ_NORETURN MOZ_HAVE_NORETURN #else -# define MOZ_NORETURN /* no support */ +#define MOZ_NORETURN /* no support */ +#endif +#if defined(MOZ_HAVE_NORETURN_PTR) +#define MOZ_NORETURN_PTR MOZ_HAVE_NORETURN_PTR +#else +#define MOZ_NORETURN_PTR /* no support */ #endif /** @@ -126,9 +136,9 @@ * MOZ_COLD int foo() { return 42; } */ #if defined(__GNUC__) || defined(__clang__) -# define MOZ_COLD __attribute__ ((cold)) +#define MOZ_COLD __attribute__((cold)) #else -# define MOZ_COLD +#define MOZ_COLD #endif /** @@ -142,9 +152,24 @@ * MOZ_NONNULL(1, 2) int foo(char *p, char *q); */ #if defined(__GNUC__) || defined(__clang__) -# define MOZ_NONNULL(...) __attribute__ ((nonnull(__VA_ARGS__))) +#define MOZ_NONNULL(...) __attribute__((nonnull(__VA_ARGS__))) #else -# define MOZ_NONNULL(...) +#define MOZ_NONNULL(...) +#endif + +/** + * MOZ_NONNULL_RETURN tells the compiler that the function's return value is + * guaranteed to be a non-null pointer, which may enable the compiler to + * optimize better at call sites. + * + * Place this attribute at the end of a function declaration. For example, + * + * char* foo(char *p, char *q) MOZ_NONNULL_RETURN; + */ +#if defined(__GNUC__) || defined(__clang__) +#define MOZ_NONNULL_RETURN __attribute__((returns_nonnull)) +#else +#define MOZ_NONNULL_RETURN #endif /* @@ -164,9 +189,9 @@ * */ #if defined(MOZ_HAVE_ANALYZER_NORETURN) -# define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS MOZ_HAVE_ANALYZER_NORETURN +#define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS MOZ_HAVE_ANALYZER_NORETURN #else -# define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS /* no support */ +#define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS /* no support */ #endif /* @@ -177,19 +202,19 @@ * AddressSanitizer. */ #if defined(__has_feature) -# if __has_feature(address_sanitizer) -# define MOZ_HAVE_ASAN_BLACKLIST -# endif +#if __has_feature(address_sanitizer) +#define MOZ_HAVE_ASAN_BLACKLIST +#endif #elif defined(__GNUC__) -# if defined(__SANITIZE_ADDRESS__) -# define MOZ_HAVE_ASAN_BLACKLIST -# endif +#if defined(__SANITIZE_ADDRESS__) +#define MOZ_HAVE_ASAN_BLACKLIST +#endif #endif #if defined(MOZ_HAVE_ASAN_BLACKLIST) -# define MOZ_ASAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_address)) +#define MOZ_ASAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_address)) #else -# define MOZ_ASAN_BLACKLIST /* nothing */ +#define MOZ_ASAN_BLACKLIST /* nothing */ #endif /* @@ -199,15 +224,99 @@ * inlining currently breaks the blacklisting mechanism of ThreadSanitizer. */ #if defined(__has_feature) -# if __has_feature(thread_sanitizer) -# define MOZ_TSAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_thread)) -# else -# define MOZ_TSAN_BLACKLIST /* nothing */ -# endif +#if __has_feature(thread_sanitizer) +#define MOZ_TSAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_thread)) +#else +#define MOZ_TSAN_BLACKLIST /* nothing */ +#endif +#else +#define MOZ_TSAN_BLACKLIST /* nothing */ +#endif + +#if defined(__has_attribute) +#if __has_attribute(no_sanitize) +#define MOZ_HAVE_NO_SANITIZE_ATTR +#endif +#endif + +#ifdef __clang__ +#ifdef MOZ_HAVE_NO_SANITIZE_ATTR +#define MOZ_HAVE_UNSIGNED_OVERFLOW_SANITIZE_ATTR +#define MOZ_HAVE_SIGNED_OVERFLOW_SANITIZE_ATTR +#endif +#endif + +/* + * MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW disables *un*signed integer overflow + * checking on the function it annotates, in builds configured to perform it. + * (Currently this is only Clang using -fsanitize=unsigned-integer-overflow, or + * via --enable-unsigned-overflow-sanitizer in Mozilla's build system.) It has + * no effect in other builds. + * + * Place this attribute at the very beginning of a function declaration. + * + * Unsigned integer overflow isn't *necessarily* a bug. It's well-defined in + * C/C++, and code may reasonably depend upon it. For example, + * + * MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW inline bool + * IsDecimal(char aChar) + * { + * // For chars less than '0', unsigned integer underflow occurs, to a value + * // much greater than 10, so the overall test is false. + * // For chars greater than '0', no overflow occurs, and only '0' to '9' + * // pass the overall test. + * return static_cast(aChar) - '0' < 10; + * } + * + * But even well-defined unsigned overflow often causes bugs when it occurs, so + * it should be restricted to functions annotated with this attribute. + * + * The compiler instrumentation to detect unsigned integer overflow has costs + * both at compile time and at runtime. Functions that are repeatedly inlined + * at compile time will also implicitly inline the necessary instrumentation, + * increasing compile time. Similarly, frequently-executed functions that + * require large amounts of instrumentation will also notice significant runtime + * slowdown to execute that instrumentation. Use this attribute to eliminate + * those costs -- but only after carefully verifying that no overflow can occur. + */ +#ifdef MOZ_HAVE_UNSIGNED_OVERFLOW_SANITIZE_ATTR +#define MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW \ + __attribute__((no_sanitize("unsigned-integer-overflow"))) +#else +#define MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW /* nothing */ +#endif + +/* + * MOZ_NO_SANITIZE_SIGNED_OVERFLOW disables *signed* integer overflow checking + * on the function it annotates, in builds configured to perform it. (Currently + * this is only Clang using -fsanitize=signed-integer-overflow, or via + * --enable-signed-overflow-sanitizer in Mozilla's build system. GCC support + * will probably be added in the future.) It has no effect in other builds. + * + * Place this attribute at the very beginning of a function declaration. + * + * Signed integer overflow is undefined behavior in C/C++: *anything* can happen + * when it occurs. *Maybe* wraparound behavior will occur, but maybe also the + * compiler will assume no overflow happens and will adversely optimize the rest + * of your code. Code that contains signed integer overflow needs to be fixed. + * + * The compiler instrumentation to detect signed integer overflow has costs both + * at compile time and at runtime. Functions that are repeatedly inlined at + * compile time will also implicitly inline the necessary instrumentation, + * increasing compile time. Similarly, frequently-executed functions that + * require large amounts of instrumentation will also notice significant runtime + * slowdown to execute that instrumentation. Use this attribute to eliminate + * those costs -- but only after carefully verifying that no overflow can occur. + */ +#ifdef MOZ_HAVE_SIGNED_OVERFLOW_SANITIZE_ATTR +#define MOZ_NO_SANITIZE_SIGNED_OVERFLOW \ + __attribute__((no_sanitize("signed-integer-overflow"))) #else -# define MOZ_TSAN_BLACKLIST /* nothing */ +#define MOZ_NO_SANITIZE_SIGNED_OVERFLOW /* nothing */ #endif +#undef MOZ_HAVE_NO_SANITIZE_ATTR + /** * MOZ_ALLOCATOR tells the compiler that the function it marks returns either a * "fresh", "pointer-free" block of memory, or nullptr. "Fresh" means that the @@ -232,9 +341,9 @@ * void *my_allocator(size_t bytes) MOZ_ALLOCATOR { ... } */ #if defined(__GNUC__) || defined(__clang__) -# define MOZ_ALLOCATOR __attribute__ ((malloc, warn_unused_result)) +#define MOZ_ALLOCATOR __attribute__((malloc, warn_unused_result)) #else -# define MOZ_ALLOCATOR +#define MOZ_ALLOCATOR #endif /** @@ -245,17 +354,58 @@ * example, write * * MOZ_MUST_USE int foo(); + * or + * MOZ_MUST_USE int foo() { return 42; } + * + * MOZ_MUST_USE is most appropriate for functions where the return value is + * some kind of success/failure indicator -- often |nsresult|, |bool| or |int| + * -- because these functions are most commonly the ones that have missing + * checks. There are three cases of note. + * + * - Fallible functions whose return values should always be checked. For + * example, a function that opens a file should always be checked because any + * subsequent operations on the file will fail if opening it fails. Such + * functions should be given a MOZ_MUST_USE annotation. + * + * - Fallible functions whose return value need not always be checked. For + * example, a function that closes a file might not be checked because it's + * common that no further operations would be performed on the file. Such + * functions do not need a MOZ_MUST_USE annotation. + * + * - Infallible functions, i.e. ones that always return a value indicating + * success. These do not need a MOZ_MUST_USE annotation. Ideally, they would + * be converted to not return a success/failure indicator, though sometimes + * interface constraints prevent this. + */ +#if defined(__GNUC__) || defined(__clang__) +#define MOZ_MUST_USE __attribute__((warn_unused_result)) +#else +#define MOZ_MUST_USE +#endif + +/** + * MOZ_MAYBE_UNUSED suppresses compiler warnings about functions that are + * never called (in this build configuration, at least). + * + * Place this attribute at the very beginning of a function declaration. For + * example, write + * + * MOZ_MAYBE_UNUSED int foo(); * * or * - * MOZ_MUST_USE int foo() { return 42; } + * MOZ_MAYBE_UNUSED int foo() { return 42; } */ #if defined(__GNUC__) || defined(__clang__) -# define MOZ_MUST_USE __attribute__ ((warn_unused_result)) +#define MOZ_MAYBE_UNUSED __attribute__((__unused__)) +#elif defined(_MSC_VER) +#define MOZ_MAYBE_UNUSED __pragma(warning(suppress : 4505)) #else -# define MOZ_MUST_USE +#define MOZ_MAYBE_UNUSED #endif +#ifdef __cplusplus + /** * MOZ_FALLTHROUGH is an annotation to suppress compiler warnings about switch * cases that fall through without a break or return statement. MOZ_FALLTHROUGH @@ -282,22 +432,25 @@ * return 5; * } */ -#if defined(__clang__) && __cplusplus >= 201103L - /* clang's fallthrough annotations are only available starting in C++11. */ -# define MOZ_FALLTHROUGH [[clang::fallthrough]] +#ifndef __has_cpp_attribute +#define __has_cpp_attribute(x) 0 +#endif + +#if __has_cpp_attribute(clang::fallthrough) +#define MOZ_FALLTHROUGH [[clang::fallthrough]] +#elif __has_cpp_attribute(gnu::fallthrough) +#define MOZ_FALLTHROUGH [[gnu::fallthrough]] #elif defined(_MSC_VER) - /* - * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis): - * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx - */ -# include -# define MOZ_FALLTHROUGH __fallthrough +/* + * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis): + * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx + */ +#include +#define MOZ_FALLTHROUGH __fallthrough #else -# define MOZ_FALLTHROUGH /* FALLTHROUGH */ +#define MOZ_FALLTHROUGH /* FALLTHROUGH */ #endif -#ifdef __cplusplus - /* * The following macros are attributes that support the static analysis plugin * included with Mozilla, and will be implemented (when such support is enabled) @@ -343,6 +496,13 @@ * * The static analyses that are performed by the plugin are as follows: * + * MOZ_CAN_RUN_SCRIPT: Applies to functions which can run script. Callers of + * this function must also be marked as MOZ_CAN_RUN_SCRIPT, and all refcounted + * arguments must be strongly held in the caller. + * MOZ_CAN_RUN_SCRIPT_BOUNDARY: Applies to functions which need to call + * MOZ_CAN_RUN_SCRIPT functions, but should not themselves be considered + * MOZ_CAN_RUN_SCRIPT. This is important for some bindings and low level code + * which need to opt out of the safety checks performed by MOZ_CAN_RUN_SCRIPT. * MOZ_MUST_OVERRIDE: Applies to all C++ member functions. All immediate * subclasses must provide an exact override of this method; if a subclass * does not override this method, the compiler will emit an error. This @@ -360,8 +520,8 @@ * expected to live on the stack or in static storage, so it is a compile-time * error to use it, or an array of such objects, as the type of a new * expression. If a member of another class uses this class, or if another - * class inherits from this class, then it is considered to be a non-heap class - * as well, although this attribute need not be provided in such cases. + * class inherits from this class, then it is considered to be a non-heap + * class as well, although this attribute need not be provided in such cases. * MOZ_HEAP_CLASS: Applies to all classes. Any class with this annotation is * expected to live on the heap, so it is a compile-time error to use it, or * an array of such objects, as the type of a variable declaration, or as a @@ -373,6 +533,10 @@ * class uses this class or if another class inherits from this class, then it * is considered to be a non-temporary class as well, although this attribute * need not be provided in such cases. + * MOZ_TEMPORARY_CLASS: Applies to all classes. Any class with this annotation + * is expected to only live in a temporary. If another class inherits from + * this class, then it is considered to be a non-temporary class as well, + * although this attribute need not be provided in such cases. * MOZ_RAII: Applies to all classes. Any class with this annotation is assumed * to be a RAII guard, which is expected to live on the stack in an automatic * allocation. It is prohibited from being allocated in a temporary, static @@ -395,6 +559,14 @@ * are disallowed by default unless they are marked as MOZ_IMPLICIT. This * attribute must be used for constructors which intend to provide implicit * conversions. + * MOZ_IS_REFPTR: Applies to class declarations of ref pointer to mark them as + * such for use with static-analysis. + * A ref pointer is an object wrapping a pointer and automatically taking care + * of its refcounting upon construction/destruction/transfer of ownership. + * This annotation implies MOZ_IS_SMARTPTR_TO_REFCOUNTED. + * MOZ_IS_SMARTPTR_TO_REFCOUNTED: Applies to class declarations of smart + * pointers to ref counted classes to mark them as such for use with + * static-analysis. * MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT: Applies to functions. Makes it a compile * time error to pass arithmetic expressions on variables to the function. * MOZ_OWNING_REF: Applies to declarations of pointers to reference counted @@ -409,25 +581,27 @@ * MOZ_NON_OWNING_REF: Applies to declarations of pointers to reference counted * types. This attribute tells the compiler that the raw pointer is a weak * reference, which is ensured to be valid by a guarantee that the reference - * will be nulled before the pointer becomes invalid. This can make the compiler - * ignore these pointers when validating the usage of pointers otherwise. + * will be nulled before the pointer becomes invalid. This can make the + * compiler ignore these pointers when validating the usage of pointers + * otherwise. * * Examples include an mOwner pointer, which is nulled by the owning class's * destructor, and is null-checked before dereferencing. - * MOZ_UNSAFE_REF: Applies to declarations of pointers to reference counted types. - * Occasionally there are non-owning references which are valid, but do not take - * the form of a MOZ_NON_OWNING_REF. Their safety may be dependent on the behaviour - * of API consumers. The string argument passed to this macro documents the safety - * conditions. This can make the compiler ignore these pointers when validating - * the usage of pointers elsewhere. - * - * Examples include an nsIAtom* member which is known at compile time to point to a - * static atom which is valid throughout the lifetime of the program, or an API which - * stores a pointer, but doesn't take ownership over it, instead requiring the API - * consumer to correctly null the value before it becomes invalid. + * MOZ_UNSAFE_REF: Applies to declarations of pointers to reference counted + * types. Occasionally there are non-owning references which are valid, but + * do not take the form of a MOZ_NON_OWNING_REF. Their safety may be + * dependent on the behaviour of API consumers. The string argument passed + * to this macro documents the safety conditions. This can make the compiler + * ignore these pointers when validating the usage of pointers elsewhere. + * + * Examples include an nsAtom* member which is known at compile time to point + * to a static atom which is valid throughout the lifetime of the program, or + * an API which stores a pointer, but doesn't take ownership over it, instead + * requiring the API consumer to correctly null the value before it becomes + * invalid. * - * Use of this annotation is discouraged when a strong reference or one of the above - * two annotations can be used instead. + * Use of this annotation is discouraged when a strong reference or one of + * the above two annotations can be used instead. * MOZ_NO_ADDREF_RELEASE_ON_RETURN: Applies to function declarations. Makes it * a compile time error to call AddRef or Release on the return value of a * function. This is intended to be used with operator->() of our smart @@ -437,8 +611,8 @@ * 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. + * a compile time error to instantiate this template with a type parameter + * which has a VTable. * MOZ_NON_MEMMOVABLE: Applies to class declarations for types that are not safe * to be moved in memory using memmove(). * MOZ_NEEDS_MEMMOVABLE_TYPE: Applies to template class declarations where the @@ -448,6 +622,14 @@ * 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_NO_DANGLING_ON_TEMPORARIES: Applies to method declarations which return + * a pointer that is freed when the destructor of the class is called. This + * prevents these methods from being called on temporaries of the class, + * reducing risks of use-after-free. + * This attribute cannot be applied to && methods. + * In some cases, adding a deleted &&-qualified overload is too restrictive as + * this method should still be callable as a non-escaping argument to another + * function. This annotation can be used in those cases. * 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 @@ -455,118 +637,139 @@ * 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. + * 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. + * 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_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. + * 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. + * MOZ_MUST_RETURN_FROM_CALLER: Applies to function or method declarations. + * Callers of the annotated function/method must return from that function + * within the calling block using an explicit `return` statement. + * Only calls to Constructors, references to local and member variables, + * and calls to functions or methods marked as MOZ_MAY_CALL_AFTER_MUST_RETURN + * may be made after the MUST_RETURN_FROM_CALLER call. + * MOZ_MAY_CALL_AFTER_MUST_RETURN: Applies to function or method declarations. + * Calls to these methods may be made in functions after calls a + * MOZ_MUST_RETURN_FROM_CALLER function or method. */ #ifdef MOZ_CLANG_PLUGIN -# define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override"))) -# define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) -# define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class"))) -# define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class"))) -# define MOZ_NON_TEMPORARY_CLASS __attribute__((annotate("moz_non_temporary_class"))) -# define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor"))) -# ifdef DEBUG - /* in debug builds, these classes do have non-trivial constructors. */ -# define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class"))) -# else -# define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class"))) \ - MOZ_TRIVIAL_CTOR_DTOR -# endif -# define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) -# define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT __attribute__((annotate("moz_no_arith_expr_in_arg"))) -# define MOZ_OWNING_REF __attribute__((annotate("moz_strong_ref"))) -# 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_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"))) +#define MOZ_CAN_RUN_SCRIPT __attribute__((annotate("moz_can_run_script"))) +#define MOZ_CAN_RUN_SCRIPT_BOUNDARY \ + __attribute__((annotate("moz_can_run_script_boundary"))) +#define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override"))) +#define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) +#define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class"))) +#define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class"))) +#define MOZ_NON_TEMPORARY_CLASS \ + __attribute__((annotate("moz_non_temporary_class"))) +#define MOZ_TEMPORARY_CLASS __attribute__((annotate("moz_temporary_class"))) +#define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor"))) +#ifdef DEBUG +/* in debug builds, these classes do have non-trivial constructors. */ +#define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS \ + __attribute__((annotate("moz_global_class"))) +#else +#define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS \ + __attribute__((annotate("moz_global_class"))) MOZ_TRIVIAL_CTOR_DTOR +#endif +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) +#define MOZ_IS_SMARTPTR_TO_REFCOUNTED \ + __attribute__((annotate("moz_is_smartptr_to_refcounted"))) +#define MOZ_IS_REFPTR \ + __attribute__((annotate("moz_is_refptr"))) MOZ_IS_SMARTPTR_TO_REFCOUNTED +#define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT \ + __attribute__((annotate("moz_no_arith_expr_in_arg"))) +#define MOZ_OWNING_REF __attribute__((annotate("moz_strong_ref"))) +#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_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_NO_DANGLING_ON_TEMPORARIES \ + __attribute__((annotate("moz_no_dangling_on_temporaries"))) +#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"))) +#define MOZ_MUST_RETURN_FROM_CALLER \ + __attribute__((annotate("moz_must_return_from_caller"))) +#define MOZ_MAY_CALL_AFTER_MUST_RETURN \ + __attribute__((annotate("moz_may_call_after_must_return"))) /* * 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 * anyways, so the warning is safe to ignore. */ -# define MOZ_HEAP_ALLOCATOR \ - _Pragma("clang diagnostic push") \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((annotate("moz_heap_allocator"))) \ - _Pragma("clang diagnostic pop") -#else -# define MOZ_MUST_OVERRIDE /* nothing */ -# define MOZ_STACK_CLASS /* nothing */ -# define MOZ_NONHEAP_CLASS /* nothing */ -# define MOZ_HEAP_CLASS /* nothing */ -# define MOZ_NON_TEMPORARY_CLASS /* nothing */ -# define MOZ_TRIVIAL_CTOR_DTOR /* nothing */ -# define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS /* nothing */ -# define MOZ_IMPLICIT /* nothing */ -# define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT /* nothing */ -# define MOZ_HEAP_ALLOCATOR /* nothing */ -# define MOZ_OWNING_REF /* nothing */ -# define MOZ_NON_OWNING_REF /* nothing */ -# define MOZ_UNSAFE_REF(reason) /* nothing */ -# define MOZ_NO_ADDREF_RELEASE_ON_RETURN /* 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_HEAP_ALLOCATOR \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((annotate("moz_heap_allocator"))) \ + _Pragma("clang diagnostic pop") +#else +#define MOZ_CAN_RUN_SCRIPT /* nothing */ +#define MOZ_CAN_RUN_SCRIPT_BOUNDARY /* nothing */ +#define MOZ_MUST_OVERRIDE /* nothing */ +#define MOZ_STACK_CLASS /* nothing */ +#define MOZ_NONHEAP_CLASS /* nothing */ +#define MOZ_HEAP_CLASS /* nothing */ +#define MOZ_NON_TEMPORARY_CLASS /* nothing */ +#define MOZ_TEMPORARY_CLASS /* nothing */ +#define MOZ_TRIVIAL_CTOR_DTOR /* nothing */ +#define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS /* nothing */ +#define MOZ_IMPLICIT /* nothing */ +#define MOZ_IS_SMARTPTR_TO_REFCOUNTED /* nothing */ +#define MOZ_IS_REFPTR /* nothing */ +#define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT /* nothing */ +#define MOZ_HEAP_ALLOCATOR /* nothing */ +#define MOZ_OWNING_REF /* nothing */ +#define MOZ_NON_OWNING_REF /* nothing */ +#define MOZ_UNSAFE_REF(reason) /* nothing */ +#define MOZ_NO_ADDREF_RELEASE_ON_RETURN /* 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_NO_DANGLING_ON_TEMPORARIES /* 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 */ +#define MOZ_MUST_RETURN_FROM_CALLER /* nothing */ +#define MOZ_MAY_CALL_AFTER_MUST_RETURN /* nothing */ +#endif /* MOZ_CLANG_PLUGIN */ #define MOZ_RAII MOZ_NON_TEMPORARY_CLASS MOZ_STACK_CLASS -/* - * MOZ_HAVE_REF_QUALIFIERS is defined for compilers that support C++11's rvalue - * qualifier, "&&". - */ -#if defined(_MSC_VER) && _MSC_VER >= 1900 -# define MOZ_HAVE_REF_QUALIFIERS -#elif defined(__clang__) -// All supported Clang versions -# define MOZ_HAVE_REF_QUALIFIERS -#elif defined(__GNUC__) -# include "mozilla/Compiler.h" -# if MOZ_GCC_VERSION_AT_LEAST(4, 8, 1) -# define MOZ_HAVE_REF_QUALIFIERS -# endif -#endif - #endif /* __cplusplus */ /** @@ -589,16 +792,40 @@ * then the annotation would be: * MOZ_FORMAT_PRINTF(3, 4) * + * The second argument should be 0 for vprintf-like functions; that + * is, those taking a va_list argument. + * * 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))) + * + * MinGW requires special handling due to different format specifiers + * on different platforms. The macro __MINGW_PRINTF_FORMAT maps to + * either gnu_printf or ms_printf depending on where we are compiling + * to avoid warnings on format specifiers that are legal. + */ +#ifdef __MINGW32__ +#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) \ + __attribute__((format(__MINGW_PRINTF_FORMAT, stringIndex, firstToCheck))) +#elif __GNUC__ +#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) \ + __attribute__((format(printf, stringIndex, firstToCheck))) #else #define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) #endif +/** + * To manually declare an XPCOM ABI-compatible virtual function, the following + * macros can be used to handle the non-standard ABI used on Windows for COM + * compatibility. E.g.: + * + * virtual ReturnType MOZ_XPCOM_ABI foo(); + */ +#if defined(XP_WIN) +#define MOZ_XPCOM_ABI __stdcall +#else +#define MOZ_XPCOM_ABI +#endif + #endif /* mozilla_Attributes_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/AutoProfilerLabel.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/AutoProfilerLabel.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/AutoProfilerLabel.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 2; 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_AutoProfilerLabel_h +#define mozilla_AutoProfilerLabel_h + +#include "mozilla/Attributes.h" +#include "mozilla/GuardObjects.h" +#include "mozilla/Types.h" + +// The Gecko Profiler defines AutoProfilerLabel, an RAII class for +// pushing/popping entries to/from the PseudoStack. +// +// This file defines a class of the same name that does much the same thing, +// but which can be used in (and only in) mozglue. A different class is +// necessary because mozglue cannot directly access sPseudoStack. +// +// Note that this class is slightly slower than the other AutoProfilerLabel, +// and it lacks the macro wrappers. It also is effectively hardwired to use +// js::ProfileEntry::Kind::CPP_NORMAL as the kind, and +// js::ProfileEntry::Category::OTHER as the category, because that's what the +// callbacks provided by the profiler use. (Specifying the kind or category in +// this file would require #including ProfilingStack.h in mozglue, which we +// don't want to do.) + +class PseudoStack; + +namespace mozilla { + +typedef PseudoStack* (*ProfilerLabelEnter)(const char*, const char*, void*, + uint32_t); +typedef void (*ProfilerLabelExit)(PseudoStack*); + +// Register callbacks that do the entry/exit work involving sPseudoStack. +MFBT_API void RegisterProfilerLabelEnterExit(ProfilerLabelEnter aEnter, + ProfilerLabelExit aExit); + +// This #ifdef prevents this AutoProfilerLabel from being defined in libxul, +// which would conflict with the one in the profiler. +#ifdef IMPL_MFBT + +class MOZ_RAII AutoProfilerLabel { + public: + AutoProfilerLabel(const char* aLabel, const char* aDynamicString, + uint32_t aLine MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + ~AutoProfilerLabel(); + + private: + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + PseudoStack* mPseudoStack; +}; + +#endif + +} // namespace mozilla + +#endif // mozilla_AutoProfilerLabel_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 @@ -57,17 +57,16 @@ * Vector sortedInts = ... * * size_t match; - * if (BinarySearchIf(sortedInts, 0, sortedInts.length(), Comparator(13), &match)) { - * printf("found 13 at %lu\n", match); + * if (BinarySearchIf(sortedInts, 0, sortedInts.length(), Comparator(13), + * &match)) { printf("found 13 at %lu\n", match); * } * */ -template -bool -BinarySearchIf(const Container& aContainer, size_t aBegin, size_t aEnd, - const Comparator& aCompare, size_t* aMatchOrInsertionPoint) -{ +template +bool BinarySearchIf(const Container& aContainer, size_t aBegin, size_t aEnd, + const Comparator& aCompare, + size_t* aMatchOrInsertionPoint) { MOZ_ASSERT(aBegin <= aEnd); size_t low = aBegin; @@ -97,13 +96,10 @@ namespace detail { -template -class BinarySearchDefaultComparator -{ -public: - explicit BinarySearchDefaultComparator(const T& aTarget) - : mTarget(aTarget) - {} +template +class BinarySearchDefaultComparator { + public: + explicit BinarySearchDefaultComparator(const T& aTarget) : mTarget(aTarget) {} template int operator()(const U& aVal) const { @@ -118,22 +114,20 @@ return 1; } -private: + private: const T& mTarget; }; -} // namespace detail +} // namespace detail template -bool -BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd, - T aTarget, size_t* aMatchOrInsertionPoint) -{ +bool BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd, + T aTarget, size_t* aMatchOrInsertionPoint) { return BinarySearchIf(aContainer, aBegin, aEnd, detail::BinarySearchDefaultComparator(aTarget), aMatchOrInsertionPoint); } -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_BinarySearch_h +#endif // mozilla_BinarySearch_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/BloomFilter.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/BloomFilter.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/BloomFilter.h @@ -52,9 +52,8 @@ * configurations. */ -template -class BloomFilter -{ +template +class BloomFilter { /* * A counting Bloom filter with 8-bit counters. For now we assume * that having two hash functions is enough, but we may revisit that @@ -103,9 +102,8 @@ * positive rate for N == 100 and to quite bad false positive * rates for larger N. */ -public: - BloomFilter() - { + public: + BloomFilter() { static_assert(KeySize <= kKeyShift, "KeySize too big"); // Should we have a custom operator new using calloc instead and @@ -145,35 +143,23 @@ void remove(uint32_t aHash); bool mightContain(uint32_t aHash) const; -private: + private: static const size_t kArraySize = (1 << KeySize); static const uint32_t kKeyMask = (1 << KeySize) - 1; static const uint32_t kKeyShift = 16; - static uint32_t hash1(uint32_t aHash) - { - return aHash & kKeyMask; - } - static uint32_t hash2(uint32_t aHash) - { + static uint32_t hash1(uint32_t aHash) { return aHash & kKeyMask; } + static uint32_t hash2(uint32_t aHash) { return (aHash >> kKeyShift) & kKeyMask; } - uint8_t& firstSlot(uint32_t aHash) - { - return mCounters[hash1(aHash)]; - } - uint8_t& secondSlot(uint32_t aHash) - { - return mCounters[hash2(aHash)]; - } + uint8_t& firstSlot(uint32_t aHash) { return mCounters[hash1(aHash)]; } + uint8_t& secondSlot(uint32_t aHash) { return mCounters[hash2(aHash)]; } - const uint8_t& firstSlot(uint32_t aHash) const - { + const uint8_t& firstSlot(uint32_t aHash) const { return mCounters[hash1(aHash)]; } - const uint8_t& secondSlot(uint32_t aHash) const - { + const uint8_t& secondSlot(uint32_t aHash) const { return mCounters[hash2(aHash)]; } @@ -182,17 +168,13 @@ uint8_t mCounters[kArraySize]; }; -template -inline void -BloomFilter::clear() -{ +template +inline void BloomFilter::clear() { memset(mCounters, 0, kArraySize); } -template -inline void -BloomFilter::add(uint32_t aHash) -{ +template +inline void BloomFilter::add(uint32_t aHash) { uint8_t& slot1 = firstSlot(aHash); if (MOZ_LIKELY(!full(slot1))) { ++slot1; @@ -203,18 +185,14 @@ } } -template -MOZ_ALWAYS_INLINE void -BloomFilter::add(const T* aValue) -{ +template +MOZ_ALWAYS_INLINE void BloomFilter::add(const T* aValue) { uint32_t hash = aValue->hash(); return add(hash); } -template -inline void -BloomFilter::remove(uint32_t aHash) -{ +template +inline void BloomFilter::remove(uint32_t aHash) { // If the slots are full, we don't know whether we bumped them to be // there when we added or not, so just leave them full. uint8_t& slot1 = firstSlot(aHash); @@ -227,30 +205,26 @@ } } -template -MOZ_ALWAYS_INLINE void -BloomFilter::remove(const T* aValue) -{ +template +MOZ_ALWAYS_INLINE void BloomFilter::remove(const T* aValue) { uint32_t hash = aValue->hash(); remove(hash); } -template -MOZ_ALWAYS_INLINE bool -BloomFilter::mightContain(uint32_t aHash) const -{ +template +MOZ_ALWAYS_INLINE bool BloomFilter::mightContain( + uint32_t aHash) const { // Check that all the slots for this hash contain something return firstSlot(aHash) && secondSlot(aHash); } -template -MOZ_ALWAYS_INLINE bool -BloomFilter::mightContain(const T* aValue) const -{ +template +MOZ_ALWAYS_INLINE bool BloomFilter::mightContain( + const T* aValue) const { uint32_t hash = aValue->hash(); return mightContain(hash); } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_BloomFilter_h */ 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 @@ -10,6 +10,7 @@ #include #include "mozilla/AllocPolicy.h" #include "mozilla/Maybe.h" +#include "mozilla/MemoryReporting.h" #include "mozilla/Move.h" #include "mozilla/ScopeExit.h" #include "mozilla/Types.h" @@ -17,34 +18,27 @@ #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). +class InfallibleAllocPolicy; + namespace mozilla { -template -class BufferList : private AllocPolicy -{ +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 - { + 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) - { - } + : mData(aData), mSize(aSize), mCapacity(aCapacity) {} Segment(const Segment&) = delete; Segment& operator=(const Segment&) = delete; @@ -56,7 +50,7 @@ char* End() const { return mData + mSize; } }; - template + template friend class BufferList; public: @@ -68,24 +62,28 @@ 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 + // destroyed. If an infallible allocator is used, an initial buffer of size + // aInitialSize and capacity aInitialCapacity is allocated automatically. This + // data will be contiguous and can be accessed via |Start()|. If a fallible + // alloc policy is used, aInitialSize must be 0, and the fallible |Init()| + // method may be called instead. 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) - { + 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) { + MOZ_ASSERT((aInitialSize == 0 || + IsSame::value), + "BufferList may only be constructed with an initial size when " + "using an infallible alloc policy"); + AllocateSegment(aInitialSize, aInitialCapacity); } } @@ -93,19 +91,17 @@ BufferList(const BufferList& aOther) = delete; BufferList(BufferList&& aOther) - : mOwning(aOther.mOwning), - mSegments(Move(aOther.mSegments)), - mSize(aOther.mSize), - mStandardCapacity(aOther.mStandardCapacity) - { + : 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) - { + BufferList& operator=(BufferList&& aOther) { Clear(); mOwning = aOther.mOwning; @@ -118,11 +114,28 @@ ~BufferList() { Clear(); } + // Initializes the BufferList with a segment of the given size and capacity. + // May only be called once, before any segments have been allocated. + bool Init(size_t aInitialSize, size_t aInitialCapacity) { + MOZ_ASSERT(mSegments.empty()); + MOZ_ASSERT(aInitialCapacity != 0); + MOZ_ASSERT(aInitialCapacity % kSegmentAlignment == 0); + + return AllocateSegment(aInitialSize, aInitialCapacity); + } + // Returns the sum of the sizes of all the buffers. size_t Size() const { return mSize; } - void Clear() - { + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) { + size_t size = mSegments.sizeOfExcludingThis(aMallocSizeOf); + for (Segment& segment : mSegments) { + size += aMallocSizeOf(segment.Start()); + } + return size; + } + + void Clear() { if (mOwning) { for (Segment& segment : mSegments) { this->free_(segment.mData); @@ -135,10 +148,9 @@ // Iterates over bytes in the segments. You can advance it by as many bytes as // you choose. - class IterImpl - { + class IterImpl { // Invariants: - // (0) mSegment <= bufferList.mSegments.size() + // (0) mSegment <= bufferList.mSegments.length() // (1) mData <= mDataEnd // (2) If mSegment is not the last segment, mData < mDataEnd uintptr_t mSegment; @@ -147,12 +159,9 @@ friend class BufferList; - public: + public: explicit IterImpl(const BufferList& aBuffers) - : mSegment(0), - mData(nullptr), - mDataEnd(nullptr) - { + : mSegment(0), mData(nullptr), mDataEnd(nullptr) { if (!aBuffers.mSegments.empty()) { mData = aBuffers.mSegments[0].Start(); mDataEnd = aBuffers.mSegments[0].End(); @@ -161,24 +170,21 @@ // Returns a pointer to the raw data. It is valid to access up to // RemainingInSegment bytes of this buffer. - char* Data() const - { + 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 - { + 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 - { + size_t RemainingInSegment() const { MOZ_RELEASE_ASSERT(mData <= mDataEnd); return mDataEnd - mData; } @@ -187,8 +193,7 @@ // 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) - { + 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); @@ -209,8 +214,7 @@ // 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) - { + bool AdvanceAcrossSegments(const BufferList& aBuffers, size_t aBytes) { size_t bytes = aBytes; while (bytes) { size_t toAdvance = std::min(bytes, RemainingInSegment()); @@ -224,21 +228,19 @@ } // Returns true when the iterator reaches the end of the BufferList. - bool Done() const - { - return mData == mDataEnd; - } + 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 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++) { + for (uintptr_t segment = mSegment; segment < aTarget.mSegment; + segment++) { offset += aBuffers.mSegments[segment].End() - data; data = aBuffers.mSegments[segment].mData; } @@ -258,7 +260,10 @@ }; // Special convenience method that returns Iter().Data(). - char* Start() { return mSegments[0].mData; } + char* Start() { + MOZ_RELEASE_ASSERT(!mSegments.empty()); + return mSegments[0].mData; + } const char* Start() const { return mSegments[0].mData; } IterImpl Iter() const { return IterImpl(*this); } @@ -267,6 +272,11 @@ // bytes may be split across multiple buffers. Size() is increased by aSize. inline bool WriteBytes(const char* aData, size_t aSize); + // Allocates a buffer of at most |aMaxBytes| bytes and, if successful, returns + // that buffer, and places its size in |aSize|. If unsuccessful, returns null + // and leaves |aSize| undefined. + inline char* AllocateBytes(size_t aMaxSize, 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. @@ -278,9 +288,10 @@ // 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; + 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 @@ -288,8 +299,9 @@ // 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()); + 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. @@ -308,18 +320,28 @@ return start.BytesUntil(*this, end); } -private: - explicit BufferList(AllocPolicy aAP) - : AllocPolicy(aAP), - mOwning(false), - mSize(0), - mStandardCapacity(0) - { + // This takes ownership of the data + void* WriteBytesZeroCopy(char* aData, size_t aSize, size_t aCapacity) { + MOZ_ASSERT(aCapacity != 0); + MOZ_ASSERT(aSize <= aCapacity); + MOZ_ASSERT(mOwning); + + if (!mSegments.append(Segment(aData, aSize, aCapacity))) { + this->free_(aData); + return nullptr; + } + mSize += aSize; + return aData; } - void* AllocateSegment(size_t aSize, size_t aCapacity) - { + private: + explicit BufferList(AllocPolicy aAP) + : AllocPolicy(aAP), mOwning(false), mSize(0), mStandardCapacity(0) {} + + char* AllocateSegment(size_t aSize, size_t aCapacity) { MOZ_RELEASE_ASSERT(mOwning); + MOZ_ASSERT(aCapacity != 0); + MOZ_ASSERT(aSize <= aCapacity); char* data = this->template pod_malloc(aCapacity); if (!data) { @@ -339,48 +361,57 @@ size_t mStandardCapacity; }; -template -bool -BufferList::WriteBytes(const char* aData, size_t aSize) -{ +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; + while (copied < aSize) { + size_t toCopy; + char* data = AllocateBytes(aSize - copied, &toCopy); + if (!data) { + return false; + } + memcpy(data, aData + copied, toCopy); + copied += toCopy; + } + + return true; +} + +template +char* BufferList::AllocateBytes(size_t aMaxSize, size_t* aSize) { + MOZ_RELEASE_ASSERT(mOwning); + MOZ_RELEASE_ASSERT(mStandardCapacity); 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; + size_t capacity = lastSegment.mCapacity - lastSegment.mSize; + if (capacity) { + size_t size = std::min(aMaxSize, capacity); + char* data = lastSegment.mData + lastSegment.mSize; - copied += toCopy; - remaining -= toCopy; - } + lastSegment.mSize += size; + mSize += size; - while (remaining) { - size_t toCopy = std::min(remaining, mStandardCapacity); - - void* data = AllocateSegment(toCopy, mStandardCapacity); - if (!data) { - return false; + *aSize = size; + return data; } - memcpy(data, aData + copied, toCopy); - - copied += toCopy; - remaining -= toCopy; } - return true; + size_t size = std::min(aMaxSize, mStandardCapacity); + char* data = AllocateSegment(size, mStandardCapacity); + if (data) { + *aSize = size; + } + return data; } -template -bool -BufferList::ReadBytes(IterImpl& aIter, char* aData, size_t aSize) const -{ +template +bool BufferList::ReadBytes(IterImpl& aIter, char* aData, + size_t aSize) const { size_t copied = 0; size_t remaining = aSize; while (remaining) { @@ -399,18 +430,20 @@ return true; } -template template -BufferList -BufferList::Borrow(IterImpl& aIter, size_t aSize, bool* aSuccess, - BorrowingAllocPolicy aAP) const -{ +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))) { + if (!toAdvance || !result.mSegments.append( + typename BufferList::Segment( + aIter.mData, toAdvance, toAdvance))) { *aSuccess = false; return result; } @@ -423,17 +456,19 @@ return result; } -template template -BufferList -BufferList::MoveFallible(bool* aSuccess, OtherAllocPolicy aAP) -{ +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))) { + if (!toAdvance || + !result.mSegments.append(typename BufferList::Segment( + iter.mData, toAdvance, toAdvance))) { *aSuccess = false; result.mSegments.clear(); return result; @@ -448,10 +483,10 @@ return result; } -template -BufferList -BufferList::Extract(IterImpl& aIter, size_t aSize, bool* aSuccess) -{ +template +BufferList BufferList::Extract(IterImpl& aIter, + size_t aSize, + bool* aSuccess) { MOZ_RELEASE_ASSERT(aSize); MOZ_RELEASE_ASSERT(mOwning); MOZ_ASSERT(aSize % kSegmentAlignment == 0); @@ -526,10 +561,9 @@ // 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)); + 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 @@ -538,8 +572,8 @@ // 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)); + (aIter.mSegment == copyStart + segmentsToCopy) || + (aIter.Done() && aIter.mSegment == copyStart + segmentsToCopy - 1)); mSegments.erase(mSegments.begin() + copyStart, mSegments.begin() + copyStart + segmentsToCopy); @@ -549,7 +583,7 @@ if (lastSegmentSize.isSome()) { // We called reserve() on result.mSegments so infallibleAppend is safe. result.mSegments.infallibleAppend( - Segment(finalSegment, 0, mStandardCapacity)); + Segment(finalSegment, 0, mStandardCapacity)); bool r = result.WriteBytes(aIter.Data(), *lastSegmentSize); MOZ_RELEASE_ASSERT(r); aIter.Advance(*this, *lastSegmentSize); @@ -563,6 +597,6 @@ return result; } -} // namespace mozilla +} // 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 @@ -37,14 +37,11 @@ * important to you, you should use the outparam version. In all other cases, * you should use the direct return version. */ -template -inline void -BitwiseCast(const From aFrom, To* aResult) -{ +template +inline void BitwiseCast(const From aFrom, To* aResult) { static_assert(sizeof(From) == sizeof(To), "To and From must have the same size"); - union - { + union { From mFrom; To mTo; } u; @@ -52,10 +49,8 @@ *aResult = u.mTo; } -template -inline To -BitwiseCast(const From aFrom) -{ +template +inline To BitwiseCast(const From aFrom) { To temp; BitwiseCast(aFrom, &temp); return temp; @@ -66,10 +61,10 @@ enum ToSignedness { ToIsSigned, ToIsUnsigned }; enum FromSignedness { FromIsSigned, FromIsUnsigned }; -template::value ? FromIsSigned : FromIsUnsigned, - ToSignedness = IsSigned::value ? ToIsSigned : ToIsUnsigned> +template ::value ? FromIsSigned : FromIsUnsigned, + ToSignedness = IsSigned::value ? ToIsSigned : ToIsUnsigned> struct BoundsCheckImpl; // Implicit conversions on operands to binary operations make this all a bit @@ -81,50 +76,37 @@ // Unsigned-to-unsigned range check -template sizeof(To)) - ? FromIsBigger - : FromIsNotBigger> +template sizeof(To)) ? FromIsBigger : FromIsNotBigger> struct UnsignedUnsignedCheck; -template -struct UnsignedUnsignedCheck -{ -public: - static bool checkBounds(const From aFrom) - { - return aFrom <= From(To(-1)); - } +template +struct UnsignedUnsignedCheck { + public: + static bool checkBounds(const From aFrom) { return aFrom <= From(To(-1)); } }; -template -struct UnsignedUnsignedCheck -{ -public: - static bool checkBounds(const From aFrom) - { - return true; - } +template +struct UnsignedUnsignedCheck { + public: + static bool checkBounds(const From aFrom) { return true; } }; -template -struct BoundsCheckImpl -{ -public: - static bool checkBounds(const From aFrom) - { +template +struct BoundsCheckImpl { + public: + static bool checkBounds(const From aFrom) { return UnsignedUnsignedCheck::checkBounds(aFrom); } }; // Signed-to-unsigned range check -template -struct BoundsCheckImpl -{ -public: - static bool checkBounds(const From aFrom) - { +template +struct BoundsCheckImpl { + public: + static bool checkBounds(const From aFrom) { if (aFrom < 0) { return false; } @@ -139,105 +121,97 @@ enum USComparison { FromIsSmaller, FromIsNotSmaller }; -template +template struct UnsignedSignedCheck; -template -struct UnsignedSignedCheck -{ -public: - static bool checkBounds(const From aFrom) - { - return true; - } +template +struct UnsignedSignedCheck { + public: + static bool checkBounds(const From aFrom) { return true; } }; -template -struct UnsignedSignedCheck -{ -public: - static bool checkBounds(const From aFrom) - { +template +struct UnsignedSignedCheck { + public: + static bool checkBounds(const From aFrom) { const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1); return aFrom <= From(MaxValue); } }; -template -struct BoundsCheckImpl -{ -public: - static bool checkBounds(const From aFrom) - { +template +struct BoundsCheckImpl { + public: + static bool checkBounds(const From aFrom) { return UnsignedSignedCheck::checkBounds(aFrom); } }; // Signed-to-signed range check -template -struct BoundsCheckImpl -{ -public: - static bool checkBounds(const From aFrom) - { +template +struct BoundsCheckImpl { + public: + static bool checkBounds(const From aFrom) { if (sizeof(From) <= sizeof(To)) { return true; } const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1); const To MinValue = -MaxValue - To(1); - return From(MinValue) <= aFrom && - From(aFrom) <= From(MaxValue); + return From(MinValue) <= aFrom && From(aFrom) <= From(MaxValue); } }; -template::value && - IsIntegral::value> +template ::value&& IsIntegral::value> class BoundsChecker; -template -class BoundsChecker -{ -public: +template +class BoundsChecker { + public: static bool checkBounds(const From aFrom) { return true; } }; -template -class BoundsChecker -{ -public: - static bool checkBounds(const From aFrom) - { +template +class BoundsChecker { + public: + static bool checkBounds(const From aFrom) { return BoundsCheckImpl::checkBounds(aFrom); } }; -template -inline bool -IsInBounds(const From aFrom) -{ +template +inline bool IsInBounds(const From aFrom) { return BoundsChecker::checkBounds(aFrom); } -} // namespace detail +} // namespace detail /** * Cast a value of integral type |From| to a value of integral type |To|, * asserting that the cast will be a safe cast per C++ (that is, that |to| is in * the range of values permitted for the type |From|). */ -template -inline To -AssertedCast(const From aFrom) -{ +template +inline To AssertedCast(const From aFrom) { MOZ_ASSERT((detail::IsInBounds(aFrom))); return static_cast(aFrom); } -} // namespace mozilla +/** + * Cast a value of integral type |From| to a value of integral type |To|, + * release asserting that the cast will be a safe cast per C++ (that is, that + * |to| is in the range of values permitted for the type |From|). + */ +template +inline To ReleaseAssertedCast(const From aFrom) { + MOZ_RELEASE_ASSERT((detail::IsInBounds(aFrom))); + return static_cast(aFrom); +} + +} // namespace mozilla #endif /* mozilla_Casting_h */ 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 @@ -35,23 +35,20 @@ namespace detail { extern MFBT_DATA Atomic gChaosModeCounter; extern MFBT_DATA ChaosFeature gChaosFeatures; -} // namespace detail +} // namespace detail /** * When "chaos mode" is activated, code that makes implicitly nondeterministic * choices is encouraged to make random and extreme choices, to test more * code paths and uncover bugs. */ -class ChaosMode -{ -public: - static void SetChaosFeature(ChaosFeature aChaosFeature) - { +class ChaosMode { + public: + static void SetChaosFeature(ChaosFeature aChaosFeature) { detail::gChaosFeatures = aChaosFeature; } - static bool isActive(ChaosFeature aFeature) - { + static bool isActive(ChaosFeature aFeature) { if (detail::gChaosModeCounter > 0) { return true; } @@ -64,16 +61,12 @@ * chaos mode state. If the activation level is nonzero all chaos mode * features are activated. */ - static void enterChaosMode() - { - detail::gChaosModeCounter++; - } + static void enterChaosMode() { detail::gChaosModeCounter++; } /** * Decrease the chaos mode activation level. See enterChaosMode(). */ - static void leaveChaosMode() - { + static void leaveChaosMode() { MOZ_ASSERT(detail::gChaosModeCounter > 0); detail::gChaosModeCounter--; } @@ -82,8 +75,7 @@ * Returns a somewhat (but not uniformly) random uint32_t < aBound. * Not to be used for anything except ChaosMode, since it's not very random. */ - static uint32_t randomUint32LessThan(uint32_t aBound) - { + static uint32_t randomUint32LessThan(uint32_t aBound) { MOZ_ASSERT(aBound != 0); return uint32_t(rand()) % aBound; } 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 @@ -18,83 +18,63 @@ */ #ifdef WIN32 -# define MOZ_USE_CHAR16_WRAPPER -# include - /** - * Win32 API extensively uses wchar_t, which is represented by a separated - * builtin type than char16_t per spec. It's not the case for MSVC prior to - * MSVC 2015, but other compilers follow the spec. We want to mix wchar_t and - * char16_t on Windows builds. This class is supposed to make it easier. It - * stores char16_t const pointer, but provides implicit casts for wchar_t as - * well. On other platforms, we simply use - * |typedef const char16_t* char16ptr_t|. Here, we want to make the class as - * similar to this typedef, including providing some casts that are allowed - * by the typedef. - */ -class char16ptr_t -{ -private: +#define MOZ_USE_CHAR16_WRAPPER +#include +#include "mozilla/Attributes.h" +/** + * Win32 API extensively uses wchar_t, which is represented by a separated + * builtin type than char16_t per spec. It's not the case for MSVC prior to + * MSVC 2015, but other compilers follow the spec. We want to mix wchar_t and + * char16_t on Windows builds. This class is supposed to make it easier. It + * stores char16_t const pointer, but provides implicit casts for wchar_t as + * well. On other platforms, we simply use + * |typedef const char16_t* char16ptr_t|. Here, we want to make the class as + * similar to this typedef, including providing some casts that are allowed + * by the typedef. + */ +class char16ptr_t { + private: const char16_t* mPtr; static_assert(sizeof(char16_t) == sizeof(wchar_t), "char16_t and wchar_t sizes differ"); -public: - char16ptr_t(const char16_t* aPtr) : mPtr(aPtr) {} - char16ptr_t(const wchar_t* aPtr) : - mPtr(reinterpret_cast(aPtr)) - {} + public: + MOZ_IMPLICIT char16ptr_t(const char16_t* aPtr) : mPtr(aPtr) {} + MOZ_IMPLICIT char16ptr_t(const wchar_t* aPtr) + : mPtr(reinterpret_cast(aPtr)) {} /* Without this, nullptr assignment would be ambiguous. */ - constexpr char16ptr_t(decltype(nullptr)) : mPtr(nullptr) {} + constexpr MOZ_IMPLICIT char16ptr_t(decltype(nullptr)) : mPtr(nullptr) {} - operator const char16_t*() const - { - return mPtr; - } - operator const wchar_t*() const - { + operator const char16_t*() const { return mPtr; } + operator const wchar_t*() const { return reinterpret_cast(mPtr); } - operator const void*() const - { - return mPtr; - } - operator bool() const - { - return mPtr != nullptr; + + operator wchar_t*() { + return const_cast(reinterpret_cast(mPtr)); } + operator const void*() const { return mPtr; } + explicit operator bool() const { return mPtr != nullptr; } + /* Explicit cast operators to allow things like (char16_t*)str. */ - explicit operator char16_t*() const - { - return const_cast(mPtr); - } - explicit operator wchar_t*() const - { + explicit operator char16_t*() const { return const_cast(mPtr); } + explicit operator wchar_t*() const { return const_cast(static_cast(*this)); } - explicit operator int() const - { - return reinterpret_cast(mPtr); - } - explicit operator unsigned int() const - { + explicit operator int() const { return reinterpret_cast(mPtr); } + explicit operator unsigned int() const { return reinterpret_cast(mPtr); } - explicit operator long() const - { - return reinterpret_cast(mPtr); - } - explicit operator unsigned long() const - { + explicit operator long() const { return reinterpret_cast(mPtr); } + explicit operator unsigned long() const { return reinterpret_cast(mPtr); } - explicit operator long long() const - { + explicit operator long long() const { return reinterpret_cast(mPtr); } - explicit operator unsigned long long() const - { + explicit operator unsigned long long() const { return reinterpret_cast(mPtr); } @@ -103,78 +83,51 @@ * WCHAR*. Supporting this requires explicit operators to support the * requisite explicit casts. */ - explicit operator const char*() const - { + explicit operator const char*() const { return reinterpret_cast(mPtr); } - explicit operator const unsigned char*() const - { + explicit operator const unsigned char*() const { return reinterpret_cast(mPtr); } - explicit operator unsigned char*() const - { - return - const_cast(reinterpret_cast(mPtr)); - } - explicit operator void*() const - { - return const_cast(mPtr); + explicit operator unsigned char*() const { + return const_cast( + reinterpret_cast(mPtr)); } + explicit operator void*() const { return const_cast(mPtr); } /* Some operators used on pointers. */ - char16_t operator[](size_t aIndex) const - { - return mPtr[aIndex]; - } - bool operator==(const char16ptr_t& aOther) const - { + char16_t operator[](size_t aIndex) const { return mPtr[aIndex]; } + bool operator==(const char16ptr_t& aOther) const { return mPtr == aOther.mPtr; } - bool operator==(decltype(nullptr)) const - { - return mPtr == nullptr; - } - bool operator!=(const char16ptr_t& aOther) const - { + bool operator==(decltype(nullptr)) const { return mPtr == nullptr; } + bool operator!=(const char16ptr_t& aOther) const { return mPtr != aOther.mPtr; } - bool operator!=(decltype(nullptr)) const - { - return mPtr != nullptr; - } - char16ptr_t operator+(int aValue) const - { - return char16ptr_t(mPtr + aValue); - } - char16ptr_t operator+(unsigned int aValue) const - { + bool operator!=(decltype(nullptr)) const { return mPtr != nullptr; } + char16ptr_t operator+(int aValue) const { return char16ptr_t(mPtr + aValue); } + char16ptr_t operator+(unsigned int aValue) const { return char16ptr_t(mPtr + aValue); } - char16ptr_t operator+(long aValue) const - { + char16ptr_t operator+(long aValue) const { return char16ptr_t(mPtr + aValue); } - char16ptr_t operator+(unsigned long aValue) const - { + char16ptr_t operator+(unsigned long aValue) const { return char16ptr_t(mPtr + aValue); } - char16ptr_t operator+(long long aValue) const - { + char16ptr_t operator+(long long aValue) const { return char16ptr_t(mPtr + aValue); } - char16ptr_t operator+(unsigned long long aValue) const - { + char16ptr_t operator+(unsigned long long aValue) const { return char16ptr_t(mPtr + aValue); } - ptrdiff_t operator-(const char16ptr_t& aOther) const - { + ptrdiff_t operator-(const char16ptr_t& aOther) const { return mPtr - aOther.mPtr; } }; -inline decltype((char*)0-(char*)0) -operator-(const char16_t* aX, const char16ptr_t aY) -{ +inline decltype((char*)0 - (char*)0) operator-(const char16_t* aX, + const char16ptr_t aY) { return aX - static_cast(aY); } Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/CheckedInt.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/CheckedInt.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/CheckedInt.h @@ -14,9 +14,27 @@ #include "mozilla/Attributes.h" #include "mozilla/IntegerTypeTraits.h" +// Probe for builtin math overflow support. Disabled for 32-bit builds for now +// since "gcc -m32" claims to support these but its implementation is buggy. +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82274 +#if defined(HAVE_64BIT_BUILD) +#if defined(__has_builtin) +#define MOZ_HAS_BUILTIN_OP_OVERFLOW (__has_builtin(__builtin_add_overflow)) +#elif defined(__GNUC__) +// (clang also defines __GNUC__ but it supports __has_builtin since at least +// v3.1 (released in 2012) so it won't get here.) +#define MOZ_HAS_BUILTIN_OP_OVERFLOW (__GNUC__ >= 5) +#else +#define MOZ_HAS_BUILTIN_OP_OVERFLOW (0) +#endif +#else +#define MOZ_HAS_BUILTIN_OP_OVERFLOW (0) +#endif + namespace mozilla { -template class CheckedInt; +template +class CheckedInt; namespace detail { @@ -33,94 +51,110 @@ struct UnsupportedType {}; -template -struct IsSupportedPass2 -{ +template +struct IsSupportedPass2 { static const bool value = false; }; -template -struct IsSupported -{ +template +struct IsSupported { static const bool value = IsSupportedPass2::value; }; -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; /* * Step 2: Implement the actual validity checks. @@ -128,25 +162,19 @@ * Ideas taken from IntegerLib, code different. */ -template -struct TwiceBiggerType -{ +template +struct TwiceBiggerType { typedef typename detail::StdintTypeForSizeAndSignedness< - sizeof(IntegerType) * 2, - IsSigned::value - >::Type Type; + sizeof(IntegerType) * 2, IsSigned::value>::Type Type; }; -template -struct TwiceBiggerType -{ +template +struct TwiceBiggerType { typedef UnsupportedType Type; }; -template -inline bool -HasSignBit(T aX) -{ +template +inline bool HasSignBit(T aX) { // In C++, right bit shifts on negative values is undefined by the standard. // Notice that signed-to-unsigned conversions are always well-defined in the // standard, as the value congruent modulo 2**n as expected. By contrast, @@ -157,104 +185,78 @@ // Bitwise ops may return a larger type, so it's good to use this inline // helper guaranteeing that the result is really of type T. -template -inline T -BinaryComplement(T aX) -{ +template +inline T BinaryComplement(T aX) { return ~aX; } -template::value, - bool IsUSigned = IsSigned::value> -struct DoesRangeContainRange -{ -}; +template ::value, + bool IsUSigned = IsSigned::value> +struct DoesRangeContainRange {}; -template -struct DoesRangeContainRange -{ +template +struct DoesRangeContainRange { static const bool value = sizeof(T) >= sizeof(U); }; -template -struct DoesRangeContainRange -{ +template +struct DoesRangeContainRange { static const bool value = sizeof(T) > sizeof(U); }; -template -struct DoesRangeContainRange -{ +template +struct DoesRangeContainRange { static const bool value = false; }; -template::value, - bool IsUSigned = IsSigned::value, - bool DoesTRangeContainURange = DoesRangeContainRange::value> +template ::value, + bool IsUSigned = IsSigned::value, + bool DoesTRangeContainURange = DoesRangeContainRange::value> struct IsInRangeImpl {}; -template -struct IsInRangeImpl -{ - static bool run(U) - { - return true; - } +template +struct IsInRangeImpl { + static bool constexpr run(U) { return true; } }; -template -struct IsInRangeImpl -{ - static bool run(U aX) - { +template +struct IsInRangeImpl { + static bool constexpr run(U aX) { return aX <= MaxValue::value && aX >= MinValue::value; } }; -template -struct IsInRangeImpl -{ - static bool run(U aX) - { - return aX <= MaxValue::value; - } +template +struct IsInRangeImpl { + static bool constexpr run(U aX) { return aX <= MaxValue::value; } }; -template -struct IsInRangeImpl -{ - static bool run(U aX) - { +template +struct IsInRangeImpl { + static bool constexpr run(U aX) { return sizeof(T) > sizeof(U) || aX <= U(MaxValue::value); } }; -template -struct IsInRangeImpl -{ - static bool run(U aX) - { - return sizeof(T) >= sizeof(U) - ? aX >= 0 - : aX >= 0 && aX <= U(MaxValue::value); +template +struct IsInRangeImpl { + static bool constexpr run(U aX) { + return sizeof(T) >= sizeof(U) ? aX >= 0 + : aX >= 0 && aX <= U(MaxValue::value); } }; -template -inline bool -IsInRange(U aX) -{ +template +inline constexpr bool IsInRange(U aX) { return IsInRangeImpl::run(aX); } -template -inline bool -IsAddValid(T aX, T aY) -{ +template +inline bool IsAddValid(T aX, T aY) { +#if MOZ_HAS_BUILTIN_OP_OVERFLOW + T dummy; + return !__builtin_add_overflow(aX, aY, &dummy); +#else // Addition is valid if the sign of aX+aY is equal to either that of aX or // that of aY. Since the value of aX+aY is undefined if we have a signed // type, we compute it using the unsigned type of the same size. Beware! @@ -265,14 +267,17 @@ typename MakeUnsigned::Type uy = aY; typename MakeUnsigned::Type result = ux + uy; return IsSigned::value - ? HasSignBit(BinaryComplement(T((result ^ aX) & (result ^ aY)))) - : BinaryComplement(aX) >= aY; + ? HasSignBit(BinaryComplement(T((result ^ aX) & (result ^ aY)))) + : BinaryComplement(aX) >= aY; +#endif } -template -inline bool -IsSubValid(T aX, T aY) -{ +template +inline bool IsSubValid(T aX, T aY) { +#if MOZ_HAS_BUILTIN_OP_OVERFLOW + T dummy; + return !__builtin_sub_overflow(aX, aY, &dummy); +#else // Subtraction is valid if either aX and aY have same sign, or aX-aY and aX // have same sign. Since the value of aX-aY is undefined if we have a signed // type, we compute it using the unsigned type of the same size. @@ -281,32 +286,28 @@ typename MakeUnsigned::Type result = ux - uy; return IsSigned::value - ? HasSignBit(BinaryComplement(T((result ^ aX) & (aX ^ aY)))) - : aX >= aY; + ? HasSignBit(BinaryComplement(T((result ^ aX) & (aX ^ aY)))) + : aX >= aY; +#endif } -template::value, - bool TwiceBiggerTypeIsSupported = - IsSupported::Type>::value> +template ::value, + bool TwiceBiggerTypeIsSupported = + IsSupported::Type>::value> struct IsMulValidImpl {}; -template -struct IsMulValidImpl -{ - static bool run(T aX, T aY) - { +template +struct IsMulValidImpl { + static bool run(T aX, T aY) { typedef typename TwiceBiggerType::Type TwiceBiggerType; TwiceBiggerType product = TwiceBiggerType(aX) * TwiceBiggerType(aY); return IsInRange(product); } }; -template -struct IsMulValidImpl -{ - static bool run(T aX, T aY) - { +template +struct IsMulValidImpl { + static bool run(T aX, T aY) { const T max = MaxValue::value; const T min = MinValue::value; @@ -314,51 +315,44 @@ return true; } if (aX > 0) { - return aY > 0 - ? aX <= max / aY - : aY >= min / aX; + return aY > 0 ? aX <= max / aY : aY >= min / aX; } // If we reach this point, we know that aX < 0. - return aY > 0 - ? aX >= min / aY - : aY >= max / aX; + return aY > 0 ? aX >= min / aY : aY >= max / aX; } }; -template -struct IsMulValidImpl -{ - static bool run(T aX, T aY) - { - return aY == 0 || aX <= MaxValue::value / aY; +template +struct IsMulValidImpl { + static bool run(T aX, T aY) { + return aY == 0 || aX <= MaxValue::value / aY; } }; -template -inline bool -IsMulValid(T aX, T aY) -{ +template +inline bool IsMulValid(T aX, T aY) { +#if MOZ_HAS_BUILTIN_OP_OVERFLOW + T dummy; + return !__builtin_mul_overflow(aX, aY, &dummy); +#else return IsMulValidImpl::run(aX, aY); +#endif } -template -inline bool -IsDivValid(T aX, T aY) -{ +template +inline bool IsDivValid(T aX, T aY) { // Keep in mind that in the signed case, min/-1 is invalid because // abs(min)>max. return aY != 0 && !(IsSigned::value && aX == MinValue::value && aY == T(-1)); } -template::value> +template ::value> struct IsModValidImpl; -template -inline bool -IsModValid(T aX, T aY) -{ +template +inline bool IsModValid(T aX, T aY) { return IsModValidImpl::run(aX, aY); } @@ -373,20 +367,14 @@ * Checking that aX>=0 is a warning when T is unsigned. */ -template -struct IsModValidImpl -{ - static inline bool run(T aX, T aY) - { - return aY >= 1; - } +template +struct IsModValidImpl { + static inline bool run(T aX, T aY) { return aY >= 1; } }; -template -struct IsModValidImpl -{ - static inline bool run(T aX, T aY) - { +template +struct IsModValidImpl { + static inline bool run(T aX, T aY) { if (aX < 0) { return false; } @@ -394,25 +382,21 @@ } }; -template::value> +template ::value> struct NegateImpl; -template -struct NegateImpl -{ - static CheckedInt negate(const CheckedInt& aVal) - { +template +struct NegateImpl { + static CheckedInt negate(const CheckedInt& aVal) { // Handle negation separately for signed/unsigned, for simpler code and to // avoid an MSVC warning negating an unsigned value. return CheckedInt(0, aVal.isValid() && aVal.mValue == 0); } }; -template -struct NegateImpl -{ - static CheckedInt negate(const CheckedInt& aVal) - { +template +struct NegateImpl { + static CheckedInt negate(const CheckedInt& aVal) { // Watch out for the min-value, which (with twos-complement) can't be // negated as -min-value is then (max-value + 1). if (!aVal.isValid() || aVal.mValue == MinValue::value) { @@ -422,8 +406,7 @@ } }; -} // namespace detail - +} // namespace detail /* * Step 3: Now define the CheckedInt class. @@ -496,24 +479,22 @@ typedef CheckedInt CheckedUint16; @endcode */ -template -class CheckedInt -{ -protected: +template +class CheckedInt { + protected: T mValue; bool mIsValid; - template - CheckedInt(U aValue, bool aIsValid) : mValue(aValue), mIsValid(aIsValid) - { - static_assert(detail::IsSupported::value && - detail::IsSupported::value, - "This type is not supported by CheckedInt"); + template + CheckedInt(U aValue, bool aIsValid) : mValue(aValue), mIsValid(aIsValid) { + static_assert( + detail::IsSupported::value && detail::IsSupported::value, + "This type is not supported by CheckedInt"); } friend struct detail::NegateImpl; -public: + public: /** * Constructs a checked integer with given @a value. The checked integer is * initialized as valid or invalid depending on whether the @a value @@ -525,38 +506,36 @@ * documentation for class CheckedInt, this constructor checks that its * argument is valid. */ - template - MOZ_IMPLICIT CheckedInt(U aValue) MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT - : mValue(T(aValue)), - mIsValid(detail::IsInRange(aValue)) - { - static_assert(detail::IsSupported::value && - detail::IsSupported::value, - "This type is not supported by CheckedInt"); + template + MOZ_IMPLICIT constexpr CheckedInt(U aValue) MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT + : mValue(T(aValue)), + mIsValid(detail::IsInRange(aValue)) { + static_assert( + detail::IsSupported::value && detail::IsSupported::value, + "This type is not supported by CheckedInt"); } - template + template friend class CheckedInt; - template - CheckedInt toChecked() const - { + template + CheckedInt toChecked() const { CheckedInt ret(mValue); ret.mIsValid = ret.mIsValid && mIsValid; return ret; } /** Constructs a valid checked integer with initial value 0 */ - CheckedInt() : mValue(0), mIsValid(true) - { + constexpr CheckedInt() : mValue(0), mIsValid(true) { static_assert(detail::IsSupported::value, "This type is not supported by CheckedInt"); } /** @returns the actual value */ - T value() const - { - MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)"); + T value() const { + MOZ_ASSERT( + mIsValid, + "Invalid checked integer (division by zero or integer overflow)"); return mValue; } @@ -565,50 +544,44 @@ * of an invalid operation or of an operation involving an invalid checked * integer */ - bool isValid() const - { - return mIsValid; - } - - template - friend CheckedInt operator +(const CheckedInt& aLhs, - const CheckedInt& aRhs); - template - CheckedInt& operator +=(U aRhs); - CheckedInt& operator +=(const CheckedInt& aRhs); - - template - friend CheckedInt operator -(const CheckedInt& aLhs, - const CheckedInt& aRhs); - template - CheckedInt& operator -=(U aRhs); - CheckedInt& operator -=(const CheckedInt& aRhs); - - template - friend CheckedInt operator *(const CheckedInt& aLhs, - const CheckedInt& aRhs); - template - CheckedInt& operator *=(U aRhs); - CheckedInt& operator *=(const CheckedInt& aRhs); - - template - friend CheckedInt operator /(const CheckedInt& aLhs, - const CheckedInt& aRhs); - template - CheckedInt& operator /=(U aRhs); - CheckedInt& operator /=(const CheckedInt& aRhs); - - template - friend CheckedInt operator %(const CheckedInt& aLhs, - const CheckedInt& aRhs); - template - CheckedInt& operator %=(U aRhs); - CheckedInt& operator %=(const CheckedInt& aRhs); - - CheckedInt operator -() const - { - return detail::NegateImpl::negate(*this); - } + bool isValid() const { return mIsValid; } + + template + friend CheckedInt operator+(const CheckedInt& aLhs, + const CheckedInt& aRhs); + template + CheckedInt& operator+=(U aRhs); + CheckedInt& operator+=(const CheckedInt& aRhs); + + template + friend CheckedInt operator-(const CheckedInt& aLhs, + const CheckedInt& aRhs); + template + CheckedInt& operator-=(U aRhs); + CheckedInt& operator-=(const CheckedInt& aRhs); + + template + friend CheckedInt operator*(const CheckedInt& aLhs, + const CheckedInt& aRhs); + template + CheckedInt& operator*=(U aRhs); + CheckedInt& operator*=(const CheckedInt& aRhs); + + template + friend CheckedInt operator/(const CheckedInt& aLhs, + const CheckedInt& aRhs); + template + CheckedInt& operator/=(U aRhs); + CheckedInt& operator/=(const CheckedInt& aRhs); + + template + friend CheckedInt operator%(const CheckedInt& aLhs, + const CheckedInt& aRhs); + template + CheckedInt& operator%=(U aRhs); + CheckedInt& operator%=(const CheckedInt& aRhs); + + CheckedInt operator-() const { return detail::NegateImpl::negate(*this); } /** * @returns true if the left and right hand sides are valid @@ -628,71 +601,87 @@ * 2. This is similar to the behavior of IEEE floats, where a==b * means that a and b have the same value *and* neither is NaN. */ - bool operator ==(const CheckedInt& aOther) const - { + bool operator==(const CheckedInt& aOther) const { return mIsValid && aOther.mIsValid && mValue == aOther.mValue; } /** prefix ++ */ - CheckedInt& operator++() - { + CheckedInt& operator++() { *this += 1; return *this; } /** postfix ++ */ - CheckedInt operator++(int) - { + CheckedInt operator++(int) { CheckedInt tmp = *this; *this += 1; return tmp; } /** prefix -- */ - CheckedInt& operator--() - { + CheckedInt& operator--() { *this -= 1; return *this; } /** postfix -- */ - CheckedInt operator--(int) - { + CheckedInt operator--(int) { CheckedInt tmp = *this; *this -= 1; return tmp; } -private: + private: /** * The !=, <, <=, >, >= operators are disabled: * see the comment on operator==. */ - template bool operator !=(U aOther) const = delete; - template bool operator < (U aOther) const = delete; - template bool operator <=(U aOther) const = delete; - template bool operator > (U aOther) const = delete; - template bool operator >=(U aOther) const = delete; -}; - -#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \ - template \ - inline CheckedInt \ - operator OP(const CheckedInt& aLhs, const CheckedInt& aRhs) \ - { \ - if (!detail::Is##NAME##Valid(aLhs.mValue, aRhs.mValue)) { \ - return CheckedInt(0, false); \ - } \ - return CheckedInt(aLhs.mValue OP aRhs.mValue, \ - aLhs.mIsValid && aRhs.mIsValid); \ - } - + template + bool operator!=(U aOther) const = delete; + template + bool operator<(U aOther) const = delete; + template + bool operator<=(U aOther) const = delete; + template + bool operator>(U aOther) const = delete; + template + bool operator>=(U aOther) const = delete; +}; + +#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \ + template \ + inline CheckedInt operator OP(const CheckedInt& aLhs, \ + const CheckedInt& aRhs) { \ + if (!detail::Is##NAME##Valid(aLhs.mValue, aRhs.mValue)) { \ + return CheckedInt(0, false); \ + } \ + return CheckedInt(aLhs.mValue OP aRhs.mValue, \ + aLhs.mIsValid && aRhs.mIsValid); \ + } + +#if MOZ_HAS_BUILTIN_OP_OVERFLOW +#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(NAME, OP, FUN) \ + template \ + inline CheckedInt operator OP(const CheckedInt& aLhs, \ + const CheckedInt& aRhs) { \ + T result; \ + if (FUN(aLhs.mValue, aRhs.mValue, &result)) { \ + return CheckedInt(0, false); \ + } \ + return CheckedInt(result, aLhs.mIsValid && aRhs.mIsValid); \ + } +MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(Add, +, __builtin_add_overflow) +MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(Sub, -, __builtin_sub_overflow) +MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(Mul, *, __builtin_mul_overflow) +#undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2 +#else MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +) MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -) MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *) +#endif + MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /) MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mod, %) - #undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR // Implement castToCheckedInt(x), making sure that @@ -703,55 +692,48 @@ namespace detail { -template -struct CastToCheckedIntImpl -{ +template +struct CastToCheckedIntImpl { typedef CheckedInt ReturnType; static CheckedInt run(U aU) { return aU; } }; -template -struct CastToCheckedIntImpl > -{ +template +struct CastToCheckedIntImpl > { typedef const CheckedInt& ReturnType; static const CheckedInt& run(const CheckedInt& aU) { return aU; } }; -} // namespace detail +} // namespace detail -template -inline typename detail::CastToCheckedIntImpl::ReturnType -castToCheckedInt(U aU) -{ - static_assert(detail::IsSupported::value && - detail::IsSupported::value, +template +inline typename detail::CastToCheckedIntImpl::ReturnType castToCheckedInt( + U aU) { + static_assert(detail::IsSupported::value && detail::IsSupported::value, "This type is not supported by CheckedInt"); return detail::CastToCheckedIntImpl::run(aU); } -#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \ - template \ - template \ - CheckedInt& CheckedInt::operator COMPOUND_OP(U aRhs) \ - { \ - *this = *this OP castToCheckedInt(aRhs); \ - return *this; \ - } \ - template \ - CheckedInt& CheckedInt::operator COMPOUND_OP(const CheckedInt& aRhs) \ - { \ - *this = *this OP aRhs; \ - return *this; \ - } \ - template \ - inline CheckedInt operator OP(const CheckedInt& aLhs, U aRhs) \ - { \ - return aLhs OP castToCheckedInt(aRhs); \ - } \ - template \ - inline CheckedInt operator OP(U aLhs, const CheckedInt& aRhs) \ - { \ - return castToCheckedInt(aLhs) OP aRhs; \ +#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \ + template \ + template \ + CheckedInt& CheckedInt::operator COMPOUND_OP(U aRhs) { \ + *this = *this OP castToCheckedInt(aRhs); \ + return *this; \ + } \ + template \ + CheckedInt& CheckedInt::operator COMPOUND_OP( \ + const CheckedInt& aRhs) { \ + *this = *this OP aRhs; \ + return *this; \ + } \ + template \ + inline CheckedInt operator OP(const CheckedInt& aLhs, U aRhs) { \ + return aLhs OP castToCheckedInt(aRhs); \ + } \ + template \ + inline CheckedInt operator OP(U aLhs, const CheckedInt& aRhs) { \ + return castToCheckedInt(aLhs) OP aRhs; \ } MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=) @@ -762,30 +744,26 @@ #undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS -template -inline bool -operator ==(const CheckedInt& aLhs, U aRhs) -{ +template +inline bool operator==(const CheckedInt& aLhs, U aRhs) { return aLhs == castToCheckedInt(aRhs); } -template -inline bool -operator ==(U aLhs, const CheckedInt& aRhs) -{ +template +inline bool operator==(U aLhs, const CheckedInt& aRhs) { return castToCheckedInt(aLhs) == aRhs; } // Convenience typedefs. -typedef CheckedInt CheckedInt8; -typedef CheckedInt CheckedUint8; -typedef CheckedInt CheckedInt16; +typedef CheckedInt CheckedInt8; +typedef CheckedInt CheckedUint8; +typedef CheckedInt CheckedInt16; typedef CheckedInt CheckedUint16; -typedef CheckedInt CheckedInt32; +typedef CheckedInt CheckedInt32; typedef CheckedInt CheckedUint32; -typedef CheckedInt CheckedInt64; +typedef CheckedInt CheckedInt64; typedef CheckedInt CheckedUint64; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_CheckedInt_h */ 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 @@ -14,26 +14,26 @@ #if !defined(__clang__) && defined(__GNUC__) -# undef MOZ_IS_GCC -# define MOZ_IS_GCC 1 - /* - * 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))) -# 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 +#undef MOZ_IS_GCC +#define MOZ_IS_GCC 1 +/* + * 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))) +#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, 9, 0) +#error "mfbt (and Gecko) require at least gcc 4.9 to build." +#endif #elif defined(_MSC_VER) -# undef MOZ_IS_MSVC -# define MOZ_IS_MSVC 1 +#undef MOZ_IS_MSVC +#define MOZ_IS_MSVC 1 #endif @@ -46,68 +46,68 @@ * the version macros and deduce macros from there. */ #ifdef __cplusplus -# include -# ifdef _STLPORT_MAJOR -# define MOZ_USING_STLPORT 1 -# define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) \ - (_STLPORT_VERSION >= ((major) << 8 | (minor) << 4 | (patch))) -# elif defined(_LIBCPP_VERSION) - /* - * libc++, unfortunately, doesn't appear to have useful versioning macros. - * Hopefully, the recommendations of N3694 with respect to standard libraries - * will get applied instead and we won't need to worry about version numbers - * here. - */ -# define MOZ_USING_LIBCXX 1 -# elif defined(__GLIBCXX__) -# define MOZ_USING_LIBSTDCXX 1 - /* - * libstdc++ is also annoying and doesn't give us useful versioning macros - * for the library. If we're using gcc, then assume that libstdc++ matches - * the compiler version. If we're using clang, we're going to have to fake - * major/minor combinations by looking for newly-defined config macros. - */ -# if MOZ_IS_GCC -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - MOZ_GCC_VERSION_AT_LEAST(major, minor, patch) -# elif defined(_GLIBCXX_THROW_OR_ABORT) -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - ((major) < 4 || ((major) == 4 && (minor) <= 8)) -# elif defined(_GLIBCXX_NOEXCEPT) -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - ((major) < 4 || ((major) == 4 && (minor) <= 7)) -# elif defined(_GLIBCXX_USE_DEPRECATED) -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - ((major) < 4 || ((major) == 4 && (minor) <= 6)) -# elif defined(_GLIBCXX_PSEUDO_VISIBILITY) -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - ((major) < 4 || ((major) == 4 && (minor) <= 5)) -# elif defined(_GLIBCXX_BEGIN_EXTERN_C) -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - ((major) < 4 || ((major) == 4 && (minor) <= 4)) -# elif defined(_GLIBCXX_VISIBILITY_ATTR) -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - ((major) < 4 || ((major) == 4 && (minor) <= 3)) -# elif defined(_GLIBCXX_VISIBILITY) -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - ((major) < 4 || ((major) == 4 && (minor) <= 2)) -# else -# error "Your version of libstdc++ is unknown to us and is likely too old." -# endif -# endif - - // Flesh out the defines for everyone else -# ifndef MOZ_USING_STLPORT -# define MOZ_USING_STLPORT 0 -# define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) 0 -# endif -# ifndef MOZ_USING_LIBCXX -# define MOZ_USING_LIBCXX 0 -# endif -# ifndef MOZ_USING_LIBSTDCXX -# define MOZ_USING_LIBSTDCXX 0 -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) 0 -# endif +#include +#ifdef _STLPORT_MAJOR +#define MOZ_USING_STLPORT 1 +#define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) \ + (_STLPORT_VERSION >= ((major) << 8 | (minor) << 4 | (patch))) +#elif defined(_LIBCPP_VERSION) +/* + * libc++, unfortunately, doesn't appear to have useful versioning macros. + * Hopefully, the recommendations of N3694 with respect to standard libraries + * will get applied instead and we won't need to worry about version numbers + * here. + */ +#define MOZ_USING_LIBCXX 1 +#elif defined(__GLIBCXX__) +#define MOZ_USING_LIBSTDCXX 1 +/* + * libstdc++ is also annoying and doesn't give us useful versioning macros + * for the library. If we're using gcc, then assume that libstdc++ matches + * the compiler version. If we're using clang, we're going to have to fake + * major/minor combinations by looking for newly-defined config macros. + */ +#if MOZ_IS_GCC +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + MOZ_GCC_VERSION_AT_LEAST(major, minor, patch) +#elif defined(_GLIBCXX_THROW_OR_ABORT) +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 8)) +#elif defined(_GLIBCXX_NOEXCEPT) +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 7)) +#elif defined(_GLIBCXX_USE_DEPRECATED) +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 6)) +#elif defined(_GLIBCXX_PSEUDO_VISIBILITY) +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 5)) +#elif defined(_GLIBCXX_BEGIN_EXTERN_C) +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 4)) +#elif defined(_GLIBCXX_VISIBILITY_ATTR) +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 3)) +#elif defined(_GLIBCXX_VISIBILITY) +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 2)) +#else +#error "Your version of libstdc++ is unknown to us and is likely too old." +#endif +#endif + +// Flesh out the defines for everyone else +#ifndef MOZ_USING_STLPORT +#define MOZ_USING_STLPORT 0 +#define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) 0 +#endif +#ifndef MOZ_USING_LIBCXX +#define MOZ_USING_LIBCXX 0 +#endif +#ifndef MOZ_USING_LIBSTDCXX +#define MOZ_USING_LIBSTDCXX 0 +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) 0 +#endif #endif /* __cplusplus */ #endif /* mozilla_Compiler_h */ 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 @@ -25,9 +25,8 @@ * 4x the speed and produces output of about 1.5x the size. */ -class LZ4 -{ -public: +class LZ4 { + public: /** * Compresses |aInputSize| bytes from |aSource| into |aDest|. Destination * buffer must be already allocated, and must be sized to handle worst cases @@ -37,8 +36,8 @@ * @param aInputSize is the input size. Max supported value is ~1.9GB * @return the number of bytes written in buffer |aDest| */ - static MFBT_API size_t - compress(const char* aSource, size_t aInputSize, char* aDest); + static MFBT_API size_t compress(const char* aSource, size_t aInputSize, + char* aDest); /** * Compress |aInputSize| bytes from |aSource| into an output buffer @@ -55,9 +54,9 @@ * @return the number of bytes written in buffer |aDest| or 0 if the * compression fails */ - static MFBT_API size_t - compressLimitedOutput(const char* aSource, size_t aInputSize, char* aDest, - size_t aMaxOutputSize); + static MFBT_API size_t compressLimitedOutput(const char* aSource, + size_t aInputSize, char* aDest, + size_t aMaxOutputSize); /** * If the source stream is malformed, the function will stop decoding @@ -72,8 +71,8 @@ * @param aOutputSize is the output size, therefore the original size * @return true on success, false on failure */ - static MFBT_API MOZ_MUST_USE bool - decompress(const char* aSource, char* aDest, size_t aOutputSize); + static MFBT_API MOZ_MUST_USE bool decompress(const char* aSource, char* aDest, + size_t aOutputSize); /** * If the source stream is malformed, the function will stop decoding @@ -92,9 +91,35 @@ * buffer (necessarily <= aMaxOutputSize) * @return true on success, false on failure */ - static MFBT_API MOZ_MUST_USE bool - decompress(const char* aSource, size_t aInputSize, char* aDest, - size_t aMaxOutputSize, size_t* aOutputSize); + static MFBT_API MOZ_MUST_USE bool decompress(const char* aSource, + size_t aInputSize, char* aDest, + size_t aMaxOutputSize, + size_t* aOutputSize); + + /** + * If the source stream is malformed, the function will stop decoding + * and return false. + * + * This function never writes beyond aDest + aMaxOutputSize, and is + * therefore protected against malicious data packets. It also ignores + * unconsumed input upon reaching aMaxOutputSize and can therefore be used + * for partial decompression. + * + * Note: Destination buffer must be already allocated. This version is + * slightly slower than the decompress without the aMaxOutputSize. + * + * @param aInputSize is the length of the input compressed data + * @param aMaxOutputSize is the size of the destination buffer (which must be + * 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 MOZ_MUST_USE bool decompressPartial(const char* aSource, + size_t aInputSize, + char* aDest, + size_t aMaxOutputSize, + size_t* aOutputSize); /* * Provides the maximum size that LZ4 may output in a "worst case" @@ -105,8 +130,7 @@ * @param aInputSize is the input size. Max supported value is ~1.9GB * @return maximum output size in a "worst case" scenario */ - static inline size_t maxCompressedSize(size_t aInputSize) - { + static inline size_t maxCompressedSize(size_t aInputSize) { size_t max = (aInputSize + (aInputSize / 255) + 16); MOZ_ASSERT(max > aInputSize); return max; 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 @@ -35,16 +35,15 @@ * DebugOnly for struct/class members and unwittingly inflating the size of * their objects in release builds. */ -template -class MOZ_STACK_CLASS DebugOnly -{ -public: +template +class MOZ_STACK_CLASS DebugOnly { + public: #ifdef DEBUG T value; - DebugOnly() { } - MOZ_IMPLICIT DebugOnly(const T& aOther) : value(aOther) { } - DebugOnly(const DebugOnly& aOther) : value(aOther.value) { } + DebugOnly() {} + MOZ_IMPLICIT DebugOnly(const T& aOther) : value(aOther) {} + DebugOnly(const DebugOnly& aOther) : value(aOther.value) {} DebugOnly& operator=(const T& aRhs) { value = aRhs; return *this; @@ -66,12 +65,12 @@ const T& operator->() const { return value; } #else - DebugOnly() { } - MOZ_IMPLICIT DebugOnly(const T&) { } - DebugOnly(const DebugOnly&) { } + DebugOnly() {} + MOZ_IMPLICIT DebugOnly(const T&) {} + DebugOnly(const DebugOnly&) {} DebugOnly& operator=(const T&) { return *this; } - void operator++(int) { } - void operator--(int) { } + void operator++(int) {} + void operator--(int) {} DebugOnly& operator+=(const T&) { return *this; } DebugOnly& operator-=(const T&) { return *this; } DebugOnly& operator&=(const T&) { return *this; } @@ -87,6 +86,6 @@ ~DebugOnly() {} }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_DebugOnly_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/DefineEnum.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/DefineEnum.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/DefineEnum.h @@ -0,0 +1,155 @@ +/* -*- 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/. */ + +/* Poor man's reflection for enumerations. */ + +#ifndef mozilla_DefineEnum_h +#define mozilla_DefineEnum_h + +#include // for size_t + +#include "mozilla/MacroArgs.h" // for MOZ_ARG_COUNT +#include "mozilla/MacroForEach.h" // for MOZ_FOR_EACH + +/** + * MOZ_UNWRAP_ARGS is a helper macro that unwraps a list of comma-separated + * items enclosed in parentheses, to yield just the items. + * + * Usage: |MOZ_UNWRAP_ARGS foo| (note the absence of parentheses in the + * invocation), where |foo| is a parenthesis-enclosed list. + * For exampe if |foo| is |(3, 4, 5)|, then the expansion is just |3, 4, 5|. + */ +#define MOZ_UNWRAP_ARGS(...) __VA_ARGS__ + +/** + * MOZ_DEFINE_ENUM(aEnumName, aEnumerators) is a macro that allows + * simultaneously defining an enumeration named |aEnumName|, and a constant + * that stores the number of enumerators it has. + * + * The motivation is to allow the enumeration to evolve over time without + * either having to manually keep such a constant up to date, or having to + * add a special "sentinel" enumerator for this purpose. (While adding a + * "sentinel" enumerator is trivial, it causes headaches with "switch" + * statements. We often try to write "switch" statements whose cases exhaust + * the enumerators and don't have a "default" case, so that if a new + * enumerator is added and we forget to handle it in the "switch", the + * compiler points it out. But this means we need to explicitly handle the + * sentinel in every "switch".) + * + * |aEnumerators| is expected to be a comma-separated list of enumerators, + * enclosed in parentheses. The enumerators may NOT have associated + * initializers (an attempt to have one will result in a compiler error). + * This ensures that the enumerator values are in the range [0, N), where N + * is the number of enumerators. + * + * The list of enumerators cannot contain a trailing comma. This is a + * limitation of MOZ_FOR_EACH, which we use in the implementation; if + * MOZ_FOR_EACH supported trailing commas, we could too. + * + * The generated constant has the name "k" + |aEnumName| + "Count", and type + * "size_t". The enumeration and the constant are both defined in the scope + * in which the macro is invoked. + * + * For convenience, a constant of the enumeration type named + * "kHighest" + |aEnumName| is also defined, whose value is the highest + * valid enumerator, assuming the enumerators have contiguous values starting + * from 0. + * + * Invocation of the macro may be followed by a semicolon, if one prefers a + * more declaration-like syntax. + * + * Example invocation: + * MOZ_DEFINE_ENUM(MyEnum, (Foo, Bar, Baz)); + * + * This expands to: + * enum MyEnum { Foo, Bar, Baz }; + * constexpr size_t kMyEnumCount = 3; + * constexpr MyEnum kHighestMyEnum = MyEnum(kMyEnumCount - 1); + * // some static_asserts to ensure the values are in the range [0, 3) + * + * The macro also has several variants: + * + * - A |_CLASS| variant, which generates an |enum class| instead of + * a plain enum. + * + * - A |_WITH_BASE| variant which generates an enum with a specified + * underlying ("base") type, which is provided as an additional + * argument in second position. + * + * - An |_AT_CLASS_SCOPE| variant, designed for enumerations defined + * at class scope. For these, the generated constants are static, + * and have names prefixed with "s" instead of "k" as per + * naming convention. + * + * (and combinations of these). + */ + +/* + * A helper macro for asserting that an enumerator does not have an initializer. + * + * The static_assert and the comparison to 0 are just scaffolding; the + * important part is forming the expression |aEnumName::aEnumeratorDecl|. + * + * If |aEnumeratorDecl| is just the enumerator name without an identifier, + * this expression compiles fine. However, if |aEnumeratorDecl| includes an + * initializer, as in |eEnumerator = initializer|, then this will fail to + * compile in expression context, since |eEnumerator| is not an lvalue. + * + * (The static_assert itself should always pass in the absence of the above + * error, since you can't get a negative enumerator value without having + * an initializer somewhere. It just provides a place to put the expression + * we want to form.) + */ +#define MOZ_ASSERT_ENUMERATOR_HAS_NO_INITIALIZER(aEnumName, aEnumeratorDecl) \ + static_assert( \ + (aEnumName::aEnumeratorDecl) >= aEnumName(0), \ + "MOZ_DEFINE_ENUM does not allow enumerators to have initializers"); + +#define MOZ_DEFINE_ENUM_IMPL(aEnumName, aClassSpec, aBaseSpec, aEnumerators) \ + enum aClassSpec aEnumName aBaseSpec{MOZ_UNWRAP_ARGS aEnumerators}; \ + constexpr size_t k##aEnumName##Count = MOZ_ARG_COUNT aEnumerators; \ + constexpr aEnumName k##Highest##aEnumName = \ + aEnumName(k##aEnumName##Count - 1); \ + MOZ_FOR_EACH(MOZ_ASSERT_ENUMERATOR_HAS_NO_INITIALIZER, (aEnumName, ), \ + aEnumerators) + +#define MOZ_DEFINE_ENUM(aEnumName, aEnumerators) \ + MOZ_DEFINE_ENUM_IMPL(aEnumName, , , aEnumerators) + +#define MOZ_DEFINE_ENUM_WITH_BASE(aEnumName, aBaseName, aEnumerators) \ + MOZ_DEFINE_ENUM_IMPL(aEnumName, , : aBaseName, aEnumerators) + +#define MOZ_DEFINE_ENUM_CLASS(aEnumName, aEnumerators) \ + MOZ_DEFINE_ENUM_IMPL(aEnumName, class, , aEnumerators) + +#define MOZ_DEFINE_ENUM_CLASS_WITH_BASE(aEnumName, aBaseName, aEnumerators) \ + MOZ_DEFINE_ENUM_IMPL(aEnumName, class, : aBaseName, aEnumerators) + +#define MOZ_DEFINE_ENUM_AT_CLASS_SCOPE_IMPL(aEnumName, aClassSpec, aBaseSpec, \ + aEnumerators) \ + enum aClassSpec aEnumName aBaseSpec{MOZ_UNWRAP_ARGS aEnumerators}; \ + constexpr static size_t s##aEnumName##Count = MOZ_ARG_COUNT aEnumerators; \ + constexpr static aEnumName s##Highest##aEnumName = \ + aEnumName(s##aEnumName##Count - 1); \ + MOZ_FOR_EACH(MOZ_ASSERT_ENUMERATOR_HAS_NO_INITIALIZER, (aEnumName, ), \ + aEnumerators) + +#define MOZ_DEFINE_ENUM_AT_CLASS_SCOPE(aEnumName, aEnumerators) \ + MOZ_DEFINE_ENUM_AT_CLASS_SCOPE_IMPL(aEnumName, , , aEnumerators) + +#define MOZ_DEFINE_ENUM_WITH_BASE_AT_CLASS_SCOPE(aEnumName, aBaseName, \ + aEnumerators) \ + MOZ_DEFINE_ENUM_AT_CLASS_SCOPE_IMPL(aEnumName, , : aBaseName, aEnumerators) + +#define MOZ_DEFINE_ENUM_CLASS_AT_CLASS_SCOPE(aEnumName, aEnumerators) \ + MOZ_DEFINE_ENUM_AT_CLASS_SCOPE_IMPL(aEnumName, class, , aEnumerators) + +#define MOZ_DEFINE_ENUM_CLASS_WITH_BASE_AT_CLASS_SCOPE(aEnumName, aBaseName, \ + aEnumerators) \ + MOZ_DEFINE_ENUM_AT_CLASS_SCOPE_IMPL(aEnumName, class, \ + : aBaseName, aEnumerators) + +#endif // mozilla_DefineEnum_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/DoublyLinkedList.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/DoublyLinkedList.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/DoublyLinkedList.h @@ -0,0 +1,373 @@ +/* -*- 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 doubly-linked list with flexible next/prev naming. */ + +#ifndef mozilla_DoublyLinkedList_h +#define mozilla_DoublyLinkedList_h + +#include +#include + +#include "mozilla/Assertions.h" + +/** + * Where mozilla::LinkedList strives for ease of use above all other + * considerations, mozilla::DoublyLinkedList strives for flexibility. The + * following are things that can be done with mozilla::DoublyLinkedList that + * cannot be done with mozilla::LinkedList: + * + * * Arbitrary next/prev placement and naming. With the tools provided here, + * the next and previous pointers can be at the end of the structure, in a + * sub-structure, stored with a tag, in a union, wherever, as long as you + * can look them up and set them on demand. + * * Can be used without deriving from a new base and, thus, does not require + * use of constructors. + * + * Example: + * + * class Observer : public DoublyLinkedListElement + * { + * public: + * void observe(char* aTopic) { ... } + * }; + * + * class ObserverContainer + * { + * private: + * DoublyLinkedList mList; + * + * public: + * void addObserver(Observer* aObserver) + * { + * // Will assert if |aObserver| is part of another list. + * mList.pushBack(aObserver); + * } + * + * void removeObserver(Observer* aObserver) + * { + * // Will assert if |aObserver| is not part of |list|. + * mList.remove(aObserver); + * } + * + * void notifyObservers(char* aTopic) + * { + * for (Observer* o : mList) { + * o->observe(aTopic); + * } + * } + * }; + */ + +namespace mozilla { + +/** + * Deriving from this will allow T to be inserted into and removed from a + * DoublyLinkedList. + */ +template +class DoublyLinkedListElement { + template + friend class DoublyLinkedList; + friend T; + T* mNext; + T* mPrev; + + public: + DoublyLinkedListElement() : mNext(nullptr), mPrev(nullptr) {} +}; + +/** + * Provides access to a DoublyLinkedListElement within T. + * + * The default implementation of this template works for types that derive + * from DoublyLinkedListElement, but one can specialize for their class so + * that some appropriate DoublyLinkedListElement reference is returned. + * + * For more complex cases (multiple DoublyLinkedListElements, for example), + * one can define their own trait class and use that as ElementAccess for + * DoublyLinkedList. See TestDoublyLinkedList.cpp for an example. + */ +template +struct GetDoublyLinkedListElement { + static_assert(mozilla::IsBaseOf, T>::value, + "You need your own specialization of GetDoublyLinkedListElement" + " or use a separate Trait."); + static DoublyLinkedListElement& Get(T* aThis) { return *aThis; } +}; + +/** + * A doubly linked list. |T| is the type of element stored in this list. |T| + * must contain or have access to unique next and previous element pointers. + * The template argument |ElementAccess| provides code to tell this list how to + * get a reference to a DoublyLinkedListElement that may reside anywhere. + */ +template > +class DoublyLinkedList final { + T* mHead; + T* mTail; + + /** + * Checks that either the list is empty and both mHead and mTail are nullptr + * or the list has entries and both mHead and mTail are non-null. + */ + bool isStateValid() const { return (mHead != nullptr) == (mTail != nullptr); } + + bool ElementNotInList(T* aElm) { + if (!ElementAccess::Get(aElm).mNext && !ElementAccess::Get(aElm).mPrev) { + // Both mNext and mPrev being NULL can mean two things: + // - the element is not in the list. + // - the element is the first and only element in the list. + // So check for the latter. + return mHead != aElm; + } + return false; + } + + public: + DoublyLinkedList() : mHead(nullptr), mTail(nullptr) {} + + class Iterator final { + T* mCurrent; + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = T*; + using reference = T&; + + Iterator() : mCurrent(nullptr) {} + explicit Iterator(T* aCurrent) : mCurrent(aCurrent) {} + + T& operator*() const { return *mCurrent; } + T* operator->() const { return mCurrent; } + + Iterator& operator++() { + mCurrent = ElementAccess::Get(mCurrent).mNext; + return *this; + } + + Iterator operator++(int) { + Iterator result = *this; + ++(*this); + return result; + } + + Iterator& operator--() { + mCurrent = ElementAccess::Get(mCurrent).mPrev; + return *this; + } + + Iterator operator--(int) { + Iterator result = *this; + --(*this); + return result; + } + + bool operator!=(const Iterator& aOther) const { + return mCurrent != aOther.mCurrent; + } + + bool operator==(const Iterator& aOther) const { + return mCurrent == aOther.mCurrent; + } + + explicit operator bool() const { return mCurrent; } + }; + + Iterator begin() { return Iterator(mHead); } + const Iterator begin() const { return Iterator(mHead); } + const Iterator cbegin() const { return Iterator(mHead); } + + Iterator end() { return Iterator(); } + const Iterator end() const { return Iterator(); } + const Iterator cend() const { return Iterator(); } + + /** + * Returns true if the list contains no elements. + */ + bool isEmpty() const { + MOZ_ASSERT(isStateValid()); + return mHead == nullptr; + } + + /** + * Inserts aElm into the list at the head position. |aElm| must not already + * be in a list. + */ + void pushFront(T* aElm) { + MOZ_ASSERT(aElm); + MOZ_ASSERT(ElementNotInList(aElm)); + MOZ_ASSERT(isStateValid()); + + ElementAccess::Get(aElm).mNext = mHead; + if (mHead) { + MOZ_ASSERT(!ElementAccess::Get(mHead).mPrev); + ElementAccess::Get(mHead).mPrev = aElm; + } + + mHead = aElm; + if (!mTail) { + mTail = aElm; + } + } + + /** + * Remove the head of the list and return it. Calling this on an empty list + * will assert. + */ + T* popFront() { + MOZ_ASSERT(!isEmpty()); + MOZ_ASSERT(isStateValid()); + + T* result = mHead; + mHead = result ? ElementAccess::Get(result).mNext : nullptr; + if (mHead) { + ElementAccess::Get(mHead).mPrev = nullptr; + } + + if (mTail == result) { + mTail = nullptr; + } + + if (result) { + ElementAccess::Get(result).mNext = nullptr; + ElementAccess::Get(result).mPrev = nullptr; + } + + return result; + } + + /** + * Inserts aElm into the list at the tail position. |aElm| must not already + * be in a list. + */ + void pushBack(T* aElm) { + MOZ_ASSERT(aElm); + MOZ_ASSERT(ElementNotInList(aElm)); + MOZ_ASSERT(isStateValid()); + + ElementAccess::Get(aElm).mNext = nullptr; + ElementAccess::Get(aElm).mPrev = mTail; + if (mTail) { + MOZ_ASSERT(!ElementAccess::Get(mTail).mNext); + ElementAccess::Get(mTail).mNext = aElm; + } + + mTail = aElm; + if (!mHead) { + mHead = aElm; + } + } + + /** + * Remove the tail of the list and return it. Calling this on an empty list + * will assert. + */ + T* popBack() { + MOZ_ASSERT(!isEmpty()); + MOZ_ASSERT(isStateValid()); + + T* result = mTail; + mTail = result ? ElementAccess::Get(result).mPrev : nullptr; + if (mTail) { + ElementAccess::Get(mTail).mNext = nullptr; + } + + if (mHead == result) { + mHead = nullptr; + } + + if (result) { + ElementAccess::Get(result).mNext = nullptr; + ElementAccess::Get(result).mPrev = nullptr; + } + + return result; + } + + /** + * Insert the given |aElm| *before* |aIter|. + */ + void insertBefore(const Iterator& aIter, T* aElm) { + MOZ_ASSERT(aElm); + MOZ_ASSERT(ElementNotInList(aElm)); + MOZ_ASSERT(isStateValid()); + + if (!aIter) { + return pushBack(aElm); + } else if (aIter == begin()) { + return pushFront(aElm); + } + + T* after = &(*aIter); + T* before = ElementAccess::Get(after).mPrev; + MOZ_ASSERT(before); + + ElementAccess::Get(before).mNext = aElm; + ElementAccess::Get(aElm).mPrev = before; + ElementAccess::Get(aElm).mNext = after; + ElementAccess::Get(after).mPrev = aElm; + } + + /** + * Removes the given element from the list. The element must be in this list. + */ + void remove(T* aElm) { + MOZ_ASSERT(aElm); + MOZ_ASSERT(ElementAccess::Get(aElm).mNext || + ElementAccess::Get(aElm).mPrev || + (aElm == mHead && aElm == mTail), + "Attempted to remove element not in this list"); + + if (T* prev = ElementAccess::Get(aElm).mPrev) { + ElementAccess::Get(prev).mNext = ElementAccess::Get(aElm).mNext; + } else { + MOZ_ASSERT(mHead == aElm); + mHead = ElementAccess::Get(aElm).mNext; + } + + if (T* next = ElementAccess::Get(aElm).mNext) { + ElementAccess::Get(next).mPrev = ElementAccess::Get(aElm).mPrev; + } else { + MOZ_ASSERT(mTail == aElm); + mTail = ElementAccess::Get(aElm).mPrev; + } + + ElementAccess::Get(aElm).mNext = nullptr; + ElementAccess::Get(aElm).mPrev = nullptr; + } + + /** + * Returns an iterator referencing the first found element whose value matches + * the given element according to operator==. + */ + Iterator find(const T& aElm) { return std::find(begin(), end(), aElm); } + + /** + * Returns whether the given element is in the list. Note that this uses + * T::operator==, not pointer comparison. + */ + bool contains(const T& aElm) { return find(aElm) != Iterator(); } + + /** + * Returns whether the given element might be in the list. Note that this + * assumes the element is either in the list or not in the list, and ignores + * the case where the element might be in another list in order to make the + * check fast. + */ + bool ElementProbablyInList(T* aElm) { + if (isEmpty()) { + return false; + } + return !ElementNotInList(aElm); + } +}; + +} // namespace mozilla + +#endif // mozilla_DoublyLinkedList_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 @@ -9,7 +9,9 @@ /* * 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: + * in their respective endianness. The addresses read from or written + * to may be misaligned (although misaligned accesses may incur + * architecture-specific performance costs). The naming scheme is: * * {Little,Big}Endian::{read,write}{Uint,Int} * @@ -74,85 +76,81 @@ #include #if defined(_MSC_VER) -# include -# pragma intrinsic(_byteswap_ushort) -# pragma intrinsic(_byteswap_ulong) -# pragma intrinsic(_byteswap_uint64) +#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 +#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 +#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 +#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 +#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 +#define MOZ_LITTLE_ENDIAN 0 #elif MOZ_LITTLE_ENDIAN -# define MOZ_BIG_ENDIAN 0 +#define MOZ_BIG_ENDIAN 0 #else -# error "Cannot determine endianness" +#error "Cannot determine endianness" #endif #if defined(__clang__) -# if __has_builtin(__builtin_bswap16) -# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 -# endif +#if __has_builtin(__builtin_bswap16) +#define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 +#endif #elif defined(__GNUC__) -# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 +#define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 #elif defined(_MSC_VER) -# define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort +#define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort #endif namespace mozilla { @@ -164,14 +162,12 @@ * arguments and/or partial specialization of function templates are not * supported by all the compilers we use. */ -template +template struct Swapper; -template -struct Swapper -{ - static T swap(T aValue) - { +template +struct Swapper { + static T swap(T aValue) { #if defined(MOZ_HAVE_BUILTIN_BYTESWAP16) return MOZ_HAVE_BUILTIN_BYTESWAP16(aValue); #else @@ -180,29 +176,23 @@ } }; -template -struct Swapper -{ - static T swap(T aValue) - { +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)); + return T(((aValue & 0x000000ffU) << 24) | ((aValue & 0x0000ff00U) << 8) | + ((aValue & 0x00ff0000U) >> 8) | ((aValue & 0xff000000U) >> 24)); #endif } }; -template -struct Swapper -{ - static inline T swap(T aValue) - { +template +struct Swapper { + static inline T swap(T aValue) { #if defined(__clang__) || defined(__GNUC__) return T(__builtin_bswap64(aValue)); #elif defined(_MSC_VER) @@ -223,42 +213,37 @@ enum Endianness { Little, Big }; #if MOZ_BIG_ENDIAN -# define MOZ_NATIVE_ENDIANNESS detail::Big +#define MOZ_NATIVE_ENDIANNESS detail::Big #else -# define MOZ_NATIVE_ENDIANNESS detail::Little +#define MOZ_NATIVE_ENDIANNESS detail::Little #endif -class EndianUtils -{ +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) - { + 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)); + MOZ_ASSERT( + (byteDestPtr <= byteSrcPtr && byteDestPtr + aCount <= byteSrcPtr) || + (byteSrcPtr <= byteDestPtr && byteSrcPtr + aCount <= byteDestPtr)); } - template - static void assertAligned(T* aPtr) - { + template + static void assertAligned(T* aPtr) { MOZ_ASSERT((uintptr_t(aPtr) % sizeof(T)) == 0, "Unaligned pointer!"); } -protected: + protected: /** * Return |aValue| converted from SourceEndian encoding to DestEndian * encoding. */ - template - static inline T maybeSwap(T aValue) - { + template + static inline T maybeSwap(T aValue) { if (SourceEndian == DestEndian) { return aValue; } @@ -269,9 +254,8 @@ * Convert |aCount| elements at |aPtr| from SourceEndian encoding to * DestEndian encoding. */ - template - static inline void maybeSwapInPlace(T* aPtr, size_t aCount) - { + template + static inline void maybeSwapInPlace(T* aPtr, size_t aCount) { assertAligned(aPtr); if (SourceEndian == DestEndian) { @@ -286,9 +270,8 @@ * 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) - { + template + static void copyAndSwapTo(void* aDest, const T* aSrc, size_t aCount) { assertNoOverlap(aDest, aSrc, aCount * sizeof(T)); assertAligned(aSrc); @@ -299,8 +282,7 @@ uint8_t* byteDestPtr = static_cast(aDest); for (size_t i = 0; i < aCount; ++i) { - union - { + union { T mVal; uint8_t mBuffer[sizeof(T)]; } u; @@ -314,9 +296,8 @@ * 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) - { + template + static void copyAndSwapFrom(T* aDest, const void* aSrc, size_t aCount) { assertNoOverlap(aDest, aSrc, aCount * sizeof(T)); assertAligned(aDest); @@ -327,8 +308,7 @@ const uint8_t* byteSrcPtr = static_cast(aSrc); for (size_t i = 0; i < aCount; ++i) { - union - { + union { T mVal; uint8_t mBuffer[sizeof(T)]; } u; @@ -339,81 +319,74 @@ } }; -template -class Endian : private EndianUtils -{ -protected: +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) - { + 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) - { + 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) - { + static MOZ_MUST_USE uint64_t readUint64(const void* aPtr) { return read(aPtr); } + /** Read a uintptr_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE uintptr_t readUintptr(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) - { + 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) - { + 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) - { + 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); + /** Read an intptr_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE intptr_t readIntptr(const void* aPtr) { + return read(aPtr); } /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeUint32(void* aPtr, uint32_t aValue) - { - write(aPtr, aValue); - } + static void writeUint16(void* aPtr, uint16_t aValue) { write(aPtr, aValue); } /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeUint64(void* aPtr, uint64_t aValue) - { - write(aPtr, aValue); - } + static void writeUint32(void* aPtr, uint32_t aValue) { write(aPtr, aValue); } /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeInt16(void* aPtr, int16_t aValue) - { - write(aPtr, aValue); - } + static void writeUint64(void* aPtr, uint64_t aValue) { write(aPtr, aValue); } /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeInt32(void* aPtr, int32_t aValue) - { + static void writeUintptr(void* aPtr, uintptr_t aValue) { write(aPtr, aValue); } /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeInt64(void* aPtr, int64_t aValue) - { - write(aPtr, aValue); - } + 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); } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeIntptr(void* aPtr, intptr_t aValue) { write(aPtr, aValue); } /* * Converts a value of type T to little-endian format. @@ -422,9 +395,8 @@ * native-endian format and you need it to appear in little-endian * format for transmission. */ - template - MOZ_MUST_USE static T swapToLittleEndian(T aValue) - { + template + MOZ_MUST_USE static T swapToLittleEndian(T aValue) { return maybeSwap(aValue); } @@ -433,28 +405,25 @@ * them to little-endian format if ThisEndian is Big. * As with memcpy, |aDest| and |aSrc| must not overlap. */ - template + template static void copyAndSwapToLittleEndian(void* aDest, const T* aSrc, - size_t aCount) - { + size_t aCount) { copyAndSwapTo(aDest, aSrc, aCount); } /* * Likewise, but converts values in place. */ - template - static void swapToLittleEndianInPlace(T* aPtr, size_t aCount) - { + 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) - { + template + MOZ_MUST_USE static T swapToBigEndian(T aValue) { return maybeSwap(aValue); } @@ -463,19 +432,17 @@ * them to big-endian format if ThisEndian is Little. * As with memcpy, |aDest| and |aSrc| must not overlap. */ - template + template static void copyAndSwapToBigEndian(void* aDest, const T* aSrc, - size_t aCount) - { + size_t aCount) { copyAndSwapTo(aDest, aSrc, aCount); } /* * Likewise, but converts values in place. */ - template - static void swapToBigEndianInPlace(T* aPtr, size_t aCount) - { + template + static void swapToBigEndianInPlace(T* aPtr, size_t aCount) { maybeSwapInPlace(aPtr, aCount); } @@ -484,32 +451,27 @@ * in network code. */ - template - MOZ_MUST_USE static T swapToNetworkOrder(T aValue) - { + template + MOZ_MUST_USE static T swapToNetworkOrder(T aValue) { return swapToBigEndian(aValue); } - template - static void - copyAndSwapToNetworkOrder(void* aDest, const T* aSrc, size_t aCount) - { + 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) - { + 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) - { + template + MOZ_MUST_USE static T swapFromLittleEndian(T aValue) { return maybeSwap(aValue); } @@ -518,28 +480,25 @@ * them to little-endian format if ThisEndian is Big. * As with memcpy, |aDest| and |aSrc| must not overlap. */ - template + template static void copyAndSwapFromLittleEndian(T* aDest, const void* aSrc, - size_t aCount) - { + size_t aCount) { copyAndSwapFrom(aDest, aSrc, aCount); } /* * Likewise, but converts values in place. */ - template - static void swapFromLittleEndianInPlace(T* aPtr, size_t aCount) - { + 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) - { + template + MOZ_MUST_USE static T swapFromBigEndian(T aValue) { return maybeSwap(aValue); } @@ -548,19 +507,17 @@ * them to big-endian format if ThisEndian is Little. * As with memcpy, |aDest| and |aSrc| must not overlap. */ - template + template static void copyAndSwapFromBigEndian(T* aDest, const void* aSrc, - size_t aCount) - { + size_t aCount) { copyAndSwapFrom(aDest, aSrc, aCount); } /* * Likewise, but converts values in place. */ - template - static void swapFromBigEndianInPlace(T* aPtr, size_t aCount) - { + template + static void swapFromBigEndianInPlace(T* aPtr, size_t aCount) { maybeSwapInPlace(aPtr, aCount); } @@ -568,35 +525,30 @@ * Synonyms for the big-endian functions, for better readability * in network code. */ - template - MOZ_MUST_USE static T swapFromNetworkOrder(T aValue) - { + template + MOZ_MUST_USE static T swapFromNetworkOrder(T aValue) { return swapFromBigEndian(aValue); } - template + template static void copyAndSwapFromNetworkOrder(T* aDest, const void* aSrc, - size_t aCount) - { + size_t aCount) { copyAndSwapFromBigEndian(aDest, aSrc, aCount); } - template - static void swapFromNetworkOrderInPlace(T* aPtr, size_t aCount) - { + template + static void swapFromNetworkOrderInPlace(T* aPtr, size_t aCount) { swapFromBigEndianInPlace(aPtr, aCount); } -private: + 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 - { + template + static T read(const void* aPtr) { + union { T mVal; uint8_t mBuffer[sizeof(T)]; } u; @@ -608,9 +560,8 @@ * Write a value of type T, in native endianness, to |aPtr|, in ThisEndian * endianness. */ - template - static void write(void* aPtr, T aValue) - { + template + static void write(void* aPtr, T aValue) { T tmp = maybeSwap(aValue); memcpy(aPtr, &tmp, sizeof(T)); } @@ -620,56 +571,56 @@ void operator=(const Endian& aOther) = delete; }; -template -class EndianReadWrite : public Endian -{ -private: +template +class EndianReadWrite : public Endian { + private: typedef Endian super; -public: - using super::readUint16; - using super::readUint32; - using super::readUint64; + public: using super::readInt16; using super::readInt32; using super::readInt64; - using super::writeUint16; - using super::writeUint32; - using super::writeUint64; + using super::readIntptr; + using super::readUint16; + using super::readUint32; + using super::readUint64; + using super::readUintptr; using super::writeInt16; using super::writeInt32; using super::writeInt64; + using super::writeIntptr; + using super::writeUint16; + using super::writeUint32; + using super::writeUint64; + using super::writeUintptr; }; } /* namespace detail */ -class LittleEndian final : public detail::EndianReadWrite -{}; +class LittleEndian final : public detail::EndianReadWrite {}; -class BigEndian final : public detail::EndianReadWrite -{}; +class BigEndian final : public detail::EndianReadWrite {}; typedef BigEndian NetworkEndian; -class NativeEndian final : public detail::Endian -{ -private: +class NativeEndian final : public detail::Endian { + private: typedef detail::Endian super; -public: + 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::copyAndSwapToBigEndian; using super::copyAndSwapToLittleEndian; - using super::swapToLittleEndianInPlace; + using super::copyAndSwapToNetworkOrder; using super::swapToBigEndian; - using super::copyAndSwapToBigEndian; using super::swapToBigEndianInPlace; + using super::swapToLittleEndian; + using super::swapToLittleEndianInPlace; using super::swapToNetworkOrder; - using super::copyAndSwapToNetworkOrder; using super::swapToNetworkOrderInPlace; /* @@ -677,14 +628,14 @@ * 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::copyAndSwapFromBigEndian; using super::copyAndSwapFromLittleEndian; - using super::swapFromLittleEndianInPlace; + using super::copyAndSwapFromNetworkOrder; using super::swapFromBigEndian; - using super::copyAndSwapFromBigEndian; using super::swapFromBigEndianInPlace; + using super::swapFromLittleEndian; + using super::swapFromLittleEndianInPlace; using super::swapFromNetworkOrder; - using super::copyAndSwapFromNetworkOrder; using super::swapFromNetworkOrderInPlace; }; 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 @@ -23,64 +23,36 @@ * using a 32 bit mask for each value so it will only work for enums with an int * representation less than 32. It works both for enum and enum class types. */ -template -class EnumSet -{ -public: - EnumSet() - : mBitField(0) - { - initVersion(); - } - - MOZ_IMPLICIT EnumSet(T aEnum) - : mBitField(bitFor(aEnum)) - { } - - EnumSet(T aEnum1, T aEnum2) - : mBitField(bitFor(aEnum1) | - bitFor(aEnum2)) - { - initVersion(); - } +template +class EnumSet { + public: + typedef uint32_t serializedType; + + EnumSet() : mBitField(0) {} + + MOZ_IMPLICIT EnumSet(T aEnum) : mBitField(bitFor(aEnum)) {} + + EnumSet(T aEnum1, T aEnum2) : mBitField(bitFor(aEnum1) | bitFor(aEnum2)) {} EnumSet(T aEnum1, T aEnum2, T aEnum3) - : mBitField(bitFor(aEnum1) | - bitFor(aEnum2) | - bitFor(aEnum3)) - { - initVersion(); - } + : mBitField(bitFor(aEnum1) | bitFor(aEnum2) | bitFor(aEnum3)) {} EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4) - : mBitField(bitFor(aEnum1) | - bitFor(aEnum2) | - bitFor(aEnum3) | - bitFor(aEnum4)) - { - initVersion(); - } + : mBitField(bitFor(aEnum1) | bitFor(aEnum2) | bitFor(aEnum3) | + bitFor(aEnum4)) {} - MOZ_IMPLICIT EnumSet(std::initializer_list list) - : mBitField(0) - { + MOZ_IMPLICIT EnumSet(std::initializer_list list) : mBitField(0) { for (auto value : list) { (*this) += value; } - initVersion(); } - EnumSet(const EnumSet& aEnumSet) - : mBitField(aEnumSet.mBitField) - { - initVersion(); - } + EnumSet(const EnumSet& aEnumSet) : mBitField(aEnumSet.mBitField) {} /** * Add an element */ - void operator+=(T aEnum) - { + void operator+=(T aEnum) { incVersion(); mBitField |= bitFor(aEnum); } @@ -88,8 +60,7 @@ /** * Add an element */ - EnumSet operator+(T aEnum) const - { + EnumSet operator+(T aEnum) const { EnumSet result(*this); result += aEnum; return result; @@ -98,8 +69,7 @@ /** * Union */ - void operator+=(const EnumSet aEnumSet) - { + void operator+=(const EnumSet aEnumSet) { incVersion(); mBitField |= aEnumSet.mBitField; } @@ -107,8 +77,7 @@ /** * Union */ - EnumSet operator+(const EnumSet aEnumSet) const - { + EnumSet operator+(const EnumSet aEnumSet) const { EnumSet result(*this); result += aEnumSet; return result; @@ -117,8 +86,7 @@ /** * Remove an element */ - void operator-=(T aEnum) - { + void operator-=(T aEnum) { incVersion(); mBitField &= ~(bitFor(aEnum)); } @@ -126,8 +94,7 @@ /** * Remove an element */ - EnumSet operator-(T aEnum) const - { + EnumSet operator-(T aEnum) const { EnumSet result(*this); result -= aEnum; return result; @@ -136,8 +103,7 @@ /** * Remove a set of elements */ - void operator-=(const EnumSet aEnumSet) - { + void operator-=(const EnumSet aEnumSet) { incVersion(); mBitField &= ~(aEnumSet.mBitField); } @@ -145,8 +111,7 @@ /** * Remove a set of elements */ - EnumSet operator-(const EnumSet aEnumSet) const - { + EnumSet operator-(const EnumSet aEnumSet) const { EnumSet result(*this); result -= aEnumSet; return result; @@ -155,8 +120,7 @@ /** * Clear */ - void clear() - { + void clear() { incVersion(); mBitField = 0; } @@ -164,8 +128,7 @@ /** * Intersection */ - void operator&=(const EnumSet aEnumSet) - { + void operator&=(const EnumSet aEnumSet) { incVersion(); mBitField &= aEnumSet.mBitField; } @@ -173,8 +136,7 @@ /** * Intersection */ - EnumSet operator&(const EnumSet aEnumSet) const - { + EnumSet operator&(const EnumSet aEnumSet) const { EnumSet result(*this); result &= aEnumSet; return result; @@ -183,24 +145,19 @@ /** * Equality */ - bool operator==(const EnumSet aEnumSet) const - { + bool operator==(const EnumSet aEnumSet) const { return mBitField == aEnumSet.mBitField; } /** * Test is an element is contained in the set. */ - bool contains(T aEnum) const - { - return mBitField & bitFor(aEnum); - } + bool contains(T aEnum) const { return mBitField & bitFor(aEnum); } /** * Return the number of elements in the set. */ - uint8_t size() const - { + uint8_t size() const { uint8_t count = 0; for (uint32_t bitField = mBitField; bitField; bitField >>= 1) { if (bitField & 1) { @@ -210,50 +167,39 @@ return count; } - bool isEmpty() const - { - return mBitField == 0; - } + bool isEmpty() const { return mBitField == 0; } - uint32_t serialize() const - { - return mBitField; - } + serializedType serialize() const { return mBitField; } - void deserialize(uint32_t aValue) - { + void deserialize(serializedType aValue) { incVersion(); mBitField = aValue; } - class ConstIterator - { + class ConstIterator { const EnumSet* mSet; uint32_t mPos; #ifdef DEBUG uint64_t mVersion; #endif - void checkVersion() { + void checkVersion() const { // 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) - { + : mSet(&aSet), mPos(aPos) { #ifdef DEBUG mVersion = mSet->mVersion; #endif MOZ_ASSERT(aPos <= kMaxBits); - if (aPos != kMaxBits && !mSet->contains(T(mPos))) - ++*this; + if (aPos != kMaxBits && !mSet->contains(T(mPos))) ++*this; } ConstIterator(const ConstIterator& aOther) - : mSet(aOther.mSet), mPos(aOther.mPos) - { + : mSet(aOther.mSet), mPos(aOther.mPos) { #ifdef DEBUG mVersion = aOther.mVersion; checkVersion(); @@ -261,8 +207,7 @@ } ConstIterator(ConstIterator&& aOther) - : mSet(aOther.mSet), mPos(aOther.mPos) - { + : mSet(aOther.mSet), mPos(aOther.mPos) { #ifdef DEBUG mVersion = aOther.mVersion; checkVersion(); @@ -270,21 +215,19 @@ aOther.mSet = nullptr; } - ~ConstIterator() { - checkVersion(); - } + ~ConstIterator() { checkVersion(); } - bool operator==(const ConstIterator& other) { + bool operator==(const ConstIterator& other) const { MOZ_ASSERT(mSet == other.mSet); checkVersion(); return mPos == other.mPos; } - bool operator!=(const ConstIterator& other) { + bool operator!=(const ConstIterator& other) const { return !(*this == other); } - T operator*() { + T operator*() const { MOZ_ASSERT(mSet); MOZ_ASSERT(mPos < kMaxBits); MOZ_ASSERT(mSet->contains(T(mPos))); @@ -303,28 +246,17 @@ } }; - ConstIterator begin() const { - return ConstIterator(*this, 0); - } + ConstIterator begin() const { return ConstIterator(*this, 0); } - ConstIterator end() const { - return ConstIterator(*this, kMaxBits); - } + ConstIterator end() const { return ConstIterator(*this, kMaxBits); } -private: - static uint32_t bitFor(T aEnum) - { + private: + static uint32_t bitFor(T aEnum) { uint32_t bitNumber = (uint32_t)aEnum; MOZ_ASSERT(bitNumber < kMaxBits); return 1U << bitNumber; } - void initVersion() { -#ifdef DEBUG - mVersion = 0; -#endif - } - void incVersion() { #ifdef DEBUG mVersion++; @@ -332,13 +264,13 @@ } static const size_t kMaxBits = 32; - uint32_t mBitField; + serializedType mBitField; #ifdef DEBUG - uint64_t mVersion; + uint64_t mVersion = 0; #endif }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_EnumSet_h_*/ 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 @@ -14,34 +14,31 @@ namespace detail { -template +template struct EnumFitsWithinHelper; // Signed enum, signed storage. -template +template struct EnumFitsWithinHelper - : public std::integral_constant -{}; + : public std::integral_constant {}; // Signed enum, unsigned storage. -template +template struct EnumFitsWithinHelper - : public std::integral_constant -{}; + : public std::integral_constant {}; // Unsigned enum, signed storage. -template +template struct EnumFitsWithinHelper - : public std::integral_constant -{}; + : public std::integral_constant {}; // Unsigned enum, unsigned storage. -template +template struct EnumFitsWithinHelper - : public std::integral_constant -{}; + : public std::integral_constant {}; -} // namespace detail +} // namespace detail /* * Type trait that determines whether the enum type T can fit within the @@ -52,19 +49,40 @@ * 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 +template struct EnumTypeFitsWithin - : public detail::EnumFitsWithinHelper< - sizeof(T), - std::is_signed::type>::value, - sizeof(Storage), - std::is_signed::value - > -{ + : 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"); + static_assert(std::is_integral::value, + "must provide an integral type"); }; -} // namespace mozilla +/* + * Provides information about highest enum member value. + * Each specialization of struct MaxEnumValue should define + * "static constexpr unsigned int value". + * + * example: + * + * enum ExampleEnum + * { + * CAT = 0, + * DOG, + * HAMSTER + * }; + * + * template <> + * struct MaxEnumValue + * { + * static constexpr unsigned int value = static_cast(HAMSTER); + * }; + */ +template +struct MaxEnumValue; // no need to define the primary template + +} // 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 @@ -38,54 +38,51 @@ * headCount[AnimalSpecies::Sheep] = 30; * */ -template -class EnumeratedArray -{ -public: +template +class EnumeratedArray { + public: static const size_t kSize = size_t(SizeAsEnumValue); -private: + private: typedef Array ArrayType; ArrayType mArray; -public: + public: EnumeratedArray() {} template MOZ_IMPLICIT EnumeratedArray(Args&&... aArgs) - : mArray{mozilla::Forward(aArgs)...} - {} + : mArray{mozilla::Forward(aArgs)...} {} - explicit EnumeratedArray(const EnumeratedArray& aOther) - { + explicit EnumeratedArray(const EnumeratedArray& aOther) { for (size_t i = 0; i < kSize; i++) { mArray[i] = aOther.mArray[i]; } } - EnumeratedArray(EnumeratedArray&& aOther) - { + EnumeratedArray(EnumeratedArray&& aOther) { for (size_t i = 0; i < kSize; i++) { mArray[i] = Move(aOther.mArray[i]); } } - ValueType& operator[](IndexType aIndex) - { + ValueType& operator[](IndexType aIndex) { return mArray[size_t(aIndex)]; } + + const ValueType& operator[](IndexType aIndex) const { return mArray[size_t(aIndex)]; } - const ValueType& operator[](IndexType aIndex) const - { - return mArray[size_t(aIndex)]; + EnumeratedArray& operator=(EnumeratedArray&& aOther) { + for (size_t i = 0; i < kSize; i++) { + mArray[i] = Move(aOther.mArray[i]); + } + return *this; } - typedef typename ArrayType::iterator iterator; - typedef typename ArrayType::const_iterator const_iterator; - typedef typename ArrayType::reverse_iterator reverse_iterator; + typedef typename ArrayType::iterator iterator; + typedef typename ArrayType::const_iterator const_iterator; + typedef typename ArrayType::reverse_iterator reverse_iterator; typedef typename ArrayType::const_reverse_iterator const_reverse_iterator; // Methods for range-based for loops. @@ -105,6 +102,6 @@ const_reverse_iterator crend() const { return mArray.crend(); } }; -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_EnumeratedArray_h +#endif // mozilla_EnumeratedArray_h 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 @@ -28,42 +28,36 @@ namespace detail { -template -class EnumeratedIterator -{ -public: +template +class EnumeratedIterator { + public: typedef typename std::underlying_type::type IntTypeT; - template - explicit EnumeratedIterator(EnumType aCurrent) - : mCurrent(aCurrent) { } + template + explicit EnumeratedIterator(EnumType aCurrent) : mCurrent(aCurrent) {} - template + template explicit EnumeratedIterator(const EnumeratedIterator& aOther) - : mCurrent(aOther.mCurrent) { } + : mCurrent(aOther.mCurrent) {} EnumTypeT operator*() const { return mCurrent; } /* Increment and decrement operators */ - EnumeratedIterator& operator++() - { + EnumeratedIterator& operator++() { mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1)); return *this; } - EnumeratedIterator& operator--() - { + EnumeratedIterator& operator--() { mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1)); return *this; } - EnumeratedIterator operator++(int) - { + EnumeratedIterator operator++(int) { auto ret = *this; mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1)); return ret; } - EnumeratedIterator operator--(int) - { + EnumeratedIterator operator--(int) { auto ret = *this; mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1)); return ret; @@ -71,83 +65,76 @@ /* Comparison operators */ - template + template friend bool operator==(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); - template + template friend bool operator!=(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); - template + template friend bool operator<(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); - template + template friend bool operator<=(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); - template + template friend bool operator>(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); - template + template friend bool operator>=(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); -private: + private: EnumTypeT mCurrent; }; -template +template bool operator==(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) -{ + const EnumeratedIterator& aIter2) { return aIter1.mCurrent == aIter2.mCurrent; } -template +template bool operator!=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) -{ + const EnumeratedIterator& aIter2) { return aIter1.mCurrent != aIter2.mCurrent; } -template +template bool operator<(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) -{ + const EnumeratedIterator& aIter2) { return aIter1.mCurrent < aIter2.mCurrent; } -template +template bool operator<=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) -{ + const EnumeratedIterator& aIter2) { return aIter1.mCurrent <= aIter2.mCurrent; } -template +template bool operator>(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) -{ + const EnumeratedIterator& aIter2) { return aIter1.mCurrent > aIter2.mCurrent; } -template +template bool operator>=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) -{ + const EnumeratedIterator& aIter2) { return aIter1.mCurrent >= aIter2.mCurrent; } -template -class EnumeratedRange -{ -public: +template +class EnumeratedRange { + public: typedef EnumeratedIterator iterator; typedef EnumeratedIterator const_iterator; typedef ReverseIterator reverse_iterator; typedef ReverseIterator const_reverse_iterator; - template + template EnumeratedRange(EnumType aBegin, EnumType aEnd) - : mBegin(aBegin), mEnd(aEnd) { } + : mBegin(aBegin), mEnd(aEnd) {} iterator begin() const { return iterator(mBegin); } const_iterator cbegin() const { return begin(); } @@ -158,44 +145,40 @@ reverse_iterator rend() const { return reverse_iterator(mBegin); } const_reverse_iterator crend() const { return rend(); } -private: + private: EnumTypeT mBegin; EnumTypeT mEnd; }; -} // namespace detail +} // namespace detail #ifdef __GNUC__ // Enums can have an unsigned underlying type, which makes some of the // comparisons below always true or always false. Temporarily disable // -Wtype-limits to avoid breaking -Werror builds. -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wtype-limits" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" #endif // Create a range to iterate from aBegin to aEnd, exclusive. -template -inline detail::EnumeratedRange -MakeEnumeratedRange(EnumType aBegin, EnumType aEnd) -{ +template +inline detail::EnumeratedRange MakeEnumeratedRange(EnumType aBegin, + EnumType aEnd) { MOZ_ASSERT(aBegin <= aEnd, "Cannot generate invalid, unbounded range!"); 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! -template -inline detail::EnumeratedRange -MakeEnumeratedRange(EnumType aEnd) -{ +template +inline detail::EnumeratedRange MakeEnumeratedRange(EnumType aEnd) { return MakeEnumeratedRange(EnumType(0), aEnd); } #ifdef __GNUC__ -# pragma GCC diagnostic pop +#pragma GCC diagnostic pop #endif -} // namespace mozilla - -#endif // mozilla_EnumeratedRange_h +} // namespace mozilla +#endif // mozilla_EnumeratedRange_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/FStream.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/FStream.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/FStream.h @@ -0,0 +1,124 @@ +/* -*- 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/. */ + +// Similar to std::ifstream/ofstream, but takes char16ptr_t on Windows. +// Until C++17, std functions can only take char* filenames. So Unicode +// filenames were lost on Windows. To address this limitations, this wrapper +// uses proprietary wchar_t* overloads on MSVC, and __gnu_cxx::stdio_filebuf +// extension on MinGW. Once we can use C++17 filesystem API everywhere, +// we will be able to avoid this wrapper. + +#ifndef mozilla_FStream_h +#define mozilla_FStream_h + +#include "mozilla/Char16.h" +#include +#include +#include +#if defined(__MINGW32__) && defined(__GLIBCXX__) +#include "mozilla/UniquePtr.h" +#include +#include +#endif + +namespace mozilla { + +#if defined(__MINGW32__) && defined(__GLIBCXX__) +// MinGW does not support wchar_t* overloads that are MSVC extension until +// C++17, so we have to implement widechar wrappers using a GNU extension. +class IFStream : public std::istream { + public: + explicit IFStream(char16ptr_t filename, openmode mode = in); + + std::filebuf* rdbuf() const { return mFileBuf.get(); } + + bool is_open() const { return mFileBuf && mFileBuf->is_open(); } + void open(char16ptr_t filename, openmode mode = in); + void close() { mFileBuf && mFileBuf->close(); } + + private: + UniquePtr mFileBuf; +}; + +inline IFStream::IFStream(char16ptr_t filename, openmode mode) + : std::istream(nullptr) { + open(filename, mode); +} + +inline void IFStream::open(char16ptr_t filename, openmode mode) { + int fmode = _O_RDONLY; + if (mode & binary) { + fmode |= _O_BINARY; + } else { + fmode |= _O_TEXT; + } + int fd = _wopen(filename, fmode); + mFileBuf = MakeUnique<__gnu_cxx::stdio_filebuf>(fd, mode); + std::istream::rdbuf(mFileBuf.get()); +} + +class OFStream : public std::ostream { + public: + explicit OFStream(char16ptr_t filename, openmode mode = out); + + std::filebuf* rdbuf() const { return mFileBuf.get(); } + + bool is_open() const { return mFileBuf && mFileBuf->is_open(); } + void open(char16ptr_t filename, openmode mode = out); + void close() { mFileBuf && mFileBuf->close(); } + + private: + UniquePtr mFileBuf; +}; + +inline OFStream::OFStream(char16ptr_t filename, openmode mode) + : std::ostream(nullptr) { + open(filename, mode); +} + +inline void OFStream::open(char16ptr_t filename, openmode mode) { + int fmode = _O_WRONLY; + if (mode & binary) { + fmode |= _O_BINARY; + } else { + fmode |= _O_TEXT; + } + if (mode & trunc) { + fmode |= _O_CREAT | _O_TRUNC; + } + int fd = _wopen(filename, fmode); + mFileBuf = MakeUnique<__gnu_cxx::stdio_filebuf>(fd, mode); + std::ostream::rdbuf(mFileBuf.get()); +} + +#elif defined(XP_WIN) +class IFStream : public std::ifstream { + public: + explicit IFStream(char16ptr_t filename, openmode mode = in) + : std::ifstream(filename, mode) {} + + void open(char16ptr_t filename, openmode mode = in) { + std::ifstream::open(filename, mode); + } +}; + +class OFStream : public std::ofstream { + public: + explicit OFStream(char16ptr_t filename, openmode mode = out) + : std::ofstream(filename, mode) {} + + void open(char16ptr_t filename, openmode mode = out) { + std::ofstream::open(filename, mode); + } +}; +#else +using IFStream = std::ifstream; +using OFStream = std::ofstream; +#endif + +} // namespace mozilla + +#endif /* mozilla_FStream_h */ 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 @@ -122,10 +122,10 @@ * P 1-P * * But the "1 or more" section of the line is subdivided the same way: *within - * that section*, in portion P the second call to |trial()| returns true, and in - * portion 1-P it returns false a second time; the skip count is two or more. - * So we return true on the second call in proportion 0.7 * 0.3, and skip at - * least the first two in proportion 0.7 * 0.7. + * that section*, in portion P the second call to |trial()| returns true, and + * in portion 1-P it returns false a second time; the skip count is two or + * more. So we return true on the second call in proportion 0.7 * 0.3, and + * skip at least the first two in proportion 0.7 * 0.7. * * skip: 0 1 2 or more * |------------------^------------^----------------------------| @@ -160,8 +160,8 @@ * it? This is exactly std::floor(std::log(X) / std::log(1-P)). * * Our algorithm is then, simply: When constructed, compute an initial skip - * count. Return false from |trial| that many times, and then compute a new skip - * count. + * count. Return false from |trial| that many times, and then compute a new + * skip count. * * For a call to |trial(n)|, if the skip count is greater than n, return false * and subtract n from the skip count. If the skip count is less than n, @@ -177,11 +177,10 @@ * random number generator; both may not be zero. */ FastBernoulliTrial(double aProbability, uint64_t aState0, uint64_t aState1) - : mProbability(0) - , mInvLogNotProbability(0) - , mGenerator(aState0, aState1) - , mSkipCount(0) - { + : mProbability(0), + mInvLogNotProbability(0), + mGenerator(aState0, aState1), + mSkipCount(0) { setProbability(aProbability); } @@ -306,7 +305,8 @@ /* Our random number generator. */ non_crypto::XorShift128PlusRNG mGenerator; - /* The number of times |trial| should return false before next returning true. */ + /* The number of times |trial| should return false before next returning true. + */ size_t mSkipCount; /* @@ -355,7 +355,7 @@ * double is 2^64, not 2^64-1, so this doesn't actually set skipCount to a * value that can be safely assigned to mSkipCount. * - * Jakub Oleson cleverly suggested flipping the sense of the comparison: if + * Jakob Olesen cleverly suggested flipping the sense of the comparison: if * we require that skipCount < SIZE_MAX, then because of the gaps (2048) * between doubles at that magnitude, the highest double less than 2^64 is * 2^64 - 2048, which is fine to store in a size_t. @@ -363,8 +363,8 @@ * (On 32-bit machines, all size_t values can be represented exactly in * double, so all is well.) */ - double skipCount = std::floor(std::log(mGenerator.nextDouble()) - * mInvLogNotProbability); + double skipCount = + std::floor(std::log(mGenerator.nextDouble()) * mInvLogNotProbability); if (skipCount < SIZE_MAX) mSkipCount = skipCount; else @@ -374,6 +374,6 @@ } }; -} /* namespace mozilla */ +} /* namespace mozilla */ #endif /* mozilla_FastBernoulliTrial_h */ 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 @@ -13,8 +13,11 @@ #include "mozilla/Attributes.h" #include "mozilla/Casting.h" #include "mozilla/MathAlgorithms.h" +#include "mozilla/MemoryChecking.h" #include "mozilla/Types.h" +#include "mozilla/TypeTraits.h" +#include #include namespace mozilla { @@ -34,33 +37,34 @@ * compiler bustage, particularly PGO-specific bustage. */ -struct FloatTypeTraits -{ - typedef uint32_t Bits; - - static const unsigned kExponentBias = 127; - static const unsigned kExponentShift = 23; - - static const Bits kSignBit = 0x80000000UL; - static const Bits kExponentBits = 0x7F800000UL; - static const Bits kSignificandBits = 0x007FFFFFUL; +struct FloatTypeTraits { + using Bits = uint32_t; + + static constexpr unsigned kExponentBias = 127; + static constexpr unsigned kExponentShift = 23; + + static constexpr Bits kSignBit = 0x80000000UL; + static constexpr Bits kExponentBits = 0x7F800000UL; + static constexpr Bits kSignificandBits = 0x007FFFFFUL; }; -struct DoubleTypeTraits -{ - typedef uint64_t Bits; - - static const unsigned kExponentBias = 1023; - static const unsigned kExponentShift = 52; - - static const Bits kSignBit = 0x8000000000000000ULL; - static const Bits kExponentBits = 0x7ff0000000000000ULL; - static const Bits kSignificandBits = 0x000fffffffffffffULL; +struct DoubleTypeTraits { + using Bits = uint64_t; + + static constexpr unsigned kExponentBias = 1023; + static constexpr unsigned kExponentShift = 52; + + static constexpr Bits kSignBit = 0x8000000000000000ULL; + static constexpr Bits kExponentBits = 0x7ff0000000000000ULL; + static constexpr Bits kSignificandBits = 0x000fffffffffffffULL; }; -template struct SelectTrait; -template<> struct SelectTrait : public FloatTypeTraits {}; -template<> struct SelectTrait : public DoubleTypeTraits {}; +template +struct SelectTrait; +template <> +struct SelectTrait : public FloatTypeTraits {}; +template <> +struct SelectTrait : public DoubleTypeTraits {}; /* * This struct contains details regarding the encoding of floating-point @@ -88,11 +92,10 @@ * http://en.wikipedia.org/wiki/IEEE_floating_point * http://en.wikipedia.org/wiki/Floating_point#IEEE_754:_floating_point_in_modern_computers */ -template -struct FloatingPoint : public SelectTrait -{ - typedef SelectTrait Base; - typedef typename Base::Bits Bits; +template +struct FloatingPoint : public SelectTrait { + using Base = SelectTrait; + using Bits = typename Base::Bits; static_assert((Base::kSignBit & Base::kExponentBits) == 0, "sign bit shouldn't overlap exponent bits"); @@ -101,8 +104,8 @@ static_assert((Base::kExponentBits & Base::kSignificandBits) == 0, "exponent bits shouldn't overlap significand bits"); - static_assert((Base::kSignBit | Base::kExponentBits | Base::kSignificandBits) == - ~Bits(0), + static_assert((Base::kSignBit | Base::kExponentBits | + Base::kSignificandBits) == ~Bits(0), "all bits accounted for"); /* @@ -116,25 +119,22 @@ }; /** Determines whether a float/double is NaN. */ -template -static MOZ_ALWAYS_INLINE bool -IsNaN(T aValue) -{ +template +static MOZ_ALWAYS_INLINE bool IsNaN(T aValue) { /* * A float/double is NaN if all exponent bits are 1 and the significand * contains at least one non-zero bit. */ typedef FloatingPoint Traits; typedef typename Traits::Bits Bits; - return (BitwiseCast(aValue) & Traits::kExponentBits) == Traits::kExponentBits && + return (BitwiseCast(aValue) & Traits::kExponentBits) == + Traits::kExponentBits && (BitwiseCast(aValue) & Traits::kSignificandBits) != 0; } /** Determines whether a float/double is +Infinity or -Infinity. */ -template -static MOZ_ALWAYS_INLINE bool -IsInfinite(T aValue) -{ +template +static MOZ_ALWAYS_INLINE bool IsInfinite(T aValue) { /* Infinities have all exponent bits set to 1 and an all-0 significand. */ typedef FloatingPoint Traits; typedef typename Traits::Bits Bits; @@ -143,10 +143,8 @@ } /** Determines whether a float/double is not NaN or infinite. */ -template -static MOZ_ALWAYS_INLINE bool -IsFinite(T aValue) -{ +template +static MOZ_ALWAYS_INLINE bool IsFinite(T aValue) { /* * NaN and Infinities are the only non-finite floats/doubles, and both have * all exponent bits set to 1. @@ -161,10 +159,8 @@ * Determines whether a float/double is negative or -0. It is an error * to call this method on a float/double which is NaN. */ -template -static MOZ_ALWAYS_INLINE bool -IsNegative(T aValue) -{ +template +static MOZ_ALWAYS_INLINE bool IsNegative(T aValue) { MOZ_ASSERT(!IsNaN(aValue), "NaN does not have a sign"); /* The sign bit is set if the double is negative. */ @@ -175,10 +171,8 @@ } /** Determines whether a float/double represents -0. */ -template -static MOZ_ALWAYS_INLINE bool -IsNegativeZero(T aValue) -{ +template +static MOZ_ALWAYS_INLINE bool IsNegativeZero(T aValue) { /* Only the sign bit is set if the value is -0. */ typedef FloatingPoint Traits; typedef typename Traits::Bits Bits; @@ -187,10 +181,8 @@ } /** Determines wether a float/double represents +0. */ -template -static MOZ_ALWAYS_INLINE bool -IsPositiveZero(T aValue) -{ +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; @@ -202,10 +194,8 @@ * Returns 0 if a float/double is NaN or infinite; * otherwise, the float/double is returned. */ -template -static MOZ_ALWAYS_INLINE T -ToZeroIfNonfinite(T aValue) -{ +template +static MOZ_ALWAYS_INLINE T ToZeroIfNonfinite(T aValue) { return IsFinite(aValue) ? aValue : 0; } @@ -215,10 +205,8 @@ * Zero is not special-cased, so ExponentComponent(0.0) is * -int_fast16_t(Traits::kExponentBias). */ -template -static MOZ_ALWAYS_INLINE int_fast16_t -ExponentComponent(T aValue) -{ +template +static MOZ_ALWAYS_INLINE int_fast16_t ExponentComponent(T aValue) { /* * The exponent component of a float/double is an unsigned number, biased * from its actual value. Subtract the bias to retrieve the actual exponent. @@ -226,15 +214,14 @@ typedef FloatingPoint Traits; typedef typename Traits::Bits Bits; Bits bits = BitwiseCast(aValue); - return int_fast16_t((bits & Traits::kExponentBits) >> Traits::kExponentShift) - + return int_fast16_t((bits & Traits::kExponentBits) >> + Traits::kExponentShift) - int_fast16_t(Traits::kExponentBias); } /** Returns +Infinity. */ -template -static MOZ_ALWAYS_INLINE T -PositiveInfinity() -{ +template +static MOZ_ALWAYS_INLINE T PositiveInfinity() { /* * Positive infinity has all exponent bits set, sign bit set to 0, and no * significand. @@ -244,10 +231,8 @@ } /** Returns -Infinity. */ -template -static MOZ_ALWAYS_INLINE T -NegativeInfinity() -{ +template +static MOZ_ALWAYS_INLINE T NegativeInfinity() { /* * Negative infinity has all exponent bits set, sign bit set to 1, and no * significand. @@ -260,11 +245,8 @@ * Computes the bit pattern for a NaN with the specified sign bit and * significand bits. */ -template::Bits Significand> -struct SpecificNaNBits -{ +template ::Bits Significand> +struct SpecificNaNBits { using Traits = FloatingPoint; static_assert(SignBit == 0 || SignBit == 1, "bad sign bit"); @@ -274,7 +256,7 @@ "significand must be nonzero"); static constexpr typename Traits::Bits value = - (SignBit * Traits::kSignBit) | Traits::kExponentBits | Significand; + (SignBit * Traits::kSignBit) | Traits::kExponentBits | Significand; }; /** @@ -293,83 +275,163 @@ * 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 void -SpecificNaN(int signbit, typename FloatingPoint::Bits significand, T* result) -{ +template +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); - BitwiseCast((signbit ? Traits::kSignBit : 0) | - Traits::kExponentBits | - significand, - result); + BitwiseCast( + (signbit ? Traits::kSignBit : 0) | Traits::kExponentBits | significand, + result); MOZ_ASSERT(IsNaN(*result)); } -template +template static MOZ_ALWAYS_INLINE T -SpecificNaN(int signbit, typename FloatingPoint::Bits significand) -{ +SpecificNaN(int signbit, typename FloatingPoint::Bits significand) { T t; SpecificNaN(signbit, significand, &t); return t; } /** Computes the smallest non-zero positive float/double value. */ -template -static MOZ_ALWAYS_INLINE T -MinNumberValue() -{ +template +static MOZ_ALWAYS_INLINE T MinNumberValue() { typedef FloatingPoint Traits; typedef typename Traits::Bits Bits; return BitwiseCast(Bits(1)); } +namespace detail { + +template +inline bool NumberEqualsSignedInteger(Float aValue, SignedInteger* aInteger) { + static_assert(IsSame::value || IsSame::value, + "Float must be an IEEE-754 floating point type"); + static_assert(IsSigned::value, + "this algorithm only works for signed types: a different one " + "will be required for unsigned types"); + static_assert(sizeof(SignedInteger) >= sizeof(int), + "this function *might* require some finessing for signed types " + "subject to integral promotion before it can be used on them"); + + MOZ_MAKE_MEM_UNDEFINED(aInteger, sizeof(*aInteger)); + + // NaNs and infinities are not integers. + if (!IsFinite(aValue)) { + return false; + } + + // Otherwise do direct comparisons against the minimum/maximum |SignedInteger| + // values that can be encoded in |Float|. + + constexpr SignedInteger MaxIntValue = + std::numeric_limits::max(); // e.g. INT32_MAX + constexpr SignedInteger MinValue = + std::numeric_limits::min(); // e.g. INT32_MIN + + static_assert(IsPowerOfTwo(Abs(MinValue)), + "MinValue should be is a small power of two, thus exactly " + "representable in float/double both"); + + constexpr unsigned SignedIntegerWidth = CHAR_BIT * sizeof(SignedInteger); + constexpr unsigned ExponentShift = FloatingPoint::kExponentShift; + + // Careful! |MaxIntValue| may not be the maximum |SignedInteger| value that + // can be encoded in |Float|. Its |SignedIntegerWidth - 1| bits of precision + // may exceed |Float|'s |ExponentShift + 1| bits of precision. If necessary, + // compute the maximum |SignedInteger| that fits in |Float| from IEEE-754 + // first principles. (|MinValue| doesn't have this problem because as a + // [relatively] small power of two it's always representable in |Float|.) + + // Per C++11 [expr.const]p2, unevaluated subexpressions of logical AND/OR and + // conditional expressions *may* contain non-constant expressions, without + // making the enclosing expression not constexpr. MSVC implements this -- but + // it sometimes warns about undefined behavior in unevaluated subexpressions. + // This bites us if we initialize |MaxValue| the obvious way including an + // |uint64_t(1) << (SignedIntegerWidth - 2 - ExponentShift)| subexpression. + // Pull that shift-amount out and give it a not-too-huge value when it's in an + // unevaluated subexpression. 🙄 + constexpr unsigned PrecisionExceededShiftAmount = + ExponentShift > SignedIntegerWidth - 1 + ? 0 + : SignedIntegerWidth - 2 - ExponentShift; + + constexpr SignedInteger MaxValue = + ExponentShift > SignedIntegerWidth - 1 + ? MaxIntValue + : SignedInteger((uint64_t(1) << (SignedIntegerWidth - 1)) - + (uint64_t(1) << PrecisionExceededShiftAmount)); + + if (static_cast(MinValue) <= aValue && + aValue <= static_cast(MaxValue)) { + auto possible = static_cast(aValue); + if (static_cast(possible) == aValue) { + *aInteger = possible; + return true; + } + } + + return false; +} + +template +inline bool NumberIsSignedInteger(Float aValue, SignedInteger* aInteger) { + static_assert(IsSame::value || IsSame::value, + "Float must be an IEEE-754 floating point type"); + static_assert(IsSigned::value, + "this algorithm only works for signed types: a different one " + "will be required for unsigned types"); + static_assert(sizeof(SignedInteger) >= sizeof(int), + "this function *might* require some finessing for signed types " + "subject to integral promotion before it can be used on them"); + + MOZ_MAKE_MEM_UNDEFINED(aInteger, sizeof(*aInteger)); + + if (IsNegativeZero(aValue)) { + return false; + } + + return NumberEqualsSignedInteger(aValue, aInteger); +} + +} // namespace detail + /** - * If aValue is equal to some int32_t value, set *aInt32 to that value and - * return true; otherwise return false. + * If |aValue| is identical to some |int32_t| value, set |*aInt32| to that value + * and return true. Otherwise return false, leaving |*aInt32| in an + * indeterminate state. * - * Note that negative zero is "equal" to zero here. To test whether a value can - * be losslessly converted to int32_t and back, use NumberIsInt32 instead. + * This method returns false for negative zero. If you want to consider -0 to + * be 0, use NumberEqualsInt32 below. */ -template -static MOZ_ALWAYS_INLINE bool -NumberEqualsInt32(T aValue, int32_t* aInt32) -{ - /* - * XXX Casting a floating-point value that doesn't truncate to int32_t, to - * int32_t, induces undefined behavior. We should definitely fix this - * (bug 744965), but as apparently it "works" in practice, it's not a - * pressing concern now. - */ - return aValue == (*aInt32 = int32_t(aValue)); +template +static MOZ_ALWAYS_INLINE bool NumberIsInt32(T aValue, int32_t* aInt32) { + return detail::NumberIsSignedInteger(aValue, aInt32); } /** - * If d can be converted to int32_t and back to an identical double value, - * set *aInt32 to that value and return true; otherwise return false. + * If |aValue| is equal to some int32_t value (where -0 and +0 are considered + * equal), set |*aInt32| to that value and return true. Otherwise return false, + * leaving |*aInt32| in an indeterminate state. * - * The difference between this and NumberEqualsInt32 is that this method returns - * false for negative zero. + * |NumberEqualsInt32(-0.0, ...)| will return true. To test whether a value can + * be losslessly converted to |int32_t| and back, use NumberIsInt32 above. */ -template -static MOZ_ALWAYS_INLINE bool -NumberIsInt32(T aValue, int32_t* aInt32) -{ - return !IsNegativeZero(aValue) && NumberEqualsInt32(aValue, aInt32); +template +static MOZ_ALWAYS_INLINE bool NumberEqualsInt32(T aValue, int32_t* aInt32) { + return detail::NumberEqualsSignedInteger(aValue, aInt32); } /** * Computes a NaN value. Do not use this method if you depend upon a particular * NaN value being returned. */ -template -static MOZ_ALWAYS_INLINE T -UnspecifiedNaN() -{ +template +static MOZ_ALWAYS_INLINE T UnspecifiedNaN() { /* * If we can use any quiet NaN, we might as well use the all-ones NaN, * since it's cheap to materialize on common platforms (such as x64, where @@ -385,10 +447,8 @@ * any NaN value to any other NaN value. (The normal equality operators equate * -0 with +0, and they equate NaN to no other value.) */ -template -static inline bool -NumbersAreIdentical(T aValue1, T aValue2) -{ +template +static inline bool NumbersAreIdentical(T aValue1, T aValue2) { typedef FloatingPoint Traits; typedef typename Traits::Bits Bits; if (IsNaN(aValue1)) { @@ -399,24 +459,22 @@ namespace detail { -template +template struct FuzzyEqualsEpsilon; -template<> -struct FuzzyEqualsEpsilon -{ +template <> +struct FuzzyEqualsEpsilon { // A number near 1e-5 that is exactly representable in a float. static float value() { return 1.0f / (1 << 17); } }; -template<> -struct FuzzyEqualsEpsilon -{ +template <> +struct FuzzyEqualsEpsilon { // A number near 1e-12 that is exactly representable in a double. static double value() { return 1.0 / (1LL << 40); } }; -} // namespace detail +} // namespace detail /** * Compare two floating point values for equality, modulo rounding error. That @@ -430,11 +488,9 @@ * numbers you are dealing with is bounded and stays around the same order of * magnitude. */ -template -static MOZ_ALWAYS_INLINE bool -FuzzyEqualsAdditive(T aValue1, T aValue2, - T aEpsilon = detail::FuzzyEqualsEpsilon::value()) -{ +template +static MOZ_ALWAYS_INLINE bool FuzzyEqualsAdditive( + T aValue1, T aValue2, T aEpsilon = detail::FuzzyEqualsEpsilon::value()) { static_assert(IsFloatingPoint::value, "floating point type required"); return Abs(aValue1 - aValue2) <= aEpsilon; } @@ -451,11 +507,9 @@ * the floating point numbers being compared, regardless of what order of * magnitude those numbers are at. */ -template -static MOZ_ALWAYS_INLINE bool -FuzzyEqualsMultiplicative(T aValue1, T aValue2, - T aEpsilon = detail::FuzzyEqualsEpsilon::value()) -{ +template +static MOZ_ALWAYS_INLINE bool FuzzyEqualsMultiplicative( + T aValue1, T aValue2, T aEpsilon = detail::FuzzyEqualsEpsilon::value()) { static_assert(IsFloatingPoint::value, "floating point type required"); // can't use std::min because of bug 965340 T smaller = Abs(aValue1) < Abs(aValue2) ? Abs(aValue1) : Abs(aValue2); @@ -471,8 +525,7 @@ * This function isn't inlined to avoid buggy optimizations by MSVC. */ MOZ_MUST_USE -extern MFBT_API bool -IsFloat32Representable(double aFloat32); +extern MFBT_API bool IsFloat32Representable(double aFloat32); } /* namespace mozilla */ 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 @@ -1,223 +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/. */ - -/* A type-erased callable wrapper. */ - -#ifndef mozilla_Function_h -#define mozilla_Function_h - -#include "mozilla/Attributes.h" // for MOZ_IMPLICIT -#include "mozilla/Move.h" -#include "mozilla/RefCounted.h" -#include "mozilla/RefPtr.h" - -// |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. -// -// Supported callable types include non-member functions, static member -// functions, and function objects (that is to say, objects with an overloaded -// call operator; this includes C++11 lambdas). Member functions aren't -// directly supported; they first need to be wrapped into a function object -// using |std::mem_fn()| or an equivalent. -// -// |Signature| is a type of the form |ReturnType(Arguments...)|. Syntactically, -// 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 -// considered "empty". Invoking an empty instance is undefined behaviour. -// An empty instance can be populated with a callable by assigning to it. -// -// This class is intended to provide functionality similar to the C++11 -// standard library class |std::function|. - -namespace mozilla { - -namespace detail { - -template -class FunctionImplBase : public mozilla::RefCounted> -{ -public: - MOZ_DECLARE_REFCOUNTED_TYPENAME(FunctionImplBase) - - virtual ~FunctionImplBase() {} - virtual ReturnType call(Arguments... aArguments) = 0; -}; - -// Normal Callable Object. -template -class FunctionImpl : public FunctionImplBase -{ - public: - explicit FunctionImpl(const Callable& aCallable) - : mCallable(aCallable) {} - - ReturnType call(Arguments... aArguments) override - { - return mCallable(Forward(aArguments)...); - } - private: - Callable mCallable; -}; - -// Base class for passing pointer to member function. -template -class MemberFunctionImplBase : public FunctionImplBase -{ -public: - explicit MemberFunctionImplBase(const Callable& aCallable) - : mCallable(aCallable) {} - - ReturnType call(Arguments... aArguments) override - { - return callInternal(Forward(aArguments)...); - } -private: - template - ReturnType callInternal(ThisType* aThis, Args&&... aArguments) - { - return (aThis->*mCallable)(Forward(aArguments)...); - } - - template - ReturnType callInternal(ThisType&& aThis, Args&&... aArguments) - { - return (aThis.*mCallable)(Forward(aArguments)...); - } - Callable mCallable; -}; - -// For non-const member function specialization of FunctionImpl. -template -class FunctionImpl - : public MemberFunctionImplBase -{ -public: - explicit FunctionImpl(ReturnType(ThisType::*aMemberFunc)(Args...)) - : MemberFunctionImplBase(aMemberFunc) - {} -}; - -// For const member function specialization of FunctionImpl. -template -class FunctionImpl - : public MemberFunctionImplBase -{ -public: - explicit FunctionImpl(ReturnType(ThisType::*aConstMemberFunc)(Args...) const) - : MemberFunctionImplBase(aConstMemberFunc) - {} -}; - -} // namespace detail - -// The primary template is never defined. As |Signature| is required to be -// of the form |ReturnType(Arguments...)|, we only define a partial -// specialization that matches this form. This allows us to use |ReturnType| -// and |Arguments| in the definition of the specialization without having to -// introspect |Signature|. -template -class function; - -template -class function -{ -public: - function() {} - - // This constructor is implicit to match the interface of |std::function|. - template - 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) { - mImpl = Move(aOther.mImpl); - return *this; - } - - template - function& operator=(const Callable& 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; - } - - template - ReturnType operator()(Args&&... aArguments) const - { - MOZ_ASSERT(mImpl); - return mImpl->call(Forward(aArguments)...); - } - - explicit operator bool() const - { - return bool(mImpl); - } - -private: - // TODO: Consider implementing a small object optimization. - 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/GuardObjects.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/GuardObjects.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/GuardObjects.h @@ -75,19 +75,14 @@ * For more details, and examples of using these macros, see * https://developer.mozilla.org/en/Using_RAII_classes_in_Mozilla */ -class GuardObjectNotifier -{ -private: +class GuardObjectNotifier { + private: bool* mStatementDone; -public: - GuardObjectNotifier() - : mStatementDone(reinterpret_cast(MOZ_POISON)) - { - } + public: + GuardObjectNotifier() : mStatementDone(reinterpret_cast(MOZ_POISON)) {} - ~GuardObjectNotifier() - { + ~GuardObjectNotifier() { // Assert that the GuardObjectNotifier has been properly initialized by // using the |MOZ_GUARD_OBJECT_NOTIFIER_INIT| macro. A poison value is // used rather than a null check to appease static analyzers that were @@ -96,19 +91,17 @@ *mStatementDone = true; } - void setStatementDone(bool* aStatementIsDone) - { + void setStatementDone(bool* aStatementIsDone) { mStatementDone = aStatementIsDone; } }; -class GuardObjectNotificationReceiver -{ -private: +class GuardObjectNotificationReceiver { + private: bool mStatementDone; -public: - GuardObjectNotificationReceiver() : mStatementDone(false) { } + public: + GuardObjectNotificationReceiver() : mStatementDone(false) {} ~GuardObjectNotificationReceiver() { /* @@ -116,11 +109,11 @@ * this assert might also fire if init is not called because the guard * object's implementation is not using the above macros correctly.) */ - MOZ_ASSERT(mStatementDone); + MOZ_ASSERT(mStatementDone, + "Guard object should not be used as a temporary."); } - void init(GuardObjectNotifier& aNotifier) - { + void init(GuardObjectNotifier& aNotifier) { aNotifier.setStatementDone(&mStatementDone); } }; @@ -133,33 +126,36 @@ #endif /* DEBUG */ #ifdef DEBUG -# define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER \ - mozilla::detail::GuardObjectNotificationReceiver _mCheckNotUsedAsTemporary; -# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM \ - , mozilla::detail::GuardObjectNotifier&& _notifier = \ - mozilla::detail::GuardObjectNotifier() -# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM \ - mozilla::detail::GuardObjectNotifier&& _notifier = \ - mozilla::detail::GuardObjectNotifier() -# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL \ - , mozilla::detail::GuardObjectNotifier&& _notifier -# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL \ - mozilla::detail::GuardObjectNotifier&& _notifier -# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT \ - , mozilla::Move(_notifier) -# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT \ - mozilla::Move(_notifier) -# define MOZ_GUARD_OBJECT_NOTIFIER_INIT \ - do { _mCheckNotUsedAsTemporary.init(_notifier); } while (0) +#define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER \ + ::mozilla::detail::GuardObjectNotificationReceiver _mCheckNotUsedAsTemporary; +#define MOZ_GUARD_OBJECT_NOTIFIER_PARAM \ + , ::mozilla::detail::GuardObjectNotifier&& _notifier = \ + ::mozilla::detail::GuardObjectNotifier() +#define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM \ + ::mozilla::detail::GuardObjectNotifier&& _notifier = \ + ::mozilla::detail::GuardObjectNotifier() +#define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL \ + , ::mozilla::detail::GuardObjectNotifier&& _notifier +#define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL \ + ::mozilla::detail::GuardObjectNotifier&& _notifier +#define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT , ::mozilla::Move(_notifier) +#define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT \ + ::mozilla::Move(_notifier) +#define MOZ_GUARD_OBJECT_NOTIFIER_INIT \ + do { \ + _mCheckNotUsedAsTemporary.init(_notifier); \ + } while (0) #else -# define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM -# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM -# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL -# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL -# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT -# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT -# define MOZ_GUARD_OBJECT_NOTIFIER_INIT do { } while (0) +#define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +#define MOZ_GUARD_OBJECT_NOTIFIER_PARAM +#define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM +#define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL +#define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL +#define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT +#define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT +#define MOZ_GUARD_OBJECT_NOTIFIER_INIT \ + do { \ + } while (0) #endif #endif /* __cplusplus */ 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 @@ -52,10 +52,10 @@ #include "mozilla/Char16.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/Types.h" +#include "mozilla/WrappingOperations.h" #include -#ifdef __cplusplus namespace mozilla { /** @@ -63,18 +63,9 @@ */ static const uint32_t kGoldenRatioU32 = 0x9E3779B9U; -inline uint32_t -RotateBitsLeft32(uint32_t aValue, uint8_t aBits) -{ - MOZ_ASSERT(aBits < 32); - return (aValue << aBits) | (aValue >> (32 - aBits)); -} - namespace detail { -inline uint32_t -AddU32ToHash(uint32_t aHash, uint32_t aValue) -{ +inline uint32_t AddU32ToHash(uint32_t aHash, uint32_t aValue) { /* * This is the meat of all our hash routines. This hash function is not * particularly sophisticated, but it seems to work well for our mostly @@ -96,52 +87,40 @@ * Otherwise, if |aHash| is 0 (as it often is for the beginning of a * message), the expression * - * (kGoldenRatioU32 * RotateBitsLeft(aHash, 5)) |xor| aValue + * mozilla::WrappingMultiply(kGoldenRatioU32, RotateBitsLeft(aHash, 5)) + * |xor| + * aValue * * evaluates to |aValue|. * * (Number-theoretic aside: Because any odd number |m| is relatively prime to - * our modulus (2^32), the list + * our modulus (2**32), the list * - * [x * m (mod 2^32) for 0 <= x < 2^32] + * [x * m (mod 2**32) for 0 <= x < 2**32] * * has no duplicate elements. This means that multiplying by |m| does not * cause us to skip any possible hash values. * - * It's also nice if |m| has large-ish order mod 2^32 -- that is, if the - * smallest k such that m^k == 1 (mod 2^32) is large -- so we can safely + * It's also nice if |m| has large-ish order mod 2**32 -- that is, if the + * smallest k such that m**k == 1 (mod 2**32) is large -- so we can safely * multiply our hash value by |m| a few times without negating the - * multiplicative effect. Our golden ratio constant has order 2^29, which is + * multiplicative effect. Our golden ratio constant has order 2**29, which is * more than enough for our purposes.) */ - return kGoldenRatioU32 * (RotateBitsLeft32(aHash, 5) ^ aValue); + return mozilla::WrappingMultiply(kGoldenRatioU32, + RotateLeft(aHash, 5) ^ aValue); } /** * AddUintptrToHash takes sizeof(uintptr_t) as a template parameter. */ -template -inline uint32_t -AddUintptrToHash(uint32_t aHash, uintptr_t aValue); - -template<> -inline uint32_t -AddUintptrToHash<4>(uint32_t aHash, uintptr_t aValue) -{ +template +inline uint32_t AddUintptrToHash(uint32_t aHash, uintptr_t aValue) { return AddU32ToHash(aHash, static_cast(aValue)); } -template<> -inline uint32_t -AddUintptrToHash<8>(uint32_t aHash, uintptr_t aValue) -{ - /* - * The static cast to uint64_t below is necessary because this function - * sometimes gets compiled on 32-bit platforms (yes, even though it's a - * template and we never call this particular override in a 32-bit build). If - * we do aValue >> 32 on a 32-bit machine, we're shifting a 32-bit uintptr_t - * right 32 bits, and the compiler throws an error. - */ +template <> +inline uint32_t AddUintptrToHash<8>(uint32_t aHash, uintptr_t aValue) { uint32_t v1 = static_cast(aValue); uint32_t v2 = static_cast(static_cast(aValue) >> 32); return AddU32ToHash(AddU32ToHash(aHash, v1), v2); @@ -156,10 +135,9 @@ * Currently, we support hashing uint32_t's, values which we can implicitly * convert to uint32_t, data pointers, and function pointers. */ -template -MOZ_MUST_USE inline uint32_t -AddToHash(uint32_t aHash, A aA) -{ +template ::value, + typename U = typename mozilla::EnableIf::Type> +MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, T aA) { /* * Try to convert |A| to uint32_t implicitly. If this works, great. If not, * we'll error out. @@ -167,10 +145,8 @@ return detail::AddU32ToHash(aHash, aA); } -template -MOZ_MUST_USE inline uint32_t -AddToHash(uint32_t aHash, A* aA) -{ +template +MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, A* aA) { /* * You might think this function should just take a void*. But then we'd only * catch data pointers and couldn't handle function pointers. @@ -181,17 +157,18 @@ return detail::AddUintptrToHash(aHash, uintptr_t(aA)); } -template<> -MOZ_MUST_USE inline uint32_t -AddToHash(uint32_t aHash, uintptr_t aA) -{ - return detail::AddUintptrToHash(aHash, aA); +// We use AddUintptrToHash() for hashing all integral types. 8-byte integral +// types are treated the same as 64-bit pointers, and smaller integral types are +// first implicitly converted to 32 bits and then passed to AddUintptrToHash() +// to be hashed. +template ::value>::Type> +MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, T aA) { + return detail::AddUintptrToHash(aHash, aA); } -template -MOZ_MUST_USE uint32_t -AddToHash(uint32_t aHash, A aArg, Args... aArgs) -{ +template +MOZ_MUST_USE uint32_t AddToHash(uint32_t aHash, A aArg, Args... aArgs) { return AddToHash(AddToHash(aHash, aArg), aArgs...); } @@ -202,19 +179,15 @@ * much better than calling AddToHash(x, y), because AddToHash(x, y) assumes * that x has already been hashed. */ -template -MOZ_MUST_USE inline uint32_t -HashGeneric(Args... aArgs) -{ +template +MOZ_MUST_USE inline uint32_t HashGeneric(Args... aArgs) { return AddToHash(0, aArgs...); } namespace detail { -template -uint32_t -HashUntilZero(const T* aStr) -{ +template +uint32_t HashUntilZero(const T* aStr) { uint32_t hash = 0; for (T c; (c = *aStr); aStr++) { hash = AddToHash(hash, c); @@ -222,10 +195,8 @@ return hash; } -template -uint32_t -HashKnownLength(const T* aStr, size_t aLength) -{ +template +uint32_t HashKnownLength(const T* aStr, size_t aLength) { uint32_t hash = 0; for (size_t i = 0; i < aLength; i++) { hash = AddToHash(hash, aStr[i]); @@ -241,34 +212,25 @@ * If you have the string's length, you might as well call the overload which * includes the length. It may be marginally faster. */ -MOZ_MUST_USE inline uint32_t -HashString(const char* aStr) -{ +MOZ_MUST_USE inline uint32_t HashString(const char* aStr) { return detail::HashUntilZero(reinterpret_cast(aStr)); } -MOZ_MUST_USE inline uint32_t -HashString(const char* aStr, size_t aLength) -{ - return detail::HashKnownLength(reinterpret_cast(aStr), aLength); +MOZ_MUST_USE inline uint32_t HashString(const char* aStr, size_t aLength) { + return detail::HashKnownLength(reinterpret_cast(aStr), + aLength); } MOZ_MUST_USE -inline uint32_t -HashString(const unsigned char* aStr, size_t aLength) -{ +inline uint32_t HashString(const unsigned char* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); } -MOZ_MUST_USE inline uint32_t -HashString(const char16_t* aStr) -{ +MOZ_MUST_USE inline uint32_t HashString(const char16_t* aStr) { return detail::HashUntilZero(aStr); } -MOZ_MUST_USE inline uint32_t -HashString(const char16_t* aStr, size_t aLength) -{ +MOZ_MUST_USE inline uint32_t HashString(const char16_t* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); } @@ -277,15 +239,11 @@ * the same width! */ #ifdef WIN32 -MOZ_MUST_USE inline uint32_t -HashString(const wchar_t* aStr) -{ +MOZ_MUST_USE inline uint32_t HashString(const wchar_t* aStr) { return detail::HashUntilZero(aStr); } -MOZ_MUST_USE inline uint32_t -HashString(const wchar_t* aStr, size_t aLength) -{ +MOZ_MUST_USE inline uint32_t HashString(const wchar_t* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); } #endif @@ -296,8 +254,8 @@ * 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_MUST_USE extern MFBT_API uint32_t -HashBytes(const void* bytes, size_t aLength); +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. @@ -315,31 +273,28 @@ * * The algorithm is SipHash-1-3. See . */ -class HashCodeScrambler -{ +class HashCodeScrambler { struct SipHasher; uint64_t mK0, mK1; -public: + public: /** Creates a new scrambler with the given 128-bit key. */ - constexpr HashCodeScrambler(uint64_t aK0, uint64_t aK1) : mK0(aK0), mK1(aK1) {} + 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 - { + 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) - { + private: + struct SipHasher { + SipHasher(uint64_t aK0, uint64_t aK1) { // 1. Initialization. mV0 = aK0 ^ UINT64_C(0x736f6d6570736575); mV1 = aK1 ^ UINT64_C(0x646f72616e646f6d); @@ -347,8 +302,7 @@ mV3 = aK1 ^ UINT64_C(0x7465646279746573); } - uint64_t sipHash(uint64_t aM) - { + uint64_t sipHash(uint64_t aM) { // 2. Compression. mV3 ^= aM; sipRound(); @@ -356,13 +310,12 @@ // 3. Finalization. mV2 ^= 0xff; - for (int i = 0; i < 3; i++) - sipRound(); + for (int i = 0; i < 3; i++) sipRound(); return mV0 ^ mV1 ^ mV2 ^ mV3; } - void sipRound() - { + MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW + void sipRound() { mV0 += mV1; mV1 = RotateLeft(mV1, 13); mV1 ^= mV0; @@ -384,6 +337,5 @@ }; } /* namespace mozilla */ -#endif /* __cplusplus */ #endif /* mozilla_HashFunctions_h */ 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 @@ -40,7 +40,7 @@ * containing indices corresponding to the tuple indices. * * template - * void Helper(const Tuple& t, IndexSequence) + * void Helper(const Tuple& t, IndexSequence) * { * Foo(Get(t)...); * } @@ -71,9 +71,8 @@ /** * Represents a compile-time sequence of integer indices. */ -template -struct IndexSequence -{ +template +struct IndexSequence { static constexpr size_t Size() { return sizeof...(Indices); } }; @@ -81,35 +80,31 @@ // Helpers used by MakeIndexSequence. -template -struct IndexTuple -{ +template +struct IndexTuple { typedef IndexTuple Next; }; // Builds IndexTuple<0, 1, ..., N - 1>. -template -struct BuildIndexTuple -{ +template +struct BuildIndexTuple { typedef typename BuildIndexTuple::Type::Next Type; }; -template<> -struct BuildIndexTuple<0> -{ +template <> +struct BuildIndexTuple<0> { typedef IndexTuple<> Type; }; -template +template struct MakeIndexSequenceImpl; -template -struct MakeIndexSequenceImpl> -{ +template +struct MakeIndexSequenceImpl> { typedef IndexSequence Type; }; -} // namespace detail +} // namespace detail /** * A utility for building an IndexSequence of consecutive indices. @@ -117,11 +112,10 @@ * Note: unlike std::make_index_sequence, this is not an alias template * to work around bugs in MSVC 2013. */ -template -struct MakeIndexSequence -{ - typedef typename detail::MakeIndexSequenceImpl::Type>::Type Type; +template +struct MakeIndexSequence { + typedef typename detail::MakeIndexSequenceImpl< + N, typename detail::BuildIndexTuple::Type>::Type Type; }; /** @@ -132,12 +126,11 @@ * Note: unlike std::index_sequence_for, this is not an alias template * to work around bugs in MSVC 2013. */ -template -struct IndexSequenceFor -{ +template +struct IndexSequenceFor { typedef typename MakeIndexSequence::Type Type; }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_IndexSequence_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/IntegerPrintfMacros.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/IntegerPrintfMacros.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/IntegerPrintfMacros.h @@ -11,8 +11,8 @@ /* * These macros should not be used with the NSPR printf-like functions or their - * users, e.g. mozilla/Logging.h. If you need to use NSPR's facilities, see the - * comment on supported formats at the top of nsprpub/pr/include/prprf.h. + * users. If you need to use NSPR's facilities, see the comment on + * supported formats at the top of nsprpub/pr/include/prprf.h. */ /* @@ -35,18 +35,50 @@ * definitions match the actual type sizes seen at compile time. */ #if defined(ANDROID) && !defined(__LP64__) -# undef PRIdPTR /* intptr_t */ -# define PRIdPTR "d" /* intptr_t */ -# undef PRIiPTR /* intptr_t */ -# define PRIiPTR "i" /* intptr_t */ -# undef PRIoPTR /* uintptr_t */ -# define PRIoPTR "o" /* uintptr_t */ -# undef PRIuPTR /* uintptr_t */ -# define PRIuPTR "u" /* uintptr_t */ -# undef PRIxPTR /* uintptr_t */ -# define PRIxPTR "x" /* uintptr_t */ -# undef PRIXPTR /* uintptr_t */ -# define PRIXPTR "X" /* uintptr_t */ +#undef PRIdPTR /* intptr_t */ +#define PRIdPTR "d" /* intptr_t */ +#undef PRIiPTR /* intptr_t */ +#define PRIiPTR "i" /* intptr_t */ +#undef PRIoPTR /* uintptr_t */ +#define PRIoPTR "o" /* uintptr_t */ +#undef PRIuPTR /* uintptr_t */ +#define PRIuPTR "u" /* uintptr_t */ +#undef PRIxPTR /* uintptr_t */ +#define PRIxPTR "x" /* uintptr_t */ +#undef PRIXPTR /* uintptr_t */ +#define PRIXPTR "X" /* uintptr_t */ #endif -#endif /* mozilla_IntegerPrintfMacros_h_ */ +/* + * Fix up Android's broken macros for [u]int_fastN_t. On ARM64, Android's + * PRI*FAST16/32 macros are defined as "d", but the types themselves are defined + * as long and unsigned long. + */ +#if defined(ANDROID) && defined(__LP64__) +#undef PRIdFAST16 /* int_fast16_t */ +#define PRIdFAST16 PRId64 /* int_fast16_t */ +#undef PRIiFAST16 /* int_fast16_t */ +#define PRIiFAST16 PRIi64 /* int_fast16_t */ +#undef PRIoFAST16 /* uint_fast16_t */ +#define PRIoFAST16 PRIo64 /* uint_fast16_t */ +#undef PRIuFAST16 /* uint_fast16_t */ +#define PRIuFAST16 PRIu64 /* uint_fast16_t */ +#undef PRIxFAST16 /* uint_fast16_t */ +#define PRIxFAST16 PRIx64 /* uint_fast16_t */ +#undef PRIXFAST16 /* uint_fast16_t */ +#define PRIXFAST16 PRIX64 /* uint_fast16_t */ +#undef PRIdFAST32 /* int_fast32_t */ +#define PRIdFAST32 PRId64 /* int_fast32_t */ +#undef PRIiFAST32 /* int_fast32_t */ +#define PRIiFAST32 PRIi64 /* int_fast32_t */ +#undef PRIoFAST32 /* uint_fast32_t */ +#define PRIoFAST32 PRIo64 /* uint_fast32_t */ +#undef PRIuFAST32 /* uint_fast32_t */ +#define PRIuFAST32 PRIu64 /* uint_fast32_t */ +#undef PRIxFAST32 /* uint_fast32_t */ +#define PRIxFAST32 PRIx64 /* uint_fast32_t */ +#undef PRIXFAST32 /* uint_fast32_t */ +#define PRIXFAST32 PRIX64 /* uint_fast32_t */ +#endif + +#endif /* mozilla_IntegerPrintfMacros_h_ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/IntegerRange.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/IntegerRange.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/IntegerRange.h @@ -17,110 +17,113 @@ namespace detail { -template -class IntegerIterator -{ -public: - template - explicit IntegerIterator(IntType aCurrent) - : mCurrent(aCurrent) { } +template +class IntegerIterator { + public: + template + explicit IntegerIterator(IntType aCurrent) : mCurrent(aCurrent) {} - template + template explicit IntegerIterator(const IntegerIterator& aOther) - : mCurrent(aOther.mCurrent) { } + : mCurrent(aOther.mCurrent) {} IntTypeT operator*() const { return mCurrent; } /* Increment and decrement operators */ - IntegerIterator& operator++() { ++mCurrent; return *this; } - IntegerIterator& operator--() { --mCurrent; return *this; } - IntegerIterator operator++(int) { auto ret = *this; ++mCurrent; return ret; } - IntegerIterator operator--(int) { auto ret = *this; --mCurrent; return ret; } + IntegerIterator& operator++() { + ++mCurrent; + return *this; + } + IntegerIterator& operator--() { + --mCurrent; + return *this; + } + IntegerIterator operator++(int) { + auto ret = *this; + ++mCurrent; + return ret; + } + IntegerIterator operator--(int) { + auto ret = *this; + --mCurrent; + return ret; + } /* Comparison operators */ - template + template friend bool operator==(const IntegerIterator& aIter1, const IntegerIterator& aIter2); - template + template friend bool operator!=(const IntegerIterator& aIter1, const IntegerIterator& aIter2); - template + template friend bool operator<(const IntegerIterator& aIter1, const IntegerIterator& aIter2); - template + template friend bool operator<=(const IntegerIterator& aIter1, const IntegerIterator& aIter2); - template + template friend bool operator>(const IntegerIterator& aIter1, const IntegerIterator& aIter2); - template + template friend bool operator>=(const IntegerIterator& aIter1, const IntegerIterator& aIter2); -private: + private: IntTypeT mCurrent; }; -template +template bool operator==(const IntegerIterator& aIter1, - const IntegerIterator& aIter2) -{ + const IntegerIterator& aIter2) { return aIter1.mCurrent == aIter2.mCurrent; } -template +template bool operator!=(const IntegerIterator& aIter1, - const IntegerIterator& aIter2) -{ + const IntegerIterator& aIter2) { return aIter1.mCurrent != aIter2.mCurrent; } -template +template bool operator<(const IntegerIterator& aIter1, - const IntegerIterator& aIter2) -{ + const IntegerIterator& aIter2) { return aIter1.mCurrent < aIter2.mCurrent; } -template +template bool operator<=(const IntegerIterator& aIter1, - const IntegerIterator& aIter2) -{ + const IntegerIterator& aIter2) { return aIter1.mCurrent <= aIter2.mCurrent; } -template +template bool operator>(const IntegerIterator& aIter1, - const IntegerIterator& aIter2) -{ + const IntegerIterator& aIter2) { return aIter1.mCurrent > aIter2.mCurrent; } -template +template bool operator>=(const IntegerIterator& aIter1, - const IntegerIterator& aIter2) -{ + const IntegerIterator& aIter2) { return aIter1.mCurrent >= aIter2.mCurrent; } -template -class IntegerRange -{ -public: +template +class IntegerRange { + public: typedef IntegerIterator iterator; typedef IntegerIterator const_iterator; typedef ReverseIterator> reverse_iterator; typedef ReverseIterator> const_reverse_iterator; - template - explicit IntegerRange(IntType aEnd) - : mBegin(0), mEnd(aEnd) { } - - template - IntegerRange(IntType1 aBegin, IntType2 aEnd) - : mBegin(aBegin), mEnd(aEnd) { } + template + explicit IntegerRange(IntType aEnd) : mBegin(0), mEnd(aEnd) {} + + template + IntegerRange(IntType1 aBegin, IntType2 aEnd) : mBegin(aBegin), mEnd(aEnd) {} iterator begin() const { return iterator(mBegin); } const_iterator cbegin() const { return begin(); } @@ -131,43 +134,33 @@ reverse_iterator rend() const { return reverse_iterator(mBegin); } const_reverse_iterator crend() const { return rend(); } -private: + private: IntTypeT mBegin; IntTypeT mEnd; }; -template::value> -struct GeqZero -{ - static bool check(T t) { - return t >= 0; - } +template ::value> +struct GeqZero { + static bool check(T t) { return t >= 0; } }; -template -struct GeqZero -{ - static bool check(T t) { - return true; - } +template +struct GeqZero { + static bool check(T t) { return true; } }; -} // namespace detail +} // namespace detail -template -detail::IntegerRange -MakeRange(IntType aEnd) -{ +template +detail::IntegerRange IntegerRange(IntType aEnd) { static_assert(IsIntegral::value, "value must be integral"); MOZ_ASSERT(detail::GeqZero::check(aEnd), "Should never have negative value here"); return detail::IntegerRange(aEnd); } -template -detail::IntegerRange -MakeRange(IntType1 aBegin, IntType2 aEnd) -{ +template +detail::IntegerRange IntegerRange(IntType1 aBegin, IntType2 aEnd) { static_assert(IsIntegral::value && IsIntegral::value, "values must both be integral"); static_assert(IsSigned::value == IsSigned::value, @@ -176,6 +169,6 @@ return detail::IntegerRange(aBegin, aEnd); } -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_IntegerRange_h +#endif // mozilla_IntegerRange_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/IntegerTypeTraits.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/IntegerTypeTraits.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/IntegerTypeTraits.h @@ -21,72 +21,61 @@ * of given size (can be 1, 2, 4 or 8) and given signedness * (false means unsigned, true means signed). */ -template +template struct StdintTypeForSizeAndSignedness; -template<> -struct StdintTypeForSizeAndSignedness<1, true> -{ +template <> +struct StdintTypeForSizeAndSignedness<1, true> { typedef int8_t Type; }; -template<> -struct StdintTypeForSizeAndSignedness<1, false> -{ +template <> +struct StdintTypeForSizeAndSignedness<1, false> { typedef uint8_t Type; }; -template<> -struct StdintTypeForSizeAndSignedness<2, true> -{ +template <> +struct StdintTypeForSizeAndSignedness<2, true> { typedef int16_t Type; }; -template<> -struct StdintTypeForSizeAndSignedness<2, false> -{ +template <> +struct StdintTypeForSizeAndSignedness<2, false> { typedef uint16_t Type; }; -template<> -struct StdintTypeForSizeAndSignedness<4, true> -{ +template <> +struct StdintTypeForSizeAndSignedness<4, true> { typedef int32_t Type; }; -template<> -struct StdintTypeForSizeAndSignedness<4, false> -{ +template <> +struct StdintTypeForSizeAndSignedness<4, false> { typedef uint32_t Type; }; -template<> -struct StdintTypeForSizeAndSignedness<8, true> -{ +template <> +struct StdintTypeForSizeAndSignedness<8, true> { typedef int64_t Type; }; -template<> -struct StdintTypeForSizeAndSignedness<8, false> -{ +template <> +struct StdintTypeForSizeAndSignedness<8, false> { typedef uint64_t Type; }; -} // namespace detail +} // namespace detail -template +template struct UnsignedStdintTypeForSize - : detail::StdintTypeForSizeAndSignedness -{}; + : detail::StdintTypeForSizeAndSignedness {}; -template +template struct SignedStdintTypeForSize - : detail::StdintTypeForSizeAndSignedness -{}; + : detail::StdintTypeForSizeAndSignedness {}; -template -struct PositionOfSignBit -{ +template +struct PositionOfSignBit { static_assert(IsIntegral::value, "PositionOfSignBit is only for integral types"); // 8 here should be CHAR_BIT from limits.h, but the world has moved on. @@ -98,17 +87,16 @@ * compile-time constant, which std::numeric_limits::min() * cannot do in c++98. */ -template -struct MinValue -{ -private: +template +struct MinValue { + private: static_assert(IsIntegral::value, "MinValue is only for integral types"); typedef typename MakeUnsigned::Type UnsignedIntegerType; static const size_t PosOfSignBit = PositionOfSignBit::value; -public: + public: // Bitwise ops may return a larger type, that's why we cast explicitly. // In C++, left bit shifts on signed values is undefined by the standard // unless the shifted value is representable. @@ -117,8 +105,8 @@ // unsigned-to-signed is only well-defined if the value is representable. static const IntegerType value = IsSigned::value - ? IntegerType(UnsignedIntegerType(1) << PosOfSignBit) - : IntegerType(0); + ? IntegerType(UnsignedIntegerType(1) << PosOfSignBit) + : IntegerType(0); }; /** @@ -126,9 +114,8 @@ * compile-time constant, which std::numeric_limits::max() * cannot do in c++98. */ -template -struct MaxValue -{ +template +struct MaxValue { static_assert(IsIntegral::value, "MaxValue is only for integral types"); @@ -138,6 +125,6 @@ static const IntegerType value = ~MinValue::value; }; -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_IntegerTypeTraits_h +#endif // mozilla_IntegerTypeTraits_h 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 @@ -92,7 +92,7 @@ #ifndef mozilla_JSONWriter_h #define mozilla_JSONWriter_h -#include "mozilla/double-conversion.h" +#include "double-conversion/double-conversion.h" #include "mozilla/IntegerPrintfMacros.h" #include "mozilla/PodOperations.h" #include "mozilla/Sprintf.h" @@ -106,9 +106,8 @@ // A quasi-functor for JSONWriter. We don't use a true functor because that // requires templatizing JSONWriter, and the templatization seeps to lots of // places we don't want it to. -class JSONWriteFunc -{ -public: +class JSONWriteFunc { + public: virtual void Write(const char* aStr) = 0; virtual ~JSONWriteFunc() {} }; @@ -117,10 +116,9 @@ // on Linux that caused link errors, whereas this formulation didn't. namespace detail { extern MFBT_DATA const char gTwoCharEscapes[256]; -} // namespace detail +} // namespace detail -class JSONWriter -{ +class JSONWriter { // From http://www.ietf.org/rfc/rfc4627.txt: // // "All Unicode characters may be placed within the quotation marks except @@ -134,8 +132,7 @@ // All control characters not in the above list are represented with a // six-char escape sequence, e.g. '\u000b' (a.k.a. '\v'). // - class EscapedString - { + class EscapedString { // Only one of |mUnownedStr| and |mOwnedStr| are ever non-null. |mIsOwned| // indicates which one is in use. They're not within a union because that // wouldn't work with UniquePtr. @@ -143,30 +140,26 @@ const char* mUnownedStr; UniquePtr mOwnedStr; - void SanityCheck() const - { - MOZ_ASSERT_IF( mIsOwned, mOwnedStr.get() && !mUnownedStr); - MOZ_ASSERT_IF(!mIsOwned, !mOwnedStr.get() && mUnownedStr); + void SanityCheck() const { + MOZ_ASSERT_IF(mIsOwned, mOwnedStr.get() && !mUnownedStr); + MOZ_ASSERT_IF(!mIsOwned, !mOwnedStr.get() && mUnownedStr); } - static char hexDigitToAsciiChar(uint8_t u) - { + static char hexDigitToAsciiChar(uint8_t u) { u = u & 0xf; return u < 10 ? '0' + u : 'a' + (u - 10); } - public: + public: explicit EscapedString(const char* aStr) - : mUnownedStr(nullptr) - , mOwnedStr(nullptr) - { + : mUnownedStr(nullptr), mOwnedStr(nullptr) { const char* p; // First, see if we need to modify the string. size_t nExtra = 0; p = aStr; while (true) { - uint8_t u = *p; // ensure it can't be interpreted as negative + uint8_t u = *p; // ensure it can't be interpreted as negative if (u == 0) { break; } @@ -194,7 +187,7 @@ size_t i = 0; while (true) { - uint8_t u = *p; // ensure it can't be interpreted as negative + uint8_t u = *p; // ensure it can't be interpreted as negative if (u == 0) { mOwnedStr[i] = 0; break; @@ -216,37 +209,32 @@ } } - ~EscapedString() - { - SanityCheck(); - } + ~EscapedString() { SanityCheck(); } - const char* get() const - { + const char* get() const { SanityCheck(); return mIsOwned ? mOwnedStr.get() : mUnownedStr; } }; -public: + public: // Collections (objects and arrays) are printed in a multi-line style by // default. This can be changed to a single-line style if SingleLineStyle is // specified. If a collection is printed in single-line style, every nested // collection within it is also printed in single-line style, even if // multi-line style is requested. enum CollectionStyle { - MultiLineStyle, // the default + MultiLineStyle, // the default SingleLineStyle }; -protected: + protected: const UniquePtr mWriter; Vector mNeedComma; // do we need a comma at depth N? Vector mNeedNewlines; // do we need newlines at depth N? size_t mDepth; // the current nesting depth - void Indent() - { + void Indent() { for (size_t i = 0; i < mDepth; i++) { mWriter->Write(" "); } @@ -255,8 +243,7 @@ // Adds whatever is necessary (maybe a comma, and then a newline and // whitespace) to separate an item (property or element) from what's come // before. - void Separator() - { + void Separator() { if (mNeedComma[mDepth]) { mWriter->Write(","); } @@ -268,16 +255,14 @@ } } - void PropertyNameAndColon(const char* aName) - { + void PropertyNameAndColon(const char* aName) { EscapedString escapedName(aName); mWriter->Write("\""); mWriter->Write(escapedName.get()); mWriter->Write("\": "); } - void Scalar(const char* aMaybePropertyName, const char* aStringValue) - { + void Scalar(const char* aMaybePropertyName, const char* aStringValue) { Separator(); if (aMaybePropertyName) { PropertyNameAndColon(aMaybePropertyName); @@ -286,8 +271,7 @@ mNeedComma[mDepth] = true; } - void QuotedScalar(const char* aMaybePropertyName, const char* aStringValue) - { + void QuotedScalar(const char* aMaybePropertyName, const char* aStringValue) { Separator(); if (aMaybePropertyName) { PropertyNameAndColon(aMaybePropertyName); @@ -298,8 +282,7 @@ mNeedComma[mDepth] = true; } - void NewVectorEntries() - { + void NewVectorEntries() { // If these tiny allocations OOM we might as well just crash because we // must be in serious memory trouble. MOZ_RELEASE_ASSERT(mNeedComma.resizeUninitialized(mDepth + 1)); @@ -309,8 +292,7 @@ } void StartCollection(const char* aMaybePropertyName, const char* aStartChar, - CollectionStyle aStyle = MultiLineStyle) - { + CollectionStyle aStyle = MultiLineStyle) { Separator(); if (aMaybePropertyName) { mWriter->Write("\""); @@ -322,12 +304,11 @@ mDepth++; NewVectorEntries(); mNeedNewlines[mDepth] = - mNeedNewlines[mDepth - 1] && aStyle == MultiLineStyle; + mNeedNewlines[mDepth - 1] && aStyle == MultiLineStyle; } // Adds the whitespace and closing char necessary to end a collection. - void EndCollection(const char* aEndChar) - { + void EndCollection(const char* aEndChar) { if (mNeedNewlines[mDepth]) { mWriter->Write("\n"); mDepth--; @@ -338,13 +319,9 @@ mWriter->Write(aEndChar); } -public: + public: explicit JSONWriter(UniquePtr aWriter) - : mWriter(Move(aWriter)) - , mNeedComma() - , mNeedNewlines() - , mDepth(0) - { + : mWriter(Move(aWriter)), mNeedComma(), mNeedNewlines(), mDepth(0) { NewVectorEntries(); } @@ -359,8 +336,7 @@ // All property names and string properties are escaped as necessary. // Prints: { - void Start(CollectionStyle aStyle = MultiLineStyle) - { + void Start(CollectionStyle aStyle = MultiLineStyle) { StartCollection(nullptr, "{", aStyle); } @@ -368,17 +344,13 @@ void End() { EndCollection("}\n"); } // Prints: "": null - void NullProperty(const char* aName) - { - Scalar(aName, "null"); - } + void NullProperty(const char* aName) { Scalar(aName, "null"); } // Prints: null void NullElement() { NullProperty(nullptr); } // Prints: "": - void BoolProperty(const char* aName, bool aBool) - { + void BoolProperty(const char* aName, bool aBool) { Scalar(aName, aBool ? "true" : "false"); } @@ -386,8 +358,7 @@ void BoolElement(bool aBool) { BoolProperty(nullptr, aBool); } // Prints: "": - void IntProperty(const char* aName, int64_t aInt) - { + void IntProperty(const char* aName, int64_t aInt) { char buf[64]; SprintfLiteral(buf, "%" PRId64, aInt); Scalar(aName, buf); @@ -397,12 +368,11 @@ void IntElement(int64_t aInt) { IntProperty(nullptr, aInt); } // Prints: "": - void DoubleProperty(const char* aName, double aDouble) - { + void DoubleProperty(const char* aName, double aDouble) { static const size_t buflen = 64; char buf[buflen]; - const double_conversion::DoubleToStringConverter &converter = - double_conversion::DoubleToStringConverter::EcmaScriptConverter(); + const double_conversion::DoubleToStringConverter& converter = + double_conversion::DoubleToStringConverter::EcmaScriptConverter(); double_conversion::StringBuilder builder(buf, buflen); converter.ToShortest(aDouble, &builder); Scalar(aName, builder.Finalize()); @@ -412,8 +382,7 @@ void DoubleElement(double aDouble) { DoubleProperty(nullptr, aDouble); } // Prints: "": "" - void StringProperty(const char* aName, const char* aStr) - { + void StringProperty(const char* aName, const char* aStr) { EscapedString escapedStr(aStr); QuotedScalar(aName, escapedStr.get()); } @@ -423,14 +392,12 @@ // Prints: "": [ void StartArrayProperty(const char* aName, - CollectionStyle aStyle = MultiLineStyle) - { + CollectionStyle aStyle = MultiLineStyle) { StartCollection(aName, "[", aStyle); } // Prints: [ - void StartArrayElement(CollectionStyle aStyle = MultiLineStyle) - { + void StartArrayElement(CollectionStyle aStyle = MultiLineStyle) { StartArrayProperty(nullptr, aStyle); } @@ -439,14 +406,12 @@ // Prints: "": { void StartObjectProperty(const char* aName, - CollectionStyle aStyle = MultiLineStyle) - { + CollectionStyle aStyle = MultiLineStyle) { StartCollection(aName, "{", aStyle); } // Prints: { - void StartObjectElement(CollectionStyle aStyle = MultiLineStyle) - { + void StartObjectElement(CollectionStyle aStyle = MultiLineStyle) { StartObjectProperty(nullptr, aStyle); } @@ -454,7 +419,6 @@ void EndObject() { EndCollection("}"); } }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_JSONWriter_h */ - Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Likely.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Likely.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Likely.h @@ -13,11 +13,11 @@ #define mozilla_Likely_h #if defined(__clang__) || defined(__GNUC__) -# define MOZ_LIKELY(x) (__builtin_expect(!!(x), 1)) -# define MOZ_UNLIKELY(x) (__builtin_expect(!!(x), 0)) +#define MOZ_LIKELY(x) (__builtin_expect(!!(x), 1)) +#define MOZ_UNLIKELY(x) (__builtin_expect(!!(x), 0)) #else -# define MOZ_LIKELY(x) (!!(x)) -# define MOZ_UNLIKELY(x) (!!(x)) +#define MOZ_LIKELY(x) (!!(x)) +#define MOZ_UNLIKELY(x) (!!(x)) #endif #endif /* mozilla_Likely_h */ 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 @@ -74,7 +74,7 @@ namespace mozilla { -template +template class LinkedListElement; namespace detail { @@ -84,9 +84,8 @@ * 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 -{ +template +struct LinkedListElementTraits { typedef T* RawType; typedef const T* ConstRawType; typedef T* ClientType; @@ -101,26 +100,28 @@ static void exitList(LinkedListElement* elt) {} }; -template -struct LinkedListElementTraits> -{ +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(); } + static void enterList(LinkedListElement>* elt) { + elt->asT()->AddRef(); + } + static void exitList(LinkedListElement>* elt) { + elt->asT()->Release(); + } }; } /* namespace detail */ -template +template class LinkedList; -template -class LinkedListElement -{ +template +class LinkedListElement { typedef typename detail::LinkedListElementTraits Traits; typedef typename Traits::RawType RawType; typedef typename Traits::ConstRawType ConstRawType; @@ -161,30 +162,24 @@ * lists, and supporting this painlessly was a key design criterion. */ -private: + private: LinkedListElement* mNext; LinkedListElement* mPrev; const bool mIsSentinel; -public: - LinkedListElement() - : mNext(this), - mPrev(this), - mIsSentinel(false) - { } + public: + LinkedListElement() : mNext(this), mPrev(this), mIsSentinel(false) {} /* * 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) - { + : mIsSentinel(aOther.mIsSentinel) { adjustLinkForMove(Move(aOther)); } - LinkedListElement& operator=(LinkedListElement&& aOther) - { + 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!"); @@ -192,8 +187,7 @@ return *this; } - ~LinkedListElement() - { + ~LinkedListElement() { if (!mIsSentinel && isInList()) { remove(); } @@ -203,22 +197,21 @@ * Get the next element in the list, or nullptr if this is the last element * in the list. */ - RawType getNext() { 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. */ - RawType getPrevious() { 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(RawType aElem) - { + void setNext(RawType aElem) { MOZ_ASSERT(isInList()); setNextUnsafe(aElem); } @@ -228,8 +221,7 @@ * linked list when you call setPrevious(); otherwise, this method will * assert. */ - void setPrevious(RawType aElem) - { + void setPrevious(RawType aElem) { MOZ_ASSERT(isInList()); setPreviousUnsafe(aElem); } @@ -238,8 +230,7 @@ * Remove this element from the list which contains it. If this element is * not currently part of a linked list, this method asserts. */ - void remove() - { + void remove() { MOZ_ASSERT(isInList()); mPrev->mNext = mNext; @@ -253,11 +244,11 @@ /* * 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. + * asserts if the element does not belong to a list. Note: In a refcounted + * list, |this| may be destroyed. */ - ClientType removeAndGetNext() - { - ClientType r = getNext(); + RawType removeAndGetNext() { + RawType r = getNext(); remove(); return r; } @@ -265,11 +256,11 @@ /* * 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. + * asserts if the element does not belong to a list. Note: In a refcounted + * list, |this| may be destroyed. */ - ClientType removeAndGetPrevious() - { - ClientType r = getPrevious(); + RawType removeAndGetPrevious() { + RawType r = getPrevious(); remove(); return r; } @@ -278,8 +269,7 @@ * Identical to remove(), but also asserts in debug builds that this element * is in aList. */ - void removeFrom(const LinkedList& aList) - { + void removeFrom(const LinkedList& aList) { aList.assertContains(asT()); remove(); } @@ -287,37 +277,26 @@ /* * Return true if |this| part is of a linked list, and false otherwise. */ - bool isInList() const - { + bool isInList() const { MOZ_ASSERT((mNext == this) == (mPrev == this)); return mNext != this; } -private: + private: friend class LinkedList; friend struct detail::LinkedListElementTraits; - enum class NodeKind { - Normal, - Sentinel - }; + enum class NodeKind { Normal, Sentinel }; explicit LinkedListElement(NodeKind nodeKind) - : mNext(this), - mPrev(this), - mIsSentinel(nodeKind == NodeKind::Sentinel) - { } + : mNext(this), mPrev(this), mIsSentinel(nodeKind == NodeKind::Sentinel) {} /* * Return |this| cast to T* if we're a normal node, or return nullptr if * we're a sentinel node. */ - RawType asT() - { - return mIsSentinel ? nullptr : static_cast(this); - } - ConstRawType asT() const - { + RawType asT() { return mIsSentinel ? nullptr : static_cast(this); } + ConstRawType asT() const { return mIsSentinel ? nullptr : static_cast(this); } @@ -325,9 +304,8 @@ * Insert aElem after this element, but don't check that this element is in * the list. This is called by LinkedList::insertFront(). */ - void setNextUnsafe(RawType aElem) - { - LinkedListElement *listElem = static_cast(aElem); + void setNextUnsafe(RawType aElem) { + LinkedListElement* listElem = static_cast(aElem); MOZ_ASSERT(!listElem->isInList()); listElem->mNext = this->mNext; @@ -342,8 +320,7 @@ * Insert aElem before this element, but don't check that this element is in * the list. This is called by LinkedList::insertBack(). */ - void setPreviousUnsafe(RawType aElem) - { + void setPreviousUnsafe(RawType aElem) { LinkedListElement* listElem = static_cast*>(aElem); MOZ_ASSERT(!listElem->isInList()); @@ -359,8 +336,7 @@ * Adjust mNext and mPrev for implementing move constructor and move * assignment. */ - void adjustLinkForMove(LinkedListElement&& aOther) - { + void adjustLinkForMove(LinkedListElement&& aOther) { if (!aOther.isInList()) { mNext = this; mPrev = this; @@ -400,10 +376,9 @@ LinkedListElement(const LinkedListElement& aOther) = delete; }; -template -class LinkedList -{ -private: +template +class LinkedList { + private: typedef typename detail::LinkedListElementTraits Traits; typedef typename Traits::RawType RawType; typedef typename Traits::ConstRawType ConstRawType; @@ -412,16 +387,14 @@ LinkedListElement sentinel; -public: + public: class Iterator { RawType mCurrent; - public: + public: explicit Iterator(RawType aCurrent) : mCurrent(aCurrent) {} - RawType operator *() const { - return mCurrent; - } + RawType operator*() const { return mCurrent; } const Iterator& operator++() { mCurrent = mCurrent->getNext(); @@ -433,15 +406,14 @@ } }; - LinkedList() : sentinel(LinkedListElement::NodeKind::Sentinel) { } + LinkedList() : sentinel(LinkedListElement::NodeKind::Sentinel) {} LinkedList(LinkedList&& aOther) - : sentinel(mozilla::Move(aOther.sentinel)) - { } + : sentinel(mozilla::Move(aOther.sentinel)) {} - LinkedList& operator=(LinkedList&& aOther) - { - MOZ_ASSERT(isEmpty(), "Assigning to a non-empty list leaks elements in that list!"); + 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; } @@ -456,8 +428,7 @@ /* * Add aElem to the front of the list. */ - void insertFront(RawType aElem) - { + void insertFront(RawType aElem) { /* Bypass setNext()'s this->isInList() assertion. */ sentinel.setNextUnsafe(aElem); } @@ -465,29 +436,25 @@ /* * Add aElem to the back of the list. */ - void insertBack(RawType aElem) - { - sentinel.setPreviousUnsafe(aElem); - } + void insertBack(RawType aElem) { sentinel.setPreviousUnsafe(aElem); } /* * Get the first element of the list, or nullptr if the list is empty. */ - RawType getFirst() { 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. */ - RawType getLast() { 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. */ - ClientType popFirst() - { + ClientType popFirst() { ClientType ret = sentinel.getNext(); if (ret) { static_cast*>(RawType(ret))->remove(); @@ -499,8 +466,7 @@ * Get and remove the last element of the list. If the list is empty, * return nullptr. */ - ClientType popLast() - { + ClientType popLast() { ClientType ret = sentinel.getPrevious(); if (ret) { static_cast*>(RawType(ret))->remove(); @@ -511,10 +477,7 @@ /* * Return true if the list is empty, or false otherwise. */ - bool isEmpty() const - { - return !sentinel.isInList(); - } + bool isEmpty() const { return !sentinel.isInList(); } /* * Remove all the elements from the list. @@ -522,10 +485,8 @@ * This runs in time linear to the list's length, because we have to mark * each element as not in the list. */ - void clear() - { + void clear() { while (popFirst()) { - continue; } } @@ -534,12 +495,8 @@ * * for (MyElementType* elt : myList) { ... } */ - Iterator begin() { - return Iterator(getFirst()); - } - Iterator end() { - return Iterator(nullptr); - } + Iterator begin() { return Iterator(getFirst()); } + Iterator end() { return Iterator(nullptr); } /* * Measures the memory consumption of the list excluding |this|. Note that @@ -547,10 +504,9 @@ * contain pointers to other memory blocks, those blocks must be measured * separately during a subsequent iteration over the list. */ - size_t sizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const - { + size_t sizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { size_t n = 0; - for (const T* t = getFirst(); t; t = t->getNext()) { + for (ConstRawType t = getFirst(); t; t = t->getNext()) { n += aMallocSizeOf(t); } return n; @@ -559,8 +515,7 @@ /* * Like sizeOfExcludingThis(), but measures |this| as well. */ - size_t sizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const - { + size_t sizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { return aMallocSizeOf(this) + sizeOfExcludingThis(aMallocSizeOf); } @@ -568,8 +523,7 @@ * In a debug build, make sure that the list is sane (no cycles, consistent * mNext/mPrev pointers, only one sentinel). Has no effect in release builds. */ - void debugAssertIsSane() const - { + void debugAssertIsSane() const { #ifdef DEBUG const LinkedListElement* slow; const LinkedListElement* fast1; @@ -579,9 +533,8 @@ * Check for cycles in the forward singly-linked list using the * tortoise/hare algorithm. */ - for (slow = sentinel.mNext, - fast1 = sentinel.mNext->mNext, - fast2 = sentinel.mNext->mNext->mNext; + for (slow = sentinel.mNext, fast1 = sentinel.mNext->mNext, + fast2 = sentinel.mNext->mNext->mNext; slow != &sentinel && fast1 != &sentinel && fast2 != &sentinel; slow = slow->mNext, fast1 = fast2->mNext, fast2 = fast1->mNext) { MOZ_ASSERT(slow != fast1); @@ -589,9 +542,8 @@ } /* Check for cycles in the backward singly-linked list. */ - for (slow = sentinel.mPrev, - fast1 = sentinel.mPrev->mPrev, - fast2 = sentinel.mPrev->mPrev->mPrev; + for (slow = sentinel.mPrev, fast1 = sentinel.mPrev->mPrev, + fast2 = sentinel.mPrev->mPrev->mPrev; slow != &sentinel && fast1 != &sentinel && fast2 != &sentinel; slow = slow->mPrev, fast1 = fast2->mPrev, fast2 = fast1->mPrev) { MOZ_ASSERT(slow != fast1); @@ -602,8 +554,7 @@ * Check that |sentinel| is the only node in the list with * mIsSentinel == true. */ - for (const LinkedListElement* elem = sentinel.mNext; - elem != &sentinel; + for (const LinkedListElement* elem = sentinel.mNext; elem != &sentinel; elem = elem->mNext) { MOZ_ASSERT(!elem->mIsSentinel); } @@ -612,20 +563,19 @@ const LinkedListElement* prev = &sentinel; const LinkedListElement* cur = sentinel.mNext; do { - MOZ_ASSERT(cur->mPrev == prev); - MOZ_ASSERT(prev->mNext == cur); + MOZ_ASSERT(cur->mPrev == prev); + MOZ_ASSERT(prev->mNext == cur); - prev = cur; - cur = cur->mNext; + prev = cur; + cur = cur->mNext; } while (cur != &sentinel); #endif /* ifdef DEBUG */ } -private: + private: friend class LinkedListElement; - void assertContains(const RawType aValue) const - { + void assertContains(const RawType aValue) const { #ifdef DEBUG for (ConstRawType elem = getFirst(); elem; elem = elem->getNext()) { if (elem == aValue) { @@ -641,11 +591,16 @@ }; template -class AutoCleanLinkedList : public LinkedList -{ -public: - ~AutoCleanLinkedList() - { +class AutoCleanLinkedList : public LinkedList { + public: + ~AutoCleanLinkedList() { clear(); } + + AutoCleanLinkedList& operator=(AutoCleanLinkedList&& aOther) { + LinkedList::operator=(Forward>(aOther)); + return *this; + } + + void clear() { while (T* element = this->popFirst()) { delete element; } 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 @@ -12,84 +12,65 @@ #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_CONCAT2(x, y) x##y #define MOZ_CONCAT(x, y) MOZ_CONCAT2(x, y) /* + * MOZ_ARG_COUNT(...) counts the number of variadic arguments. + * You must pass in between 0 and 50 (inclusive) variadic arguments. + * For example: + * + * MOZ_ARG_COUNT() expands to 0 + * MOZ_ARG_COUNT(a) expands to 1 + * MOZ_ARG_COUNT(a, b) expands to 2 + * + * Implementation notes: + * The `##__VA_ARGS__` form is a GCC extension that removes the comma if + * __VA_ARGS__ is empty. It is supported by Clang too. MSVC ignores ##, + * and its default behavior is already to strip the comma when __VA_ARGS__ + * is empty. + * + * So MOZ_MACROARGS_ARG_COUNT_HELPER() expands to + * (_, 50, 49, ...) + * MOZ_MACROARGS_ARG_COUNT_HELPER(a) expands to + * (_, a, 50, 49, ...) + * etc. + */ +#define MOZ_ARG_COUNT(...) \ + MOZ_MACROARGS_ARG_COUNT_HELPER2(MOZ_MACROARGS_ARG_COUNT_HELPER(__VA_ARGS__)) + +#define MOZ_MACROARGS_ARG_COUNT_HELPER(...) \ + (_, ##__VA_ARGS__, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, \ + 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, \ + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + +#define MOZ_MACROARGS_ARG_COUNT_HELPER2(aArgs) \ + MOZ_MACROARGS_ARG_COUNT_HELPER3 aArgs + +#define MOZ_MACROARGS_ARG_COUNT_HELPER3( \ + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, \ + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, \ + a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, \ + a47, a48, a49, a50, a51, ...) \ + a51 + +/* * MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) counts the number of variadic * arguments and prefixes it with |aPrefix|. For example: * * MOZ_PASTE_PREFIX_AND_ARG_COUNT(, foo, 42) expands to 2 * MOZ_PASTE_PREFIX_AND_ARG_COUNT(A, foo, 42, bar) expands to A3 + * MOZ_PASTE_PREFIX_AND_ARG_COUNT(A) expands to A0 + * MOZ_PASTE_PREFIX_AND_ARG_COUNT() expands to 0, but MSVC warns there + * aren't enough arguments given. * - * You must pass in between 1 and 50 (inclusive) variadic arguments, past - * |aPrefix|. It is not legal to do - * - * MOZ_PASTE_PREFIX_AND_ARG_COUNT(prefix) - * - * (that is, pass in 0 variadic arguments). To ensure that a compile-time - * error occurs when these constraints are violated, use the - * MOZ_STATIC_ASSERT_VALID_ARG_COUNT macro with the same variaidc arguments - * wherever this macro is used. - * - * Passing (__VA_ARGS__, ) rather than simply calling - * MOZ_MACROARGS_ARG_COUNT_HELPER2(__VA_ARGS__, ) very - * carefully tiptoes around a MSVC bug where it improperly expands __VA_ARGS__ - * as a single token in argument lists. For details, see: - * - * http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement - * http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644 + * You must pass in between 0 and 50 (inclusive) variadic arguments, past + * |aPrefix|. */ +#define MOZ_PASTE_PREFIX_AND_ARG_COUNT_GLUE(a, b) a b #define MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) \ - MOZ_MACROARGS_ARG_COUNT_HELPER((__VA_ARGS__, \ - aPrefix##50, aPrefix##49, aPrefix##48, aPrefix##47, aPrefix##46, \ - aPrefix##45, aPrefix##44, aPrefix##43, aPrefix##42, aPrefix##41, \ - aPrefix##40, aPrefix##39, aPrefix##38, aPrefix##37, aPrefix##36, \ - aPrefix##35, aPrefix##34, aPrefix##33, aPrefix##32, aPrefix##31, \ - aPrefix##30, aPrefix##29, aPrefix##28, aPrefix##27, aPrefix##26, \ - aPrefix##25, aPrefix##24, aPrefix##23, aPrefix##22, aPrefix##21, \ - aPrefix##20, aPrefix##19, aPrefix##18, aPrefix##17, aPrefix##16, \ - aPrefix##15, aPrefix##14, aPrefix##13, aPrefix##12, aPrefix##11, \ - aPrefix##10, aPrefix##9, aPrefix##8, aPrefix##7, aPrefix##6, \ - aPrefix##5, aPrefix##4, aPrefix##3, aPrefix##2, aPrefix##1, aPrefix##0)) - -#define MOZ_MACROARGS_ARG_COUNT_HELPER(aArgs) \ - MOZ_MACROARGS_ARG_COUNT_HELPER2 aArgs - -#define MOZ_MACROARGS_ARG_COUNT_HELPER2( \ - a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \ - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, \ - a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, \ - a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, \ - a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, \ - a51, ...) a51 - -/* - * MOZ_STATIC_ASSERT_VALID_ARG_COUNT ensures that a compile-time error occurs - * when the argument count constraints of MOZ_PASTE_PREFIX_AND_ARG_COUNT are - * violated. Use this macro wherever MOZ_PASTE_PREFIX_AND_ARG_COUNT is used - * and pass it the same variadic arguments. - * - * This macro employs a few dirty tricks to function. To detect the zero - * argument case, |(__VA_ARGS__)| is stringified, sizeof-ed, and compared to - * what it should be in the absence of arguments. - * - * Detecting too many arguments is a little trickier. With a valid argument - * count and a prefix of 1, MOZ_PASTE_PREFIX_AND_ARG_COUNT expands to e.g. 14. - * With a prefix of 0.0, it expands to e.g. 0.04. If there are too many - * arguments, it expands to the first argument over the limit. If this - * exceeding argument is a number, the assertion will fail as there is no - * number than can simultaneously be both > 10 and == 0. If the exceeding - * argument is not a number, a compile-time error should still occur due to - * the operations performed on it. - */ -#define MOZ_MACROARGS_STRINGIFY_HELPER(x) #x -#define MOZ_STATIC_ASSERT_VALID_ARG_COUNT(...) \ - static_assert( \ - sizeof(MOZ_MACROARGS_STRINGIFY_HELPER((__VA_ARGS__))) != sizeof("()") && \ - (MOZ_PASTE_PREFIX_AND_ARG_COUNT(1, __VA_ARGS__)) > 10 && \ - (int)(MOZ_PASTE_PREFIX_AND_ARG_COUNT(0.0, __VA_ARGS__)) == 0, \ - "MOZ_STATIC_ASSERT_VALID_ARG_COUNT requires 1 to 50 arguments") /* ; */ + MOZ_PASTE_PREFIX_AND_ARG_COUNT_GLUE(MOZ_CONCAT, \ + (aPrefix, MOZ_ARG_COUNT(__VA_ARGS__))) /* * MOZ_ARGS_AFTER_N expands to its arguments excluding the first |N| Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/MacroForEach.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/MacroForEach.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/MacroForEach.h @@ -34,125 +34,186 @@ * int c = MOZ_FOR_EACH(MACRO_C, (5, 8,), (1, 2)) 0; * // Expands to: MACRO_B(5, 8, 1) MACRO_B(5, 8, 2) 0; * + * MOZ_FOR_EACH_SEPARATED(aMacro, aSeparator, aFixedArgs, aArgs) is identical + * to MOZ_FOR_EACH except that it inserts |aSeparator| between each call to + * the macro. |aSeparator| must be wrapped by parens. For example: + * + * #define MACRO_A(x) x + * int a = MOZ_FOR_EACH_SEPARATED(MACRO_A, (+), (), (1, 2, 3)); + * // Expands to: MACRO_A(1) + MACRO_A(2) + MACRO_A(3); + * // And further to: 1 + 2 + 3 + * + * #define MACRO_B(t, n) t n + * void test(MOZ_FOR_EACH_SEPARATED(MACRO_B, (,), (int,), (a, b))); + * // Expands to: void test(MACRO_B(int, a) , MACRO_B(int, b)); + * // And further to: void test(int a , int b); + * * If the |aFixedArgs| list is not empty, a trailing comma must be included. * - * The |aArgs| list must be not be empty and may be up to 50 items long. Use - * MOZ_STATIC_ASSERT_VALID_ARG_COUNT to ensure that violating this constraint - * results in a compile-time error. + * The |aArgs| list may be up to 50 items long. */ #define MOZ_FOR_EACH_EXPAND_HELPER(...) __VA_ARGS__ #define MOZ_FOR_EACH_GLUE(a, b) a b +#define MOZ_FOR_EACH_SEPARATED(aMacro, aSeparator, aFixedArgs, aArgs) \ + MOZ_FOR_EACH_GLUE(MOZ_PASTE_PREFIX_AND_ARG_COUNT( \ + MOZ_FOR_EACH_, MOZ_FOR_EACH_EXPAND_HELPER aArgs), \ + (aMacro, aSeparator, aFixedArgs, aArgs)) #define MOZ_FOR_EACH(aMacro, aFixedArgs, aArgs) \ - MOZ_FOR_EACH_GLUE( \ - MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_FOR_EACH_, \ - MOZ_FOR_EACH_EXPAND_HELPER aArgs), \ - (aMacro, aFixedArgs, aArgs)) + MOZ_FOR_EACH_SEPARATED(aMacro, (), aFixedArgs, aArgs) #define MOZ_FOR_EACH_HELPER_GLUE(a, b) a b #define MOZ_FOR_EACH_HELPER(aMacro, aFixedArgs, aArgs) \ - MOZ_FOR_EACH_HELPER_GLUE( \ - aMacro, \ - (MOZ_FOR_EACH_EXPAND_HELPER aFixedArgs MOZ_ARG_1 aArgs)) - -#define MOZ_FOR_EACH_1(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) -#define MOZ_FOR_EACH_2(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_1(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_3(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_2(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_4(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_3(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_5(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_4(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_6(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_5(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_7(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_6(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_8(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_7(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_9(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_8(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_10(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_9(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_11(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_10(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_12(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_11(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_13(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_12(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_14(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_13(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_15(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_14(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_16(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_15(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_17(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_16(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_18(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_17(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_19(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_18(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_20(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_19(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_21(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_20(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_22(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_21(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_23(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_22(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_24(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_23(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_25(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_24(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_26(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_25(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_27(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_26(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_28(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_27(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_29(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_28(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_30(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_29(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_31(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_30(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_32(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_31(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_33(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_32(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_34(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_33(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_35(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_34(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_36(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_35(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_37(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_36(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_38(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_37(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_39(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_38(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_40(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_39(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_41(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_40(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_42(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_41(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_43(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_42(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_44(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_43(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_45(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_44(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_46(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_45(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_47(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_46(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_48(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_47(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_49(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_48(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_50(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_49(m, fa, (MOZ_ARGS_AFTER_1 a)) + MOZ_FOR_EACH_HELPER_GLUE( \ + aMacro, (MOZ_FOR_EACH_EXPAND_HELPER aFixedArgs MOZ_ARG_1 aArgs)) + +#define MOZ_FOR_EACH_0(m, s, fa, a) +#define MOZ_FOR_EACH_1(m, s, fa, a) MOZ_FOR_EACH_HELPER(m, fa, a) +#define MOZ_FOR_EACH_2(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_1(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_3(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_2(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_4(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_3(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_5(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_4(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_6(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_5(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_7(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_6(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_8(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_7(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_9(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_8(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_10(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_9(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_11(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_10(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_12(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_11(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_13(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_12(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_14(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_13(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_15(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_14(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_16(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_15(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_17(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_16(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_18(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_17(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_19(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_18(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_20(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_19(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_21(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_20(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_22(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_21(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_23(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_22(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_24(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_23(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_25(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_24(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_26(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_25(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_27(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_26(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_28(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_27(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_29(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_28(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_30(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_29(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_31(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_30(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_32(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_31(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_33(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_32(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_34(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_33(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_35(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_34(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_36(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_35(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_37(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_36(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_38(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_37(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_39(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_38(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_40(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_39(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_41(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_40(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_42(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_41(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_43(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_42(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_44(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_43(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_45(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_44(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_46(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_45(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_47(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_46(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_48(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_47(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_49(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_48(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_50(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_49(m, s, fa, (MOZ_ARGS_AFTER_1 a)) #endif /* mozilla_MacroForEach_h */ 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 @@ -19,10 +19,8 @@ namespace mozilla { // Greatest Common Divisor -template -MOZ_ALWAYS_INLINE IntegerType -EuclidGCD(IntegerType aA, IntegerType aB) -{ +template +MOZ_ALWAYS_INLINE IntegerType EuclidGCD(IntegerType aA, IntegerType aB) { // Euclid's algorithm; O(N) in the worst case. (There are better // ways, but we don't need them for the current use of this algo.) MOZ_ASSERT(aA > IntegerType(0)); @@ -40,36 +38,37 @@ } // Least Common Multiple -template -MOZ_ALWAYS_INLINE IntegerType -EuclidLCM(IntegerType aA, IntegerType aB) -{ +template +MOZ_ALWAYS_INLINE IntegerType EuclidLCM(IntegerType aA, IntegerType aB) { // Divide first to reduce overflow risk. return (aA / EuclidGCD(aA, aB)) * aB; } namespace detail { -template +template struct AllowDeprecatedAbsFixed : FalseType {}; -template<> struct AllowDeprecatedAbsFixed : TrueType {}; -template<> struct AllowDeprecatedAbsFixed : TrueType {}; +template <> +struct AllowDeprecatedAbsFixed : TrueType {}; +template <> +struct AllowDeprecatedAbsFixed : TrueType {}; -template +template struct AllowDeprecatedAbs : AllowDeprecatedAbsFixed {}; -template<> struct AllowDeprecatedAbs : TrueType {}; -template<> struct AllowDeprecatedAbs : TrueType {}; +template <> +struct AllowDeprecatedAbs : TrueType {}; +template <> +struct AllowDeprecatedAbs : TrueType {}; -} // namespace detail +} // namespace detail // DO NOT USE DeprecatedAbs. It exists only until its callers can be converted // to Abs below, and it will be removed when all callers have been changed. -template +template inline typename mozilla::EnableIf::value, T>::Type -DeprecatedAbs(const T aValue) -{ +DeprecatedAbs(const T aValue) { // The absolute value of the smallest possible value of a signed-integer type // won't fit in that type (on twos-complement systems -- and we're blithely // assuming we're on such systems, for the non- types listed above), @@ -80,7 +79,7 @@ // range [0, maxvalue]), doesn't produce maxvalue (because in twos-complement, // (minvalue + 1) == -maxvalue). MOZ_ASSERT(aValue >= 0 || - -(aValue + 1) != T((1ULL << (CHAR_BIT * sizeof(T) - 1)) - 1), + -(aValue + 1) != T((1ULL << (CHAR_BIT * sizeof(T) - 1)) - 1), "You can't negate the smallest possible negative integer!"); return aValue >= 0 ? aValue : -aValue; } @@ -91,72 +90,100 @@ // float/double/long double. Feel free to add overloads for other standard, // signed types if you need them. -template +template struct AbsReturnTypeFixed; -template<> struct AbsReturnTypeFixed { typedef uint8_t Type; }; -template<> struct AbsReturnTypeFixed { typedef uint16_t Type; }; -template<> struct AbsReturnTypeFixed { typedef uint32_t Type; }; -template<> struct AbsReturnTypeFixed { typedef uint64_t Type; }; +template <> +struct AbsReturnTypeFixed { + typedef uint8_t Type; +}; +template <> +struct AbsReturnTypeFixed { + typedef uint16_t Type; +}; +template <> +struct AbsReturnTypeFixed { + typedef uint32_t Type; +}; +template <> +struct AbsReturnTypeFixed { + typedef uint64_t Type; +}; -template +template struct AbsReturnType : AbsReturnTypeFixed {}; -template<> struct AbsReturnType : - EnableIf {}; -template<> struct AbsReturnType { typedef unsigned char Type; }; -template<> struct AbsReturnType { typedef unsigned short Type; }; -template<> struct AbsReturnType { typedef unsigned int Type; }; -template<> struct AbsReturnType { typedef unsigned long Type; }; -template<> struct AbsReturnType { typedef unsigned long long Type; }; -template<> struct AbsReturnType { typedef float Type; }; -template<> struct AbsReturnType { typedef double Type; }; -template<> struct AbsReturnType { typedef long double Type; }; - -} // namespace detail - -template -inline typename detail::AbsReturnType::Type -Abs(const T aValue) -{ - typedef typename detail::AbsReturnType::Type ReturnType; +template <> +struct AbsReturnType : EnableIf {}; +template <> +struct AbsReturnType { + typedef unsigned char Type; +}; +template <> +struct AbsReturnType { + typedef unsigned short Type; +}; +template <> +struct AbsReturnType { + typedef unsigned int Type; +}; +template <> +struct AbsReturnType { + typedef unsigned long Type; +}; +template <> +struct AbsReturnType { + typedef unsigned long long Type; +}; +template <> +struct AbsReturnType { + typedef float Type; +}; +template <> +struct AbsReturnType { + typedef double Type; +}; +template <> +struct AbsReturnType { + typedef long double Type; +}; + +} // namespace detail + +template +inline constexpr typename detail::AbsReturnType::Type Abs(const T aValue) { + using ReturnType = typename detail::AbsReturnType::Type; return aValue >= 0 ? ReturnType(aValue) : ~ReturnType(aValue) + 1; } -template<> -inline float -Abs(const float aFloat) -{ +template <> +inline float Abs(const float aFloat) { return std::fabs(aFloat); } -template<> -inline double -Abs(const double aDouble) -{ +template <> +inline double Abs(const double aDouble) { return std::fabs(aDouble); } -template<> -inline long double -Abs(const long double aLongDouble) -{ +template <> +inline long double Abs(const long double aLongDouble) { return std::fabs(aLongDouble); } -} // namespace mozilla +} // namespace mozilla #if defined(_MSC_VER) && \ (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64)) -# define MOZ_BITSCAN_WINDOWS +#define MOZ_BITSCAN_WINDOWS -# include -# pragma intrinsic(_BitScanForward, _BitScanReverse) +#include +#pragma intrinsic(_BitScanForward, _BitScanReverse) -# if defined(_M_AMD64) || defined(_M_X64) -# define MOZ_BITSCAN_WINDOWS64 -# pragma intrinsic(_BitScanForward64, _BitScanReverse64) -# endif +#if defined(_M_AMD64) || defined(_M_X64) +#define MOZ_BITSCAN_WINDOWS64 +#pragma intrinsic(_BitScanForward64, _BitScanReverse64) +#endif #endif @@ -166,46 +193,33 @@ #if defined(MOZ_BITSCAN_WINDOWS) -inline uint_fast8_t -CountLeadingZeroes32(uint32_t aValue) -{ +inline uint_fast8_t CountLeadingZeroes32(uint32_t aValue) { unsigned long index; - if (!_BitScanReverse(&index, static_cast(aValue))) - return 32; + if (!_BitScanReverse(&index, static_cast(aValue))) return 32; return uint_fast8_t(31 - index); } - -inline uint_fast8_t -CountTrailingZeroes32(uint32_t aValue) -{ +inline uint_fast8_t CountTrailingZeroes32(uint32_t aValue) { unsigned long index; - if (!_BitScanForward(&index, static_cast(aValue))) - return 32; + if (!_BitScanForward(&index, static_cast(aValue))) return 32; return uint_fast8_t(index); } -inline uint_fast8_t -CountPopulation32(uint32_t aValue) -{ +inline uint_fast8_t CountPopulation32(uint32_t aValue) { uint32_t x = aValue - ((aValue >> 1) & 0x55555555); x = (x & 0x33333333) + ((x >> 2) & 0x33333333); return (((x + (x >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; } -inline uint_fast8_t -CountPopulation64(uint64_t aValue) -{ +inline uint_fast8_t CountPopulation64(uint64_t aValue) { return uint_fast8_t(CountPopulation32(aValue & 0xffffffff) + CountPopulation32(aValue >> 32)); } -inline uint_fast8_t -CountLeadingZeroes64(uint64_t aValue) -{ +inline uint_fast8_t CountLeadingZeroes64(uint64_t aValue) { #if defined(MOZ_BITSCAN_WINDOWS64) unsigned long index; if (!_BitScanReverse64(&index, static_cast(aValue))) - return 64; + return 64; return uint_fast8_t(63 - index); #else uint32_t hi = uint32_t(aValue >> 32); @@ -216,13 +230,11 @@ #endif } -inline uint_fast8_t -CountTrailingZeroes64(uint64_t aValue) -{ +inline uint_fast8_t CountTrailingZeroes64(uint64_t aValue) { #if defined(MOZ_BITSCAN_WINDOWS64) unsigned long index; if (!_BitScanForward64(&index, static_cast(aValue))) - return 64; + return 64; return uint_fast8_t(index); #else uint32_t lo = uint32_t(aValue); @@ -233,58 +245,46 @@ #endif } -# ifdef MOZ_HAVE_BITSCAN64 -# undef MOZ_HAVE_BITSCAN64 -# endif +#ifdef MOZ_HAVE_BITSCAN64 +#undef MOZ_HAVE_BITSCAN64 +#endif #elif defined(__clang__) || defined(__GNUC__) -# if defined(__clang__) -# if !__has_builtin(__builtin_ctz) || !__has_builtin(__builtin_clz) -# error "A clang providing __builtin_c[lt]z is required to build" -# endif -# else - // gcc has had __builtin_clz and friends since 3.4: no need to check. -# endif - -inline uint_fast8_t -CountLeadingZeroes32(uint32_t aValue) -{ +#if defined(__clang__) +#if !__has_builtin(__builtin_ctz) || !__has_builtin(__builtin_clz) +#error "A clang providing __builtin_c[lt]z is required to build" +#endif +#else +// gcc has had __builtin_clz and friends since 3.4: no need to check. +#endif + +inline uint_fast8_t CountLeadingZeroes32(uint32_t aValue) { return __builtin_clz(aValue); } -inline uint_fast8_t -CountTrailingZeroes32(uint32_t aValue) -{ +inline uint_fast8_t CountTrailingZeroes32(uint32_t aValue) { return __builtin_ctz(aValue); } -inline uint_fast8_t -CountPopulation32(uint32_t aValue) -{ +inline uint_fast8_t CountPopulation32(uint32_t aValue) { return __builtin_popcount(aValue); } -inline uint_fast8_t -CountPopulation64(uint64_t aValue) -{ +inline uint_fast8_t CountPopulation64(uint64_t aValue) { return __builtin_popcountll(aValue); } -inline uint_fast8_t -CountLeadingZeroes64(uint64_t aValue) -{ +inline uint_fast8_t CountLeadingZeroes64(uint64_t aValue) { return __builtin_clzll(aValue); } -inline uint_fast8_t -CountTrailingZeroes64(uint64_t aValue) -{ +inline uint_fast8_t CountTrailingZeroes64(uint64_t aValue) { return __builtin_ctzll(aValue); } #else -# error "Implement these!" +#error "Implement these!" inline uint_fast8_t CountLeadingZeroes32(uint32_t aValue) = delete; inline uint_fast8_t CountTrailingZeroes32(uint32_t aValue) = delete; inline uint_fast8_t CountPopulation32(uint32_t aValue) = delete; @@ -293,7 +293,7 @@ inline uint_fast8_t CountTrailingZeroes64(uint64_t aValue) = delete; #endif -} // namespace detail +} // namespace detail /** * Compute the number of high-order zero bits in the NON-ZERO number |aValue|. @@ -306,9 +306,7 @@ * CountLeadingZeroes32(0x3FFF0100) is 2; * CountLeadingZeroes32(0x1FF50010) is 3; and so on. */ -inline uint_fast8_t -CountLeadingZeroes32(uint32_t aValue) -{ +inline uint_fast8_t CountLeadingZeroes32(uint32_t aValue) { MOZ_ASSERT(aValue != 0); return detail::CountLeadingZeroes32(aValue); } @@ -324,9 +322,7 @@ * CountTrailingZeroes32(0x0080FFFC) is 2; * CountTrailingZeroes32(0x0080FFF8) is 3; and so on. */ -inline uint_fast8_t -CountTrailingZeroes32(uint32_t aValue) -{ +inline uint_fast8_t CountTrailingZeroes32(uint32_t aValue) { MOZ_ASSERT(aValue != 0); return detail::CountTrailingZeroes32(aValue); } @@ -334,63 +330,51 @@ /** * Compute the number of one bits in the number |aValue|, */ -inline uint_fast8_t -CountPopulation32(uint32_t aValue) -{ +inline uint_fast8_t CountPopulation32(uint32_t aValue) { return detail::CountPopulation32(aValue); } /** Analogous to CountPopulation32, but for 64-bit numbers */ -inline uint_fast8_t -CountPopulation64(uint64_t aValue) -{ +inline uint_fast8_t CountPopulation64(uint64_t aValue) { return detail::CountPopulation64(aValue); } /** Analogous to CountLeadingZeroes32, but for 64-bit numbers. */ -inline uint_fast8_t -CountLeadingZeroes64(uint64_t aValue) -{ +inline uint_fast8_t CountLeadingZeroes64(uint64_t aValue) { MOZ_ASSERT(aValue != 0); return detail::CountLeadingZeroes64(aValue); } /** Analogous to CountTrailingZeroes32, but for 64-bit numbers. */ -inline uint_fast8_t -CountTrailingZeroes64(uint64_t aValue) -{ +inline uint_fast8_t CountTrailingZeroes64(uint64_t aValue) { MOZ_ASSERT(aValue != 0); return detail::CountTrailingZeroes64(aValue); } namespace detail { -template +template class CeilingLog2; -template -class CeilingLog2 -{ -public: - static uint_fast8_t compute(const T aValue) - { +template +class CeilingLog2 { + public: + static uint_fast8_t compute(const T aValue) { // Check for <= 1 to avoid the == 0 undefined case. return aValue <= 1 ? 0u : 32u - CountLeadingZeroes32(aValue - 1); } }; -template -class CeilingLog2 -{ -public: - static uint_fast8_t compute(const T aValue) - { +template +class CeilingLog2 { + public: + static uint_fast8_t compute(const T aValue) { // Check for <= 1 to avoid the == 0 undefined case. return aValue <= 1 ? 0u : 64u - CountLeadingZeroes64(aValue - 1); } }; -} // namespace detail +} // namespace detail /** * Compute the log of the least power of 2 greater than or equal to |aValue|. @@ -401,46 +385,38 @@ * CeilingLog2(5..8) is 3; * CeilingLog2(9..16) is 4; and so on. */ -template -inline uint_fast8_t -CeilingLog2(const T aValue) -{ +template +inline uint_fast8_t CeilingLog2(const T aValue) { return detail::CeilingLog2::compute(aValue); } /** A CeilingLog2 variant that accepts only size_t. */ -inline uint_fast8_t -CeilingLog2Size(size_t aValue) -{ +inline uint_fast8_t CeilingLog2Size(size_t aValue) { return CeilingLog2(aValue); } namespace detail { -template +template class FloorLog2; -template -class FloorLog2 -{ -public: - static uint_fast8_t compute(const T aValue) - { +template +class FloorLog2 { + public: + static uint_fast8_t compute(const T aValue) { return 31u - CountLeadingZeroes32(aValue | 1); } }; -template -class FloorLog2 -{ -public: - static uint_fast8_t compute(const T aValue) - { +template +class FloorLog2 { + public: + static uint_fast8_t compute(const T aValue) { return 63u - CountLeadingZeroes64(aValue | 1); } }; -} // namespace detail +} // namespace detail /** * Compute the log of the greatest power of 2 less than or equal to |aValue|. @@ -450,27 +426,19 @@ * FloorLog2(4..7) is 2; * FloorLog2(8..15) is 3; and so on. */ -template -inline uint_fast8_t -FloorLog2(const T aValue) -{ +template +inline uint_fast8_t FloorLog2(const T aValue) { return detail::FloorLog2::compute(aValue); } /** A FloorLog2 variant that accepts only size_t. */ -inline uint_fast8_t -FloorLog2Size(size_t aValue) -{ - return FloorLog2(aValue); -} +inline uint_fast8_t FloorLog2Size(size_t aValue) { return FloorLog2(aValue); } /* * Compute the smallest power of 2 greater than or equal to |x|. |x| must not * be so great that the computed value would overflow |size_t|. */ -inline size_t -RoundUpPow2(size_t aValue) -{ +inline size_t RoundUpPow2(size_t aValue) { MOZ_ASSERT(aValue <= (size_t(1) << (sizeof(size_t) * CHAR_BIT - 1)), "can't round up -- will overflow!"); return size_t(1) << CeilingLog2(aValue); @@ -479,34 +447,36 @@ /** * Rotates the bits of the given value left by the amount of the shift width. */ -template -inline T -RotateLeft(const T aValue, uint_fast8_t aShift) -{ +template +MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW inline T RotateLeft(const T aValue, + uint_fast8_t aShift) { + static_assert(IsUnsigned::value, "Rotates require unsigned values"); + MOZ_ASSERT(aShift < sizeof(T) * CHAR_BIT, "Shift value is too large!"); MOZ_ASSERT(aShift > 0, "Rotation by value length is undefined behavior, but compilers " "do not currently fold a test into the rotate instruction. " "Please remove this restriction when compilers optimize the " "zero case (http://blog.regehr.org/archives/1063)."); - static_assert(IsUnsigned::value, "Rotates require unsigned values"); + return (aValue << aShift) | (aValue >> (sizeof(T) * CHAR_BIT - aShift)); } /** * Rotates the bits of the given value right by the amount of the shift width. */ -template -inline T -RotateRight(const T aValue, uint_fast8_t aShift) -{ +template +MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW inline T RotateRight(const T aValue, + uint_fast8_t aShift) { + static_assert(IsUnsigned::value, "Rotates require unsigned values"); + MOZ_ASSERT(aShift < sizeof(T) * CHAR_BIT, "Shift value is too large!"); MOZ_ASSERT(aShift > 0, "Rotation by value length is undefined behavior, but compilers " "do not currently fold a test into the rotate instruction. " "Please remove this restriction when compilers optimize the " "zero case (http://blog.regehr.org/archives/1063)."); - static_assert(IsUnsigned::value, "Rotates require unsigned values"); + return (aValue >> aShift) | (aValue << (sizeof(T) * CHAR_BIT - aShift)); } @@ -514,32 +484,25 @@ * Returns true if |x| is a power of two. * Zero is not an integer power of two. (-Inf is not an integer) */ -template -constexpr bool -IsPowerOfTwo(T x) -{ - static_assert(IsUnsigned::value, - "IsPowerOfTwo requires unsigned values"); - return x && (x & (x - 1)) == 0; -} - -template -inline T -Clamp(const T aValue, const T aMin, const T aMax) -{ - static_assert(IsIntegral::value, - "Clamp accepts only integral types, so that it doesn't have" - " to distinguish differently-signed zeroes (which users may" - " or may not care to distinguish, likely at a perf cost) or" - " to decide how to clamp NaN or a range with a NaN" - " endpoint."); - MOZ_ASSERT(aMin <= aMax); - - if (aValue <= aMin) - return aMin; - if (aValue >= aMax) - return aMax; - return aValue; +template +constexpr bool IsPowerOfTwo(T x) { + static_assert(IsUnsigned::value, "IsPowerOfTwo requires unsigned values"); + return x && (x & (x - 1)) == 0; +} + +template +inline T Clamp(const T aValue, const T aMin, const T aMax) { + static_assert(IsIntegral::value, + "Clamp accepts only integral types, so that it doesn't have" + " to distinguish differently-signed zeroes (which users may" + " or may not care to distinguish, likely at a perf cost) or" + " to decide how to clamp NaN or a range with a NaN" + " endpoint."); + MOZ_ASSERT(aMin <= aMax); + + if (aValue <= aMin) return aMin; + if (aValue >= aMax) return aMax; + return aValue; } } /* namespace mozilla */ 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 @@ -12,15 +12,38 @@ #include "mozilla/Alignment.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" +#include "mozilla/MemoryChecking.h" #include "mozilla/Move.h" +#include "mozilla/OperatorNewExtensions.h" +#include "mozilla/Poison.h" #include "mozilla/TypeTraits.h" #include // for placement new +#include #include namespace mozilla { -struct Nothing { }; +struct Nothing {}; + +namespace detail { + +template +struct MaybePoisoner { + static const size_t N = sizeof(T); + + static void poison(void* aPtr) { +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + // Avoid MOZ_ASSERT in mozWritePoison. + if (N >= sizeof(uintptr_t)) { + mozWritePoison(aPtr, N); + } +#endif + MOZ_MAKE_MEM_UNDEFINED(aPtr, N); + } +}; + +} // namespace detail /* * Maybe is a container class which contains either zero or one elements. It @@ -80,90 +103,75 @@ * extra branches/loads/stores. Use with caution on hot paths; it's not known * whether or not this is still a problem. */ -template -class Maybe -{ - bool mIsSome; - AlignedStorage2 mStorage; +template +class MOZ_NON_PARAM MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe { + MOZ_ALIGNAS_IN_STRUCT(T) unsigned char mStorage[sizeof(T)]; + char mIsSome; // not bool -- guarantees minimal space consumption + + // GCC fails due to -Werror=strict-aliasing if |mStorage| is directly cast to + // T*. Indirecting through these functions addresses the problem. + void* data() { return mStorage; } + const void* data() const { return mStorage; } -public: - typedef T ValueType; + void poisonData() { detail::MaybePoisoner::poison(data()); } - Maybe() : mIsSome(false) { } + public: + using ValueType = T; + + Maybe() : mIsSome(false) { poisonData(); } ~Maybe() { reset(); } - MOZ_IMPLICIT Maybe(Nothing) : mIsSome(false) { } + MOZ_IMPLICIT Maybe(Nothing) : mIsSome(false) { poisonData(); } - Maybe(const Maybe& aOther) - : mIsSome(false) - { + Maybe(const Maybe& aOther) : mIsSome(false) { if (aOther.mIsSome) { emplace(*aOther); + } else { + poisonData(); } } /** - * Maybe can be copy-constructed from a Maybe if U* and T* are - * compatible, or from Maybe. + * Maybe can be copy-constructed from a Maybe if U is convertible to T. */ - 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) - { + template ::value>::type> + MOZ_IMPLICIT Maybe(const Maybe& aOther) : mIsSome(false) { if (aOther.isSome()) { emplace(*aOther); + } else { + poisonData(); } } - Maybe(Maybe&& aOther) - : mIsSome(false) - { + Maybe(Maybe&& aOther) : mIsSome(false) { if (aOther.mIsSome) { emplace(Move(*aOther)); aOther.reset(); + } else { + poisonData(); } } /** - * Maybe can be move-constructed from a Maybe if U* and T* are - * compatible, or from Maybe. + * Maybe can be move-constructed from a Maybe if U is convertible to T. */ - 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) - { + template ::value>::type> + MOZ_IMPLICIT Maybe(Maybe&& aOther) : mIsSome(false) { if (aOther.isSome()) { emplace(Move(*aOther)); aOther.reset(); + } else { + poisonData(); } } - Maybe& operator=(const Maybe& aOther) - { + Maybe& operator=(const Maybe& aOther) { if (&aOther != this) { if (aOther.mIsSome) { if (mIsSome) { - // XXX(seth): The correct code for this branch, below, can't be used - // due to a bug in Visual Studio 2010. See bug 1052940. - /* ref() = aOther.ref(); - */ - reset(); - emplace(*aOther); } else { emplace(*aOther); } @@ -174,8 +182,22 @@ return *this; } - Maybe& operator=(Maybe&& aOther) - { + template ::value>::type> + Maybe& operator=(const Maybe& aOther) { + if (aOther.isSome()) { + if (mIsSome) { + ref() = aOther.ref(); + } else { + emplace(*aOther); + } + } else { + reset(); + } + return *this; + } + + Maybe& operator=(Maybe&& aOther) { MOZ_ASSERT(this != &aOther, "Self-moves are prohibited"); if (aOther.mIsSome) { @@ -192,14 +214,31 @@ return *this; } + template ::value>::type> + Maybe& operator=(Maybe&& aOther) { + if (aOther.isSome()) { + if (mIsSome) { + ref() = Move(aOther.ref()); + } else { + emplace(Move(*aOther)); + } + aOther.reset(); + } else { + reset(); + } + + return *this; + } + /* Methods that check whether this Maybe contains a value */ explicit operator bool() const { return isSome(); } bool isSome() const { return mIsSome; } bool isNothing() const { return !mIsSome; } - /* Returns the contents of this Maybe by value. Unsafe unless |isSome()|. */ - T value() const - { + /* Returns the contents of this Maybe by value. Unsafe unless |isSome()|. + */ + T value() const { MOZ_ASSERT(mIsSome); return ref(); } @@ -208,9 +247,8 @@ * Returns the contents of this Maybe by value. If |isNothing()|, returns * the default value provided. */ - template - T valueOr(V&& aDefault) const - { + template + T valueOr(V&& aDefault) const { if (isSome()) { return ref(); } @@ -221,24 +259,22 @@ * Returns the contents of this Maybe by value. If |isNothing()|, returns * the value returned from the function or functor provided. */ - template - T valueOrFrom(F&& aFunc) const - { + template + T valueOrFrom(F&& aFunc) const { if (isSome()) { return ref(); } return aFunc(); } - /* Returns the contents of this Maybe by pointer. Unsafe unless |isSome()|. */ - T* ptr() - { + /* Returns the contents of this Maybe by pointer. Unsafe unless |isSome()|. + */ + T* ptr() { MOZ_ASSERT(mIsSome); return &ref(); } - const T* ptr() const - { + const T* ptr() const { MOZ_ASSERT(mIsSome); return &ref(); } @@ -247,16 +283,14 @@ * Returns the contents of this Maybe by pointer. If |isNothing()|, * returns the default value provided. */ - T* ptrOr(T* aDefault) - { + T* ptrOr(T* aDefault) { if (isSome()) { return ptr(); } return aDefault; } - const T* ptrOr(const T* aDefault) const - { + const T* ptrOr(const T* aDefault) const { if (isSome()) { return ptr(); } @@ -267,63 +301,55 @@ * Returns the contents of this Maybe by pointer. If |isNothing()|, * returns the value returned from the function or functor provided. */ - template - T* ptrOrFrom(F&& aFunc) - { + template + T* ptrOrFrom(F&& aFunc) { if (isSome()) { return ptr(); } return aFunc(); } - template - const T* ptrOrFrom(F&& aFunc) const - { + template + const T* ptrOrFrom(F&& aFunc) const { if (isSome()) { return ptr(); } return aFunc(); } - T* operator->() - { + T* operator->() { MOZ_ASSERT(mIsSome); return ptr(); } - const T* operator->() const - { + const T* operator->() const { MOZ_ASSERT(mIsSome); return ptr(); } /* Returns the contents of this Maybe by ref. Unsafe unless |isSome()|. */ - T& ref() - { + T& ref() { MOZ_ASSERT(mIsSome); - return *mStorage.addr(); + return *static_cast(data()); } - const T& ref() const - { + const T& ref() const { MOZ_ASSERT(mIsSome); - return *mStorage.addr(); + return *static_cast(data()); } /* * Returns the contents of this Maybe by ref. If |isNothing()|, returns * the default value provided. */ - T& refOr(T& aDefault) - { + T& refOr(T& aDefault) { if (isSome()) { return ref(); } return aDefault; } - const T& refOr(const T& aDefault) const - { + const T& refOr(const T& aDefault) const { if (isSome()) { return ref(); } @@ -334,50 +360,44 @@ * Returns the contents of this Maybe by ref. If |isNothing()|, returns the * value returned from the function or functor provided. */ - template - T& refOrFrom(F&& aFunc) - { + template + T& refOrFrom(F&& aFunc) { if (isSome()) { return ref(); } return aFunc(); } - template - const T& refOrFrom(F&& aFunc) const - { + template + const T& refOrFrom(F&& aFunc) const { if (isSome()) { return ref(); } return aFunc(); } - T& operator*() - { + T& operator*() { MOZ_ASSERT(mIsSome); return ref(); } - const T& operator*() const - { + const T& operator*() const { MOZ_ASSERT(mIsSome); return ref(); } /* If |isSome()|, runs the provided function or functor on the contents of * this Maybe. */ - template - Maybe& apply(Func aFunc) - { + template + Maybe& apply(Func aFunc) { if (isSome()) { aFunc(ref()); } return *this; } - template - const Maybe& apply(Func aFunc) const - { + template + const Maybe& apply(Func aFunc) const { if (isSome()) { aFunc(ref()); } @@ -388,9 +408,8 @@ * If |isSome()|, runs the provided function and returns the result wrapped * in a Maybe. If |isNothing()|, returns an empty Maybe value. */ - template - auto map(Func aFunc) -> Maybe>().ref()))> - { + template + auto map(Func aFunc) -> Maybe>().ref()))> { using ReturnType = decltype(aFunc(ref())); if (isSome()) { Maybe val; @@ -400,9 +419,9 @@ return Maybe(); } - template - auto map(Func aFunc) const -> Maybe>().ref()))> - { + template + auto map(Func aFunc) const + -> Maybe>().ref()))> { using ReturnType = decltype(aFunc(ref())); if (isSome()) { Maybe val; @@ -413,11 +432,11 @@ } /* If |isSome()|, empties this Maybe and destroys its contents. */ - void reset() - { + void reset() { if (isSome()) { ref().T::~T(); mIsSome = false; + poisonData(); } } @@ -425,13 +444,22 @@ * Constructs a T value in-place in this empty Maybe's storage. The * arguments to |emplace()| are the parameters to T's constructor. */ - template - void emplace(Args&&... aArgs) - { + template + void emplace(Args&&... aArgs) { MOZ_ASSERT(!mIsSome); - ::new (mStorage.addr()) T(Forward(aArgs)...); + ::new (KnownNotNull, data()) T(Forward(aArgs)...); mIsSome = true; } + + friend std::ostream& operator<<(std::ostream& aStream, + const Maybe& aMaybe) { + if (aMaybe) { + aStream << aMaybe.ref(); + } else { + aStream << ""; + } + return aStream; + } }; /* @@ -444,20 +472,17 @@ * if you need to construct a Maybe value that holds a const, volatile, or * reference value, you need to use emplace() instead. */ -template -Maybe::Type>::Type> -Some(T&& aValue) -{ - typedef typename RemoveCV::Type>::Type U; +template ::type>::type> +Maybe Some(T&& aValue) { Maybe value; value.emplace(Forward(aValue)); return value; } -template -Maybe::Type>::Type> -ToMaybe(T* aPtr) -{ +template +Maybe::Type>::Type> ToMaybe( + T* aPtr) { if (aPtr) { return Some(*aPtr); } @@ -469,18 +494,16 @@ * - both are Nothing, or * - both are Some, and the values they contain are equal. */ -template bool -operator==(const Maybe& aLHS, const Maybe& aRHS) -{ +template +bool operator==(const Maybe& aLHS, const Maybe& aRHS) { if (aLHS.isNothing() != aRHS.isNothing()) { return false; } return aLHS.isNothing() || *aLHS == *aRHS; } -template bool -operator!=(const Maybe& aLHS, const Maybe& aRHS) -{ +template +bool operator!=(const Maybe& aLHS, const Maybe& aRHS) { return !(aLHS == aRHS); } @@ -488,27 +511,23 @@ * We support comparison to Nothing to allow reasonable expressions like: * if (maybeValue == Nothing()) { ... } */ -template bool -operator==(const Maybe& aLHS, const Nothing& aRHS) -{ +template +bool operator==(const Maybe& aLHS, const Nothing& aRHS) { return aLHS.isNothing(); } -template bool -operator!=(const Maybe& aLHS, const Nothing& aRHS) -{ +template +bool operator!=(const Maybe& aLHS, const Nothing& aRHS) { return !(aLHS == aRHS); } -template bool -operator==(const Nothing& aLHS, const Maybe& aRHS) -{ +template +bool operator==(const Nothing& aLHS, const Maybe& aRHS) { return aRHS.isNothing(); } -template bool -operator!=(const Nothing& aLHS, const Maybe& aRHS) -{ +template +bool operator!=(const Nothing& aLHS, const Maybe& aRHS) { return !(aLHS == aRHS); } @@ -516,9 +535,8 @@ * Maybe values are ordered in the same way T values are ordered, except that * Nothing comes before anything else. */ -template bool -operator<(const Maybe& aLHS, const Maybe& aRHS) -{ +template +bool operator<(const Maybe& aLHS, const Maybe& aRHS) { if (aLHS.isNothing()) { return aRHS.isSome(); } @@ -528,24 +546,21 @@ return *aLHS < *aRHS; } -template bool -operator>(const Maybe& aLHS, const Maybe& aRHS) -{ +template +bool operator>(const Maybe& aLHS, const Maybe& aRHS) { return !(aLHS < aRHS || aLHS == aRHS); } -template bool -operator<=(const Maybe& aLHS, const Maybe& aRHS) -{ +template +bool operator<=(const Maybe& aLHS, const Maybe& aRHS) { return aLHS < aRHS || aLHS == aRHS; } -template bool -operator>=(const Maybe& aLHS, const Maybe& aRHS) -{ +template +bool operator>=(const Maybe& aLHS, const Maybe& aRHS) { return !(aLHS < aRHS); } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_Maybe_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/MaybeOneOf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/MaybeOneOf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/MaybeOneOf.h @@ -4,15 +4,21 @@ * 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 class storing one of two optional value types that supports in-place lazy + * construction. + */ + #ifndef mozilla_MaybeOneOf_h #define mozilla_MaybeOneOf_h -#include "mozilla/Alignment.h" #include "mozilla/Assertions.h" #include "mozilla/Move.h" +#include "mozilla/OperatorNewExtensions.h" #include "mozilla/TemplateLib.h" -#include // For placement new +#include // for placement new +#include // for size_t namespace mozilla { @@ -24,36 +30,47 @@ * |construct()|, a T1 or T2 object will be constructed with the given * arguments and that object will be destroyed when the owning MaybeOneOf is * destroyed. + * + * Because MaybeOneOf must be aligned suitable to hold any value stored within + * it, and because |alignas| requirements don't affect platform ABI with respect + * to how parameters are laid out in memory, MaybeOneOf can't be used as the + * type of a function parameter. Pass MaybeOneOf to functions by pointer or + * reference instead. */ -template -class MaybeOneOf -{ - AlignedStorage::value> storage; +template +class MOZ_NON_PARAM MaybeOneOf { + static constexpr size_t StorageAlignment = + tl::Max::value; + static constexpr size_t StorageSize = tl::Max::value; + + alignas(StorageAlignment) unsigned char storage[StorageSize]; + + // GCC fails due to -Werror=strict-aliasing if |storage| is directly cast to + // T*. Indirecting through these functions addresses the problem. + void* data() { return storage; } + const void* data() const { return storage; } enum State { None, SomeT1, SomeT2 } state; - template struct Type2State {}; + template + struct Type2State {}; template - T& as() - { + T& as() { MOZ_ASSERT(state == Type2State::result); - return *(T*)storage.addr(); + return *static_cast(data()); } template - const T& as() const - { + const T& as() const { MOZ_ASSERT(state == Type2State::result); - return *(T*)storage.addr(); + return *static_cast(data()); } -public: + public: MaybeOneOf() : state(None) {} ~MaybeOneOf() { destroyIfConstructed(); } - MaybeOneOf(MaybeOneOf&& rhs) - : state(None) - { + MaybeOneOf(MaybeOneOf&& rhs) : state(None) { if (!rhs.empty()) { if (rhs.constructed()) { construct(Move(rhs.as())); @@ -66,41 +83,38 @@ } } - MaybeOneOf &operator=(MaybeOneOf&& rhs) - { + MaybeOneOf& operator=(MaybeOneOf&& rhs) { MOZ_ASSERT(this != &rhs, "Self-move is prohibited"); this->~MaybeOneOf(); - new(this) MaybeOneOf(Move(rhs)); + new (this) MaybeOneOf(Move(rhs)); return *this; } bool empty() const { return state == None; } template - bool constructed() const { return state == Type2State::result; } + bool constructed() const { + return state == Type2State::result; + } template - void construct(Args&&... aArgs) - { + void construct(Args&&... aArgs) { MOZ_ASSERT(state == None); state = Type2State::result; - ::new (storage.addr()) T(Forward(aArgs)...); + ::new (KnownNotNull, data()) T(Forward(aArgs)...); } template - T& ref() - { + T& ref() { return as(); } template - const T& ref() const - { + const T& ref() const { return as(); } - void destroy() - { + void destroy() { MOZ_ASSERT(state == SomeT1 || state == SomeT2); if (state == SomeT1) { as().~T1(); @@ -110,34 +124,31 @@ state = None; } - void destroyIfConstructed() - { + void destroyIfConstructed() { if (!empty()) { destroy(); } } -private: + private: MaybeOneOf(const MaybeOneOf& aOther) = delete; const MaybeOneOf& operator=(const MaybeOneOf& aOther) = delete; }; template template -struct MaybeOneOf::Type2State -{ +struct MaybeOneOf::Type2State { typedef MaybeOneOf Enclosing; static const typename Enclosing::State result = Enclosing::SomeT1; }; template template -struct MaybeOneOf::Type2State -{ +struct MaybeOneOf::Type2State { typedef MaybeOneOf Enclosing; static const typename Enclosing::State result = Enclosing::SomeT2; }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_MaybeOneOf_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/MemoryChecking.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/MemoryChecking.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/MemoryChecking.h @@ -49,8 +49,8 @@ /* These definitions are usually provided through the * sanitizer/asan_interface.h header installed by ASan. */ -void MOZ_ASAN_VISIBILITY -__asan_poison_memory_region(void const volatile *addr, size_t size); +void MOZ_ASAN_VISIBILITY __asan_poison_memory_region(void const volatile *addr, + size_t size); void MOZ_ASAN_VISIBILITY __asan_unpoison_memory_region(void const volatile *addr, size_t size); @@ -67,9 +67,7 @@ * These definitions are usually provided through the * sanitizer/lsan_interface.h header installed by LSan. */ -void MOZ_EXPORT -__lsan_ignore_object(const void *p); - +void MOZ_EXPORT __lsan_ignore_object(const void *p); } #elif defined(MOZ_MSAN) #include @@ -80,19 +78,14 @@ /* These definitions are usually provided through the * sanitizer/msan_interface.h header installed by MSan. */ -void MOZ_EXPORT -__msan_poison(void const volatile *addr, size_t size); -void MOZ_EXPORT -__msan_unpoison(void const volatile *addr, size_t size); +void MOZ_EXPORT __msan_poison(void const volatile *addr, size_t size); +void MOZ_EXPORT __msan_unpoison(void const volatile *addr, size_t size); -#define MOZ_MAKE_MEM_NOACCESS(addr, size) \ - __msan_poison((addr), (size)) +#define MOZ_MAKE_MEM_NOACCESS(addr, size) __msan_poison((addr), (size)) -#define MOZ_MAKE_MEM_UNDEFINED(addr, size) \ - __msan_poison((addr), (size)) +#define MOZ_MAKE_MEM_UNDEFINED(addr, size) __msan_poison((addr), (size)) -#define MOZ_MAKE_MEM_DEFINED(addr, size) \ - __msan_unpoison((addr), (size)) +#define MOZ_MAKE_MEM_DEFINED(addr, size) __msan_unpoison((addr), (size)) } #elif defined(MOZ_VALGRIND) #define MOZ_MAKE_MEM_NOACCESS(addr, size) \ @@ -105,9 +98,15 @@ VALGRIND_MAKE_MEM_DEFINED((addr), (size)) #else -#define MOZ_MAKE_MEM_NOACCESS(addr, size) do {} while (0) -#define MOZ_MAKE_MEM_UNDEFINED(addr, size) do {} while (0) -#define MOZ_MAKE_MEM_DEFINED(addr, size) do {} while (0) +#define MOZ_MAKE_MEM_NOACCESS(addr, size) \ + do { \ + } while (0) +#define MOZ_MAKE_MEM_UNDEFINED(addr, size) \ + do { \ + } while (0) +#define MOZ_MAKE_MEM_DEFINED(addr, size) \ + do { \ + } while (0) #endif @@ -120,10 +119,9 @@ * conversant in leak-checking and/or MFBT peers. */ #if defined(MOZ_ASAN) -# define MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(X) __lsan_ignore_object(X) +#define MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(X) __lsan_ignore_object(X) #else -# define MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(X) /* nothing */ -#endif // defined(MOZ_ASAN) - +#define MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(X) /* nothing */ +#endif // defined(MOZ_ASAN) #endif /* mozilla_MemoryChecking_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Move.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Move.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Move.h @@ -196,10 +196,8 @@ * Identical to std::Move(); this is necessary until our stlport supports * std::move(). */ -template -inline typename RemoveReference::Type&& -Move(T&& aX) -{ +template +inline typename RemoveReference::Type&& Move(T&& aX) { return static_cast::Type&&>(aX); } @@ -207,32 +205,26 @@ * These two overloads are identical to std::forward(); they are necessary until * our stlport supports std::forward(). */ -template -inline T&& -Forward(typename RemoveReference::Type& aX) -{ +template +inline T&& Forward(typename RemoveReference::Type& aX) { return static_cast(aX); } -template -inline T&& -Forward(typename RemoveReference::Type&& aX) -{ +template +inline T&& Forward(typename RemoveReference::Type&& aX) { static_assert(!IsLvalueReference::value, "misuse of Forward detected! try the other overload"); return static_cast(aX); } /** Swap |aX| and |aY| using move-construction if possible. */ -template -inline void -Swap(T& aX, T& aY) -{ +template +inline void Swap(T& aX, T& aY) { T tmp(Move(aX)); aX = Move(aY); aY = Move(tmp); } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_Move_h */ 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 @@ -63,6 +63,8 @@ // for the last one, where the handle type is |void|. See below. #include "mozilla/Assertions.h" +#include "mozilla/Move.h" +#include namespace mozilla { @@ -84,8 +86,8 @@ // - 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. +// only be done with WrapNotNull() or MakeNotNull<>(), 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. @@ -98,23 +100,30 @@ // https://github.com/Microsoft/GSL/issues/89 for some discussion. // template -class NotNull -{ - template friend NotNull WrapNotNull(U aBasePtr); +class NotNull { + template + friend NotNull WrapNotNull(U aBasePtr); + template + friend NotNull MakeNotNull(Args&&... aArgs); T mBasePtr; - // This constructor is only used by WrapNotNull(). + // This constructor is only used by WrapNotNull() and MakeNotNull(). template explicit NotNull(U aBasePtr) : mBasePtr(aBasePtr) {} -public: + 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()) {} + MOZ_IMPLICIT NotNull(const NotNull& aOther) : mBasePtr(aOther.get()) { + static_assert(sizeof(T) == sizeof(NotNull), + "NotNull must have zero space overhead."); + static_assert(offsetof(NotNull, mBasePtr) == 0, + "mBasePtr must have zero offset."); + } // Default copy/move construction and assignment. NotNull(const NotNull&) = default; @@ -138,72 +147,95 @@ }; template -NotNull -WrapNotNull(const T aBasePtr) -{ +NotNull WrapNotNull(const T aBasePtr) { NotNull notNull(aBasePtr); MOZ_RELEASE_ASSERT(aBasePtr); return notNull; } +namespace detail { + +// Extract the pointed-to type from a pointer type (be it raw or smart). +// The default implementation uses the dereferencing operator of the pointer +// type to find what it's pointing to. +template +struct PointedTo { + // Remove the reference that dereferencing operators may return. + using Type = typename RemoveReference())>::Type; + using NonConstType = typename RemoveConst::Type; +}; + +// Specializations for raw pointers. +// This is especially required because VS 2017 15.6 (March 2018) started +// rejecting the above `decltype(*DeclVal())` trick for raw pointers. +// See bug 1443367. +template +struct PointedTo { + using Type = T; + using NonConstType = T; +}; + +template +struct PointedTo { + using Type = const T; + using NonConstType = T; +}; + +} // namespace detail + +// Allocate an object with infallible new, and wrap its pointer in NotNull. +// |MakeNotNull>(args...)| will run |new Ob(args...)| +// and return NotNull>. +template +NotNull MakeNotNull(Args&&... aArgs) { + using Pointee = typename detail::PointedTo::NonConstType; + static_assert(!IsArray::value, + "MakeNotNull cannot construct an array"); + return NotNull(new Pointee(Forward(aArgs)...)); +} + // Compare two NotNulls. template -inline bool -operator==(const NotNull& aLhs, const NotNull& aRhs) -{ +inline bool operator==(const NotNull& aLhs, const NotNull& aRhs) { return aLhs.get() == aRhs.get(); } template -inline bool -operator!=(const NotNull& aLhs, const NotNull& aRhs) -{ +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) -{ +inline bool operator==(const NotNull& aLhs, const U& aRhs) { return aLhs.get() == aRhs; } template -inline bool -operator!=(const NotNull& aLhs, const U& aRhs) -{ +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) -{ +inline bool operator==(const T& aLhs, const NotNull& aRhs) { return aLhs == aRhs.get(); } template -inline bool -operator!=(const T& aLhs, const NotNull& aRhs) -{ +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; +bool operator==(const NotNull&, decltype(nullptr)) = delete; template -bool -operator!=(const NotNull&, decltype(nullptr)) = delete; +bool operator!=(const NotNull&, decltype(nullptr)) = delete; // Disallow comparing a nullptr to a NotNull. template -bool -operator==(decltype(nullptr), const NotNull&) = delete; +bool operator==(decltype(nullptr), const NotNull&) = delete; template -bool -operator!=(decltype(nullptr), const NotNull&) = delete; +bool operator!=(decltype(nullptr), const NotNull&) = delete; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_NotNull_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/NullPtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/NullPtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/NullPtr.h @@ -20,12 +20,12 @@ * (fixed in C++14), so in the interests of easing a switch to , * this trait lives elsewhere. */ -template +template struct IsNullPointer : FalseType {}; -template<> +template <> struct IsNullPointer : TrueType {}; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_NullPtr_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Opaque.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Opaque.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Opaque.h @@ -18,15 +18,14 @@ * must be supported, and it's desirable to prevent accidental dependency on * exact values. */ -template -class Opaque final -{ +template +class Opaque final { static_assert(mozilla::IsIntegral::value, "mozilla::Opaque only supports integral types"); T mValue; -public: + public: Opaque() {} explicit Opaque(T aValue) : mValue(aValue) {} @@ -34,11 +33,9 @@ return mValue == aOther.mValue; } - bool operator!=(const Opaque& aOther) const { - return !(*this == aOther); - } + bool operator!=(const Opaque& aOther) const { return !(*this == aOther); } }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_Opaque_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 @@ -17,7 +17,7 @@ enum NotNullTag { KnownNotNull, }; -} // namespace mozilla +} // namespace mozilla /* * The logic here is a little subtle. [expr.new] states that if the allocation @@ -42,11 +42,9 @@ * 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) -{ +inline void* operator new(size_t, mozilla::NotNullTag, void* p) { MOZ_ASSERT(p); return p; } -#endif // mozilla_OperatorNewExtensions_h +#endif // mozilla_OperatorNewExtensions_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Pair.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Pair.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Pair.h @@ -26,114 +26,98 @@ // The extra conditions on storage for B are necessary so that PairHelper won't // ambiguously inherit from either A or B, such that one or the other base class // would be inaccessible. -template::value ? detail::AsBase : detail::AsMember, - detail::StorageType = - IsEmpty::value && !IsBaseOf::value && !IsBaseOf::value - ? detail::AsBase - : detail::AsMember> +template ::value ? detail::AsBase : detail::AsMember, + detail::StorageType = IsEmpty::value && !IsBaseOf::value && + !IsBaseOf::value + ? detail::AsBase + : detail::AsMember> struct PairHelper; -template -struct PairHelper -{ -protected: - template +template +struct PairHelper { + protected: + template PairHelper(AArg&& aA, BArg&& aB) - : mFirstA(Forward(aA)), - mSecondB(Forward(aB)) - {} + : mFirstA(Forward(aA)), mSecondB(Forward(aB)) {} A& first() { return mFirstA; } const A& first() const { return mFirstA; } B& second() { return mSecondB; } const B& second() const { return mSecondB; } - void swap(PairHelper& aOther) - { + void swap(PairHelper& aOther) { Swap(mFirstA, aOther.mFirstA); Swap(mSecondB, aOther.mSecondB); } -private: + private: A mFirstA; B mSecondB; }; -template -struct PairHelper : private B -{ -protected: - template +template +struct PairHelper : private B { + protected: + template PairHelper(AArg&& aA, BArg&& aB) - : B(Forward(aB)), - mFirstA(Forward(aA)) - {} + : B(Forward(aB)), mFirstA(Forward(aA)) {} A& first() { return mFirstA; } const A& first() const { return mFirstA; } B& second() { return *this; } const B& second() const { return *this; } - void swap(PairHelper& aOther) - { + void swap(PairHelper& aOther) { Swap(mFirstA, aOther.mFirstA); Swap(static_cast(*this), static_cast(aOther)); } -private: + private: A mFirstA; }; -template -struct PairHelper : private A -{ -protected: - template +template +struct PairHelper : private A { + protected: + template PairHelper(AArg&& aA, BArg&& aB) - : A(Forward(aA)), - mSecondB(Forward(aB)) - {} + : A(Forward(aA)), mSecondB(Forward(aB)) {} A& first() { return *this; } const A& first() const { return *this; } B& second() { return mSecondB; } const B& second() const { return mSecondB; } - void swap(PairHelper& aOther) - { + void swap(PairHelper& aOther) { Swap(static_cast(*this), static_cast(aOther)); Swap(mSecondB, aOther.mSecondB); } -private: + private: B mSecondB; }; -template -struct PairHelper : private A, private B -{ -protected: - template +template +struct PairHelper : private A, private B { + protected: + template PairHelper(AArg&& aA, BArg&& aB) - : A(Forward(aA)), - B(Forward(aB)) - {} + : A(Forward(aA)), B(Forward(aB)) {} A& first() { return static_cast(*this); } const A& first() const { return static_cast(*this); } B& second() { return static_cast(*this); } const B& second() const { return static_cast(*this); } - void swap(PairHelper& aOther) - { + void swap(PairHelper& aOther) { Swap(static_cast(*this), static_cast(aOther)); Swap(static_cast(*this), static_cast(aOther)); } }; -} // namespace detail +} // namespace detail /** * Pair is the logical concatenation of an instance of A with an instance B. @@ -148,26 +132,19 @@ * required to optimize space usage.) The first/second names are merely * conceptual! */ -template -struct Pair - : private detail::PairHelper -{ +template +struct Pair : private detail::PairHelper { typedef typename detail::PairHelper Base; -public: - template - Pair(AArg&& aA, BArg&& aB) - : Base(Forward(aA), Forward(aB)) - {} - - Pair(Pair&& aOther) - : Base(Move(aOther.first()), Move(aOther.second())) - { } + public: + template + Pair(AArg&& aA, BArg&& aB) : Base(Forward(aA), Forward(aB)) {} + + Pair(Pair&& aOther) : Base(Move(aOther.first()), Move(aOther.second())) {} Pair(const Pair& aOther) = default; - Pair& operator=(Pair&& aOther) - { + Pair& operator=(Pair&& aOther) { MOZ_ASSERT(this != &aOther, "Self-moves are prohibited"); first() = Move(aOther.first()); @@ -187,10 +164,8 @@ void swap(Pair& aOther) { Base::swap(aOther); } }; -template -void -Swap(Pair& aX, Pair& aY) -{ +template +void Swap(Pair& aX, Pair& aY) { aX.swap(aY); } @@ -202,18 +177,15 @@ * * will return a Pair. */ -template +template Pair::Type>::Type, typename RemoveCV::Type>::Type> -MakePair(A&& aA, B&& aB) -{ - return - Pair::Type>::Type, - typename RemoveCV::Type>::Type>( - Forward(aA), - Forward(aB)); +MakePair(A&& aA, B&& aB) { + return Pair::Type>::Type, + typename RemoveCV::Type>::Type>( + Forward(aA), Forward(aB)); } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_Pair_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Path.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Path.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Path.h @@ -0,0 +1,31 @@ +/* -*- 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/. */ + +/* Represents the native path format on the platform. */ + +#ifndef mozilla_Path_h +#define mozilla_Path_h + +namespace mozilla { +namespace filesystem { + +/* + * Mozilla vaiant of std::filesystem::path. + * Only |value_type| is implemented at the moment. + */ +class Path { + public: +#ifdef XP_WIN + using value_type = char16_t; +#else + using value_type = char; +#endif +}; + +} /* namespace filesystem */ +} /* namespace mozilla */ + +#endif /* mozilla_Path_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/PlatformConditionVariable.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/PlatformConditionVariable.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/PlatformConditionVariable.h @@ -0,0 +1,66 @@ +/* -*- 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_ConditionVariable_h +#define mozilla_ConditionVariable_h + +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" +#include "mozilla/PlatformMutex.h" +#include "mozilla/TimeStamp.h" + +#include +#ifndef XP_WIN +#include +#endif + +namespace mozilla { + +namespace detail { + +enum class CVStatus { NoTimeout, Timeout }; + +class ConditionVariableImpl { + public: + struct PlatformData; + + MFBT_API ConditionVariableImpl(); + MFBT_API ~ConditionVariableImpl(); + + // Wake one thread that is waiting on this condition. + MFBT_API void notify_one(); + + // Wake all threads that are waiting on this condition. + MFBT_API void notify_all(); + + // Block the current thread of execution until this condition variable is + // woken from another thread via notify_one or notify_all. + MFBT_API void wait(MutexImpl& lock); + + MFBT_API CVStatus wait_for(MutexImpl& lock, + const mozilla::TimeDuration& rel_time); + + private: + ConditionVariableImpl(const ConditionVariableImpl&) = delete; + ConditionVariableImpl& operator=(const ConditionVariableImpl&) = delete; + + PlatformData* platformData(); + +#ifndef XP_WIN + void* platformData_[sizeof(pthread_cond_t) / sizeof(void*)]; + static_assert(sizeof(pthread_cond_t) / sizeof(void*) != 0 && + sizeof(pthread_cond_t) % sizeof(void*) == 0, + "pthread_cond_t must have pointer alignment"); +#else + void* platformData_[4]; +#endif +}; + +} // namespace detail + +} // namespace mozilla + +#endif // mozilla_ConditionVariable_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/PlatformMutex.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/PlatformMutex.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/PlatformMutex.h @@ -0,0 +1,62 @@ +/* -*- 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_PlatformMutex_h +#define mozilla_PlatformMutex_h + +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" + +#if !defined(XP_WIN) +#include +#endif + +namespace mozilla { + +namespace detail { + +class ConditionVariableImpl; + +class MutexImpl { + public: + struct PlatformData; + + MFBT_API MutexImpl(); + MFBT_API ~MutexImpl(); + + bool operator==(const MutexImpl& rhs) { + return platformData_ == rhs.platformData_; + } + + protected: + MFBT_API void lock(); + MFBT_API void unlock(); + + private: + MutexImpl(const MutexImpl&) = delete; + void operator=(const MutexImpl&) = delete; + MutexImpl(MutexImpl&&) = delete; + void operator=(MutexImpl&&) = delete; + + PlatformData* platformData(); + +#if !defined(XP_WIN) + void* platformData_[sizeof(pthread_mutex_t) / sizeof(void*)]; + static_assert(sizeof(pthread_mutex_t) / sizeof(void*) != 0 && + sizeof(pthread_mutex_t) % sizeof(void*) == 0, + "pthread_mutex_t must have pointer alignment"); +#else + void* platformData_[6]; +#endif + + friend class mozilla::detail::ConditionVariableImpl; +}; + +} // namespace detail + +} // namespace mozilla + +#endif // mozilla_PlatformMutex_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/PodOperations.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/PodOperations.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/PodOperations.h @@ -25,18 +25,14 @@ namespace mozilla { /** Set the contents of |aT| to 0. */ -template -static MOZ_ALWAYS_INLINE void -PodZero(T* aT) -{ +template +static MOZ_ALWAYS_INLINE void PodZero(T* aT) { memset(aT, 0, sizeof(T)); } /** Set the contents of |aNElem| elements starting at |aT| to 0. */ -template -static MOZ_ALWAYS_INLINE void -PodZero(T* aT, size_t aNElem) -{ +template +static MOZ_ALWAYS_INLINE void PodZero(T* aT, size_t aNElem) { /* * This function is often called with 'aNElem' small; we use an inline loop * instead of calling 'memset' with a non-constant length. The compiler @@ -54,23 +50,19 @@ * ambiguous overload is left to catch mistaken uses of PodZero; if you get a * compile error involving PodZero and array types, use PodArrayZero instead. */ -template +template static void PodZero(T (&aT)[N]) = delete; -template +template static void PodZero(T (&aT)[N], size_t aNElem) = delete; /** Set the contents of the array |aT| to zero. */ template -static MOZ_ALWAYS_INLINE void -PodArrayZero(T (&aT)[N]) -{ +static MOZ_ALWAYS_INLINE void PodArrayZero(T (&aT)[N]) { memset(aT, 0, N * sizeof(T)); } template -static MOZ_ALWAYS_INLINE void -PodArrayZero(Array& aArr) -{ +static MOZ_ALWAYS_INLINE void PodArrayZero(Array& aArr) { memset(&aArr[0], 0, N * sizeof(T)); } @@ -78,10 +70,8 @@ * Assign |*aSrc| to |*aDst|. The locations must not be the same and must not * overlap. */ -template -static MOZ_ALWAYS_INLINE void -PodAssign(T* aDst, const T* aSrc) -{ +template +static MOZ_ALWAYS_INLINE void PodAssign(T* aDst, const T* aSrc) { MOZ_ASSERT(aDst + 1 <= aSrc || aSrc + 1 <= aDst, "destination and source must not overlap"); memcpy(reinterpret_cast(aDst), reinterpret_cast(aSrc), @@ -92,10 +82,8 @@ * Copy |aNElem| T elements from |aSrc| to |aDst|. The two memory ranges must * not overlap! */ -template -static MOZ_ALWAYS_INLINE void -PodCopy(T* aDst, const T* aSrc, size_t aNElem) -{ +template +static MOZ_ALWAYS_INLINE void PodCopy(T* aDst, const T* aSrc, size_t aNElem) { MOZ_ASSERT(aDst + aNElem <= aSrc || aSrc + aNElem <= aDst, "destination and source must not overlap"); if (aNElem < 128) { @@ -103,7 +91,7 @@ * Avoid using operator= in this loop, as it may have been * intentionally deleted by the POD type. */ - for (const T* srcend = aSrc + aNElem; aSrc < srcend; aSrc++, aDst++) { + for (const T *srcend = aSrc + aNElem; aSrc < srcend; aSrc++, aDst++) { PodAssign(aDst, aSrc); } } else { @@ -111,10 +99,9 @@ } } -template -static MOZ_ALWAYS_INLINE void -PodCopy(volatile T* aDst, const volatile T* aSrc, size_t aNElem) -{ +template +static MOZ_ALWAYS_INLINE void PodCopy(volatile T* aDst, const volatile T* aSrc, + size_t aNElem) { MOZ_ASSERT(aDst + aNElem <= aSrc || aSrc + aNElem <= aDst, "destination and source must not overlap"); @@ -124,8 +111,7 @@ * loops manually, using operator= rather than memcpy for the same reason, * and let the compiler optimize to the extent it can. */ - for (const volatile T* srcend = aSrc + aNElem; - aSrc < srcend; + for (const volatile T *srcend = aSrc + aNElem; aSrc < srcend; aSrc++, aDst++) { *aDst = *aSrc; } @@ -136,9 +122,7 @@ * The arrays must not overlap! */ template -static MOZ_ALWAYS_INLINE void -PodArrayCopy(T (&aDst)[N], const T (&aSrc)[N]) -{ +static MOZ_ALWAYS_INLINE void PodArrayCopy(T (&aDst)[N], const T (&aSrc)[N]) { PodCopy(aDst, aSrc, N); } @@ -148,10 +132,8 @@ * first copied from |aSrc| to a temporary array, and then from the temporary * array to |aDst|. */ -template -static MOZ_ALWAYS_INLINE void -PodMove(T* aDst, const T* aSrc, size_t aNElem) -{ +template +static MOZ_ALWAYS_INLINE void PodMove(T* aDst, const T* aSrc, size_t aNElem) { MOZ_ASSERT(aNElem <= SIZE_MAX / sizeof(T), "trying to move an impossible number of elements"); memmove(aDst, aSrc, aNElem * sizeof(T)); @@ -161,10 +143,8 @@ * Determine whether the |len| elements at |one| are memory-identical to the * |len| elements at |two|. */ -template -static MOZ_ALWAYS_INLINE bool -PodEqual(const T* one, const T* two, size_t len) -{ +template +static MOZ_ALWAYS_INLINE bool PodEqual(const T* one, const T* two, size_t len) { if (len < 128) { const T* p1end = one + len; const T* p1 = one; @@ -185,12 +165,10 @@ * |N| elements at |two|. */ template -static MOZ_ALWAYS_INLINE bool -PodEqual(const T (&one)[N], const T (&two)[N]) -{ +static MOZ_ALWAYS_INLINE bool PodEqual(const T (&one)[N], const T (&two)[N]) { return PodEqual(one, two, N); } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_PodOperations_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 @@ -16,6 +16,7 @@ #include "mozilla/Types.h" #include +#include MOZ_BEGIN_EXTERN_C @@ -24,10 +25,7 @@ /** * @return the poison value. */ -inline uintptr_t mozPoisonValue() -{ - return gMozillaPoisonValue; -} +inline uintptr_t mozPoisonValue() { return gMozillaPoisonValue; } /** * Overwrite the memory block of aSize bytes at aPtr with the poison value. @@ -35,15 +33,13 @@ * Only an even number of sizeof(uintptr_t) bytes are overwritten, the last * few bytes (if any) is not overwritten. */ -inline void mozWritePoison(void* aPtr, size_t aSize) -{ +inline void mozWritePoison(void* aPtr, size_t aSize) { const uintptr_t POISON = mozPoisonValue(); char* p = (char*)aPtr; - char* limit = p + aSize; - MOZ_ASSERT((uintptr_t)aPtr % sizeof(uintptr_t) == 0, "bad alignment"); + char* limit = p + (aSize & ~(sizeof(uintptr_t) - 1)); MOZ_ASSERT(aSize >= sizeof(uintptr_t), "poisoning this object has no effect"); for (; p < limit; p += sizeof(uintptr_t)) { - *((uintptr_t*)p) = POISON; + memcpy(p, &POISON, sizeof(POISON)); } } @@ -80,10 +76,8 @@ * various uses of the corrupted memory. */ class CorruptionCanary { -public: - CorruptionCanary() { - mValue = kCanarySet; - } + public: + CorruptionCanary() { mValue = kCanarySet; } ~CorruptionCanary() { Check(); @@ -96,12 +90,12 @@ } } -private: + private: static const uintptr_t kCanarySet = 0x0f0b0f0b; uintptr_t mValue; }; -} // mozilla +} // namespace mozilla #endif Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Printf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Printf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Printf.h @@ -0,0 +1,251 @@ +/* -*- 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/. */ + +/* Printf-like functions, with canned variants that malloc their result. */ + +#ifndef mozilla_Printf_h +#define mozilla_Printf_h + +/* +** API for PR printf like routines. +** +** These exist partly for historical reasons -- initially they were in +** NSPR, then forked in tree and modified in js/ -- but now the prime +** motivation is both closer control over the exact formatting (with +** one exception, see below) and also the ability to control where +** exactly the generated results are sent. +** +** It might seem that this could all be dispensed with in favor of a +** wrapper around |vsnprintf| -- except that this implementation +** guarantees that the %s format will accept a NULL pointer, whereas +** with standard functions this is undefined. +** +** This supports the following formats. It implements a subset of the +** standard formats; due to the use of MOZ_FORMAT_PRINTF, it is not +** permissible to extend the standard, aside from relaxing undefined +** behavior. +** +** %d - decimal +** %u - unsigned decimal +** %x - unsigned hex +** %X - unsigned uppercase hex +** %o - unsigned octal +** %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). +** Note that MSVC 2015 and newer supports the z length modifier so +** users should prefer using %z instead of %I. We are supporting %I in +** addition to %z in case third-party code that uses %I gets routed to +** use this printf implementation. +** %s - string +** %S, %ls - wide string, that is wchar_t* +** %c - character +** %p - pointer (deals with machine dependent pointer size) +** %f - float; note that this is actually formatted using the +** system's native printf, and so the results may vary +** %g - float; note that this is actually formatted using the +** system's native printf, and so the results may vary +*/ + +#include "mozilla/AllocPolicy.h" +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/IntegerPrintfMacros.h" +#include "mozilla/Types.h" +#include "mozilla/UniquePtr.h" + +#include +#include + +namespace mozilla { + +/* + * This class may be subclassed to provide a way to get the output of + * a printf-like call, as the output is generated. + */ +class PrintfTarget { + public: + /* The Printf-like interface. */ + bool MFBT_API print(const char* format, ...) MOZ_FORMAT_PRINTF(2, 3); + + /* The Vprintf-like interface. */ + bool MFBT_API vprint(const char* format, va_list) MOZ_FORMAT_PRINTF(2, 0); + + protected: + MFBT_API PrintfTarget(); + virtual ~PrintfTarget() {} + + /* Subclasses override this. It is called when more output is + available. It may be called with len==0. This should return + true on success, or false on failure. */ + virtual bool append(const char* sp, size_t len) = 0; + + private: + /* Number of bytes emitted so far. */ + size_t mEmitted; + + /* The implementation calls this to emit bytes and update + mEmitted. */ + bool emit(const char* sp, size_t len) { + mEmitted += len; + return append(sp, len); + } + + bool fill2(const char* src, int srclen, int width, int flags); + bool fill_n(const char* src, int srclen, int width, int prec, int type, + int flags); + bool cvt_l(long num, int width, int prec, int radix, int type, int flags, + const char* hxp); + bool cvt_ll(int64_t num, int width, int prec, int radix, int type, int flags, + const char* hexp); + bool cvt_f(double d, const char* fmt0, const char* fmt1); + bool cvt_s(const char* s, int width, int prec, int flags); +}; + +namespace detail { + +template +struct AllocPolicyBasedFreePolicy { + void operator()(const void* ptr) { + AllocPolicy policy; + policy.free_(const_cast(ptr)); + } +}; + +} // namespace detail + +// The type returned by Smprintf and friends. +template +using SmprintfPolicyPointer = + mozilla::UniquePtr>; + +// The default type if no alloc policy is specified. +typedef SmprintfPolicyPointer SmprintfPointer; + +// Used in the implementation of Smprintf et al. +template +class MOZ_STACK_CLASS SprintfState final : private mozilla::PrintfTarget, + private AllocPolicy { + public: + explicit SprintfState(char* base) + : mMaxlen(base ? strlen(base) : 0), + mBase(base), + mCur(base ? base + mMaxlen : 0) {} + + ~SprintfState() { this->free_(mBase); } + + bool vprint(const char* format, va_list ap_list) MOZ_FORMAT_PRINTF(2, 0) { + // The "" here has a single \0 character, which is what we're + // trying to append. + return mozilla::PrintfTarget::vprint(format, ap_list) && append("", 1); + } + + SmprintfPolicyPointer release() { + SmprintfPolicyPointer result(mBase); + mBase = nullptr; + return result; + } + + protected: + bool append(const char* sp, size_t len) override { + ptrdiff_t off; + char* newbase; + size_t newlen; + + off = mCur - mBase; + if (off + len >= mMaxlen) { + /* Grow the buffer */ + newlen = mMaxlen + ((len > 32) ? len : 32); + newbase = + static_cast(this->maybe_pod_realloc(mBase, mMaxlen, newlen)); + if (!newbase) { + /* Ran out of memory */ + return false; + } + mBase = newbase; + mMaxlen = newlen; + mCur = mBase + off; + } + + /* Copy data */ + memcpy(mCur, sp, len); + mCur += len; + MOZ_ASSERT(size_t(mCur - mBase) <= mMaxlen); + return true; + } + + private: + size_t mMaxlen; + char* mBase; + char* mCur; +}; + +/* +** sprintf into a malloc'd buffer. Return a pointer to the malloc'd +** buffer on success, nullptr on failure. Call AllocPolicy::free_ to release +** the memory returned. +*/ +template +MOZ_FORMAT_PRINTF(1, 2) +SmprintfPolicyPointer Smprintf(const char* fmt, ...) { + SprintfState ss(nullptr); + va_list ap; + va_start(ap, fmt); + bool r = ss.vprint(fmt, ap); + va_end(ap); + if (!r) { + return nullptr; + } + return ss.release(); +} + +/* +** "append" sprintf into a malloc'd buffer. "last" is the last value of +** the malloc'd buffer. sprintf will append data to the end of last, +** growing it as necessary using realloc. If last is nullptr, SmprintfAppend +** 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. +*/ +template +MOZ_FORMAT_PRINTF(2, 3) +SmprintfPolicyPointer SmprintfAppend( + SmprintfPolicyPointer&& last, const char* fmt, ...) { + SprintfState ss(last.release()); + va_list ap; + va_start(ap, fmt); + bool r = ss.vprint(fmt, ap); + va_end(ap); + if (!r) { + return nullptr; + } + return ss.release(); +} + +/* +** va_list forms of the above. +*/ +template +MOZ_FORMAT_PRINTF(1, 0) +SmprintfPolicyPointer Vsmprintf(const char* fmt, va_list ap) { + SprintfState ss(nullptr); + if (!ss.vprint(fmt, ap)) return nullptr; + return ss.release(); +} + +template +MOZ_FORMAT_PRINTF(2, 0) +SmprintfPolicyPointer VsmprintfAppend( + SmprintfPolicyPointer&& last, const char* fmt, va_list ap) { + SprintfState ss(last.release()); + if (!ss.vprint(fmt, ap)) return nullptr; + return ss.release(); +} + +} // namespace mozilla + +#endif /* mozilla_Printf_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 @@ -9,6 +9,7 @@ #include "mozilla/RangedPtr.h" #include "mozilla/TypeTraits.h" +#include "mozilla/Span.h" #include @@ -16,33 +17,34 @@ // Range is a tuple containing a pointer and a length. template -class Range -{ +class Range { const RangedPtr mStart; const RangedPtr mEnd; -public: + public: Range() : mStart(nullptr, 0), mEnd(nullptr, 0) {} Range(T* aPtr, size_t aLength) - : mStart(aPtr, aPtr, aPtr + aLength), - mEnd(aPtr + aLength, aPtr, aPtr + aLength) - {} + : 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()) - { + : 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> + template ::value, int>::Type> MOZ_IMPLICIT Range(const Range& aOther) - : mStart(aOther.mStart), - mEnd(aOther.mEnd) - {} + : mStart(aOther.mStart), mEnd(aOther.mEnd) {} + + MOZ_IMPLICIT Range(Span aSpan) : Range(aSpan.Elements(), aSpan.Length()) {} + + template ::value, int>::Type> + MOZ_IMPLICIT Range(const Span& aSpan) + : Range(aSpan.Elements(), aSpan.Length()) {} RangedPtr begin() const { return mStart; } RangedPtr end() const { return mEnd; } @@ -51,8 +53,22 @@ T& operator[](size_t aOffset) const { return mStart[aOffset]; } explicit operator bool() const { return mStart != nullptr; } + + operator Span() { return Span(mStart.get(), length()); } + + operator Span() const { return Span(mStart.get(), length()); } }; -} // namespace mozilla +template +Span MakeSpan(Range& aRange) { + return aRange; +} + +template +Span MakeSpan(const Range& aRange) { + return aRange; +} + +} // namespace mozilla #endif /* mozilla_Range_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/RangedArray.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/RangedArray.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/RangedArray.h @@ -19,29 +19,26 @@ namespace mozilla { -template -class RangedArray -{ -private: +template +class RangedArray { + private: typedef Array ArrayType; ArrayType mArr; -public: - T& operator[](size_t aIndex) - { + public: + T& operator[](size_t aIndex) { MOZ_ASSERT(aIndex == MinIndex || aIndex > MinIndex); return mArr[aIndex - MinIndex]; } - const T& operator[](size_t aIndex) const - { + const T& operator[](size_t aIndex) const { MOZ_ASSERT(aIndex == MinIndex || aIndex > MinIndex); return mArr[aIndex - MinIndex]; } - typedef typename ArrayType::iterator iterator; - typedef typename ArrayType::const_iterator const_iterator; - typedef typename ArrayType::reverse_iterator reverse_iterator; + typedef typename ArrayType::iterator iterator; + typedef typename ArrayType::const_iterator const_iterator; + typedef typename ArrayType::reverse_iterator reverse_iterator; typedef typename ArrayType::const_reverse_iterator const_reverse_iterator; // Methods for range-based for loops. @@ -61,6 +58,6 @@ const_reverse_iterator crend() const { return mArr.crend(); } }; -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_RangedArray_h +#endif // mozilla_RangedArray_h 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 @@ -39,9 +39,8 @@ * explicitly convert to T*. Keep in mind that the raw pointer of course won't * implement bounds checking in debug builds. */ -template -class RangedPtr -{ +template +class RangedPtr { T* mPtr; #ifdef DEBUG @@ -49,15 +48,13 @@ T* const mRangeEnd; #endif - void checkSanity() - { + void checkSanity() { MOZ_ASSERT(mRangeStart <= mPtr); MOZ_ASSERT(mPtr <= mRangeEnd); } /* Creates a new pointer for |aPtr|, restricted to this pointer's range. */ - RangedPtr create(T* aPtr) const - { + RangedPtr create(T* aPtr) const { #ifdef DEBUG return RangedPtr(aPtr, mRangeStart, mRangeEnd); #else @@ -67,20 +64,24 @@ uintptr_t asUintptr() const { return reinterpret_cast(mPtr); } -public: + public: RangedPtr(T* aPtr, T* aStart, T* aEnd) - : mPtr(aPtr) + : mPtr(aPtr) #ifdef DEBUG - , mRangeStart(aStart), mRangeEnd(aEnd) + , + mRangeStart(aStart), + mRangeEnd(aEnd) #endif { MOZ_ASSERT(mRangeStart <= mRangeEnd); checkSanity(); } RangedPtr(T* aPtr, T* aStart, size_t aLength) - : mPtr(aPtr) + : mPtr(aPtr) #ifdef DEBUG - , mRangeStart(aStart), mRangeEnd(aStart + aLength) + , + mRangeStart(aStart), + mRangeEnd(aStart + aLength) #endif { MOZ_ASSERT(aLength <= size_t(-1) / sizeof(T)); @@ -91,9 +92,11 @@ /* Equivalent to RangedPtr(aPtr, aPtr, aLength). */ RangedPtr(T* aPtr, size_t aLength) - : mPtr(aPtr) + : mPtr(aPtr) #ifdef DEBUG - , mRangeStart(aPtr), mRangeEnd(aPtr + aLength) + , + mRangeStart(aPtr), + mRangeEnd(aPtr + aLength) #endif { MOZ_ASSERT(aLength <= size_t(-1) / sizeof(T)); @@ -103,11 +106,13 @@ } /* Equivalent to RangedPtr(aArr, aArr, N). */ - template + template explicit RangedPtr(T (&aArr)[N]) - : mPtr(aArr) + : mPtr(aArr) #ifdef DEBUG - , mRangeStart(aArr), mRangeEnd(aArr + N) + , + mRangeStart(aArr), + mRangeEnd(aArr + N) #endif { checkSanity(); @@ -117,8 +122,7 @@ explicit operator bool() const { return mPtr != nullptr; } - void checkIdenticalRange(const RangedPtr& aOther) const - { + void checkIdenticalRange(const RangedPtr& aOther) const { MOZ_ASSERT(mRangeStart == aOther.mRangeStart); MOZ_ASSERT(mRangeEnd == aOther.mRangeEnd); } @@ -133,23 +137,20 @@ * p1 = RangedPtr(arr1 + 1, arr1, arr1 + 2); // works * p1 = RangedPtr(arr2, 3); // asserts */ - RangedPtr& operator=(const RangedPtr& aOther) - { + RangedPtr& operator=(const RangedPtr& aOther) { checkIdenticalRange(aOther); mPtr = aOther.mPtr; checkSanity(); return *this; } - RangedPtr operator+(size_t aInc) const - { + 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) const - { + RangedPtr operator-(size_t aDec) const { MOZ_ASSERT(aDec <= size_t(-1) / sizeof(T)); MOZ_ASSERT(asUintptr() - aDec * sizeof(T) <= asUintptr()); return create(mPtr - aDec); @@ -160,15 +161,13 @@ * within the range specified at creation. */ template - RangedPtr& operator=(U* aPtr) - { + RangedPtr& operator=(U* aPtr) { *this = create(aPtr); return *this; } template - RangedPtr& operator=(const RangedPtr& aPtr) - { + RangedPtr& operator=(const RangedPtr& aPtr) { MOZ_ASSERT(mRangeStart <= aPtr.mPtr); MOZ_ASSERT(aPtr.mPtr <= mRangeEnd); mPtr = aPtr.mPtr; @@ -176,115 +175,92 @@ return *this; } - RangedPtr& operator++() - { - return (*this += 1); - } + RangedPtr& operator++() { return (*this += 1); } - RangedPtr operator++(int) - { + RangedPtr operator++(int) { RangedPtr rcp = *this; ++*this; return rcp; } - RangedPtr& operator--() - { - return (*this -= 1); - } + RangedPtr& operator--() { return (*this -= 1); } - RangedPtr operator--(int) - { + RangedPtr operator--(int) { RangedPtr rcp = *this; --*this; return rcp; } - RangedPtr& operator+=(size_t aInc) - { + RangedPtr& operator+=(size_t aInc) { *this = *this + aInc; return *this; } - RangedPtr& operator-=(size_t aDec) - { + RangedPtr& operator-=(size_t aDec) { *this = *this - aDec; return *this; } - T& operator[](int aIndex) const - { + T& operator[](ptrdiff_t aIndex) const { MOZ_ASSERT(size_t(aIndex > 0 ? aIndex : -aIndex) <= size_t(-1) / sizeof(T)); return *create(mPtr + aIndex); } - T& operator*() const - { + T& operator*() const { MOZ_ASSERT(mPtr >= mRangeStart); MOZ_ASSERT(mPtr < mRangeEnd); return *mPtr; } - T* operator->() const - { + T* operator->() const { MOZ_ASSERT(mPtr >= mRangeStart); MOZ_ASSERT(mPtr < mRangeEnd); return mPtr; } template - bool operator==(const RangedPtr& aOther) const - { + bool operator==(const RangedPtr& aOther) const { return mPtr == aOther.mPtr; } template - bool operator!=(const RangedPtr& aOther) const - { + bool operator!=(const RangedPtr& aOther) const { return !(*this == aOther); } - template - bool operator==(const U* u) const - { + template + bool operator==(const U* u) const { return mPtr == u; } - template - bool operator!=(const U* u) const - { + template + bool operator!=(const U* u) const { return !(*this == u); } template - bool operator<(const RangedPtr& aOther) const - { + bool operator<(const RangedPtr& aOther) const { return mPtr < aOther.mPtr; } template - bool operator<=(const RangedPtr& aOther) const - { + bool operator<=(const RangedPtr& aOther) const { return mPtr <= aOther.mPtr; } template - bool operator>(const RangedPtr& aOther) const - { + bool operator>(const RangedPtr& aOther) const { return mPtr > aOther.mPtr; } template - bool operator>=(const RangedPtr& aOther) const - { + bool operator>=(const RangedPtr& aOther) const { return mPtr >= aOther.mPtr; } - size_t operator-(const RangedPtr& aOther) const - { + size_t operator-(const RangedPtr& aOther) const { MOZ_ASSERT(mPtr >= aOther.mPtr); return PointerRangeSize(aOther.mPtr, mPtr); } -private: + private: RangedPtr() = delete; - T* operator&() = delete; }; } /* namespace mozilla */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ReentrancyGuard.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ReentrancyGuard.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ReentrancyGuard.h @@ -16,22 +16,19 @@ namespace mozilla { /* Useful for implementing containers that assert non-reentrancy */ -class MOZ_RAII ReentrancyGuard -{ +class MOZ_RAII ReentrancyGuard { MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER #ifdef DEBUG bool& mEntered; #endif -public: - template + public: + template #ifdef DEBUG - explicit ReentrancyGuard(T& aObj - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mEntered(aObj.mEntered) + explicit ReentrancyGuard(T& aObj MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mEntered(aObj.mEntered) #else - explicit ReentrancyGuard(T& - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + explicit ReentrancyGuard(T& MOZ_GUARD_OBJECT_NOTIFIER_PARAM) #endif { MOZ_GUARD_OBJECT_NOTIFIER_INIT; @@ -40,18 +37,17 @@ mEntered = true; #endif } - ~ReentrancyGuard() - { + ~ReentrancyGuard() { #ifdef DEBUG mEntered = false; #endif } -private: + private: ReentrancyGuard(const ReentrancyGuard&) = delete; void operator=(const ReentrancyGuard&) = delete; }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_ReentrancyGuard_h */ 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 @@ -17,6 +17,8 @@ #include "mozilla/RefCountType.h" #include "mozilla/TypeTraits.h" +#include + #if defined(MOZILLA_INTERNAL_API) #include "nsXPCOM.h" #endif @@ -52,6 +54,9 @@ * Note that when deriving from RefCounted or AtomicRefCounted, you * should add MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public * section of your class, where ClassName is the name of your class. + * + * Note: SpiderMonkey should use js::RefCounted instead since that type + * will use appropriate js_delete and also not break ref-count logging. */ namespace detail { const MozRefCountType DEAD = 0xffffdead; @@ -59,20 +64,17 @@ // When building code that gets compiled into Gecko, try to use the // trace-refcount leak logging facilities. #ifdef MOZ_REFCOUNTED_LEAK_CHECKING -class RefCountLogger -{ -public: +class RefCountLogger { + public: static void logAddRef(const void* aPointer, MozRefCountType aRefCount, - const char* aTypeName, uint32_t aInstanceSize) - { + const char* aTypeName, uint32_t aInstanceSize) { MOZ_ASSERT(aRefCount != DEAD); NS_LogAddRef(const_cast(aPointer), aRefCount, aTypeName, aInstanceSize); } static void logRelease(const void* aPointer, MozRefCountType aRefCount, - const char* aTypeName) - { + const char* aTypeName) { MOZ_ASSERT(aRefCount != DEAD); NS_LogRelease(const_cast(aPointer), aRefCount, aTypeName); } @@ -80,23 +82,82 @@ #endif // This is used WeakPtr.h as well as this file. -enum RefCountAtomicity -{ - AtomicRefCount, - NonAtomicRefCount +enum RefCountAtomicity { AtomicRefCount, NonAtomicRefCount }; + +template +class RC { + public: + explicit RC(T aCount) : mValue(aCount) {} + + T operator++() { return ++mValue; } + T operator--() { return --mValue; } + + void operator=(const T& aValue) { mValue = aValue; } + + operator T() const { return mValue; } + + private: + T mValue; +}; + +template +class RC { + public: + explicit RC(T aCount) : mValue(aCount) {} + + T operator++() { + // Memory synchronization is not required when incrementing a + // reference count. The first increment of a reference count on a + // thread is not important, since the first use of the object on a + // thread can happen before it. What is important is the transfer + // of the pointer to that thread, which may happen prior to the + // first increment on that thread. The necessary memory + // synchronization is done by the mechanism that transfers the + // pointer between threads. + return mValue.fetch_add(1, std::memory_order_relaxed) + 1; + } + + T operator--() { + // Since this may be the last release on this thread, we need + // release semantics so that prior writes on this thread are visible + // to the thread that destroys the object when it reads mValue with + // acquire semantics. + T result = mValue.fetch_sub(1, std::memory_order_release) - 1; + if (result == 0) { + // We're going to destroy the object on this thread, so we need + // acquire semantics to synchronize with the memory released by + // the last release on other threads, that is, to ensure that + // writes prior to that release are now visible on this thread. + std::atomic_thread_fence(std::memory_order_acquire); + } + return result; + } + + // This method is only called in debug builds, so we're not too concerned + // about its performance. + void operator=(const T& aValue) { + mValue.store(aValue, std::memory_order_seq_cst); + } + + operator T() const { + // Use acquire semantics since we're not sure what the caller is + // doing. + return mValue.load(std::memory_order_acquire); + } + + private: + std::atomic mValue; }; -template -class RefCounted -{ -protected: +template +class RefCounted { + protected: RefCounted() : mRefCnt(0) {} ~RefCounted() { MOZ_ASSERT(mRefCnt == detail::DEAD); } -public: + public: // Compatibility with nsRefPtr. - void AddRef() const - { + void AddRef() const { // Note: this method must be thread safe for AtomicRefCounted. MOZ_ASSERT(int32_t(mRefCnt) >= 0); #ifndef MOZ_REFCOUNTED_LEAK_CHECKING @@ -110,8 +171,7 @@ #endif } - void Release() const - { + void Release() const { // Note: this method must be thread safe for AtomicRefCounted. MOZ_ASSERT(int32_t(mRefCnt) > 0); #ifndef MOZ_REFCOUNTED_LEAK_CHECKING @@ -125,10 +185,10 @@ detail::RefCountLogger::logRelease(ptr, cnt, type); #endif if (0 == cnt) { - // Because we have atomically decremented the refcount above, only - // one thread can get a 0 count here, so as long as we can assume that - // everything else in the system is accessing this object through - // RefPtrs, it's safe to access |this| here. + // Because we have atomically decremented the refcount above, only + // one thread can get a 0 count here, so as long as we can assume that + // everything else in the system is accessing this object through + // RefPtrs, it's safe to access |this| here. #ifdef DEBUG mRefCnt = detail::DEAD; #endif @@ -140,22 +200,19 @@ void ref() { AddRef(); } void deref() { Release(); } MozRefCountType refCount() const { return mRefCnt; } - bool hasOneRef() const - { + bool hasOneRef() const { MOZ_ASSERT(mRefCnt > 0); return mRefCnt == 1; } -private: - mutable typename Conditional, - MozRefCountType>::Type mRefCnt; + private: + mutable RC mRefCnt; }; #ifdef MOZ_REFCOUNTED_LEAK_CHECKING // Passing override for the optional argument marks the typeName and // typeSize functions defined by this macro as overrides. -#define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T, ...) \ +#define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T, ...) \ virtual const char* typeName() const __VA_ARGS__ { return #T; } \ virtual size_t typeSize() const __VA_ARGS__ { return sizeof(*this); } #else @@ -165,18 +222,16 @@ // Note that this macro is expanded unconditionally because it declares only // two small inline functions which will hopefully get eliminated by the linker // in non-leak-checking builds. -#define MOZ_DECLARE_REFCOUNTED_TYPENAME(T) \ +#define MOZ_DECLARE_REFCOUNTED_TYPENAME(T) \ const char* typeName() const { return #T; } \ size_t typeSize() const { return sizeof(*this); } -} // namespace detail +} // namespace detail -template -class RefCounted : public detail::RefCounted -{ -public: - ~RefCounted() - { +template +class RefCounted : public detail::RefCounted { + public: + ~RefCounted() { static_assert(IsBaseOf::value, "T must derive from RefCounted"); } @@ -191,20 +246,18 @@ * NOTE: Please do not use this class, use NS_INLINE_DECL_THREADSAFE_REFCOUNTING * instead. */ -template -class AtomicRefCounted : - public mozilla::detail::RefCounted -{ -public: - ~AtomicRefCounted() - { +template +class AtomicRefCounted + : public mozilla::detail::RefCounted { + public: + ~AtomicRefCounted() { static_assert(IsBaseOf::value, "T must derive from AtomicRefCounted"); } }; -} // namespace external +} // namespace external -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_RefCounted_h +#endif // mozilla_RefCounted_h 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 @@ -15,11 +15,14 @@ // template class RefPtrGetterAddRefs; +class nsQueryReferent; class nsCOMPtr_helper; namespace mozilla { -template class OwningNonNull; -template class StaticRefPtr; +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. @@ -30,35 +33,25 @@ // // 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(); - } +template +struct RefPtrTraits { + static void AddRef(U* aPtr) { aPtr->AddRef(); } + static void Release(U* aPtr) { aPtr->Release(); } }; -} // namespace mozilla +} // namespace mozilla template -class RefPtr -{ -private: - void - assign_with_AddRef(T* aRawPtr) - { +class MOZ_IS_REFPTR RefPtr { + private: + void assign_with_AddRef(T* aRawPtr) { if (aRawPtr) { ConstRemovingRefPtrTraits::AddRef(aRawPtr); } assign_assuming_AddRef(aRawPtr); } - void - assign_assuming_AddRef(T* aNewPtr) - { + void assign_assuming_AddRef(T* aNewPtr) { T* oldPtr = mRawPtr; mRawPtr = aNewPtr; if (oldPtr) { @@ -66,14 +59,13 @@ } } -private: + private: T* MOZ_OWNING_REF mRawPtr; -public: + public: typedef T element_type; - ~RefPtr() - { + ~RefPtr() { if (mRawPtr) { ConstRemovingRefPtrTraits::Release(mRawPtr); } @@ -82,59 +74,49 @@ // Constructors RefPtr() - : mRawPtr(nullptr) - // default constructor - { - } + : mRawPtr(nullptr) + // default constructor + {} RefPtr(const RefPtr& aSmartPtr) - : mRawPtr(aSmartPtr.mRawPtr) - // copy-constructor + : mRawPtr(aSmartPtr.mRawPtr) + // copy-constructor { if (mRawPtr) { ConstRemovingRefPtrTraits::AddRef(mRawPtr); } } - RefPtr(RefPtr&& aRefPtr) - : mRawPtr(aRefPtr.mRawPtr) - { + RefPtr(RefPtr&& aRefPtr) : mRawPtr(aRefPtr.mRawPtr) { aRefPtr.mRawPtr = nullptr; } // construct from a raw pointer (of the right type) - MOZ_IMPLICIT RefPtr(T* aRawPtr) - : mRawPtr(aRawPtr) - { + MOZ_IMPLICIT RefPtr(T* aRawPtr) : mRawPtr(aRawPtr) { if (mRawPtr) { ConstRemovingRefPtrTraits::AddRef(mRawPtr); } } - MOZ_IMPLICIT RefPtr(decltype(nullptr)) - : mRawPtr(nullptr) - { - } + MOZ_IMPLICIT RefPtr(decltype(nullptr)) : mRawPtr(nullptr) {} template MOZ_IMPLICIT RefPtr(already_AddRefed& aSmartPtr) - : mRawPtr(aSmartPtr.take()) - // construct from |already_AddRefed| - { - } + : mRawPtr(aSmartPtr.take()) + // construct from |already_AddRefed| + {} template MOZ_IMPLICIT RefPtr(already_AddRefed&& aSmartPtr) - : mRawPtr(aSmartPtr.take()) - // construct from |otherRefPtr.forget()| - { - } + : mRawPtr(aSmartPtr.take()) + // construct from |otherRefPtr.forget()| + {} template MOZ_IMPLICIT RefPtr(const RefPtr& aSmartPtr) - : mRawPtr(aSmartPtr.get()) - // copy-construct from a smart pointer with a related pointer type + : mRawPtr(aSmartPtr.get()) + // copy-construct from a smart pointer with a related pointer type { if (mRawPtr) { ConstRemovingRefPtrTraits::AddRef(mRawPtr); @@ -143,32 +125,29 @@ template MOZ_IMPLICIT RefPtr(RefPtr&& aSmartPtr) - : mRawPtr(aSmartPtr.forget().take()) - // construct from |Move(RefPtr)|. - { - } + : mRawPtr(aSmartPtr.forget().take()) + // construct from |Move(RefPtr)|. + {} + MOZ_IMPLICIT RefPtr(const nsQueryReferent& aHelper); MOZ_IMPLICIT RefPtr(const nsCOMPtr_helper& aHelper); // Defined in OwningNonNull.h - template + template MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull& aOther); // Defined in StaticPtr.h - template + template MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr& aOther); // Assignment operators - RefPtr& - operator=(decltype(nullptr)) - { + RefPtr& operator=(decltype(nullptr)) { assign_assuming_AddRef(nullptr); return *this; } - RefPtr& - operator=(const RefPtr& aRhs) + RefPtr& operator=(const RefPtr& aRhs) // copy assignment operator { assign_with_AddRef(aRhs.mRawPtr); @@ -176,16 +155,14 @@ } template - RefPtr& - operator=(const RefPtr& aRhs) + RefPtr& operator=(const RefPtr& aRhs) // assign from an RefPtr of a related pointer type { assign_with_AddRef(aRhs.get()); return *this; } - RefPtr& - operator=(T* aRhs) + RefPtr& operator=(T* aRhs) // assign from a raw pointer (of the right type) { assign_with_AddRef(aRhs); @@ -193,8 +170,7 @@ } template - RefPtr& - operator=(already_AddRefed& aRhs) + RefPtr& operator=(already_AddRefed& aRhs) // assign from |already_AddRefed| { assign_assuming_AddRef(aRhs.take()); @@ -202,38 +178,33 @@ } template - RefPtr& - operator=(already_AddRefed && aRhs) + RefPtr& operator=(already_AddRefed&& aRhs) // assign from |otherRefPtr.forget()| { assign_assuming_AddRef(aRhs.take()); return *this; } + RefPtr& operator=(const nsQueryReferent& aQueryReferent); RefPtr& operator=(const nsCOMPtr_helper& aHelper); - RefPtr& - operator=(RefPtr && aRefPtr) - { + RefPtr& operator=(RefPtr&& aRefPtr) { assign_assuming_AddRef(aRefPtr.mRawPtr); aRefPtr.mRawPtr = nullptr; return *this; } // Defined in OwningNonNull.h - template - RefPtr& - operator=(const mozilla::OwningNonNull& aOther); + template + RefPtr& operator=(const mozilla::OwningNonNull& aOther); // Defined in StaticPtr.h - template - RefPtr& - operator=(const mozilla::StaticRefPtr& aOther); + template + RefPtr& operator=(const mozilla::StaticRefPtr& aOther); // Other pointer operators - void - swap(RefPtr& aRhs) + void swap(RefPtr& aRhs) // ...exchange ownership with |aRhs|; can save a pair of refcount operations { T* temp = aRhs.mRawPtr; @@ -241,8 +212,7 @@ mRawPtr = temp; } - void - swap(T*& aRhs) + void swap(T*& aRhs) // ...exchange ownership with |aRhs|; can save a pair of refcount operations { T* temp = aRhs; @@ -250,8 +220,7 @@ mRawPtr = temp; } - already_AddRefed - forget() + already_AddRefed MOZ_MAY_CALL_AFTER_MUST_RETURN forget() // return the value of mRawPtr and null out mRawPtr. Useful for // already_AddRefed return values. { @@ -261,8 +230,7 @@ } template - void - forget(I** aRhs) + void forget(I** aRhs) // Set the target of aRhs to the value of mRawPtr and null out mRawPtr. // Useful to avoid unnecessary AddRef/Release pairs with "out" // parameters where aRhs bay be a T** or an I** where I is a base class @@ -273,20 +241,16 @@ mRawPtr = nullptr; } - T* - get() const + T* get() const /* - Prefer the implicit conversion provided automatically by |operator T*() const|. - Use |get()| to resolve ambiguity or to get a castable pointer. + Prefer the implicit conversion provided automatically by |operator T*() + const|. Use |get()| to resolve ambiguity or to get a castable pointer. */ { return const_cast(mRawPtr); } - operator T*() const -#ifdef MOZ_HAVE_REF_QUALIFIERS - & -#endif + operator T*() const & /* ...makes an |RefPtr| act like its underlying raw pointer type whenever it is used in a context where a raw pointer is expected. It is this operator @@ -299,7 +263,6 @@ return get(); } -#ifdef MOZ_HAVE_REF_QUALIFIERS // Don't allow implicit conversion of temporary RefPtr to raw pointer, // because the refcount might be one and the pointer will immediately become // invalid. @@ -310,75 +273,62 @@ // operator bool instead of the deleted operator T*? explicit operator bool() const { return !!mRawPtr; } bool operator!() const { return !mRawPtr; } -#endif - T* - operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN - { + T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL RefPtr with operator->()."); return get(); } template - class Proxy - { + class Proxy { typedef R (T::*member_function)(Args...); T* mRawPtr; member_function mFunction; - public: + + public: Proxy(T* aRawPtr, member_function aFunction) - : mRawPtr(aRawPtr), - mFunction(aFunction) - { - } - template - R operator()(ActualArgs&&... aArgs) - { + : mRawPtr(aRawPtr), mFunction(aFunction) {} + template + R operator()(ActualArgs&&... aArgs) { return ((*mRawPtr).*mFunction)(mozilla::Forward(aArgs)...); } }; template - Proxy operator->*(R (T::*aFptr)(Args...)) const - { + Proxy operator->*(R (T::*aFptr)(Args...)) const { MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL RefPtr with operator->*()."); return Proxy(get(), aFptr); } - RefPtr* - get_address() + RefPtr* get_address() // This is not intended to be used by clients. See |address_of| // below. { return this; } - const RefPtr* - get_address() const + const RefPtr* get_address() const // This is not intended to be used by clients. See |address_of| // below. { return this; } -public: - T& - operator*() const - { + public: + T& operator*() const { MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL RefPtr with operator*()."); return *get(); } - T** - StartAssignment() - { + T** StartAssignment() { assign_assuming_AddRef(nullptr); return reinterpret_cast(&mRawPtr); } -private: + + private: // This helper class makes |RefPtr| possible by casting away // the constness from the pointer when calling AddRef() and Release(). // @@ -389,19 +339,13 @@ // 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). - template - struct ConstRemovingRefPtrTraits - { - static void AddRef(U* aPtr) { - mozilla::RefPtrTraits::AddRef(aPtr); - } - static void Release(U* aPtr) { - mozilla::RefPtrTraits::Release(aPtr); - } + template + struct ConstRemovingRefPtrTraits { + static void AddRef(U* aPtr) { mozilla::RefPtrTraits::AddRef(aPtr); } + static void Release(U* aPtr) { mozilla::RefPtrTraits::Release(aPtr); } }; - template - struct ConstRemovingRefPtrTraits - { + template + struct ConstRemovingRefPtrTraits { static void AddRef(const U* aPtr) { mozilla::RefPtrTraits::AddRef(const_cast(aPtr)); } @@ -413,38 +357,28 @@ class nsCycleCollectionTraversalCallback; template -void -CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback, - T* aChild, const char* aName, uint32_t aFlags); +void CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback, + T* aChild, const char* aName, uint32_t aFlags); template -inline void -ImplCycleCollectionUnlink(RefPtr& aField) -{ +inline void ImplCycleCollectionUnlink(RefPtr& aField) { aField = nullptr; } template -inline void -ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, - RefPtr& aField, - const char* aName, - uint32_t aFlags = 0) -{ +inline void ImplCycleCollectionTraverse( + nsCycleCollectionTraversalCallback& aCallback, RefPtr& aField, + const char* aName, uint32_t aFlags = 0) { CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags); } template -inline RefPtr* -address_of(RefPtr& aPtr) -{ +inline RefPtr* address_of(RefPtr& aPtr) { return aPtr.get_address(); } template -inline const RefPtr* -address_of(const RefPtr& aPtr) -{ +inline const RefPtr* address_of(const RefPtr& aPtr) { return aPtr.get_address(); } @@ -468,37 +402,26 @@ This type should be a nested class inside |RefPtr|. */ { -public: - explicit - RefPtrGetterAddRefs(RefPtr& aSmartPtr) - : mTargetSmartPtr(aSmartPtr) - { + public: + explicit RefPtrGetterAddRefs(RefPtr& aSmartPtr) + : mTargetSmartPtr(aSmartPtr) { // nothing else to do } - operator void**() - { + operator void**() { return reinterpret_cast(mTargetSmartPtr.StartAssignment()); } - operator T**() - { - return mTargetSmartPtr.StartAssignment(); - } + operator T**() { return mTargetSmartPtr.StartAssignment(); } - T*& - operator*() - { - return *(mTargetSmartPtr.StartAssignment()); - } + T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); } -private: + private: RefPtr& mTargetSmartPtr; }; template -inline RefPtrGetterAddRefs -getter_AddRefs(RefPtr& aSmartPtr) +inline RefPtrGetterAddRefs getter_AddRefs(RefPtr& aSmartPtr) /* Used around a |RefPtr| when ...makes the class |RefPtrGetterAddRefs| invisible. @@ -507,127 +430,92 @@ return RefPtrGetterAddRefs(aSmartPtr); } - // Comparing two |RefPtr|s template -inline bool -operator==(const RefPtr& aLhs, const RefPtr& aRhs) -{ +inline bool operator==(const RefPtr& aLhs, const RefPtr& aRhs) { return static_cast(aLhs.get()) == static_cast(aRhs.get()); } - template -inline bool -operator!=(const RefPtr& aLhs, const RefPtr& aRhs) -{ +inline bool operator!=(const RefPtr& aLhs, const RefPtr& aRhs) { return static_cast(aLhs.get()) != static_cast(aRhs.get()); } - // Comparing an |RefPtr| to a raw pointer template -inline bool -operator==(const RefPtr& aLhs, const U* aRhs) -{ +inline bool operator==(const RefPtr& aLhs, const U* aRhs) { return static_cast(aLhs.get()) == static_cast(aRhs); } template -inline bool -operator==(const U* aLhs, const RefPtr& aRhs) -{ +inline bool operator==(const U* aLhs, const RefPtr& aRhs) { return static_cast(aLhs) == static_cast(aRhs.get()); } template -inline bool -operator!=(const RefPtr& aLhs, const U* aRhs) -{ +inline bool operator!=(const RefPtr& aLhs, const U* aRhs) { return static_cast(aLhs.get()) != static_cast(aRhs); } template -inline bool -operator!=(const U* aLhs, const RefPtr& aRhs) -{ +inline bool operator!=(const U* aLhs, const RefPtr& aRhs) { return static_cast(aLhs) != static_cast(aRhs.get()); } template -inline bool -operator==(const RefPtr& aLhs, U* aRhs) -{ +inline bool operator==(const RefPtr& aLhs, U* aRhs) { return static_cast(aLhs.get()) == const_cast(aRhs); } template -inline bool -operator==(U* aLhs, const RefPtr& aRhs) -{ +inline bool operator==(U* aLhs, const RefPtr& aRhs) { return const_cast(aLhs) == static_cast(aRhs.get()); } template -inline bool -operator!=(const RefPtr& aLhs, U* aRhs) -{ +inline bool operator!=(const RefPtr& aLhs, U* aRhs) { return static_cast(aLhs.get()) != const_cast(aRhs); } template -inline bool -operator!=(U* aLhs, const RefPtr& aRhs) -{ +inline bool operator!=(U* aLhs, const RefPtr& aRhs) { return const_cast(aLhs) != static_cast(aRhs.get()); } // Comparing an |RefPtr| to |nullptr| template -inline bool -operator==(const RefPtr& aLhs, decltype(nullptr)) -{ +inline bool operator==(const RefPtr& aLhs, decltype(nullptr)) { return aLhs.get() == nullptr; } template -inline bool -operator==(decltype(nullptr), const RefPtr& aRhs) -{ +inline bool operator==(decltype(nullptr), const RefPtr& aRhs) { return nullptr == aRhs.get(); } template -inline bool -operator!=(const RefPtr& aLhs, decltype(nullptr)) -{ +inline bool operator!=(const RefPtr& aLhs, decltype(nullptr)) { return aLhs.get() != nullptr; } template -inline bool -operator!=(decltype(nullptr), const RefPtr& aRhs) -{ +inline bool operator!=(decltype(nullptr), const RefPtr& aRhs) { return nullptr != aRhs.get(); } /*****************************************************************************/ template -inline already_AddRefed -do_AddRef(T* aObj) -{ +inline already_AddRefed do_AddRef(T* aObj) { RefPtr ref(aObj); return ref.forget(); } template -inline already_AddRefed -do_AddRef(const RefPtr& aObj) -{ +inline already_AddRefed do_AddRef(const RefPtr& aObj) { RefPtr ref(aObj); return ref.forget(); } @@ -643,14 +531,25 @@ * return MakeAndAddRef(...); * } */ -template -already_AddRefed -MakeAndAddRef(Args&&... aArgs) -{ +template +already_AddRefed MakeAndAddRef(Args&&... aArgs) { RefPtr p(new T(Forward(aArgs)...)); return p.forget(); } -} // namespace mozilla +/** + * Helper function to be able to conveniently write things like: + * + * auto runnable = + * MakeRefPtr>( + * mOnSuccess, mOnFailure, *error, mWindowID); + */ +template +RefPtr MakeRefPtr(Args&&... aArgs) { + RefPtr p(new T(Forward(aArgs)...)); + return p; +} + +} // namespace mozilla #endif /* mozilla_RefPtr_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Result.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Result.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Result.h @@ -0,0 +1,463 @@ +/* -*- 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/. */ + +/* A type suitable for returning either a value or an error from a function. */ + +#ifndef mozilla_Result_h +#define mozilla_Result_h + +#include "mozilla/Alignment.h" +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Types.h" +#include "mozilla/TypeTraits.h" +#include "mozilla/Variant.h" + +namespace mozilla { + +/** + * Empty struct, indicating success for operations that have no return value. + * For example, if you declare another empty struct `struct OutOfMemory {};`, + * then `Result` represents either success or OOM. + */ +struct Ok {}; + +template +class GenericErrorResult; +template +class Result; + +namespace detail { + +enum class PackingStrategy { + Variant, + NullIsOk, + LowBitTagIsError, + PackedVariant, +}; + +template +class ResultImplementation; + +template +class ResultImplementation { + mozilla::Variant mStorage; + + public: + explicit ResultImplementation(V aValue) : mStorage(aValue) {} + explicit ResultImplementation(E aErrorValue) : mStorage(aErrorValue) {} + + bool isOk() const { return mStorage.template is(); } + + // The callers of these functions will assert isOk() has the proper value, so + // these functions (in all ResultImplementation specializations) don't need + // to do so. + V unwrap() const { return mStorage.template as(); } + E unwrapErr() const { return mStorage.template as(); } +}; + +/** + * mozilla::Variant doesn't like storing a reference. This is a specialization + * to store E as pointer if it's a reference. + */ +template +class ResultImplementation { + mozilla::Variant mStorage; + + public: + explicit ResultImplementation(V aValue) : mStorage(aValue) {} + explicit ResultImplementation(E& aErrorValue) : mStorage(&aErrorValue) {} + + bool isOk() const { return mStorage.template is(); } + V unwrap() const { return mStorage.template as(); } + E& unwrapErr() const { return *mStorage.template as(); } +}; + +/** + * Specialization for when the success type is Ok (or another empty class) and + * the error type is a reference. + */ +template +class ResultImplementation { + E* mErrorValue; + + public: + explicit ResultImplementation(V) : mErrorValue(nullptr) {} + explicit ResultImplementation(E& aErrorValue) : mErrorValue(&aErrorValue) {} + + bool isOk() const { return mErrorValue == nullptr; } + + V unwrap() const { return V(); } + E& unwrapErr() const { return *mErrorValue; } +}; + +/** + * Specialization for when the success type is Ok (or another empty class) and + * the error type is a value type which can never have the value 0 (as + * determined by UnusedZero<>). + */ +template +class ResultImplementation { + static constexpr E NullValue = E(0); + + E mErrorValue; + + public: + explicit ResultImplementation(V) : mErrorValue(NullValue) {} + explicit ResultImplementation(E aErrorValue) : mErrorValue(aErrorValue) { + MOZ_ASSERT(aErrorValue != NullValue); + } + + bool isOk() const { return mErrorValue == NullValue; } + + V unwrap() const { return V(); } + E unwrapErr() const { return mErrorValue; } +}; + +/** + * Specialization for when alignment permits using the least significant bit as + * a tag bit. + */ +template +class ResultImplementation { + uintptr_t mBits; + + public: + explicit ResultImplementation(V* aValue) + : mBits(reinterpret_cast(aValue)) { + MOZ_ASSERT((uintptr_t(aValue) % MOZ_ALIGNOF(V)) == 0, + "Result value pointers must not be misaligned"); + } + explicit ResultImplementation(E& aErrorValue) + : mBits(reinterpret_cast(&aErrorValue) | 1) { + MOZ_ASSERT((uintptr_t(&aErrorValue) % MOZ_ALIGNOF(E)) == 0, + "Result errors must not be misaligned"); + } + + bool isOk() const { return (mBits & 1) == 0; } + + V* unwrap() const { return reinterpret_cast(mBits); } + E& unwrapErr() const { return *reinterpret_cast(mBits ^ 1); } +}; + +// Return true if any of the struct can fit in a word. +template +struct IsPackableVariant { + struct VEbool { + V v; + E e; + bool ok; + }; + struct EVbool { + E e; + V v; + bool ok; + }; + + using Impl = typename Conditional::Type; + + static const bool value = sizeof(Impl) <= sizeof(uintptr_t); +}; + +/** + * Specialization for when both type are not using all the bytes, in order to + * use one byte as a tag. + */ +template +class ResultImplementation { + using Impl = typename IsPackableVariant::Impl; + Impl data; + + public: + explicit ResultImplementation(V aValue) { + data.v = aValue; + data.ok = true; + } + explicit ResultImplementation(E aErrorValue) { + data.e = aErrorValue; + data.ok = false; + } + + bool isOk() const { return data.ok; } + + V unwrap() const { return data.v; } + E unwrapErr() const { return data.e; } +}; + +// To use nullptr as a special value, we need the counter part to exclude zero +// from its range of valid representations. +// +// By default assume that zero can be represented. +template +struct UnusedZero { + static const bool value = false; +}; + +// References can't be null. +template +struct UnusedZero { + static const bool value = true; +}; + +// A bit of help figuring out which of the above specializations to use. +// +// We begin by safely assuming types don't have a spare bit. +template +struct HasFreeLSB { + static const bool value = false; +}; + +// The lowest bit of a properly-aligned pointer is always zero if the pointee +// type is greater than byte-aligned. That bit is free to use if it's masked +// out of such pointers before they're dereferenced. +template +struct HasFreeLSB { + static const bool value = (MOZ_ALIGNOF(T) & 1) == 0; +}; + +// We store references as pointers, so they have a free bit if a pointer would +// have one. +template +struct HasFreeLSB { + static const bool value = HasFreeLSB::value; +}; + +// Select one of the previous result implementation based on the properties of +// the V and E types. +template +struct SelectResultImpl { + static const PackingStrategy value = + (IsEmpty::value && UnusedZero::value) + ? PackingStrategy::NullIsOk + : (detail::HasFreeLSB::value && detail::HasFreeLSB::value) + ? PackingStrategy::LowBitTagIsError + : (IsDefaultConstructible::value && + IsDefaultConstructible::value && + IsPackableVariant::value) + ? PackingStrategy::PackedVariant + : PackingStrategy::Variant; + + using Type = detail::ResultImplementation; +}; + +template +struct IsResult : FalseType {}; + +template +struct IsResult> : TrueType {}; + +} // namespace detail + +template +auto ToResult(Result&& aValue) + -> decltype(Forward>(aValue)) { + return Forward>(aValue); +} + +/** + * Result represents the outcome of an operation that can either succeed + * or fail. It contains either a success value of type V or an error value of + * type E. + * + * All Result methods are const, so results are basically immutable. + * This is just like Variant but with a slightly different API, and the + * following cases are optimized so Result can be stored more efficiently: + * + * - If the success type is Ok (or another empty class) and the error type is a + * reference, Result is guaranteed to be pointer-sized and all zero + * bits on success. Do not change this representation! There is JIT code that + * depends on it. + * + * - If the success type is a pointer type and the error type is a reference + * type, and the least significant bit is unused for both types when stored + * as a pointer (due to alignment rules), Result is guaranteed to be + * pointer-sized. In this case, we use the lowest bit as tag bit: 0 to + * indicate the Result's bits are a V, 1 to indicate the Result's bits (with + * the 1 masked out) encode an E*. + * + * The purpose of Result is to reduce the screwups caused by using `false` or + * `nullptr` to indicate errors. + * What screwups? See for + * a partial list. + */ +template +class MOZ_MUST_USE_TYPE Result final { + using Impl = typename detail::SelectResultImpl::Type; + + Impl mImpl; + + public: + /** + * Create a success result. + */ + MOZ_IMPLICIT Result(V aValue) : mImpl(aValue) { MOZ_ASSERT(isOk()); } + + /** + * Create an error result. + */ + explicit Result(E aErrorValue) : mImpl(aErrorValue) { MOZ_ASSERT(isErr()); } + + /** + * Implementation detail of MOZ_TRY(). + * Create an error result from another error result. + */ + template + MOZ_IMPLICIT Result(const GenericErrorResult& aErrorResult) + : mImpl(aErrorResult.mErrorValue) { + static_assert(mozilla::IsConvertible::value, + "E2 must be convertible to E"); + MOZ_ASSERT(isErr()); + } + + Result(const Result&) = default; + Result& operator=(const Result&) = default; + + /** True if this Result is a success result. */ + bool isOk() const { return mImpl.isOk(); } + + /** True if this Result is an error result. */ + bool isErr() const { return !mImpl.isOk(); } + + /** Get the success value from this Result, which must be a success result. */ + V unwrap() const { + MOZ_ASSERT(isOk()); + return mImpl.unwrap(); + } + + /** + * Get the success value from this Result, which must be a success result. + * If it is an error result, then return the aValue. + */ + V unwrapOr(V aValue) const { return isOk() ? mImpl.unwrap() : aValue; } + + /** Get the error value from this Result, which must be an error result. */ + E unwrapErr() const { + MOZ_ASSERT(isErr()); + return mImpl.unwrapErr(); + } + + /** + * Map a function V -> W over this result's success variant. If this result is + * an error, do not invoke the function and return a copy of the error. + * + * Mapping over success values invokes the function to produce a new success + * value: + * + * // Map Result to another Result + * Result res(5); + * Result res2 = res.map([](int x) { return x * x; }); + * MOZ_ASSERT(res2.unwrap() == 25); + * + * // Map Result to Result + * Result res("hello, map!"); + * Result res2 = res.map(strlen); + * MOZ_ASSERT(res2.unwrap() == 11); + * + * Mapping over an error does not invoke the function and copies the error: + * + * Result res(5); + * MOZ_ASSERT(res.isErr()); + * Result res2 = res.map([](V v) { ... }); + * MOZ_ASSERT(res2.isErr()); + * MOZ_ASSERT(res2.unwrapErr() == 5); + */ + template + auto map(F f) const -> Result { + using RetResult = Result; + return isOk() ? RetResult(f(unwrap())) : RetResult(unwrapErr()); + } + + /** + * Given a function V -> Result, apply it to this result's success value + * and return its result. If this result is an error value, then return a + * copy. + * + * This is sometimes called "flatMap" or ">>=" in other contexts. + * + * `andThen`ing over success values invokes the function to produce a new + * result: + * + * Result res("hello, andThen!"); + * Result res2 = res.andThen([](const char* s) { + * return containsHtmlTag(s) + * ? Result(Error("Invalid: contains HTML")) + * : Result(HtmlFreeString(s)); + * } + * }); + * MOZ_ASSERT(res2.isOk()); + * MOZ_ASSERT(res2.unwrap() == HtmlFreeString("hello, andThen!"); + * + * `andThen`ing over error results does not invoke the function, and just + * produces a new copy of the error result: + * + * Result res("some error"); + * auto res2 = res.andThen([](int x) { ... }); + * MOZ_ASSERT(res2.isErr()); + * MOZ_ASSERT(res.unwrapErr() == res2.unwrapErr()); + */ + template ::value>::Type> + auto andThen(F f) const -> decltype(f(*((V*)nullptr))) { + return isOk() ? f(unwrap()) : GenericErrorResult(unwrapErr()); + } +}; + +/** + * A type that auto-converts to an error Result. This is like a Result without + * a success type. It's the best return type for functions that always return + * an error--functions designed to build and populate error objects. It's also + * useful in error-handling macros; see MOZ_TRY for an example. + */ +template +class MOZ_MUST_USE_TYPE GenericErrorResult { + E mErrorValue; + + template + friend class Result; + + public: + explicit GenericErrorResult(E aErrorValue) : mErrorValue(aErrorValue) {} +}; + +template +inline GenericErrorResult Err(E&& aErrorValue) { + return GenericErrorResult(aErrorValue); +} + +} // namespace mozilla + +/** + * MOZ_TRY(expr) is the C++ equivalent of Rust's `try!(expr);`. First, it + * evaluates expr, which must produce a Result value. On success, it + * discards the result altogether. On error, it immediately returns an error + * Result from the enclosing function. + */ +#define MOZ_TRY(expr) \ + do { \ + auto mozTryTempResult_ = ::mozilla::ToResult(expr); \ + if (mozTryTempResult_.isErr()) { \ + return ::mozilla::Err(mozTryTempResult_.unwrapErr()); \ + } \ + } while (0) + +/** + * MOZ_TRY_VAR(target, expr) is the C++ equivalent of Rust's `target = + * try!(expr);`. First, it evaluates expr, which must produce a Result value. On + * success, the result's success value is assigned to target. On error, + * immediately returns the error result. |target| must evaluate to a reference + * without any side effects. + */ +#define MOZ_TRY_VAR(target, expr) \ + do { \ + auto mozTryVarTempResult_ = (expr); \ + if (mozTryVarTempResult_.isErr()) { \ + return ::mozilla::Err(mozTryVarTempResult_.unwrapErr()); \ + } \ + (target) = mozTryVarTempResult_.unwrap(); \ + } while (0) + +#endif // mozilla_Result_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ResultExtensions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ResultExtensions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ResultExtensions.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/. */ + +/* Extensions to the Result type to enable simpler handling of XPCOM/NSPR + * results. */ + +#ifndef mozilla_ResultExtensions_h +#define mozilla_ResultExtensions_h + +#include "mozilla/Assertions.h" +#include "nscore.h" +#include "prtypes.h" + +namespace mozilla { + +// Allow nsresult errors to automatically convert to nsresult values, so MOZ_TRY +// can be used in XPCOM methods with Result results. +template <> +class MOZ_MUST_USE_TYPE GenericErrorResult { + nsresult mErrorValue; + + template + friend class Result; + + public: + explicit GenericErrorResult(nsresult aErrorValue) : mErrorValue(aErrorValue) { + MOZ_ASSERT(NS_FAILED(aErrorValue)); + } + + operator nsresult() { return mErrorValue; } +}; + +// Allow MOZ_TRY to handle `PRStatus` values. +inline Result ToResult(PRStatus aValue); + +} // namespace mozilla + +#include "mozilla/Result.h" + +namespace mozilla { + +inline Result ToResult(nsresult aValue) { + if (NS_FAILED(aValue)) { + return Err(aValue); + } + return Ok(); +} + +inline Result ToResult(PRStatus aValue) { + if (aValue == PR_SUCCESS) { + return Ok(); + } + return Err(NS_ERROR_FAILURE); +} + +} // namespace mozilla + +#endif // mozilla_ResultExtensions_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ReverseIterator.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ReverseIterator.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ReverseIterator.h @@ -16,122 +16,120 @@ namespace mozilla { -template -class ReverseIterator -{ -public: - template - explicit ReverseIterator(Iterator aIter) - : mCurrent(aIter) { } +template +class ReverseIterator { + public: + template + explicit ReverseIterator(Iterator aIter) : mCurrent(aIter) {} - template + template MOZ_IMPLICIT ReverseIterator(const ReverseIterator& aOther) - : mCurrent(aOther.mCurrent) { } + : mCurrent(aOther.mCurrent) {} - decltype(*DeclVal()) operator*() const - { + decltype(*DeclVal()) operator*() const { IteratorT tmp = mCurrent; return *--tmp; } /* Increments and decrements operators */ - ReverseIterator& operator++() { --mCurrent; return *this; } - ReverseIterator& operator--() { ++mCurrent; return *this; } - ReverseIterator operator++(int) { auto ret = *this; mCurrent--; return ret; } - ReverseIterator operator--(int) { auto ret = *this; mCurrent++; return ret; } + ReverseIterator& operator++() { + --mCurrent; + return *this; + } + ReverseIterator& operator--() { + ++mCurrent; + return *this; + } + ReverseIterator operator++(int) { + auto ret = *this; + mCurrent--; + return ret; + } + ReverseIterator operator--(int) { + auto ret = *this; + mCurrent++; + return ret; + } /* Comparison operators */ - template + template friend bool operator==(const ReverseIterator& aIter1, const ReverseIterator& aIter2); - template + template friend bool operator!=(const ReverseIterator& aIter1, const ReverseIterator& aIter2); - template + template friend bool operator<(const ReverseIterator& aIter1, const ReverseIterator& aIter2); - template + template friend bool operator<=(const ReverseIterator& aIter1, const ReverseIterator& aIter2); - template + template friend bool operator>(const ReverseIterator& aIter1, const ReverseIterator& aIter2); - template + template friend bool operator>=(const ReverseIterator& aIter1, const ReverseIterator& aIter2); -private: + private: IteratorT mCurrent; }; -template -bool -operator==(const ReverseIterator& aIter1, - const ReverseIterator& aIter2) -{ +template +bool operator==(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) { return aIter1.mCurrent == aIter2.mCurrent; } -template -bool -operator!=(const ReverseIterator& aIter1, - const ReverseIterator& aIter2) -{ +template +bool operator!=(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) { return aIter1.mCurrent != aIter2.mCurrent; } -template -bool -operator<(const ReverseIterator& aIter1, - const ReverseIterator& aIter2) -{ +template +bool operator<(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) { return aIter1.mCurrent > aIter2.mCurrent; } -template -bool -operator<=(const ReverseIterator& aIter1, - const ReverseIterator& aIter2) -{ +template +bool operator<=(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) { return aIter1.mCurrent >= aIter2.mCurrent; } -template -bool -operator>(const ReverseIterator& aIter1, - const ReverseIterator& aIter2) -{ +template +bool operator>(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) { return aIter1.mCurrent < aIter2.mCurrent; } -template -bool -operator>=(const ReverseIterator& aIter1, - const ReverseIterator& aIter2) -{ +template +bool operator>=(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) { return aIter1.mCurrent <= aIter2.mCurrent; } namespace detail { -template -class IteratorRange -{ -public: +template +class IteratorRange { + public: typedef IteratorT iterator; typedef IteratorT const_iterator; typedef ReverseIterator reverse_iterator; typedef ReverseIterator const_reverse_iterator; - template + template MOZ_IMPLICIT IteratorRange(Iterator1 aIterBegin, Iterator2 aIterEnd) - : mIterBegin(aIterBegin), mIterEnd(aIterEnd) { } + : mIterBegin(aIterBegin), mIterEnd(aIterEnd) {} - template + template MOZ_IMPLICIT IteratorRange(const IteratorRange& aOther) - : mIterBegin(aOther.mIterBegin), mIterEnd(aOther.mIterEnd) { } + : mIterBegin(aOther.mIterBegin), mIterEnd(aOther.mIterEnd) {} iterator begin() const { return mIterBegin; } const_iterator cbegin() const { return begin(); } @@ -142,27 +140,25 @@ reverse_iterator rend() const { return reverse_iterator(mIterBegin); } const_reverse_iterator crend() const { return rend(); } -private: + private: IteratorT mIterBegin; IteratorT mIterEnd; }; -} // namespace detail +} // namespace detail -template -detail::IteratorRange -Reversed(Range& aRange) -{ +template +detail::IteratorRange Reversed( + Range& aRange) { return {aRange.rbegin(), aRange.rend()}; } -template -detail::IteratorRange -Reversed(const Range& aRange) -{ +template +detail::IteratorRange Reversed( + const Range& aRange) { return {aRange.rbegin(), aRange.rend()}; } -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_ReverseIterator_h +#endif // mozilla_ReverseIterator_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/RollingMean.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/RollingMean.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/RollingMean.h @@ -4,7 +4,7 @@ * 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 set abstraction for enumeration values. */ +/* Calculate the rolling mean of a series of values. */ #ifndef mozilla_RollingMean_h_ #define mozilla_RollingMean_h_ @@ -26,33 +26,28 @@ * * WARNING: Float types are not supported due to rounding errors. */ -template -class RollingMean -{ -private: +template +class RollingMean { + private: size_t mInsertIndex; size_t mMaxValues; Vector mValues; S mTotal; -public: + public: static_assert(!IsFloatingPoint::value, "floating-point types are unsupported due to rounding " "errors"); explicit RollingMean(size_t aMaxValues) - : mInsertIndex(0), - mMaxValues(aMaxValues), - mTotal(0) - { + : mInsertIndex(0), mMaxValues(aMaxValues), mTotal(0) { MOZ_ASSERT(aMaxValues > 0); } - RollingMean& operator=(RollingMean&& aOther) - { + RollingMean& operator=(RollingMean&& aOther) { MOZ_ASSERT(this != &aOther, "self-assignment is forbidden"); this->~RollingMean(); - new(this) RollingMean(aOther.mMaxValues); + new (this) RollingMean(aOther.mMaxValues); mInsertIndex = aOther.mInsertIndex; mTotal = aOther.mTotal; mValues.swap(aOther.mValues); @@ -62,8 +57,7 @@ /** * Insert a value into the rolling mean. */ - bool insert(T aValue) - { + bool insert(T aValue) { MOZ_ASSERT(mValues.length() <= mMaxValues); if (mValues.length() == mMaxValues) { @@ -83,33 +77,25 @@ /** * Calculate the rolling mean. */ - T mean() - { + T mean() { MOZ_ASSERT(!empty()); return T(mTotal / int64_t(mValues.length())); } - bool empty() - { - return mValues.empty(); - } + bool empty() { return mValues.empty(); } /** * Remove all values from the rolling mean. */ - void clear() - { + void clear() { mValues.clear(); mInsertIndex = 0; mTotal = T(0); } - size_t maxValues() - { - return mMaxValues; - } + size_t maxValues() { return mMaxValues; } }; -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_RollingMean_h_ +#endif // mozilla_RollingMean_h_ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/SHA1.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/SHA1.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/SHA1.h @@ -34,18 +34,16 @@ * The finish method may only be called once and cannot be followed by calls * to update. */ -class SHA1Sum -{ - union - { +class SHA1Sum { + union { uint32_t mW[16]; /* input buffer */ uint8_t mB[64]; } mU; - uint64_t mSize; /* count of hashed bytes. */ + uint64_t mSize; /* count of hashed bytes. */ unsigned mH[22]; /* 5 state variables, 16 tmp values, 1 extra */ bool mDone; -public: + public: MFBT_API SHA1Sum(); static const size_t kHashSize = 20; 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 @@ -35,12 +35,9 @@ * specialize the type traits accordingly. */ template -class SaturateOp -{ -public: - explicit SaturateOp(T& aValue) - : mValue(aValue) - { +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. @@ -50,20 +47,13 @@ // Add and subtract operators - T operator+(const T& aRhs) const - { - return T(mValue) += aRhs; - } + T operator+(const T& aRhs) const { return T(mValue) += aRhs; } - 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& operator+=(const T& aRhs) const { const T min = std::numeric_limits::min(); const T max = std::numeric_limits::max(); @@ -75,8 +65,7 @@ return mValue; } - const T& operator-=(const T& aRhs) const - { + const T& operator-=(const T& aRhs) const { const T min = std::numeric_limits::min(); const T max = std::numeric_limits::max(); @@ -90,31 +79,31 @@ // Increment and decrement operators - const T& operator++() const // prefix + const T& operator++() const // prefix { return operator+=(static_cast(1)); } - T operator++(int) const // postfix + T operator++(int)const // postfix { const T value(mValue); operator++(); return value; } - const T& operator--() const // prefix + const T& operator--() const // prefix { return operator-=(static_cast(1)); } - T operator--(int) const // postfix + T operator--(int)const // postfix { const T value(mValue); operator--(); return value; } -private: + private: SaturateOp(const SaturateOp&) = delete; SaturateOp(SaturateOp&&) = delete; SaturateOp& operator=(const SaturateOp&) = delete; @@ -128,139 +117,111 @@ * build on top of |SaturateOp|. */ template -class Saturate -{ -public: +class Saturate { + public: Saturate() = default; MOZ_IMPLICIT Saturate(const Saturate&) = default; - MOZ_IMPLICIT Saturate(Saturate&& aValue) - { - mValue = Move(aValue.mValue); - } + MOZ_IMPLICIT Saturate(Saturate&& aValue) { mValue = Move(aValue.mValue); } - explicit Saturate(const T& aValue) - : mValue(aValue) - { } + explicit Saturate(const T& aValue) : mValue(aValue) {} - const T& value() const - { - return mValue; - } + const T& value() const { return mValue; } // Compare operators - bool operator==(const Saturate& aRhs) const - { + bool operator==(const Saturate& aRhs) const { return mValue == aRhs.mValue; } - bool operator!=(const Saturate& aRhs) const - { - return !operator==(aRhs); - } + 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 mValue == aRhs; } - bool operator!=(const T& aRhs) const - { - return !operator==(aRhs); - } + bool operator!=(const T& aRhs) const { return !operator==(aRhs); } // Assignment operators Saturate& operator=(const Saturate&) = default; - Saturate& operator=(Saturate&& aRhs) - { + Saturate& operator=(Saturate&& aRhs) { mValue = Move(aRhs.mValue); return *this; } // Add and subtract operators - Saturate operator+(const Saturate& aRhs) const - { + Saturate operator+(const Saturate& aRhs) const { Saturate lhs(mValue); return lhs += aRhs.mValue; } - Saturate operator+(const T& aRhs) const - { + Saturate operator+(const T& aRhs) const { Saturate lhs(mValue); return lhs += aRhs; } - Saturate operator-(const Saturate& aRhs) const - { + Saturate operator-(const Saturate& aRhs) const { Saturate lhs(mValue); return lhs -= aRhs.mValue; } - Saturate operator-(const T& aRhs) const - { + Saturate operator-(const T& aRhs) const { Saturate lhs(mValue); return lhs -= aRhs; } // Compound operators - Saturate& operator+=(const Saturate& aRhs) - { + Saturate& operator+=(const Saturate& aRhs) { SaturateOp(mValue) += aRhs.mValue; return *this; } - Saturate& operator+=(const T& aRhs) - { + Saturate& operator+=(const T& aRhs) { SaturateOp(mValue) += aRhs; return *this; } - Saturate& operator-=(const Saturate& aRhs) - { + Saturate& operator-=(const Saturate& aRhs) { SaturateOp(mValue) -= aRhs.mValue; return *this; } - Saturate& operator-=(const T& aRhs) - { + Saturate& operator-=(const T& aRhs) { SaturateOp(mValue) -= aRhs; return *this; } // Increment and decrement operators - Saturate& operator++() // prefix + Saturate& operator++() // prefix { ++SaturateOp(mValue); return *this; } - Saturate operator++(int) // postfix + Saturate operator++(int) // postfix { return Saturate(SaturateOp(mValue)++); } - Saturate& operator--() // prefix + Saturate& operator--() // prefix { --SaturateOp(mValue); return *this; } - Saturate operator--(int) // postfix + Saturate operator--(int) // postfix { return Saturate(SaturateOp(mValue)--); } -private: + private: T mValue; }; -} // namespace detail +} // namespace detail typedef detail::Saturate SaturateInt8; typedef detail::Saturate SaturateInt16; @@ -269,20 +230,16 @@ typedef detail::Saturate SaturateUint16; typedef detail::Saturate SaturateUint32; -} // namespace mozilla +} // namespace mozilla -template -bool -operator==(LhsT aLhs, const mozilla::detail::Saturate& aRhs) -{ +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) -{ +template +bool operator!=(LhsT aLhs, const mozilla::detail::Saturate& aRhs) { return !(aLhs == aRhs); } -#endif // mozilla_Saturate_h +#endif // mozilla_Saturate_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ScopeExit.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ScopeExit.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ScopeExit.h @@ -91,19 +91,15 @@ bool mExecuteOnDestruction; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -public: - explicit ScopeExit(ExitFunction&& cleanup - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mExitFunction(cleanup) - , mExecuteOnDestruction(true) - { + public: + explicit ScopeExit(ExitFunction&& cleanup MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mExitFunction(cleanup), mExecuteOnDestruction(true) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } ScopeExit(ScopeExit&& rhs) - : mExitFunction(mozilla::Move(rhs.mExitFunction)) - , mExecuteOnDestruction(rhs.mExecuteOnDestruction) - { + : mExitFunction(mozilla::Move(rhs.mExitFunction)), + mExecuteOnDestruction(rhs.mExecuteOnDestruction) { rhs.release(); } @@ -113,20 +109,16 @@ } } - void release() { - mExecuteOnDestruction = false; - } + void release() { mExecuteOnDestruction = false; } -private: + private: explicit ScopeExit(const ScopeExit&) = delete; ScopeExit& operator=(const ScopeExit&) = delete; ScopeExit& operator=(ScopeExit&&) = delete; }; template -ScopeExit -MakeScopeExit(ExitFunction&& exitFunction) -{ +ScopeExit MakeScopeExit(ExitFunction&& exitFunction) { return ScopeExit(mozilla::Move(exitFunction)); } 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 @@ -64,30 +64,24 @@ * const static void release(type); * } */ -template -class MOZ_NON_TEMPORARY_CLASS Scoped -{ -public: +template +class MOZ_NON_TEMPORARY_CLASS Scoped { + public: typedef typename Traits::type Resource; explicit Scoped(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) - : mValue(Traits::empty()) - { + : mValue(Traits::empty()) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } - explicit Scoped(const Resource& aValue - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mValue(aValue) - { + explicit Scoped(const Resource& aValue MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mValue(aValue) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } /* Move constructor. */ - Scoped(Scoped&& aOther - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mValue(Move(aOther.mValue)) - { + Scoped(Scoped&& aOther MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mValue(Move(aOther.mValue)) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; aOther.mValue = Traits::empty(); } @@ -110,8 +104,7 @@ * * @return The original resource. */ - Resource forget() - { + Resource forget() { Resource tmp = mValue; mValue = Traits::empty(); return tmp; @@ -122,8 +115,7 @@ * * If this |Scoped| is currently empty, this method has no effect. */ - void dispose() - { + void dispose() { Traits::release(mValue); mValue = Traits::empty(); } @@ -140,27 +132,25 @@ */ Scoped& operator=(const Resource& aOther) { return reset(aOther); } - Scoped& reset(const Resource& aOther) - { + Scoped& reset(const Resource& aOther) { Traits::release(mValue); mValue = aOther; return *this; } /* Move assignment operator. */ - Scoped& operator=(Scoped&& aRhs) - { + Scoped& operator=(Scoped&& aRhs) { MOZ_ASSERT(&aRhs != this, "self-move-assignment not allowed"); this->~Scoped(); - new(this) Scoped(Move(aRhs)); + new (this) Scoped(Move(aRhs)); return *this; } -private: + private: explicit Scoped(const Scoped& aValue) = delete; Scoped& operator=(const Scoped& aValue) = delete; -private: + private: Resource mValue; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; @@ -173,39 +163,31 @@ * @param Traits A struct implementing clean-up. See the implementations * for more details. */ -#define SCOPED_TEMPLATE(name, Traits) \ -template \ -struct MOZ_NON_TEMPORARY_CLASS name : public mozilla::Scoped > \ -{ \ - typedef mozilla::Scoped > Super; \ - typedef typename Super::Resource Resource; \ - name& operator=(Resource aRhs) \ - { \ - Super::operator=(aRhs); \ - return *this; \ - } \ - name& operator=(name&& aRhs) \ - { \ - Super::operator=(Move(aRhs)); \ - return *this; \ - } \ - explicit name(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) \ - : Super(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT) \ - {} \ - explicit name(Resource aRhs \ - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \ - : Super(aRhs \ - MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) \ - {} \ - name(name&& aRhs \ - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \ - : Super(Move(aRhs) \ - MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) \ - {} \ -private: \ - explicit name(name&) = delete; \ - name& operator=(name&) = delete; \ -}; +#define SCOPED_TEMPLATE(name, Traits) \ + template \ + struct MOZ_NON_TEMPORARY_CLASS name \ + : public mozilla::Scoped > { \ + typedef mozilla::Scoped > Super; \ + typedef typename Super::Resource Resource; \ + name& operator=(Resource aRhs) { \ + Super::operator=(aRhs); \ + return *this; \ + } \ + name& operator=(name&& aRhs) { \ + Super::operator=(Move(aRhs)); \ + return *this; \ + } \ + explicit name(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) \ + : Super(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT) {} \ + explicit name(Resource aRhs MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \ + : Super(aRhs MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) {} \ + name(name&& aRhs MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \ + : Super(Move(aRhs) MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) {} \ + \ + private: \ + explicit name(name&) = delete; \ + name& operator=(name&) = delete; \ + }; /* * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE makes it easy to create scoped @@ -230,18 +212,20 @@ * } // file is closed with PR_Close here */ #define MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(name, Type, Deleter) \ -template <> inline void TypeSpecificDelete(Type* aValue) { Deleter(aValue); } \ -typedef ::mozilla::TypeSpecificScopedPointer name; + template <> \ + inline void TypeSpecificDelete(Type* aValue) { \ + Deleter(aValue); \ + } \ + typedef ::mozilla::TypeSpecificScopedPointer name; -template void TypeSpecificDelete(T* aValue); +template +void TypeSpecificDelete(T* aValue); template -struct TypeSpecificScopedPointerTraits -{ +struct TypeSpecificScopedPointerTraits { typedef T* type; static type empty() { return nullptr; } - static void release(type aValue) - { + static void release(type aValue) { if (aValue) { TypeSpecificDelete(aValue); } 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 @@ -48,19 +48,15 @@ // The ideal size depends on how the SegmentedVector is used and the size of // |T|, but reasonable sizes include 1024, 4096 (the default), 8192, and 16384. // -template -class SegmentedVector : private AllocPolicy -{ - template +template +class SegmentedVector : private AllocPolicy { + template struct SegmentImpl - : public mozilla::LinkedListElement> - { + : public mozilla::LinkedListElement> { SegmentImpl() : mLength(0) {} - ~SegmentImpl() - { + ~SegmentImpl() { for (uint32_t i = 0; i < mLength; i++) { (*this)[i].~T(); } @@ -70,21 +66,18 @@ T* Elems() { return reinterpret_cast(&mStorage.mBuf); } - T& operator[](size_t aIndex) - { + T& operator[](size_t aIndex) { MOZ_ASSERT(aIndex < mLength); return Elems()[aIndex]; } - const T& operator[](size_t aIndex) const - { + const T& operator[](size_t aIndex) const { MOZ_ASSERT(aIndex < mLength); return Elems()[aIndex]; } - template - void Append(U&& aU) - { + template + void Append(U&& aU) { MOZ_ASSERT(mLength < SegmentCapacity); // Pre-increment mLength so that the bounds-check in operator[] passes. mLength++; @@ -92,8 +85,7 @@ new (elem) T(mozilla::Forward(aU)); } - void PopLast() - { + void PopLast() { MOZ_ASSERT(mLength > 0); (*this)[mLength - 1].~T(); mLength--; @@ -102,8 +94,7 @@ uint32_t mLength; // The union ensures that the elements are appropriately aligned. - union Storage - { + union Storage { char mBuf[sizeof(T) * SegmentCapacity]; mozilla::AlignedElem mAlign; } mStorage; @@ -117,39 +108,39 @@ // kSingleElementSegmentSize already accounts for one element. static const size_t kSingleElementSegmentSize = sizeof(SegmentImpl<1>); static const size_t kSegmentCapacity = - kSingleElementSegmentSize <= IdealSegmentSize - ? (IdealSegmentSize - kSingleElementSegmentSize) / sizeof(T) + 1 - : 1; + kSingleElementSegmentSize <= IdealSegmentSize + ? (IdealSegmentSize - kSingleElementSegmentSize) / sizeof(T) + 1 + : 1; + public: typedef SegmentImpl Segment; -public: // The |aIdealSegmentSize| is only for sanity checking. If it's specified, we // check that the actual segment size is as close as possible to it. This // serves as a sanity check for SegmentedVectorCapacity's capacity // computation. - explicit SegmentedVector(size_t aIdealSegmentSize = 0) - { + explicit SegmentedVector(size_t aIdealSegmentSize = 0) { // The difference between the actual segment size and the ideal segment // size should be less than the size of a single element... unless the // ideal size was too small, in which case the capacity should be one. MOZ_ASSERT_IF( - aIdealSegmentSize != 0, - (sizeof(Segment) > aIdealSegmentSize && kSegmentCapacity == 1) || - aIdealSegmentSize - sizeof(Segment) < sizeof(T)); + aIdealSegmentSize != 0, + (sizeof(Segment) > aIdealSegmentSize && kSegmentCapacity == 1) || + aIdealSegmentSize - sizeof(Segment) < sizeof(T)); } + SegmentedVector(SegmentedVector&& aOther) + : mSegments(mozilla::Move(aOther.mSegments)) {} + ~SegmentedVector() { Clear(); } bool IsEmpty() const { return !mSegments.getFirst(); } // Note that this is O(n) rather than O(1), but the constant factor is very // small because it only has to do one addition per segment. - size_t Length() const - { + size_t Length() const { size_t n = 0; - for (auto segment = mSegments.getFirst(); - segment; + for (auto segment = mSegments.getFirst(); segment; segment = segment->getNext()) { n += segment->Length(); } @@ -158,9 +149,8 @@ // Returns false if the allocation failed. (If you are using an infallible // allocation policy, use InfallibleAppend() instead.) - template - MOZ_MUST_USE bool Append(U&& aU) - { + template + MOZ_MUST_USE bool Append(U&& aU) { Segment* last = mSegments.getLast(); if (!last || last->Length() == kSegmentCapacity) { last = this->template pod_malloc(1); @@ -176,15 +166,13 @@ // You should probably only use this instead of Append() if you are using an // infallible allocation policy. It will crash if the allocation fails. - template - void InfallibleAppend(U&& aU) - { + template + void InfallibleAppend(U&& aU) { bool ok = Append(mozilla::Forward(aU)); MOZ_RELEASE_ASSERT(ok); } - void Clear() - { + void Clear() { Segment* segment; while ((segment = mSegments.popFirst())) { segment->~Segment(); @@ -192,22 +180,19 @@ } } - T& GetLast() - { + T& GetLast() { MOZ_ASSERT(!IsEmpty()); Segment* last = mSegments.getLast(); return (*last)[last->Length() - 1]; } - const T& GetLast() const - { + const T& GetLast() const { MOZ_ASSERT(!IsEmpty()); Segment* last = mSegments.getLast(); return (*last)[last->Length() - 1]; } - void PopLast() - { + void PopLast() { MOZ_ASSERT(!IsEmpty()); Segment* last = mSegments.getLast(); last->PopLast(); @@ -220,8 +205,7 @@ // Equivalent to calling |PopLast| |aNumElements| times, but potentially // more efficient. - void PopLastN(uint32_t aNumElements) - { + void PopLastN(uint32_t aNumElements) { MOZ_ASSERT(aNumElements <= Length()); Segment* last; @@ -260,7 +244,6 @@ // 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(); @@ -275,35 +258,37 @@ // f(elem); // } // - class IterImpl - { + // Note, adding new entries to the SegmentedVector while using iterators + // is supported, but removing is not! + // If an iterator has entered Done() state, adding more entries to the + // vector doesn't affect it. + class IterImpl { friend class SegmentedVector; Segment* mSegment; size_t mIndex; - explicit IterImpl(SegmentedVector* aVector) - : mSegment(aVector->mSegments.getFirst()) - , mIndex(0) - {} + explicit IterImpl(SegmentedVector* aVector, bool aFromFirst) + : mSegment(aFromFirst ? aVector->mSegments.getFirst() + : aVector->mSegments.getLast()), + mIndex(aFromFirst ? 0 : (mSegment ? mSegment->Length() - 1 : 0)) { + MOZ_ASSERT_IF(mSegment, mSegment->Length() > 0); + } - public: + public: bool Done() const { return !mSegment; } - T& Get() - { + T& Get() { MOZ_ASSERT(!Done()); return (*mSegment)[mIndex]; } - const T& Get() const - { + const T& Get() const { MOZ_ASSERT(!Done()); return (*mSegment)[mIndex]; } - void Next() - { + void Next() { MOZ_ASSERT(!Done()); mIndex++; if (mIndex == mSegment->Length()) { @@ -311,29 +296,40 @@ mIndex = 0; } } + + void Prev() { + MOZ_ASSERT(!Done()); + if (mIndex == 0) { + mSegment = mSegment->getPrevious(); + if (mSegment) { + mIndex = mSegment->Length() - 1; + } + } else { + --mIndex; + } + } }; - IterImpl Iter() { return IterImpl(this); } + IterImpl Iter() { return IterImpl(this, true); } + IterImpl IterFromLast() { return IterImpl(this, false); } // Measure the memory consumption of the vector excluding |this|. Note that // it only measures the vector itself. If the vector elements contain // pointers to other memory blocks, those blocks must be measured separately // during a subsequent iteration over the vector. - size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const - { + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { return mSegments.sizeOfExcludingThis(aMallocSizeOf); } // Like sizeOfExcludingThis(), but measures |this| as well. - size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const - { + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); } -private: + private: mozilla::LinkedList mSegments; }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_SegmentedVector_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/SizePrintfMacros.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/SizePrintfMacros.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/SizePrintfMacros.h @@ -1,33 +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/. */ - -/* Implements (nonstandard) PRI{ouxX}SIZE format macros for size_t types. */ - -#ifndef mozilla_SizePrintfMacros_h_ -#define mozilla_SizePrintfMacros_h_ - -/* - * MSVC's libc does not support C99's %z format length modifier for size_t - * types. Instead, we use Microsoft's nonstandard %I modifier for size_t, which - * is unsigned __int32 on 32-bit platforms and unsigned __int64 on 64-bit - * platforms: - * - * http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx - */ - -#if defined(XP_WIN) -# define PRIoSIZE "Io" -# define PRIuSIZE "Iu" -# define PRIxSIZE "Ix" -# define PRIXSIZE "IX" -#else -# define PRIoSIZE "zo" -# define PRIuSIZE "zu" -# define PRIxSIZE "zx" -# define PRIXSIZE "zX" -#endif - -#endif /* mozilla_SizePrintfMacros_h_ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/SmallPointerArray.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/SmallPointerArray.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/SmallPointerArray.h @@ -0,0 +1,230 @@ +/* -*- 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 vector of pointers space-optimized for a small number of elements. */ +#ifndef mozilla_SmallPointerArray_h +#define mozilla_SmallPointerArray_h + +#include "mozilla/Assertions.h" +#include +#include +#include + +namespace mozilla { + +// Array class for situations where a small number of elements (<= 2) is +// expected, a large number of elements must be accomodated if necessary, +// and the size of the class must be minimal. Typical vector implementations +// will fulfill the first two requirements by simply adding inline storage +// alongside the rest of their member variables. While this strategy works, +// it brings unnecessary storage overhead for vectors with an expected small +// number of elements. This class is intended to deal with that problem. +// +// This class is similar in performance to a vector class. Accessing its +// elements when it has not grown over a size of 2 does not require an extra +// level of indirection and will therefore be faster. +// +// The minimum (inline) size is 2 * sizeof(void*). +// +// Any modification of the array invalidates any outstanding iterators. +template +class SmallPointerArray { + public: + SmallPointerArray() { + mInlineElements[0] = mInlineElements[1] = nullptr; + static_assert(sizeof(SmallPointerArray) == (2 * sizeof(void*)), + "SmallPointerArray must compile to the size of 2 pointers"); + static_assert( + offsetof(SmallPointerArray, mArray) == + offsetof(SmallPointerArray, mInlineElements) + sizeof(T*), + "mArray and mInlineElements[1] are expected to overlap in memory"); + static_assert( + offsetof(SmallPointerArray, mPadding) == + offsetof(SmallPointerArray, mInlineElements), + "mPadding and mInlineElements[0] are expected to overlap in memory"); + } + ~SmallPointerArray() { + if (!mInlineElements[0] && mArray) { + delete mArray; + } + } + + void Clear() { + if (!mInlineElements[0] && mArray) { + delete mArray; + mArray = nullptr; + return; + } + mInlineElements[0] = mInlineElements[1] = nullptr; + } + + void AppendElement(T* aElement) { + // Storing nullptr as an element is not permitted, but we do check for it + // to avoid corruption issues in non-debug builds. + + // In addition to this we assert in debug builds to point out mistakes to + // users of the class. + MOZ_ASSERT(aElement != nullptr); + if (!mInlineElements[0]) { + if (!mArray) { + mInlineElements[0] = aElement; + // Harmless if aElement == nullptr; + return; + } + + if (!aElement) { + return; + } + + mArray->push_back(aElement); + return; + } + + if (!aElement) { + return; + } + + if (!mInlineElements[1]) { + mInlineElements[1] = aElement; + return; + } + + mArray = + new std::vector({mInlineElements[0], mInlineElements[1], aElement}); + mInlineElements[0] = nullptr; + } + + bool RemoveElement(T* aElement) { + MOZ_ASSERT(aElement != nullptr); + if (aElement == nullptr) { + return false; + } + + if (mInlineElements[0] == aElement) { + // Expectected case. + mInlineElements[0] = mInlineElements[1]; + mInlineElements[1] = nullptr; + return true; + } + + if (mInlineElements[0]) { + if (mInlineElements[1] == aElement) { + mInlineElements[1] = nullptr; + return true; + } + return false; + } + + if (mArray) { + for (auto iter = mArray->begin(); iter != mArray->end(); iter++) { + if (*iter == aElement) { + mArray->erase(iter); + return true; + } + } + } + return false; + } + + bool Contains(T* aElement) const { + MOZ_ASSERT(aElement != nullptr); + if (aElement == nullptr) { + return false; + } + + if (mInlineElements[0] == aElement) { + return true; + } + + if (mInlineElements[0]) { + if (mInlineElements[1] == aElement) { + return true; + } + return false; + } + + if (mArray) { + return std::find(mArray->begin(), mArray->end(), aElement) != + mArray->end(); + } + return false; + } + + size_t Length() const { + if (mInlineElements[0]) { + if (!mInlineElements[1]) { + return 1; + } + return 2; + } + + if (mArray) { + return mArray->size(); + } + + return 0; + } + + T* ElementAt(size_t aIndex) const { + MOZ_ASSERT(aIndex < Length()); + if (mInlineElements[0]) { + return mInlineElements[aIndex]; + } + + return (*mArray)[aIndex]; + } + + T* operator[](size_t aIndex) const { return ElementAt(aIndex); } + + typedef T** iterator; + typedef const T** const_iterator; + + // Methods for range-based for loops. Manipulation invalidates these. + iterator begin() { return beginInternal(); } + const_iterator begin() const { return beginInternal(); } + const_iterator cbegin() const { return begin(); } + iterator end() { return beginInternal() + Length(); } + const_iterator end() const { return beginInternal() + Length(); } + const_iterator cend() const { return end(); } + + private: + T** beginInternal() const { + if (mInlineElements[0] || !mArray) { + return const_cast(&mInlineElements[0]); + } + + if (mArray->empty()) { + return nullptr; + } + + return &(*mArray)[0]; + } + + // mArray and mInlineElements[1] share the same area in memory. + // + // When !mInlineElements[0] && !mInlineElements[1] the array is empty. + // + // When mInlineElements[0] && !mInlineElements[1], mInlineElements[0] + // contains the first element. The array is of size 1. + // + // When mInlineElements[0] && mInlineElements[1], mInlineElements[0] + // contains the first element and mInlineElements[1] the second. The + // array is of size 2. + // + // When !mInlineElements[0] && mArray, mArray contains the full contents + // of the array and is of arbitrary size. + union { + T* mInlineElements[2]; + struct { + void* mPadding; + std::vector* mArray; + }; + }; +}; + +} // namespace mozilla + +#endif // mozilla_SmallPointerArray_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Span.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Span.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/Span.h @@ -0,0 +1,960 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +/////////////////////////////////////////////////////////////////////////////// + +// Adapted from +// https://github.com/Microsoft/GSL/blob/3819df6e378ffccf0e29465afe99c3b324c2aa70/include/gsl/span +// and +// https://github.com/Microsoft/GSL/blob/3819df6e378ffccf0e29465afe99c3b324c2aa70/include/gsl/gsl_util + +#ifndef mozilla_Span_h +#define mozilla_Span_h + +#include "mozilla/Array.h" +#include "mozilla/Assertions.h" +#include "mozilla/Casting.h" +#include "mozilla/IntegerTypeTraits.h" +#include "mozilla/Move.h" +#include "mozilla/TypeTraits.h" +#include "mozilla/UniquePtr.h" + +#include +#include +#include +#include + +// Classifications for reasons why constexpr was removed in C++14 to C++11 +// conversion. Once we upgrade compilers, we can try defining each of these +// to constexpr to restore a category of constexprs at a time. +#if !defined(__clang__) && defined(__GNUC__) && __cpp_constexpr < 201304 +#define MOZ_SPAN_ASSERTION_CONSTEXPR +#define MOZ_SPAN_GCC_CONSTEXPR +#define MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR +#define MOZ_SPAN_CONSTEXPR_NOT_JUST_RETURN +#define MOZ_SPAN_NON_CONST_CONSTEXPR +#else +#define MOZ_SPAN_ASSERTION_CONSTEXPR constexpr +#define MOZ_SPAN_GCC_CONSTEXPR constexpr +#define MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR constexpr +#define MOZ_SPAN_CONSTEXPR_NOT_JUST_RETURN constexpr +#define MOZ_SPAN_NON_CONST_CONSTEXPR constexpr +#endif + +#ifdef _MSC_VER +#pragma warning(push) + +// turn off some warnings that are noisy about our MOZ_RELEASE_ASSERT statements +#pragma warning(disable : 4127) // conditional expression is constant + +// blanket turn off warnings from CppCoreCheck for now +// so people aren't annoyed by them when running the tool. +// more targeted suppressions will be added in a future update to the GSL +#pragma warning(disable : 26481 26482 26483 26485 26490 26491 26492 26493 26495) + +#if _MSC_VER < 1910 +#pragma push_macro("constexpr") +#define constexpr /*constexpr*/ + +#endif // _MSC_VER < 1910 +#endif // _MSC_VER + +namespace mozilla { + +// Stuff from gsl_util + +// narrow_cast(): a searchable way to do narrowing casts of values +template +inline constexpr T narrow_cast(U&& u) { + return static_cast(mozilla::Forward(u)); +} + +// end gsl_util + +// [views.constants], constants +// This was -1 in gsl::span, but using size_t for sizes instead of ptrdiff_t +// and reserving a magic value that realistically doesn't occur in +// compile-time-constant Span sizes makes things a lot less messy in terms of +// comparison between signed and unsigned. +constexpr const size_t dynamic_extent = mozilla::MaxValue::value; + +template +class Span; + +// implementation details +namespace span_details { + +inline size_t strlen16(const char16_t* aZeroTerminated) { + size_t len = 0; + while (*(aZeroTerminated++)) { + len++; + } + return len; +} + +// C++14 types that we don't have because we build as C++11. +template +using remove_cv_t = typename mozilla::RemoveCV::Type; +template +using remove_const_t = typename mozilla::RemoveConst::Type; +template +using conditional_t = typename mozilla::Conditional::Type; +template +using add_pointer_t = typename mozilla::AddPointer::Type; +template +using enable_if_t = typename mozilla::EnableIf::Type; + +template +struct is_span_oracle : mozilla::FalseType {}; + +template +struct is_span_oracle> : mozilla::TrueType { +}; + +template +struct is_span : public is_span_oracle> {}; + +template +struct is_std_array_oracle : mozilla::FalseType {}; + +template +struct is_std_array_oracle> + : mozilla::TrueType {}; + +template +struct is_std_array : public is_std_array_oracle> {}; + +template +struct is_allowed_extent_conversion + : public mozilla::IntegralConstant< + bool, From == To || From == mozilla::dynamic_extent || + To == mozilla::dynamic_extent> {}; + +template +struct is_allowed_element_type_conversion + : public mozilla::IntegralConstant< + bool, mozilla::IsConvertible::value> {}; + +template +class span_iterator { + using element_type_ = typename Span::element_type; + + public: + using iterator_category = std::random_access_iterator_tag; + using value_type = remove_const_t; + using difference_type = typename Span::index_type; + + using reference = conditional_t&; + using pointer = add_pointer_t; + + constexpr span_iterator() : span_iterator(nullptr, 0) {} + + MOZ_SPAN_ASSERTION_CONSTEXPR span_iterator(const Span* span, + typename Span::index_type index) + : span_(span), index_(index) { + MOZ_RELEASE_ASSERT(span == nullptr || + (index_ >= 0 && index <= span_->Length())); + } + + friend class span_iterator; + constexpr MOZ_IMPLICIT span_iterator(const span_iterator& other) + : span_iterator(other.span_, other.index_) {} + + MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR span_iterator& + operator=(const span_iterator&) = default; + + MOZ_SPAN_GCC_CONSTEXPR reference operator*() const { + MOZ_RELEASE_ASSERT(span_); + return (*span_)[index_]; + } + + constexpr pointer operator->() const { + MOZ_RELEASE_ASSERT(span_); + return &((*span_)[index_]); + } + + MOZ_SPAN_NON_CONST_CONSTEXPR span_iterator& operator++() { + MOZ_RELEASE_ASSERT(span_ && index_ >= 0 && index_ < span_->Length()); + ++index_; + return *this; + } + + constexpr span_iterator operator++(int) { + auto ret = *this; + ++(*this); + return ret; + } + + MOZ_SPAN_NON_CONST_CONSTEXPR span_iterator& operator--() { + MOZ_RELEASE_ASSERT(span_ && index_ > 0 && index_ <= span_->Length()); + --index_; + return *this; + } + + constexpr span_iterator operator--(int) { + auto ret = *this; + --(*this); + return ret; + } + + MOZ_SPAN_CONSTEXPR_NOT_JUST_RETURN span_iterator + operator+(difference_type n) const { + auto ret = *this; + return ret += n; + } + + MOZ_SPAN_GCC_CONSTEXPR span_iterator& operator+=(difference_type n) { + MOZ_RELEASE_ASSERT(span_ && (index_ + n) >= 0 && + (index_ + n) <= span_->Length()); + index_ += n; + return *this; + } + + constexpr span_iterator operator-(difference_type n) const { + auto ret = *this; + return ret -= n; + } + + constexpr span_iterator& operator-=(difference_type n) + + { + return *this += -n; + } + + MOZ_SPAN_GCC_CONSTEXPR difference_type + operator-(const span_iterator& rhs) const { + MOZ_RELEASE_ASSERT(span_ == rhs.span_); + return index_ - rhs.index_; + } + + constexpr reference operator[](difference_type n) const { + return *(*this + n); + } + + constexpr friend bool operator==(const span_iterator& lhs, + const span_iterator& rhs) { + return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_; + } + + constexpr friend bool operator!=(const span_iterator& lhs, + const span_iterator& rhs) { + return !(lhs == rhs); + } + + MOZ_SPAN_GCC_CONSTEXPR friend bool operator<(const span_iterator& lhs, + const span_iterator& rhs) { + MOZ_RELEASE_ASSERT(lhs.span_ == rhs.span_); + return lhs.index_ < rhs.index_; + } + + constexpr friend bool operator<=(const span_iterator& lhs, + const span_iterator& rhs) { + return !(rhs < lhs); + } + + constexpr friend bool operator>(const span_iterator& lhs, + const span_iterator& rhs) { + return rhs < lhs; + } + + constexpr friend bool operator>=(const span_iterator& lhs, + const span_iterator& rhs) { + return !(rhs > lhs); + } + + void swap(span_iterator& rhs) { + std::swap(index_, rhs.index_); + std::swap(span_, rhs.span_); + } + + protected: + const Span* span_; + size_t index_; +}; + +template +inline constexpr span_iterator operator+( + typename span_iterator::difference_type n, + const span_iterator& rhs) { + return rhs + n; +} + +template +class extent_type { + public: + using index_type = size_t; + + static_assert(Ext >= 0, "A fixed-size Span must be >= 0 in size."); + + constexpr extent_type() {} + + template + MOZ_SPAN_ASSERTION_CONSTEXPR MOZ_IMPLICIT + extent_type(extent_type ext) { + static_assert( + Other == Ext || Other == dynamic_extent, + "Mismatch between fixed-size extent and size of initializing data."); + MOZ_RELEASE_ASSERT(ext.size() == Ext); + } + + MOZ_SPAN_ASSERTION_CONSTEXPR MOZ_IMPLICIT extent_type(index_type length) { + MOZ_RELEASE_ASSERT(length == Ext); + } + + constexpr index_type size() const { return Ext; } +}; + +template <> +class extent_type { + public: + using index_type = size_t; + + template + explicit constexpr extent_type(extent_type ext) : size_(ext.size()) {} + + explicit constexpr extent_type(index_type length) : size_(length) {} + + constexpr index_type size() const { return size_; } + + private: + index_type size_; +}; +} // namespace span_details + +/** + * Span - slices for C++ + * + * Span implements Rust's slice concept for C++. It's called "Span" instead of + * "Slice" to follow the naming used in C++ Core Guidelines. + * + * A Span wraps a pointer and a length that identify a non-owning view to a + * contiguous block of memory of objects of the same type. Various types, + * including (pre-decay) C arrays, XPCOM strings, nsTArray, mozilla::Array, + * mozilla::Range and contiguous standard-library containers, auto-convert + * into Spans when attempting to pass them as arguments to methods that take + * Spans. MakeSpan() functions can be used for explicit conversion in other + * contexts. (Span itself autoconverts into mozilla::Range.) + * + * Like Rust's slices, Span provides safety against out-of-bounds access by + * performing run-time bound checks. However, unlike Rust's slices, Span + * cannot provide safety against use-after-free. + * + * (Note: Span is like Rust's slice only conceptually. Due to the lack of + * ABI guarantees, you should still decompose spans/slices to raw pointer + * and length parts when crossing the FFI. The Elements() and data() methods + * are guaranteed to return a non-null pointer even for zero-length spans, + * so the pointer can be used as a raw part of a Rust slice without further + * checks.) + * + * In addition to having constructors and MakeSpan() functions that take + * various well-known types, a Span for an arbitrary type can be constructed + * (via constructor or MakeSpan()) from a pointer and a length or a pointer + * and another pointer pointing just past the last element. + * + * A Span or Span can be obtained for const char* + * or const char16_t pointing to a zero-terminated string using the + * MakeStringSpan() function. Corresponding implicit constructor does not exist + * in order to avoid accidental construction in cases where const char* or + * const char16_t* do not point to a zero-terminated string. + * + * Span has methods that follow the Mozilla naming style and methods that + * don't. The methods that follow the Mozilla naming style are meant to be + * used directly from Mozilla code. The methods that don't are meant for + * integration with C++11 range-based loops and with meta-programming that + * expects the same methods that are found on the standard-library + * containers. For example, to decompose a Span into its parts in Mozilla + * code, use Elements() and Length() (as with nsTArray) instead of data() + * and size() (as with std::vector). + * + * The pointer and length wrapped by a Span cannot be changed after a Span has + * been created. When new values are required, simply create a new Span. Span + * has a method called Subspan() that works analogously to the Substring() + * method of XPCOM strings taking a start index and an optional length. As a + * Mozilla extension (relative to Microsoft's gsl::span that mozilla::Span is + * based on), Span has methods From(start), To(end) and FromTo(start, end) + * that correspond to Rust's &slice[start..], &slice[..end] and + * &slice[start..end], respectively. (That is, the end index is the index of + * the first element not to be included in the new subspan.) + * + * When indicating a Span that's only read from, const goes inside the type + * parameter. Don't put const in front of Span. That is: + * size_t ReadsFromOneSpanAndWritesToAnother(Span aReadFrom, + * Span aWrittenTo); + * + * Any Span can be viewed as Span using the function + * AsBytes(). Any Span can be viewed as Span using the function + * AsWritableBytes(). + */ +template +class Span { + public: + // constants and types + using element_type = ElementType; + using index_type = size_t; + using pointer = element_type*; + using reference = element_type&; + + using iterator = + span_details::span_iterator, false>; + using const_iterator = + span_details::span_iterator, true>; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + constexpr static const index_type extent = Extent; + + // [Span.cons], Span constructors, copy, assignment, and destructor + // "Dependent" is needed to make "span_details::enable_if_t<(Dependent || + // Extent == 0 || Extent == mozilla::MaxValue::value)>" SFINAE, + // since "span_details::enable_if_t<(Extent == 0 || Extent == + // mozilla::MaxValue::value)>" is ill-formed when Extent is neither + // of the extreme values. + /** + * Constructor with no args. + */ + template ::value)>> + constexpr Span() : storage_(nullptr, span_details::extent_type<0>()) {} + + /** + * Constructor for nullptr. + */ + constexpr MOZ_IMPLICIT Span(std::nullptr_t) : Span() {} + + /** + * Constructor for pointer and length. + */ + constexpr Span(pointer aPtr, index_type aLength) : storage_(aPtr, aLength) {} + + /** + * Constructor for start pointer and pointer past end. + */ + constexpr Span(pointer aStartPtr, pointer aEndPtr) + : storage_(aStartPtr, std::distance(aStartPtr, aEndPtr)) {} + + /** + * Constructor for C array. + */ + template + constexpr MOZ_IMPLICIT Span(element_type (&aArr)[N]) + : storage_(&aArr[0], span_details::extent_type()) {} + + // Implicit constructors for char* and char16_t* pointers are deleted in order + // to avoid accidental construction in cases where a pointer does not point to + // a zero-terminated string. A Span or Span can be + // obtained for const char* or const char16_t pointing to a zero-terminated + // string using the MakeStringSpan() function. + Span(char* aStr) = delete; + Span(const char* aStr) = delete; + Span(char16_t* aStr) = delete; + Span(const char16_t* aStr) = delete; + + /** + * Constructor for std::array. + */ + template > + constexpr MOZ_IMPLICIT Span(std::array& aArr) + : storage_(&aArr[0], span_details::extent_type()) {} + + /** + * Constructor for const std::array. + */ + template + constexpr MOZ_IMPLICIT Span( + const std::array, N>& aArr) + : storage_(&aArr[0], span_details::extent_type()) {} + + /** + * Constructor for mozilla::Array. + */ + template > + constexpr MOZ_IMPLICIT Span(mozilla::Array& aArr) + : storage_(&aArr[0], span_details::extent_type()) {} + + /** + * Constructor for const mozilla::Array. + */ + template + constexpr MOZ_IMPLICIT Span( + const mozilla::Array, N>& aArr) + : storage_(&aArr[0], span_details::extent_type()) {} + + /** + * Constructor for mozilla::UniquePtr holding an array and length. + */ + template > + constexpr Span(const mozilla::UniquePtr& aPtr, + index_type aLength) + : storage_(aPtr.get(), aLength) {} + + // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the + // requirement on Container to be a contiguous sequence container. + /** + * Constructor for standard-library containers. + */ + template < + class Container, + class = span_details::enable_if_t< + !span_details::is_span::value && + !span_details::is_std_array::value && + mozilla::IsConvertible::value && + mozilla::IsConvertible< + typename Container::pointer, + decltype(mozilla::DeclVal().data())>::value>> + constexpr MOZ_IMPLICIT Span(Container& cont) + : Span(cont.data(), ReleaseAssertedCast(cont.size())) {} + + /** + * Constructor for standard-library containers (const version). + */ + template < + class Container, + class = span_details::enable_if_t< + mozilla::IsConst::value && + !span_details::is_span::value && + mozilla::IsConvertible::value && + mozilla::IsConvertible< + typename Container::pointer, + decltype(mozilla::DeclVal().data())>::value>> + constexpr MOZ_IMPLICIT Span(const Container& cont) + : Span(cont.data(), ReleaseAssertedCast(cont.size())) {} + + /** + * Constructor from other Span. + */ + constexpr Span(const Span& other) = default; + + /** + * Constructor from other Span. + */ + constexpr Span(Span&& other) = default; + + /** + * Constructor from other Span with conversion of element type. + */ + template ::value && + span_details::is_allowed_element_type_conversion< + OtherElementType, element_type>::value>> + constexpr MOZ_IMPLICIT Span(const Span& other) + : storage_(other.data(), + span_details::extent_type(other.size())) {} + + /** + * Constructor from other Span with conversion of element type. + */ + template ::value && + span_details::is_allowed_element_type_conversion< + OtherElementType, element_type>::value>> + constexpr MOZ_IMPLICIT Span(Span&& other) + : storage_(other.data(), + span_details::extent_type(other.size())) {} + + ~Span() = default; + MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR Span& operator=(const Span& other) = + default; + + MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR Span& operator=(Span&& other) = + default; + + // [Span.sub], Span subviews + /** + * Subspan with first N elements with compile-time N. + */ + template + constexpr Span First() const { + MOZ_RELEASE_ASSERT(Count <= size()); + return {data(), Count}; + } + + /** + * Subspan with last N elements with compile-time N. + */ + template + constexpr Span Last() const { + const size_t len = size(); + MOZ_RELEASE_ASSERT(Count <= len); + return {data() + (len - Count), Count}; + } + + /** + * Subspan with compile-time start index and length. + */ + template + constexpr Span Subspan() const { + const size_t len = size(); + MOZ_RELEASE_ASSERT(Offset <= len && + (Count == dynamic_extent || (Offset + Count <= len))); + return {data() + Offset, Count == dynamic_extent ? len - Offset : Count}; + } + + /** + * Subspan with first N elements with run-time N. + */ + constexpr Span First(index_type aCount) const { + MOZ_RELEASE_ASSERT(aCount <= size()); + return {data(), aCount}; + } + + /** + * Subspan with last N elements with run-time N. + */ + constexpr Span Last(index_type aCount) const { + const size_t len = size(); + MOZ_RELEASE_ASSERT(aCount <= len); + return {data() + (len - aCount), aCount}; + } + + /** + * Subspan with run-time start index and length. + */ + constexpr Span Subspan( + index_type aStart, index_type aLength = dynamic_extent) const { + const size_t len = size(); + MOZ_RELEASE_ASSERT(aStart <= len && (aLength == dynamic_extent || + (aStart + aLength <= len))); + return {data() + aStart, + aLength == dynamic_extent ? len - aStart : aLength}; + } + + /** + * Subspan with run-time start index. (Rust's &foo[start..]) + */ + constexpr Span From(index_type aStart) const { + return Subspan(aStart); + } + + /** + * Subspan with run-time exclusive end index. (Rust's &foo[..end]) + */ + constexpr Span To(index_type aEnd) const { + return Subspan(0, aEnd); + } + + /** + * Subspan with run-time start index and exclusive end index. + * (Rust's &foo[start..end]) + */ + constexpr Span FromTo(index_type aStart, + index_type aEnd) const { + MOZ_RELEASE_ASSERT(aStart <= aEnd); + return Subspan(aStart, aEnd - aStart); + } + + // [Span.obs], Span observers + /** + * Number of elements in the span. + */ + constexpr index_type Length() const { return size(); } + + /** + * Number of elements in the span (standard-libray duck typing version). + */ + constexpr index_type size() const { return storage_.size(); } + + /** + * Size of the span in bytes. + */ + constexpr index_type LengthBytes() const { return size_bytes(); } + + /** + * Size of the span in bytes (standard-library naming style version). + */ + constexpr index_type size_bytes() const { + return size() * narrow_cast(sizeof(element_type)); + } + + /** + * Checks if the the length of the span is zero. + */ + constexpr bool IsEmpty() const { return empty(); } + + /** + * Checks if the the length of the span is zero (standard-libray duck + * typing version). + */ + constexpr bool empty() const { return size() == 0; } + + // [Span.elem], Span element access + constexpr reference operator[](index_type idx) const { + MOZ_RELEASE_ASSERT(idx < storage_.size()); + return data()[idx]; + } + + /** + * Access element of span by index (standard-library duck typing version). + */ + constexpr reference at(index_type idx) const { return this->operator[](idx); } + + constexpr reference operator()(index_type idx) const { + return this->operator[](idx); + } + + /** + * Pointer to the first element of the span. The return value is never + * nullptr, not ever for zero-length spans, so it can be passed as-is + * to std::slice::from_raw_parts() in Rust. + */ + constexpr pointer Elements() const { return data(); } + + /** + * Pointer to the first element of the span (standard-libray duck typing + * version). The return value is never nullptr, not ever for zero-length + * spans, so it can be passed as-is to std::slice::from_raw_parts() in Rust. + */ + constexpr pointer data() const { return storage_.data(); } + + // [Span.iter], Span iterator support + iterator begin() const { return {this, 0}; } + iterator end() const { return {this, Length()}; } + + const_iterator cbegin() const { return {this, 0}; } + const_iterator cend() const { return {this, Length()}; } + + reverse_iterator rbegin() const { return reverse_iterator{end()}; } + reverse_iterator rend() const { return reverse_iterator{begin()}; } + + const_reverse_iterator crbegin() const { + return const_reverse_iterator{cend()}; + } + const_reverse_iterator crend() const { + return const_reverse_iterator{cbegin()}; + } + + private: + // this implementation detail class lets us take advantage of the + // empty base class optimization to pay for only storage of a single + // pointer in the case of fixed-size Spans + template + class storage_type : public ExtentType { + public: + template + MOZ_SPAN_ASSERTION_CONSTEXPR storage_type(pointer elements, + OtherExtentType ext) + : ExtentType(ext) + // Replace nullptr with 0x1 for Rust slice compatibility. See + // https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html + , + data_(elements ? elements : reinterpret_cast(0x1)) { + const size_t extentSize = ExtentType::size(); + MOZ_RELEASE_ASSERT( + (!elements && extentSize == 0) || + (elements && extentSize != mozilla::MaxValue::value)); + } + + constexpr pointer data() const { return data_; } + + private: + pointer data_; + }; + + storage_type> storage_; +}; + +// [Span.comparison], Span comparison operators +template +inline constexpr bool operator==(const Span& l, + const Span& r) { + return (l.size() == r.size()) && std::equal(l.begin(), l.end(), r.begin()); +} + +template +inline constexpr bool operator!=(const Span& l, + const Span& r) { + return !(l == r); +} + +template +inline constexpr bool operator<(const Span& l, + const Span& r) { + return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); +} + +template +inline constexpr bool operator<=(const Span& l, + const Span& r) { + return !(l > r); +} + +template +inline constexpr bool operator>(const Span& l, + const Span& r) { + return r < l; +} + +template +inline constexpr bool operator>=(const Span& l, + const Span& r) { + return !(l < r); +} + +namespace span_details { +// if we only supported compilers with good constexpr support then +// this pair of classes could collapse down to a constexpr function + +// we should use a narrow_cast<> to go to size_t, but older compilers may not +// see it as constexpr and so will fail compilation of the template +template +struct calculate_byte_size + : mozilla::IntegralConstant( + sizeof(ElementType) * + static_cast(Extent))> {}; + +template +struct calculate_byte_size + : mozilla::IntegralConstant {}; +} // namespace span_details + +// [Span.objectrep], views of object representation +/** + * View span as Span. + */ +template +Span::value> +AsBytes(Span s) { + return {reinterpret_cast(s.data()), s.size_bytes()}; +} + +/** + * View span as Span. + */ +template < + class ElementType, size_t Extent, + class = span_details::enable_if_t::value>> +Span::value> +AsWritableBytes(Span s) { + return {reinterpret_cast(s.data()), s.size_bytes()}; +} + +// +// MakeSpan() - Utility functions for creating Spans +// +/** + * Create span from pointer and length. + */ +template +Span MakeSpan(ElementType* aPtr, + typename Span::index_type aLength) { + return Span(aPtr, aLength); +} + +/** + * Create span from start pointer and pointer past end. + */ +template +Span MakeSpan(ElementType* aStartPtr, ElementType* aEndPtr) { + return Span(aStartPtr, aEndPtr); +} + +/** + * Create span from C array. + * MakeSpan() does not permit creating Span objects from string literals (const + * char or char16_t arrays) because the Span length would include the zero + * terminator, which may surprise callers. Use MakeStringSpan() to create a + * Span whose length that excludes the string literal's zero terminator or use + * the MakeSpan() overload that accepts a pointer and length and specify the + * string literal's full length. + */ +template ::value && + !IsSame::value>> +Span MakeSpan(ElementType (&aArr)[N]) { + return Span(aArr, N); +} + +/** + * Create span from mozilla::Array. + */ +template +Span MakeSpan(mozilla::Array& aArr) { + return aArr; +} + +/** + * Create span from const mozilla::Array. + */ +template +Span MakeSpan(const mozilla::Array& arr) { + return arr; +} + +/** + * Create span from standard-library container. + */ +template +Span MakeSpan(Container& cont) { + return Span(cont); +} + +/** + * Create span from standard-library container (const version). + */ +template +Span MakeSpan(const Container& cont) { + return Span(cont); +} + +/** + * Create span from smart pointer and length. + */ +template +Span MakeSpan(Ptr& aPtr, size_t aLength) { + return Span(aPtr, aLength); +} + +/** + * Create span from C string. + */ +inline Span MakeStringSpan(const char* aZeroTerminated) { + return Span(aZeroTerminated, std::strlen(aZeroTerminated)); +} + +/** + * Create span from UTF-16 C string. + */ +inline Span MakeStringSpan(const char16_t* aZeroTerminated) { + return Span(aZeroTerminated, + span_details::strlen16(aZeroTerminated)); +} + +} // namespace mozilla + +#ifdef _MSC_VER +#if _MSC_VER < 1910 +#undef constexpr +#pragma pop_macro("constexpr") + +#endif // _MSC_VER < 1910 + +#pragma warning(pop) +#endif // _MSC_VER + +#undef MOZ_SPAN_ASSERTION_CONSTEXPR +#undef MOZ_SPAN_GCC_CONSTEXPR +#undef MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR +#undef MOZ_SPAN_CONSTEXPR_NOT_JUST_RETURN +#undef MOZ_SPAN_NON_CONST_CONSTEXPR + +#endif // mozilla_Span_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 @@ -17,29 +17,23 @@ namespace mozilla { -template +template class SplayTree; -template -class SplayTreeNode -{ -public: - template +template +class SplayTreeNode { + public: + template friend class SplayTree; - SplayTreeNode() - : mLeft(nullptr) - , mRight(nullptr) - , mParent(nullptr) - {} + SplayTreeNode() : mLeft(nullptr), mRight(nullptr), mParent(nullptr) {} -private: + private: T* mLeft; T* mRight; T* mParent; }; - /** * Class which represents a splay tree. * Splay trees are balanced binary search trees for which search, insert and @@ -50,23 +44,16 @@ * compare(const T&, const T&) method ordering the elements. The compare * method must be free from side effects. */ -template -class SplayTree -{ +template +class SplayTree { T* mRoot; -public: - constexpr SplayTree() - : mRoot(nullptr) - {} - - bool empty() const - { - return !mRoot; - } + public: + constexpr SplayTree() : mRoot(nullptr) {} - T* find(const T& aValue) - { + bool empty() const { return !mRoot; } + + T* find(const T& aValue) { if (empty()) { return nullptr; } @@ -76,8 +63,7 @@ return Comparator::compare(aValue, *last) == 0 ? last : nullptr; } - void insert(T* aValue) - { + void insert(T* aValue) { MOZ_ASSERT(!find(*aValue), "Duplicate elements are not allowed."); if (!mRoot) { @@ -88,13 +74,11 @@ int cmp = Comparator::compare(*aValue, *last); finishInsertion(last, cmp, aValue); - return; } T* findOrInsert(const T& aValue); - T* remove(const T& aValue) - { + T* remove(const T& aValue) { T* last = lookup(aValue); MOZ_ASSERT(last, "This tree must contain the element being removed."); MOZ_ASSERT(Comparator::compare(aValue, *last) == 0); @@ -152,8 +136,7 @@ return last; } - T* removeMin() - { + T* removeMin() { MOZ_ASSERT(mRoot, "No min to remove!"); T* min = mRoot; @@ -164,18 +147,14 @@ } // For testing purposes only. - void checkCoherency() - { - checkCoherency(mRoot, nullptr); - } + void checkCoherency() { checkCoherency(mRoot, nullptr); } -private: + private: /** * Returns the node in this comparing equal to |aValue|, or a node just * greater or just less than |aValue| if there is no such node. */ - T* lookup(const T& aValue) - { + T* lookup(const T& aValue) { MOZ_ASSERT(!empty()); T* node = mRoot; @@ -194,8 +173,7 @@ return parent; } - void 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!"); T** parentPointer = (aCmp < 0) ? &aLast->mLeft : &aLast->mRight; @@ -211,8 +189,7 @@ * the rotations in this fashion preserves the amortized balancing of * the tree. */ - void splay(T* aNode) - { + void splay(T* aNode) { MOZ_ASSERT(aNode); while (aNode != mRoot) { @@ -236,8 +213,7 @@ } } - void rotate(T* aNode) - { + void rotate(T* aNode) { // Rearrange nodes so that aNode becomes the parent of its current // parent, while preserving the sortedness of the tree. T* parent = aNode->mParent; @@ -274,8 +250,7 @@ } } - T* checkCoherency(T* aNode, T* aMinimum) - { + T* checkCoherency(T* aNode, T* aMinimum) { if (mRoot) { MOZ_RELEASE_ASSERT(!mRoot->mParent); } @@ -305,10 +280,8 @@ void operator=(const SplayTree&) = delete; }; -template -T* -SplayTree::findOrInsert(const T& aValue) -{ +template +T* SplayTree::findOrInsert(const T& aValue) { if (!mRoot) { mRoot = new T(aValue); return mRoot; @@ -325,6 +298,6 @@ return t; } -} /* namespace mozilla */ +} /* namespace mozilla */ #endif /* mozilla_SplayTree_h */ 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 @@ -18,18 +18,17 @@ #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; +MOZ_FORMAT_PRINTF(2, 0) +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, ...) -{ +int SprintfLiteral(char (&buffer)[N], const char* format, ...) { va_list args; va_start(args, format); int result = VsprintfLiteral(buffer, format, args); @@ -38,4 +37,4 @@ } #endif -#endif /* mozilla_Sprintf_h_ */ +#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 @@ -4,18 +4,16 @@ * 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/. */ -/* API for getting a stack trace of the C/C++ stack on the current thread */ +/* APIs for getting a stack trace of the current thread */ #ifndef mozilla_StackWalk_h #define mozilla_StackWalk_h -/* WARNING: This file is intended to be included from C or C++ files. */ - #include "mozilla/Types.h" #include /** - * The callback for MozStackWalk. + * The callback for MozStackWalk and MozStackWalkThread. * * @param aFrameNumber The frame number (starts at 1, not 0). * @param aPC The program counter value. @@ -23,14 +21,14 @@ * pointer will be pointing to when the execution returns * to executing that at aPC. If no approximation can * be made it will be nullptr. - * @param aClosure Extra data passed in via MozStackWalk(). + * @param aClosure Extra data passed in from MozStackWalk() or + * MozStackWalkThread(). */ -typedef void -(*MozWalkStackCallback)(uint32_t aFrameNumber, void* aPC, void* aSP, - void* aClosure); +typedef void (*MozWalkStackCallback)(uint32_t aFrameNumber, void* aPC, + void* aSP, void* aClosure); /** - * Call aCallback for the C/C++ stack frames on the current thread, from + * Call aCallback for each stack frame on the current thread, from * the caller of MozStackWalk to main (or above). * * @param aCallback Callback function, called once per frame. @@ -39,27 +37,47 @@ * MozStackWalk. * @param aMaxFrames Maximum number of frames to trace. 0 means no limit. * @param aClosure Caller-supplied data passed through to aCallback. - * @param aThread The thread for which the stack is to be retrieved. - * Passing null causes us to walk the stack of the - * current thread. On Windows, this is a thread HANDLE. - * It is currently not supported on any other platform. - * @param aPlatformData Platform specific data that can help in walking the - * stack, this should be nullptr unless you really know - * what you're doing! This needs to be a pointer to a - * CONTEXT on Windows and should not be passed on other - * platforms. * * May skip some stack frames due to compiler optimizations or code * generation. - * */ -MFBT_API bool -MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames, - uint32_t aMaxFrames, void* aClosure, uintptr_t aThread, - void* aPlatformData); +MFBT_API void MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames, + uint32_t aMaxFrames, void* aClosure); + +#if defined(_WIN32) && \ + (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_IA64)) + +#include + +#define MOZ_STACKWALK_SUPPORTS_WINDOWS 1 + +/** + * Like MozStackWalk, but walks the stack for another thread. + * Call aCallback for each stack frame on the current thread, from + * the caller of MozStackWalk to main (or above). + * + * @param aCallback Same as for MozStackWalk(). + * @param aSkipFrames Same as for MozStackWalk(). + * @param aMaxFrames Same as for MozStackWalk(). + * @param aClosure Same as for MozStackWalk(). + * @param aThread The handle of the thread whose stack is to be walked. + * If 0, walks the current thread. + * @param aContext A CONTEXT, presumably obtained with GetThreadContext() + * after suspending the thread with SuspendThread(). If + * null, the CONTEXT will be re-obtained. + */ +MFBT_API void MozStackWalkThread(MozWalkStackCallback aCallback, + uint32_t aSkipFrames, uint32_t aMaxFrames, + void* aClosure, HANDLE aThread, + CONTEXT* aContext); + +#else + +#define MOZ_STACKWALK_SUPPORTS_WINDOWS 0 + +#endif -typedef struct -{ +typedef struct { /* * The name of the shared library or executable containing an * address and the address's offset within that library, or empty @@ -89,8 +107,8 @@ * @param aPC The code address. * @param aDetails A structure to be filled in with the result. */ -MFBT_API bool -MozDescribeCodeAddress(void* aPC, MozCodeAddressDetails* aDetails); +MFBT_API bool MozDescribeCodeAddress(void* aPC, + MozCodeAddressDetails* aDetails); /** * Format the information about a code address in a format suitable for @@ -118,11 +136,11 @@ * @param aFileName The filename. Possibly null or the empty string. * @param aLineNo The line number. Possibly zero. */ -MFBT_API void -MozFormatCodeAddress(char* aBuffer, uint32_t aBufferSize, uint32_t aFrameNumber, - const void* aPC, const char* aFunction, - const char* aLibrary, ptrdiff_t aLOffset, - const char* aFileName, uint32_t aLineNo); +MFBT_API void MozFormatCodeAddress(char* aBuffer, uint32_t aBufferSize, + uint32_t aFrameNumber, const void* aPC, + const char* aFunction, const char* aLibrary, + ptrdiff_t aLOffset, const char* aFileName, + uint32_t aLineNo); /** * Format the information about a code address in the same fashion as @@ -139,25 +157,17 @@ * @param aPC The code address. * @param aDetails The value filled in by MozDescribeCodeAddress(aPC). */ -MFBT_API void -MozFormatCodeAddressDetails(char* aBuffer, uint32_t aBufferSize, - uint32_t aFrameNumber, void* aPC, - const MozCodeAddressDetails* aDetails); +MFBT_API void MozFormatCodeAddressDetails( + char* aBuffer, uint32_t aBufferSize, uint32_t aFrameNumber, void* aPC, + const MozCodeAddressDetails* aDetails); namespace mozilla { -MFBT_API bool -FramePointerStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames, - uint32_t aMaxFrames, void* aClosure, void** aBp, - void* aStackEnd); - -} // namespace mozilla +MFBT_API void FramePointerStackWalk(MozWalkStackCallback aCallback, + uint32_t aSkipFrames, uint32_t aMaxFrames, + void* aClosure, void** aBp, + void* aStackEnd); -/** - * Initialize the critical sections for this platform so that we can - * abort stack walks when needed. - */ -MFBT_API void -StackWalkInitCriticalAddress(void); +} // namespace mozilla #endif 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 @@ -3,19 +3,21 @@ #include "mozilla/Types.h" +#ifdef _M_AMD64 /** * 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(); +struct MOZ_RAII AutoSuppressStackWalking { + MFBT_API AutoSuppressStackWalking(); + MFBT_API ~AutoSuppressStackWalking(); +}; -MFBT_API bool -TryAcquireStackWalkWorkaroundLock(); +MFBT_API void RegisterJitCodeRegion(uint8_t* aStart, size_t size); -MFBT_API void -ReleaseStackWalkWorkaroundLock(); +MFBT_API void UnregisterJitCodeRegion(uint8_t* aStart, size_t size); +#endif // _M_AMD64 -#endif // mozilla_StackWalk_windows_h +#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 @@ -21,10 +21,22 @@ #ifdef MOZ_CLANG_PLUGIN #ifdef __cplusplus +/** + * MOZ_KnownLive - used to opt an argument out of the CanRunScript checker so + * that we don't check it if is a strong ref. + * + * Example: + * canRunScript(MOZ_KnownLive(rawPointer)); + */ +template +static MOZ_ALWAYS_INLINE T* MOZ_KnownLive(T* ptr) { + return ptr; +} + extern "C" { #endif -/* +/** * MOZ_AssertAssignmentTest - used in MOZ_ASSERT in order to test the possible * presence of assignment instead of logical comparisons. * @@ -44,6 +56,7 @@ #else #define MOZ_CHECK_ASSERT_ASSIGNMENT(expr) (!!(expr)) +#define MOZ_KnownLive(expr) (expr) #endif /* MOZ_CLANG_PLUGIN */ -#endif /* StaticAnalysisFunctions_h */ \ No newline at end of file +#endif /* StaticAnalysisFunctions_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TaggedAnonymousMemory.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TaggedAnonymousMemory.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TaggedAnonymousMemory.h @@ -45,42 +45,34 @@ extern "C" { #endif -MFBT_API void -MozTagAnonymousMemory(const void* aPtr, size_t aLength, const char* aTag); +MFBT_API void MozTagAnonymousMemory(const void* aPtr, size_t aLength, + const char* aTag); -MFBT_API void* -MozTaggedAnonymousMmap(void* aAddr, size_t aLength, int aProt, int aFlags, - int aFd, off_t aOffset, const char* aTag); +MFBT_API void* MozTaggedAnonymousMmap(void* aAddr, size_t aLength, int aProt, + int aFlags, int aFd, off_t aOffset, + const char* aTag); -MFBT_API int -MozTaggedMemoryIsSupported(void); +MFBT_API int MozTaggedMemoryIsSupported(void); #ifdef __cplusplus -} // extern "C" +} // extern "C" #endif -#else // ANDROID +#else // ANDROID -static inline void -MozTagAnonymousMemory(const void* aPtr, size_t aLength, const char* aTag) -{ -} +static inline void MozTagAnonymousMemory(const void* aPtr, size_t aLength, + const char* aTag) {} -static inline void* -MozTaggedAnonymousMmap(void* aAddr, size_t aLength, int aProt, int aFlags, - int aFd, off_t aOffset, const char* aTag) -{ +static inline void* MozTaggedAnonymousMmap(void* aAddr, size_t aLength, + int aProt, int aFlags, int aFd, + off_t aOffset, const char* aTag) { return mmap(aAddr, aLength, aProt, aFlags, aFd, aOffset); } -static inline int -MozTaggedMemoryIsSupported(void) -{ - return 0; -} +static inline int MozTaggedMemoryIsSupported(void) { return 0; } -#endif // ANDROID +#endif // ANDROID -#endif // !XP_WIN +#endif // !XP_WIN -#endif // mozilla_TaggedAnonymousMemory_h +#endif // mozilla_TaggedAnonymousMemory_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TemplateLib.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TemplateLib.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/TemplateLib.h @@ -27,49 +27,60 @@ namespace tl { /** Compute min/max. */ -template -struct Min -{ - static const size_t value = I < J ? I : J; -}; -template -struct Max -{ - static const size_t value = I > J ? I : J; +template +struct Min { + static constexpr size_t value = + Size < Min::value ? Size : Min::value; +}; + +template +struct Min { + static constexpr size_t value = Size; +}; + +template +struct Max { + static constexpr size_t value = + Size > Max::value ? Size : Max::value; +}; + +template +struct Max { + static constexpr size_t value = Size; }; /** Compute floor(log2(i)). */ -template -struct FloorLog2 -{ +template +struct FloorLog2 { static const size_t value = 1 + FloorLog2::value; }; -template<> struct FloorLog2<0> { /* Error */ }; -template<> struct FloorLog2<1> { static const size_t value = 0; }; +template <> +struct FloorLog2<0> { /* Error */ +}; +template <> +struct FloorLog2<1> { + static const size_t value = 0; +}; /** Compute ceiling(log2(i)). */ -template -struct CeilingLog2 -{ +template +struct CeilingLog2 { static const size_t value = FloorLog2<2 * I - 1>::value; }; /** Round up to the nearest power of 2. */ -template -struct RoundUpPow2 -{ +template +struct RoundUpPow2 { static const size_t value = size_t(1) << CeilingLog2::value; }; -template<> -struct RoundUpPow2<0> -{ +template <> +struct RoundUpPow2<0> { static const size_t value = 1; }; /** Compute the number of bits in the given unsigned type. */ -template -struct BitSize -{ +template +struct BitSize { static const size_t value = sizeof(T) * CHAR_BIT; }; @@ -77,20 +88,18 @@ * Produce an N-bit mask, where N <= BitSize::value. Handle the * language-undefined edge case when N = BitSize::value. */ -template -struct NBitMask -{ +template +struct NBitMask { // Assert the precondition. On success this evaluates to 0. Otherwise it // triggers divide-by-zero at compile time: a guaranteed compile error in // C++11, and usually one in C++98. Add this value to |value| to assure // its computation. static const size_t checkPrecondition = - 0 / size_t(N < BitSize::value); + 0 / size_t(N < BitSize::value); static const size_t value = (size_t(1) << N) - 1 + checkPrecondition; }; -template<> -struct NBitMask::value> -{ +template <> +struct NBitMask::value> { static const size_t value = size_t(-1); }; @@ -98,14 +107,18 @@ * For the unsigned integral type size_t, compute a mask M for N such that * for all X, !(X & M) implies X * N will not overflow (w.r.t size_t) */ -template -struct MulOverflowMask -{ +template +struct MulOverflowMask { static const size_t value = - ~NBitMask::value - CeilingLog2::value>::value; + ~NBitMask::value - CeilingLog2::value>::value; +}; +template <> +struct MulOverflowMask<0> { /* Error */ +}; +template <> +struct MulOverflowMask<1> { + static const size_t value = 0; }; -template<> struct MulOverflowMask<0> { /* Error */ }; -template<> struct MulOverflowMask<1> { static const size_t value = 0; }; /** * And computes the logical 'and' of its argument booleans. @@ -116,18 +129,17 @@ * mozilla::t1::And<>::value is true. */ -template +template struct And; -template<> -struct And<> : public TrueType { }; +template <> +struct And<> : public TrueType {}; -template -struct And - : public Conditional, FalseType>::Type { }; +template +struct And : public Conditional, FalseType>::Type {}; -} // namespace tl +} // namespace tl -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_TemplateLib_h */ 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 @@ -15,26 +15,27 @@ namespace detail { -template -class MakeUnsignedChar - : public MakeUnsigned -{}; - -template<> -class MakeUnsignedChar -{ -public: +template +class MakeUnsignedChar : public MakeUnsigned {}; + +template <> +class MakeUnsignedChar { + public: using Type = char16_t; }; -template<> -class MakeUnsignedChar -{ -public: +template <> +class MakeUnsignedChar { + public: using Type = char32_t; }; -} // namespace detail +template +constexpr bool IsAsciiAlpha(Char aChar) { + return ('a' <= aChar && aChar <= 'z') || ('A' <= aChar && aChar <= 'Z'); +} + +} // namespace detail /** * Returns true iff |aChar| matches [a-zA-Z]. @@ -42,17 +43,12 @@ * 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'); +template +constexpr bool IsAsciiAlpha(Char aChar) { + return detail::IsAsciiAlpha( + static_cast::Type>(aChar)); } -} // namespace mozilla +} // 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 @@ -9,22 +9,8 @@ #ifndef mozilla_ThreadLocal_h #define mozilla_ThreadLocal_h -#if defined(XP_WIN) -// This file will get included in any file that wants to add a profiler mark. -// In order to not bring together we could include windef.h and -// winbase.h which are sufficient to get the prototypes for the Tls* functions. -// # include -// # include -// Unfortunately, even including these headers causes us to add a bunch of ugly -// stuff to our namespace e.g #define CreateEvent CreateEventW -extern "C" { -__declspec(dllimport) void* __stdcall TlsGetValue(unsigned long); -__declspec(dllimport) int __stdcall TlsSetValue(unsigned long, void*); -__declspec(dllimport) unsigned long __stdcall TlsAlloc(); -} -#else -# include -# include +#if !defined(XP_WIN) +#include #endif #include "mozilla/Assertions.h" @@ -33,19 +19,14 @@ namespace mozilla { -// sig_safe_t denotes an atomic type which can be read or stored in a single -// instruction. This means that data of this type is safe to be manipulated -// from a signal handler, or other similar asynchronous execution contexts. -#if defined(XP_WIN) -typedef unsigned long sig_safe_t; -#else -typedef sig_atomic_t sig_safe_t; -#endif - namespace detail { -#if defined(HAVE_THREAD_TLS_KEYWORD) -#define MOZ_HAS_THREAD_LOCAL +#ifdef XP_MACOSX +#if defined(__has_feature) +#if __has_feature(cxx_thread_local) +#define MACOSX_HAS_THREAD_LOCAL +#endif +#endif #endif /* @@ -87,69 +68,120 @@ * // Get the TLS value * int value = tlsKey.get(); */ -template -class ThreadLocal -{ -#ifndef MOZ_HAS_THREAD_LOCAL + +// Integral types narrower than void* must be extended to avoid +// warnings from valgrind on some platforms. This helper type +// achieves that without penalizing the common case of ThreadLocals +// instantiated using a pointer type. +template +struct Helper { + typedef uintptr_t Type; +}; + +template +struct Helper { + typedef S* Type; +}; + #if defined(XP_WIN) - typedef unsigned long key_t; -#else - typedef pthread_key_t key_t; -#endif +/* + * ThreadLocalKeyStorage uses Thread Local APIs that are declared in + * processthreadsapi.h. To use this class on Windows, include that file + * (or windows.h) before including ThreadLocal.h. + * + * TLS_OUT_OF_INDEXES is a #define that is used to detect whether + * an appropriate header has been included prior to this file + */ +#if defined(TLS_OUT_OF_INDEXES) +/* Despite not being used for MOZ_THREAD_LOCAL, we expose an implementation for + * Windows for cases where it's not desirable to use thread_local */ +template +class ThreadLocalKeyStorage { + public: + ThreadLocalKeyStorage() : mKey(TLS_OUT_OF_INDEXES) {} + + inline bool initialized() const { return mKey != TLS_OUT_OF_INDEXES; } + + inline void init() { mKey = TlsAlloc(); } + + inline T get() const { + void* h = TlsGetValue(mKey); + return static_cast(reinterpret_cast::Type>(h)); + } - // Integral types narrower than void* must be extended to avoid - // warnings from valgrind on some platforms. This helper type - // achieves that without penalizing the common case of ThreadLocals - // instantiated using a pointer type. - template - struct Helper - { - typedef uintptr_t Type; - }; - - template - struct Helper - { - typedef S *Type; - }; -#endif + inline bool set(const T aValue) { + void* h = + reinterpret_cast(static_cast::Type>(aValue)); + return TlsSetValue(mKey, h); + } - bool initialized() const { -#ifdef MOZ_HAS_THREAD_LOCAL - return true; -#else - return mInited; + private: + unsigned long mKey; +}; #endif +#else +template +class ThreadLocalKeyStorage { + public: + constexpr ThreadLocalKeyStorage() : mKey(0), mInited(false) {} + + inline bool initialized() const { return mInited; } + + inline void init() { mInited = !pthread_key_create(&mKey, nullptr); } + + inline T get() const { + void* h = pthread_getspecific(mKey); + return static_cast(reinterpret_cast::Type>(h)); } -public: + inline bool set(const T aValue) { + void* h = + reinterpret_cast(static_cast::Type>(aValue)); + return !pthread_setspecific(mKey, h); + } + + private: + pthread_key_t mKey; + bool mInited; +}; +#endif + +template +class ThreadLocalNativeStorage { + public: // __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 + inline bool initialized() const { return true; } + + inline void init() {} + + inline T get() const { return mValue; } + + inline bool set(const T aValue) { + mValue = aValue; + return true; + } + private: + T mValue; +}; + +template class Storage> +class ThreadLocal : public Storage { + public: MOZ_MUST_USE inline bool init(); + void infallibleInit() { + MOZ_RELEASE_ASSERT(init(), "Infallible TLS initialization failed"); + } + inline T get() const; inline void set(const T aValue); - -private: -#ifdef MOZ_HAS_THREAD_LOCAL - T mValue; -#else - key_t mKey; - bool mInited; -#endif }; -template -inline bool -ThreadLocal::init() -{ +template class Storage> +inline bool ThreadLocal::init() { static_assert(mozilla::IsPointer::value || mozilla::IsIntegral::value, "mozilla::ThreadLocal must be used with a pointer or " "integral type"); @@ -157,66 +189,42 @@ "mozilla::ThreadLocal can't be used for types larger than " "a pointer"); -#ifdef MOZ_HAS_THREAD_LOCAL - return true; -#else - if (!initialized()) { -#ifdef XP_WIN - mKey = TlsAlloc(); - mInited = mKey != 0xFFFFFFFFUL; // TLS_OUT_OF_INDEXES -#else - mInited = !pthread_key_create(&mKey, nullptr); -#endif + if (!Storage::initialized()) { + Storage::init(); } - return mInited; -#endif + return Storage::initialized(); } -template -inline T -ThreadLocal::get() const -{ -#ifdef MOZ_HAS_THREAD_LOCAL - return mValue; -#else - MOZ_ASSERT(initialized()); - void* h; -#ifdef XP_WIN - h = TlsGetValue(mKey); -#else - h = pthread_getspecific(mKey); -#endif - return static_cast(reinterpret_cast::Type>(h)); -#endif +template class Storage> +inline T ThreadLocal::get() const { + MOZ_ASSERT(Storage::initialized()); + return Storage::get(); } -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 - bool succeeded = TlsSetValue(mKey, h); -#else - bool succeeded = !pthread_setspecific(mKey, h); -#endif +template class Storage> +inline void ThreadLocal::set(const T aValue) { + MOZ_ASSERT(Storage::initialized()); + bool succeeded = Storage::set(aValue); if (!succeeded) { MOZ_CRASH(); } -#endif } -#ifdef MOZ_HAS_THREAD_LOCAL -#define MOZ_THREAD_LOCAL(TYPE) __thread mozilla::detail::ThreadLocal +#if (defined(XP_WIN) || defined(MACOSX_HAS_THREAD_LOCAL)) && \ + !defined(__MINGW32__) +#define MOZ_THREAD_LOCAL(TYPE) \ + thread_local mozilla::detail::ThreadLocal< \ + TYPE, mozilla::detail::ThreadLocalNativeStorage> +#elif defined(HAVE_THREAD_TLS_KEYWORD) +#define MOZ_THREAD_LOCAL(TYPE) \ + __thread mozilla::detail::ThreadLocal< \ + TYPE, mozilla::detail::ThreadLocalNativeStorage> #else -#define MOZ_THREAD_LOCAL(TYPE) mozilla::detail::ThreadLocal +#define MOZ_THREAD_LOCAL(TYPE) \ + mozilla::detail::ThreadLocal #endif -} // namespace detail -} // namespace mozilla +} // namespace detail +} // namespace mozilla #endif /* mozilla_ThreadLocal_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ThreadSafeWeakPtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ThreadSafeWeakPtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ThreadSafeWeakPtr.h @@ -0,0 +1,346 @@ +/* -*- 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 thread-safe weak pointer */ + +/** + * Derive from SupportsThreadSafeWeakPtr to allow thread-safe weak pointers to + * an atomically refcounted derived class. These thread-safe weak pointers may + * be safely accessed and converted to strong pointers on multiple threads. + * + * Note that SupportsThreadSafeWeakPtr necessarily already inherits from + * AtomicRefCounted, so you should not separately inherit from AtomicRefCounted. + * + * ThreadSafeWeakPtr and its implementation is distinct from the normal WeakPtr + * which is not thread-safe. The interface discipline and implementation details + * are different enough that these two implementations are separated for now for + * efficiency reasons. If you don't actually need to use weak pointers on + * multiple threads, you can just use WeakPtr instead. + * + * When deriving from SupportsThreadSafeWeakPtr, you should add + * MOZ_DECLARE_THREADSAFEWEAKREFERENCE_TYPENAME(ClassName) and + * MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public section of your + * class, where ClassName is the name of your class. + * + * Example usage: + * + * class C : public SupportsThreadSafeWeakPtr + * { + * public: + * MOZ_DECLARE_THREADSAFEWEAKREFERENCE_TYPENAME(C) + * MOZ_DECLARE_REFCOUNTED_TYPENAME(C) + * void doStuff(); + * }; + * + * ThreadSafeWeakPtr weak; + * { + * RefPtr strong = new C; + * if (strong) { + * strong->doStuff(); + * } + * // Make a new weak reference to the object from the strong reference. + * weak = strong; + * } + * MOZ_ASSERT(!bool(weak), "Weak pointers are cleared after all " + * "strong references are released."); + * + * // Convert the weak reference to a strong reference for usage. + * RefPtr other(weak); + * if (other) { + * other->doStuff(); + * } + */ + +#ifndef mozilla_ThreadSafeWeakPtr_h +#define mozilla_ThreadSafeWeakPtr_h + +#include "mozilla/Assertions.h" +#include "mozilla/Atomics.h" +#include "mozilla/RefCounted.h" +#include "mozilla/RefPtr.h" +#include "mozilla/TypeTraits.h" +#include "mozilla/Unused.h" + +#include + +namespace mozilla { + +template +class ThreadSafeWeakPtr; +template +class SupportsThreadSafeWeakPtr; + +#ifdef MOZ_REFCOUNTED_LEAK_CHECKING +#define MOZ_DECLARE_THREADSAFEWEAKREFERENCE_TYPENAME(T) \ + static const char* threadSafeWeakReferenceTypeName() { \ + return "ThreadSafeWeakReference<" #T ">"; \ + } +#else +#define MOZ_DECLARE_THREADSAFEWEAKREFERENCE_TYPENAME(T) +#endif + +namespace detail { + +// A multiple reader, single writer spin-lock. +// This lock maintains an atomic counter which is incremented every time the +// lock is acquired reading. So long as the counter remains positive, it may be +// incremented for reading multiple times. When acquiring the lock for writing, +// we must ensure the counter is 0 (no readers), and if so, set it to a negative +// value to indicate that no new readers may take the lock. +class ReadWriteSpinLock { + // Only need a type large enough to represent the number of simultaneously + // accessing threads. + typedef int32_t CounterType; + + public: + // Try to increment the counter for reading, so long as it is positive. + void readLock() { + for (;;) { + CounterType oldCounter = + mCounter & std::numeric_limits::max(); + CounterType newCounter = oldCounter + 1; + if (mCounter.compareExchange(oldCounter, newCounter)) { + break; + } + } + } + + // Decrement the counter to remove a read lock. + void readUnlock() { mCounter--; } + + // Try to acquire the write lock, but only if there are no readers. + // If successful, sets the counter to a negative value. + bool tryWriteLock() { + return mCounter.compareExchange(0, std::numeric_limits::min()); + } + + // Reset the counter to 0. + void writeUnlock() { mCounter = 0; } + + private: + Atomic mCounter; +}; + +// A shared weak reference that is used to track a SupportsThreadSafeWeakPtr +// object. It guards access to that object via a read-write spinlock. +template +class ThreadSafeWeakReference + : public external::AtomicRefCounted> { + public: + typedef T ElementType; + + explicit ThreadSafeWeakReference(T* aPtr) { mPtr = aPtr; } + +#ifdef MOZ_REFCOUNTED_LEAK_CHECKING + const char* typeName() const { + // The first time this is called mPtr is null, so don't + // invoke any methods on mPtr. + return T::threadSafeWeakReferenceTypeName(); + } + size_t typeSize() const { return sizeof(*this); } +#endif + + private: + friend class mozilla::SupportsThreadSafeWeakPtr; + template + friend class mozilla::ThreadSafeWeakPtr; + + // Does an unsafe read of the raw weak pointer. + T* get() const { return mPtr; } + + // Creates a new RefPtr to the tracked object. + // We need to acquire the read lock while we do this, as we need to atomically + // both read the pointer and then increment the refcount on it within the + // scope of the lock. This guards against the object being destroyed while in + // the middle of creating the new RefPtr. + already_AddRefed getRefPtr() { + mLock.readLock(); + RefPtr result(get()); + mLock.readUnlock(); + return result.forget(); + } + + // Try to detach the weak reference from the tracked object. + // We need to acquire the write lock while we do this, to ensure that no + // RefPtr is created to this while detaching. Once acquired, it is safe + // to check the refcount and verify that this is the last reference to + // the tracked object, so the weak reference can be safely detached. + void tryDetach(const SupportsThreadSafeWeakPtr* aOwner) { + if (mLock.tryWriteLock()) { + if (aOwner->hasOneRef()) { + mPtr = nullptr; + } + mLock.writeUnlock(); + } + } + + ReadWriteSpinLock mLock; + Atomic mPtr; +}; + +} // namespace detail + +template +class SupportsThreadSafeWeakPtr : public external::AtomicRefCounted { + protected: + typedef external::AtomicRefCounted AtomicRefCounted; + typedef detail::ThreadSafeWeakReference ThreadSafeWeakReference; + + public: + ~SupportsThreadSafeWeakPtr() { + // Clean up the shared weak reference if one exists. + if (ThreadSafeWeakReference* ptr = mRef) { + ptr->Release(); + } + } + + void Release() const { + // If there is only one remaining reference to the object when trying to + // release, then attempt to detach it from its weak reference. New + // references could possibly be created to the object while this happens, so + // take care to do this atomically inside tryDetach. + if (AtomicRefCounted::hasOneRef()) { + if (ThreadSafeWeakReference* ptr = mRef) { + ptr->tryDetach(this); + } + } + + // Once possibly detached, it is now safe to continue to decrement the + // refcount. + AtomicRefCounted::Release(); + } + + private: + template + friend class ThreadSafeWeakPtr; + + // Creates a shared weak reference for the object if one does not exist. Note + // that the object may be of an actual derived type U, but the weak reference + // is created for the supplied type T of SupportsThreadSafeWeakPtr. + already_AddRefed getThreadSafeWeakReference() { + static_assert(IsBaseOf, T>::value, + "T must derive from SupportsThreadSafeWeakPtr"); + + if (!mRef) { + RefPtr ptr( + new ThreadSafeWeakReference(static_cast(this))); + // Only set the new weak reference if one does not exist (== nullptr). + // If there is already a weak reference, just let this superflous weak + // reference get destroyed when it goes out of scope. + if (mRef.compareExchange(nullptr, ptr)) { + // If successful, forget the refcount so that the weak reference stays + // alive. + Unused << ptr.forget(); + } + } + + // Create a new RefPtr to weak reference. + RefPtr ptr(mRef); + return ptr.forget(); + } + + Atomic mRef; +}; + +// A thread-safe variant of a weak pointer +template +class ThreadSafeWeakPtr { + // Be careful to use the weak reference type T in the + // SupportsThreadSafeWeakPtr definition. + typedef typename T::ThreadSafeWeakReference ThreadSafeWeakReference; + + public: + ThreadSafeWeakPtr() {} + + ThreadSafeWeakPtr& operator=(const ThreadSafeWeakPtr& aOther) { + mRef = aOther.mRef; + return *this; + } + + ThreadSafeWeakPtr(const ThreadSafeWeakPtr& aOther) : mRef(aOther.mRef) {} + + ThreadSafeWeakPtr& operator=(ThreadSafeWeakPtr&& aOther) { + mRef = aOther.mRef.forget(); + return *this; + } + + ThreadSafeWeakPtr(ThreadSafeWeakPtr&& aOther) : mRef(aOther.mRef.forget()) {} + + ThreadSafeWeakPtr& operator=(const RefPtr& aOther) { + if (aOther) { + // Get the underlying shared weak reference to the object, creating one if + // necessary. + mRef = aOther->getThreadSafeWeakReference(); + } else { + mRef = nullptr; + } + return *this; + } + + explicit ThreadSafeWeakPtr(const RefPtr& aOther) { *this = aOther; } + + ThreadSafeWeakPtr& operator=(decltype(nullptr)) { + mRef = nullptr; + return *this; + } + + explicit ThreadSafeWeakPtr(decltype(nullptr)) {} + + explicit operator bool() const { return !!get(); } + + bool operator==(const ThreadSafeWeakPtr& aOther) const { + return get() == aOther.get(); + } + + bool operator==(const RefPtr& aOther) const { + return get() == aOther.get(); + } + + bool operator==(const T* aOther) const { return get() == aOther; } + + template + bool operator!=(const U& aOther) const { + return !(*this == aOther); + } + + // Convert the weak pointer to a strong RefPtr. + explicit operator RefPtr() const { return getRefPtr(); } + + private: + // Gets a new strong reference of the proper type T to the tracked object. + already_AddRefed getRefPtr() const { + static_assert( + IsBaseOf::value, + "T must derive from ThreadSafeWeakReference::ElementType"); + return mRef ? mRef->getRefPtr().template downcast() : nullptr; + } + + // Get a pointer to the tracked object, downcasting to the proper type T. + // Note that this operation is unsafe as it may cause races if downwind + // code depends on the value not to change after reading. + T* get() const { + static_assert( + IsBaseOf::value, + "T must derive from ThreadSafeWeakReference::ElementType"); + return mRef ? static_cast(mRef->get()) : nullptr; + } + + // A shared weak reference to an object. Note that this may be null so as to + // save memory (at the slight cost of an extra null check) if no object is + // being tracked. + RefPtr mRef; +}; + +} // namespace mozilla + +template +inline already_AddRefed do_AddRef( + const mozilla::ThreadSafeWeakPtr& aObj) { + RefPtr ref(aObj); + return ref.forget(); +} + +#endif /* mozilla_ThreadSafeWeakPtr_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 @@ -8,6 +8,8 @@ #define mozilla_TimeStamp_h #include +#include // for std::min, std::max +#include #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/FloatingPoint.h" @@ -15,8 +17,9 @@ #include "mozilla/Types.h" namespace IPC { -template struct ParamTraits; -} // namespace IPC +template +struct ParamTraits; +} // namespace IPC #ifdef XP_WIN // defines TimeStampValue as a complex value keeping both @@ -35,9 +38,8 @@ /** * Platform-specific implementation details of BaseTimeDuration. */ -class BaseTimeDurationPlatformUtils -{ -public: +class BaseTimeDurationPlatformUtils { + public: static MFBT_API double ToSeconds(int64_t aTicks); static MFBT_API double ToSecondsSigDigits(int64_t aTicks); static MFBT_API int64_t TicksFromMilliseconds(double aMilliseconds); @@ -58,16 +60,14 @@ * operations are performed on the integer count of ticks (mValue). */ template -class BaseTimeDuration -{ -public: +class BaseTimeDuration { + public: // The default duration is 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; - MOZ_IMPLICIT BaseTimeDuration(_SomethingVeryRandomHere* aZero) : mValue(0) - { + MOZ_IMPLICIT BaseTimeDuration(_SomethingVeryRandomHere* aZero) : mValue(0) { MOZ_ASSERT(!aZero, "Who's playing funny games here?"); } // Default copy-constructor and assignment are OK @@ -75,18 +75,15 @@ // Converting copy-constructor and assignment operator template explicit BaseTimeDuration(const BaseTimeDuration& aOther) - : mValue(aOther.mValue) - { } + : mValue(aOther.mValue) {} template - BaseTimeDuration& operator=(const BaseTimeDuration& aOther) - { + BaseTimeDuration& operator=(const BaseTimeDuration& aOther) { mValue = aOther.mValue; return *this; } - double ToSeconds() const - { + double ToSeconds() const { if (mValue == INT64_MAX) { return PositiveInfinity(); } @@ -98,8 +95,7 @@ // Return a duration value that includes digits of time we think to // be significant. This method should be used when displaying a // time to humans. - double ToSecondsSigDigits() const - { + double ToSecondsSigDigits() const { if (mValue == INT64_MAX) { return PositiveInfinity(); } @@ -116,12 +112,10 @@ // mValue do not allow us to represent durations of that length, // long durations are clamped to the max/min representable value // instead of overflowing. - static inline BaseTimeDuration FromSeconds(double aSeconds) - { + static inline BaseTimeDuration FromSeconds(double aSeconds) { return FromMilliseconds(aSeconds * 1000.0); } - static BaseTimeDuration FromMilliseconds(double aMilliseconds) - { + static BaseTimeDuration FromMilliseconds(double aMilliseconds) { if (aMilliseconds == PositiveInfinity()) { return Forever(); } @@ -129,38 +123,29 @@ return FromTicks(INT64_MIN); } return FromTicks( - BaseTimeDurationPlatformUtils::TicksFromMilliseconds(aMilliseconds)); + BaseTimeDurationPlatformUtils::TicksFromMilliseconds(aMilliseconds)); } - static inline BaseTimeDuration FromMicroseconds(double aMicroseconds) - { + static inline BaseTimeDuration FromMicroseconds(double aMicroseconds) { return FromMilliseconds(aMicroseconds / 1000.0); } - static BaseTimeDuration Forever() - { - return FromTicks(INT64_MAX); - } + static constexpr BaseTimeDuration Forever() { return FromTicks(INT64_MAX); } - BaseTimeDuration operator+(const BaseTimeDuration& aOther) const - { + BaseTimeDuration operator+(const BaseTimeDuration& aOther) const { return FromTicks(ValueCalculator::Add(mValue, aOther.mValue)); } - BaseTimeDuration operator-(const BaseTimeDuration& aOther) const - { + BaseTimeDuration operator-(const BaseTimeDuration& aOther) const { return FromTicks(ValueCalculator::Subtract(mValue, aOther.mValue)); } - BaseTimeDuration& operator+=(const BaseTimeDuration& aOther) - { + BaseTimeDuration& operator+=(const BaseTimeDuration& aOther) { mValue = ValueCalculator::Add(mValue, aOther.mValue); return *this; } - BaseTimeDuration& operator-=(const BaseTimeDuration& aOther) - { + BaseTimeDuration& operator-=(const BaseTimeDuration& aOther) { mValue = ValueCalculator::Subtract(mValue, aOther.mValue); return *this; } - BaseTimeDuration operator-() const - { + BaseTimeDuration operator-() const { // We don't just use FromTicks(ValueCalculator::Subtract(0, mValue)) // since that won't give the correct result for -TimeDuration::Forever(). int64_t ticks; @@ -175,7 +160,16 @@ return FromTicks(ticks); } -private: + static BaseTimeDuration Max(const BaseTimeDuration& aA, + const BaseTimeDuration& aB) { + return FromTicks(std::max(aA.mValue, aB.mValue)); + } + static BaseTimeDuration Min(const BaseTimeDuration& aA, + const BaseTimeDuration& aB) { + return FromTicks(std::min(aA.mValue, aB.mValue)); + } + + private: // Block double multiplier (slower, imprecise if long duration) - Bug 853398. // If required, use MultDouble explicitly and with care. BaseTimeDuration operator*(const double aMultiplier) const = delete; @@ -185,86 +179,68 @@ // the passed argument can then cause divide-by-zero) - Bug 1147491. BaseTimeDuration operator/(const double aDivisor) const = delete; -public: - BaseTimeDuration MultDouble(double aMultiplier) const - { + public: + BaseTimeDuration MultDouble(double aMultiplier) const { return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier)); } - BaseTimeDuration operator*(const int32_t aMultiplier) const - { + BaseTimeDuration operator*(const int32_t aMultiplier) const { return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier)); } - BaseTimeDuration operator*(const uint32_t aMultiplier) const - { + BaseTimeDuration operator*(const uint32_t aMultiplier) const { return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier)); } - BaseTimeDuration operator*(const int64_t aMultiplier) const - { + BaseTimeDuration operator*(const int64_t aMultiplier) const { return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier)); } - BaseTimeDuration operator*(const uint64_t aMultiplier) const - { + BaseTimeDuration operator*(const uint64_t aMultiplier) const { if (aMultiplier > INT64_MAX) { return Forever(); } return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier)); } - BaseTimeDuration operator/(const int64_t aDivisor) const - { + BaseTimeDuration operator/(const int64_t aDivisor) const { MOZ_ASSERT(aDivisor != 0, "Division by zero"); return FromTicks(ValueCalculator::Divide(mValue, aDivisor)); } - double operator/(const BaseTimeDuration& aOther) const - { -#ifndef MOZ_B2G - // Bug 1066388 - This fails on B2G ICS Emulator + double operator/(const BaseTimeDuration& aOther) const { MOZ_ASSERT(aOther.mValue != 0, "Division by zero"); -#endif return ValueCalculator::DivideDouble(mValue, aOther.mValue); } - BaseTimeDuration operator%(const BaseTimeDuration& aOther) const - { + BaseTimeDuration operator%(const BaseTimeDuration& aOther) const { MOZ_ASSERT(aOther.mValue != 0, "Division by zero"); return FromTicks(ValueCalculator::Modulo(mValue, aOther.mValue)); } - template - bool operator<(const BaseTimeDuration& aOther) const - { + template + bool operator<(const BaseTimeDuration& aOther) const { return mValue < aOther.mValue; } - template - bool operator<=(const BaseTimeDuration& aOther) const - { + template + bool operator<=(const BaseTimeDuration& aOther) const { return mValue <= aOther.mValue; } - template - bool operator>=(const BaseTimeDuration& aOther) const - { + template + bool operator>=(const BaseTimeDuration& aOther) const { return mValue >= aOther.mValue; } - template - bool operator>(const BaseTimeDuration& aOther) const - { + template + bool operator>(const BaseTimeDuration& aOther) const { return mValue > aOther.mValue; } - template - bool operator==(const BaseTimeDuration& aOther) const - { + template + bool operator==(const BaseTimeDuration& aOther) const { return mValue == aOther.mValue; } - template - bool operator!=(const BaseTimeDuration& aOther) const - { + template + bool operator!=(const BaseTimeDuration& aOther) const { return mValue != aOther.mValue; } - bool IsZero() const - { - return mValue == 0; - } - explicit operator bool() const - { - return mValue != 0; + bool IsZero() const { return mValue == 0; } + explicit operator bool() const { return mValue != 0; } + + friend std::ostream& operator<<(std::ostream& aStream, + const BaseTimeDuration& aDuration) { + return aStream << aDuration.ToMilliseconds() << " ms"; } // Return a best guess at the system's current timing resolution, @@ -282,21 +258,19 @@ // Comparing durations for equality will only lead to bugs on // platforms with high-resolution timers. -private: + private: friend class TimeStamp; friend struct IPC::ParamTraits>; template friend class BaseTimeDuration; - static BaseTimeDuration FromTicks(int64_t aTicks) - { + static BaseTimeDuration FromTicks(int64_t aTicks) { BaseTimeDuration t; t.mValue = aTicks; return t; } - static BaseTimeDuration FromTicks(double aTicks) - { + static BaseTimeDuration FromTicks(double aTicks) { // NOTE: this MUST be a >= test, because int64_t(double(INT64_MAX)) // overflows and gives INT64_MIN. if (aTicks >= double(INT64_MAX)) { @@ -319,15 +293,13 @@ * Perform arithmetic operations on the value of a BaseTimeDuration without * doing strict checks on the range of values. */ -class TimeDurationValueCalculator -{ -public: +class TimeDurationValueCalculator { + public: static int64_t Add(int64_t aA, int64_t aB) { return aA + aB; } static int64_t Subtract(int64_t aA, int64_t aB) { return aA - aB; } template - static int64_t Multiply(int64_t aA, T aB) - { + static int64_t Multiply(int64_t aA, T aB) { static_assert(IsIntegral::value, "Using integer multiplication routine with non-integer type." " Further specialization required"); @@ -335,17 +307,15 @@ } static int64_t Divide(int64_t aA, int64_t aB) { return aA / aB; } - static double DivideDouble(int64_t aA, int64_t aB) - { + static double DivideDouble(int64_t aA, int64_t aB) { return static_cast(aA) / aB; } static int64_t Modulo(int64_t aA, int64_t aB) { return aA % aB; } }; template <> -inline int64_t -TimeDurationValueCalculator::Multiply(int64_t aA, double aB) -{ +inline int64_t TimeDurationValueCalculator::Multiply(int64_t aA, + double aB) { return static_cast(aA * aB); } @@ -387,29 +357,32 @@ * explicitly nullable and provides an IsNull() method. time_point * is initialized to the clock's epoch and provides a * time_since_epoch() method that functions similiarly. i.e. - * t.IsNull() is equivalent to t.time_since_epoch() == decltype(t)::duration::zero(); + * t.IsNull() is equivalent to t.time_since_epoch() == + * decltype(t)::duration::zero(); */ -class TimeStamp -{ -public: +class TimeStamp { + public: /** * Initialize to the "null" moment */ constexpr TimeStamp() : mValue(0) {} - // Default copy-constructor and assignment are OK + // Default copy-constructor and assignment are OK - /** - * The system timestamps are the same as the TimeStamp - * retrieved by mozilla::TimeStamp. Since we need this for - * vsync timestamps, we enable the creation of mozilla::TimeStamps - * on platforms that support vsync aligned refresh drivers / compositors - * Verified true as of Jan 31, 2015: B2G and OS X - * False on Windows 7 - * UNTESTED ON OTHER PLATFORMS - */ -#if defined(MOZ_WIDGET_GONK) || defined(XP_DARWIN) - static TimeStamp FromSystemTime(int64_t aSystemTime) - { + /** + * The system timestamps are the same as the TimeStamp + * retrieved by mozilla::TimeStamp. Since we need this for + * vsync timestamps, we enable the creation of mozilla::TimeStamps + * on platforms that support vsync aligned refresh drivers / compositors + * Verified true as of Jan 31, 2015: B2G and OS X + * False on Windows 7 + * Android's event time uses CLOCK_MONOTONIC via SystemClock.uptimeMilles. + * So it is same value of TimeStamp posix implementation. + * Wayland/GTK event time also uses CLOCK_MONOTONIC on Weston/Mutter + * compositors. + * UNTESTED ON OTHER PLATFORMS + */ +#if defined(XP_DARWIN) || defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK) + static TimeStamp FromSystemTime(int64_t aSystemTime) { static_assert(sizeof(aSystemTime) == sizeof(TimeStampValue), "System timestamp should be same units as TimeStampValue"); return TimeStamp(aSystemTime); @@ -425,10 +398,7 @@ * Return true if this is not the "null" moment, may be used in tests, e.g.: * |if (timestamp) { ... }| */ - explicit operator bool() const - { - return mValue != 0; - } + explicit operator bool() const { return mValue != 0; } /** * Return a timestamp reflecting the current elapsed system time. This @@ -453,12 +423,12 @@ * the @a aIsInconsistent parameter will be set to true, the returned * timestamp however will still be valid though inaccurate. * - * @param aIsInconsistent Set to true if an inconsistency was detected in the - * process creation time + * @param aIsInconsistent If non-null, set to true if an inconsistency was + * detected in the process creation time * @returns A timestamp representing the time when the process was created, * this timestamp is always valid even when errors are reported */ - static MFBT_API TimeStamp ProcessCreation(bool& aIsInconsistent); + static MFBT_API TimeStamp ProcessCreation(bool* aIsInconsistent = nullptr); /** * Records a process restart. After this call ProcessCreation() will return @@ -470,8 +440,7 @@ /** * Compute the difference between two timestamps. Both must be non-null. */ - TimeDuration operator-(const TimeStamp& aOther) const - { + TimeDuration operator-(const TimeStamp& aOther) const { MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); static_assert(-INT64_MAX > INT64_MIN, "int64_t sanity check"); @@ -489,20 +458,17 @@ return TimeDuration::FromTicks(ticks); } - TimeStamp operator+(const TimeDuration& aOther) const - { + TimeStamp operator+(const TimeDuration& aOther) const { TimeStamp result = *this; result += aOther; return result; } - TimeStamp operator-(const TimeDuration& aOther) const - { + TimeStamp operator-(const TimeDuration& aOther) const { TimeStamp result = *this; result -= aOther; return result; } - TimeStamp& operator+=(const TimeDuration& aOther) - { + TimeStamp& operator+=(const TimeDuration& aOther) { MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); TimeStampValue value = mValue + aOther.mValue; // Check for underflow. @@ -514,8 +480,7 @@ mValue = value; return *this; } - TimeStamp& operator-=(const TimeDuration& aOther) - { + TimeStamp& operator-=(const TimeDuration& aOther) { MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); TimeStampValue value = mValue - aOther.mValue; // Check for underflow. @@ -528,40 +493,31 @@ return *this; } - bool operator<(const TimeStamp& aOther) const - { + bool operator<(const TimeStamp& aOther) const { MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); return mValue < aOther.mValue; } - bool operator<=(const TimeStamp& aOther) const - { + bool operator<=(const TimeStamp& aOther) const { MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); return mValue <= aOther.mValue; } - bool operator>=(const TimeStamp& aOther) const - { + bool operator>=(const TimeStamp& aOther) const { MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); return mValue >= aOther.mValue; } - bool operator>(const TimeStamp& aOther) const - { + bool operator>(const TimeStamp& aOther) const { MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); return mValue > aOther.mValue; } - bool operator==(const TimeStamp& aOther) const - { - return IsNull() - ? aOther.IsNull() - : !aOther.IsNull() && mValue == aOther.mValue; - } - bool operator!=(const TimeStamp& aOther) const - { - return !(*this == aOther); + bool operator==(const TimeStamp& aOther) const { + return IsNull() ? aOther.IsNull() + : !aOther.IsNull() && mValue == aOther.mValue; } + bool operator!=(const TimeStamp& aOther) const { return !(*this == aOther); } // Comparing TimeStamps for equality should be discouraged. Adding // two TimeStamps, or scaling TimeStamps, is nonsense and must never @@ -570,7 +526,7 @@ static MFBT_API void Startup(); static MFBT_API void Shutdown(); -private: + private: friend struct IPC::ParamTraits; friend void StartupTimelineRecordExternal(int, uint64_t); @@ -604,6 +560,6 @@ TimeStampValue mValue; }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_TimeStamp_h */ 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 @@ -13,8 +13,7 @@ class TimeStamp; -class TimeStampValue -{ +class TimeStampValue { friend struct IPC::ParamTraits; friend class TimeStamp; friend void StartupTimelineRecordExternal(int, uint64_t); @@ -30,54 +29,41 @@ MFBT_API uint64_t CheckQPC(const TimeStampValue& aOther) const; struct _SomethingVeryRandomHere; - constexpr TimeStampValue(_SomethingVeryRandomHere* aNullValue) - : mGTC(0) - , mQPC(0) - , mHasQPC(false) - , mIsNull(true) - { - } + constexpr MOZ_IMPLICIT TimeStampValue(_SomethingVeryRandomHere* aNullValue) + : mGTC(0), mQPC(0), mHasQPC(false), mIsNull(true) {} -public: + public: MFBT_API uint64_t operator-(const TimeStampValue& aOther) const; - TimeStampValue operator+(const int64_t aOther) const - { + TimeStampValue operator+(const int64_t aOther) const { return TimeStampValue(mGTC + aOther, mQPC + aOther, mHasQPC); } - TimeStampValue operator-(const int64_t aOther) const - { + TimeStampValue operator-(const int64_t aOther) const { return TimeStampValue(mGTC - aOther, mQPC - aOther, mHasQPC); } MFBT_API TimeStampValue& operator+=(const int64_t aOther); MFBT_API TimeStampValue& operator-=(const int64_t aOther); - bool operator<(const TimeStampValue& aOther) const - { + bool operator<(const TimeStampValue& aOther) const { return int64_t(*this - aOther) < 0; } - bool operator>(const TimeStampValue& aOther) const - { + bool operator>(const TimeStampValue& aOther) const { return int64_t(*this - aOther) > 0; } - bool operator<=(const TimeStampValue& aOther) const - { + bool operator<=(const TimeStampValue& aOther) const { return int64_t(*this - aOther) <= 0; } - bool operator>=(const TimeStampValue& aOther) const - { + bool operator>=(const TimeStampValue& aOther) const { return int64_t(*this - aOther) >= 0; } - bool operator==(const TimeStampValue& aOther) const - { + bool operator==(const TimeStampValue& aOther) const { return int64_t(*this - aOther) == 0; } - bool operator!=(const TimeStampValue& aOther) const - { + bool operator!=(const TimeStampValue& aOther) const { return int64_t(*this - aOther) != 0; } }; -} +} // namespace mozilla #endif /* mozilla_TimeStamp_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ToString.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ToString.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/ToString.h @@ -18,15 +18,13 @@ * A convenience function for converting an object to a string representation. * Supports any object which can be streamed to an std::ostream. */ -template -std::string -ToString(const T& aValue) -{ +template +std::string ToString(const T& aValue) { std::ostringstream stream; stream << aValue; return stream.str(); } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_ToString_h */ 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 @@ -25,7 +25,7 @@ * A helper class that allows passing around multiple variadic argument lists * by grouping them. */ -template +template struct Group; /* @@ -44,24 +44,27 @@ * immediate context of the caller). */ -template +template struct CheckConvertibilityImpl; -template -struct CheckConvertibilityImpl - : FalseType {}; - -template -struct CheckConvertibilityImpl, Group, true> - : IntegralConstant::value...>::value> { }; +template +struct CheckConvertibilityImpl : FalseType {}; -template +template +struct CheckConvertibilityImpl, Group, + true> + : IntegralConstant< + bool, + tl::And::value...>::value> {}; + +template struct CheckConvertibility; -template +template struct CheckConvertibility, Group> - : CheckConvertibilityImpl, Group, - sizeof...(SourceTypes) == sizeof...(TargetTypes)> { }; + : CheckConvertibilityImpl, Group, + sizeof...(SourceTypes) == + sizeof...(TargetTypes)> {}; /* * TupleImpl is a helper class used to implement mozilla::Tuple. @@ -87,19 +90,16 @@ * This implementation strategy is borrowed from libstdc++'s std::tuple * implementation. */ -template +template struct TupleImpl; /* * The base case of the inheritance recursion (and also the implementation * of an empty tuple). */ -template +template struct TupleImpl { - bool operator==(const TupleImpl& aOther) const - { - return true; - } + bool operator==(const TupleImpl& aOther) const { return true; } }; /* @@ -107,10 +107,9 @@ * index 'Index' of a tuple, of type 'HeadT', and inherits from the nodes * that store the remaining elements, of types 'TailT...'. */ -template +template struct TupleImpl - : public TupleImpl -{ + : public TupleImpl { typedef TupleImpl Base; // Accessors for the head and the tail. @@ -123,11 +122,11 @@ static Base& Tail(TupleImpl& aTuple) { return aTuple; } static const Base& Tail(const TupleImpl& aTuple) { return aTuple; } - TupleImpl() : Base(), mHead() { } + TupleImpl() : Base(), mHead() {} // Construct from const references to the elements. explicit TupleImpl(const HeadT& aHead, const TailT&... aTail) - : Base(aTail...), mHead(aHead) { } + : Base(aTail...), mHead(aHead) {} // Construct from objects that are convertible to the elements. // This constructor is enabled only when the argument types are actually @@ -135,39 +134,35 @@ // match for certain invocations than the copy constructor. template , - Group>::value>::Type> + CheckConvertibility, + Group>::value>::Type> explicit TupleImpl(OtherHeadT&& aHead, OtherTailT&&... aTail) - : Base(Forward(aTail)...), mHead(Forward(aHead)) { } + : Base(Forward(aTail)...), + mHead(Forward(aHead)) {} // Copy and move constructors. // We'd like to use '= default' to implement these, but MSVC 2013's support // for '= default' is incomplete and this doesn't work. TupleImpl(const TupleImpl& aOther) - : Base(Tail(aOther)) - , mHead(Head(aOther)) {} + : Base(Tail(aOther)), mHead(Head(aOther)) {} TupleImpl(TupleImpl&& aOther) - : Base(Move(Tail(aOther))) - , mHead(Forward(Head(aOther))) {} + : Base(Move(Tail(aOther))), mHead(Forward(Head(aOther))) {} // Assign from a tuple whose elements are convertible to the elements // of this tuple. template ::Type> - TupleImpl& operator=(const TupleImpl& aOther) - { + typename = typename EnableIf::Type> + TupleImpl& operator=(const TupleImpl& aOther) { typedef TupleImpl OtherT; Head(*this) = OtherT::Head(aOther); Tail(*this) = OtherT::Tail(aOther); return *this; } template ::Type> - TupleImpl& operator=(TupleImpl&& aOther) - { + typename = typename EnableIf::Type> + TupleImpl& operator=(TupleImpl&& aOther) { typedef TupleImpl OtherT; Head(*this) = Move(OtherT::Head(aOther)); Tail(*this) = Move(OtherT::Tail(aOther)); @@ -175,27 +170,25 @@ } // Copy and move assignment operators. - TupleImpl& operator=(const TupleImpl& aOther) - { + TupleImpl& operator=(const TupleImpl& aOther) { Head(*this) = Head(aOther); Tail(*this) = Tail(aOther); return *this; } - TupleImpl& operator=(TupleImpl&& aOther) - { + TupleImpl& operator=(TupleImpl&& aOther) { Head(*this) = Move(Head(aOther)); Tail(*this) = Move(Tail(aOther)); return *this; } - bool operator==(const TupleImpl& aOther) const - { + bool operator==(const TupleImpl& aOther) const { return Head(*this) == Head(aOther) && Tail(*this) == Tail(aOther); } -private: + + private: HeadT mHead; // The element stored at this index in the tuple. }; -} // namespace detail +} // namespace detail /** * Tuple is a class that stores zero or more objects, whose types are specified @@ -205,141 +198,125 @@ * Tuple allows index-based access to its elements (with the index having to be * known at compile time) via the non-member function 'Get(tuple)'. */ -template -class Tuple : public detail::TupleImpl<0, Elements...> -{ +template +class Tuple : public detail::TupleImpl<0, Elements...> { typedef detail::TupleImpl<0, Elements...> Impl; -public: + + public: // The constructors and assignment operators here are simple wrappers // around those in TupleImpl. - Tuple() : Impl() { } - explicit Tuple(const Elements&... aElements) : Impl(aElements...) { } + Tuple() : Impl() {} + explicit Tuple(const Elements&... aElements) : Impl(aElements...) {} // Here, we can't just use 'typename... OtherElements' because MSVC will give // a warning "C4520: multiple default constructors specified" (even if no one // actually instantiates the constructor with an empty parameter pack - // that's probably a bug) and we compile with warnings-as-errors. template , - detail::Group>::value>::Type> + typename = typename EnableIf, + detail::Group>::value>::Type> explicit Tuple(OtherHead&& aHead, OtherTail&&... aTail) - : Impl(Forward(aHead), Forward(aTail)...) { } - Tuple(const Tuple& aOther) : Impl(aOther) { } - Tuple(Tuple&& aOther) : Impl(Move(aOther)) { } + : Impl(Forward(aHead), Forward(aTail)...) {} + Tuple(const Tuple& aOther) : Impl(aOther) {} + Tuple(Tuple&& aOther) : Impl(Move(aOther)) {} template ::Type> - Tuple& operator=(const Tuple& aOther) - { + typename = typename EnableIf::Type> + Tuple& operator=(const Tuple& aOther) { static_cast(*this) = aOther; return *this; } template ::Type> - Tuple& operator=(Tuple&& aOther) - { + typename = typename EnableIf::Type> + Tuple& operator=(Tuple&& aOther) { static_cast(*this) = Move(aOther); return *this; } - Tuple& operator=(const Tuple& aOther) - { + Tuple& operator=(const Tuple& aOther) { static_cast(*this) = aOther; return *this; } - Tuple& operator=(Tuple&& aOther) - { + Tuple& operator=(Tuple&& aOther) { static_cast(*this) = Move(aOther); return *this; } - bool operator==(const Tuple& aOther) const - { + bool operator==(const Tuple& aOther) const { return static_cast(*this) == static_cast(aOther); } }; /** * Specialization of Tuple for two elements. - * This is created to support construction and assignment from a Pair or std::pair. + * This is created to support construction and assignment from a Pair or + * std::pair. */ template -class Tuple : public detail::TupleImpl<0, A, B> -{ +class Tuple : public detail::TupleImpl<0, A, B> { typedef detail::TupleImpl<0, A, B> Impl; -public: + public: // The constructors and assignment operators here are simple wrappers // around those in TupleImpl. - Tuple() : Impl() { } - explicit Tuple(const A& aA, const B& aB) : Impl(aA, aB) { } + Tuple() : Impl() {} + explicit Tuple(const A& aA, const B& aB) : Impl(aA, aB) {} template , - detail::Group>::value>::Type> + typename = typename EnableIf, detail::Group>::value>::Type> explicit Tuple(AArg&& aA, BArg&& aB) - : Impl(Forward(aA), Forward(aB)) { } - Tuple(const Tuple& aOther) : Impl(aOther) { } - Tuple(Tuple&& aOther) : Impl(Move(aOther)) { } + : Impl(Forward(aA), Forward(aB)) {} + Tuple(const Tuple& aOther) : Impl(aOther) {} + Tuple(Tuple&& aOther) : Impl(Move(aOther)) {} explicit Tuple(const Pair& aOther) - : Impl(aOther.first(), aOther.second()) { } - explicit Tuple(Pair&& aOther) : Impl(Forward(aOther.first()), - Forward(aOther.second())) { } + : Impl(aOther.first(), aOther.second()) {} + explicit Tuple(Pair&& aOther) + : Impl(Forward(aOther.first()), Forward(aOther.second())) {} explicit Tuple(const std::pair& aOther) - : Impl(aOther.first, aOther.second) { } - explicit Tuple(std::pair&& aOther) : Impl(Forward(aOther.first), - Forward(aOther.second)) { } + : Impl(aOther.first, aOther.second) {} + explicit Tuple(std::pair&& aOther) + : Impl(Forward(aOther.first), Forward(aOther.second)) {} template - Tuple& operator=(const Tuple& aOther) - { + Tuple& operator=(const Tuple& aOther) { static_cast(*this) = aOther; return *this; } template - Tuple& operator=(Tuple&& aOther) - { + Tuple& operator=(Tuple&& aOther) { static_cast(*this) = Move(aOther); return *this; } - Tuple& operator=(const Tuple& aOther) - { + Tuple& operator=(const Tuple& aOther) { static_cast(*this) = aOther; return *this; } - Tuple& operator=(Tuple&& aOther) - { + Tuple& operator=(Tuple&& aOther) { static_cast(*this) = Move(aOther); return *this; } template - Tuple& operator=(const Pair& aOther) - { + Tuple& operator=(const Pair& aOther) { Impl::Head(*this) = aOther.first(); Impl::Tail(*this).Head(*this) = aOther.second(); return *this; } template - Tuple& operator=(Pair&& aOther) - { + Tuple& operator=(Pair&& aOther) { Impl::Head(*this) = Forward(aOther.first()); Impl::Tail(*this).Head(*this) = Forward(aOther.second()); return *this; } template - Tuple& operator=(const std::pair& aOther) - { + Tuple& operator=(const std::pair& aOther) { Impl::Head(*this) = aOther.first; Impl::Tail(*this).Head(*this) = aOther.second; return *this; } template - Tuple& operator=(std::pair&& aOther) - { + Tuple& operator=(std::pair&& aOther) { Impl::Head(*this) = Forward(aOther.first); Impl::Tail(*this).Head(*this) = Forward(aOther.second); return *this; @@ -366,22 +343,20 @@ */ // Const reference version. -template +template auto TupleGetHelper(TupleImpl& aTuple) - -> decltype(TupleImpl::Head(aTuple)) -{ + -> decltype(TupleImpl::Head(aTuple)) { return TupleImpl::Head(aTuple); } // Non-const reference version. -template +template auto TupleGetHelper(const TupleImpl& aTuple) - -> decltype(TupleImpl::Head(aTuple)) -{ + -> decltype(TupleImpl::Head(aTuple)) { return TupleImpl::Head(aTuple); } -} // namespace detail +} // namespace detail /** * Index-based access to an element of a tuple. @@ -395,26 +370,23 @@ */ // Non-const reference version. -template +template auto Get(Tuple& aTuple) - -> decltype(detail::TupleGetHelper(aTuple)) -{ + -> decltype(detail::TupleGetHelper(aTuple)) { return detail::TupleGetHelper(aTuple); } // Const reference version. -template +template auto Get(const Tuple& aTuple) - -> decltype(detail::TupleGetHelper(aTuple)) -{ + -> decltype(detail::TupleGetHelper(aTuple)) { return detail::TupleGetHelper(aTuple); } // Rvalue reference version. -template +template auto Get(Tuple&& aTuple) - -> decltype(Move(mozilla::Get(aTuple))) -{ + -> decltype(Move(mozilla::Get(aTuple))) { // We need a 'mozilla::' qualification here to avoid // name lookup only finding the current function. return Move(mozilla::Get(aTuple)); @@ -429,11 +401,11 @@ * * auto tuple = MakeTuple(42, 0.5f, 'c'); // has type Tuple */ -template -inline Tuple::Type...> -MakeTuple(Elements&&... aElements) -{ - return Tuple::Type...>(Forward(aElements)...); +template +inline Tuple::Type...> MakeTuple( + Elements&&... aElements) { + return Tuple::Type...>( + Forward(aElements)...); } /** @@ -449,13 +421,11 @@ * char c; * Tie(i, f, c) = FunctionThatReturnsATuple(); */ -template -inline Tuple -Tie(Elements&... aVariables) -{ +template +inline Tuple Tie(Elements&... aVariables) { return Tuple(aVariables...); } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_Tuple_h */ 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 @@ -23,8 +23,10 @@ /* Forward declarations. */ -template struct RemoveCV; -template struct AddRvalueReference; +template +struct RemoveCV; +template +struct AddRvalueReference; /* 20.2.4 Function template declval [declval] */ @@ -34,7 +36,7 @@ * decltype expressions even if T does not have a default constructor, e.g.: * decltype(DeclVal().foo()) */ -template +template typename AddRvalueReference::Type DeclVal(); /* 20.9.3 Helper classes [meta.help] */ @@ -43,10 +45,9 @@ * Helper class used as a base for various type traits, exposed publicly * because exposes it as well. */ -template -struct IntegralConstant -{ - static const T value = Value; +template +struct IntegralConstant { + static constexpr T value = Value; typedef T ValueType; typedef IntegralConstant Type; }; @@ -61,13 +62,13 @@ namespace detail { -template +template struct IsVoidHelper : FalseType {}; -template<> +template <> struct IsVoidHelper : TrueType {}; -} // namespace detail +} // namespace detail /** * IsVoid determines whether a type is void. @@ -77,7 +78,7 @@ * mozilla::IsVoid::value is false; * mozilla::IsVoid::value is true. */ -template +template struct IsVoid : detail::IsVoidHelper::Type> {}; namespace detail { @@ -85,20 +86,34 @@ template struct IsIntegralHelper : FalseType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; } /* namespace detail */ @@ -111,24 +126,21 @@ * mozilla::IsIntegral::value is false; * mozilla::IsIntegral::value is false; */ -template -struct IsIntegral : detail::IsIntegralHelper::Type> -{}; +template +struct IsIntegral : detail::IsIntegralHelper::Type> {}; -template +template struct IsSame; namespace detail { -template +template struct IsFloatingPointHelper - : IntegralConstant::value || - IsSame::value || - IsSame::value> -{}; + : IntegralConstant::value || + IsSame::value || + IsSame::value> {}; -} // namespace detail +} // namespace detail /** * IsFloatingPoint determines whether a type is a floating point type (float, @@ -139,23 +151,22 @@ * mozilla::IsFloatingPoint::value is true; * mozilla::IsFloatingPoint::value is false. */ -template +template struct IsFloatingPoint - : detail::IsFloatingPointHelper::Type> -{}; + : detail::IsFloatingPointHelper::Type> {}; namespace detail { -template +template struct IsArrayHelper : FalseType {}; -template +template struct IsArrayHelper : TrueType {}; -template +template struct IsArrayHelper : TrueType {}; -} // namespace detail +} // namespace detail /** * IsArray determines whether a type is an array type, of known or unknown @@ -165,26 +176,21 @@ * mozilla::IsArray::value is true; * mozilla::IsArray::value is true. */ -template -struct IsArray : detail::IsArrayHelper::Type> -{}; +template +struct IsArray : detail::IsArrayHelper::Type> {}; namespace detail { -template +template struct IsFunPtr; -template -struct IsFunPtr - : public FalseType -{}; - -template -struct IsFunPtr - : public TrueType -{}; +template +struct IsFunPtr : public FalseType {}; + +template +struct IsFunPtr : public TrueType {}; -}; // namespace detail +}; // namespace detail /** * IsFunction determines whether a type is a function type. Function pointers @@ -198,20 +204,18 @@ * mozilla::IsFunction is false; * mozilla::IsFunction is true. */ -template -struct IsFunction - : public detail::IsFunPtr::Type *> -{}; +template +struct IsFunction : public detail::IsFunPtr::Type*> {}; namespace detail { -template +template struct IsPointerHelper : FalseType {}; -template +template struct IsPointerHelper : TrueType {}; -} // namespace detail +} // namespace detail /** * IsPointer determines whether a type is a possibly-CV-qualified pointer type @@ -228,9 +232,8 @@ * mozilla::IsPointer::value is false. * mozilla::IsPointer::value is false */ -template -struct IsPointer : detail::IsPointerHelper::Type> -{}; +template +struct IsPointer : detail::IsPointerHelper::Type> {}; /** * IsLvalueReference determines whether a type is an lvalue reference. @@ -243,10 +246,10 @@ * mozilla::IsLvalueReference::value is true; * mozilla::IsLvalueReference::value is false. */ -template +template struct IsLvalueReference : FalseType {}; -template +template struct IsLvalueReference : TrueType {}; /** @@ -260,21 +263,19 @@ * mozilla::IsRvalueReference::value is false; * mozilla::IsRvalueReference::value is true. */ -template +template struct IsRvalueReference : FalseType {}; -template +template struct IsRvalueReference : TrueType {}; namespace detail { // __is_enum is a supported extension across all of our supported compilers. -template -struct IsEnumHelper - : IntegralConstant -{}; +template +struct IsEnumHelper : IntegralConstant {}; -} // namespace detail +} // namespace detail /** * IsEnum determines whether a type is an enum type. @@ -283,10 +284,8 @@ * mozilla::IsEnum::value is false; * mozilla::IsEnum::value is false; */ -template -struct IsEnum - : detail::IsEnumHelper::Type> -{}; +template +struct IsEnum : detail::IsEnumHelper::Type> {}; namespace detail { @@ -294,12 +293,10 @@ // http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html // http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits // http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx -template -struct IsClassHelper - : IntegralConstant -{}; +template +struct IsClassHelper : IntegralConstant {}; -} // namespace detail +} // namespace detail /** * IsClass determines whether a type is a class type (but not a union). @@ -310,10 +307,8 @@ * mozilla::IsClass::value is true; * mozilla::IsClass::value is false; */ -template -struct IsClass - : detail::IsClassHelper::Type> -{}; +template +struct IsClass : detail::IsClassHelper::Type> {}; /* 20.9.4.2 Composite type traits [meta.unary.comp] */ @@ -331,11 +326,9 @@ * mozilla::IsReference::value is true; * mozilla::IsReference::value is true. */ -template -struct IsReference - : IntegralConstant::value || IsRvalueReference::value> -{}; +template +struct IsReference : IntegralConstant::value || + IsRvalueReference::value> {}; /** * IsArithmetic determines whether a type is arithmetic. A type is arithmetic @@ -345,20 +338,19 @@ * mozilla::IsArithmetic::value is true; * mozilla::IsArithmetic::value is false. */ -template -struct IsArithmetic - : IntegralConstant::value || IsFloatingPoint::value> -{}; +template +struct IsArithmetic : IntegralConstant::value || + IsFloatingPoint::value> {}; namespace detail { -template +template struct IsMemberPointerHelper : FalseType {}; -template +template struct IsMemberPointerHelper : TrueType {}; -} // namespace detail +} // namespace detail /** * IsMemberPointer determines whether a type is pointer to non-static member @@ -367,10 +359,9 @@ * mozilla::IsMemberPointer::value is true * mozilla::IsMemberPointer::value is false */ -template +template struct IsMemberPointer - : detail::IsMemberPointerHelper::Type> -{}; + : detail::IsMemberPointerHelper::Type> {}; /** * IsScalar determines whether a type is a scalar type. @@ -379,11 +370,11 @@ * mozilla::IsScalar::value is true * mozilla::IsScalar::value is false */ -template +template struct IsScalar - : IntegralConstant::value || IsEnum::value || - IsPointer::value || IsMemberPointer::value> -{}; + : IntegralConstant::value || IsEnum::value || + IsPointer::value || + IsMemberPointer::value> {}; /* 20.9.4.3 Type properties [meta.unary.prop] */ @@ -394,10 +385,10 @@ * mozilla::IsConst::value is true; * mozilla::IsConst::value is false. */ -template +template struct IsConst : FalseType {}; -template +template struct IsConst : TrueType {}; /** @@ -407,10 +398,10 @@ * mozilla::IsVolatile::value is true; * mozilla::IsVolatile::value is false. */ -template +template struct IsVolatile : FalseType {}; -template +template struct IsVolatile : TrueType {}; /** @@ -421,26 +412,43 @@ * false>, or conveniently from mozilla::IsPod for composite types) as needed to * ensure correct IsPod behavior. */ -template +template struct IsPod : public FalseType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template +struct IsPod : TrueType {}; namespace detail { @@ -448,12 +456,11 @@ // http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html // http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits // http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx -template +template struct IsEmptyHelper - : IntegralConstant::value && __is_empty(T)> -{}; + : IntegralConstant::value&& __is_empty(T)> {}; -} // namespace detail +} // namespace detail /** * IsEmpty determines whether a type is a class (but not a union) that is empty. @@ -495,34 +502,30 @@ * !mozilla::IsEmpty::value, * "all empty"); */ -template -struct IsEmpty : detail::IsEmptyHelper::Type> -{}; - +template +struct IsEmpty : detail::IsEmptyHelper::Type> {}; namespace detail { -template::value, - bool = IsIntegral::value, - typename NoCV = typename RemoveCV::Type> +template ::value, + bool = IsIntegral::value, + typename NoCV = typename RemoveCV::Type> struct IsSignedHelper; // Floating point is signed. -template +template struct IsSignedHelper : TrueType {}; // Integral is conditionally signed. -template +template struct IsSignedHelper - : IntegralConstant -{}; + : IntegralConstant {}; // Non-floating point, non-integral is not signed. -template +template struct IsSignedHelper : FalseType {}; -} // namespace detail +} // namespace detail /** * IsSigned determines whether a type is a signed arithmetic type. |char| is @@ -533,33 +536,31 @@ * mozilla::IsSigned::value is false; * mozilla::IsSigned::value is true. */ -template +template struct IsSigned : detail::IsSignedHelper {}; namespace detail { -template::value, - bool = IsIntegral::value, - typename NoCV = typename RemoveCV::Type> +template ::value, + bool = IsIntegral::value, + typename NoCV = typename RemoveCV::Type> struct IsUnsignedHelper; // Floating point is not unsigned. -template +template struct IsUnsignedHelper : FalseType {}; // Integral is conditionally unsigned. -template +template struct IsUnsignedHelper - : IntegralConstant::value || bool(NoCV(1) < NoCV(-1)))> -{}; + : IntegralConstant::value || + bool(NoCV(1) < NoCV(-1)))> {}; // Non-floating point, non-integral is not unsigned. -template +template struct IsUnsignedHelper : FalseType {}; -} // namespace detail +} // namespace detail /** * IsUnsigned determines whether a type is an unsigned arithmetic type. @@ -569,28 +570,75 @@ * mozilla::IsUnsigned::value is true; * mozilla::IsUnsigned::value is false. */ -template +template struct IsUnsigned : detail::IsUnsignedHelper {}; namespace detail { -struct DoIsDestructibleImpl -{ - template().~T())> +struct DoIsDefaultConstructibleImpl { + template static TrueType test(int); - template + template static FalseType test(...); }; -template -struct IsDestructibleImpl : public DoIsDestructibleImpl -{ +template +struct IsDefaultConstructibleImpl : public DoIsDefaultConstructibleImpl { typedef decltype(test(0)) Type; }; -} // namespace detail +} // namespace detail -template +/** + * IsDefaultConstructible determines whether a type has a public default + * constructor. + * + * struct S0 {}; // Implicit default constructor. + * struct S1 { S1(); }; + * struct S2 { explicit S2(int); }; // No implicit default constructor when + * // another one is present. + * struct S3 { S3() = delete; }; + * class C4 { C4(); }; // Default constructor is private. + * + * mozilla::IsDefaultConstructible::value is true; + * mozilla::IsDefaultConstructible::value is true; + * mozilla::IsDefaultConstructible::value is true; + * mozilla::IsDefaultConstructible::value is false; + * mozilla::IsDefaultConstructible::value is false; + * mozilla::IsDefaultConstructible::value is false. + */ +template +struct IsDefaultConstructible + : public detail::IsDefaultConstructibleImpl::Type {}; + +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 + +/** + * IsDestructible determines whether a type has a public destructor. + * + * struct S0 {}; // Implicit default destructor. + * struct S1 { ~S1(); }; + * class C2 { ~C2(); }; // private destructor. + * + * mozilla::IsDestructible::value is true; + * mozilla::IsDestructible::value is true; + * mozilla::IsDestructible::value is false. + */ +template struct IsDestructible : public detail::IsDestructibleImpl::Type {}; /* 20.9.5 Type property queries [meta.unary.prop.query] */ @@ -607,17 +655,17 @@ * mozilla::IsSame::value is false; * mozilla::IsSame::value is true. */ -template +template struct IsSame : FalseType {}; -template +template struct IsSame : TrueType {}; namespace detail { #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) -template +template struct BaseOfTester : IntegralConstant {}; #else @@ -627,47 +675,44 @@ // sample code here: // // http://stackoverflow.com/questions/2910979/how-is-base-of-works -template -struct BaseOfHelper -{ -public: +template +struct BaseOfHelper { + public: operator Base*() const; operator Derived*(); }; -template -struct BaseOfTester -{ -private: - template +template +struct BaseOfTester { + private: + template static char test(Derived*, T); static int test(Base*, int); -public: + public: static const bool value = - sizeof(test(BaseOfHelper(), int())) == sizeof(char); + sizeof(test(BaseOfHelper(), int())) == sizeof(char); }; -template -struct BaseOfTester -{ -private: - template +template +struct BaseOfTester { + private: + template static char test(Derived*, T); static int test(Base*, int); -public: + public: static const bool value = - sizeof(test(BaseOfHelper(), int())) == sizeof(char); + sizeof(test(BaseOfHelper(), int())) == sizeof(char); }; -template +template struct BaseOfTester : FalseType {}; -template +template struct BaseOfTester : TrueType {}; -template +template struct BaseOfTester : TrueType {}; #endif @@ -686,32 +731,29 @@ * mozilla::IsBaseOf::value is true; * mozilla::IsBaseOf::value is false; */ -template +template struct IsBaseOf - : IntegralConstant::value> -{}; + : IntegralConstant::value> {}; namespace detail { -template -struct ConvertibleTester -{ -private: - template +template +struct ConvertibleTester { + private: + template static char test_helper(To1); - template + template static decltype(test_helper(DeclVal())) test(int); - template + template static int test(...); -public: - static const bool value = - sizeof(test(0)) == sizeof(char); + public: + static const bool value = sizeof(test(0)) == sizeof(char); }; -} // namespace detail +} // namespace detail /** * IsConvertible determines whether a value of type From will implicitly convert @@ -738,25 +780,18 @@ * handle. The void handling here doesn't handle const/volatile void correctly, * which could be easily fixed if the need arises. */ -template +template struct IsConvertible - : IntegralConstant::value> -{}; + : IntegralConstant::value> {}; + +template +struct IsConvertible : IntegralConstant::value> {}; -template -struct IsConvertible - : IntegralConstant::value> -{}; - -template -struct IsConvertible - : IntegralConstant::value> -{}; - -template<> -struct IsConvertible - : TrueType -{}; +template +struct IsConvertible : IntegralConstant::value> {}; + +template <> +struct IsConvertible : TrueType {}; /* 20.9.7 Transformations between types [meta.trans] */ @@ -770,15 +805,13 @@ * mozilla::RemoveConst::Type is const int*; * mozilla::RemoveConst::Type is int*. */ -template -struct RemoveConst -{ +template +struct RemoveConst { typedef T Type; }; -template -struct RemoveConst -{ +template +struct RemoveConst { typedef T Type; }; @@ -790,15 +823,13 @@ * mozilla::RemoveVolatile::Type is volatile int*; * mozilla::RemoveVolatile::Type is int*. */ -template -struct RemoveVolatile -{ +template +struct RemoveVolatile { typedef T Type; }; -template -struct RemoveVolatile -{ +template +struct RemoveVolatile { typedef T Type; }; @@ -810,9 +841,8 @@ * mozilla::RemoveCV::Type is int; * mozilla::RemoveCV::Type is int*. */ -template -struct RemoveCV -{ +template +struct RemoveCV { typedef typename RemoveConst::Type>::Type Type; }; @@ -826,47 +856,42 @@ * mozilla::RemoveReference::Type is T; */ -template -struct RemoveReference -{ +template +struct RemoveReference { typedef T Type; }; -template -struct RemoveReference -{ +template +struct RemoveReference { typedef T Type; }; -template -struct RemoveReference -{ +template +struct RemoveReference { typedef T Type; }; -template +template struct Conditional; namespace detail { enum Voidness { TIsVoid, TIsNotVoid }; -template::value ? TIsVoid : TIsNotVoid> +template ::value ? TIsVoid : TIsNotVoid> struct AddLvalueReferenceHelper; -template -struct AddLvalueReferenceHelper -{ +template +struct AddLvalueReferenceHelper { typedef void Type; }; -template -struct AddLvalueReferenceHelper -{ +template +struct AddLvalueReferenceHelper { typedef T& Type; }; -} // namespace detail +} // namespace detail /** * AddLvalueReference adds an lvalue & reference to T if one isn't already @@ -882,29 +907,25 @@ * mozilla::AddLvalueReference::Type is void; * mozilla::AddLvalueReference::Type is struct S&. */ -template -struct AddLvalueReference - : detail::AddLvalueReferenceHelper -{}; +template +struct AddLvalueReference : detail::AddLvalueReferenceHelper {}; namespace detail { -template::value ? TIsVoid : TIsNotVoid> +template ::value ? TIsVoid : TIsNotVoid> struct AddRvalueReferenceHelper; -template -struct AddRvalueReferenceHelper -{ +template +struct AddRvalueReferenceHelper { typedef void Type; }; -template -struct AddRvalueReferenceHelper -{ +template +struct AddRvalueReferenceHelper { typedef T&& Type; }; -} // namespace detail +} // namespace detail /** * AddRvalueReference adds an rvalue && reference to T if one isn't already @@ -921,66 +942,69 @@ * mozilla::AddRvalueReference::Type is void; * mozilla::AddRvalueReference::Type is struct S&. */ -template -struct AddRvalueReference - : detail::AddRvalueReferenceHelper -{}; +template +struct AddRvalueReference : detail::AddRvalueReferenceHelper {}; /* 20.9.7.3 Sign modifications [meta.trans.sign] */ -template +template struct EnableIf; namespace detail { -template -struct WithC : Conditional -{}; - -template -struct WithV : Conditional -{}; +template +struct WithC : Conditional {}; +template +struct WithV : Conditional {}; -template -struct WithCV : WithC::Type> -{}; +template +struct WithCV : WithC::Type> {}; -template +template struct CorrespondingSigned; -template<> -struct CorrespondingSigned { typedef signed char Type; }; -template<> -struct CorrespondingSigned { typedef signed char Type; }; -template<> -struct CorrespondingSigned { typedef short Type; }; -template<> -struct CorrespondingSigned { typedef int Type; }; -template<> -struct CorrespondingSigned { typedef long Type; }; -template<> -struct CorrespondingSigned { typedef long long Type; }; - -template::Type, - bool IsSignedIntegerType = IsSigned::value && - !IsSame::value> +template <> +struct CorrespondingSigned { + typedef signed char Type; +}; +template <> +struct CorrespondingSigned { + typedef signed char Type; +}; +template <> +struct CorrespondingSigned { + typedef short Type; +}; +template <> +struct CorrespondingSigned { + typedef int Type; +}; +template <> +struct CorrespondingSigned { + typedef long Type; +}; +template <> +struct CorrespondingSigned { + typedef long long Type; +}; + +template ::Type, + bool IsSignedIntegerType = + IsSigned::value && !IsSame::value> struct MakeSigned; -template -struct MakeSigned -{ +template +struct MakeSigned { typedef T Type; }; -template +template struct MakeSigned - : WithCV::value, IsVolatile::value, - typename CorrespondingSigned::Type> -{}; + : WithCV::value, IsVolatile::value, + typename CorrespondingSigned::Type> {}; -} // namespace detail +} // namespace detail /** * MakeSigned produces the corresponding signed integer type for a given @@ -1004,52 +1028,58 @@ * mozilla::MakeSigned is an error; * mozilla::MakeSigned is an error. */ -template +template struct MakeSigned - : EnableIf::value && - !IsSame::Type>::value, - typename detail::MakeSigned - >::Type -{}; + : EnableIf::value && + !IsSame::Type>::value, + typename detail::MakeSigned >::Type {}; namespace detail { -template +template struct CorrespondingUnsigned; -template<> -struct CorrespondingUnsigned { typedef unsigned char Type; }; -template<> -struct CorrespondingUnsigned { typedef unsigned char Type; }; -template<> -struct CorrespondingUnsigned { typedef unsigned short Type; }; -template<> -struct CorrespondingUnsigned { typedef unsigned int Type; }; -template<> -struct CorrespondingUnsigned { typedef unsigned long Type; }; -template<> -struct CorrespondingUnsigned { typedef unsigned long long Type; }; - - -template::Type, - bool IsUnsignedIntegerType = IsUnsigned::value && - !IsSame::value> +template <> +struct CorrespondingUnsigned { + typedef unsigned char Type; +}; +template <> +struct CorrespondingUnsigned { + typedef unsigned char Type; +}; +template <> +struct CorrespondingUnsigned { + typedef unsigned short Type; +}; +template <> +struct CorrespondingUnsigned { + typedef unsigned int Type; +}; +template <> +struct CorrespondingUnsigned { + typedef unsigned long Type; +}; +template <> +struct CorrespondingUnsigned { + typedef unsigned long long Type; +}; + +template ::Type, + bool IsUnsignedIntegerType = + IsUnsigned::value && !IsSame::value> struct MakeUnsigned; -template -struct MakeUnsigned -{ +template +struct MakeUnsigned { typedef T Type; }; -template +template struct MakeUnsigned - : WithCV::value, IsVolatile::value, - typename CorrespondingUnsigned::Type> -{}; + : WithCV::value, IsVolatile::value, + typename CorrespondingUnsigned::Type> {}; -} // namespace detail +} // namespace detail /** * MakeUnsigned produces the corresponding unsigned integer type for a given @@ -1073,13 +1103,11 @@ * mozilla::MakeUnsigned is an error; * mozilla::MakeUnsigned is an error. */ -template +template struct MakeUnsigned - : EnableIf::value && - !IsSame::Type>::value, - typename detail::MakeUnsigned - >::Type -{}; + : EnableIf::value && + !IsSame::Type>::value, + typename detail::MakeUnsigned >::Type {}; /* 20.9.7.4 Array modifications [meta.trans.arr] */ @@ -1092,21 +1120,18 @@ * mozilla::RemoveExtent::Type is volatile int; * mozilla::RemoveExtent::Type is long[17]. */ -template -struct RemoveExtent -{ +template +struct RemoveExtent { typedef T Type; }; -template -struct RemoveExtent -{ +template +struct RemoveExtent { typedef T Type; }; -template -struct RemoveExtent -{ +template +struct RemoveExtent { typedef T Type; }; @@ -1114,19 +1139,17 @@ namespace detail { -template -struct RemovePointerHelper -{ +template +struct RemovePointerHelper { typedef T Type; }; -template -struct RemovePointerHelper -{ +template +struct RemovePointerHelper { typedef Pointee Type; }; -} // namespace detail +} // namespace detail /** * Produces the pointed-to type if a pointer is provided, else returns the input @@ -1143,10 +1166,9 @@ * mozilla::RemovePointer::Type is void(); * mozilla::RemovePointer::Type is bool S::*. */ -template +template struct RemovePointer - : detail::RemovePointerHelper::Type> -{}; + : detail::RemovePointerHelper::Type> {}; /** * Converts T& to T*. Otherwise returns T* given T. Note that C++17 wants @@ -1158,9 +1180,8 @@ * mozilla::AddPointer is int*; * mozilla::AddPointer is int** const. */ -template -struct AddPointer -{ +template +struct AddPointer { typedef typename RemoveReference::Type* Type; }; @@ -1184,13 +1205,11 @@ * ... * }; */ -template -struct EnableIf -{}; - -template -struct EnableIf -{ +template +struct EnableIf {}; + +template +struct EnableIf { typedef T Type; }; @@ -1200,44 +1219,38 @@ * mozilla::Conditional::Type is A; * mozilla::Conditional::Type is B; */ -template -struct Conditional -{ +template +struct Conditional { typedef A Type; }; -template -struct Conditional -{ +template +struct Conditional { typedef B Type; }; namespace detail { -template::value, - bool IsFunction = IsFunction::value> +template ::value, + bool IsFunction = IsFunction::value> struct DecaySelector; -template -struct DecaySelector -{ +template +struct DecaySelector { typedef typename RemoveCV::Type Type; }; -template -struct DecaySelector -{ +template +struct DecaySelector { typedef typename RemoveExtent::Type* Type; }; -template -struct DecaySelector -{ +template +struct DecaySelector { typedef typename AddPointer::Type Type; }; -}; // namespace detail +}; // namespace detail /** * Strips const/volatile off a type and decays it from an lvalue to an @@ -1251,10 +1264,8 @@ * mozilla::Decay::Type is int* * mozilla::Decay::Type is int(*)(int) */ -template -class Decay - : public detail::DecaySelector::Type> -{ +template +class Decay : public detail::DecaySelector::Type> { }; } /* namespace mozilla */ 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 @@ -40,70 +40,58 @@ * operators have as return type a class, CastableTypedEnumResult, * that wraps a typed enum but adds bool convertibility. */ -template -class CastableTypedEnumResult -{ -private: +template +class CastableTypedEnumResult { + private: const E mValue; -public: - explicit constexpr CastableTypedEnumResult(E aValue) - : mValue(aValue) - {} + public: + explicit constexpr CastableTypedEnumResult(E aValue) : mValue(aValue) {} constexpr operator E() const { return mValue; } - template - explicit constexpr - operator DestinationType() const { return DestinationType(mValue); } + template + explicit constexpr operator DestinationType() const { + return DestinationType(mValue); + } - constexpr bool operator !() const { return !bool(mValue); } + constexpr bool operator!() const { return !bool(mValue); } }; -#define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType) \ -template \ -constexpr ReturnType \ -operator Op(const OtherType& aE, const CastableTypedEnumResult& aR) \ -{ \ - return ReturnType(aE Op OtherType(aR)); \ -} \ -template \ -constexpr ReturnType \ -operator Op(const CastableTypedEnumResult& aR, const OtherType& aE) \ -{ \ - return ReturnType(OtherType(aR) Op aE); \ -} \ -template \ -constexpr ReturnType \ -operator Op(const CastableTypedEnumResult& aR1, \ - const CastableTypedEnumResult& aR2) \ -{ \ - return ReturnType(OtherType(aR1) Op OtherType(aR2)); \ -} +#define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType) \ + template \ + constexpr ReturnType operator Op(const OtherType& aE, \ + const CastableTypedEnumResult& aR) { \ + return ReturnType(aE Op OtherType(aR)); \ + } \ + template \ + constexpr ReturnType operator Op(const CastableTypedEnumResult& aR, \ + const OtherType& aE) { \ + return ReturnType(OtherType(aR) Op aE); \ + } \ + template \ + constexpr ReturnType operator Op(const CastableTypedEnumResult& aR1, \ + const CastableTypedEnumResult& aR2) { \ + return ReturnType(OtherType(aR1) Op OtherType(aR2)); \ + } MOZ_CASTABLETYPEDENUMRESULT_BINOP(|, E, CastableTypedEnumResult) MOZ_CASTABLETYPEDENUMRESULT_BINOP(&, E, CastableTypedEnumResult) -MOZ_CASTABLETYPEDENUMRESULT_BINOP(^, E, CastableTypedEnumResult) +MOZ_CASTABLETYPEDENUMRESULT_BINOP (^, E, CastableTypedEnumResult) MOZ_CASTABLETYPEDENUMRESULT_BINOP(==, E, bool) MOZ_CASTABLETYPEDENUMRESULT_BINOP(!=, E, bool) -MOZ_CASTABLETYPEDENUMRESULT_BINOP(||, bool, bool) -MOZ_CASTABLETYPEDENUMRESULT_BINOP(&&, bool, bool) template -constexpr CastableTypedEnumResult -operator ~(const CastableTypedEnumResult& aR) -{ +constexpr CastableTypedEnumResult operator~( + const CastableTypedEnumResult& aR) { return CastableTypedEnumResult(~(E(aR))); } -#define MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(Op) \ -template \ -E& \ -operator Op(E& aR1, \ - const CastableTypedEnumResult& aR2) \ -{ \ - return aR1 Op E(aR2); \ -} +#define MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(Op) \ + template \ + E& operator Op(E& aR1, const CastableTypedEnumResult& aR2) { \ + return aR1 Op E(aR2); \ + } MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(&=) MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(|=) @@ -114,43 +102,34 @@ #undef MOZ_CASTABLETYPEDENUMRESULT_BINOP namespace detail { -template -struct UnsignedIntegerTypeForEnum - : UnsignedStdintTypeForSize -{}; -} // namespace detail - -} // namespace mozilla - -#define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op) \ - inline constexpr mozilla::CastableTypedEnumResult \ - operator Op(Name a, Name b) \ - { \ - typedef mozilla::CastableTypedEnumResult Result; \ - typedef mozilla::detail::UnsignedIntegerTypeForEnum::Type U; \ - return Result(Name(U(a) Op U(b))); \ - } \ - \ - inline Name& \ - operator Op##=(Name& a, Name b) \ - { \ - return a = a Op b; \ - } +template +struct UnsignedIntegerTypeForEnum : UnsignedStdintTypeForSize {}; +} // namespace detail + +} // namespace mozilla + +#define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op) \ + inline constexpr mozilla::CastableTypedEnumResult operator Op( \ + Name a, Name b) { \ + typedef mozilla::CastableTypedEnumResult Result; \ + typedef mozilla::detail::UnsignedIntegerTypeForEnum::Type U; \ + return Result(Name(U(a) Op U(b))); \ + } \ + \ + inline Name& operator Op##=(Name& a, Name b) { return a = a Op b; } /** * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS generates standard bitwise operators * for the given enum type. Use this to enable using an enum type as bit-field. */ -#define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name) \ - MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |) \ - MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &) \ - MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^) \ - inline constexpr mozilla::CastableTypedEnumResult \ - operator~(Name a) \ - { \ - typedef mozilla::CastableTypedEnumResult Result; \ - typedef mozilla::detail::UnsignedIntegerTypeForEnum::Type U; \ - return Result(Name(~(U(a)))); \ - } +#define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name) \ + MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |) \ + MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &) \ + MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^) \ + inline constexpr mozilla::CastableTypedEnumResult operator~(Name a) { \ + typedef mozilla::CastableTypedEnumResult Result; \ + typedef mozilla::detail::UnsignedIntegerTypeForEnum::Type U; \ + return Result(Name(~(U(a)))); \ + } -#endif // mozilla_TypedEnumBits_h +#endif // mozilla_TypedEnumBits_h 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 @@ -38,17 +38,16 @@ * methods or data used cross-file. */ #if defined(WIN32) -# define MOZ_EXPORT __declspec(dllexport) +#define MOZ_EXPORT __declspec(dllexport) #else /* Unix */ -# ifdef HAVE_VISIBILITY_ATTRIBUTE -# define MOZ_EXPORT __attribute__((visibility("default"))) -# elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# define MOZ_EXPORT __global -# else -# define MOZ_EXPORT /* nothing */ -# endif +#ifdef HAVE_VISIBILITY_ATTRIBUTE +#define MOZ_EXPORT __attribute__((visibility("default"))) +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#define MOZ_EXPORT __global +#else +#define MOZ_EXPORT /* nothing */ +#endif #endif - /* * Whereas implementers use MOZ_EXPORT to declare and define library symbols, @@ -58,19 +57,19 @@ * mode. */ #ifdef _WIN32 -# if defined(__MWERKS__) -# define MOZ_IMPORT_API /* nothing */ -# else -# define MOZ_IMPORT_API __declspec(dllimport) -# endif +#if defined(__MWERKS__) +#define MOZ_IMPORT_API /* nothing */ #else -# define MOZ_IMPORT_API MOZ_EXPORT +#define MOZ_IMPORT_API __declspec(dllimport) +#endif +#else +#define MOZ_IMPORT_API MOZ_EXPORT #endif #if defined(_WIN32) && !defined(__MWERKS__) -# define MOZ_IMPORT_DATA __declspec(dllimport) +#define MOZ_IMPORT_DATA __declspec(dllimport) #else -# define MOZ_IMPORT_DATA MOZ_EXPORT +#define MOZ_IMPORT_DATA MOZ_EXPORT #endif /* @@ -78,24 +77,31 @@ * export mfbt declarations when building mfbt, and they expose import mfbt * declarations when using mfbt. */ -#if defined(IMPL_MFBT) -# define MFBT_API MOZ_EXPORT -# define MFBT_DATA MOZ_EXPORT -#else - /* - * On linux mozglue is linked in the program and we link libxul.so with - * -z,defs. Normally that causes the linker to reject undefined references in - * libxul.so, but as a loophole it allows undefined references to weak - * symbols. We add the weak attribute to the import version of the MFBT API - * macros to exploit this. - */ -# if defined(MOZ_GLUE_IN_PROGRAM) -# define MFBT_API __attribute__((weak)) MOZ_IMPORT_API -# define MFBT_DATA __attribute__((weak)) MOZ_IMPORT_DATA -# else -# define MFBT_API MOZ_IMPORT_API -# define MFBT_DATA MOZ_IMPORT_DATA -# endif +#if defined(IMPL_MFBT) || \ + (defined(JS_STANDALONE) && !defined(MOZ_MEMORY) && \ + (defined(EXPORT_JS_API) || defined(STATIC_EXPORTABLE_JS_API))) +#define MFBT_API MOZ_EXPORT +#define MFBT_DATA MOZ_EXPORT +#else +#if defined(JS_STANDALONE) && !defined(MOZ_MEMORY) && defined(STATIC_JS_API) +#define MFBT_API +#define MFBT_DATA +#else +/* + * On linux mozglue is linked in the program and we link libxul.so with + * -z,defs. Normally that causes the linker to reject undefined references in + * libxul.so, but as a loophole it allows undefined references to weak + * symbols. We add the weak attribute to the import version of the MFBT API + * macros to exploit this. + */ +#if defined(MOZ_GLUE_IN_PROGRAM) +#define MFBT_API __attribute__((weak)) MOZ_IMPORT_API +#define MFBT_DATA __attribute__((weak)) MOZ_IMPORT_DATA +#else +#define MFBT_API MOZ_IMPORT_API +#define MFBT_DATA MOZ_IMPORT_DATA +#endif +#endif #endif /* @@ -116,19 +122,19 @@ * its greater clarity. */ #ifdef __cplusplus -# define MOZ_BEGIN_EXTERN_C extern "C" { -# define MOZ_END_EXTERN_C } +#define MOZ_BEGIN_EXTERN_C extern "C" { +#define MOZ_END_EXTERN_C } #else -# define MOZ_BEGIN_EXTERN_C -# define MOZ_END_EXTERN_C +#define MOZ_BEGIN_EXTERN_C +#define MOZ_END_EXTERN_C #endif /* * GCC's typeof is available when decltype is not. */ #if defined(__GNUC__) && defined(__cplusplus) && \ - !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L -# define decltype __typeof__ + !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L +#define decltype __typeof__ #endif #endif /* mozilla_Types_h */ 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 @@ -18,45 +18,46 @@ namespace mozilla { -template class DefaultDelete; -template> class UniquePtr; +template +class DefaultDelete; +template > +class UniquePtr; -} // namespace mozilla +} // namespace mozilla namespace mozilla { namespace detail { -struct HasPointerTypeHelper -{ - template static double Test(...); - template static char Test(typename U::pointer* = 0); +struct HasPointerTypeHelper { + template + static double Test(...); + template + static char Test(typename U::pointer* = 0); }; template -class HasPointerType : public IntegralConstant(0)) == 1> -{ -}; +class HasPointerType + : public IntegralConstant(0)) == 1> {}; template ::value> -struct PointerTypeImpl -{ +struct PointerTypeImpl { typedef typename D::pointer Type; }; template -struct PointerTypeImpl -{ +struct PointerTypeImpl { typedef T* Type; }; template -struct PointerType -{ - typedef typename PointerTypeImpl::Type>::Type Type; +struct PointerType { + typedef + typename PointerTypeImpl::Type>::Type Type; }; -} // namespace detail +} // namespace detail /** * UniquePtr is a smart pointer that wholly owns a resource. Ownership may be @@ -184,15 +185,14 @@ * ownership of a resource into a method, should the method want it, use a * |UniquePtr&&| argument. */ -template -class UniquePtr -{ -public: +template +class UniquePtr { + public: typedef T ElementType; typedef D DeleterType; typedef typename detail::PointerType::Type Pointer; -private: + private: Pair mTuple; Pointer& ptr() { return mTuple.first(); } @@ -201,13 +201,11 @@ DeleterType& del() { return mTuple.second(); } const DeleterType& del() const { return mTuple.second(); } -public: + public: /** * Construct a UniquePtr containing |nullptr|. */ - constexpr UniquePtr() - : mTuple(static_cast(nullptr), DeleterType()) - { + constexpr UniquePtr() : mTuple(static_cast(nullptr), DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); static_assert(!IsReference::value, "must provide a deleter instance"); } @@ -215,19 +213,14 @@ /** * Construct a UniquePtr containing |aPtr|. */ - explicit UniquePtr(Pointer aPtr) - : mTuple(aPtr, DeleterType()) - { + explicit UniquePtr(Pointer aPtr) : mTuple(aPtr, DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); static_assert(!IsReference::value, "must provide a deleter instance"); } UniquePtr(Pointer aPtr, - typename Conditional::value, - D, - const D&>::Type aD1) - : mTuple(aPtr, aD1) - {} + typename Conditional::value, D, const D&>::Type aD1) + : mTuple(aPtr, aD1) {} // If you encounter an error with MSVC10 about RemoveReference below, along // the lines that "more than one partial specialization matches the template @@ -251,55 +244,45 @@ // around this with a deleter class that contains the function reference. // But this workaround is untried and untested, because variable deletion // behavior really isn't something you should use. - UniquePtr(Pointer aPtr, - typename RemoveReference::Type&& aD2) - : mTuple(aPtr, Move(aD2)) - { + UniquePtr(Pointer aPtr, typename RemoveReference::Type&& aD2) + : mTuple(aPtr, Move(aD2)) { static_assert(!IsReference::value, "rvalue deleter can't be stored by reference"); } UniquePtr(UniquePtr&& aOther) - : mTuple(aOther.release(), Forward(aOther.get_deleter())) - {} + : mTuple(aOther.release(), Forward(aOther.get_deleter())) {} MOZ_IMPLICIT - UniquePtr(decltype(nullptr)) - : mTuple(nullptr, DeleterType()) - { + UniquePtr(decltype(nullptr)) : mTuple(nullptr, DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); static_assert(!IsReference::value, "must provide a deleter instance"); } - template - MOZ_IMPLICIT - UniquePtr(UniquePtr&& aOther, - typename EnableIf::Pointer, - Pointer>::value && - !IsArray::value && - (IsReference::value - ? IsSame::value - : IsConvertible::value), - int>::Type aDummy = 0) - : mTuple(aOther.release(), Forward(aOther.get_deleter())) - { - } + template + MOZ_IMPLICIT UniquePtr( + UniquePtr&& aOther, + typename EnableIf< + IsConvertible::Pointer, Pointer>::value && + !IsArray::value && + (IsReference::value ? IsSame::value + : IsConvertible::value), + int>::Type aDummy = 0) + : mTuple(aOther.release(), Forward(aOther.get_deleter())) {} ~UniquePtr() { reset(nullptr); } - UniquePtr& operator=(UniquePtr&& aOther) - { + UniquePtr& operator=(UniquePtr&& aOther) { reset(aOther.release()); get_deleter() = Forward(aOther.get_deleter()); return *this; } - template - UniquePtr& operator=(UniquePtr&& aOther) - { - static_assert(IsConvertible::Pointer, - Pointer>::value, - "incompatible UniquePtr pointees"); + template + UniquePtr& operator=(UniquePtr&& aOther) { + static_assert( + IsConvertible::Pointer, Pointer>::value, + "incompatible UniquePtr pointees"); static_assert(!IsArray::value, "can't assign from UniquePtr holding an array"); @@ -308,15 +291,13 @@ return *this; } - UniquePtr& operator=(decltype(nullptr)) - { + UniquePtr& operator=(decltype(nullptr)) { reset(nullptr); return *this; } T& operator*() const { return *get(); } - Pointer operator->() const - { + Pointer operator->() const { MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr"); return get(); } @@ -328,15 +309,13 @@ DeleterType& get_deleter() { return del(); } const DeleterType& get_deleter() const { return del(); } - MOZ_MUST_USE Pointer release() - { + MOZ_MUST_USE Pointer release() { Pointer p = ptr(); ptr() = nullptr; return p; } - void reset(Pointer aPtr = Pointer()) - { + void reset(Pointer aPtr = Pointer()) { Pointer old = ptr(); ptr() = aPtr; if (old != nullptr) { @@ -344,37 +323,31 @@ } } - void swap(UniquePtr& aOther) - { - mTuple.swap(aOther.mTuple); - } + void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); } - UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()! - void operator=(const UniquePtr& aOther) = delete; // assign using Move()! + UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()! + void operator=(const UniquePtr& aOther) = delete; // assign using Move()! }; // In case you didn't read the comment by the main definition (you should!): the // UniquePtr specialization exists to manage array pointers. It deletes // such pointers using delete[], it will reject construction and modification // attempts using U* or U[]. Otherwise it works like the normal UniquePtr. -template -class UniquePtr -{ -public: +template +class UniquePtr { + public: typedef T* Pointer; typedef T ElementType; typedef D DeleterType; -private: + private: Pair mTuple; -public: + public: /** * Construct a UniquePtr containing nullptr. */ - constexpr UniquePtr() - : mTuple(static_cast(nullptr), DeleterType()) - { + constexpr UniquePtr() : mTuple(static_cast(nullptr), DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); static_assert(!IsReference::value, "must provide a deleter instance"); } @@ -382,9 +355,7 @@ /** * Construct a UniquePtr containing |aPtr|. */ - explicit UniquePtr(Pointer aPtr) - : mTuple(aPtr, DeleterType()) - { + explicit UniquePtr(Pointer aPtr) : mTuple(aPtr, DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); static_assert(!IsReference::value, "must provide a deleter instance"); } @@ -394,63 +365,51 @@ // fields and base classes of each element requiring destruction, and so on. // So forbid all overloads which would end up invoking delete[] on a pointer // of the wrong type. - template - UniquePtr(U&& aU, - typename EnableIf::value && - IsConvertible::value, - int>::Type aDummy = 0) - = delete; + template + UniquePtr( + U&& aU, + typename EnableIf::value && IsConvertible::value, + int>::Type aDummy = 0) = delete; UniquePtr(Pointer aPtr, - typename Conditional::value, - D, - const D&>::Type aD1) - : mTuple(aPtr, aD1) - {} + typename Conditional::value, D, const D&>::Type aD1) + : mTuple(aPtr, aD1) {} // If you encounter an error with MSVC10 about RemoveReference below, along // the lines that "more than one partial specialization matches the template // argument list": don't use UniquePtr! See the // comment by this constructor in the non-T[] specialization above. - UniquePtr(Pointer aPtr, - typename RemoveReference::Type&& aD2) - : mTuple(aPtr, Move(aD2)) - { + UniquePtr(Pointer aPtr, typename RemoveReference::Type&& aD2) + : mTuple(aPtr, Move(aD2)) { static_assert(!IsReference::value, "rvalue deleter can't be stored by reference"); } // Forbidden for the same reasons as stated above. - template - UniquePtr(U&& aU, V&& aV, - typename EnableIf::value && - IsConvertible::value, - int>::Type aDummy = 0) - = delete; + template + UniquePtr( + U&& aU, V&& aV, + typename EnableIf::value && IsConvertible::value, + int>::Type aDummy = 0) = delete; UniquePtr(UniquePtr&& aOther) - : mTuple(aOther.release(), Forward(aOther.get_deleter())) - {} + : mTuple(aOther.release(), Forward(aOther.get_deleter())) {} MOZ_IMPLICIT - UniquePtr(decltype(nullptr)) - : mTuple(nullptr, DeleterType()) - { + UniquePtr(decltype(nullptr)) : mTuple(nullptr, DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); static_assert(!IsReference::value, "must provide a deleter instance"); } ~UniquePtr() { reset(nullptr); } - UniquePtr& operator=(UniquePtr&& aOther) - { + UniquePtr& operator=(UniquePtr&& aOther) { reset(aOther.release()); get_deleter() = Forward(aOther.get_deleter()); return *this; } - UniquePtr& operator=(decltype(nullptr)) - { + UniquePtr& operator=(decltype(nullptr)) { reset(); return *this; } @@ -463,15 +422,13 @@ DeleterType& get_deleter() { return mTuple.second(); } const DeleterType& get_deleter() const { return mTuple.second(); } - MOZ_MUST_USE Pointer release() - { + MOZ_MUST_USE Pointer release() { Pointer p = mTuple.first(); mTuple.first() = nullptr; return p; } - void reset(Pointer aPtr = Pointer()) - { + void reset(Pointer aPtr = Pointer()) { Pointer old = mTuple.first(); mTuple.first() = aPtr; if (old != nullptr) { @@ -479,8 +436,7 @@ } } - void reset(decltype(nullptr)) - { + void reset(decltype(nullptr)) { Pointer old = mTuple.first(); mTuple.first() = nullptr; if (old != nullptr) { @@ -488,13 +444,13 @@ } } - template + template void reset(U) = delete; void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); } - UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()! - void operator=(const UniquePtr& aOther) = delete; // assign using Move()! + UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()! + void operator=(const UniquePtr& aOther) = delete; // assign using Move()! }; /** @@ -510,88 +466,70 @@ * types), since |delete|-ing such a type will always trigger a compilation * error. */ -template -class DefaultDelete -{ -public: +template +class DefaultDelete { + public: constexpr DefaultDelete() {} - template - MOZ_IMPLICIT DefaultDelete(const DefaultDelete& aOther, - typename EnableIf::value, - int>::Type aDummy = 0) - {} + template + MOZ_IMPLICIT DefaultDelete( + const DefaultDelete& aOther, + typename EnableIf::value, int>::Type + aDummy = 0) {} - void operator()(T* aPtr) const - { + void operator()(T* aPtr) const { static_assert(sizeof(T) > 0, "T must be complete"); delete aPtr; } }; /** A default deletion policy using operator delete[]. */ -template -class DefaultDelete -{ -public: +template +class DefaultDelete { + public: constexpr DefaultDelete() {} - void operator()(T* aPtr) const - { + void operator()(T* aPtr) const { static_assert(sizeof(T) > 0, "T must be complete"); delete[] aPtr; } - template + template void operator()(U* aPtr) const = delete; }; -template -void -Swap(UniquePtr& aX, UniquePtr& aY) -{ +template +void Swap(UniquePtr& aX, UniquePtr& aY) { aX.swap(aY); } -template -bool -operator==(const UniquePtr& aX, const UniquePtr& aY) -{ +template +bool operator==(const UniquePtr& aX, const UniquePtr& aY) { return aX.get() == aY.get(); } -template -bool -operator!=(const UniquePtr& aX, const UniquePtr& aY) -{ +template +bool operator!=(const UniquePtr& aX, const UniquePtr& aY) { return aX.get() != aY.get(); } -template -bool -operator==(const UniquePtr& aX, decltype(nullptr)) -{ +template +bool operator==(const UniquePtr& aX, decltype(nullptr)) { return !aX; } -template -bool -operator==(decltype(nullptr), const UniquePtr& aX) -{ +template +bool operator==(decltype(nullptr), const UniquePtr& aX) { return !aX; } -template -bool -operator!=(const UniquePtr& aX, decltype(nullptr)) -{ +template +bool operator!=(const UniquePtr& aX, decltype(nullptr)) { return bool(aX); } -template -bool -operator!=(decltype(nullptr), const UniquePtr& aX) -{ +template +bool operator!=(decltype(nullptr), const UniquePtr& aX) { return bool(aX); } @@ -599,25 +537,22 @@ namespace detail { -template -struct UniqueSelector -{ +template +struct UniqueSelector { typedef UniquePtr SingleObject; }; -template -struct UniqueSelector -{ +template +struct UniqueSelector { typedef UniquePtr UnknownBound; }; -template -struct UniqueSelector -{ +template +struct UniqueSelector { typedef UniquePtr KnownBound; }; -} // namespace detail +} // namespace detail /** * MakeUnique is a helper function for allocating new'd objects and arrays, @@ -673,25 +608,22 @@ * ably serves this function.) */ -template -typename detail::UniqueSelector::SingleObject -MakeUnique(Args&&... aArgs) -{ +template +typename detail::UniqueSelector::SingleObject MakeUnique(Args&&... aArgs) { return UniquePtr(new T(Forward(aArgs)...)); } -template -typename detail::UniqueSelector::UnknownBound -MakeUnique(decltype(sizeof(int)) aN) -{ +template +typename detail::UniqueSelector::UnknownBound MakeUnique( + decltype(sizeof(int)) aN) { typedef typename RemoveExtent::Type ArrayType; return UniquePtr(new ArrayType[aN]()); } -template -typename detail::UniqueSelector::KnownBound -MakeUnique(Args&&... aArgs) = delete; +template +typename detail::UniqueSelector::KnownBound MakeUnique(Args&&... aArgs) = + delete; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_UniquePtr_h */ 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 @@ -18,40 +18,35 @@ * MakeUniqueFallible works exactly like MakeUnique, except that the memory * allocation performed is done fallibly, i.e. it can return nullptr. */ -template -typename detail::UniqueSelector::SingleObject -MakeUniqueFallible(Args&&... aArgs) -{ +template +typename detail::UniqueSelector::SingleObject MakeUniqueFallible( + Args&&... aArgs) { return UniquePtr(new (fallible) T(Forward(aArgs)...)); } -template -typename detail::UniqueSelector::UnknownBound -MakeUniqueFallible(decltype(sizeof(int)) aN) -{ +template +typename detail::UniqueSelector::UnknownBound MakeUniqueFallible( + decltype(sizeof(int)) aN) { typedef typename RemoveExtent::Type ArrayType; return UniquePtr(new (fallible) ArrayType[aN]()); } -template -typename detail::UniqueSelector::KnownBound -MakeUniqueFallible(Args&&... aArgs) = delete; +template +typename detail::UniqueSelector::KnownBound MakeUniqueFallible( + Args&&... aArgs) = delete; namespace detail { -template -struct FreePolicy -{ - void operator()(const void* ptr) { - free(const_cast(ptr)); - } +template +struct FreePolicy { + void operator()(const void* ptr) { free(const_cast(ptr)); } }; -} // namespace detail +} // namespace detail -template +template using UniqueFreePtr = UniquePtr>; -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_UniquePtrExtensions_h +#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 @@ -9,145 +9,128 @@ #include #include -#include "mozilla/Alignment.h" #include "mozilla/Assertions.h" #include "mozilla/Move.h" +#include "mozilla/OperatorNewExtensions.h" +#include "mozilla/TemplateLib.h" #include "mozilla/TypeTraits.h" #ifndef mozilla_Variant_h #define mozilla_Variant_h +namespace IPC { +template +struct ParamTraits; +} // namespace IPC + namespace mozilla { -template +template class Variant; namespace detail { -// MaxSizeOf computes the maximum sizeof(T) for each T in Ts. - -template -struct MaxSizeOf -{ - static const size_t size = sizeof(T) > MaxSizeOf::size - ? sizeof(T) - : MaxSizeOf::size; -}; - -template -struct MaxSizeOf -{ - static const size_t size = sizeof(T); -}; - -// The `IsVariant` helper is used in conjunction with static_assert and -// `mozilla::EnableIf` to catch passing non-variant types to `Variant::is()` -// and friends at compile time, rather than at runtime. It ensures that the -// given type `Needle` is one of the types in the set of types `Haystack`. - -template -struct IsVariant; - -template -struct IsVariant -{ - static const bool value = false; +// Nth::Type is the Nth type (0-based) in the list of types Ts. +template +struct Nth; + +template +struct Nth<0, T, Ts...> { + using Type = T; }; -template -struct IsVariant -{ - static const bool value = true; +template +struct Nth { + using Type = typename Nth::Type; }; -template -struct IsVariant : public IsVariant { }; - /// SelectVariantTypeHelper is used in the implementation of SelectVariantType. -template +template struct SelectVariantTypeHelper; -template -struct SelectVariantTypeHelper -{ }; - -template -struct SelectVariantTypeHelper -{ +template +struct SelectVariantTypeHelper { + static constexpr size_t count = 0; +}; + +template +struct SelectVariantTypeHelper { typedef T Type; + static constexpr size_t count = + 1 + SelectVariantTypeHelper::count; }; -template -struct SelectVariantTypeHelper -{ +template +struct SelectVariantTypeHelper { typedef const T Type; + static constexpr size_t count = + 1 + SelectVariantTypeHelper::count; }; -template -struct SelectVariantTypeHelper -{ +template +struct SelectVariantTypeHelper { typedef const T& Type; + static constexpr size_t count = + 1 + SelectVariantTypeHelper::count; }; -template -struct SelectVariantTypeHelper -{ +template +struct SelectVariantTypeHelper { typedef T&& Type; + static constexpr size_t count = + 1 + SelectVariantTypeHelper::count; }; -template +template struct SelectVariantTypeHelper - : public 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. + * SelectVariantType also has a `count` member that contains the total number of + * selectable types (which will be used to check that a requested type is not + * ambiguously present twice.) */ template struct SelectVariantType - : public SelectVariantTypeHelper::Type>::Type, - Variants...> -{ }; + : public SelectVariantTypeHelper< + typename RemoveConst::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: +template +struct VariantTag { + private: static const size_t TypeCount = sizeof...(Ts); -public: - using Type = - typename Conditional::Type - >::Type; + public: + using Type = typename Conditional < TypeCount < 3, bool, + typename Conditional< + TypeCount<(1 << 8), uint_fast8_t, + size_t // stop caring past a certain point :-) + >::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. -template +template struct TagHelper; // In the case where T != U, we continue recursion. -template -struct TagHelper -{ +template +struct TagHelper { static Tag tag() { return Next::template tag(); } }; // In the case where T == U, return the tag number. -template -struct TagHelper -{ +template +struct TagHelper { static Tag tag() { return Tag(N); } }; @@ -157,106 +140,99 @@ // 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 +template +struct VariantImplementation { + template static Tag tag() { static_assert(mozilla::IsSame::value, "mozilla::Variant: tag: bad type!"); return Tag(N); } - template + template static void copyConstruct(void* aLhs, const Variant& aRhs) { - new (aLhs) T(aRhs.template as()); + ::new (KnownNotNull, aLhs) T(aRhs.template as()); } - template + template static void moveConstruct(void* aLhs, Variant&& aRhs) { - new (aLhs) T(aRhs.template extract()); + ::new (KnownNotNull, aLhs) T(aRhs.template extract()); } - template + template static void destroy(Variant& aV) { - aV.template as().~T(); + aV.template as().~T(); } - template - static bool - equal(const Variant& aLhs, const Variant& aRhs) { - return aLhs.template as() == aRhs.template as(); + template + static bool equal(const Variant& aLhs, const Variant& aRhs) { + return aLhs.template as() == aRhs.template as(); } - template - static auto - match(Matcher&& aMatcher, ConcreteVariant& aV) - -> decltype(aMatcher.match(aV.template as())) - { - return aMatcher.match(aV.template as()); + template + 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; - template + template static Tag tag() { return TagHelper::value>::tag(); } - template + template static void copyConstruct(void* aLhs, const Variant& aRhs) { - if (aRhs.template is()) { - new (aLhs) T(aRhs.template as()); + if (aRhs.template is()) { + ::new (KnownNotNull, aLhs) T(aRhs.template as()); } else { Next::copyConstruct(aLhs, aRhs); } } - template + template static void moveConstruct(void* aLhs, Variant&& aRhs) { - if (aRhs.template is()) { - new (aLhs) T(aRhs.template extract()); + if (aRhs.template is()) { + ::new (KnownNotNull, aLhs) T(aRhs.template extract()); } else { - Next::moveConstruct(aLhs, aRhs); + Next::moveConstruct(aLhs, Move(aRhs)); } } - template + template static void destroy(Variant& aV) { - if (aV.template is()) { - aV.template as().~T(); + if (aV.template is()) { + aV.template as().~T(); } else { Next::destroy(aV); } } - template + template static bool equal(const Variant& aLhs, const Variant& aRhs) { - if (aLhs.template is()) { - MOZ_ASSERT(aRhs.template is()); - return aLhs.template as() == aRhs.template as(); + if (aLhs.template is()) { + MOZ_ASSERT(aRhs.template is()); + return aLhs.template as() == aRhs.template as(); } else { return Next::equal(aLhs, aRhs); } } - template - static auto - match(Matcher&& aMatcher, ConcreteVariant& aV) - -> decltype(aMatcher.match(aV.template as())) - { - if (aV.template is()) { - return aMatcher.match(aV.template as()); + template + static auto match(Matcher&& aMatcher, ConcreteVariant& aV) + -> decltype(aMatcher.match(aV.template as())) { + if (aV.template is()) { + return aMatcher.match(aV.template as()); } else { // If you're seeing compilation errors here like "no matching // function for call to 'match'" then that means that the @@ -280,24 +256,17 @@ * primitive or very small types. */ template -struct AsVariantTemporary -{ - explicit AsVariantTemporary(const T& aValue) - : mValue(aValue) - {} - - template - explicit AsVariantTemporary(U&& aValue) - : mValue(Forward(aValue)) - {} +struct AsVariantTemporary { + explicit AsVariantTemporary(const T& aValue) : mValue(aValue) {} + + template + explicit AsVariantTemporary(U&& aValue) : mValue(Forward(aValue)) {} AsVariantTemporary(const AsVariantTemporary& aOther) - : mValue(aOther.mValue) - {} + : mValue(aOther.mValue) {} AsVariantTemporary(AsVariantTemporary&& aOther) - : mValue(Move(aOther.mValue)) - {} + : mValue(Move(aOther.mValue)) {} AsVariantTemporary() = delete; void operator=(const AsVariantTemporary&) = delete; @@ -306,7 +275,19 @@ typename RemoveConst::Type>::Type mValue; }; -} // namespace detail +} // namespace detail + +// Used to unambiguously specify one of the Variant's type. +template +struct VariantType { + using Type = T; +}; + +// Used to specify one of the Variant's type by index. +template +struct VariantIndex { + static constexpr size_t index = N; +}; /** * # mozilla::Variant @@ -328,20 +309,35 @@ * * Variant v1('a'); * Variant, B, C> v2(MakeUnique()); + * Variant v3(VariantType, 0); // disambiguation needed + * Variant v4(VariantIndex<1>, 0); // 2nd int * * 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. + * there are two easier ways to construct values: * + * A. 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'). * + * B. Brace-construction with VariantType or VariantIndex; this also allows + * in-place construction with any number of arguments. + * + * struct AB { AB(int, int){...} }; + * static Variant foo() + * { + * return {VariantIndex<0>{}, 1, 2}; + * } + * // ... + * Variant v0 = Foo(); // v0 holds AB(1,2). + * * All access to the contained value goes through type-safe accessors. + * Either the stored type, or the type index may be provided. * * void * Foo(Variant v) @@ -349,11 +345,47 @@ * if (v.is()) { * A& ref = v.as(); * ... + * } else (v.is<1>()) { // Instead of v.is. + * ... * } else { * ... * } * } * + * In some situation, a Variant may be constructed from templated types, in + * which case it is possible that the same type could be given multiple times by + * an external developer. Or seemingly-different types could be aliases. + * In this case, repeated types can only be accessed through their index, to + * prevent ambiguous access by type. + * + * // Bad! + * template + * struct ResultOrError + * { + * Variant m; + * ResultOrError() : m(int(0)) {} // Error '0' by default + * ResultOrError(const T& r) : m(r) {} + * bool IsResult() const { return m.is(); } + * bool IsError() const { return m.is(); } + * }; + * // Now instantiante with the result being an int too: + * ResultOrError myResult(123); // Fail! + * // In Variant, which 'int' are we refering to, from inside + * // ResultOrError functions? + * + * // Good! + * template + * struct ResultOrError + * { + * Variant m; + * ResultOrError() : m(VariantIndex<1>{}, 0) {} // Error '0' by default + * ResultOrError(const T& r) : m(VariantIndex<0>{}, r) {} + * bool IsResult() const { return m.is<0>(); } // 0 -> T + * bool IsError() const { return m.is<1>(); } // 1 -> int + * }; + * // Now instantiante with the result being an int too: + * ResultOrError myResult(123); // It now works! + * * Attempting to use the contained value as type `T1` when the `Variant` * instance contains a value of type `T2` causes an assertion failure. * @@ -375,8 +407,8 @@ * auto ptr = v.extract>(); * * Finally, you can exhaustively match on the contained variant and branch into - * different code paths depending which type is contained. This is preferred to - * manually checking every variant type T with is() because it provides + * different code paths depending on which type is contained. This is preferred + * to manually checking every variant type T with is() because it provides * compile-time checking that you handled every type, rather than runtime * assertion failures. * @@ -430,37 +462,76 @@ * * ... * }; + * + * Because Variant must be aligned suitable to hold any value stored within it, + * and because |alignas| requirements don't affect platform ABI with respect to + * how parameters are laid out in memory, Variant can't be used as the type of a + * function parameter. Pass Variant to functions by pointer or reference + * instead. */ -template -class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Variant -{ +template +class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant { + friend struct IPC::ParamTraits>; + using Tag = typename detail::VariantTag::Type; using Impl = detail::VariantImplementation; - using RawData = AlignedStorage::size>; + + static constexpr size_t RawDataAlignment = tl::Max::value; + static constexpr size_t RawDataSize = tl::Max::value; // Raw storage for the contained variant value. - RawData raw; + alignas(RawDataAlignment) unsigned char rawData[RawDataSize]; // 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); - } + // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a + // -Werror compile error) to reinterpret_cast<> |rawData| to |T*|, even + // through |void*|. Placing the latter cast in these separate functions + // breaks the chain such that affected GCC versions no longer warn/error. + void* ptr() { return rawData; } + + const void* ptr() const { return rawData; } -public: + public: /** Perfect forwarding construction for some variant type T. */ - template::Type> - explicit Variant(RefT&& aT) - : tag(Impl::template tag()) - { - new (ptr()) T(Forward(aT)); + template ::Type> + explicit Variant(RefT&& aT) : tag(Impl::template tag()) { + static_assert( + detail::SelectVariantType::count == 1, + "Variant can only be selected by type if that type is unique"); + ::new (KnownNotNull, ptr()) T(Forward(aT)); + } + + /** + * Perfect forwarding construction for some variant type T, by + * explicitly giving the type. + * This is necessary to construct from any number of arguments, + * or to convert from a type that is not in the Variant's type list. + */ + template + MOZ_IMPLICIT Variant(const VariantType&, Args&&... aTs) + : tag(Impl::template tag()) { + ::new (KnownNotNull, ptr()) T(Forward(aTs)...); + } + + /** + * Perfect forwarding construction for some variant type T, by + * explicitly giving the type index. + * This is necessary to construct from any number of arguments, + * or to convert from a type that is not in the Variant's type list, + * or to construct a type that is present more than once in the Variant. + */ + template + MOZ_IMPLICIT Variant(const VariantIndex&, Args&&... aTs) : tag(N) { + using T = typename detail::Nth::Type; + ::new (KnownNotNull, ptr()) T(Forward(aTs)...); } /** @@ -468,25 +539,24 @@ * stored in one of the types allowable in this Variant. This is used in the * implementation of AsVariant(). */ - template::Type> + template MOZ_IMPLICIT Variant(detail::AsVariantTemporary&& aValue) - : tag(Impl::template tag()) - { - new (ptr()) T(Move(aValue.mValue)); + : tag(Impl::template tag< + typename detail::SelectVariantType::Type>()) { + using T = typename detail::SelectVariantType::Type; + static_assert( + detail::SelectVariantType::count == 1, + "Variant can only be selected by type if that type is unique"); + ::new (KnownNotNull, ptr()) T(Move(aValue.mValue)); } /** Copy construction. */ - Variant(const Variant& aRhs) - : tag(aRhs.tag) - { + Variant(const Variant& aRhs) : tag(aRhs.tag) { Impl::copyConstruct(ptr(), aRhs); } /** Move construction. */ - Variant(Variant&& aRhs) - : tag(aRhs.tag) - { + Variant(Variant&& aRhs) : tag(aRhs.tag) { Impl::moveConstruct(ptr(), Move(aRhs)); } @@ -494,7 +564,7 @@ Variant& operator=(const Variant& aRhs) { MOZ_ASSERT(&aRhs != this, "self-assign disallowed"); this->~Variant(); - new (this) Variant(aRhs); + ::new (KnownNotNull, this) Variant(aRhs); return *this; } @@ -502,32 +572,39 @@ Variant& operator=(Variant&& aRhs) { MOZ_ASSERT(&aRhs != this, "self-assign disallowed"); this->~Variant(); - new (this) Variant(Move(aRhs)); + ::new (KnownNotNull, this) Variant(Move(aRhs)); return *this; } /** Move assignment from AsVariant(). */ template - Variant& operator=(detail::AsVariantTemporary&& aValue) - { + Variant& operator=(detail::AsVariantTemporary&& aValue) { + static_assert( + detail::SelectVariantType::count == 1, + "Variant can only be selected by type if that type is unique"); this->~Variant(); - new (this) Variant(Move(aValue)); + ::new (KnownNotNull, this) Variant(Move(aValue)); return *this; } - ~Variant() - { - Impl::destroy(*this); - } + ~Variant() { Impl::destroy(*this); } /** Check which variant type is currently contained. */ - template + template bool is() const { - static_assert(detail::IsVariant::value, - "provided a type not found in this Variant's type list"); + static_assert( + detail::SelectVariantType::count == 1, + "provided a type not uniquely found in this Variant's type list"); return Impl::template tag() == tag; } + template + bool is() const { + static_assert(N < sizeof...(Ts), + "provided an index outside of this Variant's type list"); + return N == size_t(tag); + } + /** * Operator == overload that defers to the variant type's operator== * implementation if the rhs is tagged as the same type as this one. @@ -541,28 +618,43 @@ * operator== implementation if the rhs is tagged as the same type as this * one. */ - bool operator!=(const Variant& aRhs) const { - return !(*this == aRhs); - } + bool operator!=(const Variant& aRhs) const { return !(*this == aRhs); } // Accessors for working with the contained variant value. /** Mutable reference. */ - template + template T& as() { - static_assert(detail::IsVariant::value, - "provided a type not found in this Variant's type list"); - MOZ_ASSERT(is()); - return *reinterpret_cast(&raw); + static_assert( + detail::SelectVariantType::count == 1, + "provided a type not uniquely found in this Variant's type list"); + MOZ_RELEASE_ASSERT(is()); + return *static_cast(ptr()); + } + + template + typename detail::Nth::Type& as() { + static_assert(N < sizeof...(Ts), + "provided an index outside of this Variant's type list"); + MOZ_RELEASE_ASSERT(is()); + return *static_cast::Type*>(ptr()); } /** Immutable const reference. */ - template + template const T& as() const { - static_assert(detail::IsVariant::value, + static_assert(detail::SelectVariantType::count == 1, "provided a type not found in this Variant's type list"); - MOZ_ASSERT(is()); - return *reinterpret_cast(&raw); + MOZ_RELEASE_ASSERT(is()); + return *static_cast(ptr()); + } + + template + const typename detail::Nth::Type& as() const { + static_assert(N < sizeof...(Ts), + "provided an index outside of this Variant's type list"); + MOZ_RELEASE_ASSERT(is()); + return *static_cast::Type*>(ptr()); } /** @@ -571,31 +663,35 @@ * safely-destructible state, as determined by the behavior of T's move * constructor when provided the variant's internal value. */ - template + template T extract() { - static_assert(detail::IsVariant::value, - "provided a type not found in this Variant's type list"); + static_assert( + detail::SelectVariantType::count == 1, + "provided a type not uniquely found in this Variant's type list"); MOZ_ASSERT(is()); return T(Move(as())); } + template + typename detail::Nth::Type extract() { + static_assert(N < sizeof...(Ts), + "provided an index outside of this Variant's type list"); + MOZ_RELEASE_ASSERT(is()); + return typename detail::Nth::Type(Move(as())); + } + // Exhaustive matching of all variant types on the contained value. /** Match on an immutable const reference. */ - template - auto - match(Matcher&& aMatcher) const - -> decltype(Impl::match(aMatcher, *this)) - { + template + auto match(Matcher&& aMatcher) const + -> decltype(Impl::match(aMatcher, *this)) { return Impl::match(aMatcher, *this); } /** Match on a mutable non-const reference. */ - template - auto - match(Matcher&& aMatcher) - -> decltype(Impl::match(aMatcher, *this)) - { + template + auto match(Matcher&& aMatcher) -> decltype(Impl::match(aMatcher, *this)) { return Impl::match(aMatcher, *this); } }; @@ -613,13 +709,11 @@ * 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) -{ +template +detail::AsVariantTemporary AsVariant(T&& aValue) { return detail::AsVariantTemporary(Forward(aValue)); } -} // namespace mozilla +} // 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 @@ -11,7 +11,7 @@ #include "mozilla/Alignment.h" #include "mozilla/AllocPolicy.h" -#include "mozilla/ArrayUtils.h" // for PointerRangeSize +#include "mozilla/ArrayUtils.h" // for PointerRangeSize #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/MathAlgorithms.h" @@ -22,17 +22,17 @@ #include "mozilla/TemplateLib.h" #include "mozilla/TypeTraits.h" -#include // for placement new +#include // for placement new /* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */ #ifdef _MSC_VER #pragma warning(push) -#pragma warning(disable:4345) +#pragma warning(disable : 4345) #endif namespace mozilla { -template +template class Vector; namespace detail { @@ -42,9 +42,8 @@ * allocated on the heap. This means that aCapacity*sizeof(T) is as close to a * power-of-two as possible. growStorageBy() is responsible for ensuring this. */ -template -static bool CapacityHasExcessSpace(size_t aCapacity) -{ +template +static bool CapacityHasExcessSpace(size_t aCapacity) { size_t size = aCapacity * sizeof(T); return RoundUpPow2(size) - size >= sizeof(T); } @@ -53,22 +52,19 @@ * This template class provides a default implementation for vector operations * when the element type is not known to be a POD, as judged by IsPod. */ -template -struct VectorImpl -{ +template +struct VectorImpl { /* * Constructs an object in the uninitialized memory at *aDst with aArgs. */ - template + template MOZ_NONNULL(1) - static inline void new_(T* aDst, Args&&... aArgs) - { - new(KnownNotNull, aDst) T(Forward(aArgs)...); + static inline void new_(T* aDst, Args&&... aArgs) { + new (KnownNotNull, aDst) T(Forward(aArgs)...); } /* Destroys constructed objects in the range [aBegin, aEnd). */ - static inline void destroy(T* aBegin, T* aEnd) - { + static inline void destroy(T* aBegin, T* aEnd) { MOZ_ASSERT(aBegin <= aEnd); for (T* p = aBegin; p < aEnd; ++p) { p->~T(); @@ -76,8 +72,7 @@ } /* Constructs objects in the uninitialized range [aBegin, aEnd). */ - static inline void initialize(T* aBegin, T* aEnd) - { + static inline void initialize(T* aBegin, T* aEnd) { MOZ_ASSERT(aBegin <= aEnd); for (T* p = aBegin; p < aEnd; ++p) { new_(p); @@ -88,12 +83,11 @@ * Copy-constructs objects in the uninitialized range * [aDst, aDst+(aSrcEnd-aSrcStart)) from the range [aSrcStart, aSrcEnd). */ - template - static inline void copyConstruct(T* aDst, - const U* aSrcStart, const U* aSrcEnd) - { + template + static inline void copyConstruct(T* aDst, const U* aSrcStart, + const U* aSrcEnd) { MOZ_ASSERT(aSrcStart <= aSrcEnd); - for (const U* p = aSrcStart; p < aSrcEnd; ++p, ++aDst) { + for (const U *p = aSrcStart; p < aSrcEnd; ++p, ++aDst) { new_(aDst, *p); } } @@ -102,11 +96,10 @@ * Move-constructs objects in the uninitialized range * [aDst, aDst+(aSrcEnd-aSrcStart)) from the range [aSrcStart, aSrcEnd). */ - template - static inline void moveConstruct(T* aDst, U* aSrcStart, U* aSrcEnd) - { + template + static inline void moveConstruct(T* aDst, U* aSrcStart, U* aSrcEnd) { MOZ_ASSERT(aSrcStart <= aSrcEnd); - for (U* p = aSrcStart; p < aSrcEnd; ++p, ++aDst) { + for (U *p = aSrcStart; p < aSrcEnd; ++p, ++aDst) { new_(aDst, Move(*p)); } } @@ -115,9 +108,8 @@ * Copy-constructs objects in the uninitialized range [aDst, aDst+aN) from * the same object aU. */ - template - static inline void copyConstructN(T* aDst, size_t aN, const U& aU) - { + template + static inline void copyConstructN(T* aDst, size_t aN, const U& aU) { for (T* end = aDst + aN; aDst < end; ++aDst) { new_(aDst, aU); } @@ -129,9 +121,7 @@ * aNewCap has not overflowed, and (2) multiplying aNewCap by sizeof(T) will * not overflow. */ - static inline MOZ_MUST_USE bool - growTo(Vector& aV, size_t aNewCap) - { + static inline MOZ_MUST_USE bool growTo(Vector& aV, size_t aNewCap) { MOZ_ASSERT(!aV.usingInlineStorage()); MOZ_ASSERT(!CapacityHasExcessSpace(aNewCap)); T* newbuf = aV.template pod_malloc(aNewCap); @@ -147,7 +137,7 @@ aV.free_(aV.mBegin); aV.mBegin = newbuf; /* aV.mLength is unchanged. */ - aV.mCapacity = aNewCap; + aV.mTail.mCapacity = aNewCap; return true; } }; @@ -157,13 +147,11 @@ * vector operations when the element type is known to be a POD, as judged by * IsPod. */ -template -struct VectorImpl -{ - template +template +struct VectorImpl { + template MOZ_NONNULL(1) - static inline void new_(T* aDst, Args&&... aArgs) - { + static inline void new_(T* aDst, Args&&... aArgs) { // 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 @@ -174,8 +162,7 @@ static inline void destroy(T*, T*) {} - static inline void initialize(T* aBegin, T* aEnd) - { + static inline void initialize(T* aBegin, T* aEnd) { /* * You would think that memset would be a big win (or even break even) * when we know T is a POD. But currently it's not. This is probably @@ -190,10 +177,9 @@ } } - template - static inline void copyConstruct(T* aDst, - const U* aSrcStart, const U* aSrcEnd) - { + template + static inline void copyConstruct(T* aDst, const U* aSrcStart, + const U* aSrcEnd) { /* * See above memset comment. Also, notice that copyConstruct is * currently templated (T != U), so memcpy won't work without @@ -202,52 +188,60 @@ * memcpy(aDst, aSrcStart, sizeof(T) * (aSrcEnd - aSrcStart)); */ MOZ_ASSERT(aSrcStart <= aSrcEnd); - for (const U* p = aSrcStart; p < aSrcEnd; ++p, ++aDst) { + for (const U *p = aSrcStart; p < aSrcEnd; ++p, ++aDst) { new_(aDst, *p); } } - template - static inline void moveConstruct(T* aDst, - const U* aSrcStart, const U* aSrcEnd) - { + template + static inline void moveConstruct(T* aDst, const U* aSrcStart, + const U* aSrcEnd) { copyConstruct(aDst, aSrcStart, aSrcEnd); } - static inline void copyConstructN(T* aDst, size_t aN, const T& aT) - { + static inline void copyConstructN(T* aDst, size_t aN, const T& aT) { for (T* end = aDst + aN; aDst < end; ++aDst) { new_(aDst, aT); } } - static inline MOZ_MUST_USE bool - growTo(Vector& aV, size_t aNewCap) - { + static inline MOZ_MUST_USE bool growTo(Vector& aV, size_t aNewCap) { MOZ_ASSERT(!aV.usingInlineStorage()); MOZ_ASSERT(!CapacityHasExcessSpace(aNewCap)); - T* newbuf = aV.template pod_realloc(aV.mBegin, aV.mCapacity, aNewCap); + T* newbuf = + aV.template pod_realloc(aV.mBegin, aV.mTail.mCapacity, aNewCap); if (MOZ_UNLIKELY(!newbuf)) { return false; } aV.mBegin = newbuf; /* aV.mLength is unchanged. */ - aV.mCapacity = aNewCap; + aV.mTail.mCapacity = aNewCap; return true; } - static inline void - podResizeToFit(Vector& aV) - { - if (aV.usingInlineStorage() || aV.mLength == aV.mCapacity) { + static inline void podResizeToFit(Vector& aV) { + if (aV.usingInlineStorage() || aV.mLength == aV.mTail.mCapacity) { + return; + } + if (!aV.mLength) { + aV.free_(aV.mBegin); + aV.mBegin = aV.inlineStorage(); + aV.mTail.mCapacity = aV.kInlineCapacity; +#ifdef DEBUG + aV.mTail.mReserved = 0; +#endif return; } - T* newbuf = aV.template pod_realloc(aV.mBegin, aV.mCapacity, aV.mLength); + T* newbuf = + aV.template pod_realloc(aV.mBegin, aV.mTail.mCapacity, aV.mLength); if (MOZ_UNLIKELY(!newbuf)) { return; } aV.mBegin = newbuf; - aV.mCapacity = aV.mLength; + aV.mTail.mCapacity = aV.mLength; +#ifdef DEBUG + aV.mTail.mReserved = aV.mLength; +#endif } }; @@ -255,7 +249,7 @@ // DO NOT DEFINE IN YOUR OWN CODE. struct VectorTesting; -} // namespace detail +} // namespace detail /* * STL-like container providing a short-lived, dynamic buffer. Vector calls the @@ -275,16 +269,16 @@ * Vector is not reentrant: T member functions called during Vector member * functions must not call back into the same object! */ -template -class Vector final : private AllocPolicy -{ +template +class MOZ_NON_PARAM Vector final : private AllocPolicy { /* utilities */ static const bool kElemIsPod = IsPod::value; - typedef detail::VectorImpl Impl; - friend struct detail::VectorImpl; + typedef detail::VectorImpl + Impl; + friend struct detail::VectorImpl; friend struct detail::VectorTesting; @@ -294,36 +288,39 @@ /* magic constants */ - static const int kMaxInlineBytes = 1024; - - /* compute constants */ + /** + * The maximum space allocated for inline element storage. + * + * We reduce space by what the AllocPolicy base class and prior Vector member + * fields likely consume to attempt to play well with binary size classes. + */ + static constexpr size_t kMaxInlineBytes = + 1024 - + (sizeof(AllocPolicy) + sizeof(T*) + sizeof(size_t) + sizeof(size_t)); - /* - * Consider element size to be 1 for buffer sizing if there are 0 inline - * elements. This allows us to compile when the definition of the element - * type is not visible here. + /** + * The number of T elements of inline capacity built into this Vector. This + * is usually |MinInlineCapacity|, but it may be less (or zero!) for large T. * - * Explicit specialization is only allowed at namespace scope, so in order - * to keep everything here, we use a dummy template parameter with partial - * specialization. - */ - template - struct ElemSize - { - static const size_t value = sizeof(T); - }; - template - struct ElemSize<0, Dummy> - { - static const size_t value = 1; + * We use a partially-specialized template (not explicit specialization, which + * is only allowed at namespace scope) to compute this value. The benefit is + * that |sizeof(T)| need not be computed, and |T| doesn't have to be fully + * defined at the time |Vector| appears, if no inline storage is requested. + */ + template + struct ComputeCapacity { + static constexpr size_t value = + tl::Min::value; }; - static const size_t kInlineCapacity = - tl::Min::value>::value; + template + struct ComputeCapacity<0, Dummy> { + static constexpr size_t value = 0; + }; - /* Calculate inline buffer size; avoid 0-sized array. */ - static const size_t kInlineBytes = - tl::Max<1, kInlineCapacity * ElemSize::value>::value; + /** The actual inline capacity in number of elements T. This may be zero! */ + static constexpr size_t kInlineCapacity = + ComputeCapacity::value; /* member data */ @@ -339,16 +336,81 @@ /* Number of elements in the vector. */ size_t mLength; - /* Max number of elements storable in the vector without resizing. */ - size_t mCapacity; + /* + * Memory used to store capacity, reserved element count (debug builds only), + * and inline storage. The simple "answer" is: + * + * size_t mCapacity; + * #ifdef DEBUG + * size_t mReserved; + * #endif + * alignas(T) unsigned char mBytes[kInlineCapacity * sizeof(T)]; + * + * but there are complications. First, C++ forbids zero-sized arrays that + * might result. Second, we don't want zero capacity to affect Vector's size + * (even empty classes take up a byte, unless they're base classes). + * + * Yet again, we eliminate the zero-sized array using partial specialization. + * And we eliminate potential size hit by putting capacity/reserved in one + * struct, then putting the array (if any) in a derived struct. If no array + * is needed, the derived struct won't consume extra space. + */ + struct CapacityAndReserved { + explicit CapacityAndReserved(size_t aCapacity, size_t aReserved) + : mCapacity(aCapacity) +#ifdef DEBUG + , + mReserved(aReserved) +#endif + { + } + CapacityAndReserved() = default; + + /* Max number of elements storable in the vector without resizing. */ + size_t mCapacity; #ifdef DEBUG - /* Max elements of reserved or used space in this vector. */ - size_t mReserved; + /* Max elements of reserved or used space in this vector. */ + size_t mReserved; #endif + }; - /* Memory used for inline storage. */ - AlignedStorage mStorage; +// Silence warnings about this struct possibly being padded dued to the +// alignas() in it -- there's nothing we can do to avoid it. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4324) +#endif // _MSC_VER + + template + struct CRAndStorage : CapacityAndReserved { + explicit CRAndStorage(size_t aCapacity, size_t aReserved) + : CapacityAndReserved(aCapacity, aReserved) {} + CRAndStorage() = default; + + alignas(T) unsigned char mBytes[Capacity * sizeof(T)]; + + // GCC fails due to -Werror=strict-aliasing if |mBytes| is directly cast to + // T*. Indirecting through this function addresses the problem. + void* data() { return mBytes; } + + T* storage() { return static_cast(data()); } + }; + + template + struct CRAndStorage<0, Dummy> : CapacityAndReserved { + explicit CRAndStorage(size_t aCapacity, size_t aReserved) + : CapacityAndReserved(aCapacity, aReserved) {} + CRAndStorage() = default; + + T* storage() { return nullptr; } + }; + + CRAndStorage mTail; + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER #ifdef DEBUG friend class ReentrancyGuard; @@ -357,30 +419,17 @@ /* private accessors */ - bool usingInlineStorage() const - { + bool usingInlineStorage() const { return mBegin == const_cast(this)->inlineStorage(); } - T* inlineStorage() - { - return static_cast(mStorage.addr()); - } + T* inlineStorage() { return mTail.storage(); } - T* beginNoCheck() const - { - return mBegin; - } + T* beginNoCheck() const { return mBegin; } - T* endNoCheck() - { - return mBegin + mLength; - } + T* endNoCheck() { return mBegin + mLength; } - const T* endNoCheck() const - { - return mBegin + mLength; - } + const T* endNoCheck() const { return mBegin + mLength; } #ifdef DEBUG /** @@ -390,28 +439,29 @@ * are implicitly reserved. This value is always less than or equal to * |capacity()|. It may be explicitly increased using the |reserve()| method. */ - size_t reserved() const - { - MOZ_ASSERT(mLength <= mReserved); - MOZ_ASSERT(mReserved <= mCapacity); - return mReserved; + size_t reserved() const { + MOZ_ASSERT(mLength <= mTail.mReserved); + MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity); + return mTail.mReserved; } #endif /* Append operations guaranteed to succeed due to pre-reserved space. */ - template void internalAppend(U&& aU); - template + template + void internalAppend(U&& aU); + template void internalAppendAll(const Vector& aU); void internalAppendN(const T& aT, size_t aN); - template void internalAppend(const U* aBegin, size_t aLength); + template + void internalAppend(const U* aBegin, size_t aLength); -public: + public: static const size_t sMaxInlineStorage = MinInlineCapacity; typedef T ElementType; explicit Vector(AllocPolicy = AllocPolicy()); - Vector(Vector&&); /* Move constructor. */ + Vector(Vector&&); /* Move constructor. */ Vector& operator=(Vector&&); /* Move assignment. */ ~Vector(); @@ -427,98 +477,100 @@ bool empty() const { return mLength == 0; } - size_t capacity() const { return mCapacity; } + size_t capacity() const { return mTail.mCapacity; } - T* begin() - { + T* begin() { MOZ_ASSERT(!mEntered); return mBegin; } - const T* begin() const - { + const T* begin() const { MOZ_ASSERT(!mEntered); return mBegin; } - T* end() - { + T* end() { MOZ_ASSERT(!mEntered); return mBegin + mLength; } - const T* end() const - { + const T* end() const { MOZ_ASSERT(!mEntered); return mBegin + mLength; } - T& operator[](size_t aIndex) - { + T& operator[](size_t aIndex) { MOZ_ASSERT(!mEntered); MOZ_ASSERT(aIndex < mLength); return begin()[aIndex]; } - const T& operator[](size_t aIndex) const - { + const T& operator[](size_t aIndex) const { MOZ_ASSERT(!mEntered); MOZ_ASSERT(aIndex < mLength); return begin()[aIndex]; } - T& back() - { + T& back() { MOZ_ASSERT(!mEntered); MOZ_ASSERT(!empty()); return *(end() - 1); } - const T& back() const - { + const T& back() const { MOZ_ASSERT(!mEntered); MOZ_ASSERT(!empty()); return *(end() - 1); } - class Range - { + class Range { friend class Vector; T* mCur; T* mEnd; - Range(T* aCur, T* aEnd) - : mCur(aCur) - , mEnd(aEnd) - { + Range(T* aCur, T* aEnd) : mCur(aCur), mEnd(aEnd) { MOZ_ASSERT(aCur <= aEnd); } - public: + public: bool empty() const { return mCur == mEnd; } size_t remain() const { return PointerRangeSize(mCur, mEnd); } - T& front() const { MOZ_ASSERT(!empty()); return *mCur; } - void popFront() { MOZ_ASSERT(!empty()); ++mCur; } - T popCopyFront() { MOZ_ASSERT(!empty()); return *mCur++; } + T& front() const { + MOZ_ASSERT(!empty()); + return *mCur; + } + void popFront() { + MOZ_ASSERT(!empty()); + ++mCur; + } + T popCopyFront() { + MOZ_ASSERT(!empty()); + return *mCur++; + } }; - class ConstRange - { + class ConstRange { friend class Vector; const T* mCur; const T* mEnd; - ConstRange(const T* aCur, const T* aEnd) - : mCur(aCur) - , mEnd(aEnd) - { + ConstRange(const T* aCur, const T* aEnd) : mCur(aCur), mEnd(aEnd) { MOZ_ASSERT(aCur <= aEnd); } - public: + public: bool empty() const { return mCur == mEnd; } size_t remain() const { return PointerRangeSize(mCur, mEnd); } - const T& front() const { MOZ_ASSERT(!empty()); return *mCur; } - void popFront() { MOZ_ASSERT(!empty()); ++mCur; } - T popCopyFront() { MOZ_ASSERT(!empty()); return *mCur++; } + const T& front() const { + MOZ_ASSERT(!empty()); + return *mCur; + } + void popFront() { + MOZ_ASSERT(!empty()); + ++mCur; + } + T popCopyFront() { + MOZ_ASSERT(!empty()); + return *mCur++; + } }; Range all() { return Range(begin(), end()); } @@ -610,50 +662,47 @@ * vector, instead of copying it. If it fails, |aU| is left unmoved. ("We are * not amused.") */ - template MOZ_MUST_USE 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 - MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) - { - if (!growByUninitialized(1)) - return false; + template + MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) { + if (!growByUninitialized(1)) return false; Impl::new_(&back(), Forward(aArgs)...); return true; } - template + template 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); + 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 * memory has been pre-reserved. Don't use this if you haven't reserved the * memory! */ - template void infallibleAppend(U&& aU) - { + template + void infallibleAppend(U&& aU) { internalAppend(Forward(aU)); } - void infallibleAppendN(const T& aT, size_t aN) - { - internalAppendN(aT, aN); - } - template void infallibleAppend(const U* aBegin, const U* aEnd) - { + void infallibleAppendN(const T& aT, size_t aN) { internalAppendN(aT, aN); } + template + void infallibleAppend(const U* aBegin, const U* aEnd) { internalAppend(aBegin, PointerRangeSize(aBegin, aEnd)); } - template void infallibleAppend(const U* aBegin, size_t aLength) - { + template + void infallibleAppend(const U* aBegin, size_t aLength) { internalAppend(aBegin, aLength); } - template - void infallibleEmplaceBack(Args&&... aArgs) - { + template + void infallibleEmplaceBack(Args&&... aArgs) { infallibleGrowByUninitialized(1); Impl::new_(&back(), Forward(aArgs)...); } @@ -698,6 +747,17 @@ * AllocPolicy. * * N.B. This call assumes that there are no uninitialized elements in the + * passed range [aP, aP + aLength). The range [aP + aLength, aP + + * aCapacity) must be allocated uninitialized memory. + */ + void replaceRawBuffer(T* aP, size_t aLength, size_t aCapacity); + + /** + * Transfer ownership of an array of objects into the vector. The caller + * must have allocated the array in accordance with this vector's + * AllocPolicy. + * + * N.B. This call assumes that there are no uninitialized elements in the * passed array. */ void replaceRawBuffer(T* aP, size_t aLength); @@ -717,7 +777,7 @@ * * This is inherently a linear-time operation. Be careful! */ - template + template MOZ_MUST_USE T* insert(T* aP, U&& aVal); /** @@ -746,53 +806,52 @@ void swap(Vector& aOther); -private: + private: Vector(const Vector&) = delete; void operator=(const Vector&) = delete; }; /* This does the re-entrancy check plus several other sanity checks. */ -#define MOZ_REENTRANCY_GUARD_ET_AL \ - ReentrancyGuard g(*this); \ - MOZ_ASSERT_IF(usingInlineStorage(), mCapacity == kInlineCapacity); \ - MOZ_ASSERT(reserved() <= mCapacity); \ - MOZ_ASSERT(mLength <= reserved()); \ - MOZ_ASSERT(mLength <= mCapacity) +#define MOZ_REENTRANCY_GUARD_ET_AL \ + ReentrancyGuard g(*this); \ + MOZ_ASSERT_IF(usingInlineStorage(), mTail.mCapacity == kInlineCapacity); \ + MOZ_ASSERT(reserved() <= mTail.mCapacity); \ + MOZ_ASSERT(mLength <= reserved()); \ + MOZ_ASSERT(mLength <= mTail.mCapacity) /* Vector Implementation */ -template -MOZ_ALWAYS_INLINE -Vector::Vector(AP aAP) - : AP(aAP) - , mLength(0) - , mCapacity(kInlineCapacity) +template +MOZ_ALWAYS_INLINE Vector::Vector(AP aAP) + : AP(aAP), + mLength(0), + mTail(kInlineCapacity, 0) #ifdef DEBUG - , mReserved(0) - , mEntered(false) + , + mEntered(false) #endif { - mBegin = static_cast(mStorage.addr()); + mBegin = inlineStorage(); } /* Move constructor. */ -template -MOZ_ALWAYS_INLINE -Vector::Vector(Vector&& aRhs) - : AllocPolicy(Move(aRhs)) +template +MOZ_ALWAYS_INLINE Vector::Vector(Vector&& aRhs) + : AllocPolicy(Move(aRhs)) #ifdef DEBUG - , mEntered(false) + , + mEntered(false) #endif { mLength = aRhs.mLength; - mCapacity = aRhs.mCapacity; + mTail.mCapacity = aRhs.mTail.mCapacity; #ifdef DEBUG - mReserved = aRhs.mReserved; + mTail.mReserved = aRhs.mTail.mReserved; #endif if (aRhs.usingInlineStorage()) { /* We can't move the buffer over in this case, so copy elements. */ - mBegin = static_cast(mStorage.addr()); + mBegin = inlineStorage(); Impl::moveConstruct(mBegin, aRhs.beginNoCheck(), aRhs.endNoCheck()); /* * Leave aRhs's mLength, mBegin, mCapacity, and mReserved as they are. @@ -804,30 +863,26 @@ * in-line storage. */ mBegin = aRhs.mBegin; - aRhs.mBegin = static_cast(aRhs.mStorage.addr()); - aRhs.mCapacity = kInlineCapacity; + aRhs.mBegin = aRhs.inlineStorage(); + aRhs.mTail.mCapacity = kInlineCapacity; aRhs.mLength = 0; #ifdef DEBUG - aRhs.mReserved = 0; + aRhs.mTail.mReserved = 0; #endif } } /* Move assignment. */ -template -MOZ_ALWAYS_INLINE Vector& -Vector::operator=(Vector&& aRhs) -{ +template +MOZ_ALWAYS_INLINE Vector& Vector::operator=(Vector&& aRhs) { MOZ_ASSERT(this != &aRhs, "self-move assignment is prohibited"); this->~Vector(); - new(KnownNotNull, this) Vector(Move(aRhs)); + new (KnownNotNull, this) Vector(Move(aRhs)); return *this; } -template -MOZ_ALWAYS_INLINE -Vector::~Vector() -{ +template +MOZ_ALWAYS_INLINE Vector::~Vector() { MOZ_REENTRANCY_GUARD_ET_AL; Impl::destroy(beginNoCheck(), endNoCheck()); if (!usingInlineStorage()) { @@ -835,9 +890,8 @@ } } -template -MOZ_ALWAYS_INLINE void -Vector::reverse() { +template +MOZ_ALWAYS_INLINE void Vector::reverse() { MOZ_REENTRANCY_GUARD_ET_AL; T* elems = mBegin; size_t len = mLength; @@ -852,10 +906,8 @@ * move all elements in the inline buffer to this new buffer, * and fail on OOM. */ -template -inline bool -Vector::convertToHeapStorage(size_t aNewCap) -{ +template +inline bool Vector::convertToHeapStorage(size_t aNewCap) { MOZ_ASSERT(usingInlineStorage()); /* Allocate buffer. */ @@ -872,15 +924,13 @@ /* Switch in heap buffer. */ mBegin = newBuf; /* mLength is unchanged. */ - mCapacity = aNewCap; + mTail.mCapacity = aNewCap; return true; } -template -MOZ_NEVER_INLINE bool -Vector::growStorageBy(size_t aIncr) -{ - MOZ_ASSERT(mLength + aIncr > mCapacity); +template +MOZ_NEVER_INLINE bool Vector::growStorageBy(size_t aIncr) { + MOZ_ASSERT(mLength + aIncr > mTail.mCapacity); /* * When choosing a new capacity, its size should is as close to 2**N bytes @@ -896,7 +946,7 @@ if (usingInlineStorage()) { /* This case occurs in ~70--80% of the calls to this function. */ size_t newSize = - tl::RoundUpPow2<(kInlineCapacity + 1) * sizeof(T)>::value; + tl::RoundUpPow2<(kInlineCapacity + 1) * sizeof(T)>::value; newCap = newSize / sizeof(T); goto convert; } @@ -938,8 +988,7 @@ /* Did mLength + aIncr overflow? Will newCap * sizeof(T) overflow? */ if (MOZ_UNLIKELY(newMinCap < mLength || - newMinCap & tl::MulOverflowMask<2 * sizeof(T)>::value)) - { + newMinCap & tl::MulOverflowMask<2 * sizeof(T)>::value)) { this->reportAllocOverflow(); return false; } @@ -950,7 +999,7 @@ } if (usingInlineStorage()) { -convert: + convert: return convertToHeapStorage(newCap); } @@ -958,10 +1007,8 @@ return Impl::growTo(*this, newCap); } -template -inline bool -Vector::initCapacity(size_t aRequest) -{ +template +inline bool Vector::initCapacity(size_t aRequest) { MOZ_ASSERT(empty()); MOZ_ASSERT(usingInlineStorage()); if (aRequest == 0) { @@ -972,17 +1019,15 @@ return false; } mBegin = newbuf; - mCapacity = aRequest; + mTail.mCapacity = aRequest; #ifdef DEBUG - mReserved = aRequest; + mTail.mReserved = aRequest; #endif return true; } -template -inline bool -Vector::initLengthUninitialized(size_t aRequest) -{ +template +inline bool Vector::initLengthUninitialized(size_t aRequest) { if (!initCapacity(aRequest)) { return false; } @@ -990,16 +1035,14 @@ return true; } -template -inline bool -Vector::maybeCheckSimulatedOOM(size_t aRequestedSize) -{ +template +inline bool Vector::maybeCheckSimulatedOOM(size_t aRequestedSize) { if (aRequestedSize <= N) { return true; } #ifdef DEBUG - if (aRequestedSize <= mReserved) { + if (aRequestedSize <= mTail.mReserved) { return true; } #endif @@ -1007,12 +1050,10 @@ return allocPolicy().checkSimulatedOOM(); } -template -inline bool -Vector::reserve(size_t aRequest) -{ +template +inline bool Vector::reserve(size_t aRequest) { MOZ_REENTRANCY_GUARD_ET_AL; - if (aRequest > mCapacity) { + if (aRequest > mTail.mCapacity) { if (MOZ_UNLIKELY(!growStorageBy(aRequest - mLength))) { return false; } @@ -1020,63 +1061,55 @@ return false; } #ifdef DEBUG - if (aRequest > mReserved) { - mReserved = aRequest; + if (aRequest > mTail.mReserved) { + mTail.mReserved = aRequest; } - MOZ_ASSERT(mLength <= mReserved); - MOZ_ASSERT(mReserved <= mCapacity); + MOZ_ASSERT(mLength <= mTail.mReserved); + MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity); #endif return true; } -template -inline void -Vector::shrinkBy(size_t aIncr) -{ +template +inline void Vector::shrinkBy(size_t aIncr) { MOZ_REENTRANCY_GUARD_ET_AL; MOZ_ASSERT(aIncr <= mLength); Impl::destroy(endNoCheck() - aIncr, endNoCheck()); mLength -= aIncr; } -template -MOZ_ALWAYS_INLINE void -Vector::shrinkTo(size_t aNewLength) -{ +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) -{ +template +MOZ_ALWAYS_INLINE bool Vector::growBy(size_t aIncr) { MOZ_REENTRANCY_GUARD_ET_AL; - if (aIncr > mCapacity - mLength) { + if (aIncr > mTail.mCapacity - mLength) { if (MOZ_UNLIKELY(!growStorageBy(aIncr))) { return false; } } else if (!maybeCheckSimulatedOOM(mLength + aIncr)) { return false; } - MOZ_ASSERT(mLength + aIncr <= mCapacity); + MOZ_ASSERT(mLength + aIncr <= mTail.mCapacity); T* newend = endNoCheck() + aIncr; Impl::initialize(endNoCheck(), newend); mLength += aIncr; #ifdef DEBUG - if (mLength > mReserved) { - mReserved = mLength; + if (mLength > mTail.mReserved) { + mTail.mReserved = mLength; } #endif return true; } -template -MOZ_ALWAYS_INLINE bool -Vector::growByUninitialized(size_t aIncr) -{ +template +MOZ_ALWAYS_INLINE bool Vector::growByUninitialized(size_t aIncr) { MOZ_REENTRANCY_GUARD_ET_AL; - if (aIncr > mCapacity - mLength) { + if (aIncr > mTail.mCapacity - mLength) { if (MOZ_UNLIKELY(!growStorageBy(aIncr))) { return false; } @@ -1084,26 +1117,23 @@ return false; } #ifdef DEBUG - if (mLength + aIncr > mReserved) { - mReserved = mLength + aIncr; + if (mLength + aIncr > mTail.mReserved) { + mTail.mReserved = mLength + aIncr; } #endif infallibleGrowByUninitialized(aIncr); return true; } -template -MOZ_ALWAYS_INLINE void -Vector::infallibleGrowByUninitialized(size_t aIncr) -{ +template +MOZ_ALWAYS_INLINE void Vector::infallibleGrowByUninitialized( + size_t aIncr) { MOZ_ASSERT(mLength + aIncr <= reserved()); mLength += aIncr; } -template -inline bool -Vector::resize(size_t aNewLength) -{ +template +inline bool Vector::resize(size_t aNewLength) { size_t curLength = mLength; if (aNewLength > curLength) { return growBy(aNewLength - curLength); @@ -1112,10 +1142,9 @@ return true; } -template -MOZ_ALWAYS_INLINE bool -Vector::resizeUninitialized(size_t aNewLength) -{ +template +MOZ_ALWAYS_INLINE bool Vector::resizeUninitialized( + size_t aNewLength) { size_t curLength = mLength; if (aNewLength > curLength) { return growByUninitialized(aNewLength - curLength); @@ -1124,73 +1153,60 @@ return true; } -template -inline void -Vector::clear() -{ +template +inline void Vector::clear() { MOZ_REENTRANCY_GUARD_ET_AL; Impl::destroy(beginNoCheck(), endNoCheck()); mLength = 0; } -template -inline void -Vector::clearAndFree() -{ +template +inline void Vector::clearAndFree() { clear(); if (usingInlineStorage()) { return; } this->free_(beginNoCheck()); - mBegin = static_cast(mStorage.addr()); - mCapacity = kInlineCapacity; + mBegin = inlineStorage(); + mTail.mCapacity = kInlineCapacity; #ifdef DEBUG - mReserved = 0; + mTail.mReserved = 0; #endif } -template -inline void -Vector::podResizeToFit() -{ +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 -{ - return mLength + aNeeded <= mCapacity; +template +inline bool Vector::canAppendWithoutRealloc(size_t aNeeded) const { + return mLength + aNeeded <= mTail.mCapacity; } -template -template -MOZ_ALWAYS_INLINE void -Vector::internalAppendAll(const Vector& aOther) -{ +template +template +MOZ_ALWAYS_INLINE void Vector::internalAppendAll( + const Vector& aOther) { internalAppend(aOther.begin(), aOther.length()); } -template -template -MOZ_ALWAYS_INLINE void -Vector::internalAppend(U&& aU) -{ - MOZ_ASSERT(mLength + 1 <= mReserved); - MOZ_ASSERT(mReserved <= mCapacity); +template +template +MOZ_ALWAYS_INLINE void Vector::internalAppend(U&& aU) { + MOZ_ASSERT(mLength + 1 <= mTail.mReserved); + MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity); Impl::new_(endNoCheck(), Forward(aU)); ++mLength; } -template -MOZ_ALWAYS_INLINE bool -Vector::appendN(const T& aT, size_t aNeeded) -{ +template +MOZ_ALWAYS_INLINE bool Vector::appendN(const T& aT, size_t aNeeded) { MOZ_REENTRANCY_GUARD_ET_AL; - if (mLength + aNeeded > mCapacity) { + if (mLength + aNeeded > mTail.mCapacity) { if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) { return false; } @@ -1198,29 +1214,26 @@ return false; } #ifdef DEBUG - if (mLength + aNeeded > mReserved) { - mReserved = mLength + aNeeded; + if (mLength + aNeeded > mTail.mReserved) { + mTail.mReserved = mLength + aNeeded; } #endif internalAppendN(aT, aNeeded); return true; } -template -MOZ_ALWAYS_INLINE void -Vector::internalAppendN(const T& aT, size_t aNeeded) -{ - MOZ_ASSERT(mLength + aNeeded <= mReserved); - MOZ_ASSERT(mReserved <= mCapacity); +template +MOZ_ALWAYS_INLINE void Vector::internalAppendN(const T& aT, + size_t aNeeded) { + MOZ_ASSERT(mLength + aNeeded <= mTail.mReserved); + MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity); Impl::copyConstructN(endNoCheck(), aNeeded, aT); mLength += aNeeded; } -template -template -inline T* -Vector::insert(T* aP, U&& aVal) -{ +template +template +inline T* Vector::insert(T* aP, U&& aVal) { MOZ_ASSERT(begin() <= aP); MOZ_ASSERT(aP <= end()); size_t pos = aP - begin(); @@ -1232,10 +1245,10 @@ } } else { T oldBack = Move(back()); - if (!append(Move(oldBack))) { /* Dup the last element. */ + if (!append(Move(oldBack))) { return nullptr; } - for (size_t i = oldLength; i > pos; --i) { + for (size_t i = oldLength - 1; i > pos; --i) { (*this)[i] = Move((*this)[i - 1]); } (*this)[pos] = Forward(aVal); @@ -1243,10 +1256,8 @@ return begin() + pos; } -template -inline void -Vector::erase(T* aIt) -{ +template +inline void Vector::erase(T* aIt) { MOZ_ASSERT(begin() <= aIt); MOZ_ASSERT(aIt < end()); while (aIt + 1 < end()) { @@ -1256,10 +1267,8 @@ popBack(); } -template -inline void -Vector::erase(T* aBegin, T* aEnd) -{ +template +inline void Vector::erase(T* aBegin, T* aEnd) { MOZ_ASSERT(begin() <= aBegin); MOZ_ASSERT(aBegin <= aEnd); MOZ_ASSERT(aEnd <= end()); @@ -1269,101 +1278,89 @@ shrinkBy(aEnd - aBegin); } -template -template -MOZ_ALWAYS_INLINE bool -Vector::append(const U* aInsBegin, const U* aInsEnd) -{ +template +template +MOZ_ALWAYS_INLINE bool Vector::append(const U* aInsBegin, + const U* aInsEnd) { MOZ_REENTRANCY_GUARD_ET_AL; size_t aNeeded = PointerRangeSize(aInsBegin, aInsEnd); - if (mLength + aNeeded > mCapacity) { + if (mLength + aNeeded > mTail.mCapacity) { if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) { return false; } } else if (!maybeCheckSimulatedOOM(mLength + aNeeded)) { - return false; + return false; } #ifdef DEBUG - if (mLength + aNeeded > mReserved) { - mReserved = mLength + aNeeded; + if (mLength + aNeeded > mTail.mReserved) { + mTail.mReserved = mLength + aNeeded; } #endif internalAppend(aInsBegin, aNeeded); return true; } -template -template -MOZ_ALWAYS_INLINE void -Vector::internalAppend(const U* aInsBegin, size_t aInsLength) -{ - MOZ_ASSERT(mLength + aInsLength <= mReserved); - MOZ_ASSERT(mReserved <= mCapacity); +template +template +MOZ_ALWAYS_INLINE void Vector::internalAppend(const U* aInsBegin, + size_t aInsLength) { + MOZ_ASSERT(mLength + aInsLength <= mTail.mReserved); + MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity); Impl::copyConstruct(endNoCheck(), aInsBegin, aInsBegin + aInsLength); mLength += aInsLength; } -template -template -MOZ_ALWAYS_INLINE bool -Vector::append(U&& aU) -{ +template +template +MOZ_ALWAYS_INLINE bool Vector::append(U&& aU) { MOZ_REENTRANCY_GUARD_ET_AL; - if (mLength == mCapacity) { + if (mLength == mTail.mCapacity) { if (MOZ_UNLIKELY(!growStorageBy(1))) { return false; } } else if (!maybeCheckSimulatedOOM(mLength + 1)) { - return false; + return false; } #ifdef DEBUG - if (mLength + 1 > mReserved) { - mReserved = mLength + 1; + if (mLength + 1 > mTail.mReserved) { + mTail.mReserved = mLength + 1; } #endif internalAppend(Forward(aU)); return true; } -template -template -MOZ_ALWAYS_INLINE bool -Vector::appendAll(const Vector& aOther) -{ +template +template +MOZ_ALWAYS_INLINE bool Vector::appendAll( + const Vector& aOther) { return append(aOther.begin(), aOther.length()); } -template -template -MOZ_ALWAYS_INLINE bool -Vector::append(const U* aInsBegin, size_t aInsLength) -{ +template +template +MOZ_ALWAYS_INLINE bool Vector::append(const U* aInsBegin, + size_t aInsLength) { return append(aInsBegin, aInsBegin + aInsLength); } -template -MOZ_ALWAYS_INLINE void -Vector::popBack() -{ +template +MOZ_ALWAYS_INLINE void Vector::popBack() { MOZ_REENTRANCY_GUARD_ET_AL; MOZ_ASSERT(!empty()); --mLength; endNoCheck()->~T(); } -template -MOZ_ALWAYS_INLINE T -Vector::popCopy() -{ +template +MOZ_ALWAYS_INLINE T Vector::popCopy() { T ret = back(); popBack(); return ret; } -template -inline T* -Vector::extractRawBuffer() -{ +template +inline T* Vector::extractRawBuffer() { MOZ_REENTRANCY_GUARD_ET_AL; if (usingInlineStorage()) { @@ -1371,19 +1368,17 @@ } T* ret = mBegin; - mBegin = static_cast(mStorage.addr()); + mBegin = inlineStorage(); mLength = 0; - mCapacity = kInlineCapacity; + mTail.mCapacity = kInlineCapacity; #ifdef DEBUG - mReserved = 0; + mTail.mReserved = 0; #endif return ret; } -template -inline T* -Vector::extractOrCopyRawBuffer() -{ +template +inline T* Vector::extractOrCopyRawBuffer() { if (T* ret = extractRawBuffer()) { return ret; } @@ -1397,19 +1392,18 @@ Impl::moveConstruct(copy, beginNoCheck(), endNoCheck()); Impl::destroy(beginNoCheck(), endNoCheck()); - mBegin = static_cast(mStorage.addr()); + mBegin = inlineStorage(); mLength = 0; - mCapacity = kInlineCapacity; + mTail.mCapacity = kInlineCapacity; #ifdef DEBUG - mReserved = 0; + mTail.mReserved = 0; #endif return copy; } -template -inline void -Vector::replaceRawBuffer(T* aP, size_t aLength) -{ +template +inline void Vector::replaceRawBuffer(T* aP, size_t aLength, + size_t aCapacity) { MOZ_REENTRANCY_GUARD_ET_AL; /* Destroy what we have. */ @@ -1419,48 +1413,48 @@ } /* Take in the new buffer. */ - if (aLength <= kInlineCapacity) { + if (aCapacity <= kInlineCapacity) { /* * We convert to inline storage if possible, even though aP might * otherwise be acceptable. Maybe this behaviour should be * specifiable with an argument to this function. */ - mBegin = static_cast(mStorage.addr()); + mBegin = inlineStorage(); mLength = aLength; - mCapacity = kInlineCapacity; + mTail.mCapacity = kInlineCapacity; Impl::moveConstruct(mBegin, aP, aP + aLength); Impl::destroy(aP, aP + aLength); this->free_(aP); } else { mBegin = aP; mLength = aLength; - mCapacity = aLength; + mTail.mCapacity = aCapacity; } #ifdef DEBUG - mReserved = aLength; + mTail.mReserved = aCapacity; #endif } -template -inline size_t -Vector::sizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const -{ +template +inline void Vector::replaceRawBuffer(T* aP, size_t aLength) { + replaceRawBuffer(aP, aLength, aLength); +} + +template +inline size_t Vector::sizeOfExcludingThis( + MallocSizeOf aMallocSizeOf) const { return usingInlineStorage() ? 0 : aMallocSizeOf(beginNoCheck()); } -template -inline size_t -Vector::sizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const -{ +template +inline size_t Vector::sizeOfIncludingThis( + MallocSizeOf aMallocSizeOf) const { return aMallocSizeOf(this) + sizeOfExcludingThis(aMallocSizeOf); } -template -inline void -Vector::swap(Vector& aOther) -{ - static_assert(N == 0, - "still need to implement this for N != 0"); +template +inline void Vector::swap(Vector& aOther) { + static_assert(N == 0, "still need to implement this for N != 0"); // This only works when inline storage is always empty. if (!usingInlineStorage() && aOther.usingInlineStorage()) { @@ -1476,13 +1470,13 @@ } Swap(mLength, aOther.mLength); - Swap(mCapacity, aOther.mCapacity); + Swap(mTail.mCapacity, aOther.mTail.mCapacity); #ifdef DEBUG - Swap(mReserved, aOther.mReserved); + Swap(mTail.mReserved, aOther.mTail.mReserved); #endif } -} // namespace mozilla +} // namespace mozilla #ifdef _MSC_VER #pragma warning(pop) 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 @@ -70,12 +70,21 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" +#include "mozilla/Maybe.h" #include "mozilla/RefCounted.h" #include "mozilla/RefPtr.h" #include "mozilla/TypeTraits.h" #include +#if defined(MOZILLA_INTERNAL_API) +// For thread safety checking. +#include "nsISupportsImpl.h" +#endif + +#if defined(MOZILLA_INTERNAL_API) && \ + defined(MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED) + // 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 @@ -89,31 +98,24 @@ // 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))) +// We re-use XPCOM's nsAutoOwningThread checks when they are available. This has +// the advantage that it works with cooperative thread pools. -#include #define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK \ - std::thread::id _owningThread; \ - bool _empty; // If it was initialized as a placeholder with mPtr = nullptr. + /* Will be none if mPtr = nullptr. */ \ + Maybe _owningThread; #define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \ - do { \ - _owningThread = std::this_thread::get_id(); \ - _empty = !p; \ + do { \ + if (p) { \ + _owningThread.emplace(); \ + } \ + } while (false) +#define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \ + do { \ + if (_owningThread.isSome() && !_owningThread.ref().IsCurrentThread()) { \ + WeakPtrTraits::AssertSafeToAccessFromNonOwningThread(); \ + } \ } 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(); @@ -122,16 +124,24 @@ #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) +#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; -template class SupportsWeakPtr; +template +class WeakPtr; +template +class SupportsWeakPtr; #ifdef MOZ_REFCOUNTED_LEAK_CHECKING #define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T) \ @@ -140,16 +150,21 @@ #define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T) #endif +template +struct WeakPtrTraits { + static void AssertSafeToAccessFromNonOwningThread() { + MOZ_DIAGNOSTIC_ASSERT(false, "WeakPtr accessed from multiple threads"); + } +}; + namespace detail { // This can live beyond the lifetime of the class derived from // SupportsWeakPtr. -template -class WeakReference : public ::mozilla::RefCounted > -{ -public: - explicit WeakReference(T* p) : mPtr(p) - { +template +class WeakReference : public ::mozilla::RefCounted > { + public: + explicit WeakReference(T* p) : mPtr(p) { MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK(); } @@ -159,8 +174,7 @@ } #ifdef MOZ_REFCOUNTED_LEAK_CHECKING - const char* typeName() const - { + const char* typeName() const { // The first time this is called mPtr is null, so don't // invoke any methods on mPtr. return T::weakReferenceTypeName(); @@ -172,7 +186,7 @@ void AssertThreadSafety() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); } #endif -private: + private: friend class mozilla::SupportsWeakPtr; void detach() { @@ -184,14 +198,12 @@ MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK }; -} // namespace detail +} // namespace detail template -class SupportsWeakPtr -{ -protected: - ~SupportsWeakPtr() - { +class SupportsWeakPtr { + protected: + ~SupportsWeakPtr() { static_assert(IsBaseOf, T>::value, "T must derive from SupportsWeakPtr"); if (mSelfReferencingWeakPtr) { @@ -199,20 +211,20 @@ } } -private: - const WeakPtr& SelfReferencingWeakPtr() - { + private: + const WeakPtr& SelfReferencingWeakPtr() { if (!mSelfReferencingWeakPtr) { - mSelfReferencingWeakPtr.mRef = new detail::WeakReference(static_cast(this)); + mSelfReferencingWeakPtr.mRef = + new detail::WeakReference(static_cast(this)); } else { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mSelfReferencingWeakPtr.mRef); } return mSelfReferencingWeakPtr; } - const WeakPtr& SelfReferencingWeakPtr() const - { - const WeakPtr& p = const_cast(this)->SelfReferencingWeakPtr(); + const WeakPtr& SelfReferencingWeakPtr() const { + const WeakPtr& p = + const_cast(this)->SelfReferencingWeakPtr(); return reinterpret_cast&>(p); } @@ -223,26 +235,22 @@ }; template -class WeakPtr -{ +class WeakPtr { typedef detail::WeakReference WeakReference; -public: - WeakPtr& operator=(const WeakPtr& aOther) - { + public: + WeakPtr& operator=(const WeakPtr& aOther) { mRef = aOther.mRef; MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef); return *this; } - WeakPtr(const WeakPtr& aOther) - { + WeakPtr(const WeakPtr& aOther) { // The thread safety check is performed inside of the operator= method. *this = aOther; } - WeakPtr& operator=(T* aOther) - { + WeakPtr& operator=(T* aOther) { if (aOther) { *this = aOther->SelfReferencingWeakPtr(); } else if (!mRef || mRef->get()) { @@ -254,8 +262,7 @@ return *this; } - MOZ_IMPLICIT WeakPtr(T* aOther) - { + MOZ_IMPLICIT WeakPtr(T* aOther) { *this = aOther; MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef); } @@ -270,7 +277,7 @@ T* get() const { return mRef->get(); } -private: + private: friend class SupportsWeakPtr; explicit WeakPtr(const RefPtr& aOther) : mRef(aOther) {} @@ -278,6 +285,6 @@ RefPtr mRef; }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_WeakPtr_h */ 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 @@ -7,17 +7,16 @@ #ifndef mozilla_WindowsVersion_h #define mozilla_WindowsVersion_h +#include "mozilla/Atomics.h" #include "mozilla/Attributes.h" #include #include namespace mozilla { -inline bool -IsWindowsVersionOrLater(uint32_t aVersion) -{ - static uint32_t minVersion = 0; - static uint32_t maxVersion = UINT32_MAX; +inline bool IsWindowsVersionOrLater(uint32_t aVersion) { + static Atomic minVersion(0); + static Atomic maxVersion(UINT32_MAX); if (minVersion >= aVersion) { return true; @@ -43,7 +42,7 @@ if (VerifyVersionInfo(&info, VER_MAJORVERSION | VER_MINORVERSION | - VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, conditionMask)) { minVersion = aVersion; return true; @@ -53,11 +52,9 @@ return false; } -inline bool -IsWindowsBuildOrLater(uint32_t aBuild) -{ - static uint32_t minBuild = 0; - static uint32_t maxBuild = UINT32_MAX; +inline bool IsWindowsBuildOrLater(uint32_t aBuild) { + static Atomic minBuild(0); + static Atomic maxBuild(UINT32_MAX); if (minBuild >= aBuild) { return true; @@ -84,114 +81,68 @@ return false; } -#if defined(_M_X64) || defined(_M_AMD64) -// We support only Win7 or later on Win64. -MOZ_ALWAYS_INLINE bool -IsXPSP3OrLater() -{ - return true; -} - -MOZ_ALWAYS_INLINE bool -IsWin2003OrLater() -{ - return true; -} - -MOZ_ALWAYS_INLINE bool -IsWin2003SP2OrLater() -{ - return true; -} +inline bool IsWindows10BuildOrLater(uint32_t aBuild) { + static Atomic minBuild(0); + static Atomic maxBuild(UINT32_MAX); -MOZ_ALWAYS_INLINE bool -IsVistaOrLater() -{ - return true; -} - -MOZ_ALWAYS_INLINE bool -IsVistaSP1OrLater() -{ - return true; -} - -MOZ_ALWAYS_INLINE bool -IsWin7OrLater() -{ - return true; -} -#else -MOZ_ALWAYS_INLINE bool -IsXPSP3OrLater() -{ - return IsWindowsVersionOrLater(0x05010300ul); -} + if (minBuild >= aBuild) { + return true; + } -MOZ_ALWAYS_INLINE bool -IsWin2003OrLater() -{ - return IsWindowsVersionOrLater(0x05020000ul); -} + if (aBuild >= maxBuild) { + return false; + } -MOZ_ALWAYS_INLINE bool -IsWin2003SP2OrLater() -{ - return IsWindowsVersionOrLater(0x05020200ul); -} + OSVERSIONINFOEX info; + ZeroMemory(&info, sizeof(OSVERSIONINFOEX)); + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + info.dwMajorVersion = 10; + info.dwBuildNumber = aBuild; -MOZ_ALWAYS_INLINE bool -IsVistaOrLater() -{ - return IsWindowsVersionOrLater(0x06000000ul); -} + DWORDLONG conditionMask = 0; + VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); -MOZ_ALWAYS_INLINE bool -IsVistaSP1OrLater() -{ - return IsWindowsVersionOrLater(0x06000100ul); -} + if (VerifyVersionInfo(&info, + VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, + conditionMask)) { + minBuild = aBuild; + return true; + } -MOZ_ALWAYS_INLINE bool -IsWin7OrLater() -{ - return IsWindowsVersionOrLater(0x06010000ul); + maxBuild = aBuild; + return false; } -#endif -MOZ_ALWAYS_INLINE bool -IsWin7SP1OrLater() -{ +MOZ_ALWAYS_INLINE bool IsWin7SP1OrLater() { return IsWindowsVersionOrLater(0x06010100ul); } -MOZ_ALWAYS_INLINE bool -IsWin8OrLater() -{ +MOZ_ALWAYS_INLINE bool IsWin8OrLater() { return IsWindowsVersionOrLater(0x06020000ul); } -MOZ_ALWAYS_INLINE bool -IsWin8Point1OrLater() -{ +MOZ_ALWAYS_INLINE bool IsWin8Point1OrLater() { return IsWindowsVersionOrLater(0x06030000ul); } -MOZ_ALWAYS_INLINE bool -IsWin10OrLater() -{ +MOZ_ALWAYS_INLINE bool IsWin10OrLater() { return IsWindowsVersionOrLater(0x0a000000ul); } -MOZ_ALWAYS_INLINE bool -IsNotWin7PreRTM() -{ - return IsWin7SP1OrLater() || !IsWin7OrLater() || - IsWindowsBuildOrLater(7600); +MOZ_ALWAYS_INLINE bool IsWin10CreatorsUpdateOrLater() { + return IsWindows10BuildOrLater(15063); +} + +MOZ_ALWAYS_INLINE bool IsNotWin7PreRTM() { + return IsWin7SP1OrLater() || IsWindowsBuildOrLater(7600); } -MOZ_ALWAYS_INLINE bool -IsWin7AndPre2000Compatible() { +inline bool IsWin7AndPre2000Compatible() { /* * See Bug 1279171. * We'd like to avoid using WMF on specific OS version when compatibility @@ -216,8 +167,8 @@ info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); #pragma warning(push) -#pragma warning(disable:4996) - bool success = GetVersionEx((LPOSVERSIONINFO) &info); +#pragma warning(disable : 4996) + bool success = GetVersionEx((LPOSVERSIONINFO)&info); #pragma warning(pop) if (!success) { return false; @@ -225,6 +176,6 @@ return info.dwMajorVersion < 5; } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_WindowsVersion_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/WrappingOperations.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/WrappingOperations.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/WrappingOperations.h @@ -0,0 +1,178 @@ +/* -*- 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/. */ + +/* + * Math operations that implement wraparound semantics on overflow or underflow + * without performing C++ undefined behavior or tripping up compiler-based + * integer-overflow sanitizers. + */ + +#ifndef mozilla_WrappingOperations_h +#define mozilla_WrappingOperations_h + +#include "mozilla/Attributes.h" +#include "mozilla/TypeTraits.h" + +#include + +namespace mozilla { + +namespace detail { + +template +struct WrapToSignedHelper { + static_assert(mozilla::IsUnsigned::value, + "WrapToSigned must be passed an unsigned type"); + + using SignedType = typename mozilla::MakeSigned::Type; + + static constexpr SignedType MaxValue = + (UnsignedType(1) << (CHAR_BIT * sizeof(SignedType) - 1)) - 1; + static constexpr SignedType MinValue = -MaxValue - 1; + + static constexpr UnsignedType MinValueUnsigned = + static_cast(MinValue); + static constexpr UnsignedType MaxValueUnsigned = + static_cast(MaxValue); + + // Overflow-correctness was proven in bug 1432646 and is explained in the + // comment below. This function is very hot, both at compile time and + // runtime, so disable all overflow checking in it. + MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW + MOZ_NO_SANITIZE_SIGNED_OVERFLOW static constexpr SignedType compute( + UnsignedType aValue) { + // This algorithm was originally provided here: + // https://stackoverflow.com/questions/13150449/efficient-unsigned-to-signed-cast-avoiding-implementation-defined-behavior + // + // If the value is in the non-negative signed range, just cast. + // + // If the value will be negative, compute its delta from the first number + // past the max signed integer, then add that to the minimum signed value. + // + // At the low end: if |u| is the maximum signed value plus one, then it has + // the same mathematical value as |MinValue| cast to unsigned form. The + // delta is zero, so the signed form of |u| is |MinValue| -- exactly the + // result of adding zero delta to |MinValue|. + // + // At the high end: if |u| is the maximum *unsigned* value, then it has all + // bits set. |MinValue| cast to unsigned form is purely the high bit set. + // So the delta is all bits but high set -- exactly |MaxValue|. And as + // |MinValue = -MaxValue - 1|, we have |MaxValue + (-MaxValue - 1)| to + // equal -1. + // + // Thus the delta below is in signed range, the corresponding cast is safe, + // and this computation produces values spanning [MinValue, 0): exactly the + // desired range of all negative signed integers. + return (aValue <= MaxValueUnsigned) + ? static_cast(aValue) + : static_cast(aValue - MinValueUnsigned) + MinValue; + } +}; + +} // namespace detail + +/** + * Convert an unsigned value to signed, if necessary wrapping around. + * + * This is the behavior normal C++ casting will perform in most implementations + * these days -- but this function makes explicit that such conversion is + * happening. + */ +template +inline constexpr typename detail::WrapToSignedHelper::SignedType +WrapToSigned(UnsignedType aValue) { + return detail::WrapToSignedHelper::compute(aValue); +} + +namespace detail { + +template +struct WrappingMultiplyHelper { + private: + using UnsignedT = typename MakeUnsigned::Type; + + MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW + static UnsignedT multiply(UnsignedT aX, UnsignedT aY) { + // |mozilla::WrappingMultiply| isn't constexpr because MSVC warns about + // well- defined unsigned integer overflows that may happen here. + // https://msdn.microsoft.com/en-us/library/4kze989h.aspx And constexpr + // seems to cause the warning to be emitted at |WrappingMultiply| call + // *sites* instead of here, so these #pragmas are ineffective. + // + // https://stackoverflow.com/questions/37658794/integer-constant-overflow-warning-in-constexpr + // + // If/when MSVC fix this bug, we should make these functions constexpr. + + // Begin with |1U| to ensure the overall operation chain is never promoted + // to signed integer operations that might have *signed* integer overflow. + return static_cast(1U * aX * aY); + } + + static T toResult(UnsignedT aX, UnsignedT aY) { + // We could always return WrapToSigned and rely on unsigned conversion + // undoing the wrapping when |T| is unsigned, but this seems clearer. + return IsSigned::value ? WrapToSigned(multiply(aX, aY)) + : multiply(aX, aY); + } + + public: + MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW + static T compute(T aX, T aY) { + return toResult(static_cast(aX), static_cast(aY)); + } +}; + +} // namespace detail + +/** + * Multiply two integers of the same type, and return the result converted to + * that type using wraparound semantics. This function: + * + * 1) makes explicit the desire for and dependence upon wraparound semantics, + * 2) provides wraparound semantics *safely* with no signed integer overflow + * that would have undefined behavior, and + * 3) won't trip up {,un}signed-integer overflow sanitizers (see + * build/autoconf/sanitize.m4) at runtime. + * + * For N-bit unsigned integer types, this is equivalent to multiplying the two + * numbers, then taking the result mod 2**N: + * + * WrappingMultiply(uint32_t(42), uint32_t(17)) is 714 (714 mod 2**32); + * WrappingMultiply(uint8_t(16), uint8_t(24)) is 128 (384 mod 2**8); + * WrappingMultiply(uint16_t(3), uint16_t(32768)) is 32768 (98304 mod 2*16). + * + * Use this function for any unsigned multiplication that can wrap (instead of + * normal C++ multiplication) to play nice with the sanitizers. But it's + * especially important to use it for uint16_t multiplication: in most compilers + * for uint16_t*uint16_t some operand values will trigger signed integer + * overflow with undefined behavior! http://kqueue.org/blog/2013/09/17/cltq/ + * has the grody details. Other than that one weird case, WrappingMultiply on + * unsigned types is the same as C++ multiplication. + * + * For N-bit signed integer types, this is equivalent to multiplying the two + * numbers wrapped to unsigned, taking the product mod 2**N, then wrapping that + * number to the signed range: + * + * WrappingMultiply(int16_t(-456), int16_t(123)) is + * 9448 ((-56088 mod 2**16) + 2**16); + * WrappingMultiply(int32_t(-7), int32_t(-9)) is 63 (63 mod 2**32); + * WrappingMultiply(int8_t(16), int8_t(24)) is -128 ((384 mod 2**8) - 2**8); + * WrappingMultiply(int8_t(16), int8_t(255)) is -16 ((4080 mod 2**8) - 2**8). + * + * There is no ready equivalent to this operation in C++, as applying C++ + * multiplication to signed integer types in ways that trigger overflow has + * undefined behavior. However, it's how multiplication *tends* to behave with + * most compilers in most situations, even though it's emphatically not required + * to do so. + */ +template +inline T WrappingMultiply(T aX, T aY) { + return detail::WrappingMultiplyHelper::compute(aX, aY); +} + +} /* namespace mozilla */ + +#endif /* mozilla_WrappingOperations_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 @@ -61,6 +61,7 @@ /** * Return a pseudo-random 64-bit number. */ + MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW uint64_t next() { /* * The offsetOfState*() methods below are provided so that exceedingly-rare @@ -91,7 +92,7 @@ * to get the mantissa's range. */ static constexpr int kMantissaBits = - mozilla::FloatingPoint::kExponentShift + 1; + mozilla::FloatingPoint::kExponentShift + 1; uint64_t mantissa = next() & ((UINT64_C(1) << kMantissaBits) - 1); return double(mantissa) / (UINT64_C(1) << kMantissaBits); } @@ -115,7 +116,7 @@ } }; -} // namespace non_crypto -} // namespace mozilla +} // namespace non_crypto +} // namespace mozilla -#endif // mozilla_XorShift128Plus_h +#endif // mozilla_XorShift128Plus_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/double-conversion.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/double-conversion.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/double-conversion.h @@ -1,538 +0,0 @@ -// Copyright 2012 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ -#define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ - -#include "mozilla/Types.h" -#include "utils.h" - -namespace double_conversion { - -class DoubleToStringConverter { - public: - // When calling ToFixed with a double > 10^kMaxFixedDigitsBeforePoint - // or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the - // function returns false. - static const int kMaxFixedDigitsBeforePoint = 60; - static const int kMaxFixedDigitsAfterPoint = 60; - - // When calling ToExponential with a requested_digits - // parameter > kMaxExponentialDigits then the function returns false. - static const int kMaxExponentialDigits = 120; - - // When calling ToPrecision with a requested_digits - // parameter < kMinPrecisionDigits or requested_digits > kMaxPrecisionDigits - // then the function returns false. - static const int kMinPrecisionDigits = 1; - static const int kMaxPrecisionDigits = 120; - - enum Flags { - NO_FLAGS = 0, - EMIT_POSITIVE_EXPONENT_SIGN = 1, - EMIT_TRAILING_DECIMAL_POINT = 2, - EMIT_TRAILING_ZERO_AFTER_POINT = 4, - UNIQUE_ZERO = 8 - }; - - // Flags should be a bit-or combination of the possible Flags-enum. - // - NO_FLAGS: no special flags. - // - EMIT_POSITIVE_EXPONENT_SIGN: when the number is converted into exponent - // form, emits a '+' for positive exponents. Example: 1.2e+2. - // - EMIT_TRAILING_DECIMAL_POINT: when the input number is an integer and is - // converted into decimal format then a trailing decimal point is appended. - // Example: 2345.0 is converted to "2345.". - // - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point - // emits a trailing '0'-character. This flag requires the - // EXMIT_TRAILING_DECIMAL_POINT flag. - // Example: 2345.0 is converted to "2345.0". - // - UNIQUE_ZERO: "-0.0" is converted to "0.0". - // - // Infinity symbol and nan_symbol provide the string representation for these - // special values. If the string is NULL and the special value is encountered - // then the conversion functions return false. - // - // The exponent_character is used in exponential representations. It is - // usually 'e' or 'E'. - // - // When converting to the shortest representation the converter will - // represent input numbers in decimal format if they are in the interval - // [10^decimal_in_shortest_low; 10^decimal_in_shortest_high[ - // (lower boundary included, greater boundary excluded). - // Example: with decimal_in_shortest_low = -6 and - // decimal_in_shortest_high = 21: - // ToShortest(0.000001) -> "0.000001" - // ToShortest(0.0000001) -> "1e-7" - // ToShortest(111111111111111111111.0) -> "111111111111111110000" - // ToShortest(100000000000000000000.0) -> "100000000000000000000" - // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21" - // - // When converting to precision mode the converter may add - // max_leading_padding_zeroes before returning the number in exponential - // format. - // Example with max_leading_padding_zeroes_in_precision_mode = 6. - // ToPrecision(0.0000012345, 2) -> "0.0000012" - // ToPrecision(0.00000012345, 2) -> "1.2e-7" - // Similarily the converter may add up to - // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid - // returning an exponential representation. A zero added by the - // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit. - // Examples for max_trailing_padding_zeroes_in_precision_mode = 1: - // ToPrecision(230.0, 2) -> "230" - // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT. - // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT. - DoubleToStringConverter(int flags, - const char* infinity_symbol, - const char* nan_symbol, - char exponent_character, - int decimal_in_shortest_low, - int decimal_in_shortest_high, - int max_leading_padding_zeroes_in_precision_mode, - int max_trailing_padding_zeroes_in_precision_mode) - : flags_(flags), - infinity_symbol_(infinity_symbol), - nan_symbol_(nan_symbol), - exponent_character_(exponent_character), - decimal_in_shortest_low_(decimal_in_shortest_low), - decimal_in_shortest_high_(decimal_in_shortest_high), - max_leading_padding_zeroes_in_precision_mode_( - max_leading_padding_zeroes_in_precision_mode), - max_trailing_padding_zeroes_in_precision_mode_( - max_trailing_padding_zeroes_in_precision_mode) { - // When 'trailing zero after the point' is set, then 'trailing point' - // must be set too. - ASSERT(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) || - !((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0)); - } - - // Returns a converter following the EcmaScript specification. - static MFBT_API const DoubleToStringConverter& EcmaScriptConverter(); - - // Computes the shortest string of digits that correctly represent the input - // number. Depending on decimal_in_shortest_low and decimal_in_shortest_high - // (see constructor) it then either returns a decimal representation, or an - // exponential representation. - // Example with decimal_in_shortest_low = -6, - // decimal_in_shortest_high = 21, - // EMIT_POSITIVE_EXPONENT_SIGN activated, and - // EMIT_TRAILING_DECIMAL_POINT deactived: - // ToShortest(0.000001) -> "0.000001" - // ToShortest(0.0000001) -> "1e-7" - // ToShortest(111111111111111111111.0) -> "111111111111111110000" - // ToShortest(100000000000000000000.0) -> "100000000000000000000" - // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21" - // - // Note: the conversion may round the output if the returned string - // is accurate enough to uniquely identify the input-number. - // For example the most precise representation of the double 9e59 equals - // "899999999999999918767229449717619953810131273674690656206848", but - // the converter will return the shorter (but still correct) "9e59". - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except when the input value is special and no infinity_symbol or - // nan_symbol has been given to the constructor. - bool ToShortest(double value, StringBuilder* result_builder) const { - return ToShortestIeeeNumber(value, result_builder, SHORTEST); - } - - // Same as ToShortest, but for single-precision floats. - bool ToShortestSingle(float value, StringBuilder* result_builder) const { - return ToShortestIeeeNumber(value, result_builder, SHORTEST_SINGLE); - } - - - // Computes a decimal representation with a fixed number of digits after the - // decimal point. The last emitted digit is rounded. - // - // Examples: - // ToFixed(3.12, 1) -> "3.1" - // ToFixed(3.1415, 3) -> "3.142" - // ToFixed(1234.56789, 4) -> "1234.5679" - // ToFixed(1.23, 5) -> "1.23000" - // ToFixed(0.1, 4) -> "0.1000" - // ToFixed(1e30, 2) -> "1000000000000000019884624838656.00" - // ToFixed(0.1, 30) -> "0.100000000000000005551115123126" - // ToFixed(0.1, 17) -> "0.10000000000000001" - // - // If requested_digits equals 0, then the tail of the result depends on - // the EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT. - // Examples, for requested_digits == 0, - // let EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT be - // - false and false: then 123.45 -> 123 - // 0.678 -> 1 - // - true and false: then 123.45 -> 123. - // 0.678 -> 1. - // - true and true: then 123.45 -> 123.0 - // 0.678 -> 1.0 - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except for the following cases: - // - the input value is special and no infinity_symbol or nan_symbol has - // been provided to the constructor, - // - 'value' > 10^kMaxFixedDigitsBeforePoint, or - // - 'requested_digits' > kMaxFixedDigitsAfterPoint. - // The last two conditions imply that the result will never contain more than - // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters - // (one additional character for the sign, and one for the decimal point). - MFBT_API bool ToFixed(double value, - int requested_digits, - StringBuilder* result_builder) const; - - // Computes a representation in exponential format with requested_digits - // after the decimal point. The last emitted digit is rounded. - // If requested_digits equals -1, then the shortest exponential representation - // is computed. - // - // Examples with EMIT_POSITIVE_EXPONENT_SIGN deactivated, and - // exponent_character set to 'e'. - // ToExponential(3.12, 1) -> "3.1e0" - // ToExponential(5.0, 3) -> "5.000e0" - // ToExponential(0.001, 2) -> "1.00e-3" - // ToExponential(3.1415, -1) -> "3.1415e0" - // ToExponential(3.1415, 4) -> "3.1415e0" - // ToExponential(3.1415, 3) -> "3.142e0" - // ToExponential(123456789000000, 3) -> "1.235e14" - // ToExponential(1000000000000000019884624838656.0, -1) -> "1e30" - // ToExponential(1000000000000000019884624838656.0, 32) -> - // "1.00000000000000001988462483865600e30" - // ToExponential(1234, 0) -> "1e3" - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except for the following cases: - // - the input value is special and no infinity_symbol or nan_symbol has - // been provided to the constructor, - // - 'requested_digits' > kMaxExponentialDigits. - // The last condition implies that the result will never contain more than - // kMaxExponentialDigits + 8 characters (the sign, the digit before the - // decimal point, the decimal point, the exponent character, the - // exponent's sign, and at most 3 exponent digits). - MFBT_API bool ToExponential(double value, - int requested_digits, - StringBuilder* result_builder) const; - - // Computes 'precision' leading digits of the given 'value' and returns them - // either in exponential or decimal format, depending on - // max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the - // constructor). - // The last computed digit is rounded. - // - // Example with max_leading_padding_zeroes_in_precision_mode = 6. - // ToPrecision(0.0000012345, 2) -> "0.0000012" - // ToPrecision(0.00000012345, 2) -> "1.2e-7" - // Similarily the converter may add up to - // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid - // returning an exponential representation. A zero added by the - // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit. - // Examples for max_trailing_padding_zeroes_in_precision_mode = 1: - // ToPrecision(230.0, 2) -> "230" - // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT. - // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT. - // Examples for max_trailing_padding_zeroes_in_precision_mode = 3, and no - // EMIT_TRAILING_ZERO_AFTER_POINT: - // ToPrecision(123450.0, 6) -> "123450" - // ToPrecision(123450.0, 5) -> "123450" - // ToPrecision(123450.0, 4) -> "123500" - // ToPrecision(123450.0, 3) -> "123000" - // ToPrecision(123450.0, 2) -> "1.2e5" - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except for the following cases: - // - the input value is special and no infinity_symbol or nan_symbol has - // been provided to the constructor, - // - precision < kMinPericisionDigits - // - precision > kMaxPrecisionDigits - // The last condition implies that the result will never contain more than - // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the - // exponent character, the exponent's sign, and at most 3 exponent digits). - MFBT_API bool ToPrecision(double value, - int precision, - bool* used_exponential_notation, - StringBuilder* result_builder) const; - - enum DtoaMode { - // Produce the shortest correct representation. - // For example the output of 0.299999999999999988897 is (the less accurate - // but correct) 0.3. - SHORTEST, - // Same as SHORTEST, but for single-precision floats. - SHORTEST_SINGLE, - // Produce a fixed number of digits after the decimal point. - // For instance fixed(0.1, 4) becomes 0.1000 - // If the input number is big, the output will be big. - FIXED, - // Fixed number of digits (independent of the decimal point). - PRECISION - }; - - // The maximal number of digits that are needed to emit a double in base 10. - // A higher precision can be achieved by using more digits, but the shortest - // accurate representation of any double will never use more digits than - // kBase10MaximalLength. - // Note that DoubleToAscii null-terminates its input. So the given buffer - // should be at least kBase10MaximalLength + 1 characters long. - static const MFBT_DATA int kBase10MaximalLength = 17; - - // Converts the given double 'v' to ascii. 'v' must not be NaN, +Infinity, or - // -Infinity. In SHORTEST_SINGLE-mode this restriction also applies to 'v' - // after it has been casted to a single-precision float. That is, in this - // mode static_cast(v) must not be NaN, +Infinity or -Infinity. - // - // The result should be interpreted as buffer * 10^(point-length). - // - // The output depends on the given mode: - // - SHORTEST: produce the least amount of digits for which the internal - // identity requirement is still satisfied. If the digits are printed - // (together with the correct exponent) then reading this number will give - // 'v' again. The buffer will choose the representation that is closest to - // 'v'. If there are two at the same distance, than the one farther away - // from 0 is chosen (halfway cases - ending with 5 - are rounded up). - // In this mode the 'requested_digits' parameter is ignored. - // - SHORTEST_SINGLE: same as SHORTEST but with single-precision. - // - FIXED: produces digits necessary to print a given number with - // 'requested_digits' digits after the decimal point. The produced digits - // might be too short in which case the caller has to fill the remainder - // with '0's. - // Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2. - // Halfway cases are rounded towards +/-Infinity (away from 0). The call - // toFixed(0.15, 2) thus returns buffer="2", point=0. - // The returned buffer may contain digits that would be truncated from the - // shortest representation of the input. - // - PRECISION: produces 'requested_digits' where the first digit is not '0'. - // Even though the length of produced digits usually equals - // 'requested_digits', the function is allowed to return fewer digits, in - // which case the caller has to fill the missing digits with '0's. - // Halfway cases are again rounded away from 0. - // DoubleToAscii expects the given buffer to be big enough to hold all - // digits and a terminating null-character. In SHORTEST-mode it expects a - // buffer of at least kBase10MaximalLength + 1. In all other modes the - // requested_digits parameter and the padding-zeroes limit the size of the - // output. Don't forget the decimal point, the exponent character and the - // terminating null-character when computing the maximal output size. - // The given length is only used in debug mode to ensure the buffer is big - // enough. - static MFBT_API void DoubleToAscii(double v, - DtoaMode mode, - int requested_digits, - char* buffer, - int buffer_length, - bool* sign, - int* length, - int* point); - - private: - // Implementation for ToShortest and ToShortestSingle. - MFBT_API bool ToShortestIeeeNumber(double value, - StringBuilder* result_builder, - DtoaMode mode) const; - - // If the value is a special value (NaN or Infinity) constructs the - // corresponding string using the configured infinity/nan-symbol. - // If either of them is NULL or the value is not special then the - // function returns false. - MFBT_API bool HandleSpecialValues(double value, StringBuilder* result_builder) const; - // Constructs an exponential representation (i.e. 1.234e56). - // The given exponent assumes a decimal point after the first decimal digit. - MFBT_API void CreateExponentialRepresentation(const char* decimal_digits, - int length, - int exponent, - StringBuilder* result_builder) const; - // Creates a decimal representation (i.e 1234.5678). - MFBT_API void CreateDecimalRepresentation(const char* decimal_digits, - int length, - int decimal_point, - int digits_after_point, - StringBuilder* result_builder) const; - - const int flags_; - const char* const infinity_symbol_; - const char* const nan_symbol_; - const char exponent_character_; - const int decimal_in_shortest_low_; - const int decimal_in_shortest_high_; - const int max_leading_padding_zeroes_in_precision_mode_; - const int max_trailing_padding_zeroes_in_precision_mode_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter); -}; - - -class StringToDoubleConverter { - public: - // Enumeration for allowing octals and ignoring junk when converting - // strings to numbers. - enum Flags { - NO_FLAGS = 0, - ALLOW_HEX = 1, - ALLOW_OCTALS = 2, - ALLOW_TRAILING_JUNK = 4, - ALLOW_LEADING_SPACES = 8, - ALLOW_TRAILING_SPACES = 16, - ALLOW_SPACES_AFTER_SIGN = 32 - }; - - // Flags should be a bit-or combination of the possible Flags-enum. - // - NO_FLAGS: no special flags. - // - ALLOW_HEX: recognizes the prefix "0x". Hex numbers may only be integers. - // Ex: StringToDouble("0x1234") -> 4660.0 - // In StringToDouble("0x1234.56") the characters ".56" are trailing - // junk. The result of the call is hence dependent on - // the ALLOW_TRAILING_JUNK flag and/or the junk value. - // With this flag "0x" is a junk-string. Even with ALLOW_TRAILING_JUNK, - // the string will not be parsed as "0" followed by junk. - // - // - ALLOW_OCTALS: recognizes the prefix "0" for octals: - // If a sequence of octal digits starts with '0', then the number is - // read as octal integer. Octal numbers may only be integers. - // Ex: StringToDouble("01234") -> 668.0 - // StringToDouble("012349") -> 12349.0 // Not a sequence of octal - // // digits. - // In StringToDouble("01234.56") the characters ".56" are trailing - // junk. The result of the call is hence dependent on - // the ALLOW_TRAILING_JUNK flag and/or the junk value. - // In StringToDouble("01234e56") the characters "e56" are trailing - // junk, too. - // - ALLOW_TRAILING_JUNK: ignore trailing characters that are not part of - // a double literal. - // - ALLOW_LEADING_SPACES: skip over leading spaces. - // - ALLOW_TRAILING_SPACES: ignore trailing spaces. - // - ALLOW_SPACES_AFTER_SIGN: ignore spaces after the sign. - // Ex: StringToDouble("- 123.2") -> -123.2. - // StringToDouble("+ 123.2") -> 123.2 - // - // empty_string_value is returned when an empty string is given as input. - // If ALLOW_LEADING_SPACES or ALLOW_TRAILING_SPACES are set, then a string - // containing only spaces is converted to the 'empty_string_value', too. - // - // junk_string_value is returned when - // a) ALLOW_TRAILING_JUNK is not set, and a junk character (a character not - // part of a double-literal) is found. - // b) ALLOW_TRAILING_JUNK is set, but the string does not start with a - // double literal. - // - // infinity_symbol and nan_symbol are strings that are used to detect - // inputs that represent infinity and NaN. They can be null, in which case - // they are ignored. - // The conversion routine first reads any possible signs. Then it compares the - // following character of the input-string with the first character of - // the infinity, and nan-symbol. If either matches, the function assumes, that - // a match has been found, and expects the following input characters to match - // the remaining characters of the special-value symbol. - // This means that the following restrictions apply to special-value symbols: - // - they must not start with signs ('+', or '-'), - // - they must not have the same first character. - // - they must not start with digits. - // - // Examples: - // flags = ALLOW_HEX | ALLOW_TRAILING_JUNK, - // empty_string_value = 0.0, - // junk_string_value = NaN, - // infinity_symbol = "infinity", - // nan_symbol = "nan": - // StringToDouble("0x1234") -> 4660.0. - // StringToDouble("0x1234K") -> 4660.0. - // StringToDouble("") -> 0.0 // empty_string_value. - // StringToDouble(" ") -> NaN // junk_string_value. - // StringToDouble(" 1") -> NaN // junk_string_value. - // StringToDouble("0x") -> NaN // junk_string_value. - // StringToDouble("-123.45") -> -123.45. - // StringToDouble("--123.45") -> NaN // junk_string_value. - // StringToDouble("123e45") -> 123e45. - // StringToDouble("123E45") -> 123e45. - // StringToDouble("123e+45") -> 123e45. - // StringToDouble("123E-45") -> 123e-45. - // StringToDouble("123e") -> 123.0 // trailing junk ignored. - // StringToDouble("123e-") -> 123.0 // trailing junk ignored. - // StringToDouble("+NaN") -> NaN // NaN string literal. - // StringToDouble("-infinity") -> -inf. // infinity literal. - // StringToDouble("Infinity") -> NaN // junk_string_value. - // - // flags = ALLOW_OCTAL | ALLOW_LEADING_SPACES, - // empty_string_value = 0.0, - // junk_string_value = NaN, - // infinity_symbol = NULL, - // nan_symbol = NULL: - // StringToDouble("0x1234") -> NaN // junk_string_value. - // StringToDouble("01234") -> 668.0. - // StringToDouble("") -> 0.0 // empty_string_value. - // StringToDouble(" ") -> 0.0 // empty_string_value. - // StringToDouble(" 1") -> 1.0 - // StringToDouble("0x") -> NaN // junk_string_value. - // StringToDouble("0123e45") -> NaN // junk_string_value. - // StringToDouble("01239E45") -> 1239e45. - // StringToDouble("-infinity") -> NaN // junk_string_value. - // StringToDouble("NaN") -> NaN // junk_string_value. - StringToDoubleConverter(int flags, - double empty_string_value, - double junk_string_value, - const char* infinity_symbol, - const char* nan_symbol) - : flags_(flags), - empty_string_value_(empty_string_value), - junk_string_value_(junk_string_value), - infinity_symbol_(infinity_symbol), - nan_symbol_(nan_symbol) { - } - - // Performs the conversion. - // The output parameter 'processed_characters_count' is set to the number - // of characters that have been processed to read the number. - // Spaces than are processed with ALLOW_{LEADING|TRAILING}_SPACES are included - // in the 'processed_characters_count'. Trailing junk is never included. - double StringToDouble(const char* buffer, - int length, - int* processed_characters_count) const { - return StringToIeee(buffer, length, processed_characters_count, true); - } - - // Same as StringToDouble but reads a float. - // Note that this is not equivalent to static_cast(StringToDouble(...)) - // due to potential double-rounding. - float StringToFloat(const char* buffer, - int length, - int* processed_characters_count) const { - return static_cast(StringToIeee(buffer, length, - processed_characters_count, false)); - } - - private: - const int flags_; - const double empty_string_value_; - const double junk_string_value_; - const char* const infinity_symbol_; - const char* const nan_symbol_; - - double StringToIeee(const char* buffer, - int length, - int* processed_characters_count, - bool read_as_double) const; - - DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter); -}; - -} // namespace double_conversion - -#endif // DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/fallible.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/fallible.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/fallible.h @@ -48,21 +48,17 @@ * } * */ + +#include + namespace mozilla { -struct fallible_t { }; +using fallible_t = std::nothrow_t; -/* This symbol is kept unexported, such that in corner cases where the - * compiler can't remove its use (essentially, cross compilation-unit - * calls), the smallest machine code is used. - * Depending how the linker packs symbols, it will consume between 1 and - * 8 bytes of read-only data in each executable or shared library, but - * only in those where it's actually not optimized out by the compiler. - */ -extern const fallible_t fallible; +static const fallible_t& fallible = std::nothrow; -} // namespace mozilla +} // namespace mozilla #endif -#endif // mozilla_fallible_h +#endif // mozilla_fallible_h 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 @@ -13,16 +13,14 @@ */ #if defined(__cplusplus) -# include +#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 +#include #else -# include -# include +#include #endif #if defined(__cplusplus) @@ -33,27 +31,7 @@ #include "mozilla/Attributes.h" #include "mozilla/Types.h" -#define MOZALLOC_HAVE_XMALLOC - -#if defined(MOZ_ALWAYS_INLINE_EVEN_DEBUG) -# define MOZALLOC_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG -#elif defined(HAVE_FORCEINLINE) -# define MOZALLOC_INLINE __forceinline -#else -# define MOZALLOC_INLINE inline -#endif - -/* Workaround build problem with Sun Studio 12 */ -#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# undef MOZ_MUST_USE -# define MOZ_MUST_USE -# undef MOZ_ALLOCATOR -# define MOZ_ALLOCATOR -#endif - -#if defined(__cplusplus) -extern "C" { -#endif /* ifdef __cplusplus */ +MOZ_BEGIN_EXTERN_C /* * We need to use malloc_impl and free_impl in this file when they are @@ -82,53 +60,31 @@ * passing that pointer to |free()|. */ -MFBT_API void* moz_xmalloc(size_t size) - MOZ_ALLOCATOR; +MFBT_API void* moz_xmalloc(size_t size) MOZ_ALLOCATOR; -MFBT_API void* moz_xcalloc(size_t nmemb, size_t size) - MOZ_ALLOCATOR; +MFBT_API void* moz_xcalloc(size_t nmemb, size_t size) MOZ_ALLOCATOR; -MFBT_API void* moz_xrealloc(void* ptr, size_t size) - MOZ_ALLOCATOR; +MFBT_API void* moz_xrealloc(void* ptr, size_t size) MOZ_ALLOCATOR; -MFBT_API char* moz_xstrdup(const char* str) - MOZ_ALLOCATOR; +MFBT_API char* moz_xstrdup(const char* str) MOZ_ALLOCATOR; -MFBT_API size_t moz_malloc_usable_size(void *ptr); +MFBT_API size_t moz_malloc_usable_size(void* ptr); -MFBT_API size_t moz_malloc_size_of(const void *ptr); +MFBT_API size_t moz_malloc_size_of(const void* ptr); + +/* + * Like moz_malloc_size_of(), but works reliably with interior pointers, i.e. + * pointers into the middle of a live allocation. + */ +MFBT_API size_t moz_malloc_enclosing_size_of(const void* ptr); #if defined(HAVE_STRNDUP) -MFBT_API char* moz_xstrndup(const char* str, size_t strsize) - MOZ_ALLOCATOR; +MFBT_API char* moz_xstrndup(const char* str, size_t strsize) MOZ_ALLOCATOR; #endif /* if defined(HAVE_STRNDUP) */ +MFBT_API void* moz_xmemalign(size_t boundary, size_t size) MOZ_ALLOCATOR; -#if defined(HAVE_POSIX_MEMALIGN) -MFBT_API MOZ_MUST_USE -int moz_xposix_memalign(void **ptr, size_t alignment, size_t size); - -MFBT_API MOZ_MUST_USE -int moz_posix_memalign(void **ptr, size_t alignment, size_t size); -#endif /* if defined(HAVE_POSIX_MEMALIGN) */ - - -#if defined(HAVE_MEMALIGN) -MFBT_API void* moz_xmemalign(size_t boundary, size_t size) - MOZ_ALLOCATOR; -#endif /* if defined(HAVE_MEMALIGN) */ - - -#if defined(HAVE_VALLOC) -MFBT_API void* moz_xvalloc(size_t size) - MOZ_ALLOCATOR; -#endif /* if defined(HAVE_VALLOC) */ - - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* ifdef __cplusplus */ - +MOZ_END_EXTERN_C #ifdef __cplusplus @@ -142,42 +98,41 @@ * that can be delete'd by any of * * (1) the matching infallible operator delete immediately below - * (2) the matching "fallible" operator delete further below - * (3) the matching system |operator delete(void*, std::nothrow)| - * (4) the matching system |operator delete(void*) throw(std::bad_alloc)| + * (2) the matching system |operator delete(void*, std::nothrow)| + * (3) the matching system |operator delete(void*) throw(std::bad_alloc)| * * NB: these are declared |throw(std::bad_alloc)|, though they will never * throw that exception. This declaration is consistent with the rule * that |::operator new() throw(std::bad_alloc)| will never return NULL. + * + * NB: mozilla::fallible can be used instead of std::nothrow. */ /* NB: This is defined just to silence vacuous warnings about symbol * visibility on OS X/gcc. These symbols are force-inline and not * exported. */ #if defined(XP_MACOSX) -# define MOZALLOC_EXPORT_NEW MFBT_API +#define MOZALLOC_EXPORT_NEW MFBT_API #else -# define MOZALLOC_EXPORT_NEW +#define MOZALLOC_EXPORT_NEW #endif -#if defined(ANDROID) -/* - * It's important to always specify 'throw()' in GCC because it's used to tell - * GCC that 'new' may return null. That makes GCC null-check the result before - * potentially initializing the memory to zero. - * Also, the Android minimalistic headers don't include std::bad_alloc. - */ -#define MOZALLOC_THROW_IF_HAS_EXCEPTIONS throw() -#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS -#elif defined(_MSC_VER) +#if defined(_MSC_VER) /* * Suppress build warning spam (bug 578546). */ +#if _MSC_VER < 1912 #define MOZALLOC_THROW_IF_HAS_EXCEPTIONS -#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS #else #define MOZALLOC_THROW_IF_HAS_EXCEPTIONS throw() -#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS throw(std::bad_alloc) +#endif +#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS +#else +/* + * C++11 has deprecated exception-specifications in favour of |noexcept|. + */ +#define MOZALLOC_THROW_IF_HAS_EXCEPTIONS noexcept(true) +#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS noexcept(false) #endif #define MOZALLOC_THROW_BAD_ALLOC MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS @@ -187,167 +142,99 @@ /* gcc's asan somehow doesn't like always_inline on this function. */ __attribute__((gnu_inline)) inline #else -MOZALLOC_INLINE +MOZ_ALWAYS_INLINE_EVEN_DEBUG #endif -void* operator new(size_t size) MOZALLOC_THROW_BAD_ALLOC -{ - return moz_xmalloc(size); + void* + operator new(size_t size) MOZALLOC_THROW_BAD_ALLOC { + return moz_xmalloc(size); } -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void* operator new(size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return malloc_impl(size); +MOZALLOC_EXPORT_NEW MOZ_ALWAYS_INLINE_EVEN_DEBUG void* operator new( + size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS { + return malloc_impl(size); } -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void* operator new[](size_t size) MOZALLOC_THROW_BAD_ALLOC -{ - return moz_xmalloc(size); +MOZALLOC_EXPORT_NEW MOZ_ALWAYS_INLINE_EVEN_DEBUG void* operator new[]( + size_t size) MOZALLOC_THROW_BAD_ALLOC { + return moz_xmalloc(size); } -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void* operator new[](size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return malloc_impl(size); +MOZALLOC_EXPORT_NEW MOZ_ALWAYS_INLINE_EVEN_DEBUG void* operator new[]( + size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS { + return malloc_impl(size); } -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void operator delete(void* ptr) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return free_impl(ptr); +MOZALLOC_EXPORT_NEW MOZ_ALWAYS_INLINE_EVEN_DEBUG void operator delete(void* ptr) + MOZALLOC_THROW_IF_HAS_EXCEPTIONS { + return free_impl(ptr); } -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void operator delete(void* ptr, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return free_impl(ptr); +MOZALLOC_EXPORT_NEW MOZ_ALWAYS_INLINE_EVEN_DEBUG void operator delete( + void* ptr, const std::nothrow_t&)MOZALLOC_THROW_IF_HAS_EXCEPTIONS { + return free_impl(ptr); } -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void operator delete[](void* ptr) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return free_impl(ptr); +MOZALLOC_EXPORT_NEW MOZ_ALWAYS_INLINE_EVEN_DEBUG void operator delete[]( + void* ptr) MOZALLOC_THROW_IF_HAS_EXCEPTIONS { + return free_impl(ptr); } -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void operator delete[](void* ptr, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return free_impl(ptr); +MOZALLOC_EXPORT_NEW MOZ_ALWAYS_INLINE_EVEN_DEBUG void operator delete[]( + void* ptr, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS { + return free_impl(ptr); } - -/* - * We also add a new allocator variant: "fallible operator new." - * Unlike libmozalloc's implementations of the standard nofail - * allocators, this allocator is allowed to return NULL. It can be used - * as follows - * - * Foo* f = new (mozilla::fallible) Foo(...); - * - * operator delete(fallible) is defined for completeness only. - * - * Each operator new below returns a pointer to memory that can be - * delete'd by any of - * - * (1) the matching "fallible" operator delete below - * (2) the matching infallible operator delete above - * (3) the matching system |operator delete(void*, std::nothrow)| - * (4) the matching system |operator delete(void*) throw(std::bad_alloc)| - */ - -MOZALLOC_INLINE -void* operator new(size_t size, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return malloc_impl(size); -} - -MOZALLOC_INLINE -void* operator new[](size_t size, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return malloc_impl(size); -} - -MOZALLOC_INLINE -void operator delete(void* ptr, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - free_impl(ptr); -} - -MOZALLOC_INLINE -void operator delete[](void* ptr, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - free_impl(ptr); -} - - /* * This policy is identical to MallocAllocPolicy, except it uses * moz_xmalloc/moz_xcalloc/moz_xrealloc instead of * malloc/calloc/realloc. */ -class InfallibleAllocPolicy -{ -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); +class InfallibleAllocPolicy { + 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) { + reportAllocOverflow(); + } + return static_cast(moz_xmalloc(aNumElems * sizeof(T))); + } + + template + T* pod_calloc(size_t aNumElems) { + return static_cast(moz_xcalloc(aNumElems, sizeof(T))); + } + + template + T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { + if (aNewSize & mozilla::tl::MulOverflowMask::value) { + reportAllocOverflow(); } + return static_cast(moz_xrealloc(aPtr, aNewSize * sizeof(T))); + } - template - T* pod_malloc(size_t aNumElems) - { - if (aNumElems & mozilla::tl::MulOverflowMask::value) { - reportAllocOverflow(); - } - return static_cast(moz_xmalloc(aNumElems * sizeof(T))); - } + void free_(void* aPtr) { free_impl(aPtr); } - template - T* pod_calloc(size_t aNumElems) - { - return static_cast(moz_xcalloc(aNumElems, sizeof(T))); - } + void reportAllocOverflow() const { mozalloc_abort("alloc overflow"); } - template - T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) - { - if (aNewSize & mozilla::tl::MulOverflowMask::value) { - reportAllocOverflow(); - } - return static_cast(moz_xrealloc(aPtr, aNewSize * sizeof(T))); - } - - void free_(void* aPtr) - { - free_impl(aPtr); - } - - void reportAllocOverflow() const - { - mozalloc_abort("alloc overflow"); - } - - bool checkSimulatedOOM() const - { - return true; - } + bool checkSimulatedOOM() const { return true; } }; -#endif /* ifdef __cplusplus */ +#endif /* ifdef __cplusplus */ #ifdef malloc_impl_ #undef malloc_impl_ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/mozalloc_abort.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/mozalloc_abort.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/mozalloc_abort.h @@ -18,11 +18,11 @@ * Note: MOZ_NORETURN seems to break crash stacks on ARM, so we don't * use that annotation there. */ -MFBT_API +extern "C" MFBT_API #if !defined(__arm__) - MOZ_NORETURN + MOZ_NORETURN #endif - void mozalloc_abort(const char* const msg); + void + mozalloc_abort(const char* const msg); - -#endif /* ifndef mozilla_mozalloc_abort_h */ +#endif /* ifndef mozilla_mozalloc_abort_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/mozalloc_oom.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/mozalloc_oom.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/mozalloc_oom.h @@ -22,10 +22,10 @@ * the size of the allocation on which we aborted. */ typedef void (*mozalloc_oom_abort_handler)(size_t size); -MFBT_API void mozalloc_set_oom_abort_handler(mozalloc_oom_abort_handler handler); +MFBT_API void mozalloc_set_oom_abort_handler( + mozalloc_oom_abort_handler handler); /* TODO: functions to query system memory usage and register * critical-memory handlers. */ - #endif /* ifndef mozilla_mozalloc_oom_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/unused.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/unused.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/unused.h @@ -7,6 +7,7 @@ #ifndef mozilla_unused_h #define mozilla_unused_h +#include "mozilla/Attributes.h" #include "mozilla/Types.h" #ifdef __cplusplus @@ -17,22 +18,24 @@ // Suppress GCC warnings about unused return values with // Unused << SomeFuncDeclaredWarnUnusedReturnValue(); // -struct unused_t -{ - template - inline void - operator<<(const T& /*unused*/) const {} +struct unused_t { + template + MOZ_ALWAYS_INLINE_EVEN_DEBUG void operator<<(const T& /*unused*/) const {} }; extern MFBT_DATA const unused_t Unused; -} // namespace mozilla +} // namespace mozilla -#endif // __cplusplus +#endif // __cplusplus // An alternative to mozilla::Unused for use in (a) C code and (b) code where // linking with unused.o is difficult. #define MOZ_UNUSED(expr) \ - do { if (expr) { (void)0; } } while (0) + do { \ + if (expr) { \ + (void)0; \ + } \ + } while (0) -#endif // mozilla_unused_h +#endif // mozilla_unused_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/utils.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/utils.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozilla/utils.h @@ -1,298 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DOUBLE_CONVERSION_UTILS_H_ -#define DOUBLE_CONVERSION_UTILS_H_ - -#include -#include - -#include "mozilla/Assertions.h" -#ifndef ASSERT -#define ASSERT(condition) MOZ_ASSERT(condition) -#endif -#ifndef UNIMPLEMENTED -#define UNIMPLEMENTED() MOZ_CRASH() -#endif -#ifndef UNREACHABLE -#define UNREACHABLE() MOZ_CRASH() -#endif - -// Double operations detection based on target architecture. -// Linux uses a 80bit wide floating point stack on x86. This induces double -// rounding, which in turn leads to wrong results. -// An easy way to test if the floating-point operations are correct is to -// evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then -// the result is equal to 89255e-22. -// The best way to test this, is to create a division-function and to compare -// the output of the division with the expected result. (Inlining must be -// disabled.) -// On Linux,x86 89255e-22 != Div_double(89255.0/1e22) -#if defined(_M_X64) || defined(__x86_64__) || \ - defined(__ARMEL__) || defined(__avr32__) || \ - defined(__hppa__) || defined(__ia64__) || \ - defined(__mips__) || \ - defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \ - defined(__sparc__) || defined(__sparc) || defined(__s390__) || \ - defined(__SH4__) || defined(__alpha__) || \ - defined(_MIPS_ARCH_MIPS32R2) || \ - defined(__AARCH64EL__) || defined(__aarch64__) -#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 -#elif defined(_M_IX86) || defined(__i386__) || defined(__i386) -#if defined(_WIN32) -// Windows uses a 64bit wide floating point stack. -#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 -#else -#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS -#endif // _WIN32 -#else -#error Target architecture was not detected as supported by Double-Conversion. -#endif - - -#include - -// The following macro works on both 32 and 64-bit platforms. -// Usage: instead of writing 0x1234567890123456 -// write UINT64_2PART_C(0x12345678,90123456); -#define UINT64_2PART_C(a, b) (((static_cast(a) << 32) + 0x##b##u)) - - -// The expression ARRAY_SIZE(a) is a compile-time constant of type -// size_t which represents the number of elements of the given -// array. You should only use ARRAY_SIZE on statically allocated -// arrays. -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) \ - ((sizeof(a) / sizeof(*(a))) / \ - static_cast(!(sizeof(a) % sizeof(*(a))))) -#endif - -// A macro to disallow the evil copy constructor and operator= functions -// This should be used in the private: declarations for a class -#ifndef DISALLOW_COPY_AND_ASSIGN -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) -#endif - -// A macro to disallow all the implicit constructors, namely the -// default constructor, copy constructor and operator= functions. -// -// This should be used in the private: declarations for a class -// that wants to prevent anyone from instantiating it. This is -// especially useful for classes containing only static methods. -#ifndef DISALLOW_IMPLICIT_CONSTRUCTORS -#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ - TypeName(); \ - DISALLOW_COPY_AND_ASSIGN(TypeName) -#endif - -namespace double_conversion { - -static const int kCharSize = sizeof(char); - -// Returns the maximum of the two parameters. -template -static T Max(T a, T b) { - return a < b ? b : a; -} - - -// Returns the minimum of the two parameters. -template -static T Min(T a, T b) { - return a < b ? a : b; -} - - -inline int StrLength(const char* string) { - size_t length = strlen(string); - ASSERT(length == static_cast(static_cast(length))); - return static_cast(length); -} - -// This is a simplified version of V8's Vector class. -template -class Vector { - public: - Vector() : start_(NULL), length_(0) {} - Vector(T* data, int len) : start_(data), length_(len) { - ASSERT(len == 0 || (len > 0 && data != NULL)); - } - - // Returns a vector using the same backing storage as this one, - // spanning from and including 'from', to but not including 'to'. - Vector SubVector(int from, int to) { - ASSERT(to <= length_); - ASSERT(from < to); - ASSERT(0 <= from); - return Vector(start() + from, to - from); - } - - // Returns the length of the vector. - int length() const { return length_; } - - // Returns whether or not the vector is empty. - bool is_empty() const { return length_ == 0; } - - // Returns the pointer to the start of the data in the vector. - T* start() const { return start_; } - - // Access individual vector elements - checks bounds in debug mode. - T& operator[](int index) const { - ASSERT(0 <= index && index < length_); - return start_[index]; - } - - T& first() { return start_[0]; } - - T& last() { return start_[length_ - 1]; } - - private: - T* start_; - int length_; -}; - - -// Helper class for building result strings in a character buffer. The -// purpose of the class is to use safe operations that checks the -// buffer bounds on all operations in debug mode. -class StringBuilder { - public: - StringBuilder(char* buffer, int buffer_size) - : buffer_(buffer, buffer_size), position_(0) { } - - ~StringBuilder() { if (!is_finalized()) Finalize(); } - - int size() const { return buffer_.length(); } - - // Get the current position in the builder. - int position() const { - ASSERT(!is_finalized()); - return position_; - } - - // Reset the position. - void Reset() { position_ = 0; } - - // Add a single character to the builder. It is not allowed to add - // 0-characters; use the Finalize() method to terminate the string - // instead. - void AddCharacter(char c) { - ASSERT(c != '\0'); - ASSERT(!is_finalized() && position_ < buffer_.length()); - buffer_[position_++] = c; - } - - // Add an entire string to the builder. Uses strlen() internally to - // compute the length of the input string. - void AddString(const char* s) { - AddSubstring(s, StrLength(s)); - } - - // Add the first 'n' characters of the given string 's' to the - // builder. The input string must have enough characters. - void AddSubstring(const char* s, int n) { - ASSERT(!is_finalized() && position_ + n < buffer_.length()); - ASSERT(static_cast(n) <= strlen(s)); - memmove(&buffer_[position_], s, n * kCharSize); - position_ += n; - } - - - // Add character padding to the builder. If count is non-positive, - // nothing is added to the builder. - void AddPadding(char c, int count) { - for (int i = 0; i < count; i++) { - AddCharacter(c); - } - } - - // Finalize the string by 0-terminating it and returning the buffer. - char* Finalize() { - ASSERT(!is_finalized() && position_ < buffer_.length()); - buffer_[position_] = '\0'; - // Make sure nobody managed to add a 0-character to the - // buffer while building the string. - ASSERT(strlen(buffer_.start()) == static_cast(position_)); - position_ = -1; - ASSERT(is_finalized()); - return buffer_.start(); - } - - private: - Vector buffer_; - int position_; - - bool is_finalized() const { return position_ < 0; } - - DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder); -}; - -// The type-based aliasing rule allows the compiler to assume that pointers of -// different types (for some definition of different) never alias each other. -// Thus the following code does not work: -// -// float f = foo(); -// int fbits = *(int*)(&f); -// -// The compiler 'knows' that the int pointer can't refer to f since the types -// don't match, so the compiler may cache f in a register, leaving random data -// in fbits. Using C++ style casts makes no difference, however a pointer to -// char data is assumed to alias any other pointer. This is the 'memcpy -// exception'. -// -// Bit_cast uses the memcpy exception to move the bits from a variable of one -// type of a variable of another type. Of course the end result is likely to -// be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005) -// will completely optimize BitCast away. -// -// There is an additional use for BitCast. -// Recent gccs will warn when they see casts that may result in breakage due to -// the type-based aliasing rule. If you have checked that there is no breakage -// you can use BitCast to cast one pointer type to another. This confuses gcc -// enough that it can no longer see that you have cast one pointer type to -// another thus avoiding the warning. -template -inline Dest BitCast(const Source& source) { - static_assert(sizeof(Dest) == sizeof(Source), - "BitCast's source and destination types must be the same size"); - - Dest dest; - memmove(&dest, &source, sizeof(dest)); - return dest; -} - -template -inline Dest BitCast(Source* source) { - return BitCast(reinterpret_cast(source)); -} - -} // namespace double_conversion - -#endif // DOUBLE_CONVERSION_UTILS_H_ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozjemalloc_types.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozjemalloc_types.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozjemalloc_types.h @@ -0,0 +1,151 @@ +/* -*- 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/. */ + +// Portions of this file were originally under the following license: +// +// Copyright (C) 2006-2008 Jason Evans . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice(s), this list of conditions and the following disclaimer as +// the first lines of this file unmodified other than the possible +// addition of one or more copyright notices. +// 2. Redistributions in binary form must reproduce the above copyright +// notice(s), this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef _JEMALLOC_TYPES_H_ +#define _JEMALLOC_TYPES_H_ + +// grab size_t +#ifdef _MSC_VER +#include +#else +#include +#endif +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MALLOC_USABLE_SIZE_CONST_PTR +#define MALLOC_USABLE_SIZE_CONST_PTR const +#endif + +typedef MALLOC_USABLE_SIZE_CONST_PTR void* usable_ptr_t; + +typedef size_t arena_id_t; + +typedef struct arena_params_s { + size_t mMaxDirty; + +#ifdef __cplusplus + arena_params_s() : mMaxDirty(0) {} +#endif +} arena_params_t; + +// jemalloc_stats() is not a stable interface. When using jemalloc_stats_t, be +// sure that the compiled results of jemalloc.c are in sync with this header +// file. +typedef struct { + // Run-time configuration settings. + bool opt_junk; // Fill allocated memory with kAllocJunk? + bool opt_zero; // Fill allocated memory with 0x0? + size_t narenas; // Number of arenas. + size_t quantum; // Allocation quantum. + size_t small_max; // Max quantum-spaced allocation size. + size_t large_max; // Max sub-chunksize allocation size. + size_t chunksize; // Size of each virtual memory mapping. + size_t page_size; // Size of pages. + size_t dirty_max; // Max dirty pages per arena. + + // Current memory usage statistics. + size_t mapped; // Bytes mapped (not necessarily committed). + size_t allocated; // Bytes allocated (committed, in use by application). + size_t waste; // Bytes committed, not in use by the + // application, and not intentionally left + // unused (i.e., not dirty). + size_t page_cache; // Committed, unused pages kept around as a + // cache. (jemalloc calls these "dirty".) + size_t bookkeeping; // Committed bytes used internally by the + // allocator. + size_t bin_unused; // Bytes committed to a bin but currently unused. +} jemalloc_stats_t; + +enum PtrInfoTag { + // The pointer is not currently known to the allocator. + // 'addr' and 'size' are always 0. + TagUnknown, + + // The pointer is within a live allocation. + // 'addr' and 'size' describe the allocation. + TagLiveSmall, + TagLiveLarge, + TagLiveHuge, + + // The pointer is within a small freed allocation. + // 'addr' and 'size' describe the allocation. + TagFreedSmall, + + // The pointer is within a freed page. Details about the original + // allocation, including its size, are not available. + // 'addr' and 'size' describe the page. + TagFreedPageDirty, + TagFreedPageDecommitted, + TagFreedPageMadvised, + TagFreedPageZeroed, +}; + +// The information in jemalloc_ptr_info_t could be represented in a variety of +// ways. The chosen representation has the following properties. +// - The number of fields is minimized. +// - The 'tag' field unambiguously defines the meaning of the subsequent fields. +// Helper functions are used to group together related categories of tags. +typedef struct { + enum PtrInfoTag tag; + void* addr; // meaning depends on tag; see above + size_t size; // meaning depends on tag; see above +} jemalloc_ptr_info_t; + +static inline bool jemalloc_ptr_is_live(jemalloc_ptr_info_t* info) { + return info->tag == TagLiveSmall || info->tag == TagLiveLarge || + info->tag == TagLiveHuge; +} + +static inline bool jemalloc_ptr_is_freed(jemalloc_ptr_info_t* info) { + return info->tag == TagFreedSmall || info->tag == TagFreedPageDirty || + info->tag == TagFreedPageDecommitted || + info->tag == TagFreedPageMadvised || info->tag == TagFreedPageZeroed; +} + +static inline bool jemalloc_ptr_is_freed_page(jemalloc_ptr_info_t* info) { + return info->tag == TagFreedPageDirty || + info->tag == TagFreedPageDecommitted || + info->tag == TagFreedPageMadvised || info->tag == TagFreedPageZeroed; +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _JEMALLOC_TYPES_H_ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozmemory.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozmemory.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozmemory.h @@ -0,0 +1,64 @@ +/* -*- 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 mozmemory_h +#define mozmemory_h + +// This header is meant to be used when the following functions are +// necessary: +// - malloc_good_size (used to be called je_malloc_usable_in_advance) +// - jemalloc_stats +// - jemalloc_purge_freed_pages +// - jemalloc_free_dirty_pages +// - jemalloc_thread_local_arena +// - jemalloc_ptr_info + +#ifdef MALLOC_H +#include MALLOC_H +#endif +#include "mozmemory_wrap.h" +#include "mozilla/Attributes.h" +#include "mozilla/Types.h" +#include "mozjemalloc_types.h" + +#ifdef MOZ_MEMORY +// On OSX, malloc/malloc.h contains the declaration for malloc_good_size, +// which will call back in jemalloc, through the zone allocator so just use it. +#ifndef XP_DARWIN +MOZ_MEMORY_API size_t malloc_good_size_impl(size_t size); + +// Note: the MOZ_GLUE_IN_PROGRAM ifdef below is there to avoid -Werror turning +// the protective if into errors. MOZ_GLUE_IN_PROGRAM is what triggers MFBT_API +// to use weak imports. +static inline size_t _malloc_good_size(size_t size) { +#if defined(MOZ_GLUE_IN_PROGRAM) && !defined(IMPL_MFBT) + if (!malloc_good_size) return size; +#endif + return malloc_good_size_impl(size); +} + +#define malloc_good_size _malloc_good_size +#endif + +#define MALLOC_DECL(name, return_type, ...) \ + MOZ_JEMALLOC_API return_type name(__VA_ARGS__); +#define MALLOC_FUNCS MALLOC_FUNCS_JEMALLOC +#include "malloc_decls.h" + +#endif + +#define MALLOC_DECL(name, return_type, ...) \ + MOZ_JEMALLOC_API return_type name(__VA_ARGS__); +#define MALLOC_FUNCS MALLOC_FUNCS_ARENA +#include "malloc_decls.h" + +#ifdef __cplusplus +#define moz_create_arena() moz_create_arena_with_params(nullptr) +#else +#define moz_create_arena() moz_create_arena_with_params(NULL) +#endif + +#endif // mozmemory_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozmemory_wrap.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozmemory_wrap.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/mozmemory_wrap.h @@ -0,0 +1,170 @@ +/* -*- 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 mozmemory_wrap_h +#define mozmemory_wrap_h + +// This header contains #defines which tweak the names of various memory +// allocation functions. +// +// There are several types of functions related to memory allocation +// that are meant to be used publicly by the Gecko codebase: +// +// - malloc implementation functions: +// - malloc +// - posix_memalign +// - aligned_alloc +// - calloc +// - realloc +// - free +// - memalign +// - valloc +// - malloc_usable_size +// - malloc_good_size +// Some of these functions are specific to some systems, but for +// convenience, they are treated as being cross-platform, and available +// as such. +// +// - duplication functions: +// - strndup +// - strdup +// - wcsdup (Windows only) +// +// - jemalloc specific functions: +// - jemalloc_stats +// - jemalloc_purge_freed_pages +// - jemalloc_free_dirty_pages +// - jemalloc_thread_local_arena +// - jemalloc_ptr_info +// (these functions are native to mozjemalloc) +// +// These functions are all exported as part of libmozglue (see +// $(topsrcdir)/mozglue/build/Makefile.in), with a few implementation +// peculiarities: +// +// - On Windows, the malloc implementation functions are all prefixed with +// "je_", the duplication functions are prefixed with "wrap_", and jemalloc +// specific functions are left unprefixed. All these functions are however +// aliased when exporting them, such that the resulting mozglue.dll exports +// them unprefixed (see $(topsrcdir)/mozglue/build/mozglue.def.in). The +// prefixed malloc implementation and duplication functions are not +// exported. +// +// - On MacOSX, the system libc has a zone allocator, which allows us to +// hook custom malloc implementation functions without exporting them. +// However, since we want things in Firefox to skip the system zone +// allocator, the malloc implementation functions are all exported +// unprefixed, as well as duplication functions. +// Jemalloc-specific functions are also left unprefixed. +// +// - On Android all functions are left unprefixed. Additionally, +// C++ allocation functions (operator new/delete) are also exported and +// unprefixed. +// +// - On other systems (mostly Linux), all functions are left unprefixed. +// +// Only Android adds C++ allocation functions. +// +// Proper exporting of the various functions is done with the MOZ_MEMORY_API +// and MOZ_JEMALLOC_API macros. MOZ_MEMORY_API is meant to be used for malloc +// implementation and duplication functions, while MOZ_JEMALLOC_API is +// dedicated to jemalloc specific functions. +// +// +// All these functions are meant to be called with no prefix from Gecko code. +// In most cases, this is because that's how they are available at runtime. +// However, on Android, this relies on faulty.lib (the custom dynamic linker) +// resolving mozglue symbols before libc symbols, which is guaranteed by the +// way faulty.lib works (it respects the DT_NEEDED order, and libc always +// appears after mozglue ; which we double check when building anyways) +// +// +// Within libmozglue (when MOZ_MEMORY_IMPL is defined), all the functions +// should be suffixed with "_impl" both for declarations and use. +// That is, the implementation declaration for e.g. strdup would look like: +// char* strdup_impl(const char *) +// That implementation would call malloc by using "malloc_impl". + +#if defined(MOZ_MEMORY_IMPL) && !defined(IMPL_MFBT) +#ifdef MFBT_API // mozilla/Types.h was already included +# error mozmemory_wrap.h has to be included before mozilla/Types.h when MOZ_MEMORY_IMPL is set and IMPL_MFBT is not. +#endif +#define IMPL_MFBT +#endif + +#include "mozilla/Types.h" + +#ifndef MOZ_EXTERN_C +#ifdef __cplusplus +#define MOZ_EXTERN_C extern "C" +#else +#define MOZ_EXTERN_C +#endif +#endif + +#ifdef MOZ_MEMORY_IMPL +#define MOZ_JEMALLOC_API MOZ_EXTERN_C MFBT_API +#if defined(XP_WIN) +#define mozmem_malloc_impl(a) je_##a +#else +#define MOZ_MEMORY_API MOZ_EXTERN_C MFBT_API +#if defined(MOZ_WIDGET_ANDROID) +#define MOZ_WRAP_NEW_DELETE +#endif +#endif +#endif +#ifdef XP_WIN +#define mozmem_dup_impl(a) wrap_##a +#endif + +#if !defined(MOZ_MEMORY_IMPL) +#define MOZ_MEMORY_API MOZ_EXTERN_C MFBT_API +#define MOZ_JEMALLOC_API MOZ_EXTERN_C MFBT_API +#endif + +#ifndef MOZ_MEMORY_API +#define MOZ_MEMORY_API MOZ_EXTERN_C +#endif +#ifndef MOZ_JEMALLOC_API +#define MOZ_JEMALLOC_API MOZ_EXTERN_C +#endif + +#ifndef mozmem_malloc_impl +#define mozmem_malloc_impl(a) a +#endif +#ifndef mozmem_dup_impl +#define mozmem_dup_impl(a) a +#endif + +// Malloc implementation functions +#define malloc_impl mozmem_malloc_impl(malloc) +#define posix_memalign_impl mozmem_malloc_impl(posix_memalign) +#define aligned_alloc_impl mozmem_malloc_impl(aligned_alloc) +#define calloc_impl mozmem_malloc_impl(calloc) +#define realloc_impl mozmem_malloc_impl(realloc) +#define free_impl mozmem_malloc_impl(free) +#define memalign_impl mozmem_malloc_impl(memalign) +#define valloc_impl mozmem_malloc_impl(valloc) +#define malloc_usable_size_impl mozmem_malloc_impl(malloc_usable_size) +#define malloc_good_size_impl mozmem_malloc_impl(malloc_good_size) + +// Duplication functions +#define strndup_impl mozmem_dup_impl(strndup) +#define strdup_impl mozmem_dup_impl(strdup) +#ifdef XP_WIN +#define wcsdup_impl mozmem_dup_impl(wcsdup) +#define _aligned_malloc_impl mozmem_dup_impl(_aligned_malloc) +#endif + +// String functions +#ifdef ANDROID +// Bug 801571 and Bug 879668, libstagefright uses vasprintf, causing malloc()/ +// free() to be mismatched between bionic and mozglue implementation. +#define vasprintf_impl mozmem_dup_impl(vasprintf) +#define asprintf_impl mozmem_dup_impl(asprintf) +#endif + +#endif // mozmemory_wrap_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_darwin.cfg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_darwin.cfg +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_darwin.cfg @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#define PR_AF_INET6 30 /* same as AF_INET6 */ + +#ifdef __LITTLE_ENDIAN__ +#undef IS_BIG_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#else +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#endif + +#ifdef __LP64__ +#define IS_64 +#endif + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#undef HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS 1 + +#ifdef IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 +#define PR_BITS_PER_DWORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 +#define PR_BITS_PER_DWORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 +#define PR_ALIGN_OF_DWORD 8 + +#else /* IS_64 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#endif /* IS_64 */ + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ + Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_freebsd.cfg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_freebsd.cfg +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_freebsd.cfg @@ -0,0 +1,594 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef FREEBSD +#define FREEBSD +#endif + +#define PR_AF_INET6 28 /* same as AF_INET6 */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif + +#if defined(__i386__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__alpha__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#elif defined(__sparc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#elif defined(__ia64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#elif defined(__amd64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#elif defined(__powerpc64__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__powerpc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__aarch64__) + +#undef IS_BIG_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__arm__) + +#if defined(__ARMEB__) || defined(__ARM_BIG_ENDIAN__) +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#else +#undef IS_BIG_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#endif + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__mips64__) + +#if defined(__MIPSEB__) || defined(_MIPSEB) +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#else +#undef IS_BIG_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#endif + +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__mips__) + +#if defined(__MIPSEB__) || defined(_MIPSEB) +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#else +#undef IS_BIG_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#endif + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error "Unknown CPU architecture" + +#endif + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_linux.cfg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_linux.cfg +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_linux.cfg @@ -0,0 +1,1084 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* + * This file is used by not only Linux but also other glibc systems + * such as GNU/Hurd and GNU/k*BSD. + */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#if !defined(LINUX) && defined(__linux__) +#define LINUX +#endif + +#ifdef __FreeBSD_kernel__ +#define PR_AF_INET6 28 /* same as AF_INET6 */ +#elif defined(__GNU__) +#define PR_AF_INET6 26 /* same as AF_INET6 */ +#else +#define PR_AF_INET6 10 /* same as AF_INET6 */ +#endif + +#ifdef __powerpc64__ + +#ifdef __LITTLE_ENDIAN__ +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#else +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#endif +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__powerpc__) + +#ifdef __LITTLE_ENDIAN__ +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#else +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#endif + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__alpha) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__ia64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__x86_64__) + +#ifdef __ILP32__ + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#endif + +#elif defined(__mc68000__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 2 +#define PR_ALIGN_OF_LONG 2 +#define PR_ALIGN_OF_INT64 2 +#define PR_ALIGN_OF_FLOAT 2 +#define PR_ALIGN_OF_DOUBLE 2 +#define PR_ALIGN_OF_POINTER 2 +#define PR_ALIGN_OF_WORD 2 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__sparc__) && defined (__arch64__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__sparc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__i386__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__mips__) + +/* For _ABI64 */ +#include + +#ifdef __MIPSEB__ +#define IS_BIG_ENDIAN 1 +#undef IS_LITTLE_ENDIAN +#elif defined(__MIPSEL__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#else +#error "Unknown MIPS endianness." +#endif + +#if _MIPS_SIM == _ABI64 + +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else /* _ABI64 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#endif /* _ABI64 */ + +#elif defined(__arm__) + +#ifdef __ARMEB__ +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#elif defined(__ARMEL__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#else +#error "Unknown ARM endianness." +#endif + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__aarch64__) + +#ifdef __AARCH64EB__ +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#elif defined(__AARCH64EL__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#else +#error "Unknown Aarch64 endianness." +#endif +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__hppa__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__s390x__) + +#define IS_BIG_ENDIAN 1 +#undef IS_LITTLE_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__s390__) + +#define IS_BIG_ENDIAN 1 +#undef IS_LITTLE_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__sh__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__avr32__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__m32r__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__or1k__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error "Unknown CPU architecture" + +#endif + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#if PR_ALIGN_OF_DOUBLE == 8 +#define HAVE_ALIGNED_DOUBLES +#endif +#if PR_ALIGN_OF_INT64 == 8 +#define HAVE_ALIGNED_LONGLONGS +#endif + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_netbsd.cfg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_netbsd.cfg +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_netbsd.cfg @@ -0,0 +1,351 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef NETBSD +#define NETBSD +#endif + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif + +#if defined(__i386__) || defined(__arm32__) || defined(__ARMEL__) || \ + defined(__MIPSEL__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__sparc_v9__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#elif defined(__sparc__) || defined(__MIPSEB__) || defined(__ARMEB__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__alpha__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__amd64__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__powerpc__) || defined(__m68k__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error Must define constants for type sizes here. + +#endif + + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_openbsd.cfg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_openbsd.cfg +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_openbsd.cfg @@ -0,0 +1,353 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef OPENBSD +#define OPENBSD +#endif + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif + +#if defined(__i386__) || defined(__arm__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__amd64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#elif defined(__sparc_v9__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__sparc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__alpha__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__powerpc__) || defined(__m68k__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error Must define constants for type sizes here. + +#endif + + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_solaris.cfg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_solaris.cfg +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_solaris.cfg @@ -0,0 +1,171 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef SOLARIS +#define SOLARIS +#endif + +#define PR_AF_INET6 26 /* same as AF_INET6 */ + +#if defined(sparc) || defined(__sparc) +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_DOUBLE 8 +#if defined(__sparcv9) +#define IS_64 +#endif +#elif defined(__x86_64) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_DOUBLE 8 +#define IS_64 +#elif defined(i386) || defined(__i386) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_DOUBLE 4 +#else +#error unknown processor +#endif + +#ifdef IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_POINTER 8 + +#else /* IS_64 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_POINTER 4 + +#endif /* IS_64 */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* ifndef nspr_cpucfg___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_win95.cfg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_win95.cfg +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/md/_win95.cfg @@ -0,0 +1,272 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_PC +#define XP_PC +#endif + +#ifndef WIN32 +#define WIN32 +#endif + +#ifndef WIN95 +#define WIN95 +#endif + +#define PR_AF_INET6 23 /* same as AF_INET6 */ + +#if defined(_M_IX86) || defined(_X86_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 5 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 4 +#define PR_ALIGN_OF_DWORD 8 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_WORD 64 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 6 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 8 +#define PR_ALIGN_OF_DWORD 8 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(_M_IA64) || defined(_IA64_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_WORD 64 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 6 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 8 +#define PR_ALIGN_OF_DWORD 8 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(_M_ARM) || defined(_ARM_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 5 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 4 +#define PR_ALIGN_OF_DWORD 8 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else /* defined(_M_IX86) || defined(_X86_) */ + +#error unknown processor architecture + +#endif /* defined(_M_IX86) || defined(_X86_) */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/nspr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/nspr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/nspr.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef nspr_h___ +#define nspr_h___ + +#include "pratom.h" +#include "prbit.h" +#include "prclist.h" +#include "prcmon.h" +#include "prcvar.h" +#include "prdtoa.h" +#include "prenv.h" +#include "prerror.h" +#include "prinet.h" +#include "prinit.h" +#include "prinrval.h" +#include "prio.h" +#include "pripcsem.h" +#include "prlink.h" +#include "prlock.h" +#include "prlog.h" +#include "prlong.h" +#include "prmem.h" +#include "prmon.h" +#include "prmwait.h" +#include "prnetdb.h" +#include "prprf.h" +#include "prproces.h" +#include "prrng.h" +#include "prrwlock.h" +#include "prshm.h" +#include "prshma.h" +#include "prsystem.h" +#include "prthread.h" +#include "prtime.h" +#include "prtpool.h" +#include "prtrace.h" +#include "prtypes.h" + +#endif /* nspr_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plarena.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plarena.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plarena.h @@ -0,0 +1,327 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef plarena_h___ +#define plarena_h___ +/* + * Lifetime-based fast allocation, inspired by much prior art, including + * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes" + * David R. Hanson, Software -- Practice and Experience, Vol. 20(1). + * + * Also supports LIFO allocation (PL_ARENA_MARK/PL_ARENA_RELEASE). + */ +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +typedef struct PLArena PLArena; + +struct PLArena { + PLArena *next; /* next arena for this lifetime */ + PRUword base; /* aligned base address, follows this header */ + PRUword limit; /* one beyond last byte in arena */ + PRUword avail; /* points to next available byte */ +}; + +#ifdef PL_ARENAMETER +typedef struct PLArenaStats PLArenaStats; + +struct PLArenaStats { + PLArenaStats *next; /* next in arenaStats list */ + char *name; /* name for debugging */ + PRUint32 narenas; /* number of arenas in pool */ + PRUint32 nallocs; /* number of PL_ARENA_ALLOCATE() calls */ + PRUint32 nreclaims; /* number of reclaims from freeArenas */ + PRUint32 nmallocs; /* number of malloc() calls */ + PRUint32 ndeallocs; /* number of lifetime deallocations */ + PRUint32 ngrows; /* number of PL_ARENA_GROW() calls */ + PRUint32 ninplace; /* number of in-place growths */ + PRUint32 nreleases; /* number of PL_ARENA_RELEASE() calls */ + PRUint32 nfastrels; /* number of "fast path" releases */ + PRUint32 nbytes; /* total bytes allocated */ + PRUint32 maxalloc; /* maximum allocation size in bytes */ + PRFloat64 variance; /* size variance accumulator */ +}; +#endif + +typedef struct PLArenaPool PLArenaPool; + +struct PLArenaPool { + PLArena first; /* first arena in pool list */ + PLArena *current; /* arena from which to allocate space */ + PRUint32 arenasize; /* net exact size of a new arena */ + PRUword mask; /* alignment mask (power-of-2 - 1) */ +#ifdef PL_ARENAMETER + PLArenaStats stats; +#endif +}; + +/* + * WARNING: The PL_MAKE_MEM_ macros are for internal use by NSPR. Do NOT use + * them in your code. + * + * NOTE: Valgrind support to be added. + * + * The PL_MAKE_MEM_ macros are modeled after the MOZ_MAKE_MEM_ macros in + * Mozilla's mfbt/MemoryChecking.h. Only AddressSanitizer is supported now. + * + * Provides a common interface to the ASan (AddressSanitizer) and Valgrind + * functions used to mark memory in certain ways. In detail, the following + * three macros are provided: + * + * PL_MAKE_MEM_NOACCESS - Mark memory as unsafe to access (e.g. freed) + * PL_MAKE_MEM_UNDEFINED - Mark memory as accessible, with content undefined + * PL_MAKE_MEM_DEFINED - Mark memory as accessible, with content defined + * + * With Valgrind in use, these directly map to the three respective Valgrind + * macros. With ASan in use, the NOACCESS macro maps to poisoning the memory, + * while the UNDEFINED/DEFINED macros unpoison memory. + * + * With no memory checker available, all macros expand to the empty statement. + */ + +/* WARNING: PL_SANITIZE_ADDRESS is for internal use by this header. Do NOT + * define or test this macro in your code. + */ +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define PL_SANITIZE_ADDRESS 1 +#endif +#elif defined(__SANITIZE_ADDRESS__) +#define PL_SANITIZE_ADDRESS 1 +#endif + +#if defined(PL_SANITIZE_ADDRESS) + +/* These definitions are usually provided through the + * sanitizer/asan_interface.h header installed by ASan. + * See https://github.com/google/sanitizers/wiki/AddressSanitizerManualPoisoning + */ + +PR_IMPORT(void) __asan_poison_memory_region(void const volatile *addr, size_t size); +PR_IMPORT(void) __asan_unpoison_memory_region(void const volatile *addr, size_t size); + +#define PL_MAKE_MEM_NOACCESS(addr, size) \ + __asan_poison_memory_region((addr), (size)) + +#define PL_MAKE_MEM_UNDEFINED(addr, size) \ + __asan_unpoison_memory_region((addr), (size)) + +#define PL_MAKE_MEM_DEFINED(addr, size) \ + __asan_unpoison_memory_region((addr), (size)) + +#else + +#define PL_MAKE_MEM_NOACCESS(addr, size) +#define PL_MAKE_MEM_UNDEFINED(addr, size) +#define PL_MAKE_MEM_DEFINED(addr, size) + +#endif + +/* + * If the including .c file uses only one power-of-2 alignment, it may define + * PL_ARENA_CONST_ALIGN_MASK to the alignment mask and save a few instructions + * per ALLOCATE and GROW. + */ +#ifdef PL_ARENA_CONST_ALIGN_MASK +#define PL_ARENA_ALIGN(pool, n) (((PRUword)(n) + PL_ARENA_CONST_ALIGN_MASK) \ + & ~PL_ARENA_CONST_ALIGN_MASK) + +#define PL_INIT_ARENA_POOL(pool, name, size) \ + PL_InitArenaPool(pool, name, size, PL_ARENA_CONST_ALIGN_MASK + 1) +#else +#define PL_ARENA_ALIGN(pool, n) (((PRUword)(n) + (pool)->mask) & ~(pool)->mask) +#endif + +#define PL_ARENA_ALLOCATE(p, pool, nb) \ + PR_BEGIN_MACRO \ + PLArena *_a = (pool)->current; \ + PRUint32 _nb = PL_ARENA_ALIGN(pool, (PRUint32)nb); \ + PRUword _p = _a->avail; \ + if (_nb < (PRUint32)nb) { \ + _p = 0; \ + } else if (_nb > (_a->limit - _a->avail)) { \ + _p = (PRUword)PL_ArenaAllocate(pool, _nb); \ + } else { \ + _a->avail += _nb; \ + } \ + p = (void *)_p; \ + if (p) { \ + PL_MAKE_MEM_UNDEFINED(p, (PRUint32)nb); \ + PL_ArenaCountAllocation(pool, (PRUint32)nb); \ + } \ + PR_END_MACRO + +#define PL_ARENA_GROW(p, pool, size, incr) \ + PR_BEGIN_MACRO \ + PLArena *_a = (pool)->current; \ + PRUint32 _incr = PL_ARENA_ALIGN(pool, (PRUint32)incr); \ + if (_incr < (PRUint32)incr) { \ + p = NULL; \ + } else if (_a->avail == (PRUword)(p) + PL_ARENA_ALIGN(pool, size) && \ + _incr <= (_a->limit - _a->avail)) { \ + PL_MAKE_MEM_UNDEFINED((unsigned char *)(p) + size, (PRUint32)incr); \ + _a->avail += _incr; \ + PL_ArenaCountInplaceGrowth(pool, size, (PRUint32)incr); \ + } else { \ + p = PL_ArenaGrow(pool, p, size, (PRUint32)incr); \ + } \ + if (p) {\ + PL_ArenaCountGrowth(pool, size, (PRUint32)incr); \ + } \ + PR_END_MACRO + +#define PL_ARENA_MARK(pool) ((void *) (pool)->current->avail) +#define PR_UPTRDIFF(p,q) ((PRUword)(p) - (PRUword)(q)) + +#define PL_CLEAR_UNUSED_PATTERN(a, pattern) \ + PR_BEGIN_MACRO \ + PR_ASSERT((a)->avail <= (a)->limit); \ + PL_MAKE_MEM_UNDEFINED((void*)(a)->avail, (a)->limit - (a)->avail); \ + memset((void*)(a)->avail, (pattern), (a)->limit - (a)->avail); \ + PR_END_MACRO +#ifdef DEBUG +#define PL_FREE_PATTERN 0xDA +#define PL_CLEAR_UNUSED(a) PL_CLEAR_UNUSED_PATTERN((a), PL_FREE_PATTERN) +#define PL_CLEAR_ARENA(a) \ + PR_BEGIN_MACRO \ + PL_MAKE_MEM_UNDEFINED((void*)(a), (a)->limit - (PRUword)(a)); \ + memset((void*)(a), PL_FREE_PATTERN, (a)->limit - (PRUword)(a)); \ + PR_END_MACRO +#else +#define PL_CLEAR_UNUSED(a) +#define PL_CLEAR_ARENA(a) +#endif + +#define PL_ARENA_RELEASE(pool, mark) \ + PR_BEGIN_MACRO \ + char *_m = (char *)(mark); \ + PLArena *_a = (pool)->current; \ + if (PR_UPTRDIFF(_m, _a->base) <= PR_UPTRDIFF(_a->avail, _a->base)) { \ + _a->avail = (PRUword)PL_ARENA_ALIGN(pool, _m); \ + PL_CLEAR_UNUSED(_a); \ + PL_MAKE_MEM_NOACCESS((void*)_a->avail, _a->limit - _a->avail); \ + PL_ArenaCountRetract(pool, _m); \ + } else { \ + PL_ArenaRelease(pool, _m); \ + } \ + PL_ArenaCountRelease(pool, _m); \ + PR_END_MACRO + +#ifdef PL_ARENAMETER +#define PL_COUNT_ARENA(pool,op) ((pool)->stats.narenas op) +#else +#define PL_COUNT_ARENA(pool,op) +#endif + +#define PL_ARENA_DESTROY(pool, a, pnext) \ + PR_BEGIN_MACRO \ + PL_COUNT_ARENA(pool,--); \ + if ((pool)->current == (a)) (pool)->current = &(pool)->first; \ + *(pnext) = (a)->next; \ + PL_CLEAR_ARENA(a); \ + free(a); \ + (a) = 0; \ + PR_END_MACRO + +/* +** Initialize an arena pool with the given name for debugging and metering, +** with a minimum gross size per arena of size bytes. The net size per arena +** is smaller than the gross size by a header of four pointers plus any +** necessary padding for alignment. +** +** Note: choose a gross size that's a power of two to avoid the heap allocator +** rounding the size up. +**/ +PR_EXTERN(void) PL_InitArenaPool( + PLArenaPool *pool, const char *name, PRUint32 size, PRUint32 align); + +/* +** Finish using arenas, freeing all memory associated with them. +** NOTE: this function is now a no-op. If you want to free a single +** PLArenaPoolUse use PL_FreeArenaPool() or PL_FinishArenaPool(). +**/ +PR_EXTERN(void) PL_ArenaFinish(void); + +/* +** Free the arenas in pool. The user may continue to allocate from pool +** after calling this function. There is no need to call PL_InitArenaPool() +** again unless PL_FinishArenaPool(pool) has been called. +**/ +PR_EXTERN(void) PL_FreeArenaPool(PLArenaPool *pool); + +/* +** Free the arenas in pool and finish using it altogether. +**/ +PR_EXTERN(void) PL_FinishArenaPool(PLArenaPool *pool); + +/* +** Compact all of the arenas in a pool so that no space is wasted. +** NOT IMPLEMENTED. Do not use. +**/ +PR_EXTERN(void) PL_CompactArenaPool(PLArenaPool *pool); + +/* +** Friend functions used by the PL_ARENA_*() macros. +** +** WARNING: do not call these functions directly. Always use the +** PL_ARENA_*() macros. +**/ +PR_EXTERN(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb); + +PR_EXTERN(void *) PL_ArenaGrow( + PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr); + +PR_EXTERN(void) PL_ArenaRelease(PLArenaPool *pool, char *mark); + +/* +** memset contents of all arenas in pool to pattern +*/ +PR_EXTERN(void) PL_ClearArenaPool(PLArenaPool *pool, PRInt32 pattern); + +/* +** A function like malloc_size() or malloc_usable_size() that measures the +** size of a heap block. +*/ +typedef size_t (*PLMallocSizeFn)(const void *ptr); + +/* +** Measure all memory used by a PLArenaPool, excluding the PLArenaPool +** structure. +*/ +PR_EXTERN(size_t) PL_SizeOfArenaPoolExcludingPool( + const PLArenaPool *pool, PLMallocSizeFn mallocSizeOf); + +#ifdef PL_ARENAMETER + +#include + +PR_EXTERN(void) PL_ArenaCountAllocation(PLArenaPool *pool, PRUint32 nb); + +PR_EXTERN(void) PL_ArenaCountInplaceGrowth( + PLArenaPool *pool, PRUint32 size, PRUint32 incr); + +PR_EXTERN(void) PL_ArenaCountGrowth( + PLArenaPool *pool, PRUint32 size, PRUint32 incr); + +PR_EXTERN(void) PL_ArenaCountRelease(PLArenaPool *pool, char *mark); + +PR_EXTERN(void) PL_ArenaCountRetract(PLArenaPool *pool, char *mark); + +PR_EXTERN(void) PL_DumpArenaStats(FILE *fp); + +#else /* !PL_ARENAMETER */ + +#define PL_ArenaCountAllocation(ap, nb) /* nothing */ +#define PL_ArenaCountInplaceGrowth(ap, size, incr) /* nothing */ +#define PL_ArenaCountGrowth(ap, size, incr) /* nothing */ +#define PL_ArenaCountRelease(ap, mark) /* nothing */ +#define PL_ArenaCountRetract(ap, mark) /* nothing */ + +#endif /* !PL_ARENAMETER */ + +PR_END_EXTERN_C + +#endif /* plarena_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plarenas.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plarenas.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plarenas.h @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** PLArena-related declarations used to be split between plarenas.h and +** plarena.h. That split wasn't useful, so now all the declarations are in +** plarena.h. However, this file still exists so that any old code that +** includes it will still work. +**/ +#include "plarena.h" Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plbase64.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plbase64.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plbase64.h @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef _plbase64_h +#define _plbase64_h + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* + * PL_Base64Encode + * + * This routine encodes the data pointed to by the "src" parameter using the + * base64 algorithm, and returns a pointer to the result. If the "srclen" + * parameter is not zero, it specifies the length of the source data. If it + * is zero, the source data is assumed to be null-terminated, and PL_strlen + * is used to determine the source length. If the "dest" parameter is not + * null, it is assumed to point to a buffer of sufficient size (which may be + * calculated: ((srclen + 2)/3)*4) into which the encoded data is placed + * (without any termination). If the "dest" parameter is null, a buffer is + * allocated from the heap to hold the encoded data, and the result *will* + * be terminated with an extra null character. It is the caller's + * responsibility to free the result when it is allocated. A null is returned + * if the allocation fails. + * + * NOTE: when calculating ((srclen + 2)/3)*4), first ensure that + * srclen <= (PR_UINT32_MAX/4) * 3 + * to avoid PRUint32 overflow. + */ + +PR_EXTERN(char *) +PL_Base64Encode +( + const char *src, + PRUint32 srclen, + char *dest +); + +/* + * PL_Base64Decode + * + * This routine decodes the data pointed to by the "src" parameter using + * the base64 algorithm, and returns a pointer to the result. The source + * may either include or exclude any trailing '=' characters. If the + * "srclen" parameter is not zero, it specifies the length of the source + * data. If it is zero, PL_strlen will be used to determine the source + * length. If the "dest" parameter is not null, it is assumed to point to + * a buffer of sufficient size (which may be calculated: (srclen * 3)/4 + * when srclen includes the '=' characters) into which the decoded data + * is placed (without any termination). If the "dest" parameter is null, + * a buffer is allocated from the heap to hold the decoded data, and the + * result *will* be terminated with an extra null character. It is the + * caller's responsibility to free the result when it is allocated. A null + * is retuned if the allocation fails, or if the source is not well-coded. + * + * NOTE: when calculating (srclen * 3)/4, first ensure that + * srclen <= PR_UINT32_MAX/3 + * to avoid PRUint32 overflow. Alternatively, calculate + * (srclen/4) * 3 + ((srclen%4) * 3)/4 + * which is equivalent but doesn't overflow for any value of srclen. + */ + +PR_EXTERN(char *) +PL_Base64Decode +( + const char *src, + PRUint32 srclen, + char *dest +); + +PR_END_EXTERN_C + +#endif /* _plbase64_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plerror.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plerror.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plerror.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: plerror.h +** Description: Simple routine to print translate the calling thread's +** error numbers and print them. +*/ + +#if defined(PLERROR_H) +#else +#define PLERROR_H + +#include "prio.h" +#include "prtypes.h" + +PR_BEGIN_EXTERN_C +/* +** Print the messages to "syserr" prepending 'msg' if not NULL. +*/ +PR_EXTERN(void) PL_PrintError(const char *msg); + +/* +** Print the messages to specified output file prepending 'msg' if not NULL. +*/ +PR_EXTERN(void) PL_FPrintError(PRFileDesc *output, const char *msg); + +PR_END_EXTERN_C + +#endif /* defined(PLERROR_H) */ + +/* plerror.h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plgetopt.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plgetopt.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plgetopt.h @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: plgetopt.h +** Description: utilities to parse argc/argv +*/ + +#if defined(PLGETOPT_H_) +#else +#define PLGETOPT_H_ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +typedef struct PLOptionInternal PLOptionInternal; + +typedef enum +{ + PL_OPT_OK, /* all's well with the option */ + PL_OPT_EOL, /* end of options list */ + PL_OPT_BAD /* invalid option (and value) */ +} PLOptStatus; + +typedef struct PLLongOpt +{ + const char * longOptName; /* long option name string */ + PRIntn longOption; /* value put in PLOptState for this option. */ + PRBool valueRequired; /* If option name not followed by '=', */ + /* value is the next argument from argv. */ +} PLLongOpt; + +typedef struct PLOptState +{ + char option; /* the name of the option */ + const char *value; /* the value of that option | NULL */ + + PLOptionInternal *internal; /* private processing state */ + + PRIntn longOption; /* value from PLLongOpt put here */ + PRIntn longOptIndex; /* index into caller's array of PLLongOpts */ +} PLOptState; + +/* + * PL_CreateOptState + * + * The argument "options" points to a string of single-character option + * names. Option names that may have an option argument value must be + * followed immediately by a ':' character. + */ +PR_EXTERN(PLOptState*) PL_CreateOptState( + PRIntn argc, char **argv, const char *options); + +/* + * PL_CreateLongOptState + * + * Alternative to PL_CreateOptState. + * Allows caller to specify BOTH a string of single-character option names, + * AND an array of structures describing "long" (keyword) option names. + * The array is terminated by a structure in which longOptName is NULL. + * Long option values (arguments) may always be given as "--name=value". + * If PLLongOpt.valueRequired is not PR_FALSE, and the option name was not + * followed by '=' then the next argument from argv is taken as the value. + */ +PR_EXTERN(PLOptState*) PL_CreateLongOptState( + PRIntn argc, char **argv, const char *options, + const PLLongOpt *longOpts); +/* + * PL_DestroyOptState + * + * Call this to destroy the PLOptState returned from PL_CreateOptState or + * PL_CreateLongOptState. + */ +PR_EXTERN(void) PL_DestroyOptState(PLOptState *opt); + +/* + * PL_GetNextOpt + * + * When this function returns PL_OPT_OK, + * - opt->option will hold the single-character option name that was parsed, + * or zero. + * When opt->option is zero, the token parsed was either a "long" (keyword) + * option or a positional parameter. + * For a positional parameter, + * - opt->longOptIndex will contain -1, and + * - opt->value will point to the positional parameter string. + * For a long option name, + * - opt->longOptIndex will contain the non-negative index of the + * PLLongOpt structure in the caller's array of PLLongOpt structures + * corresponding to the long option name, and + * For a single-character or long option, + * - opt->longOption will contain the value of the single-character option + * name, or the value of the longOption from the PLLongOpt structure + * for that long option. See notes below. + * - opt->value will point to the argument option string, or will + * be NULL if option does not require argument. If option requires + * argument but it is not provided, PL_OPT_BAD is returned. + * When opt->option is non-zero, + * - opt->longOptIndex will be -1 + * When this function returns PL_OPT_EOL, or PL_OPT_BAD, the contents of + * opt are undefined. + * + * Notes: It is possible to ignore opt->option, and always look at + * opt->longOption instead. opt->longOption will contain the same value + * as opt->option for single-character option names, and will contain the + * value of longOption from the PLLongOpt structure for long option names. + * This means that it is possible to equivalence long option names to + * single character names by giving the longOption in the PLLongOpt struct + * the same value as the single-character option name. + * For long options that are NOT intended to be equivalent to any single- + * character option, the longOption value should be chosen to not match + * any possible single character name. It might be advisable to choose + * longOption values greater than 0xff for such long options. + */ +PR_EXTERN(PLOptStatus) PL_GetNextOpt(PLOptState *opt); + +PR_END_EXTERN_C + +#endif /* defined(PLGETOPT_H_) */ + +/* plgetopt.h */ + Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plhash.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plhash.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plhash.h @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef plhash_h___ +#define plhash_h___ +/* + * API to portable hash table code. + */ +#include +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +typedef struct PLHashEntry PLHashEntry; +typedef struct PLHashTable PLHashTable; +typedef PRUint32 PLHashNumber; +#define PL_HASH_BITS 32 /* Number of bits in PLHashNumber */ +typedef PLHashNumber (PR_CALLBACK *PLHashFunction)(const void *key); +typedef PRIntn (PR_CALLBACK *PLHashComparator)(const void *v1, const void *v2); + +typedef PRIntn (PR_CALLBACK *PLHashEnumerator)(PLHashEntry *he, PRIntn i, void *arg); + +/* Flag bits in PLHashEnumerator's return value */ +#define HT_ENUMERATE_NEXT 0 /* continue enumerating entries */ +#define HT_ENUMERATE_STOP 1 /* stop enumerating entries */ +#define HT_ENUMERATE_REMOVE 2 /* remove and free the current entry */ +#define HT_ENUMERATE_UNHASH 4 /* just unhash the current entry */ + +typedef struct PLHashAllocOps { + void * (PR_CALLBACK *allocTable)(void *pool, PRSize size); + void (PR_CALLBACK *freeTable)(void *pool, void *item); + PLHashEntry * (PR_CALLBACK *allocEntry)(void *pool, const void *key); + void (PR_CALLBACK *freeEntry)(void *pool, PLHashEntry *he, PRUintn flag); +} PLHashAllocOps; + +#define HT_FREE_VALUE 0 /* just free the entry's value */ +#define HT_FREE_ENTRY 1 /* free value and entire entry */ + +struct PLHashEntry { + PLHashEntry *next; /* hash chain linkage */ + PLHashNumber keyHash; /* key hash function result */ + const void *key; /* ptr to opaque key */ + void *value; /* ptr to opaque value */ +}; + +struct PLHashTable { + PLHashEntry **buckets; /* vector of hash buckets */ + PRUint32 nentries; /* number of entries in table */ + PRUint32 shift; /* multiplicative hash shift */ + PLHashFunction keyHash; /* key hash function */ + PLHashComparator keyCompare; /* key comparison function */ + PLHashComparator valueCompare; /* value comparison function */ + const PLHashAllocOps *allocOps; /* allocation operations */ + void *allocPriv; /* allocation private data */ +#ifdef HASHMETER + PRUint32 nlookups; /* total number of lookups */ + PRUint32 nsteps; /* number of hash chains traversed */ + PRUint32 ngrows; /* number of table expansions */ + PRUint32 nshrinks; /* number of table contractions */ +#endif +}; + +/* + * Create a new hash table. + * If allocOps is null, use default allocator ops built on top of malloc(). + */ +PR_EXTERN(PLHashTable *) +PL_NewHashTable(PRUint32 numBuckets, PLHashFunction keyHash, + PLHashComparator keyCompare, PLHashComparator valueCompare, + const PLHashAllocOps *allocOps, void *allocPriv); + +PR_EXTERN(void) +PL_HashTableDestroy(PLHashTable *ht); + +/* Higher level access methods */ +PR_EXTERN(PLHashEntry *) +PL_HashTableAdd(PLHashTable *ht, const void *key, void *value); + +PR_EXTERN(PRBool) +PL_HashTableRemove(PLHashTable *ht, const void *key); + +PR_EXTERN(void *) +PL_HashTableLookup(PLHashTable *ht, const void *key); + +PR_EXTERN(void *) +PL_HashTableLookupConst(PLHashTable *ht, const void *key); + +PR_EXTERN(PRIntn) +PL_HashTableEnumerateEntries(PLHashTable *ht, PLHashEnumerator f, void *arg); + +/* General-purpose C string hash function. */ +PR_EXTERN(PLHashNumber) +PL_HashString(const void *key); + +/* Compare strings using strcmp(), return true if equal. */ +PR_EXTERN(PRIntn) +PL_CompareStrings(const void *v1, const void *v2); + +/* Stub function just returns v1 == v2 */ +PR_EXTERN(PRIntn) +PL_CompareValues(const void *v1, const void *v2); + +/* Low level access methods */ +PR_EXTERN(PLHashEntry **) +PL_HashTableRawLookup(PLHashTable *ht, PLHashNumber keyHash, const void *key); + +PR_EXTERN(PLHashEntry **) +PL_HashTableRawLookupConst(PLHashTable *ht, PLHashNumber keyHash, + const void *key); + +PR_EXTERN(PLHashEntry *) +PL_HashTableRawAdd(PLHashTable *ht, PLHashEntry **hep, PLHashNumber keyHash, + const void *key, void *value); + +PR_EXTERN(void) +PL_HashTableRawRemove(PLHashTable *ht, PLHashEntry **hep, PLHashEntry *he); + +/* This can be trivially implemented using PL_HashTableEnumerateEntries. */ +PR_EXTERN(PRIntn) +PL_HashTableDump(PLHashTable *ht, PLHashEnumerator dump, FILE *fp); + +PR_END_EXTERN_C + +#endif /* plhash_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plstr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plstr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/plstr.h @@ -0,0 +1,437 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef _plstr_h +#define _plstr_h + +/* + * plstr.h + * + * This header file exports the API to the NSPR portable library or string- + * handling functions. + * + * This API was not designed as an "optimal" or "ideal" string library; it + * was based on the good ol' unix string.3 functions, and was written to + * + * 1) replace the libc functions, for cross-platform consistency, + * 2) complete the API on platforms lacking common functions (e.g., + * strcase*), and + * 3) to implement some obvious "closure" functions that I've seen + * people hacking around in our code. + * + * Point number three largely means that most functions have an "strn" + * limited-length version, and all comparison routines have a non-case- + * sensitive version available. + */ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C +/* + * PL_strlen + * + * Returns the length of the provided string, not including the trailing '\0'. + */ + +PR_EXTERN(PRUint32) +PL_strlen(const char *str); + +/* + * PL_strnlen + * + * Returns the length of the provided string, not including the trailing '\0', + * up to the indicated maximum. The string will not be examined beyond the + * maximum; if no terminating '\0' is found, the maximum will be returned. + */ + +PR_EXTERN(PRUint32) +PL_strnlen(const char *str, PRUint32 max); + +/* + * PL_strcpy + * + * Copies the source string, up to and including the trailing '\0', into the + * destination buffer. It does not (can not) verify that the destination + * buffer is large enough. It returns the "dest" argument. + */ + +PR_EXTERN(char *) +PL_strcpy(char *dest, const char *src); + +/* + * PL_strncpy + * + * Copies the source string into the destination buffer, up to and including + * the trailing '\0' or up to and including the max'th character, whichever + * comes first. It does not (can not) verify that the destination buffer is + * large enough. If the source string is longer than the maximum length, + * the result will *not* be null-terminated (JLRU). + */ + +PR_EXTERN(char *) +PL_strncpy(char *dest, const char *src, PRUint32 max); + +/* + * PL_strncpyz + * + * Copies the source string into the destination buffer, up to and including + * the trailing '\0' or up but not including the max'th character, whichever + * comes first. It does not (can not) verify that the destination buffer is + * large enough. The destination string is always terminated with a '\0', + * unlike the traditional libc implementation. It returns the "dest" argument. + * + * NOTE: If you call this with a source "abcdefg" and a max of 5, the + * destination will end up with "abcd\0" (i.e., its strlen length will be 4)! + * + * This means you can do this: + * + * char buffer[ SOME_SIZE ]; + * PL_strncpyz(buffer, src, sizeof(buffer)); + * + * and the result will be properly terminated. + */ + +PR_EXTERN(char *) +PL_strncpyz(char *dest, const char *src, PRUint32 max); + +/* + * PL_strdup + * + * Returns a pointer to a malloc'd extent of memory containing a duplicate + * of the argument string. The size of the allocated extent is one greater + * than the length of the argument string, because of the terminator. A + * null argument, like a zero-length argument, will result in a pointer to + * a one-byte extent containing the null value. This routine returns null + * upon malloc failure. + */ + +PR_EXTERN(char *) +PL_strdup(const char *s); + +/* + * PL_strfree + * + * Free memory allocated by PL_strdup + */ + +PR_EXTERN(void) +PL_strfree(char *s); + +/* + * PL_strndup + * + * Returns a pointer to a malloc'd extent of memory containing a duplicate + * of the argument string, up to the maximum specified. If the argument + * string has a length greater than the value of the specified maximum, the + * return value will be a pointer to an extent of memory of length one + * greater than the maximum specified. A null string, a zero-length string, + * or a zero maximum will all result in a pointer to a one-byte extent + * containing the null value. This routine returns null upon malloc failure. + */ + +PR_EXTERN(char *) +PL_strndup(const char *s, PRUint32 max); + +/* + * PL_strcat + * + * Appends a copy of the string pointed to by the second argument to the + * end of the string pointed to by the first. The destination buffer is + * not (can not be) checked for sufficient size. A null destination + * argument returns null; otherwise, the first argument is returned. + */ + +PR_EXTERN(char *) +PL_strcat(char *dst, const char *src); + +/* + * PL_strncat + * + * Appends a copy of the string pointed to by the second argument, up to + * the maximum size specified, to the end of the string pointed to by the + * first. The destination buffer is not (can not be) checked for sufficient + * size. A null destination argument returns null; otherwise, the first + * argument is returned. If the maximum size limits the copy, then the + * result will *not* be null-terminated (JLRU). A null destination + * returns null; otherwise, the destination argument is returned. + */ + +PR_EXTERN(char *) +PL_strncat(char *dst, const char *src, PRUint32 max); + +/* + * PL_strcatn + * + * Appends a copy of the string pointed to by the third argument, to the + * end of the string pointed to by the first. The second argument specifies + * the maximum size of the destination buffer, including the null termination. + * If the existing string in dst is longer than the max, no action is taken. + * The resulting string will be null-terminated. A null destination returns + * null; otherwise, the destination argument is returned. + */ + +PR_EXTERN(char *) +PL_strcatn(char *dst, PRUint32 max, const char *src); + +/* + * PL_strcmp + * + * Returns an integer, the sign of which -- positive, zero, or negative -- + * reflects the lexical sorting order of the two strings indicated. The + * result is positive if the first string comes after the second. The + * NSPR implementation is not i18n. + */ + +PR_EXTERN(PRIntn) +PL_strcmp(const char *a, const char *b); + +/* + * PL_strncmp + * + * Returns an integer, the sign of which -- positive, zero, or negative -- + * reflects the lexical sorting order of the two strings indicated, up to + * the maximum specified. The result is positive if the first string comes + * after the second. The NSPR implementation is not i18n. If the maximum + * is zero, only the existance or non-existance (pointer is null) of the + * strings is compared. + */ + +PR_EXTERN(PRIntn) +PL_strncmp(const char *a, const char *b, PRUint32 max); + +/* + * PL_strcasecmp + * + * Returns an integer, the sign of which -- positive, zero or negative -- + * reflects the case-insensitive lexical sorting order of the two strings + * indicated. The result is positive if the first string comes after the + * second. The NSPR implementation is not i18n. + */ + +PR_EXTERN(PRIntn) +PL_strcasecmp(const char *a, const char *b); + +/* + * PL_strncasecmp + * + * Returns an integer, the sign of which -- positive, zero or negative -- + * reflects the case-insensitive lexical sorting order of the first n characters + * of the two strings indicated. The result is positive if the first string comes + * after the second. The NSPR implementation is not i18n. + */ + +PR_EXTERN(PRIntn) +PL_strncasecmp(const char *a, const char *b, PRUint32 max); + +/* + * PL_strchr + * + * Returns a pointer to the first instance of the specified character in the + * provided string. It returns null if the character is not found, or if the + * provided string is null. The character may be the null character. + */ + +PR_EXTERN(char *) +PL_strchr(const char *s, char c); + +/* + * PL_strrchr + * + * Returns a pointer to the last instance of the specified character in the + * provided string. It returns null if the character is not found, or if the + * provided string is null. The character may be the null character. + */ + +PR_EXTERN(char *) +PL_strrchr(const char *s, char c); + +/* + * PL_strnchr + * + * Returns a pointer to the first instance of the specified character within the + * first n characters of the provided string. It returns null if the character + * is not found, or if the provided string is null. The character may be the + * null character. + */ + +PR_EXTERN(char *) +PL_strnchr(const char *s, char c, PRUint32 n); + +/* + * PL_strnrchr + * + * Returns a pointer to the last instance of the specified character within the + * first n characters of the provided string. It returns null if the character is + * not found, or if the provided string is null. The character may be the null + * character. + */ + +PR_EXTERN(char *) +PL_strnrchr(const char *s, char c, PRUint32 n); + +/* + * NOTE: Looking for strcasechr, strcaserchr, strncasechr, or strncaserchr? + * Use strpbrk, strprbrk, strnpbrk or strnprbrk. + */ + +/* + * PL_strpbrk + * + * Returns a pointer to the first instance in the first string of any character + * (not including the terminating null character) of the second string. It returns + * null if either string is null. + */ + +PR_EXTERN(char *) +PL_strpbrk(const char *s, const char *list); + +/* + * PL_strprbrk + * + * Returns a pointer to the last instance in the first string of any character + * (not including the terminating null character) of the second string. It returns + * null if either string is null. + */ + +PR_EXTERN(char *) +PL_strprbrk(const char *s, const char *list); + +/* + * PL_strnpbrk + * + * Returns a pointer to the first instance (within the first n characters) of any + * character (not including the terminating null character) of the second string. + * It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strnpbrk(const char *s, const char *list, PRUint32 n); + +/* + * PL_strnprbrk + * + * Returns a pointer to the last instance (within the first n characters) of any + * character (not including the terminating null character) of the second string. + * It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strnprbrk(const char *s, const char *list, PRUint32 n); + +/* + * PL_strstr + * + * Returns a pointer to the first instance of the little string within the + * big one. It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strstr(const char *big, const char *little); + +/* + * PL_strrstr + * + * Returns a pointer to the last instance of the little string within the big one. + * It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strrstr(const char *big, const char *little); + +/* + * PL_strnstr + * + * Returns a pointer to the first instance of the little string within the first + * n characters of the big one. It returns null if either string is null. It + * returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strnstr(const char *big, const char *little, PRUint32 n); + +/* + * PL_strnrstr + * + * Returns a pointer to the last instance of the little string within the first + * n characters of the big one. It returns null if either string is null. It + * returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strnrstr(const char *big, const char *little, PRUint32 max); + +/* + * PL_strcasestr + * + * Returns a pointer to the first instance of the little string within the big one, + * ignoring case. It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strcasestr(const char *big, const char *little); + +/* + * PL_strcaserstr + * + * Returns a pointer to the last instance of the little string within the big one, + * ignoring case. It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strcaserstr(const char *big, const char *little); + +/* + * PL_strncasestr + * + * Returns a pointer to the first instance of the little string within the first + * n characters of the big one, ignoring case. It returns null if either string is + * null. It returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strncasestr(const char *big, const char *little, PRUint32 max); + +/* + * PL_strncaserstr + * + * Returns a pointer to the last instance of the little string within the first + * n characters of the big one, ignoring case. It returns null if either string is + * null. It returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strncaserstr(const char *big, const char *little, PRUint32 max); + +/* + * PL_strtok_r + * + * Splits the string s1 into tokens, separated by one or more characters + * from the separator string s2. The argument lasts points to a + * user-supplied char * pointer in which PL_strtok_r stores information + * for it to continue scanning the same string. + * + * In the first call to PL_strtok_r, s1 points to a string and the value + * of *lasts is ignored. PL_strtok_r returns a pointer to the first + * token, writes '\0' into the character following the first token, and + * updates *lasts. + * + * In subsequent calls, s1 is null and lasts must stay unchanged from the + * previous call. The separator string s2 may be different from call to + * call. PL_strtok_r returns a pointer to the next token in s1. When no + * token remains in s1, PL_strtok_r returns null. + */ + +PR_EXTERN(char *) +PL_strtok_r(char *s1, const char *s2, char **lasts); + +/* + * Things not (yet?) included: strspn/strcspn, strsep. + * memchr, memcmp, memcpy, memccpy, index, rindex, bcmp, bcopy, bzero. + * Any and all i18n/l10n stuff. + */ + +PR_END_EXTERN_C + +#endif /* _plstr_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/pratom.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/pratom.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/pratom.h @@ -0,0 +1,198 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* GLOBAL FUNCTIONS: +** DESCRIPTION: +** PR Atomic operations +*/ + +#ifndef pratom_h___ +#define pratom_h___ + +#include "prtypes.h" +#include "prlock.h" + +PR_BEGIN_EXTERN_C + +/* +** FUNCTION: PR_AtomicIncrement +** DESCRIPTION: +** Atomically increment a 32 bit value. +** INPUTS: +** val: a pointer to the value to increment +** RETURN: +** the returned value is the result of the increment +*/ +NSPR_API(PRInt32) PR_AtomicIncrement(PRInt32 *val); + +/* +** FUNCTION: PR_AtomicDecrement +** DESCRIPTION: +** Atomically decrement a 32 bit value. +** INPUTS: +** val: a pointer to the value to decrement +** RETURN: +** the returned value is the result of the decrement +*/ +NSPR_API(PRInt32) PR_AtomicDecrement(PRInt32 *val); + +/* +** FUNCTION: PR_AtomicSet +** DESCRIPTION: +** Atomically set a 32 bit value. +** INPUTS: +** val: A pointer to a 32 bit value to be set +** newval: The newvalue to assign to val +** RETURN: +** Returns the prior value +*/ +NSPR_API(PRInt32) PR_AtomicSet(PRInt32 *val, PRInt32 newval); + +/* +** FUNCTION: PR_AtomicAdd +** DESCRIPTION: +** Atomically add a 32 bit value. +** INPUTS: +** ptr: a pointer to the value to increment +** val: value to be added +** RETURN: +** the returned value is the result of the addition +*/ +NSPR_API(PRInt32) PR_AtomicAdd(PRInt32 *ptr, PRInt32 val); + +/* +** MACRO: PR_ATOMIC_INCREMENT +** MACRO: PR_ATOMIC_DECREMENT +** MACRO: PR_ATOMIC_SET +** MACRO: PR_ATOMIC_ADD +** DESCRIPTION: +** Macro versions of the atomic operations. They may be implemented +** as compiler intrinsics. +** +** IMPORTANT NOTE TO NSPR MAINTAINERS: +** Implement these macros with compiler intrinsics only on platforms +** where the PR_AtomicXXX functions are truly atomic (i.e., where the +** configuration macro _PR_HAVE_ATOMIC_OPS is defined). Otherwise, +** the macros and functions won't be compatible and can't be used +** interchangeably. +*/ +#if defined(_WIN32) && !defined(_WIN32_WCE) && \ + (!defined(_MSC_VER) || (_MSC_VER >= 1310)) + +#include + +#ifdef _MSC_VER +#pragma intrinsic(_InterlockedIncrement) +#pragma intrinsic(_InterlockedDecrement) +#pragma intrinsic(_InterlockedExchange) +#pragma intrinsic(_InterlockedExchangeAdd) +#endif + +#define PR_ATOMIC_INCREMENT(val) _InterlockedIncrement((long volatile *)(val)) +#define PR_ATOMIC_DECREMENT(val) _InterlockedDecrement((long volatile *)(val)) +#define PR_ATOMIC_SET(val, newval) \ + _InterlockedExchange((long volatile *)(val), (long)(newval)) +#define PR_ATOMIC_ADD(ptr, val) \ + (_InterlockedExchangeAdd((long volatile *)(ptr), (long)(val)) + (val)) + +#elif ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && \ + ((defined(__APPLE__) && \ + (defined(__ppc__) || defined(__i386__) || defined(__x86_64__))) || \ + (defined(__linux__) && \ + ((defined(__i386__) && \ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) || \ + defined(__ia64__) || defined(__x86_64__) || \ + defined(__powerpc__) || \ + (defined(__arm__) && \ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) || \ + defined(__aarch64__) || defined(__alpha) || \ + (defined(__mips__) && \ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4))))) + +/* + * Because the GCC manual warns that some processors may support + * reduced functionality of __sync_lock_test_and_set, we test for the + * processors that we believe support a full atomic exchange operation. + */ + +#define PR_ATOMIC_INCREMENT(val) __sync_add_and_fetch(val, 1) +#define PR_ATOMIC_DECREMENT(val) __sync_sub_and_fetch(val, 1) +#define PR_ATOMIC_SET(val, newval) __sync_lock_test_and_set(val, newval) +#define PR_ATOMIC_ADD(ptr, val) __sync_add_and_fetch(ptr, val) + +#else + +#define PR_ATOMIC_INCREMENT(val) PR_AtomicIncrement(val) +#define PR_ATOMIC_DECREMENT(val) PR_AtomicDecrement(val) +#define PR_ATOMIC_SET(val, newval) PR_AtomicSet(val, newval) +#define PR_ATOMIC_ADD(ptr, val) PR_AtomicAdd(ptr, val) + +#endif + +/* +** LIFO linked-list (stack) +*/ +typedef struct PRStackElemStr PRStackElem; + +struct PRStackElemStr { + PRStackElem *prstk_elem_next; /* next pointer MUST be at offset 0; + assembly language code relies on this */ +}; + +typedef struct PRStackStr PRStack; + +/* +** FUNCTION: PR_CreateStack +** DESCRIPTION: +** Create a stack, a LIFO linked list +** INPUTS: +** stack_name: a pointer to string containing the name of the stack +** RETURN: +** A pointer to the created stack, if successful, else NULL. +*/ +NSPR_API(PRStack *) PR_CreateStack(const char *stack_name); + +/* +** FUNCTION: PR_StackPush +** DESCRIPTION: +** Push an element on the top of the stack +** INPUTS: +** stack: pointer to the stack +** stack_elem: pointer to the stack element +** RETURN: +** None +*/ +NSPR_API(void) PR_StackPush(PRStack *stack, PRStackElem *stack_elem); + +/* +** FUNCTION: PR_StackPop +** DESCRIPTION: +** Remove the element on the top of the stack +** INPUTS: +** stack: pointer to the stack +** RETURN: +** A pointer to the stack element removed from the top of the stack, +** if non-empty, +** else NULL +*/ +NSPR_API(PRStackElem *) PR_StackPop(PRStack *stack); + +/* +** FUNCTION: PR_DestroyStack +** DESCRIPTION: +** Destroy the stack +** INPUTS: +** stack: pointer to the stack +** RETURN: +** PR_SUCCESS - if successfully deleted +** PR_FAILURE - if the stack is not empty +** PR_GetError will return +** PR_INVALID_STATE_ERROR - stack is not empty +*/ +NSPR_API(PRStatus) PR_DestroyStack(PRStack *stack); + +PR_END_EXTERN_C + +#endif /* pratom_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prbit.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prbit.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prbit.h @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prbit_h___ +#define prbit_h___ + +#include "prtypes.h" +PR_BEGIN_EXTERN_C + +/* +** Replace compare/jump/add/shift sequence with compiler built-in/intrinsic +** functions. +*/ +#if defined(_WIN32) && (_MSC_VER >= 1300) && \ + (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM)) +# include +# pragma intrinsic(_BitScanForward,_BitScanReverse) + __forceinline static int __prBitScanForward32(unsigned int val) + { + unsigned long idx; + _BitScanForward(&idx, (unsigned long)val); + return( (int)idx ); + } + __forceinline static int __prBitScanReverse32(unsigned int val) + { + unsigned long idx; + _BitScanReverse(&idx, (unsigned long)val); + return( (int)(31-idx) ); + } +# define pr_bitscan_ctz32(val) __prBitScanForward32(val) +# define pr_bitscan_clz32(val) __prBitScanReverse32(val) +# define PR_HAVE_BUILTIN_BITSCAN32 +#elif ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && \ + (defined(__i386__) || defined(__x86_64__) || defined(__arm__)) +# define pr_bitscan_ctz32(val) __builtin_ctz(val) +# define pr_bitscan_clz32(val) __builtin_clz(val) +# define PR_HAVE_BUILTIN_BITSCAN32 +#endif /* MSVC || GCC */ + +/* +** A prbitmap_t is a long integer that can be used for bitmaps +*/ +typedef unsigned long prbitmap_t; + +#define PR_TEST_BIT(_map,_bit) \ + ((_map)[(_bit)>>PR_BITS_PER_LONG_LOG2] & (1L << ((_bit) & (PR_BITS_PER_LONG-1)))) +#define PR_SET_BIT(_map,_bit) \ + ((_map)[(_bit)>>PR_BITS_PER_LONG_LOG2] |= (1L << ((_bit) & (PR_BITS_PER_LONG-1)))) +#define PR_CLEAR_BIT(_map,_bit) \ + ((_map)[(_bit)>>PR_BITS_PER_LONG_LOG2] &= ~(1L << ((_bit) & (PR_BITS_PER_LONG-1)))) + +/* +** Compute the log of the least power of 2 greater than or equal to n +*/ +NSPR_API(PRIntn) PR_CeilingLog2(PRUint32 i); + +/* +** Compute the log of the greatest power of 2 less than or equal to n +*/ +NSPR_API(PRIntn) PR_FloorLog2(PRUint32 i); + +/* +** Macro version of PR_CeilingLog2: Compute the log of the least power of +** 2 greater than or equal to _n. The result is returned in _log2. +*/ +#ifdef PR_HAVE_BUILTIN_BITSCAN32 +#define PR_CEILING_LOG2(_log2,_n) \ + PR_BEGIN_MACRO \ + PRUint32 j_ = (PRUint32)(_n); \ + (_log2) = (j_ <= 1 ? 0 : 32 - pr_bitscan_clz32(j_ - 1)); \ + PR_END_MACRO +#else +#define PR_CEILING_LOG2(_log2,_n) \ + PR_BEGIN_MACRO \ + PRUint32 j_ = (PRUint32)(_n); \ + (_log2) = 0; \ + if ((j_) & ((j_)-1)) \ + (_log2) += 1; \ + if ((j_) >> 16) \ + (_log2) += 16, (j_) >>= 16; \ + if ((j_) >> 8) \ + (_log2) += 8, (j_) >>= 8; \ + if ((j_) >> 4) \ + (_log2) += 4, (j_) >>= 4; \ + if ((j_) >> 2) \ + (_log2) += 2, (j_) >>= 2; \ + if ((j_) >> 1) \ + (_log2) += 1; \ + PR_END_MACRO +#endif /* PR_HAVE_BUILTIN_BITSCAN32 */ + +/* +** Macro version of PR_FloorLog2: Compute the log of the greatest power of +** 2 less than or equal to _n. The result is returned in _log2. +** +** This is equivalent to finding the highest set bit in the word. +*/ +#ifdef PR_HAVE_BUILTIN_BITSCAN32 +#define PR_FLOOR_LOG2(_log2,_n) \ + PR_BEGIN_MACRO \ + PRUint32 j_ = (PRUint32)(_n); \ + (_log2) = 31 - pr_bitscan_clz32((j_) | 1); \ + PR_END_MACRO +#else +#define PR_FLOOR_LOG2(_log2,_n) \ + PR_BEGIN_MACRO \ + PRUint32 j_ = (PRUint32)(_n); \ + (_log2) = 0; \ + if ((j_) >> 16) \ + (_log2) += 16, (j_) >>= 16; \ + if ((j_) >> 8) \ + (_log2) += 8, (j_) >>= 8; \ + if ((j_) >> 4) \ + (_log2) += 4, (j_) >>= 4; \ + if ((j_) >> 2) \ + (_log2) += 2, (j_) >>= 2; \ + if ((j_) >> 1) \ + (_log2) += 1; \ + PR_END_MACRO +#endif /* PR_HAVE_BUILTIN_BITSCAN32 */ + +/* +** Macros for rotate left and right. The argument 'a' must be an unsigned +** 32-bit integer type such as PRUint32. +** +** There is no rotate operation in the C Language, so the construct +** (a << 4) | (a >> 28) is frequently used instead. Most compilers convert +** this to a rotate instruction, but MSVC doesn't without a little help. +** To get MSVC to generate a rotate instruction, we have to use the _rotl +** or _rotr intrinsic and use a pragma to make it inline. +** +** Note: MSVC in VS2005 will do an inline rotate instruction on the above +** construct. +*/ + +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || \ + defined(_M_X64) || defined(_M_ARM)) +#include +#pragma intrinsic(_rotl, _rotr) +#define PR_ROTATE_LEFT32(a, bits) _rotl(a, bits) +#define PR_ROTATE_RIGHT32(a, bits) _rotr(a, bits) +#else +#define PR_ROTATE_LEFT32(a, bits) (((a) << (bits)) | ((a) >> (32 - (bits)))) +#define PR_ROTATE_RIGHT32(a, bits) (((a) >> (bits)) | ((a) << (32 - (bits)))) +#endif + +PR_END_EXTERN_C +#endif /* prbit_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prclist.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prclist.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prclist.h @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prclist_h___ +#define prclist_h___ + +#include "prtypes.h" + +typedef struct PRCListStr PRCList; + +/* +** Circular linked list +*/ +struct PRCListStr { + PRCList *next; + PRCList *prev; +}; + +/* +** Insert element "_e" into the list, before "_l". +*/ +#define PR_INSERT_BEFORE(_e,_l) \ + PR_BEGIN_MACRO \ + (_e)->next = (_l); \ + (_e)->prev = (_l)->prev; \ + (_l)->prev->next = (_e); \ + (_l)->prev = (_e); \ + PR_END_MACRO + +/* +** Insert element "_e" into the list, after "_l". +*/ +#define PR_INSERT_AFTER(_e,_l) \ + PR_BEGIN_MACRO \ + (_e)->next = (_l)->next; \ + (_e)->prev = (_l); \ + (_l)->next->prev = (_e); \ + (_l)->next = (_e); \ + PR_END_MACRO + +/* +** Return the element following element "_e" +*/ +#define PR_NEXT_LINK(_e) \ + ((_e)->next) +/* +** Return the element preceding element "_e" +*/ +#define PR_PREV_LINK(_e) \ + ((_e)->prev) + +/* +** Append an element "_e" to the end of the list "_l" +*/ +#define PR_APPEND_LINK(_e,_l) PR_INSERT_BEFORE(_e,_l) + +/* +** Insert an element "_e" at the head of the list "_l" +*/ +#define PR_INSERT_LINK(_e,_l) PR_INSERT_AFTER(_e,_l) + +/* Return the head/tail of the list */ +#define PR_LIST_HEAD(_l) (_l)->next +#define PR_LIST_TAIL(_l) (_l)->prev + +/* +** Remove the element "_e" from it's circular list. +*/ +#define PR_REMOVE_LINK(_e) \ + PR_BEGIN_MACRO \ + (_e)->prev->next = (_e)->next; \ + (_e)->next->prev = (_e)->prev; \ + PR_END_MACRO + +/* +** Remove the element "_e" from it's circular list. Also initializes the +** linkage. +*/ +#define PR_REMOVE_AND_INIT_LINK(_e) \ + PR_BEGIN_MACRO \ + (_e)->prev->next = (_e)->next; \ + (_e)->next->prev = (_e)->prev; \ + (_e)->next = (_e); \ + (_e)->prev = (_e); \ + PR_END_MACRO + +/* +** Return non-zero if the given circular list "_l" is empty, zero if the +** circular list is not empty +*/ +#define PR_CLIST_IS_EMPTY(_l) \ + ((_l)->next == (_l)) + +/* +** Initialize a circular list +*/ +#define PR_INIT_CLIST(_l) \ + PR_BEGIN_MACRO \ + (_l)->next = (_l); \ + (_l)->prev = (_l); \ + PR_END_MACRO + +#define PR_INIT_STATIC_CLIST(_l) \ + {(_l), (_l)} + +#endif /* prclist_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prcmon.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prcmon.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prcmon.h @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prcmon_h___ +#define prcmon_h___ + +/* +** Interface to cached monitors. Cached monitors use an address to find a +** given PR monitor. In this way a monitor can be associated with another +** object without preallocating a monitor for all objects. +** +** A hash table is used to quickly map addresses to individual monitors +** and the system automatically grows the hash table as needed. +** +** Cache monitors are about 5 times slower to use than uncached monitors. +*/ +#include "prmon.h" +#include "prinrval.h" + +PR_BEGIN_EXTERN_C + +/** +** Like PR_EnterMonitor except use the "address" to find a monitor in the +** monitor cache. If successful, returns the PRMonitor now associated +** with "address". Note that you must PR_CExitMonitor the address to +** release the monitor cache entry (otherwise the monitor cache will fill +** up). This call will return NULL if the monitor cache needs to be +** expanded and the system is out of memory. +*/ +NSPR_API(PRMonitor*) PR_CEnterMonitor(void *address); + +/* +** Like PR_ExitMonitor except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CExitMonitor(void *address); + +/* +** Like PR_Wait except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CWait(void *address, PRIntervalTime timeout); + +/* +** Like PR_Notify except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CNotify(void *address); + +/* +** Like PR_NotifyAll except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CNotifyAll(void *address); + +/* +** Set a callback to be invoked each time a monitor is recycled from the cache +** freelist, with the monitor's cache-key passed in address. +*/ +NSPR_API(void) PR_CSetOnMonitorRecycle(void (PR_CALLBACK *callback)(void *address)); + +PR_END_EXTERN_C + +#endif /* prcmon_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prcountr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prcountr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prcountr.h @@ -0,0 +1,525 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prcountr_h___ +#define prcountr_h___ + +/*---------------------------------------------------------------------------- +** prcountr.h -- NSPR Instrumentation counters +** +** The NSPR Counter Feature provides a means to "count +** something." Counters can be dynamically defined, incremented, +** decremented, set, and deleted under application program +** control. +** +** The Counter Feature is intended to be used as instrumentation, +** not as operational data. If you need a counter for operational +** data, use native integral types. +** +** Counters are 32bit unsigned intergers. On overflow, a counter +** will wrap. No exception is recognized or reported. +** +** A counter can be dynamically created using a two level naming +** convention. A "handle" is returned when the counter is +** created. The counter can subsequently be addressed by its +** handle. An API is provided to get an existing counter's handle +** given the names with which it was originally created. +** Similarly, a counter's name can be retrieved given its handle. +** +** The counter naming convention is a two-level hierarchy. The +** QName is the higher level of the hierarchy; RName is the +** lower level. RNames can be thought of as existing within a +** QName. The same RName can exist within multiple QNames. QNames +** are unique. The NSPR Counter is not a near-zero overhead +** feature. Application designers should be aware of +** serialization issues when using the Counter API. Creating a +** counter locks a large asset, potentially causing a stall. This +** suggest that applications should create counters at component +** initialization, for example, and not create and destroy them +** willy-nilly. ... You have been warned. +** +** Incrementing and Adding to counters uses atomic operations. +** The performance of these operations will vary from platform +** to platform. On platforms where atomic operations are not +** supported the overhead may be substantial. +** +** When traversing the counter database with FindNext functions, +** the instantaneous values of any given counter is that at the +** moment of extraction. The state of the entire counter database +** may not be viewed as atomic. +** +** The counter interface may be disabled (No-Op'd) at compile +** time. When DEBUG is defined at compile time, the Counter +** Feature is compiled into NSPR and applications invoking it. +** When DEBUG is not defined, the counter macros compile to +** nothing. To force the Counter Feature to be compiled into an +** optimized build, define FORCE_NSPR_COUNTERS at compile time +** for both NSPR and the application intending to use it. +** +** Application designers should use the macro form of the Counter +** Feature methods to minimize performance impact in optimized +** builds. The macros normally compile to nothing on optimized +** builds. +** +** Application designers should be aware of the effects of +** debug and optimized build differences when using result of the +** Counter Feature macros in expressions. +** +** The Counter Feature is thread-safe and SMP safe. +** +** /lth. 09-Jun-1998. +*/ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** Opaque counter handle type. +** ... don't even think of looking in here. +** +*/ +typedef void * PRCounterHandle; + +#define PRCOUNTER_NAME_MAX 31 +#define PRCOUNTER_DESC_MAX 255 + + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DEFINE_COUNTER() -- Define a PRCounterHandle +** +** DESCRIPTION: PR_DEFINE_COUNTER() is used to define a counter +** handle. +** +*/ +#define PR_DEFINE_COUNTER(name) PRCounterHandle name + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_INIT_COUNTER_HANDLE() -- Set the value of a PRCounterHandle +** +** DESCRIPTION: +** PR_INIT_COUNTER_HANDLE() sets the value of a PRCounterHandle +** to value. +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_INIT_COUNTER_HANDLE(handle,value)\ + (handle) = (PRCounterHandle)(value) +#else +#define PR_INIT_COUNTER_HANDLE(handle,value) +#endif + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_CreateCounter() -- Create a counter +** +** DESCRIPTION: PR_CreateCounter() creates a counter object and +** initializes it to zero. +** +** The macro form takes as its first argument the name of the +** PRCounterHandle to receive the handle returned from +** PR_CreateCounter(). +** +** INPUTS: +** qName: The QName for the counter object. The maximum length +** of qName is defined by PRCOUNTER_NAME_MAX +** +** rName: The RName for the counter object. The maximum length +** of qName is defined by PRCOUNTER_NAME_MAX +** +** descrioption: The description of the counter object. The +** maximum length of description is defined by +** PRCOUNTER_DESC_MAX. +** +** OUTPUTS: +** +** RETURNS: +** PRCounterHandle. +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_CREATE_COUNTER(handle,qName,rName,description)\ + (handle) = PR_CreateCounter((qName),(rName),(description)) +#else +#define PR_CREATE_COUNTER(handle,qName,rName,description) +#endif + +NSPR_API(PRCounterHandle) + PR_CreateCounter( + const char *qName, + const char *rName, + const char *description +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DestroyCounter() -- Destroy a counter object. +** +** DESCRIPTION: PR_DestroyCounter() removes a counter and +** unregisters its handle from the counter database. +** +** INPUTS: +** handle: the PRCounterHandle of the counter to be destroyed. +** +** OUTPUTS: +** The counter is destroyed. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_DESTROY_COUNTER(handle) PR_DestroyCounter((handle)) +#else +#define PR_DESTROY_COUNTER(handle) +#endif + +NSPR_API(void) + PR_DestroyCounter( + PRCounterHandle handle +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetCounterHandleFromName() -- Retreive a +** counter's handle give its name. +** +** DESCRIPTION: PR_GetCounterHandleFromName() retreives a +** counter's handle from the counter database, given the name +** the counter was originally created with. +** +** INPUTS: +** qName: Counter's original QName. +** rName: Counter's original RName. +** +** OUTPUTS: +** +** RETURNS: +** PRCounterHandle or PRCounterError. +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_GET_COUNTER_HANDLE_FROM_NAME(handle,qName,rName)\ + (handle) = PR_GetCounterHandleFromName((qName),(rName)) +#else +#define PR_GET_COUNTER_HANDLE_FROM_NAME(handle,qName,rName) +#endif + +NSPR_API(PRCounterHandle) + PR_GetCounterHandleFromName( + const char *qName, + const char *rName +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetCounterNameFromHandle() -- Retreive a +** counter's name, given its handle. +** +** DESCRIPTION: PR_GetCounterNameFromHandle() retreives a +** counter's name given its handle. +** +** INPUTS: +** qName: Where to store a pointer to qName. +** rName: Where to store a pointer to rName. +** description: Where to store a pointer to description. +** +** OUTPUTS: Pointers to the Counter Feature's copies of the names +** used when the counters were created. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_GET_COUNTER_NAME_FROM_HANDLE(handle,qName,rName,description)\ + PR_GetCounterNameFromHandle((handle),(qName),(rName),(description)) +#else +#define PR_GET_COUNTER_NAME_FROM_HANDLE(handle,qName,rName,description ) +#endif + +NSPR_API(void) + PR_GetCounterNameFromHandle( + PRCounterHandle handle, + const char **qName, + const char **rName, + const char **description +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_IncrementCounter() -- Add one to the referenced +** counter. +** +** DESCRIPTION: Add one to the referenced counter. +** +** INPUTS: +** handle: The PRCounterHandle of the counter to be incremented +** +** OUTPUTS: The counter is incrementd. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_INCREMENT_COUNTER(handle) PR_IncrementCounter(handle) +#else +#define PR_INCREMENT_COUNTER(handle) +#endif + +NSPR_API(void) + PR_IncrementCounter( + PRCounterHandle handle +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DecrementCounter() -- Subtract one from the +** referenced counter +** +** DESCRIPTION: Subtract one from the referenced counter. +** +** INPUTS: +** handle: The PRCounterHandle of the coutner to be +** decremented. +** +** OUTPUTS: the counter is decremented. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_DECREMENT_COUNTER(handle) PR_DecrementCounter(handle) +#else +#define PR_DECREMENT_COUNTER(handle) +#endif + +NSPR_API(void) + PR_DecrementCounter( + PRCounterHandle handle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_AddToCounter() -- Add a value to a counter. +** +** DESCRIPTION: Add value to the counter referenced by handle. +** +** INPUTS: +** handle: the PRCounterHandle of the counter to be added to. +** +** value: the value to be added to the counter. +** +** OUTPUTS: new value for counter. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_ADD_TO_COUNTER(handle,value)\ + PR_AddToCounter((handle),(value)) +#else +#define PR_ADD_TO_COUNTER(handle,value) +#endif + +NSPR_API(void) + PR_AddToCounter( + PRCounterHandle handle, + PRUint32 value +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_SubtractFromCounter() -- A value is subtracted +** from a counter. +** +** DESCRIPTION: +** Subtract a value from a counter. +** +** INPUTS: +** handle: the PRCounterHandle of the counter to be subtracted +** from. +** +** value: the value to be subtracted from the counter. +** +** OUTPUTS: new value for counter +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_SUBTRACT_FROM_COUNTER(handle,value)\ + PR_SubtractFromCounter((handle),(value)) +#else +#define PR_SUBTRACT_FROM_COUNTER(handle,value) +#endif + +NSPR_API(void) + PR_SubtractFromCounter( + PRCounterHandle handle, + PRUint32 value +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetCounter() -- Retreive the value of a counter +** +** DESCRIPTION: +** Retreive the value of a counter. +** +** INPUTS: +** handle: the PR_CounterHandle of the counter to be retreived +** +** OUTPUTS: +** +** RETURNS: The value of the referenced counter +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_GET_COUNTER(counter,handle)\ + (counter) = PR_GetCounter((handle)) +#else +#define PR_GET_COUNTER(counter,handle) 0 +#endif + +NSPR_API(PRUint32) + PR_GetCounter( + PRCounterHandle handle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_SetCounter() -- Replace the content of counter +** with value. +** +** DESCRIPTION: The contents of the referenced counter are +** replaced by value. +** +** INPUTS: +** handle: the PRCounterHandle of the counter whose contents +** are to be replaced. +** +** value: the new value of the counter. +** +** OUTPUTS: +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_SET_COUNTER(handle,value) PR_SetCounter((handle),(value)) +#else +#define PR_SET_COUNTER(handle,value) +#endif + +NSPR_API(void) + PR_SetCounter( + PRCounterHandle handle, + PRUint32 value +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextCounterQname() -- Retreive the next QName counter +** handle iterator +** +** DESCRIPTION: +** PR_FindNextCounterQname() retreives the first or next Qname +** the counter data base, depending on the value of handle. When +** handle is NULL, the function attempts to retreive the first +** QName handle in the database. When handle is a handle previosly +** retreived QName handle, then the function attempts to retreive +** the next QName handle. +** +** INPUTS: +** handle: PRCounterHandle or NULL. +** +** OUTPUTS: returned +** +** RETURNS: PRCounterHandle or NULL when no more QName counter +** handles are present. +** +** RESTRICTIONS: +** A concurrent PR_CreateCounter() or PR_DestroyCounter() may +** cause unpredictable results. +** +** A PRCounterHandle returned from this function may only be used +** in another PR_FindNextCounterQname() function call; other +** operations may cause unpredictable results. +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_FIND_NEXT_COUNTER_QNAME(next,handle)\ + (next) = PR_FindNextCounterQname((handle)) +#else +#define PR_FIND_NEXT_COUNTER_QNAME(next,handle) NULL +#endif + +NSPR_API(PRCounterHandle) + PR_FindNextCounterQname( + PRCounterHandle handle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextCounterRname() -- Retreive the next RName counter +** handle iterator +** +** DESCRIPTION: +** PR_FindNextCounterRname() retreives the first or next RNname +** handle from the counter data base, depending on the +** value of handle. When handle is NULL, the function attempts to +** retreive the first RName handle in the database. When handle is +** a handle previosly retreived RName handle, then the function +** attempts to retreive the next RName handle. +** +** INPUTS: +** handle: PRCounterHandle or NULL. +** qhandle: PRCounterHandle of a previously aquired via +** PR_FIND_NEXT_QNAME_HANDLE() +** +** OUTPUTS: returned +** +** RETURNS: PRCounterHandle or NULL when no more RName counter +** handles are present. +** +** RESTRICTIONS: +** A concurrent PR_CreateCounter() or PR_DestroyCounter() may +** cause unpredictable results. +** +** A PRCounterHandle returned from this function may only be used +** in another PR_FindNextCounterRname() function call; other +** operations may cause unpredictable results. +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_FIND_NEXT_COUNTER_RNAME(next,rhandle,qhandle)\ + (next) = PR_FindNextCounterRname((rhandle),(qhandle)) +#else +#define PR_FIND_NEXT_COUNTER_RNAME(next,rhandle,qhandle) +#endif + +NSPR_API(PRCounterHandle) + PR_FindNextCounterRname( + PRCounterHandle rhandle, + PRCounterHandle qhandle +); + +PR_END_EXTERN_C + +#endif /* prcountr_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prcpucfg.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prcpucfg.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prcpucfg.h @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef NSPR_PRCPUCFG_H_ +#define NSPR_PRCPUCFG_H_ + +/* + * Need to support conditionals that are defined in both the top-level build + * system as well as NSS' build system for now. + */ +#if defined(XP_DARWIN) || defined(DARWIN) +#include "md/_darwin.cfg" +#elif defined(XP_WIN) || defined(_WINDOWS) +#include "md/_win95.cfg" +#elif defined(__FreeBSD__) +#include "md/_freebsd.cfg" +#elif defined(__NetBSD__) +#include "md/_netbsd.cfg" +#elif defined(__OpenBSD__) +#include "md/_openbsd.cfg" +#elif defined(__linux__) +#include "md/_linux.cfg" +#elif defined(__sun__) +#include "md/_solaris.cfg" +#else +#error "Unsupported platform!" +#endif + +#endif /* NSPR_PRCPUCFG_H_ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prcvar.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prcvar.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prcvar.h @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prcvar_h___ +#define prcvar_h___ + +#include "prlock.h" +#include "prinrval.h" + +PR_BEGIN_EXTERN_C + +typedef struct PRCondVar PRCondVar; + +/* +** Create a new condition variable. +** +** "lock" is the lock used to protect the condition variable. +** +** Condition variables are synchronization objects that threads can use +** to wait for some condition to occur. +** +** This may fail if memory is tight or if some operating system resource +** is low. In such cases, a NULL will be returned. +*/ +NSPR_API(PRCondVar*) PR_NewCondVar(PRLock *lock); + +/* +** Destroy a condition variable. There must be no thread +** waiting on the condvar. The caller is responsible for guaranteeing +** that the condvar is no longer in use. +** +*/ +NSPR_API(void) PR_DestroyCondVar(PRCondVar *cvar); + +/* +** The thread that waits on a condition is blocked in a "waiting on +** condition" state until another thread notifies the condition or a +** caller specified amount of time expires. The lock associated with +** the condition variable will be released, which must have be held +** prior to the call to wait. +** +** Logically a notified thread is moved from the "waiting on condition" +** state and made "ready." When scheduled, it will attempt to reacquire +** the lock that it held when wait was called. +** +** The timeout has two well known values, PR_INTERVAL_NO_TIMEOUT and +** PR_INTERVAL_NO_WAIT. The former value requires that a condition be +** notified (or the thread interrupted) before it will resume from the +** wait. If the timeout has a value of PR_INTERVAL_NO_WAIT, the effect +** is to release the lock, possibly causing a rescheduling within the +** runtime, then immediately attempting to reacquire the lock and resume. +** +** Any other value for timeout will cause the thread to be rescheduled +** either due to explicit notification or an expired interval. The latter +** must be determined by treating time as one part of the monitored data +** being protected by the lock and tested explicitly for an expired +** interval. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable or the thread was interrupted (PR_Interrupt()). +** The particular reason can be extracted with PR_GetError(). +*/ +NSPR_API(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout); + +/* +** Notify ONE thread that is currently waiting on 'cvar'. Which thread is +** dependent on the implementation of the runtime. Common sense would dictate +** that all threads waiting on a single condition have identical semantics, +** therefore which one gets notified is not significant. +** +** The calling thead must hold the lock that protects the condition, as +** well as the invariants that are tightly bound to the condition, when +** notify is called. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable. +*/ +NSPR_API(PRStatus) PR_NotifyCondVar(PRCondVar *cvar); + +/* +** Notify all of the threads waiting on the condition variable. The order +** that the threads are notified is indeterminant. The lock that protects +** the condition must be held. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable. +*/ +NSPR_API(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar); + +PR_END_EXTERN_C + +#endif /* prcvar_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prdtoa.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prdtoa.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prdtoa.h @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prdtoa_h___ +#define prdtoa_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** PR_strtod() returns as a double-precision floating-point number +** the value represented by the character string pointed to by +** s00. The string is scanned up to the first unrecognized +** character. +**a +** If the value of se is not (char **)NULL, a pointer to +** the character terminating the scan is returned in the location pointed +** to by se. If no number can be formed, se is set to s00, and +** zero is returned. +*/ +NSPR_API(PRFloat64) +PR_strtod(const char *s00, char **se); + +/* +** PR_cnvtf() +** conversion routines for floating point +** prcsn - number of digits of precision to generate floating +** point value. +*/ +NSPR_API(void) PR_cnvtf(char *buf, PRIntn bufsz, PRIntn prcsn, PRFloat64 fval); + +/* +** PR_dtoa() converts double to a string. +** +** ARGUMENTS: +** If rve is not null, *rve is set to point to the end of the return value. +** If d is +-Infinity or NaN, then *decpt is set to 9999. +** +** mode: +** 0 ==> shortest string that yields d when read in +** and rounded to nearest. +*/ +NSPR_API(PRStatus) PR_dtoa(PRFloat64 d, PRIntn mode, PRIntn ndigits, + PRIntn *decpt, PRIntn *sign, char **rve, char *buf, PRSize bufsize); + +PR_END_EXTERN_C + +#endif /* prdtoa_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prenv.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prenv.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prenv.h @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prenv_h___ +#define prenv_h___ + +#include "prtypes.h" + +/*******************************************************************************/ +/*******************************************************************************/ +/****************** THESE FUNCTIONS MAY NOT BE THREAD SAFE *********************/ +/*******************************************************************************/ +/*******************************************************************************/ + +PR_BEGIN_EXTERN_C + +/* +** PR_GetEnv() -- Retrieve value of environment variable +** +** Description: +** PR_GetEnv() is modeled on Unix getenv(). +** +** +** Inputs: +** var -- The name of the environment variable +** +** Returns: +** The value of the environment variable 'var' or NULL if +** the variable is undefined. +** +** Restrictions: +** You'd think that a POSIX getenv(), putenv() would be +** consistently implemented everywhere. Surprise! It is not. On +** some platforms, a putenv() where the argument is of +** the form "name" causes the named environment variable to +** be un-set; that is: a subsequent getenv() returns NULL. On +** other platforms, the putenv() fails, on others, it is a +** no-op. Similarly, a putenv() where the argument is of the +** form "name=" causes the named environment variable to be +** un-set; a subsequent call to getenv() returns NULL. On +** other platforms, a subsequent call to getenv() returns a +** pointer to a null-string (a byte of zero). +** +** PR_GetEnv(), PR_SetEnv() provide a consistent behavior +** across all supported platforms. There are, however, some +** restrictions and some practices you must use to achieve +** consistent results everywhere. +** +** When manipulating the environment there is no way to un-set +** an environment variable across all platforms. We suggest +** you interpret the return of a pointer to null-string to +** mean the same as a return of NULL from PR_GetEnv(). +** +** A call to PR_SetEnv() where the parameter is of the form +** "name" will return PR_FAILURE; the environment remains +** unchanged. A call to PR_SetEnv() where the parameter is +** of the form "name=" may un-set the envrionment variable on +** some platforms; on others it may set the value of the +** environment variable to the null-string. +** +** For example, to test for NULL return or return of the +** null-string from PR_GetEnv(), use the following code +** fragment: +** +** char *val = PR_GetEnv("foo"); +** if ((NULL == val) || ('\0' == *val)) { +** ... interpret this as un-set ... +** } +** +** The caller must ensure that the string passed +** to PR_SetEnv() is persistent. That is: The string should +** not be on the stack, where it can be overwritten +** on return from the function calling PR_SetEnv(). +** Similarly, the string passed to PR_SetEnv() must not be +** overwritten by other actions of the process. ... Some +** platforms use the string by reference rather than copying +** it into the environment space. ... You have been warned! +** +** Use of platform-native functions that manipulate the +** environment (getenv(), putenv(), +** SetEnvironmentVariable(), etc.) must not be used with +** NSPR's similar functions. The platform-native functions +** may not be thread safe and/or may operate on different +** conceptual environment space than that operated upon by +** NSPR's functions or other environment manipulating +** functions on the same platform. (!) +** +*/ +NSPR_API(char*) PR_GetEnv(const char *var); + +/* +** PR_GetEnvSecure() -- get a security-sensitive environment variable +** +** Description: +** +** PR_GetEnvSecure() is similar to PR_GetEnv(), but it returns NULL if +** the program was run with elevated privilege (e.g., setuid or setgid +** on Unix). This can be used for cases like log file paths which +** could otherwise be used for privilege escalation. Note that some +** platforms may have platform-specific privilege elevation mechanisms +** not recognized by this function; see the implementation for details. +*/ +NSPR_API(char*) PR_GetEnvSecure(const char *var); + +/* +** PR_SetEnv() -- set, unset or change an environment variable +** +** Description: +** PR_SetEnv() is modeled on the Unix putenv() function. +** +** Inputs: +** string -- pointer to a caller supplied +** constant, persistent string of the form name=value. Where +** name is the name of the environment variable to be set or +** changed; value is the value assigned to the variable. +** +** Returns: +** PRStatus. +** +** Restrictions: +** See the Restrictions documented in the description of +** PR_GetEnv() in this header file. +** +** +*/ +NSPR_API(PRStatus) PR_SetEnv(const char *string); + +/* +** PR_DuplicateEnvironment() -- Obtain a copy of the environment. +** +** Description: +** PR_DuplicateEnvironment() copies the environment so that it can be +** modified without changing the current process's environment, and +** then passed to interfaces such as POSIX execve(). In particular, +** this avoids needing to allocate memory or take locks in the child +** after a fork(); neither of these is allowed by POSIX after a +** multithreaded process calls fork(), and PR_SetEnv does both. +** +** Inputs: +** none +** +** Returns: +** A pointer to a null-terminated array of null-terminated strings, +** like the traditional global variable "environ". The array and +** the strings are allocated with PR_Malloc(), and it is the +** caller's responsibility to free them. +** +** In case of memory allocation failure, or if the operating system +** doesn't support reading the entire environment through the global +** variable "environ" or similar, returns NULL instead. +** +** Restrictions: +** Similarly to PR_GetEnv(), this function may not interoperate as +** expected with the operating system's native environment accessors. +*/ +NSPR_API(char **) PR_DuplicateEnvironment(void); + +PR_END_EXTERN_C + +#endif /* prenv_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prerr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prerr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prerr.h @@ -0,0 +1,249 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prerr_h___ +#define prerr_h___ + +/* + * + * prerr.h + * This file is automatically generated; please do not edit it. + */ + +/* Memory allocation attempt failed */ +#define PR_OUT_OF_MEMORY_ERROR (-6000L) + +/* Invalid file descriptor */ +#define PR_BAD_DESCRIPTOR_ERROR (-5999L) + +/* The operation would have blocked */ +#define PR_WOULD_BLOCK_ERROR (-5998L) + +/* Invalid memory address argument */ +#define PR_ACCESS_FAULT_ERROR (-5997L) + +/* Invalid function for file type */ +#define PR_INVALID_METHOD_ERROR (-5996L) + +/* Invalid memory address argument */ +#define PR_ILLEGAL_ACCESS_ERROR (-5995L) + +/* Some unknown error has occurred */ +#define PR_UNKNOWN_ERROR (-5994L) + +/* Operation interrupted by another thread */ +#define PR_PENDING_INTERRUPT_ERROR (-5993L) + +/* function not implemented */ +#define PR_NOT_IMPLEMENTED_ERROR (-5992L) + +/* I/O function error */ +#define PR_IO_ERROR (-5991L) + +/* I/O operation timed out */ +#define PR_IO_TIMEOUT_ERROR (-5990L) + +/* I/O operation on busy file descriptor */ +#define PR_IO_PENDING_ERROR (-5989L) + +/* The directory could not be opened */ +#define PR_DIRECTORY_OPEN_ERROR (-5988L) + +/* Invalid function argument */ +#define PR_INVALID_ARGUMENT_ERROR (-5987L) + +/* Network address not available (in use?) */ +#define PR_ADDRESS_NOT_AVAILABLE_ERROR (-5986L) + +/* Network address type not supported */ +#define PR_ADDRESS_NOT_SUPPORTED_ERROR (-5985L) + +/* Already connected */ +#define PR_IS_CONNECTED_ERROR (-5984L) + +/* Network address is invalid */ +#define PR_BAD_ADDRESS_ERROR (-5983L) + +/* Local Network address is in use */ +#define PR_ADDRESS_IN_USE_ERROR (-5982L) + +/* Connection refused by peer */ +#define PR_CONNECT_REFUSED_ERROR (-5981L) + +/* Network address is presently unreachable */ +#define PR_NETWORK_UNREACHABLE_ERROR (-5980L) + +/* Connection attempt timed out */ +#define PR_CONNECT_TIMEOUT_ERROR (-5979L) + +/* Network file descriptor is not connected */ +#define PR_NOT_CONNECTED_ERROR (-5978L) + +/* Failure to load dynamic library */ +#define PR_LOAD_LIBRARY_ERROR (-5977L) + +/* Failure to unload dynamic library */ +#define PR_UNLOAD_LIBRARY_ERROR (-5976L) + +/* Symbol not found in any of the loaded dynamic libraries */ +#define PR_FIND_SYMBOL_ERROR (-5975L) + +/* Insufficient system resources */ +#define PR_INSUFFICIENT_RESOURCES_ERROR (-5974L) + +/* A directory lookup on a network address has failed */ +#define PR_DIRECTORY_LOOKUP_ERROR (-5973L) + +/* Attempt to access a TPD key that is out of range */ +#define PR_TPD_RANGE_ERROR (-5972L) + +/* Process open FD table is full */ +#define PR_PROC_DESC_TABLE_FULL_ERROR (-5971L) + +/* System open FD table is full */ +#define PR_SYS_DESC_TABLE_FULL_ERROR (-5970L) + +/* Network operation attempted on non-network file descriptor */ +#define PR_NOT_SOCKET_ERROR (-5969L) + +/* TCP-specific function attempted on a non-TCP file descriptor */ +#define PR_NOT_TCP_SOCKET_ERROR (-5968L) + +/* TCP file descriptor is already bound */ +#define PR_SOCKET_ADDRESS_IS_BOUND_ERROR (-5967L) + +/* Access Denied */ +#define PR_NO_ACCESS_RIGHTS_ERROR (-5966L) + +/* The requested operation is not supported by the platform */ +#define PR_OPERATION_NOT_SUPPORTED_ERROR (-5965L) + +/* The host operating system does not support the protocol requested */ +#define PR_PROTOCOL_NOT_SUPPORTED_ERROR (-5964L) + +/* Access to the remote file has been severed */ +#define PR_REMOTE_FILE_ERROR (-5963L) + +/* The value requested is too large to be stored in the data buffer provided */ +#define PR_BUFFER_OVERFLOW_ERROR (-5962L) + +/* TCP connection reset by peer */ +#define PR_CONNECT_RESET_ERROR (-5961L) + +/* Unused */ +#define PR_RANGE_ERROR (-5960L) + +/* The operation would have deadlocked */ +#define PR_DEADLOCK_ERROR (-5959L) + +/* The file is already locked */ +#define PR_FILE_IS_LOCKED_ERROR (-5958L) + +/* Write would result in file larger than the system allows */ +#define PR_FILE_TOO_BIG_ERROR (-5957L) + +/* The device for storing the file is full */ +#define PR_NO_DEVICE_SPACE_ERROR (-5956L) + +/* Unused */ +#define PR_PIPE_ERROR (-5955L) + +/* Unused */ +#define PR_NO_SEEK_DEVICE_ERROR (-5954L) + +/* Cannot perform a normal file operation on a directory */ +#define PR_IS_DIRECTORY_ERROR (-5953L) + +/* Symbolic link loop */ +#define PR_LOOP_ERROR (-5952L) + +/* File name is too long */ +#define PR_NAME_TOO_LONG_ERROR (-5951L) + +/* File not found */ +#define PR_FILE_NOT_FOUND_ERROR (-5950L) + +/* Cannot perform directory operation on a normal file */ +#define PR_NOT_DIRECTORY_ERROR (-5949L) + +/* Cannot write to a read-only file system */ +#define PR_READ_ONLY_FILESYSTEM_ERROR (-5948L) + +/* Cannot delete a directory that is not empty */ +#define PR_DIRECTORY_NOT_EMPTY_ERROR (-5947L) + +/* Cannot delete or rename a file object while the file system is busy */ +#define PR_FILESYSTEM_MOUNTED_ERROR (-5946L) + +/* Cannot rename a file to a file system on another device */ +#define PR_NOT_SAME_DEVICE_ERROR (-5945L) + +/* The directory object in the file system is corrupted */ +#define PR_DIRECTORY_CORRUPTED_ERROR (-5944L) + +/* Cannot create or rename a filename that already exists */ +#define PR_FILE_EXISTS_ERROR (-5943L) + +/* Directory is full. No additional filenames may be added */ +#define PR_MAX_DIRECTORY_ENTRIES_ERROR (-5942L) + +/* The required device was in an invalid state */ +#define PR_INVALID_DEVICE_STATE_ERROR (-5941L) + +/* The device is locked */ +#define PR_DEVICE_IS_LOCKED_ERROR (-5940L) + +/* No more entries in the directory */ +#define PR_NO_MORE_FILES_ERROR (-5939L) + +/* Encountered end of file */ +#define PR_END_OF_FILE_ERROR (-5938L) + +/* Seek error */ +#define PR_FILE_SEEK_ERROR (-5937L) + +/* The file is busy */ +#define PR_FILE_IS_BUSY_ERROR (-5936L) + +/* The I/O operation was aborted */ +#define PR_OPERATION_ABORTED_ERROR (-5935L) + +/* Operation is still in progress (probably a non-blocking connect) */ +#define PR_IN_PROGRESS_ERROR (-5934L) + +/* Operation has already been initiated (probably a non-blocking connect) */ +#define PR_ALREADY_INITIATED_ERROR (-5933L) + +/* The wait group is empty */ +#define PR_GROUP_EMPTY_ERROR (-5932L) + +/* Object state improper for request */ +#define PR_INVALID_STATE_ERROR (-5931L) + +/* Network is down */ +#define PR_NETWORK_DOWN_ERROR (-5930L) + +/* Socket shutdown */ +#define PR_SOCKET_SHUTDOWN_ERROR (-5929L) + +/* Connection aborted */ +#define PR_CONNECT_ABORTED_ERROR (-5928L) + +/* Host is unreachable */ +#define PR_HOST_UNREACHABLE_ERROR (-5927L) + +/* The library is not loaded */ +#define PR_LIBRARY_NOT_LOADED_ERROR (-5926L) + +/* The one-time function was previously called and failed. Its error code is no longer available */ +#define PR_CALL_ONCE_ERROR (-5925L) + +/* Placeholder for the end of the list */ +#define PR_MAX_ERROR (-5924L) + +extern void nspr_InitializePRErrorTable(void); +#define ERROR_TABLE_BASE_nspr (-6000L) + +#endif /* prerr_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prerror.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prerror.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prerror.h @@ -0,0 +1,294 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prerror_h___ +#define prerror_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +typedef PRInt32 PRErrorCode; + +#define PR_NSPR_ERROR_BASE -6000 + +#include "prerr.h" + +/* +** Set error will preserve an error condition within a thread context. +** The values stored are the NSPR (platform independent) translation of +** the error. Also, if available, the platform specific oserror is stored. +** If there is no appropriate OS error number, a zero my be supplied. +*/ +NSPR_API(void) PR_SetError(PRErrorCode errorCode, PRInt32 oserr); + +/* +** The text value specified may be NULL. If it is not NULL and the text length +** is zero, the string is assumed to be a null terminated C string. Otherwise +** the text is assumed to be the length specified and possibly include NULL +** characters (e.g., a multi-national string). +** +** The text will be copied into to thread structure and remain there +** until the next call to PR_SetError. +*/ +NSPR_API(void) PR_SetErrorText( + PRIntn textLength, const char *text); + +/* +** Return the current threads last set error code. +*/ +NSPR_API(PRErrorCode) PR_GetError(void); + +/* +** Return the current threads last set os error code. This is used for +** machine specific code that desires the underlying os error. +*/ +NSPR_API(PRInt32) PR_GetOSError(void); + +/* +** Get the length of the error text. If a zero is returned, then there +** is no text. Otherwise, the value returned is sufficient to contain +** the error text currently available. +*/ +NSPR_API(PRInt32) PR_GetErrorTextLength(void); + +/* +** Copy the current threads current error text. Then actual number of bytes +** copied is returned as the result. If the result is zero, the 'text' area +** is unaffected. +*/ +NSPR_API(PRInt32) PR_GetErrorText(char *text); + + +/* +Copyright (C) 1987, 1988 Student Information Processing Board of the +Massachusetts Institute of Technology. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, provided +that the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be +used in advertising or publicity pertaining to distribution of the software +without specific, written prior permission. M.I.T. and the M.I.T. S.I.P.B. +make no representations about the suitability of this software for any +purpose. It is provided "as is" without express or implied warranty. +*/ + + +/* + * NOTE: + * The interfaces for error-code-translation described in the rest of + * this file are preliminary in the 3.1 release of nspr and are subject + * to change in future releases. + */ + +/* +** Description: Localizable error code to string function. +** +** +** NSPR provides a mechanism for converting an error code to a +** descriptive string, in a caller-specified language. +** +** Error codes themselves are 32 bit (signed) integers. Typically, +** the high order 24 bits are an identifier of which error table the +** error code is from, and the low order 8 bits are a sequential error +** number within the table. NSPR supports error tables whose first +** error code is not a multiple of 256, such error code assignments +** should be avoided when possible. +** +** Error table 0 is defined to match the UNIX system call error table +** (sys_errlist); this allows errno values to be used directly in the +** library. Other error table numbers are typically formed by +** compacting together the first four characters of the error table +** name. The mapping between characters in the name and numeric +** values in the error code are defined in a system-independent +** fashion, so that two systems that can pass integral values between +** them can reliably pass error codes without loss of meaning; this +** should work even if the character sets used are not the +** same. (However, if this is to be done, error table 0 should be +** avoided, since the local system call error tables may differ.) +** +** Libraries defining error codes need only provide a table mapping +** error code numbers to names and default English descriptions, +** calling a routine to install the table, making it ``known'' to NSPR +** library. Once installed, a table may not be removed. Any error +** code the library generates can be converted to the corresponding +** error message. There is also a default format for error codes +** accidentally returned before making the table known, which is of +** the form "unknown code foo 32", where "foo" would be the name of +** the table. +** +** Normally, the error code conversion routine only supports the +** languages "i-default" and "en", returning the error-table-provided +** English description for both languages. The application may +** provide a localization plugin, allowing support for additional +** languages. +** +**/ + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +/* + * PRLanguageCode -- + * + * NSPR represents a language code as a non-negative integer. + * Languages 0 is always "i-default" the language you get without + * explicit negotiation. Language 1 is always "en", English + * which has been explicitly negotiated. Additional language + * codes are defined by an application-provided localization plugin. + */ +typedef PRUint32 PRLanguageCode; +#define PR_LANGUAGE_I_DEFAULT 0 /* i-default, the default language */ +#define PR_LANGUAGE_EN 1 /* English, explicitly negotiated */ + +/* + * struct PRErrorMessage -- + * + * An error message in an error table. + */ +struct PRErrorMessage { + const char * name; /* Macro name for error */ + const char * en_text; /* Default English text */ +}; + +/* + * struct PRErrorTable -- + * + * An error table, provided by a library. + */ +struct PRErrorTable { + const struct PRErrorMessage * msgs; /* Array of error information */ + const char *name; /* Name of error table source */ + PRErrorCode base; /* Error code for first error in table */ + int n_msgs; /* Number of codes in table */ +}; + +/* + * struct PRErrorCallbackPrivate -- + * + * A private structure for the localization plugin + */ +struct PRErrorCallbackPrivate; + +/* + * struct PRErrorCallbackTablePrivate -- + * + * A data structure under which the localization plugin may store information, + * associated with an error table, that is private to itself. + */ +struct PRErrorCallbackTablePrivate; + +/* + * PRErrorCallbackLookupFn -- + * + * A function of PRErrorCallbackLookupFn type is a localization + * plugin callback which converts an error code into a description + * in the requested language. The callback is provided the + * appropriate error table, private data for the plugin and the table. + * The callback returns the appropriate UTF-8 encoded description, or NULL + * if no description can be found. + */ +typedef const char * +PRErrorCallbackLookupFn(PRErrorCode code, PRLanguageCode language, + const struct PRErrorTable *table, + struct PRErrorCallbackPrivate *cb_private, + struct PRErrorCallbackTablePrivate *table_private); + +/* + * PRErrorCallbackNewTableFn -- + * + * A function PRErrorCallbackNewTableFn type is a localization plugin + * callback which is called once with each error table registered + * with NSPR. The callback is provided with the error table and + * the plugin's private structure. The callback returns any table private + * data it wishes to associate with the error table. Does not need to be thread + * safe. + */ +typedef struct PRErrorCallbackTablePrivate * +PRErrorCallbackNewTableFn(const struct PRErrorTable *table, + struct PRErrorCallbackPrivate *cb_private); + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/*********************************************************************** +** FUNCTION: PR_ErrorToString +** DESCRIPTION: +** Returns the UTF-8 message for an error code in +** the requested language. May return the message +** in the default language if a translation in the requested +** language is not available. The returned string is +** valid for the duration of the process. Never returns NULL. +** +***********************************************************************/ +NSPR_API(const char *) PR_ErrorToString(PRErrorCode code, + PRLanguageCode language); + + +/*********************************************************************** +** FUNCTION: PR_ErrorToName +** DESCRIPTION: +** Returns the macro name for an error code, or NULL +** if the error code is not known. The returned string is +** valid for the duration of the process. +** +** Does not work for error table 0, the system error codes. +** +***********************************************************************/ +NSPR_API(const char *) PR_ErrorToName(PRErrorCode code); + + +/*********************************************************************** +** FUNCTION: PR_ErrorLanguages +** DESCRIPTION: +** Returns the RFC 1766 language tags for the language +** codes PR_ErrorToString() supports. The returned array is valid +** for the duration of the process. Never returns NULL. The first +** item in the returned array is the language tag for PRLanguageCode 0, +** the second is for PRLanguageCode 1, and so on. The array is terminated +** with a null pointer. +** +***********************************************************************/ +NSPR_API(const char * const *) PR_ErrorLanguages(void); + + +/*********************************************************************** +** FUNCTION: PR_ErrorInstallTable +** DESCRIPTION: +** Registers an error table with NSPR. Must be done exactly once per +** table. Memory pointed to by `table' must remain valid for the life +** of the process. +** +** NOT THREAD SAFE! +** +***********************************************************************/ +NSPR_API(PRErrorCode) PR_ErrorInstallTable(const struct PRErrorTable *table); + + +/*********************************************************************** +** FUNCTION: PR_ErrorInstallCallback +** DESCRIPTION: +** Registers an error localization plugin with NSPR. May be called +** at most one time. `languages' contains the language codes supported +** by this plugin. Languages 0 and 1 must be "i-default" and "en" +** respectively. `lookup' and `newtable' contain pointers to +** the plugin callback functions. `cb_private' contains any information +** private to the plugin functions. +** +** NOT THREAD SAFE! +** +***********************************************************************/ +NSPR_API(void) PR_ErrorInstallCallback(const char * const * languages, + PRErrorCallbackLookupFn *lookup, + PRErrorCallbackNewTableFn *newtable, + struct PRErrorCallbackPrivate *cb_private); + +PR_END_EXTERN_C + +#endif /* prerror_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prinet.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prinet.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prinet.h @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* + * File: prinet.h + * Description: + * Header file used to find the system header files for socket support[1]. + * This file serves the following purposes: + * - A cross-platform, "get-everything" socket header file. On + * Unix, socket support is scattered in several header files, + * while Windows has a "get-everything" socket header file[2]. + * - NSPR needs the following macro definitions and function + * prototype declarations from these header files: + * AF_INET + * INADDR_ANY, INADDR_LOOPBACK, INADDR_BROADCAST + * ntohl(), ntohs(), htonl(), ntons(). + * NSPR does not define its own versions of these macros and + * functions. It simply uses the native versions, which have + * the same names on all supported platforms. + * This file is intended to be included by NSPR public header + * files, such as prio.h. One should not include this file directly. + * + * Notes: + * 1. This file should have been an internal header. Please do not + * depend on it to pull in the system header files you need. + * 2. WARNING: This file is no longer cross-platform as it is a no-op + * for WIN32! See the comment in the WIN32 section for details. + */ + +#ifndef prinet_h__ +#define prinet_h__ + +#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) +#include +#include /* AF_INET */ +#include /* INADDR_ANY, ..., ntohl(), ... */ +#ifdef XP_OS2 +#include +#endif +#ifdef XP_UNIX +#ifdef AIX +/* + * On AIX 4.3, the header refers to struct + * ether_addr and struct sockaddr_dl that are not declared. + * The following struct declarations eliminate the compiler + * warnings. + */ +struct ether_addr; +struct sockaddr_dl; +#endif /* AIX */ +#include +#endif /* XP_UNIX */ +#include + +#if defined(BSDI) || defined(QNX) +#include /* the only place that defines INADDR_LOOPBACK */ +#endif + +/* + * OS/2 hack. For some reason INADDR_LOOPBACK is not defined in the + * socket headers. + */ +#if defined(OS2) && !defined(INADDR_LOOPBACK) +#define INADDR_LOOPBACK 0x7f000001 +#endif + +/* + * Prototypes of ntohl() etc. are declared in + * on these platforms. + */ +#if defined(BSDI) || defined(OSF1) +#include +#endif + +/* On Android, ntohl() etc. are declared in . */ +#ifdef __ANDROID__ +#include +#endif + +#elif defined(WIN32) + +/* + * Do not include any system header files. + * + * Originally we were including . It slowed down the + * compilation of files that included NSPR headers, so we removed + * the inclusion at customer's request, which created + * an unfortunate inconsistency with other platforms. + */ + +#else + +#error Unknown platform + +#endif + +#endif /* prinet_h__ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prinit.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prinit.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prinit.h @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prinit_h___ +#define prinit_h___ + +#include "prthread.h" +#include "prtypes.h" +#include "prwin16.h" +#include + +PR_BEGIN_EXTERN_C + +/************************************************************************/ +/**************************IDENTITY AND VERSIONING***********************/ +/************************************************************************/ + +/* +** NSPR's name, this should persist until at least the turn of the +** century. +*/ +#define PR_NAME "NSPR" + +/* +** NSPR's version is used to determine the likelihood that the version you +** used to build your component is anywhere close to being compatible with +** what is in the underlying library. +** +** The format of the version string is +** ".[.] []" +*/ +#define PR_VERSION "4.19" +#define PR_VMAJOR 4 +#define PR_VMINOR 19 +#define PR_VPATCH 0 +#define PR_BETA PR_FALSE + +/* +** PRVersionCheck +** +** The basic signature of the function that is called to provide version +** checking. The result will be a boolean that indicates the likelihood +** that the underling library will perform as the caller expects. +** +** The only argument is a string, which should be the verson identifier +** of the library in question. That string will be compared against an +** equivalent string that represents the actual build version of the +** exporting library. +** +** The result will be the logical union of the directly called library +** and all dependent libraries. +*/ + +typedef PRBool (*PRVersionCheck)(const char*); + +/* +** PR_VersionCheck +** +** NSPR's existance proof of the version check function. +** +** Note that NSPR has no cooperating dependencies. +*/ + +NSPR_API(PRBool) PR_VersionCheck(const char *importedVersion); + +/* + * Returns a const string of the NSPR library version. + */ +NSPR_API(const char*) PR_GetVersion(void); + + +/************************************************************************/ +/*******************************INITIALIZATION***************************/ +/************************************************************************/ + +/* +** Initialize the runtime. Attach a thread object to the currently +** executing native thread of type "type". +** +** The specificaiton of 'maxPTDs' is ignored. +*/ +NSPR_API(void) PR_Init( + PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs); + +/* +** And alternate form of initialization, one that may become the default if +** not the only mechanism, provides a method to get the NSPR runtime init- +** ialized and place NSPR between the caller and the runtime library. This +** allows main() to be treated as any other thread root function, signalling +** its compeletion by returning and allowing the runtime to coordinate the +** completion of the other threads of the runtime. +** +** The priority of the main (or primordial) thread will be PR_PRIORITY_NORMAL. +** The thread may adjust its own priority by using PR_SetPriority(), though +** at this time the support for priorities is somewhat weak. +** +** The specificaiton of 'maxPTDs' is ignored. +** +** The value returned by PR_Initialize is the value returned from the root +** function, 'prmain'. +*/ + +typedef PRIntn (PR_CALLBACK *PRPrimordialFn)(PRIntn argc, char **argv); + +NSPR_API(PRIntn) PR_Initialize( + PRPrimordialFn prmain, PRIntn argc, char **argv, PRUintn maxPTDs); + +/* +** Return PR_TRUE if PR_Init has already been called. +*/ +NSPR_API(PRBool) PR_Initialized(void); + +/* + * Perform a graceful shutdown of NSPR. PR_Cleanup() may be called by + * the primordial thread near the end of the main() function. + * + * PR_Cleanup() attempts to synchronize the natural termination of + * process. It does that by blocking the caller, if and only if it is + * the primordial thread, until the number of user threads has dropped + * to zero. When the primordial thread returns from main(), the process + * will immediately and silently exit. That is, it will (if necessary) + * forcibly terminate any existing threads and exit without significant + * blocking and there will be no error messages or core files. + * + * PR_Cleanup() returns PR_SUCCESS if NSPR is successfully shutdown, + * or PR_FAILURE if the calling thread of this function is not the + * primordial thread. + */ +NSPR_API(PRStatus) PR_Cleanup(void); + +/* +** Disable Interrupts +** Disables timer signals used for pre-emptive scheduling. +*/ +NSPR_API(void) PR_DisableClockInterrupts(void); + +/* +** Enables Interrupts +** Enables timer signals used for pre-emptive scheduling. +*/ +NSPR_API(void) PR_EnableClockInterrupts(void); + +/* +** Block Interrupts +** Blocks the timer signal used for pre-emptive scheduling +*/ +NSPR_API(void) PR_BlockClockInterrupts(void); + +/* +** Unblock Interrupts +** Unblocks the timer signal used for pre-emptive scheduling +*/ +NSPR_API(void) PR_UnblockClockInterrupts(void); + +/* +** Create extra virtual processor threads. Generally used with MP systems. +*/ +NSPR_API(void) PR_SetConcurrency(PRUintn numCPUs); + +/* +** Control the method and size of the file descriptor (PRFileDesc*) +** cache used by the runtime. Setting 'high' to zero is for performance, +** any other value probably for debugging (see memo on FD caching). +*/ +NSPR_API(PRStatus) PR_SetFDCacheSize(PRIntn low, PRIntn high); + +/* + * Cause an immediate, nongraceful, forced termination of the process. + * It takes a PRIntn argument, which is the exit status code of the + * process. + */ +NSPR_API(void) PR_ProcessExit(PRIntn status); + +/* +** Abort the process in a non-graceful manner. This will cause a core file, +** call to the debugger or other moral equivalent as well as causing the +** entire process to stop. +*/ +NSPR_API(void) PR_Abort(void); + +/* + **************************************************************** + * + * Module initialization: + * + **************************************************************** + */ + +typedef struct PRCallOnceType { + PRIntn initialized; + PRInt32 inProgress; + PRStatus status; +} PRCallOnceType; + +typedef PRStatus (PR_CALLBACK *PRCallOnceFN)(void); + +typedef PRStatus (PR_CALLBACK *PRCallOnceWithArgFN)(void *arg); + +NSPR_API(PRStatus) PR_CallOnce( + PRCallOnceType *once, + PRCallOnceFN func +); + +NSPR_API(PRStatus) PR_CallOnceWithArg( + PRCallOnceType *once, + PRCallOnceWithArgFN func, + void *arg +); + + +PR_END_EXTERN_C + +#endif /* prinit_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prinrval.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prinrval.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prinrval.h @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: prinrval.h +** Description: API to interval timing functions of NSPR. +** +** +** NSPR provides interval times that are independent of network time +** of day values. Interval times are (in theory) accurate regardless +** of host processing requirements and also very cheap to acquire. It +** is expected that getting an interval time while in a synchronized +** function (holding one's lock). +**/ + +#if !defined(prinrval_h) +#define prinrval_h + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +typedef PRUint32 PRIntervalTime; + +/*********************************************************************** +** DEFINES: PR_INTERVAL_MIN +** PR_INTERVAL_MAX +** DESCRIPTION: +** These two constants define the range (in ticks / second) of the +** platform dependent type, PRIntervalTime. These constants bound both +** the period and the resolution of a PRIntervalTime. +***********************************************************************/ +#define PR_INTERVAL_MIN 1000UL +#define PR_INTERVAL_MAX 100000UL + +/*********************************************************************** +** DEFINES: PR_INTERVAL_NO_WAIT +** PR_INTERVAL_NO_TIMEOUT +** DESCRIPTION: +** Two reserved constants are defined in the PRIntervalTime namespace. +** They are used to indicate that the process should wait no time (return +** immediately) or wait forever (never time out), respectively. +** Note: PR_INTERVAL_NO_TIMEOUT passed as input to PR_Connect is +** interpreted as use the OS's connect timeout. +** +***********************************************************************/ +#define PR_INTERVAL_NO_WAIT 0UL +#define PR_INTERVAL_NO_TIMEOUT 0xffffffffUL + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/*********************************************************************** +** FUNCTION: PR_IntervalNow +** DESCRIPTION: +** Return the value of NSPR's free running interval timer. That timer +** can be used to establish epochs and determine intervals (be computing +** the difference between two times). +** INPUTS: void +** OUTPUTS: void +** RETURN: PRIntervalTime +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** The units of PRIntervalTime are platform dependent. They are chosen +** such that they are appropriate for the host OS, yet provide sufficient +** resolution and period to be useful to clients. +** MEMORY: N/A +** ALGORITHM: Platform dependent +***********************************************************************/ +NSPR_API(PRIntervalTime) PR_IntervalNow(void); + +/*********************************************************************** +** FUNCTION: PR_TicksPerSecond +** DESCRIPTION: +** Return the number of ticks per second for PR_IntervalNow's clock. +** The value will be in the range [PR_INTERVAL_MIN..PR_INTERVAL_MAX]. +** INPUTS: void +** OUTPUTS: void +** RETURN: PRUint32 +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** None +** MEMORY: N/A +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRUint32) PR_TicksPerSecond(void); + +/*********************************************************************** +** FUNCTION: PR_SecondsToInterval +** PR_MillisecondsToInterval +** PR_MicrosecondsToInterval +** DESCRIPTION: +** Convert standard clock units to platform dependent intervals. +** INPUTS: PRUint32 +** OUTPUTS: void +** RETURN: PRIntervalTime +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** Conversion may cause overflow, which is not reported. +** MEMORY: N/A +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRIntervalTime) PR_SecondsToInterval(PRUint32 seconds); +NSPR_API(PRIntervalTime) PR_MillisecondsToInterval(PRUint32 milli); +NSPR_API(PRIntervalTime) PR_MicrosecondsToInterval(PRUint32 micro); + +/*********************************************************************** +** FUNCTION: PR_IntervalToSeconds +** PR_IntervalToMilliseconds +** PR_IntervalToMicroseconds +** DESCRIPTION: +** Convert platform dependent intervals to standard clock units. +** INPUTS: PRIntervalTime +** OUTPUTS: void +** RETURN: PRUint32 +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** Conversion may cause overflow, which is not reported. +** MEMORY: N/A +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRUint32) PR_IntervalToSeconds(PRIntervalTime ticks); +NSPR_API(PRUint32) PR_IntervalToMilliseconds(PRIntervalTime ticks); +NSPR_API(PRUint32) PR_IntervalToMicroseconds(PRIntervalTime ticks); + +PR_END_EXTERN_C + + +#endif /* !defined(prinrval_h) */ + +/* prinrval.h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prio.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prio.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prio.h @@ -0,0 +1,2022 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* + * File: prio.h + * + * Description: PR i/o related stuff, such as file system access, file + * i/o, socket i/o, etc. + */ + +#ifndef prio_h___ +#define prio_h___ + +#include "prlong.h" +#include "prtime.h" +#include "prinrval.h" +#include "prinet.h" + +PR_BEGIN_EXTERN_C + +/* Typedefs */ +typedef struct PRDir PRDir; +typedef struct PRDirEntry PRDirEntry; +#ifdef MOZ_UNICODE +typedef struct PRDirUTF16 PRDirUTF16; +typedef struct PRDirEntryUTF16 PRDirEntryUTF16; +#endif /* MOZ_UNICODE */ +typedef struct PRFileDesc PRFileDesc; +typedef struct PRFileInfo PRFileInfo; +typedef struct PRFileInfo64 PRFileInfo64; +typedef union PRNetAddr PRNetAddr; +typedef struct PRIOMethods PRIOMethods; +typedef struct PRPollDesc PRPollDesc; +typedef struct PRFilePrivate PRFilePrivate; +typedef struct PRSendFileData PRSendFileData; + +/* +*************************************************************************** +** The file descriptor. +** This is the primary structure to represent any active open socket, +** whether it be a normal file or a network connection. Such objects +** are stackable (or layerable). Each layer may have its own set of +** method pointers and context private to that layer. All each layer +** knows about its neighbors is how to get to their method table. +*************************************************************************** +*/ + +typedef PRIntn PRDescIdentity; /* see: Layering file descriptors */ + +struct PRFileDesc { + const PRIOMethods *methods; /* the I/O methods table */ + PRFilePrivate *secret; /* layer dependent data */ + PRFileDesc *lower, *higher; /* pointers to adjacent layers */ + void (PR_CALLBACK *dtor)(PRFileDesc *fd); + /* A destructor function for layer */ + PRDescIdentity identity; /* Identity of this particular layer */ +}; + +/* +*************************************************************************** +** PRTransmitFileFlags +** +** Flags for PR_TransmitFile. Pass PR_TRANSMITFILE_CLOSE_SOCKET to +** PR_TransmitFile if the connection should be closed after the file +** is transmitted. +*************************************************************************** +*/ +typedef enum PRTransmitFileFlags { + PR_TRANSMITFILE_KEEP_OPEN = 0, /* socket is left open after file + * is transmitted. */ + PR_TRANSMITFILE_CLOSE_SOCKET = 1 /* socket is closed after file + * is transmitted. */ +} PRTransmitFileFlags; + +/* +************************************************************************** +** Macros for PRNetAddr +** +** Address families: PR_AF_INET, PR_AF_INET6, PR_AF_LOCAL +** IP addresses: PR_INADDR_ANY, PR_INADDR_LOOPBACK, PR_INADDR_BROADCAST +************************************************************************** +*/ + +#ifdef WIN32 + +#define PR_AF_INET 2 +#define PR_AF_LOCAL 1 +#define PR_INADDR_ANY (unsigned long)0x00000000 +#define PR_INADDR_LOOPBACK 0x7f000001 +#define PR_INADDR_BROADCAST (unsigned long)0xffffffff + +#else /* WIN32 */ + +#define PR_AF_INET AF_INET +#define PR_AF_LOCAL AF_UNIX +#define PR_INADDR_ANY INADDR_ANY +#define PR_INADDR_LOOPBACK INADDR_LOOPBACK +#define PR_INADDR_BROADCAST INADDR_BROADCAST + +#endif /* WIN32 */ + +/* +** Define PR_AF_INET6 in prcpucfg.h with the same +** value as AF_INET6 on platforms with IPv6 support. +** Otherwise define it here. +*/ +#ifndef PR_AF_INET6 +#define PR_AF_INET6 100 +#endif + +#define PR_AF_INET_SDP 101 +#define PR_AF_INET6_SDP 102 + +#ifndef PR_AF_UNSPEC +#define PR_AF_UNSPEC 0 +#endif + +/* +************************************************************************** +** A network address +** +** Only Internet Protocol (IPv4 and IPv6) addresses are supported. +** The address family must always represent IPv4 (AF_INET, probably == 2) +** or IPv6 (AF_INET6). +************************************************************************** +*************************************************************************/ + +struct PRIPv6Addr { + union { + PRUint8 _S6_u8[16]; + PRUint16 _S6_u16[8]; + PRUint32 _S6_u32[4]; + PRUint64 _S6_u64[2]; + } _S6_un; +}; +#define pr_s6_addr _S6_un._S6_u8 +#define pr_s6_addr16 _S6_un._S6_u16 +#define pr_s6_addr32 _S6_un._S6_u32 +#define pr_s6_addr64 _S6_un._S6_u64 + +typedef struct PRIPv6Addr PRIPv6Addr; + +union PRNetAddr { + struct { + PRUint16 family; /* address family (0x00ff maskable) */ +#ifdef XP_BEOS + char data[10]; /* Be has a smaller structure */ +#else + char data[14]; /* raw address data */ +#endif + } raw; + struct { + PRUint16 family; /* address family (AF_INET) */ + PRUint16 port; /* port number */ + PRUint32 ip; /* The actual 32 bits of address */ +#ifdef XP_BEOS + char pad[4]; /* Be has a smaller structure */ +#else + char pad[8]; +#endif + } inet; + struct { + PRUint16 family; /* address family (AF_INET6) */ + PRUint16 port; /* port number */ + PRUint32 flowinfo; /* routing information */ + PRIPv6Addr ip; /* the actual 128 bits of address */ + PRUint32 scope_id; /* set of interfaces for a scope */ + } ipv6; +#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_WIN) + struct { /* Unix domain socket address */ + PRUint16 family; /* address family (AF_UNIX) */ +#ifdef XP_OS2 + char path[108]; /* null-terminated pathname */ + /* bind fails if size is not 108. */ +#else + char path[104]; /* null-terminated pathname */ +#endif + } local; +#endif +}; + +/* +*************************************************************************** +** PRSockOption +** +** The file descriptors can have predefined options set after they file +** descriptor is created to change their behavior. Only the options in +** the following enumeration are supported. +*************************************************************************** +*/ +typedef enum PRSockOption +{ + PR_SockOpt_Nonblocking, /* nonblocking io */ + PR_SockOpt_Linger, /* linger on close if data present */ + PR_SockOpt_Reuseaddr, /* allow local address reuse */ + PR_SockOpt_Keepalive, /* keep connections alive */ + PR_SockOpt_RecvBufferSize, /* receive buffer size */ + PR_SockOpt_SendBufferSize, /* send buffer size */ + + PR_SockOpt_IpTimeToLive, /* time to live */ + PR_SockOpt_IpTypeOfService, /* type of service and precedence */ + + PR_SockOpt_AddMember, /* add an IP group membership */ + PR_SockOpt_DropMember, /* drop an IP group membership */ + PR_SockOpt_McastInterface, /* multicast interface address */ + PR_SockOpt_McastTimeToLive, /* multicast timetolive */ + PR_SockOpt_McastLoopback, /* multicast loopback */ + + PR_SockOpt_NoDelay, /* don't delay send to coalesce packets */ + PR_SockOpt_MaxSegment, /* maximum segment size */ + PR_SockOpt_Broadcast, /* enable broadcast */ + PR_SockOpt_Reuseport, /* allow local address & port reuse on + * platforms that support it */ + PR_SockOpt_Last +} PRSockOption; + +typedef struct PRLinger { + PRBool polarity; /* Polarity of the option's setting */ + PRIntervalTime linger; /* Time to linger before closing */ +} PRLinger; + +typedef struct PRMcastRequest { + PRNetAddr mcaddr; /* IP multicast address of group */ + PRNetAddr ifaddr; /* local IP address of interface */ +} PRMcastRequest; + +typedef struct PRSocketOptionData +{ + PRSockOption option; + union + { + PRUintn ip_ttl; /* IP time to live */ + PRUintn mcast_ttl; /* IP multicast time to live */ + PRUintn tos; /* IP type of service and precedence */ + PRBool non_blocking; /* Non-blocking (network) I/O */ + PRBool reuse_addr; /* Allow local address reuse */ + PRBool reuse_port; /* Allow local address & port reuse on + * platforms that support it */ + PRBool keep_alive; /* Keep connections alive */ + PRBool mcast_loopback; /* IP multicast loopback */ + PRBool no_delay; /* Don't delay send to coalesce packets */ + PRBool broadcast; /* Enable broadcast */ + PRSize max_segment; /* Maximum segment size */ + PRSize recv_buffer_size; /* Receive buffer size */ + PRSize send_buffer_size; /* Send buffer size */ + PRLinger linger; /* Time to linger on close if data present */ + PRMcastRequest add_member; /* add an IP group membership */ + PRMcastRequest drop_member; /* Drop an IP group membership */ + PRNetAddr mcast_if; /* multicast interface address */ + } value; +} PRSocketOptionData; + +/* +*************************************************************************** +** PRIOVec +** +** The I/O vector is used by the write vector method to describe the areas +** that are affected by the ouput operation. +*************************************************************************** +*/ +typedef struct PRIOVec { + char *iov_base; + int iov_len; +} PRIOVec; + +/* +*************************************************************************** +** Discover what type of socket is being described by the file descriptor. +*************************************************************************** +*/ +typedef enum PRDescType +{ + PR_DESC_FILE = 1, + PR_DESC_SOCKET_TCP = 2, + PR_DESC_SOCKET_UDP = 3, + PR_DESC_LAYERED = 4, + PR_DESC_PIPE = 5 +} PRDescType; + +typedef enum PRSeekWhence { + PR_SEEK_SET = 0, + PR_SEEK_CUR = 1, + PR_SEEK_END = 2 +} PRSeekWhence; + +NSPR_API(PRDescType) PR_GetDescType(PRFileDesc *file); + +/* +*************************************************************************** +** PRIOMethods +** +** The I/O methods table provides procedural access to the functions of +** the file descriptor. It is the responsibility of a layer implementor +** to provide suitable functions at every entry point. If a layer provides +** no functionality, it should call the next lower(higher) function of the +** same name (e.g., return fd->lower->method->close(fd->lower)); +** +** Not all functions are implemented for all types of files. In cases where +** that is true, the function will return a error indication with an error +** code of PR_INVALID_METHOD_ERROR. +*************************************************************************** +*/ + +typedef PRStatus (PR_CALLBACK *PRCloseFN)(PRFileDesc *fd); +typedef PRInt32 (PR_CALLBACK *PRReadFN)(PRFileDesc *fd, void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRWriteFN)(PRFileDesc *fd, const void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRAvailableFN)(PRFileDesc *fd); +typedef PRInt64 (PR_CALLBACK *PRAvailable64FN)(PRFileDesc *fd); +typedef PRStatus (PR_CALLBACK *PRFsyncFN)(PRFileDesc *fd); +typedef PROffset32 (PR_CALLBACK *PRSeekFN)(PRFileDesc *fd, PROffset32 offset, PRSeekWhence how); +typedef PROffset64 (PR_CALLBACK *PRSeek64FN)(PRFileDesc *fd, PROffset64 offset, PRSeekWhence how); +typedef PRStatus (PR_CALLBACK *PRFileInfoFN)(PRFileDesc *fd, PRFileInfo *info); +typedef PRStatus (PR_CALLBACK *PRFileInfo64FN)(PRFileDesc *fd, PRFileInfo64 *info); +typedef PRInt32 (PR_CALLBACK *PRWritevFN)( + PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, + PRIntervalTime timeout); +typedef PRStatus (PR_CALLBACK *PRConnectFN)( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout); +typedef PRFileDesc* (PR_CALLBACK *PRAcceptFN) ( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout); +typedef PRStatus (PR_CALLBACK *PRBindFN)(PRFileDesc *fd, const PRNetAddr *addr); +typedef PRStatus (PR_CALLBACK *PRListenFN)(PRFileDesc *fd, PRIntn backlog); +typedef PRStatus (PR_CALLBACK *PRShutdownFN)(PRFileDesc *fd, PRIntn how); +typedef PRInt32 (PR_CALLBACK *PRRecvFN)( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); +typedef PRInt32 (PR_CALLBACK *PRSendFN) ( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); +typedef PRInt32 (PR_CALLBACK *PRRecvfromFN)( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout); +typedef PRInt32 (PR_CALLBACK *PRSendtoFN)( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout); +typedef PRInt16 (PR_CALLBACK *PRPollFN)( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags); +typedef PRInt32 (PR_CALLBACK *PRAcceptreadFN)( + PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, + void *buf, PRInt32 amount, PRIntervalTime t); +typedef PRInt32 (PR_CALLBACK *PRTransmitfileFN)( + PRFileDesc *sd, PRFileDesc *fd, const void *headers, + PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime t); +typedef PRStatus (PR_CALLBACK *PRGetsocknameFN)(PRFileDesc *fd, PRNetAddr *addr); +typedef PRStatus (PR_CALLBACK *PRGetpeernameFN)(PRFileDesc *fd, PRNetAddr *addr); +typedef PRStatus (PR_CALLBACK *PRGetsocketoptionFN)( + PRFileDesc *fd, PRSocketOptionData *data); +typedef PRStatus (PR_CALLBACK *PRSetsocketoptionFN)( + PRFileDesc *fd, const PRSocketOptionData *data); +typedef PRInt32 (PR_CALLBACK *PRSendfileFN)( + PRFileDesc *networkSocket, PRSendFileData *sendData, + PRTransmitFileFlags flags, PRIntervalTime timeout); +typedef PRStatus (PR_CALLBACK *PRConnectcontinueFN)( + PRFileDesc *fd, PRInt16 out_flags); +typedef PRIntn (PR_CALLBACK *PRReservedFN)(PRFileDesc *fd); + +struct PRIOMethods { + PRDescType file_type; /* Type of file represented (tos) */ + PRCloseFN close; /* close file and destroy descriptor */ + PRReadFN read; /* read up to specified bytes into buffer */ + PRWriteFN write; /* write specified bytes from buffer */ + PRAvailableFN available; /* determine number of bytes available */ + PRAvailable64FN available64; /* ditto, 64 bit */ + PRFsyncFN fsync; /* flush all buffers to permanent store */ + PRSeekFN seek; /* position the file to the desired place */ + PRSeek64FN seek64; /* ditto, 64 bit */ + PRFileInfoFN fileInfo; /* Get information about an open file */ + PRFileInfo64FN fileInfo64; /* ditto, 64 bit */ + PRWritevFN writev; /* Write segments as described by iovector */ + PRConnectFN connect; /* Connect to the specified (net) address */ + PRAcceptFN accept; /* Accept a connection for a (net) peer */ + PRBindFN bind; /* Associate a (net) address with the fd */ + PRListenFN listen; /* Prepare to listen for (net) connections */ + PRShutdownFN shutdown; /* Shutdown a (net) connection */ + PRRecvFN recv; /* Solicit up the the specified bytes */ + PRSendFN send; /* Send all the bytes specified */ + PRRecvfromFN recvfrom; /* Solicit (net) bytes and report source */ + PRSendtoFN sendto; /* Send bytes to (net) address specified */ + PRPollFN poll; /* Test the fd to see if it is ready */ + PRAcceptreadFN acceptread; /* Accept and read on a new (net) fd */ + PRTransmitfileFN transmitfile; /* Transmit at entire file */ + PRGetsocknameFN getsockname; /* Get (net) address associated with fd */ + PRGetpeernameFN getpeername; /* Get peer's (net) address */ + PRReservedFN reserved_fn_6; /* reserved for future use */ + PRReservedFN reserved_fn_5; /* reserved for future use */ + PRGetsocketoptionFN getsocketoption; + /* Get current setting of specified option */ + PRSetsocketoptionFN setsocketoption; + /* Set value of specified option */ + PRSendfileFN sendfile; /* Send a (partial) file with header/trailer*/ + PRConnectcontinueFN connectcontinue; + /* Continue a nonblocking connect */ + PRReservedFN reserved_fn_3; /* reserved for future use */ + PRReservedFN reserved_fn_2; /* reserved for future use */ + PRReservedFN reserved_fn_1; /* reserved for future use */ + PRReservedFN reserved_fn_0; /* reserved for future use */ +}; + +/* + ************************************************************************** + * FUNCTION: PR_GetSpecialFD + * DESCRIPTION: Get the file descriptor that represents the standard input, + * output, or error stream. + * INPUTS: + * PRSpecialFD id + * A value indicating the type of stream desired: + * PR_StandardInput: standard input + * PR_StandardOuput: standard output + * PR_StandardError: standard error + * OUTPUTS: none + * RETURNS: PRFileDesc * + * If the argument is valid, PR_GetSpecialFD returns a file descriptor + * that represents the corresponding standard I/O stream. Otherwise, + * PR_GetSpecialFD returns NULL and sets error PR_INVALID_ARGUMENT_ERROR. + ************************************************************************** + */ + +typedef enum PRSpecialFD +{ + PR_StandardInput, /* standard input */ + PR_StandardOutput, /* standard output */ + PR_StandardError /* standard error */ +} PRSpecialFD; + +NSPR_API(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD id); + +#define PR_STDIN PR_GetSpecialFD(PR_StandardInput) +#define PR_STDOUT PR_GetSpecialFD(PR_StandardOutput) +#define PR_STDERR PR_GetSpecialFD(PR_StandardError) + +/* + ************************************************************************** + * Layering file descriptors + * + * File descriptors may be layered. Each layer has it's own identity. + * Identities are allocated by the runtime and are to be associated + * (by the layer implementor) with all layers that are of that type. + * It is then possible to scan the chain of layers and find a layer + * that one recongizes and therefore predict that it will implement + * a desired protocol. + * + * There are three well-known identities: + * PR_INVALID_IO_LAYER => an invalid layer identity, for error return + * PR_TOP_IO_LAYER => the identity of the top of the stack + * PR_NSPR_IO_LAYER => the identity used by NSPR proper + * PR_TOP_IO_LAYER may be used as a shorthand for identifying the topmost + * layer of an existing stack. Ie., the following two constructs are + * equivalent. + * + * rv = PR_PushIOLayer(stack, PR_TOP_IO_LAYER, my_layer); + * rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), my_layer) + * + * A string may be associated with the creation of the identity. It + * will be copied by the runtime. If queried the runtime will return + * a reference to that copied string (not yet another copy). There + * is no facility for deleting an identity. + ************************************************************************** + */ + +#define PR_IO_LAYER_HEAD (PRDescIdentity)-3 +#define PR_INVALID_IO_LAYER (PRDescIdentity)-1 +#define PR_TOP_IO_LAYER (PRDescIdentity)-2 +#define PR_NSPR_IO_LAYER (PRDescIdentity)0 + +NSPR_API(PRDescIdentity) PR_GetUniqueIdentity(const char *layer_name); +NSPR_API(const char*) PR_GetNameForIdentity(PRDescIdentity ident); +NSPR_API(PRDescIdentity) PR_GetLayersIdentity(PRFileDesc* fd); +NSPR_API(PRFileDesc*) PR_GetIdentitiesLayer(PRFileDesc* fd_stack, PRDescIdentity id); + +/* + ************************************************************************** + * PR_GetDefaultIOMethods: Accessing the default methods table. + * You may get a pointer to the default methods table by calling this function. + * You may then select any elements from that table with which to build your + * layer's methods table. You may NOT modify the table directly. + ************************************************************************** + */ +NSPR_API(const PRIOMethods *) PR_GetDefaultIOMethods(void); + +/* + ************************************************************************** + * Creating a layer + * + * A new layer may be allocated by calling PR_CreateIOLayerStub(). The + * file descriptor returned will contain the pointer to the methods table + * provided. The runtime will not modify the table nor test its correctness. + ************************************************************************** + */ +NSPR_API(PRFileDesc*) PR_CreateIOLayerStub( + PRDescIdentity ident, const PRIOMethods *methods); + +/* + ************************************************************************** + * Creating a layer + * + * A new stack may be created by calling PR_CreateIOLayer(). The + * file descriptor returned will point to the top of the stack, which has + * the layer 'fd' as the topmost layer. + * + * NOTE: This function creates a new style stack, which has a fixed, dummy + * header. The old style stack, created by a call to PR_PushIOLayer, + * results in modifying contents of the top layer of the stack, when + * pushing and popping layers of the stack. + ************************************************************************** + */ +NSPR_API(PRFileDesc*) PR_CreateIOLayer(PRFileDesc* fd); + +/* + ************************************************************************** + * Pushing a layer + * + * A file descriptor (perhaps allocated using PR_CreateIOLayerStub()) may + * be pushed into an existing stack of file descriptors at any point the + * caller deems appropriate. The new layer will be inserted into the stack + * just above the layer with the indicated identity. + * + * Note: Even if the identity parameter indicates the top-most layer of + * the stack, the value of the file descriptor describing the original + * stack will not change. + ************************************************************************** + */ +NSPR_API(PRStatus) PR_PushIOLayer( + PRFileDesc *fd_stack, PRDescIdentity id, PRFileDesc *layer); + +/* + ************************************************************************** + * Popping a layer + * + * A layer may be popped from a stack by indicating the identity of the + * layer to be removed. If found, a pointer to the removed object will + * be returned to the caller. The object then becomes the responsibility + * of the caller. + * + * Note: Even if the identity indicates the top layer of the stack, the + * reference returned will not be the file descriptor for the stack and + * that file descriptor will remain valid. + ************************************************************************** + */ +NSPR_API(PRFileDesc*) PR_PopIOLayer(PRFileDesc *fd_stack, PRDescIdentity id); + +/* + ************************************************************************** + * FUNCTION: PR_Open + * DESCRIPTION: Open a file for reading, writing, or both. + * INPUTS: + * const char *name + * The path name of the file to be opened + * PRIntn flags + * The file status flags. + * It is a bitwise OR of the following bit flags (only one of + * the first three flags below may be used): + * PR_RDONLY Open for reading only. + * PR_WRONLY Open for writing only. + * PR_RDWR Open for reading and writing. + * PR_CREATE_FILE If the file does not exist, the file is created + * If the file exists, this flag has no effect. + * PR_SYNC If set, each write will wait for both the file data + * and file status to be physically updated. + * PR_APPEND The file pointer is set to the end of + * the file prior to each write. + * PR_TRUNCATE If the file exists, its length is truncated to 0. + * PR_EXCL With PR_CREATE_FILE, if the file does not exist, + * the file is created. If the file already + * exists, no action and NULL is returned + * + * PRIntn mode + * The access permission bits of the file mode, if the file is + * created when PR_CREATE_FILE is on. + * OUTPUTS: None + * RETURNS: PRFileDesc * + * If the file is successfully opened, + * returns a pointer to the PRFileDesc + * created for the newly opened file. + * Returns a NULL pointer if the open + * failed. + * SIDE EFFECTS: + * RESTRICTIONS: + * MEMORY: + * The return value, if not NULL, points to a dynamically allocated + * PRFileDesc object. + * ALGORITHM: + ************************************************************************** + */ + +/* Open flags */ +#define PR_RDONLY 0x01 +#define PR_WRONLY 0x02 +#define PR_RDWR 0x04 +#define PR_CREATE_FILE 0x08 +#define PR_APPEND 0x10 +#define PR_TRUNCATE 0x20 +#define PR_SYNC 0x40 +#define PR_EXCL 0x80 + +/* +** File modes .... +** +** CAVEAT: 'mode' is currently only applicable on UNIX platforms. +** The 'mode' argument may be ignored by PR_Open on other platforms. +** +** 00400 Read by owner. +** 00200 Write by owner. +** 00100 Execute (search if a directory) by owner. +** 00040 Read by group. +** 00020 Write by group. +** 00010 Execute by group. +** 00004 Read by others. +** 00002 Write by others +** 00001 Execute by others. +** +*/ + +NSPR_API(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode); + +/* + ************************************************************************** + * FUNCTION: PR_OpenFile + * DESCRIPTION: + * Open a file for reading, writing, or both. + * PR_OpenFile has the same prototype as PR_Open but implements + * the specified file mode where possible. + ************************************************************************** + */ + +/* File mode bits */ +#define PR_IRWXU 00700 /* read, write, execute/search by owner */ +#define PR_IRUSR 00400 /* read permission, owner */ +#define PR_IWUSR 00200 /* write permission, owner */ +#define PR_IXUSR 00100 /* execute/search permission, owner */ +#define PR_IRWXG 00070 /* read, write, execute/search by group */ +#define PR_IRGRP 00040 /* read permission, group */ +#define PR_IWGRP 00020 /* write permission, group */ +#define PR_IXGRP 00010 /* execute/search permission, group */ +#define PR_IRWXO 00007 /* read, write, execute/search by others */ +#define PR_IROTH 00004 /* read permission, others */ +#define PR_IWOTH 00002 /* write permission, others */ +#define PR_IXOTH 00001 /* execute/search permission, others */ + +NSPR_API(PRFileDesc*) PR_OpenFile( + const char *name, PRIntn flags, PRIntn mode); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRFileDesc*) PR_OpenFileUTF16( + const PRUnichar *name, PRIntn flags, PRIntn mode); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************** + * FUNCTION: PR_Close + * DESCRIPTION: + * Close a file or socket. + * INPUTS: + * PRFileDesc *fd + * a pointer to a PRFileDesc. + * OUTPUTS: + * None. + * RETURN: + * PRStatus + * SIDE EFFECTS: + * RESTRICTIONS: + * None. + * MEMORY: + * The dynamic memory pointed to by the argument fd is freed. + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Close(PRFileDesc *fd); + +/* + ************************************************************************** + * FUNCTION: PR_Read + * DESCRIPTION: + * Read bytes from a file or socket. + * The operation will block until either an end of stream indication is + * encountered, some positive number of bytes are transferred, or there + * is an error. No more than 'amount' bytes will be transferred. + * INPUTS: + * PRFileDesc *fd + * pointer to the PRFileDesc object for the file or socket + * void *buf + * pointer to a buffer to hold the data read in. + * PRInt32 amount + * the size of 'buf' (in bytes) + * OUTPUTS: + * RETURN: + * PRInt32 + * a positive number indicates the number of bytes actually read in. + * 0 means end of file is reached or the network connection is closed. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + * SIDE EFFECTS: + * data is written into the buffer pointed to by 'buf'. + * RESTRICTIONS: + * None. + * MEMORY: + * N/A + * ALGORITHM: + * N/A + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_Read(PRFileDesc *fd, void *buf, PRInt32 amount); + +/* + *************************************************************************** + * FUNCTION: PR_Write + * DESCRIPTION: + * Write a specified number of bytes to a file or socket. The thread + * invoking this function blocks until all the data is written. + * INPUTS: + * PRFileDesc *fd + * pointer to a PRFileDesc object that refers to a file or socket + * const void *buf + * pointer to the buffer holding the data + * PRInt32 amount + * amount of data in bytes to be written from the buffer + * OUTPUTS: + * None. + * RETURN: PRInt32 + * A positive number indicates the number of bytes successfully written. + * A -1 is an indication that the operation failed. The reason + * for the failure is obtained by calling PR_GetError(). + *************************************************************************** + */ + +NSPR_API(PRInt32) PR_Write(PRFileDesc *fd,const void *buf,PRInt32 amount); + +/* + *************************************************************************** + * FUNCTION: PR_Writev + * DESCRIPTION: + * Write data to a socket. The data is organized in a PRIOVec array. The + * operation will block until all the data is written or the operation + * fails. + * INPUTS: + * PRFileDesc *fd + * Pointer that points to a PRFileDesc object for a socket. + * const PRIOVec *iov + * An array of PRIOVec. PRIOVec is a struct with the following + * two fields: + * char *iov_base; + * int iov_len; + * PRInt32 iov_size + * Number of elements in the iov array. The value of this + * argument must not be greater than PR_MAX_IOVECTOR_SIZE. + * If it is, the method will fail (PR_BUFFER_OVERFLOW_ERROR). + * PRIntervalTime timeout + * Time limit for completion of the entire write operation. + * OUTPUTS: + * None + * RETURN: + * A positive number indicates the number of bytes successfully written. + * A -1 is an indication that the operation failed. The reason + * for the failure is obtained by calling PR_GetError(). + *************************************************************************** + */ + +#define PR_MAX_IOVECTOR_SIZE 16 /* 'iov_size' must be <= */ + +NSPR_API(PRInt32) PR_Writev( + PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, + PRIntervalTime timeout); + +/* + *************************************************************************** + * FUNCTION: PR_Delete + * DESCRIPTION: + * Delete a file from the filesystem. The operation may fail if the + * file is open. + * INPUTS: + * const char *name + * Path name of the file to be deleted. + * OUTPUTS: + * None. + * RETURN: PRStatus + * The function returns PR_SUCCESS if the file is successfully + * deleted, otherwise it returns PR_FAILURE. + *************************************************************************** + */ + +NSPR_API(PRStatus) PR_Delete(const char *name); + +/**************************************************************************/ + +typedef enum PRFileType +{ + PR_FILE_FILE = 1, + PR_FILE_DIRECTORY = 2, + PR_FILE_OTHER = 3 +} PRFileType; + +struct PRFileInfo { + PRFileType type; /* Type of file */ + PROffset32 size; /* Size, in bytes, of file's contents */ + PRTime creationTime; /* Creation time per definition of PRTime */ + PRTime modifyTime; /* Last modification time per definition of PRTime */ +}; + +struct PRFileInfo64 { + PRFileType type; /* Type of file */ + PROffset64 size; /* Size, in bytes, of file's contents */ + PRTime creationTime; /* Creation time per definition of PRTime */ + PRTime modifyTime; /* Last modification time per definition of PRTime */ +}; + +/**************************************************************************** + * FUNCTION: PR_GetFileInfo, PR_GetFileInfo64 + * DESCRIPTION: + * Get the information about the file with the given path name. This is + * applicable only to NSFileDesc describing 'file' types (see + * INPUTS: + * const char *fn + * path name of the file + * OUTPUTS: + * PRFileInfo *info + * Information about the given file is written into the file + * information object pointer to by 'info'. + * RETURN: PRStatus + * PR_GetFileInfo returns PR_SUCCESS if file information is successfully + * obtained, otherwise it returns PR_FAILURE. + *************************************************************************** + */ + +NSPR_API(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info); +NSPR_API(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************** + * FUNCTION: PR_GetOpenFileInfo, PR_GetOpenFileInfo64 + * DESCRIPTION: + * Get information about an open file referred to by the + * given PRFileDesc object. + * INPUTS: + * const PRFileDesc *fd + * A reference to a valid, open file. + * OUTPUTS: + * Same as PR_GetFileInfo, PR_GetFileInfo64 + * RETURN: PRStatus + * PR_GetFileInfo returns PR_SUCCESS if file information is successfully + * obtained, otherwise it returns PR_FAILURE. + *************************************************************************** + */ + +NSPR_API(PRStatus) PR_GetOpenFileInfo(PRFileDesc *fd, PRFileInfo *info); +NSPR_API(PRStatus) PR_GetOpenFileInfo64(PRFileDesc *fd, PRFileInfo64 *info); + +/* + ************************************************************************** + * FUNCTION: PR_Rename + * DESCRIPTION: + * Rename a file from the old name 'from' to the new name 'to'. + * INPUTS: + * const char *from + * The old name of the file to be renamed. + * const char *to + * The new name of the file. + * OUTPUTS: + * None. + * RETURN: PRStatus + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Rename(const char *from, const char *to); + +/* + ************************************************************************* + * FUNCTION: PR_Access + * DESCRIPTION: + * Determine accessibility of a file. + * INPUTS: + * const char *name + * path name of the file + * PRAccessHow how + * specifies which access permission to check for. + * It can be one of the following values: + * PR_ACCESS_READ_OK Test for read permission + * PR_ACCESS_WRITE_OK Test for write permission + * PR_ACCESS_EXISTS Check existence of file + * OUTPUTS: + * None. + * RETURN: PRStatus + * PR_SUCCESS is returned if the requested access is permitted. + * Otherwise, PR_FAILURE is returned. Additional information + * regarding the reason for the failure may be retrieved from + * PR_GetError(). + ************************************************************************* + */ + +typedef enum PRAccessHow { + PR_ACCESS_EXISTS = 1, + PR_ACCESS_WRITE_OK = 2, + PR_ACCESS_READ_OK = 3 +} PRAccessHow; + +NSPR_API(PRStatus) PR_Access(const char *name, PRAccessHow how); + +/* + ************************************************************************* + * FUNCTION: PR_Seek, PR_Seek64 + * DESCRIPTION: + * Moves read-write file offset + * INPUTS: + * PRFileDesc *fd + * Pointer to a PRFileDesc object. + * PROffset32, PROffset64 offset + * Specifies a value, in bytes, that is used in conjunction + * with the 'whence' parameter to set the file pointer. A + * negative value causes seeking in the reverse direction. + * PRSeekWhence whence + * Specifies how to interpret the 'offset' parameter in setting + * the file pointer associated with the 'fd' parameter. + * Values for the 'whence' parameter are: + * PR_SEEK_SET Sets the file pointer to the value of the + * 'offset' parameter + * PR_SEEK_CUR Sets the file pointer to its current location + * plus the value of the offset parameter. + * PR_SEEK_END Sets the file pointer to the size of the + * file plus the value of the offset parameter. + * OUTPUTS: + * None. + * RETURN: PROffset32, PROffset64 + * Upon successful completion, the resulting pointer location, + * measured in bytes from the beginning of the file, is returned. + * If the PR_Seek() function fails, the file offset remains + * unchanged, and the returned value is -1. The error code can + * then be retrieved via PR_GetError(). + ************************************************************************* + */ + +NSPR_API(PROffset32) PR_Seek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence); +NSPR_API(PROffset64) PR_Seek64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence); + +/* + ************************************************************************ + * FUNCTION: PR_Available + * DESCRIPTION: + * Determine the amount of data in bytes available for reading + * in the given file or socket. + * INPUTS: + * PRFileDesc *fd + * Pointer to a PRFileDesc object that refers to a file or + * socket. + * OUTPUTS: + * None + * RETURN: PRInt32, PRInt64 + * Upon successful completion, PR_Available returns the number of + * bytes beyond the current read pointer that is available for + * reading. Otherwise, it returns a -1 and the reason for the + * failure can be retrieved via PR_GetError(). + ************************************************************************ + */ + +NSPR_API(PRInt32) PR_Available(PRFileDesc *fd); +NSPR_API(PRInt64) PR_Available64(PRFileDesc *fd); + +/* + ************************************************************************ + * FUNCTION: PR_Sync + * DESCRIPTION: + * Sync any buffered data for a fd to its backing device (disk). + * INPUTS: + * PRFileDesc *fd + * Pointer to a PRFileDesc object that refers to a file or + * socket + * OUTPUTS: + * None + * RETURN: PRStatus + * PR_SUCCESS is returned if the requested access is permitted. + * Otherwise, PR_FAILURE is returned. + ************************************************************************ + */ + +NSPR_API(PRStatus) PR_Sync(PRFileDesc *fd); + +/************************************************************************/ + +struct PRDirEntry { + const char *name; /* name of entry, relative to directory name */ +}; + +#ifdef MOZ_UNICODE +struct PRDirEntryUTF16 { + const PRUnichar *name; /* name of entry in UTF16, relative to + * directory name */ +}; +#endif /* MOZ_UNICODE */ + +#if !defined(NO_NSPR_10_SUPPORT) +#define PR_DirName(dirEntry) (dirEntry->name) +#endif + +/* + ************************************************************************* + * FUNCTION: PR_OpenDir + * DESCRIPTION: + * Open the directory by the given name + * INPUTS: + * const char *name + * path name of the directory to be opened + * OUTPUTS: + * None + * RETURN: PRDir * + * If the directory is sucessfully opened, a PRDir object is + * dynamically allocated and a pointer to it is returned. + * If the directory cannot be opened, a NULL pointer is returned. + * MEMORY: + * Upon successful completion, the return value points to + * dynamically allocated memory. + ************************************************************************* + */ + +NSPR_API(PRDir*) PR_OpenDir(const char *name); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************* + * FUNCTION: PR_ReadDir + * DESCRIPTION: + * INPUTS: + * PRDir *dir + * pointer to a PRDir object that designates an open directory + * PRDirFlags flags + * PR_SKIP_NONE Do not skip any files + * PR_SKIP_DOT Skip the directory entry "." that + * represents the current directory + * PR_SKIP_DOT_DOT Skip the directory entry ".." that + * represents the parent directory. + * PR_SKIP_BOTH Skip both '.' and '..' + * PR_SKIP_HIDDEN Skip hidden files + * OUTPUTS: + * RETURN: PRDirEntry* + * Returns a pointer to the next entry in the directory. Returns + * a NULL pointer upon reaching the end of the directory or when an + * error occurs. The actual reason can be retrieved via PR_GetError(). + ************************************************************************* + */ + +typedef enum PRDirFlags { + PR_SKIP_NONE = 0x0, + PR_SKIP_DOT = 0x1, + PR_SKIP_DOT_DOT = 0x2, + PR_SKIP_BOTH = 0x3, + PR_SKIP_HIDDEN = 0x4 +} PRDirFlags; + +NSPR_API(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************* + * FUNCTION: PR_CloseDir + * DESCRIPTION: + * Close the specified directory. + * INPUTS: + * PRDir *dir + * The directory to be closed. + * OUTPUTS: + * None + * RETURN: PRStatus + * If successful, will return a status of PR_SUCCESS. Otherwise + * a value of PR_FAILURE. The reason for the failure may be re- + * trieved using PR_GetError(). + ************************************************************************* + */ + +NSPR_API(PRStatus) PR_CloseDir(PRDir *dir); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRStatus) PR_CloseDirUTF16(PRDirUTF16 *dir); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************* + * FUNCTION: PR_MkDir + * DESCRIPTION: + * Create a new directory with the given name and access mode. + * INPUTS: + * const char *name + * The name of the directory to be created. All the path components + * up to but not including the leaf component must already exist. + * PRIntn mode + * See 'mode' definiton in PR_Open(). + * OUTPUTS: + * None + * RETURN: PRStatus + * If successful, will return a status of PR_SUCCESS. Otherwise + * a value of PR_FAILURE. The reason for the failure may be re- + * trieved using PR_GetError(). + ************************************************************************* + */ + +NSPR_API(PRStatus) PR_MkDir(const char *name, PRIntn mode); + +/* + ************************************************************************* + * FUNCTION: PR_MakeDir + * DESCRIPTION: + * Create a new directory with the given name and access mode. + * PR_MakeDir has the same prototype as PR_MkDir but implements + * the specified access mode where possible. + ************************************************************************* + */ + +NSPR_API(PRStatus) PR_MakeDir(const char *name, PRIntn mode); + +/* + ************************************************************************* + * FUNCTION: PR_RmDir + * DESCRIPTION: + * Remove a directory by the given name. + * INPUTS: + * const char *name + * The name of the directory to be removed. All the path components + * must already exist. Only the leaf component will be removed. + * OUTPUTS: + * None + * RETURN: PRStatus + * If successful, will return a status of PR_SUCCESS. Otherwise + * a value of PR_FAILURE. The reason for the failure may be re- + * trieved using PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_RmDir(const char *name); + +/* + ************************************************************************* + * FUNCTION: PR_NewUDPSocket + * DESCRIPTION: + * Create a new UDP socket. + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_NewUDPSocket returns a pointer + * to the PRFileDesc created for the newly opened UDP socket. + * Returns a NULL pointer if the creation of a new UDP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_NewUDPSocket(void); + +/* + ************************************************************************* + * FUNCTION: PR_NewTCPSocket + * DESCRIPTION: + * Create a new TCP socket. + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_NewTCPSocket returns a pointer + * to the PRFileDesc created for the newly opened TCP socket. + * Returns a NULL pointer if the creation of a new TCP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_NewTCPSocket(void); + +/* + ************************************************************************* + * FUNCTION: PR_OpenUDPSocket + * DESCRIPTION: + * Create a new UDP socket of the specified address family. + * INPUTS: + * PRIntn af + * Address family + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_OpenUDPSocket returns a pointer + * to the PRFileDesc created for the newly opened UDP socket. + * Returns a NULL pointer if the creation of a new UDP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_OpenUDPSocket(PRIntn af); + +/* + ************************************************************************* + * FUNCTION: PR_OpenTCPSocket + * DESCRIPTION: + * Create a new TCP socket of the specified address family. + * INPUTS: + * PRIntn af + * Address family + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_NewTCPSocket returns a pointer + * to the PRFileDesc created for the newly opened TCP socket. + * Returns a NULL pointer if the creation of a new TCP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_OpenTCPSocket(PRIntn af); + +/* + ************************************************************************* + * FUNCTION: PR_Connect + * DESCRIPTION: + * Initiate a connection on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a socket + * PRNetAddr *addr + * Specifies the address of the socket in its own communication + * space. + * PRIntervalTime timeout + * The function uses the lesser of the provided timeout and + * the OS's connect timeout. In particular, if you specify + * PR_INTERVAL_NO_TIMEOUT as the timeout, the OS's connection + * time limit will be used. + * + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful completion of connection initiation, PR_Connect + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Connect( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_ConnectContinue + * DESCRIPTION: + * Continue a nonblocking connect. After a nonblocking connect + * is initiated with PR_Connect() (which fails with + * PR_IN_PROGRESS_ERROR), one should call PR_Poll() on the socket, + * with the in_flags PR_POLL_WRITE | PR_POLL_EXCEPT. When + * PR_Poll() returns, one calls PR_ConnectContinue() on the + * socket to determine whether the nonblocking connect has + * completed or is still in progress. Repeat the PR_Poll(), + * PR_ConnectContinue() sequence until the nonblocking connect + * has completed. + * INPUTS: + * PRFileDesc *fd + * the file descriptor representing a socket + * PRInt16 out_flags + * the out_flags field of the poll descriptor returned by + * PR_Poll() + * RETURN: PRStatus + * If the nonblocking connect has successfully completed, + * PR_ConnectContinue returns PR_SUCCESS. If PR_ConnectContinue() + * returns PR_FAILURE, call PR_GetError(): + * - PR_IN_PROGRESS_ERROR: the nonblocking connect is still in + * progress and has not completed yet. The caller should poll + * on the file descriptor for the in_flags + * PR_POLL_WRITE|PR_POLL_EXCEPT and retry PR_ConnectContinue + * later when PR_Poll() returns. + * - Other errors: the nonblocking connect has failed with this + * error code. + */ + +NSPR_API(PRStatus) PR_ConnectContinue(PRFileDesc *fd, PRInt16 out_flags); + +/* + ************************************************************************* + * THIS FUNCTION IS DEPRECATED. USE PR_ConnectContinue INSTEAD. + * + * FUNCTION: PR_GetConnectStatus + * DESCRIPTION: + * Get the completion status of a nonblocking connect. After + * a nonblocking connect is initiated with PR_Connect() (which + * fails with PR_IN_PROGRESS_ERROR), one should call PR_Poll() + * on the socket, with the in_flags PR_POLL_WRITE | PR_POLL_EXCEPT. + * When PR_Poll() returns, one calls PR_GetConnectStatus on the + * PRPollDesc structure to determine whether the nonblocking + * connect has succeeded or failed. + * INPUTS: + * const PRPollDesc *pd + * Pointer to a PRPollDesc whose fd member is the socket, + * and in_flags must contain PR_POLL_WRITE and PR_POLL_EXCEPT. + * PR_Poll() should have been called and set the out_flags. + * RETURN: PRStatus + * If the nonblocking connect has successfully completed, + * PR_GetConnectStatus returns PR_SUCCESS. If PR_GetConnectStatus() + * returns PR_FAILURE, call PR_GetError(): + * - PR_IN_PROGRESS_ERROR: the nonblocking connect is still in + * progress and has not completed yet. + * - Other errors: the nonblocking connect has failed with this + * error code. + */ + +NSPR_API(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd); + +/* + ************************************************************************* + * FUNCTION: PR_Accept + * DESCRIPTION: + * Accept a connection on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing the rendezvous socket + * on which the caller is willing to accept new connections. + * PRIntervalTime timeout + * Time limit for completion of the accept operation. + * OUTPUTS: + * PRNetAddr *addr + * Returns the address of the connecting entity in its own + * communication space. It may be NULL. + * RETURN: PRFileDesc* + * Upon successful acceptance of a connection, PR_Accept + * returns a valid file descriptor. Otherwise, it returns NULL. + * Further failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_Accept( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_Bind + * DESCRIPTION: + * Bind an address to a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a socket. + * PRNetAddr *addr + * Specifies the address to which the socket will be bound. + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful binding of an address to a socket, PR_Bind + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Bind(PRFileDesc *fd, const PRNetAddr *addr); + +/* + ************************************************************************* + * FUNCTION: PR_Listen + * DESCRIPTION: + * Listen for connections on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a socket that will be + * used to listen for new connections. + * PRIntn backlog + * Specifies the maximum length of the queue of pending connections. + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful completion of listen request, PR_Listen + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Listen(PRFileDesc *fd, PRIntn backlog); + +/* + ************************************************************************* + * FUNCTION: PR_Shutdown + * DESCRIPTION: + * Shut down part of a full-duplex connection on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a connected socket. + * PRIntn how + * Specifies the kind of disallowed operations on the socket. + * PR_SHUTDOWN_RCV - Further receives will be disallowed + * PR_SHUTDOWN_SEND - Further sends will be disallowed + * PR_SHUTDOWN_BOTH - Further sends and receives will be disallowed + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful completion of shutdown request, PR_Shutdown + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +typedef enum PRShutdownHow +{ + PR_SHUTDOWN_RCV = 0, /* disallow further receives */ + PR_SHUTDOWN_SEND = 1, /* disallow further sends */ + PR_SHUTDOWN_BOTH = 2 /* disallow further receives and sends */ +} PRShutdownHow; + +NSPR_API(PRStatus) PR_Shutdown(PRFileDesc *fd, PRShutdownHow how); + +/* + ************************************************************************* + * FUNCTION: PR_Recv + * DESCRIPTION: + * Receive a specified number of bytes from a connected socket. + * The operation will block until some positive number of bytes are + * transferred, a time out has occurred, or there is an error. + * No more than 'amount' bytes will be transferred. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing a socket. + * void *buf + * pointer to a buffer to hold the data received. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * must be zero or PR_MSG_PEEK. + * PRIntervalTime timeout + * Time limit for completion of the receive operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * a positive number indicates the number of bytes actually received. + * 0 means the network connection is closed. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + ************************************************************************** + */ + +#define PR_MSG_PEEK 0x2 + +NSPR_API(PRInt32) PR_Recv(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_Send + * DESCRIPTION: + * Send a specified number of bytes from a connected socket. + * The operation will block until all bytes are + * processed, a time out has occurred, or there is an error. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing a socket. + * void *buf + * pointer to a buffer from where the data is sent. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * (OBSOLETE - must always be zero) + * PRIntervalTime timeout + * Time limit for completion of the send operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * A positive number indicates the number of bytes successfully processed. + * This number must always equal 'amount'. A -1 is an indication that the + * operation failed. The reason for the failure is obtained by calling + * PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_Send(PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_RecvFrom + * DESCRIPTION: + * Receive up to a specified number of bytes from socket which may + * or may not be connected. + * The operation will block until one or more bytes are + * transferred, a time out has occurred, or there is an error. + * No more than 'amount' bytes will be transferred. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing a socket. + * void *buf + * pointer to a buffer to hold the data received. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * (OBSOLETE - must always be zero) + * PRNetAddr *addr + * Specifies the address of the sending peer. It may be NULL. + * PRIntervalTime timeout + * Time limit for completion of the receive operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * a positive number indicates the number of bytes actually received. + * 0 means the network connection is closed. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_RecvFrom( + PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRNetAddr *addr, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_SendTo + * DESCRIPTION: + * Send a specified number of bytes from an unconnected socket. + * The operation will block until all bytes are + * sent, a time out has occurred, or there is an error. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing an unconnected socket. + * void *buf + * pointer to a buffer from where the data is sent. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * (OBSOLETE - must always be zero) + * PRNetAddr *addr + * Specifies the address of the peer. +.* PRIntervalTime timeout + * Time limit for completion of the send operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * A positive number indicates the number of bytes successfully sent. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_SendTo( + PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_TransmitFile +** DESCRIPTION: +** Transmitfile sends a complete file (sourceFile) across a socket +** (networkSocket). If headers is non-NULL, the headers will be sent across +** the socket prior to sending the file. +** +** Optionally, the PR_TRANSMITFILE_CLOSE_SOCKET flag may be passed to +** transmitfile. This flag specifies that transmitfile should close the +** socket after sending the data. +** +** INPUTS: +** PRFileDesc *networkSocket +** The socket to send data over +** PRFileDesc *sourceFile +** The file to send +** const void *headers +** A pointer to headers to be sent before sending data +** PRInt32 hlen +** length of header buffers in bytes. +** PRTransmitFileFlags flags +** If the flags indicate that the connection should be closed, +** it will be done immediately after transferring the file, unless +** the operation is unsuccessful. +.* PRIntervalTime timeout + * Time limit for completion of the transmit operation. +** +** RETURNS: +** Returns the number of bytes written or -1 if the operation failed. +** If an error occurs while sending the file, the PR_TRANSMITFILE_CLOSE_ +** SOCKET flag is ignored. The reason for the failure is obtained +** by calling PR_GetError(). +************************************************************************** +*/ + +NSPR_API(PRInt32) PR_TransmitFile( + PRFileDesc *networkSocket, PRFileDesc *sourceFile, + const void *headers, PRInt32 hlen, PRTransmitFileFlags flags, + PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_SendFile +** DESCRIPTION: +** PR_SendFile sends data from a file (sendData->fd) across a socket +** (networkSocket). If specified, a header and/or trailer buffer are sent +** before and after the file, respectively. The file offset, number of bytes +** of file data to send, the header and trailer buffers are specified in the +** sendData argument. +** +** Optionally, if the PR_TRANSMITFILE_CLOSE_SOCKET flag is passed, the +** socket is closed after successfully sending the data. +** +** INPUTS: +** PRFileDesc *networkSocket +** The socket to send data over +** PRSendFileData *sendData +** Contains the FD, file offset and length, header and trailer +** buffer specifications. +** PRTransmitFileFlags flags +** If the flags indicate that the connection should be closed, +** it will be done immediately after transferring the file, unless +** the operation is unsuccessful. +.* PRIntervalTime timeout + * Time limit for completion of the send operation. +** +** RETURNS: +** Returns the number of bytes written or -1 if the operation failed. +** If an error occurs while sending the file, the PR_TRANSMITFILE_CLOSE_ +** SOCKET flag is ignored. The reason for the failure is obtained +** by calling PR_GetError(). +************************************************************************** +*/ + +struct PRSendFileData { + PRFileDesc *fd; /* file to send */ + PRUint32 file_offset; /* file offset */ + PRSize file_nbytes; /* number of bytes of file data to send */ + /* if 0, send data from file_offset to */ + /* end-of-file. */ + const void *header; /* header buffer */ + PRInt32 hlen; /* header len */ + const void *trailer; /* trailer buffer */ + PRInt32 tlen; /* trailer len */ +}; + + +NSPR_API(PRInt32) PR_SendFile( + PRFileDesc *networkSocket, PRSendFileData *sendData, + PRTransmitFileFlags flags, PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_AcceptRead +** DESCRIPTION: +** AcceptRead accepts a new connection, returns the newly created +** socket's descriptor and also returns the connecting peer's address. +** AcceptRead, as its name suggests, also receives the first block of data +** sent by the peer. +** +** INPUTS: +** PRFileDesc *listenSock +** A socket descriptor that has been called with the PR_Listen() +** function, also known as the rendezvous socket. +** void *buf +** A pointer to a buffer to receive data sent by the client. This +** buffer must be large enough to receive bytes of data +** and two PRNetAddr structures, plus an extra 32 bytes. See: +** PR_ACCEPT_READ_BUF_OVERHEAD. +** PRInt32 amount +** The number of bytes of client data to receive. Does not include +** the size of the PRNetAddr structures. If 0, no data will be read +** from the client. +** PRIntervalTime timeout +** The timeout interval only applies to the read portion of the +** operation. PR_AcceptRead will block indefinitely until the +** connection is accepted; the read will timeout after the timeout +** interval elapses. +** OUTPUTS: +** PRFileDesc **acceptedSock +** The file descriptor for the newly connected socket. This parameter +** will only be valid if the function return does not indicate failure. +** PRNetAddr **peerAddr, +** The address of the remote socket. This parameter will only be +** valid if the function return does not indicate failure. The +** returned address is not guaranteed to be properly aligned. +** +** RETURNS: +** The number of bytes read from the client or -1 on failure. The reason +** for the failure is obtained by calling PR_GetError(). +************************************************************************** +**/ +/* define buffer overhead constant. Add this value to the user's +** data length when allocating a buffer to accept data. +** Example: +** #define USER_DATA_SIZE 10 +** char buf[USER_DATA_SIZE + PR_ACCEPT_READ_BUF_OVERHEAD]; +** bytesRead = PR_AcceptRead( s, fd, &a, &p, USER_DATA_SIZE, ...); +*/ +#define PR_ACCEPT_READ_BUF_OVERHEAD (32+(2*sizeof(PRNetAddr))) + +NSPR_API(PRInt32) PR_AcceptRead( + PRFileDesc *listenSock, PRFileDesc **acceptedSock, + PRNetAddr **peerAddr, void *buf, PRInt32 amount, PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_NewTCPSocketPair +** DESCRIPTION: +** Create a new TCP socket pair. The returned descriptors can be used +** interchangeably; they are interconnected full-duplex descriptors: data +** written to one can be read from the other and vice-versa. +** +** INPUTS: +** None +** OUTPUTS: +** PRFileDesc *fds[2] +** The file descriptor pair for the newly created TCP sockets. +** RETURN: PRStatus +** Upon successful completion of TCP socket pair, PR_NewTCPSocketPair +** returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further +** failure information can be obtained by calling PR_GetError(). +** XXX can we implement this on windoze and mac? +************************************************************************** +**/ +NSPR_API(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2]); + +/* +************************************************************************* +** FUNCTION: PR_GetSockName +** DESCRIPTION: +** Get socket name. Return the network address for this socket. +** +** INPUTS: +** PRFileDesc *fd +** Points to a PRFileDesc object representing the socket. +** OUTPUTS: +** PRNetAddr *addr +** Returns the address of the socket in its own communication space. +** RETURN: PRStatus +** Upon successful completion, PR_GetSockName returns PR_SUCCESS. +** Otherwise, it returns PR_FAILURE. Further failure information can +** be obtained by calling PR_GetError(). +************************************************************************** +**/ +NSPR_API(PRStatus) PR_GetSockName(PRFileDesc *fd, PRNetAddr *addr); + +/* +************************************************************************* +** FUNCTION: PR_GetPeerName +** DESCRIPTION: +** Get name of the connected peer. Return the network address for the +** connected peer socket. +** +** INPUTS: +** PRFileDesc *fd +** Points to a PRFileDesc object representing the connected peer. +** OUTPUTS: +** PRNetAddr *addr +** Returns the address of the connected peer in its own communication +** space. +** RETURN: PRStatus +** Upon successful completion, PR_GetPeerName returns PR_SUCCESS. +** Otherwise, it returns PR_FAILURE. Further failure information can +** be obtained by calling PR_GetError(). +************************************************************************** +**/ +NSPR_API(PRStatus) PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr); + +NSPR_API(PRStatus) PR_GetSocketOption( + PRFileDesc *fd, PRSocketOptionData *data); + +NSPR_API(PRStatus) PR_SetSocketOption( + PRFileDesc *fd, const PRSocketOptionData *data); + +/* + ********************************************************************* + * + * File descriptor inheritance + * + ********************************************************************* + */ + +/* + ************************************************************************ + * FUNCTION: PR_SetFDInheritable + * DESCRIPTION: + * Set the inheritance attribute of a file descriptor. + * + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object. + * PRBool inheritable + * If PR_TRUE, the file descriptor fd is set to be inheritable + * by a child process. If PR_FALSE, the file descriptor is set + * to be not inheritable by a child process. + * RETURN: PRStatus + * Upon successful completion, PR_SetFDInheritable returns PR_SUCCESS. + * Otherwise, it returns PR_FAILURE. Further failure information can + * be obtained by calling PR_GetError(). + ************************************************************************* + */ +NSPR_API(PRStatus) PR_SetFDInheritable( + PRFileDesc *fd, + PRBool inheritable); + +/* + ************************************************************************ + * FUNCTION: PR_GetInheritedFD + * DESCRIPTION: + * Get an inherited file descriptor with the specified name. + * + * INPUTS: + * const char *name + * The name of the inherited file descriptor. + * RETURN: PRFileDesc * + * Upon successful completion, PR_GetInheritedFD returns the + * inherited file descriptor with the specified name. Otherwise, + * it returns NULL. Further failure information can be obtained + * by calling PR_GetError(). + ************************************************************************* + */ +NSPR_API(PRFileDesc *) PR_GetInheritedFD(const char *name); + +/* + ********************************************************************* + * + * Memory-mapped files + * + ********************************************************************* + */ + +typedef struct PRFileMap PRFileMap; + +/* + * protection options for read and write accesses of a file mapping + */ +typedef enum PRFileMapProtect { + PR_PROT_READONLY, /* read only */ + PR_PROT_READWRITE, /* readable, and write is shared */ + PR_PROT_WRITECOPY /* readable, and write is private (copy-on-write) */ +} PRFileMapProtect; + +NSPR_API(PRFileMap *) PR_CreateFileMap( + PRFileDesc *fd, + PRInt64 size, + PRFileMapProtect prot); + +/* + * return the alignment (in bytes) of the offset argument to PR_MemMap + */ +NSPR_API(PRInt32) PR_GetMemMapAlignment(void); + +NSPR_API(void *) PR_MemMap( + PRFileMap *fmap, + PROffset64 offset, /* must be aligned and sized according to the + * return value of PR_GetMemMapAlignment() */ + PRUint32 len); + +NSPR_API(PRStatus) PR_MemUnmap(void *addr, PRUint32 len); + +NSPR_API(PRStatus) PR_CloseFileMap(PRFileMap *fmap); + +/* + * Synchronously flush the given memory-mapped address range of the given open + * file to disk. The function does not return until all modified data have + * been written to disk. + * + * On some platforms, the function will call PR_Sync(fd) internally if it is + * necessary for flushing modified data to disk synchronously. + */ +NSPR_API(PRStatus) PR_SyncMemMap( + PRFileDesc *fd, + void *addr, + PRUint32 len); + +/* + ****************************************************************** + * + * Interprocess communication + * + ****************************************************************** + */ + +/* + * Creates an anonymous pipe and returns file descriptors for the + * read and write ends of the pipe. + */ + +NSPR_API(PRStatus) PR_CreatePipe( + PRFileDesc **readPipe, + PRFileDesc **writePipe +); + +/************************************************************************/ +/************** The following definitions are for poll ******************/ +/************************************************************************/ + +struct PRPollDesc { + PRFileDesc* fd; + PRInt16 in_flags; + PRInt16 out_flags; +}; + +/* +** Bit values for PRPollDesc.in_flags or PRPollDesc.out_flags. Binary-or +** these together to produce the desired poll request. +*/ + +#if defined(_PR_POLL_BACKCOMPAT) + +#include +#define PR_POLL_READ POLLIN +#define PR_POLL_WRITE POLLOUT +#define PR_POLL_EXCEPT POLLPRI +#define PR_POLL_ERR POLLERR /* only in out_flags */ +#define PR_POLL_NVAL POLLNVAL /* only in out_flags when fd is bad */ +#define PR_POLL_HUP POLLHUP /* only in out_flags */ + +#else /* _PR_POLL_BACKCOMPAT */ + +#define PR_POLL_READ 0x1 +#define PR_POLL_WRITE 0x2 +#define PR_POLL_EXCEPT 0x4 +#define PR_POLL_ERR 0x8 /* only in out_flags */ +#define PR_POLL_NVAL 0x10 /* only in out_flags when fd is bad */ +#define PR_POLL_HUP 0x20 /* only in out_flags */ + +#endif /* _PR_POLL_BACKCOMPAT */ + +/* +************************************************************************* +** FUNCTION: PR_Poll +** DESCRIPTION: +** +** The call returns as soon as I/O is ready on one or more of the underlying +** socket objects. A count of the number of ready descriptors is +** returned unless a timeout occurs in which case zero is returned. +** +** PRPollDesc.fd should be set to a pointer to a PRFileDesc object +** representing a socket. This field can be set to NULL to indicate to +** PR_Poll that this PRFileDesc object should be ignored. +** PRPollDesc.in_flags should be set to the desired request +** (read/write/except or some combination). Upon successful return from +** this call PRPollDesc.out_flags will be set to indicate what kind of +** i/o can be performed on the respective descriptor. PR_Poll() uses the +** out_flags fields as scratch variables during the call. If PR_Poll() +** returns 0 or -1, the out_flags fields do not contain meaningful values +** and must not be used. +** +** INPUTS: +** PRPollDesc *pds A pointer to an array of PRPollDesc +** +** PRIntn npds The number of elements in the array +** If this argument is zero PR_Poll is +** equivalent to a PR_Sleep(timeout). +** +** PRIntervalTime timeout Amount of time the call will block waiting +** for I/O to become ready. If this time expires +** w/o any I/O becoming ready, the result will +** be zero. +** +** OUTPUTS: None +** RETURN: +** PRInt32 Number of PRPollDesc's with events or zero +** if the function timed out or -1 on failure. +** The reason for the failure is obtained by +** calling PR_GetError(). +************************************************************************** +*/ +NSPR_API(PRInt32) PR_Poll( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout); + +/* +************************************************************************** +** +** Pollable events +** +** A pollable event is a special kind of file descriptor. +** The only I/O operation you can perform on a pollable event +** is to poll it with the PR_POLL_READ flag. You can't +** read from or write to a pollable event. +** +** The purpose of a pollable event is to combine event waiting +** with I/O waiting in a single PR_Poll call. Pollable events +** are implemented using a pipe or a pair of TCP sockets +** connected via the loopback address, therefore setting and +** waiting for pollable events are expensive operating system +** calls. Do not use pollable events for general thread +** synchronization. Use condition variables instead. +** +** A pollable event has two states: set and unset. Events +** are not queued, so there is no notion of an event count. +** A pollable event is either set or unset. +** +** A new pollable event is created by a PR_NewPollableEvent +** call and is initially in the unset state. +** +** PR_WaitForPollableEvent blocks the calling thread until +** the pollable event is set, and then it atomically unsets +** the pollable event before it returns. +** +** To set a pollable event, call PR_SetPollableEvent. +** +** One can call PR_Poll with the PR_POLL_READ flag on a pollable +** event. When the pollable event is set, PR_Poll returns with +** the PR_POLL_READ flag set in the out_flags. +** +** To close a pollable event, call PR_DestroyPollableEvent +** (not PR_Close). +** +************************************************************************** +*/ + +NSPR_API(PRFileDesc *) PR_NewPollableEvent(void); + +NSPR_API(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event); + +NSPR_API(PRStatus) PR_SetPollableEvent(PRFileDesc *event); + +NSPR_API(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event); + +PR_END_EXTERN_C + +#endif /* prio_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/pripcsem.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/pripcsem.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/pripcsem.h @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* + * File: pripcsem.h + * + * Description: named semaphores for interprocess + * synchronization + * + * Unrelated processes obtain access to a shared semaphore + * by specifying its name. + * + * Our goal is to support named semaphores on at least + * Unix and Win32 platforms. The implementation will use + * one of the three native semaphore APIs: POSIX, System V, + * and Win32. + * + * Because POSIX named semaphores have kernel persistence, + * we are forced to have a delete function in this API. + */ + +#ifndef pripcsem_h___ +#define pripcsem_h___ + +#include "prtypes.h" +#include "prio.h" + +PR_BEGIN_EXTERN_C + +/* + * PRSem is an opaque structure that represents a named + * semaphore. + */ +typedef struct PRSem PRSem; + +/* + * PR_OpenSemaphore -- + * + * Create or open a named semaphore with the specified name. + * A handle to the semaphore is returned. + * + * If the named semaphore doesn't exist and the PR_SEM_CREATE + * flag is specified, the named semaphore is created. The + * created semaphore needs to be removed from the system with + * a PR_DeleteSemaphore call. + * + * If PR_SEM_CREATE is specified, the third argument is the + * access permission bits of the new semaphore (same + * interpretation as the mode argument to PR_Open) and the + * fourth argument is the initial value of the new semaphore. + * If PR_SEM_CREATE is not specified, the third and fourth + * arguments are ignored. + */ + +#define PR_SEM_CREATE 0x1 /* create if not exist */ +#define PR_SEM_EXCL 0x2 /* fail if already exists */ + +NSPR_API(PRSem *) PR_OpenSemaphore( + const char *name, PRIntn flags, PRIntn mode, PRUintn value); + +/* + * PR_WaitSemaphore -- + * + * If the value of the semaphore is > 0, decrement the value and return. + * If the value is 0, sleep until the value becomes > 0, then decrement + * the value and return. + * + * The "test and decrement" operation is performed atomically. + */ + +NSPR_API(PRStatus) PR_WaitSemaphore(PRSem *sem); + +/* + * PR_PostSemaphore -- + * + * Increment the value of the named semaphore by 1. + */ + +NSPR_API(PRStatus) PR_PostSemaphore(PRSem *sem); + +/* + * PR_CloseSemaphore -- + * + * Close a named semaphore handle. + */ + +NSPR_API(PRStatus) PR_CloseSemaphore(PRSem *sem); + +/* + * PR_DeleteSemaphore -- + * + * Remove a named semaphore from the system. + */ + +NSPR_API(PRStatus) PR_DeleteSemaphore(const char *name); + +PR_END_EXTERN_C + +#endif /* pripcsem_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/private/pprio.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/private/pprio.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/private/pprio.h @@ -0,0 +1,242 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: pprio.h +** +** Description: Private definitions for I/O related structures +*/ + +#ifndef pprio_h___ +#define pprio_h___ + +#include "prtypes.h" +#include "prio.h" + +PR_BEGIN_EXTERN_C + +/************************************************************************/ +/************************************************************************/ + +#ifdef _WIN64 +typedef __int64 PROsfd; +#else +typedef PRInt32 PROsfd; +#endif + +/* Return the method tables for files, tcp sockets and udp sockets */ +NSPR_API(const PRIOMethods*) PR_GetFileMethods(void); +NSPR_API(const PRIOMethods*) PR_GetTCPMethods(void); +NSPR_API(const PRIOMethods*) PR_GetUDPMethods(void); +NSPR_API(const PRIOMethods*) PR_GetPipeMethods(void); + +/* +** Convert a NSPR socket handle to a native socket handle. +** +** Using this function makes your code depend on the properties of the +** current NSPR implementation, which may change (although extremely +** unlikely because of NSPR's backward compatibility requirement). Avoid +** using it if you can. +** +** If you use this function, you need to understand what NSPR does to +** the native handle. For example, NSPR puts native socket handles in +** non-blocking mode or associates them with an I/O completion port (the +** WINNT build configuration only). Your use of the native handle should +** not interfere with NSPR's use of the native handle. If your code +** changes the configuration of the native handle, (e.g., changes it to +** blocking or closes it), NSPR will not work correctly. +*/ +NSPR_API(PROsfd) PR_FileDesc2NativeHandle(PRFileDesc *); +NSPR_API(void) PR_ChangeFileDescNativeHandle(PRFileDesc *, PROsfd); +NSPR_API(PRFileDesc*) PR_AllocFileDesc(PROsfd osfd, + const PRIOMethods *methods); +NSPR_API(void) PR_FreeFileDesc(PRFileDesc *fd); +/* +** Import an existing OS file to NSPR. +*/ +NSPR_API(PRFileDesc*) PR_ImportFile(PROsfd osfd); +NSPR_API(PRFileDesc*) PR_ImportPipe(PROsfd osfd); +NSPR_API(PRFileDesc*) PR_ImportTCPSocket(PROsfd osfd); +NSPR_API(PRFileDesc*) PR_ImportUDPSocket(PROsfd osfd); + + +/* + ************************************************************************* + * FUNCTION: PR_CreateSocketPollFd + * DESCRIPTION: + * Create a PRFileDesc wrapper for a native socket handle, for use with + * PR_Poll only + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_CreateSocketPollFd returns a pointer + * to the PRFileDesc created for the native socket handle + * Returns a NULL pointer if the create of a new PRFileDesc failed + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_CreateSocketPollFd(PROsfd osfd); + +/* + ************************************************************************* + * FUNCTION: PR_DestroySocketPollFd + * DESCRIPTION: + * Destroy the PRFileDesc wrapper created by PR_CreateSocketPollFd + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_DestroySocketPollFd returns + * PR_SUCCESS, else PR_FAILURE + * + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd); + + +/* +** Macros for PR_Socket +** +** Socket types: PR_SOCK_STREAM, PR_SOCK_DGRAM +*/ + +#ifdef WIN32 + +#define PR_SOCK_STREAM 1 +#define PR_SOCK_DGRAM 2 + +#else /* WIN32 */ + +#define PR_SOCK_STREAM SOCK_STREAM +#define PR_SOCK_DGRAM SOCK_DGRAM + +#endif /* WIN32 */ + +/* +** Create a new Socket; this function is obsolete. +*/ +NSPR_API(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto); + +/* FUNCTION: PR_LockFile +** DESCRIPTION: +** Lock a file for exclusive access. +** RETURNS: +** PR_SUCCESS when the lock is held +** PR_FAILURE otherwise +*/ +NSPR_API(PRStatus) PR_LockFile(PRFileDesc *fd); + +/* FUNCTION: PR_TLockFile +** DESCRIPTION: +** Test and Lock a file for exclusive access. Do not block if the +** file cannot be locked immediately. +** RETURNS: +** PR_SUCCESS when the lock is held +** PR_FAILURE otherwise +*/ +NSPR_API(PRStatus) PR_TLockFile(PRFileDesc *fd); + +/* FUNCTION: PR_UnlockFile +** DESCRIPTION: +** Unlock a file which has been previously locked successfully by this +** process. +** RETURNS: +** PR_SUCCESS when the lock is released +** PR_FAILURE otherwise +*/ +NSPR_API(PRStatus) PR_UnlockFile(PRFileDesc *fd); + +/* +** Emulate acceptread by accept and recv. +*/ +NSPR_API(PRInt32) PR_EmulateAcceptRead(PRFileDesc *sd, PRFileDesc **nd, + PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout); + +/* +** Emulate sendfile by reading from the file and writing to the socket. +** The file is memory-mapped if memory-mapped files are supported. +*/ +NSPR_API(PRInt32) PR_EmulateSendFile( + PRFileDesc *networkSocket, PRSendFileData *sendData, + PRTransmitFileFlags flags, PRIntervalTime timeout); + +#ifdef WIN32 +/* FUNCTION: PR_NTFast_AcceptRead +** DESCRIPTION: +** NT has the notion of an "accept context", which is only needed in +** order to make certain calls. By default, a socket connected via +** AcceptEx can only do a limited number of things without updating +** the acceptcontext. The generic version of PR_AcceptRead always +** updates the accept context. This version does not. +**/ +NSPR_API(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd, + PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime t); + +typedef void (*_PR_AcceptTimeoutCallback)(void *); + +/* FUNCTION: PR_NTFast_AcceptRead_WithTimeoutCallback +** DESCRIPTION: +** The AcceptEx call combines the accept with the read function. However, +** our daemon threads need to be able to wakeup and reliably flush their +** log buffers if the Accept times out. However, with the current blocking +** interface to AcceptRead, there is no way for us to timeout the Accept; +** this is because when we timeout the Read, we can close the newly +** socket and continue; but when we timeout the accept itself, there is no +** new socket to timeout. So instead, this version of the function is +** provided. After the initial timeout period elapses on the accept() +** portion of the function, it will call the callback routine and then +** continue the accept. If the timeout occurs on the read, it will +** close the connection and return error. +*/ +NSPR_API(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback( + PRFileDesc *sd, + PRFileDesc **nd, + PRNetAddr **raddr, + void *buf, + PRInt32 amount, + PRIntervalTime t, + _PR_AcceptTimeoutCallback callback, + void *callback_arg); + +/* FUNCTION: PR_NTFast_Accept +** DESCRIPTION: +** NT has the notion of an "accept context", which is only needed in +** order to make certain calls. By default, a socket connected via +** AcceptEx can only do a limited number of things without updating +** the acceptcontext. The generic version of PR_Accept always +** updates the accept context. This version does not. +**/ +NSPR_API(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr, + PRIntervalTime timeout); + +/* FUNCTION: PR_NTFast_Update +** DESCRIPTION: +** For sockets accepted with PR_NTFast_Accept or PR_NTFastAcceptRead, +** this function will update the accept context for those sockets, +** so that the socket can make general purpose socket calls. +** Without calling this, the only operations supported on the socket +** Are PR_Read, PR_Write, PR_Transmitfile, and PR_Close. +*/ +NSPR_API(void) PR_NTFast_UpdateAcceptContext(PRFileDesc *acceptSock, + PRFileDesc *listenSock); + + +/* FUNCTION: PR_NT_CancelIo +** DESCRIPTION: +** Cancel IO operations on fd. +*/ +NSPR_API(PRStatus) PR_NT_CancelIo(PRFileDesc *fd); + + +#endif /* WIN32 */ + +PR_END_EXTERN_C + +#endif /* pprio_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/private/pprthred.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/private/pprthred.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/private/pprthred.h @@ -0,0 +1,331 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef pprthred_h___ +#define pprthred_h___ + +/* +** API for PR private functions. These calls are to be used by internal +** developers only. +*/ +#include "nspr.h" + +#if defined(XP_OS2) +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_WIN +#include +#endif + +PR_BEGIN_EXTERN_C + +/*--------------------------------------------------------------------------- +** THREAD PRIVATE FUNCTIONS +---------------------------------------------------------------------------*/ + +/* +** Associate a thread object with an existing native thread. +** "type" is the type of thread object to attach +** "priority" is the priority to assign to the thread +** "stack" defines the shape of the threads stack +** +** This can return NULL if some kind of error occurs, or if memory is +** tight. This call invokes "start(obj,arg)" and returns when the +** function returns. The thread object is automatically destroyed. +** +** This call is not normally needed unless you create your own native +** thread. PR_Init does this automatically for the primordial thread. +*/ +NSPR_API(PRThread*) PR_AttachThread(PRThreadType type, + PRThreadPriority priority, + PRThreadStack *stack); + +/* +** Detach the nspr thread from the currently executing native thread. +** The thread object will be destroyed and all related data attached +** to it. The exit procs will be invoked. +** +** This call is not normally needed unless you create your own native +** thread. PR_Exit will automatially detach the nspr thread object +** created by PR_Init for the primordial thread. +** +** This call returns after the nspr thread object is destroyed. +*/ +NSPR_API(void) PR_DetachThread(void); + +/* +** Get the id of the named thread. Each thread is assigned a unique id +** when it is created or attached. +*/ +NSPR_API(PRUint32) PR_GetThreadID(PRThread *thread); + +/* +** Set the procedure that is called when a thread is dumped. The procedure +** will be applied to the argument, arg, when called. Setting the procedure +** to NULL effectively removes it. +*/ +typedef void (*PRThreadDumpProc)(PRFileDesc *fd, PRThread *t, void *arg); +NSPR_API(void) PR_SetThreadDumpProc( + PRThread* thread, PRThreadDumpProc dump, void *arg); + +/* +** Get this thread's affinity mask. The affinity mask is a 32 bit quantity +** marking a bit for each processor this process is allowed to run on. +** The processor mask is returned in the mask argument. +** The least-significant-bit represents processor 0. +** +** Returns 0 on success, -1 on failure. +*/ +NSPR_API(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask); + +/* +** Set this thread's affinity mask. +** +** Returns 0 on success, -1 on failure. +*/ +NSPR_API(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask ); + +/* +** Set the default CPU Affinity mask. +** +*/ +NSPR_API(PRInt32) PR_SetCPUAffinityMask(PRUint32 mask); + +/* +** Show status of all threads to standard error output. +*/ +NSPR_API(void) PR_ShowStatus(void); + +/* +** Set thread recycle mode to on (1) or off (0) +*/ +NSPR_API(void) PR_SetThreadRecycleMode(PRUint32 flag); + + +/*--------------------------------------------------------------------------- +** THREAD PRIVATE FUNCTIONS FOR GARBAGE COLLECTIBLE THREADS +---------------------------------------------------------------------------*/ + +/* +** Only Garbage collectible threads participate in resume all, suspend all and +** enumeration operations. They are also different during creation when +** platform specific action may be needed (For example, all Solaris GC able +** threads are bound threads). +*/ + +/* +** Same as PR_CreateThread except that the thread is marked as garbage +** collectible. +*/ +NSPR_API(PRThread*) PR_CreateThreadGCAble(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); + +/* +** Same as PR_AttachThread except that the thread being attached is marked as +** garbage collectible. +*/ +NSPR_API(PRThread*) PR_AttachThreadGCAble(PRThreadType type, + PRThreadPriority priority, + PRThreadStack *stack); + +/* +** Mark the thread as garbage collectible. +*/ +NSPR_API(void) PR_SetThreadGCAble(void); + +/* +** Unmark the thread as garbage collectible. +*/ +NSPR_API(void) PR_ClearThreadGCAble(void); + +/* +** This routine prevents all other GC able threads from running. This call is needed by +** the garbage collector. +*/ +NSPR_API(void) PR_SuspendAll(void); + +/* +** This routine unblocks all other GC able threads that were suspended from running by +** PR_SuspendAll(). This call is needed by the garbage collector. +*/ +NSPR_API(void) PR_ResumeAll(void); + +/* +** Return the thread stack pointer of the given thread. +** Needed by the garbage collector. +*/ +NSPR_API(void *) PR_GetSP(PRThread *thread); + +/* +** Save the registers that the GC would find interesting into the thread +** "t". isCurrent will be non-zero if the thread state that is being +** saved is the currently executing thread. Return the address of the +** first register to be scanned as well as the number of registers to +** scan in "np". +** +** If "isCurrent" is non-zero then it is allowed for the thread context +** area to be used as scratch storage to hold just the registers +** necessary for scanning. +** +** This function simply calls the internal function _MD_HomeGCRegisters(). +*/ +NSPR_API(PRWord *) PR_GetGCRegisters(PRThread *t, int isCurrent, int *np); + +/* +** (Get|Set)ExecutionEnvironent +** +** Used by Java to associate it's execution environment so garbage collector +** can find it. If return is NULL, then it's probably not a collectable thread. +** +** There's no locking required around these calls. +*/ +NSPR_API(void*) GetExecutionEnvironment(PRThread *thread); +NSPR_API(void) SetExecutionEnvironment(PRThread* thread, void *environment); + +/* +** Enumeration function that applies "func(thread,i,arg)" to each active +** thread in the process. The enumerator returns PR_SUCCESS if the enumeration +** should continue, any other value is considered failure, and enumeration +** stops, returning the failure value from PR_EnumerateThreads. +** Needed by the garbage collector. +*/ +typedef PRStatus (PR_CALLBACK *PREnumerator)(PRThread *t, int i, void *arg); +NSPR_API(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg); + +/* +** Signature of a thread stack scanning function. It is applied to every +** contiguous group of potential pointers within a thread. Count denotes the +** number of pointers. +*/ +typedef PRStatus +(PR_CALLBACK *PRScanStackFun)(PRThread* t, + void** baseAddr, PRUword count, void* closure); + +/* +** Applies scanFun to all contiguous groups of potential pointers +** within a thread. This includes the stack, registers, and thread-local +** data. If scanFun returns a status value other than PR_SUCCESS the scan +** is aborted, and the status value is returned. +*/ +NSPR_API(PRStatus) +PR_ThreadScanStackPointers(PRThread* t, + PRScanStackFun scanFun, void* scanClosure); + +/* +** Calls PR_ThreadScanStackPointers for every thread. +*/ +NSPR_API(PRStatus) +PR_ScanStackPointers(PRScanStackFun scanFun, void* scanClosure); + +/* +** Returns a conservative estimate on the amount of stack space left +** on a thread in bytes, sufficient for making decisions about whether +** to continue recursing or not. +*/ +NSPR_API(PRUword) +PR_GetStackSpaceLeft(PRThread* t); + +/*--------------------------------------------------------------------------- +** THREAD CPU PRIVATE FUNCTIONS +---------------------------------------------------------------------------*/ + +/* +** Get a pointer to the primordial CPU. +*/ +NSPR_API(struct _PRCPU *) _PR_GetPrimordialCPU(void); + +/*--------------------------------------------------------------------------- +** THREAD SYNCHRONIZATION PRIVATE FUNCTIONS +---------------------------------------------------------------------------*/ + +/* +** Create a new named monitor (named for debugging purposes). +** Monitors are re-entrant locks with a built-in condition variable. +** +** This may fail if memory is tight or if some operating system resource +** is low. +*/ +NSPR_API(PRMonitor*) PR_NewNamedMonitor(const char* name); + +/* +** Test and then lock the lock if it's not already locked by some other +** thread. Return PR_FALSE if some other thread owned the lock at the +** time of the call. +*/ +NSPR_API(PRBool) PR_TestAndLock(PRLock *lock); + +/* +** Test and then enter the mutex associated with the monitor if it's not +** already entered by some other thread. Return PR_FALSE if some other +** thread owned the mutex at the time of the call. +*/ +NSPR_API(PRBool) PR_TestAndEnterMonitor(PRMonitor *mon); + +/* +** Return the number of times that the current thread has entered the +** mutex. Returns zero if the current thread has not entered the mutex. +*/ +NSPR_API(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon); + +/* +** Just like PR_CEnterMonitor except that if the monitor is owned by +** another thread NULL is returned. +*/ +NSPR_API(PRMonitor*) PR_CTestAndEnterMonitor(void *address); + +/*--------------------------------------------------------------------------- +** PLATFORM-SPECIFIC INITIALIZATION FUNCTIONS +---------------------------------------------------------------------------*/ +#if defined(IRIX) +/* +** Irix specific initialization funtion to be called before PR_Init +** is called by the application. Sets the CONF_INITUSERS and CONF_INITSIZE +** attributes of the shared arena set up by nspr. +** +** The environment variables _NSPR_IRIX_INITUSERS and _NSPR_IRIX_INITSIZE +** can also be used to set these arena attributes. If _NSPR_IRIX_INITUSERS +** is set, but not _NSPR_IRIX_INITSIZE, the value of the CONF_INITSIZE +** attribute of the nspr arena is scaled as a function of the +** _NSPR_IRIX_INITUSERS value. +** +** If the _PR_Irix_Set_Arena_Params() is called in addition to setting the +** environment variables, the values of the environment variables are used. +** +*/ +NSPR_API(void) _PR_Irix_Set_Arena_Params(PRInt32 initusers, PRInt32 initsize); + +#endif /* IRIX */ + +#if defined(XP_OS2) +/* +** These functions need to be called at the start and end of a thread. +** An EXCEPTIONREGISTRATIONRECORD must be declared on the stack and its +** address passed to the two functions. +*/ +NSPR_API(void) PR_OS2_SetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* e); +NSPR_API(void) PR_OS2_UnsetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* e); +#endif /* XP_OS2 */ + +/* I think PR_GetMonitorEntryCount is useless. All you really want is this... */ +#define PR_InMonitor(m) (PR_GetMonitorEntryCount(m) > 0) + +/*--------------------------------------------------------------------------- +** Special X-Lock hack for client +---------------------------------------------------------------------------*/ + +#ifdef XP_UNIX +extern void PR_XLock(void); +extern void PR_XUnlock(void); +extern PRBool PR_XIsLocked(void); +#endif /* XP_UNIX */ + +PR_END_EXTERN_C + +#endif /* pprthred_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/private/prpriv.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/private/prpriv.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/private/prpriv.h @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prpriv_h___ +#define prpriv_h___ + +/* + * NSPR 2.0 Private API + */ + +#include "private/pprio.h" +#include "private/pprthred.h" + +#endif /* prpriv_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prlink.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prlink.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prlink.h @@ -0,0 +1,230 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prlink_h___ +#define prlink_h___ + +/* +** API to static and dynamic linking. +*/ +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +typedef struct PRLibrary PRLibrary; + +typedef struct PRStaticLinkTable { + const char *name; + void (*fp)(void); +} PRStaticLinkTable; + +/* +** Change the default library path to the given string. The string is +** copied. This call will fail if it runs out of memory. +** +** The string provided as 'path' is copied. The caller can do whatever is +** convenient with the argument when the function is complete. +*/ +NSPR_API(PRStatus) PR_SetLibraryPath(const char *path); + +/* +** Return a character string which contains the path used to search for +** dynamically loadable libraries. +** +** The returned value is basically a copy of a PR_SetLibraryPath(). +** The storage is allocated by the runtime and becomes the responsibilty +** of the caller. +*/ +NSPR_API(char*) PR_GetLibraryPath(void); + +/* +** Given a directory name "dir" and a library name "lib" construct a full +** path name that will refer to the actual dynamically loaded +** library. This does not test for existance of said file, it just +** constructs the full filename. The name constructed is system dependent +** and prepared for PR_LoadLibrary. The result must be free'd when the +** caller is done with it. +** +** The storage for the result is allocated by the runtime and becomes the +** responsibility of the caller. +*/ +NSPR_API(char*) PR_GetLibraryName(const char *dir, const char *lib); + +/* +** +** Free the memory allocated, for the caller, by PR_GetLibraryName +*/ +NSPR_API(void) PR_FreeLibraryName(char *mem); + +/* +** Given a library "name" try to load the library. The argument "name" +** is a machine-dependent name for the library, such as the full pathname +** returned by PR_GetLibraryName. If the library is already loaded, +** this function will avoid loading the library twice. +** +** If the library is loaded successfully, then a pointer to the PRLibrary +** structure representing the library is returned. Otherwise, NULL is +** returned. +** +** This increments the reference count of the library. +*/ +NSPR_API(PRLibrary*) PR_LoadLibrary(const char *name); + +/* +** Each operating system has its preferred way of specifying +** a file in the file system. Most operating systems use +** a pathname. Mac OS Classic, on the other hand, uses the FSSpec +** structure to specify a file. PRLibSpec allows NSPR clients +** to use the type of file specification that is most efficient +** for a particular platform. +** +** On some operating systems such as Mac OS Classic, a shared library +** may contain code fragments that can be individually loaded. +** PRLibSpec also allows NSPR clients to identify a code fragment +** in a library, if code fragments are supported by the OS. +** A code fragment can be specified by name or by an integer index. +** +** Right now PRLibSpec supports four types of library specification: +** a pathname in the native character encoding, a Mac code fragment +** by name, a Mac code fragment by index, and a UTF-16 pathname. +*/ + +typedef enum PRLibSpecType { + PR_LibSpec_Pathname, + PR_LibSpec_MacNamedFragment, /* obsolete (for Mac OS Classic) */ + PR_LibSpec_MacIndexedFragment, /* obsolete (for Mac OS Classic) */ + PR_LibSpec_PathnameU /* supported only on Win32 */ +} PRLibSpecType; + +struct FSSpec; /* Mac OS Classic FSSpec */ + +typedef struct PRLibSpec { + PRLibSpecType type; + union { + /* if type is PR_LibSpec_Pathname */ + const char *pathname; + + /* if type is PR_LibSpec_MacNamedFragment */ + struct { + const struct FSSpec *fsspec; + const char *name; + } mac_named_fragment; /* obsolete (for Mac OS Classic) */ + + /* if type is PR_LibSpec_MacIndexedFragment */ + struct { + const struct FSSpec *fsspec; + PRUint32 index; + } mac_indexed_fragment; /* obsolete (for Mac OS Classic) */ + + /* if type is PR_LibSpec_PathnameU */ + const PRUnichar *pathname_u; /* supported only on Win32 */ + } value; +} PRLibSpec; + +/* +** The following bit flags may be or'd together and passed +** as the 'flags' argument to PR_LoadLibraryWithFlags. +** Flags not supported by the underlying OS are ignored. +*/ + +#define PR_LD_LAZY 0x1 /* equivalent to RTLD_LAZY on Unix */ +#define PR_LD_NOW 0x2 /* equivalent to RTLD_NOW on Unix */ +#define PR_LD_GLOBAL 0x4 /* equivalent to RTLD_GLOBAL on Unix */ +#define PR_LD_LOCAL 0x8 /* equivalent to RTLD_LOCAL on Unix */ +/* The following is equivalent to LOAD_WITH_ALTERED_SEARCH_PATH on Windows */ +#define PR_LD_ALT_SEARCH_PATH 0x10 +/* 0x8000 reserved for NSPR internal use */ + +/* +** Load the specified library, in the manner specified by 'flags'. +*/ + +NSPR_API(PRLibrary *) +PR_LoadLibraryWithFlags( + PRLibSpec libSpec, /* the shared library */ + PRIntn flags /* flags that affect the loading */ +); + +/* +** Unload a previously loaded library. If the library was a static +** library then the static link table will no longer be referenced. The +** associated PRLibrary object is freed. +** +** PR_FAILURE is returned if the library cannot be unloaded. +** +** This function decrements the reference count of the library. +*/ +NSPR_API(PRStatus) PR_UnloadLibrary(PRLibrary *lib); + +/* +** Given the name of a procedure, return the address of the function that +** implements the procedure, or NULL if no such function can be +** found. This does not find symbols in the main program (the ".exe"); +** use PR_LoadStaticLibrary to register symbols in the main program. +** +** This function does not modify the reference count of the library. +*/ +NSPR_API(void*) PR_FindSymbol(PRLibrary *lib, const char *name); + +/* +** Similar to PR_FindSymbol, except that the return value is a pointer to +** a function, and not a pointer to void. Casting between a data pointer +** and a function pointer is not portable according to the C standard. +** Any function pointer can be cast to any other function pointer. +** +** This function does not modify the reference count of the library. +*/ +typedef void (*PRFuncPtr)(void); +NSPR_API(PRFuncPtr) PR_FindFunctionSymbol(PRLibrary *lib, const char *name); + +/* +** Finds a symbol in one of the currently loaded libraries. Given the +** name of a procedure, return the address of the function that +** implements the procedure, and return the library that contains that +** symbol, or NULL if no such function can be found. This does not find +** symbols in the main program (the ".exe"); use PR_AddStaticLibrary to +** register symbols in the main program. +** +** This increments the reference count of the library. +*/ +NSPR_API(void*) PR_FindSymbolAndLibrary(const char *name, + PRLibrary* *lib); + +/* +** Similar to PR_FindSymbolAndLibrary, except that the return value is +** a pointer to a function, and not a pointer to void. Casting between a +** data pointer and a function pointer is not portable according to the C +** standard. Any function pointer can be cast to any other function pointer. +** +** This increments the reference count of the library. +*/ +NSPR_API(PRFuncPtr) PR_FindFunctionSymbolAndLibrary(const char *name, + PRLibrary* *lib); + +/* +** Register a static link table with the runtime under the name +** "name". The symbols present in the static link table will be made +** available to PR_FindSymbol. If "name" is null then the symbols will be +** made available to the library which represents the executable. The +** tables are not copied. +** +** Returns the library object if successful, null otherwise. +** +** This increments the reference count of the library. +*/ +NSPR_API(PRLibrary*) PR_LoadStaticLibrary( + const char *name, const PRStaticLinkTable *table); + +/* +** Return the pathname of the file that the library "name" was loaded +** from. "addr" is the address of a function defined in the library. +** +** The caller is responsible for freeing the result with PR_Free. +*/ +NSPR_API(char *) PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr); + +PR_END_EXTERN_C + +#endif /* prlink_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prlock.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prlock.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prlock.h @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: prlock.h +** Description: API to basic locking functions of NSPR. +** +** +** NSPR provides basic locking mechanisms for thread synchronization. Locks +** are lightweight resource contention controls that prevent multiple threads +** from accessing something (code/data) simultaneously. +**/ + +#ifndef prlock_h___ +#define prlock_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +/* + * PRLock -- + * + * NSPR represents the lock as an opaque entity to the client of the + * API. All routines operate on a pointer to this opaque entity. + */ + +typedef struct PRLock PRLock; + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/*********************************************************************** +** FUNCTION: PR_NewLock +** DESCRIPTION: +** Returns a pointer to a newly created opaque lock object. +** INPUTS: void +** OUTPUTS: void +** RETURN: PRLock* +** If the lock can not be created because of resource constraints, NULL +** is returned. +** +***********************************************************************/ +NSPR_API(PRLock*) PR_NewLock(void); + +/*********************************************************************** +** FUNCTION: PR_DestroyLock +** DESCRIPTION: +** Destroys a given opaque lock object. +** INPUTS: PRLock *lock +** Lock to be freed. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_DestroyLock(PRLock *lock); + +/*********************************************************************** +** FUNCTION: PR_Lock +** DESCRIPTION: +** Lock a lock. +** INPUTS: PRLock *lock +** Lock to locked. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_Lock(PRLock *lock); + +/*********************************************************************** +** FUNCTION: PR_Unlock +** DESCRIPTION: +** Unlock a lock. Unlocking an unlocked lock has undefined results. +** INPUTS: PRLock *lock +** Lock to unlocked. +** OUTPUTS: void +** RETURN: PR_STATUS +** Returns PR_FAILURE if the caller does not own the lock. +***********************************************************************/ +NSPR_API(PRStatus) PR_Unlock(PRLock *lock); + +/*********************************************************************** +** MACRO: PR_ASSERT_CURRENT_THREAD_OWNS_LOCK +** DESCRIPTION: +** If the current thread owns |lock|, this assertion is guaranteed to +** succeed. Otherwise, the behavior of this function is undefined. +** INPUTS: PRLock *lock +** Lock to assert ownership of. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +#if defined(DEBUG) || defined(FORCE_PR_ASSERT) +#define PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(/* PrLock* */ lock) \ + PR_AssertCurrentThreadOwnsLock(lock) +#else +#define PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(/* PrLock* */ lock) +#endif + +/* Don't call this function directly. */ +NSPR_API(void) PR_AssertCurrentThreadOwnsLock(PRLock *lock); + +PR_END_EXTERN_C + +#endif /* prlock_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prlog.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prlog.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prlog.h @@ -0,0 +1,222 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prlog_h___ +#define prlog_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** prlog.h -- Declare interfaces to NSPR's Logging service +** +** NSPR provides a logging service that is used by NSPR itself and is +** available to client programs. +** +** To use the service from a client program, you should create a +** PRLogModuleInfo structure by calling PR_NewLogModule(). After +** creating the LogModule, you can write to the log using the PR_LOG() +** macro. +** +** Initialization of the log service is handled by NSPR initialization. +** +** At execution time, you must enable the log service. To enable the +** log service, set the environment variable: NSPR_LOG_MODULES +** variable. +** +** NSPR_LOG_MODULES variable has the form: +** +** :[, :]* +** +** Where: +** is the name passed to PR_NewLogModule(). +** is a numeric constant, e.g. 5. This value is the maximum +** value of a log event, enumerated by PRLogModuleLevel, that you want +** written to the log. +** +** For example: to record all events of greater value than or equal to +** PR_LOG_ERROR for a LogModule names "gizmo", say: +** +** set NSPR_LOG_MODULES=gizmo:2 +** +** Note that you must specify the numeric value of PR_LOG_ERROR. +** +** Special LogModule names are provided for controlling NSPR's log +** service at execution time. These controls should be set in the +** NSPR_LOG_MODULES environment variable at execution time to affect +** NSPR's log service for your application. +** +** The special LogModule "all" enables all LogModules. To enable all +** LogModule calls to PR_LOG(), say: +** +** set NSPR_LOG_MODULES=all:5 +** +** The special LogModule name "sync" tells the NSPR log service to do +** unbuffered logging. +** +** The special LogModule name "bufsize:" tells NSPR to set the +** log buffer to . +** +** The environment variable NSPR_LOG_FILE specifies the log file to use +** unless the default of "stderr" is acceptable. For MS Windows +** systems, NSPR_LOG_FILE can be set to a special value: "WinDebug" +** (case sensitive). This value causes PR_LOG() output to be written +** using the Windows API OutputDebugString(). OutputDebugString() +** writes to the debugger window; some people find this helpful. +** +** +** To put log messages in your programs, use the PR_LOG macro: +** +** PR_LOG(, , (, *)); +** +** Where is the address of a PRLogModuleInfo structure, and +** is one of the levels defined by the enumeration: +** PRLogModuleLevel. is a printf() style of argument list. That +** is: (fmtstring, ...). +** +** Example: +** +** main() { +** PRIntn one = 1; +** PRLogModuleInfo * myLm = PR_NewLogModule("gizmo"); +** PR_LOG( myLm, PR_LOG_ALWAYS, ("Log this! %d\n", one)); +** return; +** } +** +** Note the use of printf() style arguments as the third agrument(s) to +** PR_LOG(). +** +** After compiling and linking you application, set the environment: +** +** set NSPR_LOG_MODULES=gizmo:5 +** set NSPR_LOG_FILE=logfile.txt +** +** When you execute your application, the string "Log this! 1" will be +** written to the file "logfile.txt". +** +** Note to NSPR engineers: a number of PRLogModuleInfo structures are +** defined and initialized in prinit.c. See this module for ideas on +** what to log where. +** +*/ + +typedef enum PRLogModuleLevel { + PR_LOG_NONE = 0, /* nothing */ + PR_LOG_ALWAYS = 1, /* always printed */ + PR_LOG_ERROR = 2, /* error messages */ + PR_LOG_WARNING = 3, /* warning messages */ + PR_LOG_DEBUG = 4, /* debug messages */ + + PR_LOG_NOTICE = PR_LOG_DEBUG, /* notice messages */ + PR_LOG_WARN = PR_LOG_WARNING, /* warning messages */ + PR_LOG_MIN = PR_LOG_DEBUG, /* minimal debugging messages */ + PR_LOG_MAX = PR_LOG_DEBUG /* maximal debugging messages */ +} PRLogModuleLevel; + +/* +** One of these structures is created for each module that uses logging. +** "name" is the name of the module +** "level" is the debugging level selected for that module +*/ +typedef struct PRLogModuleInfo { + const char *name; + PRLogModuleLevel level; + struct PRLogModuleInfo *next; +} PRLogModuleInfo; + +/* +** Create a new log module. +*/ +NSPR_API(PRLogModuleInfo*) PR_NewLogModule(const char *name); + +/* +** Set the file to use for logging. Returns PR_FALSE if the file cannot +** be created +*/ +NSPR_API(PRBool) PR_SetLogFile(const char *name); + +/* +** Set the size of the logging buffer. If "buffer_size" is zero then the +** logging becomes "synchronous" (or unbuffered). +*/ +NSPR_API(void) PR_SetLogBuffering(PRIntn buffer_size); + +/* +** Print a string to the log. "fmt" is a PR_snprintf format type. All +** messages printed to the log are preceeded by the name of the thread +** and a time stamp. Also, the routine provides a missing newline if one +** is not provided. +*/ +NSPR_API(void) PR_LogPrint(const char *fmt, ...); + +/* +** Flush the log to its file. +*/ +NSPR_API(void) PR_LogFlush(void); + +NSPR_API(void) PR_Assert(const char *s, const char *file, PRIntn ln) + PR_PRETEND_NORETURN; + +#if defined(DEBUG) || defined(FORCE_PR_LOG) +#define PR_LOGGING 1 + +#define PR_LOG_TEST(_module,_level) \ + ((_module)->level >= (_level)) + +/* +** Log something. +** "module" is the address of a PRLogModuleInfo structure +** "level" is the desired logging level +** "args" is a variable length list of arguments to print, in the following +** format: ("printf style format string", ...) +*/ +#define PR_LOG(_module,_level,_args) \ + PR_BEGIN_MACRO \ + if (PR_LOG_TEST(_module,_level)) { \ + PR_LogPrint _args; \ + } \ + PR_END_MACRO + +#else /* defined(DEBUG) || defined(FORCE_PR_LOG) */ + +#undef PR_LOGGING +#define PR_LOG_TEST(module,level) 0 +#define PR_LOG(module,level,args) + +#endif /* defined(DEBUG) || defined(FORCE_PR_LOG) */ + +#ifndef NO_NSPR_10_SUPPORT + +#ifdef PR_LOGGING +#define PR_LOG_BEGIN PR_LOG +#define PR_LOG_END PR_LOG +#define PR_LOG_DEFINE PR_NewLogModule +#else +#define PR_LOG_BEGIN(module,level,args) +#define PR_LOG_END(module,level,args) +#define PR_LOG_DEFINE(_name) NULL +#endif /* PR_LOGGING */ + +#endif /* NO_NSPR_10_SUPPORT */ + +#if defined(DEBUG) || defined(FORCE_PR_ASSERT) + +#define PR_ASSERT(_expr) \ + ((_expr)?((void)0):PR_Assert(# _expr,__FILE__,__LINE__)) + +#define PR_NOT_REACHED(_reasonStr) \ + PR_Assert(_reasonStr,__FILE__,__LINE__) + +#else + +#define PR_ASSERT(expr) ((void) 0) +#define PR_NOT_REACHED(reasonStr) + +#endif /* defined(DEBUG) || defined(FORCE_PR_ASSERT) */ + +PR_END_EXTERN_C + +#endif /* prlog_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prlong.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prlong.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prlong.h @@ -0,0 +1,403 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: prlong.h +** Description: Portable access to 64 bit numerics +** +** Long-long (64-bit signed integer type) support. Some C compilers +** don't support 64 bit integers yet, so we use these macros to +** support both machines that do and don't. +**/ +#ifndef prlong_h___ +#define prlong_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/*********************************************************************** +** DEFINES: LL_MaxInt +** LL_MinInt +** LL_Zero +** LL_MaxUint +** DESCRIPTION: +** Various interesting constants and static variable +** initializer +***********************************************************************/ +NSPR_API(PRInt64) LL_MaxInt(void); +NSPR_API(PRInt64) LL_MinInt(void); +NSPR_API(PRInt64) LL_Zero(void); +NSPR_API(PRUint64) LL_MaxUint(void); + +#if defined(HAVE_LONG_LONG) + +/* Keep this in sync with prtypes.h. */ +#if PR_BYTES_PER_LONG == 8 && !defined(PR_ALTERNATE_INT64_TYPEDEF) +#define LL_MAXINT 9223372036854775807L +#define LL_MININT (-LL_MAXINT - 1L) +#define LL_ZERO 0L +#define LL_MAXUINT 18446744073709551615UL +#define LL_INIT(hi, lo) ((hi ## L << 32) + lo ## L) +#elif defined(WIN32) && !defined(__GNUC__) +#define LL_MAXINT 9223372036854775807i64 +#define LL_MININT (-LL_MAXINT - 1i64) +#define LL_ZERO 0i64 +#define LL_MAXUINT 18446744073709551615ui64 +#define LL_INIT(hi, lo) ((hi ## i64 << 32) + lo ## i64) +#else +#define LL_MAXINT 9223372036854775807LL +#define LL_MININT (-LL_MAXINT - 1LL) +#define LL_ZERO 0LL +#define LL_MAXUINT 18446744073709551615ULL +#define LL_INIT(hi, lo) ((hi ## LL << 32) + lo ## LL) +#endif + +/*********************************************************************** +** MACROS: LL_* +** DESCRIPTION: +** The following macros define portable access to the 64 bit +** math facilities. +** +***********************************************************************/ + +/*********************************************************************** +** MACROS: LL_ +** +** LL_IS_ZERO Test for zero +** LL_EQ Test for equality +** LL_NE Test for inequality +** LL_GE_ZERO Test for zero or positive +** LL_CMP Compare two values +***********************************************************************/ +#define LL_IS_ZERO(a) ((a) == 0) +#define LL_EQ(a, b) ((a) == (b)) +#define LL_NE(a, b) ((a) != (b)) +#define LL_GE_ZERO(a) ((a) >= 0) +#define LL_CMP(a, op, b) ((PRInt64)(a) op (PRInt64)(b)) +#define LL_UCMP(a, op, b) ((PRUint64)(a) op (PRUint64)(b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_AND Logical and +** LL_OR Logical or +** LL_XOR Logical exclusion +** LL_OR2 A disgusting deviation +** LL_NOT Negation (one's complement) +***********************************************************************/ +#define LL_AND(r, a, b) ((r) = (a) & (b)) +#define LL_OR(r, a, b) ((r) = (a) | (b)) +#define LL_XOR(r, a, b) ((r) = (a) ^ (b)) +#define LL_OR2(r, a) ((r) = (r) | (a)) +#define LL_NOT(r, a) ((r) = ~(a)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_NEG Negation (two's complement) +** LL_ADD Summation (two's complement) +** LL_SUB Difference (two's complement) +***********************************************************************/ +#define LL_NEG(r, a) ((r) = -(a)) +#define LL_ADD(r, a, b) ((r) = (a) + (b)) +#define LL_SUB(r, a, b) ((r) = (a) - (b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_MUL Product (two's complement) +** LL_DIV Quotient (two's complement) +** LL_MOD Modulus (two's complement) +***********************************************************************/ +#define LL_MUL(r, a, b) ((r) = (a) * (b)) +#define LL_DIV(r, a, b) ((r) = (a) / (b)) +#define LL_MOD(r, a, b) ((r) = (a) % (b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_SHL Shift left [0..64] bits +** LL_SHR Shift right [0..64] bits with sign extension +** LL_USHR Unsigned shift right [0..64] bits +** LL_ISHL Signed shift left [0..64] bits +***********************************************************************/ +#define LL_SHL(r, a, b) ((r) = (PRInt64)(a) << (b)) +#define LL_SHR(r, a, b) ((r) = (PRInt64)(a) >> (b)) +#define LL_USHR(r, a, b) ((r) = (PRUint64)(a) >> (b)) +#define LL_ISHL(r, a, b) ((r) = (PRInt64)(a) << (b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_L2I Convert to signed 32 bit +** LL_L2UI Convert to unsigned 32 bit +** LL_L2F Convert to floating point +** LL_L2D Convert to floating point +** LL_I2L Convert signed to 64 bit +** LL_UI2L Convert unsigned to 64 bit +** LL_F2L Convert float to 64 bit +** LL_D2L Convert float to 64 bit +***********************************************************************/ +#define LL_L2I(i, l) ((i) = (PRInt32)(l)) +#define LL_L2UI(ui, l) ((ui) = (PRUint32)(l)) +#define LL_L2F(f, l) ((f) = (PRFloat64)(l)) +#define LL_L2D(d, l) ((d) = (PRFloat64)(l)) + +#define LL_I2L(l, i) ((l) = (PRInt64)(i)) +#define LL_UI2L(l, ui) ((l) = (PRInt64)(ui)) +#define LL_F2L(l, f) ((l) = (PRInt64)(f)) +#define LL_D2L(l, d) ((l) = (PRInt64)(d)) + +/*********************************************************************** +** MACROS: LL_UDIVMOD +** DESCRIPTION: +** Produce both a quotient and a remainder given an unsigned +** INPUTS: PRUint64 a: The dividend of the operation +** PRUint64 b: The quotient of the operation +** OUTPUTS: PRUint64 *qp: pointer to quotient +** PRUint64 *rp: pointer to remainder +***********************************************************************/ +#define LL_UDIVMOD(qp, rp, a, b) \ + (*(qp) = ((PRUint64)(a) / (b)), \ + *(rp) = ((PRUint64)(a) % (b))) + +#else /* !HAVE_LONG_LONG */ + +#define LL_MAXINT LL_MaxInt() +#define LL_MININT LL_MinInt() +#define LL_ZERO LL_Zero() +#define LL_MAXUINT LL_MaxUint() + +#ifdef IS_LITTLE_ENDIAN +#define LL_INIT(hi, lo) {PR_UINT32(lo), PR_UINT32(hi)} +#else +#define LL_INIT(hi, lo) {PR_UINT32(hi), PR_UINT32(lo)} +#endif + +#define LL_IS_ZERO(a) (((a).hi == 0) && ((a).lo == 0)) +#define LL_EQ(a, b) (((a).hi == (b).hi) && ((a).lo == (b).lo)) +#define LL_NE(a, b) (((a).hi != (b).hi) || ((a).lo != (b).lo)) +#define LL_GE_ZERO(a) (((a).hi >> 31) == 0) + +#define LL_CMP(a, op, b) (((a).hi == (b).hi) ? ((a).lo op (b).lo) : \ + ((PRInt32)(a).hi op (PRInt32)(b).hi)) +#define LL_UCMP(a, op, b) (((a).hi == (b).hi) ? ((a).lo op (b).lo) : \ + ((a).hi op (b).hi)) + +#define LL_AND(r, a, b) ((r).lo = (a).lo & (b).lo, \ + (r).hi = (a).hi & (b).hi) +#define LL_OR(r, a, b) ((r).lo = (a).lo | (b).lo, \ + (r).hi = (a).hi | (b).hi) +#define LL_XOR(r, a, b) ((r).lo = (a).lo ^ (b).lo, \ + (r).hi = (a).hi ^ (b).hi) +#define LL_OR2(r, a) ((r).lo = (r).lo | (a).lo, \ + (r).hi = (r).hi | (a).hi) +#define LL_NOT(r, a) ((r).lo = ~(a).lo, \ + (r).hi = ~(a).hi) + +#define LL_NEG(r, a) ((r).lo = -(PRInt32)(a).lo, \ + (r).hi = -(PRInt32)(a).hi - ((r).lo != 0)) +#define LL_ADD(r, a, b) { \ + PRInt64 _a, _b; \ + _a = a; _b = b; \ + (r).lo = _a.lo + _b.lo; \ + (r).hi = _a.hi + _b.hi + ((r).lo < _b.lo); \ +} + +#define LL_SUB(r, a, b) { \ + PRInt64 _a, _b; \ + _a = a; _b = b; \ + (r).lo = _a.lo - _b.lo; \ + (r).hi = _a.hi - _b.hi - (_a.lo < _b.lo); \ +} + +#define LL_MUL(r, a, b) { \ + PRInt64 _a, _b; \ + _a = a; _b = b; \ + LL_MUL32(r, _a.lo, _b.lo); \ + (r).hi += _a.hi * _b.lo + _a.lo * _b.hi; \ +} + +#define _lo16(a) ((a) & PR_BITMASK(16)) +#define _hi16(a) ((a) >> 16) + +#define LL_MUL32(r, a, b) { \ + PRUint32 _a1, _a0, _b1, _b0, _y0, _y1, _y2, _y3; \ + _a1 = _hi16(a), _a0 = _lo16(a); \ + _b1 = _hi16(b), _b0 = _lo16(b); \ + _y0 = _a0 * _b0; \ + _y1 = _a0 * _b1; \ + _y2 = _a1 * _b0; \ + _y3 = _a1 * _b1; \ + _y1 += _hi16(_y0); /* can't carry */ \ + _y1 += _y2; /* might carry */ \ + if (_y1 < _y2) \ + _y3 += (PRUint32)(PR_BIT(16)); /* propagate */ \ + (r).lo = (_lo16(_y1) << 16) + _lo16(_y0); \ + (r).hi = _y3 + _hi16(_y1); \ +} + +#define LL_UDIVMOD(qp, rp, a, b) ll_udivmod(qp, rp, a, b) + +NSPR_API(void) ll_udivmod(PRUint64 *qp, PRUint64 *rp, PRUint64 a, PRUint64 b); + +#define LL_DIV(r, a, b) { \ + PRInt64 _a, _b; \ + PRUint32 _negative = (PRInt32)(a).hi < 0; \ + if (_negative) { \ + LL_NEG(_a, a); \ + } else { \ + _a = a; \ + } \ + if ((PRInt32)(b).hi < 0) { \ + _negative ^= 1; \ + LL_NEG(_b, b); \ + } else { \ + _b = b; \ + } \ + LL_UDIVMOD(&(r), 0, _a, _b); \ + if (_negative) \ + LL_NEG(r, r); \ +} + +#define LL_MOD(r, a, b) { \ + PRInt64 _a, _b; \ + PRUint32 _negative = (PRInt32)(a).hi < 0; \ + if (_negative) { \ + LL_NEG(_a, a); \ + } else { \ + _a = a; \ + } \ + if ((PRInt32)(b).hi < 0) { \ + LL_NEG(_b, b); \ + } else { \ + _b = b; \ + } \ + LL_UDIVMOD(0, &(r), _a, _b); \ + if (_negative) \ + LL_NEG(r, r); \ +} + +#define LL_SHL(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = _a.lo << ((b) & 31); \ + (r).hi = (_a.hi << ((b) & 31)) | (_a.lo >> (32 - (b))); \ + } else { \ + (r).lo = 0; \ + (r).hi = _a.lo << ((b) & 31); \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +/* a is an PRInt32, b is PRInt32, r is PRInt64 */ +#define LL_ISHL(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a.lo = (a); \ + _a.hi = 0; \ + if ((b) < 32) { \ + (r).lo = (a) << ((b) & 31); \ + (r).hi = ((a) >> (32 - (b))); \ + } else { \ + (r).lo = 0; \ + (r).hi = (a) << ((b) & 31); \ + } \ + } else { \ + (r).lo = (a); \ + (r).hi = 0; \ + } \ +} + +#define LL_SHR(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> ((b) & 31)); \ + (r).hi = (PRInt32)_a.hi >> ((b) & 31); \ + } else { \ + (r).lo = (PRInt32)_a.hi >> ((b) & 31); \ + (r).hi = (PRInt32)_a.hi >> 31; \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +#define LL_USHR(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> ((b) & 31)); \ + (r).hi = _a.hi >> ((b) & 31); \ + } else { \ + (r).lo = _a.hi >> ((b) & 31); \ + (r).hi = 0; \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +#define LL_L2I(i, l) ((i) = (l).lo) +#define LL_L2UI(ui, l) ((ui) = (l).lo) +#define LL_L2F(f, l) { double _d; LL_L2D(_d, l); (f) = (PRFloat64)_d; } + +#define LL_L2D(d, l) { \ + int _negative; \ + PRInt64 _absval; \ + \ + _negative = (l).hi >> 31; \ + if (_negative) { \ + LL_NEG(_absval, l); \ + } else { \ + _absval = l; \ + } \ + (d) = (double)_absval.hi * 4.294967296e9 + _absval.lo; \ + if (_negative) \ + (d) = -(d); \ +} + +#define LL_I2L(l, i) { PRInt32 _i = ((PRInt32)(i)) >> 31; (l).lo = (i); (l).hi = _i; } +#define LL_UI2L(l, ui) ((l).lo = (ui), (l).hi = 0) +#define LL_F2L(l, f) { double _d = (double)f; LL_D2L(l, _d); } + +#define LL_D2L(l, d) { \ + int _negative; \ + double _absval, _d_hi; \ + PRInt64 _lo_d; \ + \ + _negative = ((d) < 0); \ + _absval = _negative ? -(d) : (d); \ + \ + (l).hi = _absval / 4.294967296e9; \ + (l).lo = 0; \ + LL_L2D(_d_hi, l); \ + _absval -= _d_hi; \ + _lo_d.hi = 0; \ + if (_absval < 0) { \ + _lo_d.lo = -_absval; \ + LL_SUB(l, l, _lo_d); \ + } else { \ + _lo_d.lo = _absval; \ + LL_ADD(l, l, _lo_d); \ + } \ + \ + if (_negative) \ + LL_NEG(l, l); \ +} + +#endif /* !HAVE_LONG_LONG */ + +PR_END_EXTERN_C + +#endif /* prlong_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prmem.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prmem.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prmem.h @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: prmem.h +** Description: API to NSPR memory management functions +** +*/ +#ifndef prmem_h___ +#define prmem_h___ + +#include "prtypes.h" +#include + +PR_BEGIN_EXTERN_C + +/* +** Thread safe memory allocation. +** +** NOTE: pr wraps up malloc, free, calloc, realloc so they are already +** thread safe (and are not declared here - look in stdlib.h). +*/ + +/* +** PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free have the same signatures +** as their libc equivalent malloc, calloc, realloc, and free, and have +** the same semantics. (Note that the argument type size_t is replaced +** by PRUint32.) Memory allocated by PR_Malloc, PR_Calloc, or PR_Realloc +** must be freed by PR_Free. +*/ + +NSPR_API(void *) PR_Malloc(PRUint32 size); + +NSPR_API(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize); + +NSPR_API(void *) PR_Realloc(void *ptr, PRUint32 size); + +NSPR_API(void) PR_Free(void *ptr); + +/* +** The following are some convenience macros defined in terms of +** PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free. +*/ + +/*********************************************************************** +** FUNCTION: PR_MALLOC() +** DESCRIPTION: +** PR_NEW() allocates an untyped item of size _size from the heap. +** INPUTS: _size: size in bytes of item to be allocated +** OUTPUTS: untyped pointer to the node allocated +** RETURN: pointer to node or error returned from malloc(). +***********************************************************************/ +#define PR_MALLOC(_bytes) (PR_Malloc((_bytes))) + +/*********************************************************************** +** FUNCTION: PR_NEW() +** DESCRIPTION: +** PR_NEW() allocates an item of type _struct from the heap. +** INPUTS: _struct: a data type +** OUTPUTS: pointer to _struct +** RETURN: pointer to _struct or error returns from malloc(). +***********************************************************************/ +#define PR_NEW(_struct) ((_struct *) PR_MALLOC(sizeof(_struct))) + +/*********************************************************************** +** FUNCTION: PR_REALLOC() +** DESCRIPTION: +** PR_REALLOC() re-allocates _ptr bytes from the heap as a _size +** untyped item. +** INPUTS: _ptr: pointer to node to reallocate +** _size: size of node to allocate +** OUTPUTS: pointer to node allocated +** RETURN: pointer to node allocated +***********************************************************************/ +#define PR_REALLOC(_ptr, _size) (PR_Realloc((_ptr), (_size))) + +/*********************************************************************** +** FUNCTION: PR_CALLOC() +** DESCRIPTION: +** PR_CALLOC() allocates a _size bytes untyped item from the heap +** and sets the allocated memory to all 0x00. +** INPUTS: _size: size of node to allocate +** OUTPUTS: pointer to node allocated +** RETURN: pointer to node allocated +***********************************************************************/ +#define PR_CALLOC(_size) (PR_Calloc(1, (_size))) + +/*********************************************************************** +** FUNCTION: PR_NEWZAP() +** DESCRIPTION: +** PR_NEWZAP() allocates an item of type _struct from the heap +** and sets the allocated memory to all 0x00. +** INPUTS: _struct: a data type +** OUTPUTS: pointer to _struct +** RETURN: pointer to _struct +***********************************************************************/ +#define PR_NEWZAP(_struct) ((_struct*)PR_Calloc(1, sizeof(_struct))) + +/*********************************************************************** +** FUNCTION: PR_DELETE() +** DESCRIPTION: +** PR_DELETE() unallocates an object previosly allocated via PR_NEW() +** or PR_NEWZAP() to the heap. +** INPUTS: pointer to previously allocated object +** OUTPUTS: the referenced object is returned to the heap +** RETURN: void +***********************************************************************/ +#define PR_DELETE(_ptr) { PR_Free(_ptr); (_ptr) = NULL; } + +/*********************************************************************** +** FUNCTION: PR_FREEIF() +** DESCRIPTION: +** PR_FREEIF() conditionally unallocates an object previously allocated +** vial PR_NEW() or PR_NEWZAP(). If the pointer to the object is +** equal to zero (0), the object is not released. +** INPUTS: pointer to previously allocated object +** OUTPUTS: the referenced object is conditionally returned to the heap +** RETURN: void +***********************************************************************/ +#define PR_FREEIF(_ptr) if (_ptr) PR_DELETE(_ptr) + +PR_END_EXTERN_C + +#endif /* prmem_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prmon.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prmon.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prmon.h @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prmon_h___ +#define prmon_h___ + +#include "prtypes.h" +#include "prinrval.h" + +PR_BEGIN_EXTERN_C + +typedef struct PRMonitor PRMonitor; + +/* +** Create a new monitor. Monitors are re-entrant locks with a single built-in +** condition variable. +** +** This may fail if memory is tight or if some operating system resource +** is low. +*/ +NSPR_API(PRMonitor*) PR_NewMonitor(void); + +/* +** Destroy a monitor. The caller is responsible for guaranteeing that the +** monitor is no longer in use. There must be no thread waiting on the monitor's +** condition variable and that the lock is not held. +** +*/ +NSPR_API(void) PR_DestroyMonitor(PRMonitor *mon); + +/* +** Enter the lock associated with the monitor. If the calling thread currently +** is in the monitor, the call to enter will silently succeed. In either case, +** it will increment the entry count by one. +*/ +NSPR_API(void) PR_EnterMonitor(PRMonitor *mon); + +/* +** Decrement the entry count associated with the monitor. If the decremented +** entry count is zero, the monitor is exited. Returns PR_FAILURE if the +** calling thread has not entered the monitor. +*/ +NSPR_API(PRStatus) PR_ExitMonitor(PRMonitor *mon); + +/* +** Wait for a notify on the monitor's condition variable. Sleep for "ticks" +** amount of time (if "ticks" is PR_INTERVAL_NO_TIMEOUT then the sleep is +** indefinite). +** +** While the thread is waiting it exits the monitor (as if it called +** PR_ExitMonitor as many times as it had called PR_EnterMonitor). When +** the wait has finished the thread regains control of the monitors lock +** with the same entry count as before the wait began. +** +** The thread waiting on the monitor will be resumed when the monitor is +** notified (assuming the thread is the next in line to receive the +** notify) or when the "ticks" timeout elapses. +** +** Returns PR_FAILURE if the caller has not entered the monitor. +*/ +NSPR_API(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime ticks); + +/* +** Notify a thread waiting on the monitor's condition variable. If a thread +** is waiting on the condition variable (using PR_Wait) then it is awakened +** and attempts to reenter the monitor. +*/ +NSPR_API(PRStatus) PR_Notify(PRMonitor *mon); + +/* +** Notify all of the threads waiting on the monitor's condition variable. +** All of threads waiting on the condition are scheduled to reenter the +** monitor. +*/ +NSPR_API(PRStatus) PR_NotifyAll(PRMonitor *mon); + +/* +** PR_ASSERT_CURRENT_THREAD_IN_MONITOR +** If the current thread is in |mon|, this assertion is guaranteed to +** succeed. Otherwise, the behavior of this function is undefined. +*/ +#if defined(DEBUG) || defined(FORCE_PR_ASSERT) +#define PR_ASSERT_CURRENT_THREAD_IN_MONITOR(/* PRMonitor* */ mon) \ + PR_AssertCurrentThreadInMonitor(mon) +#else +#define PR_ASSERT_CURRENT_THREAD_IN_MONITOR(/* PRMonitor* */ mon) +#endif + +/* Don't call this function directly. */ +NSPR_API(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon); + +PR_END_EXTERN_C + +#endif /* prmon_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prmwait.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prmwait.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prmwait.h @@ -0,0 +1,380 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#if defined(_PRMWAIT_H) +#else +#define _PRMWAIT_H + +#include "prio.h" +#include "prtypes.h" +#include "prclist.h" + +PR_BEGIN_EXTERN_C + +/********************************************************************************/ +/********************************************************************************/ +/********************************************************************************/ +/****************************** WARNING ****************************/ +/********************************************************************************/ +/**************************** This is work in progress. *************************/ +/************************** Do not make any assumptions *************************/ +/************************** about the stability of this *************************/ +/************************** API or the underlying imple- ************************/ +/************************** mentation. ************************/ +/********************************************************************************/ +/********************************************************************************/ + +/* +** STRUCTURE: PRWaitGroup +** DESCRIPTION: +** The client may define several wait groups in order to semantically +** tie a collection of file descriptors for a single purpose. This allows +** easier dispatching of threads that returned with active file descriptors +** from the wait function. +*/ +typedef struct PRWaitGroup PRWaitGroup; + +/* +** ENUMERATION: PRMWStatus +** DESCRIPTION: +** This enumeration is used to indicate the completion status of +** a receive wait object. Generally stated, a positive value indicates +** that the operation is not yet complete. A zero value indicates +** success (similar to PR_SUCCESS) and any negative value is an +** indication of failure. The reason for the failure can be retrieved +** by calling PR_GetError(). +** +** PR_MW_PENDING The operation is still pending. None of the other +** fields of the object are currently valid. +** PR_MW_SUCCESS The operation is complete and it was successful. +** PR_MW_FAILURE The operation failed. The reason for the failure +** can be retrieved by calling PR_GetError(). +** PR_MW_TIMEOUT The amount of time allowed for by the object's +** 'timeout' field has expired w/o the operation +** otherwise coming to closure. +** PR_MW_INTERRUPT The operation was cancelled, either by the client +** calling PR_CancelWaitFileDesc() or destroying the +** entire wait group (PR_DestroyWaitGroup()). +*/ +typedef enum PRMWStatus +{ + PR_MW_PENDING = 1, + PR_MW_SUCCESS = 0, + PR_MW_FAILURE = -1, + PR_MW_TIMEOUT = -2, + PR_MW_INTERRUPT = -3 +} PRMWStatus; + +/* +** STRUCTURE: PRMemoryDescriptor +** DESCRIPTION: +** THis is a descriptor for an interval of memory. It contains a +** pointer to the first byte of that memory and the length (in +** bytes) of the interval. +*/ +typedef struct PRMemoryDescriptor +{ + void *start; /* pointer to first byte of memory */ + PRSize length; /* length (in bytes) of memory interval */ +} PRMemoryDescriptor; + +/* +** STRUCTURE: PRMWaitClientData +** DESCRIPTION: +** An opague stucture for which a client MAY give provide a concrete +** definition and associate with a receive descriptor. The NSPR runtime +** does not manage this field. It is completely up to the client. +*/ +typedef struct PRMWaitClientData PRMWaitClientData; + +/* +** STRUCTURE: PRRecvWait +** DESCRIPTION: +** A receive wait object contains the file descriptor that is subject +** to the wait and the amount of time (beginning epoch established +** when the object is presented to the runtime) the the channel should +** block before abandoning the process. +** +** The success of the wait operation will be noted in the object's +** 'outcome' field. The fields are not valid when the NSPR runtime +** is in possession of the object. +** +** The memory descriptor describes an interval of writable memory +** in the caller's address space where data from an initial read +** can be placed. The description may indicate a null interval. +*/ +typedef struct PRRecvWait +{ + PRCList internal; /* internal runtime linkages */ + + PRFileDesc *fd; /* file descriptor associated w/ object */ + PRMWStatus outcome; /* outcome of the current/last operation */ + PRIntervalTime timeout; /* time allowed for entire operation */ + + PRInt32 bytesRecv; /* number of bytes transferred into buffer */ + PRMemoryDescriptor buffer; /* where to store first segment of input data */ + PRMWaitClientData *client; /* pointer to arbitrary client defined data */ +} PRRecvWait; + +/* +** STRUCTURE: PRMWaitEnumerator +** DESCRIPTION: +** An enumeration object is used to store the state of an existing +** enumeration over a wait group. The opaque object must be allocated +** by the client and the reference presented on each call to the +** pseudo-stateless enumerator. The enumeration objects are sharable +** only in serial fashion. +*/ +typedef struct PRMWaitEnumerator PRMWaitEnumerator; + + +/* +** FUNCTION: PR_AddWaitFileDesc +** DESCRIPTION: +** This function will effectively add a file descriptor to the +** list of those waiting for network receive. The new descriptor +** will be semantically tied to the wait group specified. +** +** The ownership for the storage pointed to by 'desc' is temporarily +** passed over the the NSPR runtime. It will be handed back by the +** function PR_WaitRecvReady(). +** +** INPUTS +** group A reference to a PRWaitGroup or NULL. Wait groups are +** created by calling PR_CreateWaitGroup() and are used +** to semantically group various file descriptors by the +** client's application. +** desc A reference to a valid PRRecvWait. The object of the +** reference must be preserved and not be modified +** until its ownership is returned to the client. +** RETURN +** PRStatus An indication of success. If equal to PR_FAILUE details +** of the failure are avaiable via PR_GetError(). +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** Invalid 'group' identifier or duplicate 'desc' object. +** PR_OUT_OF_MEMORY_ERROR +** Insuffient memory for internal data structures. +** PR_INVALID_STATE_ERROR +** The group is being destroyed. +*/ +NSPR_API(PRStatus) PR_AddWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc); + +/* +** FUNCTION: PR_WaitRecvReady +** DESCRIPTION: +** PR_WaitRecvReady will block the calling thread until one of the +** file descriptors that have been added via PR_AddWaitFileDesc is +** available for input I/O. +** INPUT +** group A pointer to a valid PRWaitGroup or NULL (the null +** group. The function will block the caller until a +** channel from the wait group becomes ready for receive +** or there is some sort of error. +** RETURN +** PRReciveWait +** When the caller is resumed it is either returned a +** valid pointer to a previously added receive wait or +** a NULL. If the latter, the function has terminated +** for a reason that can be determined by calling +** PR_GetError(). +** If a valid pointer is returned, the reference is to the +** file descriptor contained in the receive wait object. +** The outcome of the wait operation may still fail, and +** if it has, that fact will be noted in the object's +** outcome field. Details can be retrieved from PR_GetError(). +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The 'group' is not known by the runtime. +** PR_PENDING_INTERRUPT_ERROR + The thread was interrupted. +** PR_INVALID_STATE_ERROR +** The group is being destroyed. +*/ +NSPR_API(PRRecvWait*) PR_WaitRecvReady(PRWaitGroup *group); + +/* +** FUNCTION: PR_CancelWaitFileDesc +** DESCRIPTION: +** PR_CancelWaitFileDesc is provided as a means for cancelling operations +** on objects previously submitted by use of PR_AddWaitFileDesc(). If +** the runtime knows of the object, it will be marked as having failed +** because it was interrupted (similar to PR_Interrupt()). The first +** available thread waiting on the group will be made to return the +** PRRecvWait object with the outcome noted. +** +** INPUTS +** group The wait group under which the wait receive object was +** added. +** desc A pointer to the wait receive object that is to be +** cancelled. +** RETURN +** PRStatus If the wait receive object was located and associated +** with the specified wait group, the status returned will +** be PR_SUCCESS. There is still a race condition that would +** permit the offected object to complete normally, but it +** is assured that it will complete in the near future. +** If the receive object or wait group are invalid, the +** function will return with a status of PR_FAILURE. +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The 'group' argument is not recognized as a valid group. +** PR_COLLECTION_EMPTY_ERROR +** There are no more receive wait objects in the group's +** collection. +** PR_INVALID_STATE_ERROR +** The group is being destroyed. +*/ +NSPR_API(PRStatus) PR_CancelWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc); + +/* +** FUNCTION: PR_CancelWaitGroup +** DESCRIPTION: +** PR_CancelWaitGroup is provided as a means for cancelling operations +** on objects previously submitted by use of PR_AddWaitFileDesc(). Each +** successive call will return a pointer to a PRRecvWait object that +** was previously registered via PR_AddWaitFileDesc(). If no wait +** objects are associated with the wait group, a NULL will be returned. +** This function should be called in a loop until a NULL is returned +** to reclaim all the wait objects prior to calling PR_DestroyWaitGroup(). +** +** INPUTS +** group The wait group under which the wait receive object was +** added. +** RETURN +** PRRecvWait* If the wait group is valid and at least one receive wait +** object is present in the group, that object will be +** marked as PR_MW_INTERRUPT'd and removed from the group's +** queues. Otherwise a NULL will be returned and the reason +** for the NULL may be retrieved by calling PR_GetError(). +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** PR_GROUP_EMPTY_ERROR +*/ +NSPR_API(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group); + +/* +** FUNCTION: PR_CreateWaitGroup +** DESCRIPTION: +** A wait group is an opaque object that a client may create in order +** to semantically group various wait requests. Each wait group is +** unique, including the default wait group (NULL). A wait request +** that was added under a wait group will only be serviced by a caller +** that specified the same wait group. +** +** INPUT +** size The size of the hash table to be used to contain the +** receive wait objects. This is just the initial size. +** It will grow as it needs to, but to avoid that hassle +** one can suggest a suitable size initially. It should +** be ~30% larger than the maximum number of receive wait +** objects expected. +** RETURN +** PRWaitGroup If successful, the function will return a pointer to an +** object that was allocated by and owned by the runtime. +** The reference remains valid until it is explicitly destroyed +** by calling PR_DestroyWaitGroup(). +** +** ERRORS +** PR_OUT_OF_MEMORY_ERROR +*/ +NSPR_API(PRWaitGroup*) PR_CreateWaitGroup(PRInt32 size); + +/* +** FUNCTION: PR_DestroyWaitGroup +** DESCRIPTION: +** Undo the effects of PR_CreateWaitGroup(). Any receive wait operations +** on the group will be treated as if the each had been the target of a +** PR_CancelWaitFileDesc(). +** +** INPUT +** group Reference to a wait group previously allocated using +** PR_CreateWaitGroup(). +** RETURN +** PRStatus Will be PR_SUCCESS if the wait group was valid and there +** are no receive wait objects in that group. Otherwise +** will indicate PR_FAILURE. +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The 'group' argument does not reference a known object. +** PR_INVALID_STATE_ERROR +** The group still contains receive wait objects. +*/ +NSPR_API(PRStatus) PR_DestroyWaitGroup(PRWaitGroup *group); + +/* +** FUNCTION: PR_CreateMWaitEnumerator +** DESCRIPTION: +** The PR_CreateMWaitEnumerator() function returns a reference to an +** opaque PRMWaitEnumerator object. The enumerator object is required +** as an argument for each successive call in the stateless enumeration +** of the indicated wait group. +** +** group The wait group that the enumeration is intended to +** process. It may be be the default wait group (NULL). +** RETURN +** PRMWaitEnumerator* group +** A reference to an object that will be used to store +** intermediate state of enumerations. +** ERRORS +** Errors are indicated by the function returning a NULL. +** PR_INVALID_ARGUMENT_ERROR +** The 'group' argument does not reference a known object. +** PR_OUT_OF_MEMORY_ERROR +*/ +NSPR_API(PRMWaitEnumerator*) PR_CreateMWaitEnumerator(PRWaitGroup *group); + +/* +** FUNCTION: PR_DestroyMWaitEnumerator +** DESCRIPTION: +** Destroys the object created by PR_CreateMWaitEnumerator(). The reference +** used as an argument becomes invalid. +** +** INPUT +** PRMWaitEnumerator* enumerator +** The PRMWaitEnumerator object to destroy. +** RETURN +** PRStatus +** PR_SUCCESS if successful, PR_FAILURE otherwise. +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The enumerator is invalid. +*/ +NSPR_API(PRStatus) PR_DestroyMWaitEnumerator(PRMWaitEnumerator* enumerator); + +/* +** FUNCTION: PR_EnumerateWaitGroup +** DESCRIPTION: +** PR_EnumerateWaitGroup is a thread safe enumerator over a wait group. +** Each call to the enumerator must present a valid PRMWaitEnumerator +** rererence and a pointer to the "previous" element returned from the +** enumeration process or a NULL. +** +** An enumeration is started by passing a NULL as the "previous" value. +** Subsequent calls to the enumerator must pass in the result of the +** previous call. The enumeration end is signaled by the runtime returning +** a NULL as the result. +** +** Modifications to the content of the wait group are allowed during +** an enumeration. The effect is that the enumeration may have to be +** "reset" and that may result in duplicates being returned from the +** enumeration. +** +** An enumeration may be abandoned at any time. The runtime is not +** keeping any state, so there are no issues in that regard. +*/ +NSPR_API(PRRecvWait*) PR_EnumerateWaitGroup( + PRMWaitEnumerator *enumerator, const PRRecvWait *previous); + +PR_END_EXTERN_C + +#endif /* defined(_PRMWAIT_H) */ + +/* prmwait.h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prnetdb.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prnetdb.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prnetdb.h @@ -0,0 +1,467 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prnetdb_h___ +#define prnetdb_h___ + +#include "prtypes.h" +#include "prio.h" + +PR_BEGIN_EXTERN_C + + +/* + ********************************************************************* + * Translate an Internet address to/from a character string + ********************************************************************* + */ +NSPR_API(PRStatus) PR_StringToNetAddr( + const char *string, PRNetAddr *addr); + +NSPR_API(PRStatus) PR_NetAddrToString( + const PRNetAddr *addr, char *string, PRUint32 size); + +/* +** Structures returned by network data base library. All addresses are +** supplied in host order, and returned in network order (suitable for +** use in system calls). +*/ +/* +** Beware that WINSOCK.H defines h_addrtype and h_length as short. +** Client code does direct struct copies of hostent to PRHostEnt and +** hence the ifdef. +*/ +typedef struct PRHostEnt { + char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ +#ifdef WIN32 + PRInt16 h_addrtype; /* host address type */ + PRInt16 h_length; /* length of address */ +#else + PRInt32 h_addrtype; /* host address type */ + PRInt32 h_length; /* length of address */ +#endif + char **h_addr_list; /* list of addresses from name server */ +} PRHostEnt; + +/* A safe size to use that will mostly work... */ +#if (defined(AIX) && defined(_THREAD_SAFE)) || defined(OSF1) +#define PR_NETDB_BUF_SIZE sizeof(struct protoent_data) +#else +#define PR_NETDB_BUF_SIZE 1024 +#endif + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetHostByName() +** Lookup a host by name. +** +** INPUTS: +** char *hostname Character string defining the host name of interest +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *hostentry +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ +NSPR_API(PRStatus) PR_GetHostByName( + const char *hostname, char *buf, PRIntn bufsize, PRHostEnt *hostentry); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetIPNodeByName() +** Lookup a host by name. Equivalent to getipnodebyname(AI_DEFAULT) +** of RFC 2553. +** +** INPUTS: +** char *hostname Character string defining the host name of interest +** PRUint16 af Address family (either PR_AF_INET or PR_AF_INET6) +** PRIntn flags Specifies the types of addresses that are searched +** for and the types of addresses that are returned. +** The only supported flag is PR_AI_DEFAULT. +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *hostentry +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ + + +#define PR_AI_ALL 0x08 +#define PR_AI_V4MAPPED 0x10 +#define PR_AI_ADDRCONFIG 0x20 +#define PR_AI_NOCANONNAME 0x8000 +#define PR_AI_DEFAULT (PR_AI_V4MAPPED | PR_AI_ADDRCONFIG) + +NSPR_API(PRStatus) PR_GetIPNodeByName( + const char *hostname, + PRUint16 af, + PRIntn flags, + char *buf, + PRIntn bufsize, + PRHostEnt *hostentry); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetHostByAddr() +** Lookup a host entry by its network address. +** +** INPUTS: +** char *hostaddr IP address of host in question +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *hostentry +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ +NSPR_API(PRStatus) PR_GetHostByAddr( + const PRNetAddr *hostaddr, char *buf, PRIntn bufsize, PRHostEnt *hostentry); + +/*********************************************************************** +** FUNCTION: PR_EnumerateHostEnt() +** DESCRIPTION: +** A stateless enumerator over a PRHostEnt structure acquired from +** PR_GetHostByName() PR_GetHostByAddr() to evaluate the possible +** network addresses. +** +** INPUTS: +** PRIntn enumIndex Index of the enumeration. The enumeration starts +** and ends with a value of zero. +** +** PRHostEnt *hostEnt A pointer to a host entry struct that was +** previously returned by PR_GetHostByName() or +** PR_GetHostByAddr(). +** +** PRUint16 port The port number to be assigned as part of the +** PRNetAddr. +** +** OUTPUTS: +** PRNetAddr *address A pointer to an address structure that will be +** filled in by the call to the enumeration if the +** result of the call is greater than zero. +** +** RETURN: +** PRIntn The value that should be used for the next call +** of the enumerator ('enumIndex'). The enumeration +** is ended if this value is returned zero. +** If a value of -1 is returned, the enumeration +** has failed. The reason for the failure can be +** retrieved by calling PR_GetError(). +***********************************************************************/ +NSPR_API(PRIntn) PR_EnumerateHostEnt( + PRIntn enumIndex, const PRHostEnt *hostEnt, PRUint16 port, PRNetAddr *address); + +/*********************************************************************** +** FUNCTION: PR_InitializeNetAddr(), +** DESCRIPTION: +** Initialize the fields of a PRNetAddr, assigning well known values as +** appropriate. +** +** INPUTS +** PRNetAddrValue val The value to be assigned to the IP Address portion +** of the network address. This can only specify the +** special well known values that are equivalent to +** INADDR_ANY and INADDR_LOOPBACK. +** +** PRUint16 port The port number to be assigned in the structure. +** +** OUTPUTS: +** PRNetAddr *addr The address to be manipulated. +** +** RETURN: +** PRStatus To indicate success or failure. If the latter, the +** reason for the failure can be retrieved by calling +** PR_GetError(); +***********************************************************************/ +typedef enum PRNetAddrValue +{ + PR_IpAddrNull, /* do NOT overwrite the IP address */ + PR_IpAddrAny, /* assign logical INADDR_ANY to IP address */ + PR_IpAddrLoopback, /* assign logical INADDR_LOOPBACK */ + PR_IpAddrV4Mapped /* IPv4 mapped address */ +} PRNetAddrValue; + +NSPR_API(PRStatus) PR_InitializeNetAddr( + PRNetAddrValue val, PRUint16 port, PRNetAddr *addr); + +/*********************************************************************** +** FUNCTION: PR_SetNetAddr(), +** DESCRIPTION: +** Set the fields of a PRNetAddr, assigning well known values as +** appropriate. This function is similar to PR_InitializeNetAddr +** but differs in that the address family is specified. +** +** INPUTS +** PRNetAddrValue val The value to be assigned to the IP Address portion +** of the network address. This can only specify the +** special well known values that are equivalent to +** INADDR_ANY and INADDR_LOOPBACK. +** +** PRUint16 af The address family (either PR_AF_INET or PR_AF_INET6) +** +** PRUint16 port The port number to be assigned in the structure. +** +** OUTPUTS: +** PRNetAddr *addr The address to be manipulated. +** +** RETURN: +** PRStatus To indicate success or failure. If the latter, the +** reason for the failure can be retrieved by calling +** PR_GetError(); +***********************************************************************/ +NSPR_API(PRStatus) PR_SetNetAddr( + PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_IsNetAddrType() +** Determine if the network address is of the specified type. +** +** INPUTS: +** const PRNetAddr *addr A network address. +** PRNetAddrValue The type of network address +** +** RETURN: +** PRBool PR_TRUE if the network address is of the +** specified type, else PR_FALSE. +***********************************************************************/ +NSPR_API(PRBool) PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_ConvertIPv4AddrToIPv6() +** Convert an IPv4 addr to an (IPv4-mapped) IPv6 addr +** +** INPUTS: +** PRUint32 v4addr IPv4 address +** +** OUTPUTS: +** PRIPv6Addr *v6addr The converted IPv6 address +** +** RETURN: +** void +** +***********************************************************************/ +NSPR_API(void) PR_ConvertIPv4AddrToIPv6(PRUint32 v4addr, PRIPv6Addr *v6addr); + +/*********************************************************************** +** MACRO: +** DESCRIPTION: PR_NetAddrFamily() +** Get the 'family' field of a PRNetAddr union. +** +** INPUTS: +** const PRNetAddr *addr A network address. +** +** RETURN: +** PRUint16 The 'family' field of 'addr'. +***********************************************************************/ +#define PR_NetAddrFamily(addr) ((addr)->raw.family) + +/*********************************************************************** +** MACRO: +** DESCRIPTION: PR_NetAddrInetPort() +** Get the 'port' field of a PRNetAddr union. +** +** INPUTS: +** const PRNetAddr *addr A network address. +** +** RETURN: +** PRUint16 The 'port' field of 'addr'. +***********************************************************************/ +#define PR_NetAddrInetPort(addr) \ + ((addr)->raw.family == PR_AF_INET6 ? (addr)->ipv6.port : (addr)->inet.port) + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetProtoByName() +** Lookup a protocol entry based on protocol's name +** +** INPUTS: +** char *protocolname Character string of the protocol's name. +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *PRProtoEnt +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ + +typedef struct PRProtoEnt { + char *p_name; /* official protocol name */ + char **p_aliases; /* alias list */ +#ifdef WIN32 + PRInt16 p_num; /* protocol # */ +#else + PRInt32 p_num; /* protocol # */ +#endif +} PRProtoEnt; + +NSPR_API(PRStatus) PR_GetProtoByName( + const char* protocolname, char* buffer, PRInt32 bufsize, PRProtoEnt* result); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetProtoByNumber() +** Lookup a protocol entry based on protocol's number +** +** INPUTS: +** PRInt32 protocolnumber +** Number assigned to the protocol. +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *PRProtoEnt +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ +NSPR_API(PRStatus) PR_GetProtoByNumber( + PRInt32 protocolnumber, char* buffer, PRInt32 bufsize, PRProtoEnt* result); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetAddrInfoByName() +** Look up a host by name. Equivalent to getaddrinfo(host, NULL, ...) of +** RFC 3493. +** +** INPUTS: +** char *hostname Character string defining the host name of interest +** PRUint16 af May be PR_AF_UNSPEC or PR_AF_INET. +** PRIntn flags May be either PR_AI_ADDRCONFIG or +** PR_AI_ADDRCONFIG | PR_AI_NOCANONNAME. Include +** PR_AI_NOCANONNAME to suppress the determination of +** the canonical name corresponding to hostname. +** RETURN: +** PRAddrInfo* Handle to a data structure containing the results +** of the host lookup. Use PR_EnumerateAddrInfo to +** inspect the PRNetAddr values stored in this object. +** When no longer needed, this handle must be destroyed +** with a call to PR_FreeAddrInfo. If a lookup error +** occurs, then NULL will be returned. +***********************************************************************/ +typedef struct PRAddrInfo PRAddrInfo; + +NSPR_API(PRAddrInfo*) PR_GetAddrInfoByName( + const char *hostname, PRUint16 af, PRIntn flags); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_FreeAddrInfo() +** Destroy the PRAddrInfo handle allocated by PR_GetAddrInfoByName(). +** +** INPUTS: +** PRAddrInfo *addrInfo +** The handle resulting from a successful call to +** PR_GetAddrInfoByName(). +** RETURN: +** void +***********************************************************************/ +NSPR_API(void) PR_FreeAddrInfo(PRAddrInfo *addrInfo); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_EnumerateAddrInfo() +** A stateless enumerator over a PRAddrInfo handle acquired from +** PR_GetAddrInfoByName() to inspect the possible network addresses. +** +** INPUTS: +** void *enumPtr Index pointer of the enumeration. The enumeration +** starts and ends with a value of NULL. +** const PRAddrInfo *addrInfo +** The PRAddrInfo handle returned by a successful +** call to PR_GetAddrInfoByName(). +** PRUint16 port The port number to be assigned as part of the +** PRNetAddr. +** OUTPUTS: +** PRNetAddr *result A pointer to an address structure that will be +** filled in by the call to the enumeration if the +** result of the call is not NULL. +** RETURN: +** void* The value that should be used for the next call +** of the enumerator ('enumPtr'). The enumeration +** is ended if this value is NULL. +***********************************************************************/ +NSPR_API(void *) PR_EnumerateAddrInfo( + void *enumPtr, const PRAddrInfo *addrInfo, PRUint16 port, PRNetAddr *result); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetCanonNameFromAddrInfo() +** Extracts the canonical name of the hostname passed to +** PR_GetAddrInfoByName(). +** +** INPUTS: +** const PRAddrInfo *addrInfo +** The PRAddrInfo handle returned by a successful +** call to PR_GetAddrInfoByName(). +** RETURN: +** const char * A const pointer to the canonical hostname stored +** in the given PRAddrInfo handle. This pointer is +** invalidated once the PRAddrInfo handle is destroyed +** by a call to PR_FreeAddrInfo(). +***********************************************************************/ +NSPR_API(const char *) PR_GetCanonNameFromAddrInfo( + const PRAddrInfo *addrInfo); + +/*********************************************************************** +** FUNCTIONS: PR_ntohs, PR_ntohl, PR_ntohll, PR_htons, PR_htonl, PR_htonll +** +** DESCRIPTION: API entries for the common byte ordering routines. +** +** PR_ntohs 16 bit conversion from network to host +** PR_ntohl 32 bit conversion from network to host +** PR_ntohll 64 bit conversion from network to host +** PR_htons 16 bit conversion from host to network +** PR_htonl 32 bit conversion from host to network +** PR_ntonll 64 bit conversion from host to network +** +***********************************************************************/ +NSPR_API(PRUint16) PR_ntohs(PRUint16); +NSPR_API(PRUint32) PR_ntohl(PRUint32); +NSPR_API(PRUint64) PR_ntohll(PRUint64); +NSPR_API(PRUint16) PR_htons(PRUint16); +NSPR_API(PRUint32) PR_htonl(PRUint32); +NSPR_API(PRUint64) PR_htonll(PRUint64); + +PR_END_EXTERN_C + +#endif /* prnetdb_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prolock.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prolock.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prolock.h @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prolock_h___ +#define prolock_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** A locking mechanism, built on the existing PRLock definition, +** is provided that will permit applications to define a Lock +** Hierarchy (or Lock Ordering) schema. An application designed +** using the Ordered Lock functions will terminate with a +** diagnostic message when a lock inversion condition is +** detected. +** +** The lock ordering detection is compile-time enabled only. In +** optimized builds of NSPR, the Ordered Lock functions map +** directly to PRLock functions, providing no lock order +** detection. +** +** The Ordered Lock Facility is compiled in when DEBUG is defined at +** compile-time. Ordered Lock can be forced on in optimized builds by +** defining FORCE_NSPR_ORDERED_LOCK at compile-time. Both the +** application using Ordered Lock and NSPR must be compiled with the +** facility enabled to achieve the desired results. +** +** Application designers should use the macro interfaces to the Ordered +** Lock facility to ensure that it is compiled out in optimized builds. +** +** Application designers are responsible for defining their own +** lock hierarchy. +** +** Ordered Lock is thread-safe and SMP safe. +** +** See Also: prlock.h +** +** /lth. 10-Jun-1998. +** +*/ + +/* +** Opaque type for ordered lock. +** ... Don't even think of looking in here. +** +*/ + +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +typedef void * PROrderedLock; +#else +/* +** Map PROrderedLock and methods onto PRLock when ordered locking +** is not compiled in. +** +*/ +#include "prlock.h" + +typedef PRLock PROrderedLock; +#endif + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_CreateOrderedLock() -- Create an Ordered Lock +** +** DESCRIPTION: PR_CreateOrderedLock() creates an ordered lock. +** +** INPUTS: +** order: user defined order of this lock. +** name: name of the lock. For debugging purposes. +** +** OUTPUTS: returned +** +** RETURNS: PR_OrderedLock pointer +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_CREATE_ORDERED_LOCK(order,name)\ + PR_CreateOrderedLock((order),(name)) +#else +#define PR_CREATE_ORDERED_LOCK(order) PR_NewLock() +#endif + +NSPR_API(PROrderedLock *) + PR_CreateOrderedLock( + PRInt32 order, + const char *name +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DestroyOrderedLock() -- Destroy an Ordered Lock +** +** DESCRIPTION: PR_DestroyOrderedLock() destroys the ordered lock +** referenced by lock. +** +** INPUTS: lock: pointer to a PROrderedLock +** +** OUTPUTS: the lock is destroyed +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_DESTROY_ORDERED_LOCK(lock) PR_DestroyOrderedLock((lock)) +#else +#define PR_DESTROY_ORDERED_LOCK(lock) PR_DestroyLock((lock)) +#endif + +NSPR_API(void) + PR_DestroyOrderedLock( + PROrderedLock *lock +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_LockOrderedLock() -- Lock an ordered lock +** +** DESCRIPTION: PR_LockOrderedLock() locks the ordered lock +** referenced by lock. If the order of lock is less than or equal +** to the order of the highest lock held by the locking thread, +** the function asserts. +** +** INPUTS: lock: a pointer to a PROrderedLock +** +** OUTPUTS: The lock is held or the function asserts. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_LOCK_ORDERED_LOCK(lock) PR_LockOrderedLock((lock)) +#else +#define PR_LOCK_ORDERED_LOCK(lock) PR_Lock((lock)) +#endif + +NSPR_API(void) + PR_LockOrderedLock( + PROrderedLock *lock +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_UnlockOrderedLock() -- unlock and Ordered Lock +** +** DESCRIPTION: PR_UnlockOrderedLock() unlocks the lock referenced +** by lock. +** +** INPUTS: lock: a pointer to a PROrderedLock +** +** OUTPUTS: the lock is unlocked +** +** RETURNS: +** PR_SUCCESS +** PR_FAILURE +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_UNLOCK_ORDERED_LOCK(lock) PR_UnlockOrderedLock((lock)) +#else +#define PR_UNLOCK_ORDERED_LOCK(lock) PR_Unlock((lock)) +#endif + +NSPR_API(PRStatus) + PR_UnlockOrderedLock( + PROrderedLock *lock +); + +PR_END_EXTERN_C + +#endif /* prolock_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prpdce.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prpdce.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prpdce.h @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* + * File: prpdce.h + * Description: This file is the API defined to allow for DCE (aka POSIX) + * thread emulation in an NSPR environment. It is not the + * intent that this be a fully supported API. + */ + +#if !defined(PRPDCE_H) +#define PRPDCE_H + +#include "prlock.h" +#include "prcvar.h" +#include "prtypes.h" +#include "prinrval.h" + +PR_BEGIN_EXTERN_C + +#define _PR_NAKED_CV_LOCK (PRLock*)0xdce1dce1 + +/* +** Test and acquire a lock. +** +** If the lock is acquired by the calling thread, the +** return value will be PR_SUCCESS. If the lock is +** already held, by another thread or this thread, the +** result will be PR_FAILURE. +*/ +NSPR_API(PRStatus) PRP_TryLock(PRLock *lock); + +/* +** Create a naked condition variable +** +** A "naked" condition variable is one that is not created bound +** to a lock. The CV created with this function is the only type +** that may be used in the subsequent "naked" condition variable +** operations (see PRP_NakedWait, PRP_NakedNotify, PRP_NakedBroadcast); +*/ +NSPR_API(PRCondVar*) PRP_NewNakedCondVar(void); + +/* +** Destroy a naked condition variable +** +** Destroy the condition variable created by PR_NewNakedCondVar. +*/ +NSPR_API(void) PRP_DestroyNakedCondVar(PRCondVar *cvar); + +/* +** Wait on a condition +** +** Wait on the condition variable 'cvar'. It is asserted that +** the lock protecting the condition 'lock' is held by the +** calling thread. If more time expires than that declared in +** 'timeout' the condition will be notified. Waits can be +** interrupted by another thread. +** +** NB: The CV ('cvar') must be one created using PR_NewNakedCondVar. +*/ +NSPR_API(PRStatus) PRP_NakedWait( + PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout); + +/* +** Notify a thread waiting on a condition +** +** Notify the condition specified 'cvar'. +** +** NB: The CV ('cvar') must be one created using PR_NewNakedCondVar. +*/ +NSPR_API(PRStatus) PRP_NakedNotify(PRCondVar *cvar); + +/* +** Notify all threads waiting on a condition +** +** Notify the condition specified 'cvar'. +** +** NB: The CV ('cvar') must be one created using PR_NewNakedCondVar. +*/ +NSPR_API(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar); + +PR_END_EXTERN_C + +#endif /* PRPDCE_H */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prprf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prprf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prprf.h @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prprf_h___ +#define prprf_h___ + +/* +** API for PR printf like routines. Supports the following formats +** %d - decimal +** %u - unsigned decimal +** %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 - string +** %c - character +** %p - pointer (deals with machine dependent pointer size) +** %f - float +** %g - float +*/ +#include "prtypes.h" +#include "prio.h" +#include +#include + +PR_BEGIN_EXTERN_C + +/* +** 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 (PRUint32)-1 if an error occurs. +*/ +NSPR_API(PRUint32) PR_snprintf(char *out, PRUint32 outlen, const char *fmt, ...); + +/* +** sprintf into a PR_MALLOC'd buffer. Return a pointer to the malloc'd +** buffer on success, NULL on failure. Call "PR_smprintf_free" to release +** the memory returned. +*/ +NSPR_API(char*) PR_smprintf(const char *fmt, ...); + +/* +** Free the memory allocated, for the caller, by PR_smprintf +*/ +NSPR_API(void) PR_smprintf_free(char *mem); + +/* +** "append" sprintf into a PR_MALLOC'd buffer. "last" is the last value of +** the PR_MALLOC'd buffer. sprintf will append data to the end of last, +** growing it as necessary using realloc. If last is NULL, PR_sprintf_append +** will allocate the initial string. The return value is the new value of +** last for subsequent calls, or NULL if there is a malloc failure. +*/ +NSPR_API(char*) PR_sprintf_append(char *last, const char *fmt, ...); + +/* +** sprintf into a function. The function "f" is called with a string to +** place into the output. "arg" is an opaque pointer used by the stuff +** function to hold any state needed to do the storage of the output +** data. The return value is a count of the number of characters fed to +** the stuff function, or (PRUint32)-1 if an error occurs. +*/ +typedef PRIntn (*PRStuffFunc)(void *arg, const char *s, PRUint32 slen); + +NSPR_API(PRUint32) PR_sxprintf(PRStuffFunc f, void *arg, const char *fmt, ...); + +/* +** fprintf to a PRFileDesc +*/ +NSPR_API(PRUint32) PR_fprintf(struct PRFileDesc* fd, const char *fmt, ...); + +/* +** va_list forms of the above. +*/ +NSPR_API(PRUint32) PR_vsnprintf(char *out, PRUint32 outlen, const char *fmt, va_list ap); +NSPR_API(char*) PR_vsmprintf(const char *fmt, va_list ap); +NSPR_API(char*) PR_vsprintf_append(char *last, const char *fmt, va_list ap); +NSPR_API(PRUint32) PR_vsxprintf(PRStuffFunc f, void *arg, const char *fmt, va_list ap); +NSPR_API(PRUint32) PR_vfprintf(struct PRFileDesc* fd, const char *fmt, va_list ap); + +/* +*************************************************************************** +** FUNCTION: PR_sscanf +** DESCRIPTION: +** PR_sscanf() scans the input character string, performs data +** conversions, and stores the converted values in the data objects +** pointed to by its arguments according to the format control +** string. +** +** PR_sscanf() behaves the same way as the sscanf() function in the +** Standard C Library (stdio.h), with the following exceptions: +** - PR_sscanf() handles the NSPR integer and floating point types, +** such as PRInt16, PRInt32, PRInt64, and PRFloat64, whereas +** sscanf() handles the standard C types like short, int, long, +** and double. +** - PR_sscanf() has no multibyte character support, while sscanf() +** does. +** INPUTS: +** const char *buf +** a character string holding the input to scan +** const char *fmt +** the format control string for the conversions +** ... +** variable number of arguments, each of them is a pointer to +** a data object in which the converted value will be stored +** OUTPUTS: none +** RETURNS: PRInt32 +** The number of values converted and stored. +** RESTRICTIONS: +** Multibyte characters in 'buf' or 'fmt' are not allowed. +*************************************************************************** +*/ + +NSPR_API(PRInt32) PR_sscanf(const char *buf, const char *fmt, ...); + +PR_END_EXTERN_C + +#endif /* prprf_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prproces.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prproces.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prproces.h @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prproces_h___ +#define prproces_h___ + +#include "prtypes.h" +#include "prio.h" + +PR_BEGIN_EXTERN_C + +/************************************************************************/ +/*****************************PROCESS OPERATIONS*************************/ +/************************************************************************/ + +typedef struct PRProcess PRProcess; +typedef struct PRProcessAttr PRProcessAttr; + +NSPR_API(PRProcessAttr *) PR_NewProcessAttr(void); + +NSPR_API(void) PR_ResetProcessAttr(PRProcessAttr *attr); + +NSPR_API(void) PR_DestroyProcessAttr(PRProcessAttr *attr); + +NSPR_API(void) PR_ProcessAttrSetStdioRedirect( + PRProcessAttr *attr, + PRSpecialFD stdioFd, + PRFileDesc *redirectFd +); + +/* + * OBSOLETE -- use PR_ProcessAttrSetStdioRedirect instead. + */ +NSPR_API(void) PR_SetStdioRedirect( + PRProcessAttr *attr, + PRSpecialFD stdioFd, + PRFileDesc *redirectFd +); + +NSPR_API(PRStatus) PR_ProcessAttrSetCurrentDirectory( + PRProcessAttr *attr, + const char *dir +); + +NSPR_API(PRStatus) PR_ProcessAttrSetInheritableFD( + PRProcessAttr *attr, + PRFileDesc *fd, + const char *name +); + +/* +** Create a new process +** +** Create a new process executing the file specified as 'path' and with +** the supplied arguments and environment. +** +** This function may fail because of illegal access (permissions), +** invalid arguments or insufficient resources. +** +** A process may be created such that the creator can later synchronize its +** termination using PR_WaitProcess(). +*/ + +NSPR_API(PRProcess*) PR_CreateProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr); + +NSPR_API(PRStatus) PR_CreateProcessDetached( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr); + +NSPR_API(PRStatus) PR_DetachProcess(PRProcess *process); + +NSPR_API(PRStatus) PR_WaitProcess(PRProcess *process, PRInt32 *exitCode); + +NSPR_API(PRStatus) PR_KillProcess(PRProcess *process); + +PR_END_EXTERN_C + +#endif /* prproces_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prrng.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prrng.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prrng.h @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + + +/* +** prrng.h -- NSPR Random Number Generator +** +** +** lth. 29-Oct-1999. +*/ + +#ifndef prrng_h___ +#define prrng_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** PR_GetRandomNoise() -- Get random noise from the host platform +** +** Description: +** PR_GetRandomNoise() provides, depending on platform, a random value. +** The length of the random value is dependent on platform and the +** platform's ability to provide a random value at that moment. +** +** The intent of PR_GetRandomNoise() is to provide a "seed" value for a +** another random number generator that may be suitable for +** cryptographic operations. This implies that the random value +** provided may not be, by itself, cryptographically secure. The value +** generated by PR_GetRandomNoise() is at best, extremely difficult to +** predict and is as non-deterministic as the underlying platfrom can +** provide. +** +** Inputs: +** buf -- pointer to a caller supplied buffer to contain the +** generated random number. buf must be at least as large as +** is specified in the 'size' argument. +** +** size -- the requested size of the generated random number +** +** Outputs: +** a random number provided in 'buf'. +** +** Returns: +** PRSize value equal to the size of the random number actually +** generated, or zero. The generated size may be less than the size +** requested. A return value of zero means that PR_GetRandomNoise() is +** not implemented on this platform, or there is no available noise +** available to be returned at the time of the call. +** +** Restrictions: +** Calls to PR_GetRandomNoise() may use a lot of CPU on some platforms. +** Some platforms may block for up to a few seconds while they +** accumulate some noise. Busy machines generate lots of noise, but +** care is advised when using PR_GetRandomNoise() frequently in your +** application. +** +** History: +** Parts of the model dependent implementation for PR_GetRandomNoise() +** were taken in whole or part from code previously in Netscape's NSS +** component. +** +*/ +NSPR_API(PRSize) PR_GetRandomNoise( + void *buf, + PRSize size +); + +PR_END_EXTERN_C + +#endif /* prrng_h___ */ +/* end prrng.h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prrwlock.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prrwlock.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prrwlock.h @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: prrwlock.h +** Description: API to basic reader-writer lock functions of NSPR. +** +**/ + +#ifndef prrwlock_h___ +#define prrwlock_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* + * PRRWLock -- + * + * The reader writer lock, PRRWLock, is an opaque object to the clients + * of NSPR. All routines operate on a pointer to this opaque entity. + */ + + +typedef struct PRRWLock PRRWLock; + +#define PR_RWLOCK_RANK_NONE 0 + + +/*********************************************************************** +** FUNCTION: PR_NewRWLock +** DESCRIPTION: +** Returns a pointer to a newly created reader-writer lock object. +** INPUTS: Lock rank +** Lock name +** OUTPUTS: void +** RETURN: PRRWLock* +** If the lock cannot be created because of resource constraints, NULL +** is returned. +** +***********************************************************************/ +NSPR_API(PRRWLock*) PR_NewRWLock(PRUint32 lock_rank, const char *lock_name); + +/*********************************************************************** +** FUNCTION: PR_DestroyRWLock +** DESCRIPTION: +** Destroys a given RW lock object. +** INPUTS: PRRWLock *lock - Lock to be freed. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_DestroyRWLock(PRRWLock *lock); + +/*********************************************************************** +** FUNCTION: PR_RWLock_Rlock +** DESCRIPTION: +** Apply a read lock (non-exclusive) on a RWLock +** INPUTS: PRRWLock *lock - Lock to be read-locked. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_RWLock_Rlock(PRRWLock *lock); + +/*********************************************************************** +** FUNCTION: PR_RWLock_Wlock +** DESCRIPTION: +** Apply a write lock (exclusive) on a RWLock +** INPUTS: PRRWLock *lock - Lock to write-locked. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_RWLock_Wlock(PRRWLock *lock); + +/*********************************************************************** +** FUNCTION: PR_RWLock_Unlock +** DESCRIPTION: +** Release a RW lock. Unlocking an unlocked lock has undefined results. +** INPUTS: PRRWLock *lock - Lock to unlocked. +** OUTPUTS: void +** RETURN: void +***********************************************************************/ +NSPR_API(void) PR_RWLock_Unlock(PRRWLock *lock); + +PR_END_EXTERN_C + +#endif /* prrwlock_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prshm.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prshm.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prshm.h @@ -0,0 +1,257 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** prshm.h -- NSPR Shared Memory +** +** NSPR Named Shared Memory API provides a cross-platform named +** shared-memory interface. NSPR Named Shared Memory is modeled on +** similar constructs in Unix and Windows operating systems. Shared +** memory allows multiple processes to access one or more common shared +** memory regions, using it as an inter-process communication channel. +** +** Notes on Platform Independence: +** NSPR Named Shared Memory is built on the native services offered +** by most platforms. The NSPR Named Shared Memory API tries to +** provide a least common denominator interface so that it works +** across all supported platforms. To ensure that it works everywhere, +** some platform considerations must be accomodated and the protocol +** for using NSPR Shared Memory API must be observed. +** +** Protocol: +** Multiple shared memories can be created using NSPR's Shared Memory +** feature. For each named shared memory, as defined by the name +** given in the PR_OpenSharedMemory() call, a protocol for using the +** shared memory API is required to ensure desired behavior. Failing +** to follow the protocol may yield unpredictable results. +** +** PR_OpenSharedMemory() will create the shared memory segment, if it +** does not already exist, or open a connection that the existing +** shared memory segment if it already exists. +** +** PR_AttachSharedMemory() should be called following +** PR_OpenSharedMemory() to map the memory segment to an address in +** the application's address space. +** +** PR_AttachSharedMemory() may be called to re-map a shared memory +** segment after detaching the same PRSharedMemory object. Be +** sure to detach it when done. +** +** PR_DetachSharedMemory() should be called to un-map the shared +** memory segment from the application's address space. +** +** PR_CloseSharedMemory() should be called when no further use of the +** PRSharedMemory object is required within a process. Following a +** call to PR_CloseSharedMemory() the PRSharedMemory object is +** invalid and cannot be reused. +** +** PR_DeleteSharedMemory() should be called before process +** termination. After calling PR_DeleteSharedMemory() any further use +** of the shared memory associated with the name may cause +** unpredictable results. +** +** Files: +** The name passed to PR_OpenSharedMemory() should be a valid filename +** for a unix platform. PR_OpenSharedMemory() creates file using the +** name passed in. Some platforms may mangle the name before creating +** the file and the shared memory. +** +** The unix implementation may use SysV IPC shared memory, Posix +** shared memory, or memory mapped files; the filename may used to +** define the namespace. On Windows, the name is significant, but +** there is no file associated with name. +** +** No assumptions about the persistence of data in the named file +** should be made. Depending on platform, the shared memory may be +** mapped onto system paging space and be discarded at process +** termination. +** +** All names provided to PR_OpenSharedMemory() should be valid +** filename syntax or name syntax for shared memory for the target +** platform. Referenced directories should have permissions +** appropriate for writing. +** +** Limits: +** Different platforms have limits on both the number and size of +** shared memory resources. The default system limits on some +** platforms may be smaller than your requirements. These limits may +** be adjusted on some platforms either via boot-time options or by +** setting the size of the system paging space to accomodate more +** and/or larger shared memory segment(s). +** +** Security: +** On unix platforms, depending on implementation, contents of the +** backing store for the shared memory can be exposed via the file +** system. Set permissions and or access controls at create and attach +** time to ensure you get the desired security. +** +** On windows platforms, no special security measures are provided. +** +** Example: +** The test case pr/tests/nameshm1.c provides an example of use as +** well as testing the operation of NSPR's Named Shared Memory. +** +** lth. 18-Aug-1999. +*/ + +#ifndef prshm_h___ +#define prshm_h___ + +#include "prtypes.h" +#include "prio.h" + +PR_BEGIN_EXTERN_C + +/* +** Declare opaque type PRSharedMemory. +*/ +typedef struct PRSharedMemory PRSharedMemory; + +/* +** FUNCTION: PR_OpenSharedMemory() +** +** DESCRIPTION: +** PR_OpenSharedMemory() creates a new shared-memory segment or +** associates a previously created memory segment with name. +** +** When parameter create is (PR_SHM_EXCL | PR_SHM_CREATE) and the +** shared memory already exists, the function returns NULL with the +** error set to PR_FILE_EXISTS_ERROR. +** +** When parameter create is PR_SHM_CREATE and the shared memory +** already exists, a handle to that memory segment is returned. If +** the segment does not exist, it is created and a pointer to the +** related PRSharedMemory structure is returned. +** +** When parameter create is 0, and the shared memory exists, a +** pointer to a PRSharedMemory is returned. If the shared memory does +** not exist, NULL is returned with the error set to +** PR_FILE_NOT_FOUND_ERROR. +** +** INPUTS: +** name -- the name the shared-memory segment is known as. +** size -- the size of the shared memory segment. +** flags -- Options for creating the shared memory +** mode -- Same as is passed to PR_Open() +** +** OUTPUTS: +** The shared memory is allocated. +** +** RETURNS: Pointer to opaque structure PRSharedMemory or NULL. +** NULL is returned on error. The reason for the error can be +** retrieved via PR_GetError() and PR_GetOSError(); +** +*/ +NSPR_API( PRSharedMemory * ) + PR_OpenSharedMemory( + const char *name, + PRSize size, + PRIntn flags, + PRIntn mode +); +/* Define values for PR_OpenShareMemory(...,create) */ +#define PR_SHM_CREATE 0x1 /* create if not exist */ +#define PR_SHM_EXCL 0x2 /* fail if already exists */ + +/* +** FUNCTION: PR_AttachSharedMemory() +** +** DESCRIPTION: +** PR_AttachSharedMemory() maps the shared-memory described by +** shm to the current process. +** +** INPUTS: +** shm -- The handle returned from PR_OpenSharedMemory(). +** flags -- options for mapping the shared memory. +** PR_SHM_READONLY causes the memory to be attached +** read-only. +** +** OUTPUTS: +** On success, the shared memory segment represented by shm is mapped +** into the process' address space. +** +** RETURNS: Address where shared memory is mapped, or NULL. +** NULL is returned on error. The reason for the error can be +** retrieved via PR_GetError() and PR_GetOSError(); +** +** +*/ +NSPR_API( void * ) + PR_AttachSharedMemory( + PRSharedMemory *shm, + PRIntn flags +); +/* Define values for PR_AttachSharedMemory(...,flags) */ +#define PR_SHM_READONLY 0x01 + +/* +** FUNCTION: PR_DetachSharedMemory() +** +** DESCRIPTION: +** PR_DetachSharedMemory() detaches the shared-memory described +** by shm. +** +** INPUTS: +** shm -- The handle returned from PR_OpenSharedMemory(). +** addr -- The address at which the memory was attached. +** +** OUTPUTS: +** The shared memory mapped to an address via a previous call to +** PR_AttachSharedMemory() is unmapped. +** +** RETURNS: PRStatus +** +*/ +NSPR_API( PRStatus ) + PR_DetachSharedMemory( + PRSharedMemory *shm, + void *addr +); + +/* +** FUNCTION: PR_CloseSharedMemory() +** +** DESCRIPTION: +** PR_CloseSharedMemory() closes the shared-memory described by +** shm. +** +** INPUTS: +** shm -- The handle returned from PR_OpenSharedMemory(). +** +** OUTPUTS: +** the shared memory represented by shm is closed +** +** RETURNS: PRStatus +** +*/ +NSPR_API( PRStatus ) + PR_CloseSharedMemory( + PRSharedMemory *shm +); + +/* +** FUNCTION: PR_DeleteSharedMemory() +** +** DESCRIPTION: +** The shared memory resource represented by name is released. +** +** INPUTS: +** name -- the name the shared-memory segment +** +** OUTPUTS: +** depending on platform, resources may be returned to the underlying +** operating system. +** +** RETURNS: PRStatus +** +*/ +NSPR_API( PRStatus ) + PR_DeleteSharedMemory( + const char *name +); + +PR_END_EXTERN_C + +#endif /* prshm_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prshma.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prshma.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prshma.h @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** prshma.h -- NSPR Anonymous Shared Memory +** +** NSPR provides an anonymous shared memory based on NSPR's PRFileMap +** type. The anonymous file-mapped shared memory provides an inheritable +** shared memory, as in: the child process inherits the shared memory. +** Compare the file-mapped anonymous shared memory to to a named shared +** memory described in prshm.h. The intent is to provide a shared +** memory that is accessable only by parent and child processes. ... +** It's a security thing. +** +** Depending on the underlying platform, the file-mapped shared memory +** may be backed by a file. ... surprise! ... On some platforms, no +** real file backs the shared memory. On platforms where the shared +** memory is backed by a file, the file's name in the filesystem is +** visible to other processes for only the duration of the creation of +** the file, hopefully a very short time. This restricts processess +** that do not inherit the shared memory from opening the file and +** reading or writing its contents. Further, when all processes +** using an anonymous shared memory terminate, the backing file is +** deleted. ... If you are not paranoid, you're not paying attention. +** +** The file-mapped shared memory requires a protocol for the parent +** process and child process to share the memory. NSPR provides two +** protocols. Use one or the other; don't mix and match. +** +** In the first protocol, the job of passing the inheritable shared +** memory is done via helper-functions with PR_CreateProcess(). In the +** second protocol, the parent process is responsible for creating the +** child process; the parent and child are mutually responsible for +** passing a FileMap string. NSPR provides helper functions for +** extracting data from the PRFileMap object. ... See the examples +** below. +** +** Both sides should adhere strictly to the protocol for proper +** operation. The pseudo-code below shows the use of a file-mapped +** shared memory by a parent and child processes. In the examples, the +** server creates the file-mapped shared memory, the client attaches to +** it. +** +** First protocol. +** Server: +** +** fm = PR_OpenAnonFileMap(dirName, size, FilemapProt); +** addr = PR_MemMap(fm); +** attr = PR_NewProcessAttr(); +** PR_ProcessAttrSetInheritableFileMap( attr, fm, shmname ); +** PR_CreateProcess(Client); +** PR_DestroyProcessAttr(attr); +** ... yadda ... +** PR_MemUnmap( addr ); +** PR_CloseFileMap(fm); +** +** +** Client: +** ... started by server via PR_CreateProcess() +** fm = PR_GetInheritedFileMap( shmname ); +** addr = PR_MemMap(fm); +** ... yadda ... +** PR_MemUnmap(addr); +** PR_CloseFileMap(fm); +** +** +** Second Protocol: +** Server: +** +** fm = PR_OpenAnonFileMap(dirName, size, FilemapProt); +** fmstring = PR_ExportFileMapAsString( fm ); +** addr = PR_MemMap(fm); +** ... application specific technique to pass fmstring to child +** ... yadda ... Server uses his own magic to create child +** PR_MemUnmap( addr ); +** PR_CloseFileMap(fm); +** +** +** Client: +** ... started by server via his own magic +** ... application specific technique to find fmstring from parent +** fm = PR_ImportFileMapFromString( fmstring ) +** addr = PR_MemMap(fm); +** ... yadda ... +** PR_MemUnmap(addr); +** PR_CloseFileMap(fm); +** +** +** lth. 2-Jul-1999. +** +** Note: The second protocol was requested by NelsonB (7/1999); this is +** to accomodate servers which already create their own child processes +** using platform native methods. +** +*/ + +#ifndef prshma_h___ +#define prshma_h___ + +#include "prtypes.h" +#include "prio.h" +#include "prproces.h" + +PR_BEGIN_EXTERN_C + +/* +** PR_OpenAnonFileMap() -- Creates an anonymous file-mapped shared memory +** +** Description: +** PR_OpenAnonFileMap() creates an anonymous shared memory. If the +** shared memory already exists, a handle is returned to that shared +** memory object. +** +** On Unix platforms, PR_OpenAnonFileMap() uses 'dirName' as a +** directory name, without the trailing '/', to contain the anonymous +** file. A filename is generated for the name. +** +** On Windows platforms, dirName is ignored. +** +** Inputs: +** dirName -- A directory name to contain the anonymous file. +** size -- The size of the shared memory +** prot -- How the shared memory is mapped. See prio.h +** +** Outputs: +** PRFileMap * +** +** Returns: +** Pointer to PRFileMap or NULL on error. +** +*/ +NSPR_API( PRFileMap *) +PR_OpenAnonFileMap( + const char *dirName, + PRSize size, + PRFileMapProtect prot +); + +/* +** PR_ProcessAttrSetInheritableFileMap() -- Prepare FileMap for export +** to my children processes via PR_CreateProcess() +** +** Description: +** PR_ProcessAttrSetInheritableFileMap() connects the PRFileMap to +** PRProcessAttr with shmname. A subsequent call to PR_CreateProcess() +** makes the PRFileMap importable by the child process. +** +** Inputs: +** attr -- PRProcessAttr, used to pass data to PR_CreateProcess() +** fm -- PRFileMap structure to be passed to the child process +** shmname -- The name for the PRFileMap; used by child. +** +** Outputs: +** PRFileMap * +** +** Returns: +** PRStatus +** +*/ +NSPR_API(PRStatus) +PR_ProcessAttrSetInheritableFileMap( + PRProcessAttr *attr, + PRFileMap *fm, + const char *shmname +); + +/* +** PR_GetInheritedFileMap() -- Import a PRFileMap previously exported +** by my parent process via PR_CreateProcess() +** +** Description: +** PR_GetInheritedFileMap() retrieves a PRFileMap object exported from +** its parent process via PR_CreateProcess(). +** +** Inputs: +** shmname -- The name provided to PR_ProcessAttrSetInheritableFileMap() +** +** Outputs: +** PRFileMap * +** +** Returns: +** PRFileMap pointer or NULL. +** +*/ +NSPR_API( PRFileMap *) +PR_GetInheritedFileMap( + const char *shmname +); + +/* +** PR_ExportFileMapAsString() -- Creates a string identifying a PRFileMap +** +** Description: +** Creates an identifier, as a string, from a PRFileMap object +** previously created with PR_OpenAnonFileMap(). +** +** Inputs: +** fm -- PRFileMap pointer to be represented as a string. +** bufsize -- sizeof(buf) +** buf -- a buffer of length PR_FILEMAP_STRING_BUFSIZE +** +** Outputs: +** buf contains the stringized PRFileMap identifier +** +** Returns: +** PRStatus +** +*/ +NSPR_API( PRStatus ) +PR_ExportFileMapAsString( + PRFileMap *fm, + PRSize bufsize, + char *buf +); +#define PR_FILEMAP_STRING_BUFSIZE 128 + +/* +** PR_ImportFileMapFromString() -- Creates a PRFileMap from the identifying string +** +** Description: +** PR_ImportFileMapFromString() creates a PRFileMap object from a +** string previously created by PR_ExportFileMapAsString(). +** +** Inputs: +** fmstring -- string created by PR_ExportFileMapAsString() +** +** Returns: +** PRFileMap pointer or NULL. +** +*/ +NSPR_API( PRFileMap * ) +PR_ImportFileMapFromString( + const char *fmstring +); + +PR_END_EXTERN_C +#endif /* prshma_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prsystem.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prsystem.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prsystem.h @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prsystem_h___ +#define prsystem_h___ + +/* +** API to NSPR functions returning system info. +*/ +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** Get the host' directory separator. +** Pathnames are then assumed to be of the form: +** []*() +*/ + +NSPR_API(char) PR_GetDirectorySeparator(void); + +/* +** OBSOLETE -- the function name is misspelled. +** Use PR_GetDirectorySeparator instead. +*/ + +NSPR_API(char) PR_GetDirectorySepartor(void); + +/* +** Get the host' path separator. +** Paths are assumed to be of the form: +** []* +*/ + +NSPR_API(char) PR_GetPathSeparator(void); + +/* Types of information available via PR_GetSystemInfo(...) */ +typedef enum { + PR_SI_HOSTNAME, /* the hostname with the domain name (if any) + * removed */ + PR_SI_SYSNAME, + PR_SI_RELEASE, + PR_SI_ARCHITECTURE, + PR_SI_HOSTNAME_UNTRUNCATED /* the hostname exactly as configured + * on the system */ +} PRSysInfo; + + +/* +** If successful returns a null termintated string in 'buf' for +** the information indicated in 'cmd'. If unseccussful the reason for +** the failure can be retrieved from PR_GetError(). +** +** The buffer is allocated by the caller and should be at least +** SYS_INFO_BUFFER_LENGTH bytes in length. +*/ + +#define SYS_INFO_BUFFER_LENGTH 256 + +NSPR_API(PRStatus) PR_GetSystemInfo(PRSysInfo cmd, char *buf, PRUint32 buflen); + +/* +** Return the number of bytes in a page +*/ +NSPR_API(PRInt32) PR_GetPageSize(void); + +/* +** Return log2 of the size of a page +*/ +NSPR_API(PRInt32) PR_GetPageShift(void); + +/* +** PR_GetNumberOfProcessors() -- returns the number of CPUs +** +** Description: +** PR_GetNumberOfProcessors() extracts the number of processors +** (CPUs available in an SMP system) and returns the number. +** +** Parameters: +** none +** +** Returns: +** The number of available processors or -1 on error +** +*/ +NSPR_API(PRInt32) PR_GetNumberOfProcessors( void ); + +/* +** PR_GetPhysicalMemorySize() -- returns the amount of system RAM +** +** Description: +** PR_GetPhysicalMemorySize() determines the amount of physical RAM +** in the system and returns the size in bytes. +** +** Parameters: +** none +** +** Returns: +** The amount of system RAM, or 0 on failure. +** +*/ +NSPR_API(PRUint64) PR_GetPhysicalMemorySize(void); + +PR_END_EXTERN_C + +#endif /* prsystem_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prthread.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prthread.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prthread.h @@ -0,0 +1,272 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prthread_h___ +#define prthread_h___ + +/* +** API for NSPR threads. On some architectures (Mac OS Classic +** notably) pre-emptibility is not guaranteed. Hard priority scheduling +** is not guaranteed, so programming using priority based synchronization +** is a no-no. +** +** NSPR threads are scheduled based loosely on their client set priority. +** In general, a thread of a higher priority has a statistically better +** chance of running relative to threads of lower priority. However, +** NSPR uses multiple strategies to provide execution vehicles for thread +** abstraction of various host platforms. As it turns out, there is little +** NSPR can do to affect the scheduling attributes of "GLOBAL" threads. +** However, a semblance of GLOBAL threads is used to implement "LOCAL" +** threads. An arbitrary number of such LOCAL threads can be assigned to +** a single GLOBAL thread. +** +** For scheduling, NSPR will attempt to run the highest priority LOCAL +** thread associated with a given GLOBAL thread. It is further assumed +** that the host OS will apply some form of "fair" scheduling on the +** GLOBAL threads. +** +** Threads have a "system flag" which when set indicates the thread +** doesn't count for determining when the process should exit (the +** process exits when the last user thread exits). +** +** Threads also have a "scope flag" which controls whether the threads +** are scheduled in the local scope or scheduled by the OS globally. This +** indicates whether a thread is permanently bound to a native OS thread. +** An unbound thread competes for scheduling resources in the same process. +** +** Another flag is "state flag" which control whether the thread is joinable. +** It allows other threads to wait for the created thread to reach completion. +** +** Threads can have "per-thread-data" attached to them. Each thread has a +** per-thread error number and error string which are updated when NSPR +** operations fail. +*/ +#include "prtypes.h" +#include "prinrval.h" + +PR_BEGIN_EXTERN_C + +typedef struct PRThread PRThread; +typedef struct PRThreadStack PRThreadStack; + +typedef enum PRThreadType { + PR_USER_THREAD, + PR_SYSTEM_THREAD +} PRThreadType; + +typedef enum PRThreadScope { + PR_LOCAL_THREAD, + PR_GLOBAL_THREAD, + PR_GLOBAL_BOUND_THREAD +} PRThreadScope; + +typedef enum PRThreadState { + PR_JOINABLE_THREAD, + PR_UNJOINABLE_THREAD +} PRThreadState; + +typedef enum PRThreadPriority +{ + PR_PRIORITY_FIRST = 0, /* just a placeholder */ + PR_PRIORITY_LOW = 0, /* the lowest possible priority */ + PR_PRIORITY_NORMAL = 1, /* most common expected priority */ + PR_PRIORITY_HIGH = 2, /* slightly more aggressive scheduling */ + PR_PRIORITY_URGENT = 3, /* it does little good to have more than one */ + PR_PRIORITY_LAST = 3 /* this is just a placeholder */ +} PRThreadPriority; + +/* +** Create a new thread: +** "type" is the type of thread to create +** "start(arg)" will be invoked as the threads "main" +** "priority" will be created thread's priority +** "scope" will specify whether the thread is local or global +** "state" will specify whether the thread is joinable or not +** "stackSize" the size of the stack, in bytes. The value can be zero +** and then a machine specific stack size will be chosen. +** +** This can return NULL if some kind of error occurs, such as if memory is +** tight. +** +** If you want the thread to start up waiting for the creator to do +** something, enter a lock before creating the thread and then have the +** threads start routine enter and exit the same lock. When you are ready +** for the thread to run, exit the lock. +** +** If you want to detect the completion of the created thread, the thread +** should be created joinable. Then, use PR_JoinThread to synchrnoize the +** termination of another thread. +** +** When the start function returns the thread exits. If it is the last +** PR_USER_THREAD to exit then the process exits. +*/ +NSPR_API(PRThread*) PR_CreateThread(PRThreadType type, + void (PR_CALLBACK *start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); + +/* +** Wait for thread termination: +** "thread" is the target thread +** +** This can return PR_FAILURE if no joinable thread could be found +** corresponding to the specified target thread. +** +** The calling thread is blocked until the target thread completes. +** Several threads cannot wait for the same thread to complete; one thread +** will operate successfully and others will terminate with an error PR_FAILURE. +** The calling thread will not be blocked if the target thread has already +** terminated. +*/ +NSPR_API(PRStatus) PR_JoinThread(PRThread *thread); + +/* +** Return the current thread object for the currently running code. +** Never returns NULL. +*/ +NSPR_API(PRThread*) PR_GetCurrentThread(void); +#ifndef NO_NSPR_10_SUPPORT +#define PR_CurrentThread() PR_GetCurrentThread() /* for nspr1.0 compat. */ +#endif /* NO_NSPR_10_SUPPORT */ + +/* +** Get the priority of "thread". +*/ +NSPR_API(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread); + +/* +** Change the priority of the "thread" to "priority". +** +** PR_SetThreadPriority works in a best-effort manner. On some platforms a +** special privilege, such as root access, is required to change thread +** priorities, especially to raise thread priorities. If the caller doesn't +** have enough privileges to change thread priorites, the function has no +** effect except causing a future PR_GetThreadPriority call to return +** |priority|. +*/ +NSPR_API(void) PR_SetThreadPriority(PRThread *thread, PRThreadPriority priority); + +/* +** Set the name of the current thread, which will be visible in a debugger +** and accessible via a call to PR_GetThreadName(). +*/ +NSPR_API(PRStatus) PR_SetCurrentThreadName(const char *name); + +/* +** Return the name of "thread", if set. Otherwise return NULL. +*/ +NSPR_API(const char *) PR_GetThreadName(const PRThread *thread); + +/* +** This routine returns a new index for per-thread-private data table. +** The index is visible to all threads within a process. This index can +** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines +** to save and retrieve data associated with the index for a thread. +** +** Each index is associationed with a destructor function ('dtor'). The function +** may be specified as NULL when the index is created. If it is not NULL, the +** function will be called when: +** - the thread exits and the private data for the associated index +** is not NULL, +** - new thread private data is set and the current private data is +** not NULL. +** +** The index independently maintains specific values for each binding thread. +** A thread can only get access to its own thread-specific-data. +** +** Upon a new index return the value associated with the index for all threads +** is NULL, and upon thread creation the value associated with all indices for +** that thread is NULL. +** +** Returns PR_FAILURE if the total number of indices will exceed the maximun +** allowed. +*/ +typedef void (PR_CALLBACK *PRThreadPrivateDTOR)(void *priv); + +NSPR_API(PRStatus) PR_NewThreadPrivateIndex( + PRUintn *newIndex, PRThreadPrivateDTOR destructor); + +/* +** Define some per-thread-private data. +** "tpdIndex" is an index into the per-thread private data table +** "priv" is the per-thread-private data +** +** If the per-thread private data table has a previously registered +** destructor function and a non-NULL per-thread-private data value, +** the destructor function is invoked. +** +** This can return PR_FAILURE if the index is invalid. +*/ +NSPR_API(PRStatus) PR_SetThreadPrivate(PRUintn tpdIndex, void *priv); + +/* +** Recover the per-thread-private data for the current thread. "tpdIndex" is +** the index into the per-thread private data table. +** +** The returned value may be NULL which is indistinguishable from an error +** condition. +** +** A thread can only get access to its own thread-specific-data. +*/ +NSPR_API(void*) PR_GetThreadPrivate(PRUintn tpdIndex); + +/* +** This routine sets the interrupt request for a target thread. The interrupt +** request remains in the thread's state until it is delivered exactly once +** or explicitly canceled. +** +** A thread that has been interrupted will fail all NSPR blocking operations +** that return a PRStatus (I/O, waiting on a condition, etc). +** +** PR_Interrupt may itself fail if the target thread is invalid. +*/ +NSPR_API(PRStatus) PR_Interrupt(PRThread *thread); + +/* +** Clear the interrupt request for the calling thread. If no such request +** is pending, this operation is a noop. +*/ +NSPR_API(void) PR_ClearInterrupt(void); + +/* +** Block the interrupt for the calling thread. +*/ +NSPR_API(void) PR_BlockInterrupt(void); + +/* +** Unblock the interrupt for the calling thread. +*/ +NSPR_API(void) PR_UnblockInterrupt(void); + +/* +** Make the current thread sleep until "ticks" time amount of time +** has expired. If "ticks" is PR_INTERVAL_NO_WAIT then the call is +** equivalent to calling PR_Yield. Calling PR_Sleep with an argument +** equivalent to PR_INTERVAL_NO_TIMEOUT is an error and will result +** in a PR_FAILURE error return. +*/ +NSPR_API(PRStatus) PR_Sleep(PRIntervalTime ticks); + +/* +** Get the scoping of this thread. +*/ +NSPR_API(PRThreadScope) PR_GetThreadScope(const PRThread *thread); + +/* +** Get the type of this thread. +*/ +NSPR_API(PRThreadType) PR_GetThreadType(const PRThread *thread); + +/* +** Get the join state of this thread. +*/ +NSPR_API(PRThreadState) PR_GetThreadState(const PRThread *thread); + +PR_END_EXTERN_C + +#endif /* prthread_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prtime.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prtime.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prtime.h @@ -0,0 +1,262 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* + *---------------------------------------------------------------------- + * + * prtime.h -- + * + * NSPR date and time functions + * + *----------------------------------------------------------------------- + */ + +#ifndef prtime_h___ +#define prtime_h___ + +#include "prlong.h" + +PR_BEGIN_EXTERN_C + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +#define PR_MSEC_PER_SEC 1000L +#define PR_USEC_PER_SEC 1000000L +#define PR_NSEC_PER_SEC 1000000000L +#define PR_USEC_PER_MSEC 1000L +#define PR_NSEC_PER_MSEC 1000000L + +/* + * PRTime -- + * + * NSPR represents basic time as 64-bit signed integers relative + * to midnight (00:00:00), January 1, 1970 Greenwich Mean Time (GMT). + * (GMT is also known as Coordinated Universal Time, UTC.) + * The units of time are in microseconds. Negative times are allowed + * to represent times prior to the January 1970 epoch. Such values are + * intended to be exported to other systems or converted to human + * readable form. + * + * Notes on porting: PRTime corresponds to time_t in ANSI C. NSPR 1.0 + * simply uses PRInt64. + */ + +typedef PRInt64 PRTime; + +/* + * Time zone and daylight saving time corrections applied to GMT to + * obtain the local time of some geographic location + */ + +typedef struct PRTimeParameters { + PRInt32 tp_gmt_offset; /* the offset from GMT in seconds */ + PRInt32 tp_dst_offset; /* contribution of DST in seconds */ +} PRTimeParameters; + +/* + * PRExplodedTime -- + * + * Time broken down into human-readable components such as year, month, + * day, hour, minute, second, and microsecond. Time zone and daylight + * saving time corrections may be applied. If they are applied, the + * offsets from the GMT must be saved in the 'tm_params' field so that + * all the information is available to reconstruct GMT. + * + * Notes on porting: PRExplodedTime corrresponds to struct tm in + * ANSI C, with the following differences: + * - an additional field tm_usec; + * - replacing tm_isdst by tm_params; + * - the month field is spelled tm_month, not tm_mon; + * - we use absolute year, AD, not the year since 1900. + * The corresponding type in NSPR 1.0 is called PRTime. Below is + * a table of date/time type correspondence in the three APIs: + * API time since epoch time in components + * ANSI C time_t struct tm + * NSPR 1.0 PRInt64 PRTime + * NSPR 2.0 PRTime PRExplodedTime + */ + +typedef struct PRExplodedTime { + PRInt32 tm_usec; /* microseconds past tm_sec (0-99999) */ + PRInt32 tm_sec; /* seconds past tm_min (0-61, accomodating + up to two leap seconds) */ + PRInt32 tm_min; /* minutes past tm_hour (0-59) */ + PRInt32 tm_hour; /* hours past tm_day (0-23) */ + PRInt32 tm_mday; /* days past tm_mon (1-31, note that it + starts from 1) */ + PRInt32 tm_month; /* months past tm_year (0-11, Jan = 0) */ + PRInt16 tm_year; /* absolute year, AD (note that we do not + count from 1900) */ + + PRInt8 tm_wday; /* calculated day of the week + (0-6, Sun = 0) */ + PRInt16 tm_yday; /* calculated day of the year + (0-365, Jan 1 = 0) */ + + PRTimeParameters tm_params; /* time parameters used by conversion */ +} PRExplodedTime; + +/* + * PRTimeParamFn -- + * + * A function of PRTimeParamFn type returns the time zone and + * daylight saving time corrections for some geographic location, + * given the current time in GMT. The input argument gmt should + * point to a PRExplodedTime that is in GMT, i.e., whose + * tm_params contains all 0's. + * + * For any time zone other than GMT, the computation is intended to + * consist of two steps: + * - Figure out the time zone correction, tp_gmt_offset. This number + * usually depends on the geographic location only. But it may + * also depend on the current time. For example, all of China + * is one time zone right now. But this situation may change + * in the future. + * - Figure out the daylight saving time correction, tp_dst_offset. + * This number depends on both the geographic location and the + * current time. Most of the DST rules are expressed in local + * current time. If so, one should apply the time zone correction + * to GMT before applying the DST rules. + */ + +typedef PRTimeParameters (PR_CALLBACK *PRTimeParamFn)(const PRExplodedTime *gmt); + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/* + * The PR_Now routine returns the current time relative to the + * epoch, midnight, January 1, 1970 UTC. The units of the returned + * value are microseconds since the epoch. + * + * The values returned are not guaranteed to advance in a linear fashion + * due to the application of time correction protocols which synchronize + * computer clocks to some external time source. Consequently it should + * not be depended on for interval timing. + * + * The implementation is machine dependent. + * Cf. time_t time(time_t *tp) in ANSI C. + */ +NSPR_API(PRTime) +PR_Now(void); + +/* + * Expand time binding it to time parameters provided by PRTimeParamFn. + * The calculation is envisoned to proceed in the following steps: + * - From given PRTime, calculate PRExplodedTime in GMT + * - Apply the given PRTimeParamFn to the GMT that we just calculated + * to obtain PRTimeParameters. + * - Add the PRTimeParameters offsets to GMT to get the local time + * as PRExplodedTime. + */ + +NSPR_API(void) PR_ExplodeTime( + PRTime usecs, PRTimeParamFn params, PRExplodedTime *exploded); + +/* Reverse operation of PR_ExplodeTime */ +NSPR_API(PRTime) +PR_ImplodeTime(const PRExplodedTime *exploded); + +/* + * Adjust exploded time to normalize field overflows after manipulation. + * Note that the following fields of PRExplodedTime should not be + * manipulated: + * - tm_month and tm_year: because the number of days in a month and + * number of days in a year are not constant, it is ambiguous to + * manipulate the month and year fields, although one may be tempted + * to. For example, what does "a month from January 31st" mean? + * - tm_wday and tm_yday: these fields are calculated by NSPR. Users + * should treat them as "read-only". + */ + +NSPR_API(void) PR_NormalizeTime( + PRExplodedTime *exploded, PRTimeParamFn params); + +/**********************************************************************/ +/*********************** TIME PARAMETER FUNCTIONS *********************/ +/**********************************************************************/ + +/* Time parameters that suit current host machine */ +NSPR_API(PRTimeParameters) PR_LocalTimeParameters(const PRExplodedTime *gmt); + +/* Time parameters that represent Greenwich Mean Time */ +NSPR_API(PRTimeParameters) PR_GMTParameters(const PRExplodedTime *gmt); + +/* + * Time parameters that represent the US Pacific Time Zone, with the + * current daylight saving time rules (for testing only) + */ +NSPR_API(PRTimeParameters) PR_USPacificTimeParameters(const PRExplodedTime *gmt); + +/* + * This parses a time/date string into a PRExplodedTime + * struct. It populates all fields but it can't split + * the offset from UTC into tp_gmt_offset and tp_dst_offset in + * most cases (exceptions: PST/PDT, MST/MDT, CST/CDT, EST/EDT, GMT/BST). + * In those cases tp_gmt_offset will be the sum of these two and + * tp_dst_offset will be 0. + * It returns PR_SUCCESS on success, and PR_FAILURE + * if the time/date string can't be parsed. + * + * Many formats are handled, including: + * + * 14 Apr 89 03:20:12 + * 14 Apr 89 03:20 GMT + * Fri, 17 Mar 89 4:01:33 + * Fri, 17 Mar 89 4:01 GMT + * Mon Jan 16 16:12 PDT 1989 + * Mon Jan 16 16:12 +0130 1989 + * 6 May 1992 16:41-JST (Wednesday) + * 22-AUG-1993 10:59:12.82 + * 22-AUG-1993 10:59pm + * 22-AUG-1993 12:59am + * 22-AUG-1993 12:59 PM + * Friday, August 04, 1995 3:54 PM + * 06/21/95 04:24:34 PM + * 20/06/95 21:07 + * 95-06-08 19:32:48 EDT + * + * If the input string doesn't contain a description of the timezone, + * we consult the `default_to_gmt' to decide whether the string should + * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE). + * The correct value for this argument depends on what standard specified + * the time string which you are parsing. + */ + +NSPR_API(PRStatus) PR_ParseTimeStringToExplodedTime ( + const char *string, + PRBool default_to_gmt, + PRExplodedTime *result); + +/* + * This uses PR_ParseTimeStringToExplodedTime to parse + * a time/date string and PR_ImplodeTime to transform it into + * a PRTime (microseconds after "1-Jan-1970 00:00:00 GMT"). + * It returns PR_SUCCESS on success, and PR_FAILURE + * if the time/date string can't be parsed. + */ + +NSPR_API(PRStatus) PR_ParseTimeString ( + const char *string, + PRBool default_to_gmt, + PRTime *result); + +/* Format a time value into a buffer. Same semantics as strftime() */ +NSPR_API(PRUint32) PR_FormatTime(char *buf, int buflen, const char *fmt, + const PRExplodedTime *time); + +/* Format a time value into a buffer. Time is always in US English format, + * regardless of locale setting. + */ +NSPR_API(PRUint32) +PR_FormatTimeUSEnglish(char *buf, PRUint32 bufSize, + const char *format, const PRExplodedTime *time); + +PR_END_EXTERN_C + +#endif /* prtime_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prtpool.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prtpool.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prtpool.h @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prtpool_h___ +#define prtpool_h___ + +#include "prtypes.h" +#include "prthread.h" +#include "prio.h" +#include "prerror.h" + +/* + * NOTE: + * THIS API IS A PRELIMINARY VERSION IN NSPR 4.0 AND IS SUBJECT TO + * CHANGE + */ + +PR_BEGIN_EXTERN_C + +typedef struct PRJobIoDesc { + PRFileDesc *socket; + PRErrorCode error; + PRIntervalTime timeout; +} PRJobIoDesc; + +typedef struct PRThreadPool PRThreadPool; +typedef struct PRJob PRJob; +typedef void (PR_CALLBACK *PRJobFn) (void *arg); + +/* Create thread pool */ +NSPR_API(PRThreadPool *) +PR_CreateThreadPool(PRInt32 initial_threads, PRInt32 max_threads, + PRUint32 stacksize); + +/* queue a job */ +NSPR_API(PRJob *) +PR_QueueJob(PRThreadPool *tpool, PRJobFn fn, void *arg, PRBool joinable); + +/* queue a job, when a socket is readable */ +NSPR_API(PRJob *) +PR_QueueJob_Read(PRThreadPool *tpool, PRJobIoDesc *iod, + PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when a socket is writeable */ +NSPR_API(PRJob *) +PR_QueueJob_Write(PRThreadPool *tpool, PRJobIoDesc *iod, + PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when a socket has a pending connection */ +NSPR_API(PRJob *) +PR_QueueJob_Accept(PRThreadPool *tpool, PRJobIoDesc *iod, + PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when the socket connection to addr succeeds or fails */ +NSPR_API(PRJob *) +PR_QueueJob_Connect(PRThreadPool *tpool, PRJobIoDesc *iod, + const PRNetAddr *addr, PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when a timer exipres */ +NSPR_API(PRJob *) +PR_QueueJob_Timer(PRThreadPool *tpool, PRIntervalTime timeout, + PRJobFn fn, void * arg, PRBool joinable); +/* cancel a job */ +NSPR_API(PRStatus) +PR_CancelJob(PRJob *job); + +/* join a job */ +NSPR_API(PRStatus) +PR_JoinJob(PRJob *job); + +/* shutdown pool */ +NSPR_API(PRStatus) +PR_ShutdownThreadPool(PRThreadPool *tpool); + +/* join pool, wait for exit of all threads */ +NSPR_API(PRStatus) +PR_JoinThreadPool(PRThreadPool *tpool); + +PR_END_EXTERN_C + +#endif /* prtpool_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prtrace.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prtrace.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prtrace.h @@ -0,0 +1,646 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prtrace_h___ +#define prtrace_h___ +/* +** prtrace.h -- NSPR's Trace Facility. +** +** The Trace Facility provides a means to trace application +** program events within a process. When implementing an +** application program an engineer may insert a "Trace" function +** call, passing arguments to be traced. The "Trace" function +** combines the user trace data with identifying data and +** writes this data in time ordered sequence into a circular +** in-memory buffer; when the buffer fills, it wraps. +** +** Functions are provided to set and/or re-configure the size of +** the trace buffer, control what events are recorded in the +** buffer, enable and disable tracing based on specific user +** supplied data and other control functions. Methods are provided +** to record the trace entries in the in-memory trace buffer to +** a file. +** +** Tracing may cause a performance degredation to the application +** depending on the number and placement of calls to the tracing +** facility. When tracing is compiled in and all tracing is +** disabled via the runtime controls, the overhead should be +** minimal. ... Famous last words, eh? +** +** When DEBUG is defined at compile time, the Trace Facility is +** compiled as part of NSPR and any application using NSPR's +** header files will have tracing compiled in. When DEBUG is not +** defined, the Trace Facility is not compiled into NSPR nor +** exported in its header files. If the Trace Facility is +** desired in a non-debug build, then FORCE_NSPR_TRACE may be +** defined at compile time for both the optimized build of NSPR +** and the application. NSPR and any application using NSPR's +** Trace Facility must be compiled with the same level of trace +** conditioning or unresolved references may be realized at link +** time. +** +** For any of the Trace Facility methods that requires a trace +** handle as an input argument, the caller must ensure that the +** trace handle argument is valid. An invalid trace handle +** argument may cause unpredictable results. +** +** Trace Facility methods are thread-safe and SMP safe. +** +** Users of the Trace Facility should use the defined macros to +** invoke trace methods, not the function calls directly. e.g. +** PR_TRACE( h1,0,1,2, ...); not PR_Trace(h1,0,1,2, ...); +** +** Application designers should be aware of the effects of +** debug and optimized build differences when using result of the +** Trace Facility macros in expressions. +** +** See Also: prcountr.h +** +** /lth. 08-Jun-1998. +*/ + +#include "prtypes.h" +#include "prthread.h" +#include "prtime.h" + +PR_BEGIN_EXTERN_C + +/* +** Opaque type for the trace handle +** ... Don't even think about looking in here. +** +*/ +typedef void * PRTraceHandle; + +/* +** PRTraceEntry -- A trace entry in the in-memory trace buffer +** looks like this. +** +*/ +typedef struct PRTraceEntry +{ + PRThread *thread; /* The thread creating the trace entry */ + PRTraceHandle handle; /* PRTraceHandle creating the trace entry */ + PRTime time; /* Value of PR_Now() at time of trace entry */ + PRUint32 userData[8]; /* user supplied trace data */ +} PRTraceEntry; + +/* +** PRTraceOption -- command operands to +** PR_[Set|Get]TraceOption(). See descriptive meanings there. +** +*/ +typedef enum PRTraceOption +{ + PRTraceBufSize, + PRTraceEnable, + PRTraceDisable, + PRTraceSuspend, + PRTraceResume, + PRTraceSuspendRecording, + PRTraceResumeRecording, + PRTraceLockHandles, + PRTraceUnLockHandles, + PRTraceStopRecording +} PRTraceOption; + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DEFINE_TRACE() -- Define a PRTraceHandle +** +** DESCRIPTION: PR_DEFINE_TRACE() is used to define a trace +** handle. +** +*/ +#define PR_DEFINE_TRACE(name) PRTraceHandle name + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_INIT_TRACE_HANDLE() -- Set the value of a PRTraceHandle +** +** DESCRIPTION: +** PR_INIT_TRACE_HANDLE() sets the value of a PRTraceHandle +** to value. e.g. PR_INIT_TRACE_HANDLE( myHandle, NULL ); +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_INIT_TRACE_HANDLE(handle,value)\ + (handle) = (PRCounterHandle)(value) +#else +#define PR_INIT_TRACE_HANDLE(handle,value) +#endif + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_CreateTrace() -- Create a trace handle +** +** DESCRIPTION: +** PR_CreateTrace() creates a new trace handle. Tracing is +** enabled for this handle when it is created. The trace handle +** is intended for use in other Trace Facility calls. +** +** PR_CreateTrace() registers the QName, RName and description +** data so that this data can be retrieved later. +** +** INPUTS: +** qName: pointer to string. QName for this trace handle. +** +** rName: pointer to string. RName for this trace handle. +** +** description: pointer to string. Descriptive data about this +** trace handle. +** +** OUTPUTS: +** Creates the trace handle. +** Registers the QName and RName with the trace facility. +** +** RETURNS: +** PRTraceHandle +** +** RESTRICTIONS: +** qName is limited to 31 characters. +** rName is limited to 31 characters. +** description is limited to 255 characters. +** +*/ +#define PRTRACE_NAME_MAX 31 +#define PRTRACE_DESC_MAX 255 + +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_CREATE_TRACE(handle,qName,rName,description)\ + (handle) = PR_CreateTrace((qName),(rName),(description)) +#else +#define PR_CREATE_TRACE(handle,qName,rName,description) +#endif + +NSPR_API(PRTraceHandle) + PR_CreateTrace( + const char *qName, /* QName for this trace handle */ + const char *rName, /* RName for this trace handle */ + const char *description /* description for this trace handle */ +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DestroyTrace() -- Destroy a trace handle +** +** DESCRIPTION: +** PR_DestroyTrace() removes the referenced trace handle and +** associated QName, RName and description data from the Trace +** Facility. +** +** INPUTS: handle. A PRTraceHandle +** +** OUTPUTS: +** The trace handle is unregistered. +** The QName, RName and description are removed. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_DESTROY_TRACE(handle)\ + PR_DestroyTrace((handle)) +#else +#define PR_DESTROY_TRACE(handle) +#endif + +NSPR_API(void) + PR_DestroyTrace( + PRTraceHandle handle /* Handle to be destroyed */ +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_Trace() -- Make a trace entry in the in-memory trace +** +** DESCRIPTION: +** PR_Trace() makes an entry in the in-memory trace buffer for +** the referenced trace handle. The next logically available +** PRTraceEntry is used; when the next trace entry would overflow +** the trace table, the table wraps. +** +** PR_Trace() for a specific trace handle may be disabled by +** calling PR_SetTraceOption() specifying PRTraceDisable for the +** trace handle to be disabled. +** +** INPUTS: +** handle: PRTraceHandle. The trace handle for this trace. +** +** userData[0..7]: unsigned 32bit integers. user supplied data +** that is copied into the PRTraceEntry +** +** OUTPUTS: +** A PRTraceEntry is (conditionally) formatted in the in-memory +** trace buffer. +** +** RETURNS: void. +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_TRACE(handle,ud0,ud1,ud2,ud3,ud4,ud5,ud6,ud7)\ + PR_Trace((handle),(ud0),(ud1),(ud2),(ud3),(ud4),(ud5),(ud6),(ud7)) +#else +#define PR_TRACE(handle,ud0,ud1,ud2,ud3,ud4,ud5,ud6,ud7) +#endif + +NSPR_API(void) + PR_Trace( + PRTraceHandle handle, /* use this trace handle */ + PRUint32 userData0, /* User supplied data word 0 */ + PRUint32 userData1, /* User supplied data word 1 */ + PRUint32 userData2, /* User supplied data word 2 */ + PRUint32 userData3, /* User supplied data word 3 */ + PRUint32 userData4, /* User supplied data word 4 */ + PRUint32 userData5, /* User supplied data word 5 */ + PRUint32 userData6, /* User supplied data word 6 */ + PRUint32 userData7 /* User supplied data word 7 */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_SetTraceOption() -- Control the Trace Facility +** +** DESCRIPTION: +** PR_SetTraceOption() controls the Trace Facility. Depending on +** command and value, attributes of the Trace Facility may be +** changed. +** +** INPUTS: +** command: An enumerated value in the set of PRTraceOption. +** value: pointer to the data to be set. Type of the data is +** dependent on command; for each value of command, the type +** and meaning of dereferenced value is shown. +** +** PRTraceBufSize: unsigned long: the size of the trace buffer, +** in bytes. +** +** PRTraceEnable: PRTraceHandle. The trace handle to be +** enabled. +** +** PRTraceDisable: PRTraceHandle. The trace handle to be +** disabled. +** +** PRTraceSuspend: void. value must be NULL. All tracing is +** suspended. +** +** PRTraceResume: void. value must be NULL. Tracing for all +** previously enabled, prior to a PRTraceSuspend, is resumed. +** +** PRTraceStopRecording: void. value must be NULL. If recording +** (see: ** PR_RecordTraceEntries()) is being done, +** PRTraceStopRecording causes PR_RecordTraceEntries() to return +** to its caller. If recording is not being done, this function +** has no effect. +** +** PRTraceSuspendRecording: void. Must be NULL. If recording is +** being done, PRTraceSuspendRecording causes further writes to +** the trace file to be suspended. Data in the in-memory +** trace buffer that would ordinarily be written to the +** trace file will not be written. Trace entries will continue +** to be entered in the in-memory buffer. If the Trace Facility +** recording is already in a suspended state, the call has no +** effect. +** +** PRTraceResumeRecording: void. value must be NULL. If +** recording for the Trace Facility has been previously been +** suspended, this causes recording to resume. Recording resumes +** with the next in-memory buffer segment that would be written +** if trace recording had not been suspended. If recording is +** not currently suspended, the call has no effect. +** +** PRTraceLockHandles: void. value must be NULL. Locks the +** trace handle lock. While the trace handle lock is held, +** calls to PR_CreateTrace() will block until the lock is +** released. +** +** PRTraceUnlockHandles: void. value must be NULL. Unlocks the +** trace handle lock. +** +** OUTPUTS: +** The operation of the Trace Facility may be changed. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_SET_TRACE_OPTION(command,value)\ + PR_SetTraceOption((command),(value)) +#else +#define PR_SET_TRACE_OPTION(command,value) +#endif + +NSPR_API(void) + PR_SetTraceOption( + PRTraceOption command, /* One of the enumerated values */ + void *value /* command value or NULL */ +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceOption() -- Retrieve settings from the Trace Facility +** +** DESCRIPTION: +** PR_GetTraceOption() retrieves the current setting of the +** Trace Facility control depending on command. +** +** +** PRTraceBufSize: unsigned long: the size of the trace buffer, +** in bytes. +** +** +** INPUTS: +** command: one of the enumerated values in PRTraceOptions +** valid for PR_GetTraceOption(). +** +** OUTPUTS: +** dependent on command. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_OPTION(command,value)\ + PR_GetTraceOption((command),(value)) +#else +#define PR_GET_TRACE_OPTION(command,value) +#endif + +NSPR_API(void) + PR_GetTraceOption( + PRTraceOption command, /* One of the enumerated values */ + void *value /* command value or NULL */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceHandleFromName() -- Retrieve an existing +** handle by name. +** +** DESCRIPTION: +** PR_GetTraceHandleFromName() retreives an existing tracehandle +** using the name specified by qName and rName. +** +** INPUTS: +** qName: pointer to string. QName for this trace handle. +** +** rName: pointer to string. RName for this trace handle. +** +** +** OUTPUTS: returned. +** +** RETURNS: +** PRTraceHandle associated with qName and rName or NULL when +** there is no match. +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_HANDLE_FROM_NAME(handle,qName,rName)\ + (handle) = PR_GetTraceHandleFromName((qName),(rName)) +#else +#define PR_GET_TRACE_HANDLE_FROM_NAME(handle,qName,rName) +#endif + +NSPR_API(PRTraceHandle) + PR_GetTraceHandleFromName( + const char *qName, /* QName search argument */ + const char *rName /* RName search argument */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceNameFromHandle() -- Retreive trace name +** by bandle. +** +** DESCRIPTION: +** PR_GetTraceNameFromHandle() retreives the existing qName, +** rName, and description for the referenced trace handle. +** +** INPUTS: handle: PRTraceHandle. +** +** OUTPUTS: pointers to the Trace Facility's copy of qName, +** rName and description. ... Don't mess with these values. +** They're mine. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_NAME_FROM_HANDLE(handle,qName,rName,description)\ + PR_GetTraceNameFromHandle((handle),(qName),(rName),(description)) +#else +#define PR_GET_TRACE_NAME_FROM_HANDLE(handle,qName,rName,description) +#endif + +NSPR_API(void) + PR_GetTraceNameFromHandle( + PRTraceHandle handle, /* handle as search argument */ + const char **qName, /* pointer to associated QName */ + const char **rName, /* pointer to associated RName */ + const char **description /* pointer to associated description */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextTraceQname() -- Retrieive a QName handle +** iterator. +** +** DESCRIPTION: +** PR_FindNextTraceQname() retreives the first or next trace +** QName handle, depending on the value of handle, from the trace +** database. The PRTraceHandle returned can be used as an +** iterator to traverse the QName handles in the Trace database. +** +** INPUTS: +** handle: When NULL, PR_FindNextQname() returns the first QName +** handle. When a handle is a valid PRTraceHandle previously +** retreived using PR_FindNextQname() the next QName handle is +** retreived. +** +** OUTPUTS: returned. +** +** RETURNS: +** PRTraceHandle or NULL when there are no trace handles. +** +** RESTRICTIONS: +** Iterating thru the trace handles via FindFirst/FindNext +** should be done under protection of the trace handle lock. +** See: PR_SetTraceOption( PRLockTraceHandles ). +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_FIND_NEXT_TRACE_QNAME(next,handle)\ + (next) = PR_FindNextTraceQname((handle)) +#else +#define PR_FIND_NEXT_TRACE_QNAME(next,handle) +#endif + +NSPR_API(PRTraceHandle) + PR_FindNextTraceQname( + PRTraceHandle handle +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextTraceRname() -- Retrieive an RName handle +** iterator. +** +** DESCRIPTION: +** PR_FindNextTraceRname() retreives the first or next trace +** RName handle, depending on the value of handle, from the trace +** database. The PRTraceHandle returned can be used as an +** iterator to traverse the RName handles in the Trace database. +** +** INPUTS: +** rhandle: When NULL, PR_FindNextRname() returns the first +** RName handle. When a handle is a valid PRTraceHandle +** previously retreived using PR_FindNextRname() the next RName +** handle is retreived. +** qhandle: A valid PRTraceHandle retruned from a previous call +** to PR_FIND_NEXT_TRACE_QNAME(). +** +** OUTPUTS: returned. +** +** RETURNS: +** PRTraceHandle or NULL when there are no trace handles. +** +** RESTRICTIONS: +** Iterating thru the trace handles via FindNext should be done +** under protection of the trace handle lock. See: ( +** PR_SetTraceOption( PRLockTraceHandles ). +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_FIND_NEXT_TRACE_RNAME(next,rhandle,qhandle)\ + (next) = PR_FindNextTraceRname((rhandle),(qhandle)) +#else +#define PR_FIND_NEXT_TRACE_RNAME(next,rhandle,qhandle) +#endif + +NSPR_API(PRTraceHandle) + PR_FindNextTraceRname( + PRTraceHandle rhandle, + PRTraceHandle qhandle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_RecordTraceEntries() -- Write trace entries to external media +** +** DESCRIPTION: +** PR_RecordTraceEntries() causes entries in the in-memory trace +** buffer to be written to external media. +** +** When PR_RecordTraceEntries() is called from an application +** thread, the function appears to block until another thread +** calls PR_SetTraceOption() with the PRTraceStopRecording +** option. This suggests that PR_RecordTraceEntries() should be +** called from a user supplied thread whose only job is to +** record trace entries. +** +** The environment variable NSPR_TRACE_LOG controls the operation +** of this function. When NSPR_TRACE_LOG is not defined in the +** environment, no recording of trace entries occurs. When +** NSPR_TRACE_LOG is defined, the value of its definition must be +** the filename of the file to receive the trace entry buffer. +** +** PR_RecordTraceEntries() attempts to record the in-memory +** buffer to a file, subject to the setting of the environment +** variable NSPR_TRACE_LOG. It is possible because of system +** load, the thread priority of the recording thread, number of +** active trace records being written over time, and other +** variables that some trace records can be lost. ... In other +** words: don't bet the farm on getting everything. +** +** INPUTS: none +** +** OUTPUTS: none +** +** RETURNS: PR_STATUS +** PR_SUCCESS no errors were found. +** PR_FAILURE errors were found. +** +** RESTRICTIONS: +** Only one thread can call PR_RecordTraceEntries() within a +** process. +** +** On error, PR_RecordTraceEntries() may return prematurely. +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_RECORD_TRACE_ENTRIES()\ + PR_RecordTraceEntries() +#else +#define PR_RECORD_TRACE_ENTRIES() +#endif + +NSPR_API(void) + PR_RecordTraceEntries( + void +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceEntries() -- Retreive trace entries from +** the Trace Facility +** +** DESCRIPTION: +** PR_GetTraceEntries() retreives trace entries from the Trace +** Facility. Up to count trace entries are copied from the Trace +** Facility into buffer. Only those trace entries that have not +** been copied via a previous call to PR_GetTraceEntries() are +** copied. The actual number copied is placed in the PRInt32 +** variable pointed to by found. +** +** If more than count trace entries have entered the Trace +** Facility since the last call to PR_GetTraceEntries() +** a lost data condition is returned. In this case, the most +** recent count trace entries are copied into buffer and found is +** set to count. +** +** INPUTS: +** count. The number of trace entries to be copied into buffer. +** +** +** OUTPUTS: +** buffer. An array of PRTraceEntries. The buffer is supplied +** by the caller. +** +** found: 32bit signed integer. The number of PRTraceEntries +** actually copied. found is always less than or equal to count. +** +** RETURNS: +** zero when there is no lost data. +** non-zero when some PRTraceEntries have been lost. +** +** RESTRICTIONS: +** This is a real performance pig. The copy out operation is bad +** enough, but depending on then frequency of calls to the +** function, serious performance impact to the operating +** application may be realized. ... YMMV. +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_ENTRIES(buffer,count,found)\ + PR_GetTraceEntries((buffer),(count),(found)) +#else +#define PR_GET_TRACE_ENTRIES(buffer,count,found) +#endif + +NSPR_API(PRIntn) + PR_GetTraceEntries( + PRTraceEntry *buffer, /* where to write output */ + PRInt32 count, /* number to get */ + PRInt32 *found /* number you got */ +); + +PR_END_EXTERN_C + +#endif /* prtrace_h___ */ + Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prtypes.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prtypes.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prtypes.h @@ -0,0 +1,598 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: prtypes.h +** Description: Definitions of NSPR's basic types +** +** Prototypes and macros used to make up for deficiencies that we have found +** in ANSI environments. +** +** Since we do not wrap and all the other standard headers, authors +** of portable code will not know in general that they need these definitions. +** Instead of requiring these authors to find the dependent uses in their code +** and take the following steps only in those C files, we take steps once here +** for all C files. +**/ + +#ifndef prtypes_h___ +#define prtypes_h___ + +#ifdef MDCPUCFG +#include MDCPUCFG +#else +#include "prcpucfg.h" +#endif + +#include + +/*********************************************************************** +** MACROS: PR_EXTERN +** PR_IMPLEMENT +** DESCRIPTION: +** These are only for externally visible routines and globals. For +** internal routines, just use "extern" for type checking and that +** will not export internal cross-file or forward-declared symbols. +** Define a macro for declaring procedures return types. We use this to +** deal with windoze specific type hackery for DLL definitions. Use +** PR_EXTERN when the prototype for the method is declared. Use +** PR_IMPLEMENT for the implementation of the method. +** +** Example: +** in dowhim.h +** PR_EXTERN( void ) DoWhatIMean( void ); +** in dowhim.c +** PR_IMPLEMENT( void ) DoWhatIMean( void ) { return; } +** +** +***********************************************************************/ +#if defined(WIN32) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_BEOS) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) extern __declspec(dllexport) __type +#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_OS2) && defined(__declspec) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) extern __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) extern __declspec(dllimport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(SYMBIAN) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#ifdef __WINS__ +#define PR_IMPORT(__type) extern __declspec(dllexport) __type +#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type +#else +#define PR_IMPORT(__type) extern __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) extern __declspec(dllimport) __type +#endif + +#define PR_EXTERN(__type) extern __type +#define PR_IMPLEMENT(__type) __type +#define PR_EXTERN_DATA(__type) extern __type +#define PR_IMPLEMENT_DATA(__type) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#else /* Unix */ + +/* GCC 3.3 and later support the visibility attribute. */ +#if (__GNUC__ >= 4) || \ + (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) +#define PR_VISIBILITY_DEFAULT __attribute__((visibility("default"))) +#else +#define PR_VISIBILITY_DEFAULT +#endif + +#define PR_EXPORT(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_EXPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPORT(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type + +#define PR_EXTERN(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPLEMENT(__type) PR_VISIBILITY_DEFAULT __type +#define PR_EXTERN_DATA(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPLEMENT_DATA(__type) PR_VISIBILITY_DEFAULT __type +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#endif + +#if defined(_NSPR_BUILD_) +#define NSPR_API(__type) PR_EXPORT(__type) +#define NSPR_DATA_API(__type) PR_EXPORT_DATA(__type) +#else +#define NSPR_API(__type) PR_IMPORT(__type) +#define NSPR_DATA_API(__type) PR_IMPORT_DATA(__type) +#endif + +/*********************************************************************** +** MACROS: PR_BEGIN_MACRO +** PR_END_MACRO +** DESCRIPTION: +** Macro body brackets so that macros with compound statement definitions +** behave syntactically more like functions when called. +***********************************************************************/ +#define PR_BEGIN_MACRO do { +#define PR_END_MACRO } while (0) + +/*********************************************************************** +** MACROS: PR_BEGIN_EXTERN_C +** PR_END_EXTERN_C +** DESCRIPTION: +** Macro shorthands for conditional C++ extern block delimiters. +***********************************************************************/ +#ifdef __cplusplus +#define PR_BEGIN_EXTERN_C extern "C" { +#define PR_END_EXTERN_C } +#else +#define PR_BEGIN_EXTERN_C +#define PR_END_EXTERN_C +#endif + +/*********************************************************************** +** MACROS: PR_BIT +** PR_BITMASK +** DESCRIPTION: +** Bit masking macros. XXX n must be <= 31 to be portable +***********************************************************************/ +#define PR_BIT(n) ((PRUint32)1 << (n)) +#define PR_BITMASK(n) (PR_BIT(n) - 1) + +/*********************************************************************** +** MACROS: PR_ROUNDUP +** PR_MIN +** PR_MAX +** PR_ABS +** DESCRIPTION: +** Commonly used macros for operations on compatible types. +***********************************************************************/ +#define PR_ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y)) +#define PR_MIN(x,y) ((x)<(y)?(x):(y)) +#define PR_MAX(x,y) ((x)>(y)?(x):(y)) +#define PR_ABS(x) ((x)<0?-(x):(x)) + +/*********************************************************************** +** MACROS: PR_ARRAY_SIZE +** DESCRIPTION: +** The number of elements in an array. +***********************************************************************/ +#define PR_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) + +PR_BEGIN_EXTERN_C + +/* +** Starting in NSPR 4.9.5, NSPR's exact-width integer types should match +** the exact-width integer types defined in . This allows sloppy +** code to use PRInt{N} and int{N}_t interchangeably. +** +** The 8-bit and 16-bit integer types can only be defined using char and +** short. All platforms define the 32-bit integer types using int. So only +** the 64-bit integer types could be defined differently. +** +** NSPR's original strategy was to use the "shortest" 64-bit integer type: +** if long is 64-bit, then prefer it over long long. This strategy is also +** used by Linux/glibc, FreeBSD, and NetBSD. +** +** Other platforms use a different strategy: simply define the 64-bit +** integer types using long long. We define the PR_ALTERNATE_INT64_TYPEDEF +** macro on these platforms. Note that PR_ALTERNATE_INT64_TYPEDEF is for +** internal use by NSPR headers only. Do not define or test this macro in +** your code. +** +** NOTE: NSPR can't use because C99 requires C++ code to define +** __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS to make all the macros +** defined in available. This strange requirement is gone in +** C11. When most platforms ignore this C99 requirement, NSPR will be able +** to use . A patch to do that is in NSPR bug 634793. +*/ + +#if defined(__APPLE__) || defined(__OpenBSD__) +#define PR_ALTERNATE_INT64_TYPEDEF +#endif + +/************************************************************************ +** TYPES: PRUint8 +** PRInt8 +** DESCRIPTION: +** The int8 types are known to be 8 bits each. There is no type that +** is equivalent to a plain "char". +************************************************************************/ +#if PR_BYTES_PER_BYTE == 1 +typedef unsigned char PRUint8; +/* +** There are two scenarios that require us to define PRInt8 as type 'char'. +** (1) +** Some cfront-based C++ compilers do not like 'signed char' and +** issue the warning message: +** warning: "signed" not implemented (ignored) +** For these compilers, we have to define PRInt8 as plain 'char'. +** Make sure that plain 'char' is indeed signed under these compilers. +** (2) +** Mozilla C++ code expects the PRInt{N} and int{N}_t types to match (see bug +** 634793). If a platform defines int8_t as 'char', but NSPR defines it as +** 'signed char', it results in a type mismatch. +** On such platforms we define PRInt8 as 'char' to avoid the mismatch. +*/ +#if (defined(HPUX) && defined(__cplusplus) /* reason 1*/ \ + && !defined(__GNUC__) && __cplusplus < 199707L) \ + || (defined(SCO) && defined(__cplusplus) /* reason 1 */ \ + && !defined(__GNUC__) && __cplusplus == 1L) \ + || (defined(__sun) && defined(__cplusplus)) /* reason 2 */ +typedef char PRInt8; +#else +typedef signed char PRInt8; +#endif +#else +#error No suitable type for PRInt8/PRUint8 +#endif + +/************************************************************************ + * MACROS: PR_INT8_MAX + * PR_INT8_MIN + * PR_UINT8_MAX + * DESCRIPTION: + * The maximum and minimum values of a PRInt8 or PRUint8. +************************************************************************/ + +#define PR_INT8_MAX 127 +#define PR_INT8_MIN (-128) +#define PR_UINT8_MAX 255U + +/************************************************************************ +** TYPES: PRUint16 +** PRInt16 +** DESCRIPTION: +** The int16 types are known to be 16 bits each. +************************************************************************/ +#if PR_BYTES_PER_SHORT == 2 +typedef unsigned short PRUint16; +typedef short PRInt16; +#else +#error No suitable type for PRInt16/PRUint16 +#endif + +/************************************************************************ + * MACROS: PR_INT16_MAX + * PR_INT16_MIN + * PR_UINT16_MAX + * DESCRIPTION: + * The maximum and minimum values of a PRInt16 or PRUint16. +************************************************************************/ + +#define PR_INT16_MAX 32767 +#define PR_INT16_MIN (-32768) +#define PR_UINT16_MAX 65535U + +/************************************************************************ +** TYPES: PRUint32 +** PRInt32 +** DESCRIPTION: +** The int32 types are known to be 32 bits each. +************************************************************************/ +#if PR_BYTES_PER_INT == 4 +typedef unsigned int PRUint32; +typedef int PRInt32; +#define PR_INT32(x) x +#define PR_UINT32(x) x ## U +#elif PR_BYTES_PER_LONG == 4 +typedef unsigned long PRUint32; +typedef long PRInt32; +#define PR_INT32(x) x ## L +#define PR_UINT32(x) x ## UL +#else +#error No suitable type for PRInt32/PRUint32 +#endif + +/************************************************************************ + * MACROS: PR_INT32_MAX + * PR_INT32_MIN + * PR_UINT32_MAX + * DESCRIPTION: + * The maximum and minimum values of a PRInt32 or PRUint32. +************************************************************************/ + +#define PR_INT32_MAX PR_INT32(2147483647) +#define PR_INT32_MIN (-PR_INT32_MAX - 1) +#define PR_UINT32_MAX PR_UINT32(4294967295) + +/************************************************************************ +** TYPES: PRUint64 +** PRInt64 +** DESCRIPTION: +** The int64 types are known to be 64 bits each. Care must be used when +** declaring variables of type PRUint64 or PRInt64. Different hardware +** architectures and even different compilers have varying support for +** 64 bit values. The only guaranteed portability requires the use of +** the LL_ macros (see prlong.h). +** +** MACROS: PR_INT64 +** PR_UINT64 +** DESCRIPTION: +** The PR_INT64 and PR_UINT64 macros provide a portable way for +** specifying 64-bit integer constants. They can only be used if +** PRInt64 and PRUint64 are defined as compiler-supported 64-bit +** integer types (i.e., if HAVE_LONG_LONG is defined, which is true +** for all the supported compilers topday). If PRInt64 and PRUint64 +** are defined as structs, the LL_INIT macro defined in prlong.h has +** to be used. +** +** MACROS: PR_INT64_MAX +** PR_INT64_MIN +** PR_UINT64_MAX +** DESCRIPTION: +** The maximum and minimum values of a PRInt64 or PRUint64. +************************************************************************/ +#ifdef HAVE_LONG_LONG +/* Keep this in sync with prlong.h. */ +#if PR_BYTES_PER_LONG == 8 && !defined(PR_ALTERNATE_INT64_TYPEDEF) +typedef long PRInt64; +typedef unsigned long PRUint64; +#define PR_INT64(x) x ## L +#define PR_UINT64(x) x ## UL +#elif defined(WIN32) && !defined(__GNUC__) +typedef __int64 PRInt64; +typedef unsigned __int64 PRUint64; +#define PR_INT64(x) x ## i64 +#define PR_UINT64(x) x ## ui64 +#else +typedef long long PRInt64; +typedef unsigned long long PRUint64; +#define PR_INT64(x) x ## LL +#define PR_UINT64(x) x ## ULL +#endif /* PR_BYTES_PER_LONG == 8 */ + +#define PR_INT64_MAX PR_INT64(0x7fffffffffffffff) +#define PR_INT64_MIN (-PR_INT64_MAX - 1) +#define PR_UINT64_MAX PR_UINT64(-1) +#else /* !HAVE_LONG_LONG */ +typedef struct { +#ifdef IS_LITTLE_ENDIAN + PRUint32 lo, hi; +#else + PRUint32 hi, lo; +#endif +} PRInt64; +typedef PRInt64 PRUint64; + +#define PR_INT64_MAX (PRInt64){0x7fffffff, 0xffffffff} +#define PR_INT64_MIN (PRInt64){0xffffffff, 0xffffffff} +#define PR_UINT64_MAX (PRUint64){0xffffffff, 0xffffffff} + +#endif /* !HAVE_LONG_LONG */ + +/************************************************************************ +** TYPES: PRUintn +** PRIntn +** DESCRIPTION: +** The PRIntn types are most appropriate for automatic variables. They are +** guaranteed to be at least 16 bits, though various architectures may +** define them to be wider (e.g., 32 or even 64 bits). These types are +** never valid for fields of a structure. +************************************************************************/ +#if PR_BYTES_PER_INT >= 2 +typedef int PRIntn; +typedef unsigned int PRUintn; +#else +#error 'sizeof(int)' not sufficient for platform use +#endif + +/************************************************************************ +** TYPES: PRFloat64 +** DESCRIPTION: +** NSPR's floating point type is always 64 bits. +************************************************************************/ +typedef double PRFloat64; + +/************************************************************************ +** TYPES: PRSize +** DESCRIPTION: +** A type for representing the size of objects. +************************************************************************/ +typedef size_t PRSize; + + +/************************************************************************ +** TYPES: PROffset32, PROffset64 +** DESCRIPTION: +** A type for representing byte offsets from some location. +************************************************************************/ +typedef PRInt32 PROffset32; +typedef PRInt64 PROffset64; + +/************************************************************************ +** TYPES: PRPtrDiff +** DESCRIPTION: +** A type for pointer difference. Variables of this type are suitable +** for storing a pointer or pointer subtraction. +************************************************************************/ +typedef ptrdiff_t PRPtrdiff; + +/************************************************************************ +** TYPES: PRUptrdiff +** DESCRIPTION: +** A type for pointer difference. Variables of this type are suitable +** for storing a pointer or pointer sutraction. +************************************************************************/ +#ifdef _WIN64 +typedef PRUint64 PRUptrdiff; +#else +typedef unsigned long PRUptrdiff; +#endif + +/************************************************************************ +** TYPES: PRBool +** DESCRIPTION: +** Use PRBool for variables and parameter types. Use PR_FALSE and PR_TRUE +** for clarity of target type in assignments and actual arguments. Use +** 'if (bool)', 'while (!bool)', '(bool) ? x : y' etc., to test booleans +** just as you would C int-valued conditions. +************************************************************************/ +typedef PRIntn PRBool; +#define PR_TRUE 1 +#define PR_FALSE 0 + +/************************************************************************ +** TYPES: PRPackedBool +** DESCRIPTION: +** Use PRPackedBool within structs where bitfields are not desirable +** but minimum and consistant overhead matters. +************************************************************************/ +typedef PRUint8 PRPackedBool; + +/* +** Status code used by some routines that have a single point of failure or +** special status return. +*/ +typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus; + +#ifndef __PRUNICHAR__ +#define __PRUNICHAR__ +#ifdef WIN32 +typedef wchar_t PRUnichar; +#else +typedef PRUint16 PRUnichar; +#endif +#endif + +/* +** WARNING: The undocumented data types PRWord and PRUword are +** only used in the garbage collection and arena code. Do not +** use PRWord and PRUword in new code. +** +** A PRWord is an integer that is the same size as a void*. +** It implements the notion of a "word" in the Java Virtual +** Machine. (See Sec. 3.4 "Words", The Java Virtual Machine +** Specification, Addison-Wesley, September 1996. +** http://java.sun.com/docs/books/vmspec/index.html.) +*/ +#ifdef _WIN64 +typedef PRInt64 PRWord; +typedef PRUint64 PRUword; +#else +typedef long PRWord; +typedef unsigned long PRUword; +#endif + +/* + * PR_PRETEND_NORETURN, specified at the end of a function declaration, + * indicates that for the purposes of static analysis, this function does not + * return. (The function definition does not need to be annotated.) + * + * void PR_Assert(const char *s, const char *file, PRIntn ln) + * PR_PRETEND_NORETURN; + * + * Some static analyzers, like scan-build from clang, can use this information + * to eliminate false positives. From the upstream documentation of + * scan-build: + * This attribute is useful for annotating assertion handlers that actually + * can return, but for the purpose of using the analyzer we want to pretend + * that such functions do not return. + */ +#ifdef __clang_analyzer__ +#if __has_extension(attribute_analyzer_noreturn) +#define PR_PRETEND_NORETURN __attribute__((analyzer_noreturn)) +#endif +#endif + +#ifndef PR_PRETEND_NORETURN +#define PR_PRETEND_NORETURN /* no support */ +#endif + +#if defined(NO_NSPR_10_SUPPORT) +#else +/********* ???????????????? FIX ME ??????????????????????????? *****/ +/********************** Some old definitions until pr=>ds transition is done ***/ +/********************** Also, we are still using NSPR 1.0. GC ******************/ +/* +** Fundamental NSPR macros, used nearly everywhere. +*/ + +#define PR_PUBLIC_API PR_IMPLEMENT + +/* +** Macro body brackets so that macros with compound statement definitions +** behave syntactically more like functions when called. +*/ +#define NSPR_BEGIN_MACRO do { +#define NSPR_END_MACRO } while (0) + +/* +** Macro shorthands for conditional C++ extern block delimiters. +*/ +#ifdef NSPR_BEGIN_EXTERN_C +#undef NSPR_BEGIN_EXTERN_C +#endif +#ifdef NSPR_END_EXTERN_C +#undef NSPR_END_EXTERN_C +#endif + +#ifdef __cplusplus +#define NSPR_BEGIN_EXTERN_C extern "C" { +#define NSPR_END_EXTERN_C } +#else +#define NSPR_BEGIN_EXTERN_C +#define NSPR_END_EXTERN_C +#endif + +#include "obsolete/protypes.h" + +/********* ????????????? End Fix me ?????????????????????????????? *****/ +#endif /* NO_NSPR_10_SUPPORT */ + +/* +** Compile-time assert. "condition" must be a constant expression. +** The macro can be used only in places where an "extern" declaration is +** allowed. +*/ +#define PR_STATIC_ASSERT(condition) \ + extern void pr_static_assert(int arg[(condition) ? 1 : -1]) + +PR_END_EXTERN_C + +#endif /* prtypes_h___ */ + Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prvrsion.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prvrsion.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prvrsion.h @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + + +/* author: jstewart */ + +#if defined(_PRVERSION_H) +#else +#define _PRVERSION_H + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* All components participating in the PR version protocol must expose + * a structure and a function. The structure is defined below and named + * according to the naming conventions outlined further below. The function + * is called libVersionPoint and returns a pointer to this structure. + */ + +/* on NT, always pack the structure the same. */ +#ifdef _WIN32 +#pragma pack(push, 8) +#endif + +typedef struct { + /* + * The first field defines which version of this structure is in use. + * At this time, only version 2 is specified. If this value is not + * 2, you must read no further into the structure. + */ + PRInt32 version; + + /* for Version 2, this is the body format. */ + PRInt64 buildTime; /* 64 bits - usecs since midnight, 1/1/1970 */ + char * buildTimeString;/* a human readable version of the time */ + + PRUint8 vMajor; /* Major version of this component */ + PRUint8 vMinor; /* Minor version of this component */ + PRUint8 vPatch; /* Patch level of this component */ + + PRBool beta; /* true if this is a beta component */ + PRBool debug; /* true if this is a debug component */ + PRBool special; /* true if this component is a special build */ + + char * filename; /* The original filename */ + char * description; /* description of this component */ + char * security; /* level of security in this component */ + char * copyright; /* The copyright for this file */ + char * comment; /* free form field for misc usage */ + char * specialString; /* the special variant for this build */ +} PRVersionDescription; + +/* on NT, restore the previous packing */ +#ifdef _WIN32 +#pragma pack(pop) +#endif + +/* + * All components must define an entrypoint named libVersionPoint which + * is of type versionEntryPointType. + * + * For example, for a library named libfoo, we would have: + * + * PRVersionDescription prVersionDescription_libfoo = + * { + * ... + * }; + * + * PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint(void) + * { + * return &prVersionDescription_libfoo; + * } + */ +typedef const PRVersionDescription *(*versionEntryPointType)(void); + +/* + * Where you declare your libVersionPoint, do it like this: + * PR_IMPLEMENT(const PRVersionDescription *) libVersionPoint(void) { + * fill it in... + * } + */ + +/* + * NAMING CONVENTION FOR struct + * + * all components should also expose a static PRVersionDescription + * The name of the struct should be calculated as follows: + * Take the value of filename. (If filename is not specified, calculate + * a short, unique string.) Convert all non-alphanumeric characters + * to '_'. To this, prepend "PRVersionDescription_". Thus for libfoo.so, + * the symbol name is "PRVersionDescription_libfoo_so". + * so the file should have + * PRVersionDescription PRVersionDescription_libfoo_so { fill it in }; + * on NT, this file should be declspec export. + */ + +PR_END_EXTERN_C + +#endif /* defined(_PRVERSION_H) */ + +/* prvrsion.h */ + Index: ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prwin16.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prwin16.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-debug/nspr/prwin16.h @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prwin16_h___ +#define prwin16_h___ + +/* +** Condition use of this header on platform. +*/ +#if (defined(XP_PC) && !defined(_WIN32) && !defined(XP_OS2) && defined(MOZILLA_CLIENT)) || defined(WIN16) +#include + +PR_BEGIN_EXTERN_C +/* +** Win16 stdio special case. +** To get stdio to work for Win16, all calls to printf() and related +** things must be called from the environment of the .EXE; calls to +** printf() from the .DLL send output to the bit-bucket. +** +** To make sure that PR_fprintf(), and related functions, work correctly, +** the actual stream I/O to stdout, stderr, stdin must be done in the +** .EXE. To do this, a hack is placed in _MD_Write() such that the +** fd for stdio handles results in a call to the .EXE. +** +** file w16stdio.c contains the functions that get called from NSPR +** to do the actual I/O. w16stdio.o must be statically linked with +** any application needing stdio for Win16. +** +** The address of these functions must be made available to the .DLL +** so he can call back to the .EXE. To do this, function +** PR_MD_RegisterW16StdioCallbacks() is called from the .EXE. +** The arguments are the functions defined in w16stdio.c +** At runtime, MD_Write() calls the registered functions, if any +** were registered. +** +** prinit.h contains a macro PR_STDIO_INIT() that calls the registration +** function for Win16; For other platforms, the macro is a No-Op. +** +** Note that stdio is not operational at all on Win16 GUI applications. +** This special case exists to provide stdio capability from the NSPR +** .DLL for command line applications only. NSPR's test cases are +** almost exclusively command line applications. +** +** See also: w16io.c, w16stdio.c +*/ +typedef PRInt32 (PR_CALLBACK *PRStdinRead)( void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRStdoutWrite)( void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRStderrWrite)( void *buf, PRInt32 amount); + +NSPR_API(PRStatus) +PR_MD_RegisterW16StdioCallbacks( + PRStdinRead inReadf, /* i: function pointer for stdin read */ + PRStdoutWrite outWritef, /* i: function pointer for stdout write */ + PRStderrWrite errWritef /* i: function pointer for stderr write */ + ); + +NSPR_API(PRInt32) +_PL_W16StdioWrite( void *buf, PRInt32 amount ); + +NSPR_API(PRInt32) +_PL_W16StdioRead( void *buf, PRInt32 amount ); + +#define PR_STDIO_INIT() PR_MD_RegisterW16StdioCallbacks( \ + _PL_W16StdioRead, _PL_W16StdioWrite, _PL_W16StdioWrite ); \ + PR_INIT_CALLBACKS(); + +/* +** Win16 hackery. +** +*/ +struct PRMethodCallbackStr { + int (PR_CALLBACK *auxOutput)(const char *outputString); + size_t (PR_CALLBACK *strftime)(char *s, size_t len, const char *fmt, const struct tm *p); + void * (PR_CALLBACK *malloc)( size_t size ); + void * (PR_CALLBACK *calloc)(size_t n, size_t size ); + void * (PR_CALLBACK *realloc)( void* old_blk, size_t size ); + void (PR_CALLBACK *free)( void *ptr ); + void * (PR_CALLBACK *getenv)( const char *name); + int (PR_CALLBACK *putenv)( const char *assoc); +/* void * (PR_CALLBACK *perror)( const char *prefix ); */ +}; + +NSPR_API(void) PR_MDRegisterCallbacks(struct PRMethodCallbackStr *); + +int PR_CALLBACK _PL_W16CallBackPuts( const char *outputString ); +size_t PR_CALLBACK _PL_W16CallBackStrftime( + char *s, + size_t len, + const char *fmt, + const struct tm *p ); +void * PR_CALLBACK _PL_W16CallBackMalloc( size_t size ); +void * PR_CALLBACK _PL_W16CallBackCalloc( size_t n, size_t size ); +void * PR_CALLBACK _PL_W16CallBackRealloc( + void *old_blk, + size_t size ); +void PR_CALLBACK _PL_W16CallBackFree( void *ptr ); +void * PR_CALLBACK _PL_W16CallBackGetenv( const char *name ); +int PR_CALLBACK _PL_W16CallBackPutenv( const char *assoc ); + +/* +** Hackery! +** +** These functions are provided as static link points. +** This is to satisfy the quick port of Gromit to NSPR 2.0 +** ... Don't do this! ... alas, It may never go away. +** +*/ +NSPR_API(int) PR_MD_printf(const char *, ...); +NSPR_API(void) PR_MD_exit(int); +NSPR_API(size_t) PR_MD_strftime(char *, size_t, const char *, const struct tm *); +NSPR_API(int) PR_MD_sscanf(const char *, const char *, ...); +NSPR_API(void*) PR_MD_malloc( size_t size ); +NSPR_API(void*) PR_MD_calloc( size_t n, size_t size ); +NSPR_API(void*) PR_MD_realloc( void* old_blk, size_t size ); +NSPR_API(void) PR_MD_free( void *ptr ); +NSPR_API(char*) PR_MD_getenv( const char *name ); +NSPR_API(int) PR_MD_putenv( const char *assoc ); +NSPR_API(int) PR_MD_fprintf(FILE *fPtr, const char *fmt, ...); + +#define PR_INIT_CALLBACKS() \ + { \ + static struct PRMethodCallbackStr cbf = { \ + _PL_W16CallBackPuts, \ + _PL_W16CallBackStrftime, \ + _PL_W16CallBackMalloc, \ + _PL_W16CallBackCalloc, \ + _PL_W16CallBackRealloc, \ + _PL_W16CallBackFree, \ + _PL_W16CallBackGetenv, \ + _PL_W16CallBackPutenv, \ + }; \ + PR_MDRegisterCallbacks( &cbf ); \ + } + + +/* +** Get the exception context for Win16 MFC applications threads +*/ +NSPR_API(void *) PR_W16GetExceptionContext(void); +/* +** Set the exception context for Win16 MFC applications threads +*/ +NSPR_API(void) PR_W16SetExceptionContext(void *context); + +PR_END_EXTERN_C +#else +/* +** For platforms other than Win16, define +** PR_STDIO_INIT() as a No-Op. +*/ +#define PR_STDIO_INIT() +#endif /* WIN16 || MOZILLA_CLIENT */ + +#endif /* prwin16_h___ */ + + + + + + + + Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/double-conversion/double-conversion.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/double-conversion/double-conversion.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/double-conversion/double-conversion.h @@ -0,0 +1,548 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ +#define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ + +#include "mozilla/Types.h" +#include + +namespace double_conversion { + +class DoubleToStringConverter { + public: + // When calling ToFixed with a double > 10^kMaxFixedDigitsBeforePoint + // or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the + // function returns false. + static const int kMaxFixedDigitsBeforePoint = 60; + static const int kMaxFixedDigitsAfterPoint = 60; + + // When calling ToExponential with a requested_digits + // parameter > kMaxExponentialDigits then the function returns false. + static const int kMaxExponentialDigits = 120; + + // When calling ToPrecision with a requested_digits + // parameter < kMinPrecisionDigits or requested_digits > kMaxPrecisionDigits + // then the function returns false. + static const int kMinPrecisionDigits = 1; + static const int kMaxPrecisionDigits = 120; + + enum Flags { + NO_FLAGS = 0, + EMIT_POSITIVE_EXPONENT_SIGN = 1, + EMIT_TRAILING_DECIMAL_POINT = 2, + EMIT_TRAILING_ZERO_AFTER_POINT = 4, + UNIQUE_ZERO = 8 + }; + + // Flags should be a bit-or combination of the possible Flags-enum. + // - NO_FLAGS: no special flags. + // - EMIT_POSITIVE_EXPONENT_SIGN: when the number is converted into exponent + // form, emits a '+' for positive exponents. Example: 1.2e+2. + // - EMIT_TRAILING_DECIMAL_POINT: when the input number is an integer and is + // converted into decimal format then a trailing decimal point is appended. + // Example: 2345.0 is converted to "2345.". + // - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point + // emits a trailing '0'-character. This flag requires the + // EXMIT_TRAILING_DECIMAL_POINT flag. + // Example: 2345.0 is converted to "2345.0". + // - UNIQUE_ZERO: "-0.0" is converted to "0.0". + // + // Infinity symbol and nan_symbol provide the string representation for these + // special values. If the string is NULL and the special value is encountered + // then the conversion functions return false. + // + // The exponent_character is used in exponential representations. It is + // usually 'e' or 'E'. + // + // When converting to the shortest representation the converter will + // represent input numbers in decimal format if they are in the interval + // [10^decimal_in_shortest_low; 10^decimal_in_shortest_high[ + // (lower boundary included, greater boundary excluded). + // Example: with decimal_in_shortest_low = -6 and + // decimal_in_shortest_high = 21: + // ToShortest(0.000001) -> "0.000001" + // ToShortest(0.0000001) -> "1e-7" + // ToShortest(111111111111111111111.0) -> "111111111111111110000" + // ToShortest(100000000000000000000.0) -> "100000000000000000000" + // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21" + // + // When converting to precision mode the converter may add + // max_leading_padding_zeroes before returning the number in exponential + // format. + // Example with max_leading_padding_zeroes_in_precision_mode = 6. + // ToPrecision(0.0000012345, 2) -> "0.0000012" + // ToPrecision(0.00000012345, 2) -> "1.2e-7" + // Similarily the converter may add up to + // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid + // returning an exponential representation. A zero added by the + // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit. + // Examples for max_trailing_padding_zeroes_in_precision_mode = 1: + // ToPrecision(230.0, 2) -> "230" + // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT. + // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT. + DoubleToStringConverter(int flags, + const char* infinity_symbol, + const char* nan_symbol, + char exponent_character, + int decimal_in_shortest_low, + int decimal_in_shortest_high, + int max_leading_padding_zeroes_in_precision_mode, + int max_trailing_padding_zeroes_in_precision_mode) + : flags_(flags), + infinity_symbol_(infinity_symbol), + nan_symbol_(nan_symbol), + exponent_character_(exponent_character), + decimal_in_shortest_low_(decimal_in_shortest_low), + decimal_in_shortest_high_(decimal_in_shortest_high), + max_leading_padding_zeroes_in_precision_mode_( + max_leading_padding_zeroes_in_precision_mode), + max_trailing_padding_zeroes_in_precision_mode_( + max_trailing_padding_zeroes_in_precision_mode) { + // When 'trailing zero after the point' is set, then 'trailing point' + // must be set too. + ASSERT(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) || + !((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0)); + } + + // Returns a converter following the EcmaScript specification. + static MFBT_API const DoubleToStringConverter& EcmaScriptConverter(); + + // Computes the shortest string of digits that correctly represent the input + // number. Depending on decimal_in_shortest_low and decimal_in_shortest_high + // (see constructor) it then either returns a decimal representation, or an + // exponential representation. + // Example with decimal_in_shortest_low = -6, + // decimal_in_shortest_high = 21, + // EMIT_POSITIVE_EXPONENT_SIGN activated, and + // EMIT_TRAILING_DECIMAL_POINT deactived: + // ToShortest(0.000001) -> "0.000001" + // ToShortest(0.0000001) -> "1e-7" + // ToShortest(111111111111111111111.0) -> "111111111111111110000" + // ToShortest(100000000000000000000.0) -> "100000000000000000000" + // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21" + // + // Note: the conversion may round the output if the returned string + // is accurate enough to uniquely identify the input-number. + // For example the most precise representation of the double 9e59 equals + // "899999999999999918767229449717619953810131273674690656206848", but + // the converter will return the shorter (but still correct) "9e59". + // + // Returns true if the conversion succeeds. The conversion always succeeds + // except when the input value is special and no infinity_symbol or + // nan_symbol has been given to the constructor. + bool ToShortest(double value, StringBuilder* result_builder) const { + return ToShortestIeeeNumber(value, result_builder, SHORTEST); + } + + // Same as ToShortest, but for single-precision floats. + bool ToShortestSingle(float value, StringBuilder* result_builder) const { + return ToShortestIeeeNumber(value, result_builder, SHORTEST_SINGLE); + } + + + // Computes a decimal representation with a fixed number of digits after the + // decimal point. The last emitted digit is rounded. + // + // Examples: + // ToFixed(3.12, 1) -> "3.1" + // ToFixed(3.1415, 3) -> "3.142" + // ToFixed(1234.56789, 4) -> "1234.5679" + // ToFixed(1.23, 5) -> "1.23000" + // ToFixed(0.1, 4) -> "0.1000" + // ToFixed(1e30, 2) -> "1000000000000000019884624838656.00" + // ToFixed(0.1, 30) -> "0.100000000000000005551115123126" + // ToFixed(0.1, 17) -> "0.10000000000000001" + // + // If requested_digits equals 0, then the tail of the result depends on + // the EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT. + // Examples, for requested_digits == 0, + // let EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT be + // - false and false: then 123.45 -> 123 + // 0.678 -> 1 + // - true and false: then 123.45 -> 123. + // 0.678 -> 1. + // - true and true: then 123.45 -> 123.0 + // 0.678 -> 1.0 + // + // Returns true if the conversion succeeds. The conversion always succeeds + // except for the following cases: + // - the input value is special and no infinity_symbol or nan_symbol has + // been provided to the constructor, + // - 'value' > 10^kMaxFixedDigitsBeforePoint, or + // - 'requested_digits' > kMaxFixedDigitsAfterPoint. + // The last two conditions imply that the result will never contain more than + // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters + // (one additional character for the sign, and one for the decimal point). + MFBT_API bool ToFixed(double value, + int requested_digits, + StringBuilder* result_builder) const; + + // Computes a representation in exponential format with requested_digits + // after the decimal point. The last emitted digit is rounded. + // If requested_digits equals -1, then the shortest exponential representation + // is computed. + // + // Examples with EMIT_POSITIVE_EXPONENT_SIGN deactivated, and + // exponent_character set to 'e'. + // ToExponential(3.12, 1) -> "3.1e0" + // ToExponential(5.0, 3) -> "5.000e0" + // ToExponential(0.001, 2) -> "1.00e-3" + // ToExponential(3.1415, -1) -> "3.1415e0" + // ToExponential(3.1415, 4) -> "3.1415e0" + // ToExponential(3.1415, 3) -> "3.142e0" + // ToExponential(123456789000000, 3) -> "1.235e14" + // ToExponential(1000000000000000019884624838656.0, -1) -> "1e30" + // ToExponential(1000000000000000019884624838656.0, 32) -> + // "1.00000000000000001988462483865600e30" + // ToExponential(1234, 0) -> "1e3" + // + // Returns true if the conversion succeeds. The conversion always succeeds + // except for the following cases: + // - the input value is special and no infinity_symbol or nan_symbol has + // been provided to the constructor, + // - 'requested_digits' > kMaxExponentialDigits. + // The last condition implies that the result will never contain more than + // kMaxExponentialDigits + 8 characters (the sign, the digit before the + // decimal point, the decimal point, the exponent character, the + // exponent's sign, and at most 3 exponent digits). + MFBT_API bool ToExponential(double value, + int requested_digits, + StringBuilder* result_builder) const; + + // Computes 'precision' leading digits of the given 'value' and returns them + // either in exponential or decimal format, depending on + // max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the + // constructor). + // The last computed digit is rounded. + // + // Example with max_leading_padding_zeroes_in_precision_mode = 6. + // ToPrecision(0.0000012345, 2) -> "0.0000012" + // ToPrecision(0.00000012345, 2) -> "1.2e-7" + // Similarily the converter may add up to + // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid + // returning an exponential representation. A zero added by the + // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit. + // Examples for max_trailing_padding_zeroes_in_precision_mode = 1: + // ToPrecision(230.0, 2) -> "230" + // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT. + // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT. + // Examples for max_trailing_padding_zeroes_in_precision_mode = 3, and no + // EMIT_TRAILING_ZERO_AFTER_POINT: + // ToPrecision(123450.0, 6) -> "123450" + // ToPrecision(123450.0, 5) -> "123450" + // ToPrecision(123450.0, 4) -> "123500" + // ToPrecision(123450.0, 3) -> "123000" + // ToPrecision(123450.0, 2) -> "1.2e5" + // + // Returns true if the conversion succeeds. The conversion always succeeds + // except for the following cases: + // - the input value is special and no infinity_symbol or nan_symbol has + // been provided to the constructor, + // - precision < kMinPericisionDigits + // - precision > kMaxPrecisionDigits + // The last condition implies that the result will never contain more than + // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the + // exponent character, the exponent's sign, and at most 3 exponent digits). + MFBT_API bool ToPrecision(double value, + int precision, + bool* used_exponential_notation, + StringBuilder* result_builder) const; + + enum DtoaMode { + // Produce the shortest correct representation. + // For example the output of 0.299999999999999988897 is (the less accurate + // but correct) 0.3. + SHORTEST, + // Same as SHORTEST, but for single-precision floats. + SHORTEST_SINGLE, + // Produce a fixed number of digits after the decimal point. + // For instance fixed(0.1, 4) becomes 0.1000 + // If the input number is big, the output will be big. + FIXED, + // Fixed number of digits (independent of the decimal point). + PRECISION + }; + + // The maximal number of digits that are needed to emit a double in base 10. + // A higher precision can be achieved by using more digits, but the shortest + // accurate representation of any double will never use more digits than + // kBase10MaximalLength. + // Note that DoubleToAscii null-terminates its input. So the given buffer + // should be at least kBase10MaximalLength + 1 characters long. + static const MFBT_DATA int kBase10MaximalLength = 17; + + // Converts the given double 'v' to ascii. 'v' must not be NaN, +Infinity, or + // -Infinity. In SHORTEST_SINGLE-mode this restriction also applies to 'v' + // after it has been casted to a single-precision float. That is, in this + // mode static_cast(v) must not be NaN, +Infinity or -Infinity. + // + // The result should be interpreted as buffer * 10^(point-length). + // + // The output depends on the given mode: + // - SHORTEST: produce the least amount of digits for which the internal + // identity requirement is still satisfied. If the digits are printed + // (together with the correct exponent) then reading this number will give + // 'v' again. The buffer will choose the representation that is closest to + // 'v'. If there are two at the same distance, than the one farther away + // from 0 is chosen (halfway cases - ending with 5 - are rounded up). + // In this mode the 'requested_digits' parameter is ignored. + // - SHORTEST_SINGLE: same as SHORTEST but with single-precision. + // - FIXED: produces digits necessary to print a given number with + // 'requested_digits' digits after the decimal point. The produced digits + // might be too short in which case the caller has to fill the remainder + // with '0's. + // Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2. + // Halfway cases are rounded towards +/-Infinity (away from 0). The call + // toFixed(0.15, 2) thus returns buffer="2", point=0. + // The returned buffer may contain digits that would be truncated from the + // shortest representation of the input. + // - PRECISION: produces 'requested_digits' where the first digit is not '0'. + // Even though the length of produced digits usually equals + // 'requested_digits', the function is allowed to return fewer digits, in + // which case the caller has to fill the missing digits with '0's. + // Halfway cases are again rounded away from 0. + // DoubleToAscii expects the given buffer to be big enough to hold all + // digits and a terminating null-character. In SHORTEST-mode it expects a + // buffer of at least kBase10MaximalLength + 1. In all other modes the + // requested_digits parameter and the padding-zeroes limit the size of the + // output. Don't forget the decimal point, the exponent character and the + // terminating null-character when computing the maximal output size. + // The given length is only used in debug mode to ensure the buffer is big + // enough. + static MFBT_API void DoubleToAscii(double v, + DtoaMode mode, + int requested_digits, + char* buffer, + int buffer_length, + bool* sign, + int* length, + int* point); + + private: + // Implementation for ToShortest and ToShortestSingle. + MFBT_API bool ToShortestIeeeNumber(double value, + StringBuilder* result_builder, + DtoaMode mode) const; + + // If the value is a special value (NaN or Infinity) constructs the + // corresponding string using the configured infinity/nan-symbol. + // If either of them is NULL or the value is not special then the + // function returns false. + MFBT_API bool HandleSpecialValues(double value, StringBuilder* result_builder) const; + // Constructs an exponential representation (i.e. 1.234e56). + // The given exponent assumes a decimal point after the first decimal digit. + MFBT_API void CreateExponentialRepresentation(const char* decimal_digits, + int length, + int exponent, + StringBuilder* result_builder) const; + // Creates a decimal representation (i.e 1234.5678). + MFBT_API void CreateDecimalRepresentation(const char* decimal_digits, + int length, + int decimal_point, + int digits_after_point, + StringBuilder* result_builder) const; + + const int flags_; + const char* const infinity_symbol_; + const char* const nan_symbol_; + const char exponent_character_; + const int decimal_in_shortest_low_; + const int decimal_in_shortest_high_; + const int max_leading_padding_zeroes_in_precision_mode_; + const int max_trailing_padding_zeroes_in_precision_mode_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter); +}; + + +class StringToDoubleConverter { + public: + // Enumeration for allowing octals and ignoring junk when converting + // strings to numbers. + enum Flags { + NO_FLAGS = 0, + ALLOW_HEX = 1, + ALLOW_OCTALS = 2, + ALLOW_TRAILING_JUNK = 4, + ALLOW_LEADING_SPACES = 8, + ALLOW_TRAILING_SPACES = 16, + ALLOW_SPACES_AFTER_SIGN = 32, + ALLOW_CASE_INSENSIBILITY = 64, + }; + + // Flags should be a bit-or combination of the possible Flags-enum. + // - NO_FLAGS: no special flags. + // - ALLOW_HEX: recognizes the prefix "0x". Hex numbers may only be integers. + // Ex: StringToDouble("0x1234") -> 4660.0 + // In StringToDouble("0x1234.56") the characters ".56" are trailing + // junk. The result of the call is hence dependent on + // the ALLOW_TRAILING_JUNK flag and/or the junk value. + // With this flag "0x" is a junk-string. Even with ALLOW_TRAILING_JUNK, + // the string will not be parsed as "0" followed by junk. + // + // - ALLOW_OCTALS: recognizes the prefix "0" for octals: + // If a sequence of octal digits starts with '0', then the number is + // read as octal integer. Octal numbers may only be integers. + // Ex: StringToDouble("01234") -> 668.0 + // StringToDouble("012349") -> 12349.0 // Not a sequence of octal + // // digits. + // In StringToDouble("01234.56") the characters ".56" are trailing + // junk. The result of the call is hence dependent on + // the ALLOW_TRAILING_JUNK flag and/or the junk value. + // In StringToDouble("01234e56") the characters "e56" are trailing + // junk, too. + // - ALLOW_TRAILING_JUNK: ignore trailing characters that are not part of + // a double literal. + // - ALLOW_LEADING_SPACES: skip over leading whitespace, including spaces, + // new-lines, and tabs. + // - ALLOW_TRAILING_SPACES: ignore trailing whitespace. + // - ALLOW_SPACES_AFTER_SIGN: ignore whitespace after the sign. + // Ex: StringToDouble("- 123.2") -> -123.2. + // StringToDouble("+ 123.2") -> 123.2 + // - ALLOW_CASE_INSENSIBILITY: ignore case of characters for special values: + // infinity and nan. + // + // empty_string_value is returned when an empty string is given as input. + // If ALLOW_LEADING_SPACES or ALLOW_TRAILING_SPACES are set, then a string + // containing only spaces is converted to the 'empty_string_value', too. + // + // junk_string_value is returned when + // a) ALLOW_TRAILING_JUNK is not set, and a junk character (a character not + // part of a double-literal) is found. + // b) ALLOW_TRAILING_JUNK is set, but the string does not start with a + // double literal. + // + // infinity_symbol and nan_symbol are strings that are used to detect + // inputs that represent infinity and NaN. They can be null, in which case + // they are ignored. + // The conversion routine first reads any possible signs. Then it compares the + // following character of the input-string with the first character of + // the infinity, and nan-symbol. If either matches, the function assumes, that + // a match has been found, and expects the following input characters to match + // the remaining characters of the special-value symbol. + // This means that the following restrictions apply to special-value symbols: + // - they must not start with signs ('+', or '-'), + // - they must not have the same first character. + // - they must not start with digits. + // + // Examples: + // flags = ALLOW_HEX | ALLOW_TRAILING_JUNK, + // empty_string_value = 0.0, + // junk_string_value = NaN, + // infinity_symbol = "infinity", + // nan_symbol = "nan": + // StringToDouble("0x1234") -> 4660.0. + // StringToDouble("0x1234K") -> 4660.0. + // StringToDouble("") -> 0.0 // empty_string_value. + // StringToDouble(" ") -> NaN // junk_string_value. + // StringToDouble(" 1") -> NaN // junk_string_value. + // StringToDouble("0x") -> NaN // junk_string_value. + // StringToDouble("-123.45") -> -123.45. + // StringToDouble("--123.45") -> NaN // junk_string_value. + // StringToDouble("123e45") -> 123e45. + // StringToDouble("123E45") -> 123e45. + // StringToDouble("123e+45") -> 123e45. + // StringToDouble("123E-45") -> 123e-45. + // StringToDouble("123e") -> 123.0 // trailing junk ignored. + // StringToDouble("123e-") -> 123.0 // trailing junk ignored. + // StringToDouble("+NaN") -> NaN // NaN string literal. + // StringToDouble("-infinity") -> -inf. // infinity literal. + // StringToDouble("Infinity") -> NaN // junk_string_value. + // + // flags = ALLOW_OCTAL | ALLOW_LEADING_SPACES, + // empty_string_value = 0.0, + // junk_string_value = NaN, + // infinity_symbol = NULL, + // nan_symbol = NULL: + // StringToDouble("0x1234") -> NaN // junk_string_value. + // StringToDouble("01234") -> 668.0. + // StringToDouble("") -> 0.0 // empty_string_value. + // StringToDouble(" ") -> 0.0 // empty_string_value. + // StringToDouble(" 1") -> 1.0 + // StringToDouble("0x") -> NaN // junk_string_value. + // StringToDouble("0123e45") -> NaN // junk_string_value. + // StringToDouble("01239E45") -> 1239e45. + // StringToDouble("-infinity") -> NaN // junk_string_value. + // StringToDouble("NaN") -> NaN // junk_string_value. + StringToDoubleConverter(int flags, + double empty_string_value, + double junk_string_value, + const char* infinity_symbol, + const char* nan_symbol) + : flags_(flags), + empty_string_value_(empty_string_value), + junk_string_value_(junk_string_value), + infinity_symbol_(infinity_symbol), + nan_symbol_(nan_symbol) { + } + + // Performs the conversion. + // The output parameter 'processed_characters_count' is set to the number + // of characters that have been processed to read the number. + // Spaces than are processed with ALLOW_{LEADING|TRAILING}_SPACES are included + // in the 'processed_characters_count'. Trailing junk is never included. + double StringToDouble(const char* buffer, + int length, + int* processed_characters_count) const; + + // Same as StringToDouble above but for 16 bit characters. + double StringToDouble(const uc16* buffer, + int length, + int* processed_characters_count) const; + + // Same as StringToDouble but reads a float. + // Note that this is not equivalent to static_cast(StringToDouble(...)) + // due to potential double-rounding. + float StringToFloat(const char* buffer, + int length, + int* processed_characters_count) const; + + // Same as StringToFloat above but for 16 bit characters. + float StringToFloat(const uc16* buffer, + int length, + int* processed_characters_count) const; + + private: + const int flags_; + const double empty_string_value_; + const double junk_string_value_; + const char* const infinity_symbol_; + const char* const nan_symbol_; + + template + double StringToIeee(Iterator start_pointer, + int length, + bool read_as_double, + int* processed_characters_count) const; + + DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter); +}; + +} // namespace double_conversion + +#endif // DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/double-conversion/utils.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/double-conversion/utils.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/double-conversion/utils.h @@ -0,0 +1,326 @@ +// Copyright 2010 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef DOUBLE_CONVERSION_UTILS_H_ +#define DOUBLE_CONVERSION_UTILS_H_ + +#include +#include + +#include "mozilla/Assertions.h" +#ifndef ASSERT +#define ASSERT(condition) \ + MOZ_ASSERT(condition) +#endif +#ifndef UNIMPLEMENTED +#define UNIMPLEMENTED() MOZ_CRASH() +#endif +#ifndef DOUBLE_CONVERSION_NO_RETURN +#ifdef _MSC_VER +#define DOUBLE_CONVERSION_NO_RETURN __declspec(noreturn) +#else +#define DOUBLE_CONVERSION_NO_RETURN __attribute__((noreturn)) +#endif +#endif +#ifndef UNREACHABLE +#ifdef _MSC_VER +void DOUBLE_CONVERSION_NO_RETURN abort_noreturn(); +inline void abort_noreturn() { MOZ_CRASH(); } +#define UNREACHABLE() (abort_noreturn()) +#else +#define UNREACHABLE() MOZ_CRASH() +#endif +#endif + + +// Double operations detection based on target architecture. +// Linux uses a 80bit wide floating point stack on x86. This induces double +// rounding, which in turn leads to wrong results. +// An easy way to test if the floating-point operations are correct is to +// evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then +// the result is equal to 89255e-22. +// The best way to test this, is to create a division-function and to compare +// the output of the division with the expected result. (Inlining must be +// disabled.) +// On Linux,x86 89255e-22 != Div_double(89255.0/1e22) +#if defined(_M_X64) || defined(__x86_64__) || \ + defined(__ARMEL__) || defined(__avr32__) || \ + defined(__hppa__) || defined(__ia64__) || \ + defined(__mips__) || \ + defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \ + defined(_POWER) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \ + defined(__sparc__) || defined(__sparc) || defined(__s390__) || \ + defined(__SH4__) || defined(__alpha__) || \ + defined(_MIPS_ARCH_MIPS32R2) || \ + defined(__AARCH64EL__) || defined(__aarch64__) || \ + defined(__riscv) +#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 +#elif defined(__mc68000__) +#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS +#elif defined(_M_IX86) || defined(__i386__) || defined(__i386) +#if defined(_WIN32) +// Windows uses a 64bit wide floating point stack. +#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 +#else +#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS +#endif // _WIN32 +#else +#error Target architecture was not detected as supported by Double-Conversion. +#endif + +#if defined(__GNUC__) +#define DOUBLE_CONVERSION_UNUSED __attribute__((unused)) +#else +#define DOUBLE_CONVERSION_UNUSED +#endif + +#include + +typedef uint16_t uc16; + +// The following macro works on both 32 and 64-bit platforms. +// Usage: instead of writing 0x1234567890123456 +// write UINT64_2PART_C(0x12345678,90123456); +#define UINT64_2PART_C(a, b) (((static_cast(a) << 32) + 0x##b##u)) + + +// The expression ARRAY_SIZE(a) is a compile-time constant of type +// size_t which represents the number of elements of the given +// array. You should only use ARRAY_SIZE on statically allocated +// arrays. +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) \ + ((sizeof(a) / sizeof(*(a))) / \ + static_cast(!(sizeof(a) % sizeof(*(a))))) +#endif + +// A macro to disallow the evil copy constructor and operator= functions +// This should be used in the private: declarations for a class +#ifndef DISALLOW_COPY_AND_ASSIGN +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) +#endif + +// A macro to disallow all the implicit constructors, namely the +// default constructor, copy constructor and operator= functions. +// +// This should be used in the private: declarations for a class +// that wants to prevent anyone from instantiating it. This is +// especially useful for classes containing only static methods. +#ifndef DISALLOW_IMPLICIT_CONSTRUCTORS +#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ + TypeName(); \ + DISALLOW_COPY_AND_ASSIGN(TypeName) +#endif + +namespace double_conversion { + +static const int kCharSize = sizeof(char); + +// Returns the maximum of the two parameters. +template +static T Max(T a, T b) { + return a < b ? b : a; +} + + +// Returns the minimum of the two parameters. +template +static T Min(T a, T b) { + return a < b ? a : b; +} + + +inline int StrLength(const char* string) { + size_t length = strlen(string); + ASSERT(length == static_cast(static_cast(length))); + return static_cast(length); +} + +// This is a simplified version of V8's Vector class. +template +class Vector { + public: + Vector() : start_(NULL), length_(0) {} + Vector(T* data, int len) : start_(data), length_(len) { + ASSERT(len == 0 || (len > 0 && data != NULL)); + } + + // Returns a vector using the same backing storage as this one, + // spanning from and including 'from', to but not including 'to'. + Vector SubVector(int from, int to) { + ASSERT(to <= length_); + ASSERT(from < to); + ASSERT(0 <= from); + return Vector(start() + from, to - from); + } + + // Returns the length of the vector. + int length() const { return length_; } + + // Returns whether or not the vector is empty. + bool is_empty() const { return length_ == 0; } + + // Returns the pointer to the start of the data in the vector. + T* start() const { return start_; } + + // Access individual vector elements - checks bounds in debug mode. + T& operator[](int index) const { + ASSERT(0 <= index && index < length_); + return start_[index]; + } + + T& first() { return start_[0]; } + + T& last() { return start_[length_ - 1]; } + + private: + T* start_; + int length_; +}; + + +// Helper class for building result strings in a character buffer. The +// purpose of the class is to use safe operations that checks the +// buffer bounds on all operations in debug mode. +class StringBuilder { + public: + StringBuilder(char* buffer, int buffer_size) + : buffer_(buffer, buffer_size), position_(0) { } + + ~StringBuilder() { if (!is_finalized()) Finalize(); } + + int size() const { return buffer_.length(); } + + // Get the current position in the builder. + int position() const { + ASSERT(!is_finalized()); + return position_; + } + + // Reset the position. + void Reset() { position_ = 0; } + + // Add a single character to the builder. It is not allowed to add + // 0-characters; use the Finalize() method to terminate the string + // instead. + void AddCharacter(char c) { + ASSERT(c != '\0'); + ASSERT(!is_finalized() && position_ < buffer_.length()); + buffer_[position_++] = c; + } + + // Add an entire string to the builder. Uses strlen() internally to + // compute the length of the input string. + void AddString(const char* s) { + AddSubstring(s, StrLength(s)); + } + + // Add the first 'n' characters of the given string 's' to the + // builder. The input string must have enough characters. + void AddSubstring(const char* s, int n) { + ASSERT(!is_finalized() && position_ + n < buffer_.length()); + ASSERT(static_cast(n) <= strlen(s)); + memmove(&buffer_[position_], s, n * kCharSize); + position_ += n; + } + + + // Add character padding to the builder. If count is non-positive, + // nothing is added to the builder. + void AddPadding(char c, int count) { + for (int i = 0; i < count; i++) { + AddCharacter(c); + } + } + + // Finalize the string by 0-terminating it and returning the buffer. + char* Finalize() { + ASSERT(!is_finalized() && position_ < buffer_.length()); + buffer_[position_] = '\0'; + // Make sure nobody managed to add a 0-character to the + // buffer while building the string. + ASSERT(strlen(buffer_.start()) == static_cast(position_)); + position_ = -1; + ASSERT(is_finalized()); + return buffer_.start(); + } + + private: + Vector buffer_; + int position_; + + bool is_finalized() const { return position_ < 0; } + + DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder); +}; + +// The type-based aliasing rule allows the compiler to assume that pointers of +// different types (for some definition of different) never alias each other. +// Thus the following code does not work: +// +// float f = foo(); +// int fbits = *(int*)(&f); +// +// The compiler 'knows' that the int pointer can't refer to f since the types +// don't match, so the compiler may cache f in a register, leaving random data +// in fbits. Using C++ style casts makes no difference, however a pointer to +// char data is assumed to alias any other pointer. This is the 'memcpy +// exception'. +// +// Bit_cast uses the memcpy exception to move the bits from a variable of one +// type of a variable of another type. Of course the end result is likely to +// be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005) +// will completely optimize BitCast away. +// +// There is an additional use for BitCast. +// Recent gccs will warn when they see casts that may result in breakage due to +// the type-based aliasing rule. If you have checked that there is no breakage +// you can use BitCast to cast one pointer type to another. This confuses gcc +// enough that it can no longer see that you have cast one pointer type to +// another thus avoiding the warning. +template +inline Dest BitCast(const Source& source) { + // Compile time assertion: sizeof(Dest) == sizeof(Source) + // A compile error here means your Dest and Source have different sizes. + DOUBLE_CONVERSION_UNUSED + typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1]; + + Dest dest; + memmove(&dest, &source, sizeof(dest)); + return dest; +} + +template +inline Dest BitCast(Source* source) { + return BitCast(reinterpret_cast(source)); +} + +} // namespace double_conversion + +#endif // DOUBLE_CONVERSION_UTILS_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 @@ -1,61 +1,61 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=78: - * - * 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_config_h -#define js_config_h - -/* Definitions set at build time that affect SpiderMonkey's public API. - This header file is generated by the SpiderMonkey configure script, - and installed along with jsapi.h. */ - -/* 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 */ - -/* Define to 1 if SpiderMonkey should support multi-threaded clients. */ -/* #undef JS_THREADSAFE */ - -/* Define to 1 if SpiderMonkey should include ctypes support. */ -/* #undef JS_HAS_CTYPES */ - -/* Define to 1 if SpiderMonkey should support the ability to perform - entirely too much GC. */ -/* #undef JS_GC_ZEAL */ - -/* Define to 1 if SpiderMonkey should use small chunks. */ -/* #undef JS_GC_SMALL_CHUNK_SIZE */ - -/* Define to 1 to perform extra assertions and heap poisoning. */ -/* #undef JS_CRASH_DIAGNOSTICS */ - -/* Define to 1 if SpiderMonkey is in NUNBOX32 mode. */ -#define JS_NUNBOX32 1 - -/* Define to 1 if SpiderMonkey is in PUNBOX64 mode. */ -/* #undef JS_PUNBOX64 */ - -/* MOZILLA JSAPI version number components */ -#define MOZJS_MAJOR_VERSION 52 -#define MOZJS_MINOR_VERSION 9 - -#endif /* js_config_h */ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * 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_config_h +#define js_config_h + +/* Definitions set at build time that affect SpiderMonkey's public API. + This header file is generated by the SpiderMonkey configure script, + and installed along with jsapi.h. */ + +/* 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 */ + +/* Define to 1 if SpiderMonkey should support multi-threaded clients. */ +/* #undef JS_THREADSAFE */ + +/* Define to 1 if SpiderMonkey should include ctypes support. */ +/* #undef JS_HAS_CTYPES */ + +/* Define to 1 if SpiderMonkey should support the ability to perform + entirely too much GC. */ +/* #undef JS_GC_ZEAL */ + +/* Define to 1 if SpiderMonkey should use small chunks. */ +/* #undef JS_GC_SMALL_CHUNK_SIZE */ + +/* Define to 1 to perform extra assertions and heap poisoning. */ +/* #undef JS_CRASH_DIAGNOSTICS */ + +/* Define to 1 if SpiderMonkey is in NUNBOX32 mode. */ +#define JS_NUNBOX32 1 + +/* Define to 1 if SpiderMonkey is in PUNBOX64 mode. */ +/* #undef JS_PUNBOX64 */ + +/* MOZILLA JSAPI version number components */ +#define MOZJS_MAJOR_VERSION 60 +#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 @@ -19,9 +19,7 @@ * is an integer literal specifying the total number of * replaceable arguments in the following format string. * - * is an exception index from the enum in jsexn.c; - * JSEXN_NONE for none. The given exception index will be raised by the - * engine when the corresponding error occurs. + * is an enum JSExnType value, defined in jsapi.h. * * is a string literal, optionally containing sequences * {X} where X is an integer representing the argument number that will @@ -29,7 +27,7 @@ * * e.g. * - * MSG_DEF(JSMSG_NOT_A_SUBSPECIES, 2, JSEXN_NONE, + * MSG_DEF(JSMSG_NOT_A_SUBSPECIES, 2, JSEXN_TYPEERROR, * "{0} is not a member of the {1} family") * * can be used: @@ -38,7 +36,7 @@ * * to report: * - * "Rhino is not a member of the Monkey family" + * "TypeError: Rhino is not a member of the Monkey family" */ MSG_DEF(JSMSG_NOT_AN_ERROR, 0, JSEXN_ERR, "") @@ -47,7 +45,6 @@ MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}") MSG_DEF(JSMSG_NO_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} has no constructor") MSG_DEF(JSMSG_BAD_SORT_ARG, 0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument") -MSG_DEF(JSMSG_CANT_WATCH, 1, JSEXN_TYPEERR, "can't watch non-native objects of class {0}") MSG_DEF(JSMSG_READ_ONLY, 1, JSEXN_TYPEERR, "{0} is read-only") MSG_DEF(JSMSG_CANT_DELETE, 1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted") MSG_DEF(JSMSG_CANT_TRUNCATE_ARRAY, 0, JSEXN_TYPEERR, "can't delete non-configurable array element") @@ -58,31 +55,34 @@ MSG_DEF(JSMSG_TOPRIMITIVE_RETURNED_OBJECT, 2, JSEXN_TYPEERR, "can't convert {0} to {1}: its [Symbol.toPrimitive] method returned an object") MSG_DEF(JSMSG_NO_PROPERTIES, 1, JSEXN_TYPEERR, "{0} has no properties") MSG_DEF(JSMSG_BAD_REGEXP_FLAG, 1, JSEXN_SYNTAXERR, "invalid regular expression flag {0}") -MSG_DEF(JSMSG_ARG_INDEX_OUT_OF_RANGE, 1, JSEXN_RANGEERR, "argument {0} accesses an index that is out of range") +MSG_DEF(JSMSG_INVALID_DATA_VIEW_LENGTH, 0, JSEXN_RANGEERR, "invalid data view length") +MSG_DEF(JSMSG_OFFSET_LARGER_THAN_FILESIZE, 0, JSEXN_RANGEERR, "offset is larger than filesize") +MSG_DEF(JSMSG_OFFSET_OUT_OF_BUFFER, 0, JSEXN_RANGEERR, "start offset is outside the bounds of the buffer") +MSG_DEF(JSMSG_OFFSET_OUT_OF_DATAVIEW, 0, JSEXN_RANGEERR, "offset is outside the bounds of the DataView") MSG_DEF(JSMSG_SPREAD_TOO_LARGE, 0, JSEXN_RANGEERR, "array too large due to spread operand(s)") 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_PREV, 2, JSEXN_NOTE, "Previously declared at line {0}, column {1}") MSG_DEF(JSMSG_REDECLARED_VAR, 2, JSEXN_SYNTAXERR, "redeclaration of {0} {1}") MSG_DEF(JSMSG_UNDECLARED_VAR, 1, JSEXN_REFERENCEERR, "assignment to undeclared variable {0}") -MSG_DEF(JSMSG_GETTER_ONLY, 0, JSEXN_TYPEERR, "setting a property that has only a getter") +MSG_DEF(JSMSG_GETTER_ONLY, 1, JSEXN_TYPEERR, "setting getter-only property {0}") MSG_DEF(JSMSG_OVERWRITING_ACCESSOR, 1, JSEXN_TYPEERR, "can't overwrite accessor property {0}") MSG_DEF(JSMSG_UNDEFINED_PROP, 1, JSEXN_REFERENCEERR, "reference to undefined property {0}") 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_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_BUILTIN_CTOR_NO_NEW, 1, JSEXN_TYPEERR, "calling a builtin {0} constructor without new is forbidden") -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}") MSG_DEF(JSMSG_MISSING_FUN_ARG, 2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}") MSG_DEF(JSMSG_NOT_NONNULL_OBJECT, 1, JSEXN_TYPEERR, "{0} is not a non-null object") -MSG_DEF(JSMSG_SET_NON_OBJECT_RECEIVER, 1, JSEXN_TYPEERR, "can't assign to properties of {0}: not an object") +MSG_DEF(JSMSG_NOT_NONNULL_OBJECT_NAME, 2, JSEXN_TYPEERR, "{0} must be an object, got {1}") +MSG_DEF(JSMSG_NOT_NONNULL_OBJECT_ARG, 3, JSEXN_TYPEERR, "{0} argument of {1} must be an object, got {2}") +MSG_DEF(JSMSG_SET_NON_OBJECT_RECEIVER, 2, JSEXN_TYPEERR, "can't assign to property {1} on {0}: not an object") MSG_DEF(JSMSG_INVALID_DESCRIPTOR, 0, JSEXN_TYPEERR, "property descriptors must not specify a value or be writable when a getter or setter has been specified") MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE, 1, JSEXN_TYPEERR, "{0}: Object is not extensible") MSG_DEF(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE, 2, JSEXN_TYPEERR, "can't define property {1}: {0} is not extensible") @@ -93,20 +93,20 @@ 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_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_ITER_METHOD_RETURNED_PRIMITIVE, 1, JSEXN_TYPEERR, "iterator.{0}() 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}") MSG_DEF(JSMSG_CANT_SET_PROTO_CYCLE, 0, JSEXN_TYPEERR, "can't set prototype: it would cause a prototype chain cycle") MSG_DEF(JSMSG_INVALID_ARG_TYPE, 3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}") MSG_DEF(JSMSG_TERMINATED, 1, JSEXN_ERR, "Script terminated by timeout at:\n{0}") -MSG_DEF(JSMSG_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_UNINITIALIZED_THIS, 1, JSEXN_REFERENCEERR, "must call super constructor before using |this| in {0} class constructor") +MSG_DEF(JSMSG_UNINITIALIZED_THIS_ARROW, 0, JSEXN_REFERENCEERR, "must call super constructor before using |this| in arrow function in derived class constructor") MSG_DEF(JSMSG_BAD_DERIVED_RETURN, 1, JSEXN_TYPEERR, "derived class constructor returned invalid value {0}") +MSG_DEF(JSMSG_BAD_HERITAGE, 2, JSEXN_TYPEERR, "class heritage {0} is {1}") +MSG_DEF(JSMSG_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0} is not an object or null") // JSON MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data") @@ -116,7 +116,8 @@ MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS, 1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}") MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS, 0, JSEXN_REFERENCEERR, "invalid assignment left-hand side") MSG_DEF(JSMSG_BAD_PROTOTYPE, 1, JSEXN_TYPEERR, "'prototype' property of {0} is not an object") -MSG_DEF(JSMSG_IN_NOT_OBJECT, 1, JSEXN_TYPEERR, "invalid 'in' operand {0}") +MSG_DEF(JSMSG_IN_NOT_OBJECT, 1, JSEXN_TYPEERR, "right-hand side of 'in' should be an object, got {0}") +MSG_DEF(JSMSG_IN_STRING, 2, JSEXN_TYPEERR, "cannot use 'in' operator to search for '{0}' in '{1}'") MSG_DEF(JSMSG_TOO_MANY_CON_SPREADARGS, 0, JSEXN_RANGEERR, "too many constructor arguments") 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") @@ -133,6 +134,7 @@ MSG_DEF(JSMSG_NEGATIVE_REPETITION_COUNT, 0, JSEXN_RANGEERR, "repeat count must be non-negative") MSG_DEF(JSMSG_NOT_A_CODEPOINT, 1, JSEXN_RANGEERR, "{0} is not a valid code point") MSG_DEF(JSMSG_RESULTING_STRING_TOO_LARGE, 0, JSEXN_RANGEERR, "repeat count must be less than infinity and not overflow maximum string size") +MSG_DEF(JSMSG_DEPRECATED_STRING_METHOD, 2, JSEXN_WARN, "String.{0} is deprecated; use String.prototype.{1} instead") // Number MSG_DEF(JSMSG_BAD_RADIX, 0, JSEXN_RANGEERR, "radix must be an integer at least 2 and no greater than 36") @@ -155,7 +157,8 @@ // Wrappers MSG_DEF(JSMSG_ACCESSOR_DEF_DENIED, 1, JSEXN_ERR, "Permission denied to define accessor property {0}") MSG_DEF(JSMSG_DEAD_OBJECT, 0, JSEXN_TYPEERR, "can't access dead object") -MSG_DEF(JSMSG_UNWRAP_DENIED, 0, JSEXN_ERR, "permission denied to unwrap object") +MSG_DEF(JSMSG_OBJECT_ACCESS_DENIED, 0, JSEXN_ERR, "Permission denied to access object") +MSG_DEF(JSMSG_PROPERTY_ACCESS_DENIED, 1, JSEXN_ERR, "Permission denied to access property {0}") // JSAPI-only (Not thrown as JS exceptions) MSG_DEF(JSMSG_BAD_CLONE_FUNOBJ_SCOPE, 0, JSEXN_TYPEERR, "bad cloned function scope chain") @@ -180,13 +183,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 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_AWAIT_OUTSIDE_ASYNC, 0, JSEXN_SYNTAXERR, "await is only valid in async functions and async generators") MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)") MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated") MSG_DEF(JSMSG_BAD_CONST_DECL, 0, JSEXN_SYNTAXERR, "missing = in const declaration") @@ -200,23 +201,22 @@ 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_INCOP_OPERAND, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand") MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition") MSG_DEF(JSMSG_BAD_OCTAL, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant") -MSG_DEF(JSMSG_BAD_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, "'{0}' can't be defined or assigned to in strict mode code") +MSG_DEF(JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS, 0, JSEXN_SYNTAXERR, "'arguments' can't be defined or assigned to in strict mode code") +MSG_DEF(JSMSG_BAD_STRICT_ASSIGN_EVAL, 0, JSEXN_SYNTAXERR, "'eval' 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") MSG_DEF(JSMSG_BAD_SUPERCALL, 0, JSEXN_SYNTAXERR, "super() is only valid in derived class constructors") -MSG_DEF(JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION, 0, JSEXN_SYNTAXERR, "missing ] after array comprehension") MSG_DEF(JSMSG_BRACKET_AFTER_LIST, 0, JSEXN_SYNTAXERR, "missing ] after element list") MSG_DEF(JSMSG_BRACKET_IN_INDEX, 0, JSEXN_SYNTAXERR, "missing ] in index expression") +MSG_DEF(JSMSG_BRACKET_OPENED, 2, JSEXN_NOTE, "[ opened at line {0}, column {1}") MSG_DEF(JSMSG_CATCH_AFTER_GENERAL, 0, JSEXN_SYNTAXERR, "catch after unconditional catch") MSG_DEF(JSMSG_CATCH_IDENTIFIER, 0, JSEXN_SYNTAXERR, "missing identifier in catch") MSG_DEF(JSMSG_CATCH_OR_FINALLY, 0, JSEXN_SYNTAXERR, "missing catch or finally after try") @@ -227,6 +227,7 @@ MSG_DEF(JSMSG_COMP_PROP_UNTERM_EXPR, 0, JSEXN_SYNTAXERR, "missing ] in computed property name") MSG_DEF(JSMSG_CONTRARY_NONDIRECTIVE, 1, JSEXN_SYNTAXERR, "'{0}' statement won't be enforced as a directive because it isn't in directive prologue position") MSG_DEF(JSMSG_CURLY_AFTER_BODY, 0, JSEXN_SYNTAXERR, "missing } after function body") +MSG_DEF(JSMSG_CURLY_OPENED, 2, JSEXN_NOTE, "{ opened at line {0}, column {1}") 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_LIST, 0, JSEXN_SYNTAXERR, "missing } after property list") @@ -256,15 +257,19 @@ 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_FOR_AWAIT_OUTSIDE_ASYNC, 0, JSEXN_SYNTAXERR, "for await (... of ...) is only valid in async functions and async generators") 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_BAD_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid escape sequence") 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_OF_AFTER_FOR_LOOP_DECL, 0, JSEXN_SYNTAXERR, "a declaration in the head of a for-of loop can't have an initializer") +MSG_DEF(JSMSG_IN_AFTER_LEXICAL_FOR_DECL,0,JSEXN_SYNTAXERR, "a lexical declaration in the head of a for-in loop can't have an initializer") MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers") +MSG_DEF(JSMSG_INVALID_ID, 1, JSEXN_SYNTAXERR, "{0} is an invalid identifier") MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found") -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") @@ -313,7 +318,6 @@ MSG_DEF(JSMSG_SELFHOSTED_UNBOUND_NAME, 0, JSEXN_TYPEERR, "self-hosted code may not contain unbound name lookups") 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_WARN, "unreachable code after return statement") MSG_DEF(JSMSG_STRICT_CODE_WITH, 0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements") @@ -329,18 +333,21 @@ MSG_DEF(JSMSG_TOO_MANY_YIELDS, 0, JSEXN_SYNTAXERR, "too many yield expressions") MSG_DEF(JSMSG_TOUGH_BREAK, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch") MSG_DEF(JSMSG_UNEXPECTED_TOKEN, 2, JSEXN_SYNTAXERR, "expected {0}, got {1}") +MSG_DEF(JSMSG_UNEXPECTED_TOKEN_NO_EXPECT, 1, JSEXN_SYNTAXERR, "unexpected token: {0}") +MSG_DEF(JSMSG_UNEXPECTED_PARAMLIST_END,0, JSEXN_SYNTAXERR, "unexpected end of function parameter list") MSG_DEF(JSMSG_UNNAMED_CLASS_STMT, 0, JSEXN_SYNTAXERR, "class statement requires a name") MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT, 0, JSEXN_SYNTAXERR, "function statement requires a name") MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 0, JSEXN_SYNTAXERR, "unterminated comment") MSG_DEF(JSMSG_UNTERMINATED_REGEXP, 0, JSEXN_SYNTAXERR, "unterminated regular expression literal") -MSG_DEF(JSMSG_UNTERMINATED_STRING, 0, JSEXN_SYNTAXERR, "unterminated string literal") +MSG_DEF(JSMSG_EOF_BEFORE_END_OF_LITERAL,1,JSEXN_SYNTAXERR, "{0} literal not terminated before end of script") +MSG_DEF(JSMSG_EOL_BEFORE_END_OF_STRING,1, JSEXN_SYNTAXERR, "{0} string literal contains an unescaped line break") +MSG_DEF(JSMSG_EOF_IN_ESCAPE_IN_LITERAL,1, JSEXN_SYNTAXERR, "reached end of script in the middle of an escape sequence in a {0} literal") MSG_DEF(JSMSG_USELESS_EXPR, 0, JSEXN_TYPEERR, "useless expression") MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL, 0, JSEXN_SYNTAXERR, "\"use asm\" is only meaningful in the Directive Prologue of a function body") MSG_DEF(JSMSG_VAR_HIDES_ARG, 1, JSEXN_TYPEERR, "variable {0} redeclares argument") MSG_DEF(JSMSG_WHILE_AFTER_DO, 0, JSEXN_SYNTAXERR, "missing while after do-loop body") -MSG_DEF(JSMSG_YIELD_IN_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_YIELD_OUTSIDE_GENERATOR, 0, JSEXN_SYNTAXERR, "yield expression is only valid in generators") MSG_DEF(JSMSG_BAD_COLUMN_NUMBER, 0, JSEXN_RANGEERR, "column number out of range") MSG_DEF(JSMSG_COMPUTED_NAME_IN_PATTERN,0, JSEXN_SYNTAXERR, "computed property names aren't supported in this destructuring declaration") MSG_DEF(JSMSG_DEFAULT_IN_PATTERN, 0, JSEXN_SYNTAXERR, "destructuring defaults aren't supported in this destructuring declaration") @@ -354,6 +361,16 @@ // wasm MSG_DEF(JSMSG_WASM_COMPILE_ERROR, 1, JSEXN_WASMCOMPILEERROR, "{0}") +MSG_DEF(JSMSG_WASM_NO_SHMEM_COMPILE, 0, JSEXN_WASMCOMPILEERROR, "shared memory is disabled") +MSG_DEF(JSMSG_WASM_BAD_IMPORT_TYPE, 2, JSEXN_WASMLINKERROR, "import object field '{0}' is not a {1}") +MSG_DEF(JSMSG_WASM_BAD_IMPORT_SIG, 2, JSEXN_WASMLINKERROR, "imported function '{0}.{1}' signature mismatch") +MSG_DEF(JSMSG_WASM_BAD_IMP_SIZE, 1, JSEXN_WASMLINKERROR, "imported {0} with incompatible size") +MSG_DEF(JSMSG_WASM_BAD_IMP_MAX, 1, JSEXN_WASMLINKERROR, "imported {0} with incompatible maximum size") +MSG_DEF(JSMSG_WASM_IMP_SHARED_REQD, 0, JSEXN_WASMLINKERROR, "imported unshared memory but shared required") +MSG_DEF(JSMSG_WASM_IMP_SHARED_BANNED, 0, JSEXN_WASMLINKERROR, "imported shared memory but unshared required") +MSG_DEF(JSMSG_WASM_BAD_FIT, 2, JSEXN_WASMLINKERROR, "{0} segment does not fit in {1}") +MSG_DEF(JSMSG_WASM_BAD_I64_LINK, 0, JSEXN_WASMLINKERROR, "cannot pass i64 to or from JS") +MSG_DEF(JSMSG_WASM_NO_SHMEM_LINK, 0, JSEXN_WASMLINKERROR, "shared memory is disabled") MSG_DEF(JSMSG_WASM_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") @@ -362,23 +379,24 @@ 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_WAKE_OVERFLOW, 0, JSEXN_WASMRUNTIMEERROR, "too many woken agents") MSG_DEF(JSMSG_WASM_BAD_UINT32, 2, JSEXN_RANGEERR, "bad {0} {1}") MSG_DEF(JSMSG_WASM_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_IMPORT_FIELD, 1, JSEXN_TYPEERR, "import object field '{0}' is not an Object") MSG_DEF(JSMSG_WASM_BAD_TABLE_VALUE, 0, JSEXN_TYPEERR, "can only assign WebAssembly exported functions to Table") -MSG_DEF(JSMSG_WASM_BAD_I64, 0, JSEXN_TYPEERR, "cannot pass i64 to or from JS") +MSG_DEF(JSMSG_WASM_BAD_I64_TYPE, 0, JSEXN_TYPEERR, "cannot pass i64 to or from JS") +MSG_DEF(JSMSG_WASM_BAD_GLOBAL_TYPE, 0, JSEXN_TYPEERR, "bad type for a WebAssembly.Global") MSG_DEF(JSMSG_WASM_NO_TRANSFER, 0, JSEXN_TYPEERR, "cannot transfer WebAssembly/asm.js ArrayBuffer") +MSG_DEF(JSMSG_WASM_STREAM_ERROR, 0, JSEXN_TYPEERR, "stream error during WebAssembly compilation") MSG_DEF(JSMSG_WASM_TEXT_FAIL, 1, JSEXN_SYNTAXERR, "wasm text error: {0}") +MSG_DEF(JSMSG_WASM_MISSING_MAXIMUM, 0, JSEXN_TYPEERR, "'shared' is true but maximum is not specified") +MSG_DEF(JSMSG_WASM_GLOBAL_IMMUTABLE, 0, JSEXN_TYPEERR, "can't set value of immutable global") // Proxy MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE, 2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value") @@ -388,31 +406,30 @@ 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") -MSG_DEF(JSMSG_CANT_DEFINE_NE_AS_NC, 0, JSEXN_TYPEERR, "proxy can't define a non-existent property as non-configurable") +MSG_DEF(JSMSG_CANT_DEFINE_INVALID, 2, JSEXN_TYPEERR, "proxy can't define an incompatible property descriptor ('{0}', {1})") +MSG_DEF(JSMSG_CANT_DEFINE_NEW, 1, JSEXN_TYPEERR, "proxy can't define a new property '{0}' on a non-extensible object") +MSG_DEF(JSMSG_CANT_DEFINE_NE_AS_NC, 1, JSEXN_TYPEERR, "proxy can't define a non-existent '{0}' property as non-configurable") MSG_DEF(JSMSG_PROXY_DEFINE_RETURNED_FALSE, 1, JSEXN_TYPEERR, "proxy defineProperty handler returned false for property '{0}'") MSG_DEF(JSMSG_PROXY_DELETE_RETURNED_FALSE, 1, JSEXN_TYPEERR, "can't delete property '{0}': proxy deleteProperty handler returned false") MSG_DEF(JSMSG_PROXY_PREVENTEXTENSIONS_RETURNED_FALSE, 0, JSEXN_TYPEERR, "proxy preventExtensions handler returned false") MSG_DEF(JSMSG_PROXY_SET_RETURNED_FALSE, 1, JSEXN_TYPEERR, "proxy set handler returned false for property '{0}'") MSG_DEF(JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE, 0, JSEXN_TYPEERR, "proxy can't report an extensible object as non-extensible") -MSG_DEF(JSMSG_CANT_REPORT_C_AS_NC, 0, JSEXN_TYPEERR, "proxy can't report existing configurable property as non-configurable") -MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE, 0, JSEXN_TYPEERR, "proxy can't report an existing own property as non-existent on a non-extensible object") -MSG_DEF(JSMSG_CANT_REPORT_INVALID, 0, JSEXN_TYPEERR, "proxy can't report an incompatible property descriptor") -MSG_DEF(JSMSG_CANT_REPORT_NC_AS_NE, 0, JSEXN_TYPEERR, "proxy can't report a non-configurable own property as non-existent") -MSG_DEF(JSMSG_CANT_REPORT_NEW, 0, JSEXN_TYPEERR, "proxy can't report a new property on a non-extensible object") -MSG_DEF(JSMSG_CANT_REPORT_NE_AS_NC, 0, JSEXN_TYPEERR, "proxy can't report a non-existent property as non-configurable") -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_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") -MSG_DEF(JSMSG_OBJECT_ACCESS_DENIED, 0, JSEXN_ERR, "Permission denied to access object") -MSG_DEF(JSMSG_PROPERTY_ACCESS_DENIED, 1, JSEXN_ERR, "Permission denied to access property {0}") +MSG_DEF(JSMSG_CANT_REPORT_C_AS_NC, 1, JSEXN_TYPEERR, "proxy can't report existing configurable property '{0}' as non-configurable") +MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE, 1, JSEXN_TYPEERR, "proxy can't report an existing own property '{0}' as non-existent on a non-extensible object") +MSG_DEF(JSMSG_CANT_REPORT_INVALID, 2, JSEXN_TYPEERR, "proxy can't report an incompatible property descriptor ('{0}', {1})") +MSG_DEF(JSMSG_CANT_REPORT_NC_AS_NE, 1, JSEXN_TYPEERR, "proxy can't report a non-configurable own property '{0}' as non-existent") +MSG_DEF(JSMSG_CANT_REPORT_NEW, 1, JSEXN_TYPEERR, "proxy can't report a new property '{0}' on a non-extensible object") +MSG_DEF(JSMSG_CANT_REPORT_NE_AS_NC, 1, JSEXN_TYPEERR, "proxy can't report a non-existent property '{0}' as non-configurable") +MSG_DEF(JSMSG_CANT_SET_NW_NC, 1, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property '{0}'") +MSG_DEF(JSMSG_CANT_SET_WO_SETTER, 1, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property '{0}' without a setter") +MSG_DEF(JSMSG_CANT_SKIP_NC, 1, JSEXN_TYPEERR, "proxy can't skip a non-configurable property '{0}'") +MSG_DEF(JSMSG_OWNKEYS_STR_SYM, 0, JSEXN_TYPEERR, "proxy [[OwnPropertyKeys]] must return an array with only string and symbol elements") +MSG_DEF(JSMSG_OWNKEYS_DUPLICATE, 1, JSEXN_TYPEERR, "proxy [[OwnPropertyKeys]] can't report property '{0}' more than once") +MSG_DEF(JSMSG_MUST_REPORT_SAME_VALUE, 1, JSEXN_TYPEERR, "proxy must report the same value for the non-writable, non-configurable property '{0}'") +MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED, 1, JSEXN_TYPEERR, "proxy must report undefined for a non-configurable accessor property '{0}' without a getter") MSG_DEF(JSMSG_PROXY_CONSTRUCT_OBJECT, 0, JSEXN_TYPEERR, "proxy [[Construct]] must return an object") MSG_DEF(JSMSG_PROXY_EXTENSIBILITY, 0, JSEXN_TYPEERR, "proxy must report same extensiblitity as target") -MSG_DEF(JSMSG_PROXY_GETOWN_OBJORUNDEF, 0, JSEXN_TYPEERR, "proxy [[GetOwnProperty]] must return an object or undefined") +MSG_DEF(JSMSG_PROXY_GETOWN_OBJORUNDEF, 1, JSEXN_TYPEERR, "proxy [[GetOwnProperty]] must return an object or undefined for property '{0}'") 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") @@ -424,12 +441,13 @@ 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_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") +MSG_DEF(JSMSG_SC_SAB_REFCNT_OFLO, 0, JSEXN_TYPEERR, "SharedArrayBuffer has too many references") +MSG_DEF(JSMSG_SC_SHMEM_TRANSFERABLE, 0, JSEXN_TYPEERR, "Shared memory objects must not be in the transfer list") +MSG_DEF(JSMSG_SC_SHMEM_POLICY, 0, JSEXN_TYPEERR, "Policy object must forbid cloning shared memory objects cross-process") // 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}") @@ -462,6 +480,10 @@ 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") +MSG_DEF(JSMSG_DEBUG_NO_BINARY_SOURCE, 0, JSEXN_ERR, "WebAssembly binary source is not available") + +// Testing functions +MSG_DEF(JSMSG_TESTING_SCRIPTS_ONLY, 0, JSEXN_TYPEERR, "only works on scripts") // Tracelogger MSG_DEF(JSMSG_TRACELOGGER_ENABLE_FAIL, 1, JSEXN_ERR, "enabling tracelogger failed: {0}") @@ -470,9 +492,10 @@ MSG_DEF(JSMSG_DATE_NOT_FINITE, 0, JSEXN_RANGEERR, "date value is not finite in DateTimeFormat.format()") MSG_DEF(JSMSG_INTERNAL_INTL_ERROR, 0, JSEXN_ERR, "internal error while computing Intl data") MSG_DEF(JSMSG_INTL_OBJECT_NOT_INITED, 3, JSEXN_TYPEERR, "Intl.{0}.prototype.{1} called on value that's not an object initialized as a {2}") -MSG_DEF(JSMSG_INTL_OBJECT_REINITED, 0, JSEXN_TYPEERR, "can't initialize object twice as an object of an Intl constructor") MSG_DEF(JSMSG_INVALID_CURRENCY_CODE, 1, JSEXN_RANGEERR, "invalid currency code in NumberFormat(): {0}") MSG_DEF(JSMSG_INVALID_DIGITS_VALUE, 1, JSEXN_RANGEERR, "invalid digits value: {0}") +MSG_DEF(JSMSG_INVALID_KEYS_TYPE, 0, JSEXN_TYPEERR, "calendar info keys must be an object or undefined") +MSG_DEF(JSMSG_INVALID_KEY, 1, JSEXN_RANGEERR, "invalid key: {0}") MSG_DEF(JSMSG_INVALID_LANGUAGE_TAG, 1, JSEXN_RANGEERR, "invalid language tag: {0}") MSG_DEF(JSMSG_INVALID_LOCALES_ELEMENT, 0, JSEXN_TYPEERR, "invalid element in locales argument") MSG_DEF(JSMSG_INVALID_LOCALE_MATCHER, 1, JSEXN_RANGEERR, "invalid locale matcher in supportedLocalesOf(): {0}") @@ -497,7 +520,7 @@ 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_UNICODE_OVERFLOW, 1, JSEXN_SYNTAXERR, "Unicode codepoint must not be greater than 0x10FFFF in {0}") MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression") MSG_DEF(JSMSG_UNTERM_CLASS, 0, JSEXN_SYNTAXERR, "unterminated character class") @@ -547,7 +570,7 @@ // Atomics and futexes 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_WAIT_NOT_ALLOWED, 0, JSEXN_TYPEERR, "waiting is not allowed on this thread") // XPConnect wrappers and DOM bindings MSG_DEF(JSMSG_CANT_SET_INTERPOSED, 1, JSEXN_TYPEERR, "unable to set interposed data property '{0}'") @@ -564,14 +587,13 @@ // Modules MSG_DEF(JSMSG_BAD_DEFAULT_EXPORT, 0, JSEXN_SYNTAXERR, "default export cannot be provided by export *") -MSG_DEF(JSMSG_MISSING_INDIRECT_EXPORT, 1, JSEXN_SYNTAXERR, "indirect export '{0}' not found") -MSG_DEF(JSMSG_AMBIGUOUS_INDIRECT_EXPORT, 1, JSEXN_SYNTAXERR, "ambiguous indirect export '{0}'") -MSG_DEF(JSMSG_MISSING_IMPORT, 1, JSEXN_SYNTAXERR, "import '{0}' not found") -MSG_DEF(JSMSG_AMBIGUOUS_IMPORT, 1, JSEXN_SYNTAXERR, "ambiguous import '{0}'") +MSG_DEF(JSMSG_MISSING_INDIRECT_EXPORT, 0, JSEXN_SYNTAXERR, "indirect export not found") +MSG_DEF(JSMSG_AMBIGUOUS_INDIRECT_EXPORT, 0, JSEXN_SYNTAXERR, "ambiguous indirect export") +MSG_DEF(JSMSG_MISSING_IMPORT, 0, JSEXN_SYNTAXERR, "import not found") +MSG_DEF(JSMSG_AMBIGUOUS_IMPORT, 0, JSEXN_SYNTAXERR, "ambiguous import") 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") +MSG_DEF(JSMSG_BAD_MODULE_STATUS, 0, JSEXN_INTERNALERR, "module record has unexpected status") // Promise MSG_DEF(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself.") @@ -579,3 +601,49 @@ 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.") + +// Iterator +MSG_DEF(JSMSG_RETURN_NOT_CALLABLE, 0, JSEXN_TYPEERR, "property 'return' of iterator is not callable") +MSG_DEF(JSMSG_ITERATOR_NO_THROW, 0, JSEXN_TYPEERR, "iterator does not have a 'throw' method") + +// Async Iteration +MSG_DEF(JSMSG_FOR_AWAIT_NOT_OF, 0, JSEXN_SYNTAXERR, "'for await' loop should be used with 'of'") +MSG_DEF(JSMSG_NOT_AN_ASYNC_GENERATOR, 0, JSEXN_TYPEERR, "Not an async generator") +MSG_DEF(JSMSG_NOT_AN_ASYNC_ITERATOR, 0, JSEXN_TYPEERR, "Not an async from sync iterator") +MSG_DEF(JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.asyncIterator]() returned a non-object value") + +// ReadableStream +MSG_DEF(JSMSG_READABLESTREAM_UNDERLYINGSOURCE_TYPE_WRONG,0, JSEXN_RANGEERR,"'underlyingSource.type' must be \"bytes\" or undefined.") +MSG_DEF(JSMSG_READABLESTREAM_INVALID_READER_MODE, 0, JSEXN_RANGEERR,"'mode' must be \"byob\" or undefined.") +MSG_DEF(JSMSG_NUMBER_MUST_BE_FINITE_NON_NEGATIVE, 1, JSEXN_RANGEERR, "'{0}' must be a finite, non-negative number.") +MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_BYTESWRITTEN, 0, JSEXN_RANGEERR, "'bytesWritten' exceeds remaining length.") +MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_VIEW_SIZE, 0, JSEXN_RANGEERR, "view size does not match requested data.") +MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_INVALID_VIEW_OFFSET, 0, JSEXN_RANGEERR, "view offset does not match requested position.") +MSG_DEF(JSMSG_READABLESTREAM_NOT_LOCKED, 1, JSEXN_TYPEERR, "'{0}' may only be called on a locked stream.") +MSG_DEF(JSMSG_READABLESTREAM_LOCKED, 0, JSEXN_TYPEERR, "A Reader may only be created for an unlocked ReadableStream.") +MSG_DEF(JSMSG_READABLESTREAM_NOT_BYTE_STREAM_CONTROLLER, 1, JSEXN_TYPEERR, "{0} requires a ReadableByteStreamController.") +MSG_DEF(JSMSG_READABLESTREAM_NOT_DEFAULT_CONTROLLER, 1, JSEXN_TYPEERR, "{0} requires a ReadableStreamDefaultController.") +MSG_DEF(JSMSG_READABLESTREAM_CONTROLLER_SET, 0, JSEXN_TYPEERR, "The ReadableStream already has a controller defined.") +MSG_DEF(JSMSG_READABLESTREAMREADER_NOT_OWNED, 1, JSEXN_TYPEERR, "The ReadableStream reader method '{0}' may only be called on a reader owned by a stream.") +MSG_DEF(JSMSG_READABLESTREAMREADER_NOT_EMPTY, 1, JSEXN_TYPEERR, "The ReadableStream reader method '{0}' may not be called on a reader with read requests.") +MSG_DEF(JSMSG_READABLESTREAMBYOBREADER_READ_EMPTY_VIEW, 0, JSEXN_TYPEERR, "ReadableStreamBYOBReader.read() was passed an empty TypedArrayBuffer view.") +MSG_DEF(JSMSG_READABLESTREAMREADER_RELEASED, 0, JSEXN_TYPEERR, "The ReadableStream reader was released.") +MSG_DEF(JSMSG_READABLESTREAMCONTROLLER_CLOSED, 1, JSEXN_TYPEERR, "'{0}' called on a stream already closing.") +MSG_DEF(JSMSG_READABLESTREAMCONTROLLER_NOT_READABLE, 1, JSEXN_TYPEERR, "'{0}' may only be called on a stream in the 'readable' state.") +MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_BAD_CHUNKSIZE,0, JSEXN_RANGEERR, "ReadableByteStreamController requires a positive integer or undefined for 'autoAllocateChunkSize'.") +MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_BAD_CHUNK, 1, JSEXN_TYPEERR, "{0} passed a bad chunk.") +MSG_DEF(JSMSG_READABLEBYTESTREAMCONTROLLER_CLOSE_PENDING_PULL, 0, JSEXN_TYPEERR, "The ReadableByteStreamController cannot be closed while the buffer is being filled.") +MSG_DEF(JSMSG_READABLESTREAMBYOBREQUEST_NO_CONTROLLER, 1, JSEXN_TYPEERR, "ReadableStreamBYOBRequest method '{0}' called on a request with no controller.") +MSG_DEF(JSMSG_READABLESTREAMBYOBREQUEST_RESPOND_CLOSED, 0, JSEXN_TYPEERR, "ReadableStreamBYOBRequest method 'respond' called with non-zero number of bytes with a closed controller.") +MSG_DEF(JSMSG_READABLESTREAM_METHOD_NOT_IMPLEMENTED, 1, JSEXN_TYPEERR, "ReadableStream method {0} not yet implemented") + +// Other Stream-related +MSG_DEF(JSMSG_STREAM_INVALID_HIGHWATERMARK, 0, JSEXN_RANGEERR, "'highWaterMark' must be a non-negative, non-NaN number.") + +// Response-related +MSG_DEF(JSMSG_ERROR_CONSUMING_RESPONSE, 0, JSEXN_TYPEERR, "there was an error consuming the Response") +MSG_DEF(JSMSG_BAD_RESPONSE_VALUE, 0, JSEXN_TYPEERR, "expected Response or Promise resolving to Response") +MSG_DEF(JSMSG_BAD_RESPONSE_MIME_TYPE, 0, JSEXN_TYPEERR, "Response has unsupported MIME type") +MSG_DEF(JSMSG_BAD_RESPONSE_CORS_SAME_ORIGIN, 0, JSEXN_TYPEERR, "Response.type must be 'basic', 'cors' or 'default'") +MSG_DEF(JSMSG_BAD_RESPONSE_STATUS, 0, JSEXN_TYPEERR, "Response does not have ok status") +MSG_DEF(JSMSG_RESPONSE_ALREADY_CONSUMED, 0, JSEXN_TYPEERR, "Response already consumed") Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/AllocPolicy.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/AllocPolicy.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/AllocPolicy.h @@ -0,0 +1,183 @@ +/* -*- 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/. */ + +/* + * JS allocation policies. + * + * The allocators here are for system memory with lifetimes which are not + * managed by the GC. See the comment at the top of vm/MallocProvider.h. + */ + +#ifndef js_AllocPolicy_h +#define js_AllocPolicy_h + +#include "js/TypeDecls.h" +#include "js/Utility.h" + +extern JS_PUBLIC_API void JS_ReportOutOfMemory(JSContext* cx); + +namespace js { + +enum class AllocFunction { Malloc, Calloc, Realloc }; +/* Policy for using system memory functions and doing no error reporting. */ +class SystemAllocPolicy { + public: + template + T* maybe_pod_malloc(size_t numElems) { + return js_pod_malloc(numElems); + } + template + T* maybe_pod_calloc(size_t numElems) { + return js_pod_calloc(numElems); + } + template + T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) { + return js_pod_realloc(p, oldSize, newSize); + } + template + T* pod_malloc(size_t numElems) { + return maybe_pod_malloc(numElems); + } + template + T* pod_calloc(size_t numElems) { + return maybe_pod_calloc(numElems); + } + template + T* pod_realloc(T* p, size_t oldSize, size_t newSize) { + return maybe_pod_realloc(p, oldSize, newSize); + } + void free_(void* p) { js_free(p); } + void reportAllocOverflow() const {} + bool checkSimulatedOOM() const { return !js::oom::ShouldFailWithOOM(); } +}; + +JS_FRIEND_API void ReportOutOfMemory(JSContext* cx); + +/* + * Allocation policy that calls the system memory functions and reports errors + * to the context. Since the JSContext given on construction is stored for + * the lifetime of the container, this policy may only be used for containers + * whose lifetime is a shorter than the given JSContext. + * + * FIXME bug 647103 - rewrite this in terms of temporary allocation functions, + * not the system ones. + */ +class TempAllocPolicy { + JSContext* const cx_; + + /* + * Non-inline helper to call JSRuntime::onOutOfMemory with minimal + * code bloat. + */ + JS_FRIEND_API void* onOutOfMemory(AllocFunction allocFunc, size_t nbytes, + void* reallocPtr = nullptr); + + template + T* onOutOfMemoryTyped(AllocFunction allocFunc, size_t numElems, + void* reallocPtr = nullptr) { + size_t bytes; + if (MOZ_UNLIKELY(!CalculateAllocSize(numElems, &bytes))) return nullptr; + return static_cast(onOutOfMemory(allocFunc, bytes, reallocPtr)); + } + + public: + MOZ_IMPLICIT TempAllocPolicy(JSContext* cx) : cx_(cx) {} + + template + T* maybe_pod_malloc(size_t numElems) { + return js_pod_malloc(numElems); + } + + template + T* maybe_pod_calloc(size_t numElems) { + return js_pod_calloc(numElems); + } + + template + T* maybe_pod_realloc(T* prior, size_t oldSize, size_t newSize) { + return js_pod_realloc(prior, oldSize, newSize); + } + + template + T* pod_malloc(size_t numElems) { + T* p = maybe_pod_malloc(numElems); + if (MOZ_UNLIKELY(!p)) + p = onOutOfMemoryTyped(AllocFunction::Malloc, numElems); + return p; + } + + template + T* pod_calloc(size_t numElems) { + T* p = maybe_pod_calloc(numElems); + if (MOZ_UNLIKELY(!p)) + p = onOutOfMemoryTyped(AllocFunction::Calloc, numElems); + return p; + } + + template + T* pod_realloc(T* prior, size_t oldSize, size_t newSize) { + T* p2 = maybe_pod_realloc(prior, oldSize, newSize); + if (MOZ_UNLIKELY(!p2)) + p2 = onOutOfMemoryTyped(AllocFunction::Realloc, newSize, prior); + return p2; + } + + void free_(void* p) { js_free(p); } + + JS_FRIEND_API void reportAllocOverflow() const; + + bool checkSimulatedOOM() const { + if (js::oom::ShouldFailWithOOM()) { + ReportOutOfMemory(cx_); + return false; + } + + return true; + } +}; + +/* + * Allocation policy that uses Zone::pod_malloc and friends, so that memory + * pressure is accounted for on the zone. This is suitable for memory associated + * with GC things allocated in the zone. + * + * Since it doesn't hold a JSContext (those may not live long enough), it can't + * report out-of-memory conditions itself; the caller must check for OOM and + * take the appropriate action. + * + * FIXME bug 647103 - replace these *AllocPolicy names. + */ +class ZoneAllocPolicy { + JS::Zone* const zone; + + public: + MOZ_IMPLICIT ZoneAllocPolicy(JS::Zone* z) : zone(z) {} + + // These methods are defined in gc/Zone.h. + template + inline T* maybe_pod_malloc(size_t numElems); + template + inline T* maybe_pod_calloc(size_t numElems); + template + inline T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize); + template + inline T* pod_malloc(size_t numElems); + template + inline T* pod_calloc(size_t numElems); + template + inline T* pod_realloc(T* p, size_t oldSize, size_t newSize); + + void free_(void* p) { js_free(p); } + void reportAllocOverflow() const {} + + MOZ_MUST_USE bool checkSimulatedOOM() const { + return !js::oom::ShouldFailWithOOM(); + } +}; + +} /* namespace js */ + +#endif /* js_AllocPolicy_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-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 @@ -74,12 +74,11 @@ #include "js/Value.h" /* Typedef for native functions called by the JS VM. */ -typedef bool -(* JSNative)(JSContext* cx, unsigned argc, JS::Value* vp); +typedef bool (*JSNative)(JSContext* cx, unsigned argc, JS::Value* vp); namespace JS { -extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue; +extern JS_PUBLIC_DATA const HandleValue UndefinedHandleValue; namespace detail { @@ -87,239 +86,244 @@ * Compute |this| for the |vp| inside a JSNative, either boxing primitives or * replacing with the global object as necessary. */ -extern JS_PUBLIC_API(Value) -ComputeThis(JSContext* cx, JS::Value* vp); +extern JS_PUBLIC_API Value ComputeThis(JSContext* cx, JS::Value* vp); #ifdef JS_DEBUG -extern JS_PUBLIC_API(void) -CheckIsValidConstructible(const Value& v); +extern JS_PUBLIC_API void CheckIsValidConstructible(const Value& v); #endif -class MOZ_STACK_CLASS IncludeUsedRval -{ - protected: +class MOZ_STACK_CLASS IncludeUsedRval { + mutable bool usedRval_; + + public: + bool usedRval() const { return usedRval_; } + void setUsedRval() const { usedRval_ = true; } + void clearUsedRval() const { usedRval_ = false; } + void assertUnusedRval() const { MOZ_ASSERT(!usedRval_); } +}; + +class MOZ_STACK_CLASS NoUsedRval { + public: + bool usedRval() const { return false; } + void setUsedRval() const {} + void clearUsedRval() const {} + void assertUnusedRval() const {} +}; + +template +class MOZ_STACK_CLASS CallArgsBase { + static_assert(mozilla::IsSame::value || + mozilla::IsSame::value, + "WantUsedRval can only be IncludeUsedRval or NoUsedRval"); + + protected: + Value* argv_; + unsigned argc_; + bool constructing_ : 1; + + // True if the caller does not use the return value. + bool ignoresReturnValue_ : 1; + #ifdef JS_DEBUG - mutable bool usedRval_; - void setUsedRval() const { usedRval_ = true; } - void clearUsedRval() const { usedRval_ = false; } - void assertUnusedRval() const { MOZ_ASSERT(!usedRval_); } + WantUsedRval wantUsedRval_; + bool usedRval() const { return wantUsedRval_.usedRval(); } + void setUsedRval() const { wantUsedRval_.setUsedRval(); } + void clearUsedRval() const { wantUsedRval_.clearUsedRval(); } + void assertUnusedRval() const { wantUsedRval_.assertUnusedRval(); } #else - void setUsedRval() const {} - void clearUsedRval() const {} - void assertUnusedRval() const {} + bool usedRval() const { return false; } + void setUsedRval() const {} + void clearUsedRval() const {} + void assertUnusedRval() const {} #endif -}; -class MOZ_STACK_CLASS NoUsedRval -{ - protected: - void setUsedRval() const {} - void clearUsedRval() const {} - void assertUnusedRval() const {} -}; + public: + // CALLEE ACCESS + + /* + * Returns the function being called, as a value. Must not be called after + * rval() has been used! + */ + HandleValue calleev() const { + 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(); } -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: - // CALLEE ACCESS - - /* - * Returns the function being called, as a value. Must not be called after - * rval() has been used! - */ - HandleValue calleev() const { - 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; + // CALLING/CONSTRUCTING-DIFFERENTIATIONS + + bool isConstructing() const { + if (!argv_[-1].isMagic()) return false; #ifdef JS_DEBUG - if (!this->usedRval_) - CheckIsValidConstructible(calleev()); + if (!this->usedRval()) CheckIsValidConstructible(calleev()); #endif - return true; - } + return true; + } + + bool ignoresReturnValue() const { return ignoresReturnValue_; } - 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 - * responsibility to box the value if needed. - */ - HandleValue thisv() const { - // Some internal code uses thisv() in constructing cases, so don't do - // this yet. - // MOZ_ASSERT(!argv_[-1].isMagic(JS_IS_CONSTRUCTING)); - return HandleValue::fromMarkedLocation(&argv_[-1]); - } - - Value computeThis(JSContext* cx) const { - if (thisv().isObject()) - return thisv(); - - return ComputeThis(cx, base()); - } - - // 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 - * calleev() can no longer be used. (If you're compiling against a debug - * build of SpiderMonkey, these methods will assert to aid debugging.) - * - * If the method you're implementing succeeds by returning true, you *must* - * set this. (SpiderMonkey doesn't currently assert this, but it will do - * so eventually.) You don't need to use or change this if your method - * fails. - */ - MutableHandleValue rval() const { - this->setUsedRval(); - return MutableHandleValue::fromMarkedLocation(&argv_[-2]); - } - - 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(const Value& aCalleev) const { - this->clearUsedRval(); - argv_[-2] = aCalleev; - } - - void setThis(const Value& aThisv) const { - argv_[-1] = aThisv; - } - - MutableHandleValue mutableThisv() const { - return MutableHandleValue::fromMarkedLocation(&argv_[-1]); - } - - public: - // 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. - - Value* array() const { return argv_; } - Value* end() const { return argv_ + argc_ + constructing_; } - - 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; - } + 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 + * responsibility to box the value if needed. + */ + HandleValue thisv() const { + // Some internal code uses thisv() in constructing cases, so don't do + // this yet. + // MOZ_ASSERT(!argv_[-1].isMagic(JS_IS_CONSTRUCTING)); + return HandleValue::fromMarkedLocation(&argv_[-1]); + } + + Value computeThis(JSContext* cx) const { + if (thisv().isObject()) return thisv(); + + return ComputeThis(cx, base()); + } + + // 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 + * calleev() can no longer be used. (If you're compiling against a debug + * build of SpiderMonkey, these methods will assert to aid debugging.) + * + * If the method you're implementing succeeds by returning true, you *must* + * set this. (SpiderMonkey doesn't currently assert this, but it will do + * so eventually.) You don't need to use or change this if your method + * fails. + */ + MutableHandleValue rval() const { + this->setUsedRval(); + return MutableHandleValue::fromMarkedLocation(&argv_[-2]); + } + + 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(const Value& aCalleev) const { + this->clearUsedRval(); + argv_[-2] = aCalleev; + } + + void setThis(const Value& aThisv) const { argv_[-1] = aThisv; } + + MutableHandleValue mutableThisv() const { + return MutableHandleValue::fromMarkedLocation(&argv_[-1]); + } + + public: + // 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. + + Value* array() const { return argv_; } + Value* end() const { return argv_ + argc_ + constructing_; } + + 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; + } }; -} // namespace detail +} // namespace detail -class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase -{ - private: - friend CallArgs CallArgsFromVp(unsigned argc, Value* vp); - friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing); - - static CallArgs create(unsigned argc, Value* argv, bool constructing) { - CallArgs args; - args.clearUsedRval(); - args.argv_ = argv; - args.argc_ = argc; - args.constructing_ = constructing; +class MOZ_STACK_CLASS CallArgs + : public detail::CallArgsBase { + private: + friend CallArgs CallArgsFromVp(unsigned argc, Value* vp); + friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, + bool constructing, bool ignoresReturnValue); + + static CallArgs create(unsigned argc, Value* argv, bool constructing, + bool ignoresReturnValue = false) { + CallArgs args; + args.clearUsedRval(); + args.argv_ = argv; + args.argc_ = argc; + args.constructing_ = constructing; + args.ignoresReturnValue_ = ignoresReturnValue; #ifdef DEBUG - for (unsigned i = 0; i < argc; ++i) - MOZ_ASSERT_IF(argv[i].isMarkable(), !GCThingIsMarkedGray(GCCellPtr(argv[i]))); + MOZ_ASSERT(ValueIsNotGray(args.thisv())); + MOZ_ASSERT(ValueIsNotGray(args.calleev())); + for (unsigned i = 0; i < argc; ++i) MOZ_ASSERT(ValueIsNotGray(argv[i])); #endif - return args; - } - - public: - /* - * Returns true if there are at least |required| arguments passed in. If - * false, it reports an error message on the context. - */ - JS_PUBLIC_API(bool) requireAtLeast(JSContext* cx, const char* fnname, unsigned required) const; + return args; + } + public: + /* + * Returns true if there are at least |required| arguments passed in. If + * false, it reports an error message on the context. + */ + JS_PUBLIC_API bool requireAtLeast(JSContext* cx, const char* fnname, + unsigned required) const; }; -MOZ_ALWAYS_INLINE CallArgs -CallArgsFromVp(unsigned argc, Value* vp) -{ - return CallArgs::create(argc, vp + 2, vp[1].isMagic(JS_IS_CONSTRUCTING)); +MOZ_ALWAYS_INLINE CallArgs CallArgsFromVp(unsigned argc, Value* vp) { + return CallArgs::create(argc, vp + 2, vp[1].isMagic(JS_IS_CONSTRUCTING)); } // This method is only intended for internal use in SpiderMonkey. We may // eventually move it to an internal header. Embedders should use // JS::CallArgsFromVp! -MOZ_ALWAYS_INLINE CallArgs -CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing = false) -{ - return CallArgs::create(stackSlots - constructing, sp - stackSlots, constructing); +MOZ_ALWAYS_INLINE CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, + bool constructing = false, + bool ignoresReturnValue = false) { + return CallArgs::create(stackSlots - constructing, sp - stackSlots, + constructing, ignoresReturnValue); } -} // namespace JS +} // namespace JS /* * Macros to hide interpreter stack layout details from a JSNative using its @@ -336,10 +340,8 @@ * Note: if this method returns null, an error has occurred and must be * propagated or caught. */ -MOZ_ALWAYS_INLINE JS::Value -JS_THIS(JSContext* cx, JS::Value* vp) -{ - return vp[1].isPrimitive() ? JS::detail::ComputeThis(cx, vp) : vp[1]; +MOZ_ALWAYS_INLINE JS::Value JS_THIS(JSContext* cx, JS::Value* vp) { + return vp[1].isPrimitive() ? JS::detail::ComputeThis(cx, vp) : vp[1]; } /* @@ -349,7 +351,7 @@ * 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()) +#define JS_THIS_OBJECT(cx, vp) (JS_THIS(cx, vp).toObjectOrNull()) /* * |this| is passed to functions in ES5 without change. Functions themselves @@ -364,6 +366,6 @@ * But: DO NOT USE THIS! Instead use JS::CallArgs::thisv(), above. * */ -#define JS_THIS_VALUE(cx,vp) ((vp)[1]) +#define JS_THIS_VALUE(cx, vp) ((vp)[1]) #endif /* js_CallArgs_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/CallNonGenericMethod.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/CallNonGenericMethod.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/CallNonGenericMethod.h @@ -23,10 +23,12 @@ namespace detail { // DON'T CALL THIS DIRECTLY. It's for use only by CallNonGenericMethod! -extern JS_PUBLIC_API(bool) -CallMethodIfWrapped(JSContext* cx, IsAcceptableThis test, NativeImpl impl, const CallArgs& args); +extern JS_PUBLIC_API bool CallMethodIfWrapped(JSContext* cx, + IsAcceptableThis test, + NativeImpl impl, + const CallArgs& args); -} // namespace detail +} // namespace detail // Methods usually act upon |this| objects only from a single global object and // compartment. Sometimes, however, a method must act upon |this| values from @@ -73,7 +75,8 @@ // answer_getAnswer(JSContext* cx, unsigned argc, JS::Value* vp) // { // JS::CallArgs args = JS::CallArgsFromVp(argc, vp); -// return JS::CallNonGenericMethod(cx, args); +// return JS::CallNonGenericMethod(cx, args); // } // // Note that, because they are used as template arguments, the predicate @@ -91,27 +94,25 @@ // Note: JS::CallNonGenericMethod will only work correctly if it's called in // tail position in a JSNative. Do not call it from any other place. // -template -MOZ_ALWAYS_INLINE bool -CallNonGenericMethod(JSContext* cx, const CallArgs& args) -{ - HandleValue thisv = args.thisv(); - if (Test(thisv)) - return Impl(cx, args); +template +MOZ_ALWAYS_INLINE bool CallNonGenericMethod(JSContext* cx, + const CallArgs& args) { + HandleValue thisv = args.thisv(); + if (Test(thisv)) return Impl(cx, args); - return detail::CallMethodIfWrapped(cx, Test, Impl, args); + return detail::CallMethodIfWrapped(cx, Test, Impl, args); } -MOZ_ALWAYS_INLINE bool -CallNonGenericMethod(JSContext* cx, IsAcceptableThis Test, NativeImpl Impl, const CallArgs& args) -{ - HandleValue thisv = args.thisv(); - if (Test(thisv)) - return Impl(cx, args); +MOZ_ALWAYS_INLINE bool CallNonGenericMethod(JSContext* cx, + IsAcceptableThis Test, + NativeImpl Impl, + const CallArgs& args) { + HandleValue thisv = args.thisv(); + if (Test(thisv)) return Impl(cx, args); - return detail::CallMethodIfWrapped(cx, Test, Impl, args); + return detail::CallMethodIfWrapped(cx, Test, Impl, args); } -} // namespace JS +} // namespace JS #endif /* js_CallNonGenericMethod_h */ 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 @@ -12,10 +12,6 @@ #include "js/TypeDecls.h" #include "js/Utility.h" -namespace js { -class ExclusiveContext; -} // namespace js - class JSFlatString; namespace JS { @@ -26,95 +22,84 @@ * byte is treated as a 2-byte character, and there is no way to pass in a * string containing characters beyond U+00FF. */ -class Latin1Chars : public mozilla::Range -{ - 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) - : Base(const_cast(aBytes), aLength) - {} - Latin1Chars(const char* aBytes, size_t aLength) - : Base(reinterpret_cast(const_cast(aBytes)), aLength) - {} +class Latin1Chars : public mozilla::Range { + 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) + : Base(const_cast(aBytes), aLength) {} + Latin1Chars(const char* aBytes, size_t aLength) + : Base(reinterpret_cast(const_cast(aBytes)), + aLength) {} }; /* * A Latin1Chars, but with \0 termination for C compatibility. */ -class Latin1CharsZ : public mozilla::RangedPtr -{ - typedef mozilla::RangedPtr Base; - - public: - using CharT = Latin1Char; - - Latin1CharsZ() : Base(nullptr, 0) {} - - Latin1CharsZ(char* aBytes, size_t aLength) - : Base(reinterpret_cast(aBytes), aLength) - { - MOZ_ASSERT(aBytes[aLength] == '\0'); - } - - Latin1CharsZ(Latin1Char* aBytes, size_t aLength) - : Base(aBytes, aLength) - { - MOZ_ASSERT(aBytes[aLength] == '\0'); - } +class Latin1CharsZ : public mozilla::RangedPtr { + typedef mozilla::RangedPtr Base; + + public: + using CharT = Latin1Char; + + Latin1CharsZ() : Base(nullptr, 0) {} + + Latin1CharsZ(char* aBytes, size_t aLength) + : Base(reinterpret_cast(aBytes), aLength) { + MOZ_ASSERT(aBytes[aLength] == '\0'); + } + + Latin1CharsZ(Latin1Char* aBytes, size_t aLength) : Base(aBytes, aLength) { + MOZ_ASSERT(aBytes[aLength] == '\0'); + } - using Base::operator=; + using Base::operator=; - char* c_str() { return reinterpret_cast(get()); } + char* c_str() { return reinterpret_cast(get()); } }; -class UTF8Chars : public mozilla::Range -{ - typedef mozilla::Range Base; - - public: - using CharT = unsigned char; - - UTF8Chars() : Base() {} - UTF8Chars(char* aBytes, size_t aLength) - : Base(reinterpret_cast(aBytes), aLength) - {} - UTF8Chars(const char* aBytes, size_t aLength) - : Base(reinterpret_cast(const_cast(aBytes)), aLength) - {} +class UTF8Chars : public mozilla::Range { + typedef mozilla::Range Base; + + public: + using CharT = unsigned char; + + UTF8Chars() : Base() {} + UTF8Chars(char* aBytes, size_t aLength) + : Base(reinterpret_cast(aBytes), aLength) {} + UTF8Chars(const char* aBytes, size_t aLength) + : Base(reinterpret_cast(const_cast(aBytes)), + aLength) {} }; /* * SpiderMonkey also deals directly with UTF-8 encoded text in some places. */ -class UTF8CharsZ : public mozilla::RangedPtr -{ - typedef mozilla::RangedPtr Base; - - public: - using CharT = unsigned char; - - UTF8CharsZ() : Base(nullptr, 0) {} - - UTF8CharsZ(char* aBytes, size_t aLength) - : Base(reinterpret_cast(aBytes), aLength) - { - MOZ_ASSERT(aBytes[aLength] == '\0'); - } - - UTF8CharsZ(unsigned char* aBytes, size_t aLength) - : Base(aBytes, aLength) - { - MOZ_ASSERT(aBytes[aLength] == '\0'); - } +class UTF8CharsZ : public mozilla::RangedPtr { + typedef mozilla::RangedPtr Base; + + public: + using CharT = unsigned char; + + UTF8CharsZ() : Base(nullptr, 0) {} - using Base::operator=; + UTF8CharsZ(char* aBytes, size_t aLength) + : Base(reinterpret_cast(aBytes), aLength) { + MOZ_ASSERT(aBytes[aLength] == '\0'); + } - char* c_str() { return reinterpret_cast(get()); } + UTF8CharsZ(unsigned char* aBytes, size_t aLength) : Base(aBytes, aLength) { + MOZ_ASSERT(aBytes[aLength] == '\0'); + } + + using Base::operator=; + + char* c_str() { return reinterpret_cast(get()); } }; /* @@ -123,34 +108,30 @@ * 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'); +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); + validate(aLength); #endif - } + } - const void* get() const { return data_; } + const void* get() const { return data_; } - const char* c_str() const { return data_; } + const char* c_str() const { return data_; } - explicit operator bool() const { return data_ != nullptr; } + explicit operator bool() const { return data_ != nullptr; } - private: + private: #ifdef DEBUG - void validate(size_t aLength); + void validate(size_t aLength); #endif }; @@ -162,37 +143,34 @@ * manually interpreting UTF-16 extension characters embedded in the JS * string. */ -class TwoByteChars : public mozilla::Range -{ - 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) {} +class TwoByteChars : public mozilla::Range { + 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) {} }; /* * A TwoByteChars, but \0 terminated for compatibility with JSFlatString. */ -class TwoByteCharsZ : public mozilla::RangedPtr -{ - typedef mozilla::RangedPtr Base; - - public: - using CharT = char16_t; - - TwoByteCharsZ() : Base(nullptr, 0) {} - - TwoByteCharsZ(char16_t* chars, size_t length) - : Base(chars, length) - { - MOZ_ASSERT(chars[length] == '\0'); - } +class TwoByteCharsZ : public mozilla::RangedPtr { + typedef mozilla::RangedPtr Base; + + public: + using CharT = char16_t; + + TwoByteCharsZ() : Base(nullptr, 0) {} + + TwoByteCharsZ(char16_t* chars, size_t length) : Base(chars, length) { + MOZ_ASSERT(chars[length] == '\0'); + } - using Base::operator=; + using Base::operator=; }; typedef mozilla::RangedPtr ConstCharPtr; @@ -200,15 +178,15 @@ /* * Like TwoByteChars, but the chars are const. */ -class ConstTwoByteChars : public mozilla::Range -{ - typedef mozilla::Range Base; +class ConstTwoByteChars : public mozilla::Range { + typedef mozilla::Range Base; - public: - using CharT = char16_t; + public: + using CharT = char16_t; - ConstTwoByteChars() : Base() {} - ConstTwoByteChars(const char16_t* aChars, size_t aLength) : Base(aChars, aLength) {} + ConstTwoByteChars() : Base() {} + ConstTwoByteChars(const char16_t* aChars, size_t aLength) + : Base(aChars, aLength) {} }; /* @@ -221,23 +199,22 @@ * will return a nullptr chars (which can be tested for with the ! operator). * This method cannot trigger GC. */ -extern Latin1CharsZ -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); +extern Latin1CharsZ LossyTwoByteCharsToNewLatin1CharsZ( + JSContext* cx, const mozilla::Range tbchars); + +inline Latin1CharsZ LossyTwoByteCharsToNewLatin1CharsZ(JSContext* 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); +extern UTF8CharsZ CharsToNewUTF8CharsZ(JSContext* maybeCx, + const mozilla::Range chars); -JS_PUBLIC_API(uint32_t) -Utf8ToOneUcs4Char(const uint8_t* utf8Buffer, int utf8Length); +JS_PUBLIC_API uint32_t Utf8ToOneUcs4Char(const uint8_t* utf8Buffer, + int utf8Length); /* * Inflate bytes in UTF-8 encoding to char16_t. @@ -245,32 +222,31 @@ * - On success, returns a malloc'd TwoByteCharsZ, and updates |outlen| to hold * its length; the length value excludes the trailing null. */ -extern JS_PUBLIC_API(TwoByteCharsZ) -UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); +extern JS_PUBLIC_API TwoByteCharsZ UTF8CharsToNewTwoByteCharsZ( + JSContext* cx, const UTF8Chars utf8, size_t* outlen); /* * Like UTF8CharsToNewTwoByteCharsZ, but for ConstUTF8CharsZ. */ -extern JS_PUBLIC_API(TwoByteCharsZ) -UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen); +extern JS_PUBLIC_API TwoByteCharsZ UTF8CharsToNewTwoByteCharsZ( + JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen); /* - * 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. + * The same as UTF8CharsToNewTwoByteCharsZ(), except that any malformed UTF-8 + * characters will be replaced by \uFFFD. No exception will be thrown for + * malformed UTF-8 input. */ -extern JS_PUBLIC_API(TwoByteCharsZ) -LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); +extern JS_PUBLIC_API TwoByteCharsZ LossyUTF8CharsToNewTwoByteCharsZ( + JSContext* cx, const UTF8Chars utf8, size_t* outlen); -extern JS_PUBLIC_API(TwoByteCharsZ) -LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen); +extern JS_PUBLIC_API TwoByteCharsZ LossyUTF8CharsToNewTwoByteCharsZ( + JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen); /* * Returns the length of the char buffer required to encode |s| as UTF8. * Does not include the null-terminator. */ -JS_PUBLIC_API(size_t) -GetDeflatedUTF8StringLength(JSFlatString* s); +JS_PUBLIC_API size_t GetDeflatedUTF8StringLength(JSFlatString* s); /* * Encode |src| as UTF8. The caller must either ensure |dst| has enough space @@ -284,35 +260,31 @@ * 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, - size_t* dstlenp = nullptr, size_t* numcharsp = nullptr); +JS_PUBLIC_API void 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 -}; +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); +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. + * 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) +extern JS_PUBLIC_API Latin1CharsZ UTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); /* @@ -320,17 +292,22 @@ * storing its length (excluding null terminator) in |*outlen|. Non-Latin-1 * codepoints are replaced by '?'. Returns Latin1CharsZ() on failure. */ -extern JS_PUBLIC_API(Latin1CharsZ) -LossyUTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen); +extern JS_PUBLIC_API Latin1CharsZ LossyUTF8CharsToNewLatin1CharsZ( + JSContext* cx, const UTF8Chars utf8, size_t* outlen); /* * 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); +extern JS_PUBLIC_API bool StringIsASCII(const char* s); + +/* + * Returns true if the given length-delimited string is a valid UTF-8 string, + * false otherwise. + */ +extern JS_PUBLIC_API bool StringIsUTF8(const uint8_t* s, uint32_t length); -} // namespace JS +} // namespace JS inline void JS_free(JS::Latin1CharsZ& ptr) { js_free((void*)ptr.get()); } inline void JS_free(JS::UTF8CharsZ& ptr) { js_free((void*)ptr.get()); } 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 @@ -34,24 +34,17 @@ // This is equal to JSFunction::class_. Use it in places where you don't want // to #include jsfun.h. -extern JS_FRIEND_DATA(const js::Class* const) FunctionClassPtr; +extern JS_FRIEND_DATA const js::Class* const FunctionClassPtr; -} // namespace js +} // namespace js namespace JS { -class AutoIdVector; - /** * The answer to a successful query as to whether an object is an Array per * ES6's internal |IsArray| operation (as exposed by |Array.isArray|). */ -enum class IsArrayAnswer -{ - Array, - NotArray, - RevokedProxy -}; +enum class IsArrayAnswer { Array, NotArray, RevokedProxy }; /** * ES6 7.2.2. @@ -65,8 +58,8 @@ * revoked, or if |obj| is a proxy whose target (at any number of hops) is a * revoked proxy, this method throws a TypeError and returns false. */ -extern JS_PUBLIC_API(bool) -IsArray(JSContext* cx, HandleObject obj, bool* isArray); +extern JS_PUBLIC_API bool IsArray(JSContext* cx, HandleObject obj, + bool* isArray); /** * Identical to IsArray above, but the nature of the object (if successfully @@ -76,8 +69,8 @@ * * Most users will want the overload above, not this one. */ -extern JS_PUBLIC_API(bool) -IsArray(JSContext* cx, HandleObject obj, IsArrayAnswer* answer); +extern JS_PUBLIC_API bool IsArray(JSContext* cx, HandleObject obj, + IsArrayAnswer* answer); /** * Per ES6, the [[DefineOwnProperty]] internal method has three different @@ -112,143 +105,229 @@ * argv.rval().setBoolean(bool(result)); * return true; */ -class ObjectOpResult -{ - private: - /** - * code_ is either one of the special codes OkCode or Uninitialized, or - * an error code. For now the error codes are private to the JS engine; - * they're defined in js/src/js.msg. - * - * code_ is uintptr_t (rather than uint32_t) for the convenience of the - * JITs, which would otherwise have to deal with either padding or stack - * alignment on 64-bit platforms. - */ - uintptr_t code_; - - public: - enum SpecialCodes : uintptr_t { - OkCode = 0, - Uninitialized = uintptr_t(-1) - }; - - ObjectOpResult() : code_(Uninitialized) {} - - /* Return true if succeed() was called. */ - bool ok() const { - MOZ_ASSERT(code_ != Uninitialized); - return code_ == OkCode; - } - - explicit operator bool() const { return ok(); } - - /* Set this ObjectOpResult to true and return true. */ - bool succeed() { - code_ = OkCode; - return true; - } - - /* - * Set this ObjectOpResult to false with an error code. - * - * Always returns true, as a convenience. Typical usage will be: - * - * if (funny condition) - * return result.fail(JSMSG_CANT_DO_THE_THINGS); - * - * The true return value indicates that no exception is pending, and it - * would be OK to ignore the failure and continue. - */ - bool fail(uint32_t msg) { - MOZ_ASSERT(msg != OkCode); - code_ = msg; - return true; - } - - JS_PUBLIC_API(bool) failCantRedefineProp(); - JS_PUBLIC_API(bool) failReadOnly(); - JS_PUBLIC_API(bool) failGetterOnly(); - JS_PUBLIC_API(bool) failCantDelete(); - - JS_PUBLIC_API(bool) failCantSetInterposed(); - JS_PUBLIC_API(bool) failCantDefineWindowElement(); - JS_PUBLIC_API(bool) failCantDeleteWindowElement(); - JS_PUBLIC_API(bool) failCantDeleteWindowNamedProperty(); - JS_PUBLIC_API(bool) failCantPreventExtensions(); - JS_PUBLIC_API(bool) failCantSetProto(); - JS_PUBLIC_API(bool) failNoNamedSetter(); - JS_PUBLIC_API(bool) failNoIndexedSetter(); - - uint32_t failureCode() const { - MOZ_ASSERT(!ok()); - return uint32_t(code_); - } - - /* - * Report an error or warning if necessary; return true to proceed and - * false if an error was reported. Call this when failure should cause - * a warning if extraWarnings are enabled. - * - * The precise rules are like this: - * - * - If ok(), then we succeeded. Do nothing and return true. - * - Otherwise, if |strict| is true, or if cx has both extraWarnings and - * werrorOption enabled, throw a TypeError and return false. - * - Otherwise, if cx has extraWarnings enabled, emit a warning and - * return true. - * - Otherwise, do nothing and return true. - */ - bool checkStrictErrorOrWarning(JSContext* cx, HandleObject obj, HandleId id, bool strict) { - if (ok()) - return true; - return reportStrictErrorOrWarning(cx, obj, id, strict); - } - - /* - * The same as checkStrictErrorOrWarning(cx, id, strict), except the - * operation is not associated with a particular property id. This is - * used for [[PreventExtensions]] and [[SetPrototypeOf]]. failureCode() - * must not be an error that has "{0}" in the error message. - */ - bool checkStrictErrorOrWarning(JSContext* cx, HandleObject obj, bool strict) { - return ok() || reportStrictErrorOrWarning(cx, obj, strict); - } - - /* Throw a TypeError. Call this only if !ok(). */ - bool reportError(JSContext* cx, HandleObject obj, HandleId id) { - return reportStrictErrorOrWarning(cx, obj, id, true); - } - - /* - * The same as reportError(cx, obj, id), except the operation is not - * associated with a particular property id. - */ - bool reportError(JSContext* cx, HandleObject obj) { - return reportStrictErrorOrWarning(cx, obj, true); - } - - /* Helper function for checkStrictErrorOrWarning's slow path. */ - JS_PUBLIC_API(bool) reportStrictErrorOrWarning(JSContext* cx, HandleObject obj, HandleId id, bool strict); - JS_PUBLIC_API(bool) reportStrictErrorOrWarning(JSContext* cx, HandleObject obj, bool strict); - - /* - * Convenience method. Return true if ok() or if strict is false; otherwise - * throw a TypeError and return false. - */ - bool checkStrict(JSContext* cx, HandleObject obj, HandleId id) { - return checkStrictErrorOrWarning(cx, obj, id, true); - } - - /* - * Convenience method. The same as checkStrict(cx, id), except the - * operation is not associated with a particular property id. - */ - bool checkStrict(JSContext* cx, HandleObject obj) { - return checkStrictErrorOrWarning(cx, obj, true); - } +class ObjectOpResult { + private: + /** + * code_ is either one of the special codes OkCode or Uninitialized, or + * an error code. For now the error codes are private to the JS engine; + * they're defined in js/src/js.msg. + * + * code_ is uintptr_t (rather than uint32_t) for the convenience of the + * JITs, which would otherwise have to deal with either padding or stack + * alignment on 64-bit platforms. + */ + uintptr_t code_; + + public: + enum SpecialCodes : uintptr_t { OkCode = 0, Uninitialized = uintptr_t(-1) }; + + ObjectOpResult() : code_(Uninitialized) {} + + /* Return true if succeed() was called. */ + bool ok() const { + MOZ_ASSERT(code_ != Uninitialized); + return code_ == OkCode; + } + + explicit operator bool() const { return ok(); } + + /* Set this ObjectOpResult to true and return true. */ + bool succeed() { + code_ = OkCode; + return true; + } + + /* + * Set this ObjectOpResult to false with an error code. + * + * Always returns true, as a convenience. Typical usage will be: + * + * if (funny condition) + * return result.fail(JSMSG_CANT_DO_THE_THINGS); + * + * The true return value indicates that no exception is pending, and it + * would be OK to ignore the failure and continue. + */ + bool fail(uint32_t msg) { + MOZ_ASSERT(msg != OkCode); + code_ = msg; + return true; + } + + JS_PUBLIC_API bool failCantRedefineProp(); + JS_PUBLIC_API bool failReadOnly(); + JS_PUBLIC_API bool failGetterOnly(); + JS_PUBLIC_API bool failCantDelete(); + + JS_PUBLIC_API bool failCantSetInterposed(); + JS_PUBLIC_API bool failCantDefineWindowElement(); + JS_PUBLIC_API bool failCantDeleteWindowElement(); + JS_PUBLIC_API bool failCantDeleteWindowNamedProperty(); + JS_PUBLIC_API bool failCantPreventExtensions(); + JS_PUBLIC_API bool failCantSetProto(); + JS_PUBLIC_API bool failNoNamedSetter(); + JS_PUBLIC_API bool failNoIndexedSetter(); + + uint32_t failureCode() const { + MOZ_ASSERT(!ok()); + return uint32_t(code_); + } + + /* + * Report an error or warning if necessary; return true to proceed and + * false if an error was reported. Call this when failure should cause + * a warning if extraWarnings are enabled. + * + * The precise rules are like this: + * + * - If ok(), then we succeeded. Do nothing and return true. + * - Otherwise, if |strict| is true, or if cx has both extraWarnings and + * werrorOption enabled, throw a TypeError and return false. + * - Otherwise, if cx has extraWarnings enabled, emit a warning and + * return true. + * - Otherwise, do nothing and return true. + */ + bool checkStrictErrorOrWarning(JSContext* cx, HandleObject obj, HandleId id, + bool strict) { + if (ok()) return true; + return reportStrictErrorOrWarning(cx, obj, id, strict); + } + + /* + * The same as checkStrictErrorOrWarning(cx, id, strict), except the + * operation is not associated with a particular property id. This is + * used for [[PreventExtensions]] and [[SetPrototypeOf]]. failureCode() + * must not be an error that has "{0}" in the error message. + */ + bool checkStrictErrorOrWarning(JSContext* cx, HandleObject obj, bool strict) { + return ok() || reportStrictErrorOrWarning(cx, obj, strict); + } + + /* Throw a TypeError. Call this only if !ok(). */ + bool reportError(JSContext* cx, HandleObject obj, HandleId id) { + return reportStrictErrorOrWarning(cx, obj, id, true); + } + + /* + * The same as reportError(cx, obj, id), except the operation is not + * associated with a particular property id. + */ + bool reportError(JSContext* cx, HandleObject obj) { + return reportStrictErrorOrWarning(cx, obj, true); + } + + /* Helper function for checkStrictErrorOrWarning's slow path. */ + JS_PUBLIC_API bool reportStrictErrorOrWarning(JSContext* cx, HandleObject obj, + HandleId id, bool strict); + JS_PUBLIC_API bool reportStrictErrorOrWarning(JSContext* cx, HandleObject obj, + bool strict); + + /* + * Convenience method. Return true if ok() or if strict is false; otherwise + * throw a TypeError and return false. + */ + bool checkStrict(JSContext* cx, HandleObject obj, HandleId id) { + return checkStrictErrorOrWarning(cx, obj, id, true); + } + + /* + * Convenience method. The same as checkStrict(cx, id), except the + * operation is not associated with a particular property id. + */ + bool checkStrict(JSContext* cx, HandleObject obj) { + return checkStrictErrorOrWarning(cx, obj, true); + } +}; + +class PropertyResult { + union { + js::Shape* shape_; + uintptr_t bits_; + }; + + static const uintptr_t NotFound = 0; + static const uintptr_t NonNativeProperty = 1; + static const uintptr_t DenseOrTypedArrayElement = 1; + + public: + PropertyResult() : bits_(NotFound) {} + + explicit PropertyResult(js::Shape* propertyShape) : shape_(propertyShape) { + MOZ_ASSERT(!isFound() || isNativeProperty()); + } + + explicit operator bool() const { return isFound(); } + + bool isFound() const { return bits_ != NotFound; } + + bool isNonNativeProperty() const { return bits_ == NonNativeProperty; } + + bool isDenseOrTypedArrayElement() const { + return bits_ == DenseOrTypedArrayElement; + } + + bool isNativeProperty() const { return isFound() && !isNonNativeProperty(); } + + js::Shape* maybeShape() const { + MOZ_ASSERT(!isNonNativeProperty()); + return isFound() ? shape_ : nullptr; + } + + js::Shape* shape() const { + MOZ_ASSERT(isNativeProperty()); + return shape_; + } + + void setNotFound() { bits_ = NotFound; } + + void setNativeProperty(js::Shape* propertyShape) { + shape_ = propertyShape; + MOZ_ASSERT(isNativeProperty()); + } + + void setNonNativeProperty() { bits_ = NonNativeProperty; } + + void setDenseOrTypedArrayElement() { bits_ = DenseOrTypedArrayElement; } + + void trace(JSTracer* trc); +}; + +} // namespace JS + +namespace js { + +template +class WrappedPtrOperations { + const JS::PropertyResult& value() const { + return static_cast(this)->get(); + } + + public: + bool isFound() const { return value().isFound(); } + explicit operator bool() const { return bool(value()); } + js::Shape* maybeShape() const { return value().maybeShape(); } + js::Shape* shape() const { return value().shape(); } + bool isNativeProperty() const { return value().isNativeProperty(); } + bool isNonNativeProperty() const { return value().isNonNativeProperty(); } + bool isDenseOrTypedArrayElement() const { + return value().isDenseOrTypedArrayElement(); + } + js::Shape* asTaggedShape() const { return value().asTaggedShape(); } }; -} // namespace JS +template +class MutableWrappedPtrOperations + : public WrappedPtrOperations { + JS::PropertyResult& value() { return static_cast(this)->get(); } + + public: + void setNotFound() { value().setNotFound(); } + void setNativeProperty(js::Shape* shape) { value().setNativeProperty(shape); } + void setNonNativeProperty() { value().setNonNativeProperty(); } + void setDenseOrTypedArrayElement() { value().setDenseOrTypedArrayElement(); } +}; + +} // namespace js // JSClass operation signatures. @@ -257,24 +336,20 @@ * be a string (Unicode property identifier) or an int (element index). The * *vp out parameter, on success, is the new property value after the action. */ -typedef bool -(* JSGetterOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleValue vp); +typedef bool (*JSGetterOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::MutableHandleValue vp); /** Add a property named by id to obj. */ -typedef bool -(* JSAddPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v); +typedef bool (*JSAddPropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, JS::HandleValue v); /** * Set a property named by id in obj, treating the assignment as strict * mode code if strict is true. Note the jsid id type -- id may be a string - * (Unicode property identifier) or an int (element index). The *vp out - * parameter, on success, is the new property value after the - * set. - */ -typedef bool -(* JSSetterOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleValue vp, JS::ObjectOpResult& result); + * (Unicode property identifier) or an int (element index). + */ +typedef bool (*JSSetterOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::HandleValue v, JS::ObjectOpResult& result); /** * Delete a property named by id in obj. @@ -291,9 +366,8 @@ * property, or an inherited property, is allowed -- it's just pointless), * call result.succeed() and return true. */ -typedef bool -(* JSDeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::ObjectOpResult& result); +typedef bool (*JSDeletePropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, JS::ObjectOpResult& result); /** * The type of ObjectOps::enumerate. This callback overrides a portion of @@ -308,24 +382,23 @@ * object's property keys. If `enumerableOnly` is true, the callback should only * add enumerable properties. */ -typedef bool -(* JSNewEnumerateOp)(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties, - bool enumerableOnly); +typedef bool (*JSNewEnumerateOp)(JSContext* cx, JS::HandleObject obj, + JS::AutoIdVector& properties, + bool enumerableOnly); /** * The old-style JSClass.enumerate op should define all lazy properties not * yet reflected in obj. */ -typedef bool -(* JSEnumerateOp)(JSContext* cx, JS::HandleObject obj); +typedef bool (*JSEnumerateOp)(JSContext* cx, JS::HandleObject obj); /** * The type of ObjectOps::funToString. This callback allows an object to * provide a custom string to use when Function.prototype.toString is invoked on * that object. A null return value means OOM. */ -typedef JSString* -(* JSFunToStringOp)(JSContext* cx, JS::HandleObject obj, unsigned indent); +typedef JSString* (*JSFunToStringOp)(JSContext* cx, JS::HandleObject obj, + bool isToSource); /** * Resolve a lazy property named by id in obj by defining it directly in obj. @@ -336,9 +409,8 @@ * 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, - bool* resolvedp); +typedef bool (*JSResolveOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, bool* resolvedp); /** * A class with a resolve hook can optionally have a mayResolve hook. This hook @@ -351,30 +423,23 @@ * can be nullptr: during JIT compilation we sometimes know the Class but not * the object. */ -typedef bool -(* JSMayResolveOp)(const JSAtomState& names, jsid id, JSObject* maybeObj); +typedef bool (*JSMayResolveOp)(const JSAtomState& names, jsid id, + JSObject* maybeObj); /** * Finalize obj, which the garbage collector has determined to be unreachable * from other live objects or from GC roots. Obviously, finalizers must never * store a reference to obj. */ -typedef void -(* JSFinalizeOp)(JSFreeOp* fop, JSObject* obj); - -/** Finalizes external strings created by JS_NewExternalString. */ -struct JSStringFinalizer { - void (*finalize)(JS::Zone* zone, const JSStringFinalizer* fin, char16_t* chars); -}; +typedef void (*JSFinalizeOp)(JSFreeOp* fop, JSObject* obj); /** * Check whether v is an instance of obj. Return false on error or exception, * true on success with true in *bp if v is an instance of obj, false in * *bp otherwise. */ -typedef bool -(* JSHasInstanceOp)(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp, - bool* bp); +typedef bool (*JSHasInstanceOp)(JSContext* cx, JS::HandleObject obj, + JS::MutableHandleValue vp, bool* bp); /** * Function type for trace operation of the class called to enumerate all @@ -390,384 +455,353 @@ * JS_IsGCMarkingTracer and apply a special code like emptying caches or * marking its native structures. */ -typedef void -(* JSTraceOp)(JSTracer* trc, JSObject* obj); +typedef void (*JSTraceOp)(JSTracer* trc, JSObject* obj); -typedef JSObject* -(* JSWeakmapKeyDelegateOp)(JSObject* obj); +typedef JSObject* (*JSWeakmapKeyDelegateOp)(JSObject* obj); -typedef void -(* JSObjectMovedOp)(JSObject* obj, const JSObject* old); +typedef size_t (*JSObjectMovedOp)(JSObject* obj, JSObject* old); /* js::Class operation signatures. */ namespace js { -typedef bool -(* LookupPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleObject objp, JS::MutableHandle propp); -typedef bool -(* DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc, - JS::ObjectOpResult& result); -typedef bool -(* HasPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); -typedef bool -(* GetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleValue receiver, JS::HandleId id, - JS::MutableHandleValue vp); -typedef bool -(* SetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, - JS::HandleValue receiver, JS::ObjectOpResult& result); -typedef bool -(* GetOwnPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); -typedef bool -(* DeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::ObjectOpResult& result); - -typedef bool -(* WatchOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); - -typedef bool -(* UnwatchOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id); - -class JS_FRIEND_API(ElementAdder) -{ - public: - enum GetBehavior { - // Check if the element exists before performing the Get and preserve - // holes. - CheckHasElemPreserveHoles, - - // Perform a Get operation, like obj[index] in JS. - GetElement - }; - - private: - // Only one of these is used. - JS::RootedObject resObj_; - JS::Value* vp_; +typedef bool (*LookupPropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, JS::MutableHandleObject objp, + JS::MutableHandle propp); +typedef bool (*DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, + JS::Handle desc, + JS::ObjectOpResult& result); +typedef bool (*HasPropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, bool* foundp); +typedef bool (*GetPropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleValue receiver, JS::HandleId id, + JS::MutableHandleValue vp); +typedef bool (*SetPropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, JS::HandleValue v, + JS::HandleValue receiver, + JS::ObjectOpResult& result); +typedef bool (*GetOwnPropertyOp)( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::MutableHandle desc); +typedef bool (*DeletePropertyOp)(JSContext* cx, JS::HandleObject obj, + JS::HandleId id, JS::ObjectOpResult& result); + +class JS_FRIEND_API ElementAdder { + public: + enum GetBehavior { + // Check if the element exists before performing the Get and preserve + // holes. + CheckHasElemPreserveHoles, + + // Perform a Get operation, like obj[index] in JS. + GetElement + }; + + private: + // Only one of these is used. + JS::RootedObject resObj_; + JS::Value* vp_; - uint32_t index_; + uint32_t index_; #ifdef DEBUG - uint32_t length_; + uint32_t length_; #endif - GetBehavior getBehavior_; + GetBehavior getBehavior_; - public: - ElementAdder(JSContext* cx, JSObject* obj, uint32_t length, GetBehavior behavior) - : resObj_(cx, obj), vp_(nullptr), index_(0), + public: + ElementAdder(JSContext* cx, JSObject* obj, uint32_t 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), + getBehavior_(behavior) { + } + ElementAdder(JSContext* cx, JS::Value* vp, uint32_t length, + GetBehavior behavior) + : resObj_(cx), + vp_(vp), + index_(0), #ifdef DEBUG length_(length), #endif - getBehavior_(behavior) - {} + getBehavior_(behavior) { + } - GetBehavior getBehavior() const { return getBehavior_; } + GetBehavior getBehavior() const { return getBehavior_; } - bool append(JSContext* cx, JS::HandleValue v); - void appendHole(); + bool append(JSContext* cx, JS::HandleValue v); + void appendHole(); }; -typedef bool -(* GetElementsOp)(JSContext* cx, JS::HandleObject obj, uint32_t begin, uint32_t end, - ElementAdder* adder); +typedef bool (*GetElementsOp)(JSContext* cx, JS::HandleObject obj, + uint32_t begin, uint32_t end, + ElementAdder* adder); -typedef void -(* FinalizeOp)(FreeOp* fop, JSObject* obj); +typedef void (*FinalizeOp)(FreeOp* fop, JSObject* obj); // 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; +#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; \ + } \ + JSEnumerateOp getEnumerate() const { \ + return cOps ? cOps->enumerate : nullptr; \ + } \ + JSNewEnumerateOp getNewEnumerate() const { \ + return cOps ? cOps->newEnumerate : 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); \ + } + +// XXX: MOZ_NONHEAP_CLASS allows objects to be created statically or on the +// stack. We actually want to ban stack objects too, but that's currently not +// possible. So we define JS_STATIC_CLASS to make the intention clearer. +#define JS_STATIC_CLASS MOZ_NONHEAP_CLASS + +struct JS_STATIC_CLASS ClassOps { + /* Function pointer members (may be null). */ + JSAddPropertyOp addProperty; + JSDeletePropertyOp delProperty; + JSEnumerateOp enumerate; + JSNewEnumerateOp newEnumerate; + 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); -/** Callback for custom post-processing after class initialization via ClassSpec. */ +/** + * Callback for custom post-processing after class initialization via + * ClassSpec. + */ typedef bool (*FinishClassInitOp)(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto); const size_t JSCLASS_CACHED_PROTO_WIDTH = 6; -struct ClassSpec -{ - // All properties except flags should be accessed through accessor. - ClassObjectCreationOp createConstructor_; - ClassObjectCreationOp createPrototype_; - const JSFunctionSpec* constructorFunctions_; - const JSPropertySpec* constructorProperties_; - const JSFunctionSpec* prototypeFunctions_; - const JSPropertySpec* prototypeProperties_; - FinishClassInitOp finishInit_; - uintptr_t flags; - - static const size_t ProtoKeyWidth = JSCLASS_CACHED_PROTO_WIDTH; - - 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_; } - - bool delegated() const { - return (flags & IsDelegated); - } - - // The ProtoKey this class inherits from. - JSProtoKey inheritanceProtoKey() const { - MOZ_ASSERT(defined()); - static_assert(JSProto_Null == 0, "zeroed key must be null"); - - // Default: Inherit from Object. - if (!(flags & ProtoKeyMask)) - return JSProto_Object; - - return JSProtoKey(flags & ProtoKeyMask); - } - - bool shouldDefineConstructor() const { - MOZ_ASSERT(defined()); - return !(flags & DontDefineConstructor); - } - - const ClassSpec* delegatedClassSpec() const { - MOZ_ASSERT(delegated()); - return reinterpret_cast(createConstructor_); - } - - ClassObjectCreationOp createConstructorHook() const { - if (delegated()) - return delegatedClassSpec()->createConstructorHook(); - return createConstructor_; - } - ClassObjectCreationOp createPrototypeHook() const { - if (delegated()) - return delegatedClassSpec()->createPrototypeHook(); - return createPrototype_; - } - const JSFunctionSpec* constructorFunctions() const { - if (delegated()) - return delegatedClassSpec()->constructorFunctions(); - return constructorFunctions_; - } - const JSPropertySpec* constructorProperties() const { - if (delegated()) - return delegatedClassSpec()->constructorProperties(); - return constructorProperties_; - } - const JSFunctionSpec* prototypeFunctions() const { - if (delegated()) - return delegatedClassSpec()->prototypeFunctions(); - return prototypeFunctions_; - } - const JSPropertySpec* prototypeProperties() const { - if (delegated()) - return delegatedClassSpec()->prototypeProperties(); - return prototypeProperties_; - } - FinishClassInitOp finishInitHook() const { - if (delegated()) - return delegatedClassSpec()->finishInitHook(); - return finishInit_; - } -}; - -struct ClassExtension -{ - /** - * If an object is used as a key in a weakmap, it may be desirable for the - * garbage collector to keep that object around longer than it otherwise - * would. A common case is when the key is a wrapper around an object in - * another compartment, and we want to avoid collecting the wrapper (and - * removing the weakmap entry) as long as the wrapped object is alive. In - * that case, the wrapped object is returned by the wrapper's - * weakmapKeyDelegateOp hook. As long as the wrapper is used as a weakmap - * key, it will not be collected (and remain in the weakmap) until the - * wrapped object is collected. - */ - JSWeakmapKeyDelegateOp weakmapKeyDelegateOp; - - /** - * Optional hook called when an object is moved by a compacting GC. - * - * There may exist weak pointers to an object that are not traced through - * when the normal trace APIs are used, for example objects in the wrapper - * cache. This hook allows these pointers to be updated. - * - * Note that this hook can be called before JS_NewObject() returns if a GC - * is triggered during construction of the object. This can happen for - * global objects for example. - */ - JSObjectMovedOp objectMovedOp; +struct JS_STATIC_CLASS ClassSpec { + ClassObjectCreationOp createConstructor; + ClassObjectCreationOp createPrototype; + const JSFunctionSpec* constructorFunctions; + const JSPropertySpec* constructorProperties; + const JSFunctionSpec* prototypeFunctions; + const JSPropertySpec* prototypeProperties; + FinishClassInitOp finishInit; + uintptr_t flags; + + static const size_t ProtoKeyWidth = JSCLASS_CACHED_PROTO_WIDTH; + + static const uintptr_t ProtoKeyMask = (1 << ProtoKeyWidth) - 1; + static const uintptr_t DontDefineConstructor = 1 << ProtoKeyWidth; + + bool defined() const { return !!createConstructor; } + + // The ProtoKey this class inherits from. + JSProtoKey inheritanceProtoKey() const { + MOZ_ASSERT(defined()); + static_assert(JSProto_Null == 0, "zeroed key must be null"); + + // Default: Inherit from Object. + if (!(flags & ProtoKeyMask)) return JSProto_Object; + + return JSProtoKey(flags & ProtoKeyMask); + } + + bool shouldDefineConstructor() const { + MOZ_ASSERT(defined()); + return !(flags & DontDefineConstructor); + } }; -inline ClassObjectCreationOp DELEGATED_CLASSSPEC(const ClassSpec* spec) { - return reinterpret_cast(const_cast(spec)); -} +struct JS_STATIC_CLASS ClassExtension { + /** + * If an object is used as a key in a weakmap, it may be desirable for the + * garbage collector to keep that object around longer than it otherwise + * would. A common case is when the key is a wrapper around an object in + * another compartment, and we want to avoid collecting the wrapper (and + * removing the weakmap entry) as long as the wrapped object is alive. In + * that case, the wrapped object is returned by the wrapper's + * weakmapKeyDelegateOp hook. As long as the wrapper is used as a weakmap + * key, it will not be collected (and remain in the weakmap) until the + * wrapped object is collected. + */ + JSWeakmapKeyDelegateOp weakmapKeyDelegateOp; + + /** + * Optional hook called when an object is moved by generational or + * compacting GC. + * + * There may exist weak pointers to an object that are not traced through + * when the normal trace APIs are used, for example objects in the wrapper + * cache. This hook allows these pointers to be updated. + * + * Note that this hook can be called before JS_NewObject() returns if a GC + * is triggered during construction of the object. This can happen for + * global objects for example. + * + * The function should return the difference between nursery bytes used and + * tenured bytes used, which may be nonzero e.g. if some nursery-allocated + * data beyond the actual GC thing is moved into malloced memory. + * + * This is used to compute the nursery promotion rate. + */ + JSObjectMovedOp objectMovedOp; +}; -#define JS_NULL_CLASS_SPEC nullptr -#define JS_NULL_CLASS_EXT 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; +struct JS_STATIC_CLASS ObjectOps { + LookupPropertyOp lookupProperty; + DefinePropertyOp defineProperty; + HasPropertyOp hasProperty; + GetPropertyOp getProperty; + SetPropertyOp setProperty; + GetOwnPropertyOp getOwnPropertyDescriptor; + DeletePropertyOp deleteProperty; + GetElementsOp getElements; + JSFunToStringOp funToString; }; #define JS_NULL_OBJECT_OPS nullptr -} // namespace js +} // namespace js // Classes, objects, and properties. 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; +struct JS_STATIC_CLASS JSClassOps { + /* Function pointer members (may be null). */ + JSAddPropertyOp addProperty; + JSDeletePropertyOp delProperty; + JSEnumerateOp enumerate; + JSNewEnumerateOp newEnumerate; + 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(JSClassOps, JSFreeOp); + JS_CLASS_MEMBERS(JSClassOps, JSFreeOp); - void* reserved[3]; + void* reserved[3]; }; -#define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot -#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 -#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 -#define JSCLASS_USERBIT1 (1<<7) // Reserved for embeddings. +// Objects have private slot. +static const uint32_t JSCLASS_HAS_PRIVATE = 1 << 0; -// To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or -// JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where -// n is a constant in [1, 255]. Reserved slots are indexed from 0 to n-1. -#define JSCLASS_RESERVED_SLOTS_SHIFT 8 // room for 8 flags below */ -#define JSCLASS_RESERVED_SLOTS_WIDTH 8 // and 16 above this field */ -#define JSCLASS_RESERVED_SLOTS_MASK JS_BITMASK(JSCLASS_RESERVED_SLOTS_WIDTH) -#define JSCLASS_HAS_RESERVED_SLOTS(n) (((n) & JSCLASS_RESERVED_SLOTS_MASK) \ - << JSCLASS_RESERVED_SLOTS_SHIFT) -#define JSCLASS_RESERVED_SLOTS(clasp) (((clasp)->flags \ - >> JSCLASS_RESERVED_SLOTS_SHIFT) \ - & JSCLASS_RESERVED_SLOTS_MASK) - -#define JSCLASS_HIGH_FLAGS_SHIFT (JSCLASS_RESERVED_SLOTS_SHIFT + \ - JSCLASS_RESERVED_SLOTS_WIDTH) - -#define JSCLASS_IS_ANONYMOUS (1<<(JSCLASS_HIGH_FLAGS_SHIFT+0)) -#define JSCLASS_IS_GLOBAL (1<<(JSCLASS_HIGH_FLAGS_SHIFT+1)) -#define JSCLASS_INTERNAL_FLAG2 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+2)) -#define JSCLASS_INTERNAL_FLAG3 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+3)) +// Class's initialization code will call `SetNewObjectMetadata` itself. +static const uint32_t JSCLASS_DELAY_METADATA_BUILDER = 1 << 1; + +// Class is an XPCWrappedNative. WeakMaps use this to override the wrapper +// disposal mechanism. +static const uint32_t JSCLASS_IS_WRAPPED_NATIVE = 1 << 2; + +// Private is `nsISupports*`. +static const uint32_t JSCLASS_PRIVATE_IS_NSISUPPORTS = 1 << 3; + +// Objects are DOM. +static const uint32_t JSCLASS_IS_DOMJSCLASS = 1 << 4; + +// 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. +static const uint32_t JSCLASS_HAS_XRAYED_CONSTRUCTOR = 1 << 5; + +// Objects of this class act like the value undefined, in some contexts. +static const uint32_t JSCLASS_EMULATES_UNDEFINED = 1 << 6; + +// Reserved for embeddings. +static const uint32_t JSCLASS_USERBIT1 = 1 << 7; -#define JSCLASS_IS_PROXY (1<<(JSCLASS_HIGH_FLAGS_SHIFT+4)) +// To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or +// JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where n +// is a constant in [1, 255]. Reserved slots are indexed from 0 to n-1. -#define JSCLASS_SKIP_NURSERY_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+5)) +// Room for 8 flags below ... +static const uintptr_t JSCLASS_RESERVED_SLOTS_SHIFT = 8; +// ... and 16 above this field. +static const uint32_t JSCLASS_RESERVED_SLOTS_WIDTH = 8; + +static const uint32_t JSCLASS_RESERVED_SLOTS_MASK = + JS_BITMASK(JSCLASS_RESERVED_SLOTS_WIDTH); + +#define JSCLASS_HAS_RESERVED_SLOTS(n) \ + (((n)&JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT) +#define JSCLASS_RESERVED_SLOTS(clasp) \ + (((clasp)->flags >> JSCLASS_RESERVED_SLOTS_SHIFT) & \ + JSCLASS_RESERVED_SLOTS_MASK) + +#define JSCLASS_HIGH_FLAGS_SHIFT \ + (JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH) + +static const uint32_t JSCLASS_IS_ANONYMOUS = 1 + << (JSCLASS_HIGH_FLAGS_SHIFT + 0); +static const uint32_t JSCLASS_IS_GLOBAL = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 1); +static const uint32_t JSCLASS_INTERNAL_FLAG2 = + 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 2); +static const uint32_t JSCLASS_INTERNAL_FLAG3 = + 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 3); +static const uint32_t JSCLASS_IS_PROXY = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 4); +static const uint32_t JSCLASS_SKIP_NURSERY_FINALIZE = + 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 5); // Reserved for embeddings. -#define JSCLASS_USERBIT2 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+6)) -#define JSCLASS_USERBIT3 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+7)) +static const uint32_t JSCLASS_USERBIT2 = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 6); +static const uint32_t 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)) +static const uint32_t JSCLASS_BACKGROUND_FINALIZE = + 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 8); +static const uint32_t JSCLASS_FOREGROUND_FINALIZE = + 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 9); // Bits 26 through 31 are reserved for the CACHED_PROTO_KEY mechanism, see // below. @@ -785,141 +819,157 @@ // JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at // the beginning of every global object's slots for use by the // application. -#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5 -#define JSCLASS_GLOBAL_SLOT_COUNT \ - (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 \ - JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0) -#define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp) \ - (((clasp)->flags & JSCLASS_IS_GLOBAL) \ - && JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT) +static const uint32_t JSCLASS_GLOBAL_APPLICATION_SLOTS = 5; +static const uint32_t JSCLASS_GLOBAL_SLOT_COUNT = + JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 37; + +#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \ + (JSCLASS_IS_GLOBAL | \ + JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n))) +#define JSCLASS_GLOBAL_FLAGS JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0) +#define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp) \ + (((clasp)->flags & JSCLASS_IS_GLOBAL) && \ + JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT) // Fast access to the original value of each standard class's prototype. -#define JSCLASS_CACHED_PROTO_SHIFT (JSCLASS_HIGH_FLAGS_SHIFT + 10) -#define JSCLASS_CACHED_PROTO_MASK JS_BITMASK(js::JSCLASS_CACHED_PROTO_WIDTH) -#define JSCLASS_HAS_CACHED_PROTO(key) (uint32_t(key) << JSCLASS_CACHED_PROTO_SHIFT) -#define JSCLASS_CACHED_PROTO_KEY(clasp) ((JSProtoKey) \ - (((clasp)->flags \ - >> JSCLASS_CACHED_PROTO_SHIFT) \ - & JSCLASS_CACHED_PROTO_MASK)) +static const uint32_t JSCLASS_CACHED_PROTO_SHIFT = + JSCLASS_HIGH_FLAGS_SHIFT + 10; +static const uint32_t JSCLASS_CACHED_PROTO_MASK = + JS_BITMASK(js::JSCLASS_CACHED_PROTO_WIDTH); + +#define JSCLASS_HAS_CACHED_PROTO(key) \ + (uint32_t(key) << JSCLASS_CACHED_PROTO_SHIFT) +#define JSCLASS_CACHED_PROTO_KEY(clasp) \ + ((JSProtoKey)(((clasp)->flags >> JSCLASS_CACHED_PROTO_SHIFT) & \ + JSCLASS_CACHED_PROTO_MASK)) // Initializer for unused members of statically initialized JSClass structs. -#define JSCLASS_NO_INTERNAL_MEMBERS {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} -#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,JSCLASS_NO_INTERNAL_MEMBERS +#define JSCLASS_NO_INTERNAL_MEMBERS \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +#define JSCLASS_NO_OPTIONAL_MEMBERS 0, 0, 0, 0, 0, JSCLASS_NO_INTERNAL_MEMBERS namespace js { -struct Class -{ - 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 - * describe their properties and layout. Classes using this flag must - * provide their own property behavior, either by being proxy classes (do - * this) or by overriding all the ObjectOps except getElements, watch and - * unwatch (don't do this). - */ - static const uint32_t NON_NATIVE = JSCLASS_INTERNAL_FLAG2; - - bool isNative() const { - return !(flags & NON_NATIVE); - } - - bool hasPrivate() const { - return !!(flags & JSCLASS_HAS_PRIVATE); - } - - bool emulatesUndefined() const { - return flags & JSCLASS_EMULATES_UNDEFINED; - } - - bool isJSFunction() const { - return this == js::FunctionClassPtr; - } - - bool nonProxyCallable() const { - MOZ_ASSERT(!isProxy()); - return isJSFunction() || getCall(); - } - - bool isProxy() const { - return flags & JSCLASS_IS_PROXY; - } - - bool isDOMClass() const { - return flags & JSCLASS_IS_DOMJSCLASS; - } - - 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; } +struct JS_STATIC_CLASS Class { + 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 + * describe their properties and layout. Classes using this flag must + * provide their own property behavior, either by being proxy classes (do + * this) or by overriding all the ObjectOps except getElements + * (don't do this). + */ + static const uint32_t NON_NATIVE = JSCLASS_INTERNAL_FLAG2; + + bool isNative() const { return !(flags & NON_NATIVE); } + + bool hasPrivate() const { return !!(flags & JSCLASS_HAS_PRIVATE); } + + bool emulatesUndefined() const { return flags & JSCLASS_EMULATES_UNDEFINED; } + + bool isJSFunction() const { return this == js::FunctionClassPtr; } + + bool nonProxyCallable() const { + MOZ_ASSERT(!isProxy()); + return isJSFunction() || getCall(); + } + + bool isProxy() const { return flags & JSCLASS_IS_PROXY; } + + bool isDOMClass() const { return flags & JSCLASS_IS_DOMJSCLASS; } + + 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->createConstructor : nullptr; + } + ClassObjectCreationOp specCreatePrototypeHook() const { + return spec ? spec->createPrototype : 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->finishInit : 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; + } + GetElementsOp getOpsGetElements() const { + return oOps ? oOps->getElements : 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), +static_assert(offsetof(JSClassOps, addProperty) == + offsetof(ClassOps, addProperty), "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), +static_assert(offsetof(JSClassOps, delProperty) == + offsetof(ClassOps, delProperty), "ClassOps and JSClassOps must be consistent"); static_assert(offsetof(JSClassOps, enumerate) == offsetof(ClassOps, enumerate), "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, newEnumerate) == + offsetof(ClassOps, newEnumerate), + "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), +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"); @@ -927,7 +977,8 @@ "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), +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"); @@ -943,16 +994,12 @@ static_assert(sizeof(JSClass) == sizeof(Class), "Class and JSClass must be consistent"); -static MOZ_ALWAYS_INLINE const JSClass* -Jsvalify(const Class* c) -{ - return (const JSClass*)c; +static MOZ_ALWAYS_INLINE const JSClass* Jsvalify(const Class* c) { + return (const JSClass*)c; } -static MOZ_ALWAYS_INLINE const Class* -Valueify(const JSClass* c) -{ - return (const Class*)c; +static MOZ_ALWAYS_INLINE const Class* Valueify(const JSClass* c) { + return (const Class*)c; } /** @@ -960,36 +1007,34 @@ * value of objects. */ enum class ESClass { - Object, - Array, - Number, - String, - Boolean, - RegExp, - ArrayBuffer, - SharedArrayBuffer, - Date, - Set, - Map, - Promise, - MapIterator, - SetIterator, - Arguments, - Error, + Object, + Array, + Number, + String, + Boolean, + RegExp, + ArrayBuffer, + SharedArrayBuffer, + Date, + Set, + Map, + Promise, + MapIterator, + SetIterator, + Arguments, + Error, - /** None of the above. */ - Other + /** None of the above. */ + Other }; /* Fills |vp| with the unboxed value for boxed types, or undefined otherwise. */ -bool -Unbox(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp); +bool Unbox(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp); #ifdef DEBUG -JS_FRIEND_API(bool) -HasObjectMovedOp(JSObject* obj); +JS_FRIEND_API bool HasObjectMovedOp(JSObject* obj); #endif -} /* namespace js */ +} /* namespace js */ -#endif /* js_Class_h */ +#endif /* js_Class_h */ 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 @@ -11,7 +11,9 @@ #include "mozilla/Casting.h" #include "mozilla/FloatingPoint.h" +#include "mozilla/MathAlgorithms.h" #include "mozilla/TypeTraits.h" +#include "mozilla/WrappingOperations.h" #include @@ -20,59 +22,55 @@ #include "js/RootingAPI.h" #include "js/Value.h" -struct JSContext; - namespace js { /* DO NOT CALL THIS. Use JS::ToBoolean. */ -extern JS_PUBLIC_API(bool) -ToBooleanSlow(JS::HandleValue v); +extern JS_PUBLIC_API bool ToBooleanSlow(JS::HandleValue v); /* DO NOT CALL THIS. Use JS::ToNumber. */ -extern JS_PUBLIC_API(bool) -ToNumberSlow(JSContext* cx, JS::HandleValue v, double* dp); +extern JS_PUBLIC_API bool 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); +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); +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); +extern JS_PUBLIC_API bool ToInt16Slow(JSContext* cx, JS::HandleValue v, + int16_t* out); /* DO NOT CALL THIS. Use JS::ToInt32. */ -extern JS_PUBLIC_API(bool) -ToInt32Slow(JSContext* cx, JS::HandleValue v, int32_t* out); +extern JS_PUBLIC_API bool ToInt32Slow(JSContext* cx, JS::HandleValue v, + int32_t* out); /* DO NOT CALL THIS. Use JS::ToUint32. */ -extern JS_PUBLIC_API(bool) -ToUint32Slow(JSContext* cx, JS::HandleValue v, uint32_t* out); +extern JS_PUBLIC_API bool ToUint32Slow(JSContext* cx, JS::HandleValue v, + uint32_t* out); /* DO NOT CALL THIS. Use JS::ToUint16. */ -extern JS_PUBLIC_API(bool) -ToUint16Slow(JSContext* cx, JS::HandleValue v, uint16_t* out); +extern JS_PUBLIC_API bool ToUint16Slow(JSContext* cx, JS::HandleValue v, + uint16_t* out); /* DO NOT CALL THIS. Use JS::ToInt64. */ -extern JS_PUBLIC_API(bool) -ToInt64Slow(JSContext* cx, JS::HandleValue v, int64_t* out); +extern JS_PUBLIC_API bool ToInt64Slow(JSContext* cx, JS::HandleValue v, + int64_t* out); /* DO NOT CALL THIS. Use JS::ToUint64. */ -extern JS_PUBLIC_API(bool) -ToUint64Slow(JSContext* cx, JS::HandleValue v, uint64_t* out); +extern JS_PUBLIC_API bool ToUint64Slow(JSContext* cx, JS::HandleValue v, + uint64_t* out); /* DO NOT CALL THIS. Use JS::ToString. */ -extern JS_PUBLIC_API(JSString*) -ToStringSlow(JSContext* cx, JS::HandleValue v); +extern JS_PUBLIC_API JSString* ToStringSlow(JSContext* cx, JS::HandleValue v); /* DO NOT CALL THIS. Use JS::ToObject. */ -extern JS_PUBLIC_API(JSObject*) -ToObjectSlow(JSContext* cx, JS::HandleValue v, bool reportScanStack); +extern JS_PUBLIC_API JSObject* ToObjectSlow(JSContext* cx, JS::HandleValue v, + bool reportScanStack); -} // namespace js +} // namespace js namespace JS { @@ -84,14 +82,12 @@ * needed, and that the compartments for cx and v are correct. * Also check that GC would be safe at this point. */ -extern JS_PUBLIC_API(void) -AssertArgumentsAreSane(JSContext* cx, HandleValue v); +extern JS_PUBLIC_API void AssertArgumentsAreSane(JSContext* cx, HandleValue v); #else -inline void AssertArgumentsAreSane(JSContext* cx, HandleValue v) -{} +inline void AssertArgumentsAreSane(JSContext* cx, HandleValue v) {} #endif /* JS_DEBUG */ -} // namespace detail +} // namespace detail /** * ES6 draft 20141224, 7.1.1, second algorithm. @@ -101,189 +97,156 @@ * wish to fall back to the ES6 default conversion behavior shared by most * objects in JS, codified as OrdinaryToPrimitive. */ -extern JS_PUBLIC_API(bool) -OrdinaryToPrimitive(JSContext* cx, HandleObject obj, JSType type, MutableHandleValue vp); +extern JS_PUBLIC_API bool OrdinaryToPrimitive(JSContext* cx, HandleObject obj, + JSType type, + MutableHandleValue vp); /* ES6 draft 20141224, 7.1.2. */ -MOZ_ALWAYS_INLINE bool -ToBoolean(HandleValue v) -{ - if (v.isBoolean()) - return v.toBoolean(); - if (v.isInt32()) - return v.toInt32() != 0; - if (v.isNullOrUndefined()) - return false; - if (v.isDouble()) { - double d = v.toDouble(); - return !mozilla::IsNaN(d) && d != 0; - } - if (v.isSymbol()) - return true; +MOZ_ALWAYS_INLINE bool ToBoolean(HandleValue v) { + if (v.isBoolean()) return v.toBoolean(); + if (v.isInt32()) return v.toInt32() != 0; + if (v.isNullOrUndefined()) return false; + if (v.isDouble()) { + double d = v.toDouble(); + return !mozilla::IsNaN(d) && d != 0; + } + if (v.isSymbol()) return true; - /* The slow path handles strings and objects. */ - return js::ToBooleanSlow(v); + /* The slow path handles strings and objects. */ + return js::ToBooleanSlow(v); } /* ES6 draft 20141224, 7.1.3. */ -MOZ_ALWAYS_INLINE bool -ToNumber(JSContext* cx, HandleValue v, double* out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isNumber()) { - *out = v.toNumber(); - return true; - } - return js::ToNumberSlow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToNumber(JSContext* cx, HandleValue v, double* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isNumber()) { + *out = v.toNumber(); + return true; + } + return js::ToNumberSlow(cx, v, out); } /* ES6 draft 20141224, ToInteger (specialized for doubles). */ -inline double -ToInteger(double d) -{ - if (d == 0) - return d; - - if (!mozilla::IsFinite(d)) { - if (mozilla::IsNaN(d)) - return 0; - return d; - } +inline double ToInteger(double d) { + if (d == 0) return d; + + if (!mozilla::IsFinite(d)) { + if (mozilla::IsNaN(d)) return 0; + return d; + } - return d < 0 ? ceil(d) : floor(d); + return d < 0 ? ceil(d) : floor(d); } /* ES6 draft 20141224, 7.1.5. */ -MOZ_ALWAYS_INLINE bool -ToInt32(JSContext* cx, JS::HandleValue v, int32_t* out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isInt32()) { - *out = v.toInt32(); - return true; - } - return js::ToInt32Slow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToInt32(JSContext* cx, JS::HandleValue v, int32_t* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = v.toInt32(); + return true; + } + return js::ToInt32Slow(cx, v, out); } /* ES6 draft 20141224, 7.1.6. */ -MOZ_ALWAYS_INLINE bool -ToUint32(JSContext* cx, HandleValue v, uint32_t* out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isInt32()) { - *out = uint32_t(v.toInt32()); - return true; - } - return js::ToUint32Slow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToUint32(JSContext* cx, HandleValue v, uint32_t* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = uint32_t(v.toInt32()); + return true; + } + return js::ToUint32Slow(cx, v, out); } /* ES6 draft 20141224, 7.1.7. */ -MOZ_ALWAYS_INLINE bool -ToInt16(JSContext *cx, JS::HandleValue v, int16_t *out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isInt32()) { - *out = int16_t(v.toInt32()); - return true; - } - return js::ToInt16Slow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToInt16(JSContext* cx, JS::HandleValue v, int16_t* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = int16_t(v.toInt32()); + return true; + } + return js::ToInt16Slow(cx, v, out); } /* ES6 draft 20141224, 7.1.8. */ -MOZ_ALWAYS_INLINE bool -ToUint16(JSContext* cx, HandleValue v, uint16_t* out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isInt32()) { - *out = uint16_t(v.toInt32()); - return true; - } - return js::ToUint16Slow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToUint16(JSContext* cx, HandleValue v, uint16_t* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = uint16_t(v.toInt32()); + return true; + } + return js::ToUint16Slow(cx, v, out); } /* ES6 draft 20141224, 7.1.9 */ -MOZ_ALWAYS_INLINE bool -ToInt8(JSContext *cx, JS::HandleValue v, int8_t *out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isInt32()) { - *out = int8_t(v.toInt32()); - return true; - } - return js::ToInt8Slow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToInt8(JSContext* cx, JS::HandleValue v, int8_t* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = int8_t(v.toInt32()); + return true; + } + 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); +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. */ -MOZ_ALWAYS_INLINE bool -ToInt64(JSContext* cx, HandleValue v, int64_t* out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isInt32()) { - *out = int64_t(v.toInt32()); - return true; - } - return js::ToInt64Slow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToInt64(JSContext* cx, HandleValue v, int64_t* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = int64_t(v.toInt32()); + return true; + } + return js::ToInt64Slow(cx, v, out); } /* * Non-standard, with behavior similar to that of ToUint32, except in its * producing a uint64_t. */ -MOZ_ALWAYS_INLINE bool -ToUint64(JSContext* cx, HandleValue v, uint64_t* out) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isInt32()) { - *out = uint64_t(v.toInt32()); - return true; - } - return js::ToUint64Slow(cx, v, out); +MOZ_ALWAYS_INLINE bool ToUint64(JSContext* cx, HandleValue v, uint64_t* out) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isInt32()) { + *out = uint64_t(v.toInt32()); + return true; + } + return js::ToUint64Slow(cx, v, out); } /* ES6 draft 20141224, 7.1.12. */ -MOZ_ALWAYS_INLINE JSString* -ToString(JSContext* cx, HandleValue v) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isString()) - return v.toString(); - return js::ToStringSlow(cx, v); +MOZ_ALWAYS_INLINE JSString* ToString(JSContext* cx, HandleValue v) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isString()) return v.toString(); + return js::ToStringSlow(cx, v); } /* ES6 draft 20141224, 7.1.13. */ -inline JSObject* -ToObject(JSContext* cx, HandleValue v) -{ - detail::AssertArgumentsAreSane(cx, v); - - if (v.isObject()) - return &v.toObject(); - return js::ToObjectSlow(cx, v, false); +inline JSObject* ToObject(JSContext* cx, HandleValue v) { + detail::AssertArgumentsAreSane(cx, v); + + if (v.isObject()) return &v.toObject(); + return js::ToObjectSlow(cx, v, false); } namespace detail { @@ -301,281 +264,248 @@ * * but has been generalized to all integer widths. */ -template -inline ResultType -ToUintWidth(double d) -{ - static_assert(mozilla::IsUnsigned::value, - "ResultType must be an unsigned type"); - - uint64_t bits = mozilla::BitwiseCast(d); - unsigned DoubleExponentShift = mozilla::FloatingPoint::kExponentShift; - - // Extract the exponent component. (Be careful here! It's not technically - // the exponent in NaN, infinities, and subnormals.) - int_fast16_t exp = - int_fast16_t((bits & mozilla::FloatingPoint::kExponentBits) >> DoubleExponentShift) - - int_fast16_t(mozilla::FloatingPoint::kExponentBias); - - // If the exponent's less than zero, abs(d) < 1, so the result is 0. (This - // also handles subnormals.) - if (exp < 0) - return 0; - - uint_fast16_t exponent = mozilla::AssertedCast(exp); - - // If the exponent is greater than or equal to the bits of precision of a - // double plus ResultType's width, the number is either infinite, NaN, or - // too large to have lower-order bits in the congruent value. (Example: - // 2**84 is exactly representable as a double. The next exact double is - // 2**84 + 2**32. Thus if ResultType is int32_t, an exponent >= 84 implies - // floor(abs(d)) == 0 mod 2**32.) Return 0 in all these cases. - const size_t ResultWidth = CHAR_BIT * sizeof(ResultType); - if (exponent >= DoubleExponentShift + ResultWidth) - return 0; - - // The significand contains the bits that will determine the final result. - // Shift those bits left or right, according to the exponent, to their - // locations in the unsigned binary representation of floor(abs(d)). - static_assert(sizeof(ResultType) <= sizeof(uint64_t), - "Left-shifting below would lose upper bits"); - ResultType result = (exponent > DoubleExponentShift) - ? ResultType(bits << (exponent - DoubleExponentShift)) - : ResultType(bits >> (DoubleExponentShift - exponent)); - - // Two further complications remain. First, |result| may contain bogus - // sign/exponent bits. Second, IEEE-754 numbers' significands (excluding - // subnormals, but we already handled those) have an implicit leading 1 - // which may affect the final result. - // - // It may appear that there's complexity here depending on how ResultWidth - // and DoubleExponentShift relate, but it turns out there's not. - // - // Assume ResultWidth < DoubleExponentShift: - // Only right-shifts leave bogus bits in |result|. For this to happen, - // we must right-shift by > |DoubleExponentShift - ResultWidth|, implying - // |exponent < ResultWidth|. - // The implicit leading bit only matters if it appears in the final - // result -- if |2**exponent mod 2**ResultWidth != 0|. This implies - // |exponent < ResultWidth|. - // Otherwise assume ResultWidth >= DoubleExponentShift: - // Any left-shift less than |ResultWidth - DoubleExponentShift| leaves - // bogus bits in |result|. This implies |exponent < ResultWidth|. Any - // right-shift less than |ResultWidth| does too, which implies - // |DoubleExponentShift - ResultWidth < exponent|. By assumption, then, - // |exponent| is negative, but we excluded that above. So bogus bits - // need only |exponent < ResultWidth|. - // The implicit leading bit matters identically to the other case, so - // again, |exponent < ResultWidth|. - if (exponent < ResultWidth) { - ResultType implicitOne = ResultType(1) << exponent; - result &= implicitOne - 1; // remove bogus bits - result += implicitOne; // add the implicit bit - } - - // Compute the congruent value in the signed range. - return (bits & mozilla::FloatingPoint::kSignBit) ? ~result + 1 : result; -} - -template -inline ResultType -ToIntWidth(double d) -{ - static_assert(mozilla::IsSigned::value, - "ResultType must be a signed type"); - - const ResultType MaxValue = (1ULL << (CHAR_BIT * sizeof(ResultType) - 1)) - 1; - const ResultType MinValue = -MaxValue - 1; - - typedef typename mozilla::MakeUnsigned::Type UnsignedResult; - UnsignedResult u = ToUintWidth(d); - if (u <= UnsignedResult(MaxValue)) - return static_cast(u); - return (MinValue + static_cast(u - MaxValue)) - 1; +template +inline ResultType ToUintWidth(double d) { + static_assert(mozilla::IsUnsigned::value, + "ResultType must be an unsigned type"); + + uint64_t bits = mozilla::BitwiseCast(d); + unsigned DoubleExponentShift = mozilla::FloatingPoint::kExponentShift; + + // Extract the exponent component. (Be careful here! It's not technically + // the exponent in NaN, infinities, and subnormals.) + int_fast16_t exp = + int_fast16_t((bits & mozilla::FloatingPoint::kExponentBits) >> + DoubleExponentShift) - + int_fast16_t(mozilla::FloatingPoint::kExponentBias); + + // If the exponent's less than zero, abs(d) < 1, so the result is 0. (This + // also handles subnormals.) + if (exp < 0) return 0; + + uint_fast16_t exponent = mozilla::AssertedCast(exp); + + // If the exponent is greater than or equal to the bits of precision of a + // double plus ResultType's width, the number is either infinite, NaN, or + // too large to have lower-order bits in the congruent value. (Example: + // 2**84 is exactly representable as a double. The next exact double is + // 2**84 + 2**32. Thus if ResultType is int32_t, an exponent >= 84 implies + // floor(abs(d)) == 0 mod 2**32.) Return 0 in all these cases. + const size_t ResultWidth = CHAR_BIT * sizeof(ResultType); + if (exponent >= DoubleExponentShift + ResultWidth) return 0; + + // The significand contains the bits that will determine the final result. + // Shift those bits left or right, according to the exponent, to their + // locations in the unsigned binary representation of floor(abs(d)). + static_assert(sizeof(ResultType) <= sizeof(uint64_t), + "Left-shifting below would lose upper bits"); + ResultType result = + (exponent > DoubleExponentShift) + ? ResultType(bits << (exponent - DoubleExponentShift)) + : ResultType(bits >> (DoubleExponentShift - exponent)); + + // Two further complications remain. First, |result| may contain bogus + // sign/exponent bits. Second, IEEE-754 numbers' significands (excluding + // subnormals, but we already handled those) have an implicit leading 1 + // which may affect the final result. + // + // It may appear that there's complexity here depending on how ResultWidth + // and DoubleExponentShift relate, but it turns out there's not. + // + // Assume ResultWidth < DoubleExponentShift: + // Only right-shifts leave bogus bits in |result|. For this to happen, + // we must right-shift by > |DoubleExponentShift - ResultWidth|, implying + // |exponent < ResultWidth|. + // The implicit leading bit only matters if it appears in the final + // result -- if |2**exponent mod 2**ResultWidth != 0|. This implies + // |exponent < ResultWidth|. + // Otherwise assume ResultWidth >= DoubleExponentShift: + // Any left-shift less than |ResultWidth - DoubleExponentShift| leaves + // bogus bits in |result|. This implies |exponent < ResultWidth|. Any + // right-shift less than |ResultWidth| does too, which implies + // |DoubleExponentShift - ResultWidth < exponent|. By assumption, then, + // |exponent| is negative, but we excluded that above. So bogus bits + // need only |exponent < ResultWidth|. + // The implicit leading bit matters identically to the other case, so + // again, |exponent < ResultWidth|. + if (exponent < ResultWidth) { + ResultType implicitOne = ResultType(1) << exponent; + result &= implicitOne - 1; // remove bogus bits + result += implicitOne; // add the implicit bit + } + + // Compute the congruent value in the signed range. + return (bits & mozilla::FloatingPoint::kSignBit) ? ~result + 1 + : result; +} + +template +inline ResultType ToIntWidth(double d) { + static_assert(mozilla::IsSigned::value, + "ResultType must be a signed type"); + + using UnsignedResult = typename mozilla::MakeUnsigned::Type; + UnsignedResult u = ToUintWidth(d); + + return mozilla::WrapToSigned(u); } -} // namespace detail +} // namespace detail /* ES5 9.5 ToInt32 (specialized for doubles). */ -inline int32_t -ToInt32(double d) -{ - // clang crashes compiling this when targeting arm: - // https://llvm.org/bugs/show_bug.cgi?id=22974 -#if defined (__arm__) && defined (__GNUC__) && !defined(__clang__) - int32_t i; - uint32_t tmp0; - uint32_t tmp1; - uint32_t tmp2; - asm ( - // We use a pure integer solution here. In the 'softfp' ABI, the argument - // will start in r0 and r1, and VFP can't do all of the necessary ECMA - // conversions by itself so some integer code will be required anyway. A - // hybrid solution is faster on A9, but this pure integer solution is - // notably faster for A8. - - // %0 is the result register, and may alias either of the %[QR]1 registers. - // %Q4 holds the lower part of the mantissa. - // %R4 holds the sign, exponent, and the upper part of the mantissa. - // %1, %2 and %3 are used as temporary values. - - // Extract the exponent. -" mov %1, %R4, LSR #20\n" -" bic %1, %1, #(1 << 11)\n" // Clear the sign. - - // Set the implicit top bit of the mantissa. This clobbers a bit of the - // exponent, but we have already extracted that. -" orr %R4, %R4, #(1 << 20)\n" - - // Special Cases - // We should return zero in the following special cases: - // - Exponent is 0x000 - 1023: +/-0 or subnormal. - // - Exponent is 0x7ff - 1023: +/-INFINITY or NaN - // - This case is implicitly handled by the standard code path anyway, - // as shifting the mantissa up by the exponent will result in '0'. - // - // The result is composed of the mantissa, prepended with '1' and - // bit-shifted left by the (decoded) exponent. Note that because the r1[20] - // is the bit with value '1', r1 is effectively already shifted (left) by - // 20 bits, and r0 is already shifted by 52 bits. - - // Adjust the exponent to remove the encoding offset. If the decoded - // exponent is negative, quickly bail out with '0' as such values round to - // zero anyway. This also catches +/-0 and subnormals. -" sub %1, %1, #0xff\n" -" subs %1, %1, #0x300\n" -" bmi 8f\n" - - // %1 = (decoded) exponent >= 0 - // %R4 = upper mantissa and sign - - // ---- Lower Mantissa ---- -" subs %3, %1, #52\n" // Calculate exp-52 -" bmi 1f\n" - - // Shift r0 left by exp-52. - // Ensure that we don't overflow ARM's 8-bit shift operand range. - // We need to handle anything up to an 11-bit value here as we know that - // 52 <= exp <= 1024 (0x400). Any shift beyond 31 bits results in zero - // anyway, so as long as we don't touch the bottom 5 bits, we can use - // a logical OR to push long shifts into the 32 <= (exp&0xff) <= 255 range. -" bic %2, %3, #0xff\n" -" orr %3, %3, %2, LSR #3\n" - // We can now perform a straight shift, avoiding the need for any - // conditional instructions or extra branches. -" mov %Q4, %Q4, LSL %3\n" -" b 2f\n" -"1:\n" // Shift r0 right by 52-exp. - // We know that 0 <= exp < 52, and we can shift up to 255 bits so 52-exp - // will always be a valid shift and we can sk%3 the range check for this case. -" rsb %3, %1, #52\n" -" mov %Q4, %Q4, LSR %3\n" - - // %1 = (decoded) exponent - // %R4 = upper mantissa and sign - // %Q4 = partially-converted integer - -"2:\n" - // ---- Upper Mantissa ---- - // This is much the same as the lower mantissa, with a few different - // boundary checks and some masking to hide the exponent & sign bit in the - // upper word. - // Note that the upper mantissa is pre-shifted by 20 in %R4, but we shift - // it left more to remove the sign and exponent so it is effectively - // pre-shifted by 31 bits. -" subs %3, %1, #31\n" // Calculate exp-31 -" mov %1, %R4, LSL #11\n" // Re-use %1 as a temporary register. -" bmi 3f\n" - - // Shift %R4 left by exp-31. - // Avoid overflowing the 8-bit shift range, as before. -" bic %2, %3, #0xff\n" -" orr %3, %3, %2, LSR #3\n" - // Perform the shift. -" mov %2, %1, LSL %3\n" -" b 4f\n" -"3:\n" // Shift r1 right by 31-exp. - // We know that 0 <= exp < 31, and we can shift up to 255 bits so 31-exp - // will always be a valid shift and we can skip the range check for this case. -" rsb %3, %3, #0\n" // Calculate 31-exp from -(exp-31) -" mov %2, %1, LSR %3\n" // Thumb-2 can't do "LSR %3" in "orr". - - // %Q4 = partially-converted integer (lower) - // %R4 = upper mantissa and sign - // %2 = partially-converted integer (upper) - -"4:\n" - // Combine the converted parts. -" orr %Q4, %Q4, %2\n" - // Negate the result if we have to, and move it to %0 in the process. To - // avoid conditionals, we can do this by inverting on %R4[31], then adding - // %R4[31]>>31. -" eor %Q4, %Q4, %R4, ASR #31\n" -" add %0, %Q4, %R4, LSR #31\n" -" b 9f\n" -"8:\n" - // +/-INFINITY, +/-0, subnormals, NaNs, and anything else out-of-range that - // will result in a conversion of '0'. -" mov %0, #0\n" -"9:\n" - : "=r" (i), "=&r" (tmp0), "=&r" (tmp1), "=&r" (tmp2), "=&r" (d) - : "4" (d) - : "cc" - ); - return i; +inline int32_t ToInt32(double d) { +// clang crashes compiling this when targeting arm: +// https://llvm.org/bugs/show_bug.cgi?id=22974 +#if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) + int32_t i; + uint32_t tmp0; + uint32_t tmp1; + uint32_t tmp2; + asm( + // We use a pure integer solution here. In the 'softfp' ABI, the argument + // will start in r0 and r1, and VFP can't do all of the necessary ECMA + // conversions by itself so some integer code will be required anyway. A + // hybrid solution is faster on A9, but this pure integer solution is + // notably faster for A8. + + // %0 is the result register, and may alias either of the %[QR]1 + // registers. + // %Q4 holds the lower part of the mantissa. + // %R4 holds the sign, exponent, and the upper part of the mantissa. + // %1, %2 and %3 are used as temporary values. + + // Extract the exponent. + " mov %1, %R4, LSR #20\n" + " bic %1, %1, #(1 << 11)\n" // Clear the sign. + + // Set the implicit top bit of the mantissa. This clobbers a bit of the + // exponent, but we have already extracted that. + " orr %R4, %R4, #(1 << 20)\n" + + // Special Cases + // We should return zero in the following special cases: + // - Exponent is 0x000 - 1023: +/-0 or subnormal. + // - Exponent is 0x7ff - 1023: +/-INFINITY or NaN + // - This case is implicitly handled by the standard code path + // anyway, as shifting the mantissa up by the exponent will + // result in '0'. + // + // The result is composed of the mantissa, prepended with '1' and + // bit-shifted left by the (decoded) exponent. Note that because the + // r1[20] is the bit with value '1', r1 is effectively already shifted + // (left) by 20 bits, and r0 is already shifted by 52 bits. + + // Adjust the exponent to remove the encoding offset. If the decoded + // exponent is negative, quickly bail out with '0' as such values round to + // zero anyway. This also catches +/-0 and subnormals. + " sub %1, %1, #0xff\n" + " subs %1, %1, #0x300\n" + " bmi 8f\n" + + // %1 = (decoded) exponent >= 0 + // %R4 = upper mantissa and sign + + // ---- Lower Mantissa ---- + " subs %3, %1, #52\n" // Calculate exp-52 + " bmi 1f\n" + + // Shift r0 left by exp-52. + // Ensure that we don't overflow ARM's 8-bit shift operand range. + // We need to handle anything up to an 11-bit value here as we know that + // 52 <= exp <= 1024 (0x400). Any shift beyond 31 bits results in zero + // anyway, so as long as we don't touch the bottom 5 bits, we can use + // a logical OR to push long shifts into the 32 <= (exp&0xff) <= 255 + // range. + " bic %2, %3, #0xff\n" + " orr %3, %3, %2, LSR #3\n" + // We can now perform a straight shift, avoiding the need for any + // conditional instructions or extra branches. + " mov %Q4, %Q4, LSL %3\n" + " b 2f\n" + "1:\n" // Shift r0 right by 52-exp. + // We know that 0 <= exp < 52, and we can shift up to 255 bits so + // 52-exp will always be a valid shift and we can sk%3 the range + // check for this case. + " rsb %3, %1, #52\n" + " mov %Q4, %Q4, LSR %3\n" + + // %1 = (decoded) exponent + // %R4 = upper mantissa and sign + // %Q4 = partially-converted integer + + "2:\n" + // ---- Upper Mantissa ---- + // This is much the same as the lower mantissa, with a few different + // boundary checks and some masking to hide the exponent & sign bit in the + // upper word. + // Note that the upper mantissa is pre-shifted by 20 in %R4, but we shift + // it left more to remove the sign and exponent so it is effectively + // pre-shifted by 31 bits. + " subs %3, %1, #31\n" // Calculate exp-31 + " mov %1, %R4, LSL #11\n" // Re-use %1 as a temporary register. + " bmi 3f\n" + + // Shift %R4 left by exp-31. + // Avoid overflowing the 8-bit shift range, as before. + " bic %2, %3, #0xff\n" + " orr %3, %3, %2, LSR #3\n" + // Perform the shift. + " mov %2, %1, LSL %3\n" + " b 4f\n" + "3:\n" // Shift r1 right by 31-exp. + // We know that 0 <= exp < 31, and we can shift up to 255 bits so + // 31-exp will always be a valid shift and we can skip the range + // check for this case. + " rsb %3, %3, #0\n" // Calculate 31-exp from -(exp-31) + " mov %2, %1, LSR %3\n" // Thumb-2 can't do "LSR %3" in "orr". + + // %Q4 = partially-converted integer (lower) + // %R4 = upper mantissa and sign + // %2 = partially-converted integer (upper) + + "4:\n" + // Combine the converted parts. + " orr %Q4, %Q4, %2\n" + // Negate the result if we have to, and move it to %0 in the process. To + // avoid conditionals, we can do this by inverting on %R4[31], then adding + // %R4[31]>>31. + " eor %Q4, %Q4, %R4, ASR #31\n" + " add %0, %Q4, %R4, LSR #31\n" + " b 9f\n" + "8:\n" + // +/-INFINITY, +/-0, subnormals, NaNs, and anything else out-of-range + // that will result in a conversion of '0'. + " mov %0, #0\n" + "9:\n" + : "=r"(i), "=&r"(tmp0), "=&r"(tmp1), "=&r"(tmp2), "=&r"(d) + : "4"(d) + : "cc"); + return i; #else - return detail::ToIntWidth(d); + return detail::ToIntWidth(d); #endif } /* ES5 9.6 (specialized for doubles). */ -inline uint32_t -ToUint32(double d) -{ - return detail::ToUintWidth(d); -} +inline uint32_t ToUint32(double d) { return detail::ToUintWidth(d); } /* WEBIDL 4.2.4 */ -inline int8_t -ToInt8(double d) -{ - return detail::ToIntWidth(d); -} +inline int8_t ToInt8(double d) { return detail::ToIntWidth(d); } /* ECMA-262 7.1.10 ToUInt8() specialized for doubles. */ -inline int8_t -ToUint8(double d) -{ - return detail::ToUintWidth(d); -} +inline int8_t ToUint8(double d) { return detail::ToUintWidth(d); } /* WEBIDL 4.2.6 */ -inline int16_t -ToInt16(double d) -{ - return detail::ToIntWidth(d); -} +inline int16_t ToInt16(double d) { return detail::ToIntWidth(d); } -inline uint16_t -ToUint16(double d) -{ - return detail::ToUintWidth(d); -} +inline uint16_t ToUint16(double d) { return detail::ToUintWidth(d); } /* WEBIDL 4.2.10 */ -inline int64_t -ToInt64(double d) -{ - return detail::ToIntWidth(d); -} +inline int64_t ToInt64(double d) { return detail::ToIntWidth(d); } /* WEBIDL 4.2.11 */ -inline uint64_t -ToUint64(double d) -{ - return detail::ToUintWidth(d); -} +inline uint64_t ToUint64(double d) { return detail::ToUintWidth(d); } -} // namespace JS +} // namespace JS #endif /* js_Conversions_h */ 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 @@ -35,8 +35,6 @@ #include "js/Conversions.h" #include "js/Value.h" -struct JSContext; - namespace JS { /** @@ -52,8 +50,7 @@ * changes, or immediately before operations requiring instantaneous * correctness, to guarantee correct behavior. */ -extern JS_PUBLIC_API(void) -ResetTimeZone(); +extern JS_PUBLIC_API void ResetTimeZone(); class ClippedTime; inline ClippedTime TimeClip(double time); @@ -76,78 +73,76 @@ * JavaScript dates. This also forces users to perform any desired clipping, * as only the user knows what behavior is desired when clipping occurs. */ -class ClippedTime -{ - double t; +class ClippedTime { + double t; - explicit ClippedTime(double time) : t(time) {} - friend ClippedTime TimeClip(double time); + explicit ClippedTime(double time) : t(time) {} + friend ClippedTime TimeClip(double time); - public: - // Create an invalid date. - ClippedTime() : t(mozilla::UnspecifiedNaN()) {} + public: + // Create an invalid date. + ClippedTime() : t(mozilla::UnspecifiedNaN()) {} - // Create an invalid date/time, more explicitly; prefer this to the default - // constructor. - static ClippedTime invalid() { return ClippedTime(); } + // Create an invalid date/time, more explicitly; prefer this to the default + // constructor. + static ClippedTime invalid() { return ClippedTime(); } - double toDouble() const { return t; } + double toDouble() const { return t; } - bool isValid() const { return !mozilla::IsNaN(t); } + bool isValid() const { return !mozilla::IsNaN(t); } }; // ES6 20.3.1.15. // // Clip a double to JavaScript's date range (or to an invalid date) using the // ECMAScript TimeClip algorithm. -inline ClippedTime -TimeClip(double time) -{ - // Steps 1-2. - const double MaxTimeMagnitude = 8.64e15; - if (!mozilla::IsFinite(time) || mozilla::Abs(time) > MaxTimeMagnitude) - return ClippedTime(mozilla::UnspecifiedNaN()); +inline ClippedTime TimeClip(double time) { + // Steps 1-2. + const double MaxTimeMagnitude = 8.64e15; + if (!mozilla::IsFinite(time) || mozilla::Abs(time) > MaxTimeMagnitude) + return ClippedTime(mozilla::UnspecifiedNaN()); - // Step 3. - return ClippedTime(ToInteger(time) + (+0.0)); + // Step 3. + return ClippedTime(ToInteger(time) + (+0.0)); } // Produce a double Value from the given time. Because times may be NaN, // prefer using this to manual canonicalization. -inline Value -TimeValue(ClippedTime time) -{ - return DoubleValue(JS::CanonicalizeNaN(time.toDouble())); +inline Value TimeValue(ClippedTime time) { + return DoubleValue(JS::CanonicalizeNaN(time.toDouble())); } // Create a new Date object whose [[DateValue]] internal slot contains the // clipped |time|. (Users who must represent times outside that range must use // another representation.) -extern JS_PUBLIC_API(JSObject*) -NewDateObject(JSContext* cx, ClippedTime time); +extern JS_PUBLIC_API JSObject* NewDateObject(JSContext* cx, ClippedTime time); // Year is a year, month is 0-11, day is 1-based. The return value is a number // of milliseconds since the epoch. // // Consistent with the MakeDate algorithm defined in ECMAScript, this value is // *not* clipped! Use JS::TimeClip if you need a clipped date. -JS_PUBLIC_API(double) -MakeDate(double year, unsigned month, unsigned day); +JS_PUBLIC_API double MakeDate(double year, unsigned month, unsigned day); + +// Year is a year, month is 0-11, day is 1-based, and time is in milliseconds. +// The return value is a number of milliseconds since the epoch. +// +// Consistent with the MakeDate algorithm defined in ECMAScript, this value is +// *not* clipped! Use JS::TimeClip if you need a clipped date. +JS_PUBLIC_API double MakeDate(double year, unsigned month, unsigned day, + double time); // Takes an integer number of milliseconds since the epoch and returns the // year. Can return NaN, and will do so if NaN is passed in. -JS_PUBLIC_API(double) -YearFromTime(double time); +JS_PUBLIC_API double YearFromTime(double time); // Takes an integer number of milliseconds since the epoch and returns the // month (0-11). Can return NaN, and will do so if NaN is passed in. -JS_PUBLIC_API(double) -MonthFromTime(double time); +JS_PUBLIC_API double MonthFromTime(double time); // Takes an integer number of milliseconds since the epoch and returns the // day (1-based). Can return NaN, and will do so if NaN is passed in. -JS_PUBLIC_API(double) -DayFromTime(double time); +JS_PUBLIC_API double DayFromTime(double time); // Takes an integer year and returns the number of days from epoch to the given // year. @@ -155,16 +150,30 @@ // 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); +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); +// This should usually be ensured by computing |year| as +// |JS::DayFromYear(time)|. +JS_PUBLIC_API double DayWithinYear(double time, double year); + +// The callback will be a wrapper function that accepts a single double (the +// time to clamp and jitter.) Inside the JS Engine, other parameters that may be +// needed are all constant, so they are handled inside the wrapper function +using ReduceMicrosecondTimePrecisionCallback = double (*)(double); + +// Set a callback into the toolkit/components/resistfingerprinting function that +// will centralize time resolution and jitter into one place. +JS_PUBLIC_API void SetReduceMicrosecondTimePrecisionCallback( + ReduceMicrosecondTimePrecisionCallback callback); + +// Sets the time resolution for fingerprinting protection, and whether jitter +// should occur. If resolution is set to zero, then no rounding or jitter will +// occur. This is used if the callback above is not specified. +JS_PUBLIC_API void SetTimeResolutionUsec(uint32_t resolution, bool jitter); -} // namespace JS +} // 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 @@ -22,7 +22,7 @@ namespace js { class Debugger; -} // namespace js +} // namespace js namespace JS { namespace dbg { @@ -99,7 +99,8 @@ // return false; // result = builder.newObject(cx); // return result && -// result.defineProperty(cx, "eventType", SafelyFetchType(eventObject)) && +// result.defineProperty(cx, "eventType", +// SafelyFetchType(eventObject)) && // result.defineProperty(cx, "event", eventObject); // } // @@ -120,135 +121,134 @@ class BuilderOrigin; class Builder { - // The Debugger instance whose client we are building a value for. We build - // objects in this object's compartment. - PersistentRootedObject debuggerObject; - - // debuggerObject's Debugger structure, for convenience. - js::Debugger* debugger; - - // Check that |thing| is in the same compartment as our debuggerObject. Used - // for assertions when constructing BuiltThings. We can overload this as we - // add more instantiations of BuiltThing. + // The Debugger instance whose client we are building a value for. We build + // objects in this object's compartment. + PersistentRootedObject debuggerObject; + + // debuggerObject's Debugger structure, for convenience. + js::Debugger* debugger; + + // Check that |thing| is in the same compartment as our debuggerObject. Used + // for assertions when constructing BuiltThings. We can overload this as we + // add more instantiations of BuiltThing. #if DEBUG - void assertBuilt(JSObject* obj); + void assertBuilt(JSObject* obj); #else - void assertBuilt(JSObject* obj) { } + void assertBuilt(JSObject* obj) {} #endif - protected: - // A reference to a trusted object or value. At the moment, we only use it - // with JSObject*. - template - class BuiltThing { - friend class BuilderOrigin; - - protected: - // The Builder to which this trusted thing belongs. - Builder& owner; - - // A rooted reference to our value. - PersistentRooted value; - - BuiltThing(JSContext* cx, Builder& owner_, T value_ = GCPolicy::initial()) - : owner(owner_), value(cx, value_) - { - owner.assertBuilt(value_); - } - - // Forward some things from our owner, for convenience. - js::Debugger* debugger() const { return owner.debugger; } - JSObject* debuggerObject() const { return owner.debuggerObject; } - - public: - BuiltThing(const BuiltThing& rhs) : owner(rhs.owner), value(rhs.value) { } - BuiltThing& operator=(const BuiltThing& rhs) { - MOZ_ASSERT(&owner == &rhs.owner); - owner.assertBuilt(rhs.value); - value = rhs.value; - return *this; - } - - explicit operator bool() const { - // If we ever instantiate BuiltThing, this might not suffice. - return value; - } - - private: - BuiltThing() = delete; - }; - - public: - // A reference to a trusted object, possibly null. Instances of Object are - // always properly rooted. They can be copied and assigned, as if they were - // pointers. - class Object: private BuiltThing { - friend class Builder; // for construction - friend class BuilderOrigin; // for unwrapping - - typedef BuiltThing Base; - - // This is private, because only Builders can create Objects that - // actually point to something (hence the 'friend' declaration). - Object(JSContext* cx, Builder& owner_, HandleObject obj) : Base(cx, owner_, obj.get()) { } - - bool definePropertyToTrusted(JSContext* cx, const char* name, - JS::MutableHandleValue value); - - public: - Object(JSContext* cx, Builder& owner_) : Base(cx, owner_, nullptr) { } - Object(const Object& rhs) : Base(rhs) { } - - // Our automatically-generated assignment operator can see our base - // class's assignment operator, so we don't need to write one out here. - - // Set the property named |name| on this object to |value|. - // - // If |value| is a string or primitive, re-wrap it for the debugger's - // compartment. - // - // If |value| is an object, assume it is a debuggee object and make a - // Debugger.Object instance referring to it. Set that as the propery's - // value. - // - // If |value| is another trusted object, store it directly as the - // property's value. - // - // On error, report the problem on cx and return false. - bool defineProperty(JSContext* cx, const char* name, JS::HandleValue value); - bool defineProperty(JSContext* cx, const char* name, JS::HandleObject value); - bool defineProperty(JSContext* cx, const char* name, Object& value); - - using Base::operator bool; - }; - - // Build an empty object for direct use by debugger code, owned by this - // Builder. If an error occurs, report it on cx and return a false Object. - Object newObject(JSContext* cx); + protected: + // A reference to a trusted object or value. At the moment, we only use it + // with JSObject*. + template + class BuiltThing { + friend class BuilderOrigin; + + protected: + // The Builder to which this trusted thing belongs. + Builder& owner; + + // A rooted reference to our value. + PersistentRooted value; + + BuiltThing(JSContext* cx, Builder& owner_, + T value_ = GCPolicy::initial()) + : owner(owner_), value(cx, value_) { + owner.assertBuilt(value_); + } + + // Forward some things from our owner, for convenience. + js::Debugger* debugger() const { return owner.debugger; } + JSObject* debuggerObject() const { return owner.debuggerObject; } + + public: + BuiltThing(const BuiltThing& rhs) : owner(rhs.owner), value(rhs.value) {} + BuiltThing& operator=(const BuiltThing& rhs) { + MOZ_ASSERT(&owner == &rhs.owner); + owner.assertBuilt(rhs.value); + value = rhs.value; + return *this; + } + + explicit operator bool() const { + // If we ever instantiate BuiltThing, this might not suffice. + return value; + } + + private: + BuiltThing() = delete; + }; + + public: + // A reference to a trusted object, possibly null. Instances of Object are + // always properly rooted. They can be copied and assigned, as if they were + // pointers. + class Object : private BuiltThing { + friend class Builder; // for construction + friend class BuilderOrigin; // for unwrapping + + typedef BuiltThing Base; + + // This is private, because only Builders can create Objects that + // actually point to something (hence the 'friend' declaration). + Object(JSContext* cx, Builder& owner_, HandleObject obj) + : Base(cx, owner_, obj.get()) {} + + bool definePropertyToTrusted(JSContext* cx, const char* name, + JS::MutableHandleValue value); + + public: + Object(JSContext* cx, Builder& owner_) : Base(cx, owner_, nullptr) {} + Object(const Object& rhs) : Base(rhs) {} + + // Our automatically-generated assignment operator can see our base + // class's assignment operator, so we don't need to write one out here. + + // Set the property named |name| on this object to |value|. + // + // If |value| is a string or primitive, re-wrap it for the debugger's + // compartment. + // + // If |value| is an object, assume it is a debuggee object and make a + // Debugger.Object instance referring to it. Set that as the propery's + // value. + // + // If |value| is another trusted object, store it directly as the + // property's value. + // + // On error, report the problem on cx and return false. + bool defineProperty(JSContext* cx, const char* name, JS::HandleValue value); + bool defineProperty(JSContext* cx, const char* name, + JS::HandleObject value); + bool defineProperty(JSContext* cx, const char* name, Object& value); + + using Base::operator bool; + }; + + // Build an empty object for direct use by debugger code, owned by this + // Builder. If an error occurs, report it on cx and return a false Object. + Object newObject(JSContext* cx); - protected: - Builder(JSContext* cx, js::Debugger* debugger); + protected: + Builder(JSContext* cx, js::Debugger* debugger); }; // Debugger itself instantiates this subclass of Builder, which can unwrap // BuiltThings that belong to it. class BuilderOrigin : public Builder { - template - T unwrapAny(const BuiltThing& thing) { - MOZ_ASSERT(&thing.owner == this); - return thing.value.get(); - } - - public: - BuilderOrigin(JSContext* cx, js::Debugger* debugger_) - : Builder(cx, debugger_) - { } + template + T unwrapAny(const BuiltThing& thing) { + MOZ_ASSERT(&thing.owner == this); + return thing.value.get(); + } + + public: + BuilderOrigin(JSContext* cx, js::Debugger* debugger_) + : Builder(cx, debugger_) {} - JSObject* unwrap(Object& object) { return unwrapAny(object); } + JSObject* unwrap(Object& object) { return unwrapAny(object); } }; - - // Finding the size of blocks allocated with malloc // ------------------------------------------------ // @@ -259,16 +259,13 @@ // Tell Debuggers in |cx| to use |mallocSizeOf| to find the size of // malloc'd blocks. -JS_PUBLIC_API(void) -SetDebuggerMallocSizeOf(JSContext* cx, mozilla::MallocSizeOf mallocSizeOf); +JS_PUBLIC_API void SetDebuggerMallocSizeOf(JSContext* cx, + mozilla::MallocSizeOf mallocSizeOf); // Get the MallocSizeOf function that the given context is using to find the // size of malloc'd blocks. -JS_PUBLIC_API(mozilla::MallocSizeOf) -GetDebuggerMallocSizeOf(JSContext* cx); +JS_PUBLIC_API mozilla::MallocSizeOf GetDebuggerMallocSizeOf(JSContext* cx); - - // Debugger and Garbage Collection Events // -------------------------------------- // @@ -279,54 +276,24 @@ // empty. Instead, we rely on embedders to call back into SpiderMonkey after a // GC and notify Debuggers to call their onGarbageCollection hook. +// Determine whether it's necessary to call FireOnGarbageCollectionHook() after +// a GC. This is only required if there are debuggers with an +// onGarbageCollection hook observing a global in the set of collected zones. +JS_PUBLIC_API bool FireOnGarbageCollectionHookRequired(JSContext* cx); // For each Debugger that observed a debuggee involved in the given GC event, // call its `onGarbageCollection` hook. -JS_PUBLIC_API(bool) -FireOnGarbageCollectionHook(JSContext* cx, GarbageCollectionEvent::Ptr&& data); - - - -// Handlers for observing Promises -// ------------------------------- -// -// The Debugger wants to observe behavior of promises, which are implemented by -// Gecko with webidl and which SpiderMonkey knows nothing about. On the other -// hand, Gecko knows nothing about which (if any) debuggers are observing a -// promise's global. The compromise is that Gecko is responsible for calling -// these handlers at the appropriate times, and SpiderMonkey will handle -// notifying any Debugger instances that are observing the given promise's -// global. - -// Notify any Debugger instances observing this promise's global that a new -// promise was allocated. -JS_PUBLIC_API(void) -onNewPromise(JSContext* cx, HandleObject promise); - -// Notify any Debugger instances observing this promise's global that the -// promise has settled (ie, it has either been fulfilled or rejected). Note that -// this is *not* equivalent to the promise resolution (ie, the promise's fate -// getting locked in) because you can resolve a promise with another pending -// promise, in which case neither promise has settled yet. -// -// It is Gecko's responsibility to ensure that this is never called on the same -// promise more than once (because a promise can only make the transition from -// unsettled to settled once). -JS_PUBLIC_API(void) -onPromiseSettled(JSContext* cx, HandleObject promise); +JS_PUBLIC_API bool FireOnGarbageCollectionHook( + JSContext* cx, GarbageCollectionEvent::Ptr&& data); - - // Return true if the given value is a Debugger object, false otherwise. -JS_PUBLIC_API(bool) -IsDebugger(JSObject& obj); +JS_PUBLIC_API bool IsDebugger(JSObject& obj); // Append each of the debuggee global objects observed by the Debugger object // |dbgObj| to |vector|. Returns true on success, false on failure. -JS_PUBLIC_API(bool) -GetDebuggeeGlobals(JSContext* cx, JSObject& dbgObj, AutoObjectVector& vector); +JS_PUBLIC_API bool GetDebuggeeGlobals(JSContext* cx, JSObject& dbgObj, + AutoObjectVector& vector); - // Hooks for reporting where JavaScript execution began. // // Our performance tools would like to be able to label blocks of JavaScript @@ -340,45 +307,40 @@ // call the appropriate |Entry| member function to indicate where we've begun // execution. -class MOZ_STACK_CLASS JS_PUBLIC_API(AutoEntryMonitor) { - JSRuntime* runtime_; - AutoEntryMonitor* savedMonitor_; - - public: - explicit AutoEntryMonitor(JSContext* cx); - ~AutoEntryMonitor(); - - // 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, - 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, - const char* asyncCause) = 0; +class MOZ_STACK_CLASS JS_PUBLIC_API AutoEntryMonitor { + JSContext* cx_; + AutoEntryMonitor* savedMonitor_; + + public: + explicit AutoEntryMonitor(JSContext* cx); + ~AutoEntryMonitor(); + + // 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, 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, + const char* asyncCause) = 0; - // Execution of the function or script has ended. - virtual void Exit(JSContext* cx) { } + // Execution of the function or script has ended. + virtual void Exit(JSContext* cx) {} }; - - -} // namespace dbg -} // namespace JS - +} // namespace dbg +} // namespace JS #endif /* js_Debug_h */ 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 @@ -4,136 +4,404 @@ * 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/. */ +/* + * High-level interface to the JS garbage collector. + */ + #ifndef js_GCAPI_h #define js_GCAPI_h +#include "mozilla/TimeStamp.h" #include "mozilla/Vector.h" #include "js/GCAnnotations.h" -#include "js/HeapAPI.h" +#include "js/TypeDecls.h" #include "js/UniquePtr.h" +#include "js/Utility.h" + +struct JSFreeOp; + +#ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattributes" +#endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING + +class JS_PUBLIC_API JSTracer; + +#ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING +#pragma GCC diagnostic pop +#endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING namespace js { namespace gc { class GCRuntime; -} // namespace gc +} // namespace gc namespace gcstats { struct Statistics; -} // namespace gcstats -} // namespace js +} // namespace gcstats +} // namespace js typedef enum JSGCMode { - /** Perform only global GCs. */ - JSGC_MODE_GLOBAL = 0, + /** Perform only global GCs. */ + JSGC_MODE_GLOBAL = 0, - /** Perform per-zone GCs until too much garbage has accumulated. */ - JSGC_MODE_ZONE = 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_ZONE. - */ - JSGC_MODE_INCREMENTAL = 2 + /** + * Collect in short time slices rather than all at once. Implies + * JSGC_MODE_ZONE. + */ + JSGC_MODE_INCREMENTAL = 2 } JSGCMode; /** * Kinds of js_GC invocation. */ typedef enum JSGCInvocationKind { - /* Normal invocation. */ - GC_NORMAL = 0, + /* Normal invocation. */ + GC_NORMAL = 0, - /* Minimize GC triggers and release empty GC chunks right away. */ - GC_SHRINK = 1 + /* Minimize GC triggers and release empty GC chunks right away. */ + GC_SHRINK = 1 } JSGCInvocationKind; +typedef enum JSGCParamKey { + /** + * Maximum nominal heap before last ditch GC. + * + * Soft limit on the number of bytes we are allowed to allocate in the GC + * heap. Attempts to allocate gcthings over this limit will return null and + * subsequently invoke the standard OOM machinery, independent of available + * physical memory. + * + * Pref: javascript.options.mem.max + * Default: 0xffffffff + */ + JSGC_MAX_BYTES = 0, + + /** + * Initial value for the malloc bytes threshold. + * + * Pref: javascript.options.mem.high_water_mark + * Default: TuningDefaults::MaxMallocBytes + */ + JSGC_MAX_MALLOC_BYTES = 1, + + /** + * Maximum size of the generational GC nurseries. + * + * Pref: javascript.options.mem.nursery.max_kb + * Default: JS::DefaultNurseryBytes + */ + JSGC_MAX_NURSERY_BYTES = 2, + + /** Amount of bytes allocated by the GC. */ + JSGC_BYTES = 3, + + /** Number of times GC has been invoked. Includes both major and minor GC. */ + JSGC_NUMBER = 4, + + /** + * Select GC mode. + * + * See: JSGCMode in GCAPI.h + * prefs: javascript.options.mem.gc_per_zone and + * javascript.options.mem.gc_incremental. + * Default: JSGC_MODE_INCREMENTAL + */ + JSGC_MODE = 6, + + /** Number of cached empty GC chunks. */ + JSGC_UNUSED_CHUNKS = 7, + + /** Total number of allocated GC chunks. */ + JSGC_TOTAL_CHUNKS = 8, + + /** + * Max milliseconds to spend in an incremental GC slice. + * + * Pref: javascript.options.mem.gc_incremental_slice_ms + * Default: DefaultTimeBudget. + */ + JSGC_SLICE_TIME_BUDGET = 9, + + /** + * Maximum size the GC mark stack can grow to. + * + * Pref: none + * Default: MarkStack::DefaultCapacity + */ + JSGC_MARK_STACK_LIMIT = 10, + + /** + * GCs less than this far apart in time will be considered 'high-frequency + * GCs'. + * + * See setGCLastBytes in jsgc.cpp. + * + * Pref: javascript.options.mem.gc_high_frequency_time_limit_ms + * Default: HighFrequencyThresholdUsec + */ + JSGC_HIGH_FREQUENCY_TIME_LIMIT = 11, + + /** + * Start of dynamic heap growth. + * + * Pref: javascript.options.mem.gc_high_frequency_low_limit_mb + * Default: HighFrequencyLowLimitBytes + */ + JSGC_HIGH_FREQUENCY_LOW_LIMIT = 12, + + /** + * End of dynamic heap growth. + * + * Pref: javascript.options.mem.gc_high_frequency_high_limit_mb + * Default: HighFrequencyHighLimitBytes + */ + JSGC_HIGH_FREQUENCY_HIGH_LIMIT = 13, + + /** + * Upper bound of heap growth. + * + * Pref: javascript.options.mem.gc_high_frequency_heap_growth_max + * Default: HighFrequencyHeapGrowthMax + */ + JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX = 14, + + /** + * Lower bound of heap growth. + * + * Pref: javascript.options.mem.gc_high_frequency_heap_growth_min + * Default: HighFrequencyHeapGrowthMin + */ + JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN = 15, + + /** + * Heap growth for low frequency GCs. + * + * Pref: javascript.options.mem.gc_low_frequency_heap_growth + * Default: LowFrequencyHeapGrowth + */ + JSGC_LOW_FREQUENCY_HEAP_GROWTH = 16, + + /** + * If false, the heap growth factor is fixed at 3. If true, it is determined + * based on whether GCs are high- or low- frequency. + * + * Pref: javascript.options.mem.gc_dynamic_heap_growth + * Default: DynamicHeapGrowthEnabled + */ + JSGC_DYNAMIC_HEAP_GROWTH = 17, + + /** + * If true, high-frequency GCs will use a longer mark slice. + * + * Pref: javascript.options.mem.gc_dynamic_mark_slice + * Default: DynamicMarkSliceEnabled + */ + JSGC_DYNAMIC_MARK_SLICE = 18, + + /** + * Lower limit after which we limit the heap growth. + * + * The base value used to compute zone->threshold.gcTriggerBytes(). When + * usage.gcBytes() surpasses threshold.gcTriggerBytes() for a zone, the + * zone may be scheduled for a GC, depending on the exact circumstances. + * + * Pref: javascript.options.mem.gc_allocation_threshold_mb + * Default GCZoneAllocThresholdBase + */ + JSGC_ALLOCATION_THRESHOLD = 19, + + /** + * We try to keep at least this many unused chunks in the free chunk pool at + * all times, even after a shrinking GC. + * + * Pref: javascript.options.mem.gc_min_empty_chunk_count + * Default: MinEmptyChunkCount + */ + JSGC_MIN_EMPTY_CHUNK_COUNT = 21, + + /** + * We never keep more than this many unused chunks in the free chunk + * pool. + * + * Pref: javascript.options.mem.gc_min_empty_chunk_count + * Default: MinEmptyChunkCount + */ + JSGC_MAX_EMPTY_CHUNK_COUNT = 22, + + /** + * Whether compacting GC is enabled. + * + * Pref: javascript.options.mem.gc_compacting + * Default: CompactingEnabled + */ + JSGC_COMPACTING_ENABLED = 23, + + /** + * Factor for triggering a GC based on JSGC_ALLOCATION_THRESHOLD + * + * Default: ZoneAllocThresholdFactorDefault + * Pref: None + */ + JSGC_ALLOCATION_THRESHOLD_FACTOR = 25, + + /** + * Factor for triggering a GC based on JSGC_ALLOCATION_THRESHOLD. + * Used if another GC (in different zones) is already running. + * + * Default: ZoneAllocThresholdFactorAvoidInterruptDefault + * Pref: None + */ + JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT = 26, +} JSGCParamKey; + +/* + * Generic trace operation that calls JS::TraceEdge on each traceable thing's + * location reachable from data. + */ +typedef void (*JSTraceDataOp)(JSTracer* trc, void* data); + +typedef enum JSGCStatus { JSGC_BEGIN, JSGC_END } JSGCStatus; + +typedef void (*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 zones, before anything has been + * swept. The collector will not yield to the mutator before calling the + * callback with JSFINALIZE_GROUP_START status. + */ + JSFINALIZE_GROUP_PREPARE, + + /** + * Called after preparing to sweep a group of zones. Weak references to + * unmarked things have been removed at this point, but no GC things have + * been swept. The collector may yield to the mutator after this point. + */ + JSFINALIZE_GROUP_START, + + /** + * Called after sweeping a group of zones. All dead GC things have been + * swept at this point. + */ + JSFINALIZE_GROUP_END, + + /** + * Called at the end of collection when everything has been swept. + */ + JSFINALIZE_COLLECTION_END +} JSFinalizeStatus; + +typedef void (*JSFinalizeCallback)(JSFreeOp* fop, JSFinalizeStatus status, + void* data); + +typedef void (*JSWeakPointerZonesCallback)(JSContext* cx, void* data); + +typedef void (*JSWeakPointerCompartmentCallback)(JSContext* cx, + JSCompartment* comp, + void* data); + +/** + * Finalizes external strings created by JS_NewExternalString. The finalizer + * can be called off the main thread. + */ +struct JSStringFinalizer { + void (*finalize)(const JSStringFinalizer* fin, char16_t* chars); +}; + namespace JS { -#define GCREASONS(D) \ - /* Reasons internal to the JS engine */ \ - D(API) \ - D(EAGER_ALLOC_TRIGGER) \ - D(DESTROY_RUNTIME) \ - D(UNUSED0) \ - D(LAST_DITCH) \ - D(TOO_MUCH_MALLOC) \ - D(ALLOC_TRIGGER) \ - D(DEBUG_GC) \ - D(COMPARTMENT_REVIVED) \ - D(RESET) \ - D(OUT_OF_NURSERY) \ - D(EVICT_NURSERY) \ - D(FULL_STORE_BUFFER) \ - D(SHARED_MEMORY_LIMIT) \ - D(UNUSED1) \ - D(INCREMENTAL_TOO_SLOW) \ - D(ABORT_GC) \ - \ - /* These are reserved for future use. */ \ - D(RESERVED0) \ - D(RESERVED1) \ - D(RESERVED2) \ - D(RESERVED3) \ - D(RESERVED4) \ - D(RESERVED5) \ - D(RESERVED6) \ - D(RESERVED7) \ - D(RESERVED8) \ - D(RESERVED9) \ - D(RESERVED10) \ - D(RESERVED11) \ - D(RESERVED12) \ - D(RESERVED13) \ - D(RESERVED14) \ - D(RESERVED15) \ - \ - /* Reasons from Firefox */ \ - D(DOM_WINDOW_UTILS) \ - D(COMPONENT_UTILS) \ - D(MEM_PRESSURE) \ - D(CC_WAITING) \ - D(CC_FORCED) \ - D(LOAD_END) \ - D(POST_COMPARTMENT) \ - D(PAGE_HIDE) \ - D(NSJSCONTEXT_DESTROY) \ - D(SET_NEW_DOCUMENT) \ - D(SET_DOC_SHELL) \ - D(DOM_UTILS) \ - D(DOM_IPC) \ - D(DOM_WORKER) \ - D(INTER_SLICE_GC) \ - D(REFRESH_FRAME) \ - D(FULL_GC_TIMER) \ - D(SHUTDOWN_CC) \ - D(FINISH_LARGE_EVALUATE) \ - D(USER_INACTIVE) \ - D(XPCONNECT_SHUTDOWN) +#define GCREASONS(D) \ + /* Reasons internal to the JS engine */ \ + D(API) \ + D(EAGER_ALLOC_TRIGGER) \ + D(DESTROY_RUNTIME) \ + D(ROOTS_REMOVED) \ + D(LAST_DITCH) \ + D(TOO_MUCH_MALLOC) \ + D(ALLOC_TRIGGER) \ + D(DEBUG_GC) \ + D(COMPARTMENT_REVIVED) \ + D(RESET) \ + D(OUT_OF_NURSERY) \ + D(EVICT_NURSERY) \ + D(DELAYED_ATOMS_GC) \ + D(SHARED_MEMORY_LIMIT) \ + D(IDLE_TIME_COLLECTION) \ + D(INCREMENTAL_TOO_SLOW) \ + D(ABORT_GC) \ + D(FULL_WHOLE_CELL_BUFFER) \ + D(FULL_GENERIC_BUFFER) \ + D(FULL_VALUE_BUFFER) \ + D(FULL_CELL_PTR_BUFFER) \ + D(FULL_SLOT_BUFFER) \ + D(FULL_SHAPE_BUFFER) \ + \ + /* These are reserved for future use. */ \ + D(RESERVED0) \ + D(RESERVED1) \ + D(RESERVED2) \ + D(RESERVED3) \ + D(RESERVED4) \ + D(RESERVED5) \ + D(RESERVED6) \ + D(RESERVED7) \ + D(RESERVED8) \ + D(RESERVED9) \ + \ + /* Reasons from Firefox */ \ + D(DOM_WINDOW_UTILS) \ + D(COMPONENT_UTILS) \ + D(MEM_PRESSURE) \ + D(CC_WAITING) \ + D(CC_FORCED) \ + D(LOAD_END) \ + D(POST_COMPARTMENT) \ + D(PAGE_HIDE) \ + D(NSJSCONTEXT_DESTROY) \ + D(SET_NEW_DOCUMENT) \ + D(SET_DOC_SHELL) \ + D(DOM_UTILS) \ + D(DOM_IPC) \ + D(DOM_WORKER) \ + D(INTER_SLICE_GC) \ + D(UNUSED1) \ + D(FULL_GC_TIMER) \ + D(SHUTDOWN_CC) \ + D(UNUSED2) \ + D(USER_INACTIVE) \ + D(XPCONNECT_SHUTDOWN) \ + D(DOCSHELL) \ + D(HTML_PARSER) namespace gcreason { /* GCReasons will end up looking like JSGC_MAYBEGC */ enum Reason { #define MAKE_REASON(name) name, - GCREASONS(MAKE_REASON) + GCREASONS(MAKE_REASON) #undef MAKE_REASON - NO_REASON, - NUM_REASONS, + NO_REASON, + NUM_REASONS, - /* - * For telemetry, we want to keep a fixed max bucket size over time so we - * don't have to switch histograms. 100 is conservative; as of this writing - * there are 52. But the cost of extra buckets seems to be low while the - * cost of switching histograms is high. - */ - NUM_TELEMETRY_REASONS = 100 + /* + * For telemetry, we want to keep a fixed max bucket size over time so we + * don't have to switch histograms. 100 is conservative; as of this writing + * there are 52. But the cost of extra buckets seems to be low while the + * cost of switching histograms is high. + */ + 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); +extern JS_PUBLIC_API const char* ExplainReason(JS::gcreason::Reason reason); } /* namespace gcreason */ @@ -154,36 +422,31 @@ /** * Schedule the given zone to be collected as part of the next GC. */ -extern JS_PUBLIC_API(void) -PrepareZoneForGC(Zone* zone); +extern JS_PUBLIC_API void PrepareZoneForGC(Zone* zone); /** * Schedule all zones to be collected in the next GC. */ -extern JS_PUBLIC_API(void) -PrepareForFullGC(JSContext* cx); +extern JS_PUBLIC_API void PrepareForFullGC(JSContext* cx); /** * When performing an incremental GC, the zones that were selected for the * previous incremental slice must be selected in subsequent slices as well. * This function selects those slices automatically. */ -extern JS_PUBLIC_API(void) -PrepareForIncrementalGC(JSContext* cx); +extern JS_PUBLIC_API void 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(JSContext* cx); +extern JS_PUBLIC_API bool IsGCScheduled(JSContext* cx); /** * Undoes the effect of the Prepare methods above. The given zone will not be * collected in the next GC. */ -extern JS_PUBLIC_API(void) -SkipZoneForGC(Zone* zone); +extern JS_PUBLIC_API void SkipZoneForGC(Zone* zone); /* * Non-Incremental GC: @@ -200,8 +463,8 @@ * to objects will be cleared and all unreferenced objects will be removed from * the system. */ -extern JS_PUBLIC_API(void) -GCForReason(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason); +extern JS_PUBLIC_API void GCForReason(JSContext* cx, JSGCInvocationKind gckind, + gcreason::Reason reason); /* * Incremental GC: @@ -232,9 +495,10 @@ * 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(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason, - int64_t millis = 0); +extern JS_PUBLIC_API void StartIncrementalGC(JSContext* cx, + JSGCInvocationKind gckind, + gcreason::Reason reason, + int64_t millis = 0); /** * Perform a slice of an ongoing incremental collection. When this function @@ -244,8 +508,9 @@ * Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or * shorter than the requested interval. */ -extern JS_PUBLIC_API(void) -IncrementalGCSlice(JSContext* cx, gcreason::Reason reason, int64_t millis = 0); +extern JS_PUBLIC_API void IncrementalGCSlice(JSContext* cx, + gcreason::Reason reason, + int64_t millis = 0); /** * If IsIncrementalGCInProgress(cx), this call finishes the ongoing collection @@ -253,8 +518,8 @@ * this is equivalent to GCForReason. When this function returns, * IsIncrementalGCInProgress(cx) will always be false. */ -extern JS_PUBLIC_API(void) -FinishIncrementalGC(JSContext* cx, gcreason::Reason reason); +extern JS_PUBLIC_API void FinishIncrementalGC(JSContext* cx, + gcreason::Reason reason); /** * If IsIncrementalGCInProgress(cx), this call aborts the ongoing collection and @@ -262,138 +527,147 @@ * state. This may take an arbitrarily long time. When this function returns, * IsIncrementalGCInProgress(cx) will always be false. */ -extern JS_PUBLIC_API(void) -AbortIncrementalGC(JSContext* cx); +extern JS_PUBLIC_API void AbortIncrementalGC(JSContext* cx); namespace dbg { // The `JS::dbg::GarbageCollectionEvent` class is essentially a view of the // `js::gcstats::Statistics` data without the uber implementation-specific bits. // It should generally be palatable for web developers. -class GarbageCollectionEvent -{ - // The major GC number of the GC cycle this data pertains to. - uint64_t majorGCNumber_; - - // Reference to a non-owned, statically allocated C string. This is a very - // short reason explaining why a GC was triggered. - const char* reason; - - // Reference to a nullable, non-owned, statically allocated C string. If the - // collection was forced to be non-incremental, this is a short reason of - // why the GC could not perform an incremental collection. - const char* nonincrementalReason; - - // Represents a single slice of a possibly multi-slice incremental garbage - // collection. - struct Collection { - double startTimestamp; - double endTimestamp; - }; - - // The set of garbage collection slices that made up this GC cycle. - mozilla::Vector collections; - - GarbageCollectionEvent(const GarbageCollectionEvent& rhs) = delete; - GarbageCollectionEvent& operator=(const GarbageCollectionEvent& rhs) = delete; - - public: - explicit GarbageCollectionEvent(uint64_t majorGCNum) - : majorGCNumber_(majorGCNum) - , reason(nullptr) - , nonincrementalReason(nullptr) - , collections() - { } +class GarbageCollectionEvent { + // The major GC number of the GC cycle this data pertains to. + uint64_t majorGCNumber_; - using Ptr = js::UniquePtr; - static Ptr Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t majorGCNumber); + // Reference to a non-owned, statically allocated C string. This is a very + // short reason explaining why a GC was triggered. + const char* reason; - JSObject* toJSObject(JSContext* cx) const; + // Reference to a nullable, non-owned, statically allocated C string. If the + // collection was forced to be non-incremental, this is a short reason of + // why the GC could not perform an incremental collection. + const char* nonincrementalReason; - uint64_t majorGCNumber() const { return majorGCNumber_; } -}; + // Represents a single slice of a possibly multi-slice incremental garbage + // collection. + struct Collection { + mozilla::TimeStamp startTimestamp; + mozilla::TimeStamp endTimestamp; + }; -} // namespace dbg + // The set of garbage collection slices that made up this GC cycle. + mozilla::Vector collections; -enum GCProgress { - /* - * During non-incremental GC, the GC is bracketed by JSGC_CYCLE_BEGIN/END - * callbacks. During an incremental GC, the sequence of callbacks is as - * follows: - * JSGC_CYCLE_BEGIN, JSGC_SLICE_END (first slice) - * JSGC_SLICE_BEGIN, JSGC_SLICE_END (second slice) - * ... - * JSGC_SLICE_BEGIN, JSGC_CYCLE_END (last slice) - */ - - GC_CYCLE_BEGIN, - GC_SLICE_BEGIN, - GC_SLICE_END, - GC_CYCLE_END + GarbageCollectionEvent(const GarbageCollectionEvent& rhs) = delete; + GarbageCollectionEvent& operator=(const GarbageCollectionEvent& rhs) = delete; + + public: + explicit GarbageCollectionEvent(uint64_t majorGCNum) + : majorGCNumber_(majorGCNum), + reason(nullptr), + nonincrementalReason(nullptr), + collections() {} + + using Ptr = js::UniquePtr; + static Ptr Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, + uint64_t majorGCNumber); + + JSObject* toJSObject(JSContext* cx) const; + + uint64_t majorGCNumber() const { return majorGCNumber_; } }; -struct JS_PUBLIC_API(GCDescription) { - bool isZone_; - JSGCInvocationKind invocationKind_; - gcreason::Reason reason_; - - GCDescription(bool isZone, JSGCInvocationKind kind, gcreason::Reason reason) - : isZone_(isZone), invocationKind_(kind), reason_(reason) {} - - char16_t* formatSliceMessage(JSContext* cx) const; - char16_t* formatSummaryMessage(JSContext* cx) const; - char16_t* formatJSON(JSContext* cx, uint64_t timestamp) const; +} // namespace dbg + +enum GCProgress { + /* + * During GC, the GC is bracketed by GC_CYCLE_BEGIN/END callbacks. Each + * slice between those (whether an incremental or the sole non-incremental + * slice) is bracketed by GC_SLICE_BEGIN/GC_SLICE_END. + */ + + GC_CYCLE_BEGIN, + GC_SLICE_BEGIN, + GC_SLICE_END, + GC_CYCLE_END +}; + +struct JS_PUBLIC_API GCDescription { + bool isZone_; + bool isComplete_; + JSGCInvocationKind invocationKind_; + gcreason::Reason reason_; + + GCDescription(bool isZone, bool isComplete, JSGCInvocationKind kind, + gcreason::Reason reason) + : isZone_(isZone), + isComplete_(isComplete), + invocationKind_(kind), + reason_(reason) {} + + char16_t* formatSliceMessage(JSContext* cx) const; + char16_t* formatSummaryMessage(JSContext* cx) const; + char16_t* formatJSON(JSContext* cx, uint64_t timestamp) const; + + mozilla::TimeStamp startTime(JSContext* cx) const; + mozilla::TimeStamp endTime(JSContext* cx) const; + mozilla::TimeStamp lastSliceStart(JSContext* cx) const; + mozilla::TimeStamp lastSliceEnd(JSContext* cx) const; + + JS::UniqueChars sliceToJSON(JSContext* cx) const; + JS::UniqueChars summaryToJSON(JSContext* cx) const; - JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSContext* cx) const; + JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSContext* cx) const; }; -typedef void -(* GCSliceCallback)(JSContext* cx, GCProgress progress, const GCDescription& desc); +extern JS_PUBLIC_API UniqueChars MinorGcToJSON(JSContext* cx); + +typedef void (*GCSliceCallback)(JSContext* cx, GCProgress progress, + const GCDescription& desc); /** * The GC slice callback is called at the beginning and end of each slice. This * callback may be used for GC notifications as well as to perform additional * marking. */ -extern JS_PUBLIC_API(GCSliceCallback) +extern JS_PUBLIC_API GCSliceCallback 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 + /** + * 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); +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); +extern JS_PUBLIC_API GCNurseryCollectionCallback SetGCNurseryCollectionCallback( + JSContext* cx, GCNurseryCollectionCallback callback); -typedef void -(* DoCycleCollectionCallback)(JSContext* cx); +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) +extern JS_PUBLIC_API DoCycleCollectionCallback SetDoCycleCollectionCallback(JSContext* cx, DoCycleCollectionCallback callback); /** @@ -402,8 +676,7 @@ * There is not currently a way to re-enable incremental GC once it has been * disabled on the runtime. */ -extern JS_PUBLIC_API(void) -DisableIncrementalGC(JSContext* cx); +extern JS_PUBLIC_API void DisableIncrementalGC(JSContext* cx); /** * Returns true if incremental GC is enabled. Simply having incremental GC @@ -413,42 +686,24 @@ * GCDescription returned by GCSliceCallback may help narrow down the cause if * collections are not happening incrementally when expected. */ -extern JS_PUBLIC_API(bool) -IsIncrementalGCEnabled(JSContext* cx); +extern JS_PUBLIC_API bool IsIncrementalGCEnabled(JSContext* cx); /** * Returns true while an incremental GC is ongoing, both when actively * collecting and between slices. */ -extern JS_PUBLIC_API(bool) -IsIncrementalGCInProgress(JSContext* cx); - -/* - * Returns true when writes to GC things must call an incremental (pre) barrier. - * This is generally only true when running mutator code in-between GC slices. - * At other times, the barrier may be elided for performance. - */ -extern JS_PUBLIC_API(bool) -IsIncrementalBarrierNeeded(JSContext* cx); +extern JS_PUBLIC_API bool IsIncrementalGCInProgress(JSContext* cx); -/* - * Notify the GC that a reference to a GC thing is about to be overwritten. - * These methods must be called if IsIncrementalBarrierNeeded. +/** + * Returns true while an incremental GC is ongoing, both when actively + * collecting and between slices. */ -extern JS_PUBLIC_API(void) -IncrementalReferenceBarrier(GCCellPtr thing); - -extern JS_PUBLIC_API(void) -IncrementalValueBarrier(const Value& v); - -extern JS_PUBLIC_API(void) -IncrementalObjectBarrier(JSObject* obj); +extern JS_PUBLIC_API bool IsIncrementalGCInProgress(JSRuntime* rt); /** * Returns true if the most recent GC ran incrementally. */ -extern JS_PUBLIC_API(bool) -WasIncrementalGC(JSContext* cx); +extern JS_PUBLIC_API bool WasIncrementalGC(JSRuntime* rt); /* * Generational GC: @@ -459,40 +714,36 @@ */ /** Ensure that generational GC is disabled within some scope. */ -class JS_PUBLIC_API(AutoDisableGenerationalGC) -{ - js::gc::GCRuntime* gc; - - public: - explicit AutoDisableGenerationalGC(JSRuntime* rt); - ~AutoDisableGenerationalGC(); +class JS_PUBLIC_API AutoDisableGenerationalGC { + JSContext* cx; + + public: + explicit AutoDisableGenerationalGC(JSContext* cx); + ~AutoDisableGenerationalGC(); }; /** * Returns true if generational allocation and collection is currently enabled * on the given runtime. */ -extern JS_PUBLIC_API(bool) -IsGenerationalGCEnabled(JSRuntime* rt); +extern JS_PUBLIC_API bool IsGenerationalGCEnabled(JSRuntime* rt); /** * Returns the GC's "number". This does not correspond directly to the number * of GCs that have been run, but is guaranteed to be monotonically increasing * with GC activity. */ -extern JS_PUBLIC_API(size_t) -GetGCNumber(); +extern JS_PUBLIC_API size_t GetGCNumber(); /** * Pass a subclass of this "abstract" class to callees to require that they * never GC. Subclasses can use assertions or the hazard analysis to ensure no * GC happens. */ -class JS_PUBLIC_API(AutoRequireNoGC) -{ - protected: - AutoRequireNoGC() {} - ~AutoRequireNoGC() {} +class JS_PUBLIC_API AutoRequireNoGC { + protected: + AutoRequireNoGC() {} + ~AutoRequireNoGC() {} }; /** @@ -503,59 +754,27 @@ * This works by entering a GC unsafe region, which is checked on allocation and * on GC. */ -class JS_PUBLIC_API(AutoAssertNoGC) : public AutoRequireNoGC -{ - js::gc::GCRuntime* gc; - size_t gcNumber; - - public: - AutoAssertNoGC(); - explicit AutoAssertNoGC(JSRuntime* rt); - explicit AutoAssertNoGC(JSContext* cx); - ~AutoAssertNoGC(); -}; - -/** - * Assert if an allocation of a GC thing occurs while this class is live. This - * class does not disable the static rooting hazard analysis. - */ -class JS_PUBLIC_API(AutoAssertNoAlloc) -{ -#ifdef JS_DEBUG - js::gc::GCRuntime* gc; - - public: - AutoAssertNoAlloc() : gc(nullptr) {} - explicit AutoAssertNoAlloc(JSContext* cx); - void disallowAlloc(JSRuntime* rt); - ~AutoAssertNoAlloc(); +class JS_PUBLIC_API AutoAssertNoGC : public AutoRequireNoGC { +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + JSContext* cx_; + + public: + // This gets the context from TLS if it is not passed in. + explicit AutoAssertNoGC(JSContext* cx = nullptr); + ~AutoAssertNoGC(); #else - public: - AutoAssertNoAlloc() {} - explicit AutoAssertNoAlloc(JSContext* cx) {} - void disallowAlloc(JSRuntime* rt) {} + public: + explicit AutoAssertNoGC(JSContext* cx = nullptr) {} + ~AutoAssertNoGC() {} #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 - * in complex regions, since it cannot understand dataflow. + * Disable the static rooting hazard analysis in the live region and assert in + * debug builds 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 in complex regions, since it cannot understand + * dataflow. * * Note: GC behavior is unpredictable even when deterministic and is generally * non-deterministic in practice. The fact that this guard has not @@ -565,12 +784,18 @@ * that the hazard analysis is correct for that code, rather than relying * on this class. */ -class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertNoAlloc -{ - public: - AutoSuppressGCAnalysis() : AutoAssertNoAlloc() {} - explicit AutoSuppressGCAnalysis(JSContext* cx) : AutoAssertNoAlloc(cx) {} +#ifdef DEBUG +class JS_PUBLIC_API AutoSuppressGCAnalysis : public AutoAssertNoGC { + public: + explicit AutoSuppressGCAnalysis(JSContext* cx = nullptr) + : AutoAssertNoGC(cx) {} } JS_HAZ_GC_SUPPRESSED; +#else +class JS_PUBLIC_API AutoSuppressGCAnalysis : public AutoRequireNoGC { + public: + explicit AutoSuppressGCAnalysis(JSContext* cx = nullptr) {} +} JS_HAZ_GC_SUPPRESSED; +#endif /** * Assert that code is only ever called from a GC callback, disable the static @@ -580,10 +805,13 @@ * This is useful to make the static analysis ignore code that runs in GC * callbacks. */ -class JS_PUBLIC_API(AutoAssertGCCallback) : public AutoSuppressGCAnalysis -{ - public: - explicit AutoAssertGCCallback(JSObject* obj); +class JS_PUBLIC_API AutoAssertGCCallback : public AutoSuppressGCAnalysis { + public: +#ifdef DEBUG + AutoAssertGCCallback(); +#else + AutoAssertGCCallback() {} +#endif }; /** @@ -599,125 +827,175 @@ * We only do the assertion checking in DEBUG builds. */ #ifdef DEBUG -class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertNoGC -{ - public: - AutoCheckCannotGC() : AutoAssertNoGC() {} - explicit AutoCheckCannotGC(JSContext* cx) : AutoAssertNoGC(cx) {} +class JS_PUBLIC_API AutoCheckCannotGC : public AutoAssertNoGC { + public: + explicit AutoCheckCannotGC(JSContext* cx = nullptr) : AutoAssertNoGC(cx) {} } JS_HAZ_GC_INVALIDATED; #else -class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoRequireNoGC -{ - public: - AutoCheckCannotGC() {} - explicit AutoCheckCannotGC(JSContext* cx) {} +class JS_PUBLIC_API AutoCheckCannotGC : public AutoRequireNoGC { + public: + explicit AutoCheckCannotGC(JSContext* cx = nullptr) {} } 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. The return value indicates - * if anything was unmarked. +/* + * Internal to Firefox. */ -extern JS_FRIEND_API(bool) -UnmarkGrayGCThingRecursively(GCCellPtr thing); +extern JS_FRIEND_API void NotifyGCRootsRemoved(JSContext* cx); } /* namespace JS */ -namespace js { -namespace gc { +/** + * Register externally maintained GC roots. + * + * traceOp: the trace operation. For each root the implementation should call + * 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(JSContext* cx, + JSTraceDataOp traceOp, + void* data); -static MOZ_ALWAYS_INLINE void -ExposeGCThingToActiveJS(JS::GCCellPtr thing) -{ - // 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; - - // 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 (!thing.mayBeOwnedByOtherRuntime() && js::gc::detail::CellIsMarkedGray(thing.asCell())) - JS::UnmarkGrayGCThingRecursively(thing); -} +/** Undo a call to JS_AddExtraGCRootsTracer. */ +extern JS_PUBLIC_API void JS_RemoveExtraGCRootsTracer(JSContext* cx, + JSTraceDataOp traceOp, + void* data); -static MOZ_ALWAYS_INLINE void -MarkGCThingAsLive(JSRuntime* aRt, JS::GCCellPtr thing) -{ - // 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; +extern JS_PUBLIC_API void JS_GC(JSContext* cx); - JS::shadow::Runtime* rt = JS::shadow::Runtime::asShadowRuntime(aRt); - MOZ_DIAGNOSTIC_ASSERT(rt->allowGCBarriers()); +extern JS_PUBLIC_API void JS_MaybeGC(JSContext* cx); - if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing)) - JS::IncrementalReferenceBarrier(thing); -} +extern JS_PUBLIC_API void JS_SetGCCallback(JSContext* cx, JSGCCallback cb, + void* data); -} /* namespace gc */ -} /* namespace js */ +extern JS_PUBLIC_API void JS_SetObjectsTenuredCallback( + JSContext* cx, JSObjectsTenuredCallback cb, void* data); -namespace JS { +extern JS_PUBLIC_API bool JS_AddFinalizeCallback(JSContext* cx, + JSFinalizeCallback cb, + void* data); + +extern JS_PUBLIC_API void JS_RemoveFinalizeCallback(JSContext* cx, + JSFinalizeCallback cb); /* - * This should be called when an object that is marked gray is exposed to the JS - * engine (by handing it to running JS code or writing it into live JS - * data). During incremental GC, since the gray bits haven't been computed yet, - * we conservatively mark the object black. - */ -static MOZ_ALWAYS_INLINE void -ExposeObjectToActiveJS(JSObject* obj) -{ - MOZ_ASSERT(obj); - js::gc::ExposeGCThingToActiveJS(GCCellPtr(obj)); -} + * Weak pointers and garbage collection + * + * Weak pointers are by their nature not marked as part of garbage collection, + * but they may need to be updated in two cases after a GC: + * + * 1) Their referent was found not to be live and is about to be finalized + * 2) Their referent has been moved by a compacting GC + * + * To handle this, any part of the system that maintain weak pointers to + * JavaScript GC things must register a callback with + * JS_(Add,Remove)WeakPointer{ZoneGroup,Compartment}Callback(). This callback + * must then call JS_UpdateWeakPointerAfterGC() on all weak pointers it knows + * about. + * + * Since sweeping is incremental, we have several callbacks to avoid repeatedly + * having to visit all embedder structures. The WeakPointerZonesCallback is + * called once for each strongly connected group of zones, whereas the + * WeakPointerCompartmentCallback is called once for each compartment that is + * visited while sweeping. Structures that cannot contain references in more + * than one compartment should sweep the relevant per-compartment structures + * using the latter callback to minimizer per-slice overhead. + * + * The argument to JS_UpdateWeakPointerAfterGC() is an in-out param. If the + * referent is about to be finalized the pointer will be set to null. If the + * referent has been moved then the pointer will be updated to point to the 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 bool JS_AddWeakPointerZonesCallback( + JSContext* cx, JSWeakPointerZonesCallback cb, void* data); + +extern JS_PUBLIC_API void JS_RemoveWeakPointerZonesCallback( + JSContext* cx, JSWeakPointerZonesCallback cb); + +extern JS_PUBLIC_API bool JS_AddWeakPointerCompartmentCallback( + JSContext* cx, JSWeakPointerCompartmentCallback cb, void* data); -static MOZ_ALWAYS_INLINE void -ExposeScriptToActiveJS(JSScript* script) -{ - js::gc::ExposeGCThingToActiveJS(GCCellPtr(script)); +extern JS_PUBLIC_API void JS_RemoveWeakPointerCompartmentCallback( + JSContext* cx, JSWeakPointerCompartmentCallback cb); + +namespace JS { +template +class Heap; } -/* - * If a GC is currently marking, mark the string black. +extern JS_PUBLIC_API void JS_UpdateWeakPointerAfterGC( + JS::Heap* objp); + +extern JS_PUBLIC_API void JS_UpdateWeakPointerAfterGCUnbarriered( + JSObject** objp); + +extern JS_PUBLIC_API void JS_SetGCParameter(JSContext* cx, JSGCParamKey key, + uint32_t value); + +extern JS_PUBLIC_API void JS_ResetGCParameter(JSContext* cx, JSGCParamKey key); + +extern JS_PUBLIC_API uint32_t JS_GetGCParameter(JSContext* cx, + JSGCParamKey key); + +extern JS_PUBLIC_API void JS_SetGCParametersBasedOnAvailableMemory( + JSContext* cx, uint32_t availMem); + +/** + * Create a new JSString whose chars member refers to external memory, i.e., + * memory requiring application-specific finalization. */ -static MOZ_ALWAYS_INLINE void -MarkStringAsLive(Zone* zone, JSString* string) -{ - JSRuntime* rt = JS::shadow::Zone::asShadowZone(zone)->runtimeFromMainThread(); - js::gc::MarkGCThingAsLive(rt, GCCellPtr(string)); -} +extern JS_PUBLIC_API JSString* JS_NewExternalString( + JSContext* cx, const char16_t* chars, size_t length, + const JSStringFinalizer* fin); -/* - * Internal to Firefox. - * - * Note: this is not related to the PokeGC in nsJSEnvironment. +/** + * Create a new JSString whose chars member may refer to external memory. + * If a new external string is allocated, |*allocatedExternal| is set to true. + * Otherwise the returned string is either not an external string or an + * external string allocated by a previous call and |*allocatedExternal| is set + * to false. If |*allocatedExternal| is false, |fin| won't be called. */ -extern JS_FRIEND_API(void) -PokeGC(JSContext* cx); +extern JS_PUBLIC_API JSString* JS_NewMaybeExternalString( + JSContext* cx, const char16_t* chars, size_t length, + const JSStringFinalizer* fin, bool* allocatedExternal); -/* - * Internal to Firefox. +/** + * Return whether 'str' was created with JS_NewExternalString or + * JS_NewExternalStringWithClosure. */ -extern JS_FRIEND_API(void) -NotifyDidPaint(JSContext* cx); +extern JS_PUBLIC_API bool JS_IsExternalString(JSString* str); -} /* namespace JS */ +/** + * Return the 'fin' arg passed to JS_NewExternalString. + */ +extern JS_PUBLIC_API const JSStringFinalizer* JS_GetExternalStringFinalizer( + JSString* str); + +namespace JS { + +extern JS_PUBLIC_API bool IsIdleGCTaskNeeded(JSRuntime* rt); + +extern JS_PUBLIC_API void RunIdleTimeGCTask(JSRuntime* rt); + +} // namespace JS + +namespace js { +namespace gc { + +/** + * Create an object providing access to the garbage collector's internal notion + * of the current state of memory (both GC heap memory and GCthing-controlled + * malloc memory. + */ +extern JS_PUBLIC_API JSObject* NewMemoryInfoObject(JSContext* cx); + +} /* namespace gc */ +} /* namespace js */ #endif /* js_GCAPI_h */ 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 @@ -12,19 +12,19 @@ #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"))) +#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"))) +#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"))) +#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"))) +#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 @@ -33,24 +33,24 @@ // but makes sense for something like ErrorResult, which only contains a GC // pointer when it holds an exception (and it does its own rooting, // conditionally.) -# define JS_HAZ_NON_GC_POINTER __attribute__((tag("Suppressed GC Pointer"))) +#define JS_HAZ_NON_GC_POINTER __attribute__((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"))) +#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"))) +#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 +#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 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,6 +7,8 @@ #ifndef GCHashTable_h #define GCHashTable_h +#include "mozilla/Maybe.h" + #include "js/GCPolicyAPI.h" #include "js/HashTable.h" #include "js/RootingAPI.h" @@ -18,9 +20,9 @@ // Define a reasonable default GC policy for GC-aware Maps. template struct DefaultMapSweepPolicy { - static bool needsSweep(Key* key, Value* value) { - return GCPolicy::needsSweep(key) || GCPolicy::needsSweep(value); - } + static bool needsSweep(Key* key, Value* value) { + return GCPolicy::needsSweep(key) || GCPolicy::needsSweep(value); + } }; // A GCHashMap is a GC-aware HashMap, meaning that it has additional trace and @@ -47,52 +49,51 @@ // 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 = js::TempAllocPolicy, typename MapSweepPolicy = DefaultMapSweepPolicy> -class GCHashMap : public js::HashMap -{ - using Base = js::HashMap; - - public: - explicit GCHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {} - - static void trace(GCHashMap* map, JSTracer* trc) { map->trace(trc); } - void trace(JSTracer* trc) { - if (!this->initialized()) - return; - for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { - GCPolicy::trace(trc, &e.front().value(), "hashmap value"); - GCPolicy::trace(trc, &e.front().mutableKey(), "hashmap key"); - } - } - - void sweep() { - if (!this->initialized()) - return; - - for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { - if (MapSweepPolicy::needsSweep(&e.front().mutableKey(), &e.front().value())) - e.removeFront(); - } - } - - // GCHashMap is movable - GCHashMap(GCHashMap&& rhs) : Base(mozilla::Move(rhs)) {} - void operator=(GCHashMap&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - Base::operator=(mozilla::Move(rhs)); - } - - private: - // GCHashMap is not copyable or assignable - GCHashMap(const GCHashMap& hm) = delete; - GCHashMap& operator=(const GCHashMap& hm) = delete; +class GCHashMap : public js::HashMap { + using Base = js::HashMap; + + public: + explicit GCHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {} + + static void trace(GCHashMap* map, JSTracer* trc) { map->trace(trc); } + void trace(JSTracer* trc) { + if (!this->initialized()) return; + for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { + GCPolicy::trace(trc, &e.front().value(), "hashmap value"); + GCPolicy::trace(trc, &e.front().mutableKey(), "hashmap key"); + } + } + + bool needsSweep() const { return this->initialized() && !this->empty(); } + + void sweep() { + if (!this->initialized()) return; + + for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { + if (MapSweepPolicy::needsSweep(&e.front().mutableKey(), + &e.front().value())) + e.removeFront(); + } + } + + // GCHashMap is movable + GCHashMap(GCHashMap&& rhs) : Base(mozilla::Move(rhs)) {} + void operator=(GCHashMap&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); + Base::operator=(mozilla::Move(rhs)); + } + + private: + // GCHashMap is not copyable or assignable + GCHashMap(const GCHashMap& hm) = delete; + GCHashMap& operator=(const GCHashMap& hm) = delete; }; -} // namespace JS +} // namespace JS namespace js { @@ -101,137 +102,117 @@ // 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 = JS::GCHashMap; - using Lookup = typename Map::Lookup; - - 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); } - Range all() const { return map().all(); } - bool empty() const { return map().empty(); } - 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 = JS::GCHashMap; - using Lookup = typename Map::Lookup; - - 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(); } - void remove(Ptr p) { map().remove(p); } - - template - bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { - return map().add(p, mozilla::Forward(k), mozilla::Forward(v)); - } - - template - bool add(AddPtr& p, KeyInput&& k) { - return map().add(p, mozilla::Forward(k), Map::Value()); - } - - template - bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { - return map().relookupOrAdd(p, k, - mozilla::Forward(k), - mozilla::Forward(v)); - } - - template - bool put(KeyInput&& k, ValueInput&& v) { - return map().put(mozilla::Forward(k), mozilla::Forward(v)); - } - - template - bool putNew(KeyInput&& k, ValueInput&& v) { - return map().putNew(mozilla::Forward(k), mozilla::Forward(v)); - } +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 WrappedPtrOperations, Wrapper> { + using Map = JS::GCHashMap; + using Lookup = typename Map::Lookup; + + 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); } + Range all() const { return map().all(); } + bool empty() const { return map().empty(); } + 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 MutableWrappedPtrOperations, Wrapper> + : public WrappedPtrOperations, Wrapper> { + using Map = JS::GCHashMap; + using Lookup = typename Map::Lookup; + + Map& map() { return static_cast(this)->get(); } + + public: + using AddPtr = typename Map::AddPtr; + struct Enum : public Map::Enum { + explicit Enum(Wrapper& 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(); } + void remove(Ptr p) { map().remove(p); } + + template + bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { + return map().add(p, mozilla::Forward(k), + mozilla::Forward(v)); + } + + template + bool add(AddPtr& p, KeyInput&& k) { + return map().add(p, mozilla::Forward(k), Map::Value()); + } + + template + bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { + return map().relookupOrAdd(p, k, mozilla::Forward(k), + mozilla::Forward(v)); + } + + template + bool put(KeyInput&& k, ValueInput&& v) { + return map().put(mozilla::Forward(k), + mozilla::Forward(v)); + } + + template + bool putNew(KeyInput&& k, ValueInput&& v) { + return map().putNew(mozilla::Forward(k), + mozilla::Forward(v)); + } }; -template -class RootedBase> - : public MutableGCHashMapOperations>, A,B,C,D,E> -{}; - -template -class MutableHandleBase> - : public MutableGCHashMapOperations>, A,B,C,D,E> -{}; - -template -class HandleBase> - : public GCHashMapOperations>, A,B,C,D,E> -{}; - -template -class WeakCacheBase> - : public MutableGCHashMapOperations>, A,B,C,D,E> -{}; - -} // namespace js +} // namespace js namespace JS { @@ -248,152 +229,518 @@ // 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 , +template , typename AllocPolicy = js::TempAllocPolicy> -class GCHashSet : public js::HashSet -{ - using Base = js::HashSet; - - public: - explicit GCHashSet(AllocPolicy a = AllocPolicy()) : Base(a) {} - - static void trace(GCHashSet* set, JSTracer* trc) { set->trace(trc); } - void trace(JSTracer* trc) { - if (!this->initialized()) - return; - for (typename Base::Enum e(*this); !e.empty(); e.popFront()) - 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())) - e.removeFront(); - } - } - - // GCHashSet is movable - GCHashSet(GCHashSet&& rhs) : Base(mozilla::Move(rhs)) {} - void operator=(GCHashSet&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - Base::operator=(mozilla::Move(rhs)); - } - - private: - // GCHashSet is not copyable or assignable - GCHashSet(const GCHashSet& hs) = delete; - GCHashSet& operator=(const GCHashSet& hs) = delete; -}; - -} // namespace JS +class GCHashSet : public js::HashSet { + using Base = js::HashSet; -namespace js { + public: + explicit GCHashSet(AllocPolicy a = AllocPolicy()) : Base(a) {} -template -class GCHashSetOperations -{ - using Set = JS::GCHashSet; - using Lookup = typename Set::Lookup; - - 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); } - Range all() const { return set().all(); } - bool empty() const { return set().empty(); } - 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); - } + static void trace(GCHashSet* set, JSTracer* trc) { set->trace(trc); } + void trace(JSTracer* trc) { + if (!this->initialized()) return; + for (typename Base::Enum e(*this); !e.empty(); e.popFront()) + GCPolicy::trace(trc, &e.mutableFront(), "hashset element"); + } + + bool needsSweep() const { return this->initialized() && !this->empty(); } + + void sweep() { + if (!this->initialized()) return; + for (typename Base::Enum e(*this); !e.empty(); e.popFront()) { + if (GCPolicy::needsSweep(&e.mutableFront())) e.removeFront(); + } + } + + // GCHashSet is movable + GCHashSet(GCHashSet&& rhs) : Base(mozilla::Move(rhs)) {} + void operator=(GCHashSet&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); + Base::operator=(mozilla::Move(rhs)); + } + + private: + // GCHashSet is not copyable or assignable + GCHashSet(const GCHashSet& hs) = delete; + GCHashSet& operator=(const GCHashSet& hs) = delete; }; -template -class MutableGCHashSetOperations - : public GCHashSetOperations -{ - using Set = JS::GCHashSet; - using Lookup = typename Set::Lookup; - - 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 - bool add(AddPtr& p, TInput&& t) { - return set().add(p, mozilla::Forward(t)); - } - - template - bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) { - return set().relookupOrAdd(p, l, mozilla::Forward(t)); - } - - template - bool put(TInput&& t) { - return set().put(mozilla::Forward(t)); - } +} // namespace JS - template - bool putNew(TInput&& t) { - return set().putNew(mozilla::Forward(t)); - } - - template - bool putNew(const Lookup& l, TInput&& t) { - return set().putNew(l, mozilla::Forward(t)); - } -}; +namespace js { -template -class RootedBase> - : public MutableGCHashSetOperations>, T, HP, AP> -{ +template +class WrappedPtrOperations, Wrapper> { + using Set = JS::GCHashSet; + + const Set& set() const { return static_cast(this)->get(); } + + public: + using Lookup = typename Set::Lookup; + 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); } + Range all() const { return set().all(); } + bool empty() const { return set().empty(); } + 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 MutableWrappedPtrOperations, Wrapper> + : public WrappedPtrOperations, Wrapper> { + using Set = JS::GCHashSet; + using Lookup = typename Set::Lookup; + + 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(Wrapper& 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 + bool add(AddPtr& p, TInput&& t) { + return set().add(p, mozilla::Forward(t)); + } + + template + bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) { + return set().relookupOrAdd(p, l, mozilla::Forward(t)); + } + + template + bool put(TInput&& t) { + return set().put(mozilla::Forward(t)); + } + + template + bool putNew(TInput&& t) { + return set().putNew(mozilla::Forward(t)); + } + + template + bool putNew(const Lookup& l, TInput&& t) { + return set().putNew(l, mozilla::Forward(t)); + } }; -template -class MutableHandleBase> - : public MutableGCHashSetOperations>, T, HP, AP> -{ -}; +} /* namespace js */ -template -class HandleBase> - : public GCHashSetOperations>, T, HP, AP> -{ -}; +namespace JS { -template -class WeakCacheBase> - : public MutableGCHashSetOperations>, T, HP, AP> -{ +// Specialize WeakCache for GCHashMap to provide a barriered map that does not +// need to be swept immediately. +template +class WeakCache> + : protected detail::WeakCacheBase { + using Map = GCHashMap; + using Self = WeakCache; + + Map map; + bool needsBarrier; + + public: + template + explicit WeakCache(Zone* zone, Args&&... args) + : WeakCacheBase(zone), + map(mozilla::Forward(args)...), + needsBarrier(false) {} + template + explicit WeakCache(JSRuntime* rt, Args&&... args) + : WeakCacheBase(rt), + map(mozilla::Forward(args)...), + needsBarrier(false) {} + ~WeakCache() { MOZ_ASSERT(!needsBarrier); } + + bool needsSweep() override { return map.needsSweep(); } + + size_t sweep() override { + if (!this->initialized()) return 0; + + size_t steps = map.count(); + map.sweep(); + return steps; + } + + bool setNeedsIncrementalBarrier(bool needs) override { + MOZ_ASSERT(needsBarrier != needs); + needsBarrier = needs; + return true; + } + + bool needsIncrementalBarrier() const override { return needsBarrier; } + + private: + using Entry = typename Map::Entry; + + static bool entryNeedsSweep(const Entry& prior) { + Key key(prior.key()); + Value value(prior.value()); + bool result = MapSweepPolicy::needsSweep(&key, &value); + MOZ_ASSERT(prior.key() == key); // We shouldn't update here. + MOZ_ASSERT(prior.value() == value); // We shouldn't update here. + return result; + } + + public: + using Lookup = typename Map::Lookup; + using Ptr = typename Map::Ptr; + using AddPtr = typename Map::AddPtr; + + struct Range { + explicit Range(const typename Map::Range& r) : range(r) { settle(); } + Range() {} + + bool empty() const { return range.empty(); } + const Entry& front() const { return range.front(); } + + void popFront() { + range.popFront(); + settle(); + } + + private: + typename Map::Range range; + + void settle() { + while (!empty() && entryNeedsSweep(front())) popFront(); + } + }; + + struct Enum : public Map::Enum { + explicit Enum(Self& cache) : Map::Enum(cache.map) { + // This operation is not allowed while barriers are in place as we + // may also need to enumerate the set for sweeping. + MOZ_ASSERT(!cache.needsBarrier); + } + }; + + bool initialized() const { return map.initialized(); } + + Ptr lookup(const Lookup& l) const { + Ptr ptr = map.lookup(l); + if (needsBarrier && ptr && entryNeedsSweep(*ptr)) { + const_cast(map).remove(ptr); + return Ptr(); + } + return ptr; + } + + AddPtr lookupForAdd(const Lookup& l) const { + AddPtr ptr = map.lookupForAdd(l); + if (needsBarrier && ptr && entryNeedsSweep(*ptr)) { + const_cast(map).remove(ptr); + return map.lookupForAdd(l); + } + return ptr; + } + + Range all() const { return Range(map.all()); } + + bool empty() const { + // This operation is not currently allowed while barriers are in place + // as it would require iterating the map and the caller expects a + // constant time operation. + MOZ_ASSERT(!needsBarrier); + return map.empty(); + } + + uint32_t count() const { + // This operation is not currently allowed while barriers are in place + // as it would require iterating the set and the caller expects a + // constant time operation. + MOZ_ASSERT(!needsBarrier); + return map.count(); + } + + size_t capacity() const { return map.capacity(); } + + bool has(const Lookup& l) const { return 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); + } + + bool init(uint32_t len = 16) { + MOZ_ASSERT(!needsBarrier); + return map.init(len); + } + + void clear() { + // This operation is not currently allowed while barriers are in place + // since it doesn't make sense to clear a cache while it is being swept. + MOZ_ASSERT(!needsBarrier); + map.clear(); + } + + void finish() { + // This operation is not currently allowed while barriers are in place + // since it doesn't make sense to destroy a cache while it is being swept. + MOZ_ASSERT(!needsBarrier); + map.finish(); + } + + void remove(Ptr p) { + // This currently supports removing entries during incremental + // sweeping. If we allow these tables to be swept incrementally this may + // no longer be possible. + map.remove(p); + } + + void remove(const Lookup& l) { + Ptr p = lookup(l); + if (p) remove(p); + } + + template + bool add(AddPtr& p, KeyInput&& k) { + using mozilla::Forward; + return map.add(p, Forward(k)); + } + + template + bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { + using mozilla::Forward; + return map.add(p, Forward(k), Forward(v)); + } + + template + bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { + using mozilla::Forward; + return map.relookupOrAdd(p, Forward(k), Forward(v)); + } + + template + bool put(KeyInput&& k, ValueInput&& v) { + using mozilla::Forward; + return map.put(Forward(k), Forward(v)); + } + + template + bool putNew(KeyInput&& k, ValueInput&& v) { + using mozilla::Forward; + return map.putNew(Forward(k), Forward(v)); + } +}; + +// Specialize WeakCache for GCHashSet to provide a barriered set that does not +// need to be swept immediately. +template +class WeakCache> + : protected detail::WeakCacheBase { + using Set = GCHashSet; + using Self = WeakCache; + + Set set; + bool needsBarrier; + + public: + using Entry = typename Set::Entry; + + template + explicit WeakCache(Zone* zone, Args&&... args) + : WeakCacheBase(zone), + set(mozilla::Forward(args)...), + needsBarrier(false) {} + template + explicit WeakCache(JSRuntime* rt, Args&&... args) + : WeakCacheBase(rt), + set(mozilla::Forward(args)...), + needsBarrier(false) {} + + size_t sweep() override { + if (!this->initialized()) return 0; + + size_t steps = set.count(); + set.sweep(); + return steps; + } + + bool needsSweep() override { return set.needsSweep(); } + + bool setNeedsIncrementalBarrier(bool needs) override { + MOZ_ASSERT(needsBarrier != needs); + needsBarrier = needs; + return true; + } + + bool needsIncrementalBarrier() const override { return needsBarrier; } + + private: + static bool entryNeedsSweep(const Entry& prior) { + Entry entry(prior); + bool result = GCPolicy::needsSweep(&entry); + MOZ_ASSERT(prior == entry); // We shouldn't update here. + return result; + } + + public: + using Lookup = typename Set::Lookup; + using Ptr = typename Set::Ptr; + using AddPtr = typename Set::AddPtr; + + struct Range { + explicit Range(const typename Set::Range& r) : range(r) { settle(); } + Range() {} + + bool empty() const { return range.empty(); } + const Entry& front() const { return range.front(); } + + void popFront() { + range.popFront(); + settle(); + } + + private: + typename Set::Range range; + + void settle() { + while (!empty() && entryNeedsSweep(front())) popFront(); + } + }; + + struct Enum : public Set::Enum { + explicit Enum(Self& cache) : Set::Enum(cache.set) { + // This operation is not allowed while barriers are in place as we + // may also need to enumerate the set for sweeping. + MOZ_ASSERT(!cache.needsBarrier); + } + }; + + bool initialized() const { return set.initialized(); } + + Ptr lookup(const Lookup& l) const { + Ptr ptr = set.lookup(l); + if (needsBarrier && ptr && entryNeedsSweep(*ptr)) { + const_cast(set).remove(ptr); + return Ptr(); + } + return ptr; + } + + AddPtr lookupForAdd(const Lookup& l) const { + AddPtr ptr = set.lookupForAdd(l); + if (needsBarrier && ptr && entryNeedsSweep(*ptr)) { + const_cast(set).remove(ptr); + return set.lookupForAdd(l); + } + return ptr; + } + + Range all() const { return Range(set.all()); } + + bool empty() const { + // This operation is not currently allowed while barriers are in place + // as it would require iterating the set and the caller expects a + // constant time operation. + MOZ_ASSERT(!needsBarrier); + return set.empty(); + } + + uint32_t count() const { + // This operation is not currently allowed while barriers are in place + // as it would require iterating the set and the caller expects a + // constant time operation. + MOZ_ASSERT(!needsBarrier); + return set.count(); + } + + size_t capacity() const { return set.capacity(); } + + bool has(const Lookup& l) const { return 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); + } + + bool init(uint32_t len = 16) { + MOZ_ASSERT(!needsBarrier); + return set.init(len); + } + + void clear() { + // This operation is not currently allowed while barriers are in place + // since it doesn't make sense to clear a cache while it is being swept. + MOZ_ASSERT(!needsBarrier); + set.clear(); + } + + void finish() { + // This operation is not currently allowed while barriers are in place + // since it doesn't make sense to destroy a cache while it is being swept. + MOZ_ASSERT(!needsBarrier); + set.finish(); + } + + void remove(Ptr p) { + // This currently supports removing entries during incremental + // sweeping. If we allow these tables to be swept incrementally this may + // no longer be possible. + set.remove(p); + } + + void remove(const Lookup& l) { + Ptr p = lookup(l); + if (p) remove(p); + } + + template + bool add(AddPtr& p, TInput&& t) { + return set.add(p, mozilla::Forward(t)); + } + + template + bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) { + return set.relookupOrAdd(p, l, mozilla::Forward(t)); + } + + template + bool put(TInput&& t) { + return set.put(mozilla::Forward(t)); + } + + template + bool putNew(TInput&& t) { + return set.putNew(mozilla::Forward(t)); + } + + template + bool putNew(const Lookup& l, TInput&& t) { + return set.putNew(l, mozilla::Forward(t)); + } }; -} /* namespace js */ +} // namespace JS #endif /* GCHashTable_h */ 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 @@ -40,125 +40,155 @@ #ifndef GCPolicyAPI_h #define GCPolicyAPI_h +#include "mozilla/Maybe.h" #include "mozilla/UniquePtr.h" #include "js/TraceKind.h" #include "js/TracingAPI.h" +#include "js/TypeDecls.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*) + 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) + 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; -} +#define FOR_EACH_PUBLIC_AGGREGATE_GC_POINTER_TYPE(D) D(JSPropertyDescriptor) 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(); - } +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(); } + + static bool isValid(const T& tp) { return true; } }; // 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 {}; +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); - } + static T initial() { return T(); } + static void trace(JSTracer* trc, T* t, const char* name) {} + static bool needsSweep(T* v) { return false; } + static bool isValid(const T& v) { return true; } +}; +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; + } + static bool isValid(T v) { return js::gc::IsCellPointerValidOrNull(v); } +}; +template <> +struct GCPolicy : public GCPointerPolicy {}; +template <> +struct GCPolicy : public GCPointerPolicy {}; +template <> +struct GCPolicy : public GCPointerPolicy {}; +template <> +struct GCPolicy : public GCPointerPolicy {}; +template <> +struct GCPolicy : public GCPointerPolicy {}; +template <> +struct GCPolicy : public GCPointerPolicy {}; + +template +struct NonGCPointerPolicy { + static T initial() { return nullptr; } + static void trace(JSTracer* trc, T* vp, const char* name) { + if (*vp) (*vp)->trace(trc); + } + static bool needsSweep(T* vp) { + if (*vp) return (*vp)->needsSweep(); + return false; + } + static bool isValid(T v) { return true; } +}; + +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 *thingp && 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; - } +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; + } + static bool isValid(const mozilla::UniquePtr& t) { + if (t.get()) return GCPolicy::isValid(*t.get()); + return true; + } }; -} // namespace JS +// GCPolicy> forwards tracing/sweeping to GCPolicy if +// when the Maybe is full. +template +struct GCPolicy> { + static mozilla::Maybe initial() { return mozilla::Maybe(); } + static void trace(JSTracer* trc, mozilla::Maybe* tp, const char* name) { + if (tp->isSome()) GCPolicy::trace(trc, tp->ptr(), name); + } + static bool needsSweep(mozilla::Maybe* tp) { + if (tp->isSome()) return GCPolicy::needsSweep(tp->ptr()); + return false; + } + static bool isValid(const mozilla::Maybe& t) { + if (t.isSome()) return GCPolicy::isValid(t.ref()); + return true; + } +}; + +template <> +struct GCPolicy; // see Realm.h + +} // namespace JS -#endif // GCPolicyAPI_h +#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 @@ -43,156 +43,149 @@ // 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)); - } +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); - } +struct GCVariantImplementation { + using Next = GCVariantImplementation; - 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); + 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 +} // namespace detail template -struct GCPolicy> -{ - using Impl = detail::GCVariantImplementation; +struct GCPolicy> { + using Impl = detail::GCVariantImplementation; - // Variants do not provide initial(). They do not have a default initial - // value and one must be provided. + // 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 { + static void trace(JSTracer* trc, mozilla::Variant* v, + const char* name) { + Impl::trace(trc, v, name); + } -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(); - } + static bool isValid(const mozilla::Variant& v) { + return v.match(IsValidMatcher()); + } + private: + struct IsValidMatcher { 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())); - } + bool match(T& v) { + return GCPolicy::isValid(v); + }; + }; }; -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(); } +} // namespace JS - public: - template - JS::MutableHandle as() { - return JS::MutableHandle::fromMarkedLocation(&variant().template as()); - } +namespace js { - template - typename Matcher::ReturnType - match(Matcher& matcher) { - return Impl::match(matcher, JS::MutableHandle::fromMarkedLocation(&variant())); - } +template +class WrappedPtrOperations, Wrapper> { + 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 RootedBase> - : public MutableGCVariantOperations>, Ts...> -{ }; - -template -class MutableHandleBase> - : public MutableGCVariantOperations>, Ts...> -{ }; - -template -class HandleBase> - : public GCVariantOperations>, Ts...> -{ }; - -template -class PersistentRootedBase> - : public MutableGCVariantOperations>, Ts...> -{ }; +template +class MutableWrappedPtrOperations, Wrapper> + : public WrappedPtrOperations, Wrapper> { + 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())); + } +}; -} // namespace js +} // namespace js -#endif // js_GCVariant_h +#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 @@ -30,220 +30,253 @@ // 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); - } +class GCVector { + mozilla::Vector vector; - void popBack() { return vector.popBack(); } - T popCopy() { return vector.popCopy(); } + public: + explicit GCVector(AllocPolicy alloc = AllocPolicy()) : vector(alloc) {} - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return vector.sizeOfExcludingThis(mallocSizeOf); - } + GCVector(GCVector&& vec) : vector(mozilla::Move(vec.vector)) {} - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return vector.sizeOfIncludingThis(mallocSizeOf); + 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); } + MOZ_MUST_USE bool reserve(size_t req) { return vector.reserve(req); } + void shrinkBy(size_t amount) { return vector.shrinkBy(amount); } + MOZ_MUST_USE bool growBy(size_t amount) { return vector.growBy(amount); } + MOZ_MUST_USE bool resize(size_t newLen) { return vector.resize(newLen); } + + void clear() { return vector.clear(); } + void clearAndFree() { return vector.clearAndFree(); } + + template + bool append(U&& item) { + return vector.append(mozilla::Forward(item)); + } + + template + MOZ_MUST_USE 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 + MOZ_MUST_USE bool appendAll(const U& aU) { + return vector.append(aU.begin(), aU.end()); + } + + MOZ_MUST_USE bool appendN(const T& val, size_t count) { + return vector.appendN(val, count); + } + + template + MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd) { + return vector.append(aBegin, aEnd); + } + template + MOZ_MUST_USE 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"); + } + + bool needsSweep() const { return !this->empty(); } + + void sweep() { + uint32_t src, dst = 0; + for (src = 0; src < length(); src++) { + if (!GCPolicy::needsSweep(&vector[src])) { + if (dst != src) vector[dst] = vector[src].unbarrieredGet(); + dst++; + } } - static void trace(GCVector* vec, JSTracer* trc) { vec->trace(trc); } - - void trace(JSTracer* trc) { - for (auto& elem : vector) - GCPolicy::trace(trc, &elem, "vector element"); - } + if (dst != length()) vector.shrinkTo(dst); + } }; -} // namespace JS +} // 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(); } +template +class WrappedPtrOperations, Wrapper> { + 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)); + } +}; - JS::Handle operator[](size_t aIndex) const { - return JS::Handle::fromMarkedLocation(&vec().operator[](aIndex)); - } +template +class MutableWrappedPtrOperations, + Wrapper> + : public WrappedPtrOperations, + Wrapper> { + 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)); + } + + MOZ_MUST_USE bool initCapacity(size_t aRequest) { + return vec().initCapacity(aRequest); + } + MOZ_MUST_USE bool reserve(size_t aRequest) { return vec().reserve(aRequest); } + void shrinkBy(size_t aIncr) { vec().shrinkBy(aIncr); } + MOZ_MUST_USE bool growBy(size_t aIncr) { return vec().growBy(aIncr); } + MOZ_MUST_USE bool resize(size_t aNewLength) { + return vec().resize(aNewLength); + } + MOZ_MUST_USE bool growByUninitialized(size_t aIncr) { + return vec().growByUninitialized(aIncr); + } + void infallibleGrowByUninitialized(size_t aIncr) { + vec().infallibleGrowByUninitialized(aIncr); + } + MOZ_MUST_USE bool resizeUninitialized(size_t aNewLength) { + return vec().resizeUninitialized(aNewLength); + } + void clear() { vec().clear(); } + void clearAndFree() { vec().clearAndFree(); } + template + MOZ_MUST_USE bool append(U&& aU) { + return vec().append(mozilla::Forward(aU)); + } + template + MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) { + return vec().emplaceBack(mozilla::Forward(aArgs...)); + } + template + MOZ_MUST_USE bool appendAll(const U& aU) { + return vec().appendAll(aU); + } + MOZ_MUST_USE bool appendN(const T& aT, size_t aN) { + return vec().appendN(aT, aN); + } + template + MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd) { + return vec().append(aBegin, aEnd); + } + template + MOZ_MUST_USE 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 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(); } +} // namespace js - 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)); - } +namespace JS { - 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); } -}; +// An automatically rooted vector for stack use. +template +class AutoVector : public Rooted> { + using Vec = GCVector; + using Base = Rooted; -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> -{}; + public: + explicit AutoVector(JSContext* cx) : Base(cx, Vec(cx)) {} +}; -} // namespace js +} // namespace JS -#endif // js_GCVector_h +#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 @@ -26,12 +26,16 @@ namespace js { class TempAllocPolicy; -template struct DefaultHasher; -template class HashMapEntry; +template +struct DefaultHasher; +template +class HashMapEntry; namespace detail { - template class HashTableEntry; - template class HashTable; -} // namespace detail +template +class HashTableEntry; +template +class HashTable; +} // namespace detail /*****************************************************************************/ @@ -56,249 +60,249 @@ // HashPolicy requirements: // - see Hash Policy section below // AllocPolicy: -// - see jsalloc.h +// - see AllocPolicy.h // // Note: // - HashMap is not reentrant: Key/Value/HashPolicy/AllocPolicy members // called by HashMap must not call back into the same HashMap object. // - Due to the lack of exception handling, the user must call |init()|. -template , +template , class AllocPolicy = TempAllocPolicy> -class HashMap -{ - typedef HashMapEntry TableEntry; - - struct MapHashPolicy : HashPolicy - { - using Base = HashPolicy; - typedef Key KeyType; - static const Key& getKey(TableEntry& e) { return e.key(); } - static void setKey(TableEntry& e, Key& k) { HashPolicy::rekey(e.mutableKey(), k); } - }; - - typedef detail::HashTable Impl; - Impl impl; - - public: - typedef typename HashPolicy::Lookup Lookup; - typedef TableEntry Entry; - - // HashMap construction is fallible (due to OOM); thus the user must call - // init after constructing a HashMap and check the return value. - explicit HashMap(AllocPolicy a = AllocPolicy()) : impl(a) {} - MOZ_MUST_USE bool init(uint32_t len = 16) { return impl.init(len); } - bool initialized() const { return impl.initialized(); } - - // Return whether the given lookup value is present in the map. E.g.: - // - // typedef HashMap HM; - // HM h; - // if (HM::Ptr p = h.lookup(3)) { - // const HM::Entry& e = *p; // p acts like a pointer to Entry - // assert(p->key == 3); // Entry contains the key - // char val = p->value; // and value - // } - // - // Also see the definition of Ptr in HashTable above (with T = Entry). - typedef typename Impl::Ptr Ptr; - Ptr lookup(const Lookup& l) const { return impl.lookup(l); } - - // Like lookup, but does not assert if two threads call lookup at the same - // time. Only use this method when none of the threads will modify the map. - Ptr readonlyThreadsafeLookup(const Lookup& l) const { return impl.readonlyThreadsafeLookup(l); } - - // Assuming |p.found()|, remove |*p|. - void remove(Ptr p) { impl.remove(p); } - - // Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient - // insertion of Key |k| (where |HashPolicy::match(k,l) == true|) using - // |add(p,k,v)|. After |add(p,k,v)|, |p| points to the new Entry. E.g.: - // - // typedef HashMap HM; - // HM h; - // HM::AddPtr p = h.lookupForAdd(3); - // if (!p) { - // if (!h.add(p, 3, 'a')) - // return false; - // } - // const HM::Entry& e = *p; // p acts like a pointer to Entry - // assert(p->key == 3); // Entry contains the key - // char val = p->value; // and value - // - // Also see the definition of AddPtr in HashTable above (with T = Entry). - // - // N.B. The caller must ensure that no mutating hash table operations - // occur between a pair of |lookupForAdd| and |add| calls. To avoid - // looking up the key a second time, the caller may use the more efficient - // relookupOrAdd method. This method reuses part of the hashing computation - // to more efficiently insert the key if it has not been added. For - // example, a mutation-handling version of the previous example: - // - // HM::AddPtr p = h.lookupForAdd(3); - // if (!p) { - // call_that_may_mutate_h(); - // if (!h.relookupOrAdd(p, 3, 'a')) - // return false; - // } - // const HM::Entry& e = *p; - // assert(p->key == 3); - // char val = p->value; - typedef typename Impl::AddPtr AddPtr; - AddPtr lookupForAdd(const Lookup& l) const { - return impl.lookupForAdd(l); - } - - template - MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { - return impl.add(p, - mozilla::Forward(k), - mozilla::Forward(v)); - } - - template - MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k) { - return impl.add(p, mozilla::Forward(k), Value()); - } - - template - MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { - return impl.relookupOrAdd(p, k, - mozilla::Forward(k), - mozilla::Forward(v)); - } - - // |all()| returns a Range containing |count()| elements. E.g.: - // - // typedef HashMap HM; - // HM h; - // for (HM::Range r = h.all(); !r.empty(); r.popFront()) - // char c = r.front().value(); - // - // Also see the definition of Range in HashTable above (with T = Entry). - typedef typename Impl::Range Range; - Range all() const { return impl.all(); } - - // Typedef for the enumeration class. An Enum may be used to examine and - // remove table entries: - // - // typedef HashMap HM; - // HM s; - // for (HM::Enum e(s); !e.empty(); e.popFront()) - // if (e.front().value() == 'l') - // e.removeFront(); - // - // Table resize may occur in Enum's destructor. Also see the definition of - // Enum in HashTable above (with T = Entry). - typedef typename Impl::Enum Enum; - - // Remove all entries. This does not shrink the table. For that consider - // using the finish() method. - void clear() { impl.clear(); } - - // Remove all the entries and release all internal buffers. The map must - // be initialized again before any use. - void finish() { impl.finish(); } - - // Does the table contain any entries? - bool empty() const { return impl.empty(); } - - // Number of live elements in the map. - uint32_t count() const { return impl.count(); } +class HashMap { + typedef HashMapEntry TableEntry; - // Total number of allocation in the dynamic table. Note: resize will - // happen well before count() == capacity(). - size_t capacity() const { return impl.capacity(); } - - // Don't just call |impl.sizeOfExcludingThis()| because there's no - // guarantee that |impl| is the first field in HashMap. - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return impl.sizeOfExcludingThis(mallocSizeOf); - } - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); - } - - Generation generation() const { - return impl.generation(); - } - - /************************************************** Shorthand operations */ - - bool has(const Lookup& l) const { - return impl.lookup(l).found(); - } - - // Overwrite existing value with v. Return false on oom. - template - MOZ_MUST_USE bool put(KeyInput&& k, ValueInput&& v) { - AddPtr p = lookupForAdd(k); - if (p) { - p->value() = mozilla::Forward(v); - return true; - } - return add(p, mozilla::Forward(k), mozilla::Forward(v)); - } - - // Like put, but assert that the given key is not already present. - template - MOZ_MUST_USE bool putNew(KeyInput&& k, ValueInput&& v) { - return impl.putNew(k, mozilla::Forward(k), mozilla::Forward(v)); - } - - // Only call this to populate an empty map after reserving space with init(). - template - void putNewInfallible(KeyInput&& k, ValueInput&& v) { - impl.putNewInfallible(k, mozilla::Forward(k), mozilla::Forward(v)); - } - - // Add (k,defaultValue) if |k| is not found. Return a false-y Ptr on oom. - Ptr lookupWithDefault(const Key& k, const Value& defaultValue) { - AddPtr p = lookupForAdd(k); - if (p) - return p; - bool ok = add(p, k, defaultValue); - MOZ_ASSERT_IF(!ok, !p); // p is left false-y on oom. - (void)ok; - return p; - } - - // Remove if present. - void remove(const Lookup& l) { - if (Ptr p = lookup(l)) - remove(p); - } - - // Infallibly rekey one entry, if necessary. - // Requires template parameters Key and HashPolicy::Lookup to be the same type. - void rekeyIfMoved(const Key& old_key, const Key& new_key) { - if (old_key != new_key) - rekeyAs(old_key, new_key, new_key); - } - - // Infallibly rekey one entry if present, and return whether that happened. - bool rekeyAs(const Lookup& old_lookup, const Lookup& new_lookup, const Key& new_key) { - if (Ptr p = lookup(old_lookup)) { - impl.rekeyAndMaybeRehash(p, new_lookup, new_key); - return true; - } - return false; - } - - // HashMap is movable - HashMap(HashMap&& rhs) : impl(mozilla::Move(rhs.impl)) {} - void operator=(HashMap&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - impl = mozilla::Move(rhs.impl); - } - - private: - // HashMap is not copyable or assignable - HashMap(const HashMap& hm) = delete; - HashMap& operator=(const HashMap& hm) = delete; + struct MapHashPolicy : HashPolicy { + using Base = HashPolicy; + typedef Key KeyType; + static const Key& getKey(TableEntry& e) { return e.key(); } + static void setKey(TableEntry& e, Key& k) { + HashPolicy::rekey(e.mutableKey(), k); + } + }; + + typedef detail::HashTable Impl; + Impl impl; + + public: + typedef typename HashPolicy::Lookup Lookup; + typedef TableEntry Entry; + + // HashMap construction is fallible (due to OOM); thus the user must call + // init after constructing a HashMap and check the return value. + explicit HashMap(AllocPolicy a = AllocPolicy()) : impl(a) {} + MOZ_MUST_USE bool init(uint32_t len = 16) { return impl.init(len); } + bool initialized() const { return impl.initialized(); } + + // Return whether the given lookup value is present in the map. E.g.: + // + // typedef HashMap HM; + // HM h; + // if (HM::Ptr p = h.lookup(3)) { + // const HM::Entry& e = *p; // p acts like a pointer to Entry + // assert(p->key == 3); // Entry contains the key + // char val = p->value; // and value + // } + // + // Also see the definition of Ptr in HashTable above (with T = Entry). + typedef typename Impl::Ptr Ptr; + MOZ_ALWAYS_INLINE Ptr lookup(const Lookup& l) const { return impl.lookup(l); } + + // Like lookup, but does not assert if two threads call lookup at the same + // time. Only use this method when none of the threads will modify the map. + MOZ_ALWAYS_INLINE Ptr readonlyThreadsafeLookup(const Lookup& l) const { + return impl.readonlyThreadsafeLookup(l); + } + + // Assuming |p.found()|, remove |*p|. + void remove(Ptr p) { impl.remove(p); } + + // Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient + // insertion of Key |k| (where |HashPolicy::match(k,l) == true|) using + // |add(p,k,v)|. After |add(p,k,v)|, |p| points to the new Entry. E.g.: + // + // typedef HashMap HM; + // HM h; + // HM::AddPtr p = h.lookupForAdd(3); + // if (!p) { + // if (!h.add(p, 3, 'a')) + // return false; + // } + // const HM::Entry& e = *p; // p acts like a pointer to Entry + // assert(p->key == 3); // Entry contains the key + // char val = p->value; // and value + // + // Also see the definition of AddPtr in HashTable above (with T = Entry). + // + // N.B. The caller must ensure that no mutating hash table operations + // occur between a pair of |lookupForAdd| and |add| calls. To avoid + // looking up the key a second time, the caller may use the more efficient + // relookupOrAdd method. This method reuses part of the hashing computation + // to more efficiently insert the key if it has not been added. For + // example, a mutation-handling version of the previous example: + // + // HM::AddPtr p = h.lookupForAdd(3); + // if (!p) { + // call_that_may_mutate_h(); + // if (!h.relookupOrAdd(p, 3, 'a')) + // return false; + // } + // const HM::Entry& e = *p; + // assert(p->key == 3); + // char val = p->value; + typedef typename Impl::AddPtr AddPtr; + MOZ_ALWAYS_INLINE AddPtr lookupForAdd(const Lookup& l) const { + return impl.lookupForAdd(l); + } + + template + MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { + return impl.add(p, mozilla::Forward(k), + mozilla::Forward(v)); + } + + template + MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k) { + return impl.add(p, mozilla::Forward(k), Value()); + } + + template + MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { + return impl.relookupOrAdd(p, k, mozilla::Forward(k), + mozilla::Forward(v)); + } + + // |all()| returns a Range containing |count()| elements. E.g.: + // + // typedef HashMap HM; + // HM h; + // for (HM::Range r = h.all(); !r.empty(); r.popFront()) + // char c = r.front().value(); + // + // Also see the definition of Range in HashTable above (with T = Entry). + typedef typename Impl::Range Range; + Range all() const { return impl.all(); } + + // Typedef for the enumeration class. An Enum may be used to examine and + // remove table entries: + // + // typedef HashMap HM; + // HM s; + // for (HM::Enum e(s); !e.empty(); e.popFront()) + // if (e.front().value() == 'l') + // e.removeFront(); + // + // Table resize may occur in Enum's destructor. Also see the definition of + // Enum in HashTable above (with T = Entry). + typedef typename Impl::Enum Enum; + + // Remove all entries. This does not shrink the table. For that consider + // using the finish() method. + void clear() { impl.clear(); } + + // Remove all entries. Unlike clear() this method tries to shrink the table. + // Unlike finish() it does not require the map to be initialized again. + void clearAndShrink() { impl.clearAndShrink(); } + + // Remove all the entries and release all internal buffers. The map must + // be initialized again before any use. + void finish() { impl.finish(); } + + // Does the table contain any entries? + bool empty() const { return impl.empty(); } + + // Number of live elements in the map. + uint32_t count() const { return impl.count(); } + + // Total number of allocation in the dynamic table. Note: resize will + // happen well before count() == capacity(). + size_t capacity() const { return impl.capacity(); } + + // Don't just call |impl.sizeOfExcludingThis()| because there's no + // guarantee that |impl| is the first field in HashMap. + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return impl.sizeOfExcludingThis(mallocSizeOf); + } + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); + } + + Generation generation() const { return impl.generation(); } + + /************************************************** Shorthand operations */ + + bool has(const Lookup& l) const { return impl.lookup(l).found(); } + + // Overwrite existing value with v. Return false on oom. + template + MOZ_MUST_USE bool put(KeyInput&& k, ValueInput&& v) { + AddPtr p = lookupForAdd(k); + if (p) { + p->value() = mozilla::Forward(v); + return true; + } + return add(p, mozilla::Forward(k), + mozilla::Forward(v)); + } + + // Like put, but assert that the given key is not already present. + template + MOZ_MUST_USE bool putNew(KeyInput&& k, ValueInput&& v) { + return impl.putNew(k, mozilla::Forward(k), + mozilla::Forward(v)); + } + + // Only call this to populate an empty map after reserving space with init(). + template + void putNewInfallible(KeyInput&& k, ValueInput&& v) { + impl.putNewInfallible(k, mozilla::Forward(k), + mozilla::Forward(v)); + } + + // Add (k,defaultValue) if |k| is not found. Return a false-y Ptr on oom. + Ptr lookupWithDefault(const Key& k, const Value& defaultValue) { + AddPtr p = lookupForAdd(k); + if (p) return p; + bool ok = add(p, k, defaultValue); + MOZ_ASSERT_IF(!ok, !p); // p is left false-y on oom. + (void)ok; + return p; + } + + // Remove if present. + void remove(const Lookup& l) { + if (Ptr p = lookup(l)) remove(p); + } + + // Infallibly rekey one entry, if necessary. + // Requires template parameters Key and HashPolicy::Lookup to be the same + // type. + void rekeyIfMoved(const Key& old_key, const Key& new_key) { + if (old_key != new_key) rekeyAs(old_key, new_key, new_key); + } + + // Infallibly rekey one entry if present, and return whether that happened. + bool rekeyAs(const Lookup& old_lookup, const Lookup& new_lookup, + const Key& new_key) { + if (Ptr p = lookup(old_lookup)) { + impl.rekeyAndMaybeRehash(p, new_lookup, new_key); + return true; + } + return false; + } + + // HashMap is movable + HashMap(HashMap&& rhs) : impl(mozilla::Move(rhs.impl)) {} + void operator=(HashMap&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); + impl = mozilla::Move(rhs.impl); + } + + private: + // HashMap is not copyable or assignable + HashMap(const HashMap& hm) = delete; + HashMap& operator=(const HashMap& hm) = delete; - friend class Impl::Enum; + friend class Impl::Enum; }; /*****************************************************************************/ @@ -312,233 +316,233 @@ // HashPolicy requirements: // - see Hash Policy section below // AllocPolicy: -// - see jsalloc.h +// - see AllocPolicy.h // // Note: // - HashSet is not reentrant: T/HashPolicy/AllocPolicy members called by // HashSet must not call back into the same HashSet object. // - Due to the lack of exception handling, the user must call |init()|. -template , +template , class AllocPolicy = TempAllocPolicy> -class HashSet -{ - struct SetOps : HashPolicy - { - using Base = HashPolicy; - typedef T KeyType; - static const KeyType& getKey(const T& t) { return t; } - static void setKey(T& t, KeyType& k) { HashPolicy::rekey(t, k); } - }; - - typedef detail::HashTable Impl; - Impl impl; - - public: - typedef typename HashPolicy::Lookup Lookup; - typedef T Entry; - - // HashSet construction is fallible (due to OOM); thus the user must call - // init after constructing a HashSet and check the return value. - explicit HashSet(AllocPolicy a = AllocPolicy()) : impl(a) {} - MOZ_MUST_USE bool init(uint32_t len = 16) { return impl.init(len); } - bool initialized() const { return impl.initialized(); } - - // Return whether the given lookup value is present in the map. E.g.: - // - // typedef HashSet HS; - // HS h; - // if (HS::Ptr p = h.lookup(3)) { - // assert(*p == 3); // p acts like a pointer to int - // } - // - // Also see the definition of Ptr in HashTable above. - typedef typename Impl::Ptr Ptr; - Ptr lookup(const Lookup& l) const { return impl.lookup(l); } - - // Like lookup, but does not assert if two threads call lookup at the same - // time. Only use this method when none of the threads will modify the map. - Ptr readonlyThreadsafeLookup(const Lookup& l) const { return impl.readonlyThreadsafeLookup(l); } - - // Assuming |p.found()|, remove |*p|. - void remove(Ptr p) { impl.remove(p); } - - // Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient - // insertion of T value |t| (where |HashPolicy::match(t,l) == true|) using - // |add(p,t)|. After |add(p,t)|, |p| points to the new element. E.g.: - // - // typedef HashSet HS; - // HS h; - // HS::AddPtr p = h.lookupForAdd(3); - // if (!p) { - // if (!h.add(p, 3)) - // return false; - // } - // assert(*p == 3); // p acts like a pointer to int - // - // Also see the definition of AddPtr in HashTable above. - // - // N.B. The caller must ensure that no mutating hash table operations - // occur between a pair of |lookupForAdd| and |add| calls. To avoid - // looking up the key a second time, the caller may use the more efficient - // relookupOrAdd method. This method reuses part of the hashing computation - // to more efficiently insert the key if it has not been added. For - // example, a mutation-handling version of the previous example: - // - // HS::AddPtr p = h.lookupForAdd(3); - // if (!p) { - // call_that_may_mutate_h(); - // if (!h.relookupOrAdd(p, 3, 3)) - // return false; - // } - // assert(*p == 3); - // - // Note that relookupOrAdd(p,l,t) performs Lookup using |l| and adds the - // entry |t|, where the caller ensures match(l,t). - typedef typename Impl::AddPtr AddPtr; - AddPtr lookupForAdd(const Lookup& l) const { return impl.lookupForAdd(l); } - - template - MOZ_MUST_USE bool add(AddPtr& p, U&& u) { - return impl.add(p, mozilla::Forward(u)); - } - - template - MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, U&& u) { - return impl.relookupOrAdd(p, l, mozilla::Forward(u)); - } - - // |all()| returns a Range containing |count()| elements: - // - // typedef HashSet HS; - // HS h; - // for (HS::Range r = h.all(); !r.empty(); r.popFront()) - // int i = r.front(); - // - // Also see the definition of Range in HashTable above. - typedef typename Impl::Range Range; - Range all() const { return impl.all(); } +class HashSet { + struct SetOps : HashPolicy { + using Base = HashPolicy; + typedef T KeyType; + static const KeyType& getKey(const T& t) { return t; } + static void setKey(T& t, KeyType& k) { HashPolicy::rekey(t, k); } + }; + + typedef detail::HashTable Impl; + Impl impl; + + public: + typedef typename HashPolicy::Lookup Lookup; + typedef T Entry; + + // HashSet construction is fallible (due to OOM); thus the user must call + // init after constructing a HashSet and check the return value. + explicit HashSet(AllocPolicy a = AllocPolicy()) : impl(a) {} + MOZ_MUST_USE bool init(uint32_t len = 16) { return impl.init(len); } + bool initialized() const { return impl.initialized(); } + + // Return whether the given lookup value is present in the map. E.g.: + // + // typedef HashSet HS; + // HS h; + // if (HS::Ptr p = h.lookup(3)) { + // assert(*p == 3); // p acts like a pointer to int + // } + // + // Also see the definition of Ptr in HashTable above. + typedef typename Impl::Ptr Ptr; + MOZ_ALWAYS_INLINE Ptr lookup(const Lookup& l) const { return impl.lookup(l); } + + // Like lookup, but does not assert if two threads call lookup at the same + // time. Only use this method when none of the threads will modify the map. + MOZ_ALWAYS_INLINE Ptr readonlyThreadsafeLookup(const Lookup& l) const { + return impl.readonlyThreadsafeLookup(l); + } + + // Assuming |p.found()|, remove |*p|. + void remove(Ptr p) { impl.remove(p); } + + // Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient + // insertion of T value |t| (where |HashPolicy::match(t,l) == true|) using + // |add(p,t)|. After |add(p,t)|, |p| points to the new element. E.g.: + // + // typedef HashSet HS; + // HS h; + // HS::AddPtr p = h.lookupForAdd(3); + // if (!p) { + // if (!h.add(p, 3)) + // return false; + // } + // assert(*p == 3); // p acts like a pointer to int + // + // Also see the definition of AddPtr in HashTable above. + // + // N.B. The caller must ensure that no mutating hash table operations + // occur between a pair of |lookupForAdd| and |add| calls. To avoid + // looking up the key a second time, the caller may use the more efficient + // relookupOrAdd method. This method reuses part of the hashing computation + // to more efficiently insert the key if it has not been added. For + // example, a mutation-handling version of the previous example: + // + // HS::AddPtr p = h.lookupForAdd(3); + // if (!p) { + // call_that_may_mutate_h(); + // if (!h.relookupOrAdd(p, 3, 3)) + // return false; + // } + // assert(*p == 3); + // + // Note that relookupOrAdd(p,l,t) performs Lookup using |l| and adds the + // entry |t|, where the caller ensures match(l,t). + typedef typename Impl::AddPtr AddPtr; + MOZ_ALWAYS_INLINE AddPtr lookupForAdd(const Lookup& l) const { + return impl.lookupForAdd(l); + } + + template + MOZ_MUST_USE bool add(AddPtr& p, U&& u) { + return impl.add(p, mozilla::Forward(u)); + } + + template + MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, U&& u) { + return impl.relookupOrAdd(p, l, mozilla::Forward(u)); + } + + // |all()| returns a Range containing |count()| elements: + // + // typedef HashSet HS; + // HS h; + // for (HS::Range r = h.all(); !r.empty(); r.popFront()) + // int i = r.front(); + // + // Also see the definition of Range in HashTable above. + typedef typename Impl::Range Range; + Range all() const { return impl.all(); } + + // Typedef for the enumeration class. An Enum may be used to examine and + // remove table entries: + // + // typedef HashSet HS; + // HS s; + // for (HS::Enum e(s); !e.empty(); e.popFront()) + // if (e.front() == 42) + // e.removeFront(); + // + // Table resize may occur in Enum's destructor. Also see the definition of + // Enum in HashTable above. + typedef typename Impl::Enum Enum; + + // Remove all entries. This does not shrink the table. For that consider + // using the finish() method. + void clear() { impl.clear(); } + + // Remove all entries. Unlike clear() this method tries to shrink the table. + // Unlike finish() it does not require the set to be initialized again. + void clearAndShrink() { impl.clearAndShrink(); } + + // Remove all the entries and release all internal buffers. The set must + // be initialized again before any use. + void finish() { impl.finish(); } + + // Does the table contain any entries? + bool empty() const { return impl.empty(); } + + // Number of live elements in the map. + uint32_t count() const { return impl.count(); } + + // Total number of allocation in the dynamic table. Note: resize will + // happen well before count() == capacity(). + size_t capacity() const { return impl.capacity(); } + + // Don't just call |impl.sizeOfExcludingThis()| because there's no + // guarantee that |impl| is the first field in HashSet. + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return impl.sizeOfExcludingThis(mallocSizeOf); + } + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); + } + + Generation generation() const { return impl.generation(); } + + /************************************************** Shorthand operations */ + + bool has(const Lookup& l) const { return impl.lookup(l).found(); } + + // Add |u| if it is not present already. Return false on oom. + template + MOZ_MUST_USE bool put(U&& u) { + AddPtr p = lookupForAdd(u); + return p ? true : add(p, mozilla::Forward(u)); + } + + // Like put, but assert that the given key is not already present. + template + MOZ_MUST_USE bool putNew(U&& u) { + return impl.putNew(u, mozilla::Forward(u)); + } + + template + MOZ_MUST_USE bool putNew(const Lookup& l, U&& u) { + return impl.putNew(l, mozilla::Forward(u)); + } + + // Only call this to populate an empty set after reserving space with init(). + template + void putNewInfallible(const Lookup& l, U&& u) { + impl.putNewInfallible(l, mozilla::Forward(u)); + } + + void remove(const Lookup& l) { + if (Ptr p = lookup(l)) remove(p); + } + + // Infallibly rekey one entry, if present. + // Requires template parameters T and HashPolicy::Lookup to be the same type. + void rekeyIfMoved(const Lookup& old_value, const T& new_value) { + if (old_value != new_value) rekeyAs(old_value, new_value, new_value); + } + + // Infallibly rekey one entry if present, and return whether that happened. + bool rekeyAs(const Lookup& old_lookup, const Lookup& new_lookup, + const T& new_value) { + if (Ptr p = lookup(old_lookup)) { + impl.rekeyAndMaybeRehash(p, new_lookup, new_value); + return true; + } + return false; + } + + // Infallibly replace the current key at |p| with an equivalent key. + // Specifically, both HashPolicy::hash and HashPolicy::match must return + // identical results for the new and old key when applied against all + // possible matching values. + void replaceKey(Ptr p, const T& new_value) { + MOZ_ASSERT(p.found()); + MOZ_ASSERT(*p != new_value); + MOZ_ASSERT(HashPolicy::hash(*p) == HashPolicy::hash(new_value)); + MOZ_ASSERT(HashPolicy::match(*p, new_value)); + const_cast(*p) = new_value; + } + + // HashSet is movable + HashSet(HashSet&& rhs) : impl(mozilla::Move(rhs.impl)) {} + void operator=(HashSet&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); + impl = mozilla::Move(rhs.impl); + } + + private: + // HashSet is not copyable or assignable + HashSet(const HashSet& hs) = delete; + HashSet& operator=(const HashSet& hs) = delete; - // Typedef for the enumeration class. An Enum may be used to examine and - // remove table entries: - // - // typedef HashSet HS; - // HS s; - // for (HS::Enum e(s); !e.empty(); e.popFront()) - // if (e.front() == 42) - // e.removeFront(); - // - // Table resize may occur in Enum's destructor. Also see the definition of - // Enum in HashTable above. - typedef typename Impl::Enum Enum; - - // Remove all entries. This does not shrink the table. For that consider - // using the finish() method. - void clear() { impl.clear(); } - - // Remove all the entries and release all internal buffers. The set must - // be initialized again before any use. - void finish() { impl.finish(); } - - // Does the table contain any entries? - bool empty() const { return impl.empty(); } - - // Number of live elements in the map. - uint32_t count() const { return impl.count(); } - - // Total number of allocation in the dynamic table. Note: resize will - // happen well before count() == capacity(). - size_t capacity() const { return impl.capacity(); } - - // Don't just call |impl.sizeOfExcludingThis()| because there's no - // guarantee that |impl| is the first field in HashSet. - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return impl.sizeOfExcludingThis(mallocSizeOf); - } - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return mallocSizeOf(this) + impl.sizeOfExcludingThis(mallocSizeOf); - } - - Generation generation() const { - return impl.generation(); - } - - /************************************************** Shorthand operations */ - - bool has(const Lookup& l) const { - return impl.lookup(l).found(); - } - - // Add |u| if it is not present already. Return false on oom. - template - MOZ_MUST_USE bool put(U&& u) { - AddPtr p = lookupForAdd(u); - return p ? true : add(p, mozilla::Forward(u)); - } - - // Like put, but assert that the given key is not already present. - template - MOZ_MUST_USE bool putNew(U&& u) { - return impl.putNew(u, mozilla::Forward(u)); - } - - template - MOZ_MUST_USE bool putNew(const Lookup& l, U&& u) { - return impl.putNew(l, mozilla::Forward(u)); - } - - // Only call this to populate an empty set after reserving space with init(). - template - void putNewInfallible(const Lookup& l, U&& u) { - impl.putNewInfallible(l, mozilla::Forward(u)); - } - - void remove(const Lookup& l) { - if (Ptr p = lookup(l)) - remove(p); - } - - // Infallibly rekey one entry, if present. - // Requires template parameters T and HashPolicy::Lookup to be the same type. - void rekeyIfMoved(const Lookup& old_value, const T& new_value) { - if (old_value != new_value) - rekeyAs(old_value, new_value, new_value); - } - - // Infallibly rekey one entry if present, and return whether that happened. - bool rekeyAs(const Lookup& old_lookup, const Lookup& new_lookup, const T& new_value) { - if (Ptr p = lookup(old_lookup)) { - impl.rekeyAndMaybeRehash(p, new_lookup, new_value); - return true; - } - return false; - } - - // Infallibly replace the current key at |p| with an equivalent key. - // Specifically, both HashPolicy::hash and HashPolicy::match must return - // identical results for the new and old key when applied against all - // possible matching values. - void replaceKey(Ptr p, const T& new_value) { - MOZ_ASSERT(p.found()); - MOZ_ASSERT(*p != new_value); - MOZ_ASSERT(HashPolicy::hash(*p) == HashPolicy::hash(new_value)); - MOZ_ASSERT(HashPolicy::match(*p, new_value)); - const_cast(*p) = new_value; - } - - // HashSet is movable - HashSet(HashSet&& rhs) : impl(mozilla::Move(rhs.impl)) {} - void operator=(HashSet&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - impl = mozilla::Move(rhs.impl); - } - - private: - // HashSet is not copyable or assignable - HashSet(const HashSet& hs) = delete; - HashSet& operator=(const HashSet& hs) = delete; - - friend class Impl::Enum; + friend class Impl::Enum; }; /*****************************************************************************/ @@ -568,31 +572,18 @@ // h.add(p, k); // } -// Pointer hashing policy that strips the lowest zeroBits when calculating the -// hash to improve key distribution. -template -struct PointerHasher -{ - typedef Key Lookup; - static HashNumber hash(const Lookup& l) { - size_t word = reinterpret_cast(l) >> zeroBits; - static_assert(sizeof(HashNumber) == 4, - "subsequent code assumes a four-byte hash"); -#if JS_BITS_PER_WORD == 32 - return HashNumber(word); -#else - static_assert(sizeof(word) == 8, - "unexpected word size, new hashing strategy required to " - "properly incorporate all bits"); - return HashNumber((word >> 32) ^ word); -#endif - } - static bool match(const Key& k, const Lookup& l) { - return k == l; - } - static void rekey(Key& k, const Key& newKey) { - k = newKey; - } +// Pointer hashing policy that uses HashGeneric() to create good hashes for +// pointers. Note that we don't shift out the lowest k bits to generate a +// good distribution for arena allocated pointers. +template +struct PointerHasher { + typedef Key Lookup; + static HashNumber hash(const Lookup& l) { + size_t word = reinterpret_cast(l); + return mozilla::HashGeneric(word); + } + static bool match(const Key& k, const Lookup& l) { return k == l; } + static void rekey(Key& k, const Key& newKey) { k = newKey; } }; // Default hash policy: just use the 'lookup' value. This of course only @@ -600,87 +591,78 @@ // the result of the 'hash' which means that it is 'ok' if the lookup value is // not well distributed over the HashNumber domain. template -struct DefaultHasher -{ - typedef Key Lookup; - static HashNumber hash(const Lookup& l) { - // Hash if can implicitly cast to hash number type. - return l; - } - static bool match(const Key& k, const Lookup& l) { - // Use builtin or overloaded operator==. - return k == l; - } - static void rekey(Key& k, const Key& newKey) { - k = newKey; - } +struct DefaultHasher { + typedef Key Lookup; + static HashNumber hash(const Lookup& l) { + // Hash if can implicitly cast to hash number type. + return l; + } + static bool match(const Key& k, const Lookup& l) { + // Use builtin or overloaded operator==. + return k == l; + } + static void rekey(Key& k, const Key& newKey) { k = newKey; } }; // Specialize hashing policy for pointer types. It assumes that the type is // at least word-aligned. For types with smaller size use PointerHasher. template -struct DefaultHasher : PointerHasher::value> -{}; +struct DefaultHasher : PointerHasher {}; // Specialize hashing policy for mozilla::UniquePtr to proxy the UniquePtr's // raw pointer to PointerHasher. template -struct DefaultHasher> -{ - using Lookup = mozilla::UniquePtr; - using PtrHasher = PointerHasher::value>; - - static HashNumber hash(const Lookup& l) { - return PtrHasher::hash(l.get()); - } - static bool match(const mozilla::UniquePtr& k, const Lookup& l) { - return PtrHasher::match(k.get(), l.get()); - } - static void rekey(mozilla::UniquePtr& k, mozilla::UniquePtr&& newKey) { - k = mozilla::Move(newKey); - } +struct DefaultHasher> { + using Lookup = mozilla::UniquePtr; + using PtrHasher = PointerHasher; + + static HashNumber hash(const Lookup& l) { return PtrHasher::hash(l.get()); } + static bool match(const mozilla::UniquePtr& k, const Lookup& l) { + return PtrHasher::match(k.get(), l.get()); + } + static void rekey(mozilla::UniquePtr& k, + mozilla::UniquePtr&& newKey) { + k = mozilla::Move(newKey); + } }; // For doubles, we can xor the two uint32s. template <> -struct DefaultHasher -{ - typedef double Lookup; - static HashNumber hash(double d) { - static_assert(sizeof(HashNumber) == 4, - "subsequent code assumes a four-byte hash"); - uint64_t u = mozilla::BitwiseCast(d); - return HashNumber(u ^ (u >> 32)); - } - static bool match(double lhs, double rhs) { - return mozilla::BitwiseCast(lhs) == mozilla::BitwiseCast(rhs); - } +struct DefaultHasher { + typedef double Lookup; + static HashNumber hash(double d) { + static_assert(sizeof(HashNumber) == 4, + "subsequent code assumes a four-byte hash"); + uint64_t u = mozilla::BitwiseCast(d); + return HashNumber(u ^ (u >> 32)); + } + static bool match(double lhs, double rhs) { + return mozilla::BitwiseCast(lhs) == + mozilla::BitwiseCast(rhs); + } }; template <> -struct DefaultHasher -{ - typedef float Lookup; - static HashNumber hash(float f) { - static_assert(sizeof(HashNumber) == 4, - "subsequent code assumes a four-byte hash"); - return HashNumber(mozilla::BitwiseCast(f)); - } - static bool match(float lhs, float rhs) { - return mozilla::BitwiseCast(lhs) == mozilla::BitwiseCast(rhs); - } +struct DefaultHasher { + typedef float Lookup; + static HashNumber hash(float f) { + static_assert(sizeof(HashNumber) == 4, + "subsequent code assumes a four-byte hash"); + return HashNumber(mozilla::BitwiseCast(f)); + } + static bool match(float lhs, float rhs) { + return mozilla::BitwiseCast(lhs) == + mozilla::BitwiseCast(rhs); + } }; // A hash policy that compares C strings. -struct CStringHasher -{ - typedef const char* Lookup; - static js::HashNumber hash(Lookup l) { - return mozilla::HashString(l); - } - static bool match(const char* key, Lookup lookup) { - return strcmp(key, lookup) == 0; - } +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. @@ -692,27 +674,32 @@ // 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; } +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)); +static bool HasHash(Lookup&& l) { + return FallibleHashMethods::hasHash( + mozilla::Forward(l)); } template -static bool -EnsureHash(Lookup&& l) { - return FallibleHashMethods::ensureHash(mozilla::Forward(l)); +static bool EnsureHash(Lookup&& l) { + return FallibleHashMethods::ensureHash( + mozilla::Forward(l)); } /*****************************************************************************/ @@ -723,58 +710,56 @@ // HashTable directly. template -class HashMapEntry -{ - Key key_; - Value value_; - - template friend class detail::HashTable; - template friend class detail::HashTableEntry; - template friend class HashMap; - - public: - template - HashMapEntry(KeyInput&& k, ValueInput&& v) +class HashMapEntry { + Key key_; + Value value_; + + template + friend class detail::HashTable; + template + friend class detail::HashTableEntry; + template + friend class HashMap; + + public: + template + HashMapEntry(KeyInput&& k, ValueInput&& v) : key_(mozilla::Forward(k)), - value_(mozilla::Forward(v)) - {} + value_(mozilla::Forward(v)) {} - HashMapEntry(HashMapEntry&& rhs) - : key_(mozilla::Move(rhs.key_)), - value_(mozilla::Move(rhs.value_)) - {} - - void operator=(HashMapEntry&& rhs) { - key_ = mozilla::Move(rhs.key_); - value_ = mozilla::Move(rhs.value_); - } - - typedef Key KeyType; - typedef Value ValueType; + HashMapEntry(HashMapEntry&& rhs) + : key_(mozilla::Move(rhs.key_)), value_(mozilla::Move(rhs.value_)) {} - const Key& key() const { return key_; } - Key& mutableKey() { return key_; } - const Value& value() const { return value_; } - Value& value() { return value_; } - - private: - HashMapEntry(const HashMapEntry&) = delete; - void operator=(const HashMapEntry&) = delete; + void operator=(HashMapEntry&& rhs) { + key_ = mozilla::Move(rhs.key_); + value_ = mozilla::Move(rhs.value_); + } + + typedef Key KeyType; + typedef Value ValueType; + + const Key& key() const { return key_; } + Key& mutableKey() { return key_; } + const Value& value() const { return value_; } + Value& value() { return value_; } + + private: + HashMapEntry(const HashMapEntry&) = delete; + void operator=(const HashMapEntry&) = delete; }; -} // namespace js +} // namespace js namespace mozilla { template -struct IsPod > : IsPod {}; +struct IsPod> : IsPod {}; template -struct IsPod > - : IntegralConstant::value && IsPod::value> -{}; +struct IsPod> + : IntegralConstant::value && IsPod::value> {}; -} // namespace mozilla +} // namespace mozilla namespace js { @@ -784,1097 +769,1054 @@ class HashTable; template -class HashTableEntry -{ - template friend class HashTable; - typedef typename mozilla::RemoveConst::Type NonConstT; - - HashNumber keyHash; - mozilla::AlignedStorage2 mem; - - static const HashNumber sFreeKey = 0; - static const HashNumber sRemovedKey = 1; - static const HashNumber sCollisionBit = 1; - - static bool isLiveHash(HashNumber hash) - { - return hash > sRemovedKey; - } - - HashTableEntry(const HashTableEntry&) = delete; - void operator=(const HashTableEntry&) = delete; - ~HashTableEntry() = delete; - - public: - // NB: HashTableEntry is treated as a POD: no constructor or destructor calls. - - void destroyIfLive() { - if (isLive()) - mem.addr()->~T(); - } - - void destroy() { - MOZ_ASSERT(isLive()); - mem.addr()->~T(); - } - - void swap(HashTableEntry* other) { - if (this == other) - return; - MOZ_ASSERT(isLive()); - if (other->isLive()) { - mozilla::Swap(*mem.addr(), *other->mem.addr()); - } else { - *other->mem.addr() = mozilla::Move(*mem.addr()); - destroy(); - } - mozilla::Swap(keyHash, other->keyHash); - } - - T& get() { MOZ_ASSERT(isLive()); return *mem.addr(); } - NonConstT& getMutable() { MOZ_ASSERT(isLive()); return *mem.addr(); } - - bool isFree() const { return keyHash == sFreeKey; } - void clearLive() { MOZ_ASSERT(isLive()); keyHash = sFreeKey; mem.addr()->~T(); } - void clear() { if (isLive()) mem.addr()->~T(); keyHash = sFreeKey; } - bool isRemoved() const { return keyHash == sRemovedKey; } - void removeLive() { MOZ_ASSERT(isLive()); keyHash = sRemovedKey; mem.addr()->~T(); } - bool isLive() const { return isLiveHash(keyHash); } - void setCollision() { MOZ_ASSERT(isLive()); keyHash |= sCollisionBit; } - void unsetCollision() { keyHash &= ~sCollisionBit; } - bool hasCollision() const { return keyHash & sCollisionBit; } - bool matchHash(HashNumber hn) { return (keyHash & ~sCollisionBit) == hn; } - HashNumber getKeyHash() const { return keyHash & ~sCollisionBit; } - - template - void setLive(HashNumber hn, Args&&... args) - { - MOZ_ASSERT(!isLive()); - keyHash = hn; - new(mem.addr()) T(mozilla::Forward(args)...); - MOZ_ASSERT(isLive()); - } +class HashTableEntry { + template + friend class HashTable; + typedef typename mozilla::RemoveConst::Type NonConstT; + + HashNumber keyHash; + mozilla::AlignedStorage2 mem; + + static const HashNumber sFreeKey = 0; + static const HashNumber sRemovedKey = 1; + static const HashNumber sCollisionBit = 1; + + static bool isLiveHash(HashNumber hash) { return hash > sRemovedKey; } + + HashTableEntry(const HashTableEntry&) = delete; + void operator=(const HashTableEntry&) = delete; + ~HashTableEntry() = delete; + + public: + // NB: HashTableEntry is treated as a POD: no constructor or destructor calls. + + void destroyIfLive() { + if (isLive()) mem.addr()->~T(); + } + + void destroy() { + MOZ_ASSERT(isLive()); + mem.addr()->~T(); + } + + void swap(HashTableEntry* other) { + if (this == other) return; + MOZ_ASSERT(isLive()); + if (other->isLive()) { + mozilla::Swap(*mem.addr(), *other->mem.addr()); + } else { + *other->mem.addr() = mozilla::Move(*mem.addr()); + destroy(); + } + mozilla::Swap(keyHash, other->keyHash); + } + + T& get() { + MOZ_ASSERT(isLive()); + return *mem.addr(); + } + NonConstT& getMutable() { + MOZ_ASSERT(isLive()); + return *mem.addr(); + } + + bool isFree() const { return keyHash == sFreeKey; } + void clearLive() { + MOZ_ASSERT(isLive()); + keyHash = sFreeKey; + mem.addr()->~T(); + } + void clear() { + if (isLive()) mem.addr()->~T(); + keyHash = sFreeKey; + } + bool isRemoved() const { return keyHash == sRemovedKey; } + void removeLive() { + MOZ_ASSERT(isLive()); + keyHash = sRemovedKey; + mem.addr()->~T(); + } + bool isLive() const { return isLiveHash(keyHash); } + void setCollision() { + MOZ_ASSERT(isLive()); + keyHash |= sCollisionBit; + } + void unsetCollision() { keyHash &= ~sCollisionBit; } + bool hasCollision() const { return keyHash & sCollisionBit; } + bool matchHash(HashNumber hn) { return (keyHash & ~sCollisionBit) == hn; } + HashNumber getKeyHash() const { return keyHash & ~sCollisionBit; } + + template + void setLive(HashNumber hn, Args&&... args) { + MOZ_ASSERT(!isLive()); + keyHash = hn; + new (mem.addr()) T(mozilla::Forward(args)...); + MOZ_ASSERT(isLive()); + } }; template -class HashTable : private AllocPolicy -{ - friend class mozilla::ReentrancyGuard; - - typedef typename mozilla::RemoveConst::Type NonConstT; - typedef typename HashPolicy::KeyType Key; - typedef typename HashPolicy::Lookup Lookup; - - public: - typedef HashTableEntry Entry; - - // A nullable pointer to a hash table element. A Ptr |p| can be tested - // either explicitly |if (p.found()) p->...| or using boolean conversion - // |if (p) p->...|. Ptr objects must not be used after any mutating hash - // table operations unless |generation()| is tested. - class Ptr - { - friend class HashTable; - - Entry* entry_; -#ifdef JS_DEBUG - const HashTable* table_; - Generation generation; -#endif - - protected: - Ptr(Entry& entry, const HashTable& tableArg) - : entry_(&entry) -#ifdef JS_DEBUG - , table_(&tableArg) - , generation(tableArg.generation()) -#endif - {} - - public: - Ptr() - : entry_(nullptr) -#ifdef JS_DEBUG - , table_(nullptr) - , generation(0) -#endif - {} - - bool isValid() const { - return !entry_; - } +class HashTable : private AllocPolicy { + friend class mozilla::ReentrancyGuard; - bool found() const { - if (isValid()) - return false; -#ifdef JS_DEBUG - MOZ_ASSERT(generation == table_->generation()); -#endif - return entry_->isLive(); - } + typedef typename mozilla::RemoveConst::Type NonConstT; + typedef typename HashPolicy::KeyType Key; + typedef typename HashPolicy::Lookup Lookup; - explicit operator bool() const { - return found(); - } - - bool operator==(const Ptr& rhs) const { - MOZ_ASSERT(found() && rhs.found()); - return entry_ == rhs.entry_; - } + public: + typedef HashTableEntry Entry; - bool operator!=(const Ptr& rhs) const { -#ifdef JS_DEBUG - MOZ_ASSERT(generation == table_->generation()); -#endif - return !(*this == rhs); - } + // A nullable pointer to a hash table element. A Ptr |p| can be tested + // either explicitly |if (p.found()) p->...| or using boolean conversion + // |if (p) p->...|. Ptr objects must not be used after any mutating hash + // table operations unless |generation()| is tested. + class Ptr { + friend class HashTable; - T& operator*() const { + Entry* entry_; #ifdef JS_DEBUG - MOZ_ASSERT(found()); - MOZ_ASSERT(generation == table_->generation()); + const HashTable* table_; + Generation generation; #endif - return entry_->get(); - } - T* operator->() const { + protected: + Ptr(Entry& entry, const HashTable& tableArg) + : entry_(&entry) #ifdef JS_DEBUG - MOZ_ASSERT(found()); - MOZ_ASSERT(generation == table_->generation()); + , + table_(&tableArg), + generation(tableArg.generation()) #endif - return &entry_->get(); - } - }; - - // A Ptr that can be used to add a key after a failed lookup. - class AddPtr : public Ptr { - friend class HashTable; - HashNumber keyHash; -#ifdef JS_DEBUG - uint64_t mutationCount; -#endif + } - AddPtr(Entry& entry, const HashTable& tableArg, HashNumber hn) - : Ptr(entry, tableArg) - , keyHash(hn) + public: + Ptr() + : entry_(nullptr) #ifdef JS_DEBUG - , mutationCount(tableArg.mutationCount) + , + table_(nullptr), + generation(0) #endif - {} - - public: - AddPtr() : keyHash(0) {} - }; - - // A collection of hash table entries. The collection is enumerated by - // calling |front()| followed by |popFront()| as long as |!empty()|. As - // with Ptr/AddPtr, Range objects must not be used after any mutating hash - // table operation unless the |generation()| is tested. - class Range { - protected: - friend class HashTable; + } - Range(const HashTable& tableArg, Entry* c, Entry* e) - : cur(c) - , end(e) -#ifdef JS_DEBUG - , table_(&tableArg) - , mutationCount(tableArg.mutationCount) - , generation(tableArg.generation()) - , validEntry(true) -#endif - { - while (cur < end && !cur->isLive()) - ++cur; - } + bool isValid() const { return !!entry_; } - Entry* cur; - Entry* end; + bool found() const { + if (!isValid()) return false; #ifdef JS_DEBUG - const HashTable* table_; - uint64_t mutationCount; - Generation generation; - bool validEntry; + MOZ_ASSERT(generation == table_->generation()); #endif + return entry_->isLive(); + } - public: - Range() - : cur(nullptr) - , end(nullptr) -#ifdef JS_DEBUG - , table_(nullptr) - , mutationCount(0) - , generation(0) - , validEntry(false) -#endif - {} + explicit operator bool() const { return found(); } - bool empty() const { -#ifdef JS_DEBUG - MOZ_ASSERT(generation == table_->generation()); - MOZ_ASSERT(mutationCount == table_->mutationCount); -#endif - return cur == end; - } + bool operator==(const Ptr& rhs) const { + MOZ_ASSERT(found() && rhs.found()); + return entry_ == rhs.entry_; + } - T& front() const { - MOZ_ASSERT(!empty()); + bool operator!=(const Ptr& rhs) const { #ifdef JS_DEBUG - MOZ_ASSERT(validEntry); - MOZ_ASSERT(generation == table_->generation()); - MOZ_ASSERT(mutationCount == table_->mutationCount); + MOZ_ASSERT(generation == table_->generation()); #endif - return cur->get(); - } + return !(*this == rhs); + } - void popFront() { - MOZ_ASSERT(!empty()); -#ifdef JS_DEBUG - MOZ_ASSERT(generation == table_->generation()); - MOZ_ASSERT(mutationCount == table_->mutationCount); -#endif - while (++cur < end && !cur->isLive()) - continue; + T& operator*() const { #ifdef JS_DEBUG - validEntry = true; + MOZ_ASSERT(found()); + MOZ_ASSERT(generation == table_->generation()); #endif - } - }; - - // A Range whose lifetime delimits a mutating enumeration of a hash table. - // Since rehashing when elements were removed during enumeration would be - // bad, it is postponed until the Enum is destructed. Since the Enum's - // destructor touches the hash table, the user must ensure that the hash - // table is still alive when the destructor runs. - class Enum : public Range - { - friend class HashTable; + return entry_->get(); + } - HashTable& table_; - bool rekeyed; - bool removed; - - /* Not copyable. */ - Enum(const Enum&) = delete; - void operator=(const Enum&) = delete; - - public: - template explicit - Enum(Map& map) : Range(map.all()), table_(map.impl), rekeyed(false), removed(false) {} - - // Removes the |front()| element from the table, leaving |front()| - // invalid until the next call to |popFront()|. For example: - // - // HashSet s; - // for (HashSet::Enum e(s); !e.empty(); e.popFront()) - // if (e.front() == 42) - // e.removeFront(); - void removeFront() { - table_.remove(*this->cur); - removed = true; + T* operator->() const { #ifdef JS_DEBUG - this->validEntry = false; - this->mutationCount = table_.mutationCount; + MOZ_ASSERT(found()); + MOZ_ASSERT(generation == table_->generation()); #endif - } + return &entry_->get(); + } + }; - NonConstT& mutableFront() { - MOZ_ASSERT(!this->empty()); + // A Ptr that can be used to add a key after a failed lookup. + class AddPtr : public Ptr { + friend class HashTable; + HashNumber keyHash; #ifdef JS_DEBUG - MOZ_ASSERT(this->validEntry); - MOZ_ASSERT(this->generation == this->Range::table_->generation()); - MOZ_ASSERT(this->mutationCount == this->Range::table_->mutationCount); + uint64_t mutationCount; #endif - return this->cur->getMutable(); - } - // Removes the |front()| element and re-inserts it into the table with - // a new key at the new Lookup position. |front()| is invalid after - // this operation until the next call to |popFront()|. - void rekeyFront(const Lookup& l, const Key& k) { - MOZ_ASSERT(&k != &HashPolicy::getKey(this->cur->get())); - Ptr p(*this->cur, table_); - table_.rekeyWithoutRehash(p, l, k); - rekeyed = true; + AddPtr(Entry& entry, const HashTable& tableArg, HashNumber hn) + : Ptr(entry, tableArg), + keyHash(hn) #ifdef JS_DEBUG - this->validEntry = false; - this->mutationCount = table_.mutationCount; -#endif - } - - void rekeyFront(const Key& k) { - rekeyFront(k, k); - } - - // Potentially rehashes the table. - ~Enum() { - if (rekeyed) { - table_.gen++; - table_.checkOverRemoved(); - } - - if (removed) - table_.compactIfUnderloaded(); - } - }; - - // HashTable is movable - HashTable(HashTable&& rhs) - : AllocPolicy(rhs) - { - mozilla::PodAssign(this, &rhs); - rhs.table = nullptr; - } - void operator=(HashTable&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); - if (table) - destroyTable(*this, table, capacity()); - mozilla::PodAssign(this, &rhs); - rhs.table = nullptr; - } - - private: - // HashTable is not copyable or assignable - HashTable(const HashTable&) = delete; - void operator=(const HashTable&) = delete; - - private: - static const size_t CAP_BITS = 30; - - public: - uint64_t gen:56; // entry storage generation number - uint64_t hashShift:8; // multiplicative hash shift - Entry* table; // entry storage - uint32_t entryCount; // number of entries in table - uint32_t removedCount; // removed entry sentinels in table - -#ifdef JS_DEBUG - uint64_t mutationCount; - mutable bool mEntered; - // Note that some updates to these stats are not thread-safe. See the - // comment on the three-argument overloading of HashTable::lookup(). - mutable struct Stats - { - uint32_t searches; // total number of table searches - uint32_t steps; // hash chain links traversed - uint32_t hits; // searches that found key - uint32_t misses; // searches that didn't find key - uint32_t addOverRemoved; // adds that recycled a removed entry - uint32_t removes; // calls to remove - uint32_t removeFrees; // calls to remove that freed the entry - uint32_t grows; // table expansions - uint32_t shrinks; // table contractions - uint32_t compresses; // table compressions - uint32_t rehashes; // tombstone decontaminations - } stats; -# define METER(x) x -#else -# define METER(x) + , + mutationCount(tableArg.mutationCount) #endif - - // The default initial capacity is 32 (enough to hold 16 elements), but it - // can be as low as 4. - static const unsigned sMinCapacityLog2 = 2; - static const unsigned sMinCapacity = 1 << sMinCapacityLog2; - static const unsigned sMaxInit = JS_BIT(CAP_BITS - 1); - static const unsigned sMaxCapacity = JS_BIT(CAP_BITS); - static const unsigned sHashBits = mozilla::tl::BitSize::value; - - // Hash-table alpha is conceptually a fraction, but to avoid floating-point - // math we implement it as a ratio of integers. - static const uint8_t sAlphaDenominator = 4; - static const uint8_t sMinAlphaNumerator = 1; // min alpha: 1/4 - static const uint8_t sMaxAlphaNumerator = 3; // max alpha: 3/4 - - static const HashNumber sFreeKey = Entry::sFreeKey; - static const HashNumber sRemovedKey = Entry::sRemovedKey; - static const HashNumber sCollisionBit = Entry::sCollisionBit; - - void setTableSizeLog2(unsigned sizeLog2) - { - hashShift = sHashBits - sizeLog2; - } - - static bool isLiveHash(HashNumber hash) - { - return Entry::isLiveHash(hash); - } - - static HashNumber prepareHash(const Lookup& l) { - HashNumber keyHash = ScrambleHashCode(HashPolicy::hash(l)); - - // Avoid reserved hash codes. - if (!isLiveHash(keyHash)) - keyHash -= (sRemovedKey + 1); - return keyHash & ~sCollisionBit; } - enum FailureBehavior { DontReportFailure = false, ReportFailure = true }; + public: + AddPtr() : keyHash(0) {} + }; - static Entry* createTable(AllocPolicy& alloc, uint32_t capacity, - FailureBehavior reportFailure = ReportFailure) - { - static_assert(sFreeKey == 0, - "newly-calloc'd tables have to be considered empty"); - if (reportFailure) - return alloc.template pod_calloc(capacity); - - return alloc.template maybe_pod_calloc(capacity); - } - - static Entry* maybeCreateTable(AllocPolicy& alloc, uint32_t capacity) - { - static_assert(sFreeKey == 0, - "newly-calloc'd tables have to be considered empty"); - return alloc.template maybe_pod_calloc(capacity); - } + // A collection of hash table entries. The collection is enumerated by + // calling |front()| followed by |popFront()| as long as |!empty()|. As + // with Ptr/AddPtr, Range objects must not be used after any mutating hash + // table operation unless the |generation()| is tested. + class Range { + protected: + friend class HashTable; - static void destroyTable(AllocPolicy& alloc, Entry* oldTable, uint32_t capacity) - { - Entry* end = oldTable + capacity; - for (Entry* e = oldTable; e < end; ++e) - e->destroyIfLive(); - alloc.free_(oldTable); - } - - public: - explicit HashTable(AllocPolicy ap) - : AllocPolicy(ap) - , gen(0) - , hashShift(sHashBits) - , table(nullptr) - , entryCount(0) - , removedCount(0) + Range(const HashTable& tableArg, Entry* c, Entry* e) + : cur(c), + end(e) #ifdef JS_DEBUG - , mutationCount(0) - , mEntered(false) + , + table_(&tableArg), + mutationCount(tableArg.mutationCount), + generation(tableArg.generation()), + validEntry(true) #endif - {} - - MOZ_MUST_USE bool init(uint32_t length) - { - MOZ_ASSERT(!initialized()); - - // Reject all lengths whose initial computed capacity would exceed - // sMaxCapacity. Round that maximum length down to the nearest power - // of two for speedier code. - if (MOZ_UNLIKELY(length > sMaxInit)) { - this->reportAllocOverflow(); - return false; - } - - static_assert((sMaxInit * sAlphaDenominator) / sAlphaDenominator == sMaxInit, - "multiplication in numerator below could overflow"); - static_assert(sMaxInit * sAlphaDenominator <= UINT32_MAX - sMaxAlphaNumerator, - "numerator calculation below could potentially overflow"); - - // Compute the smallest capacity allowing |length| elements to be - // inserted without rehashing: ceil(length / max-alpha). (Ceiling - // integral division: .) - uint32_t newCapacity = - (length * sAlphaDenominator + sMaxAlphaNumerator - 1) / sMaxAlphaNumerator; - if (newCapacity < sMinCapacity) - newCapacity = sMinCapacity; - - // FIXME: use JS_CEILING_LOG2 when PGO stops crashing (bug 543034). - uint32_t roundUp = sMinCapacity, roundUpLog2 = sMinCapacityLog2; - while (roundUp < newCapacity) { - roundUp <<= 1; - ++roundUpLog2; - } - - newCapacity = roundUp; - MOZ_ASSERT(newCapacity >= length); - MOZ_ASSERT(newCapacity <= sMaxCapacity); - - table = createTable(*this, newCapacity); - if (!table) - return false; - - setTableSizeLog2(roundUpLog2); - METER(memset(&stats, 0, sizeof(stats))); - return true; - } - - bool initialized() const - { - return !!table; - } - - ~HashTable() - { - if (table) - destroyTable(*this, table, capacity()); - } - - private: - HashNumber hash1(HashNumber hash0) const { - return hash0 >> hashShift; + while (cur < end && !cur->isLive()) ++cur; } - struct DoubleHash - { - HashNumber h2; - HashNumber sizeMask; - }; - - DoubleHash hash2(HashNumber curKeyHash) const - { - unsigned sizeLog2 = sHashBits - hashShift; - DoubleHash dh = { - ((curKeyHash << sizeLog2) >> hashShift) | 1, - (HashNumber(1) << sizeLog2) - 1 - }; - return dh; - } - - static HashNumber applyDoubleHash(HashNumber h1, const DoubleHash& dh) - { - return (h1 - dh.h2) & dh.sizeMask; - } - - bool overloaded() - { - static_assert(sMaxCapacity <= UINT32_MAX / sMaxAlphaNumerator, - "multiplication below could overflow"); - return entryCount + removedCount >= - capacity() * sMaxAlphaNumerator / sAlphaDenominator; - } - - // Would the table be underloaded if it had the given capacity and entryCount? - static bool wouldBeUnderloaded(uint32_t capacity, uint32_t entryCount) - { - static_assert(sMaxCapacity <= UINT32_MAX / sMinAlphaNumerator, - "multiplication below could overflow"); - return capacity > sMinCapacity && - entryCount <= capacity * sMinAlphaNumerator / sAlphaDenominator; - } - - bool underloaded() - { - return wouldBeUnderloaded(capacity(), entryCount); - } - - static bool match(Entry& e, const Lookup& l) - { - return HashPolicy::match(HashPolicy::getKey(e.get()), l); - } - - // Warning: in order for readonlyThreadsafeLookup() to be safe this - // function must not modify the table in any way when |collisionBit| is 0. - // (The use of the METER() macro to increment stats violates this - // restriction but we will live with that for now because it's enabled so - // rarely.) - Entry& lookup(const Lookup& l, HashNumber keyHash, unsigned collisionBit) const - { - MOZ_ASSERT(isLiveHash(keyHash)); - MOZ_ASSERT(!(keyHash & sCollisionBit)); - MOZ_ASSERT(collisionBit == 0 || collisionBit == sCollisionBit); - MOZ_ASSERT(table); - METER(stats.searches++); - - // Compute the primary hash address. - HashNumber h1 = hash1(keyHash); - Entry* entry = &table[h1]; - - // Miss: return space for a new entry. - if (entry->isFree()) { - METER(stats.misses++); - return *entry; - } - - // Hit: return entry. - if (entry->matchHash(keyHash) && match(*entry, l)) { - METER(stats.hits++); - return *entry; - } - - // Collision: double hash. - DoubleHash dh = hash2(keyHash); - - // Save the first removed entry pointer so we can recycle later. - Entry* firstRemoved = nullptr; - - while (true) { - if (MOZ_UNLIKELY(entry->isRemoved())) { - if (!firstRemoved) - firstRemoved = entry; - } else { - if (collisionBit == sCollisionBit) - entry->setCollision(); - } - - METER(stats.steps++); - h1 = applyDoubleHash(h1, dh); - - entry = &table[h1]; - if (entry->isFree()) { - METER(stats.misses++); - return firstRemoved ? *firstRemoved : *entry; - } - - if (entry->matchHash(keyHash) && match(*entry, l)) { - METER(stats.hits++); - return *entry; - } - } - } - - // This is a copy of lookup hardcoded to the assumptions: - // 1. the lookup is a lookupForAdd - // 2. the key, whose |keyHash| has been passed is not in the table, - // 3. no entries have been removed from the table. - // This specialized search avoids the need for recovering lookup values - // from entries, which allows more flexible Lookup/Key types. - Entry& findFreeEntry(HashNumber keyHash) - { - MOZ_ASSERT(!(keyHash & sCollisionBit)); - MOZ_ASSERT(table); - METER(stats.searches++); - - // We assume 'keyHash' has already been distributed. - - // Compute the primary hash address. - HashNumber h1 = hash1(keyHash); - Entry* entry = &table[h1]; - - // Miss: return space for a new entry. - if (!entry->isLive()) { - METER(stats.misses++); - return *entry; - } - - // Collision: double hash. - DoubleHash dh = hash2(keyHash); - - while (true) { - MOZ_ASSERT(!entry->isRemoved()); - entry->setCollision(); - - METER(stats.steps++); - h1 = applyDoubleHash(h1, dh); - - entry = &table[h1]; - if (!entry->isLive()) { - METER(stats.misses++); - return *entry; - } - } - } - - enum RebuildStatus { NotOverloaded, Rehashed, RehashFailed }; - - RebuildStatus changeTableSize(int deltaLog2, FailureBehavior reportFailure = ReportFailure) - { - // Look, but don't touch, until we succeed in getting new entry store. - Entry* oldTable = table; - uint32_t oldCap = capacity(); - uint32_t newLog2 = sHashBits - hashShift + deltaLog2; - uint32_t newCapacity = JS_BIT(newLog2); - if (MOZ_UNLIKELY(newCapacity > sMaxCapacity)) { - if (reportFailure) - this->reportAllocOverflow(); - return RehashFailed; - } - - Entry* newTable = createTable(*this, newCapacity, reportFailure); - if (!newTable) - return RehashFailed; - - // We can't fail from here on, so update table parameters. - setTableSizeLog2(newLog2); - removedCount = 0; - gen++; - table = newTable; - - // Copy only live entries, leaving removed ones behind. - Entry* end = oldTable + oldCap; - for (Entry* src = oldTable; src < end; ++src) { - if (src->isLive()) { - HashNumber hn = src->getKeyHash(); - findFreeEntry(hn).setLive( - hn, mozilla::Move(const_cast(src->get()))); - src->destroy(); - } - } - - // All entries have been destroyed, no need to destroyTable. - this->free_(oldTable); - return Rehashed; - } - - bool shouldCompressTable() - { - // Compress if a quarter or more of all entries are removed. - return removedCount >= (capacity() >> 2); - } - - RebuildStatus checkOverloaded(FailureBehavior reportFailure = ReportFailure) - { - if (!overloaded()) - return NotOverloaded; - - int deltaLog2; - if (shouldCompressTable()) { - METER(stats.compresses++); - deltaLog2 = 0; - } else { - METER(stats.grows++); - deltaLog2 = 1; - } - - return changeTableSize(deltaLog2, reportFailure); - } - - // Infallibly rehash the table if we are overloaded with removals. - void checkOverRemoved() - { - if (overloaded()) { - if (checkOverloaded(DontReportFailure) == RehashFailed) - rehashTableInPlace(); - } - } - - void remove(Entry& e) - { - MOZ_ASSERT(table); - METER(stats.removes++); - - if (e.hasCollision()) { - e.removeLive(); - removedCount++; - } else { - METER(stats.removeFrees++); - e.clearLive(); - } - entryCount--; + Entry* cur; + Entry* end; #ifdef JS_DEBUG - mutationCount++; + const HashTable* table_; + uint64_t mutationCount; + Generation generation; + bool validEntry; #endif - } - - void checkUnderloaded() - { - if (underloaded()) { - METER(stats.shrinks++); - (void) changeTableSize(-1, DontReportFailure); - } - } - - // Resize the table down to the largest capacity which doesn't underload the - // table. Since we call checkUnderloaded() on every remove, you only need - // to call this after a bulk removal of items done without calling remove(). - void compactIfUnderloaded() - { - int32_t resizeLog2 = 0; - uint32_t newCapacity = capacity(); - while (wouldBeUnderloaded(newCapacity, entryCount)) { - newCapacity = newCapacity >> 1; - resizeLog2--; - } - - if (resizeLog2 != 0) - (void) changeTableSize(resizeLog2, DontReportFailure); - } - // This is identical to changeTableSize(currentSize), but without requiring - // a second table. We do this by recycling the collision bits to tell us if - // the element is already inserted or still waiting to be inserted. Since - // already-inserted elements win any conflicts, we get the same table as we - // would have gotten through random insertion order. - void rehashTableInPlace() + public: + Range() + : cur(nullptr), + end(nullptr) +#ifdef JS_DEBUG + , + table_(nullptr), + mutationCount(0), + generation(0), + validEntry(false) +#endif { - METER(stats.rehashes++); - removedCount = 0; - for (size_t i = 0; i < capacity(); ++i) - table[i].unsetCollision(); - - for (size_t i = 0; i < capacity();) { - Entry* src = &table[i]; - - if (!src->isLive() || src->hasCollision()) { - ++i; - continue; - } - - HashNumber keyHash = src->getKeyHash(); - HashNumber h1 = hash1(keyHash); - DoubleHash dh = hash2(keyHash); - Entry* tgt = &table[h1]; - while (true) { - if (!tgt->hasCollision()) { - src->swap(tgt); - tgt->setCollision(); - break; - } - - h1 = applyDoubleHash(h1, dh); - tgt = &table[h1]; - } - } - - // TODO: this algorithm leaves collision bits on *all* elements, even if - // they are on no collision path. We have the option of setting the - // collision bits correctly on a subsequent pass or skipping the rehash - // unless we are totally filled with tombstones: benchmark to find out - // which approach is best. } - // Note: |l| may be a reference to a piece of |u|, so this function - // must take care not to use |l| after moving |u|. - // - // Prefer to use putNewInfallible; this function does not check - // invariants. - template - void putNewInfallibleInternal(const Lookup& l, Args&&... args) - { - MOZ_ASSERT(table); - - HashNumber keyHash = prepareHash(l); - Entry* entry = &findFreeEntry(keyHash); - MOZ_ASSERT(entry); - - if (entry->isRemoved()) { - METER(stats.addOverRemoved++); - removedCount--; - keyHash |= sCollisionBit; - } - - entry->setLive(keyHash, mozilla::Forward(args)...); - entryCount++; + bool empty() const { #ifdef JS_DEBUG - mutationCount++; + MOZ_ASSERT(generation == table_->generation()); + MOZ_ASSERT(mutationCount == table_->mutationCount); #endif + return cur == end; } - public: - void clear() - { - if (mozilla::IsPod::value) { - memset(table, 0, sizeof(*table) * capacity()); - } else { - uint32_t tableCapacity = capacity(); - Entry* end = table + tableCapacity; - for (Entry* e = table; e < end; ++e) - e->clear(); - } - removedCount = 0; - entryCount = 0; + T& front() const { + MOZ_ASSERT(!empty()); #ifdef JS_DEBUG - mutationCount++; + MOZ_ASSERT(validEntry); + MOZ_ASSERT(generation == table_->generation()); + MOZ_ASSERT(mutationCount == table_->mutationCount); #endif + return cur->get(); } - void finish() - { + void popFront() { + MOZ_ASSERT(!empty()); #ifdef JS_DEBUG - MOZ_ASSERT(!mEntered); + MOZ_ASSERT(generation == table_->generation()); + MOZ_ASSERT(mutationCount == table_->mutationCount); #endif - if (!table) - return; - - destroyTable(*this, table, capacity()); - table = nullptr; - gen++; - entryCount = 0; - removedCount = 0; + while (++cur < end && !cur->isLive()) continue; #ifdef JS_DEBUG - mutationCount++; + validEntry = true; #endif } + }; - Range all() const - { - MOZ_ASSERT(table); - return Range(*this, table, table + capacity()); - } - - bool empty() const - { - MOZ_ASSERT(table); - return !entryCount; - } - - uint32_t count() const - { - MOZ_ASSERT(table); - return entryCount; - } - - uint32_t capacity() const - { - MOZ_ASSERT(table); - return JS_BIT(sHashBits - hashShift); - } - - Generation generation() const - { - MOZ_ASSERT(table); - return Generation(gen); - } - - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const - { - return mallocSizeOf(table); - } + // A Range whose lifetime delimits a mutating enumeration of a hash table. + // Since rehashing when elements were removed during enumeration would be + // bad, it is postponed until the Enum is destructed. Since the Enum's + // destructor touches the hash table, the user must ensure that the hash + // table is still alive when the destructor runs. + class Enum : public Range { + friend class HashTable; - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const - { - return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf); - } + HashTable& table_; + bool rekeyed; + bool removed; - 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); - } + // Enum is movable but not copyable. + Enum(const Enum&) = delete; + void operator=(const Enum&) = delete; - Ptr readonlyThreadsafeLookup(const Lookup& l) const - { - if (!HasHash(l)) - return Ptr(); - HashNumber keyHash = prepareHash(l); - return Ptr(lookup(l, keyHash, 0), *this); - } + public: + template + explicit Enum(Map& map) + : Range(map.all()), table_(map.impl), rekeyed(false), removed(false) {} - 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); - return p; + MOZ_IMPLICIT Enum(Enum&& other) + : Range(other), + table_(other.table_), + rekeyed(other.rekeyed), + removed(other.removed) { + other.rekeyed = false; + other.removed = false; } - template - 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()) { - if (!this->checkSimulatedOOM()) - return false; - METER(stats.addOverRemoved++); - removedCount--; - p.keyHash |= sCollisionBit; - } else { - // Preserve the validity of |p.entry_|. - RebuildStatus status = checkOverloaded(); - if (status == RehashFailed) - return false; - if (status == NotOverloaded && !this->checkSimulatedOOM()) - return false; - if (status == Rehashed) - p.entry_ = &findFreeEntry(p.keyHash); - } - - p.entry_->setLive(p.keyHash, mozilla::Forward(args)...); - entryCount++; -#ifdef JS_DEBUG - mutationCount++; - p.generation = generation(); - p.mutationCount = mutationCount; + // Removes the |front()| element from the table, leaving |front()| + // invalid until the next call to |popFront()|. For example: + // + // HashSet s; + // for (HashSet::Enum e(s); !e.empty(); e.popFront()) + // if (e.front() == 42) + // e.removeFront(); + void removeFront() { + table_.remove(*this->cur); + removed = true; +#ifdef JS_DEBUG + this->validEntry = false; + this->mutationCount = table_.mutationCount; +#endif + } + + NonConstT& mutableFront() { + MOZ_ASSERT(!this->empty()); +#ifdef JS_DEBUG + MOZ_ASSERT(this->validEntry); + MOZ_ASSERT(this->generation == this->Range::table_->generation()); + MOZ_ASSERT(this->mutationCount == this->Range::table_->mutationCount); +#endif + return this->cur->getMutable(); + } + + // Removes the |front()| element and re-inserts it into the table with + // a new key at the new Lookup position. |front()| is invalid after + // this operation until the next call to |popFront()|. + void rekeyFront(const Lookup& l, const Key& k) { + MOZ_ASSERT(&k != &HashPolicy::getKey(this->cur->get())); + Ptr p(*this->cur, table_); + table_.rekeyWithoutRehash(p, l, k); + rekeyed = true; +#ifdef JS_DEBUG + this->validEntry = false; + this->mutationCount = table_.mutationCount; +#endif + } + + void rekeyFront(const Key& k) { rekeyFront(k, k); } + + // Potentially rehashes the table. + ~Enum() { + if (rekeyed) { + table_.gen++; + table_.checkOverRemoved(); + } + + if (removed) table_.compactIfUnderloaded(); + } + }; + + // HashTable is movable + HashTable(HashTable&& rhs) : AllocPolicy(rhs) { + mozilla::PodAssign(this, &rhs); + rhs.table = nullptr; + } + void operator=(HashTable&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited"); + if (table) destroyTable(*this, table, capacity()); + mozilla::PodAssign(this, &rhs); + rhs.table = nullptr; + } + + private: + // HashTable is not copyable or assignable + HashTable(const HashTable&) = delete; + void operator=(const HashTable&) = delete; + + private: + static const size_t CAP_BITS = 30; + + public: + uint64_t gen : 56; // entry storage generation number + uint64_t hashShift : 8; // multiplicative hash shift + Entry* table; // entry storage + uint32_t entryCount; // number of entries in table + uint32_t removedCount; // removed entry sentinels in table + +#ifdef JS_DEBUG + uint64_t mutationCount; + mutable bool mEntered; + // Note that some updates to these stats are not thread-safe. See the + // comment on the three-argument overloading of HashTable::lookup(). + mutable struct Stats { + uint32_t searches; // total number of table searches + uint32_t steps; // hash chain links traversed + uint32_t hits; // searches that found key + uint32_t misses; // searches that didn't find key + uint32_t addOverRemoved; // adds that recycled a removed entry + uint32_t removes; // calls to remove + uint32_t removeFrees; // calls to remove that freed the entry + uint32_t grows; // table expansions + uint32_t shrinks; // table contractions + uint32_t compresses; // table compressions + uint32_t rehashes; // tombstone decontaminations + } stats; +#define METER(x) x +#else +#define METER(x) #endif - return true; - } - // Note: |l| may be a reference to a piece of |u|, so this function - // must take care not to use |l| after moving |u|. - template - void putNewInfallible(const Lookup& l, Args&&... args) - { - MOZ_ASSERT(!lookup(l).found()); - mozilla::ReentrancyGuard g(*this); - putNewInfallibleInternal(l, mozilla::Forward(args)...); - } - - // Note: |l| may be alias arguments in |args|, so this function must take - // care not to use |l| after moving |args|. - template - MOZ_MUST_USE bool putNew(const Lookup& l, Args&&... args) - { - if (!this->checkSimulatedOOM()) - return false; - - if (!EnsureHash(l)) - return false; - - if (checkOverloaded() == RehashFailed) - return false; - - putNewInfallible(l, mozilla::Forward(args)...); - return true; - } - - // Note: |l| may be a reference to a piece of |u|, so this function - // must take care not to use |l| after moving |u|. - template - MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, Args&&... args) - { - // Check for error from ensureHash() here. - if (p.isValid()) - return false; - -#ifdef JS_DEBUG - p.generation = generation(); - p.mutationCount = mutationCount; -#endif - { - mozilla::ReentrancyGuard g(*this); - MOZ_ASSERT(prepareHash(l) == p.keyHash); // l has not been destroyed - p.entry_ = &lookup(l, p.keyHash, sCollisionBit); - } - return p.found() || add(p, mozilla::Forward(args)...); - } - - void remove(Ptr p) - { - MOZ_ASSERT(table); - mozilla::ReentrancyGuard g(*this); - MOZ_ASSERT(p.found()); - remove(*p.entry_); - checkUnderloaded(); - } - - void rekeyWithoutRehash(Ptr p, const Lookup& l, const Key& k) - { - MOZ_ASSERT(table); - mozilla::ReentrancyGuard g(*this); - MOZ_ASSERT(p.found()); - typename HashTableEntry::NonConstT t(mozilla::Move(*p)); - HashPolicy::setKey(t, const_cast(k)); - remove(*p.entry_); - putNewInfallibleInternal(l, mozilla::Move(t)); - } + // The default initial capacity is 32 (enough to hold 16 elements), but it + // can be as low as 4. + static const unsigned sMinCapacityLog2 = 2; + static const unsigned sMinCapacity = 1 << sMinCapacityLog2; + static const unsigned sMaxInit = JS_BIT(CAP_BITS - 1); + static const unsigned sMaxCapacity = JS_BIT(CAP_BITS); + static const unsigned sHashBits = mozilla::tl::BitSize::value; + + // Hash-table alpha is conceptually a fraction, but to avoid floating-point + // math we implement it as a ratio of integers. + static const uint8_t sAlphaDenominator = 4; + static const uint8_t sMinAlphaNumerator = 1; // min alpha: 1/4 + static const uint8_t sMaxAlphaNumerator = 3; // max alpha: 3/4 + + static const HashNumber sFreeKey = Entry::sFreeKey; + static const HashNumber sRemovedKey = Entry::sRemovedKey; + static const HashNumber sCollisionBit = Entry::sCollisionBit; + + void setTableSizeLog2(unsigned sizeLog2) { hashShift = sHashBits - sizeLog2; } + + static bool isLiveHash(HashNumber hash) { return Entry::isLiveHash(hash); } + + static HashNumber prepareHash(const Lookup& l) { + HashNumber keyHash = ScrambleHashCode(HashPolicy::hash(l)); + + // Avoid reserved hash codes. + if (!isLiveHash(keyHash)) keyHash -= (sRemovedKey + 1); + return keyHash & ~sCollisionBit; + } + + enum FailureBehavior { DontReportFailure = false, ReportFailure = true }; + + static Entry* createTable(AllocPolicy& alloc, uint32_t capacity, + FailureBehavior reportFailure = ReportFailure) { + static_assert(sFreeKey == 0, + "newly-calloc'd tables have to be considered empty"); + if (reportFailure) return alloc.template pod_calloc(capacity); + + return alloc.template maybe_pod_calloc(capacity); + } + + static Entry* maybeCreateTable(AllocPolicy& alloc, uint32_t capacity) { + static_assert(sFreeKey == 0, + "newly-calloc'd tables have to be considered empty"); + return alloc.template maybe_pod_calloc(capacity); + } + + static void destroyTable(AllocPolicy& alloc, Entry* oldTable, + uint32_t capacity) { + Entry* end = oldTable + capacity; + for (Entry* e = oldTable; e < end; ++e) e->destroyIfLive(); + alloc.free_(oldTable); + } + + public: + explicit HashTable(AllocPolicy ap) + : AllocPolicy(ap), + gen(0), + hashShift(sHashBits), + table(nullptr), + entryCount(0), + removedCount(0) +#ifdef JS_DEBUG + , + mutationCount(0), + mEntered(false) +#endif + { + } + + MOZ_MUST_USE bool init(uint32_t length) { + MOZ_ASSERT(!initialized()); + + // Reject all lengths whose initial computed capacity would exceed + // sMaxCapacity. Round that maximum length down to the nearest power + // of two for speedier code. + if (MOZ_UNLIKELY(length > sMaxInit)) { + this->reportAllocOverflow(); + return false; + } + + static_assert( + (sMaxInit * sAlphaDenominator) / sAlphaDenominator == sMaxInit, + "multiplication in numerator below could overflow"); + static_assert( + sMaxInit * sAlphaDenominator <= UINT32_MAX - sMaxAlphaNumerator, + "numerator calculation below could potentially overflow"); + + // Compute the smallest capacity allowing |length| elements to be + // inserted without rehashing: ceil(length / max-alpha). (Ceiling + // integral division: .) + uint32_t newCapacity = + (length * sAlphaDenominator + sMaxAlphaNumerator - 1) / + sMaxAlphaNumerator; + if (newCapacity < sMinCapacity) newCapacity = sMinCapacity; + + // FIXME: use JS_CEILING_LOG2 when PGO stops crashing (bug 543034). + uint32_t roundUp = sMinCapacity, roundUpLog2 = sMinCapacityLog2; + while (roundUp < newCapacity) { + roundUp <<= 1; + ++roundUpLog2; + } + + newCapacity = roundUp; + MOZ_ASSERT(newCapacity >= length); + MOZ_ASSERT(newCapacity <= sMaxCapacity); + + table = createTable(*this, newCapacity); + if (!table) return false; + + setTableSizeLog2(roundUpLog2); + METER(memset(&stats, 0, sizeof(stats))); + return true; + } + + bool initialized() const { return !!table; } + + ~HashTable() { + if (table) destroyTable(*this, table, capacity()); + } + + private: + HashNumber hash1(HashNumber hash0) const { return hash0 >> hashShift; } + + struct DoubleHash { + HashNumber h2; + HashNumber sizeMask; + }; + + DoubleHash hash2(HashNumber curKeyHash) const { + unsigned sizeLog2 = sHashBits - hashShift; + DoubleHash dh = {((curKeyHash << sizeLog2) >> hashShift) | 1, + (HashNumber(1) << sizeLog2) - 1}; + return dh; + } + + static HashNumber applyDoubleHash(HashNumber h1, const DoubleHash& dh) { + return (h1 - dh.h2) & dh.sizeMask; + } + + bool overloaded() { + static_assert(sMaxCapacity <= UINT32_MAX / sMaxAlphaNumerator, + "multiplication below could overflow"); + return entryCount + removedCount >= + capacity() * sMaxAlphaNumerator / sAlphaDenominator; + } + + // Would the table be underloaded if it had the given capacity and entryCount? + static bool wouldBeUnderloaded(uint32_t capacity, uint32_t entryCount) { + static_assert(sMaxCapacity <= UINT32_MAX / sMinAlphaNumerator, + "multiplication below could overflow"); + return capacity > sMinCapacity && + entryCount <= capacity * sMinAlphaNumerator / sAlphaDenominator; + } + + bool underloaded() { return wouldBeUnderloaded(capacity(), entryCount); } + + static MOZ_ALWAYS_INLINE bool match(Entry& e, const Lookup& l) { + return HashPolicy::match(HashPolicy::getKey(e.get()), l); + } + + // Warning: in order for readonlyThreadsafeLookup() to be safe this + // function must not modify the table in any way when |collisionBit| is 0. + // (The use of the METER() macro to increment stats violates this + // restriction but we will live with that for now because it's enabled so + // rarely.) + MOZ_ALWAYS_INLINE Entry& lookup(const Lookup& l, HashNumber keyHash, + unsigned collisionBit) const { + MOZ_ASSERT(isLiveHash(keyHash)); + MOZ_ASSERT(!(keyHash & sCollisionBit)); + MOZ_ASSERT(collisionBit == 0 || collisionBit == sCollisionBit); + MOZ_ASSERT(table); + METER(stats.searches++); + + // Compute the primary hash address. + HashNumber h1 = hash1(keyHash); + Entry* entry = &table[h1]; + + // Miss: return space for a new entry. + if (entry->isFree()) { + METER(stats.misses++); + return *entry; + } + + // Hit: return entry. + if (entry->matchHash(keyHash) && match(*entry, l)) { + METER(stats.hits++); + return *entry; + } + + // Collision: double hash. + DoubleHash dh = hash2(keyHash); + + // Save the first removed entry pointer so we can recycle later. + Entry* firstRemoved = nullptr; + + while (true) { + if (MOZ_UNLIKELY(entry->isRemoved())) { + if (!firstRemoved) firstRemoved = entry; + } else { + if (collisionBit == sCollisionBit) entry->setCollision(); + } + + METER(stats.steps++); + h1 = applyDoubleHash(h1, dh); + + entry = &table[h1]; + if (entry->isFree()) { + METER(stats.misses++); + return firstRemoved ? *firstRemoved : *entry; + } + + if (entry->matchHash(keyHash) && match(*entry, l)) { + METER(stats.hits++); + return *entry; + } + } + } + + // This is a copy of lookup hardcoded to the assumptions: + // 1. the lookup is a lookupForAdd + // 2. the key, whose |keyHash| has been passed is not in the table, + // 3. no entries have been removed from the table. + // This specialized search avoids the need for recovering lookup values + // from entries, which allows more flexible Lookup/Key types. + Entry& findFreeEntry(HashNumber keyHash) { + MOZ_ASSERT(!(keyHash & sCollisionBit)); + MOZ_ASSERT(table); + METER(stats.searches++); + + // We assume 'keyHash' has already been distributed. + + // Compute the primary hash address. + HashNumber h1 = hash1(keyHash); + Entry* entry = &table[h1]; + + // Miss: return space for a new entry. + if (!entry->isLive()) { + METER(stats.misses++); + return *entry; + } + + // Collision: double hash. + DoubleHash dh = hash2(keyHash); + + while (true) { + MOZ_ASSERT(!entry->isRemoved()); + entry->setCollision(); + + METER(stats.steps++); + h1 = applyDoubleHash(h1, dh); + + entry = &table[h1]; + if (!entry->isLive()) { + METER(stats.misses++); + return *entry; + } + } + } + + enum RebuildStatus { NotOverloaded, Rehashed, RehashFailed }; + + RebuildStatus changeTableSize(int deltaLog2, + FailureBehavior reportFailure = ReportFailure) { + // Look, but don't touch, until we succeed in getting new entry store. + Entry* oldTable = table; + uint32_t oldCap = capacity(); + uint32_t newLog2 = sHashBits - hashShift + deltaLog2; + uint32_t newCapacity = JS_BIT(newLog2); + if (MOZ_UNLIKELY(newCapacity > sMaxCapacity)) { + if (reportFailure) this->reportAllocOverflow(); + return RehashFailed; + } + + Entry* newTable = createTable(*this, newCapacity, reportFailure); + if (!newTable) return RehashFailed; + + // We can't fail from here on, so update table parameters. + setTableSizeLog2(newLog2); + removedCount = 0; + gen++; + table = newTable; + + // Copy only live entries, leaving removed ones behind. + Entry* end = oldTable + oldCap; + for (Entry* src = oldTable; src < end; ++src) { + if (src->isLive()) { + HashNumber hn = src->getKeyHash(); + findFreeEntry(hn).setLive( + hn, + mozilla::Move(const_cast(src->get()))); + src->destroy(); + } + } + + // All entries have been destroyed, no need to destroyTable. + this->free_(oldTable); + return Rehashed; + } + + bool shouldCompressTable() { + // Compress if a quarter or more of all entries are removed. + return removedCount >= (capacity() >> 2); + } + + RebuildStatus checkOverloaded(FailureBehavior reportFailure = ReportFailure) { + if (!overloaded()) return NotOverloaded; + + int deltaLog2; + if (shouldCompressTable()) { + METER(stats.compresses++); + deltaLog2 = 0; + } else { + METER(stats.grows++); + deltaLog2 = 1; + } + + return changeTableSize(deltaLog2, reportFailure); + } + + // Infallibly rehash the table if we are overloaded with removals. + void checkOverRemoved() { + if (overloaded()) { + if (checkOverloaded(DontReportFailure) == RehashFailed) + rehashTableInPlace(); + } + } + + void remove(Entry& e) { + MOZ_ASSERT(table); + METER(stats.removes++); + + if (e.hasCollision()) { + e.removeLive(); + removedCount++; + } else { + METER(stats.removeFrees++); + e.clearLive(); + } + entryCount--; +#ifdef JS_DEBUG + mutationCount++; +#endif + } + + void checkUnderloaded() { + if (underloaded()) { + METER(stats.shrinks++); + (void)changeTableSize(-1, DontReportFailure); + } + } + + // Resize the table down to the largest capacity which doesn't underload the + // table. Since we call checkUnderloaded() on every remove, you only need + // to call this after a bulk removal of items done without calling remove(). + void compactIfUnderloaded() { + int32_t resizeLog2 = 0; + uint32_t newCapacity = capacity(); + while (wouldBeUnderloaded(newCapacity, entryCount)) { + newCapacity = newCapacity >> 1; + resizeLog2--; + } + + if (resizeLog2 != 0) (void)changeTableSize(resizeLog2, DontReportFailure); + } + + // This is identical to changeTableSize(currentSize), but without requiring + // a second table. We do this by recycling the collision bits to tell us if + // the element is already inserted or still waiting to be inserted. Since + // already-inserted elements win any conflicts, we get the same table as we + // would have gotten through random insertion order. + void rehashTableInPlace() { + METER(stats.rehashes++); + removedCount = 0; + gen++; + for (size_t i = 0; i < capacity(); ++i) table[i].unsetCollision(); + + for (size_t i = 0; i < capacity();) { + Entry* src = &table[i]; + + if (!src->isLive() || src->hasCollision()) { + ++i; + continue; + } + + HashNumber keyHash = src->getKeyHash(); + HashNumber h1 = hash1(keyHash); + DoubleHash dh = hash2(keyHash); + Entry* tgt = &table[h1]; + while (true) { + if (!tgt->hasCollision()) { + src->swap(tgt); + tgt->setCollision(); + break; + } + + h1 = applyDoubleHash(h1, dh); + tgt = &table[h1]; + } + } + + // TODO: this algorithm leaves collision bits on *all* elements, even if + // they are on no collision path. We have the option of setting the + // collision bits correctly on a subsequent pass or skipping the rehash + // unless we are totally filled with tombstones: benchmark to find out + // which approach is best. + } + + // Note: |l| may be a reference to a piece of |u|, so this function + // must take care not to use |l| after moving |u|. + // + // Prefer to use putNewInfallible; this function does not check + // invariants. + template + void putNewInfallibleInternal(const Lookup& l, Args&&... args) { + MOZ_ASSERT(table); + + HashNumber keyHash = prepareHash(l); + Entry* entry = &findFreeEntry(keyHash); + MOZ_ASSERT(entry); + + if (entry->isRemoved()) { + METER(stats.addOverRemoved++); + removedCount--; + keyHash |= sCollisionBit; + } + + entry->setLive(keyHash, mozilla::Forward(args)...); + entryCount++; +#ifdef JS_DEBUG + mutationCount++; +#endif + } + + public: + void clear() { + if (mozilla::IsPod::value) { + memset(table, 0, sizeof(*table) * capacity()); + } else { + uint32_t tableCapacity = capacity(); + Entry* end = table + tableCapacity; + for (Entry* e = table; e < end; ++e) e->clear(); + } + removedCount = 0; + entryCount = 0; +#ifdef JS_DEBUG + mutationCount++; +#endif + } + + void clearAndShrink() { + clear(); + compactIfUnderloaded(); + } + + void finish() { +#ifdef JS_DEBUG + MOZ_ASSERT(!mEntered); +#endif + if (!table) return; + + destroyTable(*this, table, capacity()); + table = nullptr; + gen++; + entryCount = 0; + removedCount = 0; +#ifdef JS_DEBUG + mutationCount++; +#endif + } + + Range all() const { + MOZ_ASSERT(table); + return Range(*this, table, table + capacity()); + } + + bool empty() const { + MOZ_ASSERT(table); + return !entryCount; + } + + uint32_t count() const { + MOZ_ASSERT(table); + return entryCount; + } + + uint32_t capacity() const { + MOZ_ASSERT(table); + return JS_BIT(sHashBits - hashShift); + } + + Generation generation() const { + MOZ_ASSERT(table); + return Generation(gen); + } + + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return mallocSizeOf(table); + } + + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf); + } + + MOZ_ALWAYS_INLINE Ptr lookup(const Lookup& l) const { + mozilla::ReentrancyGuard g(*this); + if (!HasHash(l)) return Ptr(); + HashNumber keyHash = prepareHash(l); + return Ptr(lookup(l, keyHash, 0), *this); + } + + MOZ_ALWAYS_INLINE Ptr readonlyThreadsafeLookup(const Lookup& l) const { + if (!HasHash(l)) return Ptr(); + HashNumber keyHash = prepareHash(l); + return Ptr(lookup(l, keyHash, 0), *this); + } + + MOZ_ALWAYS_INLINE AddPtr lookupForAdd(const Lookup& l) const { + mozilla::ReentrancyGuard g(*this); + if (!EnsureHash(l)) return AddPtr(); + HashNumber keyHash = prepareHash(l); + // Calling constructor in return statement here avoid excess copying + // when build with Visual Studio 2015 and 2017, but it triggers a bug in + // gcc which is fixed in gcc-6. See bug 1385181. +#if MOZ_IS_GCC && __GNUC__ < 6 + AddPtr p(lookup(l, keyHash, sCollisionBit), *this, keyHash); + return p; +#else + return AddPtr(lookup(l, keyHash, sCollisionBit), *this, keyHash); +#endif + } - void rekeyAndMaybeRehash(Ptr p, const Lookup& l, const Key& k) - { - rekeyWithoutRehash(p, l, k); - checkOverRemoved(); - } + template + MOZ_MUST_USE bool add(AddPtr& p, Args&&... args) { + mozilla::ReentrancyGuard g(*this); + MOZ_ASSERT(table); + MOZ_ASSERT_IF(p.isValid(), p.table_ == this); + MOZ_ASSERT(!p.found()); + MOZ_ASSERT(!(p.keyHash & sCollisionBit)); + + // Check for error from ensureHash() here. + if (!p.isValid()) return false; + + MOZ_ASSERT(p.generation == generation()); +#ifdef JS_DEBUG + MOZ_ASSERT(p.mutationCount == mutationCount); +#endif + + // Changing an entry from removed to live does not affect whether we + // are overloaded and can be handled separately. + if (p.entry_->isRemoved()) { + if (!this->checkSimulatedOOM()) return false; + METER(stats.addOverRemoved++); + removedCount--; + p.keyHash |= sCollisionBit; + } else { + // Preserve the validity of |p.entry_|. + RebuildStatus status = checkOverloaded(); + if (status == RehashFailed) return false; + if (status == NotOverloaded && !this->checkSimulatedOOM()) return false; + if (status == Rehashed) p.entry_ = &findFreeEntry(p.keyHash); + } + + p.entry_->setLive(p.keyHash, mozilla::Forward(args)...); + entryCount++; +#ifdef JS_DEBUG + mutationCount++; + p.generation = generation(); + p.mutationCount = mutationCount; +#endif + return true; + } + + // Note: |l| may be a reference to a piece of |u|, so this function + // must take care not to use |l| after moving |u|. + template + void putNewInfallible(const Lookup& l, Args&&... args) { + MOZ_ASSERT(!lookup(l).found()); + mozilla::ReentrancyGuard g(*this); + putNewInfallibleInternal(l, mozilla::Forward(args)...); + } + + // Note: |l| may be alias arguments in |args|, so this function must take + // care not to use |l| after moving |args|. + template + MOZ_MUST_USE bool putNew(const Lookup& l, Args&&... args) { + if (!this->checkSimulatedOOM()) return false; + + if (!EnsureHash(l)) return false; + + if (checkOverloaded() == RehashFailed) return false; + + putNewInfallible(l, mozilla::Forward(args)...); + return true; + } + + // Note: |l| may be a reference to a piece of |u|, so this function + // must take care not to use |l| after moving |u|. + template + MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, Args&&... args) { + // Check for error from ensureHash() here. + if (!p.isValid()) return false; + +#ifdef JS_DEBUG + p.generation = generation(); + p.mutationCount = mutationCount; +#endif + { + mozilla::ReentrancyGuard g(*this); + MOZ_ASSERT(prepareHash(l) == p.keyHash); // l has not been destroyed + p.entry_ = &lookup(l, p.keyHash, sCollisionBit); + } + return p.found() || add(p, mozilla::Forward(args)...); + } + + void remove(Ptr p) { + MOZ_ASSERT(table); + mozilla::ReentrancyGuard g(*this); + MOZ_ASSERT(p.found()); + MOZ_ASSERT(p.generation == generation()); + remove(*p.entry_); + checkUnderloaded(); + } + + void rekeyWithoutRehash(Ptr p, const Lookup& l, const Key& k) { + MOZ_ASSERT(table); + mozilla::ReentrancyGuard g(*this); + MOZ_ASSERT(p.found()); + MOZ_ASSERT(p.generation == generation()); + typename HashTableEntry::NonConstT t(mozilla::Move(*p)); + HashPolicy::setKey(t, const_cast(k)); + remove(*p.entry_); + putNewInfallibleInternal(l, mozilla::Move(t)); + } + + void rekeyAndMaybeRehash(Ptr p, const Lookup& l, const Key& k) { + rekeyWithoutRehash(p, l, k); + checkOverRemoved(); + } #undef METER }; -} // namespace detail -} // namespace js +} // namespace detail +} // namespace js -#endif /* js_HashTable_h */ +#endif /* js_HashTable_h */ 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,13 +17,18 @@ /* These values are private to the JS engine. */ namespace js { -JS_FRIEND_API(bool) -CurrentThreadCanAccessZone(JS::Zone* zone); +JS_FRIEND_API bool CurrentThreadCanAccessZone(JS::Zone* zone); namespace gc { struct Cell; +/* + * The low bit is set so this should never equal a normal pointer, and the high + * bit is set so this should never equal the upper 32 bits of a 64-bit pointer. + */ +const uint32_t Relocated = uintptr_t(0xbad0bad1); + const size_t ArenaShift = 12; const size_t ArenaSize = size_t(1) << ArenaShift; const size_t ArenaMask = ArenaSize - 1; @@ -36,9 +41,19 @@ const size_t ChunkSize = size_t(1) << ChunkShift; const size_t ChunkMask = ChunkSize - 1; -const size_t CellShift = 3; -const size_t CellSize = size_t(1) << CellShift; -const size_t CellMask = CellSize - 1; +const size_t CellAlignShift = 3; +const size_t CellAlignBytes = size_t(1) << CellAlignShift; +const size_t CellAlignMask = CellAlignBytes - 1; + +const size_t CellBytesPerMarkBit = CellAlignBytes; + +/* + * We sometimes use an index to refer to a cell in an arena. The index for a + * cell is found by dividing by the cell alignment so not all indicies refer to + * valid cells. + */ +const size_t ArenaCellIndexBytes = CellAlignBytes; +const size_t MaxArenaCellIndex = ArenaSize / CellAlignBytes; /* These are magic constants derived from actual offsets in gc/Heap.h. */ #ifdef JS_GC_SMALL_CHUNK_SIZE @@ -51,36 +66,40 @@ 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 ChunkStoreBufferOffset = + ChunkSize - ChunkTrailerSize + sizeof(uint64_t); const size_t ArenaZoneOffset = sizeof(size_t); -const size_t ArenaHeaderSize = sizeof(size_t) + 2 * sizeof(uintptr_t) + - sizeof(size_t) + sizeof(uintptr_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 - * depends on the size of the GCThing. Objects marked gray are eligible for - * cycle collection. + * Live objects are marked black or gray. Everything reachable from a JS root is + * marked black. Objects marked gray are eligible for cycle collection. + * + * BlackBit: GrayOrBlackBit: Color: + * 0 0 white + * 0 1 gray + * 1 0 black + * 1 1 black */ -static const uint32_t BLACK = 0; -static const uint32_t GRAY = 1; +enum class ColorBit : uint32_t { BlackBit = 0, GrayOrBlackBit = 1 }; /* * The "location" field in the Chunk trailer is a enum indicating various roles * of the chunk. */ -enum class ChunkLocation : uint32_t -{ - Invalid = 0, - Nursery = 1, - TenuredHeap = 2 +enum class ChunkLocation : uint32_t { + Invalid = 0, + Nursery = 1, + TenuredHeap = 2 }; #ifdef JS_DEBUG /* When downcasting, ensure we are actually the right type. */ -extern JS_FRIEND_API(void) -AssertGCThingHasType(js::gc::Cell* cell, JS::TraceKind kind); +extern JS_FRIEND_API void AssertGCThingHasType(js::gc::Cell* cell, + JS::TraceKind kind); #else -inline void -AssertGCThingHasType(js::gc::Cell* cell, JS::TraceKind kind) {} +inline void AssertGCThingHasType(js::gc::Cell* cell, JS::TraceKind kind) {} #endif MOZ_ALWAYS_INLINE bool IsInsideNursery(const js::gc::Cell* cell); @@ -89,62 +108,79 @@ } /* namespace js */ namespace JS { -struct Zone; -/* Default size for the generational nursery in bytes. */ +/* + * This list enumerates the different types of conceptual stacks we have in + * SpiderMonkey. In reality, they all share the C stack, but we allow different + * stack limits depending on the type of code running. + */ +enum StackKind { + StackForSystemCode, // C++, such as the GC, running on behalf of the VM. + StackForTrustedScript, // Script running with trusted principals. + StackForUntrustedScript, // Script running with untrusted principals. + StackKindCount +}; + +/* + * Default size for the generational nursery in bytes. + * This is the initial nursery size, when running in the browser this is + * updated by JS_SetGCParameter(). + */ const uint32_t DefaultNurseryBytes = 16 * js::gc::ChunkSize; -/* Default maximum heap size in bytes to pass to JS_NewRuntime(). */ +/* Default maximum heap size in bytes to pass to JS_NewContext(). */ const uint32_t DefaultHeapMaxBytes = 32 * 1024 * 1024; namespace shadow { -struct Zone -{ - protected: - JSRuntime* const runtime_; - 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; +struct Zone { + enum GCState : uint8_t { NoGC, Mark, MarkGray, Sweep, Finished, Compact }; - bool needsIncrementalBarrier_; + protected: + JSRuntime* const runtime_; + JSTracer* const barrierTracer_; // A pointer to the JSRuntime's |gcMarker|. + uint32_t needsIncrementalBarrier_; + GCState gcState_; - Zone(JSRuntime* runtime, JSTracer* barrierTracerArg) + Zone(JSRuntime* runtime, JSTracer* barrierTracerArg) : runtime_(runtime), barrierTracer_(barrierTracerArg), - needsIncrementalBarrier_(false) - { - for (auto& stackRootPtr : stackRoots_) - stackRootPtr = nullptr; - } - - bool needsIncrementalBarrier() const { - return needsIncrementalBarrier_; - } - - JSTracer* barrierTracer() { - MOZ_ASSERT(needsIncrementalBarrier_); - MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); - return barrierTracer_; - } - - JSRuntime* runtimeFromMainThread() const { - MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); - return runtime_; - } - - // Note: Unrestricted access to the zone's runtime from an arbitrary - // thread can easily lead to races. Use this method very carefully. - JSRuntime* runtimeFromAnyThread() const { - return runtime_; - } - - static MOZ_ALWAYS_INLINE JS::shadow::Zone* asShadowZone(JS::Zone* zone) { - return reinterpret_cast(zone); - } + needsIncrementalBarrier_(0), + gcState_(NoGC) {} + + public: + bool needsIncrementalBarrier() const { return needsIncrementalBarrier_; } + + JSTracer* barrierTracer() { + MOZ_ASSERT(needsIncrementalBarrier_); + MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); + return barrierTracer_; + } + + JSRuntime* runtimeFromActiveCooperatingThread() const { + MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); + return runtime_; + } + + // Note: Unrestricted access to the zone's runtime from an arbitrary + // thread can easily lead to races. Use this method very carefully. + JSRuntime* runtimeFromAnyThread() const { return runtime_; } + + GCState gcState() const { return gcState_; } + bool wasGCStarted() const { return gcState_ != NoGC; } + bool isGCMarkingBlack() const { return gcState_ == Mark; } + bool isGCMarkingGray() const { return gcState_ == MarkGray; } + bool isGCSweeping() const { return gcState_ == Sweep; } + bool isGCFinished() const { return gcState_ == Finished; } + bool isGCCompacting() const { return gcState_ == Compact; } + bool isGCMarking() const { return gcState_ == Mark || gcState_ == MarkGray; } + bool isGCSweepingOrCompacting() const { + return gcState_ == Sweep || gcState_ == Compact; + } + + static MOZ_ALWAYS_INLINE JS::shadow::Zone* asShadowZone(JS::Zone* zone) { + return reinterpret_cast(zone); + } }; } /* namespace shadow */ @@ -156,114 +192,121 @@ * is for use when that is not possible because a single pointer must point * to several kinds of GC thing. */ -class JS_FRIEND_API(GCCellPtr) -{ - public: - // Construction from a void* and trace kind. - GCCellPtr(void* gcthing, JS::TraceKind traceKind) : ptr(checkedCast(gcthing, traceKind)) {} - - // Automatically construct a null GCCellPtr from nullptr. - MOZ_IMPLICIT GCCellPtr(decltype(nullptr)) : ptr(checkedCast(nullptr, JS::TraceKind::Null)) {} - - // Construction from an explicit type. - template - explicit GCCellPtr(T* p) : ptr(checkedCast(p, JS::MapTypeToTraceKind::kind)) { } - explicit GCCellPtr(JSFunction* p) : ptr(checkedCast(p, JS::TraceKind::Object)) { } - explicit GCCellPtr(JSFlatString* str) : ptr(checkedCast(str, JS::TraceKind::String)) { } - explicit GCCellPtr(const Value& v); - - JS::TraceKind kind() const { - JS::TraceKind traceKind = JS::TraceKind(ptr & OutOfLineTraceKindMask); - if (uintptr_t(traceKind) != OutOfLineTraceKindMask) - return traceKind; - return outOfLineKind(); - } - - // Allow GCCellPtr to be used in a boolean context. - explicit operator bool() const { - MOZ_ASSERT(bool(asCell()) == (kind() != JS::TraceKind::Null)); - return asCell(); - } - - // Simplify checks to the kind. - template - bool is() const { return kind() == JS::MapTypeToTraceKind::kind; } - - // Conversions to more specific types must match the kind. Access to - // further refined types is not allowed directly from a GCCellPtr. - template - T& as() const { - MOZ_ASSERT(kind() == JS::MapTypeToTraceKind::kind); - // We can't use static_cast here, because the fact that JSObject - // inherits from js::gc::Cell is not part of the public API. - return *reinterpret_cast(asCell()); - } - - // Return a pointer to the cell this |GCCellPtr| refers to, or |nullptr|. - // (It would be more symmetrical with |to| for this to return a |Cell&|, but - // the result can be |nullptr|, and null references are undefined behavior.) - js::gc::Cell* asCell() const { - return reinterpret_cast(ptr & ~OutOfLineTraceKindMask); - } - - // The CC's trace logger needs an identity that is XPIDL serializable. - uint64_t unsafeAsInteger() const { - return static_cast(unsafeAsUIntPtr()); - } - // Inline mark bitmap access requires direct pointer arithmetic. - uintptr_t unsafeAsUIntPtr() const { - MOZ_ASSERT(asCell()); - MOZ_ASSERT(!js::gc::IsInsideNursery(asCell())); - return reinterpret_cast(asCell()); - } - - bool mayBeOwnedByOtherRuntime() const; - - private: - static uintptr_t checkedCast(void* p, JS::TraceKind traceKind) { - js::gc::Cell* cell = static_cast(p); - MOZ_ASSERT((uintptr_t(p) & OutOfLineTraceKindMask) == 0); - AssertGCThingHasType(cell, traceKind); - // Note: the OutOfLineTraceKindMask bits are set on all out-of-line kinds - // so that we can mask instead of branching. - MOZ_ASSERT_IF(uintptr_t(traceKind) >= OutOfLineTraceKindMask, - (uintptr_t(traceKind) & OutOfLineTraceKindMask) == OutOfLineTraceKindMask); - return uintptr_t(p) | (uintptr_t(traceKind) & OutOfLineTraceKindMask); - } +class JS_FRIEND_API GCCellPtr { + public: + // Construction from a void* and trace kind. + GCCellPtr(void* gcthing, JS::TraceKind traceKind) + : ptr(checkedCast(gcthing, traceKind)) {} + + // Automatically construct a null GCCellPtr from nullptr. + MOZ_IMPLICIT GCCellPtr(decltype(nullptr)) + : ptr(checkedCast(nullptr, JS::TraceKind::Null)) {} + + // Construction from an explicit type. + template + explicit GCCellPtr(T* p) + : ptr(checkedCast(p, JS::MapTypeToTraceKind::kind)) {} + explicit GCCellPtr(JSFunction* p) + : ptr(checkedCast(p, JS::TraceKind::Object)) {} + explicit GCCellPtr(JSFlatString* str) + : ptr(checkedCast(str, JS::TraceKind::String)) {} + explicit GCCellPtr(const Value& v); + + JS::TraceKind kind() const { + JS::TraceKind traceKind = JS::TraceKind(ptr & OutOfLineTraceKindMask); + if (uintptr_t(traceKind) != OutOfLineTraceKindMask) return traceKind; + return outOfLineKind(); + } + + // Allow GCCellPtr to be used in a boolean context. + explicit operator bool() const { + MOZ_ASSERT(bool(asCell()) == (kind() != JS::TraceKind::Null)); + return asCell(); + } + + // Simplify checks to the kind. + template + bool is() const { + return kind() == JS::MapTypeToTraceKind::kind; + } + + // Conversions to more specific types must match the kind. Access to + // further refined types is not allowed directly from a GCCellPtr. + template + T& as() const { + MOZ_ASSERT(kind() == JS::MapTypeToTraceKind::kind); + // We can't use static_cast here, because the fact that JSObject + // inherits from js::gc::Cell is not part of the public API. + return *reinterpret_cast(asCell()); + } + + // Return a pointer to the cell this |GCCellPtr| refers to, or |nullptr|. + // (It would be more symmetrical with |to| for this to return a |Cell&|, but + // the result can be |nullptr|, and null references are undefined behavior.) + js::gc::Cell* asCell() const { + return reinterpret_cast(ptr & ~OutOfLineTraceKindMask); + } + + // The CC's trace logger needs an identity that is XPIDL serializable. + uint64_t unsafeAsInteger() const { + return static_cast(unsafeAsUIntPtr()); + } + // Inline mark bitmap access requires direct pointer arithmetic. + uintptr_t unsafeAsUIntPtr() const { + MOZ_ASSERT(asCell()); + MOZ_ASSERT(!js::gc::IsInsideNursery(asCell())); + return reinterpret_cast(asCell()); + } + + MOZ_ALWAYS_INLINE bool mayBeOwnedByOtherRuntime() const { + if (is() || is()) + return mayBeOwnedByOtherRuntimeSlow(); + return false; + } + + private: + static uintptr_t checkedCast(void* p, JS::TraceKind traceKind) { + js::gc::Cell* cell = static_cast(p); + MOZ_ASSERT((uintptr_t(p) & OutOfLineTraceKindMask) == 0); + AssertGCThingHasType(cell, traceKind); + // Note: the OutOfLineTraceKindMask bits are set on all out-of-line kinds + // so that we can mask instead of branching. + MOZ_ASSERT_IF(uintptr_t(traceKind) >= OutOfLineTraceKindMask, + (uintptr_t(traceKind) & OutOfLineTraceKindMask) == + OutOfLineTraceKindMask); + return uintptr_t(p) | (uintptr_t(traceKind) & OutOfLineTraceKindMask); + } - JS::TraceKind outOfLineKind() const; + bool mayBeOwnedByOtherRuntimeSlow() const; - uintptr_t ptr; + JS::TraceKind outOfLineKind() const; + + uintptr_t ptr; }; -inline bool -operator==(const GCCellPtr& ptr1, const GCCellPtr& ptr2) -{ - return ptr1.asCell() == ptr2.asCell(); +inline bool operator==(const GCCellPtr& ptr1, const GCCellPtr& ptr2) { + return ptr1.asCell() == ptr2.asCell(); } -inline bool -operator!=(const GCCellPtr& ptr1, const GCCellPtr& ptr2) -{ - return !(ptr1 == ptr2); +inline bool operator!=(const GCCellPtr& ptr1, const GCCellPtr& ptr2) { + return !(ptr1 == ptr2); } // Unwraps the given GCCellPtr and calls the given functor with a template // argument of the actual type of the pointer. template -auto -DispatchTyped(F f, GCCellPtr thing, Args&&... args) - -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) -{ - switch (thing.kind()) { +auto DispatchTyped(F f, GCCellPtr thing, Args&&... args) + -> decltype(f(static_cast(nullptr), + mozilla::Forward(args)...)) { + switch (thing.kind()) { #define JS_EXPAND_DEF(name, type, _) \ - case JS::TraceKind::name: \ - return f(&thing.as(), mozilla::Forward(args)...); - JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); + case JS::TraceKind::name: \ + return f(&thing.as(), mozilla::Forward(args)...); + JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); #undef JS_EXPAND_DEF - default: - MOZ_CRASH("Invalid trace kind in DispatchTyped for GCCellPtr."); - } + default: + MOZ_CRASH("Invalid trace kind in DispatchTyped for GCCellPtr."); + } } } /* namespace JS */ @@ -272,73 +315,104 @@ namespace gc { namespace detail { -static MOZ_ALWAYS_INLINE uintptr_t* -GetGCThingMarkBitmap(const uintptr_t addr) -{ - MOZ_ASSERT(addr); - const uintptr_t bmap_addr = (addr & ~ChunkMask) | ChunkMarkBitmapOffset; - return reinterpret_cast(bmap_addr); -} - -static MOZ_ALWAYS_INLINE void -GetGCThingMarkWordAndMask(const uintptr_t addr, uint32_t color, - uintptr_t** wordp, uintptr_t* maskp) -{ - MOZ_ASSERT(addr); - const size_t bit = (addr & js::gc::ChunkMask) / js::gc::CellSize + color; - MOZ_ASSERT(bit < js::gc::ChunkMarkBitmapBits); - uintptr_t* bitmap = GetGCThingMarkBitmap(addr); - const uintptr_t nbits = sizeof(*bitmap) * CHAR_BIT; - *maskp = uintptr_t(1) << (bit % nbits); - *wordp = &bitmap[bit / nbits]; -} - -static MOZ_ALWAYS_INLINE JS::Zone* -GetGCThingZone(const uintptr_t addr) -{ - MOZ_ASSERT(addr); - const uintptr_t zone_addr = (addr & ~ArenaMask) | ArenaZoneOffset; - return *reinterpret_cast(zone_addr); - +static MOZ_ALWAYS_INLINE uintptr_t* GetGCThingMarkBitmap(const uintptr_t addr) { + // Note: the JIT pre-barrier trampolines inline this code. Update that + // code too when making changes here! + MOZ_ASSERT(addr); + const uintptr_t bmap_addr = (addr & ~ChunkMask) | ChunkMarkBitmapOffset; + return reinterpret_cast(bmap_addr); +} + +static MOZ_ALWAYS_INLINE void GetGCThingMarkWordAndMask(const uintptr_t addr, + ColorBit colorBit, + uintptr_t** wordp, + uintptr_t* maskp) { + // Note: the JIT pre-barrier trampolines inline this code. Update that + // code too when making changes here! + MOZ_ASSERT(addr); + const size_t bit = (addr & js::gc::ChunkMask) / js::gc::CellBytesPerMarkBit + + static_cast(colorBit); + MOZ_ASSERT(bit < js::gc::ChunkMarkBitmapBits); + uintptr_t* bitmap = GetGCThingMarkBitmap(addr); + const uintptr_t nbits = sizeof(*bitmap) * CHAR_BIT; + *maskp = uintptr_t(1) << (bit % nbits); + *wordp = &bitmap[bit / nbits]; +} + +static MOZ_ALWAYS_INLINE JS::Zone* GetGCThingZone(const uintptr_t addr) { + MOZ_ASSERT(addr); + const uintptr_t zone_addr = (addr & ~ArenaMask) | ArenaZoneOffset; + return *reinterpret_cast(zone_addr); +} + +static MOZ_ALWAYS_INLINE bool TenuredCellIsMarkedGray(const Cell* cell) { + // Return true if GrayOrBlackBit is set and BlackBit is not set. + MOZ_ASSERT(cell); + MOZ_ASSERT(!js::gc::IsInsideNursery(cell)); + + uintptr_t *grayWord, grayMask; + js::gc::detail::GetGCThingMarkWordAndMask( + uintptr_t(cell), js::gc::ColorBit::GrayOrBlackBit, &grayWord, &grayMask); + if (!(*grayWord & grayMask)) return false; + + uintptr_t *blackWord, blackMask; + js::gc::detail::GetGCThingMarkWordAndMask( + uintptr_t(cell), js::gc::ColorBit::BlackBit, &blackWord, &blackMask); + return !(*blackWord & blackMask); +} + +static MOZ_ALWAYS_INLINE bool CellIsMarkedGray(const Cell* cell) { + MOZ_ASSERT(cell); + if (js::gc::IsInsideNursery(cell)) return false; + return TenuredCellIsMarkedGray(cell); } -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); - 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); + +#ifdef DEBUG +extern JS_PUBLIC_API bool CellIsNotGray(const Cell* cell); + +extern JS_PUBLIC_API bool ObjectIsMarkedBlack(const JSObject* obj); +#endif + +MOZ_ALWAYS_INLINE ChunkLocation GetCellLocation(const void* cell) { + uintptr_t addr = uintptr_t(cell); + addr &= ~js::gc::ChunkMask; + addr |= js::gc::ChunkLocationOffset; + return *reinterpret_cast(addr); } -extern JS_PUBLIC_API(bool) -CellIsMarkedGrayIfKnown(const Cell* cell); +MOZ_ALWAYS_INLINE bool NurseryCellHasStoreBuffer(const void* cell) { + uintptr_t addr = uintptr_t(cell); + addr &= ~js::gc::ChunkMask; + addr |= js::gc::ChunkStoreBufferOffset; + return *reinterpret_cast(addr) != nullptr; +} } /* namespace detail */ -MOZ_ALWAYS_INLINE bool -IsInsideNursery(const js::gc::Cell* cell) -{ - if (!cell) - return false; - uintptr_t addr = uintptr_t(cell); - addr &= ~js::gc::ChunkMask; - addr |= js::gc::ChunkLocationOffset; - auto location = *reinterpret_cast(addr); - MOZ_ASSERT(location == ChunkLocation::Nursery || location == ChunkLocation::TenuredHeap); - return location == ChunkLocation::Nursery; +MOZ_ALWAYS_INLINE bool IsInsideNursery(const js::gc::Cell* cell) { + if (!cell) return false; + auto location = detail::GetCellLocation(cell); + MOZ_ASSERT(location == ChunkLocation::Nursery || + location == ChunkLocation::TenuredHeap); + return location == ChunkLocation::Nursery; +} + +MOZ_ALWAYS_INLINE bool IsCellPointerValid(const void* cell) { + auto addr = uintptr_t(cell); + if (addr < ChunkSize || addr % CellAlignBytes != 0) return false; + auto location = detail::GetCellLocation(cell); + if (location == ChunkLocation::TenuredHeap) + return !!detail::GetGCThingZone(addr); + if (location == ChunkLocation::Nursery) + return detail::NurseryCellHasStoreBuffer(cell); + return false; +} + +MOZ_ALWAYS_INLINE bool IsCellPointerValidOrNull(const void* cell) { + if (!cell) return true; + return IsCellPointerValid(cell); } } /* namespace gc */ @@ -346,61 +420,137 @@ namespace JS { -static MOZ_ALWAYS_INLINE Zone* -GetTenuredGCThingZone(GCCellPtr thing) -{ - MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell())); - return js::gc::detail::GetGCThingZone(thing.unsafeAsUIntPtr()); +static MOZ_ALWAYS_INLINE Zone* GetTenuredGCThingZone(GCCellPtr thing) { + MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell())); + return js::gc::detail::GetGCThingZone(thing.unsafeAsUIntPtr()); } -static MOZ_ALWAYS_INLINE Zone* -GetStringZone(JSString* str) -{ - return js::gc::detail::GetGCThingZone(uintptr_t(str)); +extern JS_PUBLIC_API Zone* GetNurseryStringZone(JSString* str); + +static MOZ_ALWAYS_INLINE Zone* GetStringZone(JSString* str) { + if (!js::gc::IsInsideNursery(reinterpret_cast(str))) + return js::gc::detail::GetGCThingZone(reinterpret_cast(str)); + return GetNurseryStringZone(str); } -extern JS_PUBLIC_API(Zone*) -GetObjectZone(JSObject* obj); +extern JS_PUBLIC_API Zone* GetObjectZone(JSObject* obj); -static MOZ_ALWAYS_INLINE bool -GCThingIsMarkedGray(GCCellPtr thing) -{ - if (thing.mayBeOwnedByOtherRuntime()) - return false; - return js::gc::detail::CellIsMarkedGrayIfKnown(thing.asCell()); +extern JS_PUBLIC_API Zone* GetValueZone(const Value& value); + +static MOZ_ALWAYS_INLINE bool GCThingIsMarkedGray(GCCellPtr thing) { + if (thing.mayBeOwnedByOtherRuntime()) return false; + return js::gc::detail::CellIsMarkedGrayIfKnown(thing.asCell()); } -extern JS_PUBLIC_API(JS::TraceKind) -GCThingTraceKind(void* thing); +extern JS_PUBLIC_API JS::TraceKind GCThingTraceKind(void* thing); -} /* namespace JS */ +extern JS_PUBLIC_API void EnableNurseryStrings(JSContext* cx); + +extern JS_PUBLIC_API void DisableNurseryStrings(JSContext* cx); + +/* + * Returns true when writes to GC thing pointers (and reads from weak pointers) + * must call an incremental barrier. This is generally only true when running + * mutator code in-between GC slices. At other times, the barrier may be elided + * for performance. + */ +extern JS_PUBLIC_API bool IsIncrementalBarrierNeeded(JSContext* cx); + +/* + * Notify the GC that a reference to a JSObject is about to be overwritten. + * This method must be called if IsIncrementalBarrierNeeded. + */ +extern JS_PUBLIC_API void IncrementalPreWriteBarrier(JSObject* obj); + +/* + * Notify the GC that a weak reference to a GC thing has been read. + * This method must be called if IsIncrementalBarrierNeeded. + */ +extern JS_PUBLIC_API void IncrementalReadBarrier(GCCellPtr thing); + +/** + * Unsets the gray bit for anything reachable from |thing|. |kind| should not be + * JS::TraceKind::Shape. |thing| should be non-null. The return value indicates + * if anything was unmarked. + */ +extern JS_FRIEND_API bool UnmarkGrayGCThingRecursively(GCCellPtr thing); + +} // namespace JS namespace js { namespace gc { -static MOZ_ALWAYS_INLINE bool -IsIncrementalBarrierNeededOnTenuredGCThing(JS::shadow::Runtime* rt, const JS::GCCellPtr thing) -{ - MOZ_ASSERT(thing); - MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell())); - - // 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()); +static MOZ_ALWAYS_INLINE bool IsIncrementalBarrierNeededOnTenuredGCThing( + const JS::GCCellPtr thing) { + MOZ_ASSERT(thing); + MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell())); + + // TODO: I'd like to assert !CurrentThreadIsHeapBusy() here but this gets + // called while we are tracing the heap, e.g. during memory reporting + // (see bug 1313318). + MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting()); - JS::Zone* zone = JS::GetTenuredGCThingZone(thing); - return JS::shadow::Zone::asShadowZone(zone)->needsIncrementalBarrier(); + JS::Zone* zone = JS::GetTenuredGCThingZone(thing); + return JS::shadow::Zone::asShadowZone(zone)->needsIncrementalBarrier(); } -/** - * Create an object providing access to the garbage collector's internal notion - * of the current state of memory (both GC heap memory and GCthing-controlled - * malloc memory. +static MOZ_ALWAYS_INLINE void ExposeGCThingToActiveJS(JS::GCCellPtr thing) { + // 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; + + // There's nothing to do for permanent GC things that might be owned by + // another runtime. + if (thing.mayBeOwnedByOtherRuntime()) return; + + if (IsIncrementalBarrierNeededOnTenuredGCThing(thing)) + JS::IncrementalReadBarrier(thing); + else if (js::gc::detail::TenuredCellIsMarkedGray(thing.asCell())) + JS::UnmarkGrayGCThingRecursively(thing); + + MOZ_ASSERT(!js::gc::detail::TenuredCellIsMarkedGray(thing.asCell())); +} + +template +extern JS_PUBLIC_API bool EdgeNeedsSweepUnbarrieredSlow(T* thingp); + +static MOZ_ALWAYS_INLINE bool EdgeNeedsSweepUnbarriered(JSObject** objp) { + // This function does not handle updating nursery pointers. Raw JSObject + // pointers should be updated separately or replaced with + // JS::Heap which handles this automatically. + MOZ_ASSERT(!JS::CurrentThreadIsHeapMinorCollecting()); + if (IsInsideNursery(reinterpret_cast(*objp))) return false; + + auto zone = + JS::shadow::Zone::asShadowZone(detail::GetGCThingZone(uintptr_t(*objp))); + if (!zone->isGCSweepingOrCompacting()) return false; + + return EdgeNeedsSweepUnbarrieredSlow(objp); +} + +} // namespace gc +} // namespace js + +namespace JS { + +/* + * This should be called when an object that is marked gray is exposed to the JS + * engine (by handing it to running JS code or writing it into live JS + * data). During incremental GC, since the gray bits haven't been computed yet, + * we conservatively mark the object black. */ -extern JS_PUBLIC_API(JSObject*) -NewMemoryInfoObject(JSContext* cx); +static MOZ_ALWAYS_INLINE void ExposeObjectToActiveJS(JSObject* obj) { + MOZ_ASSERT(obj); + MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&obj)); + js::gc::ExposeGCThingToActiveJS(GCCellPtr(obj)); +} -} /* namespace gc */ -} /* namespace js */ +static MOZ_ALWAYS_INLINE void ExposeScriptToActiveJS(JSScript* script) { + MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&script)); + js::gc::ExposeGCThingToActiveJS(GCCellPtr(script)); +} + +} /* namespace JS */ #endif /* js_HeapAPI_h */ 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 @@ -27,35 +27,30 @@ #include "js/TypeDecls.h" #include "js/Utility.h" -struct jsid -{ - size_t asBits; - bool operator==(const jsid& rhs) const { return asBits == rhs.asBits; } - bool operator!=(const jsid& rhs) const { return asBits != rhs.asBits; } +struct jsid { + size_t asBits; + bool operator==(const jsid& rhs) const { return asBits == rhs.asBits; } + bool operator!=(const jsid& rhs) const { return asBits != rhs.asBits; } } JS_HAZ_GC_POINTER; #define JSID_BITS(id) (id.asBits) -#define JSID_TYPE_STRING 0x0 -#define JSID_TYPE_INT 0x1 -#define JSID_TYPE_VOID 0x2 -#define JSID_TYPE_SYMBOL 0x4 -#define JSID_TYPE_MASK 0x7 +#define JSID_TYPE_STRING 0x0 +#define JSID_TYPE_INT 0x1 +#define JSID_TYPE_VOID 0x2 +#define JSID_TYPE_SYMBOL 0x4 +#define JSID_TYPE_MASK 0x7 // Avoid using canonical 'id' for jsid parameters since this is a magic word in // Objective-C++ which, apparently, wants to be able to #include jsapi.h. #define id iden -static MOZ_ALWAYS_INLINE bool -JSID_IS_STRING(jsid id) -{ - return (JSID_BITS(id) & JSID_TYPE_MASK) == 0; +static MOZ_ALWAYS_INLINE bool JSID_IS_STRING(jsid id) { + return (JSID_BITS(id) & JSID_TYPE_MASK) == 0; } -static MOZ_ALWAYS_INLINE JSString* -JSID_TO_STRING(jsid id) -{ - MOZ_ASSERT(JSID_IS_STRING(id)); - return (JSString*)JSID_BITS(id); +static MOZ_ALWAYS_INLINE JSString* JSID_TO_STRING(jsid id) { + MOZ_ASSERT(JSID_IS_STRING(id)); + return (JSString*)JSID_BITS(id); } /** @@ -65,143 +60,135 @@ * N.B. if a jsid is backed by a string which has not been interned, that * string must be appropriately rooted to avoid being collected by the GC. */ -JS_PUBLIC_API(jsid) -INTERNED_STRING_TO_JSID(JSContext* cx, JSString* str); +JS_PUBLIC_API jsid INTERNED_STRING_TO_JSID(JSContext* cx, JSString* str); -static MOZ_ALWAYS_INLINE bool -JSID_IS_INT(jsid id) -{ - return !!(JSID_BITS(id) & JSID_TYPE_INT); +static MOZ_ALWAYS_INLINE bool JSID_IS_INT(jsid id) { + return !!(JSID_BITS(id) & JSID_TYPE_INT); } -static MOZ_ALWAYS_INLINE int32_t -JSID_TO_INT(jsid id) -{ - MOZ_ASSERT(JSID_IS_INT(id)); - return ((uint32_t)JSID_BITS(id)) >> 1; +static MOZ_ALWAYS_INLINE int32_t JSID_TO_INT(jsid id) { + MOZ_ASSERT(JSID_IS_INT(id)); + uint32_t bits = static_cast(JSID_BITS(id)) >> 1; + return static_cast(bits); } -#define JSID_INT_MIN 0 -#define JSID_INT_MAX INT32_MAX +#define JSID_INT_MIN 0 +#define JSID_INT_MAX INT32_MAX -static MOZ_ALWAYS_INLINE bool -INT_FITS_IN_JSID(int32_t i) -{ - return i >= 0; -} +static MOZ_ALWAYS_INLINE bool INT_FITS_IN_JSID(int32_t i) { return i >= 0; } -static MOZ_ALWAYS_INLINE jsid -INT_TO_JSID(int32_t i) -{ - jsid id; - MOZ_ASSERT(INT_FITS_IN_JSID(i)); - JSID_BITS(id) = ((i << 1) | JSID_TYPE_INT); - return id; +static MOZ_ALWAYS_INLINE jsid INT_TO_JSID(int32_t i) { + jsid id; + MOZ_ASSERT(INT_FITS_IN_JSID(i)); + uint32_t bits = (static_cast(i) << 1) | JSID_TYPE_INT; + JSID_BITS(id) = static_cast(bits); + return id; } -static MOZ_ALWAYS_INLINE bool -JSID_IS_SYMBOL(jsid id) -{ - return (JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_SYMBOL && - JSID_BITS(id) != JSID_TYPE_SYMBOL; +static MOZ_ALWAYS_INLINE bool JSID_IS_SYMBOL(jsid id) { + return (JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_SYMBOL && + JSID_BITS(id) != JSID_TYPE_SYMBOL; } -static MOZ_ALWAYS_INLINE JS::Symbol* -JSID_TO_SYMBOL(jsid id) -{ - MOZ_ASSERT(JSID_IS_SYMBOL(id)); - return (JS::Symbol*)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); +static MOZ_ALWAYS_INLINE JS::Symbol* JSID_TO_SYMBOL(jsid id) { + MOZ_ASSERT(JSID_IS_SYMBOL(id)); + return (JS::Symbol*)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); } -static MOZ_ALWAYS_INLINE jsid -SYMBOL_TO_JSID(JS::Symbol* sym) -{ - jsid id; - MOZ_ASSERT(sym != nullptr); - MOZ_ASSERT((size_t(sym) & JSID_TYPE_MASK) == 0); - MOZ_ASSERT(!js::gc::IsInsideNursery(reinterpret_cast(sym))); - JSID_BITS(id) = (size_t(sym) | JSID_TYPE_SYMBOL); - return id; +static MOZ_ALWAYS_INLINE jsid SYMBOL_TO_JSID(JS::Symbol* sym) { + jsid id; + MOZ_ASSERT(sym != nullptr); + MOZ_ASSERT((size_t(sym) & JSID_TYPE_MASK) == 0); + MOZ_ASSERT(!js::gc::IsInsideNursery(reinterpret_cast(sym))); + JSID_BITS(id) = (size_t(sym) | JSID_TYPE_SYMBOL); + return id; } -static MOZ_ALWAYS_INLINE bool -JSID_IS_GCTHING(jsid id) -{ - return JSID_IS_STRING(id) || JSID_IS_SYMBOL(id); +static MOZ_ALWAYS_INLINE bool JSID_IS_GCTHING(jsid id) { + return JSID_IS_STRING(id) || JSID_IS_SYMBOL(id); } -static MOZ_ALWAYS_INLINE JS::GCCellPtr -JSID_TO_GCTHING(jsid id) -{ - void* thing = (void*)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); - if (JSID_IS_STRING(id)) - return JS::GCCellPtr(thing, JS::TraceKind::String); - MOZ_ASSERT(JSID_IS_SYMBOL(id)); - return JS::GCCellPtr(thing, JS::TraceKind::Symbol); +static MOZ_ALWAYS_INLINE JS::GCCellPtr JSID_TO_GCTHING(jsid id) { + void* thing = (void*)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK); + if (JSID_IS_STRING(id)) return JS::GCCellPtr(thing, JS::TraceKind::String); + MOZ_ASSERT(JSID_IS_SYMBOL(id)); + return JS::GCCellPtr(thing, JS::TraceKind::Symbol); } -static MOZ_ALWAYS_INLINE bool -JSID_IS_VOID(const jsid id) -{ - MOZ_ASSERT_IF(((size_t)JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_VOID, - JSID_BITS(id) == JSID_TYPE_VOID); - return (size_t)JSID_BITS(id) == JSID_TYPE_VOID; +static MOZ_ALWAYS_INLINE bool JSID_IS_VOID(const jsid id) { + MOZ_ASSERT_IF(((size_t)JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_VOID, + JSID_BITS(id) == JSID_TYPE_VOID); + return (size_t)JSID_BITS(id) == JSID_TYPE_VOID; } -static MOZ_ALWAYS_INLINE bool -JSID_IS_EMPTY(const jsid id) -{ - return (size_t)JSID_BITS(id) == JSID_TYPE_SYMBOL; +static MOZ_ALWAYS_INLINE bool JSID_IS_EMPTY(const jsid id) { + return (size_t)JSID_BITS(id) == JSID_TYPE_SYMBOL; } -extern JS_PUBLIC_DATA(const jsid) JSID_VOID; -extern JS_PUBLIC_DATA(const jsid) JSID_EMPTY; +extern JS_PUBLIC_DATA const jsid JSID_VOID; +extern JS_PUBLIC_DATA const jsid JSID_EMPTY; -extern JS_PUBLIC_DATA(const JS::HandleId) JSID_VOIDHANDLE; -extern JS_PUBLIC_DATA(const JS::HandleId) JSID_EMPTYHANDLE; +extern JS_PUBLIC_DATA const JS::HandleId JSID_VOIDHANDLE; +extern JS_PUBLIC_DATA const JS::HandleId JSID_EMPTYHANDLE; namespace JS { template <> -struct GCPolicy -{ - static jsid initial() { return JSID_VOID; } - static void trace(JSTracer* trc, jsid* idp, const char* name) { - js::UnsafeTraceManuallyBarrieredEdge(trc, idp, name); - } +struct GCPolicy { + static jsid initial() { return JSID_VOID; } + static void trace(JSTracer* trc, jsid* idp, const char* name) { + js::UnsafeTraceManuallyBarrieredEdge(trc, idp, name); + } + static bool isValid(jsid id) { + return !JSID_IS_GCTHING(id) || + js::gc::IsCellPointerValid(JSID_TO_GCTHING(id).asCell()); + } }; -} // namespace JS +#ifdef DEBUG +MOZ_ALWAYS_INLINE bool IdIsNotGray(jsid id) { + if (!JSID_IS_GCTHING(id)) return true; + + return CellIsNotGray(JSID_TO_GCTHING(id).asCell()); +} +#endif + +} // 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)); - } +struct BarrierMethods { + static gc::Cell* asGCThingOrNull(jsid id) { + if (JSID_IS_STRING(id)) + return reinterpret_cast(JSID_TO_STRING(id)); + if (JSID_IS_SYMBOL(id)) + return reinterpret_cast(JSID_TO_SYMBOL(id)); + return nullptr; + } + static void postBarrier(jsid* idp, jsid prev, jsid next) {} + static void 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, const jsid& id, Args&&... args) - -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) -{ - if (JSID_IS_STRING(id)) - return f(JSID_TO_STRING(id), mozilla::Forward(args)...); - if (JSID_IS_SYMBOL(id)) - return f(JSID_TO_SYMBOL(id), mozilla::Forward(args)...); - MOZ_ASSERT(!JSID_IS_GCTHING(id)); - return F::defaultValue(id); +auto DispatchTyped(F f, const jsid& id, Args&&... args) + -> decltype(f(static_cast(nullptr), + mozilla::Forward(args)...)) { + if (JSID_IS_STRING(id)) + return f(JSID_TO_STRING(id), mozilla::Forward(args)...); + if (JSID_IS_SYMBOL(id)) + return f(JSID_TO_SYMBOL(id), mozilla::Forward(args)...); + MOZ_ASSERT(!JSID_IS_GCTHING(id)); + return F::defaultValue(id); } #undef id -} // namespace js +} // namespace js #endif /* js_Id_h */ 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 @@ -13,7 +13,7 @@ namespace JS { namespace detail { -enum class InitState { Uninitialized = 0, Running, ShutDown }; +enum class InitState { Uninitialized = 0, Initializing, Running, ShutDown }; /** * SpiderMonkey's initialization status is tracked here, and it controls things @@ -22,14 +22,12 @@ * manner, so this (internal -- embedders, don't use!) variable doesn't need to * be atomic. */ -extern JS_PUBLIC_DATA(InitState) -libraryInitState; +extern JS_PUBLIC_DATA InitState libraryInitState; -extern JS_PUBLIC_API(const char*) -InitWithFailureDiagnostic(bool isDebugBuild); +extern JS_PUBLIC_API const char* InitWithFailureDiagnostic(bool isDebugBuild); -} // namespace detail -} // namespace JS +} // namespace detail +} // namespace JS // These are equivalent to ICU's |UMemAllocFn|, |UMemReallocFn|, and // |UMemFreeFn| types. The first argument (called |context| in the ICU docs) @@ -43,14 +41,13 @@ * *must* be called before JS_Init. Don't use it unless you know what you're * doing! */ -extern JS_PUBLIC_API(bool) -JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, - JS_ICUReallocFn reallocFn, - JS_ICUFreeFn freeFn); +extern JS_PUBLIC_API bool JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, + JS_ICUReallocFn reallocFn, + JS_ICUFreeFn freeFn); /** * Initialize SpiderMonkey, returning true only if initialization succeeded. - * Once this method has succeeded, it is safe to call JS_NewRuntime and other + * Once this method has succeeded, it is safe to call JS_NewContext and other * JSAPI methods. * * This method must be called before any other JSAPI method is used on any @@ -61,13 +58,11 @@ * is, calling JS_Init/JSAPI methods/JS_ShutDown in that order, then doing so * again). This restriction may eventually be lifted. */ -inline bool -JS_Init(void) -{ +inline bool JS_Init(void) { #ifdef DEBUG - return !JS::detail::InitWithFailureDiagnostic(true); + return !JS::detail::InitWithFailureDiagnostic(true); #else - return !JS::detail::InitWithFailureDiagnostic(false); + return !JS::detail::InitWithFailureDiagnostic(false); #endif } @@ -76,19 +71,17 @@ * pointer to a string literal that describes how initialization failed, which * can be useful for debugging purposes. */ -inline const char* -JS_InitWithFailureDiagnostic(void) -{ +inline const char* JS_InitWithFailureDiagnostic(void) { #ifdef DEBUG - return JS::detail::InitWithFailureDiagnostic(true); + return JS::detail::InitWithFailureDiagnostic(true); #else - return JS::detail::InitWithFailureDiagnostic(false); + return JS::detail::InitWithFailureDiagnostic(false); #endif } /* - * Returns true if SpiderMonkey has been initialized successfully, even if it has - * possibly been shut down. + * 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 @@ -96,10 +89,8 @@ * 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; +inline bool JS_IsInitialized(void) { + return JS::detail::libraryInitState >= JS::detail::InitState::Running; } /** @@ -119,7 +110,6 @@ * 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(void) -JS_ShutDown(void); +extern JS_PUBLIC_API void JS_ShutDown(void); #endif /* js_Initialization_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/LegacyIntTypes.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/LegacyIntTypes.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/LegacyIntTypes.h @@ -1,59 +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/. */ - -/* - * This section typedefs the old 'native' types to the new types. - * These redefinitions are provided solely to allow JSAPI users to more easily - * transition to types. They are not to be used in the JSAPI, and - * new JSAPI user code should not use them. This mapping file may eventually - * be removed from SpiderMonkey, so don't depend on it in the long run. - */ - -/* - * BEWARE: Comity with other implementers of these types is not guaranteed. - * Indeed, if you use this header and third-party code defining these - * types, *expect* to encounter either compile errors or link errors, - * depending how these types are used and on the order of inclusion. - * It is safest to use only the types. - */ -#ifndef js_LegacyIntTypes_h -#define js_LegacyIntTypes_h - -#include - -#include "js-config.h" - -typedef uint8_t uint8; -typedef uint16_t uint16; -typedef uint32_t uint32; -typedef uint64_t uint64; - -/* - * On AIX 4.3, sys/inttypes.h (which is included by sys/types.h, a very - * common header file) defines the types int8, int16, int32, and int64. - * So we don't define these four types here to avoid conflicts in case - * the code also includes sys/types.h. - */ -#if defined(AIX) && defined(HAVE_SYS_INTTYPES_H) -#include -#else -typedef int8_t int8; -typedef int16_t int16; -typedef int32_t int32; -typedef int64_t int64; -#endif /* AIX && HAVE_SYS_INTTYPES_H */ - -typedef uint8_t JSUint8; -typedef uint16_t JSUint16; -typedef uint32_t JSUint32; -typedef uint64_t JSUint64; - -typedef int8_t JSInt8; -typedef int16_t JSInt16; -typedef int32_t JSInt32; -typedef int64_t JSInt64; - -#endif /* js_LegacyIntTypes_h */ 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 @@ -16,82 +16,98 @@ #include -#include "jsalloc.h" #include "jspubtd.h" +#include "js/AllocPolicy.h" #include "js/HashTable.h" #include "js/TracingAPI.h" #include "js/Utility.h" #include "js/Vector.h" -class nsISupports; // Needed for ObjectPrivateVisitor. +class nsISupports; // Needed for ObjectPrivateVisitor. namespace JS { -struct TabSizes -{ - enum Kind { - Objects, - Strings, - Private, - Other - }; - - TabSizes() { mozilla::PodZero(this); } - - void add(Kind kind, size_t n) { - switch (kind) { - case Objects: objects += n; break; - case Strings: strings += n; break; - case Private: private_ += n; break; - case Other: other += n; break; - default: MOZ_CRASH("bad TabSizes kind"); - } - } +struct TabSizes { + enum Kind { Objects, Strings, Private, Other }; + + TabSizes() { mozilla::PodZero(this); } - size_t objects; - size_t strings; - size_t private_; - size_t other; + void add(Kind kind, size_t n) { + switch (kind) { + case Objects: + objects += n; + break; + case Strings: + strings += n; + break; + case Private: + private_ += n; + break; + case Other: + other += n; + break; + default: + MOZ_CRASH("bad TabSizes kind"); + } + } + + size_t objects; + size_t strings; + size_t private_; + size_t other; }; /** These are the measurements used by Servo. */ -struct ServoSizes -{ - enum Kind { - GCHeapUsed, - GCHeapUnused, - GCHeapAdmin, - GCHeapDecommitted, - MallocHeap, - NonHeap, - Ignore - }; - - ServoSizes() { mozilla::PodZero(this); } - - void add(Kind kind, size_t n) { - switch (kind) { - case GCHeapUsed: gcHeapUsed += n; break; - case GCHeapUnused: gcHeapUnused += n; break; - case GCHeapAdmin: gcHeapAdmin += n; break; - case GCHeapDecommitted: gcHeapDecommitted += n; break; - case MallocHeap: mallocHeap += n; break; - case NonHeap: nonHeap += n; break; - case Ignore: /* do nothing */ break; - default: MOZ_CRASH("bad ServoSizes kind"); - } - } - - size_t gcHeapUsed; - size_t gcHeapUnused; - size_t gcHeapAdmin; - size_t gcHeapDecommitted; - size_t mallocHeap; - size_t nonHeap; +struct ServoSizes { + enum Kind { + GCHeapUsed, + GCHeapUnused, + GCHeapAdmin, + GCHeapDecommitted, + MallocHeap, + NonHeap, + Ignore + }; + + ServoSizes() { mozilla::PodZero(this); } + + void add(Kind kind, size_t n) { + switch (kind) { + case GCHeapUsed: + gcHeapUsed += n; + break; + case GCHeapUnused: + gcHeapUnused += n; + break; + case GCHeapAdmin: + gcHeapAdmin += n; + break; + case GCHeapDecommitted: + gcHeapDecommitted += n; + break; + case MallocHeap: + mallocHeap += n; + break; + case NonHeap: + nonHeap += n; + break; + case Ignore: /* do nothing */ + break; + default: + MOZ_CRASH("bad ServoSizes kind"); + } + } + + size_t gcHeapUsed; + size_t gcHeapUnused; + size_t gcHeapAdmin; + size_t gcHeapDecommitted; + size_t mallocHeap; + size_t nonHeap; }; -} // namespace JS +} // namespace JS namespace js { @@ -104,25 +120,23 @@ * We need to define this value here, rather than in the code which actually * generates the memory reports, because NotableStringInfo uses this value. */ -JS_FRIEND_API(size_t) MemoryReportingSundriesThreshold(); +JS_FRIEND_API size_t MemoryReportingSundriesThreshold(); /** * This hash policy avoids flattening ropes (which perturbs the site being * measured and requires a JSContext) at the expense of doing a FULL ROPE COPY * on every hash and match! Beware. */ -struct InefficientNonFlatteningStringHashPolicy -{ - typedef JSString* Lookup; - static HashNumber hash(const Lookup& l); - static bool match(const JSString* const& k, const Lookup& l); +struct InefficientNonFlatteningStringHashPolicy { + typedef JSString* Lookup; + static HashNumber hash(const Lookup& l); + static bool match(const JSString* const& k, const Lookup& l); }; -struct CStringHashPolicy -{ - typedef const char* Lookup; - static HashNumber hash(const Lookup& l); - static bool match(const char* const& k, const Lookup& l); +struct CStringHashPolicy { + typedef const char* Lookup; + static HashNumber hash(const Lookup& l); + static bool match(const char* const& k, const Lookup& l); }; // This file features many classes with numerous size_t fields, and each such @@ -141,128 +155,108 @@ // In some classes, one or more of the macro arguments aren't used. We use '_' // for those. // -#define DECL_SIZE(tabKind, servoKind, mSize) size_t mSize; -#define ZERO_SIZE(tabKind, servoKind, mSize) mSize(0), -#define COPY_OTHER_SIZE(tabKind, servoKind, mSize) mSize(other.mSize), -#define ADD_OTHER_SIZE(tabKind, servoKind, mSize) mSize += other.mSize; +#define DECL_SIZE(tabKind, servoKind, mSize) size_t mSize; +#define ZERO_SIZE(tabKind, servoKind, mSize) mSize(0), +#define COPY_OTHER_SIZE(tabKind, servoKind, mSize) mSize(other.mSize), +#define ADD_OTHER_SIZE(tabKind, servoKind, mSize) mSize += other.mSize; #define SUB_OTHER_SIZE(tabKind, servoKind, mSize) \ - MOZ_ASSERT(mSize >= other.mSize); \ - mSize -= other.mSize; -#define ADD_SIZE_TO_N(tabKind, servoKind, mSize) n += mSize; -#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(tabKind, servoKind, mSize) \ - /* Avoid self-comparison warnings by comparing enums indirectly. */ \ - n += (mozilla::IsSame::value) \ - ? mSize \ - : 0; -#define ADD_TO_TAB_SIZES(tabKind, servoKind, mSize) sizes->add(JS::TabSizes::tabKind, mSize); -#define ADD_TO_SERVO_SIZES(tabKind, servoKind, mSize) sizes->add(JS::ServoSizes::servoKind, mSize); + MOZ_ASSERT(mSize >= other.mSize); \ + mSize -= other.mSize; +#define ADD_SIZE_TO_N(tabKind, servoKind, mSize) n += mSize; +#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(tabKind, servoKind, mSize) \ + /* Avoid self-comparison warnings by comparing enums indirectly. */ \ + n += (mozilla::IsSame::value) \ + ? mSize \ + : 0; +#define ADD_TO_TAB_SIZES(tabKind, servoKind, mSize) \ + sizes->add(JS::TabSizes::tabKind, mSize); +#define ADD_TO_SERVO_SIZES(tabKind, servoKind, mSize) \ + sizes->add(JS::ServoSizes::servoKind, mSize); -} // namespace js +} // namespace js namespace JS { -struct ClassInfo -{ -#define FOR_EACH_SIZE(macro) \ - macro(Objects, GCHeapUsed, objectsGCHeap) \ - macro(Objects, MallocHeap, objectsMallocHeapSlots) \ - macro(Objects, MallocHeap, objectsMallocHeapElementsNormal) \ - macro(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \ - macro(Objects, MallocHeap, objectsMallocHeapMisc) \ - macro(Objects, NonHeap, objectsNonHeapElementsNormal) \ - macro(Objects, NonHeap, objectsNonHeapElementsShared) \ - macro(Objects, NonHeap, objectsNonHeapElementsWasm) \ - macro(Objects, NonHeap, objectsNonHeapCodeWasm) - - ClassInfo() - : FOR_EACH_SIZE(ZERO_SIZE) - wasmGuardPages(0) - {} +struct ClassInfo { +#define FOR_EACH_SIZE(MACRO) \ + MACRO(Objects, GCHeapUsed, objectsGCHeap) \ + MACRO(Objects, MallocHeap, objectsMallocHeapSlots) \ + MACRO(Objects, MallocHeap, objectsMallocHeapElementsNormal) \ + MACRO(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \ + MACRO(Objects, MallocHeap, objectsMallocHeapMisc) \ + MACRO(Objects, NonHeap, objectsNonHeapElementsNormal) \ + MACRO(Objects, NonHeap, objectsNonHeapElementsShared) \ + MACRO(Objects, NonHeap, objectsNonHeapElementsWasm) \ + MACRO(Objects, NonHeap, objectsNonHeapCodeWasm) - void add(const ClassInfo& other) { - FOR_EACH_SIZE(ADD_OTHER_SIZE) - } + ClassInfo() : FOR_EACH_SIZE(ZERO_SIZE) wasmGuardPages(0) {} - void subtract(const ClassInfo& other) { - FOR_EACH_SIZE(SUB_OTHER_SIZE) - } + void add(const ClassInfo& other) { FOR_EACH_SIZE(ADD_OTHER_SIZE) } - size_t sizeOfAllThings() const { - size_t n = 0; - FOR_EACH_SIZE(ADD_SIZE_TO_N) - return n; - } + void subtract(const ClassInfo& other){FOR_EACH_SIZE(SUB_OTHER_SIZE)} - bool isNotable() const { - static const size_t NotabilityThreshold = 16 * 1024; - return sizeOfAllThings() >= NotabilityThreshold; - } + 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; - } + bool isNotable() const { + static const size_t NotabilityThreshold = 16 * 1024; + return sizeOfAllThings() >= NotabilityThreshold; + } - void addToTabSizes(TabSizes* sizes) const { - FOR_EACH_SIZE(ADD_TO_TAB_SIZES) - } + size_t sizeOfLiveGCThings() const { + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) + return n; + } - void addToServoSizes(ServoSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) - } + 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) - size_t wasmGuardPages; + 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) +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() - {} + ShapeInfo() : FOR_EACH_SIZE(ZERO_SIZE) dummy() {} - void add(const ShapeInfo& other) { - FOR_EACH_SIZE(ADD_OTHER_SIZE) - } + void add(const ShapeInfo& other) { FOR_EACH_SIZE(ADD_OTHER_SIZE) } - void subtract(const ShapeInfo& other) { - FOR_EACH_SIZE(SUB_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 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; - } + 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 addToTabSizes(TabSizes* sizes) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES) } - void addToServoSizes(ServoSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_SERVO_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) + FOR_EACH_SIZE(DECL_SIZE) int dummy; // present just to absorb the trailing + // comma from FOR_EACH_SIZE(ZERO_SIZE) #undef FOR_EACH_SIZE }; @@ -275,74 +269,61 @@ * The only difference between this class and ClassInfo is that this class * holds a copy of the filename. */ -struct NotableClassInfo : public ClassInfo -{ - NotableClassInfo(); - NotableClassInfo(const char* className, const ClassInfo& info); - NotableClassInfo(NotableClassInfo&& info); - NotableClassInfo& operator=(NotableClassInfo&& info); +struct NotableClassInfo : public ClassInfo { + NotableClassInfo(); + NotableClassInfo(const char* className, const ClassInfo& info); + NotableClassInfo(NotableClassInfo&& info); + NotableClassInfo& operator=(NotableClassInfo&& info); - ~NotableClassInfo() { - js_free(className_); - } + ~NotableClassInfo() { js_free(className_); } - char* className_; + char* className_; - private: - NotableClassInfo(const NotableClassInfo& info) = delete; + private: + NotableClassInfo(const NotableClassInfo& info) = delete; }; /** Data for tracking JIT-code memory usage. */ -struct CodeSizes -{ -#define FOR_EACH_SIZE(macro) \ - macro(_, NonHeap, ion) \ - macro(_, NonHeap, baseline) \ - macro(_, NonHeap, regexp) \ - macro(_, NonHeap, other) \ - macro(_, NonHeap, unused) - - CodeSizes() - : FOR_EACH_SIZE(ZERO_SIZE) - dummy() - {} +struct CodeSizes { +#define FOR_EACH_SIZE(MACRO) \ + MACRO(_, NonHeap, ion) \ + MACRO(_, NonHeap, baseline) \ + MACRO(_, NonHeap, regexp) \ + MACRO(_, NonHeap, other) \ + MACRO(_, NonHeap, unused) - void addToServoSizes(ServoSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) - } + CodeSizes() : FOR_EACH_SIZE(ZERO_SIZE) dummy() {} - FOR_EACH_SIZE(DECL_SIZE) - int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE) + 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 }; /** Data for tracking GC memory usage. */ -struct GCSizes -{ - // |nurseryDecommitted| is marked as NonHeap rather than GCHeapDecommitted - // because we don't consider the nursery to be part of the GC heap. -#define FOR_EACH_SIZE(macro) \ - macro(_, MallocHeap, marker) \ - macro(_, NonHeap, nurseryCommitted) \ - macro(_, MallocHeap, nurseryMallocedBuffers) \ - macro(_, MallocHeap, storeBufferVals) \ - macro(_, MallocHeap, storeBufferCells) \ - macro(_, MallocHeap, storeBufferSlots) \ - macro(_, MallocHeap, storeBufferWholeCells) \ - macro(_, MallocHeap, storeBufferGenerics) - - GCSizes() - : FOR_EACH_SIZE(ZERO_SIZE) - dummy() - {} +struct GCSizes { +// |nurseryDecommitted| is marked as NonHeap rather than GCHeapDecommitted +// because we don't consider the nursery to be part of the GC heap. +#define FOR_EACH_SIZE(MACRO) \ + MACRO(_, MallocHeap, marker) \ + MACRO(_, NonHeap, nurseryCommitted) \ + MACRO(_, MallocHeap, nurseryMallocedBuffers) \ + MACRO(_, MallocHeap, storeBufferVals) \ + MACRO(_, MallocHeap, storeBufferCells) \ + MACRO(_, MallocHeap, storeBufferSlots) \ + MACRO(_, MallocHeap, storeBufferWholeCells) \ + MACRO(_, MallocHeap, storeBufferGenerics) - void addToServoSizes(ServoSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) - } + GCSizes() : FOR_EACH_SIZE(ZERO_SIZE) dummy() {} + + 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) + FOR_EACH_SIZE(DECL_SIZE) int dummy; // present just to absorb the trailing + // comma from FOR_EACH_SIZE(ZERO_SIZE) #undef FOR_EACH_SIZE }; @@ -354,52 +335,45 @@ * chars will not be aggregated together if one is a short string and the other * is not. */ -struct StringInfo -{ -#define FOR_EACH_SIZE(macro) \ - macro(Strings, GCHeapUsed, gcHeapLatin1) \ - macro(Strings, GCHeapUsed, gcHeapTwoByte) \ - macro(Strings, MallocHeap, mallocHeapLatin1) \ - macro(Strings, MallocHeap, mallocHeapTwoByte) - - StringInfo() - : FOR_EACH_SIZE(ZERO_SIZE) - numCopies(0) - {} - - void add(const StringInfo& other) { - FOR_EACH_SIZE(ADD_OTHER_SIZE); - numCopies++; - } - - void subtract(const StringInfo& other) { - FOR_EACH_SIZE(SUB_OTHER_SIZE); - numCopies--; - } +struct StringInfo { +#define FOR_EACH_SIZE(MACRO) \ + MACRO(Strings, GCHeapUsed, gcHeapLatin1) \ + MACRO(Strings, GCHeapUsed, gcHeapTwoByte) \ + MACRO(Strings, MallocHeap, mallocHeapLatin1) \ + MACRO(Strings, MallocHeap, mallocHeapTwoByte) + + StringInfo() : FOR_EACH_SIZE(ZERO_SIZE) numCopies(0) {} + + void add(const StringInfo& other) { + FOR_EACH_SIZE(ADD_OTHER_SIZE); + numCopies++; + } + + void subtract(const StringInfo& other) { + FOR_EACH_SIZE(SUB_OTHER_SIZE); + numCopies--; + } + + bool isNotable() const { + static const size_t NotabilityThreshold = 16 * 1024; + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N) + return n >= NotabilityThreshold; + } + + size_t sizeOfLiveGCThings() const { + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) + return n; + } - bool isNotable() const { - static const size_t NotabilityThreshold = 16 * 1024; - size_t n = 0; - FOR_EACH_SIZE(ADD_SIZE_TO_N) - return n >= NotabilityThreshold; - } + void addToTabSizes(TabSizes* sizes) const { FOR_EACH_SIZE(ADD_TO_TAB_SIZES) } - size_t sizeOfLiveGCThings() const { - size_t n = 0; - FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) - return n; - } + void addToServoSizes(ServoSizes* sizes) const { + FOR_EACH_SIZE(ADD_TO_SERVO_SIZES)} - 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) - uint32_t numCopies; // How many copies of the string have we seen? + FOR_EACH_SIZE(DECL_SIZE) + uint32_t numCopies; // How many copies of the string have we seen? #undef FOR_EACH_SIZE }; @@ -411,65 +385,57 @@ * The only difference between this class and StringInfo is that * NotableStringInfo holds a copy of some or all of the string's chars. */ -struct NotableStringInfo : public StringInfo -{ - static const size_t MAX_SAVED_CHARS = 1024; - - NotableStringInfo(); - NotableStringInfo(JSString* str, const StringInfo& info); - NotableStringInfo(NotableStringInfo&& info); - NotableStringInfo& operator=(NotableStringInfo&& info); +struct NotableStringInfo : public StringInfo { + static const size_t MAX_SAVED_CHARS = 1024; - ~NotableStringInfo() { - js_free(buffer); - } + NotableStringInfo(); + NotableStringInfo(JSString* str, const StringInfo& info); + NotableStringInfo(NotableStringInfo&& info); + NotableStringInfo& operator=(NotableStringInfo&& info); - char* buffer; - size_t length; + ~NotableStringInfo() { js_free(buffer); } - private: - NotableStringInfo(const NotableStringInfo& info) = delete; + char* buffer; + size_t length; + + private: + NotableStringInfo(const NotableStringInfo& info) = delete; }; /** * This class holds information about the memory taken up by script sources * from a particular file. */ -struct ScriptSourceInfo -{ -#define FOR_EACH_SIZE(macro) \ - macro(_, MallocHeap, misc) - - ScriptSourceInfo() - : FOR_EACH_SIZE(ZERO_SIZE) - numScripts(0) - {} - - void add(const ScriptSourceInfo& other) { - FOR_EACH_SIZE(ADD_OTHER_SIZE) - numScripts++; - } - - void subtract(const ScriptSourceInfo& other) { - FOR_EACH_SIZE(SUB_OTHER_SIZE) - numScripts--; - } - - void addToServoSizes(ServoSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) - } +struct ScriptSourceInfo { +#define FOR_EACH_SIZE(MACRO) MACRO(_, MallocHeap, misc) - bool isNotable() const { - static const size_t NotabilityThreshold = 16 * 1024; - size_t n = 0; - FOR_EACH_SIZE(ADD_SIZE_TO_N) - return n >= NotabilityThreshold; - } + ScriptSourceInfo() : FOR_EACH_SIZE(ZERO_SIZE) numScripts(0) {} - FOR_EACH_SIZE(DECL_SIZE) - uint32_t numScripts; // How many ScriptSources come from this file? (It - // can be more than one in XML files that have - // multiple scripts in CDATA sections.) + void add(const ScriptSourceInfo& other) { + FOR_EACH_SIZE(ADD_OTHER_SIZE) + numScripts++; + } + + void subtract(const ScriptSourceInfo& other) { + FOR_EACH_SIZE(SUB_OTHER_SIZE) + numScripts--; + } + + void addToServoSizes(ServoSizes* sizes) const { + FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) + } + + bool isNotable() const { + static const size_t NotabilityThreshold = 16 * 1024; + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N) + return n >= NotabilityThreshold; + } + + FOR_EACH_SIZE(DECL_SIZE) + uint32_t numScripts; // How many ScriptSources come from this file? (It + // can be more than one in XML files that have + // multiple scripts in CDATA sections.) #undef FOR_EACH_SIZE }; @@ -481,483 +447,496 @@ * The only difference between this class and ScriptSourceInfo is that this * class holds a copy of the filename. */ -struct NotableScriptSourceInfo : public ScriptSourceInfo -{ - NotableScriptSourceInfo(); - NotableScriptSourceInfo(const char* filename, const ScriptSourceInfo& info); - NotableScriptSourceInfo(NotableScriptSourceInfo&& info); - NotableScriptSourceInfo& operator=(NotableScriptSourceInfo&& info); +struct NotableScriptSourceInfo : public ScriptSourceInfo { + NotableScriptSourceInfo(); + NotableScriptSourceInfo(const char* filename, const ScriptSourceInfo& info); + NotableScriptSourceInfo(NotableScriptSourceInfo&& info); + NotableScriptSourceInfo& operator=(NotableScriptSourceInfo&& info); - ~NotableScriptSourceInfo() { - js_free(filename_); - } + ~NotableScriptSourceInfo() { js_free(filename_); } - char* filename_; + char* filename_; - private: - NotableScriptSourceInfo(const NotableScriptSourceInfo& info) = delete; + private: + NotableScriptSourceInfo(const NotableScriptSourceInfo& info) = delete; }; /** - * These measurements relate directly to the JSRuntime, and not to zones and - * compartments within it. + * These measurements relate directly to the JSRuntime, and not to zones, + * compartments, and realms within it. */ -struct RuntimeSizes -{ -#define FOR_EACH_SIZE(macro) \ - macro(_, MallocHeap, object) \ - macro(_, MallocHeap, atomsTable) \ - macro(_, MallocHeap, contexts) \ - macro(_, MallocHeap, temporary) \ - macro(_, MallocHeap, interpreterStack) \ - macro(_, MallocHeap, mathCache) \ - macro(_, MallocHeap, sharedImmutableStringsCache) \ - macro(_, MallocHeap, sharedIntlData) \ - macro(_, MallocHeap, uncompressedSourceCache) \ - macro(_, MallocHeap, scriptData) - - RuntimeSizes() - : FOR_EACH_SIZE(ZERO_SIZE) - scriptSourceInfo(), +struct RuntimeSizes { +#define FOR_EACH_SIZE(MACRO) \ + MACRO(_, MallocHeap, object) \ + MACRO(_, MallocHeap, atomsTable) \ + MACRO(_, MallocHeap, atomsMarkBitmaps) \ + MACRO(_, MallocHeap, contexts) \ + MACRO(_, MallocHeap, temporary) \ + MACRO(_, MallocHeap, interpreterStack) \ + MACRO(_, MallocHeap, mathCache) \ + MACRO(_, MallocHeap, sharedImmutableStringsCache) \ + MACRO(_, MallocHeap, sharedIntlData) \ + MACRO(_, MallocHeap, uncompressedSourceCache) \ + MACRO(_, MallocHeap, scriptData) \ + MACRO(_, MallocHeap, tracelogger) + + RuntimeSizes() + : FOR_EACH_SIZE(ZERO_SIZE) scriptSourceInfo(), code(), gc(), - notableScriptSources() - { - allScriptSources = js_new(); - if (!allScriptSources || !allScriptSources->init()) - MOZ_CRASH("oom"); - } - - ~RuntimeSizes() { - // |allScriptSources| is usually deleted and set to nullptr before this - // destructor runs. But there are failure cases due to OOMs that may - // prevent that, so it doesn't hurt to try again here. - js_delete(allScriptSources); - } - - void addToServoSizes(ServoSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) - scriptSourceInfo.addToServoSizes(sizes); - code.addToServoSizes(sizes); - gc.addToServoSizes(sizes); - } - - // The script source measurements in |scriptSourceInfo| are initially for - // all script sources. At the end, if the measurement granularity is - // FineGrained, we subtract the measurements of the notable script sources - // and move them into |notableScriptSources|. - FOR_EACH_SIZE(DECL_SIZE) - ScriptSourceInfo scriptSourceInfo; - CodeSizes code; - GCSizes gc; - - typedef js::HashMap ScriptSourcesHashMap; - - // |allScriptSources| is only used transiently. During the reporting phase - // it is filled with info about every script source in the runtime. It's - // then used to fill in |notableScriptSources| (which actually gets - // reported), and immediately discarded afterwards. - ScriptSourcesHashMap* allScriptSources; - js::Vector notableScriptSources; - -#undef FOR_EACH_SIZE -}; - -struct UnusedGCThingSizes -{ -#define FOR_EACH_SIZE(macro) \ - macro(Other, GCHeapUnused, object) \ - macro(Other, GCHeapUnused, script) \ - macro(Other, GCHeapUnused, lazyScript) \ - macro(Other, GCHeapUnused, shape) \ - macro(Other, GCHeapUnused, baseShape) \ - macro(Other, GCHeapUnused, objectGroup) \ - macro(Other, GCHeapUnused, string) \ - macro(Other, GCHeapUnused, symbol) \ - macro(Other, GCHeapUnused, jitcode) \ - macro(Other, GCHeapUnused, scope) - - UnusedGCThingSizes() - : FOR_EACH_SIZE(ZERO_SIZE) - dummy() - {} + notableScriptSources() { + allScriptSources = js_new(); + if (!allScriptSources || !allScriptSources->init()) MOZ_CRASH("oom"); + } + + ~RuntimeSizes() { + // |allScriptSources| is usually deleted and set to nullptr before this + // destructor runs. But there are failure cases due to OOMs that may + // prevent that, so it doesn't hurt to try again here. + js_delete(allScriptSources); + } + + void addToServoSizes(ServoSizes* sizes) const { + FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) + scriptSourceInfo.addToServoSizes(sizes); + code.addToServoSizes(sizes); + gc.addToServoSizes(sizes); + } + + // The script source measurements in |scriptSourceInfo| are initially for + // all script sources. At the end, if the measurement granularity is + // FineGrained, we subtract the measurements of the notable script sources + // and move them into |notableScriptSources|. + FOR_EACH_SIZE(DECL_SIZE) + ScriptSourceInfo scriptSourceInfo; + CodeSizes code; + GCSizes gc; + + typedef js::HashMap + ScriptSourcesHashMap; + + // |allScriptSources| is only used transiently. During the reporting phase + // it is filled with info about every script source in the runtime. It's + // then used to fill in |notableScriptSources| (which actually gets + // reported), and immediately discarded afterwards. + ScriptSourcesHashMap* allScriptSources; + js::Vector + notableScriptSources; + +#undef FOR_EACH_SIZE +}; + +struct UnusedGCThingSizes { +#define FOR_EACH_SIZE(MACRO) \ + MACRO(Other, GCHeapUnused, object) \ + MACRO(Other, GCHeapUnused, script) \ + MACRO(Other, GCHeapUnused, lazyScript) \ + MACRO(Other, GCHeapUnused, shape) \ + MACRO(Other, GCHeapUnused, baseShape) \ + MACRO(Other, GCHeapUnused, objectGroup) \ + MACRO(Other, GCHeapUnused, string) \ + MACRO(Other, GCHeapUnused, symbol) \ + MACRO(Other, GCHeapUnused, jitcode) \ + MACRO(Other, GCHeapUnused, scope) \ + MACRO(Other, GCHeapUnused, regExpShared) + + UnusedGCThingSizes() : FOR_EACH_SIZE(ZERO_SIZE) dummy() {} + + UnusedGCThingSizes(UnusedGCThingSizes&& other) + : FOR_EACH_SIZE(COPY_OTHER_SIZE) dummy() {} + + void addToKind(JS::TraceKind kind, intptr_t n) { + switch (kind) { + case JS::TraceKind::Object: + object += n; + break; + case JS::TraceKind::String: + string += n; + break; + case JS::TraceKind::Symbol: + symbol += n; + break; + case JS::TraceKind::Script: + script += n; + break; + case JS::TraceKind::Shape: + shape += n; + break; + case JS::TraceKind::BaseShape: + baseShape += n; + break; + 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; + case JS::TraceKind::RegExpShared: + regExpShared += n; + break; + default: + MOZ_CRASH("Bad trace kind for UnusedGCThingSizes"); + } + } + + void addSizes(const UnusedGCThingSizes& other){FOR_EACH_SIZE(ADD_OTHER_SIZE)} + + size_t totalSize() const { + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N) + return n; + } + + void addToTabSizes(JS::TabSizes* sizes) const { + FOR_EACH_SIZE(ADD_TO_TAB_SIZES) + } + + void addToServoSizes(JS::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 +}; + +struct ZoneStats { +#define FOR_EACH_SIZE(MACRO) \ + MACRO(Other, GCHeapUsed, symbolsGCHeap) \ + MACRO(Other, GCHeapAdmin, gcHeapArenaAdmin) \ + MACRO(Other, GCHeapUsed, lazyScriptsGCHeap) \ + MACRO(Other, MallocHeap, lazyScriptsMallocHeap) \ + MACRO(Other, GCHeapUsed, jitCodesGCHeap) \ + MACRO(Other, GCHeapUsed, objectGroupsGCHeap) \ + MACRO(Other, MallocHeap, objectGroupsMallocHeap) \ + MACRO(Other, GCHeapUsed, scopesGCHeap) \ + MACRO(Other, MallocHeap, scopesMallocHeap) \ + MACRO(Other, GCHeapUsed, regExpSharedsGCHeap) \ + MACRO(Other, MallocHeap, regExpSharedsMallocHeap) \ + MACRO(Other, MallocHeap, typePool) \ + MACRO(Other, MallocHeap, regexpZone) \ + MACRO(Other, MallocHeap, jitZone) \ + MACRO(Other, MallocHeap, baselineStubsOptimized) \ + MACRO(Other, MallocHeap, cachedCFG) \ + MACRO(Other, MallocHeap, uniqueIdMap) \ + MACRO(Other, MallocHeap, shapeTables) - UnusedGCThingSizes(UnusedGCThingSizes&& other) - : FOR_EACH_SIZE(COPY_OTHER_SIZE) - dummy() - {} - - void addToKind(JS::TraceKind kind, intptr_t n) { - switch (kind) { - case JS::TraceKind::Object: object += n; break; - case JS::TraceKind::String: string += n; break; - case JS::TraceKind::Symbol: symbol += n; break; - case JS::TraceKind::Script: script += n; break; - case JS::TraceKind::Shape: shape += n; break; - case JS::TraceKind::BaseShape: baseShape += n; break; - 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"); - } - } - - void addSizes(const UnusedGCThingSizes& other) { - FOR_EACH_SIZE(ADD_OTHER_SIZE) - } - - size_t totalSize() const { - size_t n = 0; - FOR_EACH_SIZE(ADD_SIZE_TO_N) - return n; - } - - void addToTabSizes(JS::TabSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_TAB_SIZES) - } - - void addToServoSizes(JS::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 -}; - -struct ZoneStats -{ -#define FOR_EACH_SIZE(macro) \ - macro(Other, GCHeapUsed, symbolsGCHeap) \ - macro(Other, GCHeapAdmin, gcHeapArenaAdmin) \ - macro(Other, GCHeapUsed, lazyScriptsGCHeap) \ - macro(Other, MallocHeap, lazyScriptsMallocHeap) \ - macro(Other, GCHeapUsed, jitCodesGCHeap) \ - macro(Other, GCHeapUsed, objectGroupsGCHeap) \ - macro(Other, MallocHeap, objectGroupsMallocHeap) \ - macro(Other, GCHeapUsed, scopesGCHeap) \ - macro(Other, MallocHeap, scopesMallocHeap) \ - macro(Other, MallocHeap, typePool) \ - macro(Other, MallocHeap, baselineStubsOptimized) \ - macro(Other, MallocHeap, uniqueIdMap) \ - macro(Other, MallocHeap, shapeTables) - - ZoneStats() - : FOR_EACH_SIZE(ZERO_SIZE) - unusedGCThings(), + ZoneStats() + : FOR_EACH_SIZE(ZERO_SIZE) unusedGCThings(), stringInfo(), shapeInfo(), extra(), allStrings(nullptr), notableStrings(), - isTotals(true) - {} + isTotals(true) {} - ZoneStats(ZoneStats&& other) + ZoneStats(ZoneStats&& other) : FOR_EACH_SIZE(COPY_OTHER_SIZE) - unusedGCThings(mozilla::Move(other.unusedGCThings)), + 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)), - isTotals(other.isTotals) - { - other.allStrings = nullptr; - MOZ_ASSERT(!other.isTotals); - } - - ~ZoneStats() { - // |allStrings| is usually deleted and set to nullptr before this - // destructor runs. But there are failure cases due to OOMs that may - // prevent that, so it doesn't hurt to try again here. - js_delete(allStrings); - } - - bool initStrings(JSRuntime* rt); - - void addSizes(const ZoneStats& other) { - MOZ_ASSERT(isTotals); - FOR_EACH_SIZE(ADD_OTHER_SIZE) - unusedGCThings.addSizes(other.unusedGCThings); - stringInfo.add(other.stringInfo); - shapeInfo.add(other.shapeInfo); - } - - size_t sizeOfLiveGCThings() const { - MOZ_ASSERT(isTotals); - size_t n = 0; - FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) - n += stringInfo.sizeOfLiveGCThings(); - n += shapeInfo.sizeOfLiveGCThings(); - return n; - } - - void addToTabSizes(JS::TabSizes* sizes) const { - MOZ_ASSERT(isTotals); - FOR_EACH_SIZE(ADD_TO_TAB_SIZES) - unusedGCThings.addToTabSizes(sizes); - stringInfo.addToTabSizes(sizes); - shapeInfo.addToTabSizes(sizes); - } + isTotals(other.isTotals) { + other.allStrings = nullptr; + MOZ_ASSERT(!other.isTotals); + } + + ~ZoneStats() { + // |allStrings| is usually deleted and set to nullptr before this + // destructor runs. But there are failure cases due to OOMs that may + // prevent that, so it doesn't hurt to try again here. + js_delete(allStrings); + } + + bool initStrings(); + + void addSizes(const ZoneStats& other) { + MOZ_ASSERT(isTotals); + FOR_EACH_SIZE(ADD_OTHER_SIZE) + unusedGCThings.addSizes(other.unusedGCThings); + stringInfo.add(other.stringInfo); + shapeInfo.add(other.shapeInfo); + } + + size_t sizeOfLiveGCThings() const { + MOZ_ASSERT(isTotals); + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) + n += stringInfo.sizeOfLiveGCThings(); + n += shapeInfo.sizeOfLiveGCThings(); + return n; + } + + void addToTabSizes(JS::TabSizes* sizes) const { + MOZ_ASSERT(isTotals); + FOR_EACH_SIZE(ADD_TO_TAB_SIZES) + unusedGCThings.addToTabSizes(sizes); + stringInfo.addToTabSizes(sizes); + shapeInfo.addToTabSizes(sizes); + } + + void addToServoSizes(JS::ServoSizes* sizes) const { + MOZ_ASSERT(isTotals); + 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, + // if the measurement granularity is FineGrained, we subtract the + // measurements of the notable script sources and move them into + // |notableStrings|. + FOR_EACH_SIZE(DECL_SIZE) + UnusedGCThingSizes unusedGCThings; + StringInfo stringInfo; + ShapeInfo shapeInfo; + void* extra; // This field can be used by embedders. + + typedef js::HashMap + StringsHashMap; + + // |allStrings| is only used transiently. During the zone traversal it is + // filled with info about every string in the zone. It's then used to fill + // in |notableStrings| (which actually gets reported), and immediately + // discarded afterwards. + StringsHashMap* allStrings; + js::Vector notableStrings; + bool isTotals; + +#undef FOR_EACH_SIZE +}; + +struct CompartmentStats { +// We assume that |objectsPrivate| is on the malloc heap, but it's not +// actually guaranteed. But for Servo, at least, it's a moot point because +// it doesn't provide an ObjectPrivateVisitor so the value will always be +// zero. +#define FOR_EACH_SIZE(MACRO) \ + MACRO(Private, MallocHeap, objectsPrivate) \ + MACRO(Other, GCHeapUsed, scriptsGCHeap) \ + MACRO(Other, MallocHeap, scriptsMallocHeapData) \ + MACRO(Other, MallocHeap, baselineData) \ + MACRO(Other, MallocHeap, baselineStubsFallback) \ + MACRO(Other, MallocHeap, ionData) \ + MACRO(Other, MallocHeap, typeInferenceTypeScripts) \ + MACRO(Other, MallocHeap, typeInferenceAllocationSiteTables) \ + MACRO(Other, MallocHeap, typeInferenceArrayTypeTables) \ + MACRO(Other, MallocHeap, typeInferenceObjectTypeTables) \ + MACRO(Other, MallocHeap, compartmentObject) \ + MACRO(Other, MallocHeap, compartmentTables) \ + MACRO(Other, MallocHeap, innerViewsTable) \ + MACRO(Other, MallocHeap, lazyArrayBuffersTable) \ + MACRO(Other, MallocHeap, objectMetadataTable) \ + MACRO(Other, MallocHeap, crossCompartmentWrappersTable) \ + MACRO(Other, MallocHeap, savedStacksSet) \ + MACRO(Other, MallocHeap, varNamesSet) \ + MACRO(Other, MallocHeap, nonSyntacticLexicalScopesTable) \ + MACRO(Other, MallocHeap, jitCompartment) \ + MACRO(Other, MallocHeap, privateData) \ + MACRO(Other, MallocHeap, scriptCountsMap) - void addToServoSizes(JS::ServoSizes *sizes) const { - MOZ_ASSERT(isTotals); - 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, - // if the measurement granularity is FineGrained, we subtract the - // measurements of the notable script sources and move them into - // |notableStrings|. - FOR_EACH_SIZE(DECL_SIZE) - UnusedGCThingSizes unusedGCThings; - StringInfo stringInfo; - ShapeInfo shapeInfo; - void* extra; // This field can be used by embedders. - - typedef js::HashMap StringsHashMap; - - // |allStrings| is only used transiently. During the zone traversal it is - // filled with info about every string in the zone. It's then used to fill - // in |notableStrings| (which actually gets reported), and immediately - // discarded afterwards. - StringsHashMap* allStrings; - js::Vector notableStrings; - bool isTotals; - -#undef FOR_EACH_SIZE -}; - -struct CompartmentStats -{ - // We assume that |objectsPrivate| is on the malloc heap, but it's not - // actually guaranteed. But for Servo, at least, it's a moot point because - // it doesn't provide an ObjectPrivateVisitor so the value will always be - // zero. -#define FOR_EACH_SIZE(macro) \ - macro(Private, MallocHeap, objectsPrivate) \ - macro(Other, GCHeapUsed, scriptsGCHeap) \ - macro(Other, MallocHeap, scriptsMallocHeapData) \ - macro(Other, MallocHeap, baselineData) \ - macro(Other, MallocHeap, baselineStubsFallback) \ - macro(Other, MallocHeap, ionData) \ - macro(Other, MallocHeap, typeInferenceTypeScripts) \ - macro(Other, MallocHeap, typeInferenceAllocationSiteTables) \ - macro(Other, MallocHeap, typeInferenceArrayTypeTables) \ - macro(Other, MallocHeap, typeInferenceObjectTypeTables) \ - macro(Other, MallocHeap, compartmentObject) \ - macro(Other, MallocHeap, compartmentTables) \ - macro(Other, MallocHeap, innerViewsTable) \ - macro(Other, MallocHeap, lazyArrayBuffersTable) \ - macro(Other, MallocHeap, objectMetadataTable) \ - macro(Other, MallocHeap, crossCompartmentWrappersTable) \ - macro(Other, MallocHeap, regexpCompartment) \ - macro(Other, MallocHeap, savedStacksSet) \ - macro(Other, MallocHeap, varNamesSet) \ - macro(Other, MallocHeap, nonSyntacticLexicalScopesTable) \ - macro(Other, MallocHeap, jitCompartment) \ - macro(Other, MallocHeap, privateData) - - CompartmentStats() - : FOR_EACH_SIZE(ZERO_SIZE) - classInfo(), + CompartmentStats() + : FOR_EACH_SIZE(ZERO_SIZE) classInfo(), extra(), allClasses(nullptr), notableClasses(), - isTotals(true) - {} + isTotals(true) {} - CompartmentStats(CompartmentStats&& other) + CompartmentStats(CompartmentStats&& other) : FOR_EACH_SIZE(COPY_OTHER_SIZE) - classInfo(mozilla::Move(other.classInfo)), + classInfo(mozilla::Move(other.classInfo)), extra(other.extra), allClasses(other.allClasses), notableClasses(mozilla::Move(other.notableClasses)), - isTotals(other.isTotals) - { - other.allClasses = nullptr; - MOZ_ASSERT(!other.isTotals); - } - - CompartmentStats(const CompartmentStats&) = delete; // disallow copying - - ~CompartmentStats() { - // |allClasses| is usually deleted and set to nullptr before this - // destructor runs. But there are failure cases due to OOMs that may - // prevent that, so it doesn't hurt to try again here. - js_delete(allClasses); - } - - bool initClasses(JSRuntime* rt); - - void addSizes(const CompartmentStats& other) { - MOZ_ASSERT(isTotals); - FOR_EACH_SIZE(ADD_OTHER_SIZE) - classInfo.add(other.classInfo); - } - - size_t sizeOfLiveGCThings() const { - MOZ_ASSERT(isTotals); - size_t n = 0; - FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) - n += classInfo.sizeOfLiveGCThings(); - return n; - } - - void addToTabSizes(TabSizes* sizes) const { - MOZ_ASSERT(isTotals); - FOR_EACH_SIZE(ADD_TO_TAB_SIZES); - classInfo.addToTabSizes(sizes); - } - - void addToServoSizes(ServoSizes *sizes) const { - MOZ_ASSERT(isTotals); - FOR_EACH_SIZE(ADD_TO_SERVO_SIZES); - classInfo.addToServoSizes(sizes); - } - - // The class measurements in |classInfo| are initially for all classes. At - // the end, if the measurement granularity is FineGrained, we subtract the - // measurements of the notable classes and move them into |notableClasses|. - FOR_EACH_SIZE(DECL_SIZE) - ClassInfo classInfo; - void* extra; // This field can be used by embedders. - - typedef js::HashMap ClassesHashMap; - - // These are similar to |allStrings| and |notableStrings| in ZoneStats. - ClassesHashMap* allClasses; - js::Vector notableClasses; - bool isTotals; + isTotals(other.isTotals) { + other.allClasses = nullptr; + MOZ_ASSERT(!other.isTotals); + } + + CompartmentStats(const CompartmentStats&) = delete; // disallow copying + + ~CompartmentStats() { + // |allClasses| is usually deleted and set to nullptr before this + // destructor runs. But there are failure cases due to OOMs that may + // prevent that, so it doesn't hurt to try again here. + js_delete(allClasses); + } + + bool initClasses(); + + void addSizes(const CompartmentStats& other) { + MOZ_ASSERT(isTotals); + FOR_EACH_SIZE(ADD_OTHER_SIZE) + classInfo.add(other.classInfo); + } + + size_t sizeOfLiveGCThings() const { + MOZ_ASSERT(isTotals); + size_t n = 0; + FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING) + n += classInfo.sizeOfLiveGCThings(); + return n; + } + + void addToTabSizes(TabSizes* sizes) const { + MOZ_ASSERT(isTotals); + FOR_EACH_SIZE(ADD_TO_TAB_SIZES); + classInfo.addToTabSizes(sizes); + } + + void addToServoSizes(ServoSizes* sizes) const { + MOZ_ASSERT(isTotals); + FOR_EACH_SIZE(ADD_TO_SERVO_SIZES); + classInfo.addToServoSizes(sizes); + } + + // The class measurements in |classInfo| are initially for all classes. At + // the end, if the measurement granularity is FineGrained, we subtract the + // measurements of the notable classes and move them into |notableClasses|. + FOR_EACH_SIZE(DECL_SIZE) + ClassInfo classInfo; + void* extra; // This field can be used by embedders. + + typedef js::HashMap + ClassesHashMap; + + // These are similar to |allStrings| and |notableStrings| in ZoneStats. + ClassesHashMap* allClasses; + js::Vector notableClasses; + bool isTotals; #undef FOR_EACH_SIZE }; -typedef js::Vector CompartmentStatsVector; +typedef js::Vector + CompartmentStatsVector; typedef js::Vector ZoneStatsVector; -struct RuntimeStats -{ - // |gcHeapChunkTotal| is ignored because it's the sum of all the other - // values. |gcHeapGCThings| is ignored because it's the sum of some of the - // values from the zones and compartments. Both of those values are not - // reported directly, but are just present for sanity-checking other - // values. -#define FOR_EACH_SIZE(macro) \ - macro(_, Ignore, gcHeapChunkTotal) \ - macro(_, GCHeapDecommitted, gcHeapDecommittedArenas) \ - macro(_, GCHeapUnused, gcHeapUnusedChunks) \ - macro(_, GCHeapUnused, gcHeapUnusedArenas) \ - macro(_, GCHeapAdmin, gcHeapChunkAdmin) \ - macro(_, Ignore, gcHeapGCThings) - - explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf) - : FOR_EACH_SIZE(ZERO_SIZE) - runtime(), +struct RuntimeStats { +// |gcHeapChunkTotal| is ignored because it's the sum of all the other +// values. |gcHeapGCThings| is ignored because it's the sum of some of the +// values from the zones and compartments. Both of those values are not +// reported directly, but are just present for sanity-checking other +// values. +#define FOR_EACH_SIZE(MACRO) \ + MACRO(_, Ignore, gcHeapChunkTotal) \ + MACRO(_, GCHeapDecommitted, gcHeapDecommittedArenas) \ + MACRO(_, GCHeapUnused, gcHeapUnusedChunks) \ + MACRO(_, GCHeapUnused, gcHeapUnusedArenas) \ + MACRO(_, GCHeapAdmin, gcHeapChunkAdmin) \ + MACRO(_, Ignore, gcHeapGCThings) + + explicit RuntimeStats(mozilla::MallocSizeOf mallocSizeOf) + : FOR_EACH_SIZE(ZERO_SIZE) runtime(), cTotals(), zTotals(), compartmentStatsVector(), zoneStatsVector(), currZoneStats(nullptr), - mallocSizeOf_(mallocSizeOf) - {} + mallocSizeOf_(mallocSizeOf) {} - // Here's a useful breakdown of the GC heap. - // - // - rtStats.gcHeapChunkTotal - // - decommitted bytes - // - rtStats.gcHeapDecommittedArenas (decommitted arenas in non-empty chunks) - // - unused bytes - // - rtStats.gcHeapUnusedChunks (empty chunks) - // - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks) - // - rtStats.zTotals.unusedGCThings.totalSize() (empty GC thing slots within non-empty arenas) - // - used bytes - // - rtStats.gcHeapChunkAdmin - // - rtStats.zTotals.gcHeapArenaAdmin - // - rtStats.gcHeapGCThings (in-use GC things) - // == rtStats.zTotals.sizeOfLiveGCThings() + rtStats.cTotals.sizeOfLiveGCThings() - // - // It's possible that some arenas in empty chunks may be decommitted, but - // we don't count those under rtStats.gcHeapDecommittedArenas because (a) - // it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a - // multiple of the chunk size, which is good. - - void addToServoSizes(ServoSizes *sizes) const { - FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) - runtime.addToServoSizes(sizes); - } + // Here's a useful breakdown of the GC heap. + // + // - rtStats.gcHeapChunkTotal + // - decommitted bytes + // - rtStats.gcHeapDecommittedArenas + // (decommitted arenas in non-empty chunks) + // - unused bytes + // - rtStats.gcHeapUnusedChunks (empty chunks) + // - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks) + // - rtStats.zTotals.unusedGCThings.totalSize() + // (empty GC thing slots within non-empty arenas) + // - used bytes + // - rtStats.gcHeapChunkAdmin + // - rtStats.zTotals.gcHeapArenaAdmin + // - rtStats.gcHeapGCThings (in-use GC things) + // == (rtStats.zTotals.sizeOfLiveGCThings() + + // rtStats.cTotals.sizeOfLiveGCThings()) + // + // It's possible that some arenas in empty chunks may be decommitted, but + // we don't count those under rtStats.gcHeapDecommittedArenas because (a) + // it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a + // multiple of the chunk size, which is good. + + void addToServoSizes(ServoSizes* sizes) const { + FOR_EACH_SIZE(ADD_TO_SERVO_SIZES) + runtime.addToServoSizes(sizes); + } - FOR_EACH_SIZE(DECL_SIZE) + FOR_EACH_SIZE(DECL_SIZE) - RuntimeSizes runtime; + RuntimeSizes runtime; - CompartmentStats cTotals; // The sum of this runtime's compartments' measurements. - ZoneStats zTotals; // The sum of this runtime's zones' measurements. + CompartmentStats + cTotals; // The sum of this runtime's compartments' measurements. + ZoneStats zTotals; // The sum of this runtime's zones' measurements. - CompartmentStatsVector compartmentStatsVector; - ZoneStatsVector zoneStatsVector; + CompartmentStatsVector compartmentStatsVector; + ZoneStatsVector zoneStatsVector; - ZoneStats* currZoneStats; + ZoneStats* currZoneStats; - mozilla::MallocSizeOf mallocSizeOf_; + mozilla::MallocSizeOf mallocSizeOf_; - virtual void initExtraCompartmentStats(JSCompartment* c, CompartmentStats* cstats) = 0; - virtual void initExtraZoneStats(JS::Zone* zone, ZoneStats* zstats) = 0; + virtual void initExtraCompartmentStats(JSCompartment* c, + CompartmentStats* cstats) = 0; + virtual void initExtraZoneStats(JS::Zone* zone, ZoneStats* zstats) = 0; #undef FOR_EACH_SIZE }; -class ObjectPrivateVisitor -{ - public: - // Within CollectRuntimeStats, this method is called for each JS object - // that has an nsISupports pointer. - virtual size_t sizeOfIncludingThis(nsISupports* aSupports) = 0; +class ObjectPrivateVisitor { + public: + // Within CollectRuntimeStats, this method is called for each JS object + // that has an nsISupports pointer. + virtual size_t sizeOfIncludingThis(nsISupports* aSupports) = 0; - // A callback that gets a JSObject's nsISupports pointer, if it has one. - // Note: this function does *not* addref |iface|. - typedef bool(*GetISupportsFun)(JSObject* obj, nsISupports** iface); - GetISupportsFun getISupports_; + // A callback that gets a JSObject's nsISupports pointer, if it has one. + // Note: this function does *not* addref |iface|. + typedef bool (*GetISupportsFun)(JSObject* obj, nsISupports** iface); + GetISupportsFun getISupports_; - explicit ObjectPrivateVisitor(GetISupportsFun getISupports) - : getISupports_(getISupports) - {} + explicit ObjectPrivateVisitor(GetISupportsFun getISupports) + : getISupports_(getISupports) {} }; -extern JS_PUBLIC_API(bool) -CollectRuntimeStats(JSContext* cx, RuntimeStats* rtStats, ObjectPrivateVisitor* opv, bool anonymize); +extern JS_PUBLIC_API bool CollectRuntimeStats(JSContext* cx, + RuntimeStats* rtStats, + ObjectPrivateVisitor* opv, + bool anonymize); + +extern JS_PUBLIC_API size_t SystemCompartmentCount(JSContext* cx); -extern JS_PUBLIC_API(size_t) -SystemCompartmentCount(JSContext* cx); +extern JS_PUBLIC_API size_t UserCompartmentCount(JSContext* cx); -extern JS_PUBLIC_API(size_t) -UserCompartmentCount(JSContext* cx); +extern JS_PUBLIC_API size_t PeakSizeOfTemporary(const JSContext* cx); -extern JS_PUBLIC_API(size_t) -PeakSizeOfTemporary(const JSContext* cx); +extern JS_PUBLIC_API bool AddSizeOfTab(JSContext* cx, JS::HandleObject obj, + mozilla::MallocSizeOf mallocSizeOf, + ObjectPrivateVisitor* opv, + TabSizes* sizes); -extern JS_PUBLIC_API(bool) -AddSizeOfTab(JSContext* cx, JS::HandleObject obj, mozilla::MallocSizeOf mallocSizeOf, - ObjectPrivateVisitor* opv, TabSizes* sizes); +extern JS_PUBLIC_API bool AddServoSizeOf(JSContext* cx, + mozilla::MallocSizeOf mallocSizeOf, + ObjectPrivateVisitor* opv, + ServoSizes* sizes); -extern JS_PUBLIC_API(bool) -AddServoSizeOf(JSContext* cx, mozilla::MallocSizeOf mallocSizeOf, - ObjectPrivateVisitor *opv, ServoSizes *sizes); +extern JS_PUBLIC_API void CollectTraceLoggerStateStats(RuntimeStats* rtStats); -} // namespace JS +} // namespace JS #undef DECL_SIZE #undef ZERO_SIZE Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Principals.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Principals.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Principals.h @@ -18,68 +18,65 @@ #include "js/StructuredClone.h" namespace js { - struct JS_PUBLIC_API(PerformanceGroup); -} // namespace js +struct JS_PUBLIC_API PerformanceGroup; +} // namespace js struct JSPrincipals { - /* Don't call "destroy"; use reference counting macros below. */ - mozilla::Atomic refcount; + /* Don't call "destroy"; use reference counting macros below. */ + mozilla::Atomic refcount; #ifdef JS_DEBUG - /* A helper to facilitate principals debugging. */ - uint32_t debugToken; + /* A helper to facilitate principals debugging. */ + uint32_t debugToken; #endif - JSPrincipals() : refcount(0) {} + JSPrincipals() : refcount(0) {} - void setDebugToken(uint32_t token) { -# ifdef JS_DEBUG - debugToken = token; -# endif - } - - /* - * Write the principals with the given |writer|. Return false on failure, - * true on success. - */ - virtual bool write(JSContext* cx, JSStructuredCloneWriter* writer) = 0; - - /* - * This is not defined by the JS engine but should be provided by the - * embedding. - */ - JS_PUBLIC_API(void) dump(); + void setDebugToken(uint32_t token) { +#ifdef JS_DEBUG + debugToken = token; +#endif + } + + /* + * Write the principals with the given |writer|. Return false on failure, + * true on success. + */ + virtual bool write(JSContext* cx, JSStructuredCloneWriter* writer) = 0; + + /* + * This is not defined by the JS engine but should be provided by the + * embedding. + */ + JS_PUBLIC_API void dump(); }; -extern JS_PUBLIC_API(void) -JS_HoldPrincipals(JSPrincipals* principals); +extern JS_PUBLIC_API void JS_HoldPrincipals(JSPrincipals* principals); -extern JS_PUBLIC_API(void) -JS_DropPrincipals(JSContext* cx, JSPrincipals* principals); +extern JS_PUBLIC_API void JS_DropPrincipals(JSContext* cx, + JSPrincipals* principals); // Return whether the first principal subsumes the second. The exact meaning of // 'subsumes' is left up to the browser. Subsumption is checked inside the JS // engine when determining, e.g., which stack frames to display in a backtrace. -typedef bool -(* JSSubsumesOp)(JSPrincipals* first, JSPrincipals* second); +typedef bool (*JSSubsumesOp)(JSPrincipals* first, JSPrincipals* second); /* * Used to check if a CSP instance wants to disable eval() and friends. * See js_CheckCSPPermitsJSAction() in jsobj. */ -typedef bool -(* JSCSPEvalChecker)(JSContext* cx); +typedef bool (*JSCSPEvalChecker)(JSContext* cx); struct JSSecurityCallbacks { - JSCSPEvalChecker contentSecurityPolicyAllows; - JSSubsumesOp subsumes; + JSCSPEvalChecker contentSecurityPolicyAllows; + JSSubsumesOp subsumes; }; -extern JS_PUBLIC_API(void) -JS_SetSecurityCallbacks(JSContext* cx, const JSSecurityCallbacks* callbacks); +extern JS_PUBLIC_API void JS_SetSecurityCallbacks( + JSContext* cx, const JSSecurityCallbacks* callbacks); -extern JS_PUBLIC_API(const JSSecurityCallbacks*) -JS_GetSecurityCallbacks(JSContext* cx); +extern JS_PUBLIC_API const JSSecurityCallbacks* JS_GetSecurityCallbacks( + JSContext* cx); /* * Code running with "trusted" principals will be given a deeper stack @@ -93,19 +90,18 @@ * 'cx', JS_SetTrustedPrincipals must be called again, passing nullptr for * 'prin'. */ -extern JS_PUBLIC_API(void) -JS_SetTrustedPrincipals(JSContext* cx, JSPrincipals* prin); +extern JS_PUBLIC_API void JS_SetTrustedPrincipals(JSContext* cx, + JSPrincipals* prin); -typedef void -(* JSDestroyPrincipalsOp)(JSPrincipals* principals); +typedef void (*JSDestroyPrincipalsOp)(JSPrincipals* principals); /* * Initialize the callback that is called to destroy JSPrincipals instance * when its reference counter drops to zero. The initialization can be done * only once per JS runtime. */ -extern JS_PUBLIC_API(void) -JS_InitDestroyPrincipalsCallback(JSContext* cx, JSDestroyPrincipalsOp destroyPrincipals); +extern JS_PUBLIC_API void JS_InitDestroyPrincipalsCallback( + JSContext* cx, JSDestroyPrincipalsOp destroyPrincipals); /* * Read a JSPrincipals instance from the given |reader| and initialize the out @@ -118,15 +114,15 @@ * JSPrincipals instance, the JSReadPrincipalsOp must increment the refcount of * the resulting JSPrincipals on behalf of the caller. */ -using JSReadPrincipalsOp = bool (*)(JSContext* cx, JSStructuredCloneReader* reader, +using JSReadPrincipalsOp = bool (*)(JSContext* cx, + JSStructuredCloneReader* reader, JSPrincipals** outPrincipals); /* * Initialize the callback that is called to read JSPrincipals instances from a * buffer. The initialization can be done only once per JS runtime. */ -extern JS_PUBLIC_API(void) -JS_InitReadPrincipalsCallback(JSContext* cx, JSReadPrincipalsOp read); - +extern JS_PUBLIC_API void JS_InitReadPrincipalsCallback( + JSContext* cx, JSReadPrincipalsOp read); -#endif /* js_Principals_h */ +#endif /* js_Principals_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Printf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Printf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Printf.h @@ -0,0 +1,34 @@ +/* -*- 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_Printf_h +#define js_Printf_h + +#include "mozilla/Printf.h" + +#include + +#include "jstypes.h" +#include "js/Utility.h" + +/* Wrappers for mozilla::Smprintf and friends that are used throughout + JS. */ + +extern JS_PUBLIC_API JS::UniqueChars JS_smprintf(const char* fmt, ...) + MOZ_FORMAT_PRINTF(1, 2); + +extern JS_PUBLIC_API JS::UniqueChars JS_sprintf_append(JS::UniqueChars&& last, + const char* fmt, ...) + MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API JS::UniqueChars JS_vsmprintf(const char* fmt, va_list ap) + MOZ_FORMAT_PRINTF(1, 0); +extern JS_PUBLIC_API JS::UniqueChars JS_vsprintf_append(JS::UniqueChars&& last, + const char* fmt, + va_list ap) + MOZ_FORMAT_PRINTF(2, 0); + +#endif /* js_Printf_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/ProfilingFrameIterator.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/ProfilingFrameIterator.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/ProfilingFrameIterator.h @@ -7,29 +7,24 @@ #ifndef js_ProfilingFrameIterator_h #define js_ProfilingFrameIterator_h -#include "mozilla/Alignment.h" +#include "mozilla/Attributes.h" #include "mozilla/Maybe.h" -#include "jsbytecode.h" #include "js/GCAPI.h" #include "js/TypeDecls.h" #include "js/Utility.h" -struct JSContext; -struct JSRuntime; -class JSScript; - namespace js { - class Activation; - namespace jit { - class JitActivation; - class JitProfilingFrameIterator; - class JitcodeGlobalEntry; - } // namespace jit - namespace wasm { - class ProfilingFrameIterator; - } // namespace wasm -} // namespace js +class Activation; +namespace jit { +class JitActivation; +class JSJitProfilingFrameIterator; +class JitcodeGlobalEntry; +} // namespace jit +namespace wasm { +class ProfilingFrameIterator; +} // namespace wasm +} // namespace js namespace JS { @@ -37,170 +32,199 @@ struct ForEachTrackedOptimizationTypeInfoOp; // This iterator can be used to walk the stack of a thread suspended at an -// arbitrary pc. To provide acurate results, profiling must have been enabled +// arbitrary pc. To provide accurate results, profiling must have been enabled // (via EnableRuntimeProfilingStack) before executing the callstack being // unwound. // // Note that the caller must not do anything that could cause GC to happen while // the iterator is alive, since this could invalidate Ion code and cause its // contents to become out of date. -class JS_PUBLIC_API(ProfilingFrameIterator) -{ - JSRuntime* rt_; - uint32_t sampleBufferGen_; - js::Activation* activation_; - - // When moving past a JitActivation, we need to save the prevJitTop - // from it to use as the exit-frame pointer when the next caller jit - // activation (if any) comes around. - void* savedPrevJitTop_; - - JS::AutoCheckCannotGC nogc_; - - static const unsigned StorageSpace = 8 * sizeof(void*); - mozilla::AlignedStorage storage_; - js::wasm::ProfilingFrameIterator& wasmIter() { - MOZ_ASSERT(!done()); - MOZ_ASSERT(isWasm()); - return *reinterpret_cast(storage_.addr()); - } - const js::wasm::ProfilingFrameIterator& wasmIter() const { - MOZ_ASSERT(!done()); - MOZ_ASSERT(isWasm()); - return *reinterpret_cast(storage_.addr()); - } +class MOZ_NON_PARAM JS_PUBLIC_API ProfilingFrameIterator { + public: + enum class Kind : bool { JSJit, Wasm }; + + private: + JSContext* cx_; + mozilla::Maybe samplePositionInProfilerBuffer_; + js::Activation* activation_; + Kind kind_; + + static const unsigned StorageSpace = 8 * sizeof(void*); + alignas(void*) unsigned char storage_[StorageSpace]; + + void* storage() { return storage_; } + const void* storage() const { return storage_; } + + js::wasm::ProfilingFrameIterator& wasmIter() { + MOZ_ASSERT(!done()); + MOZ_ASSERT(isWasm()); + return *static_cast(storage()); + } + const js::wasm::ProfilingFrameIterator& wasmIter() const { + MOZ_ASSERT(!done()); + MOZ_ASSERT(isWasm()); + return *static_cast(storage()); + } + + js::jit::JSJitProfilingFrameIterator& jsJitIter() { + MOZ_ASSERT(!done()); + MOZ_ASSERT(isJSJit()); + return *static_cast(storage()); + } + + const js::jit::JSJitProfilingFrameIterator& jsJitIter() const { + MOZ_ASSERT(!done()); + MOZ_ASSERT(isJSJit()); + return *static_cast(storage()); + } + + void settleFrames(); + void settle(); + + public: + struct RegisterState { + RegisterState() : pc(nullptr), sp(nullptr), fp(nullptr), lr(nullptr) {} + void* pc; + void* sp; + void* fp; + void* lr; + }; + + ProfilingFrameIterator( + JSContext* cx, const RegisterState& state, + const mozilla::Maybe& samplePositionInProfilerBuffer = + mozilla::Nothing()); + ~ProfilingFrameIterator(); + void operator++(); + bool done() const { return !activation_; } + + // Assuming the stack grows down (we do), the return value: + // - always points into the stack + // - is weakly monotonically increasing (may be equal for successive frames) + // - will compare greater than newer native and psuedo-stack frame addresses + // and less than older native and psuedo-stack frame addresses + void* stackAddress() const; + + enum FrameKind { Frame_Baseline, Frame_Ion, Frame_Wasm }; + + struct Frame { + FrameKind kind; + void* stackAddress; + void* returnAddress; + void* activation; + const char* label; + } JS_HAZ_GC_INVALIDATED; + + bool isWasm() const; + bool isJSJit() const; + + uint32_t extractStack(Frame* frames, uint32_t offset, uint32_t end) const; + + mozilla::Maybe getPhysicalFrameWithoutLabel() const; + + private: + mozilla::Maybe getPhysicalFrameAndEntry( + js::jit::JitcodeGlobalEntry* entry) const; + + void iteratorConstruct(const RegisterState& state); + void iteratorConstruct(); + void iteratorDestroy(); + bool iteratorDone(); +} JS_HAZ_GC_INVALIDATED; - js::jit::JitProfilingFrameIterator& jitIter() { - MOZ_ASSERT(!done()); - MOZ_ASSERT(isJit()); - return *reinterpret_cast(storage_.addr()); - } +JS_FRIEND_API bool IsProfilingEnabledForContext(JSContext* cx); - const js::jit::JitProfilingFrameIterator& jitIter() const { - MOZ_ASSERT(!done()); - MOZ_ASSERT(isJit()); - return *reinterpret_cast(storage_.addr()); - } +/** + * After each sample run, this method should be called with the current buffer + * position at which the buffer contents start. This will update the + * corresponding field on the JSRuntime. + * + * See the field |profilerSampleBufferRangeStart| on JSRuntime for documentation + * about what this value is used for. + */ +JS_FRIEND_API void SetJSContextProfilerSampleBufferRangeStart( + JSContext* cx, uint64_t rangeStart); - void settle(); +class ProfiledFrameRange; - bool hasSampleBufferGen() const { - return sampleBufferGen_ != UINT32_MAX; - } +// A handle to the underlying JitcodeGlobalEntry, so as to avoid repeated +// lookups on JitcodeGlobalTable. +class MOZ_STACK_CLASS ProfiledFrameHandle { + friend class ProfiledFrameRange; + + JSRuntime* rt_; + js::jit::JitcodeGlobalEntry& entry_; + void* addr_; + void* canonicalAddr_; + const char* label_; + uint32_t depth_; + mozilla::Maybe optsIndex_; + + ProfiledFrameHandle(JSRuntime* rt, js::jit::JitcodeGlobalEntry& entry, + void* addr, const char* label, uint32_t depth); + + void updateHasTrackedOptimizations(); + + public: + const char* label() const { return label_; } + uint32_t depth() const { return depth_; } + bool hasTrackedOptimizations() const { return optsIndex_.isSome(); } + void* canonicalAddress() const { return canonicalAddr_; } + + JS_PUBLIC_API ProfilingFrameIterator::FrameKind frameKind() const; + JS_PUBLIC_API void forEachOptimizationAttempt( + ForEachTrackedOptimizationAttemptOp& op, JSScript** scriptOut, + jsbytecode** pcOut) const; - public: - struct RegisterState - { - RegisterState() : pc(nullptr), sp(nullptr), lr(nullptr) {} - void* pc; - void* sp; - void* lr; - }; - - ProfilingFrameIterator(JSContext* cx, const RegisterState& state, - uint32_t sampleBufferGen = UINT32_MAX); - ~ProfilingFrameIterator(); - void operator++(); - bool done() const { return !activation_; } - - // Assuming the stack grows down (we do), the return value: - // - always points into the stack - // - is weakly monotonically increasing (may be equal for successive frames) - // - will compare greater than newer native and psuedo-stack frame addresses - // and less than older native and psuedo-stack frame addresses - void* stackAddress() const; - - enum FrameKind - { - Frame_Baseline, - Frame_Ion, - Frame_Wasm - }; - - struct Frame - { - FrameKind kind; - void* stackAddress; - void* returnAddress; - void* activation; - UniqueChars label; - }; - - bool isWasm() const; - bool isJit() const; - - uint32_t extractStack(Frame* frames, uint32_t offset, uint32_t end) const; - - mozilla::Maybe getPhysicalFrameWithoutLabel() const; - - private: - mozilla::Maybe getPhysicalFrameAndEntry(js::jit::JitcodeGlobalEntry* entry) const; - - void iteratorConstruct(const RegisterState& state); - void iteratorConstruct(); - void iteratorDestroy(); - bool iteratorDone(); + JS_PUBLIC_API void forEachOptimizationTypeInfo( + ForEachTrackedOptimizationTypeInfoOp& op) const; }; -JS_FRIEND_API(bool) -IsProfilingEnabledForContext(JSContext* cx); - -/** - * After each sample run, this method should be called with the latest sample - * buffer generation, and the lapCount. It will update corresponding fields on - * JSRuntime. - * - * See fields |profilerSampleBufferGen|, |profilerSampleBufferLapCount| on - * JSRuntime for documentation about what these values are used for. - */ -JS_FRIEND_API(void) -UpdateJSContextProfilerSampleBufferGen(JSContext* cx, uint32_t generation, - uint32_t lapCount); - -struct ForEachProfiledFrameOp -{ - // A handle to the underlying JitcodeGlobalEntry, so as to avoid repeated - // lookups on JitcodeGlobalTable. - class MOZ_STACK_CLASS FrameHandle - { - friend JS_PUBLIC_API(void) ForEachProfiledFrame(JSContext* cx, void* addr, - ForEachProfiledFrameOp& op); - - JSRuntime* rt_; - js::jit::JitcodeGlobalEntry& entry_; - void* addr_; - void* canonicalAddr_; - const char* label_; - uint32_t depth_; - mozilla::Maybe optsIndex_; - - FrameHandle(JSRuntime* rt, js::jit::JitcodeGlobalEntry& entry, void* addr, - const char* label, uint32_t depth); - - void updateHasTrackedOptimizations(); - - public: - const char* label() const { return label_; } - uint32_t depth() const { return depth_; } - bool hasTrackedOptimizations() const { return optsIndex_.isSome(); } - void* canonicalAddress() const { return canonicalAddr_; } - - 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; - }; +class ProfiledFrameRange { + public: + class Iter final { + public: + Iter(const ProfiledFrameRange& range, uint32_t index) + : range_(range), index_(index) {} + + JS_PUBLIC_API ProfiledFrameHandle operator*() const; + + // Provide the bare minimum of iterator methods that are needed for + // C++ ranged for loops. + Iter& operator++() { + ++index_; + return *this; + } + bool operator==(const Iter& rhs) { return index_ == rhs.index_; } + bool operator!=(const Iter& rhs) { return !(*this == rhs); } - // Called once per frame. - virtual void operator()(const FrameHandle& frame) = 0; + private: + const ProfiledFrameRange& range_; + uint32_t index_; + }; + + Iter begin() const { return Iter(*this, 0); } + Iter end() const { return Iter(*this, depth_); } + + private: + friend JS_PUBLIC_API ProfiledFrameRange GetProfiledFrames(JSContext* cx, + void* addr); + + ProfiledFrameRange(JSRuntime* rt, void* addr, + js::jit::JitcodeGlobalEntry* entry) + : rt_(rt), addr_(addr), entry_(entry), depth_(0) {} + + JSRuntime* rt_; + void* addr_; + js::jit::JitcodeGlobalEntry* entry_; + // Assume maximum inlining depth is <64 + const char* labels_[64]; + uint32_t depth_; }; -JS_PUBLIC_API(void) -ForEachProfiledFrame(JSContext* cx, void* addr, ForEachProfiledFrameOp& op); +// Returns a range that can be iterated over using C++ ranged for loops. +JS_PUBLIC_API ProfiledFrameRange GetProfiledFrames(JSContext* cx, void* addr); -} // namespace JS +} // namespace JS -#endif /* js_ProfilingFrameIterator_h */ +#endif /* js_ProfilingFrameIterator_h */ 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 @@ -7,202 +7,419 @@ #ifndef js_ProfilingStack_h #define js_ProfilingStack_h -#include "jsbytecode.h" +#include +#include + #include "jstypes.h" -#include "js/TypeDecls.h" +#include "js/TypeDecls.h" #include "js/Utility.h" -struct JSRuntime; class JSTracer; +class PseudoStack; + +// This file defines the classes PseudoStack and ProfileEntry. +// The PseudoStack manages an array of ProfileEntries. +// Usage: +// +// PseudoStack* pseudoStack = ...; +// +// // For CPP stack frames: +// pseudoStack->pushCppFrame(...); +// // Execute some code. When finished, pop the entry: +// pseudoStack->pop(); +// +// // For JS stack frames: +// pseudoStack->pushJSFrame(...); +// // Execute some code. When finished, pop the entry: +// pseudoStack->pop(); +// +// +// Concurrency considerations +// +// A thread's pseudo stack (and the entries inside it) is only modified by +// that thread. However, the pseudo stack can be *read* by a different thread, +// the sampler thread: Whenever the profiler wants to sample a given thread A, +// the following happens: +// (1) Thread A is suspended. +// (2) The sampler thread (thread S) reads the PseudoStack of thread A, +// including all ProfileEntries that are currently in that stack +// (pseudoStack->entries[0..pseudoStack->stackSize()]). +// (3) Thread A is resumed. +// +// Thread suspension is achieved using platform-specific APIs; refer to each +// platform's Sampler::SuspendAndSampleAndResumeThread implementation in +// platform-*.cpp for details. +// +// When the thread is suspended, the values in pseudoStack->stackPointer and in +// the entry range pseudoStack->entries[0..pseudoStack->stackPointer] need to +// be in a consistent state, so that thread S does not read partially- +// constructed profile entries. More specifically, we have two requirements: +// (1) When adding a new entry at the top of the stack, its ProfileEntry data +// needs to be put in place *before* the stackPointer is incremented, and +// the compiler + CPU need to know that this order matters. +// (2) When popping an entry from the stack and then preparing the +// ProfileEntry data for the next frame that is about to be pushed, the +// decrement of the stackPointer in pop() needs to happen *before* the +// ProfileEntry for the new frame is being popuplated, and the compiler + +// CPU need to know that this order matters. +// +// We can express the relevance of these orderings in multiple ways. +// Option A is to make stackPointer an atomic with SequentiallyConsistent +// memory ordering. This would ensure that no writes in thread A would be +// reordered across any writes to stackPointer, which satisfies requirements +// (1) and (2) at the same time. Option A is the simplest. +// Option B is to use ReleaseAcquire memory ordering both for writes to +// stackPointer *and* for writes to ProfileEntry fields. Release-stores ensure +// that all writes that happened *before this write in program order* are not +// reordered to happen after this write. ReleaseAcquire ordering places no +// requirements on the ordering of writes that happen *after* this write in +// program order. +// Using release-stores for writes to stackPointer expresses requirement (1), +// and using release-stores for writes to the ProfileEntry fields expresses +// requirement (2). +// +// Option B is more complicated than option A, but has much better performance +// on x86/64: In a microbenchmark run on a Macbook Pro from 2017, switching +// from option A to option B reduced the overhead of pushing+popping a +// ProfileEntry by 10 nanoseconds. +// On x86/64, release-stores require no explicit hardware barriers or lock +// instructions. +// On ARM/64, option B may be slower than option A, because the compiler will +// generate hardware barriers for every single release-store instead of just +// for the writes to stackPointer. However, the actual performance impact of +// this has not yet been measured on ARM, so we're currently using option B +// everywhere. This is something that we may want to change in the future once +// we've done measurements. namespace js { // A call stack can be specified to the JS engine such that all JS entry/exits // to functions push/pop an entry to/from the specified stack. // -// For more detailed information, see vm/SPSProfiler.h. +// For more detailed information, see vm/GeckoProfiler.h. // -class ProfileEntry -{ - // All fields are marked volatile to prevent the compiler from re-ordering - // instructions. Namely this sequence: - // - // entry[size] = ...; - // size++; - // - // If the size modification were somehow reordered before the stores, then - // if a sample were taken it would be examining bogus information. - // - // A ProfileEntry represents both a C++ profile entry and a JS one. - - // Descriptive string of this entry. - const char * volatile string; - - // Stack pointer for non-JS entries, the script pointer otherwise. - void * volatile spOrScript; - - // Line number for non-JS entries, the bytecode offset otherwise. - 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 : 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 - // a JS or CPP frame with `initJsFrame` or `initCppFrame` respectively. - IS_CPP_ENTRY = 0x01, - - // Indicate that copying the frame label is not necessary when taking a - // sample of the pseudostack. - FRAME_LABEL_COPY = 0x02, - - // This ProfileEntry is a dummy entry indicating the start of a run - // of JS pseudostack entries. - BEGIN_PSEUDO_JS = 0x04, - - // This flag is used to indicate that an interpreter JS entry has OSR-ed - // into baseline. - OSR = 0x08, - - // Union of all flags. - ALL = IS_CPP_ENTRY|FRAME_LABEL_COPY|BEGIN_PSEUDO_JS|OSR, - - // Mask for removing all flags except the category information. - CATEGORY_MASK = ~ALL - }; - - // Keep these in sync with devtools/client/performance/modules/categories.js - enum class Category : uint32_t { - OTHER = 0x10, - CSS = 0x20, - JS = 0x40, - GC = 0x80, - CC = 0x100, - NETWORK = 0x200, - GRAPHICS = 0x400, - STORAGE = 0x800, - EVENTS = 0x1000, - - FIRST = OTHER, - LAST = EVENTS - }; - - static_assert((static_cast(Category::FIRST) & Flags::ALL) == 0, - "The category bitflags should not intersect with the other flags!"); - - // All of these methods are marked with the 'volatile' keyword because SPS's - // representation of the stack is stored such that all ProfileEntry - // instances are volatile. These methods would not be available unless they - // were marked as volatile as well. - - bool isCpp() const volatile { return hasFlag(IS_CPP_ENTRY); } - bool isJs() const volatile { return !isCpp(); } - - bool isCopyLabel() const volatile { return hasFlag(FRAME_LABEL_COPY); } - - void setLabel(const char* aString) volatile { string = aString; } - const char* label() const volatile { return string; } - - void initJsFrame(JSScript* aScript, jsbytecode* aPc) volatile { - flags_ = 0; - spOrScript = aScript; - setPC(aPc); - } - void initCppFrame(void* aSp, uint32_t aLine) volatile { - flags_ = IS_CPP_ENTRY; - spOrScript = aSp; - lineOrPcOffset = static_cast(aLine); - } +class ProfileEntry { + // A ProfileEntry represents either a C++ profile entry or a JS one. - void setFlag(uint32_t flag) volatile { - MOZ_ASSERT(flag != IS_CPP_ENTRY); - flags_ |= flag; - } - void unsetFlag(uint32_t flag) volatile { - MOZ_ASSERT(flag != IS_CPP_ENTRY); - flags_ &= ~flag; - } - bool hasFlag(uint32_t flag) const volatile { - return bool(flags_ & flag); - } + // WARNING WARNING WARNING + // + // All the fields below are Atomic<...,ReleaseAcquire>. This is needed so + // that writes to these fields are release-writes, which ensures that + // earlier writes in this thread don't get reordered after the writes to + // these fields. In particular, the decrement of the stack pointer in + // PseudoStack::pop() is a write that *must* happen before the values in + // this ProfileEntry are changed. Otherwise, the sampler thread might see + // an inconsistent state where the stack pointer still points to a + // ProfileEntry which has already been popped off the stack and whose + // fields have now been partially repopulated with new values. + // See the "Concurrency considerations" paragraph at the top of this file + // for more details. + + // Descriptive label for this entry. Must be a static string! Can be an + // empty string, but not a null pointer. + mozilla::Atomic label_; + + // An additional descriptive string of this entry which is combined with + // |label_| in profiler output. Need not be (and usually isn't) static. Can + // be null. + mozilla::Atomic dynamicString_; + + // Stack pointer for non-JS entries, the script pointer otherwise. + mozilla::Atomic spOrScript; + + // Line number for non-JS entries, the bytecode offset otherwise. + mozilla::Atomic lineOrPcOffset; + + // Bits 0...1 hold the Kind. Bits 2...3 are unused. Bits 4...12 hold the + // Category. + mozilla::Atomic kindAndCategory_; + + static int32_t pcToOffset(JSScript* aScript, jsbytecode* aPc); + + public: + enum class Kind : uint32_t { + // A normal C++ frame. + CPP_NORMAL = 0, + + // A special C++ frame indicating the start of a run of JS pseudostack + // entries. CPP_MARKER_FOR_JS frames are ignored, except for the sp + // field. + CPP_MARKER_FOR_JS = 1, + + // A normal JS frame. + JS_NORMAL = 2, + + // An interpreter JS frame that has OSR-ed into baseline. JS_NORMAL + // frames can be converted to JS_OSR and back. JS_OSR frames are + // ignored. + JS_OSR = 3, + + KIND_MASK = 0x3, + }; + + // Keep these in sync with devtools/client/performance/modules/categories.js + enum class Category : uint32_t { + OTHER = 1u << 4, + CSS = 1u << 5, + JS = 1u << 6, + GC = 1u << 7, + CC = 1u << 8, + NETWORK = 1u << 9, + GRAPHICS = 1u << 10, + STORAGE = 1u << 11, + EVENTS = 1u << 12, + + FIRST = OTHER, + LAST = EVENTS, + + CATEGORY_MASK = ~uint32_t(Kind::KIND_MASK), + }; + + static_assert((uint32_t(Category::FIRST) & uint32_t(Kind::KIND_MASK)) == 0, + "Category overlaps with Kind"); + + bool isCpp() const { + Kind k = kind(); + return k == Kind::CPP_NORMAL || k == Kind::CPP_MARKER_FOR_JS; + } + + bool isJs() const { + Kind k = kind(); + return k == Kind::JS_NORMAL || k == Kind::JS_OSR; + } + + void setLabel(const char* aLabel) { label_ = aLabel; } + const char* label() const { return label_; } + + const char* dynamicString() const { return dynamicString_; } + + void initCppFrame(const char* aLabel, const char* aDynamicString, void* sp, + uint32_t aLine, Kind aKind, Category aCategory) { + label_ = aLabel; + dynamicString_ = aDynamicString; + spOrScript = sp; + lineOrPcOffset = static_cast(aLine); + kindAndCategory_ = uint32_t(aKind) | uint32_t(aCategory); + MOZ_ASSERT(isCpp()); + } + + void initJsFrame(const char* aLabel, const char* aDynamicString, + JSScript* aScript, jsbytecode* aPc) { + label_ = aLabel; + dynamicString_ = aDynamicString; + spOrScript = aScript; + lineOrPcOffset = pcToOffset(aScript, aPc); + kindAndCategory_ = uint32_t(Kind::JS_NORMAL) | uint32_t(Category::JS); + MOZ_ASSERT(isJs()); + } + + void setKind(Kind aKind) { + kindAndCategory_ = uint32_t(aKind) | uint32_t(category()); + } + + Kind kind() const { + return Kind(kindAndCategory_ & uint32_t(Kind::KIND_MASK)); + } + + Category category() const { + return Category(kindAndCategory_ & uint32_t(Category::CATEGORY_MASK)); + } + + void* stackAddress() const { + MOZ_ASSERT(!isJs()); + return spOrScript; + } + + JS_PUBLIC_API JSScript* script() const; + + uint32_t line() const { + MOZ_ASSERT(!isJs()); + return static_cast(lineOrPcOffset); + } + + // Note that the pointer returned might be invalid. + JSScript* rawScript() const { + MOZ_ASSERT(isJs()); + void* script = spOrScript; + return static_cast(script); + } + + // We can't know the layout of JSScript, so look in vm/GeckoProfiler.cpp. + JS_FRIEND_API jsbytecode* pc() const; + void setPC(jsbytecode* pc); + + 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. + static const int32_t NullPCOffset = -1; +}; - uint32_t flags() const volatile { - return flags_; - } +JS_FRIEND_API void SetContextProfilingStack(JSContext* cx, + PseudoStack* pseudoStack); - uint32_t category() const volatile { - return flags_ & CATEGORY_MASK; - } - void setCategory(Category c) volatile { - MOZ_ASSERT(c >= Category::FIRST); - MOZ_ASSERT(c <= Category::LAST); - flags_ &= ~CATEGORY_MASK; - setFlag(static_cast(c)); - } +// GetContextProfilingStack also exists, but it's defined in RootingAPI.h. - void setOSR() volatile { - MOZ_ASSERT(isJs()); - setFlag(OSR); - } - void unsetOSR() volatile { - MOZ_ASSERT(isJs()); - unsetFlag(OSR); - } - bool isOSR() const volatile { - return hasFlag(OSR); - } +JS_FRIEND_API void EnableContextProfilingStack(JSContext* cx, bool enabled); - void* stackAddress() const volatile { - MOZ_ASSERT(!isJs()); - return spOrScript; - } - JS_PUBLIC_API(JSScript*) script() const volatile; - uint32_t line() const volatile { - MOZ_ASSERT(!isJs()); - return static_cast(lineOrPcOffset); - } +JS_FRIEND_API void RegisterContextProfilingEventMarker(JSContext* cx, + void (*fn)(const char*)); - // Note that the pointer returned might be invalid. - JSScript* rawScript() const volatile { - MOZ_ASSERT(isJs()); - return (JSScript*)spOrScript; - } +} // namespace js - // 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. - static const int32_t NullPCOffset = -1; - - static size_t offsetOfLabel() { return offsetof(ProfileEntry, string); } - static size_t offsetOfSpOrScript() { return offsetof(ProfileEntry, spOrScript); } - static size_t offsetOfLineOrPcOffset() { return offsetof(ProfileEntry, lineOrPcOffset); } - static size_t offsetOfFlags() { return offsetof(ProfileEntry, flags_); } +// Each thread has its own PseudoStack. That thread modifies the PseudoStack, +// pushing and popping elements as necessary. +// +// The PseudoStack is also read periodically by the profiler's sampler thread. +// This happens only when the thread that owns the PseudoStack is suspended. So +// there are no genuine parallel accesses. +// +// However, it is possible for pushing/popping to be interrupted by a periodic +// sample. Because of this, we need pushing/popping to be effectively atomic. +// +// - When pushing a new entry, we increment the stack pointer -- making the new +// entry visible to the sampler thread -- only after the new entry has been +// fully written. The stack pointer is Atomic, so +// the increment is a release-store, which ensures that this store is not +// reordered before the writes of the entry. +// +// - When popping an old entry, the only operation is the decrementing of the +// stack pointer, which is obviously atomic. +// +class PseudoStack final { + public: + PseudoStack() : stackPointer(0) {} + + ~PseudoStack() { + // The label macros keep a reference to the PseudoStack to avoid a TLS + // access. If these are somehow not all cleared we will get a + // use-after-free so better to crash now. + MOZ_RELEASE_ASSERT(stackPointer == 0); + } + + void pushCppFrame(const char* label, const char* dynamicString, void* sp, + uint32_t line, js::ProfileEntry::Kind kind, + js::ProfileEntry::Category category) { + if (stackPointer < MaxEntries) { + entries[stackPointer].initCppFrame(label, dynamicString, sp, line, kind, + category); + } + + // This must happen at the end! The compiler will not reorder this + // update because stackPointer is Atomic<..., ReleaseAcquire>, so any + // the writes above will not be reordered below the stackPointer store. + // Do the read and the write as two separate statements, in order to + // make it clear that we don't need an atomic increment, which would be + // more expensive on x86 than the separate operations done here. + // This thread is the only one that ever changes the value of + // stackPointer. + uint32_t oldStackPointer = stackPointer; + stackPointer = oldStackPointer + 1; + } + + void pushJsFrame(const char* label, const char* dynamicString, + JSScript* script, jsbytecode* pc) { + if (stackPointer < MaxEntries) { + entries[stackPointer].initJsFrame(label, dynamicString, script, pc); + } + + // This must happen at the end! The compiler will not reorder this + // update because stackPointer is Atomic<..., ReleaseAcquire>, which + // makes this assignment a release-store, so the writes above will not + // be reordered to occur after the stackPointer store. + // Do the read and the write as two separate statements, in order to + // make it clear that we don't need an atomic increment, which would be + // more expensive on x86 than the separate operations done here. + // This thread is the only one that ever changes the value of + // stackPointer. + uint32_t oldStackPointer = stackPointer; + stackPointer = oldStackPointer + 1; + } + + void pop() { + MOZ_ASSERT(stackPointer > 0); + // Do the read and the write as two separate statements, in order to + // make it clear that we don't need an atomic decrement, which would be + // more expensive on x86 than the separate operations done here. + // This thread is the only one that ever changes the value of + // stackPointer. + uint32_t oldStackPointer = stackPointer; + stackPointer = oldStackPointer - 1; + } + + uint32_t stackSize() const { + return std::min(uint32_t(stackPointer), uint32_t(MaxEntries)); + } + + private: + // No copying. + PseudoStack(const PseudoStack&) = delete; + void operator=(const PseudoStack&) = delete; + + public: + static const uint32_t MaxEntries = 1024; + + // The stack entries. + js::ProfileEntry entries[MaxEntries]; + + // This may exceed MaxEntries, so instead use the stackSize() method to + // determine the number of valid samples in entries. When this is less + // than MaxEntries, it refers to the first free entry past the top of the + // in-use stack (i.e. entries[stackPointer - 1] is the top stack entry). + // + // WARNING WARNING WARNING + // + // This is an atomic variable that uses ReleaseAcquire memory ordering. + // See the "Concurrency considerations" paragraph at the top of this file + // for more details. + mozilla::Atomic stackPointer; }; -JS_FRIEND_API(void) -SetContextProfilingStack(JSContext* cx, ProfileEntry* stack, uint32_t* size, - uint32_t max); - -JS_FRIEND_API(void) -EnableContextProfilingStack(JSContext* cx, bool enabled); - -JS_FRIEND_API(void) -RegisterContextProfilingEventMarker(JSContext* cx, void (*fn)(const char*)); +namespace js { -JS_FRIEND_API(jsbytecode*) -ProfilingGetPC(JSContext* cx, JSScript* script, void* ip); +class AutoGeckoProfilerEntry; +class GeckoProfilerEntryMarker; +class GeckoProfilerBaselineOSRMarker; + +class GeckoProfilerThread { + friend class AutoGeckoProfilerEntry; + friend class GeckoProfilerEntryMarker; + friend class GeckoProfilerBaselineOSRMarker; + + PseudoStack* pseudoStack_; + + public: + GeckoProfilerThread(); + + uint32_t stackPointer() { + MOZ_ASSERT(installed()); + return pseudoStack_->stackPointer; + } + ProfileEntry* stack() { return pseudoStack_->entries; } + PseudoStack* getPseudoStack() { return pseudoStack_; } + + /* management of whether instrumentation is on or off */ + bool installed() { return pseudoStack_ != nullptr; } + + void setProfilingStack(PseudoStack* pseudoStack); + void trace(JSTracer* trc); + + /* + * Functions which are the actual instrumentation to track run information + * + * - enter: a function has started to execute + * - updatePC: updates the pc information about where a function + * is currently executing + * - exit: this function has ceased execution, and no further + * entries/exits will be made + */ + bool enter(JSContext* cx, JSScript* script, JSFunction* maybeFun); + void exit(JSScript* script, JSFunction* maybeFun); + inline void updatePC(JSContext* cx, JSScript* script, jsbytecode* pc); +}; -} // namespace js +} // namespace js -#endif /* js_ProfilingStack_h */ +#endif /* js_ProfilingStack_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/ProtoKey.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/ProtoKey.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/ProtoKey.h @@ -0,0 +1,150 @@ +/* -*- 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_ProtoKey_h +#define js_ProtoKey_h + +/* A higher-order macro for enumerating all JSProtoKey values. */ +/* + * Consumers define macros as follows: + * macro(name, init, clasp) + * name: The canonical name of the class. + * init: Initialization function. These are |extern "C";|, and clients + * should use |extern "C" {}| as appropriate when using this macro. + * clasp: The JSClass for this object, or "dummy" if it doesn't exist. + * + * + * Consumers wishing to iterate over all the JSProtoKey values, can use + * JS_FOR_EACH_PROTOTYPE. However, there are certain values that don't + * correspond to real constructors, like Null or constructors that are disabled + * via preprocessor directives. We still need to include these in the JSProtoKey + * list in order to maintain binary XDR compatibility, but we need to provide a + * tool to handle them differently. JS_FOR_PROTOTYPES fills this niche. + * + * Consumers pass two macros to JS_FOR_PROTOTYPES - |real| and |imaginary|. The + * former is invoked for entries that have real client-exposed constructors, and + * the latter is called for the rest. Consumers that don't care about this + * distinction can simply pass the same macro to both, which is exactly what + * JS_FOR_EACH_PROTOTYPE does. + */ + +#define CLASP(NAME) (&NAME##Class) +#define OCLASP(NAME) (&NAME##Object::class_) +#define TYPED_ARRAY_CLASP(TYPE) (&TypedArrayObject::classes[Scalar::TYPE]) +#define ERROR_CLASP(TYPE) (&ErrorObject::classes[TYPE]) + +#ifdef EXPOSE_INTL_API +#define IF_INTL(REAL, IMAGINARY) REAL +#else +#define IF_INTL(REAL, IMAGINARY) IMAGINARY +#endif + +#ifdef ENABLE_BINARYDATA +#define IF_BDATA(real, imaginary) real +#else +#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 + +#define JS_FOR_PROTOTYPES_(REAL, IMAGINARY, REAL_IF_INTL, REAL_IF_BDATA, \ + REAL_IF_SAB, REAL_IF_SIMD) \ + IMAGINARY(Null, InitNullClass, dummy) \ + REAL(Object, InitViaClassSpec, OCLASP(Plain)) \ + REAL(Function, InitViaClassSpec, &JSFunction::class_) \ + REAL(Array, InitViaClassSpec, OCLASP(Array)) \ + REAL(Boolean, InitBooleanClass, OCLASP(Boolean)) \ + REAL(JSON, InitJSONClass, CLASP(JSON)) \ + REAL(Date, InitViaClassSpec, OCLASP(Date)) \ + REAL(Math, InitMathClass, CLASP(Math)) \ + REAL(Number, InitNumberClass, OCLASP(Number)) \ + REAL(String, InitStringClass, OCLASP(String)) \ + REAL(RegExp, InitViaClassSpec, OCLASP(RegExp)) \ + REAL(Error, InitViaClassSpec, ERROR_CLASP(JSEXN_ERR)) \ + REAL(InternalError, InitViaClassSpec, ERROR_CLASP(JSEXN_INTERNALERR)) \ + REAL(EvalError, InitViaClassSpec, ERROR_CLASP(JSEXN_EVALERR)) \ + REAL(RangeError, InitViaClassSpec, ERROR_CLASP(JSEXN_RANGEERR)) \ + REAL(ReferenceError, InitViaClassSpec, ERROR_CLASP(JSEXN_REFERENCEERR)) \ + REAL(SyntaxError, InitViaClassSpec, ERROR_CLASP(JSEXN_SYNTAXERR)) \ + REAL(TypeError, InitViaClassSpec, ERROR_CLASP(JSEXN_TYPEERR)) \ + REAL(URIError, InitViaClassSpec, ERROR_CLASP(JSEXN_URIERR)) \ + REAL(DebuggeeWouldRun, InitViaClassSpec, \ + ERROR_CLASP(JSEXN_DEBUGGEEWOULDRUN)) \ + REAL(CompileError, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMCOMPILEERROR)) \ + REAL(LinkError, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMLINKERROR)) \ + REAL(RuntimeError, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMRUNTIMEERROR)) \ + IMAGINARY(Iterator, dummy, dummy) \ + REAL(ArrayBuffer, InitViaClassSpec, OCLASP(ArrayBuffer)) \ + REAL(Int8Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Int8)) \ + REAL(Uint8Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8)) \ + REAL(Int16Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Int16)) \ + REAL(Uint16Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint16)) \ + REAL(Int32Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Int32)) \ + REAL(Uint32Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint32)) \ + REAL(Float32Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Float32)) \ + REAL(Float64Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Float64)) \ + REAL(Uint8ClampedArray, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8Clamped)) \ + REAL(Proxy, InitProxyClass, js::ProxyClassPtr) \ + REAL(WeakMap, InitWeakMapClass, OCLASP(WeakMap)) \ + REAL(Map, InitViaClassSpec, OCLASP(Map)) \ + REAL(Set, InitViaClassSpec, OCLASP(Set)) \ + REAL(DataView, InitViaClassSpec, OCLASP(DataView)) \ + REAL(Symbol, InitSymbolClass, OCLASP(Symbol)) \ + REAL_IF_SAB(SharedArrayBuffer, InitViaClassSpec, OCLASP(SharedArrayBuffer)) \ + REAL_IF_INTL(Intl, InitIntlClass, CLASP(Intl)) \ + REAL_IF_BDATA(TypedObject, InitTypedObjectModuleObject, \ + OCLASP(TypedObjectModule)) \ + REAL(Reflect, InitReflect, nullptr) \ + REAL_IF_SIMD(SIMD, InitSimdClass, OCLASP(Simd)) \ + REAL(WeakSet, InitWeakSetClass, OCLASP(WeakSet)) \ + REAL(TypedArray, InitViaClassSpec, \ + &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \ + REAL_IF_SAB(Atomics, InitAtomicsClass, OCLASP(Atomics)) \ + REAL(SavedFrame, InitViaClassSpec, &js::SavedFrame::class_) \ + REAL(Promise, InitViaClassSpec, OCLASP(Promise)) \ + REAL(ReadableStream, InitViaClassSpec, &js::ReadableStream::class_) \ + REAL(ReadableStreamDefaultReader, InitViaClassSpec, \ + &js::ReadableStreamDefaultReader::class_) \ + REAL(ReadableStreamBYOBReader, InitViaClassSpec, \ + &js::ReadableStreamBYOBReader::class_) \ + REAL(ReadableStreamDefaultController, InitViaClassSpec, \ + &js::ReadableStreamDefaultController::class_) \ + REAL(ReadableByteStreamController, InitViaClassSpec, \ + &js::ReadableByteStreamController::class_) \ + REAL(ReadableStreamBYOBRequest, InitViaClassSpec, \ + &js::ReadableStreamBYOBRequest::class_) \ + IMAGINARY(WritableStream, dummy, dummy) \ + IMAGINARY(WritableStreamDefaultWriter, dummy, dummy) \ + IMAGINARY(WritableStreamDefaultController, dummy, dummy) \ + REAL(ByteLengthQueuingStrategy, InitViaClassSpec, \ + &js::ByteLengthQueuingStrategy::class_) \ + REAL(CountQueuingStrategy, InitViaClassSpec, \ + &js::CountQueuingStrategy::class_) \ + REAL(WebAssembly, InitWebAssemblyClass, CLASP(WebAssembly)) \ + IMAGINARY(WasmModule, dummy, dummy) \ + IMAGINARY(WasmInstance, dummy, dummy) \ + IMAGINARY(WasmMemory, dummy, dummy) \ + IMAGINARY(WasmTable, dummy, dummy) \ + IMAGINARY(WasmGlobal, dummy, dummy) + +#define JS_FOR_PROTOTYPES(REAL, IMAGINARY) \ + JS_FOR_PROTOTYPES_(REAL, IMAGINARY, IF_INTL(REAL, IMAGINARY), \ + IF_BDATA(REAL, IMAGINARY), IF_SAB(REAL, IMAGINARY), \ + IF_SIMD(REAL, IMAGINARY)) + +#define JS_FOR_EACH_PROTOTYPE(MACRO) JS_FOR_PROTOTYPES(MACRO, MACRO) + +#endif /* js_ProtoKey_h */ 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 @@ -32,8 +32,9 @@ using JS::PropertyDescriptor; using JS::Value; -class RegExpGuard; -class JS_FRIEND_API(Wrapper); +class RegExpShared; + +class JS_FRIEND_API Wrapper; /* * A proxy is a JSObject with highly customizable behavior. ES6 specifies a @@ -146,243 +147,293 @@ * * Important: If you add a method here, you should probably also add a * Proxy::foo entry point with an AutoEnterPolicy. If you don't, you need an - * explicit override for the method in SecurityWrapper. See bug 945826 comment 0. + * explicit override for the method in SecurityWrapper. See bug 945826 comment + * 0. */ -class JS_FRIEND_API(BaseProxyHandler) -{ - /* - * Sometimes it's desirable to designate groups of proxy handlers as "similar". - * For this, we use the notion of a "family": A consumer-provided opaque pointer - * that designates the larger group to which this proxy belongs. - * - * If it will never be important to differentiate this proxy from others as - * part of a distinct group, nullptr may be used instead. - */ - const void* mFamily; - - /* - * Proxy handlers can use mHasPrototype to request the following special - * treatment from the JS engine: - * - * - When mHasPrototype is true, the engine never calls these methods: - * getPropertyDescriptor, has, set, enumerate, iterate. Instead, for - * these operations, it calls the "own" methods like - * getOwnPropertyDescriptor, hasOwn, defineProperty, - * getOwnEnumerablePropertyKeys, etc., and consults the prototype chain - * if needed. - * - * - When mHasPrototype is true, the engine calls handler->get() only if - * handler->hasOwn() says an own property exists on the proxy. If not, - * it consults the prototype chain. - * - * This is useful because it frees the ProxyHandler from having to implement - * any behavior having to do with the prototype chain. - */ - bool mHasPrototype; - - /* - * All proxies indicate whether they have any sort of interesting security - * policy that might prevent the caller from doing something it wants to - * the object. In the case of wrappers, this distinction is used to - * determine whether the caller may strip off the wrapper if it so desires. - */ - bool mHasSecurityPolicy; - - public: - explicit constexpr BaseProxyHandler(const void* aFamily, bool aHasPrototype = false, - bool aHasSecurityPolicy = false) +class JS_FRIEND_API BaseProxyHandler { + /* + * Sometimes it's desirable to designate groups of proxy handlers as + * "similar". For this, we use the notion of a "family": A consumer-provided + * opaque pointer that designates the larger group to which this proxy + * belongs. + * + * If it will never be important to differentiate this proxy from others as + * part of a distinct group, nullptr may be used instead. + */ + const void* mFamily; + + /* + * Proxy handlers can use mHasPrototype to request the following special + * treatment from the JS engine: + * + * - When mHasPrototype is true, the engine never calls these methods: + * getPropertyDescriptor, has, set, enumerate, iterate. Instead, for + * these operations, it calls the "own" methods like + * getOwnPropertyDescriptor, hasOwn, defineProperty, + * getOwnEnumerablePropertyKeys, etc., and consults the prototype chain + * if needed. + * + * - When mHasPrototype is true, the engine calls handler->get() only if + * handler->hasOwn() says an own property exists on the proxy. If not, + * it consults the prototype chain. + * + * This is useful because it frees the ProxyHandler from having to implement + * any behavior having to do with the prototype chain. + */ + bool mHasPrototype; + + /* + * All proxies indicate whether they have any sort of interesting security + * policy that might prevent the caller from doing something it wants to + * the object. In the case of wrappers, this distinction is used to + * determine whether the caller may strip off the wrapper if it so desires. + */ + bool mHasSecurityPolicy; + + public: + explicit constexpr BaseProxyHandler(const void* aFamily, + bool aHasPrototype = false, + bool aHasSecurityPolicy = false) : mFamily(aFamily), mHasPrototype(aHasPrototype), - mHasSecurityPolicy(aHasSecurityPolicy) - { } + mHasSecurityPolicy(aHasSecurityPolicy) {} - bool hasPrototype() const { - return mHasPrototype; - } - - bool hasSecurityPolicy() const { - return mHasSecurityPolicy; - } - - inline const void* family() const { - return mFamily; - } - static size_t offsetOfFamily() { - return offsetof(BaseProxyHandler, mFamily); - } - - 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. - */ - 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| - * on the proxy's |id| property. In the case when |act| is CALL, |id| is - * generally JSID_VOID. - * - * The |act| parameter to enter() specifies the action being performed. - * If |bp| is false, the method suggests that the caller throw (though it - * may still decide to squelch the error). - * - * We make these OR-able so that assertEnteredPolicy can pass a union of them. - * For example, get{,Own}PropertyDescriptor is invoked by calls to ::get() - * ::set(), in addition to being invoked on its own, so there are several - * valid Actions that could have been entered. - */ - typedef uint32_t Action; - enum { - NONE = 0x00, - GET = 0x01, - SET = 0x02, - CALL = 0x04, - ENUMERATE = 0x08, - GET_PROPERTY_DESCRIPTOR = 0x10 - }; - - virtual bool enter(JSContext* cx, HandleObject wrapper, HandleId id, Action act, - bool* bp) const; - - /* Standard internal methods. */ - virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const = 0; - virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, - ObjectOpResult& result) const = 0; - virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy, - AutoIdVector& props) const = 0; - virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id, - ObjectOpResult& result) const = 0; + bool hasPrototype() const { return mHasPrototype; } - /* - * These methods are standard, but the engine does not normally call them. - * They're opt-in. See "Proxy prototype chains" above. - * - * getPrototype() crashes if called. setPrototype() throws a TypeError. - */ - virtual bool getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const; - virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, - ObjectOpResult& result) const; - - /* 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, - ObjectOpResult& result) const = 0; - virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const = 0; + bool hasSecurityPolicy() const { return mHasSecurityPolicy; } + + inline const void* family() const { return mFamily; } + static size_t offsetOfFamily() { return offsetof(BaseProxyHandler, mFamily); } + virtual bool finalizeInBackground(const Value& priv) const { /* - * These standard internal methods are implemented, as a convenience, so - * that ProxyHandler subclasses don't have to provide every single method. - * - * The base-class implementations work by calling getPropertyDescriptor(). - * They do not follow any standard. When in doubt, override them. + * Called on creation of a proxy to determine whether its finalize + * method can be finalized on the background thread. */ - virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const; - virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, - HandleId id, MutableHandleValue vp) const; - virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result) const; + return true; + } + virtual bool canNurseryAllocate() const { /* - * [[Call]] and [[Construct]] are standard internal methods but according - * to the spec, they are not present on every object. - * - * SpiderMonkey never calls a proxy's call()/construct() internal method - * unless isCallable()/isConstructor() returns true for that proxy. - * - * BaseProxyHandler::isCallable()/isConstructor() always return false, and - * BaseProxyHandler::call()/construct() crash if called. So if you're - * creating a kind of that is never callable, you don't have to override - * anything, but otherwise you probably want to override all four. + * Nursery allocation is allowed if and only if it is safe to not + * run |finalize| when the ProxyObject dies. */ - virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const; - virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const; + return false; + } - /* SpiderMonkey extensions. */ - virtual bool enumerate(JSContext* cx, HandleObject proxy, MutableHandleObject objp) const; - virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - 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; - virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, - const CallArgs& args) const; - virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp) const; - virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, - 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; - virtual bool regexp_toShared(JSContext* cx, HandleObject proxy, RegExpGuard* g) const; - virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const; - virtual void trace(JSTracer* trc, JSObject* proxy) const; - virtual void finalize(JSFreeOp* fop, JSObject* proxy) const; - virtual void objectMoved(JSObject* proxy, const JSObject* old) const; - - // Allow proxies, wrappers in particular, to specify callability at runtime. - // Note: These do not take const JSObject*, but they do in spirit. - // We are not prepared to do this, as there's little const correctness - // in the external APIs that handle proxies. - virtual bool isCallable(JSObject* obj) const; - virtual bool isConstructor(JSObject* obj) const; - - // These two hooks must be overridden, or not overridden, in tandem -- no - // overriding just one! - virtual bool watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, - JS::HandleObject callable) const; - virtual bool unwatch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id) const; - - virtual bool getElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end, - ElementAdder* adder) const; - - /* See comment for weakmapKeyDelegateOp in js/Class.h. */ - virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const; - virtual bool isScripted() const { return false; } + /* Policy enforcement methods. + * + * enter() allows the policy to specify whether the caller may perform |act| + * on the proxy's |id| property. In the case when |act| is CALL, |id| is + * generally JSID_VOID. The |mayThrow| parameter indicates whether a + * handler that wants to throw custom exceptions when denying should do so + * or not. + * + * The |act| parameter to enter() specifies the action being performed. + * If |bp| is false, the method suggests that the caller throw (though it + * may still decide to squelch the error). + * + * We make these OR-able so that assertEnteredPolicy can pass a union of them. + * For example, get{,Own}PropertyDescriptor is invoked by calls to ::get() + * ::set(), in addition to being invoked on its own, so there are several + * valid Actions that could have been entered. + */ + typedef uint32_t Action; + enum { + NONE = 0x00, + GET = 0x01, + SET = 0x02, + CALL = 0x04, + ENUMERATE = 0x08, + GET_PROPERTY_DESCRIPTOR = 0x10 + }; + + virtual bool enter(JSContext* cx, HandleObject wrapper, HandleId id, + Action act, bool mayThrow, bool* bp) const; + + /* Standard internal methods. */ + virtual bool getOwnPropertyDescriptor( + JSContext* cx, HandleObject proxy, HandleId id, + MutableHandle desc) const = 0; + virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, + Handle desc, + ObjectOpResult& result) const = 0; + virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy, + AutoIdVector& props) const = 0; + virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id, + ObjectOpResult& result) const = 0; + + /* + * These methods are standard, but the engine does not normally call them. + * They're opt-in. See "Proxy prototype chains" above. + * + * getPrototype() crashes if called. setPrototype() throws a TypeError. + */ + virtual bool getPrototype(JSContext* cx, HandleObject proxy, + MutableHandleObject protop) const; + virtual bool setPrototype(JSContext* cx, HandleObject proxy, + HandleObject proto, ObjectOpResult& result) const; + + /* 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, + ObjectOpResult& result) const = 0; + virtual bool isExtensible(JSContext* cx, HandleObject proxy, + bool* extensible) const = 0; + + /* + * These standard internal methods are implemented, as a convenience, so + * that ProxyHandler subclasses don't have to provide every single method. + * + * The base-class implementations work by calling getPropertyDescriptor(). + * They do not follow any standard. When in doubt, override them. + */ + virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, + bool* bp) const; + virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, + HandleId id, MutableHandleValue vp) const; + virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, + HandleValue v, HandleValue receiver, + ObjectOpResult& result) const; + + /* + * [[Call]] and [[Construct]] are standard internal methods but according + * to the spec, they are not present on every object. + * + * SpiderMonkey never calls a proxy's call()/construct() internal method + * unless isCallable()/isConstructor() returns true for that proxy. + * + * BaseProxyHandler::isCallable()/isConstructor() always return false, and + * BaseProxyHandler::call()/construct() crash if called. So if you're + * creating a kind of that is never callable, you don't have to override + * anything, but otherwise you probably want to override all four. + */ + virtual bool call(JSContext* cx, HandleObject proxy, + const CallArgs& args) const; + virtual bool construct(JSContext* cx, HandleObject proxy, + const CallArgs& args) const; + + /* SpiderMonkey extensions. */ + virtual JSObject* enumerate(JSContext* cx, HandleObject proxy) const; + virtual bool getPropertyDescriptor( + JSContext* cx, HandleObject proxy, HandleId id, + 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; + virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, + const CallArgs& args) const; + virtual bool hasInstance(JSContext* cx, HandleObject proxy, + MutableHandleValue v, bool* bp) const; + virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, + 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, + bool isToSource) const; + virtual RegExpShared* regexp_toShared(JSContext* cx, + HandleObject proxy) const; + virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, + MutableHandleValue vp) const; + virtual void trace(JSTracer* trc, JSObject* proxy) const; + virtual void finalize(JSFreeOp* fop, JSObject* proxy) const; + virtual size_t objectMoved(JSObject* proxy, JSObject* old) const; + + // Allow proxies, wrappers in particular, to specify callability at runtime. + // Note: These do not take const JSObject*, but they do in spirit. + // We are not prepared to do this, as there's little const correctness + // in the external APIs that handle proxies. + virtual bool isCallable(JSObject* obj) const; + virtual bool isConstructor(JSObject* obj) const; + + virtual bool getElements(JSContext* cx, HandleObject proxy, uint32_t begin, + uint32_t end, ElementAdder* adder) const; + + /* See comment for weakmapKeyDelegateOp in js/Class.h. */ + virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const; + virtual bool isScripted() const { return false; } }; -extern JS_FRIEND_DATA(const js::Class* const) ProxyClassPtr; +extern JS_FRIEND_DATA const js::Class* const ProxyClassPtr; -inline bool IsProxy(const JSObject* obj) -{ - return GetObjectClass(obj)->isProxy(); +inline bool IsProxy(const JSObject* obj) { + 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 -// private slot to be the first slot in the proxy's values, so that the private -// slot can be accessed in the same fashion as the first reserved slot, via -// {Get,Set}ReservedOrProxyPrivateSlot. - -struct ProxyValueArray -{ - Value privateSlot; - Value extraSlots[PROXY_EXTRA_SLOTS]; - - ProxyValueArray() - : privateSlot(JS::UndefinedValue()) - { - for (size_t i = 0; i < PROXY_EXTRA_SLOTS; i++) - extraSlots[i] = JS::UndefinedValue(); - } +// Proxy slot layout +// ----------------- +// +// Every proxy has a ProxyValueArray that contains the following Values: +// +// - The private slot. +// - The reserved slots. The number of slots is determined by the proxy's Class. +// +// Proxy objects store a pointer to the reserved slots (ProxyReservedSlots*). +// The ProxyValueArray and the private slot can be accessed using +// ProxyValueArray::fromReservedSlots or ProxyDataLayout::values. +// +// Storing a pointer to ProxyReservedSlots instead of ProxyValueArray has a +// number of advantages. In particular, it means js::GetReservedSlot and +// js::SetReservedSlot can be used with both proxies and native objects. This +// works because the ProxyReservedSlots* pointer is stored where native objects +// store their dynamic slots pointer. + +struct ProxyReservedSlots { + Value slots[1]; + + static inline int offsetOfPrivateSlot(); + + static inline int offsetOfSlot(size_t slot) { + return offsetof(ProxyReservedSlots, slots[0]) + slot * sizeof(Value); + } + + void init(size_t nreserved) { + for (size_t i = 0; i < nreserved; i++) slots[i] = JS::UndefinedValue(); + } + + ProxyReservedSlots(const ProxyReservedSlots&) = delete; + void operator=(const ProxyReservedSlots&) = delete; +}; + +struct ProxyValueArray { + Value privateSlot; + ProxyReservedSlots reservedSlots; + + void init(size_t nreserved) { + privateSlot = JS::UndefinedValue(); + reservedSlots.init(nreserved); + } + + static size_t sizeOf(size_t nreserved) { + return offsetOfReservedSlots() + nreserved * sizeof(Value); + } + static MOZ_ALWAYS_INLINE ProxyValueArray* fromReservedSlots( + ProxyReservedSlots* slots) { + uintptr_t p = reinterpret_cast(slots); + return reinterpret_cast(p - offsetOfReservedSlots()); + } + static size_t offsetOfReservedSlots() { + return offsetof(ProxyValueArray, reservedSlots); + } + + ProxyValueArray(const ProxyValueArray&) = delete; + void operator=(const ProxyValueArray&) = delete; }; +/* static */ inline int ProxyReservedSlots::offsetOfPrivateSlot() { + return -int(ProxyValueArray::offsetOfReservedSlots()) + + offsetof(ProxyValueArray, privateSlot); +} + // All proxies share the same data layout. Following the object's shape and // type, the proxy has a ProxyDataLayout structure with a pointer to an array // of values and the proxy's handler. This is designed both so that proxies can @@ -391,241 +442,268 @@ // that common code can access either type of object. // // See GetReservedOrProxyPrivateSlot below. -struct ProxyDataLayout -{ - ProxyValueArray* values; - const BaseProxyHandler* handler; +struct ProxyDataLayout { + ProxyReservedSlots* reservedSlots; + const BaseProxyHandler* handler; + + MOZ_ALWAYS_INLINE ProxyValueArray* values() const { + return ProxyValueArray::fromReservedSlots(reservedSlots); + } }; const uint32_t ProxyDataOffset = 2 * sizeof(void*); -inline ProxyDataLayout* -GetProxyDataLayout(JSObject* obj) -{ - MOZ_ASSERT(IsProxy(obj)); - return reinterpret_cast(reinterpret_cast(obj) + ProxyDataOffset); +inline ProxyDataLayout* GetProxyDataLayout(JSObject* obj) { + MOZ_ASSERT(IsProxy(obj)); + 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); +inline const ProxyDataLayout* GetProxyDataLayout(const JSObject* obj) { + MOZ_ASSERT(IsProxy(obj)); + return reinterpret_cast( + reinterpret_cast(obj) + ProxyDataOffset); } -} // namespace detail +} // namespace detail -inline const BaseProxyHandler* -GetProxyHandler(const JSObject* obj) -{ - return detail::GetProxyDataLayout(obj)->handler; +inline const BaseProxyHandler* GetProxyHandler(const JSObject* obj) { + return detail::GetProxyDataLayout(obj)->handler; } -inline const Value& -GetProxyPrivate(const JSObject* obj) -{ - return detail::GetProxyDataLayout(obj)->values->privateSlot; +inline const Value& GetProxyPrivate(const JSObject* obj) { + return detail::GetProxyDataLayout(obj)->values()->privateSlot; } -inline JSObject* -GetProxyTargetObject(JSObject* obj) -{ - return GetProxyPrivate(obj).toObjectOrNull(); +inline JSObject* GetProxyTargetObject(JSObject* obj) { + return GetProxyPrivate(obj).toObjectOrNull(); } -inline const Value& -GetProxyExtra(const JSObject* obj, size_t n) -{ - MOZ_ASSERT(n < detail::PROXY_EXTRA_SLOTS); - return detail::GetProxyDataLayout(obj)->values->extraSlots[n]; +inline const Value& GetProxyReservedSlot(const JSObject* obj, size_t n) { + MOZ_ASSERT(n < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); + return detail::GetProxyDataLayout(obj)->reservedSlots->slots[n]; } -inline void -SetProxyHandler(JSObject* obj, const BaseProxyHandler* handler) -{ - detail::GetProxyDataLayout(obj)->handler = handler; +inline void SetProxyHandler(JSObject* obj, const BaseProxyHandler* handler) { + detail::GetProxyDataLayout(obj)->handler = handler; } -JS_FRIEND_API(void) -SetValueInProxy(Value* slot, const Value& value); +JS_FRIEND_API void SetValueInProxy(Value* slot, const Value& value); -inline void -SetProxyExtra(JSObject* obj, size_t n, const Value& extra) -{ - MOZ_ASSERT(n < detail::PROXY_EXTRA_SLOTS); - Value* vp = &detail::GetProxyDataLayout(obj)->values->extraSlots[n]; +inline void SetProxyReservedSlot(JSObject* obj, size_t n, const Value& extra) { + MOZ_ASSERT(n < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); + MOZ_ASSERT_IF(gc::detail::ObjectIsMarkedBlack(obj), + JS::ValueIsNotGray(extra)); - // Trigger a barrier before writing the slot. - if (vp->isMarkable() || extra.isMarkable()) - SetValueInProxy(vp, extra); - else - *vp = extra; -} + Value* vp = &detail::GetProxyDataLayout(obj)->reservedSlots->slots[n]; -inline bool -IsScriptedProxy(const JSObject* obj) -{ - return IsProxy(obj) && GetProxyHandler(obj)->isScripted(); + // Trigger a barrier before writing the slot. + if (vp->isGCThing() || extra.isGCThing()) + SetValueInProxy(vp, extra); + else + *vp = extra; } -inline const Value& -GetReservedOrProxyPrivateSlot(const JSObject* obj, size_t slot) -{ - MOZ_ASSERT(slot == 0); - MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)) || IsProxy(obj)); - return reinterpret_cast(obj)->slotRef(slot); +inline void SetProxyPrivate(JSObject* obj, const Value& value) { + MOZ_ASSERT_IF(gc::detail::ObjectIsMarkedBlack(obj), + JS::ValueIsNotGray(value)); + + Value* vp = &detail::GetProxyDataLayout(obj)->values()->privateSlot; + + // Trigger a barrier before writing the slot. + if (vp->isGCThing() || value.isGCThing()) + SetValueInProxy(vp, value); + else + *vp = value; } -inline void -SetReservedOrProxyPrivateSlot(JSObject* obj, size_t slot, const Value& value) -{ - MOZ_ASSERT(slot == 0); - MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)) || IsProxy(obj)); - shadow::Object* sobj = reinterpret_cast(obj); - if (sobj->slotRef(slot).isMarkable() || value.isMarkable()) - SetReservedOrProxyPrivateSlotWithBarrier(obj, slot, value); - else - sobj->slotRef(slot) = value; +inline bool IsScriptedProxy(const JSObject* obj) { + return IsProxy(obj) && GetProxyHandler(obj)->isScripted(); } class MOZ_STACK_CLASS ProxyOptions { - protected: - /* protected constructor for subclass */ - explicit ProxyOptions(bool singletonArg, bool lazyProtoArg = false) + protected: + /* protected constructor for subclass */ + explicit ProxyOptions(bool singletonArg, bool lazyProtoArg = false) : singleton_(singletonArg), lazyProto_(lazyProtoArg), - clasp_(ProxyClassPtr) - {} + clasp_(ProxyClassPtr) {} - public: - ProxyOptions() : singleton_(false), - lazyProto_(false), - clasp_(ProxyClassPtr) - {} - - bool singleton() const { return singleton_; } - ProxyOptions& setSingleton(bool flag) { - singleton_ = flag; - return *this; - } - - bool lazyProto() const { return lazyProto_; } - ProxyOptions& setLazyProto(bool flag) { - lazyProto_ = flag; - return *this; - } - - const Class* clasp() const { - return clasp_; - } - ProxyOptions& setClass(const Class* claspArg) { - clasp_ = claspArg; - return *this; - } - - private: - bool singleton_; - bool lazyProto_; - const Class* clasp_; + public: + ProxyOptions() + : singleton_(false), lazyProto_(false), clasp_(ProxyClassPtr) {} + + bool singleton() const { return singleton_; } + ProxyOptions& setSingleton(bool flag) { + singleton_ = flag; + return *this; + } + + bool lazyProto() const { return lazyProto_; } + ProxyOptions& setLazyProto(bool flag) { + lazyProto_ = flag; + return *this; + } + + const Class* clasp() const { return clasp_; } + ProxyOptions& setClass(const Class* claspArg) { + clasp_ = claspArg; + return *this; + } + + private: + bool singleton_; + bool lazyProto_; + const Class* clasp_; }; -JS_FRIEND_API(JSObject*) -NewProxyObject(JSContext* cx, const BaseProxyHandler* handler, HandleValue priv, - JSObject* proto, const ProxyOptions& options = ProxyOptions()); - -JSObject* -RenewProxyObject(JSContext* cx, JSObject* obj, BaseProxyHandler* handler, const Value& priv); - -class JS_FRIEND_API(AutoEnterPolicy) -{ - public: - typedef BaseProxyHandler::Action Action; - AutoEnterPolicy(JSContext* cx, const BaseProxyHandler* handler, - HandleObject wrapper, HandleId id, Action act, bool mayThrow) +JS_FRIEND_API JSObject* NewProxyObject( + JSContext* cx, const BaseProxyHandler* handler, HandleValue priv, + JSObject* proto, const ProxyOptions& options = ProxyOptions()); + +JSObject* RenewProxyObject(JSContext* cx, JSObject* obj, + BaseProxyHandler* handler, const Value& priv); + +class JS_FRIEND_API AutoEnterPolicy { + public: + typedef BaseProxyHandler::Action Action; + AutoEnterPolicy(JSContext* cx, const BaseProxyHandler* handler, + HandleObject wrapper, HandleId id, Action act, bool mayThrow) #ifdef JS_DEBUG - : context(nullptr) + : context(nullptr) #endif - { - allow = handler->hasSecurityPolicy() ? handler->enter(cx, wrapper, id, act, &rv) - : true; - recordEnter(cx, wrapper, id, act); - // We want to throw an exception if all of the following are true: - // * The policy disallowed access. - // * The policy set rv to false, indicating that we should throw. - // * The caller did not instruct us to ignore exceptions. - // * The policy did not throw itself. - if (!allow && !rv && mayThrow) - reportErrorIfExceptionIsNotPending(cx, id); - } - - virtual ~AutoEnterPolicy() { recordLeave(); } - inline bool allowed() { return allow; } - inline bool returnValue() { MOZ_ASSERT(!allowed()); return rv; } - - protected: - // no-op constructor for subclass - AutoEnterPolicy() + { + allow = handler->hasSecurityPolicy() + ? handler->enter(cx, wrapper, id, act, mayThrow, &rv) + : true; + recordEnter(cx, wrapper, id, act); + // We want to throw an exception if all of the following are true: + // * The policy disallowed access. + // * The policy set rv to false, indicating that we should throw. + // * The caller did not instruct us to ignore exceptions. + // * The policy did not throw itself. + if (!allow && !rv && mayThrow) reportErrorIfExceptionIsNotPending(cx, id); + } + + virtual ~AutoEnterPolicy() { recordLeave(); } + inline bool allowed() { return allow; } + inline bool returnValue() { + MOZ_ASSERT(!allowed()); + return rv; + } + + protected: + // no-op constructor for subclass + AutoEnterPolicy() #ifdef JS_DEBUG - : context(nullptr) - , enteredAction(BaseProxyHandler::NONE) + : context(nullptr), + enteredAction(BaseProxyHandler::NONE) #endif - {} - void reportErrorIfExceptionIsNotPending(JSContext* cx, jsid id); - bool allow; - bool rv; + { + } + void reportErrorIfExceptionIsNotPending(JSContext* cx, jsid id); + bool allow; + bool rv; #ifdef JS_DEBUG - JSContext* context; - mozilla::Maybe enteredProxy; - mozilla::Maybe enteredId; - Action enteredAction; - - // NB: We explicitly don't track the entered action here, because sometimes - // set() methods do an implicit get() during their implementation, leading - // to spurious assertions. - AutoEnterPolicy* prev; - void recordEnter(JSContext* cx, HandleObject proxy, HandleId id, Action act); - void recordLeave(); + JSContext* context; + mozilla::Maybe enteredProxy; + mozilla::Maybe enteredId; + Action enteredAction; + + // NB: We explicitly don't track the entered action here, because sometimes + // set() methods do an implicit get() during their implementation, leading + // to spurious assertions. + AutoEnterPolicy* prev; + void recordEnter(JSContext* cx, HandleObject proxy, HandleId id, Action act); + void recordLeave(); - friend JS_FRIEND_API(void) assertEnteredPolicy(JSContext* cx, JSObject* proxy, jsid id, Action act); + friend JS_FRIEND_API void assertEnteredPolicy(JSContext* cx, JSObject* proxy, + jsid id, Action act); #else - inline void recordEnter(JSContext* cx, JSObject* proxy, jsid id, Action act) {} - inline void recordLeave() {} + inline void recordEnter(JSContext* cx, JSObject* proxy, jsid id, Action act) { + } + inline void recordLeave() {} #endif + private: + // This operator needs to be deleted explicitly, otherwise Visual C++ will + // create it automatically when it is part of the export JS API. In that + // case, compile would fail because HandleId is not allowed to be assigned + // and consequently instantiation of assign operator of mozilla::Maybe + // would fail. See bug 1325351 comment 16. Copy constructor is removed at + // the same time for consistency. + AutoEnterPolicy(const AutoEnterPolicy&) = delete; + AutoEnterPolicy& operator=(const AutoEnterPolicy&) = delete; }; #ifdef JS_DEBUG -class JS_FRIEND_API(AutoWaivePolicy) : public AutoEnterPolicy { -public: - AutoWaivePolicy(JSContext* cx, HandleObject proxy, HandleId id, - BaseProxyHandler::Action act) - { - allow = true; - recordEnter(cx, proxy, id, act); - } +class JS_FRIEND_API AutoWaivePolicy : public AutoEnterPolicy { + public: + AutoWaivePolicy(JSContext* cx, HandleObject proxy, HandleId id, + BaseProxyHandler::Action act) { + allow = true; + recordEnter(cx, proxy, id, act); + } }; #else -class JS_FRIEND_API(AutoWaivePolicy) { - public: - AutoWaivePolicy(JSContext* cx, HandleObject proxy, HandleId id, - BaseProxyHandler::Action act) - {} +class JS_FRIEND_API AutoWaivePolicy { + public: + AutoWaivePolicy(JSContext* cx, HandleObject proxy, HandleId id, + BaseProxyHandler::Action act) {} }; #endif #ifdef JS_DEBUG -extern JS_FRIEND_API(void) -assertEnteredPolicy(JSContext* cx, JSObject* obj, jsid id, - BaseProxyHandler::Action act); +extern JS_FRIEND_API void assertEnteredPolicy(JSContext* cx, JSObject* obj, + jsid id, + BaseProxyHandler::Action act); #else inline void assertEnteredPolicy(JSContext* cx, JSObject* obj, jsid id, - BaseProxyHandler::Action act) -{} + BaseProxyHandler::Action act) {} #endif -extern JS_FRIEND_API(JSObject*) -InitProxyClass(JSContext* cx, JS::HandleObject obj); +extern JS_FRIEND_API JSObject* InitProxyClass(JSContext* cx, + JS::HandleObject obj); + +extern JS_FRIEND_DATA const js::ClassOps ProxyClassOps; +extern JS_FRIEND_DATA const js::ClassExtension ProxyClassExtension; +extern JS_FRIEND_DATA const js::ObjectOps ProxyObjectOps; + +template +constexpr unsigned CheckProxyFlags() { + // For now assert each Proxy Class has at least 1 reserved slot. This is + // not a hard requirement, but helps catch Classes that need an explicit + // JSCLASS_HAS_RESERVED_SLOTS since bug 1360523. + static_assert(((Flags >> JSCLASS_RESERVED_SLOTS_SHIFT) & + JSCLASS_RESERVED_SLOTS_MASK) > 0, + "Proxy Classes must have at least 1 reserved slot"); + + // ProxyValueArray must fit inline in the object, so assert the number of + // slots does not exceed MAX_FIXED_SLOTS. + static_assert( + (offsetof(js::detail::ProxyValueArray, reservedSlots) / sizeof(Value)) + + ((Flags >> JSCLASS_RESERVED_SLOTS_SHIFT) & + JSCLASS_RESERVED_SLOTS_MASK) <= + shadow::Object::MAX_FIXED_SLOTS, + "ProxyValueArray size must not exceed max JSObject size"); + + // Proxies must not have the JSCLASS_SKIP_NURSERY_FINALIZE flag set: they + // always have finalizers, and whether they can be nursery allocated is + // controlled by the canNurseryAllocate() method on the proxy handler. + static_assert(!(Flags & JSCLASS_SKIP_NURSERY_FINALIZE), + "Proxies must not use JSCLASS_SKIP_NURSERY_FINALIZE; use " + "the canNurseryAllocate() proxy handler method instead."); + return Flags; +} + +#define PROXY_CLASS_DEF(name, flags) \ + { \ + name, \ + js::Class::NON_NATIVE | JSCLASS_IS_PROXY | \ + JSCLASS_DELAY_METADATA_BUILDER | js::CheckProxyFlags(), \ + &js::ProxyClassOps, JS_NULL_CLASS_SPEC, &js::ProxyClassExtension, \ + &js::ProxyObjectOps \ + } } /* namespace js */ 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 @@ -13,30 +13,96 @@ #ifndef js_Realm_h #define js_Realm_h -#include "jstypes.h" - -struct JSContext; -class JSObject; +#include "jspubtd.h" +#include "js/GCPolicyAPI.h" +#include "js/TypeDecls.h" // forward-declaration of JS::Realm + +namespace js { +namespace gc { +JS_PUBLIC_API void TraceRealm(JSTracer* trc, JS::Realm* realm, + const char* name); +JS_PUBLIC_API bool RealmNeedsSweep(JS::Realm* realm); +} // namespace gc +} // namespace js 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); +// Each Realm holds a strong reference to its GlobalObject, and vice versa. +template <> +struct GCPolicy : public NonGCPointerPolicy { + static void trace(JSTracer* trc, Realm** vp, const char* name) { + if (*vp) ::js::gc::TraceRealm(trc, *vp, name); + } + static bool needsSweep(Realm** vp) { + return *vp && ::js::gc::RealmNeedsSweep(*vp); + } +}; + +// Get the current realm, if any. The ECMAScript spec calls this "the current +// Realm Record". +extern JS_PUBLIC_API Realm* GetCurrentRealmOrNull(JSContext* cx); + +// Return the compartment that contains a given realm. +inline JSCompartment* GetCompartmentForRealm(Realm* realm) { + // Implementation note: For now, realms are a fiction; we treat realms and + // compartments as being one-to-one, but they are actually identical. + return reinterpret_cast(realm); +} + +// Return the realm in a given compartment. +// +// Deprecated. There is currently exactly one realm per compartment, but this +// will change. +inline Realm* GetRealmForCompartment(JSCompartment* compartment) { + return reinterpret_cast(compartment); +} + +// Return an object's realm. All objects except cross-compartment wrappers are +// created in a particular realm, which never changes. Returns null if obj is +// a cross-compartment wrapper. +extern JS_PUBLIC_API Realm* GetObjectRealmOrNull(JSObject* obj); + +// Get the value of the "private data" internal field of the given Realm. +// This field is initially null and is set using SetRealmPrivate. +// It's a pointer to embeddding-specific data that SpiderMonkey never uses. +extern JS_PUBLIC_API void* GetRealmPrivate(Realm* realm); + +// Set the "private data" internal field of the given Realm. +extern JS_PUBLIC_API void SetRealmPrivate(Realm* realm, void* data); + +typedef void (*DestroyRealmCallback)(JSFreeOp* fop, Realm* realm); + +// Set the callback SpiderMonkey calls just before garbage-collecting a realm. +// Embeddings can use this callback to free private data associated with the +// realm via SetRealmPrivate. +// +// By the time this is called, the global object for the realm has already been +// collected. +extern JS_PUBLIC_API void SetDestroyRealmCallback( + JSContext* cx, DestroyRealmCallback callback); + +typedef void (*RealmNameCallback)(JSContext* cx, Handle realm, + char* buf, size_t bufsize); + +// Set the callback SpiderMonkey calls to get the name of a realm, for +// diagnostic output. +extern JS_PUBLIC_API void SetRealmNameCallback(JSContext* cx, + RealmNameCallback callback); + +// Get the global object for the given realm. Returns null only if `realm` is +// in the atoms compartment. +extern JS_PUBLIC_API JSObject* GetRealmGlobalOrNull(Handle realm); + +extern JS_PUBLIC_API JSObject* GetRealmObjectPrototype(JSContext* cx); + +extern JS_PUBLIC_API JSObject* GetRealmFunctionPrototype(JSContext* cx); + +extern JS_PUBLIC_API JSObject* GetRealmArrayPrototype(JSContext* cx); -} // namespace JS +extern JS_PUBLIC_API JSObject* GetRealmErrorPrototype(JSContext* cx); -#endif // js_Realm_h +extern JS_PUBLIC_API JSObject* GetRealmIteratorPrototype(JSContext* cx); +} // namespace JS +#endif // js_Realm_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/RefCounted.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/RefCounted.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/RefCounted.h @@ -0,0 +1,85 @@ +/* -*- 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_RefCounted_h +#define js_RefCounted_h + +#include "mozilla/Atomics.h" +#include "mozilla/RefCountType.h" + +#include "js/Utility.h" + +// These types implement the same interface as mozilla::(Atomic)RefCounted and +// must be used instead of mozilla::(Atomic)RefCounted for everything in +// SpiderMonkey. There are two reasons: +// - Release() needs to call js_delete, not delete +// - SpiderMonkey does not have MOZILLA_INTERNAL_API defined which can lead +// to ODR violations that show up as spurious leak reports when ref-counted +// types are allocated by SpiderMonkey and released by Gecko (or vice versa). + +namespace js { + +template +class RefCounted { + static const MozRefCountType DEAD = 0xffffdead; + + protected: + RefCounted() : mRefCnt(0) {} + ~RefCounted() { MOZ_ASSERT(mRefCnt == DEAD); } + + public: + void AddRef() const { + MOZ_ASSERT(int32_t(mRefCnt) >= 0); + ++mRefCnt; + } + + void Release() const { + MOZ_ASSERT(int32_t(mRefCnt) > 0); + MozRefCountType cnt = --mRefCnt; + if (0 == cnt) { +#ifdef DEBUG + mRefCnt = DEAD; +#endif + js_delete(const_cast(static_cast(this))); + } + } + + private: + mutable MozRefCountType mRefCnt; +}; + +template +class AtomicRefCounted { + static const MozRefCountType DEAD = 0xffffdead; + + protected: + AtomicRefCounted() : mRefCnt(0) {} + ~AtomicRefCounted() { MOZ_ASSERT(mRefCnt == DEAD); } + + public: + void AddRef() const { + MOZ_ASSERT(int32_t(mRefCnt) >= 0); + ++mRefCnt; + } + + void Release() const { + MOZ_ASSERT(int32_t(mRefCnt) > 0); + MozRefCountType cnt = --mRefCnt; + if (0 == cnt) { +#ifdef DEBUG + mRefCnt = DEAD; +#endif + js_delete(const_cast(static_cast(this))); + } + } + + private: + mutable mozilla::Atomic mRefCnt; +}; + +} // namespace js + +#endif /* js_RefCounted_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Result.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Result.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Result.h @@ -0,0 +1,216 @@ +/* -*- 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/. */ + +/* + * `Result` is used as the return type of many SpiderMonkey functions that + * can either succeed or fail. See "/mfbt/Result.h". + * + * + * ## Which return type to use + * + * `Result` is for return values. Obviously, if you're writing a function that + * can't fail, don't use Result. Otherwise: + * + * JS::Result<> - function can fail, doesn't return anything on success + * (defaults to `JS::Result`) + * JS::Result - like JS::Result<>, but fails only on OOM + * + * JS::Result - function can fail, returns Data on success + * JS::Result - returns Data, fails only on OOM + * + * mozilla::GenericErrorResult - always fails + * + * That last type is like a Result with no success type. It's used for + * functions like `js::ReportNotFunction` that always return an error + * result. `GenericErrorResult` implicitly converts to `Result`, + * regardless of V. + * + * + * ## Checking Results when your return type is Result + * + * When you call a function that returns a `Result`, use the `MOZ_TRY` macro to + * check for errors: + * + * MOZ_TRY(DefenestrateObject(cx, obj)); + * + * If `DefenestrateObject` returns a success result, `MOZ_TRY` is done, and + * control flows to the next statement. If `DefenestrateObject` returns an + * error result, `MOZ_TRY` will immediately return it, propagating the error to + * your caller. It's kind of like exceptions, but more explicit -- you can see + * in the code exactly where errors can happen. + * + * You can do a tail call instead of using `MOZ_TRY`: + * + * return DefenestrateObject(cx, obj); + * + * Indicate success with `return Ok();`. + * + * If the function returns a value on success, use `MOZ_TRY_VAR` to get it: + * + * RootedValue thrug(cx); + * MOZ_TRY_VAR(thrug, GetObjectThrug(cx, obj)); + * + * This behaves the same as `MOZ_TRY` on error. On success, the success + * value of `GetObjectThrug(cx, obj)` is assigned to the variable `thrug`. + * + * + * ## Checking Results when your return type is not Result + * + * This header defines alternatives to MOZ_TRY and MOZ_TRY_VAR for when you + * need to call a `Result` function from a function that uses false or nullptr + * to indicate errors: + * + * JS_TRY_OR_RETURN_FALSE(cx, DefenestrateObject(cx, obj)); + * JS_TRY_VAR_OR_RETURN_FALSE(cx, v, GetObjectThrug(cx, obj)); + * + * JS_TRY_OR_RETURN_NULL(cx, DefenestrateObject(cx, obj)); + * JS_TRY_VAR_OR_RETURN_NULL(cx, v, GetObjectThrug(cx, obj)); + * + * When TRY is not what you want, because you need to do some cleanup or + * recovery on error, use this idiom: + * + * if (!cx->resultToBool(expr_that_is_a_Result)) { + * ... your recovery code here ... + * } + * + * In place of a tail call, you can use one of these methods: + * + * return cx->resultToBool(expr); // false on error + * return cx->resultToPtr(expr); // null on error + * + * Once we are using `Result` everywhere, including in public APIs, all of + * these will go away. + * + * + * ## GC safety + * + * When a function returns a `JS::Result`, it is the program's + * responsibility to check for errors and root the object before continuing: + * + * RootedObject wrapper(cx); + * MOZ_TRY_VAR(wrapper, Enwrapify(cx, thing)); + * + * This is ideal. On error, there is no object to root; on success, the + * assignment to wrapper roots it. GC safety is ensured. + * + * `Result` has methods .isOk(), .isErr(), .unwrap(), and .unwrapErr(), but if + * you're actually using them, it's possible to create a GC hazard. The static + * analysis will catch it if so, but that's hardly convenient. So try to stick + * to the idioms shown above. + * + * + * ## Future directions + * + * At present, JS::Error and JS::OOM are empty structs. The plan is to make them + * GC things that contain the actual error information (including the exception + * value and a saved stack). + * + * The long-term plan is to remove JS_IsExceptionPending and + * JS_GetPendingException in favor of JS::Error. Exception state will no longer + * exist. + */ + +#ifndef js_Result_h +#define js_Result_h + +#include "mozilla/Result.h" + +/** + * Evaluate the boolean expression expr. If it's true, do nothing. + * If it's false, return an error result. + */ +#define JS_TRY_BOOL_TO_RESULT(cx, expr) \ + do { \ + bool ok_ = (expr); \ + if (!ok_) return (cx)->boolToResult(ok_); \ + } while (0) + +/** + * JS_TRY_OR_RETURN_FALSE(cx, expr) runs expr to compute a Result value. + * On success, nothing happens; on error, it returns false immediately. + * + * Implementation note: this involves cx because this may eventually + * do the work of setting a pending exception or reporting OOM. + */ +#define JS_TRY_OR_RETURN_FALSE(cx, expr) \ + do { \ + auto tmpResult_ = (expr); \ + if (tmpResult_.isErr()) return (cx)->resultToBool(tmpResult_); \ + } while (0) + +/** + * Like JS_TRY_OR_RETURN_FALSE, but returning nullptr on error, + * rather than false. + */ +#define JS_TRY_OR_RETURN_NULL(cx, expr) \ + do { \ + auto tmpResult_ = (expr); \ + if (tmpResult_.isErr()) { \ + JS_ALWAYS_FALSE((cx)->resultToBool(tmpResult_)); \ + return nullptr; \ + } \ + } while (0) + +#define JS_TRY_VAR_OR_RETURN_FALSE(cx, target, expr) \ + do { \ + auto tmpResult_ = (expr); \ + if (tmpResult_.isErr()) return (cx)->resultToBool(tmpResult_); \ + (target) = tmpResult_.unwrap(); \ + } while (0) + +#define JS_TRY_VAR_OR_RETURN_NULL(cx, target, expr) \ + do { \ + auto tmpResult_ = (expr); \ + if (tmpResult_.isErr()) { \ + JS_ALWAYS_FALSE((cx)->resultToBool(tmpResult_)); \ + return nullptr; \ + } \ + (target) = tmpResult_.unwrap(); \ + } while (0) + +namespace JS { + +using mozilla::Ok; + +/** + * Type representing a JS error or exception. At the moment this only + * "represents" an error in a rather abstract way. + */ +struct Error { + // Ensure sizeof(Error) > 1 so that Result can use pointer + // tagging. + int dummy; +}; + +struct OOM : public Error {}; + +/** + * `Result` is intended to be the return type of JSAPI calls and internal + * functions that can run JS code or allocate memory from the JS GC heap. Such + * functions can: + * + * - succeed, possibly returning a value; + * + * - fail with a JS exception (out-of-memory falls in this category); or + * + * - fail because JS execution was terminated, which occurs when e.g. a + * user kills a script from the "slow script" UI. This is also how we + * unwind the stack when the debugger forces the current function to + * return. JS `catch` blocks can't catch this kind of failure, + * and JS `finally` blocks don't execute. + */ +template +using Result = mozilla::Result; + +static_assert(sizeof(Result<>) == sizeof(uintptr_t), + "Result<> should be pointer-sized"); + +static_assert(sizeof(Result) == sizeof(uintptr_t), + "Result should be pointer-sized"); + +} // namespace JS + +#endif // js_Result_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 @@ -19,9 +19,9 @@ #include "jspubtd.h" #include "js/GCAnnotations.h" -#include "js/GCAPI.h" #include "js/GCPolicyAPI.h" #include "js/HeapAPI.h" +#include "js/ProfilingStack.h" #include "js/TypeDecls.h" #include "js/UniquePtr.h" #include "js/Utility.h" @@ -110,105 +110,121 @@ namespace js { template -struct BarrierMethods { -}; +struct BarrierMethods {}; -template -class RootedBase {}; +template +class WrappedPtrOperations {}; -template -class HandleBase {}; +template +class MutableWrappedPtrOperations + : public WrappedPtrOperations {}; -template -class MutableHandleBase {}; +template +class RootedBase : public MutableWrappedPtrOperations {}; -template -class HeapBase {}; +template +class HandleBase : public WrappedPtrOperations {}; -// 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; }; +template +class MutableHandleBase : public MutableWrappedPtrOperations {}; + +template +class HeapBase : public MutableWrappedPtrOperations {}; + +// 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; }; + 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 : public MutableWrappedPtrOperations {}; + template -class PersistentRootedBase {}; +class FakeRooted; -static void* const ConstNullValue = nullptr; +template +class FakeMutableHandle; namespace gc { struct Cell; -template +template struct PersistentRootedMarker; } /* namespace gc */ -#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(); } \ - const T& operator->() 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 // operator= on the derived class. Thus, define the operator= directly on the // class as we would need to manually pass it through anyway. -#define DECLARE_POINTER_ASSIGN_OPS(Wrapper, T) \ - Wrapper& operator=(const T& p) { \ - 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) \ - template Wrapper& operator=(S) = delete; \ - Wrapper& operator=(const Wrapper&) = delete; - -#define DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr) \ - const T* address() const { return &(ptr); } \ - const T& get() const { return (ptr); } \ - -#define DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr) \ - T* address() { return &(ptr); } \ - T& get() { return (ptr); } \ +#define DECLARE_POINTER_ASSIGN_OPS(Wrapper, T) \ + Wrapper& operator=(const T& p) { \ + 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) \ + template \ + Wrapper& operator=(S) = delete; \ + Wrapper& operator=(const Wrapper&) = delete; + +#define DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr) \ + const T* address() const { return &(ptr); } \ + const T& get() const { return (ptr); } + +#define DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr) \ + T* address() { return &(ptr); } \ + T& get() { return (ptr); } } /* namespace js */ namespace JS { -template class Rooted; -template class PersistentRooted; +template +class Rooted; +template +class PersistentRooted; /* This is exposing internal state of the GC for inlining purposes. */ -JS_FRIEND_API(bool) isGCEnabled(); +JS_FRIEND_API bool isGCEnabled(); -JS_FRIEND_API(void) HeapObjectPostBarrier(JSObject** objp, JSObject* prev, JSObject* next); +JS_FRIEND_API void HeapObjectPostBarrier(JSObject** objp, JSObject* prev, + JSObject* next); +JS_FRIEND_API void HeapStringPostBarrier(JSString** objp, JSString* prev, + JSString* next); #ifdef JS_DEBUG /** * For generational GC, assert that an object is in the tenured generation as * opposed to being in the nursery. */ -extern JS_FRIEND_API(void) -AssertGCThingMustBeTenured(JSObject* obj); -extern JS_FRIEND_API(void) -AssertGCThingIsNotAnObjectSubclass(js::gc::Cell* cell); +extern JS_FRIEND_API void AssertGCThingMustBeTenured(JSObject* obj); +extern JS_FRIEND_API void AssertGCThingIsNotNurseryAllocable( + js::gc::Cell* cell); #else -inline void -AssertGCThingMustBeTenured(JSObject* obj) {} -inline void -AssertGCThingIsNotAnObjectSubclass(js::gc::Cell* cell) {} +inline void AssertGCThingMustBeTenured(JSObject* obj) {} +inline void AssertGCThingIsNotNurseryAllocable(js::gc::Cell* cell) {} #endif /** @@ -231,113 +247,108 @@ * Type T must be a public GC pointer type. */ template -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(GCPolicy::initial()); - } - explicit Heap(const T& p) { init(p); } - - /* - * For Heap, move semantics are equivalent to copy semantics. In C++, a - * copy constructor taking const-ref is the way to get a single function - * that will be used for both lvalue and rvalue copies, so we can simply - * omit the rvalue variant. - */ - explicit Heap(const Heap& p) { init(p.ptr); } +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: + using ElementType = T; + + Heap() { + static_assert(sizeof(T) == sizeof(Heap), + "Heap must be binary compatible with T."); + init(GCPolicy::initial()); + } + explicit Heap(const T& p) { init(p); } + + /* + * For Heap, move semantics are equivalent to copy semantics. In C++, a + * copy constructor taking const-ref is the way to get a single function + * that will be used for both lvalue and rvalue copies, so we can simply + * omit the rvalue variant. + */ + explicit Heap(const Heap& p) { init(p.ptr); } + + ~Heap() { post(ptr, GCPolicy::initial()); } + + DECLARE_POINTER_CONSTREF_OPS(T); + DECLARE_POINTER_ASSIGN_OPS(Heap, T); + + const T* address() const { return &ptr; } + + void exposeToActiveJS() const { js::BarrierMethods::exposeToJS(ptr); } + const T& get() const { + exposeToActiveJS(); + return ptr; + } + const T& unbarrieredGet() const { return ptr; } + + 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(const T& newPtr) { + ptr = newPtr; + post(GCPolicy::initial(), ptr); + } + + void set(const T& newPtr) { + T tmp = ptr; + ptr = newPtr; + post(tmp, ptr); + } + + void post(const T& prev, const T& next) { + js::BarrierMethods::postBarrier(&ptr, prev, next); + } - ~Heap() { - post(ptr, GCPolicy::initial()); - } - - DECLARE_POINTER_CONSTREF_OPS(T); - DECLARE_POINTER_ASSIGN_OPS(Heap, T); - - const T* address() const { return &ptr; } - - void exposeToActiveJS() const { - js::BarrierMethods::exposeToJS(ptr); - } - const T& get() const { - exposeToActiveJS(); - return ptr; - } - const T& unbarrieredGet() const { - return ptr; - } - - 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(const T& newPtr) { - ptr = newPtr; - post(GCPolicy::initial(), ptr); - } - - void set(const T& newPtr) { - T tmp = ptr; - ptr = newPtr; - post(tmp, ptr); - } - - void post(const T& prev, const T& next) { - js::BarrierMethods::postBarrier(&ptr, prev, next); - } - - T ptr; + T ptr; }; -static MOZ_ALWAYS_INLINE bool -ObjectIsTenured(JSObject* obj) -{ - return !js::gc::IsInsideNursery(reinterpret_cast(obj)); +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 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(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 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); +// The following *IsNotGray functions are for use in assertions and take account +// of the eventual gray marking state at the end of any ongoing incremental GC. +#ifdef DEBUG +inline bool CellIsNotGray(js::gc::Cell* maybeCell) { + if (!maybeCell) return true; + + return js::gc::detail::CellIsNotGray(maybeCell); } -static MOZ_ALWAYS_INLINE bool -ScriptIsMarkedGray(const Heap& script) -{ - return ScriptIsMarkedGray(script.unbarrieredGet()); +inline bool ObjectIsNotGray(JSObject* maybeObj) { + return CellIsNotGray(reinterpret_cast(maybeObj)); } +inline bool ObjectIsNotGray(const JS::Heap& obj) { + return ObjectIsNotGray(obj.unbarrieredGet()); +} +#endif + /** * 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, @@ -368,79 +379,79 @@ * - It is not possible to store flag bits in a Heap. */ template -class TenuredHeap : public js::HeapBase -{ - public: - TenuredHeap() : bits(0) { - static_assert(sizeof(T) == sizeof(TenuredHeap), - "TenuredHeap must be binary compatible with T."); - } - explicit TenuredHeap(T p) : bits(0) { setPtr(p); } - explicit TenuredHeap(const TenuredHeap& p) : bits(0) { setPtr(p.getPtr()); } - - bool operator==(const TenuredHeap& other) { return bits == other.bits; } - bool operator!=(const TenuredHeap& other) { return bits != other.bits; } +class TenuredHeap : public js::HeapBase> { + public: + using ElementType = T; + + TenuredHeap() : bits(0) { + static_assert(sizeof(T) == sizeof(TenuredHeap), + "TenuredHeap must be binary compatible with T."); + } + explicit TenuredHeap(T p) : bits(0) { setPtr(p); } + explicit TenuredHeap(const TenuredHeap& p) : bits(0) { + setPtr(p.getPtr()); + } + + void setPtr(T newPtr) { + MOZ_ASSERT((reinterpret_cast(newPtr) & flagsMask) == 0); + MOZ_ASSERT(js::gc::IsCellPointerValidOrNull(newPtr)); + if (newPtr) AssertGCThingMustBeTenured(newPtr); + bits = (bits & flagsMask) | reinterpret_cast(newPtr); + } + + void setFlags(uintptr_t flagsToSet) { + MOZ_ASSERT((flagsToSet & ~flagsMask) == 0); + bits |= flagsToSet; + } + + void unsetFlags(uintptr_t flagsToUnset) { + MOZ_ASSERT((flagsToUnset & ~flagsMask) == 0); + bits &= ~flagsToUnset; + } + + bool hasFlag(uintptr_t flag) const { + MOZ_ASSERT((flag & ~flagsMask) == 0); + return (bits & flag) != 0; + } + + 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; + } + + TenuredHeap& operator=(const TenuredHeap& other) { + bits = other.bits; + return *this; + } + + private: + enum { + maskBits = 3, + flagsMask = (1 << maskBits) - 1, + }; - void setPtr(T newPtr) { - MOZ_ASSERT((reinterpret_cast(newPtr) & flagsMask) == 0); - if (newPtr) - AssertGCThingMustBeTenured(newPtr); - bits = (bits & flagsMask) | reinterpret_cast(newPtr); - } - - void setFlags(uintptr_t flagsToSet) { - MOZ_ASSERT((flagsToSet & ~flagsMask) == 0); - bits |= flagsToSet; - } - - void unsetFlags(uintptr_t flagsToUnset) { - MOZ_ASSERT((flagsToUnset & ~flagsMask) == 0); - bits &= ~flagsToUnset; - } - - bool hasFlag(uintptr_t flag) const { - MOZ_ASSERT((flag & ~flagsMask) == 0); - return (bits & flag) != 0; - } - - 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; - } - - TenuredHeap& operator=(const TenuredHeap& other) { - bits = other.bits; - return *this; - } - - private: - enum { - maskBits = 3, - flagsMask = (1 << maskBits) - 1, - }; - - uintptr_t bits; + uintptr_t bits; }; /** @@ -452,84 +463,87 @@ * specialization, define a HandleBase specialization containing them. */ template -class MOZ_NONHEAP_CLASS Handle : public js::HandleBase -{ - friend class JS::MutableHandle; - - public: - /* Creates a handle from a handle of a type convertible to T. */ - template - MOZ_IMPLICIT Handle(Handle handle, - typename mozilla::EnableIf::value, int>::Type dummy = 0) - { - static_assert(sizeof(Handle) == sizeof(T*), - "Handle must be binary compatible with T*."); - ptr = reinterpret_cast(handle.address()); - } - - MOZ_IMPLICIT Handle(decltype(nullptr)) { - static_assert(mozilla::IsPointer::value, - "nullptr_t overload not valid for non-pointer types"); - ptr = reinterpret_cast(&js::ConstNullValue); - } +class MOZ_NONHEAP_CLASS Handle : public js::HandleBase> { + friend class JS::MutableHandle; - MOZ_IMPLICIT Handle(MutableHandle handle) { - ptr = handle.address(); - } + public: + using ElementType = T; - /* - * Take care when calling this method! - * - * This creates a Handle from the raw location of a T. - * - * It should be called only if the following conditions hold: - * - * 1) the location of the T is guaranteed to be marked (for some reason - * other than being a Rooted), e.g., if it is guaranteed to be reachable - * from an implicit root. - * - * 2) the contents of the location are immutable, or at least cannot change - * for the lifetime of the handle, as its users may not expect its value - * to change underneath them. - */ - static constexpr Handle fromMarkedLocation(const T* p) { - return Handle(p, DeliberatelyChoosingThisOverload, - ImUsingThisOnlyInFromFromMarkedLocation); - } + /* Creates a handle from a handle of a type convertible to T. */ + template + MOZ_IMPLICIT Handle( + Handle handle, + typename mozilla::EnableIf::value, int>::Type + dummy = 0) { + static_assert(sizeof(Handle) == sizeof(T*), + "Handle must be binary compatible with T*."); + ptr = reinterpret_cast(handle.address()); + } + + MOZ_IMPLICIT Handle(decltype(nullptr)) { + static_assert(mozilla::IsPointer::value, + "nullptr_t overload not valid for non-pointer types"); + static void* const ConstNullValue = nullptr; + ptr = reinterpret_cast(&ConstNullValue); + } + + MOZ_IMPLICIT Handle(MutableHandle handle) { ptr = handle.address(); } + + /* + * Take care when calling this method! + * + * This creates a Handle from the raw location of a T. + * + * It should be called only if the following conditions hold: + * + * 1) the location of the T is guaranteed to be marked (for some reason + * other than being a Rooted), e.g., if it is guaranteed to be reachable + * from an implicit root. + * + * 2) the contents of the location are immutable, or at least cannot change + * for the lifetime of the handle, as its users may not expect its value + * to change underneath them. + */ + static constexpr Handle fromMarkedLocation(const T* p) { + return Handle(p, DeliberatelyChoosingThisOverload, + ImUsingThisOnlyInFromFromMarkedLocation); + } + + /* + * Construct a handle from an explicitly rooted location. This is the + * normal way to create a handle, and normally happens implicitly. + */ + template + inline MOZ_IMPLICIT Handle( + const Rooted& root, + typename mozilla::EnableIf::value, int>::Type + dummy = 0); + + template + inline MOZ_IMPLICIT Handle( + const PersistentRooted& root, + typename mozilla::EnableIf::value, int>::Type + dummy = 0); + + /* Construct a read only handle from a mutable handle. */ + template + inline MOZ_IMPLICIT Handle( + MutableHandle& root, + typename mozilla::EnableIf::value, int>::Type + dummy = 0); + + DECLARE_POINTER_CONSTREF_OPS(T); + DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr); + + private: + Handle() {} + DELETE_ASSIGNMENT_OPS(Handle, T); + + enum Disambiguator { DeliberatelyChoosingThisOverload = 42 }; + enum CallerIdentity { ImUsingThisOnlyInFromFromMarkedLocation = 17 }; + constexpr Handle(const T* p, Disambiguator, CallerIdentity) : ptr(p) {} - /* - * Construct a handle from an explicitly rooted location. This is the - * normal way to create a handle, and normally happens implicitly. - */ - template - inline - MOZ_IMPLICIT Handle(const Rooted& root, - typename mozilla::EnableIf::value, int>::Type dummy = 0); - - template - inline - MOZ_IMPLICIT Handle(const PersistentRooted& root, - typename mozilla::EnableIf::value, int>::Type dummy = 0); - - /* Construct a read only handle from a mutable handle. */ - template - inline - MOZ_IMPLICIT Handle(MutableHandle& root, - typename mozilla::EnableIf::value, int>::Type dummy = 0); - - DECLARE_POINTER_COMPARISON_OPS(T); - DECLARE_POINTER_CONSTREF_OPS(T); - DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr); - - private: - Handle() {} - DELETE_ASSIGNMENT_OPS(Handle, T); - - enum Disambiguator { DeliberatelyChoosingThisOverload = 42 }; - enum CallerIdentity { ImUsingThisOnlyInFromFromMarkedLocation = 17 }; - constexpr Handle(const T* p, Disambiguator, CallerIdentity) : ptr(p) {} - - const T* ptr; + const T* ptr; }; /** @@ -541,46 +555,50 @@ * them. */ template -class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase -{ - public: - inline MOZ_IMPLICIT MutableHandle(Rooted* root); - inline MOZ_IMPLICIT MutableHandle(PersistentRooted* root); - - private: - // Disallow nullptr for overloading purposes. - MutableHandle(decltype(nullptr)) = delete; - - public: - 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 - * to be marked (for some reason other than being a Rooted), - * e.g., if it is guaranteed to be reachable from an implicit root. - * - * Create a MutableHandle from a raw location of a T. - */ - static MutableHandle fromMarkedLocation(T* p) { - MutableHandle h; - h.ptr = p; - return h; - } +class MOZ_STACK_CLASS MutableHandle + : public js::MutableHandleBase> { + public: + using ElementType = T; + + inline MOZ_IMPLICIT MutableHandle(Rooted* root); + inline MOZ_IMPLICIT MutableHandle(PersistentRooted* root); + + private: + // Disallow nullptr for overloading purposes. + MutableHandle(decltype(nullptr)) = delete; + + public: + void set(const T& v) { + *ptr = v; + MOZ_ASSERT(GCPolicy::isValid(*ptr)); + } + void set(T&& v) { + *ptr = mozilla::Move(v); + MOZ_ASSERT(GCPolicy::isValid(*ptr)); + } + + /* + * This may be called only if the location of the T is guaranteed + * to be marked (for some reason other than being a Rooted), + * e.g., if it is guaranteed to be reachable from an implicit root. + * + * Create a MutableHandle from a raw location of a T. + */ + static MutableHandle fromMarkedLocation(T* p) { + MutableHandle h; + h.ptr = p; + return h; + } + + DECLARE_POINTER_CONSTREF_OPS(T); + DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr); + DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr); + + private: + MutableHandle() {} + DELETE_ASSIGNMENT_OPS(MutableHandle, T); - DECLARE_POINTER_CONSTREF_OPS(T); - DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr); - DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr); - - private: - MutableHandle() {} - DELETE_ASSIGNMENT_OPS(MutableHandle, T); - - T* ptr; + T* ptr; }; } /* namespace JS */ @@ -588,63 +606,71 @@ namespace js { template -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 exposeToJS(T* t) { - if (t) - js::gc::ExposeGCThingToActiveJS(JS::GCCellPtr(t)); - } +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::AssertGCThingIsNotNurseryAllocable( + reinterpret_cast(next)); + } + static void exposeToJS(T* t) { + if (t) js::gc::ExposeGCThingToActiveJS(JS::GCCellPtr(t)); + } }; template <> -struct BarrierMethods -{ - static JSObject* initial() { return nullptr; } - static gc::Cell* asGCThingOrNull(JSObject* v) { - if (!v) - return nullptr; - MOZ_ASSERT(uintptr_t(v) > 32); - return reinterpret_cast(v); - } - static void postBarrier(JSObject** vp, JSObject* prev, JSObject* next) { - JS::HeapObjectPostBarrier(vp, prev, next); - } - static void exposeToJS(JSObject* obj) { - if (obj) - JS::ExposeObjectToActiveJS(obj); - } +struct BarrierMethods { + static JSObject* initial() { return nullptr; } + static gc::Cell* asGCThingOrNull(JSObject* v) { + if (!v) return nullptr; + MOZ_ASSERT(uintptr_t(v) > 32); + return reinterpret_cast(v); + } + 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 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)); - } +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)); + } +}; + +template <> +struct BarrierMethods { + static JSString* initial() { return nullptr; } + static gc::Cell* asGCThingOrNull(JSString* v) { + if (!v) return nullptr; + MOZ_ASSERT(uintptr_t(v) > 32); + return reinterpret_cast(v); + } + static void postBarrier(JSString** vp, JSString* prev, JSString* next) { + JS::HeapStringPostBarrier(vp, prev, next); + } + static void exposeToJS(JSString* v) { + if (v) js::gc::ExposeGCThingToActiveJS(JS::GCCellPtr(v)); + } }; // Provide hash codes for Cell kinds that may be relocated and, thus, not have @@ -659,42 +685,47 @@ // aggregate Lookup kinds embed a JSObject* that is frequently null and do not // null test before dispatching to the hasher. template -struct JS_PUBLIC_API(MovableCellHasher) -{ - 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; } +struct JS_PUBLIC_API MovableCellHasher { + 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; } }; template -struct JS_PUBLIC_API(MovableCellHasher>) -{ - 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.unbarrieredGet(), l); - } - static void rekey(Key& k, const Key& newKey) { k.unsafeSet(newKey); } +struct JS_PUBLIC_API MovableCellHasher> { + 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.unbarrieredGet(), l); + } + static void rekey(Key& k, const Key& newKey) { k.unsafeSet(newKey); } }; template -struct FallibleHashMethods> -{ - template static bool hasHash(Lookup&& l) { - return MovableCellHasher::hasHash(mozilla::Forward(l)); - } - template static bool ensureHash(Lookup&& l) { - return MovableCellHasher::ensureHash(mozilla::Forward(l)); - } +struct FallibleHashMethods> { + 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 */ @@ -710,41 +741,175 @@ // DispatchWrapper, rather than DispatchWrapper itself, but that causes MSVC to // fail when Rooted is used in an IsConvertible test. template -class alignas(8) DispatchWrapper -{ - static_assert(JS::MapTypeToRootKind::kind == JS::RootKind::Traceable, - "DispatchWrapper is intended only for usage with a Traceable"); - - using TraceFn = void (*)(JSTracer*, T*, const char*); - TraceFn tracer; - alignas(gc::CellSize) T storage; - - public: - template - MOZ_IMPLICIT DispatchWrapper(U&& initial) +class alignas(8) DispatchWrapper { + static_assert(JS::MapTypeToRootKind::kind == JS::RootKind::Traceable, + "DispatchWrapper is intended only for usage with a Traceable"); + + using TraceFn = void (*)(JSTracer*, T*, const char*); + TraceFn tracer; + alignas(gc::CellAlignBytes) T storage; + + public: + template + MOZ_IMPLICIT DispatchWrapper(U&& initial) : tracer(&JS::GCPolicy::trace), - storage(mozilla::Forward(initial)) - { } + storage(mozilla::Forward(initial)) {} - // Mimic a pointer type, so that we can drop into Rooted. - T* operator &() { return &storage; } - const T* operator &() const { return &storage; } - operator T&() { return storage; } - operator const T&() const { return storage; } - - // 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, T* thingp, const char* name) { - auto wrapper = reinterpret_cast( - uintptr_t(thingp) - offsetof(DispatchWrapper, storage)); - wrapper->tracer(trc, &wrapper->storage, name); - } + // Mimic a pointer type, so that we can drop into Rooted. + T* operator&() { return &storage; } + const T* operator&() const { return &storage; } + operator T&() { return storage; } + operator const T&() const { return storage; } + + // 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, T* thingp, const char* name) { + auto wrapper = reinterpret_cast( + uintptr_t(thingp) - offsetof(DispatchWrapper, storage)); + wrapper->tracer(trc, &wrapper->storage, name); + } }; } /* namespace js */ namespace JS { +class JS_PUBLIC_API AutoGCRooter; + +// Our instantiations of Rooted and PersistentRooted require an +// instantiation of MapTypeToRootKind. +template <> +struct MapTypeToRootKind { + static const RootKind kind = RootKind::Traceable; +}; + +using RootedListHeads = + mozilla::EnumeratedArray*>; + +// Superclass of JSContext which can be used for rooting data in use by the +// current thread but that does not provide all the functions of a JSContext. +class RootingContext { + // Stack GC roots for Rooted GC heap pointers. + RootedListHeads stackRoots_; + template + friend class JS::Rooted; + + // Stack GC roots for AutoFooRooter classes. + JS::AutoGCRooter* autoGCRooters_; + friend class JS::AutoGCRooter; + + // Gecko profiling metadata. + // This isn't really rooting related. It's only here because we want + // GetContextProfilingStack to be inlineable into non-JS code, and we + // didn't want to add another superclass of JSContext just for this. + js::GeckoProfilerThread geckoProfiler_; + + public: + RootingContext(); + + void traceStackRoots(JSTracer* trc); + void checkNoGCRooters(); + + js::GeckoProfilerThread& geckoProfiler() { return geckoProfiler_; } + + protected: + // The remaining members in this class should only be accessed through + // JSContext pointers. They are unrelated to rooting and are in place so + // that inlined API functions can directly access the data. + + /* The current compartment. */ + JSCompartment* compartment_; + + /* The current zone. */ + JS::Zone* zone_; + + public: + /* Limit pointer for checking native stack consumption. */ + uintptr_t nativeStackLimit[StackKindCount]; + + static const RootingContext* get(const JSContext* cx) { + return reinterpret_cast(cx); + } + + static RootingContext* get(JSContext* cx) { + return reinterpret_cast(cx); + } + + friend JSCompartment* js::GetContextCompartment(const JSContext* cx); + friend JS::Zone* js::GetContextZone(const JSContext* cx); +}; + +class JS_PUBLIC_API AutoGCRooter { + public: + AutoGCRooter(JSContext* cx, ptrdiff_t tag) + : AutoGCRooter(JS::RootingContext::get(cx), tag) {} + AutoGCRooter(JS::RootingContext* cx, ptrdiff_t tag) + : down(cx->autoGCRooters_), tag_(tag), stackTop(&cx->autoGCRooters_) { + MOZ_ASSERT(this != *stackTop); + *stackTop = this; + } + + ~AutoGCRooter() { + MOZ_ASSERT(this == *stackTop); + *stackTop = down; + } + + /* Implemented in gc/RootMarking.cpp. */ + inline void trace(JSTracer* trc); + static void traceAll(const js::CooperatingContext& target, JSTracer* trc); + static void traceAllWrappers(const js::CooperatingContext& target, + JSTracer* trc); + + protected: + AutoGCRooter* const down; + + /* + * Discriminates actual subclass of this being used. If non-negative, the + * subclass roots an array of values of the length stored in this field. + * If negative, meaning is indicated by the corresponding value in the enum + * below. Any other negative value indicates some deeper problem such as + * memory corruption. + */ + ptrdiff_t tag_; + + enum { + VALARRAY = -2, /* js::AutoValueArray */ + PARSER = -3, /* js::frontend::Parser */ +#if defined(JS_BUILD_BINAST) + BINPARSER = -4, /* js::frontend::BinSource */ +#endif // defined(JS_BUILD_BINAST) + IONMASM = -19, /* js::jit::MacroAssembler */ + WRAPVECTOR = -20, /* js::AutoWrapperVector */ + WRAPPER = -21, /* js::AutoWrapperRooter */ + CUSTOM = -26 /* js::CustomAutoRooter */ + }; + + private: + AutoGCRooter** const stackTop; + + /* No copy or assignment semantics. */ + AutoGCRooter(AutoGCRooter& ida) = delete; + void operator=(AutoGCRooter& ida) = delete; +}; + +namespace detail { + +/* + * For pointer types, the TraceKind for tracing is based on the list it is + * 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. + */ +template +using MaybeWrapped = + typename mozilla::Conditional::kind == + JS::RootKind::Traceable, + js::DispatchWrapper, T>::Type; + +} /* namespace detail */ + /** * Local variable of type T whose value is always rooted. This is typically * used for local variables, or for non-rooted values being passed to a @@ -754,96 +919,100 @@ * specialization, define a RootedBase specialization containing them. */ template -class MOZ_RAII Rooted : public js::RootedBase -{ - 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(GCPolicy::initial()) - { - registerWithRootLists(rootLists(cx)); - } +class MOZ_RAII Rooted : public js::RootedBase> { + inline void registerWithRootLists(RootedListHeads& roots) { + this->stack = &roots[JS::MapTypeToRootKind::kind]; + this->prev = *stack; + *stack = reinterpret_cast*>(this); + } + + inline RootedListHeads& rootLists(RootingContext* cx) { + return cx->stackRoots_; + } + inline RootedListHeads& rootLists(JSContext* cx) { + return rootLists(RootingContext::get(cx)); + } + + public: + using ElementType = T; + + template + explicit Rooted(const RootingContext& cx) : ptr(GCPolicy::initial()) { + registerWithRootLists(rootLists(cx)); + } + + template + Rooted(const RootingContext& cx, S&& initial) + : ptr(mozilla::Forward(initial)) { + MOZ_ASSERT(GCPolicy::isValid(ptr)); + registerWithRootLists(rootLists(cx)); + } + + ~Rooted() { + MOZ_ASSERT(*stack == reinterpret_cast*>(this)); + *stack = prev; + } + + Rooted* previous() { return reinterpret_cast*>(prev); } + + /* + * This method is public for Rooted so that Codegen.py can use a Rooted + * interchangeably with a MutableHandleValue. + */ + void set(const T& value) { + ptr = value; + MOZ_ASSERT(GCPolicy::isValid(ptr)); + } + void set(T&& value) { + ptr = mozilla::Move(value); + MOZ_ASSERT(GCPolicy::isValid(ptr)); + } + + DECLARE_POINTER_CONSTREF_OPS(T); + DECLARE_POINTER_ASSIGN_OPS(Rooted, T); + DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); + DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr); + + private: + /* + * These need to be templated on void* to avoid aliasing issues between, for + * example, Rooted and Rooted, which use the same + * stack head pointer for different classes. + */ + Rooted** stack; + Rooted* prev; - template - Rooted(const RootingContext& cx, S&& initial) - : ptr(mozilla::Forward(initial)) - { - registerWithRootLists(rootLists(cx)); - } - - ~Rooted() { - MOZ_ASSERT(*stack == reinterpret_cast*>(this)); - *stack = prev; - } - - Rooted* previous() { return reinterpret_cast*>(prev); } - - /* - * This method is public for Rooted so that Codegen.py can use a Rooted - * interchangeably with a MutableHandleValue. - */ - void set(const T& value) { - ptr = value; - } - void set(T&& value) { - ptr = mozilla::Move(value); - } + detail::MaybeWrapped ptr; - DECLARE_POINTER_COMPARISON_OPS(T); - DECLARE_POINTER_CONSTREF_OPS(T); - DECLARE_POINTER_ASSIGN_OPS(Rooted, T); - DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); - DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr); - - private: - /* - * These need to be templated on void* to avoid aliasing issues between, for - * example, Rooted and Rooted, which use the same - * stack head pointer for different classes. - */ - Rooted** stack; - Rooted* prev; - - /* - * For pointer types, the TraceKind for tracing is based on the list it is - * 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< - MapTypeToRootKind::kind == JS::RootKind::Traceable, - js::DispatchWrapper, - T>::Type; - MaybeWrapped ptr; - - Rooted(const Rooted&) = delete; + Rooted(const Rooted&) = delete; } JS_HAZ_ROOTED; } /* namespace JS */ namespace js { +/* + * Inlinable accessors for JSContext. + * + * - These must not be available on the more restricted superclasses of + * JSContext, so we can't simply define them on RootingContext. + * + * - They're perfectly ordinary JSContext functionality, so ought to be + * usable without resorting to jsfriendapi.h, and when JSContext is an + * incomplete type. + */ +inline JSCompartment* GetContextCompartment(const JSContext* cx) { + return JS::RootingContext::get(cx)->compartment_; +} + +inline JS::Zone* GetContextZone(const JSContext* cx) { + return JS::RootingContext::get(cx)->zone_; +} + +inline PseudoStack* GetContextProfilingStack(JSContext* cx) { + return JS::RootingContext::get(cx)->geckoProfiler().getPseudoStack(); +} + /** * Augment the generic Rooted interface when T = JSObject* with * class-querying and downcasting operations. @@ -854,12 +1023,12 @@ * Rooted rooted(cx, &obj->as()); * Handle h = rooted; */ -template <> -class RootedBase -{ - public: - template - JS::Handle as() const; +template +class RootedBase + : public MutableWrappedPtrOperations { + public: + template + JS::Handle as() const; }; /** @@ -872,67 +1041,12 @@ * Rooted rooted(cx, &obj->as()); * Handle h = rooted; */ -template <> -class HandleBase -{ - public: - template - JS::Handle as() const; -}; - -/** Interface substitute for Rooted which does not root the variable's memory. */ -template -class MOZ_RAII FakeRooted : public RootedBase -{ - public: - template - explicit FakeRooted(CX* cx) : ptr(JS::GCPolicy::initial()) {} - - template - FakeRooted(CX* cx, T initial) : ptr(initial) {} - - DECLARE_POINTER_COMPARISON_OPS(T); - DECLARE_POINTER_CONSTREF_OPS(T); - DECLARE_POINTER_ASSIGN_OPS(FakeRooted, T); - DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); - DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr); - - private: - T ptr; - - void set(const T& value) { - ptr = value; - } - - FakeRooted(const FakeRooted&) = delete; -}; - -/** Interface substitute for MutableHandle which is not required to point to rooted memory. */ -template -class FakeMutableHandle : public js::MutableHandleBase -{ - public: - MOZ_IMPLICIT FakeMutableHandle(T* t) { - ptr = t; - } - - MOZ_IMPLICIT FakeMutableHandle(FakeRooted* root) { - ptr = root->address(); - } - - void set(const T& v) { - *ptr = v; - } - - DECLARE_POINTER_CONSTREF_OPS(T); - DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr); - DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr); - - private: - FakeMutableHandle() {} - DELETE_ASSIGNMENT_OPS(FakeMutableHandle, T); - - T* ptr; +template +class HandleBase + : public WrappedPtrOperations { + public: + template + JS::Handle as() const; }; /** @@ -944,103 +1058,80 @@ * which require handle types and are only called in the CanGC case. These * allow the calling code to type check. */ -enum AllowGC { - NoGC = 0, - CanGC = 1 -}; +enum AllowGC { NoGC = 0, CanGC = 1 }; template -class MaybeRooted -{ -}; +class MaybeRooted {}; -template class MaybeRooted -{ - public: - typedef JS::Handle HandleType; - typedef JS::Rooted RootType; - typedef JS::MutableHandle MutableHandleType; - - static inline JS::Handle toHandle(HandleType v) { - return v; - } - - static inline JS::MutableHandle toMutableHandle(MutableHandleType v) { - return v; - } - - template - static inline JS::Handle downcastHandle(HandleType v) { - return v.template as(); - } -}; - -template class MaybeRooted -{ - public: - typedef const T& HandleType; - typedef FakeRooted RootType; - typedef FakeMutableHandle MutableHandleType; +template +class MaybeRooted { + public: + typedef JS::Handle HandleType; + typedef JS::Rooted RootType; + typedef JS::MutableHandle MutableHandleType; - static JS::Handle toHandle(HandleType v) { - MOZ_CRASH("Bad conversion"); - } + static inline JS::Handle toHandle(HandleType v) { return v; } - static JS::MutableHandle toMutableHandle(MutableHandleType v) { - MOZ_CRASH("Bad conversion"); - } + static inline JS::MutableHandle toMutableHandle(MutableHandleType v) { + return v; + } - template - static inline T2* downcastHandle(HandleType v) { - return &v->template as(); - } + template + static inline JS::Handle downcastHandle(HandleType v) { + return v.template as(); + } }; } /* namespace js */ namespace JS { -template template -inline -Handle::Handle(const Rooted& root, - typename mozilla::EnableIf::value, int>::Type dummy) -{ - ptr = reinterpret_cast(root.address()); -} - -template template -inline -Handle::Handle(const PersistentRooted& root, - typename mozilla::EnableIf::value, int>::Type dummy) -{ - ptr = reinterpret_cast(root.address()); -} - -template template -inline -Handle::Handle(MutableHandle& root, - typename mozilla::EnableIf::value, int>::Type dummy) -{ - ptr = reinterpret_cast(root.address()); +template +template +inline Handle::Handle( + const Rooted& root, + typename mozilla::EnableIf::value, int>::Type + dummy) { + ptr = reinterpret_cast(root.address()); +} + +template +template +inline Handle::Handle( + const PersistentRooted& root, + typename mozilla::EnableIf::value, int>::Type + dummy) { + ptr = reinterpret_cast(root.address()); } template -inline -MutableHandle::MutableHandle(Rooted* root) -{ - static_assert(sizeof(MutableHandle) == sizeof(T*), - "MutableHandle must be binary compatible with T*."); - ptr = root->address(); +template +inline Handle::Handle( + MutableHandle& root, + typename mozilla::EnableIf::value, int>::Type + dummy) { + ptr = reinterpret_cast(root.address()); } template -inline -MutableHandle::MutableHandle(PersistentRooted* root) -{ - static_assert(sizeof(MutableHandle) == sizeof(T*), - "MutableHandle must be binary compatible with T*."); - ptr = root->address(); +inline MutableHandle::MutableHandle(Rooted* root) { + static_assert(sizeof(MutableHandle) == sizeof(T*), + "MutableHandle must be binary compatible with T*."); + ptr = root->address(); } +template +inline MutableHandle::MutableHandle(PersistentRooted* root) { + static_assert(sizeof(MutableHandle) == sizeof(T*), + "MutableHandle must be binary compatible with T*."); + ptr = root->address(); +} + +JS_PUBLIC_API void AddPersistentRoot(RootingContext* cx, RootKind kind, + PersistentRooted* root); + +JS_PUBLIC_API void AddPersistentRoot(JSRuntime* rt, RootKind kind, + PersistentRooted* root); + /** * A copyable, assignable global GC root type with arbitrary lifetime, an * infallible constructor, and automatic unrooting on destruction. @@ -1075,227 +1166,207 @@ * containing Heap or TenuredHeap members to make sure their referents get * marked when the object itself is marked. */ -template -class PersistentRooted : public js::PersistentRootedBase, - private mozilla::LinkedListElement> -{ - using ListBase = mozilla::LinkedListElement>; - - friend class mozilla::LinkedList; - friend class mozilla::LinkedListElement; - - void registerWithRootLists(js::RootLists& roots) { - MOZ_ASSERT(!initialized()); - JS::RootKind kind = JS::MapTypeToRootKind::kind; - roots.heapRoots_[kind].insertBack(reinterpret_cast*>(this)); - } - - 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(GCPolicy::initial()) {} - - template - explicit PersistentRooted(const RootingContext& cx) - : ptr(GCPolicy::initial()) - { - registerWithRootLists(rootLists(cx)); - } - - template - PersistentRooted(const RootingContext& cx, U&& initial) - : ptr(mozilla::Forward(initial)) - { - registerWithRootLists(rootLists(cx)); - } - - PersistentRooted(const PersistentRooted& rhs) - : mozilla::LinkedListElement>(), - ptr(rhs.ptr) - { - /* - * Copy construction takes advantage of the fact that the original - * is already inserted, and simply adds itself to whatever list the - * original was on - no JSRuntime pointer needed. - * - * This requires mutating rhs's links, but those should be 'mutable' - * anyway. C++ doesn't let us declare mutable base classes. - */ - const_cast(rhs).setNext(this); - } - - bool initialized() { - return ListBase::isInList(); - } - - template - void init(const RootingContext& cx) { - init(cx, GCPolicy::initial()); - } +template +class PersistentRooted + : public js::RootedBase>, + private mozilla::LinkedListElement> { + using ListBase = mozilla::LinkedListElement>; + + friend class mozilla::LinkedList; + friend class mozilla::LinkedListElement; + + void registerWithRootLists(RootingContext* cx) { + MOZ_ASSERT(!initialized()); + JS::RootKind kind = JS::MapTypeToRootKind::kind; + AddPersistentRoot(cx, kind, + reinterpret_cast*>(this)); + } + + void registerWithRootLists(JSRuntime* rt) { + MOZ_ASSERT(!initialized()); + JS::RootKind kind = JS::MapTypeToRootKind::kind; + AddPersistentRoot(rt, kind, + reinterpret_cast*>(this)); + } + + public: + using ElementType = T; + + PersistentRooted() : ptr(GCPolicy::initial()) {} + + explicit PersistentRooted(RootingContext* cx) : ptr(GCPolicy::initial()) { + registerWithRootLists(cx); + } + + explicit PersistentRooted(JSContext* cx) : ptr(GCPolicy::initial()) { + registerWithRootLists(RootingContext::get(cx)); + } + + template + PersistentRooted(RootingContext* cx, U&& initial) + : ptr(mozilla::Forward(initial)) { + registerWithRootLists(cx); + } + + template + PersistentRooted(JSContext* cx, U&& initial) + : ptr(mozilla::Forward(initial)) { + registerWithRootLists(RootingContext::get(cx)); + } + + explicit PersistentRooted(JSRuntime* rt) : ptr(GCPolicy::initial()) { + registerWithRootLists(rt); + } + + template + PersistentRooted(JSRuntime* rt, U&& initial) + : ptr(mozilla::Forward(initial)) { + registerWithRootLists(rt); + } - template - void init(const RootingContext& cx, U&& initial) { - ptr = mozilla::Forward(initial); - registerWithRootLists(rootLists(cx)); - } + PersistentRooted(const PersistentRooted& rhs) + : mozilla::LinkedListElement>(), ptr(rhs.ptr) { + /* + * Copy construction takes advantage of the fact that the original + * is already inserted, and simply adds itself to whatever list the + * original was on - no JSRuntime pointer needed. + * + * This requires mutating rhs's links, but those should be 'mutable' + * anyway. C++ doesn't let us declare mutable base classes. + */ + const_cast(rhs).setNext(this); + } - void reset() { - if (initialized()) { - set(GCPolicy::initial()); - ListBase::remove(); - } - } + bool initialized() { return ListBase::isInList(); } - DECLARE_POINTER_COMPARISON_OPS(T); - DECLARE_POINTER_CONSTREF_OPS(T); - DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T); - DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); - - // These are the same as DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS, except - // they check that |this| is initialized in case the caller later stores - // something in |ptr|. - T* address() { - MOZ_ASSERT(initialized()); - return &ptr; - } - T& get() { - MOZ_ASSERT(initialized()); - return ptr; - } + void init(JSContext* cx) { init(cx, GCPolicy::initial()); } - private: - template - void set(U&& value) { - MOZ_ASSERT(initialized()); - ptr = mozilla::Forward(value); - } + template + void init(JSContext* cx, U&& initial) { + ptr = mozilla::Forward(initial); + registerWithRootLists(RootingContext::get(cx)); + } + + void reset() { + if (initialized()) { + set(GCPolicy::initial()); + ListBase::remove(); + } + } + + DECLARE_POINTER_CONSTREF_OPS(T); + DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T); + DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); + + // These are the same as DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS, except + // they check that |this| is initialized in case the caller later stores + // something in |ptr|. + T* address() { + MOZ_ASSERT(initialized()); + return &ptr; + } + T& get() { + MOZ_ASSERT(initialized()); + return ptr; + } + + private: + template + void set(U&& value) { + MOZ_ASSERT(initialized()); + ptr = mozilla::Forward(value); + } - // See the comment above Rooted::ptr. - using MaybeWrapped = typename mozilla::Conditional< - MapTypeToRootKind::kind == JS::RootKind::Traceable, - js::DispatchWrapper, - T>::Type; - MaybeWrapped ptr; + detail::MaybeWrapped ptr; } JS_HAZ_ROOTED; -class JS_PUBLIC_API(ObjectPtr) -{ - Heap value; +class JS_PUBLIC_API ObjectPtr { + Heap value; - public: - ObjectPtr() : value(nullptr) {} + public: + using ElementType = JSObject*; - explicit ObjectPtr(JSObject* obj) : value(obj) {} + ObjectPtr() : value(nullptr) {} - ObjectPtr(const ObjectPtr& other) : value(other.value) {} + explicit ObjectPtr(JSObject* obj) : value(obj) {} - ObjectPtr(ObjectPtr&& other) - : value(other.value) - { - other.value = nullptr; - } + ObjectPtr(const ObjectPtr& other) : value(other.value) {} - /* Always call finalize before the destructor. */ - ~ObjectPtr() { MOZ_ASSERT(!value); } + ObjectPtr(ObjectPtr&& other) : value(other.value) { other.value = nullptr; } - void finalize(JSRuntime* rt); - void finalize(JSContext* cx); + /* Always call finalize before the destructor. */ + ~ObjectPtr() { MOZ_ASSERT(!value); } - void init(JSObject* obj) { value = obj; } + void finalize(JSRuntime* rt); + void finalize(JSContext* cx); - JSObject* get() const { return value; } - JSObject* unbarrieredGet() const { return value.unbarrieredGet(); } + void init(JSObject* obj) { value = obj; } - void writeBarrierPre(JSContext* cx) { - IncrementalObjectBarrier(value); - } + JSObject* get() const { return value; } + JSObject* unbarrieredGet() const { return value.unbarrieredGet(); } - void updateWeakPointerAfterGC(); + void writeBarrierPre(JSContext* cx) { IncrementalPreWriteBarrier(value); } - ObjectPtr& operator=(JSObject* obj) { - IncrementalObjectBarrier(value); - value = obj; - return *this; - } + void updateWeakPointerAfterGC(); + + ObjectPtr& operator=(JSObject* obj) { + IncrementalPreWriteBarrier(value); + value = obj; + return *this; + } - void trace(JSTracer* trc, const char* name); + void trace(JSTracer* trc, const char* name); - JSObject& operator*() const { return *value; } - JSObject* operator->() const { return value; } - operator JSObject*() const { return value; } + 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(); } + 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> -{ }; +template +class WrappedPtrOperations, Container> { + 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 MutableWrappedPtrOperations, Container> + : public WrappedPtrOperations, Container> { + 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); } +}; namespace gc { template -void -CallTraceCallbackOnNonHeap(T* v, const TraceCallbacks& aCallbacks, const char* aName, void* aClosure) -{ - static_assert(sizeof(T) == sizeof(JS::Heap), "T and Heap must be compatible."); - MOZ_ASSERT(v); - mozilla::DebugOnly cell = BarrierMethods::asGCThingOrNull(*v); - MOZ_ASSERT(cell); - MOZ_ASSERT(!IsInsideNursery(cell)); - JS::Heap* asHeapT = reinterpret_cast*>(v); - aCallbacks.Trace(asHeapT, aName, aClosure); +void CallTraceCallbackOnNonHeap(T* v, const TraceCallbacks& aCallbacks, + const char* aName, void* aClosure) { + static_assert(sizeof(T) == sizeof(JS::Heap), + "T and Heap must be compatible."); + MOZ_ASSERT(v); + mozilla::DebugOnly cell = BarrierMethods::asGCThingOrNull(*v); + MOZ_ASSERT(cell); + MOZ_ASSERT(!IsInsideNursery(cell)); + JS::Heap* asHeapT = reinterpret_cast*>(v); + aCallbacks.Trace(asHeapT, aName, aClosure); } } /* namespace gc */ @@ -1306,25 +1377,225 @@ namespace mozilla { template -inline void -Swap(JS::Heap& aX, JS::Heap& aY) -{ - T tmp = aX; - aX = aY; - aY = tmp; +inline void Swap(JS::Heap& aX, JS::Heap& aY) { + T tmp = aX; + aX = aY; + aY = tmp; } template -inline void -Swap(JS::TenuredHeap& aX, JS::TenuredHeap& aY) -{ - T tmp = aX; - aX = aY; - aY = tmp; +inline void Swap(JS::TenuredHeap& aX, JS::TenuredHeap& aY) { + T tmp = aX; + aX = aY; + aY = tmp; } } /* namespace mozilla */ -#undef DELETE_ASSIGNMENT_OPS +namespace js { +namespace detail { + +// DefineComparisonOps is a trait which selects which wrapper classes to define +// operator== and operator!= for. It supplies a getter function to extract the +// value to compare. This is used to avoid triggering the automatic read +// barriers where appropriate. +// +// If DefineComparisonOps is not specialized for a particular wrapper you may +// get errors such as 'invalid operands to binary expression' or 'no match for +// operator==' when trying to compare against instances of the wrapper. + +template +struct DefineComparisonOps : mozilla::FalseType {}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const JS::Heap& v) { return v.unbarrieredGet(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T get(const JS::TenuredHeap& v) { + return v.unbarrieredGetPtr(); + } +}; + +template <> +struct DefineComparisonOps : mozilla::TrueType { + static const JSObject* get(const JS::ObjectPtr& v) { + return v.unbarrieredGet(); + } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const JS::Rooted& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const JS::Handle& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const JS::MutableHandle& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const JS::PersistentRooted& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const js::FakeRooted& v) { return v.get(); } +}; + +template +struct DefineComparisonOps> : mozilla::TrueType { + static const T& get(const js::FakeMutableHandle& v) { return v.get(); } +}; + +} /* namespace detail */ +} /* namespace js */ + +// Overload operator== and operator!= for all types with the DefineComparisonOps +// trait using the supplied getter. +// +// There are four cases: + +// Case 1: comparison between two wrapper objects. + +template +typename mozilla::EnableIf::value && + js::detail::DefineComparisonOps::value, + bool>::Type +operator==(const T& a, const U& b) { + return js::detail::DefineComparisonOps::get(a) == + js::detail::DefineComparisonOps::get(b); +} + +template +typename mozilla::EnableIf::value && + js::detail::DefineComparisonOps::value, + bool>::Type +operator!=(const T& a, const U& b) { + return !(a == b); +} + +// Case 2: comparison between a wrapper object and its unwrapped element type. + +template +typename mozilla::EnableIf::value, + bool>::Type +operator==(const T& a, const typename T::ElementType& b) { + return js::detail::DefineComparisonOps::get(a) == b; +} + +template +typename mozilla::EnableIf::value, + bool>::Type +operator!=(const T& a, const typename T::ElementType& b) { + return !(a == b); +} + +template +typename mozilla::EnableIf::value, + bool>::Type +operator==(const typename T::ElementType& a, const T& b) { + return a == js::detail::DefineComparisonOps::get(b); +} + +template +typename mozilla::EnableIf::value, + bool>::Type +operator!=(const typename T::ElementType& a, const T& b) { + return !(a == b); +} + +// Case 3: For pointer wrappers, comparison between the wrapper and a const +// element pointer. + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator==( + const typename mozilla::RemovePointer::Type* a, + const T& b) { + return a == js::detail::DefineComparisonOps::get(b); +} + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator!=( + const typename mozilla::RemovePointer::Type* a, + const T& b) { + return !(a == b); +} + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator==( + const T& a, + const typename mozilla::RemovePointer::Type* b) { + return js::detail::DefineComparisonOps::get(a) == b; +} + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator!=( + const T& a, + const typename mozilla::RemovePointer::Type* b) { + return !(a == b); +} + +// Case 4: For pointer wrappers, comparison between the wrapper and nullptr. + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator==(std::nullptr_t a, const T& b) { + return a == js::detail::DefineComparisonOps::get(b); +} + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator!=(std::nullptr_t a, const T& b) { + return !(a == b); +} + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator==(const T& a, std::nullptr_t b) { + return js::detail::DefineComparisonOps::get(a) == b; +} + +template +typename mozilla::EnableIf< + js::detail::DefineComparisonOps::value && + mozilla::IsPointer::value, + bool>::Type +operator!=(const T& a, std::nullptr_t b) { + return !(a == b); +} -#endif /* js_RootingAPI_h */ +#endif /* js_RootingAPI_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/SliceBudget.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/SliceBudget.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/SliceBudget.h @@ -9,20 +9,20 @@ #include +#include "jstypes.h" + namespace js { -struct JS_PUBLIC_API(TimeBudget) -{ - int64_t budget; +struct JS_PUBLIC_API TimeBudget { + int64_t budget; - explicit TimeBudget(int64_t milliseconds) { budget = milliseconds; } + explicit TimeBudget(int64_t milliseconds) { budget = milliseconds; } }; -struct JS_PUBLIC_API(WorkBudget) -{ - int64_t budget; +struct JS_PUBLIC_API WorkBudget { + int64_t budget; - explicit WorkBudget(int64_t work) { budget = work; } + explicit WorkBudget(int64_t work) { budget = work; } }; /* @@ -31,61 +31,57 @@ * to run for unlimited time, and others are bounded. To reduce the number of * gettimeofday calls, we only check the time every 1000 operations. */ -class JS_PUBLIC_API(SliceBudget) -{ - static const int64_t unlimitedDeadline = INT64_MAX; - static const intptr_t unlimitedStartCounter = INTPTR_MAX; +class JS_PUBLIC_API SliceBudget { + static const int64_t unlimitedDeadline = INT64_MAX; + static const intptr_t unlimitedStartCounter = INTPTR_MAX; - bool checkOverBudget(); + bool checkOverBudget(); - SliceBudget(); + SliceBudget(); - public: - // Memory of the originally requested budget. If isUnlimited, neither of - // these are in use. If deadline==0, then workBudget is valid. Otherwise - // timeBudget is valid. - TimeBudget timeBudget; - WorkBudget workBudget; + public: + // Memory of the originally requested budget. If isUnlimited, neither of + // these are in use. If deadline==0, then workBudget is valid. Otherwise + // timeBudget is valid. + TimeBudget timeBudget; + WorkBudget workBudget; - int64_t deadline; /* in microseconds */ - intptr_t counter; + int64_t deadline; /* in microseconds */ + intptr_t counter; - static const intptr_t CounterReset = 1000; + static const intptr_t CounterReset = 1000; - static const int64_t UnlimitedTimeBudget = -1; - static const int64_t UnlimitedWorkBudget = -1; + static const int64_t UnlimitedTimeBudget = -1; + static const int64_t UnlimitedWorkBudget = -1; - /* Use to create an unlimited budget. */ - static SliceBudget unlimited() { return SliceBudget(); } + /* Use to create an unlimited budget. */ + static SliceBudget unlimited() { return SliceBudget(); } - /* Instantiate as SliceBudget(TimeBudget(n)). */ - explicit SliceBudget(TimeBudget time); + /* Instantiate as SliceBudget(TimeBudget(n)). */ + explicit SliceBudget(TimeBudget time); - /* Instantiate as SliceBudget(WorkBudget(n)). */ - explicit SliceBudget(WorkBudget work); + /* Instantiate as SliceBudget(WorkBudget(n)). */ + explicit SliceBudget(WorkBudget work); - void makeUnlimited() { - deadline = unlimitedDeadline; - counter = unlimitedStartCounter; - } + void makeUnlimited() { + deadline = unlimitedDeadline; + counter = unlimitedStartCounter; + } - void step(intptr_t amt = 1) { - counter -= amt; - } + void step(intptr_t amt = 1) { counter -= amt; } - bool isOverBudget() { - if (counter > 0) - return false; - return checkOverBudget(); - } + bool isOverBudget() { + if (counter > 0) return false; + return checkOverBudget(); + } - bool isWorkBudget() const { return deadline == 0; } - bool isTimeBudget() const { return deadline > 0 && !isUnlimited(); } - bool isUnlimited() const { return deadline == unlimitedDeadline; } + bool isWorkBudget() const { return deadline == 0; } + bool isTimeBudget() const { return deadline > 0 && !isUnlimited(); } + bool isUnlimited() const { return deadline == unlimitedDeadline; } - int describe(char* buffer, size_t maxlen) const; + int describe(char* buffer, size_t maxlen) const; }; -} // namespace js +} // namespace js #endif /* js_SliceBudget_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Stream.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Stream.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Stream.h @@ -0,0 +1,516 @@ +/* -*- 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/. */ + +/* + * JSAPI functions and callbacks related to WHATWG Stream objects. + * + * Much of the API here mirrors the JS API of ReadableStream and associated + * classes, e.g. ReadableStreamDefaultReader, ReadableStreamBYOBReader, + * ReadableStreamDefaultController, ReadableByteStreamController, and + * ReadableStreamBYOBRequest. + * + * There are some crucial differences, though: Functionality that's exposed + * as methods/accessors on controllers in JS is exposed as functions taking + * ReadableStream instances instead. This is because an analysis of how + * the API would be used showed that all functions that'd take controllers + * would do so by first getting the controller from the stream instance it's + * associated with and then call the function taking it. I.e., it would purely + * add boilerplate without any gains in ease of use of the API. + * + * It would probably still make sense to factor the API the same as the JS API + * if we had to keep any API stability guarantees: the JS API won't change, so + * we could be sure that the C++ API could stay the same, too. Given that we + * don't guarantee API stability, this concern isn't too pressing. + * + * Some functions exposed here deal with ReadableStream instances that have an + * embedding-provided underlying source. These instances are largely similar + * to byte streams as created using |new ReadableStream({type: "bytes"})|: + * They enable users to acquire ReadableStreamBYOBReaders and only vend chunks + * that're typed array instances. + * + * When creating an "external readable stream" using + * JS::NewReadableExternalSourceStreamObject, an underlying source and a set + * of flags can be passed to be stored on the stream. The underlying source is + * treated as an opaque void* pointer by the JS engine: it's purely meant as + * a reference to be used by the embedding to identify whatever actual source + * it uses to supply data for the stream. Similarly, the flags aren't + * interpreted by the JS engine, but are passed to some of the callbacks below + * and can be retrieved using JS::ReadableStreamGetEmbeddingFlags. + * + * External readable streams are optimized to allow the embedding to interact + * with them with a minimum of overhead: chunks aren't enqueued as individual + * typed array instances; instead, the embedding only updates the amount of + * data available using ReadableStreamUpdateDataAvailableFromSource. + * When content requests data by reading from a reader, + * WriteIntoReadRequestBufferCallback is invoked, asking the embedding to + * write data directly into the buffer we're about to hand to content. + * + * Additionally, ReadableStreamGetExternalUnderlyingSource can be used to + * get the void* pointer to the underlying source. This is equivalent to + * acquiring a reader for the stream in that it locks the stream until it + * is released again using JS::ReadableStreamReleaseExternalUnderlyingSource. + * + * Embeddings are expected to detect situations where an API exposed to JS + * takes a ReadableStream to read from that has an external underlying source. + * In those situations, it might be preferable to directly perform data + * transfers from the stream's underlying source to whatever sink the + * embedding uses, assuming that such direct transfers can be performed + * more efficiently. + * + * An example of such an optimized operation might be a ServiceWorker piping a + * fetch Response body to a TextDecoder: instead of writing chunks of data + * into JS typed array buffers only to immediately read from them again, the + * embedding can presumably directly feed the incoming data to the + * TextDecoder's underlying implementation. + */ + +#ifndef js_Stream_h +#define js_Stream_h + +#include "jstypes.h" + +#include "js/TypeDecls.h" + +namespace JS { + +/** + * Invoked whenever a reader desires more data from a ReadableStream's + * embedding-provided underlying source. + * + * The given |desiredSize| is the absolute size, not a delta from the previous + * desired size. + */ +typedef void (*RequestReadableStreamDataCallback)(JSContext* cx, + HandleObject stream, + void* underlyingSource, + uint8_t flags, + size_t desiredSize); + +/** + * Invoked to cause the embedding to fill the given |buffer| with data from + * the given embedding-provided underlying source. + * + * This can only happen after the embedding has updated the amount of data + * available using JS::ReadableStreamUpdateDataAvailableFromSource. If at + * least one read request is pending when + * JS::ReadableStreamUpdateDataAvailableFromSource is called, + * the WriteIntoReadRequestBufferCallback is invoked immediately from under + * the call to JS::WriteIntoReadRequestBufferCallback. If not, it is invoked + * if and when a new read request is made. + * + * Note: This callback *must not cause GC*, because that could potentially + * invalidate the |buffer| pointer. + */ +typedef void (*WriteIntoReadRequestBufferCallback)( + JSContext* cx, HandleObject stream, void* underlyingSource, uint8_t flags, + void* buffer, size_t length, size_t* bytesWritten); + +/** + * Invoked in reaction to the ReadableStream being canceled to allow the + * embedding to free the underlying source. + * + * This is equivalent to calling |cancel| on non-external underlying sources + * provided to the ReadableStream constructor in JavaScript. + * + * The given |reason| is the JS::Value that was passed as an argument to + * ReadableStream#cancel(). + * + * The returned JS::Value will be used to resolve the Promise returned by + * ReadableStream#cancel(). + */ +typedef Value (*CancelReadableStreamCallback)(JSContext* cx, + HandleObject stream, + void* underlyingSource, + uint8_t flags, + HandleValue reason); + +/** + * Invoked in reaction to a ReadableStream with an embedding-provided + * underlying source being closed. + */ +typedef void (*ReadableStreamClosedCallback)(JSContext* cx, HandleObject stream, + void* underlyingSource, + uint8_t flags); + +/** + * Invoked in reaction to a ReadableStream with an embedding-provided + * underlying source being errored with the + * given reason. + */ +typedef void (*ReadableStreamErroredCallback)(JSContext* cx, + HandleObject stream, + void* underlyingSource, + uint8_t flags, + HandleValue reason); + +/** + * Invoked in reaction to a ReadableStream with an embedding-provided + * underlying source being finalized. Only the underlying source is passed + * as an argument, while the ReadableStream itself is not to prevent the + * embedding from operating on a JSObject that might not be in a valid state + * anymore. + * + * Note: the ReadableStream might be finalized on a background thread. That + * means this callback might be invoked from an arbitrary thread, which the + * embedding must be able to handle. + */ +typedef void (*ReadableStreamFinalizeCallback)(void* underlyingSource, + uint8_t flags); + +/** + * Sets runtime-wide callbacks to use for interacting with embedding-provided + * hooks for operating on ReadableStream instances. + * + * See the documentation for the individual callback types for details. + */ +extern JS_PUBLIC_API void SetReadableStreamCallbacks( + JSContext* cx, RequestReadableStreamDataCallback dataRequestCallback, + WriteIntoReadRequestBufferCallback writeIntoReadRequestCallback, + CancelReadableStreamCallback cancelCallback, + ReadableStreamClosedCallback closedCallback, + ReadableStreamErroredCallback erroredCallback, + ReadableStreamFinalizeCallback finalizeCallback); + +extern JS_PUBLIC_API bool HasReadableStreamCallbacks(JSContext* cx); + +/** + * Returns a new instance of the ReadableStream builtin class in the current + * compartment, configured as a default stream. + * If a |proto| is passed, that gets set as the instance's [[Prototype]] + * instead of the original value of |ReadableStream.prototype|. + */ +extern JS_PUBLIC_API JSObject* NewReadableDefaultStreamObject( + JSContext* cx, HandleObject underlyingSource = nullptr, + HandleFunction size = nullptr, double highWaterMark = 1, + HandleObject proto = nullptr); + +/** + * Returns a new instance of the ReadableStream builtin class in the current + * compartment, configured as a byte stream. + * If a |proto| is passed, that gets set as the instance's [[Prototype]] + * instead of the original value of |ReadableStream.prototype|. + */ +extern JS_PUBLIC_API JSObject* NewReadableByteStreamObject( + JSContext* cx, HandleObject underlyingSource = nullptr, + double highWaterMark = 0, HandleObject proto = nullptr); + +/** + * Returns a new instance of the ReadableStream 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 + * |ReadableStream.prototype|. + * + * The instance is optimized for operating as a byte stream backed by an + * embedding-provided underlying source, using the callbacks set via + * |JS::SetReadableStreamCallbacks|. + * + * The given |flags| will be passed to all applicable callbacks and can be + * used to disambiguate between different types of stream sources the + * embedding might support. + * + * Note: the embedding is responsible for ensuring that the pointer to the + * underlying source stays valid as long as the stream can be read from. + * The underlying source can be freed if the tree is canceled or errored. + * It can also be freed if the stream is destroyed. The embedding is notified + * of that using ReadableStreamFinalizeCallback. + */ +extern JS_PUBLIC_API JSObject* NewReadableExternalSourceStreamObject( + JSContext* cx, void* underlyingSource, uint8_t flags = 0, + HandleObject proto = nullptr); + +/** + * Returns the flags that were passed to NewReadableExternalSourceStreamObject + * when creating the given stream. + * + * Asserts that the given stream has an embedding-provided underlying source. + */ +extern JS_PUBLIC_API uint8_t +ReadableStreamGetEmbeddingFlags(const JSObject* stream); + +/** + * Returns the embedding-provided underlying source of the given |stream|. + * + * Can be used to optimize operations if both the underlying source and the + * intended sink are embedding-provided. In that case it might be + * preferrable to pipe data directly from source to sink without interacting + * with the stream at all. + * + * Locks the stream until ReadableStreamReleaseExternalUnderlyingSource is + * called. + * + * Throws an exception if the stream is locked, i.e. if a reader has been + * acquired for the stream, or if ReadableStreamGetExternalUnderlyingSource + * has been used previously without releasing the external source again. + * + * Throws an exception if the stream isn't readable, i.e if it is errored or + * closed. This is different from ReadableStreamGetReader because we don't + * have a Promise to resolve/reject, which a reader provides. + * + * Asserts that the stream has an embedding-provided underlying source. + */ +extern JS_PUBLIC_API bool ReadableStreamGetExternalUnderlyingSource( + JSContext* cx, HandleObject stream, void** source); + +/** + * Releases the embedding-provided underlying source of the given |stream|, + * returning the stream into an unlocked state. + * + * Asserts that the stream was locked through + * ReadableStreamGetExternalUnderlyingSource. + * + * Asserts that the stream has an embedding-provided underlying source. + */ +extern JS_PUBLIC_API void ReadableStreamReleaseExternalUnderlyingSource( + JSObject* stream); + +/** + * Update the amount of data available at the underlying source of the given + * |stream|. + * + * Can only be used for streams with an embedding-provided underlying source. + * The JS engine will use the given value to satisfy read requests for the + * stream by invoking the JS::WriteIntoReadRequestBuffer callback. + */ +extern JS_PUBLIC_API bool ReadableStreamUpdateDataAvailableFromSource( + JSContext* cx, HandleObject stream, uint32_t availableData); + +/** + * Returns true if the given object is an unwrapped ReadableStream object, + * false otherwise. + */ +extern JS_PUBLIC_API bool IsReadableStream(const JSObject* obj); + +/** + * Returns true if the given object is an unwrapped + * ReadableStreamDefaultReader or ReadableStreamBYOBReader object, + * false otherwise. + */ +extern JS_PUBLIC_API bool IsReadableStreamReader(const JSObject* obj); + +/** + * Returns true if the given object is an unwrapped + * ReadableStreamDefaultReader object, false otherwise. + */ +extern JS_PUBLIC_API bool IsReadableStreamDefaultReader(const JSObject* obj); + +/** + * Returns true if the given object is an unwrapped + * ReadableStreamBYOBReader object, false otherwise. + */ +extern JS_PUBLIC_API bool IsReadableStreamBYOBReader(const JSObject* obj); + +enum class ReadableStreamMode { Default, Byte, ExternalSource }; + +/** + * Returns the stream's ReadableStreamMode. If the mode is |Byte| or + * |ExternalSource|, it's possible to acquire a BYOB reader for more optimized + * operations. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API ReadableStreamMode +ReadableStreamGetMode(const JSObject* stream); + +enum class ReadableStreamReaderMode { Default, BYOB }; + +/** + * Returns true if the given ReadableStream is readable, false if not. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API bool ReadableStreamIsReadable(const JSObject* stream); + +/** + * Returns true if the given ReadableStream is locked, false if not. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API bool ReadableStreamIsLocked(const JSObject* stream); + +/** + * Returns true if the given ReadableStream is disturbed, false if not. + * + * Asserts that |stream| is an ReadableStream instance. + */ +extern JS_PUBLIC_API bool ReadableStreamIsDisturbed(const JSObject* stream); + +/** + * Cancels the given ReadableStream with the given reason and returns a + * Promise resolved according to the result. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API JSObject* ReadableStreamCancel(JSContext* cx, + HandleObject stream, + HandleValue reason); + +/** + * Creates a reader of the type specified by the mode option and locks the + * stream to the new reader. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API JSObject* ReadableStreamGetReader( + JSContext* cx, HandleObject stream, ReadableStreamReaderMode mode); + +/** + * Tees the given ReadableStream and stores the two resulting streams in + * outparams. Returns false if the operation fails, e.g. because the stream is + * locked. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API bool ReadableStreamTee(JSContext* cx, HandleObject stream, + MutableHandleObject branch1Stream, + MutableHandleObject branch2Stream); + +/** + * Retrieves the desired combined size of additional chunks to fill the given + * ReadableStream's queue. Stores the result in |value| and sets |hasValue| to + * true on success, returns false on failure. + * + * If the stream is errored, the call will succeed but no value will be stored + * in |value| and |hasValue| will be set to false. + * + * Note: This is semantically equivalent to the |desiredSize| getter on + * the stream controller's prototype in JS. We expose it with the stream + * itself as a target for simplicity. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API void ReadableStreamGetDesiredSize(JSObject* stream, + bool* hasValue, + double* value); + +/** + * Closes the given ReadableStream. + * + * Throws a TypeError and returns false if the closing operation fails. + * + * Note: This is semantically equivalent to the |close| method on + * the stream controller's prototype in JS. We expose it with the stream + * itself as a target for simplicity. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API bool ReadableStreamClose(JSContext* cx, + HandleObject stream); + +/** + * Returns true if the given ReadableStream reader is locked, false otherwise. + * + * Asserts that |reader| is an unwrapped ReadableStreamDefaultReader or + * ReadableStreamBYOBReader instance. + */ +extern JS_PUBLIC_API bool ReadableStreamReaderIsClosed(const JSObject* reader); + +/** + * Enqueues the given chunk in the given ReadableStream. + * + * Throws a TypeError and returns false if the enqueing operation fails. + * + * Note: This is semantically equivalent to the |enqueue| method on + * the stream controller's prototype in JS. We expose it with the stream + * itself as a target for simplicity. + * + * If the ReadableStream has an underlying byte source, the given chunk must + * be a typed array or a DataView. Consider using + * ReadableByteStreamEnqueueBuffer. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API bool ReadableStreamEnqueue(JSContext* cx, + HandleObject stream, + HandleValue chunk); + +/** + * Enqueues the given buffer as a chunk in the given ReadableStream. + * + * Throws a TypeError and returns false if the enqueing operation fails. + * + * Note: This is semantically equivalent to the |enqueue| method on + * the stream controller's prototype in JS. We expose it with the stream + * itself as a target for simplicity. Additionally, the JS version only + * takes typed arrays and ArrayBufferView instances as arguments, whereas + * this takes an ArrayBuffer, obviating the need to wrap it into a typed + * array. + * + * Asserts that |stream| is an unwrapped ReadableStream instance and |buffer| + * an unwrapped ArrayBuffer instance. + */ +extern JS_PUBLIC_API bool ReadableByteStreamEnqueueBuffer(JSContext* cx, + HandleObject stream, + HandleObject buffer); + +/** + * Errors the given ReadableStream, causing all future interactions to fail + * with the given error value. + * + * Throws a TypeError and returns false if the erroring operation fails. + * + * Note: This is semantically equivalent to the |error| method on + * the stream controller's prototype in JS. We expose it with the stream + * itself as a target for simplicity. + * + * Asserts that |stream| is an unwrapped ReadableStream instance. + */ +extern JS_PUBLIC_API bool ReadableStreamError(JSContext* cx, + HandleObject stream, + HandleValue error); + +/** + * Cancels the given ReadableStream reader's associated stream. + * + * Throws a TypeError and returns false if the given reader isn't active. + * + * Asserts that |reader| is an unwrapped ReadableStreamDefaultReader or + * ReadableStreamBYOBReader instance. + */ +extern JS_PUBLIC_API bool ReadableStreamReaderCancel(JSContext* cx, + HandleObject reader, + HandleValue reason); + +/** + * Cancels the given ReadableStream reader's associated stream. + * + * Throws a TypeError and returns false if the given reader has pending + * read or readInto (for default or byob readers, respectively) requests. + * + * Asserts that |reader| is an unwrapped ReadableStreamDefaultReader or + * ReadableStreamBYOBReader instance. + */ +extern JS_PUBLIC_API bool ReadableStreamReaderReleaseLock(JSContext* cx, + HandleObject reader); + +/** + * Requests a read from the reader's associated ReadableStream and returns the + * resulting PromiseObject. + * + * Returns a Promise that's resolved with the read result once available or + * rejected immediately if the stream is errored or the operation failed. + * + * Asserts that |reader| is an unwrapped ReadableStreamDefaultReader instance. + */ +extern JS_PUBLIC_API JSObject* ReadableStreamDefaultReaderRead( + JSContext* cx, HandleObject reader); + +/** + * Requests a read from the reader's associated ReadableStream into the given + * ArrayBufferView and returns the resulting PromiseObject. + * + * Returns a Promise that's resolved with the read result once available or + * rejected immediately if the stream is errored or the operation failed. + * + * Asserts that |reader| is an unwrapped ReadableStreamDefaultReader and + * |view| an unwrapped typed array or DataView instance. + */ +extern JS_PUBLIC_API JSObject* ReadableStreamBYOBReaderRead(JSContext* cx, + HandleObject reader, + HandleObject view); + +} // namespace JS + +#endif // js_Realm_h 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 @@ -9,6 +9,7 @@ #include "mozilla/Attributes.h" #include "mozilla/BufferList.h" +#include "mozilla/MemoryReporting.h" #include "mozilla/Move.h" #include @@ -18,110 +19,217 @@ #include "js/RootingAPI.h" #include "js/TypeDecls.h" #include "js/Value.h" +#include "js/Vector.h" + +/* + * API for safe passing of structured data, HTML 2018 Feb 21 section 2.7. + * + * + * This is a serialization scheme for JS values, somewhat like JSON. It + * preserves some aspects of JS objects (strings, numbers, own data properties + * with string keys, array elements) but not others (methods, getters and + * setters, prototype chains). Unlike JSON, structured data: + * + * - can contain cyclic references. + * + * - handles Maps, Sets, and some other object types. + * + * - supports *transferring* objects of certain types from one realm to + * another, rather than cloning them. + * + * - is specified by a living standard, and continues to evolve. + * + * - is encoded in a nonstandard binary format, and is never exposed to Web + * content in its serialized form. It's used internally by the browser to + * send data from one thread/realm/domain to another, not across the + * network. + */ -struct JSRuntime; struct JSStructuredCloneReader; struct JSStructuredCloneWriter; -// API for the HTML5 internal structured cloning algorithm. +/** + * The structured-clone serialization format version number. + * + * When serialized data is stored as bytes, e.g. in your Firefox profile, later + * versions of the engine may have to read it. When you upgrade Firefox, we + * don't crawl through your whole profile converting all saved data from the + * previous version of the serialization format to the latest version. So it is + * normal to have data in old formats stored in your profile. + * + * The JS engine can *write* data only in the current format version. + * + * It can *read* any data written in the current version, and data written for + * DifferentProcess scope in earlier versions. + * + * + * ## When to bump this version number + * + * When making a change so drastic that the JS engine needs to know whether + * it's reading old or new serialized data in order to handle both correctly, + * increment this version number. Make sure the engine can still read all + * old data written with previous versions. + * + * If StructuredClone.cpp doesn't contain code that distinguishes between + * version 8 and version 9, there should not be a version 9. + * + * Do not increment for changes that only affect SameProcess encoding. + * + * Increment only for changes that would otherwise break old serialized data. + * Do not increment for new data types. (Rationale: Modulo bugs, older versions + * of the JS engine can already correctly throw errors when they encounter new, + * unrecognized features. A version number bump does not actually help them.) + */ +#define JS_STRUCTURED_CLONE_VERSION 8 namespace JS { +/** + * Indicates the "scope of validity" of serialized data. + * + * Writing plain JS data produces an array of bytes that can be copied and + * read in another process or whatever. The serialized data is Plain Old Data. + * However, HTML also supports `Transferable` objects, which, when cloned, can + * be moved from the source object into the clone, like when you take a + * photograph of someone and it steals their soul. + * See . + * We support cloning and transferring objects of many types. + * + * For example, when we transfer an ArrayBuffer (within a process), we "detach" + * the ArrayBuffer, embed the raw buffer pointer in the serialized data, and + * later install it in a new ArrayBuffer in the destination realm. Ownership + * of that buffer memory is transferred from the original ArrayBuffer to the + * serialized data and then to the clone. + * + * This only makes sense within a single address space. When we transfer an + * ArrayBuffer to another process, the contents of the buffer must be copied + * into the serialized data. (The original ArrayBuffer is still detached, + * though, for consistency; in some cases the caller shouldn't know or care if + * the recipient is in the same process.) + * + * ArrayBuffers are actually a lucky case; some objects (like MessagePorts) + * can't reasonably be stored by value in serialized data -- it's pointers or + * nothing. + * + * So there is a tradeoff between scope of validity -- how far away the + * serialized data may be sent and still make sense -- and efficiency or + * features. The read and write algorithms therefore take an argument of this + * type, allowing the user to control those trade-offs. + */ 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 + /** + * The most restrictive scope, with greatest efficiency and features. + * + * When writing, this means we're writing for an audience in the same + * process and same thread. The caller promises that the serialized data + * will **not** be shipped off to a different thread/process or stored in a + * database. It's OK to produce serialized data that contains pointers. In + * Rust terms, the serialized data will be treated as `!Send`. + * + * When reading, this means: Accept transferred objects and buffers + * (pointers). The caller promises that the serialized data was written + * using this API (otherwise, the serialized data may contain bogus + * pointers, leading to undefined behavior). + */ + SameProcessSameThread, + + /** + * When writing, this means: The caller promises that the serialized data + * will **not** be shipped off to a different process or stored in a + * database. However, it may be shipped to another thread. It's OK to + * produce serialized data that contains pointers to data that is safe to + * send across threads, such as array buffers. In Rust terms, the + * serialized data will be treated as `Send` but not `Copy`. + * + * When reading, this means the same thing as SameProcessSameThread; + * the distinction only matters when writing. + */ + 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). + * + * When reading, this means: Do not accept pointers. + */ + 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, + /** Transferable data has not been filled in yet */ + SCTAG_TMO_UNFILLED = 0, - /** Structured clone buffer does not yet own the data */ - SCTAG_TMO_UNOWNED = 1, + /** Structured clone buffer does not yet own the data */ + SCTAG_TMO_UNOWNED = 1, - /** All values at least this large are owned by the clone buffer */ - SCTAG_TMO_FIRST_OWNED = 2, + /** All values at least this large are owned by the clone buffer */ + SCTAG_TMO_FIRST_OWNED = 2, - /** Data is a pointer that can be freed */ - SCTAG_TMO_ALLOC_DATA = 2, + /** Data is a pointer that can be freed */ + SCTAG_TMO_ALLOC_DATA = 2, - /** Data is a memory mapped pointer */ - SCTAG_TMO_MAPPED_DATA = 3, + /** Data is a memory mapped pointer */ + 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 = 4, + /** + * 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 = 4, - SCTAG_TMO_USER_MIN + 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; - } +class CloneDataPolicy { + bool sharedArrayBuffer_; - bool isSharedArrayBufferAllowed() const { - return 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. @@ -131,8 +239,10 @@ * from the reader r. closure is any value passed to the JS_ReadStructuredClone * function. Return the new object on success, nullptr on error/exception. */ -typedef JSObject* (*ReadStructuredCloneOp)(JSContext* cx, JSStructuredCloneReader* r, - uint32_t tag, uint32_t data, void* closure); +typedef JSObject* (*ReadStructuredCloneOp)(JSContext* cx, + JSStructuredCloneReader* r, + uint32_t tag, uint32_t data, + void* closure); /** * Structured data serialization hook. The engine can write primitive values, @@ -146,7 +256,8 @@ * * Return true on success, false on error/exception. */ -typedef bool (*WriteStructuredCloneOp)(JSContext* cx, JSStructuredCloneWriter* w, +typedef bool (*WriteStructuredCloneOp)(JSContext* cx, + JSStructuredCloneWriter* w, JS::HandleObject obj, void* closure); /** @@ -163,10 +274,9 @@ * DATA_CLONE_ERR DOM Exception. This method is called before any other * callback and must return a non-null object in returnObject on success. */ -typedef bool (*ReadTransferStructuredCloneOp)(JSContext* cx, JSStructuredCloneReader* r, - uint32_t tag, void* content, uint64_t extraData, - void* closure, - JS::MutableHandleObject returnObject); +typedef bool (*ReadTransferStructuredCloneOp)( + JSContext* cx, JSStructuredCloneReader* r, uint32_t tag, void* content, + uint64_t extraData, void* closure, JS::MutableHandleObject returnObject); /** * Called when JS_WriteStructuredClone receives a transferable object not @@ -189,206 +299,244 @@ // Output: uint32_t* tag, JS::TransferableOwnership* ownership, - void** content, - uint64_t* extraData); + void** content, uint64_t* extraData); /** * 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); - -// The maximum supported structured-clone serialization format version. -// 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 8 +typedef void (*FreeTransferStructuredCloneOp)( + uint32_t tag, JS::TransferableOwnership ownership, void* content, + uint64_t extraData, void* closure); struct JSStructuredCloneCallbacks { - ReadStructuredCloneOp read; - WriteStructuredCloneOp write; - StructuredCloneErrorOp reportError; - ReadTransferStructuredCloneOp readTransfer; - TransferStructuredCloneOp writeTransfer; - FreeTransferStructuredCloneOp freeTransfer; + ReadStructuredCloneOp read; + WriteStructuredCloneOp write; + StructuredCloneErrorOp reportError; + ReadTransferStructuredCloneOp readTransfer; + TransferStructuredCloneOp writeTransfer; + FreeTransferStructuredCloneOp freeTransfer; }; enum OwnTransferablePolicy { - OwnsTransferablesIfAny, - IgnoreTransferablesIfAny, - NoTransferables + OwnsTransferablesIfAny, + IgnoreTransferablesIfAny, + NoTransferables }; +namespace js { +class SharedArrayRawBuffer; + +class JS_PUBLIC_API SharedArrayRawBufferRefs { + public: + SharedArrayRawBufferRefs() = default; + SharedArrayRawBufferRefs(SharedArrayRawBufferRefs&& other) = default; + SharedArrayRawBufferRefs& operator=(SharedArrayRawBufferRefs&& other); + ~SharedArrayRawBufferRefs(); + + MOZ_MUST_USE bool acquire(JSContext* cx, SharedArrayRawBuffer* rawbuf); + MOZ_MUST_USE bool acquireAll(JSContext* cx, + const SharedArrayRawBufferRefs& that); + void takeOwnership(SharedArrayRawBufferRefs&&); + void releaseAll(); + + private: + js::Vector refs_; +}; + +template +struct BufferIterator; +} // namespace js + /** * 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; - } +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_ = nullptr; + void* closure_ = nullptr; + OwnTransferablePolicy ownTransferables_ = + OwnTransferablePolicy::NoTransferables; + js::SharedArrayRawBufferRefs refsHeld_; + + 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 scope) + : bufList_(0, 0, kStandardCapacity, js::SystemAllocPolicy()), + scope_(scope), + 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 scope) + : bufList_(mozilla::Move(buffers)), + scope_(scope), + 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; + } + + bool Init(size_t initialCapacity = 0) { + return bufList_.Init(0, initialCapacity); + } + + JS::StructuredCloneScope scope() const { return scope_; } + + void initScope(JS::StructuredCloneScope scope) { + MOZ_ASSERT(Size() == 0, "initScope() of nonempty JSStructuredCloneData"); + if (scope_ != JS::StructuredCloneScope::Unassigned) + MOZ_ASSERT(scope_ == scope, + "Cannot change scope after it has been initialized"); + scope_ = scope; + } + + 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; + } + + char* AllocateBytes(size_t maxSize, size_t* size) { + return bufList_.AllocateBytes(maxSize, size); + } + + 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); }); + } + + size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) { + return bufList_.SizeOfExcludingThis(mallocSizeOf); + } - // 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(); + void discardTransferables(); }; -/** Note: if the *data contains transferable objects, it can be read only once. */ -JS_PUBLIC_API(bool) -JS_ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data, uint32_t version, - JS::StructuredCloneScope scope, - JS::MutableHandleValue vp, - const JSStructuredCloneCallbacks* optionalCallbacks, void* closure); - -JS_PUBLIC_API(bool) -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_StructuredCloneHasTransferables(JSStructuredCloneData& data, bool* hasTransferable); - -JS_PUBLIC_API(bool) -JS_StructuredClone(JSContext* cx, JS::HandleValue v, JS::MutableHandleValue vp, - const JSStructuredCloneCallbacks* optionalCallbacks, void* closure); +/** + * Implements StructuredDeserialize and StructuredDeserializeWithTransfer. + * + * Note: If `data` contains transferable objects, it can be read only once. + */ +JS_PUBLIC_API bool JS_ReadStructuredClone( + JSContext* cx, JSStructuredCloneData& data, uint32_t version, + JS::StructuredCloneScope scope, JS::MutableHandleValue vp, + const JSStructuredCloneCallbacks* optionalCallbacks, void* closure); + +/** + * Implements StructuredSerialize, StructuredSerializeForStorage, and + * StructuredSerializeWithTransfer. + * + * Note: If the scope is DifferentProcess then the cloneDataPolicy must deny + * shared-memory objects, or an error will be signaled if a shared memory object + * is seen. + */ +JS_PUBLIC_API bool 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_StructuredCloneHasTransferables( + JSStructuredCloneData& data, bool* hasTransferable); + +JS_PUBLIC_API bool JS_StructuredClone( + JSContext* cx, JS::HandleValue v, JS::MutableHandleValue vp, + const JSStructuredCloneCallbacks* optionalCallbacks, void* closure); /** * The C-style API calls to read and write structured clones are fragile -- @@ -402,103 +550,124 @@ * management, and uses the same callbacks for both writing and reading * (serializing and deserializing). */ -class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) { - const JS::StructuredCloneScope scope_; - JSStructuredCloneData data_; - uint32_t version_; - - public: - 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(); } - - JSStructuredCloneData& data() { return data_; } - bool empty() const { return !data_.Size(); } - - void clear(); - - 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(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. - */ - 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() to - * properly release that data eventually. - */ - void abandon() { data_.ownTransferables_ = OwnTransferablePolicy::IgnoreTransferablesIfAny; } - - bool read(JSContext* cx, JS::MutableHandleValue vp, - const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr); - - bool write(JSContext* cx, JS::HandleValue v, - 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: - // Copy and assignment are not supported. - JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer& other) = delete; - JSAutoStructuredCloneBuffer& operator=(const JSAutoStructuredCloneBuffer& other) = delete; +class JS_PUBLIC_API JSAutoStructuredCloneBuffer { + const JS::StructuredCloneScope scope_; + JSStructuredCloneData data_; + uint32_t version_; + + public: + JSAutoStructuredCloneBuffer(JS::StructuredCloneScope scope, + const JSStructuredCloneCallbacks* callbacks, + void* closure) + : scope_(scope), data_(scope), version_(JS_STRUCTURED_CLONE_VERSION) { + data_.setCallbacks(callbacks, closure, + OwnTransferablePolicy::NoTransferables); + } + + JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other); + JSAutoStructuredCloneBuffer& operator=(JSAutoStructuredCloneBuffer&& other); + + ~JSAutoStructuredCloneBuffer() { clear(); } + + JSStructuredCloneData& data() { return data_; } + bool empty() const { return !data_.Size(); } + + void clear(); + + 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(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. + */ + 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() to + * properly release that data eventually. + */ + void abandon() { + data_.ownTransferables_ = OwnTransferablePolicy::IgnoreTransferablesIfAny; + } + + bool read(JSContext* cx, JS::MutableHandleValue vp, + const JSStructuredCloneCallbacks* optionalCallbacks = nullptr, + void* closure = nullptr); + + bool write(JSContext* cx, JS::HandleValue v, + 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); + + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) { + return data_.SizeOfExcludingThis(mallocSizeOf); + } + + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) { + return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf); + } + + private: + // Copy and assignment are not supported. + JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer& other) = + delete; + JSAutoStructuredCloneBuffer& operator=( + const JSAutoStructuredCloneBuffer& other) = delete; }; -// The range of tag values the application may use for its own custom object types. -#define JS_SCTAG_USER_MIN ((uint32_t) 0xFFFF8000) -#define JS_SCTAG_USER_MAX ((uint32_t) 0xFFFFFFFF) +// The range of tag values the application may use for its own custom object +// types. +#define JS_SCTAG_USER_MIN ((uint32_t)0xFFFF8000) +#define JS_SCTAG_USER_MAX ((uint32_t)0xFFFFFFFF) #define JS_SCERR_RECURSION 0 #define JS_SCERR_TRANSFERABLE 1 #define JS_SCERR_DUP_TRANSFERABLE 2 #define JS_SCERR_UNSUPPORTED_TYPE 3 +#define JS_SCERR_SHMEM_TRANSFERABLE 4 -JS_PUBLIC_API(bool) -JS_ReadUint32Pair(JSStructuredCloneReader* r, uint32_t* p1, uint32_t* p2); +JS_PUBLIC_API bool JS_ReadUint32Pair(JSStructuredCloneReader* r, uint32_t* p1, + uint32_t* p2); -JS_PUBLIC_API(bool) -JS_ReadBytes(JSStructuredCloneReader* r, void* p, size_t len); +JS_PUBLIC_API bool JS_ReadBytes(JSStructuredCloneReader* r, void* p, + size_t len); -JS_PUBLIC_API(bool) -JS_ReadTypedArray(JSStructuredCloneReader* r, JS::MutableHandleValue vp); +JS_PUBLIC_API bool JS_ReadTypedArray(JSStructuredCloneReader* r, + JS::MutableHandleValue vp); -JS_PUBLIC_API(bool) -JS_WriteUint32Pair(JSStructuredCloneWriter* w, uint32_t tag, uint32_t data); +JS_PUBLIC_API bool JS_WriteUint32Pair(JSStructuredCloneWriter* w, uint32_t tag, + uint32_t data); -JS_PUBLIC_API(bool) -JS_WriteBytes(JSStructuredCloneWriter* w, const void* p, size_t len); +JS_PUBLIC_API bool JS_WriteBytes(JSStructuredCloneWriter* w, const void* p, + size_t len); -JS_PUBLIC_API(bool) -JS_WriteString(JSStructuredCloneWriter* w, JS::HandleString str); +JS_PUBLIC_API bool JS_WriteString(JSStructuredCloneWriter* w, + JS::HandleString str); -JS_PUBLIC_API(bool) -JS_WriteTypedArray(JSStructuredCloneWriter* w, JS::HandleValue v); +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 bool JS_ObjectNotWritten(JSStructuredCloneWriter* w, + JS::HandleObject obj); -JS_PUBLIC_API(JS::StructuredCloneScope) -JS_GetStructuredCloneScope(JSStructuredCloneWriter* w); +JS_PUBLIC_API JS::StructuredCloneScope JS_GetStructuredCloneScope( + JSStructuredCloneWriter* w); -#endif /* js_StructuredClone_h */ +#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 @@ -9,57 +9,73 @@ #include "js/HeapAPI.h" -namespace js { -template -class WeakCacheBase {}; -} // namespace js - namespace JS { -template class WeakCache; +namespace detail { +class WeakCacheBase; +} // namespace detail namespace shadow { -JS_PUBLIC_API(void) -RegisterWeakCache(JS::Zone* zone, JS::WeakCache* cachep); -} // namespace shadow +JS_PUBLIC_API void RegisterWeakCache(JS::Zone* zone, + JS::detail::WeakCacheBase* cachep); +JS_PUBLIC_API void RegisterWeakCache(JSRuntime* rt, + JS::detail::WeakCacheBase* cachep); +} // namespace shadow + +namespace detail { +class WeakCacheBase : public mozilla::LinkedListElement { + WeakCacheBase() = delete; + explicit WeakCacheBase(const WeakCacheBase&) = delete; + + public: + explicit WeakCacheBase(Zone* zone) { shadow::RegisterWeakCache(zone, this); } + explicit WeakCacheBase(JSRuntime* rt) { shadow::RegisterWeakCache(rt, this); } + WeakCacheBase(WeakCacheBase&& other) = default; + virtual ~WeakCacheBase() {} + + virtual size_t sweep() = 0; + virtual bool needsSweep() = 0; + + virtual bool setNeedsIncrementalBarrier(bool needs) { + // Derived classes do not support incremental barriers by default. + return false; + } + virtual bool needsIncrementalBarrier() const { + // Derived classes do not support incremental barriers by default. + return false; + } +}; +} // namespace detail // A WeakCache stores the given Sweepable container and links itself into a -// list of such caches that are swept during each GC. +// list of such caches that are swept during each GC. A WeakCache can be +// specific to a zone, or across a whole runtime, depending on which +// constructor is used. 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; } +class WeakCache : protected detail::WeakCacheBase, + public js::MutableWrappedPtrOperations> { + T cache; + + public: + using Type = T; + + template + explicit WeakCache(Zone* zone, Args&&... args) + : WeakCacheBase(zone), cache(mozilla::Forward(args)...) {} + template + explicit WeakCache(JSRuntime* rt, Args&&... args) + : WeakCacheBase(rt), cache(mozilla::Forward(args)...) {} + + const T& get() const { return cache; } + T& get() { return cache; } + + size_t sweep() override { + GCPolicy::sweep(&cache); + return 0; + } - void sweep() { sweeper(&cache); } + bool needsSweep() override { return cache.needsSweep(); } }; -} // namespace JS +} // namespace JS -#endif // js_SweepingAPI_h +#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 @@ -16,12 +16,13 @@ class BaseShape; class LazyScript; class ObjectGroup; +class RegExpShared; class Shape; class Scope; namespace jit { class JitCode; -} // namespace jit -} // namespace js +} // namespace jit +} // namespace js namespace JS { @@ -34,121 +35,141 @@ // the matching C++ types are exposed, and those that are, are opaque. // // See Value::gcKind() and JSTraceCallback in Tracer.h for more details. -enum class TraceKind -{ - // These trace kinds have a publicly exposed, although opaque, C++ type. - // Note: The order here is determined by our Value packing. Other users - // should sort alphabetically, for consistency. - Object = 0x00, - String = 0x01, - Symbol = 0x02, - Script = 0x03, - - // Shape details are exposed through JS_TraceShapeCycleCollectorChildren. - Shape = 0x04, - - // ObjectGroup details are exposed through JS_TraceObjectGroupCycleCollectorChildren. - ObjectGroup = 0x05, - - // The kind associated with a nullptr. - Null = 0x06, - - // The following kinds do not have an exposed C++ idiom. - BaseShape = 0x0F, - JitCode = 0x1F, - LazyScript = 0x2F, - Scope = 0x3F +enum class TraceKind { + // These trace kinds have a publicly exposed, although opaque, C++ type. + // Note: The order here is determined by our Value packing. Other users + // should sort alphabetically, for consistency. + Object = 0x00, + String = 0x02, + Symbol = 0x03, + + // 0x1 is not used for any GCThing Value tag, so we use it for Script. + Script = 0x01, + + // Shape details are exposed through JS_TraceShapeCycleCollectorChildren. + Shape = 0x04, + + // ObjectGroup details are exposed through + // JS_TraceObjectGroupCycleCollectorChildren. + ObjectGroup = 0x05, + + // The kind associated with a nullptr. + Null = 0x06, + + // The following kinds do not have an exposed C++ idiom. + BaseShape = 0x0F, + JitCode = 0x1F, + LazyScript = 0x2F, + Scope = 0x3F, + RegExpShared = 0x4F }; 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"); + +#define ASSERT_TRACE_KIND(tk) \ + static_assert( \ + (uintptr_t(tk) & OutOfLineTraceKindMask) == OutOfLineTraceKindMask, \ + "mask bits are set") +ASSERT_TRACE_KIND(JS::TraceKind::BaseShape); +ASSERT_TRACE_KIND(JS::TraceKind::JitCode); +ASSERT_TRACE_KIND(JS::TraceKind::LazyScript); +ASSERT_TRACE_KIND(JS::TraceKind::Scope); +ASSERT_TRACE_KIND(JS::TraceKind::RegExpShared); +#undef ASSERT_TRACE_KIND // 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; + 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) \ - D(Shape, js::Shape, true) \ - D(String, JSString, false) \ - D(Symbol, JS::Symbol, false) +#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) \ + D(Shape, js::Shape, true) \ + D(String, JSString, false) \ + D(Symbol, JS::Symbol, false) \ + D(RegExpShared, js::RegExpShared, true) // 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; \ - }; +#define JS_EXPAND_DEF(name, type, _) \ + template <> \ + struct MapTypeToTraceKind { \ + static const JS::TraceKind kind = JS::TraceKind::name; \ + }; 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) +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, + // These tagged pointers are special-cased for performance. + Id, + Value, - // Everything else. - Traceable, + // Everything else. + Traceable, - Limit + 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; \ - }; +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 +// Cell 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; + static const JS::RootKind kind = JS::RootKind::Traceable; }; template struct MapTypeToRootKind { - static const JS::RootKind kind = - JS::MapTraceKindToRootKind::kind>::kind; + static const JS::RootKind kind = + JS::MapTraceKindToRootKind::kind>::kind; +}; +template <> +struct MapTypeToRootKind { + // Not a pointer to a GC cell. Use GCPolicy. + static const JS::RootKind kind = JS::RootKind::Traceable; }; template struct MapTypeToRootKind> { - static const JS::RootKind kind = JS::MapTypeToRootKind::kind; + 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::Value; +}; +template <> +struct MapTypeToRootKind { + static const JS::RootKind kind = JS::RootKind::Id; }; -template <> struct MapTypeToRootKind { - static const JS::RootKind kind = JS::RootKind::Id; -}; -template <> struct MapTypeToRootKind : public MapTypeToRootKind {}; +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 @@ -164,49 +185,49 @@ // type designated by |traceKind| as the functor's template argument. The // |thing| parameter is optional; without it, we simply pass through |... args|. -// GCC and Clang require an explicit template declaration in front of the -// specialization of operator() because it is a dependent template. MSVC, on -// the other hand, gets very confused if we have a |template| token there. +// VS2017+, GCC and Clang require an explicit template declaration in front of +// the specialization of operator() because it is a dependent template. VS2015, +// on the other hand, gets very confused if we have a |template| token there. // The clang-cl front end defines _MSC_VER, but still requires the explicit // template declaration, so we must test for __clang__ here as well. -#if defined(_MSC_VER) && !defined(__clang__) -# define JS_DEPENDENT_TEMPLATE_HINT +#if (defined(_MSC_VER) && _MSC_VER < 1910) && !defined(__clang__) +#define JS_DEPENDENT_TEMPLATE_HINT #else -# define JS_DEPENDENT_TEMPLATE_HINT template +#define JS_DEPENDENT_TEMPLATE_HINT template #endif template -auto -DispatchTraceKindTyped(F f, JS::TraceKind traceKind, Args&&... args) - -> decltype(f. JS_DEPENDENT_TEMPLATE_HINT operator()(mozilla::Forward(args)...)) -{ - switch (traceKind) { -#define JS_EXPAND_DEF(name, type, _) \ - case JS::TraceKind::name: \ - return f. JS_DEPENDENT_TEMPLATE_HINT operator()(mozilla::Forward(args)...); - JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); +auto DispatchTraceKindTyped(F f, JS::TraceKind traceKind, Args&&... args) + -> decltype(f.JS_DEPENDENT_TEMPLATE_HINT operator()( + mozilla::Forward(args)...)) { + switch (traceKind) { +#define JS_EXPAND_DEF(name, type, _) \ + case JS::TraceKind::name: \ + return f.JS_DEPENDENT_TEMPLATE_HINT operator()( \ + mozilla::Forward(args)...); + JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); #undef JS_EXPAND_DEF - default: - MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped."); - } + default: + MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped."); + } } #undef JS_DEPENDENT_TEMPLATE_HINT template -auto -DispatchTraceKindTyped(F f, void* thing, JS::TraceKind traceKind, Args&&... args) - -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) -{ - switch (traceKind) { +auto DispatchTraceKindTyped(F f, void* thing, JS::TraceKind traceKind, + Args&&... args) + -> decltype(f(static_cast(nullptr), + mozilla::Forward(args)...)) { + switch (traceKind) { #define JS_EXPAND_DEF(name, type, _) \ - case JS::TraceKind::name: \ - return f(static_cast(thing), mozilla::Forward(args)...); - JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); + case JS::TraceKind::name: \ + return f(static_cast(thing), mozilla::Forward(args)...); + JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); #undef JS_EXPAND_DEF - default: - MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped."); - } + default: + MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped."); + } } -} // namespace JS +} // namespace JS -#endif // js_TraceKind_h +#endif // js_TraceKind_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 @@ -7,116 +7,126 @@ #ifndef js_TracingAPI_h #define js_TracingAPI_h -#include "jsalloc.h" - +#include "js/AllocPolicy.h" #include "js/HashTable.h" #include "js/HeapAPI.h" #include "js/TraceKind.h" -class JS_PUBLIC_API(JSTracer); +class JS_PUBLIC_API JSTracer; namespace JS { -class JS_PUBLIC_API(CallbackTracer); -template class Heap; -template class TenuredHeap; +class JS_PUBLIC_API CallbackTracer; +template +class Heap; +template +class TenuredHeap; /** Returns a static string equivalent of |kind|. */ -JS_FRIEND_API(const char*) -GCTraceKindToAscii(JS::TraceKind kind); +JS_FRIEND_API const char* GCTraceKindToAscii(JS::TraceKind kind); -} // namespace JS +} // namespace JS enum WeakMapTraceKind { - /** - * 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 - * the default for GCMarker. - */ - ExpandWeakMaps, - - /** - * Trace through to all values, irrespective of whether the keys are live - * or not. Used for non-marking tracers. - */ - TraceWeakMapValues, - - /** - * Trace through to all keys and values, irrespective of whether the keys - * are live or not. Used for non-marking tracers. - */ - TraceWeakMapKeysValues + /** + * 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 + * the default for GCMarker. + */ + ExpandWeakMaps, + + /** + * Trace through to all values, irrespective of whether the keys are live + * or not. Used for non-marking tracers. + */ + TraceWeakMapValues, + + /** + * Trace through to all keys and values, irrespective of whether the keys + * are live or not. Used for non-marking tracers. + */ + TraceWeakMapKeysValues }; -class JS_PUBLIC_API(JSTracer) -{ - public: - // Return the runtime set on the tracer. - JSRuntime* runtime() const { return runtime_; } - - // Return the weak map tracing behavior currently set on this tracer. - WeakMapTraceKind weakMapAction() const { return weakMapAction_; } - - 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, - - // 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; } - bool isWeakMarkingTracer() const { return tag_ == TracerKindTag::WeakMarking; } - bool isTenuringTracer() const { return tag_ == TracerKindTag::Tenuring; } - bool isCallbackTracer() const { return tag_ == TracerKindTag::Callback; } - inline JS::CallbackTracer* asCallbackTracer(); +class JS_PUBLIC_API JSTracer { + public: + // Return the runtime set on the tracer. + JSRuntime* runtime() const { return runtime_; } + + // Return the weak map tracing behavior currently set on this tracer. + WeakMapTraceKind weakMapAction() const { return weakMapAction_; } + + 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, + + // 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; + } + bool isWeakMarkingTracer() const { + return tag_ == TracerKindTag::WeakMarking; + } + bool isTenuringTracer() const { return tag_ == TracerKindTag::Tenuring; } + bool isCallbackTracer() const { return tag_ == TracerKindTag::Callback; } + inline JS::CallbackTracer* asCallbackTracer(); + bool traceWeakEdges() const { return traceWeakEdges_; } #ifdef DEBUG - bool checkEdges() { return checkEdges_; } + bool checkEdges() { return checkEdges_; } #endif - protected: - JSTracer(JSRuntime* rt, TracerKindTag tag, - WeakMapTraceKind weakTraceKind = TraceWeakMapValues) - : runtime_(rt) - , weakMapAction_(weakTraceKind) + // Get the current GC number. Only call this method if |isMarkingTracer()| + // is true. + uint32_t gcNumberForMarking() const; + + protected: + JSTracer(JSRuntime* rt, TracerKindTag tag, + WeakMapTraceKind weakTraceKind = TraceWeakMapValues) + : runtime_(rt), + weakMapAction_(weakTraceKind) #ifdef DEBUG - , checkEdges_(true) + , + checkEdges_(true) #endif - , tag_(tag) - {} + , + tag_(tag), + traceWeakEdges_(true) { + } #ifdef DEBUG - // Set whether to check edges are valid in debug builds. - void setCheckEdges(bool check) { - checkEdges_ = check; - } + // Set whether to check edges are valid in debug builds. + void setCheckEdges(bool check) { checkEdges_ = check; } #endif - private: - JSRuntime* runtime_; - WeakMapTraceKind weakMapAction_; + private: + JSRuntime* runtime_; + WeakMapTraceKind weakMapAction_; #ifdef DEBUG - bool checkEdges_; + bool checkEdges_; #endif - protected: - TracerKindTag tag_; + protected: + TracerKindTag tag_; + bool traceWeakEdges_; }; namespace JS { @@ -125,200 +135,230 @@ class AutoTracingIndex; class AutoTracingCallback; -class JS_PUBLIC_API(CallbackTracer) : public JSTracer -{ - public: - CallbackTracer(JSRuntime* rt, WeakMapTraceKind weakTraceKind = TraceWeakMapValues) +class JS_PUBLIC_API CallbackTracer : public JSTracer { + public: + CallbackTracer(JSRuntime* rt, + WeakMapTraceKind weakTraceKind = TraceWeakMapValues) : 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 - // dispatches to the fully-generic onChild implementation, so for cases that - // do not care about boxing overhead and do not need the actual edges, - // just override the generic onChild. - virtual void onObjectEdge(JSObject** objp) { onChild(JS::GCCellPtr(*objp)); } - virtual void onStringEdge(JSString** strp) { onChild(JS::GCCellPtr(*strp)); } - virtual void onSymbolEdge(JS::Symbol** symp) { onChild(JS::GCCellPtr(*symp)); } - virtual void onScriptEdge(JSScript** scriptp) { onChild(JS::GCCellPtr(*scriptp)); } - virtual void onShapeEdge(js::Shape** shapep) { - onChild(JS::GCCellPtr(*shapep, JS::TraceKind::Shape)); - } - virtual void onObjectGroupEdge(js::ObjectGroup** groupp) { - onChild(JS::GCCellPtr(*groupp, JS::TraceKind::ObjectGroup)); - } - virtual void onBaseShapeEdge(js::BaseShape** basep) { - onChild(JS::GCCellPtr(*basep, JS::TraceKind::BaseShape)); - } - virtual void onJitCodeEdge(js::jit::JitCode** codep) { - onChild(JS::GCCellPtr(*codep, JS::TraceKind::JitCode)); - } - 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. - virtual void onChild(const JS::GCCellPtr& thing) = 0; - - // Access to the tracing context: - // When tracing with a JS::CallbackTracer, we invoke the callback with the - // edge location and the type of target. This is useful for operating on - // the edge in the abstract or on the target thing, satisfying most common - // use cases. However, some tracers need additional detail about the - // specific edge that is being traced in order to be useful. Unfortunately, - // the raw pointer to the edge that we provide is not enough information to - // infer much of anything useful about that edge. - // - // In order to better support use cases that care in particular about edges - // -- as opposed to the target thing -- tracing implementations are - // responsible for providing extra context information about each edge they - // trace, as it is traced. This contains, at a minimum, an edge name and, - // when tracing an array, the index. Further specialization can be achived - // (with some complexity), by associating a functor with the tracer so - // that, when requested, the user can generate totally custom edge - // descriptions. - - // Returns the current edge's name. It is only valid to call this when - // inside the trace callback, however, the edge name will always be set. - const char* contextName() const { MOZ_ASSERT(contextName_); return contextName_; } - - // Returns the current edge's index, if marked as part of an array of edges. - // This must be called only inside the trace callback. When not tracing an - // array, the value will be InvalidIndex. - const static size_t InvalidIndex = size_t(-1); - size_t contextIndex() const { return contextIndex_; } - - // Build a description of this edge in the heap graph. This call may invoke - // the context functor, if set, which may inspect arbitrary areas of the - // heap. On the other hand, the description provided by this method may be - // substantially more accurate and useful than those provided by only the - // contextName and contextIndex. - void getTracingEdgeName(char* buffer, size_t bufferSize); - - // The trace implementation may associate a callback with one or more edges - // using AutoTracingDetails. This functor is called by getTracingEdgeName - // and is responsible for providing a textual representation of the - // currently being traced edge. The callback has access to the full heap, - // including the currently set tracing context. - class ContextFunctor { - public: - virtual void operator()(CallbackTracer* trc, char* buf, size_t bufsize) = 0; - }; + 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 + // dispatches to the fully-generic onChild implementation, so for cases that + // do not care about boxing overhead and do not need the actual edges, + // just override the generic onChild. + virtual void onObjectEdge(JSObject** objp) { onChild(JS::GCCellPtr(*objp)); } + virtual void onStringEdge(JSString** strp) { onChild(JS::GCCellPtr(*strp)); } + virtual void onSymbolEdge(JS::Symbol** symp) { + onChild(JS::GCCellPtr(*symp)); + } + virtual void onScriptEdge(JSScript** scriptp) { + onChild(JS::GCCellPtr(*scriptp)); + } + virtual void onShapeEdge(js::Shape** shapep) { + onChild(JS::GCCellPtr(*shapep, JS::TraceKind::Shape)); + } + virtual void onObjectGroupEdge(js::ObjectGroup** groupp) { + onChild(JS::GCCellPtr(*groupp, JS::TraceKind::ObjectGroup)); + } + virtual void onBaseShapeEdge(js::BaseShape** basep) { + onChild(JS::GCCellPtr(*basep, JS::TraceKind::BaseShape)); + } + virtual void onJitCodeEdge(js::jit::JitCode** codep) { + onChild(JS::GCCellPtr(*codep, JS::TraceKind::JitCode)); + } + 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)); + } + virtual void onRegExpSharedEdge(js::RegExpShared** sharedp) { + onChild(JS::GCCellPtr(*sharedp, JS::TraceKind::RegExpShared)); + } + + // Override this method to receive notification when a node in the GC + // heap graph is visited. + virtual void onChild(const JS::GCCellPtr& thing) = 0; + + // Access to the tracing context: + // When tracing with a JS::CallbackTracer, we invoke the callback with the + // edge location and the type of target. This is useful for operating on + // the edge in the abstract or on the target thing, satisfying most common + // use cases. However, some tracers need additional detail about the + // specific edge that is being traced in order to be useful. Unfortunately, + // the raw pointer to the edge that we provide is not enough information to + // infer much of anything useful about that edge. + // + // In order to better support use cases that care in particular about edges + // -- as opposed to the target thing -- tracing implementations are + // responsible for providing extra context information about each edge they + // trace, as it is traced. This contains, at a minimum, an edge name and, + // when tracing an array, the index. Further specialization can be achived + // (with some complexity), by associating a functor with the tracer so + // that, when requested, the user can generate totally custom edge + // descriptions. + + // Returns the current edge's name. It is only valid to call this when + // inside the trace callback, however, the edge name will always be set. + const char* contextName() const { + MOZ_ASSERT(contextName_); + return contextName_; + } + + // Returns the current edge's index, if marked as part of an array of edges. + // This must be called only inside the trace callback. When not tracing an + // array, the value will be InvalidIndex. + const static size_t InvalidIndex = size_t(-1); + size_t contextIndex() const { return contextIndex_; } + + // Build a description of this edge in the heap graph. This call may invoke + // the context functor, if set, which may inspect arbitrary areas of the + // heap. On the other hand, the description provided by this method may be + // substantially more accurate and useful than those provided by only the + // contextName and contextIndex. + void getTracingEdgeName(char* buffer, size_t bufferSize); + + // The trace implementation may associate a callback with one or more edges + // using AutoTracingDetails. This functor is called by getTracingEdgeName + // and is responsible for providing a textual representation of the + // currently being traced edge. The callback has access to the full heap, + // including the currently set tracing context. + class ContextFunctor { + public: + virtual void operator()(CallbackTracer* trc, char* buf, size_t bufsize) = 0; + }; #ifdef DEBUG - enum class TracerKind { DoNotCare, Moving, GrayBuffering, VerifyTraceProtoAndIface }; - virtual TracerKind getTracerKind() const { return TracerKind::DoNotCare; } + enum class TracerKind { + DoNotCare, + Moving, + GrayBuffering, + VerifyTraceProtoAndIface, + ClearEdges, + UnmarkGray + }; + virtual TracerKind getTracerKind() const { return TracerKind::DoNotCare; } #endif - // In C++, overriding a method hides all methods in the base class with - // that name, not just methods with that signature. Thus, the typed edge - // methods have to have distinct names to allow us to override them - // individually, which is freqently useful if, for example, we only want to - // process only one type of edge. - void dispatchToOnEdge(JSObject** objp) { onObjectEdge(objp); } - void dispatchToOnEdge(JSString** strp) { onStringEdge(strp); } - void dispatchToOnEdge(JS::Symbol** symp) { onSymbolEdge(symp); } - void dispatchToOnEdge(JSScript** scriptp) { onScriptEdge(scriptp); } - void dispatchToOnEdge(js::Shape** shapep) { onShapeEdge(shapep); } - void dispatchToOnEdge(js::ObjectGroup** groupp) { onObjectGroupEdge(groupp); } - 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; - const char* contextName_; + // In C++, overriding a method hides all methods in the base class with + // that name, not just methods with that signature. Thus, the typed edge + // methods have to have distinct names to allow us to override them + // individually, which is freqently useful if, for example, we only want to + // process only one type of edge. + void dispatchToOnEdge(JSObject** objp) { onObjectEdge(objp); } + void dispatchToOnEdge(JSString** strp) { onStringEdge(strp); } + void dispatchToOnEdge(JS::Symbol** symp) { onSymbolEdge(symp); } + void dispatchToOnEdge(JSScript** scriptp) { onScriptEdge(scriptp); } + void dispatchToOnEdge(js::Shape** shapep) { onShapeEdge(shapep); } + void dispatchToOnEdge(js::ObjectGroup** groupp) { onObjectGroupEdge(groupp); } + 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); } + void dispatchToOnEdge(js::RegExpShared** sharedp) { + onRegExpSharedEdge(sharedp); + } + + protected: + void setTraceWeakEdges(bool value) { traceWeakEdges_ = value; } + + private: + friend class AutoTracingName; + const char* contextName_; - friend class AutoTracingIndex; - size_t contextIndex_; + friend class AutoTracingIndex; + size_t contextIndex_; - friend class AutoTracingDetails; - ContextFunctor* contextFunctor_; + friend class AutoTracingDetails; + ContextFunctor* contextFunctor_; }; // Set the name portion of the tracer's context for the current edge. -class MOZ_RAII AutoTracingName -{ - CallbackTracer* trc_; - const char* prior_; - - public: - AutoTracingName(CallbackTracer* trc, const char* name) : trc_(trc), prior_(trc->contextName_) { - MOZ_ASSERT(name); - trc->contextName_ = name; - } - ~AutoTracingName() { - MOZ_ASSERT(trc_->contextName_); - trc_->contextName_ = prior_; - } +class MOZ_RAII AutoTracingName { + CallbackTracer* trc_; + const char* prior_; + + public: + AutoTracingName(CallbackTracer* trc, const char* name) + : trc_(trc), prior_(trc->contextName_) { + MOZ_ASSERT(name); + trc->contextName_ = name; + } + ~AutoTracingName() { + MOZ_ASSERT(trc_->contextName_); + trc_->contextName_ = prior_; + } }; // Set the index portion of the tracer's context for the current range. -class MOZ_RAII AutoTracingIndex -{ - CallbackTracer* trc_; - - public: - explicit AutoTracingIndex(JSTracer* trc, size_t initial = 0) : trc_(nullptr) { - if (trc->isCallbackTracer()) { - trc_ = trc->asCallbackTracer(); - MOZ_ASSERT(trc_->contextIndex_ == CallbackTracer::InvalidIndex); - trc_->contextIndex_ = initial; - } - } - ~AutoTracingIndex() { - if (trc_) { - MOZ_ASSERT(trc_->contextIndex_ != CallbackTracer::InvalidIndex); - trc_->contextIndex_ = CallbackTracer::InvalidIndex; - } - } +class MOZ_RAII AutoTracingIndex { + CallbackTracer* trc_; - void operator++() { - if (trc_) { - MOZ_ASSERT(trc_->contextIndex_ != CallbackTracer::InvalidIndex); - ++trc_->contextIndex_; - } + public: + explicit AutoTracingIndex(JSTracer* trc, size_t initial = 0) : trc_(nullptr) { + if (trc->isCallbackTracer()) { + trc_ = trc->asCallbackTracer(); + MOZ_ASSERT(trc_->contextIndex_ == CallbackTracer::InvalidIndex); + trc_->contextIndex_ = initial; + } + } + ~AutoTracingIndex() { + if (trc_) { + MOZ_ASSERT(trc_->contextIndex_ != CallbackTracer::InvalidIndex); + trc_->contextIndex_ = CallbackTracer::InvalidIndex; + } + } + + void operator++() { + if (trc_) { + MOZ_ASSERT(trc_->contextIndex_ != CallbackTracer::InvalidIndex); + ++trc_->contextIndex_; } + } }; // Set a context callback for the trace callback to use, if it needs a detailed // edge description. -class MOZ_RAII AutoTracingDetails -{ - CallbackTracer* trc_; - - public: - AutoTracingDetails(JSTracer* trc, CallbackTracer::ContextFunctor& func) : trc_(nullptr) { - if (trc->isCallbackTracer()) { - trc_ = trc->asCallbackTracer(); - MOZ_ASSERT(trc_->contextFunctor_ == nullptr); - trc_->contextFunctor_ = &func; - } - } - ~AutoTracingDetails() { - if (trc_) { - MOZ_ASSERT(trc_->contextFunctor_); - trc_->contextFunctor_ = nullptr; - } +class MOZ_RAII AutoTracingDetails { + CallbackTracer* trc_; + + public: + AutoTracingDetails(JSTracer* trc, CallbackTracer::ContextFunctor& func) + : trc_(nullptr) { + if (trc->isCallbackTracer()) { + trc_ = trc->asCallbackTracer(); + MOZ_ASSERT(trc_->contextFunctor_ == nullptr); + trc_->contextFunctor_ = &func; + } + } + ~AutoTracingDetails() { + if (trc_) { + MOZ_ASSERT(trc_->contextFunctor_); + trc_->contextFunctor_ = nullptr; } + } }; -} // namespace JS +} // namespace JS -JS::CallbackTracer* -JSTracer::asCallbackTracer() -{ - MOZ_ASSERT(isCallbackTracer()); - return static_cast(this); +JS::CallbackTracer* JSTracer::asCallbackTracer() { + MOZ_ASSERT(isCallbackTracer()); + return static_cast(this); } +namespace js { +namespace gc { +template +JS_PUBLIC_API void TraceExternalEdge(JSTracer* trc, T* thingp, + const char* name); +} // namespace gc +} // namespace js + namespace JS { // The JS::TraceEdge family of functions traces the given GC thing reference. @@ -335,12 +375,22 @@ // // 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); +inline void TraceEdge(JSTracer* trc, JS::Heap* thingp, const char* name) { + MOZ_ASSERT(thingp); + if (*thingp) js::gc::TraceExternalEdge(trc, thingp->unsafeGet(), name); +} -extern JS_PUBLIC_API(void) -TraceEdge(JSTracer* trc, JS::TenuredHeap* edgep, const char* name); +template +inline void TraceEdge(JSTracer* trc, JS::TenuredHeap* thingp, + const char* name) { + MOZ_ASSERT(thingp); + if (T ptr = thingp->unbarrieredGetPtr()) { + js::gc::TraceExternalEdge(trc, &ptr, name); + thingp->setPtr(ptr); + } +} // Edges that are always traced as part of root marking do not require // incremental barriers. This function allows for marking non-barriered @@ -349,29 +399,31 @@ // Note that while |edgep| must never be null, it is fine for |*edgep| to be // nullptr. template -extern JS_PUBLIC_API(void) -UnsafeTraceRoot(JSTracer* trc, T* edgep, const char* name); +extern JS_PUBLIC_API void UnsafeTraceRoot(JSTracer* trc, T* edgep, + const char* name); -extern JS_PUBLIC_API(void) -TraceChildren(JSTracer* trc, GCCellPtr thing); +extern JS_PUBLIC_API void TraceChildren(JSTracer* trc, GCCellPtr thing); -using ZoneSet = js::HashSet, js::SystemAllocPolicy>; -using CompartmentSet = js::HashSet, - js::SystemAllocPolicy>; +using ZoneSet = + js::HashSet, js::SystemAllocPolicy>; +using CompartmentSet = + js::HashSet, + js::SystemAllocPolicy>; /** * 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) -TraceIncomingCCWs(JSTracer* trc, const JS::CompartmentSet& compartments); +extern JS_PUBLIC_API void TraceIncomingCCWs( + JSTracer* trc, const JS::CompartmentSet& compartments); -} // namespace JS +} // namespace JS -extern JS_PUBLIC_API(void) -JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, - void* thing, JS::TraceKind kind, bool includeDetails); +extern JS_PUBLIC_API void JS_GetTraceThingInfo(char* buf, size_t bufsize, + JSTracer* trc, void* thing, + JS::TraceKind kind, + bool includeDetails); namespace js { @@ -381,23 +433,22 @@ // 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 -extern JS_PUBLIC_API(void) -UnsafeTraceManuallyBarrieredEdge(JSTracer* trc, T* edgep, const char* name); +extern JS_PUBLIC_API void UnsafeTraceManuallyBarrieredEdge(JSTracer* trc, + T* edgep, + const char* name); namespace gc { // Return true if the given edge is not live and is about to be swept. template -extern JS_PUBLIC_API(bool) -EdgeNeedsSweep(JS::Heap* edgep); +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 -bool -IsAboutToBeFinalizedUnbarriered(T* thingp); +bool IsAboutToBeFinalizedUnbarriered(T* thingp); -} // namespace gc -} // namespace js +} // 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 @@ -11,275 +11,294 @@ namespace JS { -#define TRACKED_STRATEGY_LIST(_) \ - _(GetProp_ArgumentsLength) \ - _(GetProp_ArgumentsCallee) \ - _(GetProp_InferredConstant) \ - _(GetProp_Constant) \ - _(GetProp_NotDefined) \ - _(GetProp_StaticName) \ - _(GetProp_SimdGetter) \ - _(GetProp_TypedObject) \ - _(GetProp_DefiniteSlot) \ - _(GetProp_Unboxed) \ - _(GetProp_CommonGetter) \ - _(GetProp_InlineAccess) \ - _(GetProp_Innerize) \ - _(GetProp_InlineCache) \ - _(GetProp_SharedCache) \ - _(GetProp_ModuleNamespace) \ - \ - _(SetProp_CommonSetter) \ - _(SetProp_TypedObject) \ - _(SetProp_DefiniteSlot) \ - _(SetProp_Unboxed) \ - _(SetProp_InlineAccess) \ - _(SetProp_InlineCache) \ - \ - _(GetElem_TypedObject) \ - _(GetElem_Dense) \ - _(GetElem_TypedStatic) \ - _(GetElem_TypedArray) \ - _(GetElem_String) \ - _(GetElem_Arguments) \ - _(GetElem_ArgumentsInlined) \ - _(GetElem_InlineCache) \ - \ - _(SetElem_TypedObject) \ - _(SetElem_TypedStatic) \ - _(SetElem_TypedArray) \ - _(SetElem_Dense) \ - _(SetElem_Arguments) \ - _(SetElem_InlineCache) \ - \ - _(BinaryArith_Concat) \ - _(BinaryArith_SpecializedTypes) \ - _(BinaryArith_SpecializedOnBaselineTypes) \ - _(BinaryArith_SharedCache) \ - _(BinaryArith_Call) \ - \ - _(InlineCache_OptimizedStub) \ - \ - _(Call_Inline) - +#define TRACKED_STRATEGY_LIST(_) \ + _(GetProp_ArgumentsLength) \ + _(GetProp_ArgumentsCallee) \ + _(GetProp_InferredConstant) \ + _(GetProp_Constant) \ + _(GetProp_NotDefined) \ + _(GetProp_StaticName) \ + _(GetProp_SimdGetter) \ + _(GetProp_TypedObject) \ + _(GetProp_DefiniteSlot) \ + _(GetProp_Unboxed) \ + _(GetProp_CommonGetter) \ + _(GetProp_InlineAccess) \ + _(GetProp_InlineProtoAccess) \ + _(GetProp_Innerize) \ + _(GetProp_InlineCache) \ + _(GetProp_ModuleNamespace) \ + \ + _(SetProp_CommonSetter) \ + _(SetProp_TypedObject) \ + _(SetProp_DefiniteSlot) \ + _(SetProp_Unboxed) \ + _(SetProp_InlineAccess) \ + _(SetProp_InlineCache) \ + \ + _(GetElem_TypedObject) \ + _(GetElem_Dense) \ + _(GetElem_TypedArray) \ + _(GetElem_String) \ + _(GetElem_Arguments) \ + _(GetElem_ArgumentsInlinedConstant) \ + _(GetElem_ArgumentsInlinedSwitch) \ + _(GetElem_InlineCache) \ + \ + _(SetElem_TypedObject) \ + _(SetElem_TypedArray) \ + _(SetElem_Dense) \ + _(SetElem_Arguments) \ + _(SetElem_InlineCache) \ + \ + _(BinaryArith_Concat) \ + _(BinaryArith_SpecializedTypes) \ + _(BinaryArith_SpecializedOnBaselineTypes) \ + _(BinaryArith_SharedCache) \ + _(BinaryArith_Call) \ + \ + _(InlineCache_OptimizedStub) \ + \ + _(NewArray_TemplateObject) \ + _(NewArray_SharedCache) \ + _(NewArray_Call) \ + \ + _(NewObject_TemplateObject) \ + _(NewObject_SharedCache) \ + _(NewObject_Call) \ + \ + _(Compare_SpecializedTypes) \ + _(Compare_Bitwise) \ + _(Compare_SpecializedOnBaselineTypes) \ + _(Compare_SharedCache) \ + _(Compare_Call) \ + \ + _(Call_Inline) // Ordering is important below. All outcomes before GenericSuccess will be // considered failures, and all outcomes after GenericSuccess will be // considered successes. -#define TRACKED_OUTCOME_LIST(_) \ - _(GenericFailure) \ - _(Disabled) \ - _(NoTypeInfo) \ - _(NoAnalysisInfo) \ - _(NoShapeInfo) \ - _(UnknownObject) \ - _(UnknownProperties) \ - _(Singleton) \ - _(NotSingleton) \ - _(NotFixedSlot) \ - _(InconsistentFixedSlot) \ - _(NotObject) \ - _(NotStruct) \ - _(NotUnboxed) \ - _(NotUndefined) \ - _(UnboxedConvertedToNative) \ - _(StructNoField) \ - _(InconsistentFieldType) \ - _(InconsistentFieldOffset) \ - _(NeedsTypeBarrier) \ - _(InDictionaryMode) \ - _(NoProtoFound) \ - _(MultiProtoPaths) \ - _(NonWritableProperty) \ - _(ProtoIndexedProps) \ - _(ArrayBadFlags) \ - _(ArrayDoubleConversion) \ - _(ArrayRange) \ - _(ArraySeenNegativeIndex) \ - _(TypedObjectHasDetachedBuffer) \ - _(TypedObjectArrayRange) \ - _(AccessNotDense) \ - _(AccessNotSimdObject) \ - _(AccessNotTypedObject) \ - _(AccessNotTypedArray) \ - _(AccessNotString) \ - _(OperandNotString) \ - _(OperandNotNumber) \ - _(OperandNotStringOrNumber) \ - _(OperandNotSimpleArith) \ - _(StaticTypedArrayUint32) \ - _(StaticTypedArrayCantComputeMask) \ - _(OutOfBounds) \ - _(GetElemStringNotCached) \ - _(NonNativeReceiver) \ - _(IndexType) \ - _(SetElemNonDenseNonTANotCached) \ - _(NoSimdJitSupport) \ - _(SimdTypeNotOptimized) \ - _(UnknownSimdProperty) \ - _(NotModuleNamespace) \ - _(UnknownProperty) \ - \ - _(ICOptStub_GenericSuccess) \ - \ - _(ICGetPropStub_ReadSlot) \ - _(ICGetPropStub_CallGetter) \ - _(ICGetPropStub_ArrayLength) \ - _(ICGetPropStub_UnboxedRead) \ - _(ICGetPropStub_UnboxedReadExpando) \ - _(ICGetPropStub_UnboxedArrayLength) \ - _(ICGetPropStub_TypedArrayLength) \ - _(ICGetPropStub_DOMProxyShadowed) \ - _(ICGetPropStub_DOMProxyUnshadowed) \ - _(ICGetPropStub_GenericProxy) \ - _(ICGetPropStub_ArgumentsLength) \ - \ - _(ICSetPropStub_Slot) \ - _(ICSetPropStub_GenericProxy) \ - _(ICSetPropStub_DOMProxyShadowed) \ - _(ICSetPropStub_DOMProxyUnshadowed) \ - _(ICSetPropStub_CallSetter) \ - _(ICSetPropStub_AddSlot) \ - _(ICSetPropStub_SetUnboxed) \ - \ - _(ICGetElemStub_ReadSlot) \ - _(ICGetElemStub_CallGetter) \ - _(ICGetElemStub_ReadUnboxed) \ - _(ICGetElemStub_Dense) \ - _(ICGetElemStub_DenseHole) \ - _(ICGetElemStub_TypedArray) \ - _(ICGetElemStub_ArgsElementMapped) \ - _(ICGetElemStub_ArgsElementUnmapped) \ - \ - _(ICSetElemStub_Dense) \ - _(ICSetElemStub_TypedArray) \ - \ - _(ICNameStub_ReadSlot) \ - _(ICNameStub_CallGetter) \ - _(ICNameStub_TypeOfNoProperty) \ - \ - _(CantInlineGeneric) \ - _(CantInlineNoTarget) \ - _(CantInlineNotInterpreted) \ - _(CantInlineNoBaseline) \ - _(CantInlineLazy) \ - _(CantInlineNotConstructor) \ - _(CantInlineClassConstructor) \ - _(CantInlineDisabledIon) \ - _(CantInlineTooManyArgs) \ - _(CantInlineNeedsArgsObj) \ - _(CantInlineDebuggee) \ - _(CantInlineUnknownProps) \ - _(CantInlineExceededDepth) \ - _(CantInlineExceededTotalBytecodeLength) \ - _(CantInlineBigCaller) \ - _(CantInlineBigCallee) \ - _(CantInlineBigCalleeInlinedBytecodeLength) \ - _(CantInlineNotHot) \ - _(CantInlineNotInDispatch) \ - _(CantInlineUnreachable) \ - _(CantInlineNativeBadForm) \ - _(CantInlineNativeBadType) \ - _(CantInlineNativeNoTemplateObj) \ - _(CantInlineBound) \ - _(CantInlineNativeNoSpecialization) \ - _(HasCommonInliningPath) \ - \ - _(GenericSuccess) \ - _(Inlined) \ - _(DOM) \ - _(Monomorphic) \ - _(Polymorphic) - -#define TRACKED_TYPESITE_LIST(_) \ - _(Receiver) \ - _(Operand) \ - _(Index) \ - _(Value) \ - _(Call_Target) \ - _(Call_This) \ - _(Call_Arg) \ - _(Call_Return) +#define TRACKED_OUTCOME_LIST(_) \ + _(GenericFailure) \ + _(Disabled) \ + _(NoTypeInfo) \ + _(NoAnalysisInfo) \ + _(NoShapeInfo) \ + _(UnknownObject) \ + _(UnknownProperties) \ + _(Singleton) \ + _(NotSingleton) \ + _(NotFixedSlot) \ + _(InconsistentFixedSlot) \ + _(NotObject) \ + _(NotStruct) \ + _(NotUnboxed) \ + _(NotUndefined) \ + _(UnboxedConvertedToNative) \ + _(StructNoField) \ + _(InconsistentFieldType) \ + _(InconsistentFieldOffset) \ + _(NeedsTypeBarrier) \ + _(InDictionaryMode) \ + _(NoProtoFound) \ + _(MultiProtoPaths) \ + _(NonWritableProperty) \ + _(ProtoIndexedProps) \ + _(ArrayBadFlags) \ + _(ArrayDoubleConversion) \ + _(ArrayRange) \ + _(ArraySeenNegativeIndex) \ + _(TypedObjectHasDetachedBuffer) \ + _(TypedObjectArrayRange) \ + _(AccessNotDense) \ + _(AccessNotSimdObject) \ + _(AccessNotTypedObject) \ + _(AccessNotTypedArray) \ + _(AccessNotString) \ + _(OperandNotString) \ + _(OperandNotNumber) \ + _(OperandNotStringOrNumber) \ + _(OperandNotSimpleArith) \ + _(OperandNotEasilyCoercibleToString) \ + _(OutOfBounds) \ + _(GetElemStringNotCached) \ + _(NonNativeReceiver) \ + _(IndexType) \ + _(SetElemNonDenseNonTANotCached) \ + _(NoSimdJitSupport) \ + _(SimdTypeNotOptimized) \ + _(UnknownSimdProperty) \ + _(NotModuleNamespace) \ + _(UnknownProperty) \ + _(NoTemplateObject) \ + _(TemplateObjectIsUnboxedWithoutInlineElements) \ + _(TemplateObjectIsPlainObjectWithDynamicSlots) \ + _(LengthTooBig) \ + _(SpeculationOnInputTypesFailed) \ + _(RelationalCompare) \ + _(OperandTypeNotBitwiseComparable) \ + _(OperandMaybeEmulatesUndefined) \ + _(LoosyUndefinedNullCompare) \ + _(LoosyInt32BooleanCompare) \ + _(CallsValueOf) \ + _(StrictCompare) \ + _(InitHole) \ + \ + _(ICOptStub_GenericSuccess) \ + \ + _(ICGetPropStub_ReadSlot) \ + _(ICGetPropStub_CallGetter) \ + _(ICGetPropStub_ArrayLength) \ + _(ICGetPropStub_UnboxedRead) \ + _(ICGetPropStub_UnboxedReadExpando) \ + _(ICGetPropStub_UnboxedArrayLength) \ + _(ICGetPropStub_TypedArrayLength) \ + _(ICGetPropStub_DOMProxyShadowed) \ + _(ICGetPropStub_DOMProxyUnshadowed) \ + _(ICGetPropStub_GenericProxy) \ + _(ICGetPropStub_ArgumentsLength) \ + \ + _(ICSetPropStub_Slot) \ + _(ICSetPropStub_GenericProxy) \ + _(ICSetPropStub_DOMProxyShadowed) \ + _(ICSetPropStub_DOMProxyUnshadowed) \ + _(ICSetPropStub_CallSetter) \ + _(ICSetPropStub_AddSlot) \ + _(ICSetPropStub_SetUnboxed) \ + \ + _(ICGetElemStub_ReadSlot) \ + _(ICGetElemStub_CallGetter) \ + _(ICGetElemStub_ReadUnboxed) \ + _(ICGetElemStub_Dense) \ + _(ICGetElemStub_DenseHole) \ + _(ICGetElemStub_TypedArray) \ + _(ICGetElemStub_ArgsElementMapped) \ + _(ICGetElemStub_ArgsElementUnmapped) \ + \ + _(ICSetElemStub_Dense) \ + _(ICSetElemStub_TypedArray) \ + \ + _(ICNameStub_ReadSlot) \ + _(ICNameStub_CallGetter) \ + _(ICNameStub_TypeOfNoProperty) \ + \ + _(CantInlineGeneric) \ + _(CantInlineNoTarget) \ + _(CantInlineNotInterpreted) \ + _(CantInlineNoBaseline) \ + _(CantInlineLazy) \ + _(CantInlineNotConstructor) \ + _(CantInlineClassConstructor) \ + _(CantInlineDisabledIon) \ + _(CantInlineTooManyArgs) \ + _(CantInlineNeedsArgsObj) \ + _(CantInlineDebuggee) \ + _(CantInlineExceededDepth) \ + _(CantInlineExceededTotalBytecodeLength) \ + _(CantInlineBigCaller) \ + _(CantInlineBigCallee) \ + _(CantInlineBigCalleeInlinedBytecodeLength) \ + _(CantInlineNotHot) \ + _(CantInlineNotInDispatch) \ + _(CantInlineUnreachable) \ + _(CantInlineNativeBadForm) \ + _(CantInlineNativeBadType) \ + _(CantInlineNativeNoTemplateObj) \ + _(CantInlineBound) \ + _(CantInlineNativeNoSpecialization) \ + _(HasCommonInliningPath) \ + \ + _(GenericSuccess) \ + _(Inlined) \ + _(DOM) \ + _(Monomorphic) \ + _(Polymorphic) + +#define TRACKED_TYPESITE_LIST(_) \ + _(Receiver) \ + _(Operand) \ + _(Index) \ + _(Value) \ + _(Call_Target) \ + _(Call_This) \ + _(Call_Arg) \ + _(Call_Return) enum class TrackedStrategy : uint32_t { #define STRATEGY_OP(name) name, - TRACKED_STRATEGY_LIST(STRATEGY_OP) + TRACKED_STRATEGY_LIST(STRATEGY_OP) #undef STRATEGY_OPT - Count + Count }; enum class TrackedOutcome : uint32_t { #define OUTCOME_OP(name) name, - TRACKED_OUTCOME_LIST(OUTCOME_OP) + TRACKED_OUTCOME_LIST(OUTCOME_OP) #undef OUTCOME_OP - Count + Count }; enum class TrackedTypeSite : uint32_t { #define TYPESITE_OP(name) name, - TRACKED_TYPESITE_LIST(TYPESITE_OP) + TRACKED_TYPESITE_LIST(TYPESITE_OP) #undef TYPESITE_OP - Count + Count }; -JS_PUBLIC_API(const char*) -TrackedStrategyString(TrackedStrategy strategy); +JS_PUBLIC_API const char* TrackedStrategyString(TrackedStrategy strategy); -JS_PUBLIC_API(const char*) -TrackedOutcomeString(TrackedOutcome outcome); +JS_PUBLIC_API const char* TrackedOutcomeString(TrackedOutcome outcome); -JS_PUBLIC_API(const char*) -TrackedTypeSiteString(TrackedTypeSite site); +JS_PUBLIC_API const char* TrackedTypeSiteString(TrackedTypeSite site); -struct ForEachTrackedOptimizationAttemptOp -{ - virtual void operator()(TrackedStrategy strategy, TrackedOutcome outcome) = 0; +struct ForEachTrackedOptimizationAttemptOp { + virtual void operator()(TrackedStrategy strategy, TrackedOutcome outcome) = 0; }; -struct ForEachTrackedOptimizationTypeInfoOp -{ - // Called 0+ times per entry, once for each type in the type set that Ion - // saw during MIR construction. readType is always called _before_ - // operator() on the same entry. - // - // The keyedBy parameter describes how the type is keyed: - // - "primitive" for primitive types - // - "constructor" for object types tied to a scripted constructor - // function. - // - "alloc site" for object types tied to an allocation site. - // - "prototype" for object types tied neither to a constructor nor - // to an allocation site, but to a prototype. - // - "singleton" for object types which only has a single value. - // - "function" for object types referring to scripted functions. - // - "native" for object types referring to native functions. - // - // The name parameter is the string representation of the type. If the - // type is keyed by "constructor", or if the type itself refers to a - // scripted function, the name is the function's displayAtom. If the type - // is keyed by "native", this is nullptr. - // - // The location parameter is the filename if the type is keyed by - // "constructor", "alloc site", or if the type itself refers to a scripted - // function. If the type is keyed by "native", it is the offset of the - // native function, suitable for use with addr2line on Linux or atos on OS - // X. Otherwise it is nullptr. - // - // The lineno parameter is the line number if the type is keyed by - // "constructor", "alloc site", or if the type itself refers to a scripted - // function. Otherwise it is Nothing(). - // - // The location parameter is the only one that may need escaping if being - // quoted. - virtual void readType(const char* keyedBy, const char* name, - const char* location, mozilla::Maybe lineno) = 0; +struct ForEachTrackedOptimizationTypeInfoOp { + // Called 0+ times per entry, once for each type in the type set that Ion + // saw during MIR construction. readType is always called _before_ + // operator() on the same entry. + // + // The keyedBy parameter describes how the type is keyed: + // - "primitive" for primitive types + // - "constructor" for object types tied to a scripted constructor + // function. + // - "alloc site" for object types tied to an allocation site. + // - "prototype" for object types tied neither to a constructor nor + // to an allocation site, but to a prototype. + // - "singleton" for object types which only has a single value. + // - "function" for object types referring to scripted functions. + // - "native" for object types referring to native functions. + // + // The name parameter is the string representation of the type. If the + // type is keyed by "constructor", or if the type itself refers to a + // scripted function, the name is the function's displayAtom. If the type + // is keyed by "native", this is nullptr. + // + // The location parameter is the filename if the type is keyed by + // "constructor", "alloc site", or if the type itself refers to a scripted + // function. If the type is keyed by "native", it is the offset of the + // native function, suitable for use with addr2line on Linux or atos on OS + // X. Otherwise it is nullptr. + // + // The lineno parameter is the line number if the type is keyed by + // "constructor", "alloc site", or if the type itself refers to a scripted + // function. Otherwise it is Nothing(). + // + // The location parameter is the only one that may need escaping if being + // quoted. + virtual void readType(const char* keyedBy, const char* name, + const char* location, + const mozilla::Maybe& lineno) = 0; - // Called once per entry. - virtual void operator()(TrackedTypeSite site, const char* mirType) = 0; + // Called once per entry. + virtual void operator()(TrackedTypeSite site, const char* mirType) = 0; }; -} // namespace JS +} // namespace JS -#endif // js_TrackedOptimizationInfo_h +#endif // js_TrackedOptimizationInfo_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/TypeDecls.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/TypeDecls.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/TypeDecls.h @@ -22,12 +22,18 @@ #include "js-config.h" +typedef uint8_t jsbytecode; + +class JSAtom; +struct JSCompartment; struct JSContext; class JSFunction; class JSObject; +struct JSRuntime; class JSScript; class JSString; class JSAddonId; +struct JSFreeOp; struct jsid; @@ -37,43 +43,51 @@ class Symbol; class Value; -template class Handle; -template class MutableHandle; -template class Rooted; -template class PersistentRooted; +class Realm; +struct Runtime; +struct Zone; + +template +class Handle; +template +class MutableHandle; +template +class Rooted; +template +class PersistentRooted; typedef Handle HandleFunction; -typedef Handle HandleId; -typedef Handle HandleObject; -typedef Handle HandleScript; -typedef Handle HandleString; +typedef Handle HandleId; +typedef Handle HandleObject; +typedef Handle HandleScript; +typedef Handle HandleString; typedef Handle HandleSymbol; -typedef Handle HandleValue; +typedef Handle HandleValue; typedef MutableHandle MutableHandleFunction; -typedef MutableHandle MutableHandleId; -typedef MutableHandle MutableHandleObject; -typedef MutableHandle MutableHandleScript; -typedef MutableHandle MutableHandleString; +typedef MutableHandle MutableHandleId; +typedef MutableHandle MutableHandleObject; +typedef MutableHandle MutableHandleScript; +typedef MutableHandle MutableHandleString; typedef MutableHandle MutableHandleSymbol; -typedef MutableHandle MutableHandleValue; +typedef MutableHandle MutableHandleValue; -typedef Rooted RootedObject; -typedef Rooted RootedFunction; -typedef Rooted RootedScript; -typedef Rooted RootedString; -typedef Rooted RootedSymbol; -typedef Rooted RootedId; -typedef Rooted RootedValue; +typedef Rooted RootedObject; +typedef Rooted RootedFunction; +typedef Rooted RootedScript; +typedef Rooted RootedString; +typedef Rooted RootedSymbol; +typedef Rooted RootedId; +typedef Rooted RootedValue; typedef PersistentRooted PersistentRootedFunction; -typedef PersistentRooted PersistentRootedId; -typedef PersistentRooted PersistentRootedObject; -typedef PersistentRooted PersistentRootedScript; -typedef PersistentRooted PersistentRootedString; +typedef PersistentRooted PersistentRootedId; +typedef PersistentRooted PersistentRootedObject; +typedef PersistentRooted PersistentRootedScript; +typedef PersistentRooted PersistentRootedString; typedef PersistentRooted PersistentRootedSymbol; -typedef PersistentRooted PersistentRootedValue; +typedef PersistentRooted PersistentRootedValue; -} // namespace JS +} // namespace JS #endif /* js_TypeDecls_h */ 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 @@ -10,6 +10,7 @@ #include "mozilla/Alignment.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" +#include "mozilla/HashFunctions.h" #include "mozilla/Maybe.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Move.h" @@ -162,8 +163,6 @@ // structure of the snapshot file, the analyses should be prepared for ubi::Node // graphs constructed from snapshots to be even more bizarre. -class JSAtom; - namespace JS { namespace ubi { @@ -171,8 +170,8 @@ class EdgeRange; class StackFrame; -} // namespace ubi -} // namespace JS +} // namespace ubi +} // namespace JS namespace JS { namespace ubi { @@ -186,118 +185,119 @@ template using Vector = mozilla::Vector; -/*** ubi::StackFrame ******************************************************************************/ +/*** ubi::StackFrame **********************************************************/ // Concrete JS::ubi::StackFrame instances backed by a live SavedFrame object // store their strings as JSAtom*, while deserialized stack frames from offline // 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 JS_PUBLIC_API(AtomOrTwoByteChars) : public Variant { - using Base = Variant; - - public: - template - MOZ_IMPLICIT AtomOrTwoByteChars(T&& rhs) : Base(Forward(rhs)) { } - - template - AtomOrTwoByteChars& operator=(T&& rhs) { - MOZ_ASSERT(this != &rhs, "self-move disallowed"); - this->~AtomOrTwoByteChars(); - new (this) AtomOrTwoByteChars(Forward(rhs)); - return *this; - } - - // Return the length of the given AtomOrTwoByteChars string. - size_t length(); - - // Copy the given AtomOrTwoByteChars string into the destination buffer, - // inflating if necessary. Does NOT null terminate. Returns the number of - // characters written to destination. - size_t copyToBuffer(RangedPtr destination, size_t length); +class JS_PUBLIC_API AtomOrTwoByteChars + : public Variant { + using Base = Variant; + + public: + template + MOZ_IMPLICIT AtomOrTwoByteChars(T&& rhs) : Base(Forward(rhs)) {} + + template + AtomOrTwoByteChars& operator=(T&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move disallowed"); + this->~AtomOrTwoByteChars(); + new (this) AtomOrTwoByteChars(Forward(rhs)); + return *this; + } + + // Return the length of the given AtomOrTwoByteChars string. + size_t length(); + + // Copy the given AtomOrTwoByteChars string into the destination buffer, + // inflating if necessary. Does NOT null terminate. Returns the number of + // characters written to destination. + size_t copyToBuffer(RangedPtr destination, size_t length); }; // The base class implemented by each ConcreteStackFrame type. Subclasses // must not add data members to this class. class BaseStackFrame { - friend class StackFrame; + friend class StackFrame; - BaseStackFrame(const StackFrame&) = delete; - BaseStackFrame& operator=(const StackFrame&) = delete; + BaseStackFrame(const StackFrame&) = delete; + BaseStackFrame& operator=(const StackFrame&) = delete; - protected: - void* ptr; - explicit BaseStackFrame(void* ptr) : ptr(ptr) { } - - public: - // This is a value type that should not have a virtual destructor. Don't add - // destructors in subclasses! - - // Get a unique identifier for this StackFrame. The identifier is not valid - // across garbage collections. - virtual uint64_t identifier() const { return uint64_t(uintptr_t(ptr)); } - - // Get this frame's parent frame. - virtual StackFrame parent() const = 0; - - // Get this frame's line number. - virtual uint32_t line() const = 0; - - // Get this frame's column number. - virtual uint32_t column() const = 0; - - // Get this frame's source name. Never null. - virtual AtomOrTwoByteChars source() const = 0; - - // Return this frame's function name if named, otherwise the inferred - // display name. Can be null. - virtual AtomOrTwoByteChars functionDisplayName() const = 0; - - // Returns true if this frame's function is system JavaScript running with - // trusted principals, false otherwise. - virtual bool isSystem() const = 0; - - // Return true if this frame's function is a self-hosted JavaScript builtin, - // false otherwise. - 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 - // cx's current compartment. - // - // Note that the process of - // - // SavedFrame - // | - // V - // JS::ubi::StackFrame - // | - // V - // offline heap snapshot - // | - // V - // JS::ubi::StackFrame - // | - // V - // SavedFrame - // - // is lossy because we cannot serialize and deserialize the SavedFrame's - // principals in the offline heap snapshot, so JS::ubi::StackFrame - // 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 MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx, - MutableHandleObject outSavedFrameStack) - const = 0; + protected: + void* ptr; + explicit BaseStackFrame(void* ptr) : ptr(ptr) {} + + public: + // This is a value type that should not have a virtual destructor. Don't add + // destructors in subclasses! + + // Get a unique identifier for this StackFrame. The identifier is not valid + // across garbage collections. + virtual uint64_t identifier() const { return uint64_t(uintptr_t(ptr)); } + + // Get this frame's parent frame. + virtual StackFrame parent() const = 0; + + // Get this frame's line number. + virtual uint32_t line() const = 0; + + // Get this frame's column number. + virtual uint32_t column() const = 0; + + // Get this frame's source name. Never null. + virtual AtomOrTwoByteChars source() const = 0; + + // Return this frame's function name if named, otherwise the inferred + // display name. Can be null. + virtual AtomOrTwoByteChars functionDisplayName() const = 0; + + // Returns true if this frame's function is system JavaScript running with + // trusted principals, false otherwise. + virtual bool isSystem() const = 0; + + // Return true if this frame's function is a self-hosted JavaScript builtin, + // false otherwise. + 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 + // cx's current compartment. + // + // Note that the process of + // + // SavedFrame + // | + // V + // JS::ubi::StackFrame + // | + // V + // offline heap snapshot + // | + // V + // JS::ubi::StackFrame + // | + // V + // SavedFrame + // + // is lossy because we cannot serialize and deserialize the SavedFrame's + // principals in the offline heap snapshot, so JS::ubi::StackFrame + // 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 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; + // Trace the concrete implementation of JS::ubi::StackFrame. + virtual void trace(JSTracer* trc) = 0; }; // A traits template with a specialization for each backing type that implements // the ubi::BaseStackFrame interface. Each specialization must be the a subclass // of ubi::BaseStackFrame. -template class ConcreteStackFrame; +template +class ConcreteStackFrame; // A JS::ubi::StackFrame represents a frame in a recorded stack. It can be // backed either by a live SavedFrame object or by a structure deserialized from @@ -313,166 +313,175 @@ // is an offline heap snapshot, the JS::ubi::StackFrame is valid as long as the // offline heap snapshot is alive. class StackFrame { - // Storage in which we allocate BaseStackFrame subclasses. - mozilla::AlignedStorage2 storage; + // Storage in which we allocate BaseStackFrame subclasses. + mozilla::AlignedStorage2 storage; - BaseStackFrame* base() { return storage.addr(); } - const BaseStackFrame* base() const { return storage.addr(); } + BaseStackFrame* base() { return storage.addr(); } + const BaseStackFrame* base() const { return storage.addr(); } - template - void construct(T* ptr) { - static_assert(mozilla::IsBaseOf>::value, - "ConcreteStackFrame must inherit from BaseStackFrame"); - static_assert(sizeof(ConcreteStackFrame) == sizeof(*base()), - "ubi::ConcreteStackFrame specializations must be the same size as " - "ubi::BaseStackFrame"); - ConcreteStackFrame::construct(base(), ptr); + template + void construct(T* ptr) { + static_assert( + mozilla::IsBaseOf>::value, + "ConcreteStackFrame must inherit from BaseStackFrame"); + static_assert( + sizeof(ConcreteStackFrame) == sizeof(*base()), + "ubi::ConcreteStackFrame specializations must be the same size as " + "ubi::BaseStackFrame"); + ConcreteStackFrame::construct(base(), ptr); + } + struct ConstructFunctor; + + public: + StackFrame() { construct(nullptr); } + + template + MOZ_IMPLICIT StackFrame(T* ptr) { + construct(ptr); + } + + template + StackFrame& operator=(T* ptr) { + construct(ptr); + return *this; + } + + // Constructors accepting SpiderMonkey's generic-pointer-ish types. + + template + explicit StackFrame(const JS::Handle& handle) { + construct(handle.get()); + } + + template + StackFrame& operator=(const JS::Handle& handle) { + construct(handle.get()); + return *this; + } + + template + explicit StackFrame(const JS::Rooted& root) { + construct(root.get()); + } + + template + StackFrame& operator=(const JS::Rooted& root) { + construct(root.get()); + return *this; + } + + // Because StackFrame is just a vtable pointer and an instance pointer, we + // can memcpy everything around instead of making concrete classes define + // virtual constructors. See the comment above Node's copy constructor for + // more details; that comment applies here as well. + StackFrame(const StackFrame& rhs) { + memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); + } + + StackFrame& operator=(const StackFrame& rhs) { + memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); + return *this; + } + + bool operator==(const StackFrame& rhs) const { + return base()->ptr == rhs.base()->ptr; + } + bool operator!=(const StackFrame& rhs) const { return !(*this == rhs); } + + explicit operator bool() const { return base()->ptr != nullptr; } + + // Copy this StackFrame's source name into the given |destination| + // buffer. Copy no more than |length| characters. The result is *not* null + // terminated. Returns how many characters were written into the buffer. + size_t source(RangedPtr destination, size_t length) const; + + // Copy this StackFrame's function display name into the given |destination| + // buffer. Copy no more than |length| characters. The result is *not* null + // terminated. Returns how many characters were written into the buffer. + size_t functionDisplayName(RangedPtr destination, + size_t length) const; + + // Get the size of the respective strings. 0 is returned for null strings. + size_t sourceLength(); + size_t functionDisplayNameLength(); + + // Methods that forward to virtual calls through BaseStackFrame. + + void trace(JSTracer* trc) { base()->trace(trc); } + uint64_t identifier() const { + auto id = base()->identifier(); + MOZ_ASSERT(JS::Value::isNumberRepresentable(id)); + return id; + } + uint32_t line() const { return base()->line(); } + uint32_t column() const { return base()->column(); } + AtomOrTwoByteChars source() const { return base()->source(); } + AtomOrTwoByteChars functionDisplayName() const { + return base()->functionDisplayName(); + } + StackFrame parent() const { return base()->parent(); } + bool isSystem() const { return base()->isSystem(); } + bool isSelfHosted(JSContext* cx) const { return base()->isSelfHosted(cx); } + MOZ_MUST_USE bool constructSavedFrameStack( + JSContext* cx, MutableHandleObject outSavedFrameStack) const { + return base()->constructSavedFrameStack(cx, outSavedFrameStack); + } + + struct HashPolicy { + using Lookup = JS::ubi::StackFrame; + + static js::HashNumber hash(const Lookup& lookup) { + return mozilla::HashGeneric(lookup.identifier()); } - struct ConstructFunctor; - - public: - StackFrame() { construct(nullptr); } - - template - MOZ_IMPLICIT StackFrame(T* ptr) { - construct(ptr); - } - - template - StackFrame& operator=(T* ptr) { - construct(ptr); - return *this; - } - - // Constructors accepting SpiderMonkey's generic-pointer-ish types. - template - explicit StackFrame(const JS::Handle& handle) { - construct(handle.get()); + static bool match(const StackFrame& key, const Lookup& lookup) { + return key == lookup; } - template - StackFrame& operator=(const JS::Handle& handle) { - construct(handle.get()); - return *this; - } - - template - explicit StackFrame(const JS::Rooted& root) { - construct(root.get()); - } - - template - StackFrame& operator=(const JS::Rooted& root) { - construct(root.get()); - return *this; - } - - // Because StackFrame is just a vtable pointer and an instance pointer, we - // can memcpy everything around instead of making concrete classes define - // virtual constructors. See the comment above Node's copy constructor for - // more details; that comment applies here as well. - StackFrame(const StackFrame& rhs) { - memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); - } - - StackFrame& operator=(const StackFrame& rhs) { - memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); - return *this; - } - - bool operator==(const StackFrame& rhs) const { return base()->ptr == rhs.base()->ptr; } - bool operator!=(const StackFrame& rhs) const { return !(*this == rhs); } - - explicit operator bool() const { - return base()->ptr != nullptr; - } - - // Copy this StackFrame's source name into the given |destination| - // buffer. Copy no more than |length| characters. The result is *not* null - // terminated. Returns how many characters were written into the buffer. - size_t source(RangedPtr destination, size_t length) const; - - // Copy this StackFrame's function display name into the given |destination| - // buffer. Copy no more than |length| characters. The result is *not* null - // terminated. Returns how many characters were written into the buffer. - size_t functionDisplayName(RangedPtr destination, size_t length) const; - - // Get the size of the respective strings. 0 is returned for null strings. - size_t sourceLength(); - size_t functionDisplayNameLength(); - - // Methods that forward to virtual calls through BaseStackFrame. - - void trace(JSTracer* trc) { base()->trace(trc); } - uint64_t identifier() const { - auto id = base()->identifier(); - MOZ_ASSERT(JS::Value::isNumberRepresentable(id)); - return id; - } - uint32_t line() const { return base()->line(); } - uint32_t column() const { return base()->column(); } - AtomOrTwoByteChars source() const { return base()->source(); } - AtomOrTwoByteChars functionDisplayName() const { return base()->functionDisplayName(); } - StackFrame parent() const { return base()->parent(); } - bool isSystem() const { return base()->isSystem(); } - bool isSelfHosted(JSContext* cx) const { return base()->isSelfHosted(cx); } - MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx, - MutableHandleObject outSavedFrameStack) const { - return base()->constructSavedFrameStack(cx, outSavedFrameStack); - } - - struct HashPolicy { - using Lookup = JS::ubi::StackFrame; - - static js::HashNumber hash(const Lookup& lookup) { - return lookup.identifier(); - } - - static bool match(const StackFrame& key, const Lookup& lookup) { - return key == lookup; - } - - static void rekey(StackFrame& k, const StackFrame& newKey) { - k = newKey; - } - }; + static void rekey(StackFrame& k, const StackFrame& newKey) { k = newKey; } + }; }; // The ubi::StackFrame null pointer. Any attempt to operate on a null // ubi::StackFrame crashes. -template<> +template <> class ConcreteStackFrame : public BaseStackFrame { - explicit ConcreteStackFrame(void* ptr) : BaseStackFrame(ptr) { } + explicit ConcreteStackFrame(void* ptr) : BaseStackFrame(ptr) {} - public: - static void construct(void* storage, void*) { new (storage) ConcreteStackFrame(nullptr); } - - uint64_t identifier() const override { return 0; } - void trace(JSTracer* trc) override { } - MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx, MutableHandleObject out) - const override - { - out.set(nullptr); - return true; - } - - uint32_t line() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } - uint32_t column() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } - AtomOrTwoByteChars source() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } - 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(JSContext* cx) const override { MOZ_CRASH("null JS::ubi::StackFrame"); } + public: + static void construct(void* storage, void*) { + new (storage) ConcreteStackFrame(nullptr); + } + + uint64_t identifier() const override { return 0; } + void trace(JSTracer* trc) override {} + MOZ_MUST_USE bool constructSavedFrameStack( + JSContext* cx, MutableHandleObject out) const override { + out.set(nullptr); + return true; + } + + uint32_t line() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } + uint32_t column() const override { MOZ_CRASH("null JS::ubi::StackFrame"); } + AtomOrTwoByteChars source() const override { + MOZ_CRASH("null JS::ubi::StackFrame"); + } + 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(JSContext* cx) const override { + MOZ_CRASH("null JS::ubi::StackFrame"); + } }; -MOZ_MUST_USE JS_PUBLIC_API(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 ************************************************************************************/ +/*** ubi::Node + * ************************************************************************************/ // A concrete node specialization can claim its referent is a member of a // particular "coarse type" which is less specific than the actual @@ -486,165 +495,160 @@ // be reused for new variants. Doing so will cause inspecting ubi::Nodes backed // by an offline heap snapshot from an older SpiderMonkey/Firefox version to // break. Consider this enum append only. -enum class CoarseType: uint32_t { - Other = 0, - Object = 1, - Script = 2, - String = 3, +enum class CoarseType : uint32_t { + Other = 0, + Object = 1, + Script = 2, + String = 3, - FIRST = Other, - LAST = String + FIRST = Other, + LAST = String }; -inline uint32_t -CoarseTypeToUint32(CoarseType type) -{ - return static_cast(type); +inline uint32_t CoarseTypeToUint32(CoarseType type) { + return static_cast(type); } -inline bool -Uint32IsValidCoarseType(uint32_t n) -{ - auto first = static_cast(CoarseType::FIRST); - auto last = static_cast(CoarseType::LAST); - MOZ_ASSERT(first < last); - return first <= n && n <= last; +inline bool Uint32IsValidCoarseType(uint32_t n) { + auto first = static_cast(CoarseType::FIRST); + auto last = static_cast(CoarseType::LAST); + MOZ_ASSERT(first < last); + return first <= n && n <= last; } -inline CoarseType -Uint32ToCoarseType(uint32_t n) -{ - MOZ_ASSERT(Uint32IsValidCoarseType(n)); - return static_cast(n); +inline CoarseType Uint32ToCoarseType(uint32_t n) { + MOZ_ASSERT(Uint32IsValidCoarseType(n)); + return static_cast(n); } // The base class implemented by each ubi::Node referent type. Subclasses must // not add data members to this class. -class JS_PUBLIC_API(Base) { - friend class Node; - - // For performance's sake, we'd prefer to avoid a virtual destructor; and - // an empty constructor seems consistent with the 'lightweight value type' - // visible behavior we're trying to achieve. But if the destructor isn't - // virtual, and a subclass overrides it, the subclass's destructor will be - // ignored. Is there a way to make the compiler catch that error? - - protected: - // Space for the actual pointer. Concrete subclasses should define a - // properly typed 'get' member function to access this. - void* ptr; - - explicit Base(void* ptr) : ptr(ptr) { } - - public: - bool operator==(const Base& rhs) const { - // Some compilers will indeed place objects of different types at - // the same address, so technically, we should include the vtable - // in this comparison. But it seems unlikely to cause problems in - // practice. - return ptr == rhs.ptr; - } - bool operator!=(const Base& rhs) const { return !(*this == rhs); } - - // An identifier for this node, guaranteed to be stable and unique for as - // long as this ubi::Node's referent is alive and at the same address. - // - // This is probably suitable for use in serializations, as it is an integral - // type. It may also help save memory when constructing HashSets of - // ubi::Nodes: since a uint64_t will always be smaller-or-equal-to the size - // of a ubi::Node, a HashSet may use less space per element - // than a HashSet. - // - // (Note that 'unique' only means 'up to equality on ubi::Node'; see the - // caveats about multiple objects allocated at the same address for - // 'ubi::Node::operator=='.) - using Id = uint64_t; - virtual Id identifier() const { return Id(uintptr_t(ptr)); } - - // Returns true if this node is pointing to something on the live heap, as - // opposed to something from a deserialized core dump. Returns false, - // otherwise. - virtual bool isLive() const { return true; }; - - // Return the coarse-grained type-of-thing that this node represents. - 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 u"strings" for this.) - // - // This must always return Concrete::concreteTypeName; we use that - // pointer as a tag for this particular referent type. - virtual const char16_t* typeName() const = 0; - - // Return the size of this node, in bytes. Include any structures that this - // 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; } - - // Return an EdgeRange that initially contains all the referent's outgoing - // edges. The caller takes ownership of the EdgeRange. - // - // If wantNames is true, compute names for edges. Doing so can be expensive - // in time and memory. - 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. - virtual JS::Zone* zone() const { return nullptr; } - - // Return the compartment for this node. Some ubi::Node referents are not - // associated with JSCompartments, such as JSStrings (which are associated - // with Zones). When the referent is not associated with a compartment, - // nullptr is returned. - virtual JSCompartment* compartment() const { return nullptr; } - - // Return whether this node's referent's allocation stack was captured. - virtual bool hasAllocationStack() const { return false; } - - // Get the stack recorded at the time this node's referent was - // allocated. This must only be called when hasAllocationStack() is true. - virtual StackFrame allocationStack() const { - MOZ_CRASH("Concrete classes that have an allocation stack must override both " - "hasAllocationStack and allocationStack."); - } - - // Methods for JSObject Referents - // - // These methods are only semantically valid if the referent is either a - // JSObject in the live heap, or represents a previously existing JSObject - // from some deserialized heap snapshot. - - // Return the object's [[Class]]'s name. - virtual const char* jsObjectClassName() const { return nullptr; } - - // If this object was constructed with `new` and we have the data available, - // place the contructor function's display name in the out parameter. - // 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 MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) - const - { - outName.reset(nullptr); - return true; - } - - // Methods for CoarseType::Script referents +class JS_PUBLIC_API Base { + friend class Node; - // Return the script's source's filename if available. If unavailable, - // return nullptr. - virtual const char* scriptFilename() const { return nullptr; } - - private: - Base(const Base& rhs) = delete; - Base& operator=(const Base& rhs) = delete; + // For performance's sake, we'd prefer to avoid a virtual destructor; and + // an empty constructor seems consistent with the 'lightweight value type' + // visible behavior we're trying to achieve. But if the destructor isn't + // virtual, and a subclass overrides it, the subclass's destructor will be + // ignored. Is there a way to make the compiler catch that error? + + protected: + // Space for the actual pointer. Concrete subclasses should define a + // properly typed 'get' member function to access this. + void* ptr; + + explicit Base(void* ptr) : ptr(ptr) {} + + public: + bool operator==(const Base& rhs) const { + // Some compilers will indeed place objects of different types at + // the same address, so technically, we should include the vtable + // in this comparison. But it seems unlikely to cause problems in + // practice. + return ptr == rhs.ptr; + } + bool operator!=(const Base& rhs) const { return !(*this == rhs); } + + // An identifier for this node, guaranteed to be stable and unique for as + // long as this ubi::Node's referent is alive and at the same address. + // + // This is probably suitable for use in serializations, as it is an integral + // type. It may also help save memory when constructing HashSets of + // ubi::Nodes: since a uint64_t will always be smaller-or-equal-to the size + // of a ubi::Node, a HashSet may use less space per element + // than a HashSet. + // + // (Note that 'unique' only means 'up to equality on ubi::Node'; see the + // caveats about multiple objects allocated at the same address for + // 'ubi::Node::operator=='.) + using Id = uint64_t; + virtual Id identifier() const { return Id(uintptr_t(ptr)); } + + // Returns true if this node is pointing to something on the live heap, as + // opposed to something from a deserialized core dump. Returns false, + // otherwise. + virtual bool isLive() const { return true; }; + + // Return the coarse-grained type-of-thing that this node represents. + 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 u"strings" for this.) + // + // This must always return Concrete::concreteTypeName; we use that + // pointer as a tag for this particular referent type. + virtual const char16_t* typeName() const = 0; + + // Return the size of this node, in bytes. Include any structures that this + // 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; } + + // Return an EdgeRange that initially contains all the referent's outgoing + // edges. The caller takes ownership of the EdgeRange. + // + // If wantNames is true, compute names for edges. Doing so can be expensive + // in time and memory. + 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. + virtual JS::Zone* zone() const { return nullptr; } + + // Return the compartment for this node. Some ubi::Node referents are not + // associated with JSCompartments, such as JSStrings (which are associated + // with Zones). When the referent is not associated with a compartment, + // nullptr is returned. + virtual JSCompartment* compartment() const { return nullptr; } + + // Return whether this node's referent's allocation stack was captured. + virtual bool hasAllocationStack() const { return false; } + + // Get the stack recorded at the time this node's referent was + // allocated. This must only be called when hasAllocationStack() is true. + virtual StackFrame allocationStack() const { + MOZ_CRASH( + "Concrete classes that have an allocation stack must override both " + "hasAllocationStack and allocationStack."); + } + + // Methods for JSObject Referents + // + // These methods are only semantically valid if the referent is either a + // JSObject in the live heap, or represents a previously existing JSObject + // from some deserialized heap snapshot. + + // Return the object's [[Class]]'s name. + virtual const char* jsObjectClassName() const { return nullptr; } + + // If this object was constructed with `new` and we have the data available, + // place the contructor function's display name in the out parameter. + // 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 MOZ_MUST_USE bool jsObjectConstructorName( + JSContext* cx, UniqueTwoByteChars& outName) const { + outName.reset(nullptr); + return true; + } + + // Methods for CoarseType::Script referents + + // Return the script's source's filename if available. If unavailable, + // return nullptr. + virtual const char* scriptFilename() const { return nullptr; } + + private: + Base(const Base& rhs) = delete; + Base& operator=(const Base& rhs) = delete; }; // A traits template with a specialization for each referent type that @@ -668,211 +672,209 @@ // // So we delegate the actual construction to this specialization, which // // knows Referent's details. // static void construct(void* storage, Referent* referent); -template +template 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. class Node { - // Storage in which we allocate Base subclasses. - mozilla::AlignedStorage2 storage; - Base* base() { return storage.addr(); } - const Base* base() const { return storage.addr(); } - - template - 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; - - public: - Node() { construct(nullptr); } - - template - MOZ_IMPLICIT Node(T* ptr) { - construct(ptr); - } - template - Node& operator=(T* ptr) { - construct(ptr); - return *this; - } - - // We can construct and assign from rooted forms of pointers. - template - MOZ_IMPLICIT Node(const Rooted& root) { - construct(root.get()); - } - template - Node& operator=(const Rooted& root) { - construct(root.get()); - return *this; - } - - // Constructors accepting SpiderMonkey's other generic-pointer-ish types. - // Note that we *do* want an implicit constructor here: JS::Value and - // JS::ubi::Node are both essentially tagged references to other sorts of - // objects, so letting conversions happen automatically is appropriate. - MOZ_IMPLICIT Node(JS::HandleValue value); - explicit Node(const JS::GCCellPtr& thing); - - // copy construction and copy assignment just use memcpy, since we know - // instances contain nothing but a vtable pointer and a data pointer. - // - // To be completely correct, concrete classes could provide a virtual - // 'construct' member function, which we could invoke on rhs to construct an - // instance in our storage. But this is good enough; there's no need to jump - // through vtables for copying and assignment that are just going to move - // two words around. The compiler knows how to optimize memcpy. - Node(const Node& rhs) { - memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); - } - - Node& operator=(const Node& rhs) { - memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); - return *this; - } - - bool operator==(const Node& rhs) const { return *base() == *rhs.base(); } - bool operator!=(const Node& rhs) const { return *base() != *rhs.base(); } - - explicit operator bool() const { - return base()->ptr != nullptr; - } - - bool isLive() const { return base()->isLive(); } - - // Get the canonical type name for the given type T. - template - static const char16_t* canonicalTypeName() { return Concrete::concreteTypeName; } - - template - bool is() const { - return base()->typeName() == canonicalTypeName(); - } - - template - T* as() const { - MOZ_ASSERT(isLive()); - MOZ_ASSERT(is()); - return static_cast(base()->ptr); - } - - template - T* asOrNull() const { - MOZ_ASSERT(isLive()); - return is() ? static_cast(base()->ptr) : nullptr; - } - - // If this node refers to something that can be represented as a JavaScript - // value that is safe to expose to JavaScript code, return that value. - // Otherwise return UndefinedValue(). JSStrings, JS::Symbols, and some (but - // not all!) JSObjects can be exposed. - JS::Value exposeToJS() const; - - CoarseType coarseType() const { return base()->coarseType(); } - const char16_t* typeName() const { return base()->typeName(); } - JS::Zone* zone() const { return base()->zone(); } - JSCompartment* compartment() const { return base()->compartment(); } - const char* jsObjectClassName() const { return base()->jsObjectClassName(); } - MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) const { - return base()->jsObjectConstructorName(cx, outName); - } - - const char* scriptFilename() const { return base()->scriptFilename(); } - - using Size = Base::Size; - Size size(mozilla::MallocSizeOf mallocSizeof) const { - auto size = base()->size(mallocSizeof); - MOZ_ASSERT(size > 0, - "C++ does not have zero-sized types! Choose 1 if you just need a " - "conservative default."); - return size; - } - - js::UniquePtr edges(JSContext* cx, bool wantNames = true) const { - return base()->edges(cx, wantNames); - } - - bool hasAllocationStack() const { return base()->hasAllocationStack(); } - StackFrame allocationStack() const { - return base()->allocationStack(); - } - - using Id = Base::Id; - Id identifier() const { - auto id = base()->identifier(); - MOZ_ASSERT(JS::Value::isNumberRepresentable(id)); - return id; - } - - // A hash policy for ubi::Nodes. - // This simply uses the stock PointerHasher on the ubi::Node's pointer. - // We specialize DefaultHasher below to make this the default. - class HashPolicy { - typedef js::PointerHasher::value> PtrHash; - - public: - typedef Node Lookup; - - static js::HashNumber hash(const Lookup& l) { return PtrHash::hash(l.base()->ptr); } - static bool match(const Node& k, const Lookup& l) { return k == l; } - static void rekey(Node& k, const Node& newKey) { k = newKey; } - }; + // Storage in which we allocate Base subclasses. + mozilla::AlignedStorage2 storage; + Base* base() { return storage.addr(); } + const Base* base() const { return storage.addr(); } + + template + 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; + + public: + Node() { construct(nullptr); } + + template + MOZ_IMPLICIT Node(T* ptr) { + construct(ptr); + } + template + Node& operator=(T* ptr) { + construct(ptr); + return *this; + } + + // We can construct and assign from rooted forms of pointers. + template + MOZ_IMPLICIT Node(const Rooted& root) { + construct(root.get()); + } + template + Node& operator=(const Rooted& root) { + construct(root.get()); + return *this; + } + + // Constructors accepting SpiderMonkey's other generic-pointer-ish types. + // Note that we *do* want an implicit constructor here: JS::Value and + // JS::ubi::Node are both essentially tagged references to other sorts of + // objects, so letting conversions happen automatically is appropriate. + MOZ_IMPLICIT Node(JS::HandleValue value); + explicit Node(const JS::GCCellPtr& thing); + + // copy construction and copy assignment just use memcpy, since we know + // instances contain nothing but a vtable pointer and a data pointer. + // + // To be completely correct, concrete classes could provide a virtual + // 'construct' member function, which we could invoke on rhs to construct an + // instance in our storage. But this is good enough; there's no need to jump + // through vtables for copying and assignment that are just going to move + // two words around. The compiler knows how to optimize memcpy. + Node(const Node& rhs) { + memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); + } + + Node& operator=(const Node& rhs) { + memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u)); + return *this; + } + + bool operator==(const Node& rhs) const { return *base() == *rhs.base(); } + bool operator!=(const Node& rhs) const { return *base() != *rhs.base(); } + + explicit operator bool() const { return base()->ptr != nullptr; } + + bool isLive() const { return base()->isLive(); } + + // Get the canonical type name for the given type T. + template + static const char16_t* canonicalTypeName() { + return Concrete::concreteTypeName; + } + + template + bool is() const { + return base()->typeName() == canonicalTypeName(); + } + + template + T* as() const { + MOZ_ASSERT(isLive()); + MOZ_ASSERT(is()); + return static_cast(base()->ptr); + } + + template + T* asOrNull() const { + MOZ_ASSERT(isLive()); + return is() ? static_cast(base()->ptr) : nullptr; + } + + // If this node refers to something that can be represented as a JavaScript + // value that is safe to expose to JavaScript code, return that value. + // Otherwise return UndefinedValue(). JSStrings, JS::Symbols, and some (but + // not all!) JSObjects can be exposed. + JS::Value exposeToJS() const; + + CoarseType coarseType() const { return base()->coarseType(); } + const char16_t* typeName() const { return base()->typeName(); } + JS::Zone* zone() const { return base()->zone(); } + JSCompartment* compartment() const { return base()->compartment(); } + const char* jsObjectClassName() const { return base()->jsObjectClassName(); } + MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, + UniqueTwoByteChars& outName) const { + return base()->jsObjectConstructorName(cx, outName); + } + + const char* scriptFilename() const { return base()->scriptFilename(); } + + using Size = Base::Size; + Size size(mozilla::MallocSizeOf mallocSizeof) const { + auto size = base()->size(mallocSizeof); + MOZ_ASSERT( + size > 0, + "C++ does not have zero-sized types! Choose 1 if you just need a " + "conservative default."); + return size; + } + + js::UniquePtr edges(JSContext* cx, bool wantNames = true) const { + return base()->edges(cx, wantNames); + } + + bool hasAllocationStack() const { return base()->hasAllocationStack(); } + StackFrame allocationStack() const { return base()->allocationStack(); } + + using Id = Base::Id; + Id identifier() const { + auto id = base()->identifier(); + MOZ_ASSERT(JS::Value::isNumberRepresentable(id)); + return id; + } + + // A hash policy for ubi::Nodes. + // This simply uses the stock PointerHasher on the ubi::Node's pointer. + // We specialize DefaultHasher below to make this the default. + class HashPolicy { + typedef js::PointerHasher PtrHash; + + public: + typedef Node Lookup; + + static js::HashNumber hash(const Lookup& l) { + return PtrHash::hash(l.base()->ptr); + } + static bool match(const Node& k, const Lookup& l) { return k == l; } + static void rekey(Node& k, const Node& newKey) { k = newKey; } + }; }; -using NodeSet = js::HashSet, js::SystemAllocPolicy>; +using NodeSet = + js::HashSet, js::SystemAllocPolicy>; using NodeSetPtr = mozilla::UniquePtr>; -/*** Edge and EdgeRange ***************************************************************************/ +/*** Edge and EdgeRange *******************************************************/ using EdgeName = UniqueTwoByteChars; // An outgoing edge to a referent node. class Edge { - public: - Edge() : name(nullptr), referent() { } + public: + Edge() : name(nullptr), referent() {} - // Construct an initialized Edge, taking ownership of |name|. - Edge(char16_t* name, const Node& referent) - : name(name) - , referent(referent) - { } - - // Move construction and assignment. - Edge(Edge&& rhs) - : name(mozilla::Move(rhs.name)) - , referent(rhs.referent) - { } - - Edge& operator=(Edge&& rhs) { - MOZ_ASSERT(&rhs != this); - this->~Edge(); - new (this) Edge(mozilla::Move(rhs)); - return *this; - } + // Construct an initialized Edge, taking ownership of |name|. + Edge(char16_t* name, const Node& referent) : name(name), referent(referent) {} - Edge(const Edge&) = delete; - Edge& operator=(const Edge&) = delete; + // Move construction and assignment. + Edge(Edge&& rhs) : name(mozilla::Move(rhs.name)), referent(rhs.referent) {} - // This edge's name. This may be nullptr, if Node::edges was called with - // false as the wantNames parameter. - // - // The storage is owned by this Edge, and will be freed when this Edge is - // 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 - // to think about lifetimes carefully to ensure traversal stays cheap.) - EdgeName name; + Edge& operator=(Edge&& rhs) { + MOZ_ASSERT(&rhs != this); + this->~Edge(); + new (this) Edge(mozilla::Move(rhs)); + return *this; + } + + Edge(const Edge&) = delete; + Edge& operator=(const Edge&) = delete; + + // This edge's name. This may be nullptr, if Node::edges was called with + // false as the wantNames parameter. + // + // The storage is owned by this Edge, and will be freed when this Edge is + // 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 + // to think about lifetimes carefully to ensure traversal stays cheap.) + EdgeName name; - // This edge's referent. - Node referent; + // This edge's referent. + Node referent; }; // EdgeRange is an abstract base class for iterating over a node's outgoing @@ -884,34 +886,33 @@ // JS::TraceChildren to to get the outgoing edges, and then store them in an // array internal to the EdgeRange. class EdgeRange { - protected: - // The current front edge of this range, or nullptr if this range is empty. - Edge* front_; - - EdgeRange() : front_(nullptr) { } - - public: - virtual ~EdgeRange() { } - - // True if there are no more edges in this range. - bool empty() const { return !front_; } - - // The front edge of this range. This is owned by the EdgeRange, and is - // only guaranteed to live until the next call to popFront, or until - // the EdgeRange is destructed. - const Edge& front() const { return *front_; } - Edge& front() { return *front_; } - - // Remove the front edge from this range. This should only be called if - // !empty(). - virtual void popFront() = 0; - - private: - EdgeRange(const EdgeRange&) = delete; - EdgeRange& operator=(const EdgeRange&) = delete; + protected: + // The current front edge of this range, or nullptr if this range is empty. + Edge* front_; + + EdgeRange() : front_(nullptr) {} + + public: + virtual ~EdgeRange() {} + + // True if there are no more edges in this range. + bool empty() const { return !front_; } + + // The front edge of this range. This is owned by the EdgeRange, and is + // only guaranteed to live until the next call to popFront, or until + // the EdgeRange is destructed. + const Edge& front() const { return *front_; } + Edge& front() { return *front_; } + + // Remove the front edge from this range. This should only be called if + // !empty(). + virtual void popFront() = 0; + + private: + EdgeRange(const EdgeRange&) = delete; + EdgeRange& operator=(const EdgeRange&) = delete; }; - typedef mozilla::Vector EdgeVector; // An EdgeRange concrete class that holds a pre-existing vector of @@ -919,29 +920,24 @@ // EdgeVector; it is up to the PreComputedEdgeRange's consumer to manage // that lifetime. class PreComputedEdgeRange : public EdgeRange { - EdgeVector& edges; - size_t i; - - void settle() { - front_ = i < edges.length() ? &edges[i] : nullptr; - } + EdgeVector& edges; + size_t i; - public: - explicit PreComputedEdgeRange(EdgeVector& edges) - : edges(edges), - i(0) - { - settle(); - } + void settle() { front_ = i < edges.length() ? &edges[i] : nullptr; } - void popFront() override { - MOZ_ASSERT(!empty()); - i++; - settle(); - } + public: + explicit PreComputedEdgeRange(EdgeVector& edges) : edges(edges), i(0) { + settle(); + } + + void popFront() override { + MOZ_ASSERT(!empty()); + i++; + settle(); + } }; -/*** RootList *************************************************************************************/ +/*** RootList *****************************************************************/ // RootList is a class that can be pointed to by a |ubi::Node|, creating a // fictional root-of-roots which has edges to every GC root in the JS @@ -971,176 +967,190 @@ // // ... // } -class MOZ_STACK_CLASS JS_PUBLIC_API(RootList) { - Maybe& noGC; +class MOZ_STACK_CLASS JS_PUBLIC_API RootList { + Maybe& noGC; - public: - JSContext* cx; - EdgeVector edges; - bool wantNames; - - RootList(JSContext* cx, Maybe& noGC, bool wantNames = false); - - // Find all GC roots. - 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. - bool initialized() { return noGC.isSome(); } - - // 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. - MOZ_MUST_USE bool addRoot(Node node, const char16_t* edgeName = nullptr); + public: + JSContext* cx; + EdgeVector edges; + bool wantNames; + + RootList(JSContext* cx, Maybe& noGC, + bool wantNames = false); + + // Find all GC roots. + 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. + bool initialized() { return noGC.isSome(); } + + // 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. + MOZ_MUST_USE bool addRoot(Node node, const char16_t* edgeName = nullptr); }; +/*** Concrete classes for ubi::Node referent types ****************************/ -/*** Concrete classes for ubi::Node referent types ************************************************/ - -template<> -class JS_PUBLIC_API(Concrete) : public Base { - protected: - explicit Concrete(RootList* ptr) : Base(ptr) { } - RootList& get() const { return *static_cast(ptr); } +template <> +class JS_PUBLIC_API Concrete : public Base { + protected: + explicit Concrete(RootList* ptr) : Base(ptr) {} + RootList& get() const { return *static_cast(ptr); } + + public: + static void construct(void* storage, RootList* ptr) { + new (storage) Concrete(ptr); + } - public: - static void construct(void* storage, RootList* ptr) { new (storage) Concrete(ptr); } + js::UniquePtr edges(JSContext* cx, bool wantNames) const override; - js::UniquePtr edges(JSContext* cx, bool wantNames) const override; - - const char16_t* typeName() const override { return concreteTypeName; } - static const char16_t concreteTypeName[]; + 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 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); } +template +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); } }; // For JS::TraceChildren-based types that have a 'compartment' method. -template -class JS_PUBLIC_API(TracerConcreteWithCompartment) : public TracerConcrete { - typedef TracerConcrete TracerBase; - JSCompartment* compartment() const override; +template +class JS_PUBLIC_API TracerConcreteWithCompartment + : public TracerConcrete { + typedef TracerConcrete TracerBase; + JSCompartment* compartment() const override; - protected: - explicit TracerConcreteWithCompartment(Referent* ptr) : TracerBase(ptr) { } + protected: + explicit TracerConcreteWithCompartment(Referent* ptr) : TracerBase(ptr) {} }; // Define specializations for some commonly-used public JSAPI types. // These can use the generic templates above. -template<> -class JS_PUBLIC_API(Concrete) : TracerConcrete { - protected: - explicit Concrete(JS::Symbol* ptr) : TracerConcrete(ptr) { } - - public: - static void construct(void* storage, JS::Symbol* ptr) { - new (storage) Concrete(ptr); - } +template <> +class JS_PUBLIC_API Concrete : TracerConcrete { + protected: + explicit Concrete(JS::Symbol* ptr) : TracerConcrete(ptr) {} + + public: + static void construct(void* storage, JS::Symbol* ptr) { + new (storage) Concrete(ptr); + } - Size size(mozilla::MallocSizeOf mallocSizeOf) const override; + Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - const char16_t* typeName() const override { return concreteTypeName; } - static const char16_t concreteTypeName[]; + 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); } - - CoarseType coarseType() const final { return CoarseType::Script; } - Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - const char* scriptFilename() const final; +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); + } + + 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[]; + 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) { } - - public: - static void construct(void* storage, JSObject* ptr) { - new (storage) Concrete(ptr); - } +template <> +class JS_PUBLIC_API Concrete + : public TracerConcreteWithCompartment { + protected: + explicit Concrete(JSObject* ptr) : TracerConcreteWithCompartment(ptr) {} + + public: + static void construct(void* storage, JSObject* ptr) { + new (storage) Concrete(ptr); + } + + const char* jsObjectClassName() const override; + MOZ_MUST_USE bool jsObjectConstructorName( + JSContext* cx, UniqueTwoByteChars& outName) const override; + Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - const char* jsObjectClassName() const override; - MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) - const override; - Size size(mozilla::MallocSizeOf mallocSizeOf) const override; + bool hasAllocationStack() const override; + StackFrame allocationStack() const override; - bool hasAllocationStack() const override; - StackFrame allocationStack() const override; + CoarseType coarseType() const final { return CoarseType::Object; } - CoarseType coarseType() const final { return CoarseType::Object; } - - const char16_t* typeName() const override { return concreteTypeName; } - static const char16_t concreteTypeName[]; + 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); } +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; + Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - CoarseType coarseType() const final { return CoarseType::String; } + CoarseType coarseType() const final { return CoarseType::String; } - const char16_t* typeName() const override { return concreteTypeName; } - static const char16_t concreteTypeName[]; + 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 JS_PUBLIC_API(Concrete) : public Base { - const char16_t* typeName() const override; - Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - js::UniquePtr edges(JSContext* cx, bool wantNames) const override; - JS::Zone* zone() const override; - JSCompartment* compartment() const override; - CoarseType coarseType() const final; - - explicit Concrete(void* ptr) : Base(ptr) { } - - public: - static void construct(void* storage, void* ptr) { new (storage) Concrete(ptr); } +// The ubi::Node null pointer. Any attempt to operate on a null ubi::Node +// asserts. +template <> +class JS_PUBLIC_API Concrete : public Base { + const char16_t* typeName() const override; + Size size(mozilla::MallocSizeOf mallocSizeOf) const override; + js::UniquePtr edges(JSContext* cx, bool wantNames) const override; + JS::Zone* zone() const override; + JSCompartment* compartment() const override; + CoarseType coarseType() const final; + + explicit Concrete(void* ptr) : Base(ptr) {} + + public: + static void construct(void* storage, void* ptr) { + new (storage) Concrete(ptr); + } }; - -} // namespace ubi -} // namespace JS +} // namespace ubi +} // namespace JS namespace js { // Make ubi::Node::HashPolicy the default hash policy for ubi::Node. -template<> struct DefaultHasher : JS::ubi::Node::HashPolicy { }; -template<> struct DefaultHasher : JS::ubi::StackFrame::HashPolicy { }; +template <> +struct DefaultHasher : JS::ubi::Node::HashPolicy {}; +template <> +struct DefaultHasher : JS::ubi::StackFrame::HashPolicy {}; -} // namespace js +} // namespace js -#endif // js_UbiNode_h +#endif // js_UbiNode_h 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 @@ -43,8 +43,9 @@ // // The visitor function, called to report that we have traversed // |edge| from |origin|. This is called once for each edge we traverse. -// As this is a breadth-first search, any prior calls to the visitor function -// were for origin nodes not further from the start nodes than |origin|. +// As this is a breadth-first search, any prior calls to the visitor +// function were for origin nodes not further from the start nodes than +// |origin|. // // |traversal| is this traversal object, passed along for convenience. // @@ -74,171 +75,171 @@ // error occurs. A false return value terminates the traversal // immediately, and causes BreadthFirst::traverse to return // false. -template +template struct BreadthFirst { - - // Construct a breadth-first traversal object that reports the nodes it - // reaches to |handler|. The traversal asserts that no GC happens in its - // runtime during its lifetime. - // - // We do nothing with noGC, other than require it to exist, with a lifetime - // that encloses our own. - BreadthFirst(JSContext* cx, Handler& handler, const JS::AutoCheckCannotGC& noGC) - : wantNames(true), cx(cx), visited(), handler(handler), pending(), - traversalBegun(false), stopRequested(false), abandonRequested(false) - { } - - // Initialize this traversal object. Return false on OOM. - bool init() { return visited.init(); } - - // Add |node| as a starting point for the traversal. You may add - // as many starting points as you like. Return false on OOM. - bool addStart(Node node) { return pending.append(node); } - - // Add |node| as a starting point for the traversal (see addStart) and also - // add it to the |visited| set. Return false on OOM. - bool addStartVisited(Node node) { - typename NodeMap::AddPtr ptr = visited.lookupForAdd(node); - if (!ptr && !visited.add(ptr, node, typename Handler::NodeData())) + // Construct a breadth-first traversal object that reports the nodes it + // reaches to |handler|. The traversal asserts that no GC happens in its + // runtime during its lifetime. + // + // We do nothing with noGC, other than require it to exist, with a lifetime + // that encloses our own. + BreadthFirst(JSContext* cx, Handler& handler, const JS::AutoRequireNoGC& noGC) + : wantNames(true), + cx(cx), + visited(), + handler(handler), + pending(), + traversalBegun(false), + stopRequested(false), + abandonRequested(false) {} + + // Initialize this traversal object. Return false on OOM. + bool init() { return visited.init(); } + + // Add |node| as a starting point for the traversal. You may add + // as many starting points as you like. Return false on OOM. + bool addStart(Node node) { return pending.append(node); } + + // Add |node| as a starting point for the traversal (see addStart) and also + // add it to the |visited| set. Return false on OOM. + bool addStartVisited(Node node) { + typename NodeMap::AddPtr ptr = visited.lookupForAdd(node); + if (!ptr && !visited.add(ptr, node, typename Handler::NodeData())) + return false; + return addStart(node); + } + + // True if the handler wants us to compute edge names; doing so can be + // expensive in time and memory. True by default. + bool wantNames; + + // Traverse the graph in breadth-first order, starting at the given + // start nodes, applying |handler::operator()| for each edge traversed + // as described above. + // + // This should be called only once per instance of this class. + // + // Return false on OOM or error return from |handler::operator()|. + bool traverse() { + MOZ_ASSERT(!traversalBegun); + traversalBegun = true; + + // While there are pending nodes, visit them. + while (!pending.empty()) { + Node origin = pending.front(); + pending.popFront(); + + // Get a range containing all origin's outgoing edges. + auto range = origin.edges(cx, wantNames); + if (!range) return false; + + // Traverse each edge. + for (; !range->empty(); range->popFront()) { + MOZ_ASSERT(!stopRequested); + + Edge& edge = range->front(); + typename NodeMap::AddPtr a = visited.lookupForAdd(edge.referent); + bool first = !a; + + if (first) { + // This is the first time we've reached |edge.referent|. + // Mark it as visited. + if (!visited.add(a, edge.referent, typename Handler::NodeData())) return false; - return addStart(node); - } - - // True if the handler wants us to compute edge names; doing so can be - // expensive in time and memory. True by default. - bool wantNames; - - // Traverse the graph in breadth-first order, starting at the given - // start nodes, applying |handler::operator()| for each edge traversed - // as described above. - // - // This should be called only once per instance of this class. - // - // Return false on OOM or error return from |handler::operator()|. - bool traverse() - { - MOZ_ASSERT(!traversalBegun); - traversalBegun = true; - - // While there are pending nodes, visit them. - while (!pending.empty()) { - Node origin = pending.front(); - pending.popFront(); - - // Get a range containing all origin's outgoing edges. - auto range = origin.edges(cx, wantNames); - if (!range) - return false; - - // Traverse each edge. - for (; !range->empty(); range->popFront()) { - MOZ_ASSERT(!stopRequested); - - Edge& edge = range->front(); - typename NodeMap::AddPtr a = visited.lookupForAdd(edge.referent); - bool first = !a; - - if (first) { - // This is the first time we've reached |edge.referent|. - // Mark it as visited. - if (!visited.add(a, edge.referent, typename Handler::NodeData())) - return false; - } - - MOZ_ASSERT(a); - - // Report this edge to the visitor function. - if (!handler(*this, origin, edge, &a->value(), first)) - return false; - - if (stopRequested) - return true; - - // Arrange to traverse this edge's referent's outgoing edges - // later --- unless |handler| asked us not to. - if (abandonRequested) { - // Skip the enqueue; reset flag for future iterations. - abandonRequested = false; - } else if (first) { - if (!pending.append(edge.referent)) - return false; - } - } } - return true; - } + MOZ_ASSERT(a); - // Stop traversal, and return true from |traverse| without visiting any - // more nodes. Only |handler::operator()| should call this function; it - // may do so to stop the traversal early, without returning false and - // then making |traverse|'s caller disambiguate that result from a real - // error. - void stop() { stopRequested = true; } - - // Request that the current edge's referent's outgoing edges not be - // traversed. This must be called the first time that referent is reached. - // Other edges *to* that referent will still be traversed. - void abandonReferent() { abandonRequested = true; } - - // 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 - // |handler| can access it to see the traversal thus far. - using NodeMap = js::HashMap, - js::SystemAllocPolicy>; - NodeMap visited; - - private: - // Our handler object. - Handler& handler; - - // A queue template. Appending and popping the front are constant time. - // Wasted space is never more than some recent actual population plus the - // current population. - template - class Queue { - js::Vector head, tail; - size_t frontIndex; - public: - Queue() : head(), tail(), frontIndex(0) { } - bool empty() { return frontIndex >= head.length(); } - T& front() { - MOZ_ASSERT(!empty()); - return head[frontIndex]; - } - void popFront() { - MOZ_ASSERT(!empty()); - frontIndex++; - if (frontIndex >= head.length()) { - head.clearAndFree(); - head.swap(tail); - frontIndex = 0; - } - } - bool append(const T& elt) { - return frontIndex == 0 ? head.append(elt) : tail.append(elt); + // Report this edge to the visitor function. + if (!handler(*this, origin, edge, &a->value(), first)) return false; + + if (stopRequested) return true; + + // Arrange to traverse this edge's referent's outgoing edges + // later --- unless |handler| asked us not to. + if (abandonRequested) { + // Skip the enqueue; reset flag for future iterations. + abandonRequested = false; + } else if (first) { + if (!pending.append(edge.referent)) return false; } - }; + } + } + + return true; + } + + // Stop traversal, and return true from |traverse| without visiting any + // more nodes. Only |handler::operator()| should call this function; it + // may do so to stop the traversal early, without returning false and + // then making |traverse|'s caller disambiguate that result from a real + // error. + void stop() { stopRequested = true; } + + // Request that the current edge's referent's outgoing edges not be + // traversed. This must be called the first time that referent is reached. + // Other edges *to* that referent will still be traversed. + void abandonReferent() { abandonRequested = true; } + + // 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 + // |handler| can access it to see the traversal thus far. + using NodeMap = js::HashMap, js::SystemAllocPolicy>; + NodeMap visited; + + private: + // Our handler object. + Handler& handler; + + // A queue template. Appending and popping the front are constant time. + // Wasted space is never more than some recent actual population plus the + // current population. + template + class Queue { + js::Vector head, tail; + size_t frontIndex; + + public: + Queue() : head(), tail(), frontIndex(0) {} + bool empty() { return frontIndex >= head.length(); } + T& front() { + MOZ_ASSERT(!empty()); + return head[frontIndex]; + } + void popFront() { + MOZ_ASSERT(!empty()); + frontIndex++; + if (frontIndex >= head.length()) { + head.clearAndFree(); + head.swap(tail); + frontIndex = 0; + } + } + bool append(const T& elt) { + return frontIndex == 0 ? head.append(elt) : tail.append(elt); + } + }; - // A queue of nodes that we have reached, but whose outgoing edges we - // have not yet traversed. Nodes reachable in fewer edges are enqueued - // earlier. - Queue pending; + // A queue of nodes that we have reached, but whose outgoing edges we + // have not yet traversed. Nodes reachable in fewer edges are enqueued + // earlier. + Queue pending; - // True if our traverse function has been called. - bool traversalBegun; + // True if our traverse function has been called. + bool traversalBegun; - // True if we've been asked to stop the traversal. - bool stopRequested; + // True if we've been asked to stop the traversal. + bool stopRequested; - // True if we've been asked to abandon the current edge's referent. - bool abandonRequested; + // True if we've been asked to abandon the current edge's referent. + bool abandonRequested; }; -} // namespace ubi -} // namespace JS +} // namespace ubi +} // namespace JS -#endif // js_UbiNodeBreadthFirst_h +#endif // js_UbiNodeBreadthFirst_h 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 @@ -74,7 +74,6 @@ // visit them; build a JS object reporting the results; and destruct count // nodes. - namespace JS { namespace ubi { @@ -83,170 +82,166 @@ class CountBase; struct CountDeleter { - JS_PUBLIC_API(void) operator()(CountBase*); + JS_PUBLIC_API void operator()(CountBase*); }; using CountBasePtr = js::UniquePtr; // Abstract base class for CountType nodes. struct CountType { - explicit CountType() { } - virtual ~CountType() { } + explicit CountType() {} + virtual ~CountType() {} - // Destruct a count tree node that this type instance constructed. - virtual void destructCount(CountBase& count) = 0; + // Destruct a count tree node that this type instance constructed. + virtual void destructCount(CountBase& count) = 0; - // Return a fresh node for the count tree that categorizes nodes according - // to this type. Return a nullptr on OOM. - virtual CountBasePtr makeCount() = 0; - - // Trace |count| and all its children, for garbage collection. - virtual void traceCount(CountBase& count, JSTracer* trc) = 0; - - // Implement the 'count' method for counts returned by this CountType - // instance's 'newCount' method. - 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 MOZ_MUST_USE bool report(JSContext* cx, CountBase& count, - MutableHandleValue report) = 0; + // Return a fresh node for the count tree that categorizes nodes according + // to this type. Return a nullptr on OOM. + virtual CountBasePtr makeCount() = 0; + + // Trace |count| and all its children, for garbage collection. + virtual void traceCount(CountBase& count, JSTracer* trc) = 0; + + // Implement the 'count' method for counts returned by this CountType + // instance's 'newCount' method. + 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 MOZ_MUST_USE bool report(JSContext* cx, CountBase& count, + MutableHandleValue report) = 0; }; using CountTypePtr = js::UniquePtr; // An abstract base class for count tree nodes. class CountBase { - // In lieu of a vtable, each CountBase points to its type, which - // carries not only the implementations of the CountBase methods, but also - // additional parameters for the type's behavior, as specified in the - // breakdown argument passed to takeCensus. - CountType& type; - - protected: - ~CountBase() { } - - public: - explicit CountBase(CountType& type) - : type(type) - , total_(0) - , smallestNodeIdCounted_(SIZE_MAX) - { } - - // Categorize and count |node| as appropriate for this count's type. - MOZ_MUST_USE bool count(mozilla::MallocSizeOf mallocSizeOf, const Node& node) { - total_++; - - auto id = node.identifier(); - if (id < smallestNodeIdCounted_) { - smallestNodeIdCounted_ = id; - } + // In lieu of a vtable, each CountBase points to its type, which + // carries not only the implementations of the CountBase methods, but also + // additional parameters for the type's behavior, as specified in the + // breakdown argument passed to takeCensus. + CountType& type; + + protected: + ~CountBase() {} + + public: + explicit CountBase(CountType& type) + : type(type), total_(0), smallestNodeIdCounted_(SIZE_MAX) {} + + // Categorize and count |node| as appropriate for this count's type. + 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_; + 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. - MOZ_MUST_USE bool report(JSContext* cx, MutableHandleValue report) { - return type.report(cx, *this, report); - } + bool ret = type.count(*this, mallocSizeOf, node); - // Down-cast this CountBase to its true type, based on its 'type' member, - // and run its destructor. - void destruct() { return type.destructCount(*this); } - - // Trace this count for garbage collection. - 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_; + 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. + 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. + void destruct() { return type.destructCount(*this); } + + // Trace this count for garbage collection. + 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 { - CountBasePtr count; + CountBasePtr count; - void trace(JSTracer* trc) override { count->trace(trc); } + void trace(JSTracer* trc) override { count->trace(trc); } - public: - RootedCount(JSContext* cx, CountBasePtr&& count) - : CustomAutoRooter(cx), - count(Move(count)) - { } - CountBase* operator->() const { return count.get(); } - explicit operator bool() const { return count.get(); } - operator CountBasePtr&() { return count; } + public: + RootedCount(JSContext* cx, CountBasePtr&& count) + : CustomAutoRooter(cx), count(Move(count)) {} + CountBase* operator->() const { return count.get(); } + explicit operator bool() const { return count.get(); } + operator CountBasePtr&() { return count; } }; // Common data for a census traversal, shared across all CountType nodes. struct Census { - JSContext* const cx; - // If the targetZones set is non-empty, then only consider nodes whose zone - // is an element of the set. If the targetZones set is empty, then nodes in - // all zones are considered. - JS::ZoneSet targetZones; - Zone* atomsZone; + JSContext* const cx; + // If the targetZones set is non-empty, then only consider nodes whose zone + // is an element of the set. If the targetZones set is empty, then nodes in + // all zones are considered. + JS::ZoneSet targetZones; + Zone* atomsZone; - explicit Census(JSContext* cx) : cx(cx), atomsZone(nullptr) { } + explicit Census(JSContext* cx) : cx(cx), atomsZone(nullptr) {} - MOZ_MUST_USE JS_PUBLIC_API(bool) init(); + MOZ_MUST_USE JS_PUBLIC_API bool init(); }; // A BreadthFirst handler type that conducts a census, using a CountBase to // categorize and count each node. class CensusHandler { - Census& census; - CountBasePtr& rootCount; - mozilla::MallocSizeOf mallocSizeOf; - - public: - CensusHandler(Census& census, CountBasePtr& rootCount, mozilla::MallocSizeOf mallocSizeOf) - : census(census), - rootCount(rootCount), - mallocSizeOf(mallocSizeOf) - { } - - 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 { }; - - MOZ_MUST_USE JS_PUBLIC_API(bool) operator() (BreadthFirst& traversal, - Node origin, const Edge& edge, - NodeData* referentData, bool first); + Census& census; + CountBasePtr& rootCount; + mozilla::MallocSizeOf mallocSizeOf; + + public: + CensusHandler(Census& census, CountBasePtr& rootCount, + mozilla::MallocSizeOf mallocSizeOf) + : census(census), rootCount(rootCount), mallocSizeOf(mallocSizeOf) {} + + 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 {}; + + 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 (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); +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); - +JS_PUBLIC_API CountTypePtr ParseBreakdown(JSContext* cx, + HandleValue breakdownValue); -} // namespace ubi -} // namespace JS +} // namespace ubi +} // namespace JS -#endif // js_UbiNodeCensus_h +#endif // js_UbiNodeCensus_h 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 @@ -13,8 +13,7 @@ #include "mozilla/Move.h" #include "mozilla/UniquePtr.h" -#include "jsalloc.h" - +#include "js/AllocPolicy.h" #include "js/UbiNode.h" #include "js/UbiNodePostOrder.h" #include "js/Utility.h" @@ -67,611 +66,598 @@ * * [0]: http://www.cs.rice.edu/~keith/EMBED/dom.pdf */ -class JS_PUBLIC_API(DominatorTree) -{ - private: - // Types. - - using PredecessorSets = js::HashMap, - js::SystemAllocPolicy>; - using NodeToIndexMap = js::HashMap, - js::SystemAllocPolicy>; - class DominatedSets; - - public: - class DominatedSetRange; +class JS_PUBLIC_API DominatorTree { + private: + // Types. + + using PredecessorSets = js::HashMap, + js::SystemAllocPolicy>; + using NodeToIndexMap = js::HashMap, + js::SystemAllocPolicy>; + class DominatedSets; + + public: + class DominatedSetRange; + + /** + * A pointer to an immediately dominated node. + * + * Don't use this type directly; it is no safer than regular pointers. This + * is only for use indirectly with range-based for loops and + * `DominatedSetRange`. + * + * @see JS::ubi::DominatorTree::getDominatedSet + */ + class DominatedNodePtr { + friend class DominatedSetRange; + + const JS::ubi::Vector& postOrder; + const uint32_t* ptr; + + DominatedNodePtr(const JS::ubi::Vector& postOrder, + const uint32_t* ptr) + : postOrder(postOrder), ptr(ptr) {} + + public: + bool operator!=(const DominatedNodePtr& rhs) const { + return ptr != rhs.ptr; + } + void operator++() { ptr++; } + const Node& operator*() const { return postOrder[*ptr]; } + }; + + /** + * A range of immediately dominated `JS::ubi::Node`s for use with + * range-based for loops. + * + * @see JS::ubi::DominatorTree::getDominatedSet + */ + class DominatedSetRange { + friend class DominatedSets; + + const JS::ubi::Vector& postOrder; + const uint32_t* beginPtr; + const uint32_t* endPtr; + + DominatedSetRange(JS::ubi::Vector& postOrder, const uint32_t* begin, + const uint32_t* end) + : postOrder(postOrder), beginPtr(begin), endPtr(end) { + MOZ_ASSERT(begin <= end); + } + + public: + DominatedNodePtr begin() const { + MOZ_ASSERT(beginPtr <= endPtr); + return DominatedNodePtr(postOrder, beginPtr); + } + + DominatedNodePtr end() const { return DominatedNodePtr(postOrder, endPtr); } + + size_t length() const { + MOZ_ASSERT(beginPtr <= endPtr); + return endPtr - beginPtr; + } /** - * A pointer to an immediately dominated node. + * Safely skip ahead `n` dominators in the range, in O(1) time. * - * Don't use this type directly; it is no safer than regular pointers. This - * is only for use indirectly with range-based for loops and - * `DominatedSetRange`. + * Example usage: * - * @see JS::ubi::DominatorTree::getDominatedSet - */ - class DominatedNodePtr - { - friend class DominatedSetRange; - - const JS::ubi::Vector& postOrder; - const uint32_t* ptr; - - DominatedNodePtr(const JS::ubi::Vector& postOrder, const uint32_t* ptr) - : postOrder(postOrder) - , ptr(ptr) - { } - - public: - bool operator!=(const DominatedNodePtr& rhs) const { return ptr != rhs.ptr; } - void operator++() { ptr++; } - const Node& operator*() const { return postOrder[*ptr]; } - }; - - /** - * A range of immediately dominated `JS::ubi::Node`s for use with - * range-based for loops. + * mozilla::Maybe range = + * myDominatorTree.getDominatedSet(myNode); + * if (range.isNothing()) { + * // Handle unknown nodes however you see fit... + * return false; + * } * - * @see JS::ubi::DominatorTree::getDominatedSet + * // Don't care about the first ten, for whatever reason. + * range->skip(10); + * for (const JS::ubi::Node& dominatedNode : *range) { + * // ... + * } */ - class DominatedSetRange - { - friend class DominatedSets; - - const JS::ubi::Vector& postOrder; - const uint32_t* beginPtr; - const uint32_t* endPtr; - - DominatedSetRange(JS::ubi::Vector& postOrder, const uint32_t* begin, const uint32_t* end) - : postOrder(postOrder) - , beginPtr(begin) - , endPtr(end) - { - MOZ_ASSERT(begin <= end); - } - - public: - DominatedNodePtr begin() const { - MOZ_ASSERT(beginPtr <= endPtr); - return DominatedNodePtr(postOrder, beginPtr); - } - - DominatedNodePtr end() const { - return DominatedNodePtr(postOrder, endPtr); - } - - size_t length() const { - MOZ_ASSERT(beginPtr <= endPtr); - return endPtr - beginPtr; - } - - /** - * Safely skip ahead `n` dominators in the range, in O(1) time. - * - * Example usage: - * - * mozilla::Maybe range = myDominatorTree.getDominatedSet(myNode); - * if (range.isNothing()) { - * // Handle unknown nodes however you see fit... - * return false; - * } - * - * // Don't care about the first ten, for whatever reason. - * range->skip(10); - * for (const JS::ubi::Node& dominatedNode : *range) { - * // ... - * } - */ - void skip(size_t n) { - beginPtr += n; - if (beginPtr > endPtr) - beginPtr = endPtr; - } - }; + void skip(size_t n) { + beginPtr += n; + if (beginPtr > endPtr) beginPtr = endPtr; + } + }; + + private: + /** + * The set of all dominated sets in a dominator tree. + * + * Internally stores the sets in a contiguous array, with a side table of + * indices into that contiguous array to denote the start index of each + * individual set. + */ + class DominatedSets { + JS::ubi::Vector dominated; + JS::ubi::Vector indices; + + DominatedSets(JS::ubi::Vector&& dominated, + JS::ubi::Vector&& indices) + : dominated(mozilla::Move(dominated)), + indices(mozilla::Move(indices)) {} + + public: + // DominatedSets is not copy-able. + DominatedSets(const DominatedSets& rhs) = delete; + DominatedSets& operator=(const DominatedSets& rhs) = delete; + + // DominatedSets is move-able. + DominatedSets(DominatedSets&& rhs) + : dominated(mozilla::Move(rhs.dominated)), + indices(mozilla::Move(rhs.indices)) { + MOZ_ASSERT(this != &rhs, "self-move not allowed"); + } + DominatedSets& operator=(DominatedSets&& rhs) { + this->~DominatedSets(); + new (this) DominatedSets(mozilla::Move(rhs)); + return *this; + } - private: /** - * The set of all dominated sets in a dominator tree. - * - * Internally stores the sets in a contiguous array, with a side table of - * indices into that contiguous array to denote the start index of each - * individual set. + * Create the DominatedSets given the mapping of a node index to its + * immediate dominator. Returns `Some` on success, `Nothing` on OOM + * failure. */ - class DominatedSets - { - JS::ubi::Vector dominated; - JS::ubi::Vector indices; - - DominatedSets(JS::ubi::Vector&& dominated, JS::ubi::Vector&& indices) - : dominated(mozilla::Move(dominated)) - , indices(mozilla::Move(indices)) - { } - - public: - // DominatedSets is not copy-able. - DominatedSets(const DominatedSets& rhs) = delete; - DominatedSets& operator=(const DominatedSets& rhs) = delete; - - // DominatedSets is move-able. - DominatedSets(DominatedSets&& rhs) - : dominated(mozilla::Move(rhs.dominated)) - , indices(mozilla::Move(rhs.indices)) - { - MOZ_ASSERT(this != &rhs, "self-move not allowed"); - } - DominatedSets& operator=(DominatedSets&& rhs) { - this->~DominatedSets(); - new (this) DominatedSets(mozilla::Move(rhs)); - return *this; - } - - /** - * Create the DominatedSets given the mapping of a node index to its - * immediate dominator. Returns `Some` on success, `Nothing` on OOM - * failure. - */ - static mozilla::Maybe Create(const JS::ubi::Vector& doms) { - auto length = doms.length(); - MOZ_ASSERT(length < UINT32_MAX); - - // Create a vector `dominated` holding a flattened set of buckets of - // immediately dominated children nodes, with a lookup table - // `indices` mapping from each node to the beginning of its bucket. - // - // This has three phases: - // - // 1. Iterate over the full set of nodes and count up the size of - // each bucket. These bucket sizes are temporarily stored in the - // `indices` vector. - // - // 2. Convert the `indices` vector to store the cumulative sum of - // the sizes of all buckets before each index, resulting in a - // mapping from node index to one past the end of that node's - // bucket. - // - // 3. Iterate over the full set of nodes again, filling in bucket - // entries from the end of the bucket's range to its - // beginning. This decrements each index as a bucket entry is - // filled in. After having filled in all of a bucket's entries, - // the index points to the start of the bucket. - - JS::ubi::Vector dominated; - JS::ubi::Vector indices; - if (!dominated.growBy(length) || !indices.growBy(length)) - return mozilla::Nothing(); - - // 1 - memset(indices.begin(), 0, length * sizeof(uint32_t)); - for (uint32_t i = 0; i < length; i++) - indices[doms[i]]++; - - // 2 - uint32_t sumOfSizes = 0; - for (uint32_t i = 0; i < length; i++) { - sumOfSizes += indices[i]; - MOZ_ASSERT(sumOfSizes <= length); - indices[i] = sumOfSizes; - } - - // 3 - for (uint32_t i = 0; i < length; i++) { - auto idxOfDom = doms[i]; - indices[idxOfDom]--; - dominated[indices[idxOfDom]] = i; - } + static mozilla::Maybe Create( + const JS::ubi::Vector& doms) { + auto length = doms.length(); + MOZ_ASSERT(length < UINT32_MAX); + + // Create a vector `dominated` holding a flattened set of buckets of + // immediately dominated children nodes, with a lookup table + // `indices` mapping from each node to the beginning of its bucket. + // + // This has three phases: + // + // 1. Iterate over the full set of nodes and count up the size of + // each bucket. These bucket sizes are temporarily stored in the + // `indices` vector. + // + // 2. Convert the `indices` vector to store the cumulative sum of + // the sizes of all buckets before each index, resulting in a + // mapping from node index to one past the end of that node's + // bucket. + // + // 3. Iterate over the full set of nodes again, filling in bucket + // entries from the end of the bucket's range to its + // beginning. This decrements each index as a bucket entry is + // filled in. After having filled in all of a bucket's entries, + // the index points to the start of the bucket. + + JS::ubi::Vector dominated; + JS::ubi::Vector indices; + if (!dominated.growBy(length) || !indices.growBy(length)) + return mozilla::Nothing(); + + // 1 + memset(indices.begin(), 0, length * sizeof(uint32_t)); + for (uint32_t i = 0; i < length; i++) indices[doms[i]]++; + + // 2 + uint32_t sumOfSizes = 0; + for (uint32_t i = 0; i < length; i++) { + sumOfSizes += indices[i]; + MOZ_ASSERT(sumOfSizes <= length); + indices[i] = sumOfSizes; + } + + // 3 + for (uint32_t i = 0; i < length; i++) { + auto idxOfDom = doms[i]; + indices[idxOfDom]--; + dominated[indices[idxOfDom]] = i; + } #ifdef DEBUG - // Assert that our buckets are non-overlapping and don't run off the - // end of the vector. - uint32_t lastIndex = 0; - for (uint32_t i = 0; i < length; i++) { - MOZ_ASSERT(indices[i] >= lastIndex); - MOZ_ASSERT(indices[i] < length); - lastIndex = indices[i]; - } + // Assert that our buckets are non-overlapping and don't run off the + // end of the vector. + uint32_t lastIndex = 0; + for (uint32_t i = 0; i < length; i++) { + MOZ_ASSERT(indices[i] >= lastIndex); + MOZ_ASSERT(indices[i] < length); + lastIndex = indices[i]; + } #endif - return mozilla::Some(DominatedSets(mozilla::Move(dominated), mozilla::Move(indices))); - } - - /** - * Get the set of nodes immediately dominated by the node at - * `postOrder[nodeIndex]`. - */ - 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 - ? dominated.end() - : &dominated[indices[nodeIndex + 1]]; - return DominatedSetRange(postOrder, &dominated[indices[nodeIndex]], end); - } - }; - - private: - // Data members. - JS::ubi::Vector postOrder; - NodeToIndexMap nodeToPostOrderIndex; - JS::ubi::Vector doms; - DominatedSets dominatedSets; - mozilla::Maybe> retainedSizes; - - private: - // We use `UNDEFINED` as a sentinel value in the `doms` vector to signal - // that we haven't found any dominators for the node at the corresponding - // index in `postOrder` yet. - static const uint32_t UNDEFINED = UINT32_MAX; - - 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)) - , dominatedSets(mozilla::Move(dominatedSets)) - , retainedSizes(mozilla::Nothing()) - { } - - static uint32_t intersect(JS::ubi::Vector& doms, uint32_t finger1, uint32_t finger2) { - while (finger1 != finger2) { - if (finger1 < finger2) - finger1 = doms[finger1]; - else if (finger2 < finger1) - finger2 = doms[finger2]; - } - return finger1; - } - - // Do the post order traversal of the heap graph and populate our - // predecessor sets. - 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++; - if (MOZ_UNLIKELY(nodeCount == UINT32_MAX)) - return false; - return postOrder.append(node); - }; - - auto onEdge = [&](const Node& origin, const Edge& edge) { - auto p = predecessorSets.lookupForAdd(edge.referent); - if (!p) { - mozilla::UniquePtr> set(js_new()); - if (!set || - !set->init() || - !predecessorSets.add(p, edge.referent, mozilla::Move(set))) - { - return false; - } - } - MOZ_ASSERT(p && p->value()); - return p->value()->put(origin); - }; - - PostOrder traversal(cx, noGC); - return traversal.init() && - traversal.addStart(root) && - traversal.traverse(onNode, onEdge); - } - - // Populates the given `map` with an entry for each node to its index in - // `postOrder`. - 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(); - if (!map.init(length)) - return false; - for (uint32_t i = 0; i < length; i++) - map.putNewInfallible(postOrder[i], i); - return true; - } - - // Convert the Node -> NodeSet predecessorSets to a index -> Vector - // form. - static MOZ_MUST_USE bool convertPredecessorSetsToVectors( - const Node& root, - JS::ubi::Vector& postOrder, - PredecessorSets& predecessorSets, - NodeToIndexMap& nodeToPostOrderIndex, - JS::ubi::Vector>& predecessorVectors) - { - MOZ_ASSERT(postOrder.length() < UINT32_MAX); - uint32_t length = postOrder.length(); - - MOZ_ASSERT(predecessorVectors.length() == 0); - if (!predecessorVectors.growBy(length)) - return false; - - for (uint32_t i = 0; i < length - 1; i++) { - auto& node = postOrder[i]; - MOZ_ASSERT(node != root, - "Only the last node should be root, since this was a post order traversal."); - - auto ptr = predecessorSets.lookup(node); - MOZ_ASSERT(ptr, - "Because this isn't the root, it had better have predecessors, or else how " - "did we even find it."); - - auto& predecessors = ptr->value(); - if (!predecessorVectors[i].reserve(predecessors->count())) - return false; - for (auto range = predecessors->all(); !range.empty(); range.popFront()) { - auto ptr = nodeToPostOrderIndex.lookup(range.front()); - MOZ_ASSERT(ptr); - predecessorVectors[i].infallibleAppend(ptr->value()); - } - } - predecessorSets.finish(); - return true; - } - - // Initialize `doms` such that the immediate dominator of the `root` is the - // `root` itself and all others are `UNDEFINED`. - static MOZ_MUST_USE bool initializeDominators(JS::ubi::Vector& doms, - uint32_t length) { - MOZ_ASSERT(doms.length() == 0); - if (!doms.growByUninitialized(length)) - return false; - doms[length - 1] = length - 1; - for (uint32_t i = 0; i < length - 1; i++) - doms[i] = UNDEFINED; - return true; - } - - void assertSanity() const { - MOZ_ASSERT(postOrder.length() == doms.length()); - MOZ_ASSERT(postOrder.length() == nodeToPostOrderIndex.count()); - MOZ_ASSERT_IF(retainedSizes.isSome(), postOrder.length() == retainedSizes->length()); - } - - MOZ_MUST_USE bool computeRetainedSizes(mozilla::MallocSizeOf mallocSizeOf) { - MOZ_ASSERT(retainedSizes.isNothing()); - auto length = postOrder.length(); - - retainedSizes.emplace(); - if (!retainedSizes->growBy(length)) { - retainedSizes = mozilla::Nothing(); - return false; - } - - // Iterate in forward order so that we know all of a node's children in - // the dominator tree have already had their retained size - // computed. Then we can simply say that the retained size of a node is - // its shallow size (JS::ubi::Node::size) plus the retained sizes of its - // immediate children in the tree. - - for (uint32_t i = 0; i < length; i++) { - auto size = postOrder[i].size(mallocSizeOf); - - for (const auto& dominated : dominatedSets.dominatedSet(postOrder, i)) { - // The root node dominates itself, but shouldn't contribute to - // its own retained size. - if (dominated == postOrder[length - 1]) { - MOZ_ASSERT(i == length - 1); - continue; - } - - auto ptr = nodeToPostOrderIndex.lookup(dominated); - MOZ_ASSERT(ptr); - auto idxOfDominated = ptr->value(); - MOZ_ASSERT(idxOfDominated < i); - size += retainedSizes.ref()[idxOfDominated]; - } - - retainedSizes.ref()[i] = size; - } - - return true; - } - - public: - // DominatorTree is not copy-able. - DominatorTree(const DominatorTree&) = delete; - DominatorTree& operator=(const DominatorTree&) = delete; - - // DominatorTree is move-able. - DominatorTree(DominatorTree&& rhs) - : postOrder(mozilla::Move(rhs.postOrder)) - , nodeToPostOrderIndex(mozilla::Move(rhs.nodeToPostOrderIndex)) - , doms(mozilla::Move(rhs.doms)) - , dominatedSets(mozilla::Move(rhs.dominatedSets)) - , retainedSizes(mozilla::Move(rhs.retainedSizes)) - { - MOZ_ASSERT(this != &rhs, "self-move is not allowed"); - } - DominatorTree& operator=(DominatorTree&& rhs) { - this->~DominatorTree(); - new (this) DominatorTree(mozilla::Move(rhs)); - return *this; + return mozilla::Some( + DominatedSets(mozilla::Move(dominated), mozilla::Move(indices))); } /** - * Construct a `DominatorTree` of the heap graph visible from `root`. The - * `root` is also used as the root of the resulting dominator tree. - * - * The resulting `DominatorTree` 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 `DominatorTree`'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 `DominatorTree`'s lifetime is - * bounded by that offline structure's lifetime. - * - * In practice, this means that within SpiderMonkey we must treat - * `DominatorTree` as if it were backed by the live heap graph and trust - * that embedders with knowledge of the graph's implementation will do the - * Right Thing. - * - * Returns `mozilla::Nothing()` on OOM failure. It is the caller's - * responsibility to handle and report the OOM. + * Get the set of nodes immediately dominated by the node at + * `postOrder[nodeIndex]`. */ - static mozilla::Maybe - Create(JSContext* cx, AutoCheckCannotGC& noGC, const Node& root) { - JS::ubi::Vector postOrder; - PredecessorSets predecessorSets; - if (!predecessorSets.init() || !doTraversal(cx, noGC, root, postOrder, predecessorSets)) - return mozilla::Nothing(); - - MOZ_ASSERT(postOrder.length() < UINT32_MAX); - uint32_t length = postOrder.length(); - MOZ_ASSERT(postOrder[length - 1] == root); - - // From here on out we wish to avoid hash table lookups, and we use - // indices into `postOrder` instead of actual nodes wherever - // possible. This greatly improves the performance of this - // implementation, but we have to pay a little bit of upfront cost to - // convert our data structures to play along first. - - NodeToIndexMap nodeToPostOrderIndex; - if (!mapNodesToTheirIndices(postOrder, nodeToPostOrderIndex)) - return mozilla::Nothing(); - - JS::ubi::Vector> predecessorVectors; - if (!convertPredecessorSetsToVectors(root, postOrder, predecessorSets, nodeToPostOrderIndex, - predecessorVectors)) - return mozilla::Nothing(); - - JS::ubi::Vector doms; - if (!initializeDominators(doms, length)) - return mozilla::Nothing(); - - bool changed = true; - while (changed) { - changed = false; - - // Iterate over the non-root nodes in reverse post order. - for (uint32_t indexPlusOne = length - 1; indexPlusOne > 0; indexPlusOne--) { - MOZ_ASSERT(postOrder[indexPlusOne - 1] != root); - - // Take the intersection of every predecessor's dominator set; - // that is the current best guess at the immediate dominator for - // this node. - - uint32_t newIDomIdx = UNDEFINED; - - auto& predecessors = predecessorVectors[indexPlusOne - 1]; - auto range = predecessors.all(); - for ( ; !range.empty(); range.popFront()) { - auto idx = range.front(); - if (doms[idx] != UNDEFINED) { - newIDomIdx = idx; - break; - } - } - - MOZ_ASSERT(newIDomIdx != UNDEFINED, - "Because the root is initialized to dominate itself and is the first " - "node in every path, there must exist a predecessor to this node that " - "also has a dominator."); - - for ( ; !range.empty(); range.popFront()) { - auto idx = range.front(); - if (doms[idx] != UNDEFINED) - newIDomIdx = intersect(doms, newIDomIdx, idx); - } - - // If the immediate dominator changed, we will have to do - // another pass of the outer while loop to continue the forward - // dataflow. - if (newIDomIdx != doms[indexPlusOne - 1]) { - doms[indexPlusOne - 1] = newIDomIdx; - changed = true; - } - } - } - - auto maybeDominatedSets = DominatedSets::Create(doms); - if (maybeDominatedSets.isNothing()) - return mozilla::Nothing(); - - return mozilla::Some(DominatorTree(mozilla::Move(postOrder), - mozilla::Move(nodeToPostOrderIndex), - mozilla::Move(doms), - mozilla::Move(*maybeDominatedSets))); - } + 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 + ? dominated.end() + : &dominated[indices[nodeIndex + 1]]; + return DominatedSetRange(postOrder, &dominated[indices[nodeIndex]], end); + } + }; + + private: + // Data members. + JS::ubi::Vector postOrder; + NodeToIndexMap nodeToPostOrderIndex; + JS::ubi::Vector doms; + DominatedSets dominatedSets; + mozilla::Maybe> retainedSizes; + + private: + // We use `UNDEFINED` as a sentinel value in the `doms` vector to signal + // that we haven't found any dominators for the node at the corresponding + // index in `postOrder` yet. + static const uint32_t UNDEFINED = UINT32_MAX; + + 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)), + dominatedSets(mozilla::Move(dominatedSets)), + retainedSizes(mozilla::Nothing()) {} + + static uint32_t intersect(JS::ubi::Vector& doms, uint32_t finger1, + uint32_t finger2) { + while (finger1 != finger2) { + if (finger1 < finger2) + finger1 = doms[finger1]; + else if (finger2 < finger1) + finger2 = doms[finger2]; + } + return finger1; + } + + // Do the post order traversal of the heap graph and populate our + // predecessor sets. + 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++; + if (MOZ_UNLIKELY(nodeCount == UINT32_MAX)) return false; + return postOrder.append(node); + }; - /** - * Get the root node for this dominator tree. - */ - const Node& root() const { - return postOrder[postOrder.length() - 1]; - } + auto onEdge = [&](const Node& origin, const Edge& edge) { + auto p = predecessorSets.lookupForAdd(edge.referent); + if (!p) { + mozilla::UniquePtr> set( + js_new()); + if (!set || !set->init() || + !predecessorSets.add(p, edge.referent, mozilla::Move(set))) { + return false; + } + } + MOZ_ASSERT(p && p->value()); + return p->value()->put(origin); + }; - /** - * Return the immediate dominator of the given `node`. If `node` was not - * reachable from the `root` that this dominator tree was constructed from, - * then return the null `JS::ubi::Node`. - */ - Node getImmediateDominator(const Node& node) const { - assertSanity(); - auto ptr = nodeToPostOrderIndex.lookup(node); - if (!ptr) - return Node(); - - auto idx = ptr->value(); - MOZ_ASSERT(idx < postOrder.length()); - return postOrder[doms[idx]]; - } + PostOrder traversal(cx, noGC); + return traversal.init() && traversal.addStart(root) && + traversal.traverse(onNode, onEdge); + } + + // Populates the given `map` with an entry for each node to its index in + // `postOrder`. + 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(); + if (!map.init(length)) return false; + for (uint32_t i = 0; i < length; i++) map.putNewInfallible(postOrder[i], i); + return true; + } + + // Convert the Node -> NodeSet predecessorSets to a index -> Vector + // form. + static MOZ_MUST_USE bool convertPredecessorSetsToVectors( + const Node& root, JS::ubi::Vector& postOrder, + PredecessorSets& predecessorSets, NodeToIndexMap& nodeToPostOrderIndex, + JS::ubi::Vector>& predecessorVectors) { + MOZ_ASSERT(postOrder.length() < UINT32_MAX); + uint32_t length = postOrder.length(); + + MOZ_ASSERT(predecessorVectors.length() == 0); + if (!predecessorVectors.growBy(length)) return false; + + for (uint32_t i = 0; i < length - 1; i++) { + auto& node = postOrder[i]; + MOZ_ASSERT(node != root, + "Only the last node should be root, since this was a post " + "order traversal."); + + auto ptr = predecessorSets.lookup(node); + MOZ_ASSERT(ptr, + "Because this isn't the root, it had better have " + "predecessors, or else how " + "did we even find it."); + + auto& predecessors = ptr->value(); + if (!predecessorVectors[i].reserve(predecessors->count())) return false; + for (auto range = predecessors->all(); !range.empty(); range.popFront()) { + auto ptr = nodeToPostOrderIndex.lookup(range.front()); + MOZ_ASSERT(ptr); + predecessorVectors[i].infallibleAppend(ptr->value()); + } + } + predecessorSets.finish(); + return true; + } + + // Initialize `doms` such that the immediate dominator of the `root` is the + // `root` itself and all others are `UNDEFINED`. + static MOZ_MUST_USE bool initializeDominators(JS::ubi::Vector& doms, + uint32_t length) { + MOZ_ASSERT(doms.length() == 0); + if (!doms.growByUninitialized(length)) return false; + doms[length - 1] = length - 1; + for (uint32_t i = 0; i < length - 1; i++) doms[i] = UNDEFINED; + return true; + } + + void assertSanity() const { + MOZ_ASSERT(postOrder.length() == doms.length()); + MOZ_ASSERT(postOrder.length() == nodeToPostOrderIndex.count()); + MOZ_ASSERT_IF(retainedSizes.isSome(), + postOrder.length() == retainedSizes->length()); + } + + MOZ_MUST_USE bool computeRetainedSizes(mozilla::MallocSizeOf mallocSizeOf) { + MOZ_ASSERT(retainedSizes.isNothing()); + auto length = postOrder.length(); + + retainedSizes.emplace(); + if (!retainedSizes->growBy(length)) { + retainedSizes = mozilla::Nothing(); + return false; + } + + // Iterate in forward order so that we know all of a node's children in + // the dominator tree have already had their retained size + // computed. Then we can simply say that the retained size of a node is + // its shallow size (JS::ubi::Node::size) plus the retained sizes of its + // immediate children in the tree. + + for (uint32_t i = 0; i < length; i++) { + auto size = postOrder[i].size(mallocSizeOf); + + for (const auto& dominated : dominatedSets.dominatedSet(postOrder, i)) { + // The root node dominates itself, but shouldn't contribute to + // its own retained size. + if (dominated == postOrder[length - 1]) { + MOZ_ASSERT(i == length - 1); + continue; + } + + auto ptr = nodeToPostOrderIndex.lookup(dominated); + MOZ_ASSERT(ptr); + auto idxOfDominated = ptr->value(); + MOZ_ASSERT(idxOfDominated < i); + size += retainedSizes.ref()[idxOfDominated]; + } + + retainedSizes.ref()[i] = size; + } + + return true; + } + + public: + // DominatorTree is not copy-able. + DominatorTree(const DominatorTree&) = delete; + DominatorTree& operator=(const DominatorTree&) = delete; + + // DominatorTree is move-able. + DominatorTree(DominatorTree&& rhs) + : postOrder(mozilla::Move(rhs.postOrder)), + nodeToPostOrderIndex(mozilla::Move(rhs.nodeToPostOrderIndex)), + doms(mozilla::Move(rhs.doms)), + dominatedSets(mozilla::Move(rhs.dominatedSets)), + retainedSizes(mozilla::Move(rhs.retainedSizes)) { + MOZ_ASSERT(this != &rhs, "self-move is not allowed"); + } + DominatorTree& operator=(DominatorTree&& rhs) { + this->~DominatorTree(); + new (this) DominatorTree(mozilla::Move(rhs)); + return *this; + } + + /** + * Construct a `DominatorTree` of the heap graph visible from `root`. The + * `root` is also used as the root of the resulting dominator tree. + * + * The resulting `DominatorTree` 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 `DominatorTree`'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 `DominatorTree`'s lifetime is + * bounded by that offline structure's lifetime. + * + * In practice, this means that within SpiderMonkey we must treat + * `DominatorTree` as if it were backed by the live heap graph and trust + * that embedders with knowledge of the graph's implementation will do the + * Right Thing. + * + * 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, + const Node& root) { + JS::ubi::Vector postOrder; + PredecessorSets predecessorSets; + if (!predecessorSets.init() || + !doTraversal(cx, noGC, root, postOrder, predecessorSets)) + return mozilla::Nothing(); + + MOZ_ASSERT(postOrder.length() < UINT32_MAX); + uint32_t length = postOrder.length(); + MOZ_ASSERT(postOrder[length - 1] == root); + + // From here on out we wish to avoid hash table lookups, and we use + // indices into `postOrder` instead of actual nodes wherever + // possible. This greatly improves the performance of this + // implementation, but we have to pay a little bit of upfront cost to + // convert our data structures to play along first. - /** - * Get the set of nodes immediately dominated by the given `node`. If `node` - * is not a member of this dominator tree, return `Nothing`. - * - * Example usage: - * - * mozilla::Maybe range = myDominatorTree.getDominatedSet(myNode); - * if (range.isNothing()) { - * // Handle unknown node however you see fit... - * return false; - * } - * - * for (const JS::ubi::Node& dominatedNode : *range) { - * // Do something with each immediately dominated node... - * } - */ - mozilla::Maybe getDominatedSet(const Node& node) { - assertSanity(); - auto ptr = nodeToPostOrderIndex.lookup(node); - if (!ptr) - return mozilla::Nothing(); - - auto idx = ptr->value(); - MOZ_ASSERT(idx < postOrder.length()); - return mozilla::Some(dominatedSets.dominatedSet(postOrder, idx)); - } + NodeToIndexMap nodeToPostOrderIndex; + if (!mapNodesToTheirIndices(postOrder, nodeToPostOrderIndex)) + return mozilla::Nothing(); - /** - * Get the retained size of the given `node`. The size is placed in - * `outSize`, or 0 if `node` is not a member of the dominator tree. Returns - * false on OOM failure, leaving `outSize` unchanged. - */ - MOZ_MUST_USE bool getRetainedSize(const Node& node, mozilla::MallocSizeOf mallocSizeOf, - Node::Size& outSize) { - assertSanity(); - auto ptr = nodeToPostOrderIndex.lookup(node); - if (!ptr) { - outSize = 0; - return true; - } + JS::ubi::Vector> predecessorVectors; + if (!convertPredecessorSetsToVectors(root, postOrder, predecessorSets, + nodeToPostOrderIndex, + predecessorVectors)) + return mozilla::Nothing(); - if (retainedSizes.isNothing() && !computeRetainedSizes(mallocSizeOf)) - return false; + JS::ubi::Vector doms; + if (!initializeDominators(doms, length)) return mozilla::Nothing(); - auto idx = ptr->value(); - MOZ_ASSERT(idx < postOrder.length()); - outSize = retainedSizes.ref()[idx]; - return true; - } + bool changed = true; + while (changed) { + changed = false; + + // Iterate over the non-root nodes in reverse post order. + for (uint32_t indexPlusOne = length - 1; indexPlusOne > 0; + indexPlusOne--) { + MOZ_ASSERT(postOrder[indexPlusOne - 1] != root); + + // Take the intersection of every predecessor's dominator set; + // that is the current best guess at the immediate dominator for + // this node. + + uint32_t newIDomIdx = UNDEFINED; + + auto& predecessors = predecessorVectors[indexPlusOne - 1]; + auto range = predecessors.all(); + for (; !range.empty(); range.popFront()) { + auto idx = range.front(); + if (doms[idx] != UNDEFINED) { + newIDomIdx = idx; + break; + } + } + + MOZ_ASSERT(newIDomIdx != UNDEFINED, + "Because the root is initialized to dominate itself and is " + "the first " + "node in every path, there must exist a predecessor to this " + "node that " + "also has a dominator."); + + for (; !range.empty(); range.popFront()) { + auto idx = range.front(); + if (doms[idx] != UNDEFINED) + newIDomIdx = intersect(doms, newIDomIdx, idx); + } + + // If the immediate dominator changed, we will have to do + // another pass of the outer while loop to continue the forward + // dataflow. + if (newIDomIdx != doms[indexPlusOne - 1]) { + doms[indexPlusOne - 1] = newIDomIdx; + changed = true; + } + } + } + + auto maybeDominatedSets = DominatedSets::Create(doms); + if (maybeDominatedSets.isNothing()) return mozilla::Nothing(); + + return mozilla::Some(DominatorTree( + mozilla::Move(postOrder), mozilla::Move(nodeToPostOrderIndex), + mozilla::Move(doms), mozilla::Move(*maybeDominatedSets))); + } + + /** + * Get the root node for this dominator tree. + */ + const Node& root() const { return postOrder[postOrder.length() - 1]; } + + /** + * Return the immediate dominator of the given `node`. If `node` was not + * reachable from the `root` that this dominator tree was constructed from, + * then return the null `JS::ubi::Node`. + */ + Node getImmediateDominator(const Node& node) const { + assertSanity(); + auto ptr = nodeToPostOrderIndex.lookup(node); + if (!ptr) return Node(); + + auto idx = ptr->value(); + MOZ_ASSERT(idx < postOrder.length()); + return postOrder[doms[idx]]; + } + + /** + * Get the set of nodes immediately dominated by the given `node`. If `node` + * is not a member of this dominator tree, return `Nothing`. + * + * Example usage: + * + * mozilla::Maybe range = + * myDominatorTree.getDominatedSet(myNode); + * if (range.isNothing()) { + * // Handle unknown node however you see fit... + * return false; + * } + * + * for (const JS::ubi::Node& dominatedNode : *range) { + * // Do something with each immediately dominated node... + * } + */ + mozilla::Maybe getDominatedSet(const Node& node) { + assertSanity(); + auto ptr = nodeToPostOrderIndex.lookup(node); + if (!ptr) return mozilla::Nothing(); + + auto idx = ptr->value(); + MOZ_ASSERT(idx < postOrder.length()); + return mozilla::Some(dominatedSets.dominatedSet(postOrder, idx)); + } + + /** + * Get the retained size of the given `node`. The size is placed in + * `outSize`, or 0 if `node` is not a member of the dominator tree. Returns + * false on OOM failure, leaving `outSize` unchanged. + */ + MOZ_MUST_USE bool getRetainedSize(const Node& node, + mozilla::MallocSizeOf mallocSizeOf, + Node::Size& outSize) { + assertSanity(); + auto ptr = nodeToPostOrderIndex.lookup(node); + if (!ptr) { + outSize = 0; + return true; + } + + if (retainedSizes.isNothing() && !computeRetainedSizes(mallocSizeOf)) + return false; + + auto idx = ptr->value(); + MOZ_ASSERT(idx < postOrder.length()); + outSize = retainedSizes.ref()[idx]; + return true; + } }; -} // namespace ubi -} // namespace JS +} // namespace ubi +} // namespace JS -#endif // js_UbiNodeDominatorTree_h +#endif // js_UbiNodeDominatorTree_h 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 @@ -11,8 +11,7 @@ #include "mozilla/Maybe.h" #include "mozilla/Move.h" -#include "jsalloc.h" - +#include "js/AllocPolicy.h" #include "js/UbiNode.h" #include "js/Utility.h" #include "js/Vector.h" @@ -53,139 +52,129 @@ * causes `PostOrder::traverse` to return false. */ struct PostOrder { - private: - struct OriginAndEdges { - Node origin; - EdgeVector edges; - - OriginAndEdges(const Node& node, EdgeVector&& edges) - : origin(node) - , edges(mozilla::Move(edges)) - { } - - OriginAndEdges(const OriginAndEdges& rhs) = delete; - OriginAndEdges& operator=(const OriginAndEdges& rhs) = delete; - - OriginAndEdges(OriginAndEdges&& rhs) - : origin(rhs.origin) - , edges(mozilla::Move(rhs.edges)) - { - MOZ_ASSERT(&rhs != this, "self-move disallowed"); - } - - OriginAndEdges& operator=(OriginAndEdges&& rhs) { - this->~OriginAndEdges(); - new (this) OriginAndEdges(mozilla::Move(rhs)); - return *this; - } - }; - - using Stack = js::Vector; - using Set = js::HashSet, js::SystemAllocPolicy>; - - JSContext* cx; - Set seen; - Stack stack; -#ifdef DEBUG - bool traversed; -#endif - - private: - 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()))) - return false; - } - return true; + private: + struct OriginAndEdges { + Node origin; + EdgeVector edges; + + OriginAndEdges(const Node& node, EdgeVector&& edges) + : origin(node), edges(mozilla::Move(edges)) {} + + OriginAndEdges(const OriginAndEdges& rhs) = delete; + OriginAndEdges& operator=(const OriginAndEdges& rhs) = delete; + + OriginAndEdges(OriginAndEdges&& rhs) + : origin(rhs.origin), edges(mozilla::Move(rhs.edges)) { + MOZ_ASSERT(&rhs != this, "self-move disallowed"); } - MOZ_MUST_USE bool pushForTraversing(const Node& node) { - EdgeVector edges; - auto range = node.edges(cx, /* wantNames */ false); - return range && - fillEdgesFromRange(edges, range) && - stack.append(OriginAndEdges(node, mozilla::Move(edges))); + OriginAndEdges& operator=(OriginAndEdges&& rhs) { + this->~OriginAndEdges(); + new (this) OriginAndEdges(mozilla::Move(rhs)); + return *this; } + }; + using Stack = js::Vector; + using Set = js::HashSet, js::SystemAllocPolicy>; - public: - // Construct a post-order traversal object. - // - // 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(JSContext* cx, AutoCheckCannotGC&) - : cx(cx) - , seen() - , stack() + JSContext* cx; + Set seen; + Stack stack; #ifdef DEBUG - , traversed(false) + bool traversed; #endif - { } - - // Initialize this traversal object. Return false on OOM. - 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. - MOZ_MUST_USE bool addStart(const Node& node) { - if (!seen.put(node)) - return false; - return pushForTraversing(node); + private: + 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()))) return false; } + return true; + } - // Traverse the graph in post-order, starting with the set of nodes passed - // to `addStart` and applying `onNode::operator()` for each node in the - // graph and `onEdge::operator()` for each edge in the graph, as described - // above. - // - // This should be called only once per instance of this class. - // - // Return false on OOM or error return from `onNode::operator()` or - // `onEdge::operator()`. - template - MOZ_MUST_USE bool traverse(NodeVisitor onNode, EdgeVisitor onEdge) { + MOZ_MUST_USE bool pushForTraversing(const Node& node) { + EdgeVector edges; + auto range = node.edges(cx, /* wantNames */ false); + return range && fillEdgesFromRange(edges, range) && + stack.append(OriginAndEdges(node, mozilla::Move(edges))); + } + + public: + // Construct a post-order traversal object. + // + // 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(JSContext* cx, AutoCheckCannotGC&) + : cx(cx), + seen(), + stack() #ifdef DEBUG - MOZ_ASSERT(!traversed, "Can only traverse() once!"); - traversed = true; + , + traversed(false) #endif + { + } - while (!stack.empty()) { - auto& origin = stack.back().origin; - auto& edges = stack.back().edges; - - if (edges.empty()) { - if (!onNode(origin)) - return false; - stack.popBack(); - continue; - } - - Edge edge = mozilla::Move(edges.back()); - edges.popBack(); - - if (!onEdge(origin, edge)) - return false; - - auto ptr = seen.lookupForAdd(edge.referent); - // We've already seen this node, don't follow its edges. - if (ptr) - continue; - - // Mark the referent as seen and follow its edges. - if (!seen.add(ptr, edge.referent) || - !pushForTraversing(edge.referent)) - { - return false; - } - } + // Initialize this traversal object. Return false on OOM. + MOZ_MUST_USE bool init() { return seen.init(); } - return true; + // Add `node` as a starting point for the traversal. You may add + // as many starting points as you like. Returns false on OOM. + MOZ_MUST_USE bool addStart(const Node& node) { + if (!seen.put(node)) return false; + return pushForTraversing(node); + } + + // Traverse the graph in post-order, starting with the set of nodes passed + // to `addStart` and applying `onNode::operator()` for each node in the + // graph and `onEdge::operator()` for each edge in the graph, as described + // above. + // + // This should be called only once per instance of this class. + // + // Return false on OOM or error return from `onNode::operator()` or + // `onEdge::operator()`. + template + 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; + auto& edges = stack.back().edges; + + if (edges.empty()) { + if (!onNode(origin)) return false; + stack.popBack(); + continue; + } + + Edge edge = mozilla::Move(edges.back()); + edges.popBack(); + + if (!onEdge(origin, edge)) return false; + + auto ptr = seen.lookupForAdd(edge.referent); + // We've already seen this node, don't follow its edges. + if (ptr) continue; + + // Mark the referent as seen and follow its edges. + if (!seen.add(ptr, edge.referent) || !pushForTraversing(edge.referent)) { + return false; + } } + + return true; + } }; -} // namespace ubi -} // namespace JS +} // namespace ubi +} // namespace JS -#endif // js_UbiNodePostOrder_h +#endif // js_UbiNodePostOrder_h 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 @@ -11,8 +11,7 @@ #include "mozilla/Maybe.h" #include "mozilla/Move.h" -#include "jsalloc.h" - +#include "js/AllocPolicy.h" #include "js/UbiNodeBreadthFirst.h" #include "js/Vector.h" @@ -22,48 +21,45 @@ /** * 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; - } +struct JS_PUBLIC_API BackEdge { + private: + Node predecessor_; + EdgeName name_; - BackEdge(const BackEdge&) = delete; - BackEdge& operator=(const BackEdge&) = delete; + public: + using Ptr = mozilla::UniquePtr>; - BackEdge(BackEdge&& rhs) - : predecessor_(rhs.predecessor_) - , name_(mozilla::Move(rhs.name_)) - { - MOZ_ASSERT(&rhs != this); - } + BackEdge() : predecessor_(), name_(nullptr) {} - BackEdge& operator=(BackEdge&& rhs) { - this->~BackEdge(); - new(this) BackEdge(Move(rhs)); - return *this; - } + 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); + } - Ptr clone() const; + BackEdge& operator=(BackEdge&& rhs) { + this->~BackEdge(); + new (this) BackEdge(Move(rhs)); + return *this; + } - const EdgeName& name() const { return name_; } - EdgeName& name() { return name_; } + Ptr clone() const; - const JS::ubi::Node& predecessor() const { return predecessor_; } + const EdgeName& name() const { return name_; } + EdgeName& name() { return name_; } + + const JS::ubi::Node& predecessor() const { return predecessor_; } }; /** @@ -76,259 +72,246 @@ * 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; +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, const 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++; } + } - }; - - // The maximum number of paths to record for each node. - uint32_t maxNumPaths_; - - // The root node we are starting the search from. - Node root_; + MOZ_ASSERT(totalPathsRecorded <= totalMaxPathsToRecord); + if (totalPathsRecorded == totalMaxPathsToRecord) traversal.stop(); - // 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()); + return true; } + }; - 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; - } + // The maximum number of paths to record for each node. + uint32_t maxNumPaths_; - ShortestPaths(const ShortestPaths&) = delete; - ShortestPaths& operator=(const ShortestPaths&) = delete; + // The root node we are starting the search from. + Node root_; - /** - * 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); + // 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); + } - MOZ_ASSERT(paths.initialized()); - return mozilla::Some(mozilla::Move(paths)); - } + path.reverse(); - /** - * 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(); + if (!func(path)) return false; } - /** - * 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; - } + return true; + } }; #ifdef DEBUG @@ -340,11 +323,11 @@ // // JSObject* foo = ...; // JS::ubi::dumpPaths(rt, JS::ubi::Node(foo)); -JS_PUBLIC_API(void) -dumpPaths(JSRuntime* rt, Node node, uint32_t maxNumPaths = 10); +JS_PUBLIC_API void dumpPaths(JSRuntime* rt, Node node, + uint32_t maxNumPaths = 10); #endif -} // namespace ubi -} // namespace JS +} // namespace ubi +} // namespace JS -#endif // js_UbiNodeShortestPaths_h +#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 @@ -13,49 +13,44 @@ namespace js { -// Replacement for mozilla::UniquePtr that defaults to js::DefaultDelete. +// Replacement for mozilla::UniquePtr that defaults to JS::DeletePolicy. template > using UniquePtr = mozilla::UniquePtr; namespace detail { -template -struct UniqueSelector -{ +template +struct UniqueSelector { typedef UniquePtr SingleObject; }; -template -struct UniqueSelector -{ +template +struct UniqueSelector { typedef UniquePtr UnknownBound; }; -template -struct UniqueSelector -{ +template +struct UniqueSelector { typedef UniquePtr KnownBound; }; -} // namespace detail +} // namespace detail // Replacement for mozilla::MakeUnique that correctly calls js_new and produces // a js::UniquePtr. -template -typename detail::UniqueSelector::SingleObject -MakeUnique(Args&&... aArgs) -{ +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; +template +typename detail::UniqueSelector::UnknownBound MakeUnique( + decltype(sizeof(int)) aN) = delete; + +template +typename detail::UniqueSelector::KnownBound MakeUnique(Args&&... aArgs) = + delete; -} // namespace js +} // 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 @@ -15,6 +15,7 @@ #include "mozilla/Scoped.h" #include "mozilla/TemplateLib.h" #include "mozilla/UniquePtr.h" +#include "mozilla/WrappingOperations.h" #include #include @@ -26,6 +27,8 @@ #include "jstypes.h" +#include "mozmemory.h" + /* The public JS engine namespace. */ namespace JS {} @@ -35,65 +38,96 @@ /* The private JS engine namespace. */ namespace js {} -#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") - -extern MOZ_NORETURN MOZ_COLD JS_PUBLIC_API(void) -JS_Assert(const char* s, const char* file, int ln); +#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") + +extern MOZ_NORETURN MOZ_COLD JS_PUBLIC_API void JS_Assert(const char* s, + const char* file, + int ln); /* * Custom allocator support for SpiderMonkey */ #if defined JS_USE_CUSTOM_ALLOCATOR -# include "jscustomallocator.h" +#include "jscustomallocator.h" #else namespace js { -namespace oom { /* - * To make testing OOM in certain helper threads more effective, - * allow restricting the OOM testing to a certain helper thread - * type. This allows us to fail e.g. in off-thread script parsing - * without causing an OOM in the main thread first. + * Thread types are used to tag threads for certain kinds of testing (see + * below), and also used to characterize threads in the thread scheduler (see + * js/src/vm/HelperThreads.cpp). + * + * Please update oom::FirstThreadTypeToTest and oom::LastThreadTypeToTest when + * adding new thread types. */ enum ThreadType { - THREAD_TYPE_NONE = 0, // 0 - THREAD_TYPE_MAIN, // 1 - THREAD_TYPE_ASMJS, // 2 - THREAD_TYPE_ION, // 3 - THREAD_TYPE_PARSE, // 4 - 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 + THREAD_TYPE_NONE = 0, // 0 + THREAD_TYPE_COOPERATING, // 1 + THREAD_TYPE_WASM, // 2 + THREAD_TYPE_ION, // 3 + THREAD_TYPE_PARSE, // 4 + THREAD_TYPE_COMPRESS, // 5 + THREAD_TYPE_GCHELPER, // 6 + THREAD_TYPE_GCPARALLEL, // 7 + THREAD_TYPE_PROMISE_TASK, // 8 + THREAD_TYPE_ION_FREE, // 9 + THREAD_TYPE_WASM_TIER2, // 10 + THREAD_TYPE_WORKER, // 11 + THREAD_TYPE_MAX // Used to check shell function arguments }; +namespace oom { + /* - * Getter/Setter functions to encapsulate mozilla::ThreadLocal, - * implementation is in jsutil.cpp. + * Theads are tagged only in certain debug contexts. Notably, to make testing + * OOM in certain helper threads more effective, we allow restricting the OOM + * testing to a certain helper thread type. This allows us to fail e.g. in + * off-thread script parsing without causing an OOM in the active thread first. + * + * Getter/Setter functions to encapsulate mozilla::ThreadLocal, implementation + * is in jsutil.cpp. */ -# if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) +#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) + +// Define the range of threads tested by simulated OOM testing and the +// like. Testing worker threads is not supported. +const ThreadType FirstThreadTypeToTest = THREAD_TYPE_COOPERATING; +const ThreadType LastThreadTypeToTest = THREAD_TYPE_WASM_TIER2; + extern bool InitThreadType(void); extern void SetThreadType(ThreadType); -extern JS_FRIEND_API(uint32_t) GetThreadType(void); -# else +extern JS_FRIEND_API uint32_t GetThreadType(void); + +#else + inline bool InitThreadType(void) { return true; } -inline void SetThreadType(ThreadType t) {}; +inline void SetThreadType(ThreadType t){}; inline uint32_t GetThreadType(void) { return 0; } -# endif + +#endif } /* namespace oom */ } /* namespace js */ -# if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) +#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) #ifdef JS_OOM_BREAKPOINT +#if defined(_MSC_VER) +static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { + __asm {} + ; +} +#else static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); } +#endif #define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint() #else -#define JS_OOM_CALL_BP_FUNC() do {} while(0) +#define JS_OOM_CALL_BP_FUNC() \ + do { \ + } while (0) #endif namespace js { @@ -104,68 +138,171 @@ * 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; - -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(); -} - -inline bool -IsSimulatedOOMAllocation() -{ - return IsThreadSimulatingOOM() && - (counter == maxAllocations || (counter > maxAllocations && failAlways)); -} - -inline bool -ShouldFailWithOOM() -{ - if (!IsThreadSimulatingOOM()) - return false; - - counter++; - if (IsSimulatedOOMAllocation()) { - JS_OOM_CALL_BP_FUNC(); - return true; - } - return false; +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; + +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(); +} + +inline bool IsSimulatedOOMAllocation() { + return IsThreadSimulatingOOM() && (counter == maxAllocations || + (counter > maxAllocations && failAlways)); +} + +inline bool ShouldFailWithOOM() { + if (!IsThreadSimulatingOOM()) return false; + + counter++; + if (IsSimulatedOOMAllocation()) { + JS_OOM_CALL_BP_FUNC(); + return true; + } + return false; +} + +inline bool HadSimulatedOOM() { return counter >= maxAllocations; } + +/* + * Out of stack space testing support, similar to OOM testing functions. + */ + +extern JS_PUBLIC_DATA uint32_t stackTargetThread; +extern JS_PUBLIC_DATA uint64_t maxStackChecks; +extern JS_PUBLIC_DATA uint64_t stackCheckCounter; +extern JS_PUBLIC_DATA bool stackCheckFailAlways; + +extern void SimulateStackOOMAfter(uint64_t checks, uint32_t thread, + bool always); + +extern void ResetSimulatedStackOOM(); + +inline bool IsThreadSimulatingStackOOM() { + return js::oom::stackTargetThread && + js::oom::stackTargetThread == js::oom::GetThreadType(); +} + +inline bool IsSimulatedStackOOMCheck() { + return IsThreadSimulatingStackOOM() && + (stackCheckCounter == maxStackChecks || + (stackCheckCounter > maxStackChecks && stackCheckFailAlways)); } -inline bool -HadSimulatedOOM() { - return counter >= maxAllocations; +inline bool ShouldFailWithStackOOM() { + if (!IsThreadSimulatingStackOOM()) return false; + + stackCheckCounter++; + if (IsSimulatedStackOOMCheck()) { + JS_OOM_CALL_BP_FUNC(); + return true; + } + return false; +} + +inline bool HadSimulatedStackOOM() { + return stackCheckCounter >= maxStackChecks; +} + +/* + * Interrupt testing support, similar to OOM testing functions. + */ + +extern JS_PUBLIC_DATA uint32_t interruptTargetThread; +extern JS_PUBLIC_DATA uint64_t maxInterruptChecks; +extern JS_PUBLIC_DATA uint64_t interruptCheckCounter; +extern JS_PUBLIC_DATA bool interruptCheckFailAlways; + +extern void SimulateInterruptAfter(uint64_t checks, uint32_t thread, + bool always); + +extern void ResetSimulatedInterrupt(); + +inline bool IsThreadSimulatingInterrupt() { + return js::oom::interruptTargetThread && + js::oom::interruptTargetThread == js::oom::GetThreadType(); +} + +inline bool IsSimulatedInterruptCheck() { + return IsThreadSimulatingInterrupt() && + (interruptCheckCounter == maxInterruptChecks || + (interruptCheckCounter > maxInterruptChecks && + interruptCheckFailAlways)); +} + +inline bool ShouldFailWithInterrupt() { + if (!IsThreadSimulatingInterrupt()) return false; + + interruptCheckCounter++; + if (IsSimulatedInterruptCheck()) { + JS_OOM_CALL_BP_FUNC(); + return true; + } + return false; +} + +inline bool HadSimulatedInterrupt() { + return interruptCheckCounter >= maxInterruptChecks; } } /* namespace oom */ } /* namespace js */ -# define JS_OOM_POSSIBLY_FAIL() \ - do { \ - if (js::oom::ShouldFailWithOOM()) \ - return nullptr; \ - } while (0) - -# define JS_OOM_POSSIBLY_FAIL_BOOL() \ - do { \ - if (js::oom::ShouldFailWithOOM()) \ - return false; \ - } while (0) +#define JS_OOM_POSSIBLY_FAIL() \ + do { \ + if (js::oom::ShouldFailWithOOM()) return nullptr; \ + } while (0) + +#define JS_OOM_POSSIBLY_FAIL_BOOL() \ + do { \ + if (js::oom::ShouldFailWithOOM()) return false; \ + } while (0) + +#define JS_STACK_OOM_POSSIBLY_FAIL() \ + do { \ + if (js::oom::ShouldFailWithStackOOM()) return false; \ + } while (0) + +#define JS_STACK_OOM_POSSIBLY_FAIL_REPORT() \ + do { \ + if (js::oom::ShouldFailWithStackOOM()) { \ + ReportOverRecursed(cx); \ + return false; \ + } \ + } while (0) + +#define JS_INTERRUPT_POSSIBLY_FAIL() \ + do { \ + if (MOZ_UNLIKELY(js::oom::ShouldFailWithInterrupt())) { \ + cx->interrupt_ = true; \ + return cx->handleInterrupt(); \ + } \ + } while (0) -# else +#else -# define JS_OOM_POSSIBLY_FAIL() do {} while(0) -# define JS_OOM_POSSIBLY_FAIL_BOOL() do {} while(0) +#define JS_OOM_POSSIBLY_FAIL() \ + do { \ + } while (0) +#define JS_OOM_POSSIBLY_FAIL_BOOL() \ + do { \ + } while (0) +#define JS_STACK_OOM_POSSIBLY_FAIL() \ + do { \ + } while (0) +#define JS_STACK_OOM_POSSIBLY_FAIL_REPORT() \ + do { \ + } while (0) +#define JS_INTERRUPT_POSSIBLY_FAIL() \ + do { \ + } while (0) namespace js { namespace oom { static inline bool IsSimulatedOOMAllocation() { return false; } @@ -173,96 +310,102 @@ } /* namespace oom */ } /* namespace js */ -# endif /* DEBUG || JS_OOM_BREAKPOINT */ +#endif /* DEBUG || JS_OOM_BREAKPOINT */ namespace js { /* Disable OOM testing in sections which are not OOM safe. */ -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; - } +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 != UINT64_MAX), - oomAfter_(0) - { - if (oomEnabled_) { - MOZ_ALWAYS_TRUE(owner_.compareExchange(nullptr, this)); - oomAfter_ = int64_t(oom::maxAllocations) - int64_t(oom::counter); - oom::maxAllocations = UINT64_MAX; - } + AutoEnterOOMUnsafeRegion() + : oomEnabled_(oom::IsThreadSimulatingOOM() && + oom::maxAllocations != UINT64_MAX), + oomAfter_(0) { + if (oomEnabled_) { + 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 == 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 = uint64_t(maxAllocations); - MOZ_ALWAYS_TRUE(owner_.compareExchange(this, nullptr)); - } + ~AutoEnterOOMUnsafeRegion() { + if (oomEnabled_) { + 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 = uint64_t(maxAllocations); + MOZ_ALWAYS_TRUE(owner_.compareExchange(this, nullptr)); } + } - private: - // Used to catch concurrent use from other threads. - static mozilla::Atomic owner_; + private: + // Used to catch concurrent use from other threads. + static mozilla::Atomic owner_; - bool oomEnabled_; - int64_t oomAfter_; + bool oomEnabled_; + int64_t oomAfter_; #endif }; } /* namespace js */ -static inline void* js_malloc(size_t bytes) -{ - JS_OOM_POSSIBLY_FAIL(); - return malloc(bytes); +// Malloc allocation. + +namespace js { + +extern JS_PUBLIC_DATA arena_id_t MallocArena; + +extern void InitMallocAllocator(); +extern void ShutDownMallocAllocator(); + +} /* namespace js */ + +static inline void* js_malloc(size_t bytes) { + JS_OOM_POSSIBLY_FAIL(); + return moz_arena_malloc(js::MallocArena, bytes); } -static inline void* js_calloc(size_t bytes) -{ - JS_OOM_POSSIBLY_FAIL(); - return calloc(bytes, 1); +static inline void* js_calloc(size_t bytes) { + JS_OOM_POSSIBLY_FAIL(); + return moz_arena_calloc(js::MallocArena, bytes, 1); } -static inline void* js_calloc(size_t nmemb, size_t size) -{ - JS_OOM_POSSIBLY_FAIL(); - return calloc(nmemb, size); +static inline void* js_calloc(size_t nmemb, size_t size) { + JS_OOM_POSSIBLY_FAIL(); + return moz_arena_calloc(js::MallocArena, nmemb, size); } -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); +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); + JS_OOM_POSSIBLY_FAIL(); + return moz_arena_realloc(js::MallocArena, p, bytes); } -static inline void js_free(void* p) -{ - free(p); +static inline void js_free(void* p) { + // TODO: This should call |moz_arena_free(js::MallocArena, p)| but we + // currently can't enforce that all memory freed here was allocated by + // js_malloc(). + free(p); } -static inline char* js_strdup(const char* s) -{ - JS_OOM_POSSIBLY_FAIL(); - return strdup(s); -} -#endif/* JS_USE_CUSTOM_ALLOCATOR */ +JS_PUBLIC_API char* js_strdup(const char* s); +#endif /* JS_USE_CUSTOM_ALLOCATOR */ #include @@ -315,15 +458,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) \ - template \ - QUALIFIERS T * \ - NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \ - void* memory = ALLOCATOR(sizeof(T)); \ - return MOZ_LIKELY(memory) \ - ? new(memory) T(mozilla::Forward(args)...) \ - : nullptr; \ - } +#define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \ + template \ + QUALIFIERS T* NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \ + void* memory = ALLOCATOR(sizeof(T)); \ + return MOZ_LIKELY(memory) ? new (memory) \ + T(mozilla::Forward(args)...) \ + : nullptr; \ + } /* * Given a class which should provide 'make' methods, add @@ -335,13 +477,13 @@ * Note: Do not add a ; at the end of a use of JS_DECLARE_MAKE_METHODS, * or the build will break. */ -#define JS_DECLARE_MAKE_METHODS(MAKENAME, NEWNAME, QUALIFIERS)\ - template \ - QUALIFIERS mozilla::UniquePtr> \ - MAKENAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \ - T* ptr = NEWNAME(mozilla::Forward(args)...); \ - return mozilla::UniquePtr>(ptr); \ - } +#define JS_DECLARE_MAKE_METHODS(MAKENAME, NEWNAME, QUALIFIERS) \ + template \ + QUALIFIERS mozilla::UniquePtr> MAKENAME( \ + Args&&... args) MOZ_HEAP_ALLOCATOR { \ + T* ptr = NEWNAME(mozilla::Forward(args)...); \ + return mozilla::UniquePtr>(ptr); \ + } JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE) @@ -352,11 +494,9 @@ * instances of type |T|. Return false if the calculation overflowed. */ template -MOZ_MUST_USE inline bool -CalculateAllocSize(size_t numElems, size_t* bytesOut) -{ - *bytesOut = numElems * sizeof(T); - return (numElems & mozilla::tl::MulOverflowMask::value) == 0; +MOZ_MUST_USE inline bool CalculateAllocSize(size_t numElems, size_t* bytesOut) { + *bytesOut = numElems * sizeof(T); + return (numElems & mozilla::tl::MulOverflowMask::value) == 0; } /* @@ -365,104 +505,88 @@ * false if the calculation overflowed. */ template -MOZ_MUST_USE inline bool -CalculateAllocSizeWithExtra(size_t numExtra, size_t* bytesOut) -{ - *bytesOut = sizeof(T) + numExtra * sizeof(Extra); - return (numExtra & mozilla::tl::MulOverflowMask::value) == 0 && - *bytesOut >= sizeof(T); +MOZ_MUST_USE inline bool CalculateAllocSizeWithExtra(size_t numExtra, + size_t* bytesOut) { + *bytesOut = sizeof(T) + numExtra * sizeof(Extra); + return (numExtra & mozilla::tl::MulOverflowMask::value) == 0 && + *bytesOut >= sizeof(T); } } /* namespace js */ template -static MOZ_ALWAYS_INLINE void -js_delete(const T* p) -{ - if (p) { - p->~T(); - js_free(const_cast(p)); - } +static MOZ_ALWAYS_INLINE void js_delete(const T* p) { + if (p) { + p->~T(); + js_free(const_cast(p)); + } } -template -static MOZ_ALWAYS_INLINE void -js_delete_poison(const T* p) -{ - if (p) { - p->~T(); - memset(const_cast(p), 0x3B, sizeof(T)); - js_free(const_cast(p)); - } +template +static MOZ_ALWAYS_INLINE void js_delete_poison(const T* p) { + if (p) { + p->~T(); + memset(const_cast(p), 0x3B, sizeof(T)); + js_free(const_cast(p)); + } } template -static MOZ_ALWAYS_INLINE T* -js_pod_malloc() -{ - return static_cast(js_malloc(sizeof(T))); +static MOZ_ALWAYS_INLINE T* js_pod_malloc() { + return static_cast(js_malloc(sizeof(T))); } template -static MOZ_ALWAYS_INLINE T* -js_pod_calloc() -{ - return static_cast(js_calloc(sizeof(T))); +static MOZ_ALWAYS_INLINE T* js_pod_calloc() { + return static_cast(js_calloc(sizeof(T))); } template -static MOZ_ALWAYS_INLINE T* -js_pod_malloc(size_t numElems) -{ - size_t bytes; - if (MOZ_UNLIKELY(!js::CalculateAllocSize(numElems, &bytes))) - return nullptr; - return static_cast(js_malloc(bytes)); +static MOZ_ALWAYS_INLINE T* js_pod_malloc(size_t numElems) { + size_t bytes; + if (MOZ_UNLIKELY(!js::CalculateAllocSize(numElems, &bytes))) + return nullptr; + return static_cast(js_malloc(bytes)); } template -static MOZ_ALWAYS_INLINE T* -js_pod_calloc(size_t numElems) -{ - size_t bytes; - if (MOZ_UNLIKELY(!js::CalculateAllocSize(numElems, &bytes))) - return nullptr; - return static_cast(js_calloc(bytes)); +static MOZ_ALWAYS_INLINE T* js_pod_calloc(size_t numElems) { + size_t bytes; + if (MOZ_UNLIKELY(!js::CalculateAllocSize(numElems, &bytes))) + return nullptr; + return static_cast(js_calloc(bytes)); } template -static MOZ_ALWAYS_INLINE T* -js_pod_realloc(T* prior, size_t oldSize, size_t newSize) -{ - MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask::value)); - size_t bytes; - if (MOZ_UNLIKELY(!js::CalculateAllocSize(newSize, &bytes))) - return nullptr; - return static_cast(js_realloc(prior, bytes)); +static MOZ_ALWAYS_INLINE T* js_pod_realloc(T* prior, size_t oldSize, + size_t newSize) { + MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask::value)); + size_t bytes; + if (MOZ_UNLIKELY(!js::CalculateAllocSize(newSize, &bytes))) return nullptr; + return static_cast(js_realloc(prior, bytes)); } namespace js { -template -struct ScopedFreePtrTraits -{ - typedef T* type; - static T* empty() { return nullptr; } - static void release(T* ptr) { js_free(ptr); } +template +struct ScopedFreePtrTraits { + typedef T* type; + static T* empty() { return nullptr; } + static void release(T* ptr) { js_free(ptr); } }; SCOPED_TEMPLATE(ScopedJSFreePtr, ScopedFreePtrTraits) template -struct ScopedDeletePtrTraits : public ScopedFreePtrTraits -{ - static void release(T* ptr) { js_delete(ptr); } +struct ScopedDeletePtrTraits : public ScopedFreePtrTraits { + static void release(T* ptr) { js_delete(ptr); } }; SCOPED_TEMPLATE(ScopedJSDeletePtr, ScopedDeletePtrTraits) template -struct ScopedReleasePtrTraits : public ScopedFreePtrTraits -{ - static void release(T* ptr) { if (ptr) ptr->release(); } +struct ScopedReleasePtrTraits : public ScopedFreePtrTraits { + static void release(T* ptr) { + if (ptr) ptr->release(); + } }; SCOPED_TEMPLATE(ScopedReleasePtr, ScopedReleasePtrTraits) @@ -470,33 +594,27 @@ namespace JS { -template -struct DeletePolicy -{ - constexpr DeletePolicy() {} - - template - MOZ_IMPLICIT DeletePolicy(DeletePolicy other, - typename mozilla::EnableIf::value, - int>::Type dummy = 0) - {} +template +struct DeletePolicy { + constexpr DeletePolicy() {} - void operator()(const T* ptr) { - js_delete(const_cast(ptr)); - } + template + MOZ_IMPLICIT DeletePolicy( + DeletePolicy other, + typename mozilla::EnableIf::value, + int>::Type dummy = 0) {} + + void operator()(const T* ptr) { js_delete(const_cast(ptr)); } }; -struct FreePolicy -{ - void operator()(const void* ptr) { - js_free(const_cast(ptr)); - } +struct FreePolicy { + void operator()(const void* ptr) { js_free(const_cast(ptr)); } }; typedef mozilla::UniquePtr UniqueChars; typedef mozilla::UniquePtr UniqueTwoByteChars; -} // namespace JS +} // namespace JS namespace js { @@ -521,26 +639,24 @@ * * FIXME: OrderedHashTable uses a bit-mask; see bug 775896. */ -inline HashNumber -ScrambleHashCode(HashNumber h) -{ - /* - * Simply returning h would not cause any hash tables to produce wrong - * answers. But it can produce pathologically bad performance: The caller - * right-shifts the result, keeping only the highest bits. The high bits of - * hash codes are very often completely entropy-free. (So are the lowest - * bits.) - * - * So we use Fibonacci hashing, as described in Knuth, The Art of Computer - * Programming, 6.4. This mixes all the bits of the input hash code h. - * - * The value of goldenRatio is taken from the hex - * expansion of the golden ratio, which starts 1.9E3779B9.... - * This value is especially good if values with consecutive hash codes - * are stored in a hash table; see Knuth for details. - */ - static const HashNumber goldenRatio = 0x9E3779B9U; - return h * goldenRatio; +inline HashNumber ScrambleHashCode(HashNumber h) { + /* + * Simply returning h would not cause any hash tables to produce wrong + * answers. But it can produce pathologically bad performance: The caller + * right-shifts the result, keeping only the highest bits. The high bits of + * hash codes are very often completely entropy-free. (So are the lowest + * bits.) + * + * So we use Fibonacci hashing, as described in Knuth, The Art of Computer + * Programming, 6.4. This mixes all the bits of the input hash code h. + * + * The value of goldenRatio is taken from the hex + * expansion of the golden ratio, which starts 1.9E3779B9.... + * This value is especially good if values with consecutive hash codes + * are stored in a hash table; see Knuth for details. + */ + static const HashNumber goldenRatio = 0x9E3779B9U; + return mozilla::WrappingMultiply(h, goldenRatio); } } /* namespace detail */ @@ -549,29 +665,33 @@ /* sixgill annotation defines */ #ifndef HAVE_STATIC_ANNOTATIONS -# define HAVE_STATIC_ANNOTATIONS -# ifdef XGILL_PLUGIN -# define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND))) -# define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND))) -# define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND))) -# define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND))) -# define STATIC_INVARIANT(COND) __attribute__((invariant(#COND))) -# define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND))) -# define STATIC_ASSUME(COND) \ - JS_BEGIN_MACRO \ - __attribute__((assume_static(#COND), unused)) \ - int STATIC_PASTE1(assume_static_, __COUNTER__); \ +#define HAVE_STATIC_ANNOTATIONS +#ifdef XGILL_PLUGIN +#define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND))) +#define STATIC_PRECONDITION_ASSUME(COND) \ + __attribute__((precondition_assume(#COND))) +#define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND))) +#define STATIC_POSTCONDITION_ASSUME(COND) \ + __attribute__((postcondition_assume(#COND))) +#define STATIC_INVARIANT(COND) __attribute__((invariant(#COND))) +#define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND))) +#define STATIC_ASSUME(COND) \ + JS_BEGIN_MACRO \ + __attribute__((assume_static(#COND), unused)) int STATIC_PASTE1( \ + assume_static_, __COUNTER__); \ + JS_END_MACRO +#else /* XGILL_PLUGIN */ +#define STATIC_PRECONDITION(COND) /* nothing */ +#define STATIC_PRECONDITION_ASSUME(COND) /* nothing */ +#define STATIC_POSTCONDITION(COND) /* nothing */ +#define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */ +#define STATIC_INVARIANT(COND) /* nothing */ +#define STATIC_INVARIANT_ASSUME(COND) /* nothing */ +#define STATIC_ASSUME(COND) \ + JS_BEGIN_MACRO /* nothing */ \ JS_END_MACRO -# else /* XGILL_PLUGIN */ -# define STATIC_PRECONDITION(COND) /* nothing */ -# define STATIC_PRECONDITION_ASSUME(COND) /* nothing */ -# define STATIC_POSTCONDITION(COND) /* nothing */ -# define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */ -# define STATIC_INVARIANT(COND) /* nothing */ -# define STATIC_INVARIANT_ASSUME(COND) /* nothing */ -# define STATIC_ASSUME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO -# endif /* XGILL_PLUGIN */ -# define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference()) +#endif /* XGILL_PLUGIN */ +#define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference()) #endif /* HAVE_STATIC_ANNOTATIONS */ #endif /* js_Utility_h */ 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 @@ -11,6 +11,7 @@ #include "mozilla/Attributes.h" #include "mozilla/Casting.h" +#include "mozilla/EndianUtils.h" #include "mozilla/FloatingPoint.h" #include "mozilla/Likely.h" @@ -23,103 +24,101 @@ #include "js/RootingAPI.h" #include "js/Utility.h" -namespace JS { class Value; } +namespace JS { +class Value; +} /* JS::Value can store a full int32_t. */ -#define JSVAL_INT_BITS 32 -#define JSVAL_INT_MIN ((int32_t)0x80000000) -#define JSVAL_INT_MAX ((int32_t)0x7fffffff) +#define JSVAL_INT_BITS 32 +#define JSVAL_INT_MIN ((int32_t)0x80000000) +#define JSVAL_INT_MAX ((int32_t)0x7fffffff) #if defined(JS_PUNBOX64) -# define JSVAL_TAG_SHIFT 47 +#define JSVAL_TAG_SHIFT 47 #endif // 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 -# define JS_ENUM_FOOTER(id) +#define JS_ENUM_HEADER(id, type) enum id : type +#define JS_ENUM_FOOTER(id) #else -# define JS_ENUM_HEADER(id, type) enum id -# define JS_ENUM_FOOTER(id) __attribute__((packed)) +#define JS_ENUM_HEADER(id, type) enum id +#define JS_ENUM_FOOTER(id) __attribute__((packed)) #endif -/* Remember to propagate changes to the C defines below. */ -JS_ENUM_HEADER(JSValueType, uint8_t) -{ - JSVAL_TYPE_DOUBLE = 0x00, - JSVAL_TYPE_INT32 = 0x01, - JSVAL_TYPE_UNDEFINED = 0x02, - JSVAL_TYPE_BOOLEAN = 0x03, - JSVAL_TYPE_MAGIC = 0x04, - JSVAL_TYPE_STRING = 0x05, - JSVAL_TYPE_SYMBOL = 0x06, - 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, - JSVAL_TYPE_MISSING = 0x21 -} JS_ENUM_FOOTER(JSValueType); +JS_ENUM_HEADER(JSValueType, uint8_t){ + JSVAL_TYPE_DOUBLE = 0x00, JSVAL_TYPE_INT32 = 0x01, + JSVAL_TYPE_BOOLEAN = 0x02, JSVAL_TYPE_UNDEFINED = 0x03, + JSVAL_TYPE_NULL = 0x04, JSVAL_TYPE_MAGIC = 0x05, JSVAL_TYPE_STRING = 0x06, + JSVAL_TYPE_SYMBOL = 0x07, JSVAL_TYPE_PRIVATE_GCTHING = 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, + JSVAL_TYPE_MISSING = 0x21} JS_ENUM_FOOTER(JSValueType); static_assert(sizeof(JSValueType) == 1, "compiler typed enum support is apparently buggy"); #if defined(JS_NUNBOX32) -/* Remember to propagate changes to the C defines below. */ -JS_ENUM_HEADER(JSValueTag, uint32_t) -{ - JSVAL_TAG_CLEAR = 0xFFFFFF80, - JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32, - JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED, - JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING, - JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL, - 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_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING -} JS_ENUM_FOOTER(JSValueTag); +JS_ENUM_HEADER(JSValueTag, uint32_t){ + JSVAL_TAG_CLEAR = 0xFFFFFF80, + JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32, + JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED, + JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL, + JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN, + JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC, + JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING, + JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL, + JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING, + JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | + JSVAL_TYPE_OBJECT} JS_ENUM_FOOTER(JSValueTag); static_assert(sizeof(JSValueTag) == sizeof(uint32_t), "compiler typed enum support is apparently buggy"); #elif defined(JS_PUNBOX64) -/* Remember to propagate changes to the C defines below. */ -JS_ENUM_HEADER(JSValueTag, uint32_t) -{ - JSVAL_TAG_MAX_DOUBLE = 0x1FFF0, - JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32, - JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED, - JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING, - JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL, - 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_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING -} JS_ENUM_FOOTER(JSValueTag); +JS_ENUM_HEADER(JSValueTag, uint32_t){ + JSVAL_TAG_MAX_DOUBLE = 0x1FFF0, + JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32, + JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED, + JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL, + JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN, + JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC, + JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING, + JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL, + JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | + JSVAL_TYPE_PRIVATE_GCTHING, + JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | + JSVAL_TYPE_OBJECT} JS_ENUM_FOOTER(JSValueTag); static_assert(sizeof(JSValueTag) == sizeof(uint32_t), "compiler typed enum support is apparently buggy"); -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_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT) -} JS_ENUM_FOOTER(JSValueShiftedTag); +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_NULL = (((uint64_t)JSVAL_TAG_NULL) << 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_STRING = (((uint64_t)JSVAL_TAG_STRING) + << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) + << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) + << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_OBJECT = + (((uint64_t)JSVAL_TAG_OBJECT) + << JSVAL_TAG_SHIFT)} JS_ENUM_FOOTER(JSValueShiftedTag); static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t), "compiler typed enum support is apparently buggy"); @@ -138,96 +137,109 @@ #if defined(JS_NUNBOX32) -#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) +#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) -#define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << 32) +#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 -#define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING +#define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT +#define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 +#define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING #elif defined(JS_PUNBOX64) -#define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) +#define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) + +// This should only be used in toGCThing, see the 'Spectre mitigations' comment. +#define JSVAL_PAYLOAD_MASK_GCTHING 0x00007FFFFFFFFFFFLL + +#define JSVAL_TAG_MASK 0xFFFF800000000000LL +#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type))) +#define JSVAL_TYPE_TO_SHIFTED_TAG(type) \ + (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << 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))) -#define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT) +#define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT +#define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 +#define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING -#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 -#define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING +#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT +#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_BOOLEAN +#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING -#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET JSVAL_SHIFTED_TAG_NULL -#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT -#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED -#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING +// JSVAL_TYPE_OBJECT and JSVAL_TYPE_NULL differ by one bit. We can use this to +// implement toObjectOrNull more efficiently. +#define JSVAL_OBJECT_OR_NULL_BIT (uint64_t(0x8) << JSVAL_TAG_SHIFT) +static_assert( + (JSVAL_SHIFTED_TAG_NULL ^ JSVAL_SHIFTED_TAG_OBJECT) == + JSVAL_OBJECT_OR_NULL_BIT, + "JSVAL_OBJECT_OR_NULL_BIT must be consistent with object and null tags"); #endif /* JS_PUNBOX64 */ -typedef enum JSWhyMagic -{ - /** a hole in a native object's elements */ - JS_ELEMENTS_HOLE, +typedef enum JSWhyMagic { + /** a hole in a native object's elements */ + JS_ELEMENTS_HOLE, - /** there is not a pending iterator value */ - JS_NO_ITER_VALUE, + /** there is not a pending iterator value */ + JS_NO_ITER_VALUE, - /** exception value thrown when closing a generator */ - JS_GENERATOR_CLOSING, + /** exception value thrown when closing a generator */ + JS_GENERATOR_CLOSING, - /** compiler sentinel value */ - JS_NO_CONSTANT, + /** compiler sentinel value */ + JS_NO_CONSTANT, - /** used in debug builds to catch tracing errors */ - JS_THIS_POISON, + /** used in debug builds to catch tracing errors */ + JS_THIS_POISON, - /** used in debug builds to catch tracing errors */ - JS_ARG_POISON, + /** used in debug builds to catch tracing errors */ + JS_ARG_POISON, - /** an empty subnode in the AST serializer */ - JS_SERIALIZE_NO_NODE, + /** an empty subnode in the AST serializer */ + JS_SERIALIZE_NO_NODE, - /** lazy arguments value on the stack */ - JS_LAZY_ARGUMENTS, + /** lazy arguments value on the stack */ + JS_LAZY_ARGUMENTS, - /** optimized-away 'arguments' value */ - JS_OPTIMIZED_ARGUMENTS, + /** optimized-away 'arguments' value */ + JS_OPTIMIZED_ARGUMENTS, - /** magic value passed to natives to indicate construction */ - JS_IS_CONSTRUCTING, + /** magic value passed to natives to indicate construction */ + JS_IS_CONSTRUCTING, - /** value of static block object slot */ - JS_BLOCK_NEEDS_CLONE, + /** value of static block object slot */ + JS_BLOCK_NEEDS_CLONE, - /** see class js::HashableValue */ - JS_HASH_KEY_EMPTY, + /** see class js::HashableValue */ + JS_HASH_KEY_EMPTY, - /** error while running Ion code */ - JS_ION_ERROR, + /** error while running Ion code */ + JS_ION_ERROR, - /** missing recover instruction result */ - JS_ION_BAILOUT, + /** missing recover instruction result */ + JS_ION_BAILOUT, - /** optimized out slot */ - JS_OPTIMIZED_OUT, + /** optimized out slot */ + JS_OPTIMIZED_OUT, - /** uninitialized lexical bindings that produce ReferenceError on touch. */ - JS_UNINITIALIZED_LEXICAL, + /** uninitialized lexical bindings that produce ReferenceError on touch. */ + JS_UNINITIALIZED_LEXICAL, - /** for local use */ - JS_GENERIC_MAGIC, + /** standard constructors are not created for off-thread parsing. */ + JS_OFF_THREAD_CONSTRUCTOR, - JS_WHY_MAGIC_COUNT + /** for local use */ + JS_GENERIC_MAGIC, + + JS_WHY_MAGIC_COUNT } JSWhyMagic; +namespace js { +static inline JS::Value PoisonedObjectValue(uintptr_t poison); +} // namespace js + namespace JS { static inline constexpr JS::Value UndefinedValue(); -static inline JS::Value PoisonedObjectValue(JSObject* obj); namespace detail { @@ -235,11 +247,10 @@ constexpr uint64_t CanonicalizedNaNSignificand = 0x8000000000000ULL; constexpr uint64_t CanonicalizedNaNBits = - mozilla::SpecificNaNBits::value; -} // namespace detail +} // namespace detail /** * Returns a generic quiet NaN value, with all payload bits set to zero. @@ -247,26 +258,21 @@ * Among other properties, this NaN's bit pattern conforms to JS::Value's * bit pattern restrictions. */ -static MOZ_ALWAYS_INLINE double -GenericNaN() -{ +static MOZ_ALWAYS_INLINE double GenericNaN() { return mozilla::SpecificNaN(detail::CanonicalizedNaNSignBit, detail::CanonicalizedNaNSignificand); } /* MSVC with PGO miscompiles this function. */ #if defined(_MSC_VER) -# pragma optimize("g", off) +#pragma optimize("g", off) #endif -static inline double -CanonicalizeNaN(double d) -{ - if (MOZ_UNLIKELY(mozilla::IsNaN(d))) - return GenericNaN(); - return d; +static inline double CanonicalizeNaN(double d) { + if (MOZ_UNLIKELY(mozilla::IsNaN(d))) return GenericNaN(); + return d; } #if defined(_MSC_VER) -# pragma optimize("", on) +#pragma optimize("", on) #endif /** @@ -275,16 +281,17 @@ * * - JS::Value has setX() and isX() members for X in * - * { Int32, Double, String, Symbol, Boolean, Undefined, Null, Object, Magic } + * { Int32, Double, String, Symbol, Boolean, Undefined, Null, + * Object, Magic } * * JS::Value also contains toX() for each of the non-singleton types. * - * - Magic is a singleton type whose payload contains either a JSWhyMagic "reason" for - * the magic value or a uint32_t value. By providing JSWhyMagic values when - * creating and checking for magic values, it is possible to assert, at - * runtime, that only magic values with the expected reason flow through a - * particular value. For example, if cx->exception has a magic value, the - * reason must be JS_GENERATOR_CLOSING. + * - Magic is a singleton type whose payload contains either a JSWhyMagic + * "reason" for the magic value or a uint32_t value. By providing JSWhyMagic + * values when creating and checking for magic values, it is possible to + * assert, at runtime, that only magic values with the expected reason flow + * through a particular value. For example, if cx->exception has a magic + * value, the reason must be JS_GENERATOR_CLOSING. * * - The JS::Value operations are preferred. The JSVAL_* operations remain for * compatibility; they may be removed at some point. These operations mostly @@ -294,1263 +301,1180 @@ * Value::setObject takes a JSObject&. (Conversely, Value::toObject returns a * JSObject&.) A convenience member Value::setObjectOrNull is provided. * - * - JSVAL_VOID is the same as the singleton value of the Undefined type. - * * - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on * 32-bit user code should avoid copying jsval/JS::Value as much as possible, * preferring to pass by const Value&. + * + * Spectre mitigations + * =================== + * To mitigate Spectre attacks, we do the following: + * + * - On 64-bit platforms, when unboxing a Value, we XOR the bits with the + * expected type tag (instead of masking the payload bits). This guarantees + * that toString, toObject, toSymbol will return an invalid pointer (because + * some high bits will be set) when called on a Value with a different type + * tag. + * + * - On 32-bit platforms,when unboxing an object/string/symbol Value, we use a + * conditional move (not speculated) to zero the payload register if the type + * doesn't match. */ -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. - */ - Value() = default; - Value(const Value& v) = default; - - /** - * Returns false if creating a NumberValue containing the given type would - * be lossy, true otherwise. - */ - template - static bool isNumberRepresentable(const T t) { - return T(double(t)) == t; - } - - /*** Mutators ***/ - - void setNull() { - data.asBits = bitsFromTagAndPayload(JSVAL_TAG_NULL, 0); - } - - void setUndefined() { - data.asBits = bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0); - } - - void setInt32(int32_t i) { - data.asBits = bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i)); - } - - int32_t& getInt32Ref() { - MOZ_ASSERT(isInt32()); - return data.s.payload.i32; - } - - void setDouble(double 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() { - setDouble(GenericNaN()); - } - - double& getDoubleRef() { - MOZ_ASSERT(isDouble()); - return data.asDouble; - } - - void setString(JSString* str) { - MOZ_ASSERT(uintptr_t(str) > 0x1000); - data.asBits = bitsFromTagAndPayload(JSVAL_TAG_STRING, PayloadType(str)); - } - - void setSymbol(JS::Symbol* sym) { - MOZ_ASSERT(uintptr_t(sym) > 0x1000); - data.asBits = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym)); - } - - void setObject(JSObject& 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); +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 - 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.asBits = bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(b)); - } - - void setMagic(JSWhyMagic why) { - data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, uint32_t(why)); - } + /* + * N.B. the default constructor leaves Value unitialized. Adding a default + * constructor prevents Value from being stored in a union. + */ + Value() = default; + Value(const Value& v) = default; + + /** + * Returns false if creating a NumberValue containing the given type would + * be lossy, true otherwise. + */ + template + static bool isNumberRepresentable(const T t) { + return T(double(t)) == t; + } + + /*** Mutators ***/ + + void setNull() { data.asBits = bitsFromTagAndPayload(JSVAL_TAG_NULL, 0); } + + void setUndefined() { + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_UNDEFINED, 0); + } + + void setInt32(int32_t i) { + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i)); + } + + int32_t& getInt32Ref() { + MOZ_ASSERT(isInt32()); + return data.s.payload.i32; + } + + void setDouble(double 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() { setDouble(GenericNaN()); } + + double& getDoubleRef() { + MOZ_ASSERT(isDouble()); + return data.asDouble; + } + + void setString(JSString* str) { + MOZ_ASSERT(js::gc::IsCellPointerValid(str)); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_STRING, PayloadType(str)); + } + + void setSymbol(JS::Symbol* sym) { + MOZ_ASSERT(js::gc::IsCellPointerValid(sym)); + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym)); + } + + void setObject(JSObject& obj) { + MOZ_ASSERT(js::gc::IsCellPointerValid(&obj)); + + // This should not be possible and is undefined behavior, but some + // ObjectValue(nullptr) are sneaking in. Try to catch them here, if + // indeed they are going through this code. I tested gcc, and it at + // least will *not* elide the null check even though it would be + // permitted according to the spec. The temporary is necessary to + // prevent gcc from helpfully pointing out that this code makes no + // sense. +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + JSObject* testObj = &obj; + MOZ_DIAGNOSTIC_ASSERT(testObj != nullptr); +#endif - void setMagicUint32(uint32_t payload) { - data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, payload); +#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 js::PoisonedObjectValue(uintptr_t poison); + + public: + void setBoolean(bool b) { + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(b)); + } + + void setMagic(JSWhyMagic why) { + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, uint32_t(why)); + } + + void setMagicUint32(uint32_t payload) { + data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, payload); + } + + bool setNumber(uint32_t ui) { + if (ui > JSVAL_INT_MAX) { + setDouble((double)ui); + return false; + } else { + setInt32((int32_t)ui); + return true; } + } - bool setNumber(uint32_t ui) { - if (ui > JSVAL_INT_MAX) { - setDouble((double)ui); - return false; - } else { - setInt32((int32_t)ui); - return true; - } + bool setNumber(double d) { + int32_t i; + if (mozilla::NumberIsInt32(d, &i)) { + setInt32(i); + return true; } - bool setNumber(double d) { - int32_t i; - if (mozilla::NumberIsInt32(d, &i)) { - setInt32(i); - return true; - } - - setDouble(d); - return false; - } + setDouble(d); + return false; + } - void setObjectOrNull(JSObject* arg) { - if (arg) - setObject(*arg); - else - setNull(); - } + void setObjectOrNull(JSObject* arg) { + if (arg) + setObject(*arg); + else + setNull(); + } - void swap(Value& rhs) { - uint64_t tmp = rhs.data.asBits; - rhs.data.asBits = data.asBits; - data.asBits = tmp; - } + void swap(Value& rhs) { + uint64_t tmp = rhs.data.asBits; + rhs.data.asBits = data.asBits; + data.asBits = tmp; + } - private: - JSValueTag toTag() const { + private: + JSValueTag toTag() const { #if defined(JS_NUNBOX32) - return data.s.tag; + return data.s.tag; #elif defined(JS_PUNBOX64) - return JSValueTag(data.asBits >> JSVAL_TAG_SHIFT); + return JSValueTag(data.asBits >> JSVAL_TAG_SHIFT); #endif - } + } - public: - /*** JIT-only interfaces to interact with and create raw Values ***/ + public: + /*** JIT-only interfaces to interact with and create raw Values ***/ #if defined(JS_NUNBOX32) - PayloadType toNunboxPayload() const { - return data.s.payload.i32; - } + PayloadType toNunboxPayload() const { + return static_cast(data.s.payload.i32); + } - JSValueTag toNunboxTag() const { - return data.s.tag; - } + JSValueTag toNunboxTag() const { return data.s.tag; } #elif defined(JS_PUNBOX64) - const void* bitsAsPunboxPointer() const { - return reinterpret_cast(data.asBits); - } + const void* bitsAsPunboxPointer() const { + return reinterpret_cast(data.asBits); + } #endif - /*** Value type queries ***/ + /*** 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. - */ + /* + * 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 { + bool isUndefined() const { #if defined(JS_NUNBOX32) - return toTag() == JSVAL_TAG_UNDEFINED; + return toTag() == JSVAL_TAG_UNDEFINED; #elif defined(JS_PUNBOX64) - return data.asBits == JSVAL_SHIFTED_TAG_UNDEFINED; + return data.asBits == JSVAL_SHIFTED_TAG_UNDEFINED; #endif - } + } - bool isNull() const { + bool isNull() const { #if defined(JS_NUNBOX32) - return toTag() == JSVAL_TAG_NULL; + return toTag() == JSVAL_TAG_NULL; #elif defined(JS_PUNBOX64) - return data.asBits == JSVAL_SHIFTED_TAG_NULL; + return data.asBits == JSVAL_SHIFTED_TAG_NULL; #endif - } + } - bool isNullOrUndefined() const { - return isNull() || isUndefined(); - } + bool isNullOrUndefined() const { return isNull() || isUndefined(); } - bool isInt32() const { - return toTag() == JSVAL_TAG_INT32; - } + bool isInt32() const { return toTag() == JSVAL_TAG_INT32; } - bool isInt32(int32_t i32) const { - return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i32)); - } + bool isInt32(int32_t i32) const { + return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i32)); + } - bool isDouble() const { + bool isDouble() const { #if defined(JS_NUNBOX32) - return uint32_t(toTag()) <= uint32_t(JSVAL_TAG_CLEAR); + return uint32_t(toTag()) <= uint32_t(JSVAL_TAG_CLEAR); #elif defined(JS_PUNBOX64) - return (data.asBits | mozilla::DoubleTypeTraits::kSignBit) <= JSVAL_SHIFTED_TAG_MAX_DOUBLE; + return (data.asBits | mozilla::DoubleTypeTraits::kSignBit) <= + JSVAL_SHIFTED_TAG_MAX_DOUBLE; #endif - } + } - bool isNumber() const { + bool isNumber() const { #if defined(JS_NUNBOX32) - MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR); - return uint32_t(toTag()) <= uint32_t(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET); + 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; + return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET; #endif - } + } - bool isString() const { - return toTag() == JSVAL_TAG_STRING; - } + bool isString() const { return toTag() == JSVAL_TAG_STRING; } - bool isSymbol() const { - return toTag() == JSVAL_TAG_SYMBOL; - } + bool isSymbol() const { return toTag() == JSVAL_TAG_SYMBOL; } - bool isObject() const { + bool isObject() const { #if defined(JS_NUNBOX32) - return toTag() == JSVAL_TAG_OBJECT; + 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; + MOZ_ASSERT((data.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); + return data.asBits >= JSVAL_SHIFTED_TAG_OBJECT; #endif - } + } - bool isPrimitive() const { + bool isPrimitive() const { #if defined(JS_NUNBOX32) - return uint32_t(toTag()) < uint32_t(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET); + 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; + return data.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET; #endif - } + } - bool isObjectOrNull() const { - 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 isObjectOrNull() const { return isObject() || isNull(); } - bool isGCThing() const { + bool isGCThing() const { #if defined(JS_NUNBOX32) - /* gcc sometimes generates signed < without explicit casts. */ - return uint32_t(toTag()) >= uint32_t(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET); + /* 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; + return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET; #endif - } + } - bool isBoolean() const { - return toTag() == JSVAL_TAG_BOOLEAN; - } + bool isBoolean() const { return toTag() == JSVAL_TAG_BOOLEAN; } - bool isTrue() const { - return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(true)); - } + bool isTrue() const { + return data.asBits == + bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(true)); + } - bool isFalse() const { - return data.asBits == bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(false)); - } + bool isFalse() const { + return data.asBits == + bitsFromTagAndPayload(JSVAL_TAG_BOOLEAN, uint32_t(false)); + } - bool isMagic() const { - return toTag() == JSVAL_TAG_MAGIC; - } + bool isMagic() const { return toTag() == JSVAL_TAG_MAGIC; } - bool isMagic(JSWhyMagic why) const { - MOZ_ASSERT_IF(isMagic(), data.s.payload.why == why); - return isMagic(); + bool isMagic(JSWhyMagic why) const { + if (!isMagic()) { + return false; } + MOZ_RELEASE_ASSERT(data.s.payload.why == why); + return true; + } - bool isMarkable() const { - return isGCThing() && !isNull(); - } + JS::TraceKind traceKind() const { + MOZ_ASSERT(isGCThing()); + 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); + } - JS::TraceKind traceKind() const { - MOZ_ASSERT(isMarkable()); - 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 { + MOZ_ASSERT(isMagic()); + return data.s.payload.why; + } - JSWhyMagic whyMagic() const { - MOZ_ASSERT(isMagic()); - return data.s.payload.why; - } - - uint32_t magicUint32() const { - MOZ_ASSERT(isMagic()); - return data.s.payload.u32; - } + uint32_t magicUint32() const { + MOZ_ASSERT(isMagic()); + return data.s.payload.u32; + } - /*** Comparison ***/ + /*** Comparison ***/ - bool operator==(const Value& rhs) const { - return data.asBits == rhs.data.asBits; - } + bool operator==(const Value& rhs) const { + return data.asBits == rhs.data.asBits; + } - bool operator!=(const Value& rhs) const { - return data.asBits != rhs.data.asBits; - } + bool operator!=(const Value& rhs) const { + return data.asBits != rhs.data.asBits; + } - friend inline bool SameType(const Value& lhs, const Value& rhs); + friend inline bool SameType(const Value& lhs, const Value& rhs); - /*** Extract the value's typed payload ***/ + /*** Extract the value's typed payload ***/ - int32_t toInt32() const { - MOZ_ASSERT(isInt32()); + int32_t toInt32() const { + MOZ_ASSERT(isInt32()); #if defined(JS_NUNBOX32) - return data.s.payload.i32; + return data.s.payload.i32; #elif defined(JS_PUNBOX64) - return int32_t(data.asBits); + return int32_t(data.asBits); #endif - } + } - double toDouble() const { - MOZ_ASSERT(isDouble()); - return data.asDouble; - } + double toDouble() const { + MOZ_ASSERT(isDouble()); + return data.asDouble; + } - double toNumber() const { - MOZ_ASSERT(isNumber()); - return isDouble() ? toDouble() : double(toInt32()); - } + double toNumber() const { + MOZ_ASSERT(isNumber()); + return isDouble() ? toDouble() : double(toInt32()); + } - JSString* toString() const { - MOZ_ASSERT(isString()); + JSString* toString() const { + MOZ_ASSERT(isString()); #if defined(JS_NUNBOX32) - return data.s.payload.str; + return data.s.payload.str; #elif defined(JS_PUNBOX64) - return reinterpret_cast(data.asBits & JSVAL_PAYLOAD_MASK); + return reinterpret_cast(data.asBits ^ JSVAL_SHIFTED_TAG_STRING); #endif - } + } - JS::Symbol* toSymbol() const { - MOZ_ASSERT(isSymbol()); + JS::Symbol* toSymbol() const { + MOZ_ASSERT(isSymbol()); #if defined(JS_NUNBOX32) - return data.s.payload.sym; + return data.s.payload.sym; #elif defined(JS_PUNBOX64) - return reinterpret_cast(data.asBits & JSVAL_PAYLOAD_MASK); + return reinterpret_cast(data.asBits ^ + JSVAL_SHIFTED_TAG_SYMBOL); #endif - } + } - JSObject& toObject() const { - MOZ_ASSERT(isObject()); + JSObject& toObject() const { + MOZ_ASSERT(isObject()); #if defined(JS_NUNBOX32) - return *data.s.payload.obj; + return *data.s.payload.obj; #elif defined(JS_PUNBOX64) - return *toObjectOrNull(); + uint64_t ptrBits = data.asBits ^ JSVAL_SHIFTED_TAG_OBJECT; + MOZ_ASSERT(ptrBits); + MOZ_ASSERT((ptrBits & 0x7) == 0); + return *reinterpret_cast(ptrBits); #endif - } + } - JSObject* toObjectOrNull() const { - MOZ_ASSERT(isObjectOrNull()); + JSObject* toObjectOrNull() const { + MOZ_ASSERT(isObjectOrNull()); #if defined(JS_NUNBOX32) - return data.s.payload.obj; + 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); + // Note: the 'Spectre mitigations' comment at the top of this class + // explains why we use XOR here and in other to* methods. + uint64_t ptrBits = + (data.asBits ^ JSVAL_SHIFTED_TAG_OBJECT) & ~JSVAL_OBJECT_OR_NULL_BIT; + MOZ_ASSERT((ptrBits & 0x7) == 0); + return reinterpret_cast(ptrBits); #endif - } + } - js::gc::Cell* toGCThing() const { - MOZ_ASSERT(isGCThing()); + js::gc::Cell* toGCThing() const { + MOZ_ASSERT(isGCThing()); #if defined(JS_NUNBOX32) - return data.s.payload.cell; + 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); + uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK_GCTHING; + MOZ_ASSERT((ptrBits & 0x7) == 0); + return reinterpret_cast(ptrBits); #endif - } + } - js::gc::Cell* toMarkablePointer() const { - MOZ_ASSERT(isMarkable()); - return toGCThing(); - } + GCCellPtr toGCCellPtr() const { return GCCellPtr(toGCThing(), traceKind()); } - GCCellPtr toGCCellPtr() const { - return GCCellPtr(toGCThing(), traceKind()); - } - - bool toBoolean() const { - MOZ_ASSERT(isBoolean()); + bool toBoolean() const { + MOZ_ASSERT(isBoolean()); #if defined(JS_NUNBOX32) - return bool(data.s.payload.boo); + return bool(data.s.payload.boo); #elif defined(JS_PUNBOX64) - return bool(data.asBits & JSVAL_PAYLOAD_MASK); + return bool(int32_t(data.asBits)); #endif - } + } - uint32_t payloadAsRawUint32() const { - MOZ_ASSERT(!isDouble()); - return data.s.payload.u32; - } + uint32_t payloadAsRawUint32() const { + MOZ_ASSERT(!isDouble()); + return data.s.payload.u32; + } - uint64_t asRawBits() const { - return data.asBits; - } + uint64_t asRawBits() const { return data.asBits; } - JSValueType extractNonDoubleType() const { - uint32_t type = toTag() & 0xF; - MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); - return JSValueType(type); - } + JSValueType extractNonDoubleType() const { + uint32_t type = toTag() & 0xF; + MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE); + return JSValueType(type); + } + + /* + * Private API + * + * Private setters/getters allow the caller to read/write arbitrary types + * that fit in the 64-bit payload. It is the caller's responsibility, after + * storing to a value with setPrivateX to read only using getPrivateX. + * Privates values are given a type which ensures they are not marked. + */ - /* - * Private API - * - * Private setters/getters allow the caller to read/write arbitrary types - * that fit in the 64-bit payload. It is the caller's responsibility, after - * storing to a value with setPrivateX to read only using getPrivateX. - * Privates values are given a type which ensures they are not marked. - */ - - void setPrivate(void* ptr) { - MOZ_ASSERT((uintptr_t(ptr) & 1) == 0); + void setPrivate(void* ptr) { + MOZ_ASSERT((uintptr_t(ptr) & 1) == 0); #if defined(JS_NUNBOX32) - data.s.tag = JSValueTag(0); - data.s.payload.ptr = ptr; + data.s.tag = JSValueTag(0); + data.s.payload.ptr = ptr; #elif defined(JS_PUNBOX64) - data.asBits = uintptr_t(ptr) >> 1; + data.asBits = uintptr_t(ptr) >> 1; #endif - MOZ_ASSERT(isDouble()); - } + MOZ_ASSERT(isDouble()); + } - void* toPrivate() const { - MOZ_ASSERT(isDouble()); + void* toPrivate() const { + MOZ_ASSERT(isDouble()); #if defined(JS_NUNBOX32) - return data.s.payload.ptr; + return data.s.payload.ptr; #elif defined(JS_PUNBOX64) - MOZ_ASSERT((data.asBits & 0x8000000000000000ULL) == 0); - return reinterpret_cast(data.asBits << 1); + MOZ_ASSERT((data.asBits & 0x8000000000000000ULL) == 0); + return reinterpret_cast(data.asBits << 1); #endif - } + } - void setPrivateUint32(uint32_t ui) { - MOZ_ASSERT(uint32_t(int32_t(ui)) == ui); - setInt32(int32_t(ui)); - } + void setPrivateUint32(uint32_t ui) { + MOZ_ASSERT(uint32_t(int32_t(ui)) == ui); + setInt32(int32_t(ui)); + } - uint32_t toPrivateUint32() const { - return uint32_t(toInt32()); - } + uint32_t toPrivateUint32() const { return uint32_t(toInt32()); } + + /* + * 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 isGCThing(), and + * as such, automatically marked. Their traceKind() is gotten via their + * cells. + */ - /* - * 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 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."); + 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); + MOZ_ASSERT(js::gc::IsCellPointerValid(cell)); #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); + // 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)); - } + data.asBits = + bitsFromTagAndPayload(JSVAL_TAG_PRIVATE_GCTHING, PayloadType(cell)); + } - bool isPrivateGCThing() const { - return toTag() == JSVAL_TAG_PRIVATE_GCTHING; - } + bool isPrivateGCThing() const { return toTag() == JSVAL_TAG_PRIVATE_GCTHING; } - const size_t* payloadWord() const { + const size_t* payloadWord() const { #if defined(JS_NUNBOX32) - return &data.s.payload.word; + return &data.s.payload.word; #elif defined(JS_PUNBOX64) - return &data.asWord; + return &data.asWord; #endif - } + } - const uintptr_t* payloadUIntPtr() const { + const uintptr_t* payloadUIntPtr() const { #if defined(JS_NUNBOX32) - return &data.s.payload.uintptr; + return &data.s.payload.uintptr; #elif defined(JS_PUNBOX64) - return &data.asUIntPtr; + return &data.asUIntPtr; #endif - } + } #if !defined(_MSC_VER) && !defined(__sparc) // Value must be POD so that MSVC will pass it by value and not in memory // (bug 689101); the same is true for SPARC as well (bug 737344). More // precisely, we don't want Value return values compiled as out params. - private: + private: #endif #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(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: - explicit constexpr Value(uint64_t asBits) : data(asBits) {} - explicit constexpr Value(double d) : data(d) {} - - void staticAssertions() { - JS_STATIC_ASSERT(sizeof(JSValueType) == 1); - JS_STATIC_ASSERT(sizeof(JSValueTag) == 4); - JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4); - JS_STATIC_ASSERT(sizeof(Value) == 8); - } + /* 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: + explicit constexpr Value(uint64_t asBits) : data(asBits) {} + explicit constexpr Value(double d) : data(d) {} + + void staticAssertions() { + JS_STATIC_ASSERT(sizeof(JSValueType) == 1); + JS_STATIC_ASSERT(sizeof(JSValueTag) == 4); + JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4); + JS_STATIC_ASSERT(sizeof(Value) == 8); + } - friend constexpr Value JS::UndefinedValue(); + friend constexpr Value JS::UndefinedValue(); - public: - static constexpr uint64_t - bitsFromTagAndPayload(JSValueTag tag, PayloadType payload) - { + public: + static constexpr uint64_t bitsFromTagAndPayload(JSValueTag tag, + PayloadType payload) { #if defined(JS_NUNBOX32) - return (uint64_t(uint32_t(tag)) << 32) | payload; + return (uint64_t(uint32_t(tag)) << 32) | payload; #elif defined(JS_PUNBOX64) - return (uint64_t(uint32_t(tag)) << JSVAL_TAG_SHIFT) | payload; + 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 fromTagAndPayload(JSValueTag tag, + PayloadType payload) { + return fromRawBits(bitsFromTagAndPayload(tag, payload)); + } - static constexpr Value - fromRawBits(uint64_t asBits) { - return Value(asBits); - } + 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 fromInt32(int32_t i) { + return fromTagAndPayload(JSVAL_TAG_INT32, uint32_t(i)); + } - static constexpr Value - fromDouble(double d) { - return Value(d); - } + 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); - } +struct MOZ_NON_PARAM alignas(8) UninitializedValue { + private: + uint64_t bits; - inline operator Value&() { - return asValueRef(); - } - inline operator Value const&() const { - return asValueRef(); - } - inline operator Value() const { - return asValueRef(); - } + 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; - } + 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) -{ - if (v.isMagic()) { - MOZ_ASSERT(v.whyMagic() == JS_OPTIMIZED_ARGUMENTS || v.whyMagic() == JS_OPTIMIZED_OUT); - return true; - } - return false; -} - -static MOZ_ALWAYS_INLINE void -ExposeValueToActiveJS(const Value& v) -{ - if (v.isMarkable()) - js::gc::ExposeGCThingToActiveJS(GCCellPtr(v)); +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) { + if (v.isMagic()) { + MOZ_ASSERT(v.whyMagic() == JS_OPTIMIZED_ARGUMENTS || + v.whyMagic() == JS_OPTIMIZED_OUT); + return true; + } + return false; +} + +static MOZ_ALWAYS_INLINE void ExposeValueToActiveJS(const Value& v) { +#ifdef DEBUG + Value tmp = v; + MOZ_ASSERT(!js::gc::EdgeNeedsSweepUnbarrieredSlow(&tmp)); +#endif + if (v.isGCThing()) js::gc::ExposeGCThingToActiveJS(GCCellPtr(v)); } /************************************************************************/ -static inline Value -NullValue() -{ - Value v; - v.setNull(); - return v; +static inline MOZ_MAY_CALL_AFTER_MUST_RETURN Value NullValue() { + Value v; + v.setNull(); + return v; } -static inline constexpr Value -UndefinedValue() -{ - return Value::fromTagAndPayload(JSVAL_TAG_UNDEFINED, 0); +static inline constexpr Value UndefinedValue() { + return Value::fromTagAndPayload(JSVAL_TAG_UNDEFINED, 0); } -static inline constexpr Value -Int32Value(int32_t i32) -{ - return Value::fromInt32(i32); +static inline constexpr Value Int32Value(int32_t i32) { + return Value::fromInt32(i32); } -static inline Value -DoubleValue(double dbl) -{ - Value v; - v.setDouble(dbl); - return v; +static inline Value DoubleValue(double dbl) { + Value v; + v.setDouble(dbl); + return v; } -static inline Value -CanonicalizedDoubleValue(double d) -{ - return MOZ_UNLIKELY(mozilla::IsNaN(d)) - ? Value::fromRawBits(detail::CanonicalizedNaNBits) - : Value::fromDouble(d); +static inline Value CanonicalizedDoubleValue(double d) { + 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; +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; + return (bits & ~mozilla::DoubleTypeTraits::kSignBit) == + detail::CanonicalizedNaNBits; } -static inline Value -DoubleNaNValue() -{ - Value v; - v.setNaN(); - return v; +static inline Value DoubleNaNValue() { + Value v; + v.setNaN(); + return v; } -static inline Value -Float32Value(float f) -{ - Value v; - v.setDouble(f); - return v; +static inline Value Float32Value(float f) { + Value v; + v.setDouble(f); + return v; } -static inline Value -StringValue(JSString* str) -{ - Value v; - v.setString(str); - return v; +static inline Value StringValue(JSString* str) { + Value v; + v.setString(str); + return v; } -static inline Value -SymbolValue(JS::Symbol* sym) -{ - Value v; - v.setSymbol(sym); - return v; +static inline Value SymbolValue(JS::Symbol* sym) { + Value v; + v.setSymbol(sym); + return v; } -static inline Value -BooleanValue(bool boo) -{ - Value v; - v.setBoolean(boo); - return v; +static inline Value BooleanValue(bool boo) { + Value v; + v.setBoolean(boo); + return v; } -static inline Value -TrueValue() -{ - Value v; - v.setBoolean(true); - return v; +static inline Value TrueValue() { + Value v; + v.setBoolean(true); + return v; } -static inline Value -FalseValue() -{ - Value v; - v.setBoolean(false); - return v; +static inline Value FalseValue() { + Value v; + v.setBoolean(false); + return v; } -static inline Value -ObjectValue(JSObject& obj) -{ - Value v; - v.setObject(obj); - return v; +static inline Value ObjectValue(JSObject& obj) { + Value v; + v.setObject(obj); + return v; } -static inline Value -ObjectValueCrashOnTouch() -{ - Value v; - v.setObject(*reinterpret_cast(0x48)); - return v; +static inline Value MagicValue(JSWhyMagic why) { + Value v; + v.setMagic(why); + return v; } -static inline Value -MagicValue(JSWhyMagic why) -{ - Value v; - v.setMagic(why); - return v; +static inline Value MagicValueUint32(uint32_t payload) { + Value v; + v.setMagicUint32(payload); + return v; } -static inline Value -MagicValueUint32(uint32_t payload) -{ - Value v; - v.setMagicUint32(payload); - return v; +static inline Value NumberValue(float f) { + Value v; + v.setNumber(f); + return v; } -static inline Value -NumberValue(float f) -{ - Value v; - v.setNumber(f); - return v; +static inline Value NumberValue(double dbl) { + Value v; + v.setNumber(dbl); + return v; } -static inline Value -NumberValue(double dbl) -{ - Value v; - v.setNumber(dbl); - return v; -} +static inline Value NumberValue(int8_t i) { return Int32Value(i); } -static inline Value -NumberValue(int8_t i) -{ - return Int32Value(i); -} +static inline Value NumberValue(uint8_t i) { return Int32Value(i); } -static inline Value -NumberValue(uint8_t i) -{ - return Int32Value(i); -} +static inline Value NumberValue(int16_t i) { return Int32Value(i); } -static inline Value -NumberValue(int16_t i) -{ - return Int32Value(i); -} +static inline Value NumberValue(uint16_t i) { return Int32Value(i); } -static inline Value -NumberValue(uint16_t i) -{ - return Int32Value(i); -} +static inline Value NumberValue(int32_t i) { return Int32Value(i); } -static inline Value -NumberValue(int32_t i) -{ - return Int32Value(i); -} - -static inline constexpr Value -NumberValue(uint32_t i) -{ - return i <= JSVAL_INT_MAX - ? Int32Value(int32_t(i)) - : Value::fromDouble(double(i)); +static inline constexpr Value NumberValue(uint32_t i) { + return i <= JSVAL_INT_MAX ? Int32Value(int32_t(i)) + : Value::fromDouble(double(i)); } namespace detail { template -class MakeNumberValue -{ - public: - template - static inline Value create(const T t) - { - Value v; - if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX) - v.setInt32(int32_t(t)); - else - v.setDouble(double(t)); - return v; - } +class MakeNumberValue { + public: + template + static inline Value create(const T t) { + Value v; + if (JSVAL_INT_MIN <= t && t <= JSVAL_INT_MAX) + v.setInt32(int32_t(t)); + else + v.setDouble(double(t)); + return v; + } }; template <> -class MakeNumberValue -{ - public: - template - static inline Value create(const T t) - { - Value v; - if (t <= JSVAL_INT_MAX) - v.setInt32(int32_t(t)); - else - v.setDouble(double(t)); - return v; - } +class MakeNumberValue { + public: + template + static inline Value create(const T t) { + Value v; + if (t <= JSVAL_INT_MAX) + v.setInt32(int32_t(t)); + else + v.setDouble(double(t)); + return v; + } }; -} // namespace detail +} // namespace detail template -static inline Value -NumberValue(const T t) -{ - MOZ_ASSERT(Value::isNumberRepresentable(t), "value creation would be lossy"); - return detail::MakeNumberValue::is_signed>::create(t); +static inline Value NumberValue(const T t) { + MOZ_ASSERT(Value::isNumberRepresentable(t), "value creation would be lossy"); + return detail::MakeNumberValue::is_signed>::create(t); } -static inline Value -ObjectOrNullValue(JSObject* obj) -{ - Value v; - v.setObjectOrNull(obj); - return v; +static inline Value ObjectOrNullValue(JSObject* obj) { + Value v; + v.setObjectOrNull(obj); + return v; } -static inline Value -PrivateValue(void* ptr) -{ - Value v; - v.setPrivate(ptr); - return v; +static inline Value PrivateValue(void* ptr) { + Value v; + v.setPrivate(ptr); + return v; } -static inline Value -PrivateUint32Value(uint32_t ui) -{ - Value v; - v.setPrivateUint32(ui); - return v; +static inline Value PrivateUint32Value(uint32_t ui) { + Value v; + v.setPrivateUint32(ui); + return v; } -static inline Value -PrivateGCThingValue(js::gc::Cell* cell) -{ - Value v; - v.setPrivateGCThing(cell); - 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) -{ +inline bool SameType(const Value& lhs, const Value& rhs) { #if defined(JS_NUNBOX32) - JSValueTag ltag = lhs.toTag(), rtag = rhs.toTag(); - return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR); + 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); + return (lhs.isDouble() && rhs.isDouble()) || + (((lhs.data.asBits ^ rhs.data.asBits) & 0xFFFF800000000000ULL) == 0); #endif } -} // namespace JS +} // namespace JS /************************************************************************/ namespace JS { -JS_PUBLIC_API(void) HeapValuePostBarrier(Value* valuep, const Value& prev, const Value& next); +JS_PUBLIC_API void HeapValuePostBarrier(Value* valuep, const Value& prev, + const Value& next); template <> -struct GCPolicy -{ - 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()); - } +struct GCPolicy { + 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()); + } + static bool isValid(const Value& value) { + return !value.isGCThing() || js::gc::IsCellPointerValid(value.toGCThing()); + } }; -} // namespace JS +} // namespace JS namespace js { template <> -struct BarrierMethods -{ - 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); - } +struct BarrierMethods { + static gc::Cell* asGCThingOrNull(const JS::Value& v) { + return v.isGCThing() ? 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; +template +class MutableValueOperations; /** * A class designed for CRTP use in implementing the non-mutating parts of the - * Value interface in Value-like classes. Outer must be a class inheriting - * ValueOperations with a visible get() method returning a const - * reference to the Value abstracted by Outer. + * Value interface in Value-like classes. Wrapper must be a class inheriting + * ValueOperations with a visible get() method returning a const + * reference to the Value abstracted by Wrapper. */ -template -class ValueOperations -{ - friend class MutableValueOperations; - - const JS::Value& value() const { return static_cast(this)->get(); } - - public: - bool isUndefined() const { return value().isUndefined(); } - bool isNull() const { return value().isNull(); } - bool isBoolean() const { return value().isBoolean(); } - bool isTrue() const { return value().isTrue(); } - bool isFalse() const { return value().isFalse(); } - bool isNumber() const { return value().isNumber(); } - bool isInt32() const { return value().isInt32(); } - bool isInt32(int32_t i32) const { return value().isInt32(i32); } - bool isDouble() const { return value().isDouble(); } - bool isString() const { return value().isString(); } - bool isSymbol() const { return value().isSymbol(); } - bool isObject() const { return value().isObject(); } - bool isMagic() const { return value().isMagic(); } - bool isMagic(JSWhyMagic why) const { return value().isMagic(why); } - bool isMarkable() const { return value().isMarkable(); } - bool isPrimitive() const { return value().isPrimitive(); } - bool isGCThing() const { return value().isGCThing(); } - - bool isNullOrUndefined() const { return value().isNullOrUndefined(); } - bool isObjectOrNull() const { return value().isObjectOrNull(); } - - bool toBoolean() const { return value().toBoolean(); } - double toNumber() const { return value().toNumber(); } - int32_t toInt32() const { return value().toInt32(); } - double toDouble() const { return value().toDouble(); } - JSString* toString() const { return value().toString(); } - JS::Symbol* toSymbol() const { return value().toSymbol(); } - JSObject& toObject() const { return value().toObject(); } - JSObject* toObjectOrNull() const { return value().toObjectOrNull(); } - gc::Cell* toGCThing() const { return value().toGCThing(); } - JS::TraceKind traceKind() const { return value().traceKind(); } - 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(); } +template +class WrappedPtrOperations { + const JS::Value& value() const { + return static_cast(this)->get(); + } + + public: + bool isUndefined() const { return value().isUndefined(); } + bool isNull() const { return value().isNull(); } + bool isBoolean() const { return value().isBoolean(); } + bool isTrue() const { return value().isTrue(); } + bool isFalse() const { return value().isFalse(); } + bool isNumber() const { return value().isNumber(); } + bool isInt32() const { return value().isInt32(); } + bool isInt32(int32_t i32) const { return value().isInt32(i32); } + bool isDouble() const { return value().isDouble(); } + bool isString() const { return value().isString(); } + bool isSymbol() const { return value().isSymbol(); } + bool isObject() const { return value().isObject(); } + bool isMagic() const { return value().isMagic(); } + bool isMagic(JSWhyMagic why) const { return value().isMagic(why); } + bool isGCThing() const { return value().isGCThing(); } + bool isPrimitive() const { return value().isPrimitive(); } + + bool isNullOrUndefined() const { return value().isNullOrUndefined(); } + bool isObjectOrNull() const { return value().isObjectOrNull(); } + + bool toBoolean() const { return value().toBoolean(); } + double toNumber() const { return value().toNumber(); } + int32_t toInt32() const { return value().toInt32(); } + double toDouble() const { return value().toDouble(); } + JSString* toString() const { return value().toString(); } + JS::Symbol* toSymbol() const { return value().toSymbol(); } + JSObject& toObject() const { return value().toObject(); } + JSObject* toObjectOrNull() const { return value().toObjectOrNull(); } + gc::Cell* toGCThing() const { return value().toGCThing(); } + JS::TraceKind traceKind() const { return value().traceKind(); } + 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(); + } - JSWhyMagic whyMagic() const { return value().whyMagic(); } - uint32_t magicUint32() const { return value().magicUint32(); } + JSWhyMagic whyMagic() const { return value().whyMagic(); } + uint32_t magicUint32() const { return value().magicUint32(); } }; /** * A class designed for CRTP use in implementing all the mutating parts of the - * Value interface in Value-like classes. Outer must be a class inheriting - * MutableValueOperations with visible get() methods returning const and - * non-const references to the Value abstracted by Outer. + * Value interface in Value-like classes. Wrapper must be a class inheriting + * MutableWrappedPtrOperations with visible get() methods returning + * const and non-const references to the Value abstracted by Wrapper. */ -template -class MutableValueOperations : public ValueOperations -{ - JS::Value& value() { return static_cast(this)->get(); } - - public: - void setNull() { value().setNull(); } - void setUndefined() { value().setUndefined(); } - void setInt32(int32_t i) { value().setInt32(i); } - void setDouble(double d) { value().setDouble(d); } - void setNaN() { setDouble(JS::GenericNaN()); } - void setBoolean(bool b) { value().setBoolean(b); } - void setMagic(JSWhyMagic why) { value().setMagic(why); } - bool setNumber(uint32_t ui) { return value().setNumber(ui); } - bool setNumber(double d) { return value().setNumber(d); } - void setString(JSString* str) { this->value().setString(str); } - 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); } +template +class MutableWrappedPtrOperations + : public WrappedPtrOperations { + JS::Value& value() { return static_cast(this)->get(); } + + public: + void setNull() { value().setNull(); } + void setUndefined() { value().setUndefined(); } + void setInt32(int32_t i) { value().setInt32(i); } + void setDouble(double d) { value().setDouble(d); } + void setNaN() { setDouble(JS::GenericNaN()); } + void setBoolean(bool b) { value().setBoolean(b); } + void setMagic(JSWhyMagic why) { value().setMagic(why); } + bool setNumber(uint32_t ui) { return value().setNumber(ui); } + bool setNumber(double d) { return value().setNumber(d); } + void setString(JSString* str) { this->value().setString(str); } + 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); + } }; /* * Augment the generic Heap interface when T = Value with * type-querying, value-extracting, and mutating operations. */ -template <> -class HeapBase : public ValueOperations > -{ - typedef JS::Heap Outer; - - friend class ValueOperations; - - void setBarriered(const JS::Value& v) { - *static_cast*>(this) = v; +template +class HeapBase + : public WrappedPtrOperations { + void setBarriered(const JS::Value& v) { + *static_cast*>(this) = v; + } + + public: + void setNull() { setBarriered(JS::NullValue()); } + void setUndefined() { setBarriered(JS::UndefinedValue()); } + void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); } + void setDouble(double d) { setBarriered(JS::DoubleValue(d)); } + void setNaN() { setDouble(JS::GenericNaN()); } + void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); } + void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); } + 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) { + setDouble((double)ui); + return false; + } else { + setInt32((int32_t)ui); + return true; } + } - public: - void setNull() { setBarriered(JS::NullValue()); } - void setUndefined() { setBarriered(JS::UndefinedValue()); } - void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); } - void setDouble(double d) { setBarriered(JS::DoubleValue(d)); } - void setNaN() { setDouble(JS::GenericNaN()); } - void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); } - void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); } - 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) { - setDouble((double)ui); - return false; - } else { - setInt32((int32_t)ui); - return true; - } + bool setNumber(double d) { + int32_t i; + if (mozilla::NumberIsInt32(d, &i)) { + setInt32(i); + return true; } - bool setNumber(double d) { - int32_t i; - if (mozilla::NumberIsInt32(d, &i)) { - setInt32(i); - return true; - } - - setDouble(d); - return false; - } + setDouble(d); + return false; + } - void setObjectOrNull(JSObject* arg) { - if (arg) - setObject(*arg); - else - setNull(); - } + void setObjectOrNull(JSObject* arg) { + if (arg) + setObject(*arg); + else + setNull(); + } }; -template <> -class HandleBase : public ValueOperations > -{}; - -template <> -class MutableHandleBase : public MutableValueOperations > -{}; - -template <> -class RootedBase : public MutableValueOperations > -{}; - -template <> -class PersistentRootedBase : public MutableValueOperations> -{}; - /* * If the Value is a GC pointer type, convert to that type and call |f| with * the pointer. If the Value is not a GC type, calls F::defaultValue. */ template -auto -DispatchTyped(F f, const JS::Value& val, Args&&... args) - -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) -{ - if (val.isString()) - return f(val.toString(), mozilla::Forward(args)...); - if (val.isObject()) - 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(const S&) {} }; -template struct IdentityDefaultAdaptor { static S defaultValue(const S& v) {return v;} }; -template struct BoolDefaultAdaptor { static bool defaultValue(const S&) { return v; } }; +auto DispatchTyped(F f, const JS::Value& val, Args&&... args) + -> decltype(f(static_cast(nullptr), + mozilla::Forward(args)...)) { + if (val.isString()) { + JSString* str = val.toString(); + MOZ_ASSERT(gc::IsCellPointerValid(str)); + return f(str, mozilla::Forward(args)...); + } + if (val.isObject()) { + JSObject* obj = &val.toObject(); + MOZ_ASSERT(gc::IsCellPointerValid(obj)); + return f(obj, mozilla::Forward(args)...); + } + if (val.isSymbol()) { + JS::Symbol* sym = val.toSymbol(); + MOZ_ASSERT(gc::IsCellPointerValid(sym)); + return f(sym, mozilla::Forward(args)...); + } + if (MOZ_UNLIKELY(val.isPrivateGCThing())) { + MOZ_ASSERT(gc::IsCellPointerValid(val.toGCThing())); + return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward(args)...); + } + MOZ_ASSERT(!val.isGCThing()); + return F::defaultValue(val); +} + +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(const S&) { return v; } +}; + +static inline JS::Value PoisonedObjectValue(uintptr_t poison) { + JS::Value v; + v.setObjectNoCheck(reinterpret_cast(poison)); + return v; +} + +} // namespace js + +#ifdef DEBUG +namespace JS { + +MOZ_ALWAYS_INLINE bool ValueIsNotGray(const Value& value) { + if (!value.isGCThing()) return true; + + return CellIsNotGray(value.toGCThing()); +} -} // namespace js +MOZ_ALWAYS_INLINE bool ValueIsNotGray(const Heap& value) { + return ValueIsNotGray(value.unbarrieredGet()); +} + +} // namespace JS +#endif /************************************************************************/ namespace JS { -extern JS_PUBLIC_DATA(const HandleValue) NullHandleValue; -extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue; -extern JS_PUBLIC_DATA(const HandleValue) TrueHandleValue; -extern JS_PUBLIC_DATA(const HandleValue) FalseHandleValue; +extern JS_PUBLIC_DATA const HandleValue NullHandleValue; +extern JS_PUBLIC_DATA const HandleValue UndefinedHandleValue; +extern JS_PUBLIC_DATA const HandleValue TrueHandleValue; +extern JS_PUBLIC_DATA const HandleValue FalseHandleValue; -} // namespace JS +} // namespace JS #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 @@ -9,12 +9,6 @@ #include "mozilla/Vector.h" -/* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */ -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4345) -#endif - namespace js { class TempAllocPolicy; @@ -22,24 +16,22 @@ namespace detail { template -struct TypeIsGCThing : mozilla::FalseType -{}; +struct TypeIsGCThing : mozilla::FalseType {}; // Uncomment this once we actually can assert it: -//template <> -//struct TypeIsGCThing : mozilla::TrueType +// template <> +// struct TypeIsGCThing : mozilla::TrueType //{}; -} // namespace detail +} // namespace detail -template ::value>::Type - > + // Don't use this with JS::Value! Use JS::AutoValueVector instead. + typename = typename mozilla::EnableIf< + !detail::TypeIsGCThing::value>::Type> using Vector = mozilla::Vector; -} // namespace js +} // namespace js #endif /* js_Vector_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/WeakMapPtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/WeakMapPtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/WeakMapPtr.h @@ -16,31 +16,31 @@ // A wrapper around the internal C++ representation of SpiderMonkey WeakMaps, // usable outside the engine. // -// The supported template specializations are enumerated in WeakMapPtr.cpp. If -// you want to use this class for a different key/value combination, add it to -// the list and the compiler will generate the relevant machinery. +// The supported template specializations are enumerated in gc/WeakMapPtr.cpp. +// If you want to use this class for a different key/value combination, add it +// to the list and the compiler will generate the relevant machinery. template -class JS_PUBLIC_API(WeakMapPtr) -{ - public: - WeakMapPtr() : ptr(nullptr) {} - bool init(JSContext* cx); - bool initialized() { return ptr != nullptr; } - void destroy(); - virtual ~WeakMapPtr() { MOZ_ASSERT(!initialized()); } - void trace(JSTracer* tracer); - - V lookup(const K& key); - bool put(JSContext* cx, const K& key, const V& value); - - private: - void* ptr; - - // WeakMapPtr is neither copyable nor assignable. - WeakMapPtr(const WeakMapPtr& wmp) = delete; - WeakMapPtr& operator=(const WeakMapPtr& wmp) = delete; +class JS_PUBLIC_API WeakMapPtr { + public: + WeakMapPtr() : ptr(nullptr) {} + bool init(JSContext* cx); + bool initialized() { return ptr != nullptr; } + void destroy(); + virtual ~WeakMapPtr() { MOZ_ASSERT(!initialized()); } + void trace(JSTracer* tracer); + + V lookup(const K& key); + bool put(JSContext* cx, const K& key, const V& value); + V removeValue(const K& key); + + private: + void* ptr; + + // WeakMapPtr is neither copyable nor assignable. + WeakMapPtr(const WeakMapPtr& wmp) = delete; + WeakMapPtr& operator=(const WeakMapPtr& wmp) = delete; }; } /* namespace JS */ -#endif /* js_WeakMapPtr_h */ +#endif /* js_WeakMapPtr_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Wrapper.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Wrapper.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/js/Wrapper.h @@ -0,0 +1,426 @@ +/* -*- 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_Wrapper_h +#define js_Wrapper_h + +#include "mozilla/Attributes.h" + +#include "js/Proxy.h" + +namespace js { + +/* + * Helper for Wrapper::New default options. + * + * Callers of Wrapper::New() who wish to specify a prototype for the created + * Wrapper, *MUST* construct a WrapperOptions with a JSContext. + */ +class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions { + public: + WrapperOptions() : ProxyOptions(false), proto_() {} + + explicit WrapperOptions(JSContext* cx) : ProxyOptions(false), proto_() { + proto_.emplace(cx); + } + + inline JSObject* proto() const; + WrapperOptions& setProto(JSObject* protoArg) { + MOZ_ASSERT(proto_); + *proto_ = protoArg; + return *this; + } + + private: + mozilla::Maybe proto_; +}; + +// Base class for proxy handlers that want to forward all operations to an +// object stored in the proxy's private slot. +class JS_FRIEND_API ForwardingProxyHandler : public BaseProxyHandler { + public: + using BaseProxyHandler::BaseProxyHandler; + + /* 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 JSObject* enumerate(JSContext* cx, HandleObject proxy) 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, + bool isToSource) const override; + virtual RegExpShared* regexp_toShared(JSContext* cx, + HandleObject proxy) 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; +}; + +/* + * A wrapper is a proxy with a target object to which it generally forwards + * 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 ForwardingProxyHandler { + unsigned mFlags; + + public: + explicit constexpr Wrapper(unsigned aFlags, bool aHasPrototype = false, + bool aHasSecurityPolicy = false) + : ForwardingProxyHandler(&family, aHasPrototype, aHasSecurityPolicy), + mFlags(aFlags) {} + + virtual bool finalizeInBackground(const Value& priv) const override; + virtual JSObject* weakmapKeyDelegate(JSObject* proxy) const override; + + using BaseProxyHandler::Action; + + enum Flags { CROSS_COMPARTMENT = 1 << 0, LAST_USED_FLAG = CROSS_COMPARTMENT }; + + static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler, + const WrapperOptions& options = WrapperOptions()); + + static JSObject* Renew(JSObject* existing, JSObject* obj, + const Wrapper* handler); + + static const Wrapper* wrapperHandler(JSObject* wrapper); + + static JSObject* wrappedObject(JSObject* wrapper); + + unsigned flags() const { return mFlags; } + + static const char family; + static const Wrapper singleton; + static const Wrapper singletonWithPrototype; + + static JSObject* defaultProto; +}; + +inline JSObject* WrapperOptions::proto() const { + return proto_ ? *proto_ : Wrapper::defaultProto; +} + +/* Base class for all cross compartment wrapper handlers. */ +class JS_FRIEND_API CrossCompartmentWrapper : public Wrapper { + public: + 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; + virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, + Handle desc, + ObjectOpResult& result) const override; + virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper, + AutoIdVector& props) const override; + virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id, + ObjectOpResult& result) const override; + virtual JSObject* enumerate(JSContext* cx, + HandleObject wrapper) 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 wrapper, + ObjectOpResult& result) const override; + virtual bool isExtensible(JSContext* cx, HandleObject wrapper, + bool* extensible) const override; + virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id, + bool* bp) const override; + virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver, + HandleId id, MutableHandleValue vp) const override; + virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, + HandleValue v, HandleValue receiver, + ObjectOpResult& result) const override; + virtual bool call(JSContext* cx, HandleObject wrapper, + const CallArgs& args) const override; + virtual bool construct(JSContext* cx, HandleObject wrapper, + const CallArgs& args) const override; + + /* SpiderMonkey extensions. */ + virtual bool getPropertyDescriptor( + JSContext* cx, HandleObject wrapper, HandleId id, + 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 nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, + const CallArgs& args) const override; + virtual bool hasInstance(JSContext* cx, HandleObject wrapper, + MutableHandleValue v, bool* bp) const override; + virtual const char* className(JSContext* cx, + HandleObject proxy) const override; + virtual JSString* fun_toString(JSContext* cx, HandleObject wrapper, + bool isToSource) const override; + virtual RegExpShared* regexp_toShared(JSContext* cx, + HandleObject proxy) 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; +}; + +class JS_FRIEND_API OpaqueCrossCompartmentWrapper + : public CrossCompartmentWrapper { + public: + explicit constexpr OpaqueCrossCompartmentWrapper() + : CrossCompartmentWrapper(0) {} + + /* Standard internal methods. */ + virtual bool getOwnPropertyDescriptor( + JSContext* cx, HandleObject wrapper, HandleId id, + MutableHandle desc) const override; + virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, + Handle desc, + ObjectOpResult& result) const override; + virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper, + AutoIdVector& props) const override; + virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id, + ObjectOpResult& result) const override; + virtual JSObject* enumerate(JSContext* cx, + HandleObject wrapper) const override; + virtual bool getPrototype(JSContext* cx, HandleObject wrapper, + 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, + ObjectOpResult& result) const override; + virtual bool isExtensible(JSContext* cx, HandleObject wrapper, + bool* extensible) const override; + virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id, + bool* bp) const override; + virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver, + HandleId id, MutableHandleValue vp) const override; + virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, + HandleValue v, HandleValue receiver, + ObjectOpResult& result) const override; + virtual bool call(JSContext* cx, HandleObject wrapper, + const CallArgs& args) const override; + virtual bool construct(JSContext* cx, HandleObject wrapper, + const CallArgs& args) const override; + + /* SpiderMonkey extensions. */ + virtual bool getPropertyDescriptor( + JSContext* cx, HandleObject wrapper, HandleId id, + 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, + 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; + virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, + bool isToSource) const override; + + static const OpaqueCrossCompartmentWrapper singleton; +}; + +/* + * Base class for security wrappers. A security wrapper is potentially hiding + * all or part of some wrapped object thus SecurityWrapper defaults to denying + * access to the wrappee. This is the opposite of Wrapper which tries to be + * completely transparent. + * + * NB: Currently, only a few ProxyHandler operations are overridden to deny + * access, relying on derived SecurityWrapper to block access when necessary. + */ +template +class JS_FRIEND_API SecurityWrapper : public Base { + public: + explicit constexpr SecurityWrapper(unsigned flags, bool hasPrototype = false) + : Base(flags, hasPrototype, /* hasSecurityPolicy = */ true) {} + + virtual bool enter(JSContext* cx, HandleObject wrapper, HandleId id, + Wrapper::Action act, bool mayThrow, + bool* bp) const override; + + virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, + Handle desc, + ObjectOpResult& result) const override; + virtual bool isExtensible(JSContext* cx, HandleObject wrapper, + bool* extensible) const override; + virtual bool preventExtensions(JSContext* cx, HandleObject wrapper, + ObjectOpResult& result) 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 nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, + const CallArgs& args) 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 RegExpShared* regexp_toShared(JSContext* cx, + HandleObject proxy) const override; + virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy, + MutableHandleValue vp) const override; + + // Allow isCallable and isConstructor. They used to be class-level, and so + // could not be guarded against. + + /* + * Allow our subclasses to select the superclass behavior they want without + * needing to specify an exact superclass. + */ + typedef Base Permissive; + typedef SecurityWrapper Restrictive; +}; + +typedef SecurityWrapper + CrossCompartmentSecurityWrapper; + +extern JSObject* TransparentObjectWrapper(JSContext* cx, HandleObject existing, + HandleObject obj); + +inline bool IsWrapper(JSObject* obj) { + return IsProxy(obj) && GetProxyHandler(obj)->family() == &Wrapper::family; +} + +// Given a JSObject, returns that object stripped of wrappers. If +// stopAtWindowProxy is true, then this returns the WindowProxy if it was +// previously wrapped. Otherwise, this returns the first object for which +// JSObject::isWrapper returns false. +// +// ExposeToActiveJS is called on wrapper targets to allow gray marking +// assertions to work while an incremental GC is in progress, but this means +// that this cannot be called from the GC or off the main thread. +JS_FRIEND_API JSObject* UncheckedUnwrap(JSObject* obj, + bool stopAtWindowProxy = true, + unsigned* flagsp = nullptr); + +// Given a JSObject, returns that object stripped of wrappers. At each stage, +// the security wrapper has the opportunity to veto the unwrap. If +// stopAtWindowProxy is true, then this returns the WindowProxy if it was +// previously wrapped. +// +// ExposeToActiveJS is called on wrapper targets to allow gray marking +// assertions to work while an incremental GC is in progress, but this means +// that this cannot be called from the GC or off the main thread. +JS_FRIEND_API JSObject* CheckedUnwrap(JSObject* obj, + bool stopAtWindowProxy = true); + +// Unwrap only the outermost security wrapper, with the same semantics as +// above. This is the checked version of Wrapper::wrappedObject. +JS_FRIEND_API JSObject* UnwrapOneChecked(JSObject* obj, + bool stopAtWindowProxy = true); + +// Given a JSObject, returns that object stripped of wrappers. This returns the +// WindowProxy if it was previously wrapped. +// +// ExposeToActiveJS is not called on wrapper targets so this can be called from +// the GC or off the main thread. +JS_FRIEND_API JSObject* UncheckedUnwrapWithoutExpose(JSObject* obj); + +void ReportAccessDenied(JSContext* cx); + +JS_FRIEND_API bool IsCrossCompartmentWrapper(JSObject* obj); + +JS_FRIEND_API void NukeCrossCompartmentWrapper(JSContext* cx, + JSObject* wrapper); + +void RemapWrapper(JSContext* cx, JSObject* wobj, JSObject* newTarget); + +JS_FRIEND_API bool RemapAllWrappersForObject(JSContext* cx, JSObject* oldTarget, + JSObject* newTarget); + +// API to recompute all cross-compartment wrappers whose source and target +// match the given filters. +JS_FRIEND_API bool RecomputeWrappers(JSContext* cx, + const CompartmentFilter& sourceFilter, + const CompartmentFilter& targetFilter); + +} /* namespace js */ + +#endif /* js_Wrapper_h */ 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 @@ -1,145 +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/. */ - -/* - * JS allocation policies. - * - * The allocators here are for system memory with lifetimes which are not - * managed by the GC. See the comment at the top of vm/MallocProvider.h. - */ - -#ifndef jsalloc_h -#define jsalloc_h - -#include "js/TypeDecls.h" -#include "js/Utility.h" - -extern JS_PUBLIC_API(void) JS_ReportOutOfMemory(JSContext* cx); - -namespace js { - -enum class AllocFunction { - Malloc, - Calloc, - Realloc -}; - -struct ContextFriendFields; - -/* Policy for using system memory functions and doing no error reporting. */ -class SystemAllocPolicy -{ - public: - template T* maybe_pod_malloc(size_t numElems) { return js_pod_malloc(numElems); } - template T* maybe_pod_calloc(size_t numElems) { return js_pod_calloc(numElems); } - template T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) { - return js_pod_realloc(p, oldSize, newSize); - } - template T* pod_malloc(size_t numElems) { return maybe_pod_malloc(numElems); } - template T* pod_calloc(size_t numElems) { return maybe_pod_calloc(numElems); } - template T* pod_realloc(T* p, size_t oldSize, size_t newSize) { - return maybe_pod_realloc(p, oldSize, newSize); - } - void free_(void* p) { js_free(p); } - void reportAllocOverflow() const {} - bool checkSimulatedOOM() const { - return !js::oom::ShouldFailWithOOM(); - } -}; - -class ExclusiveContext; -JS_FRIEND_API(void) ReportOutOfMemory(ExclusiveContext* cxArg); - -/* - * Allocation policy that calls the system memory functions and reports errors - * to the context. Since the JSContext given on construction is stored for - * the lifetime of the container, this policy may only be used for containers - * whose lifetime is a shorter than the given JSContext. - * - * FIXME bug 647103 - rewrite this in terms of temporary allocation functions, - * not the system ones. - */ -class TempAllocPolicy -{ - ContextFriendFields* const cx_; - - /* - * Non-inline helper to call JSRuntime::onOutOfMemory with minimal - * code bloat. - */ - JS_FRIEND_API(void*) onOutOfMemory(AllocFunction allocFunc, size_t nbytes, - void* reallocPtr = nullptr); - - template - T* onOutOfMemoryTyped(AllocFunction allocFunc, size_t numElems, void* reallocPtr = nullptr) { - size_t bytes; - if (MOZ_UNLIKELY(!CalculateAllocSize(numElems, &bytes))) - return nullptr; - return static_cast(onOutOfMemory(allocFunc, bytes, reallocPtr)); - } - - public: - MOZ_IMPLICIT TempAllocPolicy(JSContext* cx) : cx_((ContextFriendFields*) cx) {} // :( - MOZ_IMPLICIT TempAllocPolicy(ContextFriendFields* cx) : cx_(cx) {} - - template - T* maybe_pod_malloc(size_t numElems) { - return js_pod_malloc(numElems); - } - - template - T* maybe_pod_calloc(size_t numElems) { - return js_pod_calloc(numElems); - } - - template - T* maybe_pod_realloc(T* prior, size_t oldSize, size_t newSize) { - return js_pod_realloc(prior, oldSize, newSize); - } - - template - T* pod_malloc(size_t numElems) { - T* p = maybe_pod_malloc(numElems); - if (MOZ_UNLIKELY(!p)) - p = onOutOfMemoryTyped(AllocFunction::Malloc, numElems); - return p; - } - - template - T* pod_calloc(size_t numElems) { - T* p = maybe_pod_calloc(numElems); - if (MOZ_UNLIKELY(!p)) - p = onOutOfMemoryTyped(AllocFunction::Calloc, numElems); - return p; - } - - template - T* pod_realloc(T* prior, size_t oldSize, size_t newSize) { - T* p2 = maybe_pod_realloc(prior, oldSize, newSize); - if (MOZ_UNLIKELY(!p2)) - p2 = onOutOfMemoryTyped(AllocFunction::Realloc, newSize, prior); - return p2; - } - - void free_(void* p) { - js_free(p); - } - - JS_FRIEND_API(void) reportAllocOverflow() const; - - bool checkSimulatedOOM() const { - if (js::oom::ShouldFailWithOOM()) { - js::ReportOutOfMemory(reinterpret_cast(cx_)); - return false; - } - - return true; - } -}; - -} /* namespace js */ - -#endif /* jsalloc_h */ 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,18 +14,18 @@ #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 #include #include #include -#include "jsalloc.h" #include "jspubtd.h" +#include "js/AllocPolicy.h" #include "js/CallArgs.h" #include "js/CharacterEncoding.h" #include "js/Class.h" @@ -34,8 +34,11 @@ #include "js/Id.h" #include "js/Principals.h" #include "js/Realm.h" +#include "js/RefCounted.h" #include "js/RootingAPI.h" +#include "js/Stream.h" #include "js/TracingAPI.h" +#include "js/UniquePtr.h" #include "js/Utility.h" #include "js/Value.h" #include "js/Vector.h" @@ -48,200 +51,50 @@ #ifdef JS_DEBUG -class JS_PUBLIC_API(AutoCheckRequestDepth) -{ - JSContext* cx; - public: - explicit AutoCheckRequestDepth(JSContext* cx); - explicit AutoCheckRequestDepth(js::ContextFriendFields* cx); - ~AutoCheckRequestDepth(); +class JS_PUBLIC_API AutoCheckRequestDepth { + JSContext* cx; + + public: + explicit AutoCheckRequestDepth(JSContext* cx); + ~AutoCheckRequestDepth(); }; -# define CHECK_REQUEST(cx) \ - JS::AutoCheckRequestDepth _autoCheckRequestDepth(cx) +#define CHECK_REQUEST(cx) JS::AutoCheckRequestDepth _autoCheckRequestDepth(cx) #else -# define CHECK_REQUEST(cx) \ - ((void) 0) +#define CHECK_REQUEST(cx) ((void)0) #endif /* JS_DEBUG */ /** AutoValueArray roots an internal fixed-size array of Values. */ template -class MOZ_RAII AutoValueArray : public AutoGCRooter -{ - const size_t length_; - Value elements_[N]; - - public: - explicit AutoValueArray(JSContext* cx - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, VALARRAY), length_(N) - { - /* Always initialize in case we GC before assignment. */ - mozilla::PodArrayZero(elements_); - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - unsigned length() const { return length_; } - const Value* begin() const { return elements_; } - Value* begin() { return elements_; } - - HandleValue operator[](unsigned i) const { - MOZ_ASSERT(i < N); - return HandleValue::fromMarkedLocation(&elements_[i]); - } - MutableHandleValue operator[](unsigned i) { - MOZ_ASSERT(i < N); - return MutableHandleValue::fromMarkedLocation(&elements_[i]); - } - - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -template -class MOZ_RAII AutoVectorRooterBase : protected AutoGCRooter -{ - typedef js::Vector VectorImpl; - VectorImpl vector; - - public: - explicit AutoVectorRooterBase(JSContext* cx, ptrdiff_t tag - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, tag), vector(cx) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - explicit AutoVectorRooterBase(js::ContextFriendFields* cx, ptrdiff_t tag - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, tag), vector(cx) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - typedef T ElementType; - typedef typename VectorImpl::Range Range; - - size_t length() const { return vector.length(); } - bool empty() const { return vector.empty(); } - - 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); - } - - 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); } - - void popBack() { vector.popBack(); } - T popCopy() { return vector.popCopy(); } - - MOZ_MUST_USE bool growBy(size_t inc) { - size_t oldLength = vector.length(); - if (!vector.growByUninitialized(inc)) - return false; - makeRangeGCSafe(oldLength); - return true; - } - - MOZ_MUST_USE bool resize(size_t newLength) { - size_t oldLength = vector.length(); - if (newLength <= oldLength) { - vector.shrinkBy(oldLength - newLength); - return true; - } - if (!vector.growByUninitialized(newLength - oldLength)) - return false; - makeRangeGCSafe(oldLength); - return true; - } - - void clear() { vector.clear(); } - - MOZ_MUST_USE bool reserve(size_t newLength) { - return vector.reserve(newLength); - } - - JS::MutableHandle operator[](size_t i) { - return JS::MutableHandle::fromMarkedLocation(&vector[i]); - } - JS::Handle operator[](size_t i) const { - return JS::Handle::fromMarkedLocation(&vector[i]); - } - - const T* begin() const { return vector.begin(); } - T* begin() { return vector.begin(); } - - const T* end() const { return vector.end(); } - T* end() { return vector.end(); } - - Range all() { return vector.all(); } - - const T& back() const { return vector.back(); } - - friend void AutoGCRooter::trace(JSTracer* trc); - - private: - void makeRangeGCSafe(size_t oldLength) { - T* t = vector.begin() + oldLength; - for (size_t i = oldLength; i < vector.length(); ++i, ++t) - memset(t, 0, sizeof(T)); - } - - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -template -class MOZ_RAII AutoVectorRooter : public AutoVectorRooterBase -{ - public: - explicit AutoVectorRooter(JSContext* cx - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoVectorRooterBase(cx, this->GetTag(T())) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - explicit AutoVectorRooter(js::ContextFriendFields* cx - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoVectorRooterBase(cx, this->GetTag(T())) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -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 MOZ_RAII AutoValueArray : public AutoGCRooter { + const size_t length_; + Value elements_[N]; + + public: + explicit AutoValueArray(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, VALARRAY), length_(N) { + /* Always initialize in case we GC before assignment. */ + mozilla::PodArrayZero(elements_); + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + + unsigned length() const { return length_; } + const Value* begin() const { return elements_; } + Value* begin() { return elements_; } + + HandleValue operator[](unsigned i) const { + MOZ_ASSERT(i < N); + return HandleValue::fromMarkedLocation(&elements_[i]); + } + MutableHandleValue operator[](unsigned i) { + MOZ_ASSERT(i < N); + return MutableHandleValue::fromMarkedLocation(&elements_[i]); + } -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)) {} + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; using ValueVector = JS::GCVector; @@ -249,385 +102,278 @@ using ScriptVector = JS::GCVector; using StringVector = JS::GCVector; -template -class MOZ_RAII AutoHashMapRooter : protected AutoGCRooter -{ - private: - typedef js::HashMap HashMapImpl; +template +class MOZ_RAII AutoHashMapRooter : protected AutoGCRooter { + private: + typedef js::HashMap HashMapImpl; - public: - explicit AutoHashMapRooter(JSContext* cx, ptrdiff_t tag - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, tag), map(cx) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } + public: + explicit AutoHashMapRooter(JSContext* cx, + ptrdiff_t tag MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, tag), map(cx) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } - typedef Key KeyType; - typedef Value ValueType; - typedef typename HashMapImpl::Entry Entry; - typedef typename HashMapImpl::Lookup Lookup; - typedef typename HashMapImpl::Ptr Ptr; - typedef typename HashMapImpl::AddPtr AddPtr; + typedef Key KeyType; + typedef Value ValueType; + typedef typename HashMapImpl::Entry Entry; + typedef typename HashMapImpl::Lookup Lookup; + typedef typename HashMapImpl::Ptr Ptr; + typedef typename HashMapImpl::AddPtr AddPtr; - bool init(uint32_t len = 16) { - return map.init(len); - } - bool initialized() const { - return map.initialized(); - } - Ptr lookup(const Lookup& l) const { - return map.lookup(l); - } - void remove(Ptr p) { - map.remove(p); - } - AddPtr lookupForAdd(const Lookup& l) const { - return map.lookupForAdd(l); - } + bool init(uint32_t len = 16) { return map.init(len); } + bool initialized() const { return map.initialized(); } + Ptr lookup(const Lookup& l) const { return map.lookup(l); } + void remove(Ptr p) { map.remove(p); } + AddPtr lookupForAdd(const Lookup& l) const { return map.lookupForAdd(l); } - template - bool add(AddPtr& p, const KeyInput& k, const ValueInput& v) { - return map.add(p, k, v); - } + template + bool add(AddPtr& p, const KeyInput& k, const ValueInput& v) { + return map.add(p, k, v); + } - bool add(AddPtr& p, const Key& k) { - return map.add(p, k); - } + bool add(AddPtr& p, const Key& k) { return map.add(p, k); } - template - bool relookupOrAdd(AddPtr& p, const KeyInput& k, const ValueInput& v) { - return map.relookupOrAdd(p, k, v); - } + template + bool relookupOrAdd(AddPtr& p, const KeyInput& k, const ValueInput& v) { + return map.relookupOrAdd(p, k, v); + } - typedef typename HashMapImpl::Range Range; - Range all() const { - return map.all(); - } + typedef typename HashMapImpl::Range Range; + Range all() const { return map.all(); } - typedef typename HashMapImpl::Enum Enum; + typedef typename HashMapImpl::Enum Enum; - void clear() { - map.clear(); - } + void clear() { map.clear(); } - void finish() { - map.finish(); - } + void finish() { map.finish(); } - bool empty() const { - return map.empty(); - } + bool empty() const { return map.empty(); } - uint32_t count() const { - return map.count(); - } + uint32_t count() const { return map.count(); } - size_t capacity() const { - return map.capacity(); - } + size_t capacity() const { return map.capacity(); } - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return map.sizeOfExcludingThis(mallocSizeOf); - } - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return map.sizeOfIncludingThis(mallocSizeOf); - } + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return map.sizeOfExcludingThis(mallocSizeOf); + } + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return map.sizeOfIncludingThis(mallocSizeOf); + } - /************************************************** Shorthand operations */ + /************************************************** Shorthand operations */ - bool has(const Lookup& l) const { - return map.has(l); - } + bool has(const Lookup& l) const { return map.has(l); } - template - bool put(const KeyInput& k, const ValueInput& v) { - return map.put(k, v); - } + template + bool put(const KeyInput& k, const ValueInput& v) { + return map.put(k, v); + } - template - bool putNew(const KeyInput& k, const ValueInput& v) { - return map.putNew(k, v); - } + template + bool putNew(const KeyInput& k, const ValueInput& v) { + return map.putNew(k, v); + } - Ptr lookupWithDefault(const Key& k, const Value& defaultValue) { - return map.lookupWithDefault(k, defaultValue); - } + Ptr lookupWithDefault(const Key& k, const Value& defaultValue) { + return map.lookupWithDefault(k, defaultValue); + } - void remove(const Lookup& l) { - map.remove(l); - } + void remove(const Lookup& l) { map.remove(l); } - friend void AutoGCRooter::trace(JSTracer* trc); + friend void AutoGCRooter::trace(JSTracer* trc); - private: - AutoHashMapRooter(const AutoHashMapRooter& hmr) = delete; - AutoHashMapRooter& operator=(const AutoHashMapRooter& hmr) = delete; + private: + AutoHashMapRooter(const AutoHashMapRooter& hmr) = delete; + AutoHashMapRooter& operator=(const AutoHashMapRooter& hmr) = delete; - HashMapImpl map; + HashMapImpl map; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; -template -class MOZ_RAII AutoHashSetRooter : protected AutoGCRooter -{ - private: - typedef js::HashSet HashSetImpl; +template +class MOZ_RAII AutoHashSetRooter : protected AutoGCRooter { + private: + typedef js::HashSet HashSetImpl; - public: - explicit AutoHashSetRooter(JSContext* cx, ptrdiff_t tag - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, tag), set(cx) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } + public: + explicit AutoHashSetRooter(JSContext* cx, + ptrdiff_t tag MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, tag), set(cx) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } - typedef typename HashSetImpl::Lookup Lookup; - typedef typename HashSetImpl::Ptr Ptr; - typedef typename HashSetImpl::AddPtr AddPtr; + typedef typename HashSetImpl::Lookup Lookup; + typedef typename HashSetImpl::Ptr Ptr; + typedef typename HashSetImpl::AddPtr AddPtr; - bool init(uint32_t len = 16) { - return set.init(len); - } - bool initialized() const { - return set.initialized(); - } - Ptr lookup(const Lookup& l) const { - return set.lookup(l); - } - void remove(Ptr p) { - set.remove(p); - } - AddPtr lookupForAdd(const Lookup& l) const { - return set.lookupForAdd(l); - } + bool init(uint32_t len = 16) { return set.init(len); } + bool initialized() const { return set.initialized(); } + Ptr lookup(const Lookup& l) const { return set.lookup(l); } + void remove(Ptr p) { set.remove(p); } + AddPtr lookupForAdd(const Lookup& l) const { return set.lookupForAdd(l); } - bool add(AddPtr& p, const T& t) { - return set.add(p, t); - } + bool add(AddPtr& p, const T& t) { return set.add(p, t); } - bool relookupOrAdd(AddPtr& p, const Lookup& l, const T& t) { - return set.relookupOrAdd(p, l, t); - } + bool relookupOrAdd(AddPtr& p, const Lookup& l, const T& t) { + return set.relookupOrAdd(p, l, t); + } - typedef typename HashSetImpl::Range Range; - Range all() const { - return set.all(); - } + typedef typename HashSetImpl::Range Range; + Range all() const { return set.all(); } - typedef typename HashSetImpl::Enum Enum; + typedef typename HashSetImpl::Enum Enum; - void clear() { - set.clear(); - } + void clear() { set.clear(); } - void finish() { - set.finish(); - } + void finish() { set.finish(); } - bool empty() const { - return set.empty(); - } + bool empty() const { return set.empty(); } - uint32_t count() const { - return set.count(); - } + uint32_t count() const { return set.count(); } - size_t capacity() const { - return set.capacity(); - } + size_t capacity() const { return set.capacity(); } - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return set.sizeOfExcludingThis(mallocSizeOf); - } - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return set.sizeOfIncludingThis(mallocSizeOf); - } + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return set.sizeOfExcludingThis(mallocSizeOf); + } + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return set.sizeOfIncludingThis(mallocSizeOf); + } - /************************************************** Shorthand operations */ + /************************************************** Shorthand operations */ - bool has(const Lookup& l) const { - return set.has(l); - } + bool has(const Lookup& l) const { return set.has(l); } - bool put(const T& t) { - return set.put(t); - } + bool put(const T& t) { return set.put(t); } - bool putNew(const T& t) { - return set.putNew(t); - } + bool putNew(const T& t) { return set.putNew(t); } - void remove(const Lookup& l) { - set.remove(l); - } + void remove(const Lookup& l) { set.remove(l); } - friend void AutoGCRooter::trace(JSTracer* trc); + friend void AutoGCRooter::trace(JSTracer* trc); - private: - AutoHashSetRooter(const AutoHashSetRooter& hmr) = delete; - AutoHashSetRooter& operator=(const AutoHashSetRooter& hmr) = delete; + private: + AutoHashSetRooter(const AutoHashSetRooter& hmr) = delete; + AutoHashSetRooter& operator=(const AutoHashSetRooter& hmr) = delete; - HashSetImpl set; + HashSetImpl set; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; /** * Custom rooting behavior for internal and external clients. */ -class MOZ_RAII JS_PUBLIC_API(CustomAutoRooter) : private AutoGCRooter -{ - public: - template - explicit CustomAutoRooter(const CX& cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, CUSTOM) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - friend void AutoGCRooter::trace(JSTracer* trc); +class MOZ_RAII JS_PUBLIC_API CustomAutoRooter : private AutoGCRooter { + public: + template + explicit CustomAutoRooter(const CX& cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, CUSTOM) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + + friend void AutoGCRooter::trace(JSTracer* trc); - protected: - virtual ~CustomAutoRooter() {} + protected: + virtual ~CustomAutoRooter() {} - /** Supplied by derived class to trace roots. */ - virtual void trace(JSTracer* trc) = 0; + /** Supplied by derived class to trace roots. */ + virtual void trace(JSTracer* trc) = 0; - private: - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + private: + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; /** A handle to an array of rooted values. */ -class HandleValueArray -{ - const size_t length_; - const Value * const elements_; - - HandleValueArray(size_t len, const Value* elements) : length_(len), elements_(elements) {} - - public: - explicit HandleValueArray(const RootedValue& value) : length_(1), elements_(value.address()) {} +class HandleValueArray { + const size_t length_; + const Value* const elements_; + + HandleValueArray(size_t len, const Value* elements) + : length_(len), elements_(elements) {} + + public: + explicit HandleValueArray(HandleValue value) + : length_(1), elements_(value.address()) {} - MOZ_IMPLICIT HandleValueArray(const AutoValueVector& values) + MOZ_IMPLICIT HandleValueArray(const AutoValueVector& values) : length_(values.length()), elements_(values.begin()) {} - template - MOZ_IMPLICIT HandleValueArray(const AutoValueArray& values) : length_(N), elements_(values.begin()) {} - - /** CallArgs must already be rooted somewhere up the stack. */ - MOZ_IMPLICIT HandleValueArray(const JS::CallArgs& args) : length_(args.length()), elements_(args.array()) {} + template + MOZ_IMPLICIT HandleValueArray(const AutoValueArray& values) + : length_(N), elements_(values.begin()) {} + + /** CallArgs must already be rooted somewhere up the stack. */ + MOZ_IMPLICIT HandleValueArray(const JS::CallArgs& args) + : length_(args.length()), elements_(args.array()) {} + + /** Use with care! Only call this if the data is guaranteed to be marked. */ + static HandleValueArray fromMarkedLocation(size_t len, + const Value* elements) { + return HandleValueArray(len, elements); + } + + static HandleValueArray subarray(const HandleValueArray& values, + size_t startIndex, size_t len) { + MOZ_ASSERT(startIndex + len <= values.length()); + return HandleValueArray(len, values.begin() + startIndex); + } + + static HandleValueArray empty() { return HandleValueArray(0, nullptr); } + + size_t length() const { return length_; } + const Value* begin() const { return elements_; } + + HandleValue operator[](size_t i) const { + MOZ_ASSERT(i < length_); + return HandleValue::fromMarkedLocation(&elements_[i]); + } +}; - /** Use with care! Only call this if the data is guaranteed to be marked. */ - static HandleValueArray fromMarkedLocation(size_t len, const Value* elements) { - return HandleValueArray(len, elements); - } +} /* namespace JS */ - static HandleValueArray subarray(const HandleValueArray& values, size_t startIndex, size_t len) { - MOZ_ASSERT(startIndex + len <= values.length()); - return HandleValueArray(len, values.begin() + startIndex); - } +/************************************************************************/ - static HandleValueArray empty() { - return HandleValueArray(0, nullptr); - } +struct JSFreeOp { + protected: + JSRuntime* runtime_; - size_t length() const { return length_; } - const Value* begin() const { return elements_; } + explicit JSFreeOp(JSRuntime* rt) : runtime_(rt) {} - HandleValue operator[](size_t i) const { - MOZ_ASSERT(i < length_); - return HandleValue::fromMarkedLocation(&elements_[i]); - } + public: + JSRuntime* runtime() const { + MOZ_ASSERT(runtime_); + return runtime_; + } }; -} /* namespace JS */ +/* Callbacks and their arguments. */ /************************************************************************/ -struct JSFreeOp { - protected: - JSRuntime* runtime_; +typedef bool (*JSInterruptCallback)(JSContext* cx); - explicit JSFreeOp(JSRuntime* rt) - : runtime_(rt) { } +typedef JSObject* (*JSGetIncumbentGlobalCallback)(JSContext* cx); - public: - JSRuntime* runtime() const { - MOZ_ASSERT(runtime_); - return runtime_; - } -}; +typedef bool (*JSEnqueuePromiseJobCallback)(JSContext* cx, JS::HandleObject job, + JS::HandleObject allocationSite, + JS::HandleObject incumbentGlobal, + void* data); -/* Callbacks and their arguments. */ +namespace JS { -/************************************************************************/ +enum class PromiseRejectionHandlingState { Unhandled, Handled }; -typedef enum JSGCStatus { - JSGC_BEGIN, - JSGC_END -} JSGCStatus; - -typedef void -(* 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 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 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. - */ - JSFINALIZE_GROUP_END, - - /** - * Called at the end of collection when everything has been swept. - */ - JSFINALIZE_COLLECTION_END -} JSFinalizeStatus; - -typedef void -(* JSFinalizeCallback)(JSFreeOp* fop, JSFinalizeStatus status, bool isZoneGC, void* data); - -typedef void -(* JSWeakPointerZoneGroupCallback)(JSContext* cx, void* data); - -typedef void -(* 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 -(* JSPromiseRejectionTrackerCallback)(JSContext* cx, JS::HandleObject promise, - PromiseRejectionHandlingState state, void* data); +} /* namespace JS */ + +typedef void (*JSPromiseRejectionTrackerCallback)( + JSContext* cx, JS::HandleObject promise, + JS::PromiseRejectionHandlingState state, void* data); -typedef void -(* JSProcessPromiseCallback)(JSContext* cx, JS::HandleObject promise); +typedef void (*JSProcessPromiseCallback)(JSContext* cx, + JS::HandleObject promise); /** * Possible exception types. These types are part of a JSErrorFormatString @@ -638,51 +384,54 @@ * if we ever decide to use an entirely separate mechanism for warnings. */ typedef enum JSExnType { - JSEXN_ERR, - JSEXN_FIRST = JSEXN_ERR, - JSEXN_INTERNALERR, - JSEXN_EVALERR, - JSEXN_RANGEERR, - JSEXN_REFERENCEERR, - JSEXN_SYNTAXERR, - JSEXN_TYPEERR, - JSEXN_URIERR, - JSEXN_DEBUGGEEWOULDRUN, - JSEXN_WASMCOMPILEERROR, - JSEXN_WASMRUNTIMEERROR, - JSEXN_WARN, - JSEXN_LIMIT + JSEXN_ERR, + JSEXN_FIRST = JSEXN_ERR, + JSEXN_INTERNALERR, + JSEXN_EVALERR, + JSEXN_RANGEERR, + JSEXN_REFERENCEERR, + JSEXN_SYNTAXERR, + JSEXN_TYPEERR, + JSEXN_URIERR, + JSEXN_DEBUGGEEWOULDRUN, + JSEXN_WASMCOMPILEERROR, + JSEXN_WASMLINKERROR, + JSEXN_WASMRUNTIMEERROR, + JSEXN_ERROR_LIMIT, + JSEXN_WARN = JSEXN_ERROR_LIMIT, + JSEXN_NOTE, + JSEXN_LIMIT } JSExnType; -typedef struct JSErrorFormatString { - /** The error message name in ASCII. */ - const char* name; +struct JSErrorFormatString { + /** The error message name in ASCII. */ + const char* name; - /** The error format string in ASCII. */ - const char* format; + /** The error format string in ASCII. */ + const char* format; - /** The number of arguments to expand in the formatted error message. */ - uint16_t argCount; + /** The number of arguments to expand in the formatted error message. */ + uint16_t argCount; - /** One of the JSExnType constants above. */ - int16_t exnType; -} JSErrorFormatString; + /** One of the JSExnType constants above. */ + int16_t exnType; +}; -typedef const JSErrorFormatString* -(* JSErrorCallback)(void* userRef, const unsigned errorNumber); +typedef const JSErrorFormatString* (*JSErrorCallback)( + void* userRef, const unsigned errorNumber); -typedef bool -(* JSLocaleToUpperCase)(JSContext* cx, JS::HandleString src, JS::MutableHandleValue rval); +typedef bool (*JSLocaleToUpperCase)(JSContext* cx, JS::HandleString src, + JS::MutableHandleValue rval); -typedef bool -(* JSLocaleToLowerCase)(JSContext* cx, JS::HandleString src, JS::MutableHandleValue rval); +typedef bool (*JSLocaleToLowerCase)(JSContext* cx, JS::HandleString src, + JS::MutableHandleValue rval); -typedef bool -(* JSLocaleCompare)(JSContext* cx, JS::HandleString src1, JS::HandleString src2, - JS::MutableHandleValue rval); +typedef bool (*JSLocaleCompare)(JSContext* cx, JS::HandleString src1, + JS::HandleString src2, + JS::MutableHandleValue rval); -typedef bool -(* JSLocaleToUnicode)(JSContext* cx, const char* src, JS::MutableHandleValue rval); +typedef bool (*JSLocaleToUnicode)(JSContext* cx, const char* src, + JS::MutableHandleValue rval); /** * Callback used to ask the embedding for the cross compartment wrapper handler @@ -693,55 +442,70 @@ * wrapper with a lazily-defined prototype and the correct global. It is * guaranteed not to wrap a function. */ -typedef JSObject* -(* JSWrapObjectCallback)(JSContext* cx, JS::HandleObject existing, JS::HandleObject obj); +typedef JSObject* (*JSWrapObjectCallback)(JSContext* cx, + JS::HandleObject existing, + JS::HandleObject obj); /** * Callback used by the wrap hook to ask the embedding to prepare an object * for wrapping in a context. This might include unwrapping other wrappers * or even finding a more suitable object for the new compartment. */ -typedef void -(* JSPreWrapCallback)(JSContext* cx, JS::HandleObject scope, JS::HandleObject obj, - JS::HandleObject objectPassedToWrap, - JS::MutableHandleObject retObj); - -struct JSWrapObjectCallbacks -{ - JSWrapObjectCallback wrap; - JSPreWrapCallback preWrap; -}; +typedef void (*JSPreWrapCallback)(JSContext* cx, JS::HandleObject scope, + JS::HandleObject obj, + JS::HandleObject objectPassedToWrap, + JS::MutableHandleObject retObj); -typedef void -(* JSDestroyCompartmentCallback)(JSFreeOp* fop, JSCompartment* compartment); +struct JSWrapObjectCallbacks { + JSWrapObjectCallback wrap; + JSPreWrapCallback preWrap; +}; -typedef size_t -(* JSSizeOfIncludingThisCompartmentCallback)(mozilla::MallocSizeOf mallocSizeOf, +typedef void (*JSDestroyCompartmentCallback)(JSFreeOp* fop, JSCompartment* compartment); -typedef void -(* JSZoneCallback)(JS::Zone* zone); +typedef size_t (*JSSizeOfIncludingThisCompartmentCallback)( + mozilla::MallocSizeOf mallocSizeOf, JSCompartment* compartment); -typedef void -(* JSCompartmentNameCallback)(JSContext* cx, JSCompartment* compartment, - char* buf, size_t bufsize); +typedef void (*JSCompartmentNameCallback)(JSContext* cx, + JSCompartment* compartment, char* buf, + size_t bufsize); + +/** + * Callback used by memory reporting to ask the embedder how much memory an + * external string is keeping alive. The embedder is expected to return a value + * that corresponds to the size of the allocation that will be released by the + * JSStringFinalizer passed to JS_NewExternalString for this string. + * + * Implementations of this callback MUST NOT do anything that can cause GC. + */ +using JSExternalStringSizeofCallback = + size_t (*)(JSString* str, mozilla::MallocSizeOf mallocSizeOf); + +/** + * Callback used to intercept JavaScript errors. + */ +struct JSErrorInterceptor { + /** + * This method is called whenever an error has been raised from JS code. + * + * This method MUST be infallible. + */ + virtual void interceptError(JSContext* cx, const JS::Value& error) = 0; +}; /************************************************************************/ -static MOZ_ALWAYS_INLINE JS::Value -JS_NumberValue(double d) -{ - int32_t i; - d = JS::CanonicalizeNaN(d); - if (mozilla::NumberIsInt32(d, &i)) - return JS::Int32Value(i); - return JS::DoubleValue(d); +static MOZ_ALWAYS_INLINE JS::Value JS_NumberValue(double d) { + int32_t i; + d = JS::CanonicalizeNaN(d); + if (mozilla::NumberIsInt32(d, &i)) return JS::Int32Value(i); + return JS::DoubleValue(d); } /************************************************************************/ -JS_PUBLIC_API(bool) -JS_StringHasBeenPinned(JSContext* cx, JSString* str); +JS_PUBLIC_API bool JS_StringHasBeenPinned(JSContext* cx, JSString* str); namespace JS { @@ -762,85 +526,81 @@ * Example use: * * size_t length = 512; - * char16_t* chars = static_cast(js_malloc(sizeof(char16_t) * length)); - * JS::SourceBufferHolder srcBuf(chars, length, JS::SourceBufferHolder::GiveOwnership); - * JS::Compile(cx, options, srcBuf); - */ -class MOZ_STACK_CLASS SourceBufferHolder final -{ - public: - enum Ownership { - NoOwnership, - GiveOwnership - }; + * char16_t* chars = static_cast(js_malloc(sizeof(char16_t) * + * length)); JS::SourceBufferHolder srcBuf(chars, length, + * JS::SourceBufferHolder::GiveOwnership); JS::Compile(cx, options, srcBuf); + */ +class MOZ_STACK_CLASS SourceBufferHolder final { + public: + enum Ownership { NoOwnership, GiveOwnership }; - SourceBufferHolder(const char16_t* data, size_t dataLength, Ownership ownership) + SourceBufferHolder(const char16_t* data, size_t dataLength, + Ownership ownership) : data_(data), length_(dataLength), - ownsChars_(ownership == GiveOwnership) - { - // Ensure that null buffers properly return an unowned, empty, - // null-terminated string. - static const char16_t NullChar_ = 0; - if (!get()) { - data_ = &NullChar_; - length_ = 0; - ownsChars_ = false; - } + ownsChars_(ownership == GiveOwnership) { + // Ensure that null buffers properly return an unowned, empty, + // null-terminated string. + static const char16_t NullChar_ = 0; + if (!get()) { + data_ = &NullChar_; + length_ = 0; + ownsChars_ = false; } + } - SourceBufferHolder(SourceBufferHolder&& other) + 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_)); - } - - // Access the underlying source buffer without affecting ownership. - const char16_t* get() const { return data_; } - - // Length of the source buffer in char16_t code units (not bytes) - size_t length() const { return length_; } - - // Returns true if the SourceBufferHolder owns the buffer and will free - // it upon destruction. If true, it is legal to call take(). - bool ownsChars() const { return ownsChars_; } - - // Retrieve and take ownership of the underlying data buffer. The caller - // is now responsible for calling js_free() on the returned value, *but only - // after JS script compilation has completed*. - // - // After the buffer has been taken the SourceBufferHolder functions as if - // it had been constructed on an unowned buffer; get() and length() still - // work. In order for this to be safe the taken buffer must be kept alive - // until after JS script compilation completes as noted above. - // - // Note, it's the caller's responsibility to check ownsChars() before taking - // the buffer. Taking and then free'ing an unowned buffer will have dire - // consequences. - char16_t* take() { - MOZ_ASSERT(ownsChars_); - ownsChars_ = false; - return const_cast(data_); - } - - private: - SourceBufferHolder(SourceBufferHolder&) = delete; - SourceBufferHolder& operator=(SourceBufferHolder&) = delete; - - const char16_t* data_; - size_t length_; - bool ownsChars_; + ownsChars_(other.ownsChars_) { + other.data_ = nullptr; + other.length_ = 0; + other.ownsChars_ = false; + } + + ~SourceBufferHolder() { + if (ownsChars_) js_free(const_cast(data_)); + } + + // Access the underlying source buffer without affecting ownership. + const char16_t* get() const { return data_; } + + // Length of the source buffer in char16_t code units (not bytes) + size_t length() const { return length_; } + + // Returns true if the SourceBufferHolder owns the buffer and will free + // it upon destruction. If true, it is legal to call take(). + bool ownsChars() const { return ownsChars_; } + + // Retrieve and take ownership of the underlying data buffer. The caller + // is now responsible for calling js_free() on the returned value, *but only + // after JS script compilation has completed*. + // + // After the buffer has been taken the SourceBufferHolder functions as if + // it had been constructed on an unowned buffer; get() and length() still + // work. In order for this to be safe the taken buffer must be kept alive + // until after JS script compilation completes as noted above. + // + // Note, it's the caller's responsibility to check ownsChars() before taking + // the buffer. Taking and then free'ing an unowned buffer will have dire + // consequences. + char16_t* take() { + MOZ_ASSERT(ownsChars_); + ownsChars_ = false; + return const_cast(data_); + } + + private: + SourceBufferHolder(SourceBufferHolder&) = delete; + SourceBufferHolder& operator=(SourceBufferHolder&) = delete; + + const char16_t* data_; + size_t length_; + bool ownsChars_; }; +struct TranscodeSource; + } /* namespace JS */ /************************************************************************/ @@ -851,41 +611,42 @@ * a uint8_t to store the relevant information. Proceed with caution if * trying to reorder or change the the first byte worth of flags. */ -#define JSPROP_ENUMERATE 0x01 /* property is visible to for/in loop */ -#define JSPROP_READONLY 0x02 /* not settable: assignment is no-op. - This flag is only valid when neither - JSPROP_GETTER nor JSPROP_SETTER is - set. */ -#define JSPROP_PERMANENT 0x04 /* property cannot be deleted */ -#define JSPROP_PROPOP_ACCESSORS 0x08 /* Passed to JS_Define(UC)Property* and - JS_DefineElement if getters/setters - are JSGetterOp/JSSetterOp */ -#define JSPROP_GETTER 0x10 /* property holds getter function */ -#define JSPROP_SETTER 0x20 /* property holds setter function */ -#define JSPROP_SHARED 0x40 /* don't allocate a value slot for this - property; don't copy the property on - set of the same-named property in an - object that delegates to a prototype - containing this property */ -#define JSPROP_INTERNAL_USE_BIT 0x80 /* internal JS engine use only */ -#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 */ +/* property is visible to for/in loop */ +static const uint8_t JSPROP_ENUMERATE = 0x01; + +/* not settable: assignment is no-op. This flag is only valid when neither + JSPROP_GETTER nor JSPROP_SETTER is set. */ +static const uint8_t JSPROP_READONLY = 0x02; + +/* property cannot be deleted */ +static const uint8_t JSPROP_PERMANENT = 0x04; + +/* Passed to JS_Define(UC)Property* and JS_DefineElement if getters/setters are + JSGetterOp/JSSetterOp */ +static const uint8_t JSPROP_PROPOP_ACCESSORS = 0x08; + +/* property holds getter function */ +static const uint8_t JSPROP_GETTER = 0x10; -// 0x800 /* Unused */ +/* property holds setter function */ +static const uint8_t JSPROP_SETTER = 0x20; -#define JSFUN_HAS_REST 0x1000 /* function has ...rest parameter. */ +/* internal JS engine use only */ +static const uint8_t JSPROP_INTERNAL_USE_BIT = 0x80; -#define JSFUN_FLAGS_MASK 0x1e00 /* | of all the JSFUN_* flags */ +/* native that can be called as a ctor */ +static const unsigned JSFUN_CONSTRUCTOR = 0x400; + +/* | of all the JSFUN_* flags */ +static const unsigned JSFUN_FLAGS_MASK = 0x400; /* * If set, will allow redefining a non-configurable property, but only on a * non-DOM global. This is a temporary hack that will need to go away in bug * 1105518. */ -#define JSPROP_REDEFINE_NONCONFIGURABLE 0x1000 +static const unsigned JSPROP_REDEFINE_NONCONFIGURABLE = 0x1000; /* * Resolve hooks and enumerate hooks must pass this flag when calling @@ -899,82 +660,79 @@ * For enumerate hooks, triggering the resolve hook would be merely silly, not * fatal, except in some cases involving non-configurable properties. */ -#define JSPROP_RESOLVING 0x2000 +static const unsigned JSPROP_RESOLVING = 0x2000; -#define JSPROP_IGNORE_ENUMERATE 0x4000 /* ignore the value in JSPROP_ENUMERATE. - This flag only valid when defining over - an existing property. */ -#define JSPROP_IGNORE_READONLY 0x8000 /* ignore the value in JSPROP_READONLY. - This flag only valid when defining over - an existing property. */ -#define JSPROP_IGNORE_PERMANENT 0x10000 /* ignore the value in JSPROP_PERMANENT. - This flag only valid when defining over - an existing property. */ -#define JSPROP_IGNORE_VALUE 0x20000 /* ignore the Value in the descriptor. Nothing was - specified when passed to Object.defineProperty - from script. */ +/* ignore the value in JSPROP_ENUMERATE. This flag only valid when defining + over an existing property. */ +static const unsigned JSPROP_IGNORE_ENUMERATE = 0x4000; + +/* ignore the value in JSPROP_READONLY. This flag only valid when defining over + an existing property. */ +static const unsigned JSPROP_IGNORE_READONLY = 0x8000; + +/* ignore the value in JSPROP_PERMANENT. This flag only valid when defining + over an existing property. */ +static const unsigned JSPROP_IGNORE_PERMANENT = 0x10000; + +/* ignore the Value in the descriptor. Nothing was specified when passed to + Object.defineProperty from script. */ +static const unsigned JSPROP_IGNORE_VALUE = 0x20000; /** Microseconds since the epoch, midnight, January 1, 1970 UTC. */ -extern JS_PUBLIC_API(int64_t) -JS_Now(void); +extern JS_PUBLIC_API int64_t JS_Now(void); /** Don't want to export data, so provide accessors for non-inline Values. */ -extern JS_PUBLIC_API(JS::Value) -JS_GetNaNValue(JSContext* cx); +extern JS_PUBLIC_API JS::Value JS_GetNaNValue(JSContext* cx); -extern JS_PUBLIC_API(JS::Value) -JS_GetNegativeInfinityValue(JSContext* cx); +extern JS_PUBLIC_API JS::Value JS_GetNegativeInfinityValue(JSContext* cx); -extern JS_PUBLIC_API(JS::Value) -JS_GetPositiveInfinityValue(JSContext* cx); +extern JS_PUBLIC_API JS::Value JS_GetPositiveInfinityValue(JSContext* cx); -extern JS_PUBLIC_API(JS::Value) -JS_GetEmptyStringValue(JSContext* cx); +extern JS_PUBLIC_API JS::Value JS_GetEmptyStringValue(JSContext* cx); -extern JS_PUBLIC_API(JSString*) -JS_GetEmptyString(JSContext* cx); +extern JS_PUBLIC_API JSString* JS_GetEmptyString(JSContext* cx); -extern JS_PUBLIC_API(bool) -JS_ValueToObject(JSContext* cx, JS::HandleValue v, JS::MutableHandleObject objp); +extern JS_PUBLIC_API bool JS_ValueToObject(JSContext* cx, JS::HandleValue v, + JS::MutableHandleObject objp); -extern JS_PUBLIC_API(JSFunction*) -JS_ValueToFunction(JSContext* cx, JS::HandleValue v); +extern JS_PUBLIC_API JSFunction* JS_ValueToFunction(JSContext* cx, + JS::HandleValue v); -extern JS_PUBLIC_API(JSFunction*) -JS_ValueToConstructor(JSContext* cx, JS::HandleValue v); +extern JS_PUBLIC_API JSFunction* JS_ValueToConstructor(JSContext* cx, + JS::HandleValue v); -extern JS_PUBLIC_API(JSString*) -JS_ValueToSource(JSContext* cx, JS::Handle v); +extern JS_PUBLIC_API JSString* JS_ValueToSource(JSContext* cx, + JS::Handle v); -extern JS_PUBLIC_API(bool) -JS_DoubleIsInt32(double d, int32_t* ip); +extern JS_PUBLIC_API bool JS_DoubleIsInt32(double d, int32_t* ip); -extern JS_PUBLIC_API(JSType) -JS_TypeOfValue(JSContext* cx, JS::Handle v); +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); +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); - -extern JS_PUBLIC_API(bool) -JS_LooselyEqual(JSContext* cx, JS::Handle v1, JS::Handle v2, bool* equal); +extern JS_PUBLIC_API bool JS_StrictlyEqual(JSContext* cx, + JS::Handle v1, + JS::Handle v2, + bool* equal); + +extern JS_PUBLIC_API bool JS_LooselyEqual(JSContext* cx, + JS::Handle v1, + JS::Handle v2, + bool* equal); -extern JS_PUBLIC_API(bool) -JS_SameValue(JSContext* cx, JS::Handle v1, JS::Handle v2, bool* same); +extern JS_PUBLIC_API bool JS_SameValue(JSContext* cx, JS::Handle v1, + JS::Handle v2, bool* same); /** True iff fun is the global eval function. */ -extern JS_PUBLIC_API(bool) -JS_IsBuiltinEvalFunction(JSFunction* fun); +extern JS_PUBLIC_API bool JS_IsBuiltinEvalFunction(JSFunction* fun); /** True iff fun is the Function constructor. */ -extern JS_PUBLIC_API(bool) -JS_IsBuiltinFunctionConstructor(JSFunction* fun); +extern JS_PUBLIC_API bool JS_IsBuiltinFunctionConstructor(JSFunction* fun); /************************************************************************/ @@ -984,78 +742,112 @@ * 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 + * See: + * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference */ -extern JS_PUBLIC_API(JSContext*) -JS_NewContext(uint32_t maxbytes, - uint32_t maxNurseryBytes = JS::DefaultNurseryBytes, - JSContext* parentContext = nullptr); +// Create a new runtime, with a single cooperative context for this thread. +// On success, the new context will be the active context for the runtime. +extern JS_PUBLIC_API JSContext* JS_NewContext( + uint32_t maxbytes, uint32_t maxNurseryBytes = JS::DefaultNurseryBytes, + JSRuntime* parentRuntime = nullptr); + +// The methods below for controlling the active context in a cooperatively +// multithreaded runtime are not threadsafe, and the caller must ensure they +// are called serially if there is a chance for contention between threads. + +// Called from the active context for a runtime, yield execution so that +// this context is no longer active and can no longer use the API. +extern JS_PUBLIC_API void JS_YieldCooperativeContext(JSContext* cx); + +// Called from a context whose runtime has no active context, this thread +// becomes the active context for that runtime and may use the API. +extern JS_PUBLIC_API void JS_ResumeCooperativeContext(JSContext* cx); + +// Create a new context on this thread for cooperative multithreading in the +// same runtime as siblingContext. Called on a runtime (as indicated by +// siblingContet) which has no active context, on success the new context will +// become the runtime's active context. +extern JS_PUBLIC_API JSContext* JS_NewCooperativeContext( + JSContext* siblingContext); -extern JS_PUBLIC_API(void) -JS_DestroyContext(JSContext* cx); +namespace JS { -typedef double (*JS_CurrentEmbedderTimeFunction)(); +// Class to relinquish exclusive access to all zone groups in use by this +// thread. This allows other cooperative threads to enter the zone groups +// and modify their contents. +struct AutoRelinquishZoneGroups { + explicit AutoRelinquishZoneGroups(JSContext* cx); + ~AutoRelinquishZoneGroups(); -/** - * The embedding can specify a time function that will be used in some - * situations. The function can return the time however it likes; but - * the norm is to return times in units of milliseconds since an - * arbitrary, but consistent, epoch. If the time function is not set, - * a built-in default will be used. - */ -JS_PUBLIC_API(void) -JS_SetCurrentEmbedderTimeFunction(JS_CurrentEmbedderTimeFunction timeFn); + private: + JSContext* cx; + mozilla::Vector enterList; +}; -/** - * Return the time as computed using the current time function, or a - * suitable default if one has not been set. - */ -JS_PUBLIC_API(double) -JS_GetCurrentEmbedderTime(); +} // namespace JS + +// Destroy a context allocated with JS_NewContext or JS_NewCooperativeContext. +// The context must be the current active context in the runtime, and after +// this call the runtime will have no active context. +extern JS_PUBLIC_API void JS_DestroyContext(JSContext* cx); -JS_PUBLIC_API(void*) -JS_GetContextPrivate(JSContext* cx); +JS_PUBLIC_API void* JS_GetContextPrivate(JSContext* cx); -JS_PUBLIC_API(void) -JS_SetContextPrivate(JSContext* cx, void* data); +JS_PUBLIC_API void JS_SetContextPrivate(JSContext* cx, void* data); -extern JS_PUBLIC_API(JSContext*) -JS_GetParentContext(JSContext* cx); +extern JS_PUBLIC_API JSRuntime* JS_GetParentRuntime(JSContext* cx); -extern JS_PUBLIC_API(void) -JS_BeginRequest(JSContext* cx); +extern JS_PUBLIC_API JSRuntime* JS_GetRuntime(JSContext* cx); -extern JS_PUBLIC_API(void) -JS_EndRequest(JSContext* cx); +extern JS_PUBLIC_API void JS_BeginRequest(JSContext* cx); -extern JS_PUBLIC_API(void) -JS_SetFutexCanWait(JSContext* cx); +extern JS_PUBLIC_API void JS_EndRequest(JSContext* cx); + +extern JS_PUBLIC_API void JS_SetFutexCanWait(JSContext* cx); + +namespace JS { + +// Single threaded execution callbacks are used to notify API clients that a +// feature is in use on a context's runtime that is not yet compatible with +// cooperatively multithreaded execution. +// +// Between a call to BeginSingleThreadedExecutionCallback and a corresponding +// call to EndSingleThreadedExecutionCallback, only one thread at a time may +// enter compartments in the runtime. The begin callback may yield as necessary +// to permit other threads to finish up what they're doing, while the end +// callback may not yield or otherwise operate on the runtime (it may be called +// during GC). +// +// These callbacks may be left unspecified for runtimes which only ever have a +// single context. +typedef void (*BeginSingleThreadedExecutionCallback)(JSContext* cx); +typedef void (*EndSingleThreadedExecutionCallback)(JSContext* cx); + +extern JS_PUBLIC_API void SetSingleThreadedExecutionCallbacks( + JSContext* cx, BeginSingleThreadedExecutionCallback begin, + EndSingleThreadedExecutionCallback end); + +} // namespace JS namespace js { -void -AssertHeapIsIdle(JSRuntime* rt); +void AssertHeapIsIdle(); } /* namespace js */ -class MOZ_RAII JSAutoRequest -{ - public: - explicit JSAutoRequest(JSContext* cx - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - JS_BeginRequest(mContext); - } - ~JSAutoRequest() { - JS_EndRequest(mContext); - } - - protected: - JSContext* mContext; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +class MOZ_RAII JSAutoRequest { + public: + explicit JSAutoRequest(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + JS_BeginRequest(mContext); + } + ~JSAutoRequest() { JS_EndRequest(mContext); } + + protected: + JSContext* mContext; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER #if 0 private: @@ -1064,250 +856,320 @@ #endif }; -extern JS_PUBLIC_API(JSVersion) -JS_GetVersion(JSContext* cx); - -/** - * Mutate the version on the compartment. This is generally discouraged, but - * necessary to support the version mutation in the js and xpc shell command - * set. - * - * It would be nice to put this in jsfriendapi, but the linkage requirements - * of the shells make that impossible. - */ -JS_PUBLIC_API(void) -JS_SetVersionForCompartment(JSCompartment* compartment, JSVersion version); - -extern JS_PUBLIC_API(const char*) -JS_VersionToString(JSVersion version); - -extern JS_PUBLIC_API(JSVersion) -JS_StringToVersion(const char* string); - namespace JS { -class JS_PUBLIC_API(ContextOptions) { - public: - ContextOptions() +class JS_PUBLIC_API ContextOptions { + public: + ContextOptions() : baseline_(true), ion_(true), asmJS_(true), - wasm_(false), - wasmAlwaysBaseline_(false), + wasm_(true), + wasmBaseline_(true), + wasmIon_(true), + testWasmAwaitTier2_(false), throwOnAsmJSValidationFailure_(false), nativeRegExp_(true), - unboxedArrays_(false), asyncStack_(true), throwOnDebuggeeWouldRun_(true), dumpStackOnDebuggeeWouldRun_(false), werror_(false), strictMode_(false), - extraWarnings_(false) - { - } - - bool baseline() const { return baseline_; } - ContextOptions& setBaseline(bool flag) { - baseline_ = flag; - return *this; - } - ContextOptions& toggleBaseline() { - baseline_ = !baseline_; - return *this; - } - - bool ion() const { return ion_; } - ContextOptions& setIon(bool flag) { - ion_ = flag; - return *this; - } - ContextOptions& toggleIon() { - ion_ = !ion_; - return *this; - } - - bool asmJS() const { return asmJS_; } - ContextOptions& setAsmJS(bool flag) { - asmJS_ = flag; - return *this; - } - ContextOptions& toggleAsmJS() { - asmJS_ = !asmJS_; - return *this; - } - - bool wasm() const { return wasm_; } - ContextOptions& setWasm(bool flag) { - wasm_ = flag; - return *this; - } - ContextOptions& toggleWasm() { - wasm_ = !wasm_; - return *this; - } - - bool wasmAlwaysBaseline() const { return wasmAlwaysBaseline_; } - ContextOptions& setWasmAlwaysBaseline(bool flag) { - wasmAlwaysBaseline_ = flag; - return *this; - } - ContextOptions& toggleWasmAlwaysBaseline() { - wasmAlwaysBaseline_ = !wasmAlwaysBaseline_; - return *this; - } - - bool throwOnAsmJSValidationFailure() const { return throwOnAsmJSValidationFailure_; } - ContextOptions& setThrowOnAsmJSValidationFailure(bool flag) { - throwOnAsmJSValidationFailure_ = flag; - return *this; - } - ContextOptions& toggleThrowOnAsmJSValidationFailure() { - throwOnAsmJSValidationFailure_ = !throwOnAsmJSValidationFailure_; - return *this; - } - - bool nativeRegExp() const { return nativeRegExp_; } - ContextOptions& setNativeRegExp(bool flag) { - nativeRegExp_ = flag; - return *this; - } - - bool unboxedArrays() const { return unboxedArrays_; } - ContextOptions& setUnboxedArrays(bool flag) { - unboxedArrays_ = flag; - return *this; - } - - bool asyncStack() const { return asyncStack_; } - ContextOptions& setAsyncStack(bool flag) { - asyncStack_ = flag; - return *this; - } - - bool throwOnDebuggeeWouldRun() const { return throwOnDebuggeeWouldRun_; } - ContextOptions& setThrowOnDebuggeeWouldRun(bool flag) { - throwOnDebuggeeWouldRun_ = flag; - return *this; - } - - bool dumpStackOnDebuggeeWouldRun() const { return dumpStackOnDebuggeeWouldRun_; } - ContextOptions& setDumpStackOnDebuggeeWouldRun(bool flag) { - dumpStackOnDebuggeeWouldRun_ = flag; - return *this; - } - - bool werror() const { return werror_; } - ContextOptions& setWerror(bool flag) { - werror_ = flag; - return *this; - } - ContextOptions& toggleWerror() { - werror_ = !werror_; - return *this; - } - - bool strictMode() const { return strictMode_; } - ContextOptions& setStrictMode(bool flag) { - strictMode_ = flag; - return *this; - } - ContextOptions& toggleStrictMode() { - strictMode_ = !strictMode_; - return *this; - } - - bool extraWarnings() const { return extraWarnings_; } - ContextOptions& setExtraWarnings(bool flag) { - extraWarnings_ = flag; - return *this; - } - ContextOptions& toggleExtraWarnings() { - extraWarnings_ = !extraWarnings_; - return *this; - } + extraWarnings_(false), + streams_(false) +#ifdef FUZZING + , + fuzzing_(false) +#endif + , + expressionClosures_(false), + arrayProtoValues_(true) { + } + + bool baseline() const { return baseline_; } + ContextOptions& setBaseline(bool flag) { + baseline_ = flag; + return *this; + } + ContextOptions& toggleBaseline() { + baseline_ = !baseline_; + return *this; + } + + bool ion() const { return ion_; } + ContextOptions& setIon(bool flag) { + ion_ = flag; + return *this; + } + ContextOptions& toggleIon() { + ion_ = !ion_; + return *this; + } + + bool asmJS() const { return asmJS_; } + ContextOptions& setAsmJS(bool flag) { + asmJS_ = flag; + return *this; + } + ContextOptions& toggleAsmJS() { + asmJS_ = !asmJS_; + return *this; + } + + bool wasm() const { return wasm_; } + ContextOptions& setWasm(bool flag) { + wasm_ = flag; + return *this; + } + ContextOptions& toggleWasm() { + wasm_ = !wasm_; + return *this; + } + + bool streams() const { return streams_; } + ContextOptions& setStreams(bool flag) { + streams_ = flag; + return *this; + } + ContextOptions& toggleStreams() { + streams_ = !streams_; + return *this; + } + + bool wasmBaseline() const { return wasmBaseline_; } + ContextOptions& setWasmBaseline(bool flag) { + wasmBaseline_ = flag; + return *this; + } + ContextOptions& toggleWasmBaseline() { + wasmBaseline_ = !wasmBaseline_; + return *this; + } + + bool wasmIon() const { return wasmIon_; } + ContextOptions& setWasmIon(bool flag) { + wasmIon_ = flag; + return *this; + } + ContextOptions& toggleWasmIon() { + wasmIon_ = !wasmIon_; + return *this; + } + + bool testWasmAwaitTier2() const { return testWasmAwaitTier2_; } + ContextOptions& setTestWasmAwaitTier2(bool flag) { + testWasmAwaitTier2_ = flag; + return *this; + } + ContextOptions& toggleTestWasmAwaitTier2() { + testWasmAwaitTier2_ = !testWasmAwaitTier2_; + return *this; + } + + bool throwOnAsmJSValidationFailure() const { + return throwOnAsmJSValidationFailure_; + } + ContextOptions& setThrowOnAsmJSValidationFailure(bool flag) { + throwOnAsmJSValidationFailure_ = flag; + return *this; + } + ContextOptions& toggleThrowOnAsmJSValidationFailure() { + throwOnAsmJSValidationFailure_ = !throwOnAsmJSValidationFailure_; + return *this; + } + + bool nativeRegExp() const { return nativeRegExp_; } + ContextOptions& setNativeRegExp(bool flag) { + nativeRegExp_ = flag; + return *this; + } + + bool asyncStack() const { return asyncStack_; } + ContextOptions& setAsyncStack(bool flag) { + asyncStack_ = flag; + return *this; + } + + bool throwOnDebuggeeWouldRun() const { return throwOnDebuggeeWouldRun_; } + ContextOptions& setThrowOnDebuggeeWouldRun(bool flag) { + throwOnDebuggeeWouldRun_ = flag; + return *this; + } + + bool dumpStackOnDebuggeeWouldRun() const { + return dumpStackOnDebuggeeWouldRun_; + } + ContextOptions& setDumpStackOnDebuggeeWouldRun(bool flag) { + dumpStackOnDebuggeeWouldRun_ = flag; + return *this; + } + + bool werror() const { return werror_; } + ContextOptions& setWerror(bool flag) { + werror_ = flag; + return *this; + } + ContextOptions& toggleWerror() { + werror_ = !werror_; + return *this; + } + + bool strictMode() const { return strictMode_; } + ContextOptions& setStrictMode(bool flag) { + strictMode_ = flag; + return *this; + } + ContextOptions& toggleStrictMode() { + strictMode_ = !strictMode_; + return *this; + } + + bool extraWarnings() const { return extraWarnings_; } + ContextOptions& setExtraWarnings(bool flag) { + extraWarnings_ = flag; + return *this; + } + ContextOptions& toggleExtraWarnings() { + extraWarnings_ = !extraWarnings_; + return *this; + } + +#ifdef FUZZING + bool fuzzing() const { return fuzzing_; } + ContextOptions& setFuzzing(bool flag) { + fuzzing_ = flag; + return *this; + } +#endif - private: - 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; + bool expressionClosures() const { return expressionClosures_; } + ContextOptions& setExpressionClosures(bool flag) { + expressionClosures_ = flag; + return *this; + } + + bool arrayProtoValues() const { return arrayProtoValues_; } + ContextOptions& setArrayProtoValues(bool flag) { + arrayProtoValues_ = flag; + return *this; + } + + void disableOptionsForSafeMode() { + setBaseline(false); + setIon(false); + setAsmJS(false); + setWasm(false); + setWasmBaseline(false); + setWasmIon(false); + setNativeRegExp(false); + } + + private: + bool baseline_ : 1; + bool ion_ : 1; + bool asmJS_ : 1; + bool wasm_ : 1; + bool wasmBaseline_ : 1; + bool wasmIon_ : 1; + bool testWasmAwaitTier2_ : 1; + bool throwOnAsmJSValidationFailure_ : 1; + bool nativeRegExp_ : 1; + bool asyncStack_ : 1; + bool throwOnDebuggeeWouldRun_ : 1; + bool dumpStackOnDebuggeeWouldRun_ : 1; + bool werror_ : 1; + bool strictMode_ : 1; + bool extraWarnings_ : 1; + bool streams_ : 1; +#ifdef FUZZING + bool fuzzing_ : 1; +#endif + bool expressionClosures_ : 1; + bool arrayProtoValues_ : 1; }; -JS_PUBLIC_API(ContextOptions&) -ContextOptionsRef(JSContext* cx); +JS_PUBLIC_API ContextOptions& ContextOptionsRef(JSContext* cx); /** * 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); +JS_PUBLIC_API bool InitSelfHostedCode(JSContext* cx); /** * Asserts (in debug and release builds) that `obj` belongs to the current * thread's context. */ -JS_PUBLIC_API(void) -AssertObjectBelongsToCurrentThread(JSObject* obj); +JS_PUBLIC_API void AssertObjectBelongsToCurrentThread(JSObject* obj); } /* namespace JS */ -extern JS_PUBLIC_API(const char*) -JS_GetImplementationVersion(void); +extern JS_PUBLIC_API const char* JS_GetImplementationVersion(void); + +extern JS_PUBLIC_API void JS_SetDestroyCompartmentCallback( + JSContext* cx, JSDestroyCompartmentCallback callback); + +extern JS_PUBLIC_API void JS_SetSizeOfIncludingThisCompartmentCallback( + JSContext* cx, JSSizeOfIncludingThisCompartmentCallback callback); -extern JS_PUBLIC_API(void) -JS_SetDestroyCompartmentCallback(JSContext* cx, JSDestroyCompartmentCallback callback); +extern JS_PUBLIC_API void JS_SetCompartmentNameCallback( + JSContext* cx, JSCompartmentNameCallback callback); -extern JS_PUBLIC_API(void) -JS_SetSizeOfIncludingThisCompartmentCallback(JSContext* cx, - JSSizeOfIncludingThisCompartmentCallback callback); +extern JS_PUBLIC_API void JS_SetWrapObjectCallbacks( + JSContext* cx, const JSWrapObjectCallbacks* callbacks); -extern JS_PUBLIC_API(void) -JS_SetDestroyZoneCallback(JSContext* cx, JSZoneCallback callback); +extern JS_PUBLIC_API void JS_SetExternalStringSizeofCallback( + JSContext* cx, JSExternalStringSizeofCallback callback); -extern JS_PUBLIC_API(void) -JS_SetSweepZoneCallback(JSContext* cx, JSZoneCallback callback); +#if defined(NIGHTLY_BUILD) -extern JS_PUBLIC_API(void) -JS_SetCompartmentNameCallback(JSContext* cx, JSCompartmentNameCallback callback); +// Set a callback that will be called whenever an error +// is thrown in this runtime. This is designed as a mechanism +// for logging errors. Note that the VM makes no attempt to sanitize +// the contents of the error (so it may contain private data) +// or to sort out among errors (so it may not be the error you +// are interested in or for the component in which you are +// interested). +// +// If the callback sets a new error, this new error +// will replace the original error. +// +// May be `nullptr`. +extern JS_PUBLIC_API void JS_SetErrorInterceptorCallback( + JSRuntime*, JSErrorInterceptor* callback); -extern JS_PUBLIC_API(void) -JS_SetWrapObjectCallbacks(JSContext* cx, const JSWrapObjectCallbacks* callbacks); +extern JS_PUBLIC_API JSErrorInterceptor* JS_GetErrorInterceptorCallback( + JSRuntime*); -extern JS_PUBLIC_API(void) -JS_SetCompartmentPrivate(JSCompartment* compartment, void* data); +// Examine a value to determine if it is one of the built-in Error types. +// If so, return the error type. +extern JS_PUBLIC_API mozilla::Maybe JS_GetErrorType( + const JS::Value& val); -extern JS_PUBLIC_API(void*) -JS_GetCompartmentPrivate(JSCompartment* compartment); +#endif // defined(NIGHTLY_BUILD) -extern JS_PUBLIC_API(void) -JS_SetZoneUserData(JS::Zone* zone, void* data); +extern JS_PUBLIC_API void JS_SetCompartmentPrivate(JSCompartment* compartment, + void* data); -extern JS_PUBLIC_API(void*) -JS_GetZoneUserData(JS::Zone* zone); +extern JS_PUBLIC_API void* JS_GetCompartmentPrivate(JSCompartment* compartment); -extern JS_PUBLIC_API(bool) -JS_WrapObject(JSContext* cx, JS::MutableHandleObject objp); +extern JS_PUBLIC_API void JS_SetZoneUserData(JS::Zone* zone, void* data); -extern JS_PUBLIC_API(bool) -JS_WrapValue(JSContext* cx, JS::MutableHandleValue vp); +extern JS_PUBLIC_API void* JS_GetZoneUserData(JS::Zone* zone); -extern JS_PUBLIC_API(JSObject*) -JS_TransplantObject(JSContext* cx, JS::HandleObject origobj, JS::HandleObject target); +extern JS_PUBLIC_API bool JS_WrapObject(JSContext* cx, + JS::MutableHandleObject objp); -extern JS_PUBLIC_API(bool) -JS_RefreshCrossCompartmentWrappers(JSContext* cx, JS::Handle obj); +extern JS_PUBLIC_API bool JS_WrapValue(JSContext* cx, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API JSObject* JS_TransplantObject(JSContext* cx, + JS::HandleObject origobj, + JS::HandleObject target); + +extern JS_PUBLIC_API bool JS_RefreshCrossCompartmentWrappers( + JSContext* cx, JS::Handle obj); /* * At any time, a JSContext has a current (possibly-nullptr) compartment. @@ -1342,51 +1204,74 @@ * enter/leave calls on the context. Furthermore, only the return value of a * JS_EnterCompartment call may be passed as the 'oldCompartment' argument of * the corresponding JS_LeaveCompartment call. + * + * Entering a compartment roots the compartment and its global object for the + * lifetime of the JSAutoCompartment. */ -class MOZ_RAII JS_PUBLIC_API(JSAutoCompartment) -{ - JSContext* cx_; - JSCompartment* oldCompartment_; - public: - JSAutoCompartment(JSContext* cx, JSObject* target - MOZ_GUARD_OBJECT_NOTIFIER_PARAM); - JSAutoCompartment(JSContext* cx, JSScript* target - MOZ_GUARD_OBJECT_NOTIFIER_PARAM); - ~JSAutoCompartment(); - - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -class MOZ_RAII JS_PUBLIC_API(JSAutoNullableCompartment) -{ - JSContext* cx_; - JSCompartment* oldCompartment_; - public: - explicit JSAutoNullableCompartment(JSContext* cx, JSObject* targetOrNull - MOZ_GUARD_OBJECT_NOTIFIER_PARAM); - ~JSAutoNullableCompartment(); - - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -/** NB: This API is infallible; a nullptr return value does not indicate error. */ -extern JS_PUBLIC_API(JSCompartment*) -JS_EnterCompartment(JSContext* cx, JSObject* target); +class MOZ_RAII JS_PUBLIC_API JSAutoCompartment { + JSContext* cx_; + JSCompartment* oldCompartment_; + + public: + JSAutoCompartment(JSContext* cx, + JSObject* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + JSAutoCompartment(JSContext* cx, + JSScript* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + ~JSAutoCompartment(); + + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class MOZ_RAII JS_PUBLIC_API JSAutoNullableCompartment { + JSContext* cx_; + JSCompartment* oldCompartment_; -extern JS_PUBLIC_API(void) -JS_LeaveCompartment(JSContext* cx, JSCompartment* oldCompartment); + public: + explicit JSAutoNullableCompartment( + JSContext* cx, JSObject* targetOrNull MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + ~JSAutoNullableCompartment(); -typedef void (*JSIterateCompartmentCallback)(JSContext* cx, void* data, JSCompartment* compartment); + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +/** NB: This API is infallible; a nullptr return value does not indicate error. + * + * Entering a compartment roots the compartment and its global object until the + * matching JS_LeaveCompartment() call. + */ +extern JS_PUBLIC_API JSCompartment* JS_EnterCompartment(JSContext* cx, + JSObject* target); + +extern JS_PUBLIC_API void JS_LeaveCompartment(JSContext* cx, + JSCompartment* oldCompartment); + +typedef void (*JSIterateCompartmentCallback)(JSContext* cx, void* data, + JSCompartment* compartment); /** * This function calls |compartmentCallback| on every compartment. Beware that * there is no guarantee that the compartment will survive after the callback * returns. Also, barriers are disabled via the TraceSession. */ -extern JS_PUBLIC_API(void) -JS_IterateCompartments(JSContext* cx, void* data, - JSIterateCompartmentCallback compartmentCallback); +extern JS_PUBLIC_API void JS_IterateCompartments( + JSContext* cx, void* data, + JSIterateCompartmentCallback compartmentCallback); + +/** + * Mark a jsid after entering a new compartment. Different zones separately + * mark the ids in a runtime, and this must be used any time an id is obtained + * from one compartment and then used in another compartment, unless the two + * compartments are guaranteed to be in the same zone. + */ +extern JS_PUBLIC_API void JS_MarkCrossZoneId(JSContext* cx, jsid id); + +/** + * If value stores a jsid (an atomized string or symbol), mark that id as for + * JS_MarkCrossZoneId. + */ +extern JS_PUBLIC_API void JS_MarkCrossZoneIdValue(JSContext* cx, + const JS::Value& value); /** * Initialize standard JS class constructors, prototypes, and any top-level @@ -1395,8 +1280,8 @@ * * NB: This sets cx's global object to obj if it was null. */ -extern JS_PUBLIC_API(bool) -JS_InitStandardClasses(JSContext* cx, JS::Handle obj); +extern JS_PUBLIC_API bool JS_InitStandardClasses(JSContext* cx, + JS::Handle obj); /** * Resolve id, which must contain either a string or an int, to a standard @@ -1407,149 +1292,148 @@ * as usual for bool result-typed API entry points. * * This API can be called directly from a global object class's resolve op, - * to define standard classes lazily. The class's enumerate op should call - * JS_EnumerateStandardClasses(cx, obj), to define eagerly during for..in - * loops any classes not yet resolved lazily. - */ -extern JS_PUBLIC_API(bool) -JS_ResolveStandardClass(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolved); - -extern JS_PUBLIC_API(bool) -JS_MayResolveStandardClass(const JSAtomState& names, jsid id, JSObject* maybeObj); + * to define standard classes lazily. The class should either have an enumerate + * hook that calls JS_EnumerateStandardClasses, or a newEnumerate hook that + * calls JS_NewEnumerateStandardClasses. newEnumerate is preferred because it's + * faster (does not define all standard classes). + */ +extern JS_PUBLIC_API bool JS_ResolveStandardClass(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + bool* resolved); + +extern JS_PUBLIC_API bool JS_MayResolveStandardClass(const JSAtomState& names, + jsid id, + JSObject* maybeObj); + +extern JS_PUBLIC_API bool JS_EnumerateStandardClasses(JSContext* cx, + JS::HandleObject obj); + +extern JS_PUBLIC_API bool JS_NewEnumerateStandardClasses( + JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties, + bool enumerableOnly); -extern JS_PUBLIC_API(bool) -JS_EnumerateStandardClasses(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API bool JS_GetClassObject(JSContext* cx, JSProtoKey key, + JS::MutableHandle objp); -extern JS_PUBLIC_API(bool) -JS_GetClassObject(JSContext* cx, JSProtoKey key, JS::MutableHandle objp); - -extern JS_PUBLIC_API(bool) -JS_GetClassPrototype(JSContext* cx, JSProtoKey key, JS::MutableHandle objp); +extern JS_PUBLIC_API bool JS_GetClassPrototype( + JSContext* cx, JSProtoKey key, JS::MutableHandle objp); namespace JS { /* - * Determine if the given object is an instance/prototype/constructor for a standard - * class. If so, return the associated JSProtoKey. If not, return JSProto_Null. + * Determine if the given object is an instance/prototype/constructor for a + * standard class. If so, return the associated JSProtoKey. If not, return + * JSProto_Null. */ -extern JS_PUBLIC_API(JSProtoKey) -IdentifyStandardInstance(JSObject* obj); +extern JS_PUBLIC_API JSProtoKey IdentifyStandardInstance(JSObject* obj); -extern JS_PUBLIC_API(JSProtoKey) -IdentifyStandardPrototype(JSObject* obj); +extern JS_PUBLIC_API JSProtoKey IdentifyStandardPrototype(JSObject* obj); -extern JS_PUBLIC_API(JSProtoKey) +extern JS_PUBLIC_API JSProtoKey IdentifyStandardInstanceOrPrototype(JSObject* obj); -extern JS_PUBLIC_API(JSProtoKey) -IdentifyStandardConstructor(JSObject* obj); +extern JS_PUBLIC_API JSProtoKey IdentifyStandardConstructor(JSObject* obj); -extern JS_PUBLIC_API(void) -ProtoKeyToId(JSContext* cx, JSProtoKey key, JS::MutableHandleId idp); +extern JS_PUBLIC_API void ProtoKeyToId(JSContext* cx, JSProtoKey key, + JS::MutableHandleId idp); } /* namespace JS */ -extern JS_PUBLIC_API(JSProtoKey) -JS_IdToProtoKey(JSContext* cx, JS::HandleId id); +extern JS_PUBLIC_API JSProtoKey JS_IdToProtoKey(JSContext* cx, JS::HandleId id); /** * Returns the original value of |Function.prototype| from the global object in * which |forObj| was created. */ -extern JS_PUBLIC_API(JSObject*) -JS_GetFunctionPrototype(JSContext* cx, JS::HandleObject forObj); +extern JS_PUBLIC_API JSObject* JS_GetFunctionPrototype(JSContext* cx, + JS::HandleObject forObj); /** * Returns the original value of |Object.prototype| from the global object in * which |forObj| was created. */ -extern JS_PUBLIC_API(JSObject*) -JS_GetObjectPrototype(JSContext* cx, JS::HandleObject forObj); +extern JS_PUBLIC_API JSObject* JS_GetObjectPrototype(JSContext* cx, + JS::HandleObject forObj); /** * Returns the original value of |Array.prototype| from the global object in * which |forObj| was created. */ -extern JS_PUBLIC_API(JSObject*) -JS_GetArrayPrototype(JSContext* cx, JS::HandleObject forObj); +extern JS_PUBLIC_API JSObject* JS_GetArrayPrototype(JSContext* cx, + JS::HandleObject forObj); /** * Returns the original value of |Error.prototype| from the global * object of the current compartment of cx. */ -extern JS_PUBLIC_API(JSObject*) -JS_GetErrorPrototype(JSContext* cx); +extern JS_PUBLIC_API JSObject* JS_GetErrorPrototype(JSContext* cx); /** * Returns the %IteratorPrototype% object that all built-in iterator prototype * chains go through for the global object of the current compartment of cx. */ -extern JS_PUBLIC_API(JSObject*) -JS_GetIteratorPrototype(JSContext* cx); +extern JS_PUBLIC_API JSObject* JS_GetIteratorPrototype(JSContext* cx); -extern JS_PUBLIC_API(JSObject*) -JS_GetGlobalForObject(JSContext* cx, JSObject* obj); +extern JS_PUBLIC_API JSObject* JS_GetGlobalForObject(JSContext* cx, + JSObject* obj); -extern JS_PUBLIC_API(bool) -JS_IsGlobalObject(JSObject* obj); +extern JS_PUBLIC_API bool JS_IsGlobalObject(JSObject* obj); -extern JS_PUBLIC_API(JSObject*) -JS_GlobalLexicalEnvironment(JSObject* obj); +extern JS_PUBLIC_API JSObject* JS_GlobalLexicalEnvironment(JSObject* obj); -extern JS_PUBLIC_API(bool) -JS_HasExtensibleLexicalEnvironment(JSObject* obj); +extern JS_PUBLIC_API bool JS_HasExtensibleLexicalEnvironment(JSObject* obj); -extern JS_PUBLIC_API(JSObject*) -JS_ExtensibleLexicalEnvironment(JSObject* obj); +extern JS_PUBLIC_API JSObject* JS_ExtensibleLexicalEnvironment(JSObject* obj); /** * May return nullptr, if |c| never had a global (e.g. the atoms compartment), * or if |c|'s global has been collected. */ -extern JS_PUBLIC_API(JSObject*) -JS_GetGlobalForCompartmentOrNull(JSContext* cx, JSCompartment* c); +extern JS_PUBLIC_API JSObject* JS_GetGlobalForCompartmentOrNull( + JSContext* cx, JSCompartment* c); namespace JS { -extern JS_PUBLIC_API(JSObject*) -CurrentGlobalOrNull(JSContext* cx); +extern JS_PUBLIC_API JSObject* CurrentGlobalOrNull(JSContext* cx); -} // namespace JS +} // namespace JS /** * Add 'Reflect.parse', a SpiderMonkey extension, to the Reflect object on the * given global. */ -extern JS_PUBLIC_API(bool) -JS_InitReflectParse(JSContext* cx, JS::HandleObject global); +extern JS_PUBLIC_API bool JS_InitReflectParse(JSContext* cx, + JS::HandleObject global); /** * Add various profiling-related functions as properties of the given object. * Defined in builtin/Profilers.cpp. */ -extern JS_PUBLIC_API(bool) -JS_DefineProfilingFunctions(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API bool JS_DefineProfilingFunctions(JSContext* cx, + JS::HandleObject obj); /* Defined in vm/Debugger.cpp. */ -extern JS_PUBLIC_API(bool) -JS_DefineDebuggerObject(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API bool JS_DefineDebuggerObject(JSContext* cx, + JS::HandleObject obj); #ifdef JS_HAS_CTYPES /** * Initialize the 'ctypes' object on a global variable 'obj'. The 'ctypes' * object will be sealed. */ -extern JS_PUBLIC_API(bool) -JS_InitCTypesClass(JSContext* cx, JS::HandleObject global); +extern JS_PUBLIC_API bool JS_InitCTypesClass(JSContext* cx, + JS::HandleObject global); /** * Convert a unicode string 'source' of length 'slen' to the platform native * charset, returning a null-terminated string allocated with JS_malloc. On * failure, this function should report an error. */ -typedef char* -(* JSCTypesUnicodeToNativeFun)(JSContext* cx, const char16_t* source, size_t slen); +typedef char* (*JSCTypesUnicodeToNativeFun)(JSContext* cx, + const char16_t* source, + size_t slen); /** * Set of function pointers that ctypes can use for various internal functions. @@ -1557,243 +1441,40 @@ * and will result in the applicable ctypes functionality not being available. */ struct JSCTypesCallbacks { - JSCTypesUnicodeToNativeFun unicodeToNative; + JSCTypesUnicodeToNativeFun unicodeToNative; }; -typedef struct JSCTypesCallbacks JSCTypesCallbacks; - /** * Set the callbacks on the provided 'ctypesObj' object. 'callbacks' should be a * pointer to static data that exists for the lifetime of 'ctypesObj', but it * may safely be altered after calling this function and without having * to call this function again. */ -extern JS_PUBLIC_API(void) -JS_SetCTypesCallbacks(JSObject* ctypesObj, const JSCTypesCallbacks* callbacks); +extern JS_PUBLIC_API void JS_SetCTypesCallbacks( + JSObject* ctypesObj, const JSCTypesCallbacks* callbacks); #endif -extern JS_PUBLIC_API(void*) -JS_malloc(JSContext* cx, size_t nbytes); +extern JS_PUBLIC_API void* JS_malloc(JSContext* cx, size_t nbytes); -extern JS_PUBLIC_API(void*) -JS_realloc(JSContext* cx, void* p, size_t oldBytes, size_t newBytes); +extern JS_PUBLIC_API void* JS_realloc(JSContext* cx, void* p, size_t oldBytes, + size_t newBytes); /** * A wrapper for js_free(p) that may delay js_free(p) invocation as a * performance optimization. * cx may be nullptr. */ -extern JS_PUBLIC_API(void) -JS_free(JSContext* cx, void* p); +extern JS_PUBLIC_API void JS_free(JSContext* cx, void* p); /** * A wrapper for js_free(p) that may delay js_free(p) invocation as a * performance optimization as specified by the given JSFreeOp instance. */ -extern JS_PUBLIC_API(void) -JS_freeop(JSFreeOp* fop, void* p); +extern JS_PUBLIC_API void JS_freeop(JSFreeOp* fop, void* p); -extern JS_PUBLIC_API(void) -JS_updateMallocCounter(JSContext* cx, size_t nbytes); +extern JS_PUBLIC_API void JS_updateMallocCounter(JSContext* cx, size_t nbytes); -extern JS_PUBLIC_API(char*) -JS_strdup(JSContext* cx, const char* s); - -/** - * Register externally maintained GC roots. - * - * traceOp: the trace operation. For each root the implementation should call - * 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(JSContext* cx, JSTraceDataOp traceOp, void* data); - -/** Undo a call to JS_AddExtraGCRootsTracer. */ -extern JS_PUBLIC_API(void) -JS_RemoveExtraGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp, void* data); - -/* - * Garbage collector API. - */ -extern JS_PUBLIC_API(void) -JS_GC(JSContext* cx); - -extern JS_PUBLIC_API(void) -JS_MaybeGC(JSContext* cx); - -extern JS_PUBLIC_API(void) -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(JSContext* cx, JSFinalizeCallback cb, void* data); - -extern JS_PUBLIC_API(void) -JS_RemoveFinalizeCallback(JSContext* cx, JSFinalizeCallback cb); - -/* - * Weak pointers and garbage collection - * - * Weak pointers are by their nature not marked as part of garbage collection, - * but they may need to be updated in two cases after a GC: - * - * 1) Their referent was found not to be live and is about to be finalized - * 2) Their referent has been moved by a compacting GC - * - * To handle this, any part of the system that maintain weak pointers to - * JavaScript GC things must register a callback with - * JS_(Add,Remove)WeakPointer{ZoneGroup,Compartment}Callback(). This callback - * must then call JS_UpdateWeakPointerAfterGC() on all weak pointers it knows - * about. - * - * Since sweeping is incremental, we have several callbacks to avoid repeatedly - * having to visit all embedder structures. The WeakPointerZoneGroupCallback is - * called once for each strongly connected group of zones, whereas the - * WeakPointerCompartmentCallback is called once for each compartment that is - * visited while sweeping. Structures that cannot contain references in more - * than one compartment should sweep the relevant per-compartment structures - * using the latter callback to minimizer per-slice overhead. - * - * The argument to JS_UpdateWeakPointerAfterGC() is an in-out param. If the - * referent is about to be finalized the pointer will be set to null. If the - * referent has been moved then the pointer will be updated to point to the 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(bool) -JS_AddWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb, void* data); - -extern JS_PUBLIC_API(void) -JS_RemoveWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb); - -extern JS_PUBLIC_API(bool) -JS_AddWeakPointerCompartmentCallback(JSContext* cx, JSWeakPointerCompartmentCallback cb, - void* data); - -extern JS_PUBLIC_API(void) -JS_RemoveWeakPointerCompartmentCallback(JSContext* cx, JSWeakPointerCompartmentCallback cb); - -extern JS_PUBLIC_API(void) -JS_UpdateWeakPointerAfterGC(JS::Heap* objp); - -extern JS_PUBLIC_API(void) -JS_UpdateWeakPointerAfterGCUnbarriered(JSObject** objp); - -typedef enum JSGCParamKey { - /** Maximum nominal heap before last ditch GC. */ - JSGC_MAX_BYTES = 0, - - /** Number of JS_malloc bytes before last ditch GC. */ - JSGC_MAX_MALLOC_BYTES = 1, - - /** Amount of bytes allocated by the GC. */ - JSGC_BYTES = 3, - - /** Number of times GC has been invoked. Includes both major and minor GC. */ - JSGC_NUMBER = 4, - - /** Select GC mode. */ - JSGC_MODE = 6, - - /** Number of cached empty GC chunks. */ - JSGC_UNUSED_CHUNKS = 7, - - /** Total number of allocated GC chunks. */ - JSGC_TOTAL_CHUNKS = 8, - - /** Max milliseconds to spend in an incremental GC slice. */ - JSGC_SLICE_TIME_BUDGET = 9, - - /** Maximum size the GC mark stack can grow to. */ - JSGC_MARK_STACK_LIMIT = 10, - - /** - * GCs less than this far apart in time will be considered 'high-frequency GCs'. - * See setGCLastBytes in jsgc.cpp. - */ - JSGC_HIGH_FREQUENCY_TIME_LIMIT = 11, - - /** Start of dynamic heap growth. */ - JSGC_HIGH_FREQUENCY_LOW_LIMIT = 12, - - /** End of dynamic heap growth. */ - JSGC_HIGH_FREQUENCY_HIGH_LIMIT = 13, - - /** Upper bound of heap growth. */ - JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX = 14, - - /** Lower bound of heap growth. */ - JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN = 15, - - /** Heap growth for low frequency GCs. */ - JSGC_LOW_FREQUENCY_HEAP_GROWTH = 16, - - /** - * If false, the heap growth factor is fixed at 3. If true, it is determined - * based on whether GCs are high- or low- frequency. - */ - JSGC_DYNAMIC_HEAP_GROWTH = 17, - - /** If true, high-frequency GCs will use a longer mark slice. */ - JSGC_DYNAMIC_MARK_SLICE = 18, - - /** Lower limit after which we limit the heap growth. */ - JSGC_ALLOCATION_THRESHOLD = 19, - - /** - * We try to keep at least this many unused chunks in the free chunk pool at - * all times, even after a shrinking GC. - */ - JSGC_MIN_EMPTY_CHUNK_COUNT = 21, - - /** We never keep more than this many unused chunks in the free chunk pool. */ - JSGC_MAX_EMPTY_CHUNK_COUNT = 22, - - /** Whether compacting GC is enabled. */ - JSGC_COMPACTING_ENABLED = 23, - - /** If true, painting can trigger IGC slices. */ - JSGC_REFRESH_FRAME_SLICES_ENABLED = 24, -} JSGCParamKey; - -extern JS_PUBLIC_API(void) -JS_SetGCParameter(JSContext* cx, JSGCParamKey key, uint32_t value); - -extern JS_PUBLIC_API(uint32_t) -JS_GetGCParameter(JSContext* cx, JSGCParamKey key); - -extern JS_PUBLIC_API(void) -JS_SetGCParametersBasedOnAvailableMemory(JSContext* cx, uint32_t availMem); - -/** - * Create a new JSString whose chars member refers to external memory, i.e., - * memory requiring application-specific finalization. - */ -extern JS_PUBLIC_API(JSString*) -JS_NewExternalString(JSContext* cx, const char16_t* chars, size_t length, - const JSStringFinalizer* fin); - -/** - * Return whether 'str' was created with JS_NewExternalString or - * JS_NewExternalStringWithClosure. - */ -extern JS_PUBLIC_API(bool) -JS_IsExternalString(JSString* str); - -/** - * Return the 'fin' arg passed to JS_NewExternalString. - */ -extern JS_PUBLIC_API(const JSStringFinalizer*) -JS_GetExternalStringFinalizer(JSString* str); +extern JS_PUBLIC_API char* JS_strdup(JSContext* cx, const char* s); /** * Set the size of the native stack that should not be exceed. To disable @@ -1801,10 +1482,10 @@ * * SpiderMonkey allows for a distinction between system code (such as GCs, which * may incidentally be triggered by script but are not strictly performed on - * behalf of such script), trusted script (as determined by JS_SetTrustedPrincipals), - * and untrusted script. Each kind of code may have a different stack quota, - * allowing embedders to keep higher-priority machinery running in the face of - * scripted stack exhaustion by something else. + * behalf of such script), trusted script (as determined by + * JS_SetTrustedPrincipals), and untrusted script. Each kind of code may have a + * different stack quota, allowing embedders to keep higher-priority machinery + * running in the face of scripted stack exhaustion by something else. * * The stack quotas for each kind of code should be monotonically descending, * and may be specified with this function. If 0 is passed for a given kind @@ -1813,21 +1494,20 @@ * This function may only be called immediately after the runtime is initialized * and before any code is executed and/or interrupts requested. */ -extern JS_PUBLIC_API(void) -JS_SetNativeStackQuota(JSContext* cx, size_t systemCodeStackSize, - size_t trustedScriptStackSize = 0, - size_t untrustedScriptStackSize = 0); +extern JS_PUBLIC_API void JS_SetNativeStackQuota( + JSContext* cx, size_t systemCodeStackSize, + size_t trustedScriptStackSize = 0, size_t untrustedScriptStackSize = 0); /************************************************************************/ -extern JS_PUBLIC_API(bool) -JS_ValueToId(JSContext* cx, JS::HandleValue v, JS::MutableHandleId idp); +extern JS_PUBLIC_API bool JS_ValueToId(JSContext* cx, JS::HandleValue v, + JS::MutableHandleId idp); -extern JS_PUBLIC_API(bool) -JS_StringToId(JSContext* cx, JS::HandleString s, JS::MutableHandleId idp); +extern JS_PUBLIC_API bool JS_StringToId(JSContext* cx, JS::HandleString s, + JS::MutableHandleId idp); -extern JS_PUBLIC_API(bool) -JS_IdToValue(JSContext* cx, jsid id, JS::MutableHandle vp); +extern JS_PUBLIC_API bool JS_IdToValue(JSContext* cx, jsid id, + JS::MutableHandle vp); namespace JS { @@ -1835,38 +1515,31 @@ * Convert obj to a primitive value. On success, store the result in vp and * return true. * - * The hint argument must be JSTYPE_STRING, JSTYPE_NUMBER, or JSTYPE_VOID (no - * hint). + * The hint argument must be JSTYPE_STRING, JSTYPE_NUMBER, or + * JSTYPE_UNDEFINED (no hint). * * Implements: ES6 7.1.1 ToPrimitive(input, [PreferredType]). */ -extern JS_PUBLIC_API(bool) -ToPrimitive(JSContext* cx, JS::HandleObject obj, JSType hint, JS::MutableHandleValue vp); +extern JS_PUBLIC_API bool ToPrimitive(JSContext* cx, JS::HandleObject obj, + JSType hint, JS::MutableHandleValue vp); /** * If args.get(0) is one of the strings "string", "number", or "default", set - * *result to JSTYPE_STRING, JSTYPE_NUMBER, or JSTYPE_VOID accordingly and + * result to JSTYPE_STRING, JSTYPE_NUMBER, or JSTYPE_UNDEFINED accordingly and * return true. Otherwise, return false with a TypeError pending. * * This can be useful in implementing a @@toPrimitive method. */ -extern JS_PUBLIC_API(bool) -GetFirstArgumentAsTypeHint(JSContext* cx, CallArgs args, JSType *result); +extern JS_PUBLIC_API bool GetFirstArgumentAsTypeHint(JSContext* cx, + CallArgs args, + JSType* result); } /* namespace JS */ -extern JS_PUBLIC_API(bool) -JS_PropertyStub(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_StrictPropertyStub(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleValue vp, JS::ObjectOpResult& result); - -template +template struct JSConstScalarSpec { - const char* name; - T val; + const char* name; + T val; }; typedef JSConstScalarSpec JSConstDoubleSpec; @@ -1879,16 +1552,19 @@ * allow us to pass one JSJitInfo per function with the property/function spec, * without additional field overhead. */ -typedef struct JSNativeWrapper { - JSNative op; - const JSJitInfo* info; -} JSNativeWrapper; +struct JSNativeWrapper { + JSNative op; + const JSJitInfo* info; +}; /* - * Macro static initializers which make it easy to pass no JSJitInfo as part of a - * JSPropertySpec or JSFunctionSpec. + * Macro static initializers which make it easy to pass no JSJitInfo as part of + * a JSPropertySpec or JSFunctionSpec. */ -#define JSNATIVE_WRAPPER(native) { {native, nullptr} } +#define JSNATIVE_WRAPPER(native) \ + { \ + { native, nullptr } \ + } /** * Description of a property. JS_DefineProperties and JS_InitClass take arrays @@ -1896,73 +1572,74 @@ * are helper macros for defining such arrays. */ struct JSPropertySpec { - struct SelfHostedWrapper { - void* unused; - const char* funname; - }; - - struct ValueWrapper { - uintptr_t type; - union { - const char* string; - int32_t int32; - }; - }; + struct SelfHostedWrapper { + void* unused; + const char* funname; + }; - const char* name; - uint8_t flags; + struct ValueWrapper { + uintptr_t type; union { - struct { - union { - JSNativeWrapper native; - SelfHostedWrapper selfHosted; - } getter; - union { - JSNativeWrapper native; - SelfHostedWrapper selfHosted; - } setter; - } accessors; - ValueWrapper value; + const char* string; + int32_t int32; }; + }; - bool isAccessor() const { - return !(flags & JSPROP_INTERNAL_USE_BIT); - } - JS_PUBLIC_API(bool) getValue(JSContext* cx, JS::MutableHandleValue value) const; + const char* name; + uint8_t flags; + union { + 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()); + bool isSelfHosted() const { + MOZ_ASSERT(isAccessor()); #ifdef DEBUG - // Verify that our accessors match our JSPROP_GETTER flag. - if (flags & JSPROP_GETTER) - checkAccessorsAreSelfHosted(); - else - checkAccessorsAreNative(); + // Verify that our accessors match our JSPROP_GETTER flag. + if (flags & JSPROP_GETTER) + checkAccessorsAreSelfHosted(); + else + checkAccessorsAreNative(); #endif - return (flags & JSPROP_GETTER); - } - - static_assert(sizeof(SelfHostedWrapper) == sizeof(JSNativeWrapper), - "JSPropertySpec::getter/setter must be compact"); - static_assert(offsetof(SelfHostedWrapper, funname) == offsetof(JSNativeWrapper, info), - "JS_SELF_HOSTED* macros below require that " - "SelfHostedWrapper::funname overlay " - "JSNativeWrapper::info"); -private: - void checkAccessorsAreNative() const { - 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(accessors.setter.native.info, accessors.setter.native.op); - } + return (flags & JSPROP_GETTER); + } - void checkAccessorsAreSelfHosted() const { - MOZ_ASSERT(!accessors.getter.selfHosted.unused); - MOZ_ASSERT(!accessors.setter.selfHosted.unused); - } + static_assert(sizeof(SelfHostedWrapper) == sizeof(JSNativeWrapper), + "JSPropertySpec::getter/setter must be compact"); + static_assert(offsetof(SelfHostedWrapper, funname) == + offsetof(JSNativeWrapper, info), + "JS_SELF_HOSTED* macros below require that " + "SelfHostedWrapper::funname overlay " + "JSNativeWrapper::info"); + + private: + void checkAccessorsAreNative() const { + 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(accessors.setter.native.info, accessors.setter.native.op); + } + + void checkAccessorsAreSelfHosted() const { + MOZ_ASSERT(!accessors.getter.selfHosted.unused); + MOZ_ASSERT(!accessors.setter.selfHosted.unused); + } }; namespace JS { @@ -1972,9 +1649,8 @@ inline int CheckIsNative(JSNative native); /* NEVER DEFINED, DON'T USE. For use by JS_CAST_STRING_TO only. */ -template -inline int -CheckIsCharacterLiteral(const char (&arr)[N]); +template +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); @@ -1985,81 +1661,104 @@ /* NEVER DEFINED, DON'T USE. For use by JS_PROPERTYOP_SETTER only. */ inline int CheckIsSetterOp(JSSetterOp op); -} // namespace detail -} // namespace JS +} // namespace detail +} // namespace JS -#define JS_CAST_NATIVE_TO(v, To) \ +#define JS_CAST_NATIVE_TO(v, To) \ (static_cast(sizeof(JS::detail::CheckIsNative(v))), \ reinterpret_cast(v)) -#define JS_CAST_STRING_TO(s, To) \ +#define JS_CAST_STRING_TO(s, To) \ (static_cast(sizeof(JS::detail::CheckIsCharacterLiteral(s))), \ reinterpret_cast(s)) -#define JS_CAST_INT32_TO(s, To) \ +#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), \ +#define JS_CHECK_ACCESSOR_FLAGS(flags) \ + (static_cast::Type>(0), \ (flags)) -#define JS_PROPERTYOP_GETTER(v) \ +#define JS_PROPERTYOP_GETTER(v) \ (static_cast(sizeof(JS::detail::CheckIsGetterOp(v))), \ reinterpret_cast(v)) -#define JS_PROPERTYOP_SETTER(v) \ +#define JS_PROPERTYOP_SETTER(v) \ (static_cast(sizeof(JS::detail::CheckIsSetterOp(v))), \ reinterpret_cast(v)) -#define JS_STUBGETTER JS_PROPERTYOP_GETTER(JS_PropertyStub) - -#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*) } } + { \ + 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) \ - JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(nullptr), flags, \ - JSPROP_SHARED) -#define JS_PSGS(name, getter, setter, flags) \ - JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(setter), flags, \ - JSPROP_SHARED) -#define JS_SELF_HOSTED_GET(name, getterName, flags) \ - JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), JSNATIVE_WRAPPER(nullptr), flags, \ - JSPROP_SHARED | JSPROP_GETTER) +#define JS_PSG(name, getter, flags) \ + JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), \ + JSNATIVE_WRAPPER(nullptr), flags, 0) +#define JS_PSGS(name, getter, setter, flags) \ + JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), \ + JSNATIVE_WRAPPER(setter), flags, 0) +#define JS_SYM_GET(symbol, getter, flags) \ + JS_PS_ACCESSOR_SPEC( \ + reinterpret_cast(uint32_t(::JS::SymbolCode::symbol) + 1), \ + JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(nullptr), flags, 0) +#define JS_SELF_HOSTED_GET(name, getterName, flags) \ + JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), \ + JSNATIVE_WRAPPER(nullptr), flags, JSPROP_GETTER) #define JS_SELF_HOSTED_GETSET(name, getterName, setterName, flags) \ - 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) \ - JS_PS_ACCESSOR_SPEC(reinterpret_cast(uint32_t(::JS::SymbolCode::symbol) + 1), \ - SELFHOSTED_WRAPPER(getterName), JSNATIVE_WRAPPER(nullptr), flags, \ - JSPROP_SHARED | JSPROP_GETTER) + JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), \ + SELFHOSTED_WRAPPER(setterName), flags, \ + JSPROP_GETTER | JSPROP_SETTER) +#define JS_SELF_HOSTED_SYM_GET(symbol, getterName, flags) \ + JS_PS_ACCESSOR_SPEC( \ + reinterpret_cast(uint32_t(::JS::SymbolCode::symbol) + 1), \ + SELFHOSTED_WRAPPER(getterName), JSNATIVE_WRAPPER(nullptr), flags, \ + 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) + 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) + 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 @@ -2067,75 +1766,72 @@ * compiled during JSRuntime::initSelfHosting. */ struct JSFunctionSpec { - const char* name; - JSNativeWrapper call; - uint16_t nargs; - uint16_t flags; - const char* selfHostedName; + const char* name; + JSNativeWrapper call; + uint16_t nargs; + uint16_t flags; + const char* selfHostedName; }; /* * Terminating sentinel initializer to put at the end of a JSFunctionSpec array * that's passed to JS_DefineFunctions or JS_InitClass. */ -#define JS_FS_END JS_FS(nullptr,nullptr,0,0) +#define JS_FS_END JS_FN(nullptr, nullptr, 0, 0) /* - * Initializer macros for a JSFunctionSpec array element. JS_FN (whose name pays - * homage to the old JSNative/JSFastNative split) simply adds the flag - * JSFUN_STUB_GSOPS. JS_FNINFO allows the simple adding of - * JSJitInfos. JS_SELF_HOSTED_FN declares a self-hosted function. - * JS_INLINABLE_FN allows specifying an InlinableNative enum value for natives - * inlined or specialized by the JIT. Finally JS_FNSPEC has slots for all the - * fields. + * Initializer macros for a JSFunctionSpec array element. JS_FNINFO allows the + * simple adding of JSJitInfos. JS_SELF_HOSTED_FN declares a self-hosted + * function. JS_INLINABLE_FN allows specifying an InlinableNative enum value for + * natives inlined or specialized by the JIT. Finally JS_FNSPEC has slots for + * all the fields. * * The _SYM variants allow defining a function with a symbol key rather than a * string key. For example, use JS_SYM_FN(iterator, ...) to define an * @@iterator method. */ -#define JS_FS(name,call,nargs,flags) \ - JS_FNSPEC(name, call, nullptr, nargs, flags, nullptr) -#define JS_FN(name,call,nargs,flags) \ - JS_FNSPEC(name, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr) -#define JS_INLINABLE_FN(name,call,nargs,flags,native) \ - JS_FNSPEC(name, call, &js::jit::JitInfo_##native, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr) -#define JS_SYM_FN(symbol,call,nargs,flags) \ - JS_SYM_FNSPEC(symbol, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr) -#define JS_FNINFO(name,call,info,nargs,flags) \ - JS_FNSPEC(name, call, info, nargs, flags, nullptr) -#define JS_SELF_HOSTED_FN(name,selfHostedName,nargs,flags) \ - JS_FNSPEC(name, nullptr, nullptr, nargs, flags, selfHostedName) -#define JS_SELF_HOSTED_SYM_FN(symbol, selfHostedName, nargs, flags) \ - JS_SYM_FNSPEC(symbol, nullptr, nullptr, nargs, flags, selfHostedName) -#define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \ - JS_FNSPEC(reinterpret_cast( \ - uint32_t(::JS::SymbolCode::symbol) + 1), \ - call, info, nargs, flags, selfHostedName) -#define JS_FNSPEC(name,call,info,nargs,flags,selfHostedName) \ - {name, {call, info}, nargs, flags, selfHostedName} - -extern JS_PUBLIC_API(JSObject*) -JS_InitClass(JSContext* cx, JS::HandleObject obj, JS::HandleObject parent_proto, - const JSClass* clasp, JSNative constructor, unsigned nargs, - const JSPropertySpec* ps, const JSFunctionSpec* fs, - const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs); +#define JS_FN(name, call, nargs, flags) \ + JS_FNSPEC(name, call, nullptr, nargs, flags, nullptr) +#define JS_INLINABLE_FN(name, call, nargs, flags, native) \ + JS_FNSPEC(name, call, &js::jit::JitInfo_##native, nargs, flags, nullptr) +#define JS_SYM_FN(symbol, call, nargs, flags) \ + JS_SYM_FNSPEC(symbol, call, nullptr, nargs, flags, nullptr) +#define JS_FNINFO(name, call, info, nargs, flags) \ + JS_FNSPEC(name, call, info, nargs, flags, nullptr) +#define JS_SELF_HOSTED_FN(name, selfHostedName, nargs, flags) \ + JS_FNSPEC(name, nullptr, nullptr, nargs, flags, selfHostedName) +#define JS_SELF_HOSTED_SYM_FN(symbol, selfHostedName, nargs, flags) \ + JS_SYM_FNSPEC(symbol, nullptr, nullptr, nargs, flags, selfHostedName) +#define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \ + JS_FNSPEC( \ + reinterpret_cast(uint32_t(::JS::SymbolCode::symbol) + 1), \ + call, info, nargs, flags, selfHostedName) +#define JS_FNSPEC(name, call, info, nargs, flags, selfHostedName) \ + { name, {call, info}, nargs, flags, selfHostedName } + +extern JS_PUBLIC_API JSObject* JS_InitClass( + JSContext* cx, JS::HandleObject obj, JS::HandleObject parent_proto, + const JSClass* clasp, JSNative constructor, unsigned nargs, + const JSPropertySpec* ps, const JSFunctionSpec* fs, + const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs); /** * Set up ctor.prototype = proto and proto.constructor = ctor with the * right property flags. */ -extern JS_PUBLIC_API(bool) -JS_LinkConstructorAndPrototype(JSContext* cx, JS::Handle ctor, - JS::Handle proto); - -extern JS_PUBLIC_API(const JSClass*) -JS_GetClass(JSObject* obj); +extern JS_PUBLIC_API bool JS_LinkConstructorAndPrototype( + JSContext* cx, JS::Handle ctor, JS::Handle proto); -extern JS_PUBLIC_API(bool) -JS_InstanceOf(JSContext* cx, JS::Handle obj, const JSClass* clasp, JS::CallArgs* args); +extern JS_PUBLIC_API const JSClass* JS_GetClass(JSObject* obj); -extern JS_PUBLIC_API(bool) -JS_HasInstance(JSContext* cx, JS::Handle obj, JS::Handle v, bool* bp); +extern JS_PUBLIC_API bool JS_InstanceOf(JSContext* cx, + JS::Handle obj, + const JSClass* clasp, + JS::CallArgs* args); + +extern JS_PUBLIC_API bool JS_HasInstance(JSContext* cx, + JS::Handle obj, + JS::Handle v, bool* bp); namespace JS { @@ -2143,29 +1839,43 @@ // 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); +extern JS_PUBLIC_API bool OrdinaryHasInstance(JSContext* cx, + HandleObject objArg, + HandleValue v, bool* bp); -} // namespace JS +} // namespace JS -extern JS_PUBLIC_API(void*) -JS_GetPrivate(JSObject* obj); +extern JS_PUBLIC_API void* JS_GetPrivate(JSObject* obj); -extern JS_PUBLIC_API(void) -JS_SetPrivate(JSObject* obj, void* data); +extern JS_PUBLIC_API void JS_SetPrivate(JSObject* obj, void* data); -extern JS_PUBLIC_API(void*) -JS_GetInstancePrivate(JSContext* cx, JS::Handle obj, const JSClass* clasp, - JS::CallArgs* args); +extern JS_PUBLIC_API void* JS_GetInstancePrivate(JSContext* cx, + JS::Handle obj, + const JSClass* clasp, + JS::CallArgs* args); -extern JS_PUBLIC_API(JSObject*) -JS_GetConstructor(JSContext* cx, JS::Handle proto); +extern JS_PUBLIC_API JSObject* JS_GetConstructor(JSContext* cx, + JS::Handle proto); namespace JS { +// Specification for which zone a newly created compartment should use. enum ZoneSpecifier { - FreshZone = 0, - SystemZone = 1 + // Use the single runtime wide system zone. The meaning of this zone is + // left to the embedder. + SystemZone, + + // Use a particular existing zone. + ExistingZone, + + // Create a new zone with its own new zone group. + NewZoneInNewZoneGroup, + + // Create a new zone in the same zone group as the system zone. + NewZoneInSystemZoneGroup, + + // Create a new zone in the same zone group as another existing zone. + NewZoneInExistingZoneGroup }; /** @@ -2176,193 +1886,176 @@ * 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() +class JS_PUBLIC_API CompartmentCreationOptions { + public: + CompartmentCreationOptions() : addonId_(nullptr), traceGlobal_(nullptr), + zoneSpec_(NewZoneInSystemZoneGroup), + zonePointer_(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; - } + secureContext_(false), + clampAndJitterTime_(true) {} - // 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_; + // 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 { return zonePointer_; } + ZoneSpecifier zoneSpecifier() const { return zoneSpec_; } + + // Set the zone to use for the compartment. See ZoneSpecifier above. + CompartmentCreationOptions& setSystemZone(); + CompartmentCreationOptions& setExistingZone(JSObject* obj); + CompartmentCreationOptions& setNewZoneInNewZoneGroup(); + CompartmentCreationOptions& setNewZoneInSystemZoneGroup(); + CompartmentCreationOptions& setNewZoneInExistingZoneGroup(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; + } + + bool clampAndJitterTime() const { return clampAndJitterTime_; } + CompartmentCreationOptions& setClampAndJitterTime(bool flag) { + clampAndJitterTime_ = flag; + return *this; + } + + private: + JSAddonId* addonId_; + JSTraceOp traceGlobal_; + ZoneSpecifier zoneSpec_; + void* zonePointer_; // Per zoneSpec_, either a Zone, ZoneGroup, or null. + bool invisibleToDebugger_; + bool mergeable_; + bool preserveJitCode_; + bool cloneSingletons_; + bool sharedMemoryAndAtomics_; + bool secureContext_; + bool clampAndJitterTime_; }; /** * CompartmentBehaviors specifies behaviors of a compartment that can be * changed after the compartment's been created. */ -class JS_PUBLIC_API(CompartmentBehaviors) -{ - public: - class Override { - public: - Override() : mode_(Default) {} - - bool get(bool defaultValue) const { - if (mode_ == Default) - return defaultValue; - return mode_ == ForceTrue; - } - - void set(bool overrideValue) { - mode_ = overrideValue ? ForceTrue : ForceFalse; - } - - void reset() { - mode_ = Default; - } - - private: - enum Mode { - Default, - ForceTrue, - ForceFalse - }; - - Mode mode_; - }; - - CompartmentBehaviors() - : version_(JSVERSION_UNKNOWN) - , discardSource_(false) - , disableLazyParsing_(false) - , singletonsAsTemplates_(true) - { - } - - JSVersion version() const { return version_; } - CompartmentBehaviors& setVersion(JSVersion aVersion) { - MOZ_ASSERT(aVersion != JSVERSION_UNKNOWN); - version_ = aVersion; - 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_; } - CompartmentBehaviors& setDiscardSource(bool flag) { - discardSource_ = flag; - return *this; - } - - bool disableLazyParsing() const { return disableLazyParsing_; } - CompartmentBehaviors& setDisableLazyParsing(bool flag) { - disableLazyParsing_ = flag; - return *this; - } - - bool extraWarnings(JSContext* cx) const; - Override& extraWarningsOverride() { return extraWarningsOverride_; } - - bool getSingletonsAsTemplates() const { - return singletonsAsTemplates_; - } - CompartmentBehaviors& setSingletonsAsValues() { - singletonsAsTemplates_ = false; - return *this; - } - - private: - JSVersion version_; - bool discardSource_; - bool disableLazyParsing_; - Override extraWarningsOverride_; - - // 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_; +class JS_PUBLIC_API CompartmentBehaviors { + public: + class Override { + public: + Override() : mode_(Default) {} + + bool get(bool defaultValue) const { + if (mode_ == Default) return defaultValue; + return mode_ == ForceTrue; + } + + void set(bool overrideValue) { + mode_ = overrideValue ? ForceTrue : ForceFalse; + } + + void reset() { mode_ = Default; } + + private: + enum Mode { Default, ForceTrue, ForceFalse }; + + Mode mode_; + }; + + CompartmentBehaviors() + : discardSource_(false), + disableLazyParsing_(false), + singletonsAsTemplates_(true) {} + + // 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_; } + CompartmentBehaviors& setDiscardSource(bool flag) { + discardSource_ = flag; + return *this; + } + + bool disableLazyParsing() const { return disableLazyParsing_; } + CompartmentBehaviors& setDisableLazyParsing(bool flag) { + disableLazyParsing_ = flag; + return *this; + } + + bool extraWarnings(JSContext* cx) const; + Override& extraWarningsOverride() { return extraWarningsOverride_; } + + bool getSingletonsAsTemplates() const { return singletonsAsTemplates_; } + CompartmentBehaviors& setSingletonsAsValues() { + singletonsAsTemplates_ = false; + return *this; + } + + private: + bool discardSource_; + bool disableLazyParsing_; + Override extraWarningsOverride_; + + // 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_; }; /** @@ -2371,61 +2064,48 @@ * (CompartmentCreationOptions), and those that can be changed on an existing * compartment (CompartmentBehaviors). */ -class JS_PUBLIC_API(CompartmentOptions) -{ - public: - explicit CompartmentOptions() - : creationOptions_(), - behaviors_() - {} +class JS_PUBLIC_API CompartmentOptions { + public: + explicit CompartmentOptions() : creationOptions_(), behaviors_() {} - CompartmentOptions(const CompartmentCreationOptions& compartmentCreation, - const CompartmentBehaviors& compartmentBehaviors) + CompartmentOptions(const CompartmentCreationOptions& compartmentCreation, + const CompartmentBehaviors& compartmentBehaviors) : creationOptions_(compartmentCreation), - behaviors_(compartmentBehaviors) - {} + 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_; - } + // 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_; - } + // 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_; + private: + CompartmentCreationOptions creationOptions_; + CompartmentBehaviors behaviors_; }; -JS_PUBLIC_API(const CompartmentCreationOptions&) -CompartmentCreationOptionsRef(JSCompartment* compartment); +JS_PUBLIC_API const CompartmentCreationOptions& CompartmentCreationOptionsRef( + JSCompartment* compartment); -JS_PUBLIC_API(const CompartmentCreationOptions&) -CompartmentCreationOptionsRef(JSObject* obj); +JS_PUBLIC_API const CompartmentCreationOptions& CompartmentCreationOptionsRef( + JSObject* obj); -JS_PUBLIC_API(const CompartmentCreationOptions&) -CompartmentCreationOptionsRef(JSContext* cx); +JS_PUBLIC_API const CompartmentCreationOptions& CompartmentCreationOptionsRef( + JSContext* cx); -JS_PUBLIC_API(CompartmentBehaviors&) -CompartmentBehaviorsRef(JSCompartment* compartment); +JS_PUBLIC_API CompartmentBehaviors& CompartmentBehaviorsRef( + JSCompartment* compartment); -JS_PUBLIC_API(CompartmentBehaviors&) -CompartmentBehaviorsRef(JSObject* obj); +JS_PUBLIC_API CompartmentBehaviors& CompartmentBehaviorsRef(JSObject* obj); -JS_PUBLIC_API(CompartmentBehaviors&) -CompartmentBehaviorsRef(JSContext* cx); +JS_PUBLIC_API CompartmentBehaviors& CompartmentBehaviorsRef(JSContext* cx); /** * During global creation, we fire notifications to callbacks registered @@ -2449,367 +2129,344 @@ * place to enforce this). This lets us be sure that debugger clients never miss * breakpoints. */ -enum OnNewGlobalHookOption { - FireOnNewGlobalHook, - DontFireOnNewGlobalHook -}; +enum OnNewGlobalHookOption { FireOnNewGlobalHook, DontFireOnNewGlobalHook }; } /* namespace JS */ -extern JS_PUBLIC_API(JSObject*) -JS_NewGlobalObject(JSContext* cx, const JSClass* clasp, JSPrincipals* principals, - JS::OnNewGlobalHookOption hookOption, - 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 - * compartments is hard. To mitigate this, we create a static trace hook, installed on each global - * object, from which we can be sure the compartment is relevant, and mark it. - * - * It is still possible to specify custom trace hooks for global object classes. They can be - * provided via the CompartmentOptions passed to JS_NewGlobalObject. - */ -extern JS_PUBLIC_API(void) -JS_GlobalObjectTraceHook(JSTracer* trc, JSObject* global); +extern JS_PUBLIC_API JSObject* JS_NewGlobalObject( + JSContext* cx, const JSClass* clasp, JSPrincipals* principals, + JS::OnNewGlobalHookOption hookOption, + 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 compartments is hard. To mitigate + * this, we create a static trace hook, installed on each global object, from + * which we can be sure the compartment is relevant, and mark it. + * + * It is still possible to specify custom trace hooks for global object classes. + * They can be provided via the CompartmentOptions passed to JS_NewGlobalObject. + */ +extern JS_PUBLIC_API void JS_GlobalObjectTraceHook(JSTracer* trc, + JSObject* global); -extern JS_PUBLIC_API(void) -JS_FireOnNewGlobalObject(JSContext* cx, JS::HandleObject global); +extern JS_PUBLIC_API void JS_FireOnNewGlobalObject(JSContext* cx, + JS::HandleObject global); -extern JS_PUBLIC_API(JSObject*) -JS_NewObject(JSContext* cx, const JSClass* clasp); +extern JS_PUBLIC_API JSObject* JS_NewObject(JSContext* cx, + const JSClass* clasp); -extern JS_PUBLIC_API(bool) -JS_IsNative(JSObject* obj); +extern JS_PUBLIC_API bool JS_IsNative(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]]. */ -extern JS_PUBLIC_API(JSObject*) -JS_NewObjectWithGivenProto(JSContext* cx, const JSClass* clasp, JS::Handle proto); +extern JS_PUBLIC_API JSObject* JS_NewObjectWithGivenProto( + JSContext* cx, const JSClass* clasp, JS::Handle proto); -/** Creates a new plain object, like `new Object()`, with Object.prototype as [[Prototype]]. */ -extern JS_PUBLIC_API(JSObject*) -JS_NewPlainObject(JSContext* cx); +/** Creates a new plain object, like `new Object()`, with Object.prototype as + * [[Prototype]]. */ +extern JS_PUBLIC_API JSObject* JS_NewPlainObject(JSContext* cx); /** * Freeze obj, and all objects it refers to, recursively. This will not recurse * through non-extensible objects, on the assumption that those are already * deep-frozen. */ -extern JS_PUBLIC_API(bool) -JS_DeepFreezeObject(JSContext* cx, JS::Handle obj); +extern JS_PUBLIC_API bool JS_DeepFreezeObject(JSContext* cx, + JS::Handle obj); /** * Freezes an object; see ES5's Object.freeze(obj) method. */ -extern JS_PUBLIC_API(bool) -JS_FreezeObject(JSContext* cx, JS::Handle obj); - +extern JS_PUBLIC_API bool JS_FreezeObject(JSContext* cx, + JS::Handle obj); -/*** Property descriptors ************************************************************************/ +/*** Property descriptors ***************************************************/ namespace JS { -struct JS_PUBLIC_API(PropertyDescriptor) { - JSObject* obj; - unsigned attrs; - JSGetterOp getter; - JSSetterOp setter; - JS::Value value; - - PropertyDescriptor() - : obj(nullptr), attrs(0), getter(nullptr), setter(nullptr), value(JS::UndefinedValue()) - {} - - static void trace(PropertyDescriptor* self, JSTracer* trc) { self->trace(trc); } - void trace(JSTracer* trc); -}; - -template -class PropertyDescriptorOperations -{ - const PropertyDescriptor& desc() const { return static_cast(this)->get(); } - - bool has(unsigned bit) const { - MOZ_ASSERT(bit != 0); - MOZ_ASSERT((bit & (bit - 1)) == 0); // only a single bit - return (desc().attrs & bit) != 0; - } - - bool hasAny(unsigned bits) const { - return (desc().attrs & bits) != 0; - } - - bool hasAll(unsigned bits) const { - return (desc().attrs & bits) == bits; - } - - // Non-API attributes bit used internally for arguments objects. - enum { SHADOWABLE = JSPROP_INTERNAL_USE_BIT }; - - public: - // Descriptors with JSGetterOp/JSSetterOp are considered data - // descriptors. It's complicated. - bool isAccessorDescriptor() const { return hasAny(JSPROP_GETTER | JSPROP_SETTER); } - bool isGenericDescriptor() const { - return (desc().attrs& - (JSPROP_GETTER | JSPROP_SETTER | JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE)) == - (JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE); - } - bool isDataDescriptor() const { return !isAccessorDescriptor() && !isGenericDescriptor(); } - - bool hasConfigurable() const { return !has(JSPROP_IGNORE_PERMANENT); } - bool configurable() const { MOZ_ASSERT(hasConfigurable()); return !has(JSPROP_PERMANENT); } - - bool hasEnumerable() const { return !has(JSPROP_IGNORE_ENUMERATE); } - bool enumerable() const { MOZ_ASSERT(hasEnumerable()); return has(JSPROP_ENUMERATE); } - - bool hasValue() const { return !isAccessorDescriptor() && !has(JSPROP_IGNORE_VALUE); } - JS::HandleValue value() const { - return JS::HandleValue::fromMarkedLocation(&desc().value); - } +struct JS_PUBLIC_API PropertyDescriptor { + JSObject* obj; + unsigned attrs; + JSGetterOp getter; + JSSetterOp setter; + JS::Value value; + + PropertyDescriptor() + : obj(nullptr), + attrs(0), + getter(nullptr), + setter(nullptr), + value(JS::UndefinedValue()) {} + + static void trace(PropertyDescriptor* self, JSTracer* trc) { + self->trace(trc); + } + void trace(JSTracer* trc); +}; - bool hasWritable() const { return !isAccessorDescriptor() && !has(JSPROP_IGNORE_READONLY); } - bool writable() const { MOZ_ASSERT(hasWritable()); return !has(JSPROP_READONLY); } +} // namespace JS - bool hasGetterObject() const { return has(JSPROP_GETTER); } - JS::HandleObject getterObject() const { - MOZ_ASSERT(hasGetterObject()); - return JS::HandleObject::fromMarkedLocation( - reinterpret_cast(&desc().getter)); - } - bool hasSetterObject() const { return has(JSPROP_SETTER); } - JS::HandleObject setterObject() const { - MOZ_ASSERT(hasSetterObject()); - return JS::HandleObject::fromMarkedLocation( - reinterpret_cast(&desc().setter)); - } +namespace js { - bool hasGetterOrSetter() const { return desc().getter || desc().setter; } - bool isShared() const { return has(JSPROP_SHARED); } +template +class WrappedPtrOperations { + const JS::PropertyDescriptor& desc() const { + return static_cast(this)->get(); + } + + bool has(unsigned bit) const { + MOZ_ASSERT(bit != 0); + MOZ_ASSERT((bit & (bit - 1)) == 0); // only a single bit + return (desc().attrs & bit) != 0; + } + + bool hasAny(unsigned bits) const { return (desc().attrs & bits) != 0; } + + bool hasAll(unsigned bits) const { return (desc().attrs & bits) == bits; } + + // Non-API attributes bit used internally for arguments objects. + enum { SHADOWABLE = JSPROP_INTERNAL_USE_BIT }; + + public: + // Descriptors with JSGetterOp/JSSetterOp are considered data + // descriptors. It's complicated. + bool isAccessorDescriptor() const { + return hasAny(JSPROP_GETTER | JSPROP_SETTER); + } + bool isGenericDescriptor() const { + return (desc().attrs & (JSPROP_GETTER | JSPROP_SETTER | + JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE)) == + (JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE); + } + bool isDataDescriptor() const { + return !isAccessorDescriptor() && !isGenericDescriptor(); + } + + bool hasConfigurable() const { return !has(JSPROP_IGNORE_PERMANENT); } + bool configurable() const { + MOZ_ASSERT(hasConfigurable()); + return !has(JSPROP_PERMANENT); + } + + bool hasEnumerable() const { return !has(JSPROP_IGNORE_ENUMERATE); } + bool enumerable() const { + MOZ_ASSERT(hasEnumerable()); + return has(JSPROP_ENUMERATE); + } + + bool hasValue() const { + return !isAccessorDescriptor() && !has(JSPROP_IGNORE_VALUE); + } + JS::HandleValue value() const { + return JS::HandleValue::fromMarkedLocation(&desc().value); + } + + bool hasWritable() const { + return !isAccessorDescriptor() && !has(JSPROP_IGNORE_READONLY); + } + bool writable() const { + MOZ_ASSERT(hasWritable()); + return !has(JSPROP_READONLY); + } + + bool hasGetterObject() const { return has(JSPROP_GETTER); } + JS::HandleObject getterObject() const { + MOZ_ASSERT(hasGetterObject()); + return JS::HandleObject::fromMarkedLocation( + reinterpret_cast(&desc().getter)); + } + bool hasSetterObject() const { return has(JSPROP_SETTER); } + JS::HandleObject setterObject() const { + MOZ_ASSERT(hasSetterObject()); + return JS::HandleObject::fromMarkedLocation( + reinterpret_cast(&desc().setter)); + } + + bool hasGetterOrSetter() const { return desc().getter || desc().setter; } + + JS::HandleObject object() const { + return JS::HandleObject::fromMarkedLocation(&desc().obj); + } + unsigned attributes() const { return desc().attrs; } + JSGetterOp getter() const { return desc().getter; } + JSSetterOp setter() const { return desc().setter; } - JS::HandleObject object() const { - return JS::HandleObject::fromMarkedLocation(&desc().obj); - } - unsigned attributes() const { return desc().attrs; } - JSGetterOp getter() const { return desc().getter; } - JSSetterOp setter() const { return desc().setter; } - - void assertValid() const { + void assertValid() const { #ifdef DEBUG - MOZ_ASSERT((attributes() & ~(JSPROP_ENUMERATE | JSPROP_IGNORE_ENUMERATE | - JSPROP_PERMANENT | JSPROP_IGNORE_PERMANENT | - JSPROP_READONLY | JSPROP_IGNORE_READONLY | - JSPROP_IGNORE_VALUE | - JSPROP_GETTER | - JSPROP_SETTER | - JSPROP_SHARED | - JSPROP_REDEFINE_NONCONFIGURABLE | - JSPROP_RESOLVING | - SHADOWABLE)) == 0); - MOZ_ASSERT(!hasAll(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE)); - MOZ_ASSERT(!hasAll(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT)); - if (isAccessorDescriptor()) { - MOZ_ASSERT(has(JSPROP_SHARED)); - MOZ_ASSERT(!has(JSPROP_READONLY)); - MOZ_ASSERT(!has(JSPROP_IGNORE_READONLY)); - MOZ_ASSERT(!has(JSPROP_IGNORE_VALUE)); - MOZ_ASSERT(!has(SHADOWABLE)); - MOZ_ASSERT(value().isUndefined()); - MOZ_ASSERT_IF(!has(JSPROP_GETTER), !getter()); - MOZ_ASSERT_IF(!has(JSPROP_SETTER), !setter()); - } else { - MOZ_ASSERT(!hasAll(JSPROP_IGNORE_READONLY | JSPROP_READONLY)); - MOZ_ASSERT_IF(has(JSPROP_IGNORE_VALUE), value().isUndefined()); - } - MOZ_ASSERT(getter() != JS_PropertyStub); - MOZ_ASSERT(setter() != JS_StrictPropertyStub); - - MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_ENUMERATE)); - MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_PERMANENT)); - MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_READONLY)); - MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_VALUE)); - MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_REDEFINE_NONCONFIGURABLE)); + MOZ_ASSERT((attributes() & + ~(JSPROP_ENUMERATE | JSPROP_IGNORE_ENUMERATE | + JSPROP_PERMANENT | JSPROP_IGNORE_PERMANENT | JSPROP_READONLY | + JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE | JSPROP_GETTER | + JSPROP_SETTER | JSPROP_REDEFINE_NONCONFIGURABLE | + JSPROP_RESOLVING | SHADOWABLE)) == 0); + MOZ_ASSERT(!hasAll(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE)); + MOZ_ASSERT(!hasAll(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT)); + if (isAccessorDescriptor()) { + MOZ_ASSERT(!has(JSPROP_READONLY)); + MOZ_ASSERT(!has(JSPROP_IGNORE_READONLY)); + MOZ_ASSERT(!has(JSPROP_IGNORE_VALUE)); + MOZ_ASSERT(!has(SHADOWABLE)); + MOZ_ASSERT(value().isUndefined()); + MOZ_ASSERT_IF(!has(JSPROP_GETTER), !getter()); + MOZ_ASSERT_IF(!has(JSPROP_SETTER), !setter()); + } else { + MOZ_ASSERT(!hasAll(JSPROP_IGNORE_READONLY | JSPROP_READONLY)); + MOZ_ASSERT_IF(has(JSPROP_IGNORE_VALUE), value().isUndefined()); + } + + MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_ENUMERATE)); + MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_PERMANENT)); + MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_READONLY)); + MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_VALUE)); + MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_REDEFINE_NONCONFIGURABLE)); #endif - } + } - void assertComplete() const { + void assertComplete() const { #ifdef DEBUG - assertValid(); - MOZ_ASSERT((attributes() & ~(JSPROP_ENUMERATE | - JSPROP_PERMANENT | - JSPROP_READONLY | - JSPROP_GETTER | - JSPROP_SETTER | - JSPROP_SHARED | - JSPROP_REDEFINE_NONCONFIGURABLE | - JSPROP_RESOLVING | - SHADOWABLE)) == 0); - MOZ_ASSERT_IF(isAccessorDescriptor(), has(JSPROP_GETTER) && has(JSPROP_SETTER)); + assertValid(); + MOZ_ASSERT( + (attributes() & + ~(JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY | + JSPROP_GETTER | JSPROP_SETTER | JSPROP_REDEFINE_NONCONFIGURABLE | + JSPROP_RESOLVING | SHADOWABLE)) == 0); + MOZ_ASSERT_IF(isAccessorDescriptor(), + has(JSPROP_GETTER) && has(JSPROP_SETTER)); #endif - } + } - void assertCompleteIfFound() const { + void assertCompleteIfFound() const { #ifdef DEBUG - if (object()) - assertComplete(); + if (object()) assertComplete(); #endif - } + } }; -template -class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations -{ - PropertyDescriptor& desc() { return static_cast(this)->get(); } - - public: - void clear() { - object().set(nullptr); - setAttributes(0); - setGetter(nullptr); - setSetter(nullptr); - value().setUndefined(); - } - - void initFields(HandleObject obj, HandleValue v, unsigned attrs, - JSGetterOp getterOp, JSSetterOp setterOp) { - MOZ_ASSERT(getterOp != JS_PropertyStub); - MOZ_ASSERT(setterOp != JS_StrictPropertyStub); - - object().set(obj); - value().set(v); - setAttributes(attrs); - setGetter(getterOp); - setSetter(setterOp); - } - - void assign(PropertyDescriptor& other) { - object().set(other.obj); - setAttributes(other.attrs); - setGetter(other.getter); - setSetter(other.setter); - value().set(other.value); - } - - void setDataDescriptor(HandleValue v, unsigned attrs) { - MOZ_ASSERT((attrs & ~(JSPROP_ENUMERATE | - JSPROP_PERMANENT | - JSPROP_READONLY | - JSPROP_IGNORE_ENUMERATE | - JSPROP_IGNORE_PERMANENT | - JSPROP_IGNORE_READONLY)) == 0); - object().set(nullptr); - setAttributes(attrs); - setGetter(nullptr); - setSetter(nullptr); - value().set(v); - } - - JS::MutableHandleObject object() { - return JS::MutableHandleObject::fromMarkedLocation(&desc().obj); - } - unsigned& attributesRef() { return desc().attrs; } - JSGetterOp& getter() { return desc().getter; } - JSSetterOp& setter() { return desc().setter; } - JS::MutableHandleValue value() { - return JS::MutableHandleValue::fromMarkedLocation(&desc().value); - } - void setValue(JS::HandleValue v) { - MOZ_ASSERT(!(desc().attrs & (JSPROP_GETTER | JSPROP_SETTER))); - attributesRef() &= ~JSPROP_IGNORE_VALUE; - value().set(v); - } - - void setConfigurable(bool configurable) { - setAttributes((desc().attrs & ~(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT)) | - (configurable ? 0 : JSPROP_PERMANENT)); - } - void setEnumerable(bool enumerable) { - setAttributes((desc().attrs & ~(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE)) | - (enumerable ? JSPROP_ENUMERATE : 0)); - } - void setWritable(bool writable) { - MOZ_ASSERT(!(desc().attrs & (JSPROP_GETTER | JSPROP_SETTER))); - setAttributes((desc().attrs & ~(JSPROP_IGNORE_READONLY | JSPROP_READONLY)) | - (writable ? 0 : JSPROP_READONLY)); - } - void setAttributes(unsigned attrs) { desc().attrs = attrs; } - - void setGetter(JSGetterOp op) { - MOZ_ASSERT(op != JS_PropertyStub); - desc().getter = op; - } - void setSetter(JSSetterOp op) { - MOZ_ASSERT(op != JS_StrictPropertyStub); - desc().setter = op; - } - void setGetterObject(JSObject* obj) { - desc().getter = reinterpret_cast(obj); - desc().attrs &= ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY); - desc().attrs |= JSPROP_GETTER | JSPROP_SHARED; - } - void setSetterObject(JSObject* obj) { - desc().setter = reinterpret_cast(obj); - desc().attrs &= ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY); - desc().attrs |= JSPROP_SETTER | JSPROP_SHARED; - } - - JS::MutableHandleObject getterObject() { - MOZ_ASSERT(this->hasGetterObject()); - return JS::MutableHandleObject::fromMarkedLocation( - reinterpret_cast(&desc().getter)); - } - JS::MutableHandleObject setterObject() { - MOZ_ASSERT(this->hasSetterObject()); - return JS::MutableHandleObject::fromMarkedLocation( - reinterpret_cast(&desc().setter)); - } +template +class MutableWrappedPtrOperations + : public js::WrappedPtrOperations { + JS::PropertyDescriptor& desc() { return static_cast(this)->get(); } + + public: + void clear() { + object().set(nullptr); + setAttributes(0); + setGetter(nullptr); + setSetter(nullptr); + value().setUndefined(); + } + + void initFields(JS::HandleObject obj, JS::HandleValue v, unsigned attrs, + JSGetterOp getterOp, JSSetterOp setterOp) { + object().set(obj); + value().set(v); + setAttributes(attrs); + setGetter(getterOp); + setSetter(setterOp); + } + + void assign(JS::PropertyDescriptor& other) { + object().set(other.obj); + setAttributes(other.attrs); + setGetter(other.getter); + setSetter(other.setter); + value().set(other.value); + } + + void setDataDescriptor(JS::HandleValue v, unsigned attrs) { + MOZ_ASSERT((attrs & ~(JSPROP_ENUMERATE | JSPROP_PERMANENT | + JSPROP_READONLY | JSPROP_IGNORE_ENUMERATE | + JSPROP_IGNORE_PERMANENT | JSPROP_IGNORE_READONLY)) == + 0); + object().set(nullptr); + setAttributes(attrs); + setGetter(nullptr); + setSetter(nullptr); + value().set(v); + } + + JS::MutableHandleObject object() { + return JS::MutableHandleObject::fromMarkedLocation(&desc().obj); + } + unsigned& attributesRef() { return desc().attrs; } + JSGetterOp& getter() { return desc().getter; } + JSSetterOp& setter() { return desc().setter; } + JS::MutableHandleValue value() { + return JS::MutableHandleValue::fromMarkedLocation(&desc().value); + } + void setValue(JS::HandleValue v) { + MOZ_ASSERT(!(desc().attrs & (JSPROP_GETTER | JSPROP_SETTER))); + attributesRef() &= ~JSPROP_IGNORE_VALUE; + value().set(v); + } + + void setConfigurable(bool configurable) { + setAttributes( + (desc().attrs & ~(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT)) | + (configurable ? 0 : JSPROP_PERMANENT)); + } + void setEnumerable(bool enumerable) { + setAttributes( + (desc().attrs & ~(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE)) | + (enumerable ? JSPROP_ENUMERATE : 0)); + } + void setWritable(bool writable) { + MOZ_ASSERT(!(desc().attrs & (JSPROP_GETTER | JSPROP_SETTER))); + setAttributes((desc().attrs & ~(JSPROP_IGNORE_READONLY | JSPROP_READONLY)) | + (writable ? 0 : JSPROP_READONLY)); + } + void setAttributes(unsigned attrs) { desc().attrs = attrs; } + + void setGetter(JSGetterOp op) { desc().getter = op; } + void setSetter(JSSetterOp op) { desc().setter = op; } + void setGetterObject(JSObject* obj) { + desc().getter = reinterpret_cast(obj); + desc().attrs &= + ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY); + desc().attrs |= JSPROP_GETTER; + } + void setSetterObject(JSObject* obj) { + desc().setter = reinterpret_cast(obj); + desc().attrs &= + ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY); + desc().attrs |= JSPROP_SETTER; + } + + JS::MutableHandleObject getterObject() { + MOZ_ASSERT(this->hasGetterObject()); + return JS::MutableHandleObject::fromMarkedLocation( + reinterpret_cast(&desc().getter)); + } + JS::MutableHandleObject setterObject() { + MOZ_ASSERT(this->hasSetterObject()); + return JS::MutableHandleObject::fromMarkedLocation( + reinterpret_cast(&desc().setter)); + } }; -} /* namespace JS */ - -namespace js { - -template <> -class RootedBase - : public JS::MutablePropertyDescriptorOperations> -{}; - -template <> -class HandleBase - : public JS::PropertyDescriptorOperations> -{}; - -template <> -class MutableHandleBase - : public JS::MutablePropertyDescriptorOperations> -{}; - -} /* namespace js */ +} // namespace js namespace JS { -extern JS_PUBLIC_API(bool) -ObjectToCompletePropertyDescriptor(JSContext* cx, - JS::HandleObject obj, - JS::HandleValue descriptor, - JS::MutableHandle desc); +extern JS_PUBLIC_API bool ObjectToCompletePropertyDescriptor( + JSContext* cx, JS::HandleObject obj, JS::HandleValue descriptor, + 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 +extern JS_PUBLIC_API bool FromPropertyDescriptor( + JSContext* cx, JS::Handle desc, + JS::MutableHandleValue vp); +} // namespace JS -/*** Standard internal methods ******************************************************************** +/*** Standard internal methods ********************************************** * * The functions below are the fundamental operations on objects. * @@ -2831,8 +2488,8 @@ * * Implements: ES6 [[GetPrototypeOf]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_GetPrototype(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject result); +extern JS_PUBLIC_API bool JS_GetPrototype(JSContext* cx, JS::HandleObject obj, + JS::MutableHandleObject result); /** * If |obj| (underneath any functionally-transparent wrapper proxies) has as @@ -2841,9 +2498,9 @@ * 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); +extern JS_PUBLIC_API bool JS_GetPrototypeIfOrdinary( + JSContext* cx, JS::HandleObject obj, bool* isOrdinary, + JS::MutableHandleObject result); /** * Change the prototype of obj. @@ -2858,8 +2515,8 @@ * all other objects in the same "group" as obj to be permanently deoptimized. * It's better to create the object with the right prototype from the start. */ -extern JS_PUBLIC_API(bool) -JS_SetPrototype(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto); +extern JS_PUBLIC_API bool JS_SetPrototype(JSContext* cx, JS::HandleObject obj, + JS::HandleObject proto); /** * Determine whether obj is extensible. Extensible objects can have new @@ -2868,8 +2525,8 @@ * * Implements: ES6 [[IsExtensible]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_IsExtensible(JSContext* cx, JS::HandleObject obj, bool* extensible); +extern JS_PUBLIC_API bool JS_IsExtensible(JSContext* cx, JS::HandleObject obj, + bool* extensible); /** * Attempt to make |obj| non-extensible. @@ -2879,8 +2536,9 @@ * * Implements: ES6 [[PreventExtensions]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result); +extern JS_PUBLIC_API bool JS_PreventExtensions(JSContext* cx, + JS::HandleObject obj, + JS::ObjectOpResult& result); /** * Attempt to make the [[Prototype]] of |obj| immutable, such that any attempt @@ -2891,8 +2549,9 @@ * * This is a nonstandard internal method. */ -extern JS_PUBLIC_API(bool) -JS_SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded); +extern JS_PUBLIC_API bool JS_SetImmutablePrototype(JSContext* cx, + JS::HandleObject obj, + bool* succeeded); /** * Get a description of one of obj's own properties. If no such property exists @@ -2900,17 +2559,17 @@ * * Implements: ES6 [[GetOwnProperty]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_GetOwnPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); - -extern JS_PUBLIC_API(bool) -JS_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, - JS::MutableHandle desc); - -extern JS_PUBLIC_API(bool) -JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, - JS::MutableHandle desc); +extern JS_PUBLIC_API bool JS_GetOwnPropertyDescriptorById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::MutableHandle desc); + +extern JS_PUBLIC_API bool JS_GetOwnPropertyDescriptor( + JSContext* cx, JS::HandleObject obj, const char* name, + JS::MutableHandle desc); + +extern JS_PUBLIC_API bool JS_GetOwnUCPropertyDescriptor( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::MutableHandle desc); /** * Like JS_GetOwnPropertyDescriptorById, but also searches the prototype chain @@ -2918,13 +2577,17 @@ * property is found is returned in desc.object(). If the property is not found * on the prototype chain, this returns true with desc.object() set to null. */ -extern JS_PUBLIC_API(bool) -JS_GetPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); - -extern JS_PUBLIC_API(bool) -JS_GetPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, - JS::MutableHandle desc); +extern JS_PUBLIC_API bool JS_GetPropertyDescriptorById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::MutableHandle desc); + +extern JS_PUBLIC_API bool JS_GetPropertyDescriptor( + JSContext* cx, JS::HandleObject obj, const char* name, + JS::MutableHandle desc); + +extern JS_PUBLIC_API bool JS_GetUCPropertyDescriptor( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::MutableHandle desc); /** * Define a property on obj. @@ -2937,129 +2600,160 @@ * * Implements: ES6 [[DefineOwnProperty]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc, - JS::ObjectOpResult& result); +extern JS_PUBLIC_API bool JS_DefinePropertyById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::Handle desc, JS::ObjectOpResult& result); /** * Define a property on obj, throwing a TypeError if the attempt fails. * This is the C++ equivalent of `Object.defineProperty(obj, id, desc)`. */ -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleString value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, int32_t value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, uint32_t value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, double value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleValue value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleObject value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleString value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, int32_t value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, uint32_t value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, double value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - 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); - -extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::HandleValue value, unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::HandleObject value, unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::HandleString value, unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - int32_t value, unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - uint32_t value, unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - double value, unsigned attrs, - JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleObject value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleString value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, int32_t value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, uint32_t value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); - -extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, double value, - unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); +extern JS_PUBLIC_API bool JS_DefinePropertyById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::Handle desc); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::HandleValue value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, JSNative getter, + JSNative setter, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::HandleObject value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::HandleString value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, int32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, uint32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, double value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::HandleValue value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, JSNative getter, + JSNative setter, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::HandleObject value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::HandleString value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, int32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, uint32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, double value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + 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); + +extern JS_PUBLIC_API bool JS_DefineUCProperty( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::HandleValue value, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, JSNative getter, + JSNative setter, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::HandleObject value, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::HandleString value, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, int32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, uint32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, double value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::HandleValue value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, JSNative getter, + JSNative setter, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::HandleObject value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::HandleString value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, int32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, uint32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, double value, + unsigned attrs); /** * Compute the expression `id in obj`. @@ -3070,29 +2764,31 @@ * * Implements: ES6 [[Has]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_HasPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); +extern JS_PUBLIC_API bool JS_HasPropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, bool* foundp); + +extern JS_PUBLIC_API bool JS_HasProperty(JSContext* cx, JS::HandleObject obj, + const char* name, bool* foundp); + +extern JS_PUBLIC_API bool JS_HasUCProperty(JSContext* cx, JS::HandleObject obj, + const char16_t* name, size_t namelen, + bool* vp); -extern JS_PUBLIC_API(bool) -JS_HasProperty(JSContext* cx, JS::HandleObject obj, const char* name, bool* foundp); - -extern JS_PUBLIC_API(bool) -JS_HasUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - bool* vp); - -extern JS_PUBLIC_API(bool) -JS_HasElement(JSContext* cx, JS::HandleObject obj, uint32_t index, bool* foundp); +extern JS_PUBLIC_API bool JS_HasElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, bool* foundp); /** * Determine whether obj has an own property with the key `id`. * * Implements: ES6 7.3.11 HasOwnProperty(O, P). */ -extern JS_PUBLIC_API(bool) -JS_HasOwnPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); +extern JS_PUBLIC_API bool JS_HasOwnPropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, bool* foundp); -extern JS_PUBLIC_API(bool) -JS_HasOwnProperty(JSContext* cx, JS::HandleObject obj, const char* name, bool* foundp); +extern JS_PUBLIC_API bool JS_HasOwnProperty(JSContext* cx, JS::HandleObject obj, + const char* name, bool* foundp); /** * Get the value of the property `obj[id]`, or undefined if no such property @@ -3105,13 +2801,17 @@ * * Implements: ES6 [[Get]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_ForwardGetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::HandleValue receiver, JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_ForwardGetElementTo(JSContext* cx, JS::HandleObject obj, uint32_t index, - JS::HandleObject receiver, JS::MutableHandleValue vp); +extern JS_PUBLIC_API bool JS_ForwardGetPropertyTo(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::HandleValue receiver, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API bool JS_ForwardGetElementTo(JSContext* cx, + JS::HandleObject obj, + uint32_t index, + JS::HandleObject receiver, + JS::MutableHandleValue vp); /** * Get the value of the property `obj[id]`, or undefined if no such property @@ -3119,19 +2819,22 @@ * * Implements: ES6 7.3.1 Get(O, P). */ -extern JS_PUBLIC_API(bool) -JS_GetPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_GetProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_GetUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::MutableHandleValue vp); - -extern JS_PUBLIC_API(bool) -JS_GetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp); +extern JS_PUBLIC_API bool JS_GetPropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API bool JS_GetProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API bool JS_GetUCProperty(JSContext* cx, JS::HandleObject obj, + const char16_t* name, size_t namelen, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API bool JS_GetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::MutableHandleValue vp); /** * Perform the same property assignment as `Reflect.set(obj, id, v, receiver)`. @@ -3141,9 +2844,9 @@ * * Implements: ES6 [[Set]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_ForwardSetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, - JS::HandleValue receiver, JS::ObjectOpResult& result); +extern JS_PUBLIC_API bool JS_ForwardSetPropertyTo( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, + JS::HandleValue receiver, JS::ObjectOpResult& result); /** * Perform the assignment `obj[id] = v`. @@ -3151,33 +2854,35 @@ * This function performs non-strict assignment, so if the property is * read-only, nothing happens and no error is thrown. */ -extern JS_PUBLIC_API(bool) -JS_SetPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v); +extern JS_PUBLIC_API bool JS_SetPropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::HandleValue v); -extern JS_PUBLIC_API(bool) -JS_SetProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleValue v); +extern JS_PUBLIC_API bool JS_SetProperty(JSContext* cx, JS::HandleObject obj, + const char* name, JS::HandleValue v); -extern JS_PUBLIC_API(bool) -JS_SetUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::HandleValue v); +extern JS_PUBLIC_API bool JS_SetUCProperty(JSContext* cx, JS::HandleObject obj, + const char16_t* name, size_t namelen, + JS::HandleValue v); -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleValue v); +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, JS::HandleValue v); -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleObject v); +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, JS::HandleObject v); -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleString v); +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, JS::HandleString v); -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, int32_t v); +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, int32_t v); -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, uint32_t v); +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, uint32_t v); -extern JS_PUBLIC_API(bool) -JS_SetElement(JSContext* cx, JS::HandleObject obj, uint32_t index, double v); +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, double v); /** * Delete a property. This is the C++ equivalent of @@ -3190,33 +2895,37 @@ * * Implements: ES6 [[Delete]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_DeletePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::ObjectOpResult& result); - -extern JS_PUBLIC_API(bool) -JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, const char* name, - JS::ObjectOpResult& result); - -extern JS_PUBLIC_API(bool) -JS_DeleteUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::ObjectOpResult& result); - -extern JS_PUBLIC_API(bool) -JS_DeleteElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::ObjectOpResult& result); +extern JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::ObjectOpResult& result); + +extern JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::ObjectOpResult& result); + +extern JS_PUBLIC_API bool JS_DeleteUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, + JS::ObjectOpResult& result); + +extern JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::ObjectOpResult& result); /** * Delete a property, ignoring strict failures. This is the C++ equivalent of * the JS `delete obj[id]` in non-strict mode code. */ -extern JS_PUBLIC_API(bool) -JS_DeletePropertyById(JSContext* cx, JS::HandleObject obj, jsid id); +extern JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx, + JS::HandleObject obj, jsid id); -extern JS_PUBLIC_API(bool) -JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, const char* name); +extern JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, + const char* name); -extern JS_PUBLIC_API(bool) -JS_DeleteElement(JSContext* cx, JS::HandleObject obj, uint32_t index); +extern JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, JS::HandleObject obj, + uint32_t index); /** * Get an array of the non-symbol enumerable properties of obj. @@ -3233,8 +2942,8 @@ * 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); +extern JS_PUBLIC_API bool JS_Enumerate(JSContext* cx, JS::HandleObject obj, + JS::MutableHandle props); /* * API for determining callability and constructability. [[Call]] and @@ -3253,8 +2962,7 @@ * Functions are callable. A scripted proxy or wrapper is callable if its * target is callable. Most other objects aren't callable. */ -extern JS_PUBLIC_API(bool) -IsCallable(JSObject* obj); +extern JS_PUBLIC_API bool IsCallable(JSObject* obj); /** * Return true if the given object is a constructor. In ES6 terms, an object is @@ -3267,8 +2975,7 @@ * functions are not. A scripted proxy or wrapper is a constructor if its * target is a constructor. */ -extern JS_PUBLIC_API(bool) -IsConstructor(JSObject* obj); +extern JS_PUBLIC_API bool IsConstructor(JSObject* obj); } /* namespace JS */ @@ -3279,55 +2986,59 @@ * Implements: ES6 7.3.12 Call(F, V, [argumentsList]). * Use this function to invoke the [[Call]] internal method. */ -extern JS_PUBLIC_API(bool) -JS_CallFunctionValue(JSContext* cx, JS::HandleObject obj, JS::HandleValue fval, - const JS::HandleValueArray& args, JS::MutableHandleValue rval); - -extern JS_PUBLIC_API(bool) -JS_CallFunction(JSContext* cx, JS::HandleObject obj, JS::HandleFunction fun, - const JS::HandleValueArray& args, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool JS_CallFunctionValue(JSContext* cx, + JS::HandleObject obj, + JS::HandleValue fval, + const JS::HandleValueArray& args, + JS::MutableHandleValue rval); + +extern JS_PUBLIC_API bool JS_CallFunction(JSContext* cx, JS::HandleObject obj, + JS::HandleFunction fun, + const JS::HandleValueArray& args, + JS::MutableHandleValue rval); /** * Perform the method call `rval = obj[name](args)`. */ -extern JS_PUBLIC_API(bool) -JS_CallFunctionName(JSContext* cx, JS::HandleObject obj, const char* name, - const JS::HandleValueArray& args, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool JS_CallFunctionName(JSContext* cx, + JS::HandleObject obj, + const char* name, + const JS::HandleValueArray& args, + JS::MutableHandleValue rval); namespace JS { -static inline bool -Call(JSContext* cx, JS::HandleObject thisObj, JS::HandleFunction fun, - const JS::HandleValueArray& args, MutableHandleValue rval) -{ - return !!JS_CallFunction(cx, thisObj, fun, args, rval); +static inline bool Call(JSContext* cx, JS::HandleObject thisObj, + JS::HandleFunction fun, + const JS::HandleValueArray& args, + MutableHandleValue rval) { + return !!JS_CallFunction(cx, thisObj, fun, args, rval); } -static inline bool -Call(JSContext* cx, JS::HandleObject thisObj, JS::HandleValue fun, const JS::HandleValueArray& args, - MutableHandleValue rval) -{ - return !!JS_CallFunctionValue(cx, thisObj, fun, args, rval); +static inline bool Call(JSContext* cx, JS::HandleObject thisObj, + JS::HandleValue fun, const JS::HandleValueArray& args, + MutableHandleValue rval) { + return !!JS_CallFunctionValue(cx, thisObj, fun, args, rval); } -static inline bool -Call(JSContext* cx, JS::HandleObject thisObj, const char* name, const JS::HandleValueArray& args, - MutableHandleValue rval) -{ - return !!JS_CallFunctionName(cx, thisObj, name, args, rval); +static inline bool Call(JSContext* cx, JS::HandleObject thisObj, + const char* name, const JS::HandleValueArray& args, + MutableHandleValue rval) { + return !!JS_CallFunctionName(cx, thisObj, name, args, rval); } -extern JS_PUBLIC_API(bool) -Call(JSContext* cx, JS::HandleValue thisv, JS::HandleValue fun, const JS::HandleValueArray& args, - MutableHandleValue rval); - -static inline bool -Call(JSContext* cx, JS::HandleValue thisv, JS::HandleObject funObj, const JS::HandleValueArray& args, - MutableHandleValue rval) -{ - MOZ_ASSERT(funObj); - JS::RootedValue fun(cx, JS::ObjectValue(*funObj)); - return Call(cx, thisv, fun, args, rval); +extern JS_PUBLIC_API bool Call(JSContext* cx, JS::HandleValue thisv, + JS::HandleValue fun, + const JS::HandleValueArray& args, + MutableHandleValue rval); + +static inline bool Call(JSContext* cx, JS::HandleValue thisv, + JS::HandleObject funObj, + const JS::HandleValueArray& args, + MutableHandleValue rval) { + MOZ_ASSERT(funObj); + JS::RootedValue fun(cx, JS::ObjectValue(*funObj)); + return Call(cx, thisv, fun, args, rval); } /** @@ -3342,9 +3053,10 @@ * Implements: ES6 7.3.13 Construct(F, [argumentsList], [newTarget]). * Use this function to invoke the [[Construct]] internal method. */ -extern JS_PUBLIC_API(bool) -Construct(JSContext* cx, JS::HandleValue fun, HandleObject newTarget, - const JS::HandleValueArray &args, MutableHandleObject objp); +extern JS_PUBLIC_API bool Construct(JSContext* cx, JS::HandleValue fun, + HandleObject newTarget, + const JS::HandleValueArray& args, + MutableHandleObject objp); /** * Invoke a constructor. This is the C++ equivalent of @@ -3353,9 +3065,9 @@ * 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, - MutableHandleObject objp); +extern JS_PUBLIC_API bool Construct(JSContext* cx, JS::HandleValue fun, + const JS::HandleValueArray& args, + MutableHandleObject objp); } /* namespace JS */ @@ -3363,48 +3075,55 @@ * Invoke a constructor, like the JS expression `new ctor(...args)`. Returns * the new object, or null on error. */ -extern JS_PUBLIC_API(JSObject*) -JS_New(JSContext* cx, JS::HandleObject ctor, const JS::HandleValueArray& args); - +extern JS_PUBLIC_API JSObject* JS_New(JSContext* cx, JS::HandleObject ctor, + const JS::HandleValueArray& args); -/*** Other property-defining functions ***********************************************************/ - -extern JS_PUBLIC_API(JSObject*) -JS_DefineObject(JSContext* cx, JS::HandleObject obj, const char* name, - const JSClass* clasp = nullptr, unsigned attrs = 0); - -extern JS_PUBLIC_API(bool) -JS_DefineConstDoubles(JSContext* cx, JS::HandleObject obj, const JSConstDoubleSpec* cds); - -extern JS_PUBLIC_API(bool) -JS_DefineConstIntegers(JSContext* cx, JS::HandleObject obj, const JSConstIntegerSpec* cis); - -extern JS_PUBLIC_API(bool) -JS_DefineProperties(JSContext* cx, JS::HandleObject obj, const JSPropertySpec* ps); +/*** Other property-defining functions **************************************/ +extern JS_PUBLIC_API JSObject* JS_DefineObject(JSContext* cx, + JS::HandleObject obj, + const char* name, + const JSClass* clasp = nullptr, + unsigned attrs = 0); + +extern JS_PUBLIC_API bool JS_DefineConstDoubles(JSContext* cx, + JS::HandleObject obj, + const JSConstDoubleSpec* cds); + +extern JS_PUBLIC_API bool JS_DefineConstIntegers(JSContext* cx, + JS::HandleObject obj, + const JSConstIntegerSpec* cis); + +extern JS_PUBLIC_API bool JS_DefineProperties(JSContext* cx, + JS::HandleObject obj, + const JSPropertySpec* ps); /* * */ -extern JS_PUBLIC_API(bool) -JS_AlreadyHasOwnPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - bool* foundp); - -extern JS_PUBLIC_API(bool) -JS_AlreadyHasOwnProperty(JSContext* cx, JS::HandleObject obj, const char* name, - bool* foundp); - -extern JS_PUBLIC_API(bool) -JS_AlreadyHasOwnUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, - size_t namelen, bool* foundp); - -extern JS_PUBLIC_API(bool) -JS_AlreadyHasOwnElement(JSContext* cx, JS::HandleObject obj, uint32_t index, bool* foundp); +extern JS_PUBLIC_API bool JS_AlreadyHasOwnPropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + bool* foundp); + +extern JS_PUBLIC_API bool JS_AlreadyHasOwnProperty(JSContext* cx, + JS::HandleObject obj, + const char* name, + bool* foundp); + +extern JS_PUBLIC_API bool JS_AlreadyHasOwnUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, + bool* foundp); + +extern JS_PUBLIC_API bool JS_AlreadyHasOwnElement(JSContext* cx, + JS::HandleObject obj, + uint32_t index, bool* foundp); -extern JS_PUBLIC_API(JSObject*) -JS_NewArrayObject(JSContext* cx, const JS::HandleValueArray& contents); +extern JS_PUBLIC_API JSObject* JS_NewArrayObject( + JSContext* cx, const JS::HandleValueArray& contents); -extern JS_PUBLIC_API(JSObject*) -JS_NewArrayObject(JSContext* cx, size_t length); +extern JS_PUBLIC_API JSObject* JS_NewArrayObject(JSContext* cx, size_t length); /** * Returns true and sets |*isArray| indicating whether |value| is an Array @@ -3413,8 +3132,8 @@ * This method returns true with |*isArray == false| when passed a proxy whose * target is an Array, or when passed a revoked proxy. */ -extern JS_PUBLIC_API(bool) -JS_IsArrayObject(JSContext* cx, JS::HandleValue value, bool* isArray); +extern JS_PUBLIC_API bool JS_IsArrayObject(JSContext* cx, JS::HandleValue value, + bool* isArray); /** * Returns true and sets |*isArray| indicating whether |obj| is an Array object @@ -3423,14 +3142,16 @@ * This method returns true with |*isArray == false| when passed a proxy whose * target is an Array, or when passed a revoked proxy. */ -extern JS_PUBLIC_API(bool) -JS_IsArrayObject(JSContext* cx, JS::HandleObject obj, bool* isArray); +extern JS_PUBLIC_API bool JS_IsArrayObject(JSContext* cx, JS::HandleObject obj, + bool* isArray); -extern JS_PUBLIC_API(bool) -JS_GetArrayLength(JSContext* cx, JS::Handle obj, uint32_t* lengthp); - -extern JS_PUBLIC_API(bool) -JS_SetArrayLength(JSContext* cx, JS::Handle obj, uint32_t length); +extern JS_PUBLIC_API bool JS_GetArrayLength(JSContext* cx, + JS::Handle obj, + uint32_t* lengthp); + +extern JS_PUBLIC_API bool JS_SetArrayLength(JSContext* cx, + JS::Handle obj, + uint32_t length); namespace JS { @@ -3441,8 +3162,8 @@ * 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); +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 @@ -3451,8 +3172,8 @@ * 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); +extern JS_PUBLIC_API bool IsSetObject(JSContext* cx, JS::HandleObject obj, + bool* isSet); } /* namespace JS */ @@ -3460,23 +3181,60 @@ * Assign 'undefined' to all of the object's non-reserved slots. Note: this is * done for all slots, regardless of the associated property descriptor. */ -JS_PUBLIC_API(void) -JS_SetAllNonReservedSlotsToUndefined(JSContext* cx, JSObject* objArg); +JS_PUBLIC_API void JS_SetAllNonReservedSlotsToUndefined(JSContext* cx, + JSObject* objArg); /** * Create a new array buffer with the given contents. It must be legal to pass * these contents to free(). On success, the ownership is transferred to the * new array buffer. */ -extern JS_PUBLIC_API(JSObject*) -JS_NewArrayBufferWithContents(JSContext* cx, size_t nbytes, void* contents); +extern JS_PUBLIC_API JSObject* JS_NewArrayBufferWithContents(JSContext* cx, + size_t nbytes, + void* contents); + +namespace JS { + +using BufferContentsRefFunc = void (*)(void* contents, void* userData); + +} /* namespace JS */ /** - * 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. + * Create a new array buffer with the given contents. The ref and unref + * functions should increment or decrement the reference count of the contents. + * These functions allow array buffers to be used with embedder objects that + * use reference counting, for example. The contents must not be modified by + * any reference holders, internal or external. + * + * On success, the new array buffer takes a reference, and |ref(contents, + * refUserData)| will be called. When the array buffer is ready to be disposed + * of, |unref(contents, refUserData)| will be called to release the array + * buffer's reference on the contents. + * + * The ref and unref functions must not call any JSAPI functions that could + * cause a garbage collection. + * + * The ref function is optional. If it is nullptr, the caller is responsible + * for incrementing the reference count before passing the contents to this + * function. This also allows using non-reference-counted contents that must be + * freed with some function other than free(). + * + * The ref function may also be called in case the buffer is cloned in some + * way. Currently this is not used, but it may be in the future. If the ref + * function is nullptr, any operation where an extra reference would otherwise + * be taken, will either copy the data, or throw an exception. + */ +extern JS_PUBLIC_API JSObject* JS_NewExternalArrayBuffer( + JSContext* cx, size_t nbytes, void* contents, JS::BufferContentsRefFunc ref, + JS::BufferContentsRefFunc unref, void* refUserData = nullptr); + +/** + * 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); +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 @@ -3484,42 +3242,46 @@ * of the return value and must free it or transfer ownership via * JS_NewArrayBufferWithContents when done using it. */ -extern JS_PUBLIC_API(void*) -JS_StealArrayBufferContents(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API void* 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. + * 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: + * 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. + * 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. + * 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); +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. */ -extern JS_PUBLIC_API(JSObject*) -JS_NewMappedArrayBufferWithContents(JSContext* cx, size_t nbytes, void* contents); +extern JS_PUBLIC_API JSObject* JS_NewMappedArrayBufferWithContents( + JSContext* cx, size_t nbytes, void* contents); /** * Create memory mapped array buffer contents. * Caller must take care of closing fd after calling this function. */ -extern JS_PUBLIC_API(void*) -JS_CreateMappedArrayBufferContents(int fd, size_t offset, size_t length); +extern JS_PUBLIC_API void* JS_CreateMappedArrayBufferContents(int fd, + size_t offset, + size_t length); /** * Release the allocated resource of mapped array buffer contents before the @@ -3528,30 +3290,28 @@ * with this content, then JS_DetachArrayBuffer() should be used instead to * release the resource used by the object. */ -extern JS_PUBLIC_API(void) -JS_ReleaseMappedArrayBufferContents(void* contents, size_t length); - -extern JS_PUBLIC_API(JS::Value) -JS_GetReservedSlot(JSObject* obj, uint32_t index); +extern JS_PUBLIC_API void JS_ReleaseMappedArrayBufferContents(void* contents, + size_t length); -extern JS_PUBLIC_API(void) -JS_SetReservedSlot(JSObject* obj, uint32_t index, const JS::Value& v); +extern JS_PUBLIC_API JS::Value JS_GetReservedSlot(JSObject* obj, + uint32_t index); +extern JS_PUBLIC_API void JS_SetReservedSlot(JSObject* obj, uint32_t index, + const JS::Value& v); /************************************************************************/ /* * Functions and scripts. */ -extern JS_PUBLIC_API(JSFunction*) -JS_NewFunction(JSContext* cx, JSNative call, unsigned nargs, unsigned flags, - const char* name); +extern JS_PUBLIC_API JSFunction* JS_NewFunction(JSContext* cx, JSNative call, + unsigned nargs, unsigned flags, + const char* name); namespace JS { -extern JS_PUBLIC_API(JSFunction*) -GetSelfHostedFunction(JSContext* cx, const char* selfHostedName, HandleId id, - unsigned nargs); +extern JS_PUBLIC_API JSFunction* GetSelfHostedFunction( + JSContext* cx, const char* selfHostedName, HandleId id, unsigned nargs); /** * Create a new function based on the given JSFunctionSpec, *fs. @@ -3561,13 +3321,13 @@ * Unlike JS_DefineFunctions, this does not treat fs as an array. * *fs must not be JS_FS_END. */ -extern JS_PUBLIC_API(JSFunction*) -NewFunctionFromSpec(JSContext* cx, const JSFunctionSpec* fs, HandleId id); +extern JS_PUBLIC_API JSFunction* NewFunctionFromSpec(JSContext* cx, + const JSFunctionSpec* fs, + HandleId id); } /* namespace JS */ -extern JS_PUBLIC_API(JSObject*) -JS_GetFunctionObject(JSFunction* fun); +extern JS_PUBLIC_API JSObject* JS_GetFunctionObject(JSFunction* fun); /** * Return the function's identifier as a JSString, or null if fun is unnamed. @@ -3575,8 +3335,7 @@ * reference to it if fun is well-connected or rooted, and provided you bound * the use of the saved reference by fun's lifetime. */ -extern JS_PUBLIC_API(JSString*) -JS_GetFunctionId(JSFunction* fun); +extern JS_PUBLIC_API JSString* JS_GetFunctionId(JSFunction* fun); /** * Return a function's display name. This is the defined name if one was given @@ -3585,14 +3344,12 @@ * still return nullptr if a useful display name could not be inferred. The * same restrictions on rooting as those in JS_GetFunctionId apply. */ -extern JS_PUBLIC_API(JSString*) -JS_GetFunctionDisplayId(JSFunction* fun); +extern JS_PUBLIC_API JSString* JS_GetFunctionDisplayId(JSFunction* fun); /* * Return the arity (length) of fun. */ -extern JS_PUBLIC_API(uint16_t) -JS_GetFunctionArity(JSFunction* fun); +extern JS_PUBLIC_API uint16_t JS_GetFunctionArity(JSFunction* fun); /** * Infallible predicate to test whether obj is a function object (faster than @@ -3600,37 +3357,32 @@ * overwritten the "Function" identifier with a different constructor and then * created instances using that constructor that might be passed in as obj). */ -extern JS_PUBLIC_API(bool) -JS_ObjectIsFunction(JSContext* cx, JSObject* obj); +extern JS_PUBLIC_API bool JS_ObjectIsFunction(JSContext* cx, JSObject* obj); -extern JS_PUBLIC_API(bool) -JS_IsNativeFunction(JSObject* funobj, JSNative call); +extern JS_PUBLIC_API bool JS_IsNativeFunction(JSObject* funobj, JSNative call); /** Return whether the given function is a valid constructor. */ -extern JS_PUBLIC_API(bool) -JS_IsConstructor(JSFunction* fun); +extern JS_PUBLIC_API bool JS_IsConstructor(JSFunction* fun); + +extern JS_PUBLIC_API bool 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, + unsigned nargs, unsigned attrs); -extern JS_PUBLIC_API(bool) -JS_DefineFunctions(JSContext* cx, JS::Handle obj, const JSFunctionSpec* fs); +extern JS_PUBLIC_API JSFunction* JS_DefineUCFunction( + JSContext* cx, JS::Handle obj, const char16_t* name, + size_t namelen, JSNative call, unsigned nargs, unsigned attrs); -extern JS_PUBLIC_API(JSFunction*) -JS_DefineFunction(JSContext* cx, JS::Handle obj, const char* name, JSNative call, - unsigned nargs, unsigned attrs); - -extern JS_PUBLIC_API(JSFunction*) -JS_DefineUCFunction(JSContext* cx, JS::Handle obj, - const char16_t* name, size_t namelen, JSNative call, - unsigned nargs, unsigned attrs); - -extern JS_PUBLIC_API(JSFunction*) -JS_DefineFunctionById(JSContext* cx, JS::Handle obj, JS::Handle id, JSNative call, - unsigned nargs, unsigned attrs); +extern JS_PUBLIC_API JSFunction* 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 bool JS_IsFunctionBound(JSFunction* fun); -extern JS_PUBLIC_API(JSObject*) -JS_GetBoundFunctionTarget(JSFunction* fun); +extern JS_PUBLIC_API JSObject* JS_GetBoundFunctionTarget(JSFunction* fun); namespace JS { @@ -3638,18 +3390,18 @@ * Clone a top-level function into cx's global. This function will dynamically * fail if funobj was lexically nested inside some other function. */ -extern JS_PUBLIC_API(JSObject*) -CloneFunctionObject(JSContext* cx, HandleObject funobj); +extern JS_PUBLIC_API JSObject* CloneFunctionObject(JSContext* cx, + HandleObject funobj); /** * As above, but providing an explicit scope chain. scopeChain must not include * the global object on it; that's implicit. It needs to contain the other * objects that should end up on the clone's scope chain. */ -extern JS_PUBLIC_API(JSObject*) -CloneFunctionObject(JSContext* cx, HandleObject funobj, AutoObjectVector& scopeChain); +extern JS_PUBLIC_API JSObject* CloneFunctionObject( + JSContext* cx, HandleObject funobj, AutoObjectVector& scopeChain); -} // namespace JS +} // namespace JS /** * Given a buffer, return false if the buffer might become a valid @@ -3658,37 +3410,37 @@ * lines in a buffer until JS_BufferIsCompilableUnit is true, then pass it to * the compiler. */ -extern JS_PUBLIC_API(bool) -JS_BufferIsCompilableUnit(JSContext* cx, JS::Handle obj, const char* utf8, - size_t length); +extern JS_PUBLIC_API bool JS_BufferIsCompilableUnit(JSContext* cx, + JS::Handle obj, + const char* utf8, + size_t length); /** * |script| will always be set. On failure, it will be set to nullptr. */ -extern JS_PUBLIC_API(bool) -JS_CompileScript(JSContext* cx, const char* ascii, size_t length, - const JS::CompileOptions& options, - JS::MutableHandleScript script); +extern JS_PUBLIC_API bool JS_CompileScript(JSContext* cx, const char* ascii, + size_t length, + const JS::CompileOptions& options, + JS::MutableHandleScript script); /** * |script| will always be set. On failure, it will be set to nullptr. */ -extern JS_PUBLIC_API(bool) -JS_CompileUCScript(JSContext* cx, const char16_t* chars, size_t length, - const JS::CompileOptions& options, - JS::MutableHandleScript script); - -extern JS_PUBLIC_API(JSObject*) -JS_GetGlobalFromScript(JSScript* script); +extern JS_PUBLIC_API bool JS_CompileUCScript(JSContext* cx, + const char16_t* chars, + size_t length, + const JS::CompileOptions& options, + JS::MutableHandleScript script); -extern JS_PUBLIC_API(const char*) -JS_GetScriptFilename(JSScript* script); +extern JS_PUBLIC_API JSObject* JS_GetGlobalFromScript(JSScript* script); -extern JS_PUBLIC_API(unsigned) -JS_GetScriptBaseLineNumber(JSContext* cx, JSScript* script); +extern JS_PUBLIC_API const char* JS_GetScriptFilename(JSScript* script); -extern JS_PUBLIC_API(JSScript*) -JS_GetFunctionScript(JSContext* cx, JS::HandleFunction fun); +extern JS_PUBLIC_API unsigned JS_GetScriptBaseLineNumber(JSContext* cx, + JSScript* script); + +extern JS_PUBLIC_API JSScript* JS_GetFunctionScript(JSContext* cx, + JS::HandleFunction fun); namespace JS { @@ -3715,7 +3467,7 @@ * addrefs/copies/tracing/etc. * * Furthermore, in some cases compile options are propagated from one entity to - * another (e.g. from a scriipt to a function defined in that script). This + * another (e.g. from a script to a function defined in that script). This * involves copying over some, but not all, of the options. * * So, we have a class hierarchy that reflects these four use cases: @@ -3746,92 +3498,88 @@ * Use this in code that needs to propagate compile options from one compilation * unit to another. */ -class JS_FRIEND_API(TransitiveCompileOptions) -{ - protected: - // The Web Platform allows scripts to be loaded from arbitrary cross-origin - // sources. This allows an attack by which a malicious website loads a - // sensitive file (say, a bank statement) cross-origin (using the user's - // cookies), and sniffs the generated syntax errors (via a window.onerror - // handler) for juicy morsels of its contents. - // - // To counter this attack, HTML5 specifies that script errors should be - // sanitized ("muted") when the script is not same-origin with the global - // for which it is loaded. Callers should set this flag for cross-origin - // scripts, and it will be propagated appropriately to child scripts and - // passed back in JSErrorReports. - bool mutedErrors_; - const char* filename_; - const char* introducerFilename_; - const char16_t* sourceMapURL_; - - // This constructor leaves 'version' set to JSVERSION_UNKNOWN. The structure - // is unusable until that's set to something more specific; the derived - // classes' constructors take care of that, in ways appropriate to their - // purpose. - TransitiveCompileOptions() +class JS_FRIEND_API TransitiveCompileOptions { + protected: + // The Web Platform allows scripts to be loaded from arbitrary cross-origin + // sources. This allows an attack by which a malicious website loads a + // sensitive file (say, a bank statement) cross-origin (using the user's + // cookies), and sniffs the generated syntax errors (via a window.onerror + // handler) for juicy morsels of its contents. + // + // To counter this attack, HTML5 specifies that script errors should be + // sanitized ("muted") when the script is not same-origin with the global + // for which it is loaded. Callers should set this flag for cross-origin + // scripts, and it will be propagated appropriately to child scripts and + // passed back in JSErrorReports. + bool mutedErrors_; + const char* filename_; + const char* introducerFilename_; + const char16_t* sourceMapURL_; + + TransitiveCompileOptions() : mutedErrors_(false), filename_(nullptr), introducerFilename_(nullptr), sourceMapURL_(nullptr), - version(JSVERSION_UNKNOWN), - versionSet(false), utf8(false), selfHostingMode(false), canLazilyParse(true), strictOption(false), extraWarningsOption(false), + expressionClosuresOption(false), werrorOption(false), asmJSOption(AsmJSOption::Disabled), throwOnAsmJSValidationFailureOption(false), forceAsync(false), - installedFile(false), sourceIsLazy(false), + allowHTMLComments(true), + isProbablySystemOrAddonCode(false), + hideScriptFromDebugger(false), introductionType(nullptr), introductionLineno(0), introductionOffset(0), - hasIntroductionInfo(false) - { } + hasIntroductionInfo(false) {} - // Set all POD options (those not requiring reference counts, copies, - // rooting, or other hand-holding) to their values in |rhs|. - void copyPODTransitiveOptions(const TransitiveCompileOptions& rhs); - - public: - // Read-only accessors for non-POD options. The proper way to set these - // depends on the derived type. - bool mutedErrors() const { return mutedErrors_; } - const char* filename() const { return filename_; } - const char* introducerFilename() const { return introducerFilename_; } - const char16_t* sourceMapURL() const { return sourceMapURL_; } - virtual JSObject* element() const = 0; - virtual JSString* elementAttributeName() const = 0; - virtual JSScript* introductionScript() const = 0; - - // POD options. - JSVersion version; - bool versionSet; - bool utf8; - bool selfHostingMode; - bool canLazilyParse; - bool strictOption; - bool extraWarningsOption; - bool werrorOption; - AsmJSOption asmJSOption; - bool throwOnAsmJSValidationFailureOption; - bool forceAsync; - bool installedFile; // 'true' iff pre-compiling js file in packaged app - bool sourceIsLazy; - - // |introductionType| is a statically allocated C string: - // one of "eval", "Function", or "GeneratorFunction". - const char* introductionType; - unsigned introductionLineno; - uint32_t introductionOffset; - bool hasIntroductionInfo; + // Set all POD options (those not requiring reference counts, copies, + // rooting, or other hand-holding) to their values in |rhs|. + void copyPODTransitiveOptions(const TransitiveCompileOptions& rhs); + + public: + // Read-only accessors for non-POD options. The proper way to set these + // depends on the derived type. + bool mutedErrors() const { return mutedErrors_; } + const char* filename() const { return filename_; } + const char* introducerFilename() const { return introducerFilename_; } + const char16_t* sourceMapURL() const { return sourceMapURL_; } + virtual JSObject* element() const = 0; + virtual JSString* elementAttributeName() const = 0; + virtual JSScript* introductionScript() const = 0; + + // POD options. + bool utf8; + bool selfHostingMode; + bool canLazilyParse; + bool strictOption; + bool extraWarningsOption; + bool expressionClosuresOption; + bool werrorOption; + AsmJSOption asmJSOption; + bool throwOnAsmJSValidationFailureOption; + bool forceAsync; + bool sourceIsLazy; + bool allowHTMLComments; + bool isProbablySystemOrAddonCode; + bool hideScriptFromDebugger; + + // |introductionType| is a statically allocated C string: + // one of "eval", "Function", or "GeneratorFunction". + const char* introductionType; + unsigned introductionLineno; + uint32_t introductionOffset; + bool hasIntroductionInfo; - private: - void operator=(const TransitiveCompileOptions&) = delete; + private: + void operator=(const TransitiveCompileOptions&) = delete; }; /** @@ -3842,43 +3590,56 @@ * is protected anyway); instead, create instances only of the derived classes: * CompileOptions and OwningCompileOptions. */ -class JS_FRIEND_API(ReadOnlyCompileOptions) : public TransitiveCompileOptions -{ - friend class CompileOptions; +class JS_FRIEND_API ReadOnlyCompileOptions : public TransitiveCompileOptions { + friend class CompileOptions; - protected: - ReadOnlyCompileOptions() + protected: + ReadOnlyCompileOptions() : TransitiveCompileOptions(), lineno(1), column(0), + scriptSourceOffset(0), isRunOnce(false), - noScriptRval(false) - { } + nonSyntacticScope(false), + noScriptRval(false) {} - // Set all POD options (those not requiring reference counts, copies, - // rooting, or other hand-holding) to their values in |rhs|. - void copyPODOptions(const ReadOnlyCompileOptions& rhs); - - public: - // Read-only accessors for non-POD options. The proper way to set these - // depends on the derived type. - bool mutedErrors() const { return mutedErrors_; } - const char* filename() const { return filename_; } - const char* introducerFilename() const { return introducerFilename_; } - const char16_t* sourceMapURL() const { return sourceMapURL_; } - virtual JSObject* element() const = 0; - virtual JSString* elementAttributeName() const = 0; - virtual JSScript* introductionScript() const = 0; - - // POD options. - unsigned lineno; - unsigned column; - // isRunOnce only applies to non-function scripts. - bool isRunOnce; - bool noScriptRval; + // Set all POD options (those not requiring reference counts, copies, + // rooting, or other hand-holding) to their values in |rhs|. + void copyPODOptions(const ReadOnlyCompileOptions& rhs); + + public: + // Read-only accessors for non-POD options. The proper way to set these + // depends on the derived type. + bool mutedErrors() const { return mutedErrors_; } + const char* filename() const { return filename_; } + const char* introducerFilename() const { return introducerFilename_; } + const char16_t* sourceMapURL() const { return sourceMapURL_; } + virtual JSObject* element() const override = 0; + virtual JSString* elementAttributeName() const override = 0; + virtual JSScript* introductionScript() const override = 0; + + // POD options. + unsigned lineno; + unsigned column; + // The offset within the ScriptSource's full uncompressed text of the first + // character we're presenting for compilation with this CompileOptions. + // + // When we compile a LazyScript, we pass the compiler only the substring of + // the source the lazy function occupies. With chunked decompression, we + // may not even have the complete uncompressed source present in memory. But + // parse node positions are offsets within the ScriptSource's full text, + // and LazyScripts indicate their substring of the full source by its + // starting and ending offsets within the full text. This + // scriptSourceOffset field lets the frontend convert between these + // offsets and offsets within the substring presented for compilation. + unsigned scriptSourceOffset; + // isRunOnce only applies to non-function scripts. + bool isRunOnce; + bool nonSyntacticScope; + bool noScriptRval; - private: - void operator=(const ReadOnlyCompileOptions&) = delete; + private: + void operator=(const ReadOnlyCompileOptions&) = delete; }; /** @@ -3894,79 +3655,108 @@ * comes to refer to the object that owns this, then the whole cycle, and * anything else it entrains, will never be freed. */ -class JS_FRIEND_API(OwningCompileOptions) : public ReadOnlyCompileOptions -{ - PersistentRootedObject elementRoot; - PersistentRootedString elementAttributeNameRoot; - PersistentRootedScript introductionScriptRoot; - - public: - // A minimal constructor, for use with OwningCompileOptions::copy. This - // leaves |this.version| set to JSVERSION_UNKNOWN; the instance - // shouldn't be used until we've set that to something real (as |copy| - // will). - explicit OwningCompileOptions(JSContext* cx); - ~OwningCompileOptions(); - - JSObject* element() const override { return elementRoot; } - JSString* elementAttributeName() const override { return elementAttributeNameRoot; } - JSScript* introductionScript() const override { return introductionScriptRoot; } - - // Set this to a copy of |rhs|. Return false on OOM. - bool copy(JSContext* cx, const ReadOnlyCompileOptions& rhs); - - /* These setters make copies of their string arguments, and are fallible. */ - bool setFile(JSContext* cx, const char* f); - bool setFileAndLine(JSContext* cx, const char* f, unsigned l); - bool setSourceMapURL(JSContext* cx, const char16_t* s); - bool setIntroducerFilename(JSContext* cx, const char* s); - - /* These setters are infallible, and can be chained. */ - OwningCompileOptions& setLine(unsigned l) { lineno = l; return *this; } - OwningCompileOptions& setElement(JSObject* e) { - elementRoot = e; - return *this; - } - OwningCompileOptions& setElementAttributeName(JSString* p) { - elementAttributeNameRoot = p; - return *this; - } - OwningCompileOptions& setIntroductionScript(JSScript* s) { - introductionScriptRoot = s; - return *this; - } - OwningCompileOptions& setMutedErrors(bool mute) { - mutedErrors_ = mute; - return *this; - } - OwningCompileOptions& setVersion(JSVersion v) { - version = v; - versionSet = true; - return *this; - } - 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& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } - OwningCompileOptions& setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; } - OwningCompileOptions& setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; } - OwningCompileOptions& setSourceIsLazy(bool l) { sourceIsLazy = l; return *this; } - OwningCompileOptions& setIntroductionType(const char* t) { introductionType = t; return *this; } - bool setIntroductionInfo(JSContext* cx, const char* introducerFn, const char* intro, - unsigned line, JSScript* script, uint32_t offset) - { - if (!setIntroducerFilename(cx, introducerFn)) - return false; - introductionType = intro; - introductionLineno = line; - introductionScriptRoot = script; - introductionOffset = offset; - hasIntroductionInfo = true; - return true; - } +class JS_FRIEND_API OwningCompileOptions : public ReadOnlyCompileOptions { + PersistentRootedObject elementRoot; + PersistentRootedString elementAttributeNameRoot; + PersistentRootedScript introductionScriptRoot; + + public: + // A minimal constructor, for use with OwningCompileOptions::copy. + explicit OwningCompileOptions(JSContext* cx); + ~OwningCompileOptions(); + + JSObject* element() const override { return elementRoot; } + JSString* elementAttributeName() const override { + return elementAttributeNameRoot; + } + JSScript* introductionScript() const override { + return introductionScriptRoot; + } + + // Set this to a copy of |rhs|. Return false on OOM. + bool copy(JSContext* cx, const ReadOnlyCompileOptions& rhs); + + /* These setters make copies of their string arguments, and are fallible. */ + bool setFile(JSContext* cx, const char* f); + bool setFileAndLine(JSContext* cx, const char* f, unsigned l); + bool setSourceMapURL(JSContext* cx, const char16_t* s); + bool setIntroducerFilename(JSContext* cx, const char* s); + + /* These setters are infallible, and can be chained. */ + OwningCompileOptions& setLine(unsigned l) { + lineno = l; + return *this; + } + OwningCompileOptions& setElement(JSObject* e) { + elementRoot = e; + return *this; + } + OwningCompileOptions& setElementAttributeName(JSString* p) { + elementAttributeNameRoot = p; + return *this; + } + OwningCompileOptions& setIntroductionScript(JSScript* s) { + introductionScriptRoot = s; + return *this; + } + OwningCompileOptions& setMutedErrors(bool mute) { + mutedErrors_ = mute; + return *this; + } + OwningCompileOptions& setUTF8(bool u) { + utf8 = u; + return *this; + } + OwningCompileOptions& setColumn(unsigned c) { + column = c; + return *this; + } + OwningCompileOptions& setScriptSourceOffset(unsigned o) { + scriptSourceOffset = o; + return *this; + } + OwningCompileOptions& setIsRunOnce(bool once) { + isRunOnce = once; + return *this; + } + OwningCompileOptions& setNoScriptRval(bool nsr) { + noScriptRval = nsr; + return *this; + } + OwningCompileOptions& setSelfHostingMode(bool shm) { + selfHostingMode = shm; + return *this; + } + OwningCompileOptions& setCanLazilyParse(bool clp) { + canLazilyParse = clp; + return *this; + } + OwningCompileOptions& setSourceIsLazy(bool l) { + sourceIsLazy = l; + return *this; + } + OwningCompileOptions& setNonSyntacticScope(bool n) { + nonSyntacticScope = n; + return *this; + } + OwningCompileOptions& setIntroductionType(const char* t) { + introductionType = t; + return *this; + } + bool setIntroductionInfo(JSContext* cx, const char* introducerFn, + const char* intro, unsigned line, JSScript* script, + uint32_t offset) { + if (!setIntroducerFilename(cx, introducerFn)) return false; + introductionType = intro; + introductionLineno = line; + introductionScriptRoot = script; + introductionOffset = offset; + hasIntroductionInfo = true; + return true; + } - private: - void operator=(const CompileOptions& rhs) = delete; + private: + void operator=(const CompileOptions& rhs) = delete; }; /** @@ -3976,152 +3766,206 @@ * 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) final : public ReadOnlyCompileOptions -{ - RootedObject elementRoot; - RootedString elementAttributeNameRoot; - RootedScript introductionScriptRoot; - - public: - explicit CompileOptions(JSContext* cx, JSVersion version = JSVERSION_UNKNOWN); - CompileOptions(js::ContextFriendFields* cx, const ReadOnlyCompileOptions& rhs) - : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx), - introductionScriptRoot(cx) - { - copyPODOptions(rhs); - - filename_ = rhs.filename(); - introducerFilename_ = rhs.introducerFilename(); - sourceMapURL_ = rhs.sourceMapURL(); - elementRoot = rhs.element(); - elementAttributeNameRoot = rhs.elementAttributeName(); - introductionScriptRoot = rhs.introductionScript(); - } - - CompileOptions(js::ContextFriendFields* cx, const TransitiveCompileOptions& rhs) - : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx), - introductionScriptRoot(cx) - { - copyPODTransitiveOptions(rhs); - - filename_ = rhs.filename(); - introducerFilename_ = rhs.introducerFilename(); - sourceMapURL_ = rhs.sourceMapURL(); - elementRoot = rhs.element(); - elementAttributeNameRoot = rhs.elementAttributeName(); - introductionScriptRoot = rhs.introductionScript(); - } +class MOZ_STACK_CLASS JS_FRIEND_API CompileOptions final + : public ReadOnlyCompileOptions { + RootedObject elementRoot; + RootedString elementAttributeNameRoot; + RootedScript introductionScriptRoot; + + public: + explicit CompileOptions(JSContext* cx); + CompileOptions(JSContext* cx, const ReadOnlyCompileOptions& rhs) + : ReadOnlyCompileOptions(), + elementRoot(cx), + elementAttributeNameRoot(cx), + introductionScriptRoot(cx) { + copyPODOptions(rhs); + + filename_ = rhs.filename(); + introducerFilename_ = rhs.introducerFilename(); + sourceMapURL_ = rhs.sourceMapURL(); + elementRoot = rhs.element(); + elementAttributeNameRoot = rhs.elementAttributeName(); + introductionScriptRoot = rhs.introductionScript(); + } + + CompileOptions(JSContext* cx, const TransitiveCompileOptions& rhs) + : ReadOnlyCompileOptions(), + elementRoot(cx), + elementAttributeNameRoot(cx), + introductionScriptRoot(cx) { + copyPODTransitiveOptions(rhs); + + filename_ = rhs.filename(); + introducerFilename_ = rhs.introducerFilename(); + sourceMapURL_ = rhs.sourceMapURL(); + elementRoot = rhs.element(); + elementAttributeNameRoot = rhs.elementAttributeName(); + introductionScriptRoot = rhs.introductionScript(); + } + + JSObject* element() const override { return elementRoot; } + JSString* elementAttributeName() const override { + return elementAttributeNameRoot; + } + JSScript* introductionScript() const override { + return introductionScriptRoot; + } + + CompileOptions& setFile(const char* f) { + filename_ = f; + return *this; + } + CompileOptions& setLine(unsigned l) { + lineno = l; + return *this; + } + CompileOptions& setFileAndLine(const char* f, unsigned l) { + filename_ = f; + lineno = l; + return *this; + } + CompileOptions& setSourceMapURL(const char16_t* s) { + sourceMapURL_ = s; + return *this; + } + CompileOptions& setElement(JSObject* e) { + elementRoot = e; + return *this; + } + CompileOptions& setElementAttributeName(JSString* p) { + elementAttributeNameRoot = p; + return *this; + } + CompileOptions& setIntroductionScript(JSScript* s) { + introductionScriptRoot = s; + return *this; + } + CompileOptions& setMutedErrors(bool mute) { + mutedErrors_ = mute; + return *this; + } + CompileOptions& setUTF8(bool u) { + utf8 = u; + return *this; + } + CompileOptions& setColumn(unsigned c) { + column = c; + return *this; + } + CompileOptions& setScriptSourceOffset(unsigned o) { + scriptSourceOffset = o; + return *this; + } + CompileOptions& setIsRunOnce(bool once) { + isRunOnce = once; + return *this; + } + CompileOptions& setNoScriptRval(bool nsr) { + noScriptRval = nsr; + return *this; + } + CompileOptions& setSelfHostingMode(bool shm) { + selfHostingMode = shm; + return *this; + } + CompileOptions& setCanLazilyParse(bool clp) { + canLazilyParse = clp; + return *this; + } + CompileOptions& setSourceIsLazy(bool l) { + sourceIsLazy = l; + return *this; + } + CompileOptions& setNonSyntacticScope(bool n) { + nonSyntacticScope = n; + return *this; + } + CompileOptions& setIntroductionType(const char* t) { + introductionType = t; + return *this; + } + CompileOptions& setIntroductionInfo(const char* introducerFn, + const char* intro, unsigned line, + JSScript* script, uint32_t offset) { + introducerFilename_ = introducerFn; + introductionType = intro; + introductionLineno = line; + introductionScriptRoot = script; + introductionOffset = offset; + hasIntroductionInfo = true; + return *this; + } + CompileOptions& maybeMakeStrictMode(bool strict) { + strictOption = strictOption || strict; + return *this; + } - JSObject* element() const override { return elementRoot; } - JSString* elementAttributeName() const override { return elementAttributeNameRoot; } - JSScript* introductionScript() const override { return introductionScriptRoot; } - - CompileOptions& setFile(const char* f) { filename_ = f; return *this; } - CompileOptions& setLine(unsigned l) { lineno = l; return *this; } - CompileOptions& setFileAndLine(const char* f, unsigned l) { - filename_ = f; lineno = l; return *this; - } - CompileOptions& setSourceMapURL(const char16_t* s) { sourceMapURL_ = s; return *this; } - CompileOptions& setElement(JSObject* e) { elementRoot = e; return *this; } - CompileOptions& setElementAttributeName(JSString* p) { - elementAttributeNameRoot = p; - return *this; - } - CompileOptions& setIntroductionScript(JSScript* s) { - introductionScriptRoot = s; - return *this; - } - CompileOptions& setMutedErrors(bool mute) { - mutedErrors_ = mute; - return *this; - } - CompileOptions& setVersion(JSVersion v) { - version = v; - versionSet = true; - return *this; - } - 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& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } - CompileOptions& setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; } - CompileOptions& setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; } - CompileOptions& setSourceIsLazy(bool l) { sourceIsLazy = l; return *this; } - CompileOptions& setIntroductionType(const char* t) { introductionType = t; return *this; } - CompileOptions& setIntroductionInfo(const char* introducerFn, const char* intro, - unsigned line, JSScript* script, uint32_t offset) - { - introducerFilename_ = introducerFn; - introductionType = intro; - introductionLineno = line; - introductionScriptRoot = script; - introductionOffset = offset; - hasIntroductionInfo = true; - return *this; - } - CompileOptions& maybeMakeStrictMode(bool strict) { - strictOption = strictOption || strict; - return *this; - } - - private: - void operator=(const CompileOptions& rhs) = delete; + private: + void operator=(const CompileOptions& rhs) = delete; }; /** * |script| will always be set. On failure, it will be set to nullptr. */ -extern JS_PUBLIC_API(bool) -Compile(JSContext* cx, const ReadOnlyCompileOptions& options, - SourceBufferHolder& srcBuf, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -Compile(JSContext* cx, const ReadOnlyCompileOptions& options, - const char* bytes, size_t length, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -Compile(JSContext* cx, const ReadOnlyCompileOptions& options, - const char16_t* chars, size_t length, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -Compile(JSContext* cx, const ReadOnlyCompileOptions& options, - FILE* file, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -Compile(JSContext* cx, const ReadOnlyCompileOptions& options, - const char* filename, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, - SourceBufferHolder& srcBuf, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, - const char* bytes, size_t length, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, - const char16_t* chars, size_t length, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, - FILE* file, JS::MutableHandleScript script); - -extern JS_PUBLIC_API(bool) -CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, - const char* filename, JS::MutableHandleScript script); +extern JS_PUBLIC_API bool Compile(JSContext* cx, + const ReadOnlyCompileOptions& options, + SourceBufferHolder& srcBuf, + JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool Compile(JSContext* cx, + const ReadOnlyCompileOptions& options, + const char* bytes, size_t length, + JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool Compile(JSContext* cx, + const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool Compile(JSContext* cx, + const ReadOnlyCompileOptions& options, + FILE* file, JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool Compile(JSContext* cx, + const ReadOnlyCompileOptions& options, + const char* filename, + JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool CompileForNonSyntacticScope( + JSContext* cx, const ReadOnlyCompileOptions& options, + SourceBufferHolder& srcBuf, JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool CompileForNonSyntacticScope( + JSContext* cx, const ReadOnlyCompileOptions& options, const char* bytes, + size_t length, JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool CompileForNonSyntacticScope( + JSContext* cx, const ReadOnlyCompileOptions& options, const char16_t* chars, + size_t length, JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool CompileForNonSyntacticScope( + JSContext* cx, const ReadOnlyCompileOptions& options, FILE* file, + JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool CompileForNonSyntacticScope( + JSContext* cx, const ReadOnlyCompileOptions& options, const char* filename, + JS::MutableHandleScript script); + +extern JS_PUBLIC_API bool CanCompileOffThread( + JSContext* cx, const ReadOnlyCompileOptions& options, size_t length); -extern JS_PUBLIC_API(bool) -CanCompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, size_t length); +extern JS_PUBLIC_API bool CanDecodeOffThread( + JSContext* cx, const ReadOnlyCompileOptions& options, size_t length); /* * Off thread compilation control flow. * * After successfully triggering an off thread compile of a script, the * callback will eventually be invoked with the specified data and a token - * for the compilation. The callback will be invoked while off the main thread, + * for the compilation. The callback will be invoked while off thread, * so must ensure that its operations are thread safe. Afterwards, one of the - * following functions must be invoked on the main thread: + * following functions must be invoked on the runtime's active thread: * * - FinishOffThreadScript, to get the result script (or nullptr on failure). * - CancelOffThreadScript, to free the resources without creating a script. @@ -4131,27 +3975,50 @@ * to FinishOffThreadScript. */ -extern JS_PUBLIC_API(bool) -CompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, - const char16_t* chars, size_t length, - OffThreadCompileCallback callback, void* callbackData); - -extern JS_PUBLIC_API(JSScript*) -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 bool CompileOffThread( + JSContext* cx, const ReadOnlyCompileOptions& options, const char16_t* chars, + size_t length, OffThreadCompileCallback callback, void* callbackData); + +extern JS_PUBLIC_API JSScript* 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); + +extern JS_PUBLIC_API bool DecodeOffThreadScript( + JSContext* cx, const ReadOnlyCompileOptions& options, + mozilla::Vector& buffer /* TranscodeBuffer& */, size_t cursor, + OffThreadCompileCallback callback, void* callbackData); + +extern JS_PUBLIC_API bool DecodeOffThreadScript( + JSContext* cx, const ReadOnlyCompileOptions& options, + const mozilla::Range& range /* TranscodeRange& */, + OffThreadCompileCallback callback, void* callbackData); + +extern JS_PUBLIC_API JSScript* FinishOffThreadScriptDecoder(JSContext* cx, + void* token); + +extern JS_PUBLIC_API void CancelOffThreadScriptDecoder(JSContext* cx, + void* token); -extern JS_PUBLIC_API(JSObject*) -FinishOffThreadModule(JSContext* cx, void* token); +extern JS_PUBLIC_API bool DecodeMultiOffThreadScripts( + JSContext* cx, const ReadOnlyCompileOptions& options, + mozilla::Vector& sources, + OffThreadCompileCallback callback, void* callbackData); -extern JS_PUBLIC_API(void) -CancelOffThreadModule(JSContext* cx, void* token); +extern JS_PUBLIC_API bool FinishMultiOffThreadScriptsDecoder( + JSContext* cx, void* token, JS::MutableHandle scripts); + +extern JS_PUBLIC_API void CancelMultiOffThreadScriptsDecoder(JSContext* cx, + void* token); /** * Compile a function with envChain plus the global as its scope chain. @@ -4160,44 +4027,59 @@ * 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& envChain, - const ReadOnlyCompileOptions& options, - const char* name, unsigned nargs, const char* const* argnames, - const char16_t* chars, size_t length, JS::MutableHandleFunction fun); +extern JS_PUBLIC_API bool 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); /** * Same as above, but taking a SourceBufferHolder for the function body. */ -extern JS_PUBLIC_API(bool) -CompileFunction(JSContext* cx, AutoObjectVector& envChain, - const ReadOnlyCompileOptions& options, - const char* name, unsigned nargs, const char* const* argnames, - SourceBufferHolder& srcBuf, JS::MutableHandleFunction fun); +extern JS_PUBLIC_API bool CompileFunction(JSContext* cx, + AutoObjectVector& envChain, + const ReadOnlyCompileOptions& options, + const char* name, unsigned nargs, + const char* const* argnames, + SourceBufferHolder& srcBuf, + JS::MutableHandleFunction fun); /** * Same as above, but taking a const char * for the function body. */ -extern JS_PUBLIC_API(bool) -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); - -} /* namespace JS */ +extern JS_PUBLIC_API bool 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); -extern JS_PUBLIC_API(JSString*) -JS_DecompileScript(JSContext* cx, JS::Handle script, const char* name, unsigned indent); +/* + * Associate an element wrapper and attribute name with a previously compiled + * script, for debugging purposes. Calling this function is optional, but should + * be done before script execution if it is required. + */ +extern JS_PUBLIC_API bool InitScriptSourceElement( + JSContext* cx, HandleScript script, HandleObject element, + HandleString elementAttrName = nullptr); /* - * API extension: OR this into indent to avoid pretty-printing the decompiled - * source resulting from JS_DecompileFunction. + * For a script compiled with the hideScriptFromDebugger option, expose the + * script to the debugger by calling the debugger's onNewScript hook. */ -#define JS_DONT_PRETTY_PRINT ((unsigned)0x8000) +extern JS_PUBLIC_API void ExposeScriptToDebugger(JSContext* cx, + HandleScript script); -extern JS_PUBLIC_API(JSString*) -JS_DecompileFunction(JSContext* cx, JS::Handle fun, unsigned indent); +} /* namespace JS */ + +extern JS_PUBLIC_API JSString* JS_DecompileScript(JSContext* cx, + JS::Handle script); +extern JS_PUBLIC_API JSString* JS_DecompileFunction( + JSContext* cx, JS::Handle fun); /* * NB: JS_ExecuteScript and the JS::Evaluate APIs come in two flavors: either @@ -4219,33 +4101,46 @@ /** * Evaluate a script in the scope of the current global of cx. */ -extern JS_PUBLIC_API(bool) -JS_ExecuteScript(JSContext* cx, JS::HandleScript script, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx, + JS::HandleScript script, + JS::MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -JS_ExecuteScript(JSContext* cx, JS::HandleScript script); +extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx, + JS::HandleScript script); /** * As above, but providing an explicit scope chain. envChain must not include * the global object on it; that's implicit. It needs to contain the other * objects that should end up on the script's scope chain. */ -extern JS_PUBLIC_API(bool) -JS_ExecuteScript(JSContext* cx, JS::AutoObjectVector& envChain, - JS::HandleScript script, JS::MutableHandleValue rval); - -extern JS_PUBLIC_API(bool) -JS_ExecuteScript(JSContext* cx, JS::AutoObjectVector& envChain, JS::HandleScript script); +extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx, + JS::AutoObjectVector& envChain, + JS::HandleScript script, + JS::MutableHandleValue rval); + +extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx, + JS::AutoObjectVector& envChain, + JS::HandleScript script); namespace JS { /** * Like the above, but handles a cross-compartment script. If the script is - * cross-compartment, it is cloned into the current compartment before executing. + * cross-compartment, it is cloned into the current compartment before + * executing. + */ +extern JS_PUBLIC_API bool CloneAndExecuteScript(JSContext* cx, + JS::Handle script, + JS::MutableHandleValue rval); + +/** + * Like CloneAndExecuteScript above, but allows executing under a non-syntactic + * environment chain. */ -extern JS_PUBLIC_API(bool) -CloneAndExecuteScript(JSContext* cx, JS::Handle script, - JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool CloneAndExecuteScript(JSContext* cx, + JS::AutoObjectVector& envChain, + JS::Handle script, + JS::MutableHandleValue rval); } /* namespace JS */ @@ -4254,127 +4149,141 @@ /** * Evaluate the given source buffer in the scope of the current global of cx. */ -extern JS_PUBLIC_API(bool) -Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, - SourceBufferHolder& srcBuf, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool Evaluate(JSContext* cx, + const ReadOnlyCompileOptions& options, + SourceBufferHolder& srcBuf, + JS::MutableHandleValue rval); /** * As above, but providing an explicit scope chain. envChain must not include * the global object on it; that's implicit. It needs to contain the other * objects that should end up on the script's scope chain. */ -extern JS_PUBLIC_API(bool) -Evaluate(JSContext* cx, AutoObjectVector& envChain, const ReadOnlyCompileOptions& options, - SourceBufferHolder& srcBuf, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool Evaluate(JSContext* cx, AutoObjectVector& envChain, + const ReadOnlyCompileOptions& options, + SourceBufferHolder& srcBuf, + JS::MutableHandleValue rval); /** * Evaluate the given character buffer in the scope of the current global of cx. */ -extern JS_PUBLIC_API(bool) -Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, - const char16_t* chars, size_t length, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool Evaluate(JSContext* cx, + const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + JS::MutableHandleValue rval); /** * As above, but providing an explicit scope chain. envChain must not include * the global object on it; that's implicit. It needs to contain the other * objects that should end up on the script's scope chain. */ -extern JS_PUBLIC_API(bool) -Evaluate(JSContext* cx, AutoObjectVector& envChain, const ReadOnlyCompileOptions& options, - const char16_t* chars, size_t length, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool Evaluate(JSContext* cx, AutoObjectVector& envChain, + const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + JS::MutableHandleValue rval); /** * Evaluate the given byte buffer in the scope of the current global of cx. */ -extern JS_PUBLIC_API(bool) -Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, - const char* bytes, size_t length, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool Evaluate(JSContext* cx, + const ReadOnlyCompileOptions& options, + const char* bytes, size_t length, + JS::MutableHandleValue rval); /** * Evaluate the given file in the scope of the current global of cx. */ -extern JS_PUBLIC_API(bool) -Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, - const char* filename, JS::MutableHandleValue rval); +extern JS_PUBLIC_API bool 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); +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); +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); +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); +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); +extern JS_PUBLIC_API JS::Value GetModuleHostDefinedField(JSObject* module); /* - * Perform the ModuleDeclarationInstantiation operation on on the give source - * text module record. + * Perform the ModuleInstantiate operation on the given 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); +extern JS_PUBLIC_API bool ModuleInstantiate(JSContext* cx, + JS::HandleObject moduleRecord); /* - * Perform the ModuleEvaluation operation on on the give source text module - * record. + * Perform the ModuleEvaluate operation on the given 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. + * ModuleInstantiate must have completed prior to calling this. */ -extern JS_PUBLIC_API(bool) -ModuleEvaluation(JSContext* cx, JS::HandleObject moduleRecord); +extern JS_PUBLIC_API bool ModuleEvaluate(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. + * The result is a JavaScript array of object values. To extract the individual + * values use only JS_GetArrayLength and JS_GetElement with indices 0 to length + * - 1. + * + * The element values are objects with the following properties: + * - moduleSpecifier: the module specifier string + * - lineNumber: the line number of the import in the source text + * - columnNumber: the column number of the import in the source text + * + * These property values can be extracted with GetRequestedModuleSpecifier() and + * GetRequestedModuleSourcePos() */ -extern JS_PUBLIC_API(JSObject*) -GetRequestedModules(JSContext* cx, JS::HandleObject moduleRecord); +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); +extern JS_PUBLIC_API JSString* GetRequestedModuleSpecifier( + JSContext* cx, JS::HandleValue requestedModuleObject); + +extern JS_PUBLIC_API void GetRequestedModuleSourcePos( + JSContext* cx, JS::HandleValue requestedModuleObject, uint32_t* lineNumber, + uint32_t* columnNumber); + +extern JS_PUBLIC_API JSScript* GetModuleScript(JS::HandleObject moduleRecord); } /* namespace JS */ -extern JS_PUBLIC_API(bool) -JS_CheckForInterrupt(JSContext* cx); +extern JS_PUBLIC_API bool JS_CheckForInterrupt(JSContext* cx); /* * These functions allow setting an interrupt callback that will be called @@ -4389,17 +4298,16 @@ * 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(bool) -JS_AddInterruptCallback(JSContext* cx, 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(bool) -JS_DisableInterruptCallback(JSContext* cx); +extern JS_PUBLIC_API void JS_ResetInterruptCallback(JSContext* cx, bool enable); -extern JS_PUBLIC_API(void) -JS_ResetInterruptCallback(JSContext* cx, bool enable); +extern JS_PUBLIC_API void JS_RequestInterruptCallback(JSContext* cx); -extern JS_PUBLIC_API(void) -JS_RequestInterruptCallback(JSContext* cx); +extern JS_PUBLIC_API void JS_RequestInterruptCallbackCanWait(JSContext* cx); namespace JS { @@ -4410,8 +4318,8 @@ * 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 void SetGetIncumbentGlobalCallback( + JSContext* cx, JSGetIncumbentGlobalCallback callback); /** * Sets the callback that's invoked whenever a Promise job should be enqeued. @@ -4422,53 +4330,50 @@ * 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); +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) -SetPromiseRejectionTrackerCallback(JSContext* cx, JSPromiseRejectionTrackerCallback callback, - void* data = nullptr); +extern JS_PUBLIC_API void 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`. + * compartment, with the right slot layout. + * + * The `executor` can be a `nullptr`. In that case, the only way to resolve or + * reject the returned promise is via the `JS::ResolvePromise` and + * `JS::RejectPromise` JSAPI functions. + * + * 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); +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) -IsPromiseObject(JS::HandleObject obj); +extern JS_PUBLIC_API bool IsPromiseObject(JS::HandleObject obj); /** * Returns the current compartment's original Promise constructor. */ -extern JS_PUBLIC_API(JSObject*) -GetPromiseConstructor(JSContext* cx); +extern JS_PUBLIC_API JSObject* GetPromiseConstructor(JSContext* cx); /** * Returns the current compartment's original Promise.prototype. */ -extern JS_PUBLIC_API(JSObject*) -GetPromisePrototype(JSContext* cx); +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 -}; +enum class PromiseState { Pending, Fulfilled, Rejected }; /** * Returns the given Promise's state as a JS::PromiseState enum value. @@ -4476,53 +4381,50 @@ * 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); +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); +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); +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* GetPromiseAllocationSite( + JS::HandleObject promise); -extern JS_PUBLIC_API(JSObject*) -GetPromiseResolutionSite(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 DumpPromiseAllocationSite(JSContext* cx, + JS::HandleObject promise); -extern JS_PUBLIC_API(void) -DumpPromiseResolutionSite(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); +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); +extern JS_PUBLIC_API JSObject* CallOriginalPromiseReject( + JSContext* cx, JS::HandleValue rejectionValue); /** * Resolves the given Promise with the given `resolutionValue`. @@ -4530,8 +4432,9 @@ * 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); +extern JS_PUBLIC_API bool ResolvePromise(JSContext* cx, + JS::HandleObject promiseObj, + JS::HandleValue resolutionValue); /** * Rejects the given `promise` with the given `rejectionValue`. @@ -4539,8 +4442,9 @@ * 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); +extern JS_PUBLIC_API bool RejectPromise(JSContext* cx, + JS::HandleObject promiseObj, + JS::HandleValue rejectionValue); /** * Calls the current compartment's original Promise.prototype.then on the @@ -4550,9 +4454,9 @@ * `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); +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. @@ -4565,9 +4469,10 @@ * `Promise` or a subclass or `onResolve` and `onReject` aren't both callable * objects. */ -extern JS_PUBLIC_API(bool) -AddPromiseReactions(JSContext* cx, JS::HandleObject promise, - JS::HandleObject onResolve, JS::HandleObject onReject); +extern JS_PUBLIC_API bool AddPromiseReactions(JSContext* cx, + JS::HandleObject promise, + JS::HandleObject onResolve, + JS::HandleObject onReject); /** * Unforgeable version of the JS builtin Promise.all. @@ -4580,119 +4485,203 @@ * 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); +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. + * The Dispatchable interface allows the embedding to call SpiderMonkey + * on a JSContext thread when requested via DispatchToEventLoopCallback. */ -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) -SetAsyncTaskCallbacks(JSContext* cx, StartAsyncTaskCallback start, FinishAsyncTaskCallback finish); - -} // namespace JS - -extern JS_PUBLIC_API(bool) -JS_IsRunning(JSContext* cx); - -namespace JS { - -/** - * This class can be used to store a pointer to the youngest frame of a saved - * stack in the specified JSContext. This reference will be picked up by any new - * calls performed until the class is destroyed, with the specified asyncCause, - * that must not be empty. - * - * Any stack capture initiated during these new calls will go through the async - * stack instead of the current stack. - * - * Capturing the stack before a new call is performed will not be affected. - * - * The provided chain of SavedFrame objects can live in any compartment, - * although it will be copied to the compartment where the stack is captured. +class JS_PUBLIC_API Dispatchable { + protected: + // Dispatchables are created and destroyed by SpiderMonkey. + Dispatchable() = default; + virtual ~Dispatchable() = default; + + public: + // ShuttingDown indicates that SpiderMonkey should abort async tasks to + // expedite shutdown. + enum MaybeShuttingDown { NotShuttingDown, ShuttingDown }; + + // Called by the embedding after DispatchToEventLoopCallback succeeds. + virtual void run(JSContext* cx, MaybeShuttingDown maybeShuttingDown) = 0; +}; + +/** + * DispatchToEventLoopCallback may be called from any thread, being passed the + * same 'closure' passed to InitDispatchToEventLoop() and Dispatchable from the + * same JSRuntime. If the embedding returns 'true', the embedding must call + * Dispatchable::run() on an active JSContext thread for the same JSRuntime on + * which 'closure' was registered. If DispatchToEventLoopCallback returns + * 'false', SpiderMonkey will assume a shutdown of the JSRuntime is in progress. + * This contract implies that, by the time the final JSContext is destroyed in + * the JSRuntime, the embedding must have (1) run all Dispatchables for which + * DispatchToEventLoopCallback returned true, (2) already started returning + * false from calls to DispatchToEventLoopCallback. + */ + +typedef bool (*DispatchToEventLoopCallback)(void* closure, + Dispatchable* dispatchable); + +extern JS_PUBLIC_API void InitDispatchToEventLoop( + JSContext* cx, DispatchToEventLoopCallback callback, void* closure); + +/** + * The ConsumeStreamCallback is called from an active JSContext, passing a + * StreamConsumer that wishes to consume the given host object as a stream of + * bytes with the given MIME type. On failure, the embedding must report the + * appropriate error on 'cx'. On success, the embedding must call + * consumer->consumeChunk() repeatedly on any thread until exactly one of: + * - consumeChunk() returns false + * - the embedding calls consumer->streamClosed() + * before JS_DestroyContext(cx) or JS::ShutdownAsyncTasks(cx) is called. + * + * Note: consumeChunk() and streamClosed() may be called synchronously by + * ConsumeStreamCallback. + */ + +class JS_PUBLIC_API StreamConsumer { + protected: + // AsyncStreamConsumers are created and destroyed by SpiderMonkey. + StreamConsumer() = default; + virtual ~StreamConsumer() = default; + + public: + // Called by the embedding as each chunk of bytes becomes available. + // If this function returns 'false', the stream must drop all pointers to + // this StreamConsumer. + virtual bool consumeChunk(const uint8_t* begin, size_t length) = 0; + + // Called by the embedding when the stream is closed according to the + // contract described above. + enum CloseReason { EndOfFile, Error }; + virtual void streamClosed(CloseReason reason) = 0; + + // Provides optional stream attributes such as base or source mapping URLs. + // Necessarily called before consumeChunk() or streamClosed(). The caller + // retains ownership of the given strings. + virtual void noteResponseURLs(const char* maybeUrl, + const char* maybeSourceMapUrl) = 0; +}; + +enum class MimeType { Wasm }; + +typedef bool (*ConsumeStreamCallback)(JSContext* cx, JS::HandleObject obj, + MimeType mimeType, + StreamConsumer* consumer); + +extern JS_PUBLIC_API void InitConsumeStreamCallback( + JSContext* cx, ConsumeStreamCallback callback); + +/** + * When a JSRuntime is destroyed it implicitly cancels all async tasks in + * progress, releasing any roots held by the task. However, this is not soon + * enough for cycle collection, which needs to have roots dropped earlier so + * that the cycle collector can transitively remove roots for a future GC. For + * these and other cases, the set of pending async tasks can be canceled + * with this call earlier than JSRuntime destruction. + */ + +extern JS_PUBLIC_API void ShutdownAsyncTasks(JSContext* cx); + +/** + * Supply an alternative stack to incorporate into captured SavedFrame + * backtraces as the imputed caller of asynchronous JavaScript calls, like async + * function resumptions and DOM callbacks. + * + * When one async function awaits the result of another, it's natural to think + * of that as a sort of function call: just as execution resumes from an + * ordinary call expression when the callee returns, with the return value + * providing the value of the call expression, execution resumes from an 'await' + * expression after the awaited asynchronous function call returns, passing the + * return value along. + * + * Call the two async functions in such a situation the 'awaiter' and the + * 'awaitee'. + * + * As an async function, the awaitee contains 'await' expressions of its own. + * Whenever it executes after its first 'await', there are never any actual + * frames on the JavaScript stack under it; its awaiter is certainly not there. + * An await expression's continuation is invoked as a promise callback, and + * those are always called directly from the event loop in their own microtick. + * (Ignore unusual cases like nested event loops.) + * + * But because await expressions bear such a strong resemblance to calls (and + * deliberately so!), it would be unhelpful for stacks captured within the + * awaitee to be empty; instead, they should present the awaiter as the caller. + * + * The AutoSetAsyncStackForNewCalls RAII class supplies a SavedFrame stack to + * treat as the caller of any JavaScript invocations that occur within its + * lifetime. Any SavedFrame stack captured during such an invocation uses the + * SavedFrame passed to the constructor's 'stack' parameter as the 'asyncParent' + * property of the SavedFrame for the invocation's oldest frame. Its 'parent' + * property will be null, so stack-walking code can distinguish this + * awaiter/awaitee transition from an ordinary caller/callee transition. + * + * The constructor's 'asyncCause' parameter supplies a string explaining what + * sort of asynchronous call caused 'stack' to be spliced into the backtrace; + * for example, async function resumptions use the string "async". This appears + * as the 'asyncCause' property of the 'asyncParent' SavedFrame. + * + * Async callers are distinguished in the string form of a SavedFrame chain by + * including the 'asyncCause' string in the frame. It appears before the + * function name, with the two separated by a '*'. + * + * Note that, as each compartment has its own set of SavedFrames, the + * 'asyncParent' may actually point to a copy of 'stack', rather than the exact + * SavedFrame object passed. + * + * The youngest frame of 'stack' is not mutated to take the asyncCause string as + * its 'asyncCause' property; SavedFrame objects are immutable. Rather, a fresh + * clone of the frame is created with the needed 'asyncCause' property. + * + * The 'kind' argument specifies how aggressively 'stack' supplants any + * JavaScript frames older than this AutoSetAsyncStackForNewCalls object. If + * 'kind' is 'EXPLICIT', then all captured SavedFrame chains take on 'stack' as + * their 'asyncParent' where the chain crosses this object's scope. If 'kind' is + * 'IMPLICIT', then 'stack' is only included in captured chains if there are no + * other JavaScript frames on the stack --- that is, only if the stack would + * otherwise end at that point. + * + * AutoSetAsyncStackForNewCalls affects only SavedFrame chains; it does not + * affect Debugger.Frame or js::FrameIter. SavedFrame chains are used for + * Error.stack, allocation profiling, Promise debugging, and so on. * * See also `js/src/doc/SavedFrame/SavedFrame.md` for documentation on async * stack frames. */ -class MOZ_STACK_CLASS JS_PUBLIC_API(AutoSetAsyncStackForNewCalls) -{ - JSContext* cx; - RootedObject oldAsyncStack; - const char* oldAsyncCause; - bool oldAsyncCallIsExplicit; - - public: - enum class AsyncCallKind { - // The ordinary kind of call, where we may apply an async - // parent if there is no ordinary parent. - IMPLICIT, - // An explicit async parent, e.g., callFunctionWithAsyncStack, - // where we always want to override any ordinary parent. - EXPLICIT - }; - - // The stack parameter cannot be null by design, because it would be - // 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, - const char* asyncCause, - AsyncCallKind kind = AsyncCallKind::IMPLICIT); - ~AutoSetAsyncStackForNewCalls(); +class MOZ_STACK_CLASS JS_PUBLIC_API AutoSetAsyncStackForNewCalls { + JSContext* cx; + RootedObject oldAsyncStack; + const char* oldAsyncCause; + bool oldAsyncCallIsExplicit; + + public: + enum class AsyncCallKind { + // The ordinary kind of call, where we may apply an async + // parent if there is no ordinary parent. + IMPLICIT, + // An explicit async parent, e.g., callFunctionWithAsyncStack, + // where we always want to override any ordinary parent. + EXPLICIT + }; + + // The stack parameter cannot be null by design, because it would be + // 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, + const char* asyncCause, + AsyncCallKind kind = AsyncCallKind::IMPLICIT); + ~AutoSetAsyncStackForNewCalls(); }; -} // namespace JS +} // namespace JS /************************************************************************/ @@ -4705,65 +4694,72 @@ * for them. In contrast, all the JS_New*StringCopy* functions do not take * ownership of the character memory passed to them -- they copy it. */ -extern JS_PUBLIC_API(JSString*) -JS_NewStringCopyN(JSContext* cx, const char* s, size_t n); +extern JS_PUBLIC_API JSString* JS_NewStringCopyN(JSContext* cx, const char* s, + size_t n); -extern JS_PUBLIC_API(JSString*) -JS_NewStringCopyZ(JSContext* cx, const char* s); +extern JS_PUBLIC_API JSString* 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_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_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_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_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_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* JS_AtomizeAndPinStringN(JSContext* cx, + const char* s, + size_t length); -extern JS_PUBLIC_API(JSString*) -JS_AtomizeAndPinString(JSContext* cx, const char* s); +extern JS_PUBLIC_API JSString* JS_AtomizeAndPinString(JSContext* cx, + const char* s); -extern JS_PUBLIC_API(JSString*) -JS_NewUCString(JSContext* cx, char16_t* chars, size_t length); +extern JS_PUBLIC_API JSString* JS_NewLatin1String(JSContext* cx, + JS::Latin1Char* chars, + size_t length); -extern JS_PUBLIC_API(JSString*) -JS_NewUCStringCopyN(JSContext* cx, const char16_t* s, size_t n); +extern JS_PUBLIC_API JSString* JS_NewUCString(JSContext* cx, char16_t* chars, + size_t length); -extern JS_PUBLIC_API(JSString*) -JS_NewUCStringCopyZ(JSContext* cx, const char16_t* s); +extern JS_PUBLIC_API JSString* JS_NewUCStringCopyN(JSContext* cx, + const char16_t* s, size_t n); -extern JS_PUBLIC_API(JSString*) -JS_AtomizeUCStringN(JSContext* cx, const char16_t* s, size_t length); +extern JS_PUBLIC_API JSString* JS_NewUCStringCopyZ(JSContext* cx, + const char16_t* s); -extern JS_PUBLIC_API(JSString*) -JS_AtomizeUCString(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_AtomizeAndPinUCStringN(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_AtomizeAndPinUCString(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(bool) -JS_CompareStrings(JSContext* cx, JSString* str1, JSString* str2, int32_t* result); +extern JS_PUBLIC_API JSString* JS_AtomizeAndPinUCString(JSContext* cx, + const char16_t* s); -extern JS_PUBLIC_API(bool) -JS_StringEqualsAscii(JSContext* cx, JSString* str, const char* asciiBytes, bool* match); +extern JS_PUBLIC_API bool JS_CompareStrings(JSContext* cx, JSString* str1, + JSString* str2, int32_t* result); -extern JS_PUBLIC_API(size_t) -JS_PutEscapedString(JSContext* cx, char* buffer, size_t size, JSString* str, char quote); +extern JS_PUBLIC_API bool JS_StringEqualsAscii(JSContext* cx, JSString* str, + const char* asciiBytes, + bool* match); -extern JS_PUBLIC_API(bool) -JS_FileEscapedString(FILE* fp, JSString* str, char quote); +extern JS_PUBLIC_API size_t JS_PutEscapedString(JSContext* cx, char* buffer, + size_t size, JSString* str, + char quote); + +extern JS_PUBLIC_API bool JS_FileEscapedString(FILE* fp, JSString* str, + char quote); /* * Extracting string characters and length. @@ -4804,90 +4800,86 @@ * strings. */ -extern JS_PUBLIC_API(size_t) -JS_GetStringLength(JSString* str); +extern JS_PUBLIC_API size_t JS_GetStringLength(JSString* str); -extern JS_PUBLIC_API(bool) -JS_StringIsFlat(JSString* str); +extern JS_PUBLIC_API bool JS_StringIsFlat(JSString* str); /** Returns true iff the string's characters are stored as Latin1. */ -extern JS_PUBLIC_API(bool) -JS_StringHasLatin1Chars(JSString* str); +extern JS_PUBLIC_API bool JS_StringHasLatin1Chars(JSString* str); -extern JS_PUBLIC_API(const JS::Latin1Char*) -JS_GetLatin1StringCharsAndLength(JSContext* cx, const JS::AutoCheckCannotGC& nogc, JSString* str, - size_t* length); +extern JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1StringCharsAndLength( + JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str, + size_t* length); -extern JS_PUBLIC_API(const char16_t*) -JS_GetTwoByteStringCharsAndLength(JSContext* cx, const JS::AutoCheckCannotGC& nogc, JSString* str, - size_t* length); +extern JS_PUBLIC_API const char16_t* JS_GetTwoByteStringCharsAndLength( + JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str, + size_t* length); -extern JS_PUBLIC_API(bool) -JS_GetStringCharAt(JSContext* cx, JSString* str, size_t index, char16_t* res); +extern JS_PUBLIC_API bool JS_GetStringCharAt(JSContext* cx, JSString* str, + size_t index, char16_t* res); -extern JS_PUBLIC_API(char16_t) -JS_GetFlatStringCharAt(JSFlatString* str, size_t index); +extern JS_PUBLIC_API char16_t JS_GetFlatStringCharAt(JSFlatString* str, + size_t index); -extern JS_PUBLIC_API(const char16_t*) -JS_GetTwoByteExternalStringChars(JSString* str); +extern JS_PUBLIC_API const char16_t* JS_GetTwoByteExternalStringChars( + JSString* str); -extern JS_PUBLIC_API(bool) -JS_CopyStringChars(JSContext* cx, mozilla::Range dest, JSString* str); +extern JS_PUBLIC_API bool JS_CopyStringChars(JSContext* cx, + mozilla::Range dest, + JSString* str); -extern JS_PUBLIC_API(JSFlatString*) -JS_FlattenString(JSContext* cx, JSString* str); +extern JS_PUBLIC_API JSFlatString* JS_FlattenString(JSContext* cx, + JSString* str); -extern JS_PUBLIC_API(const JS::Latin1Char*) -JS_GetLatin1FlatStringChars(const JS::AutoCheckCannotGC& nogc, JSFlatString* str); +extern JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1FlatStringChars( + const JS::AutoRequireNoGC& nogc, JSFlatString* str); -extern JS_PUBLIC_API(const char16_t*) -JS_GetTwoByteFlatStringChars(const JS::AutoCheckCannotGC& nogc, JSFlatString* str); +extern JS_PUBLIC_API const char16_t* JS_GetTwoByteFlatStringChars( + const JS::AutoRequireNoGC& nogc, JSFlatString* str); -static MOZ_ALWAYS_INLINE JSFlatString* -JSID_TO_FLAT_STRING(jsid id) -{ - MOZ_ASSERT(JSID_IS_STRING(id)); - return (JSFlatString*)(JSID_BITS(id)); +static MOZ_ALWAYS_INLINE JSFlatString* JSID_TO_FLAT_STRING(jsid id) { + MOZ_ASSERT(JSID_IS_STRING(id)); + return (JSFlatString*)(JSID_BITS(id)); } -static MOZ_ALWAYS_INLINE JSFlatString* -JS_ASSERT_STRING_IS_FLAT(JSString* str) -{ - MOZ_ASSERT(JS_StringIsFlat(str)); - return (JSFlatString*)str; +static MOZ_ALWAYS_INLINE JSFlatString* JS_ASSERT_STRING_IS_FLAT(JSString* str) { + MOZ_ASSERT(JS_StringIsFlat(str)); + return (JSFlatString*)str; } -static MOZ_ALWAYS_INLINE JSString* -JS_FORGET_STRING_FLATNESS(JSFlatString* fstr) -{ - return (JSString*)fstr; +static MOZ_ALWAYS_INLINE JSString* JS_FORGET_STRING_FLATNESS( + JSFlatString* fstr) { + return (JSString*)fstr; } /* * Additional APIs that avoid fallibility when given a flat string. */ -extern JS_PUBLIC_API(bool) -JS_FlatStringEqualsAscii(JSFlatString* str, const char* asciiBytes); +extern JS_PUBLIC_API bool JS_FlatStringEqualsAscii(JSFlatString* str, + const char* asciiBytes); -extern JS_PUBLIC_API(size_t) -JS_PutEscapedFlatString(char* buffer, size_t size, JSFlatString* str, char quote); +extern JS_PUBLIC_API size_t JS_PutEscapedFlatString(char* buffer, size_t size, + JSFlatString* str, + char quote); /** * Create a dependent string, i.e., a string that owns no character storage, * but that refers to a slice of another string's chars. Dependent strings * are mutable by definition, so the thread safety comments above apply. */ -extern JS_PUBLIC_API(JSString*) -JS_NewDependentString(JSContext* cx, JS::HandleString str, size_t start, - size_t length); +extern JS_PUBLIC_API JSString* JS_NewDependentString(JSContext* cx, + JS::HandleString str, + size_t start, + size_t length); /** * Concatenate two strings, possibly resulting in a rope. * See above for thread safety comments. */ -extern JS_PUBLIC_API(JSString*) -JS_ConcatStrings(JSContext* cx, JS::HandleString left, JS::HandleString right); +extern JS_PUBLIC_API JSString* JS_ConcatStrings(JSContext* cx, + JS::HandleString left, + JS::HandleString right); /** * For JS_DecodeBytes, set *dstlenp to the size of the destination buffer before @@ -4899,33 +4891,29 @@ * the number of characters or bytes transferred so far. If cx is nullptr, no * error is reported on failure, and the functions simply return false. * - * NB: This function does not store an additional zero byte or char16_t after the - * transcoded string. + * NB: This function does not store an additional zero byte or char16_t after + * the transcoded string. */ -JS_PUBLIC_API(bool) -JS_DecodeBytes(JSContext* cx, const char* src, size_t srclen, char16_t* dst, - size_t* dstlenp); +JS_PUBLIC_API bool JS_DecodeBytes(JSContext* cx, const char* src, size_t srclen, + char16_t* dst, size_t* dstlenp); /** * A variation on JS_EncodeCharacters where a null terminated string is * returned that you are expected to call JS_free on when done. */ -JS_PUBLIC_API(char*) -JS_EncodeString(JSContext* cx, JSString* str); +JS_PUBLIC_API char* JS_EncodeString(JSContext* cx, JSString* str); /** * Same behavior as JS_EncodeString(), but encode into UTF-8 string */ -JS_PUBLIC_API(char*) -JS_EncodeStringToUTF8(JSContext* cx, JS::HandleString str); +JS_PUBLIC_API char* JS_EncodeStringToUTF8(JSContext* cx, JS::HandleString str); /** * Get number of bytes in the string encoding (without accounting for a * terminating zero bytes. The function returns (size_t) -1 if the string * can not be encoded into bytes and reports an error using cx accordingly. */ -JS_PUBLIC_API(size_t) -JS_GetStringEncodingLength(JSContext* cx, JSString* str); +JS_PUBLIC_API size_t JS_GetStringEncodingLength(JSContext* cx, JSString* str); /** * Encode string into a buffer. The function does not stores an additional @@ -4935,92 +4923,76 @@ * length parameter, the string will be cut and only length bytes will be * written into the buffer. */ -JS_PUBLIC_API(size_t) -JS_EncodeStringToBuffer(JSContext* cx, JSString* str, char* buffer, size_t length); - -class MOZ_RAII JSAutoByteString -{ - public: - JSAutoByteString(JSContext* cx, JSString* str - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mBytes(JS_EncodeString(cx, str)) - { - MOZ_ASSERT(cx); - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - explicit JSAutoByteString(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) - : mBytes(nullptr) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - ~JSAutoByteString() { - JS_free(nullptr, mBytes); - } - - /* Take ownership of the given byte array. */ - void initBytes(char* bytes) { - MOZ_ASSERT(!mBytes); - mBytes = bytes; - } - - char* encodeLatin1(JSContext* cx, JSString* str) { - MOZ_ASSERT(!mBytes); - MOZ_ASSERT(cx); - mBytes = JS_EncodeString(cx, str); - return mBytes; - } +JS_PUBLIC_API size_t JS_EncodeStringToBuffer(JSContext* cx, JSString* str, + char* buffer, size_t length); - char* encodeLatin1(js::ExclusiveContext* cx, JSString* str); - - char* encodeUtf8(JSContext* cx, JS::HandleString str) { - MOZ_ASSERT(!mBytes); - MOZ_ASSERT(cx); - mBytes = JS_EncodeStringToUTF8(cx, str); - return mBytes; - } - - void clear() { - js_free(mBytes); - mBytes = nullptr; - } - - char* ptr() const { - return mBytes; - } - - bool operator!() const { - return !mBytes; - } - - size_t length() const { - if (!mBytes) - return 0; - return strlen(mBytes); - } - - private: - char* mBytes; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER - - /* Copy and assignment are not supported. */ - JSAutoByteString(const JSAutoByteString& another); - JSAutoByteString& operator=(const JSAutoByteString& another); +class MOZ_RAII JSAutoByteString { + public: + JSAutoByteString(JSContext* cx, JSString* str MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mBytes(JS_EncodeString(cx, str)) { + MOZ_ASSERT(cx); + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + + explicit JSAutoByteString(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) + : mBytes(nullptr) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + + ~JSAutoByteString() { JS_free(nullptr, mBytes); } + + /* Take ownership of the given byte array. */ + void initBytes(JS::UniqueChars&& bytes) { + MOZ_ASSERT(!mBytes); + mBytes = bytes.release(); + } + + char* encodeLatin1(JSContext* cx, JSString* str) { + MOZ_ASSERT(!mBytes); + MOZ_ASSERT(cx); + mBytes = JS_EncodeString(cx, str); + return mBytes; + } + + char* encodeUtf8(JSContext* cx, JS::HandleString str) { + MOZ_ASSERT(!mBytes); + MOZ_ASSERT(cx); + mBytes = JS_EncodeStringToUTF8(cx, str); + return mBytes; + } + + void clear() { + js_free(mBytes); + mBytes = nullptr; + } + + char* ptr() const { return mBytes; } + + bool operator!() const { return !mBytes; } + + size_t length() const { + if (!mBytes) return 0; + return strlen(mBytes); + } + + private: + char* mBytes; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + + /* Copy and assignment are not supported. */ + JSAutoByteString(const JSAutoByteString& another); + JSAutoByteString& operator=(const JSAutoByteString& another); }; namespace JS { -extern JS_PUBLIC_API(JSAddonId*) -NewAddonId(JSContext* cx, JS::HandleString str); +extern JS_PUBLIC_API JSAddonId* NewAddonId(JSContext* cx, JS::HandleString str); -extern JS_PUBLIC_API(JSString*) -StringOfAddonId(JSAddonId* id); +extern JS_PUBLIC_API JSString* StringOfAddonId(JSAddonId* id); -extern JS_PUBLIC_API(JSAddonId*) -AddonIdOfObject(JSObject* obj); +extern JS_PUBLIC_API JSAddonId* AddonIdOfObject(JSObject* obj); -} // namespace JS +} // namespace JS /************************************************************************/ /* @@ -5036,18 +5008,16 @@ * If description is null, the new Symbol's [[Description]] attribute is * undefined. */ -JS_PUBLIC_API(Symbol*) -NewSymbol(JSContext* cx, HandleString description); +JS_PUBLIC_API Symbol* NewSymbol(JSContext* cx, HandleString description); /** * Symbol.for as specified in ES6. * - * Get a Symbol with the description 'key' from the Runtime-wide symbol registry. - * If there is not already a Symbol with that description in the registry, a new - * Symbol is created and registered. 'key' must not be null. + * Get a Symbol with the description 'key' from the Runtime-wide symbol + * registry. If there is not already a Symbol with that description in the + * registry, a new Symbol is created and registered. 'key' must not be null. */ -JS_PUBLIC_API(Symbol*) -GetSymbolFor(JSContext* cx, HandleString key); +JS_PUBLIC_API Symbol* GetSymbolFor(JSContext* cx, HandleString key); /** * Get the [[Description]] attribute of the given symbol. @@ -5055,31 +5025,33 @@ * This function is infallible. If it returns null, that means the symbol's * [[Description]] is undefined. */ -JS_PUBLIC_API(JSString*) -GetSymbolDescription(HandleSymbol symbol); +JS_PUBLIC_API JSString* 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) +#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) \ + MACRO(asyncIterator) enum class SymbolCode : uint32_t { - // There is one SymbolCode for each well-known symbol. +// 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. + 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() + 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. */ @@ -5090,8 +5062,7 @@ * * A symbol's SymbolCode never changes once it is created. */ -JS_PUBLIC_API(SymbolCode) -GetSymbolCode(Handle symbol); +JS_PUBLIC_API SymbolCode GetSymbolCode(Handle symbol); /** * Get one of the well-known symbols defined by ES6. A single set of well-known @@ -5099,22 +5070,18 @@ * * `which` must be in the range [0, WellKnownSymbolLimit). */ -JS_PUBLIC_API(Symbol*) -GetWellKnownSymbol(JSContext* cx, SymbolCode which); +JS_PUBLIC_API Symbol* GetWellKnownSymbol(JSContext* cx, SymbolCode which); /** * Return true if the given JSPropertySpec::name or JSFunctionSpec::name value * is actually a symbol code and not a string. See JS_SYM_FN. */ -inline bool -PropertySpecNameIsSymbol(const char* name) -{ - uintptr_t u = reinterpret_cast(name); - return u != 0 && u - 1 < WellKnownSymbolLimit; +inline bool PropertySpecNameIsSymbol(const char* name) { + uintptr_t u = reinterpret_cast(name); + return u != 0 && u - 1 < WellKnownSymbolLimit; } -JS_PUBLIC_API(bool) -PropertySpecNameEqualsId(const char* name, HandleId id); +JS_PUBLIC_API bool PropertySpecNameEqualsId(const char* name, HandleId id); /** * Create a jsid that does not need to be marked for GC. @@ -5124,8 +5091,8 @@ * symbol; either way it is immune to GC so there is no need to visit *idp * during GC marking. */ -JS_PUBLIC_API(bool) -PropertySpecNameToPermanentId(JSContext* cx, const char* name, jsid* idp); +JS_PUBLIC_API bool PropertySpecNameToPermanentId(JSContext* cx, + const char* name, jsid* idp); } /* namespace JS */ @@ -5133,14 +5100,16 @@ /* * JSON functions */ -typedef bool (* JSONWriteCallback)(const char16_t* buf, uint32_t len, void* data); +typedef bool (*JSONWriteCallback)(const char16_t* buf, uint32_t len, + void* data); /** * JSON.stringify as specified by ES5. */ -JS_PUBLIC_API(bool) -JS_Stringify(JSContext* cx, JS::MutableHandleValue value, JS::HandleObject replacer, - JS::HandleValue space, JSONWriteCallback callback, void* data); +JS_PUBLIC_API bool JS_Stringify(JSContext* cx, JS::MutableHandleValue value, + JS::HandleObject replacer, + JS::HandleValue space, + JSONWriteCallback callback, void* data); namespace JS { @@ -5161,28 +5130,28 @@ * 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); +JS_PUBLIC_API bool ToJSONMaybeSafely(JSContext* cx, JS::HandleObject input, + JSONWriteCallback callback, void* data); } /* namespace JS */ /** * JSON.parse as specified by ES5. */ -JS_PUBLIC_API(bool) -JS_ParseJSON(JSContext* cx, const char16_t* chars, uint32_t len, JS::MutableHandleValue vp); +JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, const char16_t* chars, + uint32_t len, JS::MutableHandleValue vp); -JS_PUBLIC_API(bool) -JS_ParseJSON(JSContext* cx, JS::HandleString str, JS::MutableHandleValue vp); +JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, JS::HandleString str, + JS::MutableHandleValue vp); -JS_PUBLIC_API(bool) -JS_ParseJSONWithReviver(JSContext* cx, const char16_t* chars, uint32_t len, JS::HandleValue reviver, - JS::MutableHandleValue vp); - -JS_PUBLIC_API(bool) -JS_ParseJSONWithReviver(JSContext* cx, JS::HandleString str, JS::HandleValue reviver, - JS::MutableHandleValue vp); +JS_PUBLIC_API bool JS_ParseJSONWithReviver(JSContext* cx, const char16_t* chars, + uint32_t len, + JS::HandleValue reviver, + JS::MutableHandleValue vp); + +JS_PUBLIC_API bool JS_ParseJSONWithReviver(JSContext* cx, JS::HandleString str, + JS::HandleValue reviver, + JS::MutableHandleValue vp); /************************************************************************/ @@ -5193,49 +5162,70 @@ * specify their own locales. * The locale string remains owned by the caller. */ -extern JS_PUBLIC_API(bool) -JS_SetDefaultLocale(JSContext* cx, const char* locale); +extern JS_PUBLIC_API bool JS_SetDefaultLocale(JSRuntime* rt, + const char* locale); /** * Look up the default locale for the ECMAScript Internationalization API. + * NB: The locale information is retrieved from cx's runtime. */ -extern JS_PUBLIC_API(JS::UniqueChars) -JS_GetDefaultLocale(JSContext* cx); +extern JS_PUBLIC_API JS::UniqueChars JS_GetDefaultLocale(JSContext* cx); /** * Reset the default locale to OS defaults. */ -extern JS_PUBLIC_API(void) -JS_ResetDefaultLocale(JSContext* cx); +extern JS_PUBLIC_API void JS_ResetDefaultLocale(JSRuntime* rt); /** * Locale specific string conversion and error message callbacks. */ struct JSLocaleCallbacks { - JSLocaleToUpperCase localeToUpperCase; - JSLocaleToLowerCase localeToLowerCase; - JSLocaleCompare localeCompare; // not used #if EXPOSE_INTL_API - JSLocaleToUnicode localeToUnicode; + JSLocaleToUpperCase localeToUpperCase; // not used #if EXPOSE_INTL_API + JSLocaleToLowerCase localeToLowerCase; // not used #if EXPOSE_INTL_API + JSLocaleCompare localeCompare; // not used #if EXPOSE_INTL_API + JSLocaleToUnicode localeToUnicode; }; /** * Establish locale callbacks. The pointer must persist as long as the * JSContext. Passing nullptr restores the default behaviour. */ -extern JS_PUBLIC_API(void) -JS_SetLocaleCallbacks(JSContext* cx, const JSLocaleCallbacks* callbacks); +extern JS_PUBLIC_API void JS_SetLocaleCallbacks( + JSRuntime* rt, const JSLocaleCallbacks* callbacks); /** * Return the address of the current locale callbacks struct, which may * be nullptr. */ -extern JS_PUBLIC_API(const JSLocaleCallbacks*) -JS_GetLocaleCallbacks(JSContext* cx); +extern JS_PUBLIC_API const JSLocaleCallbacks* JS_GetLocaleCallbacks( + JSRuntime* rt); /************************************************************************/ /* * Error reporting. + * + * There are four encoding variants for the error reporting API: + * UTF-8 + * JSAPI's default encoding for error handling. Use this when the encoding + * of the error message, format string, and arguments is UTF-8. + * ASCII + * Equivalent to UTF-8, but also asserts that the error message, format + * string, and arguments are all ASCII. Because ASCII is a subset of UTF-8, + * any use of this encoding variant *could* be replaced with use of the + * UTF-8 variant. This variant exists solely to double-check the + * developer's assumption that all these strings truly are ASCII, given that + * UTF-8 and ASCII strings regrettably have the same C++ type. + * UC = UTF-16 + * Use this when arguments are UTF-16. The format string must be UTF-8. + * Latin1 (planned to be removed) + * In this variant, all strings are interpreted byte-for-byte as the + * corresponding Unicode codepoint. This encoding may *safely* be used on + * any null-terminated string, regardless of its encoding. (You shouldn't + * *actually* be uncertain, but in the real world, a string's encoding -- if + * promised at all -- may be more...aspirational...than reality.) This + * encoding variant will eventually be removed -- work to convert your uses + * to UTF-8 as you're able. */ namespace JS { @@ -5246,60 +5236,59 @@ * Report an exception represented by the sprintf-like conversion of format * and its arguments. */ -extern JS_PUBLIC_API(void) -JS_ReportErrorASCII(JSContext* cx, const char* format, ...) - MOZ_FORMAT_PRINTF(2, 3); +extern JS_PUBLIC_API void JS_ReportErrorASCII(JSContext* cx, const char* format, + ...) MOZ_FORMAT_PRINTF(2, 3); -extern JS_PUBLIC_API(void) -JS_ReportErrorLatin1(JSContext* cx, const char* format, ...) +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); +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_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, ...); +extern JS_PUBLIC_API void 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_ReportErrorNumberLatin1VA(JSContext* cx, JSErrorCallback errorCallback, - void* userRef, const unsigned errorNumber, va_list ap); +extern JS_PUBLIC_API void 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, ...); +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); +extern JS_PUBLIC_API void JS_ReportErrorNumberUTF8VA( + JSContext* cx, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, va_list ap); #endif /* * Use an errorNumber to retrieve the format string, args are char16_t* */ -extern JS_PUBLIC_API(void) -JS_ReportErrorNumberUC(JSContext* cx, JSErrorCallback errorCallback, - void* userRef, const unsigned errorNumber, ...); - -extern JS_PUBLIC_API(void) -JS_ReportErrorNumberUCArray(JSContext* cx, JSErrorCallback errorCallback, - void* userRef, const unsigned errorNumber, - const char16_t** args); +extern JS_PUBLIC_API void JS_ReportErrorNumberUC(JSContext* cx, + JSErrorCallback errorCallback, + void* userRef, + const unsigned errorNumber, + ...); + +extern JS_PUBLIC_API void JS_ReportErrorNumberUCArray( + JSContext* cx, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, const char16_t** args); /** * As above, but report a warning instead (JSREPORT_IS_WARNING(report.flags)). @@ -5307,136 +5296,213 @@ * warning was not converted into an error due to the JSOPTION_WERROR option * being set, false otherwise. */ -extern JS_PUBLIC_API(bool) -JS_ReportWarningASCII(JSContext* cx, const char* format, ...) +extern JS_PUBLIC_API bool JS_ReportWarningASCII(JSContext* cx, + const char* format, ...) MOZ_FORMAT_PRINTF(2, 3); -extern JS_PUBLIC_API(bool) -JS_ReportWarningLatin1(JSContext* cx, const char* format, ...) +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, ...) +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_ReportErrorFlagsAndNumberUTF8(JSContext* cx, unsigned flags, - JSErrorCallback errorCallback, void* userRef, - const unsigned errorNumber, ...); - -extern JS_PUBLIC_API(bool) -JS_ReportErrorFlagsAndNumberUC(JSContext* cx, unsigned flags, - JSErrorCallback errorCallback, void* userRef, - const unsigned errorNumber, ...); +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_ReportErrorFlagsAndNumberUTF8( + JSContext* cx, unsigned flags, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + +extern JS_PUBLIC_API bool JS_ReportErrorFlagsAndNumberUC( + JSContext* cx, unsigned flags, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); /** * Complain when out of memory. */ -extern JS_PUBLIC_API(void) -JS_ReportOutOfMemory(JSContext* cx); +extern JS_PUBLIC_API void JS_ReportOutOfMemory(JSContext* cx); /** * Complain when an allocation size overflows the maximum supported limit. */ -extern JS_PUBLIC_API(void) -JS_ReportAllocationOverflow(JSContext* cx); +extern JS_PUBLIC_API void JS_ReportAllocationOverflow(JSContext* cx); -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'. - size_t linebufLength_; - - // The 0-based offset of error token in linebuf_. - size_t tokenOffset_; - - public: - JSErrorReport() - : linebuf_(nullptr), linebufLength_(0), tokenOffset_(0), - filename(nullptr), lineno(0), column(0), - flags(0), errorNumber(0), - exnType(0), isMuted(false), - ownsLinebuf_(false), ownsMessage_(false) - {} - - ~JSErrorReport() { - freeLinebuf(); - freeMessage(); - } +/** + * Base class that implements parts shared by JSErrorReport and + * JSErrorNotes::Note. + */ +class JSErrorBase { + // The (default) error message. + // If ownsMessage_ is true, the it is freed in destructor. + JS::ConstUTF8CharsZ message_; - const char* filename; /* source file name, URL, etc., or null */ - unsigned lineno; /* source line number */ - unsigned column; /* zero-based column index in line */ - unsigned flags; /* error/warning, etc. */ - unsigned errorNumber; /* the error number, e.g. see js.msg */ - int16_t exnType; /* One of the JSExnType constants */ - bool isMuted : 1; /* See the comment in ReadOnlyCompileOptions. */ + public: + JSErrorBase() + : filename(nullptr), + lineno(0), + column(0), + errorNumber(0), + ownsMessage_(false) {} - private: - bool ownsLinebuf_ : 1; - bool ownsMessage_ : 1; + ~JSErrorBase() { freeMessage(); } - public: - const char16_t* linebuf() const { - return linebuf_; - } - size_t linebufLength() const { - return linebufLength_; - } - size_t tokenOffset() const { - return tokenOffset_; - } - void initOwnedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, size_t tokenOffsetArg) { - initBorrowedLinebuf(linebufArg, linebufLengthArg, tokenOffsetArg); - ownsLinebuf_ = true; - } - void initBorrowedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, size_t tokenOffsetArg); - void freeLinebuf(); + // Source file name, URL, etc., or null. + const char* filename; - const JS::ConstUTF8CharsZ message() const { - return message_; - } + // Source line number. + unsigned lineno; - void initOwnedMessage(const char* messageArg) { - initBorrowedMessage(messageArg); - ownsMessage_ = true; - } - void initBorrowedMessage(const char* messageArg) { - MOZ_ASSERT(!message_); - message_ = JS::ConstUTF8CharsZ(messageArg, strlen(messageArg)); - } + // Zero-based column index in line. + unsigned column; + + // the error number, e.g. see js.msg. + unsigned errorNumber; + + private: + bool ownsMessage_ : 1; + + public: + const JS::ConstUTF8CharsZ message() const { return message_; } + + void initOwnedMessage(const char* messageArg) { + initBorrowedMessage(messageArg); + ownsMessage_ = true; + } + void initBorrowedMessage(const char* messageArg) { + MOZ_ASSERT(!message_); + message_ = JS::ConstUTF8CharsZ(messageArg, strlen(messageArg)); + } - JSString* newMessageString(JSContext* cx); + JSString* newMessageString(JSContext* cx); - void freeMessage(); + private: + void freeMessage(); +}; + +/** + * Notes associated with JSErrorReport. + */ +class JSErrorNotes { + public: + class Note : public JSErrorBase {}; + + private: + // Stores pointers to each note. + js::Vector, 1, js::SystemAllocPolicy> notes_; + + public: + JSErrorNotes(); + ~JSErrorNotes(); + + // Add an note to the given position. + bool addNoteASCII(JSContext* cx, const char* filename, unsigned lineno, + unsigned column, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, ...); + bool addNoteLatin1(JSContext* cx, const char* filename, unsigned lineno, + unsigned column, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, ...); + bool addNoteUTF8(JSContext* cx, const char* filename, unsigned lineno, + unsigned column, JSErrorCallback errorCallback, + void* userRef, const unsigned errorNumber, ...); + + JS_PUBLIC_API size_t length(); + + // Create a deep copy of notes. + js::UniquePtr copy(JSContext* cx); + + class iterator + : public std::iterator> { + js::UniquePtr* note_; + + public: + explicit iterator(js::UniquePtr* note = nullptr) : note_(note) {} + + bool operator==(iterator other) const { return note_ == other.note_; } + bool operator!=(iterator other) const { return !(*this == other); } + iterator& operator++() { + note_++; + return *this; + } + reference operator*() { return *note_; } + }; + JS_PUBLIC_API iterator begin(); + JS_PUBLIC_API iterator end(); +}; + +/** + * Describes a single error or warning that occurs in the execution of script. + */ +class JSErrorReport : public JSErrorBase { + // Offending source line without final '\n'. + // If ownsLinebuf_ is true, the buffer is freed in destructor. + const char16_t* linebuf_; + + // Number of chars in linebuf_. Does not include trailing '\0'. + size_t linebufLength_; + + // The 0-based offset of error token in linebuf_. + size_t tokenOffset_; + + public: + JSErrorReport() + : linebuf_(nullptr), + linebufLength_(0), + tokenOffset_(0), + notes(nullptr), + flags(0), + exnType(0), + isMuted(false), + ownsLinebuf_(false) {} + + ~JSErrorReport() { freeLinebuf(); } + + // Associated notes, or nullptr if there's no note. + js::UniquePtr notes; + + // error/warning, etc. + unsigned flags; + + // One of the JSExnType constants. + int16_t exnType; + + // See the comment in TransitiveCompileOptions. + bool isMuted : 1; + + private: + bool ownsLinebuf_ : 1; + + public: + const char16_t* linebuf() const { return linebuf_; } + size_t linebufLength() const { return linebufLength_; } + size_t tokenOffset() const { return tokenOffset_; } + void initOwnedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, + size_t tokenOffsetArg) { + initBorrowedLinebuf(linebufArg, linebufLengthArg, tokenOffsetArg); + ownsLinebuf_ = true; + } + void initBorrowedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, + size_t tokenOffsetArg); + + private: + void freeLinebuf(); }; /* * JSErrorReport flag values. These may be freely composed. */ -#define JSREPORT_ERROR 0x0 /* pseudo-flag for default case */ -#define JSREPORT_WARNING 0x1 /* reported via JS_ReportWarning */ -#define JSREPORT_EXCEPTION 0x2 /* exception was thrown */ -#define JSREPORT_STRICT 0x4 /* error or warning due to strict option */ +#define JSREPORT_ERROR 0x0 /* pseudo-flag for default case */ +#define JSREPORT_WARNING 0x1 /* reported via JS_ReportWarning */ +#define JSREPORT_EXCEPTION 0x2 /* exception was thrown */ +#define JSREPORT_STRICT 0x4 /* error or warning due to strict option */ -#define JSREPORT_USER_1 0x8 /* user-defined flag */ +#define JSREPORT_USER_1 0x8 /* user-defined flag */ /* * If JSREPORT_EXCEPTION is set, then a JavaScript-catchable exception @@ -5445,24 +5511,23 @@ * JS_ExecuteScript returns failure, and signal or propagate the exception, as * appropriate. */ -#define JSREPORT_IS_WARNING(flags) (((flags) & JSREPORT_WARNING) != 0) -#define JSREPORT_IS_EXCEPTION(flags) (((flags) & JSREPORT_EXCEPTION) != 0) -#define JSREPORT_IS_STRICT(flags) (((flags) & JSREPORT_STRICT) != 0) +#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) namespace JS { using WarningReporter = void (*)(JSContext* cx, JSErrorReport* report); -extern JS_PUBLIC_API(WarningReporter) +extern JS_PUBLIC_API WarningReporter SetWarningReporter(JSContext* cx, WarningReporter reporter); -extern JS_PUBLIC_API(WarningReporter) -GetWarningReporter(JSContext* cx); +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, - JSErrorReport* report, HandleString message, MutableHandleValue rval); +extern JS_PUBLIC_API bool CreateError( + JSContext* cx, JSExnType type, HandleObject stack, HandleString fileName, + uint32_t lineNumber, uint32_t columnNumber, JSErrorReport* report, + HandleString message, MutableHandleValue rval); /************************************************************************/ @@ -5470,89 +5535,84 @@ * Weak Maps. */ -extern JS_PUBLIC_API(JSObject*) -NewWeakMapObject(JSContext* cx); +extern JS_PUBLIC_API JSObject* NewWeakMapObject(JSContext* cx); -extern JS_PUBLIC_API(bool) -IsWeakMapObject(JSObject* obj); +extern JS_PUBLIC_API bool IsWeakMapObject(JSObject* obj); -extern JS_PUBLIC_API(bool) -GetWeakMapEntry(JSContext* cx, JS::HandleObject mapObj, JS::HandleObject key, - JS::MutableHandleValue val); - -extern JS_PUBLIC_API(bool) -SetWeakMapEntry(JSContext* cx, JS::HandleObject mapObj, JS::HandleObject key, - JS::HandleValue val); +extern JS_PUBLIC_API bool GetWeakMapEntry(JSContext* cx, + JS::HandleObject mapObj, + JS::HandleObject key, + JS::MutableHandleValue val); + +extern JS_PUBLIC_API bool SetWeakMapEntry(JSContext* cx, + JS::HandleObject mapObj, + JS::HandleObject key, + JS::HandleValue val); /* * Map */ -extern JS_PUBLIC_API(JSObject*) -NewMapObject(JSContext* cx); +extern JS_PUBLIC_API JSObject* NewMapObject(JSContext* cx); -extern JS_PUBLIC_API(uint32_t) -MapSize(JSContext* cx, HandleObject obj); +extern JS_PUBLIC_API uint32_t MapSize(JSContext* cx, HandleObject obj); -extern JS_PUBLIC_API(bool) -MapGet(JSContext* cx, HandleObject obj, - HandleValue key, MutableHandleValue rval); +extern JS_PUBLIC_API bool MapGet(JSContext* cx, HandleObject obj, + HandleValue key, MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -MapHas(JSContext* cx, HandleObject obj, HandleValue key, bool* rval); +extern JS_PUBLIC_API bool MapHas(JSContext* cx, HandleObject obj, + HandleValue key, bool* rval); -extern JS_PUBLIC_API(bool) -MapSet(JSContext* cx, HandleObject obj, HandleValue key, HandleValue val); +extern JS_PUBLIC_API bool MapSet(JSContext* cx, HandleObject obj, + HandleValue key, HandleValue val); -extern JS_PUBLIC_API(bool) -MapDelete(JSContext *cx, HandleObject obj, HandleValue key, bool *rval); +extern JS_PUBLIC_API bool MapDelete(JSContext* cx, HandleObject obj, + HandleValue key, bool* rval); -extern JS_PUBLIC_API(bool) -MapClear(JSContext* cx, HandleObject obj); +extern JS_PUBLIC_API bool MapClear(JSContext* cx, HandleObject obj); -extern JS_PUBLIC_API(bool) -MapKeys(JSContext* cx, HandleObject obj, MutableHandleValue rval); +extern JS_PUBLIC_API bool MapKeys(JSContext* cx, HandleObject obj, + MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -MapValues(JSContext* cx, HandleObject obj, MutableHandleValue rval); +extern JS_PUBLIC_API bool MapValues(JSContext* cx, HandleObject obj, + MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -MapEntries(JSContext* cx, HandleObject obj, MutableHandleValue rval); +extern JS_PUBLIC_API bool MapEntries(JSContext* cx, HandleObject obj, + MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -MapForEach(JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisVal); +extern JS_PUBLIC_API bool MapForEach(JSContext* cx, HandleObject obj, + HandleValue callbackFn, + HandleValue thisVal); /* * Set */ -extern JS_PUBLIC_API(JSObject *) -NewSetObject(JSContext *cx); +extern JS_PUBLIC_API JSObject* NewSetObject(JSContext* cx); -extern JS_PUBLIC_API(uint32_t) -SetSize(JSContext *cx, HandleObject obj); +extern JS_PUBLIC_API uint32_t SetSize(JSContext* cx, HandleObject obj); -extern JS_PUBLIC_API(bool) -SetHas(JSContext *cx, HandleObject obj, HandleValue key, bool *rval); +extern JS_PUBLIC_API bool SetHas(JSContext* cx, HandleObject obj, + HandleValue key, bool* rval); -extern JS_PUBLIC_API(bool) -SetDelete(JSContext *cx, HandleObject obj, HandleValue key, bool *rval); +extern JS_PUBLIC_API bool SetDelete(JSContext* cx, HandleObject obj, + HandleValue key, bool* rval); -extern JS_PUBLIC_API(bool) -SetAdd(JSContext *cx, HandleObject obj, HandleValue key); +extern JS_PUBLIC_API bool SetAdd(JSContext* cx, HandleObject obj, + HandleValue key); -extern JS_PUBLIC_API(bool) -SetClear(JSContext *cx, HandleObject obj); +extern JS_PUBLIC_API bool SetClear(JSContext* cx, HandleObject obj); -extern JS_PUBLIC_API(bool) -SetKeys(JSContext *cx, HandleObject obj, MutableHandleValue rval); +extern JS_PUBLIC_API bool SetKeys(JSContext* cx, HandleObject obj, + MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -SetValues(JSContext *cx, HandleObject obj, MutableHandleValue rval); +extern JS_PUBLIC_API bool SetValues(JSContext* cx, HandleObject obj, + MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -SetEntries(JSContext *cx, HandleObject obj, MutableHandleValue rval); +extern JS_PUBLIC_API bool SetEntries(JSContext* cx, HandleObject obj, + MutableHandleValue rval); -extern JS_PUBLIC_API(bool) -SetForEach(JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisVal); +extern JS_PUBLIC_API bool SetForEach(JSContext* cx, HandleObject obj, + HandleValue callbackFn, + HandleValue thisVal); } /* namespace JS */ @@ -5560,8 +5620,9 @@ * Dates. */ -extern JS_PUBLIC_API(JSObject*) -JS_NewDateObject(JSContext* cx, int year, int mon, int mday, int hour, int min, int sec); +extern JS_PUBLIC_API JSObject* JS_NewDateObject(JSContext* cx, int year, + int mon, int mday, int hour, + int min, int sec); /** * Returns true and sets |*isDate| indicating whether |obj| is a Date object or @@ -5570,42 +5631,47 @@ * This method returns true with |*isDate == false| when passed a proxy whose * target is a Date, or when passed a revoked proxy. */ -extern JS_PUBLIC_API(bool) -JS_ObjectIsDate(JSContext* cx, JS::HandleObject obj, bool* isDate); +extern JS_PUBLIC_API bool JS_ObjectIsDate(JSContext* cx, JS::HandleObject obj, + bool* isDate); /************************************************************************/ /* * Regular Expressions. */ -#define JSREG_FOLD 0x01u /* fold uppercase to lowercase */ -#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, const char* bytes, size_t length, unsigned flags); - -extern JS_PUBLIC_API(JSObject*) -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); - -extern JS_PUBLIC_API(bool) -JS_ClearRegExpStatics(JSContext* cx, JS::HandleObject obj); - -extern JS_PUBLIC_API(bool) -JS_ExecuteRegExp(JSContext* cx, JS::HandleObject obj, JS::HandleObject reobj, - char16_t* chars, size_t length, size_t* indexp, bool test, - JS::MutableHandleValue rval); +#define JSREG_FOLD 0x01u /* fold uppercase to lowercase */ +#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, + const char* bytes, + size_t length, + unsigned flags); + +extern JS_PUBLIC_API JSObject* 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); + +extern JS_PUBLIC_API bool JS_ClearRegExpStatics(JSContext* cx, + JS::HandleObject obj); + +extern JS_PUBLIC_API bool JS_ExecuteRegExp(JSContext* cx, JS::HandleObject obj, + JS::HandleObject reobj, + char16_t* chars, size_t length, + size_t* indexp, bool test, + JS::MutableHandleValue rval); /* RegExp interface for clients without a global object. */ -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); +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); /** * Returns true and sets |*isRegExp| indicating whether |obj| is a RegExp @@ -5614,28 +5680,26 @@ * This method returns true with |*isRegExp == false| when passed a proxy whose * target is a RegExp, or when passed a revoked proxy. */ -extern JS_PUBLIC_API(bool) -JS_ObjectIsRegExp(JSContext* cx, JS::HandleObject obj, bool* isRegExp); +extern JS_PUBLIC_API bool JS_ObjectIsRegExp(JSContext* cx, JS::HandleObject obj, + bool* isRegExp); -extern JS_PUBLIC_API(unsigned) -JS_GetRegExpFlags(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API unsigned JS_GetRegExpFlags(JSContext* cx, + JS::HandleObject obj); -extern JS_PUBLIC_API(JSString*) -JS_GetRegExpSource(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API JSString* JS_GetRegExpSource(JSContext* cx, + JS::HandleObject obj); /************************************************************************/ -extern JS_PUBLIC_API(bool) -JS_IsExceptionPending(JSContext* cx); +extern JS_PUBLIC_API bool JS_IsExceptionPending(JSContext* cx); -extern JS_PUBLIC_API(bool) -JS_GetPendingException(JSContext* cx, JS::MutableHandleValue vp); +extern JS_PUBLIC_API bool JS_GetPendingException(JSContext* cx, + JS::MutableHandleValue vp); -extern JS_PUBLIC_API(void) -JS_SetPendingException(JSContext* cx, JS::HandleValue v); +extern JS_PUBLIC_API void JS_SetPendingException(JSContext* cx, + JS::HandleValue v); -extern JS_PUBLIC_API(void) -JS_ClearPendingException(JSContext* cx); +extern JS_PUBLIC_API void JS_ClearPendingException(JSContext* cx); namespace JS { @@ -5651,58 +5715,56 @@ * ... cleanup that might re-enter JS ... * return ok; */ -class JS_PUBLIC_API(AutoSaveExceptionState) -{ - private: - JSContext* context; - bool wasPropagatingForcedReturn; - bool wasOverRecursed; - bool wasThrowing; - RootedValue exceptionValue; - - public: - /* - * Take a snapshot of cx's current exception state. Then clear any current - * pending exception in cx. - */ - explicit AutoSaveExceptionState(JSContext* cx); - - /* - * If neither drop() nor restore() was called, restore the exception - * state only if no exception is currently pending on cx. - */ - ~AutoSaveExceptionState(); - - /* - * Discard any stored exception state. - * If this is called, the destructor is a no-op. - */ - void drop() { - wasPropagatingForcedReturn = false; - wasOverRecursed = false; - wasThrowing = false; - exceptionValue.setUndefined(); - } - - /* - * Replace cx's exception state with the stored exception state. Then - * discard the stored exception state. If this is called, the - * destructor is a no-op. - */ - void restore(); +class JS_PUBLIC_API AutoSaveExceptionState { + private: + JSContext* context; + bool wasPropagatingForcedReturn; + bool wasOverRecursed; + bool wasThrowing; + RootedValue exceptionValue; + + public: + /* + * Take a snapshot of cx's current exception state. Then clear any current + * pending exception in cx. + */ + explicit AutoSaveExceptionState(JSContext* cx); + + /* + * If neither drop() nor restore() was called, restore the exception + * state only if no exception is currently pending on cx. + */ + ~AutoSaveExceptionState(); + + /* + * Discard any stored exception state. + * If this is called, the destructor is a no-op. + */ + void drop() { + wasPropagatingForcedReturn = false; + wasOverRecursed = false; + wasThrowing = false; + exceptionValue.setUndefined(); + } + + /* + * Replace cx's exception state with the stored exception state. Then + * discard the stored exception state. If this is called, the + * destructor is a no-op. + */ + void restore(); }; } /* namespace JS */ /* Deprecated API. Use AutoSaveExceptionState instead. */ -extern JS_PUBLIC_API(JSExceptionState*) -JS_SaveExceptionState(JSContext* cx); +extern JS_PUBLIC_API JSExceptionState* JS_SaveExceptionState(JSContext* cx); -extern JS_PUBLIC_API(void) -JS_RestoreExceptionState(JSContext* cx, JSExceptionState* state); +extern JS_PUBLIC_API void JS_RestoreExceptionState(JSContext* cx, + JSExceptionState* state); -extern JS_PUBLIC_API(void) -JS_DropExceptionState(JSContext* cx, JSExceptionState* state); +extern JS_PUBLIC_API void JS_DropExceptionState(JSContext* cx, + JSExceptionState* state); /** * If the given object is an exception object, the exception will have (or be @@ -5711,9 +5773,10 @@ * of the error report struct that might be returned is the same as the * lifetime of the exception object. */ -extern JS_PUBLIC_API(JSErrorReport*) -JS_ErrorFromException(JSContext* cx, JS::HandleObject obj); +extern JS_PUBLIC_API JSErrorReport* JS_ErrorFromException(JSContext* cx, + JS::HandleObject obj); +namespace JS { /** * If the given object is an exception object (or an unwrappable * cross-compartment wrapper for one), return the stack for that exception, if @@ -5721,17 +5784,9 @@ * (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(JS::HandleObject obj); +extern JS_PUBLIC_API JSObject* ExceptionStackOrNull(JS::HandleObject obj); -/* - * Throws a StopIteration exception on cx. - */ -extern JS_PUBLIC_API(bool) -JS_ThrowStopIteration(JSContext* cx); - -extern JS_PUBLIC_API(bool) -JS_IsStopIteration(const JS::Value& v); +} /* namespace JS */ /** * A JS context always has an "owner thread". The owner thread is set when the @@ -5743,8 +5798,7 @@ * non-debug builds). */ -extern JS_PUBLIC_API(void) -JS_AbortIfWrongThread(JSContext* cx); +extern JS_PUBLIC_API void JS_AbortIfWrongThread(JSContext* cx); /************************************************************************/ @@ -5753,120 +5807,126 @@ * object of the given class, using the callee to determine parentage and * [[Prototype]]. */ -extern JS_PUBLIC_API(JSObject*) -JS_NewObjectForConstructor(JSContext* cx, const JSClass* clasp, const JS::CallArgs& args); +extern JS_PUBLIC_API JSObject* JS_NewObjectForConstructor( + JSContext* cx, const JSClass* clasp, const JS::CallArgs& args); /************************************************************************/ #ifdef JS_GC_ZEAL #define JS_DEFAULT_ZEAL_FREQ 100 -extern JS_PUBLIC_API(void) -JS_GetGCZealBits(JSContext* cx, uint32_t* zealBits, uint32_t* frequency, uint32_t* nextScheduled); +extern JS_PUBLIC_API void 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); +extern JS_PUBLIC_API void JS_SetGCZeal(JSContext* cx, uint8_t zeal, + uint32_t frequency); -extern JS_PUBLIC_API(void) -JS_ScheduleGC(JSContext* cx, uint32_t count); +extern JS_PUBLIC_API void JS_ScheduleGC(JSContext* cx, uint32_t count); #endif -extern JS_PUBLIC_API(void) -JS_SetParallelParsingEnabled(JSContext* cx, bool enabled); +extern JS_PUBLIC_API void JS_SetParallelParsingEnabled(JSContext* cx, + bool enabled); -extern JS_PUBLIC_API(void) -JS_SetOffthreadIonCompilationEnabled(JSContext* cx, bool enabled); +extern JS_PUBLIC_API void JS_SetOffthreadIonCompilationEnabled(JSContext* cx, + bool enabled); -#define JIT_COMPILER_OPTIONS(Register) \ - Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \ - Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \ - 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(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") +//clang-format off +#define JIT_COMPILER_OPTIONS(Register) \ + Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \ + Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \ + 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(FULL_DEBUG_CHECKS, "jit.full-debug-checks") \ + Register(JUMP_THRESHOLD, "jump-threshold") \ + Register(UNBOXED_OBJECTS, "unboxed_objects") \ + Register(SIMULATOR_ALWAYS_INTERRUPT, "simulator.always-interrupt") \ + Register(SPECTRE_INDEX_MASKING, "spectre.index-masking") \ + Register(SPECTRE_OBJECT_MITIGATIONS_BARRIERS, "spectre.object-mitigations.barriers") \ + Register(SPECTRE_OBJECT_MITIGATIONS_MISC, "spectre.object-mitigations.misc") \ + Register(SPECTRE_STRING_MITIGATIONS, "spectre.string-mitigations") \ + Register(SPECTRE_VALUE_MASKING, "spectre.value-masking") \ + Register(SPECTRE_JIT_TO_CXX_CALLS, "spectre.jit-to-C++-calls") \ + Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \ + Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets") \ + Register(WASM_DELAY_TIER2, "wasm.delay-tier2") +//clang-format on typedef enum JSJitCompilerOption { -#define JIT_COMPILER_DECLARE(key, str) \ - JSJITCOMPILER_ ## key, +#define JIT_COMPILER_DECLARE(key, str) JSJITCOMPILER_##key, - JIT_COMPILER_OPTIONS(JIT_COMPILER_DECLARE) + JIT_COMPILER_OPTIONS(JIT_COMPILER_DECLARE) #undef JIT_COMPILER_DECLARE - JSJITCOMPILER_NOT_AN_OPTION + JSJITCOMPILER_NOT_AN_OPTION } JSJitCompilerOption; -extern JS_PUBLIC_API(void) -JS_SetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t value); -extern JS_PUBLIC_API(bool) -JS_GetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t* valueOut); +extern JS_PUBLIC_API void 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. */ -extern JS_PUBLIC_API(bool) -JS_IndexToId(JSContext* cx, uint32_t index, JS::MutableHandleId); +extern JS_PUBLIC_API bool JS_IndexToId(JSContext* cx, uint32_t index, + JS::MutableHandleId); /** * Convert chars into a jsid. * * |chars| may not be an index. */ -extern JS_PUBLIC_API(bool) -JS_CharsToId(JSContext* cx, JS::TwoByteChars chars, JS::MutableHandleId); +extern JS_PUBLIC_API bool JS_CharsToId(JSContext* cx, JS::TwoByteChars chars, + JS::MutableHandleId); /** * Test if the given string is a valid ECMAScript identifier */ -extern JS_PUBLIC_API(bool) -JS_IsIdentifier(JSContext* cx, JS::HandleString str, bool* isIdentifier); +extern JS_PUBLIC_API bool JS_IsIdentifier(JSContext* cx, JS::HandleString str, + bool* isIdentifier); /** * Test whether the given chars + length are a valid ECMAScript identifier. * This version is infallible, so just returns whether the chars are an * identifier. */ -extern JS_PUBLIC_API(bool) -JS_IsIdentifier(const char16_t* chars, size_t length); +extern JS_PUBLIC_API bool JS_IsIdentifier(const char16_t* chars, size_t length); namespace js { class ScriptSource; -} // namespace js +} // namespace js namespace JS { -class MOZ_RAII JS_PUBLIC_API(AutoFilename) -{ - private: - js::ScriptSource* ss_; - mozilla::Variant filename_; +class MOZ_RAII JS_PUBLIC_API AutoFilename { + private: + js::ScriptSource* ss_; + mozilla::Variant filename_; - AutoFilename(const AutoFilename&) = delete; - AutoFilename& operator=(const AutoFilename&) = delete; + AutoFilename(const AutoFilename&) = delete; + AutoFilename& operator=(const AutoFilename&) = delete; - public: - AutoFilename() - : ss_(nullptr), - filename_(mozilla::AsVariant(nullptr)) - {} + public: + AutoFilename() + : ss_(nullptr), filename_(mozilla::AsVariant(nullptr)) {} - ~AutoFilename() { - reset(); - } + ~AutoFilename() { reset(); } - void reset(); + void reset(); - void setOwned(UniqueChars&& filename); - void setUnowned(const char* filename); - void setScriptSource(js::ScriptSource* ss); + void setOwned(UniqueChars&& filename); + void setUnowned(const char* filename); + void setScriptSource(js::ScriptSource* ss); - const char* get() const; + const char* get() const; }; /** @@ -5877,12 +5937,11 @@ * If a the embedding has hidden the scripted caller for the topmost activation * record, this will also return false. */ -extern JS_PUBLIC_API(bool) -DescribeScriptedCaller(JSContext* cx, AutoFilename* filename = nullptr, - unsigned* lineno = nullptr, unsigned* column = nullptr); +extern JS_PUBLIC_API bool DescribeScriptedCaller( + JSContext* cx, AutoFilename* filename = nullptr, unsigned* lineno = nullptr, + unsigned* column = nullptr); -extern JS_PUBLIC_API(JSObject*) -GetScriptedCallerGlobal(JSContext* cx); +extern JS_PUBLIC_API JSObject* GetScriptedCallerGlobal(JSContext* cx); /** * Informs the JS engine that the scripted caller should be hidden. This can be @@ -5896,29 +5955,22 @@ * drop below zero, and must always be exactly zero when the activation is * popped from the stack. */ -extern JS_PUBLIC_API(void) -HideScriptedCaller(JSContext* cx); +extern JS_PUBLIC_API void HideScriptedCaller(JSContext* cx); -extern JS_PUBLIC_API(void) -UnhideScriptedCaller(JSContext* cx); +extern JS_PUBLIC_API void UnhideScriptedCaller(JSContext* cx); -class MOZ_RAII AutoHideScriptedCaller -{ - public: - explicit AutoHideScriptedCaller(JSContext* cx - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mContext(cx) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - HideScriptedCaller(mContext); - } - ~AutoHideScriptedCaller() { - UnhideScriptedCaller(mContext); - } - - protected: - JSContext* mContext; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +class MOZ_RAII AutoHideScriptedCaller { + public: + explicit AutoHideScriptedCaller(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mContext(cx) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + HideScriptedCaller(mContext); + } + ~AutoHideScriptedCaller() { UnhideScriptedCaller(mContext); } + + protected: + JSContext* mContext; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; /* @@ -5926,36 +5978,73 @@ */ typedef mozilla::Vector TranscodeBuffer; +typedef mozilla::Range TranscodeRange; -enum TranscodeResult -{ - // Successful encoding / decoding. - TranscodeResult_Ok = 0, - - // 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, - - // 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); +struct TranscodeSource { + TranscodeSource(const TranscodeRange& range_, const char* file, uint32_t line) + : range(range_), filename(file), lineno(line) {} + + const TranscodeRange range; + const char* filename; + const uint32_t lineno; +}; + +typedef mozilla::Vector TranscodeSources; + +enum TranscodeResult { + // Successful encoding / decoding. + TranscodeResult_Ok = 0, + + // 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_BadDecode = TranscodeResult_Failure | 0x4, + TranscodeResult_Failure_WrongCompileOption = TranscodeResult_Failure | 0x5, + TranscodeResult_Failure_NotInterpretedFun = TranscodeResult_Failure | 0x6, + + // There is a pending exception on the context. + 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 +DecodeScript(JSContext* cx, const TranscodeRange& range, + JS::MutableHandleScript scriptp); + +extern JS_PUBLIC_API TranscodeResult DecodeInterpretedFunction( + JSContext* cx, TranscodeBuffer& buffer, JS::MutableHandleFunction funp, + size_t cursorIndex = 0); + +// Register an encoder on the given script source, such that all functions can +// be encoded as they are parsed. This strategy is used to avoid blocking the +// active thread in a non-interruptible way. +// +// The |script| argument of |StartIncrementalEncoding| and +// |FinishIncrementalEncoding| should be the top-level script returned either as +// an out-param of any of the |Compile| functions, or the result of +// |FinishOffThreadScript|. +// +// The |buffer| argument of |FinishIncrementalEncoding| is used for appending +// the encoded bytecode into the buffer. If any of these functions failed, the +// content of |buffer| would be undefined. +extern JS_PUBLIC_API bool StartIncrementalEncoding(JSContext* cx, + JS::HandleScript script); + +extern JS_PUBLIC_API bool FinishIncrementalEncoding(JSContext* cx, + JS::HandleScript script, + TranscodeBuffer& buffer); } /* namespace JS */ @@ -5970,13 +6059,11 @@ * 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 void SetStackFormat(JSContext* cx, StackFormat format); -extern JS_PUBLIC_API(StackFormat) -GetStackFormat(JSContext* cx); +extern JS_PUBLIC_API StackFormat GetStackFormat(JSContext* cx); -} +} // namespace js namespace JS { @@ -5989,28 +6076,27 @@ * CloseAsmJSCacheEntryForReadOp, passing the same base address, size and * handle. */ -typedef bool -(* OpenAsmJSCacheEntryForReadOp)(HandleObject global, const char16_t* begin, const char16_t* limit, - size_t* size, const uint8_t** memory, intptr_t* handle); -typedef void -(* CloseAsmJSCacheEntryForReadOp)(size_t size, const uint8_t* memory, intptr_t handle); +typedef bool (*OpenAsmJSCacheEntryForReadOp)( + HandleObject global, const char16_t* begin, const char16_t* limit, + size_t* size, const uint8_t** memory, intptr_t* handle); +typedef void (*CloseAsmJSCacheEntryForReadOp)(size_t size, + const uint8_t* memory, + intptr_t handle); /** The list of reasons why an asm.js module may not be stored in the cache. */ -enum AsmJSCacheResult -{ - AsmJSCache_Success, - AsmJSCache_MIN = AsmJSCache_Success, - AsmJSCache_ModuleTooSmall, - AsmJSCache_SynchronousScript, - AsmJSCache_QuotaExceeded, - AsmJSCache_StorageInitFailure, - AsmJSCache_Disabled_Internal, - AsmJSCache_Disabled_ShellFlags, - AsmJSCache_Disabled_JitInspector, - AsmJSCache_InternalError, - AsmJSCache_Disabled_PrivateBrowsing, - AsmJSCache_ESR52, - AsmJSCache_LIMIT +enum AsmJSCacheResult { + AsmJSCache_Success, + AsmJSCache_MIN = AsmJSCache_Success, + AsmJSCache_ModuleTooSmall, + AsmJSCache_SynchronousScript, + AsmJSCache_QuotaExceeded, + AsmJSCache_StorageInitFailure, + AsmJSCache_Disabled_Internal, + AsmJSCache_Disabled_ShellFlags, + AsmJSCache_Disabled_JitInspector, + AsmJSCache_InternalError, + AsmJSCache_Disabled_PrivateBrowsing, + AsmJSCache_LIMIT }; /* @@ -6021,30 +6107,22 @@ * outparams. If the callback returns 'true', the JS engine guarantees a call * to CloseAsmJSCacheEntryForWriteOp passing the same base address, size and * handle. - * - * If 'installed' is true, then the cache entry is associated with a permanently - * installed JS file (e.g., in a packaged webapp). This information allows the - * embedding to store the cache entry in a installed location associated with - * the principal of 'global' where it will not be evicted until the associated - * installed JS file is removed. - */ -typedef AsmJSCacheResult -(* OpenAsmJSCacheEntryForWriteOp)(HandleObject global, bool installed, - const char16_t* begin, const char16_t* end, - size_t size, uint8_t** memory, intptr_t* handle); -typedef void -(* CloseAsmJSCacheEntryForWriteOp)(size_t size, uint8_t* memory, intptr_t handle); - -struct AsmJSCacheOps -{ - OpenAsmJSCacheEntryForReadOp openEntryForRead; - CloseAsmJSCacheEntryForReadOp closeEntryForRead; - OpenAsmJSCacheEntryForWriteOp openEntryForWrite; - CloseAsmJSCacheEntryForWriteOp closeEntryForWrite; + */ +typedef AsmJSCacheResult (*OpenAsmJSCacheEntryForWriteOp)( + HandleObject global, const char16_t* begin, const char16_t* end, + size_t size, uint8_t** memory, intptr_t* handle); +typedef void (*CloseAsmJSCacheEntryForWriteOp)(size_t size, uint8_t* memory, + intptr_t handle); + +struct AsmJSCacheOps { + OpenAsmJSCacheEntryForReadOp openEntryForRead; + CloseAsmJSCacheEntryForReadOp closeEntryForRead; + OpenAsmJSCacheEntryForWriteOp openEntryForWrite; + CloseAsmJSCacheEntryForWriteOp closeEntryForWrite; }; -extern JS_PUBLIC_API(void) -SetAsmJSCacheOps(JSContext* cx, const AsmJSCacheOps* callbacks); +extern JS_PUBLIC_API void SetAsmJSCacheOps(JSContext* cx, + const AsmJSCacheOps* callbacks); /** * Return the buildId (represented as a sequence of characters) associated with @@ -6055,26 +6133,38 @@ */ typedef js::Vector BuildIdCharVector; -typedef bool -(* BuildIdOp)(BuildIdCharVector* buildId); +typedef bool (*BuildIdOp)(BuildIdCharVector* buildId); -extern JS_PUBLIC_API(void) -SetBuildIdOp(JSContext* cx, BuildIdOp buildIdOp); +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. + * of efficient postMessage() and (de)serialization from a random thread. + * + * For postMessage() sharing: + * + * - GetWasmModule() is called when making a structured clone of payload + * containing a WebAssembly.Module object. The structured clone buffer holds a + * refcount of the JS::WasmModule until createObject() is called in the target + * agent's JSContext. The new WebAssembly.Module object continues to hold the + * JS::WasmModule and thus the final reference of a JS::WasmModule may be + * dropped from any thread and so the virtual destructor (and all internal + * methods of the C++ module) must be thread-safe. + * + * For (de)serialization: * * - 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. + * This interface is then taken to a background thread where the bytecode and + * compiled code are written into separate 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. Due to tiering, the serialization must + * asynchronously wait for compilation to complete before requesting the + * module's compiled code. After serialization, a reference is dropped from a + * separate thread so the virtual destructor must be thread-safe. * * - Deserialization starts when the structured clone algorithm encounters a * serialized WebAssembly.Module. On a background thread, the compiled-code file @@ -6082,35 +6172,56 @@ * 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(). + * The JS::WasmObject is then transported to a JSContext thread and the wrapping + * WebAssembly.Module object is created by calling createObject(). */ -struct WasmModule : mozilla::external::AtomicRefCounted -{ - MOZ_DECLARE_REFCOUNTED_TYPENAME(WasmModule) - virtual ~WasmModule() {} +class WasmModuleListener { + protected: + virtual ~WasmModuleListener() {} + + public: + // These method signatures are chosen to exactly match nsISupports so that a + // plain nsISupports-implementing class can trivially implement this + // interface too. We can't simply #include "nsISupports.h" so we use MFBT + // equivalents for all the platform-dependent types. + virtual MozExternalRefCountType MOZ_XPCOM_ABI AddRef() = 0; + virtual MozExternalRefCountType MOZ_XPCOM_ABI Release() = 0; - 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 void onCompilationComplete() = 0; +}; + +struct WasmModule : js::AtomicRefCounted { + virtual ~WasmModule() {} + + virtual size_t bytecodeSerializedSize() const = 0; + virtual void bytecodeSerialize(uint8_t* bytecodeBegin, + size_t bytecodeSize) const = 0; - virtual JSObject* createObject(JSContext* cx) = 0; + // Compilation must complete before the serialized code is requested. If + // compilation is not complete, the embedding must wait until notified by + // implementing WasmModuleListener. SpiderMonkey will hold a RefPtr to + // 'listener' until onCompilationComplete() is called. + virtual bool compilationComplete() const = 0; + virtual bool notifyWhenCompilationComplete(WasmModuleListener* listener) = 0; + virtual size_t compiledSerializedSize() const = 0; + virtual void compiledSerialize(uint8_t* compiledBegin, + size_t compiledSize) const = 0; + + virtual JSObject* createObject(JSContext* cx) = 0; }; -extern JS_PUBLIC_API(bool) -IsWasmModuleObject(HandleObject obj); +extern JS_PUBLIC_API bool IsWasmModuleObject(HandleObject obj); -extern JS_PUBLIC_API(RefPtr) -GetWasmModule(HandleObject obj); +extern JS_PUBLIC_API RefPtr GetWasmModule(HandleObject obj); -extern JS_PUBLIC_API(bool) -CompiledWasmModuleAssumptionsMatch(PRFileDesc* compiled, BuildIdCharVector&& buildId); +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); +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: @@ -6129,80 +6240,84 @@ * return false; * } */ -class MOZ_STACK_CLASS JS_PUBLIC_API(ForOfIterator) { - protected: - JSContext* cx_; - /* - * Use the ForOfPIC on the global object (see vm/GlobalObject.h) to try - * to optimize iteration across arrays. - * - * Case 1: Regular Iteration - * iterator - pointer to the iterator object. - * index - fixed to NOT_ARRAY (== UINT32_MAX) - * - * Case 2: Optimized Array Iteration - * iterator - pointer to the array object. - * index - current position in array. - * - * The cases are distinguished by whether or not |index| is equal to NOT_ARRAY. - */ - JS::RootedObject iterator; - uint32_t index; - - static const uint32_t NOT_ARRAY = UINT32_MAX; - - ForOfIterator(const ForOfIterator&) = delete; - ForOfIterator& operator=(const ForOfIterator&) = delete; - - public: - explicit ForOfIterator(JSContext* cx) : cx_(cx), iterator(cx_), index(NOT_ARRAY) { } - - enum NonIterableBehavior { - ThrowOnNonIterable, - AllowNonIterable - }; +class MOZ_STACK_CLASS JS_PUBLIC_API ForOfIterator { + protected: + JSContext* cx_; + /* + * Use the ForOfPIC on the global object (see vm/GlobalObject.h) to try + * to optimize iteration across arrays. + * + * Case 1: Regular Iteration + * iterator - pointer to the iterator object. + * nextMethod - value of |iterator|.next. + * index - fixed to NOT_ARRAY (== UINT32_MAX) + * + * Case 2: Optimized Array Iteration + * iterator - pointer to the array object. + * nextMethod - the undefined value. + * index - current position in array. + * + * The cases are distinguished by whether or not |index| is equal to + * NOT_ARRAY. + */ + JS::RootedObject iterator; + JS::RootedValue nextMethod; + uint32_t index; + + static const uint32_t NOT_ARRAY = UINT32_MAX; + + ForOfIterator(const ForOfIterator&) = delete; + ForOfIterator& operator=(const ForOfIterator&) = delete; + + public: + explicit ForOfIterator(JSContext* cx) + : cx_(cx), iterator(cx_), nextMethod(cx), index(NOT_ARRAY) {} + + enum NonIterableBehavior { ThrowOnNonIterable, AllowNonIterable }; + + /** + * Initialize the iterator. If AllowNonIterable is passed then if getting + * the @@iterator property from iterable returns undefined init() will just + * return true instead of throwing. Callers must then check + * valueIsIterable() before continuing with the iteration. + */ + bool init(JS::HandleValue iterable, + NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable); + + /** + * Get the next value from the iterator. If false *done is true + * after this call, do not examine val. + */ + bool next(JS::MutableHandleValue val, bool* done); + + /** + * Close the iterator. + * For the case that completion type is throw. + */ + void closeThrow(); + + /** + * If initialized with throwOnNonCallable = false, check whether + * the value is iterable. + */ + bool valueIsIterable() const { return iterator; } - /** - * Initialize the iterator. If AllowNonIterable is passed then if getting - * the @@iterator property from iterable returns undefined init() will just - * return true instead of throwing. Callers must then check - * valueIsIterable() before continuing with the iteration. - */ - bool init(JS::HandleValue iterable, - NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable); - - /** - * Get the next value from the iterator. If false *done is true - * after this call, do not examine val. - */ - bool next(JS::MutableHandleValue val, bool* done); - - /** - * If initialized with throwOnNonCallable = false, check whether - * the value is iterable. - */ - bool valueIsIterable() const { - return iterator; - } - - private: - inline bool nextFromOptimizedArray(MutableHandleValue val, bool* done); - bool materializeArrayIterator(); + private: + inline bool nextFromOptimizedArray(MutableHandleValue val, bool* done); }; - /** * If a large allocation fails when calling pod_{calloc,realloc}CanGC, the JS - * engine may call the large-allocation- failure callback, if set, to allow the + * engine may call the large-allocation-failure callback, if set, to allow the * embedding to flush caches, possibly perform shrinking GCs, etc. to make some - * room. The allocation will then be retried (and may still fail.) + * room. The allocation will then be retried (and may still fail.) This callback + * can be called on any thread and must be set at most once in a process. */ -typedef void -(* LargeAllocationFailureCallback)(void* data); +typedef void (*LargeAllocationFailureCallback)(); -extern JS_PUBLIC_API(void) -SetLargeAllocationFailureCallback(JSContext* cx, LargeAllocationFailureCallback afc, void* data); +extern JS_PUBLIC_API void SetProcessLargeAllocationFailureCallback( + LargeAllocationFailureCallback afc); /** * Unlike the error reporter, which is only called if the exception for an OOM @@ -6215,29 +6330,24 @@ * large-allocation-failure callback has returned. */ -typedef void -(* OutOfMemoryCallback)(JSContext* cx, void* data); +typedef void (*OutOfMemoryCallback)(JSContext* cx, void* data); -extern JS_PUBLIC_API(void) -SetOutOfMemoryCallback(JSContext* cx, OutOfMemoryCallback cb, void* data); +extern JS_PUBLIC_API void SetOutOfMemoryCallback(JSContext* cx, + OutOfMemoryCallback cb, + void* data); /** * Capture all frames. */ -struct AllFrames { }; +struct AllFrames {}; /** * Capture at most this many frames. */ -struct MaxFrames -{ - uint32_t maxFrames; - - explicit MaxFrames(uint32_t max) - : maxFrames(max) - { - MOZ_ASSERT(max > 0); - } +struct MaxFrames { + uint32_t maxFrames; + + explicit MaxFrames(uint32_t max) : maxFrames(max) { MOZ_ASSERT(max > 0); } }; /** @@ -6245,48 +6355,42 @@ * 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); - } +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; @@ -6309,9 +6413,9 @@ * |JS::FirstSubsumedFrame::ignoreSelfHosted| flag. Do not capture any async * stack. */ -extern JS_PUBLIC_API(bool) -CaptureCurrentStack(JSContext* cx, MutableHandleObject stackp, - StackCapture&& capture = StackCapture(AllFrames())); +extern JS_PUBLIC_API bool CaptureCurrentStack( + JSContext* cx, MutableHandleObject stackp, + StackCapture&& capture = StackCapture(AllFrames())); /* * This is a utility function for preparing an async stack to be used @@ -6323,14 +6427,13 @@ * Here |asyncStack| is the async stack to prepare. It is copied into * |cx|'s current compartment, and the newest frame is given * |asyncCause| as its asynchronous cause. If |maxFrameCount| is - * non-zero, capture at most the youngest |maxFrameCount| frames. The + * |Some(n)|, capture at most the youngest |n| frames. The * new stack object is written to |stackp|. Returns true on success, * or sets an exception and returns |false| on error. */ -extern JS_PUBLIC_API(bool) -CopyAsyncStack(JSContext* cx, HandleObject asyncStack, - HandleString asyncCause, MutableHandleObject stackp, - unsigned maxFrameCount); +extern JS_PUBLIC_API bool CopyAsyncStack( + JSContext* cx, HandleObject asyncStack, HandleString asyncCause, + MutableHandleObject stackp, const mozilla::Maybe& maxFrameCount); /* * Accessors for working with SavedFrame JSObjects @@ -6362,71 +6465,65 @@ * See also `js/src/doc/SavedFrame/SavedFrame.md`. */ -enum class SavedFrameResult { - Ok, - AccessDenied -}; +enum class SavedFrameResult { Ok, AccessDenied }; -enum class SavedFrameSelfHosted { - Include, - Exclude -}; +enum class SavedFrameSelfHosted { Include, Exclude }; /** * Given a SavedFrame JSObject, get its source property. Defaults to the empty * string. */ -extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString sourcep, - SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); +extern JS_PUBLIC_API SavedFrameResult GetSavedFrameSource( + JSContext* cx, HandleObject savedFrame, MutableHandleString sourcep, + SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its line property. Defaults to 0. */ -extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep, - SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); +extern JS_PUBLIC_API SavedFrameResult GetSavedFrameLine( + JSContext* cx, HandleObject savedFrame, uint32_t* linep, + SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its column property. Defaults to 0. */ -extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp, - SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); +extern JS_PUBLIC_API SavedFrameResult GetSavedFrameColumn( + JSContext* cx, HandleObject savedFrame, uint32_t* columnp, + SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its functionDisplayName string, or nullptr * if SpiderMonkey was unable to infer a name for the captured frame's * function. Defaults to nullptr. */ -extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, MutableHandleString namep, - SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); +extern JS_PUBLIC_API SavedFrameResult GetSavedFrameFunctionDisplayName( + JSContext* cx, HandleObject savedFrame, MutableHandleString namep, + SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its asyncCause string. Defaults to nullptr. */ -extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleString asyncCausep, - SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); +extern JS_PUBLIC_API SavedFrameResult GetSavedFrameAsyncCause( + JSContext* cx, HandleObject savedFrame, MutableHandleString asyncCausep, + SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its asyncParent SavedFrame object or nullptr * if there is no asyncParent. The `asyncParentp` out parameter is _NOT_ * guaranteed to be in the cx's compartment. Defaults to nullptr. */ -extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject asyncParentp, - SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); +extern JS_PUBLIC_API SavedFrameResult GetSavedFrameAsyncParent( + JSContext* cx, HandleObject savedFrame, MutableHandleObject asyncParentp, + SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its parent SavedFrame object or nullptr if * it is the oldest frame in the stack. The `parentp` out parameter is _NOT_ * guaranteed to be in the cx's compartment. Defaults to nullptr. */ -extern JS_PUBLIC_API(SavedFrameResult) -GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject parentp, - SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); +extern JS_PUBLIC_API SavedFrameResult GetSavedFrameParent( + JSContext* cx, HandleObject savedFrame, MutableHandleObject parentp, + SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject stack, stringify it in the same format as @@ -6440,20 +6537,18 @@ * Optional indent parameter specifies the number of white spaces to indent * each line. */ -extern JS_PUBLIC_API(bool) -BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp, - size_t indent = 0, js::StackFormat stackFormat = js::StackFormat::Default); +extern JS_PUBLIC_API bool 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); +extern JS_PUBLIC_API bool IsSavedFrame(JSObject* obj); } /* namespace JS */ - /* Stopwatch-based performance monitoring. */ namespace js { @@ -6466,124 +6561,124 @@ * provide a concrete implementation of this class, as well as the * relevant callbacks (see below). */ -struct JS_PUBLIC_API(PerformanceGroup) { - PerformanceGroup(); - - // The current iteration of the event loop. - uint64_t iteration() const; +struct JS_PUBLIC_API PerformanceGroup { + PerformanceGroup(); - // `true` if an instance of `AutoStopwatch` is already monitoring - // the performance of this performance group for this iteration - // of the event loop, `false` otherwise. - bool isAcquired(uint64_t it) const; - - // `true` if a specific instance of `AutoStopwatch` is already monitoring - // the performance of this performance group for this iteration - // of the event loop, `false` otherwise. - bool isAcquired(uint64_t it, const AutoStopwatch* owner) const; - - // Mark that an instance of `AutoStopwatch` is monitoring - // the performance of this group for a given iteration. - void acquire(uint64_t it, const AutoStopwatch* owner); - - // Mark that no `AutoStopwatch` is monitoring the - // performance of this group for the iteration. - void release(uint64_t it, const AutoStopwatch* owner); - - // The number of cycles spent in this group during this iteration - // of the event loop. Note that cycles are not a reliable measure, - // especially over short intervals. See Stopwatch.* for a more - // complete discussion on the imprecision of cycle measurement. - uint64_t recentCycles(uint64_t iteration) const; - void addRecentCycles(uint64_t iteration, uint64_t cycles); - - // The number of times this group has been activated during this - // iteration of the event loop. - uint64_t recentTicks(uint64_t iteration) const; - void addRecentTicks(uint64_t iteration, uint64_t ticks); - - // The number of microseconds spent doing CPOW during this - // iteration of the event loop. - uint64_t recentCPOW(uint64_t iteration) const; - void addRecentCPOW(uint64_t iteration, uint64_t CPOW); - - // Get rid of any data that pretends to be recent. - void resetRecentData(); - - // `true` if new measures should be added to this group, `false` - // otherwise. - bool isActive() const; - void setIsActive(bool); - - // `true` if this group has been used in the current iteration, - // `false` otherwise. - bool isUsedInThisIteration() const; - void setIsUsedInThisIteration(bool); - protected: - // An implementation of `delete` for this object. Must be provided - // by the embedding. - virtual void Delete() = 0; + // The current iteration of the event loop. + uint64_t iteration() const; - private: - // The number of cycles spent in this group during this iteration - // of the event loop. Note that cycles are not a reliable measure, - // especially over short intervals. See Runtime.cpp for a more - // complete discussion on the imprecision of cycle measurement. - uint64_t recentCycles_; - - // The number of times this group has been activated during this - // iteration of the event loop. - uint64_t recentTicks_; - - // The number of microseconds spent doing CPOW during this - // iteration of the event loop. - uint64_t recentCPOW_; - - // The current iteration of the event loop. If necessary, - // may safely overflow. - uint64_t iteration_; - - // `true` if new measures should be added to this group, `false` - // otherwise. - bool isActive_; - - // `true` if this group has been used in the current iteration, - // `false` otherwise. - bool isUsedInThisIteration_; - - // The stopwatch currently monitoring the group, - // or `nullptr` if none. Used ony for comparison. - const AutoStopwatch* owner_; - - public: - // Compatibility with RefPtr<> - void AddRef(); - void Release(); - uint64_t refCount_; + // `true` if an instance of `AutoStopwatch` is already monitoring + // the performance of this performance group for this iteration + // of the event loop, `false` otherwise. + bool isAcquired(uint64_t it) const; + + // `true` if a specific instance of `AutoStopwatch` is already monitoring + // the performance of this performance group for this iteration + // of the event loop, `false` otherwise. + bool isAcquired(uint64_t it, const AutoStopwatch* owner) const; + + // Mark that an instance of `AutoStopwatch` is monitoring + // the performance of this group for a given iteration. + void acquire(uint64_t it, const AutoStopwatch* owner); + + // Mark that no `AutoStopwatch` is monitoring the + // performance of this group for the iteration. + void release(uint64_t it, const AutoStopwatch* owner); + + // The number of cycles spent in this group during this iteration + // of the event loop. Note that cycles are not a reliable measure, + // especially over short intervals. See Stopwatch.* for a more + // complete discussion on the imprecision of cycle measurement. + uint64_t recentCycles(uint64_t iteration) const; + void addRecentCycles(uint64_t iteration, uint64_t cycles); + + // The number of times this group has been activated during this + // iteration of the event loop. + uint64_t recentTicks(uint64_t iteration) const; + void addRecentTicks(uint64_t iteration, uint64_t ticks); + + // The number of microseconds spent doing CPOW during this + // iteration of the event loop. + uint64_t recentCPOW(uint64_t iteration) const; + void addRecentCPOW(uint64_t iteration, uint64_t CPOW); + + // Get rid of any data that pretends to be recent. + void resetRecentData(); + + // `true` if new measures should be added to this group, `false` + // otherwise. + bool isActive() const; + void setIsActive(bool); + + // `true` if this group has been used in the current iteration, + // `false` otherwise. + bool isUsedInThisIteration() const; + void setIsUsedInThisIteration(bool); + + protected: + // An implementation of `delete` for this object. Must be provided + // by the embedding. + virtual void Delete() = 0; + + private: + // The number of cycles spent in this group during this iteration + // of the event loop. Note that cycles are not a reliable measure, + // especially over short intervals. See Runtime.cpp for a more + // complete discussion on the imprecision of cycle measurement. + uint64_t recentCycles_; + + // The number of times this group has been activated during this + // iteration of the event loop. + uint64_t recentTicks_; + + // The number of microseconds spent doing CPOW during this + // iteration of the event loop. + uint64_t recentCPOW_; + + // The current iteration of the event loop. If necessary, + // may safely overflow. + uint64_t iteration_; + + // `true` if new measures should be added to this group, `false` + // otherwise. + bool isActive_; + + // `true` if this group has been used in the current iteration, + // `false` otherwise. + bool isUsedInThisIteration_; + + // The stopwatch currently monitoring the group, + // or `nullptr` if none. Used ony for comparison. + const AutoStopwatch* owner_; + + public: + // Compatibility with RefPtr<> + void AddRef(); + void Release(); + uint64_t refCount_; }; -using PerformanceGroupVector = mozilla::Vector, 0, SystemAllocPolicy>; +using PerformanceGroupVector = + mozilla::Vector, 8, SystemAllocPolicy>; /** * Commit any Performance Monitoring data. * - * Until `FlushMonitoring` has been called, all PerformanceMonitoring data is invisible - * to the outside world and can cancelled with a call to `ResetMonitoring`. + * Until `FlushMonitoring` has been called, all PerformanceMonitoring data is + * invisible to the outside world and can cancelled with a call to + * `ResetMonitoring`. */ -extern JS_PUBLIC_API(bool) -FlushPerformanceMonitoring(JSContext*); +extern JS_PUBLIC_API bool FlushPerformanceMonitoring(JSContext*); /** * Cancel any measurement that hasn't been committed. */ -extern JS_PUBLIC_API(void) -ResetPerformanceMonitoring(JSContext*); +extern JS_PUBLIC_API void ResetPerformanceMonitoring(JSContext*); /** * Cleanup any memory used by performance monitoring. */ -extern JS_PUBLIC_API(void) -DisposePerformanceMonitoring(JSContext*); +extern JS_PUBLIC_API void DisposePerformanceMonitoring(JSContext*); /** * Turn on/off stopwatch-based CPU monitoring. @@ -6592,43 +6687,50 @@ * may return `false` if monitoring could not be activated, which may * happen if we are out of memory. */ -extern JS_PUBLIC_API(bool) -SetStopwatchIsMonitoringCPOW(JSContext*, bool); -extern JS_PUBLIC_API(bool) -GetStopwatchIsMonitoringCPOW(JSContext*); -extern JS_PUBLIC_API(bool) -SetStopwatchIsMonitoringJank(JSContext*, bool); -extern JS_PUBLIC_API(bool) -GetStopwatchIsMonitoringJank(JSContext*); +extern JS_PUBLIC_API bool SetStopwatchIsMonitoringCPOW(JSContext*, bool); +extern JS_PUBLIC_API bool GetStopwatchIsMonitoringCPOW(JSContext*); +extern JS_PUBLIC_API bool SetStopwatchIsMonitoringJank(JSContext*, bool); +extern JS_PUBLIC_API bool GetStopwatchIsMonitoringJank(JSContext*); // Extract the CPU rescheduling data. -extern JS_PUBLIC_API(void) -GetPerfMonitoringTestCpuRescheduling(JSContext*, uint64_t* stayed, uint64_t* moved); - +extern JS_PUBLIC_API void GetPerfMonitoringTestCpuRescheduling(JSContext*, + uint64_t* stayed, + uint64_t* moved); /** * Add a number of microseconds to the time spent waiting on CPOWs * since process start. */ -extern JS_PUBLIC_API(void) -AddCPOWPerformanceDelta(JSContext*, uint64_t delta); +extern JS_PUBLIC_API void AddCPOWPerformanceDelta(JSContext*, uint64_t delta); -typedef bool -(*StopwatchStartCallback)(uint64_t, void*); -extern JS_PUBLIC_API(bool) -SetStopwatchStartCallback(JSContext*, StopwatchStartCallback, void*); - -typedef bool -(*StopwatchCommitCallback)(uint64_t, PerformanceGroupVector&, void*); -extern JS_PUBLIC_API(bool) -SetStopwatchCommitCallback(JSContext*, StopwatchCommitCallback, void*); - -typedef bool -(*GetGroupsCallback)(JSContext*, PerformanceGroupVector&, void*); -extern JS_PUBLIC_API(bool) -SetGetPerformanceGroupsCallback(JSContext*, GetGroupsCallback, void*); +typedef bool (*StopwatchStartCallback)(uint64_t, void*); +extern JS_PUBLIC_API bool SetStopwatchStartCallback(JSContext*, + StopwatchStartCallback, + void*); + +typedef bool (*StopwatchCommitCallback)(uint64_t, PerformanceGroupVector&, + void*); +extern JS_PUBLIC_API bool SetStopwatchCommitCallback(JSContext*, + StopwatchCommitCallback, + void*); + +typedef bool (*GetGroupsCallback)(JSContext*, PerformanceGroupVector&, void*); +extern JS_PUBLIC_API bool SetGetPerformanceGroupsCallback(JSContext*, + GetGroupsCallback, + void*); + +/** + * Hint that we expect a crash. Currently, the only thing that cares is the + * breakpad injector, which (if loaded) will suppress minidump generation. + */ +extern JS_PUBLIC_API void NoteIntentionalCrash(); } /* namespace js */ +namespace js { + +enum class CompletionKind { Normal, Return, Throw }; + +} /* namespace js */ #endif /* jsapi_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/jsbytecode.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/jsbytecode.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/jsbytecode.h @@ -1,14 +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 jsbytecode_h -#define jsbytecode_h - -#include - -typedef uint8_t jsbytecode; - -#endif /* jsbytecode_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/jsclist.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/jsclist.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/jsclist.h @@ -1,107 +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 jsclist_h -#define jsclist_h - -#include "jstypes.h" - -/* -** Circular linked list -*/ -typedef struct JSCListStr { - struct JSCListStr* next; - struct JSCListStr* prev; -} JSCList; - -/* -** Insert element "_e" into the list, before "_l". -*/ -#define JS_INSERT_BEFORE(_e,_l) \ - JS_BEGIN_MACRO \ - (_e)->next = (_l); \ - (_e)->prev = (_l)->prev; \ - (_l)->prev->next = (_e); \ - (_l)->prev = (_e); \ - JS_END_MACRO - -/* -** Insert element "_e" into the list, after "_l". -*/ -#define JS_INSERT_AFTER(_e,_l) \ - JS_BEGIN_MACRO \ - (_e)->next = (_l)->next; \ - (_e)->prev = (_l); \ - (_l)->next->prev = (_e); \ - (_l)->next = (_e); \ - JS_END_MACRO - -/* -** Return the element following element "_e" -*/ -#define JS_NEXT_LINK(_e) \ - ((_e)->next) -/* -** Return the element preceding element "_e" -*/ -#define JS_PREV_LINK(_e) \ - ((_e)->prev) - -/* -** Append an element "_e" to the end of the list "_l" -*/ -#define JS_APPEND_LINK(_e,_l) JS_INSERT_BEFORE(_e,_l) - -/* -** Insert an element "_e" at the head of the list "_l" -*/ -#define JS_INSERT_LINK(_e,_l) JS_INSERT_AFTER(_e,_l) - -/* Return the head/tail of the list */ -#define JS_LIST_HEAD(_l) (_l)->next -#define JS_LIST_TAIL(_l) (_l)->prev - -/* -** Remove the element "_e" from it's circular list. -*/ -#define JS_REMOVE_LINK(_e) \ - JS_BEGIN_MACRO \ - (_e)->prev->next = (_e)->next; \ - (_e)->next->prev = (_e)->prev; \ - JS_END_MACRO - -/* -** Remove the element "_e" from it's circular list. Also initializes the -** linkage. -*/ -#define JS_REMOVE_AND_INIT_LINK(_e) \ - JS_BEGIN_MACRO \ - (_e)->prev->next = (_e)->next; \ - (_e)->next->prev = (_e)->prev; \ - (_e)->next = (_e); \ - (_e)->prev = (_e); \ - JS_END_MACRO - -/* -** Return non-zero if the given circular list "_l" is empty, zero if the -** circular list is not empty -*/ -#define JS_CLIST_IS_EMPTY(_l) \ - bool((_l)->next == (_l)) - -/* -** Initialize a circular list -*/ -#define JS_INIT_CLIST(_l) \ - JS_BEGIN_MACRO \ - (_l)->next = (_l); \ - (_l)->prev = (_l); \ - JS_END_MACRO - -#define JS_INIT_STATIC_CLIST(_l) \ - {(_l), (_l)} - -#endif /* jsclist_h */ 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 @@ -1,20 +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 jscpucfg_h -#define jscpucfg_h - -#include "mozilla/EndianUtils.h" - -#ifndef JS_STACK_GROWTH_DIRECTION -# ifdef __hppa -# define JS_STACK_GROWTH_DIRECTION (1) -# else -# define JS_STACK_GROWTH_DIRECTION (-1) -# endif -#endif - -#endif /* jscpucfg_h */ 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 @@ -13,22 +13,30 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/UniquePtr.h" -#include "jsapi.h" // For JSAutoByteString. See bug 1033916. -#include "jsbytecode.h" +#include "jsapi.h" // For JSAutoByteString. See bug 1033916. #include "jspubtd.h" #include "js/CallArgs.h" #include "js/CallNonGenericMethod.h" #include "js/Class.h" +#include "js/HeapAPI.h" +#include "js/TypeDecls.h" #include "js/Utility.h" +#ifndef JS_STACK_GROWTH_DIRECTION +#ifdef __hppa +#define JS_STACK_GROWTH_DIRECTION (1) +#else +#define JS_STACK_GROWTH_DIRECTION (-1) +#endif +#endif + #if JS_STACK_GROWTH_DIRECTION > 0 -# define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) < (limit))) +#define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) < (limit))) #else -# define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) > (limit))) +#define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) > (limit))) #endif -class JSAtom; struct JSErrorFormatString; class JSLinearString; struct JSJitInfo; @@ -40,24 +48,25 @@ } /* namespace JS */ namespace js { -class JS_FRIEND_API(BaseProxyHandler); +class JS_FRIEND_API BaseProxyHandler; class InterpreterFrame; } /* namespace js */ -extern JS_FRIEND_API(void) -JS_SetGrayGCRootsTracer(JSContext* cx, JSTraceDataOp traceOp, void* data); +extern JS_FRIEND_API void JS_SetGrayGCRootsTracer(JSContext* cx, + JSTraceDataOp traceOp, + void* data); -extern JS_FRIEND_API(JSObject*) -JS_FindCompilationScope(JSContext* cx, JS::HandleObject obj); +extern JS_FRIEND_API JSObject* JS_FindCompilationScope(JSContext* cx, + JS::HandleObject obj); -extern JS_FRIEND_API(JSFunction*) -JS_GetObjectFunction(JSObject* obj); +extern JS_FRIEND_API JSFunction* JS_GetObjectFunction(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_SplicePrototype(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto); +extern JS_FRIEND_API bool JS_SplicePrototype(JSContext* cx, + JS::HandleObject obj, + JS::HandleObject proto); -extern JS_FRIEND_API(JSObject*) -JS_NewObjectWithUniqueType(JSContext* cx, const JSClass* clasp, JS::HandleObject proto); +extern JS_FRIEND_API JSObject* JS_NewObjectWithUniqueType( + JSContext* cx, const JSClass* clasp, JS::HandleObject proto); /** * Allocate an object in exactly the same way as JS_NewObjectWithGivenProto, but @@ -65,27 +74,21 @@ * internal bookkeeping objects that are guaranteed to not have metadata * attached to them. */ -extern JS_FRIEND_API(JSObject*) -JS_NewObjectWithoutMetadata(JSContext* cx, const JSClass* clasp, JS::Handle proto); - -extern JS_FRIEND_API(uint32_t) -JS_ObjectCountDynamicSlots(JS::HandleObject obj); - -extern JS_FRIEND_API(size_t) -JS_SetProtoCalled(JSContext* cx); +extern JS_FRIEND_API JSObject* JS_NewObjectWithoutMetadata( + JSContext* cx, const JSClass* clasp, JS::Handle proto); -extern JS_FRIEND_API(size_t) -JS_GetCustomIteratorCount(JSContext* cx); +extern JS_FRIEND_API uint32_t JS_ObjectCountDynamicSlots(JS::HandleObject obj); -extern JS_FRIEND_API(bool) -JS_NondeterministicGetWeakMapKeys(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret); +extern JS_FRIEND_API bool JS_NondeterministicGetWeakMapKeys( + JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret); -extern JS_FRIEND_API(bool) -JS_NondeterministicGetWeakSetKeys(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret); +extern JS_FRIEND_API bool JS_NondeterministicGetWeakSetKeys( + JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret); // Raw JSScript* because this needs to be callable from a signal handler. -extern JS_FRIEND_API(unsigned) -JS_PCToLineNumber(JSScript* script, jsbytecode* pc, unsigned* columnp = nullptr); +extern JS_FRIEND_API unsigned JS_PCToLineNumber(JSScript* script, + jsbytecode* pc, + unsigned* columnp = nullptr); /** * Determine whether the given object is backed by a DeadObjectProxy. @@ -93,75 +96,113 @@ * Such objects hold no other objects (they have no outgoing reference edges) * and will throw if you touch them (e.g. by reading/writing a property). */ -extern JS_FRIEND_API(bool) -JS_IsDeadWrapper(JSObject* obj); +extern JS_FRIEND_API bool JS_IsDeadWrapper(JSObject* obj); + +/** + * Creates a new dead wrapper object in the given scope. To be used when + * attempting to wrap objects from scopes which are already dead. + * + * If origObject is passed, it must be an proxy object, and will be + * used to determine the characteristics of the new dead wrapper. + */ +extern JS_FRIEND_API JSObject* JS_NewDeadWrapper( + JSContext* cx, JSObject* origObject = nullptr); + +/** + * Determine whether the given object is a ScriptSourceObject. + */ +extern JS_FRIEND_API bool JS_IsScriptSourceObject(JSObject* obj); /* * Used by the cycle collector to trace through a shape or object group and * all cycle-participating data it reaches, using bounded stack space. */ -extern JS_FRIEND_API(void) -JS_TraceShapeCycleCollectorChildren(JS::CallbackTracer* trc, JS::GCCellPtr shape); -extern JS_FRIEND_API(void) -JS_TraceObjectGroupCycleCollectorChildren(JS::CallbackTracer* trc, JS::GCCellPtr group); +extern JS_FRIEND_API void JS_TraceShapeCycleCollectorChildren( + JS::CallbackTracer* trc, JS::GCCellPtr shape); +extern JS_FRIEND_API void JS_TraceObjectGroupCycleCollectorChildren( + JS::CallbackTracer* trc, JS::GCCellPtr group); +/* + * Telemetry reasons passed to the accumulate telemetry callback. + * + * It's OK for these enum values to change as they will be mapped to a fixed + * member of the mozilla::Telemetry::HistogramID enum by the callback. + */ enum { - JS_TELEMETRY_GC_REASON, - 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_AOT_USAGE, - JS_TELEMETRY_END -}; - -typedef void -(*JSAccumulateTelemetryDataCallback)(int id, uint32_t sample, const char* key); - -extern JS_FRIEND_API(void) -JS_SetAccumulateTelemetryCallback(JSContext* cx, JSAccumulateTelemetryDataCallback callback); - -extern JS_FRIEND_API(bool) -JS_GetIsSecureContext(JSCompartment* compartment); - -extern JS_FRIEND_API(JSPrincipals*) -JS_GetCompartmentPrincipals(JSCompartment* compartment); - -extern JS_FRIEND_API(void) -JS_SetCompartmentPrincipals(JSCompartment* compartment, JSPrincipals* principals); + JS_TELEMETRY_GC_REASON, + JS_TELEMETRY_GC_IS_ZONE_GC, + JS_TELEMETRY_GC_MS, + JS_TELEMETRY_GC_BUDGET_MS, + JS_TELEMETRY_GC_BUDGET_OVERRUN, + JS_TELEMETRY_GC_ANIMATION_MS, + JS_TELEMETRY_GC_MAX_PAUSE_MS_2, + 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_SLOW_TASK, + 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_ADDON_EXCEPTIONS, + JS_TELEMETRY_PRIVILEGED_PARSER_COMPILE_LAZY_AFTER_MS, + JS_TELEMETRY_WEB_PARSER_COMPILE_LAZY_AFTER_MS, + JS_TELEMETRY_END +}; + +typedef void (*JSAccumulateTelemetryDataCallback)(int id, uint32_t sample, + const char* key); + +extern JS_FRIEND_API void JS_SetAccumulateTelemetryCallback( + JSContext* cx, JSAccumulateTelemetryDataCallback callback); + +/* + * Use counter names passed to the accumulate use counter callback. + * + * It's OK to for these enum values to change as they will be mapped to a + * fixed member of the mozilla::UseCounter enum by the callback. + */ + +enum class JSUseCounter { ASMJS, WASM }; + +typedef void (*JSSetUseCounterCallback)(JSObject* obj, JSUseCounter counter); + +extern JS_FRIEND_API void JS_SetSetUseCounterCallback( + JSContext* cx, JSSetUseCounterCallback callback); + +extern JS_FRIEND_API bool JS_GetIsSecureContext(JSCompartment* compartment); -extern JS_FRIEND_API(JSPrincipals*) -JS_GetScriptPrincipals(JSScript* script); +extern JS_FRIEND_API JSPrincipals* JS_GetCompartmentPrincipals( + JSCompartment* compartment); -extern JS_FRIEND_API(bool) -JS_ScriptHasMutedErrors(JSScript* script); +extern JS_FRIEND_API void JS_SetCompartmentPrincipals( + JSCompartment* compartment, JSPrincipals* principals); -extern JS_FRIEND_API(JSObject*) -JS_CloneObject(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto); +extern JS_FRIEND_API JSPrincipals* JS_GetScriptPrincipals(JSScript* script); + +namespace js { +extern JS_FRIEND_API JSCompartment* GetScriptCompartment(JSScript* script); +} /* namespace js */ + +extern JS_FRIEND_API bool JS_ScriptHasMutedErrors(JSScript* script); + +extern JS_FRIEND_API JSObject* JS_CloneObject(JSContext* cx, + JS::HandleObject obj, + JS::HandleObject proto); /** * Copy the own properties of src to dst in a fast way. src and dst must both @@ -176,33 +217,27 @@ * dst needs to have the compartment global as its parent. This function will * preserve the existing metadata on dst, if any. */ -extern JS_FRIEND_API(bool) -JS_InitializePropertiesFromCompatibleNativeObject(JSContext* cx, - JS::HandleObject dst, - JS::HandleObject src); +extern JS_FRIEND_API bool JS_InitializePropertiesFromCompatibleNativeObject( + JSContext* cx, JS::HandleObject dst, JS::HandleObject src); -extern JS_FRIEND_API(JSString*) -JS_BasicObjectToString(JSContext* cx, JS::HandleObject obj); +extern JS_FRIEND_API JSString* JS_BasicObjectToString(JSContext* cx, + JS::HandleObject obj); namespace js { -JS_FRIEND_API(bool) -GetBuiltinClass(JSContext* cx, JS::HandleObject obj, ESClass* cls); +JS_FRIEND_API bool GetBuiltinClass(JSContext* cx, JS::HandleObject obj, + ESClass* cls); -JS_FRIEND_API(const char*) -ObjectClassName(JSContext* cx, JS::HandleObject obj); +JS_FRIEND_API const char* ObjectClassName(JSContext* cx, JS::HandleObject obj); -JS_FRIEND_API(void) -ReportOverRecursed(JSContext* maybecx); +JS_FRIEND_API void ReportOverRecursed(JSContext* maybecx); -JS_FRIEND_API(bool) -AddRawValueRoot(JSContext* cx, JS::Value* vp, const char* name); +JS_FRIEND_API bool AddRawValueRoot(JSContext* cx, JS::Value* vp, + const char* name); -JS_FRIEND_API(void) -RemoveRawValueRoot(JSContext* cx, JS::Value* vp); +JS_FRIEND_API void RemoveRawValueRoot(JSContext* cx, JS::Value* vp); -JS_FRIEND_API(JSAtom*) -GetPropertyNameFromPC(JSScript* script, jsbytecode* pc); +JS_FRIEND_API JSAtom* GetPropertyNameFromPC(JSScript* script, jsbytecode* pc); #ifdef JS_DEBUG @@ -213,69 +248,71 @@ * parameter, which will default to stderr. */ -extern JS_FRIEND_API(void) -DumpString(JSString* str, FILE* fp); +extern JS_FRIEND_API void DumpString(JSString* str, FILE* fp); -extern JS_FRIEND_API(void) -DumpAtom(JSAtom* atom, FILE* fp); +extern JS_FRIEND_API void DumpAtom(JSAtom* atom, FILE* fp); -extern JS_FRIEND_API(void) -DumpObject(JSObject* obj, FILE* fp); +extern JS_FRIEND_API void DumpObject(JSObject* obj, FILE* fp); -extern JS_FRIEND_API(void) -DumpChars(const char16_t* s, size_t n, FILE* fp); +extern JS_FRIEND_API void DumpChars(const char16_t* s, size_t n, FILE* fp); -extern JS_FRIEND_API(void) -DumpValue(const JS::Value& val, FILE* fp); +extern JS_FRIEND_API void DumpValue(const JS::Value& val, FILE* fp); -extern JS_FRIEND_API(void) -DumpId(jsid id, FILE* fp); +extern JS_FRIEND_API void DumpId(jsid id, FILE* fp); -extern JS_FRIEND_API(void) -DumpInterpreterFrame(JSContext* cx, FILE* fp, InterpreterFrame* start = nullptr); +extern JS_FRIEND_API void DumpInterpreterFrame( + JSContext* cx, FILE* fp, InterpreterFrame* start = nullptr); -extern JS_FRIEND_API(bool) -DumpPC(JSContext* cx, FILE* fp); +extern JS_FRIEND_API bool DumpPC(JSContext* cx, FILE* fp); -extern JS_FRIEND_API(bool) -DumpScript(JSContext* cx, JSScript* scriptArg, FILE* fp); +extern JS_FRIEND_API bool 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); +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, FILE* fp); -extern JS_FRIEND_API(void) -DumpBacktrace(JSContext* cx); +extern JS_FRIEND_API void DumpBacktrace(JSContext* cx); -} // namespace js +} // namespace js namespace JS { /** Exposed for DumpJSStack */ -extern JS_FRIEND_API(char*) -FormatStackDump(JSContext* cx, char* buf, bool showArgs, bool showLocals, bool showThisProps); +extern JS_FRIEND_API JS::UniqueChars FormatStackDump(JSContext* cx, + JS::UniqueChars&& 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); +extern JS_FRIEND_API bool ForceLexicalInitialization(JSContext* cx, + HandleObject obj); -} // namespace JS +/** + * Whether we are poisoning unused/released data for error detection. Governed + * by the JS_GC_POISONING #ifdef as well as the $JSGC_DISABLE_POISONING + * environment variable. + */ +extern JS_FRIEND_API int IsGCPoisoning(); + +} // namespace JS /** * Copies all own properties from |obj| to |target|. |obj| must be a "native" @@ -284,8 +321,9 @@ * This function immediately enters a compartment, and does not impose any * restrictions on the compartment of |cx|. */ -extern JS_FRIEND_API(bool) -JS_CopyPropertiesFrom(JSContext* cx, JS::HandleObject target, JS::HandleObject obj); +extern JS_FRIEND_API bool JS_CopyPropertiesFrom(JSContext* cx, + JS::HandleObject target, + JS::HandleObject obj); /* * Single-property version of the above. This function asserts that an |own| @@ -296,129 +334,45 @@ * The copyBehavior argument controls what happens with * non-configurable properties. */ -typedef enum { - MakeNonConfigurableIntoConfigurable, - CopyNonConfigurableAsIs +typedef enum { + MakeNonConfigurableIntoConfigurable, + CopyNonConfigurableAsIs } PropertyCopyBehavior; -extern JS_FRIEND_API(bool) -JS_CopyPropertyFrom(JSContext* cx, JS::HandleId id, JS::HandleObject target, - JS::HandleObject obj, - PropertyCopyBehavior copyBehavior = CopyNonConfigurableAsIs); +extern JS_FRIEND_API bool JS_CopyPropertyFrom( + JSContext* cx, JS::HandleId id, JS::HandleObject target, + JS::HandleObject obj, + PropertyCopyBehavior copyBehavior = CopyNonConfigurableAsIs); -extern JS_FRIEND_API(bool) -JS_WrapPropertyDescriptor(JSContext* cx, JS::MutableHandle desc); +extern JS_FRIEND_API bool JS_WrapPropertyDescriptor( + JSContext* cx, JS::MutableHandle desc); struct JSFunctionSpecWithHelp { - const char* name; - JSNative call; - uint16_t nargs; - uint16_t flags; - const JSJitInfo* jitInfo; - const char* usage; - const char* help; -}; - -#define JS_FN_HELP(name,call,nargs,flags,usage,help) \ - {name, call, nargs, (flags) | JSPROP_ENUMERATE | JSFUN_STUB_GSOPS, nullptr, usage, help} -#define JS_INLINABLE_FN_HELP(name,call,nargs,flags,native,usage,help) \ - {name, call, nargs, (flags) | JSPROP_ENUMERATE | JSFUN_STUB_GSOPS, &js::jit::JitInfo_##native,\ - usage, help} -#define JS_FS_HELP_END \ - {nullptr, nullptr, 0, 0, nullptr, nullptr} - -extern JS_FRIEND_API(bool) -JS_DefineFunctionsWithHelp(JSContext* cx, JS::HandleObject obj, const JSFunctionSpecWithHelp* fs); - -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(objectMoved) \ - { \ - js::proxy_WeakmapKeyDelegate, \ - objectMoved \ - } + const char* name; + JSNative call; + uint16_t nargs; + uint16_t flags; + const JSJitInfo* jitInfo; + const char* usage; + const char* help; +}; -#define PROXY_CLASS_WITH_EXT(name, flags, extPtr) \ - { \ - name, \ - js::Class::NON_NATIVE | \ - JSCLASS_IS_PROXY | \ - JSCLASS_DELAY_METADATA_BUILDER | \ - flags, \ - &js::ProxyClassOps, \ - JS_NULL_CLASS_SPEC, \ - extPtr, \ - &js::ProxyObjectOps \ - } +#define JS_FN_HELP(name, call, nargs, flags, usage, help) \ + { name, call, nargs, (flags) | JSPROP_ENUMERATE, nullptr, usage, help } +#define JS_INLINABLE_FN_HELP(name, call, nargs, flags, native, usage, help) \ + { \ + name, call, nargs, (flags) | JSPROP_ENUMERATE, &js::jit::JitInfo_##native, \ + usage, help \ + } +#define JS_FS_HELP_END \ + { nullptr, nullptr, 0, 0, nullptr, nullptr } -#define PROXY_CLASS_DEF(name, flags) \ - PROXY_CLASS_WITH_EXT(name, flags, &js::ProxyClassExtension) +extern JS_FRIEND_API bool JS_DefineFunctionsWithHelp( + JSContext* cx, JS::HandleObject obj, const JSFunctionSpecWithHelp* fs); -/* - * Proxy stubs, similar to JS_*Stub, for embedder proxy class definitions. - * - * NB: Should not be called directly. - */ +namespace js { -extern JS_FRIEND_API(bool) -proxy_LookupProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp, - JS::MutableHandle propp); -extern JS_FRIEND_API(bool) -proxy_DefineProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc, - JS::ObjectOpResult& result); -extern JS_FRIEND_API(bool) -proxy_HasProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); -extern JS_FRIEND_API(bool) -proxy_GetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleValue receiver, JS::HandleId id, - JS::MutableHandleValue vp); -extern JS_FRIEND_API(bool) -proxy_SetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue bp, - JS::HandleValue receiver, JS::ObjectOpResult& result); -extern JS_FRIEND_API(bool) -proxy_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); -extern JS_FRIEND_API(bool) -proxy_DeleteProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::ObjectOpResult& result); - -extern JS_FRIEND_API(void) -proxy_Trace(JSTracer* trc, JSObject* obj); -extern JS_FRIEND_API(JSObject*) -proxy_WeakmapKeyDelegate(JSObject* obj); -extern JS_FRIEND_API(bool) -proxy_Convert(JSContext* cx, JS::HandleObject proxy, JSType hint, JS::MutableHandleValue vp); -extern JS_FRIEND_API(void) -proxy_Finalize(FreeOp* fop, JSObject* obj); -extern JS_FRIEND_API(void) -proxy_ObjectMoved(JSObject* obj, const JSObject* old); -extern JS_FRIEND_API(bool) -proxy_HasInstance(JSContext* cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool* bp); -extern JS_FRIEND_API(bool) -proxy_Call(JSContext* cx, unsigned argc, JS::Value* vp); -extern JS_FRIEND_API(bool) -proxy_Construct(JSContext* cx, unsigned argc, JS::Value* vp); -extern JS_FRIEND_API(JSObject*) -proxy_innerObject(JSObject* obj); -extern JS_FRIEND_API(bool) -proxy_Watch(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); -extern JS_FRIEND_API(bool) -proxy_Unwatch(JSContext* cx, JS::HandleObject obj, JS::HandleId id); -extern JS_FRIEND_API(bool) -proxy_GetElements(JSContext* cx, JS::HandleObject proxy, uint32_t begin, uint32_t end, - ElementAdder* adder); -extern JS_FRIEND_API(JSString*) -proxy_FunToString(JSContext* cx, JS::HandleObject proxy, unsigned indent); +extern JS_FRIEND_API JSObject* proxy_WeakmapKeyDelegate(JSObject* obj); /** * A class of objects that return source code on demand. @@ -432,15 +386,16 @@ * find the source. */ class SourceHook { - public: - virtual ~SourceHook() { } + public: + virtual ~SourceHook() {} - /** - * Set |*src| and |*length| to refer to the source code for |filename|. - * On success, the caller owns the buffer to which |*src| points, and - * should use JS_free to free it. - */ - virtual bool load(JSContext* cx, const char* filename, char16_t** src, size_t* length) = 0; + /** + * Set |*src| and |*length| to refer to the source code for |filename|. + * On success, the caller owns the buffer to which |*src| points, and + * should use JS_free to free it. + */ + virtual bool load(JSContext* cx, const char* filename, char16_t** src, + size_t* length) = 0; }; /** @@ -449,101 +404,137 @@ * will delete it when the context itself is deleted, or when a new hook is * set. */ -extern JS_FRIEND_API(void) -SetSourceHook(JSContext* cx, mozilla::UniquePtr hook); +extern JS_FRIEND_API void SetSourceHook(JSContext* cx, + mozilla::UniquePtr hook); /** Remove |cx|'s source hook, and return it. The caller now owns the hook. */ -extern JS_FRIEND_API(mozilla::UniquePtr) -ForgetSourceHook(JSContext* cx); +extern JS_FRIEND_API mozilla::UniquePtr ForgetSourceHook( + JSContext* cx); -extern JS_FRIEND_API(JS::Zone*) -GetCompartmentZone(JSCompartment* comp); +/** + * Use the runtime's internal handling of job queues for Promise jobs. + * + * Most embeddings, notably web browsers, will have their own task scheduling + * systems and need to integrate handling of Promise jobs into that, so they + * will want to manage job queues themselves. For basic embeddings such as the + * JS shell that don't have an event loop of their own, it's easier to have + * SpiderMonkey handle job queues internally. + * + * Note that the embedding still has to trigger processing of job queues at + * right time(s), such as after evaluation of a script has run to completion. + */ +extern JS_FRIEND_API bool UseInternalJobQueues(JSContext* cx, + bool cooperative = false); + +/** + * Enqueue |job| on the internal job queue. + * + * This is useful in tests for creating situations where a call occurs with no + * other JavaScript on the stack. + */ +extern JS_FRIEND_API bool EnqueueJob(JSContext* cx, JS::HandleObject job); + +/** + * Instruct the runtime to stop draining the internal job queue. + * + * Useful if the embedding is in the process of quitting in reaction to a + * builtin being called, or if it wants to resume executing jobs later on. + */ +extern JS_FRIEND_API void StopDrainingJobQueue(JSContext* cx); -typedef bool -(* PreserveWrapperCallback)(JSContext* cx, JSObject* obj); +extern JS_FRIEND_API void RunJobs(JSContext* cx); -typedef enum { - CollectNurseryBeforeDump, - IgnoreNurseryObjects +extern JS_FRIEND_API JS::Zone* GetCompartmentZone(JSCompartment* comp); + +typedef bool (*PreserveWrapperCallback)(JSContext* cx, JSObject* obj); + +typedef enum { + CollectNurseryBeforeDump, + IgnoreNurseryObjects } DumpHeapNurseryBehaviour; - /** - * Dump the complete object graph of heap-allocated things. - * fp is the file for the dump output. - */ -extern JS_FRIEND_API(void) -DumpHeap(JSContext* cx, FILE* fp, DumpHeapNurseryBehaviour nurseryBehaviour); +/** + * Dump the complete object graph of heap-allocated things. + * fp is the file for the dump output. + */ +extern JS_FRIEND_API void 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); -JS_FRIEND_API(bool) obj_defineSetter(JSContext* cx, unsigned argc, JS::Value* vp); +JS_FRIEND_API bool obj_defineGetter(JSContext* cx, unsigned argc, + JS::Value* vp); +JS_FRIEND_API bool obj_defineSetter(JSContext* cx, unsigned argc, + JS::Value* vp); #endif -extern JS_FRIEND_API(bool) -IsSystemCompartment(JSCompartment* comp); +extern JS_FRIEND_API bool IsSystemCompartment(JSCompartment* comp); -extern JS_FRIEND_API(bool) -IsSystemZone(JS::Zone* zone); +extern JS_FRIEND_API bool IsSystemZone(JS::Zone* zone); -extern JS_FRIEND_API(bool) -IsAtomsCompartment(JSCompartment* comp); +extern JS_FRIEND_API bool IsAtomsCompartment(JSCompartment* comp); -extern JS_FRIEND_API(bool) -IsAtomsZone(JS::Zone* zone); +extern JS_FRIEND_API bool IsAtomsZone(JS::Zone* zone); -struct WeakMapTracer -{ - JSContext* context; +struct WeakMapTracer { + JSRuntime* runtime; - explicit WeakMapTracer(JSContext* cx) : context(cx) {} + explicit WeakMapTracer(JSRuntime* rt) : runtime(rt) {} - // Weak map tracer callback, called once for every binding of every - // weak map that was live at the time of the last garbage collection. - // - // m will be nullptr if the weak map is not contained in a JS Object. - // - // The callback should not GC (and will assert in a debug build if it does so.) - virtual void trace(JSObject* m, JS::GCCellPtr key, JS::GCCellPtr value) = 0; + // Weak map tracer callback, called once for every binding of every + // weak map that was live at the time of the last garbage collection. + // + // m will be nullptr if the weak map is not contained in a JS Object. + // + // The callback should not GC (and will assert in a debug build if it does + // so.) + virtual void trace(JSObject* m, JS::GCCellPtr key, JS::GCCellPtr value) = 0; }; -extern JS_FRIEND_API(void) -TraceWeakMaps(WeakMapTracer* trc); +extern JS_FRIEND_API void TraceWeakMaps(WeakMapTracer* trc); + +extern JS_FRIEND_API bool AreGCGrayBitsValid(JSRuntime* rt); -extern JS_FRIEND_API(bool) -AreGCGrayBitsValid(JSContext* cx); +extern JS_FRIEND_API bool ZoneGlobalsAreAllGray(JS::Zone* zone); -extern JS_FRIEND_API(bool) -ZoneGlobalsAreAllGray(JS::Zone* zone); +extern JS_FRIEND_API bool IsObjectZoneSweepingOrCompacting(JSObject* obj); -typedef void -(*GCThingCallback)(void* closure, JS::GCCellPtr thing); +typedef void (*GCThingCallback)(void* closure, JS::GCCellPtr thing); -extern JS_FRIEND_API(void) -VisitGrayWrapperTargets(JS::Zone* zone, GCThingCallback callback, void* closure); +extern JS_FRIEND_API void VisitGrayWrapperTargets(JS::Zone* zone, + GCThingCallback callback, + void* closure); -extern JS_FRIEND_API(JSObject*) -GetWeakmapKeyDelegate(JSObject* key); +extern JS_FRIEND_API JSObject* GetWeakmapKeyDelegate(JSObject* key); /** * Invoke cellCallback on every gray JSObject in the given zone. */ -extern JS_FRIEND_API(void) -IterateGrayObjects(JS::Zone* zone, GCThingCallback cellCallback, void* data); +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); +extern JS_FRIEND_API void IterateGrayObjectsUnderCC( + JS::Zone* zone, GCThingCallback cellCallback, void* data); + +#if defined(JS_GC_ZEAL) || defined(DEBUG) +// Trace the heap and check there are no black to gray edges. These are +// not allowed since the cycle collector could throw away the gray thing and +// leave a dangling pointer. +// +// This doesn't trace weak maps as these are handled separately. +extern JS_FRIEND_API bool CheckGrayMarkingState(JSRuntime* rt); +#endif #ifdef JS_HAS_CTYPES -extern JS_FRIEND_API(size_t) +extern JS_FRIEND_API size_t SizeOfDataIfCDataObject(mozilla::MallocSizeOf mallocSizeOf, JSObject* obj); #endif -extern JS_FRIEND_API(JSCompartment*) -GetAnyCompartmentInZone(JS::Zone* zone); +extern JS_FRIEND_API JSCompartment* GetAnyCompartmentInZone(JS::Zone* zone); /* * Shadow declarations of JS internal structures, for access by inline access @@ -554,23 +545,24 @@ namespace shadow { struct ObjectGroup { - const Class* clasp; - JSObject* proto; - JSCompartment* compartment; + const Class* clasp; + JSObject* proto; + JSCompartment* compartment; }; struct BaseShape { - const js::Class* clasp_; - JSObject* parent; + const js::Class* clasp_; + JSObject* parent; }; class Shape { -public: - shadow::BaseShape* base; - jsid _1; - uint32_t slotInfo; + public: + shadow::BaseShape* base; + void* _1; + jsid _2; + uint32_t slotInfo; - static const uint32_t FIXED_SLOTS_SHIFT = 27; + static const uint32_t FIXED_SLOTS_SHIFT = 27; }; /** @@ -579,70 +571,75 @@ * depending on the object's specific layout. */ struct Object { - shadow::ObjectGroup* group; - shadow::Shape* shape; - JS::Value* slots; - void* _1; - - size_t numFixedSlots() const { return shape->slotInfo >> Shape::FIXED_SLOTS_SHIFT; } - JS::Value* fixedSlots() const { - return (JS::Value*)(uintptr_t(this) + sizeof(shadow::Object)); - } + shadow::ObjectGroup* group; + shadow::Shape* shape; + JS::Value* slots; + void* _1; - JS::Value& slotRef(size_t slot) const { - size_t nfixed = numFixedSlots(); - if (slot < nfixed) - return fixedSlots()[slot]; - return slots[slot - nfixed]; - } + static const size_t MAX_FIXED_SLOTS = 16; + + size_t numFixedSlots() const { + return shape->slotInfo >> Shape::FIXED_SLOTS_SHIFT; + } + JS::Value* fixedSlots() const { + return (JS::Value*)(uintptr_t(this) + sizeof(shadow::Object)); + } + + JS::Value& slotRef(size_t slot) const { + size_t nfixed = numFixedSlots(); + if (slot < nfixed) return fixedSlots()[slot]; + return slots[slot - nfixed]; + } }; struct Function { - Object base; - uint16_t nargs; - uint16_t flags; - /* Used only for natives */ - JSNative native; - const JSJitInfo* jitinfo; - void* _1; -}; - -struct String -{ - static const uint32_t INLINE_CHARS_BIT = JS_BIT(2); - static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6); - static const uint32_t ROPE_FLAGS = 0; - static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1; - uint32_t flags; - uint32_t length; - union { - const JS::Latin1Char* nonInlineCharsLatin1; - const char16_t* nonInlineCharsTwoByte; - JS::Latin1Char inlineStorageLatin1[1]; - char16_t inlineStorageTwoByte[1]; - }; + Object base; + uint16_t nargs; + uint16_t flags; + /* Used only for natives */ + JSNative native; + const JSJitInfo* jitinfo; + void* _1; +}; + +struct String { + static const uint32_t NON_ATOM_BIT = JS_BIT(0); + static const uint32_t LINEAR_BIT = JS_BIT(1); + static const uint32_t INLINE_CHARS_BIT = JS_BIT(3); + static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6); + static const uint32_t EXTERNAL_FLAGS = LINEAR_BIT | NON_ATOM_BIT | JS_BIT(5); + static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1; + uint32_t flags; + uint32_t length; + union { + const JS::Latin1Char* nonInlineCharsLatin1; + const char16_t* nonInlineCharsTwoByte; + JS::Latin1Char inlineStorageLatin1[1]; + char16_t inlineStorageTwoByte[1]; + }; + const JSStringFinalizer* externalFinalizer; + + static bool nurseryCellIsString(const js::gc::Cell* cell) { + MOZ_ASSERT(IsInsideNursery(cell)); + return reinterpret_cast(cell)->flags & NON_ATOM_BIT; + } }; } /* namespace shadow */ // This is equal to |&JSObject::class_|. Use it in places where you don't want -// to #include jsobj.h. -extern JS_FRIEND_DATA(const js::Class* const) ObjectClassPtr; +// to #include vm/JSObject.h. +extern JS_FRIEND_DATA const js::Class* const ObjectClassPtr; -inline const js::Class* -GetObjectClass(const JSObject* obj) -{ - return reinterpret_cast(obj)->group->clasp; +inline const js::Class* GetObjectClass(const JSObject* obj) { + return reinterpret_cast(obj)->group->clasp; } -inline const JSClass* -GetObjectJSClass(JSObject* obj) -{ - return js::Jsvalify(GetObjectClass(obj)); +inline const JSClass* GetObjectJSClass(JSObject* obj) { + return js::Jsvalify(GetObjectClass(obj)); } -JS_FRIEND_API(const Class*) -ProtoKeyToClass(JSProtoKey key); +JS_FRIEND_API const Class* ProtoKeyToClass(JSProtoKey key); // 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,294 +648,257 @@ // JSProtoKey before calling this function. In general |key| will match the // cached proto key, except in cases where multiple JSProtoKeys share a // JSClass. -inline JSProtoKey -InheritanceProtoKeyForStandardClass(JSProtoKey key) -{ - // [Object] has nothing to inherit from. - if (key == JSProto_Object) - return JSProto_Null; +inline JSProtoKey InheritanceProtoKeyForStandardClass(JSProtoKey key) { + // [Object] has nothing to inherit from. + if (key == JSProto_Object) return JSProto_Null; - // If we're ClassSpec defined return the proto key from that - if (ProtoKeyToClass(key)->specDefined()) - return ProtoKeyToClass(key)->specInheritanceProtoKey(); + // 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; + // Otherwise, we inherit [Object]. + return JSProto_Object; } -JS_FRIEND_API(bool) -IsFunctionObject(JSObject* obj); +JS_FRIEND_API bool IsFunctionObject(JSObject* obj); -static MOZ_ALWAYS_INLINE JSCompartment* -GetObjectCompartment(JSObject* obj) -{ - return reinterpret_cast(obj)->group->compartment; +static MOZ_ALWAYS_INLINE JSCompartment* GetObjectCompartment(JSObject* obj) { + return reinterpret_cast(obj)->group->compartment; } -JS_FRIEND_API(JSObject*) -GetGlobalForObjectCrossCompartment(JSObject* obj); +JS_FRIEND_API JSObject* GetGlobalForObjectCrossCompartment(JSObject* obj); -JS_FRIEND_API(JSObject*) -GetPrototypeNoProxy(JSObject* obj); +JS_FRIEND_API JSObject* GetPrototypeNoProxy(JSObject* obj); -JS_FRIEND_API(void) -AssertSameCompartment(JSContext* cx, JSObject* obj); +JS_FRIEND_API void AssertSameCompartment(JSContext* cx, JSObject* obj); + +JS_FRIEND_API void AssertSameCompartment(JSContext* cx, JS::HandleValue v); #ifdef JS_DEBUG -JS_FRIEND_API(void) -AssertSameCompartment(JSObject* objA, JSObject* objB); +JS_FRIEND_API void AssertSameCompartment(JSObject* objA, JSObject* objB); #else inline void AssertSameCompartment(JSObject* objA, JSObject* objB) {} #endif -JS_FRIEND_API(void) -NotifyAnimationActivity(JSObject* obj); +JS_FRIEND_API void NotifyAnimationActivity(JSObject* obj); -/** - * Return the outermost enclosing function (script) of the scripted caller. - * This function returns nullptr in several cases: - * - no script is running on the context - * - the caller is in global or eval code - * In particular, this function will "stop" its outermost search at eval() and - * thus it will really return the outermost enclosing function *since the - * innermost eval*. - */ -JS_FRIEND_API(JSFunction*) -GetOutermostEnclosingFunctionOfScriptedCaller(JSContext* cx); +JS_FRIEND_API JSFunction* DefineFunctionWithReserved( + JSContext* cx, JSObject* obj, const char* name, JSNative call, + unsigned nargs, unsigned attrs); -JS_FRIEND_API(JSFunction*) -DefineFunctionWithReserved(JSContext* cx, JSObject* obj, const char* name, JSNative call, - unsigned nargs, unsigned attrs); +JS_FRIEND_API JSFunction* NewFunctionWithReserved(JSContext* cx, JSNative call, + unsigned nargs, + unsigned flags, + const char* name); -JS_FRIEND_API(JSFunction*) -NewFunctionWithReserved(JSContext* cx, JSNative call, unsigned nargs, unsigned flags, - const char* name); +JS_FRIEND_API JSFunction* NewFunctionByIdWithReserved(JSContext* cx, + JSNative native, + unsigned nargs, + unsigned flags, jsid id); -JS_FRIEND_API(JSFunction*) -NewFunctionByIdWithReserved(JSContext* cx, JSNative native, unsigned nargs, unsigned flags, - jsid id); +JS_FRIEND_API const JS::Value& GetFunctionNativeReserved(JSObject* fun, + size_t which); -JS_FRIEND_API(const JS::Value&) -GetFunctionNativeReserved(JSObject* fun, size_t which); +JS_FRIEND_API void SetFunctionNativeReserved(JSObject* fun, size_t which, + const JS::Value& val); -JS_FRIEND_API(void) -SetFunctionNativeReserved(JSObject* fun, size_t which, const JS::Value& val); +JS_FRIEND_API bool FunctionHasNativeReserved(JSObject* fun); -JS_FRIEND_API(bool) -FunctionHasNativeReserved(JSObject* fun); +JS_FRIEND_API bool GetObjectProto(JSContext* cx, JS::HandleObject obj, + JS::MutableHandleObject proto); -JS_FRIEND_API(bool) -GetObjectProto(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject proto); +extern JS_FRIEND_API JSObject* GetStaticPrototype(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -GetStaticPrototype(JSObject* obj); +JS_FRIEND_API bool GetOriginalEval(JSContext* cx, JS::HandleObject scope, + JS::MutableHandleObject eval); -JS_FRIEND_API(bool) -GetOriginalEval(JSContext* cx, JS::HandleObject scope, - JS::MutableHandleObject eval); - -inline void* -GetObjectPrivate(JSObject* obj) -{ - MOZ_ASSERT(GetObjectClass(obj)->flags & JSCLASS_HAS_PRIVATE); - const shadow::Object* nobj = reinterpret_cast(obj); - void** addr = reinterpret_cast(&nobj->fixedSlots()[nobj->numFixedSlots()]); - return *addr; +inline void* GetObjectPrivate(JSObject* obj) { + MOZ_ASSERT(GetObjectClass(obj)->flags & JSCLASS_HAS_PRIVATE); + const shadow::Object* nobj = reinterpret_cast(obj); + void** addr = + reinterpret_cast(&nobj->fixedSlots()[nobj->numFixedSlots()]); + return *addr; } -inline const JS::Value& -GetReservedSlot(JSObject* obj, size_t slot) -{ - MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); - return reinterpret_cast(obj)->slotRef(slot); +/** + * Get the value stored in an object's reserved slot. This can be used with + * both native objects and proxies, but if |obj| is known to be a proxy + * GetProxyReservedSlot is a bit more efficient. + */ +inline const JS::Value& GetReservedSlot(JSObject* obj, size_t slot) { + MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); + return reinterpret_cast(obj)->slotRef(slot); } -JS_FRIEND_API(void) -SetReservedOrProxyPrivateSlotWithBarrier(JSObject* obj, size_t slot, const JS::Value& value); +JS_FRIEND_API void SetReservedSlotWithBarrier(JSObject* obj, size_t slot, + const JS::Value& value); -inline void -SetReservedSlot(JSObject* obj, size_t slot, const JS::Value& value) -{ - MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); - shadow::Object* sobj = reinterpret_cast(obj); - if (sobj->slotRef(slot).isMarkable() || value.isMarkable()) - SetReservedOrProxyPrivateSlotWithBarrier(obj, slot, value); - else - sobj->slotRef(slot) = value; +/** + * Store a value in an object's reserved slot. This can be used with + * both native objects and proxies, but if |obj| is known to be a proxy + * SetProxyReservedSlot is a bit more efficient. + */ +inline void SetReservedSlot(JSObject* obj, size_t slot, + const JS::Value& value) { + MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); + shadow::Object* sobj = reinterpret_cast(obj); + if (sobj->slotRef(slot).isGCThing() || value.isGCThing()) + SetReservedSlotWithBarrier(obj, slot, value); + else + sobj->slotRef(slot) = value; } -JS_FRIEND_API(uint32_t) -GetObjectSlotSpan(JSObject* obj); +JS_FRIEND_API uint32_t GetObjectSlotSpan(JSObject* obj); -inline const JS::Value& -GetObjectSlot(JSObject* obj, size_t slot) -{ - MOZ_ASSERT(slot < GetObjectSlotSpan(obj)); - return reinterpret_cast(obj)->slotRef(slot); +inline const JS::Value& GetObjectSlot(JSObject* obj, size_t slot) { + MOZ_ASSERT(slot < GetObjectSlotSpan(obj)); + return reinterpret_cast(obj)->slotRef(slot); } -MOZ_ALWAYS_INLINE size_t -GetAtomLength(JSAtom* atom) -{ - return reinterpret_cast(atom)->length; +MOZ_ALWAYS_INLINE size_t GetAtomLength(JSAtom* atom) { + return reinterpret_cast(atom)->length; } static const uint32_t MaxStringLength = (1 << 28) - 1; -MOZ_ALWAYS_INLINE size_t -GetStringLength(JSString* s) -{ - return reinterpret_cast(s)->length; +MOZ_ALWAYS_INLINE size_t GetStringLength(JSString* s) { + return reinterpret_cast(s)->length; } -MOZ_ALWAYS_INLINE size_t -GetFlatStringLength(JSFlatString* s) -{ - return reinterpret_cast(s)->length; +MOZ_ALWAYS_INLINE size_t GetFlatStringLength(JSFlatString* s) { + return reinterpret_cast(s)->length; } -MOZ_ALWAYS_INLINE size_t -GetLinearStringLength(JSLinearString* s) -{ - return reinterpret_cast(s)->length; +MOZ_ALWAYS_INLINE size_t GetLinearStringLength(JSLinearString* s) { + return reinterpret_cast(s)->length; } -MOZ_ALWAYS_INLINE bool -LinearStringHasLatin1Chars(JSLinearString* s) -{ - return reinterpret_cast(s)->flags & shadow::String::LATIN1_CHARS_BIT; +MOZ_ALWAYS_INLINE bool LinearStringHasLatin1Chars(JSLinearString* s) { + return reinterpret_cast(s)->flags & + shadow::String::LATIN1_CHARS_BIT; } -MOZ_ALWAYS_INLINE bool -AtomHasLatin1Chars(JSAtom* atom) -{ - return reinterpret_cast(atom)->flags & shadow::String::LATIN1_CHARS_BIT; +MOZ_ALWAYS_INLINE bool AtomHasLatin1Chars(JSAtom* atom) { + return reinterpret_cast(atom)->flags & + shadow::String::LATIN1_CHARS_BIT; } -MOZ_ALWAYS_INLINE bool -StringHasLatin1Chars(JSString* s) -{ - return reinterpret_cast(s)->flags & shadow::String::LATIN1_CHARS_BIT; +MOZ_ALWAYS_INLINE bool StringHasLatin1Chars(JSString* s) { + return reinterpret_cast(s)->flags & + shadow::String::LATIN1_CHARS_BIT; } -MOZ_ALWAYS_INLINE const JS::Latin1Char* -GetLatin1LinearStringChars(const JS::AutoCheckCannotGC& nogc, JSLinearString* linear) -{ - MOZ_ASSERT(LinearStringHasLatin1Chars(linear)); +MOZ_ALWAYS_INLINE const JS::Latin1Char* GetLatin1LinearStringChars( + const JS::AutoRequireNoGC& nogc, JSLinearString* linear) { + MOZ_ASSERT(LinearStringHasLatin1Chars(linear)); - using shadow::String; - String* s = reinterpret_cast(linear); - if (s->flags & String::INLINE_CHARS_BIT) - return s->inlineStorageLatin1; - return s->nonInlineCharsLatin1; + using shadow::String; + String* s = reinterpret_cast(linear); + if (s->flags & String::INLINE_CHARS_BIT) return s->inlineStorageLatin1; + return s->nonInlineCharsLatin1; } -MOZ_ALWAYS_INLINE const char16_t* -GetTwoByteLinearStringChars(const JS::AutoCheckCannotGC& nogc, JSLinearString* linear) -{ - MOZ_ASSERT(!LinearStringHasLatin1Chars(linear)); +MOZ_ALWAYS_INLINE const char16_t* GetTwoByteLinearStringChars( + const JS::AutoRequireNoGC& nogc, JSLinearString* linear) { + MOZ_ASSERT(!LinearStringHasLatin1Chars(linear)); - using shadow::String; - String* s = reinterpret_cast(linear); - if (s->flags & String::INLINE_CHARS_BIT) - return s->inlineStorageTwoByte; - return s->nonInlineCharsTwoByte; + using shadow::String; + String* s = reinterpret_cast(linear); + if (s->flags & String::INLINE_CHARS_BIT) return s->inlineStorageTwoByte; + return s->nonInlineCharsTwoByte; } -MOZ_ALWAYS_INLINE JSLinearString* -AtomToLinearString(JSAtom* atom) -{ - return reinterpret_cast(atom); +MOZ_ALWAYS_INLINE JSLinearString* AtomToLinearString(JSAtom* atom) { + return reinterpret_cast(atom); } -MOZ_ALWAYS_INLINE JSFlatString* -AtomToFlatString(JSAtom* atom) -{ - return reinterpret_cast(atom); +MOZ_ALWAYS_INLINE JSFlatString* AtomToFlatString(JSAtom* atom) { + return reinterpret_cast(atom); } -MOZ_ALWAYS_INLINE JSLinearString* -FlatStringToLinearString(JSFlatString* s) -{ - return reinterpret_cast(s); +MOZ_ALWAYS_INLINE JSLinearString* FlatStringToLinearString(JSFlatString* s) { + return reinterpret_cast(s); } -MOZ_ALWAYS_INLINE const JS::Latin1Char* -GetLatin1AtomChars(const JS::AutoCheckCannotGC& nogc, JSAtom* atom) -{ - return GetLatin1LinearStringChars(nogc, AtomToLinearString(atom)); +MOZ_ALWAYS_INLINE const JS::Latin1Char* GetLatin1AtomChars( + const JS::AutoRequireNoGC& nogc, JSAtom* atom) { + return GetLatin1LinearStringChars(nogc, AtomToLinearString(atom)); } -MOZ_ALWAYS_INLINE const char16_t* -GetTwoByteAtomChars(const JS::AutoCheckCannotGC& nogc, JSAtom* atom) -{ - return GetTwoByteLinearStringChars(nogc, AtomToLinearString(atom)); +MOZ_ALWAYS_INLINE const char16_t* GetTwoByteAtomChars( + const JS::AutoRequireNoGC& nogc, JSAtom* atom) { + return GetTwoByteLinearStringChars(nogc, AtomToLinearString(atom)); } -JS_FRIEND_API(JSLinearString*) -StringToLinearStringSlow(JSContext* cx, JSString* str); - -MOZ_ALWAYS_INLINE JSLinearString* -StringToLinearString(JSContext* cx, JSString* str) -{ - using shadow::String; - String* s = reinterpret_cast(str); - if (MOZ_UNLIKELY((s->flags & String::TYPE_FLAGS_MASK) == String::ROPE_FLAGS)) - return StringToLinearStringSlow(cx, str); - return reinterpret_cast(str); -} +MOZ_ALWAYS_INLINE bool IsExternalString(JSString* str, + const JSStringFinalizer** fin, + const char16_t** chars) { + using shadow::String; + String* s = reinterpret_cast(str); -template -MOZ_ALWAYS_INLINE void -CopyLinearStringChars(CharType* dest, JSLinearString* s, size_t len, size_t start = 0); + if ((s->flags & String::TYPE_FLAGS_MASK) != String::EXTERNAL_FLAGS) + return false; -MOZ_ALWAYS_INLINE void -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[start + i]; - } else { - const char16_t* src = GetTwoByteLinearStringChars(nogc, s); - mozilla::PodCopy(dest, src + start, len); - } + MOZ_ASSERT(JS_IsExternalString(str)); + *fin = s->externalFinalizer; + *chars = s->nonInlineCharsTwoByte; + return true; +} + +JS_FRIEND_API JSLinearString* StringToLinearStringSlow(JSContext* cx, + JSString* str); + +MOZ_ALWAYS_INLINE JSLinearString* StringToLinearString(JSContext* cx, + JSString* str) { + using shadow::String; + String* s = reinterpret_cast(str); + if (MOZ_UNLIKELY(!(s->flags & String::LINEAR_BIT))) + return StringToLinearStringSlow(cx, str); + 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, 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[start + i]; + } else { + const char16_t* src = GetTwoByteLinearStringChars(nogc, s); + 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]); - } +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, CharType* dest, JSString* s, size_t len, size_t start = 0) -{ - JSLinearString* linear = StringToLinearString(cx, s); - if (!linear) - return false; +template +inline bool 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, start); - return true; + CopyLinearStringChars(dest, linear, len, start); + return true; } -inline void -CopyFlatStringChars(char16_t* dest, JSFlatString* s, size_t len) -{ - CopyLinearStringChars(dest, FlatStringToLinearString(s), len); +inline void CopyFlatStringChars(char16_t* dest, JSFlatString* s, size_t len) { + CopyLinearStringChars(dest, FlatStringToLinearString(s), len); } /** @@ -962,133 +922,146 @@ * `JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS` as flags to get * results that match the output of Reflect.ownKeys. */ -JS_FRIEND_API(bool) -GetPropertyKeys(JSContext* cx, JS::HandleObject obj, unsigned flags, JS::AutoIdVector* props); +JS_FRIEND_API bool GetPropertyKeys(JSContext* cx, JS::HandleObject obj, + unsigned flags, JS::AutoIdVector* props); -JS_FRIEND_API(bool) -AppendUnique(JSContext* cx, JS::AutoIdVector& base, JS::AutoIdVector& others); +JS_FRIEND_API bool AppendUnique(JSContext* cx, JS::AutoIdVector& base, + JS::AutoIdVector& others); -JS_FRIEND_API(bool) -StringIsArrayIndex(JSLinearString* str, uint32_t* indexp); +JS_FRIEND_API bool StringIsArrayIndex(JSLinearString* str, uint32_t* indexp); -JS_FRIEND_API(void) -SetPreserveWrapperCallback(JSContext* cx, PreserveWrapperCallback callback); +JS_FRIEND_API void SetPreserveWrapperCallback(JSContext* cx, + PreserveWrapperCallback callback); -JS_FRIEND_API(bool) -IsObjectInContextCompartment(JSObject* obj, const JSContext* cx); +JS_FRIEND_API bool IsObjectInContextCompartment(JSObject* obj, + const JSContext* cx); /* * 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. */ -#define JSITER_ENUMERATE 0x1 /* for-in compatible hidden default iterator */ -#define JSITER_FOREACH 0x2 /* get obj[key] for each property */ -#define JSITER_KEYVALUE 0x4 /* obsolete destructuring for-in wants [key, value] */ -#define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */ -#define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */ -#define JSITER_SYMBOLS 0x20 /* also include symbol property keys */ +/* 0x1 is no longer used */ +/* 0x2 is no longer used */ +/* 0x4 is no longer used */ +#define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */ +#define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */ +#define JSITER_SYMBOLS 0x20 /* also include symbol property keys */ #define JSITER_SYMBOLSONLY 0x40 /* exclude string property keys */ +#define JSITER_FORAWAITOF 0x80 /* for-await-of */ -JS_FRIEND_API(bool) -RunningWithTrustedPrincipals(JSContext* cx); +JS_FRIEND_API bool RunningWithTrustedPrincipals(JSContext* cx); -inline uintptr_t -GetNativeStackLimit(JSContext* cx, StackKind kind, int extraAllowance = 0) -{ - uintptr_t limit = ContextFriendFields::get(cx)->nativeStackLimit[kind]; +MOZ_ALWAYS_INLINE uintptr_t GetNativeStackLimit(JSContext* cx, + JS::StackKind kind, + int extraAllowance = 0) { + uintptr_t limit = JS::RootingContext::get(cx)->nativeStackLimit[kind]; #if JS_STACK_GROWTH_DIRECTION > 0 - limit += extraAllowance; + limit += extraAllowance; #else - limit -= extraAllowance; + limit -= extraAllowance; #endif - return limit; + return limit; +} + +MOZ_ALWAYS_INLINE uintptr_t GetNativeStackLimit(JSContext* cx, + int extraAllowance = 0) { + JS::StackKind kind = RunningWithTrustedPrincipals(cx) + ? JS::StackForTrustedScript + : JS::StackForUntrustedScript; + return GetNativeStackLimit(cx, kind, extraAllowance); +} + +/* + * These functions return |false| if we are close to using up the C++ stack. + * They also report an overrecursion error, except for the DontReport variants. + * The CheckSystemRecursionLimit variant gives us a little extra space so we + * can ensure that crucial code is able to run. CheckRecursionLimitConservative + * allows less space than any other check, including a safety buffer (as in, it + * uses the untrusted limit and subtracts a little more from it). + */ + +MOZ_ALWAYS_INLINE bool CheckRecursionLimit(JSContext* cx, uintptr_t limit) { + int stackDummy; + + JS_STACK_OOM_POSSIBLY_FAIL_REPORT(); + + if (!JS_CHECK_STACK_SIZE(limit, &stackDummy)) { + ReportOverRecursed(cx); + return false; + } + return true; +} + +MOZ_ALWAYS_INLINE bool CheckRecursionLimitDontReport(uintptr_t limit) { + int stackDummy; + + JS_STACK_OOM_POSSIBLY_FAIL(); + + return JS_CHECK_STACK_SIZE(limit, &stackDummy); +} + +MOZ_ALWAYS_INLINE bool CheckRecursionLimit(JSContext* cx) { + JS_STACK_OOM_POSSIBLY_FAIL_REPORT(); + + // GetNativeStackLimit(cx) is pretty slow because it has to do an uninlined + // call to RunningWithTrustedPrincipals to determine which stack limit to + // use. To work around this, check the untrusted limit first to avoid the + // overhead in most cases. + uintptr_t untrustedLimit = + GetNativeStackLimit(cx, JS::StackForUntrustedScript); + if (MOZ_LIKELY(CheckRecursionLimitDontReport(untrustedLimit))) return true; + return CheckRecursionLimit(cx, GetNativeStackLimit(cx)); +} + +MOZ_ALWAYS_INLINE bool CheckRecursionLimitDontReport(JSContext* cx) { + return CheckRecursionLimitDontReport(GetNativeStackLimit(cx)); } -inline uintptr_t -GetNativeStackLimit(JSContext* cx, int extraAllowance = 0) -{ - StackKind kind = RunningWithTrustedPrincipals(cx) ? StackForTrustedScript - : StackForUntrustedScript; - return GetNativeStackLimit(cx, kind, extraAllowance); -} - -/* - * These macros report a stack overflow and run |onerror| if we are close to - * using up the C stack. The JS_CHECK_CHROME_RECURSION variant gives us a - * little extra space so that we can ensure that crucial code is able to run. - * JS_CHECK_RECURSION_CONSERVATIVE allows less space than any other check, - * including a safety buffer (as in, it uses the untrusted limit and subtracts - * a little more from it). - */ - -#define JS_CHECK_RECURSION_LIMIT(cx, limit, onerror) \ - JS_BEGIN_MACRO \ - int stackDummy_; \ - if (!JS_CHECK_STACK_SIZE(limit, &stackDummy_)) { \ - js::ReportOverRecursed(cx); \ - onerror; \ - } \ - JS_END_MACRO - -#define JS_CHECK_RECURSION(cx, onerror) \ - JS_CHECK_RECURSION_LIMIT(cx, js::GetNativeStackLimit(cx), onerror) - -#define JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, limit, onerror) \ - JS_BEGIN_MACRO \ - int stackDummy_; \ - if (!JS_CHECK_STACK_SIZE(limit, &stackDummy_)) { \ - onerror; \ - } \ - JS_END_MACRO - -#define JS_CHECK_RECURSION_DONT_REPORT(cx, onerror) \ - JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, js::GetNativeStackLimit(cx), onerror) - -#define JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, sp, onerror) \ - JS_BEGIN_MACRO \ - if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp)) { \ - onerror; \ - } \ - JS_END_MACRO - -#define JS_CHECK_RECURSION_WITH_SP(cx, sp, onerror) \ - JS_BEGIN_MACRO \ - if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp)) { \ - js::ReportOverRecursed(cx); \ - onerror; \ - } \ - JS_END_MACRO - -#define JS_CHECK_SYSTEM_RECURSION(cx, onerror) \ - JS_CHECK_RECURSION_LIMIT(cx, js::GetNativeStackLimit(cx, js::StackForSystemCode), onerror) - -#define JS_CHECK_RECURSION_CONSERVATIVE(cx, onerror) \ - JS_CHECK_RECURSION_LIMIT(cx, \ - js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \ - onerror) - -#define JS_CHECK_RECURSION_CONSERVATIVE_DONT_REPORT(cx, onerror) \ - JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, \ - js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \ - onerror) - -JS_FRIEND_API(void) -StartPCCountProfiling(JSContext* cx); - -JS_FRIEND_API(void) -StopPCCountProfiling(JSContext* cx); - -JS_FRIEND_API(void) -PurgePCCounts(JSContext* cx); +MOZ_ALWAYS_INLINE bool CheckRecursionLimitWithStackPointerDontReport( + JSContext* cx, void* sp) { + JS_STACK_OOM_POSSIBLY_FAIL(); -JS_FRIEND_API(size_t) -GetPCCountScriptCount(JSContext* cx); + return JS_CHECK_STACK_SIZE(GetNativeStackLimit(cx), sp); +} + +MOZ_ALWAYS_INLINE bool CheckRecursionLimitWithStackPointer(JSContext* cx, + void* sp) { + JS_STACK_OOM_POSSIBLY_FAIL_REPORT(); + + if (!JS_CHECK_STACK_SIZE(GetNativeStackLimit(cx), sp)) { + ReportOverRecursed(cx); + return false; + } + return true; +} -JS_FRIEND_API(JSString*) -GetPCCountScriptSummary(JSContext* cx, size_t script); +MOZ_ALWAYS_INLINE bool CheckSystemRecursionLimit(JSContext* cx) { + return CheckRecursionLimit(cx, + GetNativeStackLimit(cx, JS::StackForSystemCode)); +} + +MOZ_ALWAYS_INLINE bool CheckRecursionLimitConservative(JSContext* cx) { + return CheckRecursionLimit( + cx, GetNativeStackLimit(cx, JS::StackForUntrustedScript, + -1024 * int(sizeof(size_t)))); +} + +MOZ_ALWAYS_INLINE bool CheckRecursionLimitConservativeDontReport( + JSContext* cx) { + return CheckRecursionLimitDontReport(GetNativeStackLimit( + cx, JS::StackForUntrustedScript, -1024 * int(sizeof(size_t)))); +} -JS_FRIEND_API(JSString*) -GetPCCountScriptContents(JSContext* cx, size_t script); +JS_FRIEND_API void StartPCCountProfiling(JSContext* cx); + +JS_FRIEND_API void StopPCCountProfiling(JSContext* cx); + +JS_FRIEND_API void PurgePCCounts(JSContext* cx); + +JS_FRIEND_API size_t GetPCCountScriptCount(JSContext* cx); + +JS_FRIEND_API JSString* GetPCCountScriptSummary(JSContext* cx, size_t script); + +JS_FRIEND_API JSString* GetPCCountScriptContents(JSContext* cx, size_t script); /** * Generate lcov trace file content for the current compartment, and allocate a @@ -1098,46 +1071,40 @@ * In case of out-of-memory, this function returns nullptr and does not set any * value to the length out-param. */ -JS_FRIEND_API(char*) -GetCodeCoverageSummary(JSContext* cx, size_t* length); +JS_FRIEND_API char* GetCodeCoverageSummary(JSContext* cx, size_t* length); -typedef void -(* ActivityCallback)(void* arg, bool active); +typedef void (*ActivityCallback)(void* arg, bool active); /** * Sets a callback that is run whenever the runtime goes idle - the * last active request ceases - and begins activity - when it was * idle and a request begins. */ -JS_FRIEND_API(void) -SetActivityCallback(JSContext* cx, ActivityCallback cb, void* arg); +JS_FRIEND_API void SetActivityCallback(JSContext* cx, ActivityCallback cb, + void* arg); -typedef bool -(* DOMInstanceClassHasProtoAtDepth)(const Class* instanceClass, - uint32_t protoID, uint32_t depth); +typedef bool (*DOMInstanceClassHasProtoAtDepth)(const Class* instanceClass, + uint32_t protoID, + uint32_t depth); struct JSDOMCallbacks { - DOMInstanceClassHasProtoAtDepth instanceClassMatchesProto; + DOMInstanceClassHasProtoAtDepth instanceClassMatchesProto; }; typedef struct JSDOMCallbacks DOMCallbacks; -extern JS_FRIEND_API(void) -SetDOMCallbacks(JSContext* cx, const DOMCallbacks* callbacks); +extern JS_FRIEND_API void SetDOMCallbacks(JSContext* cx, + const DOMCallbacks* callbacks); -extern JS_FRIEND_API(const DOMCallbacks*) -GetDOMCallbacks(JSContext* cx); +extern JS_FRIEND_API const DOMCallbacks* GetDOMCallbacks(JSContext* cx); -extern JS_FRIEND_API(JSObject*) -GetTestingFunctions(JSContext* cx); +extern JS_FRIEND_API JSObject* GetTestingFunctions(JSContext* cx); /** * Helper to convert FreeOp to JSFreeOp when the definition of FreeOp is not * available and the compiler does not know that FreeOp inherits from * JSFreeOp. */ -inline JSFreeOp* -CastToJSFreeOp(FreeOp* fop) -{ - return reinterpret_cast(fop); +inline JSFreeOp* CastToJSFreeOp(FreeOp* fop) { + return reinterpret_cast(fop); } /* Implemented in jsexn.cpp. */ @@ -1146,67 +1113,69 @@ * Get an error type name from a JSExnType constant. * Returns nullptr for invalid arguments and JSEXN_INTERNALERR */ -extern JS_FRIEND_API(JSFlatString*) -GetErrorTypeName(JSContext* cx, int16_t exnType); +extern JS_FRIEND_API JSFlatString* GetErrorTypeName(JSContext* cx, + int16_t exnType); #ifdef JS_DEBUG -extern JS_FRIEND_API(unsigned) -GetEnterCompartmentDepth(JSContext* cx); +extern JS_FRIEND_API unsigned GetEnterCompartmentDepth(JSContext* cx); #endif -class RegExpGuard; -extern JS_FRIEND_API(bool) -RegExpToSharedNonInline(JSContext* cx, JS::HandleObject regexp, RegExpGuard* shared); +extern JS_FRIEND_API RegExpShared* RegExpToSharedNonInline( + JSContext* cx, JS::HandleObject regexp); -/* Implemented in jswrapper.cpp. */ +/* Implemented in CrossCompartmentWrapper.cpp. */ typedef enum NukeReferencesToWindow { - NukeWindowReferences, - DontNukeWindowReferences + NukeWindowReferences, + DontNukeWindowReferences } NukeReferencesToWindow; +typedef enum NukeReferencesFromTarget { + NukeAllReferences, + NukeIncomingReferences, +} NukeReferencesFromTarget; + /* * These filters are designed to be ephemeral stack classes, and thus don't * do any rooting or holding of their members. */ struct CompartmentFilter { - virtual bool match(JSCompartment* c) const = 0; + virtual bool match(JSCompartment* c) const = 0; }; struct AllCompartments : public CompartmentFilter { - virtual bool match(JSCompartment* c) const override { return true; } + virtual bool match(JSCompartment* c) const override { return true; } }; struct ContentCompartmentsOnly : public CompartmentFilter { - virtual bool match(JSCompartment* c) const override { - return !IsSystemCompartment(c); - } + virtual bool match(JSCompartment* c) const override { + return !IsSystemCompartment(c); + } }; struct ChromeCompartmentsOnly : public CompartmentFilter { - virtual bool match(JSCompartment* c) const override { - return IsSystemCompartment(c); - } + virtual bool match(JSCompartment* c) const override { + return IsSystemCompartment(c); + } }; struct SingleCompartment : public CompartmentFilter { - JSCompartment* ours; - explicit SingleCompartment(JSCompartment* c) : ours(c) {} - virtual bool match(JSCompartment* c) const override { return c == ours; } + JSCompartment* ours; + explicit SingleCompartment(JSCompartment* c) : ours(c) {} + virtual bool match(JSCompartment* c) const override { return c == ours; } }; struct CompartmentsWithPrincipals : public CompartmentFilter { - JSPrincipals* principals; - explicit CompartmentsWithPrincipals(JSPrincipals* p) : principals(p) {} - virtual bool match(JSCompartment* c) const override { - return JS_GetCompartmentPrincipals(c) == principals; - } + JSPrincipals* principals; + explicit CompartmentsWithPrincipals(JSPrincipals* p) : principals(p) {} + virtual bool match(JSCompartment* c) const override { + return JS_GetCompartmentPrincipals(c) == principals; + } }; -extern JS_FRIEND_API(bool) -NukeCrossCompartmentWrappers(JSContext* cx, - const CompartmentFilter& sourceFilter, - const CompartmentFilter& targetFilter, - NukeReferencesToWindow nukeReferencesToWindow); +extern JS_FRIEND_API bool NukeCrossCompartmentWrappers( + JSContext* cx, const CompartmentFilter& sourceFilter, JSCompartment* target, + NukeReferencesToWindow nukeReferencesToWindow, + NukeReferencesFromTarget nukeReferencesFromTarget); /* Specify information about DOMProxy proxies in the DOM, for use by ICs. */ @@ -1234,24 +1203,16 @@ */ struct ExpandoAndGeneration { - ExpandoAndGeneration() - : expando(JS::UndefinedValue()), - generation(0) - {} + ExpandoAndGeneration() : expando(JS::UndefinedValue()), generation(0) {} - void OwnerUnlinked() - { - ++generation; - } + void OwnerUnlinked() { ++generation; } - static size_t offsetOfExpando() - { - return offsetof(ExpandoAndGeneration, expando); + static size_t offsetOfExpando() { + return offsetof(ExpandoAndGeneration, expando); } - static size_t offsetOfGeneration() - { - return offsetof(ExpandoAndGeneration, generation); + static size_t offsetOfGeneration() { + return offsetof(ExpandoAndGeneration, generation); } JS::Heap expando; @@ -1266,50 +1227,71 @@ ShadowsViaDirectExpando, ShadowsViaIndirectExpando } DOMProxyShadowsResult; -typedef DOMProxyShadowsResult -(* DOMProxyShadowsCheck)(JSContext* cx, JS::HandleObject object, JS::HandleId id); -JS_FRIEND_API(void) -SetDOMProxyInformation(const void* domProxyHandlerFamily, uint32_t domProxyExpandoSlot, - DOMProxyShadowsCheck domProxyShadowsCheck); +typedef DOMProxyShadowsResult (*DOMProxyShadowsCheck)(JSContext* cx, + JS::HandleObject object, + JS::HandleId id); +JS_FRIEND_API void SetDOMProxyInformation( + const void* domProxyHandlerFamily, + DOMProxyShadowsCheck domProxyShadowsCheck); const void* GetDOMProxyHandlerFamily(); -uint32_t GetDOMProxyExpandoSlot(); DOMProxyShadowsCheck GetDOMProxyShadowsCheck(); inline bool DOMProxyIsShadowing(DOMProxyShadowsResult result) { - return result == Shadows || - result == ShadowsViaDirectExpando || - result == ShadowsViaIndirectExpando; + return result == Shadows || result == ShadowsViaDirectExpando || + result == ShadowsViaIndirectExpando; } +// Callbacks and other information for use by the JITs when optimizing accesses +// on xray wrappers. +struct XrayJitInfo { + // Test whether a proxy handler is a cross compartment xray with no + // security checks. + bool (*isCrossCompartmentXray)(const BaseProxyHandler* handler); + + // Test whether xrays with a global object's compartment have expandos of + // their own, instead of sharing them with Xrays from other compartments. + bool (*globalHasExclusiveExpandos)(JSObject* obj); + + // Proxy reserved slot used by xrays in sandboxes to store their holder + // object. + size_t xrayHolderSlot; + + // Reserved slot used by xray holders to store the xray's expando object. + size_t holderExpandoSlot; + + // Reserved slot used by xray expandos to store a custom prototype. + size_t expandoProtoSlot; +}; + +JS_FRIEND_API void SetXrayJitInfo(XrayJitInfo* info); + +XrayJitInfo* GetXrayJitInfo(); + /* Implemented in jsdate.cpp. */ /** Detect whether the internal date value is NaN. */ -extern JS_FRIEND_API(bool) -DateIsValid(JSContext* cx, JS::HandleObject obj, bool* isValid); +extern JS_FRIEND_API bool DateIsValid(JSContext* cx, JS::HandleObject obj, + bool* isValid); -extern JS_FRIEND_API(bool) -DateGetMsecSinceEpoch(JSContext* cx, JS::HandleObject obj, double* msecSinceEpoch); +extern JS_FRIEND_API bool DateGetMsecSinceEpoch(JSContext* cx, + JS::HandleObject obj, + double* msecSinceEpoch); } /* namespace js */ -/* Implemented in jscntxt.cpp. */ - -/** - * Report an exception, which is currently realized as a printf-style format - * string and its arguments. - */ typedef enum JSErrNum { -#define MSG_DEF(name, count, exception, format) \ - name, +#define MSG_DEF(name, count, exception, format) name, #include "js.msg" #undef MSG_DEF - JSErr_Limit + JSErr_Limit } JSErrNum; namespace js { -extern JS_FRIEND_API(const JSErrorFormatString*) -GetErrorMessage(void* userRef, const unsigned errorNumber); +/* Implemented in vm/JSContext.cpp. */ + +extern JS_FRIEND_API const JSErrorFormatString* GetErrorMessage( + void* userRef, const unsigned errorNumber); // AutoStableStringChars is here so we can use it in ErrorReport. It // should get moved out of here if we can manage it. See bug 1040316. @@ -1323,171 +1305,163 @@ * 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 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_; - - public: - explicit AutoStableStringChars(JSContext* cx) - : s_(cx), state_(Uninitialized) - {} - - MOZ_MUST_USE - bool init(JSContext* cx, JSString* s); - - /* Like init(), but Latin1 chars are inflated to TwoByte. */ - MOZ_MUST_USE - bool initTwoByte(JSContext* cx, JSString* s); - - bool isLatin1() const { return state_ == Latin1; } - bool isTwoByte() const { return state_ == TwoByte; } - - const char16_t* twoByteChars() const { - MOZ_ASSERT(state_ == TwoByte); - return twoByteChars_; - } - - mozilla::Range latin1Range() const { - MOZ_ASSERT(state_ == Latin1); - return mozilla::Range(latin1Chars_, - GetStringLength(s_)); - } - - mozilla::Range twoByteRange() const { - MOZ_ASSERT(state_ == TwoByte); - return mozilla::Range(twoByteChars_, - GetStringLength(s_)); - } - - /* If we own the chars, transfer ownership to the caller. */ - bool maybeGiveOwnershipToCaller() { - MOZ_ASSERT(state_ != Uninitialized); - if (!ownChars_.isSome() || !ownChars_->extractRawBuffer()) - return false; - state_ = Uninitialized; - ownChars_.reset(); - return true; - } - - private: - AutoStableStringChars(const AutoStableStringChars& other) = delete; - void operator=(const AutoStableStringChars& other) = delete; - - 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(); - - enum SniffingBehavior { - WithSideEffects, - NoSideEffects - }; +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_; + + public: + explicit AutoStableStringChars(JSContext* cx) + : s_(cx), state_(Uninitialized) {} + + MOZ_MUST_USE + bool init(JSContext* cx, JSString* s); + + /* Like init(), but Latin1 chars are inflated to TwoByte. */ + MOZ_MUST_USE + bool initTwoByte(JSContext* cx, JSString* s); + + bool isLatin1() const { return state_ == Latin1; } + bool isTwoByte() const { return state_ == TwoByte; } + + const JS::Latin1Char* latin1Chars() const { + MOZ_ASSERT(state_ == Latin1); + return latin1Chars_; + } + const char16_t* twoByteChars() const { + MOZ_ASSERT(state_ == TwoByte); + return twoByteChars_; + } - /** - * 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); + mozilla::Range latin1Range() const { + MOZ_ASSERT(state_ == Latin1); + return mozilla::Range(latin1Chars_, + GetStringLength(s_)); + } - JSErrorReport* report() - { - return reportp; - } + mozilla::Range twoByteRange() const { + MOZ_ASSERT(state_ == TwoByte); + return mozilla::Range(twoByteChars_, GetStringLength(s_)); + } - const JS::ConstUTF8CharsZ toStringResult() - { - return toStringResult_; - } + /* If we own the chars, transfer ownership to the caller. */ + bool maybeGiveOwnershipToCaller() { + MOZ_ASSERT(state_ != Uninitialized); + if (!ownChars_.isSome() || !ownChars_->extractRawBuffer()) return false; + state_ = Uninitialized; + ownChars_.reset(); + return true; + } - private: - // More or less an equivalent of JS_ReportErrorNumber/js::ReportErrorNumberVA - // but fills in an ErrorReport instead of reporting it. Uses varargs to - // make it simpler to call js::ExpandErrorArgumentsVA. - // - // Returns false if we fail to actually populate the ErrorReport - // for some reason (probably out of memory). - bool populateUncaughtExceptionReportUTF8(JSContext* cx, ...); - bool populateUncaughtExceptionReportUTF8VA(JSContext* cx, va_list ap); - - // Reports exceptions from add-on scopes to telementry. - void ReportAddonExceptionToTelementry(JSContext* cx); - - // We may have a provided JSErrorReport, so need a way to represent that. - JSErrorReport* reportp; - - // Or we may need to synthesize a JSErrorReport one of our own. - JSErrorReport ownedReport; - - // And we have a string to maybe keep alive that has pointers into - // it from ownedReport. - JS::RootedString str; - - // And keep its chars alive too. - AutoStableStringChars strChars; - - // And we need to root our exception value. - JS::RootedObject exnObject; - - // And for our filename. - JSAutoByteString filename; - - // 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; + private: + AutoStableStringChars(const AutoStableStringChars& other) = delete; + void operator=(const AutoStableStringChars& other) = delete; + + 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(); + + 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 JS::ConstUTF8CharsZ toStringResult() { return toStringResult_; } + + private: + // More or less an equivalent of JS_ReportErrorNumber/js::ReportErrorNumberVA + // but fills in an ErrorReport instead of reporting it. Uses varargs to + // make it simpler to call js::ExpandErrorArgumentsVA. + // + // Returns false if we fail to actually populate the ErrorReport + // for some reason (probably out of memory). + bool populateUncaughtExceptionReportUTF8(JSContext* cx, ...); + bool populateUncaughtExceptionReportUTF8VA(JSContext* cx, va_list ap); + + // Reports exceptions from add-on scopes to telemetry. + void ReportAddonExceptionToTelemetry(JSContext* cx); + + // We may have a provided JSErrorReport, so need a way to represent that. + JSErrorReport* reportp; + + // Or we may need to synthesize a JSErrorReport one of our own. + JSErrorReport ownedReport; + + // And we have a string to maybe keep alive that has pointers into + // it from ownedReport. + JS::RootedString str; + + // And keep its chars alive too. + AutoStableStringChars strChars; + + // And we need to root our exception value. + JS::RootedObject exnObject; + + // And for our filename. + JSAutoByteString filename; + + // 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. */ -extern JS_FRIEND_API(uint64_t) -GetSCOffset(JSStructuredCloneWriter* writer); +extern JS_FRIEND_API uint64_t GetSCOffset(JSStructuredCloneWriter* writer); namespace Scalar { @@ -1498,134 +1472,129 @@ * definitions. */ enum Type { - Int8 = 0, - Uint8, - Int16, - Uint16, - Int32, - Uint32, - Float32, - Float64, - - /** - * Special type that is a uint8_t, but assignments are clamped to [0, 256). - * Treat the raw data type as a uint8_t. - */ - Uint8Clamped, - - /** - * Types that don't have their own TypedArray equivalent, for now. - */ - MaxTypedArrayViewType, - - Int64, - Float32x4, - Int8x16, - Int16x8, - Int32x4 -}; - -static inline size_t -byteSize(Type atype) -{ - switch (atype) { - case Int8: - case Uint8: - case Uint8Clamped: - return 1; - case Int16: - case Uint16: - return 2; - case Int32: - case Uint32: - case Float32: - return 4; - case Int64: - case Float64: - return 8; - case Int8x16: - case Int16x8: - case Int32x4: - case Float32x4: - return 16; - default: - MOZ_CRASH("invalid scalar type"); - } + Int8 = 0, + Uint8, + Int16, + Uint16, + Int32, + Uint32, + Float32, + Float64, + + /** + * Special type that is a uint8_t, but assignments are clamped to [0, 256). + * Treat the raw data type as a uint8_t. + */ + Uint8Clamped, + + /** + * Types that don't have their own TypedArray equivalent, for now. + */ + MaxTypedArrayViewType, + + Int64, + Float32x4, + Int8x16, + Int16x8, + Int32x4 +}; + +static inline size_t byteSize(Type atype) { + switch (atype) { + case Int8: + case Uint8: + case Uint8Clamped: + return 1; + case Int16: + case Uint16: + return 2; + case Int32: + case Uint32: + case Float32: + return 4; + case Int64: + case Float64: + return 8; + case Int8x16: + case Int16x8: + case Int32x4: + case Float32x4: + return 16; + default: + MOZ_CRASH("invalid scalar type"); + } } -static inline bool -isSignedIntType(Type atype) { - switch (atype) { - case Int8: - case Int16: - case Int32: - case Int64: - case Int8x16: - case Int16x8: - case Int32x4: - return true; - case Uint8: - case Uint8Clamped: - case Uint16: - case Uint32: - case Float32: - case Float64: - case Float32x4: - return false; - default: - MOZ_CRASH("invalid scalar type"); - } +static inline bool isSignedIntType(Type atype) { + switch (atype) { + case Int8: + case Int16: + case Int32: + case Int64: + case Int8x16: + case Int16x8: + case Int32x4: + return true; + case Uint8: + case Uint8Clamped: + case Uint16: + case Uint32: + case Float32: + case Float64: + case Float32x4: + return false; + default: + MOZ_CRASH("invalid scalar type"); + } } -static inline bool -isSimdType(Type atype) { - switch (atype) { - case Int8: - case Uint8: - case Uint8Clamped: - case Int16: - case Uint16: - case Int32: - case Uint32: - case Int64: - case Float32: - case Float64: - return false; - case Int8x16: - case Int16x8: - case Int32x4: - case Float32x4: - return true; - case MaxTypedArrayViewType: - break; - } - MOZ_CRASH("invalid scalar type"); +static inline bool isSimdType(Type atype) { + switch (atype) { + case Int8: + case Uint8: + case Uint8Clamped: + case Int16: + case Uint16: + case Int32: + case Uint32: + case Int64: + case Float32: + case Float64: + return false; + case Int8x16: + case Int16x8: + case Int32x4: + case Float32x4: + return true; + case MaxTypedArrayViewType: + break; + } + MOZ_CRASH("invalid scalar type"); } -static inline size_t -scalarByteSize(Type atype) { - switch (atype) { - case Int8x16: - return 1; - case Int16x8: - return 2; - case Int32x4: - case Float32x4: - return 4; - case Int8: - case Uint8: - case Uint8Clamped: - case Int16: - case Uint16: - case Int32: - case Uint32: - case Int64: - case Float32: - case Float64: - case MaxTypedArrayViewType: - break; - } - MOZ_CRASH("invalid simd type"); +static inline size_t scalarByteSize(Type atype) { + switch (atype) { + case Int8x16: + return 1; + case Int16x8: + return 2; + case Int32x4: + case Float32x4: + return 4; + case Int8: + case Uint8: + case Uint8Clamped: + case Int16: + case Uint16: + case Int32: + case Uint32: + case Int64: + case Float32: + case Float64: + case MaxTypedArrayViewType: + break; + } + MOZ_CRASH("invalid simd type"); } } /* namespace Scalar */ @@ -1634,27 +1603,28 @@ /* * Create a new typed array with nelements elements. * - * These functions (except the WithBuffer variants) fill in the array with zeros. + * These functions (except the WithBuffer variants) fill in the array with + * zeros. */ -extern JS_FRIEND_API(JSObject*) -JS_NewInt8Array(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewUint8Array(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewUint8ClampedArray(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewInt16Array(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewUint16Array(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewInt32Array(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewUint32Array(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewFloat32Array(JSContext* cx, uint32_t nelements); -extern JS_FRIEND_API(JSObject*) -JS_NewFloat64Array(JSContext* cx, uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewInt8Array(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewUint8Array(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewUint8ClampedArray(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewInt16Array(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewUint16Array(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewInt32Array(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewUint32Array(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewFloat32Array(JSContext* cx, + uint32_t nelements); +extern JS_FRIEND_API JSObject* JS_NewFloat64Array(JSContext* cx, + uint32_t nelements); /* * Create a new typed array and copy in values from the given object. The @@ -1664,24 +1634,24 @@ * conversion to the typed array element type. */ -extern JS_FRIEND_API(JSObject*) -JS_NewInt8ArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewUint8ArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewUint8ClampedArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewInt16ArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewUint16ArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewInt32ArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewUint32ArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewFloat32ArrayFromArray(JSContext* cx, JS::HandleObject array); -extern JS_FRIEND_API(JSObject*) -JS_NewFloat64ArrayFromArray(JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewInt8ArrayFromArray(JSContext* cx, + JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewUint8ArrayFromArray( + JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewUint8ClampedArrayFromArray( + JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewInt16ArrayFromArray( + JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewUint16ArrayFromArray( + JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewInt32ArrayFromArray( + JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewUint32ArrayFromArray( + JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewFloat32ArrayFromArray( + JSContext* cx, JS::HandleObject array); +extern JS_FRIEND_API JSObject* JS_NewFloat64ArrayFromArray( + JSContext* cx, JS::HandleObject array); /* * Create a new typed array using the given ArrayBuffer or @@ -1690,33 +1660,33 @@ * array is used as the default value. */ -extern JS_FRIEND_API(JSObject*) -JS_NewInt8ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewUint8ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewUint8ClampedArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewInt16ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewUint16ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewInt32ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewUint32ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewFloat32ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); -extern JS_FRIEND_API(JSObject*) -JS_NewFloat64ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, - uint32_t byteOffset, int32_t length); +extern JS_FRIEND_API JSObject* JS_NewInt8ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewUint8ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewUint8ClampedArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewInt16ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewUint16ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewInt32ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewUint32ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewFloat32ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); +extern JS_FRIEND_API JSObject* JS_NewFloat64ArrayWithBuffer( + JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, + int32_t length); /** * Create a new SharedArrayBuffer with the given byte length. This @@ -1724,14 +1694,14 @@ * JS::CompartmentCreationOptionsRef(cx).getSharedMemoryAndAtomicsEnabled() is * true. */ -extern JS_FRIEND_API(JSObject*) -JS_NewSharedArrayBuffer(JSContext* cx, uint32_t nbytes); +extern JS_FRIEND_API JSObject* JS_NewSharedArrayBuffer(JSContext* cx, + uint32_t nbytes); /** * Create a new ArrayBuffer with the given byte length. */ -extern JS_FRIEND_API(JSObject*) -JS_NewArrayBuffer(JSContext* cx, uint32_t nbytes); +extern JS_FRIEND_API JSObject* JS_NewArrayBuffer(JSContext* cx, + uint32_t nbytes); /** * Check whether obj supports JS_GetTypedArray* APIs. Note that this may return @@ -1739,8 +1709,7 @@ * this test or one of the JS_Is*Array tests succeeds, then it is safe to call * the various accessor JSAPI calls defined below. */ -extern JS_FRIEND_API(bool) -JS_IsTypedArrayObject(JSObject* obj); +extern JS_FRIEND_API bool JS_IsTypedArrayObject(JSObject* obj); /** * Check whether obj supports JS_GetArrayBufferView* APIs. Note that this may @@ -1749,31 +1718,21 @@ * is safe to call the various ArrayBufferView accessor JSAPI calls defined * below. */ -extern JS_FRIEND_API(bool) -JS_IsArrayBufferViewObject(JSObject* obj); +extern JS_FRIEND_API bool JS_IsArrayBufferViewObject(JSObject* obj); /* * Test for specific typed array types (ArrayBufferView subtypes) */ -extern JS_FRIEND_API(bool) -JS_IsInt8Array(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsUint8Array(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsUint8ClampedArray(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsInt16Array(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsUint16Array(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsInt32Array(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsUint32Array(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsFloat32Array(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsFloat64Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsInt8Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsUint8Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsUint8ClampedArray(JSObject* obj); +extern JS_FRIEND_API bool JS_IsInt16Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsUint16Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsInt32Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsUint32Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsFloat32Array(JSObject* obj); +extern JS_FRIEND_API bool JS_IsFloat64Array(JSObject* obj); /** * Return the isShared flag of a typed array, which denotes whether @@ -1783,8 +1742,7 @@ * be known that it would pass such a test: it is a typed array or a wrapper of * a typed array, and the unwrapping will succeed. */ -extern JS_FRIEND_API(bool) -JS_GetTypedArraySharedness(JSObject* obj); +extern JS_FRIEND_API bool JS_GetTypedArraySharedness(JSObject* obj); /* * Test for specific typed array types (ArrayBufferView subtypes) and return @@ -1793,61 +1751,50 @@ namespace js { -extern JS_FRIEND_API(JSObject*) -UnwrapInt8Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapUint8Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapUint8ClampedArray(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapInt16Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapUint16Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapInt32Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapUint32Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapFloat32Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapFloat64Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapInt8Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapUint8Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapUint8ClampedArray(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapInt16Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapUint16Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapInt32Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapUint32Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapFloat32Array(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapFloat64Array(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapArrayBuffer(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapArrayBuffer(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapArrayBufferView(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapArrayBufferView(JSObject* obj); -extern JS_FRIEND_API(JSObject*) -UnwrapSharedArrayBuffer(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapSharedArrayBuffer(JSObject* obj); +extern JS_FRIEND_API JSObject* UnwrapReadableStream(JSObject* obj); namespace detail { -extern JS_FRIEND_DATA(const Class* const) Int8ArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Uint8ArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Uint8ClampedArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Int16ArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Uint16ArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Int32ArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Uint32ArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Float32ArrayClassPtr; -extern JS_FRIEND_DATA(const Class* const) Float64ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Int8ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Uint8ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Uint8ClampedArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Int16ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Uint16ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Int32ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Uint32ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Float32ArrayClassPtr; +extern JS_FRIEND_DATA const Class* const Float64ArrayClassPtr; const size_t TypedArrayLengthSlot = 1; -} // namespace detail +} // namespace detail -#define JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Type, type) \ -inline void \ -Get ## Type ## ArrayLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, type** data) \ -{ \ - MOZ_ASSERT(GetObjectClass(obj) == detail::Type ## ArrayClassPtr); \ - const JS::Value& lenSlot = GetReservedSlot(obj, detail::TypedArrayLengthSlot); \ - *length = mozilla::AssertedCast(lenSlot.toInt32()); \ - *isSharedMemory = JS_GetTypedArraySharedness(obj); \ - *data = static_cast(GetObjectPrivate(obj)); \ -} +#define JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Type, type) \ + inline void Get##Type##ArrayLengthAndData( \ + JSObject* obj, uint32_t* length, bool* isSharedMemory, type** data) { \ + MOZ_ASSERT(GetObjectClass(obj) == detail::Type##ArrayClassPtr); \ + const JS::Value& lenSlot = \ + GetReservedSlot(obj, detail::TypedArrayLengthSlot); \ + *length = mozilla::AssertedCast(lenSlot.toInt32()); \ + *isSharedMemory = JS_GetTypedArraySharedness(obj); \ + *data = static_cast(GetObjectPrivate(obj)); \ + } JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int8, int8_t) JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8, uint8_t) @@ -1863,73 +1810,95 @@ // This one isn't inlined because it's rather tricky (by dint of having to deal // with a dozen-plus classes and varying slot layouts. -extern JS_FRIEND_API(void) -GetArrayBufferViewLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); +extern JS_FRIEND_API void GetArrayBufferViewLengthAndData(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + uint8_t** data); // This one isn't inlined because there are a bunch of different ArrayBuffer // classes that would have to be individually handled here. // // There is an isShared out argument for API consistency (eases use from DOM). // It will always be set to false. -extern JS_FRIEND_API(void) -GetArrayBufferLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); +extern JS_FRIEND_API void GetArrayBufferLengthAndData(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + uint8_t** data); // Ditto for SharedArrayBuffer. // // There is an isShared out argument for API consistency (eases use from DOM). // It will always be set to true. -extern JS_FRIEND_API(void) -GetSharedArrayBufferLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); +extern JS_FRIEND_API void GetSharedArrayBufferLengthAndData( + JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); -} // namespace js +} // namespace js -JS_FRIEND_API(uint8_t*) -JS_GetSharedArrayBufferData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); +JS_FRIEND_API uint8_t* JS_GetSharedArrayBufferData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); /* * Unwrap Typed arrays all at once. Return nullptr without throwing if the * object cannot be viewed as the correct typed array, or the typed array * object on success, filling both outparameters. */ -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsInt8Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, int8_t** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsUint8Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsUint8ClampedArray(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsInt16Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, int16_t** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsUint16Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint16_t** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsInt32Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, int32_t** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsUint32Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint32_t** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsFloat32Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, float** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsFloat64Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, double** data); -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsArrayBufferView(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsInt8Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + int8_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsUint8Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + uint8_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsUint8ClampedArray( + JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsInt16Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + int16_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsUint16Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + uint16_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsInt32Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + int32_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsUint32Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + uint32_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsFloat32Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + float** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsFloat64Array(JSObject* obj, + uint32_t* length, + bool* isSharedMemory, + double** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsArrayBufferView( + JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); /* * Unwrap an ArrayBuffer, return nullptr if it's a different type. */ -extern JS_FRIEND_API(JSObject*) -JS_GetObjectAsArrayBuffer(JSObject* obj, uint32_t* length, uint8_t** data); +extern JS_FRIEND_API JSObject* JS_GetObjectAsArrayBuffer(JSObject* obj, + uint32_t* length, + uint8_t** data); /* - * Get the type of elements in a typed array, or MaxTypedArrayViewType if a DataView. + * Get the type of elements in a typed array, or MaxTypedArrayViewType if a + * DataView. * * |obj| must have passed a JS_IsArrayBufferView/JS_Is*Array test, or somehow * be known that it would pass such a test: it is an ArrayBufferView or a * wrapper of an ArrayBufferView, and the unwrapping will succeed. */ -extern JS_FRIEND_API(js::Scalar::Type) -JS_GetArrayBufferViewType(JSObject* obj); +extern JS_FRIEND_API js::Scalar::Type JS_GetArrayBufferViewType(JSObject* obj); -extern JS_FRIEND_API(js::Scalar::Type) -JS_GetSharedArrayBufferViewType(JSObject* obj); +extern JS_FRIEND_API js::Scalar::Type JS_GetSharedArrayBufferViewType( + JSObject* obj); /* * Check whether obj supports the JS_GetArrayBuffer* APIs. Note that this may @@ -1937,11 +1906,9 @@ * unwrapping. If this test succeeds, then it is safe to call the various * accessor JSAPI calls defined below. */ -extern JS_FRIEND_API(bool) -JS_IsArrayBufferObject(JSObject* obj); +extern JS_FRIEND_API bool JS_IsArrayBufferObject(JSObject* obj); -extern JS_FRIEND_API(bool) -JS_IsSharedArrayBufferObject(JSObject* obj); +extern JS_FRIEND_API bool JS_IsSharedArrayBufferObject(JSObject* obj); /** * Return the available byte length of an array buffer. @@ -1950,11 +1917,9 @@ * that it would pass such a test: it is an ArrayBuffer or a wrapper of an * ArrayBuffer, and the unwrapping will succeed. */ -extern JS_FRIEND_API(uint32_t) -JS_GetArrayBufferByteLength(JSObject* obj); +extern JS_FRIEND_API uint32_t JS_GetArrayBufferByteLength(JSObject* obj); -extern JS_FRIEND_API(uint32_t) -JS_GetSharedArrayBufferByteLength(JSObject* obj); +extern JS_FRIEND_API uint32_t JS_GetSharedArrayBufferByteLength(JSObject* obj); /** * Return true if the arrayBuffer contains any data. This will return false for @@ -1964,8 +1929,7 @@ * that it would pass such a test: it is an ArrayBuffer or a wrapper of an * ArrayBuffer, and the unwrapping will succeed. */ -extern JS_FRIEND_API(bool) -JS_ArrayBufferHasData(JSObject* obj); +extern JS_FRIEND_API bool JS_ArrayBufferHasData(JSObject* obj); /** * Return a pointer to the start of the data referenced by a typed array. The @@ -1978,19 +1942,19 @@ * that it would pass such a test: it is an ArrayBuffer or a wrapper of an * ArrayBuffer, and the unwrapping will succeed. * - * *isSharedMemory will be set to false, the argument is present to simplify + * |*isSharedMemory| will be set to false, the argument is present to simplify * its use from code that also interacts with SharedArrayBuffer. */ -extern JS_FRIEND_API(uint8_t*) -JS_GetArrayBufferData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API uint8_t* JS_GetArrayBufferData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); /** * Check whether the obj is ArrayBufferObject and memory mapped. Note that this * may return false if a security wrapper is encountered that denies the * unwrapping. */ -extern JS_FRIEND_API(bool) -JS_IsMappedArrayBufferObject(JSObject* obj); +extern JS_FRIEND_API bool JS_IsMappedArrayBufferObject(JSObject* obj); /** * Return the number of elements in a typed array. @@ -1999,8 +1963,7 @@ * be known that it would pass such a test: it is a typed array or a wrapper of * a typed array, and the unwrapping will succeed. */ -extern JS_FRIEND_API(uint32_t) -JS_GetTypedArrayLength(JSObject* obj); +extern JS_FRIEND_API uint32_t JS_GetTypedArrayLength(JSObject* obj); /** * Return the byte offset from the start of an array buffer to the start of a @@ -2010,8 +1973,7 @@ * be known that it would pass such a test: it is a typed array or a wrapper of * a typed array, and the unwrapping will succeed. */ -extern JS_FRIEND_API(uint32_t) -JS_GetTypedArrayByteOffset(JSObject* obj); +extern JS_FRIEND_API uint32_t JS_GetTypedArrayByteOffset(JSObject* obj); /** * Return the byte length of a typed array. @@ -2020,22 +1982,24 @@ * be known that it would pass such a test: it is a typed array or a wrapper of * a typed array, and the unwrapping will succeed. */ -extern JS_FRIEND_API(uint32_t) -JS_GetTypedArrayByteLength(JSObject* obj); +extern JS_FRIEND_API uint32_t JS_GetTypedArrayByteLength(JSObject* obj); /** * Check whether obj supports JS_ArrayBufferView* APIs. Note that this may * return false if a security wrapper is encountered that denies the * unwrapping. */ -extern JS_FRIEND_API(bool) -JS_IsArrayBufferViewObject(JSObject* obj); +extern JS_FRIEND_API bool JS_IsArrayBufferViewObject(JSObject* obj); /** * More generic name for JS_GetTypedArrayByteLength to cover DataViews as well */ -extern JS_FRIEND_API(uint32_t) -JS_GetArrayBufferViewByteLength(JSObject* obj); +extern JS_FRIEND_API uint32_t JS_GetArrayBufferViewByteLength(JSObject* obj); + +/** + * More generic name for JS_GetTypedArrayByteOffset to cover DataViews as well + */ +extern JS_FRIEND_API uint32_t JS_GetArrayBufferViewByteOffset(JSObject* obj); /* * Return a pointer to the start of the data referenced by a typed array. The @@ -2048,43 +2012,49 @@ * pass such a test: it is a typed array or a wrapper of a typed array, and the * unwrapping will succeed. * - * *isSharedMemory will be set to true if the typed array maps a + * |*isSharedMemory| will be set to true if the typed array maps a * SharedArrayBuffer, otherwise to false. */ -extern JS_FRIEND_API(int8_t*) -JS_GetInt8ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(uint8_t*) -JS_GetUint8ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(uint8_t*) -JS_GetUint8ClampedArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(int16_t*) -JS_GetInt16ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(uint16_t*) -JS_GetUint16ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(int32_t*) -JS_GetInt32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(uint32_t*) -JS_GetUint32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(float*) -JS_GetFloat32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); -extern JS_FRIEND_API(double*) -JS_GetFloat64ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API int8_t* JS_GetInt8ArrayData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); +extern JS_FRIEND_API uint8_t* JS_GetUint8ArrayData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); +extern JS_FRIEND_API uint8_t* JS_GetUint8ClampedArrayData( + JSObject* obj, bool* isSharedMemory, const JS::AutoRequireNoGC&); +extern JS_FRIEND_API int16_t* JS_GetInt16ArrayData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); +extern JS_FRIEND_API uint16_t* JS_GetUint16ArrayData( + JSObject* obj, bool* isSharedMemory, const JS::AutoRequireNoGC&); +extern JS_FRIEND_API int32_t* JS_GetInt32ArrayData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); +extern JS_FRIEND_API uint32_t* JS_GetUint32ArrayData( + JSObject* obj, bool* isSharedMemory, const JS::AutoRequireNoGC&); +extern JS_FRIEND_API float* JS_GetFloat32ArrayData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); +extern JS_FRIEND_API double* JS_GetFloat64ArrayData(JSObject* obj, + bool* isSharedMemory, + const JS::AutoRequireNoGC&); /** * Same as above, but for any kind of ArrayBufferView. Prefer the type-specific * versions when possible. */ -extern JS_FRIEND_API(void*) -JS_GetArrayBufferViewData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API void* JS_GetArrayBufferViewData( + JSObject* obj, bool* isSharedMemory, const JS::AutoRequireNoGC&); /** * 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); +extern JS_FRIEND_API JSObject* JS_GetArrayBufferViewBuffer( + JSContext* cx, JS::HandleObject obj, bool* isSharedMemory); /** * Detach an ArrayBuffer, causing all associated views to no longer refer to @@ -2092,32 +2062,30 @@ * * The |changeData| argument is obsolete and ignored. */ -extern JS_FRIEND_API(bool) -JS_DetachArrayBuffer(JSContext* cx, JS::HandleObject obj); +extern JS_FRIEND_API bool JS_DetachArrayBuffer(JSContext* cx, + JS::HandleObject obj); /** * 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_IsDetachedArrayBufferObject(JSObject* obj); +extern JS_FRIEND_API bool JS_IsDetachedArrayBufferObject(JSObject* obj); /** * Check whether obj supports JS_GetDataView* APIs. */ -JS_FRIEND_API(bool) -JS_IsDataViewObject(JSObject* obj); +JS_FRIEND_API bool JS_IsDataViewObject(JSObject* obj); /** - * Create a new DataView using the given ArrayBuffer for storage. The given - * buffer must be an ArrayBuffer (or a cross-compartment wrapper of an - * ArrayBuffer), and the offset and length must fit within the bounds of the - * arrayBuffer. Currently, nullptr will be returned and an exception will be - * thrown if these conditions do not hold, but do not depend on that behavior. + * Create a new DataView using the given buffer for storage. The given buffer + * must be an ArrayBuffer or SharedArrayBuffer (or a cross-compartment wrapper + * of either type), and the offset and length must fit within the bounds of the + * buffer. Currently, nullptr will be returned and an exception will be thrown + * if these conditions do not hold, but do not depend on that behavior. */ -JS_FRIEND_API(JSObject*) -JS_NewDataView(JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, int32_t byteLength); +JS_FRIEND_API JSObject* JS_NewDataView(JSContext* cx, JS::HandleObject buffer, + uint32_t byteOffset, int32_t byteLength); /** * Return the byte offset of a data view into its array buffer. |obj| must be a @@ -2127,8 +2095,7 @@ * it would pass such a test: it is a data view or a wrapper of a data view, * and the unwrapping will succeed. */ -JS_FRIEND_API(uint32_t) -JS_GetDataViewByteOffset(JSObject* obj); +JS_FRIEND_API uint32_t JS_GetDataViewByteOffset(JSObject* obj); /** * Return the byte length of a data view. @@ -2138,8 +2105,7 @@ * and the unwrapping will succeed. If cx is nullptr, then DEBUG builds may be * unable to assert when unwrapping should be disallowed. */ -JS_FRIEND_API(uint32_t) -JS_GetDataViewByteLength(JSObject* obj); +JS_FRIEND_API uint32_t JS_GetDataViewByteLength(JSObject* obj); /** * Return a pointer to the beginning of the data referenced by a DataView. @@ -2148,82 +2114,53 @@ * it would pass such a test: it is a data view or a wrapper of a data view, * and the unwrapping will succeed. If cx is nullptr, then DEBUG builds may be * unable to assert when unwrapping should be disallowed. - */ -JS_FRIEND_API(void*) -JS_GetDataViewData(JSObject* obj, const JS::AutoCheckCannotGC&); - -namespace js { - -/** - * Add a watchpoint -- in the Object.prototype.watch sense -- to |obj| for the - * property |id|, using the callable object |callable| as the function to be - * called for notifications. - * - * This is an internal function exposed -- temporarily -- only so that DOM - * proxies can be watchable. Don't use it! We'll soon kill off the - * Object.prototype.{,un}watch functions, at which point this will go too. - */ -extern JS_FRIEND_API(bool) -WatchGuts(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); - -/** - * Remove a watchpoint -- in the Object.prototype.watch sense -- from |obj| for - * the property |id|. * - * This is an internal function exposed -- temporarily -- only so that DOM - * proxies can be watchable. Don't use it! We'll soon kill off the - * Object.prototype.{,un}watch functions, at which point this will go too. + * |*isSharedMemory| will be set to true if the DataView maps a + * SharedArrayBuffer, otherwise to false. */ -extern JS_FRIEND_API(bool) -UnwatchGuts(JSContext* cx, JS::HandleObject obj, JS::HandleId id); +JS_FRIEND_API void* JS_GetDataViewData(JSObject* obj, bool* isSharedMemory, + const JS::AutoRequireNoGC&); +namespace js { namespace jit { enum class InlinableNative : uint16_t; -} // namespace jit - -} // namespace js +} // namespace jit +} // namespace js /** * A class, expected to be passed by value, which represents the CallArgs for a * JSJitGetterOp. */ -class JSJitGetterCallArgs : protected JS::MutableHandleValue -{ - public: - explicit JSJitGetterCallArgs(const JS::CallArgs& args) - : JS::MutableHandleValue(args.rval()) - {} - - explicit JSJitGetterCallArgs(JS::RootedValue* rooted) - : JS::MutableHandleValue(rooted) - {} +class JSJitGetterCallArgs : protected JS::MutableHandleValue { + public: + explicit JSJitGetterCallArgs(const JS::CallArgs& args) + : JS::MutableHandleValue(args.rval()) {} - JS::MutableHandleValue rval() { - return *this; - } + explicit JSJitGetterCallArgs(JS::RootedValue* rooted) + : JS::MutableHandleValue(rooted) {} + + JS::MutableHandleValue rval() { return *this; } }; /** * A class, expected to be passed by value, which represents the CallArgs for a * JSJitSetterOp. */ -class JSJitSetterCallArgs : protected JS::MutableHandleValue -{ - public: - explicit JSJitSetterCallArgs(const JS::CallArgs& args) - : JS::MutableHandleValue(args[0]) - {} - - JS::MutableHandleValue operator[](unsigned i) { - MOZ_ASSERT(i == 0); - return *this; - } +class JSJitSetterCallArgs : protected JS::MutableHandleValue { + public: + explicit JSJitSetterCallArgs(const JS::CallArgs& args) + : JS::MutableHandleValue(args[0]) {} + + JS::MutableHandleValue operator[](unsigned i) { + MOZ_ASSERT(i == 0); + return *this; + } - unsigned length() const { return 1; } + unsigned length() const { return 1; } - // Add get() or maybe hasDefined() as needed + // Add get() or maybe hasDefined() as needed }; struct JSJitMethodCallArgsTraits; @@ -2232,58 +2169,49 @@ * A class, expected to be passed by reference, which represents the CallArgs * for a JSJitMethodOp. */ -class JSJitMethodCallArgs : protected JS::detail::CallArgsBase -{ - private: - typedef JS::detail::CallArgsBase Base; - friend struct JSJitMethodCallArgsTraits; - - public: - explicit JSJitMethodCallArgs(const JS::CallArgs& args) { - argv_ = args.array(); - argc_ = args.length(); - } +class JSJitMethodCallArgs + : protected JS::detail::CallArgsBase { + private: + typedef JS::detail::CallArgsBase Base; + friend struct JSJitMethodCallArgsTraits; + + public: + explicit JSJitMethodCallArgs(const JS::CallArgs& args) { + argv_ = args.array(); + argc_ = args.length(); + } - JS::MutableHandleValue rval() const { - return Base::rval(); - } + JS::MutableHandleValue rval() const { return Base::rval(); } - unsigned length() const { return Base::length(); } + unsigned length() const { return Base::length(); } - JS::MutableHandleValue operator[](unsigned i) const { - return Base::operator[](i); - } + JS::MutableHandleValue operator[](unsigned i) const { + return Base::operator[](i); + } - bool hasDefined(unsigned i) const { - return Base::hasDefined(i); - } + bool hasDefined(unsigned i) const { return Base::hasDefined(i); } - JSObject& callee() const { - // We can't use Base::callee() because that will try to poke at - // this->usedRval_, which we don't have. - return argv_[-2].toObject(); - } + JSObject& callee() const { + // We can't use Base::callee() because that will try to poke at + // this->usedRval_, which we don't have. + return argv_[-2].toObject(); + } - JS::HandleValue get(unsigned i) const { - return Base::get(i); - } + JS::HandleValue get(unsigned i) const { return Base::get(i); } }; -struct JSJitMethodCallArgsTraits -{ - static const size_t offsetOfArgv = offsetof(JSJitMethodCallArgs, argv_); - static const size_t offsetOfArgc = offsetof(JSJitMethodCallArgs, argc_); +struct JSJitMethodCallArgsTraits { + static const size_t offsetOfArgv = offsetof(JSJitMethodCallArgs, argv_); + static const size_t offsetOfArgc = offsetof(JSJitMethodCallArgs, argc_); }; -typedef bool -(* JSJitGetterOp)(JSContext* cx, JS::HandleObject thisObj, - void* specializedThis, JSJitGetterCallArgs args); -typedef bool -(* JSJitSetterOp)(JSContext* cx, JS::HandleObject thisObj, - void* specializedThis, JSJitSetterCallArgs args); -typedef bool -(* JSJitMethodOp)(JSContext* cx, JS::HandleObject thisObj, - void* specializedThis, const JSJitMethodCallArgs& args); +typedef bool (*JSJitGetterOp)(JSContext* cx, JS::HandleObject thisObj, + void* specializedThis, JSJitGetterCallArgs args); +typedef bool (*JSJitSetterOp)(JSContext* cx, JS::HandleObject thisObj, + void* specializedThis, JSJitSetterCallArgs args); +typedef bool (*JSJitMethodOp)(JSContext* cx, JS::HandleObject thisObj, + void* specializedThis, + const JSJitMethodCallArgs& args); /** * This struct contains metadata passed from the DOM to the JS Engine for JIT @@ -2291,193 +2219,186 @@ * available to general JSAPI users, but we are not currently ready to do so. */ struct JSJitInfo { - enum OpType { - Getter, - Setter, - Method, - StaticMethod, - InlinableNative, - // Must be last - OpTypeCount - }; - - enum ArgType { - // Basic types - String = (1 << 0), - Integer = (1 << 1), // Only 32-bit or less - Double = (1 << 2), // Maybe we want to add Float sometime too - Boolean = (1 << 3), - Object = (1 << 4), - Null = (1 << 5), - - // And derived types - Numeric = Integer | Double, - // Should "Primitive" use the WebIDL definition, which - // excludes string and null, or the typical JS one that includes them? - Primitive = Numeric | Boolean | Null | String, - ObjectOrNull = Object | Null, - Any = ObjectOrNull | Primitive, - - // Our sentinel value. - ArgTypeListEnd = (1 << 31) - }; - - static_assert(Any & String, "Any must include String."); - static_assert(Any & Integer, "Any must include Integer."); - static_assert(Any & Double, "Any must include Double."); - static_assert(Any & Boolean, "Any must include Boolean."); - static_assert(Any & Object, "Any must include Object."); - static_assert(Any & Null, "Any must include Null."); + enum OpType { + Getter, + Setter, + Method, + StaticMethod, + InlinableNative, + IgnoresReturnValueNative, + // Must be last + OpTypeCount + }; + + enum ArgType { + // Basic types + String = (1 << 0), + Integer = (1 << 1), // Only 32-bit or less + Double = (1 << 2), // Maybe we want to add Float sometime too + Boolean = (1 << 3), + Object = (1 << 4), + Null = (1 << 5), + + // And derived types + Numeric = Integer | Double, + // Should "Primitive" use the WebIDL definition, which + // excludes string and null, or the typical JS one that includes them? + Primitive = Numeric | Boolean | Null | String, + ObjectOrNull = Object | Null, + Any = ObjectOrNull | Primitive, + + // Our sentinel value. + ArgTypeListEnd = (1 << 31) + }; + + static_assert(Any & String, "Any must include String."); + static_assert(Any & Integer, "Any must include Integer."); + static_assert(Any & Double, "Any must include Double."); + static_assert(Any & Boolean, "Any must include Boolean."); + static_assert(Any & Object, "Any must include Object."); + static_assert(Any & Null, "Any must include Null."); + + /** + * An enum that describes what this getter/setter/method aliases. This + * determines what things can be hoisted past this call, and if this + * call is movable what it can be hoisted past. + */ + enum AliasSet { + /** + * Alias nothing: a constant value, getting it can't affect any other + * values, nothing can affect it. + */ + AliasNone, /** - * An enum that describes what this getter/setter/method aliases. This - * determines what things can be hoisted past this call, and if this - * call is movable what it can be hoisted past. + * Alias things that can modify the DOM but nothing else. Doing the + * call can't affect the behavior of any other function. */ - enum AliasSet { - /** - * Alias nothing: a constant value, getting it can't affect any other - * values, nothing can affect it. - */ - AliasNone, - - /** - * Alias things that can modify the DOM but nothing else. Doing the - * call can't affect the behavior of any other function. - */ - AliasDOMSets, - - /** - * Alias the world. Calling this can change arbitrary values anywhere - * in the system. Most things fall in this bucket. - */ - AliasEverything, - - /** Must be last. */ - AliasSetCount - }; - - bool needsOuterizedThisObject() const - { - return type() != Getter && type() != Setter; - } + AliasDOMSets, - bool isTypedMethodJitInfo() const - { - return isTypedMethod; - } + /** + * Alias the world. Calling this can change arbitrary values anywhere + * in the system. Most things fall in this bucket. + */ + AliasEverything, - OpType type() const - { - return OpType(type_); - } + /** Must be last. */ + AliasSetCount + }; - AliasSet aliasSet() const - { - return AliasSet(aliasSet_); - } + bool needsOuterizedThisObject() const { + return type() != Getter && type() != Setter; + } - JSValueType returnType() const - { - return JSValueType(returnType_); - } + bool isTypedMethodJitInfo() const { return isTypedMethod; } + + OpType type() const { return OpType(type_); } + + AliasSet aliasSet() const { return AliasSet(aliasSet_); } - union { - JSJitGetterOp getter; - JSJitSetterOp setter; - JSJitMethodOp method; - /** A DOM static method, used for Promise wrappers */ - JSNative staticMethod; - }; - - union { - uint16_t protoID; - js::jit::InlinableNative inlinableNative; - }; - - 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 - // fields before adding more members to this structure. + JSValueType returnType() const { return JSValueType(returnType_); } + + union { + JSJitGetterOp getter; + JSJitSetterOp setter; + JSJitMethodOp method; + /** A DOM static method, used for Promise wrappers */ + JSNative staticMethod; + JSNative ignoresReturnValueMethod; + }; + + static unsigned offsetOfIgnoresReturnValueNative() { + return offsetof(JSJitInfo, ignoresReturnValueMethod); + } + + union { + uint16_t protoID; + js::jit::InlinableNative inlinableNative; + }; + + 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 + // fields before adding more members to this structure. #define JITINFO_OP_TYPE_BITS 4 #define JITINFO_ALIAS_SET_BITS 4 #define JITINFO_RETURN_TYPE_BITS 8 #define JITINFO_SLOT_INDEX_BITS 10 - /** The OpType that says what sort of function we are. */ - uint32_t type_ : JITINFO_OP_TYPE_BITS; - - /** - * The alias set for this op. This is a _minimal_ alias set; in - * particular for a method it does not include whatever argument - * conversions might do. That's covered by argTypes and runtime - * analysis of the actual argument types being passed in. - */ - uint32_t aliasSet_ : JITINFO_ALIAS_SET_BITS; - - /** The return type tag. Might be JSVAL_TYPE_UNKNOWN. */ - uint32_t returnType_ : JITINFO_RETURN_TYPE_BITS; + /** The OpType that says what sort of function we are. */ + uint32_t type_ : JITINFO_OP_TYPE_BITS; - static_assert(OpTypeCount <= (1 << JITINFO_OP_TYPE_BITS), - "Not enough space for OpType"); - static_assert(AliasSetCount <= (1 << JITINFO_ALIAS_SET_BITS), - "Not enough space for AliasSet"); - static_assert((sizeof(JSValueType) * 8) <= JITINFO_RETURN_TYPE_BITS, - "Not enough space for JSValueType"); + /** + * The alias set for this op. This is a _minimal_ alias set; in + * particular for a method it does not include whatever argument + * conversions might do. That's covered by argTypes and runtime + * analysis of the actual argument types being passed in. + */ + uint32_t aliasSet_ : JITINFO_ALIAS_SET_BITS; + + /** The return type tag. Might be JSVAL_TYPE_UNKNOWN. */ + uint32_t returnType_ : JITINFO_RETURN_TYPE_BITS; + + static_assert(OpTypeCount <= (1 << JITINFO_OP_TYPE_BITS), + "Not enough space for OpType"); + static_assert(AliasSetCount <= (1 << JITINFO_ALIAS_SET_BITS), + "Not enough space for AliasSet"); + static_assert((sizeof(JSValueType) * 8) <= JITINFO_RETURN_TYPE_BITS, + "Not enough space for JSValueType"); #undef JITINFO_RETURN_TYPE_BITS #undef JITINFO_ALIAS_SET_BITS #undef JITINFO_OP_TYPE_BITS - /** Is op fallible? False in setters. */ - uint32_t isInfallible : 1; - - /** - * Is op movable? To be movable the op must - * not AliasEverything, but even that might - * not be enough (e.g. in cases when it can - * throw or is explicitly not movable). - */ - uint32_t isMovable : 1; - - /** - * Can op be dead-code eliminated? Again, this - * depends on whether the op can throw, in - * addition to the alias set. - */ - uint32_t isEliminatable : 1; - - // XXXbz should we have a JSValueType for the type of the member? - /** - * True if this is a getter that can always - * get the value from a slot of the "this" object. - */ - uint32_t isAlwaysInSlot : 1; + /** Is op fallible? False in setters. */ + uint32_t isInfallible : 1; - /** - * True if this is a getter that can sometimes (if the slot doesn't contain - * UndefinedValue()) get the value from a slot of the "this" object. - */ - uint32_t isLazilyCachedInSlot : 1; - - /** True if this is an instance of JSTypedMethodJitInfo. */ - uint32_t isTypedMethod : 1; - - /** - * If isAlwaysInSlot or isSometimesInSlot is true, - * the index of the slot to get the value from. - * Otherwise 0. - */ - uint32_t slotIndex : JITINFO_SLOT_INDEX_BITS; + /** + * Is op movable? To be movable the op must + * not AliasEverything, but even that might + * not be enough (e.g. in cases when it can + * throw or is explicitly not movable). + */ + uint32_t isMovable : 1; + + /** + * Can op be dead-code eliminated? Again, this + * depends on whether the op can throw, in + * addition to the alias set. + */ + uint32_t isEliminatable : 1; + + // XXXbz should we have a JSValueType for the type of the member? + /** + * True if this is a getter that can always + * get the value from a slot of the "this" object. + */ + uint32_t isAlwaysInSlot : 1; + + /** + * True if this is a getter that can sometimes (if the slot doesn't contain + * UndefinedValue()) get the value from a slot of the "this" object. + */ + uint32_t isLazilyCachedInSlot : 1; + + /** True if this is an instance of JSTypedMethodJitInfo. */ + uint32_t isTypedMethod : 1; + + /** + * If isAlwaysInSlot or isSometimesInSlot is true, + * the index of the slot to get the value from. + * Otherwise 0. + */ + uint32_t slotIndex : JITINFO_SLOT_INDEX_BITS; - static const size_t maxSlotIndex = (1 << JITINFO_SLOT_INDEX_BITS) - 1; + static const size_t maxSlotIndex = (1 << JITINFO_SLOT_INDEX_BITS) - 1; #undef JITINFO_SLOT_INDEX_BITS }; @@ -2488,67 +2409,60 @@ "verifying that there is no other way forward (better packing, " "smaller datatypes for fields, subclassing, etc.)."); -struct JSTypedMethodJitInfo -{ - // We use C-style inheritance here, rather than C++ style inheritance - // because not all compilers support brace-initialization for non-aggregate - // classes. Using C++ style inheritance and constructors instead of - // brace-initialization would also force the creation of static - // constructors (on some compilers) when JSJitInfo and JSTypedMethodJitInfo - // structures are declared. Since there can be several thousand of these - // structures present and we want to have roughly equivalent performance - // across a range of compilers, we do things manually. - JSJitInfo base; - - const JSJitInfo::ArgType* const argTypes; /* For a method, a list of sets of - types that the function - expects. This can be used, - for example, to figure out - when argument coercions can - have side-effects. */ +struct JSTypedMethodJitInfo { + // We use C-style inheritance here, rather than C++ style inheritance + // because not all compilers support brace-initialization for non-aggregate + // classes. Using C++ style inheritance and constructors instead of + // brace-initialization would also force the creation of static + // constructors (on some compilers) when JSJitInfo and JSTypedMethodJitInfo + // structures are declared. Since there can be several thousand of these + // structures present and we want to have roughly equivalent performance + // across a range of compilers, we do things manually. + JSJitInfo base; + + const JSJitInfo::ArgType* const argTypes; /* For a method, a list of sets of + types that the function + expects. This can be used, + for example, to figure out + when argument coercions can + have side-effects. */ }; namespace js { -static MOZ_ALWAYS_INLINE shadow::Function* -FunctionObjectToShadowFunction(JSObject* fun) -{ - MOZ_ASSERT(GetObjectClass(fun) == FunctionClassPtr); - return reinterpret_cast(fun); +static MOZ_ALWAYS_INLINE shadow::Function* FunctionObjectToShadowFunction( + JSObject* fun) { + MOZ_ASSERT(GetObjectClass(fun) == FunctionClassPtr); + return reinterpret_cast(fun); } -/* Statically asserted in jsfun.h. */ +/* Statically asserted in JSFunction.h. */ static const unsigned JS_FUNCTION_INTERPRETED_BITS = 0x0201; // Return whether the given function object is native. -static MOZ_ALWAYS_INLINE bool -FunctionObjectIsNative(JSObject* fun) -{ - return !(FunctionObjectToShadowFunction(fun)->flags & JS_FUNCTION_INTERPRETED_BITS); -} - -static MOZ_ALWAYS_INLINE JSNative -GetFunctionObjectNative(JSObject* fun) -{ - MOZ_ASSERT(FunctionObjectIsNative(fun)); - return FunctionObjectToShadowFunction(fun)->native; -} - -} // namespace js - -static MOZ_ALWAYS_INLINE const JSJitInfo* -FUNCTION_VALUE_TO_JITINFO(const JS::Value& v) -{ - MOZ_ASSERT(js::FunctionObjectIsNative(&v.toObject())); - return js::FunctionObjectToShadowFunction(&v.toObject())->jitinfo; -} - -static MOZ_ALWAYS_INLINE void -SET_JITINFO(JSFunction * func, const JSJitInfo* info) -{ - js::shadow::Function* fun = reinterpret_cast(func); - MOZ_ASSERT(!(fun->flags & js::JS_FUNCTION_INTERPRETED_BITS)); - fun->jitinfo = info; +static MOZ_ALWAYS_INLINE bool FunctionObjectIsNative(JSObject* fun) { + return !(FunctionObjectToShadowFunction(fun)->flags & + JS_FUNCTION_INTERPRETED_BITS); +} + +static MOZ_ALWAYS_INLINE JSNative GetFunctionObjectNative(JSObject* fun) { + MOZ_ASSERT(FunctionObjectIsNative(fun)); + return FunctionObjectToShadowFunction(fun)->native; +} + +} // namespace js + +static MOZ_ALWAYS_INLINE const JSJitInfo* FUNCTION_VALUE_TO_JITINFO( + const JS::Value& v) { + MOZ_ASSERT(js::FunctionObjectIsNative(&v.toObject())); + return js::FunctionObjectToShadowFunction(&v.toObject())->jitinfo; +} + +static MOZ_ALWAYS_INLINE void SET_JITINFO(JSFunction* func, + const JSJitInfo* info) { + js::shadow::Function* fun = reinterpret_cast(func); + MOZ_ASSERT(!(fun->flags & js::JS_FUNCTION_INTERPRETED_BITS)); + fun->jitinfo = info; } /* @@ -2556,19 +2470,18 @@ * eliminate Gecko's dependencies on it! */ -static MOZ_ALWAYS_INLINE jsid -JSID_FROM_BITS(size_t bits) -{ - jsid id; - JSID_BITS(id) = bits; - return id; +static MOZ_ALWAYS_INLINE jsid JSID_FROM_BITS(size_t bits) { + jsid id; + JSID_BITS(id) = bits; + return id; } namespace js { namespace detail { bool IdMatchesAtom(jsid id, JSAtom* atom); -} // namespace detail -} // namespace js +bool IdMatchesAtom(jsid id, JSString* atom); +} // namespace detail +} // namespace js /** * Must not be used on atoms that are representable as integer jsids. @@ -2591,49 +2504,44 @@ * Thus, it is only the rare third case which needs this function, which * handles any JSAtom* that is known not to be representable with an int jsid. */ -static MOZ_ALWAYS_INLINE jsid -NON_INTEGER_ATOM_TO_JSID(JSAtom* atom) -{ - MOZ_ASSERT(((size_t)atom & 0x7) == 0); - jsid id = JSID_FROM_BITS((size_t)atom); - MOZ_ASSERT(js::detail::IdMatchesAtom(id, atom)); - return id; -} - -/* All strings stored in jsids are atomized, but are not necessarily property names. */ -static MOZ_ALWAYS_INLINE bool -JSID_IS_ATOM(jsid id) -{ - return JSID_IS_STRING(id); -} - -static MOZ_ALWAYS_INLINE bool -JSID_IS_ATOM(jsid id, JSAtom* atom) -{ - return id == JSID_FROM_BITS((size_t)atom); -} - -static MOZ_ALWAYS_INLINE JSAtom* -JSID_TO_ATOM(jsid id) -{ - return (JSAtom*)JSID_TO_STRING(id); +static MOZ_ALWAYS_INLINE jsid NON_INTEGER_ATOM_TO_JSID(JSAtom* atom) { + MOZ_ASSERT(((size_t)atom & 0x7) == 0); + jsid id = JSID_FROM_BITS((size_t)atom); + MOZ_ASSERT(js::detail::IdMatchesAtom(id, atom)); + return id; +} + +static MOZ_ALWAYS_INLINE jsid NON_INTEGER_ATOM_TO_JSID(JSString* atom) { + MOZ_ASSERT(((size_t)atom & 0x7) == 0); + jsid id = JSID_FROM_BITS((size_t)atom); + MOZ_ASSERT(js::detail::IdMatchesAtom(id, atom)); + return id; +} + +/* All strings stored in jsids are atomized, but are not necessarily property + * names. */ +static MOZ_ALWAYS_INLINE bool JSID_IS_ATOM(jsid id) { + return JSID_IS_STRING(id); +} + +static MOZ_ALWAYS_INLINE bool JSID_IS_ATOM(jsid id, JSAtom* atom) { + return id == JSID_FROM_BITS((size_t)atom); +} + +static MOZ_ALWAYS_INLINE JSAtom* JSID_TO_ATOM(jsid id) { + return (JSAtom*)JSID_TO_STRING(id); } JS_STATIC_ASSERT(sizeof(jsid) == sizeof(void*)); namespace js { -static MOZ_ALWAYS_INLINE JS::Value -IdToValue(jsid id) -{ - if (JSID_IS_STRING(id)) - return JS::StringValue(JSID_TO_STRING(id)); - if (JSID_IS_INT(id)) - return JS::Int32Value(JSID_TO_INT(id)); - if (JSID_IS_SYMBOL(id)) - return JS::SymbolValue(JSID_TO_SYMBOL(id)); - MOZ_ASSERT(JSID_IS_VOID(id)); - return JS::UndefinedValue(); +static MOZ_ALWAYS_INLINE JS::Value IdToValue(jsid id) { + if (JSID_IS_STRING(id)) return JS::StringValue(JSID_TO_STRING(id)); + if (JSID_IS_INT(id)) return JS::Int32Value(JSID_TO_INT(id)); + if (JSID_IS_SYMBOL(id)) return JS::SymbolValue(JSID_TO_SYMBOL(id)); + MOZ_ASSERT(JSID_IS_VOID(id)); + return JS::UndefinedValue(); } /** @@ -2654,75 +2562,71 @@ */ struct ScriptEnvironmentPreparer { - struct Closure { - virtual bool operator()(JSContext* cx) = 0; - }; + struct Closure { + virtual bool operator()(JSContext* cx) = 0; + }; - virtual void invoke(JS::HandleObject scope, Closure& closure) = 0; + virtual void invoke(JS::HandleObject scope, Closure& closure) = 0; }; -extern JS_FRIEND_API(void) -PrepareScriptEnvironmentAndInvoke(JSContext* cx, JS::HandleObject scope, - ScriptEnvironmentPreparer::Closure& closure); +extern JS_FRIEND_API void PrepareScriptEnvironmentAndInvoke( + JSContext* cx, JS::HandleObject scope, + ScriptEnvironmentPreparer::Closure& closure); -JS_FRIEND_API(void) -SetScriptEnvironmentPreparer(JSContext* cx, ScriptEnvironmentPreparer* preparer); +JS_FRIEND_API void SetScriptEnvironmentPreparer( + JSContext* cx, ScriptEnvironmentPreparer* preparer); enum CTypesActivityType { - CTYPES_CALL_BEGIN, - CTYPES_CALL_END, - CTYPES_CALLBACK_BEGIN, - CTYPES_CALLBACK_END + CTYPES_CALL_BEGIN, + CTYPES_CALL_END, + CTYPES_CALLBACK_BEGIN, + CTYPES_CALLBACK_END }; -typedef void -(* CTypesActivityCallback)(JSContext* cx, CTypesActivityType type); +typedef void (*CTypesActivityCallback)(JSContext* cx, CTypesActivityType type); /** * Sets a callback that is run whenever js-ctypes is about to be used when * calling into C. */ -JS_FRIEND_API(void) -SetCTypesActivityCallback(JSContext* cx, CTypesActivityCallback cb); +JS_FRIEND_API void SetCTypesActivityCallback(JSContext* cx, + CTypesActivityCallback cb); -class MOZ_RAII JS_FRIEND_API(AutoCTypesActivityCallback) { - private: - JSContext* cx; - CTypesActivityCallback callback; - CTypesActivityType endType; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER - - public: - AutoCTypesActivityCallback(JSContext* cx, CTypesActivityType beginType, - CTypesActivityType endType - MOZ_GUARD_OBJECT_NOTIFIER_PARAM); - ~AutoCTypesActivityCallback() { - DoEndCallback(); - } - void DoEndCallback() { - if (callback) { - callback(cx, endType); - callback = nullptr; - } +class MOZ_RAII JS_FRIEND_API AutoCTypesActivityCallback { + private: + JSContext* cx; + CTypesActivityCallback callback; + CTypesActivityType endType; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + + public: + AutoCTypesActivityCallback(JSContext* cx, CTypesActivityType beginType, + CTypesActivityType endType + MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + ~AutoCTypesActivityCallback() { DoEndCallback(); } + void DoEndCallback() { + if (callback) { + callback(cx, endType); + callback = nullptr; } + } }; // Abstract base class for objects that build allocation metadata for JavaScript // values. struct AllocationMetadataBuilder { - 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; - } + // 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; + } }; /** @@ -2730,19 +2634,19 @@ * compartment, which may return a metadata object to associate with the * object. */ -JS_FRIEND_API(void) -SetAllocationMetadataBuilder(JSContext* cx, const AllocationMetadataBuilder *callback); +JS_FRIEND_API void SetAllocationMetadataBuilder( + JSContext* cx, const AllocationMetadataBuilder* callback); /** Get the metadata associated with an object. */ -JS_FRIEND_API(JSObject*) -GetAllocationMetadata(JSObject* obj); +JS_FRIEND_API JSObject* GetAllocationMetadata(JSObject* obj); -JS_FRIEND_API(bool) -GetElementsWithAdder(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver, - uint32_t begin, uint32_t end, js::ElementAdder* adder); +JS_FRIEND_API bool GetElementsWithAdder(JSContext* cx, JS::HandleObject obj, + JS::HandleObject receiver, + uint32_t begin, uint32_t end, + js::ElementAdder* adder); -JS_FRIEND_API(bool) -ForwardToNative(JSContext* cx, JSNative native, const JS::CallArgs& args); +JS_FRIEND_API bool ForwardToNative(JSContext* cx, JSNative native, + const JS::CallArgs& args); /** * Helper function for HTMLDocument and HTMLFormElement. @@ -2764,26 +2668,83 @@ * * Implemented in proxy/BaseProxyHandler.cpp. */ -JS_FRIEND_API(bool) -SetPropertyIgnoringNamedGetter(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::HandleValue v, JS::HandleValue receiver, - JS::Handle ownDesc, - JS::ObjectOpResult& result); - -JS_FRIEND_API(void) -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) -ExecuteInGlobalAndReturnScope(JSContext* cx, JS::HandleObject obj, JS::HandleScript script, - JS::MutableHandleObject scope); +JS_FRIEND_API bool SetPropertyIgnoringNamedGetter( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, + JS::HandleValue receiver, JS::Handle ownDesc, + JS::ObjectOpResult& result); + +// This function is for one specific use case, please don't use this for +// anything else! +extern JS_FRIEND_API bool ExecuteInGlobalAndReturnScope( + JSContext* cx, JS::HandleObject obj, JS::HandleScript script, + JS::MutableHandleObject scope); + +// These functions are provided for the JSM component loader in Gecko. +// +// A 'JSMEnvironment' refers to an environment chain constructed for JSM loading +// in a shared global. Internally it is a NonSyntacticVariablesObject with a +// corresponding extensible LexicalEnvironmentObject that is accessible by +// JS_ExtensibleLexicalEnvironment. The |this| value of that lexical environment +// is the NSVO itself. +// +// Normal global environment (ES6): JSM "global" environment: +// +// * - extensible lexical environment +// | (code runs in this environment; +// | `let/const` bindings go here) +// | +// * - JSMEnvironment (=== `this`) +// | (`var` bindings go here) +// | +// * - extensible lexical environment * - extensible lexical environment +// | (code runs in this environment; | (empty) +// | `let/const` bindings go here) | +// | | +// * - actual global (=== `this`) * - shared JSM global +// (var bindings go here; and (Object, Math, etc. live here) +// Object, Math, etc. live here) + +// Allocate a new environment in current compartment that is compatible with JSM +// shared loading. +extern JS_FRIEND_API JSObject* NewJSMEnvironment(JSContext* cx); + +// Execute the given script (copied into compartment if necessary) in the given +// JSMEnvironment. The script must have been compiled for hasNonSyntacticScope. +// The |jsmEnv| must have been previously allocated by NewJSMEnvironment. +// +// NOTE: The associated extensible lexical environment is reused. +extern JS_FRIEND_API bool ExecuteInJSMEnvironment(JSContext* cx, + JS::HandleScript script, + JS::HandleObject jsmEnv); + +// Additionally, target objects may be specified as required by the Gecko +// subscript loader. These are wrapped in non-syntactic WithEnvironments and +// temporarily placed on environment chain. +// +// See also: JS::CloneAndExecuteScript(...) +extern JS_FRIEND_API bool ExecuteInJSMEnvironment( + JSContext* cx, JS::HandleScript script, JS::HandleObject jsmEnv, + JS::AutoObjectVector& targetObj); + +// Used by native methods to determine the JSMEnvironment of caller if possible +// by looking at stack frames. Returns nullptr if top frame isn't a scripted +// caller in a JSM. +// +// NOTE: This may find NonSyntacticVariablesObject generated by other embedding +// such as a Gecko FrameScript. Caller can check the compartment if needed. +extern JS_FRIEND_API JSObject* GetJSMEnvironmentOfScriptedCaller(JSContext* cx); + +// Determine if obj is a JSMEnvironment +// +// NOTE: This may return true for an NonSyntacticVariablesObject generated by +// other embedding such as a Gecko FrameScript. Caller can check compartment. +extern JS_FRIEND_API bool IsJSMEnvironment(JSObject* obj); #if defined(XP_WIN) && defined(_WIN64) // Parameters use void* types to avoid #including windows.h. The return value of // this function is returned from the exception handler. -typedef long -(*JitExceptionHandler)(void* exceptionRecord, // PEXECTION_RECORD - void* context); // PCONTEXT +typedef long (*JitExceptionHandler)(void* exceptionRecord, // PEXECTION_RECORD + void* context); // PCONTEXT /** * Windows uses "structured exception handling" to handle faults. When a fault @@ -2804,19 +2765,10 @@ * Gecko must call SetJitExceptionFilter before any JIT code is compiled and * only once per process. */ -extern JS_FRIEND_API(void) -SetJitExceptionHandler(JitExceptionHandler handler); +extern JS_FRIEND_API void SetJitExceptionHandler(JitExceptionHandler handler); #endif /** - * 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*) -GetNearestEnclosingWithEnvironmentObjectForFunction(JSFunction* fun); - -/** * Get the first SavedFrame object in this SavedFrame stack whose principals are * subsumed by the cx's principals. If there is no such frame, return nullptr. * @@ -2824,14 +2776,25 @@ * * The savedFrame and cx do not need to be in the same compartment. */ -extern JS_FRIEND_API(JSObject*) -GetFirstSubsumedSavedFrame(JSContext* cx, JS::HandleObject savedFrame, JS::SavedFrameSelfHosted selfHosted); +extern JS_FRIEND_API JSObject* GetFirstSubsumedSavedFrame( + JSContext* cx, JS::HandleObject savedFrame, + JS::SavedFrameSelfHosted selfHosted); -extern JS_FRIEND_API(bool) -ReportIsNotFunction(JSContext* cx, JS::HandleValue v); +/** + * Get the first SavedFrame object in this SavedFrame stack whose principals are + * subsumed by the given |principals|. If there is no such frame, return + * nullptr. + * + * Do NOT pass a non-SavedFrame object here. + */ +extern JS_FRIEND_API JSObject* GetFirstSubsumedSavedFrame( + JSContext* cx, JSPrincipals* principals, JS::HandleObject savedFrame, + JS::SavedFrameSelfHosted selfHosted); -extern JS_FRIEND_API(JSObject*) -ConvertArgsToArray(JSContext* cx, const JS::CallArgs& args); +extern JS_FRIEND_API bool ReportIsNotFunction(JSContext* cx, JS::HandleValue v); + +extern JS_FRIEND_API JSObject* ConvertArgsToArray(JSContext* cx, + const JS::CallArgs& args); /** * Window and WindowProxy @@ -2853,215 +2816,114 @@ * Tell the JS engine which Class is used for WindowProxy objects. Used by the * functions below. */ -extern JS_FRIEND_API(void) -SetWindowProxyClass(JSContext* cx, const Class* clasp); +extern JS_FRIEND_API void SetWindowProxyClass(JSContext* cx, + const Class* clasp); /** * Associates a WindowProxy with a Window (global object). `windowProxy` must * have the Class set by SetWindowProxyClass. */ -extern JS_FRIEND_API(void) -SetWindowProxy(JSContext* cx, JS::HandleObject global, JS::HandleObject windowProxy); +extern JS_FRIEND_API void SetWindowProxy(JSContext* cx, JS::HandleObject global, + JS::HandleObject windowProxy); namespace detail { -JS_FRIEND_API(bool) -IsWindowSlow(JSObject* obj); +JS_FRIEND_API bool IsWindowSlow(JSObject* obj); + +JS_FRIEND_API JSObject* ToWindowProxyIfWindowSlow(JSObject* obj); -} // namespace detail +} // namespace detail /** * Returns true iff `obj` is a global object with an associated WindowProxy, * see SetWindowProxy. */ -inline bool -IsWindow(JSObject* obj) -{ - if (GetObjectClass(obj)->flags & JSCLASS_IS_GLOBAL) - return detail::IsWindowSlow(obj); - return false; +inline bool IsWindow(JSObject* obj) { + if (GetObjectClass(obj)->flags & JSCLASS_IS_GLOBAL) + return detail::IsWindowSlow(obj); + return false; } /** * Returns true iff `obj` has the WindowProxy Class (see SetWindowProxyClass). */ -JS_FRIEND_API(bool) -IsWindowProxy(JSObject* obj); +JS_FRIEND_API bool IsWindowProxy(JSObject* obj); /** * If `obj` is a Window, get its associated WindowProxy (or a CCW or dead * wrapper if the page was navigated away from), else return `obj`. This * function is infallible and never returns nullptr. */ -extern JS_FRIEND_API(JSObject*) -ToWindowProxyIfWindow(JSObject* obj); +MOZ_ALWAYS_INLINE JSObject* ToWindowProxyIfWindow(JSObject* obj) { + if (GetObjectClass(obj)->flags & JSCLASS_IS_GLOBAL) + return detail::ToWindowProxyIfWindowSlow(obj); + return obj; +} /** * If `obj` is a WindowProxy, get its associated Window (the compartment's * global), else return `obj`. This function is infallible and never returns * nullptr. */ -extern JS_FRIEND_API(JSObject*) -ToWindowIfWindowProxy(JSObject* obj); - -} /* namespace js */ - -class NativeProfiler -{ - public: - virtual ~NativeProfiler() {}; - virtual void sampleNative(void* addr, uint32_t size) = 0; - virtual void removeNative(void* addr) = 0; - virtual void reset() = 0; -}; - -class GCHeapProfiler -{ - public: - virtual ~GCHeapProfiler() {}; - virtual void sampleTenured(void* addr, uint32_t size) = 0; - virtual void sampleNursery(void* addr, uint32_t size) = 0; - virtual void markTenuredStart() = 0; - virtual void markTenured(void* addr) = 0; - virtual void sweepTenured() = 0; - virtual void sweepNursery() = 0; - virtual void moveNurseryToTenured(void* addrOld, void* addrNew) = 0; - virtual void reset() = 0; -}; - -class MemProfiler -{ - static mozilla::Atomic sActiveProfilerCount; - static JS_FRIEND_DATA(NativeProfiler*) sNativeProfiler; - - static GCHeapProfiler* GetGCHeapProfiler(void* addr); - static GCHeapProfiler* GetGCHeapProfiler(JSRuntime* runtime); - - static NativeProfiler* GetNativeProfiler() { - return sNativeProfiler; - } - - GCHeapProfiler* mGCHeapProfiler; - JSRuntime* mRuntime; - - public: - explicit MemProfiler(JSRuntime* aRuntime) : mGCHeapProfiler(nullptr), mRuntime(aRuntime) {} - - JS_FRIEND_API(void) start(GCHeapProfiler* aGCHeapProfiler); - JS_FRIEND_API(void) stop(); - - GCHeapProfiler* getGCHeapProfiler() const { - return mGCHeapProfiler; - } +extern JS_FRIEND_API JSObject* ToWindowIfWindowProxy(JSObject* obj); - static MOZ_ALWAYS_INLINE bool enabled() { - return sActiveProfilerCount > 0; - } - - static JS_FRIEND_API(MemProfiler*) GetMemProfiler(JSContext* context); - - static void SetNativeProfiler(NativeProfiler* aProfiler) { - sNativeProfiler = aProfiler; - } - - static MOZ_ALWAYS_INLINE void SampleNative(void* addr, uint32_t size) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - NativeProfiler* profiler = GetNativeProfiler(); - if (profiler) - profiler->sampleNative(addr, size); - } - - static MOZ_ALWAYS_INLINE void SampleTenured(void* addr, uint32_t size) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - GCHeapProfiler* profiler = GetGCHeapProfiler(addr); - if (profiler) - profiler->sampleTenured(addr, size); - } - - static MOZ_ALWAYS_INLINE void SampleNursery(void* addr, uint32_t size) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - GCHeapProfiler* profiler = GetGCHeapProfiler(addr); - if (profiler) - profiler->sampleNursery(addr, size); - } - - static MOZ_ALWAYS_INLINE void RemoveNative(void* addr) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - NativeProfiler* profiler = GetNativeProfiler(); - if (profiler) - profiler->removeNative(addr); - } - - static MOZ_ALWAYS_INLINE void MarkTenuredStart(JSRuntime* runtime) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - GCHeapProfiler* profiler = GetGCHeapProfiler(runtime); - if (profiler) - profiler->markTenuredStart(); - } - - static MOZ_ALWAYS_INLINE void MarkTenured(void* addr) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - GCHeapProfiler* profiler = GetGCHeapProfiler(addr); - if (profiler) - profiler->markTenured(addr); - } - - static MOZ_ALWAYS_INLINE void SweepTenured(JSRuntime* runtime) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - GCHeapProfiler* profiler = GetGCHeapProfiler(runtime); - if (profiler) - profiler->sweepTenured(); - } - - static MOZ_ALWAYS_INLINE void SweepNursery(JSRuntime* runtime) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; - - GCHeapProfiler* profiler = GetGCHeapProfiler(runtime); - if (profiler) - profiler->sweepNursery(); - } - - static MOZ_ALWAYS_INLINE void MoveNurseryToTenured(void* addrOld, void* addrNew) { - JS::AutoSuppressGCAnalysis nogc; - - if (MOZ_LIKELY(!enabled())) - return; +// Create and add the Intl.MozDateTimeFormat constructor function to the +// provided object. +// +// This custom date/time formatter constructor gives users the ability +// to specify a custom format pattern. This pattern is passed *directly* +// to ICU with NO SYNTAX PARSING OR VALIDATION WHATSOEVER. ICU appears to +// have a a modicum of testing of this, and it won't fall over completely +// if passed bad input. But the current behavior is entirely under-specified +// and emphatically not shippable on the web, and it *must* be fixed before +// this functionality can be exposed in the real world. (There are also some +// questions about whether the format exposed here is the *right* one to +// standardize, that will also need to be resolved to ship this.) +extern bool AddMozDateTimeFormatConstructor(JSContext* cx, + JS::Handle intl); + +// Create and add the Intl.RelativeTimeFormat constructor function to the +// provided object. This function throws if called more than once per +// realm/global object. +extern bool AddRelativeTimeFormatConstructor(JSContext* cx, + JS::Handle intl); + +class MOZ_STACK_CLASS JS_FRIEND_API AutoAssertNoContentJS { + public: + explicit AutoAssertNoContentJS(JSContext* cx); + ~AutoAssertNoContentJS(); + + private: + JSContext* context_; + bool prevAllowContentJS_; +}; + +// Turn on assertions so that we assert that +// !comp->validAccessPtr || *comp->validAccessPtr +// is true for every |comp| that we run JS code in. The compartment's +// validAccessPtr is set via SetCompartmentValidAccessPtr. +extern JS_FRIEND_API void EnableAccessValidation(JSContext* cx, bool enabled); + +// See EnableAccessValidation above. The caller must guarantee that accessp will +// live at least as long as |global| is alive. The JS engine reads accessp from +// threads that are allowed to run code on |global|, so all changes to *accessp +// should be made from whichever thread owns |global| at a given time. +extern JS_FRIEND_API void SetCompartmentValidAccessPtr(JSContext* cx, + JS::HandleObject global, + bool* accessp); + +// If the JS engine wants to block so that other cooperative threads can run, it +// will call the yield callback. It may do this if it needs to access a +// ZoneGroup that is held by another thread (such as the system zone group). +typedef void (*YieldCallback)(JSContext* cx); + +extern JS_FRIEND_API void SetCooperativeYieldCallback(JSContext* cx, + YieldCallback callback); + +// Returns true if the system zone is available (i.e., if no cooperative +// contexts are using it now). +extern JS_FRIEND_API bool SystemZoneAvailable(JSContext* cx); - GCHeapProfiler* profiler = GetGCHeapProfiler(addrOld); - if (profiler) - profiler->moveNurseryToTenured(addrOld, addrNew); - } -}; +} /* namespace js */ #endif /* jsfriendapi_h */ 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 @@ -27,107 +27,106 @@ * requested are available as data values after calling Stop(). The * object may be reused for many measurements. */ -class JS_FRIEND_API(PerfMeasurement) -{ - protected: - // Implementation-specific data, if any. - void* impl; - - public: - /* - * Events that may be measured. Taken directly from the list of - * "generalized hardware performance event types" in the Linux - * perf_event API, plus some of the "software events". - */ - enum EventMask { - CPU_CYCLES = 0x00000001, - INSTRUCTIONS = 0x00000002, - CACHE_REFERENCES = 0x00000004, - CACHE_MISSES = 0x00000008, - BRANCH_INSTRUCTIONS = 0x00000010, - BRANCH_MISSES = 0x00000020, - BUS_CYCLES = 0x00000040, - PAGE_FAULTS = 0x00000080, - MAJOR_PAGE_FAULTS = 0x00000100, - CONTEXT_SWITCHES = 0x00000200, - CPU_MIGRATIONS = 0x00000400, - - ALL = 0x000007ff, - NUM_MEASURABLE_EVENTS = 11 - }; - - /* - * Bitmask of events that will be measured when this object is - * active (between Start() and Stop()). This may differ from the - * bitmask passed to the constructor if the platform does not - * support measuring all of the requested events. - */ - const EventMask eventsMeasured; - - /* - * Counters for each measurable event. - * Immediately after one of these objects is created, all of the - * counters for enabled events will be zero, and all of the - * counters for disabled events will be uint64_t(-1). - */ - uint64_t cpu_cycles; - uint64_t instructions; - uint64_t cache_references; - uint64_t cache_misses; - uint64_t branch_instructions; - uint64_t branch_misses; - uint64_t bus_cycles; - uint64_t page_faults; - uint64_t major_page_faults; - uint64_t context_switches; - uint64_t cpu_migrations; - - /* - * Prepare to measure the indicated set of events. If not all of - * the requested events can be measured on the current platform, - * then the eventsMeasured bitmask will only include the subset of - * |toMeasure| corresponding to the events that can be measured. - */ - explicit PerfMeasurement(EventMask toMeasure); - - /* Done with this set of measurements, tear down OS-level state. */ - ~PerfMeasurement(); - - /* Start a measurement cycle. */ - void start(); - - /* - * End a measurement cycle, and for each enabled counter, add the - * number of measured events of that type to the appropriate - * visible variable. - */ - void stop(); - - /* Reset all enabled counters to zero. */ - void reset(); - - /* - * True if this platform supports measuring _something_, i.e. it's - * not using the stub implementation. - */ - static bool canMeasureSomething(); +class JS_FRIEND_API PerfMeasurement { + protected: + // Implementation-specific data, if any. + void* impl; + + public: + /* + * Events that may be measured. Taken directly from the list of + * "generalized hardware performance event types" in the Linux + * perf_event API, plus some of the "software events". + */ + enum EventMask { + CPU_CYCLES = 0x00000001, + INSTRUCTIONS = 0x00000002, + CACHE_REFERENCES = 0x00000004, + CACHE_MISSES = 0x00000008, + BRANCH_INSTRUCTIONS = 0x00000010, + BRANCH_MISSES = 0x00000020, + BUS_CYCLES = 0x00000040, + PAGE_FAULTS = 0x00000080, + MAJOR_PAGE_FAULTS = 0x00000100, + CONTEXT_SWITCHES = 0x00000200, + CPU_MIGRATIONS = 0x00000400, + + ALL = 0x000007ff, + NUM_MEASURABLE_EVENTS = 11 + }; + + /* + * Bitmask of events that will be measured when this object is + * active (between Start() and Stop()). This may differ from the + * bitmask passed to the constructor if the platform does not + * support measuring all of the requested events. + */ + const EventMask eventsMeasured; + + /* + * Counters for each measurable event. + * Immediately after one of these objects is created, all of the + * counters for enabled events will be zero, and all of the + * counters for disabled events will be uint64_t(-1). + */ + uint64_t cpu_cycles; + uint64_t instructions; + uint64_t cache_references; + uint64_t cache_misses; + uint64_t branch_instructions; + uint64_t branch_misses; + uint64_t bus_cycles; + uint64_t page_faults; + uint64_t major_page_faults; + uint64_t context_switches; + uint64_t cpu_migrations; + + /* + * Prepare to measure the indicated set of events. If not all of + * the requested events can be measured on the current platform, + * then the eventsMeasured bitmask will only include the subset of + * |toMeasure| corresponding to the events that can be measured. + */ + explicit PerfMeasurement(EventMask toMeasure); + + /* Done with this set of measurements, tear down OS-level state. */ + ~PerfMeasurement(); + + /* Start a measurement cycle. */ + void start(); + + /* + * End a measurement cycle, and for each enabled counter, add the + * number of measured events of that type to the appropriate + * visible variable. + */ + void stop(); + + /* Reset all enabled counters to zero. */ + void reset(); + + /* + * True if this platform supports measuring _something_, i.e. it's + * not using the stub implementation. + */ + static bool canMeasureSomething(); }; /* Inject a Javascript wrapper around the above C++ class into the * Javascript object passed as an argument (this will normally be a * global object). The JS-visible API is identical to the C++ API. */ -extern JS_FRIEND_API(JSObject*) - RegisterPerfMeasurement(JSContext* cx, JS::HandleObject global); +extern JS_FRIEND_API JSObject* RegisterPerfMeasurement(JSContext* cx, + JS::HandleObject global); /* * Given a Value which contains an instance of the aforementioned * wrapper class, extract the C++ object. Returns nullptr if the * Value is not an instance of the wrapper. */ -extern JS_FRIEND_API(PerfMeasurement*) - ExtractPerfMeasurement(const Value& wrapper); +extern JS_FRIEND_API PerfMeasurement* ExtractPerfMeasurement( + const Value& wrapper); -} // namespace JS +} // namespace JS #endif /* perf_jsperf_h */ 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 @@ -1,66 +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 jsprf_h -#define jsprf_h - -/* -** API for PR printf like routines. Supports the following formats -** %d - decimal -** %u - unsigned decimal -** %x - unsigned hex -** %X - unsigned uppercase hex -** %o - unsigned octal -** %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 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, ...) - MOZ_FORMAT_PRINTF(1, 2); - -/* -** Free the memory allocated, for the caller, by JS_smprintf -*/ -extern JS_PUBLIC_API(void) JS_smprintf_free(char* mem); - -/* -** "append" sprintf into a malloc'd buffer. "last" is the last value of -** the malloc'd buffer. sprintf will append data to the end of last, -** growing it as necessary using realloc. If last is nullptr, JS_sprintf_append -** 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, ...) - MOZ_FORMAT_PRINTF(2, 3); - -/* -** va_list forms of the above. -*/ -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); - -#endif /* jsprf_h */ 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 @@ -1,129 +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 jsprototypes_h -#define jsprototypes_h - -/* A higher-order macro for enumerating all JSProtoKey values. */ -/* - * Consumers define macros as follows: - * macro(name, code, init, clasp) - * name: The canonical name of the class. - * code: The enumerator code. There are part of the XDR API, and must not change. - * init: Initialization function. These are |extern "C";|, and clients should use - * |extern "C" {}| as appropriate when using this macro. - * clasp: The JSClass for this object, or "dummy" if it doesn't exist. - * - * - * Consumers wishing to iterate over all the JSProtoKey values, can use - * JS_FOR_EACH_PROTOTYPE. However, there are certain values that don't correspond - * to real constructors, like Null or constructors that are disabled via - * preprocessor directives. We still need to include these in the JSProtoKey list - * in order to maintain binary XDR compatibility, but we need to provide a tool - * to handle them differently. JS_FOR_PROTOTYPES fills this niche. - * - * Consumers pass two macros to JS_FOR_PROTOTYPES - |real| and |imaginary|. The - * former is invoked for entries that have real client-exposed constructors, and - * the latter is called for the rest. Consumers that don't care about this - * distinction can simply pass the same macro to both, which is exactly what - * JS_FOR_EACH_PROTOTYPE does. - */ - -#define CLASP(name) (&name##Class) -#define OCLASP(name) (&name##Object::class_) -#define TYPED_ARRAY_CLASP(type) (&TypedArrayObject::classes[Scalar::type]) -#define ERROR_CLASP(type) (&ErrorObject::classes[type]) - -#ifdef EXPOSE_INTL_API -#define IF_INTL(real,imaginary) real -#else -#define IF_INTL(real,imaginary) imaginary -#endif - -#ifdef ENABLE_BINARYDATA -#define IF_BDATA(real,imaginary) real -#else -#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)) \ - real(Function, 2, InitViaClassSpec, &JSFunction::class_) \ - real(Array, 3, InitViaClassSpec, OCLASP(Array)) \ - real(Boolean, 4, InitBooleanClass, OCLASP(Boolean)) \ - real(JSON, 5, InitJSONClass, CLASP(JSON)) \ - real(Date, 6, InitViaClassSpec, OCLASP(Date)) \ - real(Math, 7, InitMathClass, CLASP(Math)) \ - real(Number, 8, InitNumberClass, OCLASP(Number)) \ - real(String, 9, InitStringClass, OCLASP(String)) \ - real(RegExp, 10, InitViaClassSpec, OCLASP(RegExp)) \ - real(Error, 11, InitViaClassSpec, ERROR_CLASP(JSEXN_ERR)) \ - real(InternalError, 12, InitViaClassSpec, ERROR_CLASP(JSEXN_INTERNALERR)) \ - real(EvalError, 13, InitViaClassSpec, ERROR_CLASP(JSEXN_EVALERR)) \ - real(RangeError, 14, InitViaClassSpec, ERROR_CLASP(JSEXN_RANGEERR)) \ - real(ReferenceError, 15, InitViaClassSpec, ERROR_CLASP(JSEXN_REFERENCEERR)) \ - 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(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) - -#endif /* jsprototypes_h */ 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 @@ -16,455 +16,160 @@ #include "mozilla/LinkedList.h" #include "mozilla/PodOperations.h" -#include "jsprototypes.h" #include "jstypes.h" +#include "js/ProtoKey.h" +#include "js/Result.h" #include "js/TraceKind.h" #include "js/TypeDecls.h" #if defined(JS_GC_ZEAL) || defined(DEBUG) -# define JSGC_HASH_TABLE_CHECKS +#define JSGC_HASH_TABLE_CHECKS #endif namespace JS { -class AutoIdVector; -class CallArgs; - template -class Rooted; +class AutoVector; +using AutoIdVector = AutoVector; +using AutoValueVector = AutoVector; +using AutoObjectVector = AutoVector; -class JS_FRIEND_API(CompileOptions); -class JS_FRIEND_API(ReadOnlyCompileOptions); -class JS_FRIEND_API(OwningCompileOptions); -class JS_FRIEND_API(TransitiveCompileOptions); -class JS_PUBLIC_API(CompartmentOptions); - -struct RootingContext; -class Value; -struct Zone; - -namespace shadow { -struct Runtime; -} // namespace shadow +class CallArgs; -} // namespace JS +class JS_FRIEND_API CompileOptions; +class JS_FRIEND_API ReadOnlyCompileOptions; +class JS_FRIEND_API OwningCompileOptions; +class JS_FRIEND_API TransitiveCompileOptions; +class JS_PUBLIC_API CompartmentOptions; -namespace js { -class RootLists; -} // namespace js - -/* - * Run-time version enumeration. For compile-time version checking, please use - * the JS_HAS_* macros in jsversion.h, or use MOZJS_MAJOR_VERSION, - * MOZJS_MINOR_VERSION, MOZJS_PATCH_VERSION, and MOZJS_ALPHA definitions. - */ -enum JSVersion { - JSVERSION_ECMA_3 = 148, - JSVERSION_1_6 = 160, - JSVERSION_1_7 = 170, - JSVERSION_1_8 = 180, - JSVERSION_ECMA_5 = 185, - JSVERSION_DEFAULT = 0, - JSVERSION_UNKNOWN = -1, - JSVERSION_LATEST = JSVERSION_ECMA_5 -}; +} // namespace JS /* Result of typeof operator enumeration. */ enum JSType { - JSTYPE_VOID, /* undefined */ - JSTYPE_OBJECT, /* object */ - JSTYPE_FUNCTION, /* function */ - JSTYPE_STRING, /* string */ - JSTYPE_NUMBER, /* number */ - JSTYPE_BOOLEAN, /* boolean */ - JSTYPE_NULL, /* null */ - JSTYPE_SYMBOL, /* symbol */ - JSTYPE_LIMIT + JSTYPE_UNDEFINED, /* undefined */ + JSTYPE_OBJECT, /* object */ + JSTYPE_FUNCTION, /* function */ + JSTYPE_STRING, /* string */ + JSTYPE_NUMBER, /* number */ + JSTYPE_BOOLEAN, /* boolean */ + JSTYPE_NULL, /* null */ + JSTYPE_SYMBOL, /* symbol */ + JSTYPE_LIMIT }; /* Dense index into cached prototypes and class atoms for standard objects. */ enum JSProtoKey { -#define PROTOKEY_AND_INITIALIZER(name,code,init,clasp) JSProto_##name = code, - JS_FOR_EACH_PROTOTYPE(PROTOKEY_AND_INITIALIZER) +#define PROTOKEY_AND_INITIALIZER(name, init, clasp) JSProto_##name, + JS_FOR_EACH_PROTOTYPE(PROTOKEY_AND_INITIALIZER) #undef PROTOKEY_AND_INITIALIZER - JSProto_LIMIT + JSProto_LIMIT }; /* Struct forward declarations. */ struct JSClass; -struct JSCompartment; -struct JSCrossCompartmentCall; class JSErrorReport; struct JSExceptionState; struct JSFunctionSpec; struct JSLocaleCallbacks; -struct JSObjectMap; struct JSPrincipals; -struct JSPropertyName; struct JSPropertySpec; -struct JSRuntime; struct JSSecurityCallbacks; struct JSStructuredCloneCallbacks; struct JSStructuredCloneReader; struct JSStructuredCloneWriter; -class JS_PUBLIC_API(JSTracer); +class JS_PUBLIC_API JSTracer; class JSFlatString; -typedef bool (*JSInitCallback)(void); +typedef bool (*JSInitCallback)(void); -template struct JSConstScalarSpec; +template +struct JSConstScalarSpec; typedef JSConstScalarSpec JSConstDoubleSpec; typedef JSConstScalarSpec JSConstIntegerSpec; -/* - * 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 { namespace gc { class AutoTraceSession; class StoreBuffer; -} // namespace gc +} // namespace gc + +class CooperatingContext; + +inline JSCompartment* GetContextCompartment(const JSContext* cx); +inline JS::Zone* GetContextZone(const JSContext* cx); // Whether the current thread is permitted access to any part of the specified // runtime or zone. -JS_FRIEND_API(bool) -CurrentThreadCanAccessRuntime(const JSRuntime* rt); +JS_FRIEND_API bool CurrentThreadCanAccessRuntime(const JSRuntime* rt); #ifdef DEBUG -JS_FRIEND_API(bool) -CurrentThreadIsPerformingGC(); +JS_FRIEND_API bool CurrentThreadIsPerformingGC(); #endif -} // namespace js +} // namespace js namespace JS { -class JS_PUBLIC_API(AutoEnterCycleCollection); -class JS_PUBLIC_API(AutoAssertOnBarrier); -struct JS_PUBLIC_API(PropertyDescriptor); +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) - CycleCollecting // in the "Unlink" phase of cycle collection -}; - -namespace shadow { - -struct Runtime -{ - 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 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); - } - - protected: - void setGCStoreBufferPtr(js::gc::StoreBuffer* storeBuffer) { - gcStoreBufferPtr_ = storeBuffer; - } -}; - -} /* 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::RootingContext* cx, ptrdiff_t tag); - - ~AutoGCRooter() { - MOZ_ASSERT(this == *stackTop); - *stackTop = down; - } - - /* Implemented in gc/RootMarking.cpp. */ - inline void trace(JSTracer* trc); - static void traceAll(JSTracer* trc); - static void traceAllWrappers(JSTracer* trc); - - protected: - AutoGCRooter * const down; - - /* - * Discriminates actual subclass of this being used. If non-negative, the - * subclass roots an array of values of the length stored in this field. - * If negative, meaning is indicated by the corresponding value in the enum - * below. Any other negative value indicates some deeper problem such as - * memory corruption. - */ - ptrdiff_t tag_; - - enum { - VALARRAY = -2, /* js::AutoValueArray */ - PARSER = -3, /* js::frontend::Parser */ - VALVECTOR = -10, /* js::AutoValueVector */ - IDVECTOR = -11, /* js::AutoIdVector */ - OBJVECTOR = -14, /* js::AutoObjectVector */ - IONMASM = -19, /* js::jit::MacroAssembler */ - WRAPVECTOR = -20, /* js::AutoWrapperVector */ - WRAPPER = -21, /* js::AutoWrapperRooter */ - CUSTOM = -26 /* js::CustomAutoRooter */ - }; - - static ptrdiff_t GetTag(const Value& value) { return VALVECTOR; } - static ptrdiff_t GetTag(const jsid& id) { return IDVECTOR; } - static ptrdiff_t GetTag(JSObject* obj) { return OBJVECTOR; } - - private: - AutoGCRooter ** const stackTop; - - /* No copy or assignment semantics. */ - AutoGCRooter(AutoGCRooter& ida) = delete; - 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 { - -class ExclusiveContext; - -/* - * This list enumerates the different types of conceptual stacks we have in - * SpiderMonkey. In reality, they all share the C stack, but we allow different - * stack limits depending on the type of code running. - */ -enum StackKind -{ - StackForSystemCode, // C++, such as the GC, running on behalf of the VM. - StackForTrustedScript, // Script running with trusted principals. - StackForUntrustedScript, // Script running with untrusted principals. - StackKindCount + 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) + CycleCollecting // in the "Unlink" phase of cycle collection }; -using RootedListHeads = mozilla::EnumeratedArray*>; +JS_PUBLIC_API HeapState CurrentThreadHeapState(); -// Abstracts JS rooting mechanisms so they can be shared between the JSContext -// and JSRuntime. -class RootLists -{ - // Stack GC roots for Rooted GC heap pointers. - RootedListHeads stackRoots_; - template friend class JS::Rooted; - - // 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) { - for (auto& stackRootPtr : stackRoots_) - stackRootPtr = nullptr; - } - - ~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(); +static inline bool CurrentThreadIsHeapBusy() { + return CurrentThreadHeapState() != HeapState::Idle; +} - void tracePersistentRoots(JSTracer* trc); - void finishPersistentRoots(); -}; +static inline bool CurrentThreadIsHeapTracing() { + return CurrentThreadHeapState() == HeapState::Tracing; +} -} // namespace js +static inline bool CurrentThreadIsHeapMajorCollecting() { + return CurrentThreadHeapState() == HeapState::MajorCollecting; +} -namespace JS { +static inline bool CurrentThreadIsHeapMinorCollecting() { + return CurrentThreadHeapState() == HeapState::MinorCollecting; +} -/* - * 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; +static inline bool CurrentThreadIsHeapCollecting() { + HeapState state = CurrentThreadHeapState(); + return state == HeapState::MajorCollecting || + state == HeapState::MinorCollecting; +} -#ifdef DEBUG - // Whether the derived class is a JSContext or an ExclusiveContext. - bool isJSContext; -#endif +static inline bool CurrentThreadIsHeapCycleCollecting() { + return CurrentThreadHeapState() == HeapState::CycleCollecting; +} - explicit RootingContext(bool isJSContextArg) +// 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 - : isJSContext(isJSContextArg) + public: + explicit AutoEnterCycleCollection(JSRuntime* rt); + ~AutoEnterCycleCollection(); +#else + public: + explicit AutoEnterCycleCollection(JSRuntime* rt) {} + ~AutoEnterCycleCollection() {} #endif - {} - - static RootingContext* get(JSContext* cx) { - return reinterpret_cast(cx); - } }; -} // namespace JS - -namespace js { - -struct ContextFriendFields : public JS::RootingContext -{ - protected: - /* The current compartment. */ - JSCompartment* compartment_; - - /* The current zone. */ - JS::Zone* zone_; - - public: - /* Limit pointer for checking native stack consumption. */ - uintptr_t nativeStackLimit[js::StackKindCount]; - - explicit ContextFriendFields(bool isJSContext); - - static const ContextFriendFields* get(const JSContext* cx) { - return reinterpret_cast(cx); - } - - static ContextFriendFields* get(JSContext* cx) { - return reinterpret_cast(cx); - } - - friend JSCompartment* GetContextCompartment(const JSContext* cx); - friend JS::Zone* GetContextZone(const JSContext* cx); - template friend class JS::Rooted; -}; - -/* - * Inlinable accessors for JSContext. - * - * - These must not be available on the more restricted superclasses of - * JSContext, so we can't simply define them on ContextFriendFields. - * - * - They're perfectly ordinary JSContext functionality, so ought to be - * usable without resorting to jsfriendapi.h, and when JSContext is an - * incomplete type. - */ -inline JSCompartment* -GetContextCompartment(const JSContext* cx) -{ - return ContextFriendFields::get(cx)->compartment_; -} - -inline JS::Zone* -GetContextZone(const JSContext* cx) -{ - return ContextFriendFields::get(cx)->zone_; -} - -} /* namespace js */ +} /* namespace JS */ MOZ_BEGIN_EXTERN_C 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 @@ -26,13 +26,11 @@ #include "mozilla/Types.h" // jstypes.h is (or should be!) included by every file in SpiderMonkey. -// js-config.h and jsversion.h also should be included by every file. -// So include them here. -// XXX: including them in js/RequiredDefines.h should be a better option, since +// js-config.h also should be included by every file. So include it here. +// XXX: including it in js/RequiredDefines.h should be a better option, since // that is by definition the header file that should be included in all // SpiderMonkey code. However, Gecko doesn't do this! See bug 909576. #include "js-config.h" -#include "jsversion.h" /*********************************************************************** ** MACROS: JS_EXTERN_API @@ -55,10 +53,10 @@ ** ***********************************************************************/ -#define JS_EXTERN_API(type) extern MOZ_EXPORT type -#define JS_EXPORT_API(type) MOZ_EXPORT type +#define JS_EXTERN_API(type) extern MOZ_EXPORT type +#define JS_EXPORT_API(type) MOZ_EXPORT type #define JS_EXPORT_DATA(type) MOZ_EXPORT type -#define JS_IMPORT_API(type) MOZ_IMPORT_API type +#define JS_IMPORT_API(type) MOZ_IMPORT_API type #define JS_IMPORT_DATA(type) MOZ_IMPORT_DATA type /* @@ -68,20 +66,20 @@ * should not. STATIC_JS_API is used to build JS as a static library. */ #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 +#define JS_PUBLIC_API +#define JS_PUBLIC_DATA +#define JS_FRIEND_API +#define JS_FRIEND_DATA #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 -# 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 +#define JS_PUBLIC_API MOZ_EXPORT +#define JS_PUBLIC_DATA MOZ_EXPORT +#define JS_FRIEND_API MOZ_EXPORT +#define JS_FRIEND_DATA MOZ_EXPORT +#else +#define JS_PUBLIC_API MOZ_IMPORT_API +#define JS_PUBLIC_DATA MOZ_IMPORT_DATA +#define JS_FRIEND_API MOZ_IMPORT_API +#define JS_FRIEND_DATA MOZ_IMPORT_DATA #endif #if defined(_MSC_VER) && defined(_M_IX86) @@ -97,9 +95,11 @@ // 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)) +#if MOZ_IS_GCC +#if MOZ_GCC_VERSION_AT_MOST(8, 0, 0) #define JS_BROKEN_GCC_ATTRIBUTE_WARNING #endif +#endif /*********************************************************************** ** MACROS: JS_BEGIN_MACRO @@ -108,14 +108,16 @@ ** Macro body brackets so that macros with compound statement definitions ** behave syntactically more like functions when called. ***********************************************************************/ -#define JS_BEGIN_MACRO do { - +#define JS_BEGIN_MACRO do { #if defined(_MSC_VER) -# define JS_END_MACRO \ - } __pragma(warning(push)) __pragma(warning(disable:4127)) \ - while (0) __pragma(warning(pop)) -#else -# define JS_END_MACRO } while (0) +#define JS_END_MACRO \ + } \ + __pragma(warning(push)) __pragma(warning(disable : 4127)) while (0) \ + __pragma(warning(pop)) +#else +#define JS_END_MACRO \ + } \ + while (0) #endif /*********************************************************************** @@ -124,8 +126,8 @@ ** DESCRIPTION: ** Bit masking macros. XXX n must be <= 31 to be portable ***********************************************************************/ -#define JS_BIT(n) ((uint32_t)1 << (n)) -#define JS_BITMASK(n) (JS_BIT(n) - 1) +#define JS_BIT(n) ((uint32_t)1 << (n)) +#define JS_BITMASK(n) (JS_BIT(n) - 1) /*********************************************************************** ** MACROS: JS_HOWMANY @@ -133,68 +135,16 @@ ** DESCRIPTION: ** Commonly used macros for operations on compatible types. ***********************************************************************/ -#define JS_HOWMANY(x,y) (((x)+(y)-1)/(y)) -#define JS_ROUNDUP(x,y) (JS_HOWMANY(x,y)*(y)) - -#include "jscpucfg.h" - -/* - * Define JS_64BIT iff we are building in an environment with 64-bit - * addresses. - */ -#ifdef _MSC_VER -# if defined(_M_X64) || defined(_M_AMD64) -# define JS_64BIT -# endif -#elif defined(__GNUC__) -/* Additional GCC defines are when running on Solaris, AIX, and HPUX */ -# if defined(__x86_64__) || defined(__sparcv9) || \ - defined(__64BIT__) || defined(__LP64__) -# define JS_64BIT -# endif -#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* Sun Studio C/C++ */ -# if defined(__x86_64) || defined(__sparcv9) -# define JS_64BIT -# endif -#elif defined(__xlc__) || defined(__xlC__) /* IBM XL C/C++ */ -# if defined(__64BIT__) -# define JS_64BIT -# endif -#elif defined(__HP_cc) || defined(__HP_aCC) /* HP-UX cc/aCC */ -# if defined(__LP64__) -# define JS_64BIT -# endif -#else -# error "Implement me" -#endif - -/*********************************************************************** -** MACROS: JS_ARRAY_LENGTH -** JS_ARRAY_END -** DESCRIPTION: -** Macros to get the number of elements and the pointer to one past the -** last element of a C array. Use them like this: -** -** char16_t buf[10]; -** JSString* str; -** ... -** for (char16_t* s = buf; s != JS_ARRAY_END(buf); ++s) *s = ...; -** ... -** str = JS_NewStringCopyN(cx, buf, JS_ARRAY_LENGTH(buf)); -** ... -** -***********************************************************************/ - -#define JS_ARRAY_LENGTH(array) (sizeof (array) / sizeof (array)[0]) -#define JS_ARRAY_END(array) ((array) + JS_ARRAY_LENGTH(array)) +#define JS_HOWMANY(x, y) (((x) + (y)-1) / (y)) +#define JS_ROUNDUP(x, y) (JS_HOWMANY(x, y) * (y)) #define JS_BITS_PER_BYTE 8 #define JS_BITS_PER_BYTE_LOG2 3 #if defined(JS_64BIT) -# define JS_BITS_PER_WORD 64 +#define JS_BITS_PER_WORD 64 #else -# define JS_BITS_PER_WORD 32 +#define JS_BITS_PER_WORD 32 #endif /*********************************************************************** @@ -213,15 +163,15 @@ ** ***********************************************************************/ -#define JS_FUNC_TO_DATA_PTR(type, fun) (mozilla::BitwiseCast(fun)) -#define JS_DATA_TO_FUNC_PTR(type, ptr) (mozilla::BitwiseCast(ptr)) +#define JS_FUNC_TO_DATA_PTR(type, fun) (mozilla::BitwiseCast(fun)) +#define JS_DATA_TO_FUNC_PTR(type, ptr) (mozilla::BitwiseCast(ptr)) #ifdef __GNUC__ -# define JS_EXTENSION __extension__ -# define JS_EXTENSION_(s) __extension__ ({ s; }) +#define JS_EXTENSION __extension__ +#define JS_EXTENSION_(s) __extension__({ s; }) #else -# define JS_EXTENSION -# define JS_EXTENSION_(s) s +#define JS_EXTENSION +#define JS_EXTENSION_(s) s #endif #endif /* jstypes_h */ 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 @@ -1,40 +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 jsversion_h -#define jsversion_h - -/* - * JS Capability Macros. - */ -#define JS_HAS_STR_HTML_HELPERS 1 /* (no longer used) */ -#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */ -#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */ -#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */ -#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */ -#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */ -#define JS_HAS_CONST 1 /* (no longer used) */ -#define JS_HAS_FUN_EXPR_STMT 1 /* (no longer used) */ -#define JS_HAS_FOR_EACH_IN 1 /* has for each (lhs in iterable) */ -#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 /* (no longer used) */ -#define JS_HAS_EXPR_CLOSURES 1 /* has function (formals) listexpr */ - -/* (no longer used) */ -#define JS_HAS_NEW_GLOBAL_OBJECT 1 - -/* (no longer used) */ -#define JS_HAS_DESTRUCTURING_SHORTHAND (JS_HAS_DESTRUCTURING == 2) - -/* - * Feature for Object.prototype.__{define,lookup}{G,S}etter__ legacy support; - * support likely to be made opt-in at some future time. - */ -#define JS_OLD_GETTER_SETTER_METHODS 1 - -#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 @@ -1,382 +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 jswrapper_h -#define jswrapper_h - -#include "mozilla/Attributes.h" - -#include "js/Proxy.h" - -namespace js { - -/* - * Helper for Wrapper::New default options. - * - * Callers of Wrapper::New() who wish to specify a prototype for the created - * Wrapper, *MUST* construct a WrapperOptions with a JSContext. - */ -class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions { - public: - WrapperOptions() : ProxyOptions(false), - proto_() - {} - - explicit WrapperOptions(JSContext* cx) : ProxyOptions(false), - proto_() - { - proto_.emplace(cx); - } - - inline JSObject* proto() const; - WrapperOptions& setProto(JSObject* protoArg) { - MOZ_ASSERT(proto_); - *proto_ = protoArg; - return *this; - } - - private: - mozilla::Maybe proto_; -}; - -/* - * A wrapper is a proxy with a target object to which it generally forwards - * 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 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 { - CROSS_COMPARTMENT = 1 << 0, - LAST_USED_FLAG = CROSS_COMPARTMENT - }; - - static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler, - const WrapperOptions& options = WrapperOptions()); - - static JSObject* Renew(JSContext* cx, JSObject* existing, JSObject* obj, const Wrapper* handler); - - static const Wrapper* wrapperHandler(JSObject* wrapper); - - static JSObject* wrappedObject(JSObject* wrapper); - - unsigned flags() const { - return mFlags; - } - - static const char family; - static const Wrapper singleton; - static const Wrapper singletonWithPrototype; - - static JSObject* defaultProto; -}; - -inline JSObject* -WrapperOptions::proto() const -{ - return proto_ ? *proto_ : Wrapper::defaultProto; -} - -/* Base class for all cross compartment wrapper handlers. */ -class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper -{ - public: - 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; - virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, - ObjectOpResult& result) const override; - virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper, - AutoIdVector& props) const override; - virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id, - ObjectOpResult& result) const override; - virtual bool enumerate(JSContext* cx, HandleObject wrapper, 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 wrapper, - ObjectOpResult& result) const override; - virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override; - virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override; - virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver, - HandleId id, MutableHandleValue vp) const override; - virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result) const override; - virtual bool call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override; - virtual bool construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override; - - /* SpiderMonkey extensions. */ - virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - 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 nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, - const CallArgs& args) const override; - virtual bool hasInstance(JSContext* cx, HandleObject wrapper, MutableHandleValue v, - bool* bp) const override; - virtual const char* className(JSContext* cx, HandleObject proxy) const override; - virtual JSString* fun_toString(JSContext* cx, HandleObject wrapper, - 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; - - // Allocate CrossCompartmentWrappers in the nursery. - virtual bool canNurseryAllocate() const override { return true; } - - static const CrossCompartmentWrapper singleton; - static const CrossCompartmentWrapper singletonWithPrototype; -}; - -class JS_FRIEND_API(OpaqueCrossCompartmentWrapper) : public CrossCompartmentWrapper -{ - public: - explicit constexpr OpaqueCrossCompartmentWrapper() : CrossCompartmentWrapper(0) - { } - - /* Standard internal methods. */ - virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const override; - virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, - ObjectOpResult& result) const override; - virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper, - AutoIdVector& props) const override; - virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id, - ObjectOpResult& result) const override; - virtual bool enumerate(JSContext* cx, HandleObject wrapper, - MutableHandleObject objp) const override; - virtual bool getPrototype(JSContext* cx, HandleObject wrapper, - 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, - ObjectOpResult& result) const override; - virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override; - virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id, - bool* bp) const override; - virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver, - HandleId id, MutableHandleValue vp) const override; - virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result) const override; - virtual bool call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override; - virtual bool construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const override; - - /* SpiderMonkey extensions. */ - virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - 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, 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; - virtual JSString* fun_toString(JSContext* cx, HandleObject proxy, unsigned indent) const override; - - static const OpaqueCrossCompartmentWrapper singleton; -}; - -/* - * Base class for security wrappers. A security wrapper is potentially hiding - * all or part of some wrapped object thus SecurityWrapper defaults to denying - * access to the wrappee. This is the opposite of Wrapper which tries to be - * completely transparent. - * - * NB: Currently, only a few ProxyHandler operations are overridden to deny - * access, relying on derived SecurityWrapper to block access when necessary. - */ -template -class JS_FRIEND_API(SecurityWrapper) : public Base -{ - public: - explicit constexpr SecurityWrapper(unsigned flags, bool hasPrototype = false) - : Base(flags, hasPrototype, /* hasSecurityPolicy = */ true) - { } - - virtual bool enter(JSContext* cx, HandleObject wrapper, HandleId id, Wrapper::Action act, - bool* bp) const override; - - virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, - ObjectOpResult& result) const override; - virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override; - virtual bool preventExtensions(JSContext* cx, HandleObject wrapper, - ObjectOpResult& result) 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 nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, - const CallArgs& args) 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; - - // Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded - // against. - - virtual bool watch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, - JS::HandleObject callable) const override; - virtual bool unwatch(JSContext* cx, JS::HandleObject proxy, JS::HandleId id) const override; - - /* - * Allow our subclasses to select the superclass behavior they want without - * needing to specify an exact superclass. - */ - typedef Base Permissive; - typedef SecurityWrapper Restrictive; -}; - -typedef SecurityWrapper CrossCompartmentSecurityWrapper; - -extern JSObject* -TransparentObjectWrapper(JSContext* cx, HandleObject existing, HandleObject obj); - -inline bool -IsWrapper(JSObject* obj) -{ - return IsProxy(obj) && GetProxyHandler(obj)->family() == &Wrapper::family; -} - -// Given a JSObject, returns that object stripped of wrappers. If -// stopAtWindowProxy is true, then this returns the WindowProxy if it was -// previously wrapped. Otherwise, this returns the first object for -// which JSObject::isWrapper returns false. -JS_FRIEND_API(JSObject*) -UncheckedUnwrap(JSObject* obj, bool stopAtWindowProxy = true, unsigned* flagsp = nullptr); - -// Given a JSObject, returns that object stripped of wrappers. At each stage, -// the security wrapper has the opportunity to veto the unwrap. If -// stopAtWindowProxy is true, then this returns the WindowProxy if it was -// previously wrapped. -JS_FRIEND_API(JSObject*) -CheckedUnwrap(JSObject* obj, bool stopAtWindowProxy = true); - -// Unwrap only the outermost security wrapper, with the same semantics as -// above. This is the checked version of Wrapper::wrappedObject. -JS_FRIEND_API(JSObject*) -UnwrapOneChecked(JSObject* obj, bool stopAtWindowProxy = true); - -JS_FRIEND_API(bool) -IsCrossCompartmentWrapper(JSObject* obj); - -JS_FRIEND_API(void) -NukeCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper); - -void -RemapWrapper(JSContext* cx, JSObject* wobj, JSObject* newTarget); - -JS_FRIEND_API(bool) -RemapAllWrappersForObject(JSContext* cx, JSObject* oldTarget, - JSObject* newTarget); - -// API to recompute all cross-compartment wrappers whose source and target -// match the given filters. -JS_FRIEND_API(bool) -RecomputeWrappers(JSContext* cx, const CompartmentFilter& sourceFilter, - const CompartmentFilter& targetFilter); - -} /* namespace js */ - -#endif /* jswrapper_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/malloc_decls.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/malloc_decls.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/malloc_decls.h @@ -0,0 +1,125 @@ +/* -*- 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/. */ + +// Helper header to declare all the supported malloc functions. +// MALLOC_DECL arguments are: +// - function name +// - return type +// - argument types + +#ifndef malloc_decls_h +#define malloc_decls_h + +#include "mozjemalloc_types.h" + +#define MALLOC_FUNCS_MALLOC_BASE 1 +#define MALLOC_FUNCS_MALLOC_EXTRA 2 +#define MALLOC_FUNCS_MALLOC \ + (MALLOC_FUNCS_MALLOC_BASE | MALLOC_FUNCS_MALLOC_EXTRA) +#define MALLOC_FUNCS_JEMALLOC 4 +#define MALLOC_FUNCS_ARENA_BASE 8 +#define MALLOC_FUNCS_ARENA_ALLOC 16 +#define MALLOC_FUNCS_ARENA (MALLOC_FUNCS_ARENA_BASE | MALLOC_FUNCS_ARENA_ALLOC) +#define MALLOC_FUNCS_ALL \ + (MALLOC_FUNCS_MALLOC | MALLOC_FUNCS_JEMALLOC | MALLOC_FUNCS_ARENA) + +#endif // malloc_decls_h + +#ifndef MALLOC_FUNCS +#define MALLOC_FUNCS MALLOC_FUNCS_ALL +#endif + +#ifdef MALLOC_DECL +#if MALLOC_FUNCS & MALLOC_FUNCS_MALLOC_BASE +MALLOC_DECL(malloc, void*, size_t) +MALLOC_DECL(calloc, void*, size_t, size_t) +MALLOC_DECL(realloc, void*, void*, size_t) +MALLOC_DECL(free, void, void*) +MALLOC_DECL(memalign, void*, size_t, size_t) +#endif +#if MALLOC_FUNCS & MALLOC_FUNCS_MALLOC_EXTRA +MALLOC_DECL(posix_memalign, int, void**, size_t, size_t) +MALLOC_DECL(aligned_alloc, void*, size_t, size_t) +MALLOC_DECL(valloc, void*, size_t) +MALLOC_DECL(malloc_usable_size, size_t, usable_ptr_t) +MALLOC_DECL(malloc_good_size, size_t, size_t) +#endif +#if MALLOC_FUNCS & MALLOC_FUNCS_JEMALLOC +MALLOC_DECL(jemalloc_stats, void, jemalloc_stats_t*) + +// On some operating systems (Mac), we use madvise(MADV_FREE) to hand pages +// back to the operating system. On Mac, the operating system doesn't take +// this memory back immediately; instead, the OS takes it back only when the +// machine is running out of physical memory. +// +// This is great from the standpoint of efficiency, but it makes measuring our +// actual RSS difficult, because pages which we've MADV_FREE'd shouldn't count +// against our RSS. +// +// This function explicitly purges any MADV_FREE'd pages from physical memory, +// causing our reported RSS match the amount of memory we're actually using. +// +// Note that this call is expensive in two ways. First, it may be slow to +// execute, because it may make a number of slow syscalls to free memory. This +// function holds the big jemalloc locks, so basically all threads are blocked +// while this function runs. +// +// This function is also expensive in that the next time we go to access a page +// which we've just explicitly decommitted, the operating system has to attach +// to it a physical page! If we hadn't run this function, the OS would have +// less work to do. +// +// If MALLOC_DOUBLE_PURGE is not defined, this function does nothing. +MALLOC_DECL(jemalloc_purge_freed_pages, void) + +// Free all unused dirty pages in all arenas. Calling this function will slow +// down subsequent allocations so it is recommended to use it only when +// memory needs to be reclaimed at all costs (see bug 805855). This function +// provides functionality similar to mallctl("arenas.purge") in jemalloc 3. +MALLOC_DECL(jemalloc_free_dirty_pages, void) + +// Opt in or out of a thread local arena (bool argument is whether to opt-in +// (true) or out (false)). +MALLOC_DECL(jemalloc_thread_local_arena, void, bool) + +// Provide information about any allocation enclosing the given address. +MALLOC_DECL(jemalloc_ptr_info, void, const void*, jemalloc_ptr_info_t*) +#endif + +#if MALLOC_FUNCS & MALLOC_FUNCS_ARENA_BASE + +// Creates a separate arena, and returns its id, valid to use with moz_arena_* +// functions. A helper is provided in mozmemory.h that doesn't take any +// arena_params_t: moz_create_arena. +MALLOC_DECL(moz_create_arena_with_params, arena_id_t, arena_params_t*) + +// Dispose of the given arena. Subsequent uses of the arena will crash. +// Passing an invalid id (inexistent or already disposed) to this function +// will crash. +MALLOC_DECL(moz_dispose_arena, void, arena_id_t) +#endif + +#if MALLOC_FUNCS & MALLOC_FUNCS_ARENA_ALLOC +// Same as the functions without the moz_arena_ prefix, but using arenas +// created with moz_create_arena. +// The contract, even if not enforced at runtime in some configurations, +// is that moz_arena_realloc and moz_arena_free will crash if the given +// arena doesn't own the given pointer. All functions will crash if the +// arena id is invalid. +// Although discouraged, plain realloc and free can still be used on +// pointers allocated with these functions. Realloc will properly keep +// new pointers in the same arena as the original. +MALLOC_DECL(moz_arena_malloc, void*, arena_id_t, size_t) +MALLOC_DECL(moz_arena_calloc, void*, arena_id_t, size_t, size_t) +MALLOC_DECL(moz_arena_realloc, void*, arena_id_t, void*, size_t) +MALLOC_DECL(moz_arena_free, void, arena_id_t, void*) +MALLOC_DECL(moz_arena_memalign, void*, arena_id_t, size_t, size_t) +#endif + +#endif // MALLOC_DECL + +#undef MALLOC_DECL +#undef MALLOC_FUNCS 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 @@ -19,21 +19,38 @@ * This class, and the corresponding macro MOZ_ALIGNOF, figures out how many * bytes of alignment a given type needs. */ -template -class AlignmentFinder -{ - struct Aligner - { +template +class AlignmentFinder { + struct Aligner { char mChar; T mT; }; -public: + public: static const size_t alignment = sizeof(Aligner) - sizeof(T); }; #define MOZ_ALIGNOF(T) mozilla::AlignmentFinder::alignment +namespace detail { +template +struct AlignasHelper { + T mT; +}; +} // namespace detail + +/* + * Use this instead of alignof to align struct field as if it is inside + * a struct. On some platforms, there exist types which have different + * alignment between when it is used on its own and when it is used on + * a struct field. + * + * Known examples are 64bit types (uint64_t, double) on 32bit Linux, + * where they have 8byte alignment on their own, and 4byte alignment + * when in struct. + */ +#define MOZ_ALIGNAS_IN_STRUCT(T) alignas(mozilla::detail::AlignasHelper) + /* * Declare the MOZ_ALIGNED_DECL macro for declaring aligned types. * @@ -45,23 +62,21 @@ */ #if defined(__GNUC__) -# define MOZ_ALIGNED_DECL(_type, _align) \ - _type __attribute__((aligned(_align))) +#define MOZ_ALIGNED_DECL(_type, _align) _type __attribute__((aligned(_align))) #elif defined(_MSC_VER) -# define MOZ_ALIGNED_DECL(_type, _align) \ - __declspec(align(_align)) _type +#define MOZ_ALIGNED_DECL(_type, _align) __declspec(align(_align)) _type #else -# warning "We don't know how to align variables on this compiler." -# define MOZ_ALIGNED_DECL(_type, _align) _type +#warning "We don't know how to align variables on this compiler." +#define MOZ_ALIGNED_DECL(_type, _align) _type #endif /* * AlignedElem is a structure whose alignment is guaranteed to be at least N * bytes. * - * We support 1, 2, 4, 8, and 16-bit alignment. + * We support 1, 2, 4, 8, and 16-byte alignment. */ -template +template struct AlignedElem; /* @@ -69,71 +84,34 @@ * __attribute__((aligned(foo))) where foo is a template parameter. */ -template<> -struct AlignedElem<1> -{ +template <> +struct AlignedElem<1> { MOZ_ALIGNED_DECL(uint8_t elem, 1); }; -template<> -struct AlignedElem<2> -{ +template <> +struct AlignedElem<2> { MOZ_ALIGNED_DECL(uint8_t elem, 2); }; -template<> -struct AlignedElem<4> -{ +template <> +struct AlignedElem<4> { MOZ_ALIGNED_DECL(uint8_t elem, 4); }; -template<> -struct AlignedElem<8> -{ +template <> +struct AlignedElem<8> { MOZ_ALIGNED_DECL(uint8_t elem, 8); }; -template<> -struct AlignedElem<16> -{ +template <> +struct AlignedElem<16> { MOZ_ALIGNED_DECL(uint8_t elem, 16); }; -/* - * This utility pales in comparison to Boost's aligned_storage. The utility - * simply assumes that uint64_t is enough alignment for anyone. This may need - * to be extended one day... - * - * As an important side effect, pulling the storage into this template is - * enough obfuscation to confuse gcc's strict-aliasing analysis into not giving - * false negatives when we cast from the char buffer to whatever type we've - * constructed using the bytes. - */ -template -struct AlignedStorage -{ - union U - { - char mBytes[Nbytes]; - uint64_t mDummy; - } u; - - 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 -struct MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS AlignedStorage2 -{ - union U - { +template +struct MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS AlignedStorage2 { + union U { char mBytes[sizeof(T)]; uint64_t mDummy; } u; 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 @@ -13,6 +13,7 @@ #define mozilla_AllocPolicy_h #include "mozilla/Attributes.h" +#include "mozilla/Assertions.h" #include "mozilla/TemplateLib.h" #include @@ -68,12 +69,10 @@ * A policy that straightforwardly uses malloc/calloc/realloc/free and adds no * extra behaviors. */ -class MallocAllocPolicy -{ -public: +class MallocAllocPolicy { + public: template - T* maybe_pod_malloc(size_t aNumElems) - { + T* maybe_pod_malloc(size_t aNumElems) { if (aNumElems & mozilla::tl::MulOverflowMask::value) { return nullptr; } @@ -81,14 +80,12 @@ } template - T* maybe_pod_calloc(size_t aNumElems) - { + T* maybe_pod_calloc(size_t aNumElems) { return static_cast(calloc(aNumElems, sizeof(T))); } template - T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) - { + T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { if (aNewSize & mozilla::tl::MulOverflowMask::value) { return nullptr; } @@ -96,38 +93,73 @@ } template - T* pod_malloc(size_t aNumElems) - { + T* pod_malloc(size_t aNumElems) { return maybe_pod_malloc(aNumElems); } template - T* pod_calloc(size_t aNumElems) - { + T* pod_calloc(size_t aNumElems) { return maybe_pod_calloc(aNumElems); } template - T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) - { + T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { return maybe_pod_realloc(aPtr, aOldSize, aNewSize); } - void free_(void* aPtr) - { - free(aPtr); + void free_(void* aPtr) { free(aPtr); } + + void reportAllocOverflow() const {} + + MOZ_MUST_USE bool checkSimulatedOOM() const { return true; } +}; + +/* + * A policy which always fails to allocate memory, returning nullptr. Methods + * which expect an existing allocation assert. + * + * This type should be used in situations where you want to use a MFBT type with + * inline storage, and don't want to allow it to allocate on the heap. + */ +class NeverAllocPolicy { + public: + template + T* maybe_pod_malloc(size_t aNumElems) { + return nullptr; + } + + template + T* maybe_pod_calloc(size_t aNumElems) { + return nullptr; } - void reportAllocOverflow() const - { + template + T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { + MOZ_CRASH("NeverAllocPolicy::maybe_pod_realloc"); + } + + template + T* pod_malloc(size_t aNumElems) { + return nullptr; } - MOZ_MUST_USE bool checkSimulatedOOM() const - { - return true; + template + T* pod_calloc(size_t aNumElems) { + return nullptr; } + + template + T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { + MOZ_CRASH("NeverAllocPolicy::pod_realloc"); + } + + void free_(void* aPtr) { MOZ_CRASH("NeverAllocPolicy::free_"); } + + void reportAllocOverflow() const {} + + MOZ_MUST_USE bool checkSimulatedOOM() const { return true; } }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_AllocPolicy_h */ 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 @@ -17,7 +17,7 @@ struct unused_t; -} // namespace mozilla +} // namespace mozilla /** * already_AddRefed cooperates with reference counting smart pointers to enable @@ -27,10 +27,17 @@ * * TODO Move already_AddRefed to namespace mozilla. This has not yet been done * because of the sheer number of usages of already_AddRefed. + * + * When should you use already_AddRefed<>? + * * Ensure a consumer takes ownership of a reference + * * Pass ownership without calling AddRef/Release (sometimes required in + * off-main-thread code) + * * The ref pointer type you're using doesn't support move construction + * + * Otherwise, use Move(RefPtr/nsCOMPtr/etc). */ -template -struct MOZ_MUST_USE_TYPE MOZ_NON_AUTOABLE already_AddRefed -{ +template +struct MOZ_TEMPORARY_CLASS MOZ_MUST_USE_TYPE MOZ_NON_AUTOABLE already_AddRefed { /* * We want to allow returning nullptr from functions returning * already_AddRefed, for simplicity. But we also don't want to allow @@ -59,21 +66,61 @@ */ already_AddRefed() : mRawPtr(nullptr) {} - // The return and argument types here are arbitrarily selected so no - // corresponding member function exists. - typedef void (already_AddRefed::* MatchNullptr)(double, float); - MOZ_IMPLICIT already_AddRefed(MatchNullptr aRawPtr) : mRawPtr(nullptr) {} + MOZ_IMPLICIT already_AddRefed(decltype(nullptr)) : mRawPtr(nullptr) {} explicit already_AddRefed(T* aRawPtr) : mRawPtr(aRawPtr) {} - // Disallow copy constructor and copy assignment operator: move semantics used instead. + // Disallow copy constructor and copy assignment operator: move semantics used + // instead. already_AddRefed(const already_AddRefed& aOther) = delete; already_AddRefed& operator=(const already_AddRefed& aOther) = delete; - already_AddRefed(already_AddRefed&& aOther) : mRawPtr(aOther.take()) {} + // WARNING: sketchiness ahead. + // + // The x86-64 ABI for Unix-like operating systems requires structures to be + // returned via invisible reference if they are non-trivial for the purposes + // of calls according to the C++ ABI[1]. For our consideration here, that + // means that if we have a non-trivial move constructor or destructor, + // already_AddRefed must be returned by invisible reference. But + // already_AddRefed is small enough and so commonly used that it would be + // beneficial to return it via registers instead. So we need to figure out + // a way to make the move constructor and the destructor trivial. + // + // Our destructor is normally non-trivial, because it asserts that the + // stored pointer has been taken by somebody else prior to destruction. + // However, since the assert in question is compiled only for DEBUG builds, + // we can make the destructor trivial in non-DEBUG builds by simply defining + // it with `= default`. + // + // We now have to make the move constructor trivial as well. It is normally + // non-trivial, because the incoming object has its pointer null-ed during + // the move. This null-ing is done to satisfy the assert in the destructor. + // But since that destructor has no assert in non-DEBUG builds, the clearing + // is unnecessary in such builds; all we really need to perform is a copy of + // the pointer from the incoming object. So we can let the compiler define + // a trivial move constructor for us, and already_AddRefed can now be + // returned in registers rather than needing to allocate a stack slot for + // an invisible reference. + // + // The above considerations apply to Unix-like operating systems only; the + // conditions for the same optimization to apply on x86-64 Windows are much + // more strigent and are basically impossible for already_AddRefed to + // satisfy[2]. But we do get some benefit from this optimization on Windows + // because we removed the nulling of the pointer during the move, so that's + // a codesize win. + // + // [1] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#non-trivial + // [2] https://docs.microsoft.com/en-us/cpp/build/return-values-cpp + + already_AddRefed(already_AddRefed&& aOther) +#ifdef DEBUG + : mRawPtr(aOther.take()) { + } +#else + = default; +#endif - already_AddRefed& operator=(already_AddRefed&& aOther) - { + already_AddRefed& operator=(already_AddRefed&& aOther) { mRawPtr = aOther.take(); return *this; } @@ -96,23 +143,29 @@ * Note that nsRefPtr is the XPCOM reference counting smart pointer class. */ template - MOZ_IMPLICIT already_AddRefed(already_AddRefed&& aOther) : mRawPtr(aOther.take()) {} + MOZ_IMPLICIT already_AddRefed(already_AddRefed&& aOther) + : mRawPtr(aOther.take()) {} - ~already_AddRefed() { MOZ_ASSERT(!mRawPtr); } + ~already_AddRefed() +#ifdef DEBUG + { + MOZ_ASSERT(!mRawPtr); + } +#else + = default; +#endif // Specialize the unused operator<< for already_AddRefed, to allow // nsCOMPtr foo; // Unused << foo.forget(); // Note that nsCOMPtr is the XPCOM reference counting smart pointer class. friend void operator<<(const mozilla::unused_t& aUnused, - const already_AddRefed& aRhs) - { + const already_AddRefed& aRhs) { auto mutableAlreadyAddRefed = const_cast*>(&aRhs); aUnused << mutableAlreadyAddRefed->take(); } - MOZ_MUST_USE T* take() - { + MOZ_MUST_USE T* take() { T* rawPtr = mRawPtr; mRawPtr = nullptr; return rawPtr; @@ -132,16 +185,15 @@ * return F().downcast(); * } */ - template - already_AddRefed downcast() - { + template + already_AddRefed downcast() { U* tmp = static_cast(mRawPtr); mRawPtr = nullptr; return already_AddRefed(tmp); } -private: + private: T* MOZ_OWNING_REF mRawPtr; }; -#endif // AlreadyAddRefed_h +#endif // AlreadyAddRefed_h 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 @@ -18,37 +18,42 @@ namespace mozilla { -template -class Array -{ +template +class Array { T mArr[Length]; -public: + public: Array() {} template - MOZ_IMPLICIT Array(Args&&... aArgs) - : mArr{mozilla::Forward(aArgs)...} - { + 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"); + "The number of arguments should be equal to the template " + "parameter Length"); } - T& operator[](size_t aIndex) - { + T& operator[](size_t aIndex) { MOZ_ASSERT(aIndex < Length); return mArr[aIndex]; } - const T& operator[](size_t aIndex) const - { + const T& operator[](size_t aIndex) const { MOZ_ASSERT(aIndex < Length); return mArr[aIndex]; } - typedef T* iterator; - typedef const T* const_iterator; - typedef ReverseIterator reverse_iterator; + bool operator==(const Array& aOther) const { + for (size_t i = 0; i < Length; i++) { + if (mArr[i] != aOther[i]) { + return false; + } + } + return true; + } + + typedef T* iterator; + typedef const T* const_iterator; + typedef ReverseIterator reverse_iterator; typedef ReverseIterator const_reverse_iterator; // Methods for range-based for loops. @@ -61,28 +66,27 @@ // Methods for reverse iterating. reverse_iterator rbegin() { return reverse_iterator(end()); } - const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } const_reverse_iterator crbegin() const { return rbegin(); } reverse_iterator rend() { return reverse_iterator(begin()); } - const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } const_reverse_iterator crend() const { return rend(); } }; -template -class Array -{ -public: - T& operator[](size_t aIndex) - { - MOZ_CRASH("indexing into zero-length array"); - } +template +class Array { + public: + T& operator[](size_t aIndex) { MOZ_CRASH("indexing into zero-length array"); } - const T& operator[](size_t aIndex) const - { + const T& operator[](size_t aIndex) const { MOZ_CRASH("indexing into zero-length array"); } }; -} /* namespace mozilla */ +} /* namespace mozilla */ #endif /* mozilla_Array_h */ 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 @@ -37,10 +37,8 @@ * with the wrong sign even when the correct scaled distance would fit in a * ptrdiff_t. */ -template -MOZ_ALWAYS_INLINE size_t -PointerRangeSize(T* aBegin, T* aEnd) -{ +template +MOZ_ALWAYS_INLINE size_t PointerRangeSize(T* aBegin, T* aEnd) { MOZ_ASSERT(aEnd >= aBegin); return (size_t(aEnd) - size_t(aBegin)) / sizeof(T); } @@ -51,24 +49,18 @@ * * Beware of the implicit trailing '\0' when using this with string constants. */ -template -constexpr size_t -ArrayLength(T (&aArr)[N]) -{ +template +constexpr size_t ArrayLength(T (&aArr)[N]) { return N; } -template -constexpr size_t -ArrayLength(const Array& aArr) -{ +template +constexpr size_t ArrayLength(const Array& aArr) { return N; } -template -constexpr size_t -ArrayLength(const EnumeratedArray& aArr) -{ +template +constexpr size_t ArrayLength(const EnumeratedArray& aArr) { return size_t(N); } @@ -77,51 +69,38 @@ * * Beware of the implicit trailing '\0' when using this with string constants. */ -template -constexpr T* -ArrayEnd(T (&aArr)[N]) -{ +template +constexpr T* ArrayEnd(T (&aArr)[N]) { return aArr + ArrayLength(aArr); } -template -constexpr T* -ArrayEnd(Array& aArr) -{ +template +constexpr T* ArrayEnd(Array& aArr) { return &aArr[0] + ArrayLength(aArr); } -template -constexpr const T* -ArrayEnd(const Array& aArr) -{ +template +constexpr const T* ArrayEnd(const Array& aArr) { return &aArr[0] + ArrayLength(aArr); } namespace detail { -template::value>> -struct AlignedChecker -{ - static void - test(const Pointee* aPtr) - { +template ::value>> +struct AlignedChecker { + static void test(const Pointee* aPtr) { MOZ_ASSERT((uintptr_t(aPtr) % MOZ_ALIGNOF(AlignType)) == 0, "performing a range-check with a misaligned pointer"); } }; -template -struct AlignedChecker -{ - static void - test(const Pointee* aPtr) - { - } +template +struct AlignedChecker { + static void test(const Pointee* aPtr) {} }; -} // namespace detail +} // namespace detail /** * Determines whether |aPtr| points at an object in the range [aBegin, aEnd). @@ -136,13 +115,11 @@ * case no argument is required to be aligned (obviously, as void* implies no * particular alignment). */ -template -inline typename EnableIf::value || - IsBaseOf::value || - IsVoid::value, +template +inline typename EnableIf::value || IsBaseOf::value || + IsVoid::value, bool>::Type -IsInRange(const T* aPtr, const U* aBegin, const U* aEnd) -{ +IsInRange(const T* aPtr, const U* aBegin, const U* aEnd) { MOZ_ASSERT(aBegin <= aEnd); detail::AlignedChecker::test(aPtr); detail::AlignedChecker::test(aBegin); @@ -156,12 +133,9 @@ * uintptr_t values. As above, |aPtr| must be aligned, and |aBegin| and |aEnd| * must be aligned with respect to |T|. */ -template -inline bool -IsInRange(const T* aPtr, uintptr_t aBegin, uintptr_t aEnd) -{ - return IsInRange(aPtr, - reinterpret_cast(aBegin), +template +inline bool IsInRange(const T* aPtr, uintptr_t aBegin, uintptr_t aEnd) { + return IsInRange(aPtr, reinterpret_cast(aBegin), reinterpret_cast(aEnd)); } @@ -186,9 +160,10 @@ * can't call ArrayLength() when it is not a C++11 constexpr function. */ #ifdef __cplusplus -# define MOZ_ARRAY_LENGTH(array) sizeof(mozilla::detail::ArrayLengthHelper(array)) +#define MOZ_ARRAY_LENGTH(array) \ + sizeof(mozilla::detail::ArrayLengthHelper(array)) #else -# define MOZ_ARRAY_LENGTH(array) (sizeof(array)/sizeof((array)[0])) +#define MOZ_ARRAY_LENGTH(array) (sizeof(array) / sizeof((array)[0])) #endif #endif /* mozilla_ArrayUtils_h */ 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 @@ -23,7 +23,6 @@ #include "nsTraceRefcnt.h" #endif -#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 @@ -34,40 +33,38 @@ extern MFBT_DATA const char* gMozCrashReason; MOZ_END_EXTERN_C -static inline void -AnnotateMozCrashReason(const char* reason) -{ +#if !defined(DEBUG) && \ + (defined(MOZ_HAS_MOZGLUE) || defined(MOZILLA_INTERNAL_API)) +static inline void AnnotateMozCrashReason(const char* reason) { gMozCrashReason = reason; } -# define MOZ_CRASH_ANNOTATE(...) AnnotateMozCrashReason(__VA_ARGS__) +#define MOZ_CRASH_ANNOTATE(...) AnnotateMozCrashReason(__VA_ARGS__) #else -# define MOZ_CRASH_ANNOTATE(...) do { /* nothing */ } while (0) +#define MOZ_CRASH_ANNOTATE(...) \ + do { /* nothing */ \ + } while (false) #endif #include #include #include -#ifdef WIN32 - /* - * TerminateProcess and GetCurrentProcess are defined in , which - * further depends on . We hardcode these few definitions manually - * because those headers clutter the global namespace with a significant - * number of undesired macros and symbols. - */ -# ifdef __cplusplus -extern "C" { -# endif -__declspec(dllimport) int __stdcall -TerminateProcess(void* hProcess, unsigned int uExitCode); +#ifdef _MSC_VER +/* + * TerminateProcess and GetCurrentProcess are defined in , which + * further depends on . We hardcode these few definitions manually + * because those headers clutter the global namespace with a significant + * number of undesired macros and symbols. + */ +MOZ_BEGIN_EXTERN_C +__declspec(dllimport) int __stdcall TerminateProcess(void* hProcess, + unsigned int uExitCode); __declspec(dllimport) void* __stdcall GetCurrentProcess(void); -# ifdef __cplusplus -} -# endif +MOZ_END_EXTERN_C #else -# include +#include #endif #ifdef ANDROID -# include +#include #endif /* @@ -89,62 +86,66 @@ * typedef could be used. */ #ifndef __cplusplus - /* - * Some of the definitions below create an otherwise-unused typedef. This - * triggers compiler warnings with some versions of gcc, so mark the typedefs - * as permissibly-unused to disable the warnings. - */ -# if defined(__GNUC__) -# define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) -# else -# define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE /* nothing */ -# endif -# define MOZ_STATIC_ASSERT_GLUE1(x, y) x##y -# define MOZ_STATIC_ASSERT_GLUE(x, y) MOZ_STATIC_ASSERT_GLUE1(x, y) -# if defined(__SUNPRO_CC) - /* - * The Sun Studio C++ compiler is buggy when declaring, inside a function, - * another extern'd function with an array argument whose length contains a - * sizeof, triggering the error message "sizeof expression not accepted as - * size of array parameter". This bug (6688515, not public yet) would hit - * defining moz_static_assert as a function, so we always define an extern - * array for Sun Studio. - * - * We include the line number in the symbol name in a best-effort attempt - * to avoid conflicts (see below). - */ -# define MOZ_STATIC_ASSERT(cond, reason) \ - extern char MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)[(cond) ? 1 : -1] -# elif defined(__COUNTER__) - /* - * If there was no preferred alternative, use a compiler-agnostic version. - * - * Note that the non-__COUNTER__ version has a bug in C++: it can't be used - * in both |extern "C"| and normal C++ in the same translation unit. (Alas - * |extern "C"| isn't allowed in a function.) The only affected compiler - * we really care about is gcc 4.2. For that compiler and others like it, - * we include the line number in the function name to do the best we can to - * avoid conflicts. These should be rare: a conflict would require use of - * MOZ_STATIC_ASSERT on the same line in separate files in the same - * translation unit, *and* the uses would have to be in code with - * different linkage, *and* the first observed use must be in C++-linkage - * code. - */ -# define MOZ_STATIC_ASSERT(cond, reason) \ - typedef int MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __COUNTER__)[(cond) ? 1 : -1] MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE -# else -# define MOZ_STATIC_ASSERT(cond, reason) \ - extern void MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)(int arg[(cond) ? 1 : -1]) MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE -# endif +/* + * Some of the definitions below create an otherwise-unused typedef. This + * triggers compiler warnings with some versions of gcc, so mark the typedefs + * as permissibly-unused to disable the warnings. + */ +#if defined(__GNUC__) +#define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) +#else +#define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE /* nothing */ +#endif +#define MOZ_STATIC_ASSERT_GLUE1(x, y) x##y +#define MOZ_STATIC_ASSERT_GLUE(x, y) MOZ_STATIC_ASSERT_GLUE1(x, y) +#if defined(__SUNPRO_CC) +/* + * The Sun Studio C++ compiler is buggy when declaring, inside a function, + * another extern'd function with an array argument whose length contains a + * sizeof, triggering the error message "sizeof expression not accepted as + * size of array parameter". This bug (6688515, not public yet) would hit + * defining moz_static_assert as a function, so we always define an extern + * array for Sun Studio. + * + * We include the line number in the symbol name in a best-effort attempt + * to avoid conflicts (see below). + */ +#define MOZ_STATIC_ASSERT(cond, reason) \ + extern char MOZ_STATIC_ASSERT_GLUE(moz_static_assert, \ + __LINE__)[(cond) ? 1 : -1] +#elif defined(__COUNTER__) +/* + * If there was no preferred alternative, use a compiler-agnostic version. + * + * Note that the non-__COUNTER__ version has a bug in C++: it can't be used + * in both |extern "C"| and normal C++ in the same translation unit. (Alas + * |extern "C"| isn't allowed in a function.) The only affected compiler + * we really care about is gcc 4.2. For that compiler and others like it, + * we include the line number in the function name to do the best we can to + * avoid conflicts. These should be rare: a conflict would require use of + * MOZ_STATIC_ASSERT on the same line in separate files in the same + * translation unit, *and* the uses would have to be in code with + * different linkage, *and* the first observed use must be in C++-linkage + * code. + */ +#define MOZ_STATIC_ASSERT(cond, reason) \ + typedef int MOZ_STATIC_ASSERT_GLUE( \ + moz_static_assert, \ + __COUNTER__)[(cond) ? 1 : -1] MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE +#else +#define MOZ_STATIC_ASSERT(cond, reason) \ + extern void MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)( \ + int arg[(cond) ? 1 : -1]) MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE +#endif -#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) MOZ_STATIC_ASSERT(!(cond) || (expr), reason) +#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) \ + MOZ_STATIC_ASSERT(!(cond) || (expr), reason) #else -#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) static_assert(!(cond) || (expr), reason) +#define MOZ_STATIC_ASSERT_IF(cond, expr, reason) \ + static_assert(!(cond) || (expr), reason) #endif -#ifdef __cplusplus -extern "C" { -#endif +MOZ_BEGIN_EXTERN_C /* * Prints |aStr| as an assertion failure (using aFilename and aLine as the @@ -154,27 +155,25 @@ * method is primarily for internal use in this header, and only secondarily * for use in implementing release-build assertions. */ -static MOZ_COLD MOZ_ALWAYS_INLINE void -MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, int aLine) - MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS -{ +MOZ_MAYBE_UNUSED static MOZ_COLD MOZ_NEVER_INLINE void +MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, + int aLine) MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS { #ifdef ANDROID __android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert", - "Assertion failure: %s, at %s:%d\n", - aStr, aFilename, aLine); + "Assertion failure: %s, at %s:%d\n", aStr, aFilename, + aLine); #else fprintf(stderr, "Assertion failure: %s, at %s:%d\n", aStr, aFilename, aLine); -#if defined (MOZ_DUMP_ASSERTION_STACK) +#if defined(MOZ_DUMP_ASSERTION_STACK) nsTraceRefcnt::WalkTheStack(stderr); #endif fflush(stderr); #endif } -static MOZ_COLD MOZ_ALWAYS_INLINE void -MOZ_ReportCrash(const char* aStr, const char* aFilename, int aLine) - MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS -{ +MOZ_MAYBE_UNUSED static MOZ_COLD MOZ_NEVER_INLINE void MOZ_ReportCrash( + const char* aStr, const char* aFilename, + int aLine) MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS { #ifdef ANDROID __android_log_print(ANDROID_LOG_FATAL, "MOZ_CRASH", "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine); @@ -192,62 +191,53 @@ * call MOZ_CRASH instead. */ #if defined(_MSC_VER) - /* - * On MSVC use the __debugbreak compiler intrinsic, which produces an inline - * (not nested in a system function) breakpoint. This distinctively invokes - * Breakpad without requiring system library symbols on all stack-processing - * machines, as a nested breakpoint would require. - * - * We use TerminateProcess with the exit code aborting would generate - * because we don't want to invoke atexit handlers, destructors, library - * unload handlers, and so on when our process might be in a compromised - * state. - * - * We don't use abort() because it'd cause Windows to annoyingly pop up the - * process error dialog multiple times. See bug 345118 and bug 426163. - * - * We follow TerminateProcess() with a call to MOZ_NoReturn() so that the - * compiler doesn't hassle us to provide a return statement after a - * MOZ_REALLY_CRASH() call. - * - * (Technically these are Windows requirements, not MSVC requirements. But - * practically you need MSVC for debugging, and we only ship builds created - * by MSVC, so doing it this way reduces complexity.) - */ - -__declspec(noreturn) __inline void MOZ_NoReturn() {} - -# ifdef __cplusplus -# define MOZ_REALLY_CRASH(line) \ - do { \ - ::__debugbreak(); \ - *((volatile int*) NULL) = line; \ - ::TerminateProcess(::GetCurrentProcess(), 3); \ - ::MOZ_NoReturn(); \ - } while (0) -# else -# define MOZ_REALLY_CRASH(line) \ - do { \ - __debugbreak(); \ - *((volatile int*) NULL) = line; \ - TerminateProcess(GetCurrentProcess(), 3); \ - MOZ_NoReturn(); \ - } while (0) -# endif -#else -# ifdef __cplusplus -# define MOZ_REALLY_CRASH(line) \ - do { \ - *((volatile int*) NULL) = line; \ - ::abort(); \ - } while (0) -# else -# define MOZ_REALLY_CRASH(line) \ - do { \ - *((volatile int*) NULL) = line; \ - abort(); \ - } while (0) -# endif +/* + * On MSVC use the __debugbreak compiler intrinsic, which produces an inline + * (not nested in a system function) breakpoint. This distinctively invokes + * Breakpad without requiring system library symbols on all stack-processing + * machines, as a nested breakpoint would require. + * + * We use __LINE__ to prevent the compiler from folding multiple crash sites + * together, which would make crash reports hard to understand. + * + * We use TerminateProcess with the exit code aborting would generate + * because we don't want to invoke atexit handlers, destructors, library + * unload handlers, and so on when our process might be in a compromised + * state. + * + * We don't use abort() because it'd cause Windows to annoyingly pop up the + * process error dialog multiple times. See bug 345118 and bug 426163. + * + * (Technically these are Windows requirements, not MSVC requirements. But + * practically you need MSVC for debugging, and we only ship builds created + * by MSVC, so doing it this way reduces complexity.) + */ + +MOZ_MAYBE_UNUSED static MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void +MOZ_NoReturn(int aLine) { + *((volatile int*)NULL) = aLine; + TerminateProcess(GetCurrentProcess(), 3); +} + +#define MOZ_REALLY_CRASH(line) \ + do { \ + __debugbreak(); \ + MOZ_NoReturn(line); \ + } while (false) +#else +#ifdef __cplusplus +#define MOZ_REALLY_CRASH(line) \ + do { \ + *((volatile int*)NULL) = line; \ + ::abort(); \ + } while (false) +#else +#define MOZ_REALLY_CRASH(line) \ + do { \ + *((volatile int*)NULL) = line; \ + abort(); \ + } while (false) +#endif #endif /* @@ -272,18 +262,18 @@ * corrupted. */ #ifndef DEBUG -# define MOZ_CRASH(...) \ - do { \ - MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \ - 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(__LINE__); \ - } while (0) +#define MOZ_CRASH(...) \ + do { \ + MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \ + MOZ_REALLY_CRASH(__LINE__); \ + } while (false) +#else +#define MOZ_CRASH(...) \ + do { \ + MOZ_ReportCrash("" __VA_ARGS__, __FILE__, __LINE__); \ + MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \ + MOZ_REALLY_CRASH(__LINE__); \ + } while (false) #endif /* @@ -293,30 +283,35 @@ * 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. + * + * @note This macro causes data collection because crash strings are annotated + * to crash-stats and are publicly visible. Firefox data stewards must do data + * review on usages of this macro. */ #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) +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__) +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 /* @@ -326,21 +321,24 @@ * 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) + * + * @note This macro causes data collection because crash strings are annotated + * to crash-stats and are publicly visible. Firefox data stewards must do data + * review on usages of this macro. + */ +#define MOZ_CRASH_UNSAFE_PRINTF(format, ...) \ + do { \ + static_assert(MOZ_ARG_COUNT(__VA_ARGS__) > 0, \ + "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " \ + "Or maybe you want MOZ_CRASH instead?"); \ + static_assert(MOZ_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 (false) -#ifdef __cplusplus -} /* extern "C" */ -#endif +MOZ_END_EXTERN_C /* * MOZ_ASSERT(expr [, explanation-string]) asserts that |expr| must be truthy in @@ -381,6 +379,9 @@ * This can cause user pain, so use it sparingly. If a MOZ_DIAGNOSTIC_ASSERT * is firing, it should promptly be converted to a MOZ_ASSERT while the failure * is being investigated, rather than letting users suffer. + * + * MOZ_DIAGNOSTIC_ASSERT_ENABLED is defined when MOZ_DIAGNOSTIC_ASSERT is like + * MOZ_RELEASE_ASSERT rather than MOZ_ASSERT. */ /* @@ -389,13 +390,12 @@ */ #ifdef __cplusplus -# include "mozilla/TypeTraits.h" +#include "mozilla/TypeTraits.h" namespace mozilla { namespace detail { -template -struct AssertionConditionType -{ +template +struct AssertionConditionType { typedef typename RemoveReference::Type ValueT; static_assert(!IsArray::value, "Expected boolean assertion condition, got an array or a " @@ -413,52 +413,68 @@ static const bool isValid = true; }; -} // namespace detail -} // namespace mozilla -# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) \ - static_assert(mozilla::detail::AssertionConditionType::isValid, \ - "invalid assertion condition") -#else -# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) +} // namespace detail +} // namespace mozilla +#define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) \ + static_assert(mozilla::detail::AssertionConditionType::isValid, \ + "invalid assertion condition") +#else +#define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) +#endif + +#if defined(DEBUG) || defined(MOZ_ASAN) +#define MOZ_REPORT_ASSERTION_FAILURE(...) \ + MOZ_ReportAssertionFailure(__VA_ARGS__) +#else +#define MOZ_REPORT_ASSERTION_FAILURE(...) \ + do { /* nothing */ \ + } while (false) #endif /* First the single-argument form. */ -#define MOZ_ASSERT_HELPER1(expr) \ - do { \ - MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ - if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ - MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \ - MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ")"); \ - MOZ_REALLY_CRASH(__LINE__); \ - } \ - } while (0) +#define MOZ_ASSERT_HELPER1(expr) \ + do { \ + MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ + if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ + MOZ_REPORT_ASSERTION_FAILURE(#expr, __FILE__, __LINE__); \ + MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ")"); \ + MOZ_REALLY_CRASH(__LINE__); \ + } \ + } while (false) /* Now the two-argument form. */ -#define MOZ_ASSERT_HELPER2(expr, explain) \ - do { \ - MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ - if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ - MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \ +#define MOZ_ASSERT_HELPER2(expr, explain) \ + do { \ + MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ + if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ + MOZ_REPORT_ASSERTION_FAILURE(#expr " (" explain ")", __FILE__, \ + __LINE__); \ MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ") (" explain ")"); \ - MOZ_REALLY_CRASH(__LINE__); \ - } \ - } while (0) + MOZ_REALLY_CRASH(__LINE__); \ + } \ + } while (false) #define MOZ_RELEASE_ASSERT_GLUE(a, b) a b -#define MOZ_RELEASE_ASSERT(...) \ - MOZ_RELEASE_ASSERT_GLUE( \ - MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \ - (__VA_ARGS__)) +#define MOZ_RELEASE_ASSERT(...) \ + MOZ_RELEASE_ASSERT_GLUE( \ + MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \ + (__VA_ARGS__)) #ifdef DEBUG -# define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__) +#define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__) #else -# define MOZ_ASSERT(...) do { } while (0) +#define MOZ_ASSERT(...) \ + do { \ + } while (false) #endif /* DEBUG */ -#ifdef RELEASE_OR_BETA -# define MOZ_DIAGNOSTIC_ASSERT MOZ_ASSERT +#if defined(NIGHTLY_BUILD) || defined(MOZ_DEV_EDITION) +#define MOZ_DIAGNOSTIC_ASSERT MOZ_RELEASE_ASSERT +#define MOZ_DIAGNOSTIC_ASSERT_ENABLED 1 #else -# define MOZ_DIAGNOSTIC_ASSERT MOZ_RELEASE_ASSERT +#define MOZ_DIAGNOSTIC_ASSERT MOZ_ASSERT +#ifdef DEBUG +#define MOZ_DIAGNOSTIC_ASSERT_ENABLED 1 +#endif #endif /* @@ -471,14 +487,16 @@ * designed to catch bugs during debugging, not "in the field". */ #ifdef DEBUG -# define MOZ_ASSERT_IF(cond, expr) \ - do { \ - if (cond) { \ - MOZ_ASSERT(expr); \ - } \ - } while (0) -#else -# define MOZ_ASSERT_IF(cond, expr) do { } while (0) +#define MOZ_ASSERT_IF(cond, expr) \ + do { \ + if (cond) { \ + MOZ_ASSERT(expr); \ + } \ + } while (false) +#else +#define MOZ_ASSERT_IF(cond, expr) \ + do { \ + } while (false) #endif /* @@ -489,15 +507,15 @@ * asserts. */ #if defined(__clang__) || defined(__GNUC__) -# define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable() +#define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable() #elif defined(_MSC_VER) -# define MOZ_ASSUME_UNREACHABLE_MARKER() __assume(0) +#define MOZ_ASSUME_UNREACHABLE_MARKER() __assume(0) #else -# ifdef __cplusplus -# define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort() -# else -# define MOZ_ASSUME_UNREACHABLE_MARKER() abort() -# endif +#ifdef __cplusplus +#define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort() +#else +#define MOZ_ASSUME_UNREACHABLE_MARKER() abort() +#endif #endif /* @@ -546,13 +564,13 @@ * that have a safe return without crashing in release builds. */ #define MOZ_ASSERT_UNREACHABLE(reason) \ - MOZ_ASSERT(false, "MOZ_ASSERT_UNREACHABLE: " reason) + MOZ_ASSERT(false, "MOZ_ASSERT_UNREACHABLE: " reason) #define MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(reason) \ - do { \ - MOZ_ASSERT_UNREACHABLE(reason); \ - MOZ_ASSUME_UNREACHABLE_MARKER(); \ - } while (0) + do { \ + MOZ_ASSERT_UNREACHABLE(reason); \ + MOZ_ASSUME_UNREACHABLE_MARKER(); \ + } while (false) /** * MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about @@ -561,7 +579,7 @@ * 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)`, + * release builds, the MOZ_ASSERT(false) will expand to `do { } while (false)`, * 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 @@ -588,9 +606,10 @@ * } */ #ifdef DEBUG -# define MOZ_FALLTHROUGH_ASSERT(reason) MOZ_CRASH("MOZ_FALLTHROUGH_ASSERT: " reason) +#define MOZ_FALLTHROUGH_ASSERT(reason) \ + MOZ_CRASH("MOZ_FALLTHROUGH_ASSERT: " reason) #else -# define MOZ_FALLTHROUGH_ASSERT(...) MOZ_FALLTHROUGH +#define MOZ_FALLTHROUGH_ASSERT(...) MOZ_FALLTHROUGH #endif /* @@ -600,35 +619,49 @@ * using MOZ_ASSERT. */ #ifdef DEBUG -# 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_MUST_USE. */ \ - } \ - } while (0) -# define MOZ_ALWAYS_FALSE(expr) \ - do { \ - if ((expr)) { \ - /* Silence MOZ_MUST_USE. */ \ - } \ - } while (0) +#define MOZ_ALWAYS_TRUE(expr) \ + do { \ + if ((expr)) { \ + /* Do nothing. */ \ + } else { \ + MOZ_ASSERT(false, #expr); \ + } \ + } while (false) +#define MOZ_ALWAYS_FALSE(expr) \ + do { \ + if ((expr)) { \ + MOZ_ASSERT(false, #expr); \ + } else { \ + /* Do nothing. */ \ + } \ + } while (false) +#define MOZ_ALWAYS_OK(expr) MOZ_ASSERT((expr).isOk()) +#define MOZ_ALWAYS_ERR(expr) MOZ_ASSERT((expr).isErr()) +#else +#define MOZ_ALWAYS_TRUE(expr) \ + do { \ + if ((expr)) { \ + /* Silence MOZ_MUST_USE. */ \ + } \ + } while (false) +#define MOZ_ALWAYS_FALSE(expr) \ + do { \ + if ((expr)) { \ + /* Silence MOZ_MUST_USE. */ \ + } \ + } while (false) +#define MOZ_ALWAYS_OK(expr) \ + do { \ + if ((expr).isOk()) { \ + /* Silence MOZ_MUST_USE. */ \ + } \ + } while (false) +#define MOZ_ALWAYS_ERR(expr) \ + do { \ + if ((expr).isErr()) { \ + /* Silence MOZ_MUST_USE. */ \ + } \ + } while (false) #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 @@ -21,30 +21,9 @@ #include "mozilla/Compiler.h" #include "mozilla/TypeTraits.h" -#include +#include -/* - * Our minimum deployment target on clang/OS X is OS X 10.6, whose SDK - * does not have . So be sure to check for support - * along with C++0x support. - */ -#if defined(_MSC_VER) -# define MOZ_HAVE_CXX11_ATOMICS -#elif defined(__clang__) || defined(__GNUC__) - /* - * Clang doesn't like from libstdc++ before 4.7 due to the - * loose typing of the atomic builtins. GCC 4.5 and 4.6 lacks inline - * definitions for unspecialized std::atomic and causes linking errors. - * Therefore, we require at least 4.7.0 for using libstdc++. - * - * libc++ is only functional with clang. - */ -# if MOZ_USING_LIBSTDCXX && MOZ_LIBSTDCXX_VERSION_AT_LEAST(4, 7, 0) -# define MOZ_HAVE_CXX11_ATOMICS -# elif MOZ_USING_LIBCXX && defined(__clang__) -# define MOZ_HAVE_CXX11_ATOMICS -# endif -#endif +#include namespace mozilla { @@ -162,402 +141,159 @@ SequentiallyConsistent, }; -} // namespace mozilla - -// Build up the underlying intrinsics. -#ifdef MOZ_HAVE_CXX11_ATOMICS - -# include - -namespace mozilla { namespace detail { /* * We provide CompareExchangeFailureOrder to work around a bug in some * versions of GCC's header. See bug 898491. */ -template struct AtomicOrderConstraints; +template +struct AtomicOrderConstraints; -template<> -struct AtomicOrderConstraints -{ +template <> +struct AtomicOrderConstraints { static const std::memory_order AtomicRMWOrder = std::memory_order_relaxed; static const std::memory_order LoadOrder = std::memory_order_relaxed; static const std::memory_order StoreOrder = std::memory_order_relaxed; static const std::memory_order CompareExchangeFailureOrder = - std::memory_order_relaxed; + std::memory_order_relaxed; }; -template<> -struct AtomicOrderConstraints -{ +template <> +struct AtomicOrderConstraints { static const std::memory_order AtomicRMWOrder = std::memory_order_acq_rel; static const std::memory_order LoadOrder = std::memory_order_acquire; static const std::memory_order StoreOrder = std::memory_order_release; static const std::memory_order CompareExchangeFailureOrder = - std::memory_order_acquire; + std::memory_order_acquire; }; -template<> -struct AtomicOrderConstraints -{ +template <> +struct AtomicOrderConstraints { static const std::memory_order AtomicRMWOrder = std::memory_order_seq_cst; static const std::memory_order LoadOrder = std::memory_order_seq_cst; static const std::memory_order StoreOrder = std::memory_order_seq_cst; static const std::memory_order CompareExchangeFailureOrder = - std::memory_order_seq_cst; + std::memory_order_seq_cst; }; -template -struct IntrinsicBase -{ +template +struct IntrinsicBase { typedef std::atomic ValueType; typedef AtomicOrderConstraints OrderedOp; }; -template -struct IntrinsicMemoryOps : public IntrinsicBase -{ +template +struct IntrinsicMemoryOps : public IntrinsicBase { typedef IntrinsicBase Base; - static T load(const typename Base::ValueType& aPtr) - { + static T load(const typename Base::ValueType& aPtr) { return aPtr.load(Base::OrderedOp::LoadOrder); } - static void store(typename Base::ValueType& aPtr, T aVal) - { + static void store(typename Base::ValueType& aPtr, T aVal) { aPtr.store(aVal, Base::OrderedOp::StoreOrder); } - static T exchange(typename Base::ValueType& aPtr, T aVal) - { + static T exchange(typename Base::ValueType& aPtr, T aVal) { return aPtr.exchange(aVal, Base::OrderedOp::AtomicRMWOrder); } - static bool compareExchange(typename Base::ValueType& aPtr, - T aOldVal, T aNewVal) - { - return aPtr.compare_exchange_strong(aOldVal, aNewVal, - Base::OrderedOp::AtomicRMWOrder, - Base::OrderedOp::CompareExchangeFailureOrder); + static bool compareExchange(typename Base::ValueType& aPtr, T aOldVal, + T aNewVal) { + return aPtr.compare_exchange_strong( + aOldVal, aNewVal, Base::OrderedOp::AtomicRMWOrder, + Base::OrderedOp::CompareExchangeFailureOrder); } }; -template -struct IntrinsicAddSub : public IntrinsicBase -{ +template +struct IntrinsicAddSub : public IntrinsicBase { typedef IntrinsicBase Base; - static T add(typename Base::ValueType& aPtr, T aVal) - { + static T add(typename Base::ValueType& aPtr, T aVal) { return aPtr.fetch_add(aVal, Base::OrderedOp::AtomicRMWOrder); } - static T sub(typename Base::ValueType& aPtr, T aVal) - { + static T sub(typename Base::ValueType& aPtr, T aVal) { return aPtr.fetch_sub(aVal, Base::OrderedOp::AtomicRMWOrder); } }; -template -struct IntrinsicAddSub : public IntrinsicBase -{ +template +struct IntrinsicAddSub : public IntrinsicBase { typedef IntrinsicBase Base; - static T* add(typename Base::ValueType& aPtr, ptrdiff_t aVal) - { + static T* add(typename Base::ValueType& aPtr, ptrdiff_t aVal) { return aPtr.fetch_add(aVal, Base::OrderedOp::AtomicRMWOrder); } - static T* sub(typename Base::ValueType& aPtr, ptrdiff_t aVal) - { + static T* sub(typename Base::ValueType& aPtr, ptrdiff_t aVal) { return aPtr.fetch_sub(aVal, Base::OrderedOp::AtomicRMWOrder); } }; -template -struct IntrinsicIncDec : public IntrinsicAddSub -{ +template +struct IntrinsicIncDec : public IntrinsicAddSub { typedef IntrinsicBase Base; - static T inc(typename Base::ValueType& aPtr) - { + static T inc(typename Base::ValueType& aPtr) { return IntrinsicAddSub::add(aPtr, 1); } - static T dec(typename Base::ValueType& aPtr) - { + static T dec(typename Base::ValueType& aPtr) { return IntrinsicAddSub::sub(aPtr, 1); } }; -template +template struct AtomicIntrinsics : public IntrinsicMemoryOps, - public IntrinsicIncDec -{ + public IntrinsicIncDec { typedef IntrinsicBase Base; - static T or_(typename Base::ValueType& aPtr, T aVal) - { + static T or_(typename Base::ValueType& aPtr, T aVal) { return aPtr.fetch_or(aVal, Base::OrderedOp::AtomicRMWOrder); } - static T xor_(typename Base::ValueType& aPtr, T aVal) - { + static T xor_(typename Base::ValueType& aPtr, T aVal) { return aPtr.fetch_xor(aVal, Base::OrderedOp::AtomicRMWOrder); } - static T and_(typename Base::ValueType& aPtr, T aVal) - { + static T and_(typename Base::ValueType& aPtr, T aVal) { return aPtr.fetch_and(aVal, Base::OrderedOp::AtomicRMWOrder); } }; -template -struct AtomicIntrinsics - : public IntrinsicMemoryOps, public IntrinsicIncDec -{ -}; - -template -struct ToStorageTypeArgument -{ - static constexpr T convert (T aT) { return aT; } -}; - -} // namespace detail -} // namespace mozilla - -#elif defined(__GNUC__) - -namespace mozilla { -namespace detail { - -/* - * The __sync_* family of intrinsics is documented here: - * - * http://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/Atomic-Builtins.html - * - * While these intrinsics are deprecated in favor of the newer __atomic_* - * family of intrincs: - * - * http://gcc.gnu.org/onlinedocs/gcc-4.7.3/gcc/_005f_005fatomic-Builtins.html - * - * any GCC version that supports the __atomic_* intrinsics will also support - * the header and so will be handled above. We provide a version of - * atomics using the __sync_* intrinsics to support older versions of GCC. - * - * All __sync_* intrinsics that we use below act as full memory barriers, for - * both compiler and hardware reordering, except for __sync_lock_test_and_set, - * which is a only an acquire barrier. When we call __sync_lock_test_and_set, - * we add a barrier above it as appropriate. - */ - -template struct Barrier; - -/* - * Some processors (in particular, x86) don't require quite so many calls to - * __sync_sychronize as our specializations of Barrier produce. If - * performance turns out to be an issue, defining these specializations - * on a per-processor basis would be a good first tuning step. - */ - -template<> -struct Barrier -{ - static void beforeLoad() {} - static void afterLoad() {} - static void beforeStore() {} - static void afterStore() {} -}; - -template<> -struct Barrier -{ - static void beforeLoad() {} - static void afterLoad() { __sync_synchronize(); } - static void beforeStore() { __sync_synchronize(); } - static void afterStore() {} -}; - -template<> -struct Barrier -{ - static void beforeLoad() { __sync_synchronize(); } - static void afterLoad() { __sync_synchronize(); } - static void beforeStore() { __sync_synchronize(); } - static void afterStore() { __sync_synchronize(); } -}; - -template::value> -struct AtomicStorageType -{ - // For non-enums, just use the type directly. - typedef T Type; -}; - -template -struct AtomicStorageType - : Conditional -{ - static_assert(sizeof(T) == 4 || sizeof(T) == 8, - "wrong type computed in conditional above"); -}; - -template -struct IntrinsicMemoryOps -{ - typedef typename AtomicStorageType::Type ValueType; - - static T load(const ValueType& aPtr) - { - Barrier::beforeLoad(); - T val = T(aPtr); - Barrier::afterLoad(); - return val; - } - - static void store(ValueType& aPtr, T aVal) - { - Barrier::beforeStore(); - aPtr = ValueType(aVal); - Barrier::afterStore(); - } - - static T exchange(ValueType& aPtr, T aVal) - { - // __sync_lock_test_and_set is only an acquire barrier; loads and stores - // can't be moved up from after to before it, but they can be moved down - // from before to after it. We may want a stricter ordering, so we need - // an explicit barrier. - Barrier::beforeStore(); - return T(__sync_lock_test_and_set(&aPtr, ValueType(aVal))); - } - - static bool compareExchange(ValueType& aPtr, T aOldVal, T aNewVal) - { - return __sync_bool_compare_and_swap(&aPtr, ValueType(aOldVal), ValueType(aNewVal)); - } -}; - -template -struct IntrinsicAddSub - : public IntrinsicMemoryOps -{ - typedef IntrinsicMemoryOps Base; - typedef typename Base::ValueType ValueType; - - static T add(ValueType& aPtr, T aVal) - { - return T(__sync_fetch_and_add(&aPtr, ValueType(aVal))); - } - - static T sub(ValueType& aPtr, T aVal) - { - return T(__sync_fetch_and_sub(&aPtr, ValueType(aVal))); - } -}; - -template -struct IntrinsicAddSub - : public IntrinsicMemoryOps -{ - typedef IntrinsicMemoryOps Base; - typedef typename Base::ValueType ValueType; - - /* - * The reinterpret_casts are needed so that - * __sync_fetch_and_{add,sub} will properly type-check. - * - * Also, these functions do not provide standard semantics for - * pointer types, so we need to adjust the addend. - */ - static ValueType add(ValueType& aPtr, ptrdiff_t aVal) - { - ValueType amount = reinterpret_cast(aVal * sizeof(T)); - return __sync_fetch_and_add(&aPtr, amount); - } - - static ValueType sub(ValueType& aPtr, ptrdiff_t aVal) - { - ValueType amount = reinterpret_cast(aVal * sizeof(T)); - return __sync_fetch_and_sub(&aPtr, amount); - } -}; - -template -struct IntrinsicIncDec : public IntrinsicAddSub -{ - typedef IntrinsicAddSub Base; - typedef typename Base::ValueType ValueType; +template +struct AtomicIntrinsics : public IntrinsicMemoryOps, + public IntrinsicIncDec {}; - static T inc(ValueType& aPtr) { return Base::add(aPtr, 1); } - static T dec(ValueType& aPtr) { return Base::sub(aPtr, 1); } +template +struct ToStorageTypeArgument { + static constexpr T convert(T aT) { return aT; } }; -template -struct AtomicIntrinsics : public IntrinsicIncDec -{ - static T or_( T& aPtr, T aVal) { return __sync_fetch_and_or(&aPtr, aVal); } - static T xor_(T& aPtr, T aVal) { return __sync_fetch_and_xor(&aPtr, aVal); } - static T and_(T& aPtr, T aVal) { return __sync_fetch_and_and(&aPtr, aVal); } -}; - -template -struct AtomicIntrinsics : public IntrinsicIncDec -{ -}; - -template::value> -struct ToStorageTypeArgument -{ - typedef typename AtomicStorageType::Type ResultType; - - static constexpr ResultType convert (T aT) { return ResultType(aT); } -}; - -template -struct ToStorageTypeArgument -{ - static constexpr T convert (T aT) { return aT; } -}; - -} // namespace detail -} // namespace mozilla - -#else -# error "Atomic compiler intrinsics are not supported on your platform" -#endif - -namespace mozilla { - -namespace detail { - -template -class AtomicBase -{ +template +class AtomicBase { static_assert(sizeof(T) == 4 || sizeof(T) == 8, "mozilla/Atomics.h only supports 32-bit and 64-bit types"); -protected: + protected: typedef typename detail::AtomicIntrinsics Intrinsics; typedef typename Intrinsics::ValueType ValueType; ValueType mValue; -public: + public: constexpr AtomicBase() : mValue() {} explicit constexpr AtomicBase(T aInit) - : mValue(ToStorageTypeArgument::convert(aInit)) - {} + : mValue(ToStorageTypeArgument::convert(aInit)) {} // Note: we can't provide operator T() here because Atomic inherits // from AtomcBase with T=uint32_t and not T=bool. If we implemented // operator T() here, it would cause errors when comparing Atomic with // a regular bool. - T operator=(T aVal) - { + T operator=(T aVal) { Intrinsics::store(mValue, aVal); return aVal; } @@ -566,10 +302,7 @@ * Performs an atomic swap operation. aVal is stored and the previous * value of this variable is returned. */ - T exchange(T aVal) - { - return Intrinsics::exchange(mValue, aVal); - } + T exchange(T aVal) { return Intrinsics::exchange(mValue, aVal); } /** * Performs an atomic compare-and-swap operation and returns true if it @@ -582,22 +315,20 @@ * return false; * } */ - bool compareExchange(T aOldValue, T aNewValue) - { + bool compareExchange(T aOldValue, T aNewValue) { return Intrinsics::compareExchange(mValue, aOldValue, aNewValue); } -private: - template + private: + template AtomicBase(const AtomicBase& aCopy) = delete; }; -template -class AtomicBaseIncDec : public AtomicBase -{ +template +class AtomicBaseIncDec : public AtomicBase { typedef typename detail::AtomicBase Base; -public: + public: constexpr AtomicBaseIncDec() : Base() {} explicit constexpr AtomicBaseIncDec(T aInit) : Base(aInit) {} @@ -609,12 +340,12 @@ T operator++() { return Base::Intrinsics::inc(Base::mValue) + 1; } T operator--() { return Base::Intrinsics::dec(Base::mValue) - 1; } -private: - template + private: + template AtomicBaseIncDec(const AtomicBaseIncDec& aCopy) = delete; }; -} // namespace detail +} // namespace detail /** * A wrapper for a type that enforces that all memory accesses are atomic. @@ -633,9 +364,8 @@ * deliberate design choice that enables static atomic variables to be declared * without introducing extra static constructors. */ -template +template class Atomic; /** @@ -646,45 +376,40 @@ * corresponding read-modify-write operation atomically. Finally, an atomic * swap method is provided. */ -template -class Atomic::value && - !IsSame::value>::Type> - : public detail::AtomicBaseIncDec -{ +template +class Atomic< + T, Order, + typename EnableIf::value && !IsSame::value>::Type> + : public detail::AtomicBaseIncDec { typedef typename detail::AtomicBaseIncDec Base; -public: + public: constexpr Atomic() : Base() {} explicit constexpr Atomic(T aInit) : Base(aInit) {} using Base::operator=; - T operator+=(T aDelta) - { + T operator+=(T aDelta) { return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta; } - T operator-=(T aDelta) - { + T operator-=(T aDelta) { return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta; } - T operator|=(T aVal) - { + T operator|=(T aVal) { return Base::Intrinsics::or_(Base::mValue, aVal) | aVal; } - T operator^=(T aVal) - { + T operator^=(T aVal) { return Base::Intrinsics::xor_(Base::mValue, aVal) ^ aVal; } - T operator&=(T aVal) - { + T operator&=(T aVal) { return Base::Intrinsics::and_(Base::mValue, aVal) & aVal; } -private: + private: Atomic(Atomic& aOther) = delete; }; @@ -696,28 +421,25 @@ * assignment operators for addition and subtraction. Atomic swap (via * exchange()) is included as well. */ -template -class Atomic : public detail::AtomicBaseIncDec -{ +template +class Atomic : public detail::AtomicBaseIncDec { typedef typename detail::AtomicBaseIncDec Base; -public: + public: constexpr Atomic() : Base() {} explicit constexpr Atomic(T* aInit) : Base(aInit) {} using Base::operator=; - T* operator+=(ptrdiff_t aDelta) - { + T* operator+=(ptrdiff_t aDelta) { return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta; } - T* operator-=(ptrdiff_t aDelta) - { + T* operator-=(ptrdiff_t aDelta) { return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta; } -private: + private: Atomic(Atomic& aOther) = delete; }; @@ -726,13 +448,12 @@ * * The atomic store and load operations and the atomic swap method is provided. */ -template +template class Atomic::value>::Type> - : public detail::AtomicBase -{ + : public detail::AtomicBase { typedef typename detail::AtomicBase Base; -public: + public: constexpr Atomic() : Base() {} explicit constexpr Atomic(T aInit) : Base(aInit) {} @@ -740,7 +461,7 @@ using Base::operator=; -private: + private: Atomic(Atomic& aOther) = delete; }; @@ -760,41 +481,35 @@ * runtime library are not available on Windows XP. This is why we implement * Atomic with an underlying type of uint32_t. */ -template -class Atomic - : protected detail::AtomicBase -{ +template +class Atomic : protected detail::AtomicBase { typedef typename detail::AtomicBase Base; -public: + public: constexpr Atomic() : Base() {} explicit constexpr Atomic(bool aInit) : Base(aInit) {} // We provide boolean wrappers for the underlying AtomicBase methods. - MOZ_IMPLICIT operator bool() const - { + MOZ_IMPLICIT operator bool() const { return Base::Intrinsics::load(Base::mValue); } - bool operator=(bool aVal) - { - return Base::operator=(aVal); - } + bool operator=(bool aVal) { return Base::operator=(aVal); } - bool exchange(bool aVal) - { - return Base::exchange(aVal); - } + bool exchange(bool aVal) { return Base::exchange(aVal); } - bool compareExchange(bool aOldValue, bool aNewValue) - { + bool compareExchange(bool aOldValue, bool aNewValue) { return Base::compareExchange(aOldValue, aNewValue); } -private: + private: Atomic(Atomic& aOther) = delete; }; -} // namespace mozilla +// If you want to atomically swap two atomic values, use exchange(). +template +void Swap(Atomic&, Atomic&) = delete; + +} // namespace mozilla #endif /* mozilla_Atomics_h */ 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 @@ -22,19 +22,19 @@ * compiler to inline even in DEBUG builds. It should be used very rarely. */ #if defined(_MSC_VER) -# define MOZ_ALWAYS_INLINE_EVEN_DEBUG __forceinline +#define MOZ_ALWAYS_INLINE_EVEN_DEBUG __forceinline #elif defined(__GNUC__) -# define MOZ_ALWAYS_INLINE_EVEN_DEBUG __attribute__((always_inline)) inline +#define MOZ_ALWAYS_INLINE_EVEN_DEBUG __attribute__((always_inline)) inline #else -# define MOZ_ALWAYS_INLINE_EVEN_DEBUG inline +#define MOZ_ALWAYS_INLINE_EVEN_DEBUG inline #endif #if !defined(DEBUG) -# define MOZ_ALWAYS_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG +#define MOZ_ALWAYS_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG #elif defined(_MSC_VER) && !defined(__cplusplus) -# define MOZ_ALWAYS_INLINE __inline +#define MOZ_ALWAYS_INLINE __inline #else -# define MOZ_ALWAYS_INLINE inline +#define MOZ_ALWAYS_INLINE inline #endif #if defined(_MSC_VER) @@ -46,26 +46,28 @@ * Current versions of g++ do not correctly set __cplusplus, so we check both * for forward compatibility. */ -# define MOZ_HAVE_NEVER_INLINE __declspec(noinline) -# define MOZ_HAVE_NORETURN __declspec(noreturn) +#define MOZ_HAVE_NEVER_INLINE __declspec(noinline) +#define MOZ_HAVE_NORETURN __declspec(noreturn) #elif defined(__clang__) - /* - * Per Clang documentation, "Note that marketing version numbers should not - * be used to check for language features, as different vendors use different - * numbering schemes. Instead, use the feature checking macros." - */ -# ifndef __has_extension -# define __has_extension __has_feature /* compatibility, for older versions of clang */ -# endif -# if __has_attribute(noinline) -# define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) -# endif -# if __has_attribute(noreturn) -# define MOZ_HAVE_NORETURN __attribute__((noreturn)) -# endif +/* + * Per Clang documentation, "Note that marketing version numbers should not + * be used to check for language features, as different vendors use different + * numbering schemes. Instead, use the feature checking macros." + */ +#ifndef __has_extension +#define __has_extension \ + __has_feature /* compatibility, for older versions of clang */ +#endif +#if __has_attribute(noinline) +#define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) +#endif +#if __has_attribute(noreturn) +#define MOZ_HAVE_NORETURN __attribute__((noreturn)) +#endif #elif defined(__GNUC__) -# define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) -# define MOZ_HAVE_NORETURN __attribute__((noreturn)) +#define MOZ_HAVE_NEVER_INLINE __attribute__((noinline)) +#define MOZ_HAVE_NORETURN __attribute__((noreturn)) +#define MOZ_HAVE_NORETURN_PTR __attribute__((noreturn)) #endif /* @@ -73,9 +75,9 @@ * to mark some false positives */ #ifdef __clang_analyzer__ -# if __has_extension(attribute_analyzer_noreturn) -# define MOZ_HAVE_ANALYZER_NORETURN __attribute__((analyzer_noreturn)) -# endif +#if __has_extension(attribute_analyzer_noreturn) +#define MOZ_HAVE_ANALYZER_NORETURN __attribute__((analyzer_noreturn)) +#endif #endif /* @@ -85,9 +87,9 @@ * guaranteed to support this, but most do. */ #if defined(MOZ_HAVE_NEVER_INLINE) -# define MOZ_NEVER_INLINE MOZ_HAVE_NEVER_INLINE +#define MOZ_NEVER_INLINE MOZ_HAVE_NEVER_INLINE #else -# define MOZ_NEVER_INLINE /* no support */ +#define MOZ_NEVER_INLINE /* no support */ #endif /* @@ -102,12 +104,20 @@ * warnings about not initializing variables, or about any other seemingly-dodgy * operations performed after the function returns. * + * There are two variants. The GCC version of NORETURN may be applied to a + * function pointer, while for MSVC it may not. + * * This modifier does not affect the corresponding function's linking behavior. */ #if defined(MOZ_HAVE_NORETURN) -# define MOZ_NORETURN MOZ_HAVE_NORETURN +#define MOZ_NORETURN MOZ_HAVE_NORETURN #else -# define MOZ_NORETURN /* no support */ +#define MOZ_NORETURN /* no support */ +#endif +#if defined(MOZ_HAVE_NORETURN_PTR) +#define MOZ_NORETURN_PTR MOZ_HAVE_NORETURN_PTR +#else +#define MOZ_NORETURN_PTR /* no support */ #endif /** @@ -126,9 +136,9 @@ * MOZ_COLD int foo() { return 42; } */ #if defined(__GNUC__) || defined(__clang__) -# define MOZ_COLD __attribute__ ((cold)) +#define MOZ_COLD __attribute__((cold)) #else -# define MOZ_COLD +#define MOZ_COLD #endif /** @@ -142,9 +152,24 @@ * MOZ_NONNULL(1, 2) int foo(char *p, char *q); */ #if defined(__GNUC__) || defined(__clang__) -# define MOZ_NONNULL(...) __attribute__ ((nonnull(__VA_ARGS__))) +#define MOZ_NONNULL(...) __attribute__((nonnull(__VA_ARGS__))) #else -# define MOZ_NONNULL(...) +#define MOZ_NONNULL(...) +#endif + +/** + * MOZ_NONNULL_RETURN tells the compiler that the function's return value is + * guaranteed to be a non-null pointer, which may enable the compiler to + * optimize better at call sites. + * + * Place this attribute at the end of a function declaration. For example, + * + * char* foo(char *p, char *q) MOZ_NONNULL_RETURN; + */ +#if defined(__GNUC__) || defined(__clang__) +#define MOZ_NONNULL_RETURN __attribute__((returns_nonnull)) +#else +#define MOZ_NONNULL_RETURN #endif /* @@ -164,9 +189,9 @@ * */ #if defined(MOZ_HAVE_ANALYZER_NORETURN) -# define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS MOZ_HAVE_ANALYZER_NORETURN +#define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS MOZ_HAVE_ANALYZER_NORETURN #else -# define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS /* no support */ +#define MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS /* no support */ #endif /* @@ -177,19 +202,19 @@ * AddressSanitizer. */ #if defined(__has_feature) -# if __has_feature(address_sanitizer) -# define MOZ_HAVE_ASAN_BLACKLIST -# endif +#if __has_feature(address_sanitizer) +#define MOZ_HAVE_ASAN_BLACKLIST +#endif #elif defined(__GNUC__) -# if defined(__SANITIZE_ADDRESS__) -# define MOZ_HAVE_ASAN_BLACKLIST -# endif +#if defined(__SANITIZE_ADDRESS__) +#define MOZ_HAVE_ASAN_BLACKLIST +#endif #endif #if defined(MOZ_HAVE_ASAN_BLACKLIST) -# define MOZ_ASAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_address)) +#define MOZ_ASAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_address)) #else -# define MOZ_ASAN_BLACKLIST /* nothing */ +#define MOZ_ASAN_BLACKLIST /* nothing */ #endif /* @@ -199,15 +224,99 @@ * inlining currently breaks the blacklisting mechanism of ThreadSanitizer. */ #if defined(__has_feature) -# if __has_feature(thread_sanitizer) -# define MOZ_TSAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_thread)) -# else -# define MOZ_TSAN_BLACKLIST /* nothing */ -# endif +#if __has_feature(thread_sanitizer) +#define MOZ_TSAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_thread)) +#else +#define MOZ_TSAN_BLACKLIST /* nothing */ +#endif +#else +#define MOZ_TSAN_BLACKLIST /* nothing */ +#endif + +#if defined(__has_attribute) +#if __has_attribute(no_sanitize) +#define MOZ_HAVE_NO_SANITIZE_ATTR +#endif +#endif + +#ifdef __clang__ +#ifdef MOZ_HAVE_NO_SANITIZE_ATTR +#define MOZ_HAVE_UNSIGNED_OVERFLOW_SANITIZE_ATTR +#define MOZ_HAVE_SIGNED_OVERFLOW_SANITIZE_ATTR +#endif +#endif + +/* + * MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW disables *un*signed integer overflow + * checking on the function it annotates, in builds configured to perform it. + * (Currently this is only Clang using -fsanitize=unsigned-integer-overflow, or + * via --enable-unsigned-overflow-sanitizer in Mozilla's build system.) It has + * no effect in other builds. + * + * Place this attribute at the very beginning of a function declaration. + * + * Unsigned integer overflow isn't *necessarily* a bug. It's well-defined in + * C/C++, and code may reasonably depend upon it. For example, + * + * MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW inline bool + * IsDecimal(char aChar) + * { + * // For chars less than '0', unsigned integer underflow occurs, to a value + * // much greater than 10, so the overall test is false. + * // For chars greater than '0', no overflow occurs, and only '0' to '9' + * // pass the overall test. + * return static_cast(aChar) - '0' < 10; + * } + * + * But even well-defined unsigned overflow often causes bugs when it occurs, so + * it should be restricted to functions annotated with this attribute. + * + * The compiler instrumentation to detect unsigned integer overflow has costs + * both at compile time and at runtime. Functions that are repeatedly inlined + * at compile time will also implicitly inline the necessary instrumentation, + * increasing compile time. Similarly, frequently-executed functions that + * require large amounts of instrumentation will also notice significant runtime + * slowdown to execute that instrumentation. Use this attribute to eliminate + * those costs -- but only after carefully verifying that no overflow can occur. + */ +#ifdef MOZ_HAVE_UNSIGNED_OVERFLOW_SANITIZE_ATTR +#define MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW \ + __attribute__((no_sanitize("unsigned-integer-overflow"))) +#else +#define MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW /* nothing */ +#endif + +/* + * MOZ_NO_SANITIZE_SIGNED_OVERFLOW disables *signed* integer overflow checking + * on the function it annotates, in builds configured to perform it. (Currently + * this is only Clang using -fsanitize=signed-integer-overflow, or via + * --enable-signed-overflow-sanitizer in Mozilla's build system. GCC support + * will probably be added in the future.) It has no effect in other builds. + * + * Place this attribute at the very beginning of a function declaration. + * + * Signed integer overflow is undefined behavior in C/C++: *anything* can happen + * when it occurs. *Maybe* wraparound behavior will occur, but maybe also the + * compiler will assume no overflow happens and will adversely optimize the rest + * of your code. Code that contains signed integer overflow needs to be fixed. + * + * The compiler instrumentation to detect signed integer overflow has costs both + * at compile time and at runtime. Functions that are repeatedly inlined at + * compile time will also implicitly inline the necessary instrumentation, + * increasing compile time. Similarly, frequently-executed functions that + * require large amounts of instrumentation will also notice significant runtime + * slowdown to execute that instrumentation. Use this attribute to eliminate + * those costs -- but only after carefully verifying that no overflow can occur. + */ +#ifdef MOZ_HAVE_SIGNED_OVERFLOW_SANITIZE_ATTR +#define MOZ_NO_SANITIZE_SIGNED_OVERFLOW \ + __attribute__((no_sanitize("signed-integer-overflow"))) #else -# define MOZ_TSAN_BLACKLIST /* nothing */ +#define MOZ_NO_SANITIZE_SIGNED_OVERFLOW /* nothing */ #endif +#undef MOZ_HAVE_NO_SANITIZE_ATTR + /** * MOZ_ALLOCATOR tells the compiler that the function it marks returns either a * "fresh", "pointer-free" block of memory, or nullptr. "Fresh" means that the @@ -232,9 +341,9 @@ * void *my_allocator(size_t bytes) MOZ_ALLOCATOR { ... } */ #if defined(__GNUC__) || defined(__clang__) -# define MOZ_ALLOCATOR __attribute__ ((malloc, warn_unused_result)) +#define MOZ_ALLOCATOR __attribute__((malloc, warn_unused_result)) #else -# define MOZ_ALLOCATOR +#define MOZ_ALLOCATOR #endif /** @@ -245,17 +354,58 @@ * example, write * * MOZ_MUST_USE int foo(); + * or + * MOZ_MUST_USE int foo() { return 42; } + * + * MOZ_MUST_USE is most appropriate for functions where the return value is + * some kind of success/failure indicator -- often |nsresult|, |bool| or |int| + * -- because these functions are most commonly the ones that have missing + * checks. There are three cases of note. + * + * - Fallible functions whose return values should always be checked. For + * example, a function that opens a file should always be checked because any + * subsequent operations on the file will fail if opening it fails. Such + * functions should be given a MOZ_MUST_USE annotation. + * + * - Fallible functions whose return value need not always be checked. For + * example, a function that closes a file might not be checked because it's + * common that no further operations would be performed on the file. Such + * functions do not need a MOZ_MUST_USE annotation. + * + * - Infallible functions, i.e. ones that always return a value indicating + * success. These do not need a MOZ_MUST_USE annotation. Ideally, they would + * be converted to not return a success/failure indicator, though sometimes + * interface constraints prevent this. + */ +#if defined(__GNUC__) || defined(__clang__) +#define MOZ_MUST_USE __attribute__((warn_unused_result)) +#else +#define MOZ_MUST_USE +#endif + +/** + * MOZ_MAYBE_UNUSED suppresses compiler warnings about functions that are + * never called (in this build configuration, at least). + * + * Place this attribute at the very beginning of a function declaration. For + * example, write + * + * MOZ_MAYBE_UNUSED int foo(); * * or * - * MOZ_MUST_USE int foo() { return 42; } + * MOZ_MAYBE_UNUSED int foo() { return 42; } */ #if defined(__GNUC__) || defined(__clang__) -# define MOZ_MUST_USE __attribute__ ((warn_unused_result)) +#define MOZ_MAYBE_UNUSED __attribute__((__unused__)) +#elif defined(_MSC_VER) +#define MOZ_MAYBE_UNUSED __pragma(warning(suppress : 4505)) #else -# define MOZ_MUST_USE +#define MOZ_MAYBE_UNUSED #endif +#ifdef __cplusplus + /** * MOZ_FALLTHROUGH is an annotation to suppress compiler warnings about switch * cases that fall through without a break or return statement. MOZ_FALLTHROUGH @@ -282,22 +432,25 @@ * return 5; * } */ -#if defined(__clang__) && __cplusplus >= 201103L - /* clang's fallthrough annotations are only available starting in C++11. */ -# define MOZ_FALLTHROUGH [[clang::fallthrough]] +#ifndef __has_cpp_attribute +#define __has_cpp_attribute(x) 0 +#endif + +#if __has_cpp_attribute(clang::fallthrough) +#define MOZ_FALLTHROUGH [[clang::fallthrough]] +#elif __has_cpp_attribute(gnu::fallthrough) +#define MOZ_FALLTHROUGH [[gnu::fallthrough]] #elif defined(_MSC_VER) - /* - * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis): - * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx - */ -# include -# define MOZ_FALLTHROUGH __fallthrough +/* + * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis): + * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx + */ +#include +#define MOZ_FALLTHROUGH __fallthrough #else -# define MOZ_FALLTHROUGH /* FALLTHROUGH */ +#define MOZ_FALLTHROUGH /* FALLTHROUGH */ #endif -#ifdef __cplusplus - /* * The following macros are attributes that support the static analysis plugin * included with Mozilla, and will be implemented (when such support is enabled) @@ -343,6 +496,13 @@ * * The static analyses that are performed by the plugin are as follows: * + * MOZ_CAN_RUN_SCRIPT: Applies to functions which can run script. Callers of + * this function must also be marked as MOZ_CAN_RUN_SCRIPT, and all refcounted + * arguments must be strongly held in the caller. + * MOZ_CAN_RUN_SCRIPT_BOUNDARY: Applies to functions which need to call + * MOZ_CAN_RUN_SCRIPT functions, but should not themselves be considered + * MOZ_CAN_RUN_SCRIPT. This is important for some bindings and low level code + * which need to opt out of the safety checks performed by MOZ_CAN_RUN_SCRIPT. * MOZ_MUST_OVERRIDE: Applies to all C++ member functions. All immediate * subclasses must provide an exact override of this method; if a subclass * does not override this method, the compiler will emit an error. This @@ -360,8 +520,8 @@ * expected to live on the stack or in static storage, so it is a compile-time * error to use it, or an array of such objects, as the type of a new * expression. If a member of another class uses this class, or if another - * class inherits from this class, then it is considered to be a non-heap class - * as well, although this attribute need not be provided in such cases. + * class inherits from this class, then it is considered to be a non-heap + * class as well, although this attribute need not be provided in such cases. * MOZ_HEAP_CLASS: Applies to all classes. Any class with this annotation is * expected to live on the heap, so it is a compile-time error to use it, or * an array of such objects, as the type of a variable declaration, or as a @@ -373,6 +533,10 @@ * class uses this class or if another class inherits from this class, then it * is considered to be a non-temporary class as well, although this attribute * need not be provided in such cases. + * MOZ_TEMPORARY_CLASS: Applies to all classes. Any class with this annotation + * is expected to only live in a temporary. If another class inherits from + * this class, then it is considered to be a non-temporary class as well, + * although this attribute need not be provided in such cases. * MOZ_RAII: Applies to all classes. Any class with this annotation is assumed * to be a RAII guard, which is expected to live on the stack in an automatic * allocation. It is prohibited from being allocated in a temporary, static @@ -395,6 +559,14 @@ * are disallowed by default unless they are marked as MOZ_IMPLICIT. This * attribute must be used for constructors which intend to provide implicit * conversions. + * MOZ_IS_REFPTR: Applies to class declarations of ref pointer to mark them as + * such for use with static-analysis. + * A ref pointer is an object wrapping a pointer and automatically taking care + * of its refcounting upon construction/destruction/transfer of ownership. + * This annotation implies MOZ_IS_SMARTPTR_TO_REFCOUNTED. + * MOZ_IS_SMARTPTR_TO_REFCOUNTED: Applies to class declarations of smart + * pointers to ref counted classes to mark them as such for use with + * static-analysis. * MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT: Applies to functions. Makes it a compile * time error to pass arithmetic expressions on variables to the function. * MOZ_OWNING_REF: Applies to declarations of pointers to reference counted @@ -409,25 +581,27 @@ * MOZ_NON_OWNING_REF: Applies to declarations of pointers to reference counted * types. This attribute tells the compiler that the raw pointer is a weak * reference, which is ensured to be valid by a guarantee that the reference - * will be nulled before the pointer becomes invalid. This can make the compiler - * ignore these pointers when validating the usage of pointers otherwise. + * will be nulled before the pointer becomes invalid. This can make the + * compiler ignore these pointers when validating the usage of pointers + * otherwise. * * Examples include an mOwner pointer, which is nulled by the owning class's * destructor, and is null-checked before dereferencing. - * MOZ_UNSAFE_REF: Applies to declarations of pointers to reference counted types. - * Occasionally there are non-owning references which are valid, but do not take - * the form of a MOZ_NON_OWNING_REF. Their safety may be dependent on the behaviour - * of API consumers. The string argument passed to this macro documents the safety - * conditions. This can make the compiler ignore these pointers when validating - * the usage of pointers elsewhere. - * - * Examples include an nsIAtom* member which is known at compile time to point to a - * static atom which is valid throughout the lifetime of the program, or an API which - * stores a pointer, but doesn't take ownership over it, instead requiring the API - * consumer to correctly null the value before it becomes invalid. + * MOZ_UNSAFE_REF: Applies to declarations of pointers to reference counted + * types. Occasionally there are non-owning references which are valid, but + * do not take the form of a MOZ_NON_OWNING_REF. Their safety may be + * dependent on the behaviour of API consumers. The string argument passed + * to this macro documents the safety conditions. This can make the compiler + * ignore these pointers when validating the usage of pointers elsewhere. + * + * Examples include an nsAtom* member which is known at compile time to point + * to a static atom which is valid throughout the lifetime of the program, or + * an API which stores a pointer, but doesn't take ownership over it, instead + * requiring the API consumer to correctly null the value before it becomes + * invalid. * - * Use of this annotation is discouraged when a strong reference or one of the above - * two annotations can be used instead. + * Use of this annotation is discouraged when a strong reference or one of + * the above two annotations can be used instead. * MOZ_NO_ADDREF_RELEASE_ON_RETURN: Applies to function declarations. Makes it * a compile time error to call AddRef or Release on the return value of a * function. This is intended to be used with operator->() of our smart @@ -437,8 +611,8 @@ * 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. + * a compile time error to instantiate this template with a type parameter + * which has a VTable. * MOZ_NON_MEMMOVABLE: Applies to class declarations for types that are not safe * to be moved in memory using memmove(). * MOZ_NEEDS_MEMMOVABLE_TYPE: Applies to template class declarations where the @@ -448,6 +622,14 @@ * 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_NO_DANGLING_ON_TEMPORARIES: Applies to method declarations which return + * a pointer that is freed when the destructor of the class is called. This + * prevents these methods from being called on temporaries of the class, + * reducing risks of use-after-free. + * This attribute cannot be applied to && methods. + * In some cases, adding a deleted &&-qualified overload is too restrictive as + * this method should still be callable as a non-escaping argument to another + * function. This annotation can be used in those cases. * 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 @@ -455,118 +637,139 @@ * 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. + * 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. + * 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_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. + * 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. + * MOZ_MUST_RETURN_FROM_CALLER: Applies to function or method declarations. + * Callers of the annotated function/method must return from that function + * within the calling block using an explicit `return` statement. + * Only calls to Constructors, references to local and member variables, + * and calls to functions or methods marked as MOZ_MAY_CALL_AFTER_MUST_RETURN + * may be made after the MUST_RETURN_FROM_CALLER call. + * MOZ_MAY_CALL_AFTER_MUST_RETURN: Applies to function or method declarations. + * Calls to these methods may be made in functions after calls a + * MOZ_MUST_RETURN_FROM_CALLER function or method. */ #ifdef MOZ_CLANG_PLUGIN -# define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override"))) -# define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) -# define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class"))) -# define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class"))) -# define MOZ_NON_TEMPORARY_CLASS __attribute__((annotate("moz_non_temporary_class"))) -# define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor"))) -# ifdef DEBUG - /* in debug builds, these classes do have non-trivial constructors. */ -# define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class"))) -# else -# define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class"))) \ - MOZ_TRIVIAL_CTOR_DTOR -# endif -# define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) -# define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT __attribute__((annotate("moz_no_arith_expr_in_arg"))) -# define MOZ_OWNING_REF __attribute__((annotate("moz_strong_ref"))) -# 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_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"))) +#define MOZ_CAN_RUN_SCRIPT __attribute__((annotate("moz_can_run_script"))) +#define MOZ_CAN_RUN_SCRIPT_BOUNDARY \ + __attribute__((annotate("moz_can_run_script_boundary"))) +#define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override"))) +#define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) +#define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class"))) +#define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class"))) +#define MOZ_NON_TEMPORARY_CLASS \ + __attribute__((annotate("moz_non_temporary_class"))) +#define MOZ_TEMPORARY_CLASS __attribute__((annotate("moz_temporary_class"))) +#define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor"))) +#ifdef DEBUG +/* in debug builds, these classes do have non-trivial constructors. */ +#define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS \ + __attribute__((annotate("moz_global_class"))) +#else +#define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS \ + __attribute__((annotate("moz_global_class"))) MOZ_TRIVIAL_CTOR_DTOR +#endif +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) +#define MOZ_IS_SMARTPTR_TO_REFCOUNTED \ + __attribute__((annotate("moz_is_smartptr_to_refcounted"))) +#define MOZ_IS_REFPTR \ + __attribute__((annotate("moz_is_refptr"))) MOZ_IS_SMARTPTR_TO_REFCOUNTED +#define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT \ + __attribute__((annotate("moz_no_arith_expr_in_arg"))) +#define MOZ_OWNING_REF __attribute__((annotate("moz_strong_ref"))) +#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_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_NO_DANGLING_ON_TEMPORARIES \ + __attribute__((annotate("moz_no_dangling_on_temporaries"))) +#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"))) +#define MOZ_MUST_RETURN_FROM_CALLER \ + __attribute__((annotate("moz_must_return_from_caller"))) +#define MOZ_MAY_CALL_AFTER_MUST_RETURN \ + __attribute__((annotate("moz_may_call_after_must_return"))) /* * 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 * anyways, so the warning is safe to ignore. */ -# define MOZ_HEAP_ALLOCATOR \ - _Pragma("clang diagnostic push") \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((annotate("moz_heap_allocator"))) \ - _Pragma("clang diagnostic pop") -#else -# define MOZ_MUST_OVERRIDE /* nothing */ -# define MOZ_STACK_CLASS /* nothing */ -# define MOZ_NONHEAP_CLASS /* nothing */ -# define MOZ_HEAP_CLASS /* nothing */ -# define MOZ_NON_TEMPORARY_CLASS /* nothing */ -# define MOZ_TRIVIAL_CTOR_DTOR /* nothing */ -# define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS /* nothing */ -# define MOZ_IMPLICIT /* nothing */ -# define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT /* nothing */ -# define MOZ_HEAP_ALLOCATOR /* nothing */ -# define MOZ_OWNING_REF /* nothing */ -# define MOZ_NON_OWNING_REF /* nothing */ -# define MOZ_UNSAFE_REF(reason) /* nothing */ -# define MOZ_NO_ADDREF_RELEASE_ON_RETURN /* 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_HEAP_ALLOCATOR \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((annotate("moz_heap_allocator"))) \ + _Pragma("clang diagnostic pop") +#else +#define MOZ_CAN_RUN_SCRIPT /* nothing */ +#define MOZ_CAN_RUN_SCRIPT_BOUNDARY /* nothing */ +#define MOZ_MUST_OVERRIDE /* nothing */ +#define MOZ_STACK_CLASS /* nothing */ +#define MOZ_NONHEAP_CLASS /* nothing */ +#define MOZ_HEAP_CLASS /* nothing */ +#define MOZ_NON_TEMPORARY_CLASS /* nothing */ +#define MOZ_TEMPORARY_CLASS /* nothing */ +#define MOZ_TRIVIAL_CTOR_DTOR /* nothing */ +#define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS /* nothing */ +#define MOZ_IMPLICIT /* nothing */ +#define MOZ_IS_SMARTPTR_TO_REFCOUNTED /* nothing */ +#define MOZ_IS_REFPTR /* nothing */ +#define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT /* nothing */ +#define MOZ_HEAP_ALLOCATOR /* nothing */ +#define MOZ_OWNING_REF /* nothing */ +#define MOZ_NON_OWNING_REF /* nothing */ +#define MOZ_UNSAFE_REF(reason) /* nothing */ +#define MOZ_NO_ADDREF_RELEASE_ON_RETURN /* 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_NO_DANGLING_ON_TEMPORARIES /* 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 */ +#define MOZ_MUST_RETURN_FROM_CALLER /* nothing */ +#define MOZ_MAY_CALL_AFTER_MUST_RETURN /* nothing */ +#endif /* MOZ_CLANG_PLUGIN */ #define MOZ_RAII MOZ_NON_TEMPORARY_CLASS MOZ_STACK_CLASS -/* - * MOZ_HAVE_REF_QUALIFIERS is defined for compilers that support C++11's rvalue - * qualifier, "&&". - */ -#if defined(_MSC_VER) && _MSC_VER >= 1900 -# define MOZ_HAVE_REF_QUALIFIERS -#elif defined(__clang__) -// All supported Clang versions -# define MOZ_HAVE_REF_QUALIFIERS -#elif defined(__GNUC__) -# include "mozilla/Compiler.h" -# if MOZ_GCC_VERSION_AT_LEAST(4, 8, 1) -# define MOZ_HAVE_REF_QUALIFIERS -# endif -#endif - #endif /* __cplusplus */ /** @@ -589,16 +792,40 @@ * then the annotation would be: * MOZ_FORMAT_PRINTF(3, 4) * + * The second argument should be 0 for vprintf-like functions; that + * is, those taking a va_list argument. + * * 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))) + * + * MinGW requires special handling due to different format specifiers + * on different platforms. The macro __MINGW_PRINTF_FORMAT maps to + * either gnu_printf or ms_printf depending on where we are compiling + * to avoid warnings on format specifiers that are legal. + */ +#ifdef __MINGW32__ +#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) \ + __attribute__((format(__MINGW_PRINTF_FORMAT, stringIndex, firstToCheck))) +#elif __GNUC__ +#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) \ + __attribute__((format(printf, stringIndex, firstToCheck))) #else #define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) #endif +/** + * To manually declare an XPCOM ABI-compatible virtual function, the following + * macros can be used to handle the non-standard ABI used on Windows for COM + * compatibility. E.g.: + * + * virtual ReturnType MOZ_XPCOM_ABI foo(); + */ +#if defined(XP_WIN) +#define MOZ_XPCOM_ABI __stdcall +#else +#define MOZ_XPCOM_ABI +#endif + #endif /* mozilla_Attributes_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/AutoProfilerLabel.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/AutoProfilerLabel.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/AutoProfilerLabel.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 2; 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_AutoProfilerLabel_h +#define mozilla_AutoProfilerLabel_h + +#include "mozilla/Attributes.h" +#include "mozilla/GuardObjects.h" +#include "mozilla/Types.h" + +// The Gecko Profiler defines AutoProfilerLabel, an RAII class for +// pushing/popping entries to/from the PseudoStack. +// +// This file defines a class of the same name that does much the same thing, +// but which can be used in (and only in) mozglue. A different class is +// necessary because mozglue cannot directly access sPseudoStack. +// +// Note that this class is slightly slower than the other AutoProfilerLabel, +// and it lacks the macro wrappers. It also is effectively hardwired to use +// js::ProfileEntry::Kind::CPP_NORMAL as the kind, and +// js::ProfileEntry::Category::OTHER as the category, because that's what the +// callbacks provided by the profiler use. (Specifying the kind or category in +// this file would require #including ProfilingStack.h in mozglue, which we +// don't want to do.) + +class PseudoStack; + +namespace mozilla { + +typedef PseudoStack* (*ProfilerLabelEnter)(const char*, const char*, void*, + uint32_t); +typedef void (*ProfilerLabelExit)(PseudoStack*); + +// Register callbacks that do the entry/exit work involving sPseudoStack. +MFBT_API void RegisterProfilerLabelEnterExit(ProfilerLabelEnter aEnter, + ProfilerLabelExit aExit); + +// This #ifdef prevents this AutoProfilerLabel from being defined in libxul, +// which would conflict with the one in the profiler. +#ifdef IMPL_MFBT + +class MOZ_RAII AutoProfilerLabel { + public: + AutoProfilerLabel(const char* aLabel, const char* aDynamicString, + uint32_t aLine MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + ~AutoProfilerLabel(); + + private: + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + PseudoStack* mPseudoStack; +}; + +#endif + +} // namespace mozilla + +#endif // mozilla_AutoProfilerLabel_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 @@ -57,17 +57,16 @@ * Vector sortedInts = ... * * size_t match; - * if (BinarySearchIf(sortedInts, 0, sortedInts.length(), Comparator(13), &match)) { - * printf("found 13 at %lu\n", match); + * if (BinarySearchIf(sortedInts, 0, sortedInts.length(), Comparator(13), + * &match)) { printf("found 13 at %lu\n", match); * } * */ -template -bool -BinarySearchIf(const Container& aContainer, size_t aBegin, size_t aEnd, - const Comparator& aCompare, size_t* aMatchOrInsertionPoint) -{ +template +bool BinarySearchIf(const Container& aContainer, size_t aBegin, size_t aEnd, + const Comparator& aCompare, + size_t* aMatchOrInsertionPoint) { MOZ_ASSERT(aBegin <= aEnd); size_t low = aBegin; @@ -97,13 +96,10 @@ namespace detail { -template -class BinarySearchDefaultComparator -{ -public: - explicit BinarySearchDefaultComparator(const T& aTarget) - : mTarget(aTarget) - {} +template +class BinarySearchDefaultComparator { + public: + explicit BinarySearchDefaultComparator(const T& aTarget) : mTarget(aTarget) {} template int operator()(const U& aVal) const { @@ -118,22 +114,20 @@ return 1; } -private: + private: const T& mTarget; }; -} // namespace detail +} // namespace detail template -bool -BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd, - T aTarget, size_t* aMatchOrInsertionPoint) -{ +bool BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd, + T aTarget, size_t* aMatchOrInsertionPoint) { return BinarySearchIf(aContainer, aBegin, aEnd, detail::BinarySearchDefaultComparator(aTarget), aMatchOrInsertionPoint); } -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_BinarySearch_h +#endif // mozilla_BinarySearch_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/BloomFilter.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/BloomFilter.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/BloomFilter.h @@ -52,9 +52,8 @@ * configurations. */ -template -class BloomFilter -{ +template +class BloomFilter { /* * A counting Bloom filter with 8-bit counters. For now we assume * that having two hash functions is enough, but we may revisit that @@ -103,9 +102,8 @@ * positive rate for N == 100 and to quite bad false positive * rates for larger N. */ -public: - BloomFilter() - { + public: + BloomFilter() { static_assert(KeySize <= kKeyShift, "KeySize too big"); // Should we have a custom operator new using calloc instead and @@ -145,35 +143,23 @@ void remove(uint32_t aHash); bool mightContain(uint32_t aHash) const; -private: + private: static const size_t kArraySize = (1 << KeySize); static const uint32_t kKeyMask = (1 << KeySize) - 1; static const uint32_t kKeyShift = 16; - static uint32_t hash1(uint32_t aHash) - { - return aHash & kKeyMask; - } - static uint32_t hash2(uint32_t aHash) - { + static uint32_t hash1(uint32_t aHash) { return aHash & kKeyMask; } + static uint32_t hash2(uint32_t aHash) { return (aHash >> kKeyShift) & kKeyMask; } - uint8_t& firstSlot(uint32_t aHash) - { - return mCounters[hash1(aHash)]; - } - uint8_t& secondSlot(uint32_t aHash) - { - return mCounters[hash2(aHash)]; - } + uint8_t& firstSlot(uint32_t aHash) { return mCounters[hash1(aHash)]; } + uint8_t& secondSlot(uint32_t aHash) { return mCounters[hash2(aHash)]; } - const uint8_t& firstSlot(uint32_t aHash) const - { + const uint8_t& firstSlot(uint32_t aHash) const { return mCounters[hash1(aHash)]; } - const uint8_t& secondSlot(uint32_t aHash) const - { + const uint8_t& secondSlot(uint32_t aHash) const { return mCounters[hash2(aHash)]; } @@ -182,17 +168,13 @@ uint8_t mCounters[kArraySize]; }; -template -inline void -BloomFilter::clear() -{ +template +inline void BloomFilter::clear() { memset(mCounters, 0, kArraySize); } -template -inline void -BloomFilter::add(uint32_t aHash) -{ +template +inline void BloomFilter::add(uint32_t aHash) { uint8_t& slot1 = firstSlot(aHash); if (MOZ_LIKELY(!full(slot1))) { ++slot1; @@ -203,18 +185,14 @@ } } -template -MOZ_ALWAYS_INLINE void -BloomFilter::add(const T* aValue) -{ +template +MOZ_ALWAYS_INLINE void BloomFilter::add(const T* aValue) { uint32_t hash = aValue->hash(); return add(hash); } -template -inline void -BloomFilter::remove(uint32_t aHash) -{ +template +inline void BloomFilter::remove(uint32_t aHash) { // If the slots are full, we don't know whether we bumped them to be // there when we added or not, so just leave them full. uint8_t& slot1 = firstSlot(aHash); @@ -227,30 +205,26 @@ } } -template -MOZ_ALWAYS_INLINE void -BloomFilter::remove(const T* aValue) -{ +template +MOZ_ALWAYS_INLINE void BloomFilter::remove(const T* aValue) { uint32_t hash = aValue->hash(); remove(hash); } -template -MOZ_ALWAYS_INLINE bool -BloomFilter::mightContain(uint32_t aHash) const -{ +template +MOZ_ALWAYS_INLINE bool BloomFilter::mightContain( + uint32_t aHash) const { // Check that all the slots for this hash contain something return firstSlot(aHash) && secondSlot(aHash); } -template -MOZ_ALWAYS_INLINE bool -BloomFilter::mightContain(const T* aValue) const -{ +template +MOZ_ALWAYS_INLINE bool BloomFilter::mightContain( + const T* aValue) const { uint32_t hash = aValue->hash(); return mightContain(hash); } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_BloomFilter_h */ 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 @@ -10,6 +10,7 @@ #include #include "mozilla/AllocPolicy.h" #include "mozilla/Maybe.h" +#include "mozilla/MemoryReporting.h" #include "mozilla/Move.h" #include "mozilla/ScopeExit.h" #include "mozilla/Types.h" @@ -17,34 +18,27 @@ #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). +class InfallibleAllocPolicy; + namespace mozilla { -template -class BufferList : private AllocPolicy -{ +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 - { + 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) - { - } + : mData(aData), mSize(aSize), mCapacity(aCapacity) {} Segment(const Segment&) = delete; Segment& operator=(const Segment&) = delete; @@ -56,7 +50,7 @@ char* End() const { return mData + mSize; } }; - template + template friend class BufferList; public: @@ -68,24 +62,28 @@ 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 + // destroyed. If an infallible allocator is used, an initial buffer of size + // aInitialSize and capacity aInitialCapacity is allocated automatically. This + // data will be contiguous and can be accessed via |Start()|. If a fallible + // alloc policy is used, aInitialSize must be 0, and the fallible |Init()| + // method may be called instead. 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) - { + 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) { + MOZ_ASSERT((aInitialSize == 0 || + IsSame::value), + "BufferList may only be constructed with an initial size when " + "using an infallible alloc policy"); + AllocateSegment(aInitialSize, aInitialCapacity); } } @@ -93,19 +91,17 @@ BufferList(const BufferList& aOther) = delete; BufferList(BufferList&& aOther) - : mOwning(aOther.mOwning), - mSegments(Move(aOther.mSegments)), - mSize(aOther.mSize), - mStandardCapacity(aOther.mStandardCapacity) - { + : 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) - { + BufferList& operator=(BufferList&& aOther) { Clear(); mOwning = aOther.mOwning; @@ -118,11 +114,28 @@ ~BufferList() { Clear(); } + // Initializes the BufferList with a segment of the given size and capacity. + // May only be called once, before any segments have been allocated. + bool Init(size_t aInitialSize, size_t aInitialCapacity) { + MOZ_ASSERT(mSegments.empty()); + MOZ_ASSERT(aInitialCapacity != 0); + MOZ_ASSERT(aInitialCapacity % kSegmentAlignment == 0); + + return AllocateSegment(aInitialSize, aInitialCapacity); + } + // Returns the sum of the sizes of all the buffers. size_t Size() const { return mSize; } - void Clear() - { + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) { + size_t size = mSegments.sizeOfExcludingThis(aMallocSizeOf); + for (Segment& segment : mSegments) { + size += aMallocSizeOf(segment.Start()); + } + return size; + } + + void Clear() { if (mOwning) { for (Segment& segment : mSegments) { this->free_(segment.mData); @@ -135,10 +148,9 @@ // Iterates over bytes in the segments. You can advance it by as many bytes as // you choose. - class IterImpl - { + class IterImpl { // Invariants: - // (0) mSegment <= bufferList.mSegments.size() + // (0) mSegment <= bufferList.mSegments.length() // (1) mData <= mDataEnd // (2) If mSegment is not the last segment, mData < mDataEnd uintptr_t mSegment; @@ -147,12 +159,9 @@ friend class BufferList; - public: + public: explicit IterImpl(const BufferList& aBuffers) - : mSegment(0), - mData(nullptr), - mDataEnd(nullptr) - { + : mSegment(0), mData(nullptr), mDataEnd(nullptr) { if (!aBuffers.mSegments.empty()) { mData = aBuffers.mSegments[0].Start(); mDataEnd = aBuffers.mSegments[0].End(); @@ -161,24 +170,21 @@ // Returns a pointer to the raw data. It is valid to access up to // RemainingInSegment bytes of this buffer. - char* Data() const - { + 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 - { + 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 - { + size_t RemainingInSegment() const { MOZ_RELEASE_ASSERT(mData <= mDataEnd); return mDataEnd - mData; } @@ -187,8 +193,7 @@ // 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) - { + 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); @@ -209,8 +214,7 @@ // 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) - { + bool AdvanceAcrossSegments(const BufferList& aBuffers, size_t aBytes) { size_t bytes = aBytes; while (bytes) { size_t toAdvance = std::min(bytes, RemainingInSegment()); @@ -224,21 +228,19 @@ } // Returns true when the iterator reaches the end of the BufferList. - bool Done() const - { - return mData == mDataEnd; - } + 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 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++) { + for (uintptr_t segment = mSegment; segment < aTarget.mSegment; + segment++) { offset += aBuffers.mSegments[segment].End() - data; data = aBuffers.mSegments[segment].mData; } @@ -258,7 +260,10 @@ }; // Special convenience method that returns Iter().Data(). - char* Start() { return mSegments[0].mData; } + char* Start() { + MOZ_RELEASE_ASSERT(!mSegments.empty()); + return mSegments[0].mData; + } const char* Start() const { return mSegments[0].mData; } IterImpl Iter() const { return IterImpl(*this); } @@ -267,6 +272,11 @@ // bytes may be split across multiple buffers. Size() is increased by aSize. inline bool WriteBytes(const char* aData, size_t aSize); + // Allocates a buffer of at most |aMaxBytes| bytes and, if successful, returns + // that buffer, and places its size in |aSize|. If unsuccessful, returns null + // and leaves |aSize| undefined. + inline char* AllocateBytes(size_t aMaxSize, 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. @@ -278,9 +288,10 @@ // 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; + 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 @@ -288,8 +299,9 @@ // 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()); + 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. @@ -308,18 +320,28 @@ return start.BytesUntil(*this, end); } -private: - explicit BufferList(AllocPolicy aAP) - : AllocPolicy(aAP), - mOwning(false), - mSize(0), - mStandardCapacity(0) - { + // This takes ownership of the data + void* WriteBytesZeroCopy(char* aData, size_t aSize, size_t aCapacity) { + MOZ_ASSERT(aCapacity != 0); + MOZ_ASSERT(aSize <= aCapacity); + MOZ_ASSERT(mOwning); + + if (!mSegments.append(Segment(aData, aSize, aCapacity))) { + this->free_(aData); + return nullptr; + } + mSize += aSize; + return aData; } - void* AllocateSegment(size_t aSize, size_t aCapacity) - { + private: + explicit BufferList(AllocPolicy aAP) + : AllocPolicy(aAP), mOwning(false), mSize(0), mStandardCapacity(0) {} + + char* AllocateSegment(size_t aSize, size_t aCapacity) { MOZ_RELEASE_ASSERT(mOwning); + MOZ_ASSERT(aCapacity != 0); + MOZ_ASSERT(aSize <= aCapacity); char* data = this->template pod_malloc(aCapacity); if (!data) { @@ -339,48 +361,57 @@ size_t mStandardCapacity; }; -template -bool -BufferList::WriteBytes(const char* aData, size_t aSize) -{ +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; + while (copied < aSize) { + size_t toCopy; + char* data = AllocateBytes(aSize - copied, &toCopy); + if (!data) { + return false; + } + memcpy(data, aData + copied, toCopy); + copied += toCopy; + } + + return true; +} + +template +char* BufferList::AllocateBytes(size_t aMaxSize, size_t* aSize) { + MOZ_RELEASE_ASSERT(mOwning); + MOZ_RELEASE_ASSERT(mStandardCapacity); 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; + size_t capacity = lastSegment.mCapacity - lastSegment.mSize; + if (capacity) { + size_t size = std::min(aMaxSize, capacity); + char* data = lastSegment.mData + lastSegment.mSize; - copied += toCopy; - remaining -= toCopy; - } + lastSegment.mSize += size; + mSize += size; - while (remaining) { - size_t toCopy = std::min(remaining, mStandardCapacity); - - void* data = AllocateSegment(toCopy, mStandardCapacity); - if (!data) { - return false; + *aSize = size; + return data; } - memcpy(data, aData + copied, toCopy); - - copied += toCopy; - remaining -= toCopy; } - return true; + size_t size = std::min(aMaxSize, mStandardCapacity); + char* data = AllocateSegment(size, mStandardCapacity); + if (data) { + *aSize = size; + } + return data; } -template -bool -BufferList::ReadBytes(IterImpl& aIter, char* aData, size_t aSize) const -{ +template +bool BufferList::ReadBytes(IterImpl& aIter, char* aData, + size_t aSize) const { size_t copied = 0; size_t remaining = aSize; while (remaining) { @@ -399,18 +430,20 @@ return true; } -template template -BufferList -BufferList::Borrow(IterImpl& aIter, size_t aSize, bool* aSuccess, - BorrowingAllocPolicy aAP) const -{ +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))) { + if (!toAdvance || !result.mSegments.append( + typename BufferList::Segment( + aIter.mData, toAdvance, toAdvance))) { *aSuccess = false; return result; } @@ -423,17 +456,19 @@ return result; } -template template -BufferList -BufferList::MoveFallible(bool* aSuccess, OtherAllocPolicy aAP) -{ +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))) { + if (!toAdvance || + !result.mSegments.append(typename BufferList::Segment( + iter.mData, toAdvance, toAdvance))) { *aSuccess = false; result.mSegments.clear(); return result; @@ -448,10 +483,10 @@ return result; } -template -BufferList -BufferList::Extract(IterImpl& aIter, size_t aSize, bool* aSuccess) -{ +template +BufferList BufferList::Extract(IterImpl& aIter, + size_t aSize, + bool* aSuccess) { MOZ_RELEASE_ASSERT(aSize); MOZ_RELEASE_ASSERT(mOwning); MOZ_ASSERT(aSize % kSegmentAlignment == 0); @@ -526,10 +561,9 @@ // 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)); + 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 @@ -538,8 +572,8 @@ // 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)); + (aIter.mSegment == copyStart + segmentsToCopy) || + (aIter.Done() && aIter.mSegment == copyStart + segmentsToCopy - 1)); mSegments.erase(mSegments.begin() + copyStart, mSegments.begin() + copyStart + segmentsToCopy); @@ -549,7 +583,7 @@ if (lastSegmentSize.isSome()) { // We called reserve() on result.mSegments so infallibleAppend is safe. result.mSegments.infallibleAppend( - Segment(finalSegment, 0, mStandardCapacity)); + Segment(finalSegment, 0, mStandardCapacity)); bool r = result.WriteBytes(aIter.Data(), *lastSegmentSize); MOZ_RELEASE_ASSERT(r); aIter.Advance(*this, *lastSegmentSize); @@ -563,6 +597,6 @@ return result; } -} // namespace mozilla +} // 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 @@ -37,14 +37,11 @@ * important to you, you should use the outparam version. In all other cases, * you should use the direct return version. */ -template -inline void -BitwiseCast(const From aFrom, To* aResult) -{ +template +inline void BitwiseCast(const From aFrom, To* aResult) { static_assert(sizeof(From) == sizeof(To), "To and From must have the same size"); - union - { + union { From mFrom; To mTo; } u; @@ -52,10 +49,8 @@ *aResult = u.mTo; } -template -inline To -BitwiseCast(const From aFrom) -{ +template +inline To BitwiseCast(const From aFrom) { To temp; BitwiseCast(aFrom, &temp); return temp; @@ -66,10 +61,10 @@ enum ToSignedness { ToIsSigned, ToIsUnsigned }; enum FromSignedness { FromIsSigned, FromIsUnsigned }; -template::value ? FromIsSigned : FromIsUnsigned, - ToSignedness = IsSigned::value ? ToIsSigned : ToIsUnsigned> +template ::value ? FromIsSigned : FromIsUnsigned, + ToSignedness = IsSigned::value ? ToIsSigned : ToIsUnsigned> struct BoundsCheckImpl; // Implicit conversions on operands to binary operations make this all a bit @@ -81,50 +76,37 @@ // Unsigned-to-unsigned range check -template sizeof(To)) - ? FromIsBigger - : FromIsNotBigger> +template sizeof(To)) ? FromIsBigger : FromIsNotBigger> struct UnsignedUnsignedCheck; -template -struct UnsignedUnsignedCheck -{ -public: - static bool checkBounds(const From aFrom) - { - return aFrom <= From(To(-1)); - } +template +struct UnsignedUnsignedCheck { + public: + static bool checkBounds(const From aFrom) { return aFrom <= From(To(-1)); } }; -template -struct UnsignedUnsignedCheck -{ -public: - static bool checkBounds(const From aFrom) - { - return true; - } +template +struct UnsignedUnsignedCheck { + public: + static bool checkBounds(const From aFrom) { return true; } }; -template -struct BoundsCheckImpl -{ -public: - static bool checkBounds(const From aFrom) - { +template +struct BoundsCheckImpl { + public: + static bool checkBounds(const From aFrom) { return UnsignedUnsignedCheck::checkBounds(aFrom); } }; // Signed-to-unsigned range check -template -struct BoundsCheckImpl -{ -public: - static bool checkBounds(const From aFrom) - { +template +struct BoundsCheckImpl { + public: + static bool checkBounds(const From aFrom) { if (aFrom < 0) { return false; } @@ -139,105 +121,97 @@ enum USComparison { FromIsSmaller, FromIsNotSmaller }; -template +template struct UnsignedSignedCheck; -template -struct UnsignedSignedCheck -{ -public: - static bool checkBounds(const From aFrom) - { - return true; - } +template +struct UnsignedSignedCheck { + public: + static bool checkBounds(const From aFrom) { return true; } }; -template -struct UnsignedSignedCheck -{ -public: - static bool checkBounds(const From aFrom) - { +template +struct UnsignedSignedCheck { + public: + static bool checkBounds(const From aFrom) { const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1); return aFrom <= From(MaxValue); } }; -template -struct BoundsCheckImpl -{ -public: - static bool checkBounds(const From aFrom) - { +template +struct BoundsCheckImpl { + public: + static bool checkBounds(const From aFrom) { return UnsignedSignedCheck::checkBounds(aFrom); } }; // Signed-to-signed range check -template -struct BoundsCheckImpl -{ -public: - static bool checkBounds(const From aFrom) - { +template +struct BoundsCheckImpl { + public: + static bool checkBounds(const From aFrom) { if (sizeof(From) <= sizeof(To)) { return true; } const To MaxValue = To((1ULL << (CHAR_BIT * sizeof(To) - 1)) - 1); const To MinValue = -MaxValue - To(1); - return From(MinValue) <= aFrom && - From(aFrom) <= From(MaxValue); + return From(MinValue) <= aFrom && From(aFrom) <= From(MaxValue); } }; -template::value && - IsIntegral::value> +template ::value&& IsIntegral::value> class BoundsChecker; -template -class BoundsChecker -{ -public: +template +class BoundsChecker { + public: static bool checkBounds(const From aFrom) { return true; } }; -template -class BoundsChecker -{ -public: - static bool checkBounds(const From aFrom) - { +template +class BoundsChecker { + public: + static bool checkBounds(const From aFrom) { return BoundsCheckImpl::checkBounds(aFrom); } }; -template -inline bool -IsInBounds(const From aFrom) -{ +template +inline bool IsInBounds(const From aFrom) { return BoundsChecker::checkBounds(aFrom); } -} // namespace detail +} // namespace detail /** * Cast a value of integral type |From| to a value of integral type |To|, * asserting that the cast will be a safe cast per C++ (that is, that |to| is in * the range of values permitted for the type |From|). */ -template -inline To -AssertedCast(const From aFrom) -{ +template +inline To AssertedCast(const From aFrom) { MOZ_ASSERT((detail::IsInBounds(aFrom))); return static_cast(aFrom); } -} // namespace mozilla +/** + * Cast a value of integral type |From| to a value of integral type |To|, + * release asserting that the cast will be a safe cast per C++ (that is, that + * |to| is in the range of values permitted for the type |From|). + */ +template +inline To ReleaseAssertedCast(const From aFrom) { + MOZ_RELEASE_ASSERT((detail::IsInBounds(aFrom))); + return static_cast(aFrom); +} + +} // namespace mozilla #endif /* mozilla_Casting_h */ 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 @@ -35,23 +35,20 @@ namespace detail { extern MFBT_DATA Atomic gChaosModeCounter; extern MFBT_DATA ChaosFeature gChaosFeatures; -} // namespace detail +} // namespace detail /** * When "chaos mode" is activated, code that makes implicitly nondeterministic * choices is encouraged to make random and extreme choices, to test more * code paths and uncover bugs. */ -class ChaosMode -{ -public: - static void SetChaosFeature(ChaosFeature aChaosFeature) - { +class ChaosMode { + public: + static void SetChaosFeature(ChaosFeature aChaosFeature) { detail::gChaosFeatures = aChaosFeature; } - static bool isActive(ChaosFeature aFeature) - { + static bool isActive(ChaosFeature aFeature) { if (detail::gChaosModeCounter > 0) { return true; } @@ -64,16 +61,12 @@ * chaos mode state. If the activation level is nonzero all chaos mode * features are activated. */ - static void enterChaosMode() - { - detail::gChaosModeCounter++; - } + static void enterChaosMode() { detail::gChaosModeCounter++; } /** * Decrease the chaos mode activation level. See enterChaosMode(). */ - static void leaveChaosMode() - { + static void leaveChaosMode() { MOZ_ASSERT(detail::gChaosModeCounter > 0); detail::gChaosModeCounter--; } @@ -82,8 +75,7 @@ * Returns a somewhat (but not uniformly) random uint32_t < aBound. * Not to be used for anything except ChaosMode, since it's not very random. */ - static uint32_t randomUint32LessThan(uint32_t aBound) - { + static uint32_t randomUint32LessThan(uint32_t aBound) { MOZ_ASSERT(aBound != 0); return uint32_t(rand()) % aBound; } 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 @@ -18,83 +18,63 @@ */ #ifdef WIN32 -# define MOZ_USE_CHAR16_WRAPPER -# include - /** - * Win32 API extensively uses wchar_t, which is represented by a separated - * builtin type than char16_t per spec. It's not the case for MSVC prior to - * MSVC 2015, but other compilers follow the spec. We want to mix wchar_t and - * char16_t on Windows builds. This class is supposed to make it easier. It - * stores char16_t const pointer, but provides implicit casts for wchar_t as - * well. On other platforms, we simply use - * |typedef const char16_t* char16ptr_t|. Here, we want to make the class as - * similar to this typedef, including providing some casts that are allowed - * by the typedef. - */ -class char16ptr_t -{ -private: +#define MOZ_USE_CHAR16_WRAPPER +#include +#include "mozilla/Attributes.h" +/** + * Win32 API extensively uses wchar_t, which is represented by a separated + * builtin type than char16_t per spec. It's not the case for MSVC prior to + * MSVC 2015, but other compilers follow the spec. We want to mix wchar_t and + * char16_t on Windows builds. This class is supposed to make it easier. It + * stores char16_t const pointer, but provides implicit casts for wchar_t as + * well. On other platforms, we simply use + * |typedef const char16_t* char16ptr_t|. Here, we want to make the class as + * similar to this typedef, including providing some casts that are allowed + * by the typedef. + */ +class char16ptr_t { + private: const char16_t* mPtr; static_assert(sizeof(char16_t) == sizeof(wchar_t), "char16_t and wchar_t sizes differ"); -public: - char16ptr_t(const char16_t* aPtr) : mPtr(aPtr) {} - char16ptr_t(const wchar_t* aPtr) : - mPtr(reinterpret_cast(aPtr)) - {} + public: + MOZ_IMPLICIT char16ptr_t(const char16_t* aPtr) : mPtr(aPtr) {} + MOZ_IMPLICIT char16ptr_t(const wchar_t* aPtr) + : mPtr(reinterpret_cast(aPtr)) {} /* Without this, nullptr assignment would be ambiguous. */ - constexpr char16ptr_t(decltype(nullptr)) : mPtr(nullptr) {} + constexpr MOZ_IMPLICIT char16ptr_t(decltype(nullptr)) : mPtr(nullptr) {} - operator const char16_t*() const - { - return mPtr; - } - operator const wchar_t*() const - { + operator const char16_t*() const { return mPtr; } + operator const wchar_t*() const { return reinterpret_cast(mPtr); } - operator const void*() const - { - return mPtr; - } - operator bool() const - { - return mPtr != nullptr; + + operator wchar_t*() { + return const_cast(reinterpret_cast(mPtr)); } + operator const void*() const { return mPtr; } + explicit operator bool() const { return mPtr != nullptr; } + /* Explicit cast operators to allow things like (char16_t*)str. */ - explicit operator char16_t*() const - { - return const_cast(mPtr); - } - explicit operator wchar_t*() const - { + explicit operator char16_t*() const { return const_cast(mPtr); } + explicit operator wchar_t*() const { return const_cast(static_cast(*this)); } - explicit operator int() const - { - return reinterpret_cast(mPtr); - } - explicit operator unsigned int() const - { + explicit operator int() const { return reinterpret_cast(mPtr); } + explicit operator unsigned int() const { return reinterpret_cast(mPtr); } - explicit operator long() const - { - return reinterpret_cast(mPtr); - } - explicit operator unsigned long() const - { + explicit operator long() const { return reinterpret_cast(mPtr); } + explicit operator unsigned long() const { return reinterpret_cast(mPtr); } - explicit operator long long() const - { + explicit operator long long() const { return reinterpret_cast(mPtr); } - explicit operator unsigned long long() const - { + explicit operator unsigned long long() const { return reinterpret_cast(mPtr); } @@ -103,78 +83,51 @@ * WCHAR*. Supporting this requires explicit operators to support the * requisite explicit casts. */ - explicit operator const char*() const - { + explicit operator const char*() const { return reinterpret_cast(mPtr); } - explicit operator const unsigned char*() const - { + explicit operator const unsigned char*() const { return reinterpret_cast(mPtr); } - explicit operator unsigned char*() const - { - return - const_cast(reinterpret_cast(mPtr)); - } - explicit operator void*() const - { - return const_cast(mPtr); + explicit operator unsigned char*() const { + return const_cast( + reinterpret_cast(mPtr)); } + explicit operator void*() const { return const_cast(mPtr); } /* Some operators used on pointers. */ - char16_t operator[](size_t aIndex) const - { - return mPtr[aIndex]; - } - bool operator==(const char16ptr_t& aOther) const - { + char16_t operator[](size_t aIndex) const { return mPtr[aIndex]; } + bool operator==(const char16ptr_t& aOther) const { return mPtr == aOther.mPtr; } - bool operator==(decltype(nullptr)) const - { - return mPtr == nullptr; - } - bool operator!=(const char16ptr_t& aOther) const - { + bool operator==(decltype(nullptr)) const { return mPtr == nullptr; } + bool operator!=(const char16ptr_t& aOther) const { return mPtr != aOther.mPtr; } - bool operator!=(decltype(nullptr)) const - { - return mPtr != nullptr; - } - char16ptr_t operator+(int aValue) const - { - return char16ptr_t(mPtr + aValue); - } - char16ptr_t operator+(unsigned int aValue) const - { + bool operator!=(decltype(nullptr)) const { return mPtr != nullptr; } + char16ptr_t operator+(int aValue) const { return char16ptr_t(mPtr + aValue); } + char16ptr_t operator+(unsigned int aValue) const { return char16ptr_t(mPtr + aValue); } - char16ptr_t operator+(long aValue) const - { + char16ptr_t operator+(long aValue) const { return char16ptr_t(mPtr + aValue); } - char16ptr_t operator+(unsigned long aValue) const - { + char16ptr_t operator+(unsigned long aValue) const { return char16ptr_t(mPtr + aValue); } - char16ptr_t operator+(long long aValue) const - { + char16ptr_t operator+(long long aValue) const { return char16ptr_t(mPtr + aValue); } - char16ptr_t operator+(unsigned long long aValue) const - { + char16ptr_t operator+(unsigned long long aValue) const { return char16ptr_t(mPtr + aValue); } - ptrdiff_t operator-(const char16ptr_t& aOther) const - { + ptrdiff_t operator-(const char16ptr_t& aOther) const { return mPtr - aOther.mPtr; } }; -inline decltype((char*)0-(char*)0) -operator-(const char16_t* aX, const char16ptr_t aY) -{ +inline decltype((char*)0 - (char*)0) operator-(const char16_t* aX, + const char16ptr_t aY) { return aX - static_cast(aY); } Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/CheckedInt.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/CheckedInt.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/CheckedInt.h @@ -14,9 +14,27 @@ #include "mozilla/Attributes.h" #include "mozilla/IntegerTypeTraits.h" +// Probe for builtin math overflow support. Disabled for 32-bit builds for now +// since "gcc -m32" claims to support these but its implementation is buggy. +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82274 +#if defined(HAVE_64BIT_BUILD) +#if defined(__has_builtin) +#define MOZ_HAS_BUILTIN_OP_OVERFLOW (__has_builtin(__builtin_add_overflow)) +#elif defined(__GNUC__) +// (clang also defines __GNUC__ but it supports __has_builtin since at least +// v3.1 (released in 2012) so it won't get here.) +#define MOZ_HAS_BUILTIN_OP_OVERFLOW (__GNUC__ >= 5) +#else +#define MOZ_HAS_BUILTIN_OP_OVERFLOW (0) +#endif +#else +#define MOZ_HAS_BUILTIN_OP_OVERFLOW (0) +#endif + namespace mozilla { -template class CheckedInt; +template +class CheckedInt; namespace detail { @@ -33,94 +51,110 @@ struct UnsupportedType {}; -template -struct IsSupportedPass2 -{ +template +struct IsSupportedPass2 { static const bool value = false; }; -template -struct IsSupported -{ +template +struct IsSupported { static const bool value = IsSupportedPass2::value; }; -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - -template<> -struct IsSupported -{ static const bool value = true; }; - - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; - -template<> -struct IsSupportedPass2 -{ static const bool value = true; }; +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupported { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; + +template <> +struct IsSupportedPass2 { + static const bool value = true; +}; /* * Step 2: Implement the actual validity checks. @@ -128,25 +162,19 @@ * Ideas taken from IntegerLib, code different. */ -template -struct TwiceBiggerType -{ +template +struct TwiceBiggerType { typedef typename detail::StdintTypeForSizeAndSignedness< - sizeof(IntegerType) * 2, - IsSigned::value - >::Type Type; + sizeof(IntegerType) * 2, IsSigned::value>::Type Type; }; -template -struct TwiceBiggerType -{ +template +struct TwiceBiggerType { typedef UnsupportedType Type; }; -template -inline bool -HasSignBit(T aX) -{ +template +inline bool HasSignBit(T aX) { // In C++, right bit shifts on negative values is undefined by the standard. // Notice that signed-to-unsigned conversions are always well-defined in the // standard, as the value congruent modulo 2**n as expected. By contrast, @@ -157,104 +185,78 @@ // Bitwise ops may return a larger type, so it's good to use this inline // helper guaranteeing that the result is really of type T. -template -inline T -BinaryComplement(T aX) -{ +template +inline T BinaryComplement(T aX) { return ~aX; } -template::value, - bool IsUSigned = IsSigned::value> -struct DoesRangeContainRange -{ -}; +template ::value, + bool IsUSigned = IsSigned::value> +struct DoesRangeContainRange {}; -template -struct DoesRangeContainRange -{ +template +struct DoesRangeContainRange { static const bool value = sizeof(T) >= sizeof(U); }; -template -struct DoesRangeContainRange -{ +template +struct DoesRangeContainRange { static const bool value = sizeof(T) > sizeof(U); }; -template -struct DoesRangeContainRange -{ +template +struct DoesRangeContainRange { static const bool value = false; }; -template::value, - bool IsUSigned = IsSigned::value, - bool DoesTRangeContainURange = DoesRangeContainRange::value> +template ::value, + bool IsUSigned = IsSigned::value, + bool DoesTRangeContainURange = DoesRangeContainRange::value> struct IsInRangeImpl {}; -template -struct IsInRangeImpl -{ - static bool run(U) - { - return true; - } +template +struct IsInRangeImpl { + static bool constexpr run(U) { return true; } }; -template -struct IsInRangeImpl -{ - static bool run(U aX) - { +template +struct IsInRangeImpl { + static bool constexpr run(U aX) { return aX <= MaxValue::value && aX >= MinValue::value; } }; -template -struct IsInRangeImpl -{ - static bool run(U aX) - { - return aX <= MaxValue::value; - } +template +struct IsInRangeImpl { + static bool constexpr run(U aX) { return aX <= MaxValue::value; } }; -template -struct IsInRangeImpl -{ - static bool run(U aX) - { +template +struct IsInRangeImpl { + static bool constexpr run(U aX) { return sizeof(T) > sizeof(U) || aX <= U(MaxValue::value); } }; -template -struct IsInRangeImpl -{ - static bool run(U aX) - { - return sizeof(T) >= sizeof(U) - ? aX >= 0 - : aX >= 0 && aX <= U(MaxValue::value); +template +struct IsInRangeImpl { + static bool constexpr run(U aX) { + return sizeof(T) >= sizeof(U) ? aX >= 0 + : aX >= 0 && aX <= U(MaxValue::value); } }; -template -inline bool -IsInRange(U aX) -{ +template +inline constexpr bool IsInRange(U aX) { return IsInRangeImpl::run(aX); } -template -inline bool -IsAddValid(T aX, T aY) -{ +template +inline bool IsAddValid(T aX, T aY) { +#if MOZ_HAS_BUILTIN_OP_OVERFLOW + T dummy; + return !__builtin_add_overflow(aX, aY, &dummy); +#else // Addition is valid if the sign of aX+aY is equal to either that of aX or // that of aY. Since the value of aX+aY is undefined if we have a signed // type, we compute it using the unsigned type of the same size. Beware! @@ -265,14 +267,17 @@ typename MakeUnsigned::Type uy = aY; typename MakeUnsigned::Type result = ux + uy; return IsSigned::value - ? HasSignBit(BinaryComplement(T((result ^ aX) & (result ^ aY)))) - : BinaryComplement(aX) >= aY; + ? HasSignBit(BinaryComplement(T((result ^ aX) & (result ^ aY)))) + : BinaryComplement(aX) >= aY; +#endif } -template -inline bool -IsSubValid(T aX, T aY) -{ +template +inline bool IsSubValid(T aX, T aY) { +#if MOZ_HAS_BUILTIN_OP_OVERFLOW + T dummy; + return !__builtin_sub_overflow(aX, aY, &dummy); +#else // Subtraction is valid if either aX and aY have same sign, or aX-aY and aX // have same sign. Since the value of aX-aY is undefined if we have a signed // type, we compute it using the unsigned type of the same size. @@ -281,32 +286,28 @@ typename MakeUnsigned::Type result = ux - uy; return IsSigned::value - ? HasSignBit(BinaryComplement(T((result ^ aX) & (aX ^ aY)))) - : aX >= aY; + ? HasSignBit(BinaryComplement(T((result ^ aX) & (aX ^ aY)))) + : aX >= aY; +#endif } -template::value, - bool TwiceBiggerTypeIsSupported = - IsSupported::Type>::value> +template ::value, + bool TwiceBiggerTypeIsSupported = + IsSupported::Type>::value> struct IsMulValidImpl {}; -template -struct IsMulValidImpl -{ - static bool run(T aX, T aY) - { +template +struct IsMulValidImpl { + static bool run(T aX, T aY) { typedef typename TwiceBiggerType::Type TwiceBiggerType; TwiceBiggerType product = TwiceBiggerType(aX) * TwiceBiggerType(aY); return IsInRange(product); } }; -template -struct IsMulValidImpl -{ - static bool run(T aX, T aY) - { +template +struct IsMulValidImpl { + static bool run(T aX, T aY) { const T max = MaxValue::value; const T min = MinValue::value; @@ -314,51 +315,44 @@ return true; } if (aX > 0) { - return aY > 0 - ? aX <= max / aY - : aY >= min / aX; + return aY > 0 ? aX <= max / aY : aY >= min / aX; } // If we reach this point, we know that aX < 0. - return aY > 0 - ? aX >= min / aY - : aY >= max / aX; + return aY > 0 ? aX >= min / aY : aY >= max / aX; } }; -template -struct IsMulValidImpl -{ - static bool run(T aX, T aY) - { - return aY == 0 || aX <= MaxValue::value / aY; +template +struct IsMulValidImpl { + static bool run(T aX, T aY) { + return aY == 0 || aX <= MaxValue::value / aY; } }; -template -inline bool -IsMulValid(T aX, T aY) -{ +template +inline bool IsMulValid(T aX, T aY) { +#if MOZ_HAS_BUILTIN_OP_OVERFLOW + T dummy; + return !__builtin_mul_overflow(aX, aY, &dummy); +#else return IsMulValidImpl::run(aX, aY); +#endif } -template -inline bool -IsDivValid(T aX, T aY) -{ +template +inline bool IsDivValid(T aX, T aY) { // Keep in mind that in the signed case, min/-1 is invalid because // abs(min)>max. return aY != 0 && !(IsSigned::value && aX == MinValue::value && aY == T(-1)); } -template::value> +template ::value> struct IsModValidImpl; -template -inline bool -IsModValid(T aX, T aY) -{ +template +inline bool IsModValid(T aX, T aY) { return IsModValidImpl::run(aX, aY); } @@ -373,20 +367,14 @@ * Checking that aX>=0 is a warning when T is unsigned. */ -template -struct IsModValidImpl -{ - static inline bool run(T aX, T aY) - { - return aY >= 1; - } +template +struct IsModValidImpl { + static inline bool run(T aX, T aY) { return aY >= 1; } }; -template -struct IsModValidImpl -{ - static inline bool run(T aX, T aY) - { +template +struct IsModValidImpl { + static inline bool run(T aX, T aY) { if (aX < 0) { return false; } @@ -394,25 +382,21 @@ } }; -template::value> +template ::value> struct NegateImpl; -template -struct NegateImpl -{ - static CheckedInt negate(const CheckedInt& aVal) - { +template +struct NegateImpl { + static CheckedInt negate(const CheckedInt& aVal) { // Handle negation separately for signed/unsigned, for simpler code and to // avoid an MSVC warning negating an unsigned value. return CheckedInt(0, aVal.isValid() && aVal.mValue == 0); } }; -template -struct NegateImpl -{ - static CheckedInt negate(const CheckedInt& aVal) - { +template +struct NegateImpl { + static CheckedInt negate(const CheckedInt& aVal) { // Watch out for the min-value, which (with twos-complement) can't be // negated as -min-value is then (max-value + 1). if (!aVal.isValid() || aVal.mValue == MinValue::value) { @@ -422,8 +406,7 @@ } }; -} // namespace detail - +} // namespace detail /* * Step 3: Now define the CheckedInt class. @@ -496,24 +479,22 @@ typedef CheckedInt CheckedUint16; @endcode */ -template -class CheckedInt -{ -protected: +template +class CheckedInt { + protected: T mValue; bool mIsValid; - template - CheckedInt(U aValue, bool aIsValid) : mValue(aValue), mIsValid(aIsValid) - { - static_assert(detail::IsSupported::value && - detail::IsSupported::value, - "This type is not supported by CheckedInt"); + template + CheckedInt(U aValue, bool aIsValid) : mValue(aValue), mIsValid(aIsValid) { + static_assert( + detail::IsSupported::value && detail::IsSupported::value, + "This type is not supported by CheckedInt"); } friend struct detail::NegateImpl; -public: + public: /** * Constructs a checked integer with given @a value. The checked integer is * initialized as valid or invalid depending on whether the @a value @@ -525,38 +506,36 @@ * documentation for class CheckedInt, this constructor checks that its * argument is valid. */ - template - MOZ_IMPLICIT CheckedInt(U aValue) MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT - : mValue(T(aValue)), - mIsValid(detail::IsInRange(aValue)) - { - static_assert(detail::IsSupported::value && - detail::IsSupported::value, - "This type is not supported by CheckedInt"); + template + MOZ_IMPLICIT constexpr CheckedInt(U aValue) MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT + : mValue(T(aValue)), + mIsValid(detail::IsInRange(aValue)) { + static_assert( + detail::IsSupported::value && detail::IsSupported::value, + "This type is not supported by CheckedInt"); } - template + template friend class CheckedInt; - template - CheckedInt toChecked() const - { + template + CheckedInt toChecked() const { CheckedInt ret(mValue); ret.mIsValid = ret.mIsValid && mIsValid; return ret; } /** Constructs a valid checked integer with initial value 0 */ - CheckedInt() : mValue(0), mIsValid(true) - { + constexpr CheckedInt() : mValue(0), mIsValid(true) { static_assert(detail::IsSupported::value, "This type is not supported by CheckedInt"); } /** @returns the actual value */ - T value() const - { - MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)"); + T value() const { + MOZ_ASSERT( + mIsValid, + "Invalid checked integer (division by zero or integer overflow)"); return mValue; } @@ -565,50 +544,44 @@ * of an invalid operation or of an operation involving an invalid checked * integer */ - bool isValid() const - { - return mIsValid; - } - - template - friend CheckedInt operator +(const CheckedInt& aLhs, - const CheckedInt& aRhs); - template - CheckedInt& operator +=(U aRhs); - CheckedInt& operator +=(const CheckedInt& aRhs); - - template - friend CheckedInt operator -(const CheckedInt& aLhs, - const CheckedInt& aRhs); - template - CheckedInt& operator -=(U aRhs); - CheckedInt& operator -=(const CheckedInt& aRhs); - - template - friend CheckedInt operator *(const CheckedInt& aLhs, - const CheckedInt& aRhs); - template - CheckedInt& operator *=(U aRhs); - CheckedInt& operator *=(const CheckedInt& aRhs); - - template - friend CheckedInt operator /(const CheckedInt& aLhs, - const CheckedInt& aRhs); - template - CheckedInt& operator /=(U aRhs); - CheckedInt& operator /=(const CheckedInt& aRhs); - - template - friend CheckedInt operator %(const CheckedInt& aLhs, - const CheckedInt& aRhs); - template - CheckedInt& operator %=(U aRhs); - CheckedInt& operator %=(const CheckedInt& aRhs); - - CheckedInt operator -() const - { - return detail::NegateImpl::negate(*this); - } + bool isValid() const { return mIsValid; } + + template + friend CheckedInt operator+(const CheckedInt& aLhs, + const CheckedInt& aRhs); + template + CheckedInt& operator+=(U aRhs); + CheckedInt& operator+=(const CheckedInt& aRhs); + + template + friend CheckedInt operator-(const CheckedInt& aLhs, + const CheckedInt& aRhs); + template + CheckedInt& operator-=(U aRhs); + CheckedInt& operator-=(const CheckedInt& aRhs); + + template + friend CheckedInt operator*(const CheckedInt& aLhs, + const CheckedInt& aRhs); + template + CheckedInt& operator*=(U aRhs); + CheckedInt& operator*=(const CheckedInt& aRhs); + + template + friend CheckedInt operator/(const CheckedInt& aLhs, + const CheckedInt& aRhs); + template + CheckedInt& operator/=(U aRhs); + CheckedInt& operator/=(const CheckedInt& aRhs); + + template + friend CheckedInt operator%(const CheckedInt& aLhs, + const CheckedInt& aRhs); + template + CheckedInt& operator%=(U aRhs); + CheckedInt& operator%=(const CheckedInt& aRhs); + + CheckedInt operator-() const { return detail::NegateImpl::negate(*this); } /** * @returns true if the left and right hand sides are valid @@ -628,71 +601,87 @@ * 2. This is similar to the behavior of IEEE floats, where a==b * means that a and b have the same value *and* neither is NaN. */ - bool operator ==(const CheckedInt& aOther) const - { + bool operator==(const CheckedInt& aOther) const { return mIsValid && aOther.mIsValid && mValue == aOther.mValue; } /** prefix ++ */ - CheckedInt& operator++() - { + CheckedInt& operator++() { *this += 1; return *this; } /** postfix ++ */ - CheckedInt operator++(int) - { + CheckedInt operator++(int) { CheckedInt tmp = *this; *this += 1; return tmp; } /** prefix -- */ - CheckedInt& operator--() - { + CheckedInt& operator--() { *this -= 1; return *this; } /** postfix -- */ - CheckedInt operator--(int) - { + CheckedInt operator--(int) { CheckedInt tmp = *this; *this -= 1; return tmp; } -private: + private: /** * The !=, <, <=, >, >= operators are disabled: * see the comment on operator==. */ - template bool operator !=(U aOther) const = delete; - template bool operator < (U aOther) const = delete; - template bool operator <=(U aOther) const = delete; - template bool operator > (U aOther) const = delete; - template bool operator >=(U aOther) const = delete; -}; - -#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \ - template \ - inline CheckedInt \ - operator OP(const CheckedInt& aLhs, const CheckedInt& aRhs) \ - { \ - if (!detail::Is##NAME##Valid(aLhs.mValue, aRhs.mValue)) { \ - return CheckedInt(0, false); \ - } \ - return CheckedInt(aLhs.mValue OP aRhs.mValue, \ - aLhs.mIsValid && aRhs.mIsValid); \ - } - + template + bool operator!=(U aOther) const = delete; + template + bool operator<(U aOther) const = delete; + template + bool operator<=(U aOther) const = delete; + template + bool operator>(U aOther) const = delete; + template + bool operator>=(U aOther) const = delete; +}; + +#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \ + template \ + inline CheckedInt operator OP(const CheckedInt& aLhs, \ + const CheckedInt& aRhs) { \ + if (!detail::Is##NAME##Valid(aLhs.mValue, aRhs.mValue)) { \ + return CheckedInt(0, false); \ + } \ + return CheckedInt(aLhs.mValue OP aRhs.mValue, \ + aLhs.mIsValid && aRhs.mIsValid); \ + } + +#if MOZ_HAS_BUILTIN_OP_OVERFLOW +#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(NAME, OP, FUN) \ + template \ + inline CheckedInt operator OP(const CheckedInt& aLhs, \ + const CheckedInt& aRhs) { \ + T result; \ + if (FUN(aLhs.mValue, aRhs.mValue, &result)) { \ + return CheckedInt(0, false); \ + } \ + return CheckedInt(result, aLhs.mIsValid && aRhs.mIsValid); \ + } +MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(Add, +, __builtin_add_overflow) +MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(Sub, -, __builtin_sub_overflow) +MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2(Mul, *, __builtin_mul_overflow) +#undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR2 +#else MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +) MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -) MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *) +#endif + MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Div, /) MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mod, %) - #undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR // Implement castToCheckedInt(x), making sure that @@ -703,55 +692,48 @@ namespace detail { -template -struct CastToCheckedIntImpl -{ +template +struct CastToCheckedIntImpl { typedef CheckedInt ReturnType; static CheckedInt run(U aU) { return aU; } }; -template -struct CastToCheckedIntImpl > -{ +template +struct CastToCheckedIntImpl > { typedef const CheckedInt& ReturnType; static const CheckedInt& run(const CheckedInt& aU) { return aU; } }; -} // namespace detail +} // namespace detail -template -inline typename detail::CastToCheckedIntImpl::ReturnType -castToCheckedInt(U aU) -{ - static_assert(detail::IsSupported::value && - detail::IsSupported::value, +template +inline typename detail::CastToCheckedIntImpl::ReturnType castToCheckedInt( + U aU) { + static_assert(detail::IsSupported::value && detail::IsSupported::value, "This type is not supported by CheckedInt"); return detail::CastToCheckedIntImpl::run(aU); } -#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \ - template \ - template \ - CheckedInt& CheckedInt::operator COMPOUND_OP(U aRhs) \ - { \ - *this = *this OP castToCheckedInt(aRhs); \ - return *this; \ - } \ - template \ - CheckedInt& CheckedInt::operator COMPOUND_OP(const CheckedInt& aRhs) \ - { \ - *this = *this OP aRhs; \ - return *this; \ - } \ - template \ - inline CheckedInt operator OP(const CheckedInt& aLhs, U aRhs) \ - { \ - return aLhs OP castToCheckedInt(aRhs); \ - } \ - template \ - inline CheckedInt operator OP(U aLhs, const CheckedInt& aRhs) \ - { \ - return castToCheckedInt(aLhs) OP aRhs; \ +#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \ + template \ + template \ + CheckedInt& CheckedInt::operator COMPOUND_OP(U aRhs) { \ + *this = *this OP castToCheckedInt(aRhs); \ + return *this; \ + } \ + template \ + CheckedInt& CheckedInt::operator COMPOUND_OP( \ + const CheckedInt& aRhs) { \ + *this = *this OP aRhs; \ + return *this; \ + } \ + template \ + inline CheckedInt operator OP(const CheckedInt& aLhs, U aRhs) { \ + return aLhs OP castToCheckedInt(aRhs); \ + } \ + template \ + inline CheckedInt operator OP(U aLhs, const CheckedInt& aRhs) { \ + return castToCheckedInt(aLhs) OP aRhs; \ } MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=) @@ -762,30 +744,26 @@ #undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS -template -inline bool -operator ==(const CheckedInt& aLhs, U aRhs) -{ +template +inline bool operator==(const CheckedInt& aLhs, U aRhs) { return aLhs == castToCheckedInt(aRhs); } -template -inline bool -operator ==(U aLhs, const CheckedInt& aRhs) -{ +template +inline bool operator==(U aLhs, const CheckedInt& aRhs) { return castToCheckedInt(aLhs) == aRhs; } // Convenience typedefs. -typedef CheckedInt CheckedInt8; -typedef CheckedInt CheckedUint8; -typedef CheckedInt CheckedInt16; +typedef CheckedInt CheckedInt8; +typedef CheckedInt CheckedUint8; +typedef CheckedInt CheckedInt16; typedef CheckedInt CheckedUint16; -typedef CheckedInt CheckedInt32; +typedef CheckedInt CheckedInt32; typedef CheckedInt CheckedUint32; -typedef CheckedInt CheckedInt64; +typedef CheckedInt CheckedInt64; typedef CheckedInt CheckedUint64; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_CheckedInt_h */ 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 @@ -14,26 +14,26 @@ #if !defined(__clang__) && defined(__GNUC__) -# undef MOZ_IS_GCC -# define MOZ_IS_GCC 1 - /* - * 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))) -# 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 +#undef MOZ_IS_GCC +#define MOZ_IS_GCC 1 +/* + * 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))) +#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, 9, 0) +#error "mfbt (and Gecko) require at least gcc 4.9 to build." +#endif #elif defined(_MSC_VER) -# undef MOZ_IS_MSVC -# define MOZ_IS_MSVC 1 +#undef MOZ_IS_MSVC +#define MOZ_IS_MSVC 1 #endif @@ -46,68 +46,68 @@ * the version macros and deduce macros from there. */ #ifdef __cplusplus -# include -# ifdef _STLPORT_MAJOR -# define MOZ_USING_STLPORT 1 -# define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) \ - (_STLPORT_VERSION >= ((major) << 8 | (minor) << 4 | (patch))) -# elif defined(_LIBCPP_VERSION) - /* - * libc++, unfortunately, doesn't appear to have useful versioning macros. - * Hopefully, the recommendations of N3694 with respect to standard libraries - * will get applied instead and we won't need to worry about version numbers - * here. - */ -# define MOZ_USING_LIBCXX 1 -# elif defined(__GLIBCXX__) -# define MOZ_USING_LIBSTDCXX 1 - /* - * libstdc++ is also annoying and doesn't give us useful versioning macros - * for the library. If we're using gcc, then assume that libstdc++ matches - * the compiler version. If we're using clang, we're going to have to fake - * major/minor combinations by looking for newly-defined config macros. - */ -# if MOZ_IS_GCC -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - MOZ_GCC_VERSION_AT_LEAST(major, minor, patch) -# elif defined(_GLIBCXX_THROW_OR_ABORT) -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - ((major) < 4 || ((major) == 4 && (minor) <= 8)) -# elif defined(_GLIBCXX_NOEXCEPT) -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - ((major) < 4 || ((major) == 4 && (minor) <= 7)) -# elif defined(_GLIBCXX_USE_DEPRECATED) -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - ((major) < 4 || ((major) == 4 && (minor) <= 6)) -# elif defined(_GLIBCXX_PSEUDO_VISIBILITY) -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - ((major) < 4 || ((major) == 4 && (minor) <= 5)) -# elif defined(_GLIBCXX_BEGIN_EXTERN_C) -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - ((major) < 4 || ((major) == 4 && (minor) <= 4)) -# elif defined(_GLIBCXX_VISIBILITY_ATTR) -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - ((major) < 4 || ((major) == 4 && (minor) <= 3)) -# elif defined(_GLIBCXX_VISIBILITY) -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ - ((major) < 4 || ((major) == 4 && (minor) <= 2)) -# else -# error "Your version of libstdc++ is unknown to us and is likely too old." -# endif -# endif - - // Flesh out the defines for everyone else -# ifndef MOZ_USING_STLPORT -# define MOZ_USING_STLPORT 0 -# define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) 0 -# endif -# ifndef MOZ_USING_LIBCXX -# define MOZ_USING_LIBCXX 0 -# endif -# ifndef MOZ_USING_LIBSTDCXX -# define MOZ_USING_LIBSTDCXX 0 -# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) 0 -# endif +#include +#ifdef _STLPORT_MAJOR +#define MOZ_USING_STLPORT 1 +#define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) \ + (_STLPORT_VERSION >= ((major) << 8 | (minor) << 4 | (patch))) +#elif defined(_LIBCPP_VERSION) +/* + * libc++, unfortunately, doesn't appear to have useful versioning macros. + * Hopefully, the recommendations of N3694 with respect to standard libraries + * will get applied instead and we won't need to worry about version numbers + * here. + */ +#define MOZ_USING_LIBCXX 1 +#elif defined(__GLIBCXX__) +#define MOZ_USING_LIBSTDCXX 1 +/* + * libstdc++ is also annoying and doesn't give us useful versioning macros + * for the library. If we're using gcc, then assume that libstdc++ matches + * the compiler version. If we're using clang, we're going to have to fake + * major/minor combinations by looking for newly-defined config macros. + */ +#if MOZ_IS_GCC +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + MOZ_GCC_VERSION_AT_LEAST(major, minor, patch) +#elif defined(_GLIBCXX_THROW_OR_ABORT) +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 8)) +#elif defined(_GLIBCXX_NOEXCEPT) +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 7)) +#elif defined(_GLIBCXX_USE_DEPRECATED) +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 6)) +#elif defined(_GLIBCXX_PSEUDO_VISIBILITY) +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 5)) +#elif defined(_GLIBCXX_BEGIN_EXTERN_C) +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 4)) +#elif defined(_GLIBCXX_VISIBILITY_ATTR) +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 3)) +#elif defined(_GLIBCXX_VISIBILITY) +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \ + ((major) < 4 || ((major) == 4 && (minor) <= 2)) +#else +#error "Your version of libstdc++ is unknown to us and is likely too old." +#endif +#endif + +// Flesh out the defines for everyone else +#ifndef MOZ_USING_STLPORT +#define MOZ_USING_STLPORT 0 +#define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) 0 +#endif +#ifndef MOZ_USING_LIBCXX +#define MOZ_USING_LIBCXX 0 +#endif +#ifndef MOZ_USING_LIBSTDCXX +#define MOZ_USING_LIBSTDCXX 0 +#define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) 0 +#endif #endif /* __cplusplus */ #endif /* mozilla_Compiler_h */ 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 @@ -25,9 +25,8 @@ * 4x the speed and produces output of about 1.5x the size. */ -class LZ4 -{ -public: +class LZ4 { + public: /** * Compresses |aInputSize| bytes from |aSource| into |aDest|. Destination * buffer must be already allocated, and must be sized to handle worst cases @@ -37,8 +36,8 @@ * @param aInputSize is the input size. Max supported value is ~1.9GB * @return the number of bytes written in buffer |aDest| */ - static MFBT_API size_t - compress(const char* aSource, size_t aInputSize, char* aDest); + static MFBT_API size_t compress(const char* aSource, size_t aInputSize, + char* aDest); /** * Compress |aInputSize| bytes from |aSource| into an output buffer @@ -55,9 +54,9 @@ * @return the number of bytes written in buffer |aDest| or 0 if the * compression fails */ - static MFBT_API size_t - compressLimitedOutput(const char* aSource, size_t aInputSize, char* aDest, - size_t aMaxOutputSize); + static MFBT_API size_t compressLimitedOutput(const char* aSource, + size_t aInputSize, char* aDest, + size_t aMaxOutputSize); /** * If the source stream is malformed, the function will stop decoding @@ -72,8 +71,8 @@ * @param aOutputSize is the output size, therefore the original size * @return true on success, false on failure */ - static MFBT_API MOZ_MUST_USE bool - decompress(const char* aSource, char* aDest, size_t aOutputSize); + static MFBT_API MOZ_MUST_USE bool decompress(const char* aSource, char* aDest, + size_t aOutputSize); /** * If the source stream is malformed, the function will stop decoding @@ -92,9 +91,35 @@ * buffer (necessarily <= aMaxOutputSize) * @return true on success, false on failure */ - static MFBT_API MOZ_MUST_USE bool - decompress(const char* aSource, size_t aInputSize, char* aDest, - size_t aMaxOutputSize, size_t* aOutputSize); + static MFBT_API MOZ_MUST_USE bool decompress(const char* aSource, + size_t aInputSize, char* aDest, + size_t aMaxOutputSize, + size_t* aOutputSize); + + /** + * If the source stream is malformed, the function will stop decoding + * and return false. + * + * This function never writes beyond aDest + aMaxOutputSize, and is + * therefore protected against malicious data packets. It also ignores + * unconsumed input upon reaching aMaxOutputSize and can therefore be used + * for partial decompression. + * + * Note: Destination buffer must be already allocated. This version is + * slightly slower than the decompress without the aMaxOutputSize. + * + * @param aInputSize is the length of the input compressed data + * @param aMaxOutputSize is the size of the destination buffer (which must be + * 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 MOZ_MUST_USE bool decompressPartial(const char* aSource, + size_t aInputSize, + char* aDest, + size_t aMaxOutputSize, + size_t* aOutputSize); /* * Provides the maximum size that LZ4 may output in a "worst case" @@ -105,8 +130,7 @@ * @param aInputSize is the input size. Max supported value is ~1.9GB * @return maximum output size in a "worst case" scenario */ - static inline size_t maxCompressedSize(size_t aInputSize) - { + static inline size_t maxCompressedSize(size_t aInputSize) { size_t max = (aInputSize + (aInputSize / 255) + 16); MOZ_ASSERT(max > aInputSize); return max; 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 @@ -35,16 +35,15 @@ * DebugOnly for struct/class members and unwittingly inflating the size of * their objects in release builds. */ -template -class MOZ_STACK_CLASS DebugOnly -{ -public: +template +class MOZ_STACK_CLASS DebugOnly { + public: #ifdef DEBUG T value; - DebugOnly() { } - MOZ_IMPLICIT DebugOnly(const T& aOther) : value(aOther) { } - DebugOnly(const DebugOnly& aOther) : value(aOther.value) { } + DebugOnly() {} + MOZ_IMPLICIT DebugOnly(const T& aOther) : value(aOther) {} + DebugOnly(const DebugOnly& aOther) : value(aOther.value) {} DebugOnly& operator=(const T& aRhs) { value = aRhs; return *this; @@ -66,12 +65,12 @@ const T& operator->() const { return value; } #else - DebugOnly() { } - MOZ_IMPLICIT DebugOnly(const T&) { } - DebugOnly(const DebugOnly&) { } + DebugOnly() {} + MOZ_IMPLICIT DebugOnly(const T&) {} + DebugOnly(const DebugOnly&) {} DebugOnly& operator=(const T&) { return *this; } - void operator++(int) { } - void operator--(int) { } + void operator++(int) {} + void operator--(int) {} DebugOnly& operator+=(const T&) { return *this; } DebugOnly& operator-=(const T&) { return *this; } DebugOnly& operator&=(const T&) { return *this; } @@ -87,6 +86,6 @@ ~DebugOnly() {} }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_DebugOnly_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/DefineEnum.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/DefineEnum.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/DefineEnum.h @@ -0,0 +1,155 @@ +/* -*- 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/. */ + +/* Poor man's reflection for enumerations. */ + +#ifndef mozilla_DefineEnum_h +#define mozilla_DefineEnum_h + +#include // for size_t + +#include "mozilla/MacroArgs.h" // for MOZ_ARG_COUNT +#include "mozilla/MacroForEach.h" // for MOZ_FOR_EACH + +/** + * MOZ_UNWRAP_ARGS is a helper macro that unwraps a list of comma-separated + * items enclosed in parentheses, to yield just the items. + * + * Usage: |MOZ_UNWRAP_ARGS foo| (note the absence of parentheses in the + * invocation), where |foo| is a parenthesis-enclosed list. + * For exampe if |foo| is |(3, 4, 5)|, then the expansion is just |3, 4, 5|. + */ +#define MOZ_UNWRAP_ARGS(...) __VA_ARGS__ + +/** + * MOZ_DEFINE_ENUM(aEnumName, aEnumerators) is a macro that allows + * simultaneously defining an enumeration named |aEnumName|, and a constant + * that stores the number of enumerators it has. + * + * The motivation is to allow the enumeration to evolve over time without + * either having to manually keep such a constant up to date, or having to + * add a special "sentinel" enumerator for this purpose. (While adding a + * "sentinel" enumerator is trivial, it causes headaches with "switch" + * statements. We often try to write "switch" statements whose cases exhaust + * the enumerators and don't have a "default" case, so that if a new + * enumerator is added and we forget to handle it in the "switch", the + * compiler points it out. But this means we need to explicitly handle the + * sentinel in every "switch".) + * + * |aEnumerators| is expected to be a comma-separated list of enumerators, + * enclosed in parentheses. The enumerators may NOT have associated + * initializers (an attempt to have one will result in a compiler error). + * This ensures that the enumerator values are in the range [0, N), where N + * is the number of enumerators. + * + * The list of enumerators cannot contain a trailing comma. This is a + * limitation of MOZ_FOR_EACH, which we use in the implementation; if + * MOZ_FOR_EACH supported trailing commas, we could too. + * + * The generated constant has the name "k" + |aEnumName| + "Count", and type + * "size_t". The enumeration and the constant are both defined in the scope + * in which the macro is invoked. + * + * For convenience, a constant of the enumeration type named + * "kHighest" + |aEnumName| is also defined, whose value is the highest + * valid enumerator, assuming the enumerators have contiguous values starting + * from 0. + * + * Invocation of the macro may be followed by a semicolon, if one prefers a + * more declaration-like syntax. + * + * Example invocation: + * MOZ_DEFINE_ENUM(MyEnum, (Foo, Bar, Baz)); + * + * This expands to: + * enum MyEnum { Foo, Bar, Baz }; + * constexpr size_t kMyEnumCount = 3; + * constexpr MyEnum kHighestMyEnum = MyEnum(kMyEnumCount - 1); + * // some static_asserts to ensure the values are in the range [0, 3) + * + * The macro also has several variants: + * + * - A |_CLASS| variant, which generates an |enum class| instead of + * a plain enum. + * + * - A |_WITH_BASE| variant which generates an enum with a specified + * underlying ("base") type, which is provided as an additional + * argument in second position. + * + * - An |_AT_CLASS_SCOPE| variant, designed for enumerations defined + * at class scope. For these, the generated constants are static, + * and have names prefixed with "s" instead of "k" as per + * naming convention. + * + * (and combinations of these). + */ + +/* + * A helper macro for asserting that an enumerator does not have an initializer. + * + * The static_assert and the comparison to 0 are just scaffolding; the + * important part is forming the expression |aEnumName::aEnumeratorDecl|. + * + * If |aEnumeratorDecl| is just the enumerator name without an identifier, + * this expression compiles fine. However, if |aEnumeratorDecl| includes an + * initializer, as in |eEnumerator = initializer|, then this will fail to + * compile in expression context, since |eEnumerator| is not an lvalue. + * + * (The static_assert itself should always pass in the absence of the above + * error, since you can't get a negative enumerator value without having + * an initializer somewhere. It just provides a place to put the expression + * we want to form.) + */ +#define MOZ_ASSERT_ENUMERATOR_HAS_NO_INITIALIZER(aEnumName, aEnumeratorDecl) \ + static_assert( \ + (aEnumName::aEnumeratorDecl) >= aEnumName(0), \ + "MOZ_DEFINE_ENUM does not allow enumerators to have initializers"); + +#define MOZ_DEFINE_ENUM_IMPL(aEnumName, aClassSpec, aBaseSpec, aEnumerators) \ + enum aClassSpec aEnumName aBaseSpec{MOZ_UNWRAP_ARGS aEnumerators}; \ + constexpr size_t k##aEnumName##Count = MOZ_ARG_COUNT aEnumerators; \ + constexpr aEnumName k##Highest##aEnumName = \ + aEnumName(k##aEnumName##Count - 1); \ + MOZ_FOR_EACH(MOZ_ASSERT_ENUMERATOR_HAS_NO_INITIALIZER, (aEnumName, ), \ + aEnumerators) + +#define MOZ_DEFINE_ENUM(aEnumName, aEnumerators) \ + MOZ_DEFINE_ENUM_IMPL(aEnumName, , , aEnumerators) + +#define MOZ_DEFINE_ENUM_WITH_BASE(aEnumName, aBaseName, aEnumerators) \ + MOZ_DEFINE_ENUM_IMPL(aEnumName, , : aBaseName, aEnumerators) + +#define MOZ_DEFINE_ENUM_CLASS(aEnumName, aEnumerators) \ + MOZ_DEFINE_ENUM_IMPL(aEnumName, class, , aEnumerators) + +#define MOZ_DEFINE_ENUM_CLASS_WITH_BASE(aEnumName, aBaseName, aEnumerators) \ + MOZ_DEFINE_ENUM_IMPL(aEnumName, class, : aBaseName, aEnumerators) + +#define MOZ_DEFINE_ENUM_AT_CLASS_SCOPE_IMPL(aEnumName, aClassSpec, aBaseSpec, \ + aEnumerators) \ + enum aClassSpec aEnumName aBaseSpec{MOZ_UNWRAP_ARGS aEnumerators}; \ + constexpr static size_t s##aEnumName##Count = MOZ_ARG_COUNT aEnumerators; \ + constexpr static aEnumName s##Highest##aEnumName = \ + aEnumName(s##aEnumName##Count - 1); \ + MOZ_FOR_EACH(MOZ_ASSERT_ENUMERATOR_HAS_NO_INITIALIZER, (aEnumName, ), \ + aEnumerators) + +#define MOZ_DEFINE_ENUM_AT_CLASS_SCOPE(aEnumName, aEnumerators) \ + MOZ_DEFINE_ENUM_AT_CLASS_SCOPE_IMPL(aEnumName, , , aEnumerators) + +#define MOZ_DEFINE_ENUM_WITH_BASE_AT_CLASS_SCOPE(aEnumName, aBaseName, \ + aEnumerators) \ + MOZ_DEFINE_ENUM_AT_CLASS_SCOPE_IMPL(aEnumName, , : aBaseName, aEnumerators) + +#define MOZ_DEFINE_ENUM_CLASS_AT_CLASS_SCOPE(aEnumName, aEnumerators) \ + MOZ_DEFINE_ENUM_AT_CLASS_SCOPE_IMPL(aEnumName, class, , aEnumerators) + +#define MOZ_DEFINE_ENUM_CLASS_WITH_BASE_AT_CLASS_SCOPE(aEnumName, aBaseName, \ + aEnumerators) \ + MOZ_DEFINE_ENUM_AT_CLASS_SCOPE_IMPL(aEnumName, class, \ + : aBaseName, aEnumerators) + +#endif // mozilla_DefineEnum_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/DoublyLinkedList.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/DoublyLinkedList.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/DoublyLinkedList.h @@ -0,0 +1,373 @@ +/* -*- 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 doubly-linked list with flexible next/prev naming. */ + +#ifndef mozilla_DoublyLinkedList_h +#define mozilla_DoublyLinkedList_h + +#include +#include + +#include "mozilla/Assertions.h" + +/** + * Where mozilla::LinkedList strives for ease of use above all other + * considerations, mozilla::DoublyLinkedList strives for flexibility. The + * following are things that can be done with mozilla::DoublyLinkedList that + * cannot be done with mozilla::LinkedList: + * + * * Arbitrary next/prev placement and naming. With the tools provided here, + * the next and previous pointers can be at the end of the structure, in a + * sub-structure, stored with a tag, in a union, wherever, as long as you + * can look them up and set them on demand. + * * Can be used without deriving from a new base and, thus, does not require + * use of constructors. + * + * Example: + * + * class Observer : public DoublyLinkedListElement + * { + * public: + * void observe(char* aTopic) { ... } + * }; + * + * class ObserverContainer + * { + * private: + * DoublyLinkedList mList; + * + * public: + * void addObserver(Observer* aObserver) + * { + * // Will assert if |aObserver| is part of another list. + * mList.pushBack(aObserver); + * } + * + * void removeObserver(Observer* aObserver) + * { + * // Will assert if |aObserver| is not part of |list|. + * mList.remove(aObserver); + * } + * + * void notifyObservers(char* aTopic) + * { + * for (Observer* o : mList) { + * o->observe(aTopic); + * } + * } + * }; + */ + +namespace mozilla { + +/** + * Deriving from this will allow T to be inserted into and removed from a + * DoublyLinkedList. + */ +template +class DoublyLinkedListElement { + template + friend class DoublyLinkedList; + friend T; + T* mNext; + T* mPrev; + + public: + DoublyLinkedListElement() : mNext(nullptr), mPrev(nullptr) {} +}; + +/** + * Provides access to a DoublyLinkedListElement within T. + * + * The default implementation of this template works for types that derive + * from DoublyLinkedListElement, but one can specialize for their class so + * that some appropriate DoublyLinkedListElement reference is returned. + * + * For more complex cases (multiple DoublyLinkedListElements, for example), + * one can define their own trait class and use that as ElementAccess for + * DoublyLinkedList. See TestDoublyLinkedList.cpp for an example. + */ +template +struct GetDoublyLinkedListElement { + static_assert(mozilla::IsBaseOf, T>::value, + "You need your own specialization of GetDoublyLinkedListElement" + " or use a separate Trait."); + static DoublyLinkedListElement& Get(T* aThis) { return *aThis; } +}; + +/** + * A doubly linked list. |T| is the type of element stored in this list. |T| + * must contain or have access to unique next and previous element pointers. + * The template argument |ElementAccess| provides code to tell this list how to + * get a reference to a DoublyLinkedListElement that may reside anywhere. + */ +template > +class DoublyLinkedList final { + T* mHead; + T* mTail; + + /** + * Checks that either the list is empty and both mHead and mTail are nullptr + * or the list has entries and both mHead and mTail are non-null. + */ + bool isStateValid() const { return (mHead != nullptr) == (mTail != nullptr); } + + bool ElementNotInList(T* aElm) { + if (!ElementAccess::Get(aElm).mNext && !ElementAccess::Get(aElm).mPrev) { + // Both mNext and mPrev being NULL can mean two things: + // - the element is not in the list. + // - the element is the first and only element in the list. + // So check for the latter. + return mHead != aElm; + } + return false; + } + + public: + DoublyLinkedList() : mHead(nullptr), mTail(nullptr) {} + + class Iterator final { + T* mCurrent; + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = T*; + using reference = T&; + + Iterator() : mCurrent(nullptr) {} + explicit Iterator(T* aCurrent) : mCurrent(aCurrent) {} + + T& operator*() const { return *mCurrent; } + T* operator->() const { return mCurrent; } + + Iterator& operator++() { + mCurrent = ElementAccess::Get(mCurrent).mNext; + return *this; + } + + Iterator operator++(int) { + Iterator result = *this; + ++(*this); + return result; + } + + Iterator& operator--() { + mCurrent = ElementAccess::Get(mCurrent).mPrev; + return *this; + } + + Iterator operator--(int) { + Iterator result = *this; + --(*this); + return result; + } + + bool operator!=(const Iterator& aOther) const { + return mCurrent != aOther.mCurrent; + } + + bool operator==(const Iterator& aOther) const { + return mCurrent == aOther.mCurrent; + } + + explicit operator bool() const { return mCurrent; } + }; + + Iterator begin() { return Iterator(mHead); } + const Iterator begin() const { return Iterator(mHead); } + const Iterator cbegin() const { return Iterator(mHead); } + + Iterator end() { return Iterator(); } + const Iterator end() const { return Iterator(); } + const Iterator cend() const { return Iterator(); } + + /** + * Returns true if the list contains no elements. + */ + bool isEmpty() const { + MOZ_ASSERT(isStateValid()); + return mHead == nullptr; + } + + /** + * Inserts aElm into the list at the head position. |aElm| must not already + * be in a list. + */ + void pushFront(T* aElm) { + MOZ_ASSERT(aElm); + MOZ_ASSERT(ElementNotInList(aElm)); + MOZ_ASSERT(isStateValid()); + + ElementAccess::Get(aElm).mNext = mHead; + if (mHead) { + MOZ_ASSERT(!ElementAccess::Get(mHead).mPrev); + ElementAccess::Get(mHead).mPrev = aElm; + } + + mHead = aElm; + if (!mTail) { + mTail = aElm; + } + } + + /** + * Remove the head of the list and return it. Calling this on an empty list + * will assert. + */ + T* popFront() { + MOZ_ASSERT(!isEmpty()); + MOZ_ASSERT(isStateValid()); + + T* result = mHead; + mHead = result ? ElementAccess::Get(result).mNext : nullptr; + if (mHead) { + ElementAccess::Get(mHead).mPrev = nullptr; + } + + if (mTail == result) { + mTail = nullptr; + } + + if (result) { + ElementAccess::Get(result).mNext = nullptr; + ElementAccess::Get(result).mPrev = nullptr; + } + + return result; + } + + /** + * Inserts aElm into the list at the tail position. |aElm| must not already + * be in a list. + */ + void pushBack(T* aElm) { + MOZ_ASSERT(aElm); + MOZ_ASSERT(ElementNotInList(aElm)); + MOZ_ASSERT(isStateValid()); + + ElementAccess::Get(aElm).mNext = nullptr; + ElementAccess::Get(aElm).mPrev = mTail; + if (mTail) { + MOZ_ASSERT(!ElementAccess::Get(mTail).mNext); + ElementAccess::Get(mTail).mNext = aElm; + } + + mTail = aElm; + if (!mHead) { + mHead = aElm; + } + } + + /** + * Remove the tail of the list and return it. Calling this on an empty list + * will assert. + */ + T* popBack() { + MOZ_ASSERT(!isEmpty()); + MOZ_ASSERT(isStateValid()); + + T* result = mTail; + mTail = result ? ElementAccess::Get(result).mPrev : nullptr; + if (mTail) { + ElementAccess::Get(mTail).mNext = nullptr; + } + + if (mHead == result) { + mHead = nullptr; + } + + if (result) { + ElementAccess::Get(result).mNext = nullptr; + ElementAccess::Get(result).mPrev = nullptr; + } + + return result; + } + + /** + * Insert the given |aElm| *before* |aIter|. + */ + void insertBefore(const Iterator& aIter, T* aElm) { + MOZ_ASSERT(aElm); + MOZ_ASSERT(ElementNotInList(aElm)); + MOZ_ASSERT(isStateValid()); + + if (!aIter) { + return pushBack(aElm); + } else if (aIter == begin()) { + return pushFront(aElm); + } + + T* after = &(*aIter); + T* before = ElementAccess::Get(after).mPrev; + MOZ_ASSERT(before); + + ElementAccess::Get(before).mNext = aElm; + ElementAccess::Get(aElm).mPrev = before; + ElementAccess::Get(aElm).mNext = after; + ElementAccess::Get(after).mPrev = aElm; + } + + /** + * Removes the given element from the list. The element must be in this list. + */ + void remove(T* aElm) { + MOZ_ASSERT(aElm); + MOZ_ASSERT(ElementAccess::Get(aElm).mNext || + ElementAccess::Get(aElm).mPrev || + (aElm == mHead && aElm == mTail), + "Attempted to remove element not in this list"); + + if (T* prev = ElementAccess::Get(aElm).mPrev) { + ElementAccess::Get(prev).mNext = ElementAccess::Get(aElm).mNext; + } else { + MOZ_ASSERT(mHead == aElm); + mHead = ElementAccess::Get(aElm).mNext; + } + + if (T* next = ElementAccess::Get(aElm).mNext) { + ElementAccess::Get(next).mPrev = ElementAccess::Get(aElm).mPrev; + } else { + MOZ_ASSERT(mTail == aElm); + mTail = ElementAccess::Get(aElm).mPrev; + } + + ElementAccess::Get(aElm).mNext = nullptr; + ElementAccess::Get(aElm).mPrev = nullptr; + } + + /** + * Returns an iterator referencing the first found element whose value matches + * the given element according to operator==. + */ + Iterator find(const T& aElm) { return std::find(begin(), end(), aElm); } + + /** + * Returns whether the given element is in the list. Note that this uses + * T::operator==, not pointer comparison. + */ + bool contains(const T& aElm) { return find(aElm) != Iterator(); } + + /** + * Returns whether the given element might be in the list. Note that this + * assumes the element is either in the list or not in the list, and ignores + * the case where the element might be in another list in order to make the + * check fast. + */ + bool ElementProbablyInList(T* aElm) { + if (isEmpty()) { + return false; + } + return !ElementNotInList(aElm); + } +}; + +} // namespace mozilla + +#endif // mozilla_DoublyLinkedList_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 @@ -9,7 +9,9 @@ /* * 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: + * in their respective endianness. The addresses read from or written + * to may be misaligned (although misaligned accesses may incur + * architecture-specific performance costs). The naming scheme is: * * {Little,Big}Endian::{read,write}{Uint,Int} * @@ -74,85 +76,81 @@ #include #if defined(_MSC_VER) -# include -# pragma intrinsic(_byteswap_ushort) -# pragma intrinsic(_byteswap_ulong) -# pragma intrinsic(_byteswap_uint64) +#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 +#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 +#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 +#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 +#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 +#define MOZ_LITTLE_ENDIAN 0 #elif MOZ_LITTLE_ENDIAN -# define MOZ_BIG_ENDIAN 0 +#define MOZ_BIG_ENDIAN 0 #else -# error "Cannot determine endianness" +#error "Cannot determine endianness" #endif #if defined(__clang__) -# if __has_builtin(__builtin_bswap16) -# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 -# endif +#if __has_builtin(__builtin_bswap16) +#define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 +#endif #elif defined(__GNUC__) -# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 +#define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16 #elif defined(_MSC_VER) -# define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort +#define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort #endif namespace mozilla { @@ -164,14 +162,12 @@ * arguments and/or partial specialization of function templates are not * supported by all the compilers we use. */ -template +template struct Swapper; -template -struct Swapper -{ - static T swap(T aValue) - { +template +struct Swapper { + static T swap(T aValue) { #if defined(MOZ_HAVE_BUILTIN_BYTESWAP16) return MOZ_HAVE_BUILTIN_BYTESWAP16(aValue); #else @@ -180,29 +176,23 @@ } }; -template -struct Swapper -{ - static T swap(T aValue) - { +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)); + return T(((aValue & 0x000000ffU) << 24) | ((aValue & 0x0000ff00U) << 8) | + ((aValue & 0x00ff0000U) >> 8) | ((aValue & 0xff000000U) >> 24)); #endif } }; -template -struct Swapper -{ - static inline T swap(T aValue) - { +template +struct Swapper { + static inline T swap(T aValue) { #if defined(__clang__) || defined(__GNUC__) return T(__builtin_bswap64(aValue)); #elif defined(_MSC_VER) @@ -223,42 +213,37 @@ enum Endianness { Little, Big }; #if MOZ_BIG_ENDIAN -# define MOZ_NATIVE_ENDIANNESS detail::Big +#define MOZ_NATIVE_ENDIANNESS detail::Big #else -# define MOZ_NATIVE_ENDIANNESS detail::Little +#define MOZ_NATIVE_ENDIANNESS detail::Little #endif -class EndianUtils -{ +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) - { + 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)); + MOZ_ASSERT( + (byteDestPtr <= byteSrcPtr && byteDestPtr + aCount <= byteSrcPtr) || + (byteSrcPtr <= byteDestPtr && byteSrcPtr + aCount <= byteDestPtr)); } - template - static void assertAligned(T* aPtr) - { + template + static void assertAligned(T* aPtr) { MOZ_ASSERT((uintptr_t(aPtr) % sizeof(T)) == 0, "Unaligned pointer!"); } -protected: + protected: /** * Return |aValue| converted from SourceEndian encoding to DestEndian * encoding. */ - template - static inline T maybeSwap(T aValue) - { + template + static inline T maybeSwap(T aValue) { if (SourceEndian == DestEndian) { return aValue; } @@ -269,9 +254,8 @@ * Convert |aCount| elements at |aPtr| from SourceEndian encoding to * DestEndian encoding. */ - template - static inline void maybeSwapInPlace(T* aPtr, size_t aCount) - { + template + static inline void maybeSwapInPlace(T* aPtr, size_t aCount) { assertAligned(aPtr); if (SourceEndian == DestEndian) { @@ -286,9 +270,8 @@ * 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) - { + template + static void copyAndSwapTo(void* aDest, const T* aSrc, size_t aCount) { assertNoOverlap(aDest, aSrc, aCount * sizeof(T)); assertAligned(aSrc); @@ -299,8 +282,7 @@ uint8_t* byteDestPtr = static_cast(aDest); for (size_t i = 0; i < aCount; ++i) { - union - { + union { T mVal; uint8_t mBuffer[sizeof(T)]; } u; @@ -314,9 +296,8 @@ * 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) - { + template + static void copyAndSwapFrom(T* aDest, const void* aSrc, size_t aCount) { assertNoOverlap(aDest, aSrc, aCount * sizeof(T)); assertAligned(aDest); @@ -327,8 +308,7 @@ const uint8_t* byteSrcPtr = static_cast(aSrc); for (size_t i = 0; i < aCount; ++i) { - union - { + union { T mVal; uint8_t mBuffer[sizeof(T)]; } u; @@ -339,81 +319,74 @@ } }; -template -class Endian : private EndianUtils -{ -protected: +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) - { + 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) - { + 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) - { + static MOZ_MUST_USE uint64_t readUint64(const void* aPtr) { return read(aPtr); } + /** Read a uintptr_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE uintptr_t readUintptr(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) - { + 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) - { + 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) - { + 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); + /** Read an intptr_t in ThisEndian endianness from |aPtr| and return it. */ + static MOZ_MUST_USE intptr_t readIntptr(const void* aPtr) { + return read(aPtr); } /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeUint32(void* aPtr, uint32_t aValue) - { - write(aPtr, aValue); - } + static void writeUint16(void* aPtr, uint16_t aValue) { write(aPtr, aValue); } /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeUint64(void* aPtr, uint64_t aValue) - { - write(aPtr, aValue); - } + static void writeUint32(void* aPtr, uint32_t aValue) { write(aPtr, aValue); } /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeInt16(void* aPtr, int16_t aValue) - { - write(aPtr, aValue); - } + static void writeUint64(void* aPtr, uint64_t aValue) { write(aPtr, aValue); } /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeInt32(void* aPtr, int32_t aValue) - { + static void writeUintptr(void* aPtr, uintptr_t aValue) { write(aPtr, aValue); } /** Write |aValue| to |aPtr| using ThisEndian endianness. */ - static void writeInt64(void* aPtr, int64_t aValue) - { - write(aPtr, aValue); - } + 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); } + + /** Write |aValue| to |aPtr| using ThisEndian endianness. */ + static void writeIntptr(void* aPtr, intptr_t aValue) { write(aPtr, aValue); } /* * Converts a value of type T to little-endian format. @@ -422,9 +395,8 @@ * native-endian format and you need it to appear in little-endian * format for transmission. */ - template - MOZ_MUST_USE static T swapToLittleEndian(T aValue) - { + template + MOZ_MUST_USE static T swapToLittleEndian(T aValue) { return maybeSwap(aValue); } @@ -433,28 +405,25 @@ * them to little-endian format if ThisEndian is Big. * As with memcpy, |aDest| and |aSrc| must not overlap. */ - template + template static void copyAndSwapToLittleEndian(void* aDest, const T* aSrc, - size_t aCount) - { + size_t aCount) { copyAndSwapTo(aDest, aSrc, aCount); } /* * Likewise, but converts values in place. */ - template - static void swapToLittleEndianInPlace(T* aPtr, size_t aCount) - { + 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) - { + template + MOZ_MUST_USE static T swapToBigEndian(T aValue) { return maybeSwap(aValue); } @@ -463,19 +432,17 @@ * them to big-endian format if ThisEndian is Little. * As with memcpy, |aDest| and |aSrc| must not overlap. */ - template + template static void copyAndSwapToBigEndian(void* aDest, const T* aSrc, - size_t aCount) - { + size_t aCount) { copyAndSwapTo(aDest, aSrc, aCount); } /* * Likewise, but converts values in place. */ - template - static void swapToBigEndianInPlace(T* aPtr, size_t aCount) - { + template + static void swapToBigEndianInPlace(T* aPtr, size_t aCount) { maybeSwapInPlace(aPtr, aCount); } @@ -484,32 +451,27 @@ * in network code. */ - template - MOZ_MUST_USE static T swapToNetworkOrder(T aValue) - { + template + MOZ_MUST_USE static T swapToNetworkOrder(T aValue) { return swapToBigEndian(aValue); } - template - static void - copyAndSwapToNetworkOrder(void* aDest, const T* aSrc, size_t aCount) - { + 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) - { + 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) - { + template + MOZ_MUST_USE static T swapFromLittleEndian(T aValue) { return maybeSwap(aValue); } @@ -518,28 +480,25 @@ * them to little-endian format if ThisEndian is Big. * As with memcpy, |aDest| and |aSrc| must not overlap. */ - template + template static void copyAndSwapFromLittleEndian(T* aDest, const void* aSrc, - size_t aCount) - { + size_t aCount) { copyAndSwapFrom(aDest, aSrc, aCount); } /* * Likewise, but converts values in place. */ - template - static void swapFromLittleEndianInPlace(T* aPtr, size_t aCount) - { + 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) - { + template + MOZ_MUST_USE static T swapFromBigEndian(T aValue) { return maybeSwap(aValue); } @@ -548,19 +507,17 @@ * them to big-endian format if ThisEndian is Little. * As with memcpy, |aDest| and |aSrc| must not overlap. */ - template + template static void copyAndSwapFromBigEndian(T* aDest, const void* aSrc, - size_t aCount) - { + size_t aCount) { copyAndSwapFrom(aDest, aSrc, aCount); } /* * Likewise, but converts values in place. */ - template - static void swapFromBigEndianInPlace(T* aPtr, size_t aCount) - { + template + static void swapFromBigEndianInPlace(T* aPtr, size_t aCount) { maybeSwapInPlace(aPtr, aCount); } @@ -568,35 +525,30 @@ * Synonyms for the big-endian functions, for better readability * in network code. */ - template - MOZ_MUST_USE static T swapFromNetworkOrder(T aValue) - { + template + MOZ_MUST_USE static T swapFromNetworkOrder(T aValue) { return swapFromBigEndian(aValue); } - template + template static void copyAndSwapFromNetworkOrder(T* aDest, const void* aSrc, - size_t aCount) - { + size_t aCount) { copyAndSwapFromBigEndian(aDest, aSrc, aCount); } - template - static void swapFromNetworkOrderInPlace(T* aPtr, size_t aCount) - { + template + static void swapFromNetworkOrderInPlace(T* aPtr, size_t aCount) { swapFromBigEndianInPlace(aPtr, aCount); } -private: + 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 - { + template + static T read(const void* aPtr) { + union { T mVal; uint8_t mBuffer[sizeof(T)]; } u; @@ -608,9 +560,8 @@ * Write a value of type T, in native endianness, to |aPtr|, in ThisEndian * endianness. */ - template - static void write(void* aPtr, T aValue) - { + template + static void write(void* aPtr, T aValue) { T tmp = maybeSwap(aValue); memcpy(aPtr, &tmp, sizeof(T)); } @@ -620,56 +571,56 @@ void operator=(const Endian& aOther) = delete; }; -template -class EndianReadWrite : public Endian -{ -private: +template +class EndianReadWrite : public Endian { + private: typedef Endian super; -public: - using super::readUint16; - using super::readUint32; - using super::readUint64; + public: using super::readInt16; using super::readInt32; using super::readInt64; - using super::writeUint16; - using super::writeUint32; - using super::writeUint64; + using super::readIntptr; + using super::readUint16; + using super::readUint32; + using super::readUint64; + using super::readUintptr; using super::writeInt16; using super::writeInt32; using super::writeInt64; + using super::writeIntptr; + using super::writeUint16; + using super::writeUint32; + using super::writeUint64; + using super::writeUintptr; }; } /* namespace detail */ -class LittleEndian final : public detail::EndianReadWrite -{}; +class LittleEndian final : public detail::EndianReadWrite {}; -class BigEndian final : public detail::EndianReadWrite -{}; +class BigEndian final : public detail::EndianReadWrite {}; typedef BigEndian NetworkEndian; -class NativeEndian final : public detail::Endian -{ -private: +class NativeEndian final : public detail::Endian { + private: typedef detail::Endian super; -public: + 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::copyAndSwapToBigEndian; using super::copyAndSwapToLittleEndian; - using super::swapToLittleEndianInPlace; + using super::copyAndSwapToNetworkOrder; using super::swapToBigEndian; - using super::copyAndSwapToBigEndian; using super::swapToBigEndianInPlace; + using super::swapToLittleEndian; + using super::swapToLittleEndianInPlace; using super::swapToNetworkOrder; - using super::copyAndSwapToNetworkOrder; using super::swapToNetworkOrderInPlace; /* @@ -677,14 +628,14 @@ * 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::copyAndSwapFromBigEndian; using super::copyAndSwapFromLittleEndian; - using super::swapFromLittleEndianInPlace; + using super::copyAndSwapFromNetworkOrder; using super::swapFromBigEndian; - using super::copyAndSwapFromBigEndian; using super::swapFromBigEndianInPlace; + using super::swapFromLittleEndian; + using super::swapFromLittleEndianInPlace; using super::swapFromNetworkOrder; - using super::copyAndSwapFromNetworkOrder; using super::swapFromNetworkOrderInPlace; }; 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 @@ -23,64 +23,36 @@ * using a 32 bit mask for each value so it will only work for enums with an int * representation less than 32. It works both for enum and enum class types. */ -template -class EnumSet -{ -public: - EnumSet() - : mBitField(0) - { - initVersion(); - } - - MOZ_IMPLICIT EnumSet(T aEnum) - : mBitField(bitFor(aEnum)) - { } - - EnumSet(T aEnum1, T aEnum2) - : mBitField(bitFor(aEnum1) | - bitFor(aEnum2)) - { - initVersion(); - } +template +class EnumSet { + public: + typedef uint32_t serializedType; + + EnumSet() : mBitField(0) {} + + MOZ_IMPLICIT EnumSet(T aEnum) : mBitField(bitFor(aEnum)) {} + + EnumSet(T aEnum1, T aEnum2) : mBitField(bitFor(aEnum1) | bitFor(aEnum2)) {} EnumSet(T aEnum1, T aEnum2, T aEnum3) - : mBitField(bitFor(aEnum1) | - bitFor(aEnum2) | - bitFor(aEnum3)) - { - initVersion(); - } + : mBitField(bitFor(aEnum1) | bitFor(aEnum2) | bitFor(aEnum3)) {} EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4) - : mBitField(bitFor(aEnum1) | - bitFor(aEnum2) | - bitFor(aEnum3) | - bitFor(aEnum4)) - { - initVersion(); - } + : mBitField(bitFor(aEnum1) | bitFor(aEnum2) | bitFor(aEnum3) | + bitFor(aEnum4)) {} - MOZ_IMPLICIT EnumSet(std::initializer_list list) - : mBitField(0) - { + MOZ_IMPLICIT EnumSet(std::initializer_list list) : mBitField(0) { for (auto value : list) { (*this) += value; } - initVersion(); } - EnumSet(const EnumSet& aEnumSet) - : mBitField(aEnumSet.mBitField) - { - initVersion(); - } + EnumSet(const EnumSet& aEnumSet) : mBitField(aEnumSet.mBitField) {} /** * Add an element */ - void operator+=(T aEnum) - { + void operator+=(T aEnum) { incVersion(); mBitField |= bitFor(aEnum); } @@ -88,8 +60,7 @@ /** * Add an element */ - EnumSet operator+(T aEnum) const - { + EnumSet operator+(T aEnum) const { EnumSet result(*this); result += aEnum; return result; @@ -98,8 +69,7 @@ /** * Union */ - void operator+=(const EnumSet aEnumSet) - { + void operator+=(const EnumSet aEnumSet) { incVersion(); mBitField |= aEnumSet.mBitField; } @@ -107,8 +77,7 @@ /** * Union */ - EnumSet operator+(const EnumSet aEnumSet) const - { + EnumSet operator+(const EnumSet aEnumSet) const { EnumSet result(*this); result += aEnumSet; return result; @@ -117,8 +86,7 @@ /** * Remove an element */ - void operator-=(T aEnum) - { + void operator-=(T aEnum) { incVersion(); mBitField &= ~(bitFor(aEnum)); } @@ -126,8 +94,7 @@ /** * Remove an element */ - EnumSet operator-(T aEnum) const - { + EnumSet operator-(T aEnum) const { EnumSet result(*this); result -= aEnum; return result; @@ -136,8 +103,7 @@ /** * Remove a set of elements */ - void operator-=(const EnumSet aEnumSet) - { + void operator-=(const EnumSet aEnumSet) { incVersion(); mBitField &= ~(aEnumSet.mBitField); } @@ -145,8 +111,7 @@ /** * Remove a set of elements */ - EnumSet operator-(const EnumSet aEnumSet) const - { + EnumSet operator-(const EnumSet aEnumSet) const { EnumSet result(*this); result -= aEnumSet; return result; @@ -155,8 +120,7 @@ /** * Clear */ - void clear() - { + void clear() { incVersion(); mBitField = 0; } @@ -164,8 +128,7 @@ /** * Intersection */ - void operator&=(const EnumSet aEnumSet) - { + void operator&=(const EnumSet aEnumSet) { incVersion(); mBitField &= aEnumSet.mBitField; } @@ -173,8 +136,7 @@ /** * Intersection */ - EnumSet operator&(const EnumSet aEnumSet) const - { + EnumSet operator&(const EnumSet aEnumSet) const { EnumSet result(*this); result &= aEnumSet; return result; @@ -183,24 +145,19 @@ /** * Equality */ - bool operator==(const EnumSet aEnumSet) const - { + bool operator==(const EnumSet aEnumSet) const { return mBitField == aEnumSet.mBitField; } /** * Test is an element is contained in the set. */ - bool contains(T aEnum) const - { - return mBitField & bitFor(aEnum); - } + bool contains(T aEnum) const { return mBitField & bitFor(aEnum); } /** * Return the number of elements in the set. */ - uint8_t size() const - { + uint8_t size() const { uint8_t count = 0; for (uint32_t bitField = mBitField; bitField; bitField >>= 1) { if (bitField & 1) { @@ -210,50 +167,39 @@ return count; } - bool isEmpty() const - { - return mBitField == 0; - } + bool isEmpty() const { return mBitField == 0; } - uint32_t serialize() const - { - return mBitField; - } + serializedType serialize() const { return mBitField; } - void deserialize(uint32_t aValue) - { + void deserialize(serializedType aValue) { incVersion(); mBitField = aValue; } - class ConstIterator - { + class ConstIterator { const EnumSet* mSet; uint32_t mPos; #ifdef DEBUG uint64_t mVersion; #endif - void checkVersion() { + void checkVersion() const { // 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) - { + : mSet(&aSet), mPos(aPos) { #ifdef DEBUG mVersion = mSet->mVersion; #endif MOZ_ASSERT(aPos <= kMaxBits); - if (aPos != kMaxBits && !mSet->contains(T(mPos))) - ++*this; + if (aPos != kMaxBits && !mSet->contains(T(mPos))) ++*this; } ConstIterator(const ConstIterator& aOther) - : mSet(aOther.mSet), mPos(aOther.mPos) - { + : mSet(aOther.mSet), mPos(aOther.mPos) { #ifdef DEBUG mVersion = aOther.mVersion; checkVersion(); @@ -261,8 +207,7 @@ } ConstIterator(ConstIterator&& aOther) - : mSet(aOther.mSet), mPos(aOther.mPos) - { + : mSet(aOther.mSet), mPos(aOther.mPos) { #ifdef DEBUG mVersion = aOther.mVersion; checkVersion(); @@ -270,21 +215,19 @@ aOther.mSet = nullptr; } - ~ConstIterator() { - checkVersion(); - } + ~ConstIterator() { checkVersion(); } - bool operator==(const ConstIterator& other) { + bool operator==(const ConstIterator& other) const { MOZ_ASSERT(mSet == other.mSet); checkVersion(); return mPos == other.mPos; } - bool operator!=(const ConstIterator& other) { + bool operator!=(const ConstIterator& other) const { return !(*this == other); } - T operator*() { + T operator*() const { MOZ_ASSERT(mSet); MOZ_ASSERT(mPos < kMaxBits); MOZ_ASSERT(mSet->contains(T(mPos))); @@ -303,28 +246,17 @@ } }; - ConstIterator begin() const { - return ConstIterator(*this, 0); - } + ConstIterator begin() const { return ConstIterator(*this, 0); } - ConstIterator end() const { - return ConstIterator(*this, kMaxBits); - } + ConstIterator end() const { return ConstIterator(*this, kMaxBits); } -private: - static uint32_t bitFor(T aEnum) - { + private: + static uint32_t bitFor(T aEnum) { uint32_t bitNumber = (uint32_t)aEnum; MOZ_ASSERT(bitNumber < kMaxBits); return 1U << bitNumber; } - void initVersion() { -#ifdef DEBUG - mVersion = 0; -#endif - } - void incVersion() { #ifdef DEBUG mVersion++; @@ -332,13 +264,13 @@ } static const size_t kMaxBits = 32; - uint32_t mBitField; + serializedType mBitField; #ifdef DEBUG - uint64_t mVersion; + uint64_t mVersion = 0; #endif }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_EnumSet_h_*/ 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 @@ -14,34 +14,31 @@ namespace detail { -template +template struct EnumFitsWithinHelper; // Signed enum, signed storage. -template +template struct EnumFitsWithinHelper - : public std::integral_constant -{}; + : public std::integral_constant {}; // Signed enum, unsigned storage. -template +template struct EnumFitsWithinHelper - : public std::integral_constant -{}; + : public std::integral_constant {}; // Unsigned enum, signed storage. -template +template struct EnumFitsWithinHelper - : public std::integral_constant -{}; + : public std::integral_constant {}; // Unsigned enum, unsigned storage. -template +template struct EnumFitsWithinHelper - : public std::integral_constant -{}; + : public std::integral_constant {}; -} // namespace detail +} // namespace detail /* * Type trait that determines whether the enum type T can fit within the @@ -52,19 +49,40 @@ * 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 +template struct EnumTypeFitsWithin - : public detail::EnumFitsWithinHelper< - sizeof(T), - std::is_signed::type>::value, - sizeof(Storage), - std::is_signed::value - > -{ + : 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"); + static_assert(std::is_integral::value, + "must provide an integral type"); }; -} // namespace mozilla +/* + * Provides information about highest enum member value. + * Each specialization of struct MaxEnumValue should define + * "static constexpr unsigned int value". + * + * example: + * + * enum ExampleEnum + * { + * CAT = 0, + * DOG, + * HAMSTER + * }; + * + * template <> + * struct MaxEnumValue + * { + * static constexpr unsigned int value = static_cast(HAMSTER); + * }; + */ +template +struct MaxEnumValue; // no need to define the primary template + +} // 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 @@ -38,54 +38,51 @@ * headCount[AnimalSpecies::Sheep] = 30; * */ -template -class EnumeratedArray -{ -public: +template +class EnumeratedArray { + public: static const size_t kSize = size_t(SizeAsEnumValue); -private: + private: typedef Array ArrayType; ArrayType mArray; -public: + public: EnumeratedArray() {} template MOZ_IMPLICIT EnumeratedArray(Args&&... aArgs) - : mArray{mozilla::Forward(aArgs)...} - {} + : mArray{mozilla::Forward(aArgs)...} {} - explicit EnumeratedArray(const EnumeratedArray& aOther) - { + explicit EnumeratedArray(const EnumeratedArray& aOther) { for (size_t i = 0; i < kSize; i++) { mArray[i] = aOther.mArray[i]; } } - EnumeratedArray(EnumeratedArray&& aOther) - { + EnumeratedArray(EnumeratedArray&& aOther) { for (size_t i = 0; i < kSize; i++) { mArray[i] = Move(aOther.mArray[i]); } } - ValueType& operator[](IndexType aIndex) - { + ValueType& operator[](IndexType aIndex) { return mArray[size_t(aIndex)]; } + + const ValueType& operator[](IndexType aIndex) const { return mArray[size_t(aIndex)]; } - const ValueType& operator[](IndexType aIndex) const - { - return mArray[size_t(aIndex)]; + EnumeratedArray& operator=(EnumeratedArray&& aOther) { + for (size_t i = 0; i < kSize; i++) { + mArray[i] = Move(aOther.mArray[i]); + } + return *this; } - typedef typename ArrayType::iterator iterator; - typedef typename ArrayType::const_iterator const_iterator; - typedef typename ArrayType::reverse_iterator reverse_iterator; + typedef typename ArrayType::iterator iterator; + typedef typename ArrayType::const_iterator const_iterator; + typedef typename ArrayType::reverse_iterator reverse_iterator; typedef typename ArrayType::const_reverse_iterator const_reverse_iterator; // Methods for range-based for loops. @@ -105,6 +102,6 @@ const_reverse_iterator crend() const { return mArray.crend(); } }; -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_EnumeratedArray_h +#endif // mozilla_EnumeratedArray_h 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 @@ -28,42 +28,36 @@ namespace detail { -template -class EnumeratedIterator -{ -public: +template +class EnumeratedIterator { + public: typedef typename std::underlying_type::type IntTypeT; - template - explicit EnumeratedIterator(EnumType aCurrent) - : mCurrent(aCurrent) { } + template + explicit EnumeratedIterator(EnumType aCurrent) : mCurrent(aCurrent) {} - template + template explicit EnumeratedIterator(const EnumeratedIterator& aOther) - : mCurrent(aOther.mCurrent) { } + : mCurrent(aOther.mCurrent) {} EnumTypeT operator*() const { return mCurrent; } /* Increment and decrement operators */ - EnumeratedIterator& operator++() - { + EnumeratedIterator& operator++() { mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1)); return *this; } - EnumeratedIterator& operator--() - { + EnumeratedIterator& operator--() { mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1)); return *this; } - EnumeratedIterator operator++(int) - { + EnumeratedIterator operator++(int) { auto ret = *this; mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1)); return ret; } - EnumeratedIterator operator--(int) - { + EnumeratedIterator operator--(int) { auto ret = *this; mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1)); return ret; @@ -71,83 +65,76 @@ /* Comparison operators */ - template + template friend bool operator==(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); - template + template friend bool operator!=(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); - template + template friend bool operator<(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); - template + template friend bool operator<=(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); - template + template friend bool operator>(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); - template + template friend bool operator>=(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); -private: + private: EnumTypeT mCurrent; }; -template +template bool operator==(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) -{ + const EnumeratedIterator& aIter2) { return aIter1.mCurrent == aIter2.mCurrent; } -template +template bool operator!=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) -{ + const EnumeratedIterator& aIter2) { return aIter1.mCurrent != aIter2.mCurrent; } -template +template bool operator<(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) -{ + const EnumeratedIterator& aIter2) { return aIter1.mCurrent < aIter2.mCurrent; } -template +template bool operator<=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) -{ + const EnumeratedIterator& aIter2) { return aIter1.mCurrent <= aIter2.mCurrent; } -template +template bool operator>(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) -{ + const EnumeratedIterator& aIter2) { return aIter1.mCurrent > aIter2.mCurrent; } -template +template bool operator>=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) -{ + const EnumeratedIterator& aIter2) { return aIter1.mCurrent >= aIter2.mCurrent; } -template -class EnumeratedRange -{ -public: +template +class EnumeratedRange { + public: typedef EnumeratedIterator iterator; typedef EnumeratedIterator const_iterator; typedef ReverseIterator reverse_iterator; typedef ReverseIterator const_reverse_iterator; - template + template EnumeratedRange(EnumType aBegin, EnumType aEnd) - : mBegin(aBegin), mEnd(aEnd) { } + : mBegin(aBegin), mEnd(aEnd) {} iterator begin() const { return iterator(mBegin); } const_iterator cbegin() const { return begin(); } @@ -158,44 +145,40 @@ reverse_iterator rend() const { return reverse_iterator(mBegin); } const_reverse_iterator crend() const { return rend(); } -private: + private: EnumTypeT mBegin; EnumTypeT mEnd; }; -} // namespace detail +} // namespace detail #ifdef __GNUC__ // Enums can have an unsigned underlying type, which makes some of the // comparisons below always true or always false. Temporarily disable // -Wtype-limits to avoid breaking -Werror builds. -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wtype-limits" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" #endif // Create a range to iterate from aBegin to aEnd, exclusive. -template -inline detail::EnumeratedRange -MakeEnumeratedRange(EnumType aBegin, EnumType aEnd) -{ +template +inline detail::EnumeratedRange MakeEnumeratedRange(EnumType aBegin, + EnumType aEnd) { MOZ_ASSERT(aBegin <= aEnd, "Cannot generate invalid, unbounded range!"); 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! -template -inline detail::EnumeratedRange -MakeEnumeratedRange(EnumType aEnd) -{ +template +inline detail::EnumeratedRange MakeEnumeratedRange(EnumType aEnd) { return MakeEnumeratedRange(EnumType(0), aEnd); } #ifdef __GNUC__ -# pragma GCC diagnostic pop +#pragma GCC diagnostic pop #endif -} // namespace mozilla - -#endif // mozilla_EnumeratedRange_h +} // namespace mozilla +#endif // mozilla_EnumeratedRange_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/FStream.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/FStream.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/FStream.h @@ -0,0 +1,124 @@ +/* -*- 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/. */ + +// Similar to std::ifstream/ofstream, but takes char16ptr_t on Windows. +// Until C++17, std functions can only take char* filenames. So Unicode +// filenames were lost on Windows. To address this limitations, this wrapper +// uses proprietary wchar_t* overloads on MSVC, and __gnu_cxx::stdio_filebuf +// extension on MinGW. Once we can use C++17 filesystem API everywhere, +// we will be able to avoid this wrapper. + +#ifndef mozilla_FStream_h +#define mozilla_FStream_h + +#include "mozilla/Char16.h" +#include +#include +#include +#if defined(__MINGW32__) && defined(__GLIBCXX__) +#include "mozilla/UniquePtr.h" +#include +#include +#endif + +namespace mozilla { + +#if defined(__MINGW32__) && defined(__GLIBCXX__) +// MinGW does not support wchar_t* overloads that are MSVC extension until +// C++17, so we have to implement widechar wrappers using a GNU extension. +class IFStream : public std::istream { + public: + explicit IFStream(char16ptr_t filename, openmode mode = in); + + std::filebuf* rdbuf() const { return mFileBuf.get(); } + + bool is_open() const { return mFileBuf && mFileBuf->is_open(); } + void open(char16ptr_t filename, openmode mode = in); + void close() { mFileBuf && mFileBuf->close(); } + + private: + UniquePtr mFileBuf; +}; + +inline IFStream::IFStream(char16ptr_t filename, openmode mode) + : std::istream(nullptr) { + open(filename, mode); +} + +inline void IFStream::open(char16ptr_t filename, openmode mode) { + int fmode = _O_RDONLY; + if (mode & binary) { + fmode |= _O_BINARY; + } else { + fmode |= _O_TEXT; + } + int fd = _wopen(filename, fmode); + mFileBuf = MakeUnique<__gnu_cxx::stdio_filebuf>(fd, mode); + std::istream::rdbuf(mFileBuf.get()); +} + +class OFStream : public std::ostream { + public: + explicit OFStream(char16ptr_t filename, openmode mode = out); + + std::filebuf* rdbuf() const { return mFileBuf.get(); } + + bool is_open() const { return mFileBuf && mFileBuf->is_open(); } + void open(char16ptr_t filename, openmode mode = out); + void close() { mFileBuf && mFileBuf->close(); } + + private: + UniquePtr mFileBuf; +}; + +inline OFStream::OFStream(char16ptr_t filename, openmode mode) + : std::ostream(nullptr) { + open(filename, mode); +} + +inline void OFStream::open(char16ptr_t filename, openmode mode) { + int fmode = _O_WRONLY; + if (mode & binary) { + fmode |= _O_BINARY; + } else { + fmode |= _O_TEXT; + } + if (mode & trunc) { + fmode |= _O_CREAT | _O_TRUNC; + } + int fd = _wopen(filename, fmode); + mFileBuf = MakeUnique<__gnu_cxx::stdio_filebuf>(fd, mode); + std::ostream::rdbuf(mFileBuf.get()); +} + +#elif defined(XP_WIN) +class IFStream : public std::ifstream { + public: + explicit IFStream(char16ptr_t filename, openmode mode = in) + : std::ifstream(filename, mode) {} + + void open(char16ptr_t filename, openmode mode = in) { + std::ifstream::open(filename, mode); + } +}; + +class OFStream : public std::ofstream { + public: + explicit OFStream(char16ptr_t filename, openmode mode = out) + : std::ofstream(filename, mode) {} + + void open(char16ptr_t filename, openmode mode = out) { + std::ofstream::open(filename, mode); + } +}; +#else +using IFStream = std::ifstream; +using OFStream = std::ofstream; +#endif + +} // namespace mozilla + +#endif /* mozilla_FStream_h */ 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 @@ -122,10 +122,10 @@ * P 1-P * * But the "1 or more" section of the line is subdivided the same way: *within - * that section*, in portion P the second call to |trial()| returns true, and in - * portion 1-P it returns false a second time; the skip count is two or more. - * So we return true on the second call in proportion 0.7 * 0.3, and skip at - * least the first two in proportion 0.7 * 0.7. + * that section*, in portion P the second call to |trial()| returns true, and + * in portion 1-P it returns false a second time; the skip count is two or + * more. So we return true on the second call in proportion 0.7 * 0.3, and + * skip at least the first two in proportion 0.7 * 0.7. * * skip: 0 1 2 or more * |------------------^------------^----------------------------| @@ -160,8 +160,8 @@ * it? This is exactly std::floor(std::log(X) / std::log(1-P)). * * Our algorithm is then, simply: When constructed, compute an initial skip - * count. Return false from |trial| that many times, and then compute a new skip - * count. + * count. Return false from |trial| that many times, and then compute a new + * skip count. * * For a call to |trial(n)|, if the skip count is greater than n, return false * and subtract n from the skip count. If the skip count is less than n, @@ -177,11 +177,10 @@ * random number generator; both may not be zero. */ FastBernoulliTrial(double aProbability, uint64_t aState0, uint64_t aState1) - : mProbability(0) - , mInvLogNotProbability(0) - , mGenerator(aState0, aState1) - , mSkipCount(0) - { + : mProbability(0), + mInvLogNotProbability(0), + mGenerator(aState0, aState1), + mSkipCount(0) { setProbability(aProbability); } @@ -306,7 +305,8 @@ /* Our random number generator. */ non_crypto::XorShift128PlusRNG mGenerator; - /* The number of times |trial| should return false before next returning true. */ + /* The number of times |trial| should return false before next returning true. + */ size_t mSkipCount; /* @@ -355,7 +355,7 @@ * double is 2^64, not 2^64-1, so this doesn't actually set skipCount to a * value that can be safely assigned to mSkipCount. * - * Jakub Oleson cleverly suggested flipping the sense of the comparison: if + * Jakob Olesen cleverly suggested flipping the sense of the comparison: if * we require that skipCount < SIZE_MAX, then because of the gaps (2048) * between doubles at that magnitude, the highest double less than 2^64 is * 2^64 - 2048, which is fine to store in a size_t. @@ -363,8 +363,8 @@ * (On 32-bit machines, all size_t values can be represented exactly in * double, so all is well.) */ - double skipCount = std::floor(std::log(mGenerator.nextDouble()) - * mInvLogNotProbability); + double skipCount = + std::floor(std::log(mGenerator.nextDouble()) * mInvLogNotProbability); if (skipCount < SIZE_MAX) mSkipCount = skipCount; else @@ -374,6 +374,6 @@ } }; -} /* namespace mozilla */ +} /* namespace mozilla */ #endif /* mozilla_FastBernoulliTrial_h */ 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 @@ -13,8 +13,11 @@ #include "mozilla/Attributes.h" #include "mozilla/Casting.h" #include "mozilla/MathAlgorithms.h" +#include "mozilla/MemoryChecking.h" #include "mozilla/Types.h" +#include "mozilla/TypeTraits.h" +#include #include namespace mozilla { @@ -34,33 +37,34 @@ * compiler bustage, particularly PGO-specific bustage. */ -struct FloatTypeTraits -{ - typedef uint32_t Bits; - - static const unsigned kExponentBias = 127; - static const unsigned kExponentShift = 23; - - static const Bits kSignBit = 0x80000000UL; - static const Bits kExponentBits = 0x7F800000UL; - static const Bits kSignificandBits = 0x007FFFFFUL; +struct FloatTypeTraits { + using Bits = uint32_t; + + static constexpr unsigned kExponentBias = 127; + static constexpr unsigned kExponentShift = 23; + + static constexpr Bits kSignBit = 0x80000000UL; + static constexpr Bits kExponentBits = 0x7F800000UL; + static constexpr Bits kSignificandBits = 0x007FFFFFUL; }; -struct DoubleTypeTraits -{ - typedef uint64_t Bits; - - static const unsigned kExponentBias = 1023; - static const unsigned kExponentShift = 52; - - static const Bits kSignBit = 0x8000000000000000ULL; - static const Bits kExponentBits = 0x7ff0000000000000ULL; - static const Bits kSignificandBits = 0x000fffffffffffffULL; +struct DoubleTypeTraits { + using Bits = uint64_t; + + static constexpr unsigned kExponentBias = 1023; + static constexpr unsigned kExponentShift = 52; + + static constexpr Bits kSignBit = 0x8000000000000000ULL; + static constexpr Bits kExponentBits = 0x7ff0000000000000ULL; + static constexpr Bits kSignificandBits = 0x000fffffffffffffULL; }; -template struct SelectTrait; -template<> struct SelectTrait : public FloatTypeTraits {}; -template<> struct SelectTrait : public DoubleTypeTraits {}; +template +struct SelectTrait; +template <> +struct SelectTrait : public FloatTypeTraits {}; +template <> +struct SelectTrait : public DoubleTypeTraits {}; /* * This struct contains details regarding the encoding of floating-point @@ -88,11 +92,10 @@ * http://en.wikipedia.org/wiki/IEEE_floating_point * http://en.wikipedia.org/wiki/Floating_point#IEEE_754:_floating_point_in_modern_computers */ -template -struct FloatingPoint : public SelectTrait -{ - typedef SelectTrait Base; - typedef typename Base::Bits Bits; +template +struct FloatingPoint : public SelectTrait { + using Base = SelectTrait; + using Bits = typename Base::Bits; static_assert((Base::kSignBit & Base::kExponentBits) == 0, "sign bit shouldn't overlap exponent bits"); @@ -101,8 +104,8 @@ static_assert((Base::kExponentBits & Base::kSignificandBits) == 0, "exponent bits shouldn't overlap significand bits"); - static_assert((Base::kSignBit | Base::kExponentBits | Base::kSignificandBits) == - ~Bits(0), + static_assert((Base::kSignBit | Base::kExponentBits | + Base::kSignificandBits) == ~Bits(0), "all bits accounted for"); /* @@ -116,25 +119,22 @@ }; /** Determines whether a float/double is NaN. */ -template -static MOZ_ALWAYS_INLINE bool -IsNaN(T aValue) -{ +template +static MOZ_ALWAYS_INLINE bool IsNaN(T aValue) { /* * A float/double is NaN if all exponent bits are 1 and the significand * contains at least one non-zero bit. */ typedef FloatingPoint Traits; typedef typename Traits::Bits Bits; - return (BitwiseCast(aValue) & Traits::kExponentBits) == Traits::kExponentBits && + return (BitwiseCast(aValue) & Traits::kExponentBits) == + Traits::kExponentBits && (BitwiseCast(aValue) & Traits::kSignificandBits) != 0; } /** Determines whether a float/double is +Infinity or -Infinity. */ -template -static MOZ_ALWAYS_INLINE bool -IsInfinite(T aValue) -{ +template +static MOZ_ALWAYS_INLINE bool IsInfinite(T aValue) { /* Infinities have all exponent bits set to 1 and an all-0 significand. */ typedef FloatingPoint Traits; typedef typename Traits::Bits Bits; @@ -143,10 +143,8 @@ } /** Determines whether a float/double is not NaN or infinite. */ -template -static MOZ_ALWAYS_INLINE bool -IsFinite(T aValue) -{ +template +static MOZ_ALWAYS_INLINE bool IsFinite(T aValue) { /* * NaN and Infinities are the only non-finite floats/doubles, and both have * all exponent bits set to 1. @@ -161,10 +159,8 @@ * Determines whether a float/double is negative or -0. It is an error * to call this method on a float/double which is NaN. */ -template -static MOZ_ALWAYS_INLINE bool -IsNegative(T aValue) -{ +template +static MOZ_ALWAYS_INLINE bool IsNegative(T aValue) { MOZ_ASSERT(!IsNaN(aValue), "NaN does not have a sign"); /* The sign bit is set if the double is negative. */ @@ -175,10 +171,8 @@ } /** Determines whether a float/double represents -0. */ -template -static MOZ_ALWAYS_INLINE bool -IsNegativeZero(T aValue) -{ +template +static MOZ_ALWAYS_INLINE bool IsNegativeZero(T aValue) { /* Only the sign bit is set if the value is -0. */ typedef FloatingPoint Traits; typedef typename Traits::Bits Bits; @@ -187,10 +181,8 @@ } /** Determines wether a float/double represents +0. */ -template -static MOZ_ALWAYS_INLINE bool -IsPositiveZero(T aValue) -{ +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; @@ -202,10 +194,8 @@ * Returns 0 if a float/double is NaN or infinite; * otherwise, the float/double is returned. */ -template -static MOZ_ALWAYS_INLINE T -ToZeroIfNonfinite(T aValue) -{ +template +static MOZ_ALWAYS_INLINE T ToZeroIfNonfinite(T aValue) { return IsFinite(aValue) ? aValue : 0; } @@ -215,10 +205,8 @@ * Zero is not special-cased, so ExponentComponent(0.0) is * -int_fast16_t(Traits::kExponentBias). */ -template -static MOZ_ALWAYS_INLINE int_fast16_t -ExponentComponent(T aValue) -{ +template +static MOZ_ALWAYS_INLINE int_fast16_t ExponentComponent(T aValue) { /* * The exponent component of a float/double is an unsigned number, biased * from its actual value. Subtract the bias to retrieve the actual exponent. @@ -226,15 +214,14 @@ typedef FloatingPoint Traits; typedef typename Traits::Bits Bits; Bits bits = BitwiseCast(aValue); - return int_fast16_t((bits & Traits::kExponentBits) >> Traits::kExponentShift) - + return int_fast16_t((bits & Traits::kExponentBits) >> + Traits::kExponentShift) - int_fast16_t(Traits::kExponentBias); } /** Returns +Infinity. */ -template -static MOZ_ALWAYS_INLINE T -PositiveInfinity() -{ +template +static MOZ_ALWAYS_INLINE T PositiveInfinity() { /* * Positive infinity has all exponent bits set, sign bit set to 0, and no * significand. @@ -244,10 +231,8 @@ } /** Returns -Infinity. */ -template -static MOZ_ALWAYS_INLINE T -NegativeInfinity() -{ +template +static MOZ_ALWAYS_INLINE T NegativeInfinity() { /* * Negative infinity has all exponent bits set, sign bit set to 1, and no * significand. @@ -260,11 +245,8 @@ * Computes the bit pattern for a NaN with the specified sign bit and * significand bits. */ -template::Bits Significand> -struct SpecificNaNBits -{ +template ::Bits Significand> +struct SpecificNaNBits { using Traits = FloatingPoint; static_assert(SignBit == 0 || SignBit == 1, "bad sign bit"); @@ -274,7 +256,7 @@ "significand must be nonzero"); static constexpr typename Traits::Bits value = - (SignBit * Traits::kSignBit) | Traits::kExponentBits | Significand; + (SignBit * Traits::kSignBit) | Traits::kExponentBits | Significand; }; /** @@ -293,83 +275,163 @@ * 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 void -SpecificNaN(int signbit, typename FloatingPoint::Bits significand, T* result) -{ +template +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); - BitwiseCast((signbit ? Traits::kSignBit : 0) | - Traits::kExponentBits | - significand, - result); + BitwiseCast( + (signbit ? Traits::kSignBit : 0) | Traits::kExponentBits | significand, + result); MOZ_ASSERT(IsNaN(*result)); } -template +template static MOZ_ALWAYS_INLINE T -SpecificNaN(int signbit, typename FloatingPoint::Bits significand) -{ +SpecificNaN(int signbit, typename FloatingPoint::Bits significand) { T t; SpecificNaN(signbit, significand, &t); return t; } /** Computes the smallest non-zero positive float/double value. */ -template -static MOZ_ALWAYS_INLINE T -MinNumberValue() -{ +template +static MOZ_ALWAYS_INLINE T MinNumberValue() { typedef FloatingPoint Traits; typedef typename Traits::Bits Bits; return BitwiseCast(Bits(1)); } +namespace detail { + +template +inline bool NumberEqualsSignedInteger(Float aValue, SignedInteger* aInteger) { + static_assert(IsSame::value || IsSame::value, + "Float must be an IEEE-754 floating point type"); + static_assert(IsSigned::value, + "this algorithm only works for signed types: a different one " + "will be required for unsigned types"); + static_assert(sizeof(SignedInteger) >= sizeof(int), + "this function *might* require some finessing for signed types " + "subject to integral promotion before it can be used on them"); + + MOZ_MAKE_MEM_UNDEFINED(aInteger, sizeof(*aInteger)); + + // NaNs and infinities are not integers. + if (!IsFinite(aValue)) { + return false; + } + + // Otherwise do direct comparisons against the minimum/maximum |SignedInteger| + // values that can be encoded in |Float|. + + constexpr SignedInteger MaxIntValue = + std::numeric_limits::max(); // e.g. INT32_MAX + constexpr SignedInteger MinValue = + std::numeric_limits::min(); // e.g. INT32_MIN + + static_assert(IsPowerOfTwo(Abs(MinValue)), + "MinValue should be is a small power of two, thus exactly " + "representable in float/double both"); + + constexpr unsigned SignedIntegerWidth = CHAR_BIT * sizeof(SignedInteger); + constexpr unsigned ExponentShift = FloatingPoint::kExponentShift; + + // Careful! |MaxIntValue| may not be the maximum |SignedInteger| value that + // can be encoded in |Float|. Its |SignedIntegerWidth - 1| bits of precision + // may exceed |Float|'s |ExponentShift + 1| bits of precision. If necessary, + // compute the maximum |SignedInteger| that fits in |Float| from IEEE-754 + // first principles. (|MinValue| doesn't have this problem because as a + // [relatively] small power of two it's always representable in |Float|.) + + // Per C++11 [expr.const]p2, unevaluated subexpressions of logical AND/OR and + // conditional expressions *may* contain non-constant expressions, without + // making the enclosing expression not constexpr. MSVC implements this -- but + // it sometimes warns about undefined behavior in unevaluated subexpressions. + // This bites us if we initialize |MaxValue| the obvious way including an + // |uint64_t(1) << (SignedIntegerWidth - 2 - ExponentShift)| subexpression. + // Pull that shift-amount out and give it a not-too-huge value when it's in an + // unevaluated subexpression. 🙄 + constexpr unsigned PrecisionExceededShiftAmount = + ExponentShift > SignedIntegerWidth - 1 + ? 0 + : SignedIntegerWidth - 2 - ExponentShift; + + constexpr SignedInteger MaxValue = + ExponentShift > SignedIntegerWidth - 1 + ? MaxIntValue + : SignedInteger((uint64_t(1) << (SignedIntegerWidth - 1)) - + (uint64_t(1) << PrecisionExceededShiftAmount)); + + if (static_cast(MinValue) <= aValue && + aValue <= static_cast(MaxValue)) { + auto possible = static_cast(aValue); + if (static_cast(possible) == aValue) { + *aInteger = possible; + return true; + } + } + + return false; +} + +template +inline bool NumberIsSignedInteger(Float aValue, SignedInteger* aInteger) { + static_assert(IsSame::value || IsSame::value, + "Float must be an IEEE-754 floating point type"); + static_assert(IsSigned::value, + "this algorithm only works for signed types: a different one " + "will be required for unsigned types"); + static_assert(sizeof(SignedInteger) >= sizeof(int), + "this function *might* require some finessing for signed types " + "subject to integral promotion before it can be used on them"); + + MOZ_MAKE_MEM_UNDEFINED(aInteger, sizeof(*aInteger)); + + if (IsNegativeZero(aValue)) { + return false; + } + + return NumberEqualsSignedInteger(aValue, aInteger); +} + +} // namespace detail + /** - * If aValue is equal to some int32_t value, set *aInt32 to that value and - * return true; otherwise return false. + * If |aValue| is identical to some |int32_t| value, set |*aInt32| to that value + * and return true. Otherwise return false, leaving |*aInt32| in an + * indeterminate state. * - * Note that negative zero is "equal" to zero here. To test whether a value can - * be losslessly converted to int32_t and back, use NumberIsInt32 instead. + * This method returns false for negative zero. If you want to consider -0 to + * be 0, use NumberEqualsInt32 below. */ -template -static MOZ_ALWAYS_INLINE bool -NumberEqualsInt32(T aValue, int32_t* aInt32) -{ - /* - * XXX Casting a floating-point value that doesn't truncate to int32_t, to - * int32_t, induces undefined behavior. We should definitely fix this - * (bug 744965), but as apparently it "works" in practice, it's not a - * pressing concern now. - */ - return aValue == (*aInt32 = int32_t(aValue)); +template +static MOZ_ALWAYS_INLINE bool NumberIsInt32(T aValue, int32_t* aInt32) { + return detail::NumberIsSignedInteger(aValue, aInt32); } /** - * If d can be converted to int32_t and back to an identical double value, - * set *aInt32 to that value and return true; otherwise return false. + * If |aValue| is equal to some int32_t value (where -0 and +0 are considered + * equal), set |*aInt32| to that value and return true. Otherwise return false, + * leaving |*aInt32| in an indeterminate state. * - * The difference between this and NumberEqualsInt32 is that this method returns - * false for negative zero. + * |NumberEqualsInt32(-0.0, ...)| will return true. To test whether a value can + * be losslessly converted to |int32_t| and back, use NumberIsInt32 above. */ -template -static MOZ_ALWAYS_INLINE bool -NumberIsInt32(T aValue, int32_t* aInt32) -{ - return !IsNegativeZero(aValue) && NumberEqualsInt32(aValue, aInt32); +template +static MOZ_ALWAYS_INLINE bool NumberEqualsInt32(T aValue, int32_t* aInt32) { + return detail::NumberEqualsSignedInteger(aValue, aInt32); } /** * Computes a NaN value. Do not use this method if you depend upon a particular * NaN value being returned. */ -template -static MOZ_ALWAYS_INLINE T -UnspecifiedNaN() -{ +template +static MOZ_ALWAYS_INLINE T UnspecifiedNaN() { /* * If we can use any quiet NaN, we might as well use the all-ones NaN, * since it's cheap to materialize on common platforms (such as x64, where @@ -385,10 +447,8 @@ * any NaN value to any other NaN value. (The normal equality operators equate * -0 with +0, and they equate NaN to no other value.) */ -template -static inline bool -NumbersAreIdentical(T aValue1, T aValue2) -{ +template +static inline bool NumbersAreIdentical(T aValue1, T aValue2) { typedef FloatingPoint Traits; typedef typename Traits::Bits Bits; if (IsNaN(aValue1)) { @@ -399,24 +459,22 @@ namespace detail { -template +template struct FuzzyEqualsEpsilon; -template<> -struct FuzzyEqualsEpsilon -{ +template <> +struct FuzzyEqualsEpsilon { // A number near 1e-5 that is exactly representable in a float. static float value() { return 1.0f / (1 << 17); } }; -template<> -struct FuzzyEqualsEpsilon -{ +template <> +struct FuzzyEqualsEpsilon { // A number near 1e-12 that is exactly representable in a double. static double value() { return 1.0 / (1LL << 40); } }; -} // namespace detail +} // namespace detail /** * Compare two floating point values for equality, modulo rounding error. That @@ -430,11 +488,9 @@ * numbers you are dealing with is bounded and stays around the same order of * magnitude. */ -template -static MOZ_ALWAYS_INLINE bool -FuzzyEqualsAdditive(T aValue1, T aValue2, - T aEpsilon = detail::FuzzyEqualsEpsilon::value()) -{ +template +static MOZ_ALWAYS_INLINE bool FuzzyEqualsAdditive( + T aValue1, T aValue2, T aEpsilon = detail::FuzzyEqualsEpsilon::value()) { static_assert(IsFloatingPoint::value, "floating point type required"); return Abs(aValue1 - aValue2) <= aEpsilon; } @@ -451,11 +507,9 @@ * the floating point numbers being compared, regardless of what order of * magnitude those numbers are at. */ -template -static MOZ_ALWAYS_INLINE bool -FuzzyEqualsMultiplicative(T aValue1, T aValue2, - T aEpsilon = detail::FuzzyEqualsEpsilon::value()) -{ +template +static MOZ_ALWAYS_INLINE bool FuzzyEqualsMultiplicative( + T aValue1, T aValue2, T aEpsilon = detail::FuzzyEqualsEpsilon::value()) { static_assert(IsFloatingPoint::value, "floating point type required"); // can't use std::min because of bug 965340 T smaller = Abs(aValue1) < Abs(aValue2) ? Abs(aValue1) : Abs(aValue2); @@ -471,8 +525,7 @@ * This function isn't inlined to avoid buggy optimizations by MSVC. */ MOZ_MUST_USE -extern MFBT_API bool -IsFloat32Representable(double aFloat32); +extern MFBT_API bool IsFloat32Representable(double aFloat32); } /* namespace mozilla */ 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 @@ -1,223 +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/. */ - -/* A type-erased callable wrapper. */ - -#ifndef mozilla_Function_h -#define mozilla_Function_h - -#include "mozilla/Attributes.h" // for MOZ_IMPLICIT -#include "mozilla/Move.h" -#include "mozilla/RefCounted.h" -#include "mozilla/RefPtr.h" - -// |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. -// -// Supported callable types include non-member functions, static member -// functions, and function objects (that is to say, objects with an overloaded -// call operator; this includes C++11 lambdas). Member functions aren't -// directly supported; they first need to be wrapped into a function object -// using |std::mem_fn()| or an equivalent. -// -// |Signature| is a type of the form |ReturnType(Arguments...)|. Syntactically, -// 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 -// considered "empty". Invoking an empty instance is undefined behaviour. -// An empty instance can be populated with a callable by assigning to it. -// -// This class is intended to provide functionality similar to the C++11 -// standard library class |std::function|. - -namespace mozilla { - -namespace detail { - -template -class FunctionImplBase : public mozilla::RefCounted> -{ -public: - MOZ_DECLARE_REFCOUNTED_TYPENAME(FunctionImplBase) - - virtual ~FunctionImplBase() {} - virtual ReturnType call(Arguments... aArguments) = 0; -}; - -// Normal Callable Object. -template -class FunctionImpl : public FunctionImplBase -{ - public: - explicit FunctionImpl(const Callable& aCallable) - : mCallable(aCallable) {} - - ReturnType call(Arguments... aArguments) override - { - return mCallable(Forward(aArguments)...); - } - private: - Callable mCallable; -}; - -// Base class for passing pointer to member function. -template -class MemberFunctionImplBase : public FunctionImplBase -{ -public: - explicit MemberFunctionImplBase(const Callable& aCallable) - : mCallable(aCallable) {} - - ReturnType call(Arguments... aArguments) override - { - return callInternal(Forward(aArguments)...); - } -private: - template - ReturnType callInternal(ThisType* aThis, Args&&... aArguments) - { - return (aThis->*mCallable)(Forward(aArguments)...); - } - - template - ReturnType callInternal(ThisType&& aThis, Args&&... aArguments) - { - return (aThis.*mCallable)(Forward(aArguments)...); - } - Callable mCallable; -}; - -// For non-const member function specialization of FunctionImpl. -template -class FunctionImpl - : public MemberFunctionImplBase -{ -public: - explicit FunctionImpl(ReturnType(ThisType::*aMemberFunc)(Args...)) - : MemberFunctionImplBase(aMemberFunc) - {} -}; - -// For const member function specialization of FunctionImpl. -template -class FunctionImpl - : public MemberFunctionImplBase -{ -public: - explicit FunctionImpl(ReturnType(ThisType::*aConstMemberFunc)(Args...) const) - : MemberFunctionImplBase(aConstMemberFunc) - {} -}; - -} // namespace detail - -// The primary template is never defined. As |Signature| is required to be -// of the form |ReturnType(Arguments...)|, we only define a partial -// specialization that matches this form. This allows us to use |ReturnType| -// and |Arguments| in the definition of the specialization without having to -// introspect |Signature|. -template -class function; - -template -class function -{ -public: - function() {} - - // This constructor is implicit to match the interface of |std::function|. - template - 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) { - mImpl = Move(aOther.mImpl); - return *this; - } - - template - function& operator=(const Callable& 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; - } - - template - ReturnType operator()(Args&&... aArguments) const - { - MOZ_ASSERT(mImpl); - return mImpl->call(Forward(aArguments)...); - } - - explicit operator bool() const - { - return bool(mImpl); - } - -private: - // TODO: Consider implementing a small object optimization. - 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/GuardObjects.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/GuardObjects.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/GuardObjects.h @@ -75,19 +75,14 @@ * For more details, and examples of using these macros, see * https://developer.mozilla.org/en/Using_RAII_classes_in_Mozilla */ -class GuardObjectNotifier -{ -private: +class GuardObjectNotifier { + private: bool* mStatementDone; -public: - GuardObjectNotifier() - : mStatementDone(reinterpret_cast(MOZ_POISON)) - { - } + public: + GuardObjectNotifier() : mStatementDone(reinterpret_cast(MOZ_POISON)) {} - ~GuardObjectNotifier() - { + ~GuardObjectNotifier() { // Assert that the GuardObjectNotifier has been properly initialized by // using the |MOZ_GUARD_OBJECT_NOTIFIER_INIT| macro. A poison value is // used rather than a null check to appease static analyzers that were @@ -96,19 +91,17 @@ *mStatementDone = true; } - void setStatementDone(bool* aStatementIsDone) - { + void setStatementDone(bool* aStatementIsDone) { mStatementDone = aStatementIsDone; } }; -class GuardObjectNotificationReceiver -{ -private: +class GuardObjectNotificationReceiver { + private: bool mStatementDone; -public: - GuardObjectNotificationReceiver() : mStatementDone(false) { } + public: + GuardObjectNotificationReceiver() : mStatementDone(false) {} ~GuardObjectNotificationReceiver() { /* @@ -116,11 +109,11 @@ * this assert might also fire if init is not called because the guard * object's implementation is not using the above macros correctly.) */ - MOZ_ASSERT(mStatementDone); + MOZ_ASSERT(mStatementDone, + "Guard object should not be used as a temporary."); } - void init(GuardObjectNotifier& aNotifier) - { + void init(GuardObjectNotifier& aNotifier) { aNotifier.setStatementDone(&mStatementDone); } }; @@ -133,33 +126,36 @@ #endif /* DEBUG */ #ifdef DEBUG -# define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER \ - mozilla::detail::GuardObjectNotificationReceiver _mCheckNotUsedAsTemporary; -# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM \ - , mozilla::detail::GuardObjectNotifier&& _notifier = \ - mozilla::detail::GuardObjectNotifier() -# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM \ - mozilla::detail::GuardObjectNotifier&& _notifier = \ - mozilla::detail::GuardObjectNotifier() -# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL \ - , mozilla::detail::GuardObjectNotifier&& _notifier -# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL \ - mozilla::detail::GuardObjectNotifier&& _notifier -# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT \ - , mozilla::Move(_notifier) -# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT \ - mozilla::Move(_notifier) -# define MOZ_GUARD_OBJECT_NOTIFIER_INIT \ - do { _mCheckNotUsedAsTemporary.init(_notifier); } while (0) +#define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER \ + ::mozilla::detail::GuardObjectNotificationReceiver _mCheckNotUsedAsTemporary; +#define MOZ_GUARD_OBJECT_NOTIFIER_PARAM \ + , ::mozilla::detail::GuardObjectNotifier&& _notifier = \ + ::mozilla::detail::GuardObjectNotifier() +#define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM \ + ::mozilla::detail::GuardObjectNotifier&& _notifier = \ + ::mozilla::detail::GuardObjectNotifier() +#define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL \ + , ::mozilla::detail::GuardObjectNotifier&& _notifier +#define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL \ + ::mozilla::detail::GuardObjectNotifier&& _notifier +#define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT , ::mozilla::Move(_notifier) +#define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT \ + ::mozilla::Move(_notifier) +#define MOZ_GUARD_OBJECT_NOTIFIER_INIT \ + do { \ + _mCheckNotUsedAsTemporary.init(_notifier); \ + } while (0) #else -# define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM -# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM -# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL -# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL -# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT -# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT -# define MOZ_GUARD_OBJECT_NOTIFIER_INIT do { } while (0) +#define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +#define MOZ_GUARD_OBJECT_NOTIFIER_PARAM +#define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM +#define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL +#define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL +#define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT +#define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT +#define MOZ_GUARD_OBJECT_NOTIFIER_INIT \ + do { \ + } while (0) #endif #endif /* __cplusplus */ 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 @@ -52,10 +52,10 @@ #include "mozilla/Char16.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/Types.h" +#include "mozilla/WrappingOperations.h" #include -#ifdef __cplusplus namespace mozilla { /** @@ -63,18 +63,9 @@ */ static const uint32_t kGoldenRatioU32 = 0x9E3779B9U; -inline uint32_t -RotateBitsLeft32(uint32_t aValue, uint8_t aBits) -{ - MOZ_ASSERT(aBits < 32); - return (aValue << aBits) | (aValue >> (32 - aBits)); -} - namespace detail { -inline uint32_t -AddU32ToHash(uint32_t aHash, uint32_t aValue) -{ +inline uint32_t AddU32ToHash(uint32_t aHash, uint32_t aValue) { /* * This is the meat of all our hash routines. This hash function is not * particularly sophisticated, but it seems to work well for our mostly @@ -96,52 +87,40 @@ * Otherwise, if |aHash| is 0 (as it often is for the beginning of a * message), the expression * - * (kGoldenRatioU32 * RotateBitsLeft(aHash, 5)) |xor| aValue + * mozilla::WrappingMultiply(kGoldenRatioU32, RotateBitsLeft(aHash, 5)) + * |xor| + * aValue * * evaluates to |aValue|. * * (Number-theoretic aside: Because any odd number |m| is relatively prime to - * our modulus (2^32), the list + * our modulus (2**32), the list * - * [x * m (mod 2^32) for 0 <= x < 2^32] + * [x * m (mod 2**32) for 0 <= x < 2**32] * * has no duplicate elements. This means that multiplying by |m| does not * cause us to skip any possible hash values. * - * It's also nice if |m| has large-ish order mod 2^32 -- that is, if the - * smallest k such that m^k == 1 (mod 2^32) is large -- so we can safely + * It's also nice if |m| has large-ish order mod 2**32 -- that is, if the + * smallest k such that m**k == 1 (mod 2**32) is large -- so we can safely * multiply our hash value by |m| a few times without negating the - * multiplicative effect. Our golden ratio constant has order 2^29, which is + * multiplicative effect. Our golden ratio constant has order 2**29, which is * more than enough for our purposes.) */ - return kGoldenRatioU32 * (RotateBitsLeft32(aHash, 5) ^ aValue); + return mozilla::WrappingMultiply(kGoldenRatioU32, + RotateLeft(aHash, 5) ^ aValue); } /** * AddUintptrToHash takes sizeof(uintptr_t) as a template parameter. */ -template -inline uint32_t -AddUintptrToHash(uint32_t aHash, uintptr_t aValue); - -template<> -inline uint32_t -AddUintptrToHash<4>(uint32_t aHash, uintptr_t aValue) -{ +template +inline uint32_t AddUintptrToHash(uint32_t aHash, uintptr_t aValue) { return AddU32ToHash(aHash, static_cast(aValue)); } -template<> -inline uint32_t -AddUintptrToHash<8>(uint32_t aHash, uintptr_t aValue) -{ - /* - * The static cast to uint64_t below is necessary because this function - * sometimes gets compiled on 32-bit platforms (yes, even though it's a - * template and we never call this particular override in a 32-bit build). If - * we do aValue >> 32 on a 32-bit machine, we're shifting a 32-bit uintptr_t - * right 32 bits, and the compiler throws an error. - */ +template <> +inline uint32_t AddUintptrToHash<8>(uint32_t aHash, uintptr_t aValue) { uint32_t v1 = static_cast(aValue); uint32_t v2 = static_cast(static_cast(aValue) >> 32); return AddU32ToHash(AddU32ToHash(aHash, v1), v2); @@ -156,10 +135,9 @@ * Currently, we support hashing uint32_t's, values which we can implicitly * convert to uint32_t, data pointers, and function pointers. */ -template -MOZ_MUST_USE inline uint32_t -AddToHash(uint32_t aHash, A aA) -{ +template ::value, + typename U = typename mozilla::EnableIf::Type> +MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, T aA) { /* * Try to convert |A| to uint32_t implicitly. If this works, great. If not, * we'll error out. @@ -167,10 +145,8 @@ return detail::AddU32ToHash(aHash, aA); } -template -MOZ_MUST_USE inline uint32_t -AddToHash(uint32_t aHash, A* aA) -{ +template +MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, A* aA) { /* * You might think this function should just take a void*. But then we'd only * catch data pointers and couldn't handle function pointers. @@ -181,17 +157,18 @@ return detail::AddUintptrToHash(aHash, uintptr_t(aA)); } -template<> -MOZ_MUST_USE inline uint32_t -AddToHash(uint32_t aHash, uintptr_t aA) -{ - return detail::AddUintptrToHash(aHash, aA); +// We use AddUintptrToHash() for hashing all integral types. 8-byte integral +// types are treated the same as 64-bit pointers, and smaller integral types are +// first implicitly converted to 32 bits and then passed to AddUintptrToHash() +// to be hashed. +template ::value>::Type> +MOZ_MUST_USE inline uint32_t AddToHash(uint32_t aHash, T aA) { + return detail::AddUintptrToHash(aHash, aA); } -template -MOZ_MUST_USE uint32_t -AddToHash(uint32_t aHash, A aArg, Args... aArgs) -{ +template +MOZ_MUST_USE uint32_t AddToHash(uint32_t aHash, A aArg, Args... aArgs) { return AddToHash(AddToHash(aHash, aArg), aArgs...); } @@ -202,19 +179,15 @@ * much better than calling AddToHash(x, y), because AddToHash(x, y) assumes * that x has already been hashed. */ -template -MOZ_MUST_USE inline uint32_t -HashGeneric(Args... aArgs) -{ +template +MOZ_MUST_USE inline uint32_t HashGeneric(Args... aArgs) { return AddToHash(0, aArgs...); } namespace detail { -template -uint32_t -HashUntilZero(const T* aStr) -{ +template +uint32_t HashUntilZero(const T* aStr) { uint32_t hash = 0; for (T c; (c = *aStr); aStr++) { hash = AddToHash(hash, c); @@ -222,10 +195,8 @@ return hash; } -template -uint32_t -HashKnownLength(const T* aStr, size_t aLength) -{ +template +uint32_t HashKnownLength(const T* aStr, size_t aLength) { uint32_t hash = 0; for (size_t i = 0; i < aLength; i++) { hash = AddToHash(hash, aStr[i]); @@ -241,34 +212,25 @@ * If you have the string's length, you might as well call the overload which * includes the length. It may be marginally faster. */ -MOZ_MUST_USE inline uint32_t -HashString(const char* aStr) -{ +MOZ_MUST_USE inline uint32_t HashString(const char* aStr) { return detail::HashUntilZero(reinterpret_cast(aStr)); } -MOZ_MUST_USE inline uint32_t -HashString(const char* aStr, size_t aLength) -{ - return detail::HashKnownLength(reinterpret_cast(aStr), aLength); +MOZ_MUST_USE inline uint32_t HashString(const char* aStr, size_t aLength) { + return detail::HashKnownLength(reinterpret_cast(aStr), + aLength); } MOZ_MUST_USE -inline uint32_t -HashString(const unsigned char* aStr, size_t aLength) -{ +inline uint32_t HashString(const unsigned char* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); } -MOZ_MUST_USE inline uint32_t -HashString(const char16_t* aStr) -{ +MOZ_MUST_USE inline uint32_t HashString(const char16_t* aStr) { return detail::HashUntilZero(aStr); } -MOZ_MUST_USE inline uint32_t -HashString(const char16_t* aStr, size_t aLength) -{ +MOZ_MUST_USE inline uint32_t HashString(const char16_t* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); } @@ -277,15 +239,11 @@ * the same width! */ #ifdef WIN32 -MOZ_MUST_USE inline uint32_t -HashString(const wchar_t* aStr) -{ +MOZ_MUST_USE inline uint32_t HashString(const wchar_t* aStr) { return detail::HashUntilZero(aStr); } -MOZ_MUST_USE inline uint32_t -HashString(const wchar_t* aStr, size_t aLength) -{ +MOZ_MUST_USE inline uint32_t HashString(const wchar_t* aStr, size_t aLength) { return detail::HashKnownLength(aStr, aLength); } #endif @@ -296,8 +254,8 @@ * 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_MUST_USE extern MFBT_API uint32_t -HashBytes(const void* bytes, size_t aLength); +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. @@ -315,31 +273,28 @@ * * The algorithm is SipHash-1-3. See . */ -class HashCodeScrambler -{ +class HashCodeScrambler { struct SipHasher; uint64_t mK0, mK1; -public: + public: /** Creates a new scrambler with the given 128-bit key. */ - constexpr HashCodeScrambler(uint64_t aK0, uint64_t aK1) : mK0(aK0), mK1(aK1) {} + 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 - { + 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) - { + private: + struct SipHasher { + SipHasher(uint64_t aK0, uint64_t aK1) { // 1. Initialization. mV0 = aK0 ^ UINT64_C(0x736f6d6570736575); mV1 = aK1 ^ UINT64_C(0x646f72616e646f6d); @@ -347,8 +302,7 @@ mV3 = aK1 ^ UINT64_C(0x7465646279746573); } - uint64_t sipHash(uint64_t aM) - { + uint64_t sipHash(uint64_t aM) { // 2. Compression. mV3 ^= aM; sipRound(); @@ -356,13 +310,12 @@ // 3. Finalization. mV2 ^= 0xff; - for (int i = 0; i < 3; i++) - sipRound(); + for (int i = 0; i < 3; i++) sipRound(); return mV0 ^ mV1 ^ mV2 ^ mV3; } - void sipRound() - { + MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW + void sipRound() { mV0 += mV1; mV1 = RotateLeft(mV1, 13); mV1 ^= mV0; @@ -384,6 +337,5 @@ }; } /* namespace mozilla */ -#endif /* __cplusplus */ #endif /* mozilla_HashFunctions_h */ 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 @@ -40,7 +40,7 @@ * containing indices corresponding to the tuple indices. * * template - * void Helper(const Tuple& t, IndexSequence) + * void Helper(const Tuple& t, IndexSequence) * { * Foo(Get(t)...); * } @@ -71,9 +71,8 @@ /** * Represents a compile-time sequence of integer indices. */ -template -struct IndexSequence -{ +template +struct IndexSequence { static constexpr size_t Size() { return sizeof...(Indices); } }; @@ -81,35 +80,31 @@ // Helpers used by MakeIndexSequence. -template -struct IndexTuple -{ +template +struct IndexTuple { typedef IndexTuple Next; }; // Builds IndexTuple<0, 1, ..., N - 1>. -template -struct BuildIndexTuple -{ +template +struct BuildIndexTuple { typedef typename BuildIndexTuple::Type::Next Type; }; -template<> -struct BuildIndexTuple<0> -{ +template <> +struct BuildIndexTuple<0> { typedef IndexTuple<> Type; }; -template +template struct MakeIndexSequenceImpl; -template -struct MakeIndexSequenceImpl> -{ +template +struct MakeIndexSequenceImpl> { typedef IndexSequence Type; }; -} // namespace detail +} // namespace detail /** * A utility for building an IndexSequence of consecutive indices. @@ -117,11 +112,10 @@ * Note: unlike std::make_index_sequence, this is not an alias template * to work around bugs in MSVC 2013. */ -template -struct MakeIndexSequence -{ - typedef typename detail::MakeIndexSequenceImpl::Type>::Type Type; +template +struct MakeIndexSequence { + typedef typename detail::MakeIndexSequenceImpl< + N, typename detail::BuildIndexTuple::Type>::Type Type; }; /** @@ -132,12 +126,11 @@ * Note: unlike std::index_sequence_for, this is not an alias template * to work around bugs in MSVC 2013. */ -template -struct IndexSequenceFor -{ +template +struct IndexSequenceFor { typedef typename MakeIndexSequence::Type Type; }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_IndexSequence_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/IntegerPrintfMacros.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/IntegerPrintfMacros.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/IntegerPrintfMacros.h @@ -11,8 +11,8 @@ /* * These macros should not be used with the NSPR printf-like functions or their - * users, e.g. mozilla/Logging.h. If you need to use NSPR's facilities, see the - * comment on supported formats at the top of nsprpub/pr/include/prprf.h. + * users. If you need to use NSPR's facilities, see the comment on + * supported formats at the top of nsprpub/pr/include/prprf.h. */ /* @@ -35,18 +35,50 @@ * definitions match the actual type sizes seen at compile time. */ #if defined(ANDROID) && !defined(__LP64__) -# undef PRIdPTR /* intptr_t */ -# define PRIdPTR "d" /* intptr_t */ -# undef PRIiPTR /* intptr_t */ -# define PRIiPTR "i" /* intptr_t */ -# undef PRIoPTR /* uintptr_t */ -# define PRIoPTR "o" /* uintptr_t */ -# undef PRIuPTR /* uintptr_t */ -# define PRIuPTR "u" /* uintptr_t */ -# undef PRIxPTR /* uintptr_t */ -# define PRIxPTR "x" /* uintptr_t */ -# undef PRIXPTR /* uintptr_t */ -# define PRIXPTR "X" /* uintptr_t */ +#undef PRIdPTR /* intptr_t */ +#define PRIdPTR "d" /* intptr_t */ +#undef PRIiPTR /* intptr_t */ +#define PRIiPTR "i" /* intptr_t */ +#undef PRIoPTR /* uintptr_t */ +#define PRIoPTR "o" /* uintptr_t */ +#undef PRIuPTR /* uintptr_t */ +#define PRIuPTR "u" /* uintptr_t */ +#undef PRIxPTR /* uintptr_t */ +#define PRIxPTR "x" /* uintptr_t */ +#undef PRIXPTR /* uintptr_t */ +#define PRIXPTR "X" /* uintptr_t */ #endif -#endif /* mozilla_IntegerPrintfMacros_h_ */ +/* + * Fix up Android's broken macros for [u]int_fastN_t. On ARM64, Android's + * PRI*FAST16/32 macros are defined as "d", but the types themselves are defined + * as long and unsigned long. + */ +#if defined(ANDROID) && defined(__LP64__) +#undef PRIdFAST16 /* int_fast16_t */ +#define PRIdFAST16 PRId64 /* int_fast16_t */ +#undef PRIiFAST16 /* int_fast16_t */ +#define PRIiFAST16 PRIi64 /* int_fast16_t */ +#undef PRIoFAST16 /* uint_fast16_t */ +#define PRIoFAST16 PRIo64 /* uint_fast16_t */ +#undef PRIuFAST16 /* uint_fast16_t */ +#define PRIuFAST16 PRIu64 /* uint_fast16_t */ +#undef PRIxFAST16 /* uint_fast16_t */ +#define PRIxFAST16 PRIx64 /* uint_fast16_t */ +#undef PRIXFAST16 /* uint_fast16_t */ +#define PRIXFAST16 PRIX64 /* uint_fast16_t */ +#undef PRIdFAST32 /* int_fast32_t */ +#define PRIdFAST32 PRId64 /* int_fast32_t */ +#undef PRIiFAST32 /* int_fast32_t */ +#define PRIiFAST32 PRIi64 /* int_fast32_t */ +#undef PRIoFAST32 /* uint_fast32_t */ +#define PRIoFAST32 PRIo64 /* uint_fast32_t */ +#undef PRIuFAST32 /* uint_fast32_t */ +#define PRIuFAST32 PRIu64 /* uint_fast32_t */ +#undef PRIxFAST32 /* uint_fast32_t */ +#define PRIxFAST32 PRIx64 /* uint_fast32_t */ +#undef PRIXFAST32 /* uint_fast32_t */ +#define PRIXFAST32 PRIX64 /* uint_fast32_t */ +#endif + +#endif /* mozilla_IntegerPrintfMacros_h_ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/IntegerRange.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/IntegerRange.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/IntegerRange.h @@ -17,110 +17,113 @@ namespace detail { -template -class IntegerIterator -{ -public: - template - explicit IntegerIterator(IntType aCurrent) - : mCurrent(aCurrent) { } +template +class IntegerIterator { + public: + template + explicit IntegerIterator(IntType aCurrent) : mCurrent(aCurrent) {} - template + template explicit IntegerIterator(const IntegerIterator& aOther) - : mCurrent(aOther.mCurrent) { } + : mCurrent(aOther.mCurrent) {} IntTypeT operator*() const { return mCurrent; } /* Increment and decrement operators */ - IntegerIterator& operator++() { ++mCurrent; return *this; } - IntegerIterator& operator--() { --mCurrent; return *this; } - IntegerIterator operator++(int) { auto ret = *this; ++mCurrent; return ret; } - IntegerIterator operator--(int) { auto ret = *this; --mCurrent; return ret; } + IntegerIterator& operator++() { + ++mCurrent; + return *this; + } + IntegerIterator& operator--() { + --mCurrent; + return *this; + } + IntegerIterator operator++(int) { + auto ret = *this; + ++mCurrent; + return ret; + } + IntegerIterator operator--(int) { + auto ret = *this; + --mCurrent; + return ret; + } /* Comparison operators */ - template + template friend bool operator==(const IntegerIterator& aIter1, const IntegerIterator& aIter2); - template + template friend bool operator!=(const IntegerIterator& aIter1, const IntegerIterator& aIter2); - template + template friend bool operator<(const IntegerIterator& aIter1, const IntegerIterator& aIter2); - template + template friend bool operator<=(const IntegerIterator& aIter1, const IntegerIterator& aIter2); - template + template friend bool operator>(const IntegerIterator& aIter1, const IntegerIterator& aIter2); - template + template friend bool operator>=(const IntegerIterator& aIter1, const IntegerIterator& aIter2); -private: + private: IntTypeT mCurrent; }; -template +template bool operator==(const IntegerIterator& aIter1, - const IntegerIterator& aIter2) -{ + const IntegerIterator& aIter2) { return aIter1.mCurrent == aIter2.mCurrent; } -template +template bool operator!=(const IntegerIterator& aIter1, - const IntegerIterator& aIter2) -{ + const IntegerIterator& aIter2) { return aIter1.mCurrent != aIter2.mCurrent; } -template +template bool operator<(const IntegerIterator& aIter1, - const IntegerIterator& aIter2) -{ + const IntegerIterator& aIter2) { return aIter1.mCurrent < aIter2.mCurrent; } -template +template bool operator<=(const IntegerIterator& aIter1, - const IntegerIterator& aIter2) -{ + const IntegerIterator& aIter2) { return aIter1.mCurrent <= aIter2.mCurrent; } -template +template bool operator>(const IntegerIterator& aIter1, - const IntegerIterator& aIter2) -{ + const IntegerIterator& aIter2) { return aIter1.mCurrent > aIter2.mCurrent; } -template +template bool operator>=(const IntegerIterator& aIter1, - const IntegerIterator& aIter2) -{ + const IntegerIterator& aIter2) { return aIter1.mCurrent >= aIter2.mCurrent; } -template -class IntegerRange -{ -public: +template +class IntegerRange { + public: typedef IntegerIterator iterator; typedef IntegerIterator const_iterator; typedef ReverseIterator> reverse_iterator; typedef ReverseIterator> const_reverse_iterator; - template - explicit IntegerRange(IntType aEnd) - : mBegin(0), mEnd(aEnd) { } - - template - IntegerRange(IntType1 aBegin, IntType2 aEnd) - : mBegin(aBegin), mEnd(aEnd) { } + template + explicit IntegerRange(IntType aEnd) : mBegin(0), mEnd(aEnd) {} + + template + IntegerRange(IntType1 aBegin, IntType2 aEnd) : mBegin(aBegin), mEnd(aEnd) {} iterator begin() const { return iterator(mBegin); } const_iterator cbegin() const { return begin(); } @@ -131,43 +134,33 @@ reverse_iterator rend() const { return reverse_iterator(mBegin); } const_reverse_iterator crend() const { return rend(); } -private: + private: IntTypeT mBegin; IntTypeT mEnd; }; -template::value> -struct GeqZero -{ - static bool check(T t) { - return t >= 0; - } +template ::value> +struct GeqZero { + static bool check(T t) { return t >= 0; } }; -template -struct GeqZero -{ - static bool check(T t) { - return true; - } +template +struct GeqZero { + static bool check(T t) { return true; } }; -} // namespace detail +} // namespace detail -template -detail::IntegerRange -MakeRange(IntType aEnd) -{ +template +detail::IntegerRange IntegerRange(IntType aEnd) { static_assert(IsIntegral::value, "value must be integral"); MOZ_ASSERT(detail::GeqZero::check(aEnd), "Should never have negative value here"); return detail::IntegerRange(aEnd); } -template -detail::IntegerRange -MakeRange(IntType1 aBegin, IntType2 aEnd) -{ +template +detail::IntegerRange IntegerRange(IntType1 aBegin, IntType2 aEnd) { static_assert(IsIntegral::value && IsIntegral::value, "values must both be integral"); static_assert(IsSigned::value == IsSigned::value, @@ -176,6 +169,6 @@ return detail::IntegerRange(aBegin, aEnd); } -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_IntegerRange_h +#endif // mozilla_IntegerRange_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/IntegerTypeTraits.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/IntegerTypeTraits.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/IntegerTypeTraits.h @@ -21,72 +21,61 @@ * of given size (can be 1, 2, 4 or 8) and given signedness * (false means unsigned, true means signed). */ -template +template struct StdintTypeForSizeAndSignedness; -template<> -struct StdintTypeForSizeAndSignedness<1, true> -{ +template <> +struct StdintTypeForSizeAndSignedness<1, true> { typedef int8_t Type; }; -template<> -struct StdintTypeForSizeAndSignedness<1, false> -{ +template <> +struct StdintTypeForSizeAndSignedness<1, false> { typedef uint8_t Type; }; -template<> -struct StdintTypeForSizeAndSignedness<2, true> -{ +template <> +struct StdintTypeForSizeAndSignedness<2, true> { typedef int16_t Type; }; -template<> -struct StdintTypeForSizeAndSignedness<2, false> -{ +template <> +struct StdintTypeForSizeAndSignedness<2, false> { typedef uint16_t Type; }; -template<> -struct StdintTypeForSizeAndSignedness<4, true> -{ +template <> +struct StdintTypeForSizeAndSignedness<4, true> { typedef int32_t Type; }; -template<> -struct StdintTypeForSizeAndSignedness<4, false> -{ +template <> +struct StdintTypeForSizeAndSignedness<4, false> { typedef uint32_t Type; }; -template<> -struct StdintTypeForSizeAndSignedness<8, true> -{ +template <> +struct StdintTypeForSizeAndSignedness<8, true> { typedef int64_t Type; }; -template<> -struct StdintTypeForSizeAndSignedness<8, false> -{ +template <> +struct StdintTypeForSizeAndSignedness<8, false> { typedef uint64_t Type; }; -} // namespace detail +} // namespace detail -template +template struct UnsignedStdintTypeForSize - : detail::StdintTypeForSizeAndSignedness -{}; + : detail::StdintTypeForSizeAndSignedness {}; -template +template struct SignedStdintTypeForSize - : detail::StdintTypeForSizeAndSignedness -{}; + : detail::StdintTypeForSizeAndSignedness {}; -template -struct PositionOfSignBit -{ +template +struct PositionOfSignBit { static_assert(IsIntegral::value, "PositionOfSignBit is only for integral types"); // 8 here should be CHAR_BIT from limits.h, but the world has moved on. @@ -98,17 +87,16 @@ * compile-time constant, which std::numeric_limits::min() * cannot do in c++98. */ -template -struct MinValue -{ -private: +template +struct MinValue { + private: static_assert(IsIntegral::value, "MinValue is only for integral types"); typedef typename MakeUnsigned::Type UnsignedIntegerType; static const size_t PosOfSignBit = PositionOfSignBit::value; -public: + public: // Bitwise ops may return a larger type, that's why we cast explicitly. // In C++, left bit shifts on signed values is undefined by the standard // unless the shifted value is representable. @@ -117,8 +105,8 @@ // unsigned-to-signed is only well-defined if the value is representable. static const IntegerType value = IsSigned::value - ? IntegerType(UnsignedIntegerType(1) << PosOfSignBit) - : IntegerType(0); + ? IntegerType(UnsignedIntegerType(1) << PosOfSignBit) + : IntegerType(0); }; /** @@ -126,9 +114,8 @@ * compile-time constant, which std::numeric_limits::max() * cannot do in c++98. */ -template -struct MaxValue -{ +template +struct MaxValue { static_assert(IsIntegral::value, "MaxValue is only for integral types"); @@ -138,6 +125,6 @@ static const IntegerType value = ~MinValue::value; }; -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_IntegerTypeTraits_h +#endif // mozilla_IntegerTypeTraits_h 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 @@ -92,7 +92,7 @@ #ifndef mozilla_JSONWriter_h #define mozilla_JSONWriter_h -#include "mozilla/double-conversion.h" +#include "double-conversion/double-conversion.h" #include "mozilla/IntegerPrintfMacros.h" #include "mozilla/PodOperations.h" #include "mozilla/Sprintf.h" @@ -106,9 +106,8 @@ // A quasi-functor for JSONWriter. We don't use a true functor because that // requires templatizing JSONWriter, and the templatization seeps to lots of // places we don't want it to. -class JSONWriteFunc -{ -public: +class JSONWriteFunc { + public: virtual void Write(const char* aStr) = 0; virtual ~JSONWriteFunc() {} }; @@ -117,10 +116,9 @@ // on Linux that caused link errors, whereas this formulation didn't. namespace detail { extern MFBT_DATA const char gTwoCharEscapes[256]; -} // namespace detail +} // namespace detail -class JSONWriter -{ +class JSONWriter { // From http://www.ietf.org/rfc/rfc4627.txt: // // "All Unicode characters may be placed within the quotation marks except @@ -134,8 +132,7 @@ // All control characters not in the above list are represented with a // six-char escape sequence, e.g. '\u000b' (a.k.a. '\v'). // - class EscapedString - { + class EscapedString { // Only one of |mUnownedStr| and |mOwnedStr| are ever non-null. |mIsOwned| // indicates which one is in use. They're not within a union because that // wouldn't work with UniquePtr. @@ -143,30 +140,26 @@ const char* mUnownedStr; UniquePtr mOwnedStr; - void SanityCheck() const - { - MOZ_ASSERT_IF( mIsOwned, mOwnedStr.get() && !mUnownedStr); - MOZ_ASSERT_IF(!mIsOwned, !mOwnedStr.get() && mUnownedStr); + void SanityCheck() const { + MOZ_ASSERT_IF(mIsOwned, mOwnedStr.get() && !mUnownedStr); + MOZ_ASSERT_IF(!mIsOwned, !mOwnedStr.get() && mUnownedStr); } - static char hexDigitToAsciiChar(uint8_t u) - { + static char hexDigitToAsciiChar(uint8_t u) { u = u & 0xf; return u < 10 ? '0' + u : 'a' + (u - 10); } - public: + public: explicit EscapedString(const char* aStr) - : mUnownedStr(nullptr) - , mOwnedStr(nullptr) - { + : mUnownedStr(nullptr), mOwnedStr(nullptr) { const char* p; // First, see if we need to modify the string. size_t nExtra = 0; p = aStr; while (true) { - uint8_t u = *p; // ensure it can't be interpreted as negative + uint8_t u = *p; // ensure it can't be interpreted as negative if (u == 0) { break; } @@ -194,7 +187,7 @@ size_t i = 0; while (true) { - uint8_t u = *p; // ensure it can't be interpreted as negative + uint8_t u = *p; // ensure it can't be interpreted as negative if (u == 0) { mOwnedStr[i] = 0; break; @@ -216,37 +209,32 @@ } } - ~EscapedString() - { - SanityCheck(); - } + ~EscapedString() { SanityCheck(); } - const char* get() const - { + const char* get() const { SanityCheck(); return mIsOwned ? mOwnedStr.get() : mUnownedStr; } }; -public: + public: // Collections (objects and arrays) are printed in a multi-line style by // default. This can be changed to a single-line style if SingleLineStyle is // specified. If a collection is printed in single-line style, every nested // collection within it is also printed in single-line style, even if // multi-line style is requested. enum CollectionStyle { - MultiLineStyle, // the default + MultiLineStyle, // the default SingleLineStyle }; -protected: + protected: const UniquePtr mWriter; Vector mNeedComma; // do we need a comma at depth N? Vector mNeedNewlines; // do we need newlines at depth N? size_t mDepth; // the current nesting depth - void Indent() - { + void Indent() { for (size_t i = 0; i < mDepth; i++) { mWriter->Write(" "); } @@ -255,8 +243,7 @@ // Adds whatever is necessary (maybe a comma, and then a newline and // whitespace) to separate an item (property or element) from what's come // before. - void Separator() - { + void Separator() { if (mNeedComma[mDepth]) { mWriter->Write(","); } @@ -268,16 +255,14 @@ } } - void PropertyNameAndColon(const char* aName) - { + void PropertyNameAndColon(const char* aName) { EscapedString escapedName(aName); mWriter->Write("\""); mWriter->Write(escapedName.get()); mWriter->Write("\": "); } - void Scalar(const char* aMaybePropertyName, const char* aStringValue) - { + void Scalar(const char* aMaybePropertyName, const char* aStringValue) { Separator(); if (aMaybePropertyName) { PropertyNameAndColon(aMaybePropertyName); @@ -286,8 +271,7 @@ mNeedComma[mDepth] = true; } - void QuotedScalar(const char* aMaybePropertyName, const char* aStringValue) - { + void QuotedScalar(const char* aMaybePropertyName, const char* aStringValue) { Separator(); if (aMaybePropertyName) { PropertyNameAndColon(aMaybePropertyName); @@ -298,8 +282,7 @@ mNeedComma[mDepth] = true; } - void NewVectorEntries() - { + void NewVectorEntries() { // If these tiny allocations OOM we might as well just crash because we // must be in serious memory trouble. MOZ_RELEASE_ASSERT(mNeedComma.resizeUninitialized(mDepth + 1)); @@ -309,8 +292,7 @@ } void StartCollection(const char* aMaybePropertyName, const char* aStartChar, - CollectionStyle aStyle = MultiLineStyle) - { + CollectionStyle aStyle = MultiLineStyle) { Separator(); if (aMaybePropertyName) { mWriter->Write("\""); @@ -322,12 +304,11 @@ mDepth++; NewVectorEntries(); mNeedNewlines[mDepth] = - mNeedNewlines[mDepth - 1] && aStyle == MultiLineStyle; + mNeedNewlines[mDepth - 1] && aStyle == MultiLineStyle; } // Adds the whitespace and closing char necessary to end a collection. - void EndCollection(const char* aEndChar) - { + void EndCollection(const char* aEndChar) { if (mNeedNewlines[mDepth]) { mWriter->Write("\n"); mDepth--; @@ -338,13 +319,9 @@ mWriter->Write(aEndChar); } -public: + public: explicit JSONWriter(UniquePtr aWriter) - : mWriter(Move(aWriter)) - , mNeedComma() - , mNeedNewlines() - , mDepth(0) - { + : mWriter(Move(aWriter)), mNeedComma(), mNeedNewlines(), mDepth(0) { NewVectorEntries(); } @@ -359,8 +336,7 @@ // All property names and string properties are escaped as necessary. // Prints: { - void Start(CollectionStyle aStyle = MultiLineStyle) - { + void Start(CollectionStyle aStyle = MultiLineStyle) { StartCollection(nullptr, "{", aStyle); } @@ -368,17 +344,13 @@ void End() { EndCollection("}\n"); } // Prints: "": null - void NullProperty(const char* aName) - { - Scalar(aName, "null"); - } + void NullProperty(const char* aName) { Scalar(aName, "null"); } // Prints: null void NullElement() { NullProperty(nullptr); } // Prints: "": - void BoolProperty(const char* aName, bool aBool) - { + void BoolProperty(const char* aName, bool aBool) { Scalar(aName, aBool ? "true" : "false"); } @@ -386,8 +358,7 @@ void BoolElement(bool aBool) { BoolProperty(nullptr, aBool); } // Prints: "": - void IntProperty(const char* aName, int64_t aInt) - { + void IntProperty(const char* aName, int64_t aInt) { char buf[64]; SprintfLiteral(buf, "%" PRId64, aInt); Scalar(aName, buf); @@ -397,12 +368,11 @@ void IntElement(int64_t aInt) { IntProperty(nullptr, aInt); } // Prints: "": - void DoubleProperty(const char* aName, double aDouble) - { + void DoubleProperty(const char* aName, double aDouble) { static const size_t buflen = 64; char buf[buflen]; - const double_conversion::DoubleToStringConverter &converter = - double_conversion::DoubleToStringConverter::EcmaScriptConverter(); + const double_conversion::DoubleToStringConverter& converter = + double_conversion::DoubleToStringConverter::EcmaScriptConverter(); double_conversion::StringBuilder builder(buf, buflen); converter.ToShortest(aDouble, &builder); Scalar(aName, builder.Finalize()); @@ -412,8 +382,7 @@ void DoubleElement(double aDouble) { DoubleProperty(nullptr, aDouble); } // Prints: "": "" - void StringProperty(const char* aName, const char* aStr) - { + void StringProperty(const char* aName, const char* aStr) { EscapedString escapedStr(aStr); QuotedScalar(aName, escapedStr.get()); } @@ -423,14 +392,12 @@ // Prints: "": [ void StartArrayProperty(const char* aName, - CollectionStyle aStyle = MultiLineStyle) - { + CollectionStyle aStyle = MultiLineStyle) { StartCollection(aName, "[", aStyle); } // Prints: [ - void StartArrayElement(CollectionStyle aStyle = MultiLineStyle) - { + void StartArrayElement(CollectionStyle aStyle = MultiLineStyle) { StartArrayProperty(nullptr, aStyle); } @@ -439,14 +406,12 @@ // Prints: "": { void StartObjectProperty(const char* aName, - CollectionStyle aStyle = MultiLineStyle) - { + CollectionStyle aStyle = MultiLineStyle) { StartCollection(aName, "{", aStyle); } // Prints: { - void StartObjectElement(CollectionStyle aStyle = MultiLineStyle) - { + void StartObjectElement(CollectionStyle aStyle = MultiLineStyle) { StartObjectProperty(nullptr, aStyle); } @@ -454,7 +419,6 @@ void EndObject() { EndCollection("}"); } }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_JSONWriter_h */ - Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Likely.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Likely.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Likely.h @@ -13,11 +13,11 @@ #define mozilla_Likely_h #if defined(__clang__) || defined(__GNUC__) -# define MOZ_LIKELY(x) (__builtin_expect(!!(x), 1)) -# define MOZ_UNLIKELY(x) (__builtin_expect(!!(x), 0)) +#define MOZ_LIKELY(x) (__builtin_expect(!!(x), 1)) +#define MOZ_UNLIKELY(x) (__builtin_expect(!!(x), 0)) #else -# define MOZ_LIKELY(x) (!!(x)) -# define MOZ_UNLIKELY(x) (!!(x)) +#define MOZ_LIKELY(x) (!!(x)) +#define MOZ_UNLIKELY(x) (!!(x)) #endif #endif /* mozilla_Likely_h */ 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 @@ -74,7 +74,7 @@ namespace mozilla { -template +template class LinkedListElement; namespace detail { @@ -84,9 +84,8 @@ * 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 -{ +template +struct LinkedListElementTraits { typedef T* RawType; typedef const T* ConstRawType; typedef T* ClientType; @@ -101,26 +100,28 @@ static void exitList(LinkedListElement* elt) {} }; -template -struct LinkedListElementTraits> -{ +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(); } + static void enterList(LinkedListElement>* elt) { + elt->asT()->AddRef(); + } + static void exitList(LinkedListElement>* elt) { + elt->asT()->Release(); + } }; } /* namespace detail */ -template +template class LinkedList; -template -class LinkedListElement -{ +template +class LinkedListElement { typedef typename detail::LinkedListElementTraits Traits; typedef typename Traits::RawType RawType; typedef typename Traits::ConstRawType ConstRawType; @@ -161,30 +162,24 @@ * lists, and supporting this painlessly was a key design criterion. */ -private: + private: LinkedListElement* mNext; LinkedListElement* mPrev; const bool mIsSentinel; -public: - LinkedListElement() - : mNext(this), - mPrev(this), - mIsSentinel(false) - { } + public: + LinkedListElement() : mNext(this), mPrev(this), mIsSentinel(false) {} /* * 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) - { + : mIsSentinel(aOther.mIsSentinel) { adjustLinkForMove(Move(aOther)); } - LinkedListElement& operator=(LinkedListElement&& aOther) - { + 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!"); @@ -192,8 +187,7 @@ return *this; } - ~LinkedListElement() - { + ~LinkedListElement() { if (!mIsSentinel && isInList()) { remove(); } @@ -203,22 +197,21 @@ * Get the next element in the list, or nullptr if this is the last element * in the list. */ - RawType getNext() { 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. */ - RawType getPrevious() { 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(RawType aElem) - { + void setNext(RawType aElem) { MOZ_ASSERT(isInList()); setNextUnsafe(aElem); } @@ -228,8 +221,7 @@ * linked list when you call setPrevious(); otherwise, this method will * assert. */ - void setPrevious(RawType aElem) - { + void setPrevious(RawType aElem) { MOZ_ASSERT(isInList()); setPreviousUnsafe(aElem); } @@ -238,8 +230,7 @@ * Remove this element from the list which contains it. If this element is * not currently part of a linked list, this method asserts. */ - void remove() - { + void remove() { MOZ_ASSERT(isInList()); mPrev->mNext = mNext; @@ -253,11 +244,11 @@ /* * 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. + * asserts if the element does not belong to a list. Note: In a refcounted + * list, |this| may be destroyed. */ - ClientType removeAndGetNext() - { - ClientType r = getNext(); + RawType removeAndGetNext() { + RawType r = getNext(); remove(); return r; } @@ -265,11 +256,11 @@ /* * 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. + * asserts if the element does not belong to a list. Note: In a refcounted + * list, |this| may be destroyed. */ - ClientType removeAndGetPrevious() - { - ClientType r = getPrevious(); + RawType removeAndGetPrevious() { + RawType r = getPrevious(); remove(); return r; } @@ -278,8 +269,7 @@ * Identical to remove(), but also asserts in debug builds that this element * is in aList. */ - void removeFrom(const LinkedList& aList) - { + void removeFrom(const LinkedList& aList) { aList.assertContains(asT()); remove(); } @@ -287,37 +277,26 @@ /* * Return true if |this| part is of a linked list, and false otherwise. */ - bool isInList() const - { + bool isInList() const { MOZ_ASSERT((mNext == this) == (mPrev == this)); return mNext != this; } -private: + private: friend class LinkedList; friend struct detail::LinkedListElementTraits; - enum class NodeKind { - Normal, - Sentinel - }; + enum class NodeKind { Normal, Sentinel }; explicit LinkedListElement(NodeKind nodeKind) - : mNext(this), - mPrev(this), - mIsSentinel(nodeKind == NodeKind::Sentinel) - { } + : mNext(this), mPrev(this), mIsSentinel(nodeKind == NodeKind::Sentinel) {} /* * Return |this| cast to T* if we're a normal node, or return nullptr if * we're a sentinel node. */ - RawType asT() - { - return mIsSentinel ? nullptr : static_cast(this); - } - ConstRawType asT() const - { + RawType asT() { return mIsSentinel ? nullptr : static_cast(this); } + ConstRawType asT() const { return mIsSentinel ? nullptr : static_cast(this); } @@ -325,9 +304,8 @@ * Insert aElem after this element, but don't check that this element is in * the list. This is called by LinkedList::insertFront(). */ - void setNextUnsafe(RawType aElem) - { - LinkedListElement *listElem = static_cast(aElem); + void setNextUnsafe(RawType aElem) { + LinkedListElement* listElem = static_cast(aElem); MOZ_ASSERT(!listElem->isInList()); listElem->mNext = this->mNext; @@ -342,8 +320,7 @@ * Insert aElem before this element, but don't check that this element is in * the list. This is called by LinkedList::insertBack(). */ - void setPreviousUnsafe(RawType aElem) - { + void setPreviousUnsafe(RawType aElem) { LinkedListElement* listElem = static_cast*>(aElem); MOZ_ASSERT(!listElem->isInList()); @@ -359,8 +336,7 @@ * Adjust mNext and mPrev for implementing move constructor and move * assignment. */ - void adjustLinkForMove(LinkedListElement&& aOther) - { + void adjustLinkForMove(LinkedListElement&& aOther) { if (!aOther.isInList()) { mNext = this; mPrev = this; @@ -400,10 +376,9 @@ LinkedListElement(const LinkedListElement& aOther) = delete; }; -template -class LinkedList -{ -private: +template +class LinkedList { + private: typedef typename detail::LinkedListElementTraits Traits; typedef typename Traits::RawType RawType; typedef typename Traits::ConstRawType ConstRawType; @@ -412,16 +387,14 @@ LinkedListElement sentinel; -public: + public: class Iterator { RawType mCurrent; - public: + public: explicit Iterator(RawType aCurrent) : mCurrent(aCurrent) {} - RawType operator *() const { - return mCurrent; - } + RawType operator*() const { return mCurrent; } const Iterator& operator++() { mCurrent = mCurrent->getNext(); @@ -433,15 +406,14 @@ } }; - LinkedList() : sentinel(LinkedListElement::NodeKind::Sentinel) { } + LinkedList() : sentinel(LinkedListElement::NodeKind::Sentinel) {} LinkedList(LinkedList&& aOther) - : sentinel(mozilla::Move(aOther.sentinel)) - { } + : sentinel(mozilla::Move(aOther.sentinel)) {} - LinkedList& operator=(LinkedList&& aOther) - { - MOZ_ASSERT(isEmpty(), "Assigning to a non-empty list leaks elements in that list!"); + 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; } @@ -456,8 +428,7 @@ /* * Add aElem to the front of the list. */ - void insertFront(RawType aElem) - { + void insertFront(RawType aElem) { /* Bypass setNext()'s this->isInList() assertion. */ sentinel.setNextUnsafe(aElem); } @@ -465,29 +436,25 @@ /* * Add aElem to the back of the list. */ - void insertBack(RawType aElem) - { - sentinel.setPreviousUnsafe(aElem); - } + void insertBack(RawType aElem) { sentinel.setPreviousUnsafe(aElem); } /* * Get the first element of the list, or nullptr if the list is empty. */ - RawType getFirst() { 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. */ - RawType getLast() { 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. */ - ClientType popFirst() - { + ClientType popFirst() { ClientType ret = sentinel.getNext(); if (ret) { static_cast*>(RawType(ret))->remove(); @@ -499,8 +466,7 @@ * Get and remove the last element of the list. If the list is empty, * return nullptr. */ - ClientType popLast() - { + ClientType popLast() { ClientType ret = sentinel.getPrevious(); if (ret) { static_cast*>(RawType(ret))->remove(); @@ -511,10 +477,7 @@ /* * Return true if the list is empty, or false otherwise. */ - bool isEmpty() const - { - return !sentinel.isInList(); - } + bool isEmpty() const { return !sentinel.isInList(); } /* * Remove all the elements from the list. @@ -522,10 +485,8 @@ * This runs in time linear to the list's length, because we have to mark * each element as not in the list. */ - void clear() - { + void clear() { while (popFirst()) { - continue; } } @@ -534,12 +495,8 @@ * * for (MyElementType* elt : myList) { ... } */ - Iterator begin() { - return Iterator(getFirst()); - } - Iterator end() { - return Iterator(nullptr); - } + Iterator begin() { return Iterator(getFirst()); } + Iterator end() { return Iterator(nullptr); } /* * Measures the memory consumption of the list excluding |this|. Note that @@ -547,10 +504,9 @@ * contain pointers to other memory blocks, those blocks must be measured * separately during a subsequent iteration over the list. */ - size_t sizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const - { + size_t sizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { size_t n = 0; - for (const T* t = getFirst(); t; t = t->getNext()) { + for (ConstRawType t = getFirst(); t; t = t->getNext()) { n += aMallocSizeOf(t); } return n; @@ -559,8 +515,7 @@ /* * Like sizeOfExcludingThis(), but measures |this| as well. */ - size_t sizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const - { + size_t sizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { return aMallocSizeOf(this) + sizeOfExcludingThis(aMallocSizeOf); } @@ -568,8 +523,7 @@ * In a debug build, make sure that the list is sane (no cycles, consistent * mNext/mPrev pointers, only one sentinel). Has no effect in release builds. */ - void debugAssertIsSane() const - { + void debugAssertIsSane() const { #ifdef DEBUG const LinkedListElement* slow; const LinkedListElement* fast1; @@ -579,9 +533,8 @@ * Check for cycles in the forward singly-linked list using the * tortoise/hare algorithm. */ - for (slow = sentinel.mNext, - fast1 = sentinel.mNext->mNext, - fast2 = sentinel.mNext->mNext->mNext; + for (slow = sentinel.mNext, fast1 = sentinel.mNext->mNext, + fast2 = sentinel.mNext->mNext->mNext; slow != &sentinel && fast1 != &sentinel && fast2 != &sentinel; slow = slow->mNext, fast1 = fast2->mNext, fast2 = fast1->mNext) { MOZ_ASSERT(slow != fast1); @@ -589,9 +542,8 @@ } /* Check for cycles in the backward singly-linked list. */ - for (slow = sentinel.mPrev, - fast1 = sentinel.mPrev->mPrev, - fast2 = sentinel.mPrev->mPrev->mPrev; + for (slow = sentinel.mPrev, fast1 = sentinel.mPrev->mPrev, + fast2 = sentinel.mPrev->mPrev->mPrev; slow != &sentinel && fast1 != &sentinel && fast2 != &sentinel; slow = slow->mPrev, fast1 = fast2->mPrev, fast2 = fast1->mPrev) { MOZ_ASSERT(slow != fast1); @@ -602,8 +554,7 @@ * Check that |sentinel| is the only node in the list with * mIsSentinel == true. */ - for (const LinkedListElement* elem = sentinel.mNext; - elem != &sentinel; + for (const LinkedListElement* elem = sentinel.mNext; elem != &sentinel; elem = elem->mNext) { MOZ_ASSERT(!elem->mIsSentinel); } @@ -612,20 +563,19 @@ const LinkedListElement* prev = &sentinel; const LinkedListElement* cur = sentinel.mNext; do { - MOZ_ASSERT(cur->mPrev == prev); - MOZ_ASSERT(prev->mNext == cur); + MOZ_ASSERT(cur->mPrev == prev); + MOZ_ASSERT(prev->mNext == cur); - prev = cur; - cur = cur->mNext; + prev = cur; + cur = cur->mNext; } while (cur != &sentinel); #endif /* ifdef DEBUG */ } -private: + private: friend class LinkedListElement; - void assertContains(const RawType aValue) const - { + void assertContains(const RawType aValue) const { #ifdef DEBUG for (ConstRawType elem = getFirst(); elem; elem = elem->getNext()) { if (elem == aValue) { @@ -641,11 +591,16 @@ }; template -class AutoCleanLinkedList : public LinkedList -{ -public: - ~AutoCleanLinkedList() - { +class AutoCleanLinkedList : public LinkedList { + public: + ~AutoCleanLinkedList() { clear(); } + + AutoCleanLinkedList& operator=(AutoCleanLinkedList&& aOther) { + LinkedList::operator=(Forward>(aOther)); + return *this; + } + + void clear() { while (T* element = this->popFirst()) { delete element; } 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 @@ -12,84 +12,65 @@ #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_CONCAT2(x, y) x##y #define MOZ_CONCAT(x, y) MOZ_CONCAT2(x, y) /* + * MOZ_ARG_COUNT(...) counts the number of variadic arguments. + * You must pass in between 0 and 50 (inclusive) variadic arguments. + * For example: + * + * MOZ_ARG_COUNT() expands to 0 + * MOZ_ARG_COUNT(a) expands to 1 + * MOZ_ARG_COUNT(a, b) expands to 2 + * + * Implementation notes: + * The `##__VA_ARGS__` form is a GCC extension that removes the comma if + * __VA_ARGS__ is empty. It is supported by Clang too. MSVC ignores ##, + * and its default behavior is already to strip the comma when __VA_ARGS__ + * is empty. + * + * So MOZ_MACROARGS_ARG_COUNT_HELPER() expands to + * (_, 50, 49, ...) + * MOZ_MACROARGS_ARG_COUNT_HELPER(a) expands to + * (_, a, 50, 49, ...) + * etc. + */ +#define MOZ_ARG_COUNT(...) \ + MOZ_MACROARGS_ARG_COUNT_HELPER2(MOZ_MACROARGS_ARG_COUNT_HELPER(__VA_ARGS__)) + +#define MOZ_MACROARGS_ARG_COUNT_HELPER(...) \ + (_, ##__VA_ARGS__, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, \ + 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, \ + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + +#define MOZ_MACROARGS_ARG_COUNT_HELPER2(aArgs) \ + MOZ_MACROARGS_ARG_COUNT_HELPER3 aArgs + +#define MOZ_MACROARGS_ARG_COUNT_HELPER3( \ + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, \ + a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, \ + a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, \ + a47, a48, a49, a50, a51, ...) \ + a51 + +/* * MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) counts the number of variadic * arguments and prefixes it with |aPrefix|. For example: * * MOZ_PASTE_PREFIX_AND_ARG_COUNT(, foo, 42) expands to 2 * MOZ_PASTE_PREFIX_AND_ARG_COUNT(A, foo, 42, bar) expands to A3 + * MOZ_PASTE_PREFIX_AND_ARG_COUNT(A) expands to A0 + * MOZ_PASTE_PREFIX_AND_ARG_COUNT() expands to 0, but MSVC warns there + * aren't enough arguments given. * - * You must pass in between 1 and 50 (inclusive) variadic arguments, past - * |aPrefix|. It is not legal to do - * - * MOZ_PASTE_PREFIX_AND_ARG_COUNT(prefix) - * - * (that is, pass in 0 variadic arguments). To ensure that a compile-time - * error occurs when these constraints are violated, use the - * MOZ_STATIC_ASSERT_VALID_ARG_COUNT macro with the same variaidc arguments - * wherever this macro is used. - * - * Passing (__VA_ARGS__, ) rather than simply calling - * MOZ_MACROARGS_ARG_COUNT_HELPER2(__VA_ARGS__, ) very - * carefully tiptoes around a MSVC bug where it improperly expands __VA_ARGS__ - * as a single token in argument lists. For details, see: - * - * http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement - * http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644 + * You must pass in between 0 and 50 (inclusive) variadic arguments, past + * |aPrefix|. */ +#define MOZ_PASTE_PREFIX_AND_ARG_COUNT_GLUE(a, b) a b #define MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) \ - MOZ_MACROARGS_ARG_COUNT_HELPER((__VA_ARGS__, \ - aPrefix##50, aPrefix##49, aPrefix##48, aPrefix##47, aPrefix##46, \ - aPrefix##45, aPrefix##44, aPrefix##43, aPrefix##42, aPrefix##41, \ - aPrefix##40, aPrefix##39, aPrefix##38, aPrefix##37, aPrefix##36, \ - aPrefix##35, aPrefix##34, aPrefix##33, aPrefix##32, aPrefix##31, \ - aPrefix##30, aPrefix##29, aPrefix##28, aPrefix##27, aPrefix##26, \ - aPrefix##25, aPrefix##24, aPrefix##23, aPrefix##22, aPrefix##21, \ - aPrefix##20, aPrefix##19, aPrefix##18, aPrefix##17, aPrefix##16, \ - aPrefix##15, aPrefix##14, aPrefix##13, aPrefix##12, aPrefix##11, \ - aPrefix##10, aPrefix##9, aPrefix##8, aPrefix##7, aPrefix##6, \ - aPrefix##5, aPrefix##4, aPrefix##3, aPrefix##2, aPrefix##1, aPrefix##0)) - -#define MOZ_MACROARGS_ARG_COUNT_HELPER(aArgs) \ - MOZ_MACROARGS_ARG_COUNT_HELPER2 aArgs - -#define MOZ_MACROARGS_ARG_COUNT_HELPER2( \ - a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \ - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, \ - a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, \ - a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, \ - a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, \ - a51, ...) a51 - -/* - * MOZ_STATIC_ASSERT_VALID_ARG_COUNT ensures that a compile-time error occurs - * when the argument count constraints of MOZ_PASTE_PREFIX_AND_ARG_COUNT are - * violated. Use this macro wherever MOZ_PASTE_PREFIX_AND_ARG_COUNT is used - * and pass it the same variadic arguments. - * - * This macro employs a few dirty tricks to function. To detect the zero - * argument case, |(__VA_ARGS__)| is stringified, sizeof-ed, and compared to - * what it should be in the absence of arguments. - * - * Detecting too many arguments is a little trickier. With a valid argument - * count and a prefix of 1, MOZ_PASTE_PREFIX_AND_ARG_COUNT expands to e.g. 14. - * With a prefix of 0.0, it expands to e.g. 0.04. If there are too many - * arguments, it expands to the first argument over the limit. If this - * exceeding argument is a number, the assertion will fail as there is no - * number than can simultaneously be both > 10 and == 0. If the exceeding - * argument is not a number, a compile-time error should still occur due to - * the operations performed on it. - */ -#define MOZ_MACROARGS_STRINGIFY_HELPER(x) #x -#define MOZ_STATIC_ASSERT_VALID_ARG_COUNT(...) \ - static_assert( \ - sizeof(MOZ_MACROARGS_STRINGIFY_HELPER((__VA_ARGS__))) != sizeof("()") && \ - (MOZ_PASTE_PREFIX_AND_ARG_COUNT(1, __VA_ARGS__)) > 10 && \ - (int)(MOZ_PASTE_PREFIX_AND_ARG_COUNT(0.0, __VA_ARGS__)) == 0, \ - "MOZ_STATIC_ASSERT_VALID_ARG_COUNT requires 1 to 50 arguments") /* ; */ + MOZ_PASTE_PREFIX_AND_ARG_COUNT_GLUE(MOZ_CONCAT, \ + (aPrefix, MOZ_ARG_COUNT(__VA_ARGS__))) /* * MOZ_ARGS_AFTER_N expands to its arguments excluding the first |N| Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/MacroForEach.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/MacroForEach.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/MacroForEach.h @@ -34,125 +34,186 @@ * int c = MOZ_FOR_EACH(MACRO_C, (5, 8,), (1, 2)) 0; * // Expands to: MACRO_B(5, 8, 1) MACRO_B(5, 8, 2) 0; * + * MOZ_FOR_EACH_SEPARATED(aMacro, aSeparator, aFixedArgs, aArgs) is identical + * to MOZ_FOR_EACH except that it inserts |aSeparator| between each call to + * the macro. |aSeparator| must be wrapped by parens. For example: + * + * #define MACRO_A(x) x + * int a = MOZ_FOR_EACH_SEPARATED(MACRO_A, (+), (), (1, 2, 3)); + * // Expands to: MACRO_A(1) + MACRO_A(2) + MACRO_A(3); + * // And further to: 1 + 2 + 3 + * + * #define MACRO_B(t, n) t n + * void test(MOZ_FOR_EACH_SEPARATED(MACRO_B, (,), (int,), (a, b))); + * // Expands to: void test(MACRO_B(int, a) , MACRO_B(int, b)); + * // And further to: void test(int a , int b); + * * If the |aFixedArgs| list is not empty, a trailing comma must be included. * - * The |aArgs| list must be not be empty and may be up to 50 items long. Use - * MOZ_STATIC_ASSERT_VALID_ARG_COUNT to ensure that violating this constraint - * results in a compile-time error. + * The |aArgs| list may be up to 50 items long. */ #define MOZ_FOR_EACH_EXPAND_HELPER(...) __VA_ARGS__ #define MOZ_FOR_EACH_GLUE(a, b) a b +#define MOZ_FOR_EACH_SEPARATED(aMacro, aSeparator, aFixedArgs, aArgs) \ + MOZ_FOR_EACH_GLUE(MOZ_PASTE_PREFIX_AND_ARG_COUNT( \ + MOZ_FOR_EACH_, MOZ_FOR_EACH_EXPAND_HELPER aArgs), \ + (aMacro, aSeparator, aFixedArgs, aArgs)) #define MOZ_FOR_EACH(aMacro, aFixedArgs, aArgs) \ - MOZ_FOR_EACH_GLUE( \ - MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_FOR_EACH_, \ - MOZ_FOR_EACH_EXPAND_HELPER aArgs), \ - (aMacro, aFixedArgs, aArgs)) + MOZ_FOR_EACH_SEPARATED(aMacro, (), aFixedArgs, aArgs) #define MOZ_FOR_EACH_HELPER_GLUE(a, b) a b #define MOZ_FOR_EACH_HELPER(aMacro, aFixedArgs, aArgs) \ - MOZ_FOR_EACH_HELPER_GLUE( \ - aMacro, \ - (MOZ_FOR_EACH_EXPAND_HELPER aFixedArgs MOZ_ARG_1 aArgs)) - -#define MOZ_FOR_EACH_1(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) -#define MOZ_FOR_EACH_2(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_1(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_3(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_2(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_4(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_3(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_5(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_4(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_6(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_5(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_7(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_6(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_8(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_7(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_9(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_8(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_10(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_9(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_11(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_10(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_12(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_11(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_13(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_12(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_14(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_13(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_15(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_14(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_16(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_15(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_17(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_16(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_18(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_17(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_19(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_18(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_20(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_19(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_21(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_20(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_22(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_21(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_23(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_22(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_24(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_23(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_25(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_24(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_26(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_25(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_27(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_26(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_28(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_27(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_29(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_28(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_30(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_29(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_31(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_30(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_32(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_31(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_33(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_32(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_34(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_33(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_35(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_34(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_36(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_35(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_37(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_36(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_38(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_37(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_39(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_38(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_40(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_39(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_41(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_40(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_42(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_41(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_43(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_42(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_44(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_43(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_45(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_44(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_46(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_45(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_47(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_46(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_48(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_47(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_49(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_48(m, fa, (MOZ_ARGS_AFTER_1 a)) -#define MOZ_FOR_EACH_50(m, fa, a) \ - MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_49(m, fa, (MOZ_ARGS_AFTER_1 a)) + MOZ_FOR_EACH_HELPER_GLUE( \ + aMacro, (MOZ_FOR_EACH_EXPAND_HELPER aFixedArgs MOZ_ARG_1 aArgs)) + +#define MOZ_FOR_EACH_0(m, s, fa, a) +#define MOZ_FOR_EACH_1(m, s, fa, a) MOZ_FOR_EACH_HELPER(m, fa, a) +#define MOZ_FOR_EACH_2(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_1(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_3(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_2(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_4(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_3(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_5(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_4(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_6(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_5(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_7(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_6(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_8(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_7(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_9(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_8(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_10(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_9(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_11(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_10(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_12(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_11(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_13(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_12(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_14(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_13(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_15(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_14(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_16(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_15(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_17(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_16(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_18(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_17(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_19(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_18(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_20(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_19(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_21(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_20(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_22(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_21(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_23(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_22(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_24(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_23(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_25(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_24(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_26(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_25(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_27(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_26(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_28(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_27(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_29(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_28(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_30(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_29(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_31(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_30(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_32(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_31(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_33(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_32(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_34(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_33(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_35(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_34(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_36(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_35(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_37(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_36(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_38(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_37(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_39(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_38(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_40(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_39(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_41(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_40(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_42(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_41(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_43(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_42(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_44(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_43(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_45(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_44(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_46(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_45(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_47(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_46(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_48(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_47(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_49(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_48(m, s, fa, (MOZ_ARGS_AFTER_1 a)) +#define MOZ_FOR_EACH_50(m, s, fa, a) \ + MOZ_FOR_EACH_HELPER(m, fa, a) \ + MOZ_FOR_EACH_EXPAND_HELPER s MOZ_FOR_EACH_49(m, s, fa, (MOZ_ARGS_AFTER_1 a)) #endif /* mozilla_MacroForEach_h */ 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 @@ -19,10 +19,8 @@ namespace mozilla { // Greatest Common Divisor -template -MOZ_ALWAYS_INLINE IntegerType -EuclidGCD(IntegerType aA, IntegerType aB) -{ +template +MOZ_ALWAYS_INLINE IntegerType EuclidGCD(IntegerType aA, IntegerType aB) { // Euclid's algorithm; O(N) in the worst case. (There are better // ways, but we don't need them for the current use of this algo.) MOZ_ASSERT(aA > IntegerType(0)); @@ -40,36 +38,37 @@ } // Least Common Multiple -template -MOZ_ALWAYS_INLINE IntegerType -EuclidLCM(IntegerType aA, IntegerType aB) -{ +template +MOZ_ALWAYS_INLINE IntegerType EuclidLCM(IntegerType aA, IntegerType aB) { // Divide first to reduce overflow risk. return (aA / EuclidGCD(aA, aB)) * aB; } namespace detail { -template +template struct AllowDeprecatedAbsFixed : FalseType {}; -template<> struct AllowDeprecatedAbsFixed : TrueType {}; -template<> struct AllowDeprecatedAbsFixed : TrueType {}; +template <> +struct AllowDeprecatedAbsFixed : TrueType {}; +template <> +struct AllowDeprecatedAbsFixed : TrueType {}; -template +template struct AllowDeprecatedAbs : AllowDeprecatedAbsFixed {}; -template<> struct AllowDeprecatedAbs : TrueType {}; -template<> struct AllowDeprecatedAbs : TrueType {}; +template <> +struct AllowDeprecatedAbs : TrueType {}; +template <> +struct AllowDeprecatedAbs : TrueType {}; -} // namespace detail +} // namespace detail // DO NOT USE DeprecatedAbs. It exists only until its callers can be converted // to Abs below, and it will be removed when all callers have been changed. -template +template inline typename mozilla::EnableIf::value, T>::Type -DeprecatedAbs(const T aValue) -{ +DeprecatedAbs(const T aValue) { // The absolute value of the smallest possible value of a signed-integer type // won't fit in that type (on twos-complement systems -- and we're blithely // assuming we're on such systems, for the non- types listed above), @@ -80,7 +79,7 @@ // range [0, maxvalue]), doesn't produce maxvalue (because in twos-complement, // (minvalue + 1) == -maxvalue). MOZ_ASSERT(aValue >= 0 || - -(aValue + 1) != T((1ULL << (CHAR_BIT * sizeof(T) - 1)) - 1), + -(aValue + 1) != T((1ULL << (CHAR_BIT * sizeof(T) - 1)) - 1), "You can't negate the smallest possible negative integer!"); return aValue >= 0 ? aValue : -aValue; } @@ -91,72 +90,100 @@ // float/double/long double. Feel free to add overloads for other standard, // signed types if you need them. -template +template struct AbsReturnTypeFixed; -template<> struct AbsReturnTypeFixed { typedef uint8_t Type; }; -template<> struct AbsReturnTypeFixed { typedef uint16_t Type; }; -template<> struct AbsReturnTypeFixed { typedef uint32_t Type; }; -template<> struct AbsReturnTypeFixed { typedef uint64_t Type; }; +template <> +struct AbsReturnTypeFixed { + typedef uint8_t Type; +}; +template <> +struct AbsReturnTypeFixed { + typedef uint16_t Type; +}; +template <> +struct AbsReturnTypeFixed { + typedef uint32_t Type; +}; +template <> +struct AbsReturnTypeFixed { + typedef uint64_t Type; +}; -template +template struct AbsReturnType : AbsReturnTypeFixed {}; -template<> struct AbsReturnType : - EnableIf {}; -template<> struct AbsReturnType { typedef unsigned char Type; }; -template<> struct AbsReturnType { typedef unsigned short Type; }; -template<> struct AbsReturnType { typedef unsigned int Type; }; -template<> struct AbsReturnType { typedef unsigned long Type; }; -template<> struct AbsReturnType { typedef unsigned long long Type; }; -template<> struct AbsReturnType { typedef float Type; }; -template<> struct AbsReturnType { typedef double Type; }; -template<> struct AbsReturnType { typedef long double Type; }; - -} // namespace detail - -template -inline typename detail::AbsReturnType::Type -Abs(const T aValue) -{ - typedef typename detail::AbsReturnType::Type ReturnType; +template <> +struct AbsReturnType : EnableIf {}; +template <> +struct AbsReturnType { + typedef unsigned char Type; +}; +template <> +struct AbsReturnType { + typedef unsigned short Type; +}; +template <> +struct AbsReturnType { + typedef unsigned int Type; +}; +template <> +struct AbsReturnType { + typedef unsigned long Type; +}; +template <> +struct AbsReturnType { + typedef unsigned long long Type; +}; +template <> +struct AbsReturnType { + typedef float Type; +}; +template <> +struct AbsReturnType { + typedef double Type; +}; +template <> +struct AbsReturnType { + typedef long double Type; +}; + +} // namespace detail + +template +inline constexpr typename detail::AbsReturnType::Type Abs(const T aValue) { + using ReturnType = typename detail::AbsReturnType::Type; return aValue >= 0 ? ReturnType(aValue) : ~ReturnType(aValue) + 1; } -template<> -inline float -Abs(const float aFloat) -{ +template <> +inline float Abs(const float aFloat) { return std::fabs(aFloat); } -template<> -inline double -Abs(const double aDouble) -{ +template <> +inline double Abs(const double aDouble) { return std::fabs(aDouble); } -template<> -inline long double -Abs(const long double aLongDouble) -{ +template <> +inline long double Abs(const long double aLongDouble) { return std::fabs(aLongDouble); } -} // namespace mozilla +} // namespace mozilla #if defined(_MSC_VER) && \ (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64)) -# define MOZ_BITSCAN_WINDOWS +#define MOZ_BITSCAN_WINDOWS -# include -# pragma intrinsic(_BitScanForward, _BitScanReverse) +#include +#pragma intrinsic(_BitScanForward, _BitScanReverse) -# if defined(_M_AMD64) || defined(_M_X64) -# define MOZ_BITSCAN_WINDOWS64 -# pragma intrinsic(_BitScanForward64, _BitScanReverse64) -# endif +#if defined(_M_AMD64) || defined(_M_X64) +#define MOZ_BITSCAN_WINDOWS64 +#pragma intrinsic(_BitScanForward64, _BitScanReverse64) +#endif #endif @@ -166,46 +193,33 @@ #if defined(MOZ_BITSCAN_WINDOWS) -inline uint_fast8_t -CountLeadingZeroes32(uint32_t aValue) -{ +inline uint_fast8_t CountLeadingZeroes32(uint32_t aValue) { unsigned long index; - if (!_BitScanReverse(&index, static_cast(aValue))) - return 32; + if (!_BitScanReverse(&index, static_cast(aValue))) return 32; return uint_fast8_t(31 - index); } - -inline uint_fast8_t -CountTrailingZeroes32(uint32_t aValue) -{ +inline uint_fast8_t CountTrailingZeroes32(uint32_t aValue) { unsigned long index; - if (!_BitScanForward(&index, static_cast(aValue))) - return 32; + if (!_BitScanForward(&index, static_cast(aValue))) return 32; return uint_fast8_t(index); } -inline uint_fast8_t -CountPopulation32(uint32_t aValue) -{ +inline uint_fast8_t CountPopulation32(uint32_t aValue) { uint32_t x = aValue - ((aValue >> 1) & 0x55555555); x = (x & 0x33333333) + ((x >> 2) & 0x33333333); return (((x + (x >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; } -inline uint_fast8_t -CountPopulation64(uint64_t aValue) -{ +inline uint_fast8_t CountPopulation64(uint64_t aValue) { return uint_fast8_t(CountPopulation32(aValue & 0xffffffff) + CountPopulation32(aValue >> 32)); } -inline uint_fast8_t -CountLeadingZeroes64(uint64_t aValue) -{ +inline uint_fast8_t CountLeadingZeroes64(uint64_t aValue) { #if defined(MOZ_BITSCAN_WINDOWS64) unsigned long index; if (!_BitScanReverse64(&index, static_cast(aValue))) - return 64; + return 64; return uint_fast8_t(63 - index); #else uint32_t hi = uint32_t(aValue >> 32); @@ -216,13 +230,11 @@ #endif } -inline uint_fast8_t -CountTrailingZeroes64(uint64_t aValue) -{ +inline uint_fast8_t CountTrailingZeroes64(uint64_t aValue) { #if defined(MOZ_BITSCAN_WINDOWS64) unsigned long index; if (!_BitScanForward64(&index, static_cast(aValue))) - return 64; + return 64; return uint_fast8_t(index); #else uint32_t lo = uint32_t(aValue); @@ -233,58 +245,46 @@ #endif } -# ifdef MOZ_HAVE_BITSCAN64 -# undef MOZ_HAVE_BITSCAN64 -# endif +#ifdef MOZ_HAVE_BITSCAN64 +#undef MOZ_HAVE_BITSCAN64 +#endif #elif defined(__clang__) || defined(__GNUC__) -# if defined(__clang__) -# if !__has_builtin(__builtin_ctz) || !__has_builtin(__builtin_clz) -# error "A clang providing __builtin_c[lt]z is required to build" -# endif -# else - // gcc has had __builtin_clz and friends since 3.4: no need to check. -# endif - -inline uint_fast8_t -CountLeadingZeroes32(uint32_t aValue) -{ +#if defined(__clang__) +#if !__has_builtin(__builtin_ctz) || !__has_builtin(__builtin_clz) +#error "A clang providing __builtin_c[lt]z is required to build" +#endif +#else +// gcc has had __builtin_clz and friends since 3.4: no need to check. +#endif + +inline uint_fast8_t CountLeadingZeroes32(uint32_t aValue) { return __builtin_clz(aValue); } -inline uint_fast8_t -CountTrailingZeroes32(uint32_t aValue) -{ +inline uint_fast8_t CountTrailingZeroes32(uint32_t aValue) { return __builtin_ctz(aValue); } -inline uint_fast8_t -CountPopulation32(uint32_t aValue) -{ +inline uint_fast8_t CountPopulation32(uint32_t aValue) { return __builtin_popcount(aValue); } -inline uint_fast8_t -CountPopulation64(uint64_t aValue) -{ +inline uint_fast8_t CountPopulation64(uint64_t aValue) { return __builtin_popcountll(aValue); } -inline uint_fast8_t -CountLeadingZeroes64(uint64_t aValue) -{ +inline uint_fast8_t CountLeadingZeroes64(uint64_t aValue) { return __builtin_clzll(aValue); } -inline uint_fast8_t -CountTrailingZeroes64(uint64_t aValue) -{ +inline uint_fast8_t CountTrailingZeroes64(uint64_t aValue) { return __builtin_ctzll(aValue); } #else -# error "Implement these!" +#error "Implement these!" inline uint_fast8_t CountLeadingZeroes32(uint32_t aValue) = delete; inline uint_fast8_t CountTrailingZeroes32(uint32_t aValue) = delete; inline uint_fast8_t CountPopulation32(uint32_t aValue) = delete; @@ -293,7 +293,7 @@ inline uint_fast8_t CountTrailingZeroes64(uint64_t aValue) = delete; #endif -} // namespace detail +} // namespace detail /** * Compute the number of high-order zero bits in the NON-ZERO number |aValue|. @@ -306,9 +306,7 @@ * CountLeadingZeroes32(0x3FFF0100) is 2; * CountLeadingZeroes32(0x1FF50010) is 3; and so on. */ -inline uint_fast8_t -CountLeadingZeroes32(uint32_t aValue) -{ +inline uint_fast8_t CountLeadingZeroes32(uint32_t aValue) { MOZ_ASSERT(aValue != 0); return detail::CountLeadingZeroes32(aValue); } @@ -324,9 +322,7 @@ * CountTrailingZeroes32(0x0080FFFC) is 2; * CountTrailingZeroes32(0x0080FFF8) is 3; and so on. */ -inline uint_fast8_t -CountTrailingZeroes32(uint32_t aValue) -{ +inline uint_fast8_t CountTrailingZeroes32(uint32_t aValue) { MOZ_ASSERT(aValue != 0); return detail::CountTrailingZeroes32(aValue); } @@ -334,63 +330,51 @@ /** * Compute the number of one bits in the number |aValue|, */ -inline uint_fast8_t -CountPopulation32(uint32_t aValue) -{ +inline uint_fast8_t CountPopulation32(uint32_t aValue) { return detail::CountPopulation32(aValue); } /** Analogous to CountPopulation32, but for 64-bit numbers */ -inline uint_fast8_t -CountPopulation64(uint64_t aValue) -{ +inline uint_fast8_t CountPopulation64(uint64_t aValue) { return detail::CountPopulation64(aValue); } /** Analogous to CountLeadingZeroes32, but for 64-bit numbers. */ -inline uint_fast8_t -CountLeadingZeroes64(uint64_t aValue) -{ +inline uint_fast8_t CountLeadingZeroes64(uint64_t aValue) { MOZ_ASSERT(aValue != 0); return detail::CountLeadingZeroes64(aValue); } /** Analogous to CountTrailingZeroes32, but for 64-bit numbers. */ -inline uint_fast8_t -CountTrailingZeroes64(uint64_t aValue) -{ +inline uint_fast8_t CountTrailingZeroes64(uint64_t aValue) { MOZ_ASSERT(aValue != 0); return detail::CountTrailingZeroes64(aValue); } namespace detail { -template +template class CeilingLog2; -template -class CeilingLog2 -{ -public: - static uint_fast8_t compute(const T aValue) - { +template +class CeilingLog2 { + public: + static uint_fast8_t compute(const T aValue) { // Check for <= 1 to avoid the == 0 undefined case. return aValue <= 1 ? 0u : 32u - CountLeadingZeroes32(aValue - 1); } }; -template -class CeilingLog2 -{ -public: - static uint_fast8_t compute(const T aValue) - { +template +class CeilingLog2 { + public: + static uint_fast8_t compute(const T aValue) { // Check for <= 1 to avoid the == 0 undefined case. return aValue <= 1 ? 0u : 64u - CountLeadingZeroes64(aValue - 1); } }; -} // namespace detail +} // namespace detail /** * Compute the log of the least power of 2 greater than or equal to |aValue|. @@ -401,46 +385,38 @@ * CeilingLog2(5..8) is 3; * CeilingLog2(9..16) is 4; and so on. */ -template -inline uint_fast8_t -CeilingLog2(const T aValue) -{ +template +inline uint_fast8_t CeilingLog2(const T aValue) { return detail::CeilingLog2::compute(aValue); } /** A CeilingLog2 variant that accepts only size_t. */ -inline uint_fast8_t -CeilingLog2Size(size_t aValue) -{ +inline uint_fast8_t CeilingLog2Size(size_t aValue) { return CeilingLog2(aValue); } namespace detail { -template +template class FloorLog2; -template -class FloorLog2 -{ -public: - static uint_fast8_t compute(const T aValue) - { +template +class FloorLog2 { + public: + static uint_fast8_t compute(const T aValue) { return 31u - CountLeadingZeroes32(aValue | 1); } }; -template -class FloorLog2 -{ -public: - static uint_fast8_t compute(const T aValue) - { +template +class FloorLog2 { + public: + static uint_fast8_t compute(const T aValue) { return 63u - CountLeadingZeroes64(aValue | 1); } }; -} // namespace detail +} // namespace detail /** * Compute the log of the greatest power of 2 less than or equal to |aValue|. @@ -450,27 +426,19 @@ * FloorLog2(4..7) is 2; * FloorLog2(8..15) is 3; and so on. */ -template -inline uint_fast8_t -FloorLog2(const T aValue) -{ +template +inline uint_fast8_t FloorLog2(const T aValue) { return detail::FloorLog2::compute(aValue); } /** A FloorLog2 variant that accepts only size_t. */ -inline uint_fast8_t -FloorLog2Size(size_t aValue) -{ - return FloorLog2(aValue); -} +inline uint_fast8_t FloorLog2Size(size_t aValue) { return FloorLog2(aValue); } /* * Compute the smallest power of 2 greater than or equal to |x|. |x| must not * be so great that the computed value would overflow |size_t|. */ -inline size_t -RoundUpPow2(size_t aValue) -{ +inline size_t RoundUpPow2(size_t aValue) { MOZ_ASSERT(aValue <= (size_t(1) << (sizeof(size_t) * CHAR_BIT - 1)), "can't round up -- will overflow!"); return size_t(1) << CeilingLog2(aValue); @@ -479,34 +447,36 @@ /** * Rotates the bits of the given value left by the amount of the shift width. */ -template -inline T -RotateLeft(const T aValue, uint_fast8_t aShift) -{ +template +MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW inline T RotateLeft(const T aValue, + uint_fast8_t aShift) { + static_assert(IsUnsigned::value, "Rotates require unsigned values"); + MOZ_ASSERT(aShift < sizeof(T) * CHAR_BIT, "Shift value is too large!"); MOZ_ASSERT(aShift > 0, "Rotation by value length is undefined behavior, but compilers " "do not currently fold a test into the rotate instruction. " "Please remove this restriction when compilers optimize the " "zero case (http://blog.regehr.org/archives/1063)."); - static_assert(IsUnsigned::value, "Rotates require unsigned values"); + return (aValue << aShift) | (aValue >> (sizeof(T) * CHAR_BIT - aShift)); } /** * Rotates the bits of the given value right by the amount of the shift width. */ -template -inline T -RotateRight(const T aValue, uint_fast8_t aShift) -{ +template +MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW inline T RotateRight(const T aValue, + uint_fast8_t aShift) { + static_assert(IsUnsigned::value, "Rotates require unsigned values"); + MOZ_ASSERT(aShift < sizeof(T) * CHAR_BIT, "Shift value is too large!"); MOZ_ASSERT(aShift > 0, "Rotation by value length is undefined behavior, but compilers " "do not currently fold a test into the rotate instruction. " "Please remove this restriction when compilers optimize the " "zero case (http://blog.regehr.org/archives/1063)."); - static_assert(IsUnsigned::value, "Rotates require unsigned values"); + return (aValue >> aShift) | (aValue << (sizeof(T) * CHAR_BIT - aShift)); } @@ -514,32 +484,25 @@ * Returns true if |x| is a power of two. * Zero is not an integer power of two. (-Inf is not an integer) */ -template -constexpr bool -IsPowerOfTwo(T x) -{ - static_assert(IsUnsigned::value, - "IsPowerOfTwo requires unsigned values"); - return x && (x & (x - 1)) == 0; -} - -template -inline T -Clamp(const T aValue, const T aMin, const T aMax) -{ - static_assert(IsIntegral::value, - "Clamp accepts only integral types, so that it doesn't have" - " to distinguish differently-signed zeroes (which users may" - " or may not care to distinguish, likely at a perf cost) or" - " to decide how to clamp NaN or a range with a NaN" - " endpoint."); - MOZ_ASSERT(aMin <= aMax); - - if (aValue <= aMin) - return aMin; - if (aValue >= aMax) - return aMax; - return aValue; +template +constexpr bool IsPowerOfTwo(T x) { + static_assert(IsUnsigned::value, "IsPowerOfTwo requires unsigned values"); + return x && (x & (x - 1)) == 0; +} + +template +inline T Clamp(const T aValue, const T aMin, const T aMax) { + static_assert(IsIntegral::value, + "Clamp accepts only integral types, so that it doesn't have" + " to distinguish differently-signed zeroes (which users may" + " or may not care to distinguish, likely at a perf cost) or" + " to decide how to clamp NaN or a range with a NaN" + " endpoint."); + MOZ_ASSERT(aMin <= aMax); + + if (aValue <= aMin) return aMin; + if (aValue >= aMax) return aMax; + return aValue; } } /* namespace mozilla */ 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 @@ -12,15 +12,38 @@ #include "mozilla/Alignment.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" +#include "mozilla/MemoryChecking.h" #include "mozilla/Move.h" +#include "mozilla/OperatorNewExtensions.h" +#include "mozilla/Poison.h" #include "mozilla/TypeTraits.h" #include // for placement new +#include #include namespace mozilla { -struct Nothing { }; +struct Nothing {}; + +namespace detail { + +template +struct MaybePoisoner { + static const size_t N = sizeof(T); + + static void poison(void* aPtr) { +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + // Avoid MOZ_ASSERT in mozWritePoison. + if (N >= sizeof(uintptr_t)) { + mozWritePoison(aPtr, N); + } +#endif + MOZ_MAKE_MEM_UNDEFINED(aPtr, N); + } +}; + +} // namespace detail /* * Maybe is a container class which contains either zero or one elements. It @@ -80,90 +103,75 @@ * extra branches/loads/stores. Use with caution on hot paths; it's not known * whether or not this is still a problem. */ -template -class Maybe -{ - bool mIsSome; - AlignedStorage2 mStorage; +template +class MOZ_NON_PARAM MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe { + MOZ_ALIGNAS_IN_STRUCT(T) unsigned char mStorage[sizeof(T)]; + char mIsSome; // not bool -- guarantees minimal space consumption + + // GCC fails due to -Werror=strict-aliasing if |mStorage| is directly cast to + // T*. Indirecting through these functions addresses the problem. + void* data() { return mStorage; } + const void* data() const { return mStorage; } -public: - typedef T ValueType; + void poisonData() { detail::MaybePoisoner::poison(data()); } - Maybe() : mIsSome(false) { } + public: + using ValueType = T; + + Maybe() : mIsSome(false) { poisonData(); } ~Maybe() { reset(); } - MOZ_IMPLICIT Maybe(Nothing) : mIsSome(false) { } + MOZ_IMPLICIT Maybe(Nothing) : mIsSome(false) { poisonData(); } - Maybe(const Maybe& aOther) - : mIsSome(false) - { + Maybe(const Maybe& aOther) : mIsSome(false) { if (aOther.mIsSome) { emplace(*aOther); + } else { + poisonData(); } } /** - * Maybe can be copy-constructed from a Maybe if U* and T* are - * compatible, or from Maybe. + * Maybe can be copy-constructed from a Maybe if U is convertible to T. */ - 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) - { + template ::value>::type> + MOZ_IMPLICIT Maybe(const Maybe& aOther) : mIsSome(false) { if (aOther.isSome()) { emplace(*aOther); + } else { + poisonData(); } } - Maybe(Maybe&& aOther) - : mIsSome(false) - { + Maybe(Maybe&& aOther) : mIsSome(false) { if (aOther.mIsSome) { emplace(Move(*aOther)); aOther.reset(); + } else { + poisonData(); } } /** - * Maybe can be move-constructed from a Maybe if U* and T* are - * compatible, or from Maybe. + * Maybe can be move-constructed from a Maybe if U is convertible to T. */ - 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) - { + template ::value>::type> + MOZ_IMPLICIT Maybe(Maybe&& aOther) : mIsSome(false) { if (aOther.isSome()) { emplace(Move(*aOther)); aOther.reset(); + } else { + poisonData(); } } - Maybe& operator=(const Maybe& aOther) - { + Maybe& operator=(const Maybe& aOther) { if (&aOther != this) { if (aOther.mIsSome) { if (mIsSome) { - // XXX(seth): The correct code for this branch, below, can't be used - // due to a bug in Visual Studio 2010. See bug 1052940. - /* ref() = aOther.ref(); - */ - reset(); - emplace(*aOther); } else { emplace(*aOther); } @@ -174,8 +182,22 @@ return *this; } - Maybe& operator=(Maybe&& aOther) - { + template ::value>::type> + Maybe& operator=(const Maybe& aOther) { + if (aOther.isSome()) { + if (mIsSome) { + ref() = aOther.ref(); + } else { + emplace(*aOther); + } + } else { + reset(); + } + return *this; + } + + Maybe& operator=(Maybe&& aOther) { MOZ_ASSERT(this != &aOther, "Self-moves are prohibited"); if (aOther.mIsSome) { @@ -192,14 +214,31 @@ return *this; } + template ::value>::type> + Maybe& operator=(Maybe&& aOther) { + if (aOther.isSome()) { + if (mIsSome) { + ref() = Move(aOther.ref()); + } else { + emplace(Move(*aOther)); + } + aOther.reset(); + } else { + reset(); + } + + return *this; + } + /* Methods that check whether this Maybe contains a value */ explicit operator bool() const { return isSome(); } bool isSome() const { return mIsSome; } bool isNothing() const { return !mIsSome; } - /* Returns the contents of this Maybe by value. Unsafe unless |isSome()|. */ - T value() const - { + /* Returns the contents of this Maybe by value. Unsafe unless |isSome()|. + */ + T value() const { MOZ_ASSERT(mIsSome); return ref(); } @@ -208,9 +247,8 @@ * Returns the contents of this Maybe by value. If |isNothing()|, returns * the default value provided. */ - template - T valueOr(V&& aDefault) const - { + template + T valueOr(V&& aDefault) const { if (isSome()) { return ref(); } @@ -221,24 +259,22 @@ * Returns the contents of this Maybe by value. If |isNothing()|, returns * the value returned from the function or functor provided. */ - template - T valueOrFrom(F&& aFunc) const - { + template + T valueOrFrom(F&& aFunc) const { if (isSome()) { return ref(); } return aFunc(); } - /* Returns the contents of this Maybe by pointer. Unsafe unless |isSome()|. */ - T* ptr() - { + /* Returns the contents of this Maybe by pointer. Unsafe unless |isSome()|. + */ + T* ptr() { MOZ_ASSERT(mIsSome); return &ref(); } - const T* ptr() const - { + const T* ptr() const { MOZ_ASSERT(mIsSome); return &ref(); } @@ -247,16 +283,14 @@ * Returns the contents of this Maybe by pointer. If |isNothing()|, * returns the default value provided. */ - T* ptrOr(T* aDefault) - { + T* ptrOr(T* aDefault) { if (isSome()) { return ptr(); } return aDefault; } - const T* ptrOr(const T* aDefault) const - { + const T* ptrOr(const T* aDefault) const { if (isSome()) { return ptr(); } @@ -267,63 +301,55 @@ * Returns the contents of this Maybe by pointer. If |isNothing()|, * returns the value returned from the function or functor provided. */ - template - T* ptrOrFrom(F&& aFunc) - { + template + T* ptrOrFrom(F&& aFunc) { if (isSome()) { return ptr(); } return aFunc(); } - template - const T* ptrOrFrom(F&& aFunc) const - { + template + const T* ptrOrFrom(F&& aFunc) const { if (isSome()) { return ptr(); } return aFunc(); } - T* operator->() - { + T* operator->() { MOZ_ASSERT(mIsSome); return ptr(); } - const T* operator->() const - { + const T* operator->() const { MOZ_ASSERT(mIsSome); return ptr(); } /* Returns the contents of this Maybe by ref. Unsafe unless |isSome()|. */ - T& ref() - { + T& ref() { MOZ_ASSERT(mIsSome); - return *mStorage.addr(); + return *static_cast(data()); } - const T& ref() const - { + const T& ref() const { MOZ_ASSERT(mIsSome); - return *mStorage.addr(); + return *static_cast(data()); } /* * Returns the contents of this Maybe by ref. If |isNothing()|, returns * the default value provided. */ - T& refOr(T& aDefault) - { + T& refOr(T& aDefault) { if (isSome()) { return ref(); } return aDefault; } - const T& refOr(const T& aDefault) const - { + const T& refOr(const T& aDefault) const { if (isSome()) { return ref(); } @@ -334,50 +360,44 @@ * Returns the contents of this Maybe by ref. If |isNothing()|, returns the * value returned from the function or functor provided. */ - template - T& refOrFrom(F&& aFunc) - { + template + T& refOrFrom(F&& aFunc) { if (isSome()) { return ref(); } return aFunc(); } - template - const T& refOrFrom(F&& aFunc) const - { + template + const T& refOrFrom(F&& aFunc) const { if (isSome()) { return ref(); } return aFunc(); } - T& operator*() - { + T& operator*() { MOZ_ASSERT(mIsSome); return ref(); } - const T& operator*() const - { + const T& operator*() const { MOZ_ASSERT(mIsSome); return ref(); } /* If |isSome()|, runs the provided function or functor on the contents of * this Maybe. */ - template - Maybe& apply(Func aFunc) - { + template + Maybe& apply(Func aFunc) { if (isSome()) { aFunc(ref()); } return *this; } - template - const Maybe& apply(Func aFunc) const - { + template + const Maybe& apply(Func aFunc) const { if (isSome()) { aFunc(ref()); } @@ -388,9 +408,8 @@ * If |isSome()|, runs the provided function and returns the result wrapped * in a Maybe. If |isNothing()|, returns an empty Maybe value. */ - template - auto map(Func aFunc) -> Maybe>().ref()))> - { + template + auto map(Func aFunc) -> Maybe>().ref()))> { using ReturnType = decltype(aFunc(ref())); if (isSome()) { Maybe val; @@ -400,9 +419,9 @@ return Maybe(); } - template - auto map(Func aFunc) const -> Maybe>().ref()))> - { + template + auto map(Func aFunc) const + -> Maybe>().ref()))> { using ReturnType = decltype(aFunc(ref())); if (isSome()) { Maybe val; @@ -413,11 +432,11 @@ } /* If |isSome()|, empties this Maybe and destroys its contents. */ - void reset() - { + void reset() { if (isSome()) { ref().T::~T(); mIsSome = false; + poisonData(); } } @@ -425,13 +444,22 @@ * Constructs a T value in-place in this empty Maybe's storage. The * arguments to |emplace()| are the parameters to T's constructor. */ - template - void emplace(Args&&... aArgs) - { + template + void emplace(Args&&... aArgs) { MOZ_ASSERT(!mIsSome); - ::new (mStorage.addr()) T(Forward(aArgs)...); + ::new (KnownNotNull, data()) T(Forward(aArgs)...); mIsSome = true; } + + friend std::ostream& operator<<(std::ostream& aStream, + const Maybe& aMaybe) { + if (aMaybe) { + aStream << aMaybe.ref(); + } else { + aStream << ""; + } + return aStream; + } }; /* @@ -444,20 +472,17 @@ * if you need to construct a Maybe value that holds a const, volatile, or * reference value, you need to use emplace() instead. */ -template -Maybe::Type>::Type> -Some(T&& aValue) -{ - typedef typename RemoveCV::Type>::Type U; +template ::type>::type> +Maybe Some(T&& aValue) { Maybe value; value.emplace(Forward(aValue)); return value; } -template -Maybe::Type>::Type> -ToMaybe(T* aPtr) -{ +template +Maybe::Type>::Type> ToMaybe( + T* aPtr) { if (aPtr) { return Some(*aPtr); } @@ -469,18 +494,16 @@ * - both are Nothing, or * - both are Some, and the values they contain are equal. */ -template bool -operator==(const Maybe& aLHS, const Maybe& aRHS) -{ +template +bool operator==(const Maybe& aLHS, const Maybe& aRHS) { if (aLHS.isNothing() != aRHS.isNothing()) { return false; } return aLHS.isNothing() || *aLHS == *aRHS; } -template bool -operator!=(const Maybe& aLHS, const Maybe& aRHS) -{ +template +bool operator!=(const Maybe& aLHS, const Maybe& aRHS) { return !(aLHS == aRHS); } @@ -488,27 +511,23 @@ * We support comparison to Nothing to allow reasonable expressions like: * if (maybeValue == Nothing()) { ... } */ -template bool -operator==(const Maybe& aLHS, const Nothing& aRHS) -{ +template +bool operator==(const Maybe& aLHS, const Nothing& aRHS) { return aLHS.isNothing(); } -template bool -operator!=(const Maybe& aLHS, const Nothing& aRHS) -{ +template +bool operator!=(const Maybe& aLHS, const Nothing& aRHS) { return !(aLHS == aRHS); } -template bool -operator==(const Nothing& aLHS, const Maybe& aRHS) -{ +template +bool operator==(const Nothing& aLHS, const Maybe& aRHS) { return aRHS.isNothing(); } -template bool -operator!=(const Nothing& aLHS, const Maybe& aRHS) -{ +template +bool operator!=(const Nothing& aLHS, const Maybe& aRHS) { return !(aLHS == aRHS); } @@ -516,9 +535,8 @@ * Maybe values are ordered in the same way T values are ordered, except that * Nothing comes before anything else. */ -template bool -operator<(const Maybe& aLHS, const Maybe& aRHS) -{ +template +bool operator<(const Maybe& aLHS, const Maybe& aRHS) { if (aLHS.isNothing()) { return aRHS.isSome(); } @@ -528,24 +546,21 @@ return *aLHS < *aRHS; } -template bool -operator>(const Maybe& aLHS, const Maybe& aRHS) -{ +template +bool operator>(const Maybe& aLHS, const Maybe& aRHS) { return !(aLHS < aRHS || aLHS == aRHS); } -template bool -operator<=(const Maybe& aLHS, const Maybe& aRHS) -{ +template +bool operator<=(const Maybe& aLHS, const Maybe& aRHS) { return aLHS < aRHS || aLHS == aRHS; } -template bool -operator>=(const Maybe& aLHS, const Maybe& aRHS) -{ +template +bool operator>=(const Maybe& aLHS, const Maybe& aRHS) { return !(aLHS < aRHS); } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_Maybe_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/MaybeOneOf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/MaybeOneOf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/MaybeOneOf.h @@ -4,15 +4,21 @@ * 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 class storing one of two optional value types that supports in-place lazy + * construction. + */ + #ifndef mozilla_MaybeOneOf_h #define mozilla_MaybeOneOf_h -#include "mozilla/Alignment.h" #include "mozilla/Assertions.h" #include "mozilla/Move.h" +#include "mozilla/OperatorNewExtensions.h" #include "mozilla/TemplateLib.h" -#include // For placement new +#include // for placement new +#include // for size_t namespace mozilla { @@ -24,36 +30,47 @@ * |construct()|, a T1 or T2 object will be constructed with the given * arguments and that object will be destroyed when the owning MaybeOneOf is * destroyed. + * + * Because MaybeOneOf must be aligned suitable to hold any value stored within + * it, and because |alignas| requirements don't affect platform ABI with respect + * to how parameters are laid out in memory, MaybeOneOf can't be used as the + * type of a function parameter. Pass MaybeOneOf to functions by pointer or + * reference instead. */ -template -class MaybeOneOf -{ - AlignedStorage::value> storage; +template +class MOZ_NON_PARAM MaybeOneOf { + static constexpr size_t StorageAlignment = + tl::Max::value; + static constexpr size_t StorageSize = tl::Max::value; + + alignas(StorageAlignment) unsigned char storage[StorageSize]; + + // GCC fails due to -Werror=strict-aliasing if |storage| is directly cast to + // T*. Indirecting through these functions addresses the problem. + void* data() { return storage; } + const void* data() const { return storage; } enum State { None, SomeT1, SomeT2 } state; - template struct Type2State {}; + template + struct Type2State {}; template - T& as() - { + T& as() { MOZ_ASSERT(state == Type2State::result); - return *(T*)storage.addr(); + return *static_cast(data()); } template - const T& as() const - { + const T& as() const { MOZ_ASSERT(state == Type2State::result); - return *(T*)storage.addr(); + return *static_cast(data()); } -public: + public: MaybeOneOf() : state(None) {} ~MaybeOneOf() { destroyIfConstructed(); } - MaybeOneOf(MaybeOneOf&& rhs) - : state(None) - { + MaybeOneOf(MaybeOneOf&& rhs) : state(None) { if (!rhs.empty()) { if (rhs.constructed()) { construct(Move(rhs.as())); @@ -66,41 +83,38 @@ } } - MaybeOneOf &operator=(MaybeOneOf&& rhs) - { + MaybeOneOf& operator=(MaybeOneOf&& rhs) { MOZ_ASSERT(this != &rhs, "Self-move is prohibited"); this->~MaybeOneOf(); - new(this) MaybeOneOf(Move(rhs)); + new (this) MaybeOneOf(Move(rhs)); return *this; } bool empty() const { return state == None; } template - bool constructed() const { return state == Type2State::result; } + bool constructed() const { + return state == Type2State::result; + } template - void construct(Args&&... aArgs) - { + void construct(Args&&... aArgs) { MOZ_ASSERT(state == None); state = Type2State::result; - ::new (storage.addr()) T(Forward(aArgs)...); + ::new (KnownNotNull, data()) T(Forward(aArgs)...); } template - T& ref() - { + T& ref() { return as(); } template - const T& ref() const - { + const T& ref() const { return as(); } - void destroy() - { + void destroy() { MOZ_ASSERT(state == SomeT1 || state == SomeT2); if (state == SomeT1) { as().~T1(); @@ -110,34 +124,31 @@ state = None; } - void destroyIfConstructed() - { + void destroyIfConstructed() { if (!empty()) { destroy(); } } -private: + private: MaybeOneOf(const MaybeOneOf& aOther) = delete; const MaybeOneOf& operator=(const MaybeOneOf& aOther) = delete; }; template template -struct MaybeOneOf::Type2State -{ +struct MaybeOneOf::Type2State { typedef MaybeOneOf Enclosing; static const typename Enclosing::State result = Enclosing::SomeT1; }; template template -struct MaybeOneOf::Type2State -{ +struct MaybeOneOf::Type2State { typedef MaybeOneOf Enclosing; static const typename Enclosing::State result = Enclosing::SomeT2; }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_MaybeOneOf_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/MemoryChecking.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/MemoryChecking.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/MemoryChecking.h @@ -49,8 +49,8 @@ /* These definitions are usually provided through the * sanitizer/asan_interface.h header installed by ASan. */ -void MOZ_ASAN_VISIBILITY -__asan_poison_memory_region(void const volatile *addr, size_t size); +void MOZ_ASAN_VISIBILITY __asan_poison_memory_region(void const volatile *addr, + size_t size); void MOZ_ASAN_VISIBILITY __asan_unpoison_memory_region(void const volatile *addr, size_t size); @@ -67,9 +67,7 @@ * These definitions are usually provided through the * sanitizer/lsan_interface.h header installed by LSan. */ -void MOZ_EXPORT -__lsan_ignore_object(const void *p); - +void MOZ_EXPORT __lsan_ignore_object(const void *p); } #elif defined(MOZ_MSAN) #include @@ -80,19 +78,14 @@ /* These definitions are usually provided through the * sanitizer/msan_interface.h header installed by MSan. */ -void MOZ_EXPORT -__msan_poison(void const volatile *addr, size_t size); -void MOZ_EXPORT -__msan_unpoison(void const volatile *addr, size_t size); +void MOZ_EXPORT __msan_poison(void const volatile *addr, size_t size); +void MOZ_EXPORT __msan_unpoison(void const volatile *addr, size_t size); -#define MOZ_MAKE_MEM_NOACCESS(addr, size) \ - __msan_poison((addr), (size)) +#define MOZ_MAKE_MEM_NOACCESS(addr, size) __msan_poison((addr), (size)) -#define MOZ_MAKE_MEM_UNDEFINED(addr, size) \ - __msan_poison((addr), (size)) +#define MOZ_MAKE_MEM_UNDEFINED(addr, size) __msan_poison((addr), (size)) -#define MOZ_MAKE_MEM_DEFINED(addr, size) \ - __msan_unpoison((addr), (size)) +#define MOZ_MAKE_MEM_DEFINED(addr, size) __msan_unpoison((addr), (size)) } #elif defined(MOZ_VALGRIND) #define MOZ_MAKE_MEM_NOACCESS(addr, size) \ @@ -105,9 +98,15 @@ VALGRIND_MAKE_MEM_DEFINED((addr), (size)) #else -#define MOZ_MAKE_MEM_NOACCESS(addr, size) do {} while (0) -#define MOZ_MAKE_MEM_UNDEFINED(addr, size) do {} while (0) -#define MOZ_MAKE_MEM_DEFINED(addr, size) do {} while (0) +#define MOZ_MAKE_MEM_NOACCESS(addr, size) \ + do { \ + } while (0) +#define MOZ_MAKE_MEM_UNDEFINED(addr, size) \ + do { \ + } while (0) +#define MOZ_MAKE_MEM_DEFINED(addr, size) \ + do { \ + } while (0) #endif @@ -120,10 +119,9 @@ * conversant in leak-checking and/or MFBT peers. */ #if defined(MOZ_ASAN) -# define MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(X) __lsan_ignore_object(X) +#define MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(X) __lsan_ignore_object(X) #else -# define MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(X) /* nothing */ -#endif // defined(MOZ_ASAN) - +#define MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(X) /* nothing */ +#endif // defined(MOZ_ASAN) #endif /* mozilla_MemoryChecking_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Move.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Move.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Move.h @@ -196,10 +196,8 @@ * Identical to std::Move(); this is necessary until our stlport supports * std::move(). */ -template -inline typename RemoveReference::Type&& -Move(T&& aX) -{ +template +inline typename RemoveReference::Type&& Move(T&& aX) { return static_cast::Type&&>(aX); } @@ -207,32 +205,26 @@ * These two overloads are identical to std::forward(); they are necessary until * our stlport supports std::forward(). */ -template -inline T&& -Forward(typename RemoveReference::Type& aX) -{ +template +inline T&& Forward(typename RemoveReference::Type& aX) { return static_cast(aX); } -template -inline T&& -Forward(typename RemoveReference::Type&& aX) -{ +template +inline T&& Forward(typename RemoveReference::Type&& aX) { static_assert(!IsLvalueReference::value, "misuse of Forward detected! try the other overload"); return static_cast(aX); } /** Swap |aX| and |aY| using move-construction if possible. */ -template -inline void -Swap(T& aX, T& aY) -{ +template +inline void Swap(T& aX, T& aY) { T tmp(Move(aX)); aX = Move(aY); aY = Move(tmp); } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_Move_h */ 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 @@ -63,6 +63,8 @@ // for the last one, where the handle type is |void|. See below. #include "mozilla/Assertions.h" +#include "mozilla/Move.h" +#include namespace mozilla { @@ -84,8 +86,8 @@ // - 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. +// only be done with WrapNotNull() or MakeNotNull<>(), 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. @@ -98,23 +100,30 @@ // https://github.com/Microsoft/GSL/issues/89 for some discussion. // template -class NotNull -{ - template friend NotNull WrapNotNull(U aBasePtr); +class NotNull { + template + friend NotNull WrapNotNull(U aBasePtr); + template + friend NotNull MakeNotNull(Args&&... aArgs); T mBasePtr; - // This constructor is only used by WrapNotNull(). + // This constructor is only used by WrapNotNull() and MakeNotNull(). template explicit NotNull(U aBasePtr) : mBasePtr(aBasePtr) {} -public: + 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()) {} + MOZ_IMPLICIT NotNull(const NotNull& aOther) : mBasePtr(aOther.get()) { + static_assert(sizeof(T) == sizeof(NotNull), + "NotNull must have zero space overhead."); + static_assert(offsetof(NotNull, mBasePtr) == 0, + "mBasePtr must have zero offset."); + } // Default copy/move construction and assignment. NotNull(const NotNull&) = default; @@ -138,72 +147,95 @@ }; template -NotNull -WrapNotNull(const T aBasePtr) -{ +NotNull WrapNotNull(const T aBasePtr) { NotNull notNull(aBasePtr); MOZ_RELEASE_ASSERT(aBasePtr); return notNull; } +namespace detail { + +// Extract the pointed-to type from a pointer type (be it raw or smart). +// The default implementation uses the dereferencing operator of the pointer +// type to find what it's pointing to. +template +struct PointedTo { + // Remove the reference that dereferencing operators may return. + using Type = typename RemoveReference())>::Type; + using NonConstType = typename RemoveConst::Type; +}; + +// Specializations for raw pointers. +// This is especially required because VS 2017 15.6 (March 2018) started +// rejecting the above `decltype(*DeclVal())` trick for raw pointers. +// See bug 1443367. +template +struct PointedTo { + using Type = T; + using NonConstType = T; +}; + +template +struct PointedTo { + using Type = const T; + using NonConstType = T; +}; + +} // namespace detail + +// Allocate an object with infallible new, and wrap its pointer in NotNull. +// |MakeNotNull>(args...)| will run |new Ob(args...)| +// and return NotNull>. +template +NotNull MakeNotNull(Args&&... aArgs) { + using Pointee = typename detail::PointedTo::NonConstType; + static_assert(!IsArray::value, + "MakeNotNull cannot construct an array"); + return NotNull(new Pointee(Forward(aArgs)...)); +} + // Compare two NotNulls. template -inline bool -operator==(const NotNull& aLhs, const NotNull& aRhs) -{ +inline bool operator==(const NotNull& aLhs, const NotNull& aRhs) { return aLhs.get() == aRhs.get(); } template -inline bool -operator!=(const NotNull& aLhs, const NotNull& aRhs) -{ +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) -{ +inline bool operator==(const NotNull& aLhs, const U& aRhs) { return aLhs.get() == aRhs; } template -inline bool -operator!=(const NotNull& aLhs, const U& aRhs) -{ +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) -{ +inline bool operator==(const T& aLhs, const NotNull& aRhs) { return aLhs == aRhs.get(); } template -inline bool -operator!=(const T& aLhs, const NotNull& aRhs) -{ +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; +bool operator==(const NotNull&, decltype(nullptr)) = delete; template -bool -operator!=(const NotNull&, decltype(nullptr)) = delete; +bool operator!=(const NotNull&, decltype(nullptr)) = delete; // Disallow comparing a nullptr to a NotNull. template -bool -operator==(decltype(nullptr), const NotNull&) = delete; +bool operator==(decltype(nullptr), const NotNull&) = delete; template -bool -operator!=(decltype(nullptr), const NotNull&) = delete; +bool operator!=(decltype(nullptr), const NotNull&) = delete; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_NotNull_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/NullPtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/NullPtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/NullPtr.h @@ -20,12 +20,12 @@ * (fixed in C++14), so in the interests of easing a switch to , * this trait lives elsewhere. */ -template +template struct IsNullPointer : FalseType {}; -template<> +template <> struct IsNullPointer : TrueType {}; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_NullPtr_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Opaque.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Opaque.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Opaque.h @@ -18,15 +18,14 @@ * must be supported, and it's desirable to prevent accidental dependency on * exact values. */ -template -class Opaque final -{ +template +class Opaque final { static_assert(mozilla::IsIntegral::value, "mozilla::Opaque only supports integral types"); T mValue; -public: + public: Opaque() {} explicit Opaque(T aValue) : mValue(aValue) {} @@ -34,11 +33,9 @@ return mValue == aOther.mValue; } - bool operator!=(const Opaque& aOther) const { - return !(*this == aOther); - } + bool operator!=(const Opaque& aOther) const { return !(*this == aOther); } }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_Opaque_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 @@ -17,7 +17,7 @@ enum NotNullTag { KnownNotNull, }; -} // namespace mozilla +} // namespace mozilla /* * The logic here is a little subtle. [expr.new] states that if the allocation @@ -42,11 +42,9 @@ * 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) -{ +inline void* operator new(size_t, mozilla::NotNullTag, void* p) { MOZ_ASSERT(p); return p; } -#endif // mozilla_OperatorNewExtensions_h +#endif // mozilla_OperatorNewExtensions_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Pair.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Pair.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Pair.h @@ -26,114 +26,98 @@ // The extra conditions on storage for B are necessary so that PairHelper won't // ambiguously inherit from either A or B, such that one or the other base class // would be inaccessible. -template::value ? detail::AsBase : detail::AsMember, - detail::StorageType = - IsEmpty::value && !IsBaseOf::value && !IsBaseOf::value - ? detail::AsBase - : detail::AsMember> +template ::value ? detail::AsBase : detail::AsMember, + detail::StorageType = IsEmpty::value && !IsBaseOf::value && + !IsBaseOf::value + ? detail::AsBase + : detail::AsMember> struct PairHelper; -template -struct PairHelper -{ -protected: - template +template +struct PairHelper { + protected: + template PairHelper(AArg&& aA, BArg&& aB) - : mFirstA(Forward(aA)), - mSecondB(Forward(aB)) - {} + : mFirstA(Forward(aA)), mSecondB(Forward(aB)) {} A& first() { return mFirstA; } const A& first() const { return mFirstA; } B& second() { return mSecondB; } const B& second() const { return mSecondB; } - void swap(PairHelper& aOther) - { + void swap(PairHelper& aOther) { Swap(mFirstA, aOther.mFirstA); Swap(mSecondB, aOther.mSecondB); } -private: + private: A mFirstA; B mSecondB; }; -template -struct PairHelper : private B -{ -protected: - template +template +struct PairHelper : private B { + protected: + template PairHelper(AArg&& aA, BArg&& aB) - : B(Forward(aB)), - mFirstA(Forward(aA)) - {} + : B(Forward(aB)), mFirstA(Forward(aA)) {} A& first() { return mFirstA; } const A& first() const { return mFirstA; } B& second() { return *this; } const B& second() const { return *this; } - void swap(PairHelper& aOther) - { + void swap(PairHelper& aOther) { Swap(mFirstA, aOther.mFirstA); Swap(static_cast(*this), static_cast(aOther)); } -private: + private: A mFirstA; }; -template -struct PairHelper : private A -{ -protected: - template +template +struct PairHelper : private A { + protected: + template PairHelper(AArg&& aA, BArg&& aB) - : A(Forward(aA)), - mSecondB(Forward(aB)) - {} + : A(Forward(aA)), mSecondB(Forward(aB)) {} A& first() { return *this; } const A& first() const { return *this; } B& second() { return mSecondB; } const B& second() const { return mSecondB; } - void swap(PairHelper& aOther) - { + void swap(PairHelper& aOther) { Swap(static_cast(*this), static_cast(aOther)); Swap(mSecondB, aOther.mSecondB); } -private: + private: B mSecondB; }; -template -struct PairHelper : private A, private B -{ -protected: - template +template +struct PairHelper : private A, private B { + protected: + template PairHelper(AArg&& aA, BArg&& aB) - : A(Forward(aA)), - B(Forward(aB)) - {} + : A(Forward(aA)), B(Forward(aB)) {} A& first() { return static_cast(*this); } const A& first() const { return static_cast(*this); } B& second() { return static_cast(*this); } const B& second() const { return static_cast(*this); } - void swap(PairHelper& aOther) - { + void swap(PairHelper& aOther) { Swap(static_cast(*this), static_cast(aOther)); Swap(static_cast(*this), static_cast(aOther)); } }; -} // namespace detail +} // namespace detail /** * Pair is the logical concatenation of an instance of A with an instance B. @@ -148,26 +132,19 @@ * required to optimize space usage.) The first/second names are merely * conceptual! */ -template -struct Pair - : private detail::PairHelper -{ +template +struct Pair : private detail::PairHelper { typedef typename detail::PairHelper Base; -public: - template - Pair(AArg&& aA, BArg&& aB) - : Base(Forward(aA), Forward(aB)) - {} - - Pair(Pair&& aOther) - : Base(Move(aOther.first()), Move(aOther.second())) - { } + public: + template + Pair(AArg&& aA, BArg&& aB) : Base(Forward(aA), Forward(aB)) {} + + Pair(Pair&& aOther) : Base(Move(aOther.first()), Move(aOther.second())) {} Pair(const Pair& aOther) = default; - Pair& operator=(Pair&& aOther) - { + Pair& operator=(Pair&& aOther) { MOZ_ASSERT(this != &aOther, "Self-moves are prohibited"); first() = Move(aOther.first()); @@ -187,10 +164,8 @@ void swap(Pair& aOther) { Base::swap(aOther); } }; -template -void -Swap(Pair& aX, Pair& aY) -{ +template +void Swap(Pair& aX, Pair& aY) { aX.swap(aY); } @@ -202,18 +177,15 @@ * * will return a Pair. */ -template +template Pair::Type>::Type, typename RemoveCV::Type>::Type> -MakePair(A&& aA, B&& aB) -{ - return - Pair::Type>::Type, - typename RemoveCV::Type>::Type>( - Forward(aA), - Forward(aB)); +MakePair(A&& aA, B&& aB) { + return Pair::Type>::Type, + typename RemoveCV::Type>::Type>( + Forward(aA), Forward(aB)); } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_Pair_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Path.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Path.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Path.h @@ -0,0 +1,31 @@ +/* -*- 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/. */ + +/* Represents the native path format on the platform. */ + +#ifndef mozilla_Path_h +#define mozilla_Path_h + +namespace mozilla { +namespace filesystem { + +/* + * Mozilla vaiant of std::filesystem::path. + * Only |value_type| is implemented at the moment. + */ +class Path { + public: +#ifdef XP_WIN + using value_type = char16_t; +#else + using value_type = char; +#endif +}; + +} /* namespace filesystem */ +} /* namespace mozilla */ + +#endif /* mozilla_Path_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/PlatformConditionVariable.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/PlatformConditionVariable.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/PlatformConditionVariable.h @@ -0,0 +1,66 @@ +/* -*- 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_ConditionVariable_h +#define mozilla_ConditionVariable_h + +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" +#include "mozilla/PlatformMutex.h" +#include "mozilla/TimeStamp.h" + +#include +#ifndef XP_WIN +#include +#endif + +namespace mozilla { + +namespace detail { + +enum class CVStatus { NoTimeout, Timeout }; + +class ConditionVariableImpl { + public: + struct PlatformData; + + MFBT_API ConditionVariableImpl(); + MFBT_API ~ConditionVariableImpl(); + + // Wake one thread that is waiting on this condition. + MFBT_API void notify_one(); + + // Wake all threads that are waiting on this condition. + MFBT_API void notify_all(); + + // Block the current thread of execution until this condition variable is + // woken from another thread via notify_one or notify_all. + MFBT_API void wait(MutexImpl& lock); + + MFBT_API CVStatus wait_for(MutexImpl& lock, + const mozilla::TimeDuration& rel_time); + + private: + ConditionVariableImpl(const ConditionVariableImpl&) = delete; + ConditionVariableImpl& operator=(const ConditionVariableImpl&) = delete; + + PlatformData* platformData(); + +#ifndef XP_WIN + void* platformData_[sizeof(pthread_cond_t) / sizeof(void*)]; + static_assert(sizeof(pthread_cond_t) / sizeof(void*) != 0 && + sizeof(pthread_cond_t) % sizeof(void*) == 0, + "pthread_cond_t must have pointer alignment"); +#else + void* platformData_[4]; +#endif +}; + +} // namespace detail + +} // namespace mozilla + +#endif // mozilla_ConditionVariable_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/PlatformMutex.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/PlatformMutex.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/PlatformMutex.h @@ -0,0 +1,62 @@ +/* -*- 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_PlatformMutex_h +#define mozilla_PlatformMutex_h + +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" + +#if !defined(XP_WIN) +#include +#endif + +namespace mozilla { + +namespace detail { + +class ConditionVariableImpl; + +class MutexImpl { + public: + struct PlatformData; + + MFBT_API MutexImpl(); + MFBT_API ~MutexImpl(); + + bool operator==(const MutexImpl& rhs) { + return platformData_ == rhs.platformData_; + } + + protected: + MFBT_API void lock(); + MFBT_API void unlock(); + + private: + MutexImpl(const MutexImpl&) = delete; + void operator=(const MutexImpl&) = delete; + MutexImpl(MutexImpl&&) = delete; + void operator=(MutexImpl&&) = delete; + + PlatformData* platformData(); + +#if !defined(XP_WIN) + void* platformData_[sizeof(pthread_mutex_t) / sizeof(void*)]; + static_assert(sizeof(pthread_mutex_t) / sizeof(void*) != 0 && + sizeof(pthread_mutex_t) % sizeof(void*) == 0, + "pthread_mutex_t must have pointer alignment"); +#else + void* platformData_[6]; +#endif + + friend class mozilla::detail::ConditionVariableImpl; +}; + +} // namespace detail + +} // namespace mozilla + +#endif // mozilla_PlatformMutex_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/PodOperations.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/PodOperations.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/PodOperations.h @@ -25,18 +25,14 @@ namespace mozilla { /** Set the contents of |aT| to 0. */ -template -static MOZ_ALWAYS_INLINE void -PodZero(T* aT) -{ +template +static MOZ_ALWAYS_INLINE void PodZero(T* aT) { memset(aT, 0, sizeof(T)); } /** Set the contents of |aNElem| elements starting at |aT| to 0. */ -template -static MOZ_ALWAYS_INLINE void -PodZero(T* aT, size_t aNElem) -{ +template +static MOZ_ALWAYS_INLINE void PodZero(T* aT, size_t aNElem) { /* * This function is often called with 'aNElem' small; we use an inline loop * instead of calling 'memset' with a non-constant length. The compiler @@ -54,23 +50,19 @@ * ambiguous overload is left to catch mistaken uses of PodZero; if you get a * compile error involving PodZero and array types, use PodArrayZero instead. */ -template +template static void PodZero(T (&aT)[N]) = delete; -template +template static void PodZero(T (&aT)[N], size_t aNElem) = delete; /** Set the contents of the array |aT| to zero. */ template -static MOZ_ALWAYS_INLINE void -PodArrayZero(T (&aT)[N]) -{ +static MOZ_ALWAYS_INLINE void PodArrayZero(T (&aT)[N]) { memset(aT, 0, N * sizeof(T)); } template -static MOZ_ALWAYS_INLINE void -PodArrayZero(Array& aArr) -{ +static MOZ_ALWAYS_INLINE void PodArrayZero(Array& aArr) { memset(&aArr[0], 0, N * sizeof(T)); } @@ -78,10 +70,8 @@ * Assign |*aSrc| to |*aDst|. The locations must not be the same and must not * overlap. */ -template -static MOZ_ALWAYS_INLINE void -PodAssign(T* aDst, const T* aSrc) -{ +template +static MOZ_ALWAYS_INLINE void PodAssign(T* aDst, const T* aSrc) { MOZ_ASSERT(aDst + 1 <= aSrc || aSrc + 1 <= aDst, "destination and source must not overlap"); memcpy(reinterpret_cast(aDst), reinterpret_cast(aSrc), @@ -92,10 +82,8 @@ * Copy |aNElem| T elements from |aSrc| to |aDst|. The two memory ranges must * not overlap! */ -template -static MOZ_ALWAYS_INLINE void -PodCopy(T* aDst, const T* aSrc, size_t aNElem) -{ +template +static MOZ_ALWAYS_INLINE void PodCopy(T* aDst, const T* aSrc, size_t aNElem) { MOZ_ASSERT(aDst + aNElem <= aSrc || aSrc + aNElem <= aDst, "destination and source must not overlap"); if (aNElem < 128) { @@ -103,7 +91,7 @@ * Avoid using operator= in this loop, as it may have been * intentionally deleted by the POD type. */ - for (const T* srcend = aSrc + aNElem; aSrc < srcend; aSrc++, aDst++) { + for (const T *srcend = aSrc + aNElem; aSrc < srcend; aSrc++, aDst++) { PodAssign(aDst, aSrc); } } else { @@ -111,10 +99,9 @@ } } -template -static MOZ_ALWAYS_INLINE void -PodCopy(volatile T* aDst, const volatile T* aSrc, size_t aNElem) -{ +template +static MOZ_ALWAYS_INLINE void PodCopy(volatile T* aDst, const volatile T* aSrc, + size_t aNElem) { MOZ_ASSERT(aDst + aNElem <= aSrc || aSrc + aNElem <= aDst, "destination and source must not overlap"); @@ -124,8 +111,7 @@ * loops manually, using operator= rather than memcpy for the same reason, * and let the compiler optimize to the extent it can. */ - for (const volatile T* srcend = aSrc + aNElem; - aSrc < srcend; + for (const volatile T *srcend = aSrc + aNElem; aSrc < srcend; aSrc++, aDst++) { *aDst = *aSrc; } @@ -136,9 +122,7 @@ * The arrays must not overlap! */ template -static MOZ_ALWAYS_INLINE void -PodArrayCopy(T (&aDst)[N], const T (&aSrc)[N]) -{ +static MOZ_ALWAYS_INLINE void PodArrayCopy(T (&aDst)[N], const T (&aSrc)[N]) { PodCopy(aDst, aSrc, N); } @@ -148,10 +132,8 @@ * first copied from |aSrc| to a temporary array, and then from the temporary * array to |aDst|. */ -template -static MOZ_ALWAYS_INLINE void -PodMove(T* aDst, const T* aSrc, size_t aNElem) -{ +template +static MOZ_ALWAYS_INLINE void PodMove(T* aDst, const T* aSrc, size_t aNElem) { MOZ_ASSERT(aNElem <= SIZE_MAX / sizeof(T), "trying to move an impossible number of elements"); memmove(aDst, aSrc, aNElem * sizeof(T)); @@ -161,10 +143,8 @@ * Determine whether the |len| elements at |one| are memory-identical to the * |len| elements at |two|. */ -template -static MOZ_ALWAYS_INLINE bool -PodEqual(const T* one, const T* two, size_t len) -{ +template +static MOZ_ALWAYS_INLINE bool PodEqual(const T* one, const T* two, size_t len) { if (len < 128) { const T* p1end = one + len; const T* p1 = one; @@ -185,12 +165,10 @@ * |N| elements at |two|. */ template -static MOZ_ALWAYS_INLINE bool -PodEqual(const T (&one)[N], const T (&two)[N]) -{ +static MOZ_ALWAYS_INLINE bool PodEqual(const T (&one)[N], const T (&two)[N]) { return PodEqual(one, two, N); } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_PodOperations_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 @@ -16,6 +16,7 @@ #include "mozilla/Types.h" #include +#include MOZ_BEGIN_EXTERN_C @@ -24,10 +25,7 @@ /** * @return the poison value. */ -inline uintptr_t mozPoisonValue() -{ - return gMozillaPoisonValue; -} +inline uintptr_t mozPoisonValue() { return gMozillaPoisonValue; } /** * Overwrite the memory block of aSize bytes at aPtr with the poison value. @@ -35,15 +33,13 @@ * Only an even number of sizeof(uintptr_t) bytes are overwritten, the last * few bytes (if any) is not overwritten. */ -inline void mozWritePoison(void* aPtr, size_t aSize) -{ +inline void mozWritePoison(void* aPtr, size_t aSize) { const uintptr_t POISON = mozPoisonValue(); char* p = (char*)aPtr; - char* limit = p + aSize; - MOZ_ASSERT((uintptr_t)aPtr % sizeof(uintptr_t) == 0, "bad alignment"); + char* limit = p + (aSize & ~(sizeof(uintptr_t) - 1)); MOZ_ASSERT(aSize >= sizeof(uintptr_t), "poisoning this object has no effect"); for (; p < limit; p += sizeof(uintptr_t)) { - *((uintptr_t*)p) = POISON; + memcpy(p, &POISON, sizeof(POISON)); } } @@ -80,10 +76,8 @@ * various uses of the corrupted memory. */ class CorruptionCanary { -public: - CorruptionCanary() { - mValue = kCanarySet; - } + public: + CorruptionCanary() { mValue = kCanarySet; } ~CorruptionCanary() { Check(); @@ -96,12 +90,12 @@ } } -private: + private: static const uintptr_t kCanarySet = 0x0f0b0f0b; uintptr_t mValue; }; -} // mozilla +} // namespace mozilla #endif Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Printf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Printf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Printf.h @@ -0,0 +1,251 @@ +/* -*- 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/. */ + +/* Printf-like functions, with canned variants that malloc their result. */ + +#ifndef mozilla_Printf_h +#define mozilla_Printf_h + +/* +** API for PR printf like routines. +** +** These exist partly for historical reasons -- initially they were in +** NSPR, then forked in tree and modified in js/ -- but now the prime +** motivation is both closer control over the exact formatting (with +** one exception, see below) and also the ability to control where +** exactly the generated results are sent. +** +** It might seem that this could all be dispensed with in favor of a +** wrapper around |vsnprintf| -- except that this implementation +** guarantees that the %s format will accept a NULL pointer, whereas +** with standard functions this is undefined. +** +** This supports the following formats. It implements a subset of the +** standard formats; due to the use of MOZ_FORMAT_PRINTF, it is not +** permissible to extend the standard, aside from relaxing undefined +** behavior. +** +** %d - decimal +** %u - unsigned decimal +** %x - unsigned hex +** %X - unsigned uppercase hex +** %o - unsigned octal +** %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). +** Note that MSVC 2015 and newer supports the z length modifier so +** users should prefer using %z instead of %I. We are supporting %I in +** addition to %z in case third-party code that uses %I gets routed to +** use this printf implementation. +** %s - string +** %S, %ls - wide string, that is wchar_t* +** %c - character +** %p - pointer (deals with machine dependent pointer size) +** %f - float; note that this is actually formatted using the +** system's native printf, and so the results may vary +** %g - float; note that this is actually formatted using the +** system's native printf, and so the results may vary +*/ + +#include "mozilla/AllocPolicy.h" +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/IntegerPrintfMacros.h" +#include "mozilla/Types.h" +#include "mozilla/UniquePtr.h" + +#include +#include + +namespace mozilla { + +/* + * This class may be subclassed to provide a way to get the output of + * a printf-like call, as the output is generated. + */ +class PrintfTarget { + public: + /* The Printf-like interface. */ + bool MFBT_API print(const char* format, ...) MOZ_FORMAT_PRINTF(2, 3); + + /* The Vprintf-like interface. */ + bool MFBT_API vprint(const char* format, va_list) MOZ_FORMAT_PRINTF(2, 0); + + protected: + MFBT_API PrintfTarget(); + virtual ~PrintfTarget() {} + + /* Subclasses override this. It is called when more output is + available. It may be called with len==0. This should return + true on success, or false on failure. */ + virtual bool append(const char* sp, size_t len) = 0; + + private: + /* Number of bytes emitted so far. */ + size_t mEmitted; + + /* The implementation calls this to emit bytes and update + mEmitted. */ + bool emit(const char* sp, size_t len) { + mEmitted += len; + return append(sp, len); + } + + bool fill2(const char* src, int srclen, int width, int flags); + bool fill_n(const char* src, int srclen, int width, int prec, int type, + int flags); + bool cvt_l(long num, int width, int prec, int radix, int type, int flags, + const char* hxp); + bool cvt_ll(int64_t num, int width, int prec, int radix, int type, int flags, + const char* hexp); + bool cvt_f(double d, const char* fmt0, const char* fmt1); + bool cvt_s(const char* s, int width, int prec, int flags); +}; + +namespace detail { + +template +struct AllocPolicyBasedFreePolicy { + void operator()(const void* ptr) { + AllocPolicy policy; + policy.free_(const_cast(ptr)); + } +}; + +} // namespace detail + +// The type returned by Smprintf and friends. +template +using SmprintfPolicyPointer = + mozilla::UniquePtr>; + +// The default type if no alloc policy is specified. +typedef SmprintfPolicyPointer SmprintfPointer; + +// Used in the implementation of Smprintf et al. +template +class MOZ_STACK_CLASS SprintfState final : private mozilla::PrintfTarget, + private AllocPolicy { + public: + explicit SprintfState(char* base) + : mMaxlen(base ? strlen(base) : 0), + mBase(base), + mCur(base ? base + mMaxlen : 0) {} + + ~SprintfState() { this->free_(mBase); } + + bool vprint(const char* format, va_list ap_list) MOZ_FORMAT_PRINTF(2, 0) { + // The "" here has a single \0 character, which is what we're + // trying to append. + return mozilla::PrintfTarget::vprint(format, ap_list) && append("", 1); + } + + SmprintfPolicyPointer release() { + SmprintfPolicyPointer result(mBase); + mBase = nullptr; + return result; + } + + protected: + bool append(const char* sp, size_t len) override { + ptrdiff_t off; + char* newbase; + size_t newlen; + + off = mCur - mBase; + if (off + len >= mMaxlen) { + /* Grow the buffer */ + newlen = mMaxlen + ((len > 32) ? len : 32); + newbase = + static_cast(this->maybe_pod_realloc(mBase, mMaxlen, newlen)); + if (!newbase) { + /* Ran out of memory */ + return false; + } + mBase = newbase; + mMaxlen = newlen; + mCur = mBase + off; + } + + /* Copy data */ + memcpy(mCur, sp, len); + mCur += len; + MOZ_ASSERT(size_t(mCur - mBase) <= mMaxlen); + return true; + } + + private: + size_t mMaxlen; + char* mBase; + char* mCur; +}; + +/* +** sprintf into a malloc'd buffer. Return a pointer to the malloc'd +** buffer on success, nullptr on failure. Call AllocPolicy::free_ to release +** the memory returned. +*/ +template +MOZ_FORMAT_PRINTF(1, 2) +SmprintfPolicyPointer Smprintf(const char* fmt, ...) { + SprintfState ss(nullptr); + va_list ap; + va_start(ap, fmt); + bool r = ss.vprint(fmt, ap); + va_end(ap); + if (!r) { + return nullptr; + } + return ss.release(); +} + +/* +** "append" sprintf into a malloc'd buffer. "last" is the last value of +** the malloc'd buffer. sprintf will append data to the end of last, +** growing it as necessary using realloc. If last is nullptr, SmprintfAppend +** 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. +*/ +template +MOZ_FORMAT_PRINTF(2, 3) +SmprintfPolicyPointer SmprintfAppend( + SmprintfPolicyPointer&& last, const char* fmt, ...) { + SprintfState ss(last.release()); + va_list ap; + va_start(ap, fmt); + bool r = ss.vprint(fmt, ap); + va_end(ap); + if (!r) { + return nullptr; + } + return ss.release(); +} + +/* +** va_list forms of the above. +*/ +template +MOZ_FORMAT_PRINTF(1, 0) +SmprintfPolicyPointer Vsmprintf(const char* fmt, va_list ap) { + SprintfState ss(nullptr); + if (!ss.vprint(fmt, ap)) return nullptr; + return ss.release(); +} + +template +MOZ_FORMAT_PRINTF(2, 0) +SmprintfPolicyPointer VsmprintfAppend( + SmprintfPolicyPointer&& last, const char* fmt, va_list ap) { + SprintfState ss(last.release()); + if (!ss.vprint(fmt, ap)) return nullptr; + return ss.release(); +} + +} // namespace mozilla + +#endif /* mozilla_Printf_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 @@ -9,6 +9,7 @@ #include "mozilla/RangedPtr.h" #include "mozilla/TypeTraits.h" +#include "mozilla/Span.h" #include @@ -16,33 +17,34 @@ // Range is a tuple containing a pointer and a length. template -class Range -{ +class Range { const RangedPtr mStart; const RangedPtr mEnd; -public: + public: Range() : mStart(nullptr, 0), mEnd(nullptr, 0) {} Range(T* aPtr, size_t aLength) - : mStart(aPtr, aPtr, aPtr + aLength), - mEnd(aPtr + aLength, aPtr, aPtr + aLength) - {} + : 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()) - { + : 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> + template ::value, int>::Type> MOZ_IMPLICIT Range(const Range& aOther) - : mStart(aOther.mStart), - mEnd(aOther.mEnd) - {} + : mStart(aOther.mStart), mEnd(aOther.mEnd) {} + + MOZ_IMPLICIT Range(Span aSpan) : Range(aSpan.Elements(), aSpan.Length()) {} + + template ::value, int>::Type> + MOZ_IMPLICIT Range(const Span& aSpan) + : Range(aSpan.Elements(), aSpan.Length()) {} RangedPtr begin() const { return mStart; } RangedPtr end() const { return mEnd; } @@ -51,8 +53,22 @@ T& operator[](size_t aOffset) const { return mStart[aOffset]; } explicit operator bool() const { return mStart != nullptr; } + + operator Span() { return Span(mStart.get(), length()); } + + operator Span() const { return Span(mStart.get(), length()); } }; -} // namespace mozilla +template +Span MakeSpan(Range& aRange) { + return aRange; +} + +template +Span MakeSpan(const Range& aRange) { + return aRange; +} + +} // namespace mozilla #endif /* mozilla_Range_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/RangedArray.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/RangedArray.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/RangedArray.h @@ -19,29 +19,26 @@ namespace mozilla { -template -class RangedArray -{ -private: +template +class RangedArray { + private: typedef Array ArrayType; ArrayType mArr; -public: - T& operator[](size_t aIndex) - { + public: + T& operator[](size_t aIndex) { MOZ_ASSERT(aIndex == MinIndex || aIndex > MinIndex); return mArr[aIndex - MinIndex]; } - const T& operator[](size_t aIndex) const - { + const T& operator[](size_t aIndex) const { MOZ_ASSERT(aIndex == MinIndex || aIndex > MinIndex); return mArr[aIndex - MinIndex]; } - typedef typename ArrayType::iterator iterator; - typedef typename ArrayType::const_iterator const_iterator; - typedef typename ArrayType::reverse_iterator reverse_iterator; + typedef typename ArrayType::iterator iterator; + typedef typename ArrayType::const_iterator const_iterator; + typedef typename ArrayType::reverse_iterator reverse_iterator; typedef typename ArrayType::const_reverse_iterator const_reverse_iterator; // Methods for range-based for loops. @@ -61,6 +58,6 @@ const_reverse_iterator crend() const { return mArr.crend(); } }; -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_RangedArray_h +#endif // mozilla_RangedArray_h 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 @@ -39,9 +39,8 @@ * explicitly convert to T*. Keep in mind that the raw pointer of course won't * implement bounds checking in debug builds. */ -template -class RangedPtr -{ +template +class RangedPtr { T* mPtr; #ifdef DEBUG @@ -49,15 +48,13 @@ T* const mRangeEnd; #endif - void checkSanity() - { + void checkSanity() { MOZ_ASSERT(mRangeStart <= mPtr); MOZ_ASSERT(mPtr <= mRangeEnd); } /* Creates a new pointer for |aPtr|, restricted to this pointer's range. */ - RangedPtr create(T* aPtr) const - { + RangedPtr create(T* aPtr) const { #ifdef DEBUG return RangedPtr(aPtr, mRangeStart, mRangeEnd); #else @@ -67,20 +64,24 @@ uintptr_t asUintptr() const { return reinterpret_cast(mPtr); } -public: + public: RangedPtr(T* aPtr, T* aStart, T* aEnd) - : mPtr(aPtr) + : mPtr(aPtr) #ifdef DEBUG - , mRangeStart(aStart), mRangeEnd(aEnd) + , + mRangeStart(aStart), + mRangeEnd(aEnd) #endif { MOZ_ASSERT(mRangeStart <= mRangeEnd); checkSanity(); } RangedPtr(T* aPtr, T* aStart, size_t aLength) - : mPtr(aPtr) + : mPtr(aPtr) #ifdef DEBUG - , mRangeStart(aStart), mRangeEnd(aStart + aLength) + , + mRangeStart(aStart), + mRangeEnd(aStart + aLength) #endif { MOZ_ASSERT(aLength <= size_t(-1) / sizeof(T)); @@ -91,9 +92,11 @@ /* Equivalent to RangedPtr(aPtr, aPtr, aLength). */ RangedPtr(T* aPtr, size_t aLength) - : mPtr(aPtr) + : mPtr(aPtr) #ifdef DEBUG - , mRangeStart(aPtr), mRangeEnd(aPtr + aLength) + , + mRangeStart(aPtr), + mRangeEnd(aPtr + aLength) #endif { MOZ_ASSERT(aLength <= size_t(-1) / sizeof(T)); @@ -103,11 +106,13 @@ } /* Equivalent to RangedPtr(aArr, aArr, N). */ - template + template explicit RangedPtr(T (&aArr)[N]) - : mPtr(aArr) + : mPtr(aArr) #ifdef DEBUG - , mRangeStart(aArr), mRangeEnd(aArr + N) + , + mRangeStart(aArr), + mRangeEnd(aArr + N) #endif { checkSanity(); @@ -117,8 +122,7 @@ explicit operator bool() const { return mPtr != nullptr; } - void checkIdenticalRange(const RangedPtr& aOther) const - { + void checkIdenticalRange(const RangedPtr& aOther) const { MOZ_ASSERT(mRangeStart == aOther.mRangeStart); MOZ_ASSERT(mRangeEnd == aOther.mRangeEnd); } @@ -133,23 +137,20 @@ * p1 = RangedPtr(arr1 + 1, arr1, arr1 + 2); // works * p1 = RangedPtr(arr2, 3); // asserts */ - RangedPtr& operator=(const RangedPtr& aOther) - { + RangedPtr& operator=(const RangedPtr& aOther) { checkIdenticalRange(aOther); mPtr = aOther.mPtr; checkSanity(); return *this; } - RangedPtr operator+(size_t aInc) const - { + 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) const - { + RangedPtr operator-(size_t aDec) const { MOZ_ASSERT(aDec <= size_t(-1) / sizeof(T)); MOZ_ASSERT(asUintptr() - aDec * sizeof(T) <= asUintptr()); return create(mPtr - aDec); @@ -160,15 +161,13 @@ * within the range specified at creation. */ template - RangedPtr& operator=(U* aPtr) - { + RangedPtr& operator=(U* aPtr) { *this = create(aPtr); return *this; } template - RangedPtr& operator=(const RangedPtr& aPtr) - { + RangedPtr& operator=(const RangedPtr& aPtr) { MOZ_ASSERT(mRangeStart <= aPtr.mPtr); MOZ_ASSERT(aPtr.mPtr <= mRangeEnd); mPtr = aPtr.mPtr; @@ -176,115 +175,92 @@ return *this; } - RangedPtr& operator++() - { - return (*this += 1); - } + RangedPtr& operator++() { return (*this += 1); } - RangedPtr operator++(int) - { + RangedPtr operator++(int) { RangedPtr rcp = *this; ++*this; return rcp; } - RangedPtr& operator--() - { - return (*this -= 1); - } + RangedPtr& operator--() { return (*this -= 1); } - RangedPtr operator--(int) - { + RangedPtr operator--(int) { RangedPtr rcp = *this; --*this; return rcp; } - RangedPtr& operator+=(size_t aInc) - { + RangedPtr& operator+=(size_t aInc) { *this = *this + aInc; return *this; } - RangedPtr& operator-=(size_t aDec) - { + RangedPtr& operator-=(size_t aDec) { *this = *this - aDec; return *this; } - T& operator[](int aIndex) const - { + T& operator[](ptrdiff_t aIndex) const { MOZ_ASSERT(size_t(aIndex > 0 ? aIndex : -aIndex) <= size_t(-1) / sizeof(T)); return *create(mPtr + aIndex); } - T& operator*() const - { + T& operator*() const { MOZ_ASSERT(mPtr >= mRangeStart); MOZ_ASSERT(mPtr < mRangeEnd); return *mPtr; } - T* operator->() const - { + T* operator->() const { MOZ_ASSERT(mPtr >= mRangeStart); MOZ_ASSERT(mPtr < mRangeEnd); return mPtr; } template - bool operator==(const RangedPtr& aOther) const - { + bool operator==(const RangedPtr& aOther) const { return mPtr == aOther.mPtr; } template - bool operator!=(const RangedPtr& aOther) const - { + bool operator!=(const RangedPtr& aOther) const { return !(*this == aOther); } - template - bool operator==(const U* u) const - { + template + bool operator==(const U* u) const { return mPtr == u; } - template - bool operator!=(const U* u) const - { + template + bool operator!=(const U* u) const { return !(*this == u); } template - bool operator<(const RangedPtr& aOther) const - { + bool operator<(const RangedPtr& aOther) const { return mPtr < aOther.mPtr; } template - bool operator<=(const RangedPtr& aOther) const - { + bool operator<=(const RangedPtr& aOther) const { return mPtr <= aOther.mPtr; } template - bool operator>(const RangedPtr& aOther) const - { + bool operator>(const RangedPtr& aOther) const { return mPtr > aOther.mPtr; } template - bool operator>=(const RangedPtr& aOther) const - { + bool operator>=(const RangedPtr& aOther) const { return mPtr >= aOther.mPtr; } - size_t operator-(const RangedPtr& aOther) const - { + size_t operator-(const RangedPtr& aOther) const { MOZ_ASSERT(mPtr >= aOther.mPtr); return PointerRangeSize(aOther.mPtr, mPtr); } -private: + private: RangedPtr() = delete; - T* operator&() = delete; }; } /* namespace mozilla */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ReentrancyGuard.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ReentrancyGuard.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ReentrancyGuard.h @@ -16,22 +16,19 @@ namespace mozilla { /* Useful for implementing containers that assert non-reentrancy */ -class MOZ_RAII ReentrancyGuard -{ +class MOZ_RAII ReentrancyGuard { MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER #ifdef DEBUG bool& mEntered; #endif -public: - template + public: + template #ifdef DEBUG - explicit ReentrancyGuard(T& aObj - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mEntered(aObj.mEntered) + explicit ReentrancyGuard(T& aObj MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mEntered(aObj.mEntered) #else - explicit ReentrancyGuard(T& - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + explicit ReentrancyGuard(T& MOZ_GUARD_OBJECT_NOTIFIER_PARAM) #endif { MOZ_GUARD_OBJECT_NOTIFIER_INIT; @@ -40,18 +37,17 @@ mEntered = true; #endif } - ~ReentrancyGuard() - { + ~ReentrancyGuard() { #ifdef DEBUG mEntered = false; #endif } -private: + private: ReentrancyGuard(const ReentrancyGuard&) = delete; void operator=(const ReentrancyGuard&) = delete; }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_ReentrancyGuard_h */ 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 @@ -17,6 +17,8 @@ #include "mozilla/RefCountType.h" #include "mozilla/TypeTraits.h" +#include + #if defined(MOZILLA_INTERNAL_API) #include "nsXPCOM.h" #endif @@ -52,6 +54,9 @@ * Note that when deriving from RefCounted or AtomicRefCounted, you * should add MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public * section of your class, where ClassName is the name of your class. + * + * Note: SpiderMonkey should use js::RefCounted instead since that type + * will use appropriate js_delete and also not break ref-count logging. */ namespace detail { const MozRefCountType DEAD = 0xffffdead; @@ -59,20 +64,17 @@ // When building code that gets compiled into Gecko, try to use the // trace-refcount leak logging facilities. #ifdef MOZ_REFCOUNTED_LEAK_CHECKING -class RefCountLogger -{ -public: +class RefCountLogger { + public: static void logAddRef(const void* aPointer, MozRefCountType aRefCount, - const char* aTypeName, uint32_t aInstanceSize) - { + const char* aTypeName, uint32_t aInstanceSize) { MOZ_ASSERT(aRefCount != DEAD); NS_LogAddRef(const_cast(aPointer), aRefCount, aTypeName, aInstanceSize); } static void logRelease(const void* aPointer, MozRefCountType aRefCount, - const char* aTypeName) - { + const char* aTypeName) { MOZ_ASSERT(aRefCount != DEAD); NS_LogRelease(const_cast(aPointer), aRefCount, aTypeName); } @@ -80,23 +82,82 @@ #endif // This is used WeakPtr.h as well as this file. -enum RefCountAtomicity -{ - AtomicRefCount, - NonAtomicRefCount +enum RefCountAtomicity { AtomicRefCount, NonAtomicRefCount }; + +template +class RC { + public: + explicit RC(T aCount) : mValue(aCount) {} + + T operator++() { return ++mValue; } + T operator--() { return --mValue; } + + void operator=(const T& aValue) { mValue = aValue; } + + operator T() const { return mValue; } + + private: + T mValue; +}; + +template +class RC { + public: + explicit RC(T aCount) : mValue(aCount) {} + + T operator++() { + // Memory synchronization is not required when incrementing a + // reference count. The first increment of a reference count on a + // thread is not important, since the first use of the object on a + // thread can happen before it. What is important is the transfer + // of the pointer to that thread, which may happen prior to the + // first increment on that thread. The necessary memory + // synchronization is done by the mechanism that transfers the + // pointer between threads. + return mValue.fetch_add(1, std::memory_order_relaxed) + 1; + } + + T operator--() { + // Since this may be the last release on this thread, we need + // release semantics so that prior writes on this thread are visible + // to the thread that destroys the object when it reads mValue with + // acquire semantics. + T result = mValue.fetch_sub(1, std::memory_order_release) - 1; + if (result == 0) { + // We're going to destroy the object on this thread, so we need + // acquire semantics to synchronize with the memory released by + // the last release on other threads, that is, to ensure that + // writes prior to that release are now visible on this thread. + std::atomic_thread_fence(std::memory_order_acquire); + } + return result; + } + + // This method is only called in debug builds, so we're not too concerned + // about its performance. + void operator=(const T& aValue) { + mValue.store(aValue, std::memory_order_seq_cst); + } + + operator T() const { + // Use acquire semantics since we're not sure what the caller is + // doing. + return mValue.load(std::memory_order_acquire); + } + + private: + std::atomic mValue; }; -template -class RefCounted -{ -protected: +template +class RefCounted { + protected: RefCounted() : mRefCnt(0) {} ~RefCounted() { MOZ_ASSERT(mRefCnt == detail::DEAD); } -public: + public: // Compatibility with nsRefPtr. - void AddRef() const - { + void AddRef() const { // Note: this method must be thread safe for AtomicRefCounted. MOZ_ASSERT(int32_t(mRefCnt) >= 0); #ifndef MOZ_REFCOUNTED_LEAK_CHECKING @@ -110,8 +171,7 @@ #endif } - void Release() const - { + void Release() const { // Note: this method must be thread safe for AtomicRefCounted. MOZ_ASSERT(int32_t(mRefCnt) > 0); #ifndef MOZ_REFCOUNTED_LEAK_CHECKING @@ -125,10 +185,10 @@ detail::RefCountLogger::logRelease(ptr, cnt, type); #endif if (0 == cnt) { - // Because we have atomically decremented the refcount above, only - // one thread can get a 0 count here, so as long as we can assume that - // everything else in the system is accessing this object through - // RefPtrs, it's safe to access |this| here. + // Because we have atomically decremented the refcount above, only + // one thread can get a 0 count here, so as long as we can assume that + // everything else in the system is accessing this object through + // RefPtrs, it's safe to access |this| here. #ifdef DEBUG mRefCnt = detail::DEAD; #endif @@ -140,22 +200,19 @@ void ref() { AddRef(); } void deref() { Release(); } MozRefCountType refCount() const { return mRefCnt; } - bool hasOneRef() const - { + bool hasOneRef() const { MOZ_ASSERT(mRefCnt > 0); return mRefCnt == 1; } -private: - mutable typename Conditional, - MozRefCountType>::Type mRefCnt; + private: + mutable RC mRefCnt; }; #ifdef MOZ_REFCOUNTED_LEAK_CHECKING // Passing override for the optional argument marks the typeName and // typeSize functions defined by this macro as overrides. -#define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T, ...) \ +#define MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(T, ...) \ virtual const char* typeName() const __VA_ARGS__ { return #T; } \ virtual size_t typeSize() const __VA_ARGS__ { return sizeof(*this); } #else @@ -165,18 +222,16 @@ // Note that this macro is expanded unconditionally because it declares only // two small inline functions which will hopefully get eliminated by the linker // in non-leak-checking builds. -#define MOZ_DECLARE_REFCOUNTED_TYPENAME(T) \ +#define MOZ_DECLARE_REFCOUNTED_TYPENAME(T) \ const char* typeName() const { return #T; } \ size_t typeSize() const { return sizeof(*this); } -} // namespace detail +} // namespace detail -template -class RefCounted : public detail::RefCounted -{ -public: - ~RefCounted() - { +template +class RefCounted : public detail::RefCounted { + public: + ~RefCounted() { static_assert(IsBaseOf::value, "T must derive from RefCounted"); } @@ -191,20 +246,18 @@ * NOTE: Please do not use this class, use NS_INLINE_DECL_THREADSAFE_REFCOUNTING * instead. */ -template -class AtomicRefCounted : - public mozilla::detail::RefCounted -{ -public: - ~AtomicRefCounted() - { +template +class AtomicRefCounted + : public mozilla::detail::RefCounted { + public: + ~AtomicRefCounted() { static_assert(IsBaseOf::value, "T must derive from AtomicRefCounted"); } }; -} // namespace external +} // namespace external -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_RefCounted_h +#endif // mozilla_RefCounted_h 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 @@ -15,11 +15,14 @@ // template class RefPtrGetterAddRefs; +class nsQueryReferent; class nsCOMPtr_helper; namespace mozilla { -template class OwningNonNull; -template class StaticRefPtr; +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. @@ -30,35 +33,25 @@ // // 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(); - } +template +struct RefPtrTraits { + static void AddRef(U* aPtr) { aPtr->AddRef(); } + static void Release(U* aPtr) { aPtr->Release(); } }; -} // namespace mozilla +} // namespace mozilla template -class RefPtr -{ -private: - void - assign_with_AddRef(T* aRawPtr) - { +class MOZ_IS_REFPTR RefPtr { + private: + void assign_with_AddRef(T* aRawPtr) { if (aRawPtr) { ConstRemovingRefPtrTraits::AddRef(aRawPtr); } assign_assuming_AddRef(aRawPtr); } - void - assign_assuming_AddRef(T* aNewPtr) - { + void assign_assuming_AddRef(T* aNewPtr) { T* oldPtr = mRawPtr; mRawPtr = aNewPtr; if (oldPtr) { @@ -66,14 +59,13 @@ } } -private: + private: T* MOZ_OWNING_REF mRawPtr; -public: + public: typedef T element_type; - ~RefPtr() - { + ~RefPtr() { if (mRawPtr) { ConstRemovingRefPtrTraits::Release(mRawPtr); } @@ -82,59 +74,49 @@ // Constructors RefPtr() - : mRawPtr(nullptr) - // default constructor - { - } + : mRawPtr(nullptr) + // default constructor + {} RefPtr(const RefPtr& aSmartPtr) - : mRawPtr(aSmartPtr.mRawPtr) - // copy-constructor + : mRawPtr(aSmartPtr.mRawPtr) + // copy-constructor { if (mRawPtr) { ConstRemovingRefPtrTraits::AddRef(mRawPtr); } } - RefPtr(RefPtr&& aRefPtr) - : mRawPtr(aRefPtr.mRawPtr) - { + RefPtr(RefPtr&& aRefPtr) : mRawPtr(aRefPtr.mRawPtr) { aRefPtr.mRawPtr = nullptr; } // construct from a raw pointer (of the right type) - MOZ_IMPLICIT RefPtr(T* aRawPtr) - : mRawPtr(aRawPtr) - { + MOZ_IMPLICIT RefPtr(T* aRawPtr) : mRawPtr(aRawPtr) { if (mRawPtr) { ConstRemovingRefPtrTraits::AddRef(mRawPtr); } } - MOZ_IMPLICIT RefPtr(decltype(nullptr)) - : mRawPtr(nullptr) - { - } + MOZ_IMPLICIT RefPtr(decltype(nullptr)) : mRawPtr(nullptr) {} template MOZ_IMPLICIT RefPtr(already_AddRefed& aSmartPtr) - : mRawPtr(aSmartPtr.take()) - // construct from |already_AddRefed| - { - } + : mRawPtr(aSmartPtr.take()) + // construct from |already_AddRefed| + {} template MOZ_IMPLICIT RefPtr(already_AddRefed&& aSmartPtr) - : mRawPtr(aSmartPtr.take()) - // construct from |otherRefPtr.forget()| - { - } + : mRawPtr(aSmartPtr.take()) + // construct from |otherRefPtr.forget()| + {} template MOZ_IMPLICIT RefPtr(const RefPtr& aSmartPtr) - : mRawPtr(aSmartPtr.get()) - // copy-construct from a smart pointer with a related pointer type + : mRawPtr(aSmartPtr.get()) + // copy-construct from a smart pointer with a related pointer type { if (mRawPtr) { ConstRemovingRefPtrTraits::AddRef(mRawPtr); @@ -143,32 +125,29 @@ template MOZ_IMPLICIT RefPtr(RefPtr&& aSmartPtr) - : mRawPtr(aSmartPtr.forget().take()) - // construct from |Move(RefPtr)|. - { - } + : mRawPtr(aSmartPtr.forget().take()) + // construct from |Move(RefPtr)|. + {} + MOZ_IMPLICIT RefPtr(const nsQueryReferent& aHelper); MOZ_IMPLICIT RefPtr(const nsCOMPtr_helper& aHelper); // Defined in OwningNonNull.h - template + template MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull& aOther); // Defined in StaticPtr.h - template + template MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr& aOther); // Assignment operators - RefPtr& - operator=(decltype(nullptr)) - { + RefPtr& operator=(decltype(nullptr)) { assign_assuming_AddRef(nullptr); return *this; } - RefPtr& - operator=(const RefPtr& aRhs) + RefPtr& operator=(const RefPtr& aRhs) // copy assignment operator { assign_with_AddRef(aRhs.mRawPtr); @@ -176,16 +155,14 @@ } template - RefPtr& - operator=(const RefPtr& aRhs) + RefPtr& operator=(const RefPtr& aRhs) // assign from an RefPtr of a related pointer type { assign_with_AddRef(aRhs.get()); return *this; } - RefPtr& - operator=(T* aRhs) + RefPtr& operator=(T* aRhs) // assign from a raw pointer (of the right type) { assign_with_AddRef(aRhs); @@ -193,8 +170,7 @@ } template - RefPtr& - operator=(already_AddRefed& aRhs) + RefPtr& operator=(already_AddRefed& aRhs) // assign from |already_AddRefed| { assign_assuming_AddRef(aRhs.take()); @@ -202,38 +178,33 @@ } template - RefPtr& - operator=(already_AddRefed && aRhs) + RefPtr& operator=(already_AddRefed&& aRhs) // assign from |otherRefPtr.forget()| { assign_assuming_AddRef(aRhs.take()); return *this; } + RefPtr& operator=(const nsQueryReferent& aQueryReferent); RefPtr& operator=(const nsCOMPtr_helper& aHelper); - RefPtr& - operator=(RefPtr && aRefPtr) - { + RefPtr& operator=(RefPtr&& aRefPtr) { assign_assuming_AddRef(aRefPtr.mRawPtr); aRefPtr.mRawPtr = nullptr; return *this; } // Defined in OwningNonNull.h - template - RefPtr& - operator=(const mozilla::OwningNonNull& aOther); + template + RefPtr& operator=(const mozilla::OwningNonNull& aOther); // Defined in StaticPtr.h - template - RefPtr& - operator=(const mozilla::StaticRefPtr& aOther); + template + RefPtr& operator=(const mozilla::StaticRefPtr& aOther); // Other pointer operators - void - swap(RefPtr& aRhs) + void swap(RefPtr& aRhs) // ...exchange ownership with |aRhs|; can save a pair of refcount operations { T* temp = aRhs.mRawPtr; @@ -241,8 +212,7 @@ mRawPtr = temp; } - void - swap(T*& aRhs) + void swap(T*& aRhs) // ...exchange ownership with |aRhs|; can save a pair of refcount operations { T* temp = aRhs; @@ -250,8 +220,7 @@ mRawPtr = temp; } - already_AddRefed - forget() + already_AddRefed MOZ_MAY_CALL_AFTER_MUST_RETURN forget() // return the value of mRawPtr and null out mRawPtr. Useful for // already_AddRefed return values. { @@ -261,8 +230,7 @@ } template - void - forget(I** aRhs) + void forget(I** aRhs) // Set the target of aRhs to the value of mRawPtr and null out mRawPtr. // Useful to avoid unnecessary AddRef/Release pairs with "out" // parameters where aRhs bay be a T** or an I** where I is a base class @@ -273,20 +241,16 @@ mRawPtr = nullptr; } - T* - get() const + T* get() const /* - Prefer the implicit conversion provided automatically by |operator T*() const|. - Use |get()| to resolve ambiguity or to get a castable pointer. + Prefer the implicit conversion provided automatically by |operator T*() + const|. Use |get()| to resolve ambiguity or to get a castable pointer. */ { return const_cast(mRawPtr); } - operator T*() const -#ifdef MOZ_HAVE_REF_QUALIFIERS - & -#endif + operator T*() const & /* ...makes an |RefPtr| act like its underlying raw pointer type whenever it is used in a context where a raw pointer is expected. It is this operator @@ -299,7 +263,6 @@ return get(); } -#ifdef MOZ_HAVE_REF_QUALIFIERS // Don't allow implicit conversion of temporary RefPtr to raw pointer, // because the refcount might be one and the pointer will immediately become // invalid. @@ -310,75 +273,62 @@ // operator bool instead of the deleted operator T*? explicit operator bool() const { return !!mRawPtr; } bool operator!() const { return !mRawPtr; } -#endif - T* - operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN - { + T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL RefPtr with operator->()."); return get(); } template - class Proxy - { + class Proxy { typedef R (T::*member_function)(Args...); T* mRawPtr; member_function mFunction; - public: + + public: Proxy(T* aRawPtr, member_function aFunction) - : mRawPtr(aRawPtr), - mFunction(aFunction) - { - } - template - R operator()(ActualArgs&&... aArgs) - { + : mRawPtr(aRawPtr), mFunction(aFunction) {} + template + R operator()(ActualArgs&&... aArgs) { return ((*mRawPtr).*mFunction)(mozilla::Forward(aArgs)...); } }; template - Proxy operator->*(R (T::*aFptr)(Args...)) const - { + Proxy operator->*(R (T::*aFptr)(Args...)) const { MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL RefPtr with operator->*()."); return Proxy(get(), aFptr); } - RefPtr* - get_address() + RefPtr* get_address() // This is not intended to be used by clients. See |address_of| // below. { return this; } - const RefPtr* - get_address() const + const RefPtr* get_address() const // This is not intended to be used by clients. See |address_of| // below. { return this; } -public: - T& - operator*() const - { + public: + T& operator*() const { MOZ_ASSERT(mRawPtr != nullptr, "You can't dereference a NULL RefPtr with operator*()."); return *get(); } - T** - StartAssignment() - { + T** StartAssignment() { assign_assuming_AddRef(nullptr); return reinterpret_cast(&mRawPtr); } -private: + + private: // This helper class makes |RefPtr| possible by casting away // the constness from the pointer when calling AddRef() and Release(). // @@ -389,19 +339,13 @@ // 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). - template - struct ConstRemovingRefPtrTraits - { - static void AddRef(U* aPtr) { - mozilla::RefPtrTraits::AddRef(aPtr); - } - static void Release(U* aPtr) { - mozilla::RefPtrTraits::Release(aPtr); - } + template + struct ConstRemovingRefPtrTraits { + static void AddRef(U* aPtr) { mozilla::RefPtrTraits::AddRef(aPtr); } + static void Release(U* aPtr) { mozilla::RefPtrTraits::Release(aPtr); } }; - template - struct ConstRemovingRefPtrTraits - { + template + struct ConstRemovingRefPtrTraits { static void AddRef(const U* aPtr) { mozilla::RefPtrTraits::AddRef(const_cast(aPtr)); } @@ -413,38 +357,28 @@ class nsCycleCollectionTraversalCallback; template -void -CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback, - T* aChild, const char* aName, uint32_t aFlags); +void CycleCollectionNoteChild(nsCycleCollectionTraversalCallback& aCallback, + T* aChild, const char* aName, uint32_t aFlags); template -inline void -ImplCycleCollectionUnlink(RefPtr& aField) -{ +inline void ImplCycleCollectionUnlink(RefPtr& aField) { aField = nullptr; } template -inline void -ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, - RefPtr& aField, - const char* aName, - uint32_t aFlags = 0) -{ +inline void ImplCycleCollectionTraverse( + nsCycleCollectionTraversalCallback& aCallback, RefPtr& aField, + const char* aName, uint32_t aFlags = 0) { CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags); } template -inline RefPtr* -address_of(RefPtr& aPtr) -{ +inline RefPtr* address_of(RefPtr& aPtr) { return aPtr.get_address(); } template -inline const RefPtr* -address_of(const RefPtr& aPtr) -{ +inline const RefPtr* address_of(const RefPtr& aPtr) { return aPtr.get_address(); } @@ -468,37 +402,26 @@ This type should be a nested class inside |RefPtr|. */ { -public: - explicit - RefPtrGetterAddRefs(RefPtr& aSmartPtr) - : mTargetSmartPtr(aSmartPtr) - { + public: + explicit RefPtrGetterAddRefs(RefPtr& aSmartPtr) + : mTargetSmartPtr(aSmartPtr) { // nothing else to do } - operator void**() - { + operator void**() { return reinterpret_cast(mTargetSmartPtr.StartAssignment()); } - operator T**() - { - return mTargetSmartPtr.StartAssignment(); - } + operator T**() { return mTargetSmartPtr.StartAssignment(); } - T*& - operator*() - { - return *(mTargetSmartPtr.StartAssignment()); - } + T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); } -private: + private: RefPtr& mTargetSmartPtr; }; template -inline RefPtrGetterAddRefs -getter_AddRefs(RefPtr& aSmartPtr) +inline RefPtrGetterAddRefs getter_AddRefs(RefPtr& aSmartPtr) /* Used around a |RefPtr| when ...makes the class |RefPtrGetterAddRefs| invisible. @@ -507,127 +430,92 @@ return RefPtrGetterAddRefs(aSmartPtr); } - // Comparing two |RefPtr|s template -inline bool -operator==(const RefPtr& aLhs, const RefPtr& aRhs) -{ +inline bool operator==(const RefPtr& aLhs, const RefPtr& aRhs) { return static_cast(aLhs.get()) == static_cast(aRhs.get()); } - template -inline bool -operator!=(const RefPtr& aLhs, const RefPtr& aRhs) -{ +inline bool operator!=(const RefPtr& aLhs, const RefPtr& aRhs) { return static_cast(aLhs.get()) != static_cast(aRhs.get()); } - // Comparing an |RefPtr| to a raw pointer template -inline bool -operator==(const RefPtr& aLhs, const U* aRhs) -{ +inline bool operator==(const RefPtr& aLhs, const U* aRhs) { return static_cast(aLhs.get()) == static_cast(aRhs); } template -inline bool -operator==(const U* aLhs, const RefPtr& aRhs) -{ +inline bool operator==(const U* aLhs, const RefPtr& aRhs) { return static_cast(aLhs) == static_cast(aRhs.get()); } template -inline bool -operator!=(const RefPtr& aLhs, const U* aRhs) -{ +inline bool operator!=(const RefPtr& aLhs, const U* aRhs) { return static_cast(aLhs.get()) != static_cast(aRhs); } template -inline bool -operator!=(const U* aLhs, const RefPtr& aRhs) -{ +inline bool operator!=(const U* aLhs, const RefPtr& aRhs) { return static_cast(aLhs) != static_cast(aRhs.get()); } template -inline bool -operator==(const RefPtr& aLhs, U* aRhs) -{ +inline bool operator==(const RefPtr& aLhs, U* aRhs) { return static_cast(aLhs.get()) == const_cast(aRhs); } template -inline bool -operator==(U* aLhs, const RefPtr& aRhs) -{ +inline bool operator==(U* aLhs, const RefPtr& aRhs) { return const_cast(aLhs) == static_cast(aRhs.get()); } template -inline bool -operator!=(const RefPtr& aLhs, U* aRhs) -{ +inline bool operator!=(const RefPtr& aLhs, U* aRhs) { return static_cast(aLhs.get()) != const_cast(aRhs); } template -inline bool -operator!=(U* aLhs, const RefPtr& aRhs) -{ +inline bool operator!=(U* aLhs, const RefPtr& aRhs) { return const_cast(aLhs) != static_cast(aRhs.get()); } // Comparing an |RefPtr| to |nullptr| template -inline bool -operator==(const RefPtr& aLhs, decltype(nullptr)) -{ +inline bool operator==(const RefPtr& aLhs, decltype(nullptr)) { return aLhs.get() == nullptr; } template -inline bool -operator==(decltype(nullptr), const RefPtr& aRhs) -{ +inline bool operator==(decltype(nullptr), const RefPtr& aRhs) { return nullptr == aRhs.get(); } template -inline bool -operator!=(const RefPtr& aLhs, decltype(nullptr)) -{ +inline bool operator!=(const RefPtr& aLhs, decltype(nullptr)) { return aLhs.get() != nullptr; } template -inline bool -operator!=(decltype(nullptr), const RefPtr& aRhs) -{ +inline bool operator!=(decltype(nullptr), const RefPtr& aRhs) { return nullptr != aRhs.get(); } /*****************************************************************************/ template -inline already_AddRefed -do_AddRef(T* aObj) -{ +inline already_AddRefed do_AddRef(T* aObj) { RefPtr ref(aObj); return ref.forget(); } template -inline already_AddRefed -do_AddRef(const RefPtr& aObj) -{ +inline already_AddRefed do_AddRef(const RefPtr& aObj) { RefPtr ref(aObj); return ref.forget(); } @@ -643,14 +531,25 @@ * return MakeAndAddRef(...); * } */ -template -already_AddRefed -MakeAndAddRef(Args&&... aArgs) -{ +template +already_AddRefed MakeAndAddRef(Args&&... aArgs) { RefPtr p(new T(Forward(aArgs)...)); return p.forget(); } -} // namespace mozilla +/** + * Helper function to be able to conveniently write things like: + * + * auto runnable = + * MakeRefPtr>( + * mOnSuccess, mOnFailure, *error, mWindowID); + */ +template +RefPtr MakeRefPtr(Args&&... aArgs) { + RefPtr p(new T(Forward(aArgs)...)); + return p; +} + +} // namespace mozilla #endif /* mozilla_RefPtr_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Result.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Result.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Result.h @@ -0,0 +1,463 @@ +/* -*- 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/. */ + +/* A type suitable for returning either a value or an error from a function. */ + +#ifndef mozilla_Result_h +#define mozilla_Result_h + +#include "mozilla/Alignment.h" +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Types.h" +#include "mozilla/TypeTraits.h" +#include "mozilla/Variant.h" + +namespace mozilla { + +/** + * Empty struct, indicating success for operations that have no return value. + * For example, if you declare another empty struct `struct OutOfMemory {};`, + * then `Result` represents either success or OOM. + */ +struct Ok {}; + +template +class GenericErrorResult; +template +class Result; + +namespace detail { + +enum class PackingStrategy { + Variant, + NullIsOk, + LowBitTagIsError, + PackedVariant, +}; + +template +class ResultImplementation; + +template +class ResultImplementation { + mozilla::Variant mStorage; + + public: + explicit ResultImplementation(V aValue) : mStorage(aValue) {} + explicit ResultImplementation(E aErrorValue) : mStorage(aErrorValue) {} + + bool isOk() const { return mStorage.template is(); } + + // The callers of these functions will assert isOk() has the proper value, so + // these functions (in all ResultImplementation specializations) don't need + // to do so. + V unwrap() const { return mStorage.template as(); } + E unwrapErr() const { return mStorage.template as(); } +}; + +/** + * mozilla::Variant doesn't like storing a reference. This is a specialization + * to store E as pointer if it's a reference. + */ +template +class ResultImplementation { + mozilla::Variant mStorage; + + public: + explicit ResultImplementation(V aValue) : mStorage(aValue) {} + explicit ResultImplementation(E& aErrorValue) : mStorage(&aErrorValue) {} + + bool isOk() const { return mStorage.template is(); } + V unwrap() const { return mStorage.template as(); } + E& unwrapErr() const { return *mStorage.template as(); } +}; + +/** + * Specialization for when the success type is Ok (or another empty class) and + * the error type is a reference. + */ +template +class ResultImplementation { + E* mErrorValue; + + public: + explicit ResultImplementation(V) : mErrorValue(nullptr) {} + explicit ResultImplementation(E& aErrorValue) : mErrorValue(&aErrorValue) {} + + bool isOk() const { return mErrorValue == nullptr; } + + V unwrap() const { return V(); } + E& unwrapErr() const { return *mErrorValue; } +}; + +/** + * Specialization for when the success type is Ok (or another empty class) and + * the error type is a value type which can never have the value 0 (as + * determined by UnusedZero<>). + */ +template +class ResultImplementation { + static constexpr E NullValue = E(0); + + E mErrorValue; + + public: + explicit ResultImplementation(V) : mErrorValue(NullValue) {} + explicit ResultImplementation(E aErrorValue) : mErrorValue(aErrorValue) { + MOZ_ASSERT(aErrorValue != NullValue); + } + + bool isOk() const { return mErrorValue == NullValue; } + + V unwrap() const { return V(); } + E unwrapErr() const { return mErrorValue; } +}; + +/** + * Specialization for when alignment permits using the least significant bit as + * a tag bit. + */ +template +class ResultImplementation { + uintptr_t mBits; + + public: + explicit ResultImplementation(V* aValue) + : mBits(reinterpret_cast(aValue)) { + MOZ_ASSERT((uintptr_t(aValue) % MOZ_ALIGNOF(V)) == 0, + "Result value pointers must not be misaligned"); + } + explicit ResultImplementation(E& aErrorValue) + : mBits(reinterpret_cast(&aErrorValue) | 1) { + MOZ_ASSERT((uintptr_t(&aErrorValue) % MOZ_ALIGNOF(E)) == 0, + "Result errors must not be misaligned"); + } + + bool isOk() const { return (mBits & 1) == 0; } + + V* unwrap() const { return reinterpret_cast(mBits); } + E& unwrapErr() const { return *reinterpret_cast(mBits ^ 1); } +}; + +// Return true if any of the struct can fit in a word. +template +struct IsPackableVariant { + struct VEbool { + V v; + E e; + bool ok; + }; + struct EVbool { + E e; + V v; + bool ok; + }; + + using Impl = typename Conditional::Type; + + static const bool value = sizeof(Impl) <= sizeof(uintptr_t); +}; + +/** + * Specialization for when both type are not using all the bytes, in order to + * use one byte as a tag. + */ +template +class ResultImplementation { + using Impl = typename IsPackableVariant::Impl; + Impl data; + + public: + explicit ResultImplementation(V aValue) { + data.v = aValue; + data.ok = true; + } + explicit ResultImplementation(E aErrorValue) { + data.e = aErrorValue; + data.ok = false; + } + + bool isOk() const { return data.ok; } + + V unwrap() const { return data.v; } + E unwrapErr() const { return data.e; } +}; + +// To use nullptr as a special value, we need the counter part to exclude zero +// from its range of valid representations. +// +// By default assume that zero can be represented. +template +struct UnusedZero { + static const bool value = false; +}; + +// References can't be null. +template +struct UnusedZero { + static const bool value = true; +}; + +// A bit of help figuring out which of the above specializations to use. +// +// We begin by safely assuming types don't have a spare bit. +template +struct HasFreeLSB { + static const bool value = false; +}; + +// The lowest bit of a properly-aligned pointer is always zero if the pointee +// type is greater than byte-aligned. That bit is free to use if it's masked +// out of such pointers before they're dereferenced. +template +struct HasFreeLSB { + static const bool value = (MOZ_ALIGNOF(T) & 1) == 0; +}; + +// We store references as pointers, so they have a free bit if a pointer would +// have one. +template +struct HasFreeLSB { + static const bool value = HasFreeLSB::value; +}; + +// Select one of the previous result implementation based on the properties of +// the V and E types. +template +struct SelectResultImpl { + static const PackingStrategy value = + (IsEmpty::value && UnusedZero::value) + ? PackingStrategy::NullIsOk + : (detail::HasFreeLSB::value && detail::HasFreeLSB::value) + ? PackingStrategy::LowBitTagIsError + : (IsDefaultConstructible::value && + IsDefaultConstructible::value && + IsPackableVariant::value) + ? PackingStrategy::PackedVariant + : PackingStrategy::Variant; + + using Type = detail::ResultImplementation; +}; + +template +struct IsResult : FalseType {}; + +template +struct IsResult> : TrueType {}; + +} // namespace detail + +template +auto ToResult(Result&& aValue) + -> decltype(Forward>(aValue)) { + return Forward>(aValue); +} + +/** + * Result represents the outcome of an operation that can either succeed + * or fail. It contains either a success value of type V or an error value of + * type E. + * + * All Result methods are const, so results are basically immutable. + * This is just like Variant but with a slightly different API, and the + * following cases are optimized so Result can be stored more efficiently: + * + * - If the success type is Ok (or another empty class) and the error type is a + * reference, Result is guaranteed to be pointer-sized and all zero + * bits on success. Do not change this representation! There is JIT code that + * depends on it. + * + * - If the success type is a pointer type and the error type is a reference + * type, and the least significant bit is unused for both types when stored + * as a pointer (due to alignment rules), Result is guaranteed to be + * pointer-sized. In this case, we use the lowest bit as tag bit: 0 to + * indicate the Result's bits are a V, 1 to indicate the Result's bits (with + * the 1 masked out) encode an E*. + * + * The purpose of Result is to reduce the screwups caused by using `false` or + * `nullptr` to indicate errors. + * What screwups? See for + * a partial list. + */ +template +class MOZ_MUST_USE_TYPE Result final { + using Impl = typename detail::SelectResultImpl::Type; + + Impl mImpl; + + public: + /** + * Create a success result. + */ + MOZ_IMPLICIT Result(V aValue) : mImpl(aValue) { MOZ_ASSERT(isOk()); } + + /** + * Create an error result. + */ + explicit Result(E aErrorValue) : mImpl(aErrorValue) { MOZ_ASSERT(isErr()); } + + /** + * Implementation detail of MOZ_TRY(). + * Create an error result from another error result. + */ + template + MOZ_IMPLICIT Result(const GenericErrorResult& aErrorResult) + : mImpl(aErrorResult.mErrorValue) { + static_assert(mozilla::IsConvertible::value, + "E2 must be convertible to E"); + MOZ_ASSERT(isErr()); + } + + Result(const Result&) = default; + Result& operator=(const Result&) = default; + + /** True if this Result is a success result. */ + bool isOk() const { return mImpl.isOk(); } + + /** True if this Result is an error result. */ + bool isErr() const { return !mImpl.isOk(); } + + /** Get the success value from this Result, which must be a success result. */ + V unwrap() const { + MOZ_ASSERT(isOk()); + return mImpl.unwrap(); + } + + /** + * Get the success value from this Result, which must be a success result. + * If it is an error result, then return the aValue. + */ + V unwrapOr(V aValue) const { return isOk() ? mImpl.unwrap() : aValue; } + + /** Get the error value from this Result, which must be an error result. */ + E unwrapErr() const { + MOZ_ASSERT(isErr()); + return mImpl.unwrapErr(); + } + + /** + * Map a function V -> W over this result's success variant. If this result is + * an error, do not invoke the function and return a copy of the error. + * + * Mapping over success values invokes the function to produce a new success + * value: + * + * // Map Result to another Result + * Result res(5); + * Result res2 = res.map([](int x) { return x * x; }); + * MOZ_ASSERT(res2.unwrap() == 25); + * + * // Map Result to Result + * Result res("hello, map!"); + * Result res2 = res.map(strlen); + * MOZ_ASSERT(res2.unwrap() == 11); + * + * Mapping over an error does not invoke the function and copies the error: + * + * Result res(5); + * MOZ_ASSERT(res.isErr()); + * Result res2 = res.map([](V v) { ... }); + * MOZ_ASSERT(res2.isErr()); + * MOZ_ASSERT(res2.unwrapErr() == 5); + */ + template + auto map(F f) const -> Result { + using RetResult = Result; + return isOk() ? RetResult(f(unwrap())) : RetResult(unwrapErr()); + } + + /** + * Given a function V -> Result, apply it to this result's success value + * and return its result. If this result is an error value, then return a + * copy. + * + * This is sometimes called "flatMap" or ">>=" in other contexts. + * + * `andThen`ing over success values invokes the function to produce a new + * result: + * + * Result res("hello, andThen!"); + * Result res2 = res.andThen([](const char* s) { + * return containsHtmlTag(s) + * ? Result(Error("Invalid: contains HTML")) + * : Result(HtmlFreeString(s)); + * } + * }); + * MOZ_ASSERT(res2.isOk()); + * MOZ_ASSERT(res2.unwrap() == HtmlFreeString("hello, andThen!"); + * + * `andThen`ing over error results does not invoke the function, and just + * produces a new copy of the error result: + * + * Result res("some error"); + * auto res2 = res.andThen([](int x) { ... }); + * MOZ_ASSERT(res2.isErr()); + * MOZ_ASSERT(res.unwrapErr() == res2.unwrapErr()); + */ + template ::value>::Type> + auto andThen(F f) const -> decltype(f(*((V*)nullptr))) { + return isOk() ? f(unwrap()) : GenericErrorResult(unwrapErr()); + } +}; + +/** + * A type that auto-converts to an error Result. This is like a Result without + * a success type. It's the best return type for functions that always return + * an error--functions designed to build and populate error objects. It's also + * useful in error-handling macros; see MOZ_TRY for an example. + */ +template +class MOZ_MUST_USE_TYPE GenericErrorResult { + E mErrorValue; + + template + friend class Result; + + public: + explicit GenericErrorResult(E aErrorValue) : mErrorValue(aErrorValue) {} +}; + +template +inline GenericErrorResult Err(E&& aErrorValue) { + return GenericErrorResult(aErrorValue); +} + +} // namespace mozilla + +/** + * MOZ_TRY(expr) is the C++ equivalent of Rust's `try!(expr);`. First, it + * evaluates expr, which must produce a Result value. On success, it + * discards the result altogether. On error, it immediately returns an error + * Result from the enclosing function. + */ +#define MOZ_TRY(expr) \ + do { \ + auto mozTryTempResult_ = ::mozilla::ToResult(expr); \ + if (mozTryTempResult_.isErr()) { \ + return ::mozilla::Err(mozTryTempResult_.unwrapErr()); \ + } \ + } while (0) + +/** + * MOZ_TRY_VAR(target, expr) is the C++ equivalent of Rust's `target = + * try!(expr);`. First, it evaluates expr, which must produce a Result value. On + * success, the result's success value is assigned to target. On error, + * immediately returns the error result. |target| must evaluate to a reference + * without any side effects. + */ +#define MOZ_TRY_VAR(target, expr) \ + do { \ + auto mozTryVarTempResult_ = (expr); \ + if (mozTryVarTempResult_.isErr()) { \ + return ::mozilla::Err(mozTryVarTempResult_.unwrapErr()); \ + } \ + (target) = mozTryVarTempResult_.unwrap(); \ + } while (0) + +#endif // mozilla_Result_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ResultExtensions.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ResultExtensions.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ResultExtensions.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/. */ + +/* Extensions to the Result type to enable simpler handling of XPCOM/NSPR + * results. */ + +#ifndef mozilla_ResultExtensions_h +#define mozilla_ResultExtensions_h + +#include "mozilla/Assertions.h" +#include "nscore.h" +#include "prtypes.h" + +namespace mozilla { + +// Allow nsresult errors to automatically convert to nsresult values, so MOZ_TRY +// can be used in XPCOM methods with Result results. +template <> +class MOZ_MUST_USE_TYPE GenericErrorResult { + nsresult mErrorValue; + + template + friend class Result; + + public: + explicit GenericErrorResult(nsresult aErrorValue) : mErrorValue(aErrorValue) { + MOZ_ASSERT(NS_FAILED(aErrorValue)); + } + + operator nsresult() { return mErrorValue; } +}; + +// Allow MOZ_TRY to handle `PRStatus` values. +inline Result ToResult(PRStatus aValue); + +} // namespace mozilla + +#include "mozilla/Result.h" + +namespace mozilla { + +inline Result ToResult(nsresult aValue) { + if (NS_FAILED(aValue)) { + return Err(aValue); + } + return Ok(); +} + +inline Result ToResult(PRStatus aValue) { + if (aValue == PR_SUCCESS) { + return Ok(); + } + return Err(NS_ERROR_FAILURE); +} + +} // namespace mozilla + +#endif // mozilla_ResultExtensions_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ReverseIterator.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ReverseIterator.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ReverseIterator.h @@ -16,122 +16,120 @@ namespace mozilla { -template -class ReverseIterator -{ -public: - template - explicit ReverseIterator(Iterator aIter) - : mCurrent(aIter) { } +template +class ReverseIterator { + public: + template + explicit ReverseIterator(Iterator aIter) : mCurrent(aIter) {} - template + template MOZ_IMPLICIT ReverseIterator(const ReverseIterator& aOther) - : mCurrent(aOther.mCurrent) { } + : mCurrent(aOther.mCurrent) {} - decltype(*DeclVal()) operator*() const - { + decltype(*DeclVal()) operator*() const { IteratorT tmp = mCurrent; return *--tmp; } /* Increments and decrements operators */ - ReverseIterator& operator++() { --mCurrent; return *this; } - ReverseIterator& operator--() { ++mCurrent; return *this; } - ReverseIterator operator++(int) { auto ret = *this; mCurrent--; return ret; } - ReverseIterator operator--(int) { auto ret = *this; mCurrent++; return ret; } + ReverseIterator& operator++() { + --mCurrent; + return *this; + } + ReverseIterator& operator--() { + ++mCurrent; + return *this; + } + ReverseIterator operator++(int) { + auto ret = *this; + mCurrent--; + return ret; + } + ReverseIterator operator--(int) { + auto ret = *this; + mCurrent++; + return ret; + } /* Comparison operators */ - template + template friend bool operator==(const ReverseIterator& aIter1, const ReverseIterator& aIter2); - template + template friend bool operator!=(const ReverseIterator& aIter1, const ReverseIterator& aIter2); - template + template friend bool operator<(const ReverseIterator& aIter1, const ReverseIterator& aIter2); - template + template friend bool operator<=(const ReverseIterator& aIter1, const ReverseIterator& aIter2); - template + template friend bool operator>(const ReverseIterator& aIter1, const ReverseIterator& aIter2); - template + template friend bool operator>=(const ReverseIterator& aIter1, const ReverseIterator& aIter2); -private: + private: IteratorT mCurrent; }; -template -bool -operator==(const ReverseIterator& aIter1, - const ReverseIterator& aIter2) -{ +template +bool operator==(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) { return aIter1.mCurrent == aIter2.mCurrent; } -template -bool -operator!=(const ReverseIterator& aIter1, - const ReverseIterator& aIter2) -{ +template +bool operator!=(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) { return aIter1.mCurrent != aIter2.mCurrent; } -template -bool -operator<(const ReverseIterator& aIter1, - const ReverseIterator& aIter2) -{ +template +bool operator<(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) { return aIter1.mCurrent > aIter2.mCurrent; } -template -bool -operator<=(const ReverseIterator& aIter1, - const ReverseIterator& aIter2) -{ +template +bool operator<=(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) { return aIter1.mCurrent >= aIter2.mCurrent; } -template -bool -operator>(const ReverseIterator& aIter1, - const ReverseIterator& aIter2) -{ +template +bool operator>(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) { return aIter1.mCurrent < aIter2.mCurrent; } -template -bool -operator>=(const ReverseIterator& aIter1, - const ReverseIterator& aIter2) -{ +template +bool operator>=(const ReverseIterator& aIter1, + const ReverseIterator& aIter2) { return aIter1.mCurrent <= aIter2.mCurrent; } namespace detail { -template -class IteratorRange -{ -public: +template +class IteratorRange { + public: typedef IteratorT iterator; typedef IteratorT const_iterator; typedef ReverseIterator reverse_iterator; typedef ReverseIterator const_reverse_iterator; - template + template MOZ_IMPLICIT IteratorRange(Iterator1 aIterBegin, Iterator2 aIterEnd) - : mIterBegin(aIterBegin), mIterEnd(aIterEnd) { } + : mIterBegin(aIterBegin), mIterEnd(aIterEnd) {} - template + template MOZ_IMPLICIT IteratorRange(const IteratorRange& aOther) - : mIterBegin(aOther.mIterBegin), mIterEnd(aOther.mIterEnd) { } + : mIterBegin(aOther.mIterBegin), mIterEnd(aOther.mIterEnd) {} iterator begin() const { return mIterBegin; } const_iterator cbegin() const { return begin(); } @@ -142,27 +140,25 @@ reverse_iterator rend() const { return reverse_iterator(mIterBegin); } const_reverse_iterator crend() const { return rend(); } -private: + private: IteratorT mIterBegin; IteratorT mIterEnd; }; -} // namespace detail +} // namespace detail -template -detail::IteratorRange -Reversed(Range& aRange) -{ +template +detail::IteratorRange Reversed( + Range& aRange) { return {aRange.rbegin(), aRange.rend()}; } -template -detail::IteratorRange -Reversed(const Range& aRange) -{ +template +detail::IteratorRange Reversed( + const Range& aRange) { return {aRange.rbegin(), aRange.rend()}; } -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_ReverseIterator_h +#endif // mozilla_ReverseIterator_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/RollingMean.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/RollingMean.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/RollingMean.h @@ -4,7 +4,7 @@ * 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 set abstraction for enumeration values. */ +/* Calculate the rolling mean of a series of values. */ #ifndef mozilla_RollingMean_h_ #define mozilla_RollingMean_h_ @@ -26,33 +26,28 @@ * * WARNING: Float types are not supported due to rounding errors. */ -template -class RollingMean -{ -private: +template +class RollingMean { + private: size_t mInsertIndex; size_t mMaxValues; Vector mValues; S mTotal; -public: + public: static_assert(!IsFloatingPoint::value, "floating-point types are unsupported due to rounding " "errors"); explicit RollingMean(size_t aMaxValues) - : mInsertIndex(0), - mMaxValues(aMaxValues), - mTotal(0) - { + : mInsertIndex(0), mMaxValues(aMaxValues), mTotal(0) { MOZ_ASSERT(aMaxValues > 0); } - RollingMean& operator=(RollingMean&& aOther) - { + RollingMean& operator=(RollingMean&& aOther) { MOZ_ASSERT(this != &aOther, "self-assignment is forbidden"); this->~RollingMean(); - new(this) RollingMean(aOther.mMaxValues); + new (this) RollingMean(aOther.mMaxValues); mInsertIndex = aOther.mInsertIndex; mTotal = aOther.mTotal; mValues.swap(aOther.mValues); @@ -62,8 +57,7 @@ /** * Insert a value into the rolling mean. */ - bool insert(T aValue) - { + bool insert(T aValue) { MOZ_ASSERT(mValues.length() <= mMaxValues); if (mValues.length() == mMaxValues) { @@ -83,33 +77,25 @@ /** * Calculate the rolling mean. */ - T mean() - { + T mean() { MOZ_ASSERT(!empty()); return T(mTotal / int64_t(mValues.length())); } - bool empty() - { - return mValues.empty(); - } + bool empty() { return mValues.empty(); } /** * Remove all values from the rolling mean. */ - void clear() - { + void clear() { mValues.clear(); mInsertIndex = 0; mTotal = T(0); } - size_t maxValues() - { - return mMaxValues; - } + size_t maxValues() { return mMaxValues; } }; -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_RollingMean_h_ +#endif // mozilla_RollingMean_h_ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/SHA1.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/SHA1.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/SHA1.h @@ -34,18 +34,16 @@ * The finish method may only be called once and cannot be followed by calls * to update. */ -class SHA1Sum -{ - union - { +class SHA1Sum { + union { uint32_t mW[16]; /* input buffer */ uint8_t mB[64]; } mU; - uint64_t mSize; /* count of hashed bytes. */ + uint64_t mSize; /* count of hashed bytes. */ unsigned mH[22]; /* 5 state variables, 16 tmp values, 1 extra */ bool mDone; -public: + public: MFBT_API SHA1Sum(); static const size_t kHashSize = 20; 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 @@ -35,12 +35,9 @@ * specialize the type traits accordingly. */ template -class SaturateOp -{ -public: - explicit SaturateOp(T& aValue) - : mValue(aValue) - { +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. @@ -50,20 +47,13 @@ // Add and subtract operators - T operator+(const T& aRhs) const - { - return T(mValue) += aRhs; - } + T operator+(const T& aRhs) const { return T(mValue) += aRhs; } - 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& operator+=(const T& aRhs) const { const T min = std::numeric_limits::min(); const T max = std::numeric_limits::max(); @@ -75,8 +65,7 @@ return mValue; } - const T& operator-=(const T& aRhs) const - { + const T& operator-=(const T& aRhs) const { const T min = std::numeric_limits::min(); const T max = std::numeric_limits::max(); @@ -90,31 +79,31 @@ // Increment and decrement operators - const T& operator++() const // prefix + const T& operator++() const // prefix { return operator+=(static_cast(1)); } - T operator++(int) const // postfix + T operator++(int)const // postfix { const T value(mValue); operator++(); return value; } - const T& operator--() const // prefix + const T& operator--() const // prefix { return operator-=(static_cast(1)); } - T operator--(int) const // postfix + T operator--(int)const // postfix { const T value(mValue); operator--(); return value; } -private: + private: SaturateOp(const SaturateOp&) = delete; SaturateOp(SaturateOp&&) = delete; SaturateOp& operator=(const SaturateOp&) = delete; @@ -128,139 +117,111 @@ * build on top of |SaturateOp|. */ template -class Saturate -{ -public: +class Saturate { + public: Saturate() = default; MOZ_IMPLICIT Saturate(const Saturate&) = default; - MOZ_IMPLICIT Saturate(Saturate&& aValue) - { - mValue = Move(aValue.mValue); - } + MOZ_IMPLICIT Saturate(Saturate&& aValue) { mValue = Move(aValue.mValue); } - explicit Saturate(const T& aValue) - : mValue(aValue) - { } + explicit Saturate(const T& aValue) : mValue(aValue) {} - const T& value() const - { - return mValue; - } + const T& value() const { return mValue; } // Compare operators - bool operator==(const Saturate& aRhs) const - { + bool operator==(const Saturate& aRhs) const { return mValue == aRhs.mValue; } - bool operator!=(const Saturate& aRhs) const - { - return !operator==(aRhs); - } + 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 mValue == aRhs; } - bool operator!=(const T& aRhs) const - { - return !operator==(aRhs); - } + bool operator!=(const T& aRhs) const { return !operator==(aRhs); } // Assignment operators Saturate& operator=(const Saturate&) = default; - Saturate& operator=(Saturate&& aRhs) - { + Saturate& operator=(Saturate&& aRhs) { mValue = Move(aRhs.mValue); return *this; } // Add and subtract operators - Saturate operator+(const Saturate& aRhs) const - { + Saturate operator+(const Saturate& aRhs) const { Saturate lhs(mValue); return lhs += aRhs.mValue; } - Saturate operator+(const T& aRhs) const - { + Saturate operator+(const T& aRhs) const { Saturate lhs(mValue); return lhs += aRhs; } - Saturate operator-(const Saturate& aRhs) const - { + Saturate operator-(const Saturate& aRhs) const { Saturate lhs(mValue); return lhs -= aRhs.mValue; } - Saturate operator-(const T& aRhs) const - { + Saturate operator-(const T& aRhs) const { Saturate lhs(mValue); return lhs -= aRhs; } // Compound operators - Saturate& operator+=(const Saturate& aRhs) - { + Saturate& operator+=(const Saturate& aRhs) { SaturateOp(mValue) += aRhs.mValue; return *this; } - Saturate& operator+=(const T& aRhs) - { + Saturate& operator+=(const T& aRhs) { SaturateOp(mValue) += aRhs; return *this; } - Saturate& operator-=(const Saturate& aRhs) - { + Saturate& operator-=(const Saturate& aRhs) { SaturateOp(mValue) -= aRhs.mValue; return *this; } - Saturate& operator-=(const T& aRhs) - { + Saturate& operator-=(const T& aRhs) { SaturateOp(mValue) -= aRhs; return *this; } // Increment and decrement operators - Saturate& operator++() // prefix + Saturate& operator++() // prefix { ++SaturateOp(mValue); return *this; } - Saturate operator++(int) // postfix + Saturate operator++(int) // postfix { return Saturate(SaturateOp(mValue)++); } - Saturate& operator--() // prefix + Saturate& operator--() // prefix { --SaturateOp(mValue); return *this; } - Saturate operator--(int) // postfix + Saturate operator--(int) // postfix { return Saturate(SaturateOp(mValue)--); } -private: + private: T mValue; }; -} // namespace detail +} // namespace detail typedef detail::Saturate SaturateInt8; typedef detail::Saturate SaturateInt16; @@ -269,20 +230,16 @@ typedef detail::Saturate SaturateUint16; typedef detail::Saturate SaturateUint32; -} // namespace mozilla +} // namespace mozilla -template -bool -operator==(LhsT aLhs, const mozilla::detail::Saturate& aRhs) -{ +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) -{ +template +bool operator!=(LhsT aLhs, const mozilla::detail::Saturate& aRhs) { return !(aLhs == aRhs); } -#endif // mozilla_Saturate_h +#endif // mozilla_Saturate_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ScopeExit.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ScopeExit.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ScopeExit.h @@ -91,19 +91,15 @@ bool mExecuteOnDestruction; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -public: - explicit ScopeExit(ExitFunction&& cleanup - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mExitFunction(cleanup) - , mExecuteOnDestruction(true) - { + public: + explicit ScopeExit(ExitFunction&& cleanup MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mExitFunction(cleanup), mExecuteOnDestruction(true) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } ScopeExit(ScopeExit&& rhs) - : mExitFunction(mozilla::Move(rhs.mExitFunction)) - , mExecuteOnDestruction(rhs.mExecuteOnDestruction) - { + : mExitFunction(mozilla::Move(rhs.mExitFunction)), + mExecuteOnDestruction(rhs.mExecuteOnDestruction) { rhs.release(); } @@ -113,20 +109,16 @@ } } - void release() { - mExecuteOnDestruction = false; - } + void release() { mExecuteOnDestruction = false; } -private: + private: explicit ScopeExit(const ScopeExit&) = delete; ScopeExit& operator=(const ScopeExit&) = delete; ScopeExit& operator=(ScopeExit&&) = delete; }; template -ScopeExit -MakeScopeExit(ExitFunction&& exitFunction) -{ +ScopeExit MakeScopeExit(ExitFunction&& exitFunction) { return ScopeExit(mozilla::Move(exitFunction)); } 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 @@ -64,30 +64,24 @@ * const static void release(type); * } */ -template -class MOZ_NON_TEMPORARY_CLASS Scoped -{ -public: +template +class MOZ_NON_TEMPORARY_CLASS Scoped { + public: typedef typename Traits::type Resource; explicit Scoped(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) - : mValue(Traits::empty()) - { + : mValue(Traits::empty()) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } - explicit Scoped(const Resource& aValue - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mValue(aValue) - { + explicit Scoped(const Resource& aValue MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mValue(aValue) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } /* Move constructor. */ - Scoped(Scoped&& aOther - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mValue(Move(aOther.mValue)) - { + Scoped(Scoped&& aOther MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mValue(Move(aOther.mValue)) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; aOther.mValue = Traits::empty(); } @@ -110,8 +104,7 @@ * * @return The original resource. */ - Resource forget() - { + Resource forget() { Resource tmp = mValue; mValue = Traits::empty(); return tmp; @@ -122,8 +115,7 @@ * * If this |Scoped| is currently empty, this method has no effect. */ - void dispose() - { + void dispose() { Traits::release(mValue); mValue = Traits::empty(); } @@ -140,27 +132,25 @@ */ Scoped& operator=(const Resource& aOther) { return reset(aOther); } - Scoped& reset(const Resource& aOther) - { + Scoped& reset(const Resource& aOther) { Traits::release(mValue); mValue = aOther; return *this; } /* Move assignment operator. */ - Scoped& operator=(Scoped&& aRhs) - { + Scoped& operator=(Scoped&& aRhs) { MOZ_ASSERT(&aRhs != this, "self-move-assignment not allowed"); this->~Scoped(); - new(this) Scoped(Move(aRhs)); + new (this) Scoped(Move(aRhs)); return *this; } -private: + private: explicit Scoped(const Scoped& aValue) = delete; Scoped& operator=(const Scoped& aValue) = delete; -private: + private: Resource mValue; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; @@ -173,39 +163,31 @@ * @param Traits A struct implementing clean-up. See the implementations * for more details. */ -#define SCOPED_TEMPLATE(name, Traits) \ -template \ -struct MOZ_NON_TEMPORARY_CLASS name : public mozilla::Scoped > \ -{ \ - typedef mozilla::Scoped > Super; \ - typedef typename Super::Resource Resource; \ - name& operator=(Resource aRhs) \ - { \ - Super::operator=(aRhs); \ - return *this; \ - } \ - name& operator=(name&& aRhs) \ - { \ - Super::operator=(Move(aRhs)); \ - return *this; \ - } \ - explicit name(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) \ - : Super(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT) \ - {} \ - explicit name(Resource aRhs \ - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \ - : Super(aRhs \ - MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) \ - {} \ - name(name&& aRhs \ - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \ - : Super(Move(aRhs) \ - MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) \ - {} \ -private: \ - explicit name(name&) = delete; \ - name& operator=(name&) = delete; \ -}; +#define SCOPED_TEMPLATE(name, Traits) \ + template \ + struct MOZ_NON_TEMPORARY_CLASS name \ + : public mozilla::Scoped > { \ + typedef mozilla::Scoped > Super; \ + typedef typename Super::Resource Resource; \ + name& operator=(Resource aRhs) { \ + Super::operator=(aRhs); \ + return *this; \ + } \ + name& operator=(name&& aRhs) { \ + Super::operator=(Move(aRhs)); \ + return *this; \ + } \ + explicit name(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) \ + : Super(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT) {} \ + explicit name(Resource aRhs MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \ + : Super(aRhs MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) {} \ + name(name&& aRhs MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \ + : Super(Move(aRhs) MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) {} \ + \ + private: \ + explicit name(name&) = delete; \ + name& operator=(name&) = delete; \ + }; /* * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE makes it easy to create scoped @@ -230,18 +212,20 @@ * } // file is closed with PR_Close here */ #define MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(name, Type, Deleter) \ -template <> inline void TypeSpecificDelete(Type* aValue) { Deleter(aValue); } \ -typedef ::mozilla::TypeSpecificScopedPointer name; + template <> \ + inline void TypeSpecificDelete(Type* aValue) { \ + Deleter(aValue); \ + } \ + typedef ::mozilla::TypeSpecificScopedPointer name; -template void TypeSpecificDelete(T* aValue); +template +void TypeSpecificDelete(T* aValue); template -struct TypeSpecificScopedPointerTraits -{ +struct TypeSpecificScopedPointerTraits { typedef T* type; static type empty() { return nullptr; } - static void release(type aValue) - { + static void release(type aValue) { if (aValue) { TypeSpecificDelete(aValue); } 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 @@ -48,19 +48,15 @@ // The ideal size depends on how the SegmentedVector is used and the size of // |T|, but reasonable sizes include 1024, 4096 (the default), 8192, and 16384. // -template -class SegmentedVector : private AllocPolicy -{ - template +template +class SegmentedVector : private AllocPolicy { + template struct SegmentImpl - : public mozilla::LinkedListElement> - { + : public mozilla::LinkedListElement> { SegmentImpl() : mLength(0) {} - ~SegmentImpl() - { + ~SegmentImpl() { for (uint32_t i = 0; i < mLength; i++) { (*this)[i].~T(); } @@ -70,21 +66,18 @@ T* Elems() { return reinterpret_cast(&mStorage.mBuf); } - T& operator[](size_t aIndex) - { + T& operator[](size_t aIndex) { MOZ_ASSERT(aIndex < mLength); return Elems()[aIndex]; } - const T& operator[](size_t aIndex) const - { + const T& operator[](size_t aIndex) const { MOZ_ASSERT(aIndex < mLength); return Elems()[aIndex]; } - template - void Append(U&& aU) - { + template + void Append(U&& aU) { MOZ_ASSERT(mLength < SegmentCapacity); // Pre-increment mLength so that the bounds-check in operator[] passes. mLength++; @@ -92,8 +85,7 @@ new (elem) T(mozilla::Forward(aU)); } - void PopLast() - { + void PopLast() { MOZ_ASSERT(mLength > 0); (*this)[mLength - 1].~T(); mLength--; @@ -102,8 +94,7 @@ uint32_t mLength; // The union ensures that the elements are appropriately aligned. - union Storage - { + union Storage { char mBuf[sizeof(T) * SegmentCapacity]; mozilla::AlignedElem mAlign; } mStorage; @@ -117,39 +108,39 @@ // kSingleElementSegmentSize already accounts for one element. static const size_t kSingleElementSegmentSize = sizeof(SegmentImpl<1>); static const size_t kSegmentCapacity = - kSingleElementSegmentSize <= IdealSegmentSize - ? (IdealSegmentSize - kSingleElementSegmentSize) / sizeof(T) + 1 - : 1; + kSingleElementSegmentSize <= IdealSegmentSize + ? (IdealSegmentSize - kSingleElementSegmentSize) / sizeof(T) + 1 + : 1; + public: typedef SegmentImpl Segment; -public: // The |aIdealSegmentSize| is only for sanity checking. If it's specified, we // check that the actual segment size is as close as possible to it. This // serves as a sanity check for SegmentedVectorCapacity's capacity // computation. - explicit SegmentedVector(size_t aIdealSegmentSize = 0) - { + explicit SegmentedVector(size_t aIdealSegmentSize = 0) { // The difference between the actual segment size and the ideal segment // size should be less than the size of a single element... unless the // ideal size was too small, in which case the capacity should be one. MOZ_ASSERT_IF( - aIdealSegmentSize != 0, - (sizeof(Segment) > aIdealSegmentSize && kSegmentCapacity == 1) || - aIdealSegmentSize - sizeof(Segment) < sizeof(T)); + aIdealSegmentSize != 0, + (sizeof(Segment) > aIdealSegmentSize && kSegmentCapacity == 1) || + aIdealSegmentSize - sizeof(Segment) < sizeof(T)); } + SegmentedVector(SegmentedVector&& aOther) + : mSegments(mozilla::Move(aOther.mSegments)) {} + ~SegmentedVector() { Clear(); } bool IsEmpty() const { return !mSegments.getFirst(); } // Note that this is O(n) rather than O(1), but the constant factor is very // small because it only has to do one addition per segment. - size_t Length() const - { + size_t Length() const { size_t n = 0; - for (auto segment = mSegments.getFirst(); - segment; + for (auto segment = mSegments.getFirst(); segment; segment = segment->getNext()) { n += segment->Length(); } @@ -158,9 +149,8 @@ // Returns false if the allocation failed. (If you are using an infallible // allocation policy, use InfallibleAppend() instead.) - template - MOZ_MUST_USE bool Append(U&& aU) - { + template + MOZ_MUST_USE bool Append(U&& aU) { Segment* last = mSegments.getLast(); if (!last || last->Length() == kSegmentCapacity) { last = this->template pod_malloc(1); @@ -176,15 +166,13 @@ // You should probably only use this instead of Append() if you are using an // infallible allocation policy. It will crash if the allocation fails. - template - void InfallibleAppend(U&& aU) - { + template + void InfallibleAppend(U&& aU) { bool ok = Append(mozilla::Forward(aU)); MOZ_RELEASE_ASSERT(ok); } - void Clear() - { + void Clear() { Segment* segment; while ((segment = mSegments.popFirst())) { segment->~Segment(); @@ -192,22 +180,19 @@ } } - T& GetLast() - { + T& GetLast() { MOZ_ASSERT(!IsEmpty()); Segment* last = mSegments.getLast(); return (*last)[last->Length() - 1]; } - const T& GetLast() const - { + const T& GetLast() const { MOZ_ASSERT(!IsEmpty()); Segment* last = mSegments.getLast(); return (*last)[last->Length() - 1]; } - void PopLast() - { + void PopLast() { MOZ_ASSERT(!IsEmpty()); Segment* last = mSegments.getLast(); last->PopLast(); @@ -220,8 +205,7 @@ // Equivalent to calling |PopLast| |aNumElements| times, but potentially // more efficient. - void PopLastN(uint32_t aNumElements) - { + void PopLastN(uint32_t aNumElements) { MOZ_ASSERT(aNumElements <= Length()); Segment* last; @@ -260,7 +244,6 @@ // 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(); @@ -275,35 +258,37 @@ // f(elem); // } // - class IterImpl - { + // Note, adding new entries to the SegmentedVector while using iterators + // is supported, but removing is not! + // If an iterator has entered Done() state, adding more entries to the + // vector doesn't affect it. + class IterImpl { friend class SegmentedVector; Segment* mSegment; size_t mIndex; - explicit IterImpl(SegmentedVector* aVector) - : mSegment(aVector->mSegments.getFirst()) - , mIndex(0) - {} + explicit IterImpl(SegmentedVector* aVector, bool aFromFirst) + : mSegment(aFromFirst ? aVector->mSegments.getFirst() + : aVector->mSegments.getLast()), + mIndex(aFromFirst ? 0 : (mSegment ? mSegment->Length() - 1 : 0)) { + MOZ_ASSERT_IF(mSegment, mSegment->Length() > 0); + } - public: + public: bool Done() const { return !mSegment; } - T& Get() - { + T& Get() { MOZ_ASSERT(!Done()); return (*mSegment)[mIndex]; } - const T& Get() const - { + const T& Get() const { MOZ_ASSERT(!Done()); return (*mSegment)[mIndex]; } - void Next() - { + void Next() { MOZ_ASSERT(!Done()); mIndex++; if (mIndex == mSegment->Length()) { @@ -311,29 +296,40 @@ mIndex = 0; } } + + void Prev() { + MOZ_ASSERT(!Done()); + if (mIndex == 0) { + mSegment = mSegment->getPrevious(); + if (mSegment) { + mIndex = mSegment->Length() - 1; + } + } else { + --mIndex; + } + } }; - IterImpl Iter() { return IterImpl(this); } + IterImpl Iter() { return IterImpl(this, true); } + IterImpl IterFromLast() { return IterImpl(this, false); } // Measure the memory consumption of the vector excluding |this|. Note that // it only measures the vector itself. If the vector elements contain // pointers to other memory blocks, those blocks must be measured separately // during a subsequent iteration over the vector. - size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const - { + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { return mSegments.sizeOfExcludingThis(aMallocSizeOf); } // Like sizeOfExcludingThis(), but measures |this| as well. - size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const - { + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); } -private: + private: mozilla::LinkedList mSegments; }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_SegmentedVector_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/SizePrintfMacros.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/SizePrintfMacros.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/SizePrintfMacros.h @@ -1,33 +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/. */ - -/* Implements (nonstandard) PRI{ouxX}SIZE format macros for size_t types. */ - -#ifndef mozilla_SizePrintfMacros_h_ -#define mozilla_SizePrintfMacros_h_ - -/* - * MSVC's libc does not support C99's %z format length modifier for size_t - * types. Instead, we use Microsoft's nonstandard %I modifier for size_t, which - * is unsigned __int32 on 32-bit platforms and unsigned __int64 on 64-bit - * platforms: - * - * http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx - */ - -#if defined(XP_WIN) -# define PRIoSIZE "Io" -# define PRIuSIZE "Iu" -# define PRIxSIZE "Ix" -# define PRIXSIZE "IX" -#else -# define PRIoSIZE "zo" -# define PRIuSIZE "zu" -# define PRIxSIZE "zx" -# define PRIXSIZE "zX" -#endif - -#endif /* mozilla_SizePrintfMacros_h_ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/SmallPointerArray.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/SmallPointerArray.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/SmallPointerArray.h @@ -0,0 +1,230 @@ +/* -*- 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 vector of pointers space-optimized for a small number of elements. */ +#ifndef mozilla_SmallPointerArray_h +#define mozilla_SmallPointerArray_h + +#include "mozilla/Assertions.h" +#include +#include +#include + +namespace mozilla { + +// Array class for situations where a small number of elements (<= 2) is +// expected, a large number of elements must be accomodated if necessary, +// and the size of the class must be minimal. Typical vector implementations +// will fulfill the first two requirements by simply adding inline storage +// alongside the rest of their member variables. While this strategy works, +// it brings unnecessary storage overhead for vectors with an expected small +// number of elements. This class is intended to deal with that problem. +// +// This class is similar in performance to a vector class. Accessing its +// elements when it has not grown over a size of 2 does not require an extra +// level of indirection and will therefore be faster. +// +// The minimum (inline) size is 2 * sizeof(void*). +// +// Any modification of the array invalidates any outstanding iterators. +template +class SmallPointerArray { + public: + SmallPointerArray() { + mInlineElements[0] = mInlineElements[1] = nullptr; + static_assert(sizeof(SmallPointerArray) == (2 * sizeof(void*)), + "SmallPointerArray must compile to the size of 2 pointers"); + static_assert( + offsetof(SmallPointerArray, mArray) == + offsetof(SmallPointerArray, mInlineElements) + sizeof(T*), + "mArray and mInlineElements[1] are expected to overlap in memory"); + static_assert( + offsetof(SmallPointerArray, mPadding) == + offsetof(SmallPointerArray, mInlineElements), + "mPadding and mInlineElements[0] are expected to overlap in memory"); + } + ~SmallPointerArray() { + if (!mInlineElements[0] && mArray) { + delete mArray; + } + } + + void Clear() { + if (!mInlineElements[0] && mArray) { + delete mArray; + mArray = nullptr; + return; + } + mInlineElements[0] = mInlineElements[1] = nullptr; + } + + void AppendElement(T* aElement) { + // Storing nullptr as an element is not permitted, but we do check for it + // to avoid corruption issues in non-debug builds. + + // In addition to this we assert in debug builds to point out mistakes to + // users of the class. + MOZ_ASSERT(aElement != nullptr); + if (!mInlineElements[0]) { + if (!mArray) { + mInlineElements[0] = aElement; + // Harmless if aElement == nullptr; + return; + } + + if (!aElement) { + return; + } + + mArray->push_back(aElement); + return; + } + + if (!aElement) { + return; + } + + if (!mInlineElements[1]) { + mInlineElements[1] = aElement; + return; + } + + mArray = + new std::vector({mInlineElements[0], mInlineElements[1], aElement}); + mInlineElements[0] = nullptr; + } + + bool RemoveElement(T* aElement) { + MOZ_ASSERT(aElement != nullptr); + if (aElement == nullptr) { + return false; + } + + if (mInlineElements[0] == aElement) { + // Expectected case. + mInlineElements[0] = mInlineElements[1]; + mInlineElements[1] = nullptr; + return true; + } + + if (mInlineElements[0]) { + if (mInlineElements[1] == aElement) { + mInlineElements[1] = nullptr; + return true; + } + return false; + } + + if (mArray) { + for (auto iter = mArray->begin(); iter != mArray->end(); iter++) { + if (*iter == aElement) { + mArray->erase(iter); + return true; + } + } + } + return false; + } + + bool Contains(T* aElement) const { + MOZ_ASSERT(aElement != nullptr); + if (aElement == nullptr) { + return false; + } + + if (mInlineElements[0] == aElement) { + return true; + } + + if (mInlineElements[0]) { + if (mInlineElements[1] == aElement) { + return true; + } + return false; + } + + if (mArray) { + return std::find(mArray->begin(), mArray->end(), aElement) != + mArray->end(); + } + return false; + } + + size_t Length() const { + if (mInlineElements[0]) { + if (!mInlineElements[1]) { + return 1; + } + return 2; + } + + if (mArray) { + return mArray->size(); + } + + return 0; + } + + T* ElementAt(size_t aIndex) const { + MOZ_ASSERT(aIndex < Length()); + if (mInlineElements[0]) { + return mInlineElements[aIndex]; + } + + return (*mArray)[aIndex]; + } + + T* operator[](size_t aIndex) const { return ElementAt(aIndex); } + + typedef T** iterator; + typedef const T** const_iterator; + + // Methods for range-based for loops. Manipulation invalidates these. + iterator begin() { return beginInternal(); } + const_iterator begin() const { return beginInternal(); } + const_iterator cbegin() const { return begin(); } + iterator end() { return beginInternal() + Length(); } + const_iterator end() const { return beginInternal() + Length(); } + const_iterator cend() const { return end(); } + + private: + T** beginInternal() const { + if (mInlineElements[0] || !mArray) { + return const_cast(&mInlineElements[0]); + } + + if (mArray->empty()) { + return nullptr; + } + + return &(*mArray)[0]; + } + + // mArray and mInlineElements[1] share the same area in memory. + // + // When !mInlineElements[0] && !mInlineElements[1] the array is empty. + // + // When mInlineElements[0] && !mInlineElements[1], mInlineElements[0] + // contains the first element. The array is of size 1. + // + // When mInlineElements[0] && mInlineElements[1], mInlineElements[0] + // contains the first element and mInlineElements[1] the second. The + // array is of size 2. + // + // When !mInlineElements[0] && mArray, mArray contains the full contents + // of the array and is of arbitrary size. + union { + T* mInlineElements[2]; + struct { + void* mPadding; + std::vector* mArray; + }; + }; +}; + +} // namespace mozilla + +#endif // mozilla_SmallPointerArray_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Span.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Span.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/Span.h @@ -0,0 +1,960 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +/////////////////////////////////////////////////////////////////////////////// + +// Adapted from +// https://github.com/Microsoft/GSL/blob/3819df6e378ffccf0e29465afe99c3b324c2aa70/include/gsl/span +// and +// https://github.com/Microsoft/GSL/blob/3819df6e378ffccf0e29465afe99c3b324c2aa70/include/gsl/gsl_util + +#ifndef mozilla_Span_h +#define mozilla_Span_h + +#include "mozilla/Array.h" +#include "mozilla/Assertions.h" +#include "mozilla/Casting.h" +#include "mozilla/IntegerTypeTraits.h" +#include "mozilla/Move.h" +#include "mozilla/TypeTraits.h" +#include "mozilla/UniquePtr.h" + +#include +#include +#include +#include + +// Classifications for reasons why constexpr was removed in C++14 to C++11 +// conversion. Once we upgrade compilers, we can try defining each of these +// to constexpr to restore a category of constexprs at a time. +#if !defined(__clang__) && defined(__GNUC__) && __cpp_constexpr < 201304 +#define MOZ_SPAN_ASSERTION_CONSTEXPR +#define MOZ_SPAN_GCC_CONSTEXPR +#define MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR +#define MOZ_SPAN_CONSTEXPR_NOT_JUST_RETURN +#define MOZ_SPAN_NON_CONST_CONSTEXPR +#else +#define MOZ_SPAN_ASSERTION_CONSTEXPR constexpr +#define MOZ_SPAN_GCC_CONSTEXPR constexpr +#define MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR constexpr +#define MOZ_SPAN_CONSTEXPR_NOT_JUST_RETURN constexpr +#define MOZ_SPAN_NON_CONST_CONSTEXPR constexpr +#endif + +#ifdef _MSC_VER +#pragma warning(push) + +// turn off some warnings that are noisy about our MOZ_RELEASE_ASSERT statements +#pragma warning(disable : 4127) // conditional expression is constant + +// blanket turn off warnings from CppCoreCheck for now +// so people aren't annoyed by them when running the tool. +// more targeted suppressions will be added in a future update to the GSL +#pragma warning(disable : 26481 26482 26483 26485 26490 26491 26492 26493 26495) + +#if _MSC_VER < 1910 +#pragma push_macro("constexpr") +#define constexpr /*constexpr*/ + +#endif // _MSC_VER < 1910 +#endif // _MSC_VER + +namespace mozilla { + +// Stuff from gsl_util + +// narrow_cast(): a searchable way to do narrowing casts of values +template +inline constexpr T narrow_cast(U&& u) { + return static_cast(mozilla::Forward(u)); +} + +// end gsl_util + +// [views.constants], constants +// This was -1 in gsl::span, but using size_t for sizes instead of ptrdiff_t +// and reserving a magic value that realistically doesn't occur in +// compile-time-constant Span sizes makes things a lot less messy in terms of +// comparison between signed and unsigned. +constexpr const size_t dynamic_extent = mozilla::MaxValue::value; + +template +class Span; + +// implementation details +namespace span_details { + +inline size_t strlen16(const char16_t* aZeroTerminated) { + size_t len = 0; + while (*(aZeroTerminated++)) { + len++; + } + return len; +} + +// C++14 types that we don't have because we build as C++11. +template +using remove_cv_t = typename mozilla::RemoveCV::Type; +template +using remove_const_t = typename mozilla::RemoveConst::Type; +template +using conditional_t = typename mozilla::Conditional::Type; +template +using add_pointer_t = typename mozilla::AddPointer::Type; +template +using enable_if_t = typename mozilla::EnableIf::Type; + +template +struct is_span_oracle : mozilla::FalseType {}; + +template +struct is_span_oracle> : mozilla::TrueType { +}; + +template +struct is_span : public is_span_oracle> {}; + +template +struct is_std_array_oracle : mozilla::FalseType {}; + +template +struct is_std_array_oracle> + : mozilla::TrueType {}; + +template +struct is_std_array : public is_std_array_oracle> {}; + +template +struct is_allowed_extent_conversion + : public mozilla::IntegralConstant< + bool, From == To || From == mozilla::dynamic_extent || + To == mozilla::dynamic_extent> {}; + +template +struct is_allowed_element_type_conversion + : public mozilla::IntegralConstant< + bool, mozilla::IsConvertible::value> {}; + +template +class span_iterator { + using element_type_ = typename Span::element_type; + + public: + using iterator_category = std::random_access_iterator_tag; + using value_type = remove_const_t; + using difference_type = typename Span::index_type; + + using reference = conditional_t&; + using pointer = add_pointer_t; + + constexpr span_iterator() : span_iterator(nullptr, 0) {} + + MOZ_SPAN_ASSERTION_CONSTEXPR span_iterator(const Span* span, + typename Span::index_type index) + : span_(span), index_(index) { + MOZ_RELEASE_ASSERT(span == nullptr || + (index_ >= 0 && index <= span_->Length())); + } + + friend class span_iterator; + constexpr MOZ_IMPLICIT span_iterator(const span_iterator& other) + : span_iterator(other.span_, other.index_) {} + + MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR span_iterator& + operator=(const span_iterator&) = default; + + MOZ_SPAN_GCC_CONSTEXPR reference operator*() const { + MOZ_RELEASE_ASSERT(span_); + return (*span_)[index_]; + } + + constexpr pointer operator->() const { + MOZ_RELEASE_ASSERT(span_); + return &((*span_)[index_]); + } + + MOZ_SPAN_NON_CONST_CONSTEXPR span_iterator& operator++() { + MOZ_RELEASE_ASSERT(span_ && index_ >= 0 && index_ < span_->Length()); + ++index_; + return *this; + } + + constexpr span_iterator operator++(int) { + auto ret = *this; + ++(*this); + return ret; + } + + MOZ_SPAN_NON_CONST_CONSTEXPR span_iterator& operator--() { + MOZ_RELEASE_ASSERT(span_ && index_ > 0 && index_ <= span_->Length()); + --index_; + return *this; + } + + constexpr span_iterator operator--(int) { + auto ret = *this; + --(*this); + return ret; + } + + MOZ_SPAN_CONSTEXPR_NOT_JUST_RETURN span_iterator + operator+(difference_type n) const { + auto ret = *this; + return ret += n; + } + + MOZ_SPAN_GCC_CONSTEXPR span_iterator& operator+=(difference_type n) { + MOZ_RELEASE_ASSERT(span_ && (index_ + n) >= 0 && + (index_ + n) <= span_->Length()); + index_ += n; + return *this; + } + + constexpr span_iterator operator-(difference_type n) const { + auto ret = *this; + return ret -= n; + } + + constexpr span_iterator& operator-=(difference_type n) + + { + return *this += -n; + } + + MOZ_SPAN_GCC_CONSTEXPR difference_type + operator-(const span_iterator& rhs) const { + MOZ_RELEASE_ASSERT(span_ == rhs.span_); + return index_ - rhs.index_; + } + + constexpr reference operator[](difference_type n) const { + return *(*this + n); + } + + constexpr friend bool operator==(const span_iterator& lhs, + const span_iterator& rhs) { + return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_; + } + + constexpr friend bool operator!=(const span_iterator& lhs, + const span_iterator& rhs) { + return !(lhs == rhs); + } + + MOZ_SPAN_GCC_CONSTEXPR friend bool operator<(const span_iterator& lhs, + const span_iterator& rhs) { + MOZ_RELEASE_ASSERT(lhs.span_ == rhs.span_); + return lhs.index_ < rhs.index_; + } + + constexpr friend bool operator<=(const span_iterator& lhs, + const span_iterator& rhs) { + return !(rhs < lhs); + } + + constexpr friend bool operator>(const span_iterator& lhs, + const span_iterator& rhs) { + return rhs < lhs; + } + + constexpr friend bool operator>=(const span_iterator& lhs, + const span_iterator& rhs) { + return !(rhs > lhs); + } + + void swap(span_iterator& rhs) { + std::swap(index_, rhs.index_); + std::swap(span_, rhs.span_); + } + + protected: + const Span* span_; + size_t index_; +}; + +template +inline constexpr span_iterator operator+( + typename span_iterator::difference_type n, + const span_iterator& rhs) { + return rhs + n; +} + +template +class extent_type { + public: + using index_type = size_t; + + static_assert(Ext >= 0, "A fixed-size Span must be >= 0 in size."); + + constexpr extent_type() {} + + template + MOZ_SPAN_ASSERTION_CONSTEXPR MOZ_IMPLICIT + extent_type(extent_type ext) { + static_assert( + Other == Ext || Other == dynamic_extent, + "Mismatch between fixed-size extent and size of initializing data."); + MOZ_RELEASE_ASSERT(ext.size() == Ext); + } + + MOZ_SPAN_ASSERTION_CONSTEXPR MOZ_IMPLICIT extent_type(index_type length) { + MOZ_RELEASE_ASSERT(length == Ext); + } + + constexpr index_type size() const { return Ext; } +}; + +template <> +class extent_type { + public: + using index_type = size_t; + + template + explicit constexpr extent_type(extent_type ext) : size_(ext.size()) {} + + explicit constexpr extent_type(index_type length) : size_(length) {} + + constexpr index_type size() const { return size_; } + + private: + index_type size_; +}; +} // namespace span_details + +/** + * Span - slices for C++ + * + * Span implements Rust's slice concept for C++. It's called "Span" instead of + * "Slice" to follow the naming used in C++ Core Guidelines. + * + * A Span wraps a pointer and a length that identify a non-owning view to a + * contiguous block of memory of objects of the same type. Various types, + * including (pre-decay) C arrays, XPCOM strings, nsTArray, mozilla::Array, + * mozilla::Range and contiguous standard-library containers, auto-convert + * into Spans when attempting to pass them as arguments to methods that take + * Spans. MakeSpan() functions can be used for explicit conversion in other + * contexts. (Span itself autoconverts into mozilla::Range.) + * + * Like Rust's slices, Span provides safety against out-of-bounds access by + * performing run-time bound checks. However, unlike Rust's slices, Span + * cannot provide safety against use-after-free. + * + * (Note: Span is like Rust's slice only conceptually. Due to the lack of + * ABI guarantees, you should still decompose spans/slices to raw pointer + * and length parts when crossing the FFI. The Elements() and data() methods + * are guaranteed to return a non-null pointer even for zero-length spans, + * so the pointer can be used as a raw part of a Rust slice without further + * checks.) + * + * In addition to having constructors and MakeSpan() functions that take + * various well-known types, a Span for an arbitrary type can be constructed + * (via constructor or MakeSpan()) from a pointer and a length or a pointer + * and another pointer pointing just past the last element. + * + * A Span or Span can be obtained for const char* + * or const char16_t pointing to a zero-terminated string using the + * MakeStringSpan() function. Corresponding implicit constructor does not exist + * in order to avoid accidental construction in cases where const char* or + * const char16_t* do not point to a zero-terminated string. + * + * Span has methods that follow the Mozilla naming style and methods that + * don't. The methods that follow the Mozilla naming style are meant to be + * used directly from Mozilla code. The methods that don't are meant for + * integration with C++11 range-based loops and with meta-programming that + * expects the same methods that are found on the standard-library + * containers. For example, to decompose a Span into its parts in Mozilla + * code, use Elements() and Length() (as with nsTArray) instead of data() + * and size() (as with std::vector). + * + * The pointer and length wrapped by a Span cannot be changed after a Span has + * been created. When new values are required, simply create a new Span. Span + * has a method called Subspan() that works analogously to the Substring() + * method of XPCOM strings taking a start index and an optional length. As a + * Mozilla extension (relative to Microsoft's gsl::span that mozilla::Span is + * based on), Span has methods From(start), To(end) and FromTo(start, end) + * that correspond to Rust's &slice[start..], &slice[..end] and + * &slice[start..end], respectively. (That is, the end index is the index of + * the first element not to be included in the new subspan.) + * + * When indicating a Span that's only read from, const goes inside the type + * parameter. Don't put const in front of Span. That is: + * size_t ReadsFromOneSpanAndWritesToAnother(Span aReadFrom, + * Span aWrittenTo); + * + * Any Span can be viewed as Span using the function + * AsBytes(). Any Span can be viewed as Span using the function + * AsWritableBytes(). + */ +template +class Span { + public: + // constants and types + using element_type = ElementType; + using index_type = size_t; + using pointer = element_type*; + using reference = element_type&; + + using iterator = + span_details::span_iterator, false>; + using const_iterator = + span_details::span_iterator, true>; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + constexpr static const index_type extent = Extent; + + // [Span.cons], Span constructors, copy, assignment, and destructor + // "Dependent" is needed to make "span_details::enable_if_t<(Dependent || + // Extent == 0 || Extent == mozilla::MaxValue::value)>" SFINAE, + // since "span_details::enable_if_t<(Extent == 0 || Extent == + // mozilla::MaxValue::value)>" is ill-formed when Extent is neither + // of the extreme values. + /** + * Constructor with no args. + */ + template ::value)>> + constexpr Span() : storage_(nullptr, span_details::extent_type<0>()) {} + + /** + * Constructor for nullptr. + */ + constexpr MOZ_IMPLICIT Span(std::nullptr_t) : Span() {} + + /** + * Constructor for pointer and length. + */ + constexpr Span(pointer aPtr, index_type aLength) : storage_(aPtr, aLength) {} + + /** + * Constructor for start pointer and pointer past end. + */ + constexpr Span(pointer aStartPtr, pointer aEndPtr) + : storage_(aStartPtr, std::distance(aStartPtr, aEndPtr)) {} + + /** + * Constructor for C array. + */ + template + constexpr MOZ_IMPLICIT Span(element_type (&aArr)[N]) + : storage_(&aArr[0], span_details::extent_type()) {} + + // Implicit constructors for char* and char16_t* pointers are deleted in order + // to avoid accidental construction in cases where a pointer does not point to + // a zero-terminated string. A Span or Span can be + // obtained for const char* or const char16_t pointing to a zero-terminated + // string using the MakeStringSpan() function. + Span(char* aStr) = delete; + Span(const char* aStr) = delete; + Span(char16_t* aStr) = delete; + Span(const char16_t* aStr) = delete; + + /** + * Constructor for std::array. + */ + template > + constexpr MOZ_IMPLICIT Span(std::array& aArr) + : storage_(&aArr[0], span_details::extent_type()) {} + + /** + * Constructor for const std::array. + */ + template + constexpr MOZ_IMPLICIT Span( + const std::array, N>& aArr) + : storage_(&aArr[0], span_details::extent_type()) {} + + /** + * Constructor for mozilla::Array. + */ + template > + constexpr MOZ_IMPLICIT Span(mozilla::Array& aArr) + : storage_(&aArr[0], span_details::extent_type()) {} + + /** + * Constructor for const mozilla::Array. + */ + template + constexpr MOZ_IMPLICIT Span( + const mozilla::Array, N>& aArr) + : storage_(&aArr[0], span_details::extent_type()) {} + + /** + * Constructor for mozilla::UniquePtr holding an array and length. + */ + template > + constexpr Span(const mozilla::UniquePtr& aPtr, + index_type aLength) + : storage_(aPtr.get(), aLength) {} + + // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the + // requirement on Container to be a contiguous sequence container. + /** + * Constructor for standard-library containers. + */ + template < + class Container, + class = span_details::enable_if_t< + !span_details::is_span::value && + !span_details::is_std_array::value && + mozilla::IsConvertible::value && + mozilla::IsConvertible< + typename Container::pointer, + decltype(mozilla::DeclVal().data())>::value>> + constexpr MOZ_IMPLICIT Span(Container& cont) + : Span(cont.data(), ReleaseAssertedCast(cont.size())) {} + + /** + * Constructor for standard-library containers (const version). + */ + template < + class Container, + class = span_details::enable_if_t< + mozilla::IsConst::value && + !span_details::is_span::value && + mozilla::IsConvertible::value && + mozilla::IsConvertible< + typename Container::pointer, + decltype(mozilla::DeclVal().data())>::value>> + constexpr MOZ_IMPLICIT Span(const Container& cont) + : Span(cont.data(), ReleaseAssertedCast(cont.size())) {} + + /** + * Constructor from other Span. + */ + constexpr Span(const Span& other) = default; + + /** + * Constructor from other Span. + */ + constexpr Span(Span&& other) = default; + + /** + * Constructor from other Span with conversion of element type. + */ + template ::value && + span_details::is_allowed_element_type_conversion< + OtherElementType, element_type>::value>> + constexpr MOZ_IMPLICIT Span(const Span& other) + : storage_(other.data(), + span_details::extent_type(other.size())) {} + + /** + * Constructor from other Span with conversion of element type. + */ + template ::value && + span_details::is_allowed_element_type_conversion< + OtherElementType, element_type>::value>> + constexpr MOZ_IMPLICIT Span(Span&& other) + : storage_(other.data(), + span_details::extent_type(other.size())) {} + + ~Span() = default; + MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR Span& operator=(const Span& other) = + default; + + MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR Span& operator=(Span&& other) = + default; + + // [Span.sub], Span subviews + /** + * Subspan with first N elements with compile-time N. + */ + template + constexpr Span First() const { + MOZ_RELEASE_ASSERT(Count <= size()); + return {data(), Count}; + } + + /** + * Subspan with last N elements with compile-time N. + */ + template + constexpr Span Last() const { + const size_t len = size(); + MOZ_RELEASE_ASSERT(Count <= len); + return {data() + (len - Count), Count}; + } + + /** + * Subspan with compile-time start index and length. + */ + template + constexpr Span Subspan() const { + const size_t len = size(); + MOZ_RELEASE_ASSERT(Offset <= len && + (Count == dynamic_extent || (Offset + Count <= len))); + return {data() + Offset, Count == dynamic_extent ? len - Offset : Count}; + } + + /** + * Subspan with first N elements with run-time N. + */ + constexpr Span First(index_type aCount) const { + MOZ_RELEASE_ASSERT(aCount <= size()); + return {data(), aCount}; + } + + /** + * Subspan with last N elements with run-time N. + */ + constexpr Span Last(index_type aCount) const { + const size_t len = size(); + MOZ_RELEASE_ASSERT(aCount <= len); + return {data() + (len - aCount), aCount}; + } + + /** + * Subspan with run-time start index and length. + */ + constexpr Span Subspan( + index_type aStart, index_type aLength = dynamic_extent) const { + const size_t len = size(); + MOZ_RELEASE_ASSERT(aStart <= len && (aLength == dynamic_extent || + (aStart + aLength <= len))); + return {data() + aStart, + aLength == dynamic_extent ? len - aStart : aLength}; + } + + /** + * Subspan with run-time start index. (Rust's &foo[start..]) + */ + constexpr Span From(index_type aStart) const { + return Subspan(aStart); + } + + /** + * Subspan with run-time exclusive end index. (Rust's &foo[..end]) + */ + constexpr Span To(index_type aEnd) const { + return Subspan(0, aEnd); + } + + /** + * Subspan with run-time start index and exclusive end index. + * (Rust's &foo[start..end]) + */ + constexpr Span FromTo(index_type aStart, + index_type aEnd) const { + MOZ_RELEASE_ASSERT(aStart <= aEnd); + return Subspan(aStart, aEnd - aStart); + } + + // [Span.obs], Span observers + /** + * Number of elements in the span. + */ + constexpr index_type Length() const { return size(); } + + /** + * Number of elements in the span (standard-libray duck typing version). + */ + constexpr index_type size() const { return storage_.size(); } + + /** + * Size of the span in bytes. + */ + constexpr index_type LengthBytes() const { return size_bytes(); } + + /** + * Size of the span in bytes (standard-library naming style version). + */ + constexpr index_type size_bytes() const { + return size() * narrow_cast(sizeof(element_type)); + } + + /** + * Checks if the the length of the span is zero. + */ + constexpr bool IsEmpty() const { return empty(); } + + /** + * Checks if the the length of the span is zero (standard-libray duck + * typing version). + */ + constexpr bool empty() const { return size() == 0; } + + // [Span.elem], Span element access + constexpr reference operator[](index_type idx) const { + MOZ_RELEASE_ASSERT(idx < storage_.size()); + return data()[idx]; + } + + /** + * Access element of span by index (standard-library duck typing version). + */ + constexpr reference at(index_type idx) const { return this->operator[](idx); } + + constexpr reference operator()(index_type idx) const { + return this->operator[](idx); + } + + /** + * Pointer to the first element of the span. The return value is never + * nullptr, not ever for zero-length spans, so it can be passed as-is + * to std::slice::from_raw_parts() in Rust. + */ + constexpr pointer Elements() const { return data(); } + + /** + * Pointer to the first element of the span (standard-libray duck typing + * version). The return value is never nullptr, not ever for zero-length + * spans, so it can be passed as-is to std::slice::from_raw_parts() in Rust. + */ + constexpr pointer data() const { return storage_.data(); } + + // [Span.iter], Span iterator support + iterator begin() const { return {this, 0}; } + iterator end() const { return {this, Length()}; } + + const_iterator cbegin() const { return {this, 0}; } + const_iterator cend() const { return {this, Length()}; } + + reverse_iterator rbegin() const { return reverse_iterator{end()}; } + reverse_iterator rend() const { return reverse_iterator{begin()}; } + + const_reverse_iterator crbegin() const { + return const_reverse_iterator{cend()}; + } + const_reverse_iterator crend() const { + return const_reverse_iterator{cbegin()}; + } + + private: + // this implementation detail class lets us take advantage of the + // empty base class optimization to pay for only storage of a single + // pointer in the case of fixed-size Spans + template + class storage_type : public ExtentType { + public: + template + MOZ_SPAN_ASSERTION_CONSTEXPR storage_type(pointer elements, + OtherExtentType ext) + : ExtentType(ext) + // Replace nullptr with 0x1 for Rust slice compatibility. See + // https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html + , + data_(elements ? elements : reinterpret_cast(0x1)) { + const size_t extentSize = ExtentType::size(); + MOZ_RELEASE_ASSERT( + (!elements && extentSize == 0) || + (elements && extentSize != mozilla::MaxValue::value)); + } + + constexpr pointer data() const { return data_; } + + private: + pointer data_; + }; + + storage_type> storage_; +}; + +// [Span.comparison], Span comparison operators +template +inline constexpr bool operator==(const Span& l, + const Span& r) { + return (l.size() == r.size()) && std::equal(l.begin(), l.end(), r.begin()); +} + +template +inline constexpr bool operator!=(const Span& l, + const Span& r) { + return !(l == r); +} + +template +inline constexpr bool operator<(const Span& l, + const Span& r) { + return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); +} + +template +inline constexpr bool operator<=(const Span& l, + const Span& r) { + return !(l > r); +} + +template +inline constexpr bool operator>(const Span& l, + const Span& r) { + return r < l; +} + +template +inline constexpr bool operator>=(const Span& l, + const Span& r) { + return !(l < r); +} + +namespace span_details { +// if we only supported compilers with good constexpr support then +// this pair of classes could collapse down to a constexpr function + +// we should use a narrow_cast<> to go to size_t, but older compilers may not +// see it as constexpr and so will fail compilation of the template +template +struct calculate_byte_size + : mozilla::IntegralConstant( + sizeof(ElementType) * + static_cast(Extent))> {}; + +template +struct calculate_byte_size + : mozilla::IntegralConstant {}; +} // namespace span_details + +// [Span.objectrep], views of object representation +/** + * View span as Span. + */ +template +Span::value> +AsBytes(Span s) { + return {reinterpret_cast(s.data()), s.size_bytes()}; +} + +/** + * View span as Span. + */ +template < + class ElementType, size_t Extent, + class = span_details::enable_if_t::value>> +Span::value> +AsWritableBytes(Span s) { + return {reinterpret_cast(s.data()), s.size_bytes()}; +} + +// +// MakeSpan() - Utility functions for creating Spans +// +/** + * Create span from pointer and length. + */ +template +Span MakeSpan(ElementType* aPtr, + typename Span::index_type aLength) { + return Span(aPtr, aLength); +} + +/** + * Create span from start pointer and pointer past end. + */ +template +Span MakeSpan(ElementType* aStartPtr, ElementType* aEndPtr) { + return Span(aStartPtr, aEndPtr); +} + +/** + * Create span from C array. + * MakeSpan() does not permit creating Span objects from string literals (const + * char or char16_t arrays) because the Span length would include the zero + * terminator, which may surprise callers. Use MakeStringSpan() to create a + * Span whose length that excludes the string literal's zero terminator or use + * the MakeSpan() overload that accepts a pointer and length and specify the + * string literal's full length. + */ +template ::value && + !IsSame::value>> +Span MakeSpan(ElementType (&aArr)[N]) { + return Span(aArr, N); +} + +/** + * Create span from mozilla::Array. + */ +template +Span MakeSpan(mozilla::Array& aArr) { + return aArr; +} + +/** + * Create span from const mozilla::Array. + */ +template +Span MakeSpan(const mozilla::Array& arr) { + return arr; +} + +/** + * Create span from standard-library container. + */ +template +Span MakeSpan(Container& cont) { + return Span(cont); +} + +/** + * Create span from standard-library container (const version). + */ +template +Span MakeSpan(const Container& cont) { + return Span(cont); +} + +/** + * Create span from smart pointer and length. + */ +template +Span MakeSpan(Ptr& aPtr, size_t aLength) { + return Span(aPtr, aLength); +} + +/** + * Create span from C string. + */ +inline Span MakeStringSpan(const char* aZeroTerminated) { + return Span(aZeroTerminated, std::strlen(aZeroTerminated)); +} + +/** + * Create span from UTF-16 C string. + */ +inline Span MakeStringSpan(const char16_t* aZeroTerminated) { + return Span(aZeroTerminated, + span_details::strlen16(aZeroTerminated)); +} + +} // namespace mozilla + +#ifdef _MSC_VER +#if _MSC_VER < 1910 +#undef constexpr +#pragma pop_macro("constexpr") + +#endif // _MSC_VER < 1910 + +#pragma warning(pop) +#endif // _MSC_VER + +#undef MOZ_SPAN_ASSERTION_CONSTEXPR +#undef MOZ_SPAN_GCC_CONSTEXPR +#undef MOZ_SPAN_EXPLICITLY_DEFAULTED_CONSTEXPR +#undef MOZ_SPAN_CONSTEXPR_NOT_JUST_RETURN +#undef MOZ_SPAN_NON_CONST_CONSTEXPR + +#endif // mozilla_Span_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 @@ -17,29 +17,23 @@ namespace mozilla { -template +template class SplayTree; -template -class SplayTreeNode -{ -public: - template +template +class SplayTreeNode { + public: + template friend class SplayTree; - SplayTreeNode() - : mLeft(nullptr) - , mRight(nullptr) - , mParent(nullptr) - {} + SplayTreeNode() : mLeft(nullptr), mRight(nullptr), mParent(nullptr) {} -private: + private: T* mLeft; T* mRight; T* mParent; }; - /** * Class which represents a splay tree. * Splay trees are balanced binary search trees for which search, insert and @@ -50,23 +44,16 @@ * compare(const T&, const T&) method ordering the elements. The compare * method must be free from side effects. */ -template -class SplayTree -{ +template +class SplayTree { T* mRoot; -public: - constexpr SplayTree() - : mRoot(nullptr) - {} - - bool empty() const - { - return !mRoot; - } + public: + constexpr SplayTree() : mRoot(nullptr) {} - T* find(const T& aValue) - { + bool empty() const { return !mRoot; } + + T* find(const T& aValue) { if (empty()) { return nullptr; } @@ -76,8 +63,7 @@ return Comparator::compare(aValue, *last) == 0 ? last : nullptr; } - void insert(T* aValue) - { + void insert(T* aValue) { MOZ_ASSERT(!find(*aValue), "Duplicate elements are not allowed."); if (!mRoot) { @@ -88,13 +74,11 @@ int cmp = Comparator::compare(*aValue, *last); finishInsertion(last, cmp, aValue); - return; } T* findOrInsert(const T& aValue); - T* remove(const T& aValue) - { + T* remove(const T& aValue) { T* last = lookup(aValue); MOZ_ASSERT(last, "This tree must contain the element being removed."); MOZ_ASSERT(Comparator::compare(aValue, *last) == 0); @@ -152,8 +136,7 @@ return last; } - T* removeMin() - { + T* removeMin() { MOZ_ASSERT(mRoot, "No min to remove!"); T* min = mRoot; @@ -164,18 +147,14 @@ } // For testing purposes only. - void checkCoherency() - { - checkCoherency(mRoot, nullptr); - } + void checkCoherency() { checkCoherency(mRoot, nullptr); } -private: + private: /** * Returns the node in this comparing equal to |aValue|, or a node just * greater or just less than |aValue| if there is no such node. */ - T* lookup(const T& aValue) - { + T* lookup(const T& aValue) { MOZ_ASSERT(!empty()); T* node = mRoot; @@ -194,8 +173,7 @@ return parent; } - void 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!"); T** parentPointer = (aCmp < 0) ? &aLast->mLeft : &aLast->mRight; @@ -211,8 +189,7 @@ * the rotations in this fashion preserves the amortized balancing of * the tree. */ - void splay(T* aNode) - { + void splay(T* aNode) { MOZ_ASSERT(aNode); while (aNode != mRoot) { @@ -236,8 +213,7 @@ } } - void rotate(T* aNode) - { + void rotate(T* aNode) { // Rearrange nodes so that aNode becomes the parent of its current // parent, while preserving the sortedness of the tree. T* parent = aNode->mParent; @@ -274,8 +250,7 @@ } } - T* checkCoherency(T* aNode, T* aMinimum) - { + T* checkCoherency(T* aNode, T* aMinimum) { if (mRoot) { MOZ_RELEASE_ASSERT(!mRoot->mParent); } @@ -305,10 +280,8 @@ void operator=(const SplayTree&) = delete; }; -template -T* -SplayTree::findOrInsert(const T& aValue) -{ +template +T* SplayTree::findOrInsert(const T& aValue) { if (!mRoot) { mRoot = new T(aValue); return mRoot; @@ -325,6 +298,6 @@ return t; } -} /* namespace mozilla */ +} /* namespace mozilla */ #endif /* mozilla_SplayTree_h */ 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 @@ -18,18 +18,17 @@ #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; +MOZ_FORMAT_PRINTF(2, 0) +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, ...) -{ +int SprintfLiteral(char (&buffer)[N], const char* format, ...) { va_list args; va_start(args, format); int result = VsprintfLiteral(buffer, format, args); @@ -38,4 +37,4 @@ } #endif -#endif /* mozilla_Sprintf_h_ */ +#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 @@ -4,18 +4,16 @@ * 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/. */ -/* API for getting a stack trace of the C/C++ stack on the current thread */ +/* APIs for getting a stack trace of the current thread */ #ifndef mozilla_StackWalk_h #define mozilla_StackWalk_h -/* WARNING: This file is intended to be included from C or C++ files. */ - #include "mozilla/Types.h" #include /** - * The callback for MozStackWalk. + * The callback for MozStackWalk and MozStackWalkThread. * * @param aFrameNumber The frame number (starts at 1, not 0). * @param aPC The program counter value. @@ -23,14 +21,14 @@ * pointer will be pointing to when the execution returns * to executing that at aPC. If no approximation can * be made it will be nullptr. - * @param aClosure Extra data passed in via MozStackWalk(). + * @param aClosure Extra data passed in from MozStackWalk() or + * MozStackWalkThread(). */ -typedef void -(*MozWalkStackCallback)(uint32_t aFrameNumber, void* aPC, void* aSP, - void* aClosure); +typedef void (*MozWalkStackCallback)(uint32_t aFrameNumber, void* aPC, + void* aSP, void* aClosure); /** - * Call aCallback for the C/C++ stack frames on the current thread, from + * Call aCallback for each stack frame on the current thread, from * the caller of MozStackWalk to main (or above). * * @param aCallback Callback function, called once per frame. @@ -39,27 +37,47 @@ * MozStackWalk. * @param aMaxFrames Maximum number of frames to trace. 0 means no limit. * @param aClosure Caller-supplied data passed through to aCallback. - * @param aThread The thread for which the stack is to be retrieved. - * Passing null causes us to walk the stack of the - * current thread. On Windows, this is a thread HANDLE. - * It is currently not supported on any other platform. - * @param aPlatformData Platform specific data that can help in walking the - * stack, this should be nullptr unless you really know - * what you're doing! This needs to be a pointer to a - * CONTEXT on Windows and should not be passed on other - * platforms. * * May skip some stack frames due to compiler optimizations or code * generation. - * */ -MFBT_API bool -MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames, - uint32_t aMaxFrames, void* aClosure, uintptr_t aThread, - void* aPlatformData); +MFBT_API void MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames, + uint32_t aMaxFrames, void* aClosure); + +#if defined(_WIN32) && \ + (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_IA64)) + +#include + +#define MOZ_STACKWALK_SUPPORTS_WINDOWS 1 + +/** + * Like MozStackWalk, but walks the stack for another thread. + * Call aCallback for each stack frame on the current thread, from + * the caller of MozStackWalk to main (or above). + * + * @param aCallback Same as for MozStackWalk(). + * @param aSkipFrames Same as for MozStackWalk(). + * @param aMaxFrames Same as for MozStackWalk(). + * @param aClosure Same as for MozStackWalk(). + * @param aThread The handle of the thread whose stack is to be walked. + * If 0, walks the current thread. + * @param aContext A CONTEXT, presumably obtained with GetThreadContext() + * after suspending the thread with SuspendThread(). If + * null, the CONTEXT will be re-obtained. + */ +MFBT_API void MozStackWalkThread(MozWalkStackCallback aCallback, + uint32_t aSkipFrames, uint32_t aMaxFrames, + void* aClosure, HANDLE aThread, + CONTEXT* aContext); + +#else + +#define MOZ_STACKWALK_SUPPORTS_WINDOWS 0 + +#endif -typedef struct -{ +typedef struct { /* * The name of the shared library or executable containing an * address and the address's offset within that library, or empty @@ -89,8 +107,8 @@ * @param aPC The code address. * @param aDetails A structure to be filled in with the result. */ -MFBT_API bool -MozDescribeCodeAddress(void* aPC, MozCodeAddressDetails* aDetails); +MFBT_API bool MozDescribeCodeAddress(void* aPC, + MozCodeAddressDetails* aDetails); /** * Format the information about a code address in a format suitable for @@ -118,11 +136,11 @@ * @param aFileName The filename. Possibly null or the empty string. * @param aLineNo The line number. Possibly zero. */ -MFBT_API void -MozFormatCodeAddress(char* aBuffer, uint32_t aBufferSize, uint32_t aFrameNumber, - const void* aPC, const char* aFunction, - const char* aLibrary, ptrdiff_t aLOffset, - const char* aFileName, uint32_t aLineNo); +MFBT_API void MozFormatCodeAddress(char* aBuffer, uint32_t aBufferSize, + uint32_t aFrameNumber, const void* aPC, + const char* aFunction, const char* aLibrary, + ptrdiff_t aLOffset, const char* aFileName, + uint32_t aLineNo); /** * Format the information about a code address in the same fashion as @@ -139,25 +157,17 @@ * @param aPC The code address. * @param aDetails The value filled in by MozDescribeCodeAddress(aPC). */ -MFBT_API void -MozFormatCodeAddressDetails(char* aBuffer, uint32_t aBufferSize, - uint32_t aFrameNumber, void* aPC, - const MozCodeAddressDetails* aDetails); +MFBT_API void MozFormatCodeAddressDetails( + char* aBuffer, uint32_t aBufferSize, uint32_t aFrameNumber, void* aPC, + const MozCodeAddressDetails* aDetails); namespace mozilla { -MFBT_API bool -FramePointerStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames, - uint32_t aMaxFrames, void* aClosure, void** aBp, - void* aStackEnd); - -} // namespace mozilla +MFBT_API void FramePointerStackWalk(MozWalkStackCallback aCallback, + uint32_t aSkipFrames, uint32_t aMaxFrames, + void* aClosure, void** aBp, + void* aStackEnd); -/** - * Initialize the critical sections for this platform so that we can - * abort stack walks when needed. - */ -MFBT_API void -StackWalkInitCriticalAddress(void); +} // namespace mozilla #endif 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 @@ -3,19 +3,21 @@ #include "mozilla/Types.h" +#ifdef _M_AMD64 /** * 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(); +struct MOZ_RAII AutoSuppressStackWalking { + MFBT_API AutoSuppressStackWalking(); + MFBT_API ~AutoSuppressStackWalking(); +}; -MFBT_API bool -TryAcquireStackWalkWorkaroundLock(); +MFBT_API void RegisterJitCodeRegion(uint8_t* aStart, size_t size); -MFBT_API void -ReleaseStackWalkWorkaroundLock(); +MFBT_API void UnregisterJitCodeRegion(uint8_t* aStart, size_t size); +#endif // _M_AMD64 -#endif // mozilla_StackWalk_windows_h +#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 @@ -21,10 +21,22 @@ #ifdef MOZ_CLANG_PLUGIN #ifdef __cplusplus +/** + * MOZ_KnownLive - used to opt an argument out of the CanRunScript checker so + * that we don't check it if is a strong ref. + * + * Example: + * canRunScript(MOZ_KnownLive(rawPointer)); + */ +template +static MOZ_ALWAYS_INLINE T* MOZ_KnownLive(T* ptr) { + return ptr; +} + extern "C" { #endif -/* +/** * MOZ_AssertAssignmentTest - used in MOZ_ASSERT in order to test the possible * presence of assignment instead of logical comparisons. * @@ -44,6 +56,7 @@ #else #define MOZ_CHECK_ASSERT_ASSIGNMENT(expr) (!!(expr)) +#define MOZ_KnownLive(expr) (expr) #endif /* MOZ_CLANG_PLUGIN */ -#endif /* StaticAnalysisFunctions_h */ \ No newline at end of file +#endif /* StaticAnalysisFunctions_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TaggedAnonymousMemory.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TaggedAnonymousMemory.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TaggedAnonymousMemory.h @@ -45,42 +45,34 @@ extern "C" { #endif -MFBT_API void -MozTagAnonymousMemory(const void* aPtr, size_t aLength, const char* aTag); +MFBT_API void MozTagAnonymousMemory(const void* aPtr, size_t aLength, + const char* aTag); -MFBT_API void* -MozTaggedAnonymousMmap(void* aAddr, size_t aLength, int aProt, int aFlags, - int aFd, off_t aOffset, const char* aTag); +MFBT_API void* MozTaggedAnonymousMmap(void* aAddr, size_t aLength, int aProt, + int aFlags, int aFd, off_t aOffset, + const char* aTag); -MFBT_API int -MozTaggedMemoryIsSupported(void); +MFBT_API int MozTaggedMemoryIsSupported(void); #ifdef __cplusplus -} // extern "C" +} // extern "C" #endif -#else // ANDROID +#else // ANDROID -static inline void -MozTagAnonymousMemory(const void* aPtr, size_t aLength, const char* aTag) -{ -} +static inline void MozTagAnonymousMemory(const void* aPtr, size_t aLength, + const char* aTag) {} -static inline void* -MozTaggedAnonymousMmap(void* aAddr, size_t aLength, int aProt, int aFlags, - int aFd, off_t aOffset, const char* aTag) -{ +static inline void* MozTaggedAnonymousMmap(void* aAddr, size_t aLength, + int aProt, int aFlags, int aFd, + off_t aOffset, const char* aTag) { return mmap(aAddr, aLength, aProt, aFlags, aFd, aOffset); } -static inline int -MozTaggedMemoryIsSupported(void) -{ - return 0; -} +static inline int MozTaggedMemoryIsSupported(void) { return 0; } -#endif // ANDROID +#endif // ANDROID -#endif // !XP_WIN +#endif // !XP_WIN -#endif // mozilla_TaggedAnonymousMemory_h +#endif // mozilla_TaggedAnonymousMemory_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TemplateLib.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TemplateLib.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/TemplateLib.h @@ -27,49 +27,60 @@ namespace tl { /** Compute min/max. */ -template -struct Min -{ - static const size_t value = I < J ? I : J; -}; -template -struct Max -{ - static const size_t value = I > J ? I : J; +template +struct Min { + static constexpr size_t value = + Size < Min::value ? Size : Min::value; +}; + +template +struct Min { + static constexpr size_t value = Size; +}; + +template +struct Max { + static constexpr size_t value = + Size > Max::value ? Size : Max::value; +}; + +template +struct Max { + static constexpr size_t value = Size; }; /** Compute floor(log2(i)). */ -template -struct FloorLog2 -{ +template +struct FloorLog2 { static const size_t value = 1 + FloorLog2::value; }; -template<> struct FloorLog2<0> { /* Error */ }; -template<> struct FloorLog2<1> { static const size_t value = 0; }; +template <> +struct FloorLog2<0> { /* Error */ +}; +template <> +struct FloorLog2<1> { + static const size_t value = 0; +}; /** Compute ceiling(log2(i)). */ -template -struct CeilingLog2 -{ +template +struct CeilingLog2 { static const size_t value = FloorLog2<2 * I - 1>::value; }; /** Round up to the nearest power of 2. */ -template -struct RoundUpPow2 -{ +template +struct RoundUpPow2 { static const size_t value = size_t(1) << CeilingLog2::value; }; -template<> -struct RoundUpPow2<0> -{ +template <> +struct RoundUpPow2<0> { static const size_t value = 1; }; /** Compute the number of bits in the given unsigned type. */ -template -struct BitSize -{ +template +struct BitSize { static const size_t value = sizeof(T) * CHAR_BIT; }; @@ -77,20 +88,18 @@ * Produce an N-bit mask, where N <= BitSize::value. Handle the * language-undefined edge case when N = BitSize::value. */ -template -struct NBitMask -{ +template +struct NBitMask { // Assert the precondition. On success this evaluates to 0. Otherwise it // triggers divide-by-zero at compile time: a guaranteed compile error in // C++11, and usually one in C++98. Add this value to |value| to assure // its computation. static const size_t checkPrecondition = - 0 / size_t(N < BitSize::value); + 0 / size_t(N < BitSize::value); static const size_t value = (size_t(1) << N) - 1 + checkPrecondition; }; -template<> -struct NBitMask::value> -{ +template <> +struct NBitMask::value> { static const size_t value = size_t(-1); }; @@ -98,14 +107,18 @@ * For the unsigned integral type size_t, compute a mask M for N such that * for all X, !(X & M) implies X * N will not overflow (w.r.t size_t) */ -template -struct MulOverflowMask -{ +template +struct MulOverflowMask { static const size_t value = - ~NBitMask::value - CeilingLog2::value>::value; + ~NBitMask::value - CeilingLog2::value>::value; +}; +template <> +struct MulOverflowMask<0> { /* Error */ +}; +template <> +struct MulOverflowMask<1> { + static const size_t value = 0; }; -template<> struct MulOverflowMask<0> { /* Error */ }; -template<> struct MulOverflowMask<1> { static const size_t value = 0; }; /** * And computes the logical 'and' of its argument booleans. @@ -116,18 +129,17 @@ * mozilla::t1::And<>::value is true. */ -template +template struct And; -template<> -struct And<> : public TrueType { }; +template <> +struct And<> : public TrueType {}; -template -struct And - : public Conditional, FalseType>::Type { }; +template +struct And : public Conditional, FalseType>::Type {}; -} // namespace tl +} // namespace tl -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_TemplateLib_h */ 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 @@ -15,26 +15,27 @@ namespace detail { -template -class MakeUnsignedChar - : public MakeUnsigned -{}; - -template<> -class MakeUnsignedChar -{ -public: +template +class MakeUnsignedChar : public MakeUnsigned {}; + +template <> +class MakeUnsignedChar { + public: using Type = char16_t; }; -template<> -class MakeUnsignedChar -{ -public: +template <> +class MakeUnsignedChar { + public: using Type = char32_t; }; -} // namespace detail +template +constexpr bool IsAsciiAlpha(Char aChar) { + return ('a' <= aChar && aChar <= 'z') || ('A' <= aChar && aChar <= 'Z'); +} + +} // namespace detail /** * Returns true iff |aChar| matches [a-zA-Z]. @@ -42,17 +43,12 @@ * 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'); +template +constexpr bool IsAsciiAlpha(Char aChar) { + return detail::IsAsciiAlpha( + static_cast::Type>(aChar)); } -} // namespace mozilla +} // 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 @@ -9,22 +9,8 @@ #ifndef mozilla_ThreadLocal_h #define mozilla_ThreadLocal_h -#if defined(XP_WIN) -// This file will get included in any file that wants to add a profiler mark. -// In order to not bring together we could include windef.h and -// winbase.h which are sufficient to get the prototypes for the Tls* functions. -// # include -// # include -// Unfortunately, even including these headers causes us to add a bunch of ugly -// stuff to our namespace e.g #define CreateEvent CreateEventW -extern "C" { -__declspec(dllimport) void* __stdcall TlsGetValue(unsigned long); -__declspec(dllimport) int __stdcall TlsSetValue(unsigned long, void*); -__declspec(dllimport) unsigned long __stdcall TlsAlloc(); -} -#else -# include -# include +#if !defined(XP_WIN) +#include #endif #include "mozilla/Assertions.h" @@ -33,19 +19,14 @@ namespace mozilla { -// sig_safe_t denotes an atomic type which can be read or stored in a single -// instruction. This means that data of this type is safe to be manipulated -// from a signal handler, or other similar asynchronous execution contexts. -#if defined(XP_WIN) -typedef unsigned long sig_safe_t; -#else -typedef sig_atomic_t sig_safe_t; -#endif - namespace detail { -#if defined(HAVE_THREAD_TLS_KEYWORD) -#define MOZ_HAS_THREAD_LOCAL +#ifdef XP_MACOSX +#if defined(__has_feature) +#if __has_feature(cxx_thread_local) +#define MACOSX_HAS_THREAD_LOCAL +#endif +#endif #endif /* @@ -87,69 +68,120 @@ * // Get the TLS value * int value = tlsKey.get(); */ -template -class ThreadLocal -{ -#ifndef MOZ_HAS_THREAD_LOCAL + +// Integral types narrower than void* must be extended to avoid +// warnings from valgrind on some platforms. This helper type +// achieves that without penalizing the common case of ThreadLocals +// instantiated using a pointer type. +template +struct Helper { + typedef uintptr_t Type; +}; + +template +struct Helper { + typedef S* Type; +}; + #if defined(XP_WIN) - typedef unsigned long key_t; -#else - typedef pthread_key_t key_t; -#endif +/* + * ThreadLocalKeyStorage uses Thread Local APIs that are declared in + * processthreadsapi.h. To use this class on Windows, include that file + * (or windows.h) before including ThreadLocal.h. + * + * TLS_OUT_OF_INDEXES is a #define that is used to detect whether + * an appropriate header has been included prior to this file + */ +#if defined(TLS_OUT_OF_INDEXES) +/* Despite not being used for MOZ_THREAD_LOCAL, we expose an implementation for + * Windows for cases where it's not desirable to use thread_local */ +template +class ThreadLocalKeyStorage { + public: + ThreadLocalKeyStorage() : mKey(TLS_OUT_OF_INDEXES) {} + + inline bool initialized() const { return mKey != TLS_OUT_OF_INDEXES; } + + inline void init() { mKey = TlsAlloc(); } + + inline T get() const { + void* h = TlsGetValue(mKey); + return static_cast(reinterpret_cast::Type>(h)); + } - // Integral types narrower than void* must be extended to avoid - // warnings from valgrind on some platforms. This helper type - // achieves that without penalizing the common case of ThreadLocals - // instantiated using a pointer type. - template - struct Helper - { - typedef uintptr_t Type; - }; - - template - struct Helper - { - typedef S *Type; - }; -#endif + inline bool set(const T aValue) { + void* h = + reinterpret_cast(static_cast::Type>(aValue)); + return TlsSetValue(mKey, h); + } - bool initialized() const { -#ifdef MOZ_HAS_THREAD_LOCAL - return true; -#else - return mInited; + private: + unsigned long mKey; +}; #endif +#else +template +class ThreadLocalKeyStorage { + public: + constexpr ThreadLocalKeyStorage() : mKey(0), mInited(false) {} + + inline bool initialized() const { return mInited; } + + inline void init() { mInited = !pthread_key_create(&mKey, nullptr); } + + inline T get() const { + void* h = pthread_getspecific(mKey); + return static_cast(reinterpret_cast::Type>(h)); } -public: + inline bool set(const T aValue) { + void* h = + reinterpret_cast(static_cast::Type>(aValue)); + return !pthread_setspecific(mKey, h); + } + + private: + pthread_key_t mKey; + bool mInited; +}; +#endif + +template +class ThreadLocalNativeStorage { + public: // __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 + inline bool initialized() const { return true; } + + inline void init() {} + + inline T get() const { return mValue; } + + inline bool set(const T aValue) { + mValue = aValue; + return true; + } + private: + T mValue; +}; + +template class Storage> +class ThreadLocal : public Storage { + public: MOZ_MUST_USE inline bool init(); + void infallibleInit() { + MOZ_RELEASE_ASSERT(init(), "Infallible TLS initialization failed"); + } + inline T get() const; inline void set(const T aValue); - -private: -#ifdef MOZ_HAS_THREAD_LOCAL - T mValue; -#else - key_t mKey; - bool mInited; -#endif }; -template -inline bool -ThreadLocal::init() -{ +template class Storage> +inline bool ThreadLocal::init() { static_assert(mozilla::IsPointer::value || mozilla::IsIntegral::value, "mozilla::ThreadLocal must be used with a pointer or " "integral type"); @@ -157,66 +189,42 @@ "mozilla::ThreadLocal can't be used for types larger than " "a pointer"); -#ifdef MOZ_HAS_THREAD_LOCAL - return true; -#else - if (!initialized()) { -#ifdef XP_WIN - mKey = TlsAlloc(); - mInited = mKey != 0xFFFFFFFFUL; // TLS_OUT_OF_INDEXES -#else - mInited = !pthread_key_create(&mKey, nullptr); -#endif + if (!Storage::initialized()) { + Storage::init(); } - return mInited; -#endif + return Storage::initialized(); } -template -inline T -ThreadLocal::get() const -{ -#ifdef MOZ_HAS_THREAD_LOCAL - return mValue; -#else - MOZ_ASSERT(initialized()); - void* h; -#ifdef XP_WIN - h = TlsGetValue(mKey); -#else - h = pthread_getspecific(mKey); -#endif - return static_cast(reinterpret_cast::Type>(h)); -#endif +template class Storage> +inline T ThreadLocal::get() const { + MOZ_ASSERT(Storage::initialized()); + return Storage::get(); } -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 - bool succeeded = TlsSetValue(mKey, h); -#else - bool succeeded = !pthread_setspecific(mKey, h); -#endif +template class Storage> +inline void ThreadLocal::set(const T aValue) { + MOZ_ASSERT(Storage::initialized()); + bool succeeded = Storage::set(aValue); if (!succeeded) { MOZ_CRASH(); } -#endif } -#ifdef MOZ_HAS_THREAD_LOCAL -#define MOZ_THREAD_LOCAL(TYPE) __thread mozilla::detail::ThreadLocal +#if (defined(XP_WIN) || defined(MACOSX_HAS_THREAD_LOCAL)) && \ + !defined(__MINGW32__) +#define MOZ_THREAD_LOCAL(TYPE) \ + thread_local mozilla::detail::ThreadLocal< \ + TYPE, mozilla::detail::ThreadLocalNativeStorage> +#elif defined(HAVE_THREAD_TLS_KEYWORD) +#define MOZ_THREAD_LOCAL(TYPE) \ + __thread mozilla::detail::ThreadLocal< \ + TYPE, mozilla::detail::ThreadLocalNativeStorage> #else -#define MOZ_THREAD_LOCAL(TYPE) mozilla::detail::ThreadLocal +#define MOZ_THREAD_LOCAL(TYPE) \ + mozilla::detail::ThreadLocal #endif -} // namespace detail -} // namespace mozilla +} // namespace detail +} // namespace mozilla #endif /* mozilla_ThreadLocal_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ThreadSafeWeakPtr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ThreadSafeWeakPtr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ThreadSafeWeakPtr.h @@ -0,0 +1,346 @@ +/* -*- 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 thread-safe weak pointer */ + +/** + * Derive from SupportsThreadSafeWeakPtr to allow thread-safe weak pointers to + * an atomically refcounted derived class. These thread-safe weak pointers may + * be safely accessed and converted to strong pointers on multiple threads. + * + * Note that SupportsThreadSafeWeakPtr necessarily already inherits from + * AtomicRefCounted, so you should not separately inherit from AtomicRefCounted. + * + * ThreadSafeWeakPtr and its implementation is distinct from the normal WeakPtr + * which is not thread-safe. The interface discipline and implementation details + * are different enough that these two implementations are separated for now for + * efficiency reasons. If you don't actually need to use weak pointers on + * multiple threads, you can just use WeakPtr instead. + * + * When deriving from SupportsThreadSafeWeakPtr, you should add + * MOZ_DECLARE_THREADSAFEWEAKREFERENCE_TYPENAME(ClassName) and + * MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public section of your + * class, where ClassName is the name of your class. + * + * Example usage: + * + * class C : public SupportsThreadSafeWeakPtr + * { + * public: + * MOZ_DECLARE_THREADSAFEWEAKREFERENCE_TYPENAME(C) + * MOZ_DECLARE_REFCOUNTED_TYPENAME(C) + * void doStuff(); + * }; + * + * ThreadSafeWeakPtr weak; + * { + * RefPtr strong = new C; + * if (strong) { + * strong->doStuff(); + * } + * // Make a new weak reference to the object from the strong reference. + * weak = strong; + * } + * MOZ_ASSERT(!bool(weak), "Weak pointers are cleared after all " + * "strong references are released."); + * + * // Convert the weak reference to a strong reference for usage. + * RefPtr other(weak); + * if (other) { + * other->doStuff(); + * } + */ + +#ifndef mozilla_ThreadSafeWeakPtr_h +#define mozilla_ThreadSafeWeakPtr_h + +#include "mozilla/Assertions.h" +#include "mozilla/Atomics.h" +#include "mozilla/RefCounted.h" +#include "mozilla/RefPtr.h" +#include "mozilla/TypeTraits.h" +#include "mozilla/Unused.h" + +#include + +namespace mozilla { + +template +class ThreadSafeWeakPtr; +template +class SupportsThreadSafeWeakPtr; + +#ifdef MOZ_REFCOUNTED_LEAK_CHECKING +#define MOZ_DECLARE_THREADSAFEWEAKREFERENCE_TYPENAME(T) \ + static const char* threadSafeWeakReferenceTypeName() { \ + return "ThreadSafeWeakReference<" #T ">"; \ + } +#else +#define MOZ_DECLARE_THREADSAFEWEAKREFERENCE_TYPENAME(T) +#endif + +namespace detail { + +// A multiple reader, single writer spin-lock. +// This lock maintains an atomic counter which is incremented every time the +// lock is acquired reading. So long as the counter remains positive, it may be +// incremented for reading multiple times. When acquiring the lock for writing, +// we must ensure the counter is 0 (no readers), and if so, set it to a negative +// value to indicate that no new readers may take the lock. +class ReadWriteSpinLock { + // Only need a type large enough to represent the number of simultaneously + // accessing threads. + typedef int32_t CounterType; + + public: + // Try to increment the counter for reading, so long as it is positive. + void readLock() { + for (;;) { + CounterType oldCounter = + mCounter & std::numeric_limits::max(); + CounterType newCounter = oldCounter + 1; + if (mCounter.compareExchange(oldCounter, newCounter)) { + break; + } + } + } + + // Decrement the counter to remove a read lock. + void readUnlock() { mCounter--; } + + // Try to acquire the write lock, but only if there are no readers. + // If successful, sets the counter to a negative value. + bool tryWriteLock() { + return mCounter.compareExchange(0, std::numeric_limits::min()); + } + + // Reset the counter to 0. + void writeUnlock() { mCounter = 0; } + + private: + Atomic mCounter; +}; + +// A shared weak reference that is used to track a SupportsThreadSafeWeakPtr +// object. It guards access to that object via a read-write spinlock. +template +class ThreadSafeWeakReference + : public external::AtomicRefCounted> { + public: + typedef T ElementType; + + explicit ThreadSafeWeakReference(T* aPtr) { mPtr = aPtr; } + +#ifdef MOZ_REFCOUNTED_LEAK_CHECKING + const char* typeName() const { + // The first time this is called mPtr is null, so don't + // invoke any methods on mPtr. + return T::threadSafeWeakReferenceTypeName(); + } + size_t typeSize() const { return sizeof(*this); } +#endif + + private: + friend class mozilla::SupportsThreadSafeWeakPtr; + template + friend class mozilla::ThreadSafeWeakPtr; + + // Does an unsafe read of the raw weak pointer. + T* get() const { return mPtr; } + + // Creates a new RefPtr to the tracked object. + // We need to acquire the read lock while we do this, as we need to atomically + // both read the pointer and then increment the refcount on it within the + // scope of the lock. This guards against the object being destroyed while in + // the middle of creating the new RefPtr. + already_AddRefed getRefPtr() { + mLock.readLock(); + RefPtr result(get()); + mLock.readUnlock(); + return result.forget(); + } + + // Try to detach the weak reference from the tracked object. + // We need to acquire the write lock while we do this, to ensure that no + // RefPtr is created to this while detaching. Once acquired, it is safe + // to check the refcount and verify that this is the last reference to + // the tracked object, so the weak reference can be safely detached. + void tryDetach(const SupportsThreadSafeWeakPtr* aOwner) { + if (mLock.tryWriteLock()) { + if (aOwner->hasOneRef()) { + mPtr = nullptr; + } + mLock.writeUnlock(); + } + } + + ReadWriteSpinLock mLock; + Atomic mPtr; +}; + +} // namespace detail + +template +class SupportsThreadSafeWeakPtr : public external::AtomicRefCounted { + protected: + typedef external::AtomicRefCounted AtomicRefCounted; + typedef detail::ThreadSafeWeakReference ThreadSafeWeakReference; + + public: + ~SupportsThreadSafeWeakPtr() { + // Clean up the shared weak reference if one exists. + if (ThreadSafeWeakReference* ptr = mRef) { + ptr->Release(); + } + } + + void Release() const { + // If there is only one remaining reference to the object when trying to + // release, then attempt to detach it from its weak reference. New + // references could possibly be created to the object while this happens, so + // take care to do this atomically inside tryDetach. + if (AtomicRefCounted::hasOneRef()) { + if (ThreadSafeWeakReference* ptr = mRef) { + ptr->tryDetach(this); + } + } + + // Once possibly detached, it is now safe to continue to decrement the + // refcount. + AtomicRefCounted::Release(); + } + + private: + template + friend class ThreadSafeWeakPtr; + + // Creates a shared weak reference for the object if one does not exist. Note + // that the object may be of an actual derived type U, but the weak reference + // is created for the supplied type T of SupportsThreadSafeWeakPtr. + already_AddRefed getThreadSafeWeakReference() { + static_assert(IsBaseOf, T>::value, + "T must derive from SupportsThreadSafeWeakPtr"); + + if (!mRef) { + RefPtr ptr( + new ThreadSafeWeakReference(static_cast(this))); + // Only set the new weak reference if one does not exist (== nullptr). + // If there is already a weak reference, just let this superflous weak + // reference get destroyed when it goes out of scope. + if (mRef.compareExchange(nullptr, ptr)) { + // If successful, forget the refcount so that the weak reference stays + // alive. + Unused << ptr.forget(); + } + } + + // Create a new RefPtr to weak reference. + RefPtr ptr(mRef); + return ptr.forget(); + } + + Atomic mRef; +}; + +// A thread-safe variant of a weak pointer +template +class ThreadSafeWeakPtr { + // Be careful to use the weak reference type T in the + // SupportsThreadSafeWeakPtr definition. + typedef typename T::ThreadSafeWeakReference ThreadSafeWeakReference; + + public: + ThreadSafeWeakPtr() {} + + ThreadSafeWeakPtr& operator=(const ThreadSafeWeakPtr& aOther) { + mRef = aOther.mRef; + return *this; + } + + ThreadSafeWeakPtr(const ThreadSafeWeakPtr& aOther) : mRef(aOther.mRef) {} + + ThreadSafeWeakPtr& operator=(ThreadSafeWeakPtr&& aOther) { + mRef = aOther.mRef.forget(); + return *this; + } + + ThreadSafeWeakPtr(ThreadSafeWeakPtr&& aOther) : mRef(aOther.mRef.forget()) {} + + ThreadSafeWeakPtr& operator=(const RefPtr& aOther) { + if (aOther) { + // Get the underlying shared weak reference to the object, creating one if + // necessary. + mRef = aOther->getThreadSafeWeakReference(); + } else { + mRef = nullptr; + } + return *this; + } + + explicit ThreadSafeWeakPtr(const RefPtr& aOther) { *this = aOther; } + + ThreadSafeWeakPtr& operator=(decltype(nullptr)) { + mRef = nullptr; + return *this; + } + + explicit ThreadSafeWeakPtr(decltype(nullptr)) {} + + explicit operator bool() const { return !!get(); } + + bool operator==(const ThreadSafeWeakPtr& aOther) const { + return get() == aOther.get(); + } + + bool operator==(const RefPtr& aOther) const { + return get() == aOther.get(); + } + + bool operator==(const T* aOther) const { return get() == aOther; } + + template + bool operator!=(const U& aOther) const { + return !(*this == aOther); + } + + // Convert the weak pointer to a strong RefPtr. + explicit operator RefPtr() const { return getRefPtr(); } + + private: + // Gets a new strong reference of the proper type T to the tracked object. + already_AddRefed getRefPtr() const { + static_assert( + IsBaseOf::value, + "T must derive from ThreadSafeWeakReference::ElementType"); + return mRef ? mRef->getRefPtr().template downcast() : nullptr; + } + + // Get a pointer to the tracked object, downcasting to the proper type T. + // Note that this operation is unsafe as it may cause races if downwind + // code depends on the value not to change after reading. + T* get() const { + static_assert( + IsBaseOf::value, + "T must derive from ThreadSafeWeakReference::ElementType"); + return mRef ? static_cast(mRef->get()) : nullptr; + } + + // A shared weak reference to an object. Note that this may be null so as to + // save memory (at the slight cost of an extra null check) if no object is + // being tracked. + RefPtr mRef; +}; + +} // namespace mozilla + +template +inline already_AddRefed do_AddRef( + const mozilla::ThreadSafeWeakPtr& aObj) { + RefPtr ref(aObj); + return ref.forget(); +} + +#endif /* mozilla_ThreadSafeWeakPtr_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 @@ -8,6 +8,8 @@ #define mozilla_TimeStamp_h #include +#include // for std::min, std::max +#include #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/FloatingPoint.h" @@ -15,8 +17,9 @@ #include "mozilla/Types.h" namespace IPC { -template struct ParamTraits; -} // namespace IPC +template +struct ParamTraits; +} // namespace IPC #ifdef XP_WIN // defines TimeStampValue as a complex value keeping both @@ -35,9 +38,8 @@ /** * Platform-specific implementation details of BaseTimeDuration. */ -class BaseTimeDurationPlatformUtils -{ -public: +class BaseTimeDurationPlatformUtils { + public: static MFBT_API double ToSeconds(int64_t aTicks); static MFBT_API double ToSecondsSigDigits(int64_t aTicks); static MFBT_API int64_t TicksFromMilliseconds(double aMilliseconds); @@ -58,16 +60,14 @@ * operations are performed on the integer count of ticks (mValue). */ template -class BaseTimeDuration -{ -public: +class BaseTimeDuration { + public: // The default duration is 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; - MOZ_IMPLICIT BaseTimeDuration(_SomethingVeryRandomHere* aZero) : mValue(0) - { + MOZ_IMPLICIT BaseTimeDuration(_SomethingVeryRandomHere* aZero) : mValue(0) { MOZ_ASSERT(!aZero, "Who's playing funny games here?"); } // Default copy-constructor and assignment are OK @@ -75,18 +75,15 @@ // Converting copy-constructor and assignment operator template explicit BaseTimeDuration(const BaseTimeDuration& aOther) - : mValue(aOther.mValue) - { } + : mValue(aOther.mValue) {} template - BaseTimeDuration& operator=(const BaseTimeDuration& aOther) - { + BaseTimeDuration& operator=(const BaseTimeDuration& aOther) { mValue = aOther.mValue; return *this; } - double ToSeconds() const - { + double ToSeconds() const { if (mValue == INT64_MAX) { return PositiveInfinity(); } @@ -98,8 +95,7 @@ // Return a duration value that includes digits of time we think to // be significant. This method should be used when displaying a // time to humans. - double ToSecondsSigDigits() const - { + double ToSecondsSigDigits() const { if (mValue == INT64_MAX) { return PositiveInfinity(); } @@ -116,12 +112,10 @@ // mValue do not allow us to represent durations of that length, // long durations are clamped to the max/min representable value // instead of overflowing. - static inline BaseTimeDuration FromSeconds(double aSeconds) - { + static inline BaseTimeDuration FromSeconds(double aSeconds) { return FromMilliseconds(aSeconds * 1000.0); } - static BaseTimeDuration FromMilliseconds(double aMilliseconds) - { + static BaseTimeDuration FromMilliseconds(double aMilliseconds) { if (aMilliseconds == PositiveInfinity()) { return Forever(); } @@ -129,38 +123,29 @@ return FromTicks(INT64_MIN); } return FromTicks( - BaseTimeDurationPlatformUtils::TicksFromMilliseconds(aMilliseconds)); + BaseTimeDurationPlatformUtils::TicksFromMilliseconds(aMilliseconds)); } - static inline BaseTimeDuration FromMicroseconds(double aMicroseconds) - { + static inline BaseTimeDuration FromMicroseconds(double aMicroseconds) { return FromMilliseconds(aMicroseconds / 1000.0); } - static BaseTimeDuration Forever() - { - return FromTicks(INT64_MAX); - } + static constexpr BaseTimeDuration Forever() { return FromTicks(INT64_MAX); } - BaseTimeDuration operator+(const BaseTimeDuration& aOther) const - { + BaseTimeDuration operator+(const BaseTimeDuration& aOther) const { return FromTicks(ValueCalculator::Add(mValue, aOther.mValue)); } - BaseTimeDuration operator-(const BaseTimeDuration& aOther) const - { + BaseTimeDuration operator-(const BaseTimeDuration& aOther) const { return FromTicks(ValueCalculator::Subtract(mValue, aOther.mValue)); } - BaseTimeDuration& operator+=(const BaseTimeDuration& aOther) - { + BaseTimeDuration& operator+=(const BaseTimeDuration& aOther) { mValue = ValueCalculator::Add(mValue, aOther.mValue); return *this; } - BaseTimeDuration& operator-=(const BaseTimeDuration& aOther) - { + BaseTimeDuration& operator-=(const BaseTimeDuration& aOther) { mValue = ValueCalculator::Subtract(mValue, aOther.mValue); return *this; } - BaseTimeDuration operator-() const - { + BaseTimeDuration operator-() const { // We don't just use FromTicks(ValueCalculator::Subtract(0, mValue)) // since that won't give the correct result for -TimeDuration::Forever(). int64_t ticks; @@ -175,7 +160,16 @@ return FromTicks(ticks); } -private: + static BaseTimeDuration Max(const BaseTimeDuration& aA, + const BaseTimeDuration& aB) { + return FromTicks(std::max(aA.mValue, aB.mValue)); + } + static BaseTimeDuration Min(const BaseTimeDuration& aA, + const BaseTimeDuration& aB) { + return FromTicks(std::min(aA.mValue, aB.mValue)); + } + + private: // Block double multiplier (slower, imprecise if long duration) - Bug 853398. // If required, use MultDouble explicitly and with care. BaseTimeDuration operator*(const double aMultiplier) const = delete; @@ -185,86 +179,68 @@ // the passed argument can then cause divide-by-zero) - Bug 1147491. BaseTimeDuration operator/(const double aDivisor) const = delete; -public: - BaseTimeDuration MultDouble(double aMultiplier) const - { + public: + BaseTimeDuration MultDouble(double aMultiplier) const { return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier)); } - BaseTimeDuration operator*(const int32_t aMultiplier) const - { + BaseTimeDuration operator*(const int32_t aMultiplier) const { return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier)); } - BaseTimeDuration operator*(const uint32_t aMultiplier) const - { + BaseTimeDuration operator*(const uint32_t aMultiplier) const { return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier)); } - BaseTimeDuration operator*(const int64_t aMultiplier) const - { + BaseTimeDuration operator*(const int64_t aMultiplier) const { return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier)); } - BaseTimeDuration operator*(const uint64_t aMultiplier) const - { + BaseTimeDuration operator*(const uint64_t aMultiplier) const { if (aMultiplier > INT64_MAX) { return Forever(); } return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier)); } - BaseTimeDuration operator/(const int64_t aDivisor) const - { + BaseTimeDuration operator/(const int64_t aDivisor) const { MOZ_ASSERT(aDivisor != 0, "Division by zero"); return FromTicks(ValueCalculator::Divide(mValue, aDivisor)); } - double operator/(const BaseTimeDuration& aOther) const - { -#ifndef MOZ_B2G - // Bug 1066388 - This fails on B2G ICS Emulator + double operator/(const BaseTimeDuration& aOther) const { MOZ_ASSERT(aOther.mValue != 0, "Division by zero"); -#endif return ValueCalculator::DivideDouble(mValue, aOther.mValue); } - BaseTimeDuration operator%(const BaseTimeDuration& aOther) const - { + BaseTimeDuration operator%(const BaseTimeDuration& aOther) const { MOZ_ASSERT(aOther.mValue != 0, "Division by zero"); return FromTicks(ValueCalculator::Modulo(mValue, aOther.mValue)); } - template - bool operator<(const BaseTimeDuration& aOther) const - { + template + bool operator<(const BaseTimeDuration& aOther) const { return mValue < aOther.mValue; } - template - bool operator<=(const BaseTimeDuration& aOther) const - { + template + bool operator<=(const BaseTimeDuration& aOther) const { return mValue <= aOther.mValue; } - template - bool operator>=(const BaseTimeDuration& aOther) const - { + template + bool operator>=(const BaseTimeDuration& aOther) const { return mValue >= aOther.mValue; } - template - bool operator>(const BaseTimeDuration& aOther) const - { + template + bool operator>(const BaseTimeDuration& aOther) const { return mValue > aOther.mValue; } - template - bool operator==(const BaseTimeDuration& aOther) const - { + template + bool operator==(const BaseTimeDuration& aOther) const { return mValue == aOther.mValue; } - template - bool operator!=(const BaseTimeDuration& aOther) const - { + template + bool operator!=(const BaseTimeDuration& aOther) const { return mValue != aOther.mValue; } - bool IsZero() const - { - return mValue == 0; - } - explicit operator bool() const - { - return mValue != 0; + bool IsZero() const { return mValue == 0; } + explicit operator bool() const { return mValue != 0; } + + friend std::ostream& operator<<(std::ostream& aStream, + const BaseTimeDuration& aDuration) { + return aStream << aDuration.ToMilliseconds() << " ms"; } // Return a best guess at the system's current timing resolution, @@ -282,21 +258,19 @@ // Comparing durations for equality will only lead to bugs on // platforms with high-resolution timers. -private: + private: friend class TimeStamp; friend struct IPC::ParamTraits>; template friend class BaseTimeDuration; - static BaseTimeDuration FromTicks(int64_t aTicks) - { + static BaseTimeDuration FromTicks(int64_t aTicks) { BaseTimeDuration t; t.mValue = aTicks; return t; } - static BaseTimeDuration FromTicks(double aTicks) - { + static BaseTimeDuration FromTicks(double aTicks) { // NOTE: this MUST be a >= test, because int64_t(double(INT64_MAX)) // overflows and gives INT64_MIN. if (aTicks >= double(INT64_MAX)) { @@ -319,15 +293,13 @@ * Perform arithmetic operations on the value of a BaseTimeDuration without * doing strict checks on the range of values. */ -class TimeDurationValueCalculator -{ -public: +class TimeDurationValueCalculator { + public: static int64_t Add(int64_t aA, int64_t aB) { return aA + aB; } static int64_t Subtract(int64_t aA, int64_t aB) { return aA - aB; } template - static int64_t Multiply(int64_t aA, T aB) - { + static int64_t Multiply(int64_t aA, T aB) { static_assert(IsIntegral::value, "Using integer multiplication routine with non-integer type." " Further specialization required"); @@ -335,17 +307,15 @@ } static int64_t Divide(int64_t aA, int64_t aB) { return aA / aB; } - static double DivideDouble(int64_t aA, int64_t aB) - { + static double DivideDouble(int64_t aA, int64_t aB) { return static_cast(aA) / aB; } static int64_t Modulo(int64_t aA, int64_t aB) { return aA % aB; } }; template <> -inline int64_t -TimeDurationValueCalculator::Multiply(int64_t aA, double aB) -{ +inline int64_t TimeDurationValueCalculator::Multiply(int64_t aA, + double aB) { return static_cast(aA * aB); } @@ -387,29 +357,32 @@ * explicitly nullable and provides an IsNull() method. time_point * is initialized to the clock's epoch and provides a * time_since_epoch() method that functions similiarly. i.e. - * t.IsNull() is equivalent to t.time_since_epoch() == decltype(t)::duration::zero(); + * t.IsNull() is equivalent to t.time_since_epoch() == + * decltype(t)::duration::zero(); */ -class TimeStamp -{ -public: +class TimeStamp { + public: /** * Initialize to the "null" moment */ constexpr TimeStamp() : mValue(0) {} - // Default copy-constructor and assignment are OK + // Default copy-constructor and assignment are OK - /** - * The system timestamps are the same as the TimeStamp - * retrieved by mozilla::TimeStamp. Since we need this for - * vsync timestamps, we enable the creation of mozilla::TimeStamps - * on platforms that support vsync aligned refresh drivers / compositors - * Verified true as of Jan 31, 2015: B2G and OS X - * False on Windows 7 - * UNTESTED ON OTHER PLATFORMS - */ -#if defined(MOZ_WIDGET_GONK) || defined(XP_DARWIN) - static TimeStamp FromSystemTime(int64_t aSystemTime) - { + /** + * The system timestamps are the same as the TimeStamp + * retrieved by mozilla::TimeStamp. Since we need this for + * vsync timestamps, we enable the creation of mozilla::TimeStamps + * on platforms that support vsync aligned refresh drivers / compositors + * Verified true as of Jan 31, 2015: B2G and OS X + * False on Windows 7 + * Android's event time uses CLOCK_MONOTONIC via SystemClock.uptimeMilles. + * So it is same value of TimeStamp posix implementation. + * Wayland/GTK event time also uses CLOCK_MONOTONIC on Weston/Mutter + * compositors. + * UNTESTED ON OTHER PLATFORMS + */ +#if defined(XP_DARWIN) || defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK) + static TimeStamp FromSystemTime(int64_t aSystemTime) { static_assert(sizeof(aSystemTime) == sizeof(TimeStampValue), "System timestamp should be same units as TimeStampValue"); return TimeStamp(aSystemTime); @@ -425,10 +398,7 @@ * Return true if this is not the "null" moment, may be used in tests, e.g.: * |if (timestamp) { ... }| */ - explicit operator bool() const - { - return mValue != 0; - } + explicit operator bool() const { return mValue != 0; } /** * Return a timestamp reflecting the current elapsed system time. This @@ -453,12 +423,12 @@ * the @a aIsInconsistent parameter will be set to true, the returned * timestamp however will still be valid though inaccurate. * - * @param aIsInconsistent Set to true if an inconsistency was detected in the - * process creation time + * @param aIsInconsistent If non-null, set to true if an inconsistency was + * detected in the process creation time * @returns A timestamp representing the time when the process was created, * this timestamp is always valid even when errors are reported */ - static MFBT_API TimeStamp ProcessCreation(bool& aIsInconsistent); + static MFBT_API TimeStamp ProcessCreation(bool* aIsInconsistent = nullptr); /** * Records a process restart. After this call ProcessCreation() will return @@ -470,8 +440,7 @@ /** * Compute the difference between two timestamps. Both must be non-null. */ - TimeDuration operator-(const TimeStamp& aOther) const - { + TimeDuration operator-(const TimeStamp& aOther) const { MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); static_assert(-INT64_MAX > INT64_MIN, "int64_t sanity check"); @@ -489,20 +458,17 @@ return TimeDuration::FromTicks(ticks); } - TimeStamp operator+(const TimeDuration& aOther) const - { + TimeStamp operator+(const TimeDuration& aOther) const { TimeStamp result = *this; result += aOther; return result; } - TimeStamp operator-(const TimeDuration& aOther) const - { + TimeStamp operator-(const TimeDuration& aOther) const { TimeStamp result = *this; result -= aOther; return result; } - TimeStamp& operator+=(const TimeDuration& aOther) - { + TimeStamp& operator+=(const TimeDuration& aOther) { MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); TimeStampValue value = mValue + aOther.mValue; // Check for underflow. @@ -514,8 +480,7 @@ mValue = value; return *this; } - TimeStamp& operator-=(const TimeDuration& aOther) - { + TimeStamp& operator-=(const TimeDuration& aOther) { MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); TimeStampValue value = mValue - aOther.mValue; // Check for underflow. @@ -528,40 +493,31 @@ return *this; } - bool operator<(const TimeStamp& aOther) const - { + bool operator<(const TimeStamp& aOther) const { MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); return mValue < aOther.mValue; } - bool operator<=(const TimeStamp& aOther) const - { + bool operator<=(const TimeStamp& aOther) const { MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); return mValue <= aOther.mValue; } - bool operator>=(const TimeStamp& aOther) const - { + bool operator>=(const TimeStamp& aOther) const { MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); return mValue >= aOther.mValue; } - bool operator>(const TimeStamp& aOther) const - { + bool operator>(const TimeStamp& aOther) const { MOZ_ASSERT(!IsNull(), "Cannot compute with a null value"); MOZ_ASSERT(!aOther.IsNull(), "Cannot compute with aOther null value"); return mValue > aOther.mValue; } - bool operator==(const TimeStamp& aOther) const - { - return IsNull() - ? aOther.IsNull() - : !aOther.IsNull() && mValue == aOther.mValue; - } - bool operator!=(const TimeStamp& aOther) const - { - return !(*this == aOther); + bool operator==(const TimeStamp& aOther) const { + return IsNull() ? aOther.IsNull() + : !aOther.IsNull() && mValue == aOther.mValue; } + bool operator!=(const TimeStamp& aOther) const { return !(*this == aOther); } // Comparing TimeStamps for equality should be discouraged. Adding // two TimeStamps, or scaling TimeStamps, is nonsense and must never @@ -570,7 +526,7 @@ static MFBT_API void Startup(); static MFBT_API void Shutdown(); -private: + private: friend struct IPC::ParamTraits; friend void StartupTimelineRecordExternal(int, uint64_t); @@ -604,6 +560,6 @@ TimeStampValue mValue; }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_TimeStamp_h */ 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 @@ -13,8 +13,7 @@ class TimeStamp; -class TimeStampValue -{ +class TimeStampValue { friend struct IPC::ParamTraits; friend class TimeStamp; friend void StartupTimelineRecordExternal(int, uint64_t); @@ -30,54 +29,41 @@ MFBT_API uint64_t CheckQPC(const TimeStampValue& aOther) const; struct _SomethingVeryRandomHere; - constexpr TimeStampValue(_SomethingVeryRandomHere* aNullValue) - : mGTC(0) - , mQPC(0) - , mHasQPC(false) - , mIsNull(true) - { - } + constexpr MOZ_IMPLICIT TimeStampValue(_SomethingVeryRandomHere* aNullValue) + : mGTC(0), mQPC(0), mHasQPC(false), mIsNull(true) {} -public: + public: MFBT_API uint64_t operator-(const TimeStampValue& aOther) const; - TimeStampValue operator+(const int64_t aOther) const - { + TimeStampValue operator+(const int64_t aOther) const { return TimeStampValue(mGTC + aOther, mQPC + aOther, mHasQPC); } - TimeStampValue operator-(const int64_t aOther) const - { + TimeStampValue operator-(const int64_t aOther) const { return TimeStampValue(mGTC - aOther, mQPC - aOther, mHasQPC); } MFBT_API TimeStampValue& operator+=(const int64_t aOther); MFBT_API TimeStampValue& operator-=(const int64_t aOther); - bool operator<(const TimeStampValue& aOther) const - { + bool operator<(const TimeStampValue& aOther) const { return int64_t(*this - aOther) < 0; } - bool operator>(const TimeStampValue& aOther) const - { + bool operator>(const TimeStampValue& aOther) const { return int64_t(*this - aOther) > 0; } - bool operator<=(const TimeStampValue& aOther) const - { + bool operator<=(const TimeStampValue& aOther) const { return int64_t(*this - aOther) <= 0; } - bool operator>=(const TimeStampValue& aOther) const - { + bool operator>=(const TimeStampValue& aOther) const { return int64_t(*this - aOther) >= 0; } - bool operator==(const TimeStampValue& aOther) const - { + bool operator==(const TimeStampValue& aOther) const { return int64_t(*this - aOther) == 0; } - bool operator!=(const TimeStampValue& aOther) const - { + bool operator!=(const TimeStampValue& aOther) const { return int64_t(*this - aOther) != 0; } }; -} +} // namespace mozilla #endif /* mozilla_TimeStamp_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ToString.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ToString.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/ToString.h @@ -18,15 +18,13 @@ * A convenience function for converting an object to a string representation. * Supports any object which can be streamed to an std::ostream. */ -template -std::string -ToString(const T& aValue) -{ +template +std::string ToString(const T& aValue) { std::ostringstream stream; stream << aValue; return stream.str(); } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_ToString_h */ 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 @@ -25,7 +25,7 @@ * A helper class that allows passing around multiple variadic argument lists * by grouping them. */ -template +template struct Group; /* @@ -44,24 +44,27 @@ * immediate context of the caller). */ -template +template struct CheckConvertibilityImpl; -template -struct CheckConvertibilityImpl - : FalseType {}; - -template -struct CheckConvertibilityImpl, Group, true> - : IntegralConstant::value...>::value> { }; +template +struct CheckConvertibilityImpl : FalseType {}; -template +template +struct CheckConvertibilityImpl, Group, + true> + : IntegralConstant< + bool, + tl::And::value...>::value> {}; + +template struct CheckConvertibility; -template +template struct CheckConvertibility, Group> - : CheckConvertibilityImpl, Group, - sizeof...(SourceTypes) == sizeof...(TargetTypes)> { }; + : CheckConvertibilityImpl, Group, + sizeof...(SourceTypes) == + sizeof...(TargetTypes)> {}; /* * TupleImpl is a helper class used to implement mozilla::Tuple. @@ -87,19 +90,16 @@ * This implementation strategy is borrowed from libstdc++'s std::tuple * implementation. */ -template +template struct TupleImpl; /* * The base case of the inheritance recursion (and also the implementation * of an empty tuple). */ -template +template struct TupleImpl { - bool operator==(const TupleImpl& aOther) const - { - return true; - } + bool operator==(const TupleImpl& aOther) const { return true; } }; /* @@ -107,10 +107,9 @@ * index 'Index' of a tuple, of type 'HeadT', and inherits from the nodes * that store the remaining elements, of types 'TailT...'. */ -template +template struct TupleImpl - : public TupleImpl -{ + : public TupleImpl { typedef TupleImpl Base; // Accessors for the head and the tail. @@ -123,11 +122,11 @@ static Base& Tail(TupleImpl& aTuple) { return aTuple; } static const Base& Tail(const TupleImpl& aTuple) { return aTuple; } - TupleImpl() : Base(), mHead() { } + TupleImpl() : Base(), mHead() {} // Construct from const references to the elements. explicit TupleImpl(const HeadT& aHead, const TailT&... aTail) - : Base(aTail...), mHead(aHead) { } + : Base(aTail...), mHead(aHead) {} // Construct from objects that are convertible to the elements. // This constructor is enabled only when the argument types are actually @@ -135,39 +134,35 @@ // match for certain invocations than the copy constructor. template , - Group>::value>::Type> + CheckConvertibility, + Group>::value>::Type> explicit TupleImpl(OtherHeadT&& aHead, OtherTailT&&... aTail) - : Base(Forward(aTail)...), mHead(Forward(aHead)) { } + : Base(Forward(aTail)...), + mHead(Forward(aHead)) {} // Copy and move constructors. // We'd like to use '= default' to implement these, but MSVC 2013's support // for '= default' is incomplete and this doesn't work. TupleImpl(const TupleImpl& aOther) - : Base(Tail(aOther)) - , mHead(Head(aOther)) {} + : Base(Tail(aOther)), mHead(Head(aOther)) {} TupleImpl(TupleImpl&& aOther) - : Base(Move(Tail(aOther))) - , mHead(Forward(Head(aOther))) {} + : Base(Move(Tail(aOther))), mHead(Forward(Head(aOther))) {} // Assign from a tuple whose elements are convertible to the elements // of this tuple. template ::Type> - TupleImpl& operator=(const TupleImpl& aOther) - { + typename = typename EnableIf::Type> + TupleImpl& operator=(const TupleImpl& aOther) { typedef TupleImpl OtherT; Head(*this) = OtherT::Head(aOther); Tail(*this) = OtherT::Tail(aOther); return *this; } template ::Type> - TupleImpl& operator=(TupleImpl&& aOther) - { + typename = typename EnableIf::Type> + TupleImpl& operator=(TupleImpl&& aOther) { typedef TupleImpl OtherT; Head(*this) = Move(OtherT::Head(aOther)); Tail(*this) = Move(OtherT::Tail(aOther)); @@ -175,27 +170,25 @@ } // Copy and move assignment operators. - TupleImpl& operator=(const TupleImpl& aOther) - { + TupleImpl& operator=(const TupleImpl& aOther) { Head(*this) = Head(aOther); Tail(*this) = Tail(aOther); return *this; } - TupleImpl& operator=(TupleImpl&& aOther) - { + TupleImpl& operator=(TupleImpl&& aOther) { Head(*this) = Move(Head(aOther)); Tail(*this) = Move(Tail(aOther)); return *this; } - bool operator==(const TupleImpl& aOther) const - { + bool operator==(const TupleImpl& aOther) const { return Head(*this) == Head(aOther) && Tail(*this) == Tail(aOther); } -private: + + private: HeadT mHead; // The element stored at this index in the tuple. }; -} // namespace detail +} // namespace detail /** * Tuple is a class that stores zero or more objects, whose types are specified @@ -205,141 +198,125 @@ * Tuple allows index-based access to its elements (with the index having to be * known at compile time) via the non-member function 'Get(tuple)'. */ -template -class Tuple : public detail::TupleImpl<0, Elements...> -{ +template +class Tuple : public detail::TupleImpl<0, Elements...> { typedef detail::TupleImpl<0, Elements...> Impl; -public: + + public: // The constructors and assignment operators here are simple wrappers // around those in TupleImpl. - Tuple() : Impl() { } - explicit Tuple(const Elements&... aElements) : Impl(aElements...) { } + Tuple() : Impl() {} + explicit Tuple(const Elements&... aElements) : Impl(aElements...) {} // Here, we can't just use 'typename... OtherElements' because MSVC will give // a warning "C4520: multiple default constructors specified" (even if no one // actually instantiates the constructor with an empty parameter pack - // that's probably a bug) and we compile with warnings-as-errors. template , - detail::Group>::value>::Type> + typename = typename EnableIf, + detail::Group>::value>::Type> explicit Tuple(OtherHead&& aHead, OtherTail&&... aTail) - : Impl(Forward(aHead), Forward(aTail)...) { } - Tuple(const Tuple& aOther) : Impl(aOther) { } - Tuple(Tuple&& aOther) : Impl(Move(aOther)) { } + : Impl(Forward(aHead), Forward(aTail)...) {} + Tuple(const Tuple& aOther) : Impl(aOther) {} + Tuple(Tuple&& aOther) : Impl(Move(aOther)) {} template ::Type> - Tuple& operator=(const Tuple& aOther) - { + typename = typename EnableIf::Type> + Tuple& operator=(const Tuple& aOther) { static_cast(*this) = aOther; return *this; } template ::Type> - Tuple& operator=(Tuple&& aOther) - { + typename = typename EnableIf::Type> + Tuple& operator=(Tuple&& aOther) { static_cast(*this) = Move(aOther); return *this; } - Tuple& operator=(const Tuple& aOther) - { + Tuple& operator=(const Tuple& aOther) { static_cast(*this) = aOther; return *this; } - Tuple& operator=(Tuple&& aOther) - { + Tuple& operator=(Tuple&& aOther) { static_cast(*this) = Move(aOther); return *this; } - bool operator==(const Tuple& aOther) const - { + bool operator==(const Tuple& aOther) const { return static_cast(*this) == static_cast(aOther); } }; /** * Specialization of Tuple for two elements. - * This is created to support construction and assignment from a Pair or std::pair. + * This is created to support construction and assignment from a Pair or + * std::pair. */ template -class Tuple : public detail::TupleImpl<0, A, B> -{ +class Tuple : public detail::TupleImpl<0, A, B> { typedef detail::TupleImpl<0, A, B> Impl; -public: + public: // The constructors and assignment operators here are simple wrappers // around those in TupleImpl. - Tuple() : Impl() { } - explicit Tuple(const A& aA, const B& aB) : Impl(aA, aB) { } + Tuple() : Impl() {} + explicit Tuple(const A& aA, const B& aB) : Impl(aA, aB) {} template , - detail::Group>::value>::Type> + typename = typename EnableIf, detail::Group>::value>::Type> explicit Tuple(AArg&& aA, BArg&& aB) - : Impl(Forward(aA), Forward(aB)) { } - Tuple(const Tuple& aOther) : Impl(aOther) { } - Tuple(Tuple&& aOther) : Impl(Move(aOther)) { } + : Impl(Forward(aA), Forward(aB)) {} + Tuple(const Tuple& aOther) : Impl(aOther) {} + Tuple(Tuple&& aOther) : Impl(Move(aOther)) {} explicit Tuple(const Pair& aOther) - : Impl(aOther.first(), aOther.second()) { } - explicit Tuple(Pair&& aOther) : Impl(Forward(aOther.first()), - Forward(aOther.second())) { } + : Impl(aOther.first(), aOther.second()) {} + explicit Tuple(Pair&& aOther) + : Impl(Forward(aOther.first()), Forward(aOther.second())) {} explicit Tuple(const std::pair& aOther) - : Impl(aOther.first, aOther.second) { } - explicit Tuple(std::pair&& aOther) : Impl(Forward(aOther.first), - Forward(aOther.second)) { } + : Impl(aOther.first, aOther.second) {} + explicit Tuple(std::pair&& aOther) + : Impl(Forward(aOther.first), Forward(aOther.second)) {} template - Tuple& operator=(const Tuple& aOther) - { + Tuple& operator=(const Tuple& aOther) { static_cast(*this) = aOther; return *this; } template - Tuple& operator=(Tuple&& aOther) - { + Tuple& operator=(Tuple&& aOther) { static_cast(*this) = Move(aOther); return *this; } - Tuple& operator=(const Tuple& aOther) - { + Tuple& operator=(const Tuple& aOther) { static_cast(*this) = aOther; return *this; } - Tuple& operator=(Tuple&& aOther) - { + Tuple& operator=(Tuple&& aOther) { static_cast(*this) = Move(aOther); return *this; } template - Tuple& operator=(const Pair& aOther) - { + Tuple& operator=(const Pair& aOther) { Impl::Head(*this) = aOther.first(); Impl::Tail(*this).Head(*this) = aOther.second(); return *this; } template - Tuple& operator=(Pair&& aOther) - { + Tuple& operator=(Pair&& aOther) { Impl::Head(*this) = Forward(aOther.first()); Impl::Tail(*this).Head(*this) = Forward(aOther.second()); return *this; } template - Tuple& operator=(const std::pair& aOther) - { + Tuple& operator=(const std::pair& aOther) { Impl::Head(*this) = aOther.first; Impl::Tail(*this).Head(*this) = aOther.second; return *this; } template - Tuple& operator=(std::pair&& aOther) - { + Tuple& operator=(std::pair&& aOther) { Impl::Head(*this) = Forward(aOther.first); Impl::Tail(*this).Head(*this) = Forward(aOther.second); return *this; @@ -366,22 +343,20 @@ */ // Const reference version. -template +template auto TupleGetHelper(TupleImpl& aTuple) - -> decltype(TupleImpl::Head(aTuple)) -{ + -> decltype(TupleImpl::Head(aTuple)) { return TupleImpl::Head(aTuple); } // Non-const reference version. -template +template auto TupleGetHelper(const TupleImpl& aTuple) - -> decltype(TupleImpl::Head(aTuple)) -{ + -> decltype(TupleImpl::Head(aTuple)) { return TupleImpl::Head(aTuple); } -} // namespace detail +} // namespace detail /** * Index-based access to an element of a tuple. @@ -395,26 +370,23 @@ */ // Non-const reference version. -template +template auto Get(Tuple& aTuple) - -> decltype(detail::TupleGetHelper(aTuple)) -{ + -> decltype(detail::TupleGetHelper(aTuple)) { return detail::TupleGetHelper(aTuple); } // Const reference version. -template +template auto Get(const Tuple& aTuple) - -> decltype(detail::TupleGetHelper(aTuple)) -{ + -> decltype(detail::TupleGetHelper(aTuple)) { return detail::TupleGetHelper(aTuple); } // Rvalue reference version. -template +template auto Get(Tuple&& aTuple) - -> decltype(Move(mozilla::Get(aTuple))) -{ + -> decltype(Move(mozilla::Get(aTuple))) { // We need a 'mozilla::' qualification here to avoid // name lookup only finding the current function. return Move(mozilla::Get(aTuple)); @@ -429,11 +401,11 @@ * * auto tuple = MakeTuple(42, 0.5f, 'c'); // has type Tuple */ -template -inline Tuple::Type...> -MakeTuple(Elements&&... aElements) -{ - return Tuple::Type...>(Forward(aElements)...); +template +inline Tuple::Type...> MakeTuple( + Elements&&... aElements) { + return Tuple::Type...>( + Forward(aElements)...); } /** @@ -449,13 +421,11 @@ * char c; * Tie(i, f, c) = FunctionThatReturnsATuple(); */ -template -inline Tuple -Tie(Elements&... aVariables) -{ +template +inline Tuple Tie(Elements&... aVariables) { return Tuple(aVariables...); } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_Tuple_h */ 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 @@ -23,8 +23,10 @@ /* Forward declarations. */ -template struct RemoveCV; -template struct AddRvalueReference; +template +struct RemoveCV; +template +struct AddRvalueReference; /* 20.2.4 Function template declval [declval] */ @@ -34,7 +36,7 @@ * decltype expressions even if T does not have a default constructor, e.g.: * decltype(DeclVal().foo()) */ -template +template typename AddRvalueReference::Type DeclVal(); /* 20.9.3 Helper classes [meta.help] */ @@ -43,10 +45,9 @@ * Helper class used as a base for various type traits, exposed publicly * because exposes it as well. */ -template -struct IntegralConstant -{ - static const T value = Value; +template +struct IntegralConstant { + static constexpr T value = Value; typedef T ValueType; typedef IntegralConstant Type; }; @@ -61,13 +62,13 @@ namespace detail { -template +template struct IsVoidHelper : FalseType {}; -template<> +template <> struct IsVoidHelper : TrueType {}; -} // namespace detail +} // namespace detail /** * IsVoid determines whether a type is void. @@ -77,7 +78,7 @@ * mozilla::IsVoid::value is false; * mozilla::IsVoid::value is true. */ -template +template struct IsVoid : detail::IsVoidHelper::Type> {}; namespace detail { @@ -85,20 +86,34 @@ template struct IsIntegralHelper : FalseType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; -template<> struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; +template <> +struct IsIntegralHelper : TrueType {}; } /* namespace detail */ @@ -111,24 +126,21 @@ * mozilla::IsIntegral::value is false; * mozilla::IsIntegral::value is false; */ -template -struct IsIntegral : detail::IsIntegralHelper::Type> -{}; +template +struct IsIntegral : detail::IsIntegralHelper::Type> {}; -template +template struct IsSame; namespace detail { -template +template struct IsFloatingPointHelper - : IntegralConstant::value || - IsSame::value || - IsSame::value> -{}; + : IntegralConstant::value || + IsSame::value || + IsSame::value> {}; -} // namespace detail +} // namespace detail /** * IsFloatingPoint determines whether a type is a floating point type (float, @@ -139,23 +151,22 @@ * mozilla::IsFloatingPoint::value is true; * mozilla::IsFloatingPoint::value is false. */ -template +template struct IsFloatingPoint - : detail::IsFloatingPointHelper::Type> -{}; + : detail::IsFloatingPointHelper::Type> {}; namespace detail { -template +template struct IsArrayHelper : FalseType {}; -template +template struct IsArrayHelper : TrueType {}; -template +template struct IsArrayHelper : TrueType {}; -} // namespace detail +} // namespace detail /** * IsArray determines whether a type is an array type, of known or unknown @@ -165,26 +176,21 @@ * mozilla::IsArray::value is true; * mozilla::IsArray::value is true. */ -template -struct IsArray : detail::IsArrayHelper::Type> -{}; +template +struct IsArray : detail::IsArrayHelper::Type> {}; namespace detail { -template +template struct IsFunPtr; -template -struct IsFunPtr - : public FalseType -{}; - -template -struct IsFunPtr - : public TrueType -{}; +template +struct IsFunPtr : public FalseType {}; + +template +struct IsFunPtr : public TrueType {}; -}; // namespace detail +}; // namespace detail /** * IsFunction determines whether a type is a function type. Function pointers @@ -198,20 +204,18 @@ * mozilla::IsFunction is false; * mozilla::IsFunction is true. */ -template -struct IsFunction - : public detail::IsFunPtr::Type *> -{}; +template +struct IsFunction : public detail::IsFunPtr::Type*> {}; namespace detail { -template +template struct IsPointerHelper : FalseType {}; -template +template struct IsPointerHelper : TrueType {}; -} // namespace detail +} // namespace detail /** * IsPointer determines whether a type is a possibly-CV-qualified pointer type @@ -228,9 +232,8 @@ * mozilla::IsPointer::value is false. * mozilla::IsPointer::value is false */ -template -struct IsPointer : detail::IsPointerHelper::Type> -{}; +template +struct IsPointer : detail::IsPointerHelper::Type> {}; /** * IsLvalueReference determines whether a type is an lvalue reference. @@ -243,10 +246,10 @@ * mozilla::IsLvalueReference::value is true; * mozilla::IsLvalueReference::value is false. */ -template +template struct IsLvalueReference : FalseType {}; -template +template struct IsLvalueReference : TrueType {}; /** @@ -260,21 +263,19 @@ * mozilla::IsRvalueReference::value is false; * mozilla::IsRvalueReference::value is true. */ -template +template struct IsRvalueReference : FalseType {}; -template +template struct IsRvalueReference : TrueType {}; namespace detail { // __is_enum is a supported extension across all of our supported compilers. -template -struct IsEnumHelper - : IntegralConstant -{}; +template +struct IsEnumHelper : IntegralConstant {}; -} // namespace detail +} // namespace detail /** * IsEnum determines whether a type is an enum type. @@ -283,10 +284,8 @@ * mozilla::IsEnum::value is false; * mozilla::IsEnum::value is false; */ -template -struct IsEnum - : detail::IsEnumHelper::Type> -{}; +template +struct IsEnum : detail::IsEnumHelper::Type> {}; namespace detail { @@ -294,12 +293,10 @@ // http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html // http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits // http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx -template -struct IsClassHelper - : IntegralConstant -{}; +template +struct IsClassHelper : IntegralConstant {}; -} // namespace detail +} // namespace detail /** * IsClass determines whether a type is a class type (but not a union). @@ -310,10 +307,8 @@ * mozilla::IsClass::value is true; * mozilla::IsClass::value is false; */ -template -struct IsClass - : detail::IsClassHelper::Type> -{}; +template +struct IsClass : detail::IsClassHelper::Type> {}; /* 20.9.4.2 Composite type traits [meta.unary.comp] */ @@ -331,11 +326,9 @@ * mozilla::IsReference::value is true; * mozilla::IsReference::value is true. */ -template -struct IsReference - : IntegralConstant::value || IsRvalueReference::value> -{}; +template +struct IsReference : IntegralConstant::value || + IsRvalueReference::value> {}; /** * IsArithmetic determines whether a type is arithmetic. A type is arithmetic @@ -345,20 +338,19 @@ * mozilla::IsArithmetic::value is true; * mozilla::IsArithmetic::value is false. */ -template -struct IsArithmetic - : IntegralConstant::value || IsFloatingPoint::value> -{}; +template +struct IsArithmetic : IntegralConstant::value || + IsFloatingPoint::value> {}; namespace detail { -template +template struct IsMemberPointerHelper : FalseType {}; -template +template struct IsMemberPointerHelper : TrueType {}; -} // namespace detail +} // namespace detail /** * IsMemberPointer determines whether a type is pointer to non-static member @@ -367,10 +359,9 @@ * mozilla::IsMemberPointer::value is true * mozilla::IsMemberPointer::value is false */ -template +template struct IsMemberPointer - : detail::IsMemberPointerHelper::Type> -{}; + : detail::IsMemberPointerHelper::Type> {}; /** * IsScalar determines whether a type is a scalar type. @@ -379,11 +370,11 @@ * mozilla::IsScalar::value is true * mozilla::IsScalar::value is false */ -template +template struct IsScalar - : IntegralConstant::value || IsEnum::value || - IsPointer::value || IsMemberPointer::value> -{}; + : IntegralConstant::value || IsEnum::value || + IsPointer::value || + IsMemberPointer::value> {}; /* 20.9.4.3 Type properties [meta.unary.prop] */ @@ -394,10 +385,10 @@ * mozilla::IsConst::value is true; * mozilla::IsConst::value is false. */ -template +template struct IsConst : FalseType {}; -template +template struct IsConst : TrueType {}; /** @@ -407,10 +398,10 @@ * mozilla::IsVolatile::value is true; * mozilla::IsVolatile::value is false. */ -template +template struct IsVolatile : FalseType {}; -template +template struct IsVolatile : TrueType {}; /** @@ -421,26 +412,43 @@ * false>, or conveniently from mozilla::IsPod for composite types) as needed to * ensure correct IsPod behavior. */ -template +template struct IsPod : public FalseType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template<> struct IsPod : TrueType {}; -template struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template <> +struct IsPod : TrueType {}; +template +struct IsPod : TrueType {}; namespace detail { @@ -448,12 +456,11 @@ // http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html // http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits // http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx -template +template struct IsEmptyHelper - : IntegralConstant::value && __is_empty(T)> -{}; + : IntegralConstant::value&& __is_empty(T)> {}; -} // namespace detail +} // namespace detail /** * IsEmpty determines whether a type is a class (but not a union) that is empty. @@ -495,34 +502,30 @@ * !mozilla::IsEmpty::value, * "all empty"); */ -template -struct IsEmpty : detail::IsEmptyHelper::Type> -{}; - +template +struct IsEmpty : detail::IsEmptyHelper::Type> {}; namespace detail { -template::value, - bool = IsIntegral::value, - typename NoCV = typename RemoveCV::Type> +template ::value, + bool = IsIntegral::value, + typename NoCV = typename RemoveCV::Type> struct IsSignedHelper; // Floating point is signed. -template +template struct IsSignedHelper : TrueType {}; // Integral is conditionally signed. -template +template struct IsSignedHelper - : IntegralConstant -{}; + : IntegralConstant {}; // Non-floating point, non-integral is not signed. -template +template struct IsSignedHelper : FalseType {}; -} // namespace detail +} // namespace detail /** * IsSigned determines whether a type is a signed arithmetic type. |char| is @@ -533,33 +536,31 @@ * mozilla::IsSigned::value is false; * mozilla::IsSigned::value is true. */ -template +template struct IsSigned : detail::IsSignedHelper {}; namespace detail { -template::value, - bool = IsIntegral::value, - typename NoCV = typename RemoveCV::Type> +template ::value, + bool = IsIntegral::value, + typename NoCV = typename RemoveCV::Type> struct IsUnsignedHelper; // Floating point is not unsigned. -template +template struct IsUnsignedHelper : FalseType {}; // Integral is conditionally unsigned. -template +template struct IsUnsignedHelper - : IntegralConstant::value || bool(NoCV(1) < NoCV(-1)))> -{}; + : IntegralConstant::value || + bool(NoCV(1) < NoCV(-1)))> {}; // Non-floating point, non-integral is not unsigned. -template +template struct IsUnsignedHelper : FalseType {}; -} // namespace detail +} // namespace detail /** * IsUnsigned determines whether a type is an unsigned arithmetic type. @@ -569,28 +570,75 @@ * mozilla::IsUnsigned::value is true; * mozilla::IsUnsigned::value is false. */ -template +template struct IsUnsigned : detail::IsUnsignedHelper {}; namespace detail { -struct DoIsDestructibleImpl -{ - template().~T())> +struct DoIsDefaultConstructibleImpl { + template static TrueType test(int); - template + template static FalseType test(...); }; -template -struct IsDestructibleImpl : public DoIsDestructibleImpl -{ +template +struct IsDefaultConstructibleImpl : public DoIsDefaultConstructibleImpl { typedef decltype(test(0)) Type; }; -} // namespace detail +} // namespace detail -template +/** + * IsDefaultConstructible determines whether a type has a public default + * constructor. + * + * struct S0 {}; // Implicit default constructor. + * struct S1 { S1(); }; + * struct S2 { explicit S2(int); }; // No implicit default constructor when + * // another one is present. + * struct S3 { S3() = delete; }; + * class C4 { C4(); }; // Default constructor is private. + * + * mozilla::IsDefaultConstructible::value is true; + * mozilla::IsDefaultConstructible::value is true; + * mozilla::IsDefaultConstructible::value is true; + * mozilla::IsDefaultConstructible::value is false; + * mozilla::IsDefaultConstructible::value is false; + * mozilla::IsDefaultConstructible::value is false. + */ +template +struct IsDefaultConstructible + : public detail::IsDefaultConstructibleImpl::Type {}; + +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 + +/** + * IsDestructible determines whether a type has a public destructor. + * + * struct S0 {}; // Implicit default destructor. + * struct S1 { ~S1(); }; + * class C2 { ~C2(); }; // private destructor. + * + * mozilla::IsDestructible::value is true; + * mozilla::IsDestructible::value is true; + * mozilla::IsDestructible::value is false. + */ +template struct IsDestructible : public detail::IsDestructibleImpl::Type {}; /* 20.9.5 Type property queries [meta.unary.prop.query] */ @@ -607,17 +655,17 @@ * mozilla::IsSame::value is false; * mozilla::IsSame::value is true. */ -template +template struct IsSame : FalseType {}; -template +template struct IsSame : TrueType {}; namespace detail { #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) -template +template struct BaseOfTester : IntegralConstant {}; #else @@ -627,47 +675,44 @@ // sample code here: // // http://stackoverflow.com/questions/2910979/how-is-base-of-works -template -struct BaseOfHelper -{ -public: +template +struct BaseOfHelper { + public: operator Base*() const; operator Derived*(); }; -template -struct BaseOfTester -{ -private: - template +template +struct BaseOfTester { + private: + template static char test(Derived*, T); static int test(Base*, int); -public: + public: static const bool value = - sizeof(test(BaseOfHelper(), int())) == sizeof(char); + sizeof(test(BaseOfHelper(), int())) == sizeof(char); }; -template -struct BaseOfTester -{ -private: - template +template +struct BaseOfTester { + private: + template static char test(Derived*, T); static int test(Base*, int); -public: + public: static const bool value = - sizeof(test(BaseOfHelper(), int())) == sizeof(char); + sizeof(test(BaseOfHelper(), int())) == sizeof(char); }; -template +template struct BaseOfTester : FalseType {}; -template +template struct BaseOfTester : TrueType {}; -template +template struct BaseOfTester : TrueType {}; #endif @@ -686,32 +731,29 @@ * mozilla::IsBaseOf::value is true; * mozilla::IsBaseOf::value is false; */ -template +template struct IsBaseOf - : IntegralConstant::value> -{}; + : IntegralConstant::value> {}; namespace detail { -template -struct ConvertibleTester -{ -private: - template +template +struct ConvertibleTester { + private: + template static char test_helper(To1); - template + template static decltype(test_helper(DeclVal())) test(int); - template + template static int test(...); -public: - static const bool value = - sizeof(test(0)) == sizeof(char); + public: + static const bool value = sizeof(test(0)) == sizeof(char); }; -} // namespace detail +} // namespace detail /** * IsConvertible determines whether a value of type From will implicitly convert @@ -738,25 +780,18 @@ * handle. The void handling here doesn't handle const/volatile void correctly, * which could be easily fixed if the need arises. */ -template +template struct IsConvertible - : IntegralConstant::value> -{}; + : IntegralConstant::value> {}; + +template +struct IsConvertible : IntegralConstant::value> {}; -template -struct IsConvertible - : IntegralConstant::value> -{}; - -template -struct IsConvertible - : IntegralConstant::value> -{}; - -template<> -struct IsConvertible - : TrueType -{}; +template +struct IsConvertible : IntegralConstant::value> {}; + +template <> +struct IsConvertible : TrueType {}; /* 20.9.7 Transformations between types [meta.trans] */ @@ -770,15 +805,13 @@ * mozilla::RemoveConst::Type is const int*; * mozilla::RemoveConst::Type is int*. */ -template -struct RemoveConst -{ +template +struct RemoveConst { typedef T Type; }; -template -struct RemoveConst -{ +template +struct RemoveConst { typedef T Type; }; @@ -790,15 +823,13 @@ * mozilla::RemoveVolatile::Type is volatile int*; * mozilla::RemoveVolatile::Type is int*. */ -template -struct RemoveVolatile -{ +template +struct RemoveVolatile { typedef T Type; }; -template -struct RemoveVolatile -{ +template +struct RemoveVolatile { typedef T Type; }; @@ -810,9 +841,8 @@ * mozilla::RemoveCV::Type is int; * mozilla::RemoveCV::Type is int*. */ -template -struct RemoveCV -{ +template +struct RemoveCV { typedef typename RemoveConst::Type>::Type Type; }; @@ -826,47 +856,42 @@ * mozilla::RemoveReference::Type is T; */ -template -struct RemoveReference -{ +template +struct RemoveReference { typedef T Type; }; -template -struct RemoveReference -{ +template +struct RemoveReference { typedef T Type; }; -template -struct RemoveReference -{ +template +struct RemoveReference { typedef T Type; }; -template +template struct Conditional; namespace detail { enum Voidness { TIsVoid, TIsNotVoid }; -template::value ? TIsVoid : TIsNotVoid> +template ::value ? TIsVoid : TIsNotVoid> struct AddLvalueReferenceHelper; -template -struct AddLvalueReferenceHelper -{ +template +struct AddLvalueReferenceHelper { typedef void Type; }; -template -struct AddLvalueReferenceHelper -{ +template +struct AddLvalueReferenceHelper { typedef T& Type; }; -} // namespace detail +} // namespace detail /** * AddLvalueReference adds an lvalue & reference to T if one isn't already @@ -882,29 +907,25 @@ * mozilla::AddLvalueReference::Type is void; * mozilla::AddLvalueReference::Type is struct S&. */ -template -struct AddLvalueReference - : detail::AddLvalueReferenceHelper -{}; +template +struct AddLvalueReference : detail::AddLvalueReferenceHelper {}; namespace detail { -template::value ? TIsVoid : TIsNotVoid> +template ::value ? TIsVoid : TIsNotVoid> struct AddRvalueReferenceHelper; -template -struct AddRvalueReferenceHelper -{ +template +struct AddRvalueReferenceHelper { typedef void Type; }; -template -struct AddRvalueReferenceHelper -{ +template +struct AddRvalueReferenceHelper { typedef T&& Type; }; -} // namespace detail +} // namespace detail /** * AddRvalueReference adds an rvalue && reference to T if one isn't already @@ -921,66 +942,69 @@ * mozilla::AddRvalueReference::Type is void; * mozilla::AddRvalueReference::Type is struct S&. */ -template -struct AddRvalueReference - : detail::AddRvalueReferenceHelper -{}; +template +struct AddRvalueReference : detail::AddRvalueReferenceHelper {}; /* 20.9.7.3 Sign modifications [meta.trans.sign] */ -template +template struct EnableIf; namespace detail { -template -struct WithC : Conditional -{}; - -template -struct WithV : Conditional -{}; +template +struct WithC : Conditional {}; +template +struct WithV : Conditional {}; -template -struct WithCV : WithC::Type> -{}; +template +struct WithCV : WithC::Type> {}; -template +template struct CorrespondingSigned; -template<> -struct CorrespondingSigned { typedef signed char Type; }; -template<> -struct CorrespondingSigned { typedef signed char Type; }; -template<> -struct CorrespondingSigned { typedef short Type; }; -template<> -struct CorrespondingSigned { typedef int Type; }; -template<> -struct CorrespondingSigned { typedef long Type; }; -template<> -struct CorrespondingSigned { typedef long long Type; }; - -template::Type, - bool IsSignedIntegerType = IsSigned::value && - !IsSame::value> +template <> +struct CorrespondingSigned { + typedef signed char Type; +}; +template <> +struct CorrespondingSigned { + typedef signed char Type; +}; +template <> +struct CorrespondingSigned { + typedef short Type; +}; +template <> +struct CorrespondingSigned { + typedef int Type; +}; +template <> +struct CorrespondingSigned { + typedef long Type; +}; +template <> +struct CorrespondingSigned { + typedef long long Type; +}; + +template ::Type, + bool IsSignedIntegerType = + IsSigned::value && !IsSame::value> struct MakeSigned; -template -struct MakeSigned -{ +template +struct MakeSigned { typedef T Type; }; -template +template struct MakeSigned - : WithCV::value, IsVolatile::value, - typename CorrespondingSigned::Type> -{}; + : WithCV::value, IsVolatile::value, + typename CorrespondingSigned::Type> {}; -} // namespace detail +} // namespace detail /** * MakeSigned produces the corresponding signed integer type for a given @@ -1004,52 +1028,58 @@ * mozilla::MakeSigned is an error; * mozilla::MakeSigned is an error. */ -template +template struct MakeSigned - : EnableIf::value && - !IsSame::Type>::value, - typename detail::MakeSigned - >::Type -{}; + : EnableIf::value && + !IsSame::Type>::value, + typename detail::MakeSigned >::Type {}; namespace detail { -template +template struct CorrespondingUnsigned; -template<> -struct CorrespondingUnsigned { typedef unsigned char Type; }; -template<> -struct CorrespondingUnsigned { typedef unsigned char Type; }; -template<> -struct CorrespondingUnsigned { typedef unsigned short Type; }; -template<> -struct CorrespondingUnsigned { typedef unsigned int Type; }; -template<> -struct CorrespondingUnsigned { typedef unsigned long Type; }; -template<> -struct CorrespondingUnsigned { typedef unsigned long long Type; }; - - -template::Type, - bool IsUnsignedIntegerType = IsUnsigned::value && - !IsSame::value> +template <> +struct CorrespondingUnsigned { + typedef unsigned char Type; +}; +template <> +struct CorrespondingUnsigned { + typedef unsigned char Type; +}; +template <> +struct CorrespondingUnsigned { + typedef unsigned short Type; +}; +template <> +struct CorrespondingUnsigned { + typedef unsigned int Type; +}; +template <> +struct CorrespondingUnsigned { + typedef unsigned long Type; +}; +template <> +struct CorrespondingUnsigned { + typedef unsigned long long Type; +}; + +template ::Type, + bool IsUnsignedIntegerType = + IsUnsigned::value && !IsSame::value> struct MakeUnsigned; -template -struct MakeUnsigned -{ +template +struct MakeUnsigned { typedef T Type; }; -template +template struct MakeUnsigned - : WithCV::value, IsVolatile::value, - typename CorrespondingUnsigned::Type> -{}; + : WithCV::value, IsVolatile::value, + typename CorrespondingUnsigned::Type> {}; -} // namespace detail +} // namespace detail /** * MakeUnsigned produces the corresponding unsigned integer type for a given @@ -1073,13 +1103,11 @@ * mozilla::MakeUnsigned is an error; * mozilla::MakeUnsigned is an error. */ -template +template struct MakeUnsigned - : EnableIf::value && - !IsSame::Type>::value, - typename detail::MakeUnsigned - >::Type -{}; + : EnableIf::value && + !IsSame::Type>::value, + typename detail::MakeUnsigned >::Type {}; /* 20.9.7.4 Array modifications [meta.trans.arr] */ @@ -1092,21 +1120,18 @@ * mozilla::RemoveExtent::Type is volatile int; * mozilla::RemoveExtent::Type is long[17]. */ -template -struct RemoveExtent -{ +template +struct RemoveExtent { typedef T Type; }; -template -struct RemoveExtent -{ +template +struct RemoveExtent { typedef T Type; }; -template -struct RemoveExtent -{ +template +struct RemoveExtent { typedef T Type; }; @@ -1114,19 +1139,17 @@ namespace detail { -template -struct RemovePointerHelper -{ +template +struct RemovePointerHelper { typedef T Type; }; -template -struct RemovePointerHelper -{ +template +struct RemovePointerHelper { typedef Pointee Type; }; -} // namespace detail +} // namespace detail /** * Produces the pointed-to type if a pointer is provided, else returns the input @@ -1143,10 +1166,9 @@ * mozilla::RemovePointer::Type is void(); * mozilla::RemovePointer::Type is bool S::*. */ -template +template struct RemovePointer - : detail::RemovePointerHelper::Type> -{}; + : detail::RemovePointerHelper::Type> {}; /** * Converts T& to T*. Otherwise returns T* given T. Note that C++17 wants @@ -1158,9 +1180,8 @@ * mozilla::AddPointer is int*; * mozilla::AddPointer is int** const. */ -template -struct AddPointer -{ +template +struct AddPointer { typedef typename RemoveReference::Type* Type; }; @@ -1184,13 +1205,11 @@ * ... * }; */ -template -struct EnableIf -{}; - -template -struct EnableIf -{ +template +struct EnableIf {}; + +template +struct EnableIf { typedef T Type; }; @@ -1200,44 +1219,38 @@ * mozilla::Conditional::Type is A; * mozilla::Conditional::Type is B; */ -template -struct Conditional -{ +template +struct Conditional { typedef A Type; }; -template -struct Conditional -{ +template +struct Conditional { typedef B Type; }; namespace detail { -template::value, - bool IsFunction = IsFunction::value> +template ::value, + bool IsFunction = IsFunction::value> struct DecaySelector; -template -struct DecaySelector -{ +template +struct DecaySelector { typedef typename RemoveCV::Type Type; }; -template -struct DecaySelector -{ +template +struct DecaySelector { typedef typename RemoveExtent::Type* Type; }; -template -struct DecaySelector -{ +template +struct DecaySelector { typedef typename AddPointer::Type Type; }; -}; // namespace detail +}; // namespace detail /** * Strips const/volatile off a type and decays it from an lvalue to an @@ -1251,10 +1264,8 @@ * mozilla::Decay::Type is int* * mozilla::Decay::Type is int(*)(int) */ -template -class Decay - : public detail::DecaySelector::Type> -{ +template +class Decay : public detail::DecaySelector::Type> { }; } /* namespace mozilla */ 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 @@ -40,70 +40,58 @@ * operators have as return type a class, CastableTypedEnumResult, * that wraps a typed enum but adds bool convertibility. */ -template -class CastableTypedEnumResult -{ -private: +template +class CastableTypedEnumResult { + private: const E mValue; -public: - explicit constexpr CastableTypedEnumResult(E aValue) - : mValue(aValue) - {} + public: + explicit constexpr CastableTypedEnumResult(E aValue) : mValue(aValue) {} constexpr operator E() const { return mValue; } - template - explicit constexpr - operator DestinationType() const { return DestinationType(mValue); } + template + explicit constexpr operator DestinationType() const { + return DestinationType(mValue); + } - constexpr bool operator !() const { return !bool(mValue); } + constexpr bool operator!() const { return !bool(mValue); } }; -#define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType) \ -template \ -constexpr ReturnType \ -operator Op(const OtherType& aE, const CastableTypedEnumResult& aR) \ -{ \ - return ReturnType(aE Op OtherType(aR)); \ -} \ -template \ -constexpr ReturnType \ -operator Op(const CastableTypedEnumResult& aR, const OtherType& aE) \ -{ \ - return ReturnType(OtherType(aR) Op aE); \ -} \ -template \ -constexpr ReturnType \ -operator Op(const CastableTypedEnumResult& aR1, \ - const CastableTypedEnumResult& aR2) \ -{ \ - return ReturnType(OtherType(aR1) Op OtherType(aR2)); \ -} +#define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType) \ + template \ + constexpr ReturnType operator Op(const OtherType& aE, \ + const CastableTypedEnumResult& aR) { \ + return ReturnType(aE Op OtherType(aR)); \ + } \ + template \ + constexpr ReturnType operator Op(const CastableTypedEnumResult& aR, \ + const OtherType& aE) { \ + return ReturnType(OtherType(aR) Op aE); \ + } \ + template \ + constexpr ReturnType operator Op(const CastableTypedEnumResult& aR1, \ + const CastableTypedEnumResult& aR2) { \ + return ReturnType(OtherType(aR1) Op OtherType(aR2)); \ + } MOZ_CASTABLETYPEDENUMRESULT_BINOP(|, E, CastableTypedEnumResult) MOZ_CASTABLETYPEDENUMRESULT_BINOP(&, E, CastableTypedEnumResult) -MOZ_CASTABLETYPEDENUMRESULT_BINOP(^, E, CastableTypedEnumResult) +MOZ_CASTABLETYPEDENUMRESULT_BINOP (^, E, CastableTypedEnumResult) MOZ_CASTABLETYPEDENUMRESULT_BINOP(==, E, bool) MOZ_CASTABLETYPEDENUMRESULT_BINOP(!=, E, bool) -MOZ_CASTABLETYPEDENUMRESULT_BINOP(||, bool, bool) -MOZ_CASTABLETYPEDENUMRESULT_BINOP(&&, bool, bool) template -constexpr CastableTypedEnumResult -operator ~(const CastableTypedEnumResult& aR) -{ +constexpr CastableTypedEnumResult operator~( + const CastableTypedEnumResult& aR) { return CastableTypedEnumResult(~(E(aR))); } -#define MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(Op) \ -template \ -E& \ -operator Op(E& aR1, \ - const CastableTypedEnumResult& aR2) \ -{ \ - return aR1 Op E(aR2); \ -} +#define MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(Op) \ + template \ + E& operator Op(E& aR1, const CastableTypedEnumResult& aR2) { \ + return aR1 Op E(aR2); \ + } MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(&=) MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(|=) @@ -114,43 +102,34 @@ #undef MOZ_CASTABLETYPEDENUMRESULT_BINOP namespace detail { -template -struct UnsignedIntegerTypeForEnum - : UnsignedStdintTypeForSize -{}; -} // namespace detail - -} // namespace mozilla - -#define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op) \ - inline constexpr mozilla::CastableTypedEnumResult \ - operator Op(Name a, Name b) \ - { \ - typedef mozilla::CastableTypedEnumResult Result; \ - typedef mozilla::detail::UnsignedIntegerTypeForEnum::Type U; \ - return Result(Name(U(a) Op U(b))); \ - } \ - \ - inline Name& \ - operator Op##=(Name& a, Name b) \ - { \ - return a = a Op b; \ - } +template +struct UnsignedIntegerTypeForEnum : UnsignedStdintTypeForSize {}; +} // namespace detail + +} // namespace mozilla + +#define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op) \ + inline constexpr mozilla::CastableTypedEnumResult operator Op( \ + Name a, Name b) { \ + typedef mozilla::CastableTypedEnumResult Result; \ + typedef mozilla::detail::UnsignedIntegerTypeForEnum::Type U; \ + return Result(Name(U(a) Op U(b))); \ + } \ + \ + inline Name& operator Op##=(Name& a, Name b) { return a = a Op b; } /** * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS generates standard bitwise operators * for the given enum type. Use this to enable using an enum type as bit-field. */ -#define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name) \ - MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |) \ - MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &) \ - MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^) \ - inline constexpr mozilla::CastableTypedEnumResult \ - operator~(Name a) \ - { \ - typedef mozilla::CastableTypedEnumResult Result; \ - typedef mozilla::detail::UnsignedIntegerTypeForEnum::Type U; \ - return Result(Name(~(U(a)))); \ - } +#define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name) \ + MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |) \ + MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &) \ + MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^) \ + inline constexpr mozilla::CastableTypedEnumResult operator~(Name a) { \ + typedef mozilla::CastableTypedEnumResult Result; \ + typedef mozilla::detail::UnsignedIntegerTypeForEnum::Type U; \ + return Result(Name(~(U(a)))); \ + } -#endif // mozilla_TypedEnumBits_h +#endif // mozilla_TypedEnumBits_h 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 @@ -38,17 +38,16 @@ * methods or data used cross-file. */ #if defined(WIN32) -# define MOZ_EXPORT __declspec(dllexport) +#define MOZ_EXPORT __declspec(dllexport) #else /* Unix */ -# ifdef HAVE_VISIBILITY_ATTRIBUTE -# define MOZ_EXPORT __attribute__((visibility("default"))) -# elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# define MOZ_EXPORT __global -# else -# define MOZ_EXPORT /* nothing */ -# endif +#ifdef HAVE_VISIBILITY_ATTRIBUTE +#define MOZ_EXPORT __attribute__((visibility("default"))) +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#define MOZ_EXPORT __global +#else +#define MOZ_EXPORT /* nothing */ +#endif #endif - /* * Whereas implementers use MOZ_EXPORT to declare and define library symbols, @@ -58,19 +57,19 @@ * mode. */ #ifdef _WIN32 -# if defined(__MWERKS__) -# define MOZ_IMPORT_API /* nothing */ -# else -# define MOZ_IMPORT_API __declspec(dllimport) -# endif +#if defined(__MWERKS__) +#define MOZ_IMPORT_API /* nothing */ #else -# define MOZ_IMPORT_API MOZ_EXPORT +#define MOZ_IMPORT_API __declspec(dllimport) +#endif +#else +#define MOZ_IMPORT_API MOZ_EXPORT #endif #if defined(_WIN32) && !defined(__MWERKS__) -# define MOZ_IMPORT_DATA __declspec(dllimport) +#define MOZ_IMPORT_DATA __declspec(dllimport) #else -# define MOZ_IMPORT_DATA MOZ_EXPORT +#define MOZ_IMPORT_DATA MOZ_EXPORT #endif /* @@ -78,24 +77,31 @@ * export mfbt declarations when building mfbt, and they expose import mfbt * declarations when using mfbt. */ -#if defined(IMPL_MFBT) -# define MFBT_API MOZ_EXPORT -# define MFBT_DATA MOZ_EXPORT -#else - /* - * On linux mozglue is linked in the program and we link libxul.so with - * -z,defs. Normally that causes the linker to reject undefined references in - * libxul.so, but as a loophole it allows undefined references to weak - * symbols. We add the weak attribute to the import version of the MFBT API - * macros to exploit this. - */ -# if defined(MOZ_GLUE_IN_PROGRAM) -# define MFBT_API __attribute__((weak)) MOZ_IMPORT_API -# define MFBT_DATA __attribute__((weak)) MOZ_IMPORT_DATA -# else -# define MFBT_API MOZ_IMPORT_API -# define MFBT_DATA MOZ_IMPORT_DATA -# endif +#if defined(IMPL_MFBT) || \ + (defined(JS_STANDALONE) && !defined(MOZ_MEMORY) && \ + (defined(EXPORT_JS_API) || defined(STATIC_EXPORTABLE_JS_API))) +#define MFBT_API MOZ_EXPORT +#define MFBT_DATA MOZ_EXPORT +#else +#if defined(JS_STANDALONE) && !defined(MOZ_MEMORY) && defined(STATIC_JS_API) +#define MFBT_API +#define MFBT_DATA +#else +/* + * On linux mozglue is linked in the program and we link libxul.so with + * -z,defs. Normally that causes the linker to reject undefined references in + * libxul.so, but as a loophole it allows undefined references to weak + * symbols. We add the weak attribute to the import version of the MFBT API + * macros to exploit this. + */ +#if defined(MOZ_GLUE_IN_PROGRAM) +#define MFBT_API __attribute__((weak)) MOZ_IMPORT_API +#define MFBT_DATA __attribute__((weak)) MOZ_IMPORT_DATA +#else +#define MFBT_API MOZ_IMPORT_API +#define MFBT_DATA MOZ_IMPORT_DATA +#endif +#endif #endif /* @@ -116,19 +122,19 @@ * its greater clarity. */ #ifdef __cplusplus -# define MOZ_BEGIN_EXTERN_C extern "C" { -# define MOZ_END_EXTERN_C } +#define MOZ_BEGIN_EXTERN_C extern "C" { +#define MOZ_END_EXTERN_C } #else -# define MOZ_BEGIN_EXTERN_C -# define MOZ_END_EXTERN_C +#define MOZ_BEGIN_EXTERN_C +#define MOZ_END_EXTERN_C #endif /* * GCC's typeof is available when decltype is not. */ #if defined(__GNUC__) && defined(__cplusplus) && \ - !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L -# define decltype __typeof__ + !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L +#define decltype __typeof__ #endif #endif /* mozilla_Types_h */ 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 @@ -18,45 +18,46 @@ namespace mozilla { -template class DefaultDelete; -template> class UniquePtr; +template +class DefaultDelete; +template > +class UniquePtr; -} // namespace mozilla +} // namespace mozilla namespace mozilla { namespace detail { -struct HasPointerTypeHelper -{ - template static double Test(...); - template static char Test(typename U::pointer* = 0); +struct HasPointerTypeHelper { + template + static double Test(...); + template + static char Test(typename U::pointer* = 0); }; template -class HasPointerType : public IntegralConstant(0)) == 1> -{ -}; +class HasPointerType + : public IntegralConstant(0)) == 1> {}; template ::value> -struct PointerTypeImpl -{ +struct PointerTypeImpl { typedef typename D::pointer Type; }; template -struct PointerTypeImpl -{ +struct PointerTypeImpl { typedef T* Type; }; template -struct PointerType -{ - typedef typename PointerTypeImpl::Type>::Type Type; +struct PointerType { + typedef + typename PointerTypeImpl::Type>::Type Type; }; -} // namespace detail +} // namespace detail /** * UniquePtr is a smart pointer that wholly owns a resource. Ownership may be @@ -184,15 +185,14 @@ * ownership of a resource into a method, should the method want it, use a * |UniquePtr&&| argument. */ -template -class UniquePtr -{ -public: +template +class UniquePtr { + public: typedef T ElementType; typedef D DeleterType; typedef typename detail::PointerType::Type Pointer; -private: + private: Pair mTuple; Pointer& ptr() { return mTuple.first(); } @@ -201,13 +201,11 @@ DeleterType& del() { return mTuple.second(); } const DeleterType& del() const { return mTuple.second(); } -public: + public: /** * Construct a UniquePtr containing |nullptr|. */ - constexpr UniquePtr() - : mTuple(static_cast(nullptr), DeleterType()) - { + constexpr UniquePtr() : mTuple(static_cast(nullptr), DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); static_assert(!IsReference::value, "must provide a deleter instance"); } @@ -215,19 +213,14 @@ /** * Construct a UniquePtr containing |aPtr|. */ - explicit UniquePtr(Pointer aPtr) - : mTuple(aPtr, DeleterType()) - { + explicit UniquePtr(Pointer aPtr) : mTuple(aPtr, DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); static_assert(!IsReference::value, "must provide a deleter instance"); } UniquePtr(Pointer aPtr, - typename Conditional::value, - D, - const D&>::Type aD1) - : mTuple(aPtr, aD1) - {} + typename Conditional::value, D, const D&>::Type aD1) + : mTuple(aPtr, aD1) {} // If you encounter an error with MSVC10 about RemoveReference below, along // the lines that "more than one partial specialization matches the template @@ -251,55 +244,45 @@ // around this with a deleter class that contains the function reference. // But this workaround is untried and untested, because variable deletion // behavior really isn't something you should use. - UniquePtr(Pointer aPtr, - typename RemoveReference::Type&& aD2) - : mTuple(aPtr, Move(aD2)) - { + UniquePtr(Pointer aPtr, typename RemoveReference::Type&& aD2) + : mTuple(aPtr, Move(aD2)) { static_assert(!IsReference::value, "rvalue deleter can't be stored by reference"); } UniquePtr(UniquePtr&& aOther) - : mTuple(aOther.release(), Forward(aOther.get_deleter())) - {} + : mTuple(aOther.release(), Forward(aOther.get_deleter())) {} MOZ_IMPLICIT - UniquePtr(decltype(nullptr)) - : mTuple(nullptr, DeleterType()) - { + UniquePtr(decltype(nullptr)) : mTuple(nullptr, DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); static_assert(!IsReference::value, "must provide a deleter instance"); } - template - MOZ_IMPLICIT - UniquePtr(UniquePtr&& aOther, - typename EnableIf::Pointer, - Pointer>::value && - !IsArray::value && - (IsReference::value - ? IsSame::value - : IsConvertible::value), - int>::Type aDummy = 0) - : mTuple(aOther.release(), Forward(aOther.get_deleter())) - { - } + template + MOZ_IMPLICIT UniquePtr( + UniquePtr&& aOther, + typename EnableIf< + IsConvertible::Pointer, Pointer>::value && + !IsArray::value && + (IsReference::value ? IsSame::value + : IsConvertible::value), + int>::Type aDummy = 0) + : mTuple(aOther.release(), Forward(aOther.get_deleter())) {} ~UniquePtr() { reset(nullptr); } - UniquePtr& operator=(UniquePtr&& aOther) - { + UniquePtr& operator=(UniquePtr&& aOther) { reset(aOther.release()); get_deleter() = Forward(aOther.get_deleter()); return *this; } - template - UniquePtr& operator=(UniquePtr&& aOther) - { - static_assert(IsConvertible::Pointer, - Pointer>::value, - "incompatible UniquePtr pointees"); + template + UniquePtr& operator=(UniquePtr&& aOther) { + static_assert( + IsConvertible::Pointer, Pointer>::value, + "incompatible UniquePtr pointees"); static_assert(!IsArray::value, "can't assign from UniquePtr holding an array"); @@ -308,15 +291,13 @@ return *this; } - UniquePtr& operator=(decltype(nullptr)) - { + UniquePtr& operator=(decltype(nullptr)) { reset(nullptr); return *this; } T& operator*() const { return *get(); } - Pointer operator->() const - { + Pointer operator->() const { MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr"); return get(); } @@ -328,15 +309,13 @@ DeleterType& get_deleter() { return del(); } const DeleterType& get_deleter() const { return del(); } - MOZ_MUST_USE Pointer release() - { + MOZ_MUST_USE Pointer release() { Pointer p = ptr(); ptr() = nullptr; return p; } - void reset(Pointer aPtr = Pointer()) - { + void reset(Pointer aPtr = Pointer()) { Pointer old = ptr(); ptr() = aPtr; if (old != nullptr) { @@ -344,37 +323,31 @@ } } - void swap(UniquePtr& aOther) - { - mTuple.swap(aOther.mTuple); - } + void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); } - UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()! - void operator=(const UniquePtr& aOther) = delete; // assign using Move()! + UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()! + void operator=(const UniquePtr& aOther) = delete; // assign using Move()! }; // In case you didn't read the comment by the main definition (you should!): the // UniquePtr specialization exists to manage array pointers. It deletes // such pointers using delete[], it will reject construction and modification // attempts using U* or U[]. Otherwise it works like the normal UniquePtr. -template -class UniquePtr -{ -public: +template +class UniquePtr { + public: typedef T* Pointer; typedef T ElementType; typedef D DeleterType; -private: + private: Pair mTuple; -public: + public: /** * Construct a UniquePtr containing nullptr. */ - constexpr UniquePtr() - : mTuple(static_cast(nullptr), DeleterType()) - { + constexpr UniquePtr() : mTuple(static_cast(nullptr), DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); static_assert(!IsReference::value, "must provide a deleter instance"); } @@ -382,9 +355,7 @@ /** * Construct a UniquePtr containing |aPtr|. */ - explicit UniquePtr(Pointer aPtr) - : mTuple(aPtr, DeleterType()) - { + explicit UniquePtr(Pointer aPtr) : mTuple(aPtr, DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); static_assert(!IsReference::value, "must provide a deleter instance"); } @@ -394,63 +365,51 @@ // fields and base classes of each element requiring destruction, and so on. // So forbid all overloads which would end up invoking delete[] on a pointer // of the wrong type. - template - UniquePtr(U&& aU, - typename EnableIf::value && - IsConvertible::value, - int>::Type aDummy = 0) - = delete; + template + UniquePtr( + U&& aU, + typename EnableIf::value && IsConvertible::value, + int>::Type aDummy = 0) = delete; UniquePtr(Pointer aPtr, - typename Conditional::value, - D, - const D&>::Type aD1) - : mTuple(aPtr, aD1) - {} + typename Conditional::value, D, const D&>::Type aD1) + : mTuple(aPtr, aD1) {} // If you encounter an error with MSVC10 about RemoveReference below, along // the lines that "more than one partial specialization matches the template // argument list": don't use UniquePtr! See the // comment by this constructor in the non-T[] specialization above. - UniquePtr(Pointer aPtr, - typename RemoveReference::Type&& aD2) - : mTuple(aPtr, Move(aD2)) - { + UniquePtr(Pointer aPtr, typename RemoveReference::Type&& aD2) + : mTuple(aPtr, Move(aD2)) { static_assert(!IsReference::value, "rvalue deleter can't be stored by reference"); } // Forbidden for the same reasons as stated above. - template - UniquePtr(U&& aU, V&& aV, - typename EnableIf::value && - IsConvertible::value, - int>::Type aDummy = 0) - = delete; + template + UniquePtr( + U&& aU, V&& aV, + typename EnableIf::value && IsConvertible::value, + int>::Type aDummy = 0) = delete; UniquePtr(UniquePtr&& aOther) - : mTuple(aOther.release(), Forward(aOther.get_deleter())) - {} + : mTuple(aOther.release(), Forward(aOther.get_deleter())) {} MOZ_IMPLICIT - UniquePtr(decltype(nullptr)) - : mTuple(nullptr, DeleterType()) - { + UniquePtr(decltype(nullptr)) : mTuple(nullptr, DeleterType()) { static_assert(!IsPointer::value, "must provide a deleter instance"); static_assert(!IsReference::value, "must provide a deleter instance"); } ~UniquePtr() { reset(nullptr); } - UniquePtr& operator=(UniquePtr&& aOther) - { + UniquePtr& operator=(UniquePtr&& aOther) { reset(aOther.release()); get_deleter() = Forward(aOther.get_deleter()); return *this; } - UniquePtr& operator=(decltype(nullptr)) - { + UniquePtr& operator=(decltype(nullptr)) { reset(); return *this; } @@ -463,15 +422,13 @@ DeleterType& get_deleter() { return mTuple.second(); } const DeleterType& get_deleter() const { return mTuple.second(); } - MOZ_MUST_USE Pointer release() - { + MOZ_MUST_USE Pointer release() { Pointer p = mTuple.first(); mTuple.first() = nullptr; return p; } - void reset(Pointer aPtr = Pointer()) - { + void reset(Pointer aPtr = Pointer()) { Pointer old = mTuple.first(); mTuple.first() = aPtr; if (old != nullptr) { @@ -479,8 +436,7 @@ } } - void reset(decltype(nullptr)) - { + void reset(decltype(nullptr)) { Pointer old = mTuple.first(); mTuple.first() = nullptr; if (old != nullptr) { @@ -488,13 +444,13 @@ } } - template + template void reset(U) = delete; void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); } - UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()! - void operator=(const UniquePtr& aOther) = delete; // assign using Move()! + UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()! + void operator=(const UniquePtr& aOther) = delete; // assign using Move()! }; /** @@ -510,88 +466,70 @@ * types), since |delete|-ing such a type will always trigger a compilation * error. */ -template -class DefaultDelete -{ -public: +template +class DefaultDelete { + public: constexpr DefaultDelete() {} - template - MOZ_IMPLICIT DefaultDelete(const DefaultDelete& aOther, - typename EnableIf::value, - int>::Type aDummy = 0) - {} + template + MOZ_IMPLICIT DefaultDelete( + const DefaultDelete& aOther, + typename EnableIf::value, int>::Type + aDummy = 0) {} - void operator()(T* aPtr) const - { + void operator()(T* aPtr) const { static_assert(sizeof(T) > 0, "T must be complete"); delete aPtr; } }; /** A default deletion policy using operator delete[]. */ -template -class DefaultDelete -{ -public: +template +class DefaultDelete { + public: constexpr DefaultDelete() {} - void operator()(T* aPtr) const - { + void operator()(T* aPtr) const { static_assert(sizeof(T) > 0, "T must be complete"); delete[] aPtr; } - template + template void operator()(U* aPtr) const = delete; }; -template -void -Swap(UniquePtr& aX, UniquePtr& aY) -{ +template +void Swap(UniquePtr& aX, UniquePtr& aY) { aX.swap(aY); } -template -bool -operator==(const UniquePtr& aX, const UniquePtr& aY) -{ +template +bool operator==(const UniquePtr& aX, const UniquePtr& aY) { return aX.get() == aY.get(); } -template -bool -operator!=(const UniquePtr& aX, const UniquePtr& aY) -{ +template +bool operator!=(const UniquePtr& aX, const UniquePtr& aY) { return aX.get() != aY.get(); } -template -bool -operator==(const UniquePtr& aX, decltype(nullptr)) -{ +template +bool operator==(const UniquePtr& aX, decltype(nullptr)) { return !aX; } -template -bool -operator==(decltype(nullptr), const UniquePtr& aX) -{ +template +bool operator==(decltype(nullptr), const UniquePtr& aX) { return !aX; } -template -bool -operator!=(const UniquePtr& aX, decltype(nullptr)) -{ +template +bool operator!=(const UniquePtr& aX, decltype(nullptr)) { return bool(aX); } -template -bool -operator!=(decltype(nullptr), const UniquePtr& aX) -{ +template +bool operator!=(decltype(nullptr), const UniquePtr& aX) { return bool(aX); } @@ -599,25 +537,22 @@ namespace detail { -template -struct UniqueSelector -{ +template +struct UniqueSelector { typedef UniquePtr SingleObject; }; -template -struct UniqueSelector -{ +template +struct UniqueSelector { typedef UniquePtr UnknownBound; }; -template -struct UniqueSelector -{ +template +struct UniqueSelector { typedef UniquePtr KnownBound; }; -} // namespace detail +} // namespace detail /** * MakeUnique is a helper function for allocating new'd objects and arrays, @@ -673,25 +608,22 @@ * ably serves this function.) */ -template -typename detail::UniqueSelector::SingleObject -MakeUnique(Args&&... aArgs) -{ +template +typename detail::UniqueSelector::SingleObject MakeUnique(Args&&... aArgs) { return UniquePtr(new T(Forward(aArgs)...)); } -template -typename detail::UniqueSelector::UnknownBound -MakeUnique(decltype(sizeof(int)) aN) -{ +template +typename detail::UniqueSelector::UnknownBound MakeUnique( + decltype(sizeof(int)) aN) { typedef typename RemoveExtent::Type ArrayType; return UniquePtr(new ArrayType[aN]()); } -template -typename detail::UniqueSelector::KnownBound -MakeUnique(Args&&... aArgs) = delete; +template +typename detail::UniqueSelector::KnownBound MakeUnique(Args&&... aArgs) = + delete; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_UniquePtr_h */ 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 @@ -18,40 +18,35 @@ * MakeUniqueFallible works exactly like MakeUnique, except that the memory * allocation performed is done fallibly, i.e. it can return nullptr. */ -template -typename detail::UniqueSelector::SingleObject -MakeUniqueFallible(Args&&... aArgs) -{ +template +typename detail::UniqueSelector::SingleObject MakeUniqueFallible( + Args&&... aArgs) { return UniquePtr(new (fallible) T(Forward(aArgs)...)); } -template -typename detail::UniqueSelector::UnknownBound -MakeUniqueFallible(decltype(sizeof(int)) aN) -{ +template +typename detail::UniqueSelector::UnknownBound MakeUniqueFallible( + decltype(sizeof(int)) aN) { typedef typename RemoveExtent::Type ArrayType; return UniquePtr(new (fallible) ArrayType[aN]()); } -template -typename detail::UniqueSelector::KnownBound -MakeUniqueFallible(Args&&... aArgs) = delete; +template +typename detail::UniqueSelector::KnownBound MakeUniqueFallible( + Args&&... aArgs) = delete; namespace detail { -template -struct FreePolicy -{ - void operator()(const void* ptr) { - free(const_cast(ptr)); - } +template +struct FreePolicy { + void operator()(const void* ptr) { free(const_cast(ptr)); } }; -} // namespace detail +} // namespace detail -template +template using UniqueFreePtr = UniquePtr>; -} // namespace mozilla +} // namespace mozilla -#endif // mozilla_UniquePtrExtensions_h +#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 @@ -9,145 +9,128 @@ #include #include -#include "mozilla/Alignment.h" #include "mozilla/Assertions.h" #include "mozilla/Move.h" +#include "mozilla/OperatorNewExtensions.h" +#include "mozilla/TemplateLib.h" #include "mozilla/TypeTraits.h" #ifndef mozilla_Variant_h #define mozilla_Variant_h +namespace IPC { +template +struct ParamTraits; +} // namespace IPC + namespace mozilla { -template +template class Variant; namespace detail { -// MaxSizeOf computes the maximum sizeof(T) for each T in Ts. - -template -struct MaxSizeOf -{ - static const size_t size = sizeof(T) > MaxSizeOf::size - ? sizeof(T) - : MaxSizeOf::size; -}; - -template -struct MaxSizeOf -{ - static const size_t size = sizeof(T); -}; - -// The `IsVariant` helper is used in conjunction with static_assert and -// `mozilla::EnableIf` to catch passing non-variant types to `Variant::is()` -// and friends at compile time, rather than at runtime. It ensures that the -// given type `Needle` is one of the types in the set of types `Haystack`. - -template -struct IsVariant; - -template -struct IsVariant -{ - static const bool value = false; +// Nth::Type is the Nth type (0-based) in the list of types Ts. +template +struct Nth; + +template +struct Nth<0, T, Ts...> { + using Type = T; }; -template -struct IsVariant -{ - static const bool value = true; +template +struct Nth { + using Type = typename Nth::Type; }; -template -struct IsVariant : public IsVariant { }; - /// SelectVariantTypeHelper is used in the implementation of SelectVariantType. -template +template struct SelectVariantTypeHelper; -template -struct SelectVariantTypeHelper -{ }; - -template -struct SelectVariantTypeHelper -{ +template +struct SelectVariantTypeHelper { + static constexpr size_t count = 0; +}; + +template +struct SelectVariantTypeHelper { typedef T Type; + static constexpr size_t count = + 1 + SelectVariantTypeHelper::count; }; -template -struct SelectVariantTypeHelper -{ +template +struct SelectVariantTypeHelper { typedef const T Type; + static constexpr size_t count = + 1 + SelectVariantTypeHelper::count; }; -template -struct SelectVariantTypeHelper -{ +template +struct SelectVariantTypeHelper { typedef const T& Type; + static constexpr size_t count = + 1 + SelectVariantTypeHelper::count; }; -template -struct SelectVariantTypeHelper -{ +template +struct SelectVariantTypeHelper { typedef T&& Type; + static constexpr size_t count = + 1 + SelectVariantTypeHelper::count; }; -template +template struct SelectVariantTypeHelper - : public 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. + * SelectVariantType also has a `count` member that contains the total number of + * selectable types (which will be used to check that a requested type is not + * ambiguously present twice.) */ template struct SelectVariantType - : public SelectVariantTypeHelper::Type>::Type, - Variants...> -{ }; + : public SelectVariantTypeHelper< + typename RemoveConst::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: +template +struct VariantTag { + private: static const size_t TypeCount = sizeof...(Ts); -public: - using Type = - typename Conditional::Type - >::Type; + public: + using Type = typename Conditional < TypeCount < 3, bool, + typename Conditional< + TypeCount<(1 << 8), uint_fast8_t, + size_t // stop caring past a certain point :-) + >::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. -template +template struct TagHelper; // In the case where T != U, we continue recursion. -template -struct TagHelper -{ +template +struct TagHelper { static Tag tag() { return Next::template tag(); } }; // In the case where T == U, return the tag number. -template -struct TagHelper -{ +template +struct TagHelper { static Tag tag() { return Tag(N); } }; @@ -157,106 +140,99 @@ // 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 +template +struct VariantImplementation { + template static Tag tag() { static_assert(mozilla::IsSame::value, "mozilla::Variant: tag: bad type!"); return Tag(N); } - template + template static void copyConstruct(void* aLhs, const Variant& aRhs) { - new (aLhs) T(aRhs.template as()); + ::new (KnownNotNull, aLhs) T(aRhs.template as()); } - template + template static void moveConstruct(void* aLhs, Variant&& aRhs) { - new (aLhs) T(aRhs.template extract()); + ::new (KnownNotNull, aLhs) T(aRhs.template extract()); } - template + template static void destroy(Variant& aV) { - aV.template as().~T(); + aV.template as().~T(); } - template - static bool - equal(const Variant& aLhs, const Variant& aRhs) { - return aLhs.template as() == aRhs.template as(); + template + static bool equal(const Variant& aLhs, const Variant& aRhs) { + return aLhs.template as() == aRhs.template as(); } - template - static auto - match(Matcher&& aMatcher, ConcreteVariant& aV) - -> decltype(aMatcher.match(aV.template as())) - { - return aMatcher.match(aV.template as()); + template + 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; - template + template static Tag tag() { return TagHelper::value>::tag(); } - template + template static void copyConstruct(void* aLhs, const Variant& aRhs) { - if (aRhs.template is()) { - new (aLhs) T(aRhs.template as()); + if (aRhs.template is()) { + ::new (KnownNotNull, aLhs) T(aRhs.template as()); } else { Next::copyConstruct(aLhs, aRhs); } } - template + template static void moveConstruct(void* aLhs, Variant&& aRhs) { - if (aRhs.template is()) { - new (aLhs) T(aRhs.template extract()); + if (aRhs.template is()) { + ::new (KnownNotNull, aLhs) T(aRhs.template extract()); } else { - Next::moveConstruct(aLhs, aRhs); + Next::moveConstruct(aLhs, Move(aRhs)); } } - template + template static void destroy(Variant& aV) { - if (aV.template is()) { - aV.template as().~T(); + if (aV.template is()) { + aV.template as().~T(); } else { Next::destroy(aV); } } - template + template static bool equal(const Variant& aLhs, const Variant& aRhs) { - if (aLhs.template is()) { - MOZ_ASSERT(aRhs.template is()); - return aLhs.template as() == aRhs.template as(); + if (aLhs.template is()) { + MOZ_ASSERT(aRhs.template is()); + return aLhs.template as() == aRhs.template as(); } else { return Next::equal(aLhs, aRhs); } } - template - static auto - match(Matcher&& aMatcher, ConcreteVariant& aV) - -> decltype(aMatcher.match(aV.template as())) - { - if (aV.template is()) { - return aMatcher.match(aV.template as()); + template + static auto match(Matcher&& aMatcher, ConcreteVariant& aV) + -> decltype(aMatcher.match(aV.template as())) { + if (aV.template is()) { + return aMatcher.match(aV.template as()); } else { // If you're seeing compilation errors here like "no matching // function for call to 'match'" then that means that the @@ -280,24 +256,17 @@ * primitive or very small types. */ template -struct AsVariantTemporary -{ - explicit AsVariantTemporary(const T& aValue) - : mValue(aValue) - {} - - template - explicit AsVariantTemporary(U&& aValue) - : mValue(Forward(aValue)) - {} +struct AsVariantTemporary { + explicit AsVariantTemporary(const T& aValue) : mValue(aValue) {} + + template + explicit AsVariantTemporary(U&& aValue) : mValue(Forward(aValue)) {} AsVariantTemporary(const AsVariantTemporary& aOther) - : mValue(aOther.mValue) - {} + : mValue(aOther.mValue) {} AsVariantTemporary(AsVariantTemporary&& aOther) - : mValue(Move(aOther.mValue)) - {} + : mValue(Move(aOther.mValue)) {} AsVariantTemporary() = delete; void operator=(const AsVariantTemporary&) = delete; @@ -306,7 +275,19 @@ typename RemoveConst::Type>::Type mValue; }; -} // namespace detail +} // namespace detail + +// Used to unambiguously specify one of the Variant's type. +template +struct VariantType { + using Type = T; +}; + +// Used to specify one of the Variant's type by index. +template +struct VariantIndex { + static constexpr size_t index = N; +}; /** * # mozilla::Variant @@ -328,20 +309,35 @@ * * Variant v1('a'); * Variant, B, C> v2(MakeUnique()); + * Variant v3(VariantType, 0); // disambiguation needed + * Variant v4(VariantIndex<1>, 0); // 2nd int * * 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. + * there are two easier ways to construct values: * + * A. 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'). * + * B. Brace-construction with VariantType or VariantIndex; this also allows + * in-place construction with any number of arguments. + * + * struct AB { AB(int, int){...} }; + * static Variant foo() + * { + * return {VariantIndex<0>{}, 1, 2}; + * } + * // ... + * Variant v0 = Foo(); // v0 holds AB(1,2). + * * All access to the contained value goes through type-safe accessors. + * Either the stored type, or the type index may be provided. * * void * Foo(Variant v) @@ -349,11 +345,47 @@ * if (v.is()) { * A& ref = v.as(); * ... + * } else (v.is<1>()) { // Instead of v.is. + * ... * } else { * ... * } * } * + * In some situation, a Variant may be constructed from templated types, in + * which case it is possible that the same type could be given multiple times by + * an external developer. Or seemingly-different types could be aliases. + * In this case, repeated types can only be accessed through their index, to + * prevent ambiguous access by type. + * + * // Bad! + * template + * struct ResultOrError + * { + * Variant m; + * ResultOrError() : m(int(0)) {} // Error '0' by default + * ResultOrError(const T& r) : m(r) {} + * bool IsResult() const { return m.is(); } + * bool IsError() const { return m.is(); } + * }; + * // Now instantiante with the result being an int too: + * ResultOrError myResult(123); // Fail! + * // In Variant, which 'int' are we refering to, from inside + * // ResultOrError functions? + * + * // Good! + * template + * struct ResultOrError + * { + * Variant m; + * ResultOrError() : m(VariantIndex<1>{}, 0) {} // Error '0' by default + * ResultOrError(const T& r) : m(VariantIndex<0>{}, r) {} + * bool IsResult() const { return m.is<0>(); } // 0 -> T + * bool IsError() const { return m.is<1>(); } // 1 -> int + * }; + * // Now instantiante with the result being an int too: + * ResultOrError myResult(123); // It now works! + * * Attempting to use the contained value as type `T1` when the `Variant` * instance contains a value of type `T2` causes an assertion failure. * @@ -375,8 +407,8 @@ * auto ptr = v.extract>(); * * Finally, you can exhaustively match on the contained variant and branch into - * different code paths depending which type is contained. This is preferred to - * manually checking every variant type T with is() because it provides + * different code paths depending on which type is contained. This is preferred + * to manually checking every variant type T with is() because it provides * compile-time checking that you handled every type, rather than runtime * assertion failures. * @@ -430,37 +462,76 @@ * * ... * }; + * + * Because Variant must be aligned suitable to hold any value stored within it, + * and because |alignas| requirements don't affect platform ABI with respect to + * how parameters are laid out in memory, Variant can't be used as the type of a + * function parameter. Pass Variant to functions by pointer or reference + * instead. */ -template -class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Variant -{ +template +class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant { + friend struct IPC::ParamTraits>; + using Tag = typename detail::VariantTag::Type; using Impl = detail::VariantImplementation; - using RawData = AlignedStorage::size>; + + static constexpr size_t RawDataAlignment = tl::Max::value; + static constexpr size_t RawDataSize = tl::Max::value; // Raw storage for the contained variant value. - RawData raw; + alignas(RawDataAlignment) unsigned char rawData[RawDataSize]; // 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); - } + // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a + // -Werror compile error) to reinterpret_cast<> |rawData| to |T*|, even + // through |void*|. Placing the latter cast in these separate functions + // breaks the chain such that affected GCC versions no longer warn/error. + void* ptr() { return rawData; } + + const void* ptr() const { return rawData; } -public: + public: /** Perfect forwarding construction for some variant type T. */ - template::Type> - explicit Variant(RefT&& aT) - : tag(Impl::template tag()) - { - new (ptr()) T(Forward(aT)); + template ::Type> + explicit Variant(RefT&& aT) : tag(Impl::template tag()) { + static_assert( + detail::SelectVariantType::count == 1, + "Variant can only be selected by type if that type is unique"); + ::new (KnownNotNull, ptr()) T(Forward(aT)); + } + + /** + * Perfect forwarding construction for some variant type T, by + * explicitly giving the type. + * This is necessary to construct from any number of arguments, + * or to convert from a type that is not in the Variant's type list. + */ + template + MOZ_IMPLICIT Variant(const VariantType&, Args&&... aTs) + : tag(Impl::template tag()) { + ::new (KnownNotNull, ptr()) T(Forward(aTs)...); + } + + /** + * Perfect forwarding construction for some variant type T, by + * explicitly giving the type index. + * This is necessary to construct from any number of arguments, + * or to convert from a type that is not in the Variant's type list, + * or to construct a type that is present more than once in the Variant. + */ + template + MOZ_IMPLICIT Variant(const VariantIndex&, Args&&... aTs) : tag(N) { + using T = typename detail::Nth::Type; + ::new (KnownNotNull, ptr()) T(Forward(aTs)...); } /** @@ -468,25 +539,24 @@ * stored in one of the types allowable in this Variant. This is used in the * implementation of AsVariant(). */ - template::Type> + template MOZ_IMPLICIT Variant(detail::AsVariantTemporary&& aValue) - : tag(Impl::template tag()) - { - new (ptr()) T(Move(aValue.mValue)); + : tag(Impl::template tag< + typename detail::SelectVariantType::Type>()) { + using T = typename detail::SelectVariantType::Type; + static_assert( + detail::SelectVariantType::count == 1, + "Variant can only be selected by type if that type is unique"); + ::new (KnownNotNull, ptr()) T(Move(aValue.mValue)); } /** Copy construction. */ - Variant(const Variant& aRhs) - : tag(aRhs.tag) - { + Variant(const Variant& aRhs) : tag(aRhs.tag) { Impl::copyConstruct(ptr(), aRhs); } /** Move construction. */ - Variant(Variant&& aRhs) - : tag(aRhs.tag) - { + Variant(Variant&& aRhs) : tag(aRhs.tag) { Impl::moveConstruct(ptr(), Move(aRhs)); } @@ -494,7 +564,7 @@ Variant& operator=(const Variant& aRhs) { MOZ_ASSERT(&aRhs != this, "self-assign disallowed"); this->~Variant(); - new (this) Variant(aRhs); + ::new (KnownNotNull, this) Variant(aRhs); return *this; } @@ -502,32 +572,39 @@ Variant& operator=(Variant&& aRhs) { MOZ_ASSERT(&aRhs != this, "self-assign disallowed"); this->~Variant(); - new (this) Variant(Move(aRhs)); + ::new (KnownNotNull, this) Variant(Move(aRhs)); return *this; } /** Move assignment from AsVariant(). */ template - Variant& operator=(detail::AsVariantTemporary&& aValue) - { + Variant& operator=(detail::AsVariantTemporary&& aValue) { + static_assert( + detail::SelectVariantType::count == 1, + "Variant can only be selected by type if that type is unique"); this->~Variant(); - new (this) Variant(Move(aValue)); + ::new (KnownNotNull, this) Variant(Move(aValue)); return *this; } - ~Variant() - { - Impl::destroy(*this); - } + ~Variant() { Impl::destroy(*this); } /** Check which variant type is currently contained. */ - template + template bool is() const { - static_assert(detail::IsVariant::value, - "provided a type not found in this Variant's type list"); + static_assert( + detail::SelectVariantType::count == 1, + "provided a type not uniquely found in this Variant's type list"); return Impl::template tag() == tag; } + template + bool is() const { + static_assert(N < sizeof...(Ts), + "provided an index outside of this Variant's type list"); + return N == size_t(tag); + } + /** * Operator == overload that defers to the variant type's operator== * implementation if the rhs is tagged as the same type as this one. @@ -541,28 +618,43 @@ * operator== implementation if the rhs is tagged as the same type as this * one. */ - bool operator!=(const Variant& aRhs) const { - return !(*this == aRhs); - } + bool operator!=(const Variant& aRhs) const { return !(*this == aRhs); } // Accessors for working with the contained variant value. /** Mutable reference. */ - template + template T& as() { - static_assert(detail::IsVariant::value, - "provided a type not found in this Variant's type list"); - MOZ_ASSERT(is()); - return *reinterpret_cast(&raw); + static_assert( + detail::SelectVariantType::count == 1, + "provided a type not uniquely found in this Variant's type list"); + MOZ_RELEASE_ASSERT(is()); + return *static_cast(ptr()); + } + + template + typename detail::Nth::Type& as() { + static_assert(N < sizeof...(Ts), + "provided an index outside of this Variant's type list"); + MOZ_RELEASE_ASSERT(is()); + return *static_cast::Type*>(ptr()); } /** Immutable const reference. */ - template + template const T& as() const { - static_assert(detail::IsVariant::value, + static_assert(detail::SelectVariantType::count == 1, "provided a type not found in this Variant's type list"); - MOZ_ASSERT(is()); - return *reinterpret_cast(&raw); + MOZ_RELEASE_ASSERT(is()); + return *static_cast(ptr()); + } + + template + const typename detail::Nth::Type& as() const { + static_assert(N < sizeof...(Ts), + "provided an index outside of this Variant's type list"); + MOZ_RELEASE_ASSERT(is()); + return *static_cast::Type*>(ptr()); } /** @@ -571,31 +663,35 @@ * safely-destructible state, as determined by the behavior of T's move * constructor when provided the variant's internal value. */ - template + template T extract() { - static_assert(detail::IsVariant::value, - "provided a type not found in this Variant's type list"); + static_assert( + detail::SelectVariantType::count == 1, + "provided a type not uniquely found in this Variant's type list"); MOZ_ASSERT(is()); return T(Move(as())); } + template + typename detail::Nth::Type extract() { + static_assert(N < sizeof...(Ts), + "provided an index outside of this Variant's type list"); + MOZ_RELEASE_ASSERT(is()); + return typename detail::Nth::Type(Move(as())); + } + // Exhaustive matching of all variant types on the contained value. /** Match on an immutable const reference. */ - template - auto - match(Matcher&& aMatcher) const - -> decltype(Impl::match(aMatcher, *this)) - { + template + auto match(Matcher&& aMatcher) const + -> decltype(Impl::match(aMatcher, *this)) { return Impl::match(aMatcher, *this); } /** Match on a mutable non-const reference. */ - template - auto - match(Matcher&& aMatcher) - -> decltype(Impl::match(aMatcher, *this)) - { + template + auto match(Matcher&& aMatcher) -> decltype(Impl::match(aMatcher, *this)) { return Impl::match(aMatcher, *this); } }; @@ -613,13 +709,11 @@ * 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) -{ +template +detail::AsVariantTemporary AsVariant(T&& aValue) { return detail::AsVariantTemporary(Forward(aValue)); } -} // namespace mozilla +} // 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 @@ -11,7 +11,7 @@ #include "mozilla/Alignment.h" #include "mozilla/AllocPolicy.h" -#include "mozilla/ArrayUtils.h" // for PointerRangeSize +#include "mozilla/ArrayUtils.h" // for PointerRangeSize #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/MathAlgorithms.h" @@ -22,17 +22,17 @@ #include "mozilla/TemplateLib.h" #include "mozilla/TypeTraits.h" -#include // for placement new +#include // for placement new /* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */ #ifdef _MSC_VER #pragma warning(push) -#pragma warning(disable:4345) +#pragma warning(disable : 4345) #endif namespace mozilla { -template +template class Vector; namespace detail { @@ -42,9 +42,8 @@ * allocated on the heap. This means that aCapacity*sizeof(T) is as close to a * power-of-two as possible. growStorageBy() is responsible for ensuring this. */ -template -static bool CapacityHasExcessSpace(size_t aCapacity) -{ +template +static bool CapacityHasExcessSpace(size_t aCapacity) { size_t size = aCapacity * sizeof(T); return RoundUpPow2(size) - size >= sizeof(T); } @@ -53,22 +52,19 @@ * This template class provides a default implementation for vector operations * when the element type is not known to be a POD, as judged by IsPod. */ -template -struct VectorImpl -{ +template +struct VectorImpl { /* * Constructs an object in the uninitialized memory at *aDst with aArgs. */ - template + template MOZ_NONNULL(1) - static inline void new_(T* aDst, Args&&... aArgs) - { - new(KnownNotNull, aDst) T(Forward(aArgs)...); + static inline void new_(T* aDst, Args&&... aArgs) { + new (KnownNotNull, aDst) T(Forward(aArgs)...); } /* Destroys constructed objects in the range [aBegin, aEnd). */ - static inline void destroy(T* aBegin, T* aEnd) - { + static inline void destroy(T* aBegin, T* aEnd) { MOZ_ASSERT(aBegin <= aEnd); for (T* p = aBegin; p < aEnd; ++p) { p->~T(); @@ -76,8 +72,7 @@ } /* Constructs objects in the uninitialized range [aBegin, aEnd). */ - static inline void initialize(T* aBegin, T* aEnd) - { + static inline void initialize(T* aBegin, T* aEnd) { MOZ_ASSERT(aBegin <= aEnd); for (T* p = aBegin; p < aEnd; ++p) { new_(p); @@ -88,12 +83,11 @@ * Copy-constructs objects in the uninitialized range * [aDst, aDst+(aSrcEnd-aSrcStart)) from the range [aSrcStart, aSrcEnd). */ - template - static inline void copyConstruct(T* aDst, - const U* aSrcStart, const U* aSrcEnd) - { + template + static inline void copyConstruct(T* aDst, const U* aSrcStart, + const U* aSrcEnd) { MOZ_ASSERT(aSrcStart <= aSrcEnd); - for (const U* p = aSrcStart; p < aSrcEnd; ++p, ++aDst) { + for (const U *p = aSrcStart; p < aSrcEnd; ++p, ++aDst) { new_(aDst, *p); } } @@ -102,11 +96,10 @@ * Move-constructs objects in the uninitialized range * [aDst, aDst+(aSrcEnd-aSrcStart)) from the range [aSrcStart, aSrcEnd). */ - template - static inline void moveConstruct(T* aDst, U* aSrcStart, U* aSrcEnd) - { + template + static inline void moveConstruct(T* aDst, U* aSrcStart, U* aSrcEnd) { MOZ_ASSERT(aSrcStart <= aSrcEnd); - for (U* p = aSrcStart; p < aSrcEnd; ++p, ++aDst) { + for (U *p = aSrcStart; p < aSrcEnd; ++p, ++aDst) { new_(aDst, Move(*p)); } } @@ -115,9 +108,8 @@ * Copy-constructs objects in the uninitialized range [aDst, aDst+aN) from * the same object aU. */ - template - static inline void copyConstructN(T* aDst, size_t aN, const U& aU) - { + template + static inline void copyConstructN(T* aDst, size_t aN, const U& aU) { for (T* end = aDst + aN; aDst < end; ++aDst) { new_(aDst, aU); } @@ -129,9 +121,7 @@ * aNewCap has not overflowed, and (2) multiplying aNewCap by sizeof(T) will * not overflow. */ - static inline MOZ_MUST_USE bool - growTo(Vector& aV, size_t aNewCap) - { + static inline MOZ_MUST_USE bool growTo(Vector& aV, size_t aNewCap) { MOZ_ASSERT(!aV.usingInlineStorage()); MOZ_ASSERT(!CapacityHasExcessSpace(aNewCap)); T* newbuf = aV.template pod_malloc(aNewCap); @@ -147,7 +137,7 @@ aV.free_(aV.mBegin); aV.mBegin = newbuf; /* aV.mLength is unchanged. */ - aV.mCapacity = aNewCap; + aV.mTail.mCapacity = aNewCap; return true; } }; @@ -157,13 +147,11 @@ * vector operations when the element type is known to be a POD, as judged by * IsPod. */ -template -struct VectorImpl -{ - template +template +struct VectorImpl { + template MOZ_NONNULL(1) - static inline void new_(T* aDst, Args&&... aArgs) - { + static inline void new_(T* aDst, Args&&... aArgs) { // 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 @@ -174,8 +162,7 @@ static inline void destroy(T*, T*) {} - static inline void initialize(T* aBegin, T* aEnd) - { + static inline void initialize(T* aBegin, T* aEnd) { /* * You would think that memset would be a big win (or even break even) * when we know T is a POD. But currently it's not. This is probably @@ -190,10 +177,9 @@ } } - template - static inline void copyConstruct(T* aDst, - const U* aSrcStart, const U* aSrcEnd) - { + template + static inline void copyConstruct(T* aDst, const U* aSrcStart, + const U* aSrcEnd) { /* * See above memset comment. Also, notice that copyConstruct is * currently templated (T != U), so memcpy won't work without @@ -202,52 +188,60 @@ * memcpy(aDst, aSrcStart, sizeof(T) * (aSrcEnd - aSrcStart)); */ MOZ_ASSERT(aSrcStart <= aSrcEnd); - for (const U* p = aSrcStart; p < aSrcEnd; ++p, ++aDst) { + for (const U *p = aSrcStart; p < aSrcEnd; ++p, ++aDst) { new_(aDst, *p); } } - template - static inline void moveConstruct(T* aDst, - const U* aSrcStart, const U* aSrcEnd) - { + template + static inline void moveConstruct(T* aDst, const U* aSrcStart, + const U* aSrcEnd) { copyConstruct(aDst, aSrcStart, aSrcEnd); } - static inline void copyConstructN(T* aDst, size_t aN, const T& aT) - { + static inline void copyConstructN(T* aDst, size_t aN, const T& aT) { for (T* end = aDst + aN; aDst < end; ++aDst) { new_(aDst, aT); } } - static inline MOZ_MUST_USE bool - growTo(Vector& aV, size_t aNewCap) - { + static inline MOZ_MUST_USE bool growTo(Vector& aV, size_t aNewCap) { MOZ_ASSERT(!aV.usingInlineStorage()); MOZ_ASSERT(!CapacityHasExcessSpace(aNewCap)); - T* newbuf = aV.template pod_realloc(aV.mBegin, aV.mCapacity, aNewCap); + T* newbuf = + aV.template pod_realloc(aV.mBegin, aV.mTail.mCapacity, aNewCap); if (MOZ_UNLIKELY(!newbuf)) { return false; } aV.mBegin = newbuf; /* aV.mLength is unchanged. */ - aV.mCapacity = aNewCap; + aV.mTail.mCapacity = aNewCap; return true; } - static inline void - podResizeToFit(Vector& aV) - { - if (aV.usingInlineStorage() || aV.mLength == aV.mCapacity) { + static inline void podResizeToFit(Vector& aV) { + if (aV.usingInlineStorage() || aV.mLength == aV.mTail.mCapacity) { + return; + } + if (!aV.mLength) { + aV.free_(aV.mBegin); + aV.mBegin = aV.inlineStorage(); + aV.mTail.mCapacity = aV.kInlineCapacity; +#ifdef DEBUG + aV.mTail.mReserved = 0; +#endif return; } - T* newbuf = aV.template pod_realloc(aV.mBegin, aV.mCapacity, aV.mLength); + T* newbuf = + aV.template pod_realloc(aV.mBegin, aV.mTail.mCapacity, aV.mLength); if (MOZ_UNLIKELY(!newbuf)) { return; } aV.mBegin = newbuf; - aV.mCapacity = aV.mLength; + aV.mTail.mCapacity = aV.mLength; +#ifdef DEBUG + aV.mTail.mReserved = aV.mLength; +#endif } }; @@ -255,7 +249,7 @@ // DO NOT DEFINE IN YOUR OWN CODE. struct VectorTesting; -} // namespace detail +} // namespace detail /* * STL-like container providing a short-lived, dynamic buffer. Vector calls the @@ -275,16 +269,16 @@ * Vector is not reentrant: T member functions called during Vector member * functions must not call back into the same object! */ -template -class Vector final : private AllocPolicy -{ +template +class MOZ_NON_PARAM Vector final : private AllocPolicy { /* utilities */ static const bool kElemIsPod = IsPod::value; - typedef detail::VectorImpl Impl; - friend struct detail::VectorImpl; + typedef detail::VectorImpl + Impl; + friend struct detail::VectorImpl; friend struct detail::VectorTesting; @@ -294,36 +288,39 @@ /* magic constants */ - static const int kMaxInlineBytes = 1024; - - /* compute constants */ + /** + * The maximum space allocated for inline element storage. + * + * We reduce space by what the AllocPolicy base class and prior Vector member + * fields likely consume to attempt to play well with binary size classes. + */ + static constexpr size_t kMaxInlineBytes = + 1024 - + (sizeof(AllocPolicy) + sizeof(T*) + sizeof(size_t) + sizeof(size_t)); - /* - * Consider element size to be 1 for buffer sizing if there are 0 inline - * elements. This allows us to compile when the definition of the element - * type is not visible here. + /** + * The number of T elements of inline capacity built into this Vector. This + * is usually |MinInlineCapacity|, but it may be less (or zero!) for large T. * - * Explicit specialization is only allowed at namespace scope, so in order - * to keep everything here, we use a dummy template parameter with partial - * specialization. - */ - template - struct ElemSize - { - static const size_t value = sizeof(T); - }; - template - struct ElemSize<0, Dummy> - { - static const size_t value = 1; + * We use a partially-specialized template (not explicit specialization, which + * is only allowed at namespace scope) to compute this value. The benefit is + * that |sizeof(T)| need not be computed, and |T| doesn't have to be fully + * defined at the time |Vector| appears, if no inline storage is requested. + */ + template + struct ComputeCapacity { + static constexpr size_t value = + tl::Min::value; }; - static const size_t kInlineCapacity = - tl::Min::value>::value; + template + struct ComputeCapacity<0, Dummy> { + static constexpr size_t value = 0; + }; - /* Calculate inline buffer size; avoid 0-sized array. */ - static const size_t kInlineBytes = - tl::Max<1, kInlineCapacity * ElemSize::value>::value; + /** The actual inline capacity in number of elements T. This may be zero! */ + static constexpr size_t kInlineCapacity = + ComputeCapacity::value; /* member data */ @@ -339,16 +336,81 @@ /* Number of elements in the vector. */ size_t mLength; - /* Max number of elements storable in the vector without resizing. */ - size_t mCapacity; + /* + * Memory used to store capacity, reserved element count (debug builds only), + * and inline storage. The simple "answer" is: + * + * size_t mCapacity; + * #ifdef DEBUG + * size_t mReserved; + * #endif + * alignas(T) unsigned char mBytes[kInlineCapacity * sizeof(T)]; + * + * but there are complications. First, C++ forbids zero-sized arrays that + * might result. Second, we don't want zero capacity to affect Vector's size + * (even empty classes take up a byte, unless they're base classes). + * + * Yet again, we eliminate the zero-sized array using partial specialization. + * And we eliminate potential size hit by putting capacity/reserved in one + * struct, then putting the array (if any) in a derived struct. If no array + * is needed, the derived struct won't consume extra space. + */ + struct CapacityAndReserved { + explicit CapacityAndReserved(size_t aCapacity, size_t aReserved) + : mCapacity(aCapacity) +#ifdef DEBUG + , + mReserved(aReserved) +#endif + { + } + CapacityAndReserved() = default; + + /* Max number of elements storable in the vector without resizing. */ + size_t mCapacity; #ifdef DEBUG - /* Max elements of reserved or used space in this vector. */ - size_t mReserved; + /* Max elements of reserved or used space in this vector. */ + size_t mReserved; #endif + }; - /* Memory used for inline storage. */ - AlignedStorage mStorage; +// Silence warnings about this struct possibly being padded dued to the +// alignas() in it -- there's nothing we can do to avoid it. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4324) +#endif // _MSC_VER + + template + struct CRAndStorage : CapacityAndReserved { + explicit CRAndStorage(size_t aCapacity, size_t aReserved) + : CapacityAndReserved(aCapacity, aReserved) {} + CRAndStorage() = default; + + alignas(T) unsigned char mBytes[Capacity * sizeof(T)]; + + // GCC fails due to -Werror=strict-aliasing if |mBytes| is directly cast to + // T*. Indirecting through this function addresses the problem. + void* data() { return mBytes; } + + T* storage() { return static_cast(data()); } + }; + + template + struct CRAndStorage<0, Dummy> : CapacityAndReserved { + explicit CRAndStorage(size_t aCapacity, size_t aReserved) + : CapacityAndReserved(aCapacity, aReserved) {} + CRAndStorage() = default; + + T* storage() { return nullptr; } + }; + + CRAndStorage mTail; + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER #ifdef DEBUG friend class ReentrancyGuard; @@ -357,30 +419,17 @@ /* private accessors */ - bool usingInlineStorage() const - { + bool usingInlineStorage() const { return mBegin == const_cast(this)->inlineStorage(); } - T* inlineStorage() - { - return static_cast(mStorage.addr()); - } + T* inlineStorage() { return mTail.storage(); } - T* beginNoCheck() const - { - return mBegin; - } + T* beginNoCheck() const { return mBegin; } - T* endNoCheck() - { - return mBegin + mLength; - } + T* endNoCheck() { return mBegin + mLength; } - const T* endNoCheck() const - { - return mBegin + mLength; - } + const T* endNoCheck() const { return mBegin + mLength; } #ifdef DEBUG /** @@ -390,28 +439,29 @@ * are implicitly reserved. This value is always less than or equal to * |capacity()|. It may be explicitly increased using the |reserve()| method. */ - size_t reserved() const - { - MOZ_ASSERT(mLength <= mReserved); - MOZ_ASSERT(mReserved <= mCapacity); - return mReserved; + size_t reserved() const { + MOZ_ASSERT(mLength <= mTail.mReserved); + MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity); + return mTail.mReserved; } #endif /* Append operations guaranteed to succeed due to pre-reserved space. */ - template void internalAppend(U&& aU); - template + template + void internalAppend(U&& aU); + template void internalAppendAll(const Vector& aU); void internalAppendN(const T& aT, size_t aN); - template void internalAppend(const U* aBegin, size_t aLength); + template + void internalAppend(const U* aBegin, size_t aLength); -public: + public: static const size_t sMaxInlineStorage = MinInlineCapacity; typedef T ElementType; explicit Vector(AllocPolicy = AllocPolicy()); - Vector(Vector&&); /* Move constructor. */ + Vector(Vector&&); /* Move constructor. */ Vector& operator=(Vector&&); /* Move assignment. */ ~Vector(); @@ -427,98 +477,100 @@ bool empty() const { return mLength == 0; } - size_t capacity() const { return mCapacity; } + size_t capacity() const { return mTail.mCapacity; } - T* begin() - { + T* begin() { MOZ_ASSERT(!mEntered); return mBegin; } - const T* begin() const - { + const T* begin() const { MOZ_ASSERT(!mEntered); return mBegin; } - T* end() - { + T* end() { MOZ_ASSERT(!mEntered); return mBegin + mLength; } - const T* end() const - { + const T* end() const { MOZ_ASSERT(!mEntered); return mBegin + mLength; } - T& operator[](size_t aIndex) - { + T& operator[](size_t aIndex) { MOZ_ASSERT(!mEntered); MOZ_ASSERT(aIndex < mLength); return begin()[aIndex]; } - const T& operator[](size_t aIndex) const - { + const T& operator[](size_t aIndex) const { MOZ_ASSERT(!mEntered); MOZ_ASSERT(aIndex < mLength); return begin()[aIndex]; } - T& back() - { + T& back() { MOZ_ASSERT(!mEntered); MOZ_ASSERT(!empty()); return *(end() - 1); } - const T& back() const - { + const T& back() const { MOZ_ASSERT(!mEntered); MOZ_ASSERT(!empty()); return *(end() - 1); } - class Range - { + class Range { friend class Vector; T* mCur; T* mEnd; - Range(T* aCur, T* aEnd) - : mCur(aCur) - , mEnd(aEnd) - { + Range(T* aCur, T* aEnd) : mCur(aCur), mEnd(aEnd) { MOZ_ASSERT(aCur <= aEnd); } - public: + public: bool empty() const { return mCur == mEnd; } size_t remain() const { return PointerRangeSize(mCur, mEnd); } - T& front() const { MOZ_ASSERT(!empty()); return *mCur; } - void popFront() { MOZ_ASSERT(!empty()); ++mCur; } - T popCopyFront() { MOZ_ASSERT(!empty()); return *mCur++; } + T& front() const { + MOZ_ASSERT(!empty()); + return *mCur; + } + void popFront() { + MOZ_ASSERT(!empty()); + ++mCur; + } + T popCopyFront() { + MOZ_ASSERT(!empty()); + return *mCur++; + } }; - class ConstRange - { + class ConstRange { friend class Vector; const T* mCur; const T* mEnd; - ConstRange(const T* aCur, const T* aEnd) - : mCur(aCur) - , mEnd(aEnd) - { + ConstRange(const T* aCur, const T* aEnd) : mCur(aCur), mEnd(aEnd) { MOZ_ASSERT(aCur <= aEnd); } - public: + public: bool empty() const { return mCur == mEnd; } size_t remain() const { return PointerRangeSize(mCur, mEnd); } - const T& front() const { MOZ_ASSERT(!empty()); return *mCur; } - void popFront() { MOZ_ASSERT(!empty()); ++mCur; } - T popCopyFront() { MOZ_ASSERT(!empty()); return *mCur++; } + const T& front() const { + MOZ_ASSERT(!empty()); + return *mCur; + } + void popFront() { + MOZ_ASSERT(!empty()); + ++mCur; + } + T popCopyFront() { + MOZ_ASSERT(!empty()); + return *mCur++; + } }; Range all() { return Range(begin(), end()); } @@ -610,50 +662,47 @@ * vector, instead of copying it. If it fails, |aU| is left unmoved. ("We are * not amused.") */ - template MOZ_MUST_USE 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 - MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) - { - if (!growByUninitialized(1)) - return false; + template + MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) { + if (!growByUninitialized(1)) return false; Impl::new_(&back(), Forward(aArgs)...); return true; } - template + template 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); + 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 * memory has been pre-reserved. Don't use this if you haven't reserved the * memory! */ - template void infallibleAppend(U&& aU) - { + template + void infallibleAppend(U&& aU) { internalAppend(Forward(aU)); } - void infallibleAppendN(const T& aT, size_t aN) - { - internalAppendN(aT, aN); - } - template void infallibleAppend(const U* aBegin, const U* aEnd) - { + void infallibleAppendN(const T& aT, size_t aN) { internalAppendN(aT, aN); } + template + void infallibleAppend(const U* aBegin, const U* aEnd) { internalAppend(aBegin, PointerRangeSize(aBegin, aEnd)); } - template void infallibleAppend(const U* aBegin, size_t aLength) - { + template + void infallibleAppend(const U* aBegin, size_t aLength) { internalAppend(aBegin, aLength); } - template - void infallibleEmplaceBack(Args&&... aArgs) - { + template + void infallibleEmplaceBack(Args&&... aArgs) { infallibleGrowByUninitialized(1); Impl::new_(&back(), Forward(aArgs)...); } @@ -698,6 +747,17 @@ * AllocPolicy. * * N.B. This call assumes that there are no uninitialized elements in the + * passed range [aP, aP + aLength). The range [aP + aLength, aP + + * aCapacity) must be allocated uninitialized memory. + */ + void replaceRawBuffer(T* aP, size_t aLength, size_t aCapacity); + + /** + * Transfer ownership of an array of objects into the vector. The caller + * must have allocated the array in accordance with this vector's + * AllocPolicy. + * + * N.B. This call assumes that there are no uninitialized elements in the * passed array. */ void replaceRawBuffer(T* aP, size_t aLength); @@ -717,7 +777,7 @@ * * This is inherently a linear-time operation. Be careful! */ - template + template MOZ_MUST_USE T* insert(T* aP, U&& aVal); /** @@ -746,53 +806,52 @@ void swap(Vector& aOther); -private: + private: Vector(const Vector&) = delete; void operator=(const Vector&) = delete; }; /* This does the re-entrancy check plus several other sanity checks. */ -#define MOZ_REENTRANCY_GUARD_ET_AL \ - ReentrancyGuard g(*this); \ - MOZ_ASSERT_IF(usingInlineStorage(), mCapacity == kInlineCapacity); \ - MOZ_ASSERT(reserved() <= mCapacity); \ - MOZ_ASSERT(mLength <= reserved()); \ - MOZ_ASSERT(mLength <= mCapacity) +#define MOZ_REENTRANCY_GUARD_ET_AL \ + ReentrancyGuard g(*this); \ + MOZ_ASSERT_IF(usingInlineStorage(), mTail.mCapacity == kInlineCapacity); \ + MOZ_ASSERT(reserved() <= mTail.mCapacity); \ + MOZ_ASSERT(mLength <= reserved()); \ + MOZ_ASSERT(mLength <= mTail.mCapacity) /* Vector Implementation */ -template -MOZ_ALWAYS_INLINE -Vector::Vector(AP aAP) - : AP(aAP) - , mLength(0) - , mCapacity(kInlineCapacity) +template +MOZ_ALWAYS_INLINE Vector::Vector(AP aAP) + : AP(aAP), + mLength(0), + mTail(kInlineCapacity, 0) #ifdef DEBUG - , mReserved(0) - , mEntered(false) + , + mEntered(false) #endif { - mBegin = static_cast(mStorage.addr()); + mBegin = inlineStorage(); } /* Move constructor. */ -template -MOZ_ALWAYS_INLINE -Vector::Vector(Vector&& aRhs) - : AllocPolicy(Move(aRhs)) +template +MOZ_ALWAYS_INLINE Vector::Vector(Vector&& aRhs) + : AllocPolicy(Move(aRhs)) #ifdef DEBUG - , mEntered(false) + , + mEntered(false) #endif { mLength = aRhs.mLength; - mCapacity = aRhs.mCapacity; + mTail.mCapacity = aRhs.mTail.mCapacity; #ifdef DEBUG - mReserved = aRhs.mReserved; + mTail.mReserved = aRhs.mTail.mReserved; #endif if (aRhs.usingInlineStorage()) { /* We can't move the buffer over in this case, so copy elements. */ - mBegin = static_cast(mStorage.addr()); + mBegin = inlineStorage(); Impl::moveConstruct(mBegin, aRhs.beginNoCheck(), aRhs.endNoCheck()); /* * Leave aRhs's mLength, mBegin, mCapacity, and mReserved as they are. @@ -804,30 +863,26 @@ * in-line storage. */ mBegin = aRhs.mBegin; - aRhs.mBegin = static_cast(aRhs.mStorage.addr()); - aRhs.mCapacity = kInlineCapacity; + aRhs.mBegin = aRhs.inlineStorage(); + aRhs.mTail.mCapacity = kInlineCapacity; aRhs.mLength = 0; #ifdef DEBUG - aRhs.mReserved = 0; + aRhs.mTail.mReserved = 0; #endif } } /* Move assignment. */ -template -MOZ_ALWAYS_INLINE Vector& -Vector::operator=(Vector&& aRhs) -{ +template +MOZ_ALWAYS_INLINE Vector& Vector::operator=(Vector&& aRhs) { MOZ_ASSERT(this != &aRhs, "self-move assignment is prohibited"); this->~Vector(); - new(KnownNotNull, this) Vector(Move(aRhs)); + new (KnownNotNull, this) Vector(Move(aRhs)); return *this; } -template -MOZ_ALWAYS_INLINE -Vector::~Vector() -{ +template +MOZ_ALWAYS_INLINE Vector::~Vector() { MOZ_REENTRANCY_GUARD_ET_AL; Impl::destroy(beginNoCheck(), endNoCheck()); if (!usingInlineStorage()) { @@ -835,9 +890,8 @@ } } -template -MOZ_ALWAYS_INLINE void -Vector::reverse() { +template +MOZ_ALWAYS_INLINE void Vector::reverse() { MOZ_REENTRANCY_GUARD_ET_AL; T* elems = mBegin; size_t len = mLength; @@ -852,10 +906,8 @@ * move all elements in the inline buffer to this new buffer, * and fail on OOM. */ -template -inline bool -Vector::convertToHeapStorage(size_t aNewCap) -{ +template +inline bool Vector::convertToHeapStorage(size_t aNewCap) { MOZ_ASSERT(usingInlineStorage()); /* Allocate buffer. */ @@ -872,15 +924,13 @@ /* Switch in heap buffer. */ mBegin = newBuf; /* mLength is unchanged. */ - mCapacity = aNewCap; + mTail.mCapacity = aNewCap; return true; } -template -MOZ_NEVER_INLINE bool -Vector::growStorageBy(size_t aIncr) -{ - MOZ_ASSERT(mLength + aIncr > mCapacity); +template +MOZ_NEVER_INLINE bool Vector::growStorageBy(size_t aIncr) { + MOZ_ASSERT(mLength + aIncr > mTail.mCapacity); /* * When choosing a new capacity, its size should is as close to 2**N bytes @@ -896,7 +946,7 @@ if (usingInlineStorage()) { /* This case occurs in ~70--80% of the calls to this function. */ size_t newSize = - tl::RoundUpPow2<(kInlineCapacity + 1) * sizeof(T)>::value; + tl::RoundUpPow2<(kInlineCapacity + 1) * sizeof(T)>::value; newCap = newSize / sizeof(T); goto convert; } @@ -938,8 +988,7 @@ /* Did mLength + aIncr overflow? Will newCap * sizeof(T) overflow? */ if (MOZ_UNLIKELY(newMinCap < mLength || - newMinCap & tl::MulOverflowMask<2 * sizeof(T)>::value)) - { + newMinCap & tl::MulOverflowMask<2 * sizeof(T)>::value)) { this->reportAllocOverflow(); return false; } @@ -950,7 +999,7 @@ } if (usingInlineStorage()) { -convert: + convert: return convertToHeapStorage(newCap); } @@ -958,10 +1007,8 @@ return Impl::growTo(*this, newCap); } -template -inline bool -Vector::initCapacity(size_t aRequest) -{ +template +inline bool Vector::initCapacity(size_t aRequest) { MOZ_ASSERT(empty()); MOZ_ASSERT(usingInlineStorage()); if (aRequest == 0) { @@ -972,17 +1019,15 @@ return false; } mBegin = newbuf; - mCapacity = aRequest; + mTail.mCapacity = aRequest; #ifdef DEBUG - mReserved = aRequest; + mTail.mReserved = aRequest; #endif return true; } -template -inline bool -Vector::initLengthUninitialized(size_t aRequest) -{ +template +inline bool Vector::initLengthUninitialized(size_t aRequest) { if (!initCapacity(aRequest)) { return false; } @@ -990,16 +1035,14 @@ return true; } -template -inline bool -Vector::maybeCheckSimulatedOOM(size_t aRequestedSize) -{ +template +inline bool Vector::maybeCheckSimulatedOOM(size_t aRequestedSize) { if (aRequestedSize <= N) { return true; } #ifdef DEBUG - if (aRequestedSize <= mReserved) { + if (aRequestedSize <= mTail.mReserved) { return true; } #endif @@ -1007,12 +1050,10 @@ return allocPolicy().checkSimulatedOOM(); } -template -inline bool -Vector::reserve(size_t aRequest) -{ +template +inline bool Vector::reserve(size_t aRequest) { MOZ_REENTRANCY_GUARD_ET_AL; - if (aRequest > mCapacity) { + if (aRequest > mTail.mCapacity) { if (MOZ_UNLIKELY(!growStorageBy(aRequest - mLength))) { return false; } @@ -1020,63 +1061,55 @@ return false; } #ifdef DEBUG - if (aRequest > mReserved) { - mReserved = aRequest; + if (aRequest > mTail.mReserved) { + mTail.mReserved = aRequest; } - MOZ_ASSERT(mLength <= mReserved); - MOZ_ASSERT(mReserved <= mCapacity); + MOZ_ASSERT(mLength <= mTail.mReserved); + MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity); #endif return true; } -template -inline void -Vector::shrinkBy(size_t aIncr) -{ +template +inline void Vector::shrinkBy(size_t aIncr) { MOZ_REENTRANCY_GUARD_ET_AL; MOZ_ASSERT(aIncr <= mLength); Impl::destroy(endNoCheck() - aIncr, endNoCheck()); mLength -= aIncr; } -template -MOZ_ALWAYS_INLINE void -Vector::shrinkTo(size_t aNewLength) -{ +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) -{ +template +MOZ_ALWAYS_INLINE bool Vector::growBy(size_t aIncr) { MOZ_REENTRANCY_GUARD_ET_AL; - if (aIncr > mCapacity - mLength) { + if (aIncr > mTail.mCapacity - mLength) { if (MOZ_UNLIKELY(!growStorageBy(aIncr))) { return false; } } else if (!maybeCheckSimulatedOOM(mLength + aIncr)) { return false; } - MOZ_ASSERT(mLength + aIncr <= mCapacity); + MOZ_ASSERT(mLength + aIncr <= mTail.mCapacity); T* newend = endNoCheck() + aIncr; Impl::initialize(endNoCheck(), newend); mLength += aIncr; #ifdef DEBUG - if (mLength > mReserved) { - mReserved = mLength; + if (mLength > mTail.mReserved) { + mTail.mReserved = mLength; } #endif return true; } -template -MOZ_ALWAYS_INLINE bool -Vector::growByUninitialized(size_t aIncr) -{ +template +MOZ_ALWAYS_INLINE bool Vector::growByUninitialized(size_t aIncr) { MOZ_REENTRANCY_GUARD_ET_AL; - if (aIncr > mCapacity - mLength) { + if (aIncr > mTail.mCapacity - mLength) { if (MOZ_UNLIKELY(!growStorageBy(aIncr))) { return false; } @@ -1084,26 +1117,23 @@ return false; } #ifdef DEBUG - if (mLength + aIncr > mReserved) { - mReserved = mLength + aIncr; + if (mLength + aIncr > mTail.mReserved) { + mTail.mReserved = mLength + aIncr; } #endif infallibleGrowByUninitialized(aIncr); return true; } -template -MOZ_ALWAYS_INLINE void -Vector::infallibleGrowByUninitialized(size_t aIncr) -{ +template +MOZ_ALWAYS_INLINE void Vector::infallibleGrowByUninitialized( + size_t aIncr) { MOZ_ASSERT(mLength + aIncr <= reserved()); mLength += aIncr; } -template -inline bool -Vector::resize(size_t aNewLength) -{ +template +inline bool Vector::resize(size_t aNewLength) { size_t curLength = mLength; if (aNewLength > curLength) { return growBy(aNewLength - curLength); @@ -1112,10 +1142,9 @@ return true; } -template -MOZ_ALWAYS_INLINE bool -Vector::resizeUninitialized(size_t aNewLength) -{ +template +MOZ_ALWAYS_INLINE bool Vector::resizeUninitialized( + size_t aNewLength) { size_t curLength = mLength; if (aNewLength > curLength) { return growByUninitialized(aNewLength - curLength); @@ -1124,73 +1153,60 @@ return true; } -template -inline void -Vector::clear() -{ +template +inline void Vector::clear() { MOZ_REENTRANCY_GUARD_ET_AL; Impl::destroy(beginNoCheck(), endNoCheck()); mLength = 0; } -template -inline void -Vector::clearAndFree() -{ +template +inline void Vector::clearAndFree() { clear(); if (usingInlineStorage()) { return; } this->free_(beginNoCheck()); - mBegin = static_cast(mStorage.addr()); - mCapacity = kInlineCapacity; + mBegin = inlineStorage(); + mTail.mCapacity = kInlineCapacity; #ifdef DEBUG - mReserved = 0; + mTail.mReserved = 0; #endif } -template -inline void -Vector::podResizeToFit() -{ +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 -{ - return mLength + aNeeded <= mCapacity; +template +inline bool Vector::canAppendWithoutRealloc(size_t aNeeded) const { + return mLength + aNeeded <= mTail.mCapacity; } -template -template -MOZ_ALWAYS_INLINE void -Vector::internalAppendAll(const Vector& aOther) -{ +template +template +MOZ_ALWAYS_INLINE void Vector::internalAppendAll( + const Vector& aOther) { internalAppend(aOther.begin(), aOther.length()); } -template -template -MOZ_ALWAYS_INLINE void -Vector::internalAppend(U&& aU) -{ - MOZ_ASSERT(mLength + 1 <= mReserved); - MOZ_ASSERT(mReserved <= mCapacity); +template +template +MOZ_ALWAYS_INLINE void Vector::internalAppend(U&& aU) { + MOZ_ASSERT(mLength + 1 <= mTail.mReserved); + MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity); Impl::new_(endNoCheck(), Forward(aU)); ++mLength; } -template -MOZ_ALWAYS_INLINE bool -Vector::appendN(const T& aT, size_t aNeeded) -{ +template +MOZ_ALWAYS_INLINE bool Vector::appendN(const T& aT, size_t aNeeded) { MOZ_REENTRANCY_GUARD_ET_AL; - if (mLength + aNeeded > mCapacity) { + if (mLength + aNeeded > mTail.mCapacity) { if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) { return false; } @@ -1198,29 +1214,26 @@ return false; } #ifdef DEBUG - if (mLength + aNeeded > mReserved) { - mReserved = mLength + aNeeded; + if (mLength + aNeeded > mTail.mReserved) { + mTail.mReserved = mLength + aNeeded; } #endif internalAppendN(aT, aNeeded); return true; } -template -MOZ_ALWAYS_INLINE void -Vector::internalAppendN(const T& aT, size_t aNeeded) -{ - MOZ_ASSERT(mLength + aNeeded <= mReserved); - MOZ_ASSERT(mReserved <= mCapacity); +template +MOZ_ALWAYS_INLINE void Vector::internalAppendN(const T& aT, + size_t aNeeded) { + MOZ_ASSERT(mLength + aNeeded <= mTail.mReserved); + MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity); Impl::copyConstructN(endNoCheck(), aNeeded, aT); mLength += aNeeded; } -template -template -inline T* -Vector::insert(T* aP, U&& aVal) -{ +template +template +inline T* Vector::insert(T* aP, U&& aVal) { MOZ_ASSERT(begin() <= aP); MOZ_ASSERT(aP <= end()); size_t pos = aP - begin(); @@ -1232,10 +1245,10 @@ } } else { T oldBack = Move(back()); - if (!append(Move(oldBack))) { /* Dup the last element. */ + if (!append(Move(oldBack))) { return nullptr; } - for (size_t i = oldLength; i > pos; --i) { + for (size_t i = oldLength - 1; i > pos; --i) { (*this)[i] = Move((*this)[i - 1]); } (*this)[pos] = Forward(aVal); @@ -1243,10 +1256,8 @@ return begin() + pos; } -template -inline void -Vector::erase(T* aIt) -{ +template +inline void Vector::erase(T* aIt) { MOZ_ASSERT(begin() <= aIt); MOZ_ASSERT(aIt < end()); while (aIt + 1 < end()) { @@ -1256,10 +1267,8 @@ popBack(); } -template -inline void -Vector::erase(T* aBegin, T* aEnd) -{ +template +inline void Vector::erase(T* aBegin, T* aEnd) { MOZ_ASSERT(begin() <= aBegin); MOZ_ASSERT(aBegin <= aEnd); MOZ_ASSERT(aEnd <= end()); @@ -1269,101 +1278,89 @@ shrinkBy(aEnd - aBegin); } -template -template -MOZ_ALWAYS_INLINE bool -Vector::append(const U* aInsBegin, const U* aInsEnd) -{ +template +template +MOZ_ALWAYS_INLINE bool Vector::append(const U* aInsBegin, + const U* aInsEnd) { MOZ_REENTRANCY_GUARD_ET_AL; size_t aNeeded = PointerRangeSize(aInsBegin, aInsEnd); - if (mLength + aNeeded > mCapacity) { + if (mLength + aNeeded > mTail.mCapacity) { if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) { return false; } } else if (!maybeCheckSimulatedOOM(mLength + aNeeded)) { - return false; + return false; } #ifdef DEBUG - if (mLength + aNeeded > mReserved) { - mReserved = mLength + aNeeded; + if (mLength + aNeeded > mTail.mReserved) { + mTail.mReserved = mLength + aNeeded; } #endif internalAppend(aInsBegin, aNeeded); return true; } -template -template -MOZ_ALWAYS_INLINE void -Vector::internalAppend(const U* aInsBegin, size_t aInsLength) -{ - MOZ_ASSERT(mLength + aInsLength <= mReserved); - MOZ_ASSERT(mReserved <= mCapacity); +template +template +MOZ_ALWAYS_INLINE void Vector::internalAppend(const U* aInsBegin, + size_t aInsLength) { + MOZ_ASSERT(mLength + aInsLength <= mTail.mReserved); + MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity); Impl::copyConstruct(endNoCheck(), aInsBegin, aInsBegin + aInsLength); mLength += aInsLength; } -template -template -MOZ_ALWAYS_INLINE bool -Vector::append(U&& aU) -{ +template +template +MOZ_ALWAYS_INLINE bool Vector::append(U&& aU) { MOZ_REENTRANCY_GUARD_ET_AL; - if (mLength == mCapacity) { + if (mLength == mTail.mCapacity) { if (MOZ_UNLIKELY(!growStorageBy(1))) { return false; } } else if (!maybeCheckSimulatedOOM(mLength + 1)) { - return false; + return false; } #ifdef DEBUG - if (mLength + 1 > mReserved) { - mReserved = mLength + 1; + if (mLength + 1 > mTail.mReserved) { + mTail.mReserved = mLength + 1; } #endif internalAppend(Forward(aU)); return true; } -template -template -MOZ_ALWAYS_INLINE bool -Vector::appendAll(const Vector& aOther) -{ +template +template +MOZ_ALWAYS_INLINE bool Vector::appendAll( + const Vector& aOther) { return append(aOther.begin(), aOther.length()); } -template -template -MOZ_ALWAYS_INLINE bool -Vector::append(const U* aInsBegin, size_t aInsLength) -{ +template +template +MOZ_ALWAYS_INLINE bool Vector::append(const U* aInsBegin, + size_t aInsLength) { return append(aInsBegin, aInsBegin + aInsLength); } -template -MOZ_ALWAYS_INLINE void -Vector::popBack() -{ +template +MOZ_ALWAYS_INLINE void Vector::popBack() { MOZ_REENTRANCY_GUARD_ET_AL; MOZ_ASSERT(!empty()); --mLength; endNoCheck()->~T(); } -template -MOZ_ALWAYS_INLINE T -Vector::popCopy() -{ +template +MOZ_ALWAYS_INLINE T Vector::popCopy() { T ret = back(); popBack(); return ret; } -template -inline T* -Vector::extractRawBuffer() -{ +template +inline T* Vector::extractRawBuffer() { MOZ_REENTRANCY_GUARD_ET_AL; if (usingInlineStorage()) { @@ -1371,19 +1368,17 @@ } T* ret = mBegin; - mBegin = static_cast(mStorage.addr()); + mBegin = inlineStorage(); mLength = 0; - mCapacity = kInlineCapacity; + mTail.mCapacity = kInlineCapacity; #ifdef DEBUG - mReserved = 0; + mTail.mReserved = 0; #endif return ret; } -template -inline T* -Vector::extractOrCopyRawBuffer() -{ +template +inline T* Vector::extractOrCopyRawBuffer() { if (T* ret = extractRawBuffer()) { return ret; } @@ -1397,19 +1392,18 @@ Impl::moveConstruct(copy, beginNoCheck(), endNoCheck()); Impl::destroy(beginNoCheck(), endNoCheck()); - mBegin = static_cast(mStorage.addr()); + mBegin = inlineStorage(); mLength = 0; - mCapacity = kInlineCapacity; + mTail.mCapacity = kInlineCapacity; #ifdef DEBUG - mReserved = 0; + mTail.mReserved = 0; #endif return copy; } -template -inline void -Vector::replaceRawBuffer(T* aP, size_t aLength) -{ +template +inline void Vector::replaceRawBuffer(T* aP, size_t aLength, + size_t aCapacity) { MOZ_REENTRANCY_GUARD_ET_AL; /* Destroy what we have. */ @@ -1419,48 +1413,48 @@ } /* Take in the new buffer. */ - if (aLength <= kInlineCapacity) { + if (aCapacity <= kInlineCapacity) { /* * We convert to inline storage if possible, even though aP might * otherwise be acceptable. Maybe this behaviour should be * specifiable with an argument to this function. */ - mBegin = static_cast(mStorage.addr()); + mBegin = inlineStorage(); mLength = aLength; - mCapacity = kInlineCapacity; + mTail.mCapacity = kInlineCapacity; Impl::moveConstruct(mBegin, aP, aP + aLength); Impl::destroy(aP, aP + aLength); this->free_(aP); } else { mBegin = aP; mLength = aLength; - mCapacity = aLength; + mTail.mCapacity = aCapacity; } #ifdef DEBUG - mReserved = aLength; + mTail.mReserved = aCapacity; #endif } -template -inline size_t -Vector::sizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const -{ +template +inline void Vector::replaceRawBuffer(T* aP, size_t aLength) { + replaceRawBuffer(aP, aLength, aLength); +} + +template +inline size_t Vector::sizeOfExcludingThis( + MallocSizeOf aMallocSizeOf) const { return usingInlineStorage() ? 0 : aMallocSizeOf(beginNoCheck()); } -template -inline size_t -Vector::sizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const -{ +template +inline size_t Vector::sizeOfIncludingThis( + MallocSizeOf aMallocSizeOf) const { return aMallocSizeOf(this) + sizeOfExcludingThis(aMallocSizeOf); } -template -inline void -Vector::swap(Vector& aOther) -{ - static_assert(N == 0, - "still need to implement this for N != 0"); +template +inline void Vector::swap(Vector& aOther) { + static_assert(N == 0, "still need to implement this for N != 0"); // This only works when inline storage is always empty. if (!usingInlineStorage() && aOther.usingInlineStorage()) { @@ -1476,13 +1470,13 @@ } Swap(mLength, aOther.mLength); - Swap(mCapacity, aOther.mCapacity); + Swap(mTail.mCapacity, aOther.mTail.mCapacity); #ifdef DEBUG - Swap(mReserved, aOther.mReserved); + Swap(mTail.mReserved, aOther.mTail.mReserved); #endif } -} // namespace mozilla +} // namespace mozilla #ifdef _MSC_VER #pragma warning(pop) 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 @@ -70,12 +70,21 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" +#include "mozilla/Maybe.h" #include "mozilla/RefCounted.h" #include "mozilla/RefPtr.h" #include "mozilla/TypeTraits.h" #include +#if defined(MOZILLA_INTERNAL_API) +// For thread safety checking. +#include "nsISupportsImpl.h" +#endif + +#if defined(MOZILLA_INTERNAL_API) && \ + defined(MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED) + // 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 @@ -89,31 +98,24 @@ // 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))) +// We re-use XPCOM's nsAutoOwningThread checks when they are available. This has +// the advantage that it works with cooperative thread pools. -#include #define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK \ - std::thread::id _owningThread; \ - bool _empty; // If it was initialized as a placeholder with mPtr = nullptr. + /* Will be none if mPtr = nullptr. */ \ + Maybe _owningThread; #define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \ - do { \ - _owningThread = std::this_thread::get_id(); \ - _empty = !p; \ + do { \ + if (p) { \ + _owningThread.emplace(); \ + } \ + } while (false) +#define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \ + do { \ + if (_owningThread.isSome() && !_owningThread.ref().IsCurrentThread()) { \ + WeakPtrTraits::AssertSafeToAccessFromNonOwningThread(); \ + } \ } 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(); @@ -122,16 +124,24 @@ #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) +#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; -template class SupportsWeakPtr; +template +class WeakPtr; +template +class SupportsWeakPtr; #ifdef MOZ_REFCOUNTED_LEAK_CHECKING #define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T) \ @@ -140,16 +150,21 @@ #define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T) #endif +template +struct WeakPtrTraits { + static void AssertSafeToAccessFromNonOwningThread() { + MOZ_DIAGNOSTIC_ASSERT(false, "WeakPtr accessed from multiple threads"); + } +}; + namespace detail { // This can live beyond the lifetime of the class derived from // SupportsWeakPtr. -template -class WeakReference : public ::mozilla::RefCounted > -{ -public: - explicit WeakReference(T* p) : mPtr(p) - { +template +class WeakReference : public ::mozilla::RefCounted > { + public: + explicit WeakReference(T* p) : mPtr(p) { MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK(); } @@ -159,8 +174,7 @@ } #ifdef MOZ_REFCOUNTED_LEAK_CHECKING - const char* typeName() const - { + const char* typeName() const { // The first time this is called mPtr is null, so don't // invoke any methods on mPtr. return T::weakReferenceTypeName(); @@ -172,7 +186,7 @@ void AssertThreadSafety() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); } #endif -private: + private: friend class mozilla::SupportsWeakPtr; void detach() { @@ -184,14 +198,12 @@ MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK }; -} // namespace detail +} // namespace detail template -class SupportsWeakPtr -{ -protected: - ~SupportsWeakPtr() - { +class SupportsWeakPtr { + protected: + ~SupportsWeakPtr() { static_assert(IsBaseOf, T>::value, "T must derive from SupportsWeakPtr"); if (mSelfReferencingWeakPtr) { @@ -199,20 +211,20 @@ } } -private: - const WeakPtr& SelfReferencingWeakPtr() - { + private: + const WeakPtr& SelfReferencingWeakPtr() { if (!mSelfReferencingWeakPtr) { - mSelfReferencingWeakPtr.mRef = new detail::WeakReference(static_cast(this)); + mSelfReferencingWeakPtr.mRef = + new detail::WeakReference(static_cast(this)); } else { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mSelfReferencingWeakPtr.mRef); } return mSelfReferencingWeakPtr; } - const WeakPtr& SelfReferencingWeakPtr() const - { - const WeakPtr& p = const_cast(this)->SelfReferencingWeakPtr(); + const WeakPtr& SelfReferencingWeakPtr() const { + const WeakPtr& p = + const_cast(this)->SelfReferencingWeakPtr(); return reinterpret_cast&>(p); } @@ -223,26 +235,22 @@ }; template -class WeakPtr -{ +class WeakPtr { typedef detail::WeakReference WeakReference; -public: - WeakPtr& operator=(const WeakPtr& aOther) - { + public: + WeakPtr& operator=(const WeakPtr& aOther) { mRef = aOther.mRef; MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef); return *this; } - WeakPtr(const WeakPtr& aOther) - { + WeakPtr(const WeakPtr& aOther) { // The thread safety check is performed inside of the operator= method. *this = aOther; } - WeakPtr& operator=(T* aOther) - { + WeakPtr& operator=(T* aOther) { if (aOther) { *this = aOther->SelfReferencingWeakPtr(); } else if (!mRef || mRef->get()) { @@ -254,8 +262,7 @@ return *this; } - MOZ_IMPLICIT WeakPtr(T* aOther) - { + MOZ_IMPLICIT WeakPtr(T* aOther) { *this = aOther; MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef); } @@ -270,7 +277,7 @@ T* get() const { return mRef->get(); } -private: + private: friend class SupportsWeakPtr; explicit WeakPtr(const RefPtr& aOther) : mRef(aOther) {} @@ -278,6 +285,6 @@ RefPtr mRef; }; -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_WeakPtr_h */ 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 @@ -7,17 +7,16 @@ #ifndef mozilla_WindowsVersion_h #define mozilla_WindowsVersion_h +#include "mozilla/Atomics.h" #include "mozilla/Attributes.h" #include #include namespace mozilla { -inline bool -IsWindowsVersionOrLater(uint32_t aVersion) -{ - static uint32_t minVersion = 0; - static uint32_t maxVersion = UINT32_MAX; +inline bool IsWindowsVersionOrLater(uint32_t aVersion) { + static Atomic minVersion(0); + static Atomic maxVersion(UINT32_MAX); if (minVersion >= aVersion) { return true; @@ -43,7 +42,7 @@ if (VerifyVersionInfo(&info, VER_MAJORVERSION | VER_MINORVERSION | - VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, conditionMask)) { minVersion = aVersion; return true; @@ -53,11 +52,9 @@ return false; } -inline bool -IsWindowsBuildOrLater(uint32_t aBuild) -{ - static uint32_t minBuild = 0; - static uint32_t maxBuild = UINT32_MAX; +inline bool IsWindowsBuildOrLater(uint32_t aBuild) { + static Atomic minBuild(0); + static Atomic maxBuild(UINT32_MAX); if (minBuild >= aBuild) { return true; @@ -84,114 +81,68 @@ return false; } -#if defined(_M_X64) || defined(_M_AMD64) -// We support only Win7 or later on Win64. -MOZ_ALWAYS_INLINE bool -IsXPSP3OrLater() -{ - return true; -} - -MOZ_ALWAYS_INLINE bool -IsWin2003OrLater() -{ - return true; -} - -MOZ_ALWAYS_INLINE bool -IsWin2003SP2OrLater() -{ - return true; -} +inline bool IsWindows10BuildOrLater(uint32_t aBuild) { + static Atomic minBuild(0); + static Atomic maxBuild(UINT32_MAX); -MOZ_ALWAYS_INLINE bool -IsVistaOrLater() -{ - return true; -} - -MOZ_ALWAYS_INLINE bool -IsVistaSP1OrLater() -{ - return true; -} - -MOZ_ALWAYS_INLINE bool -IsWin7OrLater() -{ - return true; -} -#else -MOZ_ALWAYS_INLINE bool -IsXPSP3OrLater() -{ - return IsWindowsVersionOrLater(0x05010300ul); -} + if (minBuild >= aBuild) { + return true; + } -MOZ_ALWAYS_INLINE bool -IsWin2003OrLater() -{ - return IsWindowsVersionOrLater(0x05020000ul); -} + if (aBuild >= maxBuild) { + return false; + } -MOZ_ALWAYS_INLINE bool -IsWin2003SP2OrLater() -{ - return IsWindowsVersionOrLater(0x05020200ul); -} + OSVERSIONINFOEX info; + ZeroMemory(&info, sizeof(OSVERSIONINFOEX)); + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + info.dwMajorVersion = 10; + info.dwBuildNumber = aBuild; -MOZ_ALWAYS_INLINE bool -IsVistaOrLater() -{ - return IsWindowsVersionOrLater(0x06000000ul); -} + DWORDLONG conditionMask = 0; + VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); -MOZ_ALWAYS_INLINE bool -IsVistaSP1OrLater() -{ - return IsWindowsVersionOrLater(0x06000100ul); -} + if (VerifyVersionInfo(&info, + VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, + conditionMask)) { + minBuild = aBuild; + return true; + } -MOZ_ALWAYS_INLINE bool -IsWin7OrLater() -{ - return IsWindowsVersionOrLater(0x06010000ul); + maxBuild = aBuild; + return false; } -#endif -MOZ_ALWAYS_INLINE bool -IsWin7SP1OrLater() -{ +MOZ_ALWAYS_INLINE bool IsWin7SP1OrLater() { return IsWindowsVersionOrLater(0x06010100ul); } -MOZ_ALWAYS_INLINE bool -IsWin8OrLater() -{ +MOZ_ALWAYS_INLINE bool IsWin8OrLater() { return IsWindowsVersionOrLater(0x06020000ul); } -MOZ_ALWAYS_INLINE bool -IsWin8Point1OrLater() -{ +MOZ_ALWAYS_INLINE bool IsWin8Point1OrLater() { return IsWindowsVersionOrLater(0x06030000ul); } -MOZ_ALWAYS_INLINE bool -IsWin10OrLater() -{ +MOZ_ALWAYS_INLINE bool IsWin10OrLater() { return IsWindowsVersionOrLater(0x0a000000ul); } -MOZ_ALWAYS_INLINE bool -IsNotWin7PreRTM() -{ - return IsWin7SP1OrLater() || !IsWin7OrLater() || - IsWindowsBuildOrLater(7600); +MOZ_ALWAYS_INLINE bool IsWin10CreatorsUpdateOrLater() { + return IsWindows10BuildOrLater(15063); +} + +MOZ_ALWAYS_INLINE bool IsNotWin7PreRTM() { + return IsWin7SP1OrLater() || IsWindowsBuildOrLater(7600); } -MOZ_ALWAYS_INLINE bool -IsWin7AndPre2000Compatible() { +inline bool IsWin7AndPre2000Compatible() { /* * See Bug 1279171. * We'd like to avoid using WMF on specific OS version when compatibility @@ -216,8 +167,8 @@ info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); #pragma warning(push) -#pragma warning(disable:4996) - bool success = GetVersionEx((LPOSVERSIONINFO) &info); +#pragma warning(disable : 4996) + bool success = GetVersionEx((LPOSVERSIONINFO)&info); #pragma warning(pop) if (!success) { return false; @@ -225,6 +176,6 @@ return info.dwMajorVersion < 5; } -} // namespace mozilla +} // namespace mozilla #endif /* mozilla_WindowsVersion_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/WrappingOperations.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/WrappingOperations.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/WrappingOperations.h @@ -0,0 +1,178 @@ +/* -*- 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/. */ + +/* + * Math operations that implement wraparound semantics on overflow or underflow + * without performing C++ undefined behavior or tripping up compiler-based + * integer-overflow sanitizers. + */ + +#ifndef mozilla_WrappingOperations_h +#define mozilla_WrappingOperations_h + +#include "mozilla/Attributes.h" +#include "mozilla/TypeTraits.h" + +#include + +namespace mozilla { + +namespace detail { + +template +struct WrapToSignedHelper { + static_assert(mozilla::IsUnsigned::value, + "WrapToSigned must be passed an unsigned type"); + + using SignedType = typename mozilla::MakeSigned::Type; + + static constexpr SignedType MaxValue = + (UnsignedType(1) << (CHAR_BIT * sizeof(SignedType) - 1)) - 1; + static constexpr SignedType MinValue = -MaxValue - 1; + + static constexpr UnsignedType MinValueUnsigned = + static_cast(MinValue); + static constexpr UnsignedType MaxValueUnsigned = + static_cast(MaxValue); + + // Overflow-correctness was proven in bug 1432646 and is explained in the + // comment below. This function is very hot, both at compile time and + // runtime, so disable all overflow checking in it. + MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW + MOZ_NO_SANITIZE_SIGNED_OVERFLOW static constexpr SignedType compute( + UnsignedType aValue) { + // This algorithm was originally provided here: + // https://stackoverflow.com/questions/13150449/efficient-unsigned-to-signed-cast-avoiding-implementation-defined-behavior + // + // If the value is in the non-negative signed range, just cast. + // + // If the value will be negative, compute its delta from the first number + // past the max signed integer, then add that to the minimum signed value. + // + // At the low end: if |u| is the maximum signed value plus one, then it has + // the same mathematical value as |MinValue| cast to unsigned form. The + // delta is zero, so the signed form of |u| is |MinValue| -- exactly the + // result of adding zero delta to |MinValue|. + // + // At the high end: if |u| is the maximum *unsigned* value, then it has all + // bits set. |MinValue| cast to unsigned form is purely the high bit set. + // So the delta is all bits but high set -- exactly |MaxValue|. And as + // |MinValue = -MaxValue - 1|, we have |MaxValue + (-MaxValue - 1)| to + // equal -1. + // + // Thus the delta below is in signed range, the corresponding cast is safe, + // and this computation produces values spanning [MinValue, 0): exactly the + // desired range of all negative signed integers. + return (aValue <= MaxValueUnsigned) + ? static_cast(aValue) + : static_cast(aValue - MinValueUnsigned) + MinValue; + } +}; + +} // namespace detail + +/** + * Convert an unsigned value to signed, if necessary wrapping around. + * + * This is the behavior normal C++ casting will perform in most implementations + * these days -- but this function makes explicit that such conversion is + * happening. + */ +template +inline constexpr typename detail::WrapToSignedHelper::SignedType +WrapToSigned(UnsignedType aValue) { + return detail::WrapToSignedHelper::compute(aValue); +} + +namespace detail { + +template +struct WrappingMultiplyHelper { + private: + using UnsignedT = typename MakeUnsigned::Type; + + MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW + static UnsignedT multiply(UnsignedT aX, UnsignedT aY) { + // |mozilla::WrappingMultiply| isn't constexpr because MSVC warns about + // well- defined unsigned integer overflows that may happen here. + // https://msdn.microsoft.com/en-us/library/4kze989h.aspx And constexpr + // seems to cause the warning to be emitted at |WrappingMultiply| call + // *sites* instead of here, so these #pragmas are ineffective. + // + // https://stackoverflow.com/questions/37658794/integer-constant-overflow-warning-in-constexpr + // + // If/when MSVC fix this bug, we should make these functions constexpr. + + // Begin with |1U| to ensure the overall operation chain is never promoted + // to signed integer operations that might have *signed* integer overflow. + return static_cast(1U * aX * aY); + } + + static T toResult(UnsignedT aX, UnsignedT aY) { + // We could always return WrapToSigned and rely on unsigned conversion + // undoing the wrapping when |T| is unsigned, but this seems clearer. + return IsSigned::value ? WrapToSigned(multiply(aX, aY)) + : multiply(aX, aY); + } + + public: + MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW + static T compute(T aX, T aY) { + return toResult(static_cast(aX), static_cast(aY)); + } +}; + +} // namespace detail + +/** + * Multiply two integers of the same type, and return the result converted to + * that type using wraparound semantics. This function: + * + * 1) makes explicit the desire for and dependence upon wraparound semantics, + * 2) provides wraparound semantics *safely* with no signed integer overflow + * that would have undefined behavior, and + * 3) won't trip up {,un}signed-integer overflow sanitizers (see + * build/autoconf/sanitize.m4) at runtime. + * + * For N-bit unsigned integer types, this is equivalent to multiplying the two + * numbers, then taking the result mod 2**N: + * + * WrappingMultiply(uint32_t(42), uint32_t(17)) is 714 (714 mod 2**32); + * WrappingMultiply(uint8_t(16), uint8_t(24)) is 128 (384 mod 2**8); + * WrappingMultiply(uint16_t(3), uint16_t(32768)) is 32768 (98304 mod 2*16). + * + * Use this function for any unsigned multiplication that can wrap (instead of + * normal C++ multiplication) to play nice with the sanitizers. But it's + * especially important to use it for uint16_t multiplication: in most compilers + * for uint16_t*uint16_t some operand values will trigger signed integer + * overflow with undefined behavior! http://kqueue.org/blog/2013/09/17/cltq/ + * has the grody details. Other than that one weird case, WrappingMultiply on + * unsigned types is the same as C++ multiplication. + * + * For N-bit signed integer types, this is equivalent to multiplying the two + * numbers wrapped to unsigned, taking the product mod 2**N, then wrapping that + * number to the signed range: + * + * WrappingMultiply(int16_t(-456), int16_t(123)) is + * 9448 ((-56088 mod 2**16) + 2**16); + * WrappingMultiply(int32_t(-7), int32_t(-9)) is 63 (63 mod 2**32); + * WrappingMultiply(int8_t(16), int8_t(24)) is -128 ((384 mod 2**8) - 2**8); + * WrappingMultiply(int8_t(16), int8_t(255)) is -16 ((4080 mod 2**8) - 2**8). + * + * There is no ready equivalent to this operation in C++, as applying C++ + * multiplication to signed integer types in ways that trigger overflow has + * undefined behavior. However, it's how multiplication *tends* to behave with + * most compilers in most situations, even though it's emphatically not required + * to do so. + */ +template +inline T WrappingMultiply(T aX, T aY) { + return detail::WrappingMultiplyHelper::compute(aX, aY); +} + +} /* namespace mozilla */ + +#endif /* mozilla_WrappingOperations_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 @@ -61,6 +61,7 @@ /** * Return a pseudo-random 64-bit number. */ + MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW uint64_t next() { /* * The offsetOfState*() methods below are provided so that exceedingly-rare @@ -91,7 +92,7 @@ * to get the mantissa's range. */ static constexpr int kMantissaBits = - mozilla::FloatingPoint::kExponentShift + 1; + mozilla::FloatingPoint::kExponentShift + 1; uint64_t mantissa = next() & ((UINT64_C(1) << kMantissaBits) - 1); return double(mantissa) / (UINT64_C(1) << kMantissaBits); } @@ -115,7 +116,7 @@ } }; -} // namespace non_crypto -} // namespace mozilla +} // namespace non_crypto +} // namespace mozilla -#endif // mozilla_XorShift128Plus_h +#endif // mozilla_XorShift128Plus_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/double-conversion.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/double-conversion.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/double-conversion.h @@ -1,538 +0,0 @@ -// Copyright 2012 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ -#define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ - -#include "mozilla/Types.h" -#include "utils.h" - -namespace double_conversion { - -class DoubleToStringConverter { - public: - // When calling ToFixed with a double > 10^kMaxFixedDigitsBeforePoint - // or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the - // function returns false. - static const int kMaxFixedDigitsBeforePoint = 60; - static const int kMaxFixedDigitsAfterPoint = 60; - - // When calling ToExponential with a requested_digits - // parameter > kMaxExponentialDigits then the function returns false. - static const int kMaxExponentialDigits = 120; - - // When calling ToPrecision with a requested_digits - // parameter < kMinPrecisionDigits or requested_digits > kMaxPrecisionDigits - // then the function returns false. - static const int kMinPrecisionDigits = 1; - static const int kMaxPrecisionDigits = 120; - - enum Flags { - NO_FLAGS = 0, - EMIT_POSITIVE_EXPONENT_SIGN = 1, - EMIT_TRAILING_DECIMAL_POINT = 2, - EMIT_TRAILING_ZERO_AFTER_POINT = 4, - UNIQUE_ZERO = 8 - }; - - // Flags should be a bit-or combination of the possible Flags-enum. - // - NO_FLAGS: no special flags. - // - EMIT_POSITIVE_EXPONENT_SIGN: when the number is converted into exponent - // form, emits a '+' for positive exponents. Example: 1.2e+2. - // - EMIT_TRAILING_DECIMAL_POINT: when the input number is an integer and is - // converted into decimal format then a trailing decimal point is appended. - // Example: 2345.0 is converted to "2345.". - // - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point - // emits a trailing '0'-character. This flag requires the - // EXMIT_TRAILING_DECIMAL_POINT flag. - // Example: 2345.0 is converted to "2345.0". - // - UNIQUE_ZERO: "-0.0" is converted to "0.0". - // - // Infinity symbol and nan_symbol provide the string representation for these - // special values. If the string is NULL and the special value is encountered - // then the conversion functions return false. - // - // The exponent_character is used in exponential representations. It is - // usually 'e' or 'E'. - // - // When converting to the shortest representation the converter will - // represent input numbers in decimal format if they are in the interval - // [10^decimal_in_shortest_low; 10^decimal_in_shortest_high[ - // (lower boundary included, greater boundary excluded). - // Example: with decimal_in_shortest_low = -6 and - // decimal_in_shortest_high = 21: - // ToShortest(0.000001) -> "0.000001" - // ToShortest(0.0000001) -> "1e-7" - // ToShortest(111111111111111111111.0) -> "111111111111111110000" - // ToShortest(100000000000000000000.0) -> "100000000000000000000" - // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21" - // - // When converting to precision mode the converter may add - // max_leading_padding_zeroes before returning the number in exponential - // format. - // Example with max_leading_padding_zeroes_in_precision_mode = 6. - // ToPrecision(0.0000012345, 2) -> "0.0000012" - // ToPrecision(0.00000012345, 2) -> "1.2e-7" - // Similarily the converter may add up to - // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid - // returning an exponential representation. A zero added by the - // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit. - // Examples for max_trailing_padding_zeroes_in_precision_mode = 1: - // ToPrecision(230.0, 2) -> "230" - // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT. - // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT. - DoubleToStringConverter(int flags, - const char* infinity_symbol, - const char* nan_symbol, - char exponent_character, - int decimal_in_shortest_low, - int decimal_in_shortest_high, - int max_leading_padding_zeroes_in_precision_mode, - int max_trailing_padding_zeroes_in_precision_mode) - : flags_(flags), - infinity_symbol_(infinity_symbol), - nan_symbol_(nan_symbol), - exponent_character_(exponent_character), - decimal_in_shortest_low_(decimal_in_shortest_low), - decimal_in_shortest_high_(decimal_in_shortest_high), - max_leading_padding_zeroes_in_precision_mode_( - max_leading_padding_zeroes_in_precision_mode), - max_trailing_padding_zeroes_in_precision_mode_( - max_trailing_padding_zeroes_in_precision_mode) { - // When 'trailing zero after the point' is set, then 'trailing point' - // must be set too. - ASSERT(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) || - !((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0)); - } - - // Returns a converter following the EcmaScript specification. - static MFBT_API const DoubleToStringConverter& EcmaScriptConverter(); - - // Computes the shortest string of digits that correctly represent the input - // number. Depending on decimal_in_shortest_low and decimal_in_shortest_high - // (see constructor) it then either returns a decimal representation, or an - // exponential representation. - // Example with decimal_in_shortest_low = -6, - // decimal_in_shortest_high = 21, - // EMIT_POSITIVE_EXPONENT_SIGN activated, and - // EMIT_TRAILING_DECIMAL_POINT deactived: - // ToShortest(0.000001) -> "0.000001" - // ToShortest(0.0000001) -> "1e-7" - // ToShortest(111111111111111111111.0) -> "111111111111111110000" - // ToShortest(100000000000000000000.0) -> "100000000000000000000" - // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21" - // - // Note: the conversion may round the output if the returned string - // is accurate enough to uniquely identify the input-number. - // For example the most precise representation of the double 9e59 equals - // "899999999999999918767229449717619953810131273674690656206848", but - // the converter will return the shorter (but still correct) "9e59". - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except when the input value is special and no infinity_symbol or - // nan_symbol has been given to the constructor. - bool ToShortest(double value, StringBuilder* result_builder) const { - return ToShortestIeeeNumber(value, result_builder, SHORTEST); - } - - // Same as ToShortest, but for single-precision floats. - bool ToShortestSingle(float value, StringBuilder* result_builder) const { - return ToShortestIeeeNumber(value, result_builder, SHORTEST_SINGLE); - } - - - // Computes a decimal representation with a fixed number of digits after the - // decimal point. The last emitted digit is rounded. - // - // Examples: - // ToFixed(3.12, 1) -> "3.1" - // ToFixed(3.1415, 3) -> "3.142" - // ToFixed(1234.56789, 4) -> "1234.5679" - // ToFixed(1.23, 5) -> "1.23000" - // ToFixed(0.1, 4) -> "0.1000" - // ToFixed(1e30, 2) -> "1000000000000000019884624838656.00" - // ToFixed(0.1, 30) -> "0.100000000000000005551115123126" - // ToFixed(0.1, 17) -> "0.10000000000000001" - // - // If requested_digits equals 0, then the tail of the result depends on - // the EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT. - // Examples, for requested_digits == 0, - // let EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT be - // - false and false: then 123.45 -> 123 - // 0.678 -> 1 - // - true and false: then 123.45 -> 123. - // 0.678 -> 1. - // - true and true: then 123.45 -> 123.0 - // 0.678 -> 1.0 - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except for the following cases: - // - the input value is special and no infinity_symbol or nan_symbol has - // been provided to the constructor, - // - 'value' > 10^kMaxFixedDigitsBeforePoint, or - // - 'requested_digits' > kMaxFixedDigitsAfterPoint. - // The last two conditions imply that the result will never contain more than - // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters - // (one additional character for the sign, and one for the decimal point). - MFBT_API bool ToFixed(double value, - int requested_digits, - StringBuilder* result_builder) const; - - // Computes a representation in exponential format with requested_digits - // after the decimal point. The last emitted digit is rounded. - // If requested_digits equals -1, then the shortest exponential representation - // is computed. - // - // Examples with EMIT_POSITIVE_EXPONENT_SIGN deactivated, and - // exponent_character set to 'e'. - // ToExponential(3.12, 1) -> "3.1e0" - // ToExponential(5.0, 3) -> "5.000e0" - // ToExponential(0.001, 2) -> "1.00e-3" - // ToExponential(3.1415, -1) -> "3.1415e0" - // ToExponential(3.1415, 4) -> "3.1415e0" - // ToExponential(3.1415, 3) -> "3.142e0" - // ToExponential(123456789000000, 3) -> "1.235e14" - // ToExponential(1000000000000000019884624838656.0, -1) -> "1e30" - // ToExponential(1000000000000000019884624838656.0, 32) -> - // "1.00000000000000001988462483865600e30" - // ToExponential(1234, 0) -> "1e3" - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except for the following cases: - // - the input value is special and no infinity_symbol or nan_symbol has - // been provided to the constructor, - // - 'requested_digits' > kMaxExponentialDigits. - // The last condition implies that the result will never contain more than - // kMaxExponentialDigits + 8 characters (the sign, the digit before the - // decimal point, the decimal point, the exponent character, the - // exponent's sign, and at most 3 exponent digits). - MFBT_API bool ToExponential(double value, - int requested_digits, - StringBuilder* result_builder) const; - - // Computes 'precision' leading digits of the given 'value' and returns them - // either in exponential or decimal format, depending on - // max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the - // constructor). - // The last computed digit is rounded. - // - // Example with max_leading_padding_zeroes_in_precision_mode = 6. - // ToPrecision(0.0000012345, 2) -> "0.0000012" - // ToPrecision(0.00000012345, 2) -> "1.2e-7" - // Similarily the converter may add up to - // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid - // returning an exponential representation. A zero added by the - // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit. - // Examples for max_trailing_padding_zeroes_in_precision_mode = 1: - // ToPrecision(230.0, 2) -> "230" - // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT. - // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT. - // Examples for max_trailing_padding_zeroes_in_precision_mode = 3, and no - // EMIT_TRAILING_ZERO_AFTER_POINT: - // ToPrecision(123450.0, 6) -> "123450" - // ToPrecision(123450.0, 5) -> "123450" - // ToPrecision(123450.0, 4) -> "123500" - // ToPrecision(123450.0, 3) -> "123000" - // ToPrecision(123450.0, 2) -> "1.2e5" - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except for the following cases: - // - the input value is special and no infinity_symbol or nan_symbol has - // been provided to the constructor, - // - precision < kMinPericisionDigits - // - precision > kMaxPrecisionDigits - // The last condition implies that the result will never contain more than - // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the - // exponent character, the exponent's sign, and at most 3 exponent digits). - MFBT_API bool ToPrecision(double value, - int precision, - bool* used_exponential_notation, - StringBuilder* result_builder) const; - - enum DtoaMode { - // Produce the shortest correct representation. - // For example the output of 0.299999999999999988897 is (the less accurate - // but correct) 0.3. - SHORTEST, - // Same as SHORTEST, but for single-precision floats. - SHORTEST_SINGLE, - // Produce a fixed number of digits after the decimal point. - // For instance fixed(0.1, 4) becomes 0.1000 - // If the input number is big, the output will be big. - FIXED, - // Fixed number of digits (independent of the decimal point). - PRECISION - }; - - // The maximal number of digits that are needed to emit a double in base 10. - // A higher precision can be achieved by using more digits, but the shortest - // accurate representation of any double will never use more digits than - // kBase10MaximalLength. - // Note that DoubleToAscii null-terminates its input. So the given buffer - // should be at least kBase10MaximalLength + 1 characters long. - static const MFBT_DATA int kBase10MaximalLength = 17; - - // Converts the given double 'v' to ascii. 'v' must not be NaN, +Infinity, or - // -Infinity. In SHORTEST_SINGLE-mode this restriction also applies to 'v' - // after it has been casted to a single-precision float. That is, in this - // mode static_cast(v) must not be NaN, +Infinity or -Infinity. - // - // The result should be interpreted as buffer * 10^(point-length). - // - // The output depends on the given mode: - // - SHORTEST: produce the least amount of digits for which the internal - // identity requirement is still satisfied. If the digits are printed - // (together with the correct exponent) then reading this number will give - // 'v' again. The buffer will choose the representation that is closest to - // 'v'. If there are two at the same distance, than the one farther away - // from 0 is chosen (halfway cases - ending with 5 - are rounded up). - // In this mode the 'requested_digits' parameter is ignored. - // - SHORTEST_SINGLE: same as SHORTEST but with single-precision. - // - FIXED: produces digits necessary to print a given number with - // 'requested_digits' digits after the decimal point. The produced digits - // might be too short in which case the caller has to fill the remainder - // with '0's. - // Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2. - // Halfway cases are rounded towards +/-Infinity (away from 0). The call - // toFixed(0.15, 2) thus returns buffer="2", point=0. - // The returned buffer may contain digits that would be truncated from the - // shortest representation of the input. - // - PRECISION: produces 'requested_digits' where the first digit is not '0'. - // Even though the length of produced digits usually equals - // 'requested_digits', the function is allowed to return fewer digits, in - // which case the caller has to fill the missing digits with '0's. - // Halfway cases are again rounded away from 0. - // DoubleToAscii expects the given buffer to be big enough to hold all - // digits and a terminating null-character. In SHORTEST-mode it expects a - // buffer of at least kBase10MaximalLength + 1. In all other modes the - // requested_digits parameter and the padding-zeroes limit the size of the - // output. Don't forget the decimal point, the exponent character and the - // terminating null-character when computing the maximal output size. - // The given length is only used in debug mode to ensure the buffer is big - // enough. - static MFBT_API void DoubleToAscii(double v, - DtoaMode mode, - int requested_digits, - char* buffer, - int buffer_length, - bool* sign, - int* length, - int* point); - - private: - // Implementation for ToShortest and ToShortestSingle. - MFBT_API bool ToShortestIeeeNumber(double value, - StringBuilder* result_builder, - DtoaMode mode) const; - - // If the value is a special value (NaN or Infinity) constructs the - // corresponding string using the configured infinity/nan-symbol. - // If either of them is NULL or the value is not special then the - // function returns false. - MFBT_API bool HandleSpecialValues(double value, StringBuilder* result_builder) const; - // Constructs an exponential representation (i.e. 1.234e56). - // The given exponent assumes a decimal point after the first decimal digit. - MFBT_API void CreateExponentialRepresentation(const char* decimal_digits, - int length, - int exponent, - StringBuilder* result_builder) const; - // Creates a decimal representation (i.e 1234.5678). - MFBT_API void CreateDecimalRepresentation(const char* decimal_digits, - int length, - int decimal_point, - int digits_after_point, - StringBuilder* result_builder) const; - - const int flags_; - const char* const infinity_symbol_; - const char* const nan_symbol_; - const char exponent_character_; - const int decimal_in_shortest_low_; - const int decimal_in_shortest_high_; - const int max_leading_padding_zeroes_in_precision_mode_; - const int max_trailing_padding_zeroes_in_precision_mode_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter); -}; - - -class StringToDoubleConverter { - public: - // Enumeration for allowing octals and ignoring junk when converting - // strings to numbers. - enum Flags { - NO_FLAGS = 0, - ALLOW_HEX = 1, - ALLOW_OCTALS = 2, - ALLOW_TRAILING_JUNK = 4, - ALLOW_LEADING_SPACES = 8, - ALLOW_TRAILING_SPACES = 16, - ALLOW_SPACES_AFTER_SIGN = 32 - }; - - // Flags should be a bit-or combination of the possible Flags-enum. - // - NO_FLAGS: no special flags. - // - ALLOW_HEX: recognizes the prefix "0x". Hex numbers may only be integers. - // Ex: StringToDouble("0x1234") -> 4660.0 - // In StringToDouble("0x1234.56") the characters ".56" are trailing - // junk. The result of the call is hence dependent on - // the ALLOW_TRAILING_JUNK flag and/or the junk value. - // With this flag "0x" is a junk-string. Even with ALLOW_TRAILING_JUNK, - // the string will not be parsed as "0" followed by junk. - // - // - ALLOW_OCTALS: recognizes the prefix "0" for octals: - // If a sequence of octal digits starts with '0', then the number is - // read as octal integer. Octal numbers may only be integers. - // Ex: StringToDouble("01234") -> 668.0 - // StringToDouble("012349") -> 12349.0 // Not a sequence of octal - // // digits. - // In StringToDouble("01234.56") the characters ".56" are trailing - // junk. The result of the call is hence dependent on - // the ALLOW_TRAILING_JUNK flag and/or the junk value. - // In StringToDouble("01234e56") the characters "e56" are trailing - // junk, too. - // - ALLOW_TRAILING_JUNK: ignore trailing characters that are not part of - // a double literal. - // - ALLOW_LEADING_SPACES: skip over leading spaces. - // - ALLOW_TRAILING_SPACES: ignore trailing spaces. - // - ALLOW_SPACES_AFTER_SIGN: ignore spaces after the sign. - // Ex: StringToDouble("- 123.2") -> -123.2. - // StringToDouble("+ 123.2") -> 123.2 - // - // empty_string_value is returned when an empty string is given as input. - // If ALLOW_LEADING_SPACES or ALLOW_TRAILING_SPACES are set, then a string - // containing only spaces is converted to the 'empty_string_value', too. - // - // junk_string_value is returned when - // a) ALLOW_TRAILING_JUNK is not set, and a junk character (a character not - // part of a double-literal) is found. - // b) ALLOW_TRAILING_JUNK is set, but the string does not start with a - // double literal. - // - // infinity_symbol and nan_symbol are strings that are used to detect - // inputs that represent infinity and NaN. They can be null, in which case - // they are ignored. - // The conversion routine first reads any possible signs. Then it compares the - // following character of the input-string with the first character of - // the infinity, and nan-symbol. If either matches, the function assumes, that - // a match has been found, and expects the following input characters to match - // the remaining characters of the special-value symbol. - // This means that the following restrictions apply to special-value symbols: - // - they must not start with signs ('+', or '-'), - // - they must not have the same first character. - // - they must not start with digits. - // - // Examples: - // flags = ALLOW_HEX | ALLOW_TRAILING_JUNK, - // empty_string_value = 0.0, - // junk_string_value = NaN, - // infinity_symbol = "infinity", - // nan_symbol = "nan": - // StringToDouble("0x1234") -> 4660.0. - // StringToDouble("0x1234K") -> 4660.0. - // StringToDouble("") -> 0.0 // empty_string_value. - // StringToDouble(" ") -> NaN // junk_string_value. - // StringToDouble(" 1") -> NaN // junk_string_value. - // StringToDouble("0x") -> NaN // junk_string_value. - // StringToDouble("-123.45") -> -123.45. - // StringToDouble("--123.45") -> NaN // junk_string_value. - // StringToDouble("123e45") -> 123e45. - // StringToDouble("123E45") -> 123e45. - // StringToDouble("123e+45") -> 123e45. - // StringToDouble("123E-45") -> 123e-45. - // StringToDouble("123e") -> 123.0 // trailing junk ignored. - // StringToDouble("123e-") -> 123.0 // trailing junk ignored. - // StringToDouble("+NaN") -> NaN // NaN string literal. - // StringToDouble("-infinity") -> -inf. // infinity literal. - // StringToDouble("Infinity") -> NaN // junk_string_value. - // - // flags = ALLOW_OCTAL | ALLOW_LEADING_SPACES, - // empty_string_value = 0.0, - // junk_string_value = NaN, - // infinity_symbol = NULL, - // nan_symbol = NULL: - // StringToDouble("0x1234") -> NaN // junk_string_value. - // StringToDouble("01234") -> 668.0. - // StringToDouble("") -> 0.0 // empty_string_value. - // StringToDouble(" ") -> 0.0 // empty_string_value. - // StringToDouble(" 1") -> 1.0 - // StringToDouble("0x") -> NaN // junk_string_value. - // StringToDouble("0123e45") -> NaN // junk_string_value. - // StringToDouble("01239E45") -> 1239e45. - // StringToDouble("-infinity") -> NaN // junk_string_value. - // StringToDouble("NaN") -> NaN // junk_string_value. - StringToDoubleConverter(int flags, - double empty_string_value, - double junk_string_value, - const char* infinity_symbol, - const char* nan_symbol) - : flags_(flags), - empty_string_value_(empty_string_value), - junk_string_value_(junk_string_value), - infinity_symbol_(infinity_symbol), - nan_symbol_(nan_symbol) { - } - - // Performs the conversion. - // The output parameter 'processed_characters_count' is set to the number - // of characters that have been processed to read the number. - // Spaces than are processed with ALLOW_{LEADING|TRAILING}_SPACES are included - // in the 'processed_characters_count'. Trailing junk is never included. - double StringToDouble(const char* buffer, - int length, - int* processed_characters_count) const { - return StringToIeee(buffer, length, processed_characters_count, true); - } - - // Same as StringToDouble but reads a float. - // Note that this is not equivalent to static_cast(StringToDouble(...)) - // due to potential double-rounding. - float StringToFloat(const char* buffer, - int length, - int* processed_characters_count) const { - return static_cast(StringToIeee(buffer, length, - processed_characters_count, false)); - } - - private: - const int flags_; - const double empty_string_value_; - const double junk_string_value_; - const char* const infinity_symbol_; - const char* const nan_symbol_; - - double StringToIeee(const char* buffer, - int length, - int* processed_characters_count, - bool read_as_double) const; - - DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter); -}; - -} // namespace double_conversion - -#endif // DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/fallible.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/fallible.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/fallible.h @@ -48,21 +48,17 @@ * } * */ + +#include + namespace mozilla { -struct fallible_t { }; +using fallible_t = std::nothrow_t; -/* This symbol is kept unexported, such that in corner cases where the - * compiler can't remove its use (essentially, cross compilation-unit - * calls), the smallest machine code is used. - * Depending how the linker packs symbols, it will consume between 1 and - * 8 bytes of read-only data in each executable or shared library, but - * only in those where it's actually not optimized out by the compiler. - */ -extern const fallible_t fallible; +static const fallible_t& fallible = std::nothrow; -} // namespace mozilla +} // namespace mozilla #endif -#endif // mozilla_fallible_h +#endif // mozilla_fallible_h 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 @@ -13,16 +13,14 @@ */ #if defined(__cplusplus) -# include +#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 +#include #else -# include -# include +#include #endif #if defined(__cplusplus) @@ -33,27 +31,7 @@ #include "mozilla/Attributes.h" #include "mozilla/Types.h" -#define MOZALLOC_HAVE_XMALLOC - -#if defined(MOZ_ALWAYS_INLINE_EVEN_DEBUG) -# define MOZALLOC_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG -#elif defined(HAVE_FORCEINLINE) -# define MOZALLOC_INLINE __forceinline -#else -# define MOZALLOC_INLINE inline -#endif - -/* Workaround build problem with Sun Studio 12 */ -#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# undef MOZ_MUST_USE -# define MOZ_MUST_USE -# undef MOZ_ALLOCATOR -# define MOZ_ALLOCATOR -#endif - -#if defined(__cplusplus) -extern "C" { -#endif /* ifdef __cplusplus */ +MOZ_BEGIN_EXTERN_C /* * We need to use malloc_impl and free_impl in this file when they are @@ -82,53 +60,31 @@ * passing that pointer to |free()|. */ -MFBT_API void* moz_xmalloc(size_t size) - MOZ_ALLOCATOR; +MFBT_API void* moz_xmalloc(size_t size) MOZ_ALLOCATOR; -MFBT_API void* moz_xcalloc(size_t nmemb, size_t size) - MOZ_ALLOCATOR; +MFBT_API void* moz_xcalloc(size_t nmemb, size_t size) MOZ_ALLOCATOR; -MFBT_API void* moz_xrealloc(void* ptr, size_t size) - MOZ_ALLOCATOR; +MFBT_API void* moz_xrealloc(void* ptr, size_t size) MOZ_ALLOCATOR; -MFBT_API char* moz_xstrdup(const char* str) - MOZ_ALLOCATOR; +MFBT_API char* moz_xstrdup(const char* str) MOZ_ALLOCATOR; -MFBT_API size_t moz_malloc_usable_size(void *ptr); +MFBT_API size_t moz_malloc_usable_size(void* ptr); -MFBT_API size_t moz_malloc_size_of(const void *ptr); +MFBT_API size_t moz_malloc_size_of(const void* ptr); + +/* + * Like moz_malloc_size_of(), but works reliably with interior pointers, i.e. + * pointers into the middle of a live allocation. + */ +MFBT_API size_t moz_malloc_enclosing_size_of(const void* ptr); #if defined(HAVE_STRNDUP) -MFBT_API char* moz_xstrndup(const char* str, size_t strsize) - MOZ_ALLOCATOR; +MFBT_API char* moz_xstrndup(const char* str, size_t strsize) MOZ_ALLOCATOR; #endif /* if defined(HAVE_STRNDUP) */ +MFBT_API void* moz_xmemalign(size_t boundary, size_t size) MOZ_ALLOCATOR; -#if defined(HAVE_POSIX_MEMALIGN) -MFBT_API MOZ_MUST_USE -int moz_xposix_memalign(void **ptr, size_t alignment, size_t size); - -MFBT_API MOZ_MUST_USE -int moz_posix_memalign(void **ptr, size_t alignment, size_t size); -#endif /* if defined(HAVE_POSIX_MEMALIGN) */ - - -#if defined(HAVE_MEMALIGN) -MFBT_API void* moz_xmemalign(size_t boundary, size_t size) - MOZ_ALLOCATOR; -#endif /* if defined(HAVE_MEMALIGN) */ - - -#if defined(HAVE_VALLOC) -MFBT_API void* moz_xvalloc(size_t size) - MOZ_ALLOCATOR; -#endif /* if defined(HAVE_VALLOC) */ - - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* ifdef __cplusplus */ - +MOZ_END_EXTERN_C #ifdef __cplusplus @@ -142,42 +98,41 @@ * that can be delete'd by any of * * (1) the matching infallible operator delete immediately below - * (2) the matching "fallible" operator delete further below - * (3) the matching system |operator delete(void*, std::nothrow)| - * (4) the matching system |operator delete(void*) throw(std::bad_alloc)| + * (2) the matching system |operator delete(void*, std::nothrow)| + * (3) the matching system |operator delete(void*) throw(std::bad_alloc)| * * NB: these are declared |throw(std::bad_alloc)|, though they will never * throw that exception. This declaration is consistent with the rule * that |::operator new() throw(std::bad_alloc)| will never return NULL. + * + * NB: mozilla::fallible can be used instead of std::nothrow. */ /* NB: This is defined just to silence vacuous warnings about symbol * visibility on OS X/gcc. These symbols are force-inline and not * exported. */ #if defined(XP_MACOSX) -# define MOZALLOC_EXPORT_NEW MFBT_API +#define MOZALLOC_EXPORT_NEW MFBT_API #else -# define MOZALLOC_EXPORT_NEW +#define MOZALLOC_EXPORT_NEW #endif -#if defined(ANDROID) -/* - * It's important to always specify 'throw()' in GCC because it's used to tell - * GCC that 'new' may return null. That makes GCC null-check the result before - * potentially initializing the memory to zero. - * Also, the Android minimalistic headers don't include std::bad_alloc. - */ -#define MOZALLOC_THROW_IF_HAS_EXCEPTIONS throw() -#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS -#elif defined(_MSC_VER) +#if defined(_MSC_VER) /* * Suppress build warning spam (bug 578546). */ +#if _MSC_VER < 1912 #define MOZALLOC_THROW_IF_HAS_EXCEPTIONS -#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS #else #define MOZALLOC_THROW_IF_HAS_EXCEPTIONS throw() -#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS throw(std::bad_alloc) +#endif +#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS +#else +/* + * C++11 has deprecated exception-specifications in favour of |noexcept|. + */ +#define MOZALLOC_THROW_IF_HAS_EXCEPTIONS noexcept(true) +#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS noexcept(false) #endif #define MOZALLOC_THROW_BAD_ALLOC MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS @@ -187,167 +142,99 @@ /* gcc's asan somehow doesn't like always_inline on this function. */ __attribute__((gnu_inline)) inline #else -MOZALLOC_INLINE +MOZ_ALWAYS_INLINE_EVEN_DEBUG #endif -void* operator new(size_t size) MOZALLOC_THROW_BAD_ALLOC -{ - return moz_xmalloc(size); + void* + operator new(size_t size) MOZALLOC_THROW_BAD_ALLOC { + return moz_xmalloc(size); } -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void* operator new(size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return malloc_impl(size); +MOZALLOC_EXPORT_NEW MOZ_ALWAYS_INLINE_EVEN_DEBUG void* operator new( + size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS { + return malloc_impl(size); } -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void* operator new[](size_t size) MOZALLOC_THROW_BAD_ALLOC -{ - return moz_xmalloc(size); +MOZALLOC_EXPORT_NEW MOZ_ALWAYS_INLINE_EVEN_DEBUG void* operator new[]( + size_t size) MOZALLOC_THROW_BAD_ALLOC { + return moz_xmalloc(size); } -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void* operator new[](size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return malloc_impl(size); +MOZALLOC_EXPORT_NEW MOZ_ALWAYS_INLINE_EVEN_DEBUG void* operator new[]( + size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS { + return malloc_impl(size); } -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void operator delete(void* ptr) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return free_impl(ptr); +MOZALLOC_EXPORT_NEW MOZ_ALWAYS_INLINE_EVEN_DEBUG void operator delete(void* ptr) + MOZALLOC_THROW_IF_HAS_EXCEPTIONS { + return free_impl(ptr); } -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void operator delete(void* ptr, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return free_impl(ptr); +MOZALLOC_EXPORT_NEW MOZ_ALWAYS_INLINE_EVEN_DEBUG void operator delete( + void* ptr, const std::nothrow_t&)MOZALLOC_THROW_IF_HAS_EXCEPTIONS { + return free_impl(ptr); } -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void operator delete[](void* ptr) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return free_impl(ptr); +MOZALLOC_EXPORT_NEW MOZ_ALWAYS_INLINE_EVEN_DEBUG void operator delete[]( + void* ptr) MOZALLOC_THROW_IF_HAS_EXCEPTIONS { + return free_impl(ptr); } -MOZALLOC_EXPORT_NEW MOZALLOC_INLINE -void operator delete[](void* ptr, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return free_impl(ptr); +MOZALLOC_EXPORT_NEW MOZ_ALWAYS_INLINE_EVEN_DEBUG void operator delete[]( + void* ptr, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS { + return free_impl(ptr); } - -/* - * We also add a new allocator variant: "fallible operator new." - * Unlike libmozalloc's implementations of the standard nofail - * allocators, this allocator is allowed to return NULL. It can be used - * as follows - * - * Foo* f = new (mozilla::fallible) Foo(...); - * - * operator delete(fallible) is defined for completeness only. - * - * Each operator new below returns a pointer to memory that can be - * delete'd by any of - * - * (1) the matching "fallible" operator delete below - * (2) the matching infallible operator delete above - * (3) the matching system |operator delete(void*, std::nothrow)| - * (4) the matching system |operator delete(void*) throw(std::bad_alloc)| - */ - -MOZALLOC_INLINE -void* operator new(size_t size, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return malloc_impl(size); -} - -MOZALLOC_INLINE -void* operator new[](size_t size, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - return malloc_impl(size); -} - -MOZALLOC_INLINE -void operator delete(void* ptr, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - free_impl(ptr); -} - -MOZALLOC_INLINE -void operator delete[](void* ptr, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS -{ - free_impl(ptr); -} - - /* * This policy is identical to MallocAllocPolicy, except it uses * moz_xmalloc/moz_xcalloc/moz_xrealloc instead of * malloc/calloc/realloc. */ -class InfallibleAllocPolicy -{ -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); +class InfallibleAllocPolicy { + 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) { + reportAllocOverflow(); + } + return static_cast(moz_xmalloc(aNumElems * sizeof(T))); + } + + template + T* pod_calloc(size_t aNumElems) { + return static_cast(moz_xcalloc(aNumElems, sizeof(T))); + } + + template + T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { + if (aNewSize & mozilla::tl::MulOverflowMask::value) { + reportAllocOverflow(); } + return static_cast(moz_xrealloc(aPtr, aNewSize * sizeof(T))); + } - template - T* pod_malloc(size_t aNumElems) - { - if (aNumElems & mozilla::tl::MulOverflowMask::value) { - reportAllocOverflow(); - } - return static_cast(moz_xmalloc(aNumElems * sizeof(T))); - } + void free_(void* aPtr) { free_impl(aPtr); } - template - T* pod_calloc(size_t aNumElems) - { - return static_cast(moz_xcalloc(aNumElems, sizeof(T))); - } + void reportAllocOverflow() const { mozalloc_abort("alloc overflow"); } - template - T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) - { - if (aNewSize & mozilla::tl::MulOverflowMask::value) { - reportAllocOverflow(); - } - return static_cast(moz_xrealloc(aPtr, aNewSize * sizeof(T))); - } - - void free_(void* aPtr) - { - free_impl(aPtr); - } - - void reportAllocOverflow() const - { - mozalloc_abort("alloc overflow"); - } - - bool checkSimulatedOOM() const - { - return true; - } + bool checkSimulatedOOM() const { return true; } }; -#endif /* ifdef __cplusplus */ +#endif /* ifdef __cplusplus */ #ifdef malloc_impl_ #undef malloc_impl_ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/mozalloc_abort.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/mozalloc_abort.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/mozalloc_abort.h @@ -18,11 +18,11 @@ * Note: MOZ_NORETURN seems to break crash stacks on ARM, so we don't * use that annotation there. */ -MFBT_API +extern "C" MFBT_API #if !defined(__arm__) - MOZ_NORETURN + MOZ_NORETURN #endif - void mozalloc_abort(const char* const msg); + void + mozalloc_abort(const char* const msg); - -#endif /* ifndef mozilla_mozalloc_abort_h */ +#endif /* ifndef mozilla_mozalloc_abort_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/mozalloc_oom.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/mozalloc_oom.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/mozalloc_oom.h @@ -22,10 +22,10 @@ * the size of the allocation on which we aborted. */ typedef void (*mozalloc_oom_abort_handler)(size_t size); -MFBT_API void mozalloc_set_oom_abort_handler(mozalloc_oom_abort_handler handler); +MFBT_API void mozalloc_set_oom_abort_handler( + mozalloc_oom_abort_handler handler); /* TODO: functions to query system memory usage and register * critical-memory handlers. */ - #endif /* ifndef mozilla_mozalloc_oom_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/unused.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/unused.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/unused.h @@ -7,6 +7,7 @@ #ifndef mozilla_unused_h #define mozilla_unused_h +#include "mozilla/Attributes.h" #include "mozilla/Types.h" #ifdef __cplusplus @@ -17,22 +18,24 @@ // Suppress GCC warnings about unused return values with // Unused << SomeFuncDeclaredWarnUnusedReturnValue(); // -struct unused_t -{ - template - inline void - operator<<(const T& /*unused*/) const {} +struct unused_t { + template + MOZ_ALWAYS_INLINE_EVEN_DEBUG void operator<<(const T& /*unused*/) const {} }; extern MFBT_DATA const unused_t Unused; -} // namespace mozilla +} // namespace mozilla -#endif // __cplusplus +#endif // __cplusplus // An alternative to mozilla::Unused for use in (a) C code and (b) code where // linking with unused.o is difficult. #define MOZ_UNUSED(expr) \ - do { if (expr) { (void)0; } } while (0) + do { \ + if (expr) { \ + (void)0; \ + } \ + } while (0) -#endif // mozilla_unused_h +#endif // mozilla_unused_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/utils.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/utils.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozilla/utils.h @@ -1,298 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DOUBLE_CONVERSION_UTILS_H_ -#define DOUBLE_CONVERSION_UTILS_H_ - -#include -#include - -#include "mozilla/Assertions.h" -#ifndef ASSERT -#define ASSERT(condition) MOZ_ASSERT(condition) -#endif -#ifndef UNIMPLEMENTED -#define UNIMPLEMENTED() MOZ_CRASH() -#endif -#ifndef UNREACHABLE -#define UNREACHABLE() MOZ_CRASH() -#endif - -// Double operations detection based on target architecture. -// Linux uses a 80bit wide floating point stack on x86. This induces double -// rounding, which in turn leads to wrong results. -// An easy way to test if the floating-point operations are correct is to -// evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then -// the result is equal to 89255e-22. -// The best way to test this, is to create a division-function and to compare -// the output of the division with the expected result. (Inlining must be -// disabled.) -// On Linux,x86 89255e-22 != Div_double(89255.0/1e22) -#if defined(_M_X64) || defined(__x86_64__) || \ - defined(__ARMEL__) || defined(__avr32__) || \ - defined(__hppa__) || defined(__ia64__) || \ - defined(__mips__) || \ - defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \ - defined(__sparc__) || defined(__sparc) || defined(__s390__) || \ - defined(__SH4__) || defined(__alpha__) || \ - defined(_MIPS_ARCH_MIPS32R2) || \ - defined(__AARCH64EL__) || defined(__aarch64__) -#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 -#elif defined(_M_IX86) || defined(__i386__) || defined(__i386) -#if defined(_WIN32) -// Windows uses a 64bit wide floating point stack. -#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 -#else -#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS -#endif // _WIN32 -#else -#error Target architecture was not detected as supported by Double-Conversion. -#endif - - -#include - -// The following macro works on both 32 and 64-bit platforms. -// Usage: instead of writing 0x1234567890123456 -// write UINT64_2PART_C(0x12345678,90123456); -#define UINT64_2PART_C(a, b) (((static_cast(a) << 32) + 0x##b##u)) - - -// The expression ARRAY_SIZE(a) is a compile-time constant of type -// size_t which represents the number of elements of the given -// array. You should only use ARRAY_SIZE on statically allocated -// arrays. -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) \ - ((sizeof(a) / sizeof(*(a))) / \ - static_cast(!(sizeof(a) % sizeof(*(a))))) -#endif - -// A macro to disallow the evil copy constructor and operator= functions -// This should be used in the private: declarations for a class -#ifndef DISALLOW_COPY_AND_ASSIGN -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) -#endif - -// A macro to disallow all the implicit constructors, namely the -// default constructor, copy constructor and operator= functions. -// -// This should be used in the private: declarations for a class -// that wants to prevent anyone from instantiating it. This is -// especially useful for classes containing only static methods. -#ifndef DISALLOW_IMPLICIT_CONSTRUCTORS -#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ - TypeName(); \ - DISALLOW_COPY_AND_ASSIGN(TypeName) -#endif - -namespace double_conversion { - -static const int kCharSize = sizeof(char); - -// Returns the maximum of the two parameters. -template -static T Max(T a, T b) { - return a < b ? b : a; -} - - -// Returns the minimum of the two parameters. -template -static T Min(T a, T b) { - return a < b ? a : b; -} - - -inline int StrLength(const char* string) { - size_t length = strlen(string); - ASSERT(length == static_cast(static_cast(length))); - return static_cast(length); -} - -// This is a simplified version of V8's Vector class. -template -class Vector { - public: - Vector() : start_(NULL), length_(0) {} - Vector(T* data, int len) : start_(data), length_(len) { - ASSERT(len == 0 || (len > 0 && data != NULL)); - } - - // Returns a vector using the same backing storage as this one, - // spanning from and including 'from', to but not including 'to'. - Vector SubVector(int from, int to) { - ASSERT(to <= length_); - ASSERT(from < to); - ASSERT(0 <= from); - return Vector(start() + from, to - from); - } - - // Returns the length of the vector. - int length() const { return length_; } - - // Returns whether or not the vector is empty. - bool is_empty() const { return length_ == 0; } - - // Returns the pointer to the start of the data in the vector. - T* start() const { return start_; } - - // Access individual vector elements - checks bounds in debug mode. - T& operator[](int index) const { - ASSERT(0 <= index && index < length_); - return start_[index]; - } - - T& first() { return start_[0]; } - - T& last() { return start_[length_ - 1]; } - - private: - T* start_; - int length_; -}; - - -// Helper class for building result strings in a character buffer. The -// purpose of the class is to use safe operations that checks the -// buffer bounds on all operations in debug mode. -class StringBuilder { - public: - StringBuilder(char* buffer, int buffer_size) - : buffer_(buffer, buffer_size), position_(0) { } - - ~StringBuilder() { if (!is_finalized()) Finalize(); } - - int size() const { return buffer_.length(); } - - // Get the current position in the builder. - int position() const { - ASSERT(!is_finalized()); - return position_; - } - - // Reset the position. - void Reset() { position_ = 0; } - - // Add a single character to the builder. It is not allowed to add - // 0-characters; use the Finalize() method to terminate the string - // instead. - void AddCharacter(char c) { - ASSERT(c != '\0'); - ASSERT(!is_finalized() && position_ < buffer_.length()); - buffer_[position_++] = c; - } - - // Add an entire string to the builder. Uses strlen() internally to - // compute the length of the input string. - void AddString(const char* s) { - AddSubstring(s, StrLength(s)); - } - - // Add the first 'n' characters of the given string 's' to the - // builder. The input string must have enough characters. - void AddSubstring(const char* s, int n) { - ASSERT(!is_finalized() && position_ + n < buffer_.length()); - ASSERT(static_cast(n) <= strlen(s)); - memmove(&buffer_[position_], s, n * kCharSize); - position_ += n; - } - - - // Add character padding to the builder. If count is non-positive, - // nothing is added to the builder. - void AddPadding(char c, int count) { - for (int i = 0; i < count; i++) { - AddCharacter(c); - } - } - - // Finalize the string by 0-terminating it and returning the buffer. - char* Finalize() { - ASSERT(!is_finalized() && position_ < buffer_.length()); - buffer_[position_] = '\0'; - // Make sure nobody managed to add a 0-character to the - // buffer while building the string. - ASSERT(strlen(buffer_.start()) == static_cast(position_)); - position_ = -1; - ASSERT(is_finalized()); - return buffer_.start(); - } - - private: - Vector buffer_; - int position_; - - bool is_finalized() const { return position_ < 0; } - - DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder); -}; - -// The type-based aliasing rule allows the compiler to assume that pointers of -// different types (for some definition of different) never alias each other. -// Thus the following code does not work: -// -// float f = foo(); -// int fbits = *(int*)(&f); -// -// The compiler 'knows' that the int pointer can't refer to f since the types -// don't match, so the compiler may cache f in a register, leaving random data -// in fbits. Using C++ style casts makes no difference, however a pointer to -// char data is assumed to alias any other pointer. This is the 'memcpy -// exception'. -// -// Bit_cast uses the memcpy exception to move the bits from a variable of one -// type of a variable of another type. Of course the end result is likely to -// be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005) -// will completely optimize BitCast away. -// -// There is an additional use for BitCast. -// Recent gccs will warn when they see casts that may result in breakage due to -// the type-based aliasing rule. If you have checked that there is no breakage -// you can use BitCast to cast one pointer type to another. This confuses gcc -// enough that it can no longer see that you have cast one pointer type to -// another thus avoiding the warning. -template -inline Dest BitCast(const Source& source) { - static_assert(sizeof(Dest) == sizeof(Source), - "BitCast's source and destination types must be the same size"); - - Dest dest; - memmove(&dest, &source, sizeof(dest)); - return dest; -} - -template -inline Dest BitCast(Source* source) { - return BitCast(reinterpret_cast(source)); -} - -} // namespace double_conversion - -#endif // DOUBLE_CONVERSION_UTILS_H_ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozjemalloc_types.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozjemalloc_types.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozjemalloc_types.h @@ -0,0 +1,151 @@ +/* -*- 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/. */ + +// Portions of this file were originally under the following license: +// +// Copyright (C) 2006-2008 Jason Evans . +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice(s), this list of conditions and the following disclaimer as +// the first lines of this file unmodified other than the possible +// addition of one or more copyright notices. +// 2. Redistributions in binary form must reproduce the above copyright +// notice(s), this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef _JEMALLOC_TYPES_H_ +#define _JEMALLOC_TYPES_H_ + +// grab size_t +#ifdef _MSC_VER +#include +#else +#include +#endif +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MALLOC_USABLE_SIZE_CONST_PTR +#define MALLOC_USABLE_SIZE_CONST_PTR const +#endif + +typedef MALLOC_USABLE_SIZE_CONST_PTR void* usable_ptr_t; + +typedef size_t arena_id_t; + +typedef struct arena_params_s { + size_t mMaxDirty; + +#ifdef __cplusplus + arena_params_s() : mMaxDirty(0) {} +#endif +} arena_params_t; + +// jemalloc_stats() is not a stable interface. When using jemalloc_stats_t, be +// sure that the compiled results of jemalloc.c are in sync with this header +// file. +typedef struct { + // Run-time configuration settings. + bool opt_junk; // Fill allocated memory with kAllocJunk? + bool opt_zero; // Fill allocated memory with 0x0? + size_t narenas; // Number of arenas. + size_t quantum; // Allocation quantum. + size_t small_max; // Max quantum-spaced allocation size. + size_t large_max; // Max sub-chunksize allocation size. + size_t chunksize; // Size of each virtual memory mapping. + size_t page_size; // Size of pages. + size_t dirty_max; // Max dirty pages per arena. + + // Current memory usage statistics. + size_t mapped; // Bytes mapped (not necessarily committed). + size_t allocated; // Bytes allocated (committed, in use by application). + size_t waste; // Bytes committed, not in use by the + // application, and not intentionally left + // unused (i.e., not dirty). + size_t page_cache; // Committed, unused pages kept around as a + // cache. (jemalloc calls these "dirty".) + size_t bookkeeping; // Committed bytes used internally by the + // allocator. + size_t bin_unused; // Bytes committed to a bin but currently unused. +} jemalloc_stats_t; + +enum PtrInfoTag { + // The pointer is not currently known to the allocator. + // 'addr' and 'size' are always 0. + TagUnknown, + + // The pointer is within a live allocation. + // 'addr' and 'size' describe the allocation. + TagLiveSmall, + TagLiveLarge, + TagLiveHuge, + + // The pointer is within a small freed allocation. + // 'addr' and 'size' describe the allocation. + TagFreedSmall, + + // The pointer is within a freed page. Details about the original + // allocation, including its size, are not available. + // 'addr' and 'size' describe the page. + TagFreedPageDirty, + TagFreedPageDecommitted, + TagFreedPageMadvised, + TagFreedPageZeroed, +}; + +// The information in jemalloc_ptr_info_t could be represented in a variety of +// ways. The chosen representation has the following properties. +// - The number of fields is minimized. +// - The 'tag' field unambiguously defines the meaning of the subsequent fields. +// Helper functions are used to group together related categories of tags. +typedef struct { + enum PtrInfoTag tag; + void* addr; // meaning depends on tag; see above + size_t size; // meaning depends on tag; see above +} jemalloc_ptr_info_t; + +static inline bool jemalloc_ptr_is_live(jemalloc_ptr_info_t* info) { + return info->tag == TagLiveSmall || info->tag == TagLiveLarge || + info->tag == TagLiveHuge; +} + +static inline bool jemalloc_ptr_is_freed(jemalloc_ptr_info_t* info) { + return info->tag == TagFreedSmall || info->tag == TagFreedPageDirty || + info->tag == TagFreedPageDecommitted || + info->tag == TagFreedPageMadvised || info->tag == TagFreedPageZeroed; +} + +static inline bool jemalloc_ptr_is_freed_page(jemalloc_ptr_info_t* info) { + return info->tag == TagFreedPageDirty || + info->tag == TagFreedPageDecommitted || + info->tag == TagFreedPageMadvised || info->tag == TagFreedPageZeroed; +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _JEMALLOC_TYPES_H_ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozmemory.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozmemory.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozmemory.h @@ -0,0 +1,64 @@ +/* -*- 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 mozmemory_h +#define mozmemory_h + +// This header is meant to be used when the following functions are +// necessary: +// - malloc_good_size (used to be called je_malloc_usable_in_advance) +// - jemalloc_stats +// - jemalloc_purge_freed_pages +// - jemalloc_free_dirty_pages +// - jemalloc_thread_local_arena +// - jemalloc_ptr_info + +#ifdef MALLOC_H +#include MALLOC_H +#endif +#include "mozmemory_wrap.h" +#include "mozilla/Attributes.h" +#include "mozilla/Types.h" +#include "mozjemalloc_types.h" + +#ifdef MOZ_MEMORY +// On OSX, malloc/malloc.h contains the declaration for malloc_good_size, +// which will call back in jemalloc, through the zone allocator so just use it. +#ifndef XP_DARWIN +MOZ_MEMORY_API size_t malloc_good_size_impl(size_t size); + +// Note: the MOZ_GLUE_IN_PROGRAM ifdef below is there to avoid -Werror turning +// the protective if into errors. MOZ_GLUE_IN_PROGRAM is what triggers MFBT_API +// to use weak imports. +static inline size_t _malloc_good_size(size_t size) { +#if defined(MOZ_GLUE_IN_PROGRAM) && !defined(IMPL_MFBT) + if (!malloc_good_size) return size; +#endif + return malloc_good_size_impl(size); +} + +#define malloc_good_size _malloc_good_size +#endif + +#define MALLOC_DECL(name, return_type, ...) \ + MOZ_JEMALLOC_API return_type name(__VA_ARGS__); +#define MALLOC_FUNCS MALLOC_FUNCS_JEMALLOC +#include "malloc_decls.h" + +#endif + +#define MALLOC_DECL(name, return_type, ...) \ + MOZ_JEMALLOC_API return_type name(__VA_ARGS__); +#define MALLOC_FUNCS MALLOC_FUNCS_ARENA +#include "malloc_decls.h" + +#ifdef __cplusplus +#define moz_create_arena() moz_create_arena_with_params(nullptr) +#else +#define moz_create_arena() moz_create_arena_with_params(NULL) +#endif + +#endif // mozmemory_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/mozmemory_wrap.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/mozmemory_wrap.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/mozmemory_wrap.h @@ -0,0 +1,170 @@ +/* -*- 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 mozmemory_wrap_h +#define mozmemory_wrap_h + +// This header contains #defines which tweak the names of various memory +// allocation functions. +// +// There are several types of functions related to memory allocation +// that are meant to be used publicly by the Gecko codebase: +// +// - malloc implementation functions: +// - malloc +// - posix_memalign +// - aligned_alloc +// - calloc +// - realloc +// - free +// - memalign +// - valloc +// - malloc_usable_size +// - malloc_good_size +// Some of these functions are specific to some systems, but for +// convenience, they are treated as being cross-platform, and available +// as such. +// +// - duplication functions: +// - strndup +// - strdup +// - wcsdup (Windows only) +// +// - jemalloc specific functions: +// - jemalloc_stats +// - jemalloc_purge_freed_pages +// - jemalloc_free_dirty_pages +// - jemalloc_thread_local_arena +// - jemalloc_ptr_info +// (these functions are native to mozjemalloc) +// +// These functions are all exported as part of libmozglue (see +// $(topsrcdir)/mozglue/build/Makefile.in), with a few implementation +// peculiarities: +// +// - On Windows, the malloc implementation functions are all prefixed with +// "je_", the duplication functions are prefixed with "wrap_", and jemalloc +// specific functions are left unprefixed. All these functions are however +// aliased when exporting them, such that the resulting mozglue.dll exports +// them unprefixed (see $(topsrcdir)/mozglue/build/mozglue.def.in). The +// prefixed malloc implementation and duplication functions are not +// exported. +// +// - On MacOSX, the system libc has a zone allocator, which allows us to +// hook custom malloc implementation functions without exporting them. +// However, since we want things in Firefox to skip the system zone +// allocator, the malloc implementation functions are all exported +// unprefixed, as well as duplication functions. +// Jemalloc-specific functions are also left unprefixed. +// +// - On Android all functions are left unprefixed. Additionally, +// C++ allocation functions (operator new/delete) are also exported and +// unprefixed. +// +// - On other systems (mostly Linux), all functions are left unprefixed. +// +// Only Android adds C++ allocation functions. +// +// Proper exporting of the various functions is done with the MOZ_MEMORY_API +// and MOZ_JEMALLOC_API macros. MOZ_MEMORY_API is meant to be used for malloc +// implementation and duplication functions, while MOZ_JEMALLOC_API is +// dedicated to jemalloc specific functions. +// +// +// All these functions are meant to be called with no prefix from Gecko code. +// In most cases, this is because that's how they are available at runtime. +// However, on Android, this relies on faulty.lib (the custom dynamic linker) +// resolving mozglue symbols before libc symbols, which is guaranteed by the +// way faulty.lib works (it respects the DT_NEEDED order, and libc always +// appears after mozglue ; which we double check when building anyways) +// +// +// Within libmozglue (when MOZ_MEMORY_IMPL is defined), all the functions +// should be suffixed with "_impl" both for declarations and use. +// That is, the implementation declaration for e.g. strdup would look like: +// char* strdup_impl(const char *) +// That implementation would call malloc by using "malloc_impl". + +#if defined(MOZ_MEMORY_IMPL) && !defined(IMPL_MFBT) +#ifdef MFBT_API // mozilla/Types.h was already included +# error mozmemory_wrap.h has to be included before mozilla/Types.h when MOZ_MEMORY_IMPL is set and IMPL_MFBT is not. +#endif +#define IMPL_MFBT +#endif + +#include "mozilla/Types.h" + +#ifndef MOZ_EXTERN_C +#ifdef __cplusplus +#define MOZ_EXTERN_C extern "C" +#else +#define MOZ_EXTERN_C +#endif +#endif + +#ifdef MOZ_MEMORY_IMPL +#define MOZ_JEMALLOC_API MOZ_EXTERN_C MFBT_API +#if defined(XP_WIN) +#define mozmem_malloc_impl(a) je_##a +#else +#define MOZ_MEMORY_API MOZ_EXTERN_C MFBT_API +#if defined(MOZ_WIDGET_ANDROID) +#define MOZ_WRAP_NEW_DELETE +#endif +#endif +#endif +#ifdef XP_WIN +#define mozmem_dup_impl(a) wrap_##a +#endif + +#if !defined(MOZ_MEMORY_IMPL) +#define MOZ_MEMORY_API MOZ_EXTERN_C MFBT_API +#define MOZ_JEMALLOC_API MOZ_EXTERN_C MFBT_API +#endif + +#ifndef MOZ_MEMORY_API +#define MOZ_MEMORY_API MOZ_EXTERN_C +#endif +#ifndef MOZ_JEMALLOC_API +#define MOZ_JEMALLOC_API MOZ_EXTERN_C +#endif + +#ifndef mozmem_malloc_impl +#define mozmem_malloc_impl(a) a +#endif +#ifndef mozmem_dup_impl +#define mozmem_dup_impl(a) a +#endif + +// Malloc implementation functions +#define malloc_impl mozmem_malloc_impl(malloc) +#define posix_memalign_impl mozmem_malloc_impl(posix_memalign) +#define aligned_alloc_impl mozmem_malloc_impl(aligned_alloc) +#define calloc_impl mozmem_malloc_impl(calloc) +#define realloc_impl mozmem_malloc_impl(realloc) +#define free_impl mozmem_malloc_impl(free) +#define memalign_impl mozmem_malloc_impl(memalign) +#define valloc_impl mozmem_malloc_impl(valloc) +#define malloc_usable_size_impl mozmem_malloc_impl(malloc_usable_size) +#define malloc_good_size_impl mozmem_malloc_impl(malloc_good_size) + +// Duplication functions +#define strndup_impl mozmem_dup_impl(strndup) +#define strdup_impl mozmem_dup_impl(strdup) +#ifdef XP_WIN +#define wcsdup_impl mozmem_dup_impl(wcsdup) +#define _aligned_malloc_impl mozmem_dup_impl(_aligned_malloc) +#endif + +// String functions +#ifdef ANDROID +// Bug 801571 and Bug 879668, libstagefright uses vasprintf, causing malloc()/ +// free() to be mismatched between bionic and mozglue implementation. +#define vasprintf_impl mozmem_dup_impl(vasprintf) +#define asprintf_impl mozmem_dup_impl(asprintf) +#endif + +#endif // mozmemory_wrap_h Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_darwin.cfg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_darwin.cfg +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_darwin.cfg @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#define PR_AF_INET6 30 /* same as AF_INET6 */ + +#ifdef __LITTLE_ENDIAN__ +#undef IS_BIG_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#else +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#endif + +#ifdef __LP64__ +#define IS_64 +#endif + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#undef HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS 1 + +#ifdef IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 +#define PR_BITS_PER_DWORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 +#define PR_BITS_PER_DWORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 +#define PR_ALIGN_OF_DWORD 8 + +#else /* IS_64 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#endif /* IS_64 */ + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ + Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_freebsd.cfg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_freebsd.cfg +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_freebsd.cfg @@ -0,0 +1,594 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef FREEBSD +#define FREEBSD +#endif + +#define PR_AF_INET6 28 /* same as AF_INET6 */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif + +#if defined(__i386__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__alpha__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#elif defined(__sparc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#elif defined(__ia64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#elif defined(__amd64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#elif defined(__powerpc64__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__powerpc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__aarch64__) + +#undef IS_BIG_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__arm__) + +#if defined(__ARMEB__) || defined(__ARM_BIG_ENDIAN__) +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#else +#undef IS_BIG_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#endif + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__mips64__) + +#if defined(__MIPSEB__) || defined(_MIPSEB) +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#else +#undef IS_BIG_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#endif + +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__mips__) + +#if defined(__MIPSEB__) || defined(_MIPSEB) +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#else +#undef IS_BIG_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#endif + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error "Unknown CPU architecture" + +#endif + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_linux.cfg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_linux.cfg +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_linux.cfg @@ -0,0 +1,1084 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* + * This file is used by not only Linux but also other glibc systems + * such as GNU/Hurd and GNU/k*BSD. + */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#if !defined(LINUX) && defined(__linux__) +#define LINUX +#endif + +#ifdef __FreeBSD_kernel__ +#define PR_AF_INET6 28 /* same as AF_INET6 */ +#elif defined(__GNU__) +#define PR_AF_INET6 26 /* same as AF_INET6 */ +#else +#define PR_AF_INET6 10 /* same as AF_INET6 */ +#endif + +#ifdef __powerpc64__ + +#ifdef __LITTLE_ENDIAN__ +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#else +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#endif +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__powerpc__) + +#ifdef __LITTLE_ENDIAN__ +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#else +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#endif + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__alpha) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__ia64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__x86_64__) + +#ifdef __ILP32__ + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#endif + +#elif defined(__mc68000__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 2 +#define PR_ALIGN_OF_LONG 2 +#define PR_ALIGN_OF_INT64 2 +#define PR_ALIGN_OF_FLOAT 2 +#define PR_ALIGN_OF_DOUBLE 2 +#define PR_ALIGN_OF_POINTER 2 +#define PR_ALIGN_OF_WORD 2 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__sparc__) && defined (__arch64__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__sparc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__i386__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__mips__) + +/* For _ABI64 */ +#include + +#ifdef __MIPSEB__ +#define IS_BIG_ENDIAN 1 +#undef IS_LITTLE_ENDIAN +#elif defined(__MIPSEL__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#else +#error "Unknown MIPS endianness." +#endif + +#if _MIPS_SIM == _ABI64 + +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else /* _ABI64 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#endif /* _ABI64 */ + +#elif defined(__arm__) + +#ifdef __ARMEB__ +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#elif defined(__ARMEL__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#else +#error "Unknown ARM endianness." +#endif + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__aarch64__) + +#ifdef __AARCH64EB__ +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#elif defined(__AARCH64EL__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#else +#error "Unknown Aarch64 endianness." +#endif +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__hppa__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__s390x__) + +#define IS_BIG_ENDIAN 1 +#undef IS_LITTLE_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__s390__) + +#define IS_BIG_ENDIAN 1 +#undef IS_LITTLE_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__sh__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__avr32__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__m32r__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__or1k__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error "Unknown CPU architecture" + +#endif + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#if PR_ALIGN_OF_DOUBLE == 8 +#define HAVE_ALIGNED_DOUBLES +#endif +#if PR_ALIGN_OF_INT64 == 8 +#define HAVE_ALIGNED_LONGLONGS +#endif + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_netbsd.cfg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_netbsd.cfg +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_netbsd.cfg @@ -0,0 +1,351 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef NETBSD +#define NETBSD +#endif + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif + +#if defined(__i386__) || defined(__arm32__) || defined(__ARMEL__) || \ + defined(__MIPSEL__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__sparc_v9__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#elif defined(__sparc__) || defined(__MIPSEB__) || defined(__ARMEB__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__alpha__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__amd64__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__powerpc__) || defined(__m68k__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error Must define constants for type sizes here. + +#endif + + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_openbsd.cfg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_openbsd.cfg +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_openbsd.cfg @@ -0,0 +1,353 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef OPENBSD +#define OPENBSD +#endif + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif + +#if defined(__i386__) || defined(__arm__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__amd64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#elif defined(__sparc_v9__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__sparc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__alpha__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__powerpc__) || defined(__m68k__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error Must define constants for type sizes here. + +#endif + + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_solaris.cfg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_solaris.cfg +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_solaris.cfg @@ -0,0 +1,171 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef SOLARIS +#define SOLARIS +#endif + +#define PR_AF_INET6 26 /* same as AF_INET6 */ + +#if defined(sparc) || defined(__sparc) +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_DOUBLE 8 +#if defined(__sparcv9) +#define IS_64 +#endif +#elif defined(__x86_64) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_DOUBLE 8 +#define IS_64 +#elif defined(i386) || defined(__i386) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_DOUBLE 4 +#else +#error unknown processor +#endif + +#ifdef IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_POINTER 8 + +#else /* IS_64 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_POINTER 4 + +#endif /* IS_64 */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* ifndef nspr_cpucfg___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_win95.cfg =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_win95.cfg +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/md/_win95.cfg @@ -0,0 +1,272 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_PC +#define XP_PC +#endif + +#ifndef WIN32 +#define WIN32 +#endif + +#ifndef WIN95 +#define WIN95 +#endif + +#define PR_AF_INET6 23 /* same as AF_INET6 */ + +#if defined(_M_IX86) || defined(_X86_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 5 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 4 +#define PR_ALIGN_OF_DWORD 8 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_WORD 64 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 6 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 8 +#define PR_ALIGN_OF_DWORD 8 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(_M_IA64) || defined(_IA64_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_WORD 64 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 6 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 8 +#define PR_ALIGN_OF_DWORD 8 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(_M_ARM) || defined(_ARM_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 5 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 4 +#define PR_ALIGN_OF_DWORD 8 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else /* defined(_M_IX86) || defined(_X86_) */ + +#error unknown processor architecture + +#endif /* defined(_M_IX86) || defined(_X86_) */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif + +#ifndef NO_NSPR_10_SUPPORT + +#define BYTES_PER_BYTE PR_BYTES_PER_BYTE +#define BYTES_PER_SHORT PR_BYTES_PER_SHORT +#define BYTES_PER_INT PR_BYTES_PER_INT +#define BYTES_PER_INT64 PR_BYTES_PER_INT64 +#define BYTES_PER_LONG PR_BYTES_PER_LONG +#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT +#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE +#define BYTES_PER_WORD PR_BYTES_PER_WORD +#define BYTES_PER_DWORD PR_BYTES_PER_DWORD + +#define BITS_PER_BYTE PR_BITS_PER_BYTE +#define BITS_PER_SHORT PR_BITS_PER_SHORT +#define BITS_PER_INT PR_BITS_PER_INT +#define BITS_PER_INT64 PR_BITS_PER_INT64 +#define BITS_PER_LONG PR_BITS_PER_LONG +#define BITS_PER_FLOAT PR_BITS_PER_FLOAT +#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE +#define BITS_PER_WORD PR_BITS_PER_WORD + +#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2 +#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2 +#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2 +#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2 +#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2 +#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2 +#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2 +#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2 + +#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT +#define ALIGN_OF_INT PR_ALIGN_OF_INT +#define ALIGN_OF_LONG PR_ALIGN_OF_LONG +#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64 +#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT +#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE +#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER +#define ALIGN_OF_WORD PR_ALIGN_OF_WORD + +#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2 +#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2 +#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2 + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/nspr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/nspr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/nspr.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef nspr_h___ +#define nspr_h___ + +#include "pratom.h" +#include "prbit.h" +#include "prclist.h" +#include "prcmon.h" +#include "prcvar.h" +#include "prdtoa.h" +#include "prenv.h" +#include "prerror.h" +#include "prinet.h" +#include "prinit.h" +#include "prinrval.h" +#include "prio.h" +#include "pripcsem.h" +#include "prlink.h" +#include "prlock.h" +#include "prlog.h" +#include "prlong.h" +#include "prmem.h" +#include "prmon.h" +#include "prmwait.h" +#include "prnetdb.h" +#include "prprf.h" +#include "prproces.h" +#include "prrng.h" +#include "prrwlock.h" +#include "prshm.h" +#include "prshma.h" +#include "prsystem.h" +#include "prthread.h" +#include "prtime.h" +#include "prtpool.h" +#include "prtrace.h" +#include "prtypes.h" + +#endif /* nspr_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plarena.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plarena.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plarena.h @@ -0,0 +1,327 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef plarena_h___ +#define plarena_h___ +/* + * Lifetime-based fast allocation, inspired by much prior art, including + * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes" + * David R. Hanson, Software -- Practice and Experience, Vol. 20(1). + * + * Also supports LIFO allocation (PL_ARENA_MARK/PL_ARENA_RELEASE). + */ +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +typedef struct PLArena PLArena; + +struct PLArena { + PLArena *next; /* next arena for this lifetime */ + PRUword base; /* aligned base address, follows this header */ + PRUword limit; /* one beyond last byte in arena */ + PRUword avail; /* points to next available byte */ +}; + +#ifdef PL_ARENAMETER +typedef struct PLArenaStats PLArenaStats; + +struct PLArenaStats { + PLArenaStats *next; /* next in arenaStats list */ + char *name; /* name for debugging */ + PRUint32 narenas; /* number of arenas in pool */ + PRUint32 nallocs; /* number of PL_ARENA_ALLOCATE() calls */ + PRUint32 nreclaims; /* number of reclaims from freeArenas */ + PRUint32 nmallocs; /* number of malloc() calls */ + PRUint32 ndeallocs; /* number of lifetime deallocations */ + PRUint32 ngrows; /* number of PL_ARENA_GROW() calls */ + PRUint32 ninplace; /* number of in-place growths */ + PRUint32 nreleases; /* number of PL_ARENA_RELEASE() calls */ + PRUint32 nfastrels; /* number of "fast path" releases */ + PRUint32 nbytes; /* total bytes allocated */ + PRUint32 maxalloc; /* maximum allocation size in bytes */ + PRFloat64 variance; /* size variance accumulator */ +}; +#endif + +typedef struct PLArenaPool PLArenaPool; + +struct PLArenaPool { + PLArena first; /* first arena in pool list */ + PLArena *current; /* arena from which to allocate space */ + PRUint32 arenasize; /* net exact size of a new arena */ + PRUword mask; /* alignment mask (power-of-2 - 1) */ +#ifdef PL_ARENAMETER + PLArenaStats stats; +#endif +}; + +/* + * WARNING: The PL_MAKE_MEM_ macros are for internal use by NSPR. Do NOT use + * them in your code. + * + * NOTE: Valgrind support to be added. + * + * The PL_MAKE_MEM_ macros are modeled after the MOZ_MAKE_MEM_ macros in + * Mozilla's mfbt/MemoryChecking.h. Only AddressSanitizer is supported now. + * + * Provides a common interface to the ASan (AddressSanitizer) and Valgrind + * functions used to mark memory in certain ways. In detail, the following + * three macros are provided: + * + * PL_MAKE_MEM_NOACCESS - Mark memory as unsafe to access (e.g. freed) + * PL_MAKE_MEM_UNDEFINED - Mark memory as accessible, with content undefined + * PL_MAKE_MEM_DEFINED - Mark memory as accessible, with content defined + * + * With Valgrind in use, these directly map to the three respective Valgrind + * macros. With ASan in use, the NOACCESS macro maps to poisoning the memory, + * while the UNDEFINED/DEFINED macros unpoison memory. + * + * With no memory checker available, all macros expand to the empty statement. + */ + +/* WARNING: PL_SANITIZE_ADDRESS is for internal use by this header. Do NOT + * define or test this macro in your code. + */ +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define PL_SANITIZE_ADDRESS 1 +#endif +#elif defined(__SANITIZE_ADDRESS__) +#define PL_SANITIZE_ADDRESS 1 +#endif + +#if defined(PL_SANITIZE_ADDRESS) + +/* These definitions are usually provided through the + * sanitizer/asan_interface.h header installed by ASan. + * See https://github.com/google/sanitizers/wiki/AddressSanitizerManualPoisoning + */ + +PR_IMPORT(void) __asan_poison_memory_region(void const volatile *addr, size_t size); +PR_IMPORT(void) __asan_unpoison_memory_region(void const volatile *addr, size_t size); + +#define PL_MAKE_MEM_NOACCESS(addr, size) \ + __asan_poison_memory_region((addr), (size)) + +#define PL_MAKE_MEM_UNDEFINED(addr, size) \ + __asan_unpoison_memory_region((addr), (size)) + +#define PL_MAKE_MEM_DEFINED(addr, size) \ + __asan_unpoison_memory_region((addr), (size)) + +#else + +#define PL_MAKE_MEM_NOACCESS(addr, size) +#define PL_MAKE_MEM_UNDEFINED(addr, size) +#define PL_MAKE_MEM_DEFINED(addr, size) + +#endif + +/* + * If the including .c file uses only one power-of-2 alignment, it may define + * PL_ARENA_CONST_ALIGN_MASK to the alignment mask and save a few instructions + * per ALLOCATE and GROW. + */ +#ifdef PL_ARENA_CONST_ALIGN_MASK +#define PL_ARENA_ALIGN(pool, n) (((PRUword)(n) + PL_ARENA_CONST_ALIGN_MASK) \ + & ~PL_ARENA_CONST_ALIGN_MASK) + +#define PL_INIT_ARENA_POOL(pool, name, size) \ + PL_InitArenaPool(pool, name, size, PL_ARENA_CONST_ALIGN_MASK + 1) +#else +#define PL_ARENA_ALIGN(pool, n) (((PRUword)(n) + (pool)->mask) & ~(pool)->mask) +#endif + +#define PL_ARENA_ALLOCATE(p, pool, nb) \ + PR_BEGIN_MACRO \ + PLArena *_a = (pool)->current; \ + PRUint32 _nb = PL_ARENA_ALIGN(pool, (PRUint32)nb); \ + PRUword _p = _a->avail; \ + if (_nb < (PRUint32)nb) { \ + _p = 0; \ + } else if (_nb > (_a->limit - _a->avail)) { \ + _p = (PRUword)PL_ArenaAllocate(pool, _nb); \ + } else { \ + _a->avail += _nb; \ + } \ + p = (void *)_p; \ + if (p) { \ + PL_MAKE_MEM_UNDEFINED(p, (PRUint32)nb); \ + PL_ArenaCountAllocation(pool, (PRUint32)nb); \ + } \ + PR_END_MACRO + +#define PL_ARENA_GROW(p, pool, size, incr) \ + PR_BEGIN_MACRO \ + PLArena *_a = (pool)->current; \ + PRUint32 _incr = PL_ARENA_ALIGN(pool, (PRUint32)incr); \ + if (_incr < (PRUint32)incr) { \ + p = NULL; \ + } else if (_a->avail == (PRUword)(p) + PL_ARENA_ALIGN(pool, size) && \ + _incr <= (_a->limit - _a->avail)) { \ + PL_MAKE_MEM_UNDEFINED((unsigned char *)(p) + size, (PRUint32)incr); \ + _a->avail += _incr; \ + PL_ArenaCountInplaceGrowth(pool, size, (PRUint32)incr); \ + } else { \ + p = PL_ArenaGrow(pool, p, size, (PRUint32)incr); \ + } \ + if (p) {\ + PL_ArenaCountGrowth(pool, size, (PRUint32)incr); \ + } \ + PR_END_MACRO + +#define PL_ARENA_MARK(pool) ((void *) (pool)->current->avail) +#define PR_UPTRDIFF(p,q) ((PRUword)(p) - (PRUword)(q)) + +#define PL_CLEAR_UNUSED_PATTERN(a, pattern) \ + PR_BEGIN_MACRO \ + PR_ASSERT((a)->avail <= (a)->limit); \ + PL_MAKE_MEM_UNDEFINED((void*)(a)->avail, (a)->limit - (a)->avail); \ + memset((void*)(a)->avail, (pattern), (a)->limit - (a)->avail); \ + PR_END_MACRO +#ifdef DEBUG +#define PL_FREE_PATTERN 0xDA +#define PL_CLEAR_UNUSED(a) PL_CLEAR_UNUSED_PATTERN((a), PL_FREE_PATTERN) +#define PL_CLEAR_ARENA(a) \ + PR_BEGIN_MACRO \ + PL_MAKE_MEM_UNDEFINED((void*)(a), (a)->limit - (PRUword)(a)); \ + memset((void*)(a), PL_FREE_PATTERN, (a)->limit - (PRUword)(a)); \ + PR_END_MACRO +#else +#define PL_CLEAR_UNUSED(a) +#define PL_CLEAR_ARENA(a) +#endif + +#define PL_ARENA_RELEASE(pool, mark) \ + PR_BEGIN_MACRO \ + char *_m = (char *)(mark); \ + PLArena *_a = (pool)->current; \ + if (PR_UPTRDIFF(_m, _a->base) <= PR_UPTRDIFF(_a->avail, _a->base)) { \ + _a->avail = (PRUword)PL_ARENA_ALIGN(pool, _m); \ + PL_CLEAR_UNUSED(_a); \ + PL_MAKE_MEM_NOACCESS((void*)_a->avail, _a->limit - _a->avail); \ + PL_ArenaCountRetract(pool, _m); \ + } else { \ + PL_ArenaRelease(pool, _m); \ + } \ + PL_ArenaCountRelease(pool, _m); \ + PR_END_MACRO + +#ifdef PL_ARENAMETER +#define PL_COUNT_ARENA(pool,op) ((pool)->stats.narenas op) +#else +#define PL_COUNT_ARENA(pool,op) +#endif + +#define PL_ARENA_DESTROY(pool, a, pnext) \ + PR_BEGIN_MACRO \ + PL_COUNT_ARENA(pool,--); \ + if ((pool)->current == (a)) (pool)->current = &(pool)->first; \ + *(pnext) = (a)->next; \ + PL_CLEAR_ARENA(a); \ + free(a); \ + (a) = 0; \ + PR_END_MACRO + +/* +** Initialize an arena pool with the given name for debugging and metering, +** with a minimum gross size per arena of size bytes. The net size per arena +** is smaller than the gross size by a header of four pointers plus any +** necessary padding for alignment. +** +** Note: choose a gross size that's a power of two to avoid the heap allocator +** rounding the size up. +**/ +PR_EXTERN(void) PL_InitArenaPool( + PLArenaPool *pool, const char *name, PRUint32 size, PRUint32 align); + +/* +** Finish using arenas, freeing all memory associated with them. +** NOTE: this function is now a no-op. If you want to free a single +** PLArenaPoolUse use PL_FreeArenaPool() or PL_FinishArenaPool(). +**/ +PR_EXTERN(void) PL_ArenaFinish(void); + +/* +** Free the arenas in pool. The user may continue to allocate from pool +** after calling this function. There is no need to call PL_InitArenaPool() +** again unless PL_FinishArenaPool(pool) has been called. +**/ +PR_EXTERN(void) PL_FreeArenaPool(PLArenaPool *pool); + +/* +** Free the arenas in pool and finish using it altogether. +**/ +PR_EXTERN(void) PL_FinishArenaPool(PLArenaPool *pool); + +/* +** Compact all of the arenas in a pool so that no space is wasted. +** NOT IMPLEMENTED. Do not use. +**/ +PR_EXTERN(void) PL_CompactArenaPool(PLArenaPool *pool); + +/* +** Friend functions used by the PL_ARENA_*() macros. +** +** WARNING: do not call these functions directly. Always use the +** PL_ARENA_*() macros. +**/ +PR_EXTERN(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb); + +PR_EXTERN(void *) PL_ArenaGrow( + PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr); + +PR_EXTERN(void) PL_ArenaRelease(PLArenaPool *pool, char *mark); + +/* +** memset contents of all arenas in pool to pattern +*/ +PR_EXTERN(void) PL_ClearArenaPool(PLArenaPool *pool, PRInt32 pattern); + +/* +** A function like malloc_size() or malloc_usable_size() that measures the +** size of a heap block. +*/ +typedef size_t (*PLMallocSizeFn)(const void *ptr); + +/* +** Measure all memory used by a PLArenaPool, excluding the PLArenaPool +** structure. +*/ +PR_EXTERN(size_t) PL_SizeOfArenaPoolExcludingPool( + const PLArenaPool *pool, PLMallocSizeFn mallocSizeOf); + +#ifdef PL_ARENAMETER + +#include + +PR_EXTERN(void) PL_ArenaCountAllocation(PLArenaPool *pool, PRUint32 nb); + +PR_EXTERN(void) PL_ArenaCountInplaceGrowth( + PLArenaPool *pool, PRUint32 size, PRUint32 incr); + +PR_EXTERN(void) PL_ArenaCountGrowth( + PLArenaPool *pool, PRUint32 size, PRUint32 incr); + +PR_EXTERN(void) PL_ArenaCountRelease(PLArenaPool *pool, char *mark); + +PR_EXTERN(void) PL_ArenaCountRetract(PLArenaPool *pool, char *mark); + +PR_EXTERN(void) PL_DumpArenaStats(FILE *fp); + +#else /* !PL_ARENAMETER */ + +#define PL_ArenaCountAllocation(ap, nb) /* nothing */ +#define PL_ArenaCountInplaceGrowth(ap, size, incr) /* nothing */ +#define PL_ArenaCountGrowth(ap, size, incr) /* nothing */ +#define PL_ArenaCountRelease(ap, mark) /* nothing */ +#define PL_ArenaCountRetract(ap, mark) /* nothing */ + +#endif /* !PL_ARENAMETER */ + +PR_END_EXTERN_C + +#endif /* plarena_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plarenas.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plarenas.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plarenas.h @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** PLArena-related declarations used to be split between plarenas.h and +** plarena.h. That split wasn't useful, so now all the declarations are in +** plarena.h. However, this file still exists so that any old code that +** includes it will still work. +**/ +#include "plarena.h" Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plbase64.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plbase64.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plbase64.h @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef _plbase64_h +#define _plbase64_h + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* + * PL_Base64Encode + * + * This routine encodes the data pointed to by the "src" parameter using the + * base64 algorithm, and returns a pointer to the result. If the "srclen" + * parameter is not zero, it specifies the length of the source data. If it + * is zero, the source data is assumed to be null-terminated, and PL_strlen + * is used to determine the source length. If the "dest" parameter is not + * null, it is assumed to point to a buffer of sufficient size (which may be + * calculated: ((srclen + 2)/3)*4) into which the encoded data is placed + * (without any termination). If the "dest" parameter is null, a buffer is + * allocated from the heap to hold the encoded data, and the result *will* + * be terminated with an extra null character. It is the caller's + * responsibility to free the result when it is allocated. A null is returned + * if the allocation fails. + * + * NOTE: when calculating ((srclen + 2)/3)*4), first ensure that + * srclen <= (PR_UINT32_MAX/4) * 3 + * to avoid PRUint32 overflow. + */ + +PR_EXTERN(char *) +PL_Base64Encode +( + const char *src, + PRUint32 srclen, + char *dest +); + +/* + * PL_Base64Decode + * + * This routine decodes the data pointed to by the "src" parameter using + * the base64 algorithm, and returns a pointer to the result. The source + * may either include or exclude any trailing '=' characters. If the + * "srclen" parameter is not zero, it specifies the length of the source + * data. If it is zero, PL_strlen will be used to determine the source + * length. If the "dest" parameter is not null, it is assumed to point to + * a buffer of sufficient size (which may be calculated: (srclen * 3)/4 + * when srclen includes the '=' characters) into which the decoded data + * is placed (without any termination). If the "dest" parameter is null, + * a buffer is allocated from the heap to hold the decoded data, and the + * result *will* be terminated with an extra null character. It is the + * caller's responsibility to free the result when it is allocated. A null + * is retuned if the allocation fails, or if the source is not well-coded. + * + * NOTE: when calculating (srclen * 3)/4, first ensure that + * srclen <= PR_UINT32_MAX/3 + * to avoid PRUint32 overflow. Alternatively, calculate + * (srclen/4) * 3 + ((srclen%4) * 3)/4 + * which is equivalent but doesn't overflow for any value of srclen. + */ + +PR_EXTERN(char *) +PL_Base64Decode +( + const char *src, + PRUint32 srclen, + char *dest +); + +PR_END_EXTERN_C + +#endif /* _plbase64_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plerror.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plerror.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plerror.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: plerror.h +** Description: Simple routine to print translate the calling thread's +** error numbers and print them. +*/ + +#if defined(PLERROR_H) +#else +#define PLERROR_H + +#include "prio.h" +#include "prtypes.h" + +PR_BEGIN_EXTERN_C +/* +** Print the messages to "syserr" prepending 'msg' if not NULL. +*/ +PR_EXTERN(void) PL_PrintError(const char *msg); + +/* +** Print the messages to specified output file prepending 'msg' if not NULL. +*/ +PR_EXTERN(void) PL_FPrintError(PRFileDesc *output, const char *msg); + +PR_END_EXTERN_C + +#endif /* defined(PLERROR_H) */ + +/* plerror.h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plgetopt.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plgetopt.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plgetopt.h @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: plgetopt.h +** Description: utilities to parse argc/argv +*/ + +#if defined(PLGETOPT_H_) +#else +#define PLGETOPT_H_ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +typedef struct PLOptionInternal PLOptionInternal; + +typedef enum +{ + PL_OPT_OK, /* all's well with the option */ + PL_OPT_EOL, /* end of options list */ + PL_OPT_BAD /* invalid option (and value) */ +} PLOptStatus; + +typedef struct PLLongOpt +{ + const char * longOptName; /* long option name string */ + PRIntn longOption; /* value put in PLOptState for this option. */ + PRBool valueRequired; /* If option name not followed by '=', */ + /* value is the next argument from argv. */ +} PLLongOpt; + +typedef struct PLOptState +{ + char option; /* the name of the option */ + const char *value; /* the value of that option | NULL */ + + PLOptionInternal *internal; /* private processing state */ + + PRIntn longOption; /* value from PLLongOpt put here */ + PRIntn longOptIndex; /* index into caller's array of PLLongOpts */ +} PLOptState; + +/* + * PL_CreateOptState + * + * The argument "options" points to a string of single-character option + * names. Option names that may have an option argument value must be + * followed immediately by a ':' character. + */ +PR_EXTERN(PLOptState*) PL_CreateOptState( + PRIntn argc, char **argv, const char *options); + +/* + * PL_CreateLongOptState + * + * Alternative to PL_CreateOptState. + * Allows caller to specify BOTH a string of single-character option names, + * AND an array of structures describing "long" (keyword) option names. + * The array is terminated by a structure in which longOptName is NULL. + * Long option values (arguments) may always be given as "--name=value". + * If PLLongOpt.valueRequired is not PR_FALSE, and the option name was not + * followed by '=' then the next argument from argv is taken as the value. + */ +PR_EXTERN(PLOptState*) PL_CreateLongOptState( + PRIntn argc, char **argv, const char *options, + const PLLongOpt *longOpts); +/* + * PL_DestroyOptState + * + * Call this to destroy the PLOptState returned from PL_CreateOptState or + * PL_CreateLongOptState. + */ +PR_EXTERN(void) PL_DestroyOptState(PLOptState *opt); + +/* + * PL_GetNextOpt + * + * When this function returns PL_OPT_OK, + * - opt->option will hold the single-character option name that was parsed, + * or zero. + * When opt->option is zero, the token parsed was either a "long" (keyword) + * option or a positional parameter. + * For a positional parameter, + * - opt->longOptIndex will contain -1, and + * - opt->value will point to the positional parameter string. + * For a long option name, + * - opt->longOptIndex will contain the non-negative index of the + * PLLongOpt structure in the caller's array of PLLongOpt structures + * corresponding to the long option name, and + * For a single-character or long option, + * - opt->longOption will contain the value of the single-character option + * name, or the value of the longOption from the PLLongOpt structure + * for that long option. See notes below. + * - opt->value will point to the argument option string, or will + * be NULL if option does not require argument. If option requires + * argument but it is not provided, PL_OPT_BAD is returned. + * When opt->option is non-zero, + * - opt->longOptIndex will be -1 + * When this function returns PL_OPT_EOL, or PL_OPT_BAD, the contents of + * opt are undefined. + * + * Notes: It is possible to ignore opt->option, and always look at + * opt->longOption instead. opt->longOption will contain the same value + * as opt->option for single-character option names, and will contain the + * value of longOption from the PLLongOpt structure for long option names. + * This means that it is possible to equivalence long option names to + * single character names by giving the longOption in the PLLongOpt struct + * the same value as the single-character option name. + * For long options that are NOT intended to be equivalent to any single- + * character option, the longOption value should be chosen to not match + * any possible single character name. It might be advisable to choose + * longOption values greater than 0xff for such long options. + */ +PR_EXTERN(PLOptStatus) PL_GetNextOpt(PLOptState *opt); + +PR_END_EXTERN_C + +#endif /* defined(PLGETOPT_H_) */ + +/* plgetopt.h */ + Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plhash.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plhash.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plhash.h @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef plhash_h___ +#define plhash_h___ +/* + * API to portable hash table code. + */ +#include +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +typedef struct PLHashEntry PLHashEntry; +typedef struct PLHashTable PLHashTable; +typedef PRUint32 PLHashNumber; +#define PL_HASH_BITS 32 /* Number of bits in PLHashNumber */ +typedef PLHashNumber (PR_CALLBACK *PLHashFunction)(const void *key); +typedef PRIntn (PR_CALLBACK *PLHashComparator)(const void *v1, const void *v2); + +typedef PRIntn (PR_CALLBACK *PLHashEnumerator)(PLHashEntry *he, PRIntn i, void *arg); + +/* Flag bits in PLHashEnumerator's return value */ +#define HT_ENUMERATE_NEXT 0 /* continue enumerating entries */ +#define HT_ENUMERATE_STOP 1 /* stop enumerating entries */ +#define HT_ENUMERATE_REMOVE 2 /* remove and free the current entry */ +#define HT_ENUMERATE_UNHASH 4 /* just unhash the current entry */ + +typedef struct PLHashAllocOps { + void * (PR_CALLBACK *allocTable)(void *pool, PRSize size); + void (PR_CALLBACK *freeTable)(void *pool, void *item); + PLHashEntry * (PR_CALLBACK *allocEntry)(void *pool, const void *key); + void (PR_CALLBACK *freeEntry)(void *pool, PLHashEntry *he, PRUintn flag); +} PLHashAllocOps; + +#define HT_FREE_VALUE 0 /* just free the entry's value */ +#define HT_FREE_ENTRY 1 /* free value and entire entry */ + +struct PLHashEntry { + PLHashEntry *next; /* hash chain linkage */ + PLHashNumber keyHash; /* key hash function result */ + const void *key; /* ptr to opaque key */ + void *value; /* ptr to opaque value */ +}; + +struct PLHashTable { + PLHashEntry **buckets; /* vector of hash buckets */ + PRUint32 nentries; /* number of entries in table */ + PRUint32 shift; /* multiplicative hash shift */ + PLHashFunction keyHash; /* key hash function */ + PLHashComparator keyCompare; /* key comparison function */ + PLHashComparator valueCompare; /* value comparison function */ + const PLHashAllocOps *allocOps; /* allocation operations */ + void *allocPriv; /* allocation private data */ +#ifdef HASHMETER + PRUint32 nlookups; /* total number of lookups */ + PRUint32 nsteps; /* number of hash chains traversed */ + PRUint32 ngrows; /* number of table expansions */ + PRUint32 nshrinks; /* number of table contractions */ +#endif +}; + +/* + * Create a new hash table. + * If allocOps is null, use default allocator ops built on top of malloc(). + */ +PR_EXTERN(PLHashTable *) +PL_NewHashTable(PRUint32 numBuckets, PLHashFunction keyHash, + PLHashComparator keyCompare, PLHashComparator valueCompare, + const PLHashAllocOps *allocOps, void *allocPriv); + +PR_EXTERN(void) +PL_HashTableDestroy(PLHashTable *ht); + +/* Higher level access methods */ +PR_EXTERN(PLHashEntry *) +PL_HashTableAdd(PLHashTable *ht, const void *key, void *value); + +PR_EXTERN(PRBool) +PL_HashTableRemove(PLHashTable *ht, const void *key); + +PR_EXTERN(void *) +PL_HashTableLookup(PLHashTable *ht, const void *key); + +PR_EXTERN(void *) +PL_HashTableLookupConst(PLHashTable *ht, const void *key); + +PR_EXTERN(PRIntn) +PL_HashTableEnumerateEntries(PLHashTable *ht, PLHashEnumerator f, void *arg); + +/* General-purpose C string hash function. */ +PR_EXTERN(PLHashNumber) +PL_HashString(const void *key); + +/* Compare strings using strcmp(), return true if equal. */ +PR_EXTERN(PRIntn) +PL_CompareStrings(const void *v1, const void *v2); + +/* Stub function just returns v1 == v2 */ +PR_EXTERN(PRIntn) +PL_CompareValues(const void *v1, const void *v2); + +/* Low level access methods */ +PR_EXTERN(PLHashEntry **) +PL_HashTableRawLookup(PLHashTable *ht, PLHashNumber keyHash, const void *key); + +PR_EXTERN(PLHashEntry **) +PL_HashTableRawLookupConst(PLHashTable *ht, PLHashNumber keyHash, + const void *key); + +PR_EXTERN(PLHashEntry *) +PL_HashTableRawAdd(PLHashTable *ht, PLHashEntry **hep, PLHashNumber keyHash, + const void *key, void *value); + +PR_EXTERN(void) +PL_HashTableRawRemove(PLHashTable *ht, PLHashEntry **hep, PLHashEntry *he); + +/* This can be trivially implemented using PL_HashTableEnumerateEntries. */ +PR_EXTERN(PRIntn) +PL_HashTableDump(PLHashTable *ht, PLHashEnumerator dump, FILE *fp); + +PR_END_EXTERN_C + +#endif /* plhash_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plstr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plstr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/plstr.h @@ -0,0 +1,437 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef _plstr_h +#define _plstr_h + +/* + * plstr.h + * + * This header file exports the API to the NSPR portable library or string- + * handling functions. + * + * This API was not designed as an "optimal" or "ideal" string library; it + * was based on the good ol' unix string.3 functions, and was written to + * + * 1) replace the libc functions, for cross-platform consistency, + * 2) complete the API on platforms lacking common functions (e.g., + * strcase*), and + * 3) to implement some obvious "closure" functions that I've seen + * people hacking around in our code. + * + * Point number three largely means that most functions have an "strn" + * limited-length version, and all comparison routines have a non-case- + * sensitive version available. + */ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C +/* + * PL_strlen + * + * Returns the length of the provided string, not including the trailing '\0'. + */ + +PR_EXTERN(PRUint32) +PL_strlen(const char *str); + +/* + * PL_strnlen + * + * Returns the length of the provided string, not including the trailing '\0', + * up to the indicated maximum. The string will not be examined beyond the + * maximum; if no terminating '\0' is found, the maximum will be returned. + */ + +PR_EXTERN(PRUint32) +PL_strnlen(const char *str, PRUint32 max); + +/* + * PL_strcpy + * + * Copies the source string, up to and including the trailing '\0', into the + * destination buffer. It does not (can not) verify that the destination + * buffer is large enough. It returns the "dest" argument. + */ + +PR_EXTERN(char *) +PL_strcpy(char *dest, const char *src); + +/* + * PL_strncpy + * + * Copies the source string into the destination buffer, up to and including + * the trailing '\0' or up to and including the max'th character, whichever + * comes first. It does not (can not) verify that the destination buffer is + * large enough. If the source string is longer than the maximum length, + * the result will *not* be null-terminated (JLRU). + */ + +PR_EXTERN(char *) +PL_strncpy(char *dest, const char *src, PRUint32 max); + +/* + * PL_strncpyz + * + * Copies the source string into the destination buffer, up to and including + * the trailing '\0' or up but not including the max'th character, whichever + * comes first. It does not (can not) verify that the destination buffer is + * large enough. The destination string is always terminated with a '\0', + * unlike the traditional libc implementation. It returns the "dest" argument. + * + * NOTE: If you call this with a source "abcdefg" and a max of 5, the + * destination will end up with "abcd\0" (i.e., its strlen length will be 4)! + * + * This means you can do this: + * + * char buffer[ SOME_SIZE ]; + * PL_strncpyz(buffer, src, sizeof(buffer)); + * + * and the result will be properly terminated. + */ + +PR_EXTERN(char *) +PL_strncpyz(char *dest, const char *src, PRUint32 max); + +/* + * PL_strdup + * + * Returns a pointer to a malloc'd extent of memory containing a duplicate + * of the argument string. The size of the allocated extent is one greater + * than the length of the argument string, because of the terminator. A + * null argument, like a zero-length argument, will result in a pointer to + * a one-byte extent containing the null value. This routine returns null + * upon malloc failure. + */ + +PR_EXTERN(char *) +PL_strdup(const char *s); + +/* + * PL_strfree + * + * Free memory allocated by PL_strdup + */ + +PR_EXTERN(void) +PL_strfree(char *s); + +/* + * PL_strndup + * + * Returns a pointer to a malloc'd extent of memory containing a duplicate + * of the argument string, up to the maximum specified. If the argument + * string has a length greater than the value of the specified maximum, the + * return value will be a pointer to an extent of memory of length one + * greater than the maximum specified. A null string, a zero-length string, + * or a zero maximum will all result in a pointer to a one-byte extent + * containing the null value. This routine returns null upon malloc failure. + */ + +PR_EXTERN(char *) +PL_strndup(const char *s, PRUint32 max); + +/* + * PL_strcat + * + * Appends a copy of the string pointed to by the second argument to the + * end of the string pointed to by the first. The destination buffer is + * not (can not be) checked for sufficient size. A null destination + * argument returns null; otherwise, the first argument is returned. + */ + +PR_EXTERN(char *) +PL_strcat(char *dst, const char *src); + +/* + * PL_strncat + * + * Appends a copy of the string pointed to by the second argument, up to + * the maximum size specified, to the end of the string pointed to by the + * first. The destination buffer is not (can not be) checked for sufficient + * size. A null destination argument returns null; otherwise, the first + * argument is returned. If the maximum size limits the copy, then the + * result will *not* be null-terminated (JLRU). A null destination + * returns null; otherwise, the destination argument is returned. + */ + +PR_EXTERN(char *) +PL_strncat(char *dst, const char *src, PRUint32 max); + +/* + * PL_strcatn + * + * Appends a copy of the string pointed to by the third argument, to the + * end of the string pointed to by the first. The second argument specifies + * the maximum size of the destination buffer, including the null termination. + * If the existing string in dst is longer than the max, no action is taken. + * The resulting string will be null-terminated. A null destination returns + * null; otherwise, the destination argument is returned. + */ + +PR_EXTERN(char *) +PL_strcatn(char *dst, PRUint32 max, const char *src); + +/* + * PL_strcmp + * + * Returns an integer, the sign of which -- positive, zero, or negative -- + * reflects the lexical sorting order of the two strings indicated. The + * result is positive if the first string comes after the second. The + * NSPR implementation is not i18n. + */ + +PR_EXTERN(PRIntn) +PL_strcmp(const char *a, const char *b); + +/* + * PL_strncmp + * + * Returns an integer, the sign of which -- positive, zero, or negative -- + * reflects the lexical sorting order of the two strings indicated, up to + * the maximum specified. The result is positive if the first string comes + * after the second. The NSPR implementation is not i18n. If the maximum + * is zero, only the existance or non-existance (pointer is null) of the + * strings is compared. + */ + +PR_EXTERN(PRIntn) +PL_strncmp(const char *a, const char *b, PRUint32 max); + +/* + * PL_strcasecmp + * + * Returns an integer, the sign of which -- positive, zero or negative -- + * reflects the case-insensitive lexical sorting order of the two strings + * indicated. The result is positive if the first string comes after the + * second. The NSPR implementation is not i18n. + */ + +PR_EXTERN(PRIntn) +PL_strcasecmp(const char *a, const char *b); + +/* + * PL_strncasecmp + * + * Returns an integer, the sign of which -- positive, zero or negative -- + * reflects the case-insensitive lexical sorting order of the first n characters + * of the two strings indicated. The result is positive if the first string comes + * after the second. The NSPR implementation is not i18n. + */ + +PR_EXTERN(PRIntn) +PL_strncasecmp(const char *a, const char *b, PRUint32 max); + +/* + * PL_strchr + * + * Returns a pointer to the first instance of the specified character in the + * provided string. It returns null if the character is not found, or if the + * provided string is null. The character may be the null character. + */ + +PR_EXTERN(char *) +PL_strchr(const char *s, char c); + +/* + * PL_strrchr + * + * Returns a pointer to the last instance of the specified character in the + * provided string. It returns null if the character is not found, or if the + * provided string is null. The character may be the null character. + */ + +PR_EXTERN(char *) +PL_strrchr(const char *s, char c); + +/* + * PL_strnchr + * + * Returns a pointer to the first instance of the specified character within the + * first n characters of the provided string. It returns null if the character + * is not found, or if the provided string is null. The character may be the + * null character. + */ + +PR_EXTERN(char *) +PL_strnchr(const char *s, char c, PRUint32 n); + +/* + * PL_strnrchr + * + * Returns a pointer to the last instance of the specified character within the + * first n characters of the provided string. It returns null if the character is + * not found, or if the provided string is null. The character may be the null + * character. + */ + +PR_EXTERN(char *) +PL_strnrchr(const char *s, char c, PRUint32 n); + +/* + * NOTE: Looking for strcasechr, strcaserchr, strncasechr, or strncaserchr? + * Use strpbrk, strprbrk, strnpbrk or strnprbrk. + */ + +/* + * PL_strpbrk + * + * Returns a pointer to the first instance in the first string of any character + * (not including the terminating null character) of the second string. It returns + * null if either string is null. + */ + +PR_EXTERN(char *) +PL_strpbrk(const char *s, const char *list); + +/* + * PL_strprbrk + * + * Returns a pointer to the last instance in the first string of any character + * (not including the terminating null character) of the second string. It returns + * null if either string is null. + */ + +PR_EXTERN(char *) +PL_strprbrk(const char *s, const char *list); + +/* + * PL_strnpbrk + * + * Returns a pointer to the first instance (within the first n characters) of any + * character (not including the terminating null character) of the second string. + * It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strnpbrk(const char *s, const char *list, PRUint32 n); + +/* + * PL_strnprbrk + * + * Returns a pointer to the last instance (within the first n characters) of any + * character (not including the terminating null character) of the second string. + * It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strnprbrk(const char *s, const char *list, PRUint32 n); + +/* + * PL_strstr + * + * Returns a pointer to the first instance of the little string within the + * big one. It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strstr(const char *big, const char *little); + +/* + * PL_strrstr + * + * Returns a pointer to the last instance of the little string within the big one. + * It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strrstr(const char *big, const char *little); + +/* + * PL_strnstr + * + * Returns a pointer to the first instance of the little string within the first + * n characters of the big one. It returns null if either string is null. It + * returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strnstr(const char *big, const char *little, PRUint32 n); + +/* + * PL_strnrstr + * + * Returns a pointer to the last instance of the little string within the first + * n characters of the big one. It returns null if either string is null. It + * returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strnrstr(const char *big, const char *little, PRUint32 max); + +/* + * PL_strcasestr + * + * Returns a pointer to the first instance of the little string within the big one, + * ignoring case. It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strcasestr(const char *big, const char *little); + +/* + * PL_strcaserstr + * + * Returns a pointer to the last instance of the little string within the big one, + * ignoring case. It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strcaserstr(const char *big, const char *little); + +/* + * PL_strncasestr + * + * Returns a pointer to the first instance of the little string within the first + * n characters of the big one, ignoring case. It returns null if either string is + * null. It returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strncasestr(const char *big, const char *little, PRUint32 max); + +/* + * PL_strncaserstr + * + * Returns a pointer to the last instance of the little string within the first + * n characters of the big one, ignoring case. It returns null if either string is + * null. It returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strncaserstr(const char *big, const char *little, PRUint32 max); + +/* + * PL_strtok_r + * + * Splits the string s1 into tokens, separated by one or more characters + * from the separator string s2. The argument lasts points to a + * user-supplied char * pointer in which PL_strtok_r stores information + * for it to continue scanning the same string. + * + * In the first call to PL_strtok_r, s1 points to a string and the value + * of *lasts is ignored. PL_strtok_r returns a pointer to the first + * token, writes '\0' into the character following the first token, and + * updates *lasts. + * + * In subsequent calls, s1 is null and lasts must stay unchanged from the + * previous call. The separator string s2 may be different from call to + * call. PL_strtok_r returns a pointer to the next token in s1. When no + * token remains in s1, PL_strtok_r returns null. + */ + +PR_EXTERN(char *) +PL_strtok_r(char *s1, const char *s2, char **lasts); + +/* + * Things not (yet?) included: strspn/strcspn, strsep. + * memchr, memcmp, memcpy, memccpy, index, rindex, bcmp, bcopy, bzero. + * Any and all i18n/l10n stuff. + */ + +PR_END_EXTERN_C + +#endif /* _plstr_h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/pratom.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/pratom.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/pratom.h @@ -0,0 +1,198 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* GLOBAL FUNCTIONS: +** DESCRIPTION: +** PR Atomic operations +*/ + +#ifndef pratom_h___ +#define pratom_h___ + +#include "prtypes.h" +#include "prlock.h" + +PR_BEGIN_EXTERN_C + +/* +** FUNCTION: PR_AtomicIncrement +** DESCRIPTION: +** Atomically increment a 32 bit value. +** INPUTS: +** val: a pointer to the value to increment +** RETURN: +** the returned value is the result of the increment +*/ +NSPR_API(PRInt32) PR_AtomicIncrement(PRInt32 *val); + +/* +** FUNCTION: PR_AtomicDecrement +** DESCRIPTION: +** Atomically decrement a 32 bit value. +** INPUTS: +** val: a pointer to the value to decrement +** RETURN: +** the returned value is the result of the decrement +*/ +NSPR_API(PRInt32) PR_AtomicDecrement(PRInt32 *val); + +/* +** FUNCTION: PR_AtomicSet +** DESCRIPTION: +** Atomically set a 32 bit value. +** INPUTS: +** val: A pointer to a 32 bit value to be set +** newval: The newvalue to assign to val +** RETURN: +** Returns the prior value +*/ +NSPR_API(PRInt32) PR_AtomicSet(PRInt32 *val, PRInt32 newval); + +/* +** FUNCTION: PR_AtomicAdd +** DESCRIPTION: +** Atomically add a 32 bit value. +** INPUTS: +** ptr: a pointer to the value to increment +** val: value to be added +** RETURN: +** the returned value is the result of the addition +*/ +NSPR_API(PRInt32) PR_AtomicAdd(PRInt32 *ptr, PRInt32 val); + +/* +** MACRO: PR_ATOMIC_INCREMENT +** MACRO: PR_ATOMIC_DECREMENT +** MACRO: PR_ATOMIC_SET +** MACRO: PR_ATOMIC_ADD +** DESCRIPTION: +** Macro versions of the atomic operations. They may be implemented +** as compiler intrinsics. +** +** IMPORTANT NOTE TO NSPR MAINTAINERS: +** Implement these macros with compiler intrinsics only on platforms +** where the PR_AtomicXXX functions are truly atomic (i.e., where the +** configuration macro _PR_HAVE_ATOMIC_OPS is defined). Otherwise, +** the macros and functions won't be compatible and can't be used +** interchangeably. +*/ +#if defined(_WIN32) && !defined(_WIN32_WCE) && \ + (!defined(_MSC_VER) || (_MSC_VER >= 1310)) + +#include + +#ifdef _MSC_VER +#pragma intrinsic(_InterlockedIncrement) +#pragma intrinsic(_InterlockedDecrement) +#pragma intrinsic(_InterlockedExchange) +#pragma intrinsic(_InterlockedExchangeAdd) +#endif + +#define PR_ATOMIC_INCREMENT(val) _InterlockedIncrement((long volatile *)(val)) +#define PR_ATOMIC_DECREMENT(val) _InterlockedDecrement((long volatile *)(val)) +#define PR_ATOMIC_SET(val, newval) \ + _InterlockedExchange((long volatile *)(val), (long)(newval)) +#define PR_ATOMIC_ADD(ptr, val) \ + (_InterlockedExchangeAdd((long volatile *)(ptr), (long)(val)) + (val)) + +#elif ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && \ + ((defined(__APPLE__) && \ + (defined(__ppc__) || defined(__i386__) || defined(__x86_64__))) || \ + (defined(__linux__) && \ + ((defined(__i386__) && \ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) || \ + defined(__ia64__) || defined(__x86_64__) || \ + defined(__powerpc__) || \ + (defined(__arm__) && \ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) || \ + defined(__aarch64__) || defined(__alpha) || \ + (defined(__mips__) && \ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4))))) + +/* + * Because the GCC manual warns that some processors may support + * reduced functionality of __sync_lock_test_and_set, we test for the + * processors that we believe support a full atomic exchange operation. + */ + +#define PR_ATOMIC_INCREMENT(val) __sync_add_and_fetch(val, 1) +#define PR_ATOMIC_DECREMENT(val) __sync_sub_and_fetch(val, 1) +#define PR_ATOMIC_SET(val, newval) __sync_lock_test_and_set(val, newval) +#define PR_ATOMIC_ADD(ptr, val) __sync_add_and_fetch(ptr, val) + +#else + +#define PR_ATOMIC_INCREMENT(val) PR_AtomicIncrement(val) +#define PR_ATOMIC_DECREMENT(val) PR_AtomicDecrement(val) +#define PR_ATOMIC_SET(val, newval) PR_AtomicSet(val, newval) +#define PR_ATOMIC_ADD(ptr, val) PR_AtomicAdd(ptr, val) + +#endif + +/* +** LIFO linked-list (stack) +*/ +typedef struct PRStackElemStr PRStackElem; + +struct PRStackElemStr { + PRStackElem *prstk_elem_next; /* next pointer MUST be at offset 0; + assembly language code relies on this */ +}; + +typedef struct PRStackStr PRStack; + +/* +** FUNCTION: PR_CreateStack +** DESCRIPTION: +** Create a stack, a LIFO linked list +** INPUTS: +** stack_name: a pointer to string containing the name of the stack +** RETURN: +** A pointer to the created stack, if successful, else NULL. +*/ +NSPR_API(PRStack *) PR_CreateStack(const char *stack_name); + +/* +** FUNCTION: PR_StackPush +** DESCRIPTION: +** Push an element on the top of the stack +** INPUTS: +** stack: pointer to the stack +** stack_elem: pointer to the stack element +** RETURN: +** None +*/ +NSPR_API(void) PR_StackPush(PRStack *stack, PRStackElem *stack_elem); + +/* +** FUNCTION: PR_StackPop +** DESCRIPTION: +** Remove the element on the top of the stack +** INPUTS: +** stack: pointer to the stack +** RETURN: +** A pointer to the stack element removed from the top of the stack, +** if non-empty, +** else NULL +*/ +NSPR_API(PRStackElem *) PR_StackPop(PRStack *stack); + +/* +** FUNCTION: PR_DestroyStack +** DESCRIPTION: +** Destroy the stack +** INPUTS: +** stack: pointer to the stack +** RETURN: +** PR_SUCCESS - if successfully deleted +** PR_FAILURE - if the stack is not empty +** PR_GetError will return +** PR_INVALID_STATE_ERROR - stack is not empty +*/ +NSPR_API(PRStatus) PR_DestroyStack(PRStack *stack); + +PR_END_EXTERN_C + +#endif /* pratom_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prbit.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prbit.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prbit.h @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prbit_h___ +#define prbit_h___ + +#include "prtypes.h" +PR_BEGIN_EXTERN_C + +/* +** Replace compare/jump/add/shift sequence with compiler built-in/intrinsic +** functions. +*/ +#if defined(_WIN32) && (_MSC_VER >= 1300) && \ + (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM)) +# include +# pragma intrinsic(_BitScanForward,_BitScanReverse) + __forceinline static int __prBitScanForward32(unsigned int val) + { + unsigned long idx; + _BitScanForward(&idx, (unsigned long)val); + return( (int)idx ); + } + __forceinline static int __prBitScanReverse32(unsigned int val) + { + unsigned long idx; + _BitScanReverse(&idx, (unsigned long)val); + return( (int)(31-idx) ); + } +# define pr_bitscan_ctz32(val) __prBitScanForward32(val) +# define pr_bitscan_clz32(val) __prBitScanReverse32(val) +# define PR_HAVE_BUILTIN_BITSCAN32 +#elif ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && \ + (defined(__i386__) || defined(__x86_64__) || defined(__arm__)) +# define pr_bitscan_ctz32(val) __builtin_ctz(val) +# define pr_bitscan_clz32(val) __builtin_clz(val) +# define PR_HAVE_BUILTIN_BITSCAN32 +#endif /* MSVC || GCC */ + +/* +** A prbitmap_t is a long integer that can be used for bitmaps +*/ +typedef unsigned long prbitmap_t; + +#define PR_TEST_BIT(_map,_bit) \ + ((_map)[(_bit)>>PR_BITS_PER_LONG_LOG2] & (1L << ((_bit) & (PR_BITS_PER_LONG-1)))) +#define PR_SET_BIT(_map,_bit) \ + ((_map)[(_bit)>>PR_BITS_PER_LONG_LOG2] |= (1L << ((_bit) & (PR_BITS_PER_LONG-1)))) +#define PR_CLEAR_BIT(_map,_bit) \ + ((_map)[(_bit)>>PR_BITS_PER_LONG_LOG2] &= ~(1L << ((_bit) & (PR_BITS_PER_LONG-1)))) + +/* +** Compute the log of the least power of 2 greater than or equal to n +*/ +NSPR_API(PRIntn) PR_CeilingLog2(PRUint32 i); + +/* +** Compute the log of the greatest power of 2 less than or equal to n +*/ +NSPR_API(PRIntn) PR_FloorLog2(PRUint32 i); + +/* +** Macro version of PR_CeilingLog2: Compute the log of the least power of +** 2 greater than or equal to _n. The result is returned in _log2. +*/ +#ifdef PR_HAVE_BUILTIN_BITSCAN32 +#define PR_CEILING_LOG2(_log2,_n) \ + PR_BEGIN_MACRO \ + PRUint32 j_ = (PRUint32)(_n); \ + (_log2) = (j_ <= 1 ? 0 : 32 - pr_bitscan_clz32(j_ - 1)); \ + PR_END_MACRO +#else +#define PR_CEILING_LOG2(_log2,_n) \ + PR_BEGIN_MACRO \ + PRUint32 j_ = (PRUint32)(_n); \ + (_log2) = 0; \ + if ((j_) & ((j_)-1)) \ + (_log2) += 1; \ + if ((j_) >> 16) \ + (_log2) += 16, (j_) >>= 16; \ + if ((j_) >> 8) \ + (_log2) += 8, (j_) >>= 8; \ + if ((j_) >> 4) \ + (_log2) += 4, (j_) >>= 4; \ + if ((j_) >> 2) \ + (_log2) += 2, (j_) >>= 2; \ + if ((j_) >> 1) \ + (_log2) += 1; \ + PR_END_MACRO +#endif /* PR_HAVE_BUILTIN_BITSCAN32 */ + +/* +** Macro version of PR_FloorLog2: Compute the log of the greatest power of +** 2 less than or equal to _n. The result is returned in _log2. +** +** This is equivalent to finding the highest set bit in the word. +*/ +#ifdef PR_HAVE_BUILTIN_BITSCAN32 +#define PR_FLOOR_LOG2(_log2,_n) \ + PR_BEGIN_MACRO \ + PRUint32 j_ = (PRUint32)(_n); \ + (_log2) = 31 - pr_bitscan_clz32((j_) | 1); \ + PR_END_MACRO +#else +#define PR_FLOOR_LOG2(_log2,_n) \ + PR_BEGIN_MACRO \ + PRUint32 j_ = (PRUint32)(_n); \ + (_log2) = 0; \ + if ((j_) >> 16) \ + (_log2) += 16, (j_) >>= 16; \ + if ((j_) >> 8) \ + (_log2) += 8, (j_) >>= 8; \ + if ((j_) >> 4) \ + (_log2) += 4, (j_) >>= 4; \ + if ((j_) >> 2) \ + (_log2) += 2, (j_) >>= 2; \ + if ((j_) >> 1) \ + (_log2) += 1; \ + PR_END_MACRO +#endif /* PR_HAVE_BUILTIN_BITSCAN32 */ + +/* +** Macros for rotate left and right. The argument 'a' must be an unsigned +** 32-bit integer type such as PRUint32. +** +** There is no rotate operation in the C Language, so the construct +** (a << 4) | (a >> 28) is frequently used instead. Most compilers convert +** this to a rotate instruction, but MSVC doesn't without a little help. +** To get MSVC to generate a rotate instruction, we have to use the _rotl +** or _rotr intrinsic and use a pragma to make it inline. +** +** Note: MSVC in VS2005 will do an inline rotate instruction on the above +** construct. +*/ + +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || \ + defined(_M_X64) || defined(_M_ARM)) +#include +#pragma intrinsic(_rotl, _rotr) +#define PR_ROTATE_LEFT32(a, bits) _rotl(a, bits) +#define PR_ROTATE_RIGHT32(a, bits) _rotr(a, bits) +#else +#define PR_ROTATE_LEFT32(a, bits) (((a) << (bits)) | ((a) >> (32 - (bits)))) +#define PR_ROTATE_RIGHT32(a, bits) (((a) >> (bits)) | ((a) << (32 - (bits)))) +#endif + +PR_END_EXTERN_C +#endif /* prbit_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prclist.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prclist.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prclist.h @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prclist_h___ +#define prclist_h___ + +#include "prtypes.h" + +typedef struct PRCListStr PRCList; + +/* +** Circular linked list +*/ +struct PRCListStr { + PRCList *next; + PRCList *prev; +}; + +/* +** Insert element "_e" into the list, before "_l". +*/ +#define PR_INSERT_BEFORE(_e,_l) \ + PR_BEGIN_MACRO \ + (_e)->next = (_l); \ + (_e)->prev = (_l)->prev; \ + (_l)->prev->next = (_e); \ + (_l)->prev = (_e); \ + PR_END_MACRO + +/* +** Insert element "_e" into the list, after "_l". +*/ +#define PR_INSERT_AFTER(_e,_l) \ + PR_BEGIN_MACRO \ + (_e)->next = (_l)->next; \ + (_e)->prev = (_l); \ + (_l)->next->prev = (_e); \ + (_l)->next = (_e); \ + PR_END_MACRO + +/* +** Return the element following element "_e" +*/ +#define PR_NEXT_LINK(_e) \ + ((_e)->next) +/* +** Return the element preceding element "_e" +*/ +#define PR_PREV_LINK(_e) \ + ((_e)->prev) + +/* +** Append an element "_e" to the end of the list "_l" +*/ +#define PR_APPEND_LINK(_e,_l) PR_INSERT_BEFORE(_e,_l) + +/* +** Insert an element "_e" at the head of the list "_l" +*/ +#define PR_INSERT_LINK(_e,_l) PR_INSERT_AFTER(_e,_l) + +/* Return the head/tail of the list */ +#define PR_LIST_HEAD(_l) (_l)->next +#define PR_LIST_TAIL(_l) (_l)->prev + +/* +** Remove the element "_e" from it's circular list. +*/ +#define PR_REMOVE_LINK(_e) \ + PR_BEGIN_MACRO \ + (_e)->prev->next = (_e)->next; \ + (_e)->next->prev = (_e)->prev; \ + PR_END_MACRO + +/* +** Remove the element "_e" from it's circular list. Also initializes the +** linkage. +*/ +#define PR_REMOVE_AND_INIT_LINK(_e) \ + PR_BEGIN_MACRO \ + (_e)->prev->next = (_e)->next; \ + (_e)->next->prev = (_e)->prev; \ + (_e)->next = (_e); \ + (_e)->prev = (_e); \ + PR_END_MACRO + +/* +** Return non-zero if the given circular list "_l" is empty, zero if the +** circular list is not empty +*/ +#define PR_CLIST_IS_EMPTY(_l) \ + ((_l)->next == (_l)) + +/* +** Initialize a circular list +*/ +#define PR_INIT_CLIST(_l) \ + PR_BEGIN_MACRO \ + (_l)->next = (_l); \ + (_l)->prev = (_l); \ + PR_END_MACRO + +#define PR_INIT_STATIC_CLIST(_l) \ + {(_l), (_l)} + +#endif /* prclist_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prcmon.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prcmon.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prcmon.h @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prcmon_h___ +#define prcmon_h___ + +/* +** Interface to cached monitors. Cached monitors use an address to find a +** given PR monitor. In this way a monitor can be associated with another +** object without preallocating a monitor for all objects. +** +** A hash table is used to quickly map addresses to individual monitors +** and the system automatically grows the hash table as needed. +** +** Cache monitors are about 5 times slower to use than uncached monitors. +*/ +#include "prmon.h" +#include "prinrval.h" + +PR_BEGIN_EXTERN_C + +/** +** Like PR_EnterMonitor except use the "address" to find a monitor in the +** monitor cache. If successful, returns the PRMonitor now associated +** with "address". Note that you must PR_CExitMonitor the address to +** release the monitor cache entry (otherwise the monitor cache will fill +** up). This call will return NULL if the monitor cache needs to be +** expanded and the system is out of memory. +*/ +NSPR_API(PRMonitor*) PR_CEnterMonitor(void *address); + +/* +** Like PR_ExitMonitor except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CExitMonitor(void *address); + +/* +** Like PR_Wait except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CWait(void *address, PRIntervalTime timeout); + +/* +** Like PR_Notify except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CNotify(void *address); + +/* +** Like PR_NotifyAll except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CNotifyAll(void *address); + +/* +** Set a callback to be invoked each time a monitor is recycled from the cache +** freelist, with the monitor's cache-key passed in address. +*/ +NSPR_API(void) PR_CSetOnMonitorRecycle(void (PR_CALLBACK *callback)(void *address)); + +PR_END_EXTERN_C + +#endif /* prcmon_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prcountr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prcountr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prcountr.h @@ -0,0 +1,525 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prcountr_h___ +#define prcountr_h___ + +/*---------------------------------------------------------------------------- +** prcountr.h -- NSPR Instrumentation counters +** +** The NSPR Counter Feature provides a means to "count +** something." Counters can be dynamically defined, incremented, +** decremented, set, and deleted under application program +** control. +** +** The Counter Feature is intended to be used as instrumentation, +** not as operational data. If you need a counter for operational +** data, use native integral types. +** +** Counters are 32bit unsigned intergers. On overflow, a counter +** will wrap. No exception is recognized or reported. +** +** A counter can be dynamically created using a two level naming +** convention. A "handle" is returned when the counter is +** created. The counter can subsequently be addressed by its +** handle. An API is provided to get an existing counter's handle +** given the names with which it was originally created. +** Similarly, a counter's name can be retrieved given its handle. +** +** The counter naming convention is a two-level hierarchy. The +** QName is the higher level of the hierarchy; RName is the +** lower level. RNames can be thought of as existing within a +** QName. The same RName can exist within multiple QNames. QNames +** are unique. The NSPR Counter is not a near-zero overhead +** feature. Application designers should be aware of +** serialization issues when using the Counter API. Creating a +** counter locks a large asset, potentially causing a stall. This +** suggest that applications should create counters at component +** initialization, for example, and not create and destroy them +** willy-nilly. ... You have been warned. +** +** Incrementing and Adding to counters uses atomic operations. +** The performance of these operations will vary from platform +** to platform. On platforms where atomic operations are not +** supported the overhead may be substantial. +** +** When traversing the counter database with FindNext functions, +** the instantaneous values of any given counter is that at the +** moment of extraction. The state of the entire counter database +** may not be viewed as atomic. +** +** The counter interface may be disabled (No-Op'd) at compile +** time. When DEBUG is defined at compile time, the Counter +** Feature is compiled into NSPR and applications invoking it. +** When DEBUG is not defined, the counter macros compile to +** nothing. To force the Counter Feature to be compiled into an +** optimized build, define FORCE_NSPR_COUNTERS at compile time +** for both NSPR and the application intending to use it. +** +** Application designers should use the macro form of the Counter +** Feature methods to minimize performance impact in optimized +** builds. The macros normally compile to nothing on optimized +** builds. +** +** Application designers should be aware of the effects of +** debug and optimized build differences when using result of the +** Counter Feature macros in expressions. +** +** The Counter Feature is thread-safe and SMP safe. +** +** /lth. 09-Jun-1998. +*/ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** Opaque counter handle type. +** ... don't even think of looking in here. +** +*/ +typedef void * PRCounterHandle; + +#define PRCOUNTER_NAME_MAX 31 +#define PRCOUNTER_DESC_MAX 255 + + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DEFINE_COUNTER() -- Define a PRCounterHandle +** +** DESCRIPTION: PR_DEFINE_COUNTER() is used to define a counter +** handle. +** +*/ +#define PR_DEFINE_COUNTER(name) PRCounterHandle name + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_INIT_COUNTER_HANDLE() -- Set the value of a PRCounterHandle +** +** DESCRIPTION: +** PR_INIT_COUNTER_HANDLE() sets the value of a PRCounterHandle +** to value. +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_INIT_COUNTER_HANDLE(handle,value)\ + (handle) = (PRCounterHandle)(value) +#else +#define PR_INIT_COUNTER_HANDLE(handle,value) +#endif + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_CreateCounter() -- Create a counter +** +** DESCRIPTION: PR_CreateCounter() creates a counter object and +** initializes it to zero. +** +** The macro form takes as its first argument the name of the +** PRCounterHandle to receive the handle returned from +** PR_CreateCounter(). +** +** INPUTS: +** qName: The QName for the counter object. The maximum length +** of qName is defined by PRCOUNTER_NAME_MAX +** +** rName: The RName for the counter object. The maximum length +** of qName is defined by PRCOUNTER_NAME_MAX +** +** descrioption: The description of the counter object. The +** maximum length of description is defined by +** PRCOUNTER_DESC_MAX. +** +** OUTPUTS: +** +** RETURNS: +** PRCounterHandle. +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_CREATE_COUNTER(handle,qName,rName,description)\ + (handle) = PR_CreateCounter((qName),(rName),(description)) +#else +#define PR_CREATE_COUNTER(handle,qName,rName,description) +#endif + +NSPR_API(PRCounterHandle) + PR_CreateCounter( + const char *qName, + const char *rName, + const char *description +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DestroyCounter() -- Destroy a counter object. +** +** DESCRIPTION: PR_DestroyCounter() removes a counter and +** unregisters its handle from the counter database. +** +** INPUTS: +** handle: the PRCounterHandle of the counter to be destroyed. +** +** OUTPUTS: +** The counter is destroyed. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_DESTROY_COUNTER(handle) PR_DestroyCounter((handle)) +#else +#define PR_DESTROY_COUNTER(handle) +#endif + +NSPR_API(void) + PR_DestroyCounter( + PRCounterHandle handle +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetCounterHandleFromName() -- Retreive a +** counter's handle give its name. +** +** DESCRIPTION: PR_GetCounterHandleFromName() retreives a +** counter's handle from the counter database, given the name +** the counter was originally created with. +** +** INPUTS: +** qName: Counter's original QName. +** rName: Counter's original RName. +** +** OUTPUTS: +** +** RETURNS: +** PRCounterHandle or PRCounterError. +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_GET_COUNTER_HANDLE_FROM_NAME(handle,qName,rName)\ + (handle) = PR_GetCounterHandleFromName((qName),(rName)) +#else +#define PR_GET_COUNTER_HANDLE_FROM_NAME(handle,qName,rName) +#endif + +NSPR_API(PRCounterHandle) + PR_GetCounterHandleFromName( + const char *qName, + const char *rName +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetCounterNameFromHandle() -- Retreive a +** counter's name, given its handle. +** +** DESCRIPTION: PR_GetCounterNameFromHandle() retreives a +** counter's name given its handle. +** +** INPUTS: +** qName: Where to store a pointer to qName. +** rName: Where to store a pointer to rName. +** description: Where to store a pointer to description. +** +** OUTPUTS: Pointers to the Counter Feature's copies of the names +** used when the counters were created. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_GET_COUNTER_NAME_FROM_HANDLE(handle,qName,rName,description)\ + PR_GetCounterNameFromHandle((handle),(qName),(rName),(description)) +#else +#define PR_GET_COUNTER_NAME_FROM_HANDLE(handle,qName,rName,description ) +#endif + +NSPR_API(void) + PR_GetCounterNameFromHandle( + PRCounterHandle handle, + const char **qName, + const char **rName, + const char **description +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_IncrementCounter() -- Add one to the referenced +** counter. +** +** DESCRIPTION: Add one to the referenced counter. +** +** INPUTS: +** handle: The PRCounterHandle of the counter to be incremented +** +** OUTPUTS: The counter is incrementd. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_INCREMENT_COUNTER(handle) PR_IncrementCounter(handle) +#else +#define PR_INCREMENT_COUNTER(handle) +#endif + +NSPR_API(void) + PR_IncrementCounter( + PRCounterHandle handle +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DecrementCounter() -- Subtract one from the +** referenced counter +** +** DESCRIPTION: Subtract one from the referenced counter. +** +** INPUTS: +** handle: The PRCounterHandle of the coutner to be +** decremented. +** +** OUTPUTS: the counter is decremented. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_DECREMENT_COUNTER(handle) PR_DecrementCounter(handle) +#else +#define PR_DECREMENT_COUNTER(handle) +#endif + +NSPR_API(void) + PR_DecrementCounter( + PRCounterHandle handle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_AddToCounter() -- Add a value to a counter. +** +** DESCRIPTION: Add value to the counter referenced by handle. +** +** INPUTS: +** handle: the PRCounterHandle of the counter to be added to. +** +** value: the value to be added to the counter. +** +** OUTPUTS: new value for counter. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_ADD_TO_COUNTER(handle,value)\ + PR_AddToCounter((handle),(value)) +#else +#define PR_ADD_TO_COUNTER(handle,value) +#endif + +NSPR_API(void) + PR_AddToCounter( + PRCounterHandle handle, + PRUint32 value +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_SubtractFromCounter() -- A value is subtracted +** from a counter. +** +** DESCRIPTION: +** Subtract a value from a counter. +** +** INPUTS: +** handle: the PRCounterHandle of the counter to be subtracted +** from. +** +** value: the value to be subtracted from the counter. +** +** OUTPUTS: new value for counter +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_SUBTRACT_FROM_COUNTER(handle,value)\ + PR_SubtractFromCounter((handle),(value)) +#else +#define PR_SUBTRACT_FROM_COUNTER(handle,value) +#endif + +NSPR_API(void) + PR_SubtractFromCounter( + PRCounterHandle handle, + PRUint32 value +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetCounter() -- Retreive the value of a counter +** +** DESCRIPTION: +** Retreive the value of a counter. +** +** INPUTS: +** handle: the PR_CounterHandle of the counter to be retreived +** +** OUTPUTS: +** +** RETURNS: The value of the referenced counter +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_GET_COUNTER(counter,handle)\ + (counter) = PR_GetCounter((handle)) +#else +#define PR_GET_COUNTER(counter,handle) 0 +#endif + +NSPR_API(PRUint32) + PR_GetCounter( + PRCounterHandle handle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_SetCounter() -- Replace the content of counter +** with value. +** +** DESCRIPTION: The contents of the referenced counter are +** replaced by value. +** +** INPUTS: +** handle: the PRCounterHandle of the counter whose contents +** are to be replaced. +** +** value: the new value of the counter. +** +** OUTPUTS: +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_SET_COUNTER(handle,value) PR_SetCounter((handle),(value)) +#else +#define PR_SET_COUNTER(handle,value) +#endif + +NSPR_API(void) + PR_SetCounter( + PRCounterHandle handle, + PRUint32 value +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextCounterQname() -- Retreive the next QName counter +** handle iterator +** +** DESCRIPTION: +** PR_FindNextCounterQname() retreives the first or next Qname +** the counter data base, depending on the value of handle. When +** handle is NULL, the function attempts to retreive the first +** QName handle in the database. When handle is a handle previosly +** retreived QName handle, then the function attempts to retreive +** the next QName handle. +** +** INPUTS: +** handle: PRCounterHandle or NULL. +** +** OUTPUTS: returned +** +** RETURNS: PRCounterHandle or NULL when no more QName counter +** handles are present. +** +** RESTRICTIONS: +** A concurrent PR_CreateCounter() or PR_DestroyCounter() may +** cause unpredictable results. +** +** A PRCounterHandle returned from this function may only be used +** in another PR_FindNextCounterQname() function call; other +** operations may cause unpredictable results. +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_FIND_NEXT_COUNTER_QNAME(next,handle)\ + (next) = PR_FindNextCounterQname((handle)) +#else +#define PR_FIND_NEXT_COUNTER_QNAME(next,handle) NULL +#endif + +NSPR_API(PRCounterHandle) + PR_FindNextCounterQname( + PRCounterHandle handle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextCounterRname() -- Retreive the next RName counter +** handle iterator +** +** DESCRIPTION: +** PR_FindNextCounterRname() retreives the first or next RNname +** handle from the counter data base, depending on the +** value of handle. When handle is NULL, the function attempts to +** retreive the first RName handle in the database. When handle is +** a handle previosly retreived RName handle, then the function +** attempts to retreive the next RName handle. +** +** INPUTS: +** handle: PRCounterHandle or NULL. +** qhandle: PRCounterHandle of a previously aquired via +** PR_FIND_NEXT_QNAME_HANDLE() +** +** OUTPUTS: returned +** +** RETURNS: PRCounterHandle or NULL when no more RName counter +** handles are present. +** +** RESTRICTIONS: +** A concurrent PR_CreateCounter() or PR_DestroyCounter() may +** cause unpredictable results. +** +** A PRCounterHandle returned from this function may only be used +** in another PR_FindNextCounterRname() function call; other +** operations may cause unpredictable results. +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_FIND_NEXT_COUNTER_RNAME(next,rhandle,qhandle)\ + (next) = PR_FindNextCounterRname((rhandle),(qhandle)) +#else +#define PR_FIND_NEXT_COUNTER_RNAME(next,rhandle,qhandle) +#endif + +NSPR_API(PRCounterHandle) + PR_FindNextCounterRname( + PRCounterHandle rhandle, + PRCounterHandle qhandle +); + +PR_END_EXTERN_C + +#endif /* prcountr_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prcpucfg.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prcpucfg.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prcpucfg.h @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef NSPR_PRCPUCFG_H_ +#define NSPR_PRCPUCFG_H_ + +/* + * Need to support conditionals that are defined in both the top-level build + * system as well as NSS' build system for now. + */ +#if defined(XP_DARWIN) || defined(DARWIN) +#include "md/_darwin.cfg" +#elif defined(XP_WIN) || defined(_WINDOWS) +#include "md/_win95.cfg" +#elif defined(__FreeBSD__) +#include "md/_freebsd.cfg" +#elif defined(__NetBSD__) +#include "md/_netbsd.cfg" +#elif defined(__OpenBSD__) +#include "md/_openbsd.cfg" +#elif defined(__linux__) +#include "md/_linux.cfg" +#elif defined(__sun__) +#include "md/_solaris.cfg" +#else +#error "Unsupported platform!" +#endif + +#endif /* NSPR_PRCPUCFG_H_ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prcvar.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prcvar.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prcvar.h @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prcvar_h___ +#define prcvar_h___ + +#include "prlock.h" +#include "prinrval.h" + +PR_BEGIN_EXTERN_C + +typedef struct PRCondVar PRCondVar; + +/* +** Create a new condition variable. +** +** "lock" is the lock used to protect the condition variable. +** +** Condition variables are synchronization objects that threads can use +** to wait for some condition to occur. +** +** This may fail if memory is tight or if some operating system resource +** is low. In such cases, a NULL will be returned. +*/ +NSPR_API(PRCondVar*) PR_NewCondVar(PRLock *lock); + +/* +** Destroy a condition variable. There must be no thread +** waiting on the condvar. The caller is responsible for guaranteeing +** that the condvar is no longer in use. +** +*/ +NSPR_API(void) PR_DestroyCondVar(PRCondVar *cvar); + +/* +** The thread that waits on a condition is blocked in a "waiting on +** condition" state until another thread notifies the condition or a +** caller specified amount of time expires. The lock associated with +** the condition variable will be released, which must have be held +** prior to the call to wait. +** +** Logically a notified thread is moved from the "waiting on condition" +** state and made "ready." When scheduled, it will attempt to reacquire +** the lock that it held when wait was called. +** +** The timeout has two well known values, PR_INTERVAL_NO_TIMEOUT and +** PR_INTERVAL_NO_WAIT. The former value requires that a condition be +** notified (or the thread interrupted) before it will resume from the +** wait. If the timeout has a value of PR_INTERVAL_NO_WAIT, the effect +** is to release the lock, possibly causing a rescheduling within the +** runtime, then immediately attempting to reacquire the lock and resume. +** +** Any other value for timeout will cause the thread to be rescheduled +** either due to explicit notification or an expired interval. The latter +** must be determined by treating time as one part of the monitored data +** being protected by the lock and tested explicitly for an expired +** interval. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable or the thread was interrupted (PR_Interrupt()). +** The particular reason can be extracted with PR_GetError(). +*/ +NSPR_API(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout); + +/* +** Notify ONE thread that is currently waiting on 'cvar'. Which thread is +** dependent on the implementation of the runtime. Common sense would dictate +** that all threads waiting on a single condition have identical semantics, +** therefore which one gets notified is not significant. +** +** The calling thead must hold the lock that protects the condition, as +** well as the invariants that are tightly bound to the condition, when +** notify is called. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable. +*/ +NSPR_API(PRStatus) PR_NotifyCondVar(PRCondVar *cvar); + +/* +** Notify all of the threads waiting on the condition variable. The order +** that the threads are notified is indeterminant. The lock that protects +** the condition must be held. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable. +*/ +NSPR_API(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar); + +PR_END_EXTERN_C + +#endif /* prcvar_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prdtoa.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prdtoa.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prdtoa.h @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prdtoa_h___ +#define prdtoa_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** PR_strtod() returns as a double-precision floating-point number +** the value represented by the character string pointed to by +** s00. The string is scanned up to the first unrecognized +** character. +**a +** If the value of se is not (char **)NULL, a pointer to +** the character terminating the scan is returned in the location pointed +** to by se. If no number can be formed, se is set to s00, and +** zero is returned. +*/ +NSPR_API(PRFloat64) +PR_strtod(const char *s00, char **se); + +/* +** PR_cnvtf() +** conversion routines for floating point +** prcsn - number of digits of precision to generate floating +** point value. +*/ +NSPR_API(void) PR_cnvtf(char *buf, PRIntn bufsz, PRIntn prcsn, PRFloat64 fval); + +/* +** PR_dtoa() converts double to a string. +** +** ARGUMENTS: +** If rve is not null, *rve is set to point to the end of the return value. +** If d is +-Infinity or NaN, then *decpt is set to 9999. +** +** mode: +** 0 ==> shortest string that yields d when read in +** and rounded to nearest. +*/ +NSPR_API(PRStatus) PR_dtoa(PRFloat64 d, PRIntn mode, PRIntn ndigits, + PRIntn *decpt, PRIntn *sign, char **rve, char *buf, PRSize bufsize); + +PR_END_EXTERN_C + +#endif /* prdtoa_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prenv.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prenv.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prenv.h @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prenv_h___ +#define prenv_h___ + +#include "prtypes.h" + +/*******************************************************************************/ +/*******************************************************************************/ +/****************** THESE FUNCTIONS MAY NOT BE THREAD SAFE *********************/ +/*******************************************************************************/ +/*******************************************************************************/ + +PR_BEGIN_EXTERN_C + +/* +** PR_GetEnv() -- Retrieve value of environment variable +** +** Description: +** PR_GetEnv() is modeled on Unix getenv(). +** +** +** Inputs: +** var -- The name of the environment variable +** +** Returns: +** The value of the environment variable 'var' or NULL if +** the variable is undefined. +** +** Restrictions: +** You'd think that a POSIX getenv(), putenv() would be +** consistently implemented everywhere. Surprise! It is not. On +** some platforms, a putenv() where the argument is of +** the form "name" causes the named environment variable to +** be un-set; that is: a subsequent getenv() returns NULL. On +** other platforms, the putenv() fails, on others, it is a +** no-op. Similarly, a putenv() where the argument is of the +** form "name=" causes the named environment variable to be +** un-set; a subsequent call to getenv() returns NULL. On +** other platforms, a subsequent call to getenv() returns a +** pointer to a null-string (a byte of zero). +** +** PR_GetEnv(), PR_SetEnv() provide a consistent behavior +** across all supported platforms. There are, however, some +** restrictions and some practices you must use to achieve +** consistent results everywhere. +** +** When manipulating the environment there is no way to un-set +** an environment variable across all platforms. We suggest +** you interpret the return of a pointer to null-string to +** mean the same as a return of NULL from PR_GetEnv(). +** +** A call to PR_SetEnv() where the parameter is of the form +** "name" will return PR_FAILURE; the environment remains +** unchanged. A call to PR_SetEnv() where the parameter is +** of the form "name=" may un-set the envrionment variable on +** some platforms; on others it may set the value of the +** environment variable to the null-string. +** +** For example, to test for NULL return or return of the +** null-string from PR_GetEnv(), use the following code +** fragment: +** +** char *val = PR_GetEnv("foo"); +** if ((NULL == val) || ('\0' == *val)) { +** ... interpret this as un-set ... +** } +** +** The caller must ensure that the string passed +** to PR_SetEnv() is persistent. That is: The string should +** not be on the stack, where it can be overwritten +** on return from the function calling PR_SetEnv(). +** Similarly, the string passed to PR_SetEnv() must not be +** overwritten by other actions of the process. ... Some +** platforms use the string by reference rather than copying +** it into the environment space. ... You have been warned! +** +** Use of platform-native functions that manipulate the +** environment (getenv(), putenv(), +** SetEnvironmentVariable(), etc.) must not be used with +** NSPR's similar functions. The platform-native functions +** may not be thread safe and/or may operate on different +** conceptual environment space than that operated upon by +** NSPR's functions or other environment manipulating +** functions on the same platform. (!) +** +*/ +NSPR_API(char*) PR_GetEnv(const char *var); + +/* +** PR_GetEnvSecure() -- get a security-sensitive environment variable +** +** Description: +** +** PR_GetEnvSecure() is similar to PR_GetEnv(), but it returns NULL if +** the program was run with elevated privilege (e.g., setuid or setgid +** on Unix). This can be used for cases like log file paths which +** could otherwise be used for privilege escalation. Note that some +** platforms may have platform-specific privilege elevation mechanisms +** not recognized by this function; see the implementation for details. +*/ +NSPR_API(char*) PR_GetEnvSecure(const char *var); + +/* +** PR_SetEnv() -- set, unset or change an environment variable +** +** Description: +** PR_SetEnv() is modeled on the Unix putenv() function. +** +** Inputs: +** string -- pointer to a caller supplied +** constant, persistent string of the form name=value. Where +** name is the name of the environment variable to be set or +** changed; value is the value assigned to the variable. +** +** Returns: +** PRStatus. +** +** Restrictions: +** See the Restrictions documented in the description of +** PR_GetEnv() in this header file. +** +** +*/ +NSPR_API(PRStatus) PR_SetEnv(const char *string); + +/* +** PR_DuplicateEnvironment() -- Obtain a copy of the environment. +** +** Description: +** PR_DuplicateEnvironment() copies the environment so that it can be +** modified without changing the current process's environment, and +** then passed to interfaces such as POSIX execve(). In particular, +** this avoids needing to allocate memory or take locks in the child +** after a fork(); neither of these is allowed by POSIX after a +** multithreaded process calls fork(), and PR_SetEnv does both. +** +** Inputs: +** none +** +** Returns: +** A pointer to a null-terminated array of null-terminated strings, +** like the traditional global variable "environ". The array and +** the strings are allocated with PR_Malloc(), and it is the +** caller's responsibility to free them. +** +** In case of memory allocation failure, or if the operating system +** doesn't support reading the entire environment through the global +** variable "environ" or similar, returns NULL instead. +** +** Restrictions: +** Similarly to PR_GetEnv(), this function may not interoperate as +** expected with the operating system's native environment accessors. +*/ +NSPR_API(char **) PR_DuplicateEnvironment(void); + +PR_END_EXTERN_C + +#endif /* prenv_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prerr.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prerr.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prerr.h @@ -0,0 +1,249 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prerr_h___ +#define prerr_h___ + +/* + * + * prerr.h + * This file is automatically generated; please do not edit it. + */ + +/* Memory allocation attempt failed */ +#define PR_OUT_OF_MEMORY_ERROR (-6000L) + +/* Invalid file descriptor */ +#define PR_BAD_DESCRIPTOR_ERROR (-5999L) + +/* The operation would have blocked */ +#define PR_WOULD_BLOCK_ERROR (-5998L) + +/* Invalid memory address argument */ +#define PR_ACCESS_FAULT_ERROR (-5997L) + +/* Invalid function for file type */ +#define PR_INVALID_METHOD_ERROR (-5996L) + +/* Invalid memory address argument */ +#define PR_ILLEGAL_ACCESS_ERROR (-5995L) + +/* Some unknown error has occurred */ +#define PR_UNKNOWN_ERROR (-5994L) + +/* Operation interrupted by another thread */ +#define PR_PENDING_INTERRUPT_ERROR (-5993L) + +/* function not implemented */ +#define PR_NOT_IMPLEMENTED_ERROR (-5992L) + +/* I/O function error */ +#define PR_IO_ERROR (-5991L) + +/* I/O operation timed out */ +#define PR_IO_TIMEOUT_ERROR (-5990L) + +/* I/O operation on busy file descriptor */ +#define PR_IO_PENDING_ERROR (-5989L) + +/* The directory could not be opened */ +#define PR_DIRECTORY_OPEN_ERROR (-5988L) + +/* Invalid function argument */ +#define PR_INVALID_ARGUMENT_ERROR (-5987L) + +/* Network address not available (in use?) */ +#define PR_ADDRESS_NOT_AVAILABLE_ERROR (-5986L) + +/* Network address type not supported */ +#define PR_ADDRESS_NOT_SUPPORTED_ERROR (-5985L) + +/* Already connected */ +#define PR_IS_CONNECTED_ERROR (-5984L) + +/* Network address is invalid */ +#define PR_BAD_ADDRESS_ERROR (-5983L) + +/* Local Network address is in use */ +#define PR_ADDRESS_IN_USE_ERROR (-5982L) + +/* Connection refused by peer */ +#define PR_CONNECT_REFUSED_ERROR (-5981L) + +/* Network address is presently unreachable */ +#define PR_NETWORK_UNREACHABLE_ERROR (-5980L) + +/* Connection attempt timed out */ +#define PR_CONNECT_TIMEOUT_ERROR (-5979L) + +/* Network file descriptor is not connected */ +#define PR_NOT_CONNECTED_ERROR (-5978L) + +/* Failure to load dynamic library */ +#define PR_LOAD_LIBRARY_ERROR (-5977L) + +/* Failure to unload dynamic library */ +#define PR_UNLOAD_LIBRARY_ERROR (-5976L) + +/* Symbol not found in any of the loaded dynamic libraries */ +#define PR_FIND_SYMBOL_ERROR (-5975L) + +/* Insufficient system resources */ +#define PR_INSUFFICIENT_RESOURCES_ERROR (-5974L) + +/* A directory lookup on a network address has failed */ +#define PR_DIRECTORY_LOOKUP_ERROR (-5973L) + +/* Attempt to access a TPD key that is out of range */ +#define PR_TPD_RANGE_ERROR (-5972L) + +/* Process open FD table is full */ +#define PR_PROC_DESC_TABLE_FULL_ERROR (-5971L) + +/* System open FD table is full */ +#define PR_SYS_DESC_TABLE_FULL_ERROR (-5970L) + +/* Network operation attempted on non-network file descriptor */ +#define PR_NOT_SOCKET_ERROR (-5969L) + +/* TCP-specific function attempted on a non-TCP file descriptor */ +#define PR_NOT_TCP_SOCKET_ERROR (-5968L) + +/* TCP file descriptor is already bound */ +#define PR_SOCKET_ADDRESS_IS_BOUND_ERROR (-5967L) + +/* Access Denied */ +#define PR_NO_ACCESS_RIGHTS_ERROR (-5966L) + +/* The requested operation is not supported by the platform */ +#define PR_OPERATION_NOT_SUPPORTED_ERROR (-5965L) + +/* The host operating system does not support the protocol requested */ +#define PR_PROTOCOL_NOT_SUPPORTED_ERROR (-5964L) + +/* Access to the remote file has been severed */ +#define PR_REMOTE_FILE_ERROR (-5963L) + +/* The value requested is too large to be stored in the data buffer provided */ +#define PR_BUFFER_OVERFLOW_ERROR (-5962L) + +/* TCP connection reset by peer */ +#define PR_CONNECT_RESET_ERROR (-5961L) + +/* Unused */ +#define PR_RANGE_ERROR (-5960L) + +/* The operation would have deadlocked */ +#define PR_DEADLOCK_ERROR (-5959L) + +/* The file is already locked */ +#define PR_FILE_IS_LOCKED_ERROR (-5958L) + +/* Write would result in file larger than the system allows */ +#define PR_FILE_TOO_BIG_ERROR (-5957L) + +/* The device for storing the file is full */ +#define PR_NO_DEVICE_SPACE_ERROR (-5956L) + +/* Unused */ +#define PR_PIPE_ERROR (-5955L) + +/* Unused */ +#define PR_NO_SEEK_DEVICE_ERROR (-5954L) + +/* Cannot perform a normal file operation on a directory */ +#define PR_IS_DIRECTORY_ERROR (-5953L) + +/* Symbolic link loop */ +#define PR_LOOP_ERROR (-5952L) + +/* File name is too long */ +#define PR_NAME_TOO_LONG_ERROR (-5951L) + +/* File not found */ +#define PR_FILE_NOT_FOUND_ERROR (-5950L) + +/* Cannot perform directory operation on a normal file */ +#define PR_NOT_DIRECTORY_ERROR (-5949L) + +/* Cannot write to a read-only file system */ +#define PR_READ_ONLY_FILESYSTEM_ERROR (-5948L) + +/* Cannot delete a directory that is not empty */ +#define PR_DIRECTORY_NOT_EMPTY_ERROR (-5947L) + +/* Cannot delete or rename a file object while the file system is busy */ +#define PR_FILESYSTEM_MOUNTED_ERROR (-5946L) + +/* Cannot rename a file to a file system on another device */ +#define PR_NOT_SAME_DEVICE_ERROR (-5945L) + +/* The directory object in the file system is corrupted */ +#define PR_DIRECTORY_CORRUPTED_ERROR (-5944L) + +/* Cannot create or rename a filename that already exists */ +#define PR_FILE_EXISTS_ERROR (-5943L) + +/* Directory is full. No additional filenames may be added */ +#define PR_MAX_DIRECTORY_ENTRIES_ERROR (-5942L) + +/* The required device was in an invalid state */ +#define PR_INVALID_DEVICE_STATE_ERROR (-5941L) + +/* The device is locked */ +#define PR_DEVICE_IS_LOCKED_ERROR (-5940L) + +/* No more entries in the directory */ +#define PR_NO_MORE_FILES_ERROR (-5939L) + +/* Encountered end of file */ +#define PR_END_OF_FILE_ERROR (-5938L) + +/* Seek error */ +#define PR_FILE_SEEK_ERROR (-5937L) + +/* The file is busy */ +#define PR_FILE_IS_BUSY_ERROR (-5936L) + +/* The I/O operation was aborted */ +#define PR_OPERATION_ABORTED_ERROR (-5935L) + +/* Operation is still in progress (probably a non-blocking connect) */ +#define PR_IN_PROGRESS_ERROR (-5934L) + +/* Operation has already been initiated (probably a non-blocking connect) */ +#define PR_ALREADY_INITIATED_ERROR (-5933L) + +/* The wait group is empty */ +#define PR_GROUP_EMPTY_ERROR (-5932L) + +/* Object state improper for request */ +#define PR_INVALID_STATE_ERROR (-5931L) + +/* Network is down */ +#define PR_NETWORK_DOWN_ERROR (-5930L) + +/* Socket shutdown */ +#define PR_SOCKET_SHUTDOWN_ERROR (-5929L) + +/* Connection aborted */ +#define PR_CONNECT_ABORTED_ERROR (-5928L) + +/* Host is unreachable */ +#define PR_HOST_UNREACHABLE_ERROR (-5927L) + +/* The library is not loaded */ +#define PR_LIBRARY_NOT_LOADED_ERROR (-5926L) + +/* The one-time function was previously called and failed. Its error code is no longer available */ +#define PR_CALL_ONCE_ERROR (-5925L) + +/* Placeholder for the end of the list */ +#define PR_MAX_ERROR (-5924L) + +extern void nspr_InitializePRErrorTable(void); +#define ERROR_TABLE_BASE_nspr (-6000L) + +#endif /* prerr_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prerror.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prerror.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prerror.h @@ -0,0 +1,294 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prerror_h___ +#define prerror_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +typedef PRInt32 PRErrorCode; + +#define PR_NSPR_ERROR_BASE -6000 + +#include "prerr.h" + +/* +** Set error will preserve an error condition within a thread context. +** The values stored are the NSPR (platform independent) translation of +** the error. Also, if available, the platform specific oserror is stored. +** If there is no appropriate OS error number, a zero my be supplied. +*/ +NSPR_API(void) PR_SetError(PRErrorCode errorCode, PRInt32 oserr); + +/* +** The text value specified may be NULL. If it is not NULL and the text length +** is zero, the string is assumed to be a null terminated C string. Otherwise +** the text is assumed to be the length specified and possibly include NULL +** characters (e.g., a multi-national string). +** +** The text will be copied into to thread structure and remain there +** until the next call to PR_SetError. +*/ +NSPR_API(void) PR_SetErrorText( + PRIntn textLength, const char *text); + +/* +** Return the current threads last set error code. +*/ +NSPR_API(PRErrorCode) PR_GetError(void); + +/* +** Return the current threads last set os error code. This is used for +** machine specific code that desires the underlying os error. +*/ +NSPR_API(PRInt32) PR_GetOSError(void); + +/* +** Get the length of the error text. If a zero is returned, then there +** is no text. Otherwise, the value returned is sufficient to contain +** the error text currently available. +*/ +NSPR_API(PRInt32) PR_GetErrorTextLength(void); + +/* +** Copy the current threads current error text. Then actual number of bytes +** copied is returned as the result. If the result is zero, the 'text' area +** is unaffected. +*/ +NSPR_API(PRInt32) PR_GetErrorText(char *text); + + +/* +Copyright (C) 1987, 1988 Student Information Processing Board of the +Massachusetts Institute of Technology. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, provided +that the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be +used in advertising or publicity pertaining to distribution of the software +without specific, written prior permission. M.I.T. and the M.I.T. S.I.P.B. +make no representations about the suitability of this software for any +purpose. It is provided "as is" without express or implied warranty. +*/ + + +/* + * NOTE: + * The interfaces for error-code-translation described in the rest of + * this file are preliminary in the 3.1 release of nspr and are subject + * to change in future releases. + */ + +/* +** Description: Localizable error code to string function. +** +** +** NSPR provides a mechanism for converting an error code to a +** descriptive string, in a caller-specified language. +** +** Error codes themselves are 32 bit (signed) integers. Typically, +** the high order 24 bits are an identifier of which error table the +** error code is from, and the low order 8 bits are a sequential error +** number within the table. NSPR supports error tables whose first +** error code is not a multiple of 256, such error code assignments +** should be avoided when possible. +** +** Error table 0 is defined to match the UNIX system call error table +** (sys_errlist); this allows errno values to be used directly in the +** library. Other error table numbers are typically formed by +** compacting together the first four characters of the error table +** name. The mapping between characters in the name and numeric +** values in the error code are defined in a system-independent +** fashion, so that two systems that can pass integral values between +** them can reliably pass error codes without loss of meaning; this +** should work even if the character sets used are not the +** same. (However, if this is to be done, error table 0 should be +** avoided, since the local system call error tables may differ.) +** +** Libraries defining error codes need only provide a table mapping +** error code numbers to names and default English descriptions, +** calling a routine to install the table, making it ``known'' to NSPR +** library. Once installed, a table may not be removed. Any error +** code the library generates can be converted to the corresponding +** error message. There is also a default format for error codes +** accidentally returned before making the table known, which is of +** the form "unknown code foo 32", where "foo" would be the name of +** the table. +** +** Normally, the error code conversion routine only supports the +** languages "i-default" and "en", returning the error-table-provided +** English description for both languages. The application may +** provide a localization plugin, allowing support for additional +** languages. +** +**/ + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +/* + * PRLanguageCode -- + * + * NSPR represents a language code as a non-negative integer. + * Languages 0 is always "i-default" the language you get without + * explicit negotiation. Language 1 is always "en", English + * which has been explicitly negotiated. Additional language + * codes are defined by an application-provided localization plugin. + */ +typedef PRUint32 PRLanguageCode; +#define PR_LANGUAGE_I_DEFAULT 0 /* i-default, the default language */ +#define PR_LANGUAGE_EN 1 /* English, explicitly negotiated */ + +/* + * struct PRErrorMessage -- + * + * An error message in an error table. + */ +struct PRErrorMessage { + const char * name; /* Macro name for error */ + const char * en_text; /* Default English text */ +}; + +/* + * struct PRErrorTable -- + * + * An error table, provided by a library. + */ +struct PRErrorTable { + const struct PRErrorMessage * msgs; /* Array of error information */ + const char *name; /* Name of error table source */ + PRErrorCode base; /* Error code for first error in table */ + int n_msgs; /* Number of codes in table */ +}; + +/* + * struct PRErrorCallbackPrivate -- + * + * A private structure for the localization plugin + */ +struct PRErrorCallbackPrivate; + +/* + * struct PRErrorCallbackTablePrivate -- + * + * A data structure under which the localization plugin may store information, + * associated with an error table, that is private to itself. + */ +struct PRErrorCallbackTablePrivate; + +/* + * PRErrorCallbackLookupFn -- + * + * A function of PRErrorCallbackLookupFn type is a localization + * plugin callback which converts an error code into a description + * in the requested language. The callback is provided the + * appropriate error table, private data for the plugin and the table. + * The callback returns the appropriate UTF-8 encoded description, or NULL + * if no description can be found. + */ +typedef const char * +PRErrorCallbackLookupFn(PRErrorCode code, PRLanguageCode language, + const struct PRErrorTable *table, + struct PRErrorCallbackPrivate *cb_private, + struct PRErrorCallbackTablePrivate *table_private); + +/* + * PRErrorCallbackNewTableFn -- + * + * A function PRErrorCallbackNewTableFn type is a localization plugin + * callback which is called once with each error table registered + * with NSPR. The callback is provided with the error table and + * the plugin's private structure. The callback returns any table private + * data it wishes to associate with the error table. Does not need to be thread + * safe. + */ +typedef struct PRErrorCallbackTablePrivate * +PRErrorCallbackNewTableFn(const struct PRErrorTable *table, + struct PRErrorCallbackPrivate *cb_private); + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/*********************************************************************** +** FUNCTION: PR_ErrorToString +** DESCRIPTION: +** Returns the UTF-8 message for an error code in +** the requested language. May return the message +** in the default language if a translation in the requested +** language is not available. The returned string is +** valid for the duration of the process. Never returns NULL. +** +***********************************************************************/ +NSPR_API(const char *) PR_ErrorToString(PRErrorCode code, + PRLanguageCode language); + + +/*********************************************************************** +** FUNCTION: PR_ErrorToName +** DESCRIPTION: +** Returns the macro name for an error code, or NULL +** if the error code is not known. The returned string is +** valid for the duration of the process. +** +** Does not work for error table 0, the system error codes. +** +***********************************************************************/ +NSPR_API(const char *) PR_ErrorToName(PRErrorCode code); + + +/*********************************************************************** +** FUNCTION: PR_ErrorLanguages +** DESCRIPTION: +** Returns the RFC 1766 language tags for the language +** codes PR_ErrorToString() supports. The returned array is valid +** for the duration of the process. Never returns NULL. The first +** item in the returned array is the language tag for PRLanguageCode 0, +** the second is for PRLanguageCode 1, and so on. The array is terminated +** with a null pointer. +** +***********************************************************************/ +NSPR_API(const char * const *) PR_ErrorLanguages(void); + + +/*********************************************************************** +** FUNCTION: PR_ErrorInstallTable +** DESCRIPTION: +** Registers an error table with NSPR. Must be done exactly once per +** table. Memory pointed to by `table' must remain valid for the life +** of the process. +** +** NOT THREAD SAFE! +** +***********************************************************************/ +NSPR_API(PRErrorCode) PR_ErrorInstallTable(const struct PRErrorTable *table); + + +/*********************************************************************** +** FUNCTION: PR_ErrorInstallCallback +** DESCRIPTION: +** Registers an error localization plugin with NSPR. May be called +** at most one time. `languages' contains the language codes supported +** by this plugin. Languages 0 and 1 must be "i-default" and "en" +** respectively. `lookup' and `newtable' contain pointers to +** the plugin callback functions. `cb_private' contains any information +** private to the plugin functions. +** +** NOT THREAD SAFE! +** +***********************************************************************/ +NSPR_API(void) PR_ErrorInstallCallback(const char * const * languages, + PRErrorCallbackLookupFn *lookup, + PRErrorCallbackNewTableFn *newtable, + struct PRErrorCallbackPrivate *cb_private); + +PR_END_EXTERN_C + +#endif /* prerror_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prinet.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prinet.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prinet.h @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* + * File: prinet.h + * Description: + * Header file used to find the system header files for socket support[1]. + * This file serves the following purposes: + * - A cross-platform, "get-everything" socket header file. On + * Unix, socket support is scattered in several header files, + * while Windows has a "get-everything" socket header file[2]. + * - NSPR needs the following macro definitions and function + * prototype declarations from these header files: + * AF_INET + * INADDR_ANY, INADDR_LOOPBACK, INADDR_BROADCAST + * ntohl(), ntohs(), htonl(), ntons(). + * NSPR does not define its own versions of these macros and + * functions. It simply uses the native versions, which have + * the same names on all supported platforms. + * This file is intended to be included by NSPR public header + * files, such as prio.h. One should not include this file directly. + * + * Notes: + * 1. This file should have been an internal header. Please do not + * depend on it to pull in the system header files you need. + * 2. WARNING: This file is no longer cross-platform as it is a no-op + * for WIN32! See the comment in the WIN32 section for details. + */ + +#ifndef prinet_h__ +#define prinet_h__ + +#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) +#include +#include /* AF_INET */ +#include /* INADDR_ANY, ..., ntohl(), ... */ +#ifdef XP_OS2 +#include +#endif +#ifdef XP_UNIX +#ifdef AIX +/* + * On AIX 4.3, the header refers to struct + * ether_addr and struct sockaddr_dl that are not declared. + * The following struct declarations eliminate the compiler + * warnings. + */ +struct ether_addr; +struct sockaddr_dl; +#endif /* AIX */ +#include +#endif /* XP_UNIX */ +#include + +#if defined(BSDI) || defined(QNX) +#include /* the only place that defines INADDR_LOOPBACK */ +#endif + +/* + * OS/2 hack. For some reason INADDR_LOOPBACK is not defined in the + * socket headers. + */ +#if defined(OS2) && !defined(INADDR_LOOPBACK) +#define INADDR_LOOPBACK 0x7f000001 +#endif + +/* + * Prototypes of ntohl() etc. are declared in + * on these platforms. + */ +#if defined(BSDI) || defined(OSF1) +#include +#endif + +/* On Android, ntohl() etc. are declared in . */ +#ifdef __ANDROID__ +#include +#endif + +#elif defined(WIN32) + +/* + * Do not include any system header files. + * + * Originally we were including . It slowed down the + * compilation of files that included NSPR headers, so we removed + * the inclusion at customer's request, which created + * an unfortunate inconsistency with other platforms. + */ + +#else + +#error Unknown platform + +#endif + +#endif /* prinet_h__ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prinit.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prinit.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prinit.h @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prinit_h___ +#define prinit_h___ + +#include "prthread.h" +#include "prtypes.h" +#include "prwin16.h" +#include + +PR_BEGIN_EXTERN_C + +/************************************************************************/ +/**************************IDENTITY AND VERSIONING***********************/ +/************************************************************************/ + +/* +** NSPR's name, this should persist until at least the turn of the +** century. +*/ +#define PR_NAME "NSPR" + +/* +** NSPR's version is used to determine the likelihood that the version you +** used to build your component is anywhere close to being compatible with +** what is in the underlying library. +** +** The format of the version string is +** ".[.] []" +*/ +#define PR_VERSION "4.19" +#define PR_VMAJOR 4 +#define PR_VMINOR 19 +#define PR_VPATCH 0 +#define PR_BETA PR_FALSE + +/* +** PRVersionCheck +** +** The basic signature of the function that is called to provide version +** checking. The result will be a boolean that indicates the likelihood +** that the underling library will perform as the caller expects. +** +** The only argument is a string, which should be the verson identifier +** of the library in question. That string will be compared against an +** equivalent string that represents the actual build version of the +** exporting library. +** +** The result will be the logical union of the directly called library +** and all dependent libraries. +*/ + +typedef PRBool (*PRVersionCheck)(const char*); + +/* +** PR_VersionCheck +** +** NSPR's existance proof of the version check function. +** +** Note that NSPR has no cooperating dependencies. +*/ + +NSPR_API(PRBool) PR_VersionCheck(const char *importedVersion); + +/* + * Returns a const string of the NSPR library version. + */ +NSPR_API(const char*) PR_GetVersion(void); + + +/************************************************************************/ +/*******************************INITIALIZATION***************************/ +/************************************************************************/ + +/* +** Initialize the runtime. Attach a thread object to the currently +** executing native thread of type "type". +** +** The specificaiton of 'maxPTDs' is ignored. +*/ +NSPR_API(void) PR_Init( + PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs); + +/* +** And alternate form of initialization, one that may become the default if +** not the only mechanism, provides a method to get the NSPR runtime init- +** ialized and place NSPR between the caller and the runtime library. This +** allows main() to be treated as any other thread root function, signalling +** its compeletion by returning and allowing the runtime to coordinate the +** completion of the other threads of the runtime. +** +** The priority of the main (or primordial) thread will be PR_PRIORITY_NORMAL. +** The thread may adjust its own priority by using PR_SetPriority(), though +** at this time the support for priorities is somewhat weak. +** +** The specificaiton of 'maxPTDs' is ignored. +** +** The value returned by PR_Initialize is the value returned from the root +** function, 'prmain'. +*/ + +typedef PRIntn (PR_CALLBACK *PRPrimordialFn)(PRIntn argc, char **argv); + +NSPR_API(PRIntn) PR_Initialize( + PRPrimordialFn prmain, PRIntn argc, char **argv, PRUintn maxPTDs); + +/* +** Return PR_TRUE if PR_Init has already been called. +*/ +NSPR_API(PRBool) PR_Initialized(void); + +/* + * Perform a graceful shutdown of NSPR. PR_Cleanup() may be called by + * the primordial thread near the end of the main() function. + * + * PR_Cleanup() attempts to synchronize the natural termination of + * process. It does that by blocking the caller, if and only if it is + * the primordial thread, until the number of user threads has dropped + * to zero. When the primordial thread returns from main(), the process + * will immediately and silently exit. That is, it will (if necessary) + * forcibly terminate any existing threads and exit without significant + * blocking and there will be no error messages or core files. + * + * PR_Cleanup() returns PR_SUCCESS if NSPR is successfully shutdown, + * or PR_FAILURE if the calling thread of this function is not the + * primordial thread. + */ +NSPR_API(PRStatus) PR_Cleanup(void); + +/* +** Disable Interrupts +** Disables timer signals used for pre-emptive scheduling. +*/ +NSPR_API(void) PR_DisableClockInterrupts(void); + +/* +** Enables Interrupts +** Enables timer signals used for pre-emptive scheduling. +*/ +NSPR_API(void) PR_EnableClockInterrupts(void); + +/* +** Block Interrupts +** Blocks the timer signal used for pre-emptive scheduling +*/ +NSPR_API(void) PR_BlockClockInterrupts(void); + +/* +** Unblock Interrupts +** Unblocks the timer signal used for pre-emptive scheduling +*/ +NSPR_API(void) PR_UnblockClockInterrupts(void); + +/* +** Create extra virtual processor threads. Generally used with MP systems. +*/ +NSPR_API(void) PR_SetConcurrency(PRUintn numCPUs); + +/* +** Control the method and size of the file descriptor (PRFileDesc*) +** cache used by the runtime. Setting 'high' to zero is for performance, +** any other value probably for debugging (see memo on FD caching). +*/ +NSPR_API(PRStatus) PR_SetFDCacheSize(PRIntn low, PRIntn high); + +/* + * Cause an immediate, nongraceful, forced termination of the process. + * It takes a PRIntn argument, which is the exit status code of the + * process. + */ +NSPR_API(void) PR_ProcessExit(PRIntn status); + +/* +** Abort the process in a non-graceful manner. This will cause a core file, +** call to the debugger or other moral equivalent as well as causing the +** entire process to stop. +*/ +NSPR_API(void) PR_Abort(void); + +/* + **************************************************************** + * + * Module initialization: + * + **************************************************************** + */ + +typedef struct PRCallOnceType { + PRIntn initialized; + PRInt32 inProgress; + PRStatus status; +} PRCallOnceType; + +typedef PRStatus (PR_CALLBACK *PRCallOnceFN)(void); + +typedef PRStatus (PR_CALLBACK *PRCallOnceWithArgFN)(void *arg); + +NSPR_API(PRStatus) PR_CallOnce( + PRCallOnceType *once, + PRCallOnceFN func +); + +NSPR_API(PRStatus) PR_CallOnceWithArg( + PRCallOnceType *once, + PRCallOnceWithArgFN func, + void *arg +); + + +PR_END_EXTERN_C + +#endif /* prinit_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prinrval.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prinrval.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prinrval.h @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: prinrval.h +** Description: API to interval timing functions of NSPR. +** +** +** NSPR provides interval times that are independent of network time +** of day values. Interval times are (in theory) accurate regardless +** of host processing requirements and also very cheap to acquire. It +** is expected that getting an interval time while in a synchronized +** function (holding one's lock). +**/ + +#if !defined(prinrval_h) +#define prinrval_h + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +typedef PRUint32 PRIntervalTime; + +/*********************************************************************** +** DEFINES: PR_INTERVAL_MIN +** PR_INTERVAL_MAX +** DESCRIPTION: +** These two constants define the range (in ticks / second) of the +** platform dependent type, PRIntervalTime. These constants bound both +** the period and the resolution of a PRIntervalTime. +***********************************************************************/ +#define PR_INTERVAL_MIN 1000UL +#define PR_INTERVAL_MAX 100000UL + +/*********************************************************************** +** DEFINES: PR_INTERVAL_NO_WAIT +** PR_INTERVAL_NO_TIMEOUT +** DESCRIPTION: +** Two reserved constants are defined in the PRIntervalTime namespace. +** They are used to indicate that the process should wait no time (return +** immediately) or wait forever (never time out), respectively. +** Note: PR_INTERVAL_NO_TIMEOUT passed as input to PR_Connect is +** interpreted as use the OS's connect timeout. +** +***********************************************************************/ +#define PR_INTERVAL_NO_WAIT 0UL +#define PR_INTERVAL_NO_TIMEOUT 0xffffffffUL + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/*********************************************************************** +** FUNCTION: PR_IntervalNow +** DESCRIPTION: +** Return the value of NSPR's free running interval timer. That timer +** can be used to establish epochs and determine intervals (be computing +** the difference between two times). +** INPUTS: void +** OUTPUTS: void +** RETURN: PRIntervalTime +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** The units of PRIntervalTime are platform dependent. They are chosen +** such that they are appropriate for the host OS, yet provide sufficient +** resolution and period to be useful to clients. +** MEMORY: N/A +** ALGORITHM: Platform dependent +***********************************************************************/ +NSPR_API(PRIntervalTime) PR_IntervalNow(void); + +/*********************************************************************** +** FUNCTION: PR_TicksPerSecond +** DESCRIPTION: +** Return the number of ticks per second for PR_IntervalNow's clock. +** The value will be in the range [PR_INTERVAL_MIN..PR_INTERVAL_MAX]. +** INPUTS: void +** OUTPUTS: void +** RETURN: PRUint32 +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** None +** MEMORY: N/A +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRUint32) PR_TicksPerSecond(void); + +/*********************************************************************** +** FUNCTION: PR_SecondsToInterval +** PR_MillisecondsToInterval +** PR_MicrosecondsToInterval +** DESCRIPTION: +** Convert standard clock units to platform dependent intervals. +** INPUTS: PRUint32 +** OUTPUTS: void +** RETURN: PRIntervalTime +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** Conversion may cause overflow, which is not reported. +** MEMORY: N/A +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRIntervalTime) PR_SecondsToInterval(PRUint32 seconds); +NSPR_API(PRIntervalTime) PR_MillisecondsToInterval(PRUint32 milli); +NSPR_API(PRIntervalTime) PR_MicrosecondsToInterval(PRUint32 micro); + +/*********************************************************************** +** FUNCTION: PR_IntervalToSeconds +** PR_IntervalToMilliseconds +** PR_IntervalToMicroseconds +** DESCRIPTION: +** Convert platform dependent intervals to standard clock units. +** INPUTS: PRIntervalTime +** OUTPUTS: void +** RETURN: PRUint32 +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** Conversion may cause overflow, which is not reported. +** MEMORY: N/A +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRUint32) PR_IntervalToSeconds(PRIntervalTime ticks); +NSPR_API(PRUint32) PR_IntervalToMilliseconds(PRIntervalTime ticks); +NSPR_API(PRUint32) PR_IntervalToMicroseconds(PRIntervalTime ticks); + +PR_END_EXTERN_C + + +#endif /* !defined(prinrval_h) */ + +/* prinrval.h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prio.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prio.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prio.h @@ -0,0 +1,2022 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* + * File: prio.h + * + * Description: PR i/o related stuff, such as file system access, file + * i/o, socket i/o, etc. + */ + +#ifndef prio_h___ +#define prio_h___ + +#include "prlong.h" +#include "prtime.h" +#include "prinrval.h" +#include "prinet.h" + +PR_BEGIN_EXTERN_C + +/* Typedefs */ +typedef struct PRDir PRDir; +typedef struct PRDirEntry PRDirEntry; +#ifdef MOZ_UNICODE +typedef struct PRDirUTF16 PRDirUTF16; +typedef struct PRDirEntryUTF16 PRDirEntryUTF16; +#endif /* MOZ_UNICODE */ +typedef struct PRFileDesc PRFileDesc; +typedef struct PRFileInfo PRFileInfo; +typedef struct PRFileInfo64 PRFileInfo64; +typedef union PRNetAddr PRNetAddr; +typedef struct PRIOMethods PRIOMethods; +typedef struct PRPollDesc PRPollDesc; +typedef struct PRFilePrivate PRFilePrivate; +typedef struct PRSendFileData PRSendFileData; + +/* +*************************************************************************** +** The file descriptor. +** This is the primary structure to represent any active open socket, +** whether it be a normal file or a network connection. Such objects +** are stackable (or layerable). Each layer may have its own set of +** method pointers and context private to that layer. All each layer +** knows about its neighbors is how to get to their method table. +*************************************************************************** +*/ + +typedef PRIntn PRDescIdentity; /* see: Layering file descriptors */ + +struct PRFileDesc { + const PRIOMethods *methods; /* the I/O methods table */ + PRFilePrivate *secret; /* layer dependent data */ + PRFileDesc *lower, *higher; /* pointers to adjacent layers */ + void (PR_CALLBACK *dtor)(PRFileDesc *fd); + /* A destructor function for layer */ + PRDescIdentity identity; /* Identity of this particular layer */ +}; + +/* +*************************************************************************** +** PRTransmitFileFlags +** +** Flags for PR_TransmitFile. Pass PR_TRANSMITFILE_CLOSE_SOCKET to +** PR_TransmitFile if the connection should be closed after the file +** is transmitted. +*************************************************************************** +*/ +typedef enum PRTransmitFileFlags { + PR_TRANSMITFILE_KEEP_OPEN = 0, /* socket is left open after file + * is transmitted. */ + PR_TRANSMITFILE_CLOSE_SOCKET = 1 /* socket is closed after file + * is transmitted. */ +} PRTransmitFileFlags; + +/* +************************************************************************** +** Macros for PRNetAddr +** +** Address families: PR_AF_INET, PR_AF_INET6, PR_AF_LOCAL +** IP addresses: PR_INADDR_ANY, PR_INADDR_LOOPBACK, PR_INADDR_BROADCAST +************************************************************************** +*/ + +#ifdef WIN32 + +#define PR_AF_INET 2 +#define PR_AF_LOCAL 1 +#define PR_INADDR_ANY (unsigned long)0x00000000 +#define PR_INADDR_LOOPBACK 0x7f000001 +#define PR_INADDR_BROADCAST (unsigned long)0xffffffff + +#else /* WIN32 */ + +#define PR_AF_INET AF_INET +#define PR_AF_LOCAL AF_UNIX +#define PR_INADDR_ANY INADDR_ANY +#define PR_INADDR_LOOPBACK INADDR_LOOPBACK +#define PR_INADDR_BROADCAST INADDR_BROADCAST + +#endif /* WIN32 */ + +/* +** Define PR_AF_INET6 in prcpucfg.h with the same +** value as AF_INET6 on platforms with IPv6 support. +** Otherwise define it here. +*/ +#ifndef PR_AF_INET6 +#define PR_AF_INET6 100 +#endif + +#define PR_AF_INET_SDP 101 +#define PR_AF_INET6_SDP 102 + +#ifndef PR_AF_UNSPEC +#define PR_AF_UNSPEC 0 +#endif + +/* +************************************************************************** +** A network address +** +** Only Internet Protocol (IPv4 and IPv6) addresses are supported. +** The address family must always represent IPv4 (AF_INET, probably == 2) +** or IPv6 (AF_INET6). +************************************************************************** +*************************************************************************/ + +struct PRIPv6Addr { + union { + PRUint8 _S6_u8[16]; + PRUint16 _S6_u16[8]; + PRUint32 _S6_u32[4]; + PRUint64 _S6_u64[2]; + } _S6_un; +}; +#define pr_s6_addr _S6_un._S6_u8 +#define pr_s6_addr16 _S6_un._S6_u16 +#define pr_s6_addr32 _S6_un._S6_u32 +#define pr_s6_addr64 _S6_un._S6_u64 + +typedef struct PRIPv6Addr PRIPv6Addr; + +union PRNetAddr { + struct { + PRUint16 family; /* address family (0x00ff maskable) */ +#ifdef XP_BEOS + char data[10]; /* Be has a smaller structure */ +#else + char data[14]; /* raw address data */ +#endif + } raw; + struct { + PRUint16 family; /* address family (AF_INET) */ + PRUint16 port; /* port number */ + PRUint32 ip; /* The actual 32 bits of address */ +#ifdef XP_BEOS + char pad[4]; /* Be has a smaller structure */ +#else + char pad[8]; +#endif + } inet; + struct { + PRUint16 family; /* address family (AF_INET6) */ + PRUint16 port; /* port number */ + PRUint32 flowinfo; /* routing information */ + PRIPv6Addr ip; /* the actual 128 bits of address */ + PRUint32 scope_id; /* set of interfaces for a scope */ + } ipv6; +#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_WIN) + struct { /* Unix domain socket address */ + PRUint16 family; /* address family (AF_UNIX) */ +#ifdef XP_OS2 + char path[108]; /* null-terminated pathname */ + /* bind fails if size is not 108. */ +#else + char path[104]; /* null-terminated pathname */ +#endif + } local; +#endif +}; + +/* +*************************************************************************** +** PRSockOption +** +** The file descriptors can have predefined options set after they file +** descriptor is created to change their behavior. Only the options in +** the following enumeration are supported. +*************************************************************************** +*/ +typedef enum PRSockOption +{ + PR_SockOpt_Nonblocking, /* nonblocking io */ + PR_SockOpt_Linger, /* linger on close if data present */ + PR_SockOpt_Reuseaddr, /* allow local address reuse */ + PR_SockOpt_Keepalive, /* keep connections alive */ + PR_SockOpt_RecvBufferSize, /* receive buffer size */ + PR_SockOpt_SendBufferSize, /* send buffer size */ + + PR_SockOpt_IpTimeToLive, /* time to live */ + PR_SockOpt_IpTypeOfService, /* type of service and precedence */ + + PR_SockOpt_AddMember, /* add an IP group membership */ + PR_SockOpt_DropMember, /* drop an IP group membership */ + PR_SockOpt_McastInterface, /* multicast interface address */ + PR_SockOpt_McastTimeToLive, /* multicast timetolive */ + PR_SockOpt_McastLoopback, /* multicast loopback */ + + PR_SockOpt_NoDelay, /* don't delay send to coalesce packets */ + PR_SockOpt_MaxSegment, /* maximum segment size */ + PR_SockOpt_Broadcast, /* enable broadcast */ + PR_SockOpt_Reuseport, /* allow local address & port reuse on + * platforms that support it */ + PR_SockOpt_Last +} PRSockOption; + +typedef struct PRLinger { + PRBool polarity; /* Polarity of the option's setting */ + PRIntervalTime linger; /* Time to linger before closing */ +} PRLinger; + +typedef struct PRMcastRequest { + PRNetAddr mcaddr; /* IP multicast address of group */ + PRNetAddr ifaddr; /* local IP address of interface */ +} PRMcastRequest; + +typedef struct PRSocketOptionData +{ + PRSockOption option; + union + { + PRUintn ip_ttl; /* IP time to live */ + PRUintn mcast_ttl; /* IP multicast time to live */ + PRUintn tos; /* IP type of service and precedence */ + PRBool non_blocking; /* Non-blocking (network) I/O */ + PRBool reuse_addr; /* Allow local address reuse */ + PRBool reuse_port; /* Allow local address & port reuse on + * platforms that support it */ + PRBool keep_alive; /* Keep connections alive */ + PRBool mcast_loopback; /* IP multicast loopback */ + PRBool no_delay; /* Don't delay send to coalesce packets */ + PRBool broadcast; /* Enable broadcast */ + PRSize max_segment; /* Maximum segment size */ + PRSize recv_buffer_size; /* Receive buffer size */ + PRSize send_buffer_size; /* Send buffer size */ + PRLinger linger; /* Time to linger on close if data present */ + PRMcastRequest add_member; /* add an IP group membership */ + PRMcastRequest drop_member; /* Drop an IP group membership */ + PRNetAddr mcast_if; /* multicast interface address */ + } value; +} PRSocketOptionData; + +/* +*************************************************************************** +** PRIOVec +** +** The I/O vector is used by the write vector method to describe the areas +** that are affected by the ouput operation. +*************************************************************************** +*/ +typedef struct PRIOVec { + char *iov_base; + int iov_len; +} PRIOVec; + +/* +*************************************************************************** +** Discover what type of socket is being described by the file descriptor. +*************************************************************************** +*/ +typedef enum PRDescType +{ + PR_DESC_FILE = 1, + PR_DESC_SOCKET_TCP = 2, + PR_DESC_SOCKET_UDP = 3, + PR_DESC_LAYERED = 4, + PR_DESC_PIPE = 5 +} PRDescType; + +typedef enum PRSeekWhence { + PR_SEEK_SET = 0, + PR_SEEK_CUR = 1, + PR_SEEK_END = 2 +} PRSeekWhence; + +NSPR_API(PRDescType) PR_GetDescType(PRFileDesc *file); + +/* +*************************************************************************** +** PRIOMethods +** +** The I/O methods table provides procedural access to the functions of +** the file descriptor. It is the responsibility of a layer implementor +** to provide suitable functions at every entry point. If a layer provides +** no functionality, it should call the next lower(higher) function of the +** same name (e.g., return fd->lower->method->close(fd->lower)); +** +** Not all functions are implemented for all types of files. In cases where +** that is true, the function will return a error indication with an error +** code of PR_INVALID_METHOD_ERROR. +*************************************************************************** +*/ + +typedef PRStatus (PR_CALLBACK *PRCloseFN)(PRFileDesc *fd); +typedef PRInt32 (PR_CALLBACK *PRReadFN)(PRFileDesc *fd, void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRWriteFN)(PRFileDesc *fd, const void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRAvailableFN)(PRFileDesc *fd); +typedef PRInt64 (PR_CALLBACK *PRAvailable64FN)(PRFileDesc *fd); +typedef PRStatus (PR_CALLBACK *PRFsyncFN)(PRFileDesc *fd); +typedef PROffset32 (PR_CALLBACK *PRSeekFN)(PRFileDesc *fd, PROffset32 offset, PRSeekWhence how); +typedef PROffset64 (PR_CALLBACK *PRSeek64FN)(PRFileDesc *fd, PROffset64 offset, PRSeekWhence how); +typedef PRStatus (PR_CALLBACK *PRFileInfoFN)(PRFileDesc *fd, PRFileInfo *info); +typedef PRStatus (PR_CALLBACK *PRFileInfo64FN)(PRFileDesc *fd, PRFileInfo64 *info); +typedef PRInt32 (PR_CALLBACK *PRWritevFN)( + PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, + PRIntervalTime timeout); +typedef PRStatus (PR_CALLBACK *PRConnectFN)( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout); +typedef PRFileDesc* (PR_CALLBACK *PRAcceptFN) ( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout); +typedef PRStatus (PR_CALLBACK *PRBindFN)(PRFileDesc *fd, const PRNetAddr *addr); +typedef PRStatus (PR_CALLBACK *PRListenFN)(PRFileDesc *fd, PRIntn backlog); +typedef PRStatus (PR_CALLBACK *PRShutdownFN)(PRFileDesc *fd, PRIntn how); +typedef PRInt32 (PR_CALLBACK *PRRecvFN)( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); +typedef PRInt32 (PR_CALLBACK *PRSendFN) ( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); +typedef PRInt32 (PR_CALLBACK *PRRecvfromFN)( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout); +typedef PRInt32 (PR_CALLBACK *PRSendtoFN)( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout); +typedef PRInt16 (PR_CALLBACK *PRPollFN)( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags); +typedef PRInt32 (PR_CALLBACK *PRAcceptreadFN)( + PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, + void *buf, PRInt32 amount, PRIntervalTime t); +typedef PRInt32 (PR_CALLBACK *PRTransmitfileFN)( + PRFileDesc *sd, PRFileDesc *fd, const void *headers, + PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime t); +typedef PRStatus (PR_CALLBACK *PRGetsocknameFN)(PRFileDesc *fd, PRNetAddr *addr); +typedef PRStatus (PR_CALLBACK *PRGetpeernameFN)(PRFileDesc *fd, PRNetAddr *addr); +typedef PRStatus (PR_CALLBACK *PRGetsocketoptionFN)( + PRFileDesc *fd, PRSocketOptionData *data); +typedef PRStatus (PR_CALLBACK *PRSetsocketoptionFN)( + PRFileDesc *fd, const PRSocketOptionData *data); +typedef PRInt32 (PR_CALLBACK *PRSendfileFN)( + PRFileDesc *networkSocket, PRSendFileData *sendData, + PRTransmitFileFlags flags, PRIntervalTime timeout); +typedef PRStatus (PR_CALLBACK *PRConnectcontinueFN)( + PRFileDesc *fd, PRInt16 out_flags); +typedef PRIntn (PR_CALLBACK *PRReservedFN)(PRFileDesc *fd); + +struct PRIOMethods { + PRDescType file_type; /* Type of file represented (tos) */ + PRCloseFN close; /* close file and destroy descriptor */ + PRReadFN read; /* read up to specified bytes into buffer */ + PRWriteFN write; /* write specified bytes from buffer */ + PRAvailableFN available; /* determine number of bytes available */ + PRAvailable64FN available64; /* ditto, 64 bit */ + PRFsyncFN fsync; /* flush all buffers to permanent store */ + PRSeekFN seek; /* position the file to the desired place */ + PRSeek64FN seek64; /* ditto, 64 bit */ + PRFileInfoFN fileInfo; /* Get information about an open file */ + PRFileInfo64FN fileInfo64; /* ditto, 64 bit */ + PRWritevFN writev; /* Write segments as described by iovector */ + PRConnectFN connect; /* Connect to the specified (net) address */ + PRAcceptFN accept; /* Accept a connection for a (net) peer */ + PRBindFN bind; /* Associate a (net) address with the fd */ + PRListenFN listen; /* Prepare to listen for (net) connections */ + PRShutdownFN shutdown; /* Shutdown a (net) connection */ + PRRecvFN recv; /* Solicit up the the specified bytes */ + PRSendFN send; /* Send all the bytes specified */ + PRRecvfromFN recvfrom; /* Solicit (net) bytes and report source */ + PRSendtoFN sendto; /* Send bytes to (net) address specified */ + PRPollFN poll; /* Test the fd to see if it is ready */ + PRAcceptreadFN acceptread; /* Accept and read on a new (net) fd */ + PRTransmitfileFN transmitfile; /* Transmit at entire file */ + PRGetsocknameFN getsockname; /* Get (net) address associated with fd */ + PRGetpeernameFN getpeername; /* Get peer's (net) address */ + PRReservedFN reserved_fn_6; /* reserved for future use */ + PRReservedFN reserved_fn_5; /* reserved for future use */ + PRGetsocketoptionFN getsocketoption; + /* Get current setting of specified option */ + PRSetsocketoptionFN setsocketoption; + /* Set value of specified option */ + PRSendfileFN sendfile; /* Send a (partial) file with header/trailer*/ + PRConnectcontinueFN connectcontinue; + /* Continue a nonblocking connect */ + PRReservedFN reserved_fn_3; /* reserved for future use */ + PRReservedFN reserved_fn_2; /* reserved for future use */ + PRReservedFN reserved_fn_1; /* reserved for future use */ + PRReservedFN reserved_fn_0; /* reserved for future use */ +}; + +/* + ************************************************************************** + * FUNCTION: PR_GetSpecialFD + * DESCRIPTION: Get the file descriptor that represents the standard input, + * output, or error stream. + * INPUTS: + * PRSpecialFD id + * A value indicating the type of stream desired: + * PR_StandardInput: standard input + * PR_StandardOuput: standard output + * PR_StandardError: standard error + * OUTPUTS: none + * RETURNS: PRFileDesc * + * If the argument is valid, PR_GetSpecialFD returns a file descriptor + * that represents the corresponding standard I/O stream. Otherwise, + * PR_GetSpecialFD returns NULL and sets error PR_INVALID_ARGUMENT_ERROR. + ************************************************************************** + */ + +typedef enum PRSpecialFD +{ + PR_StandardInput, /* standard input */ + PR_StandardOutput, /* standard output */ + PR_StandardError /* standard error */ +} PRSpecialFD; + +NSPR_API(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD id); + +#define PR_STDIN PR_GetSpecialFD(PR_StandardInput) +#define PR_STDOUT PR_GetSpecialFD(PR_StandardOutput) +#define PR_STDERR PR_GetSpecialFD(PR_StandardError) + +/* + ************************************************************************** + * Layering file descriptors + * + * File descriptors may be layered. Each layer has it's own identity. + * Identities are allocated by the runtime and are to be associated + * (by the layer implementor) with all layers that are of that type. + * It is then possible to scan the chain of layers and find a layer + * that one recongizes and therefore predict that it will implement + * a desired protocol. + * + * There are three well-known identities: + * PR_INVALID_IO_LAYER => an invalid layer identity, for error return + * PR_TOP_IO_LAYER => the identity of the top of the stack + * PR_NSPR_IO_LAYER => the identity used by NSPR proper + * PR_TOP_IO_LAYER may be used as a shorthand for identifying the topmost + * layer of an existing stack. Ie., the following two constructs are + * equivalent. + * + * rv = PR_PushIOLayer(stack, PR_TOP_IO_LAYER, my_layer); + * rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), my_layer) + * + * A string may be associated with the creation of the identity. It + * will be copied by the runtime. If queried the runtime will return + * a reference to that copied string (not yet another copy). There + * is no facility for deleting an identity. + ************************************************************************** + */ + +#define PR_IO_LAYER_HEAD (PRDescIdentity)-3 +#define PR_INVALID_IO_LAYER (PRDescIdentity)-1 +#define PR_TOP_IO_LAYER (PRDescIdentity)-2 +#define PR_NSPR_IO_LAYER (PRDescIdentity)0 + +NSPR_API(PRDescIdentity) PR_GetUniqueIdentity(const char *layer_name); +NSPR_API(const char*) PR_GetNameForIdentity(PRDescIdentity ident); +NSPR_API(PRDescIdentity) PR_GetLayersIdentity(PRFileDesc* fd); +NSPR_API(PRFileDesc*) PR_GetIdentitiesLayer(PRFileDesc* fd_stack, PRDescIdentity id); + +/* + ************************************************************************** + * PR_GetDefaultIOMethods: Accessing the default methods table. + * You may get a pointer to the default methods table by calling this function. + * You may then select any elements from that table with which to build your + * layer's methods table. You may NOT modify the table directly. + ************************************************************************** + */ +NSPR_API(const PRIOMethods *) PR_GetDefaultIOMethods(void); + +/* + ************************************************************************** + * Creating a layer + * + * A new layer may be allocated by calling PR_CreateIOLayerStub(). The + * file descriptor returned will contain the pointer to the methods table + * provided. The runtime will not modify the table nor test its correctness. + ************************************************************************** + */ +NSPR_API(PRFileDesc*) PR_CreateIOLayerStub( + PRDescIdentity ident, const PRIOMethods *methods); + +/* + ************************************************************************** + * Creating a layer + * + * A new stack may be created by calling PR_CreateIOLayer(). The + * file descriptor returned will point to the top of the stack, which has + * the layer 'fd' as the topmost layer. + * + * NOTE: This function creates a new style stack, which has a fixed, dummy + * header. The old style stack, created by a call to PR_PushIOLayer, + * results in modifying contents of the top layer of the stack, when + * pushing and popping layers of the stack. + ************************************************************************** + */ +NSPR_API(PRFileDesc*) PR_CreateIOLayer(PRFileDesc* fd); + +/* + ************************************************************************** + * Pushing a layer + * + * A file descriptor (perhaps allocated using PR_CreateIOLayerStub()) may + * be pushed into an existing stack of file descriptors at any point the + * caller deems appropriate. The new layer will be inserted into the stack + * just above the layer with the indicated identity. + * + * Note: Even if the identity parameter indicates the top-most layer of + * the stack, the value of the file descriptor describing the original + * stack will not change. + ************************************************************************** + */ +NSPR_API(PRStatus) PR_PushIOLayer( + PRFileDesc *fd_stack, PRDescIdentity id, PRFileDesc *layer); + +/* + ************************************************************************** + * Popping a layer + * + * A layer may be popped from a stack by indicating the identity of the + * layer to be removed. If found, a pointer to the removed object will + * be returned to the caller. The object then becomes the responsibility + * of the caller. + * + * Note: Even if the identity indicates the top layer of the stack, the + * reference returned will not be the file descriptor for the stack and + * that file descriptor will remain valid. + ************************************************************************** + */ +NSPR_API(PRFileDesc*) PR_PopIOLayer(PRFileDesc *fd_stack, PRDescIdentity id); + +/* + ************************************************************************** + * FUNCTION: PR_Open + * DESCRIPTION: Open a file for reading, writing, or both. + * INPUTS: + * const char *name + * The path name of the file to be opened + * PRIntn flags + * The file status flags. + * It is a bitwise OR of the following bit flags (only one of + * the first three flags below may be used): + * PR_RDONLY Open for reading only. + * PR_WRONLY Open for writing only. + * PR_RDWR Open for reading and writing. + * PR_CREATE_FILE If the file does not exist, the file is created + * If the file exists, this flag has no effect. + * PR_SYNC If set, each write will wait for both the file data + * and file status to be physically updated. + * PR_APPEND The file pointer is set to the end of + * the file prior to each write. + * PR_TRUNCATE If the file exists, its length is truncated to 0. + * PR_EXCL With PR_CREATE_FILE, if the file does not exist, + * the file is created. If the file already + * exists, no action and NULL is returned + * + * PRIntn mode + * The access permission bits of the file mode, if the file is + * created when PR_CREATE_FILE is on. + * OUTPUTS: None + * RETURNS: PRFileDesc * + * If the file is successfully opened, + * returns a pointer to the PRFileDesc + * created for the newly opened file. + * Returns a NULL pointer if the open + * failed. + * SIDE EFFECTS: + * RESTRICTIONS: + * MEMORY: + * The return value, if not NULL, points to a dynamically allocated + * PRFileDesc object. + * ALGORITHM: + ************************************************************************** + */ + +/* Open flags */ +#define PR_RDONLY 0x01 +#define PR_WRONLY 0x02 +#define PR_RDWR 0x04 +#define PR_CREATE_FILE 0x08 +#define PR_APPEND 0x10 +#define PR_TRUNCATE 0x20 +#define PR_SYNC 0x40 +#define PR_EXCL 0x80 + +/* +** File modes .... +** +** CAVEAT: 'mode' is currently only applicable on UNIX platforms. +** The 'mode' argument may be ignored by PR_Open on other platforms. +** +** 00400 Read by owner. +** 00200 Write by owner. +** 00100 Execute (search if a directory) by owner. +** 00040 Read by group. +** 00020 Write by group. +** 00010 Execute by group. +** 00004 Read by others. +** 00002 Write by others +** 00001 Execute by others. +** +*/ + +NSPR_API(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode); + +/* + ************************************************************************** + * FUNCTION: PR_OpenFile + * DESCRIPTION: + * Open a file for reading, writing, or both. + * PR_OpenFile has the same prototype as PR_Open but implements + * the specified file mode where possible. + ************************************************************************** + */ + +/* File mode bits */ +#define PR_IRWXU 00700 /* read, write, execute/search by owner */ +#define PR_IRUSR 00400 /* read permission, owner */ +#define PR_IWUSR 00200 /* write permission, owner */ +#define PR_IXUSR 00100 /* execute/search permission, owner */ +#define PR_IRWXG 00070 /* read, write, execute/search by group */ +#define PR_IRGRP 00040 /* read permission, group */ +#define PR_IWGRP 00020 /* write permission, group */ +#define PR_IXGRP 00010 /* execute/search permission, group */ +#define PR_IRWXO 00007 /* read, write, execute/search by others */ +#define PR_IROTH 00004 /* read permission, others */ +#define PR_IWOTH 00002 /* write permission, others */ +#define PR_IXOTH 00001 /* execute/search permission, others */ + +NSPR_API(PRFileDesc*) PR_OpenFile( + const char *name, PRIntn flags, PRIntn mode); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRFileDesc*) PR_OpenFileUTF16( + const PRUnichar *name, PRIntn flags, PRIntn mode); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************** + * FUNCTION: PR_Close + * DESCRIPTION: + * Close a file or socket. + * INPUTS: + * PRFileDesc *fd + * a pointer to a PRFileDesc. + * OUTPUTS: + * None. + * RETURN: + * PRStatus + * SIDE EFFECTS: + * RESTRICTIONS: + * None. + * MEMORY: + * The dynamic memory pointed to by the argument fd is freed. + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Close(PRFileDesc *fd); + +/* + ************************************************************************** + * FUNCTION: PR_Read + * DESCRIPTION: + * Read bytes from a file or socket. + * The operation will block until either an end of stream indication is + * encountered, some positive number of bytes are transferred, or there + * is an error. No more than 'amount' bytes will be transferred. + * INPUTS: + * PRFileDesc *fd + * pointer to the PRFileDesc object for the file or socket + * void *buf + * pointer to a buffer to hold the data read in. + * PRInt32 amount + * the size of 'buf' (in bytes) + * OUTPUTS: + * RETURN: + * PRInt32 + * a positive number indicates the number of bytes actually read in. + * 0 means end of file is reached or the network connection is closed. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + * SIDE EFFECTS: + * data is written into the buffer pointed to by 'buf'. + * RESTRICTIONS: + * None. + * MEMORY: + * N/A + * ALGORITHM: + * N/A + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_Read(PRFileDesc *fd, void *buf, PRInt32 amount); + +/* + *************************************************************************** + * FUNCTION: PR_Write + * DESCRIPTION: + * Write a specified number of bytes to a file or socket. The thread + * invoking this function blocks until all the data is written. + * INPUTS: + * PRFileDesc *fd + * pointer to a PRFileDesc object that refers to a file or socket + * const void *buf + * pointer to the buffer holding the data + * PRInt32 amount + * amount of data in bytes to be written from the buffer + * OUTPUTS: + * None. + * RETURN: PRInt32 + * A positive number indicates the number of bytes successfully written. + * A -1 is an indication that the operation failed. The reason + * for the failure is obtained by calling PR_GetError(). + *************************************************************************** + */ + +NSPR_API(PRInt32) PR_Write(PRFileDesc *fd,const void *buf,PRInt32 amount); + +/* + *************************************************************************** + * FUNCTION: PR_Writev + * DESCRIPTION: + * Write data to a socket. The data is organized in a PRIOVec array. The + * operation will block until all the data is written or the operation + * fails. + * INPUTS: + * PRFileDesc *fd + * Pointer that points to a PRFileDesc object for a socket. + * const PRIOVec *iov + * An array of PRIOVec. PRIOVec is a struct with the following + * two fields: + * char *iov_base; + * int iov_len; + * PRInt32 iov_size + * Number of elements in the iov array. The value of this + * argument must not be greater than PR_MAX_IOVECTOR_SIZE. + * If it is, the method will fail (PR_BUFFER_OVERFLOW_ERROR). + * PRIntervalTime timeout + * Time limit for completion of the entire write operation. + * OUTPUTS: + * None + * RETURN: + * A positive number indicates the number of bytes successfully written. + * A -1 is an indication that the operation failed. The reason + * for the failure is obtained by calling PR_GetError(). + *************************************************************************** + */ + +#define PR_MAX_IOVECTOR_SIZE 16 /* 'iov_size' must be <= */ + +NSPR_API(PRInt32) PR_Writev( + PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, + PRIntervalTime timeout); + +/* + *************************************************************************** + * FUNCTION: PR_Delete + * DESCRIPTION: + * Delete a file from the filesystem. The operation may fail if the + * file is open. + * INPUTS: + * const char *name + * Path name of the file to be deleted. + * OUTPUTS: + * None. + * RETURN: PRStatus + * The function returns PR_SUCCESS if the file is successfully + * deleted, otherwise it returns PR_FAILURE. + *************************************************************************** + */ + +NSPR_API(PRStatus) PR_Delete(const char *name); + +/**************************************************************************/ + +typedef enum PRFileType +{ + PR_FILE_FILE = 1, + PR_FILE_DIRECTORY = 2, + PR_FILE_OTHER = 3 +} PRFileType; + +struct PRFileInfo { + PRFileType type; /* Type of file */ + PROffset32 size; /* Size, in bytes, of file's contents */ + PRTime creationTime; /* Creation time per definition of PRTime */ + PRTime modifyTime; /* Last modification time per definition of PRTime */ +}; + +struct PRFileInfo64 { + PRFileType type; /* Type of file */ + PROffset64 size; /* Size, in bytes, of file's contents */ + PRTime creationTime; /* Creation time per definition of PRTime */ + PRTime modifyTime; /* Last modification time per definition of PRTime */ +}; + +/**************************************************************************** + * FUNCTION: PR_GetFileInfo, PR_GetFileInfo64 + * DESCRIPTION: + * Get the information about the file with the given path name. This is + * applicable only to NSFileDesc describing 'file' types (see + * INPUTS: + * const char *fn + * path name of the file + * OUTPUTS: + * PRFileInfo *info + * Information about the given file is written into the file + * information object pointer to by 'info'. + * RETURN: PRStatus + * PR_GetFileInfo returns PR_SUCCESS if file information is successfully + * obtained, otherwise it returns PR_FAILURE. + *************************************************************************** + */ + +NSPR_API(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info); +NSPR_API(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************** + * FUNCTION: PR_GetOpenFileInfo, PR_GetOpenFileInfo64 + * DESCRIPTION: + * Get information about an open file referred to by the + * given PRFileDesc object. + * INPUTS: + * const PRFileDesc *fd + * A reference to a valid, open file. + * OUTPUTS: + * Same as PR_GetFileInfo, PR_GetFileInfo64 + * RETURN: PRStatus + * PR_GetFileInfo returns PR_SUCCESS if file information is successfully + * obtained, otherwise it returns PR_FAILURE. + *************************************************************************** + */ + +NSPR_API(PRStatus) PR_GetOpenFileInfo(PRFileDesc *fd, PRFileInfo *info); +NSPR_API(PRStatus) PR_GetOpenFileInfo64(PRFileDesc *fd, PRFileInfo64 *info); + +/* + ************************************************************************** + * FUNCTION: PR_Rename + * DESCRIPTION: + * Rename a file from the old name 'from' to the new name 'to'. + * INPUTS: + * const char *from + * The old name of the file to be renamed. + * const char *to + * The new name of the file. + * OUTPUTS: + * None. + * RETURN: PRStatus + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Rename(const char *from, const char *to); + +/* + ************************************************************************* + * FUNCTION: PR_Access + * DESCRIPTION: + * Determine accessibility of a file. + * INPUTS: + * const char *name + * path name of the file + * PRAccessHow how + * specifies which access permission to check for. + * It can be one of the following values: + * PR_ACCESS_READ_OK Test for read permission + * PR_ACCESS_WRITE_OK Test for write permission + * PR_ACCESS_EXISTS Check existence of file + * OUTPUTS: + * None. + * RETURN: PRStatus + * PR_SUCCESS is returned if the requested access is permitted. + * Otherwise, PR_FAILURE is returned. Additional information + * regarding the reason for the failure may be retrieved from + * PR_GetError(). + ************************************************************************* + */ + +typedef enum PRAccessHow { + PR_ACCESS_EXISTS = 1, + PR_ACCESS_WRITE_OK = 2, + PR_ACCESS_READ_OK = 3 +} PRAccessHow; + +NSPR_API(PRStatus) PR_Access(const char *name, PRAccessHow how); + +/* + ************************************************************************* + * FUNCTION: PR_Seek, PR_Seek64 + * DESCRIPTION: + * Moves read-write file offset + * INPUTS: + * PRFileDesc *fd + * Pointer to a PRFileDesc object. + * PROffset32, PROffset64 offset + * Specifies a value, in bytes, that is used in conjunction + * with the 'whence' parameter to set the file pointer. A + * negative value causes seeking in the reverse direction. + * PRSeekWhence whence + * Specifies how to interpret the 'offset' parameter in setting + * the file pointer associated with the 'fd' parameter. + * Values for the 'whence' parameter are: + * PR_SEEK_SET Sets the file pointer to the value of the + * 'offset' parameter + * PR_SEEK_CUR Sets the file pointer to its current location + * plus the value of the offset parameter. + * PR_SEEK_END Sets the file pointer to the size of the + * file plus the value of the offset parameter. + * OUTPUTS: + * None. + * RETURN: PROffset32, PROffset64 + * Upon successful completion, the resulting pointer location, + * measured in bytes from the beginning of the file, is returned. + * If the PR_Seek() function fails, the file offset remains + * unchanged, and the returned value is -1. The error code can + * then be retrieved via PR_GetError(). + ************************************************************************* + */ + +NSPR_API(PROffset32) PR_Seek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence); +NSPR_API(PROffset64) PR_Seek64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence); + +/* + ************************************************************************ + * FUNCTION: PR_Available + * DESCRIPTION: + * Determine the amount of data in bytes available for reading + * in the given file or socket. + * INPUTS: + * PRFileDesc *fd + * Pointer to a PRFileDesc object that refers to a file or + * socket. + * OUTPUTS: + * None + * RETURN: PRInt32, PRInt64 + * Upon successful completion, PR_Available returns the number of + * bytes beyond the current read pointer that is available for + * reading. Otherwise, it returns a -1 and the reason for the + * failure can be retrieved via PR_GetError(). + ************************************************************************ + */ + +NSPR_API(PRInt32) PR_Available(PRFileDesc *fd); +NSPR_API(PRInt64) PR_Available64(PRFileDesc *fd); + +/* + ************************************************************************ + * FUNCTION: PR_Sync + * DESCRIPTION: + * Sync any buffered data for a fd to its backing device (disk). + * INPUTS: + * PRFileDesc *fd + * Pointer to a PRFileDesc object that refers to a file or + * socket + * OUTPUTS: + * None + * RETURN: PRStatus + * PR_SUCCESS is returned if the requested access is permitted. + * Otherwise, PR_FAILURE is returned. + ************************************************************************ + */ + +NSPR_API(PRStatus) PR_Sync(PRFileDesc *fd); + +/************************************************************************/ + +struct PRDirEntry { + const char *name; /* name of entry, relative to directory name */ +}; + +#ifdef MOZ_UNICODE +struct PRDirEntryUTF16 { + const PRUnichar *name; /* name of entry in UTF16, relative to + * directory name */ +}; +#endif /* MOZ_UNICODE */ + +#if !defined(NO_NSPR_10_SUPPORT) +#define PR_DirName(dirEntry) (dirEntry->name) +#endif + +/* + ************************************************************************* + * FUNCTION: PR_OpenDir + * DESCRIPTION: + * Open the directory by the given name + * INPUTS: + * const char *name + * path name of the directory to be opened + * OUTPUTS: + * None + * RETURN: PRDir * + * If the directory is sucessfully opened, a PRDir object is + * dynamically allocated and a pointer to it is returned. + * If the directory cannot be opened, a NULL pointer is returned. + * MEMORY: + * Upon successful completion, the return value points to + * dynamically allocated memory. + ************************************************************************* + */ + +NSPR_API(PRDir*) PR_OpenDir(const char *name); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************* + * FUNCTION: PR_ReadDir + * DESCRIPTION: + * INPUTS: + * PRDir *dir + * pointer to a PRDir object that designates an open directory + * PRDirFlags flags + * PR_SKIP_NONE Do not skip any files + * PR_SKIP_DOT Skip the directory entry "." that + * represents the current directory + * PR_SKIP_DOT_DOT Skip the directory entry ".." that + * represents the parent directory. + * PR_SKIP_BOTH Skip both '.' and '..' + * PR_SKIP_HIDDEN Skip hidden files + * OUTPUTS: + * RETURN: PRDirEntry* + * Returns a pointer to the next entry in the directory. Returns + * a NULL pointer upon reaching the end of the directory or when an + * error occurs. The actual reason can be retrieved via PR_GetError(). + ************************************************************************* + */ + +typedef enum PRDirFlags { + PR_SKIP_NONE = 0x0, + PR_SKIP_DOT = 0x1, + PR_SKIP_DOT_DOT = 0x2, + PR_SKIP_BOTH = 0x3, + PR_SKIP_HIDDEN = 0x4 +} PRDirFlags; + +NSPR_API(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************* + * FUNCTION: PR_CloseDir + * DESCRIPTION: + * Close the specified directory. + * INPUTS: + * PRDir *dir + * The directory to be closed. + * OUTPUTS: + * None + * RETURN: PRStatus + * If successful, will return a status of PR_SUCCESS. Otherwise + * a value of PR_FAILURE. The reason for the failure may be re- + * trieved using PR_GetError(). + ************************************************************************* + */ + +NSPR_API(PRStatus) PR_CloseDir(PRDir *dir); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRStatus) PR_CloseDirUTF16(PRDirUTF16 *dir); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************* + * FUNCTION: PR_MkDir + * DESCRIPTION: + * Create a new directory with the given name and access mode. + * INPUTS: + * const char *name + * The name of the directory to be created. All the path components + * up to but not including the leaf component must already exist. + * PRIntn mode + * See 'mode' definiton in PR_Open(). + * OUTPUTS: + * None + * RETURN: PRStatus + * If successful, will return a status of PR_SUCCESS. Otherwise + * a value of PR_FAILURE. The reason for the failure may be re- + * trieved using PR_GetError(). + ************************************************************************* + */ + +NSPR_API(PRStatus) PR_MkDir(const char *name, PRIntn mode); + +/* + ************************************************************************* + * FUNCTION: PR_MakeDir + * DESCRIPTION: + * Create a new directory with the given name and access mode. + * PR_MakeDir has the same prototype as PR_MkDir but implements + * the specified access mode where possible. + ************************************************************************* + */ + +NSPR_API(PRStatus) PR_MakeDir(const char *name, PRIntn mode); + +/* + ************************************************************************* + * FUNCTION: PR_RmDir + * DESCRIPTION: + * Remove a directory by the given name. + * INPUTS: + * const char *name + * The name of the directory to be removed. All the path components + * must already exist. Only the leaf component will be removed. + * OUTPUTS: + * None + * RETURN: PRStatus + * If successful, will return a status of PR_SUCCESS. Otherwise + * a value of PR_FAILURE. The reason for the failure may be re- + * trieved using PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_RmDir(const char *name); + +/* + ************************************************************************* + * FUNCTION: PR_NewUDPSocket + * DESCRIPTION: + * Create a new UDP socket. + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_NewUDPSocket returns a pointer + * to the PRFileDesc created for the newly opened UDP socket. + * Returns a NULL pointer if the creation of a new UDP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_NewUDPSocket(void); + +/* + ************************************************************************* + * FUNCTION: PR_NewTCPSocket + * DESCRIPTION: + * Create a new TCP socket. + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_NewTCPSocket returns a pointer + * to the PRFileDesc created for the newly opened TCP socket. + * Returns a NULL pointer if the creation of a new TCP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_NewTCPSocket(void); + +/* + ************************************************************************* + * FUNCTION: PR_OpenUDPSocket + * DESCRIPTION: + * Create a new UDP socket of the specified address family. + * INPUTS: + * PRIntn af + * Address family + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_OpenUDPSocket returns a pointer + * to the PRFileDesc created for the newly opened UDP socket. + * Returns a NULL pointer if the creation of a new UDP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_OpenUDPSocket(PRIntn af); + +/* + ************************************************************************* + * FUNCTION: PR_OpenTCPSocket + * DESCRIPTION: + * Create a new TCP socket of the specified address family. + * INPUTS: + * PRIntn af + * Address family + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_NewTCPSocket returns a pointer + * to the PRFileDesc created for the newly opened TCP socket. + * Returns a NULL pointer if the creation of a new TCP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_OpenTCPSocket(PRIntn af); + +/* + ************************************************************************* + * FUNCTION: PR_Connect + * DESCRIPTION: + * Initiate a connection on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a socket + * PRNetAddr *addr + * Specifies the address of the socket in its own communication + * space. + * PRIntervalTime timeout + * The function uses the lesser of the provided timeout and + * the OS's connect timeout. In particular, if you specify + * PR_INTERVAL_NO_TIMEOUT as the timeout, the OS's connection + * time limit will be used. + * + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful completion of connection initiation, PR_Connect + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Connect( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_ConnectContinue + * DESCRIPTION: + * Continue a nonblocking connect. After a nonblocking connect + * is initiated with PR_Connect() (which fails with + * PR_IN_PROGRESS_ERROR), one should call PR_Poll() on the socket, + * with the in_flags PR_POLL_WRITE | PR_POLL_EXCEPT. When + * PR_Poll() returns, one calls PR_ConnectContinue() on the + * socket to determine whether the nonblocking connect has + * completed or is still in progress. Repeat the PR_Poll(), + * PR_ConnectContinue() sequence until the nonblocking connect + * has completed. + * INPUTS: + * PRFileDesc *fd + * the file descriptor representing a socket + * PRInt16 out_flags + * the out_flags field of the poll descriptor returned by + * PR_Poll() + * RETURN: PRStatus + * If the nonblocking connect has successfully completed, + * PR_ConnectContinue returns PR_SUCCESS. If PR_ConnectContinue() + * returns PR_FAILURE, call PR_GetError(): + * - PR_IN_PROGRESS_ERROR: the nonblocking connect is still in + * progress and has not completed yet. The caller should poll + * on the file descriptor for the in_flags + * PR_POLL_WRITE|PR_POLL_EXCEPT and retry PR_ConnectContinue + * later when PR_Poll() returns. + * - Other errors: the nonblocking connect has failed with this + * error code. + */ + +NSPR_API(PRStatus) PR_ConnectContinue(PRFileDesc *fd, PRInt16 out_flags); + +/* + ************************************************************************* + * THIS FUNCTION IS DEPRECATED. USE PR_ConnectContinue INSTEAD. + * + * FUNCTION: PR_GetConnectStatus + * DESCRIPTION: + * Get the completion status of a nonblocking connect. After + * a nonblocking connect is initiated with PR_Connect() (which + * fails with PR_IN_PROGRESS_ERROR), one should call PR_Poll() + * on the socket, with the in_flags PR_POLL_WRITE | PR_POLL_EXCEPT. + * When PR_Poll() returns, one calls PR_GetConnectStatus on the + * PRPollDesc structure to determine whether the nonblocking + * connect has succeeded or failed. + * INPUTS: + * const PRPollDesc *pd + * Pointer to a PRPollDesc whose fd member is the socket, + * and in_flags must contain PR_POLL_WRITE and PR_POLL_EXCEPT. + * PR_Poll() should have been called and set the out_flags. + * RETURN: PRStatus + * If the nonblocking connect has successfully completed, + * PR_GetConnectStatus returns PR_SUCCESS. If PR_GetConnectStatus() + * returns PR_FAILURE, call PR_GetError(): + * - PR_IN_PROGRESS_ERROR: the nonblocking connect is still in + * progress and has not completed yet. + * - Other errors: the nonblocking connect has failed with this + * error code. + */ + +NSPR_API(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd); + +/* + ************************************************************************* + * FUNCTION: PR_Accept + * DESCRIPTION: + * Accept a connection on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing the rendezvous socket + * on which the caller is willing to accept new connections. + * PRIntervalTime timeout + * Time limit for completion of the accept operation. + * OUTPUTS: + * PRNetAddr *addr + * Returns the address of the connecting entity in its own + * communication space. It may be NULL. + * RETURN: PRFileDesc* + * Upon successful acceptance of a connection, PR_Accept + * returns a valid file descriptor. Otherwise, it returns NULL. + * Further failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_Accept( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_Bind + * DESCRIPTION: + * Bind an address to a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a socket. + * PRNetAddr *addr + * Specifies the address to which the socket will be bound. + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful binding of an address to a socket, PR_Bind + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Bind(PRFileDesc *fd, const PRNetAddr *addr); + +/* + ************************************************************************* + * FUNCTION: PR_Listen + * DESCRIPTION: + * Listen for connections on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a socket that will be + * used to listen for new connections. + * PRIntn backlog + * Specifies the maximum length of the queue of pending connections. + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful completion of listen request, PR_Listen + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Listen(PRFileDesc *fd, PRIntn backlog); + +/* + ************************************************************************* + * FUNCTION: PR_Shutdown + * DESCRIPTION: + * Shut down part of a full-duplex connection on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a connected socket. + * PRIntn how + * Specifies the kind of disallowed operations on the socket. + * PR_SHUTDOWN_RCV - Further receives will be disallowed + * PR_SHUTDOWN_SEND - Further sends will be disallowed + * PR_SHUTDOWN_BOTH - Further sends and receives will be disallowed + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful completion of shutdown request, PR_Shutdown + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +typedef enum PRShutdownHow +{ + PR_SHUTDOWN_RCV = 0, /* disallow further receives */ + PR_SHUTDOWN_SEND = 1, /* disallow further sends */ + PR_SHUTDOWN_BOTH = 2 /* disallow further receives and sends */ +} PRShutdownHow; + +NSPR_API(PRStatus) PR_Shutdown(PRFileDesc *fd, PRShutdownHow how); + +/* + ************************************************************************* + * FUNCTION: PR_Recv + * DESCRIPTION: + * Receive a specified number of bytes from a connected socket. + * The operation will block until some positive number of bytes are + * transferred, a time out has occurred, or there is an error. + * No more than 'amount' bytes will be transferred. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing a socket. + * void *buf + * pointer to a buffer to hold the data received. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * must be zero or PR_MSG_PEEK. + * PRIntervalTime timeout + * Time limit for completion of the receive operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * a positive number indicates the number of bytes actually received. + * 0 means the network connection is closed. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + ************************************************************************** + */ + +#define PR_MSG_PEEK 0x2 + +NSPR_API(PRInt32) PR_Recv(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_Send + * DESCRIPTION: + * Send a specified number of bytes from a connected socket. + * The operation will block until all bytes are + * processed, a time out has occurred, or there is an error. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing a socket. + * void *buf + * pointer to a buffer from where the data is sent. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * (OBSOLETE - must always be zero) + * PRIntervalTime timeout + * Time limit for completion of the send operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * A positive number indicates the number of bytes successfully processed. + * This number must always equal 'amount'. A -1 is an indication that the + * operation failed. The reason for the failure is obtained by calling + * PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_Send(PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_RecvFrom + * DESCRIPTION: + * Receive up to a specified number of bytes from socket which may + * or may not be connected. + * The operation will block until one or more bytes are + * transferred, a time out has occurred, or there is an error. + * No more than 'amount' bytes will be transferred. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing a socket. + * void *buf + * pointer to a buffer to hold the data received. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * (OBSOLETE - must always be zero) + * PRNetAddr *addr + * Specifies the address of the sending peer. It may be NULL. + * PRIntervalTime timeout + * Time limit for completion of the receive operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * a positive number indicates the number of bytes actually received. + * 0 means the network connection is closed. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_RecvFrom( + PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRNetAddr *addr, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_SendTo + * DESCRIPTION: + * Send a specified number of bytes from an unconnected socket. + * The operation will block until all bytes are + * sent, a time out has occurred, or there is an error. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing an unconnected socket. + * void *buf + * pointer to a buffer from where the data is sent. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * (OBSOLETE - must always be zero) + * PRNetAddr *addr + * Specifies the address of the peer. +.* PRIntervalTime timeout + * Time limit for completion of the send operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * A positive number indicates the number of bytes successfully sent. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_SendTo( + PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_TransmitFile +** DESCRIPTION: +** Transmitfile sends a complete file (sourceFile) across a socket +** (networkSocket). If headers is non-NULL, the headers will be sent across +** the socket prior to sending the file. +** +** Optionally, the PR_TRANSMITFILE_CLOSE_SOCKET flag may be passed to +** transmitfile. This flag specifies that transmitfile should close the +** socket after sending the data. +** +** INPUTS: +** PRFileDesc *networkSocket +** The socket to send data over +** PRFileDesc *sourceFile +** The file to send +** const void *headers +** A pointer to headers to be sent before sending data +** PRInt32 hlen +** length of header buffers in bytes. +** PRTransmitFileFlags flags +** If the flags indicate that the connection should be closed, +** it will be done immediately after transferring the file, unless +** the operation is unsuccessful. +.* PRIntervalTime timeout + * Time limit for completion of the transmit operation. +** +** RETURNS: +** Returns the number of bytes written or -1 if the operation failed. +** If an error occurs while sending the file, the PR_TRANSMITFILE_CLOSE_ +** SOCKET flag is ignored. The reason for the failure is obtained +** by calling PR_GetError(). +************************************************************************** +*/ + +NSPR_API(PRInt32) PR_TransmitFile( + PRFileDesc *networkSocket, PRFileDesc *sourceFile, + const void *headers, PRInt32 hlen, PRTransmitFileFlags flags, + PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_SendFile +** DESCRIPTION: +** PR_SendFile sends data from a file (sendData->fd) across a socket +** (networkSocket). If specified, a header and/or trailer buffer are sent +** before and after the file, respectively. The file offset, number of bytes +** of file data to send, the header and trailer buffers are specified in the +** sendData argument. +** +** Optionally, if the PR_TRANSMITFILE_CLOSE_SOCKET flag is passed, the +** socket is closed after successfully sending the data. +** +** INPUTS: +** PRFileDesc *networkSocket +** The socket to send data over +** PRSendFileData *sendData +** Contains the FD, file offset and length, header and trailer +** buffer specifications. +** PRTransmitFileFlags flags +** If the flags indicate that the connection should be closed, +** it will be done immediately after transferring the file, unless +** the operation is unsuccessful. +.* PRIntervalTime timeout + * Time limit for completion of the send operation. +** +** RETURNS: +** Returns the number of bytes written or -1 if the operation failed. +** If an error occurs while sending the file, the PR_TRANSMITFILE_CLOSE_ +** SOCKET flag is ignored. The reason for the failure is obtained +** by calling PR_GetError(). +************************************************************************** +*/ + +struct PRSendFileData { + PRFileDesc *fd; /* file to send */ + PRUint32 file_offset; /* file offset */ + PRSize file_nbytes; /* number of bytes of file data to send */ + /* if 0, send data from file_offset to */ + /* end-of-file. */ + const void *header; /* header buffer */ + PRInt32 hlen; /* header len */ + const void *trailer; /* trailer buffer */ + PRInt32 tlen; /* trailer len */ +}; + + +NSPR_API(PRInt32) PR_SendFile( + PRFileDesc *networkSocket, PRSendFileData *sendData, + PRTransmitFileFlags flags, PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_AcceptRead +** DESCRIPTION: +** AcceptRead accepts a new connection, returns the newly created +** socket's descriptor and also returns the connecting peer's address. +** AcceptRead, as its name suggests, also receives the first block of data +** sent by the peer. +** +** INPUTS: +** PRFileDesc *listenSock +** A socket descriptor that has been called with the PR_Listen() +** function, also known as the rendezvous socket. +** void *buf +** A pointer to a buffer to receive data sent by the client. This +** buffer must be large enough to receive bytes of data +** and two PRNetAddr structures, plus an extra 32 bytes. See: +** PR_ACCEPT_READ_BUF_OVERHEAD. +** PRInt32 amount +** The number of bytes of client data to receive. Does not include +** the size of the PRNetAddr structures. If 0, no data will be read +** from the client. +** PRIntervalTime timeout +** The timeout interval only applies to the read portion of the +** operation. PR_AcceptRead will block indefinitely until the +** connection is accepted; the read will timeout after the timeout +** interval elapses. +** OUTPUTS: +** PRFileDesc **acceptedSock +** The file descriptor for the newly connected socket. This parameter +** will only be valid if the function return does not indicate failure. +** PRNetAddr **peerAddr, +** The address of the remote socket. This parameter will only be +** valid if the function return does not indicate failure. The +** returned address is not guaranteed to be properly aligned. +** +** RETURNS: +** The number of bytes read from the client or -1 on failure. The reason +** for the failure is obtained by calling PR_GetError(). +************************************************************************** +**/ +/* define buffer overhead constant. Add this value to the user's +** data length when allocating a buffer to accept data. +** Example: +** #define USER_DATA_SIZE 10 +** char buf[USER_DATA_SIZE + PR_ACCEPT_READ_BUF_OVERHEAD]; +** bytesRead = PR_AcceptRead( s, fd, &a, &p, USER_DATA_SIZE, ...); +*/ +#define PR_ACCEPT_READ_BUF_OVERHEAD (32+(2*sizeof(PRNetAddr))) + +NSPR_API(PRInt32) PR_AcceptRead( + PRFileDesc *listenSock, PRFileDesc **acceptedSock, + PRNetAddr **peerAddr, void *buf, PRInt32 amount, PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_NewTCPSocketPair +** DESCRIPTION: +** Create a new TCP socket pair. The returned descriptors can be used +** interchangeably; they are interconnected full-duplex descriptors: data +** written to one can be read from the other and vice-versa. +** +** INPUTS: +** None +** OUTPUTS: +** PRFileDesc *fds[2] +** The file descriptor pair for the newly created TCP sockets. +** RETURN: PRStatus +** Upon successful completion of TCP socket pair, PR_NewTCPSocketPair +** returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further +** failure information can be obtained by calling PR_GetError(). +** XXX can we implement this on windoze and mac? +************************************************************************** +**/ +NSPR_API(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2]); + +/* +************************************************************************* +** FUNCTION: PR_GetSockName +** DESCRIPTION: +** Get socket name. Return the network address for this socket. +** +** INPUTS: +** PRFileDesc *fd +** Points to a PRFileDesc object representing the socket. +** OUTPUTS: +** PRNetAddr *addr +** Returns the address of the socket in its own communication space. +** RETURN: PRStatus +** Upon successful completion, PR_GetSockName returns PR_SUCCESS. +** Otherwise, it returns PR_FAILURE. Further failure information can +** be obtained by calling PR_GetError(). +************************************************************************** +**/ +NSPR_API(PRStatus) PR_GetSockName(PRFileDesc *fd, PRNetAddr *addr); + +/* +************************************************************************* +** FUNCTION: PR_GetPeerName +** DESCRIPTION: +** Get name of the connected peer. Return the network address for the +** connected peer socket. +** +** INPUTS: +** PRFileDesc *fd +** Points to a PRFileDesc object representing the connected peer. +** OUTPUTS: +** PRNetAddr *addr +** Returns the address of the connected peer in its own communication +** space. +** RETURN: PRStatus +** Upon successful completion, PR_GetPeerName returns PR_SUCCESS. +** Otherwise, it returns PR_FAILURE. Further failure information can +** be obtained by calling PR_GetError(). +************************************************************************** +**/ +NSPR_API(PRStatus) PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr); + +NSPR_API(PRStatus) PR_GetSocketOption( + PRFileDesc *fd, PRSocketOptionData *data); + +NSPR_API(PRStatus) PR_SetSocketOption( + PRFileDesc *fd, const PRSocketOptionData *data); + +/* + ********************************************************************* + * + * File descriptor inheritance + * + ********************************************************************* + */ + +/* + ************************************************************************ + * FUNCTION: PR_SetFDInheritable + * DESCRIPTION: + * Set the inheritance attribute of a file descriptor. + * + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object. + * PRBool inheritable + * If PR_TRUE, the file descriptor fd is set to be inheritable + * by a child process. If PR_FALSE, the file descriptor is set + * to be not inheritable by a child process. + * RETURN: PRStatus + * Upon successful completion, PR_SetFDInheritable returns PR_SUCCESS. + * Otherwise, it returns PR_FAILURE. Further failure information can + * be obtained by calling PR_GetError(). + ************************************************************************* + */ +NSPR_API(PRStatus) PR_SetFDInheritable( + PRFileDesc *fd, + PRBool inheritable); + +/* + ************************************************************************ + * FUNCTION: PR_GetInheritedFD + * DESCRIPTION: + * Get an inherited file descriptor with the specified name. + * + * INPUTS: + * const char *name + * The name of the inherited file descriptor. + * RETURN: PRFileDesc * + * Upon successful completion, PR_GetInheritedFD returns the + * inherited file descriptor with the specified name. Otherwise, + * it returns NULL. Further failure information can be obtained + * by calling PR_GetError(). + ************************************************************************* + */ +NSPR_API(PRFileDesc *) PR_GetInheritedFD(const char *name); + +/* + ********************************************************************* + * + * Memory-mapped files + * + ********************************************************************* + */ + +typedef struct PRFileMap PRFileMap; + +/* + * protection options for read and write accesses of a file mapping + */ +typedef enum PRFileMapProtect { + PR_PROT_READONLY, /* read only */ + PR_PROT_READWRITE, /* readable, and write is shared */ + PR_PROT_WRITECOPY /* readable, and write is private (copy-on-write) */ +} PRFileMapProtect; + +NSPR_API(PRFileMap *) PR_CreateFileMap( + PRFileDesc *fd, + PRInt64 size, + PRFileMapProtect prot); + +/* + * return the alignment (in bytes) of the offset argument to PR_MemMap + */ +NSPR_API(PRInt32) PR_GetMemMapAlignment(void); + +NSPR_API(void *) PR_MemMap( + PRFileMap *fmap, + PROffset64 offset, /* must be aligned and sized according to the + * return value of PR_GetMemMapAlignment() */ + PRUint32 len); + +NSPR_API(PRStatus) PR_MemUnmap(void *addr, PRUint32 len); + +NSPR_API(PRStatus) PR_CloseFileMap(PRFileMap *fmap); + +/* + * Synchronously flush the given memory-mapped address range of the given open + * file to disk. The function does not return until all modified data have + * been written to disk. + * + * On some platforms, the function will call PR_Sync(fd) internally if it is + * necessary for flushing modified data to disk synchronously. + */ +NSPR_API(PRStatus) PR_SyncMemMap( + PRFileDesc *fd, + void *addr, + PRUint32 len); + +/* + ****************************************************************** + * + * Interprocess communication + * + ****************************************************************** + */ + +/* + * Creates an anonymous pipe and returns file descriptors for the + * read and write ends of the pipe. + */ + +NSPR_API(PRStatus) PR_CreatePipe( + PRFileDesc **readPipe, + PRFileDesc **writePipe +); + +/************************************************************************/ +/************** The following definitions are for poll ******************/ +/************************************************************************/ + +struct PRPollDesc { + PRFileDesc* fd; + PRInt16 in_flags; + PRInt16 out_flags; +}; + +/* +** Bit values for PRPollDesc.in_flags or PRPollDesc.out_flags. Binary-or +** these together to produce the desired poll request. +*/ + +#if defined(_PR_POLL_BACKCOMPAT) + +#include +#define PR_POLL_READ POLLIN +#define PR_POLL_WRITE POLLOUT +#define PR_POLL_EXCEPT POLLPRI +#define PR_POLL_ERR POLLERR /* only in out_flags */ +#define PR_POLL_NVAL POLLNVAL /* only in out_flags when fd is bad */ +#define PR_POLL_HUP POLLHUP /* only in out_flags */ + +#else /* _PR_POLL_BACKCOMPAT */ + +#define PR_POLL_READ 0x1 +#define PR_POLL_WRITE 0x2 +#define PR_POLL_EXCEPT 0x4 +#define PR_POLL_ERR 0x8 /* only in out_flags */ +#define PR_POLL_NVAL 0x10 /* only in out_flags when fd is bad */ +#define PR_POLL_HUP 0x20 /* only in out_flags */ + +#endif /* _PR_POLL_BACKCOMPAT */ + +/* +************************************************************************* +** FUNCTION: PR_Poll +** DESCRIPTION: +** +** The call returns as soon as I/O is ready on one or more of the underlying +** socket objects. A count of the number of ready descriptors is +** returned unless a timeout occurs in which case zero is returned. +** +** PRPollDesc.fd should be set to a pointer to a PRFileDesc object +** representing a socket. This field can be set to NULL to indicate to +** PR_Poll that this PRFileDesc object should be ignored. +** PRPollDesc.in_flags should be set to the desired request +** (read/write/except or some combination). Upon successful return from +** this call PRPollDesc.out_flags will be set to indicate what kind of +** i/o can be performed on the respective descriptor. PR_Poll() uses the +** out_flags fields as scratch variables during the call. If PR_Poll() +** returns 0 or -1, the out_flags fields do not contain meaningful values +** and must not be used. +** +** INPUTS: +** PRPollDesc *pds A pointer to an array of PRPollDesc +** +** PRIntn npds The number of elements in the array +** If this argument is zero PR_Poll is +** equivalent to a PR_Sleep(timeout). +** +** PRIntervalTime timeout Amount of time the call will block waiting +** for I/O to become ready. If this time expires +** w/o any I/O becoming ready, the result will +** be zero. +** +** OUTPUTS: None +** RETURN: +** PRInt32 Number of PRPollDesc's with events or zero +** if the function timed out or -1 on failure. +** The reason for the failure is obtained by +** calling PR_GetError(). +************************************************************************** +*/ +NSPR_API(PRInt32) PR_Poll( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout); + +/* +************************************************************************** +** +** Pollable events +** +** A pollable event is a special kind of file descriptor. +** The only I/O operation you can perform on a pollable event +** is to poll it with the PR_POLL_READ flag. You can't +** read from or write to a pollable event. +** +** The purpose of a pollable event is to combine event waiting +** with I/O waiting in a single PR_Poll call. Pollable events +** are implemented using a pipe or a pair of TCP sockets +** connected via the loopback address, therefore setting and +** waiting for pollable events are expensive operating system +** calls. Do not use pollable events for general thread +** synchronization. Use condition variables instead. +** +** A pollable event has two states: set and unset. Events +** are not queued, so there is no notion of an event count. +** A pollable event is either set or unset. +** +** A new pollable event is created by a PR_NewPollableEvent +** call and is initially in the unset state. +** +** PR_WaitForPollableEvent blocks the calling thread until +** the pollable event is set, and then it atomically unsets +** the pollable event before it returns. +** +** To set a pollable event, call PR_SetPollableEvent. +** +** One can call PR_Poll with the PR_POLL_READ flag on a pollable +** event. When the pollable event is set, PR_Poll returns with +** the PR_POLL_READ flag set in the out_flags. +** +** To close a pollable event, call PR_DestroyPollableEvent +** (not PR_Close). +** +************************************************************************** +*/ + +NSPR_API(PRFileDesc *) PR_NewPollableEvent(void); + +NSPR_API(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event); + +NSPR_API(PRStatus) PR_SetPollableEvent(PRFileDesc *event); + +NSPR_API(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event); + +PR_END_EXTERN_C + +#endif /* prio_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/pripcsem.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/pripcsem.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/pripcsem.h @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* + * File: pripcsem.h + * + * Description: named semaphores for interprocess + * synchronization + * + * Unrelated processes obtain access to a shared semaphore + * by specifying its name. + * + * Our goal is to support named semaphores on at least + * Unix and Win32 platforms. The implementation will use + * one of the three native semaphore APIs: POSIX, System V, + * and Win32. + * + * Because POSIX named semaphores have kernel persistence, + * we are forced to have a delete function in this API. + */ + +#ifndef pripcsem_h___ +#define pripcsem_h___ + +#include "prtypes.h" +#include "prio.h" + +PR_BEGIN_EXTERN_C + +/* + * PRSem is an opaque structure that represents a named + * semaphore. + */ +typedef struct PRSem PRSem; + +/* + * PR_OpenSemaphore -- + * + * Create or open a named semaphore with the specified name. + * A handle to the semaphore is returned. + * + * If the named semaphore doesn't exist and the PR_SEM_CREATE + * flag is specified, the named semaphore is created. The + * created semaphore needs to be removed from the system with + * a PR_DeleteSemaphore call. + * + * If PR_SEM_CREATE is specified, the third argument is the + * access permission bits of the new semaphore (same + * interpretation as the mode argument to PR_Open) and the + * fourth argument is the initial value of the new semaphore. + * If PR_SEM_CREATE is not specified, the third and fourth + * arguments are ignored. + */ + +#define PR_SEM_CREATE 0x1 /* create if not exist */ +#define PR_SEM_EXCL 0x2 /* fail if already exists */ + +NSPR_API(PRSem *) PR_OpenSemaphore( + const char *name, PRIntn flags, PRIntn mode, PRUintn value); + +/* + * PR_WaitSemaphore -- + * + * If the value of the semaphore is > 0, decrement the value and return. + * If the value is 0, sleep until the value becomes > 0, then decrement + * the value and return. + * + * The "test and decrement" operation is performed atomically. + */ + +NSPR_API(PRStatus) PR_WaitSemaphore(PRSem *sem); + +/* + * PR_PostSemaphore -- + * + * Increment the value of the named semaphore by 1. + */ + +NSPR_API(PRStatus) PR_PostSemaphore(PRSem *sem); + +/* + * PR_CloseSemaphore -- + * + * Close a named semaphore handle. + */ + +NSPR_API(PRStatus) PR_CloseSemaphore(PRSem *sem); + +/* + * PR_DeleteSemaphore -- + * + * Remove a named semaphore from the system. + */ + +NSPR_API(PRStatus) PR_DeleteSemaphore(const char *name); + +PR_END_EXTERN_C + +#endif /* pripcsem_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/private/pprio.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/private/pprio.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/private/pprio.h @@ -0,0 +1,242 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: pprio.h +** +** Description: Private definitions for I/O related structures +*/ + +#ifndef pprio_h___ +#define pprio_h___ + +#include "prtypes.h" +#include "prio.h" + +PR_BEGIN_EXTERN_C + +/************************************************************************/ +/************************************************************************/ + +#ifdef _WIN64 +typedef __int64 PROsfd; +#else +typedef PRInt32 PROsfd; +#endif + +/* Return the method tables for files, tcp sockets and udp sockets */ +NSPR_API(const PRIOMethods*) PR_GetFileMethods(void); +NSPR_API(const PRIOMethods*) PR_GetTCPMethods(void); +NSPR_API(const PRIOMethods*) PR_GetUDPMethods(void); +NSPR_API(const PRIOMethods*) PR_GetPipeMethods(void); + +/* +** Convert a NSPR socket handle to a native socket handle. +** +** Using this function makes your code depend on the properties of the +** current NSPR implementation, which may change (although extremely +** unlikely because of NSPR's backward compatibility requirement). Avoid +** using it if you can. +** +** If you use this function, you need to understand what NSPR does to +** the native handle. For example, NSPR puts native socket handles in +** non-blocking mode or associates them with an I/O completion port (the +** WINNT build configuration only). Your use of the native handle should +** not interfere with NSPR's use of the native handle. If your code +** changes the configuration of the native handle, (e.g., changes it to +** blocking or closes it), NSPR will not work correctly. +*/ +NSPR_API(PROsfd) PR_FileDesc2NativeHandle(PRFileDesc *); +NSPR_API(void) PR_ChangeFileDescNativeHandle(PRFileDesc *, PROsfd); +NSPR_API(PRFileDesc*) PR_AllocFileDesc(PROsfd osfd, + const PRIOMethods *methods); +NSPR_API(void) PR_FreeFileDesc(PRFileDesc *fd); +/* +** Import an existing OS file to NSPR. +*/ +NSPR_API(PRFileDesc*) PR_ImportFile(PROsfd osfd); +NSPR_API(PRFileDesc*) PR_ImportPipe(PROsfd osfd); +NSPR_API(PRFileDesc*) PR_ImportTCPSocket(PROsfd osfd); +NSPR_API(PRFileDesc*) PR_ImportUDPSocket(PROsfd osfd); + + +/* + ************************************************************************* + * FUNCTION: PR_CreateSocketPollFd + * DESCRIPTION: + * Create a PRFileDesc wrapper for a native socket handle, for use with + * PR_Poll only + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_CreateSocketPollFd returns a pointer + * to the PRFileDesc created for the native socket handle + * Returns a NULL pointer if the create of a new PRFileDesc failed + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_CreateSocketPollFd(PROsfd osfd); + +/* + ************************************************************************* + * FUNCTION: PR_DestroySocketPollFd + * DESCRIPTION: + * Destroy the PRFileDesc wrapper created by PR_CreateSocketPollFd + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_DestroySocketPollFd returns + * PR_SUCCESS, else PR_FAILURE + * + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd); + + +/* +** Macros for PR_Socket +** +** Socket types: PR_SOCK_STREAM, PR_SOCK_DGRAM +*/ + +#ifdef WIN32 + +#define PR_SOCK_STREAM 1 +#define PR_SOCK_DGRAM 2 + +#else /* WIN32 */ + +#define PR_SOCK_STREAM SOCK_STREAM +#define PR_SOCK_DGRAM SOCK_DGRAM + +#endif /* WIN32 */ + +/* +** Create a new Socket; this function is obsolete. +*/ +NSPR_API(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto); + +/* FUNCTION: PR_LockFile +** DESCRIPTION: +** Lock a file for exclusive access. +** RETURNS: +** PR_SUCCESS when the lock is held +** PR_FAILURE otherwise +*/ +NSPR_API(PRStatus) PR_LockFile(PRFileDesc *fd); + +/* FUNCTION: PR_TLockFile +** DESCRIPTION: +** Test and Lock a file for exclusive access. Do not block if the +** file cannot be locked immediately. +** RETURNS: +** PR_SUCCESS when the lock is held +** PR_FAILURE otherwise +*/ +NSPR_API(PRStatus) PR_TLockFile(PRFileDesc *fd); + +/* FUNCTION: PR_UnlockFile +** DESCRIPTION: +** Unlock a file which has been previously locked successfully by this +** process. +** RETURNS: +** PR_SUCCESS when the lock is released +** PR_FAILURE otherwise +*/ +NSPR_API(PRStatus) PR_UnlockFile(PRFileDesc *fd); + +/* +** Emulate acceptread by accept and recv. +*/ +NSPR_API(PRInt32) PR_EmulateAcceptRead(PRFileDesc *sd, PRFileDesc **nd, + PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout); + +/* +** Emulate sendfile by reading from the file and writing to the socket. +** The file is memory-mapped if memory-mapped files are supported. +*/ +NSPR_API(PRInt32) PR_EmulateSendFile( + PRFileDesc *networkSocket, PRSendFileData *sendData, + PRTransmitFileFlags flags, PRIntervalTime timeout); + +#ifdef WIN32 +/* FUNCTION: PR_NTFast_AcceptRead +** DESCRIPTION: +** NT has the notion of an "accept context", which is only needed in +** order to make certain calls. By default, a socket connected via +** AcceptEx can only do a limited number of things without updating +** the acceptcontext. The generic version of PR_AcceptRead always +** updates the accept context. This version does not. +**/ +NSPR_API(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd, + PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime t); + +typedef void (*_PR_AcceptTimeoutCallback)(void *); + +/* FUNCTION: PR_NTFast_AcceptRead_WithTimeoutCallback +** DESCRIPTION: +** The AcceptEx call combines the accept with the read function. However, +** our daemon threads need to be able to wakeup and reliably flush their +** log buffers if the Accept times out. However, with the current blocking +** interface to AcceptRead, there is no way for us to timeout the Accept; +** this is because when we timeout the Read, we can close the newly +** socket and continue; but when we timeout the accept itself, there is no +** new socket to timeout. So instead, this version of the function is +** provided. After the initial timeout period elapses on the accept() +** portion of the function, it will call the callback routine and then +** continue the accept. If the timeout occurs on the read, it will +** close the connection and return error. +*/ +NSPR_API(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback( + PRFileDesc *sd, + PRFileDesc **nd, + PRNetAddr **raddr, + void *buf, + PRInt32 amount, + PRIntervalTime t, + _PR_AcceptTimeoutCallback callback, + void *callback_arg); + +/* FUNCTION: PR_NTFast_Accept +** DESCRIPTION: +** NT has the notion of an "accept context", which is only needed in +** order to make certain calls. By default, a socket connected via +** AcceptEx can only do a limited number of things without updating +** the acceptcontext. The generic version of PR_Accept always +** updates the accept context. This version does not. +**/ +NSPR_API(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr, + PRIntervalTime timeout); + +/* FUNCTION: PR_NTFast_Update +** DESCRIPTION: +** For sockets accepted with PR_NTFast_Accept or PR_NTFastAcceptRead, +** this function will update the accept context for those sockets, +** so that the socket can make general purpose socket calls. +** Without calling this, the only operations supported on the socket +** Are PR_Read, PR_Write, PR_Transmitfile, and PR_Close. +*/ +NSPR_API(void) PR_NTFast_UpdateAcceptContext(PRFileDesc *acceptSock, + PRFileDesc *listenSock); + + +/* FUNCTION: PR_NT_CancelIo +** DESCRIPTION: +** Cancel IO operations on fd. +*/ +NSPR_API(PRStatus) PR_NT_CancelIo(PRFileDesc *fd); + + +#endif /* WIN32 */ + +PR_END_EXTERN_C + +#endif /* pprio_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/private/pprthred.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/private/pprthred.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/private/pprthred.h @@ -0,0 +1,331 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef pprthred_h___ +#define pprthred_h___ + +/* +** API for PR private functions. These calls are to be used by internal +** developers only. +*/ +#include "nspr.h" + +#if defined(XP_OS2) +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_WIN +#include +#endif + +PR_BEGIN_EXTERN_C + +/*--------------------------------------------------------------------------- +** THREAD PRIVATE FUNCTIONS +---------------------------------------------------------------------------*/ + +/* +** Associate a thread object with an existing native thread. +** "type" is the type of thread object to attach +** "priority" is the priority to assign to the thread +** "stack" defines the shape of the threads stack +** +** This can return NULL if some kind of error occurs, or if memory is +** tight. This call invokes "start(obj,arg)" and returns when the +** function returns. The thread object is automatically destroyed. +** +** This call is not normally needed unless you create your own native +** thread. PR_Init does this automatically for the primordial thread. +*/ +NSPR_API(PRThread*) PR_AttachThread(PRThreadType type, + PRThreadPriority priority, + PRThreadStack *stack); + +/* +** Detach the nspr thread from the currently executing native thread. +** The thread object will be destroyed and all related data attached +** to it. The exit procs will be invoked. +** +** This call is not normally needed unless you create your own native +** thread. PR_Exit will automatially detach the nspr thread object +** created by PR_Init for the primordial thread. +** +** This call returns after the nspr thread object is destroyed. +*/ +NSPR_API(void) PR_DetachThread(void); + +/* +** Get the id of the named thread. Each thread is assigned a unique id +** when it is created or attached. +*/ +NSPR_API(PRUint32) PR_GetThreadID(PRThread *thread); + +/* +** Set the procedure that is called when a thread is dumped. The procedure +** will be applied to the argument, arg, when called. Setting the procedure +** to NULL effectively removes it. +*/ +typedef void (*PRThreadDumpProc)(PRFileDesc *fd, PRThread *t, void *arg); +NSPR_API(void) PR_SetThreadDumpProc( + PRThread* thread, PRThreadDumpProc dump, void *arg); + +/* +** Get this thread's affinity mask. The affinity mask is a 32 bit quantity +** marking a bit for each processor this process is allowed to run on. +** The processor mask is returned in the mask argument. +** The least-significant-bit represents processor 0. +** +** Returns 0 on success, -1 on failure. +*/ +NSPR_API(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask); + +/* +** Set this thread's affinity mask. +** +** Returns 0 on success, -1 on failure. +*/ +NSPR_API(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask ); + +/* +** Set the default CPU Affinity mask. +** +*/ +NSPR_API(PRInt32) PR_SetCPUAffinityMask(PRUint32 mask); + +/* +** Show status of all threads to standard error output. +*/ +NSPR_API(void) PR_ShowStatus(void); + +/* +** Set thread recycle mode to on (1) or off (0) +*/ +NSPR_API(void) PR_SetThreadRecycleMode(PRUint32 flag); + + +/*--------------------------------------------------------------------------- +** THREAD PRIVATE FUNCTIONS FOR GARBAGE COLLECTIBLE THREADS +---------------------------------------------------------------------------*/ + +/* +** Only Garbage collectible threads participate in resume all, suspend all and +** enumeration operations. They are also different during creation when +** platform specific action may be needed (For example, all Solaris GC able +** threads are bound threads). +*/ + +/* +** Same as PR_CreateThread except that the thread is marked as garbage +** collectible. +*/ +NSPR_API(PRThread*) PR_CreateThreadGCAble(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); + +/* +** Same as PR_AttachThread except that the thread being attached is marked as +** garbage collectible. +*/ +NSPR_API(PRThread*) PR_AttachThreadGCAble(PRThreadType type, + PRThreadPriority priority, + PRThreadStack *stack); + +/* +** Mark the thread as garbage collectible. +*/ +NSPR_API(void) PR_SetThreadGCAble(void); + +/* +** Unmark the thread as garbage collectible. +*/ +NSPR_API(void) PR_ClearThreadGCAble(void); + +/* +** This routine prevents all other GC able threads from running. This call is needed by +** the garbage collector. +*/ +NSPR_API(void) PR_SuspendAll(void); + +/* +** This routine unblocks all other GC able threads that were suspended from running by +** PR_SuspendAll(). This call is needed by the garbage collector. +*/ +NSPR_API(void) PR_ResumeAll(void); + +/* +** Return the thread stack pointer of the given thread. +** Needed by the garbage collector. +*/ +NSPR_API(void *) PR_GetSP(PRThread *thread); + +/* +** Save the registers that the GC would find interesting into the thread +** "t". isCurrent will be non-zero if the thread state that is being +** saved is the currently executing thread. Return the address of the +** first register to be scanned as well as the number of registers to +** scan in "np". +** +** If "isCurrent" is non-zero then it is allowed for the thread context +** area to be used as scratch storage to hold just the registers +** necessary for scanning. +** +** This function simply calls the internal function _MD_HomeGCRegisters(). +*/ +NSPR_API(PRWord *) PR_GetGCRegisters(PRThread *t, int isCurrent, int *np); + +/* +** (Get|Set)ExecutionEnvironent +** +** Used by Java to associate it's execution environment so garbage collector +** can find it. If return is NULL, then it's probably not a collectable thread. +** +** There's no locking required around these calls. +*/ +NSPR_API(void*) GetExecutionEnvironment(PRThread *thread); +NSPR_API(void) SetExecutionEnvironment(PRThread* thread, void *environment); + +/* +** Enumeration function that applies "func(thread,i,arg)" to each active +** thread in the process. The enumerator returns PR_SUCCESS if the enumeration +** should continue, any other value is considered failure, and enumeration +** stops, returning the failure value from PR_EnumerateThreads. +** Needed by the garbage collector. +*/ +typedef PRStatus (PR_CALLBACK *PREnumerator)(PRThread *t, int i, void *arg); +NSPR_API(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg); + +/* +** Signature of a thread stack scanning function. It is applied to every +** contiguous group of potential pointers within a thread. Count denotes the +** number of pointers. +*/ +typedef PRStatus +(PR_CALLBACK *PRScanStackFun)(PRThread* t, + void** baseAddr, PRUword count, void* closure); + +/* +** Applies scanFun to all contiguous groups of potential pointers +** within a thread. This includes the stack, registers, and thread-local +** data. If scanFun returns a status value other than PR_SUCCESS the scan +** is aborted, and the status value is returned. +*/ +NSPR_API(PRStatus) +PR_ThreadScanStackPointers(PRThread* t, + PRScanStackFun scanFun, void* scanClosure); + +/* +** Calls PR_ThreadScanStackPointers for every thread. +*/ +NSPR_API(PRStatus) +PR_ScanStackPointers(PRScanStackFun scanFun, void* scanClosure); + +/* +** Returns a conservative estimate on the amount of stack space left +** on a thread in bytes, sufficient for making decisions about whether +** to continue recursing or not. +*/ +NSPR_API(PRUword) +PR_GetStackSpaceLeft(PRThread* t); + +/*--------------------------------------------------------------------------- +** THREAD CPU PRIVATE FUNCTIONS +---------------------------------------------------------------------------*/ + +/* +** Get a pointer to the primordial CPU. +*/ +NSPR_API(struct _PRCPU *) _PR_GetPrimordialCPU(void); + +/*--------------------------------------------------------------------------- +** THREAD SYNCHRONIZATION PRIVATE FUNCTIONS +---------------------------------------------------------------------------*/ + +/* +** Create a new named monitor (named for debugging purposes). +** Monitors are re-entrant locks with a built-in condition variable. +** +** This may fail if memory is tight or if some operating system resource +** is low. +*/ +NSPR_API(PRMonitor*) PR_NewNamedMonitor(const char* name); + +/* +** Test and then lock the lock if it's not already locked by some other +** thread. Return PR_FALSE if some other thread owned the lock at the +** time of the call. +*/ +NSPR_API(PRBool) PR_TestAndLock(PRLock *lock); + +/* +** Test and then enter the mutex associated with the monitor if it's not +** already entered by some other thread. Return PR_FALSE if some other +** thread owned the mutex at the time of the call. +*/ +NSPR_API(PRBool) PR_TestAndEnterMonitor(PRMonitor *mon); + +/* +** Return the number of times that the current thread has entered the +** mutex. Returns zero if the current thread has not entered the mutex. +*/ +NSPR_API(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon); + +/* +** Just like PR_CEnterMonitor except that if the monitor is owned by +** another thread NULL is returned. +*/ +NSPR_API(PRMonitor*) PR_CTestAndEnterMonitor(void *address); + +/*--------------------------------------------------------------------------- +** PLATFORM-SPECIFIC INITIALIZATION FUNCTIONS +---------------------------------------------------------------------------*/ +#if defined(IRIX) +/* +** Irix specific initialization funtion to be called before PR_Init +** is called by the application. Sets the CONF_INITUSERS and CONF_INITSIZE +** attributes of the shared arena set up by nspr. +** +** The environment variables _NSPR_IRIX_INITUSERS and _NSPR_IRIX_INITSIZE +** can also be used to set these arena attributes. If _NSPR_IRIX_INITUSERS +** is set, but not _NSPR_IRIX_INITSIZE, the value of the CONF_INITSIZE +** attribute of the nspr arena is scaled as a function of the +** _NSPR_IRIX_INITUSERS value. +** +** If the _PR_Irix_Set_Arena_Params() is called in addition to setting the +** environment variables, the values of the environment variables are used. +** +*/ +NSPR_API(void) _PR_Irix_Set_Arena_Params(PRInt32 initusers, PRInt32 initsize); + +#endif /* IRIX */ + +#if defined(XP_OS2) +/* +** These functions need to be called at the start and end of a thread. +** An EXCEPTIONREGISTRATIONRECORD must be declared on the stack and its +** address passed to the two functions. +*/ +NSPR_API(void) PR_OS2_SetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* e); +NSPR_API(void) PR_OS2_UnsetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* e); +#endif /* XP_OS2 */ + +/* I think PR_GetMonitorEntryCount is useless. All you really want is this... */ +#define PR_InMonitor(m) (PR_GetMonitorEntryCount(m) > 0) + +/*--------------------------------------------------------------------------- +** Special X-Lock hack for client +---------------------------------------------------------------------------*/ + +#ifdef XP_UNIX +extern void PR_XLock(void); +extern void PR_XUnlock(void); +extern PRBool PR_XIsLocked(void); +#endif /* XP_UNIX */ + +PR_END_EXTERN_C + +#endif /* pprthred_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/private/prpriv.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/private/prpriv.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/private/prpriv.h @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prpriv_h___ +#define prpriv_h___ + +/* + * NSPR 2.0 Private API + */ + +#include "private/pprio.h" +#include "private/pprthred.h" + +#endif /* prpriv_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prlink.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prlink.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prlink.h @@ -0,0 +1,230 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prlink_h___ +#define prlink_h___ + +/* +** API to static and dynamic linking. +*/ +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +typedef struct PRLibrary PRLibrary; + +typedef struct PRStaticLinkTable { + const char *name; + void (*fp)(void); +} PRStaticLinkTable; + +/* +** Change the default library path to the given string. The string is +** copied. This call will fail if it runs out of memory. +** +** The string provided as 'path' is copied. The caller can do whatever is +** convenient with the argument when the function is complete. +*/ +NSPR_API(PRStatus) PR_SetLibraryPath(const char *path); + +/* +** Return a character string which contains the path used to search for +** dynamically loadable libraries. +** +** The returned value is basically a copy of a PR_SetLibraryPath(). +** The storage is allocated by the runtime and becomes the responsibilty +** of the caller. +*/ +NSPR_API(char*) PR_GetLibraryPath(void); + +/* +** Given a directory name "dir" and a library name "lib" construct a full +** path name that will refer to the actual dynamically loaded +** library. This does not test for existance of said file, it just +** constructs the full filename. The name constructed is system dependent +** and prepared for PR_LoadLibrary. The result must be free'd when the +** caller is done with it. +** +** The storage for the result is allocated by the runtime and becomes the +** responsibility of the caller. +*/ +NSPR_API(char*) PR_GetLibraryName(const char *dir, const char *lib); + +/* +** +** Free the memory allocated, for the caller, by PR_GetLibraryName +*/ +NSPR_API(void) PR_FreeLibraryName(char *mem); + +/* +** Given a library "name" try to load the library. The argument "name" +** is a machine-dependent name for the library, such as the full pathname +** returned by PR_GetLibraryName. If the library is already loaded, +** this function will avoid loading the library twice. +** +** If the library is loaded successfully, then a pointer to the PRLibrary +** structure representing the library is returned. Otherwise, NULL is +** returned. +** +** This increments the reference count of the library. +*/ +NSPR_API(PRLibrary*) PR_LoadLibrary(const char *name); + +/* +** Each operating system has its preferred way of specifying +** a file in the file system. Most operating systems use +** a pathname. Mac OS Classic, on the other hand, uses the FSSpec +** structure to specify a file. PRLibSpec allows NSPR clients +** to use the type of file specification that is most efficient +** for a particular platform. +** +** On some operating systems such as Mac OS Classic, a shared library +** may contain code fragments that can be individually loaded. +** PRLibSpec also allows NSPR clients to identify a code fragment +** in a library, if code fragments are supported by the OS. +** A code fragment can be specified by name or by an integer index. +** +** Right now PRLibSpec supports four types of library specification: +** a pathname in the native character encoding, a Mac code fragment +** by name, a Mac code fragment by index, and a UTF-16 pathname. +*/ + +typedef enum PRLibSpecType { + PR_LibSpec_Pathname, + PR_LibSpec_MacNamedFragment, /* obsolete (for Mac OS Classic) */ + PR_LibSpec_MacIndexedFragment, /* obsolete (for Mac OS Classic) */ + PR_LibSpec_PathnameU /* supported only on Win32 */ +} PRLibSpecType; + +struct FSSpec; /* Mac OS Classic FSSpec */ + +typedef struct PRLibSpec { + PRLibSpecType type; + union { + /* if type is PR_LibSpec_Pathname */ + const char *pathname; + + /* if type is PR_LibSpec_MacNamedFragment */ + struct { + const struct FSSpec *fsspec; + const char *name; + } mac_named_fragment; /* obsolete (for Mac OS Classic) */ + + /* if type is PR_LibSpec_MacIndexedFragment */ + struct { + const struct FSSpec *fsspec; + PRUint32 index; + } mac_indexed_fragment; /* obsolete (for Mac OS Classic) */ + + /* if type is PR_LibSpec_PathnameU */ + const PRUnichar *pathname_u; /* supported only on Win32 */ + } value; +} PRLibSpec; + +/* +** The following bit flags may be or'd together and passed +** as the 'flags' argument to PR_LoadLibraryWithFlags. +** Flags not supported by the underlying OS are ignored. +*/ + +#define PR_LD_LAZY 0x1 /* equivalent to RTLD_LAZY on Unix */ +#define PR_LD_NOW 0x2 /* equivalent to RTLD_NOW on Unix */ +#define PR_LD_GLOBAL 0x4 /* equivalent to RTLD_GLOBAL on Unix */ +#define PR_LD_LOCAL 0x8 /* equivalent to RTLD_LOCAL on Unix */ +/* The following is equivalent to LOAD_WITH_ALTERED_SEARCH_PATH on Windows */ +#define PR_LD_ALT_SEARCH_PATH 0x10 +/* 0x8000 reserved for NSPR internal use */ + +/* +** Load the specified library, in the manner specified by 'flags'. +*/ + +NSPR_API(PRLibrary *) +PR_LoadLibraryWithFlags( + PRLibSpec libSpec, /* the shared library */ + PRIntn flags /* flags that affect the loading */ +); + +/* +** Unload a previously loaded library. If the library was a static +** library then the static link table will no longer be referenced. The +** associated PRLibrary object is freed. +** +** PR_FAILURE is returned if the library cannot be unloaded. +** +** This function decrements the reference count of the library. +*/ +NSPR_API(PRStatus) PR_UnloadLibrary(PRLibrary *lib); + +/* +** Given the name of a procedure, return the address of the function that +** implements the procedure, or NULL if no such function can be +** found. This does not find symbols in the main program (the ".exe"); +** use PR_LoadStaticLibrary to register symbols in the main program. +** +** This function does not modify the reference count of the library. +*/ +NSPR_API(void*) PR_FindSymbol(PRLibrary *lib, const char *name); + +/* +** Similar to PR_FindSymbol, except that the return value is a pointer to +** a function, and not a pointer to void. Casting between a data pointer +** and a function pointer is not portable according to the C standard. +** Any function pointer can be cast to any other function pointer. +** +** This function does not modify the reference count of the library. +*/ +typedef void (*PRFuncPtr)(void); +NSPR_API(PRFuncPtr) PR_FindFunctionSymbol(PRLibrary *lib, const char *name); + +/* +** Finds a symbol in one of the currently loaded libraries. Given the +** name of a procedure, return the address of the function that +** implements the procedure, and return the library that contains that +** symbol, or NULL if no such function can be found. This does not find +** symbols in the main program (the ".exe"); use PR_AddStaticLibrary to +** register symbols in the main program. +** +** This increments the reference count of the library. +*/ +NSPR_API(void*) PR_FindSymbolAndLibrary(const char *name, + PRLibrary* *lib); + +/* +** Similar to PR_FindSymbolAndLibrary, except that the return value is +** a pointer to a function, and not a pointer to void. Casting between a +** data pointer and a function pointer is not portable according to the C +** standard. Any function pointer can be cast to any other function pointer. +** +** This increments the reference count of the library. +*/ +NSPR_API(PRFuncPtr) PR_FindFunctionSymbolAndLibrary(const char *name, + PRLibrary* *lib); + +/* +** Register a static link table with the runtime under the name +** "name". The symbols present in the static link table will be made +** available to PR_FindSymbol. If "name" is null then the symbols will be +** made available to the library which represents the executable. The +** tables are not copied. +** +** Returns the library object if successful, null otherwise. +** +** This increments the reference count of the library. +*/ +NSPR_API(PRLibrary*) PR_LoadStaticLibrary( + const char *name, const PRStaticLinkTable *table); + +/* +** Return the pathname of the file that the library "name" was loaded +** from. "addr" is the address of a function defined in the library. +** +** The caller is responsible for freeing the result with PR_Free. +*/ +NSPR_API(char *) PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr); + +PR_END_EXTERN_C + +#endif /* prlink_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prlock.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prlock.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prlock.h @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: prlock.h +** Description: API to basic locking functions of NSPR. +** +** +** NSPR provides basic locking mechanisms for thread synchronization. Locks +** are lightweight resource contention controls that prevent multiple threads +** from accessing something (code/data) simultaneously. +**/ + +#ifndef prlock_h___ +#define prlock_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +/* + * PRLock -- + * + * NSPR represents the lock as an opaque entity to the client of the + * API. All routines operate on a pointer to this opaque entity. + */ + +typedef struct PRLock PRLock; + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/*********************************************************************** +** FUNCTION: PR_NewLock +** DESCRIPTION: +** Returns a pointer to a newly created opaque lock object. +** INPUTS: void +** OUTPUTS: void +** RETURN: PRLock* +** If the lock can not be created because of resource constraints, NULL +** is returned. +** +***********************************************************************/ +NSPR_API(PRLock*) PR_NewLock(void); + +/*********************************************************************** +** FUNCTION: PR_DestroyLock +** DESCRIPTION: +** Destroys a given opaque lock object. +** INPUTS: PRLock *lock +** Lock to be freed. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_DestroyLock(PRLock *lock); + +/*********************************************************************** +** FUNCTION: PR_Lock +** DESCRIPTION: +** Lock a lock. +** INPUTS: PRLock *lock +** Lock to locked. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_Lock(PRLock *lock); + +/*********************************************************************** +** FUNCTION: PR_Unlock +** DESCRIPTION: +** Unlock a lock. Unlocking an unlocked lock has undefined results. +** INPUTS: PRLock *lock +** Lock to unlocked. +** OUTPUTS: void +** RETURN: PR_STATUS +** Returns PR_FAILURE if the caller does not own the lock. +***********************************************************************/ +NSPR_API(PRStatus) PR_Unlock(PRLock *lock); + +/*********************************************************************** +** MACRO: PR_ASSERT_CURRENT_THREAD_OWNS_LOCK +** DESCRIPTION: +** If the current thread owns |lock|, this assertion is guaranteed to +** succeed. Otherwise, the behavior of this function is undefined. +** INPUTS: PRLock *lock +** Lock to assert ownership of. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +#if defined(DEBUG) || defined(FORCE_PR_ASSERT) +#define PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(/* PrLock* */ lock) \ + PR_AssertCurrentThreadOwnsLock(lock) +#else +#define PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(/* PrLock* */ lock) +#endif + +/* Don't call this function directly. */ +NSPR_API(void) PR_AssertCurrentThreadOwnsLock(PRLock *lock); + +PR_END_EXTERN_C + +#endif /* prlock_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prlog.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prlog.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prlog.h @@ -0,0 +1,222 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prlog_h___ +#define prlog_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** prlog.h -- Declare interfaces to NSPR's Logging service +** +** NSPR provides a logging service that is used by NSPR itself and is +** available to client programs. +** +** To use the service from a client program, you should create a +** PRLogModuleInfo structure by calling PR_NewLogModule(). After +** creating the LogModule, you can write to the log using the PR_LOG() +** macro. +** +** Initialization of the log service is handled by NSPR initialization. +** +** At execution time, you must enable the log service. To enable the +** log service, set the environment variable: NSPR_LOG_MODULES +** variable. +** +** NSPR_LOG_MODULES variable has the form: +** +** :[, :]* +** +** Where: +** is the name passed to PR_NewLogModule(). +** is a numeric constant, e.g. 5. This value is the maximum +** value of a log event, enumerated by PRLogModuleLevel, that you want +** written to the log. +** +** For example: to record all events of greater value than or equal to +** PR_LOG_ERROR for a LogModule names "gizmo", say: +** +** set NSPR_LOG_MODULES=gizmo:2 +** +** Note that you must specify the numeric value of PR_LOG_ERROR. +** +** Special LogModule names are provided for controlling NSPR's log +** service at execution time. These controls should be set in the +** NSPR_LOG_MODULES environment variable at execution time to affect +** NSPR's log service for your application. +** +** The special LogModule "all" enables all LogModules. To enable all +** LogModule calls to PR_LOG(), say: +** +** set NSPR_LOG_MODULES=all:5 +** +** The special LogModule name "sync" tells the NSPR log service to do +** unbuffered logging. +** +** The special LogModule name "bufsize:" tells NSPR to set the +** log buffer to . +** +** The environment variable NSPR_LOG_FILE specifies the log file to use +** unless the default of "stderr" is acceptable. For MS Windows +** systems, NSPR_LOG_FILE can be set to a special value: "WinDebug" +** (case sensitive). This value causes PR_LOG() output to be written +** using the Windows API OutputDebugString(). OutputDebugString() +** writes to the debugger window; some people find this helpful. +** +** +** To put log messages in your programs, use the PR_LOG macro: +** +** PR_LOG(, , (, *)); +** +** Where is the address of a PRLogModuleInfo structure, and +** is one of the levels defined by the enumeration: +** PRLogModuleLevel. is a printf() style of argument list. That +** is: (fmtstring, ...). +** +** Example: +** +** main() { +** PRIntn one = 1; +** PRLogModuleInfo * myLm = PR_NewLogModule("gizmo"); +** PR_LOG( myLm, PR_LOG_ALWAYS, ("Log this! %d\n", one)); +** return; +** } +** +** Note the use of printf() style arguments as the third agrument(s) to +** PR_LOG(). +** +** After compiling and linking you application, set the environment: +** +** set NSPR_LOG_MODULES=gizmo:5 +** set NSPR_LOG_FILE=logfile.txt +** +** When you execute your application, the string "Log this! 1" will be +** written to the file "logfile.txt". +** +** Note to NSPR engineers: a number of PRLogModuleInfo structures are +** defined and initialized in prinit.c. See this module for ideas on +** what to log where. +** +*/ + +typedef enum PRLogModuleLevel { + PR_LOG_NONE = 0, /* nothing */ + PR_LOG_ALWAYS = 1, /* always printed */ + PR_LOG_ERROR = 2, /* error messages */ + PR_LOG_WARNING = 3, /* warning messages */ + PR_LOG_DEBUG = 4, /* debug messages */ + + PR_LOG_NOTICE = PR_LOG_DEBUG, /* notice messages */ + PR_LOG_WARN = PR_LOG_WARNING, /* warning messages */ + PR_LOG_MIN = PR_LOG_DEBUG, /* minimal debugging messages */ + PR_LOG_MAX = PR_LOG_DEBUG /* maximal debugging messages */ +} PRLogModuleLevel; + +/* +** One of these structures is created for each module that uses logging. +** "name" is the name of the module +** "level" is the debugging level selected for that module +*/ +typedef struct PRLogModuleInfo { + const char *name; + PRLogModuleLevel level; + struct PRLogModuleInfo *next; +} PRLogModuleInfo; + +/* +** Create a new log module. +*/ +NSPR_API(PRLogModuleInfo*) PR_NewLogModule(const char *name); + +/* +** Set the file to use for logging. Returns PR_FALSE if the file cannot +** be created +*/ +NSPR_API(PRBool) PR_SetLogFile(const char *name); + +/* +** Set the size of the logging buffer. If "buffer_size" is zero then the +** logging becomes "synchronous" (or unbuffered). +*/ +NSPR_API(void) PR_SetLogBuffering(PRIntn buffer_size); + +/* +** Print a string to the log. "fmt" is a PR_snprintf format type. All +** messages printed to the log are preceeded by the name of the thread +** and a time stamp. Also, the routine provides a missing newline if one +** is not provided. +*/ +NSPR_API(void) PR_LogPrint(const char *fmt, ...); + +/* +** Flush the log to its file. +*/ +NSPR_API(void) PR_LogFlush(void); + +NSPR_API(void) PR_Assert(const char *s, const char *file, PRIntn ln) + PR_PRETEND_NORETURN; + +#if defined(DEBUG) || defined(FORCE_PR_LOG) +#define PR_LOGGING 1 + +#define PR_LOG_TEST(_module,_level) \ + ((_module)->level >= (_level)) + +/* +** Log something. +** "module" is the address of a PRLogModuleInfo structure +** "level" is the desired logging level +** "args" is a variable length list of arguments to print, in the following +** format: ("printf style format string", ...) +*/ +#define PR_LOG(_module,_level,_args) \ + PR_BEGIN_MACRO \ + if (PR_LOG_TEST(_module,_level)) { \ + PR_LogPrint _args; \ + } \ + PR_END_MACRO + +#else /* defined(DEBUG) || defined(FORCE_PR_LOG) */ + +#undef PR_LOGGING +#define PR_LOG_TEST(module,level) 0 +#define PR_LOG(module,level,args) + +#endif /* defined(DEBUG) || defined(FORCE_PR_LOG) */ + +#ifndef NO_NSPR_10_SUPPORT + +#ifdef PR_LOGGING +#define PR_LOG_BEGIN PR_LOG +#define PR_LOG_END PR_LOG +#define PR_LOG_DEFINE PR_NewLogModule +#else +#define PR_LOG_BEGIN(module,level,args) +#define PR_LOG_END(module,level,args) +#define PR_LOG_DEFINE(_name) NULL +#endif /* PR_LOGGING */ + +#endif /* NO_NSPR_10_SUPPORT */ + +#if defined(DEBUG) || defined(FORCE_PR_ASSERT) + +#define PR_ASSERT(_expr) \ + ((_expr)?((void)0):PR_Assert(# _expr,__FILE__,__LINE__)) + +#define PR_NOT_REACHED(_reasonStr) \ + PR_Assert(_reasonStr,__FILE__,__LINE__) + +#else + +#define PR_ASSERT(expr) ((void) 0) +#define PR_NOT_REACHED(reasonStr) + +#endif /* defined(DEBUG) || defined(FORCE_PR_ASSERT) */ + +PR_END_EXTERN_C + +#endif /* prlog_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prlong.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prlong.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prlong.h @@ -0,0 +1,403 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: prlong.h +** Description: Portable access to 64 bit numerics +** +** Long-long (64-bit signed integer type) support. Some C compilers +** don't support 64 bit integers yet, so we use these macros to +** support both machines that do and don't. +**/ +#ifndef prlong_h___ +#define prlong_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/*********************************************************************** +** DEFINES: LL_MaxInt +** LL_MinInt +** LL_Zero +** LL_MaxUint +** DESCRIPTION: +** Various interesting constants and static variable +** initializer +***********************************************************************/ +NSPR_API(PRInt64) LL_MaxInt(void); +NSPR_API(PRInt64) LL_MinInt(void); +NSPR_API(PRInt64) LL_Zero(void); +NSPR_API(PRUint64) LL_MaxUint(void); + +#if defined(HAVE_LONG_LONG) + +/* Keep this in sync with prtypes.h. */ +#if PR_BYTES_PER_LONG == 8 && !defined(PR_ALTERNATE_INT64_TYPEDEF) +#define LL_MAXINT 9223372036854775807L +#define LL_MININT (-LL_MAXINT - 1L) +#define LL_ZERO 0L +#define LL_MAXUINT 18446744073709551615UL +#define LL_INIT(hi, lo) ((hi ## L << 32) + lo ## L) +#elif defined(WIN32) && !defined(__GNUC__) +#define LL_MAXINT 9223372036854775807i64 +#define LL_MININT (-LL_MAXINT - 1i64) +#define LL_ZERO 0i64 +#define LL_MAXUINT 18446744073709551615ui64 +#define LL_INIT(hi, lo) ((hi ## i64 << 32) + lo ## i64) +#else +#define LL_MAXINT 9223372036854775807LL +#define LL_MININT (-LL_MAXINT - 1LL) +#define LL_ZERO 0LL +#define LL_MAXUINT 18446744073709551615ULL +#define LL_INIT(hi, lo) ((hi ## LL << 32) + lo ## LL) +#endif + +/*********************************************************************** +** MACROS: LL_* +** DESCRIPTION: +** The following macros define portable access to the 64 bit +** math facilities. +** +***********************************************************************/ + +/*********************************************************************** +** MACROS: LL_ +** +** LL_IS_ZERO Test for zero +** LL_EQ Test for equality +** LL_NE Test for inequality +** LL_GE_ZERO Test for zero or positive +** LL_CMP Compare two values +***********************************************************************/ +#define LL_IS_ZERO(a) ((a) == 0) +#define LL_EQ(a, b) ((a) == (b)) +#define LL_NE(a, b) ((a) != (b)) +#define LL_GE_ZERO(a) ((a) >= 0) +#define LL_CMP(a, op, b) ((PRInt64)(a) op (PRInt64)(b)) +#define LL_UCMP(a, op, b) ((PRUint64)(a) op (PRUint64)(b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_AND Logical and +** LL_OR Logical or +** LL_XOR Logical exclusion +** LL_OR2 A disgusting deviation +** LL_NOT Negation (one's complement) +***********************************************************************/ +#define LL_AND(r, a, b) ((r) = (a) & (b)) +#define LL_OR(r, a, b) ((r) = (a) | (b)) +#define LL_XOR(r, a, b) ((r) = (a) ^ (b)) +#define LL_OR2(r, a) ((r) = (r) | (a)) +#define LL_NOT(r, a) ((r) = ~(a)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_NEG Negation (two's complement) +** LL_ADD Summation (two's complement) +** LL_SUB Difference (two's complement) +***********************************************************************/ +#define LL_NEG(r, a) ((r) = -(a)) +#define LL_ADD(r, a, b) ((r) = (a) + (b)) +#define LL_SUB(r, a, b) ((r) = (a) - (b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_MUL Product (two's complement) +** LL_DIV Quotient (two's complement) +** LL_MOD Modulus (two's complement) +***********************************************************************/ +#define LL_MUL(r, a, b) ((r) = (a) * (b)) +#define LL_DIV(r, a, b) ((r) = (a) / (b)) +#define LL_MOD(r, a, b) ((r) = (a) % (b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_SHL Shift left [0..64] bits +** LL_SHR Shift right [0..64] bits with sign extension +** LL_USHR Unsigned shift right [0..64] bits +** LL_ISHL Signed shift left [0..64] bits +***********************************************************************/ +#define LL_SHL(r, a, b) ((r) = (PRInt64)(a) << (b)) +#define LL_SHR(r, a, b) ((r) = (PRInt64)(a) >> (b)) +#define LL_USHR(r, a, b) ((r) = (PRUint64)(a) >> (b)) +#define LL_ISHL(r, a, b) ((r) = (PRInt64)(a) << (b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_L2I Convert to signed 32 bit +** LL_L2UI Convert to unsigned 32 bit +** LL_L2F Convert to floating point +** LL_L2D Convert to floating point +** LL_I2L Convert signed to 64 bit +** LL_UI2L Convert unsigned to 64 bit +** LL_F2L Convert float to 64 bit +** LL_D2L Convert float to 64 bit +***********************************************************************/ +#define LL_L2I(i, l) ((i) = (PRInt32)(l)) +#define LL_L2UI(ui, l) ((ui) = (PRUint32)(l)) +#define LL_L2F(f, l) ((f) = (PRFloat64)(l)) +#define LL_L2D(d, l) ((d) = (PRFloat64)(l)) + +#define LL_I2L(l, i) ((l) = (PRInt64)(i)) +#define LL_UI2L(l, ui) ((l) = (PRInt64)(ui)) +#define LL_F2L(l, f) ((l) = (PRInt64)(f)) +#define LL_D2L(l, d) ((l) = (PRInt64)(d)) + +/*********************************************************************** +** MACROS: LL_UDIVMOD +** DESCRIPTION: +** Produce both a quotient and a remainder given an unsigned +** INPUTS: PRUint64 a: The dividend of the operation +** PRUint64 b: The quotient of the operation +** OUTPUTS: PRUint64 *qp: pointer to quotient +** PRUint64 *rp: pointer to remainder +***********************************************************************/ +#define LL_UDIVMOD(qp, rp, a, b) \ + (*(qp) = ((PRUint64)(a) / (b)), \ + *(rp) = ((PRUint64)(a) % (b))) + +#else /* !HAVE_LONG_LONG */ + +#define LL_MAXINT LL_MaxInt() +#define LL_MININT LL_MinInt() +#define LL_ZERO LL_Zero() +#define LL_MAXUINT LL_MaxUint() + +#ifdef IS_LITTLE_ENDIAN +#define LL_INIT(hi, lo) {PR_UINT32(lo), PR_UINT32(hi)} +#else +#define LL_INIT(hi, lo) {PR_UINT32(hi), PR_UINT32(lo)} +#endif + +#define LL_IS_ZERO(a) (((a).hi == 0) && ((a).lo == 0)) +#define LL_EQ(a, b) (((a).hi == (b).hi) && ((a).lo == (b).lo)) +#define LL_NE(a, b) (((a).hi != (b).hi) || ((a).lo != (b).lo)) +#define LL_GE_ZERO(a) (((a).hi >> 31) == 0) + +#define LL_CMP(a, op, b) (((a).hi == (b).hi) ? ((a).lo op (b).lo) : \ + ((PRInt32)(a).hi op (PRInt32)(b).hi)) +#define LL_UCMP(a, op, b) (((a).hi == (b).hi) ? ((a).lo op (b).lo) : \ + ((a).hi op (b).hi)) + +#define LL_AND(r, a, b) ((r).lo = (a).lo & (b).lo, \ + (r).hi = (a).hi & (b).hi) +#define LL_OR(r, a, b) ((r).lo = (a).lo | (b).lo, \ + (r).hi = (a).hi | (b).hi) +#define LL_XOR(r, a, b) ((r).lo = (a).lo ^ (b).lo, \ + (r).hi = (a).hi ^ (b).hi) +#define LL_OR2(r, a) ((r).lo = (r).lo | (a).lo, \ + (r).hi = (r).hi | (a).hi) +#define LL_NOT(r, a) ((r).lo = ~(a).lo, \ + (r).hi = ~(a).hi) + +#define LL_NEG(r, a) ((r).lo = -(PRInt32)(a).lo, \ + (r).hi = -(PRInt32)(a).hi - ((r).lo != 0)) +#define LL_ADD(r, a, b) { \ + PRInt64 _a, _b; \ + _a = a; _b = b; \ + (r).lo = _a.lo + _b.lo; \ + (r).hi = _a.hi + _b.hi + ((r).lo < _b.lo); \ +} + +#define LL_SUB(r, a, b) { \ + PRInt64 _a, _b; \ + _a = a; _b = b; \ + (r).lo = _a.lo - _b.lo; \ + (r).hi = _a.hi - _b.hi - (_a.lo < _b.lo); \ +} + +#define LL_MUL(r, a, b) { \ + PRInt64 _a, _b; \ + _a = a; _b = b; \ + LL_MUL32(r, _a.lo, _b.lo); \ + (r).hi += _a.hi * _b.lo + _a.lo * _b.hi; \ +} + +#define _lo16(a) ((a) & PR_BITMASK(16)) +#define _hi16(a) ((a) >> 16) + +#define LL_MUL32(r, a, b) { \ + PRUint32 _a1, _a0, _b1, _b0, _y0, _y1, _y2, _y3; \ + _a1 = _hi16(a), _a0 = _lo16(a); \ + _b1 = _hi16(b), _b0 = _lo16(b); \ + _y0 = _a0 * _b0; \ + _y1 = _a0 * _b1; \ + _y2 = _a1 * _b0; \ + _y3 = _a1 * _b1; \ + _y1 += _hi16(_y0); /* can't carry */ \ + _y1 += _y2; /* might carry */ \ + if (_y1 < _y2) \ + _y3 += (PRUint32)(PR_BIT(16)); /* propagate */ \ + (r).lo = (_lo16(_y1) << 16) + _lo16(_y0); \ + (r).hi = _y3 + _hi16(_y1); \ +} + +#define LL_UDIVMOD(qp, rp, a, b) ll_udivmod(qp, rp, a, b) + +NSPR_API(void) ll_udivmod(PRUint64 *qp, PRUint64 *rp, PRUint64 a, PRUint64 b); + +#define LL_DIV(r, a, b) { \ + PRInt64 _a, _b; \ + PRUint32 _negative = (PRInt32)(a).hi < 0; \ + if (_negative) { \ + LL_NEG(_a, a); \ + } else { \ + _a = a; \ + } \ + if ((PRInt32)(b).hi < 0) { \ + _negative ^= 1; \ + LL_NEG(_b, b); \ + } else { \ + _b = b; \ + } \ + LL_UDIVMOD(&(r), 0, _a, _b); \ + if (_negative) \ + LL_NEG(r, r); \ +} + +#define LL_MOD(r, a, b) { \ + PRInt64 _a, _b; \ + PRUint32 _negative = (PRInt32)(a).hi < 0; \ + if (_negative) { \ + LL_NEG(_a, a); \ + } else { \ + _a = a; \ + } \ + if ((PRInt32)(b).hi < 0) { \ + LL_NEG(_b, b); \ + } else { \ + _b = b; \ + } \ + LL_UDIVMOD(0, &(r), _a, _b); \ + if (_negative) \ + LL_NEG(r, r); \ +} + +#define LL_SHL(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = _a.lo << ((b) & 31); \ + (r).hi = (_a.hi << ((b) & 31)) | (_a.lo >> (32 - (b))); \ + } else { \ + (r).lo = 0; \ + (r).hi = _a.lo << ((b) & 31); \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +/* a is an PRInt32, b is PRInt32, r is PRInt64 */ +#define LL_ISHL(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a.lo = (a); \ + _a.hi = 0; \ + if ((b) < 32) { \ + (r).lo = (a) << ((b) & 31); \ + (r).hi = ((a) >> (32 - (b))); \ + } else { \ + (r).lo = 0; \ + (r).hi = (a) << ((b) & 31); \ + } \ + } else { \ + (r).lo = (a); \ + (r).hi = 0; \ + } \ +} + +#define LL_SHR(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> ((b) & 31)); \ + (r).hi = (PRInt32)_a.hi >> ((b) & 31); \ + } else { \ + (r).lo = (PRInt32)_a.hi >> ((b) & 31); \ + (r).hi = (PRInt32)_a.hi >> 31; \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +#define LL_USHR(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> ((b) & 31)); \ + (r).hi = _a.hi >> ((b) & 31); \ + } else { \ + (r).lo = _a.hi >> ((b) & 31); \ + (r).hi = 0; \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +#define LL_L2I(i, l) ((i) = (l).lo) +#define LL_L2UI(ui, l) ((ui) = (l).lo) +#define LL_L2F(f, l) { double _d; LL_L2D(_d, l); (f) = (PRFloat64)_d; } + +#define LL_L2D(d, l) { \ + int _negative; \ + PRInt64 _absval; \ + \ + _negative = (l).hi >> 31; \ + if (_negative) { \ + LL_NEG(_absval, l); \ + } else { \ + _absval = l; \ + } \ + (d) = (double)_absval.hi * 4.294967296e9 + _absval.lo; \ + if (_negative) \ + (d) = -(d); \ +} + +#define LL_I2L(l, i) { PRInt32 _i = ((PRInt32)(i)) >> 31; (l).lo = (i); (l).hi = _i; } +#define LL_UI2L(l, ui) ((l).lo = (ui), (l).hi = 0) +#define LL_F2L(l, f) { double _d = (double)f; LL_D2L(l, _d); } + +#define LL_D2L(l, d) { \ + int _negative; \ + double _absval, _d_hi; \ + PRInt64 _lo_d; \ + \ + _negative = ((d) < 0); \ + _absval = _negative ? -(d) : (d); \ + \ + (l).hi = _absval / 4.294967296e9; \ + (l).lo = 0; \ + LL_L2D(_d_hi, l); \ + _absval -= _d_hi; \ + _lo_d.hi = 0; \ + if (_absval < 0) { \ + _lo_d.lo = -_absval; \ + LL_SUB(l, l, _lo_d); \ + } else { \ + _lo_d.lo = _absval; \ + LL_ADD(l, l, _lo_d); \ + } \ + \ + if (_negative) \ + LL_NEG(l, l); \ +} + +#endif /* !HAVE_LONG_LONG */ + +PR_END_EXTERN_C + +#endif /* prlong_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prmem.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prmem.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prmem.h @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: prmem.h +** Description: API to NSPR memory management functions +** +*/ +#ifndef prmem_h___ +#define prmem_h___ + +#include "prtypes.h" +#include + +PR_BEGIN_EXTERN_C + +/* +** Thread safe memory allocation. +** +** NOTE: pr wraps up malloc, free, calloc, realloc so they are already +** thread safe (and are not declared here - look in stdlib.h). +*/ + +/* +** PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free have the same signatures +** as their libc equivalent malloc, calloc, realloc, and free, and have +** the same semantics. (Note that the argument type size_t is replaced +** by PRUint32.) Memory allocated by PR_Malloc, PR_Calloc, or PR_Realloc +** must be freed by PR_Free. +*/ + +NSPR_API(void *) PR_Malloc(PRUint32 size); + +NSPR_API(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize); + +NSPR_API(void *) PR_Realloc(void *ptr, PRUint32 size); + +NSPR_API(void) PR_Free(void *ptr); + +/* +** The following are some convenience macros defined in terms of +** PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free. +*/ + +/*********************************************************************** +** FUNCTION: PR_MALLOC() +** DESCRIPTION: +** PR_NEW() allocates an untyped item of size _size from the heap. +** INPUTS: _size: size in bytes of item to be allocated +** OUTPUTS: untyped pointer to the node allocated +** RETURN: pointer to node or error returned from malloc(). +***********************************************************************/ +#define PR_MALLOC(_bytes) (PR_Malloc((_bytes))) + +/*********************************************************************** +** FUNCTION: PR_NEW() +** DESCRIPTION: +** PR_NEW() allocates an item of type _struct from the heap. +** INPUTS: _struct: a data type +** OUTPUTS: pointer to _struct +** RETURN: pointer to _struct or error returns from malloc(). +***********************************************************************/ +#define PR_NEW(_struct) ((_struct *) PR_MALLOC(sizeof(_struct))) + +/*********************************************************************** +** FUNCTION: PR_REALLOC() +** DESCRIPTION: +** PR_REALLOC() re-allocates _ptr bytes from the heap as a _size +** untyped item. +** INPUTS: _ptr: pointer to node to reallocate +** _size: size of node to allocate +** OUTPUTS: pointer to node allocated +** RETURN: pointer to node allocated +***********************************************************************/ +#define PR_REALLOC(_ptr, _size) (PR_Realloc((_ptr), (_size))) + +/*********************************************************************** +** FUNCTION: PR_CALLOC() +** DESCRIPTION: +** PR_CALLOC() allocates a _size bytes untyped item from the heap +** and sets the allocated memory to all 0x00. +** INPUTS: _size: size of node to allocate +** OUTPUTS: pointer to node allocated +** RETURN: pointer to node allocated +***********************************************************************/ +#define PR_CALLOC(_size) (PR_Calloc(1, (_size))) + +/*********************************************************************** +** FUNCTION: PR_NEWZAP() +** DESCRIPTION: +** PR_NEWZAP() allocates an item of type _struct from the heap +** and sets the allocated memory to all 0x00. +** INPUTS: _struct: a data type +** OUTPUTS: pointer to _struct +** RETURN: pointer to _struct +***********************************************************************/ +#define PR_NEWZAP(_struct) ((_struct*)PR_Calloc(1, sizeof(_struct))) + +/*********************************************************************** +** FUNCTION: PR_DELETE() +** DESCRIPTION: +** PR_DELETE() unallocates an object previosly allocated via PR_NEW() +** or PR_NEWZAP() to the heap. +** INPUTS: pointer to previously allocated object +** OUTPUTS: the referenced object is returned to the heap +** RETURN: void +***********************************************************************/ +#define PR_DELETE(_ptr) { PR_Free(_ptr); (_ptr) = NULL; } + +/*********************************************************************** +** FUNCTION: PR_FREEIF() +** DESCRIPTION: +** PR_FREEIF() conditionally unallocates an object previously allocated +** vial PR_NEW() or PR_NEWZAP(). If the pointer to the object is +** equal to zero (0), the object is not released. +** INPUTS: pointer to previously allocated object +** OUTPUTS: the referenced object is conditionally returned to the heap +** RETURN: void +***********************************************************************/ +#define PR_FREEIF(_ptr) if (_ptr) PR_DELETE(_ptr) + +PR_END_EXTERN_C + +#endif /* prmem_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prmon.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prmon.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prmon.h @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prmon_h___ +#define prmon_h___ + +#include "prtypes.h" +#include "prinrval.h" + +PR_BEGIN_EXTERN_C + +typedef struct PRMonitor PRMonitor; + +/* +** Create a new monitor. Monitors are re-entrant locks with a single built-in +** condition variable. +** +** This may fail if memory is tight or if some operating system resource +** is low. +*/ +NSPR_API(PRMonitor*) PR_NewMonitor(void); + +/* +** Destroy a monitor. The caller is responsible for guaranteeing that the +** monitor is no longer in use. There must be no thread waiting on the monitor's +** condition variable and that the lock is not held. +** +*/ +NSPR_API(void) PR_DestroyMonitor(PRMonitor *mon); + +/* +** Enter the lock associated with the monitor. If the calling thread currently +** is in the monitor, the call to enter will silently succeed. In either case, +** it will increment the entry count by one. +*/ +NSPR_API(void) PR_EnterMonitor(PRMonitor *mon); + +/* +** Decrement the entry count associated with the monitor. If the decremented +** entry count is zero, the monitor is exited. Returns PR_FAILURE if the +** calling thread has not entered the monitor. +*/ +NSPR_API(PRStatus) PR_ExitMonitor(PRMonitor *mon); + +/* +** Wait for a notify on the monitor's condition variable. Sleep for "ticks" +** amount of time (if "ticks" is PR_INTERVAL_NO_TIMEOUT then the sleep is +** indefinite). +** +** While the thread is waiting it exits the monitor (as if it called +** PR_ExitMonitor as many times as it had called PR_EnterMonitor). When +** the wait has finished the thread regains control of the monitors lock +** with the same entry count as before the wait began. +** +** The thread waiting on the monitor will be resumed when the monitor is +** notified (assuming the thread is the next in line to receive the +** notify) or when the "ticks" timeout elapses. +** +** Returns PR_FAILURE if the caller has not entered the monitor. +*/ +NSPR_API(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime ticks); + +/* +** Notify a thread waiting on the monitor's condition variable. If a thread +** is waiting on the condition variable (using PR_Wait) then it is awakened +** and attempts to reenter the monitor. +*/ +NSPR_API(PRStatus) PR_Notify(PRMonitor *mon); + +/* +** Notify all of the threads waiting on the monitor's condition variable. +** All of threads waiting on the condition are scheduled to reenter the +** monitor. +*/ +NSPR_API(PRStatus) PR_NotifyAll(PRMonitor *mon); + +/* +** PR_ASSERT_CURRENT_THREAD_IN_MONITOR +** If the current thread is in |mon|, this assertion is guaranteed to +** succeed. Otherwise, the behavior of this function is undefined. +*/ +#if defined(DEBUG) || defined(FORCE_PR_ASSERT) +#define PR_ASSERT_CURRENT_THREAD_IN_MONITOR(/* PRMonitor* */ mon) \ + PR_AssertCurrentThreadInMonitor(mon) +#else +#define PR_ASSERT_CURRENT_THREAD_IN_MONITOR(/* PRMonitor* */ mon) +#endif + +/* Don't call this function directly. */ +NSPR_API(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon); + +PR_END_EXTERN_C + +#endif /* prmon_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prmwait.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prmwait.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prmwait.h @@ -0,0 +1,380 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#if defined(_PRMWAIT_H) +#else +#define _PRMWAIT_H + +#include "prio.h" +#include "prtypes.h" +#include "prclist.h" + +PR_BEGIN_EXTERN_C + +/********************************************************************************/ +/********************************************************************************/ +/********************************************************************************/ +/****************************** WARNING ****************************/ +/********************************************************************************/ +/**************************** This is work in progress. *************************/ +/************************** Do not make any assumptions *************************/ +/************************** about the stability of this *************************/ +/************************** API or the underlying imple- ************************/ +/************************** mentation. ************************/ +/********************************************************************************/ +/********************************************************************************/ + +/* +** STRUCTURE: PRWaitGroup +** DESCRIPTION: +** The client may define several wait groups in order to semantically +** tie a collection of file descriptors for a single purpose. This allows +** easier dispatching of threads that returned with active file descriptors +** from the wait function. +*/ +typedef struct PRWaitGroup PRWaitGroup; + +/* +** ENUMERATION: PRMWStatus +** DESCRIPTION: +** This enumeration is used to indicate the completion status of +** a receive wait object. Generally stated, a positive value indicates +** that the operation is not yet complete. A zero value indicates +** success (similar to PR_SUCCESS) and any negative value is an +** indication of failure. The reason for the failure can be retrieved +** by calling PR_GetError(). +** +** PR_MW_PENDING The operation is still pending. None of the other +** fields of the object are currently valid. +** PR_MW_SUCCESS The operation is complete and it was successful. +** PR_MW_FAILURE The operation failed. The reason for the failure +** can be retrieved by calling PR_GetError(). +** PR_MW_TIMEOUT The amount of time allowed for by the object's +** 'timeout' field has expired w/o the operation +** otherwise coming to closure. +** PR_MW_INTERRUPT The operation was cancelled, either by the client +** calling PR_CancelWaitFileDesc() or destroying the +** entire wait group (PR_DestroyWaitGroup()). +*/ +typedef enum PRMWStatus +{ + PR_MW_PENDING = 1, + PR_MW_SUCCESS = 0, + PR_MW_FAILURE = -1, + PR_MW_TIMEOUT = -2, + PR_MW_INTERRUPT = -3 +} PRMWStatus; + +/* +** STRUCTURE: PRMemoryDescriptor +** DESCRIPTION: +** THis is a descriptor for an interval of memory. It contains a +** pointer to the first byte of that memory and the length (in +** bytes) of the interval. +*/ +typedef struct PRMemoryDescriptor +{ + void *start; /* pointer to first byte of memory */ + PRSize length; /* length (in bytes) of memory interval */ +} PRMemoryDescriptor; + +/* +** STRUCTURE: PRMWaitClientData +** DESCRIPTION: +** An opague stucture for which a client MAY give provide a concrete +** definition and associate with a receive descriptor. The NSPR runtime +** does not manage this field. It is completely up to the client. +*/ +typedef struct PRMWaitClientData PRMWaitClientData; + +/* +** STRUCTURE: PRRecvWait +** DESCRIPTION: +** A receive wait object contains the file descriptor that is subject +** to the wait and the amount of time (beginning epoch established +** when the object is presented to the runtime) the the channel should +** block before abandoning the process. +** +** The success of the wait operation will be noted in the object's +** 'outcome' field. The fields are not valid when the NSPR runtime +** is in possession of the object. +** +** The memory descriptor describes an interval of writable memory +** in the caller's address space where data from an initial read +** can be placed. The description may indicate a null interval. +*/ +typedef struct PRRecvWait +{ + PRCList internal; /* internal runtime linkages */ + + PRFileDesc *fd; /* file descriptor associated w/ object */ + PRMWStatus outcome; /* outcome of the current/last operation */ + PRIntervalTime timeout; /* time allowed for entire operation */ + + PRInt32 bytesRecv; /* number of bytes transferred into buffer */ + PRMemoryDescriptor buffer; /* where to store first segment of input data */ + PRMWaitClientData *client; /* pointer to arbitrary client defined data */ +} PRRecvWait; + +/* +** STRUCTURE: PRMWaitEnumerator +** DESCRIPTION: +** An enumeration object is used to store the state of an existing +** enumeration over a wait group. The opaque object must be allocated +** by the client and the reference presented on each call to the +** pseudo-stateless enumerator. The enumeration objects are sharable +** only in serial fashion. +*/ +typedef struct PRMWaitEnumerator PRMWaitEnumerator; + + +/* +** FUNCTION: PR_AddWaitFileDesc +** DESCRIPTION: +** This function will effectively add a file descriptor to the +** list of those waiting for network receive. The new descriptor +** will be semantically tied to the wait group specified. +** +** The ownership for the storage pointed to by 'desc' is temporarily +** passed over the the NSPR runtime. It will be handed back by the +** function PR_WaitRecvReady(). +** +** INPUTS +** group A reference to a PRWaitGroup or NULL. Wait groups are +** created by calling PR_CreateWaitGroup() and are used +** to semantically group various file descriptors by the +** client's application. +** desc A reference to a valid PRRecvWait. The object of the +** reference must be preserved and not be modified +** until its ownership is returned to the client. +** RETURN +** PRStatus An indication of success. If equal to PR_FAILUE details +** of the failure are avaiable via PR_GetError(). +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** Invalid 'group' identifier or duplicate 'desc' object. +** PR_OUT_OF_MEMORY_ERROR +** Insuffient memory for internal data structures. +** PR_INVALID_STATE_ERROR +** The group is being destroyed. +*/ +NSPR_API(PRStatus) PR_AddWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc); + +/* +** FUNCTION: PR_WaitRecvReady +** DESCRIPTION: +** PR_WaitRecvReady will block the calling thread until one of the +** file descriptors that have been added via PR_AddWaitFileDesc is +** available for input I/O. +** INPUT +** group A pointer to a valid PRWaitGroup or NULL (the null +** group. The function will block the caller until a +** channel from the wait group becomes ready for receive +** or there is some sort of error. +** RETURN +** PRReciveWait +** When the caller is resumed it is either returned a +** valid pointer to a previously added receive wait or +** a NULL. If the latter, the function has terminated +** for a reason that can be determined by calling +** PR_GetError(). +** If a valid pointer is returned, the reference is to the +** file descriptor contained in the receive wait object. +** The outcome of the wait operation may still fail, and +** if it has, that fact will be noted in the object's +** outcome field. Details can be retrieved from PR_GetError(). +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The 'group' is not known by the runtime. +** PR_PENDING_INTERRUPT_ERROR + The thread was interrupted. +** PR_INVALID_STATE_ERROR +** The group is being destroyed. +*/ +NSPR_API(PRRecvWait*) PR_WaitRecvReady(PRWaitGroup *group); + +/* +** FUNCTION: PR_CancelWaitFileDesc +** DESCRIPTION: +** PR_CancelWaitFileDesc is provided as a means for cancelling operations +** on objects previously submitted by use of PR_AddWaitFileDesc(). If +** the runtime knows of the object, it will be marked as having failed +** because it was interrupted (similar to PR_Interrupt()). The first +** available thread waiting on the group will be made to return the +** PRRecvWait object with the outcome noted. +** +** INPUTS +** group The wait group under which the wait receive object was +** added. +** desc A pointer to the wait receive object that is to be +** cancelled. +** RETURN +** PRStatus If the wait receive object was located and associated +** with the specified wait group, the status returned will +** be PR_SUCCESS. There is still a race condition that would +** permit the offected object to complete normally, but it +** is assured that it will complete in the near future. +** If the receive object or wait group are invalid, the +** function will return with a status of PR_FAILURE. +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The 'group' argument is not recognized as a valid group. +** PR_COLLECTION_EMPTY_ERROR +** There are no more receive wait objects in the group's +** collection. +** PR_INVALID_STATE_ERROR +** The group is being destroyed. +*/ +NSPR_API(PRStatus) PR_CancelWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc); + +/* +** FUNCTION: PR_CancelWaitGroup +** DESCRIPTION: +** PR_CancelWaitGroup is provided as a means for cancelling operations +** on objects previously submitted by use of PR_AddWaitFileDesc(). Each +** successive call will return a pointer to a PRRecvWait object that +** was previously registered via PR_AddWaitFileDesc(). If no wait +** objects are associated with the wait group, a NULL will be returned. +** This function should be called in a loop until a NULL is returned +** to reclaim all the wait objects prior to calling PR_DestroyWaitGroup(). +** +** INPUTS +** group The wait group under which the wait receive object was +** added. +** RETURN +** PRRecvWait* If the wait group is valid and at least one receive wait +** object is present in the group, that object will be +** marked as PR_MW_INTERRUPT'd and removed from the group's +** queues. Otherwise a NULL will be returned and the reason +** for the NULL may be retrieved by calling PR_GetError(). +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** PR_GROUP_EMPTY_ERROR +*/ +NSPR_API(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group); + +/* +** FUNCTION: PR_CreateWaitGroup +** DESCRIPTION: +** A wait group is an opaque object that a client may create in order +** to semantically group various wait requests. Each wait group is +** unique, including the default wait group (NULL). A wait request +** that was added under a wait group will only be serviced by a caller +** that specified the same wait group. +** +** INPUT +** size The size of the hash table to be used to contain the +** receive wait objects. This is just the initial size. +** It will grow as it needs to, but to avoid that hassle +** one can suggest a suitable size initially. It should +** be ~30% larger than the maximum number of receive wait +** objects expected. +** RETURN +** PRWaitGroup If successful, the function will return a pointer to an +** object that was allocated by and owned by the runtime. +** The reference remains valid until it is explicitly destroyed +** by calling PR_DestroyWaitGroup(). +** +** ERRORS +** PR_OUT_OF_MEMORY_ERROR +*/ +NSPR_API(PRWaitGroup*) PR_CreateWaitGroup(PRInt32 size); + +/* +** FUNCTION: PR_DestroyWaitGroup +** DESCRIPTION: +** Undo the effects of PR_CreateWaitGroup(). Any receive wait operations +** on the group will be treated as if the each had been the target of a +** PR_CancelWaitFileDesc(). +** +** INPUT +** group Reference to a wait group previously allocated using +** PR_CreateWaitGroup(). +** RETURN +** PRStatus Will be PR_SUCCESS if the wait group was valid and there +** are no receive wait objects in that group. Otherwise +** will indicate PR_FAILURE. +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The 'group' argument does not reference a known object. +** PR_INVALID_STATE_ERROR +** The group still contains receive wait objects. +*/ +NSPR_API(PRStatus) PR_DestroyWaitGroup(PRWaitGroup *group); + +/* +** FUNCTION: PR_CreateMWaitEnumerator +** DESCRIPTION: +** The PR_CreateMWaitEnumerator() function returns a reference to an +** opaque PRMWaitEnumerator object. The enumerator object is required +** as an argument for each successive call in the stateless enumeration +** of the indicated wait group. +** +** group The wait group that the enumeration is intended to +** process. It may be be the default wait group (NULL). +** RETURN +** PRMWaitEnumerator* group +** A reference to an object that will be used to store +** intermediate state of enumerations. +** ERRORS +** Errors are indicated by the function returning a NULL. +** PR_INVALID_ARGUMENT_ERROR +** The 'group' argument does not reference a known object. +** PR_OUT_OF_MEMORY_ERROR +*/ +NSPR_API(PRMWaitEnumerator*) PR_CreateMWaitEnumerator(PRWaitGroup *group); + +/* +** FUNCTION: PR_DestroyMWaitEnumerator +** DESCRIPTION: +** Destroys the object created by PR_CreateMWaitEnumerator(). The reference +** used as an argument becomes invalid. +** +** INPUT +** PRMWaitEnumerator* enumerator +** The PRMWaitEnumerator object to destroy. +** RETURN +** PRStatus +** PR_SUCCESS if successful, PR_FAILURE otherwise. +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The enumerator is invalid. +*/ +NSPR_API(PRStatus) PR_DestroyMWaitEnumerator(PRMWaitEnumerator* enumerator); + +/* +** FUNCTION: PR_EnumerateWaitGroup +** DESCRIPTION: +** PR_EnumerateWaitGroup is a thread safe enumerator over a wait group. +** Each call to the enumerator must present a valid PRMWaitEnumerator +** rererence and a pointer to the "previous" element returned from the +** enumeration process or a NULL. +** +** An enumeration is started by passing a NULL as the "previous" value. +** Subsequent calls to the enumerator must pass in the result of the +** previous call. The enumeration end is signaled by the runtime returning +** a NULL as the result. +** +** Modifications to the content of the wait group are allowed during +** an enumeration. The effect is that the enumeration may have to be +** "reset" and that may result in duplicates being returned from the +** enumeration. +** +** An enumeration may be abandoned at any time. The runtime is not +** keeping any state, so there are no issues in that regard. +*/ +NSPR_API(PRRecvWait*) PR_EnumerateWaitGroup( + PRMWaitEnumerator *enumerator, const PRRecvWait *previous); + +PR_END_EXTERN_C + +#endif /* defined(_PRMWAIT_H) */ + +/* prmwait.h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prnetdb.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prnetdb.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prnetdb.h @@ -0,0 +1,467 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prnetdb_h___ +#define prnetdb_h___ + +#include "prtypes.h" +#include "prio.h" + +PR_BEGIN_EXTERN_C + + +/* + ********************************************************************* + * Translate an Internet address to/from a character string + ********************************************************************* + */ +NSPR_API(PRStatus) PR_StringToNetAddr( + const char *string, PRNetAddr *addr); + +NSPR_API(PRStatus) PR_NetAddrToString( + const PRNetAddr *addr, char *string, PRUint32 size); + +/* +** Structures returned by network data base library. All addresses are +** supplied in host order, and returned in network order (suitable for +** use in system calls). +*/ +/* +** Beware that WINSOCK.H defines h_addrtype and h_length as short. +** Client code does direct struct copies of hostent to PRHostEnt and +** hence the ifdef. +*/ +typedef struct PRHostEnt { + char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ +#ifdef WIN32 + PRInt16 h_addrtype; /* host address type */ + PRInt16 h_length; /* length of address */ +#else + PRInt32 h_addrtype; /* host address type */ + PRInt32 h_length; /* length of address */ +#endif + char **h_addr_list; /* list of addresses from name server */ +} PRHostEnt; + +/* A safe size to use that will mostly work... */ +#if (defined(AIX) && defined(_THREAD_SAFE)) || defined(OSF1) +#define PR_NETDB_BUF_SIZE sizeof(struct protoent_data) +#else +#define PR_NETDB_BUF_SIZE 1024 +#endif + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetHostByName() +** Lookup a host by name. +** +** INPUTS: +** char *hostname Character string defining the host name of interest +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *hostentry +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ +NSPR_API(PRStatus) PR_GetHostByName( + const char *hostname, char *buf, PRIntn bufsize, PRHostEnt *hostentry); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetIPNodeByName() +** Lookup a host by name. Equivalent to getipnodebyname(AI_DEFAULT) +** of RFC 2553. +** +** INPUTS: +** char *hostname Character string defining the host name of interest +** PRUint16 af Address family (either PR_AF_INET or PR_AF_INET6) +** PRIntn flags Specifies the types of addresses that are searched +** for and the types of addresses that are returned. +** The only supported flag is PR_AI_DEFAULT. +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *hostentry +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ + + +#define PR_AI_ALL 0x08 +#define PR_AI_V4MAPPED 0x10 +#define PR_AI_ADDRCONFIG 0x20 +#define PR_AI_NOCANONNAME 0x8000 +#define PR_AI_DEFAULT (PR_AI_V4MAPPED | PR_AI_ADDRCONFIG) + +NSPR_API(PRStatus) PR_GetIPNodeByName( + const char *hostname, + PRUint16 af, + PRIntn flags, + char *buf, + PRIntn bufsize, + PRHostEnt *hostentry); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetHostByAddr() +** Lookup a host entry by its network address. +** +** INPUTS: +** char *hostaddr IP address of host in question +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *hostentry +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ +NSPR_API(PRStatus) PR_GetHostByAddr( + const PRNetAddr *hostaddr, char *buf, PRIntn bufsize, PRHostEnt *hostentry); + +/*********************************************************************** +** FUNCTION: PR_EnumerateHostEnt() +** DESCRIPTION: +** A stateless enumerator over a PRHostEnt structure acquired from +** PR_GetHostByName() PR_GetHostByAddr() to evaluate the possible +** network addresses. +** +** INPUTS: +** PRIntn enumIndex Index of the enumeration. The enumeration starts +** and ends with a value of zero. +** +** PRHostEnt *hostEnt A pointer to a host entry struct that was +** previously returned by PR_GetHostByName() or +** PR_GetHostByAddr(). +** +** PRUint16 port The port number to be assigned as part of the +** PRNetAddr. +** +** OUTPUTS: +** PRNetAddr *address A pointer to an address structure that will be +** filled in by the call to the enumeration if the +** result of the call is greater than zero. +** +** RETURN: +** PRIntn The value that should be used for the next call +** of the enumerator ('enumIndex'). The enumeration +** is ended if this value is returned zero. +** If a value of -1 is returned, the enumeration +** has failed. The reason for the failure can be +** retrieved by calling PR_GetError(). +***********************************************************************/ +NSPR_API(PRIntn) PR_EnumerateHostEnt( + PRIntn enumIndex, const PRHostEnt *hostEnt, PRUint16 port, PRNetAddr *address); + +/*********************************************************************** +** FUNCTION: PR_InitializeNetAddr(), +** DESCRIPTION: +** Initialize the fields of a PRNetAddr, assigning well known values as +** appropriate. +** +** INPUTS +** PRNetAddrValue val The value to be assigned to the IP Address portion +** of the network address. This can only specify the +** special well known values that are equivalent to +** INADDR_ANY and INADDR_LOOPBACK. +** +** PRUint16 port The port number to be assigned in the structure. +** +** OUTPUTS: +** PRNetAddr *addr The address to be manipulated. +** +** RETURN: +** PRStatus To indicate success or failure. If the latter, the +** reason for the failure can be retrieved by calling +** PR_GetError(); +***********************************************************************/ +typedef enum PRNetAddrValue +{ + PR_IpAddrNull, /* do NOT overwrite the IP address */ + PR_IpAddrAny, /* assign logical INADDR_ANY to IP address */ + PR_IpAddrLoopback, /* assign logical INADDR_LOOPBACK */ + PR_IpAddrV4Mapped /* IPv4 mapped address */ +} PRNetAddrValue; + +NSPR_API(PRStatus) PR_InitializeNetAddr( + PRNetAddrValue val, PRUint16 port, PRNetAddr *addr); + +/*********************************************************************** +** FUNCTION: PR_SetNetAddr(), +** DESCRIPTION: +** Set the fields of a PRNetAddr, assigning well known values as +** appropriate. This function is similar to PR_InitializeNetAddr +** but differs in that the address family is specified. +** +** INPUTS +** PRNetAddrValue val The value to be assigned to the IP Address portion +** of the network address. This can only specify the +** special well known values that are equivalent to +** INADDR_ANY and INADDR_LOOPBACK. +** +** PRUint16 af The address family (either PR_AF_INET or PR_AF_INET6) +** +** PRUint16 port The port number to be assigned in the structure. +** +** OUTPUTS: +** PRNetAddr *addr The address to be manipulated. +** +** RETURN: +** PRStatus To indicate success or failure. If the latter, the +** reason for the failure can be retrieved by calling +** PR_GetError(); +***********************************************************************/ +NSPR_API(PRStatus) PR_SetNetAddr( + PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_IsNetAddrType() +** Determine if the network address is of the specified type. +** +** INPUTS: +** const PRNetAddr *addr A network address. +** PRNetAddrValue The type of network address +** +** RETURN: +** PRBool PR_TRUE if the network address is of the +** specified type, else PR_FALSE. +***********************************************************************/ +NSPR_API(PRBool) PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_ConvertIPv4AddrToIPv6() +** Convert an IPv4 addr to an (IPv4-mapped) IPv6 addr +** +** INPUTS: +** PRUint32 v4addr IPv4 address +** +** OUTPUTS: +** PRIPv6Addr *v6addr The converted IPv6 address +** +** RETURN: +** void +** +***********************************************************************/ +NSPR_API(void) PR_ConvertIPv4AddrToIPv6(PRUint32 v4addr, PRIPv6Addr *v6addr); + +/*********************************************************************** +** MACRO: +** DESCRIPTION: PR_NetAddrFamily() +** Get the 'family' field of a PRNetAddr union. +** +** INPUTS: +** const PRNetAddr *addr A network address. +** +** RETURN: +** PRUint16 The 'family' field of 'addr'. +***********************************************************************/ +#define PR_NetAddrFamily(addr) ((addr)->raw.family) + +/*********************************************************************** +** MACRO: +** DESCRIPTION: PR_NetAddrInetPort() +** Get the 'port' field of a PRNetAddr union. +** +** INPUTS: +** const PRNetAddr *addr A network address. +** +** RETURN: +** PRUint16 The 'port' field of 'addr'. +***********************************************************************/ +#define PR_NetAddrInetPort(addr) \ + ((addr)->raw.family == PR_AF_INET6 ? (addr)->ipv6.port : (addr)->inet.port) + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetProtoByName() +** Lookup a protocol entry based on protocol's name +** +** INPUTS: +** char *protocolname Character string of the protocol's name. +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *PRProtoEnt +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ + +typedef struct PRProtoEnt { + char *p_name; /* official protocol name */ + char **p_aliases; /* alias list */ +#ifdef WIN32 + PRInt16 p_num; /* protocol # */ +#else + PRInt32 p_num; /* protocol # */ +#endif +} PRProtoEnt; + +NSPR_API(PRStatus) PR_GetProtoByName( + const char* protocolname, char* buffer, PRInt32 bufsize, PRProtoEnt* result); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetProtoByNumber() +** Lookup a protocol entry based on protocol's number +** +** INPUTS: +** PRInt32 protocolnumber +** Number assigned to the protocol. +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *PRProtoEnt +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ +NSPR_API(PRStatus) PR_GetProtoByNumber( + PRInt32 protocolnumber, char* buffer, PRInt32 bufsize, PRProtoEnt* result); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetAddrInfoByName() +** Look up a host by name. Equivalent to getaddrinfo(host, NULL, ...) of +** RFC 3493. +** +** INPUTS: +** char *hostname Character string defining the host name of interest +** PRUint16 af May be PR_AF_UNSPEC or PR_AF_INET. +** PRIntn flags May be either PR_AI_ADDRCONFIG or +** PR_AI_ADDRCONFIG | PR_AI_NOCANONNAME. Include +** PR_AI_NOCANONNAME to suppress the determination of +** the canonical name corresponding to hostname. +** RETURN: +** PRAddrInfo* Handle to a data structure containing the results +** of the host lookup. Use PR_EnumerateAddrInfo to +** inspect the PRNetAddr values stored in this object. +** When no longer needed, this handle must be destroyed +** with a call to PR_FreeAddrInfo. If a lookup error +** occurs, then NULL will be returned. +***********************************************************************/ +typedef struct PRAddrInfo PRAddrInfo; + +NSPR_API(PRAddrInfo*) PR_GetAddrInfoByName( + const char *hostname, PRUint16 af, PRIntn flags); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_FreeAddrInfo() +** Destroy the PRAddrInfo handle allocated by PR_GetAddrInfoByName(). +** +** INPUTS: +** PRAddrInfo *addrInfo +** The handle resulting from a successful call to +** PR_GetAddrInfoByName(). +** RETURN: +** void +***********************************************************************/ +NSPR_API(void) PR_FreeAddrInfo(PRAddrInfo *addrInfo); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_EnumerateAddrInfo() +** A stateless enumerator over a PRAddrInfo handle acquired from +** PR_GetAddrInfoByName() to inspect the possible network addresses. +** +** INPUTS: +** void *enumPtr Index pointer of the enumeration. The enumeration +** starts and ends with a value of NULL. +** const PRAddrInfo *addrInfo +** The PRAddrInfo handle returned by a successful +** call to PR_GetAddrInfoByName(). +** PRUint16 port The port number to be assigned as part of the +** PRNetAddr. +** OUTPUTS: +** PRNetAddr *result A pointer to an address structure that will be +** filled in by the call to the enumeration if the +** result of the call is not NULL. +** RETURN: +** void* The value that should be used for the next call +** of the enumerator ('enumPtr'). The enumeration +** is ended if this value is NULL. +***********************************************************************/ +NSPR_API(void *) PR_EnumerateAddrInfo( + void *enumPtr, const PRAddrInfo *addrInfo, PRUint16 port, PRNetAddr *result); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetCanonNameFromAddrInfo() +** Extracts the canonical name of the hostname passed to +** PR_GetAddrInfoByName(). +** +** INPUTS: +** const PRAddrInfo *addrInfo +** The PRAddrInfo handle returned by a successful +** call to PR_GetAddrInfoByName(). +** RETURN: +** const char * A const pointer to the canonical hostname stored +** in the given PRAddrInfo handle. This pointer is +** invalidated once the PRAddrInfo handle is destroyed +** by a call to PR_FreeAddrInfo(). +***********************************************************************/ +NSPR_API(const char *) PR_GetCanonNameFromAddrInfo( + const PRAddrInfo *addrInfo); + +/*********************************************************************** +** FUNCTIONS: PR_ntohs, PR_ntohl, PR_ntohll, PR_htons, PR_htonl, PR_htonll +** +** DESCRIPTION: API entries for the common byte ordering routines. +** +** PR_ntohs 16 bit conversion from network to host +** PR_ntohl 32 bit conversion from network to host +** PR_ntohll 64 bit conversion from network to host +** PR_htons 16 bit conversion from host to network +** PR_htonl 32 bit conversion from host to network +** PR_ntonll 64 bit conversion from host to network +** +***********************************************************************/ +NSPR_API(PRUint16) PR_ntohs(PRUint16); +NSPR_API(PRUint32) PR_ntohl(PRUint32); +NSPR_API(PRUint64) PR_ntohll(PRUint64); +NSPR_API(PRUint16) PR_htons(PRUint16); +NSPR_API(PRUint32) PR_htonl(PRUint32); +NSPR_API(PRUint64) PR_htonll(PRUint64); + +PR_END_EXTERN_C + +#endif /* prnetdb_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prolock.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prolock.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prolock.h @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prolock_h___ +#define prolock_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** A locking mechanism, built on the existing PRLock definition, +** is provided that will permit applications to define a Lock +** Hierarchy (or Lock Ordering) schema. An application designed +** using the Ordered Lock functions will terminate with a +** diagnostic message when a lock inversion condition is +** detected. +** +** The lock ordering detection is compile-time enabled only. In +** optimized builds of NSPR, the Ordered Lock functions map +** directly to PRLock functions, providing no lock order +** detection. +** +** The Ordered Lock Facility is compiled in when DEBUG is defined at +** compile-time. Ordered Lock can be forced on in optimized builds by +** defining FORCE_NSPR_ORDERED_LOCK at compile-time. Both the +** application using Ordered Lock and NSPR must be compiled with the +** facility enabled to achieve the desired results. +** +** Application designers should use the macro interfaces to the Ordered +** Lock facility to ensure that it is compiled out in optimized builds. +** +** Application designers are responsible for defining their own +** lock hierarchy. +** +** Ordered Lock is thread-safe and SMP safe. +** +** See Also: prlock.h +** +** /lth. 10-Jun-1998. +** +*/ + +/* +** Opaque type for ordered lock. +** ... Don't even think of looking in here. +** +*/ + +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +typedef void * PROrderedLock; +#else +/* +** Map PROrderedLock and methods onto PRLock when ordered locking +** is not compiled in. +** +*/ +#include "prlock.h" + +typedef PRLock PROrderedLock; +#endif + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_CreateOrderedLock() -- Create an Ordered Lock +** +** DESCRIPTION: PR_CreateOrderedLock() creates an ordered lock. +** +** INPUTS: +** order: user defined order of this lock. +** name: name of the lock. For debugging purposes. +** +** OUTPUTS: returned +** +** RETURNS: PR_OrderedLock pointer +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_CREATE_ORDERED_LOCK(order,name)\ + PR_CreateOrderedLock((order),(name)) +#else +#define PR_CREATE_ORDERED_LOCK(order) PR_NewLock() +#endif + +NSPR_API(PROrderedLock *) + PR_CreateOrderedLock( + PRInt32 order, + const char *name +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DestroyOrderedLock() -- Destroy an Ordered Lock +** +** DESCRIPTION: PR_DestroyOrderedLock() destroys the ordered lock +** referenced by lock. +** +** INPUTS: lock: pointer to a PROrderedLock +** +** OUTPUTS: the lock is destroyed +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_DESTROY_ORDERED_LOCK(lock) PR_DestroyOrderedLock((lock)) +#else +#define PR_DESTROY_ORDERED_LOCK(lock) PR_DestroyLock((lock)) +#endif + +NSPR_API(void) + PR_DestroyOrderedLock( + PROrderedLock *lock +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_LockOrderedLock() -- Lock an ordered lock +** +** DESCRIPTION: PR_LockOrderedLock() locks the ordered lock +** referenced by lock. If the order of lock is less than or equal +** to the order of the highest lock held by the locking thread, +** the function asserts. +** +** INPUTS: lock: a pointer to a PROrderedLock +** +** OUTPUTS: The lock is held or the function asserts. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_LOCK_ORDERED_LOCK(lock) PR_LockOrderedLock((lock)) +#else +#define PR_LOCK_ORDERED_LOCK(lock) PR_Lock((lock)) +#endif + +NSPR_API(void) + PR_LockOrderedLock( + PROrderedLock *lock +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_UnlockOrderedLock() -- unlock and Ordered Lock +** +** DESCRIPTION: PR_UnlockOrderedLock() unlocks the lock referenced +** by lock. +** +** INPUTS: lock: a pointer to a PROrderedLock +** +** OUTPUTS: the lock is unlocked +** +** RETURNS: +** PR_SUCCESS +** PR_FAILURE +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_UNLOCK_ORDERED_LOCK(lock) PR_UnlockOrderedLock((lock)) +#else +#define PR_UNLOCK_ORDERED_LOCK(lock) PR_Unlock((lock)) +#endif + +NSPR_API(PRStatus) + PR_UnlockOrderedLock( + PROrderedLock *lock +); + +PR_END_EXTERN_C + +#endif /* prolock_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prpdce.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prpdce.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prpdce.h @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* + * File: prpdce.h + * Description: This file is the API defined to allow for DCE (aka POSIX) + * thread emulation in an NSPR environment. It is not the + * intent that this be a fully supported API. + */ + +#if !defined(PRPDCE_H) +#define PRPDCE_H + +#include "prlock.h" +#include "prcvar.h" +#include "prtypes.h" +#include "prinrval.h" + +PR_BEGIN_EXTERN_C + +#define _PR_NAKED_CV_LOCK (PRLock*)0xdce1dce1 + +/* +** Test and acquire a lock. +** +** If the lock is acquired by the calling thread, the +** return value will be PR_SUCCESS. If the lock is +** already held, by another thread or this thread, the +** result will be PR_FAILURE. +*/ +NSPR_API(PRStatus) PRP_TryLock(PRLock *lock); + +/* +** Create a naked condition variable +** +** A "naked" condition variable is one that is not created bound +** to a lock. The CV created with this function is the only type +** that may be used in the subsequent "naked" condition variable +** operations (see PRP_NakedWait, PRP_NakedNotify, PRP_NakedBroadcast); +*/ +NSPR_API(PRCondVar*) PRP_NewNakedCondVar(void); + +/* +** Destroy a naked condition variable +** +** Destroy the condition variable created by PR_NewNakedCondVar. +*/ +NSPR_API(void) PRP_DestroyNakedCondVar(PRCondVar *cvar); + +/* +** Wait on a condition +** +** Wait on the condition variable 'cvar'. It is asserted that +** the lock protecting the condition 'lock' is held by the +** calling thread. If more time expires than that declared in +** 'timeout' the condition will be notified. Waits can be +** interrupted by another thread. +** +** NB: The CV ('cvar') must be one created using PR_NewNakedCondVar. +*/ +NSPR_API(PRStatus) PRP_NakedWait( + PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout); + +/* +** Notify a thread waiting on a condition +** +** Notify the condition specified 'cvar'. +** +** NB: The CV ('cvar') must be one created using PR_NewNakedCondVar. +*/ +NSPR_API(PRStatus) PRP_NakedNotify(PRCondVar *cvar); + +/* +** Notify all threads waiting on a condition +** +** Notify the condition specified 'cvar'. +** +** NB: The CV ('cvar') must be one created using PR_NewNakedCondVar. +*/ +NSPR_API(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar); + +PR_END_EXTERN_C + +#endif /* PRPDCE_H */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prprf.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prprf.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prprf.h @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prprf_h___ +#define prprf_h___ + +/* +** API for PR printf like routines. Supports the following formats +** %d - decimal +** %u - unsigned decimal +** %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 - string +** %c - character +** %p - pointer (deals with machine dependent pointer size) +** %f - float +** %g - float +*/ +#include "prtypes.h" +#include "prio.h" +#include +#include + +PR_BEGIN_EXTERN_C + +/* +** 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 (PRUint32)-1 if an error occurs. +*/ +NSPR_API(PRUint32) PR_snprintf(char *out, PRUint32 outlen, const char *fmt, ...); + +/* +** sprintf into a PR_MALLOC'd buffer. Return a pointer to the malloc'd +** buffer on success, NULL on failure. Call "PR_smprintf_free" to release +** the memory returned. +*/ +NSPR_API(char*) PR_smprintf(const char *fmt, ...); + +/* +** Free the memory allocated, for the caller, by PR_smprintf +*/ +NSPR_API(void) PR_smprintf_free(char *mem); + +/* +** "append" sprintf into a PR_MALLOC'd buffer. "last" is the last value of +** the PR_MALLOC'd buffer. sprintf will append data to the end of last, +** growing it as necessary using realloc. If last is NULL, PR_sprintf_append +** will allocate the initial string. The return value is the new value of +** last for subsequent calls, or NULL if there is a malloc failure. +*/ +NSPR_API(char*) PR_sprintf_append(char *last, const char *fmt, ...); + +/* +** sprintf into a function. The function "f" is called with a string to +** place into the output. "arg" is an opaque pointer used by the stuff +** function to hold any state needed to do the storage of the output +** data. The return value is a count of the number of characters fed to +** the stuff function, or (PRUint32)-1 if an error occurs. +*/ +typedef PRIntn (*PRStuffFunc)(void *arg, const char *s, PRUint32 slen); + +NSPR_API(PRUint32) PR_sxprintf(PRStuffFunc f, void *arg, const char *fmt, ...); + +/* +** fprintf to a PRFileDesc +*/ +NSPR_API(PRUint32) PR_fprintf(struct PRFileDesc* fd, const char *fmt, ...); + +/* +** va_list forms of the above. +*/ +NSPR_API(PRUint32) PR_vsnprintf(char *out, PRUint32 outlen, const char *fmt, va_list ap); +NSPR_API(char*) PR_vsmprintf(const char *fmt, va_list ap); +NSPR_API(char*) PR_vsprintf_append(char *last, const char *fmt, va_list ap); +NSPR_API(PRUint32) PR_vsxprintf(PRStuffFunc f, void *arg, const char *fmt, va_list ap); +NSPR_API(PRUint32) PR_vfprintf(struct PRFileDesc* fd, const char *fmt, va_list ap); + +/* +*************************************************************************** +** FUNCTION: PR_sscanf +** DESCRIPTION: +** PR_sscanf() scans the input character string, performs data +** conversions, and stores the converted values in the data objects +** pointed to by its arguments according to the format control +** string. +** +** PR_sscanf() behaves the same way as the sscanf() function in the +** Standard C Library (stdio.h), with the following exceptions: +** - PR_sscanf() handles the NSPR integer and floating point types, +** such as PRInt16, PRInt32, PRInt64, and PRFloat64, whereas +** sscanf() handles the standard C types like short, int, long, +** and double. +** - PR_sscanf() has no multibyte character support, while sscanf() +** does. +** INPUTS: +** const char *buf +** a character string holding the input to scan +** const char *fmt +** the format control string for the conversions +** ... +** variable number of arguments, each of them is a pointer to +** a data object in which the converted value will be stored +** OUTPUTS: none +** RETURNS: PRInt32 +** The number of values converted and stored. +** RESTRICTIONS: +** Multibyte characters in 'buf' or 'fmt' are not allowed. +*************************************************************************** +*/ + +NSPR_API(PRInt32) PR_sscanf(const char *buf, const char *fmt, ...); + +PR_END_EXTERN_C + +#endif /* prprf_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prproces.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prproces.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prproces.h @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prproces_h___ +#define prproces_h___ + +#include "prtypes.h" +#include "prio.h" + +PR_BEGIN_EXTERN_C + +/************************************************************************/ +/*****************************PROCESS OPERATIONS*************************/ +/************************************************************************/ + +typedef struct PRProcess PRProcess; +typedef struct PRProcessAttr PRProcessAttr; + +NSPR_API(PRProcessAttr *) PR_NewProcessAttr(void); + +NSPR_API(void) PR_ResetProcessAttr(PRProcessAttr *attr); + +NSPR_API(void) PR_DestroyProcessAttr(PRProcessAttr *attr); + +NSPR_API(void) PR_ProcessAttrSetStdioRedirect( + PRProcessAttr *attr, + PRSpecialFD stdioFd, + PRFileDesc *redirectFd +); + +/* + * OBSOLETE -- use PR_ProcessAttrSetStdioRedirect instead. + */ +NSPR_API(void) PR_SetStdioRedirect( + PRProcessAttr *attr, + PRSpecialFD stdioFd, + PRFileDesc *redirectFd +); + +NSPR_API(PRStatus) PR_ProcessAttrSetCurrentDirectory( + PRProcessAttr *attr, + const char *dir +); + +NSPR_API(PRStatus) PR_ProcessAttrSetInheritableFD( + PRProcessAttr *attr, + PRFileDesc *fd, + const char *name +); + +/* +** Create a new process +** +** Create a new process executing the file specified as 'path' and with +** the supplied arguments and environment. +** +** This function may fail because of illegal access (permissions), +** invalid arguments or insufficient resources. +** +** A process may be created such that the creator can later synchronize its +** termination using PR_WaitProcess(). +*/ + +NSPR_API(PRProcess*) PR_CreateProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr); + +NSPR_API(PRStatus) PR_CreateProcessDetached( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr); + +NSPR_API(PRStatus) PR_DetachProcess(PRProcess *process); + +NSPR_API(PRStatus) PR_WaitProcess(PRProcess *process, PRInt32 *exitCode); + +NSPR_API(PRStatus) PR_KillProcess(PRProcess *process); + +PR_END_EXTERN_C + +#endif /* prproces_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prrng.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prrng.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prrng.h @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + + +/* +** prrng.h -- NSPR Random Number Generator +** +** +** lth. 29-Oct-1999. +*/ + +#ifndef prrng_h___ +#define prrng_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** PR_GetRandomNoise() -- Get random noise from the host platform +** +** Description: +** PR_GetRandomNoise() provides, depending on platform, a random value. +** The length of the random value is dependent on platform and the +** platform's ability to provide a random value at that moment. +** +** The intent of PR_GetRandomNoise() is to provide a "seed" value for a +** another random number generator that may be suitable for +** cryptographic operations. This implies that the random value +** provided may not be, by itself, cryptographically secure. The value +** generated by PR_GetRandomNoise() is at best, extremely difficult to +** predict and is as non-deterministic as the underlying platfrom can +** provide. +** +** Inputs: +** buf -- pointer to a caller supplied buffer to contain the +** generated random number. buf must be at least as large as +** is specified in the 'size' argument. +** +** size -- the requested size of the generated random number +** +** Outputs: +** a random number provided in 'buf'. +** +** Returns: +** PRSize value equal to the size of the random number actually +** generated, or zero. The generated size may be less than the size +** requested. A return value of zero means that PR_GetRandomNoise() is +** not implemented on this platform, or there is no available noise +** available to be returned at the time of the call. +** +** Restrictions: +** Calls to PR_GetRandomNoise() may use a lot of CPU on some platforms. +** Some platforms may block for up to a few seconds while they +** accumulate some noise. Busy machines generate lots of noise, but +** care is advised when using PR_GetRandomNoise() frequently in your +** application. +** +** History: +** Parts of the model dependent implementation for PR_GetRandomNoise() +** were taken in whole or part from code previously in Netscape's NSS +** component. +** +*/ +NSPR_API(PRSize) PR_GetRandomNoise( + void *buf, + PRSize size +); + +PR_END_EXTERN_C + +#endif /* prrng_h___ */ +/* end prrng.h */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prrwlock.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prrwlock.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prrwlock.h @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: prrwlock.h +** Description: API to basic reader-writer lock functions of NSPR. +** +**/ + +#ifndef prrwlock_h___ +#define prrwlock_h___ + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* + * PRRWLock -- + * + * The reader writer lock, PRRWLock, is an opaque object to the clients + * of NSPR. All routines operate on a pointer to this opaque entity. + */ + + +typedef struct PRRWLock PRRWLock; + +#define PR_RWLOCK_RANK_NONE 0 + + +/*********************************************************************** +** FUNCTION: PR_NewRWLock +** DESCRIPTION: +** Returns a pointer to a newly created reader-writer lock object. +** INPUTS: Lock rank +** Lock name +** OUTPUTS: void +** RETURN: PRRWLock* +** If the lock cannot be created because of resource constraints, NULL +** is returned. +** +***********************************************************************/ +NSPR_API(PRRWLock*) PR_NewRWLock(PRUint32 lock_rank, const char *lock_name); + +/*********************************************************************** +** FUNCTION: PR_DestroyRWLock +** DESCRIPTION: +** Destroys a given RW lock object. +** INPUTS: PRRWLock *lock - Lock to be freed. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_DestroyRWLock(PRRWLock *lock); + +/*********************************************************************** +** FUNCTION: PR_RWLock_Rlock +** DESCRIPTION: +** Apply a read lock (non-exclusive) on a RWLock +** INPUTS: PRRWLock *lock - Lock to be read-locked. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_RWLock_Rlock(PRRWLock *lock); + +/*********************************************************************** +** FUNCTION: PR_RWLock_Wlock +** DESCRIPTION: +** Apply a write lock (exclusive) on a RWLock +** INPUTS: PRRWLock *lock - Lock to write-locked. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_RWLock_Wlock(PRRWLock *lock); + +/*********************************************************************** +** FUNCTION: PR_RWLock_Unlock +** DESCRIPTION: +** Release a RW lock. Unlocking an unlocked lock has undefined results. +** INPUTS: PRRWLock *lock - Lock to unlocked. +** OUTPUTS: void +** RETURN: void +***********************************************************************/ +NSPR_API(void) PR_RWLock_Unlock(PRRWLock *lock); + +PR_END_EXTERN_C + +#endif /* prrwlock_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prshm.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prshm.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prshm.h @@ -0,0 +1,257 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** prshm.h -- NSPR Shared Memory +** +** NSPR Named Shared Memory API provides a cross-platform named +** shared-memory interface. NSPR Named Shared Memory is modeled on +** similar constructs in Unix and Windows operating systems. Shared +** memory allows multiple processes to access one or more common shared +** memory regions, using it as an inter-process communication channel. +** +** Notes on Platform Independence: +** NSPR Named Shared Memory is built on the native services offered +** by most platforms. The NSPR Named Shared Memory API tries to +** provide a least common denominator interface so that it works +** across all supported platforms. To ensure that it works everywhere, +** some platform considerations must be accomodated and the protocol +** for using NSPR Shared Memory API must be observed. +** +** Protocol: +** Multiple shared memories can be created using NSPR's Shared Memory +** feature. For each named shared memory, as defined by the name +** given in the PR_OpenSharedMemory() call, a protocol for using the +** shared memory API is required to ensure desired behavior. Failing +** to follow the protocol may yield unpredictable results. +** +** PR_OpenSharedMemory() will create the shared memory segment, if it +** does not already exist, or open a connection that the existing +** shared memory segment if it already exists. +** +** PR_AttachSharedMemory() should be called following +** PR_OpenSharedMemory() to map the memory segment to an address in +** the application's address space. +** +** PR_AttachSharedMemory() may be called to re-map a shared memory +** segment after detaching the same PRSharedMemory object. Be +** sure to detach it when done. +** +** PR_DetachSharedMemory() should be called to un-map the shared +** memory segment from the application's address space. +** +** PR_CloseSharedMemory() should be called when no further use of the +** PRSharedMemory object is required within a process. Following a +** call to PR_CloseSharedMemory() the PRSharedMemory object is +** invalid and cannot be reused. +** +** PR_DeleteSharedMemory() should be called before process +** termination. After calling PR_DeleteSharedMemory() any further use +** of the shared memory associated with the name may cause +** unpredictable results. +** +** Files: +** The name passed to PR_OpenSharedMemory() should be a valid filename +** for a unix platform. PR_OpenSharedMemory() creates file using the +** name passed in. Some platforms may mangle the name before creating +** the file and the shared memory. +** +** The unix implementation may use SysV IPC shared memory, Posix +** shared memory, or memory mapped files; the filename may used to +** define the namespace. On Windows, the name is significant, but +** there is no file associated with name. +** +** No assumptions about the persistence of data in the named file +** should be made. Depending on platform, the shared memory may be +** mapped onto system paging space and be discarded at process +** termination. +** +** All names provided to PR_OpenSharedMemory() should be valid +** filename syntax or name syntax for shared memory for the target +** platform. Referenced directories should have permissions +** appropriate for writing. +** +** Limits: +** Different platforms have limits on both the number and size of +** shared memory resources. The default system limits on some +** platforms may be smaller than your requirements. These limits may +** be adjusted on some platforms either via boot-time options or by +** setting the size of the system paging space to accomodate more +** and/or larger shared memory segment(s). +** +** Security: +** On unix platforms, depending on implementation, contents of the +** backing store for the shared memory can be exposed via the file +** system. Set permissions and or access controls at create and attach +** time to ensure you get the desired security. +** +** On windows platforms, no special security measures are provided. +** +** Example: +** The test case pr/tests/nameshm1.c provides an example of use as +** well as testing the operation of NSPR's Named Shared Memory. +** +** lth. 18-Aug-1999. +*/ + +#ifndef prshm_h___ +#define prshm_h___ + +#include "prtypes.h" +#include "prio.h" + +PR_BEGIN_EXTERN_C + +/* +** Declare opaque type PRSharedMemory. +*/ +typedef struct PRSharedMemory PRSharedMemory; + +/* +** FUNCTION: PR_OpenSharedMemory() +** +** DESCRIPTION: +** PR_OpenSharedMemory() creates a new shared-memory segment or +** associates a previously created memory segment with name. +** +** When parameter create is (PR_SHM_EXCL | PR_SHM_CREATE) and the +** shared memory already exists, the function returns NULL with the +** error set to PR_FILE_EXISTS_ERROR. +** +** When parameter create is PR_SHM_CREATE and the shared memory +** already exists, a handle to that memory segment is returned. If +** the segment does not exist, it is created and a pointer to the +** related PRSharedMemory structure is returned. +** +** When parameter create is 0, and the shared memory exists, a +** pointer to a PRSharedMemory is returned. If the shared memory does +** not exist, NULL is returned with the error set to +** PR_FILE_NOT_FOUND_ERROR. +** +** INPUTS: +** name -- the name the shared-memory segment is known as. +** size -- the size of the shared memory segment. +** flags -- Options for creating the shared memory +** mode -- Same as is passed to PR_Open() +** +** OUTPUTS: +** The shared memory is allocated. +** +** RETURNS: Pointer to opaque structure PRSharedMemory or NULL. +** NULL is returned on error. The reason for the error can be +** retrieved via PR_GetError() and PR_GetOSError(); +** +*/ +NSPR_API( PRSharedMemory * ) + PR_OpenSharedMemory( + const char *name, + PRSize size, + PRIntn flags, + PRIntn mode +); +/* Define values for PR_OpenShareMemory(...,create) */ +#define PR_SHM_CREATE 0x1 /* create if not exist */ +#define PR_SHM_EXCL 0x2 /* fail if already exists */ + +/* +** FUNCTION: PR_AttachSharedMemory() +** +** DESCRIPTION: +** PR_AttachSharedMemory() maps the shared-memory described by +** shm to the current process. +** +** INPUTS: +** shm -- The handle returned from PR_OpenSharedMemory(). +** flags -- options for mapping the shared memory. +** PR_SHM_READONLY causes the memory to be attached +** read-only. +** +** OUTPUTS: +** On success, the shared memory segment represented by shm is mapped +** into the process' address space. +** +** RETURNS: Address where shared memory is mapped, or NULL. +** NULL is returned on error. The reason for the error can be +** retrieved via PR_GetError() and PR_GetOSError(); +** +** +*/ +NSPR_API( void * ) + PR_AttachSharedMemory( + PRSharedMemory *shm, + PRIntn flags +); +/* Define values for PR_AttachSharedMemory(...,flags) */ +#define PR_SHM_READONLY 0x01 + +/* +** FUNCTION: PR_DetachSharedMemory() +** +** DESCRIPTION: +** PR_DetachSharedMemory() detaches the shared-memory described +** by shm. +** +** INPUTS: +** shm -- The handle returned from PR_OpenSharedMemory(). +** addr -- The address at which the memory was attached. +** +** OUTPUTS: +** The shared memory mapped to an address via a previous call to +** PR_AttachSharedMemory() is unmapped. +** +** RETURNS: PRStatus +** +*/ +NSPR_API( PRStatus ) + PR_DetachSharedMemory( + PRSharedMemory *shm, + void *addr +); + +/* +** FUNCTION: PR_CloseSharedMemory() +** +** DESCRIPTION: +** PR_CloseSharedMemory() closes the shared-memory described by +** shm. +** +** INPUTS: +** shm -- The handle returned from PR_OpenSharedMemory(). +** +** OUTPUTS: +** the shared memory represented by shm is closed +** +** RETURNS: PRStatus +** +*/ +NSPR_API( PRStatus ) + PR_CloseSharedMemory( + PRSharedMemory *shm +); + +/* +** FUNCTION: PR_DeleteSharedMemory() +** +** DESCRIPTION: +** The shared memory resource represented by name is released. +** +** INPUTS: +** name -- the name the shared-memory segment +** +** OUTPUTS: +** depending on platform, resources may be returned to the underlying +** operating system. +** +** RETURNS: PRStatus +** +*/ +NSPR_API( PRStatus ) + PR_DeleteSharedMemory( + const char *name +); + +PR_END_EXTERN_C + +#endif /* prshm_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prshma.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prshma.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prshma.h @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** prshma.h -- NSPR Anonymous Shared Memory +** +** NSPR provides an anonymous shared memory based on NSPR's PRFileMap +** type. The anonymous file-mapped shared memory provides an inheritable +** shared memory, as in: the child process inherits the shared memory. +** Compare the file-mapped anonymous shared memory to to a named shared +** memory described in prshm.h. The intent is to provide a shared +** memory that is accessable only by parent and child processes. ... +** It's a security thing. +** +** Depending on the underlying platform, the file-mapped shared memory +** may be backed by a file. ... surprise! ... On some platforms, no +** real file backs the shared memory. On platforms where the shared +** memory is backed by a file, the file's name in the filesystem is +** visible to other processes for only the duration of the creation of +** the file, hopefully a very short time. This restricts processess +** that do not inherit the shared memory from opening the file and +** reading or writing its contents. Further, when all processes +** using an anonymous shared memory terminate, the backing file is +** deleted. ... If you are not paranoid, you're not paying attention. +** +** The file-mapped shared memory requires a protocol for the parent +** process and child process to share the memory. NSPR provides two +** protocols. Use one or the other; don't mix and match. +** +** In the first protocol, the job of passing the inheritable shared +** memory is done via helper-functions with PR_CreateProcess(). In the +** second protocol, the parent process is responsible for creating the +** child process; the parent and child are mutually responsible for +** passing a FileMap string. NSPR provides helper functions for +** extracting data from the PRFileMap object. ... See the examples +** below. +** +** Both sides should adhere strictly to the protocol for proper +** operation. The pseudo-code below shows the use of a file-mapped +** shared memory by a parent and child processes. In the examples, the +** server creates the file-mapped shared memory, the client attaches to +** it. +** +** First protocol. +** Server: +** +** fm = PR_OpenAnonFileMap(dirName, size, FilemapProt); +** addr = PR_MemMap(fm); +** attr = PR_NewProcessAttr(); +** PR_ProcessAttrSetInheritableFileMap( attr, fm, shmname ); +** PR_CreateProcess(Client); +** PR_DestroyProcessAttr(attr); +** ... yadda ... +** PR_MemUnmap( addr ); +** PR_CloseFileMap(fm); +** +** +** Client: +** ... started by server via PR_CreateProcess() +** fm = PR_GetInheritedFileMap( shmname ); +** addr = PR_MemMap(fm); +** ... yadda ... +** PR_MemUnmap(addr); +** PR_CloseFileMap(fm); +** +** +** Second Protocol: +** Server: +** +** fm = PR_OpenAnonFileMap(dirName, size, FilemapProt); +** fmstring = PR_ExportFileMapAsString( fm ); +** addr = PR_MemMap(fm); +** ... application specific technique to pass fmstring to child +** ... yadda ... Server uses his own magic to create child +** PR_MemUnmap( addr ); +** PR_CloseFileMap(fm); +** +** +** Client: +** ... started by server via his own magic +** ... application specific technique to find fmstring from parent +** fm = PR_ImportFileMapFromString( fmstring ) +** addr = PR_MemMap(fm); +** ... yadda ... +** PR_MemUnmap(addr); +** PR_CloseFileMap(fm); +** +** +** lth. 2-Jul-1999. +** +** Note: The second protocol was requested by NelsonB (7/1999); this is +** to accomodate servers which already create their own child processes +** using platform native methods. +** +*/ + +#ifndef prshma_h___ +#define prshma_h___ + +#include "prtypes.h" +#include "prio.h" +#include "prproces.h" + +PR_BEGIN_EXTERN_C + +/* +** PR_OpenAnonFileMap() -- Creates an anonymous file-mapped shared memory +** +** Description: +** PR_OpenAnonFileMap() creates an anonymous shared memory. If the +** shared memory already exists, a handle is returned to that shared +** memory object. +** +** On Unix platforms, PR_OpenAnonFileMap() uses 'dirName' as a +** directory name, without the trailing '/', to contain the anonymous +** file. A filename is generated for the name. +** +** On Windows platforms, dirName is ignored. +** +** Inputs: +** dirName -- A directory name to contain the anonymous file. +** size -- The size of the shared memory +** prot -- How the shared memory is mapped. See prio.h +** +** Outputs: +** PRFileMap * +** +** Returns: +** Pointer to PRFileMap or NULL on error. +** +*/ +NSPR_API( PRFileMap *) +PR_OpenAnonFileMap( + const char *dirName, + PRSize size, + PRFileMapProtect prot +); + +/* +** PR_ProcessAttrSetInheritableFileMap() -- Prepare FileMap for export +** to my children processes via PR_CreateProcess() +** +** Description: +** PR_ProcessAttrSetInheritableFileMap() connects the PRFileMap to +** PRProcessAttr with shmname. A subsequent call to PR_CreateProcess() +** makes the PRFileMap importable by the child process. +** +** Inputs: +** attr -- PRProcessAttr, used to pass data to PR_CreateProcess() +** fm -- PRFileMap structure to be passed to the child process +** shmname -- The name for the PRFileMap; used by child. +** +** Outputs: +** PRFileMap * +** +** Returns: +** PRStatus +** +*/ +NSPR_API(PRStatus) +PR_ProcessAttrSetInheritableFileMap( + PRProcessAttr *attr, + PRFileMap *fm, + const char *shmname +); + +/* +** PR_GetInheritedFileMap() -- Import a PRFileMap previously exported +** by my parent process via PR_CreateProcess() +** +** Description: +** PR_GetInheritedFileMap() retrieves a PRFileMap object exported from +** its parent process via PR_CreateProcess(). +** +** Inputs: +** shmname -- The name provided to PR_ProcessAttrSetInheritableFileMap() +** +** Outputs: +** PRFileMap * +** +** Returns: +** PRFileMap pointer or NULL. +** +*/ +NSPR_API( PRFileMap *) +PR_GetInheritedFileMap( + const char *shmname +); + +/* +** PR_ExportFileMapAsString() -- Creates a string identifying a PRFileMap +** +** Description: +** Creates an identifier, as a string, from a PRFileMap object +** previously created with PR_OpenAnonFileMap(). +** +** Inputs: +** fm -- PRFileMap pointer to be represented as a string. +** bufsize -- sizeof(buf) +** buf -- a buffer of length PR_FILEMAP_STRING_BUFSIZE +** +** Outputs: +** buf contains the stringized PRFileMap identifier +** +** Returns: +** PRStatus +** +*/ +NSPR_API( PRStatus ) +PR_ExportFileMapAsString( + PRFileMap *fm, + PRSize bufsize, + char *buf +); +#define PR_FILEMAP_STRING_BUFSIZE 128 + +/* +** PR_ImportFileMapFromString() -- Creates a PRFileMap from the identifying string +** +** Description: +** PR_ImportFileMapFromString() creates a PRFileMap object from a +** string previously created by PR_ExportFileMapAsString(). +** +** Inputs: +** fmstring -- string created by PR_ExportFileMapAsString() +** +** Returns: +** PRFileMap pointer or NULL. +** +*/ +NSPR_API( PRFileMap * ) +PR_ImportFileMapFromString( + const char *fmstring +); + +PR_END_EXTERN_C +#endif /* prshma_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prsystem.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prsystem.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prsystem.h @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prsystem_h___ +#define prsystem_h___ + +/* +** API to NSPR functions returning system info. +*/ +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* +** Get the host' directory separator. +** Pathnames are then assumed to be of the form: +** []*() +*/ + +NSPR_API(char) PR_GetDirectorySeparator(void); + +/* +** OBSOLETE -- the function name is misspelled. +** Use PR_GetDirectorySeparator instead. +*/ + +NSPR_API(char) PR_GetDirectorySepartor(void); + +/* +** Get the host' path separator. +** Paths are assumed to be of the form: +** []* +*/ + +NSPR_API(char) PR_GetPathSeparator(void); + +/* Types of information available via PR_GetSystemInfo(...) */ +typedef enum { + PR_SI_HOSTNAME, /* the hostname with the domain name (if any) + * removed */ + PR_SI_SYSNAME, + PR_SI_RELEASE, + PR_SI_ARCHITECTURE, + PR_SI_HOSTNAME_UNTRUNCATED /* the hostname exactly as configured + * on the system */ +} PRSysInfo; + + +/* +** If successful returns a null termintated string in 'buf' for +** the information indicated in 'cmd'. If unseccussful the reason for +** the failure can be retrieved from PR_GetError(). +** +** The buffer is allocated by the caller and should be at least +** SYS_INFO_BUFFER_LENGTH bytes in length. +*/ + +#define SYS_INFO_BUFFER_LENGTH 256 + +NSPR_API(PRStatus) PR_GetSystemInfo(PRSysInfo cmd, char *buf, PRUint32 buflen); + +/* +** Return the number of bytes in a page +*/ +NSPR_API(PRInt32) PR_GetPageSize(void); + +/* +** Return log2 of the size of a page +*/ +NSPR_API(PRInt32) PR_GetPageShift(void); + +/* +** PR_GetNumberOfProcessors() -- returns the number of CPUs +** +** Description: +** PR_GetNumberOfProcessors() extracts the number of processors +** (CPUs available in an SMP system) and returns the number. +** +** Parameters: +** none +** +** Returns: +** The number of available processors or -1 on error +** +*/ +NSPR_API(PRInt32) PR_GetNumberOfProcessors( void ); + +/* +** PR_GetPhysicalMemorySize() -- returns the amount of system RAM +** +** Description: +** PR_GetPhysicalMemorySize() determines the amount of physical RAM +** in the system and returns the size in bytes. +** +** Parameters: +** none +** +** Returns: +** The amount of system RAM, or 0 on failure. +** +*/ +NSPR_API(PRUint64) PR_GetPhysicalMemorySize(void); + +PR_END_EXTERN_C + +#endif /* prsystem_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prthread.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prthread.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prthread.h @@ -0,0 +1,272 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prthread_h___ +#define prthread_h___ + +/* +** API for NSPR threads. On some architectures (Mac OS Classic +** notably) pre-emptibility is not guaranteed. Hard priority scheduling +** is not guaranteed, so programming using priority based synchronization +** is a no-no. +** +** NSPR threads are scheduled based loosely on their client set priority. +** In general, a thread of a higher priority has a statistically better +** chance of running relative to threads of lower priority. However, +** NSPR uses multiple strategies to provide execution vehicles for thread +** abstraction of various host platforms. As it turns out, there is little +** NSPR can do to affect the scheduling attributes of "GLOBAL" threads. +** However, a semblance of GLOBAL threads is used to implement "LOCAL" +** threads. An arbitrary number of such LOCAL threads can be assigned to +** a single GLOBAL thread. +** +** For scheduling, NSPR will attempt to run the highest priority LOCAL +** thread associated with a given GLOBAL thread. It is further assumed +** that the host OS will apply some form of "fair" scheduling on the +** GLOBAL threads. +** +** Threads have a "system flag" which when set indicates the thread +** doesn't count for determining when the process should exit (the +** process exits when the last user thread exits). +** +** Threads also have a "scope flag" which controls whether the threads +** are scheduled in the local scope or scheduled by the OS globally. This +** indicates whether a thread is permanently bound to a native OS thread. +** An unbound thread competes for scheduling resources in the same process. +** +** Another flag is "state flag" which control whether the thread is joinable. +** It allows other threads to wait for the created thread to reach completion. +** +** Threads can have "per-thread-data" attached to them. Each thread has a +** per-thread error number and error string which are updated when NSPR +** operations fail. +*/ +#include "prtypes.h" +#include "prinrval.h" + +PR_BEGIN_EXTERN_C + +typedef struct PRThread PRThread; +typedef struct PRThreadStack PRThreadStack; + +typedef enum PRThreadType { + PR_USER_THREAD, + PR_SYSTEM_THREAD +} PRThreadType; + +typedef enum PRThreadScope { + PR_LOCAL_THREAD, + PR_GLOBAL_THREAD, + PR_GLOBAL_BOUND_THREAD +} PRThreadScope; + +typedef enum PRThreadState { + PR_JOINABLE_THREAD, + PR_UNJOINABLE_THREAD +} PRThreadState; + +typedef enum PRThreadPriority +{ + PR_PRIORITY_FIRST = 0, /* just a placeholder */ + PR_PRIORITY_LOW = 0, /* the lowest possible priority */ + PR_PRIORITY_NORMAL = 1, /* most common expected priority */ + PR_PRIORITY_HIGH = 2, /* slightly more aggressive scheduling */ + PR_PRIORITY_URGENT = 3, /* it does little good to have more than one */ + PR_PRIORITY_LAST = 3 /* this is just a placeholder */ +} PRThreadPriority; + +/* +** Create a new thread: +** "type" is the type of thread to create +** "start(arg)" will be invoked as the threads "main" +** "priority" will be created thread's priority +** "scope" will specify whether the thread is local or global +** "state" will specify whether the thread is joinable or not +** "stackSize" the size of the stack, in bytes. The value can be zero +** and then a machine specific stack size will be chosen. +** +** This can return NULL if some kind of error occurs, such as if memory is +** tight. +** +** If you want the thread to start up waiting for the creator to do +** something, enter a lock before creating the thread and then have the +** threads start routine enter and exit the same lock. When you are ready +** for the thread to run, exit the lock. +** +** If you want to detect the completion of the created thread, the thread +** should be created joinable. Then, use PR_JoinThread to synchrnoize the +** termination of another thread. +** +** When the start function returns the thread exits. If it is the last +** PR_USER_THREAD to exit then the process exits. +*/ +NSPR_API(PRThread*) PR_CreateThread(PRThreadType type, + void (PR_CALLBACK *start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); + +/* +** Wait for thread termination: +** "thread" is the target thread +** +** This can return PR_FAILURE if no joinable thread could be found +** corresponding to the specified target thread. +** +** The calling thread is blocked until the target thread completes. +** Several threads cannot wait for the same thread to complete; one thread +** will operate successfully and others will terminate with an error PR_FAILURE. +** The calling thread will not be blocked if the target thread has already +** terminated. +*/ +NSPR_API(PRStatus) PR_JoinThread(PRThread *thread); + +/* +** Return the current thread object for the currently running code. +** Never returns NULL. +*/ +NSPR_API(PRThread*) PR_GetCurrentThread(void); +#ifndef NO_NSPR_10_SUPPORT +#define PR_CurrentThread() PR_GetCurrentThread() /* for nspr1.0 compat. */ +#endif /* NO_NSPR_10_SUPPORT */ + +/* +** Get the priority of "thread". +*/ +NSPR_API(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread); + +/* +** Change the priority of the "thread" to "priority". +** +** PR_SetThreadPriority works in a best-effort manner. On some platforms a +** special privilege, such as root access, is required to change thread +** priorities, especially to raise thread priorities. If the caller doesn't +** have enough privileges to change thread priorites, the function has no +** effect except causing a future PR_GetThreadPriority call to return +** |priority|. +*/ +NSPR_API(void) PR_SetThreadPriority(PRThread *thread, PRThreadPriority priority); + +/* +** Set the name of the current thread, which will be visible in a debugger +** and accessible via a call to PR_GetThreadName(). +*/ +NSPR_API(PRStatus) PR_SetCurrentThreadName(const char *name); + +/* +** Return the name of "thread", if set. Otherwise return NULL. +*/ +NSPR_API(const char *) PR_GetThreadName(const PRThread *thread); + +/* +** This routine returns a new index for per-thread-private data table. +** The index is visible to all threads within a process. This index can +** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines +** to save and retrieve data associated with the index for a thread. +** +** Each index is associationed with a destructor function ('dtor'). The function +** may be specified as NULL when the index is created. If it is not NULL, the +** function will be called when: +** - the thread exits and the private data for the associated index +** is not NULL, +** - new thread private data is set and the current private data is +** not NULL. +** +** The index independently maintains specific values for each binding thread. +** A thread can only get access to its own thread-specific-data. +** +** Upon a new index return the value associated with the index for all threads +** is NULL, and upon thread creation the value associated with all indices for +** that thread is NULL. +** +** Returns PR_FAILURE if the total number of indices will exceed the maximun +** allowed. +*/ +typedef void (PR_CALLBACK *PRThreadPrivateDTOR)(void *priv); + +NSPR_API(PRStatus) PR_NewThreadPrivateIndex( + PRUintn *newIndex, PRThreadPrivateDTOR destructor); + +/* +** Define some per-thread-private data. +** "tpdIndex" is an index into the per-thread private data table +** "priv" is the per-thread-private data +** +** If the per-thread private data table has a previously registered +** destructor function and a non-NULL per-thread-private data value, +** the destructor function is invoked. +** +** This can return PR_FAILURE if the index is invalid. +*/ +NSPR_API(PRStatus) PR_SetThreadPrivate(PRUintn tpdIndex, void *priv); + +/* +** Recover the per-thread-private data for the current thread. "tpdIndex" is +** the index into the per-thread private data table. +** +** The returned value may be NULL which is indistinguishable from an error +** condition. +** +** A thread can only get access to its own thread-specific-data. +*/ +NSPR_API(void*) PR_GetThreadPrivate(PRUintn tpdIndex); + +/* +** This routine sets the interrupt request for a target thread. The interrupt +** request remains in the thread's state until it is delivered exactly once +** or explicitly canceled. +** +** A thread that has been interrupted will fail all NSPR blocking operations +** that return a PRStatus (I/O, waiting on a condition, etc). +** +** PR_Interrupt may itself fail if the target thread is invalid. +*/ +NSPR_API(PRStatus) PR_Interrupt(PRThread *thread); + +/* +** Clear the interrupt request for the calling thread. If no such request +** is pending, this operation is a noop. +*/ +NSPR_API(void) PR_ClearInterrupt(void); + +/* +** Block the interrupt for the calling thread. +*/ +NSPR_API(void) PR_BlockInterrupt(void); + +/* +** Unblock the interrupt for the calling thread. +*/ +NSPR_API(void) PR_UnblockInterrupt(void); + +/* +** Make the current thread sleep until "ticks" time amount of time +** has expired. If "ticks" is PR_INTERVAL_NO_WAIT then the call is +** equivalent to calling PR_Yield. Calling PR_Sleep with an argument +** equivalent to PR_INTERVAL_NO_TIMEOUT is an error and will result +** in a PR_FAILURE error return. +*/ +NSPR_API(PRStatus) PR_Sleep(PRIntervalTime ticks); + +/* +** Get the scoping of this thread. +*/ +NSPR_API(PRThreadScope) PR_GetThreadScope(const PRThread *thread); + +/* +** Get the type of this thread. +*/ +NSPR_API(PRThreadType) PR_GetThreadType(const PRThread *thread); + +/* +** Get the join state of this thread. +*/ +NSPR_API(PRThreadState) PR_GetThreadState(const PRThread *thread); + +PR_END_EXTERN_C + +#endif /* prthread_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prtime.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prtime.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prtime.h @@ -0,0 +1,262 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* + *---------------------------------------------------------------------- + * + * prtime.h -- + * + * NSPR date and time functions + * + *----------------------------------------------------------------------- + */ + +#ifndef prtime_h___ +#define prtime_h___ + +#include "prlong.h" + +PR_BEGIN_EXTERN_C + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +#define PR_MSEC_PER_SEC 1000L +#define PR_USEC_PER_SEC 1000000L +#define PR_NSEC_PER_SEC 1000000000L +#define PR_USEC_PER_MSEC 1000L +#define PR_NSEC_PER_MSEC 1000000L + +/* + * PRTime -- + * + * NSPR represents basic time as 64-bit signed integers relative + * to midnight (00:00:00), January 1, 1970 Greenwich Mean Time (GMT). + * (GMT is also known as Coordinated Universal Time, UTC.) + * The units of time are in microseconds. Negative times are allowed + * to represent times prior to the January 1970 epoch. Such values are + * intended to be exported to other systems or converted to human + * readable form. + * + * Notes on porting: PRTime corresponds to time_t in ANSI C. NSPR 1.0 + * simply uses PRInt64. + */ + +typedef PRInt64 PRTime; + +/* + * Time zone and daylight saving time corrections applied to GMT to + * obtain the local time of some geographic location + */ + +typedef struct PRTimeParameters { + PRInt32 tp_gmt_offset; /* the offset from GMT in seconds */ + PRInt32 tp_dst_offset; /* contribution of DST in seconds */ +} PRTimeParameters; + +/* + * PRExplodedTime -- + * + * Time broken down into human-readable components such as year, month, + * day, hour, minute, second, and microsecond. Time zone and daylight + * saving time corrections may be applied. If they are applied, the + * offsets from the GMT must be saved in the 'tm_params' field so that + * all the information is available to reconstruct GMT. + * + * Notes on porting: PRExplodedTime corrresponds to struct tm in + * ANSI C, with the following differences: + * - an additional field tm_usec; + * - replacing tm_isdst by tm_params; + * - the month field is spelled tm_month, not tm_mon; + * - we use absolute year, AD, not the year since 1900. + * The corresponding type in NSPR 1.0 is called PRTime. Below is + * a table of date/time type correspondence in the three APIs: + * API time since epoch time in components + * ANSI C time_t struct tm + * NSPR 1.0 PRInt64 PRTime + * NSPR 2.0 PRTime PRExplodedTime + */ + +typedef struct PRExplodedTime { + PRInt32 tm_usec; /* microseconds past tm_sec (0-99999) */ + PRInt32 tm_sec; /* seconds past tm_min (0-61, accomodating + up to two leap seconds) */ + PRInt32 tm_min; /* minutes past tm_hour (0-59) */ + PRInt32 tm_hour; /* hours past tm_day (0-23) */ + PRInt32 tm_mday; /* days past tm_mon (1-31, note that it + starts from 1) */ + PRInt32 tm_month; /* months past tm_year (0-11, Jan = 0) */ + PRInt16 tm_year; /* absolute year, AD (note that we do not + count from 1900) */ + + PRInt8 tm_wday; /* calculated day of the week + (0-6, Sun = 0) */ + PRInt16 tm_yday; /* calculated day of the year + (0-365, Jan 1 = 0) */ + + PRTimeParameters tm_params; /* time parameters used by conversion */ +} PRExplodedTime; + +/* + * PRTimeParamFn -- + * + * A function of PRTimeParamFn type returns the time zone and + * daylight saving time corrections for some geographic location, + * given the current time in GMT. The input argument gmt should + * point to a PRExplodedTime that is in GMT, i.e., whose + * tm_params contains all 0's. + * + * For any time zone other than GMT, the computation is intended to + * consist of two steps: + * - Figure out the time zone correction, tp_gmt_offset. This number + * usually depends on the geographic location only. But it may + * also depend on the current time. For example, all of China + * is one time zone right now. But this situation may change + * in the future. + * - Figure out the daylight saving time correction, tp_dst_offset. + * This number depends on both the geographic location and the + * current time. Most of the DST rules are expressed in local + * current time. If so, one should apply the time zone correction + * to GMT before applying the DST rules. + */ + +typedef PRTimeParameters (PR_CALLBACK *PRTimeParamFn)(const PRExplodedTime *gmt); + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/* + * The PR_Now routine returns the current time relative to the + * epoch, midnight, January 1, 1970 UTC. The units of the returned + * value are microseconds since the epoch. + * + * The values returned are not guaranteed to advance in a linear fashion + * due to the application of time correction protocols which synchronize + * computer clocks to some external time source. Consequently it should + * not be depended on for interval timing. + * + * The implementation is machine dependent. + * Cf. time_t time(time_t *tp) in ANSI C. + */ +NSPR_API(PRTime) +PR_Now(void); + +/* + * Expand time binding it to time parameters provided by PRTimeParamFn. + * The calculation is envisoned to proceed in the following steps: + * - From given PRTime, calculate PRExplodedTime in GMT + * - Apply the given PRTimeParamFn to the GMT that we just calculated + * to obtain PRTimeParameters. + * - Add the PRTimeParameters offsets to GMT to get the local time + * as PRExplodedTime. + */ + +NSPR_API(void) PR_ExplodeTime( + PRTime usecs, PRTimeParamFn params, PRExplodedTime *exploded); + +/* Reverse operation of PR_ExplodeTime */ +NSPR_API(PRTime) +PR_ImplodeTime(const PRExplodedTime *exploded); + +/* + * Adjust exploded time to normalize field overflows after manipulation. + * Note that the following fields of PRExplodedTime should not be + * manipulated: + * - tm_month and tm_year: because the number of days in a month and + * number of days in a year are not constant, it is ambiguous to + * manipulate the month and year fields, although one may be tempted + * to. For example, what does "a month from January 31st" mean? + * - tm_wday and tm_yday: these fields are calculated by NSPR. Users + * should treat them as "read-only". + */ + +NSPR_API(void) PR_NormalizeTime( + PRExplodedTime *exploded, PRTimeParamFn params); + +/**********************************************************************/ +/*********************** TIME PARAMETER FUNCTIONS *********************/ +/**********************************************************************/ + +/* Time parameters that suit current host machine */ +NSPR_API(PRTimeParameters) PR_LocalTimeParameters(const PRExplodedTime *gmt); + +/* Time parameters that represent Greenwich Mean Time */ +NSPR_API(PRTimeParameters) PR_GMTParameters(const PRExplodedTime *gmt); + +/* + * Time parameters that represent the US Pacific Time Zone, with the + * current daylight saving time rules (for testing only) + */ +NSPR_API(PRTimeParameters) PR_USPacificTimeParameters(const PRExplodedTime *gmt); + +/* + * This parses a time/date string into a PRExplodedTime + * struct. It populates all fields but it can't split + * the offset from UTC into tp_gmt_offset and tp_dst_offset in + * most cases (exceptions: PST/PDT, MST/MDT, CST/CDT, EST/EDT, GMT/BST). + * In those cases tp_gmt_offset will be the sum of these two and + * tp_dst_offset will be 0. + * It returns PR_SUCCESS on success, and PR_FAILURE + * if the time/date string can't be parsed. + * + * Many formats are handled, including: + * + * 14 Apr 89 03:20:12 + * 14 Apr 89 03:20 GMT + * Fri, 17 Mar 89 4:01:33 + * Fri, 17 Mar 89 4:01 GMT + * Mon Jan 16 16:12 PDT 1989 + * Mon Jan 16 16:12 +0130 1989 + * 6 May 1992 16:41-JST (Wednesday) + * 22-AUG-1993 10:59:12.82 + * 22-AUG-1993 10:59pm + * 22-AUG-1993 12:59am + * 22-AUG-1993 12:59 PM + * Friday, August 04, 1995 3:54 PM + * 06/21/95 04:24:34 PM + * 20/06/95 21:07 + * 95-06-08 19:32:48 EDT + * + * If the input string doesn't contain a description of the timezone, + * we consult the `default_to_gmt' to decide whether the string should + * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE). + * The correct value for this argument depends on what standard specified + * the time string which you are parsing. + */ + +NSPR_API(PRStatus) PR_ParseTimeStringToExplodedTime ( + const char *string, + PRBool default_to_gmt, + PRExplodedTime *result); + +/* + * This uses PR_ParseTimeStringToExplodedTime to parse + * a time/date string and PR_ImplodeTime to transform it into + * a PRTime (microseconds after "1-Jan-1970 00:00:00 GMT"). + * It returns PR_SUCCESS on success, and PR_FAILURE + * if the time/date string can't be parsed. + */ + +NSPR_API(PRStatus) PR_ParseTimeString ( + const char *string, + PRBool default_to_gmt, + PRTime *result); + +/* Format a time value into a buffer. Same semantics as strftime() */ +NSPR_API(PRUint32) PR_FormatTime(char *buf, int buflen, const char *fmt, + const PRExplodedTime *time); + +/* Format a time value into a buffer. Time is always in US English format, + * regardless of locale setting. + */ +NSPR_API(PRUint32) +PR_FormatTimeUSEnglish(char *buf, PRUint32 bufSize, + const char *format, const PRExplodedTime *time); + +PR_END_EXTERN_C + +#endif /* prtime_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prtpool.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prtpool.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prtpool.h @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prtpool_h___ +#define prtpool_h___ + +#include "prtypes.h" +#include "prthread.h" +#include "prio.h" +#include "prerror.h" + +/* + * NOTE: + * THIS API IS A PRELIMINARY VERSION IN NSPR 4.0 AND IS SUBJECT TO + * CHANGE + */ + +PR_BEGIN_EXTERN_C + +typedef struct PRJobIoDesc { + PRFileDesc *socket; + PRErrorCode error; + PRIntervalTime timeout; +} PRJobIoDesc; + +typedef struct PRThreadPool PRThreadPool; +typedef struct PRJob PRJob; +typedef void (PR_CALLBACK *PRJobFn) (void *arg); + +/* Create thread pool */ +NSPR_API(PRThreadPool *) +PR_CreateThreadPool(PRInt32 initial_threads, PRInt32 max_threads, + PRUint32 stacksize); + +/* queue a job */ +NSPR_API(PRJob *) +PR_QueueJob(PRThreadPool *tpool, PRJobFn fn, void *arg, PRBool joinable); + +/* queue a job, when a socket is readable */ +NSPR_API(PRJob *) +PR_QueueJob_Read(PRThreadPool *tpool, PRJobIoDesc *iod, + PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when a socket is writeable */ +NSPR_API(PRJob *) +PR_QueueJob_Write(PRThreadPool *tpool, PRJobIoDesc *iod, + PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when a socket has a pending connection */ +NSPR_API(PRJob *) +PR_QueueJob_Accept(PRThreadPool *tpool, PRJobIoDesc *iod, + PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when the socket connection to addr succeeds or fails */ +NSPR_API(PRJob *) +PR_QueueJob_Connect(PRThreadPool *tpool, PRJobIoDesc *iod, + const PRNetAddr *addr, PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when a timer exipres */ +NSPR_API(PRJob *) +PR_QueueJob_Timer(PRThreadPool *tpool, PRIntervalTime timeout, + PRJobFn fn, void * arg, PRBool joinable); +/* cancel a job */ +NSPR_API(PRStatus) +PR_CancelJob(PRJob *job); + +/* join a job */ +NSPR_API(PRStatus) +PR_JoinJob(PRJob *job); + +/* shutdown pool */ +NSPR_API(PRStatus) +PR_ShutdownThreadPool(PRThreadPool *tpool); + +/* join pool, wait for exit of all threads */ +NSPR_API(PRStatus) +PR_JoinThreadPool(PRThreadPool *tpool); + +PR_END_EXTERN_C + +#endif /* prtpool_h___ */ Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prtrace.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prtrace.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prtrace.h @@ -0,0 +1,646 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prtrace_h___ +#define prtrace_h___ +/* +** prtrace.h -- NSPR's Trace Facility. +** +** The Trace Facility provides a means to trace application +** program events within a process. When implementing an +** application program an engineer may insert a "Trace" function +** call, passing arguments to be traced. The "Trace" function +** combines the user trace data with identifying data and +** writes this data in time ordered sequence into a circular +** in-memory buffer; when the buffer fills, it wraps. +** +** Functions are provided to set and/or re-configure the size of +** the trace buffer, control what events are recorded in the +** buffer, enable and disable tracing based on specific user +** supplied data and other control functions. Methods are provided +** to record the trace entries in the in-memory trace buffer to +** a file. +** +** Tracing may cause a performance degredation to the application +** depending on the number and placement of calls to the tracing +** facility. When tracing is compiled in and all tracing is +** disabled via the runtime controls, the overhead should be +** minimal. ... Famous last words, eh? +** +** When DEBUG is defined at compile time, the Trace Facility is +** compiled as part of NSPR and any application using NSPR's +** header files will have tracing compiled in. When DEBUG is not +** defined, the Trace Facility is not compiled into NSPR nor +** exported in its header files. If the Trace Facility is +** desired in a non-debug build, then FORCE_NSPR_TRACE may be +** defined at compile time for both the optimized build of NSPR +** and the application. NSPR and any application using NSPR's +** Trace Facility must be compiled with the same level of trace +** conditioning or unresolved references may be realized at link +** time. +** +** For any of the Trace Facility methods that requires a trace +** handle as an input argument, the caller must ensure that the +** trace handle argument is valid. An invalid trace handle +** argument may cause unpredictable results. +** +** Trace Facility methods are thread-safe and SMP safe. +** +** Users of the Trace Facility should use the defined macros to +** invoke trace methods, not the function calls directly. e.g. +** PR_TRACE( h1,0,1,2, ...); not PR_Trace(h1,0,1,2, ...); +** +** Application designers should be aware of the effects of +** debug and optimized build differences when using result of the +** Trace Facility macros in expressions. +** +** See Also: prcountr.h +** +** /lth. 08-Jun-1998. +*/ + +#include "prtypes.h" +#include "prthread.h" +#include "prtime.h" + +PR_BEGIN_EXTERN_C + +/* +** Opaque type for the trace handle +** ... Don't even think about looking in here. +** +*/ +typedef void * PRTraceHandle; + +/* +** PRTraceEntry -- A trace entry in the in-memory trace buffer +** looks like this. +** +*/ +typedef struct PRTraceEntry +{ + PRThread *thread; /* The thread creating the trace entry */ + PRTraceHandle handle; /* PRTraceHandle creating the trace entry */ + PRTime time; /* Value of PR_Now() at time of trace entry */ + PRUint32 userData[8]; /* user supplied trace data */ +} PRTraceEntry; + +/* +** PRTraceOption -- command operands to +** PR_[Set|Get]TraceOption(). See descriptive meanings there. +** +*/ +typedef enum PRTraceOption +{ + PRTraceBufSize, + PRTraceEnable, + PRTraceDisable, + PRTraceSuspend, + PRTraceResume, + PRTraceSuspendRecording, + PRTraceResumeRecording, + PRTraceLockHandles, + PRTraceUnLockHandles, + PRTraceStopRecording +} PRTraceOption; + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DEFINE_TRACE() -- Define a PRTraceHandle +** +** DESCRIPTION: PR_DEFINE_TRACE() is used to define a trace +** handle. +** +*/ +#define PR_DEFINE_TRACE(name) PRTraceHandle name + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_INIT_TRACE_HANDLE() -- Set the value of a PRTraceHandle +** +** DESCRIPTION: +** PR_INIT_TRACE_HANDLE() sets the value of a PRTraceHandle +** to value. e.g. PR_INIT_TRACE_HANDLE( myHandle, NULL ); +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_INIT_TRACE_HANDLE(handle,value)\ + (handle) = (PRCounterHandle)(value) +#else +#define PR_INIT_TRACE_HANDLE(handle,value) +#endif + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_CreateTrace() -- Create a trace handle +** +** DESCRIPTION: +** PR_CreateTrace() creates a new trace handle. Tracing is +** enabled for this handle when it is created. The trace handle +** is intended for use in other Trace Facility calls. +** +** PR_CreateTrace() registers the QName, RName and description +** data so that this data can be retrieved later. +** +** INPUTS: +** qName: pointer to string. QName for this trace handle. +** +** rName: pointer to string. RName for this trace handle. +** +** description: pointer to string. Descriptive data about this +** trace handle. +** +** OUTPUTS: +** Creates the trace handle. +** Registers the QName and RName with the trace facility. +** +** RETURNS: +** PRTraceHandle +** +** RESTRICTIONS: +** qName is limited to 31 characters. +** rName is limited to 31 characters. +** description is limited to 255 characters. +** +*/ +#define PRTRACE_NAME_MAX 31 +#define PRTRACE_DESC_MAX 255 + +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_CREATE_TRACE(handle,qName,rName,description)\ + (handle) = PR_CreateTrace((qName),(rName),(description)) +#else +#define PR_CREATE_TRACE(handle,qName,rName,description) +#endif + +NSPR_API(PRTraceHandle) + PR_CreateTrace( + const char *qName, /* QName for this trace handle */ + const char *rName, /* RName for this trace handle */ + const char *description /* description for this trace handle */ +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DestroyTrace() -- Destroy a trace handle +** +** DESCRIPTION: +** PR_DestroyTrace() removes the referenced trace handle and +** associated QName, RName and description data from the Trace +** Facility. +** +** INPUTS: handle. A PRTraceHandle +** +** OUTPUTS: +** The trace handle is unregistered. +** The QName, RName and description are removed. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_DESTROY_TRACE(handle)\ + PR_DestroyTrace((handle)) +#else +#define PR_DESTROY_TRACE(handle) +#endif + +NSPR_API(void) + PR_DestroyTrace( + PRTraceHandle handle /* Handle to be destroyed */ +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_Trace() -- Make a trace entry in the in-memory trace +** +** DESCRIPTION: +** PR_Trace() makes an entry in the in-memory trace buffer for +** the referenced trace handle. The next logically available +** PRTraceEntry is used; when the next trace entry would overflow +** the trace table, the table wraps. +** +** PR_Trace() for a specific trace handle may be disabled by +** calling PR_SetTraceOption() specifying PRTraceDisable for the +** trace handle to be disabled. +** +** INPUTS: +** handle: PRTraceHandle. The trace handle for this trace. +** +** userData[0..7]: unsigned 32bit integers. user supplied data +** that is copied into the PRTraceEntry +** +** OUTPUTS: +** A PRTraceEntry is (conditionally) formatted in the in-memory +** trace buffer. +** +** RETURNS: void. +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_TRACE(handle,ud0,ud1,ud2,ud3,ud4,ud5,ud6,ud7)\ + PR_Trace((handle),(ud0),(ud1),(ud2),(ud3),(ud4),(ud5),(ud6),(ud7)) +#else +#define PR_TRACE(handle,ud0,ud1,ud2,ud3,ud4,ud5,ud6,ud7) +#endif + +NSPR_API(void) + PR_Trace( + PRTraceHandle handle, /* use this trace handle */ + PRUint32 userData0, /* User supplied data word 0 */ + PRUint32 userData1, /* User supplied data word 1 */ + PRUint32 userData2, /* User supplied data word 2 */ + PRUint32 userData3, /* User supplied data word 3 */ + PRUint32 userData4, /* User supplied data word 4 */ + PRUint32 userData5, /* User supplied data word 5 */ + PRUint32 userData6, /* User supplied data word 6 */ + PRUint32 userData7 /* User supplied data word 7 */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_SetTraceOption() -- Control the Trace Facility +** +** DESCRIPTION: +** PR_SetTraceOption() controls the Trace Facility. Depending on +** command and value, attributes of the Trace Facility may be +** changed. +** +** INPUTS: +** command: An enumerated value in the set of PRTraceOption. +** value: pointer to the data to be set. Type of the data is +** dependent on command; for each value of command, the type +** and meaning of dereferenced value is shown. +** +** PRTraceBufSize: unsigned long: the size of the trace buffer, +** in bytes. +** +** PRTraceEnable: PRTraceHandle. The trace handle to be +** enabled. +** +** PRTraceDisable: PRTraceHandle. The trace handle to be +** disabled. +** +** PRTraceSuspend: void. value must be NULL. All tracing is +** suspended. +** +** PRTraceResume: void. value must be NULL. Tracing for all +** previously enabled, prior to a PRTraceSuspend, is resumed. +** +** PRTraceStopRecording: void. value must be NULL. If recording +** (see: ** PR_RecordTraceEntries()) is being done, +** PRTraceStopRecording causes PR_RecordTraceEntries() to return +** to its caller. If recording is not being done, this function +** has no effect. +** +** PRTraceSuspendRecording: void. Must be NULL. If recording is +** being done, PRTraceSuspendRecording causes further writes to +** the trace file to be suspended. Data in the in-memory +** trace buffer that would ordinarily be written to the +** trace file will not be written. Trace entries will continue +** to be entered in the in-memory buffer. If the Trace Facility +** recording is already in a suspended state, the call has no +** effect. +** +** PRTraceResumeRecording: void. value must be NULL. If +** recording for the Trace Facility has been previously been +** suspended, this causes recording to resume. Recording resumes +** with the next in-memory buffer segment that would be written +** if trace recording had not been suspended. If recording is +** not currently suspended, the call has no effect. +** +** PRTraceLockHandles: void. value must be NULL. Locks the +** trace handle lock. While the trace handle lock is held, +** calls to PR_CreateTrace() will block until the lock is +** released. +** +** PRTraceUnlockHandles: void. value must be NULL. Unlocks the +** trace handle lock. +** +** OUTPUTS: +** The operation of the Trace Facility may be changed. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_SET_TRACE_OPTION(command,value)\ + PR_SetTraceOption((command),(value)) +#else +#define PR_SET_TRACE_OPTION(command,value) +#endif + +NSPR_API(void) + PR_SetTraceOption( + PRTraceOption command, /* One of the enumerated values */ + void *value /* command value or NULL */ +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceOption() -- Retrieve settings from the Trace Facility +** +** DESCRIPTION: +** PR_GetTraceOption() retrieves the current setting of the +** Trace Facility control depending on command. +** +** +** PRTraceBufSize: unsigned long: the size of the trace buffer, +** in bytes. +** +** +** INPUTS: +** command: one of the enumerated values in PRTraceOptions +** valid for PR_GetTraceOption(). +** +** OUTPUTS: +** dependent on command. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_OPTION(command,value)\ + PR_GetTraceOption((command),(value)) +#else +#define PR_GET_TRACE_OPTION(command,value) +#endif + +NSPR_API(void) + PR_GetTraceOption( + PRTraceOption command, /* One of the enumerated values */ + void *value /* command value or NULL */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceHandleFromName() -- Retrieve an existing +** handle by name. +** +** DESCRIPTION: +** PR_GetTraceHandleFromName() retreives an existing tracehandle +** using the name specified by qName and rName. +** +** INPUTS: +** qName: pointer to string. QName for this trace handle. +** +** rName: pointer to string. RName for this trace handle. +** +** +** OUTPUTS: returned. +** +** RETURNS: +** PRTraceHandle associated with qName and rName or NULL when +** there is no match. +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_HANDLE_FROM_NAME(handle,qName,rName)\ + (handle) = PR_GetTraceHandleFromName((qName),(rName)) +#else +#define PR_GET_TRACE_HANDLE_FROM_NAME(handle,qName,rName) +#endif + +NSPR_API(PRTraceHandle) + PR_GetTraceHandleFromName( + const char *qName, /* QName search argument */ + const char *rName /* RName search argument */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceNameFromHandle() -- Retreive trace name +** by bandle. +** +** DESCRIPTION: +** PR_GetTraceNameFromHandle() retreives the existing qName, +** rName, and description for the referenced trace handle. +** +** INPUTS: handle: PRTraceHandle. +** +** OUTPUTS: pointers to the Trace Facility's copy of qName, +** rName and description. ... Don't mess with these values. +** They're mine. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_NAME_FROM_HANDLE(handle,qName,rName,description)\ + PR_GetTraceNameFromHandle((handle),(qName),(rName),(description)) +#else +#define PR_GET_TRACE_NAME_FROM_HANDLE(handle,qName,rName,description) +#endif + +NSPR_API(void) + PR_GetTraceNameFromHandle( + PRTraceHandle handle, /* handle as search argument */ + const char **qName, /* pointer to associated QName */ + const char **rName, /* pointer to associated RName */ + const char **description /* pointer to associated description */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextTraceQname() -- Retrieive a QName handle +** iterator. +** +** DESCRIPTION: +** PR_FindNextTraceQname() retreives the first or next trace +** QName handle, depending on the value of handle, from the trace +** database. The PRTraceHandle returned can be used as an +** iterator to traverse the QName handles in the Trace database. +** +** INPUTS: +** handle: When NULL, PR_FindNextQname() returns the first QName +** handle. When a handle is a valid PRTraceHandle previously +** retreived using PR_FindNextQname() the next QName handle is +** retreived. +** +** OUTPUTS: returned. +** +** RETURNS: +** PRTraceHandle or NULL when there are no trace handles. +** +** RESTRICTIONS: +** Iterating thru the trace handles via FindFirst/FindNext +** should be done under protection of the trace handle lock. +** See: PR_SetTraceOption( PRLockTraceHandles ). +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_FIND_NEXT_TRACE_QNAME(next,handle)\ + (next) = PR_FindNextTraceQname((handle)) +#else +#define PR_FIND_NEXT_TRACE_QNAME(next,handle) +#endif + +NSPR_API(PRTraceHandle) + PR_FindNextTraceQname( + PRTraceHandle handle +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextTraceRname() -- Retrieive an RName handle +** iterator. +** +** DESCRIPTION: +** PR_FindNextTraceRname() retreives the first or next trace +** RName handle, depending on the value of handle, from the trace +** database. The PRTraceHandle returned can be used as an +** iterator to traverse the RName handles in the Trace database. +** +** INPUTS: +** rhandle: When NULL, PR_FindNextRname() returns the first +** RName handle. When a handle is a valid PRTraceHandle +** previously retreived using PR_FindNextRname() the next RName +** handle is retreived. +** qhandle: A valid PRTraceHandle retruned from a previous call +** to PR_FIND_NEXT_TRACE_QNAME(). +** +** OUTPUTS: returned. +** +** RETURNS: +** PRTraceHandle or NULL when there are no trace handles. +** +** RESTRICTIONS: +** Iterating thru the trace handles via FindNext should be done +** under protection of the trace handle lock. See: ( +** PR_SetTraceOption( PRLockTraceHandles ). +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_FIND_NEXT_TRACE_RNAME(next,rhandle,qhandle)\ + (next) = PR_FindNextTraceRname((rhandle),(qhandle)) +#else +#define PR_FIND_NEXT_TRACE_RNAME(next,rhandle,qhandle) +#endif + +NSPR_API(PRTraceHandle) + PR_FindNextTraceRname( + PRTraceHandle rhandle, + PRTraceHandle qhandle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_RecordTraceEntries() -- Write trace entries to external media +** +** DESCRIPTION: +** PR_RecordTraceEntries() causes entries in the in-memory trace +** buffer to be written to external media. +** +** When PR_RecordTraceEntries() is called from an application +** thread, the function appears to block until another thread +** calls PR_SetTraceOption() with the PRTraceStopRecording +** option. This suggests that PR_RecordTraceEntries() should be +** called from a user supplied thread whose only job is to +** record trace entries. +** +** The environment variable NSPR_TRACE_LOG controls the operation +** of this function. When NSPR_TRACE_LOG is not defined in the +** environment, no recording of trace entries occurs. When +** NSPR_TRACE_LOG is defined, the value of its definition must be +** the filename of the file to receive the trace entry buffer. +** +** PR_RecordTraceEntries() attempts to record the in-memory +** buffer to a file, subject to the setting of the environment +** variable NSPR_TRACE_LOG. It is possible because of system +** load, the thread priority of the recording thread, number of +** active trace records being written over time, and other +** variables that some trace records can be lost. ... In other +** words: don't bet the farm on getting everything. +** +** INPUTS: none +** +** OUTPUTS: none +** +** RETURNS: PR_STATUS +** PR_SUCCESS no errors were found. +** PR_FAILURE errors were found. +** +** RESTRICTIONS: +** Only one thread can call PR_RecordTraceEntries() within a +** process. +** +** On error, PR_RecordTraceEntries() may return prematurely. +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_RECORD_TRACE_ENTRIES()\ + PR_RecordTraceEntries() +#else +#define PR_RECORD_TRACE_ENTRIES() +#endif + +NSPR_API(void) + PR_RecordTraceEntries( + void +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceEntries() -- Retreive trace entries from +** the Trace Facility +** +** DESCRIPTION: +** PR_GetTraceEntries() retreives trace entries from the Trace +** Facility. Up to count trace entries are copied from the Trace +** Facility into buffer. Only those trace entries that have not +** been copied via a previous call to PR_GetTraceEntries() are +** copied. The actual number copied is placed in the PRInt32 +** variable pointed to by found. +** +** If more than count trace entries have entered the Trace +** Facility since the last call to PR_GetTraceEntries() +** a lost data condition is returned. In this case, the most +** recent count trace entries are copied into buffer and found is +** set to count. +** +** INPUTS: +** count. The number of trace entries to be copied into buffer. +** +** +** OUTPUTS: +** buffer. An array of PRTraceEntries. The buffer is supplied +** by the caller. +** +** found: 32bit signed integer. The number of PRTraceEntries +** actually copied. found is always less than or equal to count. +** +** RETURNS: +** zero when there is no lost data. +** non-zero when some PRTraceEntries have been lost. +** +** RESTRICTIONS: +** This is a real performance pig. The copy out operation is bad +** enough, but depending on then frequency of calls to the +** function, serious performance impact to the operating +** application may be realized. ... YMMV. +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_ENTRIES(buffer,count,found)\ + PR_GetTraceEntries((buffer),(count),(found)) +#else +#define PR_GET_TRACE_ENTRIES(buffer,count,found) +#endif + +NSPR_API(PRIntn) + PR_GetTraceEntries( + PRTraceEntry *buffer, /* where to write output */ + PRInt32 count, /* number to get */ + PRInt32 *found /* number you got */ +); + +PR_END_EXTERN_C + +#endif /* prtrace_h___ */ + Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prtypes.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prtypes.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prtypes.h @@ -0,0 +1,598 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* +** File: prtypes.h +** Description: Definitions of NSPR's basic types +** +** Prototypes and macros used to make up for deficiencies that we have found +** in ANSI environments. +** +** Since we do not wrap and all the other standard headers, authors +** of portable code will not know in general that they need these definitions. +** Instead of requiring these authors to find the dependent uses in their code +** and take the following steps only in those C files, we take steps once here +** for all C files. +**/ + +#ifndef prtypes_h___ +#define prtypes_h___ + +#ifdef MDCPUCFG +#include MDCPUCFG +#else +#include "prcpucfg.h" +#endif + +#include + +/*********************************************************************** +** MACROS: PR_EXTERN +** PR_IMPLEMENT +** DESCRIPTION: +** These are only for externally visible routines and globals. For +** internal routines, just use "extern" for type checking and that +** will not export internal cross-file or forward-declared symbols. +** Define a macro for declaring procedures return types. We use this to +** deal with windoze specific type hackery for DLL definitions. Use +** PR_EXTERN when the prototype for the method is declared. Use +** PR_IMPLEMENT for the implementation of the method. +** +** Example: +** in dowhim.h +** PR_EXTERN( void ) DoWhatIMean( void ); +** in dowhim.c +** PR_IMPLEMENT( void ) DoWhatIMean( void ) { return; } +** +** +***********************************************************************/ +#if defined(WIN32) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_BEOS) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) extern __declspec(dllexport) __type +#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_OS2) && defined(__declspec) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) extern __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) extern __declspec(dllimport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(SYMBIAN) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#ifdef __WINS__ +#define PR_IMPORT(__type) extern __declspec(dllexport) __type +#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type +#else +#define PR_IMPORT(__type) extern __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) extern __declspec(dllimport) __type +#endif + +#define PR_EXTERN(__type) extern __type +#define PR_IMPLEMENT(__type) __type +#define PR_EXTERN_DATA(__type) extern __type +#define PR_IMPLEMENT_DATA(__type) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#else /* Unix */ + +/* GCC 3.3 and later support the visibility attribute. */ +#if (__GNUC__ >= 4) || \ + (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) +#define PR_VISIBILITY_DEFAULT __attribute__((visibility("default"))) +#else +#define PR_VISIBILITY_DEFAULT +#endif + +#define PR_EXPORT(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_EXPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPORT(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type + +#define PR_EXTERN(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPLEMENT(__type) PR_VISIBILITY_DEFAULT __type +#define PR_EXTERN_DATA(__type) extern PR_VISIBILITY_DEFAULT __type +#define PR_IMPLEMENT_DATA(__type) PR_VISIBILITY_DEFAULT __type +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#endif + +#if defined(_NSPR_BUILD_) +#define NSPR_API(__type) PR_EXPORT(__type) +#define NSPR_DATA_API(__type) PR_EXPORT_DATA(__type) +#else +#define NSPR_API(__type) PR_IMPORT(__type) +#define NSPR_DATA_API(__type) PR_IMPORT_DATA(__type) +#endif + +/*********************************************************************** +** MACROS: PR_BEGIN_MACRO +** PR_END_MACRO +** DESCRIPTION: +** Macro body brackets so that macros with compound statement definitions +** behave syntactically more like functions when called. +***********************************************************************/ +#define PR_BEGIN_MACRO do { +#define PR_END_MACRO } while (0) + +/*********************************************************************** +** MACROS: PR_BEGIN_EXTERN_C +** PR_END_EXTERN_C +** DESCRIPTION: +** Macro shorthands for conditional C++ extern block delimiters. +***********************************************************************/ +#ifdef __cplusplus +#define PR_BEGIN_EXTERN_C extern "C" { +#define PR_END_EXTERN_C } +#else +#define PR_BEGIN_EXTERN_C +#define PR_END_EXTERN_C +#endif + +/*********************************************************************** +** MACROS: PR_BIT +** PR_BITMASK +** DESCRIPTION: +** Bit masking macros. XXX n must be <= 31 to be portable +***********************************************************************/ +#define PR_BIT(n) ((PRUint32)1 << (n)) +#define PR_BITMASK(n) (PR_BIT(n) - 1) + +/*********************************************************************** +** MACROS: PR_ROUNDUP +** PR_MIN +** PR_MAX +** PR_ABS +** DESCRIPTION: +** Commonly used macros for operations on compatible types. +***********************************************************************/ +#define PR_ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y)) +#define PR_MIN(x,y) ((x)<(y)?(x):(y)) +#define PR_MAX(x,y) ((x)>(y)?(x):(y)) +#define PR_ABS(x) ((x)<0?-(x):(x)) + +/*********************************************************************** +** MACROS: PR_ARRAY_SIZE +** DESCRIPTION: +** The number of elements in an array. +***********************************************************************/ +#define PR_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) + +PR_BEGIN_EXTERN_C + +/* +** Starting in NSPR 4.9.5, NSPR's exact-width integer types should match +** the exact-width integer types defined in . This allows sloppy +** code to use PRInt{N} and int{N}_t interchangeably. +** +** The 8-bit and 16-bit integer types can only be defined using char and +** short. All platforms define the 32-bit integer types using int. So only +** the 64-bit integer types could be defined differently. +** +** NSPR's original strategy was to use the "shortest" 64-bit integer type: +** if long is 64-bit, then prefer it over long long. This strategy is also +** used by Linux/glibc, FreeBSD, and NetBSD. +** +** Other platforms use a different strategy: simply define the 64-bit +** integer types using long long. We define the PR_ALTERNATE_INT64_TYPEDEF +** macro on these platforms. Note that PR_ALTERNATE_INT64_TYPEDEF is for +** internal use by NSPR headers only. Do not define or test this macro in +** your code. +** +** NOTE: NSPR can't use because C99 requires C++ code to define +** __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS to make all the macros +** defined in available. This strange requirement is gone in +** C11. When most platforms ignore this C99 requirement, NSPR will be able +** to use . A patch to do that is in NSPR bug 634793. +*/ + +#if defined(__APPLE__) || defined(__OpenBSD__) +#define PR_ALTERNATE_INT64_TYPEDEF +#endif + +/************************************************************************ +** TYPES: PRUint8 +** PRInt8 +** DESCRIPTION: +** The int8 types are known to be 8 bits each. There is no type that +** is equivalent to a plain "char". +************************************************************************/ +#if PR_BYTES_PER_BYTE == 1 +typedef unsigned char PRUint8; +/* +** There are two scenarios that require us to define PRInt8 as type 'char'. +** (1) +** Some cfront-based C++ compilers do not like 'signed char' and +** issue the warning message: +** warning: "signed" not implemented (ignored) +** For these compilers, we have to define PRInt8 as plain 'char'. +** Make sure that plain 'char' is indeed signed under these compilers. +** (2) +** Mozilla C++ code expects the PRInt{N} and int{N}_t types to match (see bug +** 634793). If a platform defines int8_t as 'char', but NSPR defines it as +** 'signed char', it results in a type mismatch. +** On such platforms we define PRInt8 as 'char' to avoid the mismatch. +*/ +#if (defined(HPUX) && defined(__cplusplus) /* reason 1*/ \ + && !defined(__GNUC__) && __cplusplus < 199707L) \ + || (defined(SCO) && defined(__cplusplus) /* reason 1 */ \ + && !defined(__GNUC__) && __cplusplus == 1L) \ + || (defined(__sun) && defined(__cplusplus)) /* reason 2 */ +typedef char PRInt8; +#else +typedef signed char PRInt8; +#endif +#else +#error No suitable type for PRInt8/PRUint8 +#endif + +/************************************************************************ + * MACROS: PR_INT8_MAX + * PR_INT8_MIN + * PR_UINT8_MAX + * DESCRIPTION: + * The maximum and minimum values of a PRInt8 or PRUint8. +************************************************************************/ + +#define PR_INT8_MAX 127 +#define PR_INT8_MIN (-128) +#define PR_UINT8_MAX 255U + +/************************************************************************ +** TYPES: PRUint16 +** PRInt16 +** DESCRIPTION: +** The int16 types are known to be 16 bits each. +************************************************************************/ +#if PR_BYTES_PER_SHORT == 2 +typedef unsigned short PRUint16; +typedef short PRInt16; +#else +#error No suitable type for PRInt16/PRUint16 +#endif + +/************************************************************************ + * MACROS: PR_INT16_MAX + * PR_INT16_MIN + * PR_UINT16_MAX + * DESCRIPTION: + * The maximum and minimum values of a PRInt16 or PRUint16. +************************************************************************/ + +#define PR_INT16_MAX 32767 +#define PR_INT16_MIN (-32768) +#define PR_UINT16_MAX 65535U + +/************************************************************************ +** TYPES: PRUint32 +** PRInt32 +** DESCRIPTION: +** The int32 types are known to be 32 bits each. +************************************************************************/ +#if PR_BYTES_PER_INT == 4 +typedef unsigned int PRUint32; +typedef int PRInt32; +#define PR_INT32(x) x +#define PR_UINT32(x) x ## U +#elif PR_BYTES_PER_LONG == 4 +typedef unsigned long PRUint32; +typedef long PRInt32; +#define PR_INT32(x) x ## L +#define PR_UINT32(x) x ## UL +#else +#error No suitable type for PRInt32/PRUint32 +#endif + +/************************************************************************ + * MACROS: PR_INT32_MAX + * PR_INT32_MIN + * PR_UINT32_MAX + * DESCRIPTION: + * The maximum and minimum values of a PRInt32 or PRUint32. +************************************************************************/ + +#define PR_INT32_MAX PR_INT32(2147483647) +#define PR_INT32_MIN (-PR_INT32_MAX - 1) +#define PR_UINT32_MAX PR_UINT32(4294967295) + +/************************************************************************ +** TYPES: PRUint64 +** PRInt64 +** DESCRIPTION: +** The int64 types are known to be 64 bits each. Care must be used when +** declaring variables of type PRUint64 or PRInt64. Different hardware +** architectures and even different compilers have varying support for +** 64 bit values. The only guaranteed portability requires the use of +** the LL_ macros (see prlong.h). +** +** MACROS: PR_INT64 +** PR_UINT64 +** DESCRIPTION: +** The PR_INT64 and PR_UINT64 macros provide a portable way for +** specifying 64-bit integer constants. They can only be used if +** PRInt64 and PRUint64 are defined as compiler-supported 64-bit +** integer types (i.e., if HAVE_LONG_LONG is defined, which is true +** for all the supported compilers topday). If PRInt64 and PRUint64 +** are defined as structs, the LL_INIT macro defined in prlong.h has +** to be used. +** +** MACROS: PR_INT64_MAX +** PR_INT64_MIN +** PR_UINT64_MAX +** DESCRIPTION: +** The maximum and minimum values of a PRInt64 or PRUint64. +************************************************************************/ +#ifdef HAVE_LONG_LONG +/* Keep this in sync with prlong.h. */ +#if PR_BYTES_PER_LONG == 8 && !defined(PR_ALTERNATE_INT64_TYPEDEF) +typedef long PRInt64; +typedef unsigned long PRUint64; +#define PR_INT64(x) x ## L +#define PR_UINT64(x) x ## UL +#elif defined(WIN32) && !defined(__GNUC__) +typedef __int64 PRInt64; +typedef unsigned __int64 PRUint64; +#define PR_INT64(x) x ## i64 +#define PR_UINT64(x) x ## ui64 +#else +typedef long long PRInt64; +typedef unsigned long long PRUint64; +#define PR_INT64(x) x ## LL +#define PR_UINT64(x) x ## ULL +#endif /* PR_BYTES_PER_LONG == 8 */ + +#define PR_INT64_MAX PR_INT64(0x7fffffffffffffff) +#define PR_INT64_MIN (-PR_INT64_MAX - 1) +#define PR_UINT64_MAX PR_UINT64(-1) +#else /* !HAVE_LONG_LONG */ +typedef struct { +#ifdef IS_LITTLE_ENDIAN + PRUint32 lo, hi; +#else + PRUint32 hi, lo; +#endif +} PRInt64; +typedef PRInt64 PRUint64; + +#define PR_INT64_MAX (PRInt64){0x7fffffff, 0xffffffff} +#define PR_INT64_MIN (PRInt64){0xffffffff, 0xffffffff} +#define PR_UINT64_MAX (PRUint64){0xffffffff, 0xffffffff} + +#endif /* !HAVE_LONG_LONG */ + +/************************************************************************ +** TYPES: PRUintn +** PRIntn +** DESCRIPTION: +** The PRIntn types are most appropriate for automatic variables. They are +** guaranteed to be at least 16 bits, though various architectures may +** define them to be wider (e.g., 32 or even 64 bits). These types are +** never valid for fields of a structure. +************************************************************************/ +#if PR_BYTES_PER_INT >= 2 +typedef int PRIntn; +typedef unsigned int PRUintn; +#else +#error 'sizeof(int)' not sufficient for platform use +#endif + +/************************************************************************ +** TYPES: PRFloat64 +** DESCRIPTION: +** NSPR's floating point type is always 64 bits. +************************************************************************/ +typedef double PRFloat64; + +/************************************************************************ +** TYPES: PRSize +** DESCRIPTION: +** A type for representing the size of objects. +************************************************************************/ +typedef size_t PRSize; + + +/************************************************************************ +** TYPES: PROffset32, PROffset64 +** DESCRIPTION: +** A type for representing byte offsets from some location. +************************************************************************/ +typedef PRInt32 PROffset32; +typedef PRInt64 PROffset64; + +/************************************************************************ +** TYPES: PRPtrDiff +** DESCRIPTION: +** A type for pointer difference. Variables of this type are suitable +** for storing a pointer or pointer subtraction. +************************************************************************/ +typedef ptrdiff_t PRPtrdiff; + +/************************************************************************ +** TYPES: PRUptrdiff +** DESCRIPTION: +** A type for pointer difference. Variables of this type are suitable +** for storing a pointer or pointer sutraction. +************************************************************************/ +#ifdef _WIN64 +typedef PRUint64 PRUptrdiff; +#else +typedef unsigned long PRUptrdiff; +#endif + +/************************************************************************ +** TYPES: PRBool +** DESCRIPTION: +** Use PRBool for variables and parameter types. Use PR_FALSE and PR_TRUE +** for clarity of target type in assignments and actual arguments. Use +** 'if (bool)', 'while (!bool)', '(bool) ? x : y' etc., to test booleans +** just as you would C int-valued conditions. +************************************************************************/ +typedef PRIntn PRBool; +#define PR_TRUE 1 +#define PR_FALSE 0 + +/************************************************************************ +** TYPES: PRPackedBool +** DESCRIPTION: +** Use PRPackedBool within structs where bitfields are not desirable +** but minimum and consistant overhead matters. +************************************************************************/ +typedef PRUint8 PRPackedBool; + +/* +** Status code used by some routines that have a single point of failure or +** special status return. +*/ +typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus; + +#ifndef __PRUNICHAR__ +#define __PRUNICHAR__ +#ifdef WIN32 +typedef wchar_t PRUnichar; +#else +typedef PRUint16 PRUnichar; +#endif +#endif + +/* +** WARNING: The undocumented data types PRWord and PRUword are +** only used in the garbage collection and arena code. Do not +** use PRWord and PRUword in new code. +** +** A PRWord is an integer that is the same size as a void*. +** It implements the notion of a "word" in the Java Virtual +** Machine. (See Sec. 3.4 "Words", The Java Virtual Machine +** Specification, Addison-Wesley, September 1996. +** http://java.sun.com/docs/books/vmspec/index.html.) +*/ +#ifdef _WIN64 +typedef PRInt64 PRWord; +typedef PRUint64 PRUword; +#else +typedef long PRWord; +typedef unsigned long PRUword; +#endif + +/* + * PR_PRETEND_NORETURN, specified at the end of a function declaration, + * indicates that for the purposes of static analysis, this function does not + * return. (The function definition does not need to be annotated.) + * + * void PR_Assert(const char *s, const char *file, PRIntn ln) + * PR_PRETEND_NORETURN; + * + * Some static analyzers, like scan-build from clang, can use this information + * to eliminate false positives. From the upstream documentation of + * scan-build: + * This attribute is useful for annotating assertion handlers that actually + * can return, but for the purpose of using the analyzer we want to pretend + * that such functions do not return. + */ +#ifdef __clang_analyzer__ +#if __has_extension(attribute_analyzer_noreturn) +#define PR_PRETEND_NORETURN __attribute__((analyzer_noreturn)) +#endif +#endif + +#ifndef PR_PRETEND_NORETURN +#define PR_PRETEND_NORETURN /* no support */ +#endif + +#if defined(NO_NSPR_10_SUPPORT) +#else +/********* ???????????????? FIX ME ??????????????????????????? *****/ +/********************** Some old definitions until pr=>ds transition is done ***/ +/********************** Also, we are still using NSPR 1.0. GC ******************/ +/* +** Fundamental NSPR macros, used nearly everywhere. +*/ + +#define PR_PUBLIC_API PR_IMPLEMENT + +/* +** Macro body brackets so that macros with compound statement definitions +** behave syntactically more like functions when called. +*/ +#define NSPR_BEGIN_MACRO do { +#define NSPR_END_MACRO } while (0) + +/* +** Macro shorthands for conditional C++ extern block delimiters. +*/ +#ifdef NSPR_BEGIN_EXTERN_C +#undef NSPR_BEGIN_EXTERN_C +#endif +#ifdef NSPR_END_EXTERN_C +#undef NSPR_END_EXTERN_C +#endif + +#ifdef __cplusplus +#define NSPR_BEGIN_EXTERN_C extern "C" { +#define NSPR_END_EXTERN_C } +#else +#define NSPR_BEGIN_EXTERN_C +#define NSPR_END_EXTERN_C +#endif + +#include "obsolete/protypes.h" + +/********* ????????????? End Fix me ?????????????????????????????? *****/ +#endif /* NO_NSPR_10_SUPPORT */ + +/* +** Compile-time assert. "condition" must be a constant expression. +** The macro can be used only in places where an "extern" declaration is +** allowed. +*/ +#define PR_STATIC_ASSERT(condition) \ + extern void pr_static_assert(int arg[(condition) ? 1 : -1]) + +PR_END_EXTERN_C + +#endif /* prtypes_h___ */ + Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prvrsion.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prvrsion.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prvrsion.h @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + + +/* author: jstewart */ + +#if defined(_PRVERSION_H) +#else +#define _PRVERSION_H + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* All components participating in the PR version protocol must expose + * a structure and a function. The structure is defined below and named + * according to the naming conventions outlined further below. The function + * is called libVersionPoint and returns a pointer to this structure. + */ + +/* on NT, always pack the structure the same. */ +#ifdef _WIN32 +#pragma pack(push, 8) +#endif + +typedef struct { + /* + * The first field defines which version of this structure is in use. + * At this time, only version 2 is specified. If this value is not + * 2, you must read no further into the structure. + */ + PRInt32 version; + + /* for Version 2, this is the body format. */ + PRInt64 buildTime; /* 64 bits - usecs since midnight, 1/1/1970 */ + char * buildTimeString;/* a human readable version of the time */ + + PRUint8 vMajor; /* Major version of this component */ + PRUint8 vMinor; /* Minor version of this component */ + PRUint8 vPatch; /* Patch level of this component */ + + PRBool beta; /* true if this is a beta component */ + PRBool debug; /* true if this is a debug component */ + PRBool special; /* true if this component is a special build */ + + char * filename; /* The original filename */ + char * description; /* description of this component */ + char * security; /* level of security in this component */ + char * copyright; /* The copyright for this file */ + char * comment; /* free form field for misc usage */ + char * specialString; /* the special variant for this build */ +} PRVersionDescription; + +/* on NT, restore the previous packing */ +#ifdef _WIN32 +#pragma pack(pop) +#endif + +/* + * All components must define an entrypoint named libVersionPoint which + * is of type versionEntryPointType. + * + * For example, for a library named libfoo, we would have: + * + * PRVersionDescription prVersionDescription_libfoo = + * { + * ... + * }; + * + * PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint(void) + * { + * return &prVersionDescription_libfoo; + * } + */ +typedef const PRVersionDescription *(*versionEntryPointType)(void); + +/* + * Where you declare your libVersionPoint, do it like this: + * PR_IMPLEMENT(const PRVersionDescription *) libVersionPoint(void) { + * fill it in... + * } + */ + +/* + * NAMING CONVENTION FOR struct + * + * all components should also expose a static PRVersionDescription + * The name of the struct should be calculated as follows: + * Take the value of filename. (If filename is not specified, calculate + * a short, unique string.) Convert all non-alphanumeric characters + * to '_'. To this, prepend "PRVersionDescription_". Thus for libfoo.so, + * the symbol name is "PRVersionDescription_libfoo_so". + * so the file should have + * PRVersionDescription PRVersionDescription_libfoo_so { fill it in }; + * on NT, this file should be declspec export. + */ + +PR_END_EXTERN_C + +#endif /* defined(_PRVERSION_H) */ + +/* prvrsion.h */ + Index: ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prwin16.h =================================================================== --- ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prwin16.h +++ ps/trunk/libraries/source/spidermonkey/include-win32-release/nspr/prwin16.h @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +#ifndef prwin16_h___ +#define prwin16_h___ + +/* +** Condition use of this header on platform. +*/ +#if (defined(XP_PC) && !defined(_WIN32) && !defined(XP_OS2) && defined(MOZILLA_CLIENT)) || defined(WIN16) +#include + +PR_BEGIN_EXTERN_C +/* +** Win16 stdio special case. +** To get stdio to work for Win16, all calls to printf() and related +** things must be called from the environment of the .EXE; calls to +** printf() from the .DLL send output to the bit-bucket. +** +** To make sure that PR_fprintf(), and related functions, work correctly, +** the actual stream I/O to stdout, stderr, stdin must be done in the +** .EXE. To do this, a hack is placed in _MD_Write() such that the +** fd for stdio handles results in a call to the .EXE. +** +** file w16stdio.c contains the functions that get called from NSPR +** to do the actual I/O. w16stdio.o must be statically linked with +** any application needing stdio for Win16. +** +** The address of these functions must be made available to the .DLL +** so he can call back to the .EXE. To do this, function +** PR_MD_RegisterW16StdioCallbacks() is called from the .EXE. +** The arguments are the functions defined in w16stdio.c +** At runtime, MD_Write() calls the registered functions, if any +** were registered. +** +** prinit.h contains a macro PR_STDIO_INIT() that calls the registration +** function for Win16; For other platforms, the macro is a No-Op. +** +** Note that stdio is not operational at all on Win16 GUI applications. +** This special case exists to provide stdio capability from the NSPR +** .DLL for command line applications only. NSPR's test cases are +** almost exclusively command line applications. +** +** See also: w16io.c, w16stdio.c +*/ +typedef PRInt32 (PR_CALLBACK *PRStdinRead)( void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRStdoutWrite)( void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRStderrWrite)( void *buf, PRInt32 amount); + +NSPR_API(PRStatus) +PR_MD_RegisterW16StdioCallbacks( + PRStdinRead inReadf, /* i: function pointer for stdin read */ + PRStdoutWrite outWritef, /* i: function pointer for stdout write */ + PRStderrWrite errWritef /* i: function pointer for stderr write */ + ); + +NSPR_API(PRInt32) +_PL_W16StdioWrite( void *buf, PRInt32 amount ); + +NSPR_API(PRInt32) +_PL_W16StdioRead( void *buf, PRInt32 amount ); + +#define PR_STDIO_INIT() PR_MD_RegisterW16StdioCallbacks( \ + _PL_W16StdioRead, _PL_W16StdioWrite, _PL_W16StdioWrite ); \ + PR_INIT_CALLBACKS(); + +/* +** Win16 hackery. +** +*/ +struct PRMethodCallbackStr { + int (PR_CALLBACK *auxOutput)(const char *outputString); + size_t (PR_CALLBACK *strftime)(char *s, size_t len, const char *fmt, const struct tm *p); + void * (PR_CALLBACK *malloc)( size_t size ); + void * (PR_CALLBACK *calloc)(size_t n, size_t size ); + void * (PR_CALLBACK *realloc)( void* old_blk, size_t size ); + void (PR_CALLBACK *free)( void *ptr ); + void * (PR_CALLBACK *getenv)( const char *name); + int (PR_CALLBACK *putenv)( const char *assoc); +/* void * (PR_CALLBACK *perror)( const char *prefix ); */ +}; + +NSPR_API(void) PR_MDRegisterCallbacks(struct PRMethodCallbackStr *); + +int PR_CALLBACK _PL_W16CallBackPuts( const char *outputString ); +size_t PR_CALLBACK _PL_W16CallBackStrftime( + char *s, + size_t len, + const char *fmt, + const struct tm *p ); +void * PR_CALLBACK _PL_W16CallBackMalloc( size_t size ); +void * PR_CALLBACK _PL_W16CallBackCalloc( size_t n, size_t size ); +void * PR_CALLBACK _PL_W16CallBackRealloc( + void *old_blk, + size_t size ); +void PR_CALLBACK _PL_W16CallBackFree( void *ptr ); +void * PR_CALLBACK _PL_W16CallBackGetenv( const char *name ); +int PR_CALLBACK _PL_W16CallBackPutenv( const char *assoc ); + +/* +** Hackery! +** +** These functions are provided as static link points. +** This is to satisfy the quick port of Gromit to NSPR 2.0 +** ... Don't do this! ... alas, It may never go away. +** +*/ +NSPR_API(int) PR_MD_printf(const char *, ...); +NSPR_API(void) PR_MD_exit(int); +NSPR_API(size_t) PR_MD_strftime(char *, size_t, const char *, const struct tm *); +NSPR_API(int) PR_MD_sscanf(const char *, const char *, ...); +NSPR_API(void*) PR_MD_malloc( size_t size ); +NSPR_API(void*) PR_MD_calloc( size_t n, size_t size ); +NSPR_API(void*) PR_MD_realloc( void* old_blk, size_t size ); +NSPR_API(void) PR_MD_free( void *ptr ); +NSPR_API(char*) PR_MD_getenv( const char *name ); +NSPR_API(int) PR_MD_putenv( const char *assoc ); +NSPR_API(int) PR_MD_fprintf(FILE *fPtr, const char *fmt, ...); + +#define PR_INIT_CALLBACKS() \ + { \ + static struct PRMethodCallbackStr cbf = { \ + _PL_W16CallBackPuts, \ + _PL_W16CallBackStrftime, \ + _PL_W16CallBackMalloc, \ + _PL_W16CallBackCalloc, \ + _PL_W16CallBackRealloc, \ + _PL_W16CallBackFree, \ + _PL_W16CallBackGetenv, \ + _PL_W16CallBackPutenv, \ + }; \ + PR_MDRegisterCallbacks( &cbf ); \ + } + + +/* +** Get the exception context for Win16 MFC applications threads +*/ +NSPR_API(void *) PR_W16GetExceptionContext(void); +/* +** Set the exception context for Win16 MFC applications threads +*/ +NSPR_API(void) PR_W16SetExceptionContext(void *context); + +PR_END_EXTERN_C +#else +/* +** For platforms other than Win16, define +** PR_STDIO_INIT() as a No-Op. +*/ +#define PR_STDIO_INIT() +#endif /* WIN16 || MOZILLA_CLIENT */ + +#endif /* prwin16_h___ */ + + + + + + + + Index: ps/trunk/libraries/source/spidermonkey/patch.sh =================================================================== --- ps/trunk/libraries/source/spidermonkey/patch.sh +++ ps/trunk/libraries/source/spidermonkey/patch.sh @@ -1,31 +1,15 @@ #!/bin/sh # Apply patches if needed -# This script gets called from build-osx-libs.sh and build.sh. +# This script gets called from build.sh. -# 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 - -# 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. +# Mozglue symbols need to be linked against static builds. # 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 - +# Fix ~SharedArrayRawBufferRefs symbol not found. +# See https://bugzilla.mozilla.org/show_bug.cgi?id=1644600 +# Many thanks to bellaz89 for finding this and reporting it +patch -p1 < ../FixSharedArray.diff Index: ps/trunk/source/scriptinterface/ScriptTypes.h =================================================================== --- ps/trunk/source/scriptinterface/ScriptTypes.h +++ ps/trunk/source/scriptinterface/ScriptTypes.h @@ -73,7 +73,7 @@ # pragma GCC diagnostic pop #endif -#if MOZJS_MAJOR_VERSION != 52 +#if MOZJS_MAJOR_VERSION != 60 #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 \