Bug 1473830 - Mark OSR TypeBarriers for Null/Undefined/MagicOptimizedArguments as implicitly used, and don't eliminate them during DCE. r=nbp, a=lizzard
authorMatthew Gaudet <mgaudet@mozilla.com>
Thu, 21 Feb 2019 19:07:01 +0000
changeset 516110 d5cdb1c49f3983fb7f84d424f66e86622fce9d0c
parent 516109 197546cf8331433a7428de57a377215867a4250d
child 516111 a548506067f8decdabb5657f947fe28383b48515
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp, lizzard
bugs1473830
milestone66.0
Bug 1473830 - Mark OSR TypeBarriers for Null/Undefined/MagicOptimizedArguments as implicitly used, and don't eliminate them during DCE. r=nbp, a=lizzard Type barriers are marked as Guard instructions, however, in OSR blocks guards are eligible for DCE. However, Null/Undefined/MagicOptimizedArguments have no uses associated with them, and so get optimized out. To prevent that, this patch uses the ImplicitlyUsed flag to indicate to DCE that these barriers are not eligible for elimination. Differential Revision: https://phabricator.services.mozilla.com/D20388
js/src/jit/IonAnalysis.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/MIR.h
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -1281,17 +1281,18 @@ bool jit::EliminateDeadResumePointOperan
 
   return true;
 }
 
 // Test whether |def| would be needed if it had no uses.
 bool js::jit::DeadIfUnused(const MDefinition* def) {
   return !def->isEffectful() &&
          (!def->isGuard() ||
-          def->block() == def->block()->graph().osrBlock()) &&
+          (def->block() == def->block()->graph().osrBlock() &&
+           !def->isImplicitlyUsed())) &&
          !def->isGuardRangeBailouts() && !def->isControlInstruction() &&
          (!def->isInstruction() || !def->toInstruction()->resumePoint());
 }
 
 // Test whether |def| may be safely discarded, due to being dead or due to being
 // located in a basic block which has itself been marked for discarding.
 bool js::jit::IsDiscardable(const MDefinition* def) {
   return !def->hasUses() && (DeadIfUnused(def) || def->block()->isMarked());
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -1326,16 +1326,29 @@ AbortReasonOr<Ok> IonBuilder::addOsrValu
       return abort(AbortReason::Alloc);
     }
     MInstruction* barrier = MTypeBarrier::New(alloc(), def, typeSet);
     osrBlock->insertBefore(osrBlock->lastIns(), barrier);
     osrBlock->rewriteSlot(slot, barrier);
     def = barrier;
   }
 
+  // The following guards aren't directly linked into the usedef chain,
+  // however in the OSR block we need to ensure they're not optimized out, so we
+  // mark them as implicitly used.
+  switch (type) {
+    case MIRType::Null:
+    case MIRType::Undefined:
+    case MIRType::MagicOptimizedArguments:
+      def->setImplicitlyUsed();
+      break;
+    default:
+      break;
+  }
+
   switch (type) {
     case MIRType::Boolean:
     case MIRType::Int32:
     case MIRType::Double:
     case MIRType::String:
     case MIRType::Symbol:
     case MIRType::Object:
       if (type != def->type()) {
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -110,19 +110,21 @@ static inline MIRType MIRTypeFromValue(c
    * GuardRangeBailouts.                                                       \
    *                                                                           \
    * This flag prevents further optimization of instructions, which            \
    * might remove the run-time checks (bailout conditions) used as a           \
    * predicate of the previous transformation.                                 \
    */                                                                          \
   _(GuardRangeBailouts)                                                        \
                                                                                \
-  /* Keep the flagged instruction in resume points and do not substitute this  \
-   * instruction by an UndefinedValue. This might be used by call inlining     \
-   * when a function argument is not used by the inlined instructions.         \
+  /* Some instructions have uses that aren't directly represented in the graph,\
+   * and need to be handled specially. As an example, this is used to keep the \
+   * flagged instruction in resume points, not substituting with an            \
+   * UndefinedValue. This can be used by call inlining when a function argument\
+   * is not used by the inlined instructions.                                  \
    */                                                                          \
   _(ImplicitlyUsed)                                                            \
                                                                                \
   /* The instruction has been marked dead for lazy removal from resume         \
    * points.                                                                   \
    */                                                                          \
   _(Unused)                                                                    \
                                                                                \