bug 509143 - js_CloneRegExp is missing a call to js_SetLastIndex. r=mrbkap
authorIgor Bukanov <igor@mir2.org>
Wed, 19 Aug 2009 19:53:51 +0300
changeset 31892 5819b38a86861c70b8c97f4631ec00b693ab1b10
parent 31891 cf4c686996375acfb71d736351fb45c89cc4b812
child 31893 19728bf133dd610100975465a9198c4b648597f7
child 31895 9dd844f6397244a87632f9008cb8264ffca3cbce
push idunknown
push userunknown
push dateunknown
reviewersmrbkap
bugs509143
milestone1.9.3a1pre
bug 509143 - js_CloneRegExp is missing a call to js_SetLastIndex. r=mrbkap
js/src/jsregexp.cpp
js/src/jsregexp.h
js/src/jsstr.cpp
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -4990,32 +4990,62 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp
 
 out:
     JS_ARENA_RELEASE(&cx->regexpPool, mark);
     return ok;
 }
 
 /************************************************************************/
 
+static jsdouble
+GetRegExpLastIndex(JSObject *obj)
+{
+    JS_ASSERT(obj->getClass() == &js_RegExpClass);
+
+    jsval v = obj->fslots[JSSLOT_REGEXP_LAST_INDEX];
+    if (JSVAL_IS_INT(v))
+        return JSVAL_TO_INT(v);
+    JS_ASSERT(JSVAL_IS_DOUBLE(v));
+    return *JSVAL_TO_DOUBLE(v);
+}
+
+static jsval
+GetRegExpLastIndexValue(JSObject *obj)
+{
+    JS_ASSERT(obj->getClass() == &js_RegExpClass);
+    return obj->fslots[JSSLOT_REGEXP_LAST_INDEX];
+}
+
+static JSBool
+SetRegExpLastIndex(JSContext *cx, JSObject *obj, jsdouble lastIndex)
+{
+    JS_ASSERT(obj->getClass() == &js_RegExpClass);
+
+    return JS_NewNumberValue(cx, lastIndex,
+                             &obj->fslots[JSSLOT_REGEXP_LAST_INDEX]);
+}
+
 static JSBool
 regexp_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
     jsint slot;
     JSRegExp *re;
 
     if (!JSVAL_IS_INT(id))
         return JS_TRUE;
     while (OBJ_GET_CLASS(cx, obj) != &js_RegExpClass) {
         obj = OBJ_GET_PROTO(cx, obj);
         if (!obj)
             return JS_TRUE;
     }
     slot = JSVAL_TO_INT(id);
-    if (slot == REGEXP_LAST_INDEX)
-        return JS_GetReservedSlot(cx, obj, 0, vp);
+    if (slot == REGEXP_LAST_INDEX) {
+        *vp = GetRegExpLastIndexValue(obj);
+        return JS_TRUE;
+    }
 
     JS_LOCK_OBJ(cx, obj);
     re = (JSRegExp *) obj->getPrivate();
     if (re) {
         switch (slot) {
           case REGEXP_SOURCE:
             *vp = STRING_TO_JSVAL(re->source);
             break;
@@ -5052,18 +5082,17 @@ regexp_setProperty(JSContext *cx, JSObje
         if (!obj)
             return JS_TRUE;
     }
     slot = JSVAL_TO_INT(id);
     if (slot == REGEXP_LAST_INDEX) {
         if (!JS_ValueToNumber(cx, *vp, &lastIndex))
             return JS_FALSE;
         lastIndex = js_DoubleToInteger(lastIndex);
-        ok = JS_NewNumberValue(cx, lastIndex, vp) &&
-             JS_SetReservedSlot(cx, obj, 0, *vp);
+        ok = SetRegExpLastIndex(cx, obj, lastIndex);
     }
     return ok;
 }
 
 #define REGEXP_PROP_ATTRS     (JSPROP_PERMANENT | JSPROP_SHARED)
 #define RO_REGEXP_PROP_ATTRS  (REGEXP_PROP_ATTRS | JSPROP_READONLY)
 
 #define G regexp_getProperty
@@ -5323,18 +5352,17 @@ js_XDRRegExpObject(JSXDRState *xdr, JSOb
         if (!obj)
             return JS_FALSE;
         STOBJ_CLEAR_PARENT(obj);
         STOBJ_CLEAR_PROTO(obj);
         re = js_NewRegExp(xdr->cx, NULL, source, (uint8)flagsword, JS_FALSE);
         if (!re)
             return JS_FALSE;
         obj->setPrivate(re);
-        if (!js_SetLastIndex(xdr->cx, obj, 0))
-            return JS_FALSE;
+        js_ClearRegExpLastIndex(0);
         *objp = obj;
     }
     return JS_TRUE;
 }
 
 #else  /* !JS_HAS_XDR */
 
 #define js_XDRRegExpObject NULL
