Commit 3b39fc4d authored by peterwmwong's avatar peterwmwong Committed by Commit Bot

[esnext] Implement String.prototype.matchAll

Proposal repo: https://github.com/tc39/proposal-string-matchall

- Add new builtins StringPrototypeMatchAll and RegExpPrototypeMatchAll
- Add new object RegExpStringIterator

Bug: v8:6890
Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Change-Id: I9fad71900cf30e8632258c309df1c7a638ea4600
Reviewed-on: https://chromium-review.googlesource.com/981893
Commit-Queue: Peter Wong <peter.wm.wong@gmail.com>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52403}
parent 0872da37
......@@ -798,6 +798,8 @@ action("postmortem-metadata") {
"src/objects/js-array.h",
"src/objects/js-regexp-inl.h",
"src/objects/js-regexp.h",
"src/objects/js-regexp-string-iterator-inl.h",
"src/objects/js-regexp-string-iterator.h",
"src/objects/map.h",
"src/objects/map-inl.h",
"src/objects/script.h",
......@@ -1955,6 +1957,8 @@ v8_source_set("v8_base") {
"src/objects/js-promise-inl.h",
"src/objects/js-promise.h",
"src/objects/js-regexp-inl.h",
"src/objects/js-regexp-string-iterator-inl.h",
"src/objects/js-regexp-string-iterator.h",
"src/objects/js-regexp.h",
"src/objects/literal-objects-inl.h",
"src/objects/literal-objects.cc",
......
......@@ -4205,6 +4205,64 @@ void Genesis::InitializeGlobal_harmony_array_flatten() {
Builtins::kArrayPrototypeFlatMap, 1, false, DONT_ENUM);
}
void Genesis::InitializeGlobal_harmony_string_matchall() {
if (!FLAG_harmony_string_matchall) return;
{ // String.prototype.matchAll
Handle<JSFunction> string_fun(native_context()->string_function());
Handle<JSObject> string_prototype(
JSObject::cast(string_fun->instance_prototype()));
SimpleInstallFunction(string_prototype, "matchAll",
Builtins::kStringPrototypeMatchAll, 1, true);
}
{ // RegExp.prototype[@@matchAll]
Handle<JSFunction> regexp_fun(native_context()->regexp_function());
Handle<JSObject> regexp_prototype(
JSObject::cast(regexp_fun->instance_prototype()));
SimpleInstallFunction(regexp_prototype, factory()->match_all_symbol(),
"[Symbol.matchAll]",
Builtins::kRegExpPrototypeMatchAll, 1, true);
Handle<Map> regexp_prototype_map(regexp_prototype->map());
Map::SetShouldBeFastPrototypeMap(regexp_prototype_map, true, isolate());
native_context()->set_regexp_prototype_map(*regexp_prototype_map);
}
{ // --- R e g E x p S t r i n g I t e r a t o r ---
Handle<JSObject> iterator_prototype(
native_context()->initial_iterator_prototype());
Handle<JSObject> regexp_string_iterator_prototype =
factory()->NewJSObject(isolate()->object_function(), TENURED);
JSObject::ForceSetPrototype(regexp_string_iterator_prototype,
iterator_prototype);
JSObject::AddProperty(
regexp_string_iterator_prototype, factory()->to_string_tag_symbol(),
factory()->NewStringFromAsciiChecked("RegExp String Iterator"),
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
SimpleInstallFunction(regexp_string_iterator_prototype, "next",
Builtins::kRegExpStringIteratorPrototypeNext, 0,
true);
Handle<JSFunction> regexp_string_iterator_function = CreateFunction(
isolate(), factory()->NewStringFromAsciiChecked("RegExpStringIterator"),
JS_REGEXP_STRING_ITERATOR_TYPE, JSRegExpStringIterator::kSize, 0,
regexp_string_iterator_prototype, Builtins::kIllegal);
regexp_string_iterator_function->shared()->set_native(false);
native_context()->set_initial_regexp_string_iterator_prototype_map_index(
regexp_string_iterator_function->initial_map());
}
{ // @@matchAll Symbol
Handle<JSFunction> symbol_fun(native_context()->symbol_function());
InstallConstant(isolate(), symbol_fun, "matchAll",
factory()->match_all_symbol());
}
}
void Genesis::InitializeGlobal_harmony_promise_finally() {
if (!FLAG_harmony_promise_finally) return;
......
......@@ -920,6 +920,8 @@ namespace internal {
TFJ(RegExpPrototypeIgnoreCaseGetter, 0) \
/* ES #sec-regexp.prototype-@@match */ \
TFJ(RegExpPrototypeMatch, 1, kString) \
/* https://tc39.github.io/proposal-string-matchall/ */ \
TFJ(RegExpPrototypeMatchAll, 1, kString) \
/* ES #sec-get-regexp.prototype.multiline */ \
TFJ(RegExpPrototypeMultilineGetter, 0) \
/* ES #sec-regexp.prototype-@@search */ \
......@@ -947,6 +949,10 @@ namespace internal {
TFS(RegExpSearchFast, kReceiver, kPattern) \
TFS(RegExpSplit, kRegExp, kString, kLimit) \
\
/* RegExp String Iterator */ \
/* https://tc39.github.io/proposal-string-matchall/ */ \
TFJ(RegExpStringIteratorPrototypeNext, 0) \
\
/* Set */ \
TFJ(SetConstructor, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
TFJ(SetPrototypeHas, 1, kKey) \
......@@ -1024,6 +1030,8 @@ namespace internal {
TFJ(StringPrototypeLink, 1, kValue) \
/* ES6 #sec-string.prototype.match */ \
TFJ(StringPrototypeMatch, 1, kRegexp) \
/* ES #sec-string.prototype.matchAll */ \
TFJ(StringPrototypeMatchAll, 1, kRegexp) \
/* ES6 #sec-string.prototype.localecompare */ \
CPP(StringPrototypeLocaleCompare) \
/* ES6 #sec-string.prototype.padEnd */ \
......
This diff is collapsed.
......@@ -19,6 +19,19 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
Node* const map, Label* const if_isunmodified,
Label* const if_ismodified);
// Create and initialize a RegExp object.
TNode<Object> RegExpCreate(TNode<Context> context,
TNode<Context> native_context,
TNode<Object> regexp_string, TNode<String> flags);
TNode<Object> RegExpCreate(TNode<Context> context, TNode<Map> initial_map,
TNode<Object> regexp_string, TNode<String> flags);
TNode<Object> MatchAllIterator(TNode<Context> context,
TNode<Context> native_context,
TNode<Object> regexp, TNode<Object> string,
char const* method_name);
protected:
// Allocate a RegExpResult with the given length (the number of captures,
// including the match itself), index (the index where the match starts),
......
......@@ -1024,7 +1024,7 @@ void StringBuiltinsAssembler::RequireObjectCoercible(Node* const context,
void StringBuiltinsAssembler::MaybeCallFunctionAtSymbol(
Node* const context, Node* const object, Node* const maybe_string,
Handle<Symbol> symbol, const NodeFunction0& regexp_call,
const NodeFunction1& generic_call, CodeStubArguments* args) {
const NodeFunction1& generic_call) {
Label out(this);
// Smis definitely don't have an attached symbol.
......@@ -1069,12 +1069,7 @@ void StringBuiltinsAssembler::MaybeCallFunctionAtSymbol(
BIND(&stub_call);
// TODO(jgruber): Add a no-JS scope once it exists.
Node* const result = regexp_call();
if (args == nullptr) {
Return(result);
} else {
args->PopAndReturn(result);
}
regexp_call();
BIND(&slow_lookup);
}
......@@ -1094,12 +1089,7 @@ void StringBuiltinsAssembler::MaybeCallFunctionAtSymbol(
GotoIf(IsNull(maybe_func), &out);
// Attempt to call the function.
Node* const result = generic_call(maybe_func);
if (args == nullptr) {
Return(result);
} else {
args->PopAndReturn(result);
}
generic_call(maybe_func);
BIND(&out);
}
......@@ -1294,12 +1284,12 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
MaybeCallFunctionAtSymbol(
context, search, receiver, isolate()->factory()->replace_symbol(),
[=]() {
return CallBuiltin(Builtins::kRegExpReplace, context, search, receiver,
replace);
Return(CallBuiltin(Builtins::kRegExpReplace, context, search, receiver,
replace));
},
[=](Node* fn) {
Callable call_callable = CodeFactory::Call(isolate());
return CallJS(call_callable, context, fn, search, receiver, replace);
Return(CallJS(call_callable, context, fn, search, receiver, replace));
});
// Convert {receiver} and {search} to strings.
......@@ -1439,8 +1429,9 @@ class StringMatchSearchAssembler : public StringBuiltinsAssembler {
protected:
enum Variant { kMatch, kSearch };
void Generate(Variant variant, const char* method_name, Node* const receiver,
Node* maybe_regexp, Node* const context) {
void Generate(Variant variant, const char* method_name,
TNode<Object> receiver, TNode<Object> maybe_regexp,
TNode<Context> context) {
Label call_regexp_match_search(this);
Builtins::Name builtin;
......@@ -1457,32 +1448,24 @@ class StringMatchSearchAssembler : public StringBuiltinsAssembler {
MaybeCallFunctionAtSymbol(
context, maybe_regexp, receiver, symbol,
[=] { return CallBuiltin(builtin, context, maybe_regexp, receiver); },
[=] { Return(CallBuiltin(builtin, context, maybe_regexp, receiver)); },
[=](Node* fn) {
Callable call_callable = CodeFactory::Call(isolate());
return CallJS(call_callable, context, fn, maybe_regexp, receiver);
Return(CallJS(call_callable, context, fn, maybe_regexp, receiver));
});
// maybe_regexp is not a RegExp nor has [@@match / @@search] property.
{
RegExpBuiltinsAssembler regexp_asm(state());
Node* const receiver_string = ToString_Inline(context, receiver);
TNode<Object> const pattern = Select<Object>(
IsUndefined(maybe_regexp), [=] { return EmptyStringConstant(); },
[=] { return ToString_Inline(context, maybe_regexp); });
// Create RegExp
// TODO(pwong): This could be factored out as a helper (RegExpCreate) that
// also does the "is fast" checks.
Node* const native_context = LoadNativeContext(context);
Node* const regexp_function =
LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
Node* const initial_map = LoadObjectField(
regexp_function, JSFunction::kPrototypeOrInitialMapOffset);
Node* const regexp = CallRuntime(
Runtime::kRegExpInitializeAndCompile, context,
AllocateJSObjectFromMap(initial_map), pattern, EmptyStringConstant());
TNode<String> receiver_string = ToString_Inline(context, receiver);
TNode<Context> native_context = LoadNativeContext(context);
TNode<HeapObject> regexp_function = CAST(
LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX));
TNode<Map> initial_map = CAST(LoadObjectField(
regexp_function, JSFunction::kPrototypeOrInitialMapOffset));
TNode<Object> regexp = regexp_asm.RegExpCreate(
context, initial_map, maybe_regexp, EmptyStringConstant());
Label fast_path(this), slow_path(this);
regexp_asm.BranchIfFastRegExp(context, regexp, initial_map, &fast_path,
......@@ -1493,7 +1476,7 @@ class StringMatchSearchAssembler : public StringBuiltinsAssembler {
BIND(&slow_path);
{
Node* const maybe_func = GetProperty(context, regexp, symbol);
TNode<Object> maybe_func = GetProperty(context, regexp, symbol);
Callable call_callable = CodeFactory::Call(isolate());
Return(CallJS(call_callable, context, maybe_func, regexp,
receiver_string));
......@@ -1504,13 +1487,52 @@ class StringMatchSearchAssembler : public StringBuiltinsAssembler {
// ES6 #sec-string.prototype.match
TF_BUILTIN(StringPrototypeMatch, StringMatchSearchAssembler) {
Node* const receiver = Parameter(Descriptor::kReceiver);
Node* const maybe_regexp = Parameter(Descriptor::kRegexp);
Node* const context = Parameter(Descriptor::kContext);
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
TNode<Object> maybe_regexp = CAST(Parameter(Descriptor::kRegexp));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
Generate(kMatch, "String.prototype.match", receiver, maybe_regexp, context);
}
// ES #sec-string.prototype.matchAll
TF_BUILTIN(StringPrototypeMatchAll, StringBuiltinsAssembler) {
char const* method_name = "String.prototype.matchAll";
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<Object> maybe_regexp = CAST(Parameter(Descriptor::kRegexp));
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
TNode<Context> native_context = LoadNativeContext(context);
// 1. Let O be ? RequireObjectCoercible(this value).
RequireObjectCoercible(context, receiver, method_name);
// 2. If regexp is neither undefined nor null, then
Label return_match_all_iterator(this);
GotoIf(IsNullOrUndefined(maybe_regexp), &return_match_all_iterator);
{
// a. Let matcher be ? GetMethod(regexp, @@matchAll).
// b. If matcher is not undefined, then
// i. Return ? Call(matcher, regexp, « O »).
auto if_regexp_call = [&] { Goto(&return_match_all_iterator); };
auto if_generic_call = [=](Node* fn) {
Callable call_callable = CodeFactory::Call(isolate());
Return(CallJS(call_callable, context, fn, maybe_regexp, receiver));
};
MaybeCallFunctionAtSymbol(context, maybe_regexp, receiver,
isolate()->factory()->match_all_symbol(),
if_regexp_call, if_generic_call);
Goto(&return_match_all_iterator);
}
BIND(&return_match_all_iterator);
{
// 3. Return ? MatchAllIterator(regexp, O).
RegExpBuiltinsAssembler regexp_asm(state());
TNode<Object> iterator = regexp_asm.MatchAllIterator(
context, native_context, maybe_regexp, receiver, method_name);
Return(iterator);
}
}
class StringPadAssembler : public StringBuiltinsAssembler {
public:
explicit StringPadAssembler(compiler::CodeAssemblerState* state)
......@@ -1639,9 +1661,9 @@ TF_BUILTIN(StringPrototypePadStart, StringPadAssembler) {
// ES6 #sec-string.prototype.search
TF_BUILTIN(StringPrototypeSearch, StringMatchSearchAssembler) {
Node* const receiver = Parameter(Descriptor::kReceiver);
Node* const maybe_regexp = Parameter(Descriptor::kRegexp);
Node* const context = Parameter(Descriptor::kContext);
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
TNode<Object> maybe_regexp = CAST(Parameter(Descriptor::kRegexp));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
Generate(kSearch, "String.prototype.search", receiver, maybe_regexp, context);
}
......@@ -1718,15 +1740,15 @@ TF_BUILTIN(StringPrototypeSplit, StringBuiltinsAssembler) {
MaybeCallFunctionAtSymbol(
context, separator, receiver, isolate()->factory()->split_symbol(),
[=]() {
return CallBuiltin(Builtins::kRegExpSplit, context, separator, receiver,
limit);
[&]() {
args.PopAndReturn(CallBuiltin(Builtins::kRegExpSplit, context,
separator, receiver, limit));
},
[=](Node* fn) {
[&](Node* fn) {
Callable call_callable = CodeFactory::Call(isolate());
return CallJS(call_callable, context, fn, separator, receiver, limit);
},
&args);
args.PopAndReturn(
CallJS(call_callable, context, fn, separator, receiver, limit));
});
// String and integer conversions.
......
......@@ -95,14 +95,13 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
//
// Contains fast paths for Smi and RegExp objects.
// Important: {regexp_call} may not contain any code that can call into JS.
typedef std::function<Node*()> NodeFunction0;
typedef std::function<Node*(Node* fn)> NodeFunction1;
typedef std::function<void()> NodeFunction0;
typedef std::function<void(Node* fn)> NodeFunction1;
void MaybeCallFunctionAtSymbol(Node* const context, Node* const object,
Node* const maybe_string,
Handle<Symbol> symbol,
const NodeFunction0& regexp_call,
const NodeFunction1& generic_call,
CodeStubArguments* args = nullptr);
const NodeFunction1& generic_call);
};
class StringIncludesIndexOfAssembler : public StringBuiltinsAssembler {
......
......@@ -29,6 +29,7 @@ class Callable;
class CallInterfaceDescriptor;
class Isolate;
class JSCollection;
class JSRegExpStringIterator;
class JSWeakCollection;
class JSWeakMap;
class JSWeakSet;
......
......@@ -223,6 +223,7 @@ Type::bitset BitsetType::Lub(i::Map* map) {
case JS_ARRAY_BUFFER_TYPE:
case JS_ARRAY_ITERATOR_TYPE:
case JS_REGEXP_TYPE: // TODO(rossberg): there should be a RegExp type.
case JS_REGEXP_STRING_ITERATOR_TYPE:
case JS_TYPED_ARRAY_TYPE:
case JS_DATA_VIEW_TYPE:
case JS_SET_TYPE:
......
......@@ -244,6 +244,8 @@ enum ContextLookupFlags {
V(REGEXP_INTERNAL_MATCH_INFO_INDEX, RegExpMatchInfo, \
regexp_internal_match_info) \
V(REGEXP_PROTOTYPE_MAP_INDEX, Map, regexp_prototype_map) \
V(INITIAL_REGEXP_STRING_ITERATOR_PROTOTYPE_MAP_INDEX, Map, \
initial_regexp_string_iterator_prototype_map_index) \
V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map) \
V(SCRIPT_CONTEXT_TABLE_INDEX, ScriptContextTable, script_context_table) \
V(SCRIPT_FUNCTION_INDEX, JSFunction, script_function) \
......
......@@ -213,7 +213,8 @@ DEFINE_IMPLICATION(harmony_class_fields, harmony_private_fields)
V(harmony_do_expressions, "harmony do-expressions") \
V(harmony_class_fields, "harmony fields in class literals") \
V(harmony_static_fields, "harmony static fields in class literals") \
V(harmony_array_flatten, "harmony Array.prototype.flat{ten,Map}")
V(harmony_array_flatten, "harmony Array.prototype.flat{ten,Map}") \
V(harmony_string_matchall, "harmony String.prototype.matchAll")
// Features that are complete (but still behind --harmony/es-staging flag).
#define HARMONY_STAGED(V) \
......
......@@ -264,6 +264,7 @@
V(async_iterator_symbol, Symbol.asyncIterator) \
V(iterator_symbol, Symbol.iterator) \
V(intl_fallback_symbol, IntlFallback) \
V(match_all_symbol, Symbol.matchAll) \
V(match_symbol, Symbol.match) \
V(replace_symbol, Symbol.replace) \
V(search_symbol, Symbol.search) \
......
......@@ -586,6 +586,7 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
case JS_MAP_VALUE_ITERATOR_TYPE:
case JS_STRING_ITERATOR_TYPE:
case JS_REGEXP_STRING_ITERATOR_TYPE:
case JS_REGEXP_TYPE:
case JS_GLOBAL_PROXY_TYPE:
case JS_GLOBAL_OBJECT_TYPE:
......
......@@ -276,6 +276,9 @@ void HeapObject::HeapObjectVerify() {
case JS_REGEXP_TYPE:
JSRegExp::cast(this)->JSRegExpVerify();
break;
case JS_REGEXP_STRING_ITERATOR_TYPE:
JSRegExpStringIterator::cast(this)->JSRegExpStringIteratorVerify();
break;
case FILLER_TYPE:
break;
case JS_PROXY_TYPE:
......@@ -1315,6 +1318,14 @@ void JSRegExp::JSRegExpVerify() {
}
}
void JSRegExpStringIterator::JSRegExpStringIteratorVerify() {
CHECK(IsJSRegExpStringIterator());
JSObjectVerify();
CHECK(iterating_string()->IsString());
CHECK(iterating_regexp()->IsObject());
VerifySmiField(kFlagsOffset);
}
void JSProxy::JSProxyVerify() {
CHECK(IsJSProxy());
VerifyPointer(target());
......
......@@ -42,6 +42,7 @@
#include "src/objects/js-collection-inl.h"
#include "src/objects/js-promise-inl.h"
#include "src/objects/js-regexp-inl.h"
#include "src/objects/js-regexp-string-iterator-inl.h"
#include "src/objects/literal-objects.h"
#include "src/objects/module-inl.h"
#include "src/objects/regexp-match-info.h"
......
......@@ -165,6 +165,9 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
case JS_REGEXP_TYPE:
JSRegExp::cast(this)->JSRegExpPrint(os);
break;
case JS_REGEXP_STRING_ITERATOR_TYPE:
JSRegExpStringIterator::cast(this)->JSRegExpStringIteratorPrint(os);
break;
case ODDBALL_TYPE:
Oddball::cast(this)->to_string()->Print(os);
break;
......@@ -619,6 +622,16 @@ void JSRegExp::JSRegExpPrint(std::ostream& os) { // NOLINT
JSObjectPrintBody(os, this);
}
void JSRegExpStringIterator::JSRegExpStringIteratorPrint(
std::ostream& os) { // NOLINT
JSObjectPrintHeader(os, this, "JSRegExpStringIterator");
os << "\n - regex: " << Brief(iterating_regexp());
os << "\n - string: " << Brief(iterating_string());
os << "\n - done: " << done();
os << "\n - global: " << global();
os << "\n - unicode: " << unicode();
JSObjectPrintBody(os, this);
}
void Symbol::SymbolPrint(std::ostream& os) { // NOLINT
HeapObject::PrintHeader(os, "Symbol");
......@@ -1079,7 +1092,6 @@ void JSCollectionIterator::JSCollectionIteratorPrint(
os << "\n";
}
void JSSetIterator::JSSetIteratorPrint(std::ostream& os) { // NOLINT
JSObjectPrintHeader(os, this, "JSSetIterator");
JSCollectionIteratorPrint(os);
......
......@@ -59,6 +59,7 @@
#include "src/objects/debug-objects-inl.h"
#include "src/objects/frame-array-inl.h"
#include "src/objects/hash-table.h"
#include "src/objects/js-regexp-string-iterator.h"
#include "src/objects/map.h"
#include "src/objects/microtask-inl.h"
#include "src/objects/promise-inl.h"
......@@ -1369,6 +1370,8 @@ int JSObject::GetHeaderSize(InstanceType type,
return JSPromise::kSize;
case JS_REGEXP_TYPE:
return JSRegExp::kSize;
case JS_REGEXP_STRING_ITERATOR_TYPE:
return JSRegExpStringIterator::kSize;
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
return JSObject::kHeaderSize;
case JS_MESSAGE_OBJECT_TYPE:
......@@ -3100,6 +3103,7 @@ VisitorId Map::GetVisitorId(Map* map) {
case JS_STRING_ITERATOR_TYPE:
case JS_PROMISE_TYPE:
case JS_REGEXP_TYPE:
case JS_REGEXP_STRING_ITERATOR_TYPE:
case WASM_GLOBAL_TYPE:
case WASM_MEMORY_TYPE:
case WASM_MODULE_TYPE:
......
......@@ -464,6 +464,7 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
V(JS_MESSAGE_OBJECT_TYPE) \
V(JS_PROMISE_TYPE) \
V(JS_REGEXP_TYPE) \
V(JS_REGEXP_STRING_ITERATOR_TYPE) \
V(JS_SET_TYPE) \
V(JS_SET_KEY_VALUE_ITERATOR_TYPE) \
V(JS_SET_VALUE_ITERATOR_TYPE) \
......@@ -839,6 +840,7 @@ enum InstanceType : uint16_t {
JS_MESSAGE_OBJECT_TYPE,
JS_PROMISE_TYPE,
JS_REGEXP_TYPE,
JS_REGEXP_STRING_ITERATOR_TYPE,
JS_SET_TYPE,
JS_SET_KEY_VALUE_ITERATOR_TYPE,
JS_SET_VALUE_ITERATOR_TYPE,
......@@ -1073,6 +1075,7 @@ template <class C> inline bool Is(Object* obj);
V(JSProxy) \
V(JSReceiver) \
V(JSRegExp) \
V(JSRegExpStringIterator) \
V(JSSet) \
V(JSSetIterator) \
V(JSSloppyArgumentsObject) \
......
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_OBJECTS_JS_REGEXP_STRING_ITERATOR_INL_H_
#define V8_OBJECTS_JS_REGEXP_STRING_ITERATOR_INL_H_
#include "src/objects/js-regexp-string-iterator.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
TYPE_CHECKER(JSRegExpStringIterator, JS_REGEXP_STRING_ITERATOR_TYPE)
ACCESSORS(JSRegExpStringIterator, iterating_regexp, Object,
kIteratingRegExpOffset)
ACCESSORS(JSRegExpStringIterator, iterating_string, String,
kIteratedStringOffset)
SMI_ACCESSORS(JSRegExpStringIterator, flags, kFlagsOffset)
BOOL_ACCESSORS(JSRegExpStringIterator, flags, done, kDoneBit)
BOOL_ACCESSORS(JSRegExpStringIterator, flags, global, kGlobalBit)
BOOL_ACCESSORS(JSRegExpStringIterator, flags, unicode, kUnicodeBit)
CAST_ACCESSOR(JSRegExpStringIterator)
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_JS_REGEXP_STRING_ITERATOR_INL_H_
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_OBJECTS_JS_REGEXP_STRING_ITERATOR_H_
#define V8_OBJECTS_JS_REGEXP_STRING_ITERATOR_H_
#include "src/objects.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
class JSRegExpStringIterator : public JSObject {
public:
// [regexp]: the [[IteratingRegExp]] internal property.
DECL_ACCESSORS(iterating_regexp, Object)
// [string]: The [[IteratedString]] internal property.
DECL_ACCESSORS(iterating_string, String)
DECL_INT_ACCESSORS(flags)
// [boolean]: The [[Done]] internal property.
DECL_BOOLEAN_ACCESSORS(done)
// [boolean]: The [[Global]] internal property.
DECL_BOOLEAN_ACCESSORS(global)
// [boolean]: The [[Unicode]] internal property.
DECL_BOOLEAN_ACCESSORS(unicode)
DECL_CAST(JSRegExpStringIterator)
DECL_PRINTER(JSRegExpStringIterator)
DECL_VERIFIER(JSRegExpStringIterator)
static const int kIteratingRegExpOffset = JSObject::kHeaderSize;
static const int kIteratedStringOffset =
kIteratingRegExpOffset + kPointerSize;
static const int kFlagsOffset = kIteratedStringOffset + kPointerSize;
static const int kSize = kFlagsOffset + kPointerSize;
static const int kDoneBit = 0;
static const int kGlobalBit = 1;
static const int kUnicodeBit = 2;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSRegExpStringIterator);
};
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_JS_REGEXP_STRING_ITERATOR_H_
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-string-matchall
(function TestReceiverNonString() {
const iter = 'a'.matchAll(/./);
assertThrows(
() => iter.next.call(0),
TypeError
);
})();
(function TestAncestry() {
const iterProto = Object.getPrototypeOf('a'.matchAll(/./));
const arrProto = Object.getPrototypeOf([][Symbol.iterator]());
assertSame(Object.getPrototypeOf(iterProto), Object.getPrototypeOf(arrProto));
})();
function TestNoMatch(string, regex_or_string) {
const next_result = string.matchAll(regex_or_string).next();
assertSame(undefined, next_result.value);
assertTrue(next_result.done);
}
TestNoMatch('a', /b/);
TestNoMatch('a', /b/g);
TestNoMatch('a', 'b');
(function NonGlobalRegex() {
const iter = 'ab'.matchAll(/./);
let next_result = iter.next();
assertEquals(['a'], next_result.value);
assertFalse(next_result.done);
next_result = iter.next();
assertEquals(undefined, next_result.value);
assertTrue(next_result.done);
})();
function TestGlobalRegex(regex_or_string) {
const iter = 'ab'.matchAll(/./g);
let next_result = iter.next();
assertEquals(['a'], next_result.value);
assertFalse(next_result.done);
next_result = iter.next();
assertEquals(['b'], next_result.value);
assertFalse(next_result.done);
next_result = iter.next();
assertSame(undefined, next_result.value);
assertTrue(next_result.done);
}
TestGlobalRegex(/./g);
TestGlobalRegex('.');
function TestEmptyGlobalRegExp(regex_or_string) {
const iter = 'd'.matchAll(regex_or_string);
let next_result = iter.next();
assertEquals([''], next_result.value);
assertFalse(next_result.done);
next_result = iter.next();
assertEquals([''], next_result.value);
assertFalse(next_result.done);
next_result = iter.next();
assertSame(undefined, next_result.value);
assertTrue(next_result.done);
}
TestEmptyGlobalRegExp(undefined);
TestEmptyGlobalRegExp(/(?:)/g);
TestEmptyGlobalRegExp('');
(function TestGlobalRegExpLastIndex() {
const regex = /./g;
const string = 'abc';
regex.exec(string);
assertSame(1, regex.lastIndex);
const iter = string.matchAll(regex);
// Verify an internal RegExp is created and mutations to the provided RegExp
// are not abservered.
regex.exec(string);
assertSame(2, regex.lastIndex);
let next_result = iter.next();
assertEquals(['b'], next_result.value);
assertFalse(next_result.done);
assertSame(2, regex.lastIndex);
})();
......@@ -51,6 +51,8 @@ FEATURE_FLAGS = {
'class-fields-private': '--harmony-private-fields',
'Array.prototype.flatten': '--harmony-array-flatten',
'Array.prototype.flatMap': '--harmony-array-flatten',
'String.prototype.matchAll': '--harmony-string-matchall',
'Symbol.matchAll': '--harmony-string-matchall',
'numeric-separator-literal': '--harmony-numeric-separator',
}
......
......@@ -137,21 +137,22 @@ INSTANCE_TYPES = {
1072: "JS_MESSAGE_OBJECT_TYPE",
1073: "JS_PROMISE_TYPE",
1074: "JS_REGEXP_TYPE",
1075: "JS_SET_TYPE",
1076: "JS_SET_KEY_VALUE_ITERATOR_TYPE",
1077: "JS_SET_VALUE_ITERATOR_TYPE",
1078: "JS_STRING_ITERATOR_TYPE",
1079: "JS_WEAK_MAP_TYPE",
1080: "JS_WEAK_SET_TYPE",
1081: "JS_TYPED_ARRAY_TYPE",
1082: "JS_DATA_VIEW_TYPE",
1083: "WASM_GLOBAL_TYPE",
1084: "WASM_INSTANCE_TYPE",
1085: "WASM_MEMORY_TYPE",
1086: "WASM_MODULE_TYPE",
1087: "WASM_TABLE_TYPE",
1088: "JS_BOUND_FUNCTION_TYPE",
1089: "JS_FUNCTION_TYPE",
1075: "JS_REGEXP_STRING_ITERATOR_TYPE",
1076: "JS_SET_TYPE",
1077: "JS_SET_KEY_VALUE_ITERATOR_TYPE",
1078: "JS_SET_VALUE_ITERATOR_TYPE",
1079: "JS_STRING_ITERATOR_TYPE",
1080: "JS_WEAK_MAP_TYPE",
1081: "JS_WEAK_SET_TYPE",
1082: "JS_TYPED_ARRAY_TYPE",
1083: "JS_DATA_VIEW_TYPE",
1084: "WASM_GLOBAL_TYPE",
1085: "WASM_INSTANCE_TYPE",
1086: "WASM_MEMORY_TYPE",
1087: "WASM_MODULE_TYPE",
1088: "WASM_TABLE_TYPE",
1089: "JS_BOUND_FUNCTION_TYPE",
1090: "JS_FUNCTION_TYPE",
}
# List of known V8 maps.
......
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