Backed out changeset c2429d6c41fb (Bug 1004726) for regressions on B2G, r=me
authorVictor Porof <vporof@mozilla.com>
Mon, 26 May 2014 21:51:50 -0400
changeset 204370 9fa72130d50b7d82771e489399ec321c24c2fc8c
parent 204369 e0180fb7eec1e2af377e1bcdbc166b9b497a620a
child 204371 8588817f7f861d94f5bda0b7333bcb792ed8250f
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs1004726
milestone32.0a1
backs outc2429d6c41fb3b7598136535f4c6fc9428a15e09
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
Backed out changeset c2429d6c41fb (Bug 1004726) for regressions on B2G, r=me
CLOBBER
js/public/ProfilingStack.h
js/src/jit/IonMacroAssembler.cpp
js/src/jit/IonMacroAssembler.h
js/src/jit/arm/MacroAssembler-arm.h
js/src/jit/x64/MacroAssembler-x64.h
js/src/jit/x86/MacroAssembler-x86.h
js/src/vm/SPSProfiler.cpp
js/src/vm/SPSProfiler.h
tools/profiler/BreakpadSampler.cpp
tools/profiler/PseudoStack.h
tools/profiler/TableTicker.cpp
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1004726 requires a clobber for B2G Emulator builds
+Bug 994964 apparently requires a clobber, unclear why
--- a/js/public/ProfilingStack.h
+++ b/js/public/ProfilingStack.h
@@ -3,17 +3,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #ifndef js_ProfilingStack_h
 #define js_ProfilingStack_h
 
 #include "mozilla/NullPtr.h"
-
+ 
 #include "jsbytecode.h"
 #include "jstypes.h"
 
 #include "js/Utility.h"
 
 struct JSRuntime;
 
 namespace js {
@@ -29,107 +29,77 @@ class ProfileEntry
     // instructions. Namely this sequence:
     //
     //    entry[size] = ...;
     //    size++;
     //
     // If the size modification were somehow reordered before the stores, then
     // if a sample were taken it would be examining bogus information.
     //
-    // A ProfileEntry represents both a C++ profile entry and a JS one.
-
-    // Descriptive string of this entry.
-    const char * volatile string;
-
-    // Stack pointer for non-JS entries, the script pointer otherwise.
-    void * volatile spOrScript;
-
-    // Line number for non-JS entries, the bytecode offset otherwise.
-    int32_t volatile lineOrPc;
-
-    // General purpose storage describing this frame.
-    uint32_t volatile flags;
+    // A ProfileEntry represents both a C++ profile entry and a JS one. Both use
+    // the string as a description, but JS uses the sp as nullptr or (void*)1 to
+    // indicate that it is a JS entry. The script_ is then only ever examined for
+    // a JS entry, and the idx is used by both, but with different meanings.
+    //
+    const char * volatile string; // Descriptive string of this entry
+    void * volatile sp;           // Relevant stack pointer for the entry,
+                                  // less than or equal to SCRIPT_OPT_STACKPOINTER for js
+                                  // script entries, greater for non-js entries.
+    JSScript * volatile script_;  // if js(), non-null script which is running - low bit
+                                  // indicates if script is optimized or not.
+    int32_t volatile idx;         // if js(), idx of pc, otherwise line number
 
   public:
-    ProfileEntry(void) : flags(0) {}
-
-    // These traits are bit masks. Make sure they're powers of 2.
-    enum Flags {
-        // Indicate whether a profile entry represents a CPP frame. If not set,
-        // a JS frame is assumed by default. You're not allowed to publicly
-        // change the frame type. Instead, call `setJsFrame` or `setCppFrame`.
-        IS_CPP_ENTRY = 0x01,
-
-        // Indicate that copying the frame label is not necessary when taking a
-        // sample of the pseudostack.
-        FRAME_LABEL_COPY = 0x02
-    };
+    static const uintptr_t SCRIPT_OPT_STACKPOINTER = 0x1;
 
     // All of these methods are marked with the 'volatile' keyword because SPS's
     // representation of the stack is stored such that all ProfileEntry
     // instances are volatile. These methods would not be available unless they
     // were marked as volatile as well.
 
-    bool isCpp() const volatile { return hasFlag(IS_CPP_ENTRY); }
-    bool isJs() const volatile { return !isCpp(); }
-
-    bool isCopyLabel() const volatile { return hasFlag(FRAME_LABEL_COPY); };
-
-    void setLabel(const char *aString) volatile { string = aString; }
-    const char *label() const volatile { return string; }
-
-    void setJsFrame(JSScript *aScript, jsbytecode *aPc) volatile {
-        flags &= ~IS_CPP_ENTRY;
-        spOrScript = aScript;
-        setPC(aPc);
-    }
-    void setCppFrame(void *aSp, uint32_t aLine) volatile {
-        flags |= IS_CPP_ENTRY;
-        spOrScript = aSp;
-        lineOrPc = aLine;
+    bool js() const volatile {
+        MOZ_ASSERT_IF(uintptr_t(sp) <= SCRIPT_OPT_STACKPOINTER, script_ != nullptr);
+        return uintptr_t(sp) <= SCRIPT_OPT_STACKPOINTER;
     }
 
-    void setFlag(Flags flag) volatile {
-        MOZ_ASSERT(flag != IS_CPP_ENTRY);
-        flags |= flag;
+    uint32_t line() const volatile { MOZ_ASSERT(!js()); return idx; }
+    JSScript *script() const volatile { MOZ_ASSERT(js()); return script_; }
+    bool scriptIsOptimized() const volatile {
+        MOZ_ASSERT(js());
+        return uintptr_t(sp) <= SCRIPT_OPT_STACKPOINTER;
     }
-    void unsetFlag(Flags flag) volatile {
-        MOZ_ASSERT(flag != IS_CPP_ENTRY);
-        flags &= ~flag;
+    void *stackAddress() const volatile {
+        if (js())
+            return nullptr;
+        return sp;
     }
-    bool hasFlag(Flags flag) const volatile {
-        return bool(flags & uint32_t(flag));
-    }
+    const char *label() const volatile { return string; }
 
-    void *stackAddress() const volatile {
-        MOZ_ASSERT(!isJs());
-        return spOrScript;
-    }
-    JSScript *script() const volatile {
-        MOZ_ASSERT(isJs());
-        return (JSScript *)spOrScript;
-    }
-    uint32_t line() const volatile {
-        MOZ_ASSERT(!isJs());
-        return lineOrPc;
-    }
+    void setLine(uint32_t aLine) volatile { MOZ_ASSERT(!js()); idx = aLine; }
+    void setLabel(const char *aString) volatile { string = aString; }
+    void setStackAddress(void *aSp) volatile { sp = aSp; }
+    void setScript(JSScript *aScript) volatile { script_ = aScript; }
 
     // We can't know the layout of JSScript, so look in vm/SPSProfiler.cpp.
     JS_FRIEND_API(jsbytecode *) pc() const volatile;
     JS_FRIEND_API(void) setPC(jsbytecode *pc) volatile;
 
-    // The offset of a pc into a script's code can actually be 0, so to
-    // signify a nullptr pc, use a -1 index. This is checked against in
-    // pc() and setPC() to set/get the right pc.
-    static const int32_t NullPCOffset = -1;
+    static size_t offsetOfString() { return offsetof(ProfileEntry, string); }
+    static size_t offsetOfStackAddress() { return offsetof(ProfileEntry, sp); }
+    static size_t offsetOfPCIdx() { return offsetof(ProfileEntry, idx); }
+    static size_t offsetOfScript() { return offsetof(ProfileEntry, script_); }
 
-    static size_t offsetOfLabel() { return offsetof(ProfileEntry, string); }
-    static size_t offsetOfSpOrScript() { return offsetof(ProfileEntry, spOrScript); }
-    static size_t offsetOfLineOrPc() { return offsetof(ProfileEntry, lineOrPc); }
-    static size_t offsetOfFlags() { return offsetof(ProfileEntry, flags); }
+    // The index used in the entry can either be a line number or the offset of
+    // a pc into a script's code. To signify a nullptr pc, use a -1 index. This
+    // is checked against in pc() and setPC() to set/get the right pc.
+    static const int32_t NullPCIndex = -1;
+
+    // This bit is added to the stack address to indicate that copying the
+    // frame label is not necessary when taking a sample of the pseudostack.
+    static const uintptr_t NoCopyBit = 1;
 };
 
 JS_FRIEND_API(void)
 SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size,
                          uint32_t max);
 
 JS_FRIEND_API(void)
 EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled);
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -1937,20 +1937,20 @@ MacroAssembler::spsMarkJit(SPSProfiler *
     push(temp); // +4: Did we push an sps frame.
     branchTest32(Assembler::Equal, temp, temp, &spsNotEnabled);
 
     Label stackFull;
     // We always need the "safe" versions, because these are used in trampolines
     // and won't be regenerated when SPS state changes.
     spsProfileEntryAddressSafe(p, 0, temp, &stackFull);
 
-    storePtr(ImmPtr(enterJitLabel), Address(temp, ProfileEntry::offsetOfLabel()));
-    storePtr(framePtr,              Address(temp, ProfileEntry::offsetOfSpOrScript()));
-    store32(Imm32(ProfileEntry::NullPCOffset), Address(temp, ProfileEntry::offsetOfLineOrPc()));
-    store32(Imm32(ProfileEntry::IS_CPP_ENTRY), Address(temp, ProfileEntry::offsetOfFlags()));
+    storePtr(ImmPtr(enterJitLabel), Address(temp, ProfileEntry::offsetOfString()));
+    storePtr(framePtr,              Address(temp, ProfileEntry::offsetOfStackAddress()));
+    storePtr(ImmWord(uintptr_t(0)), Address(temp, ProfileEntry::offsetOfScript()));
+    store32(Imm32(ProfileEntry::NullPCIndex), Address(temp, ProfileEntry::offsetOfPCIdx()));
 
     /* Always increment the stack size, whether or not we actually pushed. */
     bind(&stackFull);
     loadPtr(AbsoluteAddress(p->addressOfSizePointer()), temp);
     add32(Imm32(1), Address(temp, 0));
 
     bind(&spsNotEnabled);
 }
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -1011,24 +1011,19 @@ class MacroAssembler : public MacroAssem
                                 Label *full)
     {
         movePtr(ImmPtr(p->sizePointer()), temp);
         load32(Address(temp, 0), temp);
         if (offset != 0)
             add32(Imm32(offset), temp);
         branch32(Assembler::GreaterThanOrEqual, temp, Imm32(p->maxSize()), full);
 
-        JS_STATIC_ASSERT(sizeof(ProfileEntry) == (2 * sizeof(void *)) + 8);
-        if (sizeof(void *) == 4) {
-            lshiftPtr(Imm32(4), temp);
-        } else {
-            lshiftPtr(Imm32(3), temp);
-            mulBy3(temp, temp);
-        }
-
+        // 4 * sizeof(void*) * idx = idx << (2 + log(sizeof(void*)))
+        JS_STATIC_ASSERT(sizeof(ProfileEntry) == 4 * sizeof(void*));
+        lshiftPtr(Imm32(2 + (sizeof(void*) == 4 ? 2 : 3)), temp);
         addPtr(ImmPtr(p->stack()), temp);
     }
 
     // The safe version of the above method refrains from assuming that the fields
     // of the SPSProfiler class are going to stay the same across different runs of
     // the jitcode.  Ion can use the more efficient unsafe version because ion jitcode
     // will not survive changes to to the profiler settings.  Baseline jitcode, however,
     // can span these changes, so any hardcoded field values will be incorrect afterwards.