@@ -5346,17 +5374,18 @@ regexp_trace(JSTracer *trc, JSObject *ob
 {
     JSRegExp *re = (JSRegExp *) obj->getPrivate();
     if (re && re->source)
         JS_CALL_STRING_TRACER(trc, re->source, "source");
 }
 
 JSClass js_RegExpClass = {
     js_RegExp_str,
-    JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_HAS_RESERVED_SLOTS(REGEXP_CLASS_FIXED_RESERVED_SLOTS) |
     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp),
     JS_PropertyStub,    JS_PropertyStub,
     JS_PropertyStub,    JS_PropertyStub,
     JS_EnumerateStub,   JS_ResolveStub,
     JS_ConvertStub,     regexp_finalize,
     NULL,               NULL,
     regexp_call,        NULL,
     js_XDRRegExpObject, NULL,
@@ -5535,23 +5564,22 @@ regexp_compile_sub(JSContext *cx, JSObje
 
     re = js_NewRegExpOpt(cx, str, opt, JS_FALSE);
 created:
     if (!re)
         return JS_FALSE;
     JS_LOCK_OBJ(cx, obj);
     oldre = (JSRegExp *) obj->getPrivate();
     obj->setPrivate(re);
-
-    JSBool ok = js_SetLastIndex(cx, obj, 0);
+    js_ClearRegExpLastIndex(obj);
     JS_UNLOCK_OBJ(cx, obj);
     if (oldre)
         js_DestroyRegExp(cx, oldre);
     *rval = OBJECT_TO_JSVAL(obj);
-    return ok;
+    return JS_TRUE;
 }
 
 static JSBool
 regexp_compile(JSContext *cx, uintN argc, jsval *vp)
 {
     JSObject *obj;
 
     obj = JS_THIS_OBJECT(cx, vp);
@@ -5576,24 +5604,20 @@ regexp_exec_sub(JSContext *cx, JSObject 
     if (!re) {
         JS_UNLOCK_OBJ(cx, obj);
         return JS_TRUE;
     }
 
     /* NB: we must reach out: after this paragraph, in order to drop re. */
     HOLD_REGEXP(cx, re);
     sticky = (re->flags & JSREG_STICKY) != 0;
-    if (re->flags & (JSREG_GLOB | JSREG_STICKY)) {
-        ok = js_GetLastIndex(cx, obj, &lastIndex);
-    } else {
-        lastIndex = 0;
-    }
+    lastIndex = (re->flags & (JSREG_GLOB | JSREG_STICKY))
+                ? GetRegExpLastIndex(obj)
+                : 0;
     JS_UNLOCK_OBJ(cx, obj);
-    if (!ok)
-        goto out;
 
     /* Now that obj is unlocked, it's safe to (potentially) grab the GC lock. */
     if (argc == 0) {
         str = cx->regExpStatics.input;
         if (!str) {
             const char *bytes = js_GetStringBytes(cx, re->source);
 
             if (bytes) {
@@ -5613,24 +5637,27 @@ regexp_exec_sub(JSContext *cx, JSObject 
         if (!str) {
             ok = JS_FALSE;
             goto out;
         }
         argv[0] = STRING_TO_JSVAL(str);
     }
 
     if (lastIndex < 0 || str->length() < lastIndex) {
-        ok = js_SetLastIndex(cx, obj, 0);
+        js_ClearRegExpLastIndex(obj);
         *rval = JSVAL_NULL;
     } else {
         i = (size_t) lastIndex;
         ok = js_ExecuteRegExp(cx, re, str, &i, test, rval);
         if (ok &&
             ((re->flags & JSREG_GLOB) || (*rval != JSVAL_NULL && sticky))) {
-            ok = js_SetLastIndex(cx, obj, (*rval == JSVAL_NULL) ? 0 : i);
+            if (*rval == JSVAL_NULL)
+                js_ClearRegExpLastIndex(obj);
+            else
+                ok = SetRegExpLastIndex(cx, obj, i);
         }
     }
 
 out:
     DROP_REGEXP(cx, re);
     return ok;
 }
 
@@ -5736,49 +5763,31 @@ js_NewRegExpObject(JSContext *cx, JSToke
     if (!re)
         return NULL;
     obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL);
     if (!obj) {
         js_DestroyRegExp(cx, re);
         return NULL;
     }
     obj->setPrivate(re);
-    if (!js_SetLastIndex(cx, obj, 0))
-        return NULL;
+    js_ClearRegExpLastIndex(obj);
     return obj;
 }
 
 JSObject *
 js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *parent)
 {
     JSObject *clone;
     JSRegExp *re;
 
     JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
     clone = js_NewObject(cx, &js_RegExpClass, NULL, parent);
     if (!clone)
         return NULL;
     re = (JSRegExp *) obj->getPrivate();
     if (re) {
         clone->setPrivate(re);
+        js_ClearRegExpLastIndex(clone);
         HOLD_REGEXP(cx, re);
     }
     return clone;
 }
 
-JSBool
-js_GetLastIndex(JSContext *cx, JSObject *obj, jsdouble *lastIndex)
-{
-    jsval v;
-
-    return JS_GetReservedSlot(cx, obj, 0, &v) &&
-           JS_ValueToNumber(cx, v, lastIndex);
-}
-
-JSBool
-js_SetLastIndex(JSContext *cx, JSObject *obj, jsdouble lastIndex)
-{
-    jsval v;
-
-    return JS_NewNumberValue(cx, lastIndex, &v) &&
-           JS_SetReservedSlot(cx, obj, 0, v);
-}
-
--- a/js/src/jsregexp.h
+++ b/js/src/jsregexp.h
@@ -180,20 +180,21 @@ js_NewRegExpObject(JSContext *cx, JSToke
                    jschar *chars, size_t length, uintN flags);
 
 extern JSBool
 js_XDRRegExpObject(JSXDRState *xdr, JSObject **objp);
 
 extern JSObject *
 js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *parent);
 
-/*
- * Get and set the per-object (clone or clone-parent) lastIndex slot.
- */
-extern JSBool
-js_GetLastIndex(JSContext *cx, JSObject *obj, jsdouble *lastIndex);
+const uint32 JSSLOT_REGEXP_LAST_INDEX = JSSLOT_PRIVATE + 1;
+const uint32 REGEXP_CLASS_FIXED_RESERVED_SLOTS = 1;
 
-extern JSBool
-js_SetLastIndex(JSContext *cx, JSObject *obj, jsdouble lastIndex);
+static inline void
+js_ClearRegExpLastIndex(JSObject *obj)
+{
+    JS_ASSERT(obj->getClass() == &js_RegExpClass);
+    obj->fslots[JSSLOT_REGEXP_LAST_INDEX] = JSVAL_ZERO;
+}
 
 JS_END_EXTERN_C
 
 #endif /* jsregexp_h___ */
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1338,36 +1338,31 @@ match_or_replace(JSContext *cx,
     if (GET_MODE(data->flags) == MODE_SEARCH) {
         ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, vp);
         if (ok) {
             *vp = (*vp == JSVAL_TRUE)
                   ? INT_TO_JSVAL(cx->regExpStatics.leftContext.length)
                   : INT_TO_JSVAL(-1);
         }
     } else if (data->flags & GLOBAL_REGEXP) {
-        if (reobj) {
-            /* Set the lastIndex property's reserved slot to 0. */
-            ok = js_SetLastIndex(cx, reobj, 0);
-        } else {
-            ok = JS_TRUE;
-        }
-        if (ok) {
-            length = str->length();
-            for (count = 0; index <= length; count++) {
-                ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, vp);
-                if (!ok || *vp != JSVAL_TRUE)
+        if (reobj)
+            js_ClearRegExpLastIndex(reobj);
+        length = str->length();
+        ok = true;
+        for (count = 0; index <= length; count++) {
+            ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, vp);
+            if (!ok || *vp != JSVAL_TRUE)
+                break;
+            ok = glob(cx, count, data);
+            if (!ok)
+                break;
+            if (cx->regExpStatics.lastMatch.length == 0) {
+                if (index == length)
                     break;
-                ok = glob(cx, count, data);
-                if (!ok)
-                    break;
-                if (cx->regExpStatics.lastMatch.length == 0) {
-                    if (index == length)
-                        break;
-                    index++;
-                }
+                index++;
             }
         }
     } else {
         if (GET_MODE(data->flags) == MODE_REPLACE) {
             test = JS_TRUE;
         } else {
             /*
              * MODE_MATCH implies str_match is being called from a script or a