Bug 1263340 - Part 1: Use internal slot for global and sticky flags in RegExpBuiltinExec. r=h4writer
authorTooru Fujisawa <arai_a@mac.com>
Fri, 22 Apr 2016 10:35:41 +0900
changeset 332298 3d31abc6b37d5c69fca3631377c36c09a3fa4d5b
parent 332297 413ad396d8a41b34cbdaf471f3e33c136e1e08fa
child 332299 53b4512a42b434524730ddf84b6f448e0a0d3c80
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs1263340
milestone48.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 1263340 - Part 1: Use internal slot for global and sticky flags in RegExpBuiltinExec. r=h4writer
js/src/builtin/RegExp.js
js/src/builtin/SelfHostingDefines.h
js/src/jit-test/tests/ion/testStringMatch.js
js/src/vm/RegExpObject.h
--- a/js/src/builtin/RegExp.js
+++ b/js/src/builtin/RegExp.js
@@ -799,69 +799,72 @@ function RegExpExec(R, S, forTest) {
     // Step 5.c.
     if (typeof result !== "object")
         ThrowTypeError(JSMSG_EXEC_NOT_OBJORNULL);
 
     // Step 5.d.
     return forTest ? result !== null : result;
 }
 
-// ES6 21.2.5.2.2.
+// ES 2017 draft rev 6a13789aa9e7c6de4e96b7d3e24d9e6eba6584ad 21.2.5.2.2.
 function RegExpBuiltinExec(R, S, forTest) {
     // ES6 21.2.5.2.1 step 6.
     // This check is here for RegExpTest.  RegExp_prototype_Exec does same
     // thing already.
     if (!IsRegExpObject(R))
         return callFunction(CallRegExpMethodIfWrapped, R, R, S, forTest, "RegExpBuiltinExec");
 
-    // Step 1-2 (skipped).
+    // Steps 1-2 (skipped).
 
-    // Steps 4-5.
+    // Step 4.
     var lastIndex = ToLength(R.lastIndex);
 
-    // Steps 6-7.
-    var global = !!R.global;
+    // Step 5.
+    var flags = UnsafeGetInt32FromReservedSlot(R, REGEXP_FLAGS_SLOT);
 
-    // Steps 8-9.
-    var sticky = !!R.sticky;
+    // Step 6.
+    var global = !!(flags & REGEXP_GLOBAL_FLAG);
 
-    // Step 10.
+    // Step 7.
+    var sticky = !!(flags & REGEXP_STICKY_FLAG);
+
+    // Step 8.
     if (!global && !sticky) {
         lastIndex = 0;
     } else {
         if (lastIndex > S.length) {
-            // Steps 15.a.i-ii, 15.c.i.1-2.
+            // Steps 12.a.i-ii, 12.c.i.1-2.
             R.lastIndex = 0;
             return forTest ? false : null;
         }
     }
 
     if (forTest) {
-        // Steps 3, 11-17, except 15.a.i-ii, 15.c.i.1-2.
+        // Steps 3, 9-25, except 12.a.i-ii, 12.c.i.1-2, 15.
         var endIndex = RegExpTester(R, S, lastIndex, sticky);
         if (endIndex == -1) {
-            // Steps 15.a.i-ii, 15.c.i.1-2.
+            // Steps 12.a.i-ii, 12.c.i.1-2.
             R.lastIndex = 0;
             return false;
         }
 
-        // Step 18.
+        // Step 15.
         if (global || sticky)
             R.lastIndex = endIndex;
 
         return true;
     }
 
-    // Steps 3, 11-17, except 15.a.i-ii, 15.c.i.1-2.
+    // Steps 3, 9-25, except 12.a.i-ii, 12.c.i.1-2, 15.
     var result = RegExpMatcher(R, S, lastIndex, sticky);
     if (result === null) {
-        // Steps 15.a.i-ii, 15.c.i.1-2.
+        // Steps 12.a.i-ii, 12.c.i.1-2.
         R.lastIndex = 0;
     } else {
-        // Step 18.
+        // Step 15.
         if (global || sticky)
             R.lastIndex = result.index + result[0].length;
     }
 
     return result;
 }
 
 // ES6 21.2.5.13.
