diff --git a/src/compiler/js-heap-broker.cc b/src/compiler/js-heap-broker.cc index e00de14b6a..8c5e60214a 100644 --- a/src/compiler/js-heap-broker.cc +++ b/src/compiler/js-heap-broker.cc @@ -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->prototype().IsJSArray() && isolate->IsAnyInitialArrayPrototype( handle(JSArray::cast(map->prototype()), isolate)) && - isolate->IsNoElementsProtectorIntact(); + Protectors::IsNoElementsIntact(isolate); } bool SupportsFastArrayResize(Isolate* isolate, Handle map) { diff --git a/src/execution/isolate.cc b/src/execution/isolate.cc index a936b2b8b2..6f0aaad680 100644 --- a/src/execution/isolate.cc +++ b/src/execution/isolate.cc @@ -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 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 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_ = diff --git a/src/execution/isolate.h b/src/execution/isolate.h index a0e5ee7395..04e54d31ef 100644 --- a/src/execution/isolate.h +++ b/src/execution/isolate.h @@ -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 array); diff --git a/src/execution/protectors.cc b/src/execution/protectors.cc index 3ac07eede3..b5b4c47a1b 100644 --- a/src/execution/protectors.cc +++ b/src/execution/protectors.cc @@ -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 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 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)); \ diff --git a/src/execution/protectors.h b/src/execution/protectors.h index f2d1653818..4601f16cf0 100644 --- a/src/execution/protectors.h +++ b/src/execution/protectors.h @@ -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 native_context); \ - static void Invalidate##name(Isolate* isolate, \ - Handle native_context); +#define DECLARE_PROTECTOR_ON_NATIVE_CONTEXT(name, unused_cell) \ + V8_EXPORT_PRIVATE static inline bool Is##name##Intact( \ + Handle native_context); \ + V8_EXPORT_PRIVATE static void Invalidate##name( \ + Isolate* isolate, Handle 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 diff --git a/src/ic/ic.cc b/src/ic/ic.cc index af9488e9ee..9015497cca 100644 --- a/src/ic/ic.cc +++ b/src/ic/ic.cc @@ -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; } diff --git a/src/objects/elements.cc b/src/objects/elements.cc index 6e5648d2f4..070ccd7069 100644 --- a/src/objects/elements.cc +++ b/src/objects/elements.cc @@ -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, diff --git a/src/objects/objects.cc b/src/objects/objects.cc index 7d4f66cc32..5ee8d2ba33 100644 --- a/src/objects/objects.cc +++ b/src/objects/objects.cc @@ -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 cell, Handle 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); diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index f8d51d0293..afda6e6a02 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -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(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(); diff --git a/test/unittests/compiler/js-call-reducer-unittest.cc b/test/unittests/compiler/js-call-reducer-unittest.cc index 32e1c3717c..10643ddc8b 100644 --- a/test/unittests/compiler/js-call-reducer-unittest.cc +++ b/test/unittests/compiler/js-call-reducer-unittest.cc @@ -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);