1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/gc/Verifier.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,611 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifdef MOZ_VALGRIND 1.11 +# include <valgrind/memcheck.h> 1.12 +#endif 1.13 + 1.14 +#include "jscntxt.h" 1.15 +#include "jsgc.h" 1.16 +#include "jsprf.h" 1.17 + 1.18 +#include "gc/GCInternals.h" 1.19 +#include "gc/Zone.h" 1.20 +#include "js/GCAPI.h" 1.21 +#include "js/HashTable.h" 1.22 + 1.23 +#include "jscntxtinlines.h" 1.24 +#include "jsgcinlines.h" 1.25 + 1.26 +using namespace js; 1.27 +using namespace js::gc; 1.28 +using namespace mozilla; 1.29 + 1.30 +#ifdef JS_GC_ZEAL 1.31 + 1.32 +/* 1.33 + * Write barrier verification 1.34 + * 1.35 + * The next few functions are for write barrier verification. 1.36 + * 1.37 + * The VerifyBarriers function is a shorthand. It checks if a verification phase 1.38 + * is currently running. If not, it starts one. Otherwise, it ends the current 1.39 + * phase and starts a new one. 1.40 + * 1.41 + * The user can adjust the frequency of verifications, which causes 1.42 + * VerifyBarriers to be a no-op all but one out of N calls. However, if the 1.43 + * |always| parameter is true, it starts a new phase no matter what. 1.44 + * 1.45 + * Pre-Barrier Verifier: 1.46 + * When StartVerifyBarriers is called, a snapshot is taken of all objects in 1.47 + * the GC heap and saved in an explicit graph data structure. Later, 1.48 + * EndVerifyBarriers traverses the heap again. Any pointer values that were in 1.49 + * the snapshot and are no longer found must be marked; otherwise an assertion 1.50 + * triggers. Note that we must not GC in between starting and finishing a 1.51 + * verification phase. 1.52 + * 1.53 + * Post-Barrier Verifier: 1.54 + * When StartVerifyBarriers is called, we create a virtual "Nursery Set" which 1.55 + * future allocations are recorded in and turn on the StoreBuffer. Later, 1.56 + * EndVerifyBarriers traverses the heap and ensures that the set of cross- 1.57 + * generational pointers we find is a subset of the pointers recorded in our 1.58 + * StoreBuffer. 1.59 + */ 1.60 + 1.61 +struct EdgeValue 1.62 +{ 1.63 + void *thing; 1.64 + JSGCTraceKind kind; 1.65 + const char *label; 1.66 +}; 1.67 + 1.68 +struct VerifyNode 1.69 +{ 1.70 + void *thing; 1.71 + JSGCTraceKind kind; 1.72 + uint32_t count; 1.73 + EdgeValue edges[1]; 1.74 +}; 1.75 + 1.76 +typedef HashMap<void *, VerifyNode *, DefaultHasher<void *>, SystemAllocPolicy> NodeMap; 1.77 + 1.78 +/* 1.79 + * The verifier data structures are simple. The entire graph is stored in a 1.80 + * single block of memory. At the beginning is a VerifyNode for the root 1.81 + * node. It is followed by a sequence of EdgeValues--the exact number is given 1.82 + * in the node. After the edges come more nodes and their edges. 1.83 + * 1.84 + * The edgeptr and term fields are used to allocate out of the block of memory 1.85 + * for the graph. If we run out of memory (i.e., if edgeptr goes beyond term), 1.86 + * we just abandon the verification. 1.87 + * 1.88 + * The nodemap field is a hashtable that maps from the address of the GC thing 1.89 + * to the VerifyNode that represents it. 1.90 + */ 1.91 +struct VerifyPreTracer : JSTracer 1.92 +{ 1.93 + JS::AutoDisableGenerationalGC noggc; 1.94 + 1.95 + /* The gcNumber when the verification began. */ 1.96 + uint64_t number; 1.97 + 1.98 + /* This counts up to gcZealFrequency to decide whether to verify. */ 1.99 + int count; 1.100 + 1.101 + /* This graph represents the initial GC "snapshot". */ 1.102 + VerifyNode *curnode; 1.103 + VerifyNode *root; 1.104 + char *edgeptr; 1.105 + char *term; 1.106 + NodeMap nodemap; 1.107 + 1.108 + VerifyPreTracer(JSRuntime *rt, JSTraceCallback callback) 1.109 + : JSTracer(rt, callback), noggc(rt), number(rt->gcNumber), count(0), root(nullptr) 1.110 + {} 1.111 + 1.112 + ~VerifyPreTracer() { 1.113 + js_free(root); 1.114 + } 1.115 +}; 1.116 + 1.117 +/* 1.118 + * This function builds up the heap snapshot by adding edges to the current 1.119 + * node. 1.120 + */ 1.121 +static void 1.122 +AccumulateEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) 1.123 +{ 1.124 + VerifyPreTracer *trc = (VerifyPreTracer *)jstrc; 1.125 + 1.126 + JS_ASSERT(!IsInsideNursery(trc->runtime(), *(uintptr_t **)thingp)); 1.127 + 1.128 + trc->edgeptr += sizeof(EdgeValue); 1.129 + if (trc->edgeptr >= trc->term) { 1.130 + trc->edgeptr = trc->term; 1.131 + return; 1.132 + } 1.133 + 1.134 + VerifyNode *node = trc->curnode; 1.135 + uint32_t i = node->count; 1.136 + 1.137 + node->edges[i].thing = *thingp; 1.138 + node->edges[i].kind = kind; 1.139 + node->edges[i].label = trc->tracingName("<unknown>"); 1.140 + node->count++; 1.141 +} 1.142 + 1.143 +static VerifyNode * 1.144 +MakeNode(VerifyPreTracer *trc, void *thing, JSGCTraceKind kind) 1.145 +{ 1.146 + NodeMap::AddPtr p = trc->nodemap.lookupForAdd(thing); 1.147 + if (!p) { 1.148 + VerifyNode *node = (VerifyNode *)trc->edgeptr; 1.149 + trc->edgeptr += sizeof(VerifyNode) - sizeof(EdgeValue); 1.150 + if (trc->edgeptr >= trc->term) { 1.151 + trc->edgeptr = trc->term; 1.152 + return nullptr; 1.153 + } 1.154 + 1.155 + node->thing = thing; 1.156 + node->count = 0; 1.157 + node->kind = kind; 1.158 + trc->nodemap.add(p, thing, node); 1.159 + return node; 1.160 + } 1.161 + return nullptr; 1.162 +} 1.163 + 1.164 +static VerifyNode * 1.165 +NextNode(VerifyNode *node) 1.166 +{ 1.167 + if (node->count == 0) 1.168 + return (VerifyNode *)((char *)node + sizeof(VerifyNode) - sizeof(EdgeValue)); 1.169 + else 1.170 + return (VerifyNode *)((char *)node + sizeof(VerifyNode) + 1.171 + sizeof(EdgeValue)*(node->count - 1)); 1.172 +} 1.173 + 1.174 +void 1.175 +gc::StartVerifyPreBarriers(JSRuntime *rt) 1.176 +{ 1.177 + if (rt->gcVerifyPreData || rt->gcIncrementalState != NO_INCREMENTAL) 1.178 + return; 1.179 + 1.180 + /* 1.181 + * The post barrier verifier requires the storebuffer to be enabled, but the 1.182 + * pre barrier verifier disables it as part of disabling GGC. Don't allow 1.183 + * starting the pre barrier verifier if the post barrier verifier is already 1.184 + * running. 1.185 + */ 1.186 + if (rt->gcVerifyPostData) 1.187 + return; 1.188 + 1.189 + MinorGC(rt, JS::gcreason::EVICT_NURSERY); 1.190 + 1.191 + AutoPrepareForTracing prep(rt, WithAtoms); 1.192 + 1.193 + if (!IsIncrementalGCSafe(rt)) 1.194 + return; 1.195 + 1.196 + for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) 1.197 + r.front()->bitmap.clear(); 1.198 + 1.199 + rt->gcNumber++; 1.200 + 1.201 + VerifyPreTracer *trc = js_new<VerifyPreTracer>(rt, JSTraceCallback(nullptr)); 1.202 + if (!trc) 1.203 + return; 1.204 + 1.205 + /* 1.206 + * Passing a function pointer directly to js_new trips a compiler bug in 1.207 + * MSVC. Work around by filling the pointer after allocating with nullptr. 1.208 + */ 1.209 + trc->setTraceCallback(AccumulateEdge); 1.210 + 1.211 + const size_t size = 64 * 1024 * 1024; 1.212 + trc->root = (VerifyNode *)js_malloc(size); 1.213 + if (!trc->root) 1.214 + goto oom; 1.215 + trc->edgeptr = (char *)trc->root; 1.216 + trc->term = trc->edgeptr + size; 1.217 + 1.218 + if (!trc->nodemap.init()) 1.219 + goto oom; 1.220 + 1.221 + /* Create the root node. */ 1.222 + trc->curnode = MakeNode(trc, nullptr, JSGCTraceKind(0)); 1.223 + 1.224 + /* We want MarkRuntime to save the roots to gcSavedRoots. */ 1.225 + rt->gcIncrementalState = MARK_ROOTS; 1.226 + 1.227 + /* Make all the roots be edges emanating from the root node. */ 1.228 + MarkRuntime(trc); 1.229 + 1.230 + VerifyNode *node; 1.231 + node = trc->curnode; 1.232 + if (trc->edgeptr == trc->term) 1.233 + goto oom; 1.234 + 1.235 + /* For each edge, make a node for it if one doesn't already exist. */ 1.236 + while ((char *)node < trc->edgeptr) { 1.237 + for (uint32_t i = 0; i < node->count; i++) { 1.238 + EdgeValue &e = node->edges[i]; 1.239 + VerifyNode *child = MakeNode(trc, e.thing, e.kind); 1.240 + if (child) { 1.241 + trc->curnode = child; 1.242 + JS_TraceChildren(trc, e.thing, e.kind); 1.243 + } 1.244 + if (trc->edgeptr == trc->term) 1.245 + goto oom; 1.246 + } 1.247 + 1.248 + node = NextNode(node); 1.249 + } 1.250 + 1.251 + rt->gcVerifyPreData = trc; 1.252 + rt->gcIncrementalState = MARK; 1.253 + rt->gcMarker.start(); 1.254 + 1.255 + rt->setNeedsBarrier(true); 1.256 + for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { 1.257 + PurgeJITCaches(zone); 1.258 + zone->setNeedsBarrier(true, Zone::UpdateIon); 1.259 + zone->allocator.arenas.purge(); 1.260 + } 1.261 + 1.262 + return; 1.263 + 1.264 +oom: 1.265 + rt->gcIncrementalState = NO_INCREMENTAL; 1.266 + js_delete(trc); 1.267 + rt->gcVerifyPreData = nullptr; 1.268 +} 1.269 + 1.270 +static bool 1.271 +IsMarkedOrAllocated(Cell *cell) 1.272 +{ 1.273 + return cell->isMarked() || cell->arenaHeader()->allocatedDuringIncremental; 1.274 +} 1.275 + 1.276 +static const uint32_t MAX_VERIFIER_EDGES = 1000; 1.277 + 1.278 +/* 1.279 + * This function is called by EndVerifyBarriers for every heap edge. If the edge 1.280 + * already existed in the original snapshot, we "cancel it out" by overwriting 1.281 + * it with nullptr. EndVerifyBarriers later asserts that the remaining 1.282 + * non-nullptr edges (i.e., the ones from the original snapshot that must have 1.283 + * been modified) must point to marked objects. 1.284 + */ 1.285 +static void 1.286 +CheckEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) 1.287 +{ 1.288 + VerifyPreTracer *trc = (VerifyPreTracer *)jstrc; 1.289 + VerifyNode *node = trc->curnode; 1.290 + 1.291 + /* Avoid n^2 behavior. */ 1.292 + if (node->count > MAX_VERIFIER_EDGES) 1.293 + return; 1.294 + 1.295 + for (uint32_t i = 0; i < node->count; i++) { 1.296 + if (node->edges[i].thing == *thingp) { 1.297 + JS_ASSERT(node->edges[i].kind == kind); 1.298 + node->edges[i].thing = nullptr; 1.299 + return; 1.300 + } 1.301 + } 1.302 +} 1.303 + 1.304 +static void 1.305 +AssertMarkedOrAllocated(const EdgeValue &edge) 1.306 +{ 1.307 + if (!edge.thing || IsMarkedOrAllocated(static_cast<Cell *>(edge.thing))) 1.308 + return; 1.309 + 1.310 + // Permanent atoms aren't marked during graph traversal. 1.311 + if (edge.kind == JSTRACE_STRING && static_cast<JSString *>(edge.thing)->isPermanentAtom()) 1.312 + return; 1.313 + 1.314 + char msgbuf[1024]; 1.315 + const char *label = edge.label; 1.316 + 1.317 + JS_snprintf(msgbuf, sizeof(msgbuf), "[barrier verifier] Unmarked edge: %s", label); 1.318 + MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__); 1.319 + MOZ_CRASH(); 1.320 +} 1.321 + 1.322 +void 1.323 +gc::EndVerifyPreBarriers(JSRuntime *rt) 1.324 +{ 1.325 + JS_ASSERT(!JS::IsGenerationalGCEnabled(rt)); 1.326 + 1.327 + AutoPrepareForTracing prep(rt, SkipAtoms); 1.328 + 1.329 + VerifyPreTracer *trc = (VerifyPreTracer *)rt->gcVerifyPreData; 1.330 + 1.331 + if (!trc) 1.332 + return; 1.333 + 1.334 + bool compartmentCreated = false; 1.335 + 1.336 + /* We need to disable barriers before tracing, which may invoke barriers. */ 1.337 + for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { 1.338 + if (!zone->needsBarrier()) 1.339 + compartmentCreated = true; 1.340 + 1.341 + zone->setNeedsBarrier(false, Zone::UpdateIon); 1.342 + PurgeJITCaches(zone); 1.343 + } 1.344 + rt->setNeedsBarrier(false); 1.345 + 1.346 + /* 1.347 + * We need to bump gcNumber so that the methodjit knows that jitcode has 1.348 + * been discarded. 1.349 + */ 1.350 + JS_ASSERT(trc->number == rt->gcNumber); 1.351 + rt->gcNumber++; 1.352 + 1.353 + rt->gcVerifyPreData = nullptr; 1.354 + rt->gcIncrementalState = NO_INCREMENTAL; 1.355 + 1.356 + if (!compartmentCreated && IsIncrementalGCSafe(rt)) { 1.357 + trc->setTraceCallback(CheckEdge); 1.358 + 1.359 + /* Start after the roots. */ 1.360 + VerifyNode *node = NextNode(trc->root); 1.361 + while ((char *)node < trc->edgeptr) { 1.362 + trc->curnode = node; 1.363 + JS_TraceChildren(trc, node->thing, node->kind); 1.364 + 1.365 + if (node->count <= MAX_VERIFIER_EDGES) { 1.366 + for (uint32_t i = 0; i < node->count; i++) 1.367 + AssertMarkedOrAllocated(node->edges[i]); 1.368 + } 1.369 + 1.370 + node = NextNode(node); 1.371 + } 1.372 + } 1.373 + 1.374 + rt->gcMarker.reset(); 1.375 + rt->gcMarker.stop(); 1.376 + 1.377 + js_delete(trc); 1.378 +} 1.379 + 1.380 +/*** Post-Barrier Verifyier ***/ 1.381 + 1.382 +struct VerifyPostTracer : JSTracer 1.383 +{ 1.384 + /* The gcNumber when the verification began. */ 1.385 + uint64_t number; 1.386 + 1.387 + /* This counts up to gcZealFrequency to decide whether to verify. */ 1.388 + int count; 1.389 + 1.390 + /* The set of edges in the StoreBuffer at the end of verification. */ 1.391 + typedef HashSet<void **, PointerHasher<void **, 3>, SystemAllocPolicy> EdgeSet; 1.392 + EdgeSet *edges; 1.393 + 1.394 + VerifyPostTracer(JSRuntime *rt, JSTraceCallback callback) 1.395 + : JSTracer(rt, callback), number(rt->gcNumber), count(0) 1.396 + {} 1.397 +}; 1.398 + 1.399 +/* 1.400 + * The post-barrier verifier runs the full store buffer and a fake nursery when 1.401 + * running and when it stops, walks the full heap to ensure that all the 1.402 + * important edges were inserted into the storebuffer. 1.403 + */ 1.404 +void 1.405 +gc::StartVerifyPostBarriers(JSRuntime *rt) 1.406 +{ 1.407 +#ifdef JSGC_GENERATIONAL 1.408 + if (rt->gcVerifyPostData || 1.409 + rt->gcIncrementalState != NO_INCREMENTAL) 1.410 + { 1.411 + return; 1.412 + } 1.413 + 1.414 + MinorGC(rt, JS::gcreason::EVICT_NURSERY); 1.415 + 1.416 + rt->gcNumber++; 1.417 + 1.418 + VerifyPostTracer *trc = js_new<VerifyPostTracer>(rt, JSTraceCallback(nullptr)); 1.419 + if (!trc) 1.420 + return; 1.421 + 1.422 + rt->gcVerifyPostData = trc; 1.423 +#endif 1.424 +} 1.425 + 1.426 +#ifdef JSGC_GENERATIONAL 1.427 +void 1.428 +PostVerifierCollectStoreBufferEdges(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) 1.429 +{ 1.430 + VerifyPostTracer *trc = (VerifyPostTracer *)jstrc; 1.431 + 1.432 + /* The nursery only stores objects. */ 1.433 + if (kind != JSTRACE_OBJECT) 1.434 + return; 1.435 + 1.436 + /* The store buffer may store extra, non-cross-generational edges. */ 1.437 + JSObject *dst = *reinterpret_cast<JSObject **>(thingp); 1.438 + if (trc->runtime()->gcNursery.isInside(thingp) || !trc->runtime()->gcNursery.isInside(dst)) 1.439 + return; 1.440 + 1.441 + /* 1.442 + * Values will be unpacked to the stack before getting here. However, the 1.443 + * only things that enter this callback are marked by the store buffer. The 1.444 + * store buffer ensures that the real tracing location is set correctly. 1.445 + */ 1.446 + void **loc = trc->tracingLocation(thingp); 1.447 + 1.448 + trc->edges->put(loc); 1.449 +} 1.450 + 1.451 +static void 1.452 +AssertStoreBufferContainsEdge(VerifyPostTracer::EdgeSet *edges, void **loc, JSObject *dst) 1.453 +{ 1.454 + if (edges->has(loc)) 1.455 + return; 1.456 + 1.457 + char msgbuf[1024]; 1.458 + JS_snprintf(msgbuf, sizeof(msgbuf), "[post-barrier verifier] Missing edge @ %p to %p", 1.459 + (void *)loc, (void *)dst); 1.460 + MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__); 1.461 + MOZ_CRASH(); 1.462 +} 1.463 + 1.464 +void 1.465 +PostVerifierVisitEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) 1.466 +{ 1.467 + VerifyPostTracer *trc = (VerifyPostTracer *)jstrc; 1.468 + 1.469 + /* The nursery only stores objects. */ 1.470 + if (kind != JSTRACE_OBJECT) 1.471 + return; 1.472 + 1.473 + /* Filter out non cross-generational edges. */ 1.474 + JS_ASSERT(!trc->runtime()->gcNursery.isInside(thingp)); 1.475 + JSObject *dst = *reinterpret_cast<JSObject **>(thingp); 1.476 + if (!trc->runtime()->gcNursery.isInside(dst)) 1.477 + return; 1.478 + 1.479 + /* 1.480 + * Values will be unpacked to the stack before getting here. However, the 1.481 + * only things that enter this callback are marked by the JS_TraceChildren 1.482 + * below. Since ObjectImpl::markChildren handles this, the real trace 1.483 + * location will be set correctly in these cases. 1.484 + */ 1.485 + void **loc = trc->tracingLocation(thingp); 1.486 + 1.487 + AssertStoreBufferContainsEdge(trc->edges, loc, dst); 1.488 +} 1.489 +#endif 1.490 + 1.491 +void 1.492 +js::gc::EndVerifyPostBarriers(JSRuntime *rt) 1.493 +{ 1.494 +#ifdef JSGC_GENERATIONAL 1.495 + VerifyPostTracer::EdgeSet edges; 1.496 + AutoPrepareForTracing prep(rt, SkipAtoms); 1.497 + 1.498 + VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData; 1.499 + 1.500 + /* Visit every entry in the store buffer and put the edges in a hash set. */ 1.501 + trc->setTraceCallback(PostVerifierCollectStoreBufferEdges); 1.502 + if (!edges.init()) 1.503 + goto oom; 1.504 + trc->edges = &edges; 1.505 + rt->gcStoreBuffer.markAll(trc); 1.506 + 1.507 + /* Walk the heap to find any edges not the the |edges| set. */ 1.508 + trc->setTraceCallback(PostVerifierVisitEdge); 1.509 + for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { 1.510 + for (size_t kind = 0; kind < FINALIZE_LIMIT; ++kind) { 1.511 + for (CellIterUnderGC cells(zone, AllocKind(kind)); !cells.done(); cells.next()) { 1.512 + Cell *src = cells.getCell(); 1.513 + JS_TraceChildren(trc, src, MapAllocToTraceKind(AllocKind(kind))); 1.514 + } 1.515 + } 1.516 + } 1.517 + 1.518 +oom: 1.519 + js_delete(trc); 1.520 + rt->gcVerifyPostData = nullptr; 1.521 +#endif 1.522 +} 1.523 + 1.524 +/*** Barrier Verifier Scheduling ***/ 1.525 + 1.526 +static void 1.527 +VerifyPreBarriers(JSRuntime *rt) 1.528 +{ 1.529 + if (rt->gcVerifyPreData) 1.530 + EndVerifyPreBarriers(rt); 1.531 + else 1.532 + StartVerifyPreBarriers(rt); 1.533 +} 1.534 + 1.535 +static void 1.536 +VerifyPostBarriers(JSRuntime *rt) 1.537 +{ 1.538 + if (rt->gcVerifyPostData) 1.539 + EndVerifyPostBarriers(rt); 1.540 + else 1.541 + StartVerifyPostBarriers(rt); 1.542 +} 1.543 + 1.544 +void 1.545 +gc::VerifyBarriers(JSRuntime *rt, VerifierType type) 1.546 +{ 1.547 + if (type == PreBarrierVerifier) 1.548 + VerifyPreBarriers(rt); 1.549 + else 1.550 + VerifyPostBarriers(rt); 1.551 +} 1.552 + 1.553 +static void 1.554 +MaybeVerifyPreBarriers(JSRuntime *rt, bool always) 1.555 +{ 1.556 + if (rt->gcZeal() != ZealVerifierPreValue) 1.557 + return; 1.558 + 1.559 + if (rt->mainThread.suppressGC) 1.560 + return; 1.561 + 1.562 + if (VerifyPreTracer *trc = (VerifyPreTracer *)rt->gcVerifyPreData) { 1.563 + if (++trc->count < rt->gcZealFrequency && !always) 1.564 + return; 1.565 + 1.566 + EndVerifyPreBarriers(rt); 1.567 + } 1.568 + 1.569 + StartVerifyPreBarriers(rt); 1.570 +} 1.571 + 1.572 +static void 1.573 +MaybeVerifyPostBarriers(JSRuntime *rt, bool always) 1.574 +{ 1.575 +#ifdef JSGC_GENERATIONAL 1.576 + if (rt->gcZeal() != ZealVerifierPostValue) 1.577 + return; 1.578 + 1.579 + if (rt->mainThread.suppressGC || !rt->gcStoreBuffer.isEnabled()) 1.580 + return; 1.581 + 1.582 + if (VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData) { 1.583 + if (++trc->count < rt->gcZealFrequency && !always) 1.584 + return; 1.585 + 1.586 + EndVerifyPostBarriers(rt); 1.587 + } 1.588 + StartVerifyPostBarriers(rt); 1.589 +#endif 1.590 +} 1.591 + 1.592 +void 1.593 +js::gc::MaybeVerifyBarriers(JSContext *cx, bool always) 1.594 +{ 1.595 + MaybeVerifyPreBarriers(cx->runtime(), always); 1.596 + MaybeVerifyPostBarriers(cx->runtime(), always); 1.597 +} 1.598 + 1.599 +void 1.600 +js::gc::FinishVerifier(JSRuntime *rt) 1.601 +{ 1.602 + if (VerifyPreTracer *trc = (VerifyPreTracer *)rt->gcVerifyPreData) { 1.603 + js_delete(trc); 1.604 + rt->gcVerifyPreData = nullptr; 1.605 + } 1.606 +#ifdef JSGC_GENERATIONAL 1.607 + if (VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData) { 1.608 + js_delete(trc); 1.609 + rt->gcVerifyPostData = nullptr; 1.610 + } 1.611 +#endif 1.612 +} 1.613 + 1.614 +#endif /* JS_GC_ZEAL */