Bug 987666 - Remove the unused dynamic root analysis. r=sfink

This commit is contained in:
Terrence Cole 2014-03-24 18:32:36 -04:00
parent 8b0a1acbe6
commit fe8f16e4e5
40 changed files with 22 additions and 653 deletions

View File

@ -152,11 +152,6 @@ template <typename T> class PersistentRooted;
/* This is exposing internal state of the GC for inlining purposes. */
JS_FRIEND_API(bool) isGCEnabled();
#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
extern void
CheckStackRoots(JSContext *cx);
#endif
/*
* JS::NullPtr acts like a nullptr pointer in contexts that require a Handle.
*
@ -819,15 +814,6 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
Rooted<void*> **stack, *prev;
#endif
#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
/* Has the rooting analysis ever scanned this Rooted's stack location? */
friend void JS::CheckStackRoots(JSContext*);
#endif
#ifdef JSGC_ROOT_ANALYSIS
bool scanned;
#endif
/*
* |ptr| must be the last field in Rooted because the analysis treats all
* Rooted as Rooted<void*> during the analysis. See bug 829372.
@ -861,81 +847,6 @@ class RootedBase<JSObject*>
JS::Handle<U*> as() const;
};
/*
* Mark a stack location as a root for the rooting analysis, without actually
* rooting it in release builds. This should only be used for stack locations
* of GC things that cannot be relocated by a garbage collection, and that
* are definitely reachable via another path.
*/
class SkipRoot
{
#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
SkipRoot **stack, *prev;
const uint8_t *start;
const uint8_t *end;
template <typename CX, typename T>
void init(CX *cx, const T *ptr, size_t count) {
SkipRoot **head = &cx->skipGCRooters;
this->stack = head;
this->prev = *stack;
*stack = this;
this->start = (const uint8_t *) ptr;
this->end = this->start + (sizeof(T) * count);
}
public:
~SkipRoot() {
MOZ_ASSERT(*stack == this);
*stack = prev;
}
SkipRoot *previous() { return prev; }
bool contains(const uint8_t *v, size_t len) {
return v >= start && v + len <= end;
}
#else /* JS_DEBUG && JSGC_ROOT_ANALYSIS */
template <typename T>
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 /* JS_DEBUG && JSGC_ROOT_ANALYSIS */
template <typename T>
SkipRoot(JSContext *cx, const T *ptr, size_t count = 1
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
{
init(ContextFriendFields::get(cx), ptr, count);
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
template <typename T>
SkipRoot(ContextFriendFields *cx, const T *ptr, size_t count = 1
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
{
init(cx, ptr, count);
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
template <typename T>
SkipRoot(PerThreadData *pt, const T *ptr, size_t count = 1
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
{
init(PerThreadDataFriendFields::get(pt), ptr, count);
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/*
* RootedGeneric<T> allows a class to instantiate its own Rooted type by
@ -958,15 +869,14 @@ class JS_PUBLIC_API(RootedGeneric)
{
public:
JS::Rooted<GCType> rooter;
SkipRoot skip;
RootedGeneric(js::ContextFriendFields *cx)
: rooter(cx), skip(cx, rooter.address())
: rooter(cx)
{
}
RootedGeneric(js::ContextFriendFields *cx, const GCType &initial)
: rooter(cx, initial), skip(cx, rooter.address())
: rooter(cx, initial)
{
}
@ -1287,17 +1197,6 @@ class PersistentRooted : private mozilla::LinkedListElement<PersistentRooted<T>
namespace js {
/*
* Hook for dynamic root analysis. Checks the native stack and poisons
* references to GC things which have not been rooted.
*/
inline void MaybeCheckStackRoots(JSContext *cx)
{
#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
JS::CheckStackRoots(cx);
#endif
}
/* Base class for automatic read-only object rooting during compilation. */
class CompilerRootNode
{

View File

@ -43,14 +43,7 @@ size_t ExecutableAllocator::determinePageSize()
ExecutablePool::Allocation ExecutableAllocator::systemAlloc(size_t n)
{
void* allocation;
#ifdef JSGC_ROOT_ANALYSIS
do {
#endif
allocation = mmap(NULL, n, INITIAL_PROTECTION_FLAGS, MAP_PRIVATE | MAP_ANON, VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY, 0);
#ifdef JSGC_ROOT_ANALYSIS
} while (allocation && JS::IsPoisonedPtr(allocation));
#endif
void *allocation = mmap(NULL, n, INITIAL_PROTECTION_FLAGS, MAP_PRIVATE | MAP_ANON, VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY, 0);
if (allocation == MAP_FAILED)
allocation = NULL;
ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n };
@ -58,7 +51,7 @@ ExecutablePool::Allocation ExecutableAllocator::systemAlloc(size_t n)
}
void ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc)
{
{
int result = munmap(alloc.pages, alloc.size);
ASSERT_UNUSED(result, !result);
}

View File

@ -1290,7 +1290,6 @@ NewUNumberFormat(JSContext *cx, HandleObject numberFormat)
bool uUseGrouping = true;
// Sprinkle appropriate rooting flavor over things the GC might care about.
SkipRoot skip(cx, &uCurrency);
RootedString currency(cx);
// We don't need to look at numberingSystem - it can only be set via
@ -1783,7 +1782,6 @@ js::intl_patternForSkeleton(JSContext *cx, unsigned argc, Value *vp)
const jschar *skeleton = JS_GetStringCharsZ(cx, jsskeleton);
if (!skeleton)
return false;
SkipRoot skip(cx, &skeleton);
uint32_t skeletonLen = u_strlen(JSCharToUChar(skeleton));
UErrorCode status = U_ZERO_ERROR;
@ -1845,9 +1843,6 @@ NewUDateFormat(JSContext *cx, HandleObject dateTimeFormat)
const UChar *uPattern = nullptr;
uint32_t uPatternLength = 0;
SkipRoot skipTimeZone(cx, &uTimeZone);
SkipRoot skipPattern(cx, &uPattern);
// We don't need to look at calendar and numberingSystem - they can only be
// set via the Unicode locale extension and are therefore already set on
// locale.

View File

@ -43,13 +43,8 @@ GetBuildConfiguration(JSContext *cx, unsigned argc, jsval *vp)
RootedObject info(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
if (!info)
return false;
RootedValue value(cx);
#ifdef JSGC_ROOT_ANALYSIS
value = BooleanValue(true);
#else
value = BooleanValue(false);
#endif
RootedValue value(cx, BooleanValue(false));
if (!JS_SetProperty(cx, info, "rooting-analysis", value))
return false;

View File

@ -3258,17 +3258,6 @@ if test -n "$JSGC_GENERATIONAL"; then
AC_DEFINE(JSGC_GENERATIONAL)
fi
dnl ========================================================
dnl = Perform moving GC stack rooting analysis
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(root-analysis,
[ --enable-root-analysis Enable moving GC stack root analysis],
JSGC_ROOT_ANALYSIS=1,
JSGC_ROOT_ANALYSIS= )
if test -n "$JSGC_ROOT_ANALYSIS"; then
AC_DEFINE(JSGC_ROOT_ANALYSIS)
fi
dnl ========================================================
dnl = Use exact stack rooting for GC
dnl ========================================================

View File

@ -188,7 +188,6 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
SourceCompressionTask *extraSct /* = nullptr */)
{
RootedString source(cx, source_);
SkipRoot skip(cx, &chars);
#if JS_TRACE_LOGGING
js::AutoTraceLog logger(js::TraceLogging::defaultLogger(),
@ -507,7 +506,6 @@ CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyComp
// FIXME: make Function pass in two strings and parse them as arguments and
// ProgramElements respectively.
SkipRoot skip(cx, &chars);
MaybeCallSourceHandler(cx, options, chars, length);

View File

@ -278,10 +278,7 @@ TokenStream::TokenStream(ExclusiveContext *cx, const ReadOnlyCompileOptions &opt
tokenbuf(cx),
cx(cx),
originPrincipals(options.originPrincipals(cx)),
strictModeGetter(smg),
tokenSkip(cx, &tokens),
linebaseSkip(cx, &linebase),
prevLinebaseSkip(cx, &prevLinebase)
strictModeGetter(smg)
{
// The caller must ensure that a reference is held on the supplied principals
// throughout compilation.

View File

@ -747,8 +747,7 @@ class MOZ_STACK_CLASS TokenStream
class TokenBuf {
public:
TokenBuf(ExclusiveContext *cx, const jschar *buf, size_t length)
: base_(buf), limit_(buf + length), ptr(buf),
skipBase(cx, &base_), skipLimit(cx, &limit_), skipPtr(cx, &ptr)
: base_(buf), limit_(buf + length), ptr(buf)
{ }
bool hasRawChars() const {
@ -827,9 +826,6 @@ class MOZ_STACK_CLASS TokenStream
const jschar *base_; // base of buffer
const jschar *limit_; // limit for quick bounds check
const jschar *ptr; // next char to get
// We are not yet moving strings
SkipRoot skipBase, skipLimit, skipPtr;
};
TokenKind getTokenInternal(Modifier modifier);
@ -898,15 +894,6 @@ class MOZ_STACK_CLASS TokenStream
ExclusiveContext *const cx;
JSPrincipals *const originPrincipals;
StrictModeGetter *strictModeGetter; // used to test for strict mode
// The tokens array stores pointers to JSAtoms. These are rooted by the
// atoms table using AutoKeepAtoms in the Parser. This SkipRoot tells the
// exact rooting analysis to ignore the atoms in the tokens array.
SkipRoot tokenSkip;
// Bug 846011
SkipRoot linebaseSkip;
SkipRoot prevLinebaseSkip;
};
// Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error

View File

@ -96,11 +96,6 @@ class IncrementalSafety
IncrementalSafety
IsIncrementalGCSafe(JSRuntime *rt);
#ifdef JSGC_ROOT_ANALYSIS
void *
GetAddressableGCThing(JSRuntime *rt, uintptr_t w);
#endif
#ifdef JS_GC_ZEAL
void
StartVerifyPreBarriers(JSRuntime *rt);

View File

@ -52,19 +52,6 @@ js::Nursery::init()
return false;
void *heap = MapAlignedPages(runtime(), NurserySize, Alignment);
#ifdef JSGC_ROOT_ANALYSIS
// Our poison pointers are not guaranteed to be invalid on 64-bit
// architectures, and often are valid. We can't just reserve the full
// poison range, because it might already have been taken up by something
// else (shared library, previous allocation). So we'll just loop and
// discard poison pointers until we get something valid.
//
// This leaks all of these poisoned pointers. It would be better if they
// were marked as uncommitted, but it's a little complicated to avoid
// clobbering pre-existing unrelated mappings.
while (IsPoisonedPtr(heap) || IsPoisonedPtr((void*)(uintptr_t(heap) + NurserySize)))
heap = MapAlignedPages(runtime(), NurserySize, Alignment);
#endif
if (!heap)
return false;

View File

@ -186,21 +186,6 @@ IsAddressableGCThing(JSRuntime *rt, uintptr_t w,
return CGCT_VALID;
}
#ifdef JSGC_ROOT_ANALYSIS
void *
js::gc::GetAddressableGCThing(JSRuntime *rt, uintptr_t w)
{
void *thing;
ArenaHeader *aheader;
AllocKind thingKind;
ConservativeGCTest status =
IsAddressableGCThing(rt, w, false, &thingKind, &aheader, &thing);
if (status != CGCT_VALID)
return nullptr;
return thing;
}
#endif
/*
* 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.

View File

@ -24,287 +24,6 @@ using namespace js;
using namespace js::gc;
using namespace mozilla;
#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
# if JS_STACK_GROWTH_DIRECTION > 0
# error "Root analysis is only supported on a descending stack."
# endif
template <typename T>
bool
CheckNonAddressThing(uintptr_t *w, Rooted<T> *rootp)
{
return w >= (uintptr_t*)rootp->address() && w < (uintptr_t*)(rootp->address() + 1);
}
static MOZ_ALWAYS_INLINE bool
CheckStackRootThing(uintptr_t *w, Rooted<void *> *rootp, ThingRootKind kind)
{
if (kind == THING_ROOT_BINDINGS)
return CheckNonAddressThing(w, reinterpret_cast<Rooted<Bindings> *>(rootp));
if (kind == THING_ROOT_PROPERTY_DESCRIPTOR)
return CheckNonAddressThing(w, reinterpret_cast<Rooted<PropertyDescriptor> *>(rootp));
if (kind == THING_ROOT_VALUE)
return CheckNonAddressThing(w, reinterpret_cast<Rooted<Value> *>(rootp));
return rootp->address() == static_cast<void*>(w);
}
struct Rooter {
Rooted<void*> *rooter;
ThingRootKind kind;
};
static void
CheckStackRoot(JSRuntime *rt, uintptr_t *w, Rooter *begin, Rooter *end)
{
/* Mark memory as defined for valgrind, as in MarkWordConservatively. */
#ifdef MOZ_VALGRIND
VALGRIND_MAKE_MEM_DEFINED(&w, sizeof(w));
#endif
void *thing = GetAddressableGCThing(rt, *w);
if (!thing)
return;
/* Don't check atoms as these will never be subject to generational collection. */
if (rt->isAtomsZone(static_cast<Cell *>(thing)->tenuredZone()))
return;
/*
* Note that |thing| may be in a free list (InFreeList(aheader, thing)),
* but we can skip that check because poisoning the pointer can't hurt; the
* pointer still cannot be used for a non-gcthing.
*/
for (Rooter *p = begin; p != end; p++) {
if (CheckStackRootThing(w, p->rooter, p->kind))
return;
}
SkipRoot *skip = TlsPerThreadData.get()->skipGCRooters;
while (skip) {
if (skip->contains(reinterpret_cast<uint8_t*>(w), sizeof(w)))
return;
skip = skip->previous();
}
for (ContextIter cx(rt); !cx.done(); cx.next()) {
skip = cx->skipGCRooters;
while (skip) {
if (skip->contains(reinterpret_cast<uint8_t*>(w), sizeof(w)))
return;
skip = skip->previous();
}
}
/*
* Only poison the last byte in the word. It is easy to get accidental
* collisions when a value that does not occupy a full word is used to
* overwrite a now-dead GC thing pointer. In this case we want to avoid
* damaging the smaller value.
*/
JS::PoisonPtr(w);
}
static void
CheckStackRootsRange(JSRuntime *rt, uintptr_t *begin, uintptr_t *end, Rooter *rbegin, Rooter *rend)
{
JS_ASSERT(begin <= end);
for (uintptr_t *i = begin; i != end; ++i)
CheckStackRoot(rt, i, rbegin, rend);
}
static void
CheckStackRootsRangeAndSkipJit(JSRuntime *rt, uintptr_t *begin, uintptr_t *end, Rooter *rbegin, Rooter *rend)
{
/*
* Regions of the stack between Ion activiations are marked exactly through
* a different mechanism. We need to skip these regions when checking the
* stack so that we do not poison IonMonkey's things.
*/
uintptr_t *i = begin;
#if defined(JS_ION)
for (jit::JitActivationIterator iter(rt); !iter.done(); ++iter) {
uintptr_t *jitMin, *jitEnd;
iter.jitStackRange(jitMin, jitEnd);
uintptr_t *upto = Min(jitMin, end);
if (upto > i)
CheckStackRootsRange(rt, i, upto, rbegin, rend);
else
break;
i = jitEnd;
}
#endif
/* The topmost Ion activiation may be beyond our prior top. */
if (i < end)
CheckStackRootsRange(rt, i, end, rbegin, rend);
}
static int
CompareRooters(const void *vpA, const void *vpB)
{
const Rooter *a = static_cast<const Rooter *>(vpA);
const Rooter *b = static_cast<const Rooter *>(vpB);
// There should be no duplicates, and we wouldn't care about their order anyway.
return (a->rooter < b->rooter) ? -1 : 1;
}
/*
* In the pathological cases that dominate much of the test case runtime,
* rooting analysis spends tons of time scanning the stack during a tight-ish
* loop. Since statically, everything is either rooted or it isn't, these scans
* are almost certain to be worthless. Detect these cases by checking whether
* the addresses of the top several rooters in the stack are recurring. Note
* that there may be more than one CheckRoots call within the loop, so we may
* alternate between a couple of stacks rather than just repeating the same one
* over and over, so we need more than a depth-1 memory.
*/
static bool
SuppressCheckRoots(js::Vector<Rooter, 0, SystemAllocPolicy> &rooters)
{
static const unsigned int NumStackMemories = 6;
static const size_t StackCheckDepth = 10;
static uint32_t stacks[NumStackMemories];
static unsigned int numMemories = 0;
static unsigned int oldestMemory = 0;
// Ugh. Sort the rooters. This should really be an O(n) rank selection
// followed by a sort. Interestingly, however, the overall scan goes a bit
// *faster* with this sort. Better branch prediction of the later
// partitioning pass, perhaps.
qsort(rooters.begin(), rooters.length(), sizeof(Rooter), CompareRooters);
// Forward-declare a variable so its address can be used to mark the
// current top of the stack.
unsigned int pos;
// Compute the hash of the current stack.
uint32_t hash = HashGeneric(&pos);
for (unsigned int i = 0; i < Min(StackCheckDepth, rooters.length()); i++)
hash = AddToHash(hash, rooters[rooters.length() - i - 1].rooter);
// Scan through the remembered stacks to find the current stack.
for (pos = 0; pos < numMemories; pos++) {
if (stacks[pos] == hash) {
// Skip this check. Technically, it is incorrect to not update the
// LRU queue position, but it'll cost us at most one extra check
// for every time a hot stack falls out of the window.
return true;
}
}
// Replace the oldest remembered stack with our current stack.
stacks[oldestMemory] = hash;
oldestMemory = (oldestMemory + 1) % NumStackMemories;
if (numMemories < NumStackMemories)
numMemories++;
return false;
}
static void
GatherRooters(js::Vector<Rooter, 0, SystemAllocPolicy> &rooters,
Rooted<void*> **thingGCRooters,
unsigned thingRootKind)
{
Rooted<void*> *rooter = thingGCRooters[thingRootKind];
while (rooter) {
Rooter r = { rooter, ThingRootKind(thingRootKind) };
JS_ALWAYS_TRUE(rooters.append(r));
rooter = rooter->previous();
}
}
void
JS::CheckStackRoots(JSContext *cx)
{
JSRuntime *rt = cx->runtime();
if (rt->gcZeal_ != ZealStackRootingValue)
return;
// GCs can't happen when analysis/inference/compilation are active.
if (cx->compartment()->activeAnalysis)
return;
if (rt->mainThread.suppressGC)
return;
// Can switch to the atoms compartment during analysis.
if (IsAtomsCompartment(cx->compartment())) {
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
if (c.get()->activeAnalysis)
return;
}
}
AutoCopyFreeListToArenas copy(rt, WithAtoms);
ConservativeGCData *cgcd = &rt->conservativeGC;
cgcd->recordStackTop();
JS_ASSERT(cgcd->hasStackToScan());
uintptr_t *stackMin, *stackEnd;
stackMin = cgcd->nativeStackTop + 1;
stackEnd = reinterpret_cast<uintptr_t *>(rt->nativeStackBase);
JS_ASSERT(stackMin <= stackEnd);
// Gather up all of the rooters
js::Vector<Rooter, 0, SystemAllocPolicy> rooters;
for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
for (ContextIter cx(rt); !cx.done(); cx.next()) {
GatherRooters(rooters, cx->thingGCRooters, i);
}
GatherRooters(rooters, rt->mainThread.thingGCRooters, i);
}
if (SuppressCheckRoots(rooters))
return;
// Truncate stackEnd to just after the address of the youngest
// already-scanned rooter on the stack, to avoid re-scanning the rest of
// the stack.
void *firstScanned = nullptr;
for (Rooter *p = rooters.begin(); p != rooters.end(); p++) {
if (p->rooter->scanned) {
uintptr_t *addr = reinterpret_cast<uintptr_t*>(p->rooter);
if (stackEnd > addr) {
stackEnd = addr;
firstScanned = p->rooter;
}
}
}
// Partition the stack by the already-scanned start address. Put everything
// that needs to be searched at the end of the vector.
Rooter *firstToScan = rooters.begin();
if (firstScanned) {
for (Rooter *p = rooters.begin(); p != rooters.end(); p++) {
if (p->rooter >= firstScanned) {
Swap(*firstToScan, *p);
++firstToScan;
}
}
}
CheckStackRootsRangeAndSkipJit(rt, stackMin, stackEnd, firstToScan, rooters.end());
CheckStackRootsRange(rt, cgcd->registerSnapshot.words,
ArrayEnd(cgcd->registerSnapshot.words),
firstToScan, rooters.end());
// Mark all rooters as scanned.
for (Rooter *p = rooters.begin(); p != rooters.end(); p++)
p->rooter->scanned = true;
}
#endif /* DEBUG && JS_GC_ZEAL && JSGC_ROOT_ANALYSIS && !JS_THREADSAFE */
#ifdef JS_GC_ZEAL
/*

View File

@ -1212,7 +1212,6 @@ GetPropertyIC::tryAttachNative(JSContext *cx, IonScript *ion, HandleObject obj,
*emitted = true;
MacroAssembler masm(cx, ion, script_, pc_);
SkipRoot skip(cx, &masm);
RepatchStubAppender attacher(*this);
const char *attachKind;
@ -2994,7 +2993,6 @@ GetElementIC::attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj,
Label failures;
MacroAssembler masm(cx, ion);
SkipRoot skip(cx, &masm);
// Ensure the index is a string.
ValueOperand val = index().reg().valueReg();

View File

@ -245,10 +245,7 @@ IsNullOrUndefined(MIRType type)
// Make sure registers are not modified between an instruction and
// its OsiPoint.
//
// Skip this check in rooting analysis builds, which poison unrooted
// pointers on the stack.
# if defined(JS_ION) && !defined(JSGC_ROOT_ANALYSIS)
# if defined(JS_ION)
# define CHECK_OSIPOINT_REGISTERS 1
# endif
#endif

View File

@ -2,7 +2,7 @@
* 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_ROOT_ANALYSIS) && !defined(JSGC_USE_EXACT_ROOTING)
#if !defined(JSGC_USE_EXACT_ROOTING)
#include "jsobj.h"
@ -85,4 +85,4 @@ BEGIN_TEST(testDerivedValues)
}
END_TEST(testDerivedValues)
#endif /* !defined(JSGC_ROOT_ANALYSIS) && !defined(JSGC_USE_EXACT_ROOTING) */
#endif /* !defined(JSGC_USE_EXACT_ROOTING) */

View File

@ -142,12 +142,11 @@ class AutoValueArray : public AutoGCRooter
{
const size_t length_;
Value elements_[N];
js::SkipRoot skip_;
public:
AutoValueArray(JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, VALARRAY), length_(N), skip_(cx, elements_, N)
: AutoGCRooter(cx, VALARRAY), length_(N)
{
/* Always initialize in case we GC before assignment. */
mozilla::PodArrayZero(elements_);
@ -176,20 +175,17 @@ class AutoVectorRooter : protected AutoGCRooter
typedef js::Vector<T, 8> VectorImpl;
VectorImpl vector;
/* Prevent overwriting of inline elements in vector. */
js::SkipRoot vectorRoot;
public:
explicit AutoVectorRooter(JSContext *cx, ptrdiff_t tag
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, tag), vector(cx), vectorRoot(cx, &vector)
: AutoGCRooter(cx, tag), vector(cx)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
explicit AutoVectorRooter(js::ContextFriendFields *cx, ptrdiff_t tag
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, tag), vector(cx), vectorRoot(cx, &vector)
: AutoGCRooter(cx, tag), vector(cx)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
@ -1039,10 +1035,6 @@ MOZ_ALWAYS_INLINE bool
ToNumber(JSContext *cx, HandleValue v, double *out)
{
AssertArgumentsAreSane(cx, v);
{
js::SkipRoot root(cx, &v);
js::MaybeCheckStackRoots(cx);
}
if (v.isNumber()) {
*out = v.toNumber();
@ -1117,7 +1109,6 @@ MOZ_ALWAYS_INLINE bool
ToUint16(JSContext *cx, JS::HandleValue v, uint16_t *out)
{
AssertArgumentsAreSane(cx, v);
js::MaybeCheckStackRoots(cx);
if (v.isInt32()) {
*out = uint16_t(v.toInt32());
@ -1130,7 +1121,6 @@ MOZ_ALWAYS_INLINE bool
ToInt32(JSContext *cx, JS::HandleValue v, int32_t *out)
{
AssertArgumentsAreSane(cx, v);
js::MaybeCheckStackRoots(cx);
if (v.isInt32()) {
*out = v.toInt32();
@ -1143,7 +1133,6 @@ MOZ_ALWAYS_INLINE bool
ToUint32(JSContext *cx, JS::HandleValue v, uint32_t *out)
{
AssertArgumentsAreSane(cx, v);
js::MaybeCheckStackRoots(cx);
if (v.isInt32()) {
*out = uint32_t(v.toInt32());
@ -1156,13 +1145,11 @@ MOZ_ALWAYS_INLINE bool
ToInt64(JSContext *cx, JS::HandleValue v, int64_t *out)
{
AssertArgumentsAreSane(cx, v);
js::MaybeCheckStackRoots(cx);
if (v.isInt32()) {
*out = int64_t(v.toInt32());
return true;
}
return js::ToInt64Slow(cx, v, out);
}
@ -1170,14 +1157,12 @@ MOZ_ALWAYS_INLINE bool
ToUint64(JSContext *cx, JS::HandleValue v, uint64_t *out)
{
AssertArgumentsAreSane(cx, v);
js::MaybeCheckStackRoots(cx);
if (v.isInt32()) {
/* Account for sign extension of negatives into the longer 64bit space. */
*out = uint64_t(int64_t(v.toInt32()));
return true;
}
return js::ToUint64Slow(cx, v, out);
}

View File

@ -325,7 +325,6 @@ AtomizeAndtake(ExclusiveContext *cx, jschar *tbchars, size_t length, InternBehav
*/
AtomSet& atoms = cx->atoms();
AtomSet::AddPtr p = atoms.lookupForAdd(lookup);
SkipRoot skipHash(cx, &p); /* Prevent the hash from being poisoned. */
if (p) {
JSAtom *atom = p->asPtr();
p->setTagged(bool(ib));
@ -377,7 +376,6 @@ AtomizeAndCopyChars(ExclusiveContext *cx, const jschar *tbchars, size_t length,
AtomSet& atoms = cx->atoms();
AtomSet::AddPtr p = atoms.lookupForAdd(lookup);
SkipRoot skipHash(cx, &p); /* Prevent the hash from being poisoned. */
if (p) {
JSAtom *atom = p->asPtr();
p->setTagged(bool(ib));

View File

@ -232,7 +232,7 @@ js::DestroyContext(JSContext *cx, DestroyContextMode mode)
MOZ_CRASH();
#endif
#if (defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)) && defined(DEBUG)
#if defined(JSGC_USE_EXACT_ROOTING) && defined(DEBUG)
for (int i = 0; i < THING_ROOT_LIMIT; ++i)
JS_ASSERT(cx->thingGCRooters[i] == nullptr);
#endif

View File

@ -393,12 +393,6 @@ class ExclusiveContext : public ThreadSafeContext
void addPendingOverRecursed();
};
inline void
MaybeCheckStackRoots(ExclusiveContext *cx)
{
MaybeCheckStackRoots(cx->maybeJSContext());
}
} /* namespace js */
struct JSContext : public js::ExclusiveContext,
@ -934,7 +928,7 @@ class AutoArrayRooter : private AutoGCRooter
public:
AutoArrayRooter(JSContext *cx, size_t len, Value *vec
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, len), array(vec), skip(cx, array, len)
: AutoGCRooter(cx, len), array(vec)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
JS_ASSERT(tag_ >= 0);
@ -980,7 +974,6 @@ class AutoArrayRooter : private AutoGCRooter
private:
Value *array;
js::SkipRoot skip;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};

View File

@ -39,12 +39,9 @@ JS_STATIC_ASSERT(offsetof(JSRuntime, mainThread) ==
PerThreadDataFriendFields::PerThreadDataFriendFields()
{
PodArrayZero(nativeStackLimit);
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
#if defined(JSGC_USE_EXACT_ROOTING)
PodArrayZero(thingGCRooters);
#endif
#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
skipGCRooters = nullptr;
#endif
}
JS_FRIEND_API(void)

View File

@ -1589,9 +1589,6 @@ FunctionConstructor(JSContext *cx, unsigned argc, Value *vp, GeneratorKind gener
const jschar *chars = linear->chars();
size_t length = linear->length();
/* Protect inlined chars from root analysis poisoning. */
SkipRoot skip(cx, &chars);
/*
* 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

@ -746,21 +746,6 @@ ChunkPool::expireAndFree(JSRuntime *rt, bool releaseAll)
Chunk::allocate(JSRuntime *rt)
{
Chunk *chunk = AllocChunk(rt);
#ifdef JSGC_ROOT_ANALYSIS
// Our poison pointers are not guaranteed to be invalid on 64-bit
// architectures, and often are valid. We can't just reserve the full
// poison range, because it might already have been taken up by something
// else (shared library, previous allocation). So we'll just loop and
// discard poison pointers until we get something valid.
//
// This leaks all of these poisoned pointers. It would be better if they
// were marked as uncommitted, but it's a little complicated to avoid
// clobbering pre-existing unrelated mappings.
while (IsPoisonedPtr(chunk))
chunk = AllocChunk(rt);
#endif
if (!chunk)
return nullptr;
chunk->init(rt);
@ -4926,10 +4911,6 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget,
TraceLogging::GC_STOP);
#endif
ContextIter cx(rt);
if (!cx.done())
MaybeCheckStackRoots(cx);
#ifdef JS_GC_ZEAL
if (rt->gcDeterministicOnly && !IsDeterministicGCReason(reason))
return;

View File

@ -437,8 +437,6 @@ CheckAllocatorState(ThreadSafeContext *cx, AllocKind kind)
// handle that here. Just check in case we need to collect instead.
js::gc::GCIfNeeded(ncx);
}
MaybeCheckStackRoots(ncx);
}
return true;

View File

@ -3384,17 +3384,7 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
size_t numBytes = sizeof(TypeNewScript)
+ (initializerList.length() * sizeof(TypeNewScript::Initializer));
TypeNewScript *newScript;
#ifdef JSGC_ROOT_ANALYSIS
// calloc can legitimately return a pointer that appears to be poisoned.
void *p;
do {
p = cx->calloc_(numBytes);
} while (IsPoisonedPtr(p));
newScript = (TypeNewScript *) p;
#else
newScript = (TypeNewScript *) cx->calloc_(numBytes);
#endif
TypeNewScript *newScript = (TypeNewScript *) cx->calloc_(numBytes);
if (!newScript)
return;

View File

@ -1562,25 +1562,6 @@ js::NonObjectToNumberSlow(ThreadSafeContext *cx, Value v, double *out)
bool
js::ToNumberSlow(ExclusiveContext *cx, Value v, double *out)
{
#ifdef DEBUG
/*
* MSVC bizarrely miscompiles this, complaining about the first brace below
* being unmatched (!). The error message points at both this opening brace
* and at the corresponding SkipRoot constructor. The error seems to derive
* from the presence guard-object macros on the SkipRoot class/constructor,
* which seems well in the weeds for an unmatched-brace syntax error.
* Otherwise the problem is inscrutable, and I haven't found a workaround.
* So for now just disable it when compiling with MSVC -- not ideal, but at
* least Windows debug shell builds complete again.
*/
#ifndef _MSC_VER
{
SkipRoot skip(cx, &v);
MaybeCheckStackRoots(cx);
}
#endif
#endif
JS_ASSERT(!v.isNumber());
goto skip_int_double;
for (;;) {

View File

@ -151,10 +151,6 @@ StringToNumber(ThreadSafeContext *cx, JSString *str, double *result);
MOZ_ALWAYS_INLINE bool
ToNumber(JSContext *cx, JS::MutableHandleValue vp)
{
#ifdef DEBUG
MaybeCheckStackRoots(cx);
#endif
if (vp.isNumber())
return true;
double d;
@ -233,13 +229,6 @@ IsDefinitelyIndex(const Value &v, uint32_t *indexp)
static inline bool
ToInteger(JSContext *cx, HandleValue v, double *dp)
{
#ifdef DEBUG
{
SkipRoot skip(cx, &v);
MaybeCheckStackRoots(cx);
}
#endif
if (v.isInt32()) {
*dp = v.toInt32();
return true;

View File

@ -795,7 +795,7 @@ class AutoPropDescArrayRooter : private AutoGCRooter
{
public:
AutoPropDescArrayRooter(JSContext *cx)
: AutoGCRooter(cx, DESCRIPTORS), descriptors(cx), skip(cx, &descriptors)
: AutoGCRooter(cx, DESCRIPTORS), descriptors(cx)
{ }
PropDesc *append() {
@ -817,7 +817,6 @@ class AutoPropDescArrayRooter : private AutoGCRooter
private:
PropDescArray descriptors;
SkipRoot skip;
};
/*

View File

@ -20,7 +20,7 @@
#include "js/TypeDecls.h"
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) || defined(JS_DEBUG)
#if defined(JSGC_USE_EXACT_ROOTING) || defined(JS_DEBUG)
# define JSGC_TRACK_EXACT_ROOTS
#endif
@ -269,8 +269,6 @@ class ExclusiveContext;
class Allocator;
class SkipRoot;
enum ThingRootKind
{
THING_ROOT_OBJECT,
@ -342,9 +340,6 @@ struct ContextFriendFields
{
#ifdef JSGC_TRACK_EXACT_ROOTS
mozilla::PodArrayZero(thingGCRooters);
#endif
#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
skipGCRooters = nullptr;
#endif
}
@ -364,18 +359,6 @@ struct ContextFriendFields
JS::Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
#endif
#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
/*
* Stack allocated list of stack locations which hold non-relocatable
* GC heap pointers (where the target is rooted somewhere else) or integer
* values which may be confused for GC heap pointers. These are used to
* suppress false positives which occur when a rooting analysis treats the
* location as holding a relocatable pointer, but have no other effect on
* GC behavior.
*/
SkipRoot *skipGCRooters;
#endif
/* Stack of thread-stack-allocated GC roots. */
JS::AutoGCRooter *autoGCRooters;
@ -443,18 +426,6 @@ struct PerThreadDataFriendFields
JS::Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
#endif
#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
/*
* Stack allocated list of stack locations which hold non-relocatable
* GC heap pointers (where the target is rooted somewhere else) or integer
* values which may be confused for GC heap pointers. These are used to
* suppress false positives which occur when a rooting analysis treats the
* location as holding a relocatable pointer, but have no other effect on
* GC behavior.
*/
SkipRoot *skipGCRooters;
#endif
/* Limit pointer for checking native stack consumption. */
uintptr_t nativeStackLimit[StackKindCount];

View File

@ -2117,7 +2117,6 @@ struct ReplaceData
{
ReplaceData(JSContext *cx)
: str(cx), g(cx), lambda(cx), elembase(cx), repstr(cx),
dollarRoot(cx, &dollar), dollarEndRoot(cx, &dollarEnd),
fig(cx, NullValue()), sb(cx)
{}
@ -2147,8 +2146,6 @@ struct ReplaceData
Rooted<JSLinearString*> repstr; /* replacement string */
const jschar *dollar; /* null or pointer to first $ in repstr */
const jschar *dollarEnd; /* limit pointer for js_strchr_limit */
SkipRoot dollarRoot; /* XXX prevent dollar from being relocated */
SkipRoot dollarEndRoot; /* ditto */
int leftIndex; /* left context index in str->chars */
JSSubString dollarStr; /* for "$$" InterpretDollar result */
bool calledBack; /* record whether callback has been called */

View File

@ -149,13 +149,6 @@ template <AllowGC allowGC>
static MOZ_ALWAYS_INLINE JSString *
ToString(JSContext *cx, JS::HandleValue v)
{
#ifdef DEBUG
if (allowGC) {
SkipRoot skip(cx, &v);
MaybeCheckStackRoots(cx);
}
#endif
if (v.isString())
return v.toString();
return ToStringSlow<allowGC>(cx, v);

View File

@ -2720,8 +2720,6 @@ EvalInContext(JSContext *cx, unsigned argc, jsval *vp)
if (!src)
return false;
SkipRoot skip(cx, &src);
bool lazy = false;
if (srclen == 4) {
if (src[0] == 'l' && src[1] == 'a' && src[2] == 'z' && src[3] == 'y') {

View File

@ -333,9 +333,6 @@ typedef bool (*CountAction)(JSContext *, const UTF8Chars, jschar *, size_t *, bo
static TwoByteCharsZ
InflateUTF8StringHelper(JSContext *cx, const UTF8Chars src, CountAction countAction, size_t *outlen)
{
// Malformed UTF8 chars could trigger errors and hence GC.
MaybeCheckStackRoots(cx);
*outlen = 0;
bool isAscii;

View File

@ -1306,9 +1306,6 @@ JSAbstractFramePtr::evaluateUCInStackFrame(JSContext *cx,
const char *filename, unsigned lineno,
MutableHandleValue rval)
{
/* Protect inlined chars from root analysis poisoning. */
SkipRoot skipChars(cx, &chars);
if (!CheckDebugMode(cx))
return false;

View File

@ -520,9 +520,6 @@ RegExpRunStatus
RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length,
size_t *lastIndex, MatchPairs &matches)
{
/* Protect inlined chars from root analysis poisoning. */
SkipRoot skip(cx, &chars);
/* Compile the code at point-of-use. */
if (!compileIfNecessary(cx))
return RegExpRunStatus_Error;
@ -576,9 +573,6 @@ RegExpRunStatus
RegExpShared::executeMatchOnly(JSContext *cx, const jschar *chars, size_t length,
size_t *lastIndex, MatchPair &match)
{
/* These chars may be inline in a string. See bug 846011. */
SkipRoot skipChars(cx, &chars);
/* Compile the code at point-of-use. */
if (!compileMatchOnlyIfNecessary(cx))
return RegExpRunStatus_Error;

View File

@ -171,7 +171,7 @@ class AutoRegExpStaticsBuffer : private JS::CustomAutoRooter
public:
explicit AutoRegExpStaticsBuffer(JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: CustomAutoRooter(cx), statics(RegExpStatics::InitBuffer()), skip(cx, &statics)
: CustomAutoRooter(cx), statics(RegExpStatics::InitBuffer())
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
@ -195,7 +195,6 @@ class AutoRegExpStaticsBuffer : private JS::CustomAutoRooter
}
RegExpStatics statics;
SkipRoot skip;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};

View File

@ -141,18 +141,6 @@ struct ConservativeGCData
*/
uintptr_t *nativeStackTop;
#if defined(JSGC_ROOT_ANALYSIS) && (JS_STACK_GROWTH_DIRECTION < 0)
/*
* Record old contents of the native stack from the last time there was a
* scan, to reduce the overhead involved in repeatedly rescanning the
* native stack during root analysis. oldStackData stores words in reverse
* order starting at oldStackEnd.
*/
uintptr_t *oldStackMin, *oldStackEnd;
uintptr_t *oldStackData;
size_t oldStackCapacity; // in sizeof(uintptr_t)
#endif
union {
jmp_buf jmpbuf;
uintptr_t words[JS_HOWMANY(sizeof(jmp_buf), sizeof(uintptr_t))];

View File

@ -188,8 +188,7 @@ inline
AutoRooterGetterSetter::Inner::Inner(ThreadSafeContext *cx, uint8_t attrs,
PropertyOp *pgetter_, StrictPropertyOp *psetter_)
: CustomAutoRooter(cx), attrs(attrs),
pgetter(pgetter_), psetter(psetter_),
getterRoot(cx, pgetter_), setterRoot(cx, psetter_)
pgetter(pgetter_), psetter(psetter_)
{
JS_ASSERT_IF(attrs & JSPROP_GETTER, !IsPoisonedPtr(*pgetter));
JS_ASSERT_IF(attrs & JSPROP_SETTER, !IsPoisonedPtr(*psetter));

View File

@ -1710,7 +1710,6 @@ EmptyShape::getInitialShape(ExclusiveContext *cx, const Class *clasp, TaggedProt
if (p)
return p->shape;
SkipRoot skip(cx, &p); /* The hash may look like a GC pointer and get poisoned. */
Rooted<TaggedProto> protoRoot(cx, proto);
RootedObject parentRoot(cx, parent);
RootedObject metadataRoot(cx, metadata);

View File

@ -338,7 +338,7 @@ class AutoPropDescRooter : private JS::CustomAutoRooter
public:
explicit AutoPropDescRooter(JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: CustomAutoRooter(cx), skip(cx, &propDesc)
: CustomAutoRooter(cx)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
@ -388,7 +388,6 @@ class AutoPropDescRooter : private JS::CustomAutoRooter
virtual void trace(JSTracer *trc);
PropDesc propDesc;
SkipRoot skip;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
@ -1321,7 +1320,6 @@ class AutoRooterGetterSetter
uint8_t attrs;
PropertyOp *pgetter;
StrictPropertyOp *psetter;
SkipRoot getterRoot, setterRoot;
};
public:

View File

@ -920,7 +920,6 @@ class TypedArrayObjectTemplate : public TypedArrayObject
#endif
NativeType *dest = static_cast<NativeType*>(thisTypedArray->viewData()) + offset;
SkipRoot skipDest(cx, &dest);
if (ar->is<ArrayObject>() && !ar->isIndexed() && ar->getDenseInitializedLength() >= len) {
JS_ASSERT(ar->as<ArrayObject>().length() == len);
@ -931,7 +930,6 @@ class TypedArrayObjectTemplate : public TypedArrayObject
* to root |src| and |dest|.
*/
const Value *src = ar->getDenseElements();
SkipRoot skipSrc(cx, &src);
uint32_t i = 0;
do {
NativeType n;
@ -1594,7 +1592,6 @@ DataViewObject::write(JSContext *cx, Handle<DataViewObject*> obj,
}
uint8_t *data;
SkipRoot skipData(cx, &data);
if (!getDataPointer(cx, obj, args, sizeof(NativeType), &data))
return false;