diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index b9892825927..3b676880d2f 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1343,6 +1343,8 @@ match_or_replace(JSContext *cx, destroy(cx, data); } } else { + jsval savedObject = JSVAL_NULL; + if (GET_MODE(data->flags) == MODE_REPLACE) { test = JS_TRUE; } else { @@ -1350,7 +1352,10 @@ match_or_replace(JSContext *cx, * MODE_MATCH implies str_match is being called from a script or a * scripted function. If the caller cares only about testing null * vs. non-null return value, optimize away the array object that - * would normally be returned in *vp. + * would normally be returned in *vp. Instead return an arbitrary + * object (not JSVAL_TRUE, for type map integrity; see bug 453564). + * The caller provides the object in *vp and is responsible for + * rooting it elsewhere. * * Assume a full array result is required, then prove otherwise. */ @@ -1364,12 +1369,16 @@ match_or_replace(JSContext *cx, case JSOP_IFEQX: case JSOP_IFNEX: test = JS_TRUE; + savedObject = *vp; + JS_ASSERT(!JSVAL_IS_PRIMITIVE(savedObject)); break; default:; } } } ok = js_ExecuteRegExp(cx, re, str, &index, test, vp); + if (ok && !JSVAL_IS_NULL(savedObject) && *vp == JSVAL_TRUE) + *vp = savedObject; } DROP_REGEXP(cx, re); @@ -1418,8 +1427,8 @@ match_glob(JSContext *cx, jsint count, GlobData *data) return OBJ_SET_PROPERTY(cx, arrayobj, INT_TO_JSID(count), &v); } -JSBool -js_StringMatchHelper(JSContext *cx, uintN argc, jsval *vp, jsbytecode *pc) +static JSBool +StringMatchHelper(JSContext *cx, uintN argc, jsval *vp, jsbytecode *pc) { JSTempValueRooter tvr; MatchData mdata; @@ -1444,29 +1453,32 @@ str_match(JSContext *cx, uintN argc, jsval *vp) for (fp = js_GetTopStackFrame(cx); fp && !fp->regs; fp = fp->down) JS_ASSERT(!fp->script); - return js_StringMatchHelper(cx, argc, vp, fp ? fp->regs->pc : NULL); + + /* Root the object in vp[0]. See comment in match_or_replace. */ + JSAutoTempValueRooter tvr(cx, vp[0]); + return StringMatchHelper(cx, argc, vp, fp ? fp->regs->pc : NULL); } #ifdef JS_TRACER static JSObject* FASTCALL String_p_match(JSContext* cx, JSString* str, jsbytecode *pc, JSObject* regexp) { - jsval vp[3] = { JSVAL_NULL, STRING_TO_JSVAL(str), OBJECT_TO_JSVAL(regexp) }; - if (!js_StringMatchHelper(cx, 1, vp, pc)) + /* arbitrary object in vp[0] */ + jsval vp[3] = { OBJECT_TO_JSVAL(regexp), STRING_TO_JSVAL(str), OBJECT_TO_JSVAL(regexp) }; + if (!StringMatchHelper(cx, 1, vp, pc)) return (JSObject*) JSVAL_TO_BOOLEAN(JSVAL_VOID); - JS_ASSERT(JSVAL_IS_NULL(vp[0]) || - (!JSVAL_IS_PRIMITIVE(vp[0]) && OBJ_IS_ARRAY(cx, JSVAL_TO_OBJECT(vp[0])))); + JS_ASSERT(JSVAL_IS_OBJECT(vp[0])); return JSVAL_TO_OBJECT(vp[0]); } static JSObject* FASTCALL String_p_match_obj(JSContext* cx, JSObject* str, jsbytecode *pc, JSObject* regexp) { - jsval vp[3] = { JSVAL_NULL, OBJECT_TO_JSVAL(str), OBJECT_TO_JSVAL(regexp) }; - if (!js_StringMatchHelper(cx, 1, vp, pc)) + /* arbitrary object in vp[0] */ + jsval vp[3] = { OBJECT_TO_JSVAL(regexp), OBJECT_TO_JSVAL(str), OBJECT_TO_JSVAL(regexp) }; + if (!StringMatchHelper(cx, 1, vp, pc)) return (JSObject*) JSVAL_TO_BOOLEAN(JSVAL_VOID); - JS_ASSERT(JSVAL_IS_NULL(vp[0]) || - (!JSVAL_IS_PRIMITIVE(vp[0]) && OBJ_IS_ARRAY(cx, JSVAL_TO_OBJECT(vp[0])))); + JS_ASSERT(JSVAL_IS_OBJECT(vp[0])); return JSVAL_TO_OBJECT(vp[0]); } #endif diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 349754e3f40..46c33b9f8c6 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -617,9 +617,6 @@ extern JSBool js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); -extern JSBool -js_StringMatchHelper(JSContext *cx, uintN argc, jsval *vp, jsbytecode *pc); - extern JSBool js_StringReplaceHelper(JSContext *cx, uintN argc, JSObject *lambda, JSString *repstr, jsval *vp); diff --git a/js/src/trace-test.js b/js/src/trace-test.js index 51b6e1f470c..028e1aaa8eb 100644 --- a/js/src/trace-test.js +++ b/js/src/trace-test.js @@ -887,6 +887,15 @@ function matchInLoop() { matchInLoop.expected = true; test(matchInLoop); +function testMatchAsCondition() { + var a = ['0', '0', '0', '0']; + var r = /0/; + "x".q; + for (var z = 0; z < 4; z++) + a[z].match(r) ? 1 : 2; +} +test(testMatchAsCondition); + function deep1(x) { if (x > 90) return 1;