mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 662646 - GC topcrash diagnostics [needs backout before Aurora merge!] (r=dmandelin)
This commit is contained in:
parent
b8f0545e72
commit
2a3d5215a6
@ -412,6 +412,12 @@ struct JSRuntime {
|
||||
/* Compartment that is currently involved in per-compartment GC */
|
||||
JSCompartment *gcCurrentCompartment;
|
||||
|
||||
/*
|
||||
* If this is non-NULL, all marked objects must belong to this compartment.
|
||||
* This is used to look for compartment bugs.
|
||||
*/
|
||||
JSCompartment *gcCheckCompartment;
|
||||
|
||||
/*
|
||||
* We can pack these flags as only the GC thread writes to them. Atomic
|
||||
* updates to packed bytes are not guaranteed, so stores issued by one
|
||||
|
@ -100,6 +100,11 @@ struct CrashRing
|
||||
char buffer[crash_buffer_size];
|
||||
};
|
||||
|
||||
/* These are the tag values for each entry in the CrashRing. */
|
||||
enum {
|
||||
JS_CRASH_TAG_GC = 0x200
|
||||
};
|
||||
|
||||
} /* namespace crash */
|
||||
} /* namespace js */
|
||||
|
||||
|
@ -268,7 +268,7 @@ js_SaveCrashData(uint64 tag, void *ptr, size_t size)
|
||||
JS_PUBLIC_API(void)
|
||||
JS_EnumerateDiagnosticMemoryRegions(JSEnumerateDiagnosticMemoryCallback callback)
|
||||
{
|
||||
#if 0
|
||||
#if 1
|
||||
if (!gInitialized) {
|
||||
gInitialized = true;
|
||||
(*callback)(&gGCStack, sizeof(gGCStack));
|
||||
|
@ -60,6 +60,8 @@
|
||||
#include "jsapi.h"
|
||||
#include "jsatom.h"
|
||||
#include "jscompartment.h"
|
||||
#include "jscrashreport.h"
|
||||
#include "jscrashformat.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsversion.h"
|
||||
#include "jsdbgapi.h"
|
||||
@ -239,9 +241,7 @@ Arena::finalize(JSContext *cx)
|
||||
if (!newFreeSpanStart)
|
||||
newFreeSpanStart = thing;
|
||||
t->finalize(cx);
|
||||
#ifdef DEBUG
|
||||
memset(t, JS_FREE_PATTERN, sizeof(T));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2662,6 +2662,12 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIMER_P
|
||||
(*c)->setGCLastBytes((*c)->gcBytes, gckind);
|
||||
}
|
||||
|
||||
struct GCCrashData
|
||||
{
|
||||
int isRegen;
|
||||
int isCompartment;
|
||||
};
|
||||
|
||||
void
|
||||
js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
|
||||
{
|
||||
@ -2683,6 +2689,11 @@ js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
|
||||
|
||||
RecordNativeStackTopForGC(cx);
|
||||
|
||||
GCCrashData crashData;
|
||||
crashData.isRegen = rt->shapeGen & SHAPE_OVERFLOW_BIT;
|
||||
crashData.isCompartment = !!comp;
|
||||
js_SaveCrashData(crash::JS_CRASH_TAG_GC, &crashData, sizeof(crashData));
|
||||
|
||||
GCTIMER_BEGIN(rt, comp);
|
||||
|
||||
do {
|
||||
@ -2721,6 +2732,8 @@ js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
|
||||
|
||||
rt->gcChunkAllocationSinceLastGC = false;
|
||||
GCTIMER_END(gckind == GC_LAST_CONTEXT);
|
||||
|
||||
js_SnapshotGCStack();
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
@ -115,6 +115,12 @@ Mark(JSTracer *trc, T *thing)
|
||||
JS_ASSERT(thing->arenaHeader()->compartment);
|
||||
JS_ASSERT(thing->arenaHeader()->compartment->rt == rt);
|
||||
|
||||
if (rt->gcCheckCompartment && thing->compartment() != rt->gcCheckCompartment &&
|
||||
thing->compartment() != rt->atomsCompartment)
|
||||
{
|
||||
JS_Assert("compartment mismatch in GC", __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't mark things outside a compartment if we are in a per-compartment
|
||||
* GC.
|
||||
@ -158,6 +164,16 @@ MarkObject(JSTracer *trc, JSObject &obj, const char *name)
|
||||
Mark(trc, &obj);
|
||||
}
|
||||
|
||||
void
|
||||
MarkCrossCompartmentObject(JSTracer *trc, JSObject &obj, const char *name)
|
||||
{
|
||||
JSRuntime *rt = trc->context->runtime;
|
||||
if (rt->gcCurrentCompartment && rt->gcCurrentCompartment != obj.compartment())
|
||||
return;
|
||||
|
||||
MarkObject(trc, obj, name);
|
||||
}
|
||||
|
||||
void
|
||||
MarkObjectWithPrinter(JSTracer *trc, JSObject &obj, JSTraceNamePrinter printer,
|
||||
const void *arg, size_t index)
|
||||
@ -351,6 +367,22 @@ MarkValue(JSTracer *trc, const js::Value &v, const char *name)
|
||||
MarkValueRaw(trc, v);
|
||||
}
|
||||
|
||||
void
|
||||
MarkCrossCompartmentValue(JSTracer *trc, const js::Value &v, const char *name)
|
||||
{
|
||||
if (v.isMarkable()) {
|
||||
js::gc::Cell *cell = (js::gc::Cell *)v.toGCThing();
|
||||
unsigned kind = v.gcKind();
|
||||
if (kind == JSTRACE_STRING && ((JSString *)cell)->isStaticAtom())
|
||||
return;
|
||||
JSRuntime *rt = trc->context->runtime;
|
||||
if (rt->gcCurrentCompartment && cell->compartment() != rt->gcCurrentCompartment)
|
||||
return;
|
||||
|
||||
MarkValue(trc, v, name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MarkValueRange(JSTracer *trc, Value *beg, Value *end, const char *name)
|
||||
{
|
||||
@ -748,6 +780,9 @@ MarkChildren(JSTracer *trc, JSXML *xml)
|
||||
void
|
||||
GCMarker::drainMarkStack()
|
||||
{
|
||||
JSRuntime *rt = context->runtime;
|
||||
rt->gcCheckCompartment = rt->gcCurrentCompartment;
|
||||
|
||||
while (!isMarkStackEmpty()) {
|
||||
while (!ropeStack.isEmpty())
|
||||
ScanRope(this, ropeStack.pop());
|
||||
@ -772,6 +807,8 @@ GCMarker::drainMarkStack()
|
||||
markDelayedChildren();
|
||||
}
|
||||
}
|
||||
|
||||
rt->gcCheckCompartment = NULL;
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
@ -62,6 +62,13 @@ MarkString(JSTracer *trc, JSString *str, const char *name);
|
||||
void
|
||||
MarkObject(JSTracer *trc, JSObject &obj, const char *name);
|
||||
|
||||
/*
|
||||
* Mark an object that may be in a different compartment from the compartment
|
||||
* being GC'd. (Although it won't be marked if it's in the wrong compartment.)
|
||||
*/
|
||||
void
|
||||
MarkCrossCompartmentObject(JSTracer *trc, JSObject &obj, const char *name);
|
||||
|
||||
void
|
||||
MarkObjectWithPrinter(JSTracer *trc, JSObject &obj, JSTraceNamePrinter printer,
|
||||
const void *arg, size_t index);
|
||||
@ -102,6 +109,13 @@ MarkValueRaw(JSTracer *trc, const js::Value &v);
|
||||
void
|
||||
MarkValue(JSTracer *trc, const js::Value &v, const char *name);
|
||||
|
||||
/*
|
||||
* Mark a value that may be in a different compartment from the compartment
|
||||
* being GC'd. (Although it won't be marked if it's in the wrong compartment.)
|
||||
*/
|
||||
void
|
||||
MarkCrossCompartmentValue(JSTracer *trc, const js::Value &v, const char *name);
|
||||
|
||||
void
|
||||
MarkValueRange(JSTracer *trc, Value *beg, Value *end, const char *name);
|
||||
|
||||
|
@ -980,11 +980,11 @@ static void
|
||||
proxy_TraceObject(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
obj->getProxyHandler()->trace(trc, obj);
|
||||
MarkValue(trc, obj->getProxyPrivate(), "private");
|
||||
MarkValue(trc, obj->getProxyExtra(), "extra");
|
||||
MarkCrossCompartmentValue(trc, obj->getProxyPrivate(), "private");
|
||||
MarkCrossCompartmentValue(trc, obj->getProxyExtra(), "extra");
|
||||
if (obj->isFunctionProxy()) {
|
||||
MarkValue(trc, GetCall(obj), "call");
|
||||
MarkValue(trc, GetConstruct(obj), "construct");
|
||||
MarkCrossCompartmentValue(trc, GetCall(obj), "call");
|
||||
MarkCrossCompartmentValue(trc, GetConstruct(obj), "construct");
|
||||
}
|
||||
}
|
||||
|
||||
@ -992,8 +992,8 @@ static void
|
||||
proxy_TraceFunction(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
proxy_TraceObject(trc, obj);
|
||||
MarkValue(trc, GetCall(obj), "call");
|
||||
MarkValue(trc, GetConstruct(obj), "construct");
|
||||
MarkCrossCompartmentValue(trc, GetCall(obj), "call");
|
||||
MarkCrossCompartmentValue(trc, GetConstruct(obj), "construct");
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -45,6 +45,7 @@
|
||||
#define jsutil_h___
|
||||
|
||||
#include "jstypes.h"
|
||||
#include "jscrashreport.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -59,6 +60,8 @@ JS_BEGIN_EXTERN_C
|
||||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
#define JS_FREE_PATTERN 0xDA
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#define JS_ASSERT(expr) \
|
||||
@ -80,8 +83,6 @@ JS_BEGIN_EXTERN_C
|
||||
# define JS_THREADSAFE_ASSERT(expr) ((void) 0)
|
||||
# endif
|
||||
|
||||
#define JS_FREE_PATTERN 0xDA
|
||||
|
||||
#else
|
||||
|
||||
#define JS_ASSERT(expr) ((void) 0)
|
||||
@ -220,6 +221,12 @@ extern JS_PUBLIC_DATA(JSUint32) OOM_counter; /* data race, who cares. */
|
||||
#define JS_OOM_POSSIBLY_FAIL() do {} while(0)
|
||||
#endif
|
||||
|
||||
static JS_INLINE void *js_record_oom(void *p) {
|
||||
if (!p)
|
||||
js_SnapshotErrorStack();
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* SpiderMonkey code should not be calling these allocation functions directly.
|
||||
* Instead, all calls should go through JSRuntime, JSContext or OffTheBooks.
|
||||
@ -227,17 +234,17 @@ extern JS_PUBLIC_DATA(JSUint32) OOM_counter; /* data race, who cares. */
|
||||
*/
|
||||
static JS_INLINE void* js_malloc(size_t bytes) {
|
||||
JS_OOM_POSSIBLY_FAIL();
|
||||
return malloc(bytes);
|
||||
return js_record_oom(malloc(bytes));
|
||||
}
|
||||
|
||||
static JS_INLINE void* js_calloc(size_t bytes) {
|
||||
JS_OOM_POSSIBLY_FAIL();
|
||||
return calloc(bytes, 1);
|
||||
return js_record_oom(calloc(bytes, 1));
|
||||
}
|
||||
|
||||
static JS_INLINE void* js_realloc(void* p, size_t bytes) {
|
||||
JS_OOM_POSSIBLY_FAIL();
|
||||
return realloc(p, bytes);
|
||||
return js_record_oom(realloc(p, bytes));
|
||||
}
|
||||
|
||||
static JS_INLINE void js_free(void* p) {
|
||||
|
@ -768,4 +768,10 @@ JSCrossCompartmentWrapper::defaultValue(JSContext *cx, JSObject *wrapper, JSType
|
||||
return call.origin->wrap(cx, vp);
|
||||
}
|
||||
|
||||
void
|
||||
JSCrossCompartmentWrapper::trace(JSTracer *trc, JSObject *wrapper)
|
||||
{
|
||||
MarkCrossCompartmentObject(trc, *wrappedObject(wrapper), "wrappedObject");
|
||||
}
|
||||
|
||||
JSCrossCompartmentWrapper JSCrossCompartmentWrapper::singleton(0u);
|
||||
|
@ -153,6 +153,8 @@ class JS_FRIEND_API(JSCrossCompartmentWrapper) : public JSWrapper {
|
||||
virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, uintN indent);
|
||||
virtual bool defaultValue(JSContext *cx, JSObject *wrapper, JSType hint, js::Value *vp);
|
||||
|
||||
virtual void trace(JSTracer *trc, JSObject *wrapper);
|
||||
|
||||
static JSCrossCompartmentWrapper singleton;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user