Bug 986680 - Part 1/4 - Define AutoGenericRegisterScope. r=nbp
authorSean Stangl <sstangl@mozilla.com>
Thu, 13 Aug 2015 12:14:27 -0700
changeset 292493 7afe43b2288ed4a485096dea49bb8b4e816f4cd4
parent 292492 fa3fabfe2b02b220229e761f4d660bdac48f4a4f
child 292494 277ae9b3ad6f5351e17399ddac8952d66df628a0
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs986680
milestone43.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 986680 - Part 1/4 - Define AutoGenericRegisterScope. r=nbp
js/src/jit/MacroAssembler.cpp
js/src/jit/MacroAssembler.h
js/src/jit/RegisterSets.h
js/src/jit/Registers.h
js/src/jit/arm/MacroAssembler-arm.cpp
js/src/jit/arm/MacroAssembler-arm.h
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -2571,16 +2571,19 @@ MacroAssembler::MacroAssembler(JSContext
 }
 
 void
 MacroAssembler::resetForNewCodeGenerator(TempAllocator& alloc)
 {
     setFramePushed(0);
     moveResolver_.clearTempObjectPool();
     moveResolver_.setAllocator(alloc);
+#ifdef DEBUG
+    debugTrackedRegisters_.clear();
+#endif
 }
 
 MacroAssembler::AfterICSaveLive
 MacroAssembler::icSaveLive(LiveRegisterSet& liveRegs)
 {
     PushRegsInMask(liveRegs);
     AfterICSaveLive aic(framePushed());
     alignFrameForICArguments(aic);
@@ -2867,8 +2870,38 @@ MacroAssembler::callWithABINoProfiler(As
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust, /* callFromAsmJS = */ true);
     call(imm);
     callWithABIPost(stackAdjust, result);
 }
 
 //}}} check_macroassembler_style
+
+namespace js {
+namespace jit {
+
+#ifdef DEBUG
+template <class RegisterType>
+AutoGenericRegisterScope<RegisterType>::AutoGenericRegisterScope(MacroAssembler& masm, RegisterType reg)
+  : RegisterType(reg), masm_(masm)
+{
+    masm.debugTrackedRegisters_.add(reg);
+}
+
+template AutoGenericRegisterScope<Register>::AutoGenericRegisterScope(MacroAssembler& masm, Register reg);
+template AutoGenericRegisterScope<FloatRegister>::AutoGenericRegisterScope(MacroAssembler& masm, FloatRegister reg);
+#endif // DEBUG
+
+#ifdef DEBUG
+template <class RegisterType>
+AutoGenericRegisterScope<RegisterType>::~AutoGenericRegisterScope()
+{
+    const RegisterType& reg = *dynamic_cast<RegisterType*>(this);
+    masm_.debugTrackedRegisters_.take(reg);
+}
+
+template AutoGenericRegisterScope<Register>::~AutoGenericRegisterScope();
+template AutoGenericRegisterScope<FloatRegister>::~AutoGenericRegisterScope();
+#endif // DEBUG
+
+} // namespace jit
+} // namespace js
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -457,16 +457,27 @@ class MacroAssembler : public MacroAssem
     // Move the stack pointer based on the requested amount.
     void adjustStack(int amount);
     void reserveStack(uint32_t amount) PER_ARCH;
     void freeStack(uint32_t amount);
 
     // Warning: This method does not update the framePushed() counter.
     void freeStack(Register amount);
 
+  private:
+    // ===============================================================
+    // Register allocation fields.
+#ifdef DEBUG
+    friend AutoRegisterScope;
+    friend AutoFloatRegisterScope;
+    // Used to track register scopes for debug builds.
+    // Manipulated by the AutoGenericRegisterScope class.
+    AllocatableRegisterSet debugTrackedRegisters_;
+#endif // DEBUG
+
   public:
     // ===============================================================
     // Simple call functions.
 
     void call(Register reg) PER_SHARED_ARCH;
     void call(const Address& addr) DEFINED_ON(x86_shared);
     void call(Label* label) PER_SHARED_ARCH;
     void call(ImmWord imm) PER_SHARED_ARCH;
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -369,16 +369,19 @@ class TypedRegisterSet
     }
     static inline TypedRegisterSet NonVolatile() {
         return TypedRegisterSet(T::Codes::AllocatableMask & T::Codes::NonVolatileMask);
     }
 
     bool empty() const {
         return !bits_;
     }
