Commit 81e7e2f4 authored by Shu-yu Guo's avatar Shu-yu Guo Committed by Commit Bot

[regexp] Implement the /d flag for RegExp indices

This CL implements the upcoming spec change:
https://github.com/tc39/proposal-regexp-match-indices/pull/49

A new JSRegExpResultWithIndices subclass is introduced with a separate map and
an extra slot for storing the indices. If /d is passed, exec() constructs a
JSRegExpResultWithIndices and eagerly builds indices.

The existing re-execution logic is removed.

Bug: v8:9548
Change-Id: Ic11853e7521017af5e8bd583c7b82bb672821132
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2616873
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72306}
parent 9dccd91c
......@@ -6136,9 +6136,10 @@ class V8_EXPORT RegExp : public Object {
kUnicode = 1 << 4,
kDotAll = 1 << 5,
kLinear = 1 << 6,
kHasIndices = 1 << 7,
};
static constexpr int kFlagCount = 7;
static constexpr int kFlagCount = 8;
/**
* Creates a regular expression from the given pattern string and
......
......@@ -7032,6 +7032,7 @@ REGEXP_FLAG_ASSERT_EQ(kIgnoreCase);
REGEXP_FLAG_ASSERT_EQ(kMultiline);
REGEXP_FLAG_ASSERT_EQ(kSticky);
REGEXP_FLAG_ASSERT_EQ(kUnicode);
REGEXP_FLAG_ASSERT_EQ(kHasIndices);
REGEXP_FLAG_ASSERT_EQ(kLinear);
#undef REGEXP_FLAG_ASSERT_EQ
......
......@@ -256,6 +256,7 @@ void CallPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
Print("/");
PrintLiteral(node->pattern(), false);
Print("/");
if (node->flags() & RegExp::kHasIndices) Print("d");
if (node->flags() & RegExp::kGlobal) Print("g");
if (node->flags() & RegExp::kIgnoreCase) Print("i");
if (node->flags() & RegExp::kLinear) Print("l");
......@@ -1156,6 +1157,7 @@ void AstPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
PrintLiteralIndented("PATTERN", node->raw_pattern(), false);
int i = 0;
EmbeddedVector<char, 128> buf;
if (node->flags() & RegExp::kHasIndices) buf[i++] = 'd';
if (node->flags() & RegExp::kGlobal) buf[i++] = 'g';
if (node->flags() & RegExp::kIgnoreCase) buf[i++] = 'i';
if (node->flags() & RegExp::kLinear) buf[i++] = 'l';
......
......@@ -842,32 +842,5 @@ Handle<AccessorInfo> Accessors::MakeErrorStackInfo(Isolate* isolate) {
&ErrorStackGetter, &ErrorStackSetter);
}
//
// Accessors::RegExpResultIndices
//
void Accessors::RegExpResultIndicesGetter(
v8::Local<v8::Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
HandleScope scope(isolate);
Handle<JSRegExpResult> regexp_result(
Handle<JSRegExpResult>::cast(Utils::OpenHandle(*info.Holder())));
MaybeHandle<JSArray> maybe_indices(
JSRegExpResult::GetAndCacheIndices(isolate, regexp_result));
Handle<JSArray> indices;
if (!maybe_indices.ToHandle(&indices)) {
isolate->OptionalRescheduleException(false);
Handle<Object> result = isolate->factory()->undefined_value();
info.GetReturnValue().Set(Utils::ToLocal(result));
} else {
info.GetReturnValue().Set(Utils::ToLocal(indices));
}
}
Handle<AccessorInfo> Accessors::MakeRegExpResultIndicesInfo(Isolate* isolate) {
return MakeAccessor(isolate, isolate->factory()->indices_string(),
&RegExpResultIndicesGetter, nullptr);
}
} // namespace internal
} // namespace v8
......@@ -44,8 +44,6 @@ class JavaScriptFrame;
kHasSideEffectToReceiver) \
V(_, function_prototype, FunctionPrototype, kHasNoSideEffect, \
kHasSideEffectToReceiver) \
V(_, regexp_result_indices, RegExpResultIndices, kHasSideEffectToReceiver, \
kHasSideEffectToReceiver) \
V(_, string_length, StringLength, kHasNoSideEffect, kHasSideEffectToReceiver)
#define ACCESSOR_SETTER_LIST(V) \
......
......@@ -88,31 +88,52 @@ TNode<RawPtrT> RegExpBuiltinsAssembler::LoadCodeObjectEntry(TNode<Code> code) {
TNode<JSRegExpResult> RegExpBuiltinsAssembler::AllocateRegExpResult(
TNode<Context> context, TNode<Smi> length, TNode<Smi> index,
TNode<String> input, TNode<JSRegExp> regexp, TNode<Number> last_index,
TNode<FixedArray>* elements_out) {
TNode<BoolT> has_indices, TNode<FixedArray>* elements_out) {
CSA_ASSERT(this, SmiLessThanOrEqual(
length, SmiConstant(JSArray::kMaxFastArrayLength)));
CSA_ASSERT(this, SmiGreaterThan(length, SmiConstant(0)));
// Allocate.
Label result_has_indices(this), allocated(this);
const ElementsKind elements_kind = PACKED_ELEMENTS;
TNode<Map> map = CAST(LoadContextElement(LoadNativeContext(context),
Context::REGEXP_RESULT_MAP_INDEX));
base::Optional<TNode<AllocationSite>> no_gc_site = base::nullopt;
TNode<IntPtrT> length_intptr = SmiUntag(length);
// Note: The returned `var_elements` may be in young large object space, but
// `var_array` is guaranteed to be in new space so we could skip write
// barriers below.
TVARIABLE(JSArray, var_array);
TVARIABLE(FixedArrayBase, var_elements);
// Note: The returned `elements` may be in young large object space, but
// `array` is guaranteed to be in new space so we could skip write barriers
// below.
TNode<JSArray> array;
TNode<FixedArrayBase> elements;
std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
elements_kind, map, length, no_gc_site, length_intptr,
kAllowLargeObjectAllocation, JSRegExpResult::kSize);
GotoIf(has_indices, &result_has_indices);
{
TNode<Map> map = CAST(LoadContextElement(LoadNativeContext(context),
Context::REGEXP_RESULT_MAP_INDEX));
std::tie(var_array, var_elements) =
AllocateUninitializedJSArrayWithElements(
elements_kind, map, length, no_gc_site, length_intptr,
kAllowLargeObjectAllocation, JSRegExpResult::kSize);
Goto(&allocated);
}
BIND(&result_has_indices);
{
TNode<Map> map =
CAST(LoadContextElement(LoadNativeContext(context),
Context::REGEXP_RESULT_WITH_INDICES_MAP_INDEX));
std::tie(var_array, var_elements) =
AllocateUninitializedJSArrayWithElements(
elements_kind, map, length, no_gc_site, length_intptr,
kAllowLargeObjectAllocation, JSRegExpResultWithIndices::kSize);
Goto(&allocated);
}
BIND(&allocated);
// Finish result initialization.
TNode<JSRegExpResult> result = UncheckedCast<JSRegExpResult>(array);
TNode<JSRegExpResult> result =
UncheckedCast<JSRegExpResult>(var_array.value());
// Load undefined value once here to avoid multiple LoadRoots.
TNode<Oddball> undefined_value = UncheckedCast<Oddball>(
......@@ -127,10 +148,6 @@ TNode<JSRegExpResult> RegExpBuiltinsAssembler::AllocateRegExpResult(
StoreObjectFieldNoWriteBarrier(result, JSRegExpResult::kNamesOffset,
undefined_value);
// Stash regexp in order to re-execute and build JSRegExpResultIndices lazily
// when the 'indices' property is accessed.
StoreObjectField(result, JSRegExpResult::kCachedIndicesOrRegexpOffset,
regexp);
StoreObjectField(result, JSRegExpResult::kRegexpInputOffset, input);
// If non-smi last_index then store an SmiZero instead.
......@@ -142,12 +159,25 @@ TNode<JSRegExpResult> RegExpBuiltinsAssembler::AllocateRegExpResult(
last_index_smi);
}
Label finish_initialization(this);
GotoIfNot(has_indices, &finish_initialization);
{
static_assert(
std::is_base_of<JSRegExpResult, JSRegExpResultWithIndices>::value,
"JSRegExpResultWithIndices is a subclass of JSRegExpResult");
StoreObjectFieldNoWriteBarrier(
result, JSRegExpResultWithIndices::kIndicesOffset, undefined_value);
Goto(&finish_initialization);
}
BIND(&finish_initialization);
// Finish elements initialization.
FillFixedArrayWithValue(elements_kind, elements, IntPtrZero(), length_intptr,
RootIndex::kUndefinedValue);
FillFixedArrayWithValue(elements_kind, var_elements.value(), IntPtrZero(),
length_intptr, RootIndex::kUndefinedValue);
if (elements_out) *elements_out = CAST(elements);
if (elements_out) *elements_out = CAST(var_elements.value());
return result;
}
......@@ -185,7 +215,7 @@ TNode<JSRegExpResult> RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
TNode<Context> context, TNode<JSRegExp> regexp,
TNode<RegExpMatchInfo> match_info, TNode<String> string,
TNode<Number> last_index) {
Label named_captures(this), out(this);
Label named_captures(this), maybe_build_indices(this), out(this);
TNode<IntPtrT> num_indices = SmiUntag(CAST(UnsafeLoadFixedArrayElement(
match_info, RegExpMatchInfo::kNumberOfCapturesIndex)));
......@@ -201,15 +231,19 @@ TNode<JSRegExpResult> RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
TNode<String> first =
CAST(CallBuiltin(Builtins::kSubString, context, string, start, end));
// Load flags and check if the result object needs to have indices.
const TNode<Smi> flags =
CAST(LoadObjectField(regexp, JSRegExp::kFlagsOffset));
const TNode<BoolT> has_indices = IsSetSmi(flags, JSRegExp::kHasIndices);
TNode<FixedArray> result_elements;
TNode<JSRegExpResult> result =
AllocateRegExpResult(context, num_results, start, string, regexp,
last_index, &result_elements);
last_index, has_indices, &result_elements);
UnsafeStoreFixedArrayElement(result_elements, 0, first);
// If no captures exist we can skip named capture handling as well.
GotoIf(SmiEqual(num_results, SmiConstant(1)), &out);
GotoIf(SmiEqual(num_results, SmiConstant(1)), &maybe_build_indices);
// Store all remaining captures.
TNode<IntPtrT> limit = IntPtrAdd(
......@@ -273,7 +307,7 @@ TNode<JSRegExpResult> RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
// index at odd indices.
TNode<Object> maybe_names =
LoadFixedArrayElement(data, JSRegExp::kIrregexpCaptureNameMapIndex);
GotoIf(TaggedEqual(maybe_names, SmiZero()), &out);
GotoIf(TaggedEqual(maybe_names, SmiZero()), &maybe_build_indices);
// One or more named captures exist, add a property for each one.
......@@ -343,8 +377,8 @@ TNode<JSRegExpResult> RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
}
var_i = i_plus_2;
Branch(IntPtrGreaterThanOrEqual(var_i.value(), names_length), &out,
&loop);
Branch(IntPtrGreaterThanOrEqual(var_i.value(), names_length),
&maybe_build_indices, &loop);
if (!V8_DICT_MODE_PROTOTYPES_BOOL) {
// TODO(v8:11167) make unconditional once OrderedNameDictionary
......@@ -358,6 +392,22 @@ TNode<JSRegExpResult> RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
}
}
// Build indices if needed (i.e. if the /d flag is present) after named
// capture groups are processed.
BIND(&maybe_build_indices);
GotoIfNot(has_indices, &out);
{
const TNode<Object> maybe_names =
LoadObjectField(result, JSRegExpResultWithIndices::kNamesOffset);
const TNode<JSRegExpResultIndices> indices =
UncheckedCast<JSRegExpResultIndices>(
CallRuntime(Runtime::kRegExpBuildIndices, context, regexp,
match_info, maybe_names));
StoreObjectField(result, JSRegExpResultWithIndices::kIndicesOffset,
indices);
Goto(&out);
}
BIND(&out);
return result;
}
......@@ -836,8 +886,20 @@ void RegExpBuiltinsAssembler::BranchIfRegExpResult(const TNode<Context> context,
const TNode<Object> initial_regexp_result_map =
LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX);
Label maybe_result_with_indices(this);
Branch(TaggedEqual(map, initial_regexp_result_map), if_isunmodified,
if_ismodified);
&maybe_result_with_indices);
BIND(&maybe_result_with_indices);
{
static_assert(
std::is_base_of<JSRegExpResult, JSRegExpResultWithIndices>::value,
"JSRegExpResultWithIndices is a subclass of JSRegExpResult");
const TNode<Object> initial_regexp_result_with_indices_map =
LoadContextElement(native_context,
Context::REGEXP_RESULT_WITH_INDICES_MAP_INDEX);
Branch(TaggedEqual(map, initial_regexp_result_with_indices_map),
if_isunmodified, if_ismodified);
}
}
// Fast path stub for ATOM regexps. String matching is done by StringIndexOf,
......@@ -945,6 +1007,7 @@ TNode<String> RegExpBuiltinsAssembler::FlagsGetter(TNode<Context> context,
BIND(&next); \
} while (false)
CASE_FOR_FLAG(JSRegExp::kHasIndices);
CASE_FOR_FLAG(JSRegExp::kGlobal);
CASE_FOR_FLAG(JSRegExp::kIgnoreCase);
CASE_FOR_FLAG(JSRegExp::kLinear);
......@@ -981,35 +1044,38 @@ TNode<String> RegExpBuiltinsAssembler::FlagsGetter(TNode<Context> context,
CASE_FOR_FLAG("sticky", JSRegExp::kSticky);
#undef CASE_FOR_FLAG
{
Label next(this);
// Check the runtime value of FLAG_enable_experimental_regexp_engine
// first.
TNode<Word32T> flag_value = UncheckedCast<Word32T>(
Load(MachineType::Uint8(),
ExternalConstant(
ExternalReference::
address_of_enable_experimental_regexp_engine())));
GotoIf(Word32Equal(Word32And(flag_value, Int32Constant(0xFF)),
Int32Constant(0)),
&next);
#define CASE_FOR_FLAG(NAME, V8_FLAG_EXTERN_REF, FLAG) \
do { \
Label next(this); \
TNode<Word32T> flag_value = UncheckedCast<Word32T>( \
Load(MachineType::Uint8(), ExternalConstant(V8_FLAG_EXTERN_REF))); \
GotoIf(Word32Equal(Word32And(flag_value, Int32Constant(0xFF)), \
Int32Constant(0)), \
&next); \
const TNode<Object> flag = GetProperty( \
context, regexp, isolate->factory()->InternalizeUtf8String(NAME)); \
Label if_isflagset(this); \
BranchIfToBooleanIsTrue(flag, &if_isflagset, &next); \
BIND(&if_isflagset); \
var_length = Uint32Add(var_length.value(), Uint32Constant(1)); \
var_flags = Signed(WordOr(var_flags.value(), IntPtrConstant(FLAG))); \
Goto(&next); \
BIND(&next); \
} while (false)
const TNode<Object> flag = GetProperty(
context, regexp, isolate->factory()->InternalizeUtf8String("linear"));
Label if_isflagset(this);
BranchIfToBooleanIsTrue(flag, &if_isflagset, &next);
BIND(&if_isflagset);
var_length = Uint32Add(var_length.value(), Uint32Constant(1));
var_flags =
Signed(WordOr(var_flags.value(), IntPtrConstant(JSRegExp::kLinear)));
Goto(&next);
BIND(&next);
}
CASE_FOR_FLAG(
"hasIndices",
ExternalReference::address_of_harmony_regexp_match_indices_flag(),
JSRegExp::kHasIndices);
CASE_FOR_FLAG(
"linear",
ExternalReference::address_of_enable_experimental_regexp_engine(),
JSRegExp::kLinear);
#undef CASE_FOR_FLAG
}
// Allocate a string of the required length and fill it with the corresponding
// char for each set flag.
// Allocate a string of the required length and fill it with the
// corresponding char for each set flag.
{
const TNode<String> result = AllocateSeqOneByteString(var_length.value());
......@@ -1029,6 +1095,7 @@ TNode<String> RegExpBuiltinsAssembler::FlagsGetter(TNode<Context> context,
BIND(&next); \
} while (false)
CASE_FOR_FLAG(JSRegExp::kHasIndices, 'd');
CASE_FOR_FLAG(JSRegExp::kGlobal, 'g');
CASE_FOR_FLAG(JSRegExp::kIgnoreCase, 'i');
CASE_FOR_FLAG(JSRegExp::kLinear, 'l');
......@@ -1283,6 +1350,9 @@ TNode<BoolT> RegExpBuiltinsAssembler::SlowFlagGetter(TNode<Context> context,
case JSRegExp::kUnicode:
name = isolate()->factory()->unicode_string();
break;
case JSRegExp::kHasIndices:
name = isolate()->factory()->has_indices_string();
break;
case JSRegExp::kLinear:
name = isolate()->factory()->linear_string();
break;
......
......@@ -22,13 +22,14 @@ class RegExpBuiltinsAssembler : public CodeStubAssembler {
TNode<RawPtrT> LoadCodeObjectEntry(TNode<Code> code);
// Allocate a RegExpResult with the given length (the number of captures,
// including the match itself), index (the index where the match starts),
// and input string.
// Allocate either a JSRegExpResult or a JSRegExpResultWithIndices (depending
// on has_indices) with the given length (the number of captures, including
// the match itself), index (the index where the match starts), and input
// string.
TNode<JSRegExpResult> AllocateRegExpResult(
TNode<Context> context, TNode<Smi> length, TNode<Smi> index,
TNode<String> input, TNode<JSRegExp> regexp, TNode<Number> last_index,
TNode<FixedArray>* elements_out = nullptr);
TNode<BoolT> has_indices, TNode<FixedArray>* elements_out = nullptr);
TNode<Object> FastLoadLastIndexBeforeSmiCheck(TNode<JSRegExp> regexp);
TNode<Smi> FastLoadLastIndex(TNode<JSRegExp> regexp) {
......
......@@ -51,8 +51,8 @@ transitioning macro RegExpExec(implicit context: Context)(
}
extern macro RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(
implicit context: Context)(
JSRegExp, RegExpMatchInfo, String, Number): JSRegExpResult;
implicit context: Context)(JSRegExp, RegExpMatchInfo, String, Number):
JSRegExpResult|JSRegExpResultWithIndices;
const kGlobalOrSticky: constexpr int31
generates 'JSRegExp::kGlobal | JSRegExp::kSticky';
......@@ -185,6 +185,7 @@ extern enum Flag constexpr 'JSRegExp::Flag' {
kSticky,
kUnicode,
kDotAll,
kHasIndices,
kLinear
}
......@@ -243,6 +244,13 @@ transitioning javascript builtin RegExpPrototypeMultilineGetter(
'RegExp.prototype.multiline');
}
transitioning javascript builtin RegExpPrototypeHasIndicesGetter(
js-implicit context: NativeContext, receiver: JSAny)(): JSAny {
return FlagGetter(
receiver, Flag::kHasIndices, kNoCounterFlagGetter,
'RegExp.prototype.hasIndices');
}
transitioning javascript builtin RegExpPrototypeLinearGetter(
js-implicit context: NativeContext, receiver: JSAny)(): JSAny {
return FlagGetter(
......
......@@ -462,6 +462,11 @@ ExternalReference ExternalReference::address_of_builtin_subclassing_flag() {
return ExternalReference(&FLAG_builtin_subclassing);
}
ExternalReference
ExternalReference::address_of_harmony_regexp_match_indices_flag() {
return ExternalReference(&FLAG_harmony_regexp_match_indices);
}
ExternalReference ExternalReference::address_of_runtime_stats_flag() {
return ExternalReference(&TracingFlags::runtime_stats);
}
......
......@@ -99,16 +99,18 @@ class StatsCounter;
#define EXTERNAL_REFERENCE_LIST(V) \
V(abort_with_reason, "abort_with_reason") \
V(address_of_builtin_subclassing_flag, "FLAG_builtin_subclassing") \
V(address_of_double_abs_constant, "double_absolute_constant") \
V(address_of_double_neg_constant, "double_negate_constant") \
V(address_of_enable_experimental_regexp_engine, \
"address_of_enable_experimental_regexp_engine") \
V(address_of_float_abs_constant, "float_absolute_constant") \
V(address_of_float_neg_constant, "float_negate_constant") \
V(address_of_harmony_regexp_match_indices_flag, \
"FLAG_harmony_regexp_match_indices") \
V(address_of_min_int, "LDoubleConstant::min_int") \
V(address_of_mock_arraybuffer_allocator_flag, \
"FLAG_mock_arraybuffer_allocator") \
V(address_of_builtin_subclassing_flag, "FLAG_builtin_subclassing") \
V(address_of_one_half, "LDoubleConstant::one_half") \
V(address_of_runtime_stats_flag, "TracingFlags::runtime_stats") \
V(address_of_the_hole_nan, "the_hole_nan") \
......
......@@ -843,6 +843,7 @@ DebugInfo::SideEffectState BuiltinGetSideEffectState(Builtins::Name id) {
case Builtins::kRegExpPrototypeSplit:
case Builtins::kRegExpPrototypeFlagsGetter:
case Builtins::kRegExpPrototypeGlobalGetter:
case Builtins::kRegExpPrototypeHasIndicesGetter:
case Builtins::kRegExpPrototypeIgnoreCaseGetter:
case Builtins::kRegExpPrototypeMatchAll:
case Builtins::kRegExpPrototypeMultilineGetter:
......
......@@ -4436,13 +4436,31 @@ void Genesis::InitializeGlobal_harmony_weak_refs_with_cleanup_some() {
void Genesis::InitializeGlobal_harmony_regexp_match_indices() {
if (!FLAG_harmony_regexp_match_indices) return;
// Add indices accessor to JSRegExpResult's initial map.
Handle<Map> initial_map(native_context()->regexp_result_map(), isolate());
Descriptor d = Descriptor::AccessorConstant(
factory()->indices_string(), factory()->regexp_result_indices_accessor(),
NONE);
Map::EnsureDescriptorSlack(isolate(), initial_map, 1);
initial_map->AppendDescriptor(isolate(), &d);
Handle<Map> source_map(native_context()->regexp_result_map(), isolate());
Handle<Map> initial_map =
Map::Copy(isolate(), source_map, "JSRegExpResult with indices");
initial_map->set_instance_size(JSRegExpResultWithIndices::kSize);
DCHECK_EQ(initial_map->GetInObjectProperties(),
JSRegExpResultWithIndices::kInObjectPropertyCount);
// indices descriptor
{
Descriptor d =
Descriptor::DataField(isolate(), factory()->indices_string(),
JSRegExpResultWithIndices::kIndicesIndex, NONE,
Representation::Tagged());
Map::EnsureDescriptorSlack(isolate(), initial_map, 1);
initial_map->AppendDescriptor(isolate(), &d);
}
native_context()->set_regexp_result_with_indices_map(*initial_map);
Handle<JSObject> prototype(native_context()->regexp_prototype(), isolate());
SimpleInstallGetter(isolate(), prototype, factory()->has_indices_string(),
Builtins::kRegExpPrototypeHasIndicesGetter, true);
// Store regexp prototype map again after change.
native_context()->set_regexp_prototype_map(prototype->map());
}
void Genesis::InitializeGlobal_harmony_string_replaceall() {
......@@ -4788,16 +4806,6 @@ bool Genesis::InstallABunchOfRandomThings() {
{
PropertyAttributes attribs = DONT_ENUM;
// cached_indices_or_regexp descriptor.
{
Descriptor d = Descriptor::DataField(
isolate(),
factory()->regexp_result_cached_indices_or_regexp_symbol(),
JSRegExpResult::kCachedIndicesOrRegExpIndex, attribs,
Representation::Tagged());
initial_map->AppendDescriptor(isolate(), &d);
}
// names descriptor.
{
Descriptor d = Descriptor::DataField(
......
......@@ -209,6 +209,7 @@
V(_, globalThis_string, "globalThis") \
V(_, groups_string, "groups") \
V(_, has_string, "has") \
V(_, has_indices_string, "hasIndices") \
V(_, ignoreCase_string, "ignoreCase") \
V(_, illegal_access_string, "illegal access") \
V(_, illegal_argument_string, "illegal argument") \
......@@ -357,7 +358,6 @@
V(_, promise_debug_message_symbol) \
V(_, promise_forwarding_handler_symbol) \
V(_, promise_handled_by_symbol) \
V(_, regexp_result_cached_indices_or_regexp_symbol) \
V(_, regexp_result_names_symbol) \
V(_, regexp_result_regexp_input_symbol) \
V(_, regexp_result_regexp_last_index_symbol) \
......
......@@ -214,6 +214,7 @@ enum ContextLookupFlags {
V(REGEXP_PROTOTYPE_MAP_INDEX, Map, regexp_prototype_map) \
V(REGEXP_REPLACE_FUNCTION_INDEX, JSFunction, regexp_replace_function) \
V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map) \
V(REGEXP_RESULT_WITH_INDICES_MAP_INDEX, Map, regexp_result_with_indices_map) \
V(REGEXP_RESULT_INDICES_MAP_INDEX, Map, regexp_result_indices_map) \
V(REGEXP_SEARCH_FUNCTION_INDEX, JSFunction, regexp_search_function) \
V(REGEXP_SPLIT_FUNCTION_INDEX, JSFunction, regexp_split_function) \
......
......@@ -24,7 +24,13 @@ TQ_OBJECT_CONSTRUCTORS_IMPL(JSRegExp)
OBJECT_CONSTRUCTORS_IMPL_CHECK_SUPER(JSRegExpResult, JSArray)
OBJECT_CONSTRUCTORS_IMPL_CHECK_SUPER(JSRegExpResultIndices, JSArray)
inline JSRegExpResultWithIndices::JSRegExpResultWithIndices(Address ptr)
: JSRegExpResult(ptr) {
SLOW_DCHECK(IsJSArray());
}
CAST_ACCESSOR(JSRegExpResult)
CAST_ACCESSOR(JSRegExpResultWithIndices)
CAST_ACCESSOR(JSRegExpResultIndices)
ACCESSORS(JSRegExp, last_index, Object, kLastIndexOffset)
......
......@@ -12,78 +12,6 @@
namespace v8 {
namespace internal {
MaybeHandle<JSArray> JSRegExpResult::GetAndCacheIndices(
Isolate* isolate, Handle<JSRegExpResult> regexp_result) {
// Check for cached indices. We do a slow lookup and set of
// the cached_indices_or_match_info and names fields just in
// case they have been migrated to dictionaries.
Handle<Object> indices_or_regexp(
GetProperty(
isolate, regexp_result,
isolate->factory()->regexp_result_cached_indices_or_regexp_symbol())
.ToHandleChecked());
if (indices_or_regexp->IsJSRegExp()) {
// Build and cache indices for next lookup.
// TODO(joshualitt): Instead of caching the indices, we could call
// ReconfigureToDataProperty on 'indices' setting its value to this
// newly created array. However, care would have to be taken to ensure
// a new map is not created each time.
// Grab regexp, its last_index, and the original subject string from the
// result and the re-execute the regexp to generate a new MatchInfo.
Handle<JSRegExp> regexp(JSRegExp::cast(*indices_or_regexp), isolate);
Handle<Object> input_object(
GetProperty(isolate, regexp_result,
isolate->factory()->regexp_result_regexp_input_symbol())
.ToHandleChecked());
Handle<String> subject(String::cast(*input_object), isolate);
Handle<Object> last_index_object(
GetProperty(
isolate, regexp_result,
isolate->factory()->regexp_result_regexp_last_index_symbol())
.ToHandleChecked());
int capture_count = regexp->CaptureCount();
Handle<RegExpMatchInfo> match_info =
RegExpMatchInfo::New(isolate, capture_count);
int last_index = Smi::ToInt(*last_index_object);
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result,
RegExp::Exec(isolate, regexp, subject, last_index, match_info),
JSArray);
DCHECK_EQ(*result, *match_info);
Handle<Object> maybe_names(
GetProperty(isolate, regexp_result,
isolate->factory()->regexp_result_names_symbol())
.ToHandleChecked());
indices_or_regexp =
JSRegExpResultIndices::BuildIndices(isolate, match_info, maybe_names);
// Cache the result and clear the names array, last_index and subject.
SetProperty(
isolate, regexp_result,
isolate->factory()->regexp_result_cached_indices_or_regexp_symbol(),
indices_or_regexp)
.ToHandleChecked();
SetProperty(isolate, regexp_result,
isolate->factory()->regexp_result_names_symbol(),
isolate->factory()->undefined_value())
.ToHandleChecked();
SetProperty(isolate, regexp_result,
isolate->factory()->regexp_result_regexp_last_index_symbol(),
isolate->factory()->undefined_value())
.ToHandleChecked();
SetProperty(isolate, regexp_result,
isolate->factory()->regexp_result_regexp_input_symbol(),
isolate->factory()->undefined_value())
.ToHandleChecked();
}
return Handle<JSArray>::cast(indices_or_regexp);
}
Handle<JSRegExpResultIndices> JSRegExpResultIndices::BuildIndices(
Isolate* isolate, Handle<RegExpMatchInfo> match_info,
Handle<Object> maybe_names) {
......
......@@ -5,6 +5,7 @@
#ifndef V8_OBJECTS_JS_REGEXP_H_
#define V8_OBJECTS_JS_REGEXP_H_
#include "src/objects/contexts.h"
#include "src/objects/js-array.h"
#include "torque-generated/bit-fields.h"
......@@ -43,7 +44,7 @@ class JSRegExp : public TorqueGeneratedJSRegExp<JSRegExp, JSObject> {
DEFINE_TORQUE_GENERATED_JS_REG_EXP_FLAGS()
static base::Optional<Flag> FlagFromChar(char c) {
STATIC_ASSERT(kFlagCount == 7);
STATIC_ASSERT(kFlagCount == 8);
// clang-format off
return c == 'g' ? base::Optional<Flag>(kGlobal)
: c == 'i' ? base::Optional<Flag>(kIgnoreCase)
......@@ -53,6 +54,8 @@ class JSRegExp : public TorqueGeneratedJSRegExp<JSRegExp, JSObject> {
: c == 's' ? base::Optional<Flag>(kDotAll)
: (FLAG_enable_experimental_regexp_engine && c == 'l')
? base::Optional<Flag>(kLinear)
: (FLAG_harmony_regexp_match_indices && c == 'd')
? base::Optional<Flag>(kHasIndices)
: base::Optional<Flag>();
// clang-format on
}
......@@ -65,6 +68,7 @@ class JSRegExp : public TorqueGeneratedJSRegExp<JSRegExp, JSObject> {
STATIC_ASSERT(static_cast<int>(kUnicode) == v8::RegExp::kUnicode);
STATIC_ASSERT(static_cast<int>(kDotAll) == v8::RegExp::kDotAll);
STATIC_ASSERT(static_cast<int>(kLinear) == v8::RegExp::kLinear);
STATIC_ASSERT(static_cast<int>(kHasIndices) == v8::RegExp::kHasIndices);
STATIC_ASSERT(kFlagCount == v8::RegExp::kFlagCount);
DECL_ACCESSORS(last_index, Object)
......@@ -249,24 +253,40 @@ class JSRegExpResult : public JSArray {
DEFINE_FIELD_OFFSET_CONSTANTS(JSArray::kHeaderSize,
TORQUE_GENERATED_JS_REG_EXP_RESULT_FIELDS)
static MaybeHandle<JSArray> GetAndCacheIndices(
Isolate* isolate, Handle<JSRegExpResult> regexp_result);
// Indices of in-object properties.
static const int kIndexIndex = 0;
static const int kInputIndex = 1;
static const int kGroupsIndex = 2;
// Private internal only fields.
static const int kCachedIndicesOrRegExpIndex = 3;
static const int kNamesIndex = 4;
static const int kRegExpInputIndex = 5;
static const int kRegExpLastIndex = 6;
static const int kInObjectPropertyCount = 7;
static const int kNamesIndex = 3;
static const int kRegExpInputIndex = 4;
static const int kRegExpLastIndex = 5;
static const int kInObjectPropertyCount = 6;
static const int kMapIndexInContext = Context::REGEXP_RESULT_MAP_INDEX;
OBJECT_CONSTRUCTORS(JSRegExpResult, JSArray);
};
class JSRegExpResultWithIndices : public JSRegExpResult {
public:
DECL_CAST(JSRegExpResultWithIndices)
// Layout description.
DEFINE_FIELD_OFFSET_CONSTANTS(
JSRegExpResult::kSize,
TORQUE_GENERATED_JS_REG_EXP_RESULT_WITH_INDICES_FIELDS)
static_assert(
JSRegExpResult::kInObjectPropertyCount == 6,
"JSRegExpResultWithIndices must be a subclass of JSRegExpResult");
static const int kIndicesIndex = 6;
static const int kInObjectPropertyCount = 7;
OBJECT_CONSTRUCTORS(JSRegExpResultWithIndices, JSRegExpResult);
};
// JSRegExpResultIndices is just a JSArray with a specific initial map.
// This initial map adds in-object properties for "group"
// properties, as assigned by RegExp.prototype.exec, which allows
......
......@@ -10,6 +10,7 @@ bitfield struct JSRegExpFlags extends uint31 {
unicode: bool: 1 bit;
dot_all: bool: 1 bit;
linear: bool: 1 bit;
has_indices: bool: 1 bit;
}
@generateCppClass
......@@ -34,6 +35,10 @@ RegExpBuiltinsAssembler::FastLoadLastIndex(FastJSRegExp): Smi;
extern operator '.lastIndex=' macro
RegExpBuiltinsAssembler::FastStoreLastIndex(FastJSRegExp, Smi): void;
@doNotGenerateCast
extern class JSRegExpConstructor extends JSFunction
generates 'TNode<JSFunction>';
extern shape JSRegExpResult extends JSArray {
// In-object properties:
// The below fields are externally exposed.
......@@ -42,15 +47,14 @@ extern shape JSRegExpResult extends JSArray {
groups: JSAny;
// The below fields are for internal use only.
cached_indices_or_regexp: JSRegExpResultIndices|JSRegExp;
names: FixedArray|Undefined;
regexp_input: String;
regexp_last_index: Smi;
}
@doNotGenerateCast
extern class JSRegExpConstructor extends JSFunction
generates 'TNode<JSFunction>';
extern shape JSRegExpResultWithIndices extends JSRegExpResult {
indices: JSAny;
}
extern shape JSRegExpResultIndices extends JSArray {
// In-object properties:
......
......@@ -1662,6 +1662,9 @@ MaybeHandle<JSRegExp> ValueDeserializer::ReadJSRegExp() {
if (!FLAG_enable_experimental_regexp_engine) {
bad_flags_mask |= JSRegExp::kLinear;
}
if (!FLAG_harmony_regexp_match_indices) {
bad_flags_mask |= JSRegExp::kHasIndices;
}
if ((raw_flags & bad_flags_mask) ||
!JSRegExp::New(isolate_, pattern, static_cast<JSRegExp::Flags>(raw_flags))
.ToHandle(&regexp)) {
......
......@@ -894,6 +894,21 @@ RUNTIME_FUNCTION(Runtime_RegExpExperimentalOneshotExec) {
last_match_info));
}
RUNTIME_FUNCTION(Runtime_RegExpBuildIndices) {
DCHECK(FLAG_harmony_regexp_match_indices);
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(RegExpMatchInfo, match_info, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, maybe_names, 2);
#ifdef DEBUG
CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
DCHECK(regexp->GetFlags() & JSRegExp::kHasIndices);
#endif
return *JSRegExpResultIndices::BuildIndices(isolate, match_info, maybe_names);
}
namespace {
class MatchInfoBackedMatch : public String::Match {
......
......@@ -385,6 +385,7 @@ namespace internal {
#define FOR_EACH_INTRINSIC_REGEXP(F, I) \
I(IsRegExp, 1, 1) \
F(RegExpBuildIndices, 3, 1) \
F(RegExpExec, 4, 1) \
F(RegExpExperimentalOneshotExec, 4, 1) \
F(RegExpExecMultiple, 4, 1) \
......
......@@ -243,8 +243,9 @@ std::string GenerateRandomFlags(FuzzerArgs* args) {
// TODO(mbid,v8:10765): Find a way to generate the kLinear flag sometimes,
// but only for patterns that are supported by the experimental engine.
constexpr size_t kFlagCount = JSRegExp::kFlagCount;
CHECK_EQ(JSRegExp::kLinear, 1 << (kFlagCount - 1));
CHECK_EQ(JSRegExp::kDotAll, 1 << (kFlagCount - 2));
CHECK_EQ(JSRegExp::kHasIndices, 1 << (kFlagCount - 1));
CHECK_EQ(JSRegExp::kLinear, 1 << (kFlagCount - 2));
CHECK_EQ(JSRegExp::kDotAll, 1 << (kFlagCount - 3));
STATIC_ASSERT((1 << kFlagCount) - 1 <= 0xFF);
const size_t flags = RandomByte(args) & ((1 << kFlagCount) - 1);
......@@ -258,6 +259,7 @@ std::string GenerateRandomFlags(FuzzerArgs* args) {
if (flags & JSRegExp::kSticky) buffer[cursor++] = 'y';
if (flags & JSRegExp::kUnicode) buffer[cursor++] = 'u';
if (flags & JSRegExp::kDotAll) buffer[cursor++] = 's';
if (flags & JSRegExp::kHasIndices) buffer[cursor++] = 'd';
return std::string(buffer, cursor);
}
......
// Copyright 2021 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: --no-harmony-regexp-match-indices
// Redefined hasIndices should not reflect in flags without
// --harmony-regexp-match-indices
{
let re = /./;
Object.defineProperty(re, "hasIndices", { get: function() { return true; } });
assertEquals("", re.flags);
}
......@@ -2,11 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --harmony-regexp-match-indices --expose-gc --stack-size=100
// Flags: --harmony-regexp-match-indices --allow-natives-syntax
// Flags: --expose-gc --stack-size=100
// Flags: --no-force-slow-path
// Sanity test.
{
const re = /a+(?<Z>z)?/;
const re = /a+(?<Z>z)?/d;
const m = re.exec("xaaaz");
assertEquals(m.indices, [[1, 5], [4, 5]]);
......@@ -15,7 +17,7 @@
// Capture groups that are not matched return `undefined`.
{
const re = /a+(?<Z>z)?/;
const re = /a+(?<Z>z)?/d;
const m = re.exec("xaaay");
assertEquals(m.indices, [[1, 4], undefined]);
......@@ -24,7 +26,7 @@
// Two capture groups.
{
const re = /a+(?<A>zz)?(?<B>ii)?/;
const re = /a+(?<A>zz)?(?<B>ii)?/d;
const m = re.exec("xaaazzii");
assertEquals(m.indices, [[1, 8], [4, 6], [6, 8]]);
......@@ -33,16 +35,16 @@
// No capture groups.
{
const re = /a+/;
const re = /a+/d;
const m = re.exec("xaaazzii");
assertEquals(m.indices [[1, 4]]);
assertEquals(m.indices, [[1, 4]]);
assertEquals(m.indices.groups, undefined);
}
// No match.
{
const re = /a+/;
const re = /a+/d;
const m = re.exec("xzzii");
assertEquals(null, m);
......@@ -50,8 +52,8 @@
// Unnamed capture groups.
{
const re = /a+(z)?/;
const m = re.exec("xaaaz")
const re = /a+(z)?/d;
const m = re.exec("xaaaz");
assertEquals(m.indices, [[1, 5], [4, 5]]);
assertEquals(m.indices.groups, undefined)
......@@ -59,7 +61,7 @@
// Named and unnamed capture groups.
{
const re = /a+(z)?(?<Y>y)?/;
const re = /a+(z)?(?<Y>y)?/d;
const m = re.exec("xaaazyy")
assertEquals(m.indices, [[1, 6], [4, 5], [5, 6]]);
......@@ -69,7 +71,7 @@
// Verify property overwrite.
{
const re = /a+(?<Z>z)?/;
const re = /a+(?<Z>z)?/d;
const m = re.exec("xaaaz");
m.indices = null;
......@@ -98,7 +100,7 @@
}
});
const re = /a+(?<Z>z)?/;
const re = /a+(?<Z>z)?/d;
const m = re.exec("xaaaz");
assertEquals(m.indices.groups, {'Z': [4, 5]})
......@@ -106,14 +108,14 @@
// Test atomic regexp.
{
const m = /undefined/.exec();
const m = (/undefined/d).exec();
assertEquals(m.indices, [[0, 9]]);
}
// Test deleting unrelated fields does not break.
{
const m = /undefined/.exec();
const m = (/undefined/d).exec();
delete m['index'];
gc();
assertEquals(m.indices, [[0, 9]]);
......@@ -121,7 +123,7 @@
// Stack overflow.
{
const re = /a+(?<Z>z)?/;
const re = /a+(?<Z>z)?/d;
const m = re.exec("xaaaz");
function rec() {
......@@ -138,9 +140,30 @@
// Match between matches.
{
const re = /a+(?<A>zz)?(?<B>ii)?/;
const re = /a+(?<A>zz)?(?<B>ii)?/d;
const m = re.exec("xaaazzii");
assertTrue(/b+(?<C>cccc)?/.test("llllllbbbbbbcccc"));
assertEquals(m.indices, [[1, 8], [4, 6], [6, 8]]);
assertEquals(m.indices.groups, {'A': [4, 6], 'B': [6, 8]});
}
// Redefined hasIndices should reflect in flags.
{
let re = /./;
Object.defineProperty(re, "hasIndices", { get: function() { return true; } });
assertEquals("d", re.flags);
}
{
// The flags field of a regexp should be sorted.
assertEquals("dgmsy", (/asdf/dymsg).flags);
// The 'hasIndices' member should be set according to the hasIndices flag.
assertTrue((/asdf/dymsg).hasIndices);
assertFalse((/asdf/ymsg).hasIndices);
// The new fields installed on the regexp prototype map shouldn't make
// unmodified regexps slow.
assertTrue(%RegexpIsUnmodified(/asdf/));
assertTrue(%RegexpIsUnmodified(/asdf/d));
}
......@@ -33,3 +33,10 @@ assertFalse((/asdf/ymsg).linear);
// unmodified regexps slow.
assertTrue(%RegexpIsUnmodified(/asdf/));
assertTrue(%RegexpIsUnmodified(/asdf/l));
// Redefined .linear should reflect in flags.
{
let re = /./;
Object.defineProperty(re, "linear", { get: function() { return true; } });
assertEquals("l", re.flags);
}
......@@ -15,8 +15,10 @@ assertThrows(() => new RegExp("((a*)*)*\1", "l"), SyntaxError)
assertFalse(RegExp.prototype.hasOwnProperty('linear'));
assertFalse(/123/.hasOwnProperty('linear'));
// Redefined .linear shouldn't reflect in flags without
// --enable-experimental-regexp-engine.
{
let re = /./;
re.linear = true;
Object.defineProperty(re, "linear", { get: function() { return true; } });
assertEquals("", re.flags);
}
......@@ -581,6 +581,9 @@
'built-ins/String/prototype/at/*': [FAIL],
'built-ins/TypedArray/prototype/at/*': [FAIL],
# Temporarily disabled until upstream tests are changed to use /d
'built-ins/RegExp/match-indices/*': [FAIL],
######################## NEEDS INVESTIGATION ###########################
# https://bugs.chromium.org/p/v8/issues/detail?id=7833
......
......@@ -1511,6 +1511,25 @@ TEST_F(ValueSerializerTest, DecodeLinearRegExp) {
i::FLAG_enable_experimental_regexp_engine = flag_was_enabled;
}
TEST_F(ValueSerializerTest, DecodeHasIndicesRegExp) {
bool flag_was_enabled = i::FLAG_harmony_regexp_match_indices;
// The last byte encodes the regexp flags.
std::vector<uint8_t> regexp_encoding = {0xFF, 0x09, 0x3F, 0x00, 0x52, 0x03,
0x66, 0x6F, 0x6F, 0xAD, 0x01};
i::FLAG_harmony_regexp_match_indices = true;
Local<Value> value = DecodeTest(regexp_encoding);
ASSERT_TRUE(value->IsRegExp());
ExpectScriptTrue("Object.getPrototypeOf(result) === RegExp.prototype");
ExpectScriptTrue("result.toString() === '/foo/dgmsy'");
i::FLAG_harmony_regexp_match_indices = false;
InvalidDecodeTest(regexp_encoding);
i::FLAG_harmony_regexp_match_indices = flag_was_enabled;
}
TEST_F(ValueSerializerTest, RoundTripMap) {
Local<Value> value = RoundTripTest("var m = new Map(); m.set(42, 'foo'); m;");
ASSERT_TRUE(value->IsMap());
......
......@@ -319,68 +319,68 @@ KNOWN_MAPS = {
("read_only_space", 0x03151): (67, "BasicBlockCountersMarkerMap"),
("read_only_space", 0x03195): (87, "ArrayBoilerplateDescriptionMap"),
("read_only_space", 0x0327d): (99, "InterceptorInfoMap"),
("read_only_space", 0x053d1): (72, "PromiseFulfillReactionJobTaskMap"),
("read_only_space", 0x053f9): (73, "PromiseRejectReactionJobTaskMap"),
("read_only_space", 0x05421): (74, "CallableTaskMap"),
("read_only_space", 0x05449): (75, "CallbackTaskMap"),
("read_only_space", 0x05471): (76, "PromiseResolveThenableJobTaskMap"),
("read_only_space", 0x05499): (79, "FunctionTemplateInfoMap"),
("read_only_space", 0x054c1): (80, "ObjectTemplateInfoMap"),
("read_only_space", 0x054e9): (81, "AccessCheckInfoMap"),
("read_only_space", 0x05511): (82, "AccessorInfoMap"),
("read_only_space", 0x05539): (83, "AccessorPairMap"),
("read_only_space", 0x05561): (84, "AliasedArgumentsEntryMap"),
("read_only_space", 0x05589): (85, "AllocationMementoMap"),
("read_only_space", 0x055b1): (88, "AsmWasmDataMap"),
("read_only_space", 0x055d9): (89, "AsyncGeneratorRequestMap"),
("read_only_space", 0x05601): (90, "BreakPointMap"),
("read_only_space", 0x05629): (91, "BreakPointInfoMap"),
("read_only_space", 0x05651): (92, "CachedTemplateObjectMap"),
("read_only_space", 0x05679): (94, "ClassPositionsMap"),
("read_only_space", 0x056a1): (95, "DebugInfoMap"),
("read_only_space", 0x056c9): (98, "FunctionTemplateRareDataMap"),
("read_only_space", 0x056f1): (100, "InterpreterDataMap"),
("read_only_space", 0x05719): (101, "ModuleRequestMap"),
("read_only_space", 0x05741): (102, "PromiseCapabilityMap"),
("read_only_space", 0x05769): (103, "PromiseReactionMap"),
("read_only_space", 0x05791): (104, "PropertyDescriptorObjectMap"),
("read_only_space", 0x057b9): (105, "PrototypeInfoMap"),
("read_only_space", 0x057e1): (106, "ScriptMap"),
("read_only_space", 0x05809): (107, "SourceTextModuleInfoEntryMap"),
("read_only_space", 0x05831): (108, "StackFrameInfoMap"),
("read_only_space", 0x05859): (109, "StackTraceFrameMap"),
("read_only_space", 0x05881): (110, "TemplateObjectDescriptionMap"),
("read_only_space", 0x058a9): (111, "Tuple2Map"),
("read_only_space", 0x058d1): (112, "WasmExceptionTagMap"),
("read_only_space", 0x058f9): (113, "WasmExportedFunctionDataMap"),
("read_only_space", 0x05921): (114, "WasmIndirectFunctionTableMap"),
("read_only_space", 0x05949): (115, "WasmJSFunctionDataMap"),
("read_only_space", 0x05971): (134, "SloppyArgumentsElementsMap"),
("read_only_space", 0x05999): (151, "DescriptorArrayMap"),
("read_only_space", 0x059c1): (156, "UncompiledDataWithoutPreparseDataMap"),
("read_only_space", 0x059e9): (155, "UncompiledDataWithPreparseDataMap"),
("read_only_space", 0x05a11): (171, "OnHeapBasicBlockProfilerDataMap"),
("read_only_space", 0x05a39): (180, "WasmCapiFunctionDataMap"),
("read_only_space", 0x05a61): (168, "InternalClassMap"),
("read_only_space", 0x05a89): (177, "SmiPairMap"),
("read_only_space", 0x05ab1): (176, "SmiBoxMap"),
("read_only_space", 0x05ad9): (145, "ExportedSubClassBaseMap"),
("read_only_space", 0x05b01): (146, "ExportedSubClassMap"),
("read_only_space", 0x05b29): (68, "AbstractInternalClassSubclass1Map"),
("read_only_space", 0x05b51): (69, "AbstractInternalClassSubclass2Map"),
("read_only_space", 0x05b79): (132, "InternalClassWithSmiElementsMap"),
("read_only_space", 0x05ba1): (169, "InternalClassWithStructElementsMap"),
("read_only_space", 0x05bc9): (147, "ExportedSubClass2Map"),
("read_only_space", 0x05bf1): (178, "SortStateMap"),
("read_only_space", 0x05c19): (86, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x05c41): (86, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x05c69): (77, "LoadHandler1Map"),
("read_only_space", 0x05c91): (77, "LoadHandler2Map"),
("read_only_space", 0x05cb9): (77, "LoadHandler3Map"),
("read_only_space", 0x05ce1): (78, "StoreHandler0Map"),
("read_only_space", 0x05d09): (78, "StoreHandler1Map"),
("read_only_space", 0x05d31): (78, "StoreHandler2Map"),
("read_only_space", 0x05d59): (78, "StoreHandler3Map"),
("read_only_space", 0x053d9): (72, "PromiseFulfillReactionJobTaskMap"),
("read_only_space", 0x05401): (73, "PromiseRejectReactionJobTaskMap"),
("read_only_space", 0x05429): (74, "CallableTaskMap"),
("read_only_space", 0x05451): (75, "CallbackTaskMap"),
("read_only_space", 0x05479): (76, "PromiseResolveThenableJobTaskMap"),
("read_only_space", 0x054a1): (79, "FunctionTemplateInfoMap"),
("read_only_space", 0x054c9): (80, "ObjectTemplateInfoMap"),
("read_only_space", 0x054f1): (81, "AccessCheckInfoMap"),
("read_only_space", 0x05519): (82, "AccessorInfoMap"),
("read_only_space", 0x05541): (83, "AccessorPairMap"),
("read_only_space", 0x05569): (84, "AliasedArgumentsEntryMap"),
("read_only_space", 0x05591): (85, "AllocationMementoMap"),
("read_only_space", 0x055b9): (88, "AsmWasmDataMap"),
("read_only_space", 0x055e1): (89, "AsyncGeneratorRequestMap"),
("read_only_space", 0x05609): (90, "BreakPointMap"),
("read_only_space", 0x05631): (91, "BreakPointInfoMap"),
("read_only_space", 0x05659): (92, "CachedTemplateObjectMap"),
("read_only_space", 0x05681): (94, "ClassPositionsMap"),
("read_only_space", 0x056a9): (95, "DebugInfoMap"),
("read_only_space", 0x056d1): (98, "FunctionTemplateRareDataMap"),
("read_only_space", 0x056f9): (100, "InterpreterDataMap"),
("read_only_space", 0x05721): (101, "ModuleRequestMap"),
("read_only_space", 0x05749): (102, "PromiseCapabilityMap"),
("read_only_space", 0x05771): (103, "PromiseReactionMap"),
("read_only_space", 0x05799): (104, "PropertyDescriptorObjectMap"),
("read_only_space", 0x057c1): (105, "PrototypeInfoMap"),
("read_only_space", 0x057e9): (106, "ScriptMap"),
("read_only_space", 0x05811): (107, "SourceTextModuleInfoEntryMap"),
("read_only_space", 0x05839): (108, "StackFrameInfoMap"),
("read_only_space", 0x05861): (109, "StackTraceFrameMap"),
("read_only_space", 0x05889): (110, "TemplateObjectDescriptionMap"),
("read_only_space", 0x058b1): (111, "Tuple2Map"),
("read_only_space", 0x058d9): (112, "WasmExceptionTagMap"),
("read_only_space", 0x05901): (113, "WasmExportedFunctionDataMap"),
("read_only_space", 0x05929): (114, "WasmIndirectFunctionTableMap"),
("read_only_space", 0x05951): (115, "WasmJSFunctionDataMap"),
("read_only_space", 0x05979): (134, "SloppyArgumentsElementsMap"),
("read_only_space", 0x059a1): (151, "DescriptorArrayMap"),
("read_only_space", 0x059c9): (156, "UncompiledDataWithoutPreparseDataMap"),
("read_only_space", 0x059f1): (155, "UncompiledDataWithPreparseDataMap"),
("read_only_space", 0x05a19): (171, "OnHeapBasicBlockProfilerDataMap"),
("read_only_space", 0x05a41): (180, "WasmCapiFunctionDataMap"),
("read_only_space", 0x05a69): (168, "InternalClassMap"),
("read_only_space", 0x05a91): (177, "SmiPairMap"),
("read_only_space", 0x05ab9): (176, "SmiBoxMap"),
("read_only_space", 0x05ae1): (145, "ExportedSubClassBaseMap"),
("read_only_space", 0x05b09): (146, "ExportedSubClassMap"),
("read_only_space", 0x05b31): (68, "AbstractInternalClassSubclass1Map"),
("read_only_space", 0x05b59): (69, "AbstractInternalClassSubclass2Map"),
("read_only_space", 0x05b81): (132, "InternalClassWithSmiElementsMap"),
("read_only_space", 0x05ba9): (169, "InternalClassWithStructElementsMap"),
("read_only_space", 0x05bd1): (147, "ExportedSubClass2Map"),
("read_only_space", 0x05bf9): (178, "SortStateMap"),
("read_only_space", 0x05c21): (86, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x05c49): (86, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x05c71): (77, "LoadHandler1Map"),
("read_only_space", 0x05c99): (77, "LoadHandler2Map"),
("read_only_space", 0x05cc1): (77, "LoadHandler3Map"),
("read_only_space", 0x05ce9): (78, "StoreHandler0Map"),
("read_only_space", 0x05d11): (78, "StoreHandler1Map"),
("read_only_space", 0x05d39): (78, "StoreHandler2Map"),
("read_only_space", 0x05d61): (78, "StoreHandler3Map"),
("map_space", 0x02119): (1057, "ExternalMap"),
("map_space", 0x02141): (1098, "JSMessageObjectMap"),
("map_space", 0x02169): (181, "WasmRttEqrefMap"),
......@@ -447,52 +447,51 @@ KNOWN_OBJECTS = {
("old_space", 0x022f5): "FunctionNameAccessor",
("old_space", 0x02339): "FunctionLengthAccessor",
("old_space", 0x0237d): "FunctionPrototypeAccessor",
("old_space", 0x023c1): "RegExpResultIndicesAccessor",
("old_space", 0x02405): "StringLengthAccessor",
("old_space", 0x02449): "InvalidPrototypeValidityCell",
("old_space", 0x02535): "EmptyScript",
("old_space", 0x02575): "ManyClosuresCell",
("old_space", 0x02581): "ArrayConstructorProtector",
("old_space", 0x02595): "NoElementsProtector",
("old_space", 0x025a9): "IsConcatSpreadableProtector",
("old_space", 0x025bd): "ArraySpeciesProtector",
("old_space", 0x025d1): "TypedArraySpeciesProtector",
("old_space", 0x025e5): "PromiseSpeciesProtector",
("old_space", 0x025f9): "RegExpSpeciesProtector",
("old_space", 0x0260d): "StringLengthProtector",
("old_space", 0x02621): "ArrayIteratorProtector",
("old_space", 0x02635): "ArrayBufferDetachingProtector",
("old_space", 0x02649): "PromiseHookProtector",
("old_space", 0x0265d): "PromiseResolveProtector",
("old_space", 0x02671): "MapIteratorProtector",
("old_space", 0x02685): "PromiseThenProtector",
("old_space", 0x02699): "SetIteratorProtector",
("old_space", 0x026ad): "StringIteratorProtector",
("old_space", 0x026c1): "SingleCharacterStringCache",
("old_space", 0x02ac9): "StringSplitCache",
("old_space", 0x02ed1): "RegExpMultipleCache",
("old_space", 0x032d9): "BuiltinsConstantsTable",
("old_space", 0x036cd): "AsyncFunctionAwaitRejectSharedFun",
("old_space", 0x036f1): "AsyncFunctionAwaitResolveSharedFun",
("old_space", 0x03715): "AsyncGeneratorAwaitRejectSharedFun",
("old_space", 0x03739): "AsyncGeneratorAwaitResolveSharedFun",
("old_space", 0x0375d): "AsyncGeneratorYieldResolveSharedFun",
("old_space", 0x03781): "AsyncGeneratorReturnResolveSharedFun",
("old_space", 0x037a5): "AsyncGeneratorReturnClosedRejectSharedFun",
("old_space", 0x037c9): "AsyncGeneratorReturnClosedResolveSharedFun",
("old_space", 0x037ed): "AsyncIteratorValueUnwrapSharedFun",
("old_space", 0x03811): "PromiseAllResolveElementSharedFun",
("old_space", 0x03835): "PromiseAllSettledResolveElementSharedFun",
("old_space", 0x03859): "PromiseAllSettledRejectElementSharedFun",
("old_space", 0x0387d): "PromiseAnyRejectElementSharedFun",
("old_space", 0x038a1): "PromiseCapabilityDefaultRejectSharedFun",
("old_space", 0x038c5): "PromiseCapabilityDefaultResolveSharedFun",
("old_space", 0x038e9): "PromiseCatchFinallySharedFun",
("old_space", 0x0390d): "PromiseGetCapabilitiesExecutorSharedFun",
("old_space", 0x03931): "PromiseThenFinallySharedFun",
("old_space", 0x03955): "PromiseThrowerFinallySharedFun",
("old_space", 0x03979): "PromiseValueThunkFinallySharedFun",
("old_space", 0x0399d): "ProxyRevokeSharedFun",
("old_space", 0x023c1): "StringLengthAccessor",
("old_space", 0x02405): "InvalidPrototypeValidityCell",
("old_space", 0x024f1): "EmptyScript",
("old_space", 0x02531): "ManyClosuresCell",
("old_space", 0x0253d): "ArrayConstructorProtector",
("old_space", 0x02551): "NoElementsProtector",
("old_space", 0x02565): "IsConcatSpreadableProtector",
("old_space", 0x02579): "ArraySpeciesProtector",
("old_space", 0x0258d): "TypedArraySpeciesProtector",
("old_space", 0x025a1): "PromiseSpeciesProtector",
("old_space", 0x025b5): "RegExpSpeciesProtector",
("old_space", 0x025c9): "StringLengthProtector",
("old_space", 0x025dd): "ArrayIteratorProtector",
("old_space", 0x025f1): "ArrayBufferDetachingProtector",
("old_space", 0x02605): "PromiseHookProtector",
("old_space", 0x02619): "PromiseResolveProtector",
("old_space", 0x0262d): "MapIteratorProtector",
("old_space", 0x02641): "PromiseThenProtector",
("old_space", 0x02655): "SetIteratorProtector",
("old_space", 0x02669): "StringIteratorProtector",
("old_space", 0x0267d): "SingleCharacterStringCache",
("old_space", 0x02a85): "StringSplitCache",
("old_space", 0x02e8d): "RegExpMultipleCache",
("old_space", 0x03295): "BuiltinsConstantsTable",
("old_space", 0x0368d): "AsyncFunctionAwaitRejectSharedFun",
("old_space", 0x036b1): "AsyncFunctionAwaitResolveSharedFun",
("old_space", 0x036d5): "AsyncGeneratorAwaitRejectSharedFun",
("old_space", 0x036f9): "AsyncGeneratorAwaitResolveSharedFun",
("old_space", 0x0371d): "AsyncGeneratorYieldResolveSharedFun",
("old_space", 0x03741): "AsyncGeneratorReturnResolveSharedFun",
("old_space", 0x03765): "AsyncGeneratorReturnClosedRejectSharedFun",
("old_space", 0x03789): "AsyncGeneratorReturnClosedResolveSharedFun",
("old_space", 0x037ad): "AsyncIteratorValueUnwrapSharedFun",
("old_space", 0x037d1): "PromiseAllResolveElementSharedFun",
("old_space", 0x037f5): "PromiseAllSettledResolveElementSharedFun",
("old_space", 0x03819): "PromiseAllSettledRejectElementSharedFun",
("old_space", 0x0383d): "PromiseAnyRejectElementSharedFun",
("old_space", 0x03861): "PromiseCapabilityDefaultRejectSharedFun",
("old_space", 0x03885): "PromiseCapabilityDefaultResolveSharedFun",
("old_space", 0x038a9): "PromiseCatchFinallySharedFun",
("old_space", 0x038cd): "PromiseGetCapabilitiesExecutorSharedFun",
("old_space", 0x038f1): "PromiseThenFinallySharedFun",
("old_space", 0x03915): "PromiseThrowerFinallySharedFun",
("old_space", 0x03939): "PromiseValueThunkFinallySharedFun",
("old_space", 0x0395d): "ProxyRevokeSharedFun",
}
# Lower 32 bits of first page addresses for various heap spaces.
......
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