Commit 8b48aa1c authored by petermarshall's avatar petermarshall Committed by Commit bot

[builtins] Move StringIncludes to a builtin.

Also add a test for when the first argument is null or undefined, as there are no tests that cover this currently.

BUG=v8:5364

Review-Url: https://codereview.chromium.org/2399423003
Cr-Commit-Position: refs/heads/master@{#40127}
parent b75a0c4a
......@@ -1437,6 +1437,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
1, true);
SimpleInstallFunction(prototype, "charCodeAt",
Builtins::kStringPrototypeCharCodeAt, 1, true);
SimpleInstallFunction(prototype, "includes",
Builtins::kStringPrototypeIncludes, 1, false);
SimpleInstallFunction(prototype, "indexOf",
Builtins::kStringPrototypeIndexOf, 1, false);
SimpleInstallFunction(prototype, "lastIndexOf",
......
......@@ -17,27 +17,6 @@ namespace internal {
namespace {
// ES#sec-isregexp IsRegExp ( argument )
Maybe<bool> IsRegExp(Isolate* isolate, Handle<Object> object) {
if (!object->IsJSReceiver()) return Just(false);
Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
if (isolate->regexp_function()->initial_map() == receiver->map()) {
// Fast-path for unmodified JSRegExp instances.
return Just(true);
}
Handle<Object> match;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, match,
JSObject::GetProperty(receiver, isolate->factory()->match_symbol()),
Nothing<bool>());
if (!match->IsUndefined(isolate)) return Just(match->BooleanValue());
return Just(object->IsJSRegExp());
}
Handle<String> PatternFlags(Isolate* isolate, Handle<JSRegExp> regexp) {
static const int kMaxFlagsLength = 5 + 1; // 5 flags and '\0';
char flags_string[kMaxFlagsLength];
......@@ -100,7 +79,7 @@ BUILTIN(RegExpConstructor) {
bool pattern_is_regexp;
{
Maybe<bool> maybe_pattern_is_regexp = IsRegExp(isolate, pattern);
Maybe<bool> maybe_pattern_is_regexp = Object::IsRegExp(isolate, pattern);
if (maybe_pattern_is_regexp.IsNothing()) {
DCHECK(isolate->has_pending_exception());
return isolate->heap()->exception();
......
......@@ -781,6 +781,41 @@ void Builtins::Generate_StringPrototypeCharCodeAt(
assembler->Return(result);
}
// ES6 section 21.1.3.7
// String.prototype.includes ( searchString [ , position ] )
BUILTIN(StringPrototypeIncludes) {
HandleScope handle_scope(isolate);
TO_THIS_STRING(str, "String.prototype.includes");
// Check if the search string is a regExp and fail if it is.
Handle<Object> search = args.atOrUndefined(isolate, 1);
Maybe<bool> is_reg_exp = Object::IsRegExp(isolate, search);
if (is_reg_exp.IsNothing()) {
DCHECK(isolate->has_pending_exception());
return isolate->heap()->exception();
}
if (is_reg_exp.FromJust()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kFirstArgumentNotRegExp,
isolate->factory()->NewStringFromStaticChars(
"String.prototype.includes")));
}
Handle<String> search_string;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, search_string,
Object::ToString(isolate, search));
Handle<Object> position;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, position,
Object::ToInteger(isolate, args.atOrUndefined(isolate, 2)));
double index = std::max(position->Number(), 0.0);
index = std::min(index, static_cast<double>(str->length()));
int index_in_str = String::IndexOf(isolate, str, search_string,
static_cast<uint32_t>(index));
return *isolate->factory()->ToBoolean(index_in_str != -1);
}
// ES6 section 21.1.3.8 String.prototype.indexOf ( searchString [ , position ] )
BUILTIN(StringPrototypeIndexOf) {
HandleScope handle_scope(isolate);
......
......@@ -609,6 +609,9 @@ namespace internal {
TFJ(StringPrototypeCharAt, 2) \
/* ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos ) */ \
TFJ(StringPrototypeCharCodeAt, 2) \
/* ES6 section 21.1.3.7 */ \
/* String.prototype.includes ( searchString [ , position ] ) */ \
CPP(StringPrototypeIncludes) \
/* ES6 section 21.1.3.8 */ \
/* String.prototype.indexOf ( searchString [ , position ] ) */ \
CPP(StringPrototypeIndexOf) \
......
......@@ -433,34 +433,6 @@ function StringEndsWith(searchString, position) { // length == 1
%FunctionSetLength(StringEndsWith, 1);
// ES6 draft 04-05-14, section 21.1.3.6
function StringIncludes(searchString, position) { // length == 1
CHECK_OBJECT_COERCIBLE(this, "String.prototype.includes");
var string = TO_STRING(this);
if (IsRegExp(searchString)) {
throw %make_type_error(kFirstArgumentNotRegExp, "String.prototype.includes");
}
searchString = TO_STRING(searchString);
var pos = TO_INTEGER(position);
var stringLength = string.length;
if (pos < 0) pos = 0;
if (pos > stringLength) pos = stringLength;
var searchStringLength = searchString.length;
if (searchStringLength + pos > stringLength) {
return false;
}
return %StringIndexOf(string, searchString, pos) !== -1;
}
%FunctionSetLength(StringIncludes, 1);
// ES6 Draft 05-22-2014, section 21.1.3.3
function StringCodePointAt(pos) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.codePointAt");
......@@ -519,7 +491,6 @@ utils.InstallFunctions(GlobalString.prototype, DONT_ENUM, [
"codePointAt", StringCodePointAt,
"concat", StringConcat,
"endsWith", StringEndsWith,
"includes", StringIncludes,
"match", StringMatchJS,
"repeat", StringRepeat,
"replace", StringReplace,
......
......@@ -1977,6 +1977,26 @@ Object* GetSimpleHash(Object* object) {
} // namespace
Maybe<bool> Object::IsRegExp(Isolate* isolate, Handle<Object> object) {
if (!object->IsJSReceiver()) return Just(false);
Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
if (isolate->regexp_function()->initial_map() == receiver->map()) {
// Fast-path for unmodified JSRegExp instances.
return Just(true);
}
Handle<Object> match;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, match,
JSObject::GetProperty(receiver, isolate->factory()->match_symbol()),
Nothing<bool>());
if (!match->IsUndefined(isolate)) return Just(match->BooleanValue());
return Just(object->IsJSRegExp());
}
Object* Object::GetHash() {
Object* hash = GetSimpleHash(this);
if (hash->IsSmi()) return hash;
......
......@@ -1376,6 +1376,10 @@ class Object {
Isolate* isolate, Handle<Object> object, uint32_t index,
Handle<Object> value, LanguageMode language_mode);
// ES#sec-isregexp IsRegExp ( argument )
// Includes checking of the mach property as per section 7.2.8 IsRegExp.
static Maybe<bool> IsRegExp(Isolate* isolate, Handle<Object> object);
// Returns the permanent hash code associated with this object. May return
// undefined if not yet created.
Object* GetHash();
......
......@@ -27,6 +27,11 @@
assertEquals(1, String.prototype.includes.length);
var s = 'a';
assertFalse(s.includes(null));
assertFalse(s.includes(undefined));
assertFalse(s.includes());
var reString = "asdf[a-z]+(asdf)?";
assertTrue(reString.includes("[a-z]+"));
assertTrue(reString.includes("(asdf)?"));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment