diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 67c983a880b1..28171bfad725 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -619,30 +619,6 @@ JSPropertyDescriptor::trace(JSTracer *trc) } } -static inline void -MarkGlobalForMinorGC(JSTracer *trc, JSCompartment *compartment) -{ -#ifdef JS_ION - /* - * Named properties of globals which have had Ion activity are treated as - * roots during minor GCs. This allows writes to globals to occur without - * needing a write barrier. - */ - JS_ASSERT(trc->runtime->isHeapMinorCollecting()); - - if (!compartment->ionCompartment()) - return; - - GlobalObject *global = compartment->maybeGlobal(); - if (!global) - return; - - /* Global reserved slots never hold nursery things. */ - for (size_t i = JSCLASS_RESERVED_SLOTS(global->getClass()); i < global->slotSpan(); ++i) - MarkValueRoot(trc, global->nativeGetSlotRef(i).unsafeGet(), "MinorGlobalRoot"); -#endif /* JS_ION */ -} - void js::gc::MarkRuntime(JSTracer *trc, bool useSavedRoots) { @@ -726,12 +702,12 @@ js::gc::MarkRuntime(JSTracer *trc, bool useSavedRoots) /* We can't use GCCompartmentsIter if we're called from TraceRuntime. */ for (CompartmentsIter c(rt); !c.done(); c.next()) { + if (trc->runtime->isHeapMinorCollecting()) + c->globalWriteBarriered = false; + if (IS_GC_MARKING_TRACER(trc) && !c->zone()->isCollecting()) continue; - if (trc->runtime->isHeapMinorCollecting()) - MarkGlobalForMinorGC(trc, c); - /* During a GC, these are treated as weak pointers. */ if (!IS_GC_MARKING_TRACER(trc)) { if (c->watchpointMap) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index d1a44d0e0c25..99e47c095f7c 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1440,9 +1440,12 @@ CodeGenerator::visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier regs.add(CallTempReg2); Register objreg; + bool isGlobal = false; if (obj->isConstant()) { + JSObject *object = &obj->toConstant()->toObject(); + isGlobal = object->is(); objreg = regs.takeAny(); - masm.movePtr(ImmGCPtr(&obj->toConstant()->toObject()), objreg); + masm.movePtr(ImmGCPtr(object), objreg); } else { objreg = ToRegister(obj); regs.takeUnchecked(objreg); @@ -1451,10 +1454,11 @@ CodeGenerator::visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier Register runtimereg = regs.takeAny(); masm.mov(ImmPtr(GetIonContext()->runtime), runtimereg); + void (*fun)(JSRuntime*, JSObject*) = isGlobal ? PostGlobalWriteBarrier : PostWriteBarrier; masm.setupUnalignedABICall(2, regs.takeAny()); masm.passABIArg(runtimereg); masm.passABIArg(objreg); - masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, PostWriteBarrier)); + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, fun)); restoreLive(ool->lir()); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 466ffcef744b..5e7b19ba4e5c 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -6423,9 +6423,7 @@ IonBuilder::setStaticName(JSObject *staticObject, PropertyName *name) if (!propertyTypes) obj = addShapeGuard(obj, staticObject->lastProperty(), Bailout_ShapeGuard); - // Note: we do not use a post barrier when writing to the global object. - // Slots in the global object will be treated as roots during a minor GC. - if (!staticObject->is() && NeedsPostBarrier(info(), value)) + if (NeedsPostBarrier(info(), value)) current->add(MPostWriteBarrier::New(obj, value)); // If the property has a known type, we may be able to optimize typed stores by not diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 3a6a10585106..618c6a945478 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -631,6 +631,16 @@ PostWriteBarrier(JSRuntime *rt, JSObject *obj) JS_ASSERT(!IsInsideNursery(rt, obj)); rt->gcStoreBuffer.putWholeCell(obj); } + +void +PostGlobalWriteBarrier(JSRuntime *rt, JSObject *obj) +{ + JS_ASSERT(obj->is()); + if (!obj->compartment()->globalWriteBarriered) { + PostWriteBarrier(rt, obj); + obj->compartment()->globalWriteBarriered = true; + } +} #endif uint32_t diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index d50c2cc9b872..2516ea28e754 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -641,6 +641,7 @@ bool FilterArguments(JSContext *cx, JSString *str); #ifdef JSGC_GENERATIONAL void PostWriteBarrier(JSRuntime *rt, JSObject *obj); +void PostGlobalWriteBarrier(JSRuntime *rt, JSObject *obj); #endif uint32_t GetIndexFromString(JSString *str); diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 7ddfec03cf12..688c11bf4f5c 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -52,6 +52,7 @@ JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options = lastAnimationTime(0), regExps(runtime_), typeReprs(runtime_), + globalWriteBarriered(false), propertyTree(thisForCtor()), gcIncomingGrayPointers(NULL), gcLiveArrayBuffers(NULL), diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index dc00edff58cd..114080777bc3 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -206,6 +206,15 @@ struct JSCompartment /* Set of all currently living type representations. */ js::TypeRepresentationHash typeReprs; + /* + * For generational GC, record whether a write barrier has added this + * compartment's global to the store buffer since the last minor GC. + * + * This is used to avoid adding it to the store buffer on every write, which + * can quickly fill the buffer and also cause performance problems. + */ + bool globalWriteBarriered; + private: void sizeOfTypeInferenceData(JS::TypeInferenceSizes *stats, mozilla::MallocSizeOf mallocSizeOf);