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 318201 3d31abc6b37d5c69fca3631377c36c09a3fa4d5b
parent 318200 413ad396d8a41b34cbdaf471f3e33c136e1e08fa
child 318202 53b4512a42b434524730ddf84b6f448e0a0d3c80
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs1263340
milestone48.0a1
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.