issue #3900: Adds spidermonkey v27 library for Android.

This commit is contained in:
James Chen 2014-02-07 14:21:41 +08:00
parent 90c4a63677
commit 20ab9daa3a
67 changed files with 4238 additions and 2708 deletions

View File

@ -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 */

View File

@ -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")

View File

@ -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 {

View File

@ -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);

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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;

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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;

View File

@ -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 */

View File

@ -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_; }

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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)

View File

@ -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 */

View File

@ -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;
}

View File

@ -1 +1 @@
e14ea931f699b1808c06886e55e977c9819f3774
38fc2004d49d7c513aff0f7f43d79524ec667c2c

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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, ...);

View File

@ -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 */

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -1,385 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* 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 */

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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(); \

View File

@ -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=;

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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_ */

View File

@ -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));
}

View File

@ -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 */

View File

@ -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!

View File

@ -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_ */

View File

@ -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 */
}

View File

@ -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_ ]

View File

@ -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)

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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) {

View File

@ -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;
};
}

View File

@ -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>

View File

@ -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)

View File

@ -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

View File

@ -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>

View File

@ -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) {}

View File

@ -1 +1 @@
0e1091b9f67b4d348d01b69e998be70c9e0b2dad
4b3fc16c923b538ff3a3d9e92edb34f7f3667c7d

View File

@ -1 +1 @@
23bfd06f14371832fa99b4efb76133ade10887ec
dcc9ffddbaadb4ee17587e6aaf603411a3e01c20

View File

@ -1 +1 @@
1eb9de4a5ab182f329be479e736c06ac8ab83a00
6f92f63db1d08b638c61e8ca9fe26f90358a21f6