Bug 1246575 - Inline RegExp.prototype.{global,ignoreCase,multiline,sticky,unicode} getters. r=h4writer
authorTooru Fujisawa <arai_a@mac.com>
Wed, 17 Feb 2016 01:40:17 +0900
changeset 331323 b7f93e7b0caad9cc07b1c8d3e0bcbad59c0d35f3
parent 331322 9b4383349c6f4a57cd8ef8fc55de8cbdc215b63c
child 331324 c5631db6889e4a4c1afe3004aac3f22e5736b4a7
push id10956
push userjolesen@mozilla.com
push dateTue, 16 Feb 2016 19:12:12 +0000
reviewersh4writer
bugs1246575
milestone47.0a1
Bug 1246575 - Inline RegExp.prototype.{global,ignoreCase,multiline,sticky,unicode} getters. r=h4writer
js/src/builtin/RegExp.cpp
js/src/builtin/RegExp.h
js/src/jit/MCallOptimize.cpp
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -470,18 +470,18 @@ regexp_global_impl(JSContext* cx, const 
     MOZ_ASSERT(IsRegExpObject(args.thisv()));
     Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
 
     /* Steps 4-6. */
     args.rval().setBoolean(reObj->global());
     return true;
 }
 
-static bool
-regexp_global(JSContext* cx, unsigned argc, JS::Value* vp)
+bool
+js::regexp_global(JSContext* cx, unsigned argc, JS::Value* vp)
 {
     /* Steps 1-3. */
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsRegExpObject, regexp_global_impl>(cx, args);
 }
 
 /* ES6 draft rev32 21.2.5.5. */
 MOZ_ALWAYS_INLINE bool
@@ -490,18 +490,18 @@ regexp_ignoreCase_impl(JSContext* cx, co
     MOZ_ASSERT(IsRegExpObject(args.thisv()));
     Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
 
     /* Steps 4-6. */
     args.rval().setBoolean(reObj->ignoreCase());
     return true;
 }
 
-static bool
-regexp_ignoreCase(JSContext* cx, unsigned argc, JS::Value* vp)
+bool
+js::regexp_ignoreCase(JSContext* cx, unsigned argc, JS::Value* vp)
 {
     /* Steps 1-3. */
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsRegExpObject, regexp_ignoreCase_impl>(cx, args);
 }
 
 /* ES6 draft rev32 21.2.5.7. */
 MOZ_ALWAYS_INLINE bool
@@ -510,18 +510,18 @@ regexp_multiline_impl(JSContext* cx, con
     MOZ_ASSERT(IsRegExpObject(args.thisv()));
     Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
 
     /* Steps 4-6. */
     args.rval().setBoolean(reObj->multiline());
     return true;
 }
 
-static bool
-regexp_multiline(JSContext* cx, unsigned argc, JS::Value* vp)
+bool
+js::regexp_multiline(JSContext* cx, unsigned argc, JS::Value* vp)
 {
     /* Steps 1-3. */
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsRegExpObject, regexp_multiline_impl>(cx, args);
 }
 
 /* ES6 draft rev32 21.2.5.10. */
 MOZ_ALWAYS_INLINE bool
@@ -559,36 +559,36 @@ regexp_sticky_impl(JSContext* cx, const 
     MOZ_ASSERT(IsRegExpObject(args.thisv()));
     Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
 
     /* Steps 4-6. */
     args.rval().setBoolean(reObj->sticky());
     return true;
 }
 
-static bool
-regexp_sticky(JSContext* cx, unsigned argc, JS::Value* vp)
+bool
+js::regexp_sticky(JSContext* cx, unsigned argc, JS::Value* vp)
 {
     /* Steps 1-3. */
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsRegExpObject, regexp_sticky_impl>(cx, args);
 }
 
 /* ES6 21.2.5.15. */
 MOZ_ALWAYS_INLINE bool
 regexp_unicode_impl(JSContext* cx, const CallArgs& args)
 {
     MOZ_ASSERT(IsRegExpObject(args.thisv()));
     /* Steps 4-6. */
     args.rval().setBoolean(args.thisv().toObject().as<RegExpObject>().unicode());
     return true;
 }
 
-static bool
-regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp)
+bool
+js::regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp)
 {
     /* Steps 1-3. */
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsRegExpObject, regexp_unicode_impl>(cx, args);
 }
 
 const JSPropertySpec js::regexp_properties[] = {
     JS_SELF_HOSTED_GET("flags", "RegExpFlagsGetter", 0),
--- a/js/src/builtin/RegExp.h
+++ b/js/src/builtin/RegExp.h
@@ -93,11 +93,23 @@ IsRegExp(JSContext* cx, HandleValue valu
 
 // RegExp ClassSpec members used in RegExpObject.cpp.
 extern bool
 regexp_construct(JSContext* cx, unsigned argc, Value* vp);
 extern const JSPropertySpec regexp_static_props[];
 extern const JSPropertySpec regexp_properties[];
 extern const JSFunctionSpec regexp_methods[];
 
+// Used in RegExpObject::isOriginalFlagGetter.
+extern bool
+regexp_global(JSContext* cx, unsigned argc, JS::Value* vp);
+extern bool
+regexp_ignoreCase(JSContext* cx, unsigned argc, JS::Value* vp);
+extern bool
+regexp_multiline(JSContext* cx, unsigned argc, JS::Value* vp);
+extern bool
+regexp_sticky(JSContext* cx, unsigned argc, JS::Value* vp);
+extern bool
+regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp);
+
 } /* namespace js */
 
 #endif /* builtin_RegExp_h */
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -304,31 +304,46 @@ IonBuilder::InliningStatus
 IonBuilder::inlineNativeGetter(CallInfo& callInfo, JSFunction* target)
 {
     MOZ_ASSERT(target->isNative());
     JSNative native = target->native();
 
     if (!optimizationInfo().inlineNative())
         return InliningStatus_NotInlined;
 
-    TemporaryTypeSet* thisTypes = callInfo.thisArg()->resultTypeSet();
+    MDefinition* thisArg = callInfo.thisArg();
+    TemporaryTypeSet* thisTypes = thisArg->resultTypeSet();
     MOZ_ASSERT(callInfo.argc() == 0);
 
+    if (!thisTypes)
+        return InliningStatus_NotInlined;
+
     // Try to optimize typed array lengths.
-    if (thisTypes) {
-        Scalar::Type type;
-
-        type = thisTypes->getTypedArrayType(constraints());
-        if (type != Scalar::MaxTypedArrayViewType &&
-            TypedArrayObject::isOriginalLengthGetter(native))
-        {
-            MInstruction* length = addTypedArrayLength(callInfo.thisArg());
-            current->push(length);
-            return InliningStatus_Inlined;
-        }
+    if (TypedArrayObject::isOriginalLengthGetter(native)) {
+        Scalar::Type type = thisTypes->getTypedArrayType(constraints());
+        if (type == Scalar::MaxTypedArrayViewType)
+            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)) {
+        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);
+        return InliningStatus_Inlined;
     }
 
     return InliningStatus_NotInlined;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineNonFunctionCall(CallInfo& callInfo, JSObject* target)
 {
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -118,16 +118,43 @@ RegExpObject::getShared(JSContext* cx, R
 
         g->init(*shared);
         return true;
     }
 
     return createShared(cx, g);
 }
 
+/* static */ bool
+RegExpObject::isOriginalFlagGetter(JSNative native, unsigned* slot)
+{
+  if (native == regexp_global) {
+      *slot = GLOBAL_FLAG_SLOT;
+      return true;
+  }
+  if (native == regexp_ignoreCase) {
+      *slot = IGNORE_CASE_FLAG_SLOT;
+      return true;
+  }
+  if (native == regexp_multiline) {
+      *slot = MULTILINE_FLAG_SLOT;
+      return true;
+  }
+  if (native == regexp_sticky) {
+      *slot = STICKY_FLAG_SLOT;
+      return true;
+  }
+  if (native == regexp_unicode) {
+      *slot = UNICODE_FLAG_SLOT;
+      return true;
+  }
+
+  return false;
+}
+
 /* static */ void
 RegExpObject::trace(JSTracer* trc, JSObject* obj)
 {
     RegExpShared* shared = obj->as<RegExpObject>().maybeShared();
     if (!shared)
         return;
 
     // When tracing through the object normally, we have the option of
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -452,16 +452,18 @@ class RegExpObject : public NativeObject
     }
 
     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);
+
     bool getShared(JSContext* cx, RegExpGuard* g);
 
     void setShared(RegExpShared& shared) {
         MOZ_ASSERT(!maybeShared());
         NativeObject::setPrivate(&shared);
     }
 
     static void trace(JSTracer* trc, JSObject* obj);