mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 987666 - Remove the unused dynamic root analysis. r=sfink
This commit is contained in:
parent
8b0a1acbe6
commit
fe8f16e4e5
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 ========================================================
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
/*
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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) */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 (;;) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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') {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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))];
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user