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

View File

@ -35,6 +35,7 @@
#include "src/execution/isolate-inl.h"
#include "src/execution/messages.h"
#include "src/execution/microtask-queue.h"
#include "src/execution/protectors-inl.h"
#include "src/execution/runtime-profiler.h"
#include "src/execution/simulator.h"
#include "src/execution/v8threads.h"
@ -3796,134 +3797,12 @@ bool Isolate::IsInAnyContext(Object object, uint32_t index) {
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) {
DisallowHeapAllocation no_gc;
if (!object->map().is_prototype_map()) return;
if (!IsNoElementsProtectorIntact()) return;
if (!Protectors::IsNoElementsIntact(this)) return;
if (!IsArrayOrObjectOrStringPrototype(*object)) return;
PropertyCell::SetValueWithInvalidation(
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());
Protectors::InvalidateNoElements(this);
}
bool Isolate::IsAnyInitialArrayPrototype(Handle<JSArray> array) {
@ -4073,9 +3952,9 @@ void Isolate::PromiseHookStateUpdated() {
bool promise_hook_or_debug_is_active_or_async_event_delegate =
promise_hook_or_async_event_delegate || debug()->is_active();
if (promise_hook_or_debug_is_active_or_async_event_delegate &&
IsPromiseHookProtectorIntact()) {
Protectors::IsPromiseHookIntact(this)) {
HandleScope scope(this);
InvalidatePromiseHookProtector();
Protectors::InvalidatePromiseHook(this);
}
promise_hook_or_async_event_delegate_ = promise_hook_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 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);
// 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
// notifications occur if the set is on the elements of the array or
// object prototype. Also ensure that changes to prototype chain between
@ -1193,11 +1183,6 @@ class Isolate final : private HiddenFactory {
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.
bool IsAnyInitialArrayPrototype(Handle<JSArray> array);

View File

@ -16,12 +16,32 @@
namespace v8 {
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) \
void Protectors::Invalidate##name(Isolate* isolate, \
Handle<NativeContext> native_context) { \
DCHECK_EQ(*native_context, isolate->raw_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, \
@ -36,6 +56,9 @@ DECLARED_PROTECTORS_ON_NATIVE_CONTEXT(
void Protectors::Invalidate##name(Isolate* isolate) { \
DCHECK(isolate->factory()->cell()->value().IsSmi()); \
DCHECK(Is##name##Intact(isolate)); \
if (FLAG_trace_protector_invalidation) { \
TraceProtectorInvalidation(#name); \
} \
PropertyCell::SetValueWithInvalidation( \
isolate, #cell, isolate->factory()->cell(), \
handle(Smi::FromInt(kProtectorInvalid), isolate)); \

View File

@ -27,6 +27,7 @@ class Protectors : public AllStatic {
V(ArraySpeciesLookupChain, ArraySpeciesProtector, array_species_protector) \
V(IsConcatSpreadableLookupChain, IsConcatSpreadableProtector, \
is_concat_spreadable_protector) \
V(NoElements, NoElementsProtector, no_elements_protector) \
\
/* The MapIterator protector protects the original iteration behaviors */ \
/* 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 */ \
/* invalidates the SetIterator protector (see below). */ \
V(MapIteratorLookupChain, MapIteratorProtector, map_iterator_protector) \
V(PromiseHook, PromiseHookProtector, promise_hook_protector) \
V(PromiseThenLookupChain, PromiseThenProtector, promise_then_protector) \
V(PromiseResolveLookupChain, PromiseResolveProtector, \
promise_resolve_protector) \
@ -80,16 +82,18 @@ class Protectors : public AllStatic {
V(TypedArraySpeciesLookupChain, TypedArraySpeciesProtector, \
typed_array_species_protector)
#define DECLARE_PROTECTOR_ON_NATIVE_CONTEXT(name, unused_cell) \
static inline bool Is##name##Intact(Handle<NativeContext> native_context); \
static void Invalidate##name(Isolate* isolate, \
Handle<NativeContext> native_context);
#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) \
static inline bool Is##name##Intact(Isolate* isolate); \
static void Invalidate##name(Isolate* isolate);
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

View File

@ -15,6 +15,7 @@
#include "src/execution/execution.h"
#include "src/execution/frames-inl.h"
#include "src/execution/isolate-inl.h"
#include "src/execution/protectors-inl.h"
#include "src/execution/runtime-profiler.h"
#include "src/handles/handles-inl.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.
if (isolate->IsNoElementsProtectorIntact()) {
if (Protectors::IsNoElementsIntact(isolate)) {
if (receiver_map->IsStringMap()) {
return true;
}

View File

@ -8,6 +8,7 @@
#include "src/execution/arguments.h"
#include "src/execution/frames.h"
#include "src/execution/isolate-inl.h"
#include "src/execution/protectors-inl.h"
#include "src/heap/factory.h"
#include "src/heap/heap-inl.h" // For MaxNumberToStringCacheSize.
#include "src/heap/heap-write-barrier-inl.h"
@ -3499,7 +3500,7 @@ class TypedElementsAccessor
return true;
}
return !isolate->IsNoElementsProtectorIntact(context);
return !Protectors::IsNoElementsIntact(isolate);
}
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
// changed.
if (IsHoleyElementsKind(array_kind) &&
isolate->IsNoElementsProtectorIntact()) {
Protectors::IsNoElementsIntact(isolate)) {
return false;
}
return true;
@ -7897,9 +7897,6 @@ void PropertyCell::SetValueWithInvalidation(Isolate* isolate,
Handle<PropertyCell> cell,
Handle<Object> new_value) {
if (cell->value() != *new_value) {
if (FLAG_trace_protector_invalidation) {
isolate->TraceProtectorInvalidation(cell_name);
}
cell->set_value(*new_value);
cell->dependent_code().DeoptimizeDependentCodeGroup(
isolate, DependentCode::kPropertyCellChangedGroup);

View File

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

View File

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