+    void clear() {
+        bits_ = 0;
+    }
 
     bool hasRegisterIndex(T reg) const {
         return !!(bits_ & (SetType(1) << reg.code()));
     }
     bool hasAllocatable(T reg) const {
         return !(~bits_ & reg.alignedOrDominatedAliasedSet());
     }
 
@@ -471,16 +474,20 @@ class RegisterSet {
     }
     static inline RegisterSet Volatile() {
         return RegisterSet(GeneralRegisterSet::Volatile(), FloatRegisterSet::Volatile());
     }
 
     bool empty() const {
         return fpu_.empty() && gpr_.empty();
     }
+    void clear() {
+        fpu_.clear();
+        gpr_.clear();
+    }
     bool emptyGeneral() const {
         return gpr_.empty();
     }
     bool emptyFloat() const {
         return fpu_.empty();
     }
     MOZ_CONSTEXPR GeneralRegisterSet gprs() const {
         return gpr_;
@@ -932,16 +939,19 @@ class CommonRegSet : public SpecializedR
     }
     RegSet& set() {
         return this->Parent::set_;
     }
 
     bool empty() const {
         return this->Parent::set_.empty();
     }
+    void clear() {
+        this->Parent::set_.clear();
+    }
 
     using Parent::add;
     void add(ValueOperand value) {
 #if defined(JS_NUNBOX32)
         add(value.payloadReg());
         add(value.typeReg());
 #elif defined(JS_PUNBOX64)
         add(value.valueReg());
--- a/js/src/jit/Registers.h
+++ b/js/src/jit/Registers.h
@@ -162,12 +162,40 @@ class MachineState
     void write(Register reg, uintptr_t value) const {
         regs_[reg.code()]->r = value;
     }
     const FloatRegisters::RegisterContent* address(FloatRegister reg) const {
         return fpregs_[reg.code()];
     }
 };
 
+class MacroAssembler;
+
+// Declares a register as owned within the scope of the object.
+// In debug mode, owned register state is tracked within the MacroAssembler,
+// and an assert will fire if ownership is conflicting.
+// In contrast to ARM64's UseScratchRegisterScope, this class has no overhead
+// in non-debug builds.
+template <class RegisterType>
+struct AutoGenericRegisterScope : public RegisterType
+{
+    // Prevent MacroAssembler templates from creating copies,
+    // which causes the destructor to fire more than once.
+    AutoGenericRegisterScope(const AutoGenericRegisterScope& other) = delete;
+
+#ifdef DEBUG
+    MacroAssembler& masm_;
+    AutoGenericRegisterScope(MacroAssembler& masm, RegisterType reg);
+    ~AutoGenericRegisterScope();
+#else
+    MOZ_CONSTEXPR AutoGenericRegisterScope(MacroAssembler& masm, RegisterType reg)
+      : RegisterType(reg)
+    { }
+#endif
+};
+
+typedef AutoGenericRegisterScope<Register> AutoRegisterScope;
+typedef AutoGenericRegisterScope<FloatRegister> AutoFloatRegisterScope;
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_Registers_h */
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -4747,16 +4747,28 @@ void
 MacroAssemblerARMCompat::callAndPushReturnAddress(Label* label)
 {
     AutoForbidPools afp(this, 2);
     ma_push(pc);
     asMasm().call(label);
 }
 
 MacroAssembler&
+MacroAssemblerARM::asMasm()
+{
+    return *static_cast<MacroAssembler*>(this);
+}
+
+const MacroAssembler&
+MacroAssemblerARM::asMasm() const
+{
+    return *static_cast<const MacroAssembler*>(this);
+}
+
+MacroAssembler&
 MacroAssemblerARMCompat::asMasm()
 {
     return *static_cast<MacroAssembler*>(this);
 }
 
 const MacroAssembler&
 MacroAssemblerARMCompat::asMasm() const
 {
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -25,16 +25,21 @@ namespace jit {
 static Register CallReg = ip;
 static const int defaultShift = 3;
 JS_STATIC_ASSERT(1 << defaultShift == sizeof(JS::Value));
 
 // MacroAssemblerARM is inheriting form Assembler defined in
 // Assembler-arm.{h,cpp}
 class MacroAssemblerARM : public Assembler
 {
+  private:
+    // Perform a downcast. Should be removed by Bug 996602.
+    MacroAssembler& asMasm();
+    const MacroAssembler& asMasm() const;
+
   protected:
     // On ARM, some instructions require a second scratch register. This
     // register defaults to lr, since it's non-allocatable (as it can be
     // clobbered by some instructions). Allow the baseline compiler to override
     // this though, since baseline IC stubs rely on lr holding the return
     // address.
     Register secondScratchReg_;