[compiler] Concurrently read properties from dictionary objects
Replace GetOwnDictionaryPropertyFromHeap with TryGetOwnDictionaryPropertyFromHeap which will return {} if we are trying to read out of bounds of the heap or the object. This is done so that we can concurrently use the method. We introduce a new compilation dependency (DependOnPropertyValueSame) which checks that the background thread indeed read the correct value. Bug: v8:7790 Change-Id: Ia5e308faf1f65add638cd271995f4f33416fbd15 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2930480 Commit-Queue: Santiago Aboy Solanes <solanes@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#75248}
This commit is contained in:
parent
919fa26613
commit
35931e83bd
@ -645,7 +645,7 @@ PropertyAccessInfo AccessInfoFactory::ComputeDictionaryProtoAccessInfo(
|
||||
}
|
||||
|
||||
auto get_accessors = [&]() {
|
||||
return JSObject::DictionaryPropertyAt(holder, dictionary_index);
|
||||
return JSObject::DictionaryPropertyAt(isolate(), holder, dictionary_index);
|
||||
};
|
||||
Handle<Map> holder_map = broker()->CanonicalPersistentHandle(holder->map());
|
||||
return AccessorAccessInfoHelper(isolate(), zone(), broker(), this,
|
||||
|
@ -4,10 +4,12 @@
|
||||
|
||||
#include "src/compiler/compilation-dependencies.h"
|
||||
|
||||
#include "src/base/optional.h"
|
||||
#include "src/compiler/compilation-dependency.h"
|
||||
#include "src/execution/protectors.h"
|
||||
#include "src/handles/handles-inl.h"
|
||||
#include "src/objects/allocation-site-inl.h"
|
||||
#include "src/objects/internal-index.h"
|
||||
#include "src/objects/js-array-inl.h"
|
||||
#include "src/objects/js-function-inl.h"
|
||||
#include "src/objects/objects-inl.h"
|
||||
@ -282,6 +284,61 @@ class OwnConstantDataPropertyDependency final : public CompilationDependency {
|
||||
ObjectRef const value_;
|
||||
};
|
||||
|
||||
class OwnConstantDictionaryPropertyDependency final
|
||||
: public CompilationDependency {
|
||||
public:
|
||||
OwnConstantDictionaryPropertyDependency(JSHeapBroker* broker,
|
||||
const JSObjectRef& holder,
|
||||
InternalIndex index,
|
||||
const ObjectRef& value)
|
||||
: broker_(broker),
|
||||
holder_(holder),
|
||||
map_(holder.map()),
|
||||
index_(index),
|
||||
value_(value) {
|
||||
// We depend on map() being cached.
|
||||
STATIC_ASSERT(ref_traits<JSObject>::ref_serialization_kind !=
|
||||
RefSerializationKind::kNeverSerialized);
|
||||
}
|
||||
|
||||
bool IsValid() const override {
|
||||
if (holder_.object()->map() != *map_.object()) {
|
||||
TRACE_BROKER_MISSING(broker_,
|
||||
"Map change detected in " << holder_.object());
|
||||
return false;
|
||||
}
|
||||
|
||||
base::Optional<Object> maybe_value = JSObject::DictionaryPropertyAt(
|
||||
holder_.object(), index_, broker_->isolate()->heap());
|
||||
|
||||
if (!maybe_value) {
|
||||
TRACE_BROKER_MISSING(
|
||||
broker_, holder_.object()
|
||||
<< "has a value that might not safe to read at index "
|
||||
<< index_.as_int());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*maybe_value != *value_.object()) {
|
||||
TRACE_BROKER_MISSING(broker_, "Constant property value changed in "
|
||||
<< holder_.object()
|
||||
<< " at InternalIndex "
|
||||
<< index_.as_int());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Install(Handle<Code> code) const override {}
|
||||
|
||||
private:
|
||||
JSHeapBroker* const broker_;
|
||||
JSObjectRef const holder_;
|
||||
MapRef const map_;
|
||||
InternalIndex const index_;
|
||||
ObjectRef const value_;
|
||||
};
|
||||
|
||||
class TransitionDependency final : public CompilationDependency {
|
||||
public:
|
||||
explicit TransitionDependency(const MapRef& map) : map_(map) {
|
||||
@ -728,6 +785,12 @@ void CompilationDependencies::DependOnOwnConstantDataProperty(
|
||||
broker_, holder, map, representation, index, value));
|
||||
}
|
||||
|
||||
void CompilationDependencies::DependOnOwnConstantDictionaryProperty(
|
||||
const JSObjectRef& holder, InternalIndex index, const ObjectRef& value) {
|
||||
RecordDependency(zone_->New<OwnConstantDictionaryPropertyDependency>(
|
||||
broker_, holder, index, value));
|
||||
}
|
||||
|
||||
bool CompilationDependencies::Commit(Handle<Code> code) {
|
||||
// Dependencies are context-dependent. In the future it may be possible to
|
||||
// restore them in the consumer native context, but for now they are
|
||||
|
@ -100,14 +100,20 @@ class V8_EXPORT_PRIVATE CompilationDependencies : public ZoneObject {
|
||||
void DependOnOwnConstantElement(const JSObjectRef& holder, uint32_t index,
|
||||
const ObjectRef& element);
|
||||
|
||||
// Record the assumption that the {value} read from {holder} on the background
|
||||
// thread is the correct value for a given property.
|
||||
// Record the assumption that the {value} read from {holder} at {index} on the
|
||||
// background thread is the correct value for a given property.
|
||||
void DependOnOwnConstantDataProperty(const JSObjectRef& holder,
|
||||
const MapRef& map,
|
||||
Representation representation,
|
||||
FieldIndex index,
|
||||
const ObjectRef& value);
|
||||
|
||||
// Record the assumption that the {value} read from {holder} at {index} on the
|
||||
// background thread is the correct value for a given dictionary property.
|
||||
void DependOnOwnConstantDictionaryProperty(const JSObjectRef& holder,
|
||||
InternalIndex index,
|
||||
const ObjectRef& value);
|
||||
|
||||
// For each given map, depend on the stability of (the maps of) all prototypes
|
||||
// up to (and including) the {last_prototype}.
|
||||
template <class MapContainer>
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
#include "src/api/api-inl.h"
|
||||
#include "src/ast/modules.h"
|
||||
#include "src/base/optional.h"
|
||||
#include "src/base/platform/platform.h"
|
||||
#include "src/codegen/code-factory.h"
|
||||
#include "src/compiler/compilation-dependencies.h"
|
||||
#include "src/compiler/graph-reducer.h"
|
||||
@ -607,12 +609,18 @@ base::Optional<ObjectRef> GetOwnFastDataPropertyFromHeap(
|
||||
return MakeRef(broker, *possibly_wrapped);
|
||||
}
|
||||
|
||||
ObjectRef GetOwnDictionaryPropertyFromHeap(JSHeapBroker* broker,
|
||||
Handle<JSObject> receiver,
|
||||
InternalIndex dict_index) {
|
||||
Handle<Object> constant =
|
||||
JSObject::DictionaryPropertyAt(receiver, dict_index);
|
||||
return MakeRef(broker, constant);
|
||||
// Tries to get the property at {dict_index}. If we are within bounds of the
|
||||
// object, we are guaranteed to see valid heap words even if the data is wrong.
|
||||
base::Optional<ObjectRef> GetOwnDictionaryPropertyFromHeap(
|
||||
JSHeapBroker* broker, Handle<JSObject> receiver, InternalIndex dict_index) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
// DictionaryPropertyAt will check that we are within the bounds of the
|
||||
// object.
|
||||
base::Optional<Object> maybe_constant = JSObject::DictionaryPropertyAt(
|
||||
receiver, dict_index, broker->isolate()->heap());
|
||||
DCHECK_IMPLIES(broker->IsMainThread(), maybe_constant);
|
||||
if (!maybe_constant) return {};
|
||||
return TryMakeRef(broker, maybe_constant.value());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -674,7 +682,8 @@ ObjectData* JSObjectData::GetOwnDictionaryProperty(JSHeapBroker* broker,
|
||||
}
|
||||
|
||||
ObjectRef property = GetOwnDictionaryPropertyFromHeap(
|
||||
broker, Handle<JSObject>::cast(object()), dict_index);
|
||||
broker, Handle<JSObject>::cast(object()), dict_index)
|
||||
.value();
|
||||
ObjectData* result(property.data());
|
||||
own_properties_.insert(std::make_pair(dict_index.as_int(), result));
|
||||
return result;
|
||||
@ -4029,12 +4038,18 @@ base::Optional<ObjectRef> JSObjectRef::GetOwnFastDataProperty(
|
||||
return TryMakeRef<Object>(broker(), property);
|
||||
}
|
||||
|
||||
ObjectRef JSObjectRef::GetOwnDictionaryProperty(
|
||||
InternalIndex index, SerializationPolicy policy) const {
|
||||
base::Optional<ObjectRef> JSObjectRef::GetOwnDictionaryProperty(
|
||||
InternalIndex index, CompilationDependencies* dependencies,
|
||||
SerializationPolicy policy) const {
|
||||
CHECK(index.is_found());
|
||||
if (data_->should_access_heap()) {
|
||||
return GetOwnDictionaryPropertyFromHeap(
|
||||
broker(), Handle<JSObject>::cast(object()), index);
|
||||
if (data_->should_access_heap() || broker()->is_concurrent_inlining()) {
|
||||
base::Optional<ObjectRef> result =
|
||||
GetOwnDictionaryPropertyFromHeap(broker(), object(), index);
|
||||
if (dependencies != nullptr && result.has_value()) {
|
||||
dependencies->DependOnOwnConstantDictionaryProperty(*this, index,
|
||||
*result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
ObjectData* property =
|
||||
data()->AsJSObject()->GetOwnDictionaryProperty(broker(), index, policy);
|
||||
|
@ -354,9 +354,10 @@ class JSObjectRef : public JSReceiverRef {
|
||||
|
||||
// Return the value of the dictionary property at {index} in the dictionary
|
||||
// if {index} is known to be an own data property of the object.
|
||||
ObjectRef GetOwnDictionaryProperty(
|
||||
InternalIndex index, SerializationPolicy policy =
|
||||
SerializationPolicy::kAssumeSerialized) const;
|
||||
base::Optional<ObjectRef> GetOwnDictionaryProperty(
|
||||
InternalIndex index, CompilationDependencies* dependencies,
|
||||
SerializationPolicy policy =
|
||||
SerializationPolicy::kAssumeSerialized) const;
|
||||
|
||||
// When concurrent inlining is enabled, reads the elements through a direct
|
||||
// relaxed read. This is to ease the transition to unserialized (or
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "src/compiler/js-native-context-specialization.h"
|
||||
|
||||
#include "src/api/api-inl.h"
|
||||
#include "src/base/optional.h"
|
||||
#include "src/builtins/accessors.h"
|
||||
#include "src/codegen/code-factory.h"
|
||||
#include "src/codegen/string-constants.h"
|
||||
@ -1283,12 +1284,20 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
||||
}
|
||||
|
||||
// Generate the actual property access.
|
||||
ValueEffectControl continuation = BuildPropertyAccess(
|
||||
base::Optional<ValueEffectControl> continuation = BuildPropertyAccess(
|
||||
lookup_start_object, receiver, value, context, frame_state, effect,
|
||||
control, feedback.name(), if_exceptions, access_info, access_mode);
|
||||
value = continuation.value();
|
||||
effect = continuation.effect();
|
||||
control = continuation.control();
|
||||
if (!continuation) {
|
||||
// At this point we maybe have added nodes into the graph (e.g. via
|
||||
// NewNode or BuildCheckMaps) in some cases but we haven't connected them
|
||||
// to End since we haven't called ReplaceWithValue. Since they are nodes
|
||||
// which are not connected with End, they will be removed by graph
|
||||
// trimming.
|
||||
return NoChange();
|
||||
}
|
||||
value = continuation->value();
|
||||
effect = continuation->effect();
|
||||
control = continuation->control();
|
||||
} else {
|
||||
// The final states for every polymorphic branch. We join them with
|
||||
// Merge+Phi+EffectPhi at the bottom.
|
||||
@ -1406,13 +1415,21 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
||||
}
|
||||
|
||||
// Generate the actual property access.
|
||||
ValueEffectControl continuation = BuildPropertyAccess(
|
||||
base::Optional<ValueEffectControl> continuation = BuildPropertyAccess(
|
||||
this_lookup_start_object, this_receiver, this_value, context,
|
||||
frame_state, this_effect, this_control, feedback.name(),
|
||||
if_exceptions, access_info, access_mode);
|
||||
values.push_back(continuation.value());
|
||||
effects.push_back(continuation.effect());
|
||||
controls.push_back(continuation.control());
|
||||
if (!continuation) {
|
||||
// At this point we maybe have added nodes into the graph (e.g. via
|
||||
// NewNode or BuildCheckMaps) in some cases but we haven't connected
|
||||
// them to End since we haven't called ReplaceWithValue. Since they are
|
||||
// nodes which are not connected with End, they will be removed by graph
|
||||
// trimming.
|
||||
return NoChange();
|
||||
}
|
||||
values.push_back(continuation->value());
|
||||
effects.push_back(continuation->effect());
|
||||
controls.push_back(continuation->control());
|
||||
}
|
||||
|
||||
DCHECK_NULL(fallthrough_control);
|
||||
@ -2340,7 +2357,7 @@ Node* JSNativeContextSpecialization::InlineApiCall(
|
||||
graph()->NewNode(common()->Call(call_descriptor), index, inputs);
|
||||
}
|
||||
|
||||
JSNativeContextSpecialization::ValueEffectControl
|
||||
base::Optional<JSNativeContextSpecialization::ValueEffectControl>
|
||||
JSNativeContextSpecialization::BuildPropertyLoad(
|
||||
Node* lookup_start_object, Node* receiver, Node* context, Node* frame_state,
|
||||
Node* effect, Node* control, NameRef const& name,
|
||||
@ -2381,7 +2398,10 @@ JSNativeContextSpecialization::BuildPropertyLoad(
|
||||
access_info.IsDictionaryProtoDataConstant());
|
||||
PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
|
||||
if (access_info.IsDictionaryProtoDataConstant()) {
|
||||
value = access_builder.FoldLoadDictPrototypeConstant(access_info);
|
||||
auto maybe_value =
|
||||
access_builder.FoldLoadDictPrototypeConstant(access_info);
|
||||
if (!maybe_value) return {};
|
||||
value = maybe_value.value();
|
||||
} else {
|
||||
value = access_builder.BuildLoadDataField(
|
||||
name, access_info, lookup_start_object, &effect, &control);
|
||||
@ -2410,7 +2430,7 @@ JSNativeContextSpecialization::BuildPropertyTest(
|
||||
return ValueEffectControl(value, effect, control);
|
||||
}
|
||||
|
||||
JSNativeContextSpecialization::ValueEffectControl
|
||||
base::Optional<JSNativeContextSpecialization::ValueEffectControl>
|
||||
JSNativeContextSpecialization::BuildPropertyAccess(
|
||||
Node* lookup_start_object, Node* receiver, Node* value, Node* context,
|
||||
Node* frame_state, Node* effect, Node* control, NameRef const& name,
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define V8_COMPILER_JS_NATIVE_CONTEXT_SPECIALIZATION_H_
|
||||
|
||||
#include "src/base/flags.h"
|
||||
#include "src/base/optional.h"
|
||||
#include "src/compiler/graph-reducer.h"
|
||||
#include "src/compiler/js-heap-broker.h"
|
||||
#include "src/deoptimizer/deoptimize-reason.h"
|
||||
@ -150,18 +151,17 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
|
||||
Node* control_;
|
||||
};
|
||||
|
||||
// Construct the appropriate subgraph for property access.
|
||||
ValueEffectControl BuildPropertyAccess(
|
||||
// Construct the appropriate subgraph for property access. Return {} if the
|
||||
// property access couldn't be built.
|
||||
base::Optional<ValueEffectControl> BuildPropertyAccess(
|
||||
Node* lookup_start_object, Node* receiver, Node* value, Node* context,
|
||||
Node* frame_state, Node* effect, Node* control, NameRef const& name,
|
||||
ZoneVector<Node*>* if_exceptions, PropertyAccessInfo const& access_info,
|
||||
AccessMode access_mode);
|
||||
ValueEffectControl BuildPropertyLoad(Node* lookup_start_object,
|
||||
Node* receiver, Node* context,
|
||||
Node* frame_state, Node* effect,
|
||||
Node* control, NameRef const& name,
|
||||
ZoneVector<Node*>* if_exceptions,
|
||||
PropertyAccessInfo const& access_info);
|
||||
base::Optional<ValueEffectControl> BuildPropertyLoad(
|
||||
Node* lookup_start_object, Node* receiver, Node* context,
|
||||
Node* frame_state, Node* effect, Node* control, NameRef const& name,
|
||||
ZoneVector<Node*>* if_exceptions, PropertyAccessInfo const& access_info);
|
||||
|
||||
ValueEffectControl BuildPropertyStore(Node* receiver, Node* value,
|
||||
Node* context, Node* frame_state,
|
||||
|
@ -4,17 +4,19 @@
|
||||
|
||||
#include "src/compiler/property-access-builder.h"
|
||||
|
||||
#include "src/base/optional.h"
|
||||
#include "src/compiler/access-builder.h"
|
||||
#include "src/compiler/access-info.h"
|
||||
#include "src/compiler/compilation-dependencies.h"
|
||||
#include "src/compiler/js-graph.h"
|
||||
#include "src/compiler/node-matchers.h"
|
||||
#include "src/compiler/simplified-operator.h"
|
||||
#include "src/objects/heap-number.h"
|
||||
#include "src/objects/lookup.h"
|
||||
|
||||
#include "src/execution/isolate-inl.h"
|
||||
#include "src/objects/field-index-inl.h"
|
||||
#include "src/objects/heap-number.h"
|
||||
#include "src/objects/internal-index.h"
|
||||
#include "src/objects/lookup.h"
|
||||
#include "src/objects/property-details.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -148,15 +150,17 @@ MachineRepresentation PropertyAccessBuilder::ConvertRepresentation(
|
||||
}
|
||||
}
|
||||
|
||||
Node* PropertyAccessBuilder::FoldLoadDictPrototypeConstant(
|
||||
base::Optional<Node*> PropertyAccessBuilder::FoldLoadDictPrototypeConstant(
|
||||
PropertyAccessInfo const& access_info) {
|
||||
DCHECK(V8_DICT_PROPERTY_CONST_TRACKING_BOOL);
|
||||
DCHECK(access_info.IsDictionaryProtoDataConstant());
|
||||
|
||||
JSObjectRef holder =
|
||||
MakeRef(broker(), access_info.holder().ToHandleChecked());
|
||||
InternalIndex index = access_info.dictionary_index();
|
||||
base::Optional<ObjectRef> value =
|
||||
holder.GetOwnDictionaryProperty(access_info.dictionary_index());
|
||||
holder.GetOwnDictionaryProperty(index, dependencies());
|
||||
if (!value) return {};
|
||||
|
||||
for (Handle<Map> map : access_info.lookup_start_object_maps()) {
|
||||
// Non-JSReceivers that passed AccessInfoFactory::ComputePropertyAccessInfo
|
||||
@ -168,7 +172,7 @@ Node* PropertyAccessBuilder::FoldLoadDictPrototypeConstant(
|
||||
Map::GetConstructorFunction(
|
||||
*map, *broker()->target_native_context().object())
|
||||
.value();
|
||||
map = handle(constructor.initial_map(), isolate());
|
||||
map = MakeRef(broker(), constructor.initial_map()).object();
|
||||
DCHECK(map->IsJSObjectMap());
|
||||
}
|
||||
dependencies()->DependOnConstantInDictionaryPrototypeChain(
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "src/base/optional.h"
|
||||
#include "src/codegen/machine-type.h"
|
||||
#include "src/compiler/js-heap-broker.h"
|
||||
#include "src/compiler/node.h"
|
||||
@ -64,9 +65,11 @@ class PropertyAccessBuilder {
|
||||
Node* lookup_start_object, Node** effect,
|
||||
Node** control);
|
||||
|
||||
// Loads a constant value from a prototype object in dictionary mode and
|
||||
// constant-folds it.
|
||||
Node* FoldLoadDictPrototypeConstant(PropertyAccessInfo const& access_info);
|
||||
// Tries to load a constant value from a prototype object in dictionary mode
|
||||
// and constant-folds it. Returns {} if the constant couldn't be safely
|
||||
// retrieved.
|
||||
base::Optional<Node*> FoldLoadDictPrototypeConstant(
|
||||
PropertyAccessInfo const& access_info);
|
||||
|
||||
// Builds the load for data-field access for minimorphic loads that use
|
||||
// dynamic map checks. These cannot depend on any information from the maps.
|
||||
|
@ -3091,7 +3091,7 @@ SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess(
|
||||
access_info.field_representation(),
|
||||
access_info.field_index(), nullptr, policy)
|
||||
: holder->GetOwnDictionaryProperty(
|
||||
access_info.dictionary_index(), policy);
|
||||
access_info.dictionary_index(), nullptr, policy);
|
||||
if (constant.has_value()) {
|
||||
result_hints->AddConstant(constant->object(), zone(), broker());
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef V8_OBJECTS_DICTIONARY_INL_H_
|
||||
#define V8_OBJECTS_DICTIONARY_INL_H_
|
||||
|
||||
#include "src/base/optional.h"
|
||||
#include "src/execution/isolate-utils-inl.h"
|
||||
#include "src/numbers/hash-seed-inl.h"
|
||||
#include "src/objects/dictionary.h"
|
||||
@ -41,6 +42,24 @@ Object Dictionary<Derived, Shape>::ValueAt(PtrComprCageBase cage_base,
|
||||
Derived::kEntryValueIndex);
|
||||
}
|
||||
|
||||
template <typename Derived, typename Shape>
|
||||
base::Optional<Object> Dictionary<Derived, Shape>::TryValueAt(
|
||||
InternalIndex entry) {
|
||||
#if DEBUG
|
||||
Isolate* isolate;
|
||||
GetIsolateFromHeapObject(*this, &isolate);
|
||||
DCHECK_NE(isolate, nullptr);
|
||||
SLOW_DCHECK(!isolate->heap()->IsPendingAllocation(*this));
|
||||
#endif // DEBUG
|
||||
// We can read length() in a non-atomic way since we are reading an
|
||||
// initialized object which is not pending allocation.
|
||||
if (DerivedHashTable::EntryToIndex(entry) + Derived::kEntryValueIndex >=
|
||||
this->length()) {
|
||||
return {};
|
||||
}
|
||||
return ValueAt(entry);
|
||||
}
|
||||
|
||||
template <typename Derived, typename Shape>
|
||||
void Dictionary<Derived, Shape>::ValueAtPut(InternalIndex entry, Object value) {
|
||||
this->set(DerivedHashTable::EntryToIndex(entry) + Derived::kEntryValueIndex,
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define V8_OBJECTS_DICTIONARY_H_
|
||||
|
||||
#include "src/base/export-template.h"
|
||||
#include "src/base/optional.h"
|
||||
#include "src/common/globals.h"
|
||||
#include "src/objects/hash-table.h"
|
||||
#include "src/objects/property-array.h"
|
||||
@ -37,9 +38,10 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) Dictionary
|
||||
|
||||
public:
|
||||
using Key = typename Shape::Key;
|
||||
// Returns the value at entry.
|
||||
inline Object ValueAt(InternalIndex entry);
|
||||
inline Object ValueAt(PtrComprCageBase cage_base, InternalIndex entry);
|
||||
// Returns {} if we would be reading out of the bounds of the object.
|
||||
inline base::Optional<Object> TryValueAt(InternalIndex entry);
|
||||
|
||||
// Set the value for entry.
|
||||
inline void ValueAtPut(InternalIndex entry, Object value);
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "src/objects/js-objects.h"
|
||||
|
||||
#include "src/api/api-arguments-inl.h"
|
||||
#include "src/base/logging.h"
|
||||
#include "src/base/optional.h"
|
||||
#include "src/common/globals.h"
|
||||
#include "src/date/date.h"
|
||||
#include "src/execution/arguments.h"
|
||||
@ -27,6 +27,7 @@
|
||||
#include "src/objects/field-type.h"
|
||||
#include "src/objects/fixed-array.h"
|
||||
#include "src/objects/heap-number.h"
|
||||
#include "src/objects/heap-object.h"
|
||||
#include "src/objects/js-array-buffer-inl.h"
|
||||
#include "src/objects/js-array-inl.h"
|
||||
#include "src/objects/lookup.h"
|
||||
@ -4174,10 +4175,10 @@ Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<Object> JSObject::DictionaryPropertyAt(Handle<JSObject> object,
|
||||
Handle<Object> JSObject::DictionaryPropertyAt(Isolate* isolate,
|
||||
Handle<JSObject> object,
|
||||
InternalIndex dict_index) {
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
|
||||
DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
|
||||
if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
|
||||
SwissNameDictionary dict = object->property_dictionary_swiss();
|
||||
return handle(dict.ValueAt(dict_index), isolate);
|
||||
@ -4187,6 +4188,27 @@ Handle<Object> JSObject::DictionaryPropertyAt(Handle<JSObject> object,
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
base::Optional<Object> JSObject::DictionaryPropertyAt(Handle<JSObject> object,
|
||||
InternalIndex dict_index,
|
||||
Heap* heap) {
|
||||
Object backing_store = object->raw_properties_or_hash(kRelaxedLoad);
|
||||
if (!backing_store.IsHeapObject()) return {};
|
||||
if (heap->IsPendingAllocation(HeapObject::cast(backing_store))) return {};
|
||||
|
||||
base::Optional<Object> maybe_obj;
|
||||
if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
|
||||
if (!backing_store.IsSwissNameDictionary()) return {};
|
||||
maybe_obj = SwissNameDictionary::cast(backing_store).TryValueAt(dict_index);
|
||||
} else {
|
||||
if (!backing_store.IsNameDictionary()) return {};
|
||||
maybe_obj = NameDictionary::cast(backing_store).TryValueAt(dict_index);
|
||||
}
|
||||
|
||||
if (!maybe_obj) return {};
|
||||
return maybe_obj.value();
|
||||
}
|
||||
|
||||
// TODO(cbruni/jkummerow): Consider moving this into elements.cc.
|
||||
bool JSObject::HasEnumerableElements() {
|
||||
// TODO(cbruni): cleanup
|
||||
|
@ -642,8 +642,15 @@ class JSObject : public TorqueGeneratedJSObject<JSObject, JSReceiver> {
|
||||
const char* reason);
|
||||
|
||||
// Access property in dictionary mode object at the given dictionary index.
|
||||
static Handle<Object> DictionaryPropertyAt(Handle<JSObject> object,
|
||||
static Handle<Object> DictionaryPropertyAt(Isolate* isolate,
|
||||
Handle<JSObject> object,
|
||||
InternalIndex dict_index);
|
||||
// Same as above, but it will return {} if we would be reading out of the
|
||||
// bounds of the object or if the dictionary is pending allocation. Use this
|
||||
// version for concurrent access.
|
||||
static base::Optional<Object> DictionaryPropertyAt(Handle<JSObject> object,
|
||||
InternalIndex dict_index,
|
||||
Heap* heap);
|
||||
|
||||
// Access fast-case object properties at index.
|
||||
static Handle<Object> FastPropertyAt(Handle<JSObject> object,
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "src/base/macros.h"
|
||||
#include "src/base/optional.h"
|
||||
#include "src/execution/isolate-utils-inl.h"
|
||||
#include "src/heap/heap.h"
|
||||
#include "src/objects/fixed-array-inl.h"
|
||||
@ -304,6 +305,22 @@ Object SwissNameDictionary::ValueAt(InternalIndex entry) {
|
||||
return ValueAtRaw(entry.as_int());
|
||||
}
|
||||
|
||||
base::Optional<Object> SwissNameDictionary::TryValueAt(InternalIndex entry) {
|
||||
#if DEBUG
|
||||
Isolate* isolate;
|
||||
GetIsolateFromHeapObject(*this, &isolate);
|
||||
DCHECK_NE(isolate, nullptr);
|
||||
SLOW_DCHECK(!isolate->heap()->IsPendingAllocation(*this));
|
||||
#endif // DEBUG
|
||||
// We can read Capacity() in a non-atomic way since we are reading an
|
||||
// initialized object which is not pending allocation.
|
||||
if (static_cast<unsigned>(entry.as_int()) >=
|
||||
static_cast<unsigned>(Capacity())) {
|
||||
return {};
|
||||
}
|
||||
return ValueAtRaw(entry.as_int());
|
||||
}
|
||||
|
||||
PropertyDetails SwissNameDictionary::DetailsAt(int entry) {
|
||||
// GetCtrl(entry) does a bounds check for |entry| value.
|
||||
DCHECK(IsFull(GetCtrl(entry)));
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "src/base/export-template.h"
|
||||
#include "src/base/optional.h"
|
||||
#include "src/common/globals.h"
|
||||
#include "src/objects/fixed-array.h"
|
||||
#include "src/objects/internal-index.h"
|
||||
@ -101,6 +102,8 @@ class V8_EXPORT_PRIVATE SwissNameDictionary : public HeapObject {
|
||||
inline Object KeyAt(InternalIndex entry);
|
||||
inline Name NameAt(InternalIndex entry);
|
||||
inline Object ValueAt(InternalIndex entry);
|
||||
// Returns {} if we would be reading out of the bounds of the object.
|
||||
inline base::Optional<Object> TryValueAt(InternalIndex entry);
|
||||
inline PropertyDetails DetailsAt(InternalIndex entry);
|
||||
|
||||
inline void ValueAtPut(InternalIndex entry, Object value);
|
||||
|
Loading…
Reference in New Issue
Block a user