Bug 810824 - Fix frame iteration to handle baseline frames. r=djvj
authorJan de Mooij <jdemooij@mozilla.com>
Tue, 13 Nov 2012 14:57:33 +0100
changeset 112745 9af743a5b908864e170751dbd54f8ac0e1ccf8fa
parent 112744 ba510446fef6ffbf32bc2bca92e414c7f0b3f603
child 112746 7c9cfaafa4a18647049e356e5404195b61a3f17f
push id1353
push userjandemooij@gmail.com
push dateTue, 13 Nov 2012 14:16:43 +0000
reviewersdjvj
bugs810824
milestone19.0a1
Bug 810824 - Fix frame iteration to handle baseline frames. r=djvj
js/src/ion/BaselineJIT.cpp
js/src/ion/BaselineJIT.h
js/src/ion/IonFrameIterator.h
js/src/ion/IonFrames.cpp
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/ion/BaselineJIT.cpp
+++ b/js/src/ion/BaselineJIT.cpp
@@ -263,16 +263,24 @@ BaselineScript::icEntryFromReturnOffset(
         if (entry.returnOffset().offset() == returnOffset.offset())
             return entry;
     }
 
     JS_NOT_REACHED("No cache");
     return icEntry(0);
 }
 
+ICEntry &
+BaselineScript::icEntryFromReturnAddress(uint8_t *returnAddr)
+{
+    JS_ASSERT(returnAddr > method_->raw());
+    CodeOffsetLabel offset(returnAddr - method_->raw());
+    return icEntryFromReturnOffset(offset);
+}
+
 void
 BaselineScript::copyICEntries(const ICEntry *entries, MacroAssembler &masm)
 {
     // Fix up the return offset in the IC entries and copy them in.
     // Also write out the IC entry ptrs in any fallback stubs that were added.
     for (uint32_t i = 0; i < numICEntries(); i++) {
         ICEntry &realEntry = icEntry(i);
         realEntry = entries[i];
--- a/js/src/ion/BaselineJIT.h
+++ b/js/src/ion/BaselineJIT.h
@@ -51,16 +51,17 @@ struct BaselineScript
     }
     void setMethod(IonCode *code) {
         //JS_ASSERT(!invalidated());
         method_ = code;
     }
 
     ICEntry &icEntry(size_t index);
     ICEntry &icEntryFromReturnOffset(CodeOffsetLabel returnOffset);
+    ICEntry &icEntryFromReturnAddress(uint8_t *returnAddr);
 
     size_t numICEntries() const {
         return icEntries_;
     }
 
     void copyICEntries(const ICEntry *entries, MacroAssembler &masm);
 };
 
--- a/js/src/ion/IonFrameIterator.h
+++ b/js/src/ion/IonFrameIterator.h
@@ -133,16 +133,17 @@ class IonFrameIterator
 
     bool isEntryJSFrame() const;
 
     void *calleeToken() const;
     JSFunction *callee() const;
     JSFunction *maybeCallee() const;
     unsigned numActualArgs() const;
     JSScript *script() const;
+    void baselineScriptAndPc(MutableHandleScript scriptRes, jsbytecode **pcRes) const;
     Value *nativeVp() const;
     Value *actualArgs() const;
 
     // Returns the return address of the frame above this one (that is, the
     // return address that returns back to the current frame).
     uint8 *returnAddressToFp() const {
         return returnAddressToFp_;
     }
--- a/js/src/ion/IonFrames.cpp
+++ b/js/src/ion/IonFrames.cpp
@@ -5,16 +5,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Ion.h"
 #include "IonFrames.h"
 #include "jsobj.h"
 #include "jsscript.h"
 #include "jsfun.h"
+#include "BaselineJIT.h"
+#include "BaselineIC.h"
 #include "IonCompartment.h"
 #include "IonFrames-inl.h"
 #include "IonFrameIterator-inl.h"
 #include "Safepoints.h"
 #include "IonSpewer.h"
 #include "IonMacroAssembler.h"
 #include "PcScriptCache.h"
 #include "PcScriptCache-inl.h"
@@ -160,16 +162,26 @@ IonFrameIterator::script() const
 {
     AutoAssertNoGC nogc;
     JS_ASSERT(isScripted());
     RawScript script = ScriptFromCalleeToken(calleeToken());
     JS_ASSERT(script);
     return script;
 }
 
+void
+IonFrameIterator::baselineScriptAndPc(MutableHandleScript scriptRes, jsbytecode **pcRes) const
+{
+    AutoAssertNoGC nogc;
+    JS_ASSERT(isBaselineJS());
+    scriptRes.set(script());
+    uint8_t *retAddr = returnAddressToFp();
+    *pcRes = scriptRes->baseline->icEntryFromReturnAddress(retAddr).pc(scriptRes);
+}
+
 Value *
 IonFrameIterator::nativeVp() const
 {
     JS_ASSERT(isNative());
     return exitFrame()->nativeExit()->vp();
 }
 
 Value *
