1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/gc/Tracer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,674 @@ 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 +#include "gc/Tracer.h" 1.11 + 1.12 +#include "mozilla/DebugOnly.h" 1.13 + 1.14 +#include "jsapi.h" 1.15 +#include "jsfun.h" 1.16 +#include "jsgc.h" 1.17 +#include "jsprf.h" 1.18 +#include "jsscript.h" 1.19 +#include "jsutil.h" 1.20 +#include "NamespaceImports.h" 1.21 + 1.22 +#include "gc/GCInternals.h" 1.23 +#include "gc/Marking.h" 1.24 + 1.25 +#include "jsgcinlines.h" 1.26 + 1.27 +using namespace js; 1.28 +using namespace js::gc; 1.29 +using mozilla::DebugOnly; 1.30 + 1.31 +JS_PUBLIC_API(void) 1.32 +JS_CallValueTracer(JSTracer *trc, Value *valuep, const char *name) 1.33 +{ 1.34 + MarkValueUnbarriered(trc, valuep, name); 1.35 +} 1.36 + 1.37 +JS_PUBLIC_API(void) 1.38 +JS_CallIdTracer(JSTracer *trc, jsid *idp, const char *name) 1.39 +{ 1.40 + MarkIdUnbarriered(trc, idp, name); 1.41 +} 1.42 + 1.43 +JS_PUBLIC_API(void) 1.44 +JS_CallObjectTracer(JSTracer *trc, JSObject **objp, const char *name) 1.45 +{ 1.46 + MarkObjectUnbarriered(trc, objp, name); 1.47 +} 1.48 + 1.49 +JS_PUBLIC_API(void) 1.50 +JS_CallStringTracer(JSTracer *trc, JSString **strp, const char *name) 1.51 +{ 1.52 + MarkStringUnbarriered(trc, strp, name); 1.53 +} 1.54 + 1.55 +JS_PUBLIC_API(void) 1.56 +JS_CallScriptTracer(JSTracer *trc, JSScript **scriptp, const char *name) 1.57 +{ 1.58 + MarkScriptUnbarriered(trc, scriptp, name); 1.59 +} 1.60 + 1.61 +JS_PUBLIC_API(void) 1.62 +JS_CallHeapValueTracer(JSTracer *trc, JS::Heap<JS::Value> *valuep, const char *name) 1.63 +{ 1.64 + MarkValueUnbarriered(trc, valuep->unsafeGet(), name); 1.65 +} 1.66 + 1.67 +JS_PUBLIC_API(void) 1.68 +JS_CallHeapIdTracer(JSTracer *trc, JS::Heap<jsid> *idp, const char *name) 1.69 +{ 1.70 + MarkIdUnbarriered(trc, idp->unsafeGet(), name); 1.71 +} 1.72 + 1.73 +JS_PUBLIC_API(void) 1.74 +JS_CallHeapObjectTracer(JSTracer *trc, JS::Heap<JSObject *> *objp, const char *name) 1.75 +{ 1.76 + MarkObjectUnbarriered(trc, objp->unsafeGet(), name); 1.77 +} 1.78 + 1.79 +JS_PUBLIC_API(void) 1.80 +JS_CallHeapStringTracer(JSTracer *trc, JS::Heap<JSString *> *strp, const char *name) 1.81 +{ 1.82 + MarkStringUnbarriered(trc, strp->unsafeGet(), name); 1.83 +} 1.84 + 1.85 +JS_PUBLIC_API(void) 1.86 +JS_CallHeapScriptTracer(JSTracer *trc, JS::Heap<JSScript *> *scriptp, const char *name) 1.87 +{ 1.88 + MarkScriptUnbarriered(trc, scriptp->unsafeGet(), name); 1.89 +} 1.90 + 1.91 +JS_PUBLIC_API(void) 1.92 +JS_CallHeapFunctionTracer(JSTracer *trc, JS::Heap<JSFunction *> *funp, const char *name) 1.93 +{ 1.94 + MarkObjectUnbarriered(trc, funp->unsafeGet(), name); 1.95 +} 1.96 + 1.97 +JS_PUBLIC_API(void) 1.98 +JS_CallTenuredObjectTracer(JSTracer *trc, JS::TenuredHeap<JSObject *> *objp, const char *name) 1.99 +{ 1.100 + JSObject *obj = objp->getPtr(); 1.101 + if (!obj) 1.102 + return; 1.103 + 1.104 + trc->setTracingLocation((void*)objp); 1.105 + MarkObjectUnbarriered(trc, &obj, name); 1.106 + 1.107 + objp->setPtr(obj); 1.108 +} 1.109 + 1.110 +JS_PUBLIC_API(void) 1.111 +JS_TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind) 1.112 +{ 1.113 + js::TraceChildren(trc, thing, kind); 1.114 +} 1.115 + 1.116 +JS_PUBLIC_API(void) 1.117 +JS_TraceRuntime(JSTracer *trc) 1.118 +{ 1.119 + AssertHeapIsIdle(trc->runtime()); 1.120 + TraceRuntime(trc); 1.121 +} 1.122 + 1.123 +static size_t 1.124 +CountDecimalDigits(size_t num) 1.125 +{ 1.126 + size_t numDigits = 0; 1.127 + do { 1.128 + num /= 10; 1.129 + numDigits++; 1.130 + } while (num > 0); 1.131 + 1.132 + return numDigits; 1.133 +} 1.134 + 1.135 +JS_PUBLIC_API(void) 1.136 +JS_GetTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, 1.137 + JSGCTraceKind kind, bool details) 1.138 +{ 1.139 + const char *name = nullptr; /* silence uninitialized warning */ 1.140 + size_t n; 1.141 + 1.142 + if (bufsize == 0) 1.143 + return; 1.144 + 1.145 + switch (kind) { 1.146 + case JSTRACE_OBJECT: 1.147 + { 1.148 + name = static_cast<JSObject *>(thing)->getClass()->name; 1.149 + break; 1.150 + } 1.151 + 1.152 + case JSTRACE_STRING: 1.153 + name = ((JSString *)thing)->isDependent() 1.154 + ? "substring" 1.155 + : "string"; 1.156 + break; 1.157 + 1.158 + case JSTRACE_SCRIPT: 1.159 + name = "script"; 1.160 + break; 1.161 + 1.162 + case JSTRACE_LAZY_SCRIPT: 1.163 + name = "lazyscript"; 1.164 + break; 1.165 + 1.166 + case JSTRACE_JITCODE: 1.167 + name = "jitcode"; 1.168 + break; 1.169 + 1.170 + case JSTRACE_SHAPE: 1.171 + name = "shape"; 1.172 + break; 1.173 + 1.174 + case JSTRACE_BASE_SHAPE: 1.175 + name = "base_shape"; 1.176 + break; 1.177 + 1.178 + case JSTRACE_TYPE_OBJECT: 1.179 + name = "type_object"; 1.180 + break; 1.181 + } 1.182 + 1.183 + n = strlen(name); 1.184 + if (n > bufsize - 1) 1.185 + n = bufsize - 1; 1.186 + js_memcpy(buf, name, n + 1); 1.187 + buf += n; 1.188 + bufsize -= n; 1.189 + *buf = '\0'; 1.190 + 1.191 + if (details && bufsize > 2) { 1.192 + switch (kind) { 1.193 + case JSTRACE_OBJECT: 1.194 + { 1.195 + JSObject *obj = (JSObject *)thing; 1.196 + if (obj->is<JSFunction>()) { 1.197 + JSFunction *fun = &obj->as<JSFunction>(); 1.198 + if (fun->displayAtom()) { 1.199 + *buf++ = ' '; 1.200 + bufsize--; 1.201 + PutEscapedString(buf, bufsize, fun->displayAtom(), 0); 1.202 + } 1.203 + } else if (obj->getClass()->flags & JSCLASS_HAS_PRIVATE) { 1.204 + JS_snprintf(buf, bufsize, " %p", obj->getPrivate()); 1.205 + } else { 1.206 + JS_snprintf(buf, bufsize, " <no private>"); 1.207 + } 1.208 + break; 1.209 + } 1.210 + 1.211 + case JSTRACE_STRING: 1.212 + { 1.213 + *buf++ = ' '; 1.214 + bufsize--; 1.215 + JSString *str = (JSString *)thing; 1.216 + 1.217 + if (str->isLinear()) { 1.218 + bool willFit = str->length() + strlen("<length > ") + 1.219 + CountDecimalDigits(str->length()) < bufsize; 1.220 + 1.221 + n = JS_snprintf(buf, bufsize, "<length %d%s> ", 1.222 + (int)str->length(), 1.223 + willFit ? "" : " (truncated)"); 1.224 + buf += n; 1.225 + bufsize -= n; 1.226 + 1.227 + PutEscapedString(buf, bufsize, &str->asLinear(), 0); 1.228 + } 1.229 + else 1.230 + JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length()); 1.231 + break; 1.232 + } 1.233 + 1.234 + case JSTRACE_SCRIPT: 1.235 + { 1.236 + JSScript *script = static_cast<JSScript *>(thing); 1.237 + JS_snprintf(buf, bufsize, " %s:%u", script->filename(), unsigned(script->lineno())); 1.238 + break; 1.239 + } 1.240 + 1.241 + case JSTRACE_LAZY_SCRIPT: 1.242 + case JSTRACE_JITCODE: 1.243 + case JSTRACE_SHAPE: 1.244 + case JSTRACE_BASE_SHAPE: 1.245 + case JSTRACE_TYPE_OBJECT: 1.246 + break; 1.247 + } 1.248 + } 1.249 + buf[bufsize - 1] = '\0'; 1.250 +} 1.251 + 1.252 +JSTracer::JSTracer(JSRuntime *rt, JSTraceCallback traceCallback, 1.253 + WeakMapTraceKind weakTraceKind /* = TraceWeakMapValues */) 1.254 + : callback(traceCallback) 1.255 + , runtime_(rt) 1.256 + , debugPrinter_(nullptr) 1.257 + , debugPrintArg_(nullptr) 1.258 + , debugPrintIndex_(size_t(-1)) 1.259 + , eagerlyTraceWeakMaps_(weakTraceKind) 1.260 +#ifdef JS_GC_ZEAL 1.261 + , realLocation_(nullptr) 1.262 +#endif 1.263 +{ 1.264 +} 1.265 + 1.266 +bool 1.267 +JSTracer::hasTracingDetails() const 1.268 +{ 1.269 + return debugPrinter_ || debugPrintArg_; 1.270 +} 1.271 + 1.272 +const char * 1.273 +JSTracer::tracingName(const char *fallback) const 1.274 +{ 1.275 + JS_ASSERT(hasTracingDetails()); 1.276 + return debugPrinter_ ? fallback : (const char *)debugPrintArg_; 1.277 +} 1.278 + 1.279 +const char * 1.280 +JSTracer::getTracingEdgeName(char *buffer, size_t bufferSize) 1.281 +{ 1.282 + if (debugPrinter_) { 1.283 + debugPrinter_(this, buffer, bufferSize); 1.284 + return buffer; 1.285 + } 1.286 + if (debugPrintIndex_ != size_t(-1)) { 1.287 + JS_snprintf(buffer, bufferSize, "%s[%lu]", 1.288 + (const char *)debugPrintArg_, 1.289 + debugPrintIndex_); 1.290 + return buffer; 1.291 + } 1.292 + return (const char*)debugPrintArg_; 1.293 +} 1.294 + 1.295 +JSTraceNamePrinter 1.296 +JSTracer::debugPrinter() const 1.297 +{ 1.298 + return debugPrinter_; 1.299 +} 1.300 + 1.301 +const void * 1.302 +JSTracer::debugPrintArg() const 1.303 +{ 1.304 + return debugPrintArg_; 1.305 +} 1.306 + 1.307 +size_t 1.308 +JSTracer::debugPrintIndex() const 1.309 +{ 1.310 + return debugPrintIndex_; 1.311 +} 1.312 + 1.313 +void 1.314 +JSTracer::setTraceCallback(JSTraceCallback traceCallback) 1.315 +{ 1.316 + callback = traceCallback; 1.317 +} 1.318 + 1.319 +#ifdef JS_GC_ZEAL 1.320 +void 1.321 +JSTracer::setTracingLocation(void *location) 1.322 +{ 1.323 + if (!realLocation_ || !location) 1.324 + realLocation_ = location; 1.325 +} 1.326 + 1.327 +void 1.328 +JSTracer::unsetTracingLocation() 1.329 +{ 1.330 + realLocation_ = nullptr; 1.331 +} 1.332 + 1.333 +void ** 1.334 +JSTracer::tracingLocation(void **thingp) 1.335 +{ 1.336 + return realLocation_ ? (void **)realLocation_ : thingp; 1.337 +} 1.338 +#endif 1.339 + 1.340 +bool 1.341 +MarkStack::init(JSGCMode gcMode) 1.342 +{ 1.343 + setBaseCapacity(gcMode); 1.344 + 1.345 + JS_ASSERT(!stack_); 1.346 + uintptr_t *newStack = js_pod_malloc<uintptr_t>(baseCapacity_); 1.347 + if (!newStack) 1.348 + return false; 1.349 + 1.350 + setStack(newStack, 0, baseCapacity_); 1.351 + return true; 1.352 +} 1.353 + 1.354 +void 1.355 +MarkStack::setBaseCapacity(JSGCMode mode) 1.356 +{ 1.357 + switch (mode) { 1.358 + case JSGC_MODE_GLOBAL: 1.359 + case JSGC_MODE_COMPARTMENT: 1.360 + baseCapacity_ = NON_INCREMENTAL_MARK_STACK_BASE_CAPACITY; 1.361 + break; 1.362 + case JSGC_MODE_INCREMENTAL: 1.363 + baseCapacity_ = INCREMENTAL_MARK_STACK_BASE_CAPACITY; 1.364 + break; 1.365 + default: 1.366 + MOZ_ASSUME_UNREACHABLE("bad gc mode"); 1.367 + } 1.368 + 1.369 + if (baseCapacity_ > maxCapacity_) 1.370 + baseCapacity_ = maxCapacity_; 1.371 +} 1.372 + 1.373 +void 1.374 +MarkStack::setMaxCapacity(size_t maxCapacity) 1.375 +{ 1.376 + JS_ASSERT(isEmpty()); 1.377 + maxCapacity_ = maxCapacity; 1.378 + if (baseCapacity_ > maxCapacity_) 1.379 + baseCapacity_ = maxCapacity_; 1.380 + 1.381 + reset(); 1.382 +} 1.383 + 1.384 +void 1.385 +MarkStack::reset() 1.386 +{ 1.387 + if (capacity() == baseCapacity_) { 1.388 + // No size change; keep the current stack. 1.389 + setStack(stack_, 0, baseCapacity_); 1.390 + return; 1.391 + } 1.392 + 1.393 + uintptr_t *newStack = (uintptr_t *)js_realloc(stack_, sizeof(uintptr_t) * baseCapacity_); 1.394 + if (!newStack) { 1.395 + // If the realloc fails, just keep using the existing stack; it's 1.396 + // not ideal but better than failing. 1.397 + newStack = stack_; 1.398 + baseCapacity_ = capacity(); 1.399 + } 1.400 + setStack(newStack, 0, baseCapacity_); 1.401 +} 1.402 + 1.403 +bool 1.404 +MarkStack::enlarge(unsigned count) 1.405 +{ 1.406 + size_t newCapacity = Min(maxCapacity_, capacity() * 2); 1.407 + if (newCapacity < capacity() + count) 1.408 + return false; 1.409 + 1.410 + size_t tosIndex = position(); 1.411 + 1.412 + uintptr_t *newStack = (uintptr_t *)js_realloc(stack_, sizeof(uintptr_t) * newCapacity); 1.413 + if (!newStack) 1.414 + return false; 1.415 + 1.416 + setStack(newStack, tosIndex, newCapacity); 1.417 + return true; 1.418 +} 1.419 + 1.420 +void 1.421 +MarkStack::setGCMode(JSGCMode gcMode) 1.422 +{ 1.423 + // The mark stack won't be resized until the next call to reset(), but 1.424 + // that will happen at the end of the next GC. 1.425 + setBaseCapacity(gcMode); 1.426 +} 1.427 + 1.428 +size_t 1.429 +MarkStack::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const 1.430 +{ 1.431 + return mallocSizeOf(stack_); 1.432 +} 1.433 + 1.434 +/* 1.435 + * DoNotTraceWeakMaps: the GC is recomputing the liveness of WeakMap entries, 1.436 + * so we delay visting entries. 1.437 + */ 1.438 +GCMarker::GCMarker(JSRuntime *rt) 1.439 + : JSTracer(rt, nullptr, DoNotTraceWeakMaps), 1.440 + stack(size_t(-1)), 1.441 + color(BLACK), 1.442 + unmarkedArenaStackTop(nullptr), 1.443 + markLaterArenas(0), 1.444 + grayBufferState(GRAY_BUFFER_UNUSED), 1.445 + started(false) 1.446 +{ 1.447 +} 1.448 + 1.449 +bool 1.450 +GCMarker::init(JSGCMode gcMode) 1.451 +{ 1.452 + return stack.init(gcMode); 1.453 +} 1.454 + 1.455 +void 1.456 +GCMarker::start() 1.457 +{ 1.458 + JS_ASSERT(!started); 1.459 + started = true; 1.460 + color = BLACK; 1.461 + 1.462 + JS_ASSERT(!unmarkedArenaStackTop); 1.463 + JS_ASSERT(markLaterArenas == 0); 1.464 + 1.465 +} 1.466 + 1.467 +void 1.468 +GCMarker::stop() 1.469 +{ 1.470 + JS_ASSERT(isDrained()); 1.471 + 1.472 + JS_ASSERT(started); 1.473 + started = false; 1.474 + 1.475 + JS_ASSERT(!unmarkedArenaStackTop); 1.476 + JS_ASSERT(markLaterArenas == 0); 1.477 + 1.478 + /* Free non-ballast stack memory. */ 1.479 + stack.reset(); 1.480 + 1.481 + resetBufferedGrayRoots(); 1.482 + grayBufferState = GRAY_BUFFER_UNUSED; 1.483 +} 1.484 + 1.485 +void 1.486 +GCMarker::reset() 1.487 +{ 1.488 + color = BLACK; 1.489 + 1.490 + stack.reset(); 1.491 + JS_ASSERT(isMarkStackEmpty()); 1.492 + 1.493 + while (unmarkedArenaStackTop) { 1.494 + ArenaHeader *aheader = unmarkedArenaStackTop; 1.495 + JS_ASSERT(aheader->hasDelayedMarking); 1.496 + JS_ASSERT(markLaterArenas); 1.497 + unmarkedArenaStackTop = aheader->getNextDelayedMarking(); 1.498 + aheader->unsetDelayedMarking(); 1.499 + aheader->markOverflow = 0; 1.500 + aheader->allocatedDuringIncremental = 0; 1.501 + markLaterArenas--; 1.502 + } 1.503 + JS_ASSERT(isDrained()); 1.504 + JS_ASSERT(!markLaterArenas); 1.505 +} 1.506 + 1.507 +void 1.508 +GCMarker::markDelayedChildren(ArenaHeader *aheader) 1.509 +{ 1.510 + if (aheader->markOverflow) { 1.511 + bool always = aheader->allocatedDuringIncremental; 1.512 + aheader->markOverflow = 0; 1.513 + 1.514 + for (CellIterUnderGC i(aheader); !i.done(); i.next()) { 1.515 + Cell *t = i.getCell(); 1.516 + if (always || t->isMarked()) { 1.517 + t->markIfUnmarked(); 1.518 + JS_TraceChildren(this, t, MapAllocToTraceKind(aheader->getAllocKind())); 1.519 + } 1.520 + } 1.521 + } else { 1.522 + JS_ASSERT(aheader->allocatedDuringIncremental); 1.523 + PushArena(this, aheader); 1.524 + } 1.525 + aheader->allocatedDuringIncremental = 0; 1.526 + /* 1.527 + * Note that during an incremental GC we may still be allocating into 1.528 + * aheader. However, prepareForIncrementalGC sets the 1.529 + * allocatedDuringIncremental flag if we continue marking. 1.530 + */ 1.531 +} 1.532 + 1.533 +bool 1.534 +GCMarker::markDelayedChildren(SliceBudget &budget) 1.535 +{ 1.536 + gcstats::MaybeAutoPhase ap; 1.537 + if (runtime()->gcIncrementalState == MARK) 1.538 + ap.construct(runtime()->gcStats, gcstats::PHASE_MARK_DELAYED); 1.539 + 1.540 + JS_ASSERT(unmarkedArenaStackTop); 1.541 + do { 1.542 + /* 1.543 + * If marking gets delayed at the same arena again, we must repeat 1.544 + * marking of its things. For that we pop arena from the stack and 1.545 + * clear its hasDelayedMarking flag before we begin the marking. 1.546 + */ 1.547 + ArenaHeader *aheader = unmarkedArenaStackTop; 1.548 + JS_ASSERT(aheader->hasDelayedMarking); 1.549 + JS_ASSERT(markLaterArenas); 1.550 + unmarkedArenaStackTop = aheader->getNextDelayedMarking(); 1.551 + aheader->unsetDelayedMarking(); 1.552 + markLaterArenas--; 1.553 + markDelayedChildren(aheader); 1.554 + 1.555 + budget.step(150); 1.556 + if (budget.isOverBudget()) 1.557 + return false; 1.558 + } while (unmarkedArenaStackTop); 1.559 + JS_ASSERT(!markLaterArenas); 1.560 + 1.561 + return true; 1.562 +} 1.563 + 1.564 +#ifdef DEBUG 1.565 +void 1.566 +GCMarker::checkZone(void *p) 1.567 +{ 1.568 + JS_ASSERT(started); 1.569 + DebugOnly<Cell *> cell = static_cast<Cell *>(p); 1.570 + JS_ASSERT_IF(cell->isTenured(), cell->tenuredZone()->isCollecting()); 1.571 +} 1.572 +#endif 1.573 + 1.574 +bool 1.575 +GCMarker::hasBufferedGrayRoots() const 1.576 +{ 1.577 + return grayBufferState == GRAY_BUFFER_OK; 1.578 +} 1.579 + 1.580 +void 1.581 +GCMarker::startBufferingGrayRoots() 1.582 +{ 1.583 + JS_ASSERT(grayBufferState == GRAY_BUFFER_UNUSED); 1.584 + grayBufferState = GRAY_BUFFER_OK; 1.585 + for (GCZonesIter zone(runtime()); !zone.done(); zone.next()) 1.586 + JS_ASSERT(zone->gcGrayRoots.empty()); 1.587 + 1.588 + JS_ASSERT(!callback); 1.589 + callback = GrayCallback; 1.590 + JS_ASSERT(IS_GC_MARKING_TRACER(this)); 1.591 +} 1.592 + 1.593 +void 1.594 +GCMarker::endBufferingGrayRoots() 1.595 +{ 1.596 + JS_ASSERT(callback == GrayCallback); 1.597 + callback = nullptr; 1.598 + JS_ASSERT(IS_GC_MARKING_TRACER(this)); 1.599 + JS_ASSERT(grayBufferState == GRAY_BUFFER_OK || 1.600 + grayBufferState == GRAY_BUFFER_FAILED); 1.601 +} 1.602 + 1.603 +void 1.604 +GCMarker::resetBufferedGrayRoots() 1.605 +{ 1.606 + for (GCZonesIter zone(runtime()); !zone.done(); zone.next()) 1.607 + zone->gcGrayRoots.clearAndFree(); 1.608 +} 1.609 + 1.610 +void 1.611 +GCMarker::markBufferedGrayRoots(JS::Zone *zone) 1.612 +{ 1.613 + JS_ASSERT(grayBufferState == GRAY_BUFFER_OK); 1.614 + JS_ASSERT(zone->isGCMarkingGray()); 1.615 + 1.616 + for (GrayRoot *elem = zone->gcGrayRoots.begin(); elem != zone->gcGrayRoots.end(); elem++) { 1.617 +#ifdef DEBUG 1.618 + setTracingDetails(elem->debugPrinter, elem->debugPrintArg, elem->debugPrintIndex); 1.619 +#endif 1.620 + void *tmp = elem->thing; 1.621 + setTracingLocation((void *)&elem->thing); 1.622 + MarkKind(this, &tmp, elem->kind); 1.623 + JS_ASSERT(tmp == elem->thing); 1.624 + } 1.625 +} 1.626 + 1.627 +void 1.628 +GCMarker::appendGrayRoot(void *thing, JSGCTraceKind kind) 1.629 +{ 1.630 + JS_ASSERT(started); 1.631 + 1.632 + if (grayBufferState == GRAY_BUFFER_FAILED) 1.633 + return; 1.634 + 1.635 + GrayRoot root(thing, kind); 1.636 +#ifdef DEBUG 1.637 + root.debugPrinter = debugPrinter(); 1.638 + root.debugPrintArg = debugPrintArg(); 1.639 + root.debugPrintIndex = debugPrintIndex(); 1.640 +#endif 1.641 + 1.642 + Zone *zone = static_cast<Cell *>(thing)->tenuredZone(); 1.643 + if (zone->isCollecting()) { 1.644 + zone->maybeAlive = true; 1.645 + if (!zone->gcGrayRoots.append(root)) { 1.646 + resetBufferedGrayRoots(); 1.647 + grayBufferState = GRAY_BUFFER_FAILED; 1.648 + } 1.649 + } 1.650 +} 1.651 + 1.652 +void 1.653 +GCMarker::GrayCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind) 1.654 +{ 1.655 + JS_ASSERT(thingp); 1.656 + JS_ASSERT(*thingp); 1.657 + GCMarker *gcmarker = static_cast<GCMarker *>(trc); 1.658 + gcmarker->appendGrayRoot(*thingp, kind); 1.659 +} 1.660 + 1.661 +size_t 1.662 +GCMarker::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const 1.663 +{ 1.664 + size_t size = stack.sizeOfExcludingThis(mallocSizeOf); 1.665 + for (ZonesIter zone(runtime(), WithAtoms); !zone.done(); zone.next()) 1.666 + size += zone->gcGrayRoots.sizeOfExcludingThis(mallocSizeOf); 1.667 + return size; 1.668 +} 1.669 + 1.670 +void 1.671 +js::SetMarkStackLimit(JSRuntime *rt, size_t limit) 1.672 +{ 1.673 + JS_ASSERT(!rt->isHeapBusy()); 1.674 + AutoStopVerifyingBarriers pauseVerification(rt, false); 1.675 + rt->gcMarker.setMaxCapacity(limit); 1.676 +} 1.677 +