js/src/gc/Tracer.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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 #include "gc/Tracer.h"
michael@0 8
michael@0 9 #include "mozilla/DebugOnly.h"
michael@0 10
michael@0 11 #include "jsapi.h"
michael@0 12 #include "jsfun.h"
michael@0 13 #include "jsgc.h"
michael@0 14 #include "jsprf.h"
michael@0 15 #include "jsscript.h"
michael@0 16 #include "jsutil.h"
michael@0 17 #include "NamespaceImports.h"
michael@0 18
michael@0 19 #include "gc/GCInternals.h"
michael@0 20 #include "gc/Marking.h"
michael@0 21
michael@0 22 #include "jsgcinlines.h"
michael@0 23
michael@0 24 using namespace js;
michael@0 25 using namespace js::gc;
michael@0 26 using mozilla::DebugOnly;
michael@0 27
michael@0 28 JS_PUBLIC_API(void)
michael@0 29 JS_CallValueTracer(JSTracer *trc, Value *valuep, const char *name)
michael@0 30 {
michael@0 31 MarkValueUnbarriered(trc, valuep, name);
michael@0 32 }
michael@0 33
michael@0 34 JS_PUBLIC_API(void)
michael@0 35 JS_CallIdTracer(JSTracer *trc, jsid *idp, const char *name)
michael@0 36 {
michael@0 37 MarkIdUnbarriered(trc, idp, name);
michael@0 38 }
michael@0 39
michael@0 40 JS_PUBLIC_API(void)
michael@0 41 JS_CallObjectTracer(JSTracer *trc, JSObject **objp, const char *name)
michael@0 42 {
michael@0 43 MarkObjectUnbarriered(trc, objp, name);
michael@0 44 }
michael@0 45
michael@0 46 JS_PUBLIC_API(void)
michael@0 47 JS_CallStringTracer(JSTracer *trc, JSString **strp, const char *name)
michael@0 48 {
michael@0 49 MarkStringUnbarriered(trc, strp, name);
michael@0 50 }
michael@0 51
michael@0 52 JS_PUBLIC_API(void)
michael@0 53 JS_CallScriptTracer(JSTracer *trc, JSScript **scriptp, const char *name)
michael@0 54 {
michael@0 55 MarkScriptUnbarriered(trc, scriptp, name);
michael@0 56 }
michael@0 57
michael@0 58 JS_PUBLIC_API(void)
michael@0 59 JS_CallHeapValueTracer(JSTracer *trc, JS::Heap<JS::Value> *valuep, const char *name)
michael@0 60 {
michael@0 61 MarkValueUnbarriered(trc, valuep->unsafeGet(), name);
michael@0 62 }
michael@0 63
michael@0 64 JS_PUBLIC_API(void)
michael@0 65 JS_CallHeapIdTracer(JSTracer *trc, JS::Heap<jsid> *idp, const char *name)
michael@0 66 {
michael@0 67 MarkIdUnbarriered(trc, idp->unsafeGet(), name);
michael@0 68 }
michael@0 69
michael@0 70 JS_PUBLIC_API(void)
michael@0 71 JS_CallHeapObjectTracer(JSTracer *trc, JS::Heap<JSObject *> *objp, const char *name)
michael@0 72 {
michael@0 73 MarkObjectUnbarriered(trc, objp->unsafeGet(), name);
michael@0 74 }
michael@0 75
michael@0 76 JS_PUBLIC_API(void)
michael@0 77 JS_CallHeapStringTracer(JSTracer *trc, JS::Heap<JSString *> *strp, const char *name)
michael@0 78 {
michael@0 79 MarkStringUnbarriered(trc, strp->unsafeGet(), name);
michael@0 80 }
michael@0 81
michael@0 82 JS_PUBLIC_API(void)
michael@0 83 JS_CallHeapScriptTracer(JSTracer *trc, JS::Heap<JSScript *> *scriptp, const char *name)
michael@0 84 {
michael@0 85 MarkScriptUnbarriered(trc, scriptp->unsafeGet(), name);
michael@0 86 }
michael@0 87
michael@0 88 JS_PUBLIC_API(void)
michael@0 89 JS_CallHeapFunctionTracer(JSTracer *trc, JS::Heap<JSFunction *> *funp, const char *name)
michael@0 90 {
michael@0 91 MarkObjectUnbarriered(trc, funp->unsafeGet(), name);
michael@0 92 }
michael@0 93
michael@0 94 JS_PUBLIC_API(void)
michael@0 95 JS_CallTenuredObjectTracer(JSTracer *trc, JS::TenuredHeap<JSObject *> *objp, const char *name)
michael@0 96 {
michael@0 97 JSObject *obj = objp->getPtr();
michael@0 98 if (!obj)
michael@0 99 return;
michael@0 100
michael@0 101 trc->setTracingLocation((void*)objp);
michael@0 102 MarkObjectUnbarriered(trc, &obj, name);
michael@0 103
michael@0 104 objp->setPtr(obj);
michael@0 105 }
michael@0 106
michael@0 107 JS_PUBLIC_API(void)
michael@0 108 JS_TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind)
michael@0 109 {
michael@0 110 js::TraceChildren(trc, thing, kind);
michael@0 111 }
michael@0 112
michael@0 113 JS_PUBLIC_API(void)
michael@0 114 JS_TraceRuntime(JSTracer *trc)
michael@0 115 {
michael@0 116 AssertHeapIsIdle(trc->runtime());
michael@0 117 TraceRuntime(trc);
michael@0 118 }
michael@0 119
michael@0 120 static size_t
michael@0 121 CountDecimalDigits(size_t num)
michael@0 122 {
michael@0 123 size_t numDigits = 0;
michael@0 124 do {
michael@0 125 num /= 10;
michael@0 126 numDigits++;
michael@0 127 } while (num > 0);
michael@0 128
michael@0 129 return numDigits;
michael@0 130 }
michael@0 131
michael@0 132 JS_PUBLIC_API(void)
michael@0 133 JS_GetTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing,
michael@0 134 JSGCTraceKind kind, bool details)
michael@0 135 {
michael@0 136 const char *name = nullptr; /* silence uninitialized warning */
michael@0 137 size_t n;
michael@0 138
michael@0 139 if (bufsize == 0)
michael@0 140 return;
michael@0 141
michael@0 142 switch (kind) {
michael@0 143 case JSTRACE_OBJECT:
michael@0 144 {
michael@0 145 name = static_cast<JSObject *>(thing)->getClass()->name;
michael@0 146 break;
michael@0 147 }
michael@0 148
michael@0 149 case JSTRACE_STRING:
michael@0 150 name = ((JSString *)thing)->isDependent()
michael@0 151 ? "substring"
michael@0 152 : "string";
michael@0 153 break;
michael@0 154
michael@0 155 case JSTRACE_SCRIPT:
michael@0 156 name = "script";
michael@0 157 break;
michael@0 158
michael@0 159 case JSTRACE_LAZY_SCRIPT:
michael@0 160 name = "lazyscript";
michael@0 161 break;
michael@0 162
michael@0 163 case JSTRACE_JITCODE:
michael@0 164 name = "jitcode";
michael@0 165 break;
michael@0 166
michael@0 167 case JSTRACE_SHAPE:
michael@0 168 name = "shape";
michael@0 169 break;
michael@0 170
michael@0 171 case JSTRACE_BASE_SHAPE:
michael@0 172 name = "base_shape";
michael@0 173 break;
michael@0 174
michael@0 175 case JSTRACE_TYPE_OBJECT:
michael@0 176 name = "type_object";
michael@0 177 break;
michael@0 178 }
michael@0 179
michael@0 180 n = strlen(name);
michael@0 181 if (n > bufsize - 1)
michael@0 182 n = bufsize - 1;
michael@0 183 js_memcpy(buf, name, n + 1);
michael@0 184 buf += n;
michael@0 185 bufsize -= n;
michael@0 186 *buf = '\0';
michael@0 187
michael@0 188 if (details && bufsize > 2) {
michael@0 189 switch (kind) {
michael@0 190 case JSTRACE_OBJECT:
michael@0 191 {
michael@0 192 JSObject *obj = (JSObject *)thing;
michael@0 193 if (obj->is<JSFunction>()) {
michael@0 194 JSFunction *fun = &obj->as<JSFunction>();
michael@0 195 if (fun->displayAtom()) {
michael@0 196 *buf++ = ' ';
michael@0 197 bufsize--;
michael@0 198 PutEscapedString(buf, bufsize, fun->displayAtom(), 0);
michael@0 199 }
michael@0 200 } else if (obj->getClass()->flags & JSCLASS_HAS_PRIVATE) {
michael@0 201 JS_snprintf(buf, bufsize, " %p", obj->getPrivate());
michael@0 202 } else {
michael@0 203 JS_snprintf(buf, bufsize, " <no private>");
michael@0 204 }
michael@0 205 break;
michael@0 206 }
michael@0 207
michael@0 208 case JSTRACE_STRING:
michael@0 209 {
michael@0 210 *buf++ = ' ';
michael@0 211 bufsize--;
michael@0 212 JSString *str = (JSString *)thing;
michael@0 213
michael@0 214 if (str->isLinear()) {
michael@0 215 bool willFit = str->length() + strlen("<length > ") +
michael@0 216 CountDecimalDigits(str->length()) < bufsize;
michael@0 217
michael@0 218 n = JS_snprintf(buf, bufsize, "<length %d%s> ",
michael@0 219 (int)str->length(),
michael@0 220 willFit ? "" : " (truncated)");
michael@0 221 buf += n;
michael@0 222 bufsize -= n;
michael@0 223
michael@0 224 PutEscapedString(buf, bufsize, &str->asLinear(), 0);
michael@0 225 }
michael@0 226 else
michael@0 227 JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length());
michael@0 228 break;
michael@0 229 }
michael@0 230
michael@0 231 case JSTRACE_SCRIPT:
michael@0 232 {
michael@0 233 JSScript *script = static_cast<JSScript *>(thing);
michael@0 234 JS_snprintf(buf, bufsize, " %s:%u", script->filename(), unsigned(script->lineno()));
michael@0 235 break;
michael@0 236 }
michael@0 237
michael@0 238 case JSTRACE_LAZY_SCRIPT:
michael@0 239 case JSTRACE_JITCODE:
michael@0 240 case JSTRACE_SHAPE:
michael@0 241 case JSTRACE_BASE_SHAPE:
michael@0 242 case JSTRACE_TYPE_OBJECT:
michael@0 243 break;
michael@0 244 }
michael@0 245 }
michael@0 246 buf[bufsize - 1] = '\0';
michael@0 247 }
michael@0 248
michael@0 249 JSTracer::JSTracer(JSRuntime *rt, JSTraceCallback traceCallback,
michael@0 250 WeakMapTraceKind weakTraceKind /* = TraceWeakMapValues */)
michael@0 251 : callback(traceCallback)
michael@0 252 , runtime_(rt)
michael@0 253 , debugPrinter_(nullptr)
michael@0 254 , debugPrintArg_(nullptr)
michael@0 255 , debugPrintIndex_(size_t(-1))
michael@0 256 , eagerlyTraceWeakMaps_(weakTraceKind)
michael@0 257 #ifdef JS_GC_ZEAL
michael@0 258 , realLocation_(nullptr)
michael@0 259 #endif
michael@0 260 {
michael@0 261 }
michael@0 262
michael@0 263 bool
michael@0 264 JSTracer::hasTracingDetails() const
michael@0 265 {
michael@0 266 return debugPrinter_ || debugPrintArg_;
michael@0 267 }
michael@0 268
michael@0 269 const char *
michael@0 270 JSTracer::tracingName(const char *fallback) const
michael@0 271 {
michael@0 272 JS_ASSERT(hasTracingDetails());
michael@0 273 return debugPrinter_ ? fallback : (const char *)debugPrintArg_;
michael@0 274 }
michael@0 275
michael@0 276 const char *
michael@0 277 JSTracer::getTracingEdgeName(char *buffer, size_t bufferSize)
michael@0 278 {
michael@0 279 if (debugPrinter_) {
michael@0 280 debugPrinter_(this, buffer, bufferSize);
michael@0 281 return buffer;
michael@0 282 }
michael@0 283 if (debugPrintIndex_ != size_t(-1)) {
michael@0 284 JS_snprintf(buffer, bufferSize, "%s[%lu]",
michael@0 285 (const char *)debugPrintArg_,
michael@0 286 debugPrintIndex_);
michael@0 287 return buffer;
michael@0 288 }
michael@0 289 return (const char*)debugPrintArg_;
michael@0 290 }
michael@0 291
michael@0 292 JSTraceNamePrinter
michael@0 293 JSTracer::debugPrinter() const
michael@0 294 {
michael@0 295 return debugPrinter_;
michael@0 296 }
michael@0 297
michael@0 298 const void *
michael@0 299 JSTracer::debugPrintArg() const
michael@0 300 {
michael@0 301 return debugPrintArg_;
michael@0 302 }
michael@0 303
michael@0 304 size_t
michael@0 305 JSTracer::debugPrintIndex() const
michael@0 306 {
michael@0 307 return debugPrintIndex_;
michael@0 308 }
michael@0 309
michael@0 310 void
michael@0 311 JSTracer::setTraceCallback(JSTraceCallback traceCallback)
michael@0 312 {
michael@0 313 callback = traceCallback;
michael@0 314 }
michael@0 315
michael@0 316 #ifdef JS_GC_ZEAL
michael@0 317 void
michael@0 318 JSTracer::setTracingLocation(void *location)
michael@0 319 {
michael@0 320 if (!realLocation_ || !location)
michael@0 321 realLocation_ = location;
michael@0 322 }
michael@0 323
michael@0 324 void
michael@0 325 JSTracer::unsetTracingLocation()
michael@0 326 {
michael@0 327 realLocation_ = nullptr;
michael@0 328 }
michael@0 329
michael@0 330 void **
michael@0 331 JSTracer::tracingLocation(void **thingp)
michael@0 332 {
michael@0 333 return realLocation_ ? (void **)realLocation_ : thingp;
michael@0 334 }
michael@0 335 #endif
michael@0 336
michael@0 337 bool
michael@0 338 MarkStack::init(JSGCMode gcMode)
michael@0 339 {
michael@0 340 setBaseCapacity(gcMode);
michael@0 341
michael@0 342 JS_ASSERT(!stack_);
michael@0 343 uintptr_t *newStack = js_pod_malloc<uintptr_t>(baseCapacity_);
michael@0 344 if (!newStack)
michael@0 345 return false;
michael@0 346
michael@0 347 setStack(newStack, 0, baseCapacity_);
michael@0 348 return true;
michael@0 349 }
michael@0 350
michael@0 351 void
michael@0 352 MarkStack::setBaseCapacity(JSGCMode mode)
michael@0 353 {
michael@0 354 switch (mode) {
michael@0 355 case JSGC_MODE_GLOBAL:
michael@0 356 case JSGC_MODE_COMPARTMENT:
michael@0 357 baseCapacity_ = NON_INCREMENTAL_MARK_STACK_BASE_CAPACITY;
michael@0 358 break;
michael@0 359 case JSGC_MODE_INCREMENTAL:
michael@0 360 baseCapacity_ = INCREMENTAL_MARK_STACK_BASE_CAPACITY;
michael@0 361 break;
michael@0 362 default:
michael@0 363 MOZ_ASSUME_UNREACHABLE("bad gc mode");
michael@0 364 }
michael@0 365
michael@0 366 if (baseCapacity_ > maxCapacity_)
michael@0 367 baseCapacity_ = maxCapacity_;
michael@0 368 }
michael@0 369
michael@0 370 void
michael@0 371 MarkStack::setMaxCapacity(size_t maxCapacity)
michael@0 372 {
michael@0 373 JS_ASSERT(isEmpty());
michael@0 374 maxCapacity_ = maxCapacity;
michael@0 375 if (baseCapacity_ > maxCapacity_)
michael@0 376 baseCapacity_ = maxCapacity_;
michael@0 377
michael@0 378 reset();
michael@0 379 }
michael@0 380
michael@0 381 void
michael@0 382 MarkStack::reset()
michael@0 383 {
michael@0 384 if (capacity() == baseCapacity_) {
michael@0 385 // No size change; keep the current stack.
michael@0 386 setStack(stack_, 0, baseCapacity_);
michael@0 387 return;
michael@0 388 }
michael@0 389
michael@0 390 uintptr_t *newStack = (uintptr_t *)js_realloc(stack_, sizeof(uintptr_t) * baseCapacity_);
michael@0 391 if (!newStack) {
michael@0 392 // If the realloc fails, just keep using the existing stack; it's
michael@0 393 // not ideal but better than failing.
michael@0 394 newStack = stack_;
michael@0 395 baseCapacity_ = capacity();
michael@0 396 }
michael@0 397 setStack(newStack, 0, baseCapacity_);
michael@0 398 }
michael@0 399
michael@0 400 bool
michael@0 401 MarkStack::enlarge(unsigned count)
michael@0 402 {
michael@0 403 size_t newCapacity = Min(maxCapacity_, capacity() * 2);
michael@0 404 if (newCapacity < capacity() + count)
michael@0 405 return false;
michael@0 406
michael@0 407 size_t tosIndex = position();
michael@0 408
michael@0 409 uintptr_t *newStack = (uintptr_t *)js_realloc(stack_, sizeof(uintptr_t) * newCapacity);
michael@0 410 if (!newStack)
michael@0 411 return false;
michael@0 412
michael@0 413 setStack(newStack, tosIndex, newCapacity);
michael@0 414 return true;
michael@0 415 }
michael@0 416
michael@0 417 void
michael@0 418 MarkStack::setGCMode(JSGCMode gcMode)
michael@0 419 {
michael@0 420 // The mark stack won't be resized until the next call to reset(), but
michael@0 421 // that will happen at the end of the next GC.
michael@0 422 setBaseCapacity(gcMode);
michael@0 423 }
michael@0 424
michael@0 425 size_t
michael@0 426 MarkStack::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
michael@0 427 {
michael@0 428 return mallocSizeOf(stack_);
michael@0 429 }
michael@0 430
michael@0 431 /*
michael@0 432 * DoNotTraceWeakMaps: the GC is recomputing the liveness of WeakMap entries,
michael@0 433 * so we delay visting entries.
michael@0 434 */
michael@0 435 GCMarker::GCMarker(JSRuntime *rt)
michael@0 436 : JSTracer(rt, nullptr, DoNotTraceWeakMaps),
michael@0 437 stack(size_t(-1)),
michael@0 438 color(BLACK),
michael@0 439 unmarkedArenaStackTop(nullptr),
michael@0 440 markLaterArenas(0),
michael@0 441 grayBufferState(GRAY_BUFFER_UNUSED),
michael@0 442 started(false)
michael@0 443 {
michael@0 444 }
michael@0 445
michael@0 446 bool
michael@0 447 GCMarker::init(JSGCMode gcMode)
michael@0 448 {
michael@0 449 return stack.init(gcMode);
michael@0 450 }
michael@0 451
michael@0 452 void
michael@0 453 GCMarker::start()
michael@0 454 {
michael@0 455 JS_ASSERT(!started);
michael@0 456 started = true;
michael@0 457 color = BLACK;
michael@0 458
michael@0 459 JS_ASSERT(!unmarkedArenaStackTop);
michael@0 460 JS_ASSERT(markLaterArenas == 0);
michael@0 461
michael@0 462 }
michael@0 463
michael@0 464 void
michael@0 465 GCMarker::stop()
michael@0 466 {
michael@0 467 JS_ASSERT(isDrained());
michael@0 468
michael@0 469 JS_ASSERT(started);
michael@0 470 started = false;
michael@0 471
michael@0 472 JS_ASSERT(!unmarkedArenaStackTop);
michael@0 473 JS_ASSERT(markLaterArenas == 0);
michael@0 474
michael@0 475 /* Free non-ballast stack memory. */
michael@0 476 stack.reset();
michael@0 477
michael@0 478 resetBufferedGrayRoots();
michael@0 479 grayBufferState = GRAY_BUFFER_UNUSED;
michael@0 480 }
michael@0 481
michael@0 482 void
michael@0 483 GCMarker::reset()
michael@0 484 {
michael@0 485 color = BLACK;
michael@0 486
michael@0 487 stack.reset();
michael@0 488 JS_ASSERT(isMarkStackEmpty());
michael@0 489
michael@0 490 while (unmarkedArenaStackTop) {
michael@0 491 ArenaHeader *aheader = unmarkedArenaStackTop;
michael@0 492 JS_ASSERT(aheader->hasDelayedMarking);
michael@0 493 JS_ASSERT(markLaterArenas);
michael@0 494 unmarkedArenaStackTop = aheader->getNextDelayedMarking();
michael@0 495 aheader->unsetDelayedMarking();
michael@0 496 aheader->markOverflow = 0;
michael@0 497 aheader->allocatedDuringIncremental = 0;
michael@0 498 markLaterArenas--;
michael@0 499 }
michael@0 500 JS_ASSERT(isDrained());
michael@0 501 JS_ASSERT(!markLaterArenas);
michael@0 502 }
michael@0 503
michael@0 504 void
michael@0 505 GCMarker::markDelayedChildren(ArenaHeader *aheader)
michael@0 506 {
michael@0 507 if (aheader->markOverflow) {
michael@0 508 bool always = aheader->allocatedDuringIncremental;
michael@0 509 aheader->markOverflow = 0;
michael@0 510
michael@0 511 for (CellIterUnderGC i(aheader); !i.done(); i.next()) {
michael@0 512 Cell *t = i.getCell();
michael@0 513 if (always || t->isMarked()) {
michael@0 514 t->markIfUnmarked();
michael@0 515 JS_TraceChildren(this, t, MapAllocToTraceKind(aheader->getAllocKind()));
michael@0 516 }
michael@0 517 }
michael@0 518 } else {
michael@0 519 JS_ASSERT(aheader->allocatedDuringIncremental);
michael@0 520 PushArena(this, aheader);
michael@0 521 }
michael@0 522 aheader->allocatedDuringIncremental = 0;
michael@0 523 /*
michael@0 524 * Note that during an incremental GC we may still be allocating into
michael@0 525 * aheader. However, prepareForIncrementalGC sets the
michael@0 526 * allocatedDuringIncremental flag if we continue marking.
michael@0 527 */
michael@0 528 }
michael@0 529
michael@0 530 bool
michael@0 531 GCMarker::markDelayedChildren(SliceBudget &budget)
michael@0 532 {
michael@0 533 gcstats::MaybeAutoPhase ap;
michael@0 534 if (runtime()->gcIncrementalState == MARK)
michael@0 535 ap.construct(runtime()->gcStats, gcstats::PHASE_MARK_DELAYED);
michael@0 536
michael@0 537 JS_ASSERT(unmarkedArenaStackTop);
michael@0 538 do {
michael@0 539 /*
michael@0 540 * If marking gets delayed at the same arena again, we must repeat
michael@0 541 * marking of its things. For that we pop arena from the stack and
michael@0 542 * clear its hasDelayedMarking flag before we begin the marking.
michael@0 543 */
michael@0 544 ArenaHeader *aheader = unmarkedArenaStackTop;
michael@0 545 JS_ASSERT(aheader->hasDelayedMarking);
michael@0 546 JS_ASSERT(markLaterArenas);
michael@0 547 unmarkedArenaStackTop = aheader->getNextDelayedMarking();
michael@0 548 aheader->unsetDelayedMarking();
michael@0 549 markLaterArenas--;
michael@0 550 markDelayedChildren(aheader);
michael@0 551
michael@0 552 budget.step(150);
michael@0 553 if (budget.isOverBudget())
michael@0 554 return false;
michael@0 555 } while (unmarkedArenaStackTop);
michael@0 556 JS_ASSERT(!markLaterArenas);
michael@0 557
michael@0 558 return true;
michael@0 559 }
michael@0 560
michael@0 561 #ifdef DEBUG
michael@0 562 void
michael@0 563 GCMarker::checkZone(void *p)
michael@0 564 {
michael@0 565 JS_ASSERT(started);
michael@0 566 DebugOnly<Cell *> cell = static_cast<Cell *>(p);
michael@0 567 JS_ASSERT_IF(cell->isTenured(), cell->tenuredZone()->isCollecting());
michael@0 568 }
michael@0 569 #endif
michael@0 570
michael@0 571 bool
michael@0 572 GCMarker::hasBufferedGrayRoots() const
michael@0 573 {
michael@0 574 return grayBufferState == GRAY_BUFFER_OK;
michael@0 575 }
michael@0 576
michael@0 577 void
michael@0 578 GCMarker::startBufferingGrayRoots()
michael@0 579 {
michael@0 580 JS_ASSERT(grayBufferState == GRAY_BUFFER_UNUSED);
michael@0 581 grayBufferState = GRAY_BUFFER_OK;
michael@0 582 for (GCZonesIter zone(runtime()); !zone.done(); zone.next())
michael@0 583 JS_ASSERT(zone->gcGrayRoots.empty());
michael@0 584
michael@0 585 JS_ASSERT(!callback);
michael@0 586 callback = GrayCallback;
michael@0 587 JS_ASSERT(IS_GC_MARKING_TRACER(this));
michael@0 588 }
michael@0 589
michael@0 590 void
michael@0 591 GCMarker::endBufferingGrayRoots()
michael@0 592 {
michael@0 593 JS_ASSERT(callback == GrayCallback);
michael@0 594 callback = nullptr;
michael@0 595 JS_ASSERT(IS_GC_MARKING_TRACER(this));
michael@0 596 JS_ASSERT(grayBufferState == GRAY_BUFFER_OK ||
michael@0 597 grayBufferState == GRAY_BUFFER_FAILED);
michael@0 598 }
michael@0 599
michael@0 600 void
michael@0 601 GCMarker::resetBufferedGrayRoots()
michael@0 602 {
michael@0 603 for (GCZonesIter zone(runtime()); !zone.done(); zone.next())
michael@0 604 zone->gcGrayRoots.clearAndFree();
michael@0 605 }
michael@0 606
michael@0 607 void
michael@0 608 GCMarker::markBufferedGrayRoots(JS::Zone *zone)
michael@0 609 {
michael@0 610 JS_ASSERT(grayBufferState == GRAY_BUFFER_OK);
michael@0 611 JS_ASSERT(zone->isGCMarkingGray());
michael@0 612
michael@0 613 for (GrayRoot *elem = zone->gcGrayRoots.begin(); elem != zone->gcGrayRoots.end(); elem++) {
michael@0 614 #ifdef DEBUG
michael@0 615 setTracingDetails(elem->debugPrinter, elem->debugPrintArg, elem->debugPrintIndex);
michael@0 616 #endif
michael@0 617 void *tmp = elem->thing;
michael@0 618 setTracingLocation((void *)&elem->thing);
michael@0 619 MarkKind(this, &tmp, elem->kind);
michael@0 620 JS_ASSERT(tmp == elem->thing);
michael@0 621 }
michael@0 622 }
michael@0 623
michael@0 624 void
michael@0 625 GCMarker::appendGrayRoot(void *thing, JSGCTraceKind kind)
michael@0 626 {
michael@0 627 JS_ASSERT(started);
michael@0 628
michael@0 629 if (grayBufferState == GRAY_BUFFER_FAILED)
michael@0 630 return;
michael@0 631
michael@0 632 GrayRoot root(thing, kind);
michael@0 633 #ifdef DEBUG
michael@0 634 root.debugPrinter = debugPrinter();
michael@0 635 root.debugPrintArg = debugPrintArg();
michael@0 636 root.debugPrintIndex = debugPrintIndex();
michael@0 637 #endif
michael@0 638
michael@0 639 Zone *zone = static_cast<Cell *>(thing)->tenuredZone();
michael@0 640 if (zone->isCollecting()) {
michael@0 641 zone->maybeAlive = true;
michael@0 642 if (!zone->gcGrayRoots.append(root)) {
michael@0 643 resetBufferedGrayRoots();
michael@0 644 grayBufferState = GRAY_BUFFER_FAILED;
michael@0 645 }
michael@0 646 }
michael@0 647 }
michael@0 648
michael@0 649 void
michael@0 650 GCMarker::GrayCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind)
michael@0 651 {
michael@0 652 JS_ASSERT(thingp);
michael@0 653 JS_ASSERT(*thingp);
michael@0 654 GCMarker *gcmarker = static_cast<GCMarker *>(trc);
michael@0 655 gcmarker->appendGrayRoot(*thingp, kind);
michael@0 656 }
michael@0 657
michael@0 658 size_t
michael@0 659 GCMarker::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
michael@0 660 {
michael@0 661 size_t size = stack.sizeOfExcludingThis(mallocSizeOf);
michael@0 662 for (ZonesIter zone(runtime(), WithAtoms); !zone.done(); zone.next())
michael@0 663 size += zone->gcGrayRoots.sizeOfExcludingThis(mallocSizeOf);
michael@0 664 return size;
michael@0 665 }
michael@0 666
michael@0 667 void
michael@0 668 js::SetMarkStackLimit(JSRuntime *rt, size_t limit)
michael@0 669 {
michael@0 670 JS_ASSERT(!rt->isHeapBusy());
michael@0 671 AutoStopVerifyingBarriers pauseVerification(rt, false);
michael@0 672 rt->gcMarker.setMaxCapacity(limit);
michael@0 673 }
michael@0 674

mercurial