Revert "[compiler] Directly read PropertyCells"

This reverts commit 42cd9eb78d.

Reason for revert: Clusterfuzz issues, e.g.
https://bugs.chromium.org/p/chromium/issues/detail?id=1176318

Original change's description:
> [compiler] Directly read PropertyCells
>
> Main changes:
>
> - Introduce a new broker data kind kBackgroundSerialized for objects
>   that can be serialized in the background (when direct reads are on).
>   (I'm planning to remove kPossiblyBackgroundSerialized in a followup,
>   in favor of a dynamic choice of kSerialized or kBackgroundSerialized).
> - Make PropertyCell use that new kind.
> - Introduce a bottleneck in runtime code for changes to PropertyCells
>   and make sure that a certain protocol is followed that allows
>   concurrent reads from the background thread.
> - Improve interface of PropertyCell in various ways.
>
> Bug: v8:7790
> Change-Id: If3d7926c3b894808811348b4b2bed153f5c06897
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2661462
> Reviewed-by: Toon Verwaest <verwaest@chromium.org>
> Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
> Commit-Queue: Georg Neis <neis@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#72586}

TBR=ulan@chromium.org,neis@chromium.org,verwaest@chromium.org,nicohartmann@chromium.org

Change-Id: Id04145760c49fa379bc5a3fc16eba664025a9180
Bug: v8:7790
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2685125
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72619}
This commit is contained in:
Georg Neis 2021-02-10 08:58:47 +01:00 committed by Commit Bot
parent d5416b9918
commit 87df0b7ecc
29 changed files with 260 additions and 455 deletions

View File

