js/src/gc/Verifier.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifdef MOZ_VALGRIND
michael@0 8 # include <valgrind/memcheck.h>
michael@0 9 #endif
michael@0 10
michael@0 11 #include "jscntxt.h"
michael@0 12 #include "jsgc.h"
michael@0 13 #include "jsprf.h"
michael@0 14
michael@0 15 #include "gc/GCInternals.h"
michael@0 16 #include "gc/Zone.h"
michael@0 17 #include "js/GCAPI.h"
michael@0 18 #include "js/HashTable.h"
michael@0 19
michael@0 20 #include "jscntxtinlines.h"
michael@0 21 #include "jsgcinlines.h"
michael@0 22
michael@0 23 using namespace js;
michael@0 24 using namespace js::gc;
michael@0 25 using namespace mozilla;
michael@0 26
michael@0 27 #ifdef JS_GC_ZEAL
michael@0 28
michael@0 29 /*
michael@0 30 * Write barrier verification
michael@0 31 *
michael@0 32 * The next few functions are for write barrier verification.
michael@0 33 *
michael@0 34 * The VerifyBarriers function is a shorthand. It checks if a verification phase
michael@0 35 * is currently running. If not, it starts one. Otherwise, it ends the current
michael@0 36 * phase and starts a new one.
michael@0 37 *
michael@0 38 * The user can adjust the frequency of verifications, which causes
michael@0 39 * VerifyBarriers to be a no-op all but one out of N calls. However, if the
michael@0 40 * |always| parameter is true, it starts a new phase no matter what.
michael@0 41 *
michael@0 42 * Pre-Barrier Verifier:
michael@0 43 * When StartVerifyBarriers is called, a snapshot is taken of all objects in
michael@0 44 * the GC heap and saved in an explicit graph data structure. Later,
michael@0 45 * EndVerifyBarriers traverses the heap again. Any pointer values that were in
michael@0 46 * the snapshot and are no longer found must be marked; otherwise an assertion
michael@0 47 * triggers. Note that we must not GC in between starting and finishing a
michael@0 48 * verification phase.
michael@0 49 *
michael@0 50 * Post-Barrier Verifier:
michael@0 51 * When StartVerifyBarriers is called, we create a virtual "Nursery Set" which
michael@0 52 * future allocations are recorded in and turn on the StoreBuffer. Later,
michael@0 53 * EndVerifyBarriers traverses the heap and ensures that the set of cross-
michael@0 54 * generational pointers we find is a subset of the pointers recorded in our
michael@0 55 * StoreBuffer.
michael@0 56 */
michael@0 57
michael@0 58 struct EdgeValue
michael@0 59 {
michael@0 60 void *thing;
michael@0 61 JSGCTraceKind kind;
michael@0 62 const char *label;
michael@0 63 };
michael@0 64
michael@0 65 struct VerifyNode
michael@0 66 {
michael@0 67 void *thing;
michael@0 68 JSGCTraceKind kind;
michael@0 69 uint32_t count;
michael@0 70 EdgeValue edges[1];
michael@0 71 };
michael@0 72
michael@0 73 typedef HashMap<void *, VerifyNode *, DefaultHasher<void *>, SystemAllocPolicy> NodeMap;
michael@0 74
michael@0 75 /*
michael@0 76 * The verifier data structures are simple. The entire graph is stored in a
michael@0 77 * single block of memory. At the beginning is a VerifyNode for the root
michael@0 78 * node. It is followed by a sequence of EdgeValues--the exact number is given
michael@0 79 * in the node. After the edges come more nodes and their edges.
michael@0 80 *
michael@0 81 * The edgeptr and term fields are used to allocate out of the block of memory
michael@0 82 * for the graph. If we run out of memory (i.e., if edgeptr goes beyond term),
michael@0 83 * we just abandon the verification.
michael@0 84 *
michael@0 85 * The nodemap field is a hashtable that maps from the address of the GC thing
michael@0 86 * to the VerifyNode that represents it.
michael@0 87 */
michael@0 88 struct VerifyPreTracer : JSTracer
michael@0 89 {
michael@0 90 JS::AutoDisableGenerationalGC noggc;
michael@0 91
michael@0 92 /* The gcNumber when the verification began. */
michael@0 93 uint64_t number;
michael@0 94
michael@0 95 /* This counts up to gcZealFrequency to decide whether to verify. */
michael@0 96 int count;
michael@0 97
michael@0 98 /* This graph represents the initial GC "snapshot". */
michael@0 99 VerifyNode *curnode;
michael@0 100 VerifyNode *root;
michael@0 101 char *edgeptr;
michael@0 102 char *term;
michael@0 103 NodeMap nodemap;
michael@0 104
michael@0 105 VerifyPreTracer(JSRuntime *rt, JSTraceCallback callback)
michael@0 106 : JSTracer(rt, callback), noggc(rt), number(rt->gcNumber), count(0), root(nullptr)
michael@0 107 {}
michael@0 108
michael@0 109 ~VerifyPreTracer() {
michael@0 110 js_free(root);
michael@0 111 }
michael@0 112 };
michael@0 113
michael@0 114 /*
michael@0 115 * This function builds up the heap snapshot by adding edges to the current
michael@0 116 * node.
michael@0 117 */
michael@0 118 static void
michael@0 119 AccumulateEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind)
michael@0 120 {
michael@0 121 VerifyPreTracer *trc = (VerifyPreTracer *)jstrc;
michael@0 122
michael@0 123 JS_ASSERT(!IsInsideNursery(trc->runtime(), *(uintptr_t **)thingp));
michael@0 124
michael@0 125 trc->edgeptr += sizeof(EdgeValue);
michael@0 126 if (trc->edgeptr >= trc->term) {
michael@0 127 trc->edgeptr = trc->term;
michael@0 128 return;
michael@0 129 }
michael@0 130
michael@0 131 VerifyNode *node = trc->curnode;
michael@0 132 uint32_t i = node->count;
michael@0 133
michael@0 134 node->edges[i].thing = *thingp;
michael@0 135 node->edges[i].kind = kind;
michael@0 136 node->edges[i].label = trc->tracingName("<unknown>");
michael@0 137 node->count++;
michael@0 138 }
michael@0 139
michael@0 140 static VerifyNode *
michael@0 141 MakeNode(VerifyPreTracer *trc, void *thing, JSGCTraceKind kind)
michael@0 142 {
michael@0 143 NodeMap::AddPtr p = trc->nodemap.lookupForAdd(thing);
michael@0 144 if (!p) {
michael@0 145 VerifyNode *node = (VerifyNode *)trc->edgeptr;
michael@0 146 trc->edgeptr += sizeof(VerifyNode) - sizeof(EdgeValue);
michael@0 147 if (trc->edgeptr >= trc->term) {
michael@0 148 trc->edgeptr = trc->term;
michael@0 149 return nullptr;
michael@0 150 }
michael@0 151
michael@0 152 node->thing = thing;
michael@0 153 node->count = 0;
michael@0 154 node->kind = kind;
michael@0 155 trc->nodemap.add(p, thing, node);
michael@0 156 return node;
michael@0 157 }
michael@0 158 return nullptr;
michael@0 159 }
michael@0 160
michael@0 161 static VerifyNode *
michael@0 162 NextNode(VerifyNode *node)
michael@0 163 {
michael@0 164 if (node->count == 0)
michael@0 165 return (VerifyNode *)((char *)node + sizeof(VerifyNode) - sizeof(EdgeValue));
michael@0 166 else
michael@0 167 return (VerifyNode *)((char *)node + sizeof(VerifyNode) +
michael@0 168 sizeof(EdgeValue)*(node->count - 1));
michael@0 169 }
michael@0 170
michael@0 171 void
michael@0 172 gc::StartVerifyPreBarriers(JSRuntime *rt)
michael@0 173 {
michael@0 174 if (rt->gcVerifyPreData || rt->gcIncrementalState != NO_INCREMENTAL)
michael@0 175 return;
michael@0 176
michael@0 177 /*
michael@0 178 * The post barrier verifier requires the storebuffer to be enabled, but the
michael@0 179 * pre barrier verifier disables it as part of disabling GGC. Don't allow
michael@0 180 * starting the pre barrier verifier if the post barrier verifier is already
michael@0 181 * running.
michael@0 182 */
michael@0 183 if (rt->gcVerifyPostData)
michael@0 184 return;
michael@0 185
michael@0 186 MinorGC(rt, JS::gcreason::EVICT_NURSERY);
michael@0 187
michael@0 188 AutoPrepareForTracing prep(rt, WithAtoms);
michael@0 189
michael@0 190 if (!IsIncrementalGCSafe(rt))
michael@0 191 return;
michael@0 192
michael@0 193 for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
michael@0 194 r.front()->bitmap.clear();
michael@0 195
michael@0 196 rt->gcNumber++;
michael@0 197
michael@0 198 VerifyPreTracer *trc = js_new<VerifyPreTracer>(rt, JSTraceCallback(nullptr));
michael@0 199 if (!trc)
michael@0 200 return;
michael@0 201
michael@0 202 /*
michael@0 203 * Passing a function pointer directly to js_new trips a compiler bug in
michael@0 204 * MSVC. Work around by filling the pointer after allocating with nullptr.
michael@0 205 */
michael@0 206 trc->setTraceCallback(AccumulateEdge);
michael@0 207
michael@0 208 const size_t size = 64 * 1024 * 1024;
michael@0 209 trc->root = (VerifyNode *)js_malloc(size);
michael@0 210 if (!trc->root)
michael@0 211 goto oom;
michael@0 212 trc->edgeptr = (char *)trc->root;
michael@0 213 trc->term = trc->edgeptr + size;
michael@0 214
michael@0 215 if (!trc->nodemap.init())
michael@0 216 goto oom;
michael@0 217
michael@0 218 /* Create the root node. */
michael@0 219 trc->curnode = MakeNode(trc, nullptr, JSGCTraceKind(0));
michael@0 220
michael@0 221 /* We want MarkRuntime to save the roots to gcSavedRoots. */
michael@0 222 rt->gcIncrementalState = MARK_ROOTS;
michael@0 223
michael@0 224 /* Make all the roots be edges emanating from the root node. */
michael@0 225 MarkRuntime(trc);
michael@0 226
michael@0 227 VerifyNode *node;
michael@0 228 node = trc->curnode;
michael@0 229 if (trc->edgeptr == trc->term)
michael@0 230 goto oom;
michael@0 231
michael@0 232 /* For each edge, make a node for it if one doesn't already exist. */
michael@0 233 while ((char *)node < trc->edgeptr) {
michael@0 234 for (uint32_t i = 0; i < node->count; i++) {
michael@0 235 EdgeValue &e = node->edges[i];
michael@0 236 VerifyNode *child = MakeNode(trc, e.thing, e.kind);
michael@0 237 if (child) {
michael@0 238 trc->curnode = child;
michael@0 239 JS_TraceChildren(trc, e.thing, e.kind);
michael@0 240 }
michael@0 241 if (trc->edgeptr == trc->term)
michael@0 242 goto oom;
michael@0 243 }
michael@0 244
michael@0 245 node = NextNode(node);
michael@0 246 }
michael@0 247
michael@0 248 rt->gcVerifyPreData = trc;
michael@0 249 rt->gcIncrementalState = MARK;
michael@0 250 rt->gcMarker.start();
michael@0 251
michael@0 252 rt->setNeedsBarrier(true);
michael@0 253 for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
michael@0 254 PurgeJITCaches(zone);
michael@0 255 zone->setNeedsBarrier(true, Zone::UpdateIon);
michael@0 256 zone->allocator.arenas.purge();
michael@0 257 }
michael@0 258
michael@0 259 return;
michael@0 260
michael@0 261 oom:
michael@0 262 rt->gcIncrementalState = NO_INCREMENTAL;
michael@0 263 js_delete(trc);
michael@0 264 rt->gcVerifyPreData = nullptr;
michael@0 265 }
michael@0 266
michael@0 267 static bool
michael@0 268 IsMarkedOrAllocated(Cell *cell)
michael@0 269 {
michael@0 270 return cell->isMarked() || cell->arenaHeader()->allocatedDuringIncremental;
michael@0 271 }
michael@0 272
michael@0 273 static const uint32_t MAX_VERIFIER_EDGES = 1000;
michael@0 274
michael@0 275 /*
michael@0 276 * This function is called by EndVerifyBarriers for every heap edge. If the edge
michael@0 277 * already existed in the original snapshot, we "cancel it out" by overwriting
michael@0 278 * it with nullptr. EndVerifyBarriers later asserts that the remaining
michael@0 279 * non-nullptr edges (i.e., the ones from the original snapshot that must have
michael@0 280 * been modified) must point to marked objects.
michael@0 281 */
michael@0 282 static void
michael@0 283 CheckEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind)
michael@0 284 {
michael@0 285 VerifyPreTracer *trc = (VerifyPreTracer *)jstrc;
michael@0 286 VerifyNode *node = trc->curnode;
michael@0 287
michael@0 288 /* Avoid n^2 behavior. */
michael@0 289 if (node->count > MAX_VERIFIER_EDGES)
michael@0 290 return;
michael@0 291
michael@0 292 for (uint32_t i = 0; i < node->count; i++) {
michael@0 293 if (node->edges[i].thing == *thingp) {
michael@0 294 JS_ASSERT(node->edges[i].kind == kind);
michael@0 295 node->edges[i].thing = nullptr;
michael@0 296 return;
michael@0 297 }
michael@0 298 }
michael@0 299 }
michael@0 300
michael@0 301 static void
michael@0 302 AssertMarkedOrAllocated(const EdgeValue &edge)
michael@0 303 {
michael@0 304 if (!edge.thing || IsMarkedOrAllocated(static_cast<Cell *>(edge.thing)))
michael@0 305 return;
michael@0 306
michael@0 307 // Permanent atoms aren't marked during graph traversal.
michael@0 308 if (edge.kind == JSTRACE_STRING && static_cast<JSString *>(edge.thing)->isPermanentAtom())
michael@0 309 return;
michael@0 310
michael@0 311 char msgbuf[1024];
michael@0 312 const char *label = edge.label;
michael@0 313
michael@0 314 JS_snprintf(msgbuf, sizeof(msgbuf), "[barrier verifier] Unmarked edge: %s", label);
michael@0 315 MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
michael@0 316 MOZ_CRASH();
michael@0 317 }
michael@0 318
michael@0 319 void
michael@0 320 gc::EndVerifyPreBarriers(JSRuntime *rt)
michael@0 321 {
michael@0 322 JS_ASSERT(!JS::IsGenerationalGCEnabled(rt));
michael@0 323
michael@0 324 AutoPrepareForTracing prep(rt, SkipAtoms);
michael@0 325
michael@0 326 VerifyPreTracer *trc = (VerifyPreTracer *)rt->gcVerifyPreData;
michael@0 327
michael@0 328 if (!trc)
michael@0 329 return;
michael@0 330
michael@0 331 bool compartmentCreated = false;
michael@0 332
michael@0 333 /* We need to disable barriers before tracing, which may invoke barriers. */
michael@0 334 for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
michael@0 335 if (!zone->needsBarrier())
michael@0 336 compartmentCreated = true;
michael@0 337
michael@0 338 zone->setNeedsBarrier(false, Zone::UpdateIon);
michael@0 339 PurgeJITCaches(zone);
michael@0 340 }
michael@0 341 rt->setNeedsBarrier(false);
michael@0 342
michael@0 343 /*
michael@0 344 * We need to bump gcNumber so that the methodjit knows that jitcode has
michael@0 345 * been discarded.
michael@0 346 */
michael@0 347 JS_ASSERT(trc->number == rt->gcNumber);
michael@0 348 rt->gcNumber++;
michael@0 349
michael@0 350 rt->gcVerifyPreData = nullptr;
michael@0 351 rt->gcIncrementalState = NO_INCREMENTAL;
michael@0 352
michael@0 353 if (!compartmentCreated && IsIncrementalGCSafe(rt)) {
michael@0 354 trc->setTraceCallback(CheckEdge);
michael@0 355
michael@0 356 /* Start after the roots. */
michael@0 357 VerifyNode *node = NextNode(trc->root);
michael@0 358 while ((char *)node < trc->edgeptr) {
michael@0 359 trc->curnode = node;
michael@0 360 JS_TraceChildren(trc, node->thing, node->kind);
michael@0 361
michael@0 362 if (node->count <= MAX_VERIFIER_EDGES) {
michael@0 363 for (uint32_t i = 0; i < node->count; i++)
michael@0 364 AssertMarkedOrAllocated(node->edges[i]);
michael@0 365 }
michael@0 366
michael@0 367 node = NextNode(node);
michael@0 368 }
michael@0 369 }
michael@0 370
michael@0 371 rt->gcMarker.reset();
michael@0 372 rt->gcMarker.stop();
michael@0 373
michael@0 374 js_delete(trc);
michael@0 375 }
michael@0 376
michael@0 377 /*** Post-Barrier Verifyier ***/
michael@0 378
michael@0 379 struct VerifyPostTracer : JSTracer
michael@0 380 {
michael@0 381 /* The gcNumber when the verification began. */
michael@0 382 uint64_t number;
michael@0 383
michael@0 384 /* This counts up to gcZealFrequency to decide whether to verify. */
michael@0 385 int count;
michael@0 386
michael@0 387 /* The set of edges in the StoreBuffer at the end of verification. */
michael@0 388 typedef HashSet<void **, PointerHasher<void **, 3>, SystemAllocPolicy> EdgeSet;
michael@0 389 EdgeSet *edges;
michael@0 390
michael@0 391 VerifyPostTracer(JSRuntime *rt, JSTraceCallback callback)
michael@0 392 : JSTracer(rt, callback), number(rt->gcNumber), count(0)
michael@0 393 {}
michael@0 394 };
michael@0 395
michael@0 396 /*
michael@0 397 * The post-barrier verifier runs the full store buffer and a fake nursery when
michael@0 398 * running and when it stops, walks the full heap to ensure that all the
michael@0 399 * important edges were inserted into the storebuffer.
michael@0 400 */
michael@0 401 void
michael@0 402 gc::StartVerifyPostBarriers(JSRuntime *rt)
michael@0 403 {
michael@0 404 #ifdef JSGC_GENERATIONAL
michael@0 405 if (rt->gcVerifyPostData ||
michael@0 406 rt->gcIncrementalState != NO_INCREMENTAL)
michael@0 407 {
michael@0 408 return;
michael@0 409 }
michael@0 410
michael@0 411 MinorGC(rt, JS::gcreason::EVICT_NURSERY);
michael@0 412
michael@0 413 rt->gcNumber++;
michael@0 414
michael@0 415 VerifyPostTracer *trc = js_new<VerifyPostTracer>(rt, JSTraceCallback(nullptr));
michael@0 416 if (!trc)
michael@0 417 return;
michael@0 418
michael@0 419 rt->gcVerifyPostData = trc;
michael@0 420 #endif
michael@0 421 }
michael@0 422
michael@0 423 #ifdef JSGC_GENERATIONAL
michael@0 424 void
michael@0 425 PostVerifierCollectStoreBufferEdges(JSTracer *jstrc, void **thingp, JSGCTraceKind kind)
michael@0 426 {
michael@0 427 VerifyPostTracer *trc = (VerifyPostTracer *)jstrc;
michael@0 428
michael@0 429 /* The nursery only stores objects. */
michael@0 430 if (kind != JSTRACE_OBJECT)
michael@0 431 return;
michael@0 432
michael@0 433 /* The store buffer may store extra, non-cross-generational edges. */
michael@0 434 JSObject *dst = *reinterpret_cast<JSObject **>(thingp);
michael@0 435 if (trc->runtime()->gcNursery.isInside(thingp) || !trc->runtime()->gcNursery.isInside(dst))
michael@0 436 return;
michael@0 437
michael@0 438 /*
michael@0 439 * Values will be unpacked to the stack before getting here. However, the
michael@0 440 * only things that enter this callback are marked by the store buffer. The
michael@0 441 * store buffer ensures that the real tracing location is set correctly.
michael@0 442 */
michael@0 443 void **loc = trc->tracingLocation(thingp);
michael@0 444
michael@0 445 trc->edges->put(loc);
michael@0 446 }
michael@0 447
michael@0 448 static void
michael@0 449 AssertStoreBufferContainsEdge(VerifyPostTracer::EdgeSet *edges, void **loc, JSObject *dst)
michael@0 450 {
michael@0 451 if (edges->has(loc))
michael@0 452 return;
michael@0 453
michael@0 454 char msgbuf[1024];
michael@0 455 JS_snprintf(msgbuf, sizeof(msgbuf), "[post-barrier verifier] Missing edge @ %p to %p",
michael@0 456 (void *)loc, (void *)dst);
michael@0 457 MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
michael@0 458 MOZ_CRASH();
michael@0 459 }
michael@0 460
michael@0 461 void
michael@0 462 PostVerifierVisitEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind)
michael@0 463 {
michael@0 464 VerifyPostTracer *trc = (VerifyPostTracer *)jstrc;
michael@0 465
michael@0 466 /* The nursery only stores objects. */
michael@0 467 if (kind != JSTRACE_OBJECT)
michael@0 468 return;
michael@0 469
michael@0 470 /* Filter out non cross-generational edges. */
michael@0 471 JS_ASSERT(!trc->runtime()->gcNursery.isInside(thingp));
michael@0 472 JSObject *dst = *reinterpret_cast<JSObject **>(thingp);
michael@0 473 if (!trc->runtime()->gcNursery.isInside(dst))
michael@0 474 return;
michael@0 475
michael@0 476 /*
michael@0 477 * Values will be unpacked to the stack before getting here. However, the
michael@0 478 * only things that enter this callback are marked by the JS_TraceChildren
michael@0 479 * below. Since ObjectImpl::markChildren handles this, the real trace
michael@0 480 * location will be set correctly in these cases.
michael@0 481 */
michael@0 482 void **loc = trc->tracingLocation(thingp);
michael@0 483
michael@0 484 AssertStoreBufferContainsEdge(trc->edges, loc, dst);
michael@0 485 }
michael@0 486 #endif
michael@0 487
michael@0 488 void
michael@0 489 js::gc::EndVerifyPostBarriers(JSRuntime *rt)
michael@0 490 {
michael@0 491 #ifdef JSGC_GENERATIONAL
michael@0 492 VerifyPostTracer::EdgeSet edges;
michael@0 493 AutoPrepareForTracing prep(rt, SkipAtoms);
michael@0 494
michael@0 495 VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData;
michael@0 496
michael@0 497 /* Visit every entry in the store buffer and put the edges in a hash set. */
michael@0 498 trc->setTraceCallback(PostVerifierCollectStoreBufferEdges);
michael@0 499 if (!edges.init())
michael@0 500 goto oom;
michael@0 501 trc->edges = &edges;
michael@0 502 rt->gcStoreBuffer.markAll(trc);
michael@0 503
michael@0 504 /* Walk the heap to find any edges not the the |edges| set. */
michael@0 505 trc->setTraceCallback(PostVerifierVisitEdge);
michael@0 506 for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) {
michael@0 507 for (size_t kind = 0; kind < FINALIZE_LIMIT; ++kind) {
michael@0 508 for (CellIterUnderGC cells(zone, AllocKind(kind)); !cells.done(); cells.next()) {
michael@0 509 Cell *src = cells.getCell();
michael@0 510 JS_TraceChildren(trc, src, MapAllocToTraceKind(AllocKind(kind)));
michael@0 511 }
michael@0 512 }
michael@0 513 }
michael@0 514
michael@0 515 oom:
michael@0 516 js_delete(trc);
michael@0 517 rt->gcVerifyPostData = nullptr;
michael@0 518 #endif
michael@0 519 }
michael@0 520
michael@0 521 /*** Barrier Verifier Scheduling ***/
michael@0 522
michael@0 523 static void
michael@0 524 VerifyPreBarriers(JSRuntime *rt)
michael@0 525 {
michael@0 526 if (rt->gcVerifyPreData)
michael@0 527 EndVerifyPreBarriers(rt);
michael@0 528 else
michael@0 529 StartVerifyPreBarriers(rt);
michael@0 530 }
michael@0 531
michael@0 532 static void
michael@0 533 VerifyPostBarriers(JSRuntime *rt)
michael@0 534 {
michael@0 535 if (rt->gcVerifyPostData)
michael@0 536 EndVerifyPostBarriers(rt);
michael@0 537 else
michael@0 538 StartVerifyPostBarriers(rt);
michael@0 539 }
michael@0 540
michael@0 541 void
michael@0 542 gc::VerifyBarriers(JSRuntime *rt, VerifierType type)
michael@0 543 {
michael@0 544 if (type == PreBarrierVerifier)
michael@0 545 VerifyPreBarriers(rt);
michael@0 546 else
michael@0 547 VerifyPostBarriers(rt);
michael@0 548 }
michael@0 549
michael@0 550 static void
michael@0 551 MaybeVerifyPreBarriers(JSRuntime *rt, bool always)
michael@0 552 {
michael@0 553 if (rt->gcZeal() != ZealVerifierPreValue)
michael@0 554 return;
michael@0 555
michael@0 556 if (rt->mainThread.suppressGC)
michael@0 557 return;
michael@0 558
michael@0 559 if (VerifyPreTracer *trc = (VerifyPreTracer *)rt->gcVerifyPreData) {
michael@0 560 if (++trc->count < rt->gcZealFrequency && !always)
michael@0 561 return;
michael@0 562
michael@0 563 EndVerifyPreBarriers(rt);
michael@0 564 }
michael@0 565
michael@0 566 StartVerifyPreBarriers(rt);
michael@0 567 }
michael@0 568
michael@0 569 static void
michael@0 570 MaybeVerifyPostBarriers(JSRuntime *rt, bool always)
michael@0 571 {
michael@0 572 #ifdef JSGC_GENERATIONAL
michael@0 573 if (rt->gcZeal() != ZealVerifierPostValue)
michael@0 574 return;
michael@0 575
michael@0 576 if (rt->mainThread.suppressGC || !rt->gcStoreBuffer.isEnabled())
michael@0 577 return;
michael@0 578
michael@0 579 if (VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData) {
michael@0 580 if (++trc->count < rt->gcZealFrequency && !always)
michael@0 581 return;
michael@0 582
michael@0 583 EndVerifyPostBarriers(rt);
michael@0 584 }
michael@0 585 StartVerifyPostBarriers(rt);
michael@0 586 #endif
michael@0 587 }
michael@0 588
michael@0 589 void
michael@0 590 js::gc::MaybeVerifyBarriers(JSContext *cx, bool always)
michael@0 591 {
michael@0 592 MaybeVerifyPreBarriers(cx->runtime(), always);
michael@0 593 MaybeVerifyPostBarriers(cx->runtime(), always);
michael@0 594 }
michael@0 595
michael@0 596 void
michael@0 597 js::gc::FinishVerifier(JSRuntime *rt)
michael@0 598 {
michael@0 599 if (VerifyPreTracer *trc = (VerifyPreTracer *)rt->gcVerifyPreData) {
michael@0 600 js_delete(trc);
michael@0 601 rt->gcVerifyPreData = nullptr;
michael@0 602 }
michael@0 603 #ifdef JSGC_GENERATIONAL
michael@0 604 if (VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData) {
michael@0 605 js_delete(trc);
michael@0 606 rt->gcVerifyPostData = nullptr;
michael@0 607 }
michael@0 608 #endif
michael@0 609 }
michael@0 610
michael@0 611 #endif /* JS_GC_ZEAL */

mercurial