Bug 914402 - Remove the defunct conservative stack scanner; r=sfink

--HG--
extra : rebase_source : c261ef7492694e9724c78edc7bc0dac7aa4357ba
This commit is contained in:
Terrence Cole 2014-09-09 15:08:23 -07:00
parent b3072839ca
commit 29dc9aff5e
28 changed files with 4 additions and 624 deletions

View File

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

View File

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

View File

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

View File

@ -1,174 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* JS::Anchor implementation. */
#ifndef js_Anchor_h
#define js_Anchor_h
#include "mozilla/Attributes.h"
#include "js/TypeDecls.h"
namespace JS {
/*
* Protecting non-Value, non-JSObject *, non-JSString * values from collection
*
* Most of the time, the garbage collector's conservative stack scanner works
* behind the scenes, finding all live values and protecting them from being
* collected. However, when JSAPI client code obtains a pointer to data the
* scanner does not know about, owned by an object the scanner does know about,
* Care Must Be Taken.
*
* The scanner recognizes only a select set of types: pointers to JSObjects and
* similar things (JSFunctions, and so on), pointers to JSStrings, and Values.
* So while the scanner finds all live |JSString| pointers, it does not notice
* |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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -17,7 +17,6 @@ UNIFIED_SOURCES += [
'testChromeBuffer.cpp',
'testClassGetter.cpp',
'testCloneScript.cpp',
'testConservativeGC.cpp',
'testContexts.cpp',
'testCustomIterator.cpp',
'testDebugger.cpp',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1344,8 +1344,4 @@ struct GCMethods<types::Type>
} // namespace js
namespace JS {
template<> class AnchorPermitted<js::types::TypeObject *> { };
} // namespace JS
#endif /* jsinferinlines_h */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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