This commit is contained in:
2youyou2 2017-09-28 11:09:34 +08:00
commit db67f9b324
1437 changed files with 339350 additions and 100467 deletions

View File

@ -99,6 +99,14 @@ include $(PREBUILT_STATIC_LIBRARY)
#======================================
include $(CLEAR_VARS)
LOCAL_MODULE := cocos_mozglue_static
LOCAL_MODULE_FILENAME := mozglue
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libmozglue.a
include $(PREBUILT_STATIC_LIBRARY)
#======================================
include $(CLEAR_VARS)
LOCAL_MODULE := spidermonkey_static
LOCAL_MODULE_FILENAME := js_static
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libjs_static.a
@ -106,7 +114,7 @@ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/$(TARGET_ARCH_ABI)/include/spidermonkey
LOCAL_CPPFLAGS := -D__STDC_LIMIT_MACROS=1 -Wno-invalid-offsetof
LOCAL_EXPORT_CPPFLAGS := -D__STDC_LIMIT_MACROS=1 -Wno-invalid-offsetof
LOCAL_STATIC_LIBRARIES += cocos_mozglue_static
include $(PREBUILT_STATIC_LIBRARY)
#======================================

View File

@ -0,0 +1,65 @@
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/*
* from: @(#)fdlibm.h 5.1 93/09/24
* $FreeBSD$
*/
#ifndef mozilla_imported_fdlibm_h
#define mozilla_imported_fdlibm_h
namespace fdlibm {
double acos(double);
double asin(double);
double atan(double);
double atan2(double, double);
double cosh(double);
double sinh(double);
double tanh(double);
double exp(double);
double log(double);
double log10(double);
double pow(double, double);
double sqrt(double);
double fabs(double);
double floor(double);
double trunc(double);
double ceil(double);
double acosh(double);
double asinh(double);
double atanh(double);
double cbrt(double);
double expm1(double);
double hypot(double, double);
double log1p(double);
double log2(double);
double rint(double);
double copysign(double, double);
double nearbyint(double);
double scalbn(double, int);
float ceilf(float);
float floorf(float);
float nearbyintf(float);
float rintf(float);
float truncf(float);
} /* namespace fdlibm */
#endif /* mozilla_imported_fdlibm_h */

32
android/arm64-v8a/include/spidermonkey/js-config.h Executable file → Normal file
View File

@ -15,6 +15,20 @@
/* Define to 1 if SpiderMonkey is in debug mode. */
/* #undef JS_DEBUG */
/*
* NB: We have a special case for rust-bindgen, which wants to be able to
* generate both debug and release bindings on a single objdir.
*/
#ifdef JS_DEBUG
#if !defined(DEBUG) && !defined(RUST_BINDGEN)
# error "SpiderMonkey was configured with --enable-debug, so DEBUG must be defined when including this header"
# endif
#else
# if defined(DEBUG) && !defined(RUST_BINDGEN)
# error "SpiderMonkey was configured with --disable-debug, so DEBUG must be not defined when including this header"
# endif
#endif
/* Define to 1 if SpiderMonkey should not use struct types in debug builds. */
/* #undef JS_NO_JSVAL_JSID_STRUCT_TYPES */
@ -28,17 +42,11 @@
entirely too much GC. */
/* #undef JS_GC_ZEAL */
/* Define to 1 if the <endian.h> header is present and
useable. See jscpucfg.h. */
#define JS_HAVE_ENDIAN_H 1
/* Define to 1 if SpiderMonkey should use small chunks. */
/* #undef JS_GC_SMALL_CHUNK_SIZE */
/* Define to 1 if the <machine/endian.h> header is present and
useable. See jscpucfg.h. */
#define JS_HAVE_MACHINE_ENDIAN_H 1
/* Define to 1 if the <sys/isa_defs.h> header is present and
useable. See jscpucfg.h. */
/* #undef JS_HAVE_SYS_ISA_DEFS_H */
/* Define to 1 to perform extra assertions and heap poisoning. */
/* #undef JS_CRASH_DIAGNOSTICS */
/* Define to 1 if SpiderMonkey is in NUNBOX32 mode. */
/* #undef JS_NUNBOX32 */
@ -47,7 +55,7 @@
#define JS_PUNBOX64 1
/* MOZILLA JSAPI version number components */
#define MOZJS_MAJOR_VERSION 33
#define MOZJS_MINOR_VERSION 1
#define MOZJS_MAJOR_VERSION 52
#define MOZJS_MINOR_VERSION 0
#endif /* js_config_h */

942
android/arm64-v8a/include/spidermonkey/js.msg Executable file → Normal file
View File

@ -9,15 +9,13 @@
*
* The format for each JS error message is:
*
* MSG_DEF(<SYMBOLIC_NAME>, <ERROR_NUMBER>, <ARGUMENT_COUNT>, <EXCEPTION_NAME>,
* MSG_DEF(<SYMBOLIC_NAME>, <ARGUMENT_COUNT>, <EXCEPTION_NAME>,
* <FORMAT_STRING>)
*
* where ;
* <SYMBOLIC_NAME> is a legal C identifer that will be used in the
* JS engine source.
*
* <ERROR_NUMBER> is an unique integral value identifying this error.
*
* <ARGUMENT_COUNT> is an integer literal specifying the total number of
* replaceable arguments in the following format string.
*
@ -31,413 +29,553 @@
*
* e.g.
*
* MSG_DEF(JSMSG_NOT_A_SUBSPECIES, 73, JSEXN_NONE, 2,
* MSG_DEF(JSMSG_NOT_A_SUBSPECIES, 2, JSEXN_NONE,
* "{0} is not a member of the {1} family")
*
* can be used:
*
* JS_ReportErrorNumber(JSMSG_NOT_A_SUBSPECIES, "Rhino", "Monkey");
* JS_ReportErrorNumberASCII(JSMSG_NOT_A_SUBSPECIES, "Rhino", "Monkey");
*
* to report:
*
* "Rhino is not a member of the Monkey family"
*
* When removing MSG_DEFs, convert them to JSMSG_UNUSED<n> placeholders:
*
* MSG_DEF(JSMSG_UNUSED7, 7, 0, JSEXN_NONE, "")
*
* Before adding a new MSG_DEF at the end, look for existing JSMSG_UNUSED<n>
* free index placeholders in the middle of the list.
*/
MSG_DEF(JSMSG_NOT_AN_ERROR, 0, 0, JSEXN_NONE, "<Error #0 is reserved>")
MSG_DEF(JSMSG_NOT_DEFINED, 1, 1, JSEXN_REFERENCEERR, "{0} is not defined")
MSG_DEF(JSMSG_INACTIVE, 2, 0, JSEXN_INTERNALERR, "nothing active on context")
MSG_DEF(JSMSG_MORE_ARGS_NEEDED, 3, 3, JSEXN_TYPEERR, "{0} requires more than {1} argument{2}")
MSG_DEF(JSMSG_BAD_CHAR, 4, 1, JSEXN_INTERNALERR, "invalid format character {0}")
MSG_DEF(JSMSG_BAD_TYPE, 5, 1, JSEXN_TYPEERR, "unknown type {0}")
MSG_DEF(JSMSG_ALLOC_OVERFLOW, 6, 0, JSEXN_INTERNALERR, "allocation size overflow")
MSG_DEF(JSMSG_MISSING_HEXDIGITS, 7, 0, JSEXN_SYNTAXERR, "missing hexadecimal digits after '0x'")
MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 8, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}")
MSG_DEF(JSMSG_NO_CONSTRUCTOR, 9, 1, JSEXN_TYPEERR, "{0} has no constructor")
MSG_DEF(JSMSG_CANT_ALIAS, 10, 3, JSEXN_TYPEERR, "can't alias {0} to {1} in class {2}")
MSG_DEF(JSMSG_NOT_SCRIPTED_FUNCTION, 11, 1, JSEXN_TYPEERR, "{0} is not a scripted function")
MSG_DEF(JSMSG_BAD_SORT_ARG, 12, 0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument")
MSG_DEF(JSMSG_BAD_ATOMIC_NUMBER, 13, 1, JSEXN_INTERNALERR, "internal error: no index for atom {0}")
MSG_DEF(JSMSG_TOO_MANY_LITERALS, 14, 0, JSEXN_INTERNALERR, "too many literals")
MSG_DEF(JSMSG_CANT_WATCH, 15, 1, JSEXN_TYPEERR, "can't watch non-native objects of class {0}")
MSG_DEF(JSMSG_STACK_UNDERFLOW, 16, 2, JSEXN_INTERNALERR, "internal error compiling {0}: stack underflow at pc {1}")
MSG_DEF(JSMSG_NEED_DIET, 17, 1, JSEXN_INTERNALERR, "{0} too large")
MSG_DEF(JSMSG_TOO_MANY_LOCAL_ROOTS, 18, 0, JSEXN_ERR, "out of local root space")
MSG_DEF(JSMSG_READ_ONLY, 19, 1, JSEXN_TYPEERR, "{0} is read-only")
MSG_DEF(JSMSG_BAD_FORMAL, 20, 0, JSEXN_SYNTAXERR, "malformed formal parameter")
MSG_DEF(JSMSG_CANT_DELETE, 21, 1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted")
MSG_DEF(JSMSG_NOT_FUNCTION, 22, 1, JSEXN_TYPEERR, "{0} is not a function")
MSG_DEF(JSMSG_NOT_CONSTRUCTOR, 23, 1, JSEXN_TYPEERR, "{0} is not a constructor")
MSG_DEF(JSMSG_INVALID_DATE, 24, 0, JSEXN_RANGEERR, "invalid date")
MSG_DEF(JSMSG_TOO_DEEP, 25, 1, JSEXN_INTERNALERR, "{0} nested too deeply")
MSG_DEF(JSMSG_OVER_RECURSED, 26, 0, JSEXN_INTERNALERR, "too much recursion")
MSG_DEF(JSMSG_IN_NOT_OBJECT, 27, 1, JSEXN_TYPEERR, "invalid 'in' operand {0}")
MSG_DEF(JSMSG_BAD_NEW_RESULT, 28, 1, JSEXN_TYPEERR, "invalid new expression result {0}")
MSG_DEF(JSMSG_OBJECT_ACCESS_DENIED, 29, 0, JSEXN_ERR, "Permission denied to access object")
MSG_DEF(JSMSG_PROPERTY_ACCESS_DENIED, 30, 1, JSEXN_ERR, "Permission denied to access property '{0}'")
MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS, 31, 1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}")
MSG_DEF(JSMSG_BAD_BYTECODE, 32, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}")
MSG_DEF(JSMSG_BAD_RADIX, 33, 0, JSEXN_RANGEERR, "radix must be an integer at least 2 and no greater than 36")
MSG_DEF(JSMSG_PAREN_BEFORE_LET, 34, 0, JSEXN_SYNTAXERR, "missing ( before let head")
MSG_DEF(JSMSG_CANT_CONVERT, 35, 1, JSEXN_ERR, "can't convert {0} to an integer")
MSG_DEF(JSMSG_CYCLIC_VALUE, 36, 1, JSEXN_TYPEERR, "cyclic {0} value")
MSG_DEF(JSMSG_COMPILE_EXECED_SCRIPT, 37, 0, JSEXN_TYPEERR, "can't compile over a script that is currently executing")
MSG_DEF(JSMSG_CANT_CONVERT_TO, 38, 2, JSEXN_TYPEERR, "can't convert {0} to {1}")
MSG_DEF(JSMSG_NO_PROPERTIES, 39, 1, JSEXN_TYPEERR, "{0} has no properties")
MSG_DEF(JSMSG_CANT_FIND_CLASS, 40, 1, JSEXN_TYPEERR, "can't find class id {0}")
MSG_DEF(JSMSG_DEAD_OBJECT, 41, 0, JSEXN_TYPEERR, "can't access dead object")
MSG_DEF(JSMSG_BYTECODE_TOO_BIG, 42, 2, JSEXN_INTERNALERR, "bytecode {0} too large (limit {1})")
MSG_DEF(JSMSG_UNKNOWN_FORMAT, 43, 1, JSEXN_INTERNALERR, "unknown bytecode format {0}")
MSG_DEF(JSMSG_TOO_MANY_CON_ARGS, 44, 0, JSEXN_SYNTAXERR, "too many constructor arguments")
MSG_DEF(JSMSG_TOO_MANY_FUN_ARGS, 45, 0, JSEXN_SYNTAXERR, "too many function arguments")
MSG_DEF(JSMSG_BAD_QUANTIFIER, 46, 0, JSEXN_SYNTAXERR, "invalid quantifier")
MSG_DEF(JSMSG_MIN_TOO_BIG, 47, 1, JSEXN_SYNTAXERR, "overlarge minimum {0}")
MSG_DEF(JSMSG_MAX_TOO_BIG, 48, 1, JSEXN_SYNTAXERR, "overlarge maximum {0}")
MSG_DEF(JSMSG_OUT_OF_ORDER, 49, 1, JSEXN_SYNTAXERR, "maximum {0} less than minimum")
MSG_DEF(JSMSG_BAD_DESTRUCT_DECL, 50, 0, JSEXN_SYNTAXERR, "missing = in destructuring declaration")
MSG_DEF(JSMSG_BAD_DESTRUCT_ASS, 51, 0, JSEXN_REFERENCEERR, "invalid destructuring assignment operator")
MSG_DEF(JSMSG_PAREN_AFTER_LET, 52, 0, JSEXN_SYNTAXERR, "missing ) after let head")
MSG_DEF(JSMSG_CURLY_AFTER_LET, 53, 0, JSEXN_SYNTAXERR, "missing } after let block")
MSG_DEF(JSMSG_MISSING_PAREN, 54, 0, JSEXN_SYNTAXERR, "unterminated parenthetical")
MSG_DEF(JSMSG_UNTERM_CLASS, 55, 0, JSEXN_SYNTAXERR, "unterminated character class")
MSG_DEF(JSMSG_TRAILING_SLASH, 56, 0, JSEXN_SYNTAXERR, "trailing \\ in regular expression")
MSG_DEF(JSMSG_BAD_CLASS_RANGE, 57, 0, JSEXN_SYNTAXERR, "invalid range in character class")
MSG_DEF(JSMSG_BAD_REGEXP_FLAG, 58, 1, JSEXN_SYNTAXERR, "invalid regular expression flag {0}")
MSG_DEF(JSMSG_NO_INPUT, 59, 5, JSEXN_SYNTAXERR, "no input for /{0}/{1}{2}{3}{4}")
MSG_DEF(JSMSG_CANT_OPEN, 60, 2, JSEXN_ERR, "can't open {0}: {1}")
MSG_DEF(JSMSG_TOO_MANY_FUN_APPLY_ARGS, 61, 0, JSEXN_RANGEERR, "arguments array passed to Function.prototype.apply is too large")
MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 62, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression")
MSG_DEF(JSMSG_TOO_BIG_TO_ENCODE, 63, 0, JSEXN_INTERNALERR, "data are to big to encode")
MSG_DEF(JSMSG_ARG_INDEX_OUT_OF_RANGE, 64, 1, JSEXN_RANGEERR, "argument {0} accesses an index that is out of range")
MSG_DEF(JSMSG_SPREAD_TOO_LARGE, 65, 0, JSEXN_RANGEERR, "array too large due to spread operand(s)")
MSG_DEF(JSMSG_SOURCE_TOO_LONG, 66, 0, JSEXN_RANGEERR, "source is too long")
MSG_DEF(JSMSG_BAD_WEAKMAP_KEY, 67, 0, JSEXN_TYPEERR, "cannot use the given object as a weak map key")
MSG_DEF(JSMSG_BAD_SCRIPT_MAGIC, 68, 0, JSEXN_INTERNALERR, "bad script XDR magic number")
MSG_DEF(JSMSG_PAREN_BEFORE_FORMAL, 69, 0, JSEXN_SYNTAXERR, "missing ( before formal parameters")
MSG_DEF(JSMSG_MISSING_FORMAL, 70, 0, JSEXN_SYNTAXERR, "missing formal parameter")
MSG_DEF(JSMSG_PAREN_AFTER_FORMAL, 71, 0, JSEXN_SYNTAXERR, "missing ) after formal parameters")
MSG_DEF(JSMSG_CURLY_BEFORE_BODY, 72, 0, JSEXN_SYNTAXERR, "missing { before function body")
MSG_DEF(JSMSG_CURLY_AFTER_BODY, 73, 0, JSEXN_SYNTAXERR, "missing } after function body")
MSG_DEF(JSMSG_PAREN_BEFORE_COND, 74, 0, JSEXN_SYNTAXERR, "missing ( before condition")
MSG_DEF(JSMSG_PAREN_AFTER_COND, 75, 0, JSEXN_SYNTAXERR, "missing ) after condition")
MSG_DEF(JSMSG_BAD_DUP_ARGS, 76, 0, JSEXN_SYNTAXERR, "duplicate argument names not allowed in this context")
MSG_DEF(JSMSG_NAME_AFTER_DOT, 77, 0, JSEXN_SYNTAXERR, "missing name after . operator")
MSG_DEF(JSMSG_BRACKET_IN_INDEX, 78, 0, JSEXN_SYNTAXERR, "missing ] in index expression")
MSG_DEF(JSMSG_ACCESSOR_DEF_DENIED, 79, 1, JSEXN_ERR, "Permission denied to define accessor property '{0}'")
MSG_DEF(JSMSG_PAREN_BEFORE_SWITCH, 80, 0, JSEXN_SYNTAXERR, "missing ( before switch expression")
MSG_DEF(JSMSG_PAREN_AFTER_SWITCH, 81, 0, JSEXN_SYNTAXERR, "missing ) after switch expression")
MSG_DEF(JSMSG_CURLY_BEFORE_SWITCH, 82, 0, JSEXN_SYNTAXERR, "missing { before switch body")
MSG_DEF(JSMSG_COLON_AFTER_CASE, 83, 0, JSEXN_SYNTAXERR, "missing : after case label")
MSG_DEF(JSMSG_WHILE_AFTER_DO, 84, 0, JSEXN_SYNTAXERR, "missing while after do-loop body")
MSG_DEF(JSMSG_PAREN_AFTER_FOR, 85, 0, JSEXN_SYNTAXERR, "missing ( after for")
MSG_DEF(JSMSG_SEMI_AFTER_FOR_INIT, 86, 0, JSEXN_SYNTAXERR, "missing ; after for-loop initializer")
MSG_DEF(JSMSG_SEMI_AFTER_FOR_COND, 87, 0, JSEXN_SYNTAXERR, "missing ; after for-loop condition")
MSG_DEF(JSMSG_PAREN_AFTER_FOR_CTRL, 88, 0, JSEXN_SYNTAXERR, "missing ) after for-loop control")
MSG_DEF(JSMSG_CURLY_BEFORE_TRY, 89, 0, JSEXN_SYNTAXERR, "missing { before try block")
MSG_DEF(JSMSG_CURLY_AFTER_TRY, 90, 0, JSEXN_SYNTAXERR, "missing } after try block")
MSG_DEF(JSMSG_PAREN_BEFORE_CATCH, 91, 0, JSEXN_SYNTAXERR, "missing ( before catch")
MSG_DEF(JSMSG_CATCH_IDENTIFIER, 92, 0, JSEXN_SYNTAXERR, "missing identifier in catch")
MSG_DEF(JSMSG_PAREN_AFTER_CATCH, 93, 0, JSEXN_SYNTAXERR, "missing ) after catch")
MSG_DEF(JSMSG_CURLY_BEFORE_CATCH, 94, 0, JSEXN_SYNTAXERR, "missing { before catch block")
MSG_DEF(JSMSG_CURLY_AFTER_CATCH, 95, 0, JSEXN_SYNTAXERR, "missing } after catch block")
MSG_DEF(JSMSG_CURLY_BEFORE_FINALLY, 96, 0, JSEXN_SYNTAXERR, "missing { before finally block")
MSG_DEF(JSMSG_CURLY_AFTER_FINALLY, 97, 0, JSEXN_SYNTAXERR, "missing } after finally block")
MSG_DEF(JSMSG_CATCH_OR_FINALLY, 98, 0, JSEXN_SYNTAXERR, "missing catch or finally after try")
MSG_DEF(JSMSG_PAREN_BEFORE_WITH, 99, 0, JSEXN_SYNTAXERR, "missing ( before with-statement object")
MSG_DEF(JSMSG_PAREN_AFTER_WITH, 100, 0, JSEXN_SYNTAXERR, "missing ) after with-statement object")
MSG_DEF(JSMSG_CURLY_IN_COMPOUND, 101, 0, JSEXN_SYNTAXERR, "missing } in compound statement")
MSG_DEF(JSMSG_NO_VARIABLE_NAME, 102, 0, JSEXN_SYNTAXERR, "missing variable name")
MSG_DEF(JSMSG_COLON_IN_COND, 103, 0, JSEXN_SYNTAXERR, "missing : in conditional expression")
MSG_DEF(JSMSG_PAREN_AFTER_ARGS, 104, 0, JSEXN_SYNTAXERR, "missing ) after argument list")
MSG_DEF(JSMSG_BRACKET_AFTER_LIST, 105, 0, JSEXN_SYNTAXERR, "missing ] after element list")
MSG_DEF(JSMSG_COLON_AFTER_ID, 106, 0, JSEXN_SYNTAXERR, "missing : after property id")
MSG_DEF(JSMSG_CURLY_AFTER_LIST, 107, 0, JSEXN_SYNTAXERR, "missing } after property list")
MSG_DEF(JSMSG_PAREN_IN_PAREN, 108, 0, JSEXN_SYNTAXERR, "missing ) in parenthetical")
MSG_DEF(JSMSG_SEMI_BEFORE_STMNT, 109, 0, JSEXN_SYNTAXERR, "missing ; before statement")
MSG_DEF(JSMSG_NO_RETURN_VALUE, 110, 1, JSEXN_TYPEERR, "function {0} does not always return a value")
MSG_DEF(JSMSG_DUPLICATE_FORMAL, 111, 1, JSEXN_SYNTAXERR, "duplicate formal argument {0}")
MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 112, 0, JSEXN_SYNTAXERR, "test for equality (==) mistyped as assignment (=)?")
MSG_DEF(JSMSG_OPTIMIZED_CLOSURE_LEAK, 113, 0, JSEXN_INTERNALERR, "can't access optimized closure")
MSG_DEF(JSMSG_TOO_MANY_DEFAULTS, 114, 0, JSEXN_SYNTAXERR, "more than one switch default")
MSG_DEF(JSMSG_TOO_MANY_CASES, 115, 0, JSEXN_INTERNALERR, "too many switch cases")
MSG_DEF(JSMSG_BAD_SWITCH, 116, 0, JSEXN_SYNTAXERR, "invalid switch statement")
MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 117, 0, JSEXN_SYNTAXERR, "invalid for/in left-hand side")
MSG_DEF(JSMSG_CATCH_AFTER_GENERAL, 118, 0, JSEXN_SYNTAXERR, "catch after unconditional catch")
MSG_DEF(JSMSG_CATCH_WITHOUT_TRY, 119, 0, JSEXN_SYNTAXERR, "catch without try")
MSG_DEF(JSMSG_FINALLY_WITHOUT_TRY, 120, 0, JSEXN_SYNTAXERR, "finally without try")
MSG_DEF(JSMSG_LABEL_NOT_FOUND, 121, 0, JSEXN_SYNTAXERR, "label not found")
MSG_DEF(JSMSG_TOUGH_BREAK, 122, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch")
MSG_DEF(JSMSG_BAD_CONTINUE, 123, 0, JSEXN_SYNTAXERR, "continue must be inside loop")
MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 124, 1, JSEXN_SYNTAXERR, "{0} not in function")
MSG_DEF(JSMSG_BAD_LABEL, 125, 0, JSEXN_SYNTAXERR, "invalid label")
MSG_DEF(JSMSG_DUPLICATE_LABEL, 126, 0, JSEXN_SYNTAXERR, "duplicate label")
MSG_DEF(JSMSG_VAR_HIDES_ARG, 127, 1, JSEXN_TYPEERR, "variable {0} redeclares argument")
MSG_DEF(JSMSG_BAD_VAR_INIT, 128, 0, JSEXN_SYNTAXERR, "invalid variable initialization")
MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS, 129, 0, JSEXN_REFERENCEERR, "invalid assignment left-hand side")
MSG_DEF(JSMSG_BAD_OPERAND, 130, 1, JSEXN_SYNTAXERR, "invalid {0} operand")
MSG_DEF(JSMSG_BAD_PROP_ID, 131, 0, JSEXN_SYNTAXERR, "invalid property id")
MSG_DEF(JSMSG_RESERVED_ID, 132, 1, JSEXN_SYNTAXERR, "{0} is a reserved identifier")
MSG_DEF(JSMSG_SYNTAX_ERROR, 133, 0, JSEXN_SYNTAXERR, "syntax error")
MSG_DEF(JSMSG_MISSING_BINARY_DIGITS, 134, 0, JSEXN_SYNTAXERR, "missing binary digits after '0b'")
MSG_DEF(JSMSG_BAD_PROTOTYPE, 135, 1, JSEXN_TYPEERR, "'prototype' property of {0} is not an object")
MSG_DEF(JSMSG_MISSING_EXPONENT, 136, 0, JSEXN_SYNTAXERR, "missing exponent")
MSG_DEF(JSMSG_OUT_OF_MEMORY, 137, 0, JSEXN_ERR, "out of memory")
MSG_DEF(JSMSG_UNTERMINATED_STRING, 138, 0, JSEXN_SYNTAXERR, "unterminated string literal")
MSG_DEF(JSMSG_TOO_MANY_PARENS, 139, 0, JSEXN_INTERNALERR, "too many parentheses in regular expression")
MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 140, 0, JSEXN_SYNTAXERR, "unterminated comment")
MSG_DEF(JSMSG_UNTERMINATED_REGEXP, 141, 0, JSEXN_SYNTAXERR, "unterminated regular expression literal")
MSG_DEF(JSMSG_BAD_CLONE_FUNOBJ_SCOPE, 142, 0, JSEXN_TYPEERR, "bad cloned function scope chain")
MSG_DEF(JSMSG_MISSING_OCTAL_DIGITS, 143, 0, JSEXN_SYNTAXERR, "missing octal digits after '0o'")
MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 144, 0, JSEXN_SYNTAXERR, "illegal character")
MSG_DEF(JSMSG_BAD_OCTAL, 145, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant")
MSG_DEF(JSMSG_RESULTING_STRING_TOO_LARGE, 146, 0, JSEXN_RANGEERR, "repeat count must be less than infinity and not overflow maximum string size")
MSG_DEF(JSMSG_UNCAUGHT_EXCEPTION, 147, 1, JSEXN_INTERNALERR, "uncaught exception: {0}")
MSG_DEF(JSMSG_INVALID_BACKREF, 148, 0, JSEXN_SYNTAXERR, "non-octal digit in an escape sequence that doesn't match a back-reference")
MSG_DEF(JSMSG_BAD_BACKREF, 149, 0, JSEXN_SYNTAXERR, "back-reference exceeds number of capturing parentheses")
MSG_DEF(JSMSG_PRECISION_RANGE, 150, 1, JSEXN_RANGEERR, "precision {0} out of range")
MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER, 151, 1, JSEXN_TYPEERR, "invalid {0} usage")
MSG_DEF(JSMSG_BAD_ARRAY_LENGTH, 152, 0, JSEXN_RANGEERR, "invalid array length")
MSG_DEF(JSMSG_CANT_DESCRIBE_PROPS, 153, 1, JSEXN_TYPEERR, "can't describe non-native properties of class {0}")
MSG_DEF(JSMSG_BAD_APPLY_ARGS, 154, 1, JSEXN_TYPEERR, "second argument to Function.prototype.{0} must be an array")
MSG_DEF(JSMSG_REDECLARED_VAR, 155, 2, JSEXN_TYPEERR, "redeclaration of {0} {1}")
MSG_DEF(JSMSG_UNDECLARED_VAR, 156, 1, JSEXN_REFERENCEERR, "assignment to undeclared variable {0}")
MSG_DEF(JSMSG_ANON_NO_RETURN_VALUE, 157, 0, JSEXN_TYPEERR, "anonymous function does not always return a value")
MSG_DEF(JSMSG_DEPRECATED_USAGE, 158, 1, JSEXN_REFERENCEERR, "deprecated {0} usage")
MSG_DEF(JSMSG_BAD_URI, 159, 0, JSEXN_URIERR, "malformed URI sequence")
MSG_DEF(JSMSG_GETTER_ONLY, 160, 0, JSEXN_TYPEERR, "setting a property that has only a getter")
MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER, 161, 0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal")
MSG_DEF(JSMSG_UNDEFINED_PROP, 162, 1, JSEXN_REFERENCEERR, "reference to undefined property {0}")
MSG_DEF(JSMSG_USELESS_EXPR, 163, 0, JSEXN_TYPEERR, "useless expression")
MSG_DEF(JSMSG_REDECLARED_PARAM, 164, 1, JSEXN_TYPEERR, "redeclaration of formal parameter {0}")
MSG_DEF(JSMSG_NEWREGEXP_FLAGGED, 165, 0, JSEXN_TYPEERR, "can't supply flags when constructing one RegExp from another")
MSG_DEF(JSMSG_RESERVED_SLOT_RANGE, 166, 0, JSEXN_RANGEERR, "reserved slot index out of range")
MSG_DEF(JSMSG_CANT_DECODE_PRINCIPALS, 167, 0, JSEXN_INTERNALERR, "can't decode JSPrincipals")
MSG_DEF(JSMSG_CANT_SEAL_OBJECT, 168, 1, JSEXN_ERR, "can't seal {0} objects")
MSG_DEF(JSMSG_TOO_MANY_CATCH_VARS, 169, 0, JSEXN_SYNTAXERR, "too many catch variables")
MSG_DEF(JSMSG_NEGATIVE_REPETITION_COUNT, 170, 0, JSEXN_RANGEERR, "repeat count must be non-negative")
MSG_DEF(JSMSG_INVALID_FOR_OF_INIT, 171, 0, JSEXN_SYNTAXERR, "for-of loop variable declaration may not have an initializer")
MSG_DEF(JSMSG_INVALID_MAP_ITERABLE, 172, 0, JSEXN_TYPEERR, "iterable for map should have array-like objects")
MSG_DEF(JSMSG_NOT_A_CODEPOINT, 173, 1, JSEXN_RANGEERR, "{0} is not a valid code point")
MSG_DEF(JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION, 174, 0, JSEXN_SYNTAXERR, "missing ] after array comprehension")
MSG_DEF(JSMSG_NESTING_GENERATOR, 175, 0, JSEXN_TYPEERR, "already executing generator")
MSG_DEF(JSMSG_PAREN_AFTER_FOR_OF_ITERABLE, 176, 0, JSEXN_SYNTAXERR, "missing ) after for-of iterable")
MSG_DEF(JSMSG_INVALID_NORMALIZE_FORM, 177, 0, JSEXN_RANGEERR, "form must be one of 'NFC', 'NFD', 'NFKC', or 'NFKD'")
MSG_DEF(JSMSG_NOTHING_TO_REPEAT, 178, 0, JSEXN_SYNTAXERR, "nothing to repeat")
MSG_DEF(JSMSG_INVALID_GROUP, 179, 0, JSEXN_SYNTAXERR, "invalid regexp group")
MSG_DEF(JSMSG_ESCAPE_AT_END_OF_REGEXP, 180, 0, JSEXN_SYNTAXERR, "\\ at end of pattern")
MSG_DEF(JSMSG_NUMBERS_OUT_OF_ORDER, 181, 0, JSEXN_SYNTAXERR, "numbers out of order in {} quantifier.")
MSG_DEF(JSMSG_BAD_GENERATOR_SEND, 182, 1, JSEXN_TYPEERR, "attempt to send {0} to newborn generator")
MSG_DEF(JSMSG_SC_NOT_TRANSFERABLE, 183, 0, JSEXN_TYPEERR, "invalid transferable array for structured clone")
MSG_DEF(JSMSG_SC_DUP_TRANSFERABLE, 184, 0, JSEXN_TYPEERR, "duplicate transferable for structured clone")
MSG_DEF(JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE, 185, 0, JSEXN_TYPEERR, "proxy can't report an extensible object as non-extensible")
MSG_DEF(JSMSG_SYMBOL_TO_STRING, 186, 0, JSEXN_TYPEERR, "can't convert symbol to string")
MSG_DEF(JSMSG_UNUSED187, 187, 0, JSEXN_NONE, "")
MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 188, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}")
MSG_DEF(JSMSG_SYMBOL_TO_PRIMITIVE, 189, 0, JSEXN_TYPEERR, "can't convert symbol object to primitive")
MSG_DEF(JSMSG_UNUSED190, 190, 0, JSEXN_NONE, "")
MSG_DEF(JSMSG_BAD_INDEX, 191, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
MSG_DEF(JSMSG_SELFHOSTED_TOP_LEVEL_LET,192,0, JSEXN_SYNTAXERR, "self-hosted code cannot contain top-level 'let' declarations")
MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 193, 0, JSEXN_SYNTAXERR, "invalid for each loop")
MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED,194, 0, JSEXN_NONE, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead")
MSG_DEF(JSMSG_TYPE_ERR_BAD_ARGS, 195, 0, JSEXN_TYPEERR, "invalid arguments")
MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 196, 1, JSEXN_TYPEERR, "redeclaration of identifier '{0}' in catch")
MSG_DEF(JSMSG_INTERNAL_INTL_ERROR, 197, 0, JSEXN_ERR, "internal error while computing Intl data")
MSG_DEF(JSMSG_DEFAULT_LOCALE_ERROR, 198, 0, JSEXN_ERR, "internal error getting the default locale")
MSG_DEF(JSMSG_TOO_MANY_LOCALS, 199, 0, JSEXN_SYNTAXERR, "too many local variables")
MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 200, 0, JSEXN_INTERNALERR, "array initialiser too large")
MSG_DEF(JSMSG_REGEXP_TOO_COMPLEX, 201, 0, JSEXN_INTERNALERR, "regular expression too complex")
MSG_DEF(JSMSG_BUFFER_TOO_SMALL, 202, 0, JSEXN_INTERNALERR, "buffer too small")
MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 203, 1, JSEXN_TYPEERR, "bad surrogate character {0}")
MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 204, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large")
MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR, 205, 1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}")
MSG_DEF(JSMSG_USER_DEFINED_ERROR, 206, 0, JSEXN_ERR, "JS_ReportError was called")
MSG_DEF(JSMSG_WRONG_CONSTRUCTOR, 207, 1, JSEXN_TYPEERR, "wrong constructor called for {0}")
MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 208, 1, JSEXN_TYPEERR, "generator function {0} returns a value")
MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 209, 0, JSEXN_TYPEERR, "anonymous generator function returns a value")
MSG_DEF(JSMSG_PROTO_SETTING_SLOW, 210, 0, JSEXN_NONE, "mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create")
MSG_DEF(JSMSG_IN_AFTER_FOR_NAME, 211, 0, JSEXN_SYNTAXERR, "missing 'in' or 'of' after for")
MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE, 212, 2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value")
MSG_DEF(JSMSG_OF_AFTER_FOR_NAME, 213, 0, JSEXN_SYNTAXERR, "missing 'of' after for")
MSG_DEF(JSMSG_BAD_GENERATOR_YIELD, 214, 1, JSEXN_TYPEERR, "yield from closing generator {0}")
MSG_DEF(JSMSG_BAD_GENERATOR_SYNTAX, 215, 1, JSEXN_SYNTAXERR, "{0} expression must be parenthesized")
MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 216, 0, JSEXN_SYNTAXERR, "invalid array comprehension left-hand side")
MSG_DEF(JSMSG_LET_COMP_BINDING, 217, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 218, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value")
MSG_DEF(JSMSG_BAD_SYMBOL, 219, 1, JSEXN_TYPEERR, "{0} is not a well-known @@-symbol")
MSG_DEF(JSMSG_BAD_DELETE_OPERAND, 220, 0, JSEXN_REFERENCEERR, "invalid delete operand")
MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 221, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand")
MSG_DEF(JSMSG_UNEXPECTED_TYPE, 222, 2, JSEXN_TYPEERR, "{0} is {1}")
MSG_DEF(JSMSG_LET_DECL_NOT_IN_BLOCK, 223, 0, JSEXN_SYNTAXERR, "let declaration not directly within block")
MSG_DEF(JSMSG_UNUSED224, 224, 0, JSEXN_NONE, "")
MSG_DEF(JSMSG_CANT_SET_ARRAY_ATTRS, 225, 0, JSEXN_INTERNALERR, "can't set attributes on indexed array properties")
MSG_DEF(JSMSG_EVAL_ARITY, 226, 0, JSEXN_TYPEERR, "eval accepts only one parameter")
MSG_DEF(JSMSG_MISSING_FUN_ARG, 227, 2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}")
MSG_DEF(JSMSG_JSON_BAD_PARSE, 228, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data")
MSG_DEF(JSMSG_JSON_BAD_STRINGIFY, 229, 0, JSEXN_ERR, "JSON.stringify")
MSG_DEF(JSMSG_NOT_CALLABLE_OR_UNDEFINED, 230, 0, JSEXN_TYPEERR, "value is not a function or undefined")
MSG_DEF(JSMSG_NOT_NONNULL_OBJECT, 231, 0, JSEXN_TYPEERR, "value is not a non-null object")
MSG_DEF(JSMSG_DEPRECATED_OCTAL, 232, 0, JSEXN_SYNTAXERR, "octal literals and octal escape sequences are deprecated")
MSG_DEF(JSMSG_STRICT_CODE_WITH, 233, 0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements")
MSG_DEF(JSMSG_DUPLICATE_PROPERTY, 234, 1, JSEXN_SYNTAXERR, "property name {0} appears more than once in object literal")
MSG_DEF(JSMSG_DEPRECATED_DELETE_OPERAND, 235, 0, JSEXN_SYNTAXERR, "applying the 'delete' operator to an unqualified name is deprecated")
MSG_DEF(JSMSG_BAD_STRICT_ASSIGN, 236, 1, JSEXN_SYNTAXERR, "can't assign to {0} in strict mode")
MSG_DEF(JSMSG_BAD_BINDING, 237, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated")
MSG_DEF(JSMSG_INVALID_DESCRIPTOR, 238, 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, 239, 1, JSEXN_TYPEERR, "{0} is not extensible")
MSG_DEF(JSMSG_CANT_REDEFINE_PROP, 240, 1, JSEXN_TYPEERR, "can't redefine non-configurable property '{0}'")
MSG_DEF(JSMSG_CANT_APPEND_TO_ARRAY, 241, 0, JSEXN_TYPEERR, "can't add elements past the end of an array if its length property is unwritable")
MSG_DEF(JSMSG_CANT_REDEFINE_ARRAY_LENGTH,242, 0, JSEXN_TYPEERR, "can't redefine array length")
MSG_DEF(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH,243, 0, JSEXN_TYPEERR, "can't define array index property past the end of an array with non-writable length")
MSG_DEF(JSMSG_TYPED_ARRAY_BAD_INDEX, 244, 0, JSEXN_ERR, "invalid or out-of-range index")
MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG, 245, 1, JSEXN_ERR, "argument {0} must be >= 0")
MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS, 246, 0, JSEXN_ERR, "invalid arguments")
MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION, 247, 0, JSEXN_ERR, "call to Function() blocked by CSP")
MSG_DEF(JSMSG_BAD_GET_SET_FIELD, 248, 1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function")
MSG_DEF(JSMSG_BAD_PROXY_FIX, 249, 0, JSEXN_TYPEERR, "proxy was fixed while executing the handler")
MSG_DEF(JSMSG_INVALID_EVAL_SCOPE_ARG, 250, 0, JSEXN_EVALERR, "invalid eval scope argument")
MSG_DEF(JSMSG_ACCESSOR_WRONG_ARGS, 251, 3, JSEXN_SYNTAXERR, "{0} functions must have {1} argument{2}")
MSG_DEF(JSMSG_THROW_TYPE_ERROR, 252, 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_BAD_TOISOSTRING_PROP, 253, 0, JSEXN_TYPEERR, "toISOString property is not callable")
MSG_DEF(JSMSG_BAD_PARSE_NODE, 254, 0, JSEXN_INTERNALERR, "bad parse node")
MSG_DEF(JSMSG_NOT_EXPECTED_TYPE, 255, 3, JSEXN_TYPEERR, "{0}: expected {1}, got {2}")
MSG_DEF(JSMSG_CALLER_IS_STRICT, 256, 0, JSEXN_TYPEERR, "access to strict mode caller function is censored")
MSG_DEF(JSMSG_NEED_DEBUG_MODE, 257, 0, JSEXN_ERR, "function can be called only in debug mode")
MSG_DEF(JSMSG_STRICT_CODE_LET_EXPR_STMT, 258, 0, JSEXN_ERR, "strict mode code may not contain unparenthesized let expression statements")
MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 259, 0, JSEXN_TYPEERR, "can't change object's extensibility")
MSG_DEF(JSMSG_SC_BAD_SERIALIZED_DATA, 260, 1, JSEXN_INTERNALERR, "bad serialized structured data ({0})")
MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE, 261, 0, JSEXN_TYPEERR, "unsupported type for structured data")
MSG_DEF(JSMSG_SC_RECURSION, 262, 0, JSEXN_INTERNALERR, "recursive object")
MSG_DEF(JSMSG_DEBUG_CANT_DEBUG_GLOBAL, 263, 0, JSEXN_ERR, "passing non-debuggable global to addDebuggee")
MSG_DEF(JSMSG_BAD_CLONE_VERSION, 264, 0, JSEXN_ERR, "unsupported structured clone version")
MSG_DEF(JSMSG_CANT_CLONE_OBJECT, 265, 0, JSEXN_TYPEERR, "can't clone object")
MSG_DEF(JSMSG_DEBUG_RESUMPTION_VALUE_DISALLOWED, 266, 0, JSEXN_TYPEERR, "resumption values are disallowed in this hook")
MSG_DEF(JSMSG_STRICT_FUNCTION_STATEMENT, 267, 0, JSEXN_SYNTAXERR, "in strict mode code, functions may be declared only at top level or immediately within another function")
MSG_DEF(JSMSG_INVALID_FOR_IN_INIT, 268, 0, JSEXN_SYNTAXERR, "for-in loop let declaration may not have an initializer")
MSG_DEF(JSMSG_CLEARED_SCOPE, 269, 0, JSEXN_TYPEERR, "attempt to run compile-and-go script on a cleared scope")
MSG_DEF(JSMSG_MALFORMED_ESCAPE, 270, 1, JSEXN_SYNTAXERR, "malformed {0} character escape sequence")
MSG_DEF(JSMSG_BAD_GENEXP_BODY, 271, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression")
MSG_DEF(JSMSG_YIELD_WITHOUT_OPERAND, 272, 0, JSEXN_SYNTAXERR, "yield without a value is deprecated, and illegal in ES6 (use 'yield undefined' instead)")
MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT, 273, 0, JSEXN_SYNTAXERR, "function statement requires a name")
MSG_DEF(JSMSG_CCW_REQUIRED, 274, 1, JSEXN_TYPEERR, "{0}: argument must be an object from a different compartment")
MSG_DEF(JSMSG_DEBUG_BAD_RESUMPTION, 275, 0, JSEXN_TYPEERR, "debugger resumption value must be undefined, {throw: val}, {return: val}, or null")
MSG_DEF(JSMSG_ASSIGN_FUNCTION_OR_NULL, 276, 1, JSEXN_TYPEERR, "value assigned to {0} must be a function or null")
MSG_DEF(JSMSG_DEBUG_NOT_LIVE, 277, 1, JSEXN_ERR, "{0} is not live")
MSG_DEF(JSMSG_DEBUG_OBJECT_WRONG_OWNER, 278, 0, JSEXN_TYPEERR, "Debugger.Object belongs to a different Debugger")
MSG_DEF(JSMSG_DEBUG_OBJECT_PROTO, 279, 0, JSEXN_TYPEERR, "Debugger.Object.prototype is not a valid Debugger.Object")
MSG_DEF(JSMSG_DEBUG_LOOP, 280, 0, JSEXN_TYPEERR, "cannot debug an object in same compartment as debugger or a compartment that is already debugging the debugger")
MSG_DEF(JSMSG_DEBUG_NOT_IDLE, 281, 0, JSEXN_ERR, "can't start debugging: a debuggee script is on the stack")
MSG_DEF(JSMSG_DEBUG_BAD_OFFSET, 282, 0, JSEXN_TYPEERR, "invalid script offset")
MSG_DEF(JSMSG_DEBUG_BAD_LINE, 283, 0, JSEXN_TYPEERR, "invalid line number")
MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGING, 284, 0, JSEXN_ERR, "can't set breakpoint: script global is not a debuggee")
MSG_DEF(JSMSG_DEBUG_COMPARTMENT_MISMATCH, 285, 2, JSEXN_TYPEERR, "{0}: descriptor .{1} property is an object in a different compartment than the target object")
MSG_DEF(JSMSG_DEBUG_NOT_SCRIPT_FRAME, 286, 0, JSEXN_ERR, "stack frame is not running JavaScript code")
MSG_DEF(JSMSG_CANT_WATCH_PROP, 287, 0, JSEXN_TYPEERR, "properties whose names are objects can't be watched")
MSG_DEF(JSMSG_CSP_BLOCKED_EVAL, 288, 0, JSEXN_ERR, "call to eval() blocked by CSP")
MSG_DEF(JSMSG_DEBUG_NO_SCOPE_OBJECT, 289, 0, JSEXN_TYPEERR, "declarative Environments don't have binding objects")
MSG_DEF(JSMSG_EMPTY_CONSEQUENT, 290, 0, JSEXN_SYNTAXERR, "mistyped ; after conditional?")
MSG_DEF(JSMSG_NOT_ITERABLE, 291, 1, JSEXN_TYPEERR, "{0} is not iterable")
MSG_DEF(JSMSG_QUERY_LINE_WITHOUT_URL, 292, 0, JSEXN_TYPEERR, "findScripts query object has 'line' property, but no 'url' property")
MSG_DEF(JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL, 293, 0, JSEXN_TYPEERR, "findScripts query object has 'innermost' property without both 'url' and 'line' properties")
MSG_DEF(JSMSG_DEBUG_VARIABLE_NOT_FOUND, 294, 0, JSEXN_TYPEERR, "variable not found in environment")
MSG_DEF(JSMSG_PARAMETER_AFTER_REST, 295, 0, JSEXN_SYNTAXERR, "parameter after rest parameter")
MSG_DEF(JSMSG_NO_REST_NAME, 296, 0, JSEXN_SYNTAXERR, "no parameter name after ...")
MSG_DEF(JSMSG_ARGUMENTS_AND_REST, 297, 0, JSEXN_SYNTAXERR, "'arguments' object may not be used in conjunction with a rest parameter")
MSG_DEF(JSMSG_FUNCTION_ARGUMENTS_AND_REST, 298, 0, JSEXN_ERR, "the 'arguments' property of a function with a rest parameter may not be used")
MSG_DEF(JSMSG_REST_WITH_DEFAULT, 299, 0, JSEXN_SYNTAXERR, "rest parameter may not have a default")
MSG_DEF(JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT, 300, 0, JSEXN_SYNTAXERR, "parameter(s) with default followed by parameter without default")
MSG_DEF(JSMSG_YIELD_IN_DEFAULT, 301, 0, JSEXN_SYNTAXERR, "yield in default expression")
MSG_DEF(JSMSG_INTRINSIC_NOT_DEFINED, 302, 1, JSEXN_REFERENCEERR, "no intrinsic function {0}")
MSG_DEF(JSMSG_ALREADY_HAS_PRAGMA, 303, 2, JSEXN_NONE, "{0} is being assigned a {1}, but already has one")
MSG_DEF(JSMSG_PAR_ARRAY_BAD_ARG, 304, 0, JSEXN_RANGEERR, "invalid parallel method argument")
MSG_DEF(JSMSG_REGEXP_RUNTIME_ERROR, 305, 0, JSEXN_INTERNALERR, "an error occurred while executing regular expression")
MSG_DEF(JSMSG_DEBUG_OPTIMIZED_OUT, 306, 0, JSEXN_ERR, "variable has been optimized out")
MSG_DEF(JSMSG_NEXT_RETURNED_PRIMITIVE,307, 0, JSEXN_TYPEERR, "iterator.next() returned a non-object value")
MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_CONFLICT, 308, 0, JSEXN_ERR, "no conflict resolution function provided")
MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BOUNDS, 309, 0, JSEXN_ERR, "index in scatter vector out of bounds")
MSG_DEF(JSMSG_CANT_REPORT_NC_AS_NE, 310, 0, JSEXN_TYPEERR, "proxy can't report a non-configurable own property as non-existent")
MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE, 311, 0, JSEXN_TYPEERR, "proxy can't report an existing own property as non-existent on a non-extensible object")
MSG_DEF(JSMSG_CANT_REPORT_NEW, 312, 0, JSEXN_TYPEERR, "proxy can't report a new property on a non-extensible object")
MSG_DEF(JSMSG_CANT_REPORT_INVALID, 313, 0, JSEXN_TYPEERR, "proxy can't report an incompatible property descriptor")
MSG_DEF(JSMSG_CANT_REPORT_NE_AS_NC, 314, 0, JSEXN_TYPEERR, "proxy can't report a non-existent property as non-configurable")
MSG_DEF(JSMSG_CANT_DEFINE_NEW, 315, 0, JSEXN_TYPEERR, "proxy can't define a new property on a non-extensible object")
MSG_DEF(JSMSG_CANT_DEFINE_INVALID, 316, 0, JSEXN_TYPEERR, "proxy can't define an incompatible property descriptor")
MSG_DEF(JSMSG_CANT_DEFINE_NE_AS_NC, 317, 0, JSEXN_TYPEERR, "proxy can't define a non-existent property as non-configurable")
MSG_DEF(JSMSG_INVALID_TRAP_RESULT, 318, 2, JSEXN_TYPEERR, "trap {1} for {0} returned an invalid result")
MSG_DEF(JSMSG_CANT_SKIP_NC, 319, 0, JSEXN_TYPEERR, "proxy can't skip a non-configurable property")
MSG_DEF(JSMSG_MUST_REPORT_SAME_VALUE, 320, 0, JSEXN_TYPEERR, "proxy must report the same value for a non-writable, non-configurable property")
MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED, 321, 0, JSEXN_TYPEERR, "proxy must report undefined for a non-configurable accessor property without a getter")
MSG_DEF(JSMSG_CANT_SET_NW_NC, 322, 0, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property")
MSG_DEF(JSMSG_CANT_SET_WO_SETTER, 323, 0, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property without a setter")
MSG_DEF(JSMSG_DEBUG_BAD_REFERENT, 324, 2, JSEXN_TYPEERR, "{0} does not refer to {1}")
MSG_DEF(JSMSG_DEBUG_WRAPPER_IN_WAY, 325, 3, JSEXN_TYPEERR, "{0} is {1}{2}a global object, but a direct reference is required")
MSG_DEF(JSMSG_UNWRAP_DENIED, 326, 0, JSEXN_ERR, "permission denied to unwrap object")
MSG_DEF(JSMSG_INTL_OBJECT_NOT_INITED, 327, 3, JSEXN_TYPEERR, "Intl.{0}.prototype.{1} called on value that's not an object initialized as a {2}")
MSG_DEF(JSMSG_INVALID_LOCALES_ELEMENT,328, 0, JSEXN_TYPEERR, "invalid element in locales argument")
MSG_DEF(JSMSG_INVALID_LANGUAGE_TAG, 329, 1, JSEXN_RANGEERR, "invalid language tag: {0}")
MSG_DEF(JSMSG_INVALID_LOCALE_MATCHER, 330, 1, JSEXN_RANGEERR, "invalid locale matcher in supportedLocalesOf(): {0}")
MSG_DEF(JSMSG_INVALID_OPTION_VALUE, 331, 2, JSEXN_RANGEERR, "invalid value {1} for option {0}")
MSG_DEF(JSMSG_INVALID_DIGITS_VALUE, 332, 1, JSEXN_RANGEERR, "invalid digits value: {0}")
MSG_DEF(JSMSG_INTL_OBJECT_REINITED, 333, 0, JSEXN_TYPEERR, "can't initialize object twice as an object of an Intl constructor")
MSG_DEF(JSMSG_INVALID_CURRENCY_CODE, 334, 1, JSEXN_RANGEERR, "invalid currency code in NumberFormat(): {0}")
MSG_DEF(JSMSG_UNDEFINED_CURRENCY, 335, 0, JSEXN_TYPEERR, "undefined currency in NumberFormat() with currency style")
MSG_DEF(JSMSG_INVALID_TIME_ZONE, 336, 1, JSEXN_RANGEERR, "invalid time zone in DateTimeFormat(): {0}")
MSG_DEF(JSMSG_DATE_NOT_FINITE, 337, 0, JSEXN_RANGEERR, "date value is not finite in DateTimeFormat.format()")
MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL, 338, 0, JSEXN_SYNTAXERR, "\"use asm\" is only meaningful in the Directive Prologue of a function body")
MSG_DEF(JSMSG_USE_ASM_TYPE_FAIL, 339, 1, JSEXN_TYPEERR, "asm.js type error: {0}")
MSG_DEF(JSMSG_USE_ASM_LINK_FAIL, 340, 1, JSEXN_TYPEERR, "asm.js link error: {0}")
MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 341, 1, JSEXN_NONE, "Successfully compiled asm.js code ({0})")
MSG_DEF(JSMSG_BAD_ARROW_ARGS, 342, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
MSG_DEF(JSMSG_YIELD_IN_ARROW, 343, 0, JSEXN_SYNTAXERR, "arrow function may not contain yield")
MSG_DEF(JSMSG_WRONG_VALUE, 344, 2, JSEXN_ERR, "expected {0} but found {1}")
MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BAD_TARGET, 345, 1, JSEXN_ERR, "target for index {0} is not an integer")
MSG_DEF(JSMSG_SELFHOSTED_UNBOUND_NAME,346, 0, JSEXN_TYPEERR, "self-hosted code may not contain unbound name lookups")
MSG_DEF(JSMSG_DEPRECATED_PRAGMA, 347, 1, JSEXN_NONE, "Using //@ to indicate {0} pragmas is deprecated. Use //# instead")
MSG_DEF(JSMSG_BAD_DESTRUCT_ASSIGN, 348, 1, JSEXN_SYNTAXERR, "can't assign to {0} using destructuring assignment")
MSG_DEF(JSMSG_TYPEDOBJECT_ARRAYTYPE_BAD_ARGS, 349, 0, JSEXN_ERR, "Invalid arguments")
MSG_DEF(JSMSG_TYPEDOBJECT_BINARYARRAY_BAD_INDEX, 350, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_ARGS, 351, 0, JSEXN_RANGEERR, "invalid field descriptor")
MSG_DEF(JSMSG_TYPEDOBJECT_NOT_BINARYSTRUCT, 352, 1, JSEXN_TYPEERR, "{0} is not a BinaryStruct")
MSG_DEF(JSMSG_TYPEDOBJECT_SUBARRAY_INTEGER_ARG, 353, 1, JSEXN_ERR, "argument {0} must be an integer")
MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_EMPTY_DESCRIPTOR, 354, 0, JSEXN_ERR, "field descriptor cannot be empty")
MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_FIELD, 355, 1, JSEXN_ERR, "field {0} is not a valid BinaryData Type descriptor")
MSG_DEF(JSMSG_GENERATOR_FINISHED, 356, 0, JSEXN_TYPEERR, "generator has already finished")
MSG_DEF(JSMSG_TYPEDOBJECT_TOO_BIG, 357, 0, JSEXN_ERR, "Type is too large to allocate")
MSG_DEF(JSMSG_TYPEDOBJECT_NOT_TYPE_OBJECT, 358, 0, JSEXN_ERR, "Expected a type object")
MSG_DEF(JSMSG_TOO_MANY_CON_SPREADARGS, 359, 0, JSEXN_RANGEERR, "too many constructor arguments")
MSG_DEF(JSMSG_TOO_MANY_FUN_SPREADARGS, 360, 0, JSEXN_RANGEERR, "too many function arguments")
MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGEE, 361, 2, JSEXN_ERR, "{0} is not a debuggee {1}")
MSG_DEF(JSMSG_TYPEDOBJECT_NOT_TYPED_OBJECT, 362, 0, JSEXN_ERR, "Expected a typed object")
MSG_DEF(JSMSG_TYPEDOBJECT_NO_SUCH_PROP, 363, 1, JSEXN_TYPEERR, "No such property: {0}")
MSG_DEF(JSMSG_TYPEDOBJECT_BAD_ARGS, 364, 0, JSEXN_TYPEERR, "invalid arguments")
MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED, 365, 0, JSEXN_TYPEERR, "handle unattached")
MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_BAD_TYPE, 366, 0, JSEXN_TYPEERR, "handle moved to destination of incorrect type")
MSG_DEF(JSMSG_NOT_AN_ERROR, 0, JSEXN_ERR, "<Error #0 is reserved>")
MSG_DEF(JSMSG_NOT_DEFINED, 1, JSEXN_REFERENCEERR, "{0} is not defined")
MSG_DEF(JSMSG_MORE_ARGS_NEEDED, 3, JSEXN_TYPEERR, "{0} requires more than {1} argument{2}")
MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}")
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")
MSG_DEF(JSMSG_NOT_FUNCTION, 1, JSEXN_TYPEERR, "{0} is not a function")
MSG_DEF(JSMSG_NOT_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} is not a constructor")
MSG_DEF(JSMSG_CANT_CONVERT_TO, 2, JSEXN_TYPEERR, "can't convert {0} to {1}")
MSG_DEF(JSMSG_TOPRIMITIVE_NOT_CALLABLE, 2, JSEXN_TYPEERR, "can't convert {0} to {1}: its [Symbol.toPrimitive] property is not a function")
MSG_DEF(JSMSG_TOPRIMITIVE_RETURNED_OBJECT, 2, JSEXN_TYPEERR, "can't convert {0} to {1}: its [Symbol.toPrimitive] method returned an object")
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_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_VAR, 2, JSEXN_SYNTAXERR, "redeclaration of {0} {1}")
MSG_DEF(JSMSG_UNDECLARED_VAR, 1, JSEXN_REFERENCEERR, "assignment to undeclared variable {0}")
MSG_DEF(JSMSG_GETTER_ONLY, 0, JSEXN_TYPEERR, "setting a property that has only a getter")
MSG_DEF(JSMSG_OVERWRITING_ACCESSOR, 1, JSEXN_TYPEERR, "can't overwrite accessor property {0}")
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_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")
MSG_DEF(JSMSG_CANT_REDEFINE_PROP, 1, JSEXN_TYPEERR, "can't redefine non-configurable property {0}")
MSG_DEF(JSMSG_CANT_REDEFINE_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't redefine array length")
MSG_DEF(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't define array index property past the end of an array with non-writable length")
MSG_DEF(JSMSG_BAD_GET_SET_FIELD, 1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function")
MSG_DEF(JSMSG_THROW_TYPE_ERROR, 0, JSEXN_TYPEERR, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them")
MSG_DEF(JSMSG_NOT_EXPECTED_TYPE, 3, JSEXN_TYPEERR, "{0}: expected {1}, got {2}")
MSG_DEF(JSMSG_NOT_ITERABLE, 1, JSEXN_TYPEERR, "{0} is not iterable")
MSG_DEF(JSMSG_NOT_ITERATOR, 1, JSEXN_TYPEERR, "{0} is not iterator")
MSG_DEF(JSMSG_ALREADY_HAS_PRAGMA, 2, JSEXN_WARN, "{0} is being assigned a {1}, but already has one")
MSG_DEF(JSMSG_GET_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.iterator]() returned a non-object value")
MSG_DEF(JSMSG_NEXT_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "iterator.next() returned a non-object value")
MSG_DEF(JSMSG_CANT_SET_PROTO, 0, JSEXN_TYPEERR, "can't set prototype of this object")
MSG_DEF(JSMSG_CANT_SET_PROTO_OF, 1, JSEXN_TYPEERR, "can't set prototype of {0}")
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_BAD_DERIVED_RETURN, 1, JSEXN_TYPEERR, "derived class constructor returned invalid value {0}")
MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 367, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level")
MSG_DEF(JSMSG_NO_IMPORT_NAME, 368, 0, JSEXN_SYNTAXERR, "missing import name")
MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 369, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
MSG_DEF(JSMSG_NO_BINDING_NAME, 370, 0, JSEXN_SYNTAXERR, "missing binding name")
MSG_DEF(JSMSG_RC_AFTER_IMPORT_SPEC_LIST, 371, 0, JSEXN_SYNTAXERR, "missing '}' after module specifier list")
MSG_DEF(JSMSG_FROM_AFTER_IMPORT_SPEC_SET, 372, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after import specifier set")
MSG_DEF(JSMSG_DECLARATION_AFTER_IMPORT, 373, 0, JSEXN_SYNTAXERR, "missing declaration after 'import' keyword")
MSG_DEF(JSMSG_MODULE_SPEC_AFTER_FROM, 374, 0, JSEXN_SYNTAXERR, "missing module specifier after 'from' keyword")
MSG_DEF(JSMSG_MODULES_NOT_IMPLEMENTED, 375, 0, JSEXN_SYNTAXERR, "modules are not implemented yet")
MSG_DEF(JSMSG_EXPORT_DECL_AT_TOP_LEVEL, 376, 0, JSEXN_SYNTAXERR, "export declarations may only appear at top level")
MSG_DEF(JSMSG_RC_AFTER_EXPORT_SPEC_LIST, 377, 0, JSEXN_SYNTAXERR, "missing '}' after export specifier list")
MSG_DEF(JSMSG_NO_EXPORT_NAME, 378, 0, JSEXN_SYNTAXERR, "missing export name")
MSG_DEF(JSMSG_DECLARATION_AFTER_EXPORT, 379, 0, JSEXN_SYNTAXERR, "missing declaration after 'export' keyword")
MSG_DEF(JSMSG_INVALID_PROTOTYPE, 380, 0, JSEXN_TYPEERR, "prototype field is not an object")
MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_TO_UNSIZED, 381, 0, JSEXN_TYPEERR, "cannot create a handle to an unsized type")
MSG_DEF(JSMSG_SETPROTOTYPEOF_FAIL, 382, 1, JSEXN_TYPEERR, "[[SetPrototypeOf]] failed on {0}")
MSG_DEF(JSMSG_INVALID_ARG_TYPE, 383, 3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}")
MSG_DEF(JSMSG_TERMINATED, 384, 1, JSEXN_ERR, "Script terminated by timeout at:\n{0}")
MSG_DEF(JSMSG_NO_SUCH_SELF_HOSTED_PROP, 385, 1, JSEXN_ERR, "No such property on self-hosted object: {0}")
MSG_DEF(JSMSG_PROXY_EXTENSIBILITY, 386, 0, JSEXN_TYPEERR, "proxy must report same extensiblitity as target")
MSG_DEF(JSMSG_PROXY_CONSTRUCT_OBJECT, 387, 0, JSEXN_TYPEERR, "proxy [[Construct]] must return an object")
MSG_DEF(JSMSG_PROXY_GETOWN_OBJORUNDEF, 388, 0, JSEXN_TYPEERR, "proxy [[GetOwnProperty]] must return an object or undefined")
MSG_DEF(JSMSG_CANT_REPORT_C_AS_NC, 389, 0, JSEXN_TYPEERR, "proxy can't report existing configurable property as non-configurable")
// JSON
MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data")
MSG_DEF(JSMSG_JSON_CYCLIC_VALUE, 0, JSEXN_TYPEERR, "cyclic object value")
// Runtime errors
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_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")
MSG_DEF(JSMSG_BAD_CONST_ASSIGN, 1, JSEXN_TYPEERR, "invalid assignment to const `{0}'")
MSG_DEF(JSMSG_CANT_DECLARE_GLOBAL_BINDING, 2, JSEXN_TYPEERR, "cannot declare global binding `{0}': {1}")
// Date
MSG_DEF(JSMSG_INVALID_DATE, 0, JSEXN_RANGEERR, "invalid date")
MSG_DEF(JSMSG_BAD_TOISOSTRING_PROP, 0, JSEXN_TYPEERR, "toISOString property is not callable")
// String
MSG_DEF(JSMSG_BAD_URI, 0, JSEXN_URIERR, "malformed URI sequence")
MSG_DEF(JSMSG_INVALID_NORMALIZE_FORM, 0, JSEXN_RANGEERR, "form must be one of 'NFC', 'NFD', 'NFKC', or 'NFKD'")
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")
// Number
MSG_DEF(JSMSG_BAD_RADIX, 0, JSEXN_RANGEERR, "radix must be an integer at least 2 and no greater than 36")
MSG_DEF(JSMSG_PRECISION_RANGE, 1, JSEXN_RANGEERR, "precision {0} out of range")
// Function
MSG_DEF(JSMSG_BAD_APPLY_ARGS, 1, JSEXN_TYPEERR, "second argument to Function.prototype.{0} must be an array")
MSG_DEF(JSMSG_BAD_FORMAL, 0, JSEXN_SYNTAXERR, "malformed formal parameter")
MSG_DEF(JSMSG_CALLER_IS_STRICT, 0, JSEXN_TYPEERR, "access to strict mode caller function is censored")
MSG_DEF(JSMSG_DEPRECATED_USAGE, 1, JSEXN_REFERENCEERR, "deprecated {0} usage")
MSG_DEF(JSMSG_NOT_SCRIPTED_FUNCTION, 1, JSEXN_TYPEERR, "{0} is not a scripted function")
MSG_DEF(JSMSG_NO_REST_NAME, 0, JSEXN_SYNTAXERR, "no parameter name after ...")
MSG_DEF(JSMSG_PARAMETER_AFTER_REST, 0, JSEXN_SYNTAXERR, "parameter after rest parameter")
MSG_DEF(JSMSG_TOO_MANY_ARGUMENTS, 0, JSEXN_RANGEERR, "too many arguments provided for a function call")
// CSP
MSG_DEF(JSMSG_CSP_BLOCKED_EVAL, 0, JSEXN_ERR, "call to eval() blocked by CSP")
MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION, 0, JSEXN_ERR, "call to Function() blocked by CSP")
// 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")
// JSAPI-only (Not thrown as JS exceptions)
MSG_DEF(JSMSG_BAD_CLONE_FUNOBJ_SCOPE, 0, JSEXN_TYPEERR, "bad cloned function scope chain")
MSG_DEF(JSMSG_CANT_CLONE_OBJECT, 0, JSEXN_TYPEERR, "can't clone object")
MSG_DEF(JSMSG_CANT_OPEN, 2, JSEXN_ERR, "can't open {0}: {1}")
MSG_DEF(JSMSG_USER_DEFINED_ERROR, 0, JSEXN_ERR, "JS_ReportError was called")
// Internal errors
MSG_DEF(JSMSG_ALLOC_OVERFLOW, 0, JSEXN_INTERNALERR, "allocation size overflow")
MSG_DEF(JSMSG_BAD_BYTECODE, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}")
MSG_DEF(JSMSG_BUFFER_TOO_SMALL, 0, JSEXN_INTERNALERR, "buffer too small")
MSG_DEF(JSMSG_BUILD_ID_NOT_AVAILABLE, 0, JSEXN_INTERNALERR, "build ID is not available")
MSG_DEF(JSMSG_BYTECODE_TOO_BIG, 2, JSEXN_INTERNALERR, "bytecode {0} too large (limit {1})")
MSG_DEF(JSMSG_ERR_DURING_THROW, 0, JSEXN_INTERNALERR, "an internal error occurred while throwing an exception")
MSG_DEF(JSMSG_NEED_DIET, 1, JSEXN_INTERNALERR, "{0} too large")
MSG_DEF(JSMSG_OUT_OF_MEMORY, 0, JSEXN_INTERNALERR, "out of memory")
MSG_DEF(JSMSG_OVER_RECURSED, 0, JSEXN_INTERNALERR, "too much recursion")
MSG_DEF(JSMSG_TOO_BIG_TO_ENCODE, 0, JSEXN_INTERNALERR, "data are to big to encode")
MSG_DEF(JSMSG_TOO_DEEP, 1, JSEXN_INTERNALERR, "{0} nested too deeply")
MSG_DEF(JSMSG_UNCAUGHT_EXCEPTION, 1, JSEXN_INTERNALERR, "uncaught exception: {0}")
MSG_DEF(JSMSG_UNKNOWN_FORMAT, 1, JSEXN_INTERNALERR, "unknown bytecode format {0}")
// 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_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")
MSG_DEF(JSMSG_BAD_CONTINUE, 0, JSEXN_SYNTAXERR, "continue must be inside loop")
MSG_DEF(JSMSG_BAD_DESTRUCT_ASS, 0, JSEXN_REFERENCEERR, "invalid destructuring assignment operator")
MSG_DEF(JSMSG_BAD_DESTRUCT_TARGET, 0, JSEXN_SYNTAXERR, "invalid destructuring target")
MSG_DEF(JSMSG_BAD_DESTRUCT_PARENS, 0, JSEXN_SYNTAXERR, "destructuring patterns in assignments can't be parenthesized")
MSG_DEF(JSMSG_BAD_DESTRUCT_DECL, 0, JSEXN_SYNTAXERR, "missing = in destructuring declaration")
MSG_DEF(JSMSG_BAD_DUP_ARGS, 0, JSEXN_SYNTAXERR, "duplicate argument names not allowed in this context")
MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 0, JSEXN_SYNTAXERR, "invalid for each loop")
MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for-in/of left-hand side")
MSG_DEF(JSMSG_LEXICAL_DECL_DEFINES_LET,0, JSEXN_SYNTAXERR, "a lexical declaration can't define a 'let' binding")
MSG_DEF(JSMSG_LET_STARTING_FOROF_LHS, 0, JSEXN_SYNTAXERR, "an expression X in 'for (X of Y)' must not start with 'let'")
MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 1, JSEXN_TYPEERR, "generator function {0} returns a value")
MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression")
MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand")
MSG_DEF(JSMSG_BAD_METHOD_DEF, 0, JSEXN_SYNTAXERR, "bad method definition")
MSG_DEF(JSMSG_BAD_OCTAL, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant")
MSG_DEF(JSMSG_BAD_OPERAND, 1, JSEXN_SYNTAXERR, "invalid {0} operand")
MSG_DEF(JSMSG_BAD_POW_LEFTSIDE, 0, JSEXN_SYNTAXERR, "unparenthesized unary expression can't appear on the left-hand side of '**'")
MSG_DEF(JSMSG_BAD_PROP_ID, 0, JSEXN_SYNTAXERR, "invalid property id")
MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 1, JSEXN_SYNTAXERR, "{0} not in function")
MSG_DEF(JSMSG_BAD_STRICT_ASSIGN, 1, JSEXN_SYNTAXERR, "'{0}' can't be defined or assigned to in strict mode code")
MSG_DEF(JSMSG_BAD_SWITCH, 0, JSEXN_SYNTAXERR, "invalid switch statement")
MSG_DEF(JSMSG_BAD_SUPER, 0, JSEXN_SYNTAXERR, "invalid use of keyword 'super'")
MSG_DEF(JSMSG_BAD_SUPERPROP, 1, JSEXN_SYNTAXERR, "use of super {0} accesses only valid within methods or eval code within methods")
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_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")
MSG_DEF(JSMSG_CATCH_WITHOUT_TRY, 0, JSEXN_SYNTAXERR, "catch without try")
MSG_DEF(JSMSG_COLON_AFTER_CASE, 0, JSEXN_SYNTAXERR, "missing : after case label")
MSG_DEF(JSMSG_COLON_AFTER_ID, 0, JSEXN_SYNTAXERR, "missing : after property id")
MSG_DEF(JSMSG_COLON_IN_COND, 0, JSEXN_SYNTAXERR, "missing : in conditional expression")
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_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")
MSG_DEF(JSMSG_CURLY_AFTER_TRY, 0, JSEXN_SYNTAXERR, "missing } after try block")
MSG_DEF(JSMSG_CURLY_BEFORE_BODY, 0, JSEXN_SYNTAXERR, "missing { before function body")
MSG_DEF(JSMSG_CURLY_BEFORE_CATCH, 0, JSEXN_SYNTAXERR, "missing { before catch block")
MSG_DEF(JSMSG_CURLY_BEFORE_CLASS, 0, JSEXN_SYNTAXERR, "missing { before class body")
MSG_DEF(JSMSG_CURLY_BEFORE_FINALLY, 0, JSEXN_SYNTAXERR, "missing { before finally block")
MSG_DEF(JSMSG_CURLY_BEFORE_SWITCH, 0, JSEXN_SYNTAXERR, "missing { before switch body")
MSG_DEF(JSMSG_CURLY_BEFORE_TRY, 0, JSEXN_SYNTAXERR, "missing { before try block")
MSG_DEF(JSMSG_CURLY_IN_COMPOUND, 0, JSEXN_SYNTAXERR, "missing } in compound statement")
MSG_DEF(JSMSG_DECLARATION_AFTER_EXPORT,0, JSEXN_SYNTAXERR, "missing declaration after 'export' keyword")
MSG_DEF(JSMSG_DECLARATION_AFTER_IMPORT,0, JSEXN_SYNTAXERR, "missing declaration after 'import' keyword")
MSG_DEF(JSMSG_DEPRECATED_DELETE_OPERAND, 0, JSEXN_SYNTAXERR, "applying the 'delete' operator to an unqualified name is deprecated")
MSG_DEF(JSMSG_DEPRECATED_EXPR_CLOSURE, 0, JSEXN_WARN, "expression closures are deprecated")
MSG_DEF(JSMSG_DEPRECATED_FOR_EACH, 0, JSEXN_WARN, "JavaScript 1.6's for-each-in loops are deprecated; consider using ES6 for-of instead")
MSG_DEF(JSMSG_DEPRECATED_OCTAL, 0, JSEXN_SYNTAXERR, "\"0\"-prefixed octal literals and octal escape sequences are deprecated; for octal literals use the \"0o\" prefix instead")
MSG_DEF(JSMSG_DEPRECATED_PRAGMA, 1, JSEXN_WARN, "Using //@ to indicate {0} pragmas is deprecated. Use //# instead")
MSG_DEF(JSMSG_DEPRECATED_BLOCK_SCOPE_FUN_REDECL, 1, JSEXN_WARN, "redeclaration of block-scoped function `{0}' is deprecated")
MSG_DEF(JSMSG_DUPLICATE_EXPORT_NAME, 1, JSEXN_SYNTAXERR, "duplicate export name '{0}'")
MSG_DEF(JSMSG_DUPLICATE_FORMAL, 1, JSEXN_SYNTAXERR, "duplicate formal argument {0}")
MSG_DEF(JSMSG_DUPLICATE_LABEL, 0, JSEXN_SYNTAXERR, "duplicate label")
MSG_DEF(JSMSG_DUPLICATE_PROPERTY, 1, JSEXN_SYNTAXERR, "property name {0} appears more than once in object literal")
MSG_DEF(JSMSG_DUPLICATE_PROTO_PROPERTY, 0, JSEXN_SYNTAXERR, "property name __proto__ appears more than once in object literal")
MSG_DEF(JSMSG_EMPTY_CONSEQUENT, 0, JSEXN_SYNTAXERR, "mistyped ; after conditional?")
MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 0, JSEXN_SYNTAXERR, "test for equality (==) mistyped as assignment (=)?")
MSG_DEF(JSMSG_EXPORT_DECL_AT_TOP_LEVEL,0, JSEXN_SYNTAXERR, "export declarations may only appear at top level of a module")
MSG_DEF(JSMSG_FINALLY_WITHOUT_TRY, 0, JSEXN_SYNTAXERR, "finally without try")
MSG_DEF(JSMSG_FORBIDDEN_AS_STATEMENT, 1, JSEXN_SYNTAXERR, "{0} can't appear in single-statement context")
MSG_DEF(JSMSG_FROM_AFTER_IMPORT_CLAUSE, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after import clause")
MSG_DEF(JSMSG_FROM_AFTER_EXPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after export *")
MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT, 2, JSEXN_SYNTAXERR, "unexpected garbage after {0}, starting with {1}")
MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER, 0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal")
MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 0, JSEXN_SYNTAXERR, "illegal character")
MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level of a module")
MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers")
MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found")
MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, 1, JSEXN_SYNTAXERR, "{0} declaration not directly within block")
MSG_DEF(JSMSG_LEXICAL_DECL_LABEL, 1, JSEXN_SYNTAXERR, "{0} declarations cannot be labelled")
MSG_DEF(JSMSG_GENERATOR_LABEL, 0, JSEXN_SYNTAXERR, "generator functions cannot be labelled")
MSG_DEF(JSMSG_FUNCTION_LABEL, 0, JSEXN_SYNTAXERR, "functions cannot be labelled")
MSG_DEF(JSMSG_SLOPPY_FUNCTION_LABEL, 0, JSEXN_SYNTAXERR, "functions can only be labelled inside blocks")
MSG_DEF(JSMSG_LINE_BREAK_AFTER_THROW, 0, JSEXN_SYNTAXERR, "no line break is allowed between 'throw' and its expression")
MSG_DEF(JSMSG_LINE_BREAK_BEFORE_ARROW, 0, JSEXN_SYNTAXERR, "no line break is allowed before '=>'")
MSG_DEF(JSMSG_MALFORMED_ESCAPE, 1, JSEXN_SYNTAXERR, "malformed {0} character escape sequence")
MSG_DEF(JSMSG_MISSING_BINARY_DIGITS, 0, JSEXN_SYNTAXERR, "missing binary digits after '0b'")
MSG_DEF(JSMSG_MISSING_EXPONENT, 0, JSEXN_SYNTAXERR, "missing exponent")
MSG_DEF(JSMSG_MISSING_EXPR_AFTER_THROW,0, JSEXN_SYNTAXERR, "throw statement is missing an expression")
MSG_DEF(JSMSG_MISSING_FORMAL, 0, JSEXN_SYNTAXERR, "missing formal parameter")
MSG_DEF(JSMSG_MISSING_HEXDIGITS, 0, JSEXN_SYNTAXERR, "missing hexadecimal digits after '0x'")
MSG_DEF(JSMSG_MISSING_OCTAL_DIGITS, 0, JSEXN_SYNTAXERR, "missing octal digits after '0o'")
MSG_DEF(JSMSG_MODULE_SPEC_AFTER_FROM, 0, JSEXN_SYNTAXERR, "missing module specifier after 'from' keyword")
MSG_DEF(JSMSG_NAME_AFTER_DOT, 0, JSEXN_SYNTAXERR, "missing name after . operator")
MSG_DEF(JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT, 0, JSEXN_SYNTAXERR, "expected named imports or namespace import after comma")
MSG_DEF(JSMSG_NO_BINDING_NAME, 0, JSEXN_SYNTAXERR, "missing binding name")
MSG_DEF(JSMSG_NO_EXPORT_NAME, 0, JSEXN_SYNTAXERR, "missing export name")
MSG_DEF(JSMSG_NO_IMPORT_NAME, 0, JSEXN_SYNTAXERR, "missing import name")
MSG_DEF(JSMSG_NO_VARIABLE_NAME, 0, JSEXN_SYNTAXERR, "missing variable name")
MSG_DEF(JSMSG_OF_AFTER_FOR_NAME, 0, JSEXN_SYNTAXERR, "missing 'of' after for")
MSG_DEF(JSMSG_PAREN_AFTER_ARGS, 0, JSEXN_SYNTAXERR, "missing ) after argument list")
MSG_DEF(JSMSG_PAREN_AFTER_CATCH, 0, JSEXN_SYNTAXERR, "missing ) after catch")
MSG_DEF(JSMSG_PAREN_AFTER_COND, 0, JSEXN_SYNTAXERR, "missing ) after condition")
MSG_DEF(JSMSG_PAREN_AFTER_FOR, 0, JSEXN_SYNTAXERR, "missing ( after for")
MSG_DEF(JSMSG_PAREN_AFTER_FORMAL, 0, JSEXN_SYNTAXERR, "missing ) after formal parameters")
MSG_DEF(JSMSG_PAREN_AFTER_FOR_CTRL, 0, JSEXN_SYNTAXERR, "missing ) after for-loop control")
MSG_DEF(JSMSG_PAREN_AFTER_FOR_OF_ITERABLE, 0, JSEXN_SYNTAXERR, "missing ) after for-of iterable")
MSG_DEF(JSMSG_PAREN_AFTER_SWITCH, 0, JSEXN_SYNTAXERR, "missing ) after switch expression")
MSG_DEF(JSMSG_PAREN_AFTER_WITH, 0, JSEXN_SYNTAXERR, "missing ) after with-statement object")
MSG_DEF(JSMSG_PAREN_BEFORE_CATCH, 0, JSEXN_SYNTAXERR, "missing ( before catch")
MSG_DEF(JSMSG_PAREN_BEFORE_COND, 0, JSEXN_SYNTAXERR, "missing ( before condition")
MSG_DEF(JSMSG_PAREN_BEFORE_FORMAL, 0, JSEXN_SYNTAXERR, "missing ( before formal parameters")
MSG_DEF(JSMSG_PAREN_BEFORE_SWITCH, 0, JSEXN_SYNTAXERR, "missing ( before switch expression")
MSG_DEF(JSMSG_PAREN_BEFORE_WITH, 0, JSEXN_SYNTAXERR, "missing ( before with-statement object")
MSG_DEF(JSMSG_PAREN_IN_PAREN, 0, JSEXN_SYNTAXERR, "missing ) in parenthetical")
MSG_DEF(JSMSG_RC_AFTER_EXPORT_SPEC_LIST, 0, JSEXN_SYNTAXERR, "missing '}' after export specifier list")
MSG_DEF(JSMSG_RC_AFTER_IMPORT_SPEC_LIST, 0, JSEXN_SYNTAXERR, "missing '}' after module specifier list")
MSG_DEF(JSMSG_REDECLARED_CATCH_IDENTIFIER, 1, JSEXN_SYNTAXERR, "redeclaration of identifier '{0}' in catch")
MSG_DEF(JSMSG_RESERVED_ID, 1, JSEXN_SYNTAXERR, "{0} is a reserved identifier")
MSG_DEF(JSMSG_REST_WITH_COMMA, 0, JSEXN_SYNTAXERR, "rest element may not have a trailing comma")
MSG_DEF(JSMSG_REST_WITH_DEFAULT, 0, JSEXN_SYNTAXERR, "rest parameter may not have a default")
MSG_DEF(JSMSG_SELFHOSTED_TOP_LEVEL_LEXICAL, 1, JSEXN_SYNTAXERR, "self-hosted code cannot contain top-level {0} declarations")
MSG_DEF(JSMSG_SELFHOSTED_METHOD_CALL, 0, JSEXN_SYNTAXERR, "self-hosted code may not contain direct method calls. Use callFunction() or callContentFunction()")
MSG_DEF(JSMSG_SELFHOSTED_UNBOUND_NAME, 0, JSEXN_TYPEERR, "self-hosted code may not contain unbound name lookups")
MSG_DEF(JSMSG_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")
MSG_DEF(JSMSG_STRICT_NON_SIMPLE_PARAMS, 1, JSEXN_SYNTAXERR, "\"use strict\" not allowed in function with {0} parameter")
MSG_DEF(JSMSG_TEMPLSTR_UNTERM_EXPR, 0, JSEXN_SYNTAXERR, "missing } in template string")
MSG_DEF(JSMSG_SIMD_NOT_A_VECTOR, 2, JSEXN_TYPEERR, "expecting a SIMD {0} object as argument {1}")
MSG_DEF(JSMSG_TOO_MANY_CASES, 0, JSEXN_INTERNALERR, "too many switch cases")
MSG_DEF(JSMSG_TOO_MANY_CATCH_VARS, 0, JSEXN_SYNTAXERR, "too many catch variables")
MSG_DEF(JSMSG_TOO_MANY_CON_ARGS, 0, JSEXN_SYNTAXERR, "too many constructor arguments")
MSG_DEF(JSMSG_TOO_MANY_DEFAULTS, 0, JSEXN_SYNTAXERR, "more than one switch default")
MSG_DEF(JSMSG_TOO_MANY_FUN_ARGS, 0, JSEXN_SYNTAXERR, "too many function arguments")
MSG_DEF(JSMSG_TOO_MANY_LOCALS, 0, JSEXN_SYNTAXERR, "too many local variables")
MSG_DEF(JSMSG_TOO_MANY_YIELDS, 0, JSEXN_SYNTAXERR, "too many yield expressions")
MSG_DEF(JSMSG_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_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_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_BAD_COLUMN_NUMBER, 0, JSEXN_RANGEERR, "column number out of range")
MSG_DEF(JSMSG_COMPUTED_NAME_IN_PATTERN,0, JSEXN_SYNTAXERR, "computed property names aren't supported in this destructuring declaration")
MSG_DEF(JSMSG_DEFAULT_IN_PATTERN, 0, JSEXN_SYNTAXERR, "destructuring defaults aren't supported in this destructuring declaration")
MSG_DEF(JSMSG_BAD_NEWTARGET, 0, JSEXN_SYNTAXERR, "new.target only allowed within functions")
MSG_DEF(JSMSG_ESCAPED_KEYWORD, 0, JSEXN_SYNTAXERR, "keywords must be written literally, without embedded escapes")
// asm.js
MSG_DEF(JSMSG_USE_ASM_TYPE_FAIL, 1, JSEXN_TYPEERR, "asm.js type error: {0}")
MSG_DEF(JSMSG_USE_ASM_LINK_FAIL, 1, JSEXN_TYPEERR, "asm.js link error: {0}")
MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 1, JSEXN_WARN, "Successfully compiled asm.js code ({0})")
// wasm
MSG_DEF(JSMSG_WASM_COMPILE_ERROR, 1, JSEXN_WASMCOMPILEERROR, "{0}")
MSG_DEF(JSMSG_WASM_IND_CALL_TO_NULL, 0, JSEXN_WASMRUNTIMEERROR, "indirect call to null")
MSG_DEF(JSMSG_WASM_IND_CALL_BAD_SIG, 0, JSEXN_WASMRUNTIMEERROR, "indirect call signature mismatch")
MSG_DEF(JSMSG_WASM_UNREACHABLE, 0, JSEXN_WASMRUNTIMEERROR, "unreachable executed")
MSG_DEF(JSMSG_WASM_INTEGER_OVERFLOW, 0, JSEXN_WASMRUNTIMEERROR, "integer overflow")
MSG_DEF(JSMSG_WASM_INVALID_CONVERSION, 0, JSEXN_WASMRUNTIMEERROR, "invalid conversion to integer")
MSG_DEF(JSMSG_WASM_INT_DIVIDE_BY_ZERO, 0, JSEXN_WASMRUNTIMEERROR, "integer divide by zero")
MSG_DEF(JSMSG_WASM_OUT_OF_BOUNDS, 0, JSEXN_WASMRUNTIMEERROR, "index out of bounds")
MSG_DEF(JSMSG_WASM_UNALIGNED_ACCESS, 0, JSEXN_WASMRUNTIMEERROR, "unaligned memory access")
MSG_DEF(JSMSG_WASM_BAD_UINT32, 2, JSEXN_RANGEERR, "bad {0} {1}")
MSG_DEF(JSMSG_WASM_BAD_GROW, 1, JSEXN_RANGEERR, "failed to grow {0}")
MSG_DEF(JSMSG_WASM_BAD_FIT, 2, JSEXN_RANGEERR, "{0} segment does not fit in {1}")
MSG_DEF(JSMSG_WASM_BAD_BUF_ARG, 0, JSEXN_TYPEERR, "first argument must be an ArrayBuffer or typed array object")
MSG_DEF(JSMSG_WASM_BAD_MOD_ARG, 0, JSEXN_TYPEERR, "first argument must be a WebAssembly.Module")
MSG_DEF(JSMSG_WASM_BAD_BUF_MOD_ARG, 0, JSEXN_TYPEERR, "first argument must be a WebAssembly.Module, ArrayBuffer or typed array object")
MSG_DEF(JSMSG_WASM_BAD_DESC_ARG, 1, JSEXN_TYPEERR, "first argument must be a {0} descriptor")
MSG_DEF(JSMSG_WASM_BAD_IMP_SIZE, 1, JSEXN_TYPEERR, "imported {0} with incompatible size")
MSG_DEF(JSMSG_WASM_BAD_IMP_MAX, 1, JSEXN_TYPEERR, "imported {0} with incompatible maximum size")
MSG_DEF(JSMSG_WASM_BAD_ELEMENT, 0, JSEXN_TYPEERR, "\"element\" property of table descriptor must be \"anyfunc\"")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG, 0, JSEXN_TYPEERR, "second argument must be an object")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_FIELD, 2, JSEXN_TYPEERR, "import object field '{0}' is not {1}")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_SIG, 0, JSEXN_TYPEERR, "imported function signature mismatch")
MSG_DEF(JSMSG_WASM_BAD_TABLE_VALUE, 0, JSEXN_TYPEERR, "can only assign WebAssembly exported functions to Table")
MSG_DEF(JSMSG_WASM_BAD_I64, 0, JSEXN_TYPEERR, "cannot pass i64 to or from JS")
MSG_DEF(JSMSG_WASM_NO_TRANSFER, 0, JSEXN_TYPEERR, "cannot transfer WebAssembly/asm.js ArrayBuffer")
MSG_DEF(JSMSG_WASM_TEXT_FAIL, 1, JSEXN_SYNTAXERR, "wasm text error: {0}")
// Proxy
MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE, 2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value")
MSG_DEF(JSMSG_BAD_GETPROTOTYPEOF_TRAP_RETURN,0,JSEXN_TYPEERR,"proxy getPrototypeOf handler returned a non-object, non-null value")
MSG_DEF(JSMSG_INCONSISTENT_GETPROTOTYPEOF_TRAP,0,JSEXN_TYPEERR,"proxy getPrototypeOf handler didn't return the target object's prototype")
MSG_DEF(JSMSG_PROXY_SETPROTOTYPEOF_RETURNED_FALSE, 0, JSEXN_TYPEERR, "proxy setPrototypeOf handler returned false")
MSG_DEF(JSMSG_PROXY_ISEXTENSIBLE_RETURNED_FALSE,0,JSEXN_TYPEERR,"proxy isExtensible handler must return the same extensibility as target")
MSG_DEF(JSMSG_INCONSISTENT_SETPROTOTYPEOF_TRAP,0,JSEXN_TYPEERR,"proxy setPrototypeOf handler returned true, even though the target's prototype is immutable because the target is non-extensible")
MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 0, JSEXN_TYPEERR, "can't change object's extensibility")
MSG_DEF(JSMSG_CANT_DEFINE_INVALID, 0, JSEXN_TYPEERR, "proxy can't define an incompatible property descriptor")
MSG_DEF(JSMSG_CANT_DEFINE_NEW, 0, JSEXN_TYPEERR, "proxy can't define a new property on a non-extensible object")
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_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_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_REVOKED, 0, JSEXN_TYPEERR, "illegal operation attempted on a revoked proxy")
MSG_DEF(JSMSG_PROXY_ARG_REVOKED, 1, JSEXN_TYPEERR, "argument {0} cannot be a revoked proxy")
MSG_DEF(JSMSG_BAD_TRAP, 1, JSEXN_TYPEERR, "proxy handler's {0} trap wasn't undefined, null, or callable")
// Structured cloning
MSG_DEF(JSMSG_SC_BAD_CLONE_VERSION, 0, JSEXN_ERR, "unsupported structured clone version")
MSG_DEF(JSMSG_SC_BAD_SERIALIZED_DATA, 1, JSEXN_INTERNALERR, "bad serialized structured data ({0})")
MSG_DEF(JSMSG_SC_DUP_TRANSFERABLE, 0, JSEXN_TYPEERR, "duplicate transferable for structured clone")
MSG_DEF(JSMSG_SC_NOT_TRANSFERABLE, 0, JSEXN_TYPEERR, "invalid transferable array for structured clone")
MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE, 0, JSEXN_TYPEERR, "unsupported type for structured data")
MSG_DEF(JSMSG_SC_NOT_CLONABLE, 1, JSEXN_TYPEERR, "{0} cannot be cloned in this context")
MSG_DEF(JSMSG_SC_SAB_TRANSFER, 0, JSEXN_WARN, "SharedArrayBuffer must not be in the transfer list")
MSG_DEF(JSMSG_SC_SAB_DISABLED, 0, JSEXN_TYPEERR, "SharedArrayBuffer not cloned - shared memory disabled in receiver")
// Debugger
MSG_DEF(JSMSG_ASSIGN_FUNCTION_OR_NULL, 1, JSEXN_TYPEERR, "value assigned to {0} must be a function or null")
MSG_DEF(JSMSG_DEBUG_BAD_AWAIT, 0, JSEXN_TYPEERR, "await expression received invalid value")
MSG_DEF(JSMSG_DEBUG_BAD_LINE, 0, JSEXN_TYPEERR, "invalid line number")
MSG_DEF(JSMSG_DEBUG_BAD_OFFSET, 0, JSEXN_TYPEERR, "invalid script offset")
MSG_DEF(JSMSG_DEBUG_BAD_REFERENT, 2, JSEXN_TYPEERR, "{0} does not refer to {1}")
MSG_DEF(JSMSG_DEBUG_BAD_RESUMPTION, 0, JSEXN_TYPEERR, "debugger resumption value must be undefined, {throw: val}, {return: val}, or null")
MSG_DEF(JSMSG_DEBUG_BAD_YIELD, 0, JSEXN_TYPEERR, "generator yielded invalid value")
MSG_DEF(JSMSG_DEBUG_CANT_DEBUG_GLOBAL, 0, JSEXN_TYPEERR, "passing non-debuggable global to addDebuggee")
MSG_DEF(JSMSG_DEBUG_CCW_REQUIRED, 1, JSEXN_TYPEERR, "{0}: argument must be an object from a different compartment")
MSG_DEF(JSMSG_DEBUG_COMPARTMENT_MISMATCH, 2, JSEXN_TYPEERR, "{0}: descriptor .{1} property is an object in a different compartment than the target object")
MSG_DEF(JSMSG_DEBUG_LOOP, 0, JSEXN_TYPEERR, "cannot debug an object in same compartment as debugger or a compartment that is already debugging the debugger")
MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGEE, 2, JSEXN_ERR, "{0} is not a debuggee {1}")
MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGING, 0, JSEXN_ERR, "can't set breakpoint: script global is not a debuggee")
MSG_DEF(JSMSG_DEBUG_NOT_IDLE, 0, JSEXN_ERR, "can't start debugging: a debuggee script is on the stack")
MSG_DEF(JSMSG_DEBUG_NOT_LIVE, 1, JSEXN_ERR, "{0} is not live")
MSG_DEF(JSMSG_DEBUG_NO_ENV_OBJECT, 0, JSEXN_TYPEERR, "declarative Environments don't have binding objects")
MSG_DEF(JSMSG_DEBUG_PROTO, 2, JSEXN_TYPEERR, "{0}.prototype is not a valid {1} instance")
MSG_DEF(JSMSG_DEBUG_WRONG_OWNER, 1, JSEXN_TYPEERR, "{0} belongs to a different Debugger")
MSG_DEF(JSMSG_DEBUG_OPTIMIZED_OUT, 1, JSEXN_ERR, "variable `{0}' has been optimized out")
MSG_DEF(JSMSG_DEBUG_RESUMPTION_VALUE_DISALLOWED, 0, JSEXN_TYPEERR, "resumption values are disallowed in this hook")
MSG_DEF(JSMSG_DEBUG_VARIABLE_NOT_FOUND,0, JSEXN_TYPEERR, "variable not found in environment")
MSG_DEF(JSMSG_DEBUG_WRAPPER_IN_WAY, 3, JSEXN_TYPEERR, "{0} is {1}{2}a global object, but a direct reference is required")
MSG_DEF(JSMSG_DEBUGGEE_WOULD_RUN, 2, JSEXN_DEBUGGEEWOULDRUN, "debuggee `{0}:{1}' would run")
MSG_DEF(JSMSG_NOT_CALLABLE_OR_UNDEFINED, 0, JSEXN_TYPEERR, "value is not a function or undefined")
MSG_DEF(JSMSG_NOT_TRACKING_ALLOCATIONS, 1, JSEXN_ERR, "Cannot call {0} without setting trackingAllocationSites to true")
MSG_DEF(JSMSG_OBJECT_METADATA_CALLBACK_ALREADY_SET, 0, JSEXN_ERR, "Cannot track object allocation, because other tools are already doing so")
MSG_DEF(JSMSG_QUERY_INNERMOST_WITHOUT_LINE_URL, 0, JSEXN_TYPEERR, "findScripts query object with 'innermost' property must have 'line' and either 'displayURL', 'url', or 'source'")
MSG_DEF(JSMSG_QUERY_LINE_WITHOUT_URL, 0, JSEXN_TYPEERR, "findScripts query object has 'line' property, but no 'displayURL', 'url', or 'source' property")
MSG_DEF(JSMSG_DEBUG_CANT_SET_OPT_ENV, 1, JSEXN_REFERENCEERR, "can't set `{0}' in an optimized-out environment")
MSG_DEF(JSMSG_DEBUG_INVISIBLE_COMPARTMENT, 0, JSEXN_TYPEERR, "object in compartment marked as invisible to Debugger")
MSG_DEF(JSMSG_DEBUG_CENSUS_BREAKDOWN, 1, JSEXN_TYPEERR, "unrecognized 'by' value in takeCensus breakdown: {0}")
MSG_DEF(JSMSG_DEBUG_PROMISE_NOT_RESOLVED, 0, JSEXN_TYPEERR, "Promise hasn't been resolved")
MSG_DEF(JSMSG_DEBUG_PROMISE_NOT_FULFILLED, 0, JSEXN_TYPEERR, "Promise hasn't been fulfilled")
MSG_DEF(JSMSG_DEBUG_PROMISE_NOT_REJECTED, 0, JSEXN_TYPEERR, "Promise hasn't been rejected")
// Tracelogger
MSG_DEF(JSMSG_TRACELOGGER_ENABLE_FAIL, 1, JSEXN_ERR, "enabling tracelogger failed: {0}")
// Intl
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_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}")
MSG_DEF(JSMSG_INVALID_OPTION_VALUE, 2, JSEXN_RANGEERR, "invalid value {1} for option {0}")
MSG_DEF(JSMSG_INVALID_TIME_ZONE, 1, JSEXN_RANGEERR, "invalid time zone in DateTimeFormat(): {0}")
MSG_DEF(JSMSG_UNDEFINED_CURRENCY, 0, JSEXN_TYPEERR, "undefined currency in NumberFormat() with currency style")
// RegExp
MSG_DEF(JSMSG_BACK_REF_OUT_OF_RANGE, 0, JSEXN_SYNTAXERR, "back reference out of range in regular expression")
MSG_DEF(JSMSG_BAD_CLASS_RANGE, 0, JSEXN_SYNTAXERR, "invalid range in character class")
MSG_DEF(JSMSG_ESCAPE_AT_END_OF_REGEXP, 0, JSEXN_SYNTAXERR, "\\ at end of pattern")
MSG_DEF(JSMSG_EXEC_NOT_OBJORNULL, 0, JSEXN_TYPEERR, "RegExp exec method should return object or null")
MSG_DEF(JSMSG_INVALID_DECIMAL_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid decimal escape in regular expression")
MSG_DEF(JSMSG_INVALID_GROUP, 0, JSEXN_SYNTAXERR, "invalid regexp group")
MSG_DEF(JSMSG_INVALID_IDENTITY_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid identity escape in regular expression")
MSG_DEF(JSMSG_INVALID_UNICODE_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid unicode escape in regular expression")
MSG_DEF(JSMSG_MISSING_PAREN, 0, JSEXN_SYNTAXERR, "unterminated parenthetical")
MSG_DEF(JSMSG_NEWREGEXP_FLAGGED, 0, JSEXN_TYPEERR, "can't supply flags when constructing one RegExp from another")
MSG_DEF(JSMSG_NOTHING_TO_REPEAT, 0, JSEXN_SYNTAXERR, "nothing to repeat")
MSG_DEF(JSMSG_NUMBERS_OUT_OF_ORDER, 0, JSEXN_SYNTAXERR, "numbers out of order in {} quantifier.")
MSG_DEF(JSMSG_RANGE_WITH_CLASS_ESCAPE, 0, JSEXN_SYNTAXERR, "character class escape cannot be used in class range in regular expression")
MSG_DEF(JSMSG_RAW_BRACE_IN_REGEP, 0, JSEXN_SYNTAXERR, "raw brace is not allowed in regular expression with unicode flag")
MSG_DEF(JSMSG_RAW_BRACKET_IN_REGEP, 0, JSEXN_SYNTAXERR, "raw bracket is not allowed in regular expression with unicode flag")
MSG_DEF(JSMSG_TOO_MANY_PARENS, 0, JSEXN_INTERNALERR, "too many parentheses in regular expression")
MSG_DEF(JSMSG_UNICODE_OVERFLOW, 0, JSEXN_SYNTAXERR, "unicode codepoint should not be greater than 0x10FFFF in regular expression")
MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression")
MSG_DEF(JSMSG_UNTERM_CLASS, 0, JSEXN_SYNTAXERR, "unterminated character class")
// Self-hosting
MSG_DEF(JSMSG_DEFAULT_LOCALE_ERROR, 0, JSEXN_ERR, "internal error getting the default locale")
MSG_DEF(JSMSG_NO_SUCH_SELF_HOSTED_PROP,1, JSEXN_ERR, "No such property on self-hosted object: {0}")
// Typed object / SIMD
MSG_DEF(JSMSG_INVALID_PROTOTYPE, 0, JSEXN_TYPEERR, "prototype field is not an object")
MSG_DEF(JSMSG_TYPEDOBJECT_BAD_ARGS, 0, JSEXN_TYPEERR, "invalid arguments")
MSG_DEF(JSMSG_TYPEDOBJECT_BINARYARRAY_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED, 0, JSEXN_TYPEERR, "handle unattached")
MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_ARGS, 0, JSEXN_RANGEERR, "invalid field descriptor")
MSG_DEF(JSMSG_TYPEDOBJECT_TOO_BIG, 0, JSEXN_ERR, "Type is too large to allocate")
MSG_DEF(JSMSG_SIMD_FAILED_CONVERSION, 0, JSEXN_RANGEERR, "SIMD conversion loses precision")
MSG_DEF(JSMSG_SIMD_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert SIMD value to number")
// Array
MSG_DEF(JSMSG_TOO_LONG_ARRAY, 0, JSEXN_TYPEERR, "Too long array")
// Typed array
MSG_DEF(JSMSG_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
MSG_DEF(JSMSG_NON_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected ArrayBuffer, but species constructor returned non-ArrayBuffer")
MSG_DEF(JSMSG_SAME_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected different ArrayBuffer, but species constructor returned same ArrayBuffer")
MSG_DEF(JSMSG_SHORT_ARRAY_BUFFER_RETURNED, 2, JSEXN_TYPEERR, "expected ArrayBuffer with at least {0} bytes, but species constructor returns ArrayBuffer with {1} bytes")
MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS, 0, JSEXN_TYPEERR, "invalid arguments")
MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG,1, JSEXN_RANGEERR, "argument {0} must be >= 0")
MSG_DEF(JSMSG_TYPED_ARRAY_DETACHED, 0, JSEXN_TYPEERR, "attempting to access detached ArrayBuffer")
MSG_DEF(JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS, 0, JSEXN_RANGEERR, "attempting to construct out-of-bounds TypedArray on ArrayBuffer")
MSG_DEF(JSMSG_TYPED_ARRAY_CALL_OR_CONSTRUCT, 1, JSEXN_TYPEERR, "cannot directly {0} builtin %TypedArray%")
MSG_DEF(JSMSG_NON_TYPED_ARRAY_RETURNED, 0, JSEXN_TYPEERR, "constructor didn't return TypedArray object")
MSG_DEF(JSMSG_SHORT_TYPED_ARRAY_RETURNED, 2, JSEXN_TYPEERR, "expected TypedArray of at least length {0}, but constructor returned TypedArray of length {1}")
// Shared array buffer
MSG_DEF(JSMSG_SHARED_ARRAY_BAD_LENGTH, 0, JSEXN_RANGEERR, "length argument out of range")
MSG_DEF(JSMSG_NON_SHARED_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected SharedArrayBuffer, but species constructor returned non-SharedArrayBuffer")
MSG_DEF(JSMSG_SAME_SHARED_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected different SharedArrayBuffer, but species constructor returned same SharedArrayBuffer")
MSG_DEF(JSMSG_SHORT_SHARED_ARRAY_BUFFER_RETURNED, 2, JSEXN_TYPEERR, "expected SharedArrayBuffer with at least {0} bytes, but species constructor returns SharedArrayBuffer with {1} bytes")
// Reflect
MSG_DEF(JSMSG_BAD_PARSE_NODE, 0, JSEXN_INTERNALERR, "bad parse node")
// Symbol
MSG_DEF(JSMSG_SYMBOL_TO_STRING, 0, JSEXN_TYPEERR, "can't convert symbol to string")
MSG_DEF(JSMSG_SYMBOL_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert symbol to number")
// 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")
// XPConnect wrappers and DOM bindings
MSG_DEF(JSMSG_CANT_SET_INTERPOSED, 1, JSEXN_TYPEERR, "unable to set interposed data property '{0}'")
MSG_DEF(JSMSG_CANT_DEFINE_WINDOW_ELEMENT, 0, JSEXN_TYPEERR, "can't define elements on a Window object")
MSG_DEF(JSMSG_CANT_DELETE_WINDOW_ELEMENT, 0, JSEXN_TYPEERR, "can't delete elements from a Window object")
MSG_DEF(JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY, 1, JSEXN_TYPEERR, "can't delete property {0} from window's named properties object")
MSG_DEF(JSMSG_CANT_PREVENT_EXTENSIONS, 0, JSEXN_TYPEERR, "can't prevent extensions on this proxy object")
MSG_DEF(JSMSG_NO_NAMED_SETTER, 2, JSEXN_TYPEERR, "{0} doesn't have a named property setter for '{1}'")
MSG_DEF(JSMSG_NO_INDEXED_SETTER, 2, JSEXN_TYPEERR, "{0} doesn't have an indexed property setter for '{1}'")
// Super
MSG_DEF(JSMSG_CANT_DELETE_SUPER, 0, JSEXN_REFERENCEERR, "invalid delete involving 'super'")
MSG_DEF(JSMSG_REINIT_THIS, 0, JSEXN_REFERENCEERR, "super() called twice in derived class constructor")
// 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_NAMESPACE_EXPORT, 0, JSEXN_SYNTAXERR, "export not found for namespace")
MSG_DEF(JSMSG_MISSING_EXPORT, 1, JSEXN_SYNTAXERR, "local binding for export '{0}' not found")
MSG_DEF(JSMSG_MODULE_INSTANTIATE_FAILED, 0, JSEXN_INTERNALERR, "attempt to re-instantiate module after failure")
MSG_DEF(JSMSG_BAD_MODULE_STATE, 0, JSEXN_INTERNALERR, "module record in unexpected state")
// Promise
MSG_DEF(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself.")
MSG_DEF(JSMSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY, 0, JSEXN_TYPEERR, "GetCapabilitiesExecutor function already invoked with non-undefined values.")
MSG_DEF(JSMSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the resolve function.")
MSG_DEF(JSMSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the reject function.")
MSG_DEF(JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON,0, JSEXN_INTERNALERR, "Promise rejection value is a non-unwrappable cross-compartment wrapper.")

View File

@ -1,174 +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::Anchor implementation. */
#ifndef js_Anchor_h
#define js_Anchor_h
#include "mozilla/Attributes.h"
#include "js/TypeDecls.h"
namespace JS {
/*
* Protecting non-Value, non-JSObject *, non-JSString * values from collection
*
* Most of the time, the garbage collector's conservative stack scanner works
* behind the scenes, finding all live values and protecting them from being
* collected. However, when JSAPI client code obtains a pointer to data the
* scanner does not know about, owned by an object the scanner does know about,
* Care Must Be Taken.
*
* The scanner recognizes only a select set of types: pointers to JSObjects and
* similar things (JSFunctions, and so on), pointers to JSStrings, and Values.
* So while the scanner finds all live |JSString| pointers, it does not notice
* |jschar| pointers.
*
* So suppose we have:
*
* void f(JSString *str) {
* const jschar *ch = JS_GetStringCharsZ(str);
* ... do stuff with ch, but no uses of str ...;
* }
*
* After the call to |JS_GetStringCharsZ|, there are no further uses of
* |str|, which means that the compiler is within its rights to not store
* it anywhere. But because the stack scanner will not notice |ch|, there
* is no longer any live value in this frame that would keep the string
* alive. If |str| is the last reference to that |JSString|, and the
* collector runs while we are using |ch|, the string's array of |jschar|s
* may be freed out from under us.
*
* Note that there is only an issue when 1) we extract a thing X the scanner
* doesn't recognize from 2) a thing Y the scanner does recognize, and 3) if Y
* gets garbage-collected, then X gets freed. If we have code like this:
*
* void g(JSObject *obj) {
* JS::Value x;
* JS_GetProperty(obj, "x", &x);
* ... do stuff with x ...
* }
*
* there's no problem, because the value we've extracted, x, is a Value, a
* type that the conservative scanner recognizes.
*
* Conservative GC frees us from the obligation to explicitly root the types it
* knows about, but when we work with derived values like |ch|, we must root
* their owners, as the derived value alone won't keep them alive.
*
* A JS::Anchor is a kind of GC root that allows us to keep the owners of
* derived values like |ch| alive throughout the Anchor's lifetime. We could
* fix the above code as follows:
*
* void f(JSString *str) {
* JS::Anchor<JSString *> a_str(str);
* const jschar *ch = JS_GetStringCharsZ(str);
* ... do stuff with ch, but no uses of str ...;
* }
*
* This simply ensures that |str| will be live until |a_str| goes out of scope.
* As long as we don't retain a pointer to the string's characters for longer
* than that, we have avoided all garbage collection hazards.
*/
template<typename T> class AnchorPermitted;
template<> class AnchorPermitted<JSObject *> { };
template<> class AnchorPermitted<const JSObject *> { };
template<> class AnchorPermitted<JSFunction *> { };
template<> class AnchorPermitted<const JSFunction *> { };
template<> class AnchorPermitted<JSString *> { };
template<> class AnchorPermitted<const JSString *> { };
template<> class AnchorPermitted<Value> { };
template<> class AnchorPermitted<const JSScript *> { };
template<> class AnchorPermitted<JSScript *> { };
template<typename T>
class Anchor : AnchorPermitted<T>
{
public:
Anchor() { }
explicit Anchor(T t) { hold = t; }
inline ~Anchor();
private:
T hold;
/*
* Rooting analysis considers use of operator= to be a use of an anchor.
* For simplicity, Anchor is treated as if it contained a GC thing, from
* construction. Thus if we had
*
* void operator=(const T &t) { hold = t; }
*
* and this code
*
* JS::Anchor<JSString*> anchor;
* stuff that could GC, producing |str|;
* anchor = str;
*
* the last line would be seen as a hazard, because the final = would "use"
* |anchor| that is a GC thing -- which could have been moved around by the
* GC. The workaround is to structure your code so that JS::Anchor is
* always constructed, living for however long the corresponding value must
* live.
*/
void operator=(const T &t) MOZ_DELETE;
Anchor(const Anchor &other) MOZ_DELETE;
void operator=(const Anchor &other) MOZ_DELETE;
};
template<typename T>
inline Anchor<T>::~Anchor()
{
#ifdef __GNUC__
/*
* No code is generated for this. But because this is marked 'volatile', G++ will
* assume it has important side-effects, and won't delete it. (G++ never looks at
* the actual text and notices it's empty.) And because we have passed |hold| to
* it, GCC will keep |hold| alive until this point.
*
* The "memory" clobber operand ensures that G++ will not move prior memory
* accesses after the asm --- it's a barrier. Unfortunately, it also means that
* G++ will assume that all memory has changed after the asm, as it would for a
* call to an unknown function. I don't know of a way to avoid that consequence.
*/
asm volatile("":: "g" (hold) : "memory");
#else
/*
* An adequate portable substitute, for non-structure types.
*
* The compiler promises that, by the end of an expression statement, the
* last-stored value to a volatile object is the same as it would be in an
* unoptimized, direct implementation (the "abstract machine" whose behavior the
* language spec describes). However, the compiler is still free to reorder
* non-volatile accesses across this store --- which is what we must prevent. So
* assigning the held value to a volatile variable, as we do here, is not enough.
*
* In our case, however, garbage collection only occurs at function calls, so it
* is sufficient to ensure that the destructor's store isn't moved earlier across
* any function calls that could collect. It is hard to imagine the compiler
* analyzing the program so thoroughly that it could prove that such motion was
* safe. In practice, compilers treat calls to the collector as opaque operations
* --- in particular, as operations which could access volatile variables, across
* which this destructor must not be moved.
*
* ("Objection, your honor! *Alleged* killer whale!")
*
* The disadvantage of this approach is that it does generate code for the store.
* We do need to use Anchors in some cases where cycles are tight.
*
* Note that there is a Anchor<Value>::~Anchor() specialization in Value.h.
*/
volatile T sink;
sink = hold;
#endif /* defined(__GNUC__) */
}
} // namespace JS
#endif /* js_Anchor_h */

435
android/arm64-v8a/include/spidermonkey/js/CallArgs.h Executable file → Normal file
View File

@ -6,16 +6,51 @@
/*
* Helper classes encapsulating access to the callee, |this| value, arguments,
* and argument count for a function call.
* and argument count for a call/construct operation.
*
* The intent of JS::CallArgs and JS::CallReceiver is that they be used to
* encapsulate access to the un-abstracted |unsigned argc, Value *vp| arguments
* to a function. It's possible (albeit deprecated) to manually index into
* |vp| to access the callee, |this|, and arguments of a function, and to set
* its return value. It's also possible to use the supported API of JS_CALLEE,
* JS_THIS, JS_ARGV, JS_RVAL and JS_SET_RVAL to the same ends. But neither API
* has the error-handling or moving-GC correctness of CallArgs or CallReceiver.
* New code should use CallArgs and CallReceiver instead whenever possible.
* JS::CallArgs encapsulates access to a JSNative's un-abstracted
* |unsigned argc, Value* vp| arguments. The principal way to create a
* JS::CallArgs is using JS::CallArgsFromVp:
*
* // If provided no arguments or a non-numeric first argument, return zero.
* // Otherwise return |this| exactly as given, without boxing.
* static bool
* Func(JSContext* cx, unsigned argc, JS::Value* vp)
* {
* JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
*
* // Guard against no arguments or a non-numeric arg0.
* if (args.length() == 0 || !args[0].isNumber()) {
* args.rval().setInt32(0);
* return true;
* }
*
* // Access to the callee must occur before accessing/setting
* // the return value.
* JSObject& callee = args.callee();
* args.rval().setObject(callee);
*
* // callee() and calleev() will now assert.
*
* // It's always fine to access thisv().
* HandleValue thisv = args.thisv();
* args.rval().set(thisv);
*
* // As the return value was last set to |this|, returns |this|.
* return true;
* }
*
* CallArgs is exposed publicly and used internally. Not all parts of its
* public interface are meant to be used by embedders! See inline comments to
* for details.
*
* It's possible (albeit deprecated) to manually index into |vp| to access the
* callee, |this|, and arguments of a function, and to set its return value.
* It's also possible to use the supported API of JS_CALLEE, JS_THIS, JS_ARGV,
* JS_RVAL, and JS_SET_RVAL to the same ends.
*
* But neither API has the error-handling or moving-GC correctness of CallArgs.
* New code should use CallArgs instead whenever possible.
*
* The eventual plan is to change JSNative to take |const CallArgs&| directly,
* for automatic assertion of correct use and to make calling functions more
@ -40,142 +75,100 @@
/* Typedef for native functions called by the JS VM. */
typedef bool
(* JSNative)(JSContext *cx, unsigned argc, JS::Value *vp);
/* Typedef for native functions that may be called in parallel. */
typedef bool
(* JSParallelNative)(js::ForkJoinContext *cx, unsigned argc, JS::Value *vp);
/*
* Typedef for native functions that may be called either in parallel or
* sequential execution.
*/
typedef bool
(* JSThreadSafeNative)(js::ThreadSafeContext *cx, unsigned argc, JS::Value *vp);
/*
* Convenience wrappers for passing in ThreadSafeNative to places that expect
* a JSNative or a JSParallelNative.
*/
template <JSThreadSafeNative threadSafeNative>
inline bool
JSNativeThreadSafeWrapper(JSContext *cx, unsigned argc, JS::Value *vp);
template <JSThreadSafeNative threadSafeNative>
inline bool
JSParallelNativeThreadSafeWrapper(js::ForkJoinContext *cx, unsigned argc, JS::Value *vp);
/*
* Compute |this| for the |vp| inside a JSNative, either boxing primitives or
* replacing with the global object as necessary.
*
* This method will go away at some point: instead use |args.thisv()|. If the
* value is an object, no further work is required. If that value is |null| or
* |undefined|, use |JS_GetGlobalForObject| to compute the global object. If
* the value is some other primitive, use |JS_ValueToObject| to box it.
*/
extern JS_PUBLIC_API(JS::Value)
JS_ComputeThis(JSContext *cx, JS::Value *vp);
(* JSNative)(JSContext* cx, unsigned argc, JS::Value* vp);
namespace JS {
extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue;
/*
* JS::CallReceiver encapsulates access to the callee, |this|, and eventual
* return value for a function call. The principal way to create a
* CallReceiver is using JS::CallReceiverFromVp:
*
* static bool
* FunctionReturningThis(JSContext *cx, unsigned argc, JS::Value *vp)
* {
* JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
*
* // Access to the callee must occur before accessing/setting
* // the return value.
* JSObject &callee = rec.callee();
* rec.rval().set(JS::ObjectValue(callee));
*
* // callee() and calleev() will now assert.
*
* // It's always fine to access thisv().
* HandleValue thisv = rec.thisv();
* rec.rval().set(thisv);
*
* // As the return value was last set to |this|, returns |this|.
* return true;
* }
*
* A note on JS_ComputeThis and JS_THIS_OBJECT: these methods currently aren't
* part of the CallReceiver interface. We will likely add them at some point.
* Until then, you should probably continue using |vp| directly for these two
* cases.
*
* CallReceiver is exposed publicly and used internally. Not all parts of its
* public interface are meant to be used by embedders! See inline comments to
* for details.
*/
namespace detail {
/*
* 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);
#ifdef JS_DEBUG
extern JS_PUBLIC_API(void)
CheckIsValidConstructible(Value v);
CheckIsValidConstructible(const Value& v);
#endif
enum UsedRval { IncludeUsedRval, NoUsedRval };
template<UsedRval WantUsedRval>
class MOZ_STACK_CLASS UsedRvalBase;
template<>
class MOZ_STACK_CLASS UsedRvalBase<IncludeUsedRval>
class MOZ_STACK_CLASS IncludeUsedRval
{
protected:
#ifdef JS_DEBUG
mutable bool usedRval_;
void setUsedRval() const { usedRval_ = true; }
void clearUsedRval() const { usedRval_ = false; }
void assertUnusedRval() const { MOZ_ASSERT(!usedRval_); }
#else
void setUsedRval() const {}
void clearUsedRval() const {}
void assertUnusedRval() const {}
#endif
};
template<>
class MOZ_STACK_CLASS UsedRvalBase<NoUsedRval>
class MOZ_STACK_CLASS NoUsedRval
{
protected:
void setUsedRval() const {}
void clearUsedRval() const {}
void assertUnusedRval() const {}
};
template<UsedRval WantUsedRval>
class MOZ_STACK_CLASS CallReceiverBase : public UsedRvalBase<
#ifdef JS_DEBUG
WantUsedRval
#else
NoUsedRval
#endif
>
template<class WantUsedRval>
class MOZ_STACK_CLASS CallArgsBase : public WantUsedRval
{
static_assert(mozilla::IsSame<WantUsedRval, IncludeUsedRval>::value ||
mozilla::IsSame<WantUsedRval, NoUsedRval>::value,
"WantUsedRval can only be IncludeUsedRval or NoUsedRval");
protected:
Value *argv_;
Value* argv_;
unsigned argc_;
bool constructing_;
public:
/*
* Returns the function being called, as an object. Must not be called
* after rval() has been used!
*/
JSObject &callee() const {
MOZ_ASSERT(!this->usedRval_);
return argv_[-2].toObject();
}
// CALLEE ACCESS
/*
* Returns the function being called, as a value. Must not be called after
* rval() has been used!
*/
HandleValue calleev() const {
MOZ_ASSERT(!this->usedRval_);
this->assertUnusedRval();
return HandleValue::fromMarkedLocation(&argv_[-2]);
}
/*
* Returns the function being called, as an object. Must not be called
* after rval() has been used!
*/
JSObject& callee() const {
return calleev().toObject();
}
// CALLING/CONSTRUCTING-DIFFERENTIATIONS
bool isConstructing() const {
if (!argv_[-1].isMagic())
return false;
#ifdef JS_DEBUG
if (!this->usedRval_)
CheckIsValidConstructible(calleev());
#endif
return true;
}
MutableHandleValue newTarget() const {
MOZ_ASSERT(constructing_);
return MutableHandleValue::fromMarkedLocation(&this->argv_[argc_]);
}
/*
* Returns the |this| value passed to the function. This method must not
* be called when the function is being called as a constructor via |new|.
@ -189,128 +182,16 @@ class MOZ_STACK_CLASS CallReceiverBase : public UsedRvalBase<
return HandleValue::fromMarkedLocation(&argv_[-1]);
}
Value computeThis(JSContext *cx) const {
Value computeThis(JSContext* cx) const {
if (thisv().isObject())
return thisv();
return JS_ComputeThis(cx, base());
return ComputeThis(cx, base());
}
bool isConstructing() const {
#ifdef JS_DEBUG
if (this->usedRval_)
CheckIsValidConstructible(calleev());
#endif
return argv_[-1].isMagic();
}
// ARGUMENTS
/*
* Returns the 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 only intended for internal use. Embedders shouldn't
// use them!
Value *base() const { return argv_ - 2; }
Value *spAfterCall() const {
this->setUsedRval();
return argv_ - 1;
}
public:
// These methods are publicly exposed, but they are *not* to be used when
// implementing a JSNative method and encapsulating access to |vp| within
// it. You probably don't want to use these!
void setCallee(Value aCalleev) const {
this->clearUsedRval();
argv_[-2] = aCalleev;
}
void setThis(Value aThisv) const {
argv_[-1] = aThisv;
}
MutableHandleValue mutableThisv() const {
return MutableHandleValue::fromMarkedLocation(&argv_[-1]);
}
};
} // namespace detail
class MOZ_STACK_CLASS CallReceiver : public detail::CallReceiverBase<detail::IncludeUsedRval>
{
private:
friend CallReceiver CallReceiverFromVp(Value *vp);
friend CallReceiver CallReceiverFromArgv(Value *argv);
};
MOZ_ALWAYS_INLINE CallReceiver
CallReceiverFromArgv(Value *argv)
{
CallReceiver receiver;
receiver.clearUsedRval();
receiver.argv_ = argv;
return receiver;
}
MOZ_ALWAYS_INLINE CallReceiver
CallReceiverFromVp(Value *vp)
{
return CallReceiverFromArgv(vp + 2);
}
/*
* JS::CallArgs encapsulates everything JS::CallReceiver does, plus access to
* the function call's arguments. The principal way to create a CallArgs is
* like so, using JS::CallArgsFromVp:
*
* static bool
* FunctionReturningArgcTimesArg0(JSContext *cx, unsigned argc, JS::Value *vp)
* {
* JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
*
* // Guard against no arguments or a non-numeric arg0.
* if (args.length() == 0 || !args[0].isNumber()) {
* args.rval().setInt32(0);
* return true;
* }
*
* args.rval().set(JS::NumberValue(args.length() * args[0].toNumber()));
* return true;
* }
*
* CallArgs is exposed publicly and used internally. Not all parts of its
* public interface are meant to be used by embedders! See inline comments to
* for details.
*/
namespace detail {
template<UsedRval WantUsedRval>
class MOZ_STACK_CLASS CallArgsBase :
public mozilla::Conditional<WantUsedRval == detail::IncludeUsedRval,
CallReceiver,
CallReceiverBase<NoUsedRval> >::Type
{
protected:
unsigned argc_;
public:
/* Returns the number of arguments. */
/* Returns the number of arguments. */
unsigned length() const { return argc_; }
/* Returns the i-th zero-indexed argument. */
@ -337,13 +218,60 @@ class MOZ_STACK_CLASS CallArgsBase :
return i < argc_ && !this->argv_[i].isUndefined();
}
public:
// These methods are publicly exposed, but we're less sure of the interface
// here than we'd like (because they're hackish and drop assertions). Try
// to avoid using these if you can.
// RETURN VALUE
Value *array() const { return this->argv_; }
Value *end() const { return this->argv_ + argc_; }
/*
* 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
@ -351,55 +279,78 @@ class MOZ_STACK_CLASS CallArgsBase :
class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase<detail::IncludeUsedRval>
{
private:
friend CallArgs CallArgsFromVp(unsigned argc, Value *vp);
friend CallArgs CallArgsFromSp(unsigned argc, Value *sp);
friend CallArgs CallArgsFromVp(unsigned argc, Value* vp);
friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing);
static CallArgs create(unsigned argc, Value *argv) {
static CallArgs create(unsigned argc, Value* argv, bool constructing) {
CallArgs args;
args.clearUsedRval();
args.argv_ = argv;
args.argc_ = argc;
args.constructing_ = constructing;
#ifdef DEBUG
for (unsigned i = 0; i < argc; ++i)
MOZ_ASSERT_IF(argv[i].isMarkable(), !GCThingIsMarkedGray(GCCellPtr(argv[i])));
#endif
return args;
}
public:
/*
* Returns true if there are at least |required| arguments passed in. If
* false, it reports an error message on the context.
*/
bool requireAtLeast(JSContext* cx, const char* fnname, unsigned required) const;
};
MOZ_ALWAYS_INLINE CallArgs
CallArgsFromVp(unsigned argc, Value *vp)
CallArgsFromVp(unsigned argc, Value* vp)
{
return CallArgs::create(argc, vp + 2);
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 argc, Value *sp)
CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing = false)
{
return CallArgs::create(argc, sp - argc);
return CallArgs::create(stackSlots - constructing, sp - stackSlots, constructing);
}
} // namespace JS
/*
* Macros to hide interpreter stack layout details from a JSNative using its
* JS::Value *vp parameter. DO NOT USE THESE! Instead use JS::CallArgs and
* JS::Value* vp parameter. DO NOT USE THESE! Instead use JS::CallArgs and
* friends, above. These macros will be removed when we change JSNative to
* take a const JS::CallArgs&.
*/
#define JS_THIS_OBJECT(cx,vp) (JS_THIS(cx,vp).toObjectOrNull())
/*
* Return |this| if |this| is an object. Otherwise, return the global object
* if |this| is null or undefined, and finally return a boxed version of any
* other primitive.
*
* Note: if this method returns null, an error has occurred and must be
* propagated or caught.
*/
MOZ_ALWAYS_INLINE JS::Value
JS_THIS(JSContext *cx, JS::Value *vp)
JS_THIS(JSContext* cx, JS::Value* vp)
{
return vp[1].isPrimitive() ? JS_ComputeThis(cx, vp) : vp[1];
return vp[1].isPrimitive() ? JS::detail::ComputeThis(cx, vp) : vp[1];
}
/*
* A note on JS_THIS_OBJECT: no equivalent method is part of the CallArgs
* interface, and we're unlikely to add one (functions shouldn't be implicitly
* exposing the global object to arbitrary callers). Continue using |vp|
* directly for this case, but be aware this API will eventually be replaced
* with a function that operates directly upon |args.thisv()|.
*/
#define JS_THIS_OBJECT(cx,vp) (JS_THIS(cx,vp).toObjectOrNull())
/*
* |this| is passed to functions in ES5 without change. Functions themselves
* do any post-processing they desire to box |this|, compute the global object,

View File

@ -18,13 +18,13 @@ typedef bool (*IsAcceptableThis)(HandleValue v);
// Implements the guts of a method; guaranteed to be provided an acceptable
// this-value, as determined by a corresponding IsAcceptableThis method.
typedef bool (*NativeImpl)(JSContext *cx, CallArgs args);
typedef bool (*NativeImpl)(JSContext* cx, const CallArgs& args);
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, CallArgs args);
CallMethodIfWrapped(JSContext* cx, IsAcceptableThis test, NativeImpl impl, const CallArgs& args);
} // namespace detail
@ -44,7 +44,7 @@ CallMethodIfWrapped(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallA
// static const JSClass AnswerClass = { ... };
//
// static bool
// IsAnswerObject(const Value &v)
// IsAnswerObject(const Value& v)
// {
// if (!v.isObject())
// return false;
@ -57,7 +57,7 @@ CallMethodIfWrapped(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallA
// its interface is the same as that of JSNative.
//
// static bool
// answer_getAnswer_impl(JSContext *cx, JS::CallArgs args)
// answer_getAnswer_impl(JSContext* cx, JS::CallArgs args)
// {
// args.rval().setInt32(42);
// return true;
@ -70,7 +70,7 @@ CallMethodIfWrapped(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallA
// declared below, passing the appropriate template and runtime arguments.
//
// static bool
// answer_getAnswer(JSContext *cx, unsigned argc, JS::Value *vp)
// answer_getAnswer(JSContext* cx, unsigned argc, JS::Value* vp)
// {
// JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
// return JS::CallNonGenericMethod<IsAnswerObject, answer_getAnswer_impl>(cx, args);
@ -93,7 +93,7 @@ CallMethodIfWrapped(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallA
//
template<IsAcceptableThis Test, NativeImpl Impl>
MOZ_ALWAYS_INLINE bool
CallNonGenericMethod(JSContext *cx, CallArgs args)
CallNonGenericMethod(JSContext* cx, const CallArgs& args)
{
HandleValue thisv = args.thisv();
if (Test(thisv))
@ -103,7 +103,7 @@ CallNonGenericMethod(JSContext *cx, CallArgs args)
}
MOZ_ALWAYS_INLINE bool
CallNonGenericMethod(JSContext *cx, IsAcceptableThis Test, NativeImpl Impl, CallArgs args)
CallNonGenericMethod(JSContext* cx, IsAcceptableThis Test, NativeImpl Impl, const CallArgs& args)
{
HandleValue thisv = args.thisv();
if (Test(thisv))

View File

@ -7,15 +7,14 @@
#ifndef js_CharacterEncoding_h
#define js_CharacterEncoding_h
#include "mozilla/NullPtr.h"
#include "mozilla/Range.h"
#include "js/TypeDecls.h"
#include "js/Utility.h"
namespace js {
struct ThreadSafeContext;
}
class ExclusiveContext;
} // namespace js
class JSFlatString;
@ -32,13 +31,15 @@ class Latin1Chars : public mozilla::Range<Latin1Char>
typedef mozilla::Range<Latin1Char> Base;
public:
using CharT = Latin1Char;
Latin1Chars() : Base() {}
Latin1Chars(char *aBytes, size_t aLength) : Base(reinterpret_cast<Latin1Char *>(aBytes), aLength) {}
Latin1Chars(const Latin1Char *aBytes, size_t aLength)
: Base(const_cast<Latin1Char *>(aBytes), aLength)
Latin1Chars(char* aBytes, size_t aLength) : Base(reinterpret_cast<Latin1Char*>(aBytes), aLength) {}
Latin1Chars(const Latin1Char* aBytes, size_t aLength)
: Base(const_cast<Latin1Char*>(aBytes), aLength)
{}
Latin1Chars(const char *aBytes, size_t aLength)
: Base(reinterpret_cast<Latin1Char *>(const_cast<char *>(aBytes)), aLength)
Latin1Chars(const char* aBytes, size_t aLength)
: Base(reinterpret_cast<Latin1Char*>(const_cast<char*>(aBytes)), aLength)
{}
};
@ -50,15 +51,17 @@ class Latin1CharsZ : public mozilla::RangedPtr<Latin1Char>
typedef mozilla::RangedPtr<Latin1Char> Base;
public:
using CharT = Latin1Char;
Latin1CharsZ() : Base(nullptr, 0) {}
Latin1CharsZ(char *aBytes, size_t aLength)
: Base(reinterpret_cast<Latin1Char *>(aBytes), aLength)
Latin1CharsZ(char* aBytes, size_t aLength)
: Base(reinterpret_cast<Latin1Char*>(aBytes), aLength)
{
MOZ_ASSERT(aBytes[aLength] == '\0');
}
Latin1CharsZ(Latin1Char *aBytes, size_t aLength)
Latin1CharsZ(Latin1Char* aBytes, size_t aLength)
: Base(aBytes, aLength)
{
MOZ_ASSERT(aBytes[aLength] == '\0');
@ -66,7 +69,7 @@ class Latin1CharsZ : public mozilla::RangedPtr<Latin1Char>
using Base::operator=;
char *c_str() { return reinterpret_cast<char *>(get()); }
char* c_str() { return reinterpret_cast<char*>(get()); }
};
class UTF8Chars : public mozilla::Range<unsigned char>
@ -74,12 +77,14 @@ class UTF8Chars : public mozilla::Range<unsigned char>
typedef mozilla::Range<unsigned char> Base;
public:
using CharT = unsigned char;
UTF8Chars() : Base() {}
UTF8Chars(char *aBytes, size_t aLength)
: Base(reinterpret_cast<unsigned char *>(aBytes), aLength)
UTF8Chars(char* aBytes, size_t aLength)
: Base(reinterpret_cast<unsigned char*>(aBytes), aLength)
{}
UTF8Chars(const char *aBytes, size_t aLength)
: Base(reinterpret_cast<unsigned char *>(const_cast<char *>(aBytes)), aLength)
UTF8Chars(const char* aBytes, size_t aLength)
: Base(reinterpret_cast<unsigned char*>(const_cast<char*>(aBytes)), aLength)
{}
};
@ -91,15 +96,17 @@ class UTF8CharsZ : public mozilla::RangedPtr<unsigned char>
typedef mozilla::RangedPtr<unsigned char> Base;
public:
using CharT = unsigned char;
UTF8CharsZ() : Base(nullptr, 0) {}
UTF8CharsZ(char *aBytes, size_t aLength)
: Base(reinterpret_cast<unsigned char *>(aBytes), aLength)
UTF8CharsZ(char* aBytes, size_t aLength)
: Base(reinterpret_cast<unsigned char*>(aBytes), aLength)
{
MOZ_ASSERT(aBytes[aLength] == '\0');
}
UTF8CharsZ(unsigned char *aBytes, size_t aLength)
UTF8CharsZ(unsigned char* aBytes, size_t aLength)
: Base(aBytes, aLength)
{
MOZ_ASSERT(aBytes[aLength] == '\0');
@ -107,7 +114,44 @@ class UTF8CharsZ : public mozilla::RangedPtr<unsigned char>
using Base::operator=;
char *c_str() { return reinterpret_cast<char *>(get()); }
char* c_str() { return reinterpret_cast<char*>(get()); }
};
/*
* A wrapper for a "const char*" that is encoded using UTF-8.
* This class does not manage ownership of the data; that is left
* to others. This differs from UTF8CharsZ in that the chars are
* const and it allows assignment.
*/
class ConstUTF8CharsZ
{
const char* data_;
public:
using CharT = unsigned char;
ConstUTF8CharsZ() : data_(nullptr)
{}
ConstUTF8CharsZ(const char* aBytes, size_t aLength)
: data_(aBytes)
{
MOZ_ASSERT(aBytes[aLength] == '\0');
#ifdef DEBUG
validate(aLength);
#endif
}
const void* get() const { return data_; }
const char* c_str() const { return data_; }
explicit operator bool() const { return data_ != nullptr; }
private:
#ifdef DEBUG
void validate(size_t aLength);
#endif
};
/*
@ -118,27 +162,31 @@ class UTF8CharsZ : public mozilla::RangedPtr<unsigned char>
* manually interpreting UTF-16 extension characters embedded in the JS
* string.
*/
class TwoByteChars : public mozilla::Range<jschar>
class TwoByteChars : public mozilla::Range<char16_t>
{
typedef mozilla::Range<jschar> Base;
typedef mozilla::Range<char16_t> Base;
public:
using CharT = char16_t;
TwoByteChars() : Base() {}
TwoByteChars(jschar *aChars, size_t aLength) : Base(aChars, aLength) {}
TwoByteChars(const jschar *aChars, size_t aLength) : Base(const_cast<jschar *>(aChars), aLength) {}
TwoByteChars(char16_t* aChars, size_t aLength) : Base(aChars, aLength) {}
TwoByteChars(const char16_t* aChars, size_t aLength) : Base(const_cast<char16_t*>(aChars), aLength) {}
};
/*
* A TwoByteChars, but \0 terminated for compatibility with JSFlatString.
*/
class TwoByteCharsZ : public mozilla::RangedPtr<jschar>
class TwoByteCharsZ : public mozilla::RangedPtr<char16_t>
{
typedef mozilla::RangedPtr<jschar> Base;
typedef mozilla::RangedPtr<char16_t> Base;
public:
using CharT = char16_t;
TwoByteCharsZ() : Base(nullptr, 0) {}
TwoByteCharsZ(jschar *chars, size_t length)
TwoByteCharsZ(char16_t* chars, size_t length)
: Base(chars, length)
{
MOZ_ASSERT(chars[length] == '\0');
@ -147,25 +195,22 @@ class TwoByteCharsZ : public mozilla::RangedPtr<jschar>
using Base::operator=;
};
typedef mozilla::RangedPtr<const jschar> ConstCharPtr;
typedef mozilla::RangedPtr<const char16_t> ConstCharPtr;
/*
* Like TwoByteChars, but the chars are const.
*/
class ConstTwoByteChars : public mozilla::RangedPtr<const jschar>
class ConstTwoByteChars : public mozilla::Range<const char16_t>
{
typedef mozilla::Range<const char16_t> Base;
public:
ConstTwoByteChars(const ConstTwoByteChars &s) : ConstCharPtr(s) {}
MOZ_IMPLICIT ConstTwoByteChars(const mozilla::RangedPtr<const jschar> &s) : ConstCharPtr(s) {}
ConstTwoByteChars(const jschar *s, size_t len) : ConstCharPtr(s, len) {}
ConstTwoByteChars(const jschar *pos, const jschar *start, size_t len)
: ConstCharPtr(pos, start, len)
{}
using CharT = char16_t;
using ConstCharPtr::operator=;
ConstTwoByteChars() : Base() {}
ConstTwoByteChars(const char16_t* aChars, size_t aLength) : Base(aChars, aLength) {}
};
/*
* Convert a 2-byte character sequence to "ISO-Latin-1". This works by
* truncating each 2-byte pair in the sequence to a 1-byte pair. If the source
@ -177,24 +222,37 @@ class ConstTwoByteChars : public mozilla::RangedPtr<const jschar>
* This method cannot trigger GC.
*/
extern Latin1CharsZ
LossyTwoByteCharsToNewLatin1CharsZ(js::ThreadSafeContext *cx,
const mozilla::Range<const jschar> tbchars);
LossyTwoByteCharsToNewLatin1CharsZ(js::ExclusiveContext* cx,
const mozilla::Range<const char16_t> tbchars);
inline Latin1CharsZ
LossyTwoByteCharsToNewLatin1CharsZ(js::ExclusiveContext* cx, const char16_t* begin, size_t length)
{
const mozilla::Range<const char16_t> tbchars(begin, length);
return JS::LossyTwoByteCharsToNewLatin1CharsZ(cx, tbchars);
}
template <typename CharT>
extern UTF8CharsZ
CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, const mozilla::Range<const CharT> chars);
CharsToNewUTF8CharsZ(js::ExclusiveContext* maybeCx, const mozilla::Range<CharT> chars);
uint32_t
Utf8ToOneUcs4Char(const uint8_t *utf8Buffer, int utf8Length);
Utf8ToOneUcs4Char(const uint8_t* utf8Buffer, int utf8Length);
/*
* Inflate bytes in UTF-8 encoding to jschars.
* Inflate bytes in UTF-8 encoding to char16_t.
* - On error, returns an empty TwoByteCharsZ.
* - On success, returns a malloc'd TwoByteCharsZ, and updates |outlen| to hold
* its length; the length value excludes the trailing null.
*/
extern TwoByteCharsZ
UTF8CharsToNewTwoByteCharsZ(JSContext *cx, const UTF8Chars utf8, size_t *outlen);
UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen);
/*
* Like UTF8CharsToNewTwoByteCharsZ, but for ConstUTF8CharsZ.
*/
extern TwoByteCharsZ
UTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen);
/*
* The same as UTF8CharsToNewTwoByteCharsZ(), except that any malformed UTF-8 characters
@ -202,25 +260,79 @@ UTF8CharsToNewTwoByteCharsZ(JSContext *cx, const UTF8Chars utf8, size_t *outlen)
* input.
*/
extern TwoByteCharsZ
LossyUTF8CharsToNewTwoByteCharsZ(JSContext *cx, const UTF8Chars utf8, size_t *outlen);
LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen);
extern 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);
GetDeflatedUTF8StringLength(JSFlatString* s);
/*
* Encode |src| as UTF8. The caller must ensure |dst| has enough space.
* Does not write the null terminator.
* Encode |src| as UTF8. The caller must either ensure |dst| has enough space
* to encode the entire string or pass the length of the buffer as |dstlenp|,
* in which case the function will encode characters from the string until
* the buffer is exhausted. Does not write the null terminator.
*
* If |dstlenp| is provided, it will be updated to hold the number of bytes
* written to the buffer. If |numcharsp| is provided, it will be updated to hold
* the number of Unicode characters written to the buffer (which can be less
* than the length of the string, if the buffer is exhausted before the string
* is fully encoded).
*/
JS_PUBLIC_API(void)
DeflateStringToUTF8Buffer(JSFlatString *src, mozilla::RangedPtr<char> dst);
DeflateStringToUTF8Buffer(JSFlatString* src, mozilla::RangedPtr<char> dst,
size_t* dstlenp = nullptr, size_t* numcharsp = nullptr);
/*
* The smallest character encoding capable of fully representing a particular
* string.
*/
enum class SmallestEncoding {
ASCII,
Latin1,
UTF16
};
/*
* Returns the smallest encoding possible for the given string: if all
* codepoints are <128 then ASCII, otherwise if all codepoints are <256
* Latin-1, else UTF16.
*/
JS_PUBLIC_API(SmallestEncoding)
FindSmallestEncoding(UTF8Chars utf8);
/*
* Return a null-terminated Latin-1 string copied from the input string,
* storing its length (excluding null terminator) in |*outlen|. Fail and
* report an error if the string contains non-Latin-1 codepoints. Returns
* Latin1CharsZ() on failure.
*/
extern Latin1CharsZ
UTF8CharsToNewLatin1CharsZ(JSContext* cx, const UTF8Chars utf8, size_t* outlen);
/*
* Return a null-terminated Latin-1 string copied from the input string,
* storing its length (excluding null terminator) in |*outlen|. Non-Latin-1
* codepoints are replaced by '?'. Returns Latin1CharsZ() on failure.
*/
extern 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 bool
StringIsASCII(const char* s);
} // 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()); }
inline void JS_free(JS::Latin1CharsZ& ptr) { js_free((void*)ptr.get()); }
inline void JS_free(JS::UTF8CharsZ& ptr) { js_free((void*)ptr.get()); }
#endif /* js_CharacterEncoding_h */

1075
android/arm64-v8a/include/spidermonkey/js/Class.h Executable file → Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,581 @@
/* -*- 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/. */
/* ECMAScript conversion operations. */
#ifndef js_Conversions_h
#define js_Conversions_h
#include "mozilla/Casting.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/TypeTraits.h"
#include <math.h>
#include "jspubtd.h"
#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);
/* DO NOT CALL THIS. Use JS::ToNumber. */
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);
/* DO NOT CALL THIS. Use JS::ToUint8. */
extern JS_PUBLIC_API(bool)
ToUint8Slow(JSContext *cx, JS::HandleValue v, uint8_t *out);
/* DO NOT CALL THIS. Use JS::ToInt16. */
extern JS_PUBLIC_API(bool)
ToInt16Slow(JSContext *cx, JS::HandleValue v, int16_t *out);
/* DO NOT CALL THIS. Use JS::ToInt32. */
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);
/* DO NOT CALL THIS. Use JS::ToUint16. */
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);
/* DO NOT CALL THIS. Use JS::ToUint64. */
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);
/* DO NOT CALL THIS. Use JS::ToObject. */
extern JS_PUBLIC_API(JSObject*)
ToObjectSlow(JSContext* cx, JS::HandleValue v, bool reportScanStack);
} // namespace js
namespace JS {
namespace detail {
#ifdef JS_DEBUG
/**
* Assert that we're not doing GC on cx, that we're in a request as
* 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);
#else
inline void AssertArgumentsAreSane(JSContext* cx, HandleValue v)
{}
#endif /* JS_DEBUG */
} // namespace detail
/**
* ES6 draft 20141224, 7.1.1, second algorithm.
*
* Most users shouldn't call this -- use JS::ToBoolean, ToNumber, or ToString
* instead. This will typically only be called from custom convert hooks that
* 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);
/* 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;
/* 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);
}
/* 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;
}
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);
}
/* 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);
}
/* 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);
}
/* 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);
}
/* 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);
}
/* ES6 ECMA-262, 7.1.10 */
MOZ_ALWAYS_INLINE bool
ToUint8(JSContext *cx, JS::HandleValue v, uint8_t *out)
{
detail::AssertArgumentsAreSane(cx, v);
if (v.isInt32()) {
*out = uint8_t(v.toInt32());
return true;
}
return js::ToUint8Slow(cx, v, out);
}
/*
* Non-standard, with behavior similar to that of ToInt32, except in its
* producing an int64_t.
*/
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);
}
/* 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);
}
/* 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);
}
namespace detail {
/*
* Convert a double value to ResultType (an unsigned integral type) using
* ECMAScript-style semantics (that is, in like manner to how ECMAScript's
* ToInt32 converts to int32_t).
*
* If d is infinite or NaN, return 0.
* Otherwise compute d2 = sign(d) * floor(abs(d)), and return the ResultType
* value congruent to d2 mod 2**(bit width of ResultType).
*
* The algorithm below is inspired by that found in
* <http://trac.webkit.org/changeset/67825/trunk/JavaScriptCore/runtime/JSValue.cpp>
* but has been generalized to all integer widths.
*/
template<typename ResultType>
inline ResultType
ToUintWidth(double d)
{
static_assert(mozilla::IsUnsigned<ResultType>::value,
"ResultType must be an unsigned type");
uint64_t bits = mozilla::BitwiseCast<uint64_t>(d);
unsigned DoubleExponentShift = mozilla::FloatingPoint<double>::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<double>::kExponentBits) >> DoubleExponentShift) -
int_fast16_t(mozilla::FloatingPoint<double>::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<uint_fast16_t>(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<double>::kSignBit) ? ~result + 1 : result;
}
template<typename ResultType>
inline ResultType
ToIntWidth(double d)
{
static_assert(mozilla::IsSigned<ResultType>::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<ResultType>::Type UnsignedResult;
UnsignedResult u = ToUintWidth<UnsignedResult>(d);
if (u <= UnsignedResult(MaxValue))
return static_cast<ResultType>(u);
return (MinValue + static_cast<ResultType>(u - MaxValue)) - 1;
}
} // 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;
#else
return detail::ToIntWidth<int32_t>(d);
#endif
}
/* ES5 9.6 (specialized for doubles). */
inline uint32_t
ToUint32(double d)
{
return detail::ToUintWidth<uint32_t>(d);
}
/* WEBIDL 4.2.4 */
inline int8_t
ToInt8(double d)
{
return detail::ToIntWidth<int8_t>(d);
}
/* ECMA-262 7.1.10 ToUInt8() specialized for doubles. */
inline int8_t
ToUint8(double d)
{
return detail::ToUintWidth<uint8_t>(d);
}
/* WEBIDL 4.2.6 */
inline int16_t
ToInt16(double d)
{
return detail::ToIntWidth<int16_t>(d);
}
inline uint16_t
ToUint16(double d)
{
return detail::ToUintWidth<uint16_t>(d);
}
/* WEBIDL 4.2.10 */
inline int64_t
ToInt64(double d)
{
return detail::ToIntWidth<int64_t>(d);
}
/* WEBIDL 4.2.11 */
inline uint64_t
ToUint64(double d)
{
return detail::ToUintWidth<uint64_t>(d);
}
} // namespace JS
#endif /* js_Conversions_h */

141
android/arm64-v8a/include/spidermonkey/js/Date.h Executable file → Normal file
View File

@ -3,15 +3,134 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* JavaScript date/time computation and creation functions. */
#ifndef js_Date_h
#define js_Date_h
#include "jstypes.h"
/*
* Dates in JavaScript are defined by IEEE-754 double precision numbers from
* the set:
*
* { t : -8.64e15 t +8.64e15 } { NaN }
*
* The single NaN value represents any invalid-date value. All other values
* represent idealized durations in milliseconds since the UTC epoch. (Leap
* seconds are ignored; leap days are not.) +0 is the only zero in this set.
* The limit represented by 8.64e15 milliseconds is 100 million days either
* side of 00:00 January 1, 1970 UTC.
*
* Dates in the above set are represented by the |ClippedTime| class. The
* double type is a superset of the above set, so it *may* (but need not)
* represent a date. Use ECMAScript's |TimeClip| method to produce a date from
* a double.
*
* Date *objects* are simply wrappers around |TimeClip|'d numbers, with a bunch
* of accessor methods to the various aspects of the represented date.
*/
#include "mozilla/FloatingPoint.h"
#include "mozilla/MathAlgorithms.h"
#include "js/Conversions.h"
#include "js/Value.h"
struct JSContext;
namespace JS {
// Year is a year, month is 0-11, day is 1-based. The return value is
// a number of milliseconds since the epoch. Can return NaN.
/**
* Re-query the system to determine the current time zone adjustment from UTC,
* including any component due to DST. If the time zone has changed, this will
* cause all Date object non-UTC methods and formatting functions to produce
* appropriately adjusted results.
*
* Left to its own devices, SpiderMonkey itself may occasionally call this
* method to attempt to keep up with system time changes. However, no
* particular frequency of checking is guaranteed. Embedders unable to accept
* occasional inaccuracies should call this method in response to system time
* changes, or immediately before operations requiring instantaneous
* correctness, to guarantee correct behavior.
*/
extern JS_PUBLIC_API(void)
ResetTimeZone();
class ClippedTime;
inline ClippedTime TimeClip(double time);
/*
* |ClippedTime| represents the limited subset of dates/times described above.
*
* An invalid date/time may be created through the |ClippedTime::invalid|
* method. Otherwise, a |ClippedTime| may be created using the |TimeClip|
* method.
*
* In typical use, the user might wish to manipulate a timestamp. The user
* performs a series of operations on it, but the final value might not be a
* date as defined above -- it could have overflowed, acquired a fractional
* component, &c. So as a *final* step, the user passes that value through
* |TimeClip| to produce a number restricted to JavaScript's date range.
*
* APIs that accept a JavaScript date value thus accept a |ClippedTime|, not a
* double. This ensures that date/time APIs will only ever receive acceptable
* 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;
explicit ClippedTime(double time) : t(time) {}
friend ClippedTime TimeClip(double time);
public:
// Create an invalid date.
ClippedTime() : t(mozilla::UnspecifiedNaN<double>()) {}
// Create an invalid date/time, more explicitly; prefer this to the default
// constructor.
static ClippedTime invalid() { return ClippedTime(); }
double toDouble() const { return 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<double>());
// 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()));
}
// 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);
// 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);
@ -30,6 +149,22 @@ MonthFromTime(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.
// NOTE: The calculation performed by this function is literally that given in
// the ECMAScript specification. Nonfinite years, years containing fractional
// components, and years outside ECMAScript's date range are not handled with
// any particular intelligence. Garbage in, garbage out.
JS_PUBLIC_API(double)
DayFromYear(double year);
// Takes an integer number of milliseconds since the epoch and an integer year,
// returns the number of days in that year. If |time| is nonfinite, returns NaN.
// Otherwise |time| *must* correspond to a time within the valid year |year|.
// This should usually be ensured by computing |year| as |JS::DayFromYear(time)|.
JS_PUBLIC_API(double)
DayWithinYear(double time, double year);
} // namespace JS
#endif /* js_Date_h */

View File

@ -0,0 +1,384 @@
/* -*- 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/. */
// Interfaces by which the embedding can interact with the Debugger API.
#ifndef js_Debug_h
#define js_Debug_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
#include "jsapi.h"
#include "jspubtd.h"
#include "js/GCAPI.h"
#include "js/RootingAPI.h"
#include "js/TypeDecls.h"
namespace js {
class Debugger;
} // namespace js
namespace JS {
namespace dbg {
// Helping embedding code build objects for Debugger
// -------------------------------------------------
//
// Some Debugger API features lean on the embedding application to construct
// their result values. For example, Debugger.Frame.prototype.scriptEntryReason
// calls hooks provided by the embedding to construct values explaining why it
// invoked JavaScript; if F is a frame called from a mouse click event handler,
// F.scriptEntryReason would return an object of the form:
//
// { eventType: "mousedown", event: <object> }
//
// where <object> is a Debugger.Object whose referent is the event being
// dispatched.
//
// However, Debugger implements a trust boundary. Debuggee code may be
// considered untrusted; debugger code needs to be protected from debuggee
// getters, setters, proxies, Object.watch watchpoints, and any other feature
// that might accidentally cause debugger code to set the debuggee running. The
// Debugger API tries to make it easy to write safe debugger code by only
// offering access to debuggee objects via Debugger.Object instances, which
// ensure that only those operations whose explicit purpose is to invoke
// debuggee code do so. But this protective membrane is only helpful if we
// interpose Debugger.Object instances in all the necessary spots.
//
// SpiderMonkey's compartment system also implements a trust boundary. The
// debuggee and debugger are always in different compartments. Inter-compartment
// work requires carefully tracking which compartment each JSObject or JS::Value
// belongs to, and ensuring that is is correctly wrapped for each operation.
//
// It seems precarious to expect the embedding's hooks to implement these trust
// boundaries. Instead, the JS::dbg::Builder API segregates the code which
// constructs trusted objects from that which deals with untrusted objects.
// Trusted objects have an entirely different C++ type, so code that improperly
// mixes trusted and untrusted objects is caught at compile time.
//
// In the structure shown above, there are two trusted objects, and one
// untrusted object:
//
// - The overall object, with the 'eventType' and 'event' properties, is a
// trusted object. We're going to return it to D.F.p.scriptEntryReason's
// caller, which will handle it directly.
//
// - The Debugger.Object instance appearing as the value of the 'event' property
// is a trusted object. It belongs to the same Debugger instance as the
// Debugger.Frame instance whose scriptEntryReason accessor was called, and
// presents a safe reflection-oriented API for inspecting its referent, which
// is:
//
// - The actual event object, an untrusted object, and the referent of the
// Debugger.Object above. (Content can do things like replacing accessors on
// Event.prototype.)
//
// Using JS::dbg::Builder, all objects and values the embedding deals with
// directly are considered untrusted, and are assumed to be debuggee values. The
// only way to construct trusted objects is to use Builder's own methods, which
// return a separate Object type. The only way to set a property on a trusted
// object is through that Object type. The actual trusted object is never
// exposed to the embedding.
//
// So, for example, the embedding might use code like the following to construct
// the object shown above, given a Builder passed to it by Debugger:
//
// bool
// MyScriptEntryReason::explain(JSContext* cx,
// Builder& builder,
// Builder::Object& result)
// {
// JSObject* eventObject = ... obtain debuggee event object somehow ...;
// if (!eventObject)
// return false;
// result = builder.newObject(cx);
// return result &&
// result.defineProperty(cx, "eventType", SafelyFetchType(eventObject)) &&
// result.defineProperty(cx, "event", eventObject);
// }
//
//
// Object::defineProperty also accepts an Object as the value to store on the
// property. By its type, we know that the value is trusted, so we set it
// directly as the property's value, without interposing a Debugger.Object
// wrapper. This allows the embedding to builted nested structures of trusted
// objects.
//
// The Builder and Builder::Object methods take care of doing whatever
// compartment switching and wrapping are necessary to construct the trusted
// values in the Debugger's compartment.
//
// The Object type is self-rooting. Construction, assignment, and destruction
// all properly root the referent object.
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.
#if DEBUG
void assertBuilt(JSObject* obj);
#else
void assertBuilt(JSObject* obj) { }
#endif
protected:
// A reference to a trusted object or value. At the moment, we only use it
// with JSObject*.
template<typename T>
class BuiltThing {
friend class BuilderOrigin;
protected:
// The Builder to which this trusted thing belongs.
Builder& owner;
// A rooted reference to our value.
PersistentRooted<T> value;
BuiltThing(JSContext* cx, Builder& owner_, T value_ = GCPolicy<T>::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<Value>, 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<JSObject*> {
friend class Builder; // for construction
friend class BuilderOrigin; // for unwrapping
typedef BuiltThing<JSObject*> 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);
};
// Debugger itself instantiates this subclass of Builder, which can unwrap
// BuiltThings that belong to it.
class BuilderOrigin : public Builder {
template<typename T>
T unwrapAny(const BuiltThing<T>& 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); }
};
// Finding the size of blocks allocated with malloc
// ------------------------------------------------
//
// Debugger.Memory wants to be able to report how many bytes items in memory are
// consuming. To do this, it needs a function that accepts a pointer to a block,
// and returns the number of bytes allocated to that block. SpiderMonkey itself
// doesn't know which function is appropriate to use, but the embedding does.
// Tell Debuggers in |cx| to use |mallocSizeOf| to find the size of
// malloc'd blocks.
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);
// Debugger and Garbage Collection Events
// --------------------------------------
//
// The Debugger wants to report about its debuggees' GC cycles, however entering
// JS after a GC is troublesome since SpiderMonkey will often do something like
// force a GC and then rely on the nursery being empty. If we call into some
// Debugger's hook after the GC, then JS runs and the nursery won't be
// empty. Instead, we rely on embedders to call back into SpiderMonkey after a
// GC and notify Debuggers to call their onGarbageCollection hook.
// 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);
// Return true if the given value is a Debugger object, false otherwise.
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);
// Hooks for reporting where JavaScript execution began.
//
// Our performance tools would like to be able to label blocks of JavaScript
// execution with the function name and source location where execution began:
// the event handler, the callback, etc.
//
// Construct an instance of this class on the stack, providing a JSContext
// belonging to the runtime in which execution will occur. Each time we enter
// JavaScript --- specifically, each time we push a JavaScript stack frame that
// has no older JS frames younger than this AutoEntryMonitor --- we will
// call the appropriate |Entry| member function to indicate where we've begun
// execution.
class MOZ_STACK_CLASS 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;
// Execution of the function or script has ended.
virtual void Exit(JSContext* cx) { }
};
} // namespace dbg
} // namespace JS
#endif /* js_Debug_h */

587
android/arm64-v8a/include/spidermonkey/js/GCAPI.h Executable file → Normal file
View File

@ -7,47 +7,67 @@
#ifndef js_GCAPI_h
#define js_GCAPI_h
#include "mozilla/NullPtr.h"
#include "mozilla/Vector.h"
#include "js/GCAnnotations.h"
#include "js/HeapAPI.h"
#include "js/UniquePtr.h"
namespace js {
namespace gc {
class GCRuntime;
}
}
} // namespace gc
namespace gcstats {
struct Statistics;
} // namespace gcstats
} // namespace js
typedef enum JSGCMode {
/* Perform only global GCs. */
/** Perform only global GCs. */
JSGC_MODE_GLOBAL = 0,
/* Perform per-compartment GCs until too much garbage has accumulated. */
JSGC_MODE_COMPARTMENT = 1,
/** Perform per-zone GCs until too much garbage has accumulated. */
JSGC_MODE_ZONE = 1,
/*
/**
* Collect in short time slices rather than all at once. Implies
* JSGC_MODE_COMPARTMENT.
* JSGC_MODE_ZONE.
*/
JSGC_MODE_INCREMENTAL = 2
} JSGCMode;
/**
* Kinds of js_GC invocation.
*/
typedef enum JSGCInvocationKind {
/* Normal invocation. */
GC_NORMAL = 0,
/* Minimize GC triggers and release empty GC chunks right away. */
GC_SHRINK = 1
} JSGCInvocationKind;
namespace JS {
#define GCREASONS(D) \
/* Reasons internal to the JS engine */ \
D(API) \
D(MAYBEGC) \
D(EAGER_ALLOC_TRIGGER) \
D(DESTROY_RUNTIME) \
D(DESTROY_CONTEXT) \
D(UNUSED0) \
D(LAST_DITCH) \
D(TOO_MUCH_MALLOC) \
D(ALLOC_TRIGGER) \
D(DEBUG_GC) \
D(TRANSPLANT) \
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) \
@ -66,10 +86,6 @@ namespace JS {
D(RESERVED13) \
D(RESERVED14) \
D(RESERVED15) \
D(RESERVED16) \
D(RESERVED17) \
D(RESERVED18) \
D(RESERVED19) \
\
/* Reasons from Firefox */ \
D(DOM_WINDOW_UTILS) \
@ -90,7 +106,9 @@ namespace JS {
D(REFRESH_FRAME) \
D(FULL_GC_TIMER) \
D(SHUTDOWN_CC) \
D(FINISH_LARGE_EVALUTE)
D(FINISH_LARGE_EVALUATE) \
D(USER_INACTIVE) \
D(XPCONNECT_SHUTDOWN)
namespace gcreason {
@ -105,12 +123,18 @@ enum Reason {
/*
* 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 26. But the cost of extra buckets seems to be low while the
* 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);
} /* namespace gcreason */
/*
@ -127,39 +151,39 @@ enum Reason {
* all zones. Failing to select any zone is an error.
*/
/*
/**
* Schedule the given zone to be collected as part of the next GC.
*/
extern JS_FRIEND_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_FRIEND_API(void)
PrepareForFullGC(JSRuntime *rt);
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_FRIEND_API(void)
PrepareForIncrementalGC(JSRuntime *rt);
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_FRIEND_API(bool)
IsGCScheduled(JSRuntime *rt);
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_FRIEND_API(void)
SkipZoneForGC(Zone *zone);
extern JS_PUBLIC_API(void)
SkipZoneForGC(Zone* zone);
/*
* Non-Incremental GC:
@ -167,21 +191,17 @@ SkipZoneForGC(Zone *zone);
* The following functions perform a non-incremental GC.
*/
/*
* Performs a non-incremental collection of all selected zones. Some objects
* that are unreachable from the program may still be alive afterwards because
* of internal references.
/**
* Performs a non-incremental collection of all selected zones.
*
* If the gckind argument is GC_NORMAL, then some objects that are unreachable
* from the program may still be alive afterwards because of internal
* references; if GC_SHRINK is passed then caches and other temporary references
* to objects will be cleared and all unreferenced objects will be removed from
* the system.
*/
extern JS_FRIEND_API(void)
GCForReason(JSRuntime *rt, gcreason::Reason reason);
/*
* Perform a non-incremental collection after clearing caches and other
* temporary references to objects. This will remove all unreferenced objects
* in the system.
*/
extern JS_FRIEND_API(void)
ShrinkingGC(JSRuntime *rt, gcreason::Reason reason);
extern JS_PUBLIC_API(void)
GCForReason(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason);
/*
* Incremental GC:
@ -198,34 +218,102 @@ ShrinkingGC(JSRuntime *rt, gcreason::Reason reason);
* JS_GC().
* - The GC mode must have been set to JSGC_MODE_INCREMENTAL with
* JS_SetGCParameter().
* - All native objects that have their own trace hook must indicate that they
* implement read and write barriers with the JSCLASS_IMPLEMENTS_BARRIERS
* flag.
*
* Note: Even if incremental GC is enabled and working correctly,
* non-incremental collections can still happen when low on memory.
*/
/*
* Begin an incremental collection and perform one slice worth of work or
* perform a slice of an ongoing incremental collection. When this function
* returns, the collection is not complete. This function must be called
* repeatedly until !IsIncrementalGCInProgress(rt).
/**
* Begin an incremental collection and perform one slice worth of work. When
* this function returns, the collection may not be complete.
* IncrementalGCSlice() must be called repeatedly until
* !IsIncrementalGCInProgress(cx).
*
* Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or
* shorter than the requested interval.
*/
extern JS_FRIEND_API(void)
IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis = 0);
extern JS_PUBLIC_API(void)
StartIncrementalGC(JSContext* cx, JSGCInvocationKind gckind, gcreason::Reason reason,
int64_t millis = 0);
/*
* If IsIncrementalGCInProgress(rt), this call finishes the ongoing collection
* by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(rt),
* this is equivalent to GCForReason. When this function returns,
* IsIncrementalGCInProgress(rt) will always be false.
/**
* Perform a slice of an ongoing incremental collection. When this function
* returns, the collection may not be complete. It must be called repeatedly
* until !IsIncrementalGCInProgress(cx).
*
* Note: SpiderMonkey's GC is not realtime. Slices in practice may be longer or
* shorter than the requested interval.
*/
extern JS_FRIEND_API(void)
FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason);
extern JS_PUBLIC_API(void)
IncrementalGCSlice(JSContext* cx, gcreason::Reason reason, int64_t millis = 0);
/**
* If IsIncrementalGCInProgress(cx), this call finishes the ongoing collection
* by performing an arbitrarily long slice. If !IsIncrementalGCInProgress(cx),
* this is equivalent to GCForReason. When this function returns,
* IsIncrementalGCInProgress(cx) will always be false.
*/
extern JS_PUBLIC_API(void)
FinishIncrementalGC(JSContext* cx, gcreason::Reason reason);
/**
* If IsIncrementalGCInProgress(cx), this call aborts the ongoing collection and
* performs whatever work needs to be done to return the collector to its idle
* state. This may take an arbitrarily long time. When this function returns,
* IsIncrementalGCInProgress(cx) will always be false.
*/
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<Collection> 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()
{ }
using Ptr = js::UniquePtr<GarbageCollectionEvent>;
static Ptr Create(JSRuntime* rt, ::js::gcstats::Statistics& stats, uint64_t majorGCNumber);
JSObject* toJSObject(JSContext* cx) const;
uint64_t majorGCNumber() const { return majorGCNumber_; }
};
} // namespace dbg
enum GCProgress {
/*
@ -244,37 +332,80 @@ enum GCProgress {
GC_CYCLE_END
};
struct JS_FRIEND_API(GCDescription) {
bool isCompartment_;
struct JS_PUBLIC_API(GCDescription) {
bool isZone_;
JSGCInvocationKind invocationKind_;
gcreason::Reason reason_;
explicit GCDescription(bool isCompartment)
: isCompartment_(isCompartment) {}
GCDescription(bool isZone, JSGCInvocationKind kind, gcreason::Reason reason)
: isZone_(isZone), invocationKind_(kind), reason_(reason) {}
jschar *formatMessage(JSRuntime *rt) const;
jschar *formatJSON(JSRuntime *rt, uint64_t timestamp) const;
char16_t* formatSliceMessage(JSContext* cx) const;
char16_t* formatSummaryMessage(JSContext* cx) const;
char16_t* formatJSON(JSContext* cx, uint64_t timestamp) const;
JS::dbg::GarbageCollectionEvent::Ptr toGCEvent(JSContext* cx) const;
};
typedef void
(* GCSliceCallback)(JSRuntime *rt, GCProgress progress, const GCDescription &desc);
(* GCSliceCallback)(JSContext* cx, GCProgress progress, const GCDescription& desc);
/*
/**
* The GC slice callback is called at the beginning and end of each slice. This
* callback may be used for GC notifications as well as to perform additional
* marking.
*/
extern JS_FRIEND_API(GCSliceCallback)
SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback);
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
};
/**
* A nursery collection callback receives the progress of the nursery collection
* and the reason for the collection.
*/
using GCNurseryCollectionCallback = void(*)(JSContext* cx, GCNurseryProgress progress,
gcreason::Reason reason);
/**
* Set the nursery collection callback for the given runtime. When set, it will
* be called at the start and end of every nursery collection.
*/
extern JS_PUBLIC_API(GCNurseryCollectionCallback)
SetGCNurseryCollectionCallback(JSContext* cx, GCNurseryCollectionCallback callback);
typedef void
(* DoCycleCollectionCallback)(JSContext* cx);
/**
* The purge gray callback is called after any COMPARTMENT_REVIVED GC in which
* the majority of compartments have been marked gray.
*/
extern JS_PUBLIC_API(DoCycleCollectionCallback)
SetDoCycleCollectionCallback(JSContext* cx, DoCycleCollectionCallback callback);
/**
* Incremental GC defaults to enabled, but may be disabled for testing or in
* embeddings that have not yet implemented barriers on their native classes.
* There is not currently a way to re-enable incremental GC once it has been
* disabled on the runtime.
*/
extern JS_FRIEND_API(void)
DisableIncrementalGC(JSRuntime *rt);
extern JS_PUBLIC_API(void)
DisableIncrementalGC(JSContext* cx);
/*
/**
* Returns true if incremental GC is enabled. Simply having incremental GC
* enabled is not sufficient to ensure incremental collections are happening.
* See the comment "Incremental GC" above for reasons why incremental GC may be
@ -282,45 +413,42 @@ DisableIncrementalGC(JSRuntime *rt);
* GCDescription returned by GCSliceCallback may help narrow down the cause if
* collections are not happening incrementally when expected.
*/
extern JS_FRIEND_API(bool)
IsIncrementalGCEnabled(JSRuntime *rt);
extern JS_PUBLIC_API(bool)
IsIncrementalGCEnabled(JSContext* cx);
/*
/**
* Returns true while an incremental GC is ongoing, both when actively
* collecting and between slices.
*/
JS_FRIEND_API(bool)
IsIncrementalGCInProgress(JSRuntime *rt);
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_FRIEND_API(bool)
IsIncrementalBarrierNeeded(JSRuntime *rt);
extern JS_FRIEND_API(bool)
IsIncrementalBarrierNeeded(JSContext *cx);
extern JS_PUBLIC_API(bool)
IsIncrementalBarrierNeeded(JSContext* cx);
/*
* Notify the GC that a reference to a GC thing is about to be overwritten.
* These methods must be called if IsIncrementalBarrierNeeded.
*/
extern JS_FRIEND_API(void)
IncrementalReferenceBarrier(void *ptr, JSGCTraceKind kind);
extern JS_PUBLIC_API(void)
IncrementalReferenceBarrier(GCCellPtr thing);
extern JS_FRIEND_API(void)
IncrementalValueBarrier(const Value &v);
extern JS_PUBLIC_API(void)
IncrementalValueBarrier(const Value& v);
extern JS_FRIEND_API(void)
IncrementalObjectBarrier(JSObject *obj);
extern JS_PUBLIC_API(void)
IncrementalObjectBarrier(JSObject* obj);
/*
/**
* Returns true if the most recent GC ran incrementally.
*/
extern JS_FRIEND_API(bool)
WasIncrementalGC(JSRuntime *rt);
extern JS_PUBLIC_API(bool)
WasIncrementalGC(JSContext* cx);
/*
* Generational GC:
@ -330,75 +458,106 @@ WasIncrementalGC(JSRuntime *rt);
* --enable-gcgenerational.
*/
/* Ensure that generational GC is disabled within some scope. */
class JS_FRIEND_API(AutoDisableGenerationalGC)
/** Ensure that generational GC is disabled within some scope. */
class JS_PUBLIC_API(AutoDisableGenerationalGC)
{
js::gc::GCRuntime *gc;
#if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
bool restartVerifier;
#endif
js::gc::GCRuntime* gc;
public:
explicit AutoDisableGenerationalGC(JSRuntime *rt);
explicit AutoDisableGenerationalGC(JSRuntime* rt);
~AutoDisableGenerationalGC();
};
/*
/**
* Returns true if generational allocation and collection is currently enabled
* on the given runtime.
*/
extern JS_FRIEND_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_FRIEND_API(size_t)
extern JS_PUBLIC_API(size_t)
GetGCNumber();
/*
* The GC does not immediately return the unused memory freed by a collection
* back to the system incase it is needed soon afterwards. This call forces the
* GC to return this memory immediately.
/**
* 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.
*/
extern JS_FRIEND_API(void)
ShrinkGCBuffers(JSRuntime *rt);
/*
* Assert if a GC occurs while this class is live. This class does not disable
* the static rooting hazard analysis.
*/
class JS_PUBLIC_API(AutoAssertOnGC)
class JS_PUBLIC_API(AutoRequireNoGC)
{
#ifdef DEBUG
js::gc::GCRuntime *gc;
protected:
AutoRequireNoGC() {}
~AutoRequireNoGC() {}
};
/**
* Diagnostic assert (see MOZ_DIAGNOSTIC_ASSERT) that GC cannot occur while this
* class is live. This class does not disable the static rooting hazard
* analysis.
*
* This works by entering a GC unsafe region, which is checked on allocation and
* on GC.
*/
class JS_PUBLIC_API(AutoAssertNoGC) : public AutoRequireNoGC
{
js::gc::GCRuntime* gc;
size_t gcNumber;
public:
AutoAssertOnGC();
explicit AutoAssertOnGC(JSRuntime *rt);
~AutoAssertOnGC();
AutoAssertNoGC();
explicit AutoAssertNoGC(JSRuntime* rt);
explicit AutoAssertNoGC(JSContext* cx);
~AutoAssertNoGC();
};
static void VerifyIsSafeToGC(JSRuntime *rt);
/**
* 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();
#else
public:
AutoAssertOnGC() {}
explicit AutoAssertOnGC(JSRuntime *rt) {}
~AutoAssertOnGC() {}
static void VerifyIsSafeToGC(JSRuntime *rt) {}
AutoAssertNoAlloc() {}
explicit AutoAssertNoAlloc(JSContext* cx) {}
void disallowAlloc(JSRuntime* rt) {}
#endif
};
/*
* Disable the static rooting hazard analysis in the live region, but assert if
* any 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.
/**
* 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.
*
* Note: GC behavior is unpredictable even when deterministice and is generally
* Note: GC behavior is unpredictable even when deterministic and is generally
* non-deterministic in practice. The fact that this guard has not
* asserted is not a guarantee that a GC cannot happen in the guarded
* region. As a rule, anyone performing a GC unsafe action should
@ -406,36 +565,115 @@ class JS_PUBLIC_API(AutoAssertOnGC)
* that the hazard analysis is correct for that code, rather than relying
* on this class.
*/
class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertOnGC
class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertNoAlloc
{
public:
AutoSuppressGCAnalysis() : AutoAssertOnGC() {}
explicit AutoSuppressGCAnalysis(JSRuntime *rt) : AutoAssertOnGC(rt) {}
AutoSuppressGCAnalysis() : AutoAssertNoAlloc() {}
explicit AutoSuppressGCAnalysis(JSContext* cx) : AutoAssertNoAlloc(cx) {}
} JS_HAZ_GC_SUPPRESSED;
/**
* Assert that code is only ever called from a GC callback, disable the static
* rooting hazard analysis and assert if any allocation that could potentially
* trigger a GC occurs while this guard object is live.
*
* 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);
};
/*
/**
* Place AutoCheckCannotGC in scopes that you believe can never GC. These
* annotations will be verified both dynamically via AutoAssertOnGC, and
* annotations will be verified both dynamically via AutoAssertNoGC, and
* statically with the rooting hazard analysis (implemented by making the
* analysis consider AutoCheckCannotGC to be a GC pointer, and therefore
* complain if it is live across a GC call.) It is useful when dealing with
* internal pointers to GC things where the GC thing itself may not be present
* for the static analysis: e.g. acquiring inline chars from a JSString* on the
* heap.
*
* We only do the assertion checking in DEBUG builds.
*/
class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertOnGC
#ifdef DEBUG
class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoAssertNoGC
{
public:
AutoCheckCannotGC() : AutoAssertOnGC() {}
explicit AutoCheckCannotGC(JSRuntime *rt) : AutoAssertOnGC(rt) {}
};
AutoCheckCannotGC() : AutoAssertNoGC() {}
explicit AutoCheckCannotGC(JSContext* cx) : AutoAssertNoGC(cx) {}
} JS_HAZ_GC_INVALIDATED;
#else
class JS_PUBLIC_API(AutoCheckCannotGC) : public AutoRequireNoGC
{
public:
AutoCheckCannotGC() {}
explicit AutoCheckCannotGC(JSContext* cx) {}
} JS_HAZ_GC_INVALIDATED;
#endif
/*
/**
* Unsets the gray bit for anything reachable from |thing|. |kind| should not be
* JSTRACE_SHAPE. |thing| should be non-null.
* JS::TraceKind::Shape. |thing| should be non-null. The return value indicates
* if anything was unmarked.
*/
extern JS_FRIEND_API(bool)
UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind);
UnmarkGrayGCThingRecursively(GCCellPtr thing);
} /* namespace JS */
namespace js {
namespace gc {
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);
}
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;
JS::shadow::Runtime* rt = JS::shadow::Runtime::asShadowRuntime(aRt);
MOZ_DIAGNOSTIC_ASSERT(rt->allowGCBarriers());
if (IsIncrementalBarrierNeededOnTenuredGCThing(rt, thing))
JS::IncrementalReferenceBarrier(thing);
}
} /* namespace gc */
} /* namespace js */
namespace JS {
/*
* This should be called when an object that is marked gray is exposed to the JS
@ -444,55 +682,26 @@ UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind);
* we conservatively mark the object black.
*/
static MOZ_ALWAYS_INLINE void
ExposeGCThingToActiveJS(void *thing, JSGCTraceKind kind)
ExposeObjectToActiveJS(JSObject* obj)
{
MOZ_ASSERT(kind != JSTRACE_SHAPE);
shadow::Runtime *rt = js::gc::GetGCThingRuntime(thing);
#ifdef JSGC_GENERATIONAL
/*
* GC things residing in the nursery cannot be gray: they have no mark bits.
* All live objects in the nursery are moved to tenured at the beginning of
* each GC slice, so the gray marker never sees nursery things.
*/
if (js::gc::IsInsideNursery((js::gc::Cell *)thing))
return;
#endif
if (IsIncrementalBarrierNeededOnGCThing(rt, thing, kind))
IncrementalReferenceBarrier(thing, kind);
else if (GCThingIsMarkedGray(thing))
UnmarkGrayGCThingRecursively(thing, kind);
MOZ_ASSERT(obj);
js::gc::ExposeGCThingToActiveJS(GCCellPtr(obj));
}
static MOZ_ALWAYS_INLINE void
ExposeObjectToActiveJS(JSObject *obj)
ExposeScriptToActiveJS(JSScript* script)
{
ExposeGCThingToActiveJS(obj, JSTRACE_OBJECT);
js::gc::ExposeGCThingToActiveJS(GCCellPtr(script));
}
/*
* If a GC is currently marking, mark the object black.
* If a GC is currently marking, mark the string black.
*/
static MOZ_ALWAYS_INLINE void
MarkGCThingAsLive(JSRuntime *rt_, void *thing, JSGCTraceKind kind)
MarkStringAsLive(Zone* zone, JSString* string)
{
shadow::Runtime *rt = shadow::Runtime::asShadowRuntime(rt_);
#ifdef JSGC_GENERATIONAL
/*
* Any object in the nursery will not be freed during any GC running at that time.
*/
if (js::gc::IsInsideNursery((js::gc::Cell *)thing))
return;
#endif
if (IsIncrementalBarrierNeededOnGCThing(rt, thing, kind))
IncrementalReferenceBarrier(thing, kind);
}
static MOZ_ALWAYS_INLINE void
MarkStringAsLive(Zone *zone, JSString *string)
{
JSRuntime *rt = JS::shadow::Zone::asShadowZone(zone)->runtimeFromMainThread();
MarkGCThingAsLive(rt, string, JSTRACE_STRING);
JSRuntime* rt = JS::shadow::Zone::asShadowZone(zone)->runtimeFromMainThread();
js::gc::MarkGCThingAsLive(rt, GCCellPtr(string));
}
/*
@ -501,13 +710,13 @@ MarkStringAsLive(Zone *zone, JSString *string)
* Note: this is not related to the PokeGC in nsJSEnvironment.
*/
extern JS_FRIEND_API(void)
PokeGC(JSRuntime *rt);
PokeGC(JSContext* cx);
/*
* Internal to Firefox.
*/
extern JS_FRIEND_API(void)
NotifyDidPaint(JSRuntime *rt);
NotifyDidPaint(JSContext* cx);
} /* namespace JS */

View File

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef js_GCAnnotations_h
#define js_GCAnnotations_h
// Set of annotations for the rooting hazard analysis, used to categorize types
// and functions.
#ifdef XGILL_PLUGIN
// Mark a type as being a GC thing (eg js::gc::Cell has this annotation).
# define JS_HAZ_GC_THING __attribute__((tag("GC Thing")))
// Mark a type as holding a pointer to a GC thing (eg JS::Value has this
// annotation.)
# define JS_HAZ_GC_POINTER __attribute__((tag("GC Pointer")))
// Mark a type as a rooted pointer, suitable for use on the stack (eg all
// Rooted<T> instantiations should have this.)
# define JS_HAZ_ROOTED __attribute__((tag("Rooted Pointer")))
// Mark a type as something that should not be held live across a GC, but which
// is not itself a GC pointer.
# define JS_HAZ_GC_INVALIDATED __attribute__((tag("Invalidated by GC")))
// Mark a type that would otherwise be considered a GC Pointer (eg because it
// contains a JS::Value field) as a non-GC pointer. It is handled almost the
// same in the analysis as a rooted pointer, except it will not be reported as
// an unnecessary root if used across a GC call. This should rarely be used,
// but makes sense for something like ErrorResult, which only contains a GC
// pointer when it holds an exception (and it does its own rooting,
// conditionally.)
# define JS_HAZ_NON_GC_POINTER __attribute__((tag("Suppressed GC Pointer")))
// Mark a function as something that runs a garbage collection, potentially
// invalidating GC pointers.
# define JS_HAZ_GC_CALL __attribute__((tag("GC Call")))
// Mark an RAII class as suppressing GC within its scope.
# define JS_HAZ_GC_SUPPRESSED __attribute__((tag("Suppress GC")))
#else
# define JS_HAZ_GC_THING
# define JS_HAZ_GC_POINTER
# define JS_HAZ_ROOTED
# define JS_HAZ_GC_INVALIDATED
# define JS_HAZ_NON_GC_POINTER
# define JS_HAZ_GC_CALL
# define JS_HAZ_GC_SUPPRESSED
#endif
#endif /* js_GCAnnotations_h */

View File

@ -0,0 +1,399 @@
/* -*- 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 GCHashTable_h
#define GCHashTable_h
#include "js/GCPolicyAPI.h"
#include "js/HashTable.h"
#include "js/RootingAPI.h"
#include "js/SweepingAPI.h"
#include "js/TracingAPI.h"
namespace JS {
// Define a reasonable default GC policy for GC-aware Maps.
template <typename Key, typename Value>
struct DefaultMapSweepPolicy {
static bool needsSweep(Key* key, Value* value) {
return GCPolicy<Key>::needsSweep(key) || GCPolicy<Value>::needsSweep(value);
}
};
// A GCHashMap is a GC-aware HashMap, meaning that it has additional trace and
// sweep methods that know how to visit all keys and values in the table.
// HashMaps that contain GC pointers will generally want to use this GCHashMap
// specialization instead of HashMap, because this conveniently supports tracing
// keys and values, and cleaning up weak entries.
//
// GCHashMap::trace applies GCPolicy<T>::trace to each entry's key and value.
// Most types of GC pointers already have appropriate specializations of
// GCPolicy, so they should just work as keys and values. Any struct type with a
// default constructor and trace and sweep functions should work as well. If you
// need to define your own GCPolicy specialization, generic helpers can be found
// in js/public/TracingAPI.h.
//
// The MapSweepPolicy template parameter controls how the table drops entries
// when swept. GCHashMap::sweep applies MapSweepPolicy::needsSweep to each table
// entry; if it returns true, the entry is dropped. The default MapSweepPolicy
// drops the entry if either the key or value is about to be finalized,
// according to its GCPolicy<T>::needsSweep method. (This default is almost
// always fine: it's hard to imagine keeping such an entry around anyway.)
//
// Note that this HashMap only knows *how* to trace and sweep, but it does not
// itself cause tracing or sweeping to be invoked. For tracing, it must be used
// with Rooted or PersistentRooted, or barriered and traced manually. For
// sweeping, currently it requires an explicit call to <map>.sweep().
template <typename Key,
typename Value,
typename HashPolicy = js::DefaultHasher<Key>,
typename AllocPolicy = js::TempAllocPolicy,
typename MapSweepPolicy = DefaultMapSweepPolicy<Key, Value>>
class GCHashMap : public js::HashMap<Key, Value, HashPolicy, AllocPolicy>
{
using Base = js::HashMap<Key, Value, HashPolicy, AllocPolicy>;
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<Value>::trace(trc, &e.front().value(), "hashmap value");
GCPolicy<Key>::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;
};
} // namespace JS
namespace js {
// HashMap that supports rekeying.
//
// If your keys are pointers to something like JSObject that can be tenured or
// compacted, prefer to use GCHashMap with MovableCellHasher, which takes
// advantage of the Zone's stable id table to make rekeying unnecessary.
template <typename Key,
typename Value,
typename HashPolicy = DefaultHasher<Key>,
typename AllocPolicy = TempAllocPolicy,
typename MapSweepPolicy = JS::DefaultMapSweepPolicy<Key, Value>>
class GCRekeyableHashMap : public JS::GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>
{
using Base = JS::GCHashMap<Key, Value, HashPolicy, AllocPolicy>;
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 <typename Outer, typename... Args>
class GCHashMapOperations
{
using Map = JS::GCHashMap<Args...>;
using Lookup = typename Map::Lookup;
const Map& map() const { return static_cast<const Outer*>(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 <typename Outer, typename... Args>
class MutableGCHashMapOperations
: public GCHashMapOperations<Outer, Args...>
{
using Map = JS::GCHashMap<Args...>;
using Lookup = typename Map::Lookup;
Map& map() { return static_cast<Outer*>(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<typename KeyInput, typename ValueInput>
bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) {
return map().add(p, mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
}
template<typename KeyInput>
bool add(AddPtr& p, KeyInput&& k) {
return map().add(p, mozilla::Forward<KeyInput>(k), Map::Value());
}
template<typename KeyInput, typename ValueInput>
bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) {
return map().relookupOrAdd(p, k,
mozilla::Forward<KeyInput>(k),
mozilla::Forward<ValueInput>(v));
}
template<typename KeyInput, typename ValueInput>
bool put(KeyInput&& k, ValueInput&& v) {
return map().put(mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
}
template<typename KeyInput, typename ValueInput>
bool putNew(KeyInput&& k, ValueInput&& v) {
return map().putNew(mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
}
};
template <typename A, typename B, typename C, typename D, typename E>
class RootedBase<JS::GCHashMap<A,B,C,D,E>>
: public MutableGCHashMapOperations<JS::Rooted<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
{};
template <typename A, typename B, typename C, typename D, typename E>
class MutableHandleBase<JS::GCHashMap<A,B,C,D,E>>
: public MutableGCHashMapOperations<JS::MutableHandle<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
{};
template <typename A, typename B, typename C, typename D, typename E>
class HandleBase<JS::GCHashMap<A,B,C,D,E>>
: public GCHashMapOperations<JS::Handle<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
{};
template <typename A, typename B, typename C, typename D, typename E>
class WeakCacheBase<JS::GCHashMap<A,B,C,D,E>>
: public MutableGCHashMapOperations<JS::WeakCache<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
{};
} // namespace js
namespace JS {
// A GCHashSet is a HashSet with an additional trace method that knows
// be traced to be kept alive will generally want to use this GCHashSet
// specialization in lieu of HashSet.
//
// Most types of GC pointers can be traced with no extra infrastructure. For
// structs and non-gc-pointer members, ensure that there is a specialization of
// GCPolicy<T> with an appropriate trace method available to handle the custom
// type. Generic helpers can be found in js/public/TracingAPI.h.
//
// Note that although this HashSet's trace will deal correctly with moved
// elements, it does not itself know when to barrier or trace elements. To
// function properly it must either be used with Rooted or barriered and traced
// manually.
template <typename T,
typename HashPolicy = js::DefaultHasher<T>,
typename AllocPolicy = js::TempAllocPolicy>
class GCHashSet : public js::HashSet<T, HashPolicy, AllocPolicy>
{
using Base = js::HashSet<T, HashPolicy, AllocPolicy>;
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<T>::trace(trc, &e.mutableFront(), "hashset element");
}
void sweep() {
if (!this->initialized())
return;
for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
if (GCPolicy<T>::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
namespace js {
template <typename Outer, typename... Args>
class GCHashSetOperations
{
using Set = JS::GCHashSet<Args...>;
using Lookup = typename Set::Lookup;
const Set& set() const { return static_cast<const Outer*>(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);
}
};
template <typename Outer, typename... Args>
class MutableGCHashSetOperations
: public GCHashSetOperations<Outer, Args...>
{
using Set = JS::GCHashSet<Args...>;
using Lookup = typename Set::Lookup;
Set& set() { return static_cast<Outer*>(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<typename TInput>
bool add(AddPtr& p, TInput&& t) {
return set().add(p, mozilla::Forward<TInput>(t));
}
template<typename TInput>
bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) {
return set().relookupOrAdd(p, l, mozilla::Forward<TInput>(t));
}
template<typename TInput>
bool put(TInput&& t) {
return set().put(mozilla::Forward<TInput>(t));
}
template<typename TInput>
bool putNew(TInput&& t) {
return set().putNew(mozilla::Forward<TInput>(t));
}
template<typename TInput>
bool putNew(const Lookup& l, TInput&& t) {
return set().putNew(l, mozilla::Forward<TInput>(t));
}
};
template <typename T, typename HP, typename AP>
class RootedBase<JS::GCHashSet<T, HP, AP>>
: public MutableGCHashSetOperations<JS::Rooted<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
{
};
template <typename T, typename HP, typename AP>
class MutableHandleBase<JS::GCHashSet<T, HP, AP>>
: public MutableGCHashSetOperations<JS::MutableHandle<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
{
};
template <typename T, typename HP, typename AP>
class HandleBase<JS::GCHashSet<T, HP, AP>>
: public GCHashSetOperations<JS::Handle<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
{
};
template <typename T, typename HP, typename AP>
class WeakCacheBase<JS::GCHashSet<T, HP, AP>>
: public MutableGCHashSetOperations<JS::WeakCache<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
{
};
} /* namespace js */
#endif /* GCHashTable_h */

View File

@ -0,0 +1,164 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// GC Policy Mechanism
// A GCPolicy controls how the GC interacts with both direct pointers to GC
// things (e.g. JSObject* or JSString*), tagged and/or optional pointers to GC
// things (e.g. Value or jsid), and C++ container types (e.g.
// JSPropertyDescriptor or GCHashMap).
//
// The GCPolicy provides at a minimum:
//
// static T initial()
// - Construct and return an empty T.
//
// static void trace(JSTracer, T* tp, const char* name)
// - Trace the edge |*tp|, calling the edge |name|. Containers like
// GCHashMap and GCHashSet use this method to trace their children.
//
// static bool needsSweep(T* tp)
// - Return true if |*tp| is about to be finalized. Otherwise, update the
// edge for moving GC, and return false. Containers like GCHashMap and
// GCHashSet use this method to decide when to remove an entry: if this
// function returns true on a key/value/member/etc, its entry is dropped
// from the container. Specializing this method is the standard way to
// get custom weak behavior from a container type.
//
// The default GCPolicy<T> assumes that T has a default constructor and |trace|
// and |needsSweep| methods, and forwards to them. GCPolicy has appropriate
// specializations for pointers to GC things and pointer-like types like
// JS::Heap<T> and mozilla::UniquePtr<T>.
//
// There are some stock structs your specializations can inherit from.
// IgnoreGCPolicy<T> does nothing. StructGCPolicy<T> forwards the methods to the
// referent type T.
#ifndef GCPolicyAPI_h
#define GCPolicyAPI_h
#include "mozilla/UniquePtr.h"
#include "js/TraceKind.h"
#include "js/TracingAPI.h"
// Expand the given macro D for each public GC pointer.
#define FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \
D(JS::Symbol*) \
D(JSAtom*) \
D(JSFunction*) \
D(JSObject*) \
D(JSScript*) \
D(JSString*)
// Expand the given macro D for each public tagged GC pointer type.
#define FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(D) \
D(JS::Value) \
D(jsid)
#define FOR_EACH_PUBLIC_AGGREGATE_GC_POINTER_TYPE(D) \
D(JSPropertyDescriptor)
class JSAtom;
class JSFunction;
class JSObject;
class JSScript;
class JSString;
namespace JS {
class Symbol;
}
namespace JS {
// Defines a policy for container types with non-GC, i.e. C storage. This
// policy dispatches to the underlying struct for GC interactions.
template <typename T>
struct StructGCPolicy
{
static T initial() {
return T();
}
static void trace(JSTracer* trc, T* tp, const char* name) {
tp->trace(trc);
}
static void sweep(T* tp) {
return tp->sweep();
}
static bool needsSweep(T* tp) {
return tp->needsSweep();
}
};
// The default GC policy attempts to defer to methods on the underlying type.
// Most C++ structures that contain a default constructor, a trace function and
// a sweep function will work out of the box with Rooted, Handle, GCVector,
// and GCHash{Set,Map}.
template <typename T> struct GCPolicy : public StructGCPolicy<T> {};
// This policy ignores any GC interaction, e.g. for non-GC types.
template <typename T>
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<uint32_t> : public IgnoreGCPolicy<uint32_t> {};
template <> struct GCPolicy<uint64_t> : public IgnoreGCPolicy<uint64_t> {};
template <typename T>
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<JS::Symbol*> : public GCPointerPolicy<JS::Symbol*> {};
template <> struct GCPolicy<JSAtom*> : public GCPointerPolicy<JSAtom*> {};
template <> struct GCPolicy<JSFunction*> : public GCPointerPolicy<JSFunction*> {};
template <> struct GCPolicy<JSObject*> : public GCPointerPolicy<JSObject*> {};
template <> struct GCPolicy<JSScript*> : public GCPointerPolicy<JSScript*> {};
template <> struct GCPolicy<JSString*> : public GCPointerPolicy<JSString*> {};
template <typename T>
struct GCPolicy<JS::Heap<T>>
{
static void trace(JSTracer* trc, JS::Heap<T>* thingp, const char* name) {
TraceEdge(trc, thingp, name);
}
static bool needsSweep(JS::Heap<T>* thingp) {
return js::gc::EdgeNeedsSweep(thingp);
}
};
// GCPolicy<UniquePtr<T>> forwards the contained pointer to GCPolicy<T>.
template <typename T, typename D>
struct GCPolicy<mozilla::UniquePtr<T, D>>
{
static mozilla::UniquePtr<T,D> initial() { return mozilla::UniquePtr<T,D>(); }
static void trace(JSTracer* trc, mozilla::UniquePtr<T,D>* tp, const char* name) {
if (tp->get())
GCPolicy<T>::trace(trc, tp->get(), name);
}
static bool needsSweep(mozilla::UniquePtr<T,D>* tp) {
if (tp->get())
return GCPolicy<T>::needsSweep(tp->get());
return false;
}
};
} // namespace JS
#endif // GCPolicyAPI_h

View File

@ -0,0 +1,198 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef js_GCVariant_h
#define js_GCVariant_h
#include "mozilla/Variant.h"
#include "js/GCPolicyAPI.h"
#include "js/RootingAPI.h"
#include "js/TracingAPI.h"
namespace JS {
// These template specializations allow Variant to be used inside GC wrappers.
//
// When matching on GC wrappers around Variants, matching should be done on
// the wrapper itself. The matcher class's methods should take Handles or
// MutableHandles. For example,
//
// struct MyMatcher
// {
// using ReturnType = const char*;
// ReturnType match(HandleObject o) { return "object"; }
// ReturnType match(HandleScript s) { return "script"; }
// };
//
// Rooted<Variant<JSObject*, JSScript*>> v(cx, someScript);
// MyMatcher mm;
// v.match(mm);
//
// If you get compile errors about inability to upcast subclasses (e.g., from
// NativeObject* to JSObject*) and are inside js/src, be sure to also include
// "gc/Policy.h".
namespace detail {
template <typename... Ts>
struct GCVariantImplementation;
// The base case.
template <typename T>
struct GCVariantImplementation<T>
{
template <typename ConcreteVariant>
static void trace(JSTracer* trc, ConcreteVariant* v, const char* name) {
T& thing = v->template as<T>();
if (!mozilla::IsPointer<T>::value || thing)
GCPolicy<T>::trace(trc, &thing, name);
}
template <typename Matcher, typename ConcreteVariant>
static typename Matcher::ReturnType
match(Matcher& matcher, Handle<ConcreteVariant> v) {
const T& thing = v.get().template as<T>();
return matcher.match(Handle<T>::fromMarkedLocation(&thing));
}
template <typename Matcher, typename ConcreteVariant>
static typename Matcher::ReturnType
match(Matcher& matcher, MutableHandle<ConcreteVariant> v) {
T& thing = v.get().template as<T>();
return matcher.match(MutableHandle<T>::fromMarkedLocation(&thing));
}
};
// The inductive case.
template <typename T, typename... Ts>
struct GCVariantImplementation<T, Ts...>
{
using Next = GCVariantImplementation<Ts...>;
template <typename ConcreteVariant>
static void trace(JSTracer* trc, ConcreteVariant* v, const char* name) {
if (v->template is<T>()) {
T& thing = v->template as<T>();
if (!mozilla::IsPointer<T>::value || thing)
GCPolicy<T>::trace(trc, &thing, name);
} else {
Next::trace(trc, v, name);
}
}
template <typename Matcher, typename ConcreteVariant>
static typename Matcher::ReturnType
match(Matcher& matcher, Handle<ConcreteVariant> v) {
if (v.get().template is<T>()) {
const T& thing = v.get().template as<T>();
return matcher.match(Handle<T>::fromMarkedLocation(&thing));
}
return Next::match(matcher, v);
}
template <typename Matcher, typename ConcreteVariant>
static typename Matcher::ReturnType
match(Matcher& matcher, MutableHandle<ConcreteVariant> v) {
if (v.get().template is<T>()) {
T& thing = v.get().template as<T>();
return matcher.match(MutableHandle<T>::fromMarkedLocation(&thing));
}
return Next::match(matcher, v);
}
};
} // namespace detail
template <typename... Ts>
struct GCPolicy<mozilla::Variant<Ts...>>
{
using Impl = detail::GCVariantImplementation<Ts...>;
// 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<Ts...>* v, const char* name) {
Impl::trace(trc, v, name);
}
};
} // namespace JS
namespace js {
template <typename Outer, typename... Ts>
class GCVariantOperations
{
using Impl = JS::detail::GCVariantImplementation<Ts...>;
using Variant = mozilla::Variant<Ts...>;
const Variant& variant() const { return static_cast<const Outer*>(this)->get(); }
public:
template <typename T>
bool is() const {
return variant().template is<T>();
}
template <typename T>
JS::Handle<T> as() const {
return Handle<T>::fromMarkedLocation(&variant().template as<T>());
}
template <typename Matcher>
typename Matcher::ReturnType
match(Matcher& matcher) const {
return Impl::match(matcher, JS::Handle<Variant>::fromMarkedLocation(&variant()));
}
};
template <typename Outer, typename... Ts>
class MutableGCVariantOperations
: public GCVariantOperations<Outer, Ts...>
{
using Impl = JS::detail::GCVariantImplementation<Ts...>;
using Variant = mozilla::Variant<Ts...>;
const Variant& variant() const { return static_cast<const Outer*>(this)->get(); }
Variant& variant() { return static_cast<Outer*>(this)->get(); }
public:
template <typename T>
JS::MutableHandle<T> as() {
return JS::MutableHandle<T>::fromMarkedLocation(&variant().template as<T>());
}
template <typename Matcher>
typename Matcher::ReturnType
match(Matcher& matcher) {
return Impl::match(matcher, JS::MutableHandle<Variant>::fromMarkedLocation(&variant()));
}
};
template <typename... Ts>
class RootedBase<mozilla::Variant<Ts...>>
: public MutableGCVariantOperations<JS::Rooted<mozilla::Variant<Ts...>>, Ts...>
{ };
template <typename... Ts>
class MutableHandleBase<mozilla::Variant<Ts...>>
: public MutableGCVariantOperations<JS::MutableHandle<mozilla::Variant<Ts...>>, Ts...>
{ };
template <typename... Ts>
class HandleBase<mozilla::Variant<Ts...>>
: public GCVariantOperations<JS::Handle<mozilla::Variant<Ts...>>, Ts...>
{ };
template <typename... Ts>
class PersistentRootedBase<mozilla::Variant<Ts...>>
: public MutableGCVariantOperations<JS::PersistentRooted<mozilla::Variant<Ts...>>, Ts...>
{ };
} // namespace js
#endif // js_GCVariant_h

View File

@ -0,0 +1,249 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef js_GCVector_h
#define js_GCVector_h
#include "mozilla/Vector.h"
#include "js/GCPolicyAPI.h"
#include "js/RootingAPI.h"
#include "js/TracingAPI.h"
#include "js/Vector.h"
namespace JS {
// A GCVector is a Vector with an additional trace method that knows how
// to visit all of the items stored in the Vector. For vectors that contain GC
// things, this is usually more convenient than manually iterating and marking
// the contents.
//
// Most types of GC pointers as keys and values can be traced with no extra
// infrastructure. For structs and non-gc-pointer members, ensure that there is
// a specialization of GCPolicy<T> with an appropriate trace method available
// to handle the custom type. Generic helpers can be found in
// js/public/TracingAPI.h.
//
// Note that although this Vector's trace will deal correctly with moved items,
// it does not itself know when to barrier or trace items. To function properly
// it must either be used with Rooted, or barriered and traced manually.
template <typename T,
size_t MinInlineCapacity = 0,
typename AllocPolicy = js::TempAllocPolicy>
class GCVector
{
mozilla::Vector<T, MinInlineCapacity, AllocPolicy> 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<typename U> bool append(U&& item) { return vector.append(mozilla::Forward<U>(item)); }
template<typename... Args>
bool
emplaceBack(Args&&... args) {
return vector.emplaceBack(mozilla::Forward<Args>(args)...);
}
template<typename U>
void infallibleAppend(U&& aU) {
return vector.infallibleAppend(mozilla::Forward<U>(aU));
}
void infallibleAppendN(const T& aT, size_t aN) {
return vector.infallibleAppendN(aT, aN);
}
template<typename U> void
infallibleAppend(const U* aBegin, const U* aEnd) {
return vector.infallibleAppend(aBegin, aEnd);
}
template<typename U> void infallibleAppend(const U* aBegin, size_t aLength) {
return vector.infallibleAppend(aBegin, aLength);
}
template<typename U, size_t O, class BP>
bool appendAll(const mozilla::Vector<U, O, BP>& aU) { return vector.appendAll(aU); }
template<typename U, size_t O, class BP>
bool appendAll(const GCVector<U, O, BP>& aU) { return vector.append(aU.begin(), aU.length()); }
bool appendN(const T& val, size_t count) { return vector.appendN(val, count); }
template<typename U> bool append(const U* aBegin, const U* aEnd) {
return vector.append(aBegin, aEnd);
}
template<typename U> 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<T>::trace(trc, &elem, "vector element");
}
};
} // namespace JS
namespace js {
template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
class GCVectorOperations
{
using Vec = JS::GCVector<T, Capacity, AllocPolicy>;
const Vec& vec() const { return static_cast<const Outer*>(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<T> operator[](size_t aIndex) const {
return JS::Handle<T>::fromMarkedLocation(&vec().operator[](aIndex));
}
};
template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
class MutableGCVectorOperations
: public GCVectorOperations<Outer, T, Capacity, AllocPolicy>
{
using Vec = JS::GCVector<T, Capacity, AllocPolicy>;
const Vec& vec() const { return static_cast<const Outer*>(this)->get(); }
Vec& vec() { return static_cast<Outer*>(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<T> operator[](size_t aIndex) const {
return JS::Handle<T>::fromMarkedLocation(&vec().operator[](aIndex));
}
JS::MutableHandle<T> operator[](size_t aIndex) {
return JS::MutableHandle<T>::fromMarkedLocation(&vec().operator[](aIndex));
}
bool initCapacity(size_t aRequest) { return vec().initCapacity(aRequest); }
bool reserve(size_t aRequest) { return vec().reserve(aRequest); }
void shrinkBy(size_t aIncr) { vec().shrinkBy(aIncr); }
bool growBy(size_t aIncr) { return vec().growBy(aIncr); }
bool resize(size_t aNewLength) { return vec().resize(aNewLength); }
bool growByUninitialized(size_t aIncr) { return vec().growByUninitialized(aIncr); }
void infallibleGrowByUninitialized(size_t aIncr) { vec().infallibleGrowByUninitialized(aIncr); }
bool resizeUninitialized(size_t aNewLength) { return vec().resizeUninitialized(aNewLength); }
void clear() { vec().clear(); }
void clearAndFree() { vec().clearAndFree(); }
template<typename U> bool append(U&& aU) { return vec().append(mozilla::Forward<U>(aU)); }
template<typename... Args> bool emplaceBack(Args&&... aArgs) {
return vec().emplaceBack(mozilla::Forward<Args...>(aArgs...));
}
template<typename U, size_t O, class BP>
bool appendAll(const mozilla::Vector<U, O, BP>& aU) { return vec().appendAll(aU); }
template<typename U, size_t O, class BP>
bool appendAll(const JS::GCVector<U, O, BP>& aU) { return vec().appendAll(aU); }
bool appendN(const T& aT, size_t aN) { return vec().appendN(aT, aN); }
template<typename U> bool append(const U* aBegin, const U* aEnd) {
return vec().append(aBegin, aEnd);
}
template<typename U> bool append(const U* aBegin, size_t aLength) {
return vec().append(aBegin, aLength);
}
template<typename U> void infallibleAppend(U&& aU) {
vec().infallibleAppend(mozilla::Forward<U>(aU));
}
void infallibleAppendN(const T& aT, size_t aN) { vec().infallibleAppendN(aT, aN); }
template<typename U> void infallibleAppend(const U* aBegin, const U* aEnd) {
vec().infallibleAppend(aBegin, aEnd);
}
template<typename U> void infallibleAppend(const U* aBegin, size_t aLength) {
vec().infallibleAppend(aBegin, aLength);
}
void popBack() { vec().popBack(); }
T popCopy() { return vec().popCopy(); }
template<typename U> T* insert(T* aP, U&& aVal) {
return vec().insert(aP, mozilla::Forward<U>(aVal));
}
void erase(T* aT) { vec().erase(aT); }
void erase(T* aBegin, T* aEnd) { vec().erase(aBegin, aEnd); }
};
template <typename T, size_t N, typename AP>
class RootedBase<JS::GCVector<T,N,AP>>
: public MutableGCVectorOperations<JS::Rooted<JS::GCVector<T,N,AP>>, T,N,AP>
{};
template <typename T, size_t N, typename AP>
class MutableHandleBase<JS::GCVector<T,N,AP>>
: public MutableGCVectorOperations<JS::MutableHandle<JS::GCVector<T,N,AP>>, T,N,AP>
{};
template <typename T, size_t N, typename AP>
class HandleBase<JS::GCVector<T,N,AP>>
: public GCVectorOperations<JS::Handle<JS::GCVector<T,N,AP>>, T,N,AP>
{};
template <typename T, size_t N, typename AP>
class PersistentRootedBase<JS::GCVector<T,N,AP>>
: public MutableGCVectorOperations<JS::PersistentRooted<JS::GCVector<T,N,AP>>, T,N,AP>
{};
} // namespace js
#endif // js_GCVector_h

712
android/arm64-v8a/include/spidermonkey/js/HashTable.h Executable file → Normal file

File diff suppressed because it is too large Load Diff

411
android/arm64-v8a/include/spidermonkey/js/HeapAPI.h Executable file → Normal file
View File

@ -11,18 +11,14 @@
#include "jspubtd.h"
#include "js/TraceKind.h"
#include "js/Utility.h"
/* These values are private to the JS engine. */
namespace js {
// Whether the current thread is permitted access to any part of the specified
// runtime or zone.
JS_FRIEND_API(bool)
CurrentThreadCanAccessRuntime(JSRuntime *rt);
JS_FRIEND_API(bool)
CurrentThreadCanAccessZone(JS::Zone *zone);
CurrentThreadCanAccessZone(JS::Zone* zone);
namespace gc {
@ -53,7 +49,11 @@ const size_t ChunkMarkBitmapOffset = 1032352;
const size_t ChunkMarkBitmapBits = 129024;
#endif
const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*);
const size_t ChunkLocationOffset = ChunkSize - 2 * sizeof(void*) - sizeof(uint64_t);
const size_t ChunkTrailerSize = 2 * sizeof(uintptr_t) + sizeof(uint64_t);
const size_t ChunkLocationOffset = ChunkSize - ChunkTrailerSize;
const size_t ArenaZoneOffset = sizeof(size_t);
const size_t ArenaHeaderSize = sizeof(size_t) + 2 * sizeof(uintptr_t) +
sizeof(size_t) + sizeof(uintptr_t);
/*
* Live objects are marked black. How many other additional colors are available
@ -64,33 +64,27 @@ static const uint32_t BLACK = 0;
static const uint32_t GRAY = 1;
/*
* The "location" field in the Chunk trailer is a bit vector indicting various
* roles of the chunk.
*
* The value 0 for the "location" field is invalid, at least one bit must be
* set.
*
* Some bits preclude others, for example, any "nursery" bit precludes any
* "tenured" or "middle generation" bit.
* The "location" field in the Chunk trailer is a enum indicating various roles
* of the chunk.
*/
const uintptr_t ChunkLocationBitNursery = 1; // Standard GGC nursery
const uintptr_t ChunkLocationBitTenuredHeap = 2; // Standard GGC tenured generation
const uintptr_t ChunkLocationBitPJSNewspace = 4; // The PJS generational GC's allocation space
const uintptr_t ChunkLocationBitPJSFromspace = 8; // The PJS generational GC's fromspace (during GC)
const uintptr_t ChunkLocationAnyNursery = ChunkLocationBitNursery |
ChunkLocationBitPJSNewspace |
ChunkLocationBitPJSFromspace;
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, JSGCTraceKind kind);
AssertGCThingHasType(js::gc::Cell* cell, JS::TraceKind kind);
#else
inline void
AssertGCThingHasType(js::gc::Cell *cell, JSGCTraceKind kind) {}
AssertGCThingHasType(js::gc::Cell* cell, JS::TraceKind kind) {}
#endif
MOZ_ALWAYS_INLINE bool IsInsideNursery(const js::gc::Cell* cell);
} /* namespace gc */
} /* namespace js */
@ -98,220 +92,315 @@ namespace JS {
struct Zone;
/* Default size for the generational nursery in bytes. */
const uint32_t DefaultNurseryBytes = 16 * 1024 * 1024;
const uint32_t DefaultNurseryBytes = 16 * js::gc::ChunkSize;
/* Default maximum heap size in bytes to pass to JS_NewRuntime(). */
const uint32_t DefaultHeapMaxBytes = 32 * 1024 * 1024;
/*
* We cannot expose the class hierarchy: the implementation is hidden. Instead
* we provide cast functions with strong debug-mode assertions.
*/
static MOZ_ALWAYS_INLINE js::gc::Cell *
AsCell(JSObject *obj)
{
js::gc::Cell *cell = reinterpret_cast<js::gc::Cell *>(obj);
AssertGCThingHasType(cell, JSTRACE_OBJECT);
return cell;
}
static MOZ_ALWAYS_INLINE js::gc::Cell *
AsCell(JSFunction *fun)
{
js::gc::Cell *cell = reinterpret_cast<js::gc::Cell *>(fun);
AssertGCThingHasType(cell, JSTRACE_OBJECT);
return cell;
}
static MOZ_ALWAYS_INLINE js::gc::Cell *
AsCell(JSString *str)
{
js::gc::Cell *cell = reinterpret_cast<js::gc::Cell *>(str);
AssertGCThingHasType(cell, JSTRACE_STRING);
return cell;
}
static MOZ_ALWAYS_INLINE js::gc::Cell *
AsCell(JSFlatString *flat)
{
js::gc::Cell *cell = reinterpret_cast<js::gc::Cell *>(flat);
AssertGCThingHasType(cell, JSTRACE_STRING);
return cell;
}
static MOZ_ALWAYS_INLINE js::gc::Cell *
AsCell(JS::Symbol *sym)
{
js::gc::Cell *cell = reinterpret_cast<js::gc::Cell *>(sym);
AssertGCThingHasType(cell, JSTRACE_SYMBOL);
return cell;
}
static MOZ_ALWAYS_INLINE js::gc::Cell *
AsCell(JSScript *script)
{
js::gc::Cell *cell = reinterpret_cast<js::gc::Cell *>(script);
AssertGCThingHasType(cell, JSTRACE_SCRIPT);
return cell;
}
namespace shadow {
struct ArenaHeader
{
JS::Zone *zone;
};
struct Zone
{
protected:
JSRuntime *const runtime_;
JSTracer *const barrierTracer_; // A pointer to the JSRuntime's |gcMarker|.
JSRuntime* const runtime_;
JSTracer* const barrierTracer_; // A pointer to the JSRuntime's |gcMarker|.
public:
bool needsBarrier_;
// Stack GC roots for Rooted GC pointers.
js::RootedListHeads stackRoots_;
template <typename T> friend class JS::Rooted;
Zone(JSRuntime *runtime, JSTracer *barrierTracerArg)
bool needsIncrementalBarrier_;
Zone(JSRuntime* runtime, JSTracer* barrierTracerArg)
: runtime_(runtime),
barrierTracer_(barrierTracerArg),
needsBarrier_(false)
{}
bool needsBarrier() const {
return needsBarrier_;
needsIncrementalBarrier_(false)
{
for (auto& stackRootPtr : stackRoots_)
stackRootPtr = nullptr;
}
JSTracer *barrierTracer() {
MOZ_ASSERT(needsBarrier_);
bool needsIncrementalBarrier() const {
return needsIncrementalBarrier_;
}
JSTracer* barrierTracer() {
MOZ_ASSERT(needsIncrementalBarrier_);
MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_));
return barrierTracer_;
}
JSRuntime *runtimeFromMainThread() const {
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 {
JSRuntime* runtimeFromAnyThread() const {
return runtime_;
}
static JS::shadow::Zone *asShadowZone(JS::Zone *zone) {
static MOZ_ALWAYS_INLINE JS::shadow::Zone* asShadowZone(JS::Zone* zone) {
return reinterpret_cast<JS::shadow::Zone*>(zone);
}
};
} /* namespace shadow */
/**
* A GC pointer, tagged with the trace kind.
*
* In general, a GC pointer should be stored with an exact type. This class
* 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 <typename T>
explicit GCCellPtr(T* p) : ptr(checkedCast(p, JS::MapTypeToTraceKind<T>::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 <typename T>
bool is() const { return kind() == JS::MapTypeToTraceKind<T>::kind; }
// Conversions to more specific types must match the kind. Access to
// further refined types is not allowed directly from a GCCellPtr.
template <typename T>
T& as() const {
MOZ_ASSERT(kind() == JS::MapTypeToTraceKind<T>::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<T*>(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<js::gc::Cell*>(ptr & ~OutOfLineTraceKindMask);
}
// The CC's trace logger needs an identity that is XPIDL serializable.
uint64_t unsafeAsInteger() const {
return static_cast<uint64_t>(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<uintptr_t>(asCell());
}
bool mayBeOwnedByOtherRuntime() const;
private:
static uintptr_t checkedCast(void* p, JS::TraceKind traceKind) {
js::gc::Cell* cell = static_cast<js::gc::Cell*>(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;
uintptr_t ptr;
};
inline bool
operator==(const GCCellPtr& ptr1, const GCCellPtr& ptr2)
{
return ptr1.asCell() == ptr2.asCell();
}
inline bool
operator!=(const GCCellPtr& ptr1, const GCCellPtr& ptr2)
{
return !(ptr1 == ptr2);
}
// Unwraps the given GCCellPtr and calls the given functor with a template
// argument of the actual type of the pointer.
template <typename F, typename... Args>
auto
DispatchTyped(F f, GCCellPtr thing, Args&&... args)
-> decltype(f(static_cast<JSObject*>(nullptr), mozilla::Forward<Args>(args)...))
{
switch (thing.kind()) {
#define JS_EXPAND_DEF(name, type, _) \
case JS::TraceKind::name: \
return f(&thing.as<type>(), mozilla::Forward<Args>(args)...);
JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
#undef JS_EXPAND_DEF
default:
MOZ_CRASH("Invalid trace kind in DispatchTyped for GCCellPtr.");
}
}
} /* namespace JS */
namespace js {
namespace gc {
namespace detail {
static MOZ_ALWAYS_INLINE uintptr_t *
GetGCThingMarkBitmap(const void *thing)
static MOZ_ALWAYS_INLINE uintptr_t*
GetGCThingMarkBitmap(const uintptr_t addr)
{
MOZ_ASSERT(thing);
uintptr_t addr = uintptr_t(thing);
addr &= ~js::gc::ChunkMask;
addr |= js::gc::ChunkMarkBitmapOffset;
return reinterpret_cast<uintptr_t *>(addr);
}
static MOZ_ALWAYS_INLINE JS::shadow::Runtime *
GetGCThingRuntime(const void *thing)
{
MOZ_ASSERT(thing);
uintptr_t addr = uintptr_t(thing);
addr &= ~js::gc::ChunkMask;
addr |= js::gc::ChunkRuntimeOffset;
return *reinterpret_cast<JS::shadow::Runtime **>(addr);
MOZ_ASSERT(addr);
const uintptr_t bmap_addr = (addr & ~ChunkMask) | ChunkMarkBitmapOffset;
return reinterpret_cast<uintptr_t*>(bmap_addr);
}
static MOZ_ALWAYS_INLINE void
GetGCThingMarkWordAndMask(const void *thing, uint32_t color,
uintptr_t **wordp, uintptr_t *maskp)
GetGCThingMarkWordAndMask(const uintptr_t addr, uint32_t color,
uintptr_t** wordp, uintptr_t* maskp)
{
uintptr_t addr = uintptr_t(thing);
size_t bit = (addr & js::gc::ChunkMask) / js::gc::CellSize + color;
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(thing);
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::shadow::ArenaHeader *
GetGCThingArena(void *thing)
static MOZ_ALWAYS_INLINE JS::Zone*
GetGCThingZone(const uintptr_t addr)
{
uintptr_t addr = uintptr_t(thing);
addr &= ~js::gc::ArenaMask;
return reinterpret_cast<JS::shadow::ArenaHeader *>(addr);
MOZ_ASSERT(addr);
const uintptr_t zone_addr = (addr & ~ArenaMask) | ArenaZoneOffset;
return *reinterpret_cast<JS::Zone**>(zone_addr);
}
MOZ_ALWAYS_INLINE bool
IsInsideNursery(const js::gc::Cell *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<JS::shadow::Runtime**>(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);
} /* namespace detail */
MOZ_ALWAYS_INLINE bool
IsInsideNursery(const js::gc::Cell* cell)
{
#ifdef JSGC_GENERATIONAL
if (!cell)
return false;
uintptr_t addr = uintptr_t(cell);
addr &= ~js::gc::ChunkMask;
addr |= js::gc::ChunkLocationOffset;
uint32_t location = *reinterpret_cast<uint32_t *>(addr);
JS_ASSERT(location != 0);
return location & ChunkLocationAnyNursery;
#else
return false;
#endif
auto location = *reinterpret_cast<ChunkLocation*>(addr);
MOZ_ASSERT(location == ChunkLocation::Nursery || location == ChunkLocation::TenuredHeap);
return location == ChunkLocation::Nursery;
}
} /* namespace gc */
} /* namespace js */
namespace JS {
static MOZ_ALWAYS_INLINE Zone *
GetGCThingZone(void *thing)
static MOZ_ALWAYS_INLINE Zone*
GetTenuredGCThingZone(GCCellPtr thing)
{
MOZ_ASSERT(thing);
return js::gc::GetGCThingArena(thing)->zone;
MOZ_ASSERT(!js::gc::IsInsideNursery(thing.asCell()));
return js::gc::detail::GetGCThingZone(thing.unsafeAsUIntPtr());
}
static MOZ_ALWAYS_INLINE Zone *
GetObjectZone(JSObject *obj)
static MOZ_ALWAYS_INLINE Zone*
GetStringZone(JSString* str)
{
return GetGCThingZone(obj);
return js::gc::detail::GetGCThingZone(uintptr_t(str));
}
extern JS_PUBLIC_API(Zone*)
GetObjectZone(JSObject* obj);
static MOZ_ALWAYS_INLINE bool
GCThingIsMarkedGray(void *thing)
GCThingIsMarkedGray(GCCellPtr thing)
{
#ifdef JSGC_GENERATIONAL
/*
* GC things residing in the nursery cannot be gray: they have no mark bits.
* All live objects in the nursery are moved to tenured at the beginning of
* each GC slice, so the gray marker never sees nursery things.
*/
if (js::gc::IsInsideNursery((js::gc::Cell *)thing))
if (thing.mayBeOwnedByOtherRuntime())
return false;
#endif
uintptr_t *word, mask;
js::gc::GetGCThingMarkWordAndMask(thing, js::gc::GRAY, &word, &mask);
return *word & mask;
return js::gc::detail::CellIsMarkedGrayIfKnown(thing.asCell());
}
static MOZ_ALWAYS_INLINE bool
IsIncrementalBarrierNeededOnGCThing(shadow::Runtime *rt, void *thing, JSGCTraceKind kind)
{
if (!rt->needsBarrier_)
return false;
JS::Zone *zone = GetGCThingZone(thing);
return reinterpret_cast<shadow::Zone *>(zone)->needsBarrier_;
}
extern JS_PUBLIC_API(JS::TraceKind)
GCThingTraceKind(void* 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());
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.
*/
extern JS_PUBLIC_API(JSObject*)
NewMemoryInfoObject(JSContext* cx);
} /* namespace gc */
} /* namespace js */
#endif /* js_HeapAPI_h */

106
android/arm64-v8a/include/spidermonkey/js/Id.h Executable file → Normal file
View File

@ -8,7 +8,7 @@
#define js_Id_h
// A jsid is an identifier for a property or method of an object which is
// either a 31-bit signed integer, interned string or object.
// either a 31-bit unsigned integer, interned string or symbol.
//
// Also, there is an additional jsid value, JSID_VOID, which does not occur in
// JS scripts but may be used to indicate the absence of a valid jsid. A void
@ -17,11 +17,9 @@
// entry points expecting a jsid and do not need to handle JSID_VOID in hooks
// receiving a jsid except when explicitly noted in the API contract.
//
// A jsid is not implicitly convertible to or from a jsval; JS_ValueToId or
// A jsid is not implicitly convertible to or from a Value; JS_ValueToId or
// JS_IdToValue must be used instead.
#include "mozilla/NullPtr.h"
#include "jstypes.h"
#include "js/HeapAPI.h"
@ -32,9 +30,9 @@
struct jsid
{
size_t asBits;
bool operator==(jsid rhs) const { return asBits == rhs.asBits; }
bool operator!=(jsid rhs) const { return asBits != rhs.asBits; }
};
bool operator==(const jsid& rhs) const { return asBits == rhs.asBits; }
bool operator!=(const jsid& rhs) const { return asBits != rhs.asBits; }
} JS_HAZ_GC_POINTER;
#define JSID_BITS(id) (id.asBits)
#define JSID_TYPE_STRING 0x0
@ -53,18 +51,22 @@ JSID_IS_STRING(jsid id)
return (JSID_BITS(id) & JSID_TYPE_MASK) == 0;
}
static MOZ_ALWAYS_INLINE JSString *
static MOZ_ALWAYS_INLINE JSString*
JSID_TO_STRING(jsid id)
{
MOZ_ASSERT(JSID_IS_STRING(id));
return (JSString *)JSID_BITS(id);
return (JSString*)JSID_BITS(id);
}
static MOZ_ALWAYS_INLINE bool
JSID_IS_ZERO(jsid id)
{
return JSID_BITS(id) == 0;
}
/**
* Only JSStrings that have been interned via the JSAPI can be turned into
* jsids by API clients.
*
* 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);
static MOZ_ALWAYS_INLINE bool
JSID_IS_INT(jsid id)
@ -104,21 +106,20 @@ JSID_IS_SYMBOL(jsid id)
JSID_BITS(id) != JSID_TYPE_SYMBOL;
}
static MOZ_ALWAYS_INLINE JS::Symbol *
static MOZ_ALWAYS_INLINE JS::Symbol*
JSID_TO_SYMBOL(jsid id)
{
MOZ_ASSERT(JSID_IS_SYMBOL(id));
return (JS::Symbol *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
return (JS::Symbol*)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
}
static MOZ_ALWAYS_INLINE jsid
SYMBOL_TO_JSID(JS::Symbol *sym)
SYMBOL_TO_JSID(JS::Symbol* sym)
{
jsid id;
MOZ_ASSERT(sym != nullptr);
MOZ_ASSERT((size_t(sym) & JSID_TYPE_MASK) == 0);
JS_ASSERT(!js::gc::IsInsideNursery(JS::AsCell(sym)));
JS_ASSERT(!JS::IsPoisonedPtr(sym));
MOZ_ASSERT(!js::gc::IsInsideNursery(reinterpret_cast<js::gc::Cell*>(sym)));
JSID_BITS(id) = (size_t(sym) | JSID_TYPE_SYMBOL);
return id;
}
@ -129,10 +130,14 @@ JSID_IS_GCTHING(jsid id)
return JSID_IS_STRING(id) || JSID_IS_SYMBOL(id);
}
static MOZ_ALWAYS_INLINE void *
static MOZ_ALWAYS_INLINE JS::GCCellPtr
JSID_TO_GCTHING(jsid id)
{
return (void *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
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
@ -140,13 +145,13 @@ 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);
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);
return (size_t)JSID_BITS(id) == JSID_TYPE_SYMBOL;
}
extern JS_PUBLIC_DATA(const jsid) JSID_VOID;
@ -155,31 +160,48 @@ 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;
namespace js {
namespace JS {
inline bool
IsPoisonedId(jsid id)
{
if (JSID_IS_STRING(id))
return JS::IsPoisonedPtr(JSID_TO_STRING(id));
if (JSID_IS_SYMBOL(id))
return JS::IsPoisonedPtr(JSID_TO_SYMBOL(id));
return false;
}
template <> struct GCMethods<jsid>
template <>
struct GCPolicy<jsid>
{
static jsid initial() { return JSID_VOID; }
static bool poisoned(jsid id) { return IsPoisonedId(id); }
static bool needsPostBarrier(jsid id) { return false; }
#ifdef JSGC_GENERATIONAL
static void postBarrier(jsid *idp) {}
static void relocate(jsid *idp) {}
#endif
static void trace(JSTracer* trc, jsid* idp, const char* name) {
js::UnsafeTraceManuallyBarrieredEdge(trc, idp, name);
}
};
} // namespace JS
namespace js {
template <>
struct BarrierMethods<jsid>
{
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 <typename F, typename... Args>
auto
DispatchTyped(F f, const jsid& id, Args&&... args)
-> decltype(f(static_cast<JSString*>(nullptr), mozilla::Forward<Args>(args)...))
{
if (JSID_IS_STRING(id))
return f(JSID_TO_STRING(id), mozilla::Forward<Args>(args)...);
if (JSID_IS_SYMBOL(id))
return f(JSID_TO_SYMBOL(id), mozilla::Forward<Args>(args)...);
MOZ_ASSERT(!JSID_IS_GCTHING(id));
return F::defaultValue(id);
}
#undef id
}
} // namespace js
#endif /* js_Id_h */

View File

@ -0,0 +1,125 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* SpiderMonkey initialization and shutdown APIs. */
#ifndef js_Initialization_h
#define js_Initialization_h
#include "jstypes.h"
namespace JS {
namespace detail {
enum class InitState { Uninitialized = 0, Running, ShutDown };
/**
* SpiderMonkey's initialization status is tracked here, and it controls things
* that should happen only once across all runtimes. It's an API requirement
* that JS_Init (and JS_ShutDown, if called) be called in a thread-aware
* manner, so this (internal -- embedders, don't use!) variable doesn't need to
* be atomic.
*/
extern JS_PUBLIC_DATA(InitState)
libraryInitState;
extern JS_PUBLIC_API(const char*)
InitWithFailureDiagnostic(bool isDebugBuild);
} // namespace detail
} // namespace JS
// These are equivalent to ICU's |UMemAllocFn|, |UMemReallocFn|, and
// |UMemFreeFn| types. The first argument (called |context| in the ICU docs)
// will always be nullptr and should be ignored.
typedef void* (*JS_ICUAllocFn)(const void*, size_t size);
typedef void* (*JS_ICUReallocFn)(const void*, void* p, size_t size);
typedef void (*JS_ICUFreeFn)(const void*, void* p);
/**
* This function can be used to track memory used by ICU. If it is called, it
* *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);
/**
* Initialize SpiderMonkey, returning true only if initialization succeeded.
* Once this method has succeeded, it is safe to call JS_NewRuntime and other
* JSAPI methods.
*
* This method must be called before any other JSAPI method is used on any
* thread. Once it has been used, it is safe to call any JSAPI method, and it
* remains safe to do so until JS_ShutDown is correctly called.
*
* It is currently not possible to initialize SpiderMonkey multiple times (that
* 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)
{
#ifdef DEBUG
return !JS::detail::InitWithFailureDiagnostic(true);
#else
return !JS::detail::InitWithFailureDiagnostic(false);
#endif
}
/**
* A variant of JS_Init. On success it returns nullptr. On failure it returns a
* pointer to a string literal that describes how initialization failed, which
* can be useful for debugging purposes.
*/
inline const char*
JS_InitWithFailureDiagnostic(void)
{
#ifdef DEBUG
return JS::detail::InitWithFailureDiagnostic(true);
#else
return JS::detail::InitWithFailureDiagnostic(false);
#endif
}
/*
* Returns true if SpiderMonkey has been initialized successfully, even if it has
* possibly been shut down.
*
* Note that it is the responsibility of the embedder to call JS_Init() and
* JS_ShutDown() at the correct times, and therefore this API should ideally not
* be necessary to use. This is only intended to be used in cases where the
* embedder isn't in full control of deciding whether to initialize SpiderMonkey
* or hand off the task to another consumer.
*/
inline bool
JS_IsInitialized(void)
{
return JS::detail::libraryInitState != JS::detail::InitState::Uninitialized;
}
/**
* Destroy free-standing resources allocated by SpiderMonkey, not associated
* with any runtime, context, or other structure.
*
* This method should be called after all other JSAPI data has been properly
* cleaned up: every new runtime must have been destroyed, every new context
* must have been destroyed, and so on. Calling this method before all other
* resources have been destroyed has undefined behavior.
*
* Failure to call this method, at present, has no adverse effects other than
* leaking memory. This may not always be the case; it's recommended that all
* embedders call this method when all other JSAPI operations have completed.
*
* It is currently not possible to initialize SpiderMonkey multiple times (that
* 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);
#endif /* js_Initialization_h */

View File

705
android/arm64-v8a/include/spidermonkey/js/MemoryMetrics.h Executable file → Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,385 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef js_OldDebugAPI_h
#define js_OldDebugAPI_h
/*
* JS debugger API.
*/
#include "mozilla/NullPtr.h"
#include "jsapi.h"
#include "jsbytecode.h"
#include "js/CallArgs.h"
#include "js/TypeDecls.h"
class JSAtom;
struct JSFreeOp;
namespace js {
class InterpreterFrame;
class FrameIter;
class ScriptSource;
}
// Raw JSScript* because this needs to be callable from a signal handler.
extern JS_PUBLIC_API(unsigned)
JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc);
extern JS_PUBLIC_API(const char *)
JS_GetScriptFilename(JSScript *script);
namespace JS {
extern JS_PUBLIC_API(char *)
FormatStackDump(JSContext *cx, char *buf, bool showArgs, bool showLocals, bool showThisProps);
} // namespace JS
# ifdef JS_DEBUG
JS_FRIEND_API(void) js_DumpValue(const JS::Value &val);
JS_FRIEND_API(void) js_DumpId(jsid id);
JS_FRIEND_API(void) js_DumpInterpreterFrame(JSContext *cx, js::InterpreterFrame *start = nullptr);
# endif
JS_FRIEND_API(void)
js_DumpBacktrace(JSContext *cx);
typedef enum JSTrapStatus {
JSTRAP_ERROR,
JSTRAP_CONTINUE,
JSTRAP_RETURN,
JSTRAP_THROW,
JSTRAP_LIMIT
} JSTrapStatus;
typedef JSTrapStatus
(* JSTrapHandler)(JSContext *cx, JSScript *script, jsbytecode *pc, JS::Value *rval,
JS::Value closure);
typedef JSTrapStatus
(* JSDebuggerHandler)(JSContext *cx, JSScript *script, jsbytecode *pc, JS::Value *rval,
void *closure);
typedef bool
(* JSWatchPointHandler)(JSContext *cx, JSObject *obj, jsid id, JS::Value old,
JS::Value *newp, void *closure);
extern JS_PUBLIC_API(JSCompartment *)
JS_EnterCompartmentOfScript(JSContext *cx, JSScript *target);
extern JS_PUBLIC_API(JSString *)
JS_DecompileScript(JSContext *cx, JS::HandleScript script, const char *name, unsigned indent);
/*
* Currently, we only support runtime-wide debugging. In the future, we should
* be able to support compartment-wide debugging.
*/
extern JS_PUBLIC_API(void)
JS_SetRuntimeDebugMode(JSRuntime *rt, bool debug);
/*
* Debug mode is a compartment-wide mode that enables a debugger to attach
* to and interact with running methodjit-ed frames. In particular, it causes
* every function to be compiled as if an eval was present (so eval-in-frame)
* can work, and it ensures that functions can be re-JITed for other debug
* features. In general, it is not safe to interact with frames that were live
* before debug mode was enabled. For this reason, it is also not safe to
* enable debug mode while frames are live.
*/
/* Get current state of debugging mode. */
extern JS_PUBLIC_API(bool)
JS_GetDebugMode(JSContext *cx);
/*
* Turn on/off debugging mode for all compartments. This returns false if any code
* from any of the runtime's compartments is running or on the stack.
*/
JS_FRIEND_API(bool)
JS_SetDebugModeForAllCompartments(JSContext *cx, bool debug);
/*
* Turn on/off debugging mode for a single compartment. This should only be
* used when no code from this compartment is running or on the stack in any
* thread.
*/
JS_FRIEND_API(bool)
JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, bool debug);
/*
* Turn on/off debugging mode for a context's compartment.
*/
JS_FRIEND_API(bool)
JS_SetDebugMode(JSContext *cx, bool debug);
/* Turn on single step mode. */
extern JS_PUBLIC_API(bool)
JS_SetSingleStepMode(JSContext *cx, JS::HandleScript script, bool singleStep);
/* The closure argument will be marked. */
extern JS_PUBLIC_API(bool)
JS_SetTrap(JSContext *cx, JS::HandleScript script, jsbytecode *pc,
JSTrapHandler handler, JS::HandleValue closure);
extern JS_PUBLIC_API(void)
JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
JSTrapHandler *handlerp, JS::Value *closurep);
extern JS_PUBLIC_API(void)
JS_ClearScriptTraps(JSRuntime *rt, JSScript *script);
extern JS_PUBLIC_API(void)
JS_ClearAllTrapsForCompartment(JSContext *cx);
/************************************************************************/
extern JS_PUBLIC_API(bool)
JS_SetWatchPoint(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
JSWatchPointHandler handler, JS::HandleObject closure);
extern JS_PUBLIC_API(bool)
JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsid id,
JSWatchPointHandler *handlerp, JSObject **closurep);
extern JS_PUBLIC_API(bool)
JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj);
/************************************************************************/
extern JS_PUBLIC_API(jsbytecode *)
JS_LineNumberToPC(JSContext *cx, JSScript *script, unsigned lineno);
extern JS_PUBLIC_API(jsbytecode *)
JS_EndPC(JSContext *cx, JSScript *script);
extern JS_PUBLIC_API(bool)
JS_GetLinePCs(JSContext *cx, JSScript *script,
unsigned startLine, unsigned maxLines,
unsigned* count, unsigned** lines, jsbytecode*** pcs);
extern JS_PUBLIC_API(unsigned)
JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun);
extern JS_PUBLIC_API(bool)
JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun);
/*
* N.B. The mark is in the context temp pool and thus the caller must take care
* to call JS_ReleaseFunctionLocalNameArray in a LIFO manner (wrt to any other
* call that may use the temp pool.
*/
extern JS_PUBLIC_API(uintptr_t *)
JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp);
extern JS_PUBLIC_API(JSAtom *)
JS_LocalNameToAtom(uintptr_t w);
extern JS_PUBLIC_API(JSString *)
JS_AtomKey(JSAtom *atom);
extern JS_PUBLIC_API(void)
JS_ReleaseFunctionLocalNameArray(JSContext *cx, void *mark);
extern JS_PUBLIC_API(JSScript *)
JS_GetFunctionScript(JSContext *cx, JS::HandleFunction fun);
extern JS_PUBLIC_API(JSNative)
JS_GetFunctionNative(JSContext *cx, JSFunction *fun);
JS_PUBLIC_API(JSFunction *)
JS_GetScriptFunction(JSContext *cx, JSScript *script);
extern JS_PUBLIC_API(JSObject *)
JS_GetParentOrScopeChain(JSContext *cx, JSObject *obj);
/************************************************************************/
/*
* This is almost JS_GetClass(obj)->name except that certain debug-only
* proxies are made transparent. In particular, this function turns the class
* of any scope (returned via JS_GetFrameScopeChain or JS_GetFrameCalleeObject)
* from "Proxy" to "Call", "Block", "With" etc.
*/
extern JS_PUBLIC_API(const char *)
JS_GetDebugClassName(JSObject *obj);
/************************************************************************/
extern JS_PUBLIC_API(const jschar *)
JS_GetScriptSourceMap(JSContext *cx, JSScript *script);
extern JS_PUBLIC_API(unsigned)
JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script);
extern JS_PUBLIC_API(unsigned)
JS_GetScriptLineExtent(JSContext *cx, JSScript *script);
extern JS_PUBLIC_API(JSVersion)
JS_GetScriptVersion(JSContext *cx, JSScript *script);
extern JS_PUBLIC_API(bool)
JS_GetScriptIsSelfHosted(JSScript *script);
/************************************************************************/
typedef struct JSPropertyDesc {
JS::Value id; /* primary id, atomized string, or int */
JS::Value value; /* property value */
uint8_t flags; /* flags, see below */
uint8_t spare; /* unused */
JS::Value alias; /* alias id if JSPD_ALIAS flag */
} JSPropertyDesc;
#define JSPD_ENUMERATE 0x01 /* visible to for/in loop */
#define JSPD_READONLY 0x02 /* assignment is error */
#define JSPD_PERMANENT 0x04 /* property cannot be deleted */
#define JSPD_ALIAS 0x08 /* property has an alias id */
#define JSPD_EXCEPTION 0x40 /* exception occurred fetching the property, */
/* value is exception */
#define JSPD_ERROR 0x80 /* native getter returned false without */
/* throwing an exception */
typedef struct JSPropertyDescArray {
uint32_t length; /* number of elements in array */
JSPropertyDesc *array; /* alloc'd by Get, freed by Put */
} JSPropertyDescArray;
typedef struct JSScopeProperty JSScopeProperty;
extern JS_PUBLIC_API(bool)
JS_GetPropertyDescArray(JSContext *cx, JS::HandleObject obj, JSPropertyDescArray *pda);
extern JS_PUBLIC_API(void)
JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda);
/************************************************************************/
/*
* JSAbstractFramePtr is the public version of AbstractFramePtr, a pointer to a
* StackFrame or baseline JIT frame.
*/
class JS_PUBLIC_API(JSAbstractFramePtr)
{
uintptr_t ptr_;
jsbytecode *pc_;
protected:
JSAbstractFramePtr()
: ptr_(0), pc_(nullptr)
{ }
public:
JSAbstractFramePtr(void *raw, jsbytecode *pc);
uintptr_t raw() const { return ptr_; }
jsbytecode *pc() const { return pc_; }
operator bool() const { return !!ptr_; }
JSObject *scopeChain(JSContext *cx);
JSObject *callObject(JSContext *cx);
JSFunction *maybeFun();
JSScript *script();
bool getThisValue(JSContext *cx, JS::MutableHandleValue thisv);
bool isDebuggerFrame();
bool evaluateInStackFrame(JSContext *cx,
const char *bytes, unsigned length,
const char *filename, unsigned lineno,
JS::MutableHandleValue rval);
bool evaluateUCInStackFrame(JSContext *cx,
const jschar *chars, unsigned length,
const char *filename, unsigned lineno,
JS::MutableHandleValue rval);
};
class JS_PUBLIC_API(JSNullFramePtr) : public JSAbstractFramePtr
{
public:
JSNullFramePtr()
: JSAbstractFramePtr()
{}
};
/*
* This class does not work when IonMonkey is active. It's only used by jsd,
* which can only be used when IonMonkey is disabled.
*
* To find the calling script and line number, use JS_DescribeSciptedCaller.
* To summarize the call stack, use JS::DescribeStack.
*/
class JS_PUBLIC_API(JSBrokenFrameIterator)
{
void *data_;
public:
explicit JSBrokenFrameIterator(JSContext *cx);
~JSBrokenFrameIterator();
bool done() const;
JSBrokenFrameIterator& operator++();
JSAbstractFramePtr abstractFramePtr() const;
jsbytecode *pc() const;
bool isConstructing() const;
};
typedef bool
(* JSDebugErrorHook)(JSContext *cx, const char *message, JSErrorReport *report,
void *closure);
typedef struct JSDebugHooks {
JSDebuggerHandler debuggerHandler;
void *debuggerHandlerData;
} JSDebugHooks;
/************************************************************************/
extern JS_PUBLIC_API(bool)
JS_SetDebuggerHandler(JSRuntime *rt, JSDebuggerHandler hook, void *closure);
/************************************************************************/
extern JS_PUBLIC_API(const JSDebugHooks *)
JS_GetGlobalDebugHooks(JSRuntime *rt);
/**
* Add various profiling-related functions as properties of the given object.
*/
extern JS_PUBLIC_API(bool)
JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj);
/* Defined in vm/Debugger.cpp. */
extern JS_PUBLIC_API(bool)
JS_DefineDebuggerObject(JSContext *cx, JS::HandleObject obj);
extern JS_PUBLIC_API(void)
JS_DumpPCCounts(JSContext *cx, JS::HandleScript script);
extern JS_PUBLIC_API(void)
JS_DumpCompartmentPCCounts(JSContext *cx);
namespace js {
extern JS_FRIEND_API(bool)
CanCallContextDebugHandler(JSContext *cx);
}
/* Call the context debug handler on the topmost scripted frame. */
extern JS_FRIEND_API(bool)
js_CallContextDebugHandler(JSContext *cx);
#endif /* js_OldDebugAPI_h */

70
android/arm64-v8a/include/spidermonkey/js/Principals.h Executable file → Normal file
View File

@ -15,25 +15,35 @@
#include "jspubtd.h"
#include "js/StructuredClone.h"
namespace js {
struct PerformanceGroup;
} // namespace js
struct JSPrincipals {
/* Don't call "destroy"; use reference counting macros below. */
#ifdef JS_THREADSAFE
mozilla::Atomic<int32_t> refcount;
#else
int32_t refcount;
#endif
#ifdef JS_DEBUG
/* A helper to facilitate principals debugging. */
uint32_t debugToken;
#endif
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.
@ -42,23 +52,23 @@ struct JSPrincipals {
};
extern JS_PUBLIC_API(void)
JS_HoldPrincipals(JSPrincipals *principals);
JS_HoldPrincipals(JSPrincipals* principals);
extern JS_PUBLIC_API(void)
JS_DropPrincipals(JSRuntime *rt, JSPrincipals *principals);
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);
(* 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);
(* JSCSPEvalChecker)(JSContext* cx);
struct JSSecurityCallbacks {
JSCSPEvalChecker contentSecurityPolicyAllows;
@ -66,10 +76,10 @@ struct JSSecurityCallbacks {
};
extern JS_PUBLIC_API(void)
JS_SetSecurityCallbacks(JSRuntime *rt, const JSSecurityCallbacks *callbacks);
JS_SetSecurityCallbacks(JSContext* cx, const JSSecurityCallbacks* callbacks);
extern JS_PUBLIC_API(const JSSecurityCallbacks *)
JS_GetSecurityCallbacks(JSRuntime *rt);
extern JS_PUBLIC_API(const JSSecurityCallbacks*)
JS_GetSecurityCallbacks(JSContext* cx);
/*
* Code running with "trusted" principals will be given a deeper stack
@ -77,17 +87,17 @@ JS_GetSecurityCallbacks(JSRuntime *rt);
* untrusted script has exhausted the stack. This function sets the
* runtime-wide trusted principal.
*
* This principals is not held (via JS_HoldPrincipals/JS_DropPrincipals) since
* there is no available JSContext. Instead, the caller must ensure that the
* given principals stays valid for as long as 'rt' may point to it. If the
* principals would be destroyed before 'rt', JS_SetTrustedPrincipals must be
* called again, passing nullptr for 'prin'.
* This principals is not held (via JS_HoldPrincipals/JS_DropPrincipals).
* Instead, the caller must ensure that the given principals stays valid for as
* long as 'cx' may point to it. If the principals would be destroyed before
* 'cx', JS_SetTrustedPrincipals must be called again, passing nullptr for
* 'prin'.
*/
extern JS_PUBLIC_API(void)
JS_SetTrustedPrincipals(JSRuntime *rt, const JSPrincipals *prin);
JS_SetTrustedPrincipals(JSContext* cx, JSPrincipals* prin);
typedef void
(* JSDestroyPrincipalsOp)(JSPrincipals *principals);
(* JSDestroyPrincipalsOp)(JSPrincipals* principals);
/*
* Initialize the callback that is called to destroy JSPrincipals instance
@ -95,6 +105,28 @@ typedef void
* only once per JS runtime.
*/
extern JS_PUBLIC_API(void)
JS_InitDestroyPrincipalsCallback(JSRuntime *rt, JSDestroyPrincipalsOp destroyPrincipals);
JS_InitDestroyPrincipalsCallback(JSContext* cx, JSDestroyPrincipalsOp destroyPrincipals);
/*
* Read a JSPrincipals instance from the given |reader| and initialize the out
* paratemer |outPrincipals| to the JSPrincipals instance read.
*
* Return false on failure, true on success. The |outPrincipals| parameter
* should not be modified if false is returned.
*
* The caller is not responsible for calling JS_HoldPrincipals on the resulting
* JSPrincipals instance, the JSReadPrincipalsOp must increment the refcount of
* the resulting JSPrincipals on behalf of the caller.
*/
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);
#endif /* js_Principals_h */

View File

@ -0,0 +1,203 @@
/* -*- 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_ProfilingFrameIterator_h
#define js_ProfilingFrameIterator_h
#include "mozilla/Alignment.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
namespace JS {
struct ForEachTrackedOptimizationAttemptOp;
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
// (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<StorageSpace> storage_;
js::wasm::ProfilingFrameIterator& wasmIter() {
MOZ_ASSERT(!done());
MOZ_ASSERT(isWasm());
return *reinterpret_cast<js::wasm::ProfilingFrameIterator*>(storage_.addr());
}
const js::wasm::ProfilingFrameIterator& wasmIter() const {
MOZ_ASSERT(!done());
MOZ_ASSERT(isWasm());
return *reinterpret_cast<const js::wasm::ProfilingFrameIterator*>(storage_.addr());
}
js::jit::JitProfilingFrameIterator& jitIter() {
MOZ_ASSERT(!done());
MOZ_ASSERT(isJit());
return *reinterpret_cast<js::jit::JitProfilingFrameIterator*>(storage_.addr());
}
const js::jit::JitProfilingFrameIterator& jitIter() const {
MOZ_ASSERT(!done());
MOZ_ASSERT(isJit());
return *reinterpret_cast<const js::jit::JitProfilingFrameIterator*>(storage_.addr());
}
void settle();
bool hasSampleBufferGen() const {
return sampleBufferGen_ != UINT32_MAX;
}
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<Frame> getPhysicalFrameWithoutLabel() const;
private:
mozilla::Maybe<Frame> getPhysicalFrameAndEntry(js::jit::JitcodeGlobalEntry* entry) const;
void iteratorConstruct(const RegisterState& state);
void iteratorConstruct();
void iteratorDestroy();
bool iteratorDone();
};
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<uint8_t> 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_; }
ProfilingFrameIterator::FrameKind frameKind() const;
void forEachOptimizationAttempt(ForEachTrackedOptimizationAttemptOp& op,
JSScript** scriptOut, jsbytecode** pcOut) const;
void forEachOptimizationTypeInfo(ForEachTrackedOptimizationTypeInfoOp& op) const;
};
// Called once per frame.
virtual void operator()(const FrameHandle& frame) = 0;
};
JS_PUBLIC_API(void)
ForEachProfiledFrame(JSContext* cx, void* addr, ForEachProfiledFrameOp& op);
} // namespace JS
#endif /* js_ProfilingFrameIterator_h */

View File

@ -7,15 +7,14 @@
#ifndef js_ProfilingStack_h
#define js_ProfilingStack_h
#include "mozilla/NullPtr.h"
#include "mozilla/TypedEnum.h"
#include "jsbytecode.h"
#include "jstypes.h"
#include "js/TypeDecls.h"
#include "js/Utility.h"
struct JSRuntime;
class JSTracer;
namespace js {
@ -44,41 +43,57 @@ class ProfileEntry
void * volatile spOrScript;
// Line number for non-JS entries, the bytecode offset otherwise.
int32_t volatile lineOrPc;
int32_t volatile lineOrPcOffset;
// General purpose storage describing this frame.
uint32_t volatile flags_;
public:
// These traits are bit masks. Make sure they're powers of 2.
enum Flags {
enum Flags : uint32_t {
// Indicate whether a profile entry represents a CPP frame. If not set,
// a JS frame is assumed by default. You're not allowed to publicly
// change the frame type. Instead, call `setJsFrame` or `setCppFrame`.
// 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 = ~IS_CPP_ENTRY & ~FRAME_LABEL_COPY
CATEGORY_MASK = ~ALL
};
MOZ_BEGIN_NESTED_ENUM_CLASS(Category, uint32_t)
OTHER = 0x04,
CSS = 0x08,
JS = 0x10,
GC = 0x20,
CC = 0x40,
NETWORK = 0x80,
GRAPHICS = 0x100,
STORAGE = 0x200,
EVENTS = 0x400,
// 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
MOZ_END_NESTED_ENUM_CLASS(Category)
};
static_assert((static_cast<int>(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
@ -88,20 +103,20 @@ class ProfileEntry
bool isCpp() const volatile { return hasFlag(IS_CPP_ENTRY); }
bool isJs() const volatile { return !isCpp(); }
bool isCopyLabel() const volatile { return hasFlag(FRAME_LABEL_COPY); };
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 setLabel(const char* aString) volatile { string = aString; }
const char* label() const volatile { return string; }
void setJsFrame(JSScript *aScript, jsbytecode *aPc) volatile {
void initJsFrame(JSScript* aScript, jsbytecode* aPc) volatile {
flags_ = 0;
spOrScript = aScript;
setPC(aPc);
}
void setCppFrame(void *aSp, uint32_t aLine) volatile {
void initCppFrame(void* aSp, uint32_t aLine) volatile {
flags_ = IS_CPP_ENTRY;
spOrScript = aSp;
lineOrPc = static_cast<int32_t>(aLine);
lineOrPcOffset = static_cast<int32_t>(aLine);
}
void setFlag(uint32_t flag) volatile {
@ -119,26 +134,50 @@ class ProfileEntry
uint32_t flags() const volatile {
return flags_;
}
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<uint32_t>(c));
}
void *stackAddress() const volatile {
void setOSR() volatile {
MOZ_ASSERT(isJs());
setFlag(OSR);
}
void unsetOSR() volatile {
MOZ_ASSERT(isJs());
unsetFlag(OSR);
}
bool isOSR() const volatile {
return hasFlag(OSR);
}
void* stackAddress() const volatile {
MOZ_ASSERT(!isJs());
return spOrScript;
}
JSScript *script() const volatile {
MOZ_ASSERT(isJs());
return (JSScript *)spOrScript;
}
JSScript* script() const volatile;
uint32_t line() const volatile {
MOZ_ASSERT(!isJs());
return static_cast<uint32_t>(lineOrPc);
return static_cast<uint32_t>(lineOrPcOffset);
}
// Note that the pointer returned might be invalid.
JSScript* rawScript() const volatile {
MOZ_ASSERT(isJs());
return (JSScript*)spOrScript;
}
// We can't know the layout of JSScript, so look in vm/SPSProfiler.cpp.
JS_FRIEND_API(jsbytecode *) pc() const volatile;
JS_FRIEND_API(void) setPC(jsbytecode *pc) volatile;
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
@ -147,22 +186,22 @@ class ProfileEntry
static size_t offsetOfLabel() { return offsetof(ProfileEntry, string); }
static size_t offsetOfSpOrScript() { return offsetof(ProfileEntry, spOrScript); }
static size_t offsetOfLineOrPc() { return offsetof(ProfileEntry, lineOrPc); }
static size_t offsetOfLineOrPcOffset() { return offsetof(ProfileEntry, lineOrPcOffset); }
static size_t offsetOfFlags() { return offsetof(ProfileEntry, flags_); }
};
JS_FRIEND_API(void)
SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size,
SetContextProfilingStack(JSContext* cx, ProfileEntry* stack, uint32_t* size,
uint32_t max);
JS_FRIEND_API(void)
EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled);
EnableContextProfilingStack(JSContext* cx, bool enabled);
JS_FRIEND_API(void)
RegisterRuntimeProfilingEventMarker(JSRuntime *rt, void (*fn)(const char *));
RegisterContextProfilingEventMarker(JSContext* cx, void (*fn)(const char*));
JS_FRIEND_API(jsbytecode*)
ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip);
ProfilingGetPC(JSContext* cx, JSScript* script, void* ip);
} // namespace js

View File

@ -1,95 +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::PropertyKey implementation. */
#ifndef js_PropertyKey_h
#define js_PropertyKey_h
#include "js/TypeDecls.h"
#include "js/Value.h"
namespace JS {
class PropertyKey;
namespace detail {
extern JS_PUBLIC_API(bool)
ToPropertyKeySlow(JSContext *cx, HandleValue v, PropertyKey *key);
} // namespace detail
/*
* A PropertyKey is a key used to access some property on an object. It is a
* natural way to represent a property accessed using a JavaScript value.
*
* PropertyKey can represent indexes, named properties, and ES6 symbols. The
* latter aren't implemented in SpiderMonkey yet, but PropertyKey carves out
* space for them.
*/
class PropertyKey
{
Value v;
friend JS_PUBLIC_API(bool) detail::ToPropertyKeySlow(JSContext *cx, HandleValue v, PropertyKey *key);
public:
explicit PropertyKey(uint32_t index) : v(PrivateUint32Value(index)) {}
/*
* An index is a string property name whose characters exactly spell out an
* unsigned 32-bit integer in decimal: "0", "1", "2", ...., "4294967294",
* "4294967295".
*/
bool isIndex(uint32_t *index) {
// The implementation here assumes that private uint32_t are stored
// using the int32_t representation. This is purely an implementation
// detail: embedders must not rely upon this!
if (!v.isInt32())
return false;
*index = v.toPrivateUint32();
return true;
}
/*
* A name is a string property name which is *not* an index. Note that by
* the ECMAScript language grammar, any dotted property access |obj.prop|
* will access a named property.
*/
bool isName(JSString **str) {
uint32_t dummy;
if (isIndex(&dummy))
return false;
*str = v.toString();
return true;
}
/*
* A symbol is a property name that's a Symbol, a particular kind of object
* in ES6. It is the only kind of property name that's not a string.
*
* SpiderMonkey doesn't yet implement symbols, but we're carving out API
* space for them in advance.
*/
bool isSymbol() {
return false;
}
};
inline bool
ToPropertyKey(JSContext *cx, HandleValue v, PropertyKey *key)
{
if (v.isInt32() && v.toInt32() >= 0) {
*key = PropertyKey(uint32_t(v.toInt32()));
return true;
}
return detail::ToPropertyKeySlow(cx, v, key);
}
} // namespace JS
#endif /* js_PropertyKey_h */

View File

@ -0,0 +1,632 @@
/* -*- 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_Proxy_h
#define js_Proxy_h
#include "mozilla/Maybe.h"
#include "jsfriendapi.h"
#include "js/CallNonGenericMethod.h"
#include "js/Class.h"
namespace js {
using JS::AutoIdVector;
using JS::CallArgs;
using JS::Handle;
using JS::HandleId;
using JS::HandleObject;
using JS::HandleValue;
using JS::IsAcceptableThis;
using JS::MutableHandle;
using JS::MutableHandleObject;
using JS::MutableHandleValue;
using JS::NativeImpl;
using JS::ObjectOpResult;
using JS::PrivateValue;
using JS::PropertyDescriptor;
using JS::Value;
class RegExpGuard;
class JS_FRIEND_API(Wrapper);
/*
* A proxy is a JSObject with highly customizable behavior. ES6 specifies a
* single kind of proxy, but the customization mechanisms we use to implement
* ES6 Proxy objects are also useful wherever an object with weird behavior is
* wanted. Proxies are used to implement:
*
* - the scope objects used by the Debugger's frame.eval() method
* (see js::GetDebugScopeForFunction)
*
* - the khuey hack, whereby a whole compartment can be blown away
* even if other compartments hold references to objects in it
* (see js::NukeCrossCompartmentWrappers)
*
* - XPConnect security wrappers, which protect chrome from malicious content
* (js/xpconnect/wrappers)
*
* - DOM objects with special property behavior, like named getters
* (dom/bindings/Codegen.py generates these proxies from WebIDL)
*
* - semi-transparent use of objects that live in other processes
* (CPOWs, implemented in js/ipc)
*
* ### Proxies and internal methods
*
* ES2016 specifies 13 internal methods. The runtime semantics of just
* about everything a script can do to an object is specified in terms
* of these internal methods. For example:
*
* JS code ES6 internal method that gets called
* --------------------------- --------------------------------
* obj.prop obj.[[Get]](obj, "prop")
* "prop" in obj obj.[[HasProperty]]("prop")
* new obj() obj.[[Construct]](<empty argument List>)
*
* With regard to the implementation of these internal methods, there are three
* very different kinds of object in SpiderMonkey.
*
* 1. Native objects' internal methods are implemented in vm/NativeObject.cpp,
* with duplicate (but functionally identical) implementations scattered
* through the ICs and JITs.
*
* 2. Certain non-native objects have internal methods that are implemented as
* magical js::ObjectOps hooks. We're trying to get rid of these.
*
* 3. All other objects are proxies. A proxy's internal methods are
* implemented in C++, as the virtual methods of a C++ object stored on the
* proxy, known as its handler.
*
* This means that just about anything you do to a proxy will end up going
* through a C++ virtual method call. Possibly several. There's no reason the
* JITs and ICs can't specialize for particular proxies, based on the handler;
* but currently we don't do much of this, so the virtual method overhead
* typically is actually incurred.
*
* ### The proxy handler hierarchy
*
* A major use case for proxies is to forward each internal method call to
* another object, known as its target. The target can be an arbitrary JS
* object. Not every proxy has the notion of a target, however.
*
* To minimize code duplication, a set of abstract proxy handler classes is
* provided, from which other handlers may inherit. These abstract classes are
* organized in the following hierarchy:
*
* BaseProxyHandler
* |
* Wrapper // has a target, can be unwrapped to reveal
* | // target (see js::CheckedUnwrap)
* |
* CrossCompartmentWrapper // target is in another compartment;
* // implements membrane between compartments
*
* Example: Some DOM objects (including all the arraylike DOM objects) are
* implemented as proxies. Since these objects don't need to forward operations
* to any underlying JS object, DOMJSProxyHandler directly subclasses
* BaseProxyHandler.
*
* Gecko's security wrappers are examples of cross-compartment wrappers.
*
* ### Proxy prototype chains
*
* In addition to the normal methods, there are two models for proxy prototype
* chains.
*
* 1. Proxies can use the standard prototype mechanism used throughout the
* engine. To do so, simply pass a prototype to NewProxyObject() at
* creation time. All prototype accesses will then "just work" to treat the
* proxy as a "normal" object.
*
* 2. A proxy can implement more complicated prototype semantics (if, for
* example, it wants to delegate the prototype lookup to a wrapped object)
* by passing Proxy::LazyProto as the prototype at create time. This
* guarantees that the getPrototype() handler method will be called every
* time the object's prototype chain is accessed.
*
* This system is implemented with two methods: {get,set}Prototype. The
* default implementation of setPrototype throws a TypeError. Since it is
* not possible to create an object without a sense of prototype chain,
* handlers must implement getPrototype if opting in to the dynamic
* prototype system.
*/
/*
* BaseProxyHandler is the most generic kind of proxy handler. It does not make
* any assumptions about the target. Consequently, it does not provide any
* default implementation for most methods. As a convenience, a few high-level
* methods, like get() and set(), are given default implementations that work by
* calling the low-level methods, like getOwnPropertyDescriptor().
*
* 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.
*/
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)
{ }
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<PropertyDescriptor> desc) const = 0;
virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
Handle<PropertyDescriptor> 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 bool enumerate(JSContext* cx, HandleObject proxy, MutableHandleObject objp) const;
virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> 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; }
};
extern JS_FRIEND_DATA(const js::Class* const) ProxyClassPtr;
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();
}
};
// 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
// be easily swapped with other objects (via RemapWrapper) and to mimic the
// layout of other objects (proxies and other objects have the same size) so
// that common code can access either type of object.
//
// See GetReservedOrProxyPrivateSlot below.
struct ProxyDataLayout
{
ProxyValueArray* values;
const BaseProxyHandler* handler;
};
const uint32_t ProxyDataOffset = 2 * sizeof(void*);
inline ProxyDataLayout*
GetProxyDataLayout(JSObject* obj)
{
MOZ_ASSERT(IsProxy(obj));
return reinterpret_cast<ProxyDataLayout*>(reinterpret_cast<uint8_t*>(obj) + ProxyDataOffset);
}
inline const ProxyDataLayout*
GetProxyDataLayout(const JSObject* obj)
{
MOZ_ASSERT(IsProxy(obj));
return reinterpret_cast<const ProxyDataLayout*>(reinterpret_cast<const uint8_t*>(obj) +
ProxyDataOffset);
}
} // namespace detail
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 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 void
SetProxyHandler(JSObject* obj, const BaseProxyHandler* handler)
{
detail::GetProxyDataLayout(obj)->handler = handler;
}
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];
// Trigger a barrier before writing the slot.
if (vp->isMarkable() || extra.isMarkable())
SetValueInProxy(vp, extra);
else
*vp = extra;
}
inline bool
IsScriptedProxy(const JSObject* obj)
{
return IsProxy(obj) && GetProxyHandler(obj)->isScripted();
}
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<const shadow::Object*>(obj)->slotRef(slot);
}
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<shadow::Object*>(obj);
if (sobj->slotRef(slot).isMarkable() || value.isMarkable())
SetReservedOrProxyPrivateSlotWithBarrier(obj, slot, value);
else
sobj->slotRef(slot) = value;
}
class MOZ_STACK_CLASS ProxyOptions {
protected:
/* protected constructor for subclass */
explicit ProxyOptions(bool singletonArg, bool lazyProtoArg = false)
: singleton_(singletonArg),
lazyProto_(lazyProtoArg),
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_;
};
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)
#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()
#ifdef JS_DEBUG
: context(nullptr)
, enteredAction(BaseProxyHandler::NONE)
#endif
{}
void reportErrorIfExceptionIsNotPending(JSContext* cx, jsid id);
bool allow;
bool rv;
#ifdef JS_DEBUG
JSContext* context;
mozilla::Maybe<HandleObject> enteredProxy;
mozilla::Maybe<HandleId> 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);
#else
inline void recordEnter(JSContext* cx, JSObject* proxy, jsid id, Action act) {}
inline void recordLeave() {}
#endif
};
#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);
}
};
#else
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);
#else
inline void assertEnteredPolicy(JSContext* cx, JSObject* obj, jsid id,
BaseProxyHandler::Action act)
{}
#endif
extern JS_FRIEND_API(JSObject*)
InitProxyClass(JSContext* cx, JS::HandleObject obj);
} /* namespace js */
#endif /* js_Proxy_h */

View File

@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Ways to get various per-Realm objects. All the getters declared in this
* header operate on the Realm corresponding to the current compartment on the
* JSContext.
*/
#ifndef js_Realm_h
#define js_Realm_h
#include "jstypes.h"
struct JSContext;
class JSObject;
namespace JS {
extern JS_PUBLIC_API(JSObject*)
GetRealmObjectPrototype(JSContext* cx);
extern JS_PUBLIC_API(JSObject*)
GetRealmFunctionPrototype(JSContext* cx);
extern JS_PUBLIC_API(JSObject*)
GetRealmArrayPrototype(JSContext* cx);
extern JS_PUBLIC_API(JSObject*)
GetRealmErrorPrototype(JSContext* cx);
extern JS_PUBLIC_API(JSObject*)
GetRealmIteratorPrototype(JSContext* cx);
} // namespace JS
#endif // js_Realm_h

View File

1213
android/arm64-v8a/include/spidermonkey/js/RootingAPI.h Executable file → Normal file

File diff suppressed because it is too large Load Diff

75
android/arm64-v8a/include/spidermonkey/js/SliceBudget.h Executable file → Normal file
View File

@ -11,30 +11,60 @@
namespace js {
/*
* This class records how much work has been done in a given collection slice, so that
* we can return before pausing for too long. Some slices are allowed to run for
* unlimited time, and others are bounded. To reduce the number of gettimeofday
* calls, we only check the time every 1000 operations.
*/
struct JS_PUBLIC_API(SliceBudget)
struct JS_PUBLIC_API(TimeBudget)
{
int64_t budget;
explicit TimeBudget(int64_t milliseconds) { budget = milliseconds; }
};
struct JS_PUBLIC_API(WorkBudget)
{
int64_t budget;
explicit WorkBudget(int64_t work) { budget = work; }
};
/*
* This class records how much work has been done in a given collection slice,
* so that we can return before pausing for too long. Some slices are allowed
* 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;
bool checkOverBudget();
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;
int64_t deadline; /* in microseconds */
intptr_t counter;
static const intptr_t CounterReset = 1000;
static const int64_t Unlimited = 0;
static int64_t TimeBudget(int64_t millis);
static int64_t WorkBudget(int64_t work);
static const int64_t UnlimitedTimeBudget = -1;
static const int64_t UnlimitedWorkBudget = -1;
/* Equivalent to SliceBudget(UnlimitedBudget). */
SliceBudget();
/* Use to create an unlimited budget. */
static SliceBudget unlimited() { return SliceBudget(); }
/* Instantiate as SliceBudget(Time/WorkBudget(n)). */
explicit SliceBudget(int64_t budget);
/* Instantiate as SliceBudget(TimeBudget(n)). */
explicit SliceBudget(TimeBudget time);
void reset() {
/* Instantiate as SliceBudget(WorkBudget(n)). */
explicit SliceBudget(WorkBudget work);
void makeUnlimited() {
deadline = unlimitedDeadline;
counter = unlimitedStartCounter;
}
@ -43,22 +73,17 @@ struct JS_PUBLIC_API(SliceBudget)
counter -= amt;
}
bool checkOverBudget();
bool isOverBudget() {
if (counter >= 0)
if (counter > 0)
return false;
return checkOverBudget();
}
bool isUnlimited() {
return deadline == unlimitedDeadline;
}
private:
static const int64_t unlimitedDeadline = INT64_MAX;
static const intptr_t unlimitedStartCounter = INTPTR_MAX;
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;
};
} // namespace js

View File

@ -7,7 +7,8 @@
#ifndef js_StructuredClone_h
#define js_StructuredClone_h
#include "mozilla/NullPtr.h"
#include "mozilla/Attributes.h"
#include "mozilla/BufferList.h"
#include <stdint.h>
@ -24,104 +25,153 @@ struct JSStructuredCloneWriter;
// API for the HTML5 internal structured cloning algorithm.
namespace JS {
enum class StructuredCloneScope : uint32_t {
SameProcessSameThread,
SameProcessDifferentThread,
DifferentProcess
};
enum TransferableOwnership {
// Transferable data has not been filled in yet
/** Transferable data has not been filled in yet */
SCTAG_TMO_UNFILLED = 0,
// Structured clone buffer does not yet own the data
/** 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
/** 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
/** Data is a pointer that can be freed */
SCTAG_TMO_ALLOC_DATA = 2,
// Data is a SharedArrayBufferObject's buffer
SCTAG_TMO_SHARED_BUFFER = 3,
/** Data is a memory mapped pointer */
SCTAG_TMO_MAPPED_DATA = 3,
// Data is a memory mapped pointer
SCTAG_TMO_MAPPED_DATA = 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 = 5,
/**
* 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
};
class CloneDataPolicy
{
bool sharedArrayBuffer_;
public:
// The default is to allow all policy-controlled aspects.
CloneDataPolicy() :
sharedArrayBuffer_(true)
{}
// In the JS engine, SharedArrayBuffers can only be cloned intra-process
// because the shared memory areas are allocated in process-private memory.
// Clients should therefore deny SharedArrayBuffers when cloning data that
// are to be transmitted inter-process.
//
// Clients should also deny SharedArrayBuffers when cloning data that are to
// be transmitted intra-process if policy needs dictate such denial.
CloneDataPolicy& denySharedArrayBuffer() {
sharedArrayBuffer_ = false;
return *this;
}
bool isSharedArrayBufferAllowed() const {
return sharedArrayBuffer_;
}
};
} /* namespace JS */
// Read structured data from the reader r. This hook is used to read a value
// previously serialized by a call to the WriteStructuredCloneOp hook.
//
// tag and data are the pair of uint32_t values from the header. The callback
// may use the JS_Read* APIs to read any other relevant parts of the object
// 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);
/**
* Read structured data from the reader r. This hook is used to read a value
* previously serialized by a call to the WriteStructuredCloneOp hook.
*
* tag and data are the pair of uint32_t values from the header. The callback
* may use the JS_Read* APIs to read any other relevant parts of the object
* 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);
// Structured data serialization hook. The engine can write primitive values,
// Objects, Arrays, Dates, RegExps, TypedArrays, and ArrayBuffers. Any other
// type of object requires application support. This callback must first use
// the JS_WriteUint32Pair API to write an object header, passing a value
// greater than JS_SCTAG_USER to the tag parameter. Then it can use the
// JS_Write* APIs to write any other relevant parts of the value v to the
// writer w. closure is any value passed to the JS_WriteStructuredCLone function.
//
// Return true on success, false on error/exception.
typedef bool (*WriteStructuredCloneOp)(JSContext *cx, JSStructuredCloneWriter *w,
JS::HandleObject obj, void *closure);
/**
* Structured data serialization hook. The engine can write primitive values,
* Objects, Arrays, Dates, RegExps, TypedArrays, ArrayBuffers, Sets, Maps,
* and SharedTypedArrays. Any other type of object requires application support.
* This callback must first use the JS_WriteUint32Pair API to write an object
* header, passing a value greater than JS_SCTAG_USER to the tag parameter.
* Then it can use the JS_Write* APIs to write any other relevant parts of
* the value v to the writer w. closure is any value passed to the
* JS_WriteStructuredClone function.
*
* Return true on success, false on error/exception.
*/
typedef bool (*WriteStructuredCloneOp)(JSContext* cx, JSStructuredCloneWriter* w,
JS::HandleObject obj, void* closure);
// This is called when JS_WriteStructuredClone is given an invalid transferable.
// To follow HTML5, the application must throw a DATA_CLONE_ERR DOMException
// with error set to one of the JS_SCERR_* values.
typedef void (*StructuredCloneErrorOp)(JSContext *cx, uint32_t errorid);
/**
* This is called when JS_WriteStructuredClone is given an invalid transferable.
* To follow HTML5, the application must throw a DATA_CLONE_ERR DOMException
* with error set to one of the JS_SCERR_* values.
*/
typedef void (*StructuredCloneErrorOp)(JSContext* cx, uint32_t errorid);
// This is called when JS_ReadStructuredClone receives a transferable object
// not known to the engine. If this hook does not exist or returns false, the
// JS engine calls the reportError op if set, otherwise it throws a
// 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,
/**
* This is called when JS_ReadStructuredClone receives a transferable object
* not known to the engine. If this hook does not exist or returns false, the
* JS engine calls the reportError op if set, otherwise it throws a
* 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);
// Called when JS_WriteStructuredClone receives a transferable object not
// handled by the engine. If this hook does not exist or returns false, the JS
// engine will call the reportError hook or fall back to throwing a
// DATA_CLONE_ERR DOM Exception. This method is called before any other
// callback.
//
// tag: indicates what type of transferable this is. Must be greater than
// 0xFFFF0201 (value of the internal SCTAG_TRANSFER_MAP_PENDING_ENTRY)
//
// ownership: see TransferableOwnership, above. Used to communicate any needed
// ownership info to the FreeTransferStructuredCloneOp.
//
// content, extraData: what the ReadTransferStructuredCloneOp will receive
//
typedef bool (*TransferStructuredCloneOp)(JSContext *cx,
/**
* Called when JS_WriteStructuredClone receives a transferable object not
* handled by the engine. If this hook does not exist or returns false, the JS
* engine will call the reportError hook or fall back to throwing a
* DATA_CLONE_ERR DOM Exception. This method is called before any other
* callback.
*
* tag: indicates what type of transferable this is. Must be greater than
* 0xFFFF0201 (value of the internal SCTAG_TRANSFER_MAP_PENDING_ENTRY)
*
* ownership: see TransferableOwnership, above. Used to communicate any needed
* ownership info to the FreeTransferStructuredCloneOp.
*
* content, extraData: what the ReadTransferStructuredCloneOp will receive
*/
typedef bool (*TransferStructuredCloneOp)(JSContext* cx,
JS::Handle<JSObject*> obj,
void *closure,
void* closure,
// Output:
uint32_t *tag,
JS::TransferableOwnership *ownership,
void **content,
uint64_t *extraData);
uint32_t* tag,
JS::TransferableOwnership* ownership,
void** content,
uint64_t* extraData);
// Called when JS_ClearStructuredClone has to free an unknown transferable
// object. Note that it should never trigger a garbage collection (and will
// assert in a debug build if it does.)
/**
* Called when freeing an unknown transferable object. Note that it
* should never trigger a garbage collection (and will assert in a
* debug build if it does.)
*/
typedef void (*FreeTransferStructuredCloneOp)(uint32_t tag, JS::TransferableOwnership ownership,
void *content, uint64_t extraData, void *closure);
void* content, uint64_t extraData, void* closure);
// The maximum supported structured-clone serialization format version. 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 4
// 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
struct JSStructuredCloneCallbacks {
ReadStructuredCloneOp read;
@ -132,86 +182,141 @@ struct JSStructuredCloneCallbacks {
FreeTransferStructuredCloneOp freeTransfer;
};
// Note: if the *data contains transferable objects, it can be read only once.
enum OwnTransferablePolicy {
OwnsTransferablesIfAny,
IgnoreTransferablesIfAny,
NoTransferables
};
class MOZ_NON_MEMMOVABLE JSStructuredCloneData : public mozilla::BufferList<js::SystemAllocPolicy>
{
typedef js::SystemAllocPolicy AllocPolicy;
typedef mozilla::BufferList<js::SystemAllocPolicy> BufferList;
static const size_t kInitialSize = 0;
static const size_t kInitialCapacity = 4096;
static const size_t kStandardCapacity = 4096;
const JSStructuredCloneCallbacks* callbacks_;
void* closure_;
OwnTransferablePolicy ownTransferables_;
void setOptionalCallbacks(const JSStructuredCloneCallbacks* callbacks,
void* closure,
OwnTransferablePolicy policy) {
callbacks_ = callbacks;
closure_ = closure;
ownTransferables_ = policy;
}
friend struct JSStructuredCloneWriter;
friend class JS_PUBLIC_API(JSAutoStructuredCloneBuffer);
public:
explicit JSStructuredCloneData(AllocPolicy aAP = AllocPolicy())
: BufferList(kInitialSize, kInitialCapacity, kStandardCapacity, aAP)
, callbacks_(nullptr)
, closure_(nullptr)
, ownTransferables_(OwnTransferablePolicy::NoTransferables)
{}
MOZ_IMPLICIT JSStructuredCloneData(BufferList&& buffers)
: BufferList(Move(buffers))
, callbacks_(nullptr)
, closure_(nullptr)
, ownTransferables_(OwnTransferablePolicy::NoTransferables)
{}
JSStructuredCloneData(JSStructuredCloneData&& other) = default;
JSStructuredCloneData& operator=(JSStructuredCloneData&& other) = default;
~JSStructuredCloneData();
using BufferList::BufferList;
};
/** Note: if the *data contains transferable objects, it can be read only once. */
JS_PUBLIC_API(bool)
JS_ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, uint32_t version,
JS_ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data, uint32_t version,
JS::StructuredCloneScope scope,
JS::MutableHandleValue vp,
const JSStructuredCloneCallbacks *optionalCallbacks, void *closure);
// Note: On success, the caller is responsible for calling
// JS_ClearStructuredClone(*datap, nbytes, optionalCallbacks, closure).
JS_PUBLIC_API(bool)
JS_WriteStructuredClone(JSContext *cx, JS::HandleValue v, uint64_t **datap, size_t *nbytesp,
const JSStructuredCloneCallbacks *optionalCallbacks,
void *closure, JS::HandleValue transferable);
const JSStructuredCloneCallbacks* optionalCallbacks, void* closure);
JS_PUBLIC_API(bool)
JS_ClearStructuredClone(uint64_t *data, size_t nbytes,
const JSStructuredCloneCallbacks *optionalCallbacks,
void *closure);
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(const uint64_t *data, size_t nbytes, bool *hasTransferable);
JS_StructuredCloneHasTransferables(JSStructuredCloneData& data, bool* hasTransferable);
JS_PUBLIC_API(bool)
JS_StructuredClone(JSContext *cx, JS::HandleValue v, JS::MutableHandleValue vp,
const JSStructuredCloneCallbacks *optionalCallbacks, void *closure);
JS_StructuredClone(JSContext* cx, JS::HandleValue v, JS::MutableHandleValue vp,
const JSStructuredCloneCallbacks* optionalCallbacks, void* closure);
// RAII sugar for JS_WriteStructuredClone.
/** RAII sugar for JS_WriteStructuredClone. */
class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
uint64_t *data_;
size_t nbytes_;
const JS::StructuredCloneScope scope_;
JSStructuredCloneData data_;
uint32_t version_;
const JSStructuredCloneCallbacks *callbacks_;
void *closure_;
public:
JSAutoStructuredCloneBuffer()
: data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION),
callbacks_(nullptr), closure_(nullptr)
{}
JSAutoStructuredCloneBuffer(JS::StructuredCloneScope scope,
const JSStructuredCloneCallbacks* callbacks, void* closure)
: scope_(scope), version_(JS_STRUCTURED_CLONE_VERSION)
{
data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
}
JSAutoStructuredCloneBuffer(const JSStructuredCloneCallbacks *callbacks, void *closure)
: data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION),
callbacks_(callbacks), closure_(closure)
{}
JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer &&other);
JSAutoStructuredCloneBuffer &operator=(JSAutoStructuredCloneBuffer &&other);
JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other);
JSAutoStructuredCloneBuffer& operator=(JSAutoStructuredCloneBuffer&& other);
~JSAutoStructuredCloneBuffer() { clear(); }
uint64_t *data() const { return data_; }
size_t nbytes() const { return nbytes_; }
JSStructuredCloneData& data() { return data_; }
bool empty() const { return !data_.Size(); }
void clear();
void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
// Copy some memory. It will be automatically freed by the destructor.
bool copy(const uint64_t *data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
/** Copy some memory. It will be automatically freed by the destructor. */
bool copy(const JSStructuredCloneData& data, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr);
// Adopt some memory. It will be automatically freed by the destructor.
// data must have been allocated by the JS engine (e.g., extracted via
// JSAutoStructuredCloneBuffer::steal).
void adopt(uint64_t *data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
/**
* 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);
// Remove the buffer so that it will not be automatically freed.
// After this, the caller is responsible for feeding the memory back to
// JSAutoStructuredCloneBuffer::adopt.
void steal(uint64_t **datap, size_t *nbytesp, uint32_t *versionp=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);
bool read(JSContext *cx, JS::MutableHandleValue vp,
const JSStructuredCloneCallbacks *optionalCallbacks=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 write(JSContext *cx, JS::HandleValue v,
const JSStructuredCloneCallbacks *optionalCallbacks=nullptr, void *closure=nullptr);
bool read(JSContext* cx, JS::MutableHandleValue vp,
const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
bool write(JSContext *cx, JS::HandleValue v, JS::HandleValue transferable,
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) MOZ_DELETE;
JSAutoStructuredCloneBuffer &operator=(const JSAutoStructuredCloneBuffer &other) MOZ_DELETE;
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.
@ -220,26 +325,34 @@ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
#define JS_SCERR_RECURSION 0
#define JS_SCERR_TRANSFERABLE 1
JS_PUBLIC_API(void)
JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks);
#define JS_SCERR_DUP_TRANSFERABLE 2
#define JS_SCERR_UNSUPPORTED_TYPE 3
JS_PUBLIC_API(bool)
JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2);
JS_ReadUint32Pair(JSStructuredCloneReader* r, uint32_t* p1, uint32_t* p2);
JS_PUBLIC_API(bool)
JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len);
JS_ReadBytes(JSStructuredCloneReader* r, void* p, size_t len);
JS_PUBLIC_API(bool)
JS_ReadTypedArray(JSStructuredCloneReader *r, JS::MutableHandleValue vp);
JS_ReadTypedArray(JSStructuredCloneReader* r, JS::MutableHandleValue vp);
JS_PUBLIC_API(bool)
JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32_t tag, uint32_t data);
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_WriteBytes(JSStructuredCloneWriter* w, const void* p, size_t len);
JS_PUBLIC_API(bool)
JS_WriteTypedArray(JSStructuredCloneWriter *w, JS::HandleValue v);
JS_WriteString(JSStructuredCloneWriter* w, JS::HandleString str);
JS_PUBLIC_API(bool)
JS_WriteTypedArray(JSStructuredCloneWriter* w, JS::HandleValue v);
JS_PUBLIC_API(bool)
JS_ObjectNotWritten(JSStructuredCloneWriter* w, JS::HandleObject obj);
JS_PUBLIC_API(JS::StructuredCloneScope)
JS_GetStructuredCloneScope(JSStructuredCloneWriter* w);
#endif /* js_StructuredClone_h */

View File

@ -0,0 +1,65 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef js_SweepingAPI_h
#define js_SweepingAPI_h
#include "js/HeapAPI.h"
namespace js {
template <typename T>
class WeakCacheBase {};
} // namespace js
namespace JS {
template <typename T> class WeakCache;
namespace shadow {
JS_PUBLIC_API(void)
RegisterWeakCache(JS::Zone* zone, JS::WeakCache<void*>* cachep);
} // namespace shadow
// A WeakCache stores the given Sweepable container and links itself into a
// list of such caches that are swept during each GC.
template <typename T>
class WeakCache : public js::WeakCacheBase<T>,
private mozilla::LinkedListElement<WeakCache<T>>
{
friend class mozilla::LinkedListElement<WeakCache<T>>;
friend class mozilla::LinkedList<WeakCache<T>>;
WeakCache() = delete;
WeakCache(const WeakCache&) = delete;
using SweepFn = void (*)(T*);
SweepFn sweeper;
T cache;
public:
using Type = T;
template <typename U>
WeakCache(Zone* zone, U&& initial)
: cache(mozilla::Forward<U>(initial))
{
sweeper = GCPolicy<T>::sweep;
shadow::RegisterWeakCache(zone, reinterpret_cast<WeakCache<void*>*>(this));
}
WeakCache(WeakCache&& other)
: sweeper(other.sweeper),
cache(mozilla::Move(other.cache))
{
}
const T& get() const { return cache; }
T& get() { return cache; }
void sweep() { sweeper(&cache); }
};
} // namespace JS
#endif // js_SweepingAPI_h

View File

@ -0,0 +1,212 @@
/* -*- 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_TraceKind_h
#define js_TraceKind_h
#include "mozilla/UniquePtr.h"
#include "js/TypeDecls.h"
// Forward declarations of all the types a TraceKind can denote.
namespace js {
class BaseShape;
class LazyScript;
class ObjectGroup;
class Shape;
class Scope;
namespace jit {
class JitCode;
} // namespace jit
} // namespace js
namespace JS {
// When tracing a thing, the GC needs to know about the layout of the object it
// is looking at. There are a fixed number of different layouts that the GC
// knows about. The "trace kind" is a static map which tells which layout a GC
// thing has.
//
// Although this map is public, the details are completely hidden. Not all of
// 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
};
const static uintptr_t OutOfLineTraceKindMask = 0x07;
static_assert(uintptr_t(JS::TraceKind::BaseShape) & OutOfLineTraceKindMask, "mask bits are set");
static_assert(uintptr_t(JS::TraceKind::JitCode) & OutOfLineTraceKindMask, "mask bits are set");
static_assert(uintptr_t(JS::TraceKind::LazyScript) & OutOfLineTraceKindMask, "mask bits are set");
static_assert(uintptr_t(JS::TraceKind::Scope) & OutOfLineTraceKindMask, "mask bits are set");
// When this header is imported inside SpiderMonkey, the class definitions are
// available and we can query those definitions to find the correct kind
// directly from the class hierarchy.
template <typename T>
struct MapTypeToTraceKind {
static const JS::TraceKind kind = T::TraceKind;
};
// When this header is used outside SpiderMonkey, the class definitions are not
// available, so the following table containing all public GC types is used.
#define JS_FOR_EACH_TRACEKIND(D) \
/* PrettyName TypeName AddToCCKind */ \
D(BaseShape, js::BaseShape, true) \
D(JitCode, js::jit::JitCode, true) \
D(LazyScript, js::LazyScript, true) \
D(Scope, js::Scope, true) \
D(Object, JSObject, true) \
D(ObjectGroup, js::ObjectGroup, true) \
D(Script, JSScript, true) \
D(Shape, js::Shape, true) \
D(String, JSString, false) \
D(Symbol, JS::Symbol, false)
// Map from all public types to their trace kind.
#define JS_EXPAND_DEF(name, type, _) \
template <> struct MapTypeToTraceKind<type> { \
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)
#undef EXPAND_ROOT_KIND
// These tagged pointers are special-cased for performance.
Id,
Value,
// Everything else.
Traceable,
Limit
};
// Most RootKind correspond directly to a trace kind.
template <TraceKind traceKind> struct MapTraceKindToRootKind {};
#define JS_EXPAND_DEF(name, _0, _1) \
template <> struct MapTraceKindToRootKind<JS::TraceKind::name> { \
static const JS::RootKind kind = JS::RootKind::name; \
};
JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF)
#undef JS_EXPAND_DEF
// Specify the RootKind for all types. Value and jsid map to special cases;
// pointer types we can derive directly from the TraceKind; everything else
// should go in the Traceable list and use GCPolicy<T>::trace for tracing.
template <typename T>
struct MapTypeToRootKind {
static const JS::RootKind kind = JS::RootKind::Traceable;
};
template <typename T>
struct MapTypeToRootKind<T*> {
static const JS::RootKind kind =
JS::MapTraceKindToRootKind<JS::MapTypeToTraceKind<T>::kind>::kind;
};
template <typename T>
struct MapTypeToRootKind<mozilla::UniquePtr<T>> {
static const JS::RootKind kind = JS::MapTypeToRootKind<T>::kind;
};
template <> struct MapTypeToRootKind<JS::Value> {
static const JS::RootKind kind = JS::RootKind::Value;
};
template <> struct MapTypeToRootKind<jsid> {
static const JS::RootKind kind = JS::RootKind::Id;
};
template <> struct MapTypeToRootKind<JSFunction*> : public MapTypeToRootKind<JSObject*> {};
// Fortunately, few places in the system need to deal with fully abstract
// cells. In those places that do, we generally want to move to a layout
// templated function as soon as possible. This template wraps the upcast
// for that dispatch.
//
// Given a call:
//
// DispatchTraceKindTyped(f, thing, traceKind, ... args)
//
// Downcast the |void *thing| to the specific type designated by |traceKind|,
// and pass it to the functor |f| along with |... args|, forwarded. Pass the
// 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.
// 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
#else
# define JS_DEPENDENT_TEMPLATE_HINT template
#endif
template <typename F, typename... Args>
auto
DispatchTraceKindTyped(F f, JS::TraceKind traceKind, Args&&... args)
-> decltype(f. JS_DEPENDENT_TEMPLATE_HINT operator()<JSObject>(mozilla::Forward<Args>(args)...))
{
switch (traceKind) {
#define JS_EXPAND_DEF(name, type, _) \
case JS::TraceKind::name: \
return f. JS_DEPENDENT_TEMPLATE_HINT operator()<type>(mozilla::Forward<Args>(args)...);
JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
#undef JS_EXPAND_DEF
default:
MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped.");
}
}
#undef JS_DEPENDENT_TEMPLATE_HINT
template <typename F, typename... Args>
auto
DispatchTraceKindTyped(F f, void* thing, JS::TraceKind traceKind, Args&&... args)
-> decltype(f(static_cast<JSObject*>(nullptr), mozilla::Forward<Args>(args)...))
{
switch (traceKind) {
#define JS_EXPAND_DEF(name, type, _) \
case JS::TraceKind::name: \
return f(static_cast<type*>(thing), mozilla::Forward<Args>(args)...);
JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
#undef JS_EXPAND_DEF
default:
MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped.");
}
}
} // namespace JS
#endif // js_TraceKind_h

519
android/arm64-v8a/include/spidermonkey/js/TracingAPI.h Executable file → Normal file
View File

@ -7,210 +7,397 @@
#ifndef js_TracingAPI_h
#define js_TracingAPI_h
#include "mozilla/NullPtr.h"
#include "jsalloc.h"
#include "jspubtd.h"
#include "js/HashTable.h"
#include "js/HeapAPI.h"
#include "js/TraceKind.h"
class JS_PUBLIC_API(JSTracer);
namespace JS {
class JS_PUBLIC_API(CallbackTracer);
template <typename T> class Heap;
template <typename T> class TenuredHeap;
}
// Tracer callback, called for each traceable thing directly referenced by a
// particular object or runtime structure. It is the callback responsibility
// to ensure the traversal of the full object graph via calling eventually
// JS_TraceChildren on the passed thing. In this case the callback must be
// prepared to deal with cycles in the traversal graph.
//
// kind argument is one of JSTRACE_OBJECT, JSTRACE_STRING or a tag denoting
// internal implementation-specific traversal kind. In the latter case the only
// operations on thing that the callback can do is to call JS_TraceChildren or
// JS_GetTraceThingInfo.
//
// If eagerlyTraceWeakMaps is true, when we trace a WeakMap visit all
// of its mappings. This should be used in cases where the tracer
// wants to use the existing liveness of entries.
typedef void
(* JSTraceCallback)(JSTracer *trc, void **thingp, JSGCTraceKind kind);
/** Returns a static string equivalent of |kind|. */
JS_FRIEND_API(const char*)
GCTraceKindToAscii(JS::TraceKind kind);
// Callback that JSTraceOp implementation can provide to return a string
// describing the reference traced with JS_CallTracer.
typedef void
(* JSTraceNamePrinter)(JSTracer *trc, char *buf, size_t bufsize);
} // namespace JS
enum WeakMapTraceKind {
DoNotTraceWeakMaps = 0,
TraceWeakMapValues = 1,
TraceWeakMapKeysValues = 2
/**
* 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:
JSTracer(JSRuntime *rt, JSTraceCallback traceCallback,
WeakMapTraceKind weakTraceKind = TraceWeakMapValues);
// Set debugging information about a reference to a traceable thing to prepare
// for the following call to JS_CallTracer.
//
// When printer is null, arg must be const char * or char * C string naming
// the reference and index must be either (size_t)-1 indicating that the name
// alone describes the reference or it must be an index into some array vector
// that stores the reference.
//
// When printer callback is not null, the arg and index arguments are
// available to the callback as debugPrintArg_ and debugPrintIndex_ fields
// of JSTracer.
//
// The storage for name or callback's arguments needs to live only until
// the following call to JS_CallTracer returns.
void setTracingDetails(JSTraceNamePrinter printer, const void *arg, size_t index) {
debugPrinter_ = printer;
debugPrintArg_ = arg;
debugPrintIndex_ = index;
}
void setTracingIndex(const char *name, size_t index) {
setTracingDetails(nullptr, (void *)name, index);
}
void setTracingName(const char *name) {
setTracingDetails(nullptr, (void *)name, size_t(-1));
}
// Remove the currently set tracing details.
void clearTracingDetails() {
debugPrinter_ = nullptr;
debugPrintArg_ = nullptr;
}
// Return true if tracing details are currently set.
bool hasTracingDetails() const;
// Get the string set with the most recent call to setTracingName or return
// fallback if a name printer function has been installed.
const char *tracingName(const char *fallback) const;
// Build a description of this edge in the heap graph. This call may invoke
// the debug printer, which may inspect arbitrary areas of the heap.
const char *getTracingEdgeName(char *buffer, size_t bufferSize);
// Access the currently active tracing details.
JSTraceNamePrinter debugPrinter() const;
const void *debugPrintArg() const;
size_t debugPrintIndex() const;
// Return the runtime set on the tracer.
JSRuntime *runtime() const { return runtime_; }
JSRuntime* runtime() const { return runtime_; }
// Return the weak map tracing behavior set on this tracer.
WeakMapTraceKind eagerlyTraceWeakMaps() const { return eagerlyTraceWeakMaps_; }
// Return the weak map tracing behavior currently set on this tracer.
WeakMapTraceKind weakMapAction() const { return weakMapAction_; }
// Update the trace callback.
void setTraceCallback(JSTraceCallback traceCallback);
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,
#ifdef JS_GC_ZEAL
// Sets the "real" location for a marked reference, when passing the address
// directly is not feasable. This address is used for matching against the
// store buffer when verifying the correctness of the entrees there.
//
// This is currently complicated by our need to nest calls for Values
// stored as keys in hash tables.
void setTracingLocation(void *location);
void unsetTracingLocation();
void **tracingLocation(void **thingp);
#else
void setTracingLocation(void *location) {}
void unsetTracingLocation() {}
void **tracingLocation(void **thingp) { return nullptr; }
// 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();
#ifdef DEBUG
bool checkEdges() { return checkEdges_; }
#endif
// We expose |callback| directly so that IS_GC_MARKING_TRACER can compare
// it to GCMarker::GrayCallback.
JSTraceCallback callback;
protected:
JSTracer(JSRuntime* rt, TracerKindTag tag,
WeakMapTraceKind weakTraceKind = TraceWeakMapValues)
: runtime_(rt)
, weakMapAction_(weakTraceKind)
#ifdef DEBUG
, checkEdges_(true)
#endif
, tag_(tag)
{}
#ifdef DEBUG
// Set whether to check edges are valid in debug builds.
void setCheckEdges(bool check) {
checkEdges_ = check;
}
#endif
private:
JSRuntime *runtime_;
JSTraceNamePrinter debugPrinter_;
const void *debugPrintArg_;
size_t debugPrintIndex_;
WeakMapTraceKind eagerlyTraceWeakMaps_;
#ifdef JS_GC_ZEAL
void *realLocation_;
JSRuntime* runtime_;
WeakMapTraceKind weakMapAction_;
#ifdef DEBUG
bool checkEdges_;
#endif
protected:
TracerKindTag tag_;
};
// The JS_Call*Tracer family of functions traces the given GC thing reference.
// This performs the tracing action configured on the given JSTracer:
// typically calling the JSTracer::callback or marking the thing as live.
//
// The argument to JS_Call*Tracer is an in-out param: when the function
// returns, the garbage collector might have moved the GC thing. In this case,
// the reference passed to JS_Call*Tracer will be updated to the object's new
// location. Callers of this method are responsible for updating any state
// that is dependent on the object's address. For example, if the object's
// address is used as a key in a hashtable, then the object must be removed
// and re-inserted with the correct hash.
//
extern JS_PUBLIC_API(void)
JS_CallValueTracer(JSTracer *trc, JS::Value *valuep, const char *name);
namespace JS {
extern JS_PUBLIC_API(void)
JS_CallIdTracer(JSTracer *trc, jsid *idp, const char *name);
class AutoTracingName;
class AutoTracingIndex;
class AutoTracingCallback;
extern JS_PUBLIC_API(void)
JS_CallObjectTracer(JSTracer *trc, JSObject **objp, const char *name);
extern JS_PUBLIC_API(void)
JS_CallStringTracer(JSTracer *trc, JSString **strp, const char *name);
extern JS_PUBLIC_API(void)
JS_CallScriptTracer(JSTracer *trc, JSScript **scriptp, const char *name);
extern JS_PUBLIC_API(void)
JS_CallHeapValueTracer(JSTracer *trc, JS::Heap<JS::Value> *valuep, const char *name);
extern JS_PUBLIC_API(void)
JS_CallHeapIdTracer(JSTracer *trc, JS::Heap<jsid> *idp, const char *name);
extern JS_PUBLIC_API(void)
JS_CallHeapObjectTracer(JSTracer *trc, JS::Heap<JSObject *> *objp, const char *name);
extern JS_PUBLIC_API(void)
JS_CallHeapStringTracer(JSTracer *trc, JS::Heap<JSString *> *strp, const char *name);
extern JS_PUBLIC_API(void)
JS_CallHeapScriptTracer(JSTracer *trc, JS::Heap<JSScript *> *scriptp, const char *name);
extern JS_PUBLIC_API(void)
JS_CallHeapFunctionTracer(JSTracer *trc, JS::Heap<JSFunction *> *funp, const char *name);
template <typename HashSetEnum>
inline void
JS_CallHashSetObjectTracer(JSTracer *trc, HashSetEnum &e, JSObject *const &key, const char *name)
class JS_PUBLIC_API(CallbackTracer) : public JSTracer
{
JSObject *updated = key;
trc->setTracingLocation(reinterpret_cast<void *>(&const_cast<JSObject *&>(key)));
JS_CallObjectTracer(trc, &updated, name);
if (updated != key)
e.rekeyFront(key, updated);
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;
};
#ifdef DEBUG
enum class TracerKind { DoNotCare, Moving, GrayBuffering, VerifyTraceProtoAndIface };
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_;
friend class AutoTracingIndex;
size_t contextIndex_;
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_;
}
};
// 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;
}
}
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;
}
}
};
} // namespace JS
JS::CallbackTracer*
JSTracer::asCallbackTracer()
{
MOZ_ASSERT(isCallbackTracer());
return static_cast<JS::CallbackTracer*>(this);
}
// Trace an object that is known to always be tenured. No post barriers are
// required in this case.
namespace JS {
// The JS::TraceEdge family of functions traces the given GC thing reference.
// This performs the tracing action configured on the given JSTracer: typically
// calling the JSTracer::callback or marking the thing as live.
//
// The argument to JS::TraceEdge is an in-out param: when the function returns,
// the garbage collector might have moved the GC thing. In this case, the
// reference passed to JS::TraceEdge will be updated to the thing's new
// location. Callers of this method are responsible for updating any state that
// is dependent on the object's address. For example, if the object's address
// is used as a key in a hashtable, then the object must be removed and
// re-inserted with the correct hash.
//
// Note that while |edgep| must never be null, it is fine for |*edgep| to be
// nullptr.
template <typename T>
extern JS_PUBLIC_API(void)
JS_CallTenuredObjectTracer(JSTracer *trc, JS::TenuredHeap<JSObject *> *objp, const char *name);
TraceEdge(JSTracer* trc, JS::Heap<T>* edgep, const char* name);
extern JS_PUBLIC_API(void)
JS_TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind);
TraceEdge(JSTracer* trc, JS::TenuredHeap<JSObject*>* edgep, const char* name);
// Edges that are always traced as part of root marking do not require
// incremental barriers. This function allows for marking non-barriered
// pointers, but asserts that this happens during root marking.
//
// Note that while |edgep| must never be null, it is fine for |*edgep| to be
// nullptr.
template <typename T>
extern JS_PUBLIC_API(void)
UnsafeTraceRoot(JSTracer* trc, T* edgep, const char* name);
extern JS_PUBLIC_API(void)
JS_TraceRuntime(JSTracer *trc);
TraceChildren(JSTracer* trc, GCCellPtr thing);
using ZoneSet = js::HashSet<Zone*, js::DefaultHasher<Zone*>, js::SystemAllocPolicy>;
using CompartmentSet = js::HashSet<JSCompartment*, js::DefaultHasher<JSCompartment*>,
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);
} // namespace JS
extern JS_PUBLIC_API(void)
JS_GetTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc,
void *thing, JSGCTraceKind kind, bool includeDetails);
JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc,
void* thing, JS::TraceKind kind, bool includeDetails);
namespace js {
// Trace an edge that is not a GC root and is not wrapped in a barriered
// wrapper for some reason.
//
// This method does not check if |*edgep| is non-null before tracing through
// it, so callers must check any nullable pointer before calling this method.
template <typename T>
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 <typename T>
extern JS_PUBLIC_API(bool)
EdgeNeedsSweep(JS::Heap<T>* edgep);
// Not part of the public API, but declared here so we can use it in GCPolicy
// which is.
template <typename T>
bool
IsAboutToBeFinalizedUnbarriered(T* thingp);
} // namespace gc
} // namespace js
#endif /* js_TracingAPI_h */

View File

@ -0,0 +1,285 @@
/* -*- 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_TrackedOptimizationInfo_h
#define js_TrackedOptimizationInfo_h
#include "mozilla/Maybe.h"
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)
// 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)
enum class TrackedStrategy : uint32_t {
#define STRATEGY_OP(name) name,
TRACKED_STRATEGY_LIST(STRATEGY_OP)
#undef STRATEGY_OPT
Count
};
enum class TrackedOutcome : uint32_t {
#define OUTCOME_OP(name) name,
TRACKED_OUTCOME_LIST(OUTCOME_OP)
#undef OUTCOME_OP
Count
};
enum class TrackedTypeSite : uint32_t {
#define TYPESITE_OP(name) name,
TRACKED_TYPESITE_LIST(TYPESITE_OP)
#undef TYPESITE_OP
Count
};
JS_PUBLIC_API(const char*)
TrackedStrategyString(TrackedStrategy strategy);
JS_PUBLIC_API(const char*)
TrackedOutcomeString(TrackedOutcome outcome);
JS_PUBLIC_API(const char*)
TrackedTypeSiteString(TrackedTypeSite site);
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<unsigned> lineno) = 0;
// Called once per entry.
virtual void operator()(TrackedTypeSite site, const char* mirType) = 0;
};
} // namespace JS
#endif // js_TrackedOptimizationInfo_h

2
android/arm64-v8a/include/spidermonkey/js/TypeDecls.h Executable file → Normal file
View File

@ -31,8 +31,6 @@ class JSAddonId;
struct jsid;
typedef char16_t jschar;
namespace JS {
typedef unsigned char Latin1Char;

954
android/arm64-v8a/include/spidermonkey/js/UbiNode.h Executable file → Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,8 +4,8 @@
* License, v. 2.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_UbiNodeTraverse_h
#define js_UbiNodeTraverse_h
#ifndef js_UbiNodeBreadthFirst_h
#define js_UbiNodeBreadthFirst_h
#include "js/UbiNode.h"
#include "js/Utility.h"
@ -37,9 +37,9 @@ namespace ubi {
// resources, move constructors and assignment operators are probably a
// good idea, too.
//
// bool operator() (BreadthFirst &traversal,
// Node origin, const Edge &edge,
// Handler::NodeData *referentData, bool first);
// bool operator() (BreadthFirst& traversal,
// Node origin, const Edge& edge,
// Handler::NodeData* referentData, bool first);
//
// The visitor function, called to report that we have traversed
// |edge| from |origin|. This is called once for each edge we traverse.
@ -57,8 +57,15 @@ namespace ubi {
// the algorithm knows whether it has just created the entry in
// |traversal.visited|, so it passes it along for convenience.
//
// The visitor function may call |traversal.abandonReferent()| if it
// doesn't want to traverse the outgoing edges of |edge.referent|. You can
// use this to limit the traversal to a given portion of the graph: it will
// never visit nodes reachable only through nodes that you have abandoned.
// Note that |abandonReferent| must be called the first time the given node
// is reached; that is, |first| must be true.
//
// The visitor function may call |traversal.stop()| if it doesn't want
// to visit any more nodes.
// to visit any more nodes at all.
//
// The visitor function may consult |traversal.visited| for information
// about other nodes, but it should not add or remove entries.
@ -71,14 +78,14 @@ template<typename Handler>
struct BreadthFirst {
// Construct a breadth-first traversal object that reports the nodes it
// reaches to |handler|. The traversal object reports OOM on |cx|, and
// asserts that no GC happens in |cx|'s runtime during its lifetime.
// 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)
: cx(cx), visited(cx), handler(handler), pending(cx),
traversalBegun(false), stopRequested(false)
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.
@ -88,6 +95,19 @@ struct BreadthFirst {
// 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.
@ -100,13 +120,13 @@ struct BreadthFirst {
MOZ_ASSERT(!traversalBegun);
traversalBegun = true;
// While there are pending nodes, visit them, until we've found a path to the target.
// 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.
js::ScopedJSDeletePtr<EdgeRange> range(origin.edges(cx));
auto range = origin.edges(cx, wantNames);
if (!range)
return false;
@ -114,18 +134,15 @@ struct BreadthFirst {
for (; !range->empty(); range->popFront()) {
MOZ_ASSERT(!stopRequested);
const Edge &edge = range->front();
Edge& edge = range->front();
typename NodeMap::AddPtr a = visited.lookupForAdd(edge.referent);
bool first = !a;
if (first) {
// This is the first time we've reached |edge.referent|.
// Create an entry for it in |visited|, and arrange to
// traverse its outgoing edges later.
if (!visited.add(a, edge.referent, typename Handler::NodeData()) ||
!pending.append(edge.referent)) {
// Mark it as visited.
if (!visited.add(a, edge.referent, typename Handler::NodeData()))
return false;
}
}
MOZ_ASSERT(a);
@ -136,6 +153,16 @@ struct BreadthFirst {
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;
}
}
}
@ -149,30 +176,36 @@ struct BreadthFirst {
// 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;
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.
typedef js::HashMap<Node, typename Handler::NodeData> NodeMap;
using NodeMap = js::HashMap<Node, typename Handler::NodeData, js::DefaultHasher<Node>,
js::SystemAllocPolicy>;
NodeMap visited;
private:
// Our handler object.
Handler &handler;
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 <typename T>
class Queue {
js::Vector<T, 0> head, tail;
js::Vector<T, 0, js::SystemAllocPolicy> head, tail;
size_t frontIndex;
public:
Queue(JSContext *cx) : head(cx), tail(cx), frontIndex(0) { }
Queue() : head(), tail(), frontIndex(0) { }
bool empty() { return frontIndex >= head.length(); }
T &front() {
T& front() {
MOZ_ASSERT(!empty());
return head[frontIndex];
}
@ -185,7 +218,7 @@ struct BreadthFirst {
frontIndex = 0;
}
}
bool append(const T &elt) {
bool append(const T& elt) {
return frontIndex == 0 ? head.append(elt) : tail.append(elt);
}
};
@ -200,9 +233,12 @@ struct BreadthFirst {
// 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;
};
} // namespace ubi
} // namespace JS
#endif // js_UbiNodeTraverse.h
#endif // js_UbiNodeBreadthFirst_h

View File

@ -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/. */
#ifndef js_UbiNodeCensus_h
#define js_UbiNodeCensus_h
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
#include <algorithm>
#include "jsapi.h"
#include "js/UbiNode.h"
#include "js/UbiNodeBreadthFirst.h"
// A census is a ubi::Node traversal that assigns each node to one or more
// buckets, and returns a report with the size of each bucket.
//
// We summarize the results of a census with counts broken down according to
// criteria selected by the API consumer code that is requesting the census. For
// example, the following breakdown might give an interesting overview of the
// heap:
//
// - all nodes
// - objects
// - objects with a specific [[Class]] *
// - strings
// - scripts
// - all other Node types
// - nodes with a specific ubi::Node::typeName *
//
// Obviously, the parts of this tree marked with * represent many separate
// counts, depending on how many distinct [[Class]] values and ubi::Node type
// names we encounter.
//
// The supported types of breakdowns are documented in
// js/src/doc/Debugger/Debugger.Memory.md.
//
// When we parse the 'breakdown' argument to takeCensus, we build a tree of
// CountType nodes. For example, for the breakdown shown in the
// Debugger.Memory.prototype.takeCensus, documentation:
//
// {
// by: "coarseType",
// objects: { by: "objectClass" },
// other: { by: "internalType" }
// }
//
// we would build the following tree of CountType subclasses:
//
// ByCoarseType
// objects: ByObjectClass
// each class: SimpleCount
// scripts: SimpleCount
// strings: SimpleCount
// other: ByUbinodeType
// each type: SimpleCount
//
// The interior nodes are all breakdown types that categorize nodes according to
// one characteristic or another; and the leaf nodes are all SimpleType.
//
// Each CountType has its own concrete C++ type that holds the counts it
// produces. SimpleCount::Count just holds totals. ByObjectClass::Count has a
// hash table whose keys are object class names and whose values are counts of
// some other type (in the example above, SimpleCount).
//
// To keep actual count nodes small, they have no vtable. Instead, each count
// points to its CountType, which knows how to carry out all the operations we
// need on a Count. A CountType can produce new count nodes; process nodes as we
// visit them; build a JS object reporting the results; and destruct count
// nodes.
namespace JS {
namespace ubi {
struct Census;
class CountBase;
struct CountDeleter {
void operator()(CountBase*);
};
using CountBasePtr = js::UniquePtr<CountBase, CountDeleter>;
// Abstract base class for CountType nodes.
struct CountType {
explicit CountType() { }
virtual ~CountType() { }
// 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;
};
using CountTypePtr = js::UniquePtr<CountType>;
// 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;
}
#ifdef DEBUG
size_t oldTotal = total_;
#endif
bool ret = type.count(*this, mallocSizeOf, node);
MOZ_ASSERT(total_ == oldTotal,
"CountType::count should not increment total_, CountBase::count handles that");
return ret;
}
// Construct a JavaScript object reporting the counts recorded in this
// count, and store it in |report|. Return true on success, or false on
// failure.
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;
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; }
};
// 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;
explicit Census(JSContext* cx) : cx(cx), atomsZone(nullptr) { }
MOZ_MUST_USE 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 bool operator() (BreadthFirst<CensusHandler>& traversal,
Node origin, const Edge& edge,
NodeData* referentData, bool first);
};
using CensusTraversal = BreadthFirst<CensusHandler>;
// Examine the census options supplied by the API consumer, and (among other
// things) use that to build a CountType tree.
MOZ_MUST_USE 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.
CountTypePtr ParseBreakdown(JSContext* cx, HandleValue breakdownValue);
} // namespace ubi
} // namespace JS
#endif // js_UbiNodeCensus_h

View File

@ -0,0 +1,677 @@
/* -*- 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_UbiNodeDominatorTree_h
#define js_UbiNodeDominatorTree_h
#include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Maybe.h"
#include "mozilla/Move.h"
#include "mozilla/UniquePtr.h"
#include "jsalloc.h"
#include "js/UbiNode.h"
#include "js/UbiNodePostOrder.h"
#include "js/Utility.h"
#include "js/Vector.h"
namespace JS {
namespace ubi {
/**
* In a directed graph with a root node `R`, a node `A` is said to "dominate" a
* node `B` iff every path from `R` to `B` contains `A`. A node `A` is said to
* be the "immediate dominator" of a node `B` iff it dominates `B`, is not `B`
* itself, and does not dominate any other nodes which also dominate `B` in
* turn.
*
* If we take every node from a graph `G` and create a new graph `T` with edges
* to each node from its immediate dominator, then `T` is a tree (each node has
* only one immediate dominator, or none if it is the root). This tree is called
* a "dominator tree".
*
* This class represents a dominator tree constructed from a `JS::ubi::Node`
* heap graph. The domination relationship and dominator trees are useful tools
* for analyzing heap graphs because they tell you:
*
* - Exactly what could be reclaimed by the GC if some node `A` became
* unreachable: those nodes which are dominated by `A`,
*
* - The "retained size" of a node in the heap graph, in contrast to its
* "shallow size". The "shallow size" is the space taken by a node itself,
* not counting anything it references. The "retained size" of a node is its
* shallow size plus the size of all the things that would be collected if
* the original node wasn't (directly or indirectly) referencing them. In
* other words, the retained size is the shallow size of a node plus the
* shallow sizes of every other node it dominates. For example, the root
* node in a binary tree might have a small shallow size that does not take
* up much space itself, but it dominates the rest of the binary tree and
* its retained size is therefore significant (assuming no external
* references into the tree).
*
* The simple, engineered algorithm presented in "A Simple, Fast Dominance
* Algorithm" by Cooper el al[0] is used to find dominators and construct the
* dominator tree. This algorithm runs in O(n^2) time, but is faster in practice
* than alternative algorithms with better theoretical running times, such as
* Lengauer-Tarjan which runs in O(e * log(n)). The big caveat to that statement
* is that Cooper et al found it is faster in practice *on control flow graphs*
* and I'm not convinced that this property also holds on *heap* graphs. That
* said, the implementation of this algorithm is *much* simpler than
* Lengauer-Tarjan and has been found to be fast enough at least for the time
* being.
*
* [0]: http://www.cs.rice.edu/~keith/EMBED/dom.pdf
*/
class JS_PUBLIC_API(DominatorTree)
{
private:
// Types.
using PredecessorSets = js::HashMap<Node, NodeSetPtr, js::DefaultHasher<Node>,
js::SystemAllocPolicy>;
using NodeToIndexMap = js::HashMap<Node, uint32_t, js::DefaultHasher<Node>,
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<Node>& postOrder;
const uint32_t* ptr;
DominatedNodePtr(const JS::ubi::Vector<Node>& 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<Node>& postOrder;
const uint32_t* beginPtr;
const uint32_t* endPtr;
DominatedSetRange(JS::ubi::Vector<Node>& 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<DominatedSetRange> 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;
}
};
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<uint32_t> dominated;
JS::ubi::Vector<uint32_t> indices;
DominatedSets(JS::ubi::Vector<uint32_t>&& dominated, JS::ubi::Vector<uint32_t>&& 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<DominatedSets> Create(const JS::ubi::Vector<uint32_t>& 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<uint32_t> dominated;
JS::ubi::Vector<uint32_t> 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];
}
#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<Node>& 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<Node> postOrder;
NodeToIndexMap nodeToPostOrderIndex;
JS::ubi::Vector<uint32_t> doms;
DominatedSets dominatedSets;
mozilla::Maybe<JS::ubi::Vector<JS::ubi::Node::Size>> 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<Node>&& postOrder, NodeToIndexMap&& nodeToPostOrderIndex,
JS::ubi::Vector<uint32_t>&& 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<uint32_t>& 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<Node>& 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<NodeSet, DeletePolicy<NodeSet>> set(js_new<NodeSet>());
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<Node>& 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<index>
// form.
static MOZ_MUST_USE bool convertPredecessorSetsToVectors(
const Node& root,
JS::ubi::Vector<Node>& postOrder,
PredecessorSets& predecessorSets,
NodeToIndexMap& nodeToPostOrderIndex,
JS::ubi::Vector<JS::ubi::Vector<uint32_t>>& 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<uint32_t>& 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<DominatorTree>
Create(JSContext* cx, AutoCheckCannotGC& noGC, const Node& root) {
JS::ubi::Vector<Node> 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<JS::ubi::Vector<uint32_t>> predecessorVectors;
if (!convertPredecessorSetsToVectors(root, postOrder, predecessorSets, nodeToPostOrderIndex,
predecessorVectors))
return mozilla::Nothing();
JS::ubi::Vector<uint32_t> 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)));
}
/**
* 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<DominatedSetRange> 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<DominatedSetRange> 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
#endif // js_UbiNodeDominatorTree_h

View File

@ -0,0 +1,191 @@
/* -*- 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_UbiNodePostOrder_h
#define js_UbiNodePostOrder_h
#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"
#include "mozilla/Move.h"
#include "jsalloc.h"
#include "js/UbiNode.h"
#include "js/Utility.h"
#include "js/Vector.h"
namespace JS {
namespace ubi {
/**
* A post-order depth-first traversal of `ubi::Node` graphs.
*
* No GC may occur while an instance of `PostOrder` is live.
*
* The `NodeVisitor` type provided to `PostOrder::traverse` must have the
* following member:
*
* bool operator()(Node& node)
*
* The node visitor method. This method is called once for each `node`
* reachable from the start set in post-order.
*
* This visitor function should return true on success, or false if an error
* occurs. A false return value terminates the traversal immediately, and
* causes `PostOrder::traverse` to return false.
*
* The `EdgeVisitor` type provided to `PostOrder::traverse` must have the
* following member:
*
* bool operator()(Node& origin, Edge& edge)
*
* The edge visitor method. This method is called once for each outgoing
* `edge` from `origin` that is reachable from the start set.
*
* NB: UNLIKE NODES, THERE IS NO GUARANTEED ORDER IN WHICH EDGES AND THEIR
* ORIGINS ARE VISITED!
*
* This visitor function should return true on success, or false if an error
* occurs. A false return value terminates the traversal immediately, and
* 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<OriginAndEdges, 256, js::SystemAllocPolicy>;
using Set = js::HashSet<Node, js::DefaultHasher<Node>, js::SystemAllocPolicy>;
JSContext* cx;
Set seen;
Stack stack;
#ifdef DEBUG
bool traversed;
#endif
private:
MOZ_MUST_USE bool fillEdgesFromRange(EdgeVector& edges, js::UniquePtr<EdgeRange>& range) {
MOZ_ASSERT(range);
for ( ; !range->empty(); range->popFront()) {
if (!edges.append(mozilla::Move(range->front())))
return false;
}
return true;
}
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
, traversed(false)
#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);
}
// 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<typename NodeVisitor, typename EdgeVisitor>
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
#endif // js_UbiNodePostOrder_h

View File

@ -0,0 +1,350 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef js_UbiNodeShortestPaths_h
#define js_UbiNodeShortestPaths_h
#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"
#include "mozilla/Move.h"
#include "jsalloc.h"
#include "js/UbiNodeBreadthFirst.h"
#include "js/Vector.h"
namespace JS {
namespace ubi {
/**
* A back edge along a path in the heap graph.
*/
struct JS_PUBLIC_API(BackEdge)
{
private:
Node predecessor_;
EdgeName name_;
public:
using Ptr = mozilla::UniquePtr<BackEdge, JS::DeletePolicy<BackEdge>>;
BackEdge() : predecessor_(), name_(nullptr) { }
MOZ_MUST_USE bool init(const Node& predecessor, Edge& edge) {
MOZ_ASSERT(!predecessor_);
MOZ_ASSERT(!name_);
predecessor_ = predecessor;
name_ = mozilla::Move(edge.name);
return true;
}
BackEdge(const BackEdge&) = delete;
BackEdge& operator=(const BackEdge&) = delete;
BackEdge(BackEdge&& rhs)
: predecessor_(rhs.predecessor_)
, name_(mozilla::Move(rhs.name_))
{
MOZ_ASSERT(&rhs != this);
}
BackEdge& operator=(BackEdge&& rhs) {
this->~BackEdge();
new(this) BackEdge(Move(rhs));
return *this;
}
Ptr clone() const;
const EdgeName& name() const { return name_; }
EdgeName& name() { return name_; }
const JS::ubi::Node& predecessor() const { return predecessor_; }
};
/**
* A path is a series of back edges from which we discovered a target node.
*/
using Path = JS::ubi::Vector<BackEdge*>;
/**
* The `JS::ubi::ShortestPaths` type represents a collection of up to N shortest
* retaining paths for each of a target set of nodes, starting from the same
* root node.
*/
struct JS_PUBLIC_API(ShortestPaths)
{
private:
// Types, type aliases, and data members.
using BackEdgeVector = JS::ubi::Vector<BackEdge::Ptr>;
using NodeToBackEdgeVectorMap = js::HashMap<Node, BackEdgeVector, js::DefaultHasher<Node>,
js::SystemAllocPolicy>;
struct Handler;
using Traversal = BreadthFirst<Handler>;
/**
* 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<BackEdge>());
if (!thisBackEdge || !thisBackEdge->init(origin, edge))
return false;
ptr->value().infallibleAppend(mozilla::Move(thisBackEdge));
totalPathsRecorded++;
}
}
MOZ_ASSERT(totalPathsRecorded <= totalMaxPathsToRecord);
if (totalPathsRecorded == totalMaxPathsToRecord)
traversal.stop();
return true;
}
};
// The maximum number of paths to record for each node.
uint32_t maxNumPaths_;
// The root node we are starting the search from.
Node root_;
// The set of nodes we are searching for paths to.
NodeSet targets_;
// The resulting paths.
NodeToBackEdgeVectorMap paths_;
// Need to keep alive the traversal's back edges so we can walk them later
// when the traversal is over when recreating the shortest paths.
Traversal::NodeMap backEdges_;
private:
// Private methods.
ShortestPaths(uint32_t maxNumPaths, const Node& root, NodeSet&& targets)
: maxNumPaths_(maxNumPaths)
, root_(root)
, targets_(mozilla::Move(targets))
, paths_()
, backEdges_()
{
MOZ_ASSERT(maxNumPaths_ > 0);
MOZ_ASSERT(root_);
MOZ_ASSERT(targets_.initialized());
}
bool initialized() const {
return targets_.initialized() &&
paths_.initialized() &&
backEdges_.initialized();
}
public:
// Public methods.
ShortestPaths(ShortestPaths&& rhs)
: maxNumPaths_(rhs.maxNumPaths_)
, root_(rhs.root_)
, targets_(mozilla::Move(rhs.targets_))
, paths_(mozilla::Move(rhs.paths_))
, backEdges_(mozilla::Move(rhs.backEdges_))
{
MOZ_ASSERT(this != &rhs, "self-move is not allowed");
}
ShortestPaths& operator=(ShortestPaths&& rhs) {
this->~ShortestPaths();
new (this) ShortestPaths(mozilla::Move(rhs));
return *this;
}
ShortestPaths(const ShortestPaths&) = delete;
ShortestPaths& operator=(const ShortestPaths&) = delete;
/**
* Construct a new `JS::ubi::ShortestPaths`, finding up to `maxNumPaths`
* shortest retaining paths for each target node in `targets` starting from
* `root`.
*
* The resulting `ShortestPaths` instance must not outlive the
* `JS::ubi::Node` graph it was constructed from.
*
* - For `JS::ubi::Node` graphs backed by the live heap graph, this means
* that the `ShortestPaths`'s lifetime _must_ be contained within the
* scope of the provided `AutoCheckCannotGC` reference because a GC will
* invalidate the nodes.
*
* - For `JS::ubi::Node` graphs backed by some other offline structure
* provided by the embedder, the resulting `ShortestPaths`'s lifetime is
* bounded by that offline structure's lifetime.
*
* Returns `mozilla::Nothing()` on OOM failure. It is the caller's
* responsibility to handle and report the OOM.
*/
static mozilla::Maybe<ShortestPaths>
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 <class Func>
MOZ_MUST_USE bool forEachPath(const Node& target, Func func) {
MOZ_ASSERT(initialized());
MOZ_ASSERT(targets_.has(target));
auto ptr = paths_.lookup(target);
// We didn't find any paths to this target, so nothing to do here.
if (!ptr)
return true;
MOZ_ASSERT(ptr->value().length() <= maxNumPaths_);
Path path;
for (const auto& backEdge : ptr->value()) {
path.clear();
if (!path.append(backEdge.get()))
return false;
Node here = backEdge->predecessor();
MOZ_ASSERT(here);
while (here != root_) {
auto p = backEdges_.lookup(here);
MOZ_ASSERT(p);
if (!path.append(&p->value()))
return false;
here = p->value().predecessor();
MOZ_ASSERT(here);
}
path.reverse();
if (!func(path))
return false;
}
return true;
}
};
#ifdef DEBUG
// A helper function to dump the first `maxNumPaths` shortest retaining paths to
// `node` from the GC roots. Useful when GC things you expect to have been
// reclaimed by the collector haven't been!
//
// Usage:
//
// JSObject* foo = ...;
// JS::ubi::dumpPaths(rt, JS::ubi::Node(foo));
JS_PUBLIC_API(void)
dumpPaths(JSRuntime* rt, Node node, uint32_t maxNumPaths = 10);
#endif
} // namespace ubi
} // namespace JS
#endif // js_UbiNodeShortestPaths_h

View File

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef js_UniquePtr_h
#define js_UniquePtr_h
#include "mozilla/UniquePtr.h"
#include "js/Utility.h"
namespace js {
// Replacement for mozilla::UniquePtr that defaults to js::DefaultDelete.
template <typename T, typename D = JS::DeletePolicy<T>>
using UniquePtr = mozilla::UniquePtr<T, D>;
namespace detail {
template<typename T>
struct UniqueSelector
{
typedef UniquePtr<T> SingleObject;
};
template<typename T>
struct UniqueSelector<T[]>
{
typedef UniquePtr<T[]> UnknownBound;
};
template<typename T, decltype(sizeof(int)) N>
struct UniqueSelector<T[N]>
{
typedef UniquePtr<T[N]> KnownBound;
};
} // namespace detail
// Replacement for mozilla::MakeUnique that correctly calls js_new and produces
// a js::UniquePtr.
template<typename T, typename... Args>
typename detail::UniqueSelector<T>::SingleObject
MakeUnique(Args&&... aArgs)
{
return UniquePtr<T>(js_new<T>(mozilla::Forward<Args>(aArgs)...));
}
template<typename T>
typename detail::UniqueSelector<T>::UnknownBound
MakeUnique(decltype(sizeof(int)) aN) = delete;
template<typename T, typename... Args>
typename detail::UniqueSelector<T>::KnownBound
MakeUnique(Args&&... aArgs) = delete;
} // namespace js
#endif /* js_UniquePtr_h */

705
android/arm64-v8a/include/spidermonkey/js/Utility.h Executable file → Normal file
View File

@ -8,12 +8,13 @@
#define js_Utility_h
#include "mozilla/Assertions.h"
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/Compiler.h"
#include "mozilla/Move.h"
#include "mozilla/NullPtr.h"
#include "mozilla/Scoped.h"
#include "mozilla/TemplateLib.h"
#include "mozilla/UniquePtr.h"
#include <stdlib.h>
#include <string.h>
@ -34,29 +35,11 @@ namespace mozilla {}
/* The private JS engine namespace. */
namespace js {}
/*
* Patterns used by SpiderMonkey to overwrite unused memory. If you are
* accessing an object with one of these pattern, you probably have a dangling
* pointer.
*/
#define JS_FRESH_NURSERY_PATTERN 0x2F
#define JS_SWEPT_NURSERY_PATTERN 0x2B
#define JS_ALLOCATED_NURSERY_PATTERN 0x2D
#define JS_FRESH_TENURED_PATTERN 0x4F
#define JS_SWEPT_TENURED_PATTERN 0x4B
#define JS_ALLOCATED_TENURED_PATTERN 0x4D
#define JS_SWEPT_CODE_PATTERN 0x3b
#define JS_SWEPT_FRAME_PATTERN 0x5b
#define JS_POISONED_FORKJOIN_CHUNK 0xBD
#define JS_ASSERT(expr) MOZ_ASSERT(expr)
#define JS_ASSERT_IF(cond, expr) MOZ_ASSERT_IF(cond, expr)
#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 JS_PUBLIC_API(void)
JS_Assert(const char *s, const char *file, int ln);
extern MOZ_NORETURN MOZ_COLD JS_PUBLIC_API(void)
JS_Assert(const char* s, const char* file, int ln);
/*
* Custom allocator support for SpiderMonkey
@ -64,14 +47,47 @@ JS_Assert(const char *s, const char *file, int ln);
#if defined JS_USE_CUSTOM_ALLOCATOR
# include "jscustomallocator.h"
#else
# if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
namespace js {
namespace oom {
/*
* In order to test OOM conditions, when the testing function
* oomAfterAllocations COUNT is passed, we fail continuously after the NUM'th
* allocation from now.
* 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.
*/
extern JS_PUBLIC_DATA(uint32_t) OOM_maxAllocations; /* set in builtin/TestingFunctions.cpp */
extern JS_PUBLIC_DATA(uint32_t) OOM_counter; /* data race, who cares. */
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
};
/*
* Getter/Setter functions to encapsulate mozilla::ThreadLocal,
* implementation is in jsutil.cpp.
*/
# if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
extern bool InitThreadType(void);
extern void SetThreadType(ThreadType);
extern uint32_t GetThreadType(void);
# else
inline bool InitThreadType(void) { return true; }
inline void SetThreadType(ThreadType t) {};
inline uint32_t GetThreadType(void) { return 0; }
# endif
} /* namespace oom */
} /* namespace js */
# if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
#ifdef JS_OOM_BREAKPOINT
static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); }
@ -80,19 +96,133 @@ static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); }
#define JS_OOM_CALL_BP_FUNC() do {} while(0)
#endif
# define JS_OOM_POSSIBLY_FAIL() \
do \
{ \
if (++OOM_counter > OOM_maxAllocations) { \
JS_OOM_CALL_BP_FUNC();\
return nullptr; \
} \
namespace js {
namespace oom {
/*
* Out of memory testing support. We provide various testing functions to
* simulate OOM conditions and so we can test that they are handled correctly.
*/
extern JS_PUBLIC_DATA(uint32_t) targetThread;
extern JS_PUBLIC_DATA(uint64_t) maxAllocations;
extern JS_PUBLIC_DATA(uint64_t) counter;
extern JS_PUBLIC_DATA(bool) failAlways;
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;
}
} /* 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)
# else
# define JS_OOM_POSSIBLY_FAIL() do {} while(0)
# define JS_OOM_POSSIBLY_FAIL_BOOL() do {} while(0)
namespace js {
namespace oom {
static inline bool IsSimulatedOOMAllocation() { return false; }
static inline bool ShouldFailWithOOM() { return false; }
} /* namespace oom */
} /* namespace js */
# endif /* DEBUG || JS_OOM_BREAKPOINT */
namespace js {
/* Disable OOM testing in sections which are not OOM safe. */
struct MOZ_RAII 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() {
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<AutoEnterOOMUnsafeRegion*> owner_;
bool oomEnabled_;
int64_t oomAfter_;
#endif
};
} /* namespace js */
static inline void* js_malloc(size_t bytes)
{
JS_OOM_POSSIBLY_FAIL();
@ -113,6 +243,11 @@ static inline void* js_calloc(size_t nmemb, size_t 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);
JS_OOM_POSSIBLY_FAIL();
return realloc(p, bytes);
}
@ -121,6 +256,12 @@ static inline void js_free(void* p)
{
free(p);
}
static inline char* js_strdup(const char* s)
{
JS_OOM_POSSIBLY_FAIL();
return strdup(s);
}
#endif/* JS_USE_CUSTOM_ALLOCATOR */
#include <new>
@ -152,7 +293,7 @@ static inline void js_free(void* p)
* general SpiderMonkey idiom that a JSContext-taking function reports its
* own errors.)
*
* - Otherwise, use js_malloc/js_realloc/js_calloc/js_free/js_new
* - Otherwise, use js_malloc/js_realloc/js_calloc/js_new
*
* Deallocation:
*
@ -167,400 +308,137 @@ static inline void js_free(void* p)
* on another thread.
*/
#define JS_NEW_BODY(allocator, t, parms) \
void *memory = allocator(sizeof(t)); \
return memory ? new(memory) t parms : nullptr;
#define JS_MAKE_BODY(newname, T, parms) \
T *ptr = newname<T> parms; \
return mozilla::UniquePtr<T, JS::DeletePolicy<T>>(ptr);
/*
* Given a class which should provide 'new' methods, add
* JS_DECLARE_NEW_METHODS (see JSContext for a usage example). This
* adds news with up to 12 parameters. Add more versions of new below if
* you need more than 12 parameters.
* Given a class which should provide a 'new' method, add
* JS_DECLARE_NEW_METHODS (see js::MallocProvider for an example).
*
* 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 <class T>\
QUALIFIERS T *NEWNAME() MOZ_HEAP_ALLOCATOR {\
JS_NEW_BODY(ALLOCATOR, T, ())\
}\
\
template <class T, class P1>\
QUALIFIERS T *NEWNAME(P1 &&p1) MOZ_HEAP_ALLOCATOR {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1)))\
}\
\
template <class T, class P1, class P2>\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2) MOZ_HEAP_ALLOCATOR {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2)))\
}\
\
template <class T, class P1, class P2, class P3>\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3) MOZ_HEAP_ALLOCATOR {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3)))\
}\
\
template <class T, class P1, class P2, class P3, class P4>\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4) MOZ_HEAP_ALLOCATOR {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5>\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5) MOZ_HEAP_ALLOCATOR {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6>\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6) MOZ_HEAP_ALLOCATOR {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7>\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7) MOZ_HEAP_ALLOCATOR {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8) MOZ_HEAP_ALLOCATOR {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7),\
mozilla::Forward<P8>(p8)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9) MOZ_HEAP_ALLOCATOR {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7),\
mozilla::Forward<P8>(p8),\
mozilla::Forward<P9>(p9)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10>\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10) MOZ_HEAP_ALLOCATOR {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7),\
mozilla::Forward<P8>(p8),\
mozilla::Forward<P9>(p9),\
mozilla::Forward<P10>(p10)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11>\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11) MOZ_HEAP_ALLOCATOR {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7),\
mozilla::Forward<P8>(p8),\
mozilla::Forward<P9>(p9),\
mozilla::Forward<P10>(p10),\
mozilla::Forward<P11>(p11)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11, class P12>\
QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11, P12 &&p12) MOZ_HEAP_ALLOCATOR {\
JS_NEW_BODY(ALLOCATOR, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7),\
mozilla::Forward<P8>(p8),\
mozilla::Forward<P9>(p9),\
mozilla::Forward<P10>(p10),\
mozilla::Forward<P11>(p11),\
mozilla::Forward<P12>(p12)))\
}\
#define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \
template <class T, typename... Args> \
QUALIFIERS T * \
NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \
void* memory = ALLOCATOR(sizeof(T)); \
return MOZ_LIKELY(memory) \
? new(memory) T(mozilla::Forward<Args>(args)...) \
: nullptr; \
}
/*
* Given a class which should provide 'make' methods, add
* JS_DECLARE_MAKE_METHODS (see JSContext for a usage example). This method
* is functionally the same as JS_DECLARE_NEW_METHODS: it just declares methods
* that return mozilla::UniquePtr instances that will singly-manage ownership
* of the created object. This adds makes with up to 12 parameters. Add more
* versions below if you need more than 12 parameters.
* JS_DECLARE_MAKE_METHODS (see js::MallocProvider for an example). This
* method is functionally the same as JS_DECLARE_NEW_METHODS: it just declares
* methods that return mozilla::UniquePtr instances that will singly-manage
* ownership of the created object.
*
* 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 <class T> \
QUALIFIERS \
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
MAKENAME() MOZ_HEAP_ALLOCATOR {\
JS_MAKE_BODY(NEWNAME, T, ())\
}\
\
template <class T, class P1> \
QUALIFIERS \
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
MAKENAME(P1 &&p1) MOZ_HEAP_ALLOCATOR {\
JS_MAKE_BODY(NEWNAME, T,\
(mozilla::Forward<P1>(p1)))\
}\
\
template <class T, class P1, class P2> \
QUALIFIERS \
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
MAKENAME(P1 &&p1, P2 &&p2) MOZ_HEAP_ALLOCATOR {\
JS_MAKE_BODY(NEWNAME, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2)))\
}\
\
template <class T, class P1, class P2, class P3> \
QUALIFIERS \
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3) MOZ_HEAP_ALLOCATOR {\
JS_MAKE_BODY(NEWNAME, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3)))\
}\
\
template <class T, class P1, class P2, class P3, class P4> \
QUALIFIERS \
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4) MOZ_HEAP_ALLOCATOR {\
JS_MAKE_BODY(NEWNAME, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5> \
QUALIFIERS \
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5) MOZ_HEAP_ALLOCATOR {\
JS_MAKE_BODY(NEWNAME, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6> \
QUALIFIERS \
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6) MOZ_HEAP_ALLOCATOR {\
JS_MAKE_BODY(NEWNAME, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7> \
QUALIFIERS \
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7) MOZ_HEAP_ALLOCATOR {\
JS_MAKE_BODY(NEWNAME, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8> \
QUALIFIERS \
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8) MOZ_HEAP_ALLOCATOR {\
JS_MAKE_BODY(NEWNAME, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7),\
mozilla::Forward<P8>(p8)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9> \
QUALIFIERS \
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9) MOZ_HEAP_ALLOCATOR {\
JS_MAKE_BODY(NEWNAME, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7),\
mozilla::Forward<P8>(p8),\
mozilla::Forward<P9>(p9)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10> \
QUALIFIERS \
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10) MOZ_HEAP_ALLOCATOR {\
JS_MAKE_BODY(NEWNAME, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7),\
mozilla::Forward<P8>(p8),\
mozilla::Forward<P9>(p9),\
mozilla::Forward<P10>(p10)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11> \
QUALIFIERS \
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11) MOZ_HEAP_ALLOCATOR {\
JS_MAKE_BODY(NEWNAME, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7),\
mozilla::Forward<P8>(p8),\
mozilla::Forward<P9>(p9),\
mozilla::Forward<P10>(p10),\
mozilla::Forward<P11>(p11)))\
}\
\
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11, class P12> \
QUALIFIERS \
mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
MAKENAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11, P12 &&p12) MOZ_HEAP_ALLOCATOR {\
JS_MAKE_BODY(NEWNAME, T,\
(mozilla::Forward<P1>(p1),\
mozilla::Forward<P2>(p2),\
mozilla::Forward<P3>(p3),\
mozilla::Forward<P4>(p4),\
mozilla::Forward<P5>(p5),\
mozilla::Forward<P6>(p6),\
mozilla::Forward<P7>(p7),\
mozilla::Forward<P8>(p8),\
mozilla::Forward<P9>(p9),\
mozilla::Forward<P10>(p10),\
mozilla::Forward<P11>(p11),\
mozilla::Forward<P12>(p12)))\
}\
template <class T, typename... Args> \
QUALIFIERS mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
MAKENAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \
T* ptr = NEWNAME<T>(mozilla::Forward<Args>(args)...); \
return mozilla::UniquePtr<T, JS::DeletePolicy<T>>(ptr); \
}
JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE)
namespace js {
/*
* Calculate the number of bytes needed to allocate |numElems| contiguous
* instances of type |T|. Return false if the calculation overflowed.
*/
template <typename T>
MOZ_MUST_USE inline bool
CalculateAllocSize(size_t numElems, size_t* bytesOut)
{
*bytesOut = numElems * sizeof(T);
return (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) == 0;
}
/*
* Calculate the number of bytes needed to allocate a single instance of type
* |T| followed by |numExtra| contiguous instances of type |Extra|. Return
* false if the calculation overflowed.
*/
template <typename T, typename Extra>
MOZ_MUST_USE inline bool
CalculateAllocSizeWithExtra(size_t numExtra, size_t* bytesOut)
{
*bytesOut = sizeof(T) + numExtra * sizeof(Extra);
return (numExtra & mozilla::tl::MulOverflowMask<sizeof(Extra)>::value) == 0 &&
*bytesOut >= sizeof(T);
}
} /* namespace js */
template <class T>
static MOZ_ALWAYS_INLINE void
js_delete(T *p)
js_delete(const T* p)
{
if (p) {
p->~T();
js_free(p);
js_free(const_cast<T*>(p));
}
}
template<class T>
static MOZ_ALWAYS_INLINE void
js_delete_poison(T *p)
js_delete_poison(const T* p)
{
if (p) {
p->~T();
memset(p, 0x3B, sizeof(T));
js_free(p);
memset(const_cast<T*>(p), 0x3B, sizeof(T));
js_free(const_cast<T*>(p));
}
}
template <class T>
static MOZ_ALWAYS_INLINE T *
static MOZ_ALWAYS_INLINE T*
js_pod_malloc()
{
return (T *)js_malloc(sizeof(T));
return static_cast<T*>(js_malloc(sizeof(T)));
}
template <class T>
static MOZ_ALWAYS_INLINE T *
static MOZ_ALWAYS_INLINE T*
js_pod_calloc()
{
return (T *)js_calloc(sizeof(T));
return static_cast<T*>(js_calloc(sizeof(T)));
}
template <class T>
static MOZ_ALWAYS_INLINE T *
static MOZ_ALWAYS_INLINE T*
js_pod_malloc(size_t numElems)
{
if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
size_t bytes;
if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes)))
return nullptr;
return (T *)js_malloc(numElems * sizeof(T));
return static_cast<T*>(js_malloc(bytes));
}
template <class T>
static MOZ_ALWAYS_INLINE T *
static MOZ_ALWAYS_INLINE T*
js_pod_calloc(size_t numElems)
{
if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
size_t bytes;
if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes)))
return nullptr;
return (T *)js_calloc(numElems * sizeof(T));
return static_cast<T*>(js_calloc(bytes));
}
template <class T>
static MOZ_ALWAYS_INLINE T*
js_pod_realloc(T* prior, size_t oldSize, size_t newSize)
{
MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
size_t bytes;
if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes)))
return nullptr;
return static_cast<T*>(js_realloc(prior, bytes));
}
namespace js {
@ -577,14 +455,14 @@ SCOPED_TEMPLATE(ScopedJSFreePtr, ScopedFreePtrTraits)
template <typename T>
struct ScopedDeletePtrTraits : public ScopedFreePtrTraits<T>
{
static void release(T *ptr) { js_delete(ptr); }
static void release(T* ptr) { js_delete(ptr); }
};
SCOPED_TEMPLATE(ScopedJSDeletePtr, ScopedDeletePtrTraits)
template <typename T>
struct ScopedReleasePtrTraits : public ScopedFreePtrTraits<T>
{
static void release(T *ptr) { if (ptr) ptr->release(); }
static void release(T* ptr) { if (ptr) ptr->release(); }
};
SCOPED_TEMPLATE(ScopedReleasePtr, ScopedReleasePtrTraits)
@ -595,18 +473,29 @@ namespace JS {
template<typename T>
struct DeletePolicy
{
void operator()(T* ptr) {
js_delete(ptr);
constexpr DeletePolicy() {}
template<typename U>
MOZ_IMPLICIT DeletePolicy(DeletePolicy<U> other,
typename mozilla::EnableIf<mozilla::IsConvertible<U*, T*>::value,
int>::Type dummy = 0)
{}
void operator()(const T* ptr) {
js_delete(const_cast<T*>(ptr));
}
};
struct FreePolicy
{
void operator()(void* ptr) {
js_free(ptr);
void operator()(const void* ptr) {
js_free(const_cast<void*>(ptr));
}
};
typedef mozilla::UniquePtr<char[], JS::FreePolicy> UniqueChars;
typedef mozilla::UniquePtr<char16_t[], JS::FreePolicy> UniqueTwoByteChars;
} // namespace JS
namespace js {
@ -644,7 +533,7 @@ ScrambleHashCode(HashNumber h)
*
* 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
@ -658,40 +547,6 @@ ScrambleHashCode(HashNumber h)
} /* namespace js */
namespace JS {
/*
* Methods for poisoning GC heap pointer words and checking for poisoned words.
* These are in this file for use in Value methods and so forth.
*
* If the moving GC hazard analysis is in use and detects a non-rooted stack
* pointer to a GC thing, one byte of that pointer is poisoned to refer to an
* invalid location. For both 32 bit and 64 bit systems, the fourth byte of the
* pointer is overwritten, to reduce the likelihood of accidentally changing
* a live integer value.
*/
inline void PoisonPtr(void *v)
{
#if defined(JSGC_ROOT_ANALYSIS) && defined(JS_DEBUG)
uint8_t *ptr = (uint8_t *) v + 3;
*ptr = JS_FREE_PATTERN;
#endif
}
template <typename T>
inline bool IsPoisonedPtr(T *v)
{
#if defined(JSGC_ROOT_ANALYSIS) && defined(JS_DEBUG)
uint32_t mask = uintptr_t(v) & 0xff000000;
return mask == uint32_t(JS_FREE_PATTERN << 24);
#else
return false;
#endif
}
}
/* sixgill annotation defines */
#ifndef HAVE_STATIC_ANNOTATIONS
# define HAVE_STATIC_ANNOTATIONS
@ -702,23 +557,11 @@ inline bool IsPoisonedPtr(T *v)
# 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_PASTE2(X,Y) X ## Y
# define STATIC_PASTE1(X,Y) STATIC_PASTE2(X,Y)
# define STATIC_ASSERT(COND) \
JS_BEGIN_MACRO \
__attribute__((assert_static(#COND), unused)) \
int STATIC_PASTE1(assert_static_, __COUNTER__); \
JS_END_MACRO
# define STATIC_ASSUME(COND) \
JS_BEGIN_MACRO \
__attribute__((assume_static(#COND), unused)) \
int STATIC_PASTE1(assume_static_, __COUNTER__); \
JS_END_MACRO
# define STATIC_ASSERT_RUNTIME(COND) \
JS_BEGIN_MACRO \
__attribute__((assert_static_runtime(#COND), unused)) \
int STATIC_PASTE1(assert_static_runtime_, __COUNTER__); \
JS_END_MACRO
# else /* XGILL_PLUGIN */
# define STATIC_PRECONDITION(COND) /* nothing */
# define STATIC_PRECONDITION_ASSUME(COND) /* nothing */
@ -726,9 +569,7 @@ inline bool IsPoisonedPtr(T *v)
# define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */
# define STATIC_INVARIANT(COND) /* nothing */
# define STATIC_INVARIANT_ASSUME(COND) /* nothing */
# define STATIC_ASSERT(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
# define STATIC_ASSUME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
# define STATIC_ASSERT_RUNTIME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
# endif /* XGILL_PLUGIN */
# define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference())
#endif /* HAVE_STATIC_ANNOTATIONS */

1878
android/arm64-v8a/include/spidermonkey/js/Value.h Executable file → Normal file

File diff suppressed because it is too large Load Diff

55
android/arm64-v8a/include/spidermonkey/js/Vector.h Executable file → Normal file
View File

@ -19,47 +19,26 @@ namespace js {
class TempAllocPolicy;
// If we had C++11 template aliases, we could just use this:
//
// template <typename T,
// size_t MinInlineCapacity = 0,
// class AllocPolicy = TempAllocPolicy>
// using Vector = mozilla::Vector<T, MinInlineCapacity, AllocPolicy>;
//
// ...and get rid of all the CRTP madness in mozilla::Vector(Base). But we
// can't because compiler support's not up to snuff. (Template aliases are in
// gcc 4.7 and clang 3.0 and are expected to be in MSVC 2013.) Instead, have a
// completely separate class inheriting from mozilla::Vector, and throw CRTP at
// the problem til things work.
//
// This workaround presents a couple issues. First, because js::Vector is a
// distinct type from mozilla::Vector, overload resolution, method calls, etc.
// are affected. *Hopefully* this won't be too bad in practice. (A bunch of
// places had to be fixed when mozilla::Vector was introduced, but it wasn't a
// crazy number.) Second, mozilla::Vector's interface has to be made subclass-
// ready via CRTP -- or rather, via mozilla::VectorBase, which basically no one
// should use. :-) Third, we have to redefine the constructors and the non-
// inherited operators. Blech. Happily there aren't too many of these, so it
// isn't the end of the world.
namespace detail {
template <typename T>
struct TypeIsGCThing : mozilla::FalseType
{};
// Uncomment this once we actually can assert it:
//template <>
//struct TypeIsGCThing<JS::Value> : mozilla::TrueType
//{};
} // namespace detail
template <typename T,
size_t MinInlineCapacity = 0,
class AllocPolicy = TempAllocPolicy>
class Vector
: public mozilla::VectorBase<T,
MinInlineCapacity,
AllocPolicy,
Vector<T, MinInlineCapacity, AllocPolicy> >
{
typedef typename mozilla::VectorBase<T, MinInlineCapacity, AllocPolicy, Vector> Base;
public:
explicit Vector(AllocPolicy alloc = AllocPolicy()) : Base(alloc) {}
Vector(Vector &&vec) : Base(mozilla::Move(vec)) {}
Vector &operator=(Vector &&vec) {
return Base::operator=(mozilla::Move(vec));
}
};
class AllocPolicy = TempAllocPolicy,
// Don't use this with JS::Value! Use JS::AutoValueVector instead.
typename = typename mozilla::EnableIf<!detail::TypeIsGCThing<T>::value>::Type
>
using Vector = mozilla::Vector<T, MinInlineCapacity, AllocPolicy>;
} // namespace js

20
android/arm64-v8a/include/spidermonkey/js/WeakMapPtr.h Executable file → Normal file
View File

@ -23,24 +23,22 @@ template <typename K, typename V>
class JS_PUBLIC_API(WeakMapPtr)
{
public:
WeakMapPtr() : ptr(nullptr) {};
bool init(JSContext *cx);
bool initialized() { return ptr != nullptr; };
WeakMapPtr() : ptr(nullptr) {}
bool init(JSContext* cx);
bool initialized() { return ptr != nullptr; }
void destroy();
virtual ~WeakMapPtr() { MOZ_ASSERT(!initialized()); }
void trace(JSTracer *tracer);
void trace(JSTracer* tracer);
V lookup(const K &key);
bool put(JSContext *cx, const K &key, const V &value);
static void keyMarkCallback(JSTracer *trc, K key, void *data);
V lookup(const K& key);
bool put(JSContext* cx, const K& key, const V& value);
private:
void *ptr;
void* ptr;
// WeakMapPtr is neither copyable nor assignable.
WeakMapPtr(const WeakMapPtr &wmp) MOZ_DELETE;
WeakMapPtr &operator=(const WeakMapPtr &wmp) MOZ_DELETE;
WeakMapPtr(const WeakMapPtr& wmp) = delete;
WeakMapPtr& operator=(const WeakMapPtr& wmp) = delete;
};
} /* namespace JS */

91
android/arm64-v8a/include/spidermonkey/jsalloc.h Executable file → Normal file
View File

@ -19,19 +19,38 @@
namespace js {
enum class AllocFunction {
Malloc,
Calloc,
Realloc
};
struct ContextFriendFields;
/* Policy for using system memory functions and doing no error reporting. */
class SystemAllocPolicy
{
public:
void *malloc_(size_t bytes) { return js_malloc(bytes); }
void *calloc_(size_t bytes) { return js_calloc(bytes); }
void *realloc_(void *p, size_t oldBytes, size_t bytes) { return js_realloc(p, bytes); }
void free_(void *p) { js_free(p); }
template <typename T> T* maybe_pod_malloc(size_t numElems) { return js_pod_malloc<T>(numElems); }
template <typename T> T* maybe_pod_calloc(size_t numElems) { return js_pod_calloc<T>(numElems); }
template <typename T> T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) {
return js_pod_realloc<T>(p, oldSize, newSize);
}
template <typename T> T* pod_malloc(size_t numElems) { return maybe_pod_malloc<T>(numElems); }
template <typename T> T* pod_calloc(size_t numElems) { return maybe_pod_calloc<T>(numElems); }
template <typename T> T* pod_realloc(T* p, size_t oldSize, size_t newSize) {
return maybe_pod_realloc<T>(p, oldSize, newSize);
}
void free_(void* p) { js_free(p); }
void reportAllocOverflow() const {}
bool checkSimulatedOOM() const {
return !js::oom::ShouldFailWithOOM();
}
};
class ExclusiveContext;
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
@ -43,44 +62,80 @@ class SystemAllocPolicy
*/
class TempAllocPolicy
{
ContextFriendFields *const cx_;
ContextFriendFields* const cx_;
/*
* Non-inline helper to call JSRuntime::onOutOfMemory with minimal
* code bloat.
*/
JS_FRIEND_API(void *) onOutOfMemory(void *p, size_t nbytes);
JS_FRIEND_API(void*) onOutOfMemory(AllocFunction allocFunc, size_t nbytes,
void* reallocPtr = nullptr);
template <typename T>
T* onOutOfMemoryTyped(AllocFunction allocFunc, size_t numElems, void* reallocPtr = nullptr) {
size_t bytes;
if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes)))
return nullptr;
return static_cast<T*>(onOutOfMemory(allocFunc, bytes, reallocPtr));
}
public:
MOZ_IMPLICIT TempAllocPolicy(JSContext *cx) : cx_((ContextFriendFields *) cx) {} // :(
MOZ_IMPLICIT TempAllocPolicy(ContextFriendFields *cx) : cx_(cx) {}
MOZ_IMPLICIT TempAllocPolicy(JSContext* cx) : cx_((ContextFriendFields*) cx) {} // :(
MOZ_IMPLICIT TempAllocPolicy(ContextFriendFields* cx) : cx_(cx) {}
void *malloc_(size_t bytes) {
void *p = js_malloc(bytes);
template <typename T>
T* maybe_pod_malloc(size_t numElems) {
return js_pod_malloc<T>(numElems);
}
template <typename T>
T* maybe_pod_calloc(size_t numElems) {
return js_pod_calloc<T>(numElems);
}
template <typename T>
T* maybe_pod_realloc(T* prior, size_t oldSize, size_t newSize) {
return js_pod_realloc<T>(prior, oldSize, newSize);
}
template <typename T>
T* pod_malloc(size_t numElems) {
T* p = maybe_pod_malloc<T>(numElems);
if (MOZ_UNLIKELY(!p))
p = onOutOfMemory(nullptr, bytes);
p = onOutOfMemoryTyped<T>(AllocFunction::Malloc, numElems);
return p;
}
void *calloc_(size_t bytes) {
void *p = js_calloc(bytes);
template <typename T>
T* pod_calloc(size_t numElems) {
T* p = maybe_pod_calloc<T>(numElems);
if (MOZ_UNLIKELY(!p))
p = onOutOfMemory(nullptr, bytes);
p = onOutOfMemoryTyped<T>(AllocFunction::Calloc, numElems);
return p;
}
void *realloc_(void *p, size_t oldBytes, size_t bytes) {
void *p2 = js_realloc(p, bytes);
template <typename T>
T* pod_realloc(T* prior, size_t oldSize, size_t newSize) {
T* p2 = maybe_pod_realloc<T>(prior, oldSize, newSize);
if (MOZ_UNLIKELY(!p2))
p2 = onOutOfMemory(p2, bytes);
p2 = onOutOfMemoryTyped<T>(AllocFunction::Realloc, newSize, prior);
return p2;
}
void free_(void *p) {
void free_(void* p) {
js_free(p);
}
JS_FRIEND_API(void) reportAllocOverflow() const;
bool checkSimulatedOOM() const {
if (js::oom::ShouldFailWithOOM()) {
js::ReportOutOfMemory(reinterpret_cast<ExclusiveContext*>(cx_));
return false;
}
return true;
}
};
} /* namespace js */

6607
android/arm64-v8a/include/spidermonkey/jsapi.h Executable file → Normal file

File diff suppressed because it is too large Load Diff

0
android/arm64-v8a/include/spidermonkey/jsbytecode.h Executable file → Normal file
View File

6
android/arm64-v8a/include/spidermonkey/jsclist.h Executable file → Normal file
View File

@ -13,8 +13,8 @@
** Circular linked list
*/
typedef struct JSCListStr {
struct JSCListStr *next;
struct JSCListStr *prev;
struct JSCListStr* next;
struct JSCListStr* prev;
} JSCList;
/*
@ -90,7 +90,7 @@ typedef struct JSCListStr {
** circular list is not empty
*/
#define JS_CLIST_IS_EMPTY(_l) \
((_l)->next == (_l))
bool((_l)->next == (_l))
/*
** Initialize a circular list

94
android/arm64-v8a/include/spidermonkey/jscpucfg.h Executable file → Normal file
View File

@ -7,99 +7,7 @@
#ifndef jscpucfg_h
#define jscpucfg_h
#define JS_HAVE_LONG_LONG
#if defined(_WIN64)
# if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)
# define IS_LITTLE_ENDIAN 1
# undef IS_BIG_ENDIAN
# else /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */
# error "CPU type is unknown"
# endif /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */
#elif defined(_WIN32)
# ifdef __WATCOMC__
# define HAVE_VA_LIST_AS_ARRAY 1
# endif
# define IS_LITTLE_ENDIAN 1
# undef IS_BIG_ENDIAN
#elif defined(__APPLE__) || defined(__powerpc__) || defined(__ppc__)
# if __LITTLE_ENDIAN__
# define IS_LITTLE_ENDIAN 1
# undef IS_BIG_ENDIAN
# elif __BIG_ENDIAN__
# undef IS_LITTLE_ENDIAN
# define IS_BIG_ENDIAN 1
# endif
#elif defined(JS_HAVE_ENDIAN_H)
# include <endian.h>
# if defined(__BYTE_ORDER)
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define IS_LITTLE_ENDIAN 1
# undef IS_BIG_ENDIAN
# elif __BYTE_ORDER == __BIG_ENDIAN
# undef IS_LITTLE_ENDIAN
# define IS_BIG_ENDIAN 1
# endif
# else /* !defined(__BYTE_ORDER) */
# error "endian.h does not define __BYTE_ORDER. Cannot determine endianness."
# endif
/* BSDs */
#elif defined(JS_HAVE_MACHINE_ENDIAN_H)
# include <sys/types.h>
# include <machine/endian.h>
# if defined(_BYTE_ORDER)
# if _BYTE_ORDER == _LITTLE_ENDIAN
# define IS_LITTLE_ENDIAN 1
# undef IS_BIG_ENDIAN
# elif _BYTE_ORDER == _BIG_ENDIAN
# undef IS_LITTLE_ENDIAN
# define IS_BIG_ENDIAN 1
# endif
# else /* !defined(_BYTE_ORDER) */
# error "machine/endian.h does not define _BYTE_ORDER. Cannot determine endianness."
# endif
#elif defined(JS_HAVE_SYS_ISA_DEFS_H)
# include <sys/isa_defs.h>
# if defined(_BIG_ENDIAN)
# undef IS_LITTLE_ENDIAN
# define IS_BIG_ENDIAN 1
# elif defined(_LITTLE_ENDIAN)
# define IS_LITTLE_ENDIAN 1
# undef IS_BIG_ENDIAN
# else /* !defined(_LITTLE_ENDIAN) */
# error "sys/isa_defs.h does not define _BIG_ENDIAN or _LITTLE_ENDIAN. Cannot determine endianness."
# endif
# if !defined(JS_STACK_GROWTH_DIRECTION)
# if defined(_STACK_GROWS_UPWARD)
# define JS_STACK_GROWTH_DIRECTION (1)
# elif defined(_STACK_GROWS_DOWNWARD)
# define JS_STACK_GROWTH_DIRECTION (-1)
# endif
# endif
#elif defined(__sparc) || defined(__sparc__) || \
defined(_POWER) || defined(__hppa) || \
defined(_MIPSEB) || defined(_BIG_ENDIAN)
/* IA64 running HP-UX will have _BIG_ENDIAN defined.
* IA64 running Linux will have endian.h and be handled above.
*/
# undef IS_LITTLE_ENDIAN
# define IS_BIG_ENDIAN 1
#else /* !defined(__sparc) && !defined(__sparc__) && ... */
# error "Cannot determine endianness of your platform. Please add support to jscpucfg.h."
#endif
#include "mozilla/EndianUtils.h"
#ifndef JS_STACK_GROWTH_DIRECTION
# ifdef __hppa

2646
android/arm64-v8a/include/spidermonkey/jsfriendapi.h Executable file → Normal file

File diff suppressed because it is too large Load Diff

4
android/arm64-v8a/include/spidermonkey/jsperf.h Executable file → Normal file
View File

@ -118,7 +118,7 @@ class JS_FRIEND_API(PerfMeasurement)
* global object). The JS-visible API is identical to the C++ API.
*/
extern JS_FRIEND_API(JSObject*)
RegisterPerfMeasurement(JSContext *cx, JS::HandleObject global);
RegisterPerfMeasurement(JSContext* cx, JS::HandleObject global);
/*
* Given a Value which contains an instance of the aforementioned
@ -126,7 +126,7 @@ extern JS_FRIEND_API(JSObject*)
* Value is not an instance of the wrapper.
*/
extern JS_FRIEND_API(PerfMeasurement*)
ExtractPerfMeasurement(Value wrapper);
ExtractPerfMeasurement(const Value& wrapper);
} // namespace JS

35
android/arm64-v8a/include/spidermonkey/jsprf.h Executable file → Normal file
View File

@ -14,39 +14,38 @@
** %x - unsigned hex
** %X - unsigned uppercase hex
** %o - unsigned octal
** %hd, %hu, %hx, %hX, %ho - 16-bit versions of above
** %ld, %lu, %lx, %lX, %lo - 32-bit versions of above
** %lld, %llu, %llx, %llX, %llo - 64 bit versions of above
** %s - ascii string
** %hs - ucs2 string
** %hd, %hu, %hx, %hX, %ho - "short" versions of above
** %ld, %lu, %lx, %lX, %lo - "long" versions of above
** %lld, %llu, %llx, %llX, %llo - "long long" versions of above
** %zd, %zo, %zu, %zx, %zX - size_t versions of above
** %Id, %Io, %Iu, %Ix, %IX - size_t versions of above (for Windows compat)
** You should use PRI*SIZE macros instead
** %s - string
** %c - character
** %p - pointer (deals with machine dependent pointer size)
** %f - float
** %g - float
*/
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/SizePrintfMacros.h"
#include <stdarg.h>
#include "jstypes.h"
/*
** sprintf into a fixed size buffer. Guarantees that a NUL is at the end
** of the buffer. Returns the length of the written output, NOT including
** the NUL, or (uint32_t)-1 if an error occurs.
*/
extern JS_PUBLIC_API(uint32_t) JS_snprintf(char *out, uint32_t outlen, const char *fmt, ...);
/*
** sprintf into a malloc'd buffer. Return a pointer to the malloc'd
** buffer on success, nullptr on failure. Call "JS_smprintf_free" to release
** the memory returned.
*/
extern JS_PUBLIC_API(char*) JS_smprintf(const char *fmt, ...);
extern JS_PUBLIC_API(char*) JS_smprintf(const char* fmt, ...)
MOZ_FORMAT_PRINTF(1, 2);
/*
** Free the memory allocated, for the caller, by JS_smprintf
*/
extern JS_PUBLIC_API(void) JS_smprintf_free(char *mem);
extern JS_PUBLIC_API(void) JS_smprintf_free(char* mem);
/*
** "append" sprintf into a malloc'd buffer. "last" is the last value of
@ -55,13 +54,13 @@ extern JS_PUBLIC_API(void) JS_smprintf_free(char *mem);
** will allocate the initial string. The return value is the new value of
** last for subsequent calls, or nullptr if there is a malloc failure.
*/
extern JS_PUBLIC_API(char*) JS_sprintf_append(char *last, const char *fmt, ...);
extern JS_PUBLIC_API(char*) JS_sprintf_append(char* last, const char* fmt, ...)
MOZ_FORMAT_PRINTF(2, 3);
/*
** va_list forms of the above.
*/
extern JS_PUBLIC_API(uint32_t) JS_vsnprintf(char *out, uint32_t outlen, const char *fmt, va_list ap);
extern JS_PUBLIC_API(char*) JS_vsmprintf(const char *fmt, va_list ap);
extern JS_PUBLIC_API(char*) JS_vsprintf_append(char *last, const char *fmt, va_list ap);
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 */

116
android/arm64-v8a/include/spidermonkey/jsprototypes.h Executable file → Normal file
View File

@ -35,12 +35,7 @@
#define CLASP(name) (&name##Class)
#define OCLASP(name) (&name##Object::class_)
#define TYPED_ARRAY_CLASP(type) (&TypedArrayObject::classes[Scalar::type])
#ifdef ENABLE_PARALLEL_JS
#define IF_PJS(real,imaginary) real
#else
#define IF_PJS(real,imaginary) imaginary
#endif
#define ERROR_CLASP(type) (&ErrorObject::classes[type])
#ifdef EXPOSE_INTL_API
#define IF_INTL(real,imaginary) real
@ -54,61 +49,80 @@
#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 JS_HAS_SYMBOLS
#define IF_SYMBOLS(real,imaginary) real
#ifdef SPIDERMONKEY_PROMISE
#define IF_PROMISE(real,imaginary) real
#else
#define IF_SYMBOLS(real,imaginary) imaginary
#define IF_PROMISE(real,imaginary) imaginary
#endif
#define JS_FOR_PROTOTYPES(real,imaginary) \
imaginary(Null, 0, js_InitNullClass, dummy) \
real(Object, 1, js_InitViaClassSpec, &JSObject::class_) \
real(Function, 2, js_InitViaClassSpec, &JSFunction::class_) \
real(Array, 3, js_InitViaClassSpec, OCLASP(Array)) \
real(Boolean, 4, js_InitBooleanClass, OCLASP(Boolean)) \
real(JSON, 5, js_InitJSONClass, CLASP(JSON)) \
real(Date, 6, js_InitViaClassSpec, OCLASP(Date)) \
real(Math, 7, js_InitMathClass, CLASP(Math)) \
real(Number, 8, js_InitNumberClass, OCLASP(Number)) \
real(String, 9, js_InitStringClass, OCLASP(String)) \
real(RegExp, 10, js_InitRegExpClass, OCLASP(RegExp)) \
real(Error, 11, js_InitViaClassSpec, OCLASP(Error)) \
real(InternalError, 12, js_InitViaClassSpec, OCLASP(Error)) \
real(EvalError, 13, js_InitViaClassSpec, OCLASP(Error)) \
real(RangeError, 14, js_InitViaClassSpec, OCLASP(Error)) \
real(ReferenceError, 15, js_InitViaClassSpec, OCLASP(Error)) \
real(SyntaxError, 16, js_InitViaClassSpec, OCLASP(Error)) \
real(TypeError, 17, js_InitViaClassSpec, OCLASP(Error)) \
real(URIError, 18, js_InitViaClassSpec, OCLASP(Error)) \
real(Iterator, 19, js_InitIteratorClasses, OCLASP(PropertyIterator)) \
real(StopIteration, 20, js_InitIteratorClasses, OCLASP(StopIteration)) \
real(ArrayBuffer, 21, js_InitArrayBufferClass, &js::ArrayBufferObject::protoClass) \
real(Int8Array, 22, js_InitViaClassSpec, TYPED_ARRAY_CLASP(Int8)) \
real(Uint8Array, 23, js_InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8)) \
real(Int16Array, 24, js_InitViaClassSpec, TYPED_ARRAY_CLASP(Int16)) \
real(Uint16Array, 25, js_InitViaClassSpec, TYPED_ARRAY_CLASP(Uint16)) \
real(Int32Array, 26, js_InitViaClassSpec, TYPED_ARRAY_CLASP(Int32)) \
real(Uint32Array, 27, js_InitViaClassSpec, TYPED_ARRAY_CLASP(Uint32)) \
real(Float32Array, 28, js_InitViaClassSpec, TYPED_ARRAY_CLASP(Float32)) \
real(Float64Array, 29, js_InitViaClassSpec, TYPED_ARRAY_CLASP(Float64)) \
real(Uint8ClampedArray, 30, js_InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8Clamped)) \
real(Proxy, 31, js_InitProxyClass, &ProxyObject::uncallableClass_) \
real(WeakMap, 32, js_InitWeakMapClass, OCLASP(WeakMap)) \
real(Map, 33, js_InitMapClass, OCLASP(Map)) \
real(Set, 34, js_InitSetClass, OCLASP(Set)) \
real(DataView, 35, js_InitDataViewClass, OCLASP(DataView)) \
IF_SYMBOLS(real,imaginary)(Symbol, 36, js_InitSymbolClass, &js::SymbolObject::class_) \
IF_SAB(real,imaginary)(SharedArrayBuffer, 37, js_InitSharedArrayBufferClass, &js::SharedArrayBufferObject::protoClass) \
IF_INTL(real,imaginary) (Intl, 38, js_InitIntlClass, CLASP(Intl)) \
IF_BDATA(real,imaginary)(TypedObject, 39, js_InitTypedObjectModuleObject, OCLASP(TypedObjectModule)) \
imaginary(GeneratorFunction, 40, js_InitIteratorClasses, dummy) \
IF_BDATA(real,imaginary)(SIMD, 41, js_InitSIMDClass, OCLASP(SIMD)) \
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)

View File

@ -1,563 +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 jsproxy_h
#define jsproxy_h
#include "mozilla/Maybe.h"
#include "jsfriendapi.h"
#include "js/CallNonGenericMethod.h"
#include "js/Class.h"
namespace js {
using JS::AutoIdVector;
using JS::CallArgs;
using JS::HandleId;
using JS::HandleObject;
using JS::HandleValue;
using JS::IsAcceptableThis;
using JS::MutableHandle;
using JS::MutableHandleObject;
using JS::MutableHandleValue;
using JS::NativeImpl;
using JS::PrivateValue;
using JS::Value;
class RegExpGuard;
class JS_FRIEND_API(Wrapper);
/*
* A proxy is a JSObject that implements generic behavior by providing custom
* implementations for each object trap. The implementation for each trap is
* provided by a C++ object stored on the proxy, known as its handler.
*
* A major use case for proxies is to forward each trap to another object,
* known as its target. The target can be an arbitrary C++ object. Not every
* proxy has the notion of a target, however.
*
* Proxy traps are grouped into fundamental and derived traps. Every proxy has
* to at least provide implementations for the fundamental traps, but the
* derived traps can be implemented in terms of the fundamental ones
* BaseProxyHandler provides implementations of the derived traps in terms of
* the (pure virtual) fundamental traps.
*
* In addition to the normal traps, there are two models for proxy prototype
* chains. First, proxies may opt to use the standard prototype mechanism used
* throughout the engine. To do so, simply pass a prototype to NewProxyObject()
* at creation time. All prototype accesses will then "just work" to treat the
* proxy as a "normal" object. Alternatively, if instead the proxy wishes to
* implement more complicated prototype semantics (if, for example, it wants to
* delegate the prototype lookup to a wrapped object), it may pass Proxy::LazyProto
* as the prototype at create time and opt in to the trapped prototype system,
* which guarantees that their trap will be called on any and every prototype
* chain access of the object.
*
* This system is implemented with two traps: {get,set}PrototypeOf. The default
* implementation of setPrototypeOf throws a TypeError. Since it is not possible
* to create an object without a sense of prototype chain, handler implementors
* must provide a getPrototypeOf trap if opting in to the dynamic prototype system.
*
* To minimize code duplication, a set of abstract proxy handler classes is
* provided, from which other handlers may inherit. These abstract classes
* are organized in the following hierarchy:
*
* BaseProxyHandler
* |
* DirectProxyHandler
* |
* Wrapper
*/
/*
* BaseProxyHandler is the most generic kind of proxy handler. It does not make
* any assumptions about the target. Consequently, it does not provide any
* default implementation for the fundamental traps. It does, however, implement
* the derived traps in terms of the fundamental ones. This allows consumers of
* this class to define any custom behavior they want.
*
* Important: If you add a trap 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 trap in SecurityWrapper. See bug 945826 comment 0.
*/
class JS_FRIEND_API(BaseProxyHandler)
{
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" traps like
* getOwnPropertyDescriptor, hasOwn, defineProperty, keys, 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 BaseProxyHandler(const void *family, bool hasPrototype = false,
bool hasSecurityPolicy = false);
virtual ~BaseProxyHandler();
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(Value priv) const {
/*
* Called on creation of a proxy to determine whether its finalize
* method can be finalized on the background thread.
*/
return true;
}
/* Policy enforcement traps.
*
* 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 trap 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 both calls to ::get()
* and ::set() (since we need to look up the accessor), so its
* assertEnteredPolicy would pass GET | SET.
*/
typedef uint32_t Action;
enum {
NONE = 0x00,
GET = 0x01,
SET = 0x02,
CALL = 0x04,
ENUMERATE = 0x08
};
virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Action act,
bool *bp) const;
/* ES5 Harmony fundamental proxy traps. */
virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const = 0;
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const = 0;
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
HandleId id, MutableHandle<JSPropertyDescriptor> desc) const = 0;
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const = 0;
virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
AutoIdVector &props) const = 0;
virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const = 0;
virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const = 0;
/* ES5 Harmony derived proxy traps. */
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const;
virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const;
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp) const;
virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const;
virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const;
virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
MutableHandleValue vp) const;
/* Spidermonkey extensions. */
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const = 0;
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const;
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const;
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const;
virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp) const;
virtual bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) 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 defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp) const;
virtual void finalize(JSFreeOp *fop, JSObject *proxy) const;
virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const;
virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp) 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 slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
HandleObject result) const;
/* See comment for weakmapKeyDelegateOp in js/Class.h. */
virtual JSObject *weakmapKeyDelegate(JSObject *proxy) const;
virtual bool isScripted() const { return false; }
};
/*
* DirectProxyHandler includes a notion of a target object. All traps are
* reimplemented such that they forward their behavior to the target. This
* allows consumers of this class to forward to another object as transparently
* and efficiently as possible.
*
* Important: If you add a trap 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_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler
{
public:
explicit DirectProxyHandler(const void *family, bool hasPrototype = false,
bool hasSecurityPolicy = false);
/* ES5 Harmony fundamental proxy traps. */
virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id,
bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject proxy,
AutoIdVector &props) const MOZ_OVERRIDE;
/* ES5 Harmony derived proxy traps. */
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id,
bool *bp) const MOZ_OVERRIDE;
virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id,
bool *bp) const MOZ_OVERRIDE;
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool keys(JSContext *cx, HandleObject proxy,
AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
MutableHandleValue vp) const MOZ_OVERRIDE;
/* Spidermonkey extensions. */
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const MOZ_OVERRIDE;
virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
bool *bp) const MOZ_OVERRIDE;
virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
MutableHandleObject protop) const MOZ_OVERRIDE;
virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
bool *bp) const MOZ_OVERRIDE;
virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
JSContext *cx) const MOZ_OVERRIDE;
virtual const char *className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual JSString *fun_toString(JSContext *cx, HandleObject proxy,
unsigned indent) const MOZ_OVERRIDE;
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy,
RegExpGuard *g) const MOZ_OVERRIDE;
virtual JSObject *weakmapKeyDelegate(JSObject *proxy) const MOZ_OVERRIDE;
};
/*
* Dispatch point for handlers that executes the appropriate C++ or scripted traps.
*
* Important: All proxy traps need either (a) an AutoEnterPolicy in their
* Proxy::foo entry point below or (b) an override in SecurityWrapper. See bug
* 945826 comment 0.
*/
class Proxy
{
public:
/* ES5 Harmony fundamental proxy traps. */
static bool preventExtensions(JSContext *cx, HandleObject proxy);
static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc);
static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandleValue vp);
static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc);
static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandleValue vp);
static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc);
static bool getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props);
static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
static bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props);
/* ES5 Harmony derived proxy traps. */
static bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
static bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp);
static bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp);
static bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props);
static bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp);
/* Spidermonkey extensions. */
static bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible);
static bool call(JSContext *cx, HandleObject proxy, const CallArgs &args);
static bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args);
static bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args);
static bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp);
static bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx);
static const char *className(JSContext *cx, HandleObject proxy);
static JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent);
static bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g);
static bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp);
static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
static bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp);
static bool watch(JSContext *cx, HandleObject proxy, HandleId id, HandleObject callable);
static bool unwatch(JSContext *cx, HandleObject proxy, HandleId id);
static bool slice(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end,
HandleObject result);
/* IC entry path for handling __noSuchMethod__ on access. */
static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id,
MutableHandleValue vp);
};
// Use these in places where you don't want to #include vm/ProxyObject.h.
extern JS_FRIEND_DATA(const js::Class* const) CallableProxyClassPtr;
extern JS_FRIEND_DATA(const js::Class* const) UncallableProxyClassPtr;
inline bool IsProxy(JSObject *obj)
{
return GetObjectClass(obj)->isProxy();
}
/*
* These are part of the API.
*
* NOTE: PROXY_PRIVATE_SLOT is 0 because that way slot 0 is usable by API
* clients for both proxy and non-proxy objects. So an API client that only
* needs to store one slot's worth of data doesn't need to branch on what sort
* of object it has.
*/
const uint32_t PROXY_PRIVATE_SLOT = 0;
const uint32_t PROXY_HANDLER_SLOT = 1;
const uint32_t PROXY_EXTRA_SLOT = 2;
const uint32_t PROXY_MINIMUM_SLOTS = 4;
inline const BaseProxyHandler *
GetProxyHandler(JSObject *obj)
{
JS_ASSERT(IsProxy(obj));
return (const BaseProxyHandler *) GetReservedSlot(obj, PROXY_HANDLER_SLOT).toPrivate();
}
inline const Value &
GetProxyPrivate(JSObject *obj)
{
JS_ASSERT(IsProxy(obj));
return GetReservedSlot(obj, PROXY_PRIVATE_SLOT);
}
inline JSObject *
GetProxyTargetObject(JSObject *obj)
{
JS_ASSERT(IsProxy(obj));
return GetProxyPrivate(obj).toObjectOrNull();
}
inline const Value &
GetProxyExtra(JSObject *obj, size_t n)
{
JS_ASSERT(IsProxy(obj));
return GetReservedSlot(obj, PROXY_EXTRA_SLOT + n);
}
inline void
SetProxyHandler(JSObject *obj, BaseProxyHandler *handler)
{
JS_ASSERT(IsProxy(obj));
SetReservedSlot(obj, PROXY_HANDLER_SLOT, PrivateValue(handler));
}
inline void
SetProxyExtra(JSObject *obj, size_t n, const Value &extra)
{
JS_ASSERT(IsProxy(obj));
JS_ASSERT(n <= 1);
SetReservedSlot(obj, PROXY_EXTRA_SLOT + n, extra);
}
inline bool
IsScriptedProxy(JSObject *obj)
{
return IsProxy(obj) && GetProxyHandler(obj)->isScripted();
}
class MOZ_STACK_CLASS ProxyOptions {
protected:
/* protected constructor for subclass */
ProxyOptions(bool singletonArg, const Class *claspArg)
: singleton_(singletonArg),
clasp_(claspArg)
{}
public:
ProxyOptions() : singleton_(false),
clasp_(UncallableProxyClassPtr)
{}
bool singleton() const { return singleton_; }
ProxyOptions &setSingleton(bool flag) {
singleton_ = flag;
return *this;
}
const Class *clasp() const {
return clasp_;
}
ProxyOptions &setClass(const Class *claspArg) {
clasp_ = claspArg;
return *this;
}
ProxyOptions &selectDefaultClass(bool callable) {
const Class *classp = callable? CallableProxyClassPtr :
UncallableProxyClassPtr;
return setClass(classp);
}
private:
bool singleton_;
const Class *clasp_;
};
JS_FRIEND_API(JSObject *)
NewProxyObject(JSContext *cx, const BaseProxyHandler *handler, HandleValue priv,
JSObject *proto, JSObject *parent, const ProxyOptions &options = ProxyOptions());
JSObject *
RenewProxyObject(JSContext *cx, JSObject *obj, BaseProxyHandler *handler, 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)
#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() { JS_ASSERT(!allowed()); return rv; }
protected:
// no-op constructor for subclass
AutoEnterPolicy()
#ifdef JS_DEBUG
: context(nullptr)
, enteredAction(BaseProxyHandler::NONE)
#endif
{};
void reportErrorIfExceptionIsNotPending(JSContext *cx, jsid id);
bool allow;
bool rv;
#ifdef JS_DEBUG
JSContext *context;
mozilla::Maybe<HandleObject> enteredProxy;
mozilla::Maybe<HandleId> enteredId;
Action enteredAction;
// NB: We explicitly don't track the entered action here, because sometimes
// SET traps 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);
#else
inline void recordEnter(JSContext *cx, JSObject *proxy, jsid id, Action act) {}
inline void recordLeave() {}
#endif
};
#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);
}
};
#else
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);
#else
inline void assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id,
BaseProxyHandler::Action act)
{};
#endif
} /* namespace js */
extern JS_FRIEND_API(JSObject *)
js_InitProxyClass(JSContext *cx, JS::HandleObject obj);
#endif /* jsproxy_h */

580
android/arm64-v8a/include/spidermonkey/jspubtd.h Executable file → Normal file
View File

@ -12,17 +12,18 @@
*/
#include "mozilla/Assertions.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/LinkedList.h"
#include "mozilla/NullPtr.h"
#include "mozilla/PodOperations.h"
#include "jsprototypes.h"
#include "jstypes.h"
#include "js/TraceKind.h"
#include "js/TypeDecls.h"
#if defined(JSGC_USE_EXACT_ROOTING) || defined(JS_DEBUG)
# define JSGC_TRACK_EXACT_ROOTS
#if defined(JS_GC_ZEAL) || defined(DEBUG)
# define JSGC_HASH_TABLE_CHECKS
#endif
namespace JS {
@ -36,14 +37,21 @@ class Rooted;
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 JS */
namespace shadow {
struct Runtime;
} // namespace shadow
} // namespace JS
namespace js {
struct ContextFriendFields;
class RootLists;
} // namespace js
/*
@ -83,56 +91,16 @@ enum JSProtoKey {
JSProto_LIMIT
};
/*
* This enum type is used to control the behavior of a JSObject property
* iterator function that has type JSNewEnumerate.
*/
enum JSIterateOp {
/* Create new iterator state over enumerable properties. */
JSENUMERATE_INIT,
/* Create new iterator state over all properties. */
JSENUMERATE_INIT_ALL,
/* Iterate once. */
JSENUMERATE_NEXT,
/* Destroy iterator state. */
JSENUMERATE_DESTROY
};
/* See Value::gcKind() and JSTraceCallback in Tracer.h. */
enum JSGCTraceKind {
JSTRACE_OBJECT,
JSTRACE_STRING,
JSTRACE_SYMBOL,
JSTRACE_SCRIPT,
/*
* Trace kinds internal to the engine. The embedding can only see them if
* it implements JSTraceCallback.
*/
JSTRACE_LAZY_SCRIPT,
JSTRACE_JITCODE,
JSTRACE_SHAPE,
JSTRACE_BASE_SHAPE,
JSTRACE_TYPE_OBJECT,
JSTRACE_LAST = JSTRACE_TYPE_OBJECT
};
/* Struct forward declarations. */
struct JSClass;
struct JSCompartment;
struct JSConstDoubleSpec;
struct JSCrossCompartmentCall;
struct JSErrorReport;
class JSErrorReport;
struct JSExceptionState;
struct JSFunctionSpec;
struct JSIdArray;
struct JSLocaleCallbacks;
struct JSObjectMap;
struct JSPrincipals;
struct JSPropertyDescriptor;
struct JSPropertyName;
struct JSPropertySpec;
struct JSRuntime;
@ -144,119 +112,146 @@ class JS_PUBLIC_API(JSTracer);
class JSFlatString;
#ifdef JS_THREADSAFE
typedef struct PRCallOnceType JSCallOnceType;
#else
typedef bool JSCallOnceType;
#endif
typedef bool (*JSInitCallback)(void);
template<typename T> struct JSConstScalarSpec;
typedef JSConstScalarSpec<double> JSConstDoubleSpec;
typedef JSConstScalarSpec<int32_t> JSConstIntegerSpec;
/*
* Generic trace operation that calls JS_CallTracer on each traceable thing
* stored in data.
* Generic trace operation that calls JS::TraceEdge on each traceable thing's
* location reachable from data.
*/
typedef void
(* JSTraceDataOp)(JSTracer *trc, void *data);
void js_FinishGC(JSRuntime *rt);
(* JSTraceDataOp)(JSTracer* trc, void* data);
namespace js {
namespace gc {
class AutoTraceSession;
class StoreBuffer;
void MarkPersistentRootedChains(JSTracer *);
void FinishPersistentRootedChains(JSRuntime *);
}
}
} // namespace gc
// Whether the current thread is permitted access to any part of the specified
// runtime or zone.
JS_FRIEND_API(bool)
CurrentThreadCanAccessRuntime(const JSRuntime* rt);
#ifdef DEBUG
JS_FRIEND_API(bool)
CurrentThreadIsPerformingGC();
#endif
} // namespace js
namespace JS {
typedef void (*OffThreadCompileCallback)(void *token, void *callbackData);
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
{
/* Restrict zone access during Minor GC. */
bool needsBarrier_;
#ifdef JSGC_GENERATIONAL
private:
js::gc::StoreBuffer *gcStoreBufferPtr_;
#endif
JS::HeapState heapState_;
public:
explicit Runtime(
#ifdef JSGC_GENERATIONAL
js::gc::StoreBuffer *storeBuffer
#endif
)
: needsBarrier_(false)
#ifdef JSGC_GENERATIONAL
, gcStoreBufferPtr_(storeBuffer)
#endif
{}
bool needsBarrier() const {
return needsBarrier_;
protected:
void setHeapState(JS::HeapState newState) {
MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(asRuntime()));
MOZ_ASSERT(heapState_ != newState);
heapState_ = newState;
}
#ifdef JSGC_GENERATIONAL
js::gc::StoreBuffer *gcStoreBufferPtr() { return gcStoreBufferPtr_; }
#endif
JS::HeapState heapState() const {
MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(asRuntime()) ||
js::CurrentThreadIsPerformingGC());
return heapState_;
}
static JS::shadow::Runtime *asShadowRuntime(JSRuntime *rt) {
// 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<const JSRuntime*>(this);
}
static JS::shadow::Runtime* asShadowRuntime(JSRuntime* rt) {
return reinterpret_cast<JS::shadow::Runtime*>(rt);
}
/* Allow inlining of PersistentRooted constructors and destructors. */
private:
template <typename Referent> friend class JS::PersistentRooted;
friend void js::gc::MarkPersistentRootedChains(JSTracer *);
friend void js::gc::FinishPersistentRootedChains(JSRuntime *rt);
mozilla::LinkedList<PersistentRootedFunction> functionPersistentRooteds;
mozilla::LinkedList<PersistentRootedId> idPersistentRooteds;
mozilla::LinkedList<PersistentRootedObject> objectPersistentRooteds;
mozilla::LinkedList<PersistentRootedScript> scriptPersistentRooteds;
mozilla::LinkedList<PersistentRootedString> stringPersistentRooteds;
mozilla::LinkedList<PersistentRootedValue> valuePersistentRooteds;
/* Specializations of this return references to the appropriate list. */
template<typename Referent>
inline mozilla::LinkedList<PersistentRooted<Referent> > &getPersistentRootedList();
protected:
void setGCStoreBufferPtr(js::gc::StoreBuffer* storeBuffer) {
gcStoreBufferPtr_ = storeBuffer;
}
};
template<>
inline mozilla::LinkedList<PersistentRootedFunction>
&Runtime::getPersistentRootedList<JSFunction *>() { return functionPersistentRooteds; }
template<>
inline mozilla::LinkedList<PersistentRootedId>
&Runtime::getPersistentRootedList<jsid>() { return idPersistentRooteds; }
template<>
inline mozilla::LinkedList<PersistentRootedObject>
&Runtime::getPersistentRootedList<JSObject *>() { return objectPersistentRooteds; }
template<>
inline mozilla::LinkedList<PersistentRootedScript>
&Runtime::getPersistentRootedList<JSScript *>() { return scriptPersistentRooteds; }
template<>
inline mozilla::LinkedList<PersistentRootedString>
&Runtime::getPersistentRootedList<JSString *>() { return stringPersistentRooteds; }
template<>
inline mozilla::LinkedList<PersistentRootedValue>
&Runtime::getPersistentRootedList<Value>() { return valuePersistentRooteds; }
} /* namespace shadow */
// Decorates the Unlinking phase of CycleCollection so that accidental use
// of barriered accessors results in assertions instead of leaks.
class MOZ_STACK_CLASS JS_PUBLIC_API(AutoEnterCycleCollection)
{
#ifdef DEBUG
JSRuntime* runtime;
public:
explicit AutoEnterCycleCollection(JSContext* cx);
~AutoEnterCycleCollection();
#else
public:
explicit AutoEnterCycleCollection(JSContext* cx) {}
~AutoEnterCycleCollection() {}
#endif
};
class JS_PUBLIC_API(AutoGCRooter)
{
public:
AutoGCRooter(JSContext *cx, ptrdiff_t tag);
AutoGCRooter(js::ContextFriendFields *cx, ptrdiff_t tag);
AutoGCRooter(JSContext* cx, ptrdiff_t tag);
AutoGCRooter(JS::RootingContext* cx, ptrdiff_t tag);
~AutoGCRooter() {
MOZ_ASSERT(this == *stackTop);
@ -264,16 +259,9 @@ class JS_PUBLIC_API(AutoGCRooter)
}
/* Implemented in gc/RootMarking.cpp. */
inline void trace(JSTracer *trc);
static void traceAll(JSTracer *trc);
static void traceAllWrappers(JSTracer *trc);
/* T must be a context type */
template<typename T>
static void traceAllInContext(T* cx, JSTracer *trc) {
for (AutoGCRooter *gcr = cx->autoGCRooters; gcr; gcr = gcr->down)
gcr->trace(trc);
}
inline void trace(JSTracer* trc);
static void traceAll(JSTracer* trc);
static void traceAllWrappers(JSTracer* trc);
protected:
AutoGCRooter * const down;
@ -290,74 +278,40 @@ class JS_PUBLIC_API(AutoGCRooter)
enum {
VALARRAY = -2, /* js::AutoValueArray */
PARSER = -3, /* js::frontend::Parser */
SHAPEVECTOR = -4, /* js::AutoShapeVector */
IDARRAY = -6, /* js::AutoIdArray */
DESCVECTOR = -7, /* js::AutoPropDescVector */
VALVECTOR = -10, /* js::AutoValueVector */
IDVECTOR = -13, /* js::AutoIdVector */
IDVECTOR = -11, /* js::AutoIdVector */
OBJVECTOR = -14, /* js::AutoObjectVector */
STRINGVECTOR =-15, /* js::AutoStringVector */
SCRIPTVECTOR =-16, /* js::AutoScriptVector */
NAMEVECTOR = -17, /* js::AutoNameVector */
HASHABLEVALUE=-18, /* js::HashableValue */
IONMASM = -19, /* js::jit::MacroAssembler */
IONALLOC = -20, /* js::jit::AutoTempAllocatorRooter */
WRAPVECTOR = -21, /* js::AutoWrapperVector */
WRAPPER = -22, /* js::AutoWrapperRooter */
OBJOBJHASHMAP=-23, /* js::AutoObjectObjectHashMap */
OBJU32HASHMAP=-24, /* js::AutoObjectUnsigned32HashMap */
OBJHASHSET = -25, /* js::AutoObjectHashSet */
JSONPARSER = -26, /* js::JSONParser */
CUSTOM = -27, /* js::CustomAutoRooter */
FUNVECTOR = -28 /* js::AutoFunctionVector */
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) MOZ_DELETE;
void operator=(AutoGCRooter &ida) MOZ_DELETE;
AutoGCRooter(AutoGCRooter& ida) = delete;
void operator=(AutoGCRooter& ida) = delete;
};
// Our instantiations of Rooted<void*> and PersistentRooted<void*> require an
// instantiation of MapTypeToRootKind.
template <>
struct MapTypeToRootKind<void*> {
static const RootKind kind = RootKind::Traceable;
};
} /* namespace JS */
namespace js {
/*
* Parallel operations in general can have one of three states. They may
* succeed, fail, or "bail", where bail indicates that the code encountered an
* unexpected condition and should be re-run sequentially. Different
* subcategories of the "bail" state are encoded as variants of TP_RETRY_*.
*/
enum ParallelResult { TP_SUCCESS, TP_RETRY_SEQUENTIALLY, TP_RETRY_AFTER_GC, TP_FATAL };
struct ThreadSafeContext;
class ForkJoinContext;
class ExclusiveContext;
class Allocator;
enum ThingRootKind
{
THING_ROOT_OBJECT,
THING_ROOT_SHAPE,
THING_ROOT_BASE_SHAPE,
THING_ROOT_TYPE_OBJECT,
THING_ROOT_STRING,
THING_ROOT_SYMBOL,
THING_ROOT_JIT_CODE,
THING_ROOT_SCRIPT,
THING_ROOT_LAZY_SCRIPT,
THING_ROOT_ID,
THING_ROOT_VALUE,
THING_ROOT_TYPE,
THING_ROOT_BINDINGS,
THING_ROOT_PROPERTY_DESCRIPTOR,
THING_ROOT_PROP_DESC,
THING_ROOT_LIMIT
};
/*
* 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
@ -371,82 +325,120 @@ enum StackKind
StackKindCount
};
template <typename T>
struct RootKind;
using RootedListHeads = mozilla::EnumeratedArray<JS::RootKind, JS::RootKind::Limit,
JS::Rooted<void*>*>;
/*
* Specifically mark the ThingRootKind of externally visible types, so that
* JSAPI users may use JSRooted... types without having the class definition
* available.
*/
template<typename T, ThingRootKind Kind>
struct SpecificRootKind
// Abstracts JS rooting mechanisms so they can be shared between the JSContext
// and JSRuntime.
class RootLists
{
static ThingRootKind rootKind() { return Kind; }
};
// Stack GC roots for Rooted GC heap pointers.
RootedListHeads stackRoots_;
template <typename T> friend class JS::Rooted;
template <> struct RootKind<JSObject *> : SpecificRootKind<JSObject *, THING_ROOT_OBJECT> {};
template <> struct RootKind<JSFlatString *> : SpecificRootKind<JSFlatString *, THING_ROOT_STRING> {};
template <> struct RootKind<JSFunction *> : SpecificRootKind<JSFunction *, THING_ROOT_OBJECT> {};
template <> struct RootKind<JSString *> : SpecificRootKind<JSString *, THING_ROOT_STRING> {};
template <> struct RootKind<JS::Symbol *> : SpecificRootKind<JS::Symbol *, THING_ROOT_SYMBOL> {};
template <> struct RootKind<JSScript *> : SpecificRootKind<JSScript *, THING_ROOT_SCRIPT> {};
template <> struct RootKind<jsid> : SpecificRootKind<jsid, THING_ROOT_ID> {};
template <> struct RootKind<JS::Value> : SpecificRootKind<JS::Value, THING_ROOT_VALUE> {};
// Stack GC roots for AutoFooRooter classes.
JS::AutoGCRooter* autoGCRooters_;
friend class JS::AutoGCRooter;
struct ContextFriendFields
{
protected:
JSRuntime *const runtime_;
/* The current compartment. */
JSCompartment *compartment_;
/* The current zone. */
JS::Zone *zone_;
// Heap GC roots for PersistentRooted pointers.
mozilla::EnumeratedArray<JS::RootKind, JS::RootKind::Limit,
mozilla::LinkedList<JS::PersistentRooted<void*>>> heapRoots_;
template <typename T> friend class JS::PersistentRooted;
public:
explicit ContextFriendFields(JSRuntime *rt)
: runtime_(rt), compartment_(nullptr), zone_(nullptr), autoGCRooters(nullptr)
{
#ifdef JSGC_TRACK_EXACT_ROOTS
mozilla::PodArrayZero(thingGCRooters);
#endif
RootLists() : autoGCRooters_(nullptr) {
for (auto& stackRootPtr : stackRoots_)
stackRootPtr = nullptr;
}
static const ContextFriendFields *get(const JSContext *cx) {
return reinterpret_cast<const ContextFriendFields *>(cx);
~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<Traceable> that
// outlives the RootLists.
MOZ_ASSERT(heapRoots_[JS::RootKind::Traceable].isEmpty());
}
static ContextFriendFields *get(JSContext *cx) {
return reinterpret_cast<ContextFriendFields *>(cx);
}
#ifdef JSGC_TRACK_EXACT_ROOTS
private:
/*
* Stack allocated GC roots for stack GC heap pointers, which may be
* overwritten if moved during a GC.
*/
JS::Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
public:
template <class T>
inline JS::Rooted<T> *gcRooters() {
js::ThingRootKind kind = RootKind<T>::rootKind();
return reinterpret_cast<JS::Rooted<T> *>(thingGCRooters[kind]);
}
#endif
void traceStackRoots(JSTracer* trc);
void checkNoGCRooters();
/* Stack of thread-stack-allocated GC roots. */
JS::AutoGCRooter *autoGCRooters;
void tracePersistentRoots(JSTracer* trc);
void finishPersistentRoots();
};
friend JSRuntime *GetRuntime(const JSContext *cx);
friend JSCompartment *GetContextCompartment(const JSContext *cx);
friend JS::Zone *GetContextZone(const JSContext *cx);
} // namespace js
namespace JS {
/*
* 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;
#ifdef DEBUG
// Whether the derived class is a JSContext or an ExclusiveContext.
bool isJSContext;
#endif
explicit RootingContext(bool isJSContextArg)
#ifdef DEBUG
: isJSContext(isJSContextArg)
#endif
{}
static RootingContext* get(JSContext* cx) {
return reinterpret_cast<RootingContext*>(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<const ContextFriendFields*>(cx);
}
static ContextFriendFields* get(JSContext* cx) {
return reinterpret_cast<ContextFriendFields*>(cx);
}
friend JSCompartment* GetContextCompartment(const JSContext* cx);
friend JS::Zone* GetContextZone(const JSContext* cx);
template <typename T> friend class JS::Rooted;
};
@ -460,89 +452,25 @@ struct ContextFriendFields
* usable without resorting to jsfriendapi.h, and when JSContext is an
* incomplete type.
*/
inline JSRuntime *
GetRuntime(const JSContext *cx)
{
return ContextFriendFields::get(cx)->runtime_;
}
inline JSCompartment *
GetContextCompartment(const JSContext *cx)
inline JSCompartment*
GetContextCompartment(const JSContext* cx)
{
return ContextFriendFields::get(cx)->compartment_;
}
inline JS::Zone *
GetContextZone(const JSContext *cx)
inline JS::Zone*
GetContextZone(const JSContext* cx)
{
return ContextFriendFields::get(cx)->zone_;
}
class PerThreadData;
struct PerThreadDataFriendFields
{
private:
// Note: this type only exists to permit us to derive the offset of
// the perThread data within the real JSRuntime* type in a portable
// way.
struct RuntimeDummy : JS::shadow::Runtime
{
struct PerThreadDummy {
void *field1;
uintptr_t field2;
#ifdef JS_DEBUG
uint64_t field3;
#endif
} mainThread;
};
public:
PerThreadDataFriendFields();
#ifdef JSGC_TRACK_EXACT_ROOTS
private:
/*
* Stack allocated GC roots for stack GC heap pointers, which may be
* overwritten if moved during a GC.
*/
JS::Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
public:
template <class T>
inline JS::Rooted<T> *gcRooters() {
js::ThingRootKind kind = RootKind<T>::rootKind();
return reinterpret_cast<JS::Rooted<T> *>(thingGCRooters[kind]);
}
#endif
/* Limit pointer for checking native stack consumption. */
uintptr_t nativeStackLimit[StackKindCount];
static const size_t RuntimeMainThreadOffset = offsetof(RuntimeDummy, mainThread);
static inline PerThreadDataFriendFields *get(js::PerThreadData *pt) {
return reinterpret_cast<PerThreadDataFriendFields *>(pt);
}
static inline PerThreadDataFriendFields *getMainThread(JSRuntime *rt) {
// mainThread must always appear directly after |JS::shadow::Runtime|.
// Tested by a JS_STATIC_ASSERT in |jsfriendapi.cpp|
return reinterpret_cast<PerThreadDataFriendFields *>(
reinterpret_cast<char*>(rt) + RuntimeMainThreadOffset);
}
static inline const PerThreadDataFriendFields *getMainThread(const JSRuntime *rt) {
// mainThread must always appear directly after |JS::shadow::Runtime|.
// Tested by a JS_STATIC_ASSERT in |jsfriendapi.cpp|
return reinterpret_cast<const PerThreadDataFriendFields *>(
reinterpret_cast<const char*>(rt) + RuntimeMainThreadOffset);
}
template <typename T> friend class JS::Rooted;
};
} /* namespace js */
MOZ_BEGIN_EXTERN_C
// Defined in NSPR prio.h.
typedef struct PRFileDesc PRFileDesc;
MOZ_END_EXTERN_C
#endif /* jspubtd_h */

41
android/arm64-v8a/include/spidermonkey/jstypes.h Executable file → Normal file
View File

@ -22,6 +22,7 @@
#define jstypes_h
#include "mozilla/Attributes.h"
#include "mozilla/Casting.h"
#include "mozilla/Types.h"
// jstypes.h is (or should be!) included by every file in SpiderMonkey.
@ -69,18 +70,16 @@
#if defined(STATIC_JS_API)
# define JS_PUBLIC_API(t) t
# define JS_PUBLIC_DATA(t) t
# define JS_FRIEND_API(t) t
# define JS_FRIEND_DATA(t) t
#elif defined(EXPORT_JS_API) || defined(STATIC_EXPORTABLE_JS_API)
# define JS_PUBLIC_API(t) MOZ_EXPORT t
# define JS_PUBLIC_DATA(t) MOZ_EXPORT t
#else
# define JS_PUBLIC_API(t) MOZ_IMPORT_API t
# define JS_PUBLIC_DATA(t) MOZ_IMPORT_DATA t
#endif
#if defined(STATIC_JS_API) || defined(EXPORT_JS_API) || defined(STATIC_EXPORTABLE_JS_API)
# define JS_FRIEND_API(t) MOZ_EXPORT t
# define JS_FRIEND_DATA(t) MOZ_EXPORT t
#else
# define JS_PUBLIC_API(t) MOZ_IMPORT_API t
# define JS_PUBLIC_DATA(t) MOZ_IMPORT_DATA t
# define JS_FRIEND_API(t) MOZ_IMPORT_API t
# define JS_FRIEND_DATA(t) MOZ_IMPORT_DATA t
#endif
@ -103,7 +102,7 @@
***********************************************************************/
#define JS_BEGIN_MACRO do {
#if defined(_MSC_VER) && _MSC_VER >= 1400
#if defined(_MSC_VER)
# define JS_END_MACRO \
} __pragma(warning(push)) __pragma(warning(disable:4127)) \
while (0) __pragma(warning(pop))
@ -168,10 +167,10 @@
** Macros to get the number of elements and the pointer to one past the
** last element of a C array. Use them like this:
**
** jschar buf[10], *s;
** JSString *str;
** char16_t buf[10];
** JSString* str;
** ...
** for (s = buf; s != JS_ARRAY_END(buf); ++s) *s = ...;
** for (char16_t* s = buf; s != JS_ARRAY_END(buf); ++s) *s = ...;
** ...
** str = JS_NewStringCopyN(cx, buf, JS_ARRAY_LENGTH(buf));
** ...
@ -194,26 +193,20 @@
** MACROS: JS_FUNC_TO_DATA_PTR
** JS_DATA_TO_FUNC_PTR
** DESCRIPTION:
** Macros to convert between function and data pointers assuming that
** they have the same size. Use them like this:
** Macros to convert between function and data pointers of the same
** size. Use them like this:
**
** JSPropertyOp nativeGetter;
** JSObject *scriptedGetter;
** JSGetterOp nativeGetter;
** JSObject* scriptedGetter;
** ...
** scriptedGetter = JS_FUNC_TO_DATA_PTR(JSObject *, nativeGetter);
** scriptedGetter = JS_FUNC_TO_DATA_PTR(JSObject*, nativeGetter);
** ...
** nativeGetter = JS_DATA_TO_FUNC_PTR(JSPropertyOp, scriptedGetter);
** nativeGetter = JS_DATA_TO_FUNC_PTR(JSGetterOp, scriptedGetter);
**
***********************************************************************/
#ifdef __GNUC__
# define JS_FUNC_TO_DATA_PTR(type, fun) (__extension__ (type) (size_t) (fun))
# define JS_DATA_TO_FUNC_PTR(type, ptr) (__extension__ (type) (size_t) (ptr))
#else
/* Use an extra (void *) cast for MSVC. */
# define JS_FUNC_TO_DATA_PTR(type, fun) ((type) (void *) (fun))
# define JS_DATA_TO_FUNC_PTR(type, ptr) ((type) (void *) (ptr))
#endif
#define JS_FUNC_TO_DATA_PTR(type, fun) (mozilla::BitwiseCast<type>(fun))
#define JS_DATA_TO_FUNC_PTR(type, ptr) (mozilla::BitwiseCast<type>(ptr))
#ifdef __GNUC__
# define JS_EXTENSION __extension__

30
android/arm64-v8a/include/spidermonkey/jsversion.h Executable file → Normal file
View File

@ -10,32 +10,25 @@
/*
* JS Capability Macros.
*/
#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */
#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 /* has JS2 const as alternative var */
#define JS_HAS_FUN_EXPR_STMT 1 /* has function expression statement */
#define JS_HAS_NO_SUCH_METHOD 1 /* has o.__noSuchMethod__ handler */
#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 /* has yield in generator function */
#define JS_HAS_BLOCK_SCOPE 1 /* has block scope via let/arraycomp */
#define JS_HAS_DESTRUCTURING 2 /* has [a,b] = ... or {p:a,q:b} = ... */
#define JS_HAS_GENERATOR_EXPRS 1 /* has (expr for (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 */
#ifdef NIGHTLY_BUILD
#define JS_HAS_TEMPLATE_STRINGS 1 /* has template string support */
#endif
/* Support for JS_NewGlobalObject. */
/* (no longer used) */
#define JS_HAS_NEW_GLOBAL_OBJECT 1
/* Support for JS_MakeSystemObject. */
#define JS_HAS_MAKE_SYSTEM_OBJECT 1
/* Feature-test macro for evolving destructuring support. */
/* (no longer used) */
#define JS_HAS_DESTRUCTURING_SHORTHAND (JS_HAS_DESTRUCTURING == 2)
/*
@ -44,9 +37,4 @@
*/
#define JS_OLD_GETTER_SETTER_METHODS 1
/* Support for Symbols - Nightly-only for now. */
#ifdef NIGHTLY_BUILD
#define JS_HAS_SYMBOLS 1
#endif
#endif /* jsversion_h */

449
android/arm64-v8a/include/spidermonkey/jswrapper.h Executable file → Normal file
View File

@ -9,12 +9,10 @@
#include "mozilla/Attributes.h"
#include "jsproxy.h"
#include "js/Proxy.h"
namespace js {
class DummyFrameGuard;
/*
* Helper for Wrapper::New default options.
*
@ -23,20 +21,20 @@ class DummyFrameGuard;
*/
class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions {
public:
WrapperOptions() : ProxyOptions(false, nullptr),
WrapperOptions() : ProxyOptions(false),
proto_()
{}
explicit WrapperOptions(JSContext *cx) : ProxyOptions(false, nullptr),
explicit WrapperOptions(JSContext* cx) : ProxyOptions(false),
proto_()
{
proto_.construct(cx);
proto_.emplace(cx);
}
inline JSObject *proto() const;
WrapperOptions &setProto(JSObject *protoArg) {
JS_ASSERT(!proto_.empty());
proto_.ref() = protoArg;
inline JSObject* proto() const;
WrapperOptions& setProto(JSObject* protoArg) {
MOZ_ASSERT(proto_);
*proto_ = protoArg;
return *this;
}
@ -46,17 +44,87 @@ class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions {
/*
* A wrapper is a proxy with a target object to which it generally forwards
* operations, but may restrict access to certain operations or instrument
* the trap operations in various ways. A wrapper is distinct from a Direct Proxy
* Handler in the sense that it can be "unwrapped" in C++, exposing the underlying
* object (Direct Proxy Handlers have an underlying target object, but don't
* expect to expose this object via any kind of unwrapping operation). Callers
* should be careful to avoid unwrapping security wrappers in the wrong context.
* operations, but may restrict access to certain operations or augment those
* operations in various ways.
*
* A wrapper can be "unwrapped" in C++, exposing the underlying object.
* Callers should be careful to avoid unwrapping security wrappers in the wrong
* context.
*
* Important: If you add a method implementation here, you probably also need
* to add an override in CrossCompartmentWrapper. If you don't, you risk
* compartment mismatches. See bug 945826 comment 0.
*/
class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
class JS_FRIEND_API(Wrapper) : public BaseProxyHandler
{
unsigned mFlags;
public:
explicit constexpr Wrapper(unsigned aFlags, bool aHasPrototype = false,
bool aHasSecurityPolicy = false)
: BaseProxyHandler(&family, aHasPrototype, aHasSecurityPolicy),
mFlags(aFlags)
{ }
virtual bool finalizeInBackground(const Value& priv) const override;
/* Standard internal methods. */
virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const override;
virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
Handle<PropertyDescriptor> 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<PropertyDescriptor> 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;
@ -65,96 +133,149 @@ class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
LAST_USED_FLAG = CROSS_COMPARTMENT
};
virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
MutableHandleValue vp) const MOZ_OVERRIDE;
static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler,
const WrapperOptions& options = WrapperOptions());
static JSObject *New(JSContext *cx, JSObject *obj, JSObject *parent, const Wrapper *handler,
const WrapperOptions *options = nullptr);
static JSObject* Renew(JSContext* cx, JSObject* existing, JSObject* obj, const Wrapper* handler);
static JSObject *Renew(JSContext *cx, JSObject *existing, JSObject *obj, const Wrapper *handler);
static const Wrapper* wrapperHandler(JSObject* wrapper);
static const Wrapper *wrapperHandler(JSObject *wrapper);
static JSObject *wrappedObject(JSObject *wrapper);
static JSObject* wrappedObject(JSObject* wrapper);
unsigned flags() const {
return mFlags;
}
explicit Wrapper(unsigned flags, bool hasPrototype = false, bool hasSecurityPolicy = false);
virtual ~Wrapper();
virtual bool finalizeInBackground(Value priv) const MOZ_OVERRIDE;
static const char family;
static const Wrapper singleton;
static const Wrapper singletonWithPrototype;
static JSObject *defaultProto;
static JSObject* defaultProto;
};
inline JSObject *
inline JSObject*
WrapperOptions::proto() const
{
return proto_.empty() ? Wrapper::defaultProto : proto_.ref();
return proto_ ? *proto_ : Wrapper::defaultProto;
}
/* Base class for all cross compartment wrapper handlers. */
class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
{
public:
explicit CrossCompartmentWrapper(unsigned flags, bool hasPrototype = false,
bool hasSecurityPolicy = false);
explicit constexpr CrossCompartmentWrapper(unsigned aFlags, bool aHasPrototype = false,
bool aHasSecurityPolicy = false)
: Wrapper(CROSS_COMPARTMENT | aFlags, aHasPrototype, aHasSecurityPolicy)
{ }
virtual ~CrossCompartmentWrapper();
/* Standard internal methods. */
virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> desc) const override;
virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
Handle<PropertyDescriptor> 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;
/* ES5 Harmony fundamental wrapper traps. */
virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) const MOZ_OVERRIDE;
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_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;
/* ES5 Harmony derived wrapper traps. */
virtual bool has(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool hasOwn(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool get(JSContext *cx, HandleObject wrapper, HandleObject receiver,
HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, HandleObject wrapper, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool keys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool iterate(JSContext *cx, HandleObject wrapper, unsigned flags,
MutableHandleValue vp) const MOZ_OVERRIDE;
/* SpiderMonkey extensions. */
virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
MutableHandle<PropertyDescriptor> 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;
/* Spidermonkey extensions. */
virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject wrapper, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, HandleObject wrapper, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const MOZ_OVERRIDE;
virtual bool hasInstance(JSContext *cx, HandleObject wrapper, MutableHandleValue v,
bool *bp) const MOZ_OVERRIDE;
virtual const char *className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual JSString *fun_toString(JSContext *cx, HandleObject wrapper,
unsigned indent) const MOZ_OVERRIDE;
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE;
virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint,
MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
MutableHandleObject protop) const MOZ_OVERRIDE;
virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
bool *bp) const MOZ_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<PropertyDescriptor> desc) const override;
virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
Handle<PropertyDescriptor> 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<PropertyDescriptor> 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
@ -168,28 +289,36 @@ template <class Base>
class JS_FRIEND_API(SecurityWrapper) : public Base
{
public:
explicit SecurityWrapper(unsigned flags, bool hasPrototype = false);
explicit constexpr SecurityWrapper(unsigned flags, bool hasPrototype = false)
: Base(flags, hasPrototype, /* hasSecurityPolicy = */ true)
{ }
virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE;
virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) const MOZ_OVERRIDE;
virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Wrapper::Action act,
bool *bp) const MOZ_OVERRIDE;
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const MOZ_OVERRIDE;
virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint,
MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
JSContext *cx) const MOZ_OVERRIDE;
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool enter(JSContext* cx, HandleObject wrapper, HandleId id, Wrapper::Action act,
bool* bp) const override;
virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
bool *bp) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
Handle<PropertyDescriptor> 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 watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
JS::HandleObject callable) const MOZ_OVERRIDE;
virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id) const MOZ_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
@ -199,138 +328,54 @@ class JS_FRIEND_API(SecurityWrapper) : public Base
typedef SecurityWrapper<Base> Restrictive;
};
typedef SecurityWrapper<Wrapper> SameCompartmentSecurityWrapper;
typedef SecurityWrapper<CrossCompartmentWrapper> CrossCompartmentSecurityWrapper;
class JS_FRIEND_API(DeadObjectProxy) : public BaseProxyHandler
{
public:
// This variable exists solely to provide a unique address for use as an identifier.
static const char sDeadObjectFamily;
explicit DeadObjectProxy();
/* ES5 Harmony fundamental wrapper traps. */
virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE;
/* Spidermonkey extensions. */
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const MOZ_OVERRIDE;
virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
bool *bp) const MOZ_OVERRIDE;
virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
JSContext *cx) const MOZ_OVERRIDE;
virtual const char *className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const MOZ_OVERRIDE;
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE;
virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
MutableHandleObject protop) const MOZ_OVERRIDE;
static const DeadObjectProxy singleton;
};
extern JSObject *
TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj,
HandleObject parent, unsigned flags);
// Proxy family for wrappers. Public so that IsWrapper() can be fully inlined by
// jsfriendapi users.
// This variable exists solely to provide a unique address for use as an identifier.
extern JS_FRIEND_DATA(const char) sWrapperFamily;
extern JSObject*
TransparentObjectWrapper(JSContext* cx, HandleObject existing, HandleObject obj);
inline bool
IsWrapper(JSObject *obj)
IsWrapper(JSObject* obj)
{
return IsProxy(obj) && GetProxyHandler(obj)->family() == &sWrapperFamily;
return IsProxy(obj) && GetProxyHandler(obj)->family() == &Wrapper::family;
}
// Given a JSObject, returns that object stripped of wrappers. If
// stopAtOuter is true, then this returns the outer window if it was
// 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 stopAtOuter = true, unsigned *flagsp = nullptr);
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. Since checked
// code should never be unwrapping outer window wrappers, we always stop at
// outer windows.
JS_FRIEND_API(JSObject *)
CheckedUnwrap(JSObject *obj, bool stopAtOuter = true);
// 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 stopAtOuter = true);
JS_FRIEND_API(JSObject*)
UnwrapOneChecked(JSObject* obj, bool stopAtWindowProxy = true);
JS_FRIEND_API(bool)
IsCrossCompartmentWrapper(JSObject *obj);
bool
IsDeadProxyObject(JSObject *obj);
JSObject *
NewDeadProxyObject(JSContext *cx, JSObject *parent,
const ProxyOptions &options = ProxyOptions());
IsCrossCompartmentWrapper(JSObject* obj);
void
NukeCrossCompartmentWrapper(JSContext *cx, JSObject *wrapper);
NukeCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper);
bool
RemapWrapper(JSContext *cx, JSObject *wobj, JSObject *newTarget);
void
RemapWrapper(JSContext* cx, JSObject* wobj, JSObject* newTarget);
JS_FRIEND_API(bool)
RemapAllWrappersForObject(JSContext *cx, JSObject *oldTarget,
JSObject *newTarget);
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);
/*
* This auto class should be used around any code, such as brain transplants,
* that may touch dead zones. Brain transplants can cause problems
* because they operate on all compartments, whether live or dead. A brain
* transplant can cause a formerly dead object to be "reanimated" by causing a
* read or write barrier to be invoked on it during the transplant. In this way,
* a zone becomes a zombie, kept alive by repeatedly consuming
* (transplanted) brains.
*
* To work around this issue, we observe when mark bits are set on objects in
* dead zones. If this happens during a brain transplant, we do a full,
* non-incremental GC at the end of the brain transplant. This will clean up any
* objects that were improperly marked.
*/
struct JS_FRIEND_API(AutoMaybeTouchDeadZones)
{
// The version that takes an object just uses it for its runtime.
explicit AutoMaybeTouchDeadZones(JSContext *cx);
explicit AutoMaybeTouchDeadZones(JSObject *obj);
~AutoMaybeTouchDeadZones();
private:
JSRuntime *runtime;
unsigned markCount;
bool inIncremental;
bool manipulatingDeadZones;
};
RecomputeWrappers(JSContext* cx, const CompartmentFilter& sourceFilter,
const CompartmentFilter& targetFilter);
} /* namespace js */

View File

@ -9,6 +9,7 @@
#ifndef mozilla_Alignment_h
#define mozilla_Alignment_h
#include "mozilla/Attributes.h"
#include <stddef.h>
#include <stdint.h>
@ -119,10 +120,17 @@ struct AlignedStorage
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<typename T>
struct AlignedStorage2
struct MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS AlignedStorage2
{
union U
{
@ -132,6 +140,13 @@ struct AlignedStorage2
const T* addr() const { return reinterpret_cast<const T*>(u.mBytes); }
T* addr() { return static_cast<T*>(static_cast<void*>(u.mBytes)); }
AlignedStorage2() = default;
// AlignedStorage2 is non-copyable: the default copy constructor violates
// strict aliasing rules, per bug 1269319.
AlignedStorage2(const AlignedStorage2&) = delete;
void operator=(const AlignedStorage2&) = delete;
};
} /* namespace mozilla */

View File

@ -12,6 +12,9 @@
#ifndef mozilla_AllocPolicy_h
#define mozilla_AllocPolicy_h
#include "mozilla/Attributes.h"
#include "mozilla/TemplateLib.h"
#include <stddef.h>
#include <stdlib.h>
@ -24,20 +27,38 @@ namespace mozilla {
* mechanism when OOM occurs. The concept modeled here is as follows:
*
* - public copy constructor, assignment, destructor
* - void* malloc_(size_t)
* - template <typename T> T* maybe_pod_malloc(size_t)
* Fallible, but doesn't report an error on OOM.
* - template <typename T> T* maybe_pod_calloc(size_t)
* Fallible, but doesn't report an error on OOM.
* - template <typename T> T* maybe_pod_realloc(T*, size_t, size_t)
* Fallible, but doesn't report an error on OOM. The old allocation
* size is passed in, in addition to the new allocation size requested.
* - template <typename T> T* pod_malloc(size_t)
* Responsible for OOM reporting when null is returned.
* - void* calloc_(size_t)
* - template <typename T> T* pod_calloc(size_t)
* Responsible for OOM reporting when null is returned.
* - void* realloc_(void*, size_t, size_t)
* Responsible for OOM reporting when null is returned. The *used* bytes
* of the previous buffer is passed in (rather than the old allocation
* size), in addition to the *new* allocation size requested.
* - template <typename T> T* pod_realloc(T*, size_t, size_t)
* Responsible for OOM reporting when null is returned. The old allocation
* size is passed in, in addition to the new allocation size requested.
* - void free_(void*)
* - void reportAllocOverflow() const
* Called on allocation overflow (that is, an allocation implicitly tried
* to allocate more than the available memory space -- think allocating an
* array of large-size objects, where N * size overflows) before null is
* returned.
* - bool checkSimulatedOOM() const
* Some clients generally allocate memory yet in some circumstances won't
* need to do so. For example, appending to a vector with a small amount of
* inline storage generally allocates memory, but no allocation occurs
* unless appending exceeds inline storage. But for testing purposes, it
* can be useful to treat *every* operation as allocating.
* Clients (such as this hypothetical append method implementation) should
* call this method in situations that don't allocate, but could generally,
* to support this. The default behavior should return true; more
* complicated behavior might be to return false only after a certain
* number of allocations-or-check-simulated-OOMs (coordinating with the
* other AllocPolicy methods) have occurred.
*
* mfbt provides (and typically uses by default) only MallocAllocPolicy, which
* does nothing more than delegate to the malloc/alloc/free functions.
@ -50,19 +71,46 @@ namespace mozilla {
class MallocAllocPolicy
{
public:
void* malloc_(size_t aBytes)
template <typename T>
T* maybe_pod_malloc(size_t aNumElems)
{
return malloc(aBytes);
if (aNumElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
return nullptr;
}
return static_cast<T*>(malloc(aNumElems * sizeof(T)));
}
void* calloc_(size_t aBytes)
template <typename T>
T* maybe_pod_calloc(size_t aNumElems)
{
return calloc(aBytes, 1);
return static_cast<T*>(calloc(aNumElems, sizeof(T)));
}
void* realloc_(void* aPtr, size_t aOldBytes, size_t aBytes)
template <typename T>
T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize)
{
return realloc(aPtr, aBytes);
if (aNewSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
return nullptr;
}
return static_cast<T*>(realloc(aPtr, aNewSize * sizeof(T)));
}
template <typename T>
T* pod_malloc(size_t aNumElems)
{
return maybe_pod_malloc<T>(aNumElems);
}
template <typename T>
T* pod_calloc(size_t aNumElems)
{
return maybe_pod_calloc<T>(aNumElems);
}
template <typename T>
T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize)
{
return maybe_pod_realloc<T>(aPtr, aOldSize, aNewSize);
}
void free_(void* aPtr)
@ -73,6 +121,11 @@ public:
void reportAllocOverflow() const
{
}
MOZ_MUST_USE bool checkSimulatedOOM() const
{
return true;
}
};
} // namespace mozilla

View File

@ -0,0 +1,147 @@
/* -*- 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/. */
/* Typed temporary pointers for reference-counted smart pointers. */
#ifndef AlreadyAddRefed_h
#define AlreadyAddRefed_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
namespace mozilla {
struct unused_t;
} // namespace mozilla
/**
* already_AddRefed cooperates with reference counting smart pointers to enable
* you to assign in a pointer _without_ |AddRef|ing it. You might want to use
* this as a return type from a function that returns an already |AddRef|ed
* pointer.
*
* TODO Move already_AddRefed to namespace mozilla. This has not yet been done
* because of the sheer number of usages of already_AddRefed.
*/
template<class T>
struct MOZ_MUST_USE_TYPE MOZ_NON_AUTOABLE already_AddRefed
{
/*
* We want to allow returning nullptr from functions returning
* already_AddRefed<T>, for simplicity. But we also don't want to allow
* returning raw T*, instead preferring creation of already_AddRefed<T> from
* a reference counting smart pointer.
*
* We address the latter requirement by making the (T*) constructor explicit.
* But |return nullptr| won't consider an explicit constructor, so we need
* another constructor to handle it. Plain old (decltype(nullptr)) doesn't
* cut it, because if nullptr is emulated as __null (with type int or long),
* passing nullptr to an int/long parameter triggers compiler warnings. We
* need a type that no one can pass accidentally; a pointer-to-member-function
* (where no such function exists) does the trick nicely.
*
* That handles the return-value case. What about for locals, argument types,
* and so on? |already_AddRefed<T>(nullptr)| considers both overloads (and
* the (already_AddRefed<T>&&) overload as well!), so there's an ambiguity.
* We can target true nullptr using decltype(nullptr), but we can't target
* emulated nullptr the same way, because passing __null to an int/long
* parameter triggers compiler warnings. So just give up on this, and provide
* this behavior through the default constructor.
*
* We can revert to simply explicit (T*) and implicit (decltype(nullptr)) when
* nullptr no longer needs to be emulated to support the ancient b2g compiler.
* (The () overload could also be removed, if desired, if we changed callers.)
*/
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) {}
explicit already_AddRefed(T* aRawPtr) : mRawPtr(aRawPtr) {}
// Disallow copy constructor and copy assignment operator: move semantics used instead.
already_AddRefed(const already_AddRefed<T>& aOther) = delete;
already_AddRefed<T>& operator=(const already_AddRefed<T>& aOther) = delete;
already_AddRefed(already_AddRefed<T>&& aOther) : mRawPtr(aOther.take()) {}
already_AddRefed<T>& operator=(already_AddRefed<T>&& aOther)
{
mRawPtr = aOther.take();
return *this;
}
/**
* This helper is useful in cases like
*
* already_AddRefed<BaseClass>
* Foo()
* {
* RefPtr<SubClass> x = ...;
* return x.forget();
* }
*
* The autoconversion allows one to omit the idiom
*
* RefPtr<BaseClass> y = x.forget();
* return y.forget();
*
* Note that nsRefPtr is the XPCOM reference counting smart pointer class.
*/
template <typename U>
MOZ_IMPLICIT already_AddRefed(already_AddRefed<U>&& aOther) : mRawPtr(aOther.take()) {}
~already_AddRefed() { MOZ_ASSERT(!mRawPtr); }
// Specialize the unused operator<< for already_AddRefed, to allow
// nsCOMPtr<nsIFoo> 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<T>& aRhs)
{
auto mutableAlreadyAddRefed = const_cast<already_AddRefed<T>*>(&aRhs);
aUnused << mutableAlreadyAddRefed->take();
}
MOZ_MUST_USE T* take()
{
T* rawPtr = mRawPtr;
mRawPtr = nullptr;
return rawPtr;
}
/**
* This helper provides a static_cast replacement for already_AddRefed, so
* if you have
*
* already_AddRefed<Parent> F();
*
* you can write
*
* already_AddRefed<Child>
* G()
* {
* return F().downcast<Child>();
* }
*/
template<class U>
already_AddRefed<U> downcast()
{
U* tmp = static_cast<U*>(mRawPtr);
mRawPtr = nullptr;
return already_AddRefed<U>(tmp);
}
private:
T* MOZ_OWNING_REF mRawPtr;
};
#endif // AlreadyAddRefed_h

33
android/arm64-v8a/include/spidermonkey/mozilla/Array.h Executable file → Normal file
View File

@ -11,6 +11,8 @@
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
#include "mozilla/ReverseIterator.h"
#include <stddef.h>
@ -22,6 +24,16 @@ class Array
T mArr[Length];
public:
Array() {}
template <typename... Args>
MOZ_IMPLICIT Array(Args&&... aArgs)
: mArr{mozilla::Forward<Args>(aArgs)...}
{
static_assert(sizeof...(aArgs) == Length,
"The number of arguments should be equal to the template parameter Length");
}
T& operator[](size_t aIndex)
{
MOZ_ASSERT(aIndex < Length);
@ -33,6 +45,27 @@ public:
MOZ_ASSERT(aIndex < Length);
return mArr[aIndex];
}
typedef T* iterator;
typedef const T* const_iterator;
typedef ReverseIterator<T*> reverse_iterator;
typedef ReverseIterator<const T*> const_reverse_iterator;
// Methods for range-based for loops.
iterator begin() { return mArr; }
const_iterator begin() const { return mArr; }
const_iterator cbegin() const { return begin(); }
iterator end() { return mArr + Length; }
const_iterator end() const { return mArr + Length; }
const_iterator cend() const { return end(); }
// Methods for reverse iterating.
reverse_iterator rbegin() { return 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 crend() const { return rend(); }
};
template<typename T>

View File

@ -20,15 +20,22 @@
#include "mozilla/Alignment.h"
#include "mozilla/Array.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/TypeTraits.h"
namespace mozilla {
/*
* Safely subtract two pointers when it is known that aEnd >= aBegin. This
* avoids the common compiler bug that if (size_t(aEnd) - size_t(aBegin)) has
* the MSB set, the unsigned subtraction followed by right shift will produce
* -1, or size_t(-1), instead of the real difference.
* Safely subtract two pointers when it is known that aEnd >= aBegin, yielding a
* size_t result.
*
* Ordinary pointer subtraction yields a ptrdiff_t result, which, being signed,
* has insufficient range to express the distance between pointers at opposite
* ends of the address space. Furthermore, most compilers use ptrdiff_t to
* represent the intermediate byte address distance, before dividing by
* sizeof(T); if that intermediate result overflows, they'll produce results
* with the wrong sign even when the correct scaled distance would fit in a
* ptrdiff_t.
*/
template<class T>
MOZ_ALWAYS_INLINE size_t
@ -45,40 +52,47 @@ PointerRangeSize(T* aBegin, T* aEnd)
* Beware of the implicit trailing '\0' when using this with string constants.
*/
template<typename T, size_t N>
MOZ_CONSTEXPR size_t
constexpr size_t
ArrayLength(T (&aArr)[N])
{
return N;
}
template<typename T, size_t N>
MOZ_CONSTEXPR size_t
constexpr size_t
ArrayLength(const Array<T, N>& aArr)
{
return N;
}
template<typename E, E N, typename T>
constexpr size_t
ArrayLength(const EnumeratedArray<E, N, T>& aArr)
{
return size_t(N);
}
/*
* Compute the address one past the last element of a constant-length array.
*
* Beware of the implicit trailing '\0' when using this with string constants.
*/
template<typename T, size_t N>
MOZ_CONSTEXPR T*
constexpr T*
ArrayEnd(T (&aArr)[N])
{
return aArr + ArrayLength(aArr);
}
template<typename T, size_t N>
MOZ_CONSTEXPR T*
constexpr T*
ArrayEnd(Array<T, N>& aArr)
{
return &aArr[0] + ArrayLength(aArr);
}
template<typename T, size_t N>
MOZ_CONSTEXPR const T*
constexpr const T*
ArrayEnd(const Array<T, N>& aArr)
{
return &aArr[0] + ArrayLength(aArr);
@ -86,22 +100,23 @@ ArrayEnd(const Array<T, N>& aArr)
namespace detail {
template<typename AlignType, typename Pointee>
template<typename AlignType, typename Pointee,
typename = EnableIf<!IsVoid<AlignType>::value>>
struct AlignedChecker
{
static void
test(Pointee* aPtr)
test(const Pointee* aPtr)
{
MOZ_ASSERT((uintptr_t(aPtr) % MOZ_ALIGNOF(AlignType)) == 0,
"performing a range-check with a misaligned pointer");
}
};
template<typename Pointee>
struct AlignedChecker<void, Pointee>
template<typename AlignType, typename Pointee>
struct AlignedChecker<AlignType, Pointee>
{
static void
test(Pointee* aPtr)
test(const Pointee* aPtr)
{
}
};
@ -126,13 +141,14 @@ inline typename EnableIf<IsSame<T, U>::value ||
IsBaseOf<T, U>::value ||
IsVoid<T>::value,
bool>::Type
IsInRange(T* aPtr, U* aBegin, U* aEnd)
IsInRange(const T* aPtr, const U* aBegin, const U* aEnd)
{
MOZ_ASSERT(aBegin <= aEnd);
detail::AlignedChecker<U, T>::test(aPtr);
detail::AlignedChecker<U, U>::test(aBegin);
detail::AlignedChecker<U, U>::test(aEnd);
return aBegin <= static_cast<U*>(aPtr) && static_cast<U*>(aPtr) < aEnd;
return aBegin <= reinterpret_cast<const U*>(aPtr) &&
reinterpret_cast<const U*>(aPtr) < aEnd;
}
/**
@ -142,10 +158,11 @@ IsInRange(T* aPtr, U* aBegin, U* aEnd)
*/
template<typename T>
inline bool
IsInRange(T* aPtr, uintptr_t aBegin, uintptr_t aEnd)
IsInRange(const T* aPtr, uintptr_t aBegin, uintptr_t aEnd)
{
return IsInRange(aPtr,
reinterpret_cast<T*>(aBegin), reinterpret_cast<T*>(aEnd));
reinterpret_cast<const T*>(aBegin),
reinterpret_cast<const T*>(aEnd));
}
namespace detail {

View File

@ -17,10 +17,33 @@
#include "mozilla/Compiler.h"
#include "mozilla/Likely.h"
#include "mozilla/MacroArgs.h"
#include "mozilla/StaticAnalysisFunctions.h"
#include "mozilla/Types.h"
#ifdef MOZ_DUMP_ASSERTION_STACK
#include "nsTraceRefcnt.h"
#endif
#if defined(MOZ_HAS_MOZGLUE) || defined(MOZILLA_INTERNAL_API)
/*
* The crash reason set by MOZ_CRASH_ANNOTATE is consumed by the crash reporter
* if present. It is declared here (and defined in Assertions.cpp) to make it
* available to all code, even libraries that don't link with the crash reporter
* directly.
*/
MOZ_BEGIN_EXTERN_C
extern MFBT_DATA const char* gMozCrashReason;
MOZ_END_EXTERN_C
static inline void
AnnotateMozCrashReason(const char* reason)
{
gMozCrashReason = reason;
}
# define MOZ_CRASH_ANNOTATE(...) AnnotateMozCrashReason(__VA_ARGS__)
#else
# define MOZ_CRASH_ANNOTATE(...) do { /* nothing */ } while (0)
#endif
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@ -131,7 +154,7 @@ extern "C" {
* method is primarily for internal use in this header, and only secondarily
* for use in implementing release-build assertions.
*/
static MOZ_ALWAYS_INLINE void
static MOZ_COLD MOZ_ALWAYS_INLINE void
MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, int aLine)
MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
{
@ -141,14 +164,14 @@ MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, int aLine)
aStr, aFilename, aLine);
#else
fprintf(stderr, "Assertion failure: %s, at %s:%d\n", aStr, aFilename, aLine);
#ifdef MOZ_DUMP_ASSERTION_STACK
#if defined (MOZ_DUMP_ASSERTION_STACK)
nsTraceRefcnt::WalkTheStack(stderr);
#endif
fflush(stderr);
#endif
}
static MOZ_ALWAYS_INLINE void
static MOZ_COLD MOZ_ALWAYS_INLINE void
MOZ_ReportCrash(const char* aStr, const char* aFilename, int aLine)
MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
{
@ -157,7 +180,7 @@ MOZ_ReportCrash(const char* aStr, const char* aFilename, int aLine)
"Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine);
#else
fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine);
#ifdef MOZ_DUMP_ASSERTION_STACK
#if defined(MOZ_DUMP_ASSERTION_STACK)
nsTraceRefcnt::WalkTheStack(stderr);
#endif
fflush(stderr);
@ -198,7 +221,7 @@ __declspec(noreturn) __inline void MOZ_NoReturn() {}
# define MOZ_REALLY_CRASH() \
do { \
::__debugbreak(); \
*((volatile int*) NULL) = 123; \
*((volatile int*) NULL) = __LINE__; \
::TerminateProcess(::GetCurrentProcess(), 3); \
::MOZ_NoReturn(); \
} while (0)
@ -206,7 +229,7 @@ __declspec(noreturn) __inline void MOZ_NoReturn() {}
# define MOZ_REALLY_CRASH() \
do { \
__debugbreak(); \
*((volatile int*) NULL) = 123; \
*((volatile int*) NULL) = __LINE__; \
TerminateProcess(GetCurrentProcess(), 3); \
MOZ_NoReturn(); \
} while (0)
@ -215,13 +238,13 @@ __declspec(noreturn) __inline void MOZ_NoReturn() {}
# ifdef __cplusplus
# define MOZ_REALLY_CRASH() \
do { \
*((volatile int*) NULL) = 123; \
*((volatile int*) NULL) = __LINE__; \
::abort(); \
} while (0)
# else
# define MOZ_REALLY_CRASH() \
do { \
*((volatile int*) NULL) = 123; \
*((volatile int*) NULL) = __LINE__; \
abort(); \
} while (0)
# endif
@ -249,11 +272,16 @@ __declspec(noreturn) __inline void MOZ_NoReturn() {}
* corrupted.
*/
#ifndef DEBUG
# define MOZ_CRASH(...) MOZ_REALLY_CRASH()
# define MOZ_CRASH(...) \
do { \
MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \
MOZ_REALLY_CRASH(); \
} while (0)
#else
# define MOZ_CRASH(...) \
do { \
MOZ_ReportCrash("" __VA_ARGS__, __FILE__, __LINE__); \
MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \
MOZ_REALLY_CRASH(); \
} while (0)
#endif
@ -294,6 +322,13 @@ __declspec(noreturn) __inline void MOZ_NoReturn() {}
* MOZ_ASSERT has no effect in non-debug builds. It is designed to catch bugs
* *only* during debugging, not "in the field". If you want the latter, use
* MOZ_RELEASE_ASSERT, which applies to non-debug builds as well.
*
* MOZ_DIAGNOSTIC_ASSERT works like MOZ_RELEASE_ASSERT in Nightly/Aurora and
* MOZ_ASSERT in Beta/Release - use this when a condition is potentially rare
* enough to require real user testing to hit, but is not security-sensitive.
* 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.
*/
/*
@ -302,37 +337,12 @@ __declspec(noreturn) __inline void MOZ_NoReturn() {}
*/
#ifdef __cplusplus
# if defined(__clang__)
# define MOZ_SUPPORT_ASSERT_CONDITION_TYPE_VALIDATION
# elif defined(__GNUC__)
// B2G GCC 4.4 has insufficient decltype support.
# if MOZ_GCC_VERSION_AT_LEAST(4, 5, 0)
# define MOZ_SUPPORT_ASSERT_CONDITION_TYPE_VALIDATION
# endif
# elif defined(_MSC_VER)
// Disabled for now because of insufficient decltype support. Bug 1004028.
# endif
#endif
#ifdef MOZ_SUPPORT_ASSERT_CONDITION_TYPE_VALIDATION
# include "mozilla/TypeTraits.h"
namespace mozilla {
namespace detail {
template<typename T>
struct IsFunction
{
static const bool value = false;
};
template<typename R, typename... A>
struct IsFunction<R(A...)>
{
static const bool value = true;
};
template<typename T>
void ValidateAssertConditionType()
struct AssertionConditionType
{
typedef typename RemoveReference<T>::Type ValueT;
static_assert(!IsArray<ValueT>::value,
@ -347,12 +357,15 @@ void ValidateAssertConditionType()
"fail. Shouldn't your code gracefully handle this case instead "
"of asserting? Anyway, if you really want to do that, write an "
"explicit boolean condition, like !!x or x!=0.");
}
static const bool isValid = true;
};
} // namespace detail
} // namespace mozilla
# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) \
mozilla::detail::ValidateAssertConditionType<decltype(x)>()
static_assert(mozilla::detail::AssertionConditionType<decltype(x)>::isValid, \
"invalid assertion condition")
#else
# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x)
#endif
@ -361,8 +374,9 @@ void ValidateAssertConditionType()
#define MOZ_ASSERT_HELPER1(expr) \
do { \
MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
if (MOZ_UNLIKELY(!(expr))) { \
if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \
MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \
MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ")"); \
MOZ_REALLY_CRASH(); \
} \
} while (0)
@ -370,8 +384,9 @@ void ValidateAssertConditionType()
#define MOZ_ASSERT_HELPER2(expr, explain) \
do { \
MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
if (MOZ_UNLIKELY(!(expr))) { \
if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \
MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \
MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ") (" explain ")"); \
MOZ_REALLY_CRASH(); \
} \
} while (0)
@ -388,14 +403,10 @@ void ValidateAssertConditionType()
# define MOZ_ASSERT(...) do { } while (0)
#endif /* DEBUG */
/*
* MOZ_NIGHTLY_ASSERT is defined for both debug and release builds on the
* Nightly channel, but only debug builds on Aurora, Beta, and Release.
*/
#if defined(NIGHTLY_BUILD)
# define MOZ_NIGHTLY_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__)
#ifdef RELEASE_OR_BETA
# define MOZ_DIAGNOSTIC_ASSERT MOZ_ASSERT
#else
# define MOZ_NIGHTLY_ASSERT(...) MOZ_ASSERT(__VA_ARGS__)
# define MOZ_DIAGNOSTIC_ASSERT MOZ_RELEASE_ASSERT
#endif
/*
@ -425,23 +436,8 @@ void ValidateAssertConditionType()
* should use MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE because it has extra
* asserts.
*/
#if defined(__clang__)
#if defined(__clang__) || defined(__GNUC__)
# define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable()
#elif defined(__GNUC__)
/*
* __builtin_unreachable() was implemented in gcc 4.5. If we don't have
* that, call a noreturn function; abort() will do nicely. Qualify the call
* in C++ in case there's another abort() visible in local scope.
*/
# if MOZ_GCC_VERSION_AT_LEAST(4, 5, 0)
# define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable()
# else
# ifdef __cplusplus
# define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort()
# else
# define MOZ_ASSUME_UNREACHABLE_MARKER() abort()
# endif
# endif
#elif defined(_MSC_VER)
# define MOZ_ASSUME_UNREACHABLE_MARKER() __assume(0)
#else
@ -494,12 +490,11 @@ void ValidateAssertConditionType()
*/
/*
* Assert in all debug builds plus the Nightly channel's release builds. Take
* this extra testing precaution because hitting MOZ_ASSUME_UNREACHABLE_MARKER
* could trigger exploitable undefined behavior.
* Unconditional assert in debug builds for (assumed) unreachable code paths
* that have a safe return without crashing in release builds.
*/
#define MOZ_ASSERT_UNREACHABLE(reason) \
MOZ_NIGHTLY_ASSERT(false, "MOZ_ASSERT_UNREACHABLE: " reason)
MOZ_ASSERT(false, "MOZ_ASSERT_UNREACHABLE: " reason)
#define MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(reason) \
do { \
@ -507,13 +502,44 @@ void ValidateAssertConditionType()
MOZ_ASSUME_UNREACHABLE_MARKER(); \
} while (0)
/*
* TODO: Bug 990764: Audit all MOZ_ASSUME_UNREACHABLE calls and replace them
* with MOZ_ASSERT_UNREACHABLE, MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE, or
* MOZ_CRASH. For now, preserve the macro's same meaning of unreachable.
/**
* MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about
* switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in
* debug builds, but intentionally fall through in release builds to handle
* unexpected values.
*
* Why do we need MOZ_FALLTHROUGH_ASSERT in addition to MOZ_FALLTHROUGH? In
* release builds, the MOZ_ASSERT(false) will expand to `do { } while (0)`,
* requiring a MOZ_FALLTHROUGH annotation to suppress a -Wimplicit-fallthrough
* warning. In debug builds, the MOZ_ASSERT(false) will expand to something like
* `if (true) { MOZ_CRASH(); }` and the MOZ_FALLTHROUGH annotation will cause
* a -Wunreachable-code warning. The MOZ_FALLTHROUGH_ASSERT macro breaks this
* warning stalemate.
*
* // Example before MOZ_FALLTHROUGH_ASSERT:
* switch (foo) {
* default:
* // This case wants to assert in debug builds, fall through in release.
* MOZ_ASSERT(false); // -Wimplicit-fallthrough warning in release builds!
* MOZ_FALLTHROUGH; // but -Wunreachable-code warning in debug builds!
* case 5:
* return 5;
* }
*
* // Example with MOZ_FALLTHROUGH_ASSERT:
* switch (foo) {
* default:
* // This case asserts in debug builds, falls through in release.
* MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!");
* case 5:
* return 5;
* }
*/
#define MOZ_ASSUME_UNREACHABLE(reason) \
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(reason)
#ifdef DEBUG
# define MOZ_FALLTHROUGH_ASSERT(reason) MOZ_CRASH("MOZ_FALLTHROUGH_ASSERT: " reason)
#else
# define MOZ_FALLTHROUGH_ASSERT(...) MOZ_FALLTHROUGH
#endif
/*
* MOZ_ALWAYS_TRUE(expr) and MOZ_ALWAYS_FALSE(expr) always evaluate the provided
@ -522,13 +548,38 @@ void ValidateAssertConditionType()
* using MOZ_ASSERT.
*/
#ifdef DEBUG
# define MOZ_ALWAYS_TRUE(expr) MOZ_ASSERT((expr))
# define MOZ_ALWAYS_FALSE(expr) MOZ_ASSERT(!(expr))
# define MOZ_ALWAYS_TRUE(expr) \
do { \
if ((expr)) { \
/* Do nothing. */ \
} else { \
MOZ_ASSERT(false, #expr); \
} \
} while (0)
# define MOZ_ALWAYS_FALSE(expr) \
do { \
if ((expr)) { \
MOZ_ASSERT(false, #expr); \
} else { \
/* Do nothing. */ \
} \
} while (0)
#else
# define MOZ_ALWAYS_TRUE(expr) ((void)(expr))
# define MOZ_ALWAYS_FALSE(expr) ((void)(expr))
# 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)
#endif
#undef MOZ_DUMP_ASSERTION_STACK
#undef MOZ_CRASH_CRASHREPORT
#endif /* mozilla_Assertions_h */

557
android/arm64-v8a/include/spidermonkey/mozilla/Atomics.h Executable file → Normal file
View File

@ -28,27 +28,22 @@
* does not have <atomic>. So be sure to check for <atomic> support
* along with C++0x support.
*/
#if defined(__clang__) || defined(__GNUC__)
#if defined(_MSC_VER)
# define MOZ_HAVE_CXX11_ATOMICS
#elif defined(__clang__) || defined(__GNUC__)
/*
* Clang doesn't like <atomic> 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++ <atomic> 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
# elif MOZ_USING_LIBCXX && defined(__clang__)
# define MOZ_HAVE_CXX11_ATOMICS
# endif
#elif defined(_MSC_VER) && _MSC_VER >= 1700
# if defined(DEBUG)
/*
* Provide our own failure code since we're having trouble linking to
* std::_Debug_message (bug 982310).
*/
# define _INVALID_MEMORY_ORDER MOZ_CRASH("Invalid memory order")
# endif
# define MOZ_HAVE_CXX11_ATOMICS
#endif
namespace mozilla {
@ -272,29 +267,12 @@ struct IntrinsicAddSub<T*, Order> : public IntrinsicBase<T*, Order>
static T* add(typename Base::ValueType& aPtr, ptrdiff_t aVal)
{
return aPtr.fetch_add(fixupAddend(aVal), Base::OrderedOp::AtomicRMWOrder);
return aPtr.fetch_add(aVal, Base::OrderedOp::AtomicRMWOrder);
}
static T* sub(typename Base::ValueType& aPtr, ptrdiff_t aVal)
{
return aPtr.fetch_sub(fixupAddend(aVal), Base::OrderedOp::AtomicRMWOrder);
}
private:
/*
* GCC 4.6's <atomic> header has a bug where adding X to an
* atomic<T*> is not the same as adding X to a T*. Hence the need
* for this function to provide the correct addend.
*/
static ptrdiff_t fixupAddend(ptrdiff_t aVal)
{
#if defined(__clang__) || defined(_MSC_VER)
return aVal;
#elif defined(__GNUC__) && MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) && \
!MOZ_GCC_VERSION_AT_LEAST(4, 7, 0)
return aVal * sizeof(T);
#else
return aVal;
#endif
return aPtr.fetch_sub(aVal, Base::OrderedOp::AtomicRMWOrder);
}
};
@ -342,6 +320,12 @@ struct AtomicIntrinsics<T*, Order>
{
};
template<typename T>
struct ToStorageTypeArgument
{
static constexpr T convert (T aT) { return aT; }
};
} // namespace detail
} // namespace mozilla
@ -406,60 +390,81 @@ struct Barrier<SequentiallyConsistent>
static void afterStore() { __sync_synchronize(); }
};
template<typename T, bool TIsEnum = IsEnum<T>::value>
struct AtomicStorageType
{
// For non-enums, just use the type directly.
typedef T Type;
};
template<typename T>
struct AtomicStorageType<T, true>
: Conditional<sizeof(T) == 4, uint32_t, uint64_t>
{
static_assert(sizeof(T) == 4 || sizeof(T) == 8,
"wrong type computed in conditional above");
};
template<typename T, MemoryOrdering Order>
struct IntrinsicMemoryOps
{
static T load(const T& aPtr)
typedef typename AtomicStorageType<T>::Type ValueType;
static T load(const ValueType& aPtr)
{
Barrier<Order>::beforeLoad();
T val = aPtr;
T val = T(aPtr);
Barrier<Order>::afterLoad();
return val;
}
static void store(T& aPtr, T aVal)
static void store(ValueType& aPtr, T aVal)
{
Barrier<Order>::beforeStore();
aPtr = aVal;
aPtr = ValueType(aVal);
Barrier<Order>::afterStore();
}
static T exchange(T& aPtr, T aVal)
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<Order>::beforeStore();
return __sync_lock_test_and_set(&aPtr, aVal);
return T(__sync_lock_test_and_set(&aPtr, ValueType(aVal)));
}
static bool compareExchange(T& aPtr, T aOldVal, T aNewVal)
static bool compareExchange(ValueType& aPtr, T aOldVal, T aNewVal)
{
return __sync_bool_compare_and_swap(&aPtr, aOldVal, aNewVal);
return __sync_bool_compare_and_swap(&aPtr, ValueType(aOldVal), ValueType(aNewVal));
}
};
template<typename T>
template<typename T, MemoryOrdering Order>
struct IntrinsicAddSub
: public IntrinsicMemoryOps<T, Order>
{
typedef T ValueType;
typedef IntrinsicMemoryOps<T, Order> Base;
typedef typename Base::ValueType ValueType;
static T add(T& aPtr, T aVal)
static T add(ValueType& aPtr, T aVal)
{
return __sync_fetch_and_add(&aPtr, aVal);
return T(__sync_fetch_and_add(&aPtr, ValueType(aVal)));
}
static T sub(T& aPtr, T aVal)
static T sub(ValueType& aPtr, T aVal)
{
return __sync_fetch_and_sub(&aPtr, aVal);
return T(__sync_fetch_and_sub(&aPtr, ValueType(aVal)));
}
};
template<typename T>
struct IntrinsicAddSub<T*>
template<typename T, MemoryOrdering Order>
struct IntrinsicAddSub<T*, Order>
: public IntrinsicMemoryOps<T*, Order>
{
typedef T* ValueType;
typedef IntrinsicMemoryOps<T*, Order> Base;
typedef typename Base::ValueType ValueType;
/*
* The reinterpret_casts are needed so that
@ -481,16 +486,18 @@ struct IntrinsicAddSub<T*>
}
};
template<typename T>
struct IntrinsicIncDec : public IntrinsicAddSub<T>
template<typename T, MemoryOrdering Order>
struct IntrinsicIncDec : public IntrinsicAddSub<T, Order>
{
static T inc(T& aPtr) { return IntrinsicAddSub<T>::add(aPtr, 1); }
static T dec(T& aPtr) { return IntrinsicAddSub<T>::sub(aPtr, 1); }
typedef IntrinsicAddSub<T, Order> Base;
typedef typename Base::ValueType ValueType;
static T inc(ValueType& aPtr) { return Base::add(aPtr, 1); }
static T dec(ValueType& aPtr) { return Base::sub(aPtr, 1); }
};
template<typename T, MemoryOrdering Order>
struct AtomicIntrinsics : public IntrinsicMemoryOps<T, Order>,
public IntrinsicIncDec<T>
struct AtomicIntrinsics : public IntrinsicIncDec<T, Order>
{
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); }
@ -498,401 +505,22 @@ struct AtomicIntrinsics : public IntrinsicMemoryOps<T, Order>,
};
template<typename T, MemoryOrdering Order>
struct AtomicIntrinsics<T*, Order> : public IntrinsicMemoryOps<T*, Order>,
public IntrinsicIncDec<T*>
struct AtomicIntrinsics<T*, Order> : public IntrinsicIncDec<T*, Order>
{
};
} // namespace detail
} // namespace mozilla
#elif defined(_MSC_VER)
/*
* Windows comes with a full complement of atomic operations.
* Unfortunately, most of those aren't available for Windows XP (even if
* the compiler supports intrinsics for them), which is the oldest
* version of Windows we support. Therefore, we only provide operations
* on 32-bit datatypes for 32-bit Windows versions; for 64-bit Windows
* versions, we support 64-bit datatypes as well.
*/
# include <intrin.h>
# pragma intrinsic(_InterlockedExchangeAdd)
# pragma intrinsic(_InterlockedOr)
# pragma intrinsic(_InterlockedXor)
# pragma intrinsic(_InterlockedAnd)
# pragma intrinsic(_InterlockedExchange)
# pragma intrinsic(_InterlockedCompareExchange)
namespace mozilla {
namespace detail {
# if !defined(_M_IX86) && !defined(_M_X64)
/*
* The implementations below are optimized for x86ish systems. You
* will have to modify them if you are porting to Windows on a
* different architecture.
*/
# error "Unknown CPU type"
# endif
/*
* The PrimitiveIntrinsics template should define |Type|, the datatype of size
* DataSize upon which we operate, and the following eight functions.
*
* static Type add(Type* aPtr, Type aVal);
* static Type sub(Type* aPtr, Type aVal);
* static Type or_(Type* aPtr, Type aVal);
* static Type xor_(Type* aPtr, Type aVal);
* static Type and_(Type* aPtr, Type aVal);
*
* These functions perform the obvious operation on the value contained in
* |*aPtr| combined with |aVal| and return the value previously stored in
* |*aPtr|.
*
* static void store(Type* aPtr, Type aVal);
*
* This function atomically stores |aVal| into |*aPtr| and must provide a full
* memory fence after the store to prevent compiler and hardware instruction
* reordering. It should also act as a compiler barrier to prevent reads and
* writes from moving to after the store.
*
* static Type exchange(Type* aPtr, Type aVal);
*
* This function atomically stores |aVal| into |*aPtr| and returns the
* previous contents of |*aPtr|;
*
* static bool compareExchange(Type* aPtr, Type aOldVal, Type aNewVal);
*
* This function atomically performs the following operation:
*
* if (*aPtr == aOldVal) {
* *aPtr = aNewVal;
* return true;
* } else {
* return false;
* }
*
*/
template<size_t DataSize> struct PrimitiveIntrinsics;
template<>
struct PrimitiveIntrinsics<4>
template<typename T, bool TIsEnum = IsEnum<T>::value>
struct ToStorageTypeArgument
{
typedef long Type;
typedef typename AtomicStorageType<T>::Type ResultType;
static Type add(Type* aPtr, Type aVal)
{
return _InterlockedExchangeAdd(aPtr, aVal);
}
static Type sub(Type* aPtr, Type aVal)
{
/*
* _InterlockedExchangeSubtract isn't available before Windows 7,
* and we must support Windows XP.
*/
return _InterlockedExchangeAdd(aPtr, -aVal);
}
static Type or_(Type* aPtr, Type aVal)
{
return _InterlockedOr(aPtr, aVal);
}
static Type xor_(Type* aPtr, Type aVal)
{
return _InterlockedXor(aPtr, aVal);
}
static Type and_(Type* aPtr, Type aVal)
{
return _InterlockedAnd(aPtr, aVal);
}
static void store(Type* aPtr, Type aVal)
{
_InterlockedExchange(aPtr, aVal);
}
static Type exchange(Type* aPtr, Type aVal)
{
return _InterlockedExchange(aPtr, aVal);
}
static bool compareExchange(Type* aPtr, Type aOldVal, Type aNewVal)
{
return _InterlockedCompareExchange(aPtr, aNewVal, aOldVal) == aOldVal;
}
};
# if defined(_M_X64)
# pragma intrinsic(_InterlockedExchangeAdd64)
# pragma intrinsic(_InterlockedOr64)
# pragma intrinsic(_InterlockedXor64)
# pragma intrinsic(_InterlockedAnd64)
# pragma intrinsic(_InterlockedExchange64)
# pragma intrinsic(_InterlockedCompareExchange64)
template <>
struct PrimitiveIntrinsics<8>
{
typedef __int64 Type;
static Type add(Type* aPtr, Type aVal)
{
return _InterlockedExchangeAdd64(aPtr, aVal);
}
static Type sub(Type* aPtr, Type aVal)
{
/*
* There is no _InterlockedExchangeSubtract64.
*/
return _InterlockedExchangeAdd64(aPtr, -aVal);
}
static Type or_(Type* aPtr, Type aVal)
{
return _InterlockedOr64(aPtr, aVal);
}
static Type xor_(Type* aPtr, Type aVal)
{
return _InterlockedXor64(aPtr, aVal);
}
static Type and_(Type* aPtr, Type aVal)
{
return _InterlockedAnd64(aPtr, aVal);
}
static void store(Type* aPtr, Type aVal)
{
_InterlockedExchange64(aPtr, aVal);
}
static Type exchange(Type* aPtr, Type aVal)
{
return _InterlockedExchange64(aPtr, aVal);
}
static bool compareExchange(Type* aPtr, Type aOldVal, Type aNewVal)
{
return _InterlockedCompareExchange64(aPtr, aNewVal, aOldVal) == aOldVal;
}
};
# endif
# pragma intrinsic(_ReadWriteBarrier)
template<MemoryOrdering Order> struct Barrier;
/*
* We do not provide an afterStore method in Barrier, as Relaxed and
* ReleaseAcquire orderings do not require one, and the required barrier
* for SequentiallyConsistent is handled by PrimitiveIntrinsics.
*/
template<>
struct Barrier<Relaxed>
{
static void beforeLoad() {}
static void afterLoad() {}
static void beforeStore() {}
};
template<>
struct Barrier<ReleaseAcquire>
{
static void beforeLoad() {}
static void afterLoad() { _ReadWriteBarrier(); }
static void beforeStore() { _ReadWriteBarrier(); }
};
template<>
struct Barrier<SequentiallyConsistent>
{
static void beforeLoad() { _ReadWriteBarrier(); }
static void afterLoad() { _ReadWriteBarrier(); }
static void beforeStore() { _ReadWriteBarrier(); }
};
template<typename PrimType, typename T>
struct CastHelper
{
static PrimType toPrimType(T aVal) { return static_cast<PrimType>(aVal); }
static T fromPrimType(PrimType aVal) { return static_cast<T>(aVal); }
};
template<typename PrimType, typename T>
struct CastHelper<PrimType, T*>
{
static PrimType toPrimType(T* aVal) { return reinterpret_cast<PrimType>(aVal); }
static T* fromPrimType(PrimType aVal) { return reinterpret_cast<T*>(aVal); }
static constexpr ResultType convert (T aT) { return ResultType(aT); }
};
template<typename T>
struct IntrinsicBase
struct ToStorageTypeArgument<T, false>
{
typedef T ValueType;
typedef PrimitiveIntrinsics<sizeof(T)> Primitives;
typedef typename Primitives::Type PrimType;
static_assert(sizeof(PrimType) == sizeof(T),
"Selection of PrimitiveIntrinsics was wrong");
typedef CastHelper<PrimType, T> Cast;
};
template<typename T, MemoryOrdering Order>
struct IntrinsicMemoryOps : public IntrinsicBase<T>
{
typedef typename IntrinsicBase<T>::ValueType ValueType;
typedef typename IntrinsicBase<T>::Primitives Primitives;
typedef typename IntrinsicBase<T>::PrimType PrimType;
typedef typename IntrinsicBase<T>::Cast Cast;
static ValueType load(const ValueType& aPtr)
{
Barrier<Order>::beforeLoad();
ValueType val = aPtr;
Barrier<Order>::afterLoad();
return val;
}
static void store(ValueType& aPtr, ValueType aVal)
{
// For SequentiallyConsistent, Primitives::store() will generate the
// proper memory fence. Everything else just needs a barrier before
// the store.
if (Order == SequentiallyConsistent) {
Primitives::store(reinterpret_cast<PrimType*>(&aPtr),
Cast::toPrimType(aVal));
} else {
Barrier<Order>::beforeStore();
aPtr = aVal;
}
}
static ValueType exchange(ValueType& aPtr, ValueType aVal)
{
PrimType oldval =
Primitives::exchange(reinterpret_cast<PrimType*>(&aPtr),
Cast::toPrimType(aVal));
return Cast::fromPrimType(oldval);
}
static bool compareExchange(ValueType& aPtr, ValueType aOldVal,
ValueType aNewVal)
{
return Primitives::compareExchange(reinterpret_cast<PrimType*>(&aPtr),
Cast::toPrimType(aOldVal),
Cast::toPrimType(aNewVal));
}
};
template<typename T>
struct IntrinsicApplyHelper : public IntrinsicBase<T>
{
typedef typename IntrinsicBase<T>::ValueType ValueType;
typedef typename IntrinsicBase<T>::PrimType PrimType;
typedef typename IntrinsicBase<T>::Cast Cast;
typedef PrimType (*BinaryOp)(PrimType*, PrimType);
typedef PrimType (*UnaryOp)(PrimType*);
static ValueType applyBinaryFunction(BinaryOp aOp, ValueType& aPtr,
ValueType aVal)
{
PrimType* primTypePtr = reinterpret_cast<PrimType*>(&aPtr);
PrimType primTypeVal = Cast::toPrimType(aVal);
return Cast::fromPrimType(aOp(primTypePtr, primTypeVal));
}
static ValueType applyUnaryFunction(UnaryOp aOp, ValueType& aPtr)
{
PrimType* primTypePtr = reinterpret_cast<PrimType*>(&aPtr);
return Cast::fromPrimType(aOp(primTypePtr));
}
};
template<typename T>
struct IntrinsicAddSub : public IntrinsicApplyHelper<T>
{
typedef typename IntrinsicApplyHelper<T>::ValueType ValueType;
typedef typename IntrinsicBase<T>::Primitives Primitives;
static ValueType add(ValueType& aPtr, ValueType aVal)
{
return applyBinaryFunction(&Primitives::add, aPtr, aVal);
}
static ValueType sub(ValueType& aPtr, ValueType aVal)
{
return applyBinaryFunction(&Primitives::sub, aPtr, aVal);
}
};
template<typename T>
struct IntrinsicAddSub<T*> : public IntrinsicApplyHelper<T*>
{
typedef typename IntrinsicApplyHelper<T*>::ValueType ValueType;
typedef typename IntrinsicBase<T*>::Primitives Primitives;
static ValueType add(ValueType& aPtr, ptrdiff_t aAmount)
{
return applyBinaryFunction(&Primitives::add, aPtr,
(ValueType)(aAmount * sizeof(T)));
}
static ValueType sub(ValueType& aPtr, ptrdiff_t aAmount)
{
return applyBinaryFunction(&Primitives::sub, aPtr,
(ValueType)(aAmount * sizeof(T)));
}
};
template<typename T>
struct IntrinsicIncDec : public IntrinsicAddSub<T>
{
typedef typename IntrinsicAddSub<T>::ValueType ValueType;
static ValueType inc(ValueType& aPtr) { return add(aPtr, 1); }
static ValueType dec(ValueType& aPtr) { return sub(aPtr, 1); }
};
template<typename T, MemoryOrdering Order>
struct AtomicIntrinsics : public IntrinsicMemoryOps<T, Order>,
public IntrinsicIncDec<T>
{
typedef typename IntrinsicIncDec<T>::ValueType ValueType;
typedef typename IntrinsicBase<T>::Primitives Primitives;
static ValueType or_(ValueType& aPtr, T aVal)
{
return applyBinaryFunction(&Primitives::or_, aPtr, aVal);
}
static ValueType xor_(ValueType& aPtr, T aVal)
{
return applyBinaryFunction(&Primitives::xor_, aPtr, aVal);
}
static ValueType and_(ValueType& aPtr, T aVal)
{
return applyBinaryFunction(&Primitives::and_, aPtr, aVal);
}
};
template<typename T, MemoryOrdering Order>
struct AtomicIntrinsics<T*, Order> : public IntrinsicMemoryOps<T*, Order>,
public IntrinsicIncDec<T*>
{
typedef typename IntrinsicMemoryOps<T*, Order>::ValueType ValueType;
// This is required to make us be able to build with MSVC10, for unknown
// reasons.
typedef typename IntrinsicBase<T*>::Primitives Primitives;
static constexpr T convert (T aT) { return aT; }
};
} // namespace detail
@ -909,18 +537,19 @@ namespace detail {
template<typename T, MemoryOrdering Order>
class AtomicBase
{
// We only support 32-bit types on 32-bit Windows, which constrains our
// implementation elsewhere. But we support pointer-sized types everywhere.
static_assert(sizeof(T) == 4 || (sizeof(uintptr_t) == 8 && sizeof(T) == 8),
"mozilla/Atomics.h only supports 32-bit and pointer-sized types");
static_assert(sizeof(T) == 4 || sizeof(T) == 8,
"mozilla/Atomics.h only supports 32-bit and 64-bit types");
protected:
typedef typename detail::AtomicIntrinsics<T, Order> Intrinsics;
typename Intrinsics::ValueType mValue;
typedef typename Intrinsics::ValueType ValueType;
ValueType mValue;
public:
MOZ_CONSTEXPR AtomicBase() : mValue() {}
explicit MOZ_CONSTEXPR AtomicBase(T aInit) : mValue(aInit) {}
constexpr AtomicBase() : mValue() {}
explicit constexpr AtomicBase(T aInit)
: mValue(ToStorageTypeArgument<T>::convert(aInit))
{}
// Note: we can't provide operator T() here because Atomic<bool> inherits
// from AtomcBase with T=uint32_t and not T=bool. If we implemented
@ -960,7 +589,7 @@ public:
private:
template<MemoryOrdering AnyOrder>
AtomicBase(const AtomicBase<T, AnyOrder>& aCopy) MOZ_DELETE;
AtomicBase(const AtomicBase<T, AnyOrder>& aCopy) = delete;
};
template<typename T, MemoryOrdering Order>
@ -969,8 +598,8 @@ class AtomicBaseIncDec : public AtomicBase<T, Order>
typedef typename detail::AtomicBase<T, Order> Base;
public:
MOZ_CONSTEXPR AtomicBaseIncDec() : Base() {}
explicit MOZ_CONSTEXPR AtomicBaseIncDec(T aInit) : Base(aInit) {}
constexpr AtomicBaseIncDec() : Base() {}
explicit constexpr AtomicBaseIncDec(T aInit) : Base(aInit) {}
using Base::operator=;
@ -982,7 +611,7 @@ public:
private:
template<MemoryOrdering AnyOrder>
AtomicBaseIncDec(const AtomicBaseIncDec<T, AnyOrder>& aCopy) MOZ_DELETE;
AtomicBaseIncDec(const AtomicBaseIncDec<T, AnyOrder>& aCopy) = delete;
};
} // namespace detail
@ -1025,8 +654,8 @@ class Atomic<T, Order, typename EnableIf<IsIntegral<T>::value &&
typedef typename detail::AtomicBaseIncDec<T, Order> Base;
public:
MOZ_CONSTEXPR Atomic() : Base() {}
explicit MOZ_CONSTEXPR Atomic(T aInit) : Base(aInit) {}
constexpr Atomic() : Base() {}
explicit constexpr Atomic(T aInit) : Base(aInit) {}
using Base::operator=;
@ -1056,7 +685,7 @@ public:
}
private:
Atomic(Atomic<T, Order>& aOther) MOZ_DELETE;
Atomic(Atomic<T, Order>& aOther) = delete;
};
/**
@ -1073,8 +702,8 @@ class Atomic<T*, Order> : public detail::AtomicBaseIncDec<T*, Order>
typedef typename detail::AtomicBaseIncDec<T*, Order> Base;
public:
MOZ_CONSTEXPR Atomic() : Base() {}
explicit MOZ_CONSTEXPR Atomic(T* aInit) : Base(aInit) {}
constexpr Atomic() : Base() {}
explicit constexpr Atomic(T* aInit) : Base(aInit) {}
using Base::operator=;
@ -1089,7 +718,7 @@ public:
}
private:
Atomic(Atomic<T*, Order>& aOther) MOZ_DELETE;
Atomic(Atomic<T*, Order>& aOther) = delete;
};
/**
@ -1104,15 +733,15 @@ class Atomic<T, Order, typename EnableIf<IsEnum<T>::value>::Type>
typedef typename detail::AtomicBase<T, Order> Base;
public:
MOZ_CONSTEXPR Atomic() : Base() {}
explicit MOZ_CONSTEXPR Atomic(T aInit) : Base(aInit) {}
constexpr Atomic() : Base() {}
explicit constexpr Atomic(T aInit) : Base(aInit) {}
operator T() const { return Base::Intrinsics::load(Base::mValue); }
operator T() const { return T(Base::Intrinsics::load(Base::mValue)); }
using Base::operator=;
private:
Atomic(Atomic<T, Order>& aOther) MOZ_DELETE;
Atomic(Atomic<T, Order>& aOther) = delete;
};
/**
@ -1138,11 +767,11 @@ class Atomic<bool, Order>
typedef typename detail::AtomicBase<uint32_t, Order> Base;
public:
MOZ_CONSTEXPR Atomic() : Base() {}
explicit MOZ_CONSTEXPR Atomic(bool aInit) : Base(aInit) {}
constexpr Atomic() : Base() {}
explicit constexpr Atomic(bool aInit) : Base(aInit) {}
// We provide boolean wrappers for the underlying AtomicBase methods.
operator bool() const
MOZ_IMPLICIT operator bool() const
{
return Base::Intrinsics::load(Base::mValue);
}
@ -1163,7 +792,7 @@ public:
}
private:
Atomic(Atomic<bool, Order>& aOther) MOZ_DELETE;
Atomic(Atomic<bool, Order>& aOther) = delete;
};
} // namespace mozilla

View File

@ -45,24 +45,7 @@
* standardly, by checking whether __cplusplus has a C++11 or greater value.
* Current versions of g++ do not correctly set __cplusplus, so we check both
* for forward compatibility.
*
* Even though some versions of MSVC support explicit conversion operators, we
* don't indicate support for them here, due to
* http://stackoverflow.com/questions/20498142/visual-studio-2013-explicit-keyword-bug
*/
# if _MSC_VER >= 1800
# define MOZ_HAVE_CXX11_DELETE
# endif
# if _MSC_VER >= 1700
# define MOZ_HAVE_CXX11_FINAL final
# else
# if defined(__clang__)
# error Please do not try to use clang-cl with MSVC10 or below emulation!
# endif
/* MSVC <= 10 used to spell "final" as "sealed". */
# define MOZ_HAVE_CXX11_FINAL sealed
# endif
# define MOZ_HAVE_CXX11_OVERRIDE
# define MOZ_HAVE_NEVER_INLINE __declspec(noinline)
# define MOZ_HAVE_NORETURN __declspec(noreturn)
#elif defined(__clang__)
@ -74,19 +57,6 @@
# ifndef __has_extension
# define __has_extension __has_feature /* compatibility, for older versions of clang */
# endif
# if __has_extension(cxx_constexpr)
# define MOZ_HAVE_CXX11_CONSTEXPR
# endif
# if __has_extension(cxx_explicit_conversions)
# define MOZ_HAVE_EXPLICIT_CONVERSION
# endif
# if __has_extension(cxx_deleted_functions)
# define MOZ_HAVE_CXX11_DELETE
# endif
# if __has_extension(cxx_override_control)
# define MOZ_HAVE_CXX11_OVERRIDE
# define MOZ_HAVE_CXX11_FINAL final
# endif
# if __has_attribute(noinline)
# define MOZ_HAVE_NEVER_INLINE __attribute__((noinline))
# endif
@ -94,24 +64,6 @@
# define MOZ_HAVE_NORETURN __attribute__((noreturn))
# endif
#elif defined(__GNUC__)
# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
# if MOZ_GCC_VERSION_AT_LEAST(4, 7, 0)
# define MOZ_HAVE_CXX11_OVERRIDE
# define MOZ_HAVE_CXX11_FINAL final
# endif
# if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0)
# define MOZ_HAVE_CXX11_CONSTEXPR
# endif
# if MOZ_GCC_VERSION_AT_LEAST(4, 5, 0)
# define MOZ_HAVE_EXPLICIT_CONVERSION
# endif
# define MOZ_HAVE_CXX11_DELETE
# else
/* __final is a non-C++11 GCC synonym for 'final', per GCC r176655. */
# if MOZ_GCC_VERSION_AT_LEAST(4, 7, 0)
# define MOZ_HAVE_CXX11_FINAL __final
# endif
# endif
# define MOZ_HAVE_NEVER_INLINE __attribute__((noinline))
# define MOZ_HAVE_NORETURN __attribute__((noreturn))
#endif
@ -126,49 +78,6 @@
# endif
#endif
/*
* The MOZ_CONSTEXPR specifier declares that a C++11 compiler can evaluate a
* function at compile time. A constexpr function cannot examine any values
* except its arguments and can have no side effects except its return value.
* The MOZ_CONSTEXPR_VAR specifier tells a C++11 compiler that a variable's
* value may be computed at compile time. It should be prefered to just
* marking variables as MOZ_CONSTEXPR because if the compiler does not support
* constexpr it will fall back to making the variable const, and some compilers
* do not accept variables being marked both const and constexpr.
*/
#ifdef MOZ_HAVE_CXX11_CONSTEXPR
# define MOZ_CONSTEXPR constexpr
# define MOZ_CONSTEXPR_VAR constexpr
#else
# define MOZ_CONSTEXPR /* no support */
# define MOZ_CONSTEXPR_VAR const
#endif
/*
* MOZ_EXPLICIT_CONVERSION is a specifier on a type conversion
* overloaded operator that declares that a C++11 compiler should restrict
* this operator to allow only explicit type conversions, disallowing
* implicit conversions.
*
* Example:
*
* template<typename T>
* class Ptr
* {
* T* mPtr;
* MOZ_EXPLICIT_CONVERSION operator bool() const
* {
* return mPtr != nullptr;
* }
* };
*
*/
#ifdef MOZ_HAVE_EXPLICIT_CONVERSION
# define MOZ_EXPLICIT_CONVERSION explicit
#else
# define MOZ_EXPLICIT_CONVERSION /* no support */
#endif
/*
* MOZ_NEVER_INLINE is a macro which expands to tell the compiler that the
* method decorated with it must never be inlined, even if the compiler would
@ -201,6 +110,43 @@
# define MOZ_NORETURN /* no support */
#endif
/**
* MOZ_COLD tells the compiler that a function is "cold", meaning infrequently
* executed. This may lead it to optimize for size more aggressively than speed,
* or to allocate the body of the function in a distant part of the text segment
* to help keep it from taking up unnecessary icache when it isn't in use.
*
* Place this attribute at the very beginning of a function definition. For
* example, write
*
* MOZ_COLD int foo();
*
* or
*
* MOZ_COLD int foo() { return 42; }
*/
#if defined(__GNUC__) || defined(__clang__)
# define MOZ_COLD __attribute__ ((cold))
#else
# define MOZ_COLD
#endif
/**
* MOZ_NONNULL tells the compiler that some of the arguments to a function are
* known to be non-null. The arguments are a list of 1-based argument indexes
* identifying arguments which are known to be non-null.
*
* Place this attribute at the very beginning of a function definition. For
* example, write
*
* MOZ_NONNULL(1, 2) int foo(char *p, char *q);
*/
#if defined(__GNUC__) || defined(__clang__)
# define MOZ_NONNULL(...) __attribute__ ((nonnull(__VA_ARGS__)))
#else
# define MOZ_NONNULL(...)
#endif
/*
* MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS, specified at the end of a function
* declaration, indicates that for the purposes of static analysis, this
@ -262,165 +208,96 @@
# define MOZ_TSAN_BLACKLIST /* nothing */
#endif
#ifdef __cplusplus
/*
* MOZ_DELETE, specified immediately prior to the ';' terminating an undefined-
* method declaration, attempts to delete that method from the corresponding
* class. An attempt to use the method will always produce an error *at compile
* time* (instead of sometimes as late as link time) when this macro can be
* implemented. For example, you can use MOZ_DELETE to produce classes with no
* implicit copy constructor or assignment operator:
*
* struct NonCopyable
* {
* private:
* NonCopyable(const NonCopyable& aOther) MOZ_DELETE;
* void operator=(const NonCopyable& aOther) MOZ_DELETE;
* };
*
* If MOZ_DELETE can't be implemented for the current compiler, use of the
* annotated method will still cause an error, but the error might occur at link
* time in some cases rather than at compile time.
*
* MOZ_DELETE relies on C++11 functionality not universally implemented. As a
* backstop, method declarations using MOZ_DELETE should be private.
*/
#if defined(MOZ_HAVE_CXX11_DELETE)
# define MOZ_DELETE = delete
#else
# define MOZ_DELETE /* no support */
#endif
/*
* MOZ_OVERRIDE explicitly indicates that a virtual member function in a class
* overrides a member function of a base class, rather than potentially being a
* new member function. MOZ_OVERRIDE should be placed immediately before the
* ';' terminating the member function's declaration, or before '= 0;' if the
* member function is pure. If the member function is defined in the class
* definition, it should appear before the opening brace of the function body.
*
* class Base
* {
* public:
* virtual void f() = 0;
* };
* class Derived1 : public Base
* {
* public:
* virtual void f() MOZ_OVERRIDE;
* };
* class Derived2 : public Base
* {
* public:
* virtual void f() MOZ_OVERRIDE = 0;
* };
* class Derived3 : public Base
* {
* public:
* virtual void f() MOZ_OVERRIDE { }
* };
*
* In compilers supporting C++11 override controls, MOZ_OVERRIDE *requires* that
* the function marked with it override a member function of a base class: it
* is a compile error if it does not. Otherwise MOZ_OVERRIDE does not affect
* semantics and merely documents the override relationship to the reader (but
* of course must still be used correctly to not break C++11 compilers).
*/
#if defined(MOZ_HAVE_CXX11_OVERRIDE)
# define MOZ_OVERRIDE override
#else
# define MOZ_OVERRIDE /* no support */
#endif
/*
* MOZ_FINAL indicates that some functionality cannot be overridden through
* inheritance. It can be used to annotate either classes/structs or virtual
* member functions.
*
* To annotate a class/struct with MOZ_FINAL, place MOZ_FINAL immediately after
* the name of the class, before the list of classes from which it derives (if
* any) and before its opening brace. MOZ_FINAL must not be used to annotate
* unnamed classes or structs. (With some compilers, and with C++11 proper, the
* underlying expansion is ambiguous with specifying a class name.)
*
* class Base MOZ_FINAL
* {
* public:
* Base();
* ~Base();
* virtual void f() { }
* };
* // This will be an error in some compilers:
* class Derived : public Base
* {
* public:
* ~Derived() { }
* };
*
* One particularly common reason to specify MOZ_FINAL upon a class is to tell
* the compiler that it's not dangerous for it to have a non-virtual destructor
* yet have one or more virtual functions, silencing the warning it might emit
* in this case. Suppose Base above weren't annotated with MOZ_FINAL. Because
* ~Base() is non-virtual, an attempt to delete a Derived* through a Base*
* wouldn't call ~Derived(), so any cleanup ~Derived() might do wouldn't happen.
* (Formally C++ says behavior is undefined, but compilers will likely just call
* ~Base() and not ~Derived().) Specifying MOZ_FINAL tells the compiler that
* it's safe for the destructor to be non-virtual.
*
* In compilers implementing final controls, it is an error to inherit from a
* class annotated with MOZ_FINAL. In other compilers it serves only as
* documentation.
*
* To annotate a virtual member function with MOZ_FINAL, place MOZ_FINAL
* immediately before the ';' terminating the member function's declaration, or
* before '= 0;' if the member function is pure. If the member function is
* defined in the class definition, it should appear before the opening brace of
* the function body. (This placement is identical to that for MOZ_OVERRIDE.
* If both are used, they should appear in the order 'MOZ_FINAL MOZ_OVERRIDE'
* for consistency.)
*
* class Base
* {
* public:
* virtual void f() MOZ_FINAL;
* };
* class Derived
* {
* public:
* // This will be an error in some compilers:
* virtual void f();
* };
*
* In compilers implementing final controls, it is an error for a derived class
* to override a method annotated with MOZ_FINAL. In other compilers it serves
* only as documentation.
*/
#if defined(MOZ_HAVE_CXX11_FINAL)
# define MOZ_FINAL MOZ_HAVE_CXX11_FINAL
#else
# define MOZ_FINAL /* no support */
#endif
/**
* MOZ_WARN_UNUSED_RESULT tells the compiler to emit a warning if a function's
* return value is not used by the caller.
* 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
* block is not pointed to by any other reachable pointer in the program.
* "Pointer-free" means that the block contains no pointers to any valid object
* in the program. It may be initialized with other (non-pointer) values.
*
* Place this attribute at the very beginning of a function definition. For
* example, write
* Placing this attribute on appropriate functions helps GCC analyze pointer
* aliasing more accurately in their callers.
*
* MOZ_WARN_UNUSED_RESULT int foo();
* GCC warns if a caller ignores the value returned by a function marked with
* MOZ_ALLOCATOR: it is hard to imagine cases where dropping the value returned
* by a function that meets the criteria above would be intentional.
*
* Place this attribute after the argument list and 'this' qualifiers of a
* function definition. For example, write
*
* void *my_allocator(size_t) MOZ_ALLOCATOR;
*
* or
*
* MOZ_WARN_UNUSED_RESULT int foo() { return 42; }
* void *my_allocator(size_t bytes) MOZ_ALLOCATOR { ... }
*/
#if defined(__GNUC__) || defined(__clang__)
# define MOZ_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
# define MOZ_ALLOCATOR __attribute__ ((malloc, warn_unused_result))
#else
# define MOZ_WARN_UNUSED_RESULT
# define MOZ_ALLOCATOR
#endif
/**
* MOZ_MUST_USE tells the compiler to emit a warning if a function's
* return value is not used by the caller.
*
* Place this attribute at the very beginning of a function declaration. For
* example, write
*
* MOZ_MUST_USE int foo();
*
* or
*
* MOZ_MUST_USE int foo() { return 42; }
*/
#if defined(__GNUC__) || defined(__clang__)
# define MOZ_MUST_USE __attribute__ ((warn_unused_result))
#else
# define MOZ_MUST_USE
#endif
/**
* MOZ_FALLTHROUGH is an annotation to suppress compiler warnings about switch
* cases that fall through without a break or return statement. MOZ_FALLTHROUGH
* is only needed on cases that have code.
*
* MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about
* switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in
* debug builds, but intentionally fall through in release builds. See comment
* in Assertions.h for more details.
*
* switch (foo) {
* case 1: // These cases have no code. No fallthrough annotations are needed.
* case 2:
* case 3: // This case has code, so a fallthrough annotation is needed!
* foo++;
* MOZ_FALLTHROUGH;
* case 4:
* return foo;
*
* default:
* // This case asserts in debug builds, falls through in release.
* MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!");
* case 5:
* return 5;
* }
*/
#if defined(__clang__) && __cplusplus >= 201103L
/* clang's fallthrough annotations are only available starting in C++11. */
# define MOZ_FALLTHROUGH [[clang::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 <sal.h>
# define MOZ_FALLTHROUGH __fallthrough
#else
# 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)
@ -429,17 +306,17 @@
* following is a guide on where to place the attributes.
*
* Attributes that apply to a struct or class precede the name of the class:
* (Note that this is different from the placement of MOZ_FINAL for classes!)
* (Note that this is different from the placement of final for classes!)
*
* class MOZ_CLASS_ATTRIBUTE SomeClass {};
*
* Attributes that apply to functions follow the parentheses and const
* qualifiers but precede MOZ_FINAL, MOZ_OVERRIDE and the function body:
* qualifiers but precede final, override and the function body:
*
* void DeclaredFunction() MOZ_FUNCTION_ATTRIBUTE;
* void SomeFunction() MOZ_FUNCTION_ATTRIBUTE {}
* void PureFunction() const MOZ_FUNCTION_ATTRIBUTE = 0;
* void OverriddenFunction() MOZ_FUNCTION_ATTIRBUTE MOZ_OVERRIDE;
* void OverriddenFunction() MOZ_FUNCTION_ATTIRBUTE override;
*
* Attributes that apply to variables or parameters follow the variable's name:
*
@ -482,10 +359,35 @@
* MOZ_NONHEAP_CLASS: Applies to all classes. Any class with this annotation is
* 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 (unless placement new is being used). 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
* 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.
* 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
* temporary object. If a member of another class uses this class, or if
* another class inherits from this class, then it is considered to be a heap
* class as well, although this attribute need not be provided in such cases.
* MOZ_NON_TEMPORARY_CLASS: Applies to all classes. Any class with this
* annotation is expected not to live in a temporary. 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-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
* storage, or on the heap. This is a combination of MOZ_STACK_CLASS and
* MOZ_NON_TEMPORARY_CLASS.
* MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS: Applies to all classes that are
* intended to prevent introducing static initializers. This attribute
* currently makes it a compile-time error to instantiate these classes
* anywhere other than at the global scope, or as a static member of a class.
* In non-debug mode, it also prohibits non-trivial constructors and
* destructors.
* MOZ_TRIVIAL_CTOR_DTOR: Applies to all classes that must have both a trivial
* or constexpr constructor and a trivial destructor. Setting this attribute
* on a class makes it a compile-time error for that class to get a
* non-trivial constructor or destructor for any reason.
* MOZ_HEAP_ALLOCATOR: Applies to any function. This indicates that the return
* value is allocated on the heap, and will as a result check such allocations
* during MOZ_STACK_CLASS and MOZ_NONHEAP_CLASS annotation checking.
@ -493,12 +395,122 @@
* 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_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
* types. This attribute tells the compiler that the raw pointer is a strong
* reference, where ownership through methods such as AddRef and Release is
* managed manually. This can make the compiler ignore these pointers when
* validating the usage of pointers otherwise.
*
* Example uses include owned pointers inside of unions, and pointers stored
* in POD types where a using a smart pointer class would make the object
* non-POD.
* 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.
*
* 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.
*
* 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
* pointer classes to ensure that the refcount of an object wrapped in a
* smart pointer is not manipulated directly.
* MOZ_MUST_USE_TYPE: Applies to type declarations. Makes it a compile time
* error to not use the return value of a function which has this type. This
* is intended to be used with types which it is an error to not use.
* MOZ_NEEDS_NO_VTABLE_TYPE: Applies to template class declarations. Makes it
* a compile time error to instantiate this template with a type parameter which
* has a VTable.
* 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
* template arguments are required to be safe to move in memory using
* memmove(). Passing MOZ_NON_MEMMOVABLE types to these templates is a
* compile time error.
* MOZ_NEEDS_MEMMOVABLE_MEMBERS: Applies to class declarations where each member
* must be safe to move in memory using memmove(). MOZ_NON_MEMMOVABLE types
* used in members of these classes are compile time errors.
* MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS: Applies to template class
* declarations where an instance of the template should be considered, for
* static analysis purposes, to inherit any type annotations (such as
* MOZ_MUST_USE_TYPE and MOZ_STACK_CLASS) from its template arguments.
* MOZ_INIT_OUTSIDE_CTOR: Applies to class member declarations. Occasionally
* there are class members that are not initialized in the constructor,
* but logic elsewhere in the class ensures they are initialized prior to use.
* Using this attribute on a member disables the check that this member must be
* initialized in constructors via list-initialization, in the constructor body,
* or via functions called from the constructor body.
* MOZ_IS_CLASS_INIT: Applies to class method declarations. Occasionally the
* constructor doesn't initialize all of the member variables and another function
* is used to initialize the rest. This marker is used to make the static analysis
* tool aware that the marked function is part of the initialization process
* and to include the marked function in the scan mechanism that determines witch
* member variables still remain uninitialized.
* MOZ_NON_PARAM: Applies to types. Makes it compile time error to use the type
* in parameter without pointer or reference.
* MOZ_NON_AUTOABLE: Applies to class declarations. Makes it a compile time error to
* use `auto` in place of this type in variable declarations. This is intended to
* be used with types which are intended to be implicitly constructed into other
* other types before being assigned to variables.
* MOZ_REQUIRED_BASE_METHOD: Applies to virtual class method declarations.
* Sometimes derived classes override methods that need to be called by their
* overridden counterparts. This marker indicates that the marked method must
* be called by the method that it overrides.
*/
#ifdef MOZ_CLANG_PLUGIN
# define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override")))
# 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")))
/*
* 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
@ -513,24 +525,80 @@
# 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_RAII MOZ_NON_TEMPORARY_CLASS MOZ_STACK_CLASS
/*
* MOZ_THIS_IN_INITIALIZER_LIST is used to avoid a warning when we know that
* it's safe to use 'this' in an initializer list.
* MOZ_HAVE_REF_QUALIFIERS is defined for compilers that support C++11's rvalue
* qualifier, "&&".
*/
#ifdef _MSC_VER
# define MOZ_THIS_IN_INITIALIZER_LIST() \
__pragma(warning(push)) \
__pragma(warning(disable:4355)) \
this \
__pragma(warning(pop))
#else
# define MOZ_THIS_IN_INITIALIZER_LIST() this
#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 */
/**
* Printf style formats. MOZ_FORMAT_PRINTF can be used to annotate a
* function or method that is "printf-like"; this will let (some)
* compilers check that the arguments match the template string.
*
* This macro takes two arguments. The first argument is the argument
* number of the template string. The second argument is the argument
* number of the '...' argument holding the arguments.
*
* Argument numbers start at 1. Note that the implicit "this"
* argument of a non-static member function counts as an argument.
*
* So, for a simple case like:
* void print_something (int whatever, const char *fmt, ...);
* The corresponding annotation would be
* MOZ_FORMAT_PRINTF(2, 3)
* However, if "print_something" were a non-static member function,
* then the annotation would be:
* MOZ_FORMAT_PRINTF(3, 4)
*
* Note that the checking is limited to standards-conforming
* printf-likes, and in particular this should not be used for
* PR_snprintf and friends, which are "printf-like" but which assign
* different meanings to the various formats.
*/
#ifdef __GNUC__
#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck) \
__attribute__ ((format (printf, stringIndex, firstToCheck)))
#else
#define MOZ_FORMAT_PRINTF(stringIndex, firstToCheck)
#endif
#endif /* mozilla_Attributes_h */

View File

@ -14,8 +14,9 @@
namespace mozilla {
/*
* The algorithm searches the given container |aContainer| over the sorted
* index range [aBegin, aEnd) for an index |i| where |aContainer[i] == aTarget|.
* The BinarySearch() algorithm searches the given container |aContainer| over
* the sorted index range [aBegin, aEnd) for an index |i| where
* |aContainer[i] == aTarget|.
* If such an index |i| is found, BinarySearch returns |true| and the index is
* returned via the outparam |aMatchOrInsertionPoint|. If no index is found,
* BinarySearch returns |false| and the outparam returns the first index in
@ -29,34 +30,61 @@ namespace mozilla {
* if (BinarySearch(sortedInts, 0, sortedInts.length(), 13, &match)) {
* printf("found 13 at %lu\n", match);
* }
*
* The BinarySearchIf() version behaves similarly, but takes |aComparator|, a
* functor to compare the values with, instead of a value to find.
* That functor should take one argument - the value to compare - and return an
* |int| with the comparison result:
*
* * 0, if the argument is equal to,
* * less than 0, if the argument is greater than,
* * greater than 0, if the argument is less than
*
* the value.
*
* Example:
*
* struct Comparator {
* int operator()(int aVal) const {
* if (mTarget < aVal) { return -1; }
* if (mTarget > aVal) { return 1; }
* return 0;
* }
* explicit Comparator(int aTarget) : mTarget(aTarget) {}
* const int mTarget;
* };
*
* Vector<int> sortedInts = ...
*
* size_t match;
* if (BinarySearchIf(sortedInts, 0, sortedInts.length(), Comparator(13), &match)) {
* printf("found 13 at %lu\n", match);
* }
*
*/
template <typename Container, typename T>
template<typename Container, typename Comparator>
bool
BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd,
T aTarget, size_t* aMatchOrInsertionPoint)
BinarySearchIf(const Container& aContainer, size_t aBegin, size_t aEnd,
const Comparator& aCompare, size_t* aMatchOrInsertionPoint)
{
MOZ_ASSERT(aBegin <= aEnd);
size_t low = aBegin;
size_t high = aEnd;
while (low != high) {
while (high != low) {
size_t middle = low + (high - low) / 2;
// Allow any intermediate type so long as it provides a suitable ordering
// relation.
const auto& middleValue = aContainer[middle];
const int result = aCompare(aContainer[middle]);
MOZ_ASSERT(aContainer[low] <= aContainer[middle]);
MOZ_ASSERT(aContainer[middle] <= aContainer[high - 1]);
MOZ_ASSERT(aContainer[low] <= aContainer[high - 1]);
if (aTarget == middleValue) {
if (result == 0) {
*aMatchOrInsertionPoint = middle;
return true;
}
if (aTarget < middleValue) {
if (result < 0) {
high = middle;
} else {
low = middle + 1;
@ -67,6 +95,45 @@ BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd,
return false;
}
namespace detail {
template<class T>
class BinarySearchDefaultComparator
{
public:
explicit BinarySearchDefaultComparator(const T& aTarget)
: mTarget(aTarget)
{}
template <class U>
int operator()(const U& aVal) const {
if (mTarget == aVal) {
return 0;
}
if (mTarget < aVal) {
return -1;
}
return 1;
}
private:
const T& mTarget;
};
} // namespace detail
template <typename Container, typename T>
bool
BinarySearch(const Container& aContainer, size_t aBegin, size_t aEnd,
T aTarget, size_t* aMatchOrInsertionPoint)
{
return BinarySearchIf(aContainer, aBegin, aEnd,
detail::BinarySearchDefaultComparator<T>(aTarget),
aMatchOrInsertionPoint);
}
} // namespace mozilla
#endif // mozilla_BinarySearch_h

View File

View File

@ -0,0 +1,517 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_BufferList_h
#define mozilla_BufferList_h
#include <algorithm>
#include "mozilla/AllocPolicy.h"
#include "mozilla/Move.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/Types.h"
#include "mozilla/TypeTraits.h"
#include "mozilla/Vector.h"
#include <string.h>
// BufferList represents a sequence of buffers of data. A BufferList can choose
// to own its buffers or not. The class handles writing to the buffers,
// iterating over them, and reading data out. Unlike SegmentedVector, the
// buffers may be of unequal size. Like SegmentedVector, BufferList is a nice
// way to avoid large contiguous allocations (which can trigger OOMs).
namespace mozilla {
template<typename AllocPolicy>
class BufferList : private AllocPolicy
{
// Each buffer in a BufferList has a size and a capacity. The first mSize
// bytes are initialized and the remaining |mCapacity - mSize| bytes are free.
struct Segment
{
char* mData;
size_t mSize;
size_t mCapacity;
Segment(char* aData, size_t aSize, size_t aCapacity)
: mData(aData),
mSize(aSize),
mCapacity(aCapacity)
{
}
Segment(const Segment&) = delete;
Segment& operator=(const Segment&) = delete;
Segment(Segment&&) = default;
Segment& operator=(Segment&&) = default;
char* Start() const { return mData; }
char* End() const { return mData + mSize; }
};
template<typename OtherAllocPolicy>
friend class BufferList;
public:
// For the convenience of callers, all segments are required to be a multiple
// of 8 bytes in capacity. Also, every buffer except the last one is required
// to be full (i.e., size == capacity). Therefore, a byte at offset N within
// the BufferList and stored in memory at an address A will satisfy
// (N % Align == A % Align) if Align == 2, 4, or 8.
static const size_t kSegmentAlignment = 8;
// Allocate a BufferList. The BufferList will free all its buffers when it is
// destroyed. An initial buffer of size aInitialSize and capacity
// aInitialCapacity is allocated automatically. This data will be contiguous
// an can be accessed via |Start()|. Subsequent buffers will be allocated with
// capacity aStandardCapacity.
BufferList(size_t aInitialSize,
size_t aInitialCapacity,
size_t aStandardCapacity,
AllocPolicy aAP = AllocPolicy())
: AllocPolicy(aAP),
mOwning(true),
mSegments(aAP),
mSize(0),
mStandardCapacity(aStandardCapacity)
{
MOZ_ASSERT(aInitialCapacity % kSegmentAlignment == 0);
MOZ_ASSERT(aStandardCapacity % kSegmentAlignment == 0);
if (aInitialCapacity) {
AllocateSegment(aInitialSize, aInitialCapacity);
}
}
BufferList(const BufferList& aOther) = delete;
BufferList(BufferList&& aOther)
: mOwning(aOther.mOwning),
mSegments(Move(aOther.mSegments)),
mSize(aOther.mSize),
mStandardCapacity(aOther.mStandardCapacity)
{
aOther.mSegments.clear();
aOther.mSize = 0;
}
BufferList& operator=(const BufferList& aOther) = delete;
BufferList& operator=(BufferList&& aOther)
{
Clear();
mOwning = aOther.mOwning;
mSegments = Move(aOther.mSegments);
mSize = aOther.mSize;
aOther.mSegments.clear();
aOther.mSize = 0;
return *this;
}
~BufferList() { Clear(); }
// Returns the sum of the sizes of all the buffers.
size_t Size() const { return mSize; }
void Clear()
{
if (mOwning) {
for (Segment& segment : mSegments) {
this->free_(segment.mData);
}
}
mSegments.clear();
mSize = 0;
}
// Iterates over bytes in the segments. You can advance it by as many bytes as
// you choose.
class IterImpl
{
// Invariants:
// (0) mSegment <= bufferList.mSegments.size()
// (1) mData <= mDataEnd
// (2) If mSegment is not the last segment, mData < mDataEnd
uintptr_t mSegment;
char* mData;
char* mDataEnd;
friend class BufferList;
public:
explicit IterImpl(const BufferList& aBuffers)
: mSegment(0),
mData(nullptr),
mDataEnd(nullptr)
{
if (!aBuffers.mSegments.empty()) {
mData = aBuffers.mSegments[0].Start();
mDataEnd = aBuffers.mSegments[0].End();
}
}
// Returns a pointer to the raw data. It is valid to access up to
// RemainingInSegment bytes of this buffer.
char* Data() const
{
MOZ_RELEASE_ASSERT(!Done());
return mData;
}
// Returns true if the memory in the range [Data(), Data() + aBytes) is all
// part of one contiguous buffer.
bool HasRoomFor(size_t aBytes) const
{
MOZ_RELEASE_ASSERT(mData <= mDataEnd);
return size_t(mDataEnd - mData) >= aBytes;
}
// Returns the maximum value aBytes for which HasRoomFor(aBytes) will be
// true.
size_t RemainingInSegment() const
{
MOZ_RELEASE_ASSERT(mData <= mDataEnd);
return mDataEnd - mData;
}
// Advances the iterator by aBytes bytes. aBytes must be less than
// RemainingInSegment(). If advancing by aBytes takes the iterator to the
// end of a buffer, it will be moved to the beginning of the next buffer
// unless it is the last buffer.
void Advance(const BufferList& aBuffers, size_t aBytes)
{
const Segment& segment = aBuffers.mSegments[mSegment];
MOZ_RELEASE_ASSERT(segment.Start() <= mData);
MOZ_RELEASE_ASSERT(mData <= mDataEnd);
MOZ_RELEASE_ASSERT(mDataEnd == segment.End());
MOZ_RELEASE_ASSERT(HasRoomFor(aBytes));
mData += aBytes;
if (mData == mDataEnd && mSegment + 1 < aBuffers.mSegments.length()) {
mSegment++;
const Segment& nextSegment = aBuffers.mSegments[mSegment];
mData = nextSegment.Start();
mDataEnd = nextSegment.End();
MOZ_RELEASE_ASSERT(mData < mDataEnd);
}
}
// Advance the iterator by aBytes, possibly crossing segments. This function
// returns false if it runs out of buffers to advance through. Otherwise it
// returns true.
bool AdvanceAcrossSegments(const BufferList& aBuffers, size_t aBytes)
{
size_t bytes = aBytes;
while (bytes) {
size_t toAdvance = std::min(bytes, RemainingInSegment());
if (!toAdvance) {
return false;
}
Advance(aBuffers, toAdvance);
bytes -= toAdvance;
}
return true;
}
// Returns true when the iterator reaches the end of the BufferList.
bool Done() const
{
return mData == mDataEnd;
}
private:
// Count the bytes we would need to advance in order to reach aTarget.
size_t BytesUntil(const BufferList& aBuffers, const IterImpl& aTarget) const {
size_t offset = 0;
MOZ_ASSERT(aTarget.IsIn(aBuffers));
char* data = mData;
for (uintptr_t segment = mSegment; segment < aTarget.mSegment; segment++) {
offset += aBuffers.mSegments[segment].End() - data;
data = aBuffers.mSegments[segment].mData;
}
MOZ_RELEASE_ASSERT(IsIn(aBuffers));
MOZ_RELEASE_ASSERT(aTarget.mData >= data);
offset += aTarget.mData - data;
return offset;
}
bool IsIn(const BufferList& aBuffers) const {
return mSegment < aBuffers.mSegments.length() &&
mData >= aBuffers.mSegments[mSegment].mData &&
mData < aBuffers.mSegments[mSegment].End();
}
};
// Special convenience method that returns Iter().Data().
char* Start() { return mSegments[0].mData; }
const char* Start() const { return mSegments[0].mData; }
IterImpl Iter() const { return IterImpl(*this); }
// Copies aSize bytes from aData into the BufferList. The storage for these
// bytes may be split across multiple buffers. Size() is increased by aSize.
inline bool WriteBytes(const char* aData, size_t aSize);
// Copies possibly non-contiguous byte range starting at aIter into
// aData. aIter is advanced by aSize bytes. Returns false if it runs out of
// data before aSize.
inline bool ReadBytes(IterImpl& aIter, char* aData, size_t aSize) const;
// Return a new BufferList that shares storage with this BufferList. The new
// BufferList is read-only. It allows iteration over aSize bytes starting at
// aIter. Borrow can fail, in which case *aSuccess will be false upon
// return. The borrowed BufferList can use a different AllocPolicy than the
// original one. However, it is not responsible for freeing buffers, so the
// AllocPolicy is only used for the buffer vector.
template<typename BorrowingAllocPolicy>
BufferList<BorrowingAllocPolicy> Borrow(IterImpl& aIter, size_t aSize, bool* aSuccess,
BorrowingAllocPolicy aAP = BorrowingAllocPolicy()) const;
// Return a new BufferList and move storage from this BufferList to it. The
// new BufferList owns the buffers. Move can fail, in which case *aSuccess
// will be false upon return. The new BufferList can use a different
// AllocPolicy than the original one. The new OtherAllocPolicy is responsible
// for freeing buffers, so the OtherAllocPolicy must use freeing method
// compatible to the original one.
template<typename OtherAllocPolicy>
BufferList<OtherAllocPolicy> MoveFallible(bool* aSuccess, OtherAllocPolicy aAP = OtherAllocPolicy());
// Return a new BufferList that adopts the byte range starting at Iter so that
// range [aIter, aIter + aSize) is transplanted to the returned BufferList.
// Contents of the buffer before aIter + aSize is left undefined.
// Extract can fail, in which case *aSuccess will be false upon return. The
// moved buffers are erased from the original BufferList. In case of extract
// fails, the original BufferList is intact. All other iterators except aIter
// are invalidated.
// This method requires aIter and aSize to be 8-byte aligned.
BufferList Extract(IterImpl& aIter, size_t aSize, bool* aSuccess);
// Return the number of bytes from 'start' to 'end', two iterators within
// this BufferList.
size_t RangeLength(const IterImpl& start, const IterImpl& end) const {
MOZ_ASSERT(start.IsIn(*this) && end.IsIn(*this));
return start.BytesUntil(*this, end);
}
private:
explicit BufferList(AllocPolicy aAP)
: AllocPolicy(aAP),
mOwning(false),
mSize(0),
mStandardCapacity(0)
{
}
void* AllocateSegment(size_t aSize, size_t aCapacity)
{
MOZ_RELEASE_ASSERT(mOwning);
char* data = this->template pod_malloc<char>(aCapacity);
if (!data) {
return nullptr;
}
if (!mSegments.append(Segment(data, aSize, aCapacity))) {
this->free_(data);
return nullptr;
}
mSize += aSize;
return data;
}
bool mOwning;
Vector<Segment, 1, AllocPolicy> mSegments;
size_t mSize;
size_t mStandardCapacity;
};
template<typename AllocPolicy>
bool
BufferList<AllocPolicy>::WriteBytes(const char* aData, size_t aSize)
{
MOZ_RELEASE_ASSERT(mOwning);
MOZ_RELEASE_ASSERT(mStandardCapacity);
size_t copied = 0;
size_t remaining = aSize;
if (!mSegments.empty()) {
Segment& lastSegment = mSegments.back();
size_t toCopy = std::min(aSize, lastSegment.mCapacity - lastSegment.mSize);
memcpy(lastSegment.mData + lastSegment.mSize, aData, toCopy);
lastSegment.mSize += toCopy;
mSize += toCopy;
copied += toCopy;
remaining -= toCopy;
}
while (remaining) {
size_t toCopy = std::min(remaining, mStandardCapacity);
void* data = AllocateSegment(toCopy, mStandardCapacity);
if (!data) {
return false;
}
memcpy(data, aData + copied, toCopy);
copied += toCopy;
remaining -= toCopy;
}
return true;
}
template<typename AllocPolicy>
bool
BufferList<AllocPolicy>::ReadBytes(IterImpl& aIter, char* aData, size_t aSize) const
{
size_t copied = 0;
size_t remaining = aSize;
while (remaining) {
size_t toCopy = std::min(aIter.RemainingInSegment(), remaining);
if (!toCopy) {
// We've run out of data in the last segment.
return false;
}
memcpy(aData + copied, aIter.Data(), toCopy);
copied += toCopy;
remaining -= toCopy;
aIter.Advance(*this, toCopy);
}
return true;
}
template<typename AllocPolicy> template<typename BorrowingAllocPolicy>
BufferList<BorrowingAllocPolicy>
BufferList<AllocPolicy>::Borrow(IterImpl& aIter, size_t aSize, bool* aSuccess,
BorrowingAllocPolicy aAP) const
{
BufferList<BorrowingAllocPolicy> result(aAP);
size_t size = aSize;
while (size) {
size_t toAdvance = std::min(size, aIter.RemainingInSegment());
if (!toAdvance || !result.mSegments.append(typename BufferList<BorrowingAllocPolicy>::Segment(aIter.mData, toAdvance, toAdvance))) {
*aSuccess = false;
return result;
}
aIter.Advance(*this, toAdvance);
size -= toAdvance;
}
result.mSize = aSize;
*aSuccess = true;
return result;
}
template<typename AllocPolicy> template<typename OtherAllocPolicy>
BufferList<OtherAllocPolicy>
BufferList<AllocPolicy>::MoveFallible(bool* aSuccess, OtherAllocPolicy aAP)
{
BufferList<OtherAllocPolicy> result(0, 0, mStandardCapacity, aAP);
IterImpl iter = Iter();
while (!iter.Done()) {
size_t toAdvance = iter.RemainingInSegment();
if (!toAdvance || !result.mSegments.append(typename BufferList<OtherAllocPolicy>::Segment(iter.mData, toAdvance, toAdvance))) {
*aSuccess = false;
result.mSegments.clear();
return result;
}
iter.Advance(*this, toAdvance);
}
result.mSize = mSize;
mSegments.clear();
mSize = 0;
*aSuccess = true;
return result;
}
template<typename AllocPolicy>
BufferList<AllocPolicy>
BufferList<AllocPolicy>::Extract(IterImpl& aIter, size_t aSize, bool* aSuccess)
{
MOZ_RELEASE_ASSERT(aSize);
MOZ_RELEASE_ASSERT(mOwning);
MOZ_ASSERT(aSize % kSegmentAlignment == 0);
MOZ_ASSERT(intptr_t(aIter.mData) % kSegmentAlignment == 0);
IterImpl iter = aIter;
size_t size = aSize;
size_t toCopy = std::min(size, aIter.RemainingInSegment());
MOZ_ASSERT(toCopy % kSegmentAlignment == 0);
BufferList result(0, toCopy, mStandardCapacity);
BufferList error(0, 0, mStandardCapacity);
// Copy the head
if (!result.WriteBytes(aIter.mData, toCopy)) {
*aSuccess = false;
return error;
}
iter.Advance(*this, toCopy);
size -= toCopy;
// Move segments to result
auto resultGuard = MakeScopeExit([&] {
*aSuccess = false;
result.mSegments.erase(result.mSegments.begin()+1, result.mSegments.end());
});
size_t movedSize = 0;
uintptr_t toRemoveStart = iter.mSegment;
uintptr_t toRemoveEnd = iter.mSegment;
while (!iter.Done() &&
!iter.HasRoomFor(size)) {
if (!result.mSegments.append(Segment(mSegments[iter.mSegment].mData,
mSegments[iter.mSegment].mSize,
mSegments[iter.mSegment].mCapacity))) {
return error;
}
movedSize += iter.RemainingInSegment();
size -= iter.RemainingInSegment();
toRemoveEnd++;
iter.Advance(*this, iter.RemainingInSegment());
}
if (size) {
if (!iter.HasRoomFor(size) ||
!result.WriteBytes(iter.Data(), size)) {
return error;
}
iter.Advance(*this, size);
}
mSegments.erase(mSegments.begin() + toRemoveStart, mSegments.begin() + toRemoveEnd);
mSize -= movedSize;
aIter.mSegment = iter.mSegment - (toRemoveEnd - toRemoveStart);
aIter.mData = iter.mData;
aIter.mDataEnd = iter.mDataEnd;
MOZ_ASSERT(aIter.mDataEnd == mSegments[aIter.mSegment].End());
result.mSize = aSize;
resultGuard.release();
*aSuccess = true;
return result;
}
} // namespace mozilla
#endif /* mozilla_BufferList_h */

View File

@ -17,16 +17,29 @@
namespace mozilla {
/**
* Return a value of type |To|, containing the underlying bit pattern of
* Sets the outparam value of type |To| with the same underlying bit pattern of
* |aFrom|.
*
* |To| and |From| must be types of the same size; be careful of cross-platform
* size differences, or this might fail to compile on some but not all
* platforms.
*
* There is also a variant that returns the value directly. In most cases, the
* two variants should be identical. However, in the specific case of x86
* chips, the behavior differs: returning floating-point values directly is done
* through the x87 stack, and x87 loads and stores turn signaling NaNs into
* quiet NaNs... silently. Returning floating-point values via outparam,
* however, is done entirely within the SSE registers when SSE2 floating-point
* is enabled in the compiler, which has semantics-preserving behavior you would
* expect.
*
* If preserving the distinction between signaling NaNs and quiet NaNs is
* important to you, you should use the outparam version. In all other cases,
* you should use the direct return version.
*/
template<typename To, typename From>
inline To
BitwiseCast(const From aFrom)
inline void
BitwiseCast(const From aFrom, To* aResult)
{
static_assert(sizeof(From) == sizeof(To),
"To and From must have the same size");
@ -36,7 +49,16 @@ BitwiseCast(const From aFrom)
To mTo;
} u;
u.mFrom = aFrom;
return u.mTo;
*aResult = u.mTo;
}
template<typename To, typename From>
inline To
BitwiseCast(const From aFrom)
{
To temp;
BitwiseCast<To, From>(aFrom, &temp);
return temp;
}
namespace detail {
@ -210,7 +232,7 @@ IsInBounds(const From aFrom)
*/
template<typename To, typename From>
inline To
SafeCast(const From aFrom)
AssertedCast(const From aFrom)
{
MOZ_ASSERT((detail::IsInBounds<From, To>(aFrom)));
return static_cast<To>(aFrom);

View File

@ -7,11 +7,36 @@
#ifndef mozilla_ChaosMode_h
#define mozilla_ChaosMode_h
#include "mozilla/Atomics.h"
#include "mozilla/EnumSet.h"
#include <stdint.h>
#include <stdlib.h>
namespace mozilla {
enum ChaosFeature {
None = 0x0,
// Altering thread scheduling.
ThreadScheduling = 0x1,
// Altering network request scheduling.
NetworkScheduling = 0x2,
// Altering timer scheduling.
TimerScheduling = 0x4,
// Read and write less-than-requested amounts.
IOAmounts = 0x8,
// Iterate over hash tables in random order.
HashTableIteration = 0x10,
// Randomly refuse to use cached version of image (when allowed by spec).
ImageCache = 0x20,
Any = 0xffffffff,
};
namespace detail {
extern MFBT_DATA Atomic<uint32_t> gChaosModeCounter;
extern MFBT_DATA ChaosFeature gChaosFeatures;
} // namespace detail
/**
* When "chaos mode" is activated, code that makes implicitly nondeterministic
* choices is encouraged to make random and extreme choices, to test more
@ -20,10 +45,37 @@ namespace mozilla {
class ChaosMode
{
public:
static bool isActive()
static void SetChaosFeature(ChaosFeature aChaosFeature)
{
// Flip this to true to activate chaos mode
return false;
detail::gChaosFeatures = aChaosFeature;
}
static bool isActive(ChaosFeature aFeature)
{
if (detail::gChaosModeCounter > 0) {
return true;
}
return detail::gChaosFeatures & aFeature;
}
/**
* Increase the chaos mode activation level. An equivalent number of
* calls to leaveChaosMode must be made in order to restore the original
* chaos mode state. If the activation level is nonzero all chaos mode
* features are activated.
*/
static void enterChaosMode()
{
detail::gChaosModeCounter++;
}
/**
* Decrease the chaos mode activation level. See enterChaosMode().
*/
static void leaveChaosMode()
{
MOZ_ASSERT(detail::gChaosModeCounter > 0);
detail::gChaosModeCounter--;
}
/**
@ -32,6 +84,7 @@ public:
*/
static uint32_t randomUint32LessThan(uint32_t aBound)
{
MOZ_ASSERT(aBound != 0);
return uint32_t(rand()) % aBound;
}
};

114
android/arm64-v8a/include/spidermonkey/mozilla/Char16.h Executable file → Normal file
View File

@ -17,47 +17,19 @@
* is a 16-bit code unit of a Unicode code point, not a "character".
*/
#ifdef _MSC_VER
/*
* C++11 says char16_t is a distinct builtin type, but Windows's yvals.h
* typedefs char16_t as an unsigned short. We would like to alias char16_t
* to Windows's 16-bit wchar_t so we can declare UTF-16 literals as constant
* expressions (and pass char16_t pointers to Windows APIs). We #define
* _CHAR16T here in order to prevent yvals.h from overriding our char16_t
* typedefs, which we set to wchar_t for C++ code.
*
* In addition, #defining _CHAR16T will prevent yvals.h from defining a
* char32_t type, so we have to undo that damage here and provide our own,
* which is identical to the yvals.h type.
*/
# define MOZ_UTF16_HELPER(s) L##s
# define _CHAR16T
typedef wchar_t char16_t;
typedef unsigned int char32_t;
#else
/* C++11 has a builtin char16_t type. */
# define MOZ_UTF16_HELPER(s) u##s
/**
* This macro is used to distinguish when char16_t would be a distinct
* typedef from wchar_t.
*/
# define MOZ_CHAR16_IS_NOT_WCHAR
# ifdef WIN32
# define MOZ_USE_CHAR16_WRAPPER
# endif
#endif
#ifdef MOZ_USE_CHAR16_WRAPPER
# include <string>
#ifdef WIN32
# define MOZ_USE_CHAR16_WRAPPER
# include <cstdint>
/**
* 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, but GCC
* follows 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.
* 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
{
@ -91,10 +63,6 @@ public:
{
return mPtr != nullptr;
}
operator std::wstring() const
{
return std::wstring(static_cast<const wchar_t*>(*this));
}
/* Explicit cast operators to allow things like (char16_t*)str. */
explicit operator char16_t*() const
@ -105,6 +73,30 @@ public:
{
return const_cast<wchar_t*>(static_cast<const wchar_t*>(*this));
}
explicit operator int() const
{
return reinterpret_cast<intptr_t>(mPtr);
}
explicit operator unsigned int() const
{
return reinterpret_cast<uintptr_t>(mPtr);
}
explicit operator long() const
{
return reinterpret_cast<intptr_t>(mPtr);
}
explicit operator unsigned long() const
{
return reinterpret_cast<uintptr_t>(mPtr);
}
explicit operator long long() const
{
return reinterpret_cast<intptr_t>(mPtr);
}
explicit operator unsigned long long() const
{
return reinterpret_cast<uintptr_t>(mPtr);
}
/**
* Some Windows API calls accept BYTE* but require that data actually be
@ -150,7 +142,27 @@ public:
{
return mPtr != nullptr;
}
char16ptr_t operator+(size_t aValue) const
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
{
return char16ptr_t(mPtr + aValue);
}
char16ptr_t operator+(unsigned long aValue) const
{
return char16ptr_t(mPtr + aValue);
}
char16ptr_t operator+(long long aValue) const
{
return char16ptr_t(mPtr + aValue);
}
char16ptr_t operator+(unsigned long long aValue) const
{
return char16ptr_t(mPtr + aValue);
}
@ -172,20 +184,10 @@ typedef const char16_t* char16ptr_t;
#endif
/*
* Macro arguments used in concatenation or stringification won't be expanded.
* Therefore, in order for |MOZ_UTF16(FOO)| to work as expected (which is to
* expand |FOO| before doing whatever |MOZ_UTF16| needs to do to it) a helper
* macro, |MOZ_UTF16_HELPER| needs to be inserted in between to allow the macro
* argument to expand. See "3.10.6 Separate Expansion of Macro Arguments" of the
* CPP manual for a more accurate and precise explanation.
*/
#define MOZ_UTF16(s) MOZ_UTF16_HELPER(s)
static_assert(sizeof(char16_t) == 2, "Is char16_t type 16 bits?");
static_assert(char16_t(-1) > char16_t(0), "Is char16_t type unsigned?");
static_assert(sizeof(MOZ_UTF16('A')) == 2, "Is char literal 16 bits?");
static_assert(sizeof(MOZ_UTF16("")[0]) == 2, "Is string char 16 bits?");
static_assert(sizeof(u'A') == 2, "Is unicode char literal 16 bits?");
static_assert(sizeof(u""[0]) == 2, "Is unicode string char 16 bits?");
#endif

View File

@ -11,6 +11,7 @@
#include <stdint.h>
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/IntegerTypeTraits.h"
namespace mozilla {
@ -525,7 +526,7 @@ public:
* argument is valid.
*/
template<typename U>
CheckedInt(U aValue)
MOZ_IMPLICIT CheckedInt(U aValue) MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT
: mValue(T(aValue)),
mIsValid(detail::IsInRange<T>(aValue))
{
@ -574,30 +575,35 @@ public:
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator +=(U aRhs);
CheckedInt& operator +=(const CheckedInt<T>& aRhs);
template<typename U>
friend CheckedInt<U> operator -(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator -=(U aRhs);
CheckedInt& operator -=(const CheckedInt<T>& aRhs);
template<typename U>
friend CheckedInt<U> operator *(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator *=(U aRhs);
CheckedInt& operator *=(const CheckedInt<T>& aRhs);
template<typename U>
friend CheckedInt<U> operator /(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator /=(U aRhs);
CheckedInt& operator /=(const CheckedInt<T>& aRhs);
template<typename U>
friend CheckedInt<U> operator %(const CheckedInt<U>& aLhs,
const CheckedInt<U>& aRhs);
template<typename U>
CheckedInt& operator %=(U aRhs);
CheckedInt& operator %=(const CheckedInt<T>& aRhs);
CheckedInt operator -() const
{
@ -662,17 +668,17 @@ private:
* The !=, <, <=, >, >= operators are disabled:
* see the comment on operator==.
*/
template<typename U> bool operator !=(U aOther) const MOZ_DELETE;
template<typename U> bool operator < (U aOther) const MOZ_DELETE;
template<typename U> bool operator <=(U aOther) const MOZ_DELETE;
template<typename U> bool operator > (U aOther) const MOZ_DELETE;
template<typename U> bool operator >=(U aOther) const MOZ_DELETE;
template<typename U> bool operator !=(U aOther) const = delete;
template<typename U> bool operator < (U aOther) const = delete;
template<typename U> bool operator <=(U aOther) const = delete;
template<typename U> bool operator > (U aOther) const = delete;
template<typename U> bool operator >=(U aOther) const = delete;
};
#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
template<typename T> \
inline CheckedInt<T> \
operator OP(const CheckedInt<T> &aLhs, const CheckedInt<T> &aRhs) \
operator OP(const CheckedInt<T>& aLhs, const CheckedInt<T>& aRhs) \
{ \
if (!detail::Is##NAME##Valid(aLhs.mValue, aRhs.mValue)) { \
return CheckedInt<T>(0, false); \
@ -723,23 +729,29 @@ castToCheckedInt(U aU)
return detail::CastToCheckedIntImpl<T, U>::run(aU);
}
#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
template<typename T> \
template<typename U> \
CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U aRhs) \
{ \
*this = *this OP castToCheckedInt<T>(aRhs); \
return *this; \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(const CheckedInt<T> &aLhs, U aRhs) \
{ \
return aLhs OP castToCheckedInt<T>(aRhs); \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(U aLhs, const CheckedInt<T> &aRhs) \
{ \
return castToCheckedInt<T>(aLhs) OP aRhs; \
#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
template<typename T> \
template<typename U> \
CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U aRhs) \
{ \
*this = *this OP castToCheckedInt<T>(aRhs); \
return *this; \
} \
template<typename T> \
CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(const CheckedInt<T>& aRhs) \
{ \
*this = *this OP aRhs; \
return *this; \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(const CheckedInt<T>& aLhs, U aRhs) \
{ \
return aLhs OP castToCheckedInt<T>(aRhs); \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(U aLhs, const CheckedInt<T>& aRhs) \
{ \
return castToCheckedInt<T>(aLhs) OP aRhs; \
}
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
@ -752,14 +764,14 @@ MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(%, %=)
template<typename T, typename U>
inline bool
operator ==(const CheckedInt<T> &aLhs, U aRhs)
operator ==(const CheckedInt<T>& aLhs, U aRhs)
{
return aLhs == castToCheckedInt<T>(aRhs);
}
template<typename T, typename U>
inline bool
operator ==(U aLhs, const CheckedInt<T> &aRhs)
operator ==(U aLhs, const CheckedInt<T>& aRhs)
{
return castToCheckedInt<T>(aLhs) == aRhs;
}

View File

@ -10,40 +10,30 @@
#define mozilla_Compiler_h
#define MOZ_IS_GCC 0
#define MOS_IS_MSVC 0
#define MOZ_IS_MSVC 0
#if !defined(__clang__) && defined(__GNUC__)
# undef MOZ_IS_GCC
# define MOZ_IS_GCC 1
/*
* This macro should simplify gcc version checking. For example, to check
* for gcc 4.5.1 or later, check `#if MOZ_GCC_VERSION_AT_LEAST(4, 5, 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)))
# if !MOZ_GCC_VERSION_AT_LEAST(4, 4, 0)
# error "mfbt (and Gecko) require at least gcc 4.4 to build."
# define MOZ_GCC_VERSION_AT_MOST(major, minor, patchlevel) \
((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) \
<= ((major) * 10000 + (minor) * 100 + (patchlevel)))
# if !MOZ_GCC_VERSION_AT_LEAST(4, 8, 0)
# error "mfbt (and Gecko) require at least gcc 4.8 to build."
# endif
#elif defined(_MSC_VER)
# undef MOZ_IS_MSVC
# define MOZ_IS_MSVC 1
/*
* This macro should simplify MSVC version checking. For example, to check
* for VC10 or later, check `#ifdef MOZ_MSVC_VERSION_AT_LEAST(10)`.
*/
# define MOZ_MSVC_VERSION_AT_LEAST(version) \
(version == 10 ? _MSC_VER >= 1600 : \
(version == 11 ? _MSC_VER >= 1700 : \
(version == 12 ? _MSC_VER >= 1800 : \
(version == 13 ? _MSC_VER >= 1900 : \
0))))
# if !MOZ_MSVC_VERSION_AT_LEAST(10)
# error "mfbt (and Gecko) require at least MSVC 2010 RTM to build."
# endif
#endif

View File

@ -9,8 +9,8 @@
#ifndef mozilla_Compression_h_
#define mozilla_Compression_h_
#include "mozilla/Types.h"
#include "mozilla/Assertions.h"
#include "mozilla/Types.h"
namespace mozilla {
namespace Compression {
@ -61,8 +61,7 @@ public:
/**
* If the source stream is malformed, the function will stop decoding
* and return a negative result, indicating the byte position of the
* faulty instruction
* and return false.
*
* This function never writes outside of provided buffers, and never
* modifies input buffer.
@ -71,9 +70,9 @@ public:
* minimum of |aOutputSize| bytes.
*
* @param aOutputSize is the output size, therefore the original size
* @return the number of bytes read in the source buffer
* @return true on success, false on failure
*/
static MFBT_API bool
static MFBT_API MOZ_MUST_USE bool
decompress(const char* aSource, char* aDest, size_t aOutputSize);
/**
@ -91,8 +90,9 @@ public:
* already allocated)
* @param aOutputSize the actual number of bytes decoded in the destination
* buffer (necessarily <= aMaxOutputSize)
* @return true on success, false on failure
*/
static MFBT_API bool
static MFBT_API MOZ_MUST_USE bool
decompress(const char* aSource, size_t aInputSize, char* aDest,
size_t aMaxOutputSize, size_t* aOutputSize);

View File

@ -1,16 +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/. */
/* mfbt math constants. */
#ifndef mozilla_Constants_h
#define mozilla_Constants_h
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
#endif /* mozilla_Constants_h */

View File

@ -24,17 +24,19 @@ namespace mozilla {
* DebugOnly<bool> check = func();
* MOZ_ASSERT(check);
*
* more concisely than declaring |check| conditional on #ifdef DEBUG, but also
* without allocating storage space for |check| in release builds.
* more concisely than declaring |check| conditional on #ifdef DEBUG.
*
* DebugOnly instances can only be coerced to T in debug builds. In release
* builds they don't have a value, so type coercion is not well defined.
*
* Note that DebugOnly instances still take up one byte of space, plus padding,
* when used as members of structs.
* NOTE: DebugOnly instances still take up one byte of space, plus padding, even
* in optimized, non-DEBUG builds (see bug 1253094 comment 37 for more info).
* For this reason the class is MOZ_STACK_CLASS to prevent consumers using
* DebugOnly for struct/class members and unwittingly inflating the size of
* their objects in release builds.
*/
template<typename T>
class DebugOnly
class MOZ_STACK_CLASS DebugOnly
{
public:
#ifdef DEBUG
@ -51,6 +53,10 @@ public:
void operator++(int) { value++; }
void operator--(int) { value--; }
// Do not define operator+=(), etc. here. These will coerce via the
// implicit cast and built-in operators. Defining explicit methods here
// will create ambiguity the compiler can't deal with.
T* operator&() { return &value; }
operator T&() { return value; }
@ -66,6 +72,11 @@ public:
DebugOnly& operator=(const T&) { return *this; }
void operator++(int) { }
void operator--(int) { }
DebugOnly& operator+=(const T&) { return *this; }
DebugOnly& operator-=(const T&) { return *this; }
DebugOnly& operator&=(const T&) { return *this; }
DebugOnly& operator|=(const T&) { return *this; }
DebugOnly& operator^=(const T&) { return *this; }
#endif
/*
@ -76,6 +87,6 @@ public:
~DebugOnly() {}
};
}
} // namespace mozilla
#endif /* mozilla_DebugOnly_h */

View File

@ -30,8 +30,8 @@
/**
* Imported from:
* http://src.chromium.org/viewvc/blink/trunk/Source/core/platform/Decimal.h
* Check hg log for the svn rev of the last update from Blink core.
* https://chromium.googlesource.com/chromium/src.git/+/master/third_party/WebKit/Source/platform/Decimal.h
* Check UPSTREAM-GIT-SHA for the commit ID of the last update from Blink core.
*/
#ifndef Decimal_h
@ -48,13 +48,21 @@
#define ASSERT MOZ_ASSERT
#endif
// To use WTF_MAKE_FAST_ALLOCATED we'd need:
// http://src.chromium.org/viewvc/blink/trunk/Source/wtf/FastMalloc.h
// Since we don't allocate Decimal objects, no need.
#define WTF_MAKE_FAST_ALLOCATED \
void ignore_this_dummy_method() MOZ_DELETE
#define PLATFORM_EXPORT
namespace WebCore {
// To use USING_FAST_MALLOC we'd need:
// https://chromium.googlesource.com/chromium/src.git/+/master/third_party/WebKit/Source/wtf/Allocator.h
// Since we don't allocate Decimal objects, no need.
#define USING_FAST_MALLOC(type) \
void ignore_this_dummy_method() = delete
#define DISALLOW_NEW() \
private: \
void* operator new(size_t) = delete; \
void* operator new(size_t, void*) = delete; \
public:
namespace blink {
namespace DecimalPrivate {
class SpecialValueHandler;
@ -65,8 +73,8 @@ class SpecialValueHandler;
// FIXME: Once all C++ compiler support decimal type, we should replace this
// class to compiler supported one. See below URI for current status of decimal
// type for C++: // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1977.html
class Decimal {
WTF_MAKE_FAST_ALLOCATED;
class PLATFORM_EXPORT Decimal {
USING_FAST_MALLOC(Decimal);
public:
enum Sign {
Positive,
@ -75,6 +83,7 @@ public:
// You should not use EncodedData other than unit testing.
class EncodedData {
DISALLOW_NEW();
// For accessing FormatClass.
friend class Decimal;
friend class DecimalPrivate::SpecialValueHandler;
@ -151,7 +160,7 @@ public:
bool isZero() const { return m_data.isZero(); }
MFBT_API Decimal abs() const;
MFBT_API Decimal ceiling() const;
MFBT_API Decimal ceil() const;
MFBT_API Decimal floor() const;
MFBT_API Decimal remainder(const Decimal&) const;
MFBT_API Decimal round() const;
@ -196,13 +205,13 @@ private:
EncodedData m_data;
};
} // namespace WebCore
} // namespace blink
namespace mozilla {
typedef WebCore::Decimal Decimal;
}
typedef blink::Decimal Decimal;
} // namespace mozilla
#undef WTF_MAKE_FAST_ALLOCATED
#undef USING_FAST_MALLOC
#ifdef DEFINED_ASSERT_FOR_DECIMAL_H
#undef DEFINED_ASSERT_FOR_DECIMAL_H
@ -210,4 +219,3 @@ namespace mozilla {
#endif
#endif // Decimal_h

View File

@ -61,8 +61,8 @@
* };
*/
#ifndef mozilla_Endian_h
#define mozilla_Endian_h
#ifndef mozilla_EndianUtils_h
#define mozilla_EndianUtils_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
@ -73,7 +73,7 @@
#include <stdint.h>
#include <string.h>
#if defined(_MSC_VER) && _MSC_VER >= 1300
#if defined(_MSC_VER)
# include <stdlib.h>
# pragma intrinsic(_byteswap_ushort)
# pragma intrinsic(_byteswap_ulong)
@ -89,6 +89,8 @@
#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
@ -148,11 +150,9 @@
# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16
# endif
#elif defined(__GNUC__)
# if MOZ_GCC_VERSION_AT_LEAST(4, 8, 0)
# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16
# endif
# 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 {
@ -344,37 +344,37 @@ class Endian : private EndianUtils
{
protected:
/** Read a uint16_t in ThisEndian endianness from |aPtr| and return it. */
static MOZ_WARN_UNUSED_RESULT uint16_t readUint16(const void* aPtr)
static MOZ_MUST_USE uint16_t readUint16(const void* aPtr)
{
return read<uint16_t>(aPtr);
}
/** Read a uint32_t in ThisEndian endianness from |aPtr| and return it. */
static MOZ_WARN_UNUSED_RESULT uint32_t readUint32(const void* aPtr)
static MOZ_MUST_USE uint32_t readUint32(const void* aPtr)
{
return read<uint32_t>(aPtr);
}
/** Read a uint64_t in ThisEndian endianness from |aPtr| and return it. */
static MOZ_WARN_UNUSED_RESULT uint64_t readUint64(const void* aPtr)
static MOZ_MUST_USE uint64_t readUint64(const void* aPtr)
{
return read<uint64_t>(aPtr);
}
/** Read an int16_t in ThisEndian endianness from |aPtr| and return it. */
static MOZ_WARN_UNUSED_RESULT int16_t readInt16(const void* aPtr)
static MOZ_MUST_USE int16_t readInt16(const void* aPtr)
{
return read<int16_t>(aPtr);
}
/** Read an int32_t in ThisEndian endianness from |aPtr| and return it. */
static MOZ_WARN_UNUSED_RESULT int32_t readInt32(const void* aPtr)
static MOZ_MUST_USE int32_t readInt32(const void* aPtr)
{
return read<uint32_t>(aPtr);
}
/** Read an int64_t in ThisEndian endianness from |aPtr| and return it. */
static MOZ_WARN_UNUSED_RESULT int64_t readInt64(const void* aPtr)
static MOZ_MUST_USE int64_t readInt64(const void* aPtr)
{
return read<int64_t>(aPtr);
}
@ -423,7 +423,7 @@ protected:
* format for transmission.
*/
template<typename T>
MOZ_WARN_UNUSED_RESULT static T swapToLittleEndian(T aValue)
MOZ_MUST_USE static T swapToLittleEndian(T aValue)
{
return maybeSwap<ThisEndian, Little>(aValue);
}
@ -453,7 +453,7 @@ protected:
* Converts a value of type T to big-endian format.
*/
template<typename T>
MOZ_WARN_UNUSED_RESULT static T swapToBigEndian(T aValue)
MOZ_MUST_USE static T swapToBigEndian(T aValue)
{
return maybeSwap<ThisEndian, Big>(aValue);
}
@ -485,7 +485,7 @@ protected:
*/
template<typename T>
MOZ_WARN_UNUSED_RESULT static T swapToNetworkOrder(T aValue)
MOZ_MUST_USE static T swapToNetworkOrder(T aValue)
{
return swapToBigEndian(aValue);
}
@ -508,7 +508,7 @@ protected:
* Converts a value of type T from little-endian format.
*/
template<typename T>
MOZ_WARN_UNUSED_RESULT static T swapFromLittleEndian(T aValue)
MOZ_MUST_USE static T swapFromLittleEndian(T aValue)
{
return maybeSwap<Little, ThisEndian>(aValue);
}
@ -538,7 +538,7 @@ protected:
* Converts a value of type T from big-endian format.
*/
template<typename T>
MOZ_WARN_UNUSED_RESULT static T swapFromBigEndian(T aValue)
MOZ_MUST_USE static T swapFromBigEndian(T aValue)
{
return maybeSwap<Big, ThisEndian>(aValue);
}
@ -569,7 +569,7 @@ protected:
* in network code.
*/
template<typename T>
MOZ_WARN_UNUSED_RESULT static T swapFromNetworkOrder(T aValue)
MOZ_MUST_USE static T swapFromNetworkOrder(T aValue)
{
return swapFromBigEndian(aValue);
}
@ -615,9 +615,9 @@ private:
memcpy(aPtr, &tmp, sizeof(T));
}
Endian() MOZ_DELETE;
Endian(const Endian& aTther) MOZ_DELETE;
void operator=(const Endian& aOther) MOZ_DELETE;
Endian() = delete;
Endian(const Endian& aTther) = delete;
void operator=(const Endian& aOther) = delete;
};
template<Endianness ThisEndian>
@ -643,15 +643,15 @@ public:
} /* namespace detail */
class LittleEndian MOZ_FINAL : public detail::EndianReadWrite<detail::Little>
class LittleEndian final : public detail::EndianReadWrite<detail::Little>
{};
class BigEndian MOZ_FINAL : public detail::EndianReadWrite<detail::Big>
class BigEndian final : public detail::EndianReadWrite<detail::Big>
{};
typedef BigEndian NetworkEndian;
class NativeEndian MOZ_FINAL : public detail::Endian<MOZ_NATIVE_ENDIANNESS>
class NativeEndian final : public detail::Endian<MOZ_NATIVE_ENDIANNESS>
{
private:
typedef detail::Endian<MOZ_NATIVE_ENDIANNESS> super;
@ -692,4 +692,4 @@ public:
} /* namespace mozilla */
#endif /* mozilla_Endian_h */
#endif /* mozilla_EndianUtils_h */

162
android/arm64-v8a/include/spidermonkey/mozilla/EnumSet.h Executable file → Normal file
View File

@ -12,6 +12,8 @@
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include <initializer_list>
#include <stdint.h>
namespace mozilla {
@ -27,7 +29,9 @@ class EnumSet
public:
EnumSet()
: mBitField(0)
{ }
{
initVersion();
}
MOZ_IMPLICIT EnumSet(T aEnum)
: mBitField(bitFor(aEnum))
@ -36,30 +40,48 @@ public:
EnumSet(T aEnum1, T aEnum2)
: mBitField(bitFor(aEnum1) |
bitFor(aEnum2))
{ }
{
initVersion();
}
EnumSet(T aEnum1, T aEnum2, T aEnum3)
: mBitField(bitFor(aEnum1) |
bitFor(aEnum2) |
bitFor(aEnum3))
{ }
{
initVersion();
}
EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4)
: mBitField(bitFor(aEnum1) |
bitFor(aEnum2) |
bitFor(aEnum3) |
bitFor(aEnum4))
{ }
: mBitField(bitFor(aEnum1) |
bitFor(aEnum2) |
bitFor(aEnum3) |
bitFor(aEnum4))
{
initVersion();
}
MOZ_IMPLICIT EnumSet(std::initializer_list<T> list)
: mBitField(0)
{
for (auto value : list) {
(*this) += value;
}
initVersion();
}
EnumSet(const EnumSet& aEnumSet)
: mBitField(aEnumSet.mBitField)
{ }
: mBitField(aEnumSet.mBitField)
{
initVersion();
}
/**
* Add an element
*/
void operator+=(T aEnum)
{
incVersion();
mBitField |= bitFor(aEnum);
}
@ -78,6 +100,7 @@ public:
*/
void operator+=(const EnumSet<T> aEnumSet)
{
incVersion();
mBitField |= aEnumSet.mBitField;
}
@ -96,6 +119,7 @@ public:
*/
void operator-=(T aEnum)
{
incVersion();
mBitField &= ~(bitFor(aEnum));
}
@ -114,6 +138,7 @@ public:
*/
void operator-=(const EnumSet<T> aEnumSet)
{
incVersion();
mBitField &= ~(aEnumSet.mBitField);
}
@ -127,11 +152,21 @@ public:
return result;
}
/**
* Clear
*/
void clear()
{
incVersion();
mBitField = 0;
}
/**
* Intersection
*/
void operator&=(const EnumSet<T> aEnumSet)
{
incVersion();
mBitField &= aEnumSet.mBitField;
}
@ -164,7 +199,7 @@ public:
/**
* Return the number of elements in the set.
*/
uint8_t size()
uint8_t size() const
{
uint8_t count = 0;
for (uint32_t bitField = mBitField; bitField; bitField >>= 1) {
@ -187,18 +222,121 @@ public:
void deserialize(uint32_t aValue)
{
incVersion();
mBitField = aValue;
}
class ConstIterator
{
const EnumSet<T>* mSet;
uint32_t mPos;
#ifdef DEBUG
uint64_t mVersion;
#endif
void checkVersion() {
// Check that the set has not been modified while being iterated.
MOZ_ASSERT_IF(mSet, mSet->mVersion == mVersion);
}
public:
ConstIterator(const EnumSet<T>& aSet, uint32_t aPos)
: mSet(&aSet), mPos(aPos)
{
#ifdef DEBUG
mVersion = mSet->mVersion;
#endif
MOZ_ASSERT(aPos <= kMaxBits);
if (aPos != kMaxBits && !mSet->contains(T(mPos)))
++*this;
}
ConstIterator(const ConstIterator& aOther)
: mSet(aOther.mSet), mPos(aOther.mPos)
{
#ifdef DEBUG
mVersion = aOther.mVersion;
checkVersion();
#endif
}
ConstIterator(ConstIterator&& aOther)
: mSet(aOther.mSet), mPos(aOther.mPos)
{
#ifdef DEBUG
mVersion = aOther.mVersion;
checkVersion();
#endif
aOther.mSet = nullptr;
}
~ConstIterator() {
checkVersion();
}
bool operator==(const ConstIterator& other) {
MOZ_ASSERT(mSet == other.mSet);
checkVersion();
return mPos == other.mPos;
}
bool operator!=(const ConstIterator& other) {
return !(*this == other);
}
T operator*() {
MOZ_ASSERT(mSet);
MOZ_ASSERT(mPos < kMaxBits);
MOZ_ASSERT(mSet->contains(T(mPos)));
checkVersion();
return T(mPos);
}
ConstIterator& operator++() {
MOZ_ASSERT(mSet);
MOZ_ASSERT(mPos < kMaxBits);
checkVersion();
do {
mPos++;
} while (mPos < kMaxBits && !mSet->contains(T(mPos)));
return *this;
}
};
ConstIterator begin() const {
return ConstIterator(*this, 0);
}
ConstIterator end() const {
return ConstIterator(*this, kMaxBits);
}
private:
static uint32_t bitFor(T aEnum)
{
uint32_t bitNumber = (uint32_t)aEnum;
MOZ_ASSERT(bitNumber < 32);
MOZ_ASSERT(bitNumber < kMaxBits);
return 1U << bitNumber;
}
void initVersion() {
#ifdef DEBUG
mVersion = 0;
#endif
}
void incVersion() {
#ifdef DEBUG
mVersion++;
#endif
}
static const size_t kMaxBits = 32;
uint32_t mBitField;
#ifdef DEBUG
uint64_t mVersion;
#endif
};
} // namespace mozilla

View File

@ -0,0 +1,70 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Type traits for enums. */
#ifndef mozilla_EnumTypeTraits_h
#define mozilla_EnumTypeTraits_h
#include <type_traits>
namespace mozilla {
namespace detail {
template<size_t EnumSize, bool EnumSigned, size_t StorageSize, bool StorageSigned>
struct EnumFitsWithinHelper;
// Signed enum, signed storage.
template<size_t EnumSize, size_t StorageSize>
struct EnumFitsWithinHelper<EnumSize, true, StorageSize, true>
: public std::integral_constant<bool, (EnumSize <= StorageSize)>
{};
// Signed enum, unsigned storage.
template<size_t EnumSize, size_t StorageSize>
struct EnumFitsWithinHelper<EnumSize, true, StorageSize, false>
: public std::integral_constant<bool, false>
{};
// Unsigned enum, signed storage.
template<size_t EnumSize, size_t StorageSize>
struct EnumFitsWithinHelper<EnumSize, false, StorageSize, true>
: public std::integral_constant<bool, (EnumSize * 2 <= StorageSize)>
{};
// Unsigned enum, unsigned storage.
template<size_t EnumSize, size_t StorageSize>
struct EnumFitsWithinHelper<EnumSize, false, StorageSize, false>
: public std::integral_constant<bool, (EnumSize <= StorageSize)>
{};
} // namespace detail
/*
* Type trait that determines whether the enum type T can fit within the
* integral type Storage without data loss. This trait should be used with
* caution with an enum type whose underlying type has not been explicitly
* specified: for such enums, the C++ implementation is free to choose a type
* no smaller than int whose range encompasses all possible values of the enum.
* So for an enum with only small non-negative values, the underlying type may
* be either int or unsigned int, depending on the whims of the implementation.
*/
template<typename T, typename Storage>
struct EnumTypeFitsWithin
: public detail::EnumFitsWithinHelper<
sizeof(T),
std::is_signed<typename std::underlying_type<T>::type>::value,
sizeof(Storage),
std::is_signed<Storage>::value
>
{
static_assert(std::is_enum<T>::value, "must provide an enum type");
static_assert(std::is_integral<Storage>::value, "must provide an integral type");
};
} // namespace mozilla
#endif /* mozilla_EnumTypeTraits_h */

View File

@ -10,14 +10,13 @@
#define mozilla_EnumeratedArray_h
#include "mozilla/Array.h"
#include "mozilla/TypedEnum.h"
#include "mozilla/Move.h"
namespace mozilla {
/**
* EnumeratedArray is a fixed-size array container for use when an
* array is indexed by a specific enum class, as currently implemented
* by MOZ_BEGIN_ENUM_CLASS.
* array is indexed by a specific enum class.
*
* This provides type safety by guarding at compile time against accidentally
* indexing such arrays with unrelated values. This also removes the need
@ -27,11 +26,11 @@ namespace mozilla {
*
* Example:
*
* MOZ_BEGIN_ENUM_CLASS(AnimalSpecies)
* enum class AnimalSpecies {
* Cow,
* Sheep,
* Count
* MOZ_END_ENUM_CLASS(AnimalSpecies)
* };
*
* EnumeratedArray<AnimalSpecies, AnimalSpecies::Count, int> headCount;
*
@ -40,7 +39,7 @@ namespace mozilla {
*
*/
template<typename IndexType,
MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE(IndexType) SizeAsEnumValue,
IndexType SizeAsEnumValue,
typename ValueType>
class EnumeratedArray
{
@ -48,11 +47,18 @@ public:
static const size_t kSize = size_t(SizeAsEnumValue);
private:
Array<ValueType, kSize> mArray;
typedef Array<ValueType, kSize> ArrayType;
ArrayType mArray;
public:
EnumeratedArray() {}
template <typename... Args>
MOZ_IMPLICIT EnumeratedArray(Args&&... aArgs)
: mArray{mozilla::Forward<Args>(aArgs)...}
{}
explicit EnumeratedArray(const EnumeratedArray& aOther)
{
for (size_t i = 0; i < kSize; i++) {
@ -60,6 +66,13 @@ public:
}
}
EnumeratedArray(EnumeratedArray&& aOther)
{
for (size_t i = 0; i < kSize; i++) {
mArray[i] = Move(aOther.mArray[i]);
}
}
ValueType& operator[](IndexType aIndex)
{
return mArray[size_t(aIndex)];
@ -69,6 +82,27 @@ public:
{
return mArray[size_t(aIndex)];
}
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.
iterator begin() { return mArray.begin(); }
const_iterator begin() const { return mArray.begin(); }
const_iterator cbegin() const { return mArray.cbegin(); }
iterator end() { return mArray.end(); }
const_iterator end() const { return mArray.end(); }
const_iterator cend() const { return mArray.cend(); }
// Methods for reverse iterating.
reverse_iterator rbegin() { return mArray.rbegin(); }
const_reverse_iterator rbegin() const { return mArray.rbegin(); }
const_reverse_iterator crbegin() const { return mArray.crbegin(); }
reverse_iterator rend() { return mArray.rend(); }
const_reverse_iterator rend() const { return mArray.rend(); }
const_reverse_iterator crend() const { return mArray.crend(); }
};
} // namespace mozilla

View File

@ -0,0 +1,201 @@
/* -*- 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/. */
/* Iterator over contiguous enum values */
/*
* Implements generator functions that create a range to iterate over the values
* of a scoped or unscoped enum. Unlike IntegerRange, which can only function on
* the underlying integral type, the elements of the generated sequence will
* have the type of the enum in question.
*
* Note that the enum values should be contiguous in the iterated range;
* unfortunately there exists no way for EnumeratedRange to enforce this
* either dynamically or at compile time.
*/
#ifndef mozilla_EnumeratedRange_h
#define mozilla_EnumeratedRange_h
#include <type_traits>
#include "mozilla/ReverseIterator.h"
namespace mozilla {
namespace detail {
template<typename EnumTypeT>
class EnumeratedIterator
{
public:
typedef typename std::underlying_type<EnumTypeT>::type IntTypeT;
template<typename EnumType>
explicit EnumeratedIterator(EnumType aCurrent)
: mCurrent(aCurrent) { }
template<typename EnumType>
explicit EnumeratedIterator(const EnumeratedIterator<EnumType>& aOther)
: mCurrent(aOther.mCurrent) { }
EnumTypeT operator*() const { return mCurrent; }
/* Increment and decrement operators */
EnumeratedIterator& operator++()
{
mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1));
return *this;
}
EnumeratedIterator& operator--()
{
mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1));
return *this;
}
EnumeratedIterator operator++(int)
{
auto ret = *this;
mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1));
return ret;
}
EnumeratedIterator operator--(int)
{
auto ret = *this;
mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1));
return ret;
}
/* Comparison operators */
template<typename EnumType>
friend bool operator==(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2);
template<typename EnumType>
friend bool operator!=(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2);
template<typename EnumType>
friend bool operator<(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2);
template<typename EnumType>
friend bool operator<=(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2);
template<typename EnumType>
friend bool operator>(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2);
template<typename EnumType>
friend bool operator>=(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2);
private:
EnumTypeT mCurrent;
};
template<typename EnumType>
bool operator==(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2)
{
return aIter1.mCurrent == aIter2.mCurrent;
}
template<typename EnumType>
bool operator!=(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2)
{
return aIter1.mCurrent != aIter2.mCurrent;
}
template<typename EnumType>
bool operator<(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2)
{
return aIter1.mCurrent < aIter2.mCurrent;
}
template<typename EnumType>
bool operator<=(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2)
{
return aIter1.mCurrent <= aIter2.mCurrent;
}
template<typename EnumType>
bool operator>(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2)
{
return aIter1.mCurrent > aIter2.mCurrent;
}
template<typename EnumType>
bool operator>=(const EnumeratedIterator<EnumType>& aIter1,
const EnumeratedIterator<EnumType>& aIter2)
{
return aIter1.mCurrent >= aIter2.mCurrent;
}
template<typename EnumTypeT>
class EnumeratedRange
{
public:
typedef EnumeratedIterator<EnumTypeT> iterator;
typedef EnumeratedIterator<EnumTypeT> const_iterator;
typedef ReverseIterator<iterator> reverse_iterator;
typedef ReverseIterator<const_iterator> const_reverse_iterator;
template<typename EnumType>
EnumeratedRange(EnumType aBegin, EnumType aEnd)
: mBegin(aBegin), mEnd(aEnd) { }
iterator begin() const { return iterator(mBegin); }
const_iterator cbegin() const { return begin(); }
iterator end() const { return iterator(mEnd); }
const_iterator cend() const { return end(); }
reverse_iterator rbegin() const { return reverse_iterator(mEnd); }
const_reverse_iterator crbegin() const { return rbegin(); }
reverse_iterator rend() const { return reverse_iterator(mBegin); }
const_reverse_iterator crend() const { return rend(); }
private:
EnumTypeT mBegin;
EnumTypeT mEnd;
};
} // 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"
#endif
// Create a range to iterate from aBegin to aEnd, exclusive.
template<typename EnumType>
inline detail::EnumeratedRange<EnumType>
MakeEnumeratedRange(EnumType aBegin, EnumType aEnd)
{
MOZ_ASSERT(aBegin <= aEnd, "Cannot generate invalid, unbounded range!");
return detail::EnumeratedRange<EnumType>(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<typename EnumType>
inline detail::EnumeratedRange<EnumType>
MakeEnumeratedRange(EnumType aEnd)
{
return MakeEnumeratedRange(EnumType(0), aEnd);
}
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
} // namespace mozilla
#endif // mozilla_EnumeratedRange_h

View File

@ -0,0 +1,379 @@
/* -*- 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_FastBernoulliTrial_h
#define mozilla_FastBernoulliTrial_h
#include "mozilla/Assertions.h"
#include "mozilla/XorShift128PlusRNG.h"
#include <cmath>
#include <stdint.h>
namespace mozilla {
/**
* class FastBernoulliTrial: Efficient sampling with uniform probability
*
* When gathering statistics about a program's behavior, we may be observing
* events that occur very frequently (e.g., function calls or memory
* allocations) and we may be gathering information that is somewhat expensive
* to produce (e.g., call stacks). Sampling all the events could have a
* significant impact on the program's performance.
*
* Why not just sample every N'th event? This technique is called "systematic
* sampling"; it's simple and efficient, and it's fine if we imagine a
* patternless stream of events. But what if we're sampling allocations, and the
* program happens to have a loop where each iteration does exactly N
* allocations? You would end up sampling the same allocation every time through
* the loop; the entire rest of the loop becomes invisible to your measurements!
* More generally, if each iteration does M allocations, and M and N have any
* common divisor at all, most allocation sites will never be sampled. If
* they're both even, say, the odd-numbered allocations disappear from your
* results.
*
* Ideally, we'd like each event to have some probability P of being sampled,
* independent of its neighbors and of its position in the sequence. This is
* called "Bernoulli sampling", and it doesn't suffer from any of the problems
* mentioned above.
*
* One disadvantage of Bernoulli sampling is that you can't be sure exactly how
* many samples you'll get: technically, it's possible that you might sample
* none of them, or all of them. But if the number of events N is large, these
* aren't likely outcomes; you can generally expect somewhere around P * N
* events to be sampled.
*
* The other disadvantage of Bernoulli sampling is that you have to generate a
* random number for every event, which can be slow.
*
* [significant pause]
*
* BUT NOT WITH THIS CLASS! FastBernoulliTrial lets you do true Bernoulli
* sampling, while generating a fresh random number only when we do decide to
* sample an event, not on every trial. When it decides not to sample, a call to
* |FastBernoulliTrial::trial| is nothing but decrementing a counter and
* comparing it to zero. So the lower your sampling probability is, the less
* overhead FastBernoulliTrial imposes.
*
* Probabilities of 0 and 1 are handled efficiently. (In neither case need we
* ever generate a random number at all.)
*
* The essential API:
*
* - FastBernoulliTrial(double P)
* Construct an instance that selects events with probability P.
*
* - FastBernoulliTrial::trial()
* Return true with probability P. Call this each time an event occurs, to
* decide whether to sample it or not.
*
* - FastBernoulliTrial::trial(size_t n)
* Equivalent to calling trial() |n| times, and returning true if any of those
* calls do. However, like trial, this runs in fast constant time.
*
* What is this good for? In some applications, some events are "bigger" than
* others. For example, large allocations are more significant than small
* allocations. Perhaps we'd like to imagine that we're drawing allocations
* from a stream of bytes, and performing a separate Bernoulli trial on every
* byte from the stream. We can accomplish this by calling |t.trial(S)| for
* the number of bytes S, and sampling the event if that returns true.
*
* Of course, this style of sampling needs to be paired with analysis and
* presentation that makes the size of the event apparent, lest trials with
* large values for |n| appear to be indistinguishable from those with small
* values for |n|.
*/
class FastBernoulliTrial {
/*
* This comment should just read, "Generate skip counts with a geometric
* distribution", and leave everyone to go look that up and see why it's the
* right thing to do, if they don't know already.
*
* BUT IF YOU'RE CURIOUS, COMMENTS ARE FREE...
*
* Instead of generating a fresh random number for every trial, we can
* randomly generate a count of how many times we should return false before
* the next time we return true. We call this a "skip count". Once we've
* returned true, we generate a fresh skip count, and begin counting down
* again.
*
* Here's an awesome fact: by exercising a little care in the way we generate
* skip counts, we can produce results indistinguishable from those we would
* get "rolling the dice" afresh for every trial.
*
* In short, skip counts in Bernoulli trials of probability P obey a geometric
* distribution. If a random variable X is uniformly distributed from [0..1),
* then std::floor(std::log(X) / std::log(1-P)) has the appropriate geometric
* distribution for the skip counts.
*
* Why that formula?
*
* Suppose we're to return |true| with some probability P, say, 0.3. Spread
* all possible futures along a line segment of length 1. In portion P of
* those cases, we'll return true on the next call to |trial|; the skip count
* is 0. For the remaining portion 1-P of cases, the skip count is 1 or more.
*
* skip: 0 1 or more
* |------------------^-----------------------------------------|
* portion: 0.3 0.7
* 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.
*
* skip: 0 1 2 or more
* |------------------^------------^----------------------------|
* portion: 0.3 0.7 * 0.3 0.7 * 0.7
* P (1-P)*P (1-P)^2
*
* We can continue to subdivide:
*
* skip >= 0: |------------------------------------------------- (1-P)^0 --|
* skip >= 1: | ------------------------------- (1-P)^1 --|
* skip >= 2: | ------------------ (1-P)^2 --|
* skip >= 3: | ^ ---------- (1-P)^3 --|
* skip >= 4: | . --- (1-P)^4 --|
* .
* ^X, see below
*
* In other words, the likelihood of the next n calls to |trial| returning
* false is (1-P)^n. The longer a run we require, the more the likelihood
* drops. Further calls may return false too, but this is the probability
* we'll skip at least n.
*
* This is interesting, because we can pick a point along this line segment
* and see which skip count's range it falls within; the point X above, for
* example, is within the ">= 2" range, but not within the ">= 3" range, so it
* designates a skip count of 2. So if we pick points on the line at random
* and use the skip counts they fall under, that will be indistinguishable
* from generating a fresh random number between 0 and 1 for each trial and
* comparing it to P.
*
* So to find the skip count for a point X, we must ask: To what whole power
* must we raise 1-P such that we include X, but the next power would exclude
* 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.
*
* 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,
* return true and compute a new skip count. Since each trial is independent,
* it doesn't matter by how much n overshoots the skip count; we can actually
* compute a new skip count at *any* time without affecting the distribution.
* This is really beautiful.
*/
public:
/**
* Construct a fast Bernoulli trial generator. Calls to |trial()| return true
* with probability |aProbability|. Use |aState0| and |aState1| to seed the
* 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)
{
setProbability(aProbability);
}
/**
* Return true with probability |mProbability|. Call this each time an event
* occurs, to decide whether to sample it or not. The lower |mProbability| is,
* the faster this function runs.
*/
bool trial() {
if (mSkipCount) {
mSkipCount--;
return false;
}
return chooseSkipCount();
}
/**
* Equivalent to calling trial() |n| times, and returning true if any of those
* calls do. However, like trial, this runs in fast constant time.
*
* What is this good for? In some applications, some events are "bigger" than
* others. For example, large allocations are more significant than small
* allocations. Perhaps we'd like to imagine that we're drawing allocations
* from a stream of bytes, and performing a separate Bernoulli trial on every
* byte from the stream. We can accomplish this by calling |t.trial(S)| for
* the number of bytes S, and sampling the event if that returns true.
*
* Of course, this style of sampling needs to be paired with analysis and
* presentation that makes the "size" of the event apparent, lest trials with
* large values for |n| appear to be indistinguishable from those with small
* values for |n|, despite being potentially much more likely to be sampled.
*/
bool trial(size_t aCount) {
if (mSkipCount > aCount) {
mSkipCount -= aCount;
return false;
}
return chooseSkipCount();
}
void setRandomState(uint64_t aState0, uint64_t aState1) {
mGenerator.setState(aState0, aState1);
}
void setProbability(double aProbability) {
MOZ_ASSERT(0 <= aProbability && aProbability <= 1);
mProbability = aProbability;
if (0 < mProbability && mProbability < 1) {
/*
* Let's look carefully at how this calculation plays out in floating-
* point arithmetic. We'll assume IEEE, but the final C++ code we arrive
* at would still be fine if our numbers were mathematically perfect. So,
* while we've considered IEEE's edge cases, we haven't done anything that
* should be actively bad when using other representations.
*
* (In the below, read comparisons as exact mathematical comparisons: when
* we say something "equals 1", that means it's exactly equal to 1. We
* treat approximation using intervals with open boundaries: saying a
* value is in (0,1) doesn't specify how close to 0 or 1 the value gets.
* When we use closed boundaries like [2**-53, 1], we're careful to ensure
* the boundary values are actually representable.)
*
* - After the comparison above, we know mProbability is in (0,1).
*
* - The gaps below 1 are 2**-53, so that interval is (0, 1-2**-53].
*
* - Because the floating-point gaps near 1 are wider than those near
* zero, there are many small positive doubles ε such that 1-ε rounds to
* exactly 1. However, 2**-53 can be represented exactly. So
* 1-mProbability is in [2**-53, 1].
*
* - log(1 - mProbability) is thus in (-37, 0].
*
* That range includes zero, but when we use mInvLogNotProbability, it
* would be helpful if we could trust that it's negative. So when log(1
* - mProbability) is 0, we'll just set mProbability to 0, so that
* mInvLogNotProbability is not used in chooseSkipCount.
*
* - How much of the range of mProbability does this cause us to ignore?
* The only value for which log returns 0 is exactly 1; the slope of log
* at 1 is 1, so for small ε such that 1 - ε != 1, log(1 - ε) is -ε,
* never 0. The gaps near one are larger than the gaps near zero, so if
* 1 - ε wasn't 1, then -ε is representable. So if log(1 - mProbability)
* isn't 0, then 1 - mProbability isn't 1, which means that mProbability
* is at least 2**-53, as discussed earlier. This is a sampling
* likelihood of roughly one in ten trillion, which is unlikely to be
* distinguishable from zero in practice.
*
* So by forbidding zero, we've tightened our range to (-37, -2**-53].
*
* - Finally, 1 / log(1 - mProbability) is in [-2**53, -1/37). This all
* falls readily within the range of an IEEE double.
*
* ALL THAT HAVING BEEN SAID: here are the five lines of actual code:
*/
double logNotProbability = std::log(1 - mProbability);
if (logNotProbability == 0.0)
mProbability = 0.0;
else
mInvLogNotProbability = 1 / logNotProbability;
}
chooseSkipCount();
}
private:
/* The likelihood that any given call to |trial| should return true. */
double mProbability;
/*
* The value of 1/std::log(1 - mProbability), cached for repeated use.
*
* If mProbability is exactly 0 or exactly 1, we don't use this value.
* Otherwise, we guarantee this value is in the range [-2**53, -1/37), i.e.
* definitely negative, as required by chooseSkipCount. See setProbability for
* the details.
*/
double mInvLogNotProbability;
/* Our random number generator. */
non_crypto::XorShift128PlusRNG mGenerator;
/* The number of times |trial| should return false before next returning true. */
size_t mSkipCount;
/*
* Choose the next skip count. This also returns the value that |trial| should
* return, since we have to check for the extreme values for mProbability
* anyway, and |trial| should never return true at all when mProbability is 0.
*/
bool chooseSkipCount() {
/*
* If the probability is 1.0, every call to |trial| returns true. Make sure
* mSkipCount is 0.
*/
if (mProbability == 1.0) {
mSkipCount = 0;
return true;
}
/*
* If the probabilility is zero, |trial| never returns true. Don't bother us
* for a while.
*/
if (mProbability == 0.0) {
mSkipCount = SIZE_MAX;
return false;
}
/*
* What sorts of values can this call to std::floor produce?
*
* Since mGenerator.nextDouble returns a value in [0, 1-2**-53], std::log
* returns a value in the range [-infinity, -2**-53], all negative. Since
* mInvLogNotProbability is negative (see its comments), the product is
* positive and possibly infinite. std::floor returns +infinity unchanged.
* So the result will always be positive.
*
* Converting a double to an integer that is out of range for that integer
* is undefined behavior, so we must clamp our result to SIZE_MAX, to ensure
* we get an acceptable value for mSkipCount.
*
* The clamp is written carefully. Note that if we had said:
*
* if (skipCount > SIZE_MAX)
* skipCount = SIZE_MAX;
*
* that leads to undefined behavior 64-bit machines: SIZE_MAX coerced to
* 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
* 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.
*
* (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);
if (skipCount < SIZE_MAX)
mSkipCount = skipCount;
else
mSkipCount = SIZE_MAX;
return true;
}
};
} /* namespace mozilla */
#endif /* mozilla_FastBernoulliTrial_h */

View File

@ -115,7 +115,7 @@ struct FloatingPoint : public SelectTrait<T>
static_assert(sizeof(T) == sizeof(Bits), "Bits must be same size as T");
};
/** Determines whether a double is NaN. */
/** Determines whether a float/double is NaN. */
template<typename T>
static MOZ_ALWAYS_INLINE bool
IsNaN(T aValue)
@ -126,9 +126,8 @@ IsNaN(T aValue)
*/
typedef FloatingPoint<T> Traits;
typedef typename Traits::Bits Bits;
Bits bits = BitwiseCast<Bits>(aValue);
return (bits & Traits::kExponentBits) == Traits::kExponentBits &&
(bits & Traits::kSignificandBits) != 0;
return (BitwiseCast<Bits>(aValue) & Traits::kExponentBits) == Traits::kExponentBits &&
(BitwiseCast<Bits>(aValue) & Traits::kSignificandBits) != 0;
}
/** Determines whether a float/double is +Infinity or -Infinity. */
@ -159,8 +158,8 @@ IsFinite(T aValue)
}
/**
* Determines whether a float/double is negative. It is an error to call this
* method on a float/double which is NaN.
* 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<typename T>
static MOZ_ALWAYS_INLINE bool
@ -187,6 +186,29 @@ IsNegativeZero(T aValue)
return bits == Traits::kSignBit;
}
/** Determines wether a float/double represents +0. */
template<typename T>
static MOZ_ALWAYS_INLINE bool
IsPositiveZero(T aValue)
{
/* All bits are zero if the value is +0. */
typedef FloatingPoint<T> Traits;
typedef typename Traits::Bits Bits;
Bits bits = BitwiseCast<Bits>(aValue);
return bits == 0;
}
/**
* Returns 0 if a float/double is NaN or infinite;
* otherwise, the float/double is returned.
*/
template<typename T>
static MOZ_ALWAYS_INLINE T
ToZeroIfNonfinite(T aValue)
{
return IsFinite(aValue) ? aValue : 0;
}
/**
* Returns the exponent portion of the float/double.
*
@ -234,21 +256,65 @@ NegativeInfinity()
return BitwiseCast<T>(Traits::kSignBit | Traits::kExponentBits);
}
/**
* Computes the bit pattern for a NaN with the specified sign bit and
* significand bits.
*/
template<typename T,
int SignBit,
typename FloatingPoint<T>::Bits Significand>
struct SpecificNaNBits
{
using Traits = FloatingPoint<T>;
/** Constructs a NaN value with the specified sign bit and significand bits. */
static_assert(SignBit == 0 || SignBit == 1, "bad sign bit");
static_assert((Significand & ~Traits::kSignificandBits) == 0,
"significand must only have significand bits set");
static_assert(Significand & Traits::kSignificandBits,
"significand must be nonzero");
static constexpr typename Traits::Bits value =
(SignBit * Traits::kSignBit) | Traits::kExponentBits | Significand;
};
/**
* Constructs a NaN value with the specified sign bit and significand bits.
*
* There is also a variant that returns the value directly. In most cases, the
* two variants should be identical. However, in the specific case of x86
* chips, the behavior differs: returning floating-point values directly is done
* through the x87 stack, and x87 loads and stores turn signaling NaNs into
* quiet NaNs... silently. Returning floating-point values via outparam,
* however, is done entirely within the SSE registers when SSE2 floating-point
* is enabled in the compiler, which has semantics-preserving behavior you would
* expect.
*
* If preserving the distinction between signaling NaNs and quiet NaNs is
* important to you, you should use the outparam version. In all other cases,
* you should use the direct return version.
*/
template<typename T>
static MOZ_ALWAYS_INLINE T
SpecificNaN(int signbit, typename FloatingPoint<T>::Bits significand)
static MOZ_ALWAYS_INLINE void
SpecificNaN(int signbit, typename FloatingPoint<T>::Bits significand, T* result)
{
typedef FloatingPoint<T> Traits;
MOZ_ASSERT(signbit == 0 || signbit == 1);
MOZ_ASSERT((significand & ~Traits::kSignificandBits) == 0);
MOZ_ASSERT(significand & Traits::kSignificandBits);
T t = BitwiseCast<T>((signbit ? Traits::kSignBit : 0) |
Traits::kExponentBits |
significand);
MOZ_ASSERT(IsNaN(t));
BitwiseCast<T>((signbit ? Traits::kSignBit : 0) |
Traits::kExponentBits |
significand,
result);
MOZ_ASSERT(IsNaN(*result));
}
template<typename T>
static MOZ_ALWAYS_INLINE T
SpecificNaN(int signbit, typename FloatingPoint<T>::Bits significand)
{
T t;
SpecificNaN(signbit, significand, &t);
return t;
}
@ -404,7 +470,7 @@ FuzzyEqualsMultiplicative(T aValue1, T aValue2,
*
* This function isn't inlined to avoid buggy optimizations by MSVC.
*/
MOZ_WARN_UNUSED_RESULT
MOZ_MUST_USE
extern MFBT_API bool
IsFloat32Representable(double aFloat32);

View File

@ -0,0 +1,223 @@
/* -*- 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<Signature>| 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<typename ReturnType, typename... Arguments>
class FunctionImplBase : public mozilla::RefCounted<FunctionImplBase<ReturnType, Arguments...>>
{
public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(FunctionImplBase)
virtual ~FunctionImplBase() {}
virtual ReturnType call(Arguments... aArguments) = 0;
};
// Normal Callable Object.
template <typename Callable, typename ReturnType, typename... Arguments>
class FunctionImpl : public FunctionImplBase<ReturnType, Arguments...>
{
public:
explicit FunctionImpl(const Callable& aCallable)
: mCallable(aCallable) {}
ReturnType call(Arguments... aArguments) override
{
return mCallable(Forward<Arguments>(aArguments)...);
}
private:
Callable mCallable;
};
// Base class for passing pointer to member function.
template <typename Callable, typename ReturnType, typename... Arguments>
class MemberFunctionImplBase : public FunctionImplBase<ReturnType, Arguments...>
{
public:
explicit MemberFunctionImplBase(const Callable& aCallable)
: mCallable(aCallable) {}
ReturnType call(Arguments... aArguments) override
{
return callInternal(Forward<Arguments>(aArguments)...);
}
private:
template<typename ThisType, typename... Args>
ReturnType callInternal(ThisType* aThis, Args&&... aArguments)
{
return (aThis->*mCallable)(Forward<Args>(aArguments)...);
}
template<typename ThisType, typename... Args>
ReturnType callInternal(ThisType&& aThis, Args&&... aArguments)
{
return (aThis.*mCallable)(Forward<Args>(aArguments)...);
}
Callable mCallable;
};
// For non-const member function specialization of FunctionImpl.
template <typename ThisType, typename... Args, typename ReturnType, typename... Arguments>
class FunctionImpl<ReturnType(ThisType::*)(Args...),
ReturnType, Arguments...>
: public MemberFunctionImplBase<ReturnType(ThisType::*)(Args...),
ReturnType, Arguments...>
{
public:
explicit FunctionImpl(ReturnType(ThisType::*aMemberFunc)(Args...))
: MemberFunctionImplBase<ReturnType(ThisType::*)(Args...),
ReturnType, Arguments...>(aMemberFunc)
{}
};
// For const member function specialization of FunctionImpl.
template <typename ThisType, typename... Args, typename ReturnType, typename... Arguments>
class FunctionImpl<ReturnType(ThisType::*)(Args...) const,
ReturnType, Arguments...>
: public MemberFunctionImplBase<ReturnType(ThisType::*)(Args...) const,
ReturnType, Arguments...>
{
public:
explicit FunctionImpl(ReturnType(ThisType::*aConstMemberFunc)(Args...) const)
: MemberFunctionImplBase<ReturnType(ThisType::*)(Args...) const,
ReturnType, Arguments...>(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<typename Signature>
class function;
template<typename ReturnType, typename... Arguments>
class function<ReturnType(Arguments...)>
{
public:
function() {}
// This constructor is implicit to match the interface of |std::function|.
template <typename Callable>
MOZ_IMPLICIT function(const Callable& aCallable)
: mImpl(new detail::FunctionImpl<Callable, ReturnType, Arguments...>(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 <typename Callable>
function& operator=(const Callable& aCallable)
{
mImpl = new detail::FunctionImpl<Callable, ReturnType, Arguments...>(aCallable);
return *this;
}
function& operator=(const function& aFunction)
{
mImpl = aFunction.mImpl;
return *this;
}
function& operator=(decltype(nullptr))
{
mImpl = nullptr;
return *this;
}
template<typename... Args>
ReturnType operator()(Args&&... aArguments) const
{
MOZ_ASSERT(mImpl);
return mImpl->call(Forward<Args>(aArguments)...);
}
explicit operator bool() const
{
return bool(mImpl);
}
private:
// TODO: Consider implementing a small object optimization.
RefPtr<detail::FunctionImplBase<ReturnType, Arguments...>> mImpl;
};
template<typename Signature>
bool
operator==(const function<Signature>& aX, decltype(nullptr))
{
return !aX;
}
template<typename Signature>
bool
operator==(decltype(nullptr), const function<Signature>& aX)
{
return !aX;
}
template<typename Signature>
bool
operator!=(const function<Signature>& aX, decltype(nullptr))
{
return bool(aX);
}
template<typename Signature>
bool
operator!=(decltype(nullptr), const function<Signature>& aX)
{
return bool(aX);
}
} // namespace mozilla
#endif /* mozilla_Function_h */

View File

@ -10,13 +10,20 @@
#define mozilla_GuardObjects_h
#include "mozilla/Assertions.h"
#include "mozilla/NullPtr.h"
#include "mozilla/Move.h"
#include "mozilla/Types.h"
#ifdef __cplusplus
#ifdef DEBUG
/**
* A custom define is used rather than |mozPoisonValue()| due to cascading
* build failures relating to how mfbt is linked on different operating
* systems. See bug 1160253.
*/
#define MOZ_POISON uintptr_t(-1)
namespace mozilla {
namespace detail {
@ -74,9 +81,20 @@ private:
bool* mStatementDone;
public:
GuardObjectNotifier() : mStatementDone(nullptr) { }
GuardObjectNotifier()
: mStatementDone(reinterpret_cast<bool*>(MOZ_POISON))
{
}
~GuardObjectNotifier() { *mStatementDone = true; }
~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
// (incorrectly) detecting null pointer dereferences.
MOZ_ASSERT(mStatementDone != reinterpret_cast<bool*>(MOZ_POISON));
*mStatementDone = true;
}
void setStatementDone(bool* aStatementIsDone)
{
@ -101,40 +119,36 @@ public:
MOZ_ASSERT(mStatementDone);
}
void init(const GuardObjectNotifier& aConstNotifier)
void init(GuardObjectNotifier& aNotifier)
{
/*
* aConstNotifier is passed as a const reference so that we can pass a
* temporary, but we really intend it as non-const.
*/
GuardObjectNotifier& notifier =
const_cast<GuardObjectNotifier&>(aConstNotifier);
notifier.setStatementDone(&mStatementDone);
aNotifier.setStatementDone(&mStatementDone);
}
};
} /* namespace detail */
} /* namespace mozilla */
#undef MOZ_POISON
#endif /* DEBUG */
#ifdef DEBUG
# define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER \
mozilla::detail::GuardObjectNotificationReceiver _mCheckNotUsedAsTemporary;
# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM \
, const mozilla::detail::GuardObjectNotifier& _notifier = \
, mozilla::detail::GuardObjectNotifier&& _notifier = \
mozilla::detail::GuardObjectNotifier()
# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM \
const mozilla::detail::GuardObjectNotifier& _notifier = \
mozilla::detail::GuardObjectNotifier&& _notifier = \
mozilla::detail::GuardObjectNotifier()
# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL \
, const mozilla::detail::GuardObjectNotifier& _notifier
, mozilla::detail::GuardObjectNotifier&& _notifier
# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL \
const mozilla::detail::GuardObjectNotifier& _notifier
mozilla::detail::GuardObjectNotifier&& _notifier
# define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT \
, _notifier
, mozilla::Move(_notifier)
# define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT \
_notifier
mozilla::Move(_notifier)
# define MOZ_GUARD_OBJECT_NOTIFIER_INIT \
do { _mCheckNotUsedAsTemporary.init(_notifier); } while (0)
#else

View File

@ -10,7 +10,7 @@
* This file exports functions for hashing data down to a 32-bit value,
* including:
*
* - HashString Hash a char* or uint16_t/wchar_t* of known or unknown
* - HashString Hash a char* or char16_t/wchar_t* of known or unknown
* length.
*
* - HashBytes Hash a byte array of known length.
@ -50,6 +50,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Char16.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Types.h"
#include <stdint.h>
@ -156,7 +157,7 @@ AddUintptrToHash<8>(uint32_t aHash, uintptr_t aValue)
* convert to uint32_t, data pointers, and function pointers.
*/
template<typename A>
MOZ_WARN_UNUSED_RESULT inline uint32_t
MOZ_MUST_USE inline uint32_t
AddToHash(uint32_t aHash, A aA)
{
/*
@ -167,7 +168,7 @@ AddToHash(uint32_t aHash, A aA)
}
template<typename A>
MOZ_WARN_UNUSED_RESULT inline uint32_t
MOZ_MUST_USE inline uint32_t
AddToHash(uint32_t aHash, A* aA)
{
/*
@ -181,38 +182,17 @@ AddToHash(uint32_t aHash, A* aA)
}
template<>
MOZ_WARN_UNUSED_RESULT inline uint32_t
MOZ_MUST_USE inline uint32_t
AddToHash(uint32_t aHash, uintptr_t aA)
{
return detail::AddUintptrToHash<sizeof(uintptr_t)>(aHash, aA);
}
template<typename A, typename B>
MOZ_WARN_UNUSED_RESULT uint32_t
AddToHash(uint32_t aHash, A aA, B aB)
template<typename A, typename... Args>
MOZ_MUST_USE uint32_t
AddToHash(uint32_t aHash, A aArg, Args... aArgs)
{
return AddToHash(AddToHash(aHash, aA), aB);
}
template<typename A, typename B, typename C>
MOZ_WARN_UNUSED_RESULT uint32_t
AddToHash(uint32_t aHash, A aA, B aB, C aC)
{
return AddToHash(AddToHash(aHash, aA, aB), aC);
}
template<typename A, typename B, typename C, typename D>
MOZ_WARN_UNUSED_RESULT uint32_t
AddToHash(uint32_t aHash, A aA, B aB, C aC, D aD)
{
return AddToHash(AddToHash(aHash, aA, aB, aC), aD);
}
template<typename A, typename B, typename C, typename D, typename E>
MOZ_WARN_UNUSED_RESULT uint32_t
AddToHash(uint32_t aHash, A aA, B aB, C aC, D aD, E aE)
{
return AddToHash(AddToHash(aHash, aA, aB, aC, aD), aE);
return AddToHash(AddToHash(aHash, aArg), aArgs...);
}
/**
@ -222,39 +202,11 @@ AddToHash(uint32_t aHash, A aA, B aB, C aC, D aD, E aE)
* much better than calling AddToHash(x, y), because AddToHash(x, y) assumes
* that x has already been hashed.
*/
template<typename A>
MOZ_WARN_UNUSED_RESULT inline uint32_t
HashGeneric(A aA)
template<typename... Args>
MOZ_MUST_USE inline uint32_t
HashGeneric(Args... aArgs)
{
return AddToHash(0, aA);
}
template<typename A, typename B>
MOZ_WARN_UNUSED_RESULT inline uint32_t
HashGeneric(A aA, B aB)
{
return AddToHash(0, aA, aB);
}
template<typename A, typename B, typename C>
MOZ_WARN_UNUSED_RESULT inline uint32_t
HashGeneric(A aA, B aB, C aC)
{
return AddToHash(0, aA, aB, aC);
}
template<typename A, typename B, typename C, typename D>
MOZ_WARN_UNUSED_RESULT inline uint32_t
HashGeneric(A aA, B aB, C aC, D aD)
{
return AddToHash(0, aA, aB, aC, aD);
}
template<typename A, typename B, typename C, typename D, typename E>
MOZ_WARN_UNUSED_RESULT inline uint32_t
HashGeneric(A aA, B aB, C aC, D aD, E aE)
{
return AddToHash(0, aA, aB, aC, aD, aE);
return AddToHash(0, aArgs...);
}
namespace detail {
@ -289,63 +241,49 @@ HashKnownLength(const T* aStr, size_t aLength)
* If you have the string's length, you might as well call the overload which
* includes the length. It may be marginally faster.
*/
MOZ_WARN_UNUSED_RESULT inline uint32_t
MOZ_MUST_USE inline uint32_t
HashString(const char* aStr)
{
return detail::HashUntilZero(aStr);
return detail::HashUntilZero(reinterpret_cast<const unsigned char*>(aStr));
}
MOZ_WARN_UNUSED_RESULT inline uint32_t
MOZ_MUST_USE inline uint32_t
HashString(const char* aStr, size_t aLength)
{
return detail::HashKnownLength(aStr, aLength);
return detail::HashKnownLength(reinterpret_cast<const unsigned char*>(aStr), aLength);
}
MOZ_WARN_UNUSED_RESULT
MOZ_MUST_USE
inline uint32_t
HashString(const unsigned char* aStr, size_t aLength)
{
return detail::HashKnownLength(aStr, aLength);
}
MOZ_WARN_UNUSED_RESULT inline uint32_t
HashString(const uint16_t* aStr)
{
return detail::HashUntilZero(aStr);
}
MOZ_WARN_UNUSED_RESULT inline uint32_t
HashString(const uint16_t* aStr, size_t aLength)
{
return detail::HashKnownLength(aStr, aLength);
}
#ifdef MOZ_CHAR16_IS_NOT_WCHAR
MOZ_WARN_UNUSED_RESULT inline uint32_t
MOZ_MUST_USE inline uint32_t
HashString(const char16_t* aStr)
{
return detail::HashUntilZero(aStr);
}
MOZ_WARN_UNUSED_RESULT inline uint32_t
MOZ_MUST_USE inline uint32_t
HashString(const char16_t* aStr, size_t aLength)
{
return detail::HashKnownLength(aStr, aLength);
}
#endif
/*
* On Windows, wchar_t (char16_t) is not the same as uint16_t, even though it's
* On Windows, wchar_t is not the same as char16_t, even though it's
* the same width!
*/
#ifdef WIN32
MOZ_WARN_UNUSED_RESULT inline uint32_t
MOZ_MUST_USE inline uint32_t
HashString(const wchar_t* aStr)
{
return detail::HashUntilZero(aStr);
}
MOZ_WARN_UNUSED_RESULT inline uint32_t
MOZ_MUST_USE inline uint32_t
HashString(const wchar_t* aStr, size_t aLength)
{
return detail::HashKnownLength(aStr, aLength);
@ -358,9 +296,93 @@ HashString(const wchar_t* aStr, size_t aLength)
* This hash walks word-by-word, rather than byte-by-byte, so you won't get the
* same result out of HashBytes as you would out of HashString.
*/
MOZ_WARN_UNUSED_RESULT extern MFBT_API uint32_t
MOZ_MUST_USE extern MFBT_API uint32_t
HashBytes(const void* bytes, size_t aLength);
/**
* A pseudorandom function mapping 32-bit integers to 32-bit integers.
*
* This is for when you're feeding private data (like pointer values or credit
* card numbers) to a non-crypto hash function (like HashBytes) and then using
* the hash code for something that untrusted parties could observe (like a JS
* Map). Plug in a HashCodeScrambler before that last step to avoid leaking the
* private data.
*
* By itself, this does not prevent hash-flooding DoS attacks, because an
* attacker can still generate many values with exactly equal hash codes by
* attacking the non-crypto hash function alone. Equal hash codes will, of
* course, still be equal however much you scramble them.
*
* The algorithm is SipHash-1-3. See <https://131002.net/siphash/>.
*/
class HashCodeScrambler
{
struct SipHasher;
uint64_t mK0, mK1;
public:
/** Creates a new scrambler with the given 128-bit key. */
constexpr HashCodeScrambler(uint64_t aK0, uint64_t aK1) : mK0(aK0), mK1(aK1) {}
/**
* Scramble a hash code. Always produces the same result for the same
* combination of key and hash code.
*/
uint32_t scramble(uint32_t aHashCode) const
{
SipHasher hasher(mK0, mK1);
return uint32_t(hasher.sipHash(aHashCode));
}
private:
struct SipHasher
{
SipHasher(uint64_t aK0, uint64_t aK1)
{
// 1. Initialization.
mV0 = aK0 ^ UINT64_C(0x736f6d6570736575);
mV1 = aK1 ^ UINT64_C(0x646f72616e646f6d);
mV2 = aK0 ^ UINT64_C(0x6c7967656e657261);
mV3 = aK1 ^ UINT64_C(0x7465646279746573);
}
uint64_t sipHash(uint64_t aM)
{
// 2. Compression.
mV3 ^= aM;
sipRound();
mV0 ^= aM;
// 3. Finalization.
mV2 ^= 0xff;
for (int i = 0; i < 3; i++)
sipRound();
return mV0 ^ mV1 ^ mV2 ^ mV3;
}
void sipRound()
{
mV0 += mV1;
mV1 = RotateLeft(mV1, 13);
mV1 ^= mV0;
mV0 = RotateLeft(mV0, 32);
mV2 += mV3;
mV3 = RotateLeft(mV3, 16);
mV3 ^= mV2;
mV0 += mV3;
mV3 = RotateLeft(mV3, 21);
mV3 ^= mV0;
mV2 += mV1;
mV1 = RotateLeft(mV1, 17);
mV1 ^= mV2;
mV2 = RotateLeft(mV2, 32);
}
uint64_t mV0, mV1, mV2, mV3;
};
};
} /* namespace mozilla */
#endif /* __cplusplus */

View File

@ -0,0 +1,143 @@
/* -*- 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 utility for expanding a tuple into a variadic argument list.
* Based on std::index_sequence. */
/**
* Example usage:
*
* Problem:
*
* You have a variadic function Foo:
*
* template <typename... Args> void Foo(Args...);
*
* And a variadic function Bar, which contains a tuple:
*
* template <typename... Args>
* void Bar() {
* // ...
* Tuple<Args...> t;
* }
*
* And inside Bar, you want to call Foo with the elements of the tuple as
* arguments to Foo.
*
* You want to write:
*
* Foo(Get<0>(t), Get<1>(t), ..., Get<N>(t))
*
* but you can't literally write that, because N is different for different
* instantiations of Bar.
*
* Solution:
*
* Write a helper function which takes the tuple, and an index sequence
* containing indices corresponding to the tuple indices.
*
* template <typename... Args, size_t... Indices>
* void Helper(const Tuple<Args...>& t, IndexSequence<Indices>)
* {
* Foo(Get<Indices>(t)...);
* }
*
* Assuming 'Indices...' are 0, 1, ..., N - 1, where N is the size of the
* tuple, pack expansion will expand the pack 'Get<Indices>(t)...' to
* 'Get<0>(t), Get<1>(t), ..., Get<N>(t)'.
*
* Finally, call the helper, creating the index sequence to pass in like so:
*
* template <typename... Args>
* void Bar() {
* // ...
* Tuple<Args...> t;
* Helper(t, typename IndexSequenceFor<Args...>::Type());
* }
*/
#ifndef mozilla_IndexSequence_h
#define mozilla_IndexSequence_h
#include "mozilla/Attributes.h"
#include <stddef.h>
namespace mozilla {
/**
* Represents a compile-time sequence of integer indices.
*/
template<size_t... Indices>
struct IndexSequence
{
static constexpr size_t Size() { return sizeof...(Indices); }
};
namespace detail {
// Helpers used by MakeIndexSequence.
template<size_t... Indices>
struct IndexTuple
{
typedef IndexTuple<Indices..., sizeof...(Indices)> Next;
};
// Builds IndexTuple<0, 1, ..., N - 1>.
template<size_t N>
struct BuildIndexTuple
{
typedef typename BuildIndexTuple<N - 1>::Type::Next Type;
};
template<>
struct BuildIndexTuple<0>
{
typedef IndexTuple<> Type;
};
template<size_t N, typename IndexTuple>
struct MakeIndexSequenceImpl;
template<size_t N, size_t... Indices>
struct MakeIndexSequenceImpl<N, IndexTuple<Indices...>>
{
typedef IndexSequence<Indices...> Type;
};
} // namespace detail
/**
* A utility for building an IndexSequence of consecutive indices.
* MakeIndexSequence<N>::Type evaluates to IndexSequence<0, 1, .., N - 1>.
* Note: unlike std::make_index_sequence, this is not an alias template
* to work around bugs in MSVC 2013.
*/
template<size_t N>
struct MakeIndexSequence
{
typedef typename detail::MakeIndexSequenceImpl<N,
typename detail::BuildIndexTuple<N>::Type>::Type Type;
};
/**
* A utility for building an IndexSequence of consecutive indices
* corresponding to a variadic argument list.
* IndexSequenceFor<Types...> evaluates to IndexSequence<0, 1, ..., N - 1>
* where N is the number of types in Types.
* Note: unlike std::index_sequence_for, this is not an alias template
* to work around bugs in MSVC 2013.
*/
template<typename... Types>
struct IndexSequenceFor
{
typedef typename MakeIndexSequence<sizeof...(Types)>::Type Type;
};
} // namespace mozilla
#endif /* mozilla_IndexSequence_h */

View File

@ -4,39 +4,29 @@
* License, v. 2.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 the C99 <inttypes.h> interface, minus the SCN* format macros. */
/* Implements the C99 <inttypes.h> interface. */
#ifndef mozilla_IntegerPrintfMacros_h_
#define mozilla_IntegerPrintfMacros_h_
/*
* MSVC++ doesn't include <inttypes.h>, even in versions shipping <stdint.h>, so
* we have to reimplement it there. Note: <inttypes.h> #includes <stdint.h>.
*
* Note that this header DOES NOT implement <inttypes.h>'s scanf macros. MSVC's
* scanf doesn't have sufficient format specifier support to implement them
* (specifically, to implement scanning into an 8-bit location).
*
* http://stackoverflow.com/questions/3036396/scanfd-char-char-as-int-format-string
*
* Moreover, scanf is a footgun: if the input number exceeds the bounds of the
* target type, behavior is undefined (in the compiler sense: that is, this code
* 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.
*/
/*
* scanf is a footgun: if the input number exceeds the bounds of the target
* type, behavior is undefined (in the compiler sense: that is, this code
* could overwrite your hard drive with zeroes):
*
* uint8_t u;
* sscanf("256", "%" SCNu8, &u); // BAD
*
* This header will sometimes provide SCN* macros, by dint of being implemented
* using <inttypes.h>. But for these reasons, *never* use them!
* For this reason, *never* use the SCN* macros provided by this header!
*/
#if defined(MOZ_CUSTOM_INTTYPES_H)
# include MOZ_CUSTOM_INTTYPES_H
#elif defined(_MSC_VER)
# include "mozilla/MSIntTypes.h"
#else
# include <inttypes.h>
#endif
#include <inttypes.h>
/*
* Fix up Android's broken [u]intptr_t inttype macros. Android's PRI*PTR

View File

@ -0,0 +1,181 @@
/* -*- 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/. */
/* Iterator over ranges of integers */
#ifndef mozilla_IntegerRange_h
#define mozilla_IntegerRange_h
#include "mozilla/Assertions.h"
#include "mozilla/ReverseIterator.h"
#include "mozilla/TypeTraits.h"
namespace mozilla {
namespace detail {
template<typename IntTypeT>
class IntegerIterator
{
public:
template<typename IntType>
explicit IntegerIterator(IntType aCurrent)
: mCurrent(aCurrent) { }
template<typename IntType>
explicit IntegerIterator(const IntegerIterator<IntType>& aOther)
: 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; }
/* Comparison operators */
template<typename IntType1, typename IntType2>
friend bool operator==(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2);
template<typename IntType1, typename IntType2>
friend bool operator!=(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2);
template<typename IntType1, typename IntType2>
friend bool operator<(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2);
template<typename IntType1, typename IntType2>
friend bool operator<=(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2);
template<typename IntType1, typename IntType2>
friend bool operator>(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2);
template<typename IntType1, typename IntType2>
friend bool operator>=(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2);
private:
IntTypeT mCurrent;
};
template<typename IntType1, typename IntType2>
bool operator==(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2)
{
return aIter1.mCurrent == aIter2.mCurrent;
}
template<typename IntType1, typename IntType2>
bool operator!=(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2)
{
return aIter1.mCurrent != aIter2.mCurrent;
}
template<typename IntType1, typename IntType2>
bool operator<(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2)
{
return aIter1.mCurrent < aIter2.mCurrent;
}
template<typename IntType1, typename IntType2>
bool operator<=(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2)
{
return aIter1.mCurrent <= aIter2.mCurrent;
}
template<typename IntType1, typename IntType2>
bool operator>(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2)
{
return aIter1.mCurrent > aIter2.mCurrent;
}
template<typename IntType1, typename IntType2>
bool operator>=(const IntegerIterator<IntType1>& aIter1,
const IntegerIterator<IntType2>& aIter2)
{
return aIter1.mCurrent >= aIter2.mCurrent;
}
template<typename IntTypeT>
class IntegerRange
{
public:
typedef IntegerIterator<IntTypeT> iterator;
typedef IntegerIterator<IntTypeT> const_iterator;
typedef ReverseIterator<IntegerIterator<IntTypeT>> reverse_iterator;
typedef ReverseIterator<IntegerIterator<IntTypeT>> const_reverse_iterator;
template<typename IntType>
explicit IntegerRange(IntType aEnd)
: mBegin(0), mEnd(aEnd) { }
template<typename IntType1, typename IntType2>
IntegerRange(IntType1 aBegin, IntType2 aEnd)
: mBegin(aBegin), mEnd(aEnd) { }
iterator begin() const { return iterator(mBegin); }
const_iterator cbegin() const { return begin(); }
iterator end() const { return iterator(mEnd); }
const_iterator cend() const { return end(); }
reverse_iterator rbegin() const { return reverse_iterator(mEnd); }
const_reverse_iterator crbegin() const { return rbegin(); }
reverse_iterator rend() const { return reverse_iterator(mBegin); }
const_reverse_iterator crend() const { return rend(); }
private:
IntTypeT mBegin;
IntTypeT mEnd;
};
template<typename T, bool = IsUnsigned<T>::value>
struct GeqZero
{
static bool check(T t) {
return t >= 0;
}
};
template<typename T>
struct GeqZero<T, true>
{
static bool check(T t) {
return true;
}
};
} // namespace detail
template<typename IntType>
detail::IntegerRange<IntType>
MakeRange(IntType aEnd)
{
static_assert(IsIntegral<IntType>::value, "value must be integral");
MOZ_ASSERT(detail::GeqZero<IntType>::check(aEnd),
"Should never have negative value here");
return detail::IntegerRange<IntType>(aEnd);
}
template<typename IntType1, typename IntType2>
detail::IntegerRange<IntType2>
MakeRange(IntType1 aBegin, IntType2 aEnd)
{
static_assert(IsIntegral<IntType1>::value && IsIntegral<IntType2>::value,
"values must both be integral");
static_assert(IsSigned<IntType1>::value == IsSigned<IntType2>::value,
"signed/unsigned mismatch");
MOZ_ASSERT(aEnd >= aBegin, "End value should be larger than begin value");
return detail::IntegerRange<IntType2>(aBegin, aEnd);
}
} // namespace mozilla
#endif // mozilla_IntegerRange_h

View File

@ -79,6 +79,11 @@ struct UnsignedStdintTypeForSize
: detail::StdintTypeForSizeAndSignedness<Size, false>
{};
template<size_t Size>
struct SignedStdintTypeForSize
: detail::StdintTypeForSizeAndSignedness<Size, true>
{};
template<typename IntegerType>
struct PositionOfSignBit
{

View File

@ -0,0 +1,460 @@
/* -*- 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 JSON pretty-printer class. */
// A typical JSON-writing library requires you to first build up a data
// structure that represents a JSON object and then serialize it (to file, or
// somewhere else). This approach makes for a clean API, but building the data
// structure takes up memory. Sometimes that isn't desirable, such as when the
// JSON data is produced for memory reporting.
//
// The JSONWriter class instead allows JSON data to be written out
// incrementally without building up large data structures.
//
// The API is slightly uglier than you would see in a typical JSON-writing
// library, but still fairly easy to use. It's possible to generate invalid
// JSON with JSONWriter, but typically the most basic testing will identify any
// such problems.
//
// Similarly, there are no RAII facilities for automatically closing objects
// and arrays. These would be nice if you are generating all your code within
// nested functions, but in other cases you'd have to maintain an explicit
// stack of RAII objects and manually unwind it, which is no better than just
// calling "end" functions. Furthermore, the consequences of forgetting to
// close an object or array are obvious and, again, will be identified via
// basic testing, unlike other cases where RAII is typically used (e.g. smart
// pointers) and the consequences of defects are more subtle.
//
// Importantly, the class does solve the two hard problems of JSON
// pretty-printing, which are (a) correctly escaping strings, and (b) adding
// appropriate indentation and commas between items.
//
// By default, every property is placed on its own line. However, it is
// possible to request that objects and arrays be placed entirely on a single
// line, which can reduce output size significantly in some cases.
//
// Strings used (for property names and string property values) are |const
// char*| throughout, and can be ASCII or UTF-8.
//
// EXAMPLE
// -------
// Assume that |MyWriteFunc| is a class that implements |JSONWriteFunc|. The
// following code:
//
// JSONWriter w(MakeUnique<MyWriteFunc>());
// w.Start();
// {
// w.NullProperty("null");
// w.BoolProperty("bool", true);
// w.IntProperty("int", 1);
// w.StartArrayProperty("array");
// {
// w.StringElement("string");
// w.StartObjectElement();
// {
// w.DoubleProperty("double", 3.4);
// w.StartArrayProperty("single-line array", w.SingleLineStyle);
// {
// w.IntElement(1);
// w.StartObjectElement(); // SingleLineStyle is inherited from
// w.EndObjectElement(); // above for this collection
// }
// w.EndArray();
// }
// w.EndObjectElement();
// }
// w.EndArrayProperty();
// }
// w.End();
//
// will produce pretty-printed output for the following JSON object:
//
// {
// "null": null,
// "bool": true,
// "int": 1,
// "array": [
// "string",
// {
// "double": 3.4,
// "single-line array": [1, {}]
// }
// ]
// }
//
// The nesting in the example code is obviously optional, but can aid
// readability.
#ifndef mozilla_JSONWriter_h
#define mozilla_JSONWriter_h
#include "mozilla/double-conversion.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Sprintf.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Vector.h"
#include <stdio.h>
namespace mozilla {
// 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:
virtual void Write(const char* aStr) = 0;
virtual ~JSONWriteFunc() {}
};
// Ideally this would be within |EscapedString| but when compiling with GCC
// on Linux that caused link errors, whereas this formulation didn't.
namespace detail {
extern MFBT_DATA const char gTwoCharEscapes[256];
} // namespace detail
class JSONWriter
{
// From http://www.ietf.org/rfc/rfc4627.txt:
//
// "All Unicode characters may be placed within the quotation marks except
// for the characters that must be escaped: quotation mark, reverse
// solidus, and the control characters (U+0000 through U+001F)."
//
// This implementation uses two-char escape sequences where possible, namely:
//
// \", \\, \b, \f, \n, \r, \t
//
// 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
{
// 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.
bool mIsOwned;
const char* mUnownedStr;
UniquePtr<char[]> mOwnedStr;
void SanityCheck() const
{
MOZ_ASSERT_IF( mIsOwned, mOwnedStr.get() && !mUnownedStr);
MOZ_ASSERT_IF(!mIsOwned, !mOwnedStr.get() && mUnownedStr);
}
static char hexDigitToAsciiChar(uint8_t u)
{
u = u & 0xf;
return u < 10 ? '0' + u : 'a' + (u - 10);
}
public:
explicit EscapedString(const char* aStr)
: 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
if (u == 0) {
break;
}
if (detail::gTwoCharEscapes[u]) {
nExtra += 1;
} else if (u <= 0x1f) {
nExtra += 5;
}
p++;
}
if (nExtra == 0) {
// No escapes needed. Easy.
mIsOwned = false;
mUnownedStr = aStr;
return;
}
// Escapes are needed. We'll create a new string.
mIsOwned = true;
size_t len = (p - aStr) + nExtra;
mOwnedStr = MakeUnique<char[]>(len + 1);
p = aStr;
size_t i = 0;
while (true) {
uint8_t u = *p; // ensure it can't be interpreted as negative
if (u == 0) {
mOwnedStr[i] = 0;
break;
}
if (detail::gTwoCharEscapes[u]) {
mOwnedStr[i++] = '\\';
mOwnedStr[i++] = detail::gTwoCharEscapes[u];
} else if (u <= 0x1f) {
mOwnedStr[i++] = '\\';
mOwnedStr[i++] = 'u';
mOwnedStr[i++] = '0';
mOwnedStr[i++] = '0';
mOwnedStr[i++] = hexDigitToAsciiChar((u & 0x00f0) >> 4);
mOwnedStr[i++] = hexDigitToAsciiChar(u & 0x000f);
} else {
mOwnedStr[i++] = u;
}
p++;
}
}
~EscapedString()
{
SanityCheck();
}
const char* get() const
{
SanityCheck();
return mIsOwned ? mOwnedStr.get() : mUnownedStr;
}
};
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
SingleLineStyle
};
protected:
const UniquePtr<JSONWriteFunc> mWriter;
Vector<bool, 8> mNeedComma; // do we need a comma at depth N?
Vector<bool, 8> mNeedNewlines; // do we need newlines at depth N?
size_t mDepth; // the current nesting depth
void Indent()
{
for (size_t i = 0; i < mDepth; i++) {
mWriter->Write(" ");
}
}
// 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()
{
if (mNeedComma[mDepth]) {
mWriter->Write(",");
}
if (mDepth > 0 && mNeedNewlines[mDepth]) {
mWriter->Write("\n");
Indent();
} else if (mNeedComma[mDepth]) {
mWriter->Write(" ");
}
}
void PropertyNameAndColon(const char* aName)
{
EscapedString escapedName(aName);
mWriter->Write("\"");
mWriter->Write(escapedName.get());
mWriter->Write("\": ");
}
void Scalar(const char* aMaybePropertyName, const char* aStringValue)
{
Separator();
if (aMaybePropertyName) {
PropertyNameAndColon(aMaybePropertyName);
}
mWriter->Write(aStringValue);
mNeedComma[mDepth] = true;
}
void QuotedScalar(const char* aMaybePropertyName, const char* aStringValue)
{
Separator();
if (aMaybePropertyName) {
PropertyNameAndColon(aMaybePropertyName);
}
mWriter->Write("\"");
mWriter->Write(aStringValue);
mWriter->Write("\"");
mNeedComma[mDepth] = true;
}
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));
MOZ_RELEASE_ASSERT(mNeedNewlines.resizeUninitialized(mDepth + 1));
mNeedComma[mDepth] = false;
mNeedNewlines[mDepth] = true;
}
void StartCollection(const char* aMaybePropertyName, const char* aStartChar,
CollectionStyle aStyle = MultiLineStyle)
{
Separator();
if (aMaybePropertyName) {
mWriter->Write("\"");
mWriter->Write(aMaybePropertyName);
mWriter->Write("\": ");
}
mWriter->Write(aStartChar);
mNeedComma[mDepth] = true;
mDepth++;
NewVectorEntries();
mNeedNewlines[mDepth] =
mNeedNewlines[mDepth - 1] && aStyle == MultiLineStyle;
}
// Adds the whitespace and closing char necessary to end a collection.
void EndCollection(const char* aEndChar)
{
if (mNeedNewlines[mDepth]) {
mWriter->Write("\n");
mDepth--;
Indent();
} else {
mDepth--;
}
mWriter->Write(aEndChar);
}
public:
explicit JSONWriter(UniquePtr<JSONWriteFunc> aWriter)
: mWriter(Move(aWriter))
, mNeedComma()
, mNeedNewlines()
, mDepth(0)
{
NewVectorEntries();
}
// Returns the JSONWriteFunc passed in at creation, for temporary use. The
// JSONWriter object still owns the JSONWriteFunc.
JSONWriteFunc* WriteFunc() const { return mWriter.get(); }
// For all the following functions, the "Prints:" comment indicates what the
// basic output looks like. However, it doesn't indicate the whitespace and
// trailing commas, which are automatically added as required.
//
// All property names and string properties are escaped as necessary.
// Prints: {
void Start(CollectionStyle aStyle = MultiLineStyle)
{
StartCollection(nullptr, "{", aStyle);
}
// Prints: }
void End() { EndCollection("}\n"); }
// Prints: "<aName>": null
void NullProperty(const char* aName)
{
Scalar(aName, "null");
}
// Prints: null
void NullElement() { NullProperty(nullptr); }
// Prints: "<aName>": <aBool>
void BoolProperty(const char* aName, bool aBool)
{
Scalar(aName, aBool ? "true" : "false");
}
// Prints: <aBool>
void BoolElement(bool aBool) { BoolProperty(nullptr, aBool); }
// Prints: "<aName>": <aInt>
void IntProperty(const char* aName, int64_t aInt)
{
char buf[64];
SprintfLiteral(buf, "%" PRId64, aInt);
Scalar(aName, buf);
}
// Prints: <aInt>
void IntElement(int64_t aInt) { IntProperty(nullptr, aInt); }
// Prints: "<aName>": <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();
double_conversion::StringBuilder builder(buf, buflen);
converter.ToShortest(aDouble, &builder);
Scalar(aName, builder.Finalize());
}
// Prints: <aDouble>
void DoubleElement(double aDouble) { DoubleProperty(nullptr, aDouble); }
// Prints: "<aName>": "<aStr>"
void StringProperty(const char* aName, const char* aStr)
{
EscapedString escapedStr(aStr);
QuotedScalar(aName, escapedStr.get());
}
// Prints: "<aStr>"
void StringElement(const char* aStr) { StringProperty(nullptr, aStr); }
// Prints: "<aName>": [
void StartArrayProperty(const char* aName,
CollectionStyle aStyle = MultiLineStyle)
{
StartCollection(aName, "[", aStyle);
}
// Prints: [
void StartArrayElement(CollectionStyle aStyle = MultiLineStyle)
{
StartArrayProperty(nullptr, aStyle);
}
// Prints: ]
void EndArray() { EndCollection("]"); }
// Prints: "<aName>": {
void StartObjectProperty(const char* aName,
CollectionStyle aStyle = MultiLineStyle)
{
StartCollection(aName, "{", aStyle);
}
// Prints: {
void StartObjectElement(CollectionStyle aStyle = MultiLineStyle)
{
StartObjectProperty(nullptr, aStyle);
}
// Prints: }
void EndObject() { EndCollection("}"); }
};
} // namespace mozilla
#endif /* mozilla_JSONWriter_h */

Some files were not shown because too many files have changed in this diff Show More