@ -256,6 +256,8 @@ class FieldConstnessDependency final : public CompilationDependency {
class GlobalPropertyDependency final : public CompilationDependency {
public:
// TODO(neis): Once the concurrent compiler frontend is always-on, we no
// longer need to explicitly store the type and the read_only flag.
GlobalPropertyDependency(const PropertyCellRef& cell, PropertyCellType type,
bool read_only)
: cell_(cell), type_(type), read_only_(read_only) {
@ -437,13 +439,14 @@ PropertyConstness CompilationDependencies::DependOnFieldConstness(
void CompilationDependencies::DependOnGlobalProperty(
const PropertyCellRef& cell) {
DCHECK(!cell.IsNeverSerializedHeapObject());
PropertyCellType type = cell.property_details().cell_type();
bool read_only = cell.property_details().IsReadOnly();
RecordDependency(zone_->New<GlobalPropertyDependency>(cell, type, read_only));
}
bool CompilationDependencies::DependOnProtector(const PropertyCellRef& cell) {
cell.SerializeAsProtector();
DCHECK(!cell.IsNeverSerializedHeapObject());
if (cell.value().AsSmi() != Protectors::kProtectorValid) return false;
RecordDependency(zone_->New<ProtectorDependency>(cell));
return true;

View File

@ -101,13 +101,6 @@ enum class OddballType : uint8_t {
V(HeapNumber) \
V(Map)
// This list is sorted such that subtypes appear before their supertypes.
// DO NOT VIOLATE THIS PROPERTY!
// Types in this list can be serialized on demand from the background thread.
#define HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(V) \
/* Subtypes of HeapObject */ \
V(PropertyCell)
// This list is sorted such that subtypes appear before their supertypes.
// DO NOT VIOLATE THIS PROPERTY!
#define HEAP_BROKER_SERIALIZED_OBJECT_LIST(V) \
@ -139,6 +132,7 @@ enum class OddballType : uint8_t {
V(FunctionTemplateInfo) \
V(JSReceiver) \
V(Name) \
V(PropertyCell) \
V(SourceTextModule) \
/* Subtypes of Object */ \
V(HeapObject)
@ -152,7 +146,6 @@ class PropertyAccessInfo;
#define FORWARD_DECL(Name) class Name##Ref;
HEAP_BROKER_SERIALIZED_OBJECT_LIST(FORWARD_DECL)
HEAP_BROKER_POSSIBLY_BACKGROUND_SERIALIZED_OBJECT_LIST(FORWARD_DECL)
HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(FORWARD_DECL)
HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(FORWARD_DECL)
#undef FORWARD_DECL
@ -182,14 +175,12 @@ class V8_EXPORT_PRIVATE ObjectRef {
#define HEAP_IS_METHOD_DECL(Name) bool Is##Name() const;
HEAP_BROKER_SERIALIZED_OBJECT_LIST(HEAP_IS_METHOD_DECL)
HEAP_BROKER_POSSIBLY_BACKGROUND_SERIALIZED_OBJECT_LIST(HEAP_IS_METHOD_DECL)
HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(HEAP_IS_METHOD_DECL)
HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(HEAP_IS_METHOD_DECL)
#undef HEAP_IS_METHOD_DECL
#define HEAP_AS_METHOD_DECL(Name) Name##Ref As##Name() const;
HEAP_BROKER_SERIALIZED_OBJECT_LIST(HEAP_AS_METHOD_DECL)
HEAP_BROKER_POSSIBLY_BACKGROUND_SERIALIZED_OBJECT_LIST(HEAP_AS_METHOD_DECL)
HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(HEAP_AS_METHOD_DECL)
HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(HEAP_AS_METHOD_DECL)
#undef HEAP_AS_METHOD_DECL
@ -313,16 +304,9 @@ class PropertyCellRef : public HeapObjectRef {
Handle<PropertyCell> object() const;
// Can be called from a background thread.
V8_WARN_UNUSED_RESULT bool Serialize() const;
void SerializeAsProtector() const {
bool serialized = Serialize();
// A protector always holds a Smi value and its cell type never changes, so
// Serialize can't fail.
CHECK(serialized);
}
PropertyDetails property_details() const;
void Serialize();
ObjectRef value() const;
};

View File

@ -653,7 +653,6 @@ Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) {
} else {
PropertyCellRef array_constructor_protector(
broker(), factory()->array_constructor_protector());
array_constructor_protector.SerializeAsProtector();
can_inline_call = array_constructor_protector.value().AsSmi() ==
Protectors::kProtectorValid;
}

View File

@ -32,7 +32,6 @@
#include "src/objects/literal-objects-inl.h"
#include "src/objects/module-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/property-details.h"
#include "src/objects/template-objects-inl.h"
#include "src/objects/templates.h"
#include "src/utils/utils.h"
@ -46,8 +45,9 @@ namespace compiler {
#define FORWARD_DECL(Name) class Name##Data;
HEAP_BROKER_SERIALIZED_OBJECT_LIST(FORWARD_DECL)
// TODO(solanes, v8:10866): Remove once FLAG_turbo_direct_heap_access is
// removed.
HEAP_BROKER_POSSIBLY_BACKGROUND_SERIALIZED_OBJECT_LIST(FORWARD_DECL)
HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(FORWARD_DECL)
HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(FORWARD_DECL)
#undef FORWARD_DECL
@ -84,7 +84,6 @@ enum ObjectDataKind {
kSmi,
kSerializedHeapObject,
kPossiblyBackgroundSerializedHeapObject,
kBackgroundSerializedHeapObject,
kUnserializedHeapObject,
kNeverSerializedHeapObject,
kUnserializedReadOnlyHeapObject
@ -139,8 +138,7 @@ class ObjectData : public ZoneObject {
CHECK_IMPLIES(broker->mode() == JSHeapBroker::kSerialized,
kind == kUnserializedReadOnlyHeapObject || kind == kSmi ||
kind == kNeverSerializedHeapObject ||
kind == kPossiblyBackgroundSerializedHeapObject ||
kind == kBackgroundSerializedHeapObject);
kind == kPossiblyBackgroundSerializedHeapObject);
CHECK_IMPLIES(kind == kUnserializedReadOnlyHeapObject,
IsReadOnlyHeapObject(*object));
}
@ -148,14 +146,14 @@ class ObjectData : public ZoneObject {
#define DECLARE_IS(Name) bool Is##Name() const;
HEAP_BROKER_SERIALIZED_OBJECT_LIST(DECLARE_IS)
HEAP_BROKER_POSSIBLY_BACKGROUND_SERIALIZED_OBJECT_LIST(DECLARE_IS)
HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(DECLARE_IS)
HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(DECLARE_IS)
#undef DECLARE_IS
#define DECLARE_AS(Name) Name##Data* As##Name();
HEAP_BROKER_SERIALIZED_OBJECT_LIST(DECLARE_AS)
// TODO(solanes, v8:10866): Remove once FLAG_turbo_direct_heap_access is
// removed.
HEAP_BROKER_POSSIBLY_BACKGROUND_SERIALIZED_OBJECT_LIST(DECLARE_AS)
HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(DECLARE_AS)
HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(DECLARE_AS)
#undef DECLARE_AS
@ -199,26 +197,17 @@ class HeapObjectData : public ObjectData {
class PropertyCellData : public HeapObjectData {
public:
PropertyCellData(JSHeapBroker* broker, ObjectData** storage,
Handle<PropertyCell> object,
ObjectDataKind kind = ObjectDataKind::kSerializedHeapObject);
Handle<PropertyCell> object);
bool Serialize(JSHeapBroker* broker);
PropertyDetails property_details() const { return property_details_; }
PropertyDetails property_details() const {
CHECK(serialized());
return property_details_;
}
ObjectData* value() const {
DCHECK(serialized());
return value_;
}
void Serialize(JSHeapBroker* broker);
ObjectData* value() const { return value_; }
private:
PropertyDetails property_details_ = PropertyDetails::Empty();
ObjectData* value_ = nullptr;
PropertyDetails const property_details_;
bool serialized() const { return value_ != nullptr; }
ObjectData* value_ = nullptr;
};
// TODO(mslekova): Once we have real-world usage data, we might want to
@ -301,65 +290,16 @@ void JSHeapBroker::IncrementTracingIndentation() { ++trace_indentation_; }
void JSHeapBroker::DecrementTracingIndentation() { --trace_indentation_; }
PropertyCellData::PropertyCellData(JSHeapBroker* broker, ObjectData** storage,
Handle<PropertyCell> object,
ObjectDataKind kind)
: HeapObjectData(broker, storage, object, kind) {}
Handle<PropertyCell> object)
: HeapObjectData(broker, storage, object),
property_details_(object->property_details()) {}
bool PropertyCellData::Serialize(JSHeapBroker* broker) {
if (serialized()) return true;
void PropertyCellData::Serialize(JSHeapBroker* broker) {
if (value_ != nullptr) return;
TraceScope tracer(broker, this, "PropertyCellData::Serialize");
auto cell = Handle<PropertyCell>::cast(object());
// While this code runs on a background thread, the property cell might
// undergo state transitions via calls to PropertyCell::Transition. These
// transitions follow a certain protocol on which we rely here to ensure that
// we only report success when we can guarantee consistent data. A key
// property is that after transitioning from cell type A to B (A != B), there
// will never be a transition back to A, unless A is kConstant and the new
// value is the hole (i.e. the property cell was invalidated, which is a final
// state).
PropertyDetails property_details = cell->property_details(kAcquireLoad);
Handle<Object> value =
broker->CanonicalPersistentHandle(cell->value(kAcquireLoad));
if (broker->ObjectMayBeUninitialized(value)) {
DCHECK(!broker->IsMainThread());
return false;
}
{
PropertyDetails property_details_again =
cell->property_details(kAcquireLoad);
if (property_details != property_details_again) {
DCHECK(!broker->IsMainThread());
return false;
}
}
if (property_details.cell_type() == PropertyCellType::kConstant) {
Handle<Object> value_again =
broker->CanonicalPersistentHandle(cell->value(kAcquireLoad));
if (*value != *value_again) {
DCHECK(!broker->IsMainThread());
return false;
}
}
ObjectData* value_data = broker->TryGetOrCreateData(value, false);
if (value_data == nullptr) {
DCHECK(!broker->IsMainThread());
return false;
}
PropertyCell::CheckDataIsCompatible(property_details, *value);
DCHECK(!serialized());
property_details_ = property_details;
value_ = value_data;
DCHECK(serialized());
return true;
value_ = broker->GetOrCreateData(cell->value());
}
void FunctionTemplateInfoData::SerializeCallCode(JSHeapBroker* broker) {
@ -1277,8 +1217,7 @@ HeapObjectData::HeapObjectData(JSHeapBroker* broker, ObjectData** storage,
CHECK_IMPLIES(kind == kSerializedHeapObject,
broker->mode() == JSHeapBroker::kSerializing);
CHECK_IMPLIES(broker->mode() == JSHeapBroker::kSerialized,
kind == kPossiblyBackgroundSerializedHeapObject ||
kind == kBackgroundSerializedHeapObject);
kind == kPossiblyBackgroundSerializedHeapObject);
}
InstanceType HeapObjectData::GetMapInstanceType() const {
@ -2189,17 +2128,15 @@ class CodeData : public HeapObjectData {
}
HEAP_BROKER_SERIALIZED_OBJECT_LIST(DEFINE_IS)
HEAP_BROKER_POSSIBLY_BACKGROUND_SERIALIZED_OBJECT_LIST(DEFINE_IS)
HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(DEFINE_IS)
HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(DEFINE_IS)
#undef DEFINE_IS
#define DEFINE_AS(Name) \
Name##Data* ObjectData::As##Name() { \
CHECK(Is##Name()); \
CHECK(kind_ == kSerializedHeapObject || \
kind_ == kPossiblyBackgroundSerializedHeapObject || \
kind_ == kBackgroundSerializedHeapObject); \
return static_cast<Name##Data*>(this); \
#define DEFINE_AS(Name) \
Name##Data* ObjectData::As##Name() { \
CHECK(Is##Name()); \
CHECK(kind_ == kSerializedHeapObject || \
kind_ == kPossiblyBackgroundSerializedHeapObject); \
return static_cast<Name##Data*>(this); \
}
HEAP_BROKER_SERIALIZED_OBJECT_LIST(DEFINE_AS)
#undef DEFINE_AS
@ -2211,15 +2148,6 @@ HEAP_BROKER_SERIALIZED_OBJECT_LIST(DEFINE_AS)
}
HEAP_BROKER_POSSIBLY_BACKGROUND_SERIALIZED_OBJECT_LIST(DEFINE_AS)
#undef DEFINE_AS
#define DEFINE_AS(Name) \
Name##Data* ObjectData::As##Name() { \
CHECK(Is##Name()); \
CHECK(kind_ == kSerializedHeapObject || \
kind_ == kBackgroundSerializedHeapObject); \
return static_cast<Name##Data*>(this); \
}
HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(DEFINE_AS)
#undef DEFINE_AS
// TODO(solanes, v8:10866): Remove once FLAG_turbo_direct_heap_access is
// removed.
@ -2824,6 +2752,8 @@ void JSHeapBroker::InitializeAndStartSerializing(
// Throw away the dummy data that we created while disabled.
refs_->Clear();
refs_ = nullptr;
refs_ =
zone()->New<RefsMap>(kInitialRefsBucketCount, AddressMatcher(), zone());
@ -2838,7 +2768,7 @@ void JSHeapBroker::InitializeAndStartSerializing(
CollectArrayAndObjectPrototypes();
Factory* const f = isolate()->factory();
if (!FLAG_turbo_direct_heap_access) {
{
ObjectData* data;
data = GetOrCreateData(f->array_buffer_detaching_protector());
if (!data->should_access_heap()) data->AsPropertyCell()->Serialize(this);
@ -2892,9 +2822,6 @@ ObjectData* JSHeapBroker::TryGetOrCreateData(Handle<Object> object,
return *storage;
}
CHECK(mode() == JSHeapBroker::kSerializing ||
mode() == JSHeapBroker::kSerialized);
ObjectData* object_data;
if (object->IsSmi()) {
entry = refs_->LookupOrInsert(object.address());
@ -2933,26 +2860,8 @@ ObjectData* JSHeapBroker::TryGetOrCreateData(Handle<Object> object,
object_data = zone()->New<name##Data>(this, &(entry->value), \
Handle<name>::cast(object));
HEAP_BROKER_POSSIBLY_BACKGROUND_SERIALIZED_OBJECT_LIST(
CREATE_DATA_FOR_POSSIBLE_SERIALIZATION)
CREATE_DATA_FOR_POSSIBLE_SERIALIZATION)
#undef CREATE_DATA_FOR_POSSIBLE_SERIALIZATION
#define CREATE_DATA_FOR_BACKGROUND_SERIALIZATION(name) \
} else if (object->Is##name()) { \
if (FLAG_turbo_direct_heap_access) { \
entry = refs_->LookupOrInsert(object.address()); \
object_data = zone()->New<name##Data>( \
this, &(entry->value), Handle<name>::cast(object), \
kBackgroundSerializedHeapObject); \
} else if (mode() == kSerializing) { \
entry = refs_->LookupOrInsert(object.address()); \
object_data = zone()->New<name##Data>(this, &(entry->value), \
Handle<name>::cast(object)); \
} else { \
CHECK(!crash_on_error); \
return nullptr; \
}
HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(
CREATE_DATA_FOR_BACKGROUND_SERIALIZATION)
#undef CREATE_DATA_FOR_SERIALIZATION
#define CREATE_DATA_FOR_SERIALIZATION(name) \
} else if (object->Is##name()) { \
if (mode() == kSerializing) { \
@ -2990,23 +2899,9 @@ ObjectData* JSHeapBroker::GetOrCreateData(
}
HEAP_BROKER_SERIALIZED_OBJECT_LIST(DEFINE_IS_AND_AS)
HEAP_BROKER_POSSIBLY_BACKGROUND_SERIALIZED_OBJECT_LIST(DEFINE_IS_AND_AS)
HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(DEFINE_IS_AND_AS)
HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(DEFINE_IS_AND_AS)
#undef DEFINE_IS_AND_AS
bool JSHeapBroker::StackHasOverflowed() const {
DCHECK_IMPLIES(local_isolate_ == nullptr,
ThreadId::Current() == isolate_->thread_id());
return (local_isolate_ != nullptr)
? StackLimitCheck::HasOverflowed(local_isolate_)
: StackLimitCheck(isolate_).HasOverflowed();
}
bool JSHeapBroker::ObjectMayBeUninitialized(Handle<Object> object) const {
return !IsMainThread() && object->IsHeapObject() &&
isolate()->heap()->IsPendingAllocation(HeapObject::cast(*object));
}
bool ObjectRef::IsSmi() const { return data()->is_smi(); }
int ObjectRef::AsSmi() const {
@ -4279,7 +4174,6 @@ Handle<Object> ObjectRef::object() const {
HEAP_BROKER_SERIALIZED_OBJECT_LIST(DEF_OBJECT_GETTER)
HEAP_BROKER_POSSIBLY_BACKGROUND_SERIALIZED_OBJECT_LIST(DEF_OBJECT_GETTER)
HEAP_BROKER_BACKGROUND_SERIALIZED_OBJECT_LIST(DEF_OBJECT_GETTER)
HEAP_BROKER_NEVER_SERIALIZED_OBJECT_LIST(DEF_OBJECT_GETTER)
#undef DEF_OBJECT_GETTER
@ -4532,11 +4426,10 @@ bool JSBoundFunctionRef::Serialize() {
return data()->AsJSBoundFunction()->Serialize(broker());
}
bool PropertyCellRef::Serialize() const {
if (data_->should_access_heap()) return true;
CHECK(broker()->mode() == JSHeapBroker::kSerializing ||
broker()->mode() == JSHeapBroker::kSerialized);
return data()->AsPropertyCell()->Serialize(broker());
void PropertyCellRef::Serialize() {
if (data_->should_access_heap()) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
data()->AsPropertyCell()->Serialize(broker());
}
void FunctionTemplateInfoRef::SerializeCallCode() {
@ -4676,8 +4569,6 @@ bool GlobalAccessFeedback::immutable() const {
base::Optional<ObjectRef> GlobalAccessFeedback::GetConstantHint() const {
if (IsPropertyCell()) {
bool cell_serialized = property_cell().Serialize();
CHECK(cell_serialized); // Can't fail on the main thread.
return property_cell().value();
} else if (IsScriptContextSlot() && immutable()) {
return script_context().get(slot_index());
@ -5000,10 +4891,7 @@ ProcessedFeedback const& JSHeapBroker::ReadFeedbackForGlobalAccess(
// The wanted name belongs (or did belong) to a property on the global
// object and the feedback is the cell holding its value.
PropertyCellRef cell(this, Handle<PropertyCell>::cast(feedback_value));
ObjectRef(
this,
CanonicalPersistentHandle(
Handle<PropertyCell>::cast(feedback_value)->value(kAcquireLoad)));
cell.Serialize();
return *zone()->New<GlobalAccessFeedback>(cell, nexus.kind());
}
@ -5480,6 +5368,14 @@ TemplateObjectFeedback const& ProcessedFeedback::AsTemplateObject() const {
return *static_cast<TemplateObjectFeedback const*>(this);
}
bool JSHeapBroker::StackHasOverflowed() const {
DCHECK_IMPLIES(local_isolate_ == nullptr,
ThreadId::Current() == isolate_->thread_id());
return (local_isolate_ != nullptr)
? StackLimitCheck::HasOverflowed(local_isolate_)
: StackLimitCheck(isolate_).HasOverflowed();
}
OffHeapBytecodeArray::OffHeapBytecodeArray(BytecodeArrayRef bytecode_array)
: array_(bytecode_array) {}

View File

@ -313,16 +313,6 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
friend class HeapObjectRef;
friend class ObjectRef;
friend class ObjectData;
friend class PropertyCellData;
bool IsMainThread() const {
return local_isolate() == nullptr || local_isolate()->is_main_thread();
}
// If this returns false, the object is guaranteed to be fully initialized and
// thus safe to read from a memory safety perspective. The converse does not
// necessarily hold.
bool ObjectMayBeUninitialized(Handle<Object> object) const;
bool CanUseFeedback(const FeedbackNexus& nexus) const;
const ProcessedFeedback& NewInsufficientFeedback(FeedbackSlotKind kind) const;

View File

@ -802,9 +802,9 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
Node* node, Node* lookup_start_object, Node* receiver, Node* value,
NameRef const& name, AccessMode access_mode, Node* key,
PropertyCellRef const& property_cell, Node* effect) {
if (!property_cell.Serialize()) {
TRACE_BROKER_MISSING(broker(), "usable data for " << property_cell);
return NoChange();
Node* control = NodeProperties::GetControlInput(node);
if (effect == nullptr) {
effect = NodeProperties::GetEffectInput(node);
}
ObjectRef property_cell_value = property_cell.value();
@ -819,11 +819,6 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
PropertyCellType property_cell_type = property_details.cell_type();
DCHECK_EQ(kData, property_details.kind());
Node* control = NodeProperties::GetControlInput(node);
if (effect == nullptr) {
effect = NodeProperties::GetEffectInput(node);
}
// We have additional constraints for stores.
if (access_mode == AccessMode::kStore) {
DCHECK_EQ(receiver, lookup_start_object);
@ -928,6 +923,10 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
DCHECK_EQ(receiver, lookup_start_object);
DCHECK(!property_details.IsReadOnly());
switch (property_details.cell_type()) {
case PropertyCellType::kUndefined: {
UNREACHABLE();
break;
}
case PropertyCellType::kConstant: {
// Record a code dependency on the cell, and just deoptimize if the new
// value doesn't match the previous value stored inside the cell.
@ -998,8 +997,6 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
jsgraph()->Constant(property_cell), value, effect, control);
break;
}
case PropertyCellType::kUndefined:
UNREACHABLE();
}
}

View File

@ -594,8 +594,6 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
PropertyCellRef string_length_protector(
broker(), factory()->string_length_protector());
string_length_protector.SerializeAsProtector();
if (string_length_protector.value().AsSmi() ==
Protectors::kProtectorValid) {
// We can just deoptimize if the {length} is out-of-bounds. Besides

View File

@ -1203,10 +1203,6 @@ PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl(
}
}
if (FLAG_turbo_direct_heap_access) {
isolate->heap()->PublishPendingAllocations();
}
return SUCCEEDED;
}

View File

@ -2991,9 +2991,7 @@ SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess(
base::Optional<PropertyCellRef> cell = global_object.GetPropertyCell(
name, SerializationPolicy::kSerializeIfNeeded);
if (access_mode == AccessMode::kLoad && cell.has_value()) {
result_hints->AddConstant(
handle(cell->object()->value(), broker()->isolate()), zone(),
broker());
result_hints->AddConstant(cell->value().object(), zone(), broker());
}
}

View File

@ -967,9 +967,11 @@ void Oddball::OddballVerify(Isolate* isolate) {
}
void PropertyCell::PropertyCellVerify(Isolate* isolate) {
// TODO(torque): replace with USE_TORQUE_VERIFIER(PropertyCell) once
// it supports UniqueName type.
TorqueGeneratedClassVerifiers::PropertyCellVerify(*this, isolate);
CHECK(name().IsUniqueName());
CheckDataIsCompatible(property_details(), value());
}
void CodeDataContainer::CodeDataContainerVerify(Isolate* isolate) {

View File

@ -1524,11 +1524,11 @@ void PropertyCell::PropertyCellPrint(std::ostream& os) { // NOLINT
PrintHeader(os, "PropertyCell");
os << "\n - name: ";
name().NamePrint(os);
os << "\n - value: " << Brief(value(kAcquireLoad));
os << "\n - value: " << Brief(value());
os << "\n - details: ";
PropertyDetails details = property_details(kAcquireLoad);
details.PrintAsSlowTo(os, true);
os << "\n - cell_type: " << details.cell_type();
property_details().PrintAsSlowTo(os, true);
PropertyCellType cell_type = property_details().cell_type();
os << "\n - cell_type: " << cell_type;
os << "\n";
}

View File

@ -6,6 +6,7 @@
#define V8_EXECUTION_PROTECTORS_INL_H_
#include "src/execution/protectors.h"
#include "src/objects/contexts-inl.h"
#include "src/objects/property-cell-inl.h"
#include "src/objects/smi.h"

View File

@ -53,7 +53,9 @@ DECLARED_PROTECTORS_ON_ISOLATE(V)
TraceProtectorInvalidation(#name); \
} \
isolate->CountUsage(v8::Isolate::kInvalidated##name##Protector); \
isolate->factory()->cell()->InvalidateProtector(); \
PropertyCell::SetValueWithInvalidation( \
isolate, #cell, isolate->factory()->cell(), \
handle(Smi::FromInt(kProtectorInvalid), isolate)); \
DCHECK(!Is##name##Intact(isolate)); \
}
DECLARED_PROTECTORS_ON_ISOLATE(INVALIDATE_PROTECTOR_ON_ISOLATE_DEFINITION)

View File

@ -1372,8 +1372,6 @@ Handle<FeedbackCell> Factory::NewManyClosuresCell(Handle<HeapObject> value) {
}
Handle<PropertyCell> Factory::NewPropertyCell(Handle<Name> name,
PropertyDetails details,
Handle<Object> value,
AllocationType allocation) {
DCHECK(name->IsUniqueName());
STATIC_ASSERT(PropertyCell::kSize <= kMaxRegularHeapObjectSize);
@ -1382,18 +1380,12 @@ Handle<PropertyCell> Factory::NewPropertyCell(Handle<Name> name,
Handle<PropertyCell> cell(PropertyCell::cast(result), isolate());
cell->set_dependent_code(DependentCode::cast(*empty_weak_fixed_array()),
SKIP_WRITE_BARRIER);
cell->set_property_details(PropertyDetails(Smi::zero()));
cell->set_name(*name);
cell->set_value(*value);
cell->set_property_details_raw(details.AsSmi());
cell->set_value(*the_hole_value());
return cell;
}
Handle<PropertyCell> Factory::NewProtector() {
return NewPropertyCell(
empty_string(), PropertyDetails::Empty(PropertyCellType::kConstantType),
handle(Smi::FromInt(Protectors::kProtectorValid), isolate()));
}
Handle<TransitionArray> Factory::NewTransitionArray(int number_of_transitions,
int slack) {
int capacity = TransitionArray::LengthFor(number_of_transitions + slack);
@ -2058,8 +2050,8 @@ Handle<JSGlobalObject> Factory::NewJSGlobalObject(
PropertyDetails d(kAccessor, details.attributes(),
PropertyCellType::kMutable);
Handle<Name> name(descs->GetKey(i), isolate());
Handle<Object> value(descs->GetStrongValue(i), isolate());
Handle<PropertyCell> cell = NewPropertyCell(name, d, value);
Handle<PropertyCell> cell = NewPropertyCell(name);
cell->set_value(descs->GetStrongValue(i));
// |dictionary| already contains enough space for all properties.
USE(GlobalDictionary::Add(isolate(), dictionary, name, cell, d));
}

View File

@ -386,9 +386,7 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
Handle<Cell> NewCell(Handle<Object> value);
Handle<PropertyCell> NewPropertyCell(
Handle<Name> name, PropertyDetails details, Handle<Object> value,
AllocationType allocation = AllocationType::kOld);
Handle<PropertyCell> NewProtector();
Handle<Name> name, AllocationType allocation = AllocationType::kOld);
Handle<FeedbackCell> NewNoClosuresCell(Handle<HeapObject> value);
Handle<FeedbackCell> NewOneClosureCell(Handle<HeapObject> value);

View File

@ -857,22 +857,117 @@ void Heap::CreateInitialObjects() {
set_empty_script(*script);
// Protectors
set_array_buffer_detaching_protector(*factory->NewProtector());
set_array_constructor_protector(*factory->NewProtector());
set_array_iterator_protector(*factory->NewProtector());
set_array_species_protector(*factory->NewProtector());
set_is_concat_spreadable_protector(*factory->NewProtector());
set_map_iterator_protector(*factory->NewProtector());
set_no_elements_protector(*factory->NewProtector());
set_promise_hook_protector(*factory->NewProtector());
set_promise_resolve_protector(*factory->NewProtector());
set_promise_species_protector(*factory->NewProtector());
set_promise_then_protector(*factory->NewProtector());
set_regexp_species_protector(*factory->NewProtector());
set_set_iterator_protector(*factory->NewProtector());
set_string_iterator_protector(*factory->NewProtector());
set_string_length_protector(*factory->NewProtector());
set_typed_array_species_protector(*factory->NewProtector());
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
set_array_constructor_protector(*cell);
}
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
set_no_elements_protector(*cell);
}
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
set_array_iterator_protector(*cell);
}
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
set_map_iterator_protector(*cell);
}
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
set_set_iterator_protector(*cell);
}
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
set_is_concat_spreadable_protector(*cell);
}
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
set_array_species_protector(*cell);
}
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
set_typed_array_species_protector(*cell);
}
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
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());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
set_string_iterator_protector(*cell);
}
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
set_string_length_protector(*cell);
}
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
set_array_buffer_detaching_protector(*cell);
}
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
set_promise_hook_protector(*cell);
}
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
set_promise_resolve_protector(*cell);
}
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
set_promise_then_protector(*cell);
}
set_serialized_objects(roots.empty_fixed_array());
set_serialized_global_proxy_sizes(roots.empty_fixed_array());

View File

@ -2603,8 +2603,12 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
native_context()->set_regexp_last_match_info(*last_match_info);
// Install the species protector cell.
Handle<PropertyCell> cell = factory->NewProtector();
native_context()->set_regexp_species_protector(*cell);
{
Handle<PropertyCell> cell =
factory->NewPropertyCell(factory->empty_string());
cell->set_value(Smi::FromInt(Protectors::kProtectorValid));
native_context()->set_regexp_species_protector(*cell);
}
DCHECK(regexp_fun->HasFastProperties());
}

View File

@ -322,7 +322,16 @@ template <typename Dictionary>
void GlobalDictionaryShape::DetailsAtPut(Dictionary dict, InternalIndex entry,
PropertyDetails value) {
DCHECK(entry.is_found());
dict.CellAt(entry).UpdatePropertyDetailsExceptCellType(value);
PropertyCell cell = dict.CellAt(entry);
// Deopt when when making a writable property read-only. The reverse direction
// is uninteresting because Turbofan does not currently rely on read-only
// unless the property is also configurable, in which case it will stay
// read-only forever.
if (!cell.property_details().IsReadOnly() && value.IsReadOnly()) {
cell.dependent_code().DeoptimizeDependentCodeGroup(
DependentCode::kPropertyCellChangedGroup);
}
cell.set_property_details(value);
}
} // namespace internal

View File

@ -2453,16 +2453,19 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object, Handle<Name> name,
if (entry.is_not_found()) {
DCHECK_IMPLIES(global_obj->map().is_prototype_map(),
Map::IsPrototypeChainInvalidated(global_obj->map()));
auto cell = isolate->factory()->NewPropertyCell(name);
cell->set_value(*value);
auto cell_type = value->IsUndefined(roots) ? PropertyCellType::kUndefined
: PropertyCellType::kConstant;
details = details.set_cell_type(cell_type);
auto cell = isolate->factory()->NewPropertyCell(name, details, value);
value = cell;
dictionary =
GlobalDictionary::Add(isolate, dictionary, name, cell, details);
GlobalDictionary::Add(isolate, dictionary, name, value, details);
global_obj->set_global_dictionary(*dictionary, kReleaseStore);
} else {
PropertyCell::PrepareForValue(isolate, dictionary, entry, value, details);
DCHECK_EQ(dictionary->CellAt(entry).value(), *value);
Handle<PropertyCell> cell = PropertyCell::PrepareForValue(
isolate, dictionary, entry, value, details);
cell->set_value(*value);
}
} else {
if (V8_DICT_MODE_PROTOTYPES_BOOL) {

View File

@ -494,8 +494,8 @@ void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
Handle<PropertyCell> cell = PropertyCell::PrepareForValue(
isolate(), dictionary, dictionary_entry(), value, details);
cell->set_value(*value);
property_details_ = cell->property_details();
DCHECK_EQ(cell->value(), *value);
} else {
PropertyDetails details(kData, attributes, PropertyConstness::kMutable);
if (V8_DICT_MODE_PROTOTYPES_BOOL) {
@ -554,12 +554,13 @@ void LookupIterator::PrepareTransitionToDataProperty(
if (map->is_dictionary_map()) {
state_ = TRANSITION;
if (map->IsJSGlobalObjectMap()) {
Handle<PropertyCell> cell = isolate_->factory()->NewPropertyCell(name());
DCHECK(cell->value(isolate_).IsTheHole(isolate_));
DCHECK(!value->IsTheHole(isolate_));
// Don't set enumeration index (it will be set during value store).
property_details_ = PropertyDetails(
kData, attributes, PropertyCell::InitialType(isolate_, value));
transition_ = isolate_->factory()->NewPropertyCell(
name(), property_details_, value);
transition_ = cell;
has_property_ = true;
} else {
// Don't set enumeration index (it will be set during value store).
@ -1033,13 +1034,9 @@ void LookupIterator::WriteDataValue(Handle<Object> value,
DCHECK_EQ(PropertyConstness::kConst, property_details_.constness());
}
} else if (holder->IsJSGlobalObject(isolate_)) {
// PropertyCell::PrepareForValue already wrote the value into the cell.
#ifdef DEBUG
GlobalDictionary dictionary =
JSGlobalObject::cast(*holder).global_dictionary(isolate_, kAcquireLoad);
PropertyCell cell = dictionary.CellAt(isolate_, dictionary_entry());
DCHECK_EQ(cell.value(), *value);
#endif // DEBUG
dictionary.CellAt(isolate_, dictionary_entry()).set_value(*value);
} else {
DCHECK_IMPLIES(holder->IsJSProxy(isolate_), name()->IsPrivate(isolate_));
// Check similar to fast mode case above.
@ -1144,9 +1141,7 @@ LookupIterator::State LookupIterator::LookupInSpecialHolder(
number_ = dict.FindEntry(isolate(), name_);
if (number_.is_not_found()) return NOT_FOUND;
PropertyCell cell = dict.CellAt(isolate_, number_);
if (cell.value(isolate_).IsTheHole(isolate_)) {
return NOT_FOUND;
}
if (cell.value(isolate_).IsTheHole(isolate_)) return NOT_FOUND;
property_details_ = cell.property_details();
has_property_ = true;
switch (property_details_.kind()) {

View File

@ -2150,7 +2150,7 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
os << " value=";
HeapStringAllocator allocator;
StringStream accumulator(&allocator);
cell.value(kAcquireLoad).ShortPrint(&accumulator);
cell.value().ShortPrint(&accumulator);
os << accumulator.ToCString().get();
os << '>';
break;
@ -6355,7 +6355,8 @@ void PropertyCell::ClearAndInvalidate(ReadOnlyRoots roots) {
DCHECK(!value().IsTheHole(roots));
PropertyDetails details = property_details();
details = details.set_cell_type(PropertyCellType::kConstant);
Transition(details, roots.the_hole_value_handle());
set_value(roots.the_hole_value());
set_property_details(details);
dependent_code().DeoptimizeDependentCodeGroup(
DependentCode::kPropertyCellChangedGroup);
}
@ -6367,15 +6368,15 @@ Handle<PropertyCell> PropertyCell::InvalidateAndReplaceEntry(
Handle<PropertyCell> cell(dictionary->CellAt(entry), isolate);
Handle<Name> name(cell->name(), isolate);
PropertyDetails details = cell->property_details();
Handle<Object> value(cell->value(), isolate);
DCHECK(details.IsConfigurable());
DCHECK(!value->IsTheHole(isolate));
DCHECK(!cell->value().IsTheHole(isolate));
// Swap with a copy of type kMutable.
// Swap with a copy.
Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell(name);
new_cell->set_value(cell->value());
// Cell is officially mutable henceforth.
details = details.set_cell_type(PropertyCellType::kMutable);
Handle<PropertyCell> new_cell =
isolate->factory()->NewPropertyCell(name, details, value);
new_cell->set_property_details(details);
dictionary->ValueAtPut(entry, *new_cell);
cell->ClearAndInvalidate(ReadOnlyRoots(isolate));
@ -6423,6 +6424,7 @@ PropertyCellType PropertyCell::UpdatedType(Isolate* isolate,
case PropertyCellType::kMutable:
return PropertyCellType::kMutable;
}
UNREACHABLE();
}
Handle<PropertyCell> PropertyCell::PrepareForValue(
@ -6445,8 +6447,17 @@ Handle<PropertyCell> PropertyCell::PrepareForValue(
cell = PropertyCell::InvalidateAndReplaceEntry(isolate, dictionary, entry);
}
// Install new property details.
details = details.set_cell_type(new_type);
cell->Transition(details, value);
cell->set_property_details(details);
if (new_type == PropertyCellType::kConstant ||
new_type == PropertyCellType::kConstantType) {
// Store the value now to ensure that the cell contains the constant or
// type information. Otherwise subsequent store operation will turn
// the cell to mutable.
cell->set_value(*value);
}
// Deopt when transitioning from a constant type or when making a writable
// property read-only. Making a read-only property writable again is not
@ -6463,58 +6474,17 @@ Handle<PropertyCell> PropertyCell::PrepareForValue(
}
// static
void PropertyCell::InvalidateProtector() {
if (value() != Smi::FromInt(Protectors::kProtectorInvalid)) {
DCHECK_EQ(value(), Smi::FromInt(Protectors::kProtectorValid));
set_value(Smi::FromInt(Protectors::kProtectorInvalid), kReleaseStore);
dependent_code().DeoptimizeDependentCodeGroup(
void PropertyCell::SetValueWithInvalidation(Isolate* isolate,
const char* cell_name,
Handle<PropertyCell> cell,
Handle<Object> new_value) {
if (cell->value() != *new_value) {
cell->set_value(*new_value);
cell->dependent_code().DeoptimizeDependentCodeGroup(
DependentCode::kPropertyCellChangedGroup);
}
}
// static
bool PropertyCell::CheckDataIsCompatible(PropertyDetails details,
Object value) {
DisallowGarbageCollection no_gc;
PropertyCellType cell_type = details.cell_type();
if (value.IsTheHole()) {
CHECK_EQ(cell_type, PropertyCellType::kConstant);
} else {
CHECK_EQ(value.IsAccessorInfo() || value.IsAccessorPair(),
details.kind() == kAccessor);
DCHECK_IMPLIES(cell_type == PropertyCellType::kUndefined,
value.IsUndefined());
}
return true;
}
#ifdef DEBUG
bool PropertyCell::CanTransitionTo(PropertyDetails new_details,
Object new_value) const {
// Extending the implementation of PropertyCells with additional states
// and/or transitions likely requires changes to PropertyCellData::Serialize.
DisallowGarbageCollection no_gc;
DCHECK(CheckDataIsCompatible(new_details, new_value));
switch (property_details().cell_type()) {
case PropertyCellType::kUndefined:
return new_details.cell_type() != PropertyCellType::kUndefined;
case PropertyCellType::kConstant:
return !value().IsTheHole() &&
new_details.cell_type() != PropertyCellType::kUndefined;
case PropertyCellType::kConstantType:
return new_details.cell_type() == PropertyCellType::kConstantType ||
new_details.cell_type() == PropertyCellType::kMutable ||
(new_details.cell_type() == PropertyCellType::kConstant &&
new_value.IsTheHole());
case PropertyCellType::kMutable:
return new_details.cell_type() == PropertyCellType::kMutable ||
(new_details.cell_type() == PropertyCellType::kConstant &&
new_value.IsTheHole());
}
UNREACHABLE();
}
#endif // DEBUG
int JSGeneratorObject::source_position() const {
CHECK(is_suspended());
DCHECK(function().shared().HasBytecodeArray());

View File

@ -22,43 +22,15 @@ CAST_ACCESSOR(PropertyCell)
ACCESSORS(PropertyCell, dependent_code, DependentCode, kDependentCodeOffset)
ACCESSORS(PropertyCell, name, Name, kNameOffset)
ACCESSORS(PropertyCell, property_details_raw, Smi, kPropertyDetailsRawOffset)
RELEASE_ACQUIRE_ACCESSORS(PropertyCell, property_details_raw, Smi,
kPropertyDetailsRawOffset)
ACCESSORS(PropertyCell, value, Object, kValueOffset)
RELEASE_ACQUIRE_ACCESSORS(PropertyCell, value, Object, kValueOffset)
ACCESSORS(PropertyCell, property_details_raw, Smi, kPropertyDetailsRawOffset)
PropertyDetails PropertyCell::property_details() const {
return PropertyDetails(Smi::cast(property_details_raw()));
}
PropertyDetails PropertyCell::property_details(AcquireLoadTag tag) const {
return PropertyDetails(Smi::cast(property_details_raw(tag)));
}
void PropertyCell::UpdatePropertyDetailsExceptCellType(
PropertyDetails details) {
DCHECK(CheckDataIsCompatible(details, value()));
PropertyDetails old_details = property_details();
CHECK_EQ(old_details.cell_type(), details.cell_type());
set_property_details_raw(details.AsSmi(), kReleaseStore);
// Deopt when making a writable property read-only. The reverse direction
// is uninteresting because Turbofan does not currently rely on read-only
// unless the property is also configurable, in which case it will stay
// read-only forever.
if (!old_details.IsReadOnly() && details.IsReadOnly()) {
dependent_code().DeoptimizeDependentCodeGroup(
DependentCode::kPropertyCellChangedGroup);
}
}
void PropertyCell::Transition(PropertyDetails new_details,
Handle<Object> new_value) {
DCHECK(CanTransitionTo(new_details, *new_value));
// This code must be in sync with its counterpart in
// PropertyCellData::Serialize.
set_value(*new_value, kReleaseStore);
set_property_details_raw(new_details.AsSmi(), kReleaseStore);
void PropertyCell::set_property_details(PropertyDetails details) {
set_property_details_raw(details.AsSmi());
}
} // namespace internal

View File

@ -20,24 +20,16 @@ class PropertyCell : public HeapObject {
DECL_GETTER(name, Name)
// [property_details]: details of the global property.
DECL_GETTER(property_details_raw, Smi)
DECL_ACQUIRE_GETTER(property_details_raw, Smi)
inline PropertyDetails property_details() const;
inline PropertyDetails property_details(AcquireLoadTag tag) const;
inline void UpdatePropertyDetailsExceptCellType(PropertyDetails details);
DECL_ACCESSORS(property_details_raw, Smi)
// [value]: value of the global property.
DECL_GETTER(value, Object)
DECL_ACQUIRE_GETTER(value, Object)
DECL_ACCESSORS(value, Object)
// [dependent_code]: code that depends on the type of the global property.
DECL_ACCESSORS(dependent_code, DependentCode)
// Changes the value and/or property details.
// For global properties:
inline void Transition(PropertyDetails new_details, Handle<Object> new_value);
// For protectors:
void InvalidateProtector();
inline PropertyDetails property_details() const;
inline void set_property_details(PropertyDetails details);
static PropertyCellType InitialType(Isolate* isolate, Handle<Object> value);
@ -60,9 +52,9 @@ class PropertyCell : public HeapObject {
Isolate* isolate, Handle<GlobalDictionary> dictionary,
InternalIndex entry);
// Whether or not the {details} and {value} fit together. This is an
// approximation with false positives.
static bool CheckDataIsCompatible(PropertyDetails details, Object value);
static void SetValueWithInvalidation(Isolate* isolate, const char* cell_name,
Handle<PropertyCell> cell,
Handle<Object> new_value);
DECL_CAST(PropertyCell)
DECL_PRINTER(PropertyCell)
@ -79,16 +71,6 @@ class PropertyCell : public HeapObject {
friend class Factory;
DECL_SETTER(name, Name)
DECL_SETTER(value, Object)
DECL_RELEASE_SETTER(value, Object)
DECL_SETTER(property_details_raw, Smi)
DECL_RELEASE_SETTER(property_details_raw, Smi)
#ifdef DEBUG
// Whether the property cell can transition to the given state. This is an
// approximation with false positives.
bool CanTransitionTo(PropertyDetails new_details, Object new_value) const;
#endif // DEBUG
};
} // namespace internal

View File

@ -215,7 +215,7 @@ enum class PropertyCellType {
kUndefined, // The PREMONOMORPHIC of property cells.
kConstant, // Cell has been assigned only once.
kConstantType, // Cell has been assigned only one type.
// Value for dictionaries not holding cells, must be 0:
// Value for dictionaries not holding cells, must have value 0:
kNoCell = kMutable,
};
@ -262,14 +262,6 @@ class PropertyDetails {
return PropertyDetails(kData, NONE, cell_type);
}
bool operator==(PropertyDetails const& other) {
return value_ == other.value_;
}
bool operator!=(PropertyDetails const& other) {
return value_ != other.value_;
}
int pointer() const { return DescriptorPointer::decode(value_); }
PropertyDetails set_pointer(int i) const {

View File

@ -881,8 +881,7 @@ void TestNameDictionaryLookup() {
};
for (size_t i = 0; i < arraysize(keys); i++) {
Handle<Object> value =
factory->NewPropertyCell(keys[i], fake_details, keys[i]);
Handle<Object> value = factory->NewPropertyCell(keys[i]);
dictionary =
Dictionary::Add(isolate, dictionary, keys[i], value, fake_details);
}

View File

@ -1,69 +0,0 @@
// Copyright 2021 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax
// Flags: --concurrent-recompilation --block-concurrent-recompilation
// Flags: --nostress-opt --no-always-opt
// --nostress-opt is in place because this particular optimization
// (guaranteeing that the Array prototype chain has no elements) is
// maintained isolate-wide. Once it's been "broken" by the change
// to the Object prototype below, future compiles will not use the
// optimization anymore, and the code will remain optimized despite
// additional changes to the prototype chain.
if (!%IsConcurrentRecompilationSupported()) {
print("Concurrent recompilation is disabled. Skipping this test.");
quit();
}
function f1(a, i) {
return a[i] + 0.5;
}
%PrepareFunctionForOptimization(f1);
var arr = [0.0,,2.5];
assertEquals(0.5, f1(arr, 0));
assertEquals(0.5, f1(arr, 0));
// Optimized code of f1 depends on initial object and array maps.
%OptimizeFunctionOnNextCall(f1, "concurrent");
// Kick off recompilation.
assertEquals(0.5, f1(arr, 0));
// Invalidate current initial object map.
Object.prototype[1] = 1.5;
assertEquals(2, f1(arr, 1));
// Not yet optimized since concurrent recompilation is blocked.
assertUnoptimized(f1, "no sync");
// Let concurrent recompilation proceed.
%UnblockConcurrentRecompilation();
// Sync with background thread to conclude optimization, which may or may not
// bailout due to map dependency, depending on whether the compiler read the
// NoElements protector before or after the store to Object.prototype above.
assertEquals(2, f1(arr, 1));
// Clear type info for stress runs.
%ClearFunctionFeedback(f1);

View File

@ -28,7 +28,6 @@
// Flags: --allow-natives-syntax
// Flags: --concurrent-recompilation --block-concurrent-recompilation
// Flags: --nostress-opt --no-always-opt
// Flags: --no-turbo-direct-heap-access
// --nostress-opt is in place because this particular optimization
// (guaranteeing that the Array prototype chain has no elements) is
@ -45,6 +44,7 @@ if (!%IsConcurrentRecompilationSupported()) {
function f1(a, i) {
return a[i] + 0.5;
}
%PrepareFunctionForOptimization(f1);
%PrepareFunctionForOptimization(f1);
var arr = [0.0,,2.5];
@ -53,9 +53,7 @@ assertEquals(0.5, f1(arr, 0));
// Optimized code of f1 depends on initial object and array maps.
%OptimizeFunctionOnNextCall(f1, "concurrent");
// Kick off recompilation. Note that the NoElements protector is read by the
// compiler in the main-thread phase of compilation, i.e., before the store to
// Object.prototype below.
// Kick off recompilation;
assertEquals(0.5, f1(arr, 0));
// Invalidate current initial object map after compile graph has been created.
Object.prototype[1] = 1.5;
@ -67,5 +65,5 @@ assertUnoptimized(f1, "no sync");
// Sync with background thread to conclude optimization, which bails out
// due to map dependency.
assertUnoptimized(f1, "sync");
// Clear type info for stress runs.
//Clear type info for stress runs.
%ClearFunctionFeedback(f1);

View File

@ -1046,8 +1046,7 @@
'compiler/regress-905555-2': [SKIP],
'compiler/regress-905555': [SKIP],
'compiler/regress-9945-1': [SKIP],
'concurrent-initial-prototype-change-1': [SKIP],
'concurrent-initial-prototype-change-2': [SKIP],
'concurrent-initial-prototype-change': [SKIP],
'regress/regress-356053': [SKIP],
'regress/regress-embedded-cons-string': [SKIP],

View File

@ -54,14 +54,14 @@ INCOMPATIBLE_FLAGS_PER_VARIANT = {
"nooptimization": ["--opt", "--always-opt", "--no-liftoff", "--wasm-tier-up"],
"slow_path": ["--no-force-slow-path"],
"stress_concurrent_allocation": ["--single-threaded-gc", "--predictable"],
"stress_concurrent_inlining": ["--single-threaded", "--predictable", "--no-turbo-direct-heap-access"],
"stress_concurrent_inlining": ["--single-threaded", "--predictable"],
"stress_incremental_marking": ["--no-stress-incremental-marking"],
"future": ["--parallel-compile-tasks", "--no-turbo-direct-heap-access"],
"future": ["--parallel-compile-tasks"],
"stress_js_bg_compile_wasm_code_gc": ["--no-stress-background-compile", "--parallel-compile-tasks"],
"stress": ["--no-stress-opt", "--always-opt", "--no-always-opt", "--liftoff", "--max-inlined-bytecode-size=*",
"--max-inlined-bytecode-size-cumulative=*", "--stress-inline"],
"turboprop": ["--interrupt-budget=*", "--no-turbo-direct-heap-access", "--no-turboprop"],
"turboprop_as_toptier": ["--interrupt-budget=*", "--no-turbo-direct-heap-access", "--no-turboprop", "--no-turboprop-as-toptier"],
"turboprop": ["--interrupt-budget=*", "--no-turboprop"],
"turboprop_as_toptier": ["--interrupt-budget=*", "--no-turboprop", "--no-turboprop-as-toptier"],
"code_serializer": ["--cache=after-execute", "--cache=full-code-cache", "--cache=none"],
"no_local_heaps": ["--concurrent-inlining", "--turboprop"],
"experimental_regexp": ["--no-enable-experimental-regexp-engine", "--no-default-to-experimental-regexp-engine"],
@ -96,7 +96,7 @@ INCOMPATIBLE_FLAGS_PER_EXTRA_FLAG = {
"--stress_concurrent_allocation": ["--single-threaded-gc", "--predictable"],
"--stress_concurrent_inlining": ["--single-threaded", "--predictable"],
"--stress-flush-bytecode": ["--no-stress-flush-bytecode"],
"--future": ["--parallel-compile-tasks", "--no-turbo-direct-heap-access"],
"--future": ["--parallel-compile-tasks"],
"--stress-incremental-marking": INCOMPATIBLE_FLAGS_PER_VARIANT["stress_incremental_marking"],
}