@@ -1042,83 +1037,80 @@ class MacroAssembler : public MacroAssem
         // Load size
         load32(Address(temp, 0), temp);
         if (offset != 0)
             add32(Imm32(offset), temp);
 
         // Test against max size.
         branch32(Assembler::LessThanOrEqual, AbsoluteAddress(p->addressOfMaxSize()), temp, full);
 
-        JS_STATIC_ASSERT(sizeof(ProfileEntry) == (2 * sizeof(void *)) + 8);
-        if (sizeof(void *) == 4) {
-            lshiftPtr(Imm32(4), temp);
-        } else {
-            lshiftPtr(Imm32(3), temp);
-            mulBy3(temp, temp);
-        }
-
+        // 4 * sizeof(void*) * idx = idx << (2 + log(sizeof(void*)))
+        JS_STATIC_ASSERT(sizeof(ProfileEntry) == 4 * sizeof(void*));
+        lshiftPtr(Imm32(2 + (sizeof(void*) == 4 ? 2 : 3)), temp);
         push(temp);
         loadPtr(AbsoluteAddress(p->addressOfStack()), temp);
         addPtr(Address(StackPointer, 0), temp);
         addPtr(Imm32(sizeof(size_t)), StackPointer);
     }
 
   public:
     // These functions are needed by the IonInstrumentation interface defined in
     // vm/SPSProfiler.h.  They will modify the pseudostack provided to SPS to
     // perform the actual instrumentation.
 
     void spsUpdatePCIdx(SPSProfiler *p, int32_t idx, Register temp) {
         Label stackFull;
         spsProfileEntryAddress(p, -1, temp, &stackFull);
-        store32(Imm32(idx), Address(temp, ProfileEntry::offsetOfLineOrPc()));
+        store32(Imm32(idx), Address(temp, ProfileEntry::offsetOfPCIdx()));
         bind(&stackFull);
     }
 
     void spsUpdatePCIdx(SPSProfiler *p, Register idx, Register temp) {
         Label stackFull;
         spsProfileEntryAddressSafe(p, -1, temp, &stackFull);
-        store32(idx, Address(temp, ProfileEntry::offsetOfLineOrPc()));
+        store32(idx, Address(temp, ProfileEntry::offsetOfPCIdx()));
         bind(&stackFull);
     }
 
     // spsPushFrame variant for Ion-optimized scripts.
     void spsPushFrame(SPSProfiler *p, const char *str, JSScript *s, Register temp) {
         Label stackFull;
         spsProfileEntryAddress(p, 0, temp, &stackFull);
 
-        storePtr(ImmPtr(str), Address(temp, ProfileEntry::offsetOfLabel()));
-        storePtr(ImmGCPtr(s), Address(temp, ProfileEntry::offsetOfSpOrScript()));
-        store32(Imm32(ProfileEntry::NullPCOffset), Address(temp, ProfileEntry::offsetOfLineOrPc()));
-        store32(Imm32(0), Address(temp, ProfileEntry::offsetOfFlags()));
+        storePtr(ImmPtr(str),  Address(temp, ProfileEntry::offsetOfString()));
+        storePtr(ImmGCPtr(s),  Address(temp, ProfileEntry::offsetOfScript()));
+        storePtr(ImmPtr((void*) ProfileEntry::SCRIPT_OPT_STACKPOINTER),
+                 Address(temp, ProfileEntry::offsetOfStackAddress()));
+        store32(Imm32(ProfileEntry::NullPCIndex), Address(temp, ProfileEntry::offsetOfPCIdx()));
 
         /* Always increment the stack size, whether or not we actually pushed. */
         bind(&stackFull);
         movePtr(ImmPtr(p->sizePointer()), temp);
         add32(Imm32(1), Address(temp, 0));
     }
 
     // spsPushFrame variant for Baseline-optimized scripts.
     void spsPushFrame(SPSProfiler *p, const Address &str, const Address &script,
                       Register temp, Register temp2)
     {
         Label stackFull;
         spsProfileEntryAddressSafe(p, 0, temp, &stackFull);
 
         loadPtr(str, temp2);
-        storePtr(temp2, Address(temp, ProfileEntry::offsetOfLabel()));
+        storePtr(temp2, Address(temp, ProfileEntry::offsetOfString()));
 
         loadPtr(script, temp2);
-        storePtr(temp2, Address(temp, ProfileEntry::offsetOfSpOrScript()));
+        storePtr(temp2, Address(temp, ProfileEntry::offsetOfScript()));
+
+        storePtr(ImmPtr(nullptr), Address(temp, ProfileEntry::offsetOfStackAddress()));
 
         // Store 0 for PCIdx because that's what interpreter does.
         // (See probes::EnterScript, which calls spsProfiler.enter, which pushes an entry
         //  with 0 pcIdx).
-        store32(Imm32(0), Address(temp, ProfileEntry::offsetOfLineOrPc()));
-        store32(Imm32(0), Address(temp, ProfileEntry::offsetOfFlags()));
+        store32(Imm32(0), Address(temp, ProfileEntry::offsetOfPCIdx()));
 
         /* Always increment the stack size, whether or not we actually pushed. */
         bind(&stackFull);
         movePtr(ImmPtr(p->addressOfSizePointer()), temp);
         loadPtr(Address(temp, 0), temp);
         add32(Imm32(1), Address(temp, 0));
     }
 
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -1422,19 +1422,16 @@ class MacroAssemblerARMCompat : public M
     void addPtr(Imm32 imm, const Register dest);
     void addPtr(Imm32 imm, const Address &dest);
     void addPtr(ImmWord imm, const Register dest) {
         addPtr(Imm32(imm.value), dest);
     }
     void addPtr(ImmPtr imm, const Register dest) {
         addPtr(ImmWord(uintptr_t(imm.value)), dest);
     }
