[protectors] Move regexp species protector back to the isolate
This reverts the changes made in https://chromium-review.googlesource.com/c/v8/v8/+/1695465 https://chromium-review.googlesource.com/c/v8/v8/+/1776078 We originally moved this protector to the native context to avoid cross-native-context pollution of protector state. Ideally, invalidating a protector in one NC should not affect any other NC. But as it turns out, having the protector on the NC causes more problems than it solves since all affected callers now need to find the correct native context to check. Sometimes (e.g. in CSA regexp builtins) it is possible to blindly check the current NC, but the reasoning behind this optimization is tricky to understand. Sometimes, fetching the correct NC is not possible due to access restrictions. These implementation complexities outweigh the (unknown) potential performance benefits. In the future we should attempt to move away from the protector concept for these kinds of checks. Bug: chromium:1069964,v8:9463 Change-Id: I2cbb2ec7266282165dae5e4a6c8bdbda520c50a9 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2157382 Reviewed-by: Igor Sheludko <ishell@chromium.org> Reviewed-by: Dominik Inführ <dinfuehr@chromium.org> Commit-Queue: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#67415}
This commit is contained in:
parent
f8be9948d3
commit
af45cf6dae
@ -729,13 +729,9 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExp(
|
||||
|
||||
// This should only be needed for String.p.(split||matchAll), but we are
|
||||
// conservative here.
|
||||
// Note: we are using the current native context here, which may or may not
|
||||
// match the object's native context. That's fine: in case of a mismatch, we
|
||||
// will bail in the next step when comparing the object's map against the
|
||||
// current native context's initial regexp map.
|
||||
TNode<NativeContext> native_context = LoadNativeContext(context);
|
||||
GotoIf(IsRegExpSpeciesProtectorCellInvalid(native_context), if_ismodified);
|
||||
GotoIf(IsRegExpSpeciesProtectorCellInvalid(), if_ismodified);
|
||||
|
||||
TNode<NativeContext> native_context = LoadNativeContext(context);
|
||||
TNode<JSFunction> regexp_fun =
|
||||
CAST(LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX));
|
||||
TNode<Map> initial_map = CAST(
|
||||
|
@ -5879,12 +5879,10 @@ TNode<BoolT> CodeStubAssembler::IsTypedArraySpeciesProtectorCellInvalid() {
|
||||
return TaggedEqual(cell_value, invalid);
|
||||
}
|
||||
|
||||
TNode<BoolT> CodeStubAssembler::IsRegExpSpeciesProtectorCellInvalid(
|
||||
TNode<NativeContext> native_context) {
|
||||
TNode<PropertyCell> cell = CAST(LoadContextElement(
|
||||
native_context, Context::REGEXP_SPECIES_PROTECTOR_INDEX));
|
||||
TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
|
||||
TNode<BoolT> CodeStubAssembler::IsRegExpSpeciesProtectorCellInvalid() {
|
||||
TNode<Smi> invalid = SmiConstant(Protectors::kProtectorInvalid);
|
||||
TNode<PropertyCell> cell = RegExpSpeciesProtectorConstant();
|
||||
TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
|
||||
return TaggedEqual(cell_value, invalid);
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,7 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
|
||||
V(PromiseSpeciesProtector, promise_species_protector, \
|
||||
PromiseSpeciesProtector) \
|
||||
V(PromiseThenProtector, promise_then_protector, PromiseThenProtector) \
|
||||
V(RegExpSpeciesProtector, regexp_species_protector, RegExpSpeciesProtector) \
|
||||
V(SetIteratorProtector, set_iterator_protector, SetIteratorProtector) \
|
||||
V(SingleCharacterStringCache, single_character_string_cache, \
|
||||
SingleCharacterStringCache) \
|
||||
@ -2657,8 +2658,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
TNode<BoolT> IsPromiseThenProtectorCellInvalid();
|
||||
TNode<BoolT> IsArraySpeciesProtectorCellInvalid();
|
||||
TNode<BoolT> IsTypedArraySpeciesProtectorCellInvalid();
|
||||
TNode<BoolT> IsRegExpSpeciesProtectorCellInvalid(
|
||||
TNode<NativeContext> native_context);
|
||||
TNode<BoolT> IsRegExpSpeciesProtectorCellInvalid();
|
||||
TNode<BoolT> IsPromiseSpeciesProtectorCellInvalid();
|
||||
|
||||
TNode<BoolT> IsMockArrayBufferAllocatorFlag() {
|
||||
|
@ -13,14 +13,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#define DEFINE_PROTECTOR_ON_NATIVE_CONTEXT_CHECK(name, cell) \
|
||||
bool Protectors::Is##name##Intact(Handle<NativeContext> native_context) { \
|
||||
PropertyCell species_cell = native_context->cell(); \
|
||||
return species_cell.value().IsSmi() && \
|
||||
Smi::ToInt(species_cell.value()) == kProtectorValid; \
|
||||
}
|
||||
DECLARED_PROTECTORS_ON_NATIVE_CONTEXT(DEFINE_PROTECTOR_ON_NATIVE_CONTEXT_CHECK)
|
||||
|
||||
#define DEFINE_PROTECTOR_ON_ISOLATE_CHECK(name, root_index, unused_cell) \
|
||||
bool Protectors::Is##name##Intact(Isolate* isolate) { \
|
||||
PropertyCell cell = \
|
||||
@ -29,6 +21,7 @@ DECLARED_PROTECTORS_ON_NATIVE_CONTEXT(DEFINE_PROTECTOR_ON_NATIVE_CONTEXT_CHECK)
|
||||
Smi::ToInt(cell.value()) == kProtectorValid; \
|
||||
}
|
||||
DECLARED_PROTECTORS_ON_ISOLATE(DEFINE_PROTECTOR_ON_ISOLATE_CHECK)
|
||||
#undef DEFINE_PROTECTORS_ON_ISOLATE_CHECK
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -41,29 +41,10 @@ constexpr bool IsDefined(v8::Isolate::UseCounterFeature) { return true; }
|
||||
STATIC_ASSERT(IsDefined(v8::Isolate::kInvalidated##Name##Protector));
|
||||
|
||||
DECLARED_PROTECTORS_ON_ISOLATE(V)
|
||||
DECLARED_PROTECTORS_ON_NATIVE_CONTEXT(V)
|
||||
#undef V
|
||||
|
||||
} // namespace
|
||||
|
||||
#define INVALIDATE_PROTECTOR_ON_NATIVE_CONTEXT_DEFINITION(name, cell) \
|
||||
void Protectors::Invalidate##name(Isolate* isolate, \
|
||||
Handle<NativeContext> native_context) { \
|
||||
DCHECK(native_context->cell().value().IsSmi()); \
|
||||
DCHECK(Is##name##Intact(native_context)); \
|
||||
if (FLAG_trace_protector_invalidation) { \
|
||||
TraceProtectorInvalidation(#name); \
|
||||
} \
|
||||
Handle<PropertyCell> species_cell(native_context->cell(), isolate); \
|
||||
PropertyCell::SetValueWithInvalidation( \
|
||||
isolate, #cell, species_cell, \
|
||||
handle(Smi::FromInt(kProtectorInvalid), isolate)); \
|
||||
DCHECK(!Is##name##Intact(native_context)); \
|
||||
}
|
||||
DECLARED_PROTECTORS_ON_NATIVE_CONTEXT(
|
||||
INVALIDATE_PROTECTOR_ON_NATIVE_CONTEXT_DEFINITION)
|
||||
#undef INVALIDATE_PROTECTOR_ON_NATIVE_CONTEXT_DEFINITION
|
||||
|
||||
#define INVALIDATE_PROTECTOR_ON_ISOLATE_DEFINITION(name, unused_index, cell) \
|
||||
void Protectors::Invalidate##name(Isolate* isolate) { \
|
||||
DCHECK(isolate->factory()->cell()->value().IsSmi()); \
|
||||
|
@ -15,9 +15,6 @@ class Protectors : public AllStatic {
|
||||
static const int kProtectorValid = 1;
|
||||
static const int kProtectorInvalid = 0;
|
||||
|
||||
#define DECLARED_PROTECTORS_ON_NATIVE_CONTEXT(V) \
|
||||
V(RegExpSpeciesLookupChain, regexp_species_protector)
|
||||
|
||||
#define DECLARED_PROTECTORS_ON_ISOLATE(V) \
|
||||
V(ArrayBufferDetaching, ArrayBufferDetachingProtector, \
|
||||
array_buffer_detaching_protector) \
|
||||
@ -41,6 +38,8 @@ class Protectors : public AllStatic {
|
||||
/* property holder is the %IteratorPrototype%. Note that this also */ \
|
||||
/* invalidates the SetIterator protector (see below). */ \
|
||||
V(MapIteratorLookupChain, MapIteratorProtector, map_iterator_protector) \
|
||||
V(RegExpSpeciesLookupChain, RegExpSpeciesProtector, \
|
||||
regexp_species_protector) \
|
||||
V(PromiseHook, PromiseHookProtector, promise_hook_protector) \
|
||||
V(PromiseThenLookupChain, PromiseThenProtector, promise_then_protector) \
|
||||
V(PromiseResolveLookupChain, PromiseResolveProtector, \
|
||||
@ -82,19 +81,9 @@ class Protectors : public AllStatic {
|
||||
V(TypedArraySpeciesLookupChain, TypedArraySpeciesProtector, \
|
||||
typed_array_species_protector)
|
||||
|
||||
#define DECLARE_PROTECTOR_ON_NATIVE_CONTEXT(name, unused_cell) \
|
||||
V8_EXPORT_PRIVATE static inline bool Is##name##Intact( \
|
||||
Handle<NativeContext> native_context); \
|
||||
V8_EXPORT_PRIVATE static void Invalidate##name( \
|
||||
Isolate* isolate, Handle<NativeContext> native_context);
|
||||
|
||||
DECLARED_PROTECTORS_ON_NATIVE_CONTEXT(DECLARE_PROTECTOR_ON_NATIVE_CONTEXT)
|
||||
#undef DECLARE_PROTECTOR_ON_NATIVE_CONTEXT
|
||||
|
||||
#define DECLARE_PROTECTOR_ON_ISOLATE(name, unused_root_index, unused_cell) \
|
||||
V8_EXPORT_PRIVATE static inline bool Is##name##Intact(Isolate* isolate); \
|
||||
V8_EXPORT_PRIVATE static void Invalidate##name(Isolate* isolate);
|
||||
|
||||
DECLARED_PROTECTORS_ON_ISOLATE(DECLARE_PROTECTOR_ON_ISOLATE)
|
||||
#undef DECLARE_PROTECTOR_ON_ISOLATE
|
||||
};
|
||||
|
@ -911,6 +911,13 @@ void Heap::CreateInitialObjects() {
|
||||
set_promise_species_protector(*cell);
|
||||
}
|
||||
|
||||
{
|
||||
Handle<PropertyCell> cell =
|
||||
factory->NewPropertyCell(factory->empty_string());
|
||||
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
|
||||
set_regexp_species_protector(*cell);
|
||||
}
|
||||
|
||||
{
|
||||
Handle<PropertyCell> cell =
|
||||
factory->NewPropertyCell(factory->empty_string());
|
||||
|
@ -192,20 +192,11 @@ void LookupIterator::InternalUpdateProtector(Isolate* isolate,
|
||||
if (!receiver_generic->IsHeapObject()) return;
|
||||
Handle<HeapObject> receiver = Handle<HeapObject>::cast(receiver_generic);
|
||||
|
||||
// Getting the native_context from the isolate as a fallback. If possible, we
|
||||
// use the receiver's creation context instead.
|
||||
Handle<NativeContext> native_context = isolate->native_context();
|
||||
|
||||
ReadOnlyRoots roots(isolate);
|
||||
if (*name == roots.constructor_string()) {
|
||||
// Fetching the context in here since the operation is rather expensive.
|
||||
if (receiver->IsJSReceiver()) {
|
||||
native_context = Handle<JSReceiver>::cast(receiver)->GetCreationContext();
|
||||
}
|
||||
|
||||
if (!Protectors::IsArraySpeciesLookupChainIntact(isolate) &&
|
||||
!Protectors::IsPromiseSpeciesLookupChainIntact(isolate) &&
|
||||
!Protectors::IsRegExpSpeciesLookupChainIntact(native_context) &&
|
||||
!Protectors::IsRegExpSpeciesLookupChainIntact(isolate) &&
|
||||
!Protectors::IsTypedArraySpeciesLookupChainIntact(isolate)) {
|
||||
return;
|
||||
}
|
||||
@ -221,10 +212,8 @@ void LookupIterator::InternalUpdateProtector(Isolate* isolate,
|
||||
Protectors::InvalidatePromiseSpeciesLookupChain(isolate);
|
||||
return;
|
||||
} else if (receiver->IsJSRegExp(isolate)) {
|
||||
if (!Protectors::IsRegExpSpeciesLookupChainIntact(native_context)) {
|
||||
return;
|
||||
}
|
||||
Protectors::InvalidateRegExpSpeciesLookupChain(isolate, native_context);
|
||||
if (!Protectors::IsRegExpSpeciesLookupChainIntact(isolate)) return;
|
||||
Protectors::InvalidateRegExpSpeciesLookupChain(isolate);
|
||||
return;
|
||||
} else if (receiver->IsJSTypedArray(isolate)) {
|
||||
if (!Protectors::IsTypedArraySpeciesLookupChainIntact(isolate)) return;
|
||||
@ -250,10 +239,8 @@ void LookupIterator::InternalUpdateProtector(Isolate* isolate,
|
||||
Protectors::InvalidatePromiseSpeciesLookupChain(isolate);
|
||||
} else if (isolate->IsInAnyContext(*receiver,
|
||||
Context::REGEXP_PROTOTYPE_INDEX)) {
|
||||
if (!Protectors::IsRegExpSpeciesLookupChainIntact(native_context)) {
|
||||
return;
|
||||
}
|
||||
Protectors::InvalidateRegExpSpeciesLookupChain(isolate, native_context);
|
||||
if (!Protectors::IsRegExpSpeciesLookupChainIntact(isolate)) return;
|
||||
Protectors::InvalidateRegExpSpeciesLookupChain(isolate);
|
||||
} else if (isolate->IsInAnyContext(
|
||||
receiver->map(isolate).prototype(isolate),
|
||||
Context::TYPED_ARRAY_PROTOTYPE_INDEX)) {
|
||||
@ -289,14 +276,9 @@ void LookupIterator::InternalUpdateProtector(Isolate* isolate,
|
||||
Protectors::InvalidateStringIteratorLookupChain(isolate);
|
||||
}
|
||||
} else if (*name == roots.species_symbol()) {
|
||||
// Fetching the context in here since the operation is rather expensive.
|
||||
if (receiver->IsJSReceiver()) {
|
||||
native_context = Handle<JSReceiver>::cast(receiver)->GetCreationContext();
|
||||
}
|
||||
|
||||
if (!Protectors::IsArraySpeciesLookupChainIntact(isolate) &&
|
||||
!Protectors::IsPromiseSpeciesLookupChainIntact(isolate) &&
|
||||
!Protectors::IsRegExpSpeciesLookupChainIntact(native_context) &&
|
||||
!Protectors::IsRegExpSpeciesLookupChainIntact(isolate) &&
|
||||
!Protectors::IsTypedArraySpeciesLookupChainIntact(isolate)) {
|
||||
return;
|
||||
}
|
||||
@ -313,10 +295,8 @@ void LookupIterator::InternalUpdateProtector(Isolate* isolate,
|
||||
Protectors::InvalidatePromiseSpeciesLookupChain(isolate);
|
||||
} else if (isolate->IsInAnyContext(*receiver,
|
||||
Context::REGEXP_FUNCTION_INDEX)) {
|
||||
if (!Protectors::IsRegExpSpeciesLookupChainIntact(native_context)) {
|
||||
return;
|
||||
}
|
||||
Protectors::InvalidateRegExpSpeciesLookupChain(isolate, native_context);
|
||||
if (!Protectors::IsRegExpSpeciesLookupChainIntact(isolate)) return;
|
||||
Protectors::InvalidateRegExpSpeciesLookupChain(isolate);
|
||||
} else if (IsTypedArrayFunctionInAnyContext(isolate, *receiver)) {
|
||||
if (!Protectors::IsTypedArraySpeciesLookupChainIntact(isolate)) return;
|
||||
Protectors::InvalidateTypedArraySpeciesLookupChain(isolate);
|
||||
|
@ -185,10 +185,7 @@ bool RegExpUtils::IsUnmodifiedRegExp(Isolate* isolate, Handle<Object> obj) {
|
||||
// property. Similar spots in CSA would use BranchIfFastRegExp_Strict in this
|
||||
// case.
|
||||
|
||||
if (!Protectors::IsRegExpSpeciesLookupChainIntact(
|
||||
recv.GetCreationContext())) {
|
||||
return false;
|
||||
}
|
||||
if (!Protectors::IsRegExpSpeciesLookupChainIntact(isolate)) return false;
|
||||
|
||||
// The smi check is required to omit ToLength(lastIndex) calls with possible
|
||||
// user-code execution on the fast path.
|
||||
|
@ -214,6 +214,7 @@ class Symbol;
|
||||
V(PropertyCell, array_species_protector, ArraySpeciesProtector) \
|
||||
V(PropertyCell, typed_array_species_protector, TypedArraySpeciesProtector) \
|
||||
V(PropertyCell, promise_species_protector, PromiseSpeciesProtector) \
|
||||
V(PropertyCell, regexp_species_protector, RegExpSpeciesProtector) \
|
||||
V(PropertyCell, string_length_protector, StringLengthProtector) \
|
||||
V(PropertyCell, array_iterator_protector, ArrayIteratorProtector) \
|
||||
V(PropertyCell, array_buffer_detaching_protector, \
|
||||
|
8
test/mjsunit/regress/regress-1069964.js
Normal file
8
test/mjsunit/regress/regress-1069964.js
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
Realm.createAllowCrossRealmAccess();
|
||||
const c = Realm.global(1);
|
||||
Realm.detachGlobal(1);
|
||||
try { c.constructor = () => {}; } catch {}
|
@ -417,19 +417,20 @@ KNOWN_OBJECTS = {
|
||||
("old_space", 0x004e1): "ArraySpeciesProtector",
|
||||
("old_space", 0x004f5): "TypedArraySpeciesProtector",
|
||||
("old_space", 0x00509): "PromiseSpeciesProtector",
|
||||
("old_space", 0x0051d): "StringLengthProtector",
|
||||
("old_space", 0x00531): "ArrayIteratorProtector",
|
||||
("old_space", 0x00545): "ArrayBufferDetachingProtector",
|
||||
("old_space", 0x00559): "PromiseHookProtector",
|
||||
("old_space", 0x0056d): "PromiseResolveProtector",
|
||||
("old_space", 0x00581): "MapIteratorProtector",
|
||||
("old_space", 0x00595): "PromiseThenProtector",
|
||||
("old_space", 0x005a9): "SetIteratorProtector",
|
||||
("old_space", 0x005bd): "StringIteratorProtector",
|
||||
("old_space", 0x005d1): "SingleCharacterStringCache",
|
||||
("old_space", 0x009d9): "StringSplitCache",
|
||||
("old_space", 0x00de1): "RegExpMultipleCache",
|
||||
("old_space", 0x011e9): "BuiltinsConstantsTable",
|
||||
("old_space", 0x0051d): "RegExpSpeciesProtector",
|
||||
("old_space", 0x00531): "StringLengthProtector",
|
||||
("old_space", 0x00545): "ArrayIteratorProtector",
|
||||
("old_space", 0x00559): "ArrayBufferDetachingProtector",
|
||||
("old_space", 0x0056d): "PromiseHookProtector",
|
||||
("old_space", 0x00581): "PromiseResolveProtector",
|
||||
("old_space", 0x00595): "MapIteratorProtector",
|
||||
("old_space", 0x005a9): "PromiseThenProtector",
|
||||
("old_space", 0x005bd): "SetIteratorProtector",
|
||||
("old_space", 0x005d1): "StringIteratorProtector",
|
||||
("old_space", 0x005e5): "SingleCharacterStringCache",
|
||||
("old_space", 0x009ed): "StringSplitCache",
|
||||
("old_space", 0x00df5): "RegExpMultipleCache",
|
||||
("old_space", 0x011fd): "BuiltinsConstantsTable",
|
||||
}
|
||||
|
||||
# Lower 32 bits of first page addresses for various heap spaces.
|
||||
|
Loading…
Reference in New Issue
Block a user