mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 837773 - Move JS::Anchor into js/public/Anchor.h, necessary to properly make Value.h an independent header. r=jorendorff
--HG-- rename : js/src/jsval.h => js/public/Value.h extra : rebase_source : c109f562aea18e7466b6af6fd1dd2efae11b0333
This commit is contained in:
parent
3eea5b83c2
commit
69cc8dd4d8
163
js/public/Anchor.h
Normal file
163
js/public/Anchor.h
Normal file
@ -0,0 +1,163 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* JS::Anchor implementation. */
|
||||
|
||||
#ifndef js_Anchor_h___
|
||||
#define js_Anchor_h___
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class JSFunction;
|
||||
class JSObject;
|
||||
class JSScript;
|
||||
class JSString;
|
||||
|
||||
namespace JS { class Value; }
|
||||
|
||||
namespace JS {
|
||||
|
||||
/*
|
||||
* Protecting non-Value, non-JSObject *, non-JSString * values from collection
|
||||
*
|
||||
* Most of the time, the garbage collector's conservative stack scanner works
|
||||
* behind the scenes, finding all live values and protecting them from being
|
||||
* collected. However, when JSAPI client code obtains a pointer to data the
|
||||
* scanner does not know about, owned by an object the scanner does know about,
|
||||
* Care Must Be Taken.
|
||||
*
|
||||
* The scanner recognizes only a select set of types: pointers to JSObjects and
|
||||
* similar things (JSFunctions, and so on), pointers to JSStrings, and Values.
|
||||
* So while the scanner finds all live |JSString| pointers, it does not notice
|
||||
* |jschar| pointers.
|
||||
*
|
||||
* So suppose we have:
|
||||
*
|
||||
* void f(JSString *str) {
|
||||
* const jschar *ch = JS_GetStringCharsZ(str);
|
||||
* ... do stuff with ch, but no uses of str ...;
|
||||
* }
|
||||
*
|
||||
* After the call to |JS_GetStringCharsZ|, there are no further uses of
|
||||
* |str|, which means that the compiler is within its rights to not store
|
||||
* it anywhere. But because the stack scanner will not notice |ch|, there
|
||||
* is no longer any live value in this frame that would keep the string
|
||||
* alive. If |str| is the last reference to that |JSString|, and the
|
||||
* collector runs while we are using |ch|, the string's array of |jschar|s
|
||||
* may be freed out from under us.
|
||||
*
|
||||
* Note that there is only an issue when 1) we extract a thing X the scanner
|
||||
* doesn't recognize from 2) a thing Y the scanner does recognize, and 3) if Y
|
||||
* gets garbage-collected, then X gets freed. If we have code like this:
|
||||
*
|
||||
* void g(JSObject *obj) {
|
||||
* JS::Value x;
|
||||
* JS_GetProperty(obj, "x", &x);
|
||||
* ... do stuff with x ...
|
||||
* }
|
||||
*
|
||||
* there's no problem, because the value we've extracted, x, is a Value, a
|
||||
* type that the conservative scanner recognizes.
|
||||
*
|
||||
* Conservative GC frees us from the obligation to explicitly root the types it
|
||||
* knows about, but when we work with derived values like |ch|, we must root
|
||||
* their owners, as the derived value alone won't keep them alive.
|
||||
*
|
||||
* A JS::Anchor is a kind of GC root that allows us to keep the owners of
|
||||
* derived values like |ch| alive throughout the Anchor's lifetime. We could
|
||||
* fix the above code as follows:
|
||||
*
|
||||
* void f(JSString *str) {
|
||||
* JS::Anchor<JSString *> a_str(str);
|
||||
* const jschar *ch = JS_GetStringCharsZ(str);
|
||||
* ... do stuff with ch, but no uses of str ...;
|
||||
* }
|
||||
*
|
||||
* This simply ensures that |str| will be live until |a_str| goes out of scope.
|
||||
* As long as we don't retain a pointer to the string's characters for longer
|
||||
* than that, we have avoided all garbage collection hazards.
|
||||
*/
|
||||
template<typename T> class AnchorPermitted;
|
||||
template<> class AnchorPermitted<JSObject *> { };
|
||||
template<> class AnchorPermitted<const JSObject *> { };
|
||||
template<> class AnchorPermitted<JSFunction *> { };
|
||||
template<> class AnchorPermitted<const JSFunction *> { };
|
||||
template<> class AnchorPermitted<JSString *> { };
|
||||
template<> class AnchorPermitted<const JSString *> { };
|
||||
template<> class AnchorPermitted<Value> { };
|
||||
template<> class AnchorPermitted<const JSScript *> { };
|
||||
template<> class AnchorPermitted<JSScript *> { };
|
||||
|
||||
template<typename T>
|
||||
class Anchor : AnchorPermitted<T>
|
||||
{
|
||||
public:
|
||||
Anchor() { }
|
||||
explicit Anchor(T t) { hold = t; }
|
||||
inline ~Anchor();
|
||||
T &get() { return hold; }
|
||||
const T &get() const { return hold; }
|
||||
void set(const T &t) { hold = t; }
|
||||
void operator=(const T &t) { hold = t; }
|
||||
void clear() { hold = 0; }
|
||||
|
||||
private:
|
||||
T hold;
|
||||
Anchor(const Anchor &other) MOZ_DELETE;
|
||||
void operator=(const Anchor &other) MOZ_DELETE;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline Anchor<T>::~Anchor()
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
/*
|
||||
* No code is generated for this. But because this is marked 'volatile', G++ will
|
||||
* assume it has important side-effects, and won't delete it. (G++ never looks at
|
||||
* the actual text and notices it's empty.) And because we have passed |hold| to
|
||||
* it, GCC will keep |hold| alive until this point.
|
||||
*
|
||||
* The "memory" clobber operand ensures that G++ will not move prior memory
|
||||
* accesses after the asm --- it's a barrier. Unfortunately, it also means that
|
||||
* G++ will assume that all memory has changed after the asm, as it would for a
|
||||
* call to an unknown function. I don't know of a way to avoid that consequence.
|
||||
*/
|
||||
asm volatile("":: "g" (hold) : "memory");
|
||||
#else
|
||||
/*
|
||||
* An adequate portable substitute, for non-structure types.
|
||||
*
|
||||
* The compiler promises that, by the end of an expression statement, the
|
||||
* last-stored value to a volatile object is the same as it would be in an
|
||||
* unoptimized, direct implementation (the "abstract machine" whose behavior the
|
||||
* language spec describes). However, the compiler is still free to reorder
|
||||
* non-volatile accesses across this store --- which is what we must prevent. So
|
||||
* assigning the held value to a volatile variable, as we do here, is not enough.
|
||||
*
|
||||
* In our case, however, garbage collection only occurs at function calls, so it
|
||||
* is sufficient to ensure that the destructor's store isn't moved earlier across
|
||||
* any function calls that could collect. It is hard to imagine the compiler
|
||||
* analyzing the program so thoroughly that it could prove that such motion was
|
||||
* safe. In practice, compilers treat calls to the collector as opaque operations
|
||||
* --- in particular, as operations which could access volatile variables, across
|
||||
* which this destructor must not be moved.
|
||||
*
|
||||
* ("Objection, your honor! *Alleged* killer whale!")
|
||||
*
|
||||
* The disadvantage of this approach is that it does generate code for the store.
|
||||
* We do need to use Anchors in some cases where cycles are tight.
|
||||
*
|
||||
* Note that there is a Anchor<Value>::~Anchor() specialization in Value.h.
|
||||
*/
|
||||
volatile T sink;
|
||||
sink = hold;
|
||||
#endif /* defined(__GNUC__) */
|
||||
}
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#endif /* js_Anchor_h___ */
|
@ -10,6 +10,7 @@
|
||||
#ifndef js_Value_h___
|
||||
#define js_Value_h___
|
||||
|
||||
#include "js/Anchor.h"
|
||||
#include "js/Utility.h"
|
||||
|
||||
/*
|
||||
@ -836,4 +837,28 @@ static jsval_layout JSVAL_TO_IMPL(JS::Value);
|
||||
static JS::Value IMPL_TO_JSVAL(jsval_layout);
|
||||
#endif
|
||||
|
||||
namespace JS {
|
||||
|
||||
#ifndef __GNUC__
|
||||
/*
|
||||
* The default assignment operator for |struct C| has the signature:
|
||||
*
|
||||
* C& C::operator=(const C&)
|
||||
*
|
||||
* And in particular requires implicit conversion of |this| to type |C| for the
|
||||
* return value. But |volatile C| cannot thus be converted to |C|, so just
|
||||
* doing |sink = hold| as in the non-specialized version would fail to compile.
|
||||
* Do the assignment on asBits instead, since I don't think we want to give
|
||||
* jsval_layout an assignment operator returning |volatile jsval_layout|.
|
||||
*/
|
||||
template<>
|
||||
inline Anchor<Value>::~Anchor()
|
||||
{
|
||||
volatile uint64_t bits;
|
||||
bits = JSVAL_TO_IMPL(hold).asBits;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#endif /* js_Value_h___ */
|
||||
|
@ -223,10 +223,11 @@ EXPORTS_NAMESPACES += js
|
||||
# that we ensure we don't over-expose our internal integer typedefs. Note that
|
||||
# LegacyIntTypes.h below is deliberately exempted from this requirement.
|
||||
EXPORTS_js = \
|
||||
Anchor.h \
|
||||
CharacterEncoding.h \
|
||||
GCAPI.h \
|
||||
HashTable.h \
|
||||
HeapAPI.h \
|
||||
GCAPI.h \
|
||||
LegacyIntTypes.h \
|
||||
MemoryMetrics.h \
|
||||
TemplateLib.h \
|
||||
|
@ -17,6 +17,9 @@
|
||||
#include "jspubtd.h"
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "js/Anchor.h"
|
||||
#include "js/CharacterEncoding.h"
|
||||
#include "js/GCAPI.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/HeapAPI.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
|
163
js/src/jsapi.h
163
js/src/jsapi.h
@ -27,6 +27,7 @@
|
||||
#include "jsutil.h"
|
||||
|
||||
#include "gc/Root.h"
|
||||
#include "js/Anchor.h"
|
||||
#include "js/CharacterEncoding.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/Utility.h"
|
||||
@ -56,146 +57,6 @@ class StableCharPtr : public CharPtr {
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* Protecting non-jsval, non-JSObject *, non-JSString * values from collection
|
||||
*
|
||||
* Most of the time, the garbage collector's conservative stack scanner works
|
||||
* behind the scenes, finding all live values and protecting them from being
|
||||
* collected. However, when JSAPI client code obtains a pointer to data the
|
||||
* scanner does not know about, owned by an object the scanner does know about,
|
||||
* Care Must Be Taken.
|
||||
*
|
||||
* The scanner recognizes only a select set of types: pointers to JSObjects and
|
||||
* similar things (JSFunctions, and so on), pointers to JSStrings, and jsvals.
|
||||
* So while the scanner finds all live |JSString| pointers, it does not notice
|
||||
* |jschar| pointers.
|
||||
*
|
||||
* So suppose we have:
|
||||
*
|
||||
* void f(JSString *str) {
|
||||
* const jschar *ch = JS_GetStringCharsZ(str);
|
||||
* ... do stuff with ch, but no uses of str ...;
|
||||
* }
|
||||
*
|
||||
* After the call to |JS_GetStringCharsZ|, there are no further uses of
|
||||
* |str|, which means that the compiler is within its rights to not store
|
||||
* it anywhere. But because the stack scanner will not notice |ch|, there
|
||||
* is no longer any live value in this frame that would keep the string
|
||||
* alive. If |str| is the last reference to that |JSString|, and the
|
||||
* collector runs while we are using |ch|, the string's array of |jschar|s
|
||||
* may be freed out from under us.
|
||||
*
|
||||
* Note that there is only an issue when 1) we extract a thing X the scanner
|
||||
* doesn't recognize from 2) a thing Y the scanner does recognize, and 3) if Y
|
||||
* gets garbage-collected, then X gets freed. If we have code like this:
|
||||
*
|
||||
* void g(JSObject *obj) {
|
||||
* jsval x;
|
||||
* JS_GetProperty(obj, "x", &x);
|
||||
* ... do stuff with x ...
|
||||
* }
|
||||
*
|
||||
* there's no problem, because the value we've extracted, x, is a jsval, a
|
||||
* type that the conservative scanner recognizes.
|
||||
*
|
||||
* Conservative GC frees us from the obligation to explicitly root the types it
|
||||
* knows about, but when we work with derived values like |ch|, we must root
|
||||
* their owners, as the derived value alone won't keep them alive.
|
||||
*
|
||||
* A JS::Anchor is a kind of GC root that allows us to keep the owners of
|
||||
* derived values like |ch| alive throughout the Anchor's lifetime. We could
|
||||
* fix the above code as follows:
|
||||
*
|
||||
* void f(JSString *str) {
|
||||
* JS::Anchor<JSString *> a_str(str);
|
||||
* const jschar *ch = JS_GetStringCharsZ(str);
|
||||
* ... do stuff with ch, but no uses of str ...;
|
||||
* }
|
||||
*
|
||||
* This simply ensures that |str| will be live until |a_str| goes out of scope.
|
||||
* As long as we don't retain a pointer to the string's characters for longer
|
||||
* than that, we have avoided all garbage collection hazards.
|
||||
*/
|
||||
template<typename T> class AnchorPermitted;
|
||||
template<> class AnchorPermitted<JSObject *> { };
|
||||
template<> class AnchorPermitted<const JSObject *> { };
|
||||
template<> class AnchorPermitted<JSFunction *> { };
|
||||
template<> class AnchorPermitted<const JSFunction *> { };
|
||||
template<> class AnchorPermitted<JSString *> { };
|
||||
template<> class AnchorPermitted<const JSString *> { };
|
||||
template<> class AnchorPermitted<Value> { };
|
||||
template<> class AnchorPermitted<const JSScript *> { };
|
||||
template<> class AnchorPermitted<JSScript *> { };
|
||||
|
||||
template<typename T>
|
||||
class Anchor: AnchorPermitted<T>
|
||||
{
|
||||
public:
|
||||
Anchor() { }
|
||||
explicit Anchor(T t) { hold = t; }
|
||||
inline ~Anchor();
|
||||
T &get() { return hold; }
|
||||
const T &get() const { return hold; }
|
||||
void set(const T &t) { hold = t; }
|
||||
void operator=(const T &t) { hold = t; }
|
||||
void clear() { hold = 0; }
|
||||
private:
|
||||
T hold;
|
||||
Anchor(const Anchor &) MOZ_DELETE;
|
||||
const Anchor &operator=(const Anchor &) MOZ_DELETE;
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
template<typename T>
|
||||
inline Anchor<T>::~Anchor()
|
||||
{
|
||||
/*
|
||||
* No code is generated for this. But because this is marked 'volatile', G++ will
|
||||
* assume it has important side-effects, and won't delete it. (G++ never looks at
|
||||
* the actual text and notices it's empty.) And because we have passed |hold| to
|
||||
* it, GCC will keep |hold| alive until this point.
|
||||
*
|
||||
* The "memory" clobber operand ensures that G++ will not move prior memory
|
||||
* accesses after the asm --- it's a barrier. Unfortunately, it also means that
|
||||
* G++ will assume that all memory has changed after the asm, as it would for a
|
||||
* call to an unknown function. I don't know of a way to avoid that consequence.
|
||||
*/
|
||||
asm volatile("":: "g" (hold) : "memory");
|
||||
}
|
||||
#else
|
||||
template<typename T>
|
||||
inline Anchor<T>::~Anchor()
|
||||
{
|
||||
/*
|
||||
* An adequate portable substitute, for non-structure types.
|
||||
*
|
||||
* The compiler promises that, by the end of an expression statement, the
|
||||
* last-stored value to a volatile object is the same as it would be in an
|
||||
* unoptimized, direct implementation (the "abstract machine" whose behavior the
|
||||
* language spec describes). However, the compiler is still free to reorder
|
||||
* non-volatile accesses across this store --- which is what we must prevent. So
|
||||
* assigning the held value to a volatile variable, as we do here, is not enough.
|
||||
*
|
||||
* In our case, however, garbage collection only occurs at function calls, so it
|
||||
* is sufficient to ensure that the destructor's store isn't moved earlier across
|
||||
* any function calls that could collect. It is hard to imagine the compiler
|
||||
* analyzing the program so thoroughly that it could prove that such motion was
|
||||
* safe. In practice, compilers treat calls to the collector as opaque operations
|
||||
* --- in particular, as operations which could access volatile variables, across
|
||||
* which this destructor must not be moved.
|
||||
*
|
||||
* ("Objection, your honor! *Alleged* killer whale!")
|
||||
*
|
||||
* The disadvantage of this approach is that it does generate code for the store.
|
||||
* We do need to use Anchors in some cases where cycles are tight.
|
||||
*
|
||||
* NB: there is a Anchor<Value>::~Anchor() specialization below.
|
||||
*/
|
||||
volatile T sink;
|
||||
sink = hold;
|
||||
}
|
||||
#endif /* defined(__GNUC__) */
|
||||
|
||||
/*
|
||||
* JS::Value is the C++ interface for a single JavaScript Engine value.
|
||||
* A few general notes on JS::Value:
|
||||
@ -977,28 +838,6 @@ class RootedBase<JS::Value> : public MutableValueOperations<Rooted<JS::Value> >
|
||||
|
||||
namespace JS {
|
||||
|
||||
#ifndef __GNUC__
|
||||
|
||||
/*
|
||||
* The default assignment operator for |struct C| has the signature:
|
||||
*
|
||||
* C& C::operator=(const C&)
|
||||
*
|
||||
* And in particular requires implicit conversion of |this| to type |C| for the
|
||||
* return value. But |volatile C| cannot thus be converted to |C|, so just
|
||||
* doing |sink = hold| as in the non-specialized version would fail to compile.
|
||||
* Do the assignment on asBits instead, since I don't think we want to give
|
||||
* jsval_layout an assignment operator returning |volatile jsval_layout|.
|
||||
*/
|
||||
template<>
|
||||
inline Anchor<Value>::~Anchor()
|
||||
{
|
||||
volatile uint64_t bits;
|
||||
bits = JSVAL_TO_IMPL(hold).asBits;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined JS_THREADSAFE && defined DEBUG
|
||||
|
||||
class JS_PUBLIC_API(AutoCheckRequestDepth)
|
||||
|
Loading…
Reference in New Issue
Block a user