Commit fa2bed3f authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[regexp] Move the RegExpSpeciesProtector to the native context

Prior to this CL, it was possible to pollute another context's
fast/slow-path state for RegExp builtins due to the species protector
being per-isolate rather than per-context. Among other things, this
means that iframes can slow down the main site, and slowdowns persist
across page reloads and navigation within the same tab.

This CL thus moves the RegExpSpeciesProtector to the native context.

The same should be done for all other protectors in the future.

Bug: chromium:977382, v8:5577, v8:9463
Change-Id: I577f470229cb9dfcd4a88c20b1b9111c65a9b85f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1695465
Auto-Submit: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62631}
parent a61ce8a0
...@@ -928,9 +928,9 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExp( ...@@ -928,9 +928,9 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExp(
// This should only be needed for String.p.(split||matchAll), but we are // This should only be needed for String.p.(split||matchAll), but we are
// conservative here. // conservative here.
GotoIf(IsRegExpSpeciesProtectorCellInvalid(), if_ismodified); TNode<Context> native_context = LoadNativeContext(context);
GotoIf(IsRegExpSpeciesProtectorCellInvalid(native_context), if_ismodified);
Node* const native_context = LoadNativeContext(context);
Node* const regexp_fun = Node* const regexp_fun =
LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
Node* const initial_map = Node* const initial_map =
......
...@@ -6098,10 +6098,13 @@ TNode<BoolT> CodeStubAssembler::IsTypedArraySpeciesProtectorCellInvalid() { ...@@ -6098,10 +6098,13 @@ TNode<BoolT> CodeStubAssembler::IsTypedArraySpeciesProtectorCellInvalid() {
return WordEqual(cell_value, invalid); return WordEqual(cell_value, invalid);
} }
TNode<BoolT> CodeStubAssembler::IsRegExpSpeciesProtectorCellInvalid() { TNode<BoolT> CodeStubAssembler::IsRegExpSpeciesProtectorCellInvalid(
Node* invalid = SmiConstant(Isolate::kProtectorInvalid); TNode<Context> native_context) {
Node* cell = LoadRoot(RootIndex::kRegExpSpeciesProtector); CSA_ASSERT(this, IsNativeContext(native_context));
Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset); TNode<PropertyCell> cell = CAST(LoadContextElement(
native_context, Context::REGEXP_SPECIES_PROTECTOR_INDEX));
TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
TNode<Smi> invalid = SmiConstant(Isolate::kProtectorInvalid);
return WordEqual(cell_value, invalid); return WordEqual(cell_value, invalid);
} }
......
...@@ -39,7 +39,6 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol }; ...@@ -39,7 +39,6 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
PromiseSpeciesProtector) \ PromiseSpeciesProtector) \
V(TypedArraySpeciesProtector, typed_array_species_protector, \ V(TypedArraySpeciesProtector, typed_array_species_protector, \
TypedArraySpeciesProtector) \ TypedArraySpeciesProtector) \
V(RegExpSpeciesProtector, regexp_species_protector, RegExpSpeciesProtector)
#define HEAP_IMMUTABLE_IMMOVABLE_OBJECT_LIST(V) \ #define HEAP_IMMUTABLE_IMMOVABLE_OBJECT_LIST(V) \
V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \ V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \
...@@ -2321,7 +2320,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ...@@ -2321,7 +2320,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsPromiseThenProtectorCellInvalid(); TNode<BoolT> IsPromiseThenProtectorCellInvalid();
TNode<BoolT> IsArraySpeciesProtectorCellInvalid(); TNode<BoolT> IsArraySpeciesProtectorCellInvalid();
TNode<BoolT> IsTypedArraySpeciesProtectorCellInvalid(); TNode<BoolT> IsTypedArraySpeciesProtectorCellInvalid();
TNode<BoolT> IsRegExpSpeciesProtectorCellInvalid(); TNode<BoolT> IsRegExpSpeciesProtectorCellInvalid(
TNode<Context> native_context);
TNode<BoolT> IsPromiseSpeciesProtectorCellInvalid(); TNode<BoolT> IsPromiseSpeciesProtectorCellInvalid();
TNode<BoolT> IsMockArrayBufferAllocatorFlag() { TNode<BoolT> IsMockArrayBufferAllocatorFlag() {
......
...@@ -145,9 +145,10 @@ bool Isolate::IsTypedArraySpeciesLookupChainIntact() { ...@@ -145,9 +145,10 @@ bool Isolate::IsTypedArraySpeciesLookupChainIntact() {
Smi::ToInt(species_cell.value()) == kProtectorValid; Smi::ToInt(species_cell.value()) == kProtectorValid;
} }
bool Isolate::IsRegExpSpeciesLookupChainIntact() { bool Isolate::IsRegExpSpeciesLookupChainIntact(
PropertyCell species_cell = Handle<NativeContext> native_context) {
PropertyCell::cast(root(RootIndex::kRegExpSpeciesProtector)); DCHECK_EQ(*native_context, this->raw_native_context());
PropertyCell species_cell = native_context->regexp_species_protector();
return species_cell.value().IsSmi() && return species_cell.value().IsSmi() &&
Smi::ToInt(species_cell.value()) == kProtectorValid; Smi::ToInt(species_cell.value()) == kProtectorValid;
} }
......
...@@ -3979,13 +3979,16 @@ void Isolate::InvalidateTypedArraySpeciesProtector() { ...@@ -3979,13 +3979,16 @@ void Isolate::InvalidateTypedArraySpeciesProtector() {
DCHECK(!IsTypedArraySpeciesLookupChainIntact()); DCHECK(!IsTypedArraySpeciesLookupChainIntact());
} }
void Isolate::InvalidateRegExpSpeciesProtector() { void Isolate::InvalidateRegExpSpeciesProtector(
DCHECK(factory()->regexp_species_protector()->value().IsSmi()); Handle<NativeContext> native_context) {
DCHECK(IsRegExpSpeciesLookupChainIntact()); DCHECK_EQ(*native_context, this->raw_native_context());
DCHECK(native_context->regexp_species_protector().value().IsSmi());
DCHECK(IsRegExpSpeciesLookupChainIntact(native_context));
Handle<PropertyCell> species_cell(native_context->regexp_species_protector(),
this);
PropertyCell::SetValueWithInvalidation( PropertyCell::SetValueWithInvalidation(
this, factory()->regexp_species_protector(), this, species_cell, handle(Smi::FromInt(kProtectorInvalid), this));
handle(Smi::FromInt(kProtectorInvalid), this)); DCHECK(!IsRegExpSpeciesLookupChainIntact(native_context));
DCHECK(!IsRegExpSpeciesLookupChainIntact());
} }
void Isolate::InvalidatePromiseSpeciesProtector() { void Isolate::InvalidatePromiseSpeciesProtector() {
......
...@@ -1176,7 +1176,8 @@ class Isolate final : private HiddenFactory { ...@@ -1176,7 +1176,8 @@ class Isolate final : private HiddenFactory {
inline bool IsArraySpeciesLookupChainIntact(); inline bool IsArraySpeciesLookupChainIntact();
inline bool IsTypedArraySpeciesLookupChainIntact(); inline bool IsTypedArraySpeciesLookupChainIntact();
inline bool IsRegExpSpeciesLookupChainIntact(); inline bool IsRegExpSpeciesLookupChainIntact(
Handle<NativeContext> native_context);
// Check that the @@species protector is intact, which guards the lookup of // Check that the @@species protector is intact, which guards the lookup of
// "constructor" on JSPromise instances, whose [[Prototype]] is the initial // "constructor" on JSPromise instances, whose [[Prototype]] is the initial
...@@ -1261,7 +1262,7 @@ class Isolate final : private HiddenFactory { ...@@ -1261,7 +1262,7 @@ class Isolate final : private HiddenFactory {
void InvalidateArrayConstructorProtector(); void InvalidateArrayConstructorProtector();
void InvalidateArraySpeciesProtector(); void InvalidateArraySpeciesProtector();
void InvalidateTypedArraySpeciesProtector(); void InvalidateTypedArraySpeciesProtector();
void InvalidateRegExpSpeciesProtector(); void InvalidateRegExpSpeciesProtector(Handle<NativeContext> native_context);
void InvalidatePromiseSpeciesProtector(); void InvalidatePromiseSpeciesProtector();
void InvalidateIsConcatSpreadableProtector(); void InvalidateIsConcatSpreadableProtector();
void InvalidateStringLengthOverflowProtector(); void InvalidateStringLengthOverflowProtector();
......
...@@ -874,10 +874,6 @@ void Heap::CreateInitialObjects() { ...@@ -874,10 +874,6 @@ void Heap::CreateInitialObjects() {
cell->set_value(Smi::FromInt(Isolate::kProtectorValid)); cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
set_promise_species_protector(*cell); set_promise_species_protector(*cell);
cell = factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
set_regexp_species_protector(*cell);
cell = factory->NewPropertyCell(factory->empty_string()); cell = factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Isolate::kProtectorValid)); cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
set_string_iterator_protector(*cell); set_string_iterator_protector(*cell);
......
...@@ -2597,6 +2597,14 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -2597,6 +2597,14 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Handle<RegExpMatchInfo> last_match_info = factory->NewRegExpMatchInfo(); Handle<RegExpMatchInfo> last_match_info = factory->NewRegExpMatchInfo();
native_context()->set_regexp_last_match_info(*last_match_info); native_context()->set_regexp_last_match_info(*last_match_info);
// Install the species protector cell.
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
native_context()->set_regexp_species_protector(*cell);
}
// Force the RegExp constructor to fast properties, so that we can use the // Force the RegExp constructor to fast properties, so that we can use the
// fast paths for various things like // fast paths for various things like
// //
......
...@@ -238,11 +238,12 @@ enum ContextLookupFlags { ...@@ -238,11 +238,12 @@ enum ContextLookupFlags {
V(REGEXP_EXEC_FUNCTION_INDEX, JSFunction, regexp_exec_function) \ V(REGEXP_EXEC_FUNCTION_INDEX, JSFunction, regexp_exec_function) \
V(REGEXP_FUNCTION_INDEX, JSFunction, regexp_function) \ V(REGEXP_FUNCTION_INDEX, JSFunction, regexp_function) \
V(REGEXP_LAST_MATCH_INFO_INDEX, RegExpMatchInfo, regexp_last_match_info) \ V(REGEXP_LAST_MATCH_INFO_INDEX, RegExpMatchInfo, regexp_last_match_info) \
V(REGEXP_PROTOTYPE_INDEX, JSObject, regexp_prototype) \
V(REGEXP_PROTOTYPE_MAP_INDEX, Map, regexp_prototype_map) \ V(REGEXP_PROTOTYPE_MAP_INDEX, Map, regexp_prototype_map) \
V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map) \
V(REGEXP_SPECIES_PROTECTOR_INDEX, PropertyCell, regexp_species_protector) \
V(INITIAL_REGEXP_STRING_ITERATOR_PROTOTYPE_MAP_INDEX, Map, \ V(INITIAL_REGEXP_STRING_ITERATOR_PROTOTYPE_MAP_INDEX, Map, \
initial_regexp_string_iterator_prototype_map) \ initial_regexp_string_iterator_prototype_map) \
V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map) \
V(REGEXP_PROTOTYPE_INDEX, JSObject, regexp_prototype) \
V(SCRIPT_CONTEXT_TABLE_INDEX, ScriptContextTable, script_context_table) \ V(SCRIPT_CONTEXT_TABLE_INDEX, ScriptContextTable, script_context_table) \
V(SCRIPT_EXECUTION_CALLBACK_INDEX, Object, script_execution_callback) \ V(SCRIPT_EXECUTION_CALLBACK_INDEX, Object, script_execution_callback) \
V(SECURITY_TOKEN_INDEX, Object, security_token) \ V(SECURITY_TOKEN_INDEX, Object, security_token) \
......
...@@ -233,11 +233,13 @@ bool IsTypedArrayFunctionInAnyContext(Isolate* isolate, JSReceiver holder) { ...@@ -233,11 +233,13 @@ bool IsTypedArrayFunctionInAnyContext(Isolate* isolate, JSReceiver holder) {
void LookupIterator::InternalUpdateProtector() { void LookupIterator::InternalUpdateProtector() {
if (isolate_->bootstrapper()->IsActive()) return; if (isolate_->bootstrapper()->IsActive()) return;
Handle<NativeContext> native_context = isolate_->native_context();
ReadOnlyRoots roots(isolate_); ReadOnlyRoots roots(isolate_);
if (*name_ == roots.constructor_string()) { if (*name_ == roots.constructor_string()) {
if (!isolate_->IsArraySpeciesLookupChainIntact() && if (!isolate_->IsArraySpeciesLookupChainIntact() &&
!isolate_->IsPromiseSpeciesLookupChainIntact() && !isolate_->IsPromiseSpeciesLookupChainIntact() &&
!isolate_->IsRegExpSpeciesLookupChainIntact() && !isolate_->IsRegExpSpeciesLookupChainIntact(native_context) &&
!isolate_->IsTypedArraySpeciesLookupChainIntact()) { !isolate_->IsTypedArraySpeciesLookupChainIntact()) {
return; return;
} }
...@@ -253,8 +255,8 @@ void LookupIterator::InternalUpdateProtector() { ...@@ -253,8 +255,8 @@ void LookupIterator::InternalUpdateProtector() {
isolate_->InvalidatePromiseSpeciesProtector(); isolate_->InvalidatePromiseSpeciesProtector();
return; return;
} else if (holder_->IsJSRegExp(isolate_)) { } else if (holder_->IsJSRegExp(isolate_)) {
if (!isolate_->IsRegExpSpeciesLookupChainIntact()) return; if (!isolate_->IsRegExpSpeciesLookupChainIntact(native_context)) return;
isolate_->InvalidateRegExpSpeciesProtector(); isolate_->InvalidateRegExpSpeciesProtector(native_context);
return; return;
} else if (holder_->IsJSTypedArray(isolate_)) { } else if (holder_->IsJSTypedArray(isolate_)) {
if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return; if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
...@@ -280,8 +282,8 @@ void LookupIterator::InternalUpdateProtector() { ...@@ -280,8 +282,8 @@ void LookupIterator::InternalUpdateProtector() {
isolate_->InvalidatePromiseSpeciesProtector(); isolate_->InvalidatePromiseSpeciesProtector();
} else if (isolate_->IsInAnyContext(*holder_, } else if (isolate_->IsInAnyContext(*holder_,
Context::REGEXP_PROTOTYPE_INDEX)) { Context::REGEXP_PROTOTYPE_INDEX)) {
if (!isolate_->IsRegExpSpeciesLookupChainIntact()) return; if (!isolate_->IsRegExpSpeciesLookupChainIntact(native_context)) return;
isolate_->InvalidateRegExpSpeciesProtector(); isolate_->InvalidateRegExpSpeciesProtector(native_context);
} else if (isolate_->IsInAnyContext( } else if (isolate_->IsInAnyContext(
holder_->map(isolate_).prototype(isolate_), holder_->map(isolate_).prototype(isolate_),
Context::TYPED_ARRAY_PROTOTYPE_INDEX)) { Context::TYPED_ARRAY_PROTOTYPE_INDEX)) {
...@@ -315,7 +317,7 @@ void LookupIterator::InternalUpdateProtector() { ...@@ -315,7 +317,7 @@ void LookupIterator::InternalUpdateProtector() {
} else if (*name_ == roots.species_symbol()) { } else if (*name_ == roots.species_symbol()) {
if (!isolate_->IsArraySpeciesLookupChainIntact() && if (!isolate_->IsArraySpeciesLookupChainIntact() &&
!isolate_->IsPromiseSpeciesLookupChainIntact() && !isolate_->IsPromiseSpeciesLookupChainIntact() &&
!isolate_->IsRegExpSpeciesLookupChainIntact() && !isolate_->IsRegExpSpeciesLookupChainIntact(native_context) &&
!isolate_->IsTypedArraySpeciesLookupChainIntact()) { !isolate_->IsTypedArraySpeciesLookupChainIntact()) {
return; return;
} }
...@@ -332,8 +334,8 @@ void LookupIterator::InternalUpdateProtector() { ...@@ -332,8 +334,8 @@ void LookupIterator::InternalUpdateProtector() {
isolate_->InvalidatePromiseSpeciesProtector(); isolate_->InvalidatePromiseSpeciesProtector();
} else if (isolate_->IsInAnyContext(*holder_, } else if (isolate_->IsInAnyContext(*holder_,
Context::REGEXP_FUNCTION_INDEX)) { Context::REGEXP_FUNCTION_INDEX)) {
if (!isolate_->IsRegExpSpeciesLookupChainIntact()) return; if (!isolate_->IsRegExpSpeciesLookupChainIntact(native_context)) return;
isolate_->InvalidateRegExpSpeciesProtector(); isolate_->InvalidateRegExpSpeciesProtector(native_context);
} else if (IsTypedArrayFunctionInAnyContext(isolate_, *holder_)) { } else if (IsTypedArrayFunctionInAnyContext(isolate_, *holder_)) {
if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return; if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
isolate_->InvalidateTypedArraySpeciesProtector(); isolate_->InvalidateTypedArraySpeciesProtector();
......
...@@ -179,7 +179,9 @@ bool RegExpUtils::IsUnmodifiedRegExp(Isolate* isolate, Handle<Object> obj) { ...@@ -179,7 +179,9 @@ bool RegExpUtils::IsUnmodifiedRegExp(Isolate* isolate, Handle<Object> obj) {
return false; return false;
} }
if (!isolate->IsRegExpSpeciesLookupChainIntact()) return false; if (!isolate->IsRegExpSpeciesLookupChainIntact(isolate->native_context())) {
return false;
}
// The smi check is required to omit ToLength(lastIndex) calls with possible // The smi check is required to omit ToLength(lastIndex) calls with possible
// user-code execution on the fast path. // user-code execution on the fast path.
......
...@@ -219,7 +219,6 @@ class Symbol; ...@@ -219,7 +219,6 @@ class Symbol;
V(Cell, is_concat_spreadable_protector, IsConcatSpreadableProtector) \ V(Cell, is_concat_spreadable_protector, IsConcatSpreadableProtector) \
V(PropertyCell, array_species_protector, ArraySpeciesProtector) \ V(PropertyCell, array_species_protector, ArraySpeciesProtector) \
V(PropertyCell, typed_array_species_protector, TypedArraySpeciesProtector) \ V(PropertyCell, typed_array_species_protector, TypedArraySpeciesProtector) \
V(PropertyCell, regexp_species_protector, RegExpSpeciesProtector) \
V(PropertyCell, promise_species_protector, PromiseSpeciesProtector) \ V(PropertyCell, promise_species_protector, PromiseSpeciesProtector) \
V(Cell, string_length_protector, StringLengthProtector) \ V(Cell, string_length_protector, StringLengthProtector) \
V(PropertyCell, array_iterator_protector, ArrayIteratorProtector) \ V(PropertyCell, array_iterator_protector, ArrayIteratorProtector) \
......
...@@ -409,21 +409,20 @@ KNOWN_OBJECTS = { ...@@ -409,21 +409,20 @@ KNOWN_OBJECTS = {
("old_space", 0x006e9): "IsConcatSpreadableProtector", ("old_space", 0x006e9): "IsConcatSpreadableProtector",
("old_space", 0x006f9): "ArraySpeciesProtector", ("old_space", 0x006f9): "ArraySpeciesProtector",
("old_space", 0x00721): "TypedArraySpeciesProtector", ("old_space", 0x00721): "TypedArraySpeciesProtector",
("old_space", 0x00749): "RegExpSpeciesProtector", ("old_space", 0x00749): "PromiseSpeciesProtector",
("old_space", 0x00771): "PromiseSpeciesProtector", ("old_space", 0x00771): "StringLengthProtector",
("old_space", 0x00799): "StringLengthProtector", ("old_space", 0x00781): "ArrayIteratorProtector",
("old_space", 0x007a9): "ArrayIteratorProtector", ("old_space", 0x007a9): "ArrayBufferDetachingProtector",
("old_space", 0x007d1): "ArrayBufferDetachingProtector", ("old_space", 0x007d1): "PromiseHookProtector",
("old_space", 0x007f9): "PromiseHookProtector", ("old_space", 0x007f9): "PromiseResolveProtector",
("old_space", 0x00821): "PromiseResolveProtector", ("old_space", 0x00809): "MapIteratorProtector",
("old_space", 0x00831): "MapIteratorProtector", ("old_space", 0x00831): "PromiseThenProtector",
("old_space", 0x00859): "PromiseThenProtector", ("old_space", 0x00859): "SetIteratorProtector",
("old_space", 0x00881): "SetIteratorProtector", ("old_space", 0x00881): "StringIteratorProtector",
("old_space", 0x008a9): "StringIteratorProtector", ("old_space", 0x008a9): "SingleCharacterStringCache",
("old_space", 0x008d1): "SingleCharacterStringCache", ("old_space", 0x010b9): "StringSplitCache",
("old_space", 0x010e1): "StringSplitCache", ("old_space", 0x018c9): "RegExpMultipleCache",
("old_space", 0x018f1): "RegExpMultipleCache", ("old_space", 0x020d9): "BuiltinsConstantsTable",
("old_space", 0x02101): "BuiltinsConstantsTable",
} }
# List of known V8 Frame Markers. # List of known V8 Frame Markers.
......
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