Bug 1249235 - Store RegExp flags into single slot. r=h4writer
authorTooru Fujisawa <arai_a@mac.com>
Sat, 20 Feb 2016 05:43:50 +0900
changeset 284933 d1a4b82b556a5491cd824e70f781a55f7025269d
parent 284932 36fdf01130f9d403fd8f03fc3c21c909a4c373f3
child 284934 5887f21323b5a45050c0d27f4188932253f1a9be
push id17718
push userphilringnalda@gmail.com
push dateSun, 21 Feb 2016 01:37:10 +0000
treeherderfx-team@889096db9c1b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs1249235
milestone47.0a1
Bug 1249235 - Store RegExp flags into single slot. r=h4writer
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.h
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -14179,8 +14179,20 @@ IonBuilder::addLexicalCheck(MDefinition*
         current->add(lexicalCheck);
         if (failedLexicalCheck_)
             lexicalCheck->setNotMovableUnchecked();
         return lexicalCheck;
     }
 
     return input;
 }
+
+MDefinition*
+IonBuilder::convertToBoolean(MDefinition* input)
+{
+    // Convert to bool with the '!!' idiom
+    MNot* resultInverted = MNot::New(alloc(), input, constraints());
+    current->add(resultInverted);
+    MNot* result = MNot::New(alloc(), resultInverted, constraints());
+    current->add(result);
+
+    return result;
+}
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -643,16 +643,18 @@ class IonBuilder
     }
 
     bool improveThisTypesForCall();
 
     MDefinition* getCallee();
     MDefinition* getAliasedVar(ScopeCoordinate sc);
     MDefinition* addLexicalCheck(MDefinition* input);
 
+    MDefinition* convertToBoolean(MDefinition* input);
+
     bool tryFoldInstanceOf(MDefinition* lhs, JSObject* protoObject);
     bool hasOnProtoChain(TypeSet::ObjectKey* key, JSObject* protoObject, bool* hasOnProto);
 
     bool jsop_add(MDefinition* left, MDefinition* right);
     bool jsop_bitnot();
     bool jsop_bitop(JSOp op);
     bool jsop_binary_arith(JSOp op);
     bool jsop_binary_arith(JSOp op, MDefinition* left, MDefinition* right);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -323,26 +323,33 @@ IonBuilder::inlineNativeGetter(CallInfo&
             return InliningStatus_NotInlined;
 
         MInstruction* length = addTypedArrayLength(thisArg);
         current->push(length);
         return InliningStatus_Inlined;
     }
 
     // Try to optimize RegExp getters.
-    unsigned slot = 0;
-    if (RegExpObject::isOriginalFlagGetter(native, &slot)) {
+    RegExpFlag mask = NoFlags;
+    if (RegExpObject::isOriginalFlagGetter(native, &mask)) {
         const Class* clasp = thisTypes->getKnownClass(constraints());
         if (clasp != &RegExpObject::class_)
             return InliningStatus_NotInlined;
 
-        MLoadFixedSlot* load = MLoadFixedSlot::New(alloc(), thisArg, slot);
-        current->add(load);
-        current->push(load);
-        load->setResultType(MIRType_Boolean);
+        MLoadFixedSlot* flags = MLoadFixedSlot::New(alloc(), thisArg, RegExpObject::flagsSlot());
+        current->add(flags);
+        flags->setResultType(MIRType_Int32);
+        MConstant* maskConst = MConstant::New(alloc(), Int32Value(mask));
+        current->add(maskConst);
+        MBitAnd* maskedFlag = MBitAnd::New(alloc(), flags, maskConst);
+        maskedFlag->setInt32Specialization();
+        current->add(maskedFlag);
+
+        MDefinition* result = convertToBoolean(maskedFlag);
+        current->push(result);
         return InliningStatus_Inlined;
     }
 
     return InliningStatus_NotInlined;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineNonFunctionCall(CallInfo& callInfo, JSObject* target)
@@ -2168,21 +2175,17 @@ IonBuilder::inlineHasClass(CallInfo& cal
                 MHasClass* hasClass = MHasClass::New(alloc(), callInfo.getArg(0), remaining[i]);
                 current->add(hasClass);
                 MBitOr* either = MBitOr::New(alloc(), last, hasClass);
                 either->infer(inspector, pc);
                 current->add(either);
                 last = either;
             }
 
-            // Convert to bool with the '!!' idiom
-            MNot* resultInverted = MNot::New(alloc(), last, constraints());
-            current->add(resultInverted);
-            MNot* result = MNot::New(alloc(), resultInverted, constraints());
-            current->add(result);
+            MDefinition* result = convertToBoolean(last);
             current->push(result);
         }
     }
 
     callInfo.setImplicitlyUsedUnchecked();
     return InliningStatus_Inlined;
 }
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -5586,16 +5586,21 @@ class MBinaryBitwiseInstruction
     MDefinition* foldUnnecessaryBitop();
     virtual MDefinition* foldIfZero(size_t operand) = 0;
     virtual MDefinition* foldIfNegOne(size_t operand) = 0;
     virtual MDefinition* foldIfEqual()  = 0;
     virtual MDefinition* foldIfAllBitsSet(size_t operand)  = 0;
     virtual void infer(BaselineInspector* inspector, jsbytecode* pc);
     void collectRangeInfoPreTrunc() override;
 
+    void setInt32Specialization() {
+        specialization_ = MIRType_Int32;
+        setResultType(MIRType_Int32);
+    }
+
     bool congruentTo(const MDefinition* ins) const override {
         return binaryCongruentTo(ins);
     }
     AliasSet getAliasSet() const override {
         if (specialization_ >= MIRType_Object)
             return AliasSet::Store(AliasSet::Any);
         return AliasSet::None();
     }
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -119,36 +119,36 @@ RegExpObject::getShared(JSContext* cx, R
         g->init(*shared);
         return true;
     }
 
     return createShared(cx, g);
 }
 
 /* static */ bool
-RegExpObject::isOriginalFlagGetter(JSNative native, unsigned* slot)
+RegExpObject::isOriginalFlagGetter(JSNative native, RegExpFlag* mask)
 {
   if (native == regexp_global) {
-      *slot = GLOBAL_FLAG_SLOT;
+      *mask = GlobalFlag;
       return true;
   }
   if (native == regexp_ignoreCase) {
-      *slot = IGNORE_CASE_FLAG_SLOT;
+      *mask = IgnoreCaseFlag;
       return true;
   }
   if (native == regexp_multiline) {
-      *slot = MULTILINE_FLAG_SLOT;
+      *mask = MultilineFlag;
       return true;
   }
   if (native == regexp_sticky) {
-      *slot = STICKY_FLAG_SLOT;
+      *mask = StickyFlag;
       return true;
   }
   if (native == regexp_unicode) {
-      *slot = UNICODE_FLAG_SLOT;
+      *mask = UnicodeFlag;
       return true;
   }
 
   return false;
 }
 
 /* static */ void
 RegExpObject::trace(JSTracer* trc, JSObject* obj)
@@ -295,21 +295,17 @@ RegExpObject::init(ExclusiveContext* cx,
     /*
      * If this is a re-initialization with an existing RegExpShared, 'flags'
      * may not match getShared()->flags, so forget the RegExpShared.
      */
     self->NativeObject::setPrivate(nullptr);
 
     self->zeroLastIndex();
     self->setSource(source);
-    self->setGlobal(flags & GlobalFlag);
-    self->setIgnoreCase(flags & IgnoreCaseFlag);
-    self->setMultiline(flags & MultilineFlag);
-    self->setSticky(flags & StickyFlag);
-    self->setUnicode(flags & UnicodeFlag);
+    self->setFlags(flags);
     return true;
 }
 
 static MOZ_ALWAYS_INLINE bool
 IsLineTerminator(const JS::Latin1Char c)
 {
     return c == '\n' || c == '\r';
 }
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -351,25 +351,21 @@ class RegExpCompartment
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
 };
 
 class RegExpObject : public NativeObject
 {
     static const unsigned LAST_INDEX_SLOT          = 0;
     static const unsigned SOURCE_SLOT              = 1;
-    static const unsigned GLOBAL_FLAG_SLOT         = 2;
-    static const unsigned IGNORE_CASE_FLAG_SLOT    = 3;
-    static const unsigned MULTILINE_FLAG_SLOT      = 4;
-    static const unsigned STICKY_FLAG_SLOT         = 5;
-    static const unsigned UNICODE_FLAG_SLOT        = 6;
+    static const unsigned FLAGS_SLOT               = 2;
 
   public:
-    static const unsigned RESERVED_SLOTS = 7;
-    static const unsigned PRIVATE_SLOT = 7;
+    static const unsigned RESERVED_SLOTS = 3;
+    static const unsigned PRIVATE_SLOT = 3;
 
     static const Class class_;
 
     // The maximum number of pairs a MatchResult can have, without having to
     // allocate a bigger MatchResult.
     static const size_t MaxPairCount = 14;
 
     /*
@@ -414,55 +410,34 @@ class RegExpObject : public NativeObject
     JSFlatString* toString(JSContext* cx) const;
 
     JSAtom* getSource() const { return &getSlot(SOURCE_SLOT).toString()->asAtom(); }
 
     void setSource(JSAtom* source) {
         setSlot(SOURCE_SLOT, StringValue(source));
     }
 
-    RegExpFlag getFlags() const {
-        unsigned flags = 0;
-        flags |= global() ? GlobalFlag : 0;
-        flags |= ignoreCase() ? IgnoreCaseFlag : 0;
-        flags |= multiline() ? MultilineFlag : 0;
-        flags |= sticky() ? StickyFlag : 0;
-        flags |= unicode() ? UnicodeFlag : 0;
-        return RegExpFlag(flags);
-    }
-
     /* Flags. */
 
-    void setIgnoreCase(bool enabled) {
-        setSlot(IGNORE_CASE_FLAG_SLOT, BooleanValue(enabled));
+    static unsigned flagsSlot() { return FLAGS_SLOT; }
+
+    RegExpFlag getFlags() const {
+        return RegExpFlag(getFixedSlot(FLAGS_SLOT).toInt32());
     }
-
-    void setGlobal(bool enabled) {
-        setSlot(GLOBAL_FLAG_SLOT, BooleanValue(enabled));
+    void setFlags(RegExpFlag flags) {
+        setSlot(FLAGS_SLOT, Int32Value(flags));
     }
 
-    void setMultiline(bool enabled) {
-        setSlot(MULTILINE_FLAG_SLOT, BooleanValue(enabled));
-    }
-
-    void setSticky(bool enabled) {
-        setSlot(STICKY_FLAG_SLOT, BooleanValue(enabled));
-    }
+    bool ignoreCase() const { return getFlags() & IgnoreCaseFlag; }
+    bool global() const     { return getFlags() & GlobalFlag; }
+    bool multiline() const  { return getFlags() & MultilineFlag; }
+    bool sticky() const     { return getFlags() & StickyFlag; }
+    bool unicode() const    { return getFlags() & UnicodeFlag; }
 
-    void setUnicode(bool enabled) {
-        setSlot(UNICODE_FLAG_SLOT, BooleanValue(enabled));
-    }
-
-    bool ignoreCase() const { return getFixedSlot(IGNORE_CASE_FLAG_SLOT).toBoolean(); }
-    bool global() const     { return getFixedSlot(GLOBAL_FLAG_SLOT).toBoolean(); }
-    bool multiline() const  { return getFixedSlot(MULTILINE_FLAG_SLOT).toBoolean(); }
-    bool sticky() const     { return getFixedSlot(STICKY_FLAG_SLOT).toBoolean(); }
-    bool unicode() const    { return getFixedSlot(UNICODE_FLAG_SLOT).toBoolean(); }
-
-    static bool isOriginalFlagGetter(JSNative native, unsigned* slot);
+    static bool isOriginalFlagGetter(JSNative native, RegExpFlag* mask);
 
     bool getShared(JSContext* cx, RegExpGuard* g);
 
     void setShared(RegExpShared& shared) {
         MOZ_ASSERT(!maybeShared());
         NativeObject::setPrivate(&shared);
     }