Bug 1312525 - Always trigger the pre-barrier when setting an unlazified script r=sfink a=gchang
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 02 Nov 2016 11:11:14 +0000
changeset 356428 1a8ed7ba82adecdd095ae3d7d99bcf672ef7e976
parent 356427 ffae4aede5a1ed6c8374af2b443b701714576119
child 356429 f29e3dc3f53e186ff2822be1d28f50b2e76853d2
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink, gchang
bugs1312525
milestone51.0a2
Bug 1312525 - Always trigger the pre-barrier when setting an unlazified script r=sfink a=gchang
js/src/gc/Verifier.cpp
js/src/jsfun.cpp
js/src/jsfun.h
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -289,32 +289,29 @@ CheckEdgeTracer::onChild(const JS::GCCel
 
 void
 js::gc::AssertSafeToSkipBarrier(TenuredCell* thing)
 {
     Zone* zone = thing->zoneFromAnyThread();
     MOZ_ASSERT(!zone->needsIncrementalBarrier() || zone->isAtomsZone());
 }
 
-static void
-AssertMarkedOrAllocated(const EdgeValue& edge)
+static bool
+IsMarkedOrAllocated(const EdgeValue& edge)
 {
     if (!edge.thing || IsMarkedOrAllocated(TenuredCell::fromPointer(edge.thing)))
-        return;
+        return true;
 
     // Permanent atoms and well-known symbols aren't marked during graph traversal.
     if (edge.kind == JS::TraceKind::String && static_cast<JSString*>(edge.thing)->isPermanentAtom())
-        return;
+        return true;
     if (edge.kind == JS::TraceKind::Symbol && static_cast<JS::Symbol*>(edge.thing)->isWellKnownSymbol())
-        return;
+        return true;
 
-    char msgbuf[1024];
-    SprintfLiteral(msgbuf, "[barrier verifier] Unmarked edge: %s", edge.label);
-    MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
-    MOZ_CRASH();
+    return false;
 }
 
 void
 gc::GCRuntime::endVerifyPreBarriers()
 {
     VerifyPreTracer* trc = verifyPreData;
 
     if (!trc)
@@ -350,18 +347,29 @@ gc::GCRuntime::endVerifyPreBarriers()
 
         /* Start after the roots. */
         VerifyNode* node = NextNode(trc->root);
         while ((char*)node < trc->edgeptr) {
             cetrc.node = node;
             js::TraceChildren(&cetrc, node->thing, node->kind);
 
             if (node->count <= MAX_VERIFIER_EDGES) {
-                for (uint32_t i = 0; i < node->count; i++)
-                    AssertMarkedOrAllocated(node->edges[i]);
+                for (uint32_t i = 0; i < node->count; i++) {
+                    EdgeValue& edge = node->edges[i];
+                    if (!IsMarkedOrAllocated(edge)) {
+                        char msgbuf[1024];
+                        SprintfLiteral(msgbuf,
+                                       "[barrier verifier] Unmarked edge: %s %p '%s' edge to %s %p",
+                                       JS::GCTraceKindToAscii(node->kind), node->thing,
+                                       edge.label,
+                                       JS::GCTraceKindToAscii(edge.kind), edge.thing);
+                        MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
+                        MOZ_CRASH();
+                    }
+                }
             }
 
             node = NextNode(node);
         }
     }
 
     marker.reset();
     marker.stop();
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1418,20 +1418,16 @@ JSFunction::getBoundFunctionArgumentCoun
 
 /* static */ bool
 JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFunction fun)
 {
     MOZ_ASSERT(fun->isInterpretedLazy());
 
     Rooted<LazyScript*> lazy(cx, fun->lazyScriptOrNull());
     if (lazy) {
-        // Trigger a pre barrier on the lazy script being overwritten.
-        if (cx->zone()->needsIncrementalBarrier())
-            LazyScript::writeBarrierPre(lazy);
-
         RootedScript script(cx, lazy->maybeScript());
 
         // Only functions without inner functions or direct eval are
         // re-lazified. Functions with either of those are on the static scope
         // chain of their inner functions, or in the case of eval, possibly
         // eval'd inner functions. This prohibits re-lazification as
         // StaticScopeIter queries needsCallObject of those functions, which
         // requires a non-lazy script.  Note that if this ever changes,
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -469,21 +469,23 @@ class JSFunction : public js::NativeObje
         mutableScript() = script_;
     }
 
     void initScript(JSScript* script_) {
         mutableScript().init(script_);
     }
 
     void setUnlazifiedScript(JSScript* script) {
-        // Note: createScriptForLazilyInterpretedFunction triggers a barrier on
-        // lazy script before it is overwritten here.
         MOZ_ASSERT(isInterpretedLazy());
-        if (lazyScriptOrNull() && !lazyScript()->maybeScript())
-            lazyScript()->initScript(script);
+        if (lazyScriptOrNull()) {
+            // Trigger a pre barrier on the lazy script being overwritten.
+            js::LazyScript::writeBarrierPre(lazyScriptOrNull());
+            if (!lazyScript()->maybeScript())
+                lazyScript()->initScript(script);
+        }
         flags_ &= ~INTERPRETED_LAZY;
         flags_ |= INTERPRETED;
         initScript(script);
     }
 
     void initLazyScript(js::LazyScript* lazy) {
         MOZ_ASSERT(isInterpreted());
         flags_ &= ~INTERPRETED;