[protectors] Migrate final two protectors to their own file

Bug: v8:9463
Change-Id: I62290f29086c370b1f4f773de9a4d8f926edf313
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1818732
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Commit-Queue: Joshua Litt <joshualitt@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64005}
This commit is contained in:
Joshua Litt 2019-09-25 07:48:32 -07:00 committed by Commit Bot
parent 43f44e5311
commit 318d66d95f
10 changed files with 50 additions and 157 deletions

View File

@ -16,6 +16,7 @@
#include "src/compiler/bytecode-analysis.h" #include "src/compiler/bytecode-analysis.h"
#include "src/compiler/graph-reducer.h" #include "src/compiler/graph-reducer.h"
#include "src/compiler/per-isolate-compiler-cache.h" #include "src/compiler/per-isolate-compiler-cache.h"
#include "src/execution/protectors-inl.h"
#include "src/init/bootstrapper.h" #include "src/init/bootstrapper.h"
#include "src/objects/allocation-site-inl.h" #include "src/objects/allocation-site-inl.h"
#include "src/objects/api-callbacks.h" #include "src/objects/api-callbacks.h"
@ -1120,7 +1121,7 @@ bool SupportsFastArrayIteration(Isolate* isolate, Handle<Map> map) {
map->prototype().IsJSArray() && map->prototype().IsJSArray() &&
isolate->IsAnyInitialArrayPrototype( isolate->IsAnyInitialArrayPrototype(
handle(JSArray::cast(map->prototype()), isolate)) && handle(JSArray::cast(map->prototype()), isolate)) &&
isolate->IsNoElementsProtectorIntact(); Protectors::IsNoElementsIntact(isolate);
} }
bool SupportsFastArrayResize(Isolate* isolate, Handle<Map> map) { bool SupportsFastArrayResize(Isolate* isolate, Handle<Map> map) {

View File

@ -35,6 +35,7 @@
#include "src/execution/isolate-inl.h" #include "src/execution/isolate-inl.h"
#include "src/execution/messages.h" #include "src/execution/messages.h"
#include "src/execution/microtask-queue.h" #include "src/execution/microtask-queue.h"
#include "src/execution/protectors-inl.h"
#include "src/execution/runtime-profiler.h" #include "src/execution/runtime-profiler.h"
#include "src/execution/simulator.h" #include "src/execution/simulator.h"
#include "src/execution/v8threads.h" #include "src/execution/v8threads.h"
@ -3796,134 +3797,12 @@ bool Isolate::IsInAnyContext(Object object, uint32_t index) {
return false; return false;
} }
bool Isolate::IsNoElementsProtectorIntact(Context context) {
PropertyCell no_elements_cell = heap()->no_elements_protector();
bool cell_reports_intact =
no_elements_cell.value().IsSmi() &&
Smi::ToInt(no_elements_cell.value()) == kProtectorValid;
#ifdef DEBUG
Context native_context = context.native_context();
Map root_array_map =
native_context.GetInitialJSArrayMap(GetInitialFastElementsKind());
JSObject initial_array_proto = JSObject::cast(
native_context.get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX));
JSObject initial_object_proto = JSObject::cast(
native_context.get(Context::INITIAL_OBJECT_PROTOTYPE_INDEX));
JSObject initial_string_proto = JSObject::cast(
native_context.get(Context::INITIAL_STRING_PROTOTYPE_INDEX));
if (root_array_map.is_null() || initial_array_proto == initial_object_proto) {
// We are in the bootstrapping process, and the entire check sequence
// shouldn't be performed.
return cell_reports_intact;
}
// Check that the array prototype hasn't been altered WRT empty elements.
if (root_array_map.prototype() != initial_array_proto) {
DCHECK_EQ(false, cell_reports_intact);
return cell_reports_intact;
}
FixedArrayBase elements = initial_array_proto.elements();
ReadOnlyRoots roots(heap());
if (elements != roots.empty_fixed_array() &&
elements != roots.empty_slow_element_dictionary()) {
DCHECK_EQ(false, cell_reports_intact);
return cell_reports_intact;
}
// Check that the Object.prototype hasn't been altered WRT empty elements.
elements = initial_object_proto.elements();
if (elements != roots.empty_fixed_array() &&
elements != roots.empty_slow_element_dictionary()) {
DCHECK_EQ(false, cell_reports_intact);
return cell_reports_intact;
}
// Check that the Array.prototype has the Object.prototype as its
// [[Prototype]] and that the Object.prototype has a null [[Prototype]].
PrototypeIterator iter(this, initial_array_proto);
if (iter.IsAtEnd() || iter.GetCurrent() != initial_object_proto) {
DCHECK_EQ(false, cell_reports_intact);
DCHECK(!has_pending_exception());
return cell_reports_intact;
}
iter.Advance();
if (!iter.IsAtEnd()) {
DCHECK_EQ(false, cell_reports_intact);
DCHECK(!has_pending_exception());
return cell_reports_intact;
}
DCHECK(!has_pending_exception());
// Check that the String.prototype hasn't been altered WRT empty elements.
elements = initial_string_proto.elements();
if (elements != roots.empty_fixed_array() &&
elements != roots.empty_slow_element_dictionary()) {
DCHECK_EQ(false, cell_reports_intact);
return cell_reports_intact;
}
// Check that the String.prototype has the Object.prototype
// as its [[Prototype]] still.
if (initial_string_proto.map().prototype() != initial_object_proto) {
DCHECK_EQ(false, cell_reports_intact);
return cell_reports_intact;
}
#endif
return cell_reports_intact;
}
bool Isolate::IsNoElementsProtectorIntact() {
return Isolate::IsNoElementsProtectorIntact(context());
}
bool Isolate::IsPromiseHookProtectorIntact() {
PropertyCell promise_hook_cell = heap()->promise_hook_protector();
bool is_promise_hook_protector_intact =
Smi::ToInt(promise_hook_cell.value()) == kProtectorValid;
DCHECK_IMPLIES(is_promise_hook_protector_intact,
!promise_hook_or_async_event_delegate_);
DCHECK_IMPLIES(is_promise_hook_protector_intact,
!promise_hook_or_debug_is_active_or_async_event_delegate_);
return is_promise_hook_protector_intact;
}
void Isolate::UpdateNoElementsProtectorOnSetElement(Handle<JSObject> object) { void Isolate::UpdateNoElementsProtectorOnSetElement(Handle<JSObject> object) {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
if (!object->map().is_prototype_map()) return; if (!object->map().is_prototype_map()) return;
if (!IsNoElementsProtectorIntact()) return; if (!Protectors::IsNoElementsIntact(this)) return;
if (!IsArrayOrObjectOrStringPrototype(*object)) return; if (!IsArrayOrObjectOrStringPrototype(*object)) return;
PropertyCell::SetValueWithInvalidation( Protectors::InvalidateNoElements(this);
this, "no_elements_protector", factory()->no_elements_protector(),
handle(Smi::FromInt(kProtectorInvalid), this));
}
void Isolate::TraceProtectorInvalidation(const char* protector_name) {
static constexpr char kInvalidateProtectorTracingCategory[] =
"V8.InvalidateProtector";
static constexpr char kInvalidateProtectorTracingArg[] = "protector-name";
DCHECK(FLAG_trace_protector_invalidation);
// TODO(jgruber): Remove the PrintF once tracing can output to stdout.
i::PrintF("Invalidating protector cell %s in isolate %p\n", protector_name,
this);
TRACE_EVENT_INSTANT1("v8", kInvalidateProtectorTracingCategory,
TRACE_EVENT_SCOPE_THREAD, kInvalidateProtectorTracingArg,
protector_name);
}
void Isolate::InvalidatePromiseHookProtector() {
DCHECK(factory()->promise_hook_protector()->value().IsSmi());
DCHECK(IsPromiseHookProtectorIntact());
PropertyCell::SetValueWithInvalidation(
this, "promise_hook_protector", factory()->promise_hook_protector(),
handle(Smi::FromInt(kProtectorInvalid), this));
DCHECK(!IsPromiseHookProtectorIntact());
} }
bool Isolate::IsAnyInitialArrayPrototype(Handle<JSArray> array) { bool Isolate::IsAnyInitialArrayPrototype(Handle<JSArray> array) {
@ -4073,9 +3952,9 @@ void Isolate::PromiseHookStateUpdated() {
bool promise_hook_or_debug_is_active_or_async_event_delegate = bool promise_hook_or_debug_is_active_or_async_event_delegate =
promise_hook_or_async_event_delegate || debug()->is_active(); promise_hook_or_async_event_delegate || debug()->is_active();
if (promise_hook_or_debug_is_active_or_async_event_delegate && if (promise_hook_or_debug_is_active_or_async_event_delegate &&
IsPromiseHookProtectorIntact()) { Protectors::IsPromiseHookIntact(this)) {
HandleScope scope(this); HandleScope scope(this);
InvalidatePromiseHookProtector(); Protectors::InvalidatePromiseHook(this);
} }
promise_hook_or_async_event_delegate_ = promise_hook_or_async_event_delegate; promise_hook_or_async_event_delegate_ = promise_hook_or_async_event_delegate;
promise_hook_or_debug_is_active_or_async_event_delegate_ = promise_hook_or_debug_is_active_or_async_event_delegate_ =

View File

@ -1166,18 +1166,8 @@ class Isolate final : private HiddenFactory {
static const int kProtectorValid = 1; static const int kProtectorValid = 1;
static const int kProtectorInvalid = 0; static const int kProtectorInvalid = 0;
// The version with an explicit context parameter can be used when
// Isolate::context is not set up, e.g. when calling directly into C++ from
// CSA.
bool IsNoElementsProtectorIntact(Context context);
V8_EXPORT_PRIVATE bool IsNoElementsProtectorIntact();
bool IsArrayOrObjectOrStringPrototype(Object object); bool IsArrayOrObjectOrStringPrototype(Object object);
// Disable promise optimizations if promise (debug) hooks have ever been
// active, because those can observe promises.
bool IsPromiseHookProtectorIntact();
// On intent to set an element in object, make sure that appropriate // On intent to set an element in object, make sure that appropriate
// notifications occur if the set is on the elements of the array or // notifications occur if the set is on the elements of the array or
// object prototype. Also ensure that changes to prototype chain between // object prototype. Also ensure that changes to prototype chain between
@ -1193,11 +1183,6 @@ class Isolate final : private HiddenFactory {
UpdateNoElementsProtectorOnSetElement(object); UpdateNoElementsProtectorOnSetElement(object);
} }
// The `protector_name` C string must be statically allocated.
void TraceProtectorInvalidation(const char* protector_name);
V8_EXPORT_PRIVATE void InvalidatePromiseHookProtector();
// Returns true if array is the initial array prototype in any native context. // Returns true if array is the initial array prototype in any native context.
bool IsAnyInitialArrayPrototype(Handle<JSArray> array); bool IsAnyInitialArrayPrototype(Handle<JSArray> array);

View File

@ -16,12 +16,32 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace {
void TraceProtectorInvalidation(const char* protector_name) {
DCHECK(FLAG_trace_protector_invalidation);
static constexpr char kInvalidateProtectorTracingCategory[] =
"V8.InvalidateProtector";
static constexpr char kInvalidateProtectorTracingArg[] = "protector-name";
DCHECK(FLAG_trace_protector_invalidation);
// TODO(jgruber): Remove the PrintF once tracing can output to stdout.
i::PrintF("Invalidating protector cell %s", protector_name);
TRACE_EVENT_INSTANT1("v8", kInvalidateProtectorTracingCategory,
TRACE_EVENT_SCOPE_THREAD, kInvalidateProtectorTracingArg,
protector_name);
}
} // namespace
#define INVALIDATE_PROTECTOR_ON_NATIVE_CONTEXT_DEFINITION(name, cell) \ #define INVALIDATE_PROTECTOR_ON_NATIVE_CONTEXT_DEFINITION(name, cell) \
void Protectors::Invalidate##name(Isolate* isolate, \ void Protectors::Invalidate##name(Isolate* isolate, \
Handle<NativeContext> native_context) { \ Handle<NativeContext> native_context) { \
DCHECK_EQ(*native_context, isolate->raw_native_context()); \ DCHECK_EQ(*native_context, isolate->raw_native_context()); \
DCHECK(native_context->cell().value().IsSmi()); \ DCHECK(native_context->cell().value().IsSmi()); \
DCHECK(Is##name##Intact(native_context)); \ DCHECK(Is##name##Intact(native_context)); \
if (FLAG_trace_protector_invalidation) { \
TraceProtectorInvalidation(#name); \
} \
Handle<PropertyCell> species_cell(native_context->cell(), isolate); \ Handle<PropertyCell> species_cell(native_context->cell(), isolate); \
PropertyCell::SetValueWithInvalidation( \ PropertyCell::SetValueWithInvalidation( \
isolate, #cell, species_cell, \ isolate, #cell, species_cell, \
@ -36,6 +56,9 @@ DECLARED_PROTECTORS_ON_NATIVE_CONTEXT(
void Protectors::Invalidate##name(Isolate* isolate) { \ void Protectors::Invalidate##name(Isolate* isolate) { \
DCHECK(isolate->factory()->cell()->value().IsSmi()); \ DCHECK(isolate->factory()->cell()->value().IsSmi()); \
DCHECK(Is##name##Intact(isolate)); \ DCHECK(Is##name##Intact(isolate)); \
if (FLAG_trace_protector_invalidation) { \
TraceProtectorInvalidation(#name); \
} \
PropertyCell::SetValueWithInvalidation( \ PropertyCell::SetValueWithInvalidation( \
isolate, #cell, isolate->factory()->cell(), \ isolate, #cell, isolate->factory()->cell(), \
handle(Smi::FromInt(kProtectorInvalid), isolate)); \ handle(Smi::FromInt(kProtectorInvalid), isolate)); \

View File

@ -27,6 +27,7 @@ class Protectors : public AllStatic {
V(ArraySpeciesLookupChain, ArraySpeciesProtector, array_species_protector) \ V(ArraySpeciesLookupChain, ArraySpeciesProtector, array_species_protector) \
V(IsConcatSpreadableLookupChain, IsConcatSpreadableProtector, \ V(IsConcatSpreadableLookupChain, IsConcatSpreadableProtector, \
is_concat_spreadable_protector) \ is_concat_spreadable_protector) \
V(NoElements, NoElementsProtector, no_elements_protector) \
\ \
/* The MapIterator protector protects the original iteration behaviors */ \ /* The MapIterator protector protects the original iteration behaviors */ \
/* of Map.prototype.keys(), Map.prototype.values(), and */ \ /* of Map.prototype.keys(), Map.prototype.values(), and */ \
@ -40,6 +41,7 @@ class Protectors : public AllStatic {
/* property holder is the %IteratorPrototype%. Note that this also */ \ /* property holder is the %IteratorPrototype%. Note that this also */ \
/* invalidates the SetIterator protector (see below). */ \ /* invalidates the SetIterator protector (see below). */ \
V(MapIteratorLookupChain, MapIteratorProtector, map_iterator_protector) \ V(MapIteratorLookupChain, MapIteratorProtector, map_iterator_protector) \
V(PromiseHook, PromiseHookProtector, promise_hook_protector) \
V(PromiseThenLookupChain, PromiseThenProtector, promise_then_protector) \ V(PromiseThenLookupChain, PromiseThenProtector, promise_then_protector) \
V(PromiseResolveLookupChain, PromiseResolveProtector, \ V(PromiseResolveLookupChain, PromiseResolveProtector, \
promise_resolve_protector) \ promise_resolve_protector) \
@ -80,16 +82,18 @@ class Protectors : public AllStatic {
V(TypedArraySpeciesLookupChain, TypedArraySpeciesProtector, \ V(TypedArraySpeciesLookupChain, TypedArraySpeciesProtector, \
typed_array_species_protector) typed_array_species_protector)
#define DECLARE_PROTECTOR_ON_NATIVE_CONTEXT(name, unused_cell) \ #define DECLARE_PROTECTOR_ON_NATIVE_CONTEXT(name, unused_cell) \
static inline bool Is##name##Intact(Handle<NativeContext> native_context); \ V8_EXPORT_PRIVATE static inline bool Is##name##Intact( \
static void Invalidate##name(Isolate* isolate, \ Handle<NativeContext> native_context); \
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) DECLARED_PROTECTORS_ON_NATIVE_CONTEXT(DECLARE_PROTECTOR_ON_NATIVE_CONTEXT)
#undef DECLARE_PROTECTOR_ON_NATIVE_CONTEXT #undef DECLARE_PROTECTOR_ON_NATIVE_CONTEXT
#define DECLARE_PROTECTOR_ON_ISOLATE(name, unused_root_index, unused_cell) \ #define DECLARE_PROTECTOR_ON_ISOLATE(name, unused_root_index, unused_cell) \
static inline bool Is##name##Intact(Isolate* isolate); \ V8_EXPORT_PRIVATE static inline bool Is##name##Intact(Isolate* isolate); \
static void Invalidate##name(Isolate* isolate); V8_EXPORT_PRIVATE static void Invalidate##name(Isolate* isolate);
DECLARED_PROTECTORS_ON_ISOLATE(DECLARE_PROTECTOR_ON_ISOLATE) DECLARED_PROTECTORS_ON_ISOLATE(DECLARE_PROTECTOR_ON_ISOLATE)
#undef DECLARE_PROTECTOR_ON_ISOLATE #undef DECLARE_PROTECTOR_ON_ISOLATE

View File

@ -15,6 +15,7 @@
#include "src/execution/execution.h" #include "src/execution/execution.h"
#include "src/execution/frames-inl.h" #include "src/execution/frames-inl.h"
#include "src/execution/isolate-inl.h" #include "src/execution/isolate-inl.h"
#include "src/execution/protectors-inl.h"
#include "src/execution/runtime-profiler.h" #include "src/execution/runtime-profiler.h"
#include "src/handles/handles-inl.h" #include "src/handles/handles-inl.h"
#include "src/ic/call-optimization.h" #include "src/ic/call-optimization.h"
@ -1076,7 +1077,7 @@ bool AllowConvertHoleElementToUndefined(Isolate* isolate,
} }
// For other {receiver}s we need to check the "no elements" protector. // For other {receiver}s we need to check the "no elements" protector.
if (isolate->IsNoElementsProtectorIntact()) { if (Protectors::IsNoElementsIntact(isolate)) {
if (receiver_map->IsStringMap()) { if (receiver_map->IsStringMap()) {
return true; return true;
} }

View File

@ -8,6 +8,7 @@
#include "src/execution/arguments.h" #include "src/execution/arguments.h"
#include "src/execution/frames.h" #include "src/execution/frames.h"
#include "src/execution/isolate-inl.h" #include "src/execution/isolate-inl.h"
#include "src/execution/protectors-inl.h"
#include "src/heap/factory.h" #include "src/heap/factory.h"
#include "src/heap/heap-inl.h" // For MaxNumberToStringCacheSize. #include "src/heap/heap-inl.h" // For MaxNumberToStringCacheSize.
#include "src/heap/heap-write-barrier-inl.h" #include "src/heap/heap-write-barrier-inl.h"
@ -3499,7 +3500,7 @@ class TypedElementsAccessor
return true; return true;
} }
return !isolate->IsNoElementsProtectorIntact(context); return !Protectors::IsNoElementsIntact(isolate);
} }
static bool TryCopyElementsFastNumber(Context context, JSArray source, static bool TryCopyElementsFastNumber(Context context, JSArray source,

View File

@ -1781,7 +1781,7 @@ bool Object::IterationHasObservableEffects() {
// the prototype. This could have different results if the prototype has been // the prototype. This could have different results if the prototype has been
// changed. // changed.
if (IsHoleyElementsKind(array_kind) && if (IsHoleyElementsKind(array_kind) &&
isolate->IsNoElementsProtectorIntact()) { Protectors::IsNoElementsIntact(isolate)) {
return false; return false;
} }
return true; return true;
@ -7897,9 +7897,6 @@ void PropertyCell::SetValueWithInvalidation(Isolate* isolate,
Handle<PropertyCell> cell, Handle<PropertyCell> cell,
Handle<Object> new_value) { Handle<Object> new_value) {
if (cell->value() != *new_value) { if (cell->value() != *new_value) {
if (FLAG_trace_protector_invalidation) {
isolate->TraceProtectorInvalidation(cell_name);
}
cell->set_value(*new_value); cell->set_value(*new_value);
cell->dependent_code().DeoptimizeDependentCodeGroup( cell->dependent_code().DeoptimizeDependentCodeGroup(
isolate, DependentCode::kPropertyCellChangedGroup); isolate, DependentCode::kPropertyCellChangedGroup);

View File

@ -46,6 +46,7 @@
#include "src/execution/arguments.h" #include "src/execution/arguments.h"
#include "src/execution/execution.h" #include "src/execution/execution.h"
#include "src/execution/futex-emulation.h" #include "src/execution/futex-emulation.h"
#include "src/execution/protectors-inl.h"
#include "src/execution/vm-state.h" #include "src/execution/vm-state.h"
#include "src/handles/global-handles.h" #include "src/handles/global-handles.h"
#include "src/heap/heap-inl.h" #include "src/heap/heap-inl.h"
@ -18188,10 +18189,10 @@ static void BreakArrayGuarantees(const char* script) {
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
v8::internal::Isolate* i_isolate = v8::internal::Isolate* i_isolate =
reinterpret_cast<v8::internal::Isolate*>(isolate1); reinterpret_cast<v8::internal::Isolate*>(isolate1);
CHECK(i_isolate->IsNoElementsProtectorIntact()); CHECK(v8::internal::Protectors::IsNoElementsIntact(i_isolate));
// Run something in new isolate. // Run something in new isolate.
CompileRun(script); CompileRun(script);
CHECK(!i_isolate->IsNoElementsProtectorIntact()); CHECK(!v8::internal::Protectors::IsNoElementsIntact(i_isolate));
} }
isolate1->Exit(); isolate1->Exit();
isolate1->Dispose(); isolate1->Dispose();

View File

@ -11,6 +11,7 @@
#include "src/compiler/js-graph.h" #include "src/compiler/js-graph.h"
#include "src/compiler/simplified-operator.h" #include "src/compiler/simplified-operator.h"
#include "src/execution/isolate.h" #include "src/execution/isolate.h"
#include "src/execution/protectors.h"
#include "src/heap/factory.h" #include "src/heap/factory.h"
#include "src/objects/feedback-vector.h" #include "src/objects/feedback-vector.h"
#include "test/unittests/compiler/graph-unittest.h" #include "test/unittests/compiler/graph-unittest.h"
@ -193,7 +194,7 @@ TEST_F(JSCallReducerTest, PromiseConstructorWithHook) {
graph()->NewNode(javascript()->Construct(3), promise, executor, promise, graph()->NewNode(javascript()->Construct(3), promise, executor, promise,
context, frame_state, effect, control); context, frame_state, effect, control);
isolate()->InvalidatePromiseHookProtector(); Protectors::InvalidatePromiseHook(isolate());
Reduction r = Reduce(construct); Reduction r = Reduce(construct);