@@ -691,26 +703,33 @@ ion::GetPcScript(JSContext *cx, MutableH
     }
 
     // Attempt to lookup address in cache.
     if (rt->ionPcScriptCache && rt->ionPcScriptCache->get(rt, hash, retAddr, scriptRes, pcRes))
         return;
 
     // Lookup failed: undertake expensive process to recover the innermost inlined frame.
     ++it; // Skip exit frame.
-    InlineFrameIterator ifi(&it);
+    jsbytecode *pc = NULL;
 
-    // Set the result.
-    scriptRes.set(ifi.script());
+    if (it.isOptimizedJS()) {
+        InlineFrameIterator ifi(&it);
+        scriptRes.set(ifi.script());
+        pc = ifi.pc();
+    } else {
+        JS_ASSERT(it.isBaselineJS());
+        it.baselineScriptAndPc(scriptRes, &pc);
+    }
+
     if (pcRes)
-        *pcRes = ifi.pc();
+        *pcRes = pc;
 
     // Add entry to cache.
     if (rt->ionPcScriptCache)
-        rt->ionPcScriptCache->add(hash, retAddr, ifi.pc(), ifi.script());
+        rt->ionPcScriptCache->add(hash, retAddr, pc, scriptRes);
 }
 
 void
 OsiIndex::fixUpOffset(MacroAssembler &masm)
 {
     callPointDisplacement_ = masm.actualOffset(callPointDisplacement_);
 }
 
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1365,19 +1365,17 @@ StackIter::settleOnNewState()
                 // may have an empty Ion activation.
                 if (ionFrames_.done()) {
                     state_ = SCRIPTED;
                     script_ = fp_->script();
                     return;
                 }
 
                 state_ = ION;
-                ionInlineFrames_ = ion::InlineFrameIterator(&ionFrames_);
-                pc_ = ionInlineFrames_.pc();
-                script_ = ionInlineFrames_.script();
+                nextIonFrame();
                 return;
             }
 #endif /* JS_ION */
 
             state_ = SCRIPTED;
             script_ = fp_->script();
             return;
         }
@@ -1464,34 +1462,45 @@ StackIter::StackIter(const StackIter &ot
     ionFrames_(other.ionFrames_),
     ionInlineFrames_(other.ionInlineFrames_)
 #endif
 {
 }
 
 #ifdef JS_ION
 void
+StackIter::nextIonFrame()
+{
+    if (ionFrames_.isOptimizedJS()) {
+        ionInlineFrames_ = ion::InlineFrameIterator(&ionFrames_);
+        pc_ = ionInlineFrames_.pc();
+        script_ = ionInlineFrames_.script();
+    } else {
+        JS_ASSERT(ionFrames_.isBaselineJS());
+        ionFrames_.baselineScriptAndPc(&script_, &pc_);
+    }
+}
+
+void
 StackIter::popIonFrame()
 {
     AutoAssertNoGC nogc;
     // Keep fp which describes all ion frames.
     poisonRegs();
-    if (ionFrames_.isScripted() && ionInlineFrames_.more()) {
+    if (ionFrames_.isOptimizedJS() && ionInlineFrames_.more()) {
         ++ionInlineFrames_;
         pc_ = ionInlineFrames_.pc();
         script_ = ionInlineFrames_.script();
     } else {
         ++ionFrames_;
         while (!ionFrames_.done() && !ionFrames_.isScripted())
             ++ionFrames_;
 
         if (!ionFrames_.done()) {
-            ionInlineFrames_ = ion::InlineFrameIterator(&ionFrames_);
-            pc_ = ionInlineFrames_.pc();
-            script_ = ionInlineFrames_.script();
+            nextIonFrame();
             return;
         }
 
         // The activation has no other frames. If entryfp is NULL, it was invoked
         // by a native written in C++, using FastInvoke, on top of another activation.
         ion::IonActivation *activation = ionActivations_.activation();
         if (!activation->entryfp()) {
             JS_ASSERT(activation->prevpc());
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1736,16 +1736,17 @@ class StackIter
     ion::IonFrameIterator ionFrames_;
     ion::InlineFrameIterator ionInlineFrames_;
 #endif
 
     void poisonRegs();
     void popFrame();
     void popCall();
 #ifdef JS_ION
+    void nextIonFrame();
     void popIonFrame();
 #endif
     void settleOnNewSegment();
     void settleOnNewState();
     void startOnSegment(StackSegment *seg);
 
   public:
     StackIter(JSContext *cx, SavedOption = STOP_AT_SAVED);