--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -640,17 +640,16 @@ const JSFunctionSpec js::regexp_methods[
#if JS_HAS_TOSOURCE
JS_SELF_HOSTED_FN(js_toSource_str, "RegExpToString", 0, 0),
#endif
JS_SELF_HOSTED_FN(js_toString_str, "RegExpToString", 0, 0),
JS_FN("compile", regexp_compile, 2,0),
JS_SELF_HOSTED_FN("exec", "RegExp_prototype_Exec", 1,0),
JS_SELF_HOSTED_FN("test", "RegExpTest" , 1,0),
JS_SELF_HOSTED_SYM_FN(match, "RegExpMatch", 1,0),
- JS_SELF_HOSTED_SYM_FN(search, "RegExpSearch", 1,0),
JS_FS_END
};
#define STATIC_PAREN_GETTER_CODE(parenNum) \
if (!res->createParen(cx, parenNum, args.rval())) \
return false; \
if (args.rval().isUndefined()) \
args.rval().setString(cx->runtime()->emptyString); \
@@ -1081,22 +1080,24 @@ js::RegExpPrototypeOptimizableRaw(JSCont
bool has = false;
if (!HasOwnDataPropertyPure(cx, proto, SYMBOL_TO_JSID(cx->wellKnownSymbols().match), &has))
return false;
if (!has) {
*result = false;
return true;
}
+ /*
if (!HasOwnDataPropertyPure(cx, proto, SYMBOL_TO_JSID(cx->wellKnownSymbols().search), &has))
return false;
if (!has) {
*result = false;
return true;
}
+ */
if (!HasOwnDataPropertyPure(cx, proto, NameToId(cx->names().exec), &has))
return false;
if (!has) {
*result = false;
return true;
}
--- a/js/src/builtin/RegExp.js
+++ b/js/src/builtin/RegExp.js
@@ -142,48 +142,16 @@ function RegExpMatch(string) {
rx.lastIndex = fullUnicode ? AdvanceStringIndex(S, lastIndex) : lastIndex + 1;
}
// Step 6.e.iii.5.
n++;
}
}
-// ES 2016 draft Mar 25, 2016 21.2.5.9.
-function RegExpSearch(string) {
- // Step 1.
- var rx = this;
-
- // Step 2.
- if (!IsObject(rx))
- ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, rx === null ? "null" : typeof rx);
-
- // Step 3.
- var S = ToString(string);
-
- // Step 4.
- var previousLastIndex = rx.lastIndex;
-
- // Step 5.
- rx.lastIndex = 0;
-
- // Step 6.
- var result = RegExpExec(rx, S, false);
-
- // Step 7.
- rx.lastIndex = previousLastIndex;
-
- // Step 8.
- if (result === null)
- return -1;
-
- // Step 9.
- return result.index;
-}
-
// ES6 21.2.5.2.
// NOTE: This is not RegExpExec (21.2.5.2.1).
function RegExp_prototype_Exec(string) {
// Steps 1-3.
var R = this;
if (!IsObject(R) || !IsRegExpObject(R))
return callFunction(CallRegExpMethodIfWrapped, R, string, "RegExp_prototype_Exec");
--- a/js/src/builtin/String.js
+++ b/js/src/builtin/String.js
@@ -66,79 +66,16 @@ function String_match(regexp) {
}
function String_generic_match(thisValue, regexp) {
if (thisValue === undefined)
ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.match');
return callFunction(String_match, thisValue, regexp);
}
-function StringProtoHasNoSearch() {
- var ObjectProto = GetBuiltinPrototype("Object");
- var StringProto = GetBuiltinPrototype("String");
- if (!ObjectHasPrototype(StringProto, ObjectProto))
- return false;
- return !(std_search in StringProto);
-}
-
-function IsStringSearchOptimizable() {
- var RegExpProto = GetBuiltinPrototype("RegExp");
- // If RegExpPrototypeOptimizable succeeds, `exec` and `@@search` are
- // guaranteed to be data properties.
- return RegExpPrototypeOptimizable(RegExpProto) &&
- RegExpProto.exec === RegExp_prototype_Exec &&
- RegExpProto[std_search] === RegExpSearch;
-}
-
-// ES 2016 draft Mar 25, 2016 21.1.3.15.
-function String_search(regexp) {
- // Step 1.
- RequireObjectCoercible(this);
-
- // Step 2.
- var isPatternString = (typeof regexp === "string");
- if (!(isPatternString && StringProtoHasNoSearch()) && regexp !== undefined && regexp !== null) {
- // Step 2.a.
- var searcher = regexp[std_search];
-
- // Step 2.b.
- if (searcher !== undefined)
- return callContentFunction(searcher, regexp, this);
- }
-
- // Step 3.
- var string = ToString(this);
-
- // FIXME: Non-standard flags argument (bug 1108382).
- var flags = undefined;
- if (arguments.length > 1) {
- if (IsMatchFlagsArgumentEnabled())
- flags = arguments[1];
- WarnOnceAboutFlagsArgument();
- } else {
- if (isPatternString && IsStringSearchOptimizable()) {
- var flatResult = FlatStringSearch(string, regexp);
- if (flatResult !== -2)
- return flatResult;
- }
- }
-
- // Step 4.
- var rx = RegExpCreate(regexp, flags);
-
- // Step 5.
- return callContentFunction(GetMethod(rx, std_search), rx, string);
-}
-
-function String_generic_search(thisValue, regexp) {
- if (thisValue === undefined)
- ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.search');
- return callFunction(String_search, thisValue, regexp);
-}
-
/* ES6 Draft Oct 14, 2014 21.1.3.19 */
function String_substring(start, end) {
// Steps 1-3.
RequireObjectCoercible(this);
var str = ToString(this);
// Step 4.
var len = str.length;
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2184,17 +2184,18 @@ MustCloneRegExpForCall(MCall* call, uint
// this is a native call that does not let the regex escape.
JSFunction* target = call->getSingleTarget();
if (!target || !target->isNative())
return true;
if (useIndex == MCall::IndexOfArgument(0) &&
(target->native() == str_split ||
- target->native() == str_replace))
+ target->native() == str_replace ||
+ target->native() == str_search))
{
return false;
}
return true;
}
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -4861,17 +4861,16 @@ GetSymbolFor(JSContext* cx, HandleString
*/
JS_PUBLIC_API(JSString*)
GetSymbolDescription(HandleSymbol symbol);
/* Well-known symbols. */
#define JS_FOR_EACH_WELL_KNOWN_SYMBOL(macro) \
macro(iterator) \
macro(match) \
- macro(search) \
macro(species) \
macro(toPrimitive) \
macro(unscopables)
enum class SymbolCode : uint32_t {
// There is one SymbolCode for each well-known symbol.
#define JS_DEFINE_SYMBOL_ENUM(name) name,
JS_FOR_EACH_WELL_KNOWN_SYMBOL(JS_DEFINE_SYMBOL_ENUM) // SymbolCode::iterator, etc.
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -2290,16 +2290,61 @@ AdvanceStringIndex(HandleLinearString in
/* Step 10. */
if (!unicode::IsTrailSurrogate(second))
return index + 1;
/* Step 11. */
return index + 2;
}
+bool
+js::str_search(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ RootedString str(cx, ThisToStringForStringProto(cx, args));
+ if (!str)
+ return false;
+
+ StringRegExpGuard g(cx);
+ if (!g.init(cx, args, true))
+ return false;
+ if (const FlatMatch* fm = g.tryFlatMatch(cx, str, 1, args.length())) {
+ args.rval().setInt32(fm->match());
+ return true;
+ }
+
+ if (cx->isExceptionPending()) /* from tryFlatMatch */
+ return false;
+
+ if (!g.normalizeRegExp(cx, false, 1, args))
+ return false;
+
+ RootedLinearString linearStr(cx, str->ensureLinear(cx));
+ if (!linearStr)
+ return false;
+
+ RegExpStatics* res = cx->global()->getRegExpStatics(cx);
+ if (!res)
+ return false;
+
+ /* Per ECMAv5 15.5.4.12 (5) The last index property is ignored and left unchanged. */
+ ScopedMatchPairs matches(&cx->tempLifoAlloc());
+ RegExpShared& re = g.regExp();
+ bool sticky = re.sticky();
+ RegExpRunStatus status = re.execute(cx, linearStr, 0, sticky, &matches, nullptr);
+ if (status == RegExpRunStatus_Error)
+ return false;
+
+ if (status == RegExpRunStatus_Success)
+ res->updateLazily(cx, linearStr, &re, 0, sticky);
+
+ args.rval().setInt32(status == RegExpRunStatus_Success_NotFound ? -1 : matches[0].start);
+ return true;
+}
+
// Utility for building a rope (lazy concatenation) of strings.
class RopeBuilder {
JSContext* cx;
RootedString res;
RopeBuilder(const RopeBuilder& other) = delete;
void operator=(const RopeBuilder& other) = delete;
@@ -3943,17 +3988,17 @@ static const JSFunctionSpec string_metho
#endif
JS_SELF_HOSTED_FN("repeat", "String_repeat", 1,0),
#if EXPOSE_INTL_API
JS_FN("normalize", str_normalize, 0,JSFUN_GENERIC_NATIVE),
#endif
/* Perl-ish methods (search is actually Python-esque). */
JS_SELF_HOSTED_FN("match", "String_match", 1,0),
- JS_SELF_HOSTED_FN("search", "String_search", 1,0),
+ JS_FN("search", str_search, 1,JSFUN_GENERIC_NATIVE),
JS_INLINABLE_FN("replace", str_replace, 2,JSFUN_GENERIC_NATIVE, StringReplace),
JS_INLINABLE_FN("split", str_split, 2,JSFUN_GENERIC_NATIVE, StringSplit),
JS_SELF_HOSTED_FN("substr", "String_substr", 2,0),
/* Python-esque sequence methods. */
JS_FN("concat", str_concat, 1,JSFUN_GENERIC_NATIVE),
JS_SELF_HOSTED_FN("slice", "String_slice", 2,0),
@@ -4098,17 +4143,16 @@ static const JSFunctionSpec string_stati
JS_SELF_HOSTED_FN("fromCodePoint", "String_static_fromCodePoint", 1,0),
JS_SELF_HOSTED_FN("raw", "String_static_raw", 2,JSFUN_HAS_REST),
JS_SELF_HOSTED_FN("substring", "String_static_substring", 3,0),
JS_SELF_HOSTED_FN("substr", "String_static_substr", 3,0),
JS_SELF_HOSTED_FN("slice", "String_static_slice", 3,0),
JS_SELF_HOSTED_FN("match", "String_generic_match", 2,0),
- JS_SELF_HOSTED_FN("search", "String_generic_search", 2,0),
// This must be at the end because of bug 853075: functions listed after
// self-hosted methods aren't available in self-hosted code.
#if EXPOSE_INTL_API
JS_SELF_HOSTED_FN("localeCompare", "String_static_localeCompare", 2,0),
#endif
JS_FS_END
};
@@ -5255,39 +5299,8 @@ js::FlatStringMatch(JSContext* cx, unsig
if (!isFlat) {
args.rval().setUndefined();
return true;
}
return BuildFlatMatchArray(cx, str, pattern, match, args.rval());
}
-
-bool
-js::FlatStringSearch(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- MOZ_ASSERT(args.length() == 2);
- MOZ_ASSERT(args[0].isString());
- MOZ_ASSERT(args[1].isString());
-#ifdef DEBUG
- bool isOptimizable = false;
- if (!CallIsStringOptimizable(cx, "IsStringSearchOptimizable", &isOptimizable))
- return false;
- MOZ_ASSERT(isOptimizable);
-#endif
-
- RootedString str(cx,args[0].toString());
- RootedString pattern(cx, args[1].toString());
-
- bool isFlat = false;
- int32_t match = 0;
- if (!FlatStringMatchHelper(cx, str, pattern, &isFlat, &match))
- return false;
-
- if (!isFlat) {
- args.rval().setInt32(-2);
- return true;
- }
-
- args.rval().setInt32(match);
- return true;
-}
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -426,16 +426,19 @@ FileEscapedString(FILE* fp, const char*
{
Fprinter out(fp);
bool res = EscapedStringPrinter(out, chars, length, quote);
out.finish();
return res;
}
bool
+str_search(JSContext* cx, unsigned argc, Value* vp);
+
+bool
str_split(JSContext* cx, unsigned argc, Value* vp);
JSObject*
str_split_string(JSContext* cx, HandleObjectGroup group, HandleString str, HandleString sep);
JSString *
str_flat_replace_string(JSContext *cx, HandleString string, HandleString pattern,
HandleString replacement);
@@ -445,14 +448,11 @@ str_replace_string_raw(JSContext* cx, Ha
HandleString replacement);
extern bool
StringConstructor(JSContext* cx, unsigned argc, Value* vp);
extern bool
FlatStringMatch(JSContext* cx, unsigned argc, Value* vp);
-extern bool
-FlatStringSearch(JSContext* cx, unsigned argc, Value* vp);
-
} /* namespace js */
#endif /* jsstr_h */
deleted file mode 100644
--- a/js/src/tests/ecma_6/RegExp/search-this.js
+++ /dev/null
@@ -1,12 +0,0 @@
-var BUGNUMBER = 887016;
-var summary = "RegExp.prototype[@@search] should check this value.";
-
-print(BUGNUMBER + ": " + summary);
-
-for (var v of [null, 1, true, undefined, "", Symbol.iterator]) {
- assertThrowsInstanceOf(() => RegExp.prototype[Symbol.search].call(v),
- TypeError);
-}
-
-if (typeof reportCompare === "function")
- reportCompare(true, true);
deleted file mode 100644
--- a/js/src/tests/ecma_6/RegExp/search-trace.js
+++ /dev/null
@@ -1,76 +0,0 @@
-var BUGNUMBER = 887016;
-var summary = "Trace RegExp.prototype[@@search] behavior.";
-
-print(BUGNUMBER + ": " + summary);
-
-var n;
-var log;
-var target;
-
-var execResult;
-var lastIndexResult;
-var lastIndexExpected;
-
-function P(index) {
- return new Proxy({ index }, {
- get(that, name) {
- log += "get:result[" + name + "],";
- return that[name];
- }
- });
-}
-
-var myRegExp = {
- get lastIndex() {
- log += "get:lastIndex,";
- return lastIndexResult[n];
- },
- set lastIndex(v) {
- log += "set:lastIndex,";
- assertEq(v, lastIndexExpected[n]);
- },
- get exec() {
- log += "get:exec,";
- return function(S) {
- log += "call:exec,";
- assertEq(S, target);
- return execResult[n++];
- };
- },
-};
-
-function reset() {
- n = 0;
- log = "";
- target = "abcAbcABC";
-}
-
-// Trace hit.
-reset();
-execResult = [ P(16) ];
-lastIndexResult = [ 10, , ];
-lastIndexExpected = [ 0, 10 ];
-var ret = RegExp.prototype[Symbol.search].call(myRegExp, target);
-assertEq(ret, 16);
-assertEq(log,
- "get:lastIndex," +
- "set:lastIndex," +
- "get:exec,call:exec," +
- "set:lastIndex," +
- "get:result[index],");
-
-// Trace not hit.
-reset();
-execResult = [ null ];
-lastIndexResult = [ 10, , ];
-lastIndexExpected = [ 0, 10 ];
-ret = RegExp.prototype[Symbol.search].call(myRegExp, target);
-assertEq(ret, -1);
-assertEq(log,
- "get:lastIndex," +
- "set:lastIndex," +
- "get:exec,call:exec," +
- "set:lastIndex,");
-
-if (typeof reportCompare === "function")
- reportCompare(true, true);
deleted file mode 100644
--- a/js/src/tests/ecma_6/RegExp/search.js
+++ /dev/null
@@ -1,26 +0,0 @@
-var BUGNUMBER = 887016;
-var summary = "Implement RegExp.prototype[@@search].";
-
-print(BUGNUMBER + ": " + summary);
-
-assertEq(RegExp.prototype[Symbol.search].name, "[Symbol.search]");
-assertEq(RegExp.prototype[Symbol.search].length, 1);
-var desc = Object.getOwnPropertyDescriptor(RegExp.prototype, Symbol.search);
-assertEq(desc.configurable, true);
-assertEq(desc.enumerable, false);
-assertEq(desc.writable, true);
-
-var re = /B/;
-var v = re[Symbol.search]("abcAbcABC");
-assertEq(v, 7);
-
-re = /B/i;
-v = re[Symbol.search]("abcAbcABCD");
-assertEq(v, 1);
-
-re = /d/;
-v = re[Symbol.search]("abcAbcABCD");
-assertEq(v, -1);
-
-if (typeof reportCompare === "function")
- reportCompare(true, true);
deleted file mode 100644
--- a/js/src/tests/ecma_6/String/search.js
+++ /dev/null
@@ -1,27 +0,0 @@
-var BUGNUMBER = 887016;
-var summary = "Call RegExp.prototype[@@search] from String.prototype.search.";
-
-print(BUGNUMBER + ": " + summary);
-
-var called = 0;
-var myRegExp = {
- [Symbol.search](S) {
- assertEq(S, "abcAbcABC");
- called++;
- return 42;
- }
-};
-assertEq("abcAbcABC".search(myRegExp), 42);
-assertEq(called, 1);
-
-called = 0;
-RegExp.prototype[Symbol.search] = function(S) {
- assertEq(S, "abcAbcABC");
- called++;
- return 43;
-};
-assertEq("abcAbcABC".search("abc"), 43);
-assertEq(called, 1);
-
-if (typeof reportCompare === "function")
- reportCompare(true, true);
--- a/js/src/tests/ecma_6/Symbol/well-known.js
+++ b/js/src/tests/ecma_6/Symbol/well-known.js
@@ -1,15 +1,14 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
var names = [
"iterator",
"match",
- "search",
"species",
"toPrimitive",
"unscopables"
];
for (var name of names) {
// Well-known symbols exist.
assertEq(typeof Symbol[name], "symbol");
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -303,25 +303,23 @@
macro(number, number, "number") \
macro(boolean, boolean, "boolean") \
macro(null, null, "null") \
macro(symbol, symbol, "symbol") \
/* Well-known atom names must be continuous and ordered, matching \
* enum JS::SymbolCode in jsapi.h. */ \
macro(iterator, iterator, "iterator") \
macro(match, match, "match") \
- macro(search, search, "search") \
macro(species, species, "species") \
macro(toPrimitive, toPrimitive, "toPrimitive") \
macro(unscopables, unscopables, "unscopables") \
/* Same goes for the descriptions of the well-known symbols. */ \
macro(Symbol_hasInstance, Symbol_hasInstance, "Symbol.hasInstance") \
macro(Symbol_isConcatSpreadable, Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable") \
macro(Symbol_iterator, Symbol_iterator, "Symbol.iterator") \
macro(Symbol_match, Symbol_match, "Symbol.match") \
- macro(Symbol_search, Symbol_search, "Symbol.search") \
macro(Symbol_species, Symbol_species, "Symbol.species") \
macro(Symbol_toPrimitive, Symbol_toPrimitive, "Symbol.toPrimitive") \
macro(Symbol_unscopables, Symbol_unscopables, "Symbol.unscopables") \
/* Function names for properties named by symbols. */ \
macro(Symbol_iterator_fun, Symbol_iterator_fun, "[Symbol.iterator]") \
#endif /* vm_CommonPropertyNames_h */
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -456,24 +456,16 @@ GlobalObject::initSelfHostingBuiltins(JS
RootedValue std_match(cx);
std_match.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::match));
if (!JS_DefineProperty(cx, global, "std_match", std_match,
JSPROP_PERMANENT | JSPROP_READONLY))
{
return false;
}
- RootedValue std_search(cx);
- std_search.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::search));
- if (!JS_DefineProperty(cx, global, "std_search", std_search,
- JSPROP_PERMANENT | JSPROP_READONLY))
- {
- return false;
- }
-
RootedValue std_species(cx);
std_species.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::species));
if (!JS_DefineProperty(cx, global, "std_species", std_species,
JSPROP_PERMANENT | JSPROP_READONLY))
{
return false;
}
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2416,17 +2416,16 @@ static const JSFunctionSpec intrinsic_fu
RegExpTester),
JS_FN("RegExpCreate", intrinsic_RegExpCreate, 2,0),
JS_INLINABLE_FN("RegExpPrototypeOptimizable", RegExpPrototypeOptimizable, 1,0,
RegExpPrototypeOptimizable),
JS_INLINABLE_FN("RegExpInstanceOptimizable", RegExpInstanceOptimizable, 1,0,
RegExpInstanceOptimizable),
JS_FN("FlatStringMatch", FlatStringMatch, 2,0),
- JS_FN("FlatStringSearch", FlatStringSearch, 2,0),
// See builtin/RegExp.h for descriptions of the regexp_* functions.
JS_FN("regexp_exec_no_statics", regexp_exec_no_statics, 2,0),
JS_FN("regexp_test_no_statics", regexp_test_no_statics, 2,0),
JS_FN("regexp_construct", regexp_construct_self_hosting, 2,0),
JS_FN("IsMatchFlagsArgumentEnabled", IsMatchFlagsArgumentEnabled, 0,0),
JS_FN("WarnOnceAboutFlagsArgument", WarnOnceAboutFlagsArgument, 0,0),
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -222,17 +222,17 @@ https://bugzilla.mozilla.org/show_bug.cg
gPrototypeProperties['Function'] =
["constructor", "toSource", "toString", "apply", "call", "bind",
"isGenerator", "length", "name", "arguments", "caller"];
gConstructorProperties['Function'] = constructorProps([])
gPrototypeProperties['RegExp'] =
["constructor", "toSource", "toString", "compile", "exec", "test",
- Symbol.match, Symbol.search,
+ Symbol.match,
"flags", "global", "ignoreCase", "multiline", "source", "sticky", "unicode",
"lastIndex"];
gConstructorProperties['RegExp'] =
constructorProps(["input", "lastMatch", "lastParen",
"leftContext", "rightContext", "$1", "$2", "$3", "$4",
"$5", "$6", "$7", "$8", "$9", "$_", "$&", "$+",
"$`", "$'"])