-    void mulBy3(const Register &src, const Register &dest) {
-        as_add(dest, src, lsl(src, 1));
-    }
 
     void setStackArg(Register reg, uint32_t arg);
 
     void breakpoint();
     // conditional breakpoint
     void breakpoint(Condition cc);
 
     void compareDouble(FloatRegister lhs, FloatRegister rhs);
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -567,19 +567,16 @@ class MacroAssemblerX64 : public MacroAs
         subq(src, dest);
     }
     void subPtr(const Address &addr, Register dest) {
         subq(Operand(addr), dest);
     }
     void subPtr(Register src, const Address &dest) {
         subq(src, Operand(dest));
     }
-    void mulBy3(const Register &src, const Register &dest) {
-        lea(Operand(src, src, TimesTwo), dest);
-    }
 
     void branch32(Condition cond, AbsoluteAddress lhs, Imm32 rhs, Label *label) {
         if (JSC::X86Assembler::isAddressImmediate(lhs.addr)) {
             branch32(cond, Operand(lhs), rhs, label);
         } else {
             mov(ImmPtr(lhs.addr), ScratchReg);
             branch32(cond, Address(ScratchReg, 0), rhs, label);
         }
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -576,19 +576,16 @@ class MacroAssemblerX86 : public MacroAs
         subl(src, dest);
     }
     void subPtr(const Address &addr, Register dest) {
         subl(Operand(addr), dest);
     }
     void subPtr(Register src, const Address &dest) {
         subl(src, Operand(dest));
     }
-    void mulBy3(const Register &src, const Register &dest) {
-        lea(Operand(src, src, TimesTwo), dest);
-    }
 
     void branch32(Condition cond, AbsoluteAddress lhs, Imm32 rhs, Label *label) {
         cmpl(Operand(lhs), rhs);
         j(cond, label);
     }
     void branch32(Condition cond, AbsoluteAddress lhs, Register rhs, Label *label) {
         cmpl(Operand(lhs), rhs);
         j(cond, label);
--- a/js/src/vm/SPSProfiler.cpp
+++ b/js/src/vm/SPSProfiler.cpp
@@ -157,49 +157,49 @@ SPSProfiler::enter(JSScript *script, JSF
 
 #ifdef DEBUG
     // In debug builds, assert the JS pseudo frames already on the stack
     // have a non-null pc. Only look at the top frames to avoid quadratic
     // behavior.
     if (*size_ > 0 && *size_ - 1 < max_) {
         size_t start = (*size_ > 4) ? *size_ - 4 : 0;
         for (size_t i = start; i < *size_ - 1; i++)
-            MOZ_ASSERT_IF(stack_[i].isJs(), stack_[i].pc() != nullptr);
+            MOZ_ASSERT_IF(stack_[i].js(), stack_[i].pc() != nullptr);
     }
 #endif
 
-    push(str, nullptr, script, script->code(), /* copy = */ true);
+    push(str, nullptr, script, script->code());
     return true;
 }
 
 void
 SPSProfiler::exit(JSScript *script, JSFunction *maybeFun)
 {
     pop();
 
 #ifdef DEBUG
     /* Sanity check to make sure push/pop balanced */
     if (*size_ < max_) {
         const char *str = profileString(script, maybeFun);
         /* Can't fail lookup because we should already be in the set */
         JS_ASSERT(str != nullptr);
 
         // Bug 822041
-        if (!stack_[*size_].isJs()) {
+        if (!stack_[*size_].js()) {
             fprintf(stderr, "--- ABOUT TO FAIL ASSERTION ---\n");
             fprintf(stderr, " stack=%p size=%d/%d\n", (void*) stack_, *size_, max_);
             for (int32_t i = *size_; i >= 0; i--) {
-                if (stack_[i].isJs())
+                if (stack_[i].js())
                     fprintf(stderr, "  [%d] JS %s\n", i, stack_[i].label());
                 else
                     fprintf(stderr, "  [%d] C line %d %s\n", i, stack_[i].line(), stack_[i].label());
             }
         }
 
-        JS_ASSERT(stack_[*size_].isJs());
+        JS_ASSERT(stack_[*size_].js());
         JS_ASSERT(stack_[*size_].script() == script);
         JS_ASSERT(strcmp((const char*) stack_[*size_].label(), str) == 0);
         stack_[*size_].setLabel(nullptr);
         stack_[*size_].setPC(nullptr);
     }
 #endif
 }
 
@@ -209,47 +209,37 @@ SPSProfiler::enterNative(const char *str
     /* these operations cannot be re-ordered, so volatile-ize operations */
     volatile ProfileEntry *stack = stack_;
     volatile uint32_t *size = size_;
     uint32_t current = *size;
 
     JS_ASSERT(enabled());
     if (current < max_) {
         stack[current].setLabel(string);
-        stack[current].setCppFrame(sp, 0);
+        stack[current].setStackAddress(sp);
+        stack[current].setScript(nullptr);
+        stack[current].setLine(0);
     }
     *size = current + 1;
 }
 
 void
-SPSProfiler::push(const char *string, void *sp, JSScript *script, jsbytecode *pc, bool copy)
+SPSProfiler::push(const char *string, void *sp, JSScript *script, jsbytecode *pc)
 {
-    JS_ASSERT_IF(sp != nullptr, script == nullptr && pc == nullptr);
-    JS_ASSERT_IF(sp == nullptr, script != nullptr && pc != nullptr);
-
     /* these operations cannot be re-ordered, so volatile-ize operations */
     volatile ProfileEntry *stack = stack_;
     volatile uint32_t *size = size_;
     uint32_t current = *size;
 
     JS_ASSERT(installed());
     if (current < max_) {
-        volatile ProfileEntry &entry = stack[current];
-        entry.setLabel(string);
-
-        if (sp != nullptr)
-            entry.setCppFrame(sp, 0);
-        else
-            entry.setJsFrame(script, pc);
-
-        // Track if mLabel needs a copy.
-        if (copy)
-            entry.setFlag(js::ProfileEntry::FRAME_LABEL_COPY);
-        else
-            entry.unsetFlag(js::ProfileEntry::FRAME_LABEL_COPY);
+        stack[current].setLabel(string);
+        stack[current].setStackAddress(sp);
+        stack[current].setScript(script);
+        stack[current].setPC(pc);
     }
     *size = current + 1;
 }
 
 void
 SPSProfiler::pop()
 {
     JS_ASSERT(installed());
@@ -318,38 +308,37 @@ SPSEntryMarker::SPSEntryMarker(JSRuntime
     : profiler(&rt->spsProfiler)
 {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     if (!profiler->installed()) {
         profiler = nullptr;
         return;
     }
     size_before = *profiler->size_;
-    profiler->push("js::RunScript", this, nullptr, nullptr, /* copy = */ false);
+    profiler->pushNoCopy("js::RunScript", this, nullptr, nullptr);
 }
+
 SPSEntryMarker::~SPSEntryMarker()
 {
     if (profiler != nullptr) {
         profiler->pop();
         JS_ASSERT(size_before == *profiler->size_);
     }
 }
 
 JS_FRIEND_API(jsbytecode*)
 ProfileEntry::pc() const volatile
 {
-    MOZ_ASSERT(isJs());
-    return lineOrPc == NullPCOffset ? nullptr : script()->offsetToPC(lineOrPc);
+    return idx == NullPCIndex ? nullptr : script()->offsetToPC(idx);
 }
 
 JS_FRIEND_API(void)
 ProfileEntry::setPC(jsbytecode *pc) volatile
 {
-    MOZ_ASSERT(isJs());
-    lineOrPc = pc == nullptr ? NullPCOffset : script()->pcToOffset(pc);
+    idx = pc == nullptr ? NullPCIndex : script()->pcToOffset(pc);
 }
 
 JS_FRIEND_API(void)
 js::SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size, uint32_t max)
 {
     rt->spsProfiler.setProfilingStack(stack, size, max);
 }
 
--- a/js/src/vm/SPSProfiler.h
+++ b/js/src/vm/SPSProfiler.h
@@ -123,17 +123,23 @@ class SPSProfiler
     uint32_t             *size_;
     uint32_t             max_;
     bool                 slowAssertions;
     uint32_t             enabled_;
     PRLock               *lock_;
     void                (*eventMarker_)(const char *);
 
     const char *allocProfileString(JSScript *script, JSFunction *function);
-    void push(const char *string, void *sp, JSScript *script, jsbytecode *pc, bool copy);
+    void push(const char *string, void *sp, JSScript *script, jsbytecode *pc);
+    void pushNoCopy(const char *string, void *sp,
+                    JSScript *script, jsbytecode *pc) {
+        push(string, reinterpret_cast<void*>(
+            reinterpret_cast<uintptr_t>(sp) | ProfileEntry::NoCopyBit),
+            script, pc);
+    }
     void pop();
 
   public:
     explicit SPSProfiler(JSRuntime *rt);
     ~SPSProfiler();
 
     bool init();
 
@@ -426,17 +432,17 @@ class SPSInstrumentation
      */
     void pushManual(JSScript *script, Assembler &masm, Register scratch,
                     bool inlinedFunction = false)
     {
         if (!enabled())
             return;
 
         if (!inlinedFunction)
-            masm.spsUpdatePCIdx(profiler_, ProfileEntry::NullPCOffset, scratch);
+            masm.spsUpdatePCIdx(profiler_, ProfileEntry::NullPCIndex, scratch);
 
         setPushed(script);
     }
 
     /*
      * Signals that the current function is leaving for a function call. This
      * can happen both on JS function calls and also calls to C++. This
      * internally manages how many leave() calls have been seen, and only the
@@ -467,18 +473,18 @@ class SPSInstrumentation
      * state with leave() to only emit instrumentation at proper times.
      */
     void reenter(Assembler &masm, Register scratch, bool inlinedFunction = false) {
         if (!enabled() || !frame->script || frame->left-- != 1)
             return;
         if (frame->skipNext) {
             frame->skipNext = false;
         } else {
-            if (!inlinedFunction)
-                masm.spsUpdatePCIdx(profiler_, ProfileEntry::NullPCOffset, scratch);
+             if (!inlinedFunction)
+                 masm.spsUpdatePCIdx(profiler_, ProfileEntry::NullPCIndex, scratch);
         }
     }
 
     /*
      * Signifies exiting a JS frame, popping the SPS entry. Because there can be
      * multiple return sites of a function, this does not cease instrumentation
      * emission.
      */
--- a/tools/profiler/BreakpadSampler.cpp
+++ b/tools/profiler/BreakpadSampler.cpp
@@ -92,17 +92,17 @@ void genProfileEntry(/*MODIFIED*/Unwinde
       char text[sizeof(void*)];
       for (size_t pos = 0; pos < sizeof(void*) && j+pos < strLen; pos++) {
         text[pos] = sampleLabel[j+pos];
       }
       j += sizeof(void*)/sizeof(char);
       // Cast to *((void**) to pass the text data to a void*
       utb__addEntry( utb, ProfileEntry('d', *((void**)(&text[0]))) );
     }
-    if (entry.isJs()) {
+    if (entry.js()) {
       if (!entry.pc()) {
         // The JIT only allows the top-most entry to have a nullptr pc
         MOZ_ASSERT(&entry == &stack->mStack[stack->stackSize() - 1]);
         // If stack-walking was disabled, then that's just unfortunate
         if (lastpc) {
           jsbytecode *jspc = js::ProfilingGetPC(stack->mRuntime, entry.script(),
                                                 lastpc);
           if (jspc) {
@@ -222,17 +222,17 @@ void populateBuffer(UnwinderThreadBuffer
       utb__addEntry( utb, ProfileEntry('h'/*hint*/, 'N'/*native-trace*/) );
       genPseudoBacktraceEntries(utb, stack, sample);
       break;
     case UnwINVALID:
     default:
       MOZ_CRASH();
   }
 
-  if (recordSample) {
+  if (recordSample) {    
     // add a "flush now" hint
     utb__addEntry( utb, ProfileEntry('h'/*hint*/, 'F'/*flush*/) );
   }
 
   // Add any extras
   if (!sLastTracerEvent.IsNull() && sample) {
     TimeDuration delta = sample->timestamp - sLastTracerEvent;
     utb__addEntry( utb, ProfileEntry('r', static_cast<float>(delta.ToMilliseconds())) );
--- a/tools/profiler/PseudoStack.h
+++ b/tools/profiler/PseudoStack.h
@@ -80,16 +80,36 @@ static inline uint32_t sMin(uint32_t l, 
 // walking is not available on the platform we are running on.
 //
 // Each entry has a descriptive string, a relevant stack address, and some extra
 // information the JS engine might want to inform SPS of. This class inherits
 // from the JS engine's version of the entry to ensure that the size and layout
 // of the two representations are consistent.
 class StackEntry : public js::ProfileEntry
 {
+public:
+
+  bool isCopyLabel() const volatile {
+    return !((uintptr_t)stackAddress() & 0x1);
+  }
+
+  void setStackAddressCopy(void *sparg, bool copy) volatile {
+    // Tagged pointer. Less significant bit used to track if mLabel needs a
+    // copy. Note that we don't need the last bit of the stack address for
+    // proper ordering. This is optimized for encoding within the JS engine's
+    // instrumentation, so we do the extra work here of encoding a bit.
+    // Last bit 1 = Don't copy, Last bit 0 = Copy.
+    if (copy) {
+      setStackAddress(reinterpret_cast<void*>(
+                        reinterpret_cast<uintptr_t>(sparg) & ~NoCopyBit));
+    } else {
+      setStackAddress(reinterpret_cast<void*>(
+                        reinterpret_cast<uintptr_t>(sparg) | NoCopyBit));
+    }
+  }
 };
 
 class ProfilerMarkerPayload;
 template<typename T>
 class ProfilerLinkedList;
 class JSStreamWriter;
 class JSCustomArray;
 class ThreadProfile;
@@ -338,35 +358,33 @@ public:
   }
 
   // called within signal. Function must be reentrant
   ProfilerMarkerLinkedList* getPendingMarkers()
   {
     return mPendingMarkers.getPendingMarkers();
   }
 
-  void push(const char *aName, void *aStackAddress, uint32_t line, bool aCopy)
+  void push(const char *aName, uint32_t line)
+  {
+    push(aName, nullptr, false, line);
+  }
+
+  void push(const char *aName, void *aStackAddress, bool aCopy, uint32_t line)
   {
     if (size_t(mStackPointer) >= mozilla::ArrayLength(mStack)) {
       mStackPointer++;
       return;
     }
 
-    volatile StackEntry &entry = mStack[mStackPointer];
-
     // Make sure we increment the pointer after the name has
     // been written such that mStack is always consistent.
-    entry.setLabel(aName);
-    entry.setCppFrame(aStackAddress, line);
-
-    // Track if mLabel needs a copy.
-    if (aCopy)
-      entry.setFlag(js::ProfileEntry::FRAME_LABEL_COPY);
-    else
-      entry.unsetFlag(js::ProfileEntry::FRAME_LABEL_COPY);
+    mStack[mStackPointer].setLabel(aName);
+    mStack[mStackPointer].setStackAddressCopy(aStackAddress, aCopy);
+    mStack[mStackPointer].setLine(line);
 
     // Prevent the optimizer from re-ordering these instructions
     STORE_SEQUENCER();
     mStackPointer++;
   }
   void pop()
   {
     mStackPointer--;
--- a/tools/profiler/TableTicker.cpp
+++ b/tools/profiler/TableTicker.cpp
@@ -342,17 +342,17 @@ void addProfileEntry(volatile StackEntry
   // First entry has tagName 's' (start)
   // Check for magic pointer bit 1 to indicate copy
   const char* sampleLabel = entry.label();
   if (entry.isCopyLabel()) {
     // Store the string using 1 or more 'd' (dynamic) tags
     // that will happen to the preceding tag
 
     addDynamicTag(aProfile, 'c', sampleLabel);
-    if (entry.isJs()) {
+    if (entry.js()) {
       if (!entry.pc()) {
         // The JIT only allows the top-most entry to have a nullptr pc
         MOZ_ASSERT(&entry == &stack->mStack[stack->stackSize() - 1]);
         // If stack-walking was disabled, then that's just unfortunate
         if (lastpc) {
           jsbytecode *jspc = js::ProfilingGetPC(stack->mRuntime, entry.script(),
                                                 lastpc);
           if (jspc) {
@@ -362,22 +362,17 @@ void addProfileEntry(volatile StackEntry
       } else {
         lineno = JS_PCToLineNumber(nullptr, entry.script(), entry.pc());
       }
     } else {
       lineno = entry.line();
     }
   } else {
     aProfile.addTag(ProfileEntry('c', sampleLabel));
-
-    // XXX: Bug 1010578. Don't assume a CPP entry and try to get the
-    // line for js entries as well.
-    if (entry.isCpp()) {
-      lineno = entry.line();
-    }
+    lineno = entry.line();
   }
   if (lineno != -1) {
     aProfile.addTag(ProfileEntry('n', lineno));
   }
 }
 
 #if defined(USE_NS_STACKWALK) || defined(USE_EHABI_STACKWALK)
 typedef struct {
@@ -507,17 +502,17 @@ void TableTicker::doNativeBacktrace(Thre
   // The pseudostack contains an "EnterJIT" frame whenever we enter
   // JIT code with profiling enabled; the stack pointer value points
   // the saved registers.  We use this to unwind resume unwinding
   // after encounting JIT code.
   for (uint32_t i = pseudoStack->stackSize(); i > 0; --i) {
     // The pseudostack grows towards higher indices, so we iterate
     // backwards (from callee to caller).
     volatile StackEntry &entry = pseudoStack->mStack[i - 1];
-    if (!entry.isJs() && strcmp(entry.label(), "EnterJIT") == 0) {
+    if (!entry.js() && strcmp(entry.label(), "EnterJIT") == 0) {
       // Found JIT entry frame.  Unwind up to that point (i.e., force
       // the stack walk to stop before the block of saved registers;
       // note that it yields nondecreasing stack pointers), then restore
       // the saved state.
       uint32_t *vSP = reinterpret_cast<uint32_t*>(entry.stackAddress());
 
       array.count += EHABIStackWalk(*mcontext,
                                     /* stackBase = */ vSP,