mirror of https://github.com/axmolengine/axmol.git
issue #3900: Adds spidermonkey v27 library for Android.
This commit is contained in:
parent
90c4a63677
commit
20ab9daa3a
|
@ -5,8 +5,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_config_h___
|
||||
#define js_config_h___
|
||||
#ifndef js_config_h
|
||||
#define js_config_h
|
||||
|
||||
/* Definitions set at build time that affect SpiderMonkey's public API.
|
||||
This header file is generated by the SpiderMonkey configure script,
|
||||
|
@ -34,12 +34,8 @@
|
|||
useable. See jscpucfg.h. */
|
||||
/* #undef JS_HAVE_SYS_ISA_DEFS_H */
|
||||
|
||||
/* The configure script defines these if it doesn't #define
|
||||
JS_HAVE_STDINT_H. */
|
||||
#define JS_BYTES_PER_WORD 4
|
||||
|
||||
/* MOZILLA JSAPI version number components */
|
||||
#define MOZJS_MAJOR_VERSION 25
|
||||
#define MOZJS_MAJOR_VERSION 27
|
||||
#define MOZJS_MINOR_VERSION 0
|
||||
|
||||
#endif /* js_config_h___ */
|
||||
#endif /* js_config_h */
|
||||
|
|
|
@ -221,8 +221,8 @@ MSG_DEF(JSMSG_CANT_DECODE_PRINCIPALS, 167, 0, JSEXN_INTERNALERR, "can't decode J
|
|||
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_UNUSED171, 171, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_UNUSED172, 172, 0, JSEXN_NONE, "")
|
||||
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_UNUSED173, 173, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_UNUSED174, 174, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_NESTING_GENERATOR, 175, 0, JSEXN_TYPEERR, "already executing generator")
|
||||
|
@ -233,8 +233,8 @@ MSG_DEF(JSMSG_UNUSED179, 179, 0, JSEXN_NONE, "")
|
|||
MSG_DEF(JSMSG_UNUSED180, 180, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_UNUSED181, 181, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_BAD_GENERATOR_SEND, 182, 1, JSEXN_TYPEERR, "attempt to send {0} to newborn generator")
|
||||
MSG_DEF(JSMSG_UNUSED183, 183, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_UNUSED184, 184, 0, JSEXN_NONE, "")
|
||||
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_UNUSED186, 186, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_UNUSED187, 187, 0, JSEXN_NONE, "")
|
||||
|
@ -260,7 +260,7 @@ MSG_DEF(JSMSG_USER_DEFINED_ERROR, 206, 0, JSEXN_ERR, "JS_ReportError was cal
|
|||
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_NAME_AFTER_FOR_PAREN, 210, 0, JSEXN_SYNTAXERR, "missing name after for (")
|
||||
MSG_DEF(JSMSG_UNUSED210, 210, 0, JSEXN_NONE, "")
|
||||
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_UNUSED213, 213, 0, JSEXN_NONE, "")
|
||||
|
@ -269,7 +269,7 @@ MSG_DEF(JSMSG_BAD_GENERATOR_SYNTAX, 215, 1, JSEXN_SYNTAXERR, "{0} expression m
|
|||
MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 216, 0, JSEXN_SYNTAXERR, "invalid array comprehension left-hand side")
|
||||
MSG_DEF(JSMSG_UNUSED217, 217, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 218, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value")
|
||||
MSG_DEF(JSMSG_UNUSED219, 219, 0, JSEXN_NONE, "")
|
||||
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}")
|
||||
|
@ -353,7 +353,7 @@ MSG_DEF(JSMSG_REST_WITH_DEFAULT, 299, 0, JSEXN_SYNTAXERR, "rest parameter m
|
|||
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_SOURCEMAP, 303, 1, JSEXN_ERR, "{0} is being assigned a source map, yet already has one")
|
||||
MSG_DEF(JSMSG_ALREADY_HAS_PRAGMA, 303, 2, JSEXN_ERR, "{0} is being assigned a {1}, but already has one")
|
||||
MSG_DEF(JSMSG_PAR_ARRAY_BAD_ARG, 304, 1, JSEXN_RANGEERR, "invalid ParallelArray{0} argument")
|
||||
MSG_DEF(JSMSG_PAR_ARRAY_BAD_PARTITION, 305, 0, JSEXN_ERR, "argument must be divisible by outermost dimension")
|
||||
MSG_DEF(JSMSG_PAR_ARRAY_REDUCE_EMPTY, 306, 0, JSEXN_ERR, "cannot reduce ParallelArray object whose outermost dimension is empty")
|
||||
|
@ -375,7 +375,7 @@ MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED, 321, 0, JSEXN_TYPEERR, "proxy must report
|
|||
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, 2, JSEXN_TYPEERR, "{0} is a wrapper around {1}, but a direct reference is required")
|
||||
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")
|
||||
|
@ -400,12 +400,23 @@ MSG_DEF(JSMSG_YIELD_IN_ARROW, 346, 0, JSEXN_SYNTAXERR, "arrow function m
|
|||
MSG_DEF(JSMSG_WRONG_VALUE, 347, 2, JSEXN_ERR, "expected {0} but found {1}")
|
||||
MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BAD_TARGET, 348, 1, JSEXN_ERR, "target for index {0} is not an integer")
|
||||
MSG_DEF(JSMSG_SELFHOSTED_UNBOUND_NAME,349, 0, JSEXN_TYPEERR, "self-hosted code may not contain unbound name lookups")
|
||||
MSG_DEF(JSMSG_DEPRECATED_SOURCE_MAP, 350, 0, JSEXN_SYNTAXERR, "Using //@ to indicate source map URL pragmas is deprecated. Use //# instead")
|
||||
MSG_DEF(JSMSG_DEPRECATED_PRAGMA, 350, 1, JSEXN_SYNTAXERR, "Using //@ to indicate {0} pragmas is deprecated. Use //# instead")
|
||||
MSG_DEF(JSMSG_BAD_DESTRUCT_ASSIGN, 351, 1, JSEXN_SYNTAXERR, "can't assign to {0} using destructuring assignment")
|
||||
MSG_DEF(JSMSG_BINARYDATA_ARRAYTYPE_BAD_ARGS, 352, 0, JSEXN_ERR, "Invalid arguments")
|
||||
MSG_DEF(JSMSG_BINARYDATA_BINARYARRAY_BAD_INDEX, 353, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
|
||||
MSG_DEF(JSMSG_BINARYDATA_STRUCTTYPE_BAD_ARGS, 354, 0, JSEXN_RANGEERR, "invalid field descriptor")
|
||||
MSG_DEF(JSMSG_BINARYDATA_NOT_BINARYSTRUCT, 355, 1, JSEXN_TYPEERR, "{0} is not a BinaryStruct")
|
||||
MSG_DEF(JSMSG_BINARYDATA_SUBARRAY_INTEGER_ARG, 356, 1, JSEXN_ERR, "argument {0} must be an integer")
|
||||
MSG_DEF(JSMSG_BINARYDATA_STRUCTTYPE_EMPTY_DESCRIPTOR, 357, 0, JSEXN_ERR, "field descriptor cannot be empty")
|
||||
MSG_DEF(JSMSG_BINARYDATA_STRUCTTYPE_BAD_FIELD, 358, 1, JSEXN_ERR, "field {0} is not a valid BinaryData Type descriptor")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_ARRAYTYPE_BAD_ARGS, 352, 0, JSEXN_ERR, "Invalid arguments")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_BINARYARRAY_BAD_INDEX, 353, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_ARGS, 354, 0, JSEXN_RANGEERR, "invalid field descriptor")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_NOT_BINARYSTRUCT, 355, 1, JSEXN_TYPEERR, "{0} is not a BinaryStruct")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_SUBARRAY_INTEGER_ARG, 356, 1, JSEXN_ERR, "argument {0} must be an integer")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_EMPTY_DESCRIPTOR, 357, 0, JSEXN_ERR, "field descriptor cannot be empty")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_FIELD, 358, 1, JSEXN_ERR, "field {0} is not a valid BinaryData Type descriptor")
|
||||
MSG_DEF(JSMSG_GENERATOR_FINISHED, 359, 0, JSEXN_TYPEERR, "generator has already finished")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_TOO_BIG, 360, 0, JSEXN_ERR, "Type is too large to allocate")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_NOT_TYPE_OBJECT, 361, 0, JSEXN_ERR, "Expected a type object")
|
||||
MSG_DEF(JSMSG_TOO_MANY_CON_SPREADARGS, 362, 0, JSEXN_RANGEERR, "too many constructor arguments")
|
||||
MSG_DEF(JSMSG_TOO_MANY_FUN_SPREADARGS, 363, 0, JSEXN_RANGEERR, "too many function arguments")
|
||||
MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGEE, 364, 2, JSEXN_ERR, "{0} is not a debuggee {1}")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_NOT_TYPED_OBJECT, 365, 0, JSEXN_ERR, "Expected a typed object")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_NO_SUCH_PROP, 366, 1, JSEXN_TYPEERR, "No such property: {0}")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 367, 2, JSEXN_TYPEERR, "argument {0} invalid: expected {1}")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED, 368, 0, JSEXN_TYPEERR, "handle unattached")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_BAD_TYPE, 369, 0, JSEXN_TYPEERR, "handle moved to destination of incorrect type")
|
||||
|
|
|
@ -11,12 +11,7 @@
|
|||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class JSFunction;
|
||||
class JSObject;
|
||||
class JSScript;
|
||||
class JSString;
|
||||
|
||||
namespace JS { class Value; }
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
namespace JS {
|
||||
|
||||
|
|
|
@ -38,22 +38,19 @@
|
|||
#include "js/RootingAPI.h"
|
||||
#include "js/Value.h"
|
||||
|
||||
struct JSContext;
|
||||
class JSObject;
|
||||
|
||||
/* Typedef for native functions called by the JS VM. */
|
||||
typedef JSBool
|
||||
typedef bool
|
||||
(* JSNative)(JSContext *cx, unsigned argc, JS::Value *vp);
|
||||
|
||||
/* Typedef for native functions that may be called in parallel. */
|
||||
typedef js::ParallelResult
|
||||
typedef bool
|
||||
(* JSParallelNative)(js::ForkJoinSlice *slice, unsigned argc, JS::Value *vp);
|
||||
|
||||
/*
|
||||
* Typedef for native functions that may be called either in parallel or
|
||||
* sequential execution.
|
||||
*/
|
||||
typedef JSBool
|
||||
typedef bool
|
||||
(* JSThreadSafeNative)(js::ThreadSafeContext *cx, unsigned argc, JS::Value *vp);
|
||||
|
||||
/*
|
||||
|
@ -61,11 +58,11 @@ typedef JSBool
|
|||
* a JSNative or a JSParallelNative.
|
||||
*/
|
||||
template <JSThreadSafeNative threadSafeNative>
|
||||
inline JSBool
|
||||
inline bool
|
||||
JSNativeThreadSafeWrapper(JSContext *cx, unsigned argc, JS::Value *vp);
|
||||
|
||||
template <JSThreadSafeNative threadSafeNative>
|
||||
inline js::ParallelResult
|
||||
inline bool
|
||||
JSParallelNativeThreadSafeWrapper(js::ForkJoinSlice *slice, unsigned argc, JS::Value *vp);
|
||||
|
||||
/*
|
||||
|
@ -89,7 +86,7 @@ extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue;
|
|||
* return value for a function call. The principal way to create a
|
||||
* CallReceiver is using JS::CallReceiverFromVp:
|
||||
*
|
||||
* static JSBool
|
||||
* static bool
|
||||
* FunctionReturningThis(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
* {
|
||||
* JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
|
||||
|
@ -282,7 +279,7 @@ CallReceiverFromVp(Value *vp)
|
|||
* the function call's arguments. The principal way to create a CallArgs is
|
||||
* like so, using JS::CallArgsFromVp:
|
||||
*
|
||||
* static JSBool
|
||||
* static bool
|
||||
* FunctionReturningArgcTimesArg0(JSContext *cx, unsigned argc, JS::Value *vp)
|
||||
* {
|
||||
* JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/* -*- 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_CallNonGenericMethod_h
|
||||
#define js_CallNonGenericMethod_h
|
||||
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "js/CallArgs.h"
|
||||
|
||||
namespace JS {
|
||||
|
||||
// Returns true if |v| is considered an acceptable this-value.
|
||||
typedef bool (*IsAcceptableThis)(Handle<Value> 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);
|
||||
|
||||
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);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Methods usually act upon |this| objects only from a single global object and
|
||||
// compartment. Sometimes, however, a method must act upon |this| values from
|
||||
// multiple global objects or compartments. In such cases the |this| value a
|
||||
// method might see will be wrapped, such that various access to the object --
|
||||
// to its class, its private data, its reserved slots, and so on -- will not
|
||||
// work properly without entering that object's compartment. This method
|
||||
// implements a solution to this problem.
|
||||
//
|
||||
// To implement a method that accepts |this| values from multiple compartments,
|
||||
// define two functions. The first function matches the IsAcceptableThis type
|
||||
// and indicates whether the provided value is an acceptable |this| for the
|
||||
// method; it must be a pure function only of its argument.
|
||||
//
|
||||
// static const JSClass AnswerClass = { ... };
|
||||
//
|
||||
// static bool
|
||||
// IsAnswerObject(const Value &v)
|
||||
// {
|
||||
// if (!v.isObject())
|
||||
// return false;
|
||||
// return JS_GetClass(&v.toObject()) == &AnswerClass;
|
||||
// }
|
||||
//
|
||||
// The second function implements the NativeImpl signature and defines the
|
||||
// behavior of the method when it is provided an acceptable |this| value.
|
||||
// Aside from some typing niceties -- see the CallArgs interface for details --
|
||||
// its interface is the same as that of JSNative.
|
||||
//
|
||||
// static bool
|
||||
// answer_getAnswer_impl(JSContext *cx, JS::CallArgs args)
|
||||
// {
|
||||
// args.rval().setInt32(42);
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// The implementation function is guaranteed to be called *only* with a |this|
|
||||
// value which is considered acceptable.
|
||||
//
|
||||
// Now to implement the actual method, write a JSNative that calls the method
|
||||
// declared below, passing the appropriate template and runtime arguments.
|
||||
//
|
||||
// static bool
|
||||
// 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);
|
||||
// }
|
||||
//
|
||||
// Note that, because they are used as template arguments, the predicate
|
||||
// and implementation functions must have external linkage. (This is
|
||||
// unfortunate, but GCC wasn't inlining things as one would hope when we
|
||||
// passed them as function arguments.)
|
||||
//
|
||||
// JS::CallNonGenericMethod will test whether |args.thisv()| is acceptable. If
|
||||
// it is, it will call the provided implementation function, which will return
|
||||
// a value and indicate success. If it is not, it will attempt to unwrap
|
||||
// |this| and call the implementation function on the unwrapped |this|. If
|
||||
// that succeeds, all well and good. If it doesn't succeed, a TypeError will
|
||||
// be thrown.
|
||||
//
|
||||
// Note: JS::CallNonGenericMethod will only work correctly if it's called in
|
||||
// tail position in a JSNative. Do not call it from any other place.
|
||||
//
|
||||
template<IsAcceptableThis Test, NativeImpl Impl>
|
||||
JS_ALWAYS_INLINE bool
|
||||
CallNonGenericMethod(JSContext *cx, CallArgs args)
|
||||
{
|
||||
HandleValue thisv = args.thisv();
|
||||
if (Test(thisv))
|
||||
return Impl(cx, args);
|
||||
|
||||
return detail::CallMethodIfWrapped(cx, Test, Impl, args);
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE bool
|
||||
CallNonGenericMethod(JSContext *cx, IsAcceptableThis Test, NativeImpl Impl, CallArgs args)
|
||||
{
|
||||
HandleValue thisv = args.thisv();
|
||||
if (Test(thisv))
|
||||
return Impl(cx, args);
|
||||
|
||||
return detail::CallMethodIfWrapped(cx, Test, Impl, args);
|
||||
}
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#endif /* js_CallNonGenericMethod_h */
|
|
@ -7,11 +7,15 @@
|
|||
#ifndef js_CharacterEncoding_h
|
||||
#define js_CharacterEncoding_h
|
||||
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "mozilla/Range.h"
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Utility.h"
|
||||
|
||||
#include "jspubtd.h"
|
||||
namespace js {
|
||||
struct ThreadSafeContext;
|
||||
}
|
||||
|
||||
namespace JS {
|
||||
|
||||
|
@ -41,7 +45,7 @@ class Latin1CharsZ : public mozilla::RangedPtr<unsigned char>
|
|||
typedef mozilla::RangedPtr<unsigned char> Base;
|
||||
|
||||
public:
|
||||
Latin1CharsZ() : Base(NULL, 0) {}
|
||||
Latin1CharsZ() : Base(nullptr, 0) {}
|
||||
|
||||
Latin1CharsZ(char *aBytes, size_t aLength)
|
||||
: Base(reinterpret_cast<unsigned char *>(aBytes), aLength)
|
||||
|
@ -80,7 +84,7 @@ class UTF8CharsZ : public mozilla::RangedPtr<unsigned char>
|
|||
typedef mozilla::RangedPtr<unsigned char> Base;
|
||||
|
||||
public:
|
||||
UTF8CharsZ() : Base(NULL, 0) {}
|
||||
UTF8CharsZ() : Base(nullptr, 0) {}
|
||||
|
||||
UTF8CharsZ(char *aBytes, size_t aLength)
|
||||
: Base(reinterpret_cast<unsigned char *>(aBytes), aLength)
|
||||
|
@ -138,7 +142,7 @@ class TwoByteCharsZ : public mozilla::RangedPtr<jschar>
|
|||
typedef mozilla::RangedPtr<jschar> Base;
|
||||
|
||||
public:
|
||||
TwoByteCharsZ() : Base(NULL, 0) {}
|
||||
TwoByteCharsZ() : Base(nullptr, 0) {}
|
||||
|
||||
TwoByteCharsZ(jschar *chars, size_t length)
|
||||
: Base(chars, length)
|
||||
|
@ -154,7 +158,7 @@ class TwoByteCharsZ : public mozilla::RangedPtr<jschar>
|
|||
* output. The returned string is zero terminated. The returned string or the
|
||||
* returned string's |start()| must be freed with JS_free or js_free,
|
||||
* respectively. If allocation fails, an OOM error will be set and the method
|
||||
* will return a NULL chars (which can be tested for with the ! operator).
|
||||
* will return a nullptr chars (which can be tested for with the ! operator).
|
||||
* This method cannot trigger GC.
|
||||
*/
|
||||
extern Latin1CharsZ
|
||||
|
|
|
@ -0,0 +1,699 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
/* JSClass definition and its component types, plus related interfaces. */
|
||||
|
||||
#ifndef js_Class_h
|
||||
#define js_Class_h
|
||||
|
||||
#include "mozilla/NullPtr.h"
|
||||
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "js/CallArgs.h"
|
||||
#include "js/Id.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
/*
|
||||
* A JSClass acts as a vtable for JS objects that allows JSAPI clients to
|
||||
* control various aspects of the behavior of an object like property lookup.
|
||||
* js::Class is an engine-private extension that allows more control over
|
||||
* object behavior and, e.g., allows custom slow layout.
|
||||
*/
|
||||
|
||||
class JSFreeOp;
|
||||
|
||||
namespace js {
|
||||
|
||||
class Class;
|
||||
class FreeOp;
|
||||
class PropertyId;
|
||||
class PropertyName;
|
||||
class Shape;
|
||||
class SpecialId;
|
||||
|
||||
// This is equal to JSFunction::class_. Use it in places where you don't want
|
||||
// to #include jsfun.h.
|
||||
extern JS_FRIEND_DATA(const js::Class* const) FunctionClassPtr;
|
||||
|
||||
static JS_ALWAYS_INLINE jsid
|
||||
SPECIALID_TO_JSID(const SpecialId &sid);
|
||||
|
||||
/*
|
||||
* We partition the ways to refer to a property into three: by an index
|
||||
* (uint32_t); by a string whose characters do not represent an index
|
||||
* (PropertyName, see vm/String.h); and by various special values.
|
||||
*
|
||||
* Special values are encoded using SpecialId, which is layout-compatible but
|
||||
* non-interconvertible with jsid. A SpecialId is used for JSID_VOID, which
|
||||
* does not occur in JS scripts but may be used to indicate the absence of a
|
||||
* valid identifier. In the future, a SpecialId may also be an object used by
|
||||
* Harmony-proposed private names.
|
||||
*/
|
||||
class SpecialId
|
||||
{
|
||||
uintptr_t bits_;
|
||||
|
||||
/* Needs access to raw bits. */
|
||||
friend JS_ALWAYS_INLINE jsid SPECIALID_TO_JSID(const SpecialId &sid);
|
||||
friend class PropertyId;
|
||||
|
||||
static const uintptr_t TYPE_VOID = JSID_TYPE_VOID;
|
||||
static const uintptr_t TYPE_OBJECT = JSID_TYPE_OBJECT;
|
||||
static const uintptr_t TYPE_MASK = JSID_TYPE_MASK;
|
||||
|
||||
SpecialId(uintptr_t bits) : bits_(bits) { }
|
||||
|
||||
public:
|
||||
SpecialId() : bits_(TYPE_VOID) { }
|
||||
|
||||
/* Object-valued */
|
||||
|
||||
SpecialId(JSObject &obj)
|
||||
: bits_(uintptr_t(&obj) | TYPE_OBJECT)
|
||||
{
|
||||
JS_ASSERT(&obj != nullptr);
|
||||
JS_ASSERT((uintptr_t(&obj) & TYPE_MASK) == 0);
|
||||
}
|
||||
|
||||
bool isObject() const {
|
||||
return (bits_ & TYPE_MASK) == TYPE_OBJECT && bits_ != TYPE_OBJECT;
|
||||
}
|
||||
|
||||
JSObject *toObject() const {
|
||||
JS_ASSERT(isObject());
|
||||
return reinterpret_cast<JSObject *>(bits_ & ~TYPE_MASK);
|
||||
}
|
||||
|
||||
/* Empty */
|
||||
|
||||
static SpecialId empty() {
|
||||
SpecialId sid(TYPE_OBJECT);
|
||||
JS_ASSERT(sid.isEmpty());
|
||||
return sid;
|
||||
}
|
||||
|
||||
bool isEmpty() const {
|
||||
return bits_ == TYPE_OBJECT;
|
||||
}
|
||||
|
||||
/* Void */
|
||||
|
||||
static SpecialId voidId() {
|
||||
SpecialId sid(TYPE_VOID);
|
||||
JS_ASSERT(sid.isVoid());
|
||||
return sid;
|
||||
}
|
||||
|
||||
bool isVoid() const {
|
||||
return bits_ == TYPE_VOID;
|
||||
}
|
||||
};
|
||||
|
||||
static JS_ALWAYS_INLINE jsid
|
||||
SPECIALID_TO_JSID(const SpecialId &sid)
|
||||
{
|
||||
jsid id;
|
||||
JSID_BITS(id) = sid.bits_;
|
||||
JS_ASSERT_IF(sid.isObject(), JSID_IS_OBJECT(id) && JSID_TO_OBJECT(id) == sid.toObject());
|
||||
JS_ASSERT_IF(sid.isVoid(), JSID_IS_VOID(id));
|
||||
JS_ASSERT_IF(sid.isEmpty(), JSID_IS_EMPTY(id));
|
||||
return id;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
JSID_IS_SPECIAL(jsid id)
|
||||
{
|
||||
return JSID_IS_OBJECT(id) || JSID_IS_EMPTY(id) || JSID_IS_VOID(id);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE SpecialId
|
||||
JSID_TO_SPECIALID(jsid id)
|
||||
{
|
||||
JS_ASSERT(JSID_IS_SPECIAL(id));
|
||||
if (JSID_IS_OBJECT(id))
|
||||
return SpecialId(*JSID_TO_OBJECT(id));
|
||||
if (JSID_IS_EMPTY(id))
|
||||
return SpecialId::empty();
|
||||
JS_ASSERT(JSID_IS_VOID(id));
|
||||
return SpecialId::voidId();
|
||||
}
|
||||
|
||||
typedef JS::Handle<SpecialId> HandleSpecialId;
|
||||
|
||||
} // namespace js
|
||||
|
||||
// JSClass operation signatures.
|
||||
|
||||
// Add or get a property named by id in obj. Note the jsid id type -- id may
|
||||
// be a string (Unicode property identifier) or an int (element index). The
|
||||
// *vp out parameter, on success, is the new property value after the action.
|
||||
typedef bool
|
||||
(* JSPropertyOp)(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JS::Value> vp);
|
||||
|
||||
// Set a property named by id in obj, treating the assignment as strict
|
||||
// mode code if strict is true. Note the jsid id type -- id may be a string
|
||||
// (Unicode property identifier) or an int (element index). The *vp out
|
||||
// parameter, on success, is the new property value after the
|
||||
// set.
|
||||
typedef bool
|
||||
(* JSStrictPropertyOp)(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
||||
bool strict, JS::MutableHandle<JS::Value> vp);
|
||||
|
||||
// Delete a property named by id in obj.
|
||||
//
|
||||
// If an error occurred, return false as per normal JSAPI error practice.
|
||||
//
|
||||
// If no error occurred, but the deletion attempt wasn't allowed (perhaps
|
||||
// because the property was non-configurable), set *succeeded to false and
|
||||
// return true. This will cause |delete obj[id]| to evaluate to false in
|
||||
// non-strict mode code, and to throw a TypeError in strict mode code.
|
||||
//
|
||||
// If no error occurred and the deletion wasn't disallowed (this is *not* the
|
||||
// same as saying that a deletion actually occurred -- deleting a non-existent
|
||||
// property, or an inherited property, is allowed -- it's just pointless),
|
||||
// set *succeeded to true and return true.
|
||||
typedef bool
|
||||
(* JSDeletePropertyOp)(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
||||
bool *succeeded);
|
||||
|
||||
// This function type is used for callbacks that enumerate the properties of
|
||||
// a JSObject. The behavior depends on the value of enum_op:
|
||||
//
|
||||
// JSENUMERATE_INIT
|
||||
// A new, opaque iterator state should be allocated and stored in *statep.
|
||||
// (You can use PRIVATE_TO_JSVAL() to tag the pointer to be stored).
|
||||
//
|
||||
// The number of properties that will be enumerated should be returned as
|
||||
// an integer jsval in *idp, if idp is non-null, and provided the number of
|
||||
// enumerable properties is known. If idp is non-null and the number of
|
||||
// enumerable properties can't be computed in advance, *idp should be set
|
||||
// to JSVAL_ZERO.
|
||||
//
|
||||
// JSENUMERATE_INIT_ALL
|
||||
// Used identically to JSENUMERATE_INIT, but exposes all properties of the
|
||||
// object regardless of enumerability.
|
||||
//
|
||||
// JSENUMERATE_NEXT
|
||||
// A previously allocated opaque iterator state is passed in via statep.
|
||||
// Return the next jsid in the iteration using *idp. The opaque iterator
|
||||
// state pointed at by statep is destroyed and *statep is set to JSVAL_NULL
|
||||
// if there are no properties left to enumerate.
|
||||
//
|
||||
// JSENUMERATE_DESTROY
|
||||
// Destroy the opaque iterator state previously allocated in *statep by a
|
||||
// call to this function when enum_op was JSENUMERATE_INIT or
|
||||
// JSENUMERATE_INIT_ALL.
|
||||
//
|
||||
// The return value is used to indicate success, with a value of false
|
||||
// indicating failure.
|
||||
typedef bool
|
||||
(* JSNewEnumerateOp)(JSContext *cx, JS::Handle<JSObject*> obj, JSIterateOp enum_op,
|
||||
JS::MutableHandle<JS::Value> statep, JS::MutableHandle<jsid> idp);
|
||||
|
||||
// The old-style JSClass.enumerate op should define all lazy properties not
|
||||
// yet reflected in obj.
|
||||
typedef bool
|
||||
(* JSEnumerateOp)(JSContext *cx, JS::Handle<JSObject*> obj);
|
||||
|
||||
// Resolve a lazy property named by id in obj by defining it directly in obj.
|
||||
// Lazy properties are those reflected from some peer native property space
|
||||
// (e.g., the DOM attributes for a given node reflected as obj) on demand.
|
||||
//
|
||||
// JS looks for a property in an object, and if not found, tries to resolve
|
||||
// the given id. If resolve succeeds, the engine looks again in case resolve
|
||||
// defined obj[id]. If no such property exists directly in obj, the process
|
||||
// is repeated with obj's prototype, etc.
|
||||
//
|
||||
// NB: JSNewResolveOp provides a cheaper way to resolve lazy properties.
|
||||
typedef bool
|
||||
(* JSResolveOp)(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id);
|
||||
|
||||
// Like JSResolveOp, but flags provide contextual information as follows:
|
||||
//
|
||||
// JSRESOLVE_ASSIGNING obj[id] is on the left-hand side of an assignment
|
||||
//
|
||||
// The *objp out parameter, on success, should be null to indicate that id
|
||||
// was not resolved; and non-null, referring to obj or one of its prototypes,
|
||||
// if id was resolved. The hook may assume *objp is null on entry.
|
||||
//
|
||||
// This hook instead of JSResolveOp is called via the JSClass.resolve member
|
||||
// if JSCLASS_NEW_RESOLVE is set in JSClass.flags.
|
||||
typedef bool
|
||||
(* JSNewResolveOp)(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, unsigned flags,
|
||||
JS::MutableHandle<JSObject*> objp);
|
||||
|
||||
// Convert obj to the given type, returning true with the resulting value in
|
||||
// *vp on success, and returning false on error or exception.
|
||||
typedef bool
|
||||
(* JSConvertOp)(JSContext *cx, JS::Handle<JSObject*> obj, JSType type,
|
||||
JS::MutableHandle<JS::Value> vp);
|
||||
|
||||
// Finalize obj, which the garbage collector has determined to be unreachable
|
||||
// from other live objects or from GC roots. Obviously, finalizers must never
|
||||
// store a reference to obj.
|
||||
typedef void
|
||||
(* JSFinalizeOp)(JSFreeOp *fop, JSObject *obj);
|
||||
|
||||
// Finalizes external strings created by JS_NewExternalString.
|
||||
struct JSStringFinalizer {
|
||||
void (*finalize)(const JSStringFinalizer *fin, jschar *chars);
|
||||
};
|
||||
|
||||
// JSClass.checkAccess type: check whether obj[id] may be accessed per mode,
|
||||
// returning false on error/exception, true on success with obj[id]'s last-got
|
||||
// value in *vp, and its attributes in *attrsp. As for JSPropertyOp above, id
|
||||
// is either a string or an int jsval.
|
||||
typedef bool
|
||||
(* JSCheckAccessOp)(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
||||
JSAccessMode mode, JS::MutableHandle<JS::Value> vp);
|
||||
|
||||
// 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);
|
||||
|
||||
// Check whether v is an instance of obj. Return false on error or exception,
|
||||
// true on success with true in *bp if v is an instance of obj, false in
|
||||
// *bp otherwise.
|
||||
typedef bool
|
||||
(* JSHasInstanceOp)(JSContext *cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JS::Value> vp,
|
||||
bool *bp);
|
||||
|
||||
// Function type for trace operation of the class called to enumerate all
|
||||
// traceable things reachable from obj's private data structure. For each such
|
||||
// thing, a trace implementation must call one of the JS_Call*Tracer variants
|
||||
// on the thing.
|
||||
//
|
||||
// JSTraceOp implementation can assume that no other threads mutates object
|
||||
// state. It must not change state of the object or corresponding native
|
||||
// structures. The only exception for this rule is the case when the embedding
|
||||
// needs a tight integration with GC. In that case the embedding can check if
|
||||
// the traversal is a part of the marking phase through calling
|
||||
// JS_IsGCMarkingTracer and apply a special code like emptying caches or
|
||||
// marking its native structures.
|
||||
typedef void
|
||||
(* JSTraceOp)(JSTracer *trc, JSObject *obj);
|
||||
|
||||
// A generic type for functions mapping an object to another object, or null
|
||||
// if an error or exception was thrown on cx.
|
||||
typedef JSObject *
|
||||
(* JSObjectOp)(JSContext *cx, JS::Handle<JSObject*> obj);
|
||||
|
||||
// Hook that creates an iterator object for a given object. Returns the
|
||||
// iterator object or null if an error or exception was thrown on cx.
|
||||
typedef JSObject *
|
||||
(* JSIteratorOp)(JSContext *cx, JS::HandleObject obj, bool keysonly);
|
||||
|
||||
typedef JSObject *
|
||||
(* JSWeakmapKeyDelegateOp)(JSObject *obj);
|
||||
|
||||
/* js::Class operation signatures. */
|
||||
|
||||
namespace js {
|
||||
|
||||
typedef bool
|
||||
(* LookupGenericOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp);
|
||||
typedef bool
|
||||
(* LookupPropOp)(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name,
|
||||
JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp);
|
||||
typedef bool
|
||||
(* LookupElementOp)(JSContext *cx, JS::HandleObject obj, uint32_t index,
|
||||
JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp);
|
||||
typedef bool
|
||||
(* LookupSpecialOp)(JSContext *cx, JS::HandleObject obj, HandleSpecialId sid,
|
||||
JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp);
|
||||
typedef bool
|
||||
(* DefineGenericOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value,
|
||||
JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
|
||||
typedef bool
|
||||
(* DefinePropOp)(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name,
|
||||
JS::HandleValue value, JSPropertyOp getter, JSStrictPropertyOp setter,
|
||||
unsigned attrs);
|
||||
typedef bool
|
||||
(* DefineElementOp)(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value,
|
||||
JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
|
||||
typedef bool
|
||||
(* DefineSpecialOp)(JSContext *cx, JS::HandleObject obj, HandleSpecialId sid,
|
||||
JS::HandleValue value, JSPropertyOp getter, JSStrictPropertyOp setter,
|
||||
unsigned attrs);
|
||||
typedef bool
|
||||
(* GenericIdOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
|
||||
JS::MutableHandleValue vp);
|
||||
typedef bool
|
||||
(* PropertyIdOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver,
|
||||
JS::Handle<PropertyName*> name, JS::MutableHandleValue vp);
|
||||
typedef bool
|
||||
(* ElementIdOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, uint32_t index,
|
||||
JS::MutableHandleValue vp);
|
||||
typedef bool
|
||||
(* ElementIfPresentOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver,
|
||||
uint32_t index, JS::MutableHandleValue vp, bool* present);
|
||||
typedef bool
|
||||
(* SpecialIdOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver,
|
||||
HandleSpecialId sid, JS::MutableHandleValue vp);
|
||||
typedef bool
|
||||
(* StrictGenericIdOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::MutableHandleValue vp, bool strict);
|
||||
typedef bool
|
||||
(* StrictPropertyIdOp)(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name,
|
||||
JS::MutableHandleValue vp, bool strict);
|
||||
typedef bool
|
||||
(* StrictElementIdOp)(JSContext *cx, JS::HandleObject obj, uint32_t index,
|
||||
JS::MutableHandleValue vp, bool strict);
|
||||
typedef bool
|
||||
(* StrictSpecialIdOp)(JSContext *cx, JS::HandleObject obj, HandleSpecialId sid,
|
||||
JS::MutableHandleValue vp, bool strict);
|
||||
typedef bool
|
||||
(* GenericAttributesOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp);
|
||||
typedef bool
|
||||
(* PropertyAttributesOp)(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name,
|
||||
unsigned *attrsp);
|
||||
typedef bool
|
||||
(* DeletePropertyOp)(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name,
|
||||
bool *succeeded);
|
||||
typedef bool
|
||||
(* DeleteElementOp)(JSContext *cx, JS::HandleObject obj, uint32_t index, bool *succeeded);
|
||||
typedef bool
|
||||
(* DeleteSpecialOp)(JSContext *cx, JS::HandleObject obj, HandleSpecialId sid, bool *succeeded);
|
||||
|
||||
typedef bool
|
||||
(* WatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
|
||||
|
||||
typedef bool
|
||||
(* UnwatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
|
||||
|
||||
typedef JSObject *
|
||||
(* ObjectOp)(JSContext *cx, JS::HandleObject obj);
|
||||
typedef void
|
||||
(* FinalizeOp)(FreeOp *fop, JSObject *obj);
|
||||
|
||||
#define JS_CLASS_MEMBERS \
|
||||
const char *name; \
|
||||
uint32_t flags; \
|
||||
\
|
||||
/* Mandatory function pointer members. */ \
|
||||
JSPropertyOp addProperty; \
|
||||
JSDeletePropertyOp delProperty; \
|
||||
JSPropertyOp getProperty; \
|
||||
JSStrictPropertyOp setProperty; \
|
||||
JSEnumerateOp enumerate; \
|
||||
JSResolveOp resolve; \
|
||||
JSConvertOp convert; \
|
||||
\
|
||||
/* Optional members (may be null). */ \
|
||||
FinalizeOp finalize; \
|
||||
JSCheckAccessOp checkAccess; \
|
||||
JSNative call; \
|
||||
JSHasInstanceOp hasInstance; \
|
||||
JSNative construct; \
|
||||
JSTraceOp trace
|
||||
|
||||
/*
|
||||
* The helper struct to measure the size of JS_CLASS_MEMBERS to know how much
|
||||
* we have to pad js::Class to match the size of JSClass.
|
||||
*/
|
||||
struct ClassSizeMeasurement
|
||||
{
|
||||
JS_CLASS_MEMBERS;
|
||||
};
|
||||
|
||||
struct ClassExtension
|
||||
{
|
||||
JSObjectOp outerObject;
|
||||
JSObjectOp innerObject;
|
||||
JSIteratorOp iteratorObject;
|
||||
|
||||
/*
|
||||
* isWrappedNative is true only if the class is an XPCWrappedNative.
|
||||
* WeakMaps use this to override the wrapper disposal optimization.
|
||||
*/
|
||||
bool isWrappedNative;
|
||||
|
||||
/*
|
||||
* If an object is used as a key in a weakmap, it may be desirable for the
|
||||
* garbage collector to keep that object around longer than it otherwise
|
||||
* would. A common case is when the key is a wrapper around an object in
|
||||
* another compartment, and we want to avoid collecting the wrapper (and
|
||||
* removing the weakmap entry) as long as the wrapped object is alive. In
|
||||
* that case, the wrapped object is returned by the wrapper's
|
||||
* weakmapKeyDelegateOp hook. As long as the wrapper is used as a weakmap
|
||||
* key, it will not be collected (and remain in the weakmap) until the
|
||||
* wrapped object is collected.
|
||||
*/
|
||||
JSWeakmapKeyDelegateOp weakmapKeyDelegateOp;
|
||||
};
|
||||
|
||||
#define JS_NULL_CLASS_EXT {nullptr,nullptr,nullptr,false,nullptr}
|
||||
|
||||
struct ObjectOps
|
||||
{
|
||||
LookupGenericOp lookupGeneric;
|
||||
LookupPropOp lookupProperty;
|
||||
LookupElementOp lookupElement;
|
||||
LookupSpecialOp lookupSpecial;
|
||||
DefineGenericOp defineGeneric;
|
||||
DefinePropOp defineProperty;
|
||||
DefineElementOp defineElement;
|
||||
DefineSpecialOp defineSpecial;
|
||||
GenericIdOp getGeneric;
|
||||
PropertyIdOp getProperty;
|
||||
ElementIdOp getElement;
|
||||
ElementIfPresentOp getElementIfPresent; /* can be null */
|
||||
SpecialIdOp getSpecial;
|
||||
StrictGenericIdOp setGeneric;
|
||||
StrictPropertyIdOp setProperty;
|
||||
StrictElementIdOp setElement;
|
||||
StrictSpecialIdOp setSpecial;
|
||||
GenericAttributesOp getGenericAttributes;
|
||||
GenericAttributesOp setGenericAttributes;
|
||||
DeletePropertyOp deleteProperty;
|
||||
DeleteElementOp deleteElement;
|
||||
DeleteSpecialOp deleteSpecial;
|
||||
WatchOp watch;
|
||||
UnwatchOp unwatch;
|
||||
|
||||
JSNewEnumerateOp enumerate;
|
||||
ObjectOp thisObject;
|
||||
};
|
||||
|
||||
#define JS_NULL_OBJECT_OPS \
|
||||
{nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, \
|
||||
nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, \
|
||||
nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}
|
||||
|
||||
} // namespace js
|
||||
|
||||
// Classes, objects, and properties.
|
||||
|
||||
typedef void (*JSClassInternal)();
|
||||
|
||||
struct JSClass {
|
||||
const char *name;
|
||||
uint32_t flags;
|
||||
|
||||
// Mandatory function pointer members.
|
||||
JSPropertyOp addProperty;
|
||||
JSDeletePropertyOp delProperty;
|
||||
JSPropertyOp getProperty;
|
||||
JSStrictPropertyOp setProperty;
|
||||
JSEnumerateOp enumerate;
|
||||
JSResolveOp resolve;
|
||||
JSConvertOp convert;
|
||||
|
||||
// Optional members (may be null).
|
||||
JSFinalizeOp finalize;
|
||||
JSCheckAccessOp checkAccess;
|
||||
JSNative call;
|
||||
JSHasInstanceOp hasInstance;
|
||||
JSNative construct;
|
||||
JSTraceOp trace;
|
||||
|
||||
void *reserved[42];
|
||||
};
|
||||
|
||||
#define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot
|
||||
#define JSCLASS_NEW_ENUMERATE (1<<1) // has JSNewEnumerateOp hook
|
||||
#define JSCLASS_NEW_RESOLVE (1<<2) // has JSNewResolveOp hook
|
||||
#define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) // private is (nsISupports *)
|
||||
#define JSCLASS_IS_DOMJSCLASS (1<<4) // objects are DOM
|
||||
#define JSCLASS_IMPLEMENTS_BARRIERS (1<<5) // Correctly implements GC read
|
||||
// and write barriers
|
||||
#define JSCLASS_EMULATES_UNDEFINED (1<<6) // objects of this class act
|
||||
// like the value undefined,
|
||||
// in some contexts
|
||||
#define JSCLASS_USERBIT1 (1<<7) // Reserved for embeddings.
|
||||
|
||||
// To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or
|
||||
// JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where
|
||||
// n is a constant in [1, 255]. Reserved slots are indexed from 0 to n-1.
|
||||
#define JSCLASS_RESERVED_SLOTS_SHIFT 8 // room for 8 flags below */
|
||||
#define JSCLASS_RESERVED_SLOTS_WIDTH 8 // and 16 above this field */
|
||||
#define JSCLASS_RESERVED_SLOTS_MASK JS_BITMASK(JSCLASS_RESERVED_SLOTS_WIDTH)
|
||||
#define JSCLASS_HAS_RESERVED_SLOTS(n) (((n) & JSCLASS_RESERVED_SLOTS_MASK) \
|
||||
<< JSCLASS_RESERVED_SLOTS_SHIFT)
|
||||
#define JSCLASS_RESERVED_SLOTS(clasp) (((clasp)->flags \
|
||||
>> JSCLASS_RESERVED_SLOTS_SHIFT) \
|
||||
& JSCLASS_RESERVED_SLOTS_MASK)
|
||||
|
||||
#define JSCLASS_HIGH_FLAGS_SHIFT (JSCLASS_RESERVED_SLOTS_SHIFT + \
|
||||
JSCLASS_RESERVED_SLOTS_WIDTH)
|
||||
|
||||
#define JSCLASS_IS_ANONYMOUS (1<<(JSCLASS_HIGH_FLAGS_SHIFT+0))
|
||||
#define JSCLASS_IS_GLOBAL (1<<(JSCLASS_HIGH_FLAGS_SHIFT+1))
|
||||
#define JSCLASS_INTERNAL_FLAG2 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+2))
|
||||
#define JSCLASS_INTERNAL_FLAG3 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+3))
|
||||
|
||||
// Indicate whether the proto or ctor should be frozen.
|
||||
#define JSCLASS_FREEZE_PROTO (1<<(JSCLASS_HIGH_FLAGS_SHIFT+4))
|
||||
#define JSCLASS_FREEZE_CTOR (1<<(JSCLASS_HIGH_FLAGS_SHIFT+5))
|
||||
|
||||
// Reserved for embeddings.
|
||||
#define JSCLASS_USERBIT2 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+6))
|
||||
#define JSCLASS_USERBIT3 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+7))
|
||||
|
||||
#define JSCLASS_BACKGROUND_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+8))
|
||||
|
||||
// Bits 26 through 31 are reserved for the CACHED_PROTO_KEY mechanism, see
|
||||
// below.
|
||||
|
||||
// ECMA-262 requires that most constructors used internally create objects
|
||||
// with "the original Foo.prototype value" as their [[Prototype]] (__proto__)
|
||||
// member initial value. The "original ... value" verbiage is there because
|
||||
// in ECMA-262, global properties naming class objects are read/write and
|
||||
// deleteable, for the most part.
|
||||
//
|
||||
// Implementing this efficiently requires that global objects have classes
|
||||
// with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
|
||||
// previously allowed, but is now an ES5 violation and thus unsupported.
|
||||
//
|
||||
#define JSCLASS_GLOBAL_SLOT_COUNT (3 + JSProto_LIMIT * 3 + 28)
|
||||
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
|
||||
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
|
||||
#define JSCLASS_GLOBAL_FLAGS \
|
||||
JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0)
|
||||
#define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp) \
|
||||
(((clasp)->flags & JSCLASS_IS_GLOBAL) \
|
||||
&& JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT)
|
||||
|
||||
// Fast access to the original value of each standard class's prototype.
|
||||
#define JSCLASS_CACHED_PROTO_SHIFT (JSCLASS_HIGH_FLAGS_SHIFT + 10)
|
||||
#define JSCLASS_CACHED_PROTO_WIDTH 6
|
||||
#define JSCLASS_CACHED_PROTO_MASK JS_BITMASK(JSCLASS_CACHED_PROTO_WIDTH)
|
||||
#define JSCLASS_HAS_CACHED_PROTO(key) (uint32_t(key) << JSCLASS_CACHED_PROTO_SHIFT)
|
||||
#define JSCLASS_CACHED_PROTO_KEY(clasp) ((JSProtoKey) \
|
||||
(((clasp)->flags \
|
||||
>> JSCLASS_CACHED_PROTO_SHIFT) \
|
||||
& JSCLASS_CACHED_PROTO_MASK))
|
||||
|
||||
// Initializer for unused members of statically initialized JSClass structs.
|
||||
#define JSCLASS_NO_INTERNAL_MEMBERS {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
|
||||
#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,JSCLASS_NO_INTERNAL_MEMBERS
|
||||
|
||||
namespace js {
|
||||
|
||||
struct Class
|
||||
{
|
||||
JS_CLASS_MEMBERS;
|
||||
ClassExtension ext;
|
||||
ObjectOps ops;
|
||||
uint8_t pad[sizeof(JSClass) - sizeof(ClassSizeMeasurement) -
|
||||
sizeof(ClassExtension) - sizeof(ObjectOps)];
|
||||
|
||||
/* Class is not native and its map is not a scope. */
|
||||
static const uint32_t NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
|
||||
|
||||
bool isNative() const {
|
||||
return !(flags & NON_NATIVE);
|
||||
}
|
||||
|
||||
bool hasPrivate() const {
|
||||
return !!(flags & JSCLASS_HAS_PRIVATE);
|
||||
}
|
||||
|
||||
bool emulatesUndefined() const {
|
||||
return flags & JSCLASS_EMULATES_UNDEFINED;
|
||||
}
|
||||
|
||||
bool isCallable() const {
|
||||
return this == js::FunctionClassPtr || call;
|
||||
}
|
||||
|
||||
static size_t offsetOfFlags() { return offsetof(Class, flags); }
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, name) == offsetof(Class, name));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, flags) == offsetof(Class, flags));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, addProperty) == offsetof(Class, addProperty));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, delProperty) == offsetof(Class, delProperty));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, getProperty) == offsetof(Class, getProperty));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, setProperty) == offsetof(Class, setProperty));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, enumerate) == offsetof(Class, enumerate));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, resolve) == offsetof(Class, resolve));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, convert) == offsetof(Class, convert));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, finalize) == offsetof(Class, finalize));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, checkAccess) == offsetof(Class, checkAccess));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, call) == offsetof(Class, call));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, construct) == offsetof(Class, construct));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, hasInstance) == offsetof(Class, hasInstance));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, trace) == offsetof(Class, trace));
|
||||
JS_STATIC_ASSERT(sizeof(JSClass) == sizeof(Class));
|
||||
|
||||
static JS_ALWAYS_INLINE const JSClass *
|
||||
Jsvalify(const Class *c)
|
||||
{
|
||||
return (const JSClass *)c;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE const Class *
|
||||
Valueify(const JSClass *c)
|
||||
{
|
||||
return (const Class *)c;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enumeration describing possible values of the [[Class]] internal property
|
||||
* value of objects.
|
||||
*/
|
||||
enum ESClassValue {
|
||||
ESClass_Array, ESClass_Number, ESClass_String, ESClass_Boolean,
|
||||
ESClass_RegExp, ESClass_ArrayBuffer, ESClass_Date
|
||||
};
|
||||
|
||||
/*
|
||||
* Return whether the given object has the given [[Class]] internal property
|
||||
* value. Beware, this query says nothing about the js::Class of the JSObject
|
||||
* so the caller must not assume anything about obj's representation (e.g., obj
|
||||
* may be a proxy).
|
||||
*/
|
||||
inline bool
|
||||
ObjectClassIs(JSObject &obj, ESClassValue classValue, JSContext *cx);
|
||||
|
||||
/* Just a helper that checks v.isObject before calling ObjectClassIs. */
|
||||
inline bool
|
||||
IsObjectWithClass(const JS::Value &v, ESClassValue classValue, JSContext *cx);
|
||||
|
||||
inline bool
|
||||
IsPoisonedSpecialId(js::SpecialId iden)
|
||||
{
|
||||
if (iden.isObject())
|
||||
return JS::IsPoisonedPtr(iden.toObject());
|
||||
return false;
|
||||
}
|
||||
|
||||
template <> struct GCMethods<SpecialId>
|
||||
{
|
||||
static SpecialId initial() { return SpecialId(); }
|
||||
static ThingRootKind kind() { return THING_ROOT_ID; }
|
||||
static bool poisoned(SpecialId id) { return IsPoisonedSpecialId(id); }
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* js_Class_h */
|
|
@ -7,7 +7,11 @@
|
|||
#ifndef js_GCAPI_h
|
||||
#define js_GCAPI_h
|
||||
|
||||
#include "mozilla/NullPtr.h"
|
||||
|
||||
#include "js/HeapAPI.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/Value.h"
|
||||
|
||||
namespace JS {
|
||||
|
||||
|
@ -15,13 +19,12 @@ namespace JS {
|
|||
/* Reasons internal to the JS engine */ \
|
||||
D(API) \
|
||||
D(MAYBEGC) \
|
||||
D(LAST_CONTEXT) \
|
||||
D(DESTROY_RUNTIME) \
|
||||
D(DESTROY_CONTEXT) \
|
||||
D(LAST_DITCH) \
|
||||
D(TOO_MUCH_MALLOC) \
|
||||
D(ALLOC_TRIGGER) \
|
||||
D(DEBUG_GC) \
|
||||
D(DEBUG_MODE_GC) \
|
||||
D(TRANSPLANT) \
|
||||
D(RESET) \
|
||||
D(OUT_OF_NURSERY) \
|
||||
|
@ -206,12 +209,25 @@ PokeGC(JSRuntime *rt);
|
|||
extern JS_FRIEND_API(bool)
|
||||
WasIncrementalGC(JSRuntime *rt);
|
||||
|
||||
class ObjectPtr
|
||||
extern JS_FRIEND_API(size_t)
|
||||
GetGCNumber();
|
||||
|
||||
class AutoAssertNoGC {
|
||||
#ifdef DEBUG
|
||||
size_t gcNumber;
|
||||
|
||||
public:
|
||||
AutoAssertNoGC();
|
||||
~AutoAssertNoGC();
|
||||
#endif
|
||||
};
|
||||
|
||||
class JS_PUBLIC_API(ObjectPtr)
|
||||
{
|
||||
Heap<JSObject *> value;
|
||||
|
||||
public:
|
||||
ObjectPtr() : value(NULL) {}
|
||||
ObjectPtr() : value(nullptr) {}
|
||||
|
||||
ObjectPtr(JSObject *obj) : value(obj) {}
|
||||
|
||||
|
@ -221,7 +237,7 @@ class ObjectPtr
|
|||
void finalize(JSRuntime *rt) {
|
||||
if (IsIncrementalBarrierNeeded(rt))
|
||||
IncrementalObjectBarrier(value);
|
||||
value = NULL;
|
||||
value = nullptr;
|
||||
}
|
||||
|
||||
void init(JSObject *obj) { value = obj; }
|
||||
|
@ -232,9 +248,7 @@ class ObjectPtr
|
|||
IncrementalObjectBarrier(value);
|
||||
}
|
||||
|
||||
bool isAboutToBeFinalized() {
|
||||
return JS_IsAboutToBeFinalized(&value);
|
||||
}
|
||||
bool isAboutToBeFinalized();
|
||||
|
||||
ObjectPtr &operator=(JSObject *obj) {
|
||||
IncrementalObjectBarrier(value);
|
||||
|
@ -242,9 +256,7 @@ class ObjectPtr
|
|||
return *this;
|
||||
}
|
||||
|
||||
void trace(JSTracer *trc, const char *name) {
|
||||
JS_CallHeapObjectTracer(trc, &value, name);
|
||||
}
|
||||
void trace(JSTracer *trc, const char *name);
|
||||
|
||||
JSObject &operator*() const { return *value; }
|
||||
JSObject *operator->() const { return value; }
|
||||
|
@ -255,7 +267,7 @@ class ObjectPtr
|
|||
* Unsets the gray bit for anything reachable from |thing|. |kind| should not be
|
||||
* JSTRACE_SHAPE. |thing| should be non-null.
|
||||
*/
|
||||
extern JS_FRIEND_API(void)
|
||||
extern JS_FRIEND_API(bool)
|
||||
UnmarkGrayGCThingRecursively(void *thing, JSGCTraceKind kind);
|
||||
|
||||
/*
|
||||
|
@ -276,7 +288,7 @@ ExposeGCThingToActiveJS(void *thing, JSGCTraceKind kind)
|
|||
* 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 (uintptr_t(thing) >= rt->gcNurseryStart_ && uintptr_t(thing) < rt->gcNurseryEnd_)
|
||||
if (js::gc::IsInsideNursery(rt, thing))
|
||||
return;
|
||||
#endif
|
||||
if (IsIncrementalBarrierNeededOnGCThing(rt, thing, kind))
|
||||
|
@ -292,6 +304,37 @@ ExposeValueToActiveJS(const Value &v)
|
|||
ExposeGCThingToActiveJS(v.toGCThing(), v.gcKind());
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE void
|
||||
ExposeObjectToActiveJS(JSObject *obj)
|
||||
{
|
||||
ExposeGCThingToActiveJS(obj, JSTRACE_OBJECT);
|
||||
}
|
||||
|
||||
/*
|
||||
* If a GC is currently marking, mark the object black.
|
||||
*/
|
||||
static JS_ALWAYS_INLINE void
|
||||
MarkGCThingAsLive(JSRuntime *rt_, void *thing, JSGCTraceKind kind)
|
||||
{
|
||||
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(rt, thing))
|
||||
return;
|
||||
#endif
|
||||
if (IsIncrementalBarrierNeededOnGCThing(rt, thing, kind))
|
||||
IncrementalReferenceBarrier(thing, kind);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE void
|
||||
MarkStringAsLive(Zone *zone, JSString *string)
|
||||
{
|
||||
JSRuntime *rt = JS::shadow::Zone::asShadowZone(zone)->runtimeFromMainThread();
|
||||
MarkGCThingAsLive(rt, string, JSTRACE_STRING);
|
||||
}
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
#endif /* js_GCAPI_h */
|
||||
|
|
|
@ -7,17 +7,18 @@
|
|||
#ifndef js_HashTable_h
|
||||
#define js_HashTable_h
|
||||
|
||||
#include "mozilla/Alignment.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Casting.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/ReentrancyGuard.h"
|
||||
#include "mozilla/TemplateLib.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "mozilla/Util.h"
|
||||
|
||||
#include "js/Utility.h"
|
||||
|
||||
|
@ -60,7 +61,7 @@ class HashMap
|
|||
{
|
||||
typedef Key KeyType;
|
||||
static const Key &getKey(TableEntry &e) { return e.key; }
|
||||
static void setKey(TableEntry &e, Key &k) { const_cast<Key &>(e.key) = k; }
|
||||
static void setKey(TableEntry &e, Key &k) { HashPolicy::rekey(const_cast<Key &>(e.key), k); }
|
||||
};
|
||||
|
||||
typedef detail::HashTable<TableEntry, MapHashPolicy, AllocPolicy> Impl;
|
||||
|
@ -138,18 +139,18 @@ class HashMap
|
|||
template<typename KeyInput, typename ValueInput>
|
||||
bool add(AddPtr &p, const KeyInput &k, const ValueInput &v) {
|
||||
Entry e(k, v);
|
||||
return impl.add(p, mozilla::Move(e));
|
||||
return impl.add(p, mozilla::OldMove(e));
|
||||
}
|
||||
|
||||
bool add(AddPtr &p, const Key &k) {
|
||||
Entry e(k, Value());
|
||||
return impl.add(p, mozilla::Move(e));
|
||||
return impl.add(p, mozilla::OldMove(e));
|
||||
}
|
||||
|
||||
template<typename KeyInput, typename ValueInput>
|
||||
bool relookupOrAdd(AddPtr &p, const KeyInput &k, const ValueInput &v) {
|
||||
Entry e(k, v);
|
||||
return impl.relookupOrAdd(p, k, mozilla::Move(e));
|
||||
return impl.relookupOrAdd(p, k, mozilla::OldMove(e));
|
||||
}
|
||||
|
||||
// |all()| returns a Range containing |count()| elements. E.g.:
|
||||
|
@ -213,7 +214,7 @@ class HashMap
|
|||
/************************************************** Shorthand operations */
|
||||
|
||||
bool has(const Lookup &l) const {
|
||||
return impl.lookup(l) != NULL;
|
||||
return impl.lookup(l) != nullptr;
|
||||
}
|
||||
|
||||
// Overwrite existing value with v. Return false on oom.
|
||||
|
@ -231,7 +232,7 @@ class HashMap
|
|||
template<typename KeyInput, typename ValueInput>
|
||||
bool putNew(const KeyInput &k, const ValueInput &v) {
|
||||
Entry e(k, v);
|
||||
return impl.putNew(k, mozilla::Move(e));
|
||||
return impl.putNew(k, mozilla::OldMove(e));
|
||||
}
|
||||
|
||||
// Add (k,defaultValue) if |k| is not found. Return a false-y Ptr on oom.
|
||||
|
@ -249,17 +250,22 @@ class HashMap
|
|||
remove(p);
|
||||
}
|
||||
|
||||
// Infallibly rekey one entry, if necessary.
|
||||
// Requires template parameters Key and HashPolicy::Lookup to be the same type.
|
||||
void rekeyIfMoved(const Key &old_key, const Key &new_key) {
|
||||
if (old_key != new_key)
|
||||
rekeyAs(old_key, new_key, new_key);
|
||||
}
|
||||
|
||||
// Infallibly rekey one entry, if present.
|
||||
void rekey(const Lookup &old_key, const Key &new_key) {
|
||||
if (old_key != new_key) {
|
||||
if (Ptr p = lookup(old_key))
|
||||
impl.rekey(p, new_key, new_key);
|
||||
}
|
||||
void rekeyAs(const Lookup &old_lookup, const Lookup &new_lookup, const Key &new_key) {
|
||||
if (Ptr p = lookup(old_lookup))
|
||||
impl.rekeyAndMaybeRehash(p, new_lookup, new_key);
|
||||
}
|
||||
|
||||
// HashMap is movable
|
||||
HashMap(mozilla::MoveRef<HashMap> rhs) : impl(mozilla::Move(rhs->impl)) {}
|
||||
void operator=(mozilla::MoveRef<HashMap> rhs) { impl = mozilla::Move(rhs->impl); }
|
||||
HashMap(mozilla::MoveRef<HashMap> rhs) : impl(mozilla::OldMove(rhs->impl)) {}
|
||||
void operator=(mozilla::MoveRef<HashMap> rhs) { impl = mozilla::OldMove(rhs->impl); }
|
||||
|
||||
private:
|
||||
// HashMap is not copyable or assignable
|
||||
|
@ -295,7 +301,7 @@ class HashSet
|
|||
{
|
||||
typedef T KeyType;
|
||||
static const KeyType &getKey(const T &t) { return t; }
|
||||
static void setKey(T &t, KeyType &k) { t = k; }
|
||||
static void setKey(T &t, KeyType &k) { HashPolicy::rekey(t, k); }
|
||||
};
|
||||
|
||||
typedef detail::HashTable<const T, SetOps, AllocPolicy> Impl;
|
||||
|
@ -323,6 +329,10 @@ class HashSet
|
|||
typedef typename Impl::Ptr Ptr;
|
||||
Ptr lookup(const Lookup &l) const { return impl.lookup(l); }
|
||||
|
||||
// Like lookup, but does not assert if two threads call lookup at the same
|
||||
// time. Only use this method when none of the threads will modify the map.
|
||||
Ptr readonlyThreadsafeLookup(const Lookup &l) const { return impl.readonlyThreadsafeLookup(l); }
|
||||
|
||||
// Assuming |p.found()|, remove |*p|.
|
||||
void remove(Ptr p) { impl.remove(p); }
|
||||
|
||||
|
@ -425,7 +435,7 @@ class HashSet
|
|||
/************************************************** Shorthand operations */
|
||||
|
||||
bool has(const Lookup &l) const {
|
||||
return impl.lookup(l) != NULL;
|
||||
return impl.lookup(l) != nullptr;
|
||||
}
|
||||
|
||||
// Overwrite existing value with v. Return false on oom.
|
||||
|
@ -449,16 +459,21 @@ class HashSet
|
|||
}
|
||||
|
||||
// Infallibly rekey one entry, if present.
|
||||
void rekey(const Lookup &old_key, const T &new_key) {
|
||||
if (old_key != new_key) {
|
||||
if (Ptr p = lookup(old_key))
|
||||
impl.rekey(p, new_key, new_key);
|
||||
}
|
||||
// Requires template parameters T and HashPolicy::Lookup to be the same type.
|
||||
void rekeyIfMoved(const Lookup &old_value, const T &new_value) {
|
||||
if (old_value != new_value)
|
||||
rekeyAs(old_value, new_value, new_value);
|
||||
}
|
||||
|
||||
// Infallibly rekey one entry, if present.
|
||||
void rekeyAs(const Lookup &old_lookup, const Lookup &new_lookup, const T &new_value) {
|
||||
if (Ptr p = lookup(old_lookup))
|
||||
impl.rekeyAndMaybeRehash(p, new_lookup, new_value);
|
||||
}
|
||||
|
||||
// HashSet is movable
|
||||
HashSet(mozilla::MoveRef<HashSet> rhs) : impl(mozilla::Move(rhs->impl)) {}
|
||||
void operator=(mozilla::MoveRef<HashSet> rhs) { impl = mozilla::Move(rhs->impl); }
|
||||
HashSet(mozilla::MoveRef<HashSet> rhs) : impl(mozilla::OldMove(rhs->impl)) {}
|
||||
void operator=(mozilla::MoveRef<HashSet> rhs) { impl = mozilla::OldMove(rhs->impl); }
|
||||
|
||||
private:
|
||||
// HashSet is not copyable or assignable
|
||||
|
@ -505,7 +520,7 @@ struct PointerHasher
|
|||
JS_ASSERT(!JS::IsPoisonedPtr(l));
|
||||
size_t word = reinterpret_cast<size_t>(l) >> zeroBits;
|
||||
JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
|
||||
#if JS_BYTES_PER_WORD == 4
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
return HashNumber(word);
|
||||
#else
|
||||
JS_STATIC_ASSERT(sizeof word == 8);
|
||||
|
@ -517,6 +532,9 @@ struct PointerHasher
|
|||
JS_ASSERT(!JS::IsPoisonedPtr(l));
|
||||
return k == l;
|
||||
}
|
||||
static void rekey(Key &k, const Key& newKey) {
|
||||
k = newKey;
|
||||
}
|
||||
};
|
||||
|
||||
// Default hash policy: just use the 'lookup' value. This of course only
|
||||
|
@ -535,6 +553,9 @@ struct DefaultHasher
|
|||
// Use builtin or overloaded operator==.
|
||||
return k == l;
|
||||
}
|
||||
static void rekey(Key &k, const Key& newKey) {
|
||||
k = newKey;
|
||||
}
|
||||
};
|
||||
|
||||
// Specialize hashing policy for pointer types. It assumes that the type is
|
||||
|
@ -558,6 +579,19 @@ struct DefaultHasher<double>
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DefaultHasher<float>
|
||||
{
|
||||
typedef float Lookup;
|
||||
static HashNumber hash(float f) {
|
||||
JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
|
||||
return HashNumber(mozilla::BitwiseCast<uint32_t>(f));
|
||||
}
|
||||
static bool match(float lhs, float rhs) {
|
||||
return mozilla::BitwiseCast<uint32_t>(lhs) == mozilla::BitwiseCast<uint32_t>(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
// Both HashMap and HashSet are implemented by a single HashTable that is even
|
||||
|
@ -579,7 +613,7 @@ class HashMapEntry
|
|||
HashMapEntry(const KeyInput &k, const ValueInput &v) : key(k), value(v) {}
|
||||
|
||||
HashMapEntry(mozilla::MoveRef<HashMapEntry> rhs)
|
||||
: key(mozilla::Move(rhs->key)), value(mozilla::Move(rhs->value)) { }
|
||||
: key(mozilla::OldMove(rhs->key)), value(mozilla::OldMove(rhs->value)) { }
|
||||
|
||||
typedef Key KeyType;
|
||||
typedef Value ValueType;
|
||||
|
@ -750,7 +784,7 @@ class HashTable : private AllocPolicy
|
|||
mozilla::DebugOnly<bool> validEntry;
|
||||
|
||||
public:
|
||||
Range() : cur(NULL), end(NULL), validEntry(false) {}
|
||||
Range() : cur(nullptr), end(nullptr), validEntry(false) {}
|
||||
|
||||
bool empty() const {
|
||||
return cur == end;
|
||||
|
@ -808,7 +842,7 @@ class HashTable : private AllocPolicy
|
|||
// a new key at the new Lookup position. |front()| is invalid after
|
||||
// this operation until the next call to |popFront()|.
|
||||
void rekeyFront(const Lookup &l, const Key &k) {
|
||||
table.rekey(*this->cur, l, k);
|
||||
table.rekeyWithoutRehash(*this->cur, l, k);
|
||||
rekeyed = true;
|
||||
this->validEntry = false;
|
||||
}
|
||||
|
@ -834,13 +868,13 @@ class HashTable : private AllocPolicy
|
|||
: AllocPolicy(*rhs)
|
||||
{
|
||||
mozilla::PodAssign(this, &*rhs);
|
||||
rhs->table = NULL;
|
||||
rhs->table = nullptr;
|
||||
}
|
||||
void operator=(mozilla::MoveRef<HashTable> rhs) {
|
||||
if (table)
|
||||
destroyTable(*this, table, capacity());
|
||||
mozilla::PodAssign(this, &*rhs);
|
||||
rhs->table = NULL;
|
||||
rhs->table = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -941,7 +975,7 @@ class HashTable : private AllocPolicy
|
|||
entryCount(0),
|
||||
gen(0),
|
||||
removedCount(0),
|
||||
table(NULL),
|
||||
table(nullptr),
|
||||
entered(false),
|
||||
mutationCount(0)
|
||||
{}
|
||||
|
@ -1067,7 +1101,7 @@ class HashTable : private AllocPolicy
|
|||
DoubleHash dh = hash2(keyHash);
|
||||
|
||||
// Save the first removed entry pointer so we can recycle later.
|
||||
Entry *firstRemoved = NULL;
|
||||
Entry *firstRemoved = nullptr;
|
||||
|
||||
while(true) {
|
||||
if (JS_UNLIKELY(entry->isRemoved())) {
|
||||
|
@ -1163,7 +1197,7 @@ class HashTable : private AllocPolicy
|
|||
for (Entry *src = oldTable, *end = src + oldCap; src < end; ++src) {
|
||||
if (src->isLive()) {
|
||||
HashNumber hn = src->getKeyHash();
|
||||
findFreeEntry(hn).setLive(hn, mozilla::Move(src->get()));
|
||||
findFreeEntry(hn).setLive(hn, mozilla::OldMove(src->get()));
|
||||
src->destroy();
|
||||
}
|
||||
}
|
||||
|
@ -1307,7 +1341,7 @@ class HashTable : private AllocPolicy
|
|||
return;
|
||||
|
||||
destroyTable(*this, table, capacity());
|
||||
table = NULL;
|
||||
table = nullptr;
|
||||
gen++;
|
||||
entryCount = 0;
|
||||
removedCount = 0;
|
||||
|
@ -1456,15 +1490,21 @@ class HashTable : private AllocPolicy
|
|||
checkUnderloaded();
|
||||
}
|
||||
|
||||
void rekey(Ptr p, const Lookup &l, const Key &k)
|
||||
void rekeyWithoutRehash(Ptr p, const Lookup &l, const Key &k)
|
||||
{
|
||||
JS_ASSERT(table);
|
||||
mozilla::ReentrancyGuard g(*this);
|
||||
JS_ASSERT(p.found());
|
||||
typename HashTableEntry<T>::NonConstT t(mozilla::Move(*p));
|
||||
typename HashTableEntry<T>::NonConstT t(mozilla::OldMove(*p));
|
||||
HashPolicy::setKey(t, const_cast<Key &>(k));
|
||||
remove(*p.entry_);
|
||||
putNewInfallible(l, mozilla::Move(t));
|
||||
putNewInfallible(l, mozilla::OldMove(t));
|
||||
}
|
||||
|
||||
void rekeyAndMaybeRehash(Ptr p, const Lookup &l, const Key &k)
|
||||
{
|
||||
rekeyWithoutRehash(p, l, k);
|
||||
checkOverRemoved();
|
||||
}
|
||||
|
||||
#undef METER
|
||||
|
|
|
@ -7,12 +7,23 @@
|
|||
#ifndef js_HeapAPI_h
|
||||
#define js_HeapAPI_h
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "jspubtd.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);
|
||||
|
||||
namespace gc {
|
||||
|
||||
const size_t ArenaShift = 12;
|
||||
|
@ -57,9 +68,43 @@ struct ArenaHeader
|
|||
|
||||
struct Zone
|
||||
{
|
||||
protected:
|
||||
JSRuntime *const runtime_;
|
||||
JSTracer *const barrierTracer_; // A pointer to the JSRuntime's |gcMarker|.
|
||||
|
||||
public:
|
||||
bool needsBarrier_;
|
||||
|
||||
Zone() : needsBarrier_(false) {}
|
||||
Zone(JSRuntime *runtime, JSTracer *barrierTracerArg)
|
||||
: runtime_(runtime),
|
||||
barrierTracer_(barrierTracerArg),
|
||||
needsBarrier_(false)
|
||||
{}
|
||||
|
||||
bool needsBarrier() const {
|
||||
return needsBarrier_;
|
||||
}
|
||||
|
||||
JSTracer *barrierTracer() {
|
||||
JS_ASSERT(needsBarrier_);
|
||||
JS_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_));
|
||||
return barrierTracer_;
|
||||
}
|
||||
|
||||
JSRuntime *runtimeFromMainThread() const {
|
||||
JS_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_));
|
||||
return runtime_;
|
||||
}
|
||||
|
||||
// Note: Unrestricted access to the zone's runtime from an arbitrary
|
||||
// thread can easily lead to races. Use this method very carefully.
|
||||
JSRuntime *runtimeFromAnyThread() const {
|
||||
return runtime_;
|
||||
}
|
||||
|
||||
static JS::shadow::Zone *asShadowZone(JS::Zone *zone) {
|
||||
return reinterpret_cast<JS::shadow::Zone*>(zone);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace shadow */
|
||||
|
@ -94,8 +139,9 @@ GetGCThingMarkWordAndMask(const void *thing, uint32_t color,
|
|||
size_t bit = (addr & js::gc::ChunkMask) / js::gc::CellSize + color;
|
||||
JS_ASSERT(bit < js::gc::ChunkMarkBitmapBits);
|
||||
uintptr_t *bitmap = GetGCThingMarkBitmap(thing);
|
||||
*maskp = uintptr_t(1) << (bit % JS_BITS_PER_WORD);
|
||||
*wordp = &bitmap[bit / JS_BITS_PER_WORD];
|
||||
const uintptr_t nbits = sizeof(*bitmap) * CHAR_BIT;
|
||||
*maskp = uintptr_t(1) << (bit % nbits);
|
||||
*wordp = &bitmap[bit / nbits];
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JS::shadow::ArenaHeader *
|
||||
|
@ -106,6 +152,16 @@ GetGCThingArena(void *thing)
|
|||
return reinterpret_cast<JS::shadow::ArenaHeader *>(addr);
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE bool
|
||||
IsInsideNursery(const JS::shadow::Runtime *runtime, const void *p)
|
||||
{
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
return uintptr_t(p) >= runtime->gcNurseryStart_ && uintptr_t(p) < runtime->gcNurseryEnd_;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} /* namespace gc */
|
||||
|
||||
} /* namespace js */
|
||||
|
@ -128,6 +184,16 @@ GetObjectZone(JSObject *obj)
|
|||
static JS_ALWAYS_INLINE bool
|
||||
GCThingIsMarkedGray(void *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.
|
||||
*/
|
||||
JS::shadow::Runtime *rt = js::gc::GetGCThingRuntime(thing);
|
||||
if (js::gc::IsInsideNursery(rt, thing))
|
||||
return false;
|
||||
#endif
|
||||
uintptr_t *word, mask;
|
||||
js::gc::GetGCThingMarkWordAndMask(thing, js::gc::GRAY, &word, &mask);
|
||||
return *word & mask;
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
/* -*- 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_Id_h
|
||||
#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.
|
||||
//
|
||||
// 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
|
||||
// jsid is not a valid id and only arises as an exceptional API return value,
|
||||
// such as in JS_NextProperty. Embeddings must not pass JSID_VOID into JSAPI
|
||||
// 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
|
||||
// JS_IdToValue must be used instead.
|
||||
|
||||
#include "mozilla/NullPtr.h"
|
||||
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Utility.h"
|
||||
|
||||
#ifdef JS_USE_JSID_STRUCT_TYPES
|
||||
struct jsid
|
||||
{
|
||||
size_t asBits;
|
||||
bool operator==(jsid rhs) const { return asBits == rhs.asBits; }
|
||||
bool operator!=(jsid rhs) const { return asBits != rhs.asBits; }
|
||||
};
|
||||
# define JSID_BITS(id) (id.asBits)
|
||||
#else
|
||||
# define JSID_BITS(id) (id)
|
||||
#endif
|
||||
|
||||
#define JSID_TYPE_STRING 0x0
|
||||
#define JSID_TYPE_INT 0x1
|
||||
#define JSID_TYPE_VOID 0x2
|
||||
#define JSID_TYPE_OBJECT 0x4
|
||||
#define JSID_TYPE_MASK 0x7
|
||||
|
||||
// Avoid using canonical 'id' for jsid parameters since this is a magic word in
|
||||
// Objective-C++ which, apparently, wants to be able to #include jsapi.h.
|
||||
#define id iden
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
JSID_IS_STRING(jsid id)
|
||||
{
|
||||
return (JSID_BITS(id) & JSID_TYPE_MASK) == 0;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSString *
|
||||
JSID_TO_STRING(jsid id)
|
||||
{
|
||||
JS_ASSERT(JSID_IS_STRING(id));
|
||||
return (JSString *)JSID_BITS(id);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
JSID_IS_ZERO(jsid id)
|
||||
{
|
||||
return JSID_BITS(id) == 0;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
JSID_IS_INT(jsid id)
|
||||
{
|
||||
return !!(JSID_BITS(id) & JSID_TYPE_INT);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE int32_t
|
||||
JSID_TO_INT(jsid id)
|
||||
{
|
||||
JS_ASSERT(JSID_IS_INT(id));
|
||||
return ((uint32_t)JSID_BITS(id)) >> 1;
|
||||
}
|
||||
|
||||
#define JSID_INT_MIN 0
|
||||
#define JSID_INT_MAX INT32_MAX
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
INT_FITS_IN_JSID(int32_t i)
|
||||
{
|
||||
return i >= 0;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsid
|
||||
INT_TO_JSID(int32_t i)
|
||||
{
|
||||
jsid id;
|
||||
JS_ASSERT(INT_FITS_IN_JSID(i));
|
||||
JSID_BITS(id) = ((i << 1) | JSID_TYPE_INT);
|
||||
return id;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
JSID_IS_OBJECT(jsid id)
|
||||
{
|
||||
return (JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_OBJECT &&
|
||||
(size_t)JSID_BITS(id) != JSID_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSObject *
|
||||
JSID_TO_OBJECT(jsid id)
|
||||
{
|
||||
JS_ASSERT(JSID_IS_OBJECT(id));
|
||||
return (JSObject *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE jsid
|
||||
OBJECT_TO_JSID(JSObject *obj)
|
||||
{
|
||||
jsid id;
|
||||
JS_ASSERT(obj != nullptr);
|
||||
JS_ASSERT(((size_t)obj & JSID_TYPE_MASK) == 0);
|
||||
JSID_BITS(id) = ((size_t)obj | JSID_TYPE_OBJECT);
|
||||
return id;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
JSID_IS_GCTHING(jsid id)
|
||||
{
|
||||
return JSID_IS_STRING(id) || JSID_IS_OBJECT(id);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE void *
|
||||
JSID_TO_GCTHING(jsid id)
|
||||
{
|
||||
return (void *)(JSID_BITS(id) & ~(size_t)JSID_TYPE_MASK);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
JSID_IS_VOID(const jsid id)
|
||||
{
|
||||
JS_ASSERT_IF(((size_t)JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_VOID,
|
||||
JSID_BITS(id) == JSID_TYPE_VOID);
|
||||
return ((size_t)JSID_BITS(id) == JSID_TYPE_VOID);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
JSID_IS_EMPTY(const jsid id)
|
||||
{
|
||||
return ((size_t)JSID_BITS(id) == JSID_TYPE_OBJECT);
|
||||
}
|
||||
|
||||
#undef id
|
||||
|
||||
#ifdef JS_USE_JSID_STRUCT_TYPES
|
||||
extern JS_PUBLIC_DATA(const jsid) JSID_VOID;
|
||||
extern JS_PUBLIC_DATA(const jsid) JSID_EMPTY;
|
||||
#else
|
||||
# define JSID_VOID ((jsid)JSID_TYPE_VOID)
|
||||
# define JSID_EMPTY ((jsid)JSID_TYPE_OBJECT)
|
||||
#endif
|
||||
|
||||
extern JS_PUBLIC_DATA(const JS::Handle<jsid>) JSID_VOIDHANDLE;
|
||||
extern JS_PUBLIC_DATA(const JS::Handle<jsid>) JSID_EMPTYHANDLE;
|
||||
|
||||
namespace js {
|
||||
|
||||
inline bool
|
||||
IsPoisonedId(jsid iden)
|
||||
{
|
||||
if (JSID_IS_STRING(iden))
|
||||
return JS::IsPoisonedPtr(JSID_TO_STRING(iden));
|
||||
if (JSID_IS_OBJECT(iden))
|
||||
return JS::IsPoisonedPtr(JSID_TO_OBJECT(iden));
|
||||
return false;
|
||||
}
|
||||
|
||||
template <> struct GCMethods<jsid>
|
||||
{
|
||||
static jsid initial() { return JSID_VOID; }
|
||||
static ThingRootKind kind() { return THING_ROOT_ID; }
|
||||
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
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* js_Id_h */
|
|
@ -7,20 +7,54 @@
|
|||
#ifndef js_MemoryMetrics_h
|
||||
#define js_MemoryMetrics_h
|
||||
|
||||
// These declarations are not within jsapi.h because they are highly likely to
|
||||
// change in the future. Depend on them at your own risk.
|
||||
// These declarations are highly likely to change in the future. Depend on them
|
||||
// at your own risk.
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "jsalloc.h"
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "js/HashTable.h"
|
||||
#include "js/Utility.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
class nsISupports; // This is needed for ObjectPrivateVisitor.
|
||||
class nsISupports; // Needed for ObjectPrivateVisitor.
|
||||
|
||||
namespace JS {
|
||||
|
||||
struct TabSizes
|
||||
{
|
||||
enum Kind {
|
||||
Objects,
|
||||
Strings,
|
||||
Private,
|
||||
Other
|
||||
};
|
||||
|
||||
TabSizes() { mozilla::PodZero(this); }
|
||||
|
||||
void add(Kind kind, size_t n) {
|
||||
switch (kind) {
|
||||
case Objects: objects += n; break;
|
||||
case Strings: strings += n; break;
|
||||
case Private: private_ += n; break;
|
||||
case Other: other += n; break;
|
||||
default: MOZ_CRASH("bad TabSizes kind");
|
||||
}
|
||||
}
|
||||
|
||||
size_t objects;
|
||||
size_t strings;
|
||||
size_t private_;
|
||||
size_t other;
|
||||
};
|
||||
|
||||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
|
||||
|
@ -30,9 +64,86 @@ namespace js {
|
|||
// MemoryReportingSundriesThreshold() bytes.
|
||||
//
|
||||
// We need to define this value here, rather than in the code which actually
|
||||
// generates the memory reports, because HugeStringInfo uses this value.
|
||||
// generates the memory reports, because NotableStringInfo uses this value.
|
||||
JS_FRIEND_API(size_t) MemoryReportingSundriesThreshold();
|
||||
|
||||
// This hash policy avoids flattening ropes (which perturbs the site being
|
||||
// measured and requires a JSContext) at the expense of doing a FULL ROPE COPY
|
||||
// on every hash and match! Beware.
|
||||
struct InefficientNonFlatteningStringHashPolicy
|
||||
{
|
||||
typedef JSString *Lookup;
|
||||
static HashNumber hash(const Lookup &l);
|
||||
static bool match(const JSString *const &k, const Lookup &l);
|
||||
};
|
||||
|
||||
// This file features many classes with numerous size_t fields, and each such
|
||||
// class has one or more methods that need to operate on all of these fields.
|
||||
// Writing these individually is error-prone -- it's easy to add a new field
|
||||
// without updating all the required methods. So we define a single macro list
|
||||
// in each class to name the fields (and notable characteristics of them), and
|
||||
// then use the following macros to transform those lists into the required
|
||||
// methods.
|
||||
//
|
||||
// In some classes, one or more of the macro arguments aren't used. We use '_'
|
||||
// for those.
|
||||
//
|
||||
#define DECL_SIZE(kind, gc, mSize) size_t mSize;
|
||||
#define ZERO_SIZE(kind, gc, mSize) mSize(0),
|
||||
#define COPY_OTHER_SIZE(kind, gc, mSize) mSize(other.mSize),
|
||||
#define ADD_OTHER_SIZE(kind, gc, mSize) mSize += other.mSize;
|
||||
#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(kind, gc, mSize) n += (js::gc == js::IsLiveGCThing) ? mSize : 0;
|
||||
#define ADD_TO_TAB_SIZES(kind, gc, mSize) sizes->add(JS::TabSizes::kind, mSize);
|
||||
|
||||
// Used to annotate which size_t fields measure live GC things and which don't.
|
||||
enum {
|
||||
NotLiveGCThing = false,
|
||||
IsLiveGCThing = true
|
||||
};
|
||||
|
||||
struct ZoneStatsPod
|
||||
{
|
||||
#define FOR_EACH_SIZE(macro) \
|
||||
macro(Other, NotLiveGCThing, gcHeapArenaAdmin) \
|
||||
macro(Other, NotLiveGCThing, unusedGCThings) \
|
||||
macro(Other, IsLiveGCThing, lazyScriptsGCHeap) \
|
||||
macro(Other, NotLiveGCThing, lazyScriptsMallocHeap) \
|
||||
macro(Other, IsLiveGCThing, ionCodesGCHeap) \
|
||||
macro(Other, IsLiveGCThing, typeObjectsGCHeap) \
|
||||
macro(Other, NotLiveGCThing, typeObjectsMallocHeap) \
|
||||
macro(Other, NotLiveGCThing, typePool) \
|
||||
macro(Strings, IsLiveGCThing, stringsShortGCHeap) \
|
||||
macro(Strings, IsLiveGCThing, stringsNormalGCHeap) \
|
||||
macro(Strings, NotLiveGCThing, stringsNormalMallocHeap)
|
||||
|
||||
ZoneStatsPod()
|
||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||
extra()
|
||||
{}
|
||||
|
||||
void add(const ZoneStatsPod &other) {
|
||||
FOR_EACH_SIZE(ADD_OTHER_SIZE)
|
||||
// Do nothing with |extra|.
|
||||
}
|
||||
|
||||
size_t sizeOfLiveGCThings() const {
|
||||
size_t n = 0;
|
||||
FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
|
||||
// Do nothing with |extra|.
|
||||
return n;
|
||||
}
|
||||
|
||||
void addToTabSizes(JS::TabSizes *sizes) const {
|
||||
FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
|
||||
// Do nothing with |extra|.
|
||||
}
|
||||
|
||||
FOR_EACH_SIZE(DECL_SIZE)
|
||||
void *extra; // This field can be used by embedders.
|
||||
|
||||
#undef FOR_EACH_SIZE
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
@ -40,352 +151,320 @@ namespace JS {
|
|||
// Data for tracking memory usage of things hanging off objects.
|
||||
struct ObjectsExtraSizes
|
||||
{
|
||||
size_t slots;
|
||||
size_t elementsNonAsmJS;
|
||||
size_t elementsAsmJSHeap;
|
||||
size_t elementsAsmJSNonHeap;
|
||||
size_t argumentsData;
|
||||
size_t regExpStatics;
|
||||
size_t propertyIteratorData;
|
||||
size_t ctypesData;
|
||||
size_t private_; // The '_' suffix is required because |private| is a keyword.
|
||||
// Note that this field is measured separately from the others.
|
||||
#define FOR_EACH_SIZE(macro) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapSlots) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapElementsNonAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapElementsAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, nonHeapElementsAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, nonHeapCodeAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapAsmJSModuleData) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapArgumentsData) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapRegExpStatics) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapPropertyIteratorData) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapCtypesData)
|
||||
|
||||
ObjectsExtraSizes() { memset(this, 0, sizeof(ObjectsExtraSizes)); }
|
||||
ObjectsExtraSizes()
|
||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||
dummy()
|
||||
{}
|
||||
|
||||
void add(ObjectsExtraSizes &sizes) {
|
||||
this->slots += sizes.slots;
|
||||
this->elementsNonAsmJS += sizes.elementsNonAsmJS;
|
||||
this->elementsAsmJSHeap += sizes.elementsAsmJSHeap;
|
||||
this->elementsAsmJSNonHeap += sizes.elementsAsmJSNonHeap;
|
||||
this->argumentsData += sizes.argumentsData;
|
||||
this->regExpStatics += sizes.regExpStatics;
|
||||
this->propertyIteratorData += sizes.propertyIteratorData;
|
||||
this->ctypesData += sizes.ctypesData;
|
||||
this->private_ += sizes.private_;
|
||||
void add(const ObjectsExtraSizes &other) {
|
||||
FOR_EACH_SIZE(ADD_OTHER_SIZE)
|
||||
}
|
||||
};
|
||||
|
||||
// Data for tracking analysis/inference memory usage.
|
||||
struct TypeInferenceSizes
|
||||
{
|
||||
size_t typeScripts;
|
||||
size_t typeResults;
|
||||
size_t analysisPool;
|
||||
size_t pendingArrays;
|
||||
size_t allocationSiteTables;
|
||||
size_t arrayTypeTables;
|
||||
size_t objectTypeTables;
|
||||
|
||||
TypeInferenceSizes() { memset(this, 0, sizeof(TypeInferenceSizes)); }
|
||||
|
||||
void add(TypeInferenceSizes &sizes) {
|
||||
this->typeScripts += sizes.typeScripts;
|
||||
this->typeResults += sizes.typeResults;
|
||||
this->analysisPool += sizes.analysisPool;
|
||||
this->pendingArrays += sizes.pendingArrays;
|
||||
this->allocationSiteTables += sizes.allocationSiteTables;
|
||||
this->arrayTypeTables += sizes.arrayTypeTables;
|
||||
this->objectTypeTables += sizes.objectTypeTables;
|
||||
size_t sizeOfLiveGCThings() const {
|
||||
size_t n = 0;
|
||||
FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
|
||||
return n;
|
||||
}
|
||||
|
||||
void addToTabSizes(TabSizes *sizes) const {
|
||||
FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
|
||||
}
|
||||
|
||||
FOR_EACH_SIZE(DECL_SIZE)
|
||||
int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
|
||||
|
||||
#undef FOR_EACH_SIZE
|
||||
};
|
||||
|
||||
// Data for tracking JIT-code memory usage.
|
||||
struct CodeSizes
|
||||
{
|
||||
size_t ion;
|
||||
size_t asmJS;
|
||||
size_t baseline;
|
||||
size_t regexp;
|
||||
size_t other;
|
||||
size_t unused;
|
||||
#define FOR_EACH_SIZE(macro) \
|
||||
macro(_, _, ion) \
|
||||
macro(_, _, baseline) \
|
||||
macro(_, _, regexp) \
|
||||
macro(_, _, other) \
|
||||
macro(_, _, unused)
|
||||
|
||||
CodeSizes() { memset(this, 0, sizeof(CodeSizes)); }
|
||||
CodeSizes()
|
||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||
dummy()
|
||||
{}
|
||||
|
||||
FOR_EACH_SIZE(DECL_SIZE)
|
||||
int dummy; // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
|
||||
|
||||
#undef FOR_EACH_SIZE
|
||||
};
|
||||
|
||||
// Holds data about a huge string (one which uses more HugeStringInfo::MinSize
|
||||
// bytes of memory), so we can report it individually.
|
||||
struct HugeStringInfo
|
||||
// This class holds information about the memory taken up by identical copies of
|
||||
// a particular string. Multiple JSStrings may have their sizes aggregated
|
||||
// together into one StringInfo object.
|
||||
struct StringInfo
|
||||
{
|
||||
HugeStringInfo() : length(0), size(0) { memset(&buffer, 0, sizeof(buffer)); }
|
||||
StringInfo()
|
||||
: length(0), numCopies(0), shortGCHeap(0), normalGCHeap(0), normalMallocHeap(0)
|
||||
{}
|
||||
|
||||
StringInfo(size_t len, size_t shorts, size_t normals, size_t chars)
|
||||
: length(len),
|
||||
numCopies(1),
|
||||
shortGCHeap(shorts),
|
||||
normalGCHeap(normals),
|
||||
normalMallocHeap(chars)
|
||||
{}
|
||||
|
||||
void add(size_t shorts, size_t normals, size_t chars) {
|
||||
shortGCHeap += shorts;
|
||||
normalGCHeap += normals;
|
||||
normalMallocHeap += chars;
|
||||
numCopies++;
|
||||
}
|
||||
|
||||
void add(const StringInfo& info) {
|
||||
MOZ_ASSERT(length == info.length);
|
||||
|
||||
shortGCHeap += info.shortGCHeap;
|
||||
normalGCHeap += info.normalGCHeap;
|
||||
normalMallocHeap += info.normalMallocHeap;
|
||||
numCopies += info.numCopies;
|
||||
}
|
||||
|
||||
size_t totalSizeOf() const {
|
||||
return shortGCHeap + normalGCHeap + normalMallocHeap;
|
||||
}
|
||||
|
||||
size_t totalGCHeapSizeOf() const {
|
||||
return shortGCHeap + normalGCHeap;
|
||||
}
|
||||
|
||||
// The string's length, excluding the null-terminator.
|
||||
size_t length;
|
||||
|
||||
// How many copies of the string have we seen?
|
||||
size_t numCopies;
|
||||
|
||||
// These are all totals across all copies of the string we've seen.
|
||||
size_t shortGCHeap;
|
||||
size_t normalGCHeap;
|
||||
size_t normalMallocHeap;
|
||||
};
|
||||
|
||||
// Holds data about a notable string (one which uses more than
|
||||
// NotableStringInfo::notableSize() bytes of memory), so we can report it
|
||||
// individually.
|
||||
//
|
||||
// Essentially the only difference between this class and StringInfo is that
|
||||
// NotableStringInfo holds a copy of the string's chars.
|
||||
struct NotableStringInfo : public StringInfo
|
||||
{
|
||||
NotableStringInfo();
|
||||
NotableStringInfo(JSString *str, const StringInfo &info);
|
||||
NotableStringInfo(mozilla::MoveRef<NotableStringInfo> info);
|
||||
NotableStringInfo &operator=(mozilla::MoveRef<NotableStringInfo> info);
|
||||
|
||||
~NotableStringInfo() {
|
||||
js_free(buffer);
|
||||
}
|
||||
|
||||
// A string needs to take up this many bytes of storage before we consider
|
||||
// it to be "huge".
|
||||
static size_t MinSize() {
|
||||
// it to be "notable".
|
||||
static size_t notableSize() {
|
||||
return js::MemoryReportingSundriesThreshold();
|
||||
}
|
||||
|
||||
// A string's size in memory is not necessarily equal to twice its length
|
||||
// because the allocator and the JS engine both may round up.
|
||||
size_t length;
|
||||
size_t size;
|
||||
char *buffer;
|
||||
|
||||
// We record the first 32 chars of the escaped string here. (We escape the
|
||||
// string so we can use a char[] instead of a jschar[] here.
|
||||
char buffer[32];
|
||||
private:
|
||||
NotableStringInfo(const NotableStringInfo& info) MOZ_DELETE;
|
||||
};
|
||||
|
||||
// These measurements relate directly to the JSRuntime, and not to
|
||||
// These measurements relate directly to the JSRuntime, and not to zones and
|
||||
// compartments within it.
|
||||
struct RuntimeSizes
|
||||
{
|
||||
RuntimeSizes() { memset(this, 0, sizeof(RuntimeSizes)); }
|
||||
#define FOR_EACH_SIZE(macro) \
|
||||
macro(_, _, object) \
|
||||
macro(_, _, atomsTable) \
|
||||
macro(_, _, contexts) \
|
||||
macro(_, _, dtoa) \
|
||||
macro(_, _, temporary) \
|
||||
macro(_, _, regexpData) \
|
||||
macro(_, _, interpreterStack) \
|
||||
macro(_, _, gcMarker) \
|
||||
macro(_, _, mathCache) \
|
||||
macro(_, _, scriptData) \
|
||||
macro(_, _, scriptSources)
|
||||
|
||||
size_t object;
|
||||
size_t atomsTable;
|
||||
size_t contexts;
|
||||
size_t dtoa;
|
||||
size_t temporary;
|
||||
size_t regexpData;
|
||||
size_t interpreterStack;
|
||||
size_t gcMarker;
|
||||
size_t mathCache;
|
||||
size_t scriptData;
|
||||
size_t scriptSources;
|
||||
|
||||
CodeSizes code;
|
||||
};
|
||||
|
||||
struct ZoneStats
|
||||
{
|
||||
ZoneStats()
|
||||
: extra(NULL),
|
||||
gcHeapArenaAdmin(0),
|
||||
gcHeapUnusedGcThings(0),
|
||||
gcHeapStringsNormal(0),
|
||||
gcHeapStringsShort(0),
|
||||
gcHeapLazyScripts(0),
|
||||
gcHeapTypeObjects(0),
|
||||
gcHeapIonCodes(0),
|
||||
stringCharsNonHuge(0),
|
||||
lazyScripts(0),
|
||||
typeObjects(0),
|
||||
typePool(0),
|
||||
hugeStrings()
|
||||
RuntimeSizes()
|
||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||
code()
|
||||
{}
|
||||
|
||||
ZoneStats(const ZoneStats &other)
|
||||
: extra(other.extra),
|
||||
gcHeapArenaAdmin(other.gcHeapArenaAdmin),
|
||||
gcHeapUnusedGcThings(other.gcHeapUnusedGcThings),
|
||||
gcHeapStringsNormal(other.gcHeapStringsNormal),
|
||||
gcHeapStringsShort(other.gcHeapStringsShort),
|
||||
gcHeapLazyScripts(other.gcHeapLazyScripts),
|
||||
gcHeapTypeObjects(other.gcHeapTypeObjects),
|
||||
gcHeapIonCodes(other.gcHeapIonCodes),
|
||||
stringCharsNonHuge(other.stringCharsNonHuge),
|
||||
lazyScripts(other.lazyScripts),
|
||||
typeObjects(other.typeObjects),
|
||||
typePool(other.typePool),
|
||||
hugeStrings()
|
||||
{
|
||||
hugeStrings.appendAll(other.hugeStrings);
|
||||
FOR_EACH_SIZE(DECL_SIZE)
|
||||
CodeSizes code;
|
||||
|
||||
#undef FOR_EACH_SIZE
|
||||
};
|
||||
|
||||
struct ZoneStats : js::ZoneStatsPod
|
||||
{
|
||||
ZoneStats() {
|
||||
strings.init();
|
||||
}
|
||||
|
||||
// Add other's numbers to this object's numbers.
|
||||
void add(ZoneStats &other) {
|
||||
#define ADD(x) this->x += other.x
|
||||
ZoneStats(mozilla::MoveRef<ZoneStats> other)
|
||||
: ZoneStatsPod(other),
|
||||
strings(mozilla::OldMove(other->strings)),
|
||||
notableStrings(mozilla::OldMove(other->notableStrings))
|
||||
{}
|
||||
|
||||
ADD(gcHeapArenaAdmin);
|
||||
ADD(gcHeapUnusedGcThings);
|
||||
// Add other's numbers to this object's numbers. Both objects'
|
||||
// notableStrings vectors must be empty at this point, because we can't
|
||||
// merge them. (A NotableStringInfo contains only a prefix of the string,
|
||||
// so we can't tell whether two NotableStringInfo objects correspond to the
|
||||
// same string.)
|
||||
void add(const ZoneStats &other) {
|
||||
ZoneStatsPod::add(other);
|
||||
|
||||
ADD(gcHeapStringsNormal);
|
||||
ADD(gcHeapStringsShort);
|
||||
ADD(gcHeapLazyScripts);
|
||||
ADD(gcHeapTypeObjects);
|
||||
ADD(gcHeapIonCodes);
|
||||
MOZ_ASSERT(notableStrings.empty());
|
||||
MOZ_ASSERT(other.notableStrings.empty());
|
||||
|
||||
ADD(stringCharsNonHuge);
|
||||
ADD(lazyScripts);
|
||||
ADD(typeObjects);
|
||||
ADD(typePool);
|
||||
|
||||
#undef ADD
|
||||
|
||||
hugeStrings.appendAll(other.hugeStrings);
|
||||
for (StringsHashMap::Range r = other.strings.all(); !r.empty(); r.popFront()) {
|
||||
StringsHashMap::AddPtr p = strings.lookupForAdd(r.front().key);
|
||||
if (p) {
|
||||
// We've seen this string before; add its size to our tally.
|
||||
p->value.add(r.front().value);
|
||||
} else {
|
||||
// We haven't seen this string before; add it to the hashtable.
|
||||
strings.add(p, r.front().key, r.front().value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This field can be used by embedders.
|
||||
void *extra;
|
||||
size_t sizeOfLiveGCThings() const {
|
||||
size_t n = ZoneStatsPod::sizeOfLiveGCThings();
|
||||
for (size_t i = 0; i < notableStrings.length(); i++) {
|
||||
const JS::NotableStringInfo& info = notableStrings[i];
|
||||
n += info.totalGCHeapSizeOf();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t gcHeapArenaAdmin;
|
||||
size_t gcHeapUnusedGcThings;
|
||||
typedef js::HashMap<JSString*,
|
||||
StringInfo,
|
||||
js::InefficientNonFlatteningStringHashPolicy,
|
||||
js::SystemAllocPolicy> StringsHashMap;
|
||||
|
||||
size_t gcHeapStringsNormal;
|
||||
size_t gcHeapStringsShort;
|
||||
|
||||
size_t gcHeapLazyScripts;
|
||||
size_t gcHeapTypeObjects;
|
||||
size_t gcHeapIonCodes;
|
||||
|
||||
size_t stringCharsNonHuge;
|
||||
size_t lazyScripts;
|
||||
size_t typeObjects;
|
||||
size_t typePool;
|
||||
|
||||
js::Vector<HugeStringInfo, 0, js::SystemAllocPolicy> hugeStrings;
|
||||
|
||||
// The size of all the live things in the GC heap that don't belong to any
|
||||
// compartment.
|
||||
size_t GCHeapThingsSize();
|
||||
StringsHashMap strings;
|
||||
js::Vector<NotableStringInfo, 0, js::SystemAllocPolicy> notableStrings;
|
||||
};
|
||||
|
||||
struct CompartmentStats
|
||||
{
|
||||
#define FOR_EACH_SIZE(macro) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeapOrdinary) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeapFunction) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeapDenseArray) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeapSlowArray) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeapCrossCompartmentWrapper) \
|
||||
macro(Private, NotLiveGCThing, objectsPrivate) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapTreeGlobalParented) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapTreeNonGlobalParented) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapDict) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapBase) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapTreeTables) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapDictTables) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapTreeShapeKids) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapCompartmentTables) \
|
||||
macro(Other, IsLiveGCThing, scriptsGCHeap) \
|
||||
macro(Other, NotLiveGCThing, scriptsMallocHeapData) \
|
||||
macro(Other, NotLiveGCThing, baselineData) \
|
||||
macro(Other, NotLiveGCThing, baselineStubsFallback) \
|
||||
macro(Other, NotLiveGCThing, baselineStubsOptimized) \
|
||||
macro(Other, NotLiveGCThing, ionData) \
|
||||
macro(Other, NotLiveGCThing, typeInferenceTypeScripts) \
|
||||
macro(Other, NotLiveGCThing, typeInferencePendingArrays) \
|
||||
macro(Other, NotLiveGCThing, typeInferenceAllocationSiteTables) \
|
||||
macro(Other, NotLiveGCThing, typeInferenceArrayTypeTables) \
|
||||
macro(Other, NotLiveGCThing, typeInferenceObjectTypeTables) \
|
||||
macro(Other, NotLiveGCThing, compartmentObject) \
|
||||
macro(Other, NotLiveGCThing, crossCompartmentWrappersTable) \
|
||||
macro(Other, NotLiveGCThing, regexpCompartment) \
|
||||
macro(Other, NotLiveGCThing, debuggeesSet)
|
||||
|
||||
CompartmentStats()
|
||||
: extra(NULL),
|
||||
gcHeapObjectsOrdinary(0),
|
||||
gcHeapObjectsFunction(0),
|
||||
gcHeapObjectsDenseArray(0),
|
||||
gcHeapObjectsSlowArray(0),
|
||||
gcHeapObjectsCrossCompartmentWrapper(0),
|
||||
gcHeapShapesTreeGlobalParented(0),
|
||||
gcHeapShapesTreeNonGlobalParented(0),
|
||||
gcHeapShapesDict(0),
|
||||
gcHeapShapesBase(0),
|
||||
gcHeapScripts(0),
|
||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||
objectsExtra(),
|
||||
shapesExtraTreeTables(0),
|
||||
shapesExtraDictTables(0),
|
||||
shapesExtraTreeShapeKids(0),
|
||||
shapesCompartmentTables(0),
|
||||
scriptData(0),
|
||||
baselineData(0),
|
||||
baselineStubsFallback(0),
|
||||
baselineStubsOptimized(0),
|
||||
ionData(0),
|
||||
compartmentObject(0),
|
||||
crossCompartmentWrappersTable(0),
|
||||
regexpCompartment(0),
|
||||
debuggeesSet(0),
|
||||
typeInference()
|
||||
extra()
|
||||
{}
|
||||
|
||||
CompartmentStats(const CompartmentStats &other)
|
||||
: extra(other.extra),
|
||||
gcHeapObjectsOrdinary(other.gcHeapObjectsOrdinary),
|
||||
gcHeapObjectsFunction(other.gcHeapObjectsFunction),
|
||||
gcHeapObjectsDenseArray(other.gcHeapObjectsDenseArray),
|
||||
gcHeapObjectsSlowArray(other.gcHeapObjectsSlowArray),
|
||||
gcHeapObjectsCrossCompartmentWrapper(other.gcHeapObjectsCrossCompartmentWrapper),
|
||||
gcHeapShapesTreeGlobalParented(other.gcHeapShapesTreeGlobalParented),
|
||||
gcHeapShapesTreeNonGlobalParented(other.gcHeapShapesTreeNonGlobalParented),
|
||||
gcHeapShapesDict(other.gcHeapShapesDict),
|
||||
gcHeapShapesBase(other.gcHeapShapesBase),
|
||||
gcHeapScripts(other.gcHeapScripts),
|
||||
: FOR_EACH_SIZE(COPY_OTHER_SIZE)
|
||||
objectsExtra(other.objectsExtra),
|
||||
shapesExtraTreeTables(other.shapesExtraTreeTables),
|
||||
shapesExtraDictTables(other.shapesExtraDictTables),
|
||||
shapesExtraTreeShapeKids(other.shapesExtraTreeShapeKids),
|
||||
shapesCompartmentTables(other.shapesCompartmentTables),
|
||||
scriptData(other.scriptData),
|
||||
baselineData(other.baselineData),
|
||||
baselineStubsFallback(other.baselineStubsFallback),
|
||||
baselineStubsOptimized(other.baselineStubsOptimized),
|
||||
ionData(other.ionData),
|
||||
compartmentObject(other.compartmentObject),
|
||||
crossCompartmentWrappersTable(other.crossCompartmentWrappersTable),
|
||||
regexpCompartment(other.regexpCompartment),
|
||||
debuggeesSet(other.debuggeesSet),
|
||||
typeInference(other.typeInference)
|
||||
{
|
||||
extra(other.extra)
|
||||
{}
|
||||
|
||||
void add(const CompartmentStats &other) {
|
||||
FOR_EACH_SIZE(ADD_OTHER_SIZE)
|
||||
objectsExtra.add(other.objectsExtra);
|
||||
// Do nothing with |extra|.
|
||||
}
|
||||
|
||||
// This field can be used by embedders.
|
||||
void *extra;
|
||||
|
||||
// If you add a new number, remember to update the constructors, add(), and
|
||||
// maybe gcHeapThingsSize()!
|
||||
size_t gcHeapObjectsOrdinary;
|
||||
size_t gcHeapObjectsFunction;
|
||||
size_t gcHeapObjectsDenseArray;
|
||||
size_t gcHeapObjectsSlowArray;
|
||||
size_t gcHeapObjectsCrossCompartmentWrapper;
|
||||
size_t gcHeapShapesTreeGlobalParented;
|
||||
size_t gcHeapShapesTreeNonGlobalParented;
|
||||
size_t gcHeapShapesDict;
|
||||
size_t gcHeapShapesBase;
|
||||
size_t gcHeapScripts;
|
||||
ObjectsExtraSizes objectsExtra;
|
||||
|
||||
size_t shapesExtraTreeTables;
|
||||
size_t shapesExtraDictTables;
|
||||
size_t shapesExtraTreeShapeKids;
|
||||
size_t shapesCompartmentTables;
|
||||
size_t scriptData;
|
||||
size_t baselineData;
|
||||
size_t baselineStubsFallback;
|
||||
size_t baselineStubsOptimized;
|
||||
size_t ionData;
|
||||
size_t compartmentObject;
|
||||
size_t crossCompartmentWrappersTable;
|
||||
size_t regexpCompartment;
|
||||
size_t debuggeesSet;
|
||||
|
||||
TypeInferenceSizes typeInference;
|
||||
|
||||
// Add cStats's numbers to this object's numbers.
|
||||
void add(CompartmentStats &cStats) {
|
||||
#define ADD(x) this->x += cStats.x
|
||||
|
||||
ADD(gcHeapObjectsOrdinary);
|
||||
ADD(gcHeapObjectsFunction);
|
||||
ADD(gcHeapObjectsDenseArray);
|
||||
ADD(gcHeapObjectsSlowArray);
|
||||
ADD(gcHeapObjectsCrossCompartmentWrapper);
|
||||
ADD(gcHeapShapesTreeGlobalParented);
|
||||
ADD(gcHeapShapesTreeNonGlobalParented);
|
||||
ADD(gcHeapShapesDict);
|
||||
ADD(gcHeapShapesBase);
|
||||
ADD(gcHeapScripts);
|
||||
objectsExtra.add(cStats.objectsExtra);
|
||||
|
||||
ADD(shapesExtraTreeTables);
|
||||
ADD(shapesExtraDictTables);
|
||||
ADD(shapesExtraTreeShapeKids);
|
||||
ADD(shapesCompartmentTables);
|
||||
ADD(scriptData);
|
||||
ADD(baselineData);
|
||||
ADD(baselineStubsFallback);
|
||||
ADD(baselineStubsOptimized);
|
||||
ADD(ionData);
|
||||
ADD(compartmentObject);
|
||||
ADD(crossCompartmentWrappersTable);
|
||||
ADD(regexpCompartment);
|
||||
ADD(debuggeesSet);
|
||||
|
||||
#undef ADD
|
||||
|
||||
typeInference.add(cStats.typeInference);
|
||||
size_t sizeOfLiveGCThings() const {
|
||||
size_t n = 0;
|
||||
FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
|
||||
n += objectsExtra.sizeOfLiveGCThings();
|
||||
// Do nothing with |extra|.
|
||||
return n;
|
||||
}
|
||||
|
||||
// The size of all the live things in the GC heap.
|
||||
size_t GCHeapThingsSize();
|
||||
void addToTabSizes(TabSizes *sizes) const {
|
||||
FOR_EACH_SIZE(ADD_TO_TAB_SIZES);
|
||||
objectsExtra.addToTabSizes(sizes);
|
||||
// Do nothing with |extra|.
|
||||
}
|
||||
|
||||
FOR_EACH_SIZE(DECL_SIZE)
|
||||
ObjectsExtraSizes objectsExtra;
|
||||
void *extra; // This field can be used by embedders.
|
||||
|
||||
#undef FOR_EACH_SIZE
|
||||
};
|
||||
|
||||
struct RuntimeStats
|
||||
{
|
||||
#define FOR_EACH_SIZE(macro) \
|
||||
macro(_, _, gcHeapChunkTotal) \
|
||||
macro(_, _, gcHeapDecommittedArenas) \
|
||||
macro(_, _, gcHeapUnusedChunks) \
|
||||
macro(_, _, gcHeapUnusedArenas) \
|
||||
macro(_, _, gcHeapChunkAdmin) \
|
||||
macro(_, _, gcHeapGCThings) \
|
||||
|
||||
RuntimeStats(mozilla::MallocSizeOf mallocSizeOf)
|
||||
: runtime(),
|
||||
gcHeapChunkTotal(0),
|
||||
gcHeapDecommittedArenas(0),
|
||||
gcHeapUnusedChunks(0),
|
||||
gcHeapUnusedArenas(0),
|
||||
gcHeapUnusedGcThings(0),
|
||||
gcHeapChunkAdmin(0),
|
||||
gcHeapGcThings(0),
|
||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||
runtime(),
|
||||
cTotals(),
|
||||
zTotals(),
|
||||
compartmentStatsVector(),
|
||||
zoneStatsVector(),
|
||||
currZoneStats(NULL),
|
||||
currZoneStats(nullptr),
|
||||
mallocSizeOf_(mallocSizeOf)
|
||||
{}
|
||||
|
||||
RuntimeSizes runtime;
|
||||
|
||||
// If you add a new number, remember to update the constructor!
|
||||
|
||||
// Here's a useful breakdown of the GC heap.
|
||||
//
|
||||
// - rtStats.gcHeapChunkTotal
|
||||
|
@ -394,28 +473,24 @@ struct RuntimeStats
|
|||
// - unused bytes
|
||||
// - rtStats.gcHeapUnusedChunks (empty chunks)
|
||||
// - rtStats.gcHeapUnusedArenas (empty arenas within non-empty chunks)
|
||||
// - rtStats.total.gcHeapUnusedGcThings (empty GC thing slots within non-empty arenas)
|
||||
// - rtStats.zTotals.unusedGCThings (empty GC thing slots within non-empty arenas)
|
||||
// - used bytes
|
||||
// - rtStats.gcHeapChunkAdmin
|
||||
// - rtStats.total.gcHeapArenaAdmin
|
||||
// - rtStats.gcHeapGcThings (in-use GC things)
|
||||
// - rtStats.zTotals.gcHeapArenaAdmin
|
||||
// - rtStats.gcHeapGCThings (in-use GC things)
|
||||
// == rtStats.zTotals.sizeOfLiveGCThings() + rtStats.cTotals.sizeOfLiveGCThings()
|
||||
//
|
||||
// It's possible that some arenas in empty chunks may be decommitted, but
|
||||
// we don't count those under rtStats.gcHeapDecommittedArenas because (a)
|
||||
// it's rare, and (b) this means that rtStats.gcHeapUnusedChunks is a
|
||||
// multiple of the chunk size, which is good.
|
||||
|
||||
size_t gcHeapChunkTotal;
|
||||
size_t gcHeapDecommittedArenas;
|
||||
size_t gcHeapUnusedChunks;
|
||||
size_t gcHeapUnusedArenas;
|
||||
size_t gcHeapUnusedGcThings;
|
||||
size_t gcHeapChunkAdmin;
|
||||
size_t gcHeapGcThings;
|
||||
FOR_EACH_SIZE(DECL_SIZE)
|
||||
|
||||
// The sum of all compartment's measurements.
|
||||
CompartmentStats cTotals;
|
||||
ZoneStats zTotals;
|
||||
RuntimeSizes runtime;
|
||||
|
||||
CompartmentStats cTotals; // The sum of this runtime's compartments' measurements.
|
||||
ZoneStats zTotals; // The sum of this runtime's zones' measurements.
|
||||
|
||||
js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> compartmentStatsVector;
|
||||
js::Vector<ZoneStats, 0, js::SystemAllocPolicy> zoneStatsVector;
|
||||
|
@ -426,6 +501,8 @@ struct RuntimeStats
|
|||
|
||||
virtual void initExtraCompartmentStats(JSCompartment *c, CompartmentStats *cstats) = 0;
|
||||
virtual void initExtraZoneStats(JS::Zone *zone, ZoneStats *zstats) = 0;
|
||||
|
||||
#undef FOR_EACH_SIZE
|
||||
};
|
||||
|
||||
class ObjectPrivateVisitor
|
||||
|
@ -437,7 +514,7 @@ class ObjectPrivateVisitor
|
|||
|
||||
// A callback that gets a JSObject's nsISupports pointer, if it has one.
|
||||
// Note: this function does *not* addref |iface|.
|
||||
typedef JSBool(*GetISupportsFun)(JSObject *obj, nsISupports **iface);
|
||||
typedef bool(*GetISupportsFun)(JSObject *obj, nsISupports **iface);
|
||||
GetISupportsFun getISupports_;
|
||||
|
||||
ObjectPrivateVisitor(GetISupportsFun getISupports)
|
||||
|
@ -457,6 +534,17 @@ UserCompartmentCount(JSRuntime *rt);
|
|||
extern JS_PUBLIC_API(size_t)
|
||||
PeakSizeOfTemporary(const JSRuntime *rt);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
AddSizeOfTab(JSRuntime *rt, JSObject *obj, mozilla::MallocSizeOf mallocSizeOf,
|
||||
ObjectPrivateVisitor *opv, TabSizes *sizes);
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#undef DECL_SIZE
|
||||
#undef ZERO_SIZE
|
||||
#undef COPY_OTHER_SIZE
|
||||
#undef ADD_OTHER_SIZE
|
||||
#undef ADD_SIZE_TO_N_IF_LIVE_GC_THING
|
||||
#undef ADD_TO_TAB_SIZES
|
||||
|
||||
#endif /* js_MemoryMetrics_h */
|
||||
|
|
|
@ -4,13 +4,24 @@
|
|||
* License, v. 2.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 jsdbgapi_h
|
||||
#define jsdbgapi_h
|
||||
#ifndef js_OldDebugAPI_h
|
||||
#define js_OldDebugAPI_h
|
||||
|
||||
/*
|
||||
* JS debugger API.
|
||||
*/
|
||||
|
||||
#include "jsprvtd.h"
|
||||
#include "mozilla/NullPtr.h"
|
||||
|
||||
#include "jsbytecode.h"
|
||||
|
||||
#include "js/CallArgs.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
class JSAtom;
|
||||
class JSFreeOp;
|
||||
|
||||
namespace js { class StackFrame; }
|
||||
|
||||
namespace JS {
|
||||
|
||||
|
@ -34,21 +45,68 @@ extern JS_PUBLIC_API(void)
|
|||
FreeStackDescription(JSContext *cx, StackDescription *desc);
|
||||
|
||||
extern JS_PUBLIC_API(char *)
|
||||
FormatStackDump(JSContext *cx, char *buf,
|
||||
JSBool showArgs, JSBool showLocals,
|
||||
JSBool showThisProps);
|
||||
FormatStackDump(JSContext *cx, char *buf, bool showArgs, bool showLocals, bool showThisProps);
|
||||
|
||||
}
|
||||
|
||||
# ifdef DEBUG
|
||||
JS_FRIEND_API(void) js_DumpValue(const js::Value &val);
|
||||
JS_FRIEND_API(void) js_DumpValue(const JS::Value &val);
|
||||
JS_FRIEND_API(void) js_DumpId(jsid id);
|
||||
JS_FRIEND_API(void) js_DumpStackFrame(JSContext *cx, js::StackFrame *start = NULL);
|
||||
JS_FRIEND_API(void) js_DumpStackFrame(JSContext *cx, js::StackFrame *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
|
||||
(* JSInterruptHook)(JSContext *cx, JSScript *script, jsbytecode *pc, JS::Value *rval,
|
||||
void *closure);
|
||||
|
||||
typedef JSTrapStatus
|
||||
(* JSDebuggerHandler)(JSContext *cx, JSScript *script, jsbytecode *pc, JS::Value *rval,
|
||||
void *closure);
|
||||
|
||||
typedef JSTrapStatus
|
||||
(* JSThrowHook)(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);
|
||||
|
||||
/* called just after script creation */
|
||||
typedef void
|
||||
(* JSNewScriptHook)(JSContext *cx,
|
||||
const char *filename, /* URL of script */
|
||||
unsigned lineno, /* first line */
|
||||
JSScript *script,
|
||||
JSFunction *fun,
|
||||
void *callerdata);
|
||||
|
||||
/* called just before script destruction */
|
||||
typedef void
|
||||
(* JSDestroyScriptHook)(JSFreeOp *fop,
|
||||
JSScript *script,
|
||||
void *callerdata);
|
||||
|
||||
typedef void
|
||||
(* JSSourceHandler)(const char *filename, unsigned lineno, const jschar *str,
|
||||
size_t length, void **listenerTSData, void *closure);
|
||||
|
||||
|
||||
|
||||
extern JS_PUBLIC_API(JSCompartment *)
|
||||
JS_EnterCompartmentOfScript(JSContext *cx, JSScript *target);
|
||||
|
||||
|
@ -60,7 +118,7 @@ JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, unsigned i
|
|||
* be able to support compartment-wide debugging.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_SetRuntimeDebugMode(JSRuntime *rt, JSBool debug);
|
||||
JS_SetRuntimeDebugMode(JSRuntime *rt, bool debug);
|
||||
|
||||
/*
|
||||
* Debug mode is a compartment-wide mode that enables a debugger to attach
|
||||
|
@ -73,42 +131,42 @@ JS_SetRuntimeDebugMode(JSRuntime *rt, JSBool debug);
|
|||
*/
|
||||
|
||||
/* Get current state of debugging mode. */
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
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(JSBool)
|
||||
JS_SetDebugModeForAllCompartments(JSContext *cx, JSBool debug);
|
||||
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(JSBool)
|
||||
JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, JSBool debug);
|
||||
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(JSBool)
|
||||
JS_SetDebugMode(JSContext *cx, JSBool debug);
|
||||
JS_FRIEND_API(bool)
|
||||
JS_SetDebugMode(JSContext *cx, bool debug);
|
||||
|
||||
/* Turn on single step mode. */
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_SetSingleStepMode(JSContext *cx, JSScript *script, JSBool singleStep);
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetSingleStepMode(JSContext *cx, JSScript *script, bool singleStep);
|
||||
|
||||
/* The closure argument will be marked. */
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
JSTrapHandler handler, jsval closure);
|
||||
JSTrapHandler handler, JS::Value closure);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_ClearTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
JSTrapHandler *handlerp, jsval *closurep);
|
||||
JSTrapHandler *handlerp, JS::Value *closurep);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_ClearScriptTraps(JSRuntime *rt, JSScript *script);
|
||||
|
@ -116,28 +174,25 @@ JS_ClearScriptTraps(JSRuntime *rt, JSScript *script);
|
|||
extern JS_PUBLIC_API(void)
|
||||
JS_ClearAllTrapsForCompartment(JSContext *cx);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetInterrupt(JSRuntime *rt, JSInterruptHook handler, void *closure);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_ClearInterrupt(JSRuntime *rt, JSInterruptHook *handlerp, void **closurep);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSWatchPointHandler handler, JSObject *closure);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSWatchPointHandler *handlerp, JSObject **closurep);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_ClearWatchPointsForObject(JSContext *cx, JSObject *obj);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_ClearAllWatchPoints(JSContext *cx);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
// Raw JSScript* because this needs to be callable from a signal handler.
|
||||
|
@ -150,7 +205,7 @@ JS_LineNumberToPC(JSContext *cx, JSScript *script, unsigned lineno);
|
|||
extern JS_PUBLIC_API(jsbytecode *)
|
||||
JS_EndPC(JSContext *cx, JSScript *script);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_GetLinePCs(JSContext *cx, JSScript *script,
|
||||
unsigned startLine, unsigned maxLines,
|
||||
unsigned* count, unsigned** lines, jsbytecode*** pcs);
|
||||
|
@ -158,7 +213,7 @@ JS_GetLinePCs(JSContext *cx, JSScript *script,
|
|||
extern JS_PUBLIC_API(unsigned)
|
||||
JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun);
|
||||
|
||||
/*
|
||||
|
@ -230,9 +285,8 @@ JS_GetScriptIsSelfHosted(JSScript *script);
|
|||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* Hook setters for script creation and destruction, see jsprvtd.h for the
|
||||
* typedefs. These macros provide binary compatibility and newer, shorter
|
||||
* synonyms.
|
||||
* Hook setters for script creation and destruction. These macros provide
|
||||
* binary compatibility and newer, shorter synonyms.
|
||||
*/
|
||||
#define JS_SetNewScriptHook JS_SetNewScriptHookProc
|
||||
#define JS_SetDestroyScriptHook JS_SetDestroyScriptHookProc
|
||||
|
@ -247,11 +301,11 @@ JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
|
|||
/************************************************************************/
|
||||
|
||||
typedef struct JSPropertyDesc {
|
||||
jsval id; /* primary id, atomized string, or int */
|
||||
jsval value; /* property value */
|
||||
JS::Value id; /* primary id, atomized string, or int */
|
||||
JS::Value value; /* property value */
|
||||
uint8_t flags; /* flags, see below */
|
||||
uint8_t spare; /* unused */
|
||||
jsval alias; /* alias id if JSPD_ALIAS flag */
|
||||
JS::Value alias; /* alias id if JSPD_ALIAS flag */
|
||||
} JSPropertyDesc;
|
||||
|
||||
#define JSPD_ENUMERATE 0x01 /* visible to for/in loop */
|
||||
|
@ -260,7 +314,7 @@ typedef struct JSPropertyDesc {
|
|||
#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 JS_FALSE without */
|
||||
#define JSPD_ERROR 0x80 /* native getter returned false without */
|
||||
/* throwing an exception */
|
||||
|
||||
typedef struct JSPropertyDescArray {
|
||||
|
@ -270,7 +324,7 @@ typedef struct JSPropertyDescArray {
|
|||
|
||||
typedef struct JSScopeProperty JSScopeProperty;
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
|
@ -358,8 +412,8 @@ class JS_PUBLIC_API(JSBrokenFrameIterator)
|
|||
* or function call: just before execution begins and just after it finishes.
|
||||
* In both cases the 'current' frame is that of the executing code.
|
||||
*
|
||||
* The 'before' param is JS_TRUE for the hook invocation before the execution
|
||||
* and JS_FALSE for the invocation after the code has run.
|
||||
* The 'before' param is true for the hook invocation before the execution
|
||||
* and false for the invocation after the code has run.
|
||||
*
|
||||
* The 'ok' param is significant only on the post execution invocation to
|
||||
* signify whether or not the code completed 'normally'.
|
||||
|
@ -373,14 +427,14 @@ class JS_PUBLIC_API(JSBrokenFrameIterator)
|
|||
* in 'closure' to cause the 'after' invocation to be called with the same
|
||||
* 'closure' value as the 'before'.
|
||||
*
|
||||
* Returning NULL in the 'before' hook will cause the 'after' hook *not* to
|
||||
* Returning nullptr in the 'before' hook will cause the 'after' hook *not* to
|
||||
* be called.
|
||||
*/
|
||||
typedef void *
|
||||
(* JSInterpreterHook)(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing,
|
||||
JSBool before, JSBool *ok, void *closure);
|
||||
bool before, bool *ok, void *closure);
|
||||
|
||||
typedef JSBool
|
||||
typedef bool
|
||||
(* JSDebugErrorHook)(JSContext *cx, const char *message, JSErrorReport *report,
|
||||
void *closure);
|
||||
|
||||
|
@ -407,22 +461,22 @@ typedef struct JSDebugHooks {
|
|||
|
||||
/************************************************************************/
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetDebuggerHandler(JSRuntime *rt, JSDebuggerHandler hook, void *closure);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetThrowHook(JSRuntime *rt, JSThrowHook hook, void *closure);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure);
|
||||
|
||||
/************************************************************************/
|
||||
|
@ -433,11 +487,11 @@ JS_GetGlobalDebugHooks(JSRuntime *rt);
|
|||
/**
|
||||
* Add various profiling-related functions as properties of the given object.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj);
|
||||
|
||||
/* Defined in vm/Debugger.cpp. */
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineDebuggerObject(JSContext *cx, JSObject *obj);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
|
@ -452,8 +506,13 @@ JS_DumpPCCounts(JSContext *cx, JSScript *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(JSBool)
|
||||
extern JS_FRIEND_API(bool)
|
||||
js_CallContextDebugHandler(JSContext *cx);
|
||||
|
||||
#endif /* jsdbgapi_h */
|
||||
#endif /* js_OldDebugAPI_h */
|
|
@ -0,0 +1,95 @@
|
|||
/* -*- 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_ProfilingStack_h
|
||||
#define js_ProfilingStack_h
|
||||
|
||||
#include "mozilla/NullPtr.h"
|
||||
|
||||
#include "jsbytecode.h"
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "js/Utility.h"
|
||||
|
||||
struct JSRuntime;
|
||||
|
||||
namespace js {
|
||||
|
||||
// A call stack can be specified to the JS engine such that all JS entry/exits
|
||||
// to functions push/pop an entry to/from the specified stack.
|
||||
//
|
||||
// For more detailed information, see vm/SPSProfiler.h.
|
||||
//
|
||||
class ProfileEntry
|
||||
{
|
||||
// All fields are marked volatile to prevent the compiler from re-ordering
|
||||
// instructions. Namely this sequence:
|
||||
//
|
||||
// entry[size] = ...;
|
||||
// size++;
|
||||
//
|
||||
// If the size modification were somehow reordered before the stores, then
|
||||
// if a sample were taken it would be examining bogus information.
|
||||
//
|
||||
// A ProfileEntry represents both a C++ profile entry and a JS one. Both use
|
||||
// the string as a description, but JS uses the sp as nullptr to indicate
|
||||
// that it is a JS entry. The script_ is then only ever examined for a JS
|
||||
// entry, and the idx is used by both, but with different meanings.
|
||||
//
|
||||
const char * volatile string; // Descriptive string of this entry
|
||||
void * volatile sp; // Relevant stack pointer for the entry
|
||||
JSScript * volatile script_; // if js(), non-null script which is running
|
||||
int32_t volatile idx; // if js(), idx of pc, otherwise line number
|
||||
|
||||
public:
|
||||
// All of these methods are marked with the 'volatile' keyword because SPS's
|
||||
// representation of the stack is stored such that all ProfileEntry
|
||||
// instances are volatile. These methods would not be available unless they
|
||||
// were marked as volatile as well.
|
||||
|
||||
bool js() volatile {
|
||||
JS_ASSERT_IF(sp == nullptr, script_ != nullptr);
|
||||
return sp == nullptr;
|
||||
}
|
||||
|
||||
uint32_t line() volatile { JS_ASSERT(!js()); return idx; }
|
||||
JSScript *script() volatile { JS_ASSERT(js()); return script_; }
|
||||
void *stackAddress() volatile { return sp; }
|
||||
const char *label() volatile { return string; }
|
||||
|
||||
void setLine(uint32_t aLine) volatile { JS_ASSERT(!js()); idx = aLine; }
|
||||
void setLabel(const char *aString) volatile { string = aString; }
|
||||
void setStackAddress(void *aSp) volatile { sp = aSp; }
|
||||
void setScript(JSScript *aScript) volatile { script_ = aScript; }
|
||||
|
||||
// We can't know the layout of JSScript, so look in vm/SPSProfiler.cpp.
|
||||
JS_FRIEND_API(jsbytecode *) pc() volatile;
|
||||
JS_FRIEND_API(void) setPC(jsbytecode *pc) volatile;
|
||||
|
||||
static size_t offsetOfString() { return offsetof(ProfileEntry, string); }
|
||||
static size_t offsetOfStackAddress() { return offsetof(ProfileEntry, sp); }
|
||||
static size_t offsetOfPCIdx() { return offsetof(ProfileEntry, idx); }
|
||||
static size_t offsetOfScript() { return offsetof(ProfileEntry, script_); }
|
||||
|
||||
// The index used in the entry can either be a line number or the offset of
|
||||
// a pc into a script's code. To signify a nullptr pc, use a -1 index. This
|
||||
// is checked against in pc() and setPC() to set/get the right pc.
|
||||
static const int32_t NullPCIndex = -1;
|
||||
};
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size,
|
||||
uint32_t max);
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled);
|
||||
|
||||
JS_FRIEND_API(jsbytecode*)
|
||||
ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip);
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* js_ProfilingStack_h */
|
|
@ -9,12 +9,9 @@
|
|||
#ifndef js_PropertyKey_h
|
||||
#define js_PropertyKey_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Value.h"
|
||||
|
||||
struct JSContext;
|
||||
|
||||
namespace JS {
|
||||
|
||||
class PropertyKey;
|
||||
|
|
|
@ -15,9 +15,17 @@
|
|||
|
||||
/*
|
||||
* The c99 defining the limit macros (UINT32_MAX for example), says:
|
||||
* C++ implementations should define these macros only when __STDC_LIMIT_MACROS
|
||||
* is defined before <stdint.h> is included.
|
||||
*
|
||||
* C++ implementations should define these macros only when
|
||||
* __STDC_LIMIT_MACROS is defined before <stdint.h> is included.
|
||||
*
|
||||
* The same also occurs with __STDC_CONSTANT_MACROS for the constant macros
|
||||
* (INT8_C for example) used to specify a literal constant of the proper type,
|
||||
* and with __STDC_FORMAT_MACROS for the format macros (PRId32 for example) used
|
||||
* with the fprintf function family.
|
||||
*/
|
||||
#define __STDC_LIMIT_MACROS
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#define __STDC_FORMAT_MACROS
|
||||
|
||||
#endif /* js_RequiredDefines_h */
|
||||
|
|
|
@ -8,12 +8,14 @@
|
|||
#define js_RootingAPI_h
|
||||
|
||||
#include "mozilla/GuardObjects.h"
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
#include "js/Utility.h"
|
||||
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Utility.h"
|
||||
|
||||
/*
|
||||
* Moving GC Stack Rooting
|
||||
*
|
||||
|
@ -97,7 +99,6 @@
|
|||
|
||||
namespace js {
|
||||
|
||||
class Module;
|
||||
class ScriptSourceObject;
|
||||
|
||||
template <typename T>
|
||||
|
@ -116,13 +117,13 @@ template <typename T>
|
|||
class HeapBase {};
|
||||
|
||||
/*
|
||||
* js::NullPtr acts like a NULL pointer in contexts that require a Handle.
|
||||
* js::NullPtr acts like a nullptr pointer in contexts that require a Handle.
|
||||
*
|
||||
* Handle provides an implicit constructor for js::NullPtr so that, given:
|
||||
* foo(Handle<JSObject*> h);
|
||||
* callers can simply write:
|
||||
* foo(js::NullPtr());
|
||||
* which avoids creating a Rooted<JSObject*> just to pass NULL.
|
||||
* which avoids creating a Rooted<JSObject*> just to pass nullptr.
|
||||
*
|
||||
* This is the SpiderMonkey internal variant. js::NullPtr should be used in
|
||||
* preference to JS::NullPtr to avoid the GOT access required for JS_PUBLIC_API
|
||||
|
@ -143,9 +144,6 @@ namespace JS {
|
|||
|
||||
template <typename T> class Rooted;
|
||||
|
||||
template <typename T> class Handle;
|
||||
template <typename T> class MutableHandle;
|
||||
|
||||
/* This is exposing internal state of the GC for inlining purposes. */
|
||||
JS_FRIEND_API(bool) isGCEnabled();
|
||||
|
||||
|
@ -155,13 +153,13 @@ CheckStackRoots(JSContext *cx);
|
|||
#endif
|
||||
|
||||
/*
|
||||
* JS::NullPtr acts like a NULL pointer in contexts that require a Handle.
|
||||
* JS::NullPtr acts like a nullptr pointer in contexts that require a Handle.
|
||||
*
|
||||
* Handle provides an implicit constructor for JS::NullPtr so that, given:
|
||||
* foo(Handle<JSObject*> h);
|
||||
* callers can simply write:
|
||||
* foo(JS::NullPtr());
|
||||
* which avoids creating a Rooted<JSObject*> just to pass NULL.
|
||||
* which avoids creating a Rooted<JSObject*> just to pass nullptr.
|
||||
*/
|
||||
struct JS_PUBLIC_API(NullPtr)
|
||||
{
|
||||
|
@ -377,7 +375,7 @@ class TenuredHeap : public js::HeapBase<T>
|
|||
template <typename T>
|
||||
class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
|
||||
{
|
||||
friend class MutableHandle<T>;
|
||||
friend class JS::MutableHandle<T>;
|
||||
|
||||
public:
|
||||
/* Creates a handle from a handle of a type convertible to T. */
|
||||
|
@ -390,14 +388,14 @@ class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
|
|||
ptr = reinterpret_cast<const T *>(handle.address());
|
||||
}
|
||||
|
||||
/* Create a handle for a NULL pointer. */
|
||||
/* Create a handle for a nullptr pointer. */
|
||||
Handle(js::NullPtr) {
|
||||
static_assert(mozilla::IsPointer<T>::value,
|
||||
"js::NullPtr overload not valid for non-pointer types");
|
||||
ptr = reinterpret_cast<const T *>(&js::NullPtr::constNullValue);
|
||||
}
|
||||
|
||||
/* Create a handle for a NULL pointer. */
|
||||
/* Create a handle for a nullptr pointer. */
|
||||
Handle(JS::NullPtr) {
|
||||
static_assert(mozilla::IsPointer<T>::value,
|
||||
"JS::NullPtr overload not valid for non-pointer types");
|
||||
|
@ -457,24 +455,18 @@ class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
|
|||
bool operator!=(const T &other) const { return *ptr != other; }
|
||||
bool operator==(const T &other) const { return *ptr == other; }
|
||||
|
||||
/* Change this handle to point to the same rooted location RHS does. */
|
||||
void repoint(const Handle &rhs) { ptr = rhs.address(); }
|
||||
|
||||
private:
|
||||
Handle() {}
|
||||
|
||||
const T *ptr;
|
||||
|
||||
template <typename S>
|
||||
void operator=(S v) MOZ_DELETE;
|
||||
template <typename S> void operator=(S) MOZ_DELETE;
|
||||
void operator=(Handle) MOZ_DELETE;
|
||||
};
|
||||
|
||||
typedef Handle<JSObject*> HandleObject;
|
||||
typedef Handle<js::Module*> HandleModule;
|
||||
typedef Handle<js::ScriptSourceObject *> HandleScriptSource;
|
||||
typedef Handle<JSFunction*> HandleFunction;
|
||||
typedef Handle<JSScript*> HandleScript;
|
||||
typedef Handle<JSString*> HandleString;
|
||||
typedef Handle<jsid> HandleId;
|
||||
typedef Handle<Value> HandleValue;
|
||||
|
||||
/*
|
||||
* Similar to a handle, but the underlying storage can be changed. This is
|
||||
* useful for outparams.
|
||||
|
@ -488,6 +480,10 @@ class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T>
|
|||
{
|
||||
public:
|
||||
inline MutableHandle(Rooted<T> *root);
|
||||
MutableHandle(int) MOZ_DELETE;
|
||||
#ifdef MOZ_HAVE_CXX11_NULLPTR
|
||||
MutableHandle(decltype(nullptr)) MOZ_DELETE;
|
||||
#endif
|
||||
|
||||
void set(T v) {
|
||||
JS_ASSERT(!js::GCMethods<T>::poisoned(v));
|
||||
|
@ -526,13 +522,6 @@ class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T>
|
|||
void operator=(MutableHandle other) MOZ_DELETE;
|
||||
};
|
||||
|
||||
typedef MutableHandle<JSObject*> MutableHandleObject;
|
||||
typedef MutableHandle<JSFunction*> MutableHandleFunction;
|
||||
typedef MutableHandle<JSScript*> MutableHandleScript;
|
||||
typedef MutableHandle<JSString*> MutableHandleString;
|
||||
typedef MutableHandle<jsid> MutableHandleId;
|
||||
typedef MutableHandle<Value> MutableHandleValue;
|
||||
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
JS_PUBLIC_API(void) HeapCellPostBarrier(js::gc::Cell **cellp);
|
||||
JS_PUBLIC_API(void) HeapCellRelocate(js::gc::Cell **cellp);
|
||||
|
@ -614,7 +603,7 @@ struct RootKind<T *>
|
|||
template <typename T>
|
||||
struct GCMethods<T *>
|
||||
{
|
||||
static T *initial() { return NULL; }
|
||||
static T *initial() { return nullptr; }
|
||||
static ThingRootKind kind() { return RootKind<T *>::rootKind(); }
|
||||
static bool poisoned(T *v) { return JS::IsPoisonedPtr(v); }
|
||||
static bool needsPostBarrier(T *v) { return v; }
|
||||
|
@ -628,12 +617,11 @@ struct GCMethods<T *>
|
|||
#endif
|
||||
};
|
||||
|
||||
// XXX: Needed for cocos2d JS Bindings
|
||||
//#if defined(DEBUG)
|
||||
#if defined(DEBUG)
|
||||
/* This helper allows us to assert that Rooted<T> is scoped within a request. */
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsInRequest(JSContext *cx);
|
||||
//#endif
|
||||
#endif
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
|
@ -730,12 +718,15 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
|||
init(js::PerThreadDataFriendFields::getMainThread(rt));
|
||||
}
|
||||
|
||||
~Rooted() {
|
||||
// Note that we need to let the compiler generate the default destructor in
|
||||
// non-exact-rooting builds because of a bug in the instrumented PGO builds
|
||||
// using MSVC, see bug 915735 for more details.
|
||||
#ifdef JSGC_TRACK_EXACT_ROOTS
|
||||
~Rooted() {
|
||||
JS_ASSERT(*stack == reinterpret_cast<Rooted<void*>*>(this));
|
||||
*stack = prev;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef JSGC_TRACK_EXACT_ROOTS
|
||||
Rooted<T> *previous() { return prev; }
|
||||
|
@ -803,8 +794,6 @@ class Rooted<JSStableString *>;
|
|||
#endif
|
||||
|
||||
typedef Rooted<JSObject*> RootedObject;
|
||||
typedef Rooted<js::Module*> RootedModule;
|
||||
typedef Rooted<js::ScriptSourceObject *> RootedScriptSource;
|
||||
typedef Rooted<JSFunction*> RootedFunction;
|
||||
typedef Rooted<JSScript*> RootedScript;
|
||||
typedef Rooted<JSString*> RootedString;
|
||||
|
@ -857,6 +846,10 @@ class SkipRoot
|
|||
void init(js::ContextFriendFields *cx, const T *ptr, size_t count) {}
|
||||
|
||||
public:
|
||||
~SkipRoot() {
|
||||
// An empty destructor is needed to avoid warnings from clang about
|
||||
// unused local variables of this type.
|
||||
}
|
||||
|
||||
#endif /* DEBUG && JSGC_ROOT_ANALYSIS */
|
||||
|
||||
|
@ -1063,7 +1056,7 @@ inline void MaybeCheckStackRoots(JSContext *cx)
|
|||
class CompilerRootNode
|
||||
{
|
||||
protected:
|
||||
CompilerRootNode(js::gc::Cell *ptr) : next(NULL), ptr_(ptr) {}
|
||||
CompilerRootNode(js::gc::Cell *ptr) : next(nullptr), ptr_(ptr) {}
|
||||
|
||||
public:
|
||||
void **address() { return (void **)&ptr_; }
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
/* -*- 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_StructuredClone_h
|
||||
#define js_StructuredClone_h
|
||||
|
||||
#include "mozilla/NullPtr.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Value.h"
|
||||
|
||||
struct JSRuntime;
|
||||
struct JSStructuredCloneReader;
|
||||
struct JSStructuredCloneWriter;
|
||||
|
||||
// API for the HTML5 internal structured cloning algorithm.
|
||||
|
||||
// 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::Handle<JSObject*> 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);
|
||||
|
||||
// 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 2
|
||||
|
||||
struct JSStructuredCloneCallbacks {
|
||||
ReadStructuredCloneOp read;
|
||||
WriteStructuredCloneOp write;
|
||||
StructuredCloneErrorOp reportError;
|
||||
};
|
||||
|
||||
// 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::MutableHandleValue vp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks, void *closure);
|
||||
|
||||
// Note: On success, the caller is responsible for calling
|
||||
// JS_ClearStructuredClone(*datap, nbytesp).
|
||||
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);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ClearStructuredClone(const uint64_t *data, size_t nbytes);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StructuredCloneHasTransferables(const uint64_t *data, size_t nbytes, bool *hasTransferable);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_StructuredClone(JSContext *cx, JS::HandleValue v, JS::MutableHandleValue vp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks, void *closure);
|
||||
|
||||
// RAII sugar for JS_WriteStructuredClone.
|
||||
class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
|
||||
uint64_t *data_;
|
||||
size_t nbytes_;
|
||||
uint32_t version_;
|
||||
|
||||
public:
|
||||
JSAutoStructuredCloneBuffer()
|
||||
: data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION) {}
|
||||
|
||||
~JSAutoStructuredCloneBuffer() { clear(); }
|
||||
|
||||
uint64_t *data() const { return data_; }
|
||||
size_t nbytes() const { return nbytes_; }
|
||||
|
||||
void clear();
|
||||
|
||||
// Copy some memory. It will be automatically freed by the destructor.
|
||||
bool copy(const uint64_t *data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
bool read(JSContext *cx, JS::MutableHandleValue vp,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks=nullptr, void *closure=nullptr);
|
||||
|
||||
bool write(JSContext *cx, JS::HandleValue v,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks=nullptr, void *closure=nullptr);
|
||||
|
||||
bool write(JSContext *cx, JS::HandleValue v, JS::HandleValue transferable,
|
||||
const JSStructuredCloneCallbacks *optionalCallbacks=nullptr, void *closure=nullptr);
|
||||
|
||||
// Swap ownership with another JSAutoStructuredCloneBuffer.
|
||||
void swap(JSAutoStructuredCloneBuffer &other);
|
||||
|
||||
private:
|
||||
// Copy and assignment are not supported.
|
||||
JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer &other);
|
||||
JSAutoStructuredCloneBuffer &operator=(const JSAutoStructuredCloneBuffer &other);
|
||||
};
|
||||
|
||||
// The range of tag values the application may use for its own custom object types.
|
||||
#define JS_SCTAG_USER_MIN ((uint32_t) 0xFFFF8000)
|
||||
#define JS_SCTAG_USER_MAX ((uint32_t) 0xFFFFFFFF)
|
||||
|
||||
#define JS_SCERR_RECURSION 0
|
||||
#define JS_SCERR_TRANSFERABLE 1
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ReadTypedArray(JSStructuredCloneReader *r, JS::Value *vp);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32_t tag, uint32_t data);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len);
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_WriteTypedArray(JSStructuredCloneWriter *w, JS::Value v);
|
||||
|
||||
#endif /* js_StructuredClone_h */
|
|
@ -0,0 +1,193 @@
|
|||
/* -*- 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_Tracer_h
|
||||
#define js_Tracer_h
|
||||
|
||||
#include "mozilla/NullPtr.h"
|
||||
|
||||
#include "jspubtd.h"
|
||||
|
||||
struct JSTracer;
|
||||
|
||||
namespace JS {
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
enum WeakMapTraceKind {
|
||||
DoNotTraceWeakMaps = 0,
|
||||
TraceWeakMapValues = 1,
|
||||
TraceWeakMapKeysValues = 2
|
||||
};
|
||||
|
||||
struct JSTracer {
|
||||
JSRuntime *runtime;
|
||||
JSTraceCallback callback;
|
||||
JSTraceNamePrinter debugPrinter;
|
||||
const void *debugPrintArg;
|
||||
size_t debugPrintIndex;
|
||||
WeakMapTraceKind eagerlyTraceWeakMaps;
|
||||
#ifdef JS_GC_ZEAL
|
||||
void *realLocation;
|
||||
#endif
|
||||
};
|
||||
|
||||
// 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.
|
||||
//
|
||||
# define JS_SET_TRACING_DETAILS(trc, printer, arg, index) \
|
||||
JS_BEGIN_MACRO \
|
||||
(trc)->debugPrinter = (printer); \
|
||||
(trc)->debugPrintArg = (arg); \
|
||||
(trc)->debugPrintIndex = (index); \
|
||||
JS_END_MACRO
|
||||
|
||||
// Sets the real location for a marked reference, when passing the address
|
||||
// directly is not feasable.
|
||||
//
|
||||
// FIXME: This is currently overcomplicated by our need to nest calls for Values
|
||||
// stored as keys in hash tables, but will get simplified once we can rekey
|
||||
// in-place.
|
||||
//
|
||||
#ifdef JS_GC_ZEAL
|
||||
# define JS_SET_TRACING_LOCATION(trc, location) \
|
||||
JS_BEGIN_MACRO \
|
||||
if (!(trc)->realLocation || !(location)) \
|
||||
(trc)->realLocation = (location); \
|
||||
JS_END_MACRO
|
||||
# define JS_UNSET_TRACING_LOCATION(trc) \
|
||||
JS_BEGIN_MACRO \
|
||||
(trc)->realLocation = nullptr; \
|
||||
JS_END_MACRO
|
||||
#else
|
||||
# define JS_SET_TRACING_LOCATION(trc, location) \
|
||||
JS_BEGIN_MACRO \
|
||||
JS_END_MACRO
|
||||
# define JS_UNSET_TRACING_LOCATION(trc) \
|
||||
JS_BEGIN_MACRO \
|
||||
JS_END_MACRO
|
||||
#endif
|
||||
|
||||
// Convenience macro to describe the argument of JS_CallTracer using C string
|
||||
// and index.
|
||||
# define JS_SET_TRACING_INDEX(trc, name, index) \
|
||||
JS_SET_TRACING_DETAILS(trc, nullptr, name, index)
|
||||
|
||||
// Convenience macro to describe the argument of JS_CallTracer using C string.
|
||||
# define JS_SET_TRACING_NAME(trc, name) \
|
||||
JS_SET_TRACING_DETAILS(trc, nullptr, name, (size_t)-1)
|
||||
|
||||
// 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);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_CallIdTracer(JSTracer *trc, jsid *idp, const char *name);
|
||||
|
||||
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);
|
||||
|
||||
template <typename HashSetEnum>
|
||||
inline void
|
||||
JS_CallHashSetObjectTracer(JSTracer *trc, HashSetEnum &e, JSObject *const &key, const char *name)
|
||||
{
|
||||
JSObject *updated = key;
|
||||
JS_SET_TRACING_LOCATION(trc, reinterpret_cast<void *>(&const_cast<JSObject *&>(key)));
|
||||
JS_CallObjectTracer(trc, &updated, name);
|
||||
if (updated != key)
|
||||
e.rekeyFront(key, updated);
|
||||
}
|
||||
|
||||
// Trace an object that is known to always be tenured. No post barriers are
|
||||
// required in this case.
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_CallTenuredObjectTracer(JSTracer *trc, JS::TenuredHeap<JSObject *> *objp, const char *name);
|
||||
|
||||
// API for JSTraceCallback implementations.
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_TracerInit(JSTracer *trc, JSRuntime *rt, JSTraceCallback callback);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_TraceRuntime(JSTracer *trc);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_GetTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc,
|
||||
void *thing, JSGCTraceKind kind, bool includeDetails);
|
||||
|
||||
extern JS_PUBLIC_API(const char *)
|
||||
JS_GetTraceEdgeName(JSTracer *trc, char *buffer, int bufferSize);
|
||||
|
||||
#endif /* js_Tracer_h */
|
|
@ -0,0 +1,81 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This file contains public type declarations that are used *frequently*. If
|
||||
// it doesn't occur at least 10 times in Gecko, it probably shouldn't be in
|
||||
// here.
|
||||
//
|
||||
// It includes only:
|
||||
// - forward declarations of structs and classes;
|
||||
// - typedefs;
|
||||
// - enums (maybe).
|
||||
// It does *not* contain any struct or class definitions.
|
||||
|
||||
#ifndef js_TypeDecls_h
|
||||
#define js_TypeDecls_h
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct JSContext;
|
||||
class JSFunction;
|
||||
class JSObject;
|
||||
class JSScript;
|
||||
class JSString;
|
||||
|
||||
// In release builds, jsid is defined to be an integral type. This
|
||||
// prevents many bugs from being caught at compile time. E.g.:
|
||||
//
|
||||
// jsid id = ...
|
||||
// if (id) // error
|
||||
// ...
|
||||
//
|
||||
// size_t n = id; // error
|
||||
//
|
||||
// To catch more errors, jsid is given a struct type in C++ debug builds.
|
||||
// Struct assignment and (in C++) operator== allow correct code to be mostly
|
||||
// oblivious to the change. This feature can be explicitly disabled in debug
|
||||
// builds by defining JS_NO_JSVAL_JSID_STRUCT_TYPES.
|
||||
//
|
||||
|
||||
// Needed for cocos2d-js
|
||||
#define JS_NO_JSVAL_JSID_STRUCT_TYPES
|
||||
|
||||
#if defined(DEBUG) && !defined(JS_NO_JSVAL_JSID_STRUCT_TYPES)
|
||||
# define JS_USE_JSID_STRUCT_TYPES
|
||||
#endif
|
||||
|
||||
#ifdef JS_USE_JSID_STRUCT_TYPES
|
||||
struct jsid;
|
||||
#else
|
||||
typedef ptrdiff_t jsid;
|
||||
#endif
|
||||
|
||||
typedef char16_t jschar;
|
||||
|
||||
namespace JS {
|
||||
|
||||
class Value;
|
||||
template <typename T> class Handle;
|
||||
template <typename T> class MutableHandle;
|
||||
|
||||
typedef Handle<JSFunction*> HandleFunction;
|
||||
typedef Handle<jsid> HandleId;
|
||||
typedef Handle<JSObject*> HandleObject;
|
||||
typedef Handle<JSScript*> HandleScript;
|
||||
typedef Handle<JSString*> HandleString;
|
||||
typedef Handle<Value> HandleValue;
|
||||
|
||||
typedef MutableHandle<JSFunction*> MutableHandleFunction;
|
||||
typedef MutableHandle<jsid> MutableHandleId;
|
||||
typedef MutableHandle<JSObject*> MutableHandleObject;
|
||||
typedef MutableHandle<JSScript*> MutableHandleScript;
|
||||
typedef MutableHandle<JSString*> MutableHandleString;
|
||||
typedef MutableHandle<Value> MutableHandleValue;
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#endif /* js_TypeDecls_h */
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Compiler.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "mozilla/Scoped.h"
|
||||
#include "mozilla/TemplateLib.h"
|
||||
|
||||
|
@ -18,8 +19,8 @@
|
|||
#include <string.h>
|
||||
|
||||
#ifdef JS_OOM_DO_BACKTRACES
|
||||
#include <stdio.h>
|
||||
#include <execinfo.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "jstypes.h"
|
||||
|
@ -44,16 +45,6 @@ namespace js {}
|
|||
#define JS_ALWAYS_TRUE(expr) MOZ_ALWAYS_TRUE(expr)
|
||||
#define JS_ALWAYS_FALSE(expr) MOZ_ALWAYS_FALSE(expr)
|
||||
|
||||
#ifdef DEBUG
|
||||
# ifdef JS_THREADSAFE
|
||||
# define JS_THREADSAFE_ASSERT(expr) JS_ASSERT(expr)
|
||||
# else
|
||||
# define JS_THREADSAFE_ASSERT(expr) ((void) 0)
|
||||
# endif
|
||||
#else
|
||||
# define JS_THREADSAFE_ASSERT(expr) ((void) 0)
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG)
|
||||
# define JS_DIAGNOSTICS_ASSERT(expr) MOZ_ASSERT(expr)
|
||||
#elif defined(JS_CRASH_DIAGNOSTICS)
|
||||
|
@ -96,7 +87,7 @@ static JS_ALWAYS_INLINE void
|
|||
PrintBacktrace()
|
||||
{
|
||||
void* OOM_trace[JS_OOM_BACKTRACE_SIZE];
|
||||
char** OOM_traceSymbols = NULL;
|
||||
char** OOM_traceSymbols = nullptr;
|
||||
int32_t OOM_traceSize = 0;
|
||||
int32_t OOM_traceIdx = 0;
|
||||
OOM_traceSize = backtrace(OOM_trace, JS_OOM_BACKTRACE_SIZE);
|
||||
|
@ -126,7 +117,7 @@ PrintBacktrace()
|
|||
{ \
|
||||
if (++OOM_counter > OOM_maxAllocations) { \
|
||||
JS_OOM_EMIT_BACKTRACE();\
|
||||
return NULL; \
|
||||
return nullptr; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
@ -136,7 +127,7 @@ PrintBacktrace()
|
|||
if (++OOM_counter > OOM_maxAllocations) { \
|
||||
JS_OOM_EMIT_BACKTRACE();\
|
||||
js_ReportOutOfMemory(cx);\
|
||||
return NULL; \
|
||||
return nullptr; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
@ -145,31 +136,31 @@ PrintBacktrace()
|
|||
# define JS_OOM_POSSIBLY_FAIL_REPORT(cx) do {} while(0)
|
||||
# endif /* DEBUG */
|
||||
|
||||
static JS_INLINE void* js_malloc(size_t bytes)
|
||||
static inline void* js_malloc(size_t bytes)
|
||||
{
|
||||
JS_OOM_POSSIBLY_FAIL();
|
||||
return malloc(bytes);
|
||||
}
|
||||
|
||||
static JS_INLINE void* js_calloc(size_t bytes)
|
||||
static inline void* js_calloc(size_t bytes)
|
||||
{
|
||||
JS_OOM_POSSIBLY_FAIL();
|
||||
return calloc(bytes, 1);
|
||||
}
|
||||
|
||||
static JS_INLINE void* js_calloc(size_t nmemb, size_t size)
|
||||
static inline void* js_calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
JS_OOM_POSSIBLY_FAIL();
|
||||
return calloc(nmemb, size);
|
||||
}
|
||||
|
||||
static JS_INLINE void* js_realloc(void* p, size_t bytes)
|
||||
static inline void* js_realloc(void* p, size_t bytes)
|
||||
{
|
||||
JS_OOM_POSSIBLY_FAIL();
|
||||
return realloc(p, bytes);
|
||||
}
|
||||
|
||||
static JS_INLINE void js_free(void* p)
|
||||
static inline void js_free(void* p)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
@ -241,7 +232,7 @@ static JS_INLINE void js_free(void* p)
|
|||
|
||||
#define JS_NEW_BODY(allocator, t, parms) \
|
||||
void *memory = allocator(sizeof(t)); \
|
||||
return memory ? new(memory) t parms : NULL;
|
||||
return memory ? new(memory) t parms : nullptr;
|
||||
|
||||
/*
|
||||
* Given a class which should provide 'new' methods, add
|
||||
|
@ -360,7 +351,7 @@ static JS_ALWAYS_INLINE T *
|
|||
js_pod_malloc(size_t numElems)
|
||||
{
|
||||
if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
|
||||
return NULL;
|
||||
return nullptr;
|
||||
return (T *)js_malloc(numElems * sizeof(T));
|
||||
}
|
||||
|
||||
|
@ -369,7 +360,7 @@ static JS_ALWAYS_INLINE T *
|
|||
js_pod_calloc(size_t numElems)
|
||||
{
|
||||
if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
|
||||
return NULL;
|
||||
return nullptr;
|
||||
return (T *)js_calloc(numElems * sizeof(T));
|
||||
}
|
||||
|
||||
|
@ -379,7 +370,7 @@ template<typename T>
|
|||
struct ScopedFreePtrTraits
|
||||
{
|
||||
typedef T* type;
|
||||
static T* empty() { return NULL; }
|
||||
static T* empty() { return nullptr; }
|
||||
static void release(T* ptr) { js_free(ptr); }
|
||||
};
|
||||
SCOPED_TEMPLATE(ScopedJSFreePtr, ScopedFreePtrTraits)
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include <limits> /* for std::numeric_limits */
|
||||
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "js/Anchor.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/Utility.h"
|
||||
|
@ -248,7 +250,7 @@ typedef union jsval_layout
|
|||
union {
|
||||
int32_t i32;
|
||||
uint32_t u32;
|
||||
JSBool boo;
|
||||
uint32_t boo; // Don't use |bool| -- it must be four bytes.
|
||||
JSString *str;
|
||||
JSObject *obj;
|
||||
void *ptr;
|
||||
|
@ -295,7 +297,7 @@ typedef union jsval_layout
|
|||
union {
|
||||
int32_t i32;
|
||||
uint32_t u32;
|
||||
JSBool boo;
|
||||
uint32_t boo; // Don't use |bool| -- it must be four bytes.
|
||||
JSString *str;
|
||||
JSObject *obj;
|
||||
void *ptr;
|
||||
|
@ -333,6 +335,49 @@ typedef union jsval_layout
|
|||
|
||||
JS_STATIC_ASSERT(sizeof(jsval_layout) == 8);
|
||||
|
||||
/*
|
||||
* For codesize purposes on some platforms, it's important that the
|
||||
* compiler know that JS::Values constructed from constant values can be
|
||||
* folded to constant bit patterns at compile time, rather than
|
||||
* constructed at runtime. Doing this requires a fair amount of C++11
|
||||
* features, which are not supported on all of our compilers. Set up
|
||||
* some defines and helper macros in an attempt to confine the ugliness
|
||||
* here, rather than scattering it all about the file. The important
|
||||
* features are:
|
||||
*
|
||||
* - constexpr;
|
||||
* - defaulted functions;
|
||||
* - C99-style designated initializers.
|
||||
*/
|
||||
#if defined(__clang__)
|
||||
# if __has_feature(cxx_constexpr) && __has_feature(cxx_defaulted_functions)
|
||||
# define JS_VALUE_IS_CONSTEXPR
|
||||
# endif
|
||||
#elif defined(__GNUC__)
|
||||
/*
|
||||
* We need 4.5 for defaulted functions, 4.6 for constexpr, 4.7 because 4.6
|
||||
* doesn't understand |(X) { .field = ... }| syntax, and 4.7.3 because
|
||||
* versions prior to that have bugs in the C++ front-end that cause crashes.
|
||||
*/
|
||||
# if MOZ_GCC_VERSION_AT_LEAST(4, 7, 3)
|
||||
# define JS_VALUE_IS_CONSTEXPR
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(JS_VALUE_IS_CONSTEXPR)
|
||||
# define JS_RETURN_LAYOUT_FROM_BITS(BITS) \
|
||||
return (jsval_layout) { .asBits = (BITS) }
|
||||
# define JS_VALUE_CONSTEXPR MOZ_CONSTEXPR
|
||||
# define JS_VALUE_CONSTEXPR_VAR MOZ_CONSTEXPR_VAR
|
||||
#else
|
||||
# define JS_RETURN_LAYOUT_FROM_BITS(BITS) \
|
||||
jsval_layout l; \
|
||||
l.asBits = (BITS); \
|
||||
return l;
|
||||
# define JS_VALUE_CONSTEXPR
|
||||
# define JS_VALUE_CONSTEXPR_VAR const
|
||||
#endif
|
||||
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
|
||||
/*
|
||||
|
@ -341,15 +386,13 @@ JS_STATIC_ASSERT(sizeof(jsval_layout) == 8);
|
|||
* Thus, all comparisons should explicitly cast operands to uint32_t.
|
||||
*/
|
||||
|
||||
static inline jsval_layout
|
||||
static inline JS_VALUE_CONSTEXPR jsval_layout
|
||||
BUILD_JSVAL(JSValueTag tag, uint32_t payload)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.asBits = (((uint64_t)(uint32_t)tag) << 32) | payload;
|
||||
return l;
|
||||
JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << 32) | payload);
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_DOUBLE_IMPL(jsval_layout l)
|
||||
{
|
||||
return (uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_CLEAR;
|
||||
|
@ -364,7 +407,7 @@ DOUBLE_TO_JSVAL_IMPL(double d)
|
|||
return l;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_INT32_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.tag == JSVAL_TAG_INT32;
|
||||
|
@ -376,16 +419,20 @@ JSVAL_TO_INT32_IMPL(jsval_layout l)
|
|||
return l.s.payload.i32;
|
||||
}
|
||||
|
||||
static inline jsval_layout
|
||||
static inline JS_VALUE_CONSTEXPR jsval_layout
|
||||
INT32_TO_JSVAL_IMPL(int32_t i)
|
||||
{
|
||||
#if defined(JS_VALUE_IS_CONSTEXPR)
|
||||
return BUILD_JSVAL(JSVAL_TAG_INT32, i);
|
||||
#else
|
||||
jsval_layout l;
|
||||
l.s.tag = JSVAL_TAG_INT32;
|
||||
l.s.payload.i32 = i;
|
||||
return l;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_NUMBER_IMPL(jsval_layout l)
|
||||
{
|
||||
JSValueTag tag = l.s.tag;
|
||||
|
@ -393,13 +440,13 @@ JSVAL_IS_NUMBER_IMPL(jsval_layout l)
|
|||
return (uint32_t)tag <= (uint32_t)JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_UNDEFINED_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.tag == JSVAL_TAG_UNDEFINED;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_STRING_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.tag == JSVAL_TAG_STRING;
|
||||
|
@ -421,47 +468,46 @@ JSVAL_TO_STRING_IMPL(jsval_layout l)
|
|||
return l.s.payload.str;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_BOOLEAN_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.tag == JSVAL_TAG_BOOLEAN;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_TO_BOOLEAN_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.payload.boo;
|
||||
}
|
||||
|
||||
static inline jsval_layout
|
||||
BOOLEAN_TO_JSVAL_IMPL(JSBool b)
|
||||
BOOLEAN_TO_JSVAL_IMPL(bool b)
|
||||
{
|
||||
jsval_layout l;
|
||||
MOZ_ASSERT(b == JS_TRUE || b == JS_FALSE);
|
||||
l.s.tag = JSVAL_TAG_BOOLEAN;
|
||||
l.s.payload.boo = b;
|
||||
return l;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_MAGIC_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.tag == JSVAL_TAG_MAGIC;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_OBJECT_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.tag == JSVAL_TAG_OBJECT;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l)
|
||||
{
|
||||
return (uint32_t)l.s.tag < (uint32_t)JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l)
|
||||
{
|
||||
MOZ_ASSERT((uint32_t)l.s.tag <= (uint32_t)JSVAL_TAG_OBJECT);
|
||||
|
@ -484,7 +530,7 @@ OBJECT_TO_JSVAL_IMPL(JSObject *obj)
|
|||
return l;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_NULL_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.tag == JSVAL_TAG_NULL;
|
||||
|
@ -507,7 +553,7 @@ JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l)
|
|||
return l.s.payload.ptr;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_GCTHING_IMPL(jsval_layout l)
|
||||
{
|
||||
/* gcc sometimes generates signed < without explicit casts. */
|
||||
|
@ -520,7 +566,7 @@ JSVAL_TO_GCTHING_IMPL(jsval_layout l)
|
|||
return l.s.payload.ptr;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_TRACEABLE_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.s.tag == JSVAL_TAG_STRING || l.s.tag == JSVAL_TAG_OBJECT;
|
||||
|
@ -529,19 +575,19 @@ JSVAL_IS_TRACEABLE_IMPL(jsval_layout l)
|
|||
static inline uint32_t
|
||||
JSVAL_TRACE_KIND_IMPL(jsval_layout l)
|
||||
{
|
||||
return (uint32_t)(JSBool)JSVAL_IS_STRING_IMPL(l);
|
||||
return (uint32_t)(bool)JSVAL_IS_STRING_IMPL(l);
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32)
|
||||
{
|
||||
return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b)
|
||||
static inline bool
|
||||
JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, bool b)
|
||||
{
|
||||
return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == b);
|
||||
return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == uint32_t(b));
|
||||
}
|
||||
|
||||
static inline jsval_layout
|
||||
|
@ -553,7 +599,7 @@ MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
|
|||
return l;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs)
|
||||
{
|
||||
JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag;
|
||||
|
@ -570,15 +616,13 @@ JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l)
|
|||
|
||||
#elif JS_BITS_PER_WORD == 64
|
||||
|
||||
static inline jsval_layout
|
||||
static inline JS_VALUE_CONSTEXPR jsval_layout
|
||||
BUILD_JSVAL(JSValueTag tag, uint64_t payload)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.asBits = (((uint64_t)(uint32_t)tag) << JSVAL_TAG_SHIFT) | payload;
|
||||
return l;
|
||||
JS_RETURN_LAYOUT_FROM_BITS((((uint64_t)(uint32_t)tag) << JSVAL_TAG_SHIFT) | payload);
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_DOUBLE_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
|
||||
|
@ -593,7 +637,7 @@ DOUBLE_TO_JSVAL_IMPL(double d)
|
|||
return l;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_INT32_IMPL(jsval_layout l)
|
||||
{
|
||||
return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_INT32;
|
||||
|
@ -605,27 +649,25 @@ JSVAL_TO_INT32_IMPL(jsval_layout l)
|
|||
return (int32_t)l.asBits;
|
||||
}
|
||||
|
||||
static inline jsval_layout
|
||||
static inline JS_VALUE_CONSTEXPR jsval_layout
|
||||
INT32_TO_JSVAL_IMPL(int32_t i32)
|
||||
{
|
||||
jsval_layout l;
|
||||
l.asBits = ((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32;
|
||||
return l;
|
||||
JS_RETURN_LAYOUT_FROM_BITS(((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32);
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_NUMBER_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_UNDEFINED_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.asBits == JSVAL_SHIFTED_TAG_UNDEFINED;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_STRING_IMPL(jsval_layout l)
|
||||
{
|
||||
return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING;
|
||||
|
@ -648,47 +690,46 @@ JSVAL_TO_STRING_IMPL(jsval_layout l)
|
|||
return (JSString *)(l.asBits & JSVAL_PAYLOAD_MASK);
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_BOOLEAN_IMPL(jsval_layout l)
|
||||
{
|
||||
return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_BOOLEAN;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_TO_BOOLEAN_IMPL(jsval_layout l)
|
||||
{
|
||||
return (JSBool)l.asBits;
|
||||
return (bool)(l.asBits & JSVAL_PAYLOAD_MASK);
|
||||
}
|
||||
|
||||
static inline jsval_layout
|
||||
BOOLEAN_TO_JSVAL_IMPL(JSBool b)
|
||||
BOOLEAN_TO_JSVAL_IMPL(bool b)
|
||||
{
|
||||
jsval_layout l;
|
||||
MOZ_ASSERT(b == JS_TRUE || b == JS_FALSE);
|
||||
l.asBits = ((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN;
|
||||
return l;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_MAGIC_IMPL(jsval_layout l)
|
||||
{
|
||||
return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_OBJECT_IMPL(jsval_layout l)
|
||||
{
|
||||
MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_SHIFTED_TAG_OBJECT);
|
||||
return l.asBits >= JSVAL_SHIFTED_TAG_OBJECT;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l)
|
||||
{
|
||||
MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
|
||||
|
@ -714,13 +755,13 @@ OBJECT_TO_JSVAL_IMPL(JSObject *obj)
|
|||
return l;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_NULL_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.asBits == JSVAL_SHIFTED_TAG_NULL;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_GCTHING_IMPL(jsval_layout l)
|
||||
{
|
||||
return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET;
|
||||
|
@ -734,7 +775,7 @@ JSVAL_TO_GCTHING_IMPL(jsval_layout l)
|
|||
return (void *)ptrBits;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_TRACEABLE_IMPL(jsval_layout l)
|
||||
{
|
||||
return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l);
|
||||
|
@ -743,7 +784,7 @@ JSVAL_IS_TRACEABLE_IMPL(jsval_layout l)
|
|||
static inline uint32_t
|
||||
JSVAL_TRACE_KIND_IMPL(jsval_layout l)
|
||||
{
|
||||
return (uint32_t)(JSBool)!(JSVAL_IS_OBJECT_IMPL(l));
|
||||
return (uint32_t)(bool)!(JSVAL_IS_OBJECT_IMPL(l));
|
||||
}
|
||||
|
||||
static inline jsval_layout
|
||||
|
@ -764,14 +805,14 @@ JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l)
|
|||
return (void *)(l.asBits << 1);
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32)
|
||||
{
|
||||
return l.asBits == (((uint64_t)(uint32_t)i32) | JSVAL_SHIFTED_TAG_INT32);
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b)
|
||||
static inline bool
|
||||
JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, bool b)
|
||||
{
|
||||
return l.asBits == (((uint64_t)(uint32_t)b) | JSVAL_SHIFTED_TAG_BOOLEAN);
|
||||
}
|
||||
|
@ -784,7 +825,7 @@ MAGIC_TO_JSVAL_IMPL(JSWhyMagic why)
|
|||
return l;
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs)
|
||||
{
|
||||
uint64_t lbits = lhs.asBits, rbits = rhs.asBits;
|
||||
|
@ -803,10 +844,12 @@ JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l)
|
|||
#endif /* JS_BITS_PER_WORD */
|
||||
|
||||
static inline jsval_layout JSVAL_TO_IMPL(JS::Value v);
|
||||
static inline JS::Value IMPL_TO_JSVAL(jsval_layout l);
|
||||
static inline JS_VALUE_CONSTEXPR JS::Value IMPL_TO_JSVAL(jsval_layout l);
|
||||
|
||||
namespace JS {
|
||||
|
||||
static inline JS_VALUE_CONSTEXPR JS::Value UndefinedValue();
|
||||
|
||||
/**
|
||||
* Returns a generic quiet NaN value, with all payload bits set to zero.
|
||||
*
|
||||
|
@ -816,7 +859,7 @@ namespace JS {
|
|||
static MOZ_ALWAYS_INLINE double
|
||||
GenericNaN()
|
||||
{
|
||||
return mozilla::SpecificNaN(0, 0x8000000000000ULL);
|
||||
return mozilla::SpecificNaN(0, 0x8000000000000ULL);
|
||||
}
|
||||
|
||||
static inline double
|
||||
|
@ -869,6 +912,10 @@ class Value
|
|||
* N.B. the default constructor leaves Value unitialized. Adding a default
|
||||
* constructor prevents Value from being stored in a union.
|
||||
*/
|
||||
#if defined(JS_VALUE_IS_CONSTEXPR)
|
||||
Value() = default;
|
||||
Value(const Value& v) = default;
|
||||
#endif
|
||||
|
||||
/*** Mutators ***/
|
||||
|
||||
|
@ -893,6 +940,10 @@ class Value
|
|||
data = DOUBLE_TO_JSVAL_IMPL(d);
|
||||
}
|
||||
|
||||
void setNaN() {
|
||||
setDouble(GenericNaN());
|
||||
}
|
||||
|
||||
double &getDoubleRef() {
|
||||
MOZ_ASSERT(isDouble());
|
||||
return data.asDouble;
|
||||
|
@ -1173,16 +1224,20 @@ class Value
|
|||
jsval_layout data;
|
||||
|
||||
private:
|
||||
#if defined(JS_VALUE_IS_CONSTEXPR)
|
||||
JS_VALUE_CONSTEXPR Value(jsval_layout layout) : data(layout) {}
|
||||
#endif
|
||||
|
||||
void staticAssertions() {
|
||||
JS_STATIC_ASSERT(sizeof(JSValueType) == 1);
|
||||
JS_STATIC_ASSERT(sizeof(JSValueTag) == 4);
|
||||
JS_STATIC_ASSERT(sizeof(JSBool) == 4);
|
||||
JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4);
|
||||
JS_STATIC_ASSERT(sizeof(Value) == 8);
|
||||
}
|
||||
|
||||
friend jsval_layout (::JSVAL_TO_IMPL)(Value);
|
||||
friend Value (::IMPL_TO_JSVAL)(jsval_layout l);
|
||||
friend Value JS_VALUE_CONSTEXPR (::IMPL_TO_JSVAL)(jsval_layout l);
|
||||
friend Value JS_VALUE_CONSTEXPR (JS::UndefinedValue)();
|
||||
};
|
||||
|
||||
inline bool
|
||||
|
@ -1205,12 +1260,16 @@ NullValue()
|
|||
return v;
|
||||
}
|
||||
|
||||
static inline Value
|
||||
static inline JS_VALUE_CONSTEXPR Value
|
||||
UndefinedValue()
|
||||
{
|
||||
Value v;
|
||||
#if defined(JS_VALUE_IS_CONSTEXPR)
|
||||
return Value(BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0));
|
||||
#else
|
||||
JS::Value v;
|
||||
v.setUndefined();
|
||||
return v;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline Value
|
||||
|
@ -1229,6 +1288,22 @@ DoubleValue(double dbl)
|
|||
return v;
|
||||
}
|
||||
|
||||
static inline Value
|
||||
DoubleNaNValue()
|
||||
{
|
||||
Value v;
|
||||
v.setNaN();
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline Value
|
||||
Float32Value(float f)
|
||||
{
|
||||
Value v;
|
||||
v.setDouble(f);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline Value
|
||||
StringValue(JSString *str)
|
||||
{
|
||||
|
@ -1499,6 +1574,7 @@ class UnbarrieredMutableValueOperations : public ValueOperations<Outer>
|
|||
void setUndefined() { value()->setUndefined(); }
|
||||
void setInt32(int32_t i) { value()->setInt32(i); }
|
||||
void setDouble(double d) { value()->setDouble(d); }
|
||||
void setNaN() { setDouble(JS::GenericNaN()); }
|
||||
void setBoolean(bool b) { value()->setBoolean(b); }
|
||||
void setMagic(JSWhyMagic why) { value()->setMagic(why); }
|
||||
bool setNumber(uint32_t ui) { return value()->setNumber(ui); }
|
||||
|
@ -1620,12 +1696,16 @@ JSVAL_TO_IMPL(JS::Value v)
|
|||
return v.data;
|
||||
}
|
||||
|
||||
inline JS::Value
|
||||
inline JS_VALUE_CONSTEXPR JS::Value
|
||||
IMPL_TO_JSVAL(jsval_layout l)
|
||||
{
|
||||
#if defined(JS_VALUE_IS_CONSTEXPR)
|
||||
return JS::Value(l);
|
||||
#else
|
||||
JS::Value v;
|
||||
v.data = l;
|
||||
return v;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace JS {
|
||||
|
@ -1678,19 +1758,19 @@ static_assert(sizeof(jsval_layout) == sizeof(JS::Value),
|
|||
|
||||
/************************************************************************/
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_NULL(jsval v)
|
||||
{
|
||||
return JSVAL_IS_NULL_IMPL(JSVAL_TO_IMPL(v));
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_VOID(jsval v)
|
||||
{
|
||||
return JSVAL_IS_UNDEFINED_IMPL(JSVAL_TO_IMPL(v));
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_INT(jsval v)
|
||||
{
|
||||
return JSVAL_IS_INT32_IMPL(JSVAL_TO_IMPL(v));
|
||||
|
@ -1703,13 +1783,13 @@ JSVAL_TO_INT(jsval v)
|
|||
return JSVAL_TO_INT32_IMPL(JSVAL_TO_IMPL(v));
|
||||
}
|
||||
|
||||
static inline jsval
|
||||
static inline JS_VALUE_CONSTEXPR jsval
|
||||
INT_TO_JSVAL(int32_t i)
|
||||
{
|
||||
return IMPL_TO_JSVAL(INT32_TO_JSVAL_IMPL(i));
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_DOUBLE(jsval v)
|
||||
{
|
||||
return JSVAL_IS_DOUBLE_IMPL(JSVAL_TO_IMPL(v));
|
||||
|
@ -1724,7 +1804,7 @@ JSVAL_TO_DOUBLE(jsval v)
|
|||
return l.asDouble;
|
||||
}
|
||||
|
||||
static inline jsval
|
||||
static inline JS_VALUE_CONSTEXPR jsval
|
||||
DOUBLE_TO_JSVAL(double d)
|
||||
{
|
||||
/*
|
||||
|
@ -1733,29 +1813,35 @@ DOUBLE_TO_JSVAL(double d)
|
|||
* return IMPL_TO_JSVAL(DOUBLE_TO_JSVAL_IMPL(d));
|
||||
* because GCC from XCode 3.1.4 miscompiles the above code.
|
||||
*/
|
||||
#if defined(JS_VALUE_IS_CONSTEXPR)
|
||||
return IMPL_TO_JSVAL(MOZ_UNLIKELY(d != d)
|
||||
? (jsval_layout) { .asBits = 0x7FF8000000000000LL }
|
||||
: (jsval_layout) { .asDouble = d });
|
||||
#else
|
||||
jsval_layout l;
|
||||
if (MOZ_UNLIKELY(d != d))
|
||||
l.asBits = 0x7FF8000000000000LL;
|
||||
else
|
||||
l.asDouble = d;
|
||||
return IMPL_TO_JSVAL(l);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline jsval
|
||||
static inline JS_VALUE_CONSTEXPR jsval
|
||||
UINT_TO_JSVAL(uint32_t i)
|
||||
{
|
||||
if (i <= JSVAL_INT_MAX)
|
||||
return INT_TO_JSVAL((int32_t)i);
|
||||
return DOUBLE_TO_JSVAL((double)i);
|
||||
return (i <= JSVAL_INT_MAX
|
||||
? INT_TO_JSVAL((int32_t)i)
|
||||
: DOUBLE_TO_JSVAL((double)i));
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_NUMBER(jsval v)
|
||||
{
|
||||
return JSVAL_IS_NUMBER_IMPL(JSVAL_TO_IMPL(v));
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_STRING(jsval v)
|
||||
{
|
||||
return JSVAL_IS_STRING_IMPL(JSVAL_TO_IMPL(v));
|
||||
|
@ -1789,13 +1875,13 @@ OBJECT_TO_JSVAL(JSObject *obj)
|
|||
return IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_NULL, 0));
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_BOOLEAN(jsval v)
|
||||
{
|
||||
return JSVAL_IS_BOOLEAN_IMPL(JSVAL_TO_IMPL(v));
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_TO_BOOLEAN(jsval v)
|
||||
{
|
||||
MOZ_ASSERT(JSVAL_IS_BOOLEAN(v));
|
||||
|
@ -1803,18 +1889,18 @@ JSVAL_TO_BOOLEAN(jsval v)
|
|||
}
|
||||
|
||||
static inline jsval
|
||||
BOOLEAN_TO_JSVAL(JSBool b)
|
||||
BOOLEAN_TO_JSVAL(bool b)
|
||||
{
|
||||
return IMPL_TO_JSVAL(BOOLEAN_TO_JSVAL_IMPL(b));
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_PRIMITIVE(jsval v)
|
||||
{
|
||||
return JSVAL_IS_PRIMITIVE_IMPL(JSVAL_TO_IMPL(v));
|
||||
}
|
||||
|
||||
static inline JSBool
|
||||
static inline bool
|
||||
JSVAL_IS_GCTHING(jsval v)
|
||||
{
|
||||
return JSVAL_IS_GCTHING_IMPL(JSVAL_TO_IMPL(v));
|
||||
|
@ -1842,4 +1928,25 @@ JSVAL_TO_PRIVATE(jsval v)
|
|||
return JSVAL_TO_PRIVATE_PTR_IMPL(JSVAL_TO_IMPL(v));
|
||||
}
|
||||
|
||||
// JS constants. For efficiency, prefer predicates (e.g. v.isNull()) and
|
||||
// constructing values from scratch (e.g. Int32Value(0)). These constants are
|
||||
// stored in memory and initialized at startup, so testing against them and
|
||||
// using them requires memory loads and will be correspondingly slow.
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_NULL;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_ZERO;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_ONE;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_FALSE;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_TRUE;
|
||||
extern JS_PUBLIC_DATA(const jsval) JSVAL_VOID;
|
||||
|
||||
namespace JS {
|
||||
|
||||
extern JS_PUBLIC_DATA(const Handle<Value>) NullHandleValue;
|
||||
extern JS_PUBLIC_DATA(const Handle<Value>) UndefinedHandleValue;
|
||||
|
||||
}
|
||||
|
||||
#undef JS_VALUE_IS_CONSTEXPR
|
||||
#undef JS_RETURN_LAYOUT_FROM_BITS
|
||||
|
||||
#endif /* js_Value_h */
|
||||
|
|
|
@ -9,12 +9,9 @@
|
|||
#ifndef jsalloc_h
|
||||
#define jsalloc_h
|
||||
|
||||
#include "mozilla/AllocPolicy.h"
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Utility.h"
|
||||
|
||||
struct JSContext;
|
||||
|
||||
namespace js {
|
||||
|
||||
class ContextFriendFields;
|
||||
|
@ -56,14 +53,14 @@ class TempAllocPolicy
|
|||
void *malloc_(size_t bytes) {
|
||||
void *p = js_malloc(bytes);
|
||||
if (JS_UNLIKELY(!p))
|
||||
p = onOutOfMemory(NULL, bytes);
|
||||
p = onOutOfMemory(nullptr, bytes);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *calloc_(size_t bytes) {
|
||||
void *p = js_calloc(bytes);
|
||||
if (JS_UNLIKELY(!p))
|
||||
p = onOutOfMemory(NULL, bytes);
|
||||
p = onOutOfMemory(nullptr, bytes);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
e14ea931f699b1808c06886e55e977c9819f3774
|
||||
38fc2004d49d7c513aff0f7f43d79524ec667c2c
|
|
@ -0,0 +1,14 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jsbytecode_h
|
||||
#define jsbytecode_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t jsbytecode;
|
||||
|
||||
#endif /* jsbytecode_h */
|
|
@ -1,405 +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 jsclass_h
|
||||
#define jsclass_h
|
||||
/*
|
||||
* A JSClass acts as a vtable for JS objects that allows JSAPI clients to
|
||||
* control various aspects of the behavior of an object like property lookup.
|
||||
* js::Class is an engine-private extension that allows more control over
|
||||
* object behavior and, e.g., allows custom slow layout.
|
||||
*/
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsprvtd.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
class PropertyName;
|
||||
class SpecialId;
|
||||
class PropertyId;
|
||||
|
||||
// This is equal to JSFunction::class_. Use it in places where you don't want
|
||||
// to #include jsfun.h.
|
||||
extern JS_FRIEND_DATA(js::Class* const) FunctionClassPtr;
|
||||
|
||||
static JS_ALWAYS_INLINE jsid
|
||||
SPECIALID_TO_JSID(const SpecialId &sid);
|
||||
|
||||
/*
|
||||
* We partition the ways to refer to a property into three: by an index
|
||||
* (uint32_t); by a string whose characters do not represent an index
|
||||
* (PropertyName, see vm/String.h); and by various special values.
|
||||
*
|
||||
* Special values are encoded using SpecialId, which is layout-compatible but
|
||||
* non-interconvertible with jsid. A SpecialId is used for JSID_VOID, which
|
||||
* does not occur in JS scripts but may be used to indicate the absence of a
|
||||
* valid identifier. In the future, a SpecialId may also be an object used by
|
||||
* Harmony-proposed private names.
|
||||
*/
|
||||
class SpecialId
|
||||
{
|
||||
uintptr_t bits_;
|
||||
|
||||
/* Needs access to raw bits. */
|
||||
friend JS_ALWAYS_INLINE jsid SPECIALID_TO_JSID(const SpecialId &sid);
|
||||
friend class PropertyId;
|
||||
|
||||
static const uintptr_t TYPE_VOID = JSID_TYPE_VOID;
|
||||
static const uintptr_t TYPE_OBJECT = JSID_TYPE_OBJECT;
|
||||
static const uintptr_t TYPE_MASK = JSID_TYPE_MASK;
|
||||
|
||||
SpecialId(uintptr_t bits) : bits_(bits) { }
|
||||
|
||||
public:
|
||||
SpecialId() : bits_(TYPE_VOID) { }
|
||||
|
||||
/* Object-valued */
|
||||
|
||||
SpecialId(JSObject &obj)
|
||||
: bits_(uintptr_t(&obj) | TYPE_OBJECT)
|
||||
{
|
||||
JS_ASSERT(&obj != NULL);
|
||||
JS_ASSERT((uintptr_t(&obj) & TYPE_MASK) == 0);
|
||||
}
|
||||
|
||||
bool isObject() const {
|
||||
return (bits_ & TYPE_MASK) == TYPE_OBJECT && bits_ != TYPE_OBJECT;
|
||||
}
|
||||
|
||||
JSObject *toObject() const {
|
||||
JS_ASSERT(isObject());
|
||||
return reinterpret_cast<JSObject *>(bits_ & ~TYPE_MASK);
|
||||
}
|
||||
|
||||
/* Empty */
|
||||
|
||||
static SpecialId empty() {
|
||||
SpecialId sid(TYPE_OBJECT);
|
||||
JS_ASSERT(sid.isEmpty());
|
||||
return sid;
|
||||
}
|
||||
|
||||
bool isEmpty() const {
|
||||
return bits_ == TYPE_OBJECT;
|
||||
}
|
||||
|
||||
/* Void */
|
||||
|
||||
static SpecialId voidId() {
|
||||
SpecialId sid(TYPE_VOID);
|
||||
JS_ASSERT(sid.isVoid());
|
||||
return sid;
|
||||
}
|
||||
|
||||
bool isVoid() const {
|
||||
return bits_ == TYPE_VOID;
|
||||
}
|
||||
};
|
||||
|
||||
static JS_ALWAYS_INLINE jsid
|
||||
SPECIALID_TO_JSID(const SpecialId &sid)
|
||||
{
|
||||
jsid id;
|
||||
JSID_BITS(id) = sid.bits_;
|
||||
JS_ASSERT_IF(sid.isObject(), JSID_IS_OBJECT(id) && JSID_TO_OBJECT(id) == sid.toObject());
|
||||
JS_ASSERT_IF(sid.isVoid(), JSID_IS_VOID(id));
|
||||
JS_ASSERT_IF(sid.isEmpty(), JSID_IS_EMPTY(id));
|
||||
return id;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE bool
|
||||
JSID_IS_SPECIAL(jsid id)
|
||||
{
|
||||
return JSID_IS_OBJECT(id) || JSID_IS_EMPTY(id) || JSID_IS_VOID(id);
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE SpecialId
|
||||
JSID_TO_SPECIALID(jsid id)
|
||||
{
|
||||
JS_ASSERT(JSID_IS_SPECIAL(id));
|
||||
if (JSID_IS_OBJECT(id))
|
||||
return SpecialId(*JSID_TO_OBJECT(id));
|
||||
if (JSID_IS_EMPTY(id))
|
||||
return SpecialId::empty();
|
||||
JS_ASSERT(JSID_IS_VOID(id));
|
||||
return SpecialId::voidId();
|
||||
}
|
||||
|
||||
typedef JS::Handle<SpecialId> HandleSpecialId;
|
||||
|
||||
/* js::Class operation signatures. */
|
||||
|
||||
typedef JSBool
|
||||
(* LookupGenericOp)(JSContext *cx, HandleObject obj, HandleId id,
|
||||
MutableHandleObject objp, MutableHandleShape propp);
|
||||
typedef JSBool
|
||||
(* LookupPropOp)(JSContext *cx, HandleObject obj, HandlePropertyName name,
|
||||
MutableHandleObject objp, MutableHandleShape propp);
|
||||
typedef JSBool
|
||||
(* LookupElementOp)(JSContext *cx, HandleObject obj, uint32_t index,
|
||||
MutableHandleObject objp, MutableHandleShape propp);
|
||||
typedef JSBool
|
||||
(* LookupSpecialOp)(JSContext *cx, HandleObject obj, HandleSpecialId sid,
|
||||
MutableHandleObject objp, MutableHandleShape propp);
|
||||
typedef JSBool
|
||||
(* DefineGenericOp)(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
|
||||
PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
|
||||
typedef JSBool
|
||||
(* DefinePropOp)(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
|
||||
PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
|
||||
typedef JSBool
|
||||
(* DefineElementOp)(JSContext *cx, HandleObject obj, uint32_t index, HandleValue value,
|
||||
PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
|
||||
typedef JSBool
|
||||
(* DefineSpecialOp)(JSContext *cx, HandleObject obj, HandleSpecialId sid, HandleValue value,
|
||||
PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
|
||||
typedef JSBool
|
||||
(* GenericIdOp)(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id, MutableHandleValue vp);
|
||||
typedef JSBool
|
||||
(* PropertyIdOp)(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name, MutableHandleValue vp);
|
||||
typedef JSBool
|
||||
(* ElementIdOp)(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, MutableHandleValue vp);
|
||||
typedef JSBool
|
||||
(* ElementIfPresentOp)(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, MutableHandleValue vp, bool* present);
|
||||
typedef JSBool
|
||||
(* SpecialIdOp)(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid, MutableHandleValue vp);
|
||||
typedef JSBool
|
||||
(* StrictGenericIdOp)(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp, JSBool strict);
|
||||
typedef JSBool
|
||||
(* StrictPropertyIdOp)(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleValue vp, JSBool strict);
|
||||
typedef JSBool
|
||||
(* StrictElementIdOp)(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp, JSBool strict);
|
||||
typedef JSBool
|
||||
(* StrictSpecialIdOp)(JSContext *cx, HandleObject obj, HandleSpecialId sid, MutableHandleValue vp, JSBool strict);
|
||||
typedef JSBool
|
||||
(* GenericAttributesOp)(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp);
|
||||
typedef JSBool
|
||||
(* PropertyAttributesOp)(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp);
|
||||
typedef JSBool
|
||||
(* ElementAttributesOp)(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp);
|
||||
typedef JSBool
|
||||
(* SpecialAttributesOp)(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp);
|
||||
typedef JSBool
|
||||
(* DeletePropertyOp)(JSContext *cx, HandleObject obj, HandlePropertyName name, JSBool *succeeded);
|
||||
typedef JSBool
|
||||
(* DeleteElementOp)(JSContext *cx, HandleObject obj, uint32_t index, JSBool *succeeded);
|
||||
typedef JSBool
|
||||
(* DeleteSpecialOp)(JSContext *cx, HandleObject obj, HandleSpecialId sid, JSBool *succeeded);
|
||||
|
||||
|
||||
typedef JSObject *
|
||||
(* ObjectOp)(JSContext *cx, HandleObject obj);
|
||||
typedef void
|
||||
(* FinalizeOp)(FreeOp *fop, JSObject *obj);
|
||||
|
||||
#define JS_CLASS_MEMBERS \
|
||||
const char *name; \
|
||||
uint32_t flags; \
|
||||
\
|
||||
/* Mandatory function pointer members. */ \
|
||||
JSPropertyOp addProperty; \
|
||||
JSDeletePropertyOp delProperty; \
|
||||
JSPropertyOp getProperty; \
|
||||
JSStrictPropertyOp setProperty; \
|
||||
JSEnumerateOp enumerate; \
|
||||
JSResolveOp resolve; \
|
||||
JSConvertOp convert; \
|
||||
\
|
||||
/* Optional members (may be null). */ \
|
||||
FinalizeOp finalize; \
|
||||
JSCheckAccessOp checkAccess; \
|
||||
JSNative call; \
|
||||
JSHasInstanceOp hasInstance; \
|
||||
JSNative construct; \
|
||||
JSTraceOp trace
|
||||
|
||||
/*
|
||||
* The helper struct to measure the size of JS_CLASS_MEMBERS to know how much
|
||||
* we have to pad js::Class to match the size of JSClass.
|
||||
*/
|
||||
struct ClassSizeMeasurement
|
||||
{
|
||||
JS_CLASS_MEMBERS;
|
||||
};
|
||||
|
||||
struct ClassExtension
|
||||
{
|
||||
JSObjectOp outerObject;
|
||||
JSObjectOp innerObject;
|
||||
JSIteratorOp iteratorObject;
|
||||
|
||||
/*
|
||||
* isWrappedNative is true only if the class is an XPCWrappedNative.
|
||||
* WeakMaps use this to override the wrapper disposal optimization.
|
||||
*/
|
||||
bool isWrappedNative;
|
||||
|
||||
/*
|
||||
* If an object is used as a key in a weakmap, it may be desirable for the
|
||||
* garbage collector to keep that object around longer than it otherwise
|
||||
* would. A common case is when the key is a wrapper around an object in
|
||||
* another compartment, and we want to avoid collecting the wrapper (and
|
||||
* removing the weakmap entry) as long as the wrapped object is alive. In
|
||||
* that case, the wrapped object is returned by the wrapper's
|
||||
* weakmapKeyDelegateOp hook. As long as the wrapper is used as a weakmap
|
||||
* key, it will not be collected (and remain in the weakmap) until the
|
||||
* wrapped object is collected.
|
||||
*/
|
||||
JSWeakmapKeyDelegateOp weakmapKeyDelegateOp;
|
||||
};
|
||||
|
||||
#define JS_NULL_CLASS_EXT {NULL,NULL,NULL,false,NULL}
|
||||
|
||||
struct ObjectOps
|
||||
{
|
||||
LookupGenericOp lookupGeneric;
|
||||
LookupPropOp lookupProperty;
|
||||
LookupElementOp lookupElement;
|
||||
LookupSpecialOp lookupSpecial;
|
||||
DefineGenericOp defineGeneric;
|
||||
DefinePropOp defineProperty;
|
||||
DefineElementOp defineElement;
|
||||
DefineSpecialOp defineSpecial;
|
||||
GenericIdOp getGeneric;
|
||||
PropertyIdOp getProperty;
|
||||
ElementIdOp getElement;
|
||||
ElementIfPresentOp getElementIfPresent; /* can be null */
|
||||
SpecialIdOp getSpecial;
|
||||
StrictGenericIdOp setGeneric;
|
||||
StrictPropertyIdOp setProperty;
|
||||
StrictElementIdOp setElement;
|
||||
StrictSpecialIdOp setSpecial;
|
||||
GenericAttributesOp getGenericAttributes;
|
||||
PropertyAttributesOp getPropertyAttributes;
|
||||
ElementAttributesOp getElementAttributes;
|
||||
SpecialAttributesOp getSpecialAttributes;
|
||||
GenericAttributesOp setGenericAttributes;
|
||||
PropertyAttributesOp setPropertyAttributes;
|
||||
ElementAttributesOp setElementAttributes;
|
||||
SpecialAttributesOp setSpecialAttributes;
|
||||
DeletePropertyOp deleteProperty;
|
||||
DeleteElementOp deleteElement;
|
||||
DeleteSpecialOp deleteSpecial;
|
||||
|
||||
JSNewEnumerateOp enumerate;
|
||||
ObjectOp thisObject;
|
||||
};
|
||||
|
||||
#define JS_NULL_OBJECT_OPS \
|
||||
{NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, \
|
||||
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, \
|
||||
NULL,NULL,NULL}
|
||||
|
||||
struct Class
|
||||
{
|
||||
JS_CLASS_MEMBERS;
|
||||
ClassExtension ext;
|
||||
ObjectOps ops;
|
||||
uint8_t pad[sizeof(JSClass) - sizeof(ClassSizeMeasurement) -
|
||||
sizeof(ClassExtension) - sizeof(ObjectOps)];
|
||||
|
||||
/* Class is not native and its map is not a scope. */
|
||||
static const uint32_t NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
|
||||
|
||||
bool isNative() const {
|
||||
return !(flags & NON_NATIVE);
|
||||
}
|
||||
|
||||
bool hasPrivate() const {
|
||||
return !!(flags & JSCLASS_HAS_PRIVATE);
|
||||
}
|
||||
|
||||
bool emulatesUndefined() const {
|
||||
return flags & JSCLASS_EMULATES_UNDEFINED;
|
||||
}
|
||||
|
||||
bool isCallable() const {
|
||||
return this == js::FunctionClassPtr || call;
|
||||
}
|
||||
|
||||
static size_t offsetOfFlags() { return offsetof(Class, flags); }
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, name) == offsetof(Class, name));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, flags) == offsetof(Class, flags));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, addProperty) == offsetof(Class, addProperty));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, delProperty) == offsetof(Class, delProperty));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, getProperty) == offsetof(Class, getProperty));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, setProperty) == offsetof(Class, setProperty));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, enumerate) == offsetof(Class, enumerate));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, resolve) == offsetof(Class, resolve));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, convert) == offsetof(Class, convert));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, finalize) == offsetof(Class, finalize));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, checkAccess) == offsetof(Class, checkAccess));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, call) == offsetof(Class, call));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, construct) == offsetof(Class, construct));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, hasInstance) == offsetof(Class, hasInstance));
|
||||
JS_STATIC_ASSERT(offsetof(JSClass, trace) == offsetof(Class, trace));
|
||||
JS_STATIC_ASSERT(sizeof(JSClass) == sizeof(Class));
|
||||
|
||||
static JS_ALWAYS_INLINE JSClass *
|
||||
Jsvalify(Class *c)
|
||||
{
|
||||
return (JSClass *)c;
|
||||
}
|
||||
static JS_ALWAYS_INLINE const JSClass *
|
||||
Jsvalify(const Class *c)
|
||||
{
|
||||
return (const JSClass *)c;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE Class *
|
||||
Valueify(JSClass *c)
|
||||
{
|
||||
return (Class *)c;
|
||||
}
|
||||
static JS_ALWAYS_INLINE const Class *
|
||||
Valueify(const JSClass *c)
|
||||
{
|
||||
return (const Class *)c;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enumeration describing possible values of the [[Class]] internal property
|
||||
* value of objects.
|
||||
*/
|
||||
enum ESClassValue {
|
||||
ESClass_Array, ESClass_Number, ESClass_String, ESClass_Boolean,
|
||||
ESClass_RegExp, ESClass_ArrayBuffer, ESClass_Date
|
||||
};
|
||||
|
||||
/*
|
||||
* Return whether the given object has the given [[Class]] internal property
|
||||
* value. Beware, this query says nothing about the js::Class of the JSObject
|
||||
* so the caller must not assume anything about obj's representation (e.g., obj
|
||||
* may be a proxy).
|
||||
*/
|
||||
inline bool
|
||||
ObjectClassIs(JSObject &obj, ESClassValue classValue, JSContext *cx);
|
||||
|
||||
/* Just a helper that checks v.isObject before calling ObjectClassIs. */
|
||||
inline bool
|
||||
IsObjectWithClass(const Value &v, ESClassValue classValue, JSContext *cx);
|
||||
|
||||
inline bool
|
||||
IsPoisonedSpecialId(js::SpecialId iden)
|
||||
{
|
||||
if (iden.isObject())
|
||||
return IsPoisonedPtr(iden.toObject());
|
||||
return false;
|
||||
}
|
||||
|
||||
template <> struct GCMethods<SpecialId>
|
||||
{
|
||||
static SpecialId initial() { return SpecialId(); }
|
||||
static ThingRootKind kind() { return THING_ROOT_ID; }
|
||||
static bool poisoned(SpecialId id) { return IsPoisonedSpecialId(id); }
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsclass_h */
|
|
@ -14,8 +14,6 @@
|
|||
# if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)
|
||||
# define IS_LITTLE_ENDIAN 1
|
||||
# undef IS_BIG_ENDIAN
|
||||
# define JS_BYTES_PER_WORD 8
|
||||
# define JS_BITS_PER_WORD_LOG2 6
|
||||
# else /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */
|
||||
# error "CPU type is unknown"
|
||||
# endif /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */
|
||||
|
@ -28,8 +26,6 @@
|
|||
|
||||
# define IS_LITTLE_ENDIAN 1
|
||||
# undef IS_BIG_ENDIAN
|
||||
# define JS_BYTES_PER_WORD 4
|
||||
# define JS_BITS_PER_WORD_LOG2 5
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
# if __LITTLE_ENDIAN__
|
||||
|
@ -57,8 +53,8 @@
|
|||
|
||||
/* BSDs */
|
||||
#elif defined(JS_HAVE_MACHINE_ENDIAN_H)
|
||||
# include <sys/types.h>
|
||||
# include <machine/endian.h>
|
||||
# include <sys/types.h>
|
||||
|
||||
# if defined(_BYTE_ORDER)
|
||||
# if _BYTE_ORDER == _LITTLE_ENDIAN
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,42 +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 jslock_h
|
||||
#define jslock_h
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
|
||||
# include "jsapi.h"
|
||||
# include "pratom.h"
|
||||
# include "prcvar.h"
|
||||
# include "prinit.h"
|
||||
# include "prlock.h"
|
||||
# include "prthread.h"
|
||||
|
||||
# define JS_ATOMIC_INCREMENT(p) PR_ATOMIC_INCREMENT((int32_t *)(p))
|
||||
# define JS_ATOMIC_DECREMENT(p) PR_ATOMIC_DECREMENT((int32_t *)(p))
|
||||
# define JS_ATOMIC_ADD(p,v) PR_ATOMIC_ADD((int32_t *)(p), (int32_t)(v))
|
||||
# define JS_ATOMIC_SET(p,v) PR_ATOMIC_SET((int32_t *)(p), (int32_t)(v))
|
||||
|
||||
namespace js {
|
||||
// Defined in jsgc.cpp.
|
||||
unsigned GetCPUCount();
|
||||
}
|
||||
|
||||
#else /* JS_THREADSAFE */
|
||||
|
||||
typedef struct PRThread PRThread;
|
||||
typedef struct PRCondVar PRCondVar;
|
||||
typedef struct PRLock PRLock;
|
||||
|
||||
# define JS_ATOMIC_INCREMENT(p) (++*(p))
|
||||
# define JS_ATOMIC_DECREMENT(p) (--*(p))
|
||||
# define JS_ATOMIC_ADD(p,v) (*(p) += (v))
|
||||
# define JS_ATOMIC_SET(p,v) (*(p) = (v))
|
||||
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
||||
#endif /* jslock_h */
|
|
@ -6,7 +6,10 @@
|
|||
#ifndef perf_jsperf_h
|
||||
#define perf_jsperf_h
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Utility.h"
|
||||
|
||||
namespace JS {
|
||||
|
||||
|
@ -118,12 +121,12 @@ extern JS_FRIEND_API(JSObject*)
|
|||
RegisterPerfMeasurement(JSContext *cx, JSObject *global);
|
||||
|
||||
/*
|
||||
* Given a jsval which contains an instance of the aforementioned
|
||||
* wrapper class, extract the C++ object. Returns NULL if the
|
||||
* jsval is not an instance of the wrapper.
|
||||
* Given a Value which contains an instance of the aforementioned
|
||||
* wrapper class, extract the C++ object. Returns nullptr if the
|
||||
* Value is not an instance of the wrapper.
|
||||
*/
|
||||
extern JS_FRIEND_API(PerfMeasurement*)
|
||||
ExtractPerfMeasurement(jsval wrapper);
|
||||
ExtractPerfMeasurement(Value wrapper);
|
||||
|
||||
} // namespace JS
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "jstypes.h"
|
||||
|
||||
|
@ -39,7 +38,7 @@ extern JS_PUBLIC_API(uint32_t) JS_snprintf(char *out, uint32_t outlen, const cha
|
|||
|
||||
/*
|
||||
** sprintf into a malloc'd buffer. Return a pointer to the malloc'd
|
||||
** buffer on success, NULL on failure. Call "JS_smprintf_free" to release
|
||||
** 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, ...);
|
||||
|
@ -52,9 +51,9 @@ extern JS_PUBLIC_API(void) JS_smprintf_free(char *mem);
|
|||
/*
|
||||
** "append" sprintf into a malloc'd buffer. "last" is the last value of
|
||||
** the malloc'd buffer. sprintf will append data to the end of last,
|
||||
** growing it as necessary using realloc. If last is NULL, JS_sprintf_append
|
||||
** growing it as necessary using realloc. If last is nullptr, JS_sprintf_append
|
||||
** will allocate the initial string. The return value is the new value of
|
||||
** last for subsequent calls, or NULL if there is a malloc failure.
|
||||
** 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, ...);
|
||||
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
#ifndef jsprototypes_h
|
||||
#define jsprototypes_h
|
||||
|
||||
#include "jsversion.h"
|
||||
|
||||
/*
|
||||
* Enumerator codes in the second column must not change -- they are part of
|
||||
* the JS XDR API. Also note the symbols in the third column are extern "C";
|
||||
|
@ -56,20 +54,7 @@
|
|||
macro(DataView, 35, js_InitTypedArrayClasses) \
|
||||
macro(ParallelArray, 36, js_InitParallelArrayClass) \
|
||||
macro(Intl, 37, js_InitIntlClass) \
|
||||
macro(Type, 38, js_InitBinaryDataClasses) \
|
||||
macro(Data, 39, js_InitBinaryDataClasses) \
|
||||
macro(uint8, 40, js_InitBinaryDataClasses) \
|
||||
macro(uint16, 41, js_InitBinaryDataClasses) \
|
||||
macro(uint32, 42, js_InitBinaryDataClasses) \
|
||||
macro(uint64, 43, js_InitBinaryDataClasses) \
|
||||
macro(int8, 44, js_InitBinaryDataClasses) \
|
||||
macro(int16, 45, js_InitBinaryDataClasses) \
|
||||
macro(int32, 46, js_InitBinaryDataClasses) \
|
||||
macro(int64, 47, js_InitBinaryDataClasses) \
|
||||
macro(float32, 48, js_InitBinaryDataClasses) \
|
||||
macro(float64, 49, js_InitBinaryDataClasses) \
|
||||
macro(ArrayType, 50, js_InitBinaryDataClasses) \
|
||||
macro(StructType, 51, js_InitBinaryDataClasses) \
|
||||
macro(ArrayTypeObject, 52, js_InitBinaryDataClasses) \
|
||||
macro(TypedObject, 38, js_InitTypedObjectDummy) \
|
||||
macro(GeneratorFunction, 39, js_InitIteratorClasses) \
|
||||
|
||||
#endif /* jsprototypes_h */
|
||||
|
|
|
@ -7,11 +7,29 @@
|
|||
#ifndef jsproxy_h
|
||||
#define jsproxy_h
|
||||
|
||||
#include "jsapi.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);
|
||||
|
||||
/*
|
||||
|
@ -49,7 +67,7 @@ class JS_FRIEND_API(Wrapper);
|
|||
*/
|
||||
class JS_FRIEND_API(BaseProxyHandler)
|
||||
{
|
||||
void *mFamily;
|
||||
const void *mFamily;
|
||||
bool mHasPrototype;
|
||||
bool mHasPolicy;
|
||||
protected:
|
||||
|
@ -58,7 +76,7 @@ class JS_FRIEND_API(BaseProxyHandler)
|
|||
void setHasPolicy(bool aHasPolicy) { mHasPolicy = aHasPolicy; }
|
||||
|
||||
public:
|
||||
explicit BaseProxyHandler(void *family);
|
||||
explicit BaseProxyHandler(const void *family);
|
||||
virtual ~BaseProxyHandler();
|
||||
|
||||
bool hasPrototype() {
|
||||
|
@ -69,9 +87,12 @@ class JS_FRIEND_API(BaseProxyHandler)
|
|||
return mHasPolicy;
|
||||
}
|
||||
|
||||
inline void *family() {
|
||||
inline const void *family() {
|
||||
return mFamily;
|
||||
}
|
||||
static size_t offsetOfFamily() {
|
||||
return offsetof(BaseProxyHandler, mFamily);
|
||||
}
|
||||
|
||||
virtual bool isOuterWindow() {
|
||||
return false;
|
||||
|
@ -106,12 +127,13 @@ class JS_FRIEND_API(BaseProxyHandler)
|
|||
/* ES5 Harmony fundamental proxy traps. */
|
||||
virtual bool preventExtensions(JSContext *cx, HandleObject proxy) = 0;
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
PropertyDescriptor *desc, unsigned flags) = 0;
|
||||
MutableHandle<JSPropertyDescriptor> desc,
|
||||
unsigned flags) = 0;
|
||||
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
|
||||
HandleId id, PropertyDescriptor *desc,
|
||||
HandleId id, MutableHandle<JSPropertyDescriptor> desc,
|
||||
unsigned flags) = 0;
|
||||
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
PropertyDescriptor *desc) = 0;
|
||||
MutableHandle<JSPropertyDescriptor> desc) = 0;
|
||||
virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
|
||||
AutoIdVector &props) = 0;
|
||||
virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) = 0;
|
||||
|
@ -144,7 +166,13 @@ class JS_FRIEND_API(BaseProxyHandler)
|
|||
uint32_t index, MutableHandleValue vp, bool *present);
|
||||
virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
|
||||
|
||||
/* See comment for weakmapKeyDelegateOp in jsclass.h. */
|
||||
// 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);
|
||||
virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id);
|
||||
|
||||
/* See comment for weakmapKeyDelegateOp in js/Class.h. */
|
||||
virtual JSObject *weakmapKeyDelegate(JSObject *proxy);
|
||||
};
|
||||
|
||||
|
@ -157,17 +185,17 @@ class JS_FRIEND_API(BaseProxyHandler)
|
|||
class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler
|
||||
{
|
||||
public:
|
||||
explicit DirectProxyHandler(void *family);
|
||||
explicit DirectProxyHandler(const void *family);
|
||||
|
||||
/* ES5 Harmony fundamental proxy traps. */
|
||||
virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
|
||||
MutableHandle<JSPropertyDescriptor> desc, unsigned flags) MOZ_OVERRIDE;
|
||||
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
|
||||
HandleId id, PropertyDescriptor *desc,
|
||||
HandleId id, MutableHandle<JSPropertyDescriptor> desc,
|
||||
unsigned flags) MOZ_OVERRIDE;
|
||||
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
PropertyDescriptor *desc) MOZ_OVERRIDE;
|
||||
MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
|
||||
virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
|
||||
AutoIdVector &props) MOZ_OVERRIDE;
|
||||
virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
|
@ -204,8 +232,6 @@ class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler
|
|||
unsigned indent) MOZ_OVERRIDE;
|
||||
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy,
|
||||
RegExpGuard *g) MOZ_OVERRIDE;
|
||||
virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
|
||||
MutableHandleValue vp) MOZ_OVERRIDE;
|
||||
virtual JSObject *weakmapKeyDelegate(JSObject *proxy);
|
||||
};
|
||||
|
||||
|
@ -216,14 +242,15 @@ class Proxy
|
|||
/* ES5 Harmony fundamental proxy traps. */
|
||||
static bool preventExtensions(JSContext *cx, HandleObject proxy);
|
||||
static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
PropertyDescriptor *desc, unsigned flags);
|
||||
MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
|
||||
static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, unsigned flags, HandleId id,
|
||||
MutableHandleValue vp);
|
||||
static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
PropertyDescriptor *desc, unsigned flags);
|
||||
MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
|
||||
static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, unsigned flags, HandleId id,
|
||||
MutableHandleValue vp);
|
||||
static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, PropertyDescriptor *desc);
|
||||
static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
MutableHandle<JSPropertyDescriptor> desc);
|
||||
static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v);
|
||||
static bool getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props);
|
||||
static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
|
||||
|
@ -254,32 +281,27 @@ class Proxy
|
|||
static bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp);
|
||||
static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
|
||||
|
||||
static bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
|
||||
JS::HandleObject callable);
|
||||
static bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id);
|
||||
|
||||
/* IC entry path for handling __noSuchMethod__ on access. */
|
||||
static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id,
|
||||
MutableHandleValue vp);
|
||||
|
||||
static JSObject * const LazyProto;
|
||||
};
|
||||
|
||||
inline bool IsObjectProxyClass(const Class *clasp)
|
||||
{
|
||||
return clasp == js::ObjectProxyClassPtr || clasp == js::OuterWindowProxyClassPtr;
|
||||
}
|
||||
|
||||
inline bool IsFunctionProxyClass(const Class *clasp)
|
||||
{
|
||||
return clasp == js::FunctionProxyClassPtr;
|
||||
}
|
||||
// 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;
|
||||
extern JS_FRIEND_DATA(const js::Class* const) OuterWindowProxyClassPtr;
|
||||
|
||||
inline bool IsProxyClass(const Class *clasp)
|
||||
{
|
||||
return IsObjectProxyClass(clasp) || IsFunctionProxyClass(clasp);
|
||||
}
|
||||
|
||||
inline bool IsObjectProxy(JSObject *obj)
|
||||
{
|
||||
return IsObjectProxyClass(GetObjectClass(obj));
|
||||
}
|
||||
|
||||
inline bool IsFunctionProxy(JSObject *obj)
|
||||
{
|
||||
return IsFunctionProxyClass(GetObjectClass(obj));
|
||||
return clasp == CallableProxyClassPtr ||
|
||||
clasp == UncallableProxyClassPtr ||
|
||||
clasp == OuterWindowProxyClassPtr;
|
||||
}
|
||||
|
||||
inline bool IsProxy(JSObject *obj)
|
||||
|
@ -342,14 +364,42 @@ SetProxyExtra(JSObject *obj, size_t n, const Value &extra)
|
|||
SetReservedSlot(obj, PROXY_EXTRA_SLOT + n, extra);
|
||||
}
|
||||
|
||||
enum ProxyCallable {
|
||||
ProxyNotCallable = false,
|
||||
ProxyIsCallable = true
|
||||
class MOZ_STACK_CLASS ProxyOptions {
|
||||
public:
|
||||
ProxyOptions() : callable_(false),
|
||||
singleton_(false),
|
||||
forceForegroundFinalization_(false)
|
||||
{}
|
||||
|
||||
bool callable() const { return callable_; }
|
||||
ProxyOptions &setCallable(bool flag) {
|
||||
callable_ = flag;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool singleton() const { return singleton_; }
|
||||
ProxyOptions &setSingleton(bool flag) {
|
||||
singleton_ = flag;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool forceForegroundFinalization() const {
|
||||
return forceForegroundFinalization_;
|
||||
}
|
||||
ProxyOptions &setForceForegroundFinalization(bool flag) {
|
||||
forceForegroundFinalization_ = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
bool callable_;
|
||||
bool singleton_;
|
||||
bool forceForegroundFinalization_;
|
||||
};
|
||||
|
||||
JS_FRIEND_API(JSObject *)
|
||||
NewProxyObject(JSContext *cx, BaseProxyHandler *handler, HandleValue priv,
|
||||
JSObject *proto, JSObject *parent, ProxyCallable callable = ProxyNotCallable);
|
||||
JSObject *proto, JSObject *parent, const ProxyOptions &options = ProxyOptions());
|
||||
|
||||
JSObject *
|
||||
RenewProxyObject(JSContext *cx, JSObject *obj, BaseProxyHandler *handler, Value priv);
|
||||
|
@ -361,7 +411,7 @@ class JS_FRIEND_API(AutoEnterPolicy)
|
|||
AutoEnterPolicy(JSContext *cx, BaseProxyHandler *handler,
|
||||
HandleObject wrapper, HandleId id, Action act, bool mayThrow)
|
||||
#ifdef DEBUG
|
||||
: context(NULL)
|
||||
: context(nullptr)
|
||||
#endif
|
||||
{
|
||||
allow = handler->hasPolicy() ? handler->enter(cx, wrapper, id, act, &rv)
|
||||
|
@ -372,8 +422,8 @@ class JS_FRIEND_API(AutoEnterPolicy)
|
|||
// * 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 && !JS_IsExceptionPending(cx))
|
||||
reportError(cx, id);
|
||||
if (!allow && !rv && mayThrow)
|
||||
reportErrorIfExceptionIsNotPending(cx, id);
|
||||
}
|
||||
|
||||
virtual ~AutoEnterPolicy() { recordLeave(); }
|
||||
|
@ -384,10 +434,10 @@ class JS_FRIEND_API(AutoEnterPolicy)
|
|||
// no-op constructor for subclass
|
||||
AutoEnterPolicy()
|
||||
#ifdef DEBUG
|
||||
: context(NULL)
|
||||
: context(nullptr)
|
||||
#endif
|
||||
{};
|
||||
void reportError(JSContext *cx, jsid id);
|
||||
void reportErrorIfExceptionIsNotPending(JSContext *cx, jsid id);
|
||||
bool allow;
|
||||
bool rv;
|
||||
|
||||
|
|
|
@ -1,297 +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 jsprvtd_h
|
||||
#define jsprvtd_h
|
||||
/*
|
||||
* JS private typename definitions.
|
||||
*
|
||||
* This header is included only in other .h files, for convenience and for
|
||||
* simplicity of type naming. The alternative for structures is to use tags,
|
||||
* which are named the same as their typedef names (legal in C/C++, and less
|
||||
* noisy than suffixing the typedef name with "Struct" or "Str"). Instead,
|
||||
* all .h files that include this file may use the same typedef name, whether
|
||||
* declaring a pointer to struct type, or defining a member of struct type.
|
||||
*
|
||||
* A few fundamental scalar types are defined here too. Neither the scalar
|
||||
* nor the struct typedefs should change much, therefore the nearly-global
|
||||
* make dependency induced by this file should not prove painful.
|
||||
*/
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
#include "js/HashTable.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
/*
|
||||
* Convenience constants.
|
||||
*/
|
||||
#define JS_BITS_PER_UINT32_LOG2 5
|
||||
#define JS_BITS_PER_UINT32 32
|
||||
|
||||
/* The alignment required of objects stored in GC arenas. */
|
||||
static const unsigned JS_GCTHING_ALIGN = 8;
|
||||
static const unsigned JS_GCTHING_ZEROBITS = 3;
|
||||
|
||||
/* Scalar typedefs. */
|
||||
typedef uint8_t jsbytecode;
|
||||
typedef uint8_t jssrcnote;
|
||||
typedef uintptr_t jsatomid;
|
||||
|
||||
/* Struct typedefs. */
|
||||
typedef struct JSGCThing JSGCThing;
|
||||
typedef struct JSGenerator JSGenerator;
|
||||
typedef struct JSNativeEnumerator JSNativeEnumerator;
|
||||
typedef struct JSTryNote JSTryNote;
|
||||
|
||||
/* Friend "Advanced API" typedefs. */
|
||||
typedef struct JSAtomState JSAtomState;
|
||||
typedef struct JSCodeSpec JSCodeSpec;
|
||||
typedef struct JSPrinter JSPrinter;
|
||||
typedef struct JSStackHeader JSStackHeader;
|
||||
typedef struct JSSubString JSSubString;
|
||||
typedef struct JSSpecializedNative JSSpecializedNative;
|
||||
|
||||
/* String typedefs. */
|
||||
class JSDependentString;
|
||||
class JSExtensibleString;
|
||||
class JSExternalString;
|
||||
class JSLinearString;
|
||||
class JSRope;
|
||||
class JSAtom;
|
||||
class JSWrapper;
|
||||
|
||||
namespace js {
|
||||
|
||||
struct ArgumentsData;
|
||||
struct Class;
|
||||
|
||||
class AutoNameVector;
|
||||
class RegExpGuard;
|
||||
class RegExpObject;
|
||||
class RegExpObjectBuilder;
|
||||
class RegExpShared;
|
||||
class RegExpStatics;
|
||||
class MatchPairs;
|
||||
class PropertyName;
|
||||
class LazyScript;
|
||||
|
||||
enum RegExpFlag
|
||||
{
|
||||
IgnoreCaseFlag = 0x01,
|
||||
GlobalFlag = 0x02,
|
||||
MultilineFlag = 0x04,
|
||||
StickyFlag = 0x08,
|
||||
|
||||
NoFlags = 0x00,
|
||||
AllFlags = 0x0f
|
||||
};
|
||||
|
||||
class StringBuffer;
|
||||
|
||||
class FrameRegs;
|
||||
class StackFrame;
|
||||
class ScriptFrameIter;
|
||||
|
||||
class Proxy;
|
||||
class JS_FRIEND_API(AutoEnterPolicy);
|
||||
class JS_FRIEND_API(BaseProxyHandler);
|
||||
class JS_FRIEND_API(Wrapper);
|
||||
class JS_FRIEND_API(CrossCompartmentWrapper);
|
||||
|
||||
class TempAllocPolicy;
|
||||
class RuntimeAllocPolicy;
|
||||
|
||||
class GlobalObject;
|
||||
|
||||
template <typename K,
|
||||
typename V,
|
||||
size_t InlineElems>
|
||||
class InlineMap;
|
||||
|
||||
class LifoAlloc;
|
||||
|
||||
class Shape;
|
||||
|
||||
class Breakpoint;
|
||||
class BreakpointSite;
|
||||
class Debugger;
|
||||
class WatchpointMap;
|
||||
|
||||
/*
|
||||
* Env is the type of what ES5 calls "lexical environments" (runtime
|
||||
* activations of lexical scopes). This is currently just JSObject, and is
|
||||
* implemented by Call, Block, With, and DeclEnv objects, among others--but
|
||||
* environments and objects are really two different concepts.
|
||||
*/
|
||||
typedef JSObject Env;
|
||||
|
||||
typedef JSNative Native;
|
||||
typedef JSParallelNative ParallelNative;
|
||||
typedef JSThreadSafeNative ThreadSafeNative;
|
||||
typedef JSPropertyOp PropertyOp;
|
||||
typedef JSStrictPropertyOp StrictPropertyOp;
|
||||
typedef JSPropertyDescriptor PropertyDescriptor;
|
||||
|
||||
struct SourceCompressionToken;
|
||||
|
||||
namespace frontend {
|
||||
|
||||
struct BytecodeEmitter;
|
||||
struct Definition;
|
||||
class FullParseHandler;
|
||||
class FunctionBox;
|
||||
class ObjectBox;
|
||||
struct Token;
|
||||
struct TokenPos;
|
||||
class TokenStream;
|
||||
class ParseMapPool;
|
||||
class ParseNode;
|
||||
|
||||
template <typename ParseHandler>
|
||||
class Parser;
|
||||
|
||||
} /* namespace frontend */
|
||||
|
||||
namespace analyze {
|
||||
|
||||
struct LifetimeVariable;
|
||||
class LoopAnalysis;
|
||||
class ScriptAnalysis;
|
||||
class SlotValue;
|
||||
class SSAValue;
|
||||
class SSAUseChain;
|
||||
|
||||
} /* namespace analyze */
|
||||
|
||||
namespace types {
|
||||
|
||||
class TypeSet;
|
||||
struct TypeCallsite;
|
||||
struct TypeObject;
|
||||
struct TypeCompartment;
|
||||
|
||||
} /* namespace types */
|
||||
|
||||
typedef JS::Handle<Shape*> HandleShape;
|
||||
typedef JS::Handle<types::TypeObject*> HandleTypeObject;
|
||||
typedef JS::Handle<JSAtom*> HandleAtom;
|
||||
typedef JS::Handle<PropertyName*> HandlePropertyName;
|
||||
|
||||
typedef JS::MutableHandle<Shape*> MutableHandleShape;
|
||||
typedef JS::MutableHandle<JSAtom*> MutableHandleAtom;
|
||||
|
||||
typedef JS::Rooted<Shape*> RootedShape;
|
||||
typedef JS::Rooted<types::TypeObject*> RootedTypeObject;
|
||||
typedef JS::Rooted<JSAtom*> RootedAtom;
|
||||
typedef JS::Rooted<PropertyName*> RootedPropertyName;
|
||||
|
||||
enum XDRMode {
|
||||
XDR_ENCODE,
|
||||
XDR_DECODE
|
||||
};
|
||||
|
||||
template <XDRMode mode>
|
||||
class XDRState;
|
||||
|
||||
class FreeOp;
|
||||
|
||||
struct IdValuePair
|
||||
{
|
||||
jsid id;
|
||||
Value value;
|
||||
|
||||
IdValuePair() {}
|
||||
IdValuePair(jsid idArg)
|
||||
: id(idArg), value(UndefinedValue())
|
||||
{}
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
namespace JSC {
|
||||
|
||||
class ExecutableAllocator;
|
||||
|
||||
} /* namespace JSC */
|
||||
|
||||
namespace WTF {
|
||||
|
||||
class BumpPointerAllocator;
|
||||
|
||||
} /* namespace WTF */
|
||||
|
||||
/* "Friend" types used by jscntxt.h and jsdbgapi.h. */
|
||||
typedef enum JSTrapStatus {
|
||||
JSTRAP_ERROR,
|
||||
JSTRAP_CONTINUE,
|
||||
JSTRAP_RETURN,
|
||||
JSTRAP_THROW,
|
||||
JSTRAP_LIMIT
|
||||
} JSTrapStatus;
|
||||
|
||||
typedef JSTrapStatus
|
||||
(* JSTrapHandler)(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
|
||||
jsval closure);
|
||||
|
||||
typedef JSTrapStatus
|
||||
(* JSInterruptHook)(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
|
||||
void *closure);
|
||||
|
||||
typedef JSTrapStatus
|
||||
(* JSDebuggerHandler)(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
|
||||
void *closure);
|
||||
|
||||
typedef JSTrapStatus
|
||||
(* JSThrowHook)(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
|
||||
void *closure);
|
||||
|
||||
typedef JSBool
|
||||
(* JSWatchPointHandler)(JSContext *cx, JSObject *obj, jsid id, jsval old,
|
||||
jsval *newp, void *closure);
|
||||
|
||||
/* called just after script creation */
|
||||
typedef void
|
||||
(* JSNewScriptHook)(JSContext *cx,
|
||||
const char *filename, /* URL of script */
|
||||
unsigned lineno, /* first line */
|
||||
JSScript *script,
|
||||
JSFunction *fun,
|
||||
void *callerdata);
|
||||
|
||||
/* called just before script destruction */
|
||||
typedef void
|
||||
(* JSDestroyScriptHook)(JSFreeOp *fop,
|
||||
JSScript *script,
|
||||
void *callerdata);
|
||||
|
||||
typedef void
|
||||
(* JSSourceHandler)(const char *filename, unsigned lineno, const jschar *str,
|
||||
size_t length, void **listenerTSData, void *closure);
|
||||
|
||||
/* js::ObjectOps function pointer typedefs. */
|
||||
|
||||
/*
|
||||
* A generic type for functions mapping an object to another object, or null
|
||||
* if an error or exception was thrown on cx.
|
||||
*/
|
||||
typedef JSObject *
|
||||
(* JSObjectOp)(JSContext *cx, JS::Handle<JSObject*> obj);
|
||||
|
||||
/* Signature for class initialization ops. */
|
||||
typedef JSObject *
|
||||
(* JSClassInitializerOp)(JSContext *cx, JS::HandleObject obj);
|
||||
|
||||
/*
|
||||
* Hook that creates an iterator object for a given object. Returns the
|
||||
* iterator object or null if an error or exception was thrown on cx.
|
||||
*/
|
||||
typedef JSObject *
|
||||
(* JSIteratorOp)(JSContext *cx, JS::HandleObject obj, JSBool keysonly);
|
||||
|
||||
|
||||
#endif /* jsprvtd_h */
|
|
@ -11,72 +11,35 @@
|
|||
* JS public API typedefs.
|
||||
*/
|
||||
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
|
||||
#include "jsprototypes.h"
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) || defined(DEBUG)
|
||||
# define JSGC_TRACK_EXACT_ROOTS
|
||||
#endif
|
||||
|
||||
namespace JS {
|
||||
|
||||
/*
|
||||
* Allow headers to reference JS::Value without #including the whole jsapi.h.
|
||||
* Unfortunately, typedefs (hence jsval) cannot be declared.
|
||||
*/
|
||||
class Value;
|
||||
class AutoIdVector;
|
||||
class CallArgs;
|
||||
|
||||
template <typename T>
|
||||
class Rooted;
|
||||
|
||||
class JS_PUBLIC_API(AutoGCRooter);
|
||||
|
||||
class JS_PUBLIC_API(CompileOptions);
|
||||
class JS_PUBLIC_API(CompartmentOptions);
|
||||
|
||||
struct Zone;
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
/*
|
||||
* In release builds, jsid is defined to be an integral type. This
|
||||
* prevents many bugs from being caught at compile time. E.g.:
|
||||
*
|
||||
* jsid id = ...
|
||||
* if (id == JS_TRUE) // error
|
||||
* ...
|
||||
*
|
||||
* size_t n = id; // error
|
||||
*
|
||||
* To catch more errors, jsid is given a struct type in C++ debug builds.
|
||||
* Struct assignment and (in C++) operator== allow correct code to be mostly
|
||||
* oblivious to the change. This feature can be explicitly disabled in debug
|
||||
* builds by defining JS_NO_JSVAL_JSID_STRUCT_TYPES.
|
||||
*/
|
||||
// Needed for cocos2d-js
|
||||
#define JS_NO_JSVAL_JSID_STRUCT_TYPES
|
||||
# if defined(DEBUG) && !defined(JS_NO_JSVAL_JSID_STRUCT_TYPES)
|
||||
# define JS_USE_JSID_STRUCT_TYPES
|
||||
# endif
|
||||
|
||||
# ifdef JS_USE_JSID_STRUCT_TYPES
|
||||
struct jsid
|
||||
{
|
||||
size_t asBits;
|
||||
bool operator==(jsid rhs) const { return asBits == rhs.asBits; }
|
||||
bool operator!=(jsid rhs) const { return asBits != rhs.asBits; }
|
||||
};
|
||||
# define JSID_BITS(id) (id.asBits)
|
||||
# else /* defined(JS_USE_JSID_STRUCT_TYPES) */
|
||||
typedef ptrdiff_t jsid;
|
||||
# define JSID_BITS(id) (id)
|
||||
# endif /* defined(JS_USE_JSID_STRUCT_TYPES) */
|
||||
|
||||
#ifdef WIN32
|
||||
typedef wchar_t jschar;
|
||||
#else
|
||||
typedef uint16_t jschar;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Run-time version enumeration. For compile-time version checking, please use
|
||||
* the JS_HAS_* macros in jsversion.h, or use MOZJS_MAJOR_VERSION,
|
||||
|
@ -109,7 +72,7 @@ typedef enum JSType {
|
|||
typedef enum JSProtoKey {
|
||||
#define PROTOKEY_AND_INITIALIZER(name,code,init) JSProto_##name = code,
|
||||
JS_FOR_EACH_PROTOTYPE(PROTOKEY_AND_INITIALIZER)
|
||||
#undef JS_PROTO
|
||||
#undef PROTOKEY_AND_INITIALIZER
|
||||
JSProto_LIMIT
|
||||
} JSProtoKey;
|
||||
|
||||
|
@ -175,7 +138,6 @@ typedef enum {
|
|||
typedef struct JSClass JSClass;
|
||||
typedef struct JSCompartment JSCompartment;
|
||||
typedef struct JSConstDoubleSpec JSConstDoubleSpec;
|
||||
typedef struct JSContext JSContext;
|
||||
typedef struct JSCrossCompartmentCall JSCrossCompartmentCall;
|
||||
typedef struct JSErrorReport JSErrorReport;
|
||||
typedef struct JSExceptionState JSExceptionState;
|
||||
|
@ -195,20 +157,32 @@ typedef struct JSStructuredCloneWriter JSStructuredCloneWriter;
|
|||
typedef struct JSTracer JSTracer;
|
||||
|
||||
class JSFlatString;
|
||||
class JSFunction;
|
||||
class JSObject;
|
||||
class JSScript;
|
||||
class JSStableString; // long story
|
||||
class JSString;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
typedef struct PRCallOnceType JSCallOnceType;
|
||||
typedef struct PRCallOnceType JSCallOnceType;
|
||||
#else
|
||||
typedef JSBool JSCallOnceType;
|
||||
typedef bool JSCallOnceType;
|
||||
#endif
|
||||
typedef JSBool (*JSInitCallback)(void);
|
||||
typedef bool (*JSInitCallback)(void);
|
||||
|
||||
/*
|
||||
* Generic trace operation that calls JS_CallTracer on each traceable thing
|
||||
* stored in data.
|
||||
*/
|
||||
typedef void
|
||||
(* JSTraceDataOp)(JSTracer *trc, void *data);
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
class StoreBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
namespace JS {
|
||||
|
||||
typedef void (*OffThreadCompileCallback)(void *token, void *callbackData);
|
||||
|
||||
namespace shadow {
|
||||
|
||||
struct Runtime
|
||||
|
@ -220,15 +194,36 @@ struct Runtime
|
|||
/* Allow inlining of Nursery::isInside. */
|
||||
uintptr_t gcNurseryStart_;
|
||||
uintptr_t gcNurseryEnd_;
|
||||
|
||||
private:
|
||||
js::gc::StoreBuffer *gcStoreBufferPtr_;
|
||||
#endif
|
||||
|
||||
Runtime()
|
||||
public:
|
||||
Runtime(
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
js::gc::StoreBuffer *storeBuffer
|
||||
#endif
|
||||
)
|
||||
: needsBarrier_(false)
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
, gcNurseryStart_(0)
|
||||
, gcNurseryEnd_(0)
|
||||
, gcStoreBufferPtr_(storeBuffer)
|
||||
#endif
|
||||
{}
|
||||
|
||||
bool needsBarrier() const {
|
||||
return needsBarrier_;
|
||||
}
|
||||
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
js::gc::StoreBuffer *gcStoreBufferPtr() { return gcStoreBufferPtr_; }
|
||||
#endif
|
||||
|
||||
static JS::shadow::Runtime *asShadowRuntime(JSRuntime *rt) {
|
||||
return reinterpret_cast<JS::shadow::Runtime*>(rt);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace shadow */
|
||||
|
@ -270,6 +265,19 @@ enum ThingRootKind
|
|||
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
|
||||
* stack limits depending on the type of code running.
|
||||
*/
|
||||
enum StackKind
|
||||
{
|
||||
StackForSystemCode, // C++, such as the GC, running on behalf of the VM.
|
||||
StackForTrustedScript, // Script running with trusted principals.
|
||||
StackForUntrustedScript, // Script running with untrusted principals.
|
||||
StackKindCount
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct RootKind;
|
||||
|
||||
|
@ -305,13 +313,13 @@ struct ContextFriendFields
|
|||
|
||||
public:
|
||||
explicit ContextFriendFields(JSRuntime *rt)
|
||||
: runtime_(rt), compartment_(NULL), zone_(NULL), autoGCRooters(NULL)
|
||||
: runtime_(rt), compartment_(nullptr), zone_(nullptr), autoGCRooters(nullptr)
|
||||
{
|
||||
#ifdef JSGC_TRACK_EXACT_ROOTS
|
||||
mozilla::PodArrayZero(thingGCRooters);
|
||||
#endif
|
||||
#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
|
||||
skipGCRooters = NULL;
|
||||
skipGCRooters = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -395,7 +403,7 @@ struct PerThreadDataFriendFields
|
|||
#endif
|
||||
|
||||
/* Limit pointer for checking native stack consumption. */
|
||||
uintptr_t nativeStackLimit;
|
||||
uintptr_t nativeStackLimit[StackKindCount];
|
||||
|
||||
static const size_t RuntimeMainThreadOffset = offsetof(RuntimeDummy, mainThread);
|
||||
|
||||
|
|
|
@ -22,9 +22,16 @@
|
|||
#define jstypes_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "mozilla/Types.h"
|
||||
|
||||
// jstypes.h is (or should be!) included by every file in SpiderMonkey.
|
||||
// js-config.h and jsversion.h also should be included by every file.
|
||||
// So include them here.
|
||||
// XXX: including them in js/RequiredDefines.h should be a better option, since
|
||||
// that is by definition the header file that should be included in all
|
||||
// SpiderMonkey code. However, Gecko doesn't do this! See bug 909576.
|
||||
#include "js-config.h"
|
||||
#include "jsversion.h"
|
||||
|
||||
/***********************************************************************
|
||||
** MACROS: JS_EXTERN_API
|
||||
|
@ -82,10 +89,6 @@
|
|||
#define JS_NO_FASTCALL
|
||||
#endif
|
||||
|
||||
#ifndef JS_INLINE
|
||||
#define JS_INLINE MOZ_INLINE
|
||||
#endif
|
||||
|
||||
#ifndef JS_ALWAYS_INLINE
|
||||
#define JS_ALWAYS_INLINE MOZ_ALWAYS_INLINE
|
||||
#endif
|
||||
|
@ -180,19 +183,6 @@
|
|||
# error "Implement me"
|
||||
#endif
|
||||
|
||||
|
||||
/************************************************************************
|
||||
** TYPES: JSBool
|
||||
** DESCRIPTION:
|
||||
** Use JSBool for variables and parameter types. Use JS_FALSE and JS_TRUE
|
||||
** for clarity of target type in assignments and actual arguments. Use
|
||||
** 'if (bool)', 'while (!bool)', '(bool) ? x : y' etc., to test booleans
|
||||
** just as you would C int-valued conditions.
|
||||
************************************************************************/
|
||||
typedef int JSBool;
|
||||
#define JS_TRUE (int)1
|
||||
#define JS_FALSE (int)0
|
||||
|
||||
/***********************************************************************
|
||||
** MACROS: JS_LIKELY
|
||||
** JS_UNLIKELY
|
||||
|
@ -244,7 +234,11 @@ typedef int JSBool;
|
|||
#define JS_BITS_PER_BYTE 8
|
||||
#define JS_BITS_PER_BYTE_LOG2 3
|
||||
|
||||
#define JS_BITS_PER_WORD (JS_BITS_PER_BYTE * JS_BYTES_PER_WORD)
|
||||
#if defined(JS_64BIT)
|
||||
# define JS_BITS_PER_WORD 64
|
||||
#else
|
||||
# define JS_BITS_PER_WORD 32
|
||||
#endif
|
||||
|
||||
/***********************************************************************
|
||||
** MACROS: JS_FUNC_TO_DATA_PTR
|
||||
|
|
|
@ -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/. */
|
||||
|
||||
/*
|
||||
* PR assertion checker.
|
||||
*/
|
||||
|
||||
#ifndef jsutil_h
|
||||
#define jsutil_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Compiler.h"
|
||||
#include "mozilla/GuardObjects.h"
|
||||
|
||||
#ifdef USE_ZLIB
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#include "js/Utility.h"
|
||||
|
||||
/* Forward declarations. */
|
||||
struct JSContext;
|
||||
|
||||
static JS_ALWAYS_INLINE void *
|
||||
js_memcpy(void *dst_, const void *src_, size_t len)
|
||||
{
|
||||
char *dst = (char *) dst_;
|
||||
const char *src = (const char *) src_;
|
||||
JS_ASSERT_IF(dst >= src, (size_t) (dst - src) >= len);
|
||||
JS_ASSERT_IF(src >= dst, (size_t) (src - dst) >= len);
|
||||
|
||||
return memcpy(dst, src, len);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
template <class T>
|
||||
struct AlignmentTestStruct
|
||||
{
|
||||
char c;
|
||||
T t;
|
||||
};
|
||||
|
||||
/* This macro determines the alignment requirements of a type. */
|
||||
#define JS_ALIGNMENT_OF(t_) \
|
||||
(sizeof(js::AlignmentTestStruct<t_>) - sizeof(t_))
|
||||
|
||||
template <class T>
|
||||
class AlignedPtrAndFlag
|
||||
{
|
||||
uintptr_t bits;
|
||||
|
||||
public:
|
||||
AlignedPtrAndFlag(T *t, bool aFlag) {
|
||||
JS_ASSERT((uintptr_t(t) & 1) == 0);
|
||||
bits = uintptr_t(t) | uintptr_t(aFlag);
|
||||
}
|
||||
|
||||
T *ptr() const {
|
||||
return (T *)(bits & ~uintptr_t(1));
|
||||
}
|
||||
|
||||
bool flag() const {
|
||||
return (bits & 1) != 0;
|
||||
}
|
||||
|
||||
void setPtr(T *t) {
|
||||
JS_ASSERT((uintptr_t(t) & 1) == 0);
|
||||
bits = uintptr_t(t) | uintptr_t(flag());
|
||||
}
|
||||
|
||||
void setFlag() {
|
||||
bits |= 1;
|
||||
}
|
||||
|
||||
void unsetFlag() {
|
||||
bits &= ~uintptr_t(1);
|
||||
}
|
||||
|
||||
void set(T *t, bool aFlag) {
|
||||
JS_ASSERT((uintptr_t(t) & 1) == 0);
|
||||
bits = uintptr_t(t) | aFlag;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
static inline void
|
||||
Reverse(T *beg, T *end)
|
||||
{
|
||||
while (beg != end) {
|
||||
if (--end == beg)
|
||||
return;
|
||||
T tmp = *beg;
|
||||
*beg = *end;
|
||||
*end = tmp;
|
||||
++beg;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static inline T *
|
||||
Find(T *beg, T *end, const T &v)
|
||||
{
|
||||
for (T *p = beg; p != end; ++p) {
|
||||
if (*p == v)
|
||||
return p;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
static inline typename Container::ElementType *
|
||||
Find(Container &c, const typename Container::ElementType &v)
|
||||
{
|
||||
return Find(c.begin(), c.end(), v);
|
||||
}
|
||||
|
||||
template <typename InputIterT, typename CallableT>
|
||||
void
|
||||
ForEach(InputIterT begin, InputIterT end, CallableT f)
|
||||
{
|
||||
for (; begin != end; ++begin)
|
||||
f(*begin);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static inline T
|
||||
Min(T t1, T t2)
|
||||
{
|
||||
return t1 < t2 ? t1 : t2;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static inline T
|
||||
Max(T t1, T t2)
|
||||
{
|
||||
return t1 > t2 ? t1 : t2;
|
||||
}
|
||||
|
||||
/* Allows a const variable to be initialized after its declaration. */
|
||||
template <class T>
|
||||
static T&
|
||||
InitConst(const T &t)
|
||||
{
|
||||
return const_cast<T &>(t);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
JS_ALWAYS_INLINE T &
|
||||
ImplicitCast(U &u)
|
||||
{
|
||||
T &t = u;
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class AutoScopedAssign
|
||||
{
|
||||
public:
|
||||
AutoScopedAssign(T *addr, const T &value
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: addr_(addr), old(*addr_)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
*addr_ = value;
|
||||
}
|
||||
|
||||
~AutoScopedAssign() { *addr_ = old; }
|
||||
|
||||
private:
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
T *addr_;
|
||||
T old;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static inline bool
|
||||
IsPowerOfTwo(T t)
|
||||
{
|
||||
return t && !(t & (t - 1));
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
static inline U
|
||||
ComputeByteAlignment(T bytes, U alignment)
|
||||
{
|
||||
JS_ASSERT(IsPowerOfTwo(alignment));
|
||||
return (alignment - (bytes % alignment)) % alignment;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
static inline T
|
||||
AlignBytes(T bytes, U alignment)
|
||||
{
|
||||
return bytes + ComputeByteAlignment(bytes, alignment);
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE static size_t
|
||||
UnsignedPtrDiff(const void *bigger, const void *smaller)
|
||||
{
|
||||
return size_t(bigger) - size_t(smaller);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* A bit array is an array of bits represented by an array of words (size_t). */
|
||||
|
||||
static inline unsigned
|
||||
NumWordsForBitArrayOfLength(size_t length)
|
||||
{
|
||||
return (length + (JS_BITS_PER_WORD - 1)) / JS_BITS_PER_WORD;
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
BitArrayIndexToWordIndex(size_t length, size_t bitIndex)
|
||||
{
|
||||
unsigned wordIndex = bitIndex / JS_BITS_PER_WORD;
|
||||
JS_ASSERT(wordIndex < length);
|
||||
return wordIndex;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
BitArrayIndexToWordMask(size_t i)
|
||||
{
|
||||
return size_t(1) << (i % JS_BITS_PER_WORD);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsBitArrayElementSet(size_t *array, size_t length, size_t i)
|
||||
{
|
||||
return array[BitArrayIndexToWordIndex(length, i)] & BitArrayIndexToWordMask(i);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsAnyBitArrayElementSet(size_t *array, size_t length)
|
||||
{
|
||||
unsigned numWords = NumWordsForBitArrayOfLength(length);
|
||||
for (unsigned i = 0; i < numWords; ++i) {
|
||||
if (array[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void
|
||||
SetBitArrayElement(size_t *array, size_t length, size_t i)
|
||||
{
|
||||
array[BitArrayIndexToWordIndex(length, i)] |= BitArrayIndexToWordMask(i);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ClearBitArrayElement(size_t *array, size_t length, size_t i)
|
||||
{
|
||||
array[BitArrayIndexToWordIndex(length, i)] &= ~BitArrayIndexToWordMask(i);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ClearAllBitArrayElements(size_t *array, size_t length)
|
||||
{
|
||||
for (unsigned i = 0; i < length; ++i)
|
||||
array[i] = 0;
|
||||
}
|
||||
|
||||
#ifdef USE_ZLIB
|
||||
class Compressor
|
||||
{
|
||||
/* Number of bytes we should hand to zlib each compressMore() call. */
|
||||
static const size_t CHUNKSIZE = 2048;
|
||||
z_stream zs;
|
||||
const unsigned char *inp;
|
||||
size_t inplen;
|
||||
size_t outbytes;
|
||||
|
||||
public:
|
||||
enum Status {
|
||||
MOREOUTPUT,
|
||||
DONE,
|
||||
CONTINUE,
|
||||
OOM
|
||||
};
|
||||
|
||||
Compressor(const unsigned char *inp, size_t inplen);
|
||||
~Compressor();
|
||||
bool init();
|
||||
void setOutput(unsigned char *out, size_t outlen);
|
||||
size_t outWritten() const { return outbytes; }
|
||||
/* Compress some of the input. Return true if it should be called again. */
|
||||
Status compressMore();
|
||||
};
|
||||
|
||||
/*
|
||||
* Decompress a string. The caller must know the length of the output and
|
||||
* allocate |out| to a string of that length.
|
||||
*/
|
||||
bool DecompressString(const unsigned char *inp, size_t inplen,
|
||||
unsigned char *out, size_t outlen);
|
||||
#endif
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/* Crash diagnostics */
|
||||
#ifdef DEBUG
|
||||
# define JS_CRASH_DIAGNOSTICS 1
|
||||
#endif
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
# define JS_POISON(p, val, size) memset((p), (val), (size))
|
||||
#else
|
||||
# define JS_POISON(p, val, size) ((void) 0)
|
||||
#endif
|
||||
|
||||
/* Basic stats */
|
||||
#ifdef DEBUG
|
||||
# define JS_BASIC_STATS 1
|
||||
#endif
|
||||
#ifdef JS_BASIC_STATS
|
||||
# include <stdio.h>
|
||||
typedef struct JSBasicStats {
|
||||
uint32_t num;
|
||||
uint32_t max;
|
||||
double sum;
|
||||
double sqsum;
|
||||
uint32_t logscale; /* logarithmic scale: 0 (linear), 2, 10 */
|
||||
uint32_t hist[11];
|
||||
} JSBasicStats;
|
||||
# define JS_INIT_STATIC_BASIC_STATS {0,0,0,0,0,{0,0,0,0,0,0,0,0,0,0,0}}
|
||||
# define JS_BASIC_STATS_INIT(bs) memset((bs), 0, sizeof(JSBasicStats))
|
||||
# define JS_BASIC_STATS_ACCUM(bs,val) \
|
||||
JS_BasicStatsAccum(bs, val)
|
||||
# define JS_MeanAndStdDevBS(bs,sigma) \
|
||||
JS_MeanAndStdDev((bs)->num, (bs)->sum, (bs)->sqsum, sigma)
|
||||
extern void
|
||||
JS_BasicStatsAccum(JSBasicStats *bs, uint32_t val);
|
||||
extern double
|
||||
JS_MeanAndStdDev(uint32_t num, double sum, double sqsum, double *sigma);
|
||||
extern void
|
||||
JS_DumpBasicStats(JSBasicStats *bs, const char *title, FILE *fp);
|
||||
extern void
|
||||
JS_DumpHistogram(JSBasicStats *bs, FILE *fp);
|
||||
#else
|
||||
# define JS_BASIC_STATS_ACCUM(bs,val)
|
||||
#endif
|
||||
|
||||
/* A jsbitmap_t is a long integer that can be used for bitmaps. */
|
||||
typedef size_t jsbitmap;
|
||||
#define JS_TEST_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] & \
|
||||
((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1))))
|
||||
#define JS_SET_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] |= \
|
||||
((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1))))
|
||||
#define JS_CLEAR_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] &= \
|
||||
~((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1))))
|
||||
|
||||
/* Wrapper for various macros to stop warnings coming from their expansions. */
|
||||
#if defined(__clang__)
|
||||
# define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \
|
||||
JS_BEGIN_MACRO \
|
||||
_Pragma("clang diagnostic push") \
|
||||
/* If these _Pragmas cause warnings for you, try disabling ccache. */ \
|
||||
_Pragma("clang diagnostic ignored \"-Wunused-value\"") \
|
||||
{ expr; } \
|
||||
_Pragma("clang diagnostic pop") \
|
||||
JS_END_MACRO
|
||||
#elif MOZ_IS_GCC
|
||||
|
||||
#if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0)
|
||||
# define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \
|
||||
JS_BEGIN_MACRO \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wunused-but-set-variable\"") \
|
||||
expr; \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
JS_END_MACRO
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(JS_SILENCE_UNUSED_VALUE_IN_EXPR)
|
||||
# define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \
|
||||
JS_BEGIN_MACRO \
|
||||
expr; \
|
||||
JS_END_MACRO
|
||||
#endif
|
||||
|
||||
#endif /* jsutil_h */
|
|
@ -7,19 +7,6 @@
|
|||
#ifndef jsversion_h
|
||||
#define jsversion_h
|
||||
|
||||
/*
|
||||
* Deprecated JS_VERSION handler.
|
||||
*/
|
||||
#ifdef JS_VERSION
|
||||
# if JS_VERSION == 185
|
||||
# warning "JS_VERSION defined but unsupported (legacy)"
|
||||
# elif JS_VERSION < 185
|
||||
# error "Unsupported JS_VERSION"
|
||||
# else
|
||||
# error "Unknown JS_VERSION"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* JS Capability Macros.
|
||||
*/
|
||||
|
@ -52,15 +39,15 @@
|
|||
* Feature for Object.prototype.__{define,lookup}{G,S}etter__ legacy support;
|
||||
* support likely to be made opt-in at some future time.
|
||||
*/
|
||||
#define OLD_GETTER_SETTER_METHODS 1
|
||||
#define JS_OLD_GETTER_SETTER_METHODS 1
|
||||
|
||||
/* A kill-switch for bug 586842. Embedders shouldn't touch this! */
|
||||
#define USE_NEW_OBJECT_REPRESENTATION 0
|
||||
#define JS_USE_NEW_OBJECT_REPRESENTATION 0
|
||||
|
||||
#if USE_NEW_OBJECT_REPRESENTATION
|
||||
# define NEW_OBJECT_REPRESENTATION_ONLY() ((void)0)
|
||||
#if JS_USE_NEW_OBJECT_REPRESENTATION
|
||||
# define JS_NEW_OBJECT_REPRESENTATION_ONLY() ((void)0)
|
||||
#else
|
||||
# define NEW_OBJECT_REPRESENTATION_ONLY() \
|
||||
# define JS_NEW_OBJECT_REPRESENTATION_ONLY() \
|
||||
MOZ_ASSUME_UNREACHABLE("don't call this! to be used in the new object representation")
|
||||
#endif
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsproxy.h"
|
||||
|
||||
namespace js {
|
||||
|
@ -38,6 +37,9 @@ class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
|
|||
LAST_USED_FLAG = CROSS_COMPARTMENT
|
||||
};
|
||||
|
||||
virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
|
||||
MutableHandleValue vp) MOZ_OVERRIDE;
|
||||
|
||||
/*
|
||||
* Wrappers can explicitly specify that they are unsafe to unwrap from a
|
||||
* security perspective (as is the case for SecurityWrappers). If a wrapper
|
||||
|
@ -64,6 +66,8 @@ class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
|
|||
|
||||
virtual ~Wrapper();
|
||||
|
||||
virtual bool finalizeInBackground(Value priv) MOZ_OVERRIDE;
|
||||
|
||||
static Wrapper singleton;
|
||||
static Wrapper singletonWithPrototype;
|
||||
};
|
||||
|
@ -76,16 +80,16 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
|
|||
|
||||
virtual ~CrossCompartmentWrapper();
|
||||
|
||||
virtual bool finalizeInBackground(Value priv) MOZ_OVERRIDE;
|
||||
|
||||
/* ES5 Harmony fundamental wrapper traps. */
|
||||
virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) MOZ_OVERRIDE;
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
|
||||
PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
|
||||
MutableHandle<JSPropertyDescriptor> desc,
|
||||
unsigned flags) MOZ_OVERRIDE;
|
||||
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
|
||||
PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
|
||||
MutableHandle<JSPropertyDescriptor> desc,
|
||||
unsigned flags) MOZ_OVERRIDE;
|
||||
virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
|
||||
PropertyDescriptor *desc) MOZ_OVERRIDE;
|
||||
MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
|
||||
virtual bool getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
|
||||
AutoIdVector &props) MOZ_OVERRIDE;
|
||||
virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
|
||||
|
@ -149,7 +153,7 @@ class JS_FRIEND_API(SecurityWrapper) : public Base
|
|||
JSContext *cx) MOZ_OVERRIDE;
|
||||
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) MOZ_OVERRIDE;
|
||||
virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
|
||||
PropertyDescriptor *desc) MOZ_OVERRIDE;
|
||||
MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
|
||||
|
||||
/*
|
||||
* Allow our subclasses to select the superclass behavior they want without
|
||||
|
@ -165,18 +169,21 @@ typedef SecurityWrapper<CrossCompartmentWrapper> CrossCompartmentSecurityWrapper
|
|||
class JS_FRIEND_API(DeadObjectProxy) : public BaseProxyHandler
|
||||
{
|
||||
public:
|
||||
static int sDeadObjectFamily;
|
||||
// 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) MOZ_OVERRIDE;
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
|
||||
PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
|
||||
MutableHandle<JSPropertyDescriptor> desc,
|
||||
unsigned flags) MOZ_OVERRIDE;
|
||||
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
|
||||
PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
|
||||
MutableHandle<JSPropertyDescriptor> desc,
|
||||
unsigned flags) MOZ_OVERRIDE;
|
||||
virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
|
||||
PropertyDescriptor *desc) MOZ_OVERRIDE;
|
||||
MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
|
||||
virtual bool getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
|
||||
AutoIdVector &props) MOZ_OVERRIDE;
|
||||
virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
|
||||
|
@ -213,7 +220,8 @@ TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject obj,
|
|||
|
||||
// Proxy family for wrappers. Public so that IsWrapper() can be fully inlined by
|
||||
// jsfriendapi users.
|
||||
extern JS_FRIEND_DATA(int) sWrapperFamily;
|
||||
// This variable exists solely to provide a unique address for use as an identifier.
|
||||
extern JS_FRIEND_DATA(const char) sWrapperFamily;
|
||||
|
||||
inline bool
|
||||
IsWrapper(JSObject *obj)
|
||||
|
@ -226,7 +234,7 @@ IsWrapper(JSObject *obj)
|
|||
// 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 = NULL);
|
||||
UncheckedUnwrap(JSObject *obj, bool stopAtOuter = 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
|
||||
|
@ -247,7 +255,8 @@ bool
|
|||
IsDeadProxyObject(JSObject *obj);
|
||||
|
||||
JSObject *
|
||||
NewDeadProxyObject(JSContext *cx, JSObject *parent);
|
||||
NewDeadProxyObject(JSContext *cx, JSObject *parent,
|
||||
const ProxyOptions &options = ProxyOptions());
|
||||
|
||||
void
|
||||
NukeCrossCompartmentWrapper(JSContext *cx, JSObject *wrapper);
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
/* Functionality related to memory alignment. */
|
||||
|
||||
#ifndef mozilla_Alignment_h
|
||||
#define mozilla_Alignment_h
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/*
|
||||
* This class, and the corresponding macro MOZ_ALIGNOF, figures out how many
|
||||
* bytes of alignment a given type needs.
|
||||
*/
|
||||
template<typename T>
|
||||
class AlignmentFinder
|
||||
{
|
||||
struct Aligner
|
||||
{
|
||||
char c;
|
||||
T t;
|
||||
};
|
||||
|
||||
public:
|
||||
static const size_t alignment = sizeof(Aligner) - sizeof(T);
|
||||
};
|
||||
|
||||
#define MOZ_ALIGNOF(T) mozilla::AlignmentFinder<T>::alignment
|
||||
|
||||
/*
|
||||
* Declare the MOZ_ALIGNED_DECL macro for declaring aligned types.
|
||||
*
|
||||
* For instance,
|
||||
*
|
||||
* MOZ_ALIGNED_DECL(char arr[2], 8);
|
||||
*
|
||||
* will declare a two-character array |arr| aligned to 8 bytes.
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define MOZ_ALIGNED_DECL(_type, _align) \
|
||||
_type __attribute__((aligned(_align)))
|
||||
#elif defined(_MSC_VER)
|
||||
# define MOZ_ALIGNED_DECL(_type, _align) \
|
||||
__declspec(align(_align)) _type
|
||||
#else
|
||||
# warning "We don't know how to align variables on this compiler."
|
||||
# define MOZ_ALIGNED_DECL(_type, _align) _type
|
||||
#endif
|
||||
|
||||
/*
|
||||
* AlignedElem<N> is a structure whose alignment is guaranteed to be at least N
|
||||
* bytes.
|
||||
*
|
||||
* We support 1, 2, 4, 8, and 16-bit alignment.
|
||||
*/
|
||||
template<size_t Align>
|
||||
struct AlignedElem;
|
||||
|
||||
/*
|
||||
* We have to specialize this template because GCC doesn't like __attribute__((aligned(foo))) where
|
||||
* foo is a template parameter.
|
||||
*/
|
||||
|
||||
template<>
|
||||
struct AlignedElem<1>
|
||||
{
|
||||
MOZ_ALIGNED_DECL(uint8_t elem, 1);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AlignedElem<2>
|
||||
{
|
||||
MOZ_ALIGNED_DECL(uint8_t elem, 2);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AlignedElem<4>
|
||||
{
|
||||
MOZ_ALIGNED_DECL(uint8_t elem, 4);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AlignedElem<8>
|
||||
{
|
||||
MOZ_ALIGNED_DECL(uint8_t elem, 8);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AlignedElem<16>
|
||||
{
|
||||
MOZ_ALIGNED_DECL(uint8_t elem, 16);
|
||||
};
|
||||
|
||||
/*
|
||||
* This utility pales in comparison to Boost's aligned_storage. The utility
|
||||
* simply assumes that uint64_t is enough alignment for anyone. This may need
|
||||
* to be extended one day...
|
||||
*
|
||||
* As an important side effect, pulling the storage into this template is
|
||||
* enough obfuscation to confuse gcc's strict-aliasing analysis into not giving
|
||||
* false negatives when we cast from the char buffer to whatever type we've
|
||||
* constructed using the bytes.
|
||||
*/
|
||||
template<size_t Nbytes>
|
||||
struct AlignedStorage
|
||||
{
|
||||
union U {
|
||||
char bytes[Nbytes];
|
||||
uint64_t _;
|
||||
} u;
|
||||
|
||||
const void* addr() const { return u.bytes; }
|
||||
void* addr() { return u.bytes; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct AlignedStorage2
|
||||
{
|
||||
union U {
|
||||
char bytes[sizeof(T)];
|
||||
uint64_t _;
|
||||
} u;
|
||||
|
||||
const T* addr() const { return reinterpret_cast<const T*>(u.bytes); }
|
||||
T* addr() { return static_cast<T*>(static_cast<void*>(u.bytes)); }
|
||||
};
|
||||
|
||||
} /* namespace mozilla */
|
||||
|
||||
#endif /* mozilla_Alignment_h */
|
|
@ -180,7 +180,7 @@ __declspec(noreturn) __inline void MOZ_NoReturn() {}
|
|||
# ifdef __cplusplus
|
||||
# define MOZ_REALLY_CRASH() \
|
||||
do { \
|
||||
__debugbreak(); \
|
||||
::__debugbreak(); \
|
||||
*((volatile int*) NULL) = 123; \
|
||||
::TerminateProcess(::GetCurrentProcess(), 3); \
|
||||
::MOZ_NoReturn(); \
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#define mozilla_Atomics_h
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Compiler.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
@ -26,34 +28,16 @@
|
|||
* does not have <atomic>. So be sure to check for <atomic> support
|
||||
* along with C++0x support.
|
||||
*/
|
||||
#if defined(__clang__)
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
/*
|
||||
* clang doesn't like libstdc++'s version of <atomic> before GCC 4.7,
|
||||
* due to the loose typing of the __sync_* family of functions done by
|
||||
* GCC. We do not have a particularly good way to detect this sort of
|
||||
* case at this point, so just assume that if we're on a Linux system,
|
||||
* we can't use the system's <atomic>.
|
||||
*
|
||||
* OpenBSD uses an old libstdc++ 4.2.1 and thus doesnt have <atomic>.
|
||||
* 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++.
|
||||
*/
|
||||
# if !defined(__linux__) && !defined(__OpenBSD__) && \
|
||||
(__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && \
|
||||
__has_include(<atomic>)
|
||||
# if MOZ_USING_LIBSTDCXX && MOZ_LIBSTDCXX_VERSION_AT_LEAST(4, 7, 0)
|
||||
# define MOZ_HAVE_CXX11_ATOMICS
|
||||
# endif
|
||||
/*
|
||||
* Android uses a different C++ standard library that does not provide
|
||||
* support for <atomic>.
|
||||
*
|
||||
* GCC 4.5.x and 4.6.x's unspecialized std::atomic template doesn't include
|
||||
* inline definitions for the functions declared therein. This oversight
|
||||
* leads to linking errors when using atomic enums. We therefore require
|
||||
* GCC 4.7 or higher.
|
||||
*/
|
||||
#elif defined(__GNUC__) && !defined(__ANDROID__)
|
||||
# include "mozilla/Compiler.h"
|
||||
# if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) && \
|
||||
MOZ_GCC_VERSION_AT_LEAST(4, 7, 0)
|
||||
# elif MOZ_USING_LIBCXX
|
||||
# define MOZ_HAVE_CXX11_ATOMICS
|
||||
# endif
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1700
|
||||
|
@ -845,8 +829,8 @@ class AtomicBase
|
|||
typename Intrinsics::ValueType mValue;
|
||||
|
||||
public:
|
||||
AtomicBase() : mValue() {}
|
||||
AtomicBase(T aInit) { Intrinsics::store(mValue, aInit); }
|
||||
MOZ_CONSTEXPR AtomicBase() : mValue() {}
|
||||
MOZ_CONSTEXPR AtomicBase(T aInit) : mValue(aInit) {}
|
||||
|
||||
operator T() const { return Intrinsics::load(mValue); }
|
||||
|
||||
|
@ -889,8 +873,8 @@ class AtomicBaseIncDec : public AtomicBase<T, Order>
|
|||
typedef typename detail::AtomicBase<T, Order> Base;
|
||||
|
||||
public:
|
||||
AtomicBaseIncDec() : Base() {}
|
||||
AtomicBaseIncDec(T aInit) : Base(aInit) {}
|
||||
MOZ_CONSTEXPR AtomicBaseIncDec() : Base() {}
|
||||
MOZ_CONSTEXPR AtomicBaseIncDec(T aInit) : Base(aInit) {}
|
||||
|
||||
using Base::operator=;
|
||||
|
||||
|
@ -943,8 +927,8 @@ class Atomic<T, Order, typename EnableIf<IsIntegral<T>::value>::Type>
|
|||
typedef typename detail::AtomicBaseIncDec<T, Order> Base;
|
||||
|
||||
public:
|
||||
Atomic() : Base() {}
|
||||
Atomic(T aInit) : Base(aInit) {}
|
||||
MOZ_CONSTEXPR Atomic() : Base() {}
|
||||
MOZ_CONSTEXPR Atomic(T aInit) : Base(aInit) {}
|
||||
|
||||
using Base::operator=;
|
||||
|
||||
|
@ -972,8 +956,8 @@ class Atomic<T*, Order> : public detail::AtomicBaseIncDec<T*, Order>
|
|||
typedef typename detail::AtomicBaseIncDec<T*, Order> Base;
|
||||
|
||||
public:
|
||||
Atomic() : Base() {}
|
||||
Atomic(T* aInit) : Base(aInit) {}
|
||||
MOZ_CONSTEXPR Atomic() : Base() {}
|
||||
MOZ_CONSTEXPR Atomic(T* aInit) : Base(aInit) {}
|
||||
|
||||
using Base::operator=;
|
||||
|
||||
|
@ -1000,8 +984,8 @@ class Atomic<T, Order, typename EnableIf<IsEnum<T>::value>::Type>
|
|||
typedef typename detail::AtomicBase<T, Order> Base;
|
||||
|
||||
public:
|
||||
Atomic() : Base() {}
|
||||
Atomic(T aInit) : Base(aInit) {}
|
||||
MOZ_CONSTEXPR Atomic() : Base() {}
|
||||
MOZ_CONSTEXPR Atomic(T aInit) : Base(aInit) {}
|
||||
|
||||
using Base::operator=;
|
||||
|
||||
|
|
|
@ -11,26 +11,10 @@
|
|||
|
||||
#include "mozilla/Compiler.h"
|
||||
|
||||
/*
|
||||
* MOZ_INLINE is a macro which expands to tell the compiler that the method
|
||||
* decorated with it should be inlined. This macro is usable from C and C++
|
||||
* code, even though C89 does not support the |inline| keyword. The compiler
|
||||
* may ignore this directive if it chooses.
|
||||
*/
|
||||
#if defined(__cplusplus)
|
||||
# define MOZ_INLINE inline
|
||||
#elif defined(_MSC_VER)
|
||||
# define MOZ_INLINE __inline
|
||||
#elif defined(__GNUC__)
|
||||
# define MOZ_INLINE __inline__
|
||||
#else
|
||||
# define MOZ_INLINE inline
|
||||
#endif
|
||||
|
||||
/*
|
||||
* MOZ_ALWAYS_INLINE is a macro which expands to tell the compiler that the
|
||||
* method decorated with it must be inlined, even if the compiler thinks
|
||||
* otherwise. This is only a (much) stronger version of the MOZ_INLINE hint:
|
||||
* otherwise. This is only a (much) stronger version of the inline hint:
|
||||
* compilers are not guaranteed to respect it (although they're much more likely
|
||||
* to do so).
|
||||
*
|
||||
|
@ -40,15 +24,17 @@
|
|||
#if defined(_MSC_VER)
|
||||
# define MOZ_ALWAYS_INLINE_EVEN_DEBUG __forceinline
|
||||
#elif defined(__GNUC__)
|
||||
# define MOZ_ALWAYS_INLINE_EVEN_DEBUG __attribute__((always_inline)) MOZ_INLINE
|
||||
# define MOZ_ALWAYS_INLINE_EVEN_DEBUG __attribute__((always_inline)) inline
|
||||
#else
|
||||
# define MOZ_ALWAYS_INLINE_EVEN_DEBUG MOZ_INLINE
|
||||
# define MOZ_ALWAYS_INLINE_EVEN_DEBUG inline
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG)
|
||||
# define MOZ_ALWAYS_INLINE MOZ_INLINE
|
||||
#else
|
||||
#if !defined(DEBUG)
|
||||
# define MOZ_ALWAYS_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG
|
||||
#elif defined(_MSC_VER) && !defined(__cplusplus)
|
||||
# define MOZ_ALWAYS_INLINE __inline
|
||||
#else
|
||||
# define MOZ_ALWAYS_INLINE inline
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -170,12 +156,31 @@
|
|||
* Furthermore, it will prevent the compiler from inlining the function because
|
||||
* inlining currently breaks the blacklisting mechanism of AddressSanitizer.
|
||||
*/
|
||||
#if defined(MOZ_ASAN)
|
||||
# define MOZ_ASAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_address_safety_analysis))
|
||||
# else
|
||||
# define MOZ_ASAN_BLACKLIST
|
||||
#if defined(__has_feature)
|
||||
# if __has_feature(address_sanitizer)
|
||||
# define MOZ_ASAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_address))
|
||||
# else
|
||||
# define MOZ_ASAN_BLACKLIST /* nothing */
|
||||
# endif
|
||||
#else
|
||||
# define MOZ_ASAN_BLACKLIST /* nothing */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* MOZ_TSAN_BLACKLIST is a macro to tell ThreadSanitizer (a compile-time
|
||||
* instrumentation shipped with Clang) to not instrument the annotated function.
|
||||
* Furthermore, it will prevent the compiler from inlining the function because
|
||||
* inlining currently breaks the blacklisting mechanism of ThreadSanitizer.
|
||||
*/
|
||||
#if defined(__has_feature)
|
||||
# if __has_feature(thread_sanitizer)
|
||||
# define MOZ_TSAN_BLACKLIST MOZ_NEVER_INLINE __attribute__((no_sanitize_thread))
|
||||
# else
|
||||
# define MOZ_TSAN_BLACKLIST /* nothing */
|
||||
# endif
|
||||
#else
|
||||
# define MOZ_TSAN_BLACKLIST /* nothing */
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
|
|
|
@ -9,16 +9,11 @@
|
|||
#ifndef mozilla_Char16_h
|
||||
#define mozilla_Char16_h
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
/*
|
||||
* C11 and C++11 introduce a char16_t type and support for UTF-16 string and
|
||||
* character literals. C++11's char16_t is a distinct builtin type. C11's
|
||||
* char16_t is a typedef for uint_least16_t. Technically, char16_t is a 16-bit
|
||||
* code unit of a Unicode code point, not a "character".
|
||||
*
|
||||
* For now, Char16.h only supports C++ because we don't want mix different C
|
||||
* and C++ definitions of char16_t in the same code base.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -26,20 +21,52 @@
|
|||
* 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 our
|
||||
* char16_t as a macro to override yval.h's typedef of the same name.
|
||||
* 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 and to unsigned short 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
|
||||
# include <yvals.h>
|
||||
# define char16_t wchar_t
|
||||
# define _CHAR16T
|
||||
# ifdef __cplusplus
|
||||
typedef wchar_t char16_t;
|
||||
# else
|
||||
typedef unsigned short char16_t;
|
||||
# endif
|
||||
typedef unsigned int char32_t;
|
||||
#elif defined(__cplusplus) && \
|
||||
(__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__))
|
||||
/* 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
|
||||
#elif !defined(__cplusplus)
|
||||
# if defined(WIN32)
|
||||
# include <yvals.h>
|
||||
typedef wchar_t char16_t;
|
||||
# else
|
||||
/**
|
||||
* We can't use the stdint.h uint16_t type here because including
|
||||
* stdint.h will break building some of our C libraries, such as
|
||||
* sqlite.
|
||||
*/
|
||||
typedef unsigned short char16_t;
|
||||
# endif
|
||||
#else
|
||||
# error "Char16.h requires C++11 (or something like it) for UTF-16 support."
|
||||
#endif
|
||||
|
||||
/* This is a temporary hack until bug 927728 is fixed. */
|
||||
#define __PRUNICHAR__
|
||||
typedef char16_t PRUnichar;
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
@ -50,8 +77,12 @@
|
|||
*/
|
||||
#define MOZ_UTF16(s) MOZ_UTF16_HELPER(s)
|
||||
|
||||
#if defined(__cplusplus) && \
|
||||
(__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__))
|
||||
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?");
|
||||
#endif
|
||||
|
||||
#endif /* mozilla_Char16_h */
|
||||
|
|
|
@ -29,4 +29,77 @@
|
|||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The situation with standard libraries is a lot worse than with compilers,
|
||||
* particularly as clang and gcc could end up using one of three or so standard
|
||||
* libraries, and they may not be up-to-snuff with newer C++11 versions. To
|
||||
* detect the library, we're going to include cstddef (which is a small header
|
||||
* which will be transitively included by everybody else at some point) to grab
|
||||
* the version macros and deduce macros from there.
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
# include <cstddef>
|
||||
# ifdef _STLPORT_MAJOR
|
||||
# define MOZ_USING_STLPORT 1
|
||||
# define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) \
|
||||
(_STLPORT_VERSION >= ((major) << 8 | (minor) << 4 | (patch)))
|
||||
# elif defined(_LIBCPP_VERSION)
|
||||
/*
|
||||
* libc++, unfortunately, doesn't appear to have useful versioning macros.
|
||||
* Hopefully, the recommendations of N3694 with respect to standard libraries
|
||||
* will get applied instead and we won't need to worry about version numbers
|
||||
* here.
|
||||
*/
|
||||
# define MOZ_USING_LIBCXX 1
|
||||
# elif defined(__GLIBCXX__)
|
||||
# define MOZ_USING_LIBSTDCXX 1
|
||||
/*
|
||||
* libstdc++ is also annoying and doesn't give us useful versioning macros
|
||||
* for the library. If we're using gcc, then assume that libstdc++ matches
|
||||
* the compiler version. If we're using clang, we're going to have to fake
|
||||
* major/minor combinations by looking for newly-defined config macros.
|
||||
*/
|
||||
# if MOZ_IS_GCC
|
||||
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
|
||||
MOZ_GCC_VERSION_AT_LEAST(major, minor, patch)
|
||||
# elif defined(_GLIBCXX_THROW_OR_ABORT)
|
||||
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
|
||||
((major) < 4 || ((major) == 4 && (minor) <= 8))
|
||||
# elif defined(_GLIBCXX_NOEXCEPT)
|
||||
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
|
||||
((major) < 4 || ((major) == 4 && (minor) <= 7))
|
||||
# elif defined(_GLIBCXX_USE_DEPRECATED)
|
||||
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
|
||||
((major) < 4 || ((major) == 4 && (minor) <= 6))
|
||||
# elif defined(_GLIBCXX_PSEUDO_VISIBILITY)
|
||||
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
|
||||
((major) < 4 || ((major) == 4 && (minor) <= 5))
|
||||
# elif defined(_GLIBCXX_BEGIN_EXTERN_C)
|
||||
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
|
||||
((major) < 4 || ((major) == 4 && (minor) <= 4))
|
||||
# elif defined(_GLIBCXX_VISIBILITY_ATTR)
|
||||
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
|
||||
((major) < 4 || ((major) == 4 && (minor) <= 3))
|
||||
# elif defined(_GLIBCXX_VISIBILITY)
|
||||
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) \
|
||||
((major) < 4 || ((major) == 4 && (minor) <= 2))
|
||||
# else
|
||||
# error "Your version of libstdc++ is unknown to us and is likely too old."
|
||||
# endif
|
||||
# endif
|
||||
|
||||
// Flesh out the defines for everyone else
|
||||
# ifndef MOZ_USING_STLPORT
|
||||
# define MOZ_USING_STLPORT 0
|
||||
# define MOZ_STLPORT_VERSION_AT_LEAST(major, minor, patch) 0
|
||||
# endif
|
||||
# ifndef MOZ_USING_LIBCXX
|
||||
# define MOZ_USING_LIBCXX 0
|
||||
# endif
|
||||
# ifndef MOZ_USING_LIBSTDCXX
|
||||
# define MOZ_USING_LIBSTDCXX 0
|
||||
# define MOZ_LIBSTDCXX_VERSION_AT_LEAST(major, minor, patch) 0
|
||||
# endif
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* mozilla_Compiler_h */
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
/* Various simple compression/decompression functions. */
|
||||
|
||||
#ifndef mozilla_Compression_h_
|
||||
#define mozilla_Compression_h_
|
||||
|
||||
#include "mozilla/Types.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace Compression {
|
||||
|
||||
/**
|
||||
* LZ4 is a very fast byte-wise compression algorithm.
|
||||
*
|
||||
* Compared to Google's Snappy it is faster to compress and decompress and
|
||||
* generally produces output of about the same size.
|
||||
*
|
||||
* Compared to zlib it compresses at about 10x the speed, decompresses at about
|
||||
* 4x the speed and produces output of about 1.5x the size.
|
||||
*
|
||||
*/
|
||||
|
||||
class LZ4
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Compresses 'inputSize' bytes from 'source' into 'dest'.
|
||||
* Destination buffer must be already allocated,
|
||||
* and must be sized to handle worst cases situations (input data not compressible)
|
||||
* Worst case size evaluation is provided by function LZ4_compressBound()
|
||||
*
|
||||
* @param inputSize is the input size. Max supported value is ~1.9GB
|
||||
* @param return the number of bytes written in buffer dest
|
||||
*/
|
||||
static MFBT_API size_t compress(const char* source, size_t inputSize, char* dest);
|
||||
|
||||
/**
|
||||
* Compress 'inputSize' bytes from 'source' into an output buffer
|
||||
* 'dest' of maximum size 'maxOutputSize'. If it cannot achieve it,
|
||||
* compression will stop, and result of the function will be zero,
|
||||
* 'dest' will still be written to, but since the number of input
|
||||
* bytes consumed is not returned the result is not usable.
|
||||
*
|
||||
* This function never writes outside of provided output buffer.
|
||||
*
|
||||
* @param inputSize is the input size. Max supported value is ~1.9GB
|
||||
* @param maxOutputSize is the size of the destination buffer (which must be already allocated)
|
||||
* @return the number of bytes written in buffer 'dest'
|
||||
or 0 if the compression fails
|
||||
*/
|
||||
static MFBT_API size_t compressLimitedOutput(const char* source, size_t inputSize, char* dest,
|
||||
size_t maxOutputSize);
|
||||
|
||||
/**
|
||||
* If the source stream is malformed, the function will stop decoding
|
||||
* and return a negative result, indicating the byte position of the
|
||||
* faulty instruction
|
||||
*
|
||||
* This function never writes outside of provided buffers, and never
|
||||
* modifies input buffer.
|
||||
*
|
||||
* note : destination buffer must be already allocated.
|
||||
* its size must be a minimum of 'outputSize' bytes.
|
||||
* @param outputSize is the output size, therefore the original size
|
||||
* @return the number of bytes read in the source buffer
|
||||
*/
|
||||
static MFBT_API bool decompress(const char* source, char* dest, size_t outputSize);
|
||||
|
||||
/**
|
||||
* If the source stream is malformed, the function will stop decoding
|
||||
* and return false.
|
||||
*
|
||||
* This function never writes beyond dest + maxOutputSize, and is
|
||||
* therefore protected against malicious data packets.
|
||||
*
|
||||
* note : Destination buffer must be already allocated.
|
||||
* This version is slightly slower than the decompress
|
||||
* without the maxOutputSize
|
||||
*
|
||||
* @param inputSize is the length of the input compressed data
|
||||
* @param maxOutputSize is the size of the destination buffer (which must be already allocated)
|
||||
* @param outputSize the actual number of bytes decoded in the destination buffer (necessarily <= maxOutputSize)
|
||||
|
||||
*/
|
||||
static MFBT_API bool decompress(const char* source, size_t inputSize, char* dest,
|
||||
size_t maxOutputSize, size_t *outputSize);
|
||||
|
||||
/*
|
||||
Provides the maximum size that LZ4 may output in a "worst case"
|
||||
scenario (input data not compressible) primarily useful for memory
|
||||
allocation of output buffer.
|
||||
note : this function is limited by "int" range (2^31-1)
|
||||
|
||||
@param inputSize is the input size. Max supported value is ~1.9GB
|
||||
@return maximum output size in a "worst case" scenario
|
||||
*/
|
||||
static MFBT_API size_t maxCompressedSize(size_t inputSize)
|
||||
{
|
||||
size_t max = ((inputSize) + ((inputSize)/255) + 16);
|
||||
MOZ_ASSERT(max > inputSize);
|
||||
return max;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} /* namespace Compression */
|
||||
} /* namespace mozilla */
|
||||
|
||||
#endif /* mozilla_Compression_h_ */
|
|
@ -238,9 +238,9 @@ class EndianUtils
|
|||
{
|
||||
DebugOnly<const uint8_t*> byteDestPtr = static_cast<const uint8_t*>(dest);
|
||||
DebugOnly<const uint8_t*> byteSrcPtr = static_cast<const uint8_t*>(src);
|
||||
MOZ_ASSERT((byteDestPtr < byteSrcPtr &&
|
||||
MOZ_ASSERT((byteDestPtr <= byteSrcPtr &&
|
||||
byteDestPtr + count <= byteSrcPtr) ||
|
||||
(byteSrcPtr < byteDestPtr &&
|
||||
(byteSrcPtr <= byteDestPtr &&
|
||||
byteSrcPtr + count <= byteDestPtr));
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Casting.h"
|
||||
#include "mozilla/Types.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -58,6 +59,30 @@ static_assert((DoubleSignBit | DoubleExponentBits | DoubleSignificandBits) ==
|
|||
~uint64_t(0),
|
||||
"all bits accounted for");
|
||||
|
||||
/*
|
||||
* Ditto for |float| that must be a 32-bit double format number type, compatible
|
||||
* with the IEEE-754 standard.
|
||||
*/
|
||||
static_assert(sizeof(float) == sizeof(uint32_t), "float must be 32bits");
|
||||
|
||||
const unsigned FloatExponentBias = 127;
|
||||
const unsigned FloatExponentShift = 23;
|
||||
|
||||
const uint32_t FloatSignBit = 0x80000000UL;
|
||||
const uint32_t FloatExponentBits = 0x7F800000UL;
|
||||
const uint32_t FloatSignificandBits = 0x007FFFFFUL;
|
||||
|
||||
static_assert((FloatSignBit & FloatExponentBits) == 0,
|
||||
"sign bit doesn't overlap exponent bits");
|
||||
static_assert((FloatSignBit & FloatSignificandBits) == 0,
|
||||
"sign bit doesn't overlap significand bits");
|
||||
static_assert((FloatExponentBits & FloatSignificandBits) == 0,
|
||||
"exponent bits don't overlap significand bits");
|
||||
|
||||
static_assert((FloatSignBit | FloatExponentBits | FloatSignificandBits) ==
|
||||
~uint32_t(0),
|
||||
"all bits accounted for");
|
||||
|
||||
/** Determines whether a double is NaN. */
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
IsNaN(double d)
|
||||
|
@ -115,7 +140,12 @@ IsNegativeZero(double d)
|
|||
return bits == DoubleSignBit;
|
||||
}
|
||||
|
||||
/** Returns the exponent portion of the double. */
|
||||
/**
|
||||
* Returns the exponent portion of the double.
|
||||
*
|
||||
* Zero is not special-cased, so ExponentComponent(0.0) is
|
||||
* -int_fast16_t(DoubleExponentBias).
|
||||
*/
|
||||
static MOZ_ALWAYS_INLINE int_fast16_t
|
||||
ExponentComponent(double d)
|
||||
{
|
||||
|
@ -190,7 +220,13 @@ DoubleIsInt32(double d, int32_t* i)
|
|||
static MOZ_ALWAYS_INLINE double
|
||||
UnspecifiedNaN()
|
||||
{
|
||||
return SpecificNaN(0, 0xfffffffffffffULL);
|
||||
/*
|
||||
* If we can use any quiet NaN, we might as well use the all-ones NaN,
|
||||
* since it's cheap to materialize on common platforms (such as x64, where
|
||||
* this value can be represented in a 32-bit signed immediate field, allowing
|
||||
* it to be stored to memory in a single instruction).
|
||||
*/
|
||||
return SpecificNaN(1, 0xfffffffffffffULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -206,6 +242,46 @@ DoublesAreIdentical(double d1, double d2)
|
|||
return BitwiseCast<uint64_t>(d1) == BitwiseCast<uint64_t>(d2);
|
||||
}
|
||||
|
||||
/** Determines whether a float is NaN. */
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
IsFloatNaN(float f)
|
||||
{
|
||||
/*
|
||||
* A float is NaN if all exponent bits are 1 and the significand contains at
|
||||
* least one non-zero bit.
|
||||
*/
|
||||
uint32_t bits = BitwiseCast<uint32_t>(f);
|
||||
return (bits & FloatExponentBits) == FloatExponentBits &&
|
||||
(bits & FloatSignificandBits) != 0;
|
||||
}
|
||||
|
||||
/** Constructs a NaN value with the specified sign bit and significand bits. */
|
||||
static MOZ_ALWAYS_INLINE float
|
||||
SpecificFloatNaN(int signbit, uint32_t significand)
|
||||
{
|
||||
MOZ_ASSERT(signbit == 0 || signbit == 1);
|
||||
MOZ_ASSERT((significand & ~FloatSignificandBits) == 0);
|
||||
MOZ_ASSERT(significand & FloatSignificandBits);
|
||||
|
||||
float f = BitwiseCast<float>((signbit ? FloatSignBit : 0) |
|
||||
FloatExponentBits |
|
||||
significand);
|
||||
MOZ_ASSERT(IsFloatNaN(f));
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given value can be losslessly represented as an IEEE-754
|
||||
* single format number, false otherwise. All NaN values are considered
|
||||
* representable (notwithstanding that the exact bit pattern of a double format
|
||||
* NaN value can't be exactly represented in single format).
|
||||
*
|
||||
* This function isn't inlined to avoid buggy optimizations by MSVC.
|
||||
*/
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
extern MFBT_API bool
|
||||
IsFloat32Representable(double x);
|
||||
|
||||
} /* namespace mozilla */
|
||||
|
||||
#endif /* mozilla_FloatingPoint_h */
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Char16.h"
|
||||
#include "mozilla/Types.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
@ -326,6 +327,22 @@ HashString(const uint16_t* str, size_t length)
|
|||
return detail::HashKnownLength(str, length);
|
||||
}
|
||||
|
||||
#ifdef MOZ_CHAR16_IS_NOT_WCHAR
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
inline uint32_t
|
||||
HashString(const char16_t* str)
|
||||
{
|
||||
return detail::HashUntilZero(str);
|
||||
}
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
inline uint32_t
|
||||
HashString(const char16_t* str, size_t length)
|
||||
{
|
||||
return detail::HashKnownLength(str, length);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On Windows, wchar_t (PRUnichar) is not the same as uint16_t, even though it's
|
||||
* the same width!
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
/* Implements the C99 <inttypes.h> interface, minus the SCN* format macros. */
|
||||
|
||||
#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
|
||||
* 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!
|
||||
*/
|
||||
|
||||
#if defined(MOZ_CUSTOM_INTTYPES_H)
|
||||
# include MOZ_CUSTOM_INTTYPES_H
|
||||
#elif defined(_MSC_VER)
|
||||
# include "mozilla/MSIntTypes.h"
|
||||
#else
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#endif /* mozilla_IntegerPrintfMacros_h_ */
|
|
@ -58,6 +58,7 @@
|
|||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/NullPtr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -116,6 +117,36 @@ class LinkedListElement
|
|||
isSentinel(false)
|
||||
{ }
|
||||
|
||||
LinkedListElement(LinkedListElement<T>&& other)
|
||||
: isSentinel(other.isSentinel)
|
||||
{
|
||||
if (!other.isInList()) {
|
||||
next = this;
|
||||
prev = this;
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(other.next->prev == &other);
|
||||
MOZ_ASSERT(other.prev->next == &other);
|
||||
|
||||
/*
|
||||
* Initialize |this| with |other|'s prev/next pointers, and adjust those
|
||||
* element to point to this one.
|
||||
*/
|
||||
next = other.next;
|
||||
prev = other.prev;
|
||||
|
||||
next->prev = this;
|
||||
prev->next = this;
|
||||
|
||||
/*
|
||||
* Adjust |other| so it doesn't think it's in a list. This makes it
|
||||
* safely destructable.
|
||||
*/
|
||||
other.next = &other;
|
||||
other.prev = &other;
|
||||
}
|
||||
|
||||
~LinkedListElement() {
|
||||
if (!isSentinel && isInList())
|
||||
remove();
|
||||
|
@ -148,8 +179,8 @@ class LinkedListElement
|
|||
* linked list when you call setNext(); otherwise, this method will assert.
|
||||
*/
|
||||
void setNext(T* elem) {
|
||||
MOZ_ASSERT(isInList());
|
||||
setNextUnsafe(elem);
|
||||
MOZ_ASSERT(isInList());
|
||||
setNextUnsafe(elem);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -252,8 +283,8 @@ class LinkedListElement
|
|||
}
|
||||
|
||||
private:
|
||||
LinkedListElement& operator=(const LinkedList<T>& other) MOZ_DELETE;
|
||||
LinkedListElement(const LinkedList<T>& other) MOZ_DELETE;
|
||||
LinkedListElement& operator=(const LinkedListElement<T>& other) MOZ_DELETE;
|
||||
LinkedListElement(const LinkedListElement<T>& other) MOZ_DELETE;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
@ -265,6 +296,10 @@ class LinkedList
|
|||
public:
|
||||
LinkedList() : sentinel(LinkedListElement<T>::NODE_KIND_SENTINEL) { }
|
||||
|
||||
LinkedList(LinkedList<T>&& other)
|
||||
: sentinel(mozilla::Move(other.sentinel))
|
||||
{ }
|
||||
|
||||
~LinkedList() {
|
||||
MOZ_ASSERT(isEmpty());
|
||||
}
|
||||
|
@ -361,7 +396,7 @@ class LinkedList
|
|||
for (slow = sentinel.next,
|
||||
fast1 = sentinel.next->next,
|
||||
fast2 = sentinel.next->next->next;
|
||||
slow != sentinel && fast1 != sentinel && fast2 != sentinel;
|
||||
slow != &sentinel && fast1 != &sentinel && fast2 != &sentinel;
|
||||
slow = slow->next, fast1 = fast2->next, fast2 = fast1->next)
|
||||
{
|
||||
MOZ_ASSERT(slow != fast1);
|
||||
|
@ -372,7 +407,7 @@ class LinkedList
|
|||
for (slow = sentinel.prev,
|
||||
fast1 = sentinel.prev->prev,
|
||||
fast2 = sentinel.prev->prev->prev;
|
||||
slow != sentinel && fast1 != sentinel && fast2 != sentinel;
|
||||
slow != &sentinel && fast1 != &sentinel && fast2 != &sentinel;
|
||||
slow = slow->prev, fast1 = fast2->prev, fast2 = fast1->prev)
|
||||
{
|
||||
MOZ_ASSERT(slow != fast1);
|
||||
|
@ -384,14 +419,14 @@ class LinkedList
|
|||
* isSentinel == true.
|
||||
*/
|
||||
for (const LinkedListElement<T>* elem = sentinel.next;
|
||||
elem != sentinel;
|
||||
elem != &sentinel;
|
||||
elem = elem->next)
|
||||
{
|
||||
MOZ_ASSERT(!elem->isSentinel);
|
||||
}
|
||||
|
||||
/* Check that the next/prev pointers match up. */
|
||||
const LinkedListElement<T>* prev = sentinel;
|
||||
const LinkedListElement<T>* prev = &sentinel;
|
||||
const LinkedListElement<T>* cur = sentinel.next;
|
||||
do {
|
||||
MOZ_ASSERT(cur->prev == prev);
|
||||
|
@ -399,7 +434,7 @@ class LinkedList
|
|||
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
} while (cur != sentinel);
|
||||
} while (cur != &sentinel);
|
||||
#endif /* ifdef DEBUG */
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
// ISO C9x compliant inttypes.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The name of the author may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_INTTYPES_H_ // [
|
||||
#define _MSC_INTTYPES_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// 7.8 Format conversion of integer types
|
||||
|
||||
typedef struct {
|
||||
intmax_t quot;
|
||||
intmax_t rem;
|
||||
} imaxdiv_t;
|
||||
|
||||
// 7.8.1 Macros for format specifiers
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
|
||||
|
||||
// The fprintf macros for signed integers are:
|
||||
#define PRId8 "d"
|
||||
#define PRIi8 "i"
|
||||
#define PRIdLEAST8 "d"
|
||||
#define PRIiLEAST8 "i"
|
||||
#define PRIdFAST8 "d"
|
||||
#define PRIiFAST8 "i"
|
||||
|
||||
#define PRId16 "hd"
|
||||
#define PRIi16 "hi"
|
||||
#define PRIdLEAST16 "hd"
|
||||
#define PRIiLEAST16 "hi"
|
||||
#define PRIdFAST16 "hd"
|
||||
#define PRIiFAST16 "hi"
|
||||
|
||||
#define PRId32 "I32d"
|
||||
#define PRIi32 "I32i"
|
||||
#define PRIdLEAST32 "I32d"
|
||||
#define PRIiLEAST32 "I32i"
|
||||
#define PRIdFAST32 "I32d"
|
||||
#define PRIiFAST32 "I32i"
|
||||
|
||||
#define PRId64 "I64d"
|
||||
#define PRIi64 "I64i"
|
||||
#define PRIdLEAST64 "I64d"
|
||||
#define PRIiLEAST64 "I64i"
|
||||
#define PRIdFAST64 "I64d"
|
||||
#define PRIiFAST64 "I64i"
|
||||
|
||||
#define PRIdMAX "I64d"
|
||||
#define PRIiMAX "I64i"
|
||||
|
||||
#define PRIdPTR "Id"
|
||||
#define PRIiPTR "Ii"
|
||||
|
||||
// The fprintf macros for unsigned integers are:
|
||||
#define PRIo8 "o"
|
||||
#define PRIu8 "u"
|
||||
#define PRIx8 "x"
|
||||
#define PRIX8 "X"
|
||||
#define PRIoLEAST8 "o"
|
||||
#define PRIuLEAST8 "u"
|
||||
#define PRIxLEAST8 "x"
|
||||
#define PRIXLEAST8 "X"
|
||||
#define PRIoFAST8 "o"
|
||||
#define PRIuFAST8 "u"
|
||||
#define PRIxFAST8 "x"
|
||||
#define PRIXFAST8 "X"
|
||||
|
||||
#define PRIo16 "ho"
|
||||
#define PRIu16 "hu"
|
||||
#define PRIx16 "hx"
|
||||
#define PRIX16 "hX"
|
||||
#define PRIoLEAST16 "ho"
|
||||
#define PRIuLEAST16 "hu"
|
||||
#define PRIxLEAST16 "hx"
|
||||
#define PRIXLEAST16 "hX"
|
||||
#define PRIoFAST16 "ho"
|
||||
#define PRIuFAST16 "hu"
|
||||
#define PRIxFAST16 "hx"
|
||||
#define PRIXFAST16 "hX"
|
||||
|
||||
#define PRIo32 "I32o"
|
||||
#define PRIu32 "I32u"
|
||||
#define PRIx32 "I32x"
|
||||
#define PRIX32 "I32X"
|
||||
#define PRIoLEAST32 "I32o"
|
||||
#define PRIuLEAST32 "I32u"
|
||||
#define PRIxLEAST32 "I32x"
|
||||
#define PRIXLEAST32 "I32X"
|
||||
#define PRIoFAST32 "I32o"
|
||||
#define PRIuFAST32 "I32u"
|
||||
#define PRIxFAST32 "I32x"
|
||||
#define PRIXFAST32 "I32X"
|
||||
|
||||
#define PRIo64 "I64o"
|
||||
#define PRIu64 "I64u"
|
||||
#define PRIx64 "I64x"
|
||||
#define PRIX64 "I64X"
|
||||
#define PRIoLEAST64 "I64o"
|
||||
#define PRIuLEAST64 "I64u"
|
||||
#define PRIxLEAST64 "I64x"
|
||||
#define PRIXLEAST64 "I64X"
|
||||
#define PRIoFAST64 "I64o"
|
||||
#define PRIuFAST64 "I64u"
|
||||
#define PRIxFAST64 "I64x"
|
||||
#define PRIXFAST64 "I64X"
|
||||
|
||||
#define PRIoMAX "I64o"
|
||||
#define PRIuMAX "I64u"
|
||||
#define PRIxMAX "I64x"
|
||||
#define PRIXMAX "I64X"
|
||||
|
||||
#define PRIoPTR "Io"
|
||||
#define PRIuPTR "Iu"
|
||||
#define PRIxPTR "Ix"
|
||||
#define PRIXPTR "IX"
|
||||
|
||||
// DO NOT SUPPORT THE scanf MACROS! See the comment at the top of
|
||||
// IntegerPrintfMacros.h.
|
||||
|
||||
#endif // __STDC_FORMAT_MACROS ]
|
||||
|
||||
// 7.8.2 Functions for greatest-width integer types
|
||||
|
||||
// 7.8.2.1 The imaxabs function
|
||||
#define imaxabs _abs64
|
||||
|
||||
// 7.8.2.2 The imaxdiv function
|
||||
|
||||
// This is modified version of div() function from Microsoft's div.c found
|
||||
// in %MSVC.NET%\crt\src\div.c
|
||||
#ifdef STATIC_IMAXDIV // [
|
||||
static
|
||||
#else // STATIC_IMAXDIV ][
|
||||
_inline
|
||||
#endif // STATIC_IMAXDIV ]
|
||||
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
|
||||
{
|
||||
imaxdiv_t result;
|
||||
|
||||
result.quot = numer / denom;
|
||||
result.rem = numer % denom;
|
||||
|
||||
if (numer < 0 && result.rem > 0) {
|
||||
// did division wrong; must fix up
|
||||
++result.quot;
|
||||
result.rem -= denom;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 7.8.2.3 The strtoimax and strtoumax functions
|
||||
#define strtoimax _strtoi64
|
||||
#define strtoumax _strtoui64
|
||||
|
||||
// 7.8.2.4 The wcstoimax and wcstoumax functions
|
||||
#define wcstoimax _wcstoi64
|
||||
#define wcstoumax _wcstoui64
|
||||
|
||||
|
||||
#endif // _MSC_INTTYPES_H_ ]
|
|
@ -186,6 +186,16 @@ namespace detail {
|
|||
return uint_fast8_t(index);
|
||||
}
|
||||
|
||||
inline uint_fast8_t
|
||||
CountPopulation32(uint32_t u)
|
||||
{
|
||||
uint32_t sum2 = (u & 0x55555555) + ((u & 0xaaaaaaaa) >> 1);
|
||||
uint32_t sum4 = (sum2 & 0x33333333) + ((sum2 & 0xcccccccc) >> 2);
|
||||
uint32_t sum8 = (sum4 & 0x0f0f0f0f) + ((sum4 & 0xf0f0f0f0) >> 4);
|
||||
uint32_t sum16 = (sum8 & 0x00ff00ff) + ((sum8 & 0xff00ff00) >> 8);
|
||||
return sum16;
|
||||
}
|
||||
|
||||
inline uint_fast8_t
|
||||
CountLeadingZeroes64(uint64_t u)
|
||||
{
|
||||
|
@ -242,6 +252,12 @@ namespace detail {
|
|||
return __builtin_ctz(u);
|
||||
}
|
||||
|
||||
inline uint_fast8_t
|
||||
CountPopulation32(uint32_t u)
|
||||
{
|
||||
return __builtin_popcount(u);
|
||||
}
|
||||
|
||||
inline uint_fast8_t
|
||||
CountLeadingZeroes64(uint64_t u)
|
||||
{
|
||||
|
@ -258,6 +274,7 @@ namespace detail {
|
|||
# error "Implement these!"
|
||||
inline uint_fast8_t CountLeadingZeroes32(uint32_t u) MOZ_DELETE;
|
||||
inline uint_fast8_t CountTrailingZeroes32(uint32_t u) MOZ_DELETE;
|
||||
inline uint_fast8_t CountPopulation32(uint32_t u) MOZ_DELETE;
|
||||
inline uint_fast8_t CountLeadingZeroes64(uint64_t u) MOZ_DELETE;
|
||||
inline uint_fast8_t CountTrailingZeroes64(uint64_t u) MOZ_DELETE;
|
||||
#endif
|
||||
|
@ -300,6 +317,15 @@ CountTrailingZeroes32(uint32_t u)
|
|||
return detail::CountTrailingZeroes32(u);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the number of one bits in the number |u|,
|
||||
*/
|
||||
inline uint_fast8_t
|
||||
CountPopulation32(uint32_t u)
|
||||
{
|
||||
return detail::CountPopulation32(u);
|
||||
}
|
||||
|
||||
/** Analogous to CountLeadingZeroes32, but for 64-bit numbers. */
|
||||
inline uint_fast8_t
|
||||
CountLeadingZeroes64(uint64_t u)
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
/* -*- 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 class for lazily constructing an object without sticking it on the heap. */
|
||||
|
||||
#ifndef mozilla_Maybe_h
|
||||
#define mozilla_Maybe_h
|
||||
|
||||
#include "mozilla/Alignment.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
// For placement new
|
||||
#include <new>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/*
|
||||
* Small utility for lazily constructing objects without using dynamic storage.
|
||||
* When a Maybe<T> is constructed, it is |empty()|, i.e., no value of T has
|
||||
* been constructed and no T destructor will be called when the Maybe<T> is
|
||||
* destroyed. Upon calling |construct|, a T object will be constructed with the
|
||||
* given arguments and that object will be destroyed when the owning Maybe<T>
|
||||
* is destroyed.
|
||||
*
|
||||
* N.B. GCC seems to miss some optimizations with Maybe and may generate extra
|
||||
* branches/loads/stores. Use with caution on hot paths.
|
||||
*/
|
||||
template<class T>
|
||||
class Maybe
|
||||
{
|
||||
AlignedStorage2<T> storage;
|
||||
bool constructed;
|
||||
|
||||
T& asT() { return *storage.addr(); }
|
||||
|
||||
public:
|
||||
Maybe() { constructed = false; }
|
||||
~Maybe() { if (constructed) asT().~T(); }
|
||||
|
||||
bool empty() const { return !constructed; }
|
||||
|
||||
void construct() {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T();
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1>
|
||||
void construct(const T1& t1) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2>
|
||||
void construct(const T1& t1, const T2& t2) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3, class T4>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3, t4);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3, class T4, class T5>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3, t4, t5);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3, class T4, class T5,
|
||||
class T6>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5,
|
||||
const T6& t6) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3, t4, t5, t6);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3, class T4, class T5,
|
||||
class T6, class T7>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5,
|
||||
const T6& t6, const T7& t7) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3, class T4, class T5,
|
||||
class T6, class T7, class T8>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5,
|
||||
const T6& t6, const T7& t7, const T8& t8) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7, t8);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3, class T4, class T5,
|
||||
class T6, class T7, class T8, class T9>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5,
|
||||
const T6& t6, const T7& t7, const T8& t8, const T9& t9) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7, t8, t9);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3, class T4, class T5,
|
||||
class T6, class T7, class T8, class T9, class T10>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5,
|
||||
const T6& t6, const T7& t7, const T8& t8, const T9& t9, const T10& t10) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
T* addr() {
|
||||
MOZ_ASSERT(constructed);
|
||||
return &asT();
|
||||
}
|
||||
|
||||
T& ref() {
|
||||
MOZ_ASSERT(constructed);
|
||||
return asT();
|
||||
}
|
||||
|
||||
const T& ref() const {
|
||||
MOZ_ASSERT(constructed);
|
||||
return const_cast<Maybe*>(this)->asT();
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
ref().~T();
|
||||
constructed = false;
|
||||
}
|
||||
|
||||
void destroyIfConstructed() {
|
||||
if (!empty())
|
||||
destroy();
|
||||
}
|
||||
|
||||
private:
|
||||
Maybe(const Maybe& other) MOZ_DELETE;
|
||||
const Maybe& operator=(const Maybe& other) MOZ_DELETE;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_Maybe_h */
|
|
@ -9,11 +9,21 @@
|
|||
#ifndef mozilla_Move_h
|
||||
#define mozilla_Move_h
|
||||
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/*
|
||||
* "Move" References
|
||||
*
|
||||
* [Once upon a time, C++11 rvalue references were not implemented by all the
|
||||
* compilers we cared about, so we invented mozilla::Move() (now called
|
||||
* OldMove()), which does something similar. We're in the process of
|
||||
* transitioning away from this to pure stl (bug 896100). Until that bug is
|
||||
* completed, this header will provide both mozilla::OldMove() and
|
||||
* mozilla::Move().]
|
||||
*
|
||||
*
|
||||
* Some types can be copied much more efficiently if we know the original's
|
||||
* value need not be preserved --- that is, if we are doing a "move", not a
|
||||
* "copy". For example, if we have:
|
||||
|
@ -48,18 +58,28 @@ namespace mozilla {
|
|||
* efficiently than it can be copied, and provide an implementation of that
|
||||
* move operation.
|
||||
*
|
||||
* The Move(T&) function takes a reference to a T, and returns a MoveRef<T>
|
||||
* referring to the same value; that's 1). A MoveRef<T> is simply a reference
|
||||
* The OldMove(T&) function takes a reference to a T, and returns a MoveRef<T>
|
||||
* referring to the same value; that's (1). A MoveRef<T> is simply a reference
|
||||
* to a T, annotated to say that a copy constructor applied to it may move that
|
||||
* T, instead of copying it. Finally, a constructor that accepts an MoveRef<T>
|
||||
* should perform a more efficient move, instead of a copy, providing 2).
|
||||
* should perform a more efficient move, instead of a copy, providing (2).
|
||||
*
|
||||
* So, where we might define a copy constructor for a class C like this:
|
||||
* The Move(T&) function takes a reference to a T and returns a T&&. It acts
|
||||
* just like std::move(), which is not available on all our platforms.
|
||||
*
|
||||
* In new code, you should use Move(T&) and T&& instead of OldMove(T&) and
|
||||
* MoveRef<T>, where possible.
|
||||
*
|
||||
* Where we might define a copy constructor for a class C like this:
|
||||
*
|
||||
* C(const C& rhs) { ... copy rhs to this ... }
|
||||
*
|
||||
* we would declare a move constructor like this:
|
||||
*
|
||||
* C(C&& rhs) { .. move rhs to this ... }
|
||||
*
|
||||
* or, in the deprecated OldMove style:
|
||||
*
|
||||
* C(MoveRef<C> rhs) { ... move rhs to this ... }
|
||||
*
|
||||
* And where we might perform a copy like this:
|
||||
|
@ -68,7 +88,11 @@ namespace mozilla {
|
|||
*
|
||||
* we would perform a move like this:
|
||||
*
|
||||
* C c2(Move(c1))
|
||||
* C c2(Move(c1));
|
||||
*
|
||||
* or, in the deprecated OldMove style:
|
||||
*
|
||||
* C c2(OldMove(c1));
|
||||
*
|
||||
* Note that MoveRef<T> implicitly converts to T&, so you can pass a MoveRef<T>
|
||||
* to an ordinary copy constructor for a type that doesn't support a special
|
||||
|
@ -82,7 +106,7 @@ namespace mozilla {
|
|||
* which runs this's destructor, and then applies the move constructor to
|
||||
* *this's memory. A typical definition:
|
||||
*
|
||||
* C& operator=(MoveRef<C> rhs) {
|
||||
* C& operator=(C&& rhs) { // or |MoveRef<C> rhs|
|
||||
* this->~C();
|
||||
* new(this) C(rhs);
|
||||
* return *this;
|
||||
|
@ -90,14 +114,14 @@ namespace mozilla {
|
|||
*
|
||||
* With that in place, one can write move assignments like this:
|
||||
*
|
||||
* c2 = Move(c1);
|
||||
* c2 = Move(c1); // or OldMove()
|
||||
*
|
||||
* This destroys c1, moves c1's value to c2, and leaves c1 in an undefined but
|
||||
* destructible state.
|
||||
*
|
||||
* This header file defines MoveRef and Move in the mozilla namespace. It's up
|
||||
* to individual containers to annotate moves as such, by calling Move; and it's
|
||||
* up to individual types to define move constructors.
|
||||
* This header file defines MoveRef, Move, and OldMove in the mozilla namespace.
|
||||
* It's up to individual containers to annotate moves as such, by calling Move
|
||||
* or OldMove; and it's up to individual types to define move constructors.
|
||||
*
|
||||
* One hint: if you're writing a move constructor where the type has members
|
||||
* that should be moved themselves, it's much nicer to write this:
|
||||
|
@ -125,14 +149,14 @@ class MoveRef
|
|||
|
||||
template<typename T>
|
||||
inline MoveRef<T>
|
||||
Move(T& t)
|
||||
OldMove(T& t)
|
||||
{
|
||||
return MoveRef<T>(t);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline MoveRef<T>
|
||||
Move(const T& t)
|
||||
OldMove(const T& t)
|
||||
{
|
||||
// With some versions of gcc, for a class C, there's an (incorrect) ambiguity
|
||||
// between the C(const C&) constructor and the default C(C&&) C++11 move
|
||||
|
@ -151,14 +175,45 @@ Move(const T& t)
|
|||
return MoveRef<T>(const_cast<T&>(t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Identical to std::Move(); this is necessary until our stlport supports
|
||||
* std::move().
|
||||
*/
|
||||
template<typename T>
|
||||
inline typename RemoveReference<T>::Type&&
|
||||
Move(T&& a)
|
||||
{
|
||||
return static_cast<typename RemoveReference<T>::Type&&>(a);
|
||||
}
|
||||
|
||||
/**
|
||||
* These two overloads are identidal to std::Forward(); they are necessary until
|
||||
* our stlport supports std::forward().
|
||||
*/
|
||||
template<typename T>
|
||||
inline T&&
|
||||
Forward(typename RemoveReference<T>::Type& a)
|
||||
{
|
||||
return static_cast<T&&>(a);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T&&
|
||||
Forward(typename RemoveReference<T>::Type&& t)
|
||||
{
|
||||
static_assert(!IsLvalueReference<T>::value,
|
||||
"misuse of Forward detected! try the other overload");
|
||||
return static_cast<T&&>(t);
|
||||
}
|
||||
|
||||
/** Swap |t| and |u| using move-construction if possible. */
|
||||
template<typename T>
|
||||
inline void
|
||||
Swap(T& t, T& u)
|
||||
{
|
||||
T tmp(Move(t));
|
||||
t = Move(u);
|
||||
u = Move(tmp);
|
||||
T tmp(OldMove(t));
|
||||
t = OldMove(u);
|
||||
u = OldMove(tmp);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
#ifndef mozilla_NullPtr_h
|
||||
#define mozilla_NullPtr_h
|
||||
|
||||
#include "mozilla/Compiler.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
# ifndef __has_extension
|
||||
# define __has_extension __has_feature
|
||||
|
@ -23,6 +21,7 @@
|
|||
# endif
|
||||
#elif defined(__GNUC__)
|
||||
# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
|
||||
# include "mozilla/Compiler.h"
|
||||
# if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0)
|
||||
# define MOZ_HAVE_CXX11_NULLPTR
|
||||
# endif
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* Compatibility with std::numeric_limits<char16_t>. */
|
||||
|
||||
#ifndef mozilla_NumericLimits_h
|
||||
#define mozilla_NumericLimits_h
|
||||
|
||||
#include "mozilla/Char16.h"
|
||||
|
||||
#include <limits>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* The NumericLimits class provides a compatibility layer with std::numeric_limits
|
||||
* for char16_t, otherwise it is exactly the same as std::numeric_limits.
|
||||
* Code which does not need std::numeric_limits<char16_t> should avoid using
|
||||
* NumericLimits.
|
||||
*/
|
||||
template<typename T>
|
||||
class NumericLimits : public std::numeric_limits<T>
|
||||
{
|
||||
};
|
||||
|
||||
#ifdef MOZ_CHAR16_IS_NOT_WCHAR
|
||||
template<>
|
||||
class NumericLimits<char16_t> : public std::numeric_limits<uint16_t>
|
||||
{
|
||||
// char16_t and uint16_t numeric limits should be exactly the same.
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_NumericLimits_h */
|
|
@ -24,7 +24,7 @@ namespace mozilla {
|
|||
|
||||
/** Set the contents of |t| to 0. */
|
||||
template<typename T>
|
||||
static void
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
PodZero(T* t)
|
||||
{
|
||||
memset(t, 0, sizeof(T));
|
||||
|
@ -32,7 +32,7 @@ PodZero(T* t)
|
|||
|
||||
/** Set the contents of |nelem| elements starting at |t| to 0. */
|
||||
template<typename T>
|
||||
static void
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
PodZero(T* t, size_t nelem)
|
||||
{
|
||||
/*
|
||||
|
@ -58,7 +58,7 @@ static void PodZero(T (&t)[N], size_t nelem) MOZ_DELETE;
|
|||
|
||||
/** Set the contents of the array |t| to zero. */
|
||||
template <class T, size_t N>
|
||||
static void
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
PodArrayZero(T (&t)[N])
|
||||
{
|
||||
memset(t, 0, N * sizeof(T));
|
||||
|
@ -69,7 +69,7 @@ PodArrayZero(T (&t)[N])
|
|||
* overlap.
|
||||
*/
|
||||
template<typename T>
|
||||
static void
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
PodAssign(T* dst, const T* src)
|
||||
{
|
||||
MOZ_ASSERT(dst != src);
|
||||
|
@ -83,7 +83,7 @@ PodAssign(T* dst, const T* src)
|
|||
* overlap!
|
||||
*/
|
||||
template<typename T>
|
||||
MOZ_ALWAYS_INLINE static void
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
PodCopy(T* dst, const T* src, size_t nelem)
|
||||
{
|
||||
MOZ_ASSERT(dst != src);
|
||||
|
@ -103,7 +103,7 @@ PodCopy(T* dst, const T* src, size_t nelem)
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
MOZ_ALWAYS_INLINE static void
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
PodCopy(volatile T* dst, const volatile T* src, size_t nelem)
|
||||
{
|
||||
MOZ_ASSERT(dst != src);
|
||||
|
@ -127,7 +127,7 @@ PodCopy(volatile T* dst, const volatile T* src, size_t nelem)
|
|||
* The arrays must not overlap!
|
||||
*/
|
||||
template <class T, size_t N>
|
||||
static void
|
||||
static MOZ_ALWAYS_INLINE void
|
||||
PodArrayCopy(T (&dst)[N], const T (&src)[N])
|
||||
{
|
||||
PodCopy(dst, src, N);
|
||||
|
@ -138,7 +138,7 @@ PodArrayCopy(T (&dst)[N], const T (&src)[N])
|
|||
* |len| elements at |two|.
|
||||
*/
|
||||
template<typename T>
|
||||
MOZ_ALWAYS_INLINE static bool
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
PodEqual(const T* one, const T* two, size_t len)
|
||||
{
|
||||
if (len < 128) {
|
||||
|
|
|
@ -68,18 +68,18 @@ class RefCounted
|
|||
|
||||
public:
|
||||
// Compatibility with nsRefPtr.
|
||||
void AddRef() {
|
||||
void AddRef() const {
|
||||
MOZ_ASSERT(refCnt >= 0);
|
||||
++refCnt;
|
||||
}
|
||||
|
||||
void Release() {
|
||||
void Release() const {
|
||||
MOZ_ASSERT(refCnt > 0);
|
||||
if (0 == --refCnt) {
|
||||
#ifdef DEBUG
|
||||
refCnt = detail::DEAD;
|
||||
#endif
|
||||
delete static_cast<T*>(this);
|
||||
delete static_cast<const T*>(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ class RefCounted
|
|||
}
|
||||
|
||||
private:
|
||||
typename Conditional<Atomicity == AtomicRefCount, Atomic<int>, int>::Type refCnt;
|
||||
mutable typename Conditional<Atomicity == AtomicRefCount, Atomic<int>, int>::Type refCnt;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -63,6 +63,9 @@ template<> struct IsIntegralHelper<long long> : TrueType {};
|
|||
template<> struct IsIntegralHelper<unsigned long long> : TrueType {};
|
||||
template<> struct IsIntegralHelper<bool> : TrueType {};
|
||||
template<> struct IsIntegralHelper<wchar_t> : TrueType {};
|
||||
#ifdef MOZ_CHAR16_IS_NOT_WCHAR
|
||||
template<> struct IsIntegralHelper<char16_t> : TrueType {};
|
||||
#endif
|
||||
|
||||
} /* namespace detail */
|
||||
|
||||
|
@ -218,6 +221,9 @@ template<> struct IsPod<bool> : TrueType {};
|
|||
template<> struct IsPod<float> : TrueType {};
|
||||
template<> struct IsPod<double> : TrueType {};
|
||||
template<> struct IsPod<wchar_t> : TrueType {};
|
||||
#ifdef MOZ_CHAR16_IS_NOT_WCHAR
|
||||
template<> struct IsPod<char16_t> : TrueType {};
|
||||
#endif
|
||||
template<typename T> struct IsPod<T*> : TrueType {};
|
||||
|
||||
namespace detail {
|
||||
|
@ -418,6 +424,16 @@ struct IsConvertible
|
|||
: IntegralConstant<bool, detail::ConvertibleTester<From, To>::value>
|
||||
{};
|
||||
|
||||
/**
|
||||
* Is IsLvalueReference<T> is true if its template param is T& and is false if
|
||||
* its type is T or T&&.
|
||||
*/
|
||||
template<typename T>
|
||||
struct IsLvalueReference : FalseType {};
|
||||
|
||||
template<typename T>
|
||||
struct IsLvalueReference<T&> : TrueType {};
|
||||
|
||||
/* 20.9.7 Transformations between types [meta.trans] */
|
||||
|
||||
/* 20.9.7.1 Const-volatile modifications [meta.trans.cv] */
|
||||
|
@ -478,6 +494,32 @@ struct RemoveCV
|
|||
|
||||
/* 20.9.7.2 Reference modifications [meta.trans.ref] */
|
||||
|
||||
/**
|
||||
* Converts reference types to the underlying types.
|
||||
*
|
||||
* mozilla::RemoveReference<T>::Type is T;
|
||||
* mozilla::RemoveReference<T&>::Type is T;
|
||||
* mozilla::RemoveReference<T&&>::Type is T;
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
struct RemoveReference
|
||||
{
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct RemoveReference<T&>
|
||||
{
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct RemoveReference<T&&>
|
||||
{
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
/* 20.9.7.3 Sign modifications [meta.trans.sign] */
|
||||
|
||||
template<bool B, typename T = void>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
# endif
|
||||
#elif defined(__GNUC__)
|
||||
# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
|
||||
# if MOZ_GCC_VERSION_AT_LEAST(4, 5, 1)
|
||||
# if MOZ_GCC_VERSION_AT_LEAST(4, 6, 3)
|
||||
# define MOZ_HAVE_CXX11_ENUM_TYPE
|
||||
# define MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
# endif
|
||||
|
@ -72,7 +72,7 @@
|
|||
* strongly-typed enumeration feature of C++11 ("enum class"). If supported
|
||||
* by the compiler, an enum defined using these macros will not be implicitly
|
||||
* converted to any other type, and its enumerators will be scoped using the
|
||||
* enumeration name. Place MOZ_BEGIN_ENUM_CLASS(EnumName, type) in place of
|
||||
* enumeration name. Place MOZ_BEGIN_ENUM_CLASS(EnumName [, type]) in place of
|
||||
* "enum EnumName {", and MOZ_END_ENUM_CLASS(EnumName) in place of the closing
|
||||
* "};". For example,
|
||||
*
|
||||
|
@ -87,10 +87,9 @@
|
|||
* fail. In other compilers, Enum itself will actually be defined as a class,
|
||||
* and some implicit conversions will fail while others will succeed.
|
||||
*
|
||||
* The type argument specifies the underlying type for the enum where
|
||||
* supported, as with MOZ_ENUM_TYPE(). For simplicity, it is currently
|
||||
* mandatory. As with MOZ_ENUM_TYPE(), it will do nothing on compilers that do
|
||||
* not support it.
|
||||
* The optional type argument specifies the underlying type for the enum where
|
||||
* supported, as with MOZ_ENUM_TYPE(). As with MOZ_ENUM_TYPE(), it will do
|
||||
* nothing on compilers that do not support it.
|
||||
*
|
||||
* MOZ_{BEGIN,END}_ENUM_CLASS doesn't work for defining enum classes nested
|
||||
* inside classes. To define an enum class nested inside another class, use
|
||||
|
@ -114,7 +113,12 @@
|
|||
* All compilers that support strong enums also support an explicit
|
||||
* underlying type, so no extra check is needed.
|
||||
*/
|
||||
# define MOZ_BEGIN_NESTED_ENUM_CLASS(Name, type) \
|
||||
|
||||
/* Single-argument form. */
|
||||
# define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER1(Name) \
|
||||
enum class Name {
|
||||
/* Two-argument form. */
|
||||
# define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER2(Name, type) \
|
||||
enum class Name : type {
|
||||
# define MOZ_END_NESTED_ENUM_CLASS(Name) \
|
||||
};
|
||||
|
@ -154,8 +158,17 @@
|
|||
* {
|
||||
* return Enum::A;
|
||||
* }
|
||||
*/\
|
||||
# define MOZ_BEGIN_NESTED_ENUM_CLASS(Name, type) \
|
||||
*/
|
||||
|
||||
/* Single-argument form. */
|
||||
# define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER1(Name) \
|
||||
class Name \
|
||||
{ \
|
||||
public: \
|
||||
enum Enum \
|
||||
{
|
||||
/* Two-argument form. */
|
||||
# define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER2(Name, type) \
|
||||
class Name \
|
||||
{ \
|
||||
public: \
|
||||
|
@ -226,7 +239,36 @@
|
|||
inline int& operator<<=(int&, const Name::Enum&) MOZ_DELETE; \
|
||||
inline int& operator>>=(int&, const Name::Enum&) MOZ_DELETE;
|
||||
#endif
|
||||
# define MOZ_BEGIN_ENUM_CLASS(Name, type) MOZ_BEGIN_NESTED_ENUM_CLASS(Name, type)
|
||||
|
||||
/*
|
||||
* Count the number of arguments passed to MOZ_COUNT_BEGIN_ENUM_CLASS_ARGS,
|
||||
* very carefully tiptoeing around an MSVC bug where it improperly expands
|
||||
* __VA_ARGS__ as a single token in argument lists. See these URLs for
|
||||
* details:
|
||||
*
|
||||
* http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement
|
||||
* http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644
|
||||
*/
|
||||
# define MOZ_COUNT_BEGIN_ENUM_CLASS_ARGS_IMPL2(_1, _2, count, ...) \
|
||||
count
|
||||
# define MOZ_COUNT_BEGIN_ENUM_CLASS_ARGS_IMPL(args) \
|
||||
MOZ_COUNT_BEGIN_ENUM_CLASS_ARGS_IMPL2 args
|
||||
# define MOZ_COUNT_BEGIN_ENUM_CLASS_ARGS(...) \
|
||||
MOZ_COUNT_BEGIN_ENUM_CLASS_ARGS_IMPL((__VA_ARGS__, 2, 1, 0))
|
||||
/* Pick the right helper macro to invoke. */
|
||||
# define MOZ_BEGIN_NESTED_ENUM_CLASS_CHOOSE_HELPER2(count) \
|
||||
MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER##count
|
||||
# define MOZ_BEGIN_NESTED_ENUM_CLASS_CHOOSE_HELPER1(count) \
|
||||
MOZ_BEGIN_NESTED_ENUM_CLASS_CHOOSE_HELPER2(count)
|
||||
# define MOZ_BEGIN_NESTED_ENUM_CLASS_CHOOSE_HELPER(count) \
|
||||
MOZ_BEGIN_NESTED_ENUM_CLASS_CHOOSE_HELPER1(count)
|
||||
/* The actual macro. */
|
||||
# define MOZ_BEGIN_NESTED_ENUM_CLASS_GLUE(x, y) x y
|
||||
# define MOZ_BEGIN_NESTED_ENUM_CLASS(...) \
|
||||
MOZ_BEGIN_NESTED_ENUM_CLASS_GLUE(MOZ_BEGIN_NESTED_ENUM_CLASS_CHOOSE_HELPER(MOZ_COUNT_BEGIN_ENUM_CLASS_ARGS(__VA_ARGS__)), \
|
||||
(__VA_ARGS__))
|
||||
|
||||
# define MOZ_BEGIN_ENUM_CLASS(...) MOZ_BEGIN_NESTED_ENUM_CLASS(__VA_ARGS__)
|
||||
# define MOZ_END_ENUM_CLASS(Name) \
|
||||
MOZ_END_NESTED_ENUM_CLASS(Name) \
|
||||
MOZ_FINISH_NESTED_ENUM_CLASS(Name)
|
||||
|
|
|
@ -18,267 +18,10 @@
|
|||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "mozilla/Alignment.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/*
|
||||
* This class, and the corresponding macro MOZ_ALIGNOF, figure out how many
|
||||
* bytes of alignment a given type needs.
|
||||
*/
|
||||
template<class T>
|
||||
class AlignmentFinder
|
||||
{
|
||||
struct Aligner
|
||||
{
|
||||
char c;
|
||||
T t;
|
||||
};
|
||||
|
||||
public:
|
||||
static const size_t alignment = sizeof(Aligner) - sizeof(T);
|
||||
};
|
||||
|
||||
#define MOZ_ALIGNOF(T) mozilla::AlignmentFinder<T>::alignment
|
||||
|
||||
/*
|
||||
* Declare the MOZ_ALIGNED_DECL macro for declaring aligned types.
|
||||
*
|
||||
* For instance,
|
||||
*
|
||||
* MOZ_ALIGNED_DECL(char arr[2], 8);
|
||||
*
|
||||
* will declare a two-character array |arr| aligned to 8 bytes.
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define MOZ_ALIGNED_DECL(_type, _align) \
|
||||
_type __attribute__((aligned(_align)))
|
||||
#elif defined(_MSC_VER)
|
||||
# define MOZ_ALIGNED_DECL(_type, _align) \
|
||||
__declspec(align(_align)) _type
|
||||
#else
|
||||
# warning "We don't know how to align variables on this compiler."
|
||||
# define MOZ_ALIGNED_DECL(_type, _align) _type
|
||||
#endif
|
||||
|
||||
/*
|
||||
* AlignedElem<N> is a structure whose alignment is guaranteed to be at least N
|
||||
* bytes.
|
||||
*
|
||||
* We support 1, 2, 4, 8, and 16-bit alignment.
|
||||
*/
|
||||
template<size_t align>
|
||||
struct AlignedElem;
|
||||
|
||||
/*
|
||||
* We have to specialize this template because GCC doesn't like __attribute__((aligned(foo))) where
|
||||
* foo is a template parameter.
|
||||
*/
|
||||
|
||||
template<>
|
||||
struct AlignedElem<1>
|
||||
{
|
||||
MOZ_ALIGNED_DECL(uint8_t elem, 1);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AlignedElem<2>
|
||||
{
|
||||
MOZ_ALIGNED_DECL(uint8_t elem, 2);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AlignedElem<4>
|
||||
{
|
||||
MOZ_ALIGNED_DECL(uint8_t elem, 4);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AlignedElem<8>
|
||||
{
|
||||
MOZ_ALIGNED_DECL(uint8_t elem, 8);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AlignedElem<16>
|
||||
{
|
||||
MOZ_ALIGNED_DECL(uint8_t elem, 16);
|
||||
};
|
||||
|
||||
/*
|
||||
* This utility pales in comparison to Boost's aligned_storage. The utility
|
||||
* simply assumes that uint64_t is enough alignment for anyone. This may need
|
||||
* to be extended one day...
|
||||
*
|
||||
* As an important side effect, pulling the storage into this template is
|
||||
* enough obfuscation to confuse gcc's strict-aliasing analysis into not giving
|
||||
* false negatives when we cast from the char buffer to whatever type we've
|
||||
* constructed using the bytes.
|
||||
*/
|
||||
template<size_t nbytes>
|
||||
struct AlignedStorage
|
||||
{
|
||||
union U {
|
||||
char bytes[nbytes];
|
||||
uint64_t _;
|
||||
} u;
|
||||
|
||||
const void* addr() const { return u.bytes; }
|
||||
void* addr() { return u.bytes; }
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct AlignedStorage2
|
||||
{
|
||||
union U {
|
||||
char bytes[sizeof(T)];
|
||||
uint64_t _;
|
||||
} u;
|
||||
|
||||
const T* addr() const { return reinterpret_cast<const T*>(u.bytes); }
|
||||
T* addr() { return static_cast<T*>(static_cast<void*>(u.bytes)); }
|
||||
};
|
||||
|
||||
/*
|
||||
* Small utility for lazily constructing objects without using dynamic storage.
|
||||
* When a Maybe<T> is constructed, it is |empty()|, i.e., no value of T has
|
||||
* been constructed and no T destructor will be called when the Maybe<T> is
|
||||
* destroyed. Upon calling |construct|, a T object will be constructed with the
|
||||
* given arguments and that object will be destroyed when the owning Maybe<T>
|
||||
* is destroyed.
|
||||
*
|
||||
* N.B. GCC seems to miss some optimizations with Maybe and may generate extra
|
||||
* branches/loads/stores. Use with caution on hot paths.
|
||||
*/
|
||||
template<class T>
|
||||
class Maybe
|
||||
{
|
||||
AlignedStorage2<T> storage;
|
||||
bool constructed;
|
||||
|
||||
T& asT() { return *storage.addr(); }
|
||||
|
||||
public:
|
||||
Maybe() { constructed = false; }
|
||||
~Maybe() { if (constructed) asT().~T(); }
|
||||
|
||||
bool empty() const { return !constructed; }
|
||||
|
||||
void construct() {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T();
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1>
|
||||
void construct(const T1& t1) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2>
|
||||
void construct(const T1& t1, const T2& t2) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3, class T4>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3, t4);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3, class T4, class T5>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3, t4, t5);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3, class T4, class T5,
|
||||
class T6>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5,
|
||||
const T6& t6) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3, t4, t5, t6);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3, class T4, class T5,
|
||||
class T6, class T7>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5,
|
||||
const T6& t6, const T7& t7) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3, class T4, class T5,
|
||||
class T6, class T7, class T8>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5,
|
||||
const T6& t6, const T7& t7, const T8& t8) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7, t8);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3, class T4, class T5,
|
||||
class T6, class T7, class T8, class T9>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5,
|
||||
const T6& t6, const T7& t7, const T8& t8, const T9& t9) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7, t8, t9);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
template<class T1, class T2, class T3, class T4, class T5,
|
||||
class T6, class T7, class T8, class T9, class T10>
|
||||
void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5,
|
||||
const T6& t6, const T7& t7, const T8& t8, const T9& t9, const T10& t10) {
|
||||
MOZ_ASSERT(!constructed);
|
||||
::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
T* addr() {
|
||||
MOZ_ASSERT(constructed);
|
||||
return &asT();
|
||||
}
|
||||
|
||||
T& ref() {
|
||||
MOZ_ASSERT(constructed);
|
||||
return asT();
|
||||
}
|
||||
|
||||
const T& ref() const {
|
||||
MOZ_ASSERT(constructed);
|
||||
return const_cast<Maybe*>(this)->asT();
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
ref().~T();
|
||||
constructed = false;
|
||||
}
|
||||
|
||||
void destroyIfConstructed() {
|
||||
if (!empty())
|
||||
destroy();
|
||||
}
|
||||
|
||||
private:
|
||||
Maybe(const Maybe& other) MOZ_DELETE;
|
||||
const Maybe& operator=(const Maybe& other) MOZ_DELETE;
|
||||
};
|
||||
|
||||
/*
|
||||
* Safely subtract two pointers when it is known that end >= begin. This avoids
|
||||
* the common compiler bug that if (size_t(end) - size_t(begin)) has the MSB
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef mozilla_Vector_h
|
||||
#define mozilla_Vector_h
|
||||
|
||||
#include "mozilla/Alignment.h"
|
||||
#include "mozilla/AllocPolicy.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
@ -19,7 +20,7 @@
|
|||
#include "mozilla/ReentrancyGuard.h"
|
||||
#include "mozilla/TemplateLib.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "mozilla/Util.h" // for PointerRangeSize
|
||||
|
||||
#include <new> // for placement new
|
||||
|
||||
|
@ -85,7 +86,7 @@ struct VectorImpl
|
|||
template<typename U>
|
||||
static inline void moveConstruct(T* dst, const U* srcbeg, const U* srcend) {
|
||||
for (const U* p = srcbeg; p < srcend; ++p, ++dst)
|
||||
new(dst) T(Move(*p));
|
||||
new(dst) T(OldMove(*p));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -114,7 +115,7 @@ struct VectorImpl
|
|||
T* dst = newbuf;
|
||||
T* src = v.beginNoCheck();
|
||||
for (; src < v.endNoCheck(); ++dst, ++src)
|
||||
new(dst) T(Move(*src));
|
||||
new(dst) T(OldMove(*src));
|
||||
VectorImpl::destroy(v.beginNoCheck(), v.endNoCheck());
|
||||
v.free_(v.mBegin);
|
||||
v.mBegin = newbuf;
|
||||
|
@ -547,8 +548,8 @@ class VectorBase : private AllocPolicy
|
|||
void swap(ThisVector& other);
|
||||
|
||||
private:
|
||||
VectorBase(const ThisVector&) MOZ_DELETE;
|
||||
void operator=(const ThisVector&) MOZ_DELETE;
|
||||
VectorBase(const VectorBase&) MOZ_DELETE;
|
||||
void operator=(const VectorBase&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
/* This does the re-entrancy check plus several other sanity checks. */
|
||||
|
@ -565,14 +566,15 @@ template<typename T, size_t N, class AP, class TV>
|
|||
MOZ_ALWAYS_INLINE
|
||||
VectorBase<T, N, AP, TV>::VectorBase(AP ap)
|
||||
: AP(ap),
|
||||
mBegin(static_cast<T*>(storage.addr())),
|
||||
mLength(0),
|
||||
mCapacity(sInlineCapacity)
|
||||
#ifdef DEBUG
|
||||
, mReserved(sInlineCapacity),
|
||||
entered(false)
|
||||
#endif
|
||||
{}
|
||||
{
|
||||
mBegin = static_cast<T*>(storage.addr());
|
||||
}
|
||||
|
||||
/* Move constructor. */
|
||||
template<typename T, size_t N, class AllocPolicy, class TV>
|
||||
|
|
|
@ -14,9 +14,6 @@
|
|||
* the WeakPtrs to it and allows the WeakReference to live beyond the lifetime
|
||||
* of 'Foo'.
|
||||
*
|
||||
* AtomicSupportsWeakPtr can be used for a variant with an atomically updated
|
||||
* reference counter.
|
||||
*
|
||||
* The overhead of WeakPtr is that accesses to 'Foo' becomes an additional
|
||||
* dereference, and an additional heap allocated pointer sized object shared
|
||||
* between all of the WeakPtrs.
|
||||
|
@ -63,7 +60,6 @@
|
|||
#define mozilla_WeakPtr_h
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
@ -76,8 +72,8 @@ template <typename T, class WeakReference> class SupportsWeakPtrBase;
|
|||
namespace detail {
|
||||
|
||||
// This can live beyond the lifetime of the class derived from SupportsWeakPtrBase.
|
||||
template<class T, RefCountAtomicity Atomicity>
|
||||
class WeakReference : public RefCounted<WeakReference<T, Atomicity>, Atomicity>
|
||||
template<class T>
|
||||
class WeakReference : public ::mozilla::RefCounted<WeakReference<T> >
|
||||
{
|
||||
public:
|
||||
explicit WeakReference(T* p) : ptr(p) {}
|
||||
|
@ -86,8 +82,8 @@ class WeakReference : public RefCounted<WeakReference<T, Atomicity>, Atomicity>
|
|||
}
|
||||
|
||||
private:
|
||||
friend class WeakPtrBase<T, WeakReference>;
|
||||
friend class SupportsWeakPtrBase<T, WeakReference>;
|
||||
friend class WeakPtrBase<T, WeakReference<T> >;
|
||||
friend class SupportsWeakPtrBase<T, WeakReference<T> >;
|
||||
void detach() {
|
||||
ptr = nullptr;
|
||||
}
|
||||
|
@ -121,30 +117,10 @@ class SupportsWeakPtrBase
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
class SupportsWeakPtr
|
||||
: public SupportsWeakPtrBase<T, detail::WeakReference<T, detail::NonAtomicRefCount> >
|
||||
class SupportsWeakPtr : public SupportsWeakPtrBase<T, detail::WeakReference<T> >
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class AtomicSupportsWeakPtr
|
||||
: public SupportsWeakPtrBase<T, detail::WeakReference<T, detail::AtomicRefCount> >
|
||||
{
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct WeakReferenceCount
|
||||
{
|
||||
static const RefCountAtomicity atomicity =
|
||||
IsBaseOf<AtomicSupportsWeakPtr<T>, T>::value
|
||||
? AtomicRefCount
|
||||
: NonAtomicRefCount;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <typename T, class WeakReference>
|
||||
class WeakPtrBase
|
||||
{
|
||||
|
@ -177,9 +153,9 @@ class WeakPtrBase
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
class WeakPtr : public WeakPtrBase<T, detail::WeakReference<T, detail::WeakReferenceCount<T>::atomicity> >
|
||||
class WeakPtr : public WeakPtrBase<T, detail::WeakReference<T> >
|
||||
{
|
||||
typedef WeakPtrBase<T, detail::WeakReference<T, detail::WeakReferenceCount<T>::atomicity> > Base;
|
||||
typedef WeakPtrBase<T, detail::WeakReference<T> > Base;
|
||||
public:
|
||||
WeakPtr(const WeakPtr<T>& o) : Base(o) {}
|
||||
WeakPtr(const Base& o) : Base(o) {}
|
||||
|
|
|
@ -1 +1 @@
|
|||
0e1091b9f67b4d348d01b69e998be70c9e0b2dad
|
||||
4b3fc16c923b538ff3a3d9e92edb34f7f3667c7d
|
|
@ -1 +1 @@
|
|||
23bfd06f14371832fa99b4efb76133ade10887ec
|
||||
dcc9ffddbaadb4ee17587e6aaf603411a3e01c20
|
|
@ -1 +1 @@
|
|||
1eb9de4a5ab182f329be479e736c06ac8ab83a00
|
||||
6f92f63db1d08b638c61e8ca9fe26f90358a21f6
|
Loading…
Reference in New Issue