Bug 1075488 - Set the frame pointer on RInstructionResults for lookup. r=h4writer
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Fri, 03 Oct 2014 14:33:08 +0200
changeset 231903 0b063dbaf154328b6cbf3227f7b8e19092874db7
parent 231902 6ebee67371f43f5942ae4de4be6de58428131e50
child 231904 418296d647693fa0bd1802e39f22c596f41f4a4f
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs1075488
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1075488 - Set the frame pointer on RInstructionResults for lookup. r=h4writer
js/src/jit/BaselineBailouts.cpp
js/src/jit/IonFrames.cpp
js/src/jit/JitFrameIterator.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -384,17 +384,17 @@ struct BaselineStackBuilder
 // ahead of the bailout.
 class SnapshotIteratorForBailout : public SnapshotIterator
 {
     RInstructionResults results_;
   public:
 
     SnapshotIteratorForBailout(const IonBailoutIterator &iter)
       : SnapshotIterator(iter),
-        results_()
+        results_(iter.jsFrame())
     {
     }
 
     // Take previously computed result out of the activation, or compute the
     // results of all recover instructions contained in the snapshot.
     bool init(JSContext *cx, JitActivation *activation) {
         activation->maybeTakeIonFrameRecovery(fp_, &results_);
         if (!results_.isInitialized() && !computeInstructionResults(cx, &results_))
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -1432,27 +1432,29 @@ uint32_t
 OsiIndex::returnPointDisplacement() const
 {
     // In general, pointer arithmetic on code is bad, but in this case,
     // getting the return address from a call instruction, stepping over pools
     // would be wrong.
     return callPointDisplacement_ + Assembler::PatchWrite_NearCallSize();
 }
 
-RInstructionResults::RInstructionResults()
+RInstructionResults::RInstructionResults(IonJSFrameLayout *fp)
   : results_(nullptr),
-    fp_(nullptr)
+    fp_(fp),
+    initialized_(false)
 {
 }
 
 RInstructionResults::RInstructionResults(RInstructionResults&& src)
   : results_(mozilla::Move(src.results_)),
-    fp_(src.fp_)
+    fp_(src.fp_),
+    initialized_(src.initialized_)
 {
-    src.fp_ = nullptr;
+    src.initialized_ = false;
 }
 
 RInstructionResults&
 RInstructionResults::operator=(RInstructionResults&& rhs)
 {
     MOZ_ASSERT(&rhs != this, "self-moves are prohibited");
     this->~RInstructionResults();
     new(this) RInstructionResults(mozilla::Move(rhs));
@@ -1460,43 +1462,42 @@ RInstructionResults::operator=(RInstruct
 }
 
 RInstructionResults::~RInstructionResults()
 {
     // results_ is freed by the UniquePtr.
 }
 
 bool
-RInstructionResults::init(JSContext *cx, uint32_t numResults, IonJSFrameLayout *fp)
+RInstructionResults::init(JSContext *cx, uint32_t numResults)
 {
     if (numResults) {
         results_ = cx->make_unique<Values>();
         if (!results_ || !results_->growBy(numResults))
             return false;
 
         Value guard = MagicValue(JS_ION_BAILOUT);
         for (size_t i = 0; i < numResults; i++)
             (*results_)[i].init(guard);
     }
 
-    fp_ = fp;
+    initialized_ = true;
     return true;
 }
 
 bool
 RInstructionResults::isInitialized() const
 {
-    MOZ_ASSERT_IF(results_, fp_);
-    return fp_;
+    return initialized_;
 }
 
 IonJSFrameLayout *
 RInstructionResults::frame() const
 {
-    MOZ_ASSERT(isInitialized());
+    MOZ_ASSERT(fp_);
     return fp_;
 }
 
 RelocatableValue&
 RInstructionResults::operator [](size_t index)
 {
     return (*results_)[index];
 }
@@ -1793,19 +1794,18 @@ SnapshotIterator::initInstructionResults
         // support for Argument objects.
         if (!ionScript_->invalidate(cx, /* resetUses = */ false, "Observe recovered instruction."))
             return false;
 
         // Register the list of result on the activation.  We need to do that
         // before we initialize the list such as if any recover instruction
         // cause a GC, we can ensure that the results are properly traced by the
         // activation.
-        RInstructionResults tmp;
-        if (!fallback.activation->registerIonFrameRecovery(fallback.frame->jsFrame(),
-                                                           mozilla::Move(tmp)))
+        RInstructionResults tmp(fallback.frame->jsFrame());
+        if (!fallback.activation->registerIonFrameRecovery(mozilla::Move(tmp)))
             return false;
 
         results = fallback.activation->maybeIonFrameRecovery(fp);
 
         // Start a new snapshot at the beginning of the JitFrameIterator.  This
         // SnapshotIterator is used for evaluating the content of all recover
         // instructions.  The result is then saved on the JitActivation.
         SnapshotIterator s(*fallback.frame);
@@ -1827,17 +1827,17 @@ bool
 SnapshotIterator::computeInstructionResults(JSContext *cx, RInstructionResults *results) const
 {
     MOZ_ASSERT(!results->isInitialized());
     MOZ_ASSERT(recover_.numInstructionsRead() == 1);
 
     // The last instruction will always be a resume point.
     size_t numResults = recover_.numInstructions() - 1;
     if (!results->isInitialized()) {
-        if (!results->init(cx, numResults, fp_))
+        if (!results->init(cx, numResults))
             return false;
 
         // No need to iterate over the only resume point.
         if (!numResults) {
             MOZ_ASSERT(results->isInitialized());
             return true;
         }
 
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -271,25 +271,30 @@ class RInstructionResults
     // Vector of results of recover instructions.
     typedef mozilla::Vector<RelocatableValue, 1, SystemAllocPolicy> Values;
     mozilla::UniquePtr<Values, JS::DeletePolicy<Values> > results_;
 
     // The frame pointer is used as a key to check if the current frame already
     // bailed out.
     IonJSFrameLayout *fp_;
 
+    // Record if we tried and succeed at allocating and filling the vector of
+    // recover instruction results, if needed.  This flag is needed in order to
+    // avoid evaluating the recover instruction twice.
+    bool initialized_;
+
   public:
-    RInstructionResults();
+    RInstructionResults(IonJSFrameLayout *fp);
     RInstructionResults(RInstructionResults&& src);
 
     RInstructionResults& operator=(RInstructionResults&& rhs);
 
     ~RInstructionResults();
 
-    bool init(JSContext *cx, uint32_t numResults, IonJSFrameLayout *fp);
+    bool init(JSContext *cx, uint32_t numResults);
     bool isInitialized() const;
 
     IonJSFrameLayout *frame() const;
 
     RelocatableValue& operator[](size_t index);
 
     void trace(JSTracer *trc);
 };
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1547,24 +1547,20 @@ jit::JitActivation::markRematerializedFr
 {
     if (!rematerializedFrames_)
         return;
     for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront())
         RematerializedFrame::MarkInVector(trc, e.front().value());
 }
 
 bool
-jit::JitActivation::registerIonFrameRecovery(IonJSFrameLayout *fp, RInstructionResults&& results)
+jit::JitActivation::registerIonFrameRecovery(RInstructionResults&& results)
 {
-#ifdef DEBUG
     // Check that there is no entry in the vector yet.
-    RInstructionResults *tmp = maybeIonFrameRecovery(fp);
-    MOZ_ASSERT_IF(tmp, tmp->isInitialized());
-#endif
-
+    MOZ_ASSERT(!maybeIonFrameRecovery(results.frame()));
     if (!ionRecovery_.append(mozilla::Move(results)))
         return false;
 
     return true;
 }
 
 jit::RInstructionResults *
 jit::JitActivation::maybeIonFrameRecovery(IonJSFrameLayout *fp)
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1400,17 +1400,17 @@ class JitActivation : public Activation
 
     // Remove a previous rematerialization by fp.
     void removeRematerializedFrame(uint8_t *top);
 
     void markRematerializedFrames(JSTracer *trc);
 
 
     // Register the results of on Ion frame recovery.
-    bool registerIonFrameRecovery(IonJSFrameLayout *fp, RInstructionResults&& results);
+    bool registerIonFrameRecovery(RInstructionResults&& results);
 
     // Return the pointer to the Ion frame recovery, if it is already registered.
     RInstructionResults *maybeIonFrameRecovery(IonJSFrameLayout *fp);
 
     // If an Ion frame recovery exists for the |fp| frame exists on the
     // activation, then move its content to the |results| argument, and remove
     // it from the activation.
     void maybeTakeIonFrameRecovery(IonJSFrameLayout *fp, RInstructionResults *results);