--- a/js/src/builtin/SelfHostingDefines.h
+++ b/js/src/builtin/SelfHostingDefines.h
@@ -79,9 +79,17 @@
 // NB: keep these in sync with the copy in jsfriendapi.h.
 #define JSITER_OWNONLY    0x8   /* iterate over obj's own properties only */
 #define JSITER_HIDDEN     0x10  /* also enumerate non-enumerable properties */
 #define JSITER_SYMBOLS    0x20  /* also include symbol property keys */
 #define JSITER_SYMBOLSONLY 0x40 /* exclude string property keys */
 
 #define TELEMETRY_DEFINE_GETTER_SETTER_THIS_NULL_UNDEFINED 25
 
+#define REGEXP_FLAGS_SLOT 2
+
+#define REGEXP_IGNORECASE_FLAG  0x01
+#define REGEXP_GLOBAL_FLAG      0x02
+#define REGEXP_MULTILINE_FLAG   0x04
+#define REGEXP_STICKY_FLAG      0x08
+#define REGEXP_UNICODE_FLAG     0x10
+
 #endif
--- a/js/src/jit-test/tests/ion/testStringMatch.js
+++ b/js/src/jit-test/tests/ion/testStringMatch.js
@@ -64,56 +64,8 @@ testMod(() => {
 });
 
 var orig_match = RegExp.prototype[Symbol.match];
 testMod(() => {
   RegExp.prototype[Symbol.match] = () => ["mod"];
 }, () => {
   RegExp.prototype[Symbol.match] = orig_match;
 });
-
-var observed = false;
-function testObserved(apply, unapply) {
-  var f = function(applied) {
-    observed = false;
-    var result = "abc".match("b."); // Use meta char to avoid flat match.
-    assertEq(result.length, 1);
-    assertEq(result.index, 1);
-    assertEq(result[0], "bc");
-    assertEq(observed, applied);
-  };
-  var applied = false;
-  for (var i = 0; i < 120; i++) {
-    f(applied);
-    if (i == 40) {
-      apply();
-      applied = true;
-    }
-    if (i == 80) {
-      unapply();
-      applied = false;
-    }
-  }
-}
-
-var orig_global = Object.getOwnPropertyDescriptor(RegExp.prototype, "global");
-testObserved(() => {
-  Object.defineProperty(RegExp.prototype, "global", {
-    get: function() {
-      observed = true;
-      return false;
-    }
-  });
-}, () => {
-  Object.defineProperty(RegExp.prototype, "global", orig_global);
-});
-
-var orig_sticky = Object.getOwnPropertyDescriptor(RegExp.prototype, "sticky");
-testObserved(() => {
-  Object.defineProperty(RegExp.prototype, "sticky", {
-    get: function() {
-      observed = true;
-      return false;
-    }
-  });
-}, () => {
-  Object.defineProperty(RegExp.prototype, "sticky", orig_sticky);
-});
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -7,16 +7,17 @@
 #ifndef vm_RegExpObject_h
 #define vm_RegExpObject_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 
 #include "jscntxt.h"
 
+#include "builtin/SelfHostingDefines.h"
 #include "gc/Marking.h"
 #include "gc/Zone.h"
 #include "proxy/Proxy.h"
 #include "vm/ArrayObject.h"
 #include "vm/Shape.h"
 
 /*
  * JavaScript Regular Expressions
@@ -52,16 +53,23 @@ enum RegExpFlag
     MultilineFlag   = 0x04,
     StickyFlag      = 0x08,
     UnicodeFlag     = 0x10,
 
     NoFlags         = 0x00,
     AllFlags        = 0x1f
 };
 
+static_assert(IgnoreCaseFlag == REGEXP_IGNORECASE_FLAG &&
+              GlobalFlag == REGEXP_GLOBAL_FLAG &&
+              MultilineFlag == REGEXP_MULTILINE_FLAG &&
+              StickyFlag == REGEXP_STICKY_FLAG &&
+              UnicodeFlag == REGEXP_UNICODE_FLAG,
+              "Flag values should be in sync with self-hosted JS");
+
 enum RegExpRunStatus
 {
     RegExpRunStatus_Error,
     RegExpRunStatus_Success,
     RegExpRunStatus_Success_NotFound
 };
 
 extern RegExpObject*
@@ -390,16 +398,19 @@ class RegExpCompartment
 };
 
 class RegExpObject : public NativeObject
 {
     static const unsigned LAST_INDEX_SLOT          = 0;
     static const unsigned SOURCE_SLOT              = 1;
     static const unsigned FLAGS_SLOT               = 2;
 
+    static_assert(RegExpObject::FLAGS_SLOT == REGEXP_FLAGS_SLOT,
+                  "FLAGS_SLOT values should be in sync with self-hosted JS");
+
   public:
     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.