mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 914402 - Remove the defunct conservative stack scanner; r=sfink
--HG-- extra : rebase_source : c261ef7492694e9724c78edc7bc0dac7aa4357ba
This commit is contained in:
parent
b3072839ca
commit
29dc9aff5e
@ -66,7 +66,4 @@ MOZ_JSDOWNLOADS=1
|
||||
|
||||
MOZ_BUNDLED_FONTS=1
|
||||
|
||||
# Enable exact rooting on b2g.
|
||||
JSGC_USE_EXACT_ROOTING=1
|
||||
|
||||
JS_GC_SMALL_CHUNK_SIZE=1
|
||||
|
15
configure.in
15
configure.in
@ -3839,7 +3839,6 @@ NSS_NO_LIBPKIX=
|
||||
MOZ_CONTENT_SANDBOX=
|
||||
MOZ_GMP_SANDBOX=
|
||||
MOZ_SANDBOX=1
|
||||
JSGC_USE_EXACT_ROOTING=1
|
||||
JSGC_GENERATIONAL=
|
||||
|
||||
case "$target_os" in
|
||||
@ -7199,17 +7198,6 @@ if test -n "$JSGC_INCREMENTAL"; then
|
||||
AC_DEFINE(JSGC_INCREMENTAL)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Use exact stack rooting for GC
|
||||
dnl ========================================================
|
||||
MOZ_ARG_DISABLE_BOOL(exact-rooting,
|
||||
[ --disable-exact-rooting Enable use of conservative stack scanning for GC],
|
||||
JSGC_USE_EXACT_ROOTING= ,
|
||||
JSGC_USE_EXACT_ROOTING=1 )
|
||||
if test -n "$JSGC_USE_EXACT_ROOTING"; then
|
||||
AC_DEFINE(JSGC_USE_EXACT_ROOTING)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Use generational GC
|
||||
dnl ========================================================
|
||||
@ -9170,9 +9158,6 @@ if test -z "$JS_SHARED_LIBRARY" ; then
|
||||
ac_configure_args="$ac_configure_args --disable-export-js"
|
||||
fi
|
||||
fi
|
||||
if test -z "$JSGC_USE_EXACT_ROOTING" ; then
|
||||
ac_configure_args="$ac_configure_args --disable-exact-rooting"
|
||||
fi
|
||||
if test -z "$JSGC_GENERATIONAL" ; then
|
||||
ac_configure_args="$ac_configure_args --disable-gcgenerational"
|
||||
fi
|
||||
|
@ -1130,7 +1130,6 @@ FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* val
|
||||
*ok = false;
|
||||
return 0;
|
||||
}
|
||||
JS::Anchor<JSString*> anchor(str);
|
||||
|
||||
{
|
||||
int index;
|
||||
|
@ -1,174 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* JS::Anchor implementation. */
|
||||
|
||||
#ifndef js_Anchor_h
|
||||
#define js_Anchor_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
namespace JS {
|
||||
|
||||
/*
|
||||
* Protecting non-Value, non-JSObject *, non-JSString * values from collection
|
||||
*
|
||||
* Most of the time, the garbage collector's conservative stack scanner works
|
||||
* behind the scenes, finding all live values and protecting them from being
|
||||
* collected. However, when JSAPI client code obtains a pointer to data the
|
||||
* scanner does not know about, owned by an object the scanner does know about,
|
||||
* Care Must Be Taken.
|
||||
*
|
||||
* The scanner recognizes only a select set of types: pointers to JSObjects and
|
||||
* similar things (JSFunctions, and so on), pointers to JSStrings, and Values.
|
||||
* So while the scanner finds all live |JSString| pointers, it does not notice
|
||||
* |char16_t| pointers.
|
||||
*
|
||||
* So suppose we have:
|
||||
*
|
||||
* void f(JSString *str) {
|
||||
* const char16_t *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 |char16_t|
|
||||
* characters 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 char16_t *ch = JS_GetStringCharsZ(str);
|
||||
* ... do stuff with ch, but no uses of str ...;
|
||||
* }
|
||||
*
|
||||
* This simply ensures that |str| will be live until |a_str| goes out of scope.
|
||||
* As long as we don't retain a pointer to the string's characters for longer
|
||||
* than that, we have avoided all garbage collection hazards.
|
||||
*/
|
||||
template<typename T> class AnchorPermitted;
|
||||
template<> class AnchorPermitted<JSObject *> { };
|
||||
template<> class AnchorPermitted<const JSObject *> { };
|
||||
template<> class AnchorPermitted<JSFunction *> { };
|
||||
template<> class AnchorPermitted<const JSFunction *> { };
|
||||
template<> class AnchorPermitted<JSString *> { };
|
||||
template<> class AnchorPermitted<const JSString *> { };
|
||||
template<> class AnchorPermitted<Value> { };
|
||||
template<> class AnchorPermitted<const JSScript *> { };
|
||||
template<> class AnchorPermitted<JSScript *> { };
|
||||
|
||||
template<typename T>
|
||||
class Anchor : AnchorPermitted<T>
|
||||
{
|
||||
public:
|
||||
Anchor() { }
|
||||
explicit Anchor(T t) { hold = t; }
|
||||
inline ~Anchor();
|
||||
|
||||
private:
|
||||
T hold;
|
||||
|
||||
/*
|
||||
* Rooting analysis considers use of operator= to be a use of an anchor.
|
||||
* For simplicity, Anchor is treated as if it contained a GC thing, from
|
||||
* construction. Thus if we had
|
||||
*
|
||||
* void operator=(const T &t) { hold = t; }
|
||||
*
|
||||
* and this code
|
||||
*
|
||||
* JS::Anchor<JSString*> anchor;
|
||||
* stuff that could GC, producing |str|;
|
||||
* anchor = str;
|
||||
*
|
||||
* the last line would be seen as a hazard, because the final = would "use"
|
||||
* |anchor| that is a GC thing -- which could have been moved around by the
|
||||
* GC. The workaround is to structure your code so that JS::Anchor is
|
||||
* always constructed, living for however long the corresponding value must
|
||||
* live.
|
||||
*/
|
||||
void operator=(const T &t) MOZ_DELETE;
|
||||
|
||||
Anchor(const Anchor &other) MOZ_DELETE;
|
||||
void operator=(const Anchor &other) MOZ_DELETE;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline Anchor<T>::~Anchor()
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
/*
|
||||
* No code is generated for this. But because this is marked 'volatile', G++ will
|
||||
* assume it has important side-effects, and won't delete it. (G++ never looks at
|
||||
* the actual text and notices it's empty.) And because we have passed |hold| to
|
||||
* it, GCC will keep |hold| alive until this point.
|
||||
*
|
||||
* The "memory" clobber operand ensures that G++ will not move prior memory
|
||||
* accesses after the asm --- it's a barrier. Unfortunately, it also means that
|
||||
* G++ will assume that all memory has changed after the asm, as it would for a
|
||||
* call to an unknown function. I don't know of a way to avoid that consequence.
|
||||
*/
|
||||
asm volatile("":: "g" (hold) : "memory");
|
||||
#else
|
||||
/*
|
||||
* An adequate portable substitute, for non-structure types.
|
||||
*
|
||||
* The compiler promises that, by the end of an expression statement, the
|
||||
* last-stored value to a volatile object is the same as it would be in an
|
||||
* unoptimized, direct implementation (the "abstract machine" whose behavior the
|
||||
* language spec describes). However, the compiler is still free to reorder
|
||||
* non-volatile accesses across this store --- which is what we must prevent. So
|
||||
* assigning the held value to a volatile variable, as we do here, is not enough.
|
||||
*
|
||||
* In our case, however, garbage collection only occurs at function calls, so it
|
||||
* is sufficient to ensure that the destructor's store isn't moved earlier across
|
||||
* any function calls that could collect. It is hard to imagine the compiler
|
||||
* analyzing the program so thoroughly that it could prove that such motion was
|
||||
* safe. In practice, compilers treat calls to the collector as opaque operations
|
||||
* --- in particular, as operations which could access volatile variables, across
|
||||
* which this destructor must not be moved.
|
||||
*
|
||||
* ("Objection, your honor! *Alleged* killer whale!")
|
||||
*
|
||||
* The disadvantage of this approach is that it does generate code for the store.
|
||||
* We do need to use Anchors in some cases where cycles are tight.
|
||||
*
|
||||
* Note that there is a Anchor<Value>::~Anchor() specialization in Value.h.
|
||||
*/
|
||||
volatile T sink;
|
||||
sink = hold;
|
||||
#endif /* defined(__GNUC__) */
|
||||
}
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#endif /* js_Anchor_h */
|
@ -728,14 +728,12 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
||||
/* Note: CX is a subclass of either ContextFriendFields or PerThreadDataFriendFields. */
|
||||
template <typename CX>
|
||||
void init(CX *cx) {
|
||||
#ifdef JSGC_TRACK_EXACT_ROOTS
|
||||
js::ThingRootKind kind = js::RootKind<T>::rootKind();
|
||||
this->stack = &cx->thingGCRooters[kind];
|
||||
this->prev = *stack;
|
||||
*stack = reinterpret_cast<Rooted<void*>*>(this);
|
||||
|
||||
MOZ_ASSERT(!js::GCMethods<T>::poisoned(ptr));
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
@ -809,19 +807,12 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
||||
init(js::PerThreadDataFriendFields::getMainThread(rt));
|
||||
}
|
||||
|
||||
// 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() {
|
||||
MOZ_ASSERT(*stack == reinterpret_cast<Rooted<void*>*>(this));
|
||||
*stack = prev;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef JSGC_TRACK_EXACT_ROOTS
|
||||
Rooted<T> *previous() { return reinterpret_cast<Rooted<T>*>(prev); }
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Important: Return a reference here so passing a Rooted<T> to
|
||||
@ -854,14 +845,12 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
||||
bool operator==(const T &other) const { return ptr == other; }
|
||||
|
||||
private:
|
||||
#ifdef JSGC_TRACK_EXACT_ROOTS
|
||||
/*
|
||||
* These need to be templated on void* to avoid aliasing issues between, for
|
||||
* example, Rooted<JSObject> and Rooted<JSFunction>, which use the same
|
||||
* stack head pointer for different classes.
|
||||
*/
|
||||
Rooted<void *> **stack, *prev;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* |ptr| must be the last field in Rooted because the analysis treats all
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "js-config.h"
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "js/Anchor.h"
|
||||
#include "js/GCAPI.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/Utility.h"
|
||||
@ -1865,26 +1864,6 @@ IsPoisonedValue(const Value &v)
|
||||
return js::GCMethods<Value>::poisoned(v);
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
#ifdef JS_DEBUG
|
||||
namespace detail {
|
||||
|
||||
|
@ -55,18 +55,13 @@ GetBuildConfiguration(JSContext *cx, unsigned argc, jsval *vp)
|
||||
if (!info)
|
||||
return false;
|
||||
|
||||
RootedValue value(cx, BooleanValue(false));
|
||||
if (!JS_SetProperty(cx, info, "rooting-analysis", value))
|
||||
if (!JS_SetProperty(cx, info, "rooting-analysis", FalseHandleValue))
|
||||
return false;
|
||||
|
||||
#ifdef JSGC_USE_EXACT_ROOTING
|
||||
value = BooleanValue(true);
|
||||
#else
|
||||
value = BooleanValue(false);
|
||||
#endif
|
||||
if (!JS_SetProperty(cx, info, "exact-rooting", value))
|
||||
if (!JS_SetProperty(cx, info, "exact-rooting", TrueHandleValue))
|
||||
return false;
|
||||
|
||||
RootedValue value(cx);
|
||||
#ifdef DEBUG
|
||||
value = BooleanValue(true);
|
||||
#else
|
||||
|
@ -3099,21 +3099,6 @@ fi
|
||||
JSGC_GENERATIONAL_CONFIGURED=$JSGC_GENERATIONAL
|
||||
AC_SUBST(JSGC_GENERATIONAL_CONFIGURED)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Use exact stack rooting for GC
|
||||
dnl ========================================================
|
||||
dnl Use exact rooting by default in all shell builds. The top-level mozilla
|
||||
dnl configure.in will configure SpiderMonkey with --disable-exact-rooting as
|
||||
dnl needed on a per-platform basis.
|
||||
JSGC_USE_EXACT_ROOTING=1
|
||||
MOZ_ARG_DISABLE_BOOL(exact-rooting,
|
||||
[ --disable-exact-rooting Enable use of conservative stack scanning for GC],
|
||||
JSGC_USE_EXACT_ROOTING= ,
|
||||
JSGC_USE_EXACT_ROOTING=1 )
|
||||
if test -n "$JSGC_USE_EXACT_ROOTING"; then
|
||||
AC_DEFINE(JSGC_USE_EXACT_ROOTING)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Use compacting GC
|
||||
dnl ========================================================
|
||||
|
@ -95,8 +95,6 @@ function ignoreEdgeUse(edge, variable)
|
||||
var callee = edge.Exp[0];
|
||||
if (callee.Kind == "Var") {
|
||||
var name = callee.Variable.Name[0];
|
||||
if (/~Anchor/.test(name))
|
||||
return true;
|
||||
if (/~DebugOnly/.test(name))
|
||||
return true;
|
||||
if (/~ScopedThreadSafeStringInspector/.test(name))
|
||||
|
@ -41,8 +41,6 @@ typedef RootedValueMap::Range RootRange;
|
||||
typedef RootedValueMap::Entry RootEntry;
|
||||
typedef RootedValueMap::Enum RootEnum;
|
||||
|
||||
#ifdef JSGC_USE_EXACT_ROOTING
|
||||
|
||||
// Note: the following two functions cannot be static as long as we are using
|
||||
// GCC 4.4, since it requires template function parameters to have external
|
||||
// linkage.
|
||||
@ -135,253 +133,6 @@ MarkExactStackRoots(JSRuntime* rt, JSTracer *trc)
|
||||
MarkExactStackRootsAcrossTypes<ThreadSafeContext*>(cx.get(), trc);
|
||||
MarkExactStackRootsAcrossTypes<PerThreadData*>(&rt->mainThread, trc);
|
||||
}
|
||||
#endif /* JSGC_USE_EXACT_ROOTING */
|
||||
|
||||
enum ConservativeGCTest
|
||||
{
|
||||
CGCT_VALID,
|
||||
CGCT_LOWBITSET, /* excluded because one of the low bits was set */
|
||||
CGCT_NOTARENA, /* not within arena range in a chunk */
|
||||
CGCT_OTHERCOMPARTMENT, /* in another compartment */
|
||||
CGCT_NOTCHUNK, /* not within a valid chunk */
|
||||
CGCT_FREEARENA, /* within arena containing only free things */
|
||||
CGCT_NOTLIVE, /* gcthing is not allocated */
|
||||
CGCT_END
|
||||
};
|
||||
|
||||
/*
|
||||
* Tests whether w is a (possibly dead) GC thing. Returns CGCT_VALID and
|
||||
* details about the thing if so. On failure, returns the reason for rejection.
|
||||
*/
|
||||
#ifndef JSGC_USE_EXACT_ROOTING
|
||||
static inline ConservativeGCTest
|
||||
IsAddressableGCThing(JSRuntime *rt, uintptr_t w,
|
||||
bool skipUncollectedCompartments,
|
||||
gc::AllocKind *thingKindPtr,
|
||||
ArenaHeader **arenaHeader,
|
||||
void **thing)
|
||||
{
|
||||
/*
|
||||
* We assume that the compiler never uses sub-word alignment to store
|
||||
* pointers and does not tag pointers on its own. Additionally, the value
|
||||
* representation for all values and the jsid representation for GC-things
|
||||
* do not touch the low two bits. Thus any word with the low two bits set
|
||||
* is not a valid GC-thing.
|
||||
*/
|
||||
JS_STATIC_ASSERT(JSID_TYPE_STRING == 0 && JSID_TYPE_SYMBOL == 4);
|
||||
if (w & 0x3)
|
||||
return CGCT_LOWBITSET;
|
||||
|
||||
/*
|
||||
* An object jsid has its low bits tagged. In the value representation on
|
||||
* 64-bit, the high bits are tagged.
|
||||
*/
|
||||
const uintptr_t JSID_PAYLOAD_MASK = ~uintptr_t(JSID_TYPE_MASK);
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
uintptr_t addr = w & JSID_PAYLOAD_MASK;
|
||||
#elif JS_BITS_PER_WORD == 64
|
||||
uintptr_t addr = w & JSID_PAYLOAD_MASK & JSVAL_PAYLOAD_MASK;
|
||||
#endif
|
||||
|
||||
Chunk *chunk = Chunk::fromAddress(addr);
|
||||
|
||||
if (!rt->gc.hasChunk(chunk))
|
||||
return CGCT_NOTCHUNK;
|
||||
|
||||
/*
|
||||
* We query for pointers outside the arena array after checking for an
|
||||
* allocated chunk. Such pointers are rare and we want to reject them
|
||||
* after doing more likely rejections.
|
||||
*/
|
||||
if (!Chunk::withinArenasRange(addr))
|
||||
return CGCT_NOTARENA;
|
||||
|
||||
/* If the arena is not currently allocated, don't access the header. */
|
||||
size_t arenaOffset = Chunk::arenaIndex(addr);
|
||||
if (chunk->decommittedArenas.get(arenaOffset))
|
||||
return CGCT_FREEARENA;
|
||||
|
||||
ArenaHeader *aheader = &chunk->arenas[arenaOffset].aheader;
|
||||
|
||||
if (!aheader->allocated())
|
||||
return CGCT_FREEARENA;
|
||||
|
||||
if (skipUncollectedCompartments && !aheader->zone->isCollecting())
|
||||
return CGCT_OTHERCOMPARTMENT;
|
||||
|
||||
AllocKind thingKind = aheader->getAllocKind();
|
||||
uintptr_t offset = addr & ArenaMask;
|
||||
uintptr_t minOffset = Arena::firstThingOffset(thingKind);
|
||||
if (offset < minOffset)
|
||||
return CGCT_NOTARENA;
|
||||
|
||||
/* addr can point inside the thing so we must align the address. */
|
||||
uintptr_t shift = (offset - minOffset) % Arena::thingSize(thingKind);
|
||||
addr -= shift;
|
||||
|
||||
if (thing)
|
||||
*thing = reinterpret_cast<void *>(addr);
|
||||
if (arenaHeader)
|
||||
*arenaHeader = aheader;
|
||||
if (thingKindPtr)
|
||||
*thingKindPtr = thingKind;
|
||||
return CGCT_VALID;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns CGCT_VALID and mark it if the w can be a live GC thing and sets
|
||||
* thingKind accordingly. Otherwise returns the reason for rejection.
|
||||
*/
|
||||
static inline ConservativeGCTest
|
||||
MarkIfGCThingWord(JSTracer *trc, uintptr_t w)
|
||||
{
|
||||
void *thing;
|
||||
ArenaHeader *aheader;
|
||||
AllocKind thingKind;
|
||||
ConservativeGCTest status =
|
||||
IsAddressableGCThing(trc->runtime(), w, IS_GC_MARKING_TRACER(trc),
|
||||
&thingKind, &aheader, &thing);
|
||||
if (status != CGCT_VALID)
|
||||
return status;
|
||||
|
||||
/*
|
||||
* Check if the thing is free. We must use the list of free spans as at
|
||||
* this point we no longer have the mark bits from the previous GC run and
|
||||
* we must account for newly allocated things.
|
||||
*/
|
||||
if (InFreeList(aheader, thing))
|
||||
return CGCT_NOTLIVE;
|
||||
|
||||
JSGCTraceKind traceKind = MapAllocToTraceKind(thingKind);
|
||||
#ifdef DEBUG
|
||||
const char pattern[] = "machine_stack %p";
|
||||
char nameBuf[sizeof(pattern) - 2 + sizeof(thing) * 2];
|
||||
JS_snprintf(nameBuf, sizeof(nameBuf), pattern, thing);
|
||||
trc->setTracingName(nameBuf);
|
||||
#endif
|
||||
trc->setTracingLocation((void *)w);
|
||||
void *tmp = thing;
|
||||
MarkKind(trc, &tmp, traceKind);
|
||||
JS_ASSERT(tmp == thing);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (trc->runtime()->gc.state() == MARK_ROOTS)
|
||||
trc->runtime()->mainThread.gcSavedRoots.append(
|
||||
PerThreadData::SavedGCRoot(thing, traceKind));
|
||||
#endif
|
||||
|
||||
return CGCT_VALID;
|
||||
}
|
||||
|
||||
static void
|
||||
MarkWordConservatively(JSTracer *trc, uintptr_t w)
|
||||
{
|
||||
/*
|
||||
* The conservative scanner may access words that valgrind considers as
|
||||
* undefined. To avoid false positives and not to alter valgrind view of
|
||||
* the memory we make as memcheck-defined the argument, a copy of the
|
||||
* original word. See bug 572678.
|
||||
*/
|
||||
#ifdef MOZ_VALGRIND
|
||||
JS_SILENCE_UNUSED_VALUE_IN_EXPR(VALGRIND_MAKE_MEM_DEFINED(&w, sizeof(w)));
|
||||
#endif
|
||||
|
||||
MarkIfGCThingWord(trc, w);
|
||||
}
|
||||
|
||||
MOZ_ASAN_BLACKLIST
|
||||
static void
|
||||
MarkRangeConservatively(JSTracer *trc, const uintptr_t *begin, const uintptr_t *end)
|
||||
{
|
||||
JS_ASSERT(begin <= end);
|
||||
for (const uintptr_t *i = begin; i < end; ++i)
|
||||
MarkWordConservatively(trc, *i);
|
||||
}
|
||||
|
||||
static void
|
||||
MarkRangeConservativelyAndSkipIon(JSTracer *trc, JSRuntime *rt, const uintptr_t *begin, const uintptr_t *end)
|
||||
{
|
||||
const uintptr_t *i = begin;
|
||||
|
||||
#if JS_STACK_GROWTH_DIRECTION < 0 && !defined(JS_ARM_SIMULATOR) && !defined(JS_MIPS_SIMULATOR)
|
||||
// Walk only regions in between JIT activations. Note that non-volatile
|
||||
// registers are spilled to the stack before the entry frame, ensuring
|
||||
// that the conservative scanner will still see them.
|
||||
//
|
||||
// If the ARM or MIPS simulator is enabled, JIT activations are not on
|
||||
// the native stack but on the simulator stack, so we don't have to skip
|
||||
// JIT regions in this case.
|
||||
for (jit::JitActivationIterator iter(rt); !iter.done(); ++iter) {
|
||||
uintptr_t *jitMin, *jitEnd;
|
||||
iter.jitStackRange(jitMin, jitEnd);
|
||||
|
||||
MarkRangeConservatively(trc, i, jitMin);
|
||||
i = jitEnd;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Mark everything after the most recent Ion activation.
|
||||
MarkRangeConservatively(trc, i, end);
|
||||
}
|
||||
|
||||
MOZ_NEVER_INLINE void
|
||||
gc::GCRuntime::markConservativeStackRoots(JSTracer *trc, bool useSavedRoots)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (useSavedRoots) {
|
||||
for (PerThreadData::SavedGCRoot *root = rt->mainThread.gcSavedRoots.begin();
|
||||
root != rt->mainThread.gcSavedRoots.end();
|
||||
root++)
|
||||
{
|
||||
trc->setTracingName("cstack");
|
||||
MarkKind(trc, &root->thing, root->kind);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (incrementalState == MARK_ROOTS)
|
||||
rt->mainThread.gcSavedRoots.clearAndFree();
|
||||
#endif
|
||||
|
||||
if (!conservativeGC.hasStackToScan()) {
|
||||
JS_ASSERT(!rt->requestDepth);
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t *stackMin, *stackEnd;
|
||||
#if JS_STACK_GROWTH_DIRECTION > 0
|
||||
stackMin = reinterpret_cast<uintptr_t *>(rt->nativeStackBase);
|
||||
stackEnd = conservativeGC.nativeStackTop;
|
||||
#else
|
||||
stackMin = conservativeGC.nativeStackTop + 1;
|
||||
stackEnd = reinterpret_cast<uintptr_t *>(rt->nativeStackBase);
|
||||
#endif
|
||||
|
||||
JS_ASSERT(stackMin <= stackEnd);
|
||||
MarkRangeConservativelyAndSkipIon(trc, rt, stackMin, stackEnd);
|
||||
MarkRangeConservatively(trc, conservativeGC.registerSnapshot.words,
|
||||
ArrayEnd(conservativeGC.registerSnapshot.words));
|
||||
}
|
||||
|
||||
void
|
||||
js::MarkStackRangeConservatively(JSTracer *trc, Value *beginv, Value *endv)
|
||||
{
|
||||
const uintptr_t *begin = beginv->payloadUIntPtr();
|
||||
const uintptr_t *end = endv->payloadUIntPtr();
|
||||
#ifdef JS_NUNBOX32
|
||||
/*
|
||||
* With 64-bit jsvals on 32-bit systems, we can optimize a bit by
|
||||
* scanning only the payloads.
|
||||
*/
|
||||
JS_ASSERT(begin <= end);
|
||||
for (const uintptr_t *i = begin; i < end; i += sizeof(Value) / sizeof(uintptr_t))
|
||||
MarkWordConservatively(trc, *i);
|
||||
#else
|
||||
MarkRangeConservatively(trc, begin, end);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* JSGC_USE_EXACT_ROOTING */
|
||||
|
||||
MOZ_NEVER_INLINE void
|
||||
ConservativeGCData::recordStackTop()
|
||||
@ -723,11 +474,7 @@ js::gc::GCRuntime::markRuntime(JSTracer *trc,
|
||||
AutoGCRooter::traceAll(trc);
|
||||
|
||||
if (!rt->isBeingDestroyed()) {
|
||||
#ifdef JSGC_USE_EXACT_ROOTING
|
||||
MarkExactStackRoots(rt, trc);
|
||||
#else
|
||||
markConservativeStackRoots(trc, rootsSource == UseSavedRoots);
|
||||
#endif
|
||||
rt->markSelfHostingGlobal(trc);
|
||||
}
|
||||
|
||||
|
@ -9,10 +9,6 @@
|
||||
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
|
||||
#ifndef JSGC_USE_EXACT_ROOTING
|
||||
# error "Generational GC requires exact rooting."
|
||||
#endif
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/ReentrancyGuard.h"
|
||||
|
@ -17,7 +17,6 @@ UNIFIED_SOURCES += [
|
||||
'testChromeBuffer.cpp',
|
||||
'testClassGetter.cpp',
|
||||
'testCloneScript.cpp',
|
||||
'testConservativeGC.cpp',
|
||||
'testContexts.cpp',
|
||||
'testCustomIterator.cpp',
|
||||
'testDebugger.cpp',
|
||||
|
@ -1,68 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if !defined(JSGC_USE_EXACT_ROOTING)
|
||||
|
||||
#include "jsobj.h"
|
||||
|
||||
#include "jsapi-tests/tests.h"
|
||||
#include "vm/String.h"
|
||||
|
||||
BEGIN_TEST(testConservativeGC)
|
||||
{
|
||||
JS::RootedValue v2(cx);
|
||||
EVAL("({foo: 'bar'});", &v2);
|
||||
CHECK(v2.isObject());
|
||||
char objCopy[sizeof(JSObject)];
|
||||
js_memcpy(&objCopy, v2.toObjectOrNull(), sizeof(JSObject));
|
||||
|
||||
JS::RootedValue v3(cx);
|
||||
EVAL("String(Math.PI);", &v3);
|
||||
CHECK(v3.isString());
|
||||
char strCopy[sizeof(JSString)];
|
||||
js_memcpy(&strCopy, v3.toString(), sizeof(JSString));
|
||||
|
||||
JS::RootedValue tmp(cx);
|
||||
EVAL("({foo2: 'bar2'});", &tmp);
|
||||
CHECK(tmp.isObject());
|
||||
JS::RootedObject obj2(cx, tmp.toObjectOrNull());
|
||||
char obj2Copy[sizeof(JSObject)];
|
||||
js_memcpy(&obj2Copy, obj2, sizeof(JSObject));
|
||||
|
||||
EVAL("String(Math.sqrt(3));", &tmp);
|
||||
CHECK(tmp.isString());
|
||||
JS::RootedString str2(cx, tmp.toString());
|
||||
char str2Copy[sizeof(JSString)];
|
||||
js_memcpy(&str2Copy, str2, sizeof(JSString));
|
||||
|
||||
tmp = JSVAL_NULL;
|
||||
|
||||
JS_GC(rt);
|
||||
|
||||
EVAL("var a = [];\n"
|
||||
"for (var i = 0; i != 10000; ++i) {\n"
|
||||
"a.push(i + 0.1, [1, 2], String(Math.sqrt(i)), {a: i});\n"
|
||||
"}", &tmp);
|
||||
|
||||
JS_GC(rt);
|
||||
|
||||
checkObjectFields((JSObject *)objCopy, v2.toObjectOrNull());
|
||||
CHECK(!memcmp(strCopy, v3.toString(), sizeof(strCopy)));
|
||||
|
||||
checkObjectFields((JSObject *)obj2Copy, obj2);
|
||||
CHECK(!memcmp(str2Copy, str2, sizeof(str2Copy)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool checkObjectFields(JSObject *savedCopy, JSObject *obj)
|
||||
{
|
||||
/* Ignore fields which are unstable across GCs. */
|
||||
CHECK(savedCopy->lastProperty() == obj->lastProperty());
|
||||
return true;
|
||||
}
|
||||
|
||||
END_TEST(testConservativeGC)
|
||||
|
||||
#endif /* !defined(JSGC_USE_EXACT_ROOTING) */
|
@ -13,7 +13,6 @@
|
||||
#include "jspubtd.h"
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "js/Anchor.h"
|
||||
#include "js/CallArgs.h"
|
||||
#include "js/CallNonGenericMethod.h"
|
||||
#include "js/CharacterEncoding.h"
|
||||
|
@ -2,8 +2,6 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if defined(JSGC_USE_EXACT_ROOTING)
|
||||
|
||||
#include "js/Class.h"
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
@ -180,5 +178,3 @@ BEGIN_TEST(test_PersistentRootedAssign)
|
||||
return true;
|
||||
}
|
||||
END_TEST(test_PersistentRootedAssign)
|
||||
|
||||
#endif // defined(JSGC_USE_EXACT_ROOTING)
|
||||
|
@ -9,8 +9,6 @@
|
||||
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
#ifdef JSGC_USE_EXACT_ROOTING
|
||||
|
||||
BEGIN_TEST(testWeakMap_basicOperations)
|
||||
{
|
||||
JS::RootedObject map(cx, JS::NewWeakMapObject(cx));
|
||||
@ -240,5 +238,3 @@ checkSize(JS::HandleObject map, uint32_t expected)
|
||||
return true;
|
||||
}
|
||||
END_TEST(testWeakMap_keyDelegates)
|
||||
|
||||
#endif // JSGC_USE_EXACT_ROOTING
|
||||
|
@ -1062,8 +1062,6 @@ js::ArrayJoin(JSContext *cx, HandleObject obj, HandleLinearString sepstr, uint32
|
||||
|
||||
// Steps 1 to 6, should be done by the caller.
|
||||
|
||||
JS::Anchor<JSString*> anchor(sepstr);
|
||||
|
||||
// Step 6 is implicit in the loops below.
|
||||
|
||||
// An optimized version of a special case of steps 7-11: when length==1 and
|
||||
|
@ -267,7 +267,7 @@ js::DestroyContext(JSContext *cx, DestroyContextMode mode)
|
||||
|
||||
void
|
||||
ContextFriendFields::checkNoGCRooters() {
|
||||
#if defined(JSGC_USE_EXACT_ROOTING) && defined(DEBUG)
|
||||
#ifdef DEBUG
|
||||
for (int i = 0; i < THING_ROOT_LIMIT; ++i)
|
||||
JS_ASSERT(thingGCRooters[i] == nullptr);
|
||||
#endif
|
||||
@ -537,8 +537,6 @@ js::ReportUsageError(JSContext *cx, HandleObject callee, const char *msg)
|
||||
JS_ReportError(cx, "%s", msg);
|
||||
} else {
|
||||
JSString *str = usage.toString();
|
||||
JS::Anchor<JSString *> a_str(str);
|
||||
|
||||
if (!str->ensureFlat(cx))
|
||||
return;
|
||||
AutoStableStringChars chars(cx);
|
||||
|
@ -47,9 +47,7 @@ PerThreadDataFriendFields::PerThreadDataFriendFields()
|
||||
for (int i=0; i<StackKindCount; i++)
|
||||
nativeStackLimit[i] = UINTPTR_MAX;
|
||||
#endif
|
||||
#if defined(JSGC_USE_EXACT_ROOTING)
|
||||
PodArrayZero(thingGCRooters);
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
|
@ -1862,8 +1862,6 @@ FunctionConstructor(JSContext *cx, unsigned argc, Value *vp, GeneratorKind gener
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
JS::Anchor<JSString *> strAnchor(str);
|
||||
|
||||
/*
|
||||
* NB: (new Function) is not lexically closed by its caller, it's just an
|
||||
* anonymous function in the top-level scope that its constructor inhabits.
|
||||
|
@ -1344,8 +1344,4 @@ struct GCMethods<types::Type>
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
template<> class AnchorPermitted<js::types::TypeObject *> { };
|
||||
} // namespace JS
|
||||
|
||||
#endif /* jsinferinlines_h */
|
||||
|
@ -121,7 +121,6 @@ Quote(StringBuffer &sb, JSLinearString *str)
|
||||
static bool
|
||||
Quote(JSContext *cx, StringBuffer &sb, JSString *str)
|
||||
{
|
||||
JS::Anchor<JSString *> anchor(str);
|
||||
JSLinearString *linear = str->ensureLinear(cx);
|
||||
if (!linear)
|
||||
return false;
|
||||
@ -654,7 +653,6 @@ js_Stringify(JSContext *cx, MutableHandleValue vp, JSObject *replacer_, Value sp
|
||||
JSLinearString *str = space.toString()->ensureLinear(cx);
|
||||
if (!str)
|
||||
return false;
|
||||
JS::Anchor<JSString *> anchor(str);
|
||||
size_t len = Min(size_t(10), str->length());
|
||||
if (!gap.appendSubstring(str, 0, len))
|
||||
return false;
|
||||
@ -847,8 +845,6 @@ json_parse(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!flat)
|
||||
return false;
|
||||
|
||||
JS::Anchor<JSString *> anchor(flat);
|
||||
|
||||
AutoStableStringChars flatChars(cx);
|
||||
if (!flatChars.init(cx, flat))
|
||||
return false;
|
||||
|
@ -868,7 +868,6 @@ ToDisassemblySource(JSContext *cx, HandleValue v, JSAutoByteString *bytes)
|
||||
JSString *source = obj.as<RegExpObject>().toString(cx);
|
||||
if (!source)
|
||||
return false;
|
||||
JS::Anchor<JSString *> anchor(source);
|
||||
return bytes->encodeLatin1(cx, source);
|
||||
}
|
||||
}
|
||||
|
@ -21,10 +21,6 @@
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
#if defined(JSGC_USE_EXACT_ROOTING) || defined(JS_DEBUG)
|
||||
# define JSGC_TRACK_EXACT_ROOTS
|
||||
#endif
|
||||
|
||||
#if (defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)) || \
|
||||
(defined(JSGC_COMPACTING) && defined(DEBUG))
|
||||
# define JSGC_HASH_TABLE_CHECKS
|
||||
@ -409,9 +405,7 @@ struct ContextFriendFields
|
||||
explicit ContextFriendFields(JSRuntime *rt)
|
||||
: runtime_(rt), compartment_(nullptr), zone_(nullptr), autoGCRooters(nullptr)
|
||||
{
|
||||
#ifdef JSGC_TRACK_EXACT_ROOTS
|
||||
mozilla::PodArrayZero(thingGCRooters);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const ContextFriendFields *get(const JSContext *cx) {
|
||||
@ -422,7 +416,6 @@ struct ContextFriendFields
|
||||
return reinterpret_cast<ContextFriendFields *>(cx);
|
||||
}
|
||||
|
||||
#ifdef JSGC_TRACK_EXACT_ROOTS
|
||||
private:
|
||||
/*
|
||||
* Stack allocated GC roots for stack GC heap pointers, which may be
|
||||
@ -437,8 +430,6 @@ struct ContextFriendFields
|
||||
return reinterpret_cast<JS::Rooted<T> *>(thingGCRooters[kind]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void checkNoGCRooters();
|
||||
|
||||
/* Stack of thread-stack-allocated GC roots. */
|
||||
@ -501,7 +492,6 @@ struct PerThreadDataFriendFields
|
||||
|
||||
PerThreadDataFriendFields();
|
||||
|
||||
#ifdef JSGC_TRACK_EXACT_ROOTS
|
||||
private:
|
||||
/*
|
||||
* Stack allocated GC roots for stack GC heap pointers, which may be
|
||||
@ -515,7 +505,6 @@ struct PerThreadDataFriendFields
|
||||
js::ThingRootKind kind = RootKind<T>::rootKind();
|
||||
return reinterpret_cast<JS::Rooted<T> *>(thingGCRooters[kind]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Limit pointer for checking native stack consumption. */
|
||||
uintptr_t nativeStackLimit[StackKindCount];
|
||||
|
@ -65,7 +65,6 @@ EXPORTS += [
|
||||
# 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 += [
|
||||
'../public/Anchor.h',
|
||||
'../public/CallArgs.h',
|
||||
'../public/CallNonGenericMethod.h',
|
||||
'../public/CharacterEncoding.h',
|
||||
|
@ -1452,8 +1452,6 @@ Run(JSContext *cx, unsigned argc, jsval *vp)
|
||||
const char16_t *ucbuf = chars.twoByteRange().start().get();
|
||||
size_t buflen = str->length();
|
||||
|
||||
JS::Anchor<JSString *> a_str(str);
|
||||
|
||||
RootedScript script(cx);
|
||||
int64_t startClock = PRMJ_Now();
|
||||
{
|
||||
@ -4798,7 +4796,6 @@ static bool
|
||||
PrintHelpString(JSContext *cx, jsval v)
|
||||
{
|
||||
JSString *str = v.toString();
|
||||
JS::Anchor<JSString *> a_str(str);
|
||||
|
||||
JSLinearString *linear = str->ensureLinear(cx);
|
||||
if (!linear)
|
||||
|
@ -4943,7 +4943,6 @@ DebuggerGenericEval(JSContext *cx, const char *fullMethodName, const Value &code
|
||||
|
||||
/* Run the code and produce the completion value. */
|
||||
RootedValue rval(cx);
|
||||
JS::Anchor<JSString *> anchor(flat);
|
||||
AbstractFramePtr frame = iter ? iter->abstractFramePtr() : NullFramePtr();
|
||||
AutoStableStringChars stableChars(cx);
|
||||
if (!stableChars.initTwoByte(cx, flat))
|
||||
|
@ -1452,9 +1452,4 @@ IsImplicitDenseOrTypedArrayElement(Shape *prop)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
namespace JS {
|
||||
template<> class AnchorPermitted<js::Shape *> { };
|
||||
template<> class AnchorPermitted<const js::Shape *> { };
|
||||
}
|
||||
|
||||
#endif /* vm_Shape_h */
|
||||
|
Loading…
Reference in New Issue
Block a user