Bug 831581 - Don't poison pointers embedded in the inline asm buffer; r=bhackett

--HG--
rename : docshell/test/browser/browser_bug234628-8.js => docshell/test/browser/browser_bug134911.js
extra : rebase_source : 7a73219b7e2e02869b521da853a764bb34a3cef6
This commit is contained in:
Terrence Cole 2013-01-17 08:42:00 -08:00
parent 7cc374989b
commit 5012959b6b
7 changed files with 65 additions and 77 deletions

View File

@ -40,8 +40,10 @@
#include "assembler/wtf/Assertions.h"
#include <stdarg.h>
#include "jsfriendapi.h"
#include "jsopcode.h"
#include "gc/Root.h"
#include "methodjit/Logging.h"
#include "ion/IonSpewer.h"
@ -63,6 +65,9 @@ namespace JSC {
, m_capacity(inlineCapacity)
, m_size(0)
, m_oom(false)
#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
, m_skipInline(js::TlsPerThreadData.get(), &m_inlineBuffer)
#endif
{
}
@ -246,6 +251,17 @@ namespace JSC {
int m_capacity;
int m_size;
bool m_oom;
#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
/*
* GC Pointers baked into the code can get stored on the stack here
* through the inline assembler buffer. We need to protect these from
* being poisoned by the rooting analysis, however, they do not need to
* actually be traced: the compiler is only allowed to bake in
* non-nursery-allocated pointers, such as Shapes.
*/
js::SkipRoot m_skipInline;
#endif
};
class GenericAssembler

View File

@ -609,40 +609,7 @@ class Rooted : public RootedBase<T>
#endif
}
void init(JSRuntime *rtArg) {
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
PerThreadDataFriendFields *pt = PerThreadDataFriendFields::getMainThread(rtArg);
commonInit(pt->thingGCRooters);
#endif
}
void init(js::PerThreadData *ptArg) {
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
PerThreadDataFriendFields *pt = PerThreadDataFriendFields::get(ptArg);
commonInit(pt->thingGCRooters);
#endif
#if defined(JSGC_ROOT_ANALYSIS)
scanned = false;
#endif
}
public:
Rooted(JSRuntime *rt
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: ptr(RootMethods<T>::initial())
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
init(rt);
}
Rooted(JSRuntime *rt, T initial
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: ptr(initial)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
init(rt);
}
Rooted(JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: ptr(RootMethods<T>::initial())
@ -659,22 +626,6 @@ class Rooted : public RootedBase<T>
init(cx);
}
Rooted(js::PerThreadData *pt
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: ptr(RootMethods<T>::initial())
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
init(pt);
}
Rooted(js::PerThreadData *pt, T initial
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: ptr(initial)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
init(pt);
}
template <typename S>
Rooted(JSContext *cx, const Unrooted<S> &initial
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
@ -787,8 +738,8 @@ class SkipRoot
const uint8_t *end;
template <typename T>
void init(ContextFriendFields *cx, const T *ptr, size_t count) {
this->stack = &cx->skipGCRooters;
void init(SkipRoot **head, const T *ptr, size_t count) {
this->stack = head;
this->prev = *stack;
*stack = this;
this->start = (const uint8_t *) ptr;
@ -800,7 +751,16 @@ class SkipRoot
SkipRoot(JSContext *cx, const T *ptr, size_t count = 1
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
{
init(ContextFriendFields::get(cx), ptr, count);
init(&ContextFriendFields::get(cx)->skipGCRooters, ptr, count);
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
template <typename T>
SkipRoot(js::PerThreadData *ptd, const T *ptr, size_t count = 1
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
{
PerThreadDataFriendFields *ptff = PerThreadDataFriendFields::get(ptd);
init(&ptff->skipGCRooters, ptr, count);
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
@ -825,6 +785,13 @@ class SkipRoot
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
template <typename T>
SkipRoot(PerThreadData *ptd, const T *ptr, size_t count = 1
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
#endif /* DEBUG && JSGC_ROOT_ANALYSIS */
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER

View File

@ -43,7 +43,7 @@ typedef RootedValueMap::Enum RootEnum;
#ifdef JSGC_USE_EXACT_ROOTING
static inline void
MarkExactStackRooter(JSTracer *trc, Rooted<void*> rooter, ThingRootKind kind)
MarkExactStackRoot(JSTracer *trc, Rooted<void*> *rooter, ThingRootKind kind)
{
void **addr = (void **)rooter->address();
if (!*addr)
@ -51,7 +51,7 @@ MarkExactStackRooter(JSTracer *trc, Rooted<void*> rooter, ThingRootKind kind)
switch (kind) {
case THING_ROOT_OBJECT: MarkObjectRoot(trc, (JSObject **)addr, "exact-object"); break;
case THING_ROOT_STRING: MarkStringRoot(trc, (JSSTring **)addr, "exact-string"); break;
case THING_ROOT_STRING: MarkStringRoot(trc, (JSString **)addr, "exact-string"); break;
case THING_ROOT_SCRIPT: MarkScriptRoot(trc, (JSScript **)addr, "exact-script"); break;
case THING_ROOT_SHAPE: MarkShapeRoot(trc, (Shape **)addr, "exact-shape"); break;
case THING_ROOT_BASE_SHAPE: MarkBaseShapeRoot(trc, (BaseShape **)addr, "exact-baseshape"); break;
@ -66,11 +66,10 @@ MarkExactStackRooter(JSTracer *trc, Rooted<void*> rooter, ThingRootKind kind)
}
static inline void
MarkExactStackRooters(JSTracer *trc, Rooted<void*> rooter, ThingRootKind kind)
MarkExactStackRootList(JSTracer *trc, Rooted<void*> *rooter, ThingRootKind kind)
{
Rooted<void*> *rooter = cx->thingGCRooters[i];
while (rooter) {
MarkExactStackRoot(trc, rooter, ThingRootKind(i));
MarkExactStackRoot(trc, rooter, kind);
rooter = rooter->previous();
}
}
@ -79,10 +78,8 @@ static void
MarkExactStackRoots(JSTracer *trc)
{
for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
for (ContextIter cx(trc->runtime); !cx.done(); cx.next()) {
MarkExactStackRooters(trc, cx->thingGCRooters[i], ThingRootKind(i));
}
MarkExactStackRooters(trc, rt->mainThread.thingGCRooters[i], ThingRootKind(i));
for (ContextIter cx(trc->runtime); !cx.done(); cx.next())
MarkExactStackRootList(trc, cx->thingGCRooters[i], ThingRootKind(i));
}
}
#endif /* JSGC_USE_EXACT_ROOTING */

View File

@ -70,8 +70,14 @@ CheckStackRoot(JSRuntime *rt, uintptr_t *w, Rooter *begin, Rooter *end)
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()) {
SkipRoot *skip = cx->skipGCRooters;
skip = cx->skipGCRooters;
while (skip) {
if (skip->contains(reinterpret_cast<uint8_t*>(w), sizeof(w)))
return;
@ -239,14 +245,8 @@ JS::CheckStackRoots(JSContext *cx)
// Gather up all of the rooters
Vector< Rooter, 0, SystemAllocPolicy> rooters;
for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
Rooted<void*> *rooter = rt->mainThread.thingGCRooters[i];
while (rooter) {
Rooter r = { rooter, ThingRootKind(i) };
JS_ALWAYS_TRUE(rooters.append(r));
rooter = rooter->previous();
}
for (ContextIter cx(rt); !cx.done(); cx.next()) {
rooter = cx->thingGCRooters[i];
Rooted<void*> *rooter = cx->thingGCRooters[i];
while (rooter) {
Rooter r = { rooter, ThingRootKind(i) };
JS_ALWAYS_TRUE(rooters.append(r));

View File

@ -100,13 +100,17 @@ struct ImmGCPtr
uintptr_t value;
explicit ImmGCPtr(const gc::Cell *ptr) : value(reinterpret_cast<uintptr_t>(ptr))
{ }
{
JS_ASSERT(!IsPoisonedPtr(ptr));
}
// ImmGCPtr is rooted so we can convert safely directly from Unrooted<T>.
template <typename T>
explicit ImmGCPtr(Unrooted<T> ptr)
: value(reinterpret_cast<uintptr_t>(static_cast<T>(ptr)))
{ }
{
JS_ASSERT(!IsPoisonedPtr(static_cast<T>(ptr)));
}
};
// Specifies a hardcoded, absolute address.

View File

@ -27,8 +27,8 @@ JS_STATIC_ASSERT(offsetof(JSRuntime, mainThread) == sizeof(RuntimeFriendFields))
PerThreadDataFriendFields::PerThreadDataFriendFields()
{
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
PodArrayZero(thingGCRooters);
#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
skipGCRooters = NULL;
#endif
}

View File

@ -319,12 +319,16 @@ struct PerThreadDataFriendFields
{
PerThreadDataFriendFields();
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
/*
* Stack allocated GC roots for stack GC heap pointers, which may be
* overwritten if moved during a GC.
* 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.
*/
Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
SkipRoot *skipGCRooters;
#endif
static PerThreadDataFriendFields *get(js::PerThreadData *pt) {