Bug 1083456 - Part 1: Add JS_TraceIncomingCCWs. r=terrence

This commit is contained in:
Nick Fitzgerald 2014-11-07 11:56:00 +01:00
parent f92fbf9f5d
commit d44fae4043
7 changed files with 128 additions and 3 deletions

View File

@ -9,8 +9,11 @@
#include "mozilla/NullPtr.h"
#include "jsalloc.h"
#include "jspubtd.h"
#include "js/HashTable.h"
class JS_PUBLIC_API(JSTracer);
namespace JS {
@ -212,6 +215,15 @@ JS_TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind);
extern JS_PUBLIC_API(void)
JS_TraceRuntime(JSTracer *trc);
namespace JS {
typedef js::HashSet<Zone *, js::DefaultHasher<Zone *>, js::SystemAllocPolicy> ZoneSet;
}
// Trace every value within |zones| that is wrapped by a cross-compartment
// wrapper from a zone that is not an element of |zones|.
extern JS_PUBLIC_API(void)
JS_TraceIncomingCCWs(JSTracer *trc, const JS::ZoneSet &zones);
extern JS_PUBLIC_API(void)
JS_GetTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc,
void *thing, JSGCTraceKind kind, bool includeDetails);

View File

@ -17,6 +17,7 @@
#include "js/GCAPI.h"
#include "js/HashTable.h"
#include "js/TracingAPI.h"
#include "js/TypeDecls.h"
// JS::ubi::Node
@ -135,7 +136,6 @@
// teach the GC how to root ubi::Nodes, fix up hash tables that use them as
// keys, etc.
namespace JS {
namespace ubi {

View File

@ -18,6 +18,7 @@
#include "gc/GCInternals.h"
#include "gc/Marking.h"
#include "gc/Zone.h"
#include "vm/Symbol.h"
@ -119,6 +120,37 @@ JS_TraceRuntime(JSTracer *trc)
TraceRuntime(trc);
}
JS_PUBLIC_API(void)
JS_TraceIncomingCCWs(JSTracer *trc, const JS::ZoneSet &zones)
{
for (js::ZonesIter z(trc->runtime(), SkipAtoms); !z.done(); z.next()) {
Zone *zone = z.get();
if (!zone || zones.has(zone))
continue;
for (js::CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
JSCompartment *comp = c.get();
if (!comp)
continue;
for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) {
const CrossCompartmentKey &key = e.front().key();
// StringWrappers are just used to avoid copying strings across
// zones multiple times, and don't hold a strong reference.
if (key.kind == CrossCompartmentKey::StringWrapper)
continue;
// Ignore CCWs whose wrapped value doesn't live in our given set
// of zones.
if (!zones.has(static_cast<JSObject *>(key.wrapped)->zone()))
continue;
void *thing = key.wrapped;
trc->callback(trc, &thing, GetGCThingTraceKind(key.wrapped));
}
}
}
}
static size_t
CountDecimalDigits(size_t num)
{

View File

@ -16,6 +16,7 @@
#include "gc/FindSCCs.h"
#include "gc/GCRuntime.h"
#include "js/TracingAPI.h"
namespace js {
@ -259,7 +260,6 @@ struct Zone : public JS::shadow::Zone,
//
// This is used during GC while calculating zone groups to record edges that
// can't be determined by examining this zone by itself.
typedef js::HashSet<Zone *, js::DefaultHasher<Zone *>, js::SystemAllocPolicy> ZoneSet;
ZoneSet gcZoneGroupEdges;
// Malloc counter to measure memory pressure for GC scheduling. It runs from

View File

@ -37,6 +37,7 @@ UNIFIED_SOURCES += [
'testGCExactRooting.cpp',
'testGCFinalizeCallback.cpp',
'testGCHeapPostBarriers.cpp',
'testGCMarking.cpp',
'testGCOutOfMemory.cpp',
'testGCStoreBufferRemoval.cpp',
'testHashTable.cpp',

View File

@ -0,0 +1,79 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jsapi-tests/tests.h"
class CCWTestTracer : public JSTracer {
static void staticCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind) {
static_cast<CCWTestTracer *>(trc)->callback(thingp, kind);
}
void callback(void **thingp, JSGCTraceKind kind) {
numberOfThingsTraced++;
printf("*thingp = %p\n", *thingp);
printf("*expectedThingp = %p\n", *expectedThingp);
printf("kind = %d\n", kind);
printf("expectedKind = %d\n", expectedKind);
if (*thingp != *expectedThingp || kind != expectedKind)
okay = false;
}
public:
bool okay;
size_t numberOfThingsTraced;
void **expectedThingp;
JSGCTraceKind expectedKind;
CCWTestTracer(JSContext *cx, void **expectedThingp, JSGCTraceKind expectedKind)
: JSTracer(JS_GetRuntime(cx), staticCallback),
okay(true),
numberOfThingsTraced(0),
expectedThingp(expectedThingp),
expectedKind(expectedKind)
{ }
};
BEGIN_TEST(testTracingIncomingCCWs)
{
// Get two globals, in two different zones.
JS::RootedObject global1(cx, JS::CurrentGlobalOrNull(cx));
CHECK(global1);
JS::RootedObject global2(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
JS::FireOnNewGlobalHook));
CHECK(global2);
CHECK(global1->zone() != global2->zone());
// Define an object in one zone, that is wrapped by a CCW in another zone.
JS::RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
CHECK(obj->zone() == global1->zone());
JSAutoCompartment ac(cx, global2);
JS::RootedObject wrapper(cx, obj);
CHECK(JS_WrapObject(cx, &wrapper));
JS::RootedValue v(cx, JS::ObjectValue(*wrapper));
CHECK(JS_SetProperty(cx, global2, "ccw", v));
// Ensure that |JS_TraceIncomingCCWs| finds the object wrapped by the CCW.
JS::ZoneSet zones;
CHECK(zones.init());
CHECK(zones.put(global1->zone()));
void *thing = obj.get();
CCWTestTracer trc(cx, &thing, JSTRACE_OBJECT);
JS_TraceIncomingCCWs(&trc, zones);
CHECK(trc.numberOfThingsTraced == 1);
CHECK(trc.okay);
return true;
}
END_TEST(testTracingIncomingCCWs)

View File

@ -16,6 +16,7 @@
#include "gc/Marking.h"
#include "js/Debug.h"
#include "js/TracingAPI.h"
#include "js/UbiNode.h"
#include "js/UbiNodeTraverse.h"
#include "vm/Debugger.h"
@ -304,7 +305,7 @@ namespace dbg {
// Common data for census traversals.
struct Census {
JSContext * const cx;
Zone::ZoneSet debuggeeZones;
JS::ZoneSet debuggeeZones;
Zone *atomsZone;
explicit Census(JSContext *cx) : cx(cx), atomsZone(nullptr) { }