Commit d7fb4a64 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[turbofan] Basic brokerization for ReduceNamedAccess

Bug: v8:7790
Change-Id: I65e050929a45c3391c5c9c9b0d814ae536664cf4
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1564067
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60828}
parent 20a93efe
......@@ -3787,7 +3787,7 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
// Try to specialize JSConstruct {node}s with constant {target}s.
HeapObjectMatcher m(target);
if (m.HasValue()) {
HeapObjectRef target_ref = m.Ref(broker()).AsHeapObject();
HeapObjectRef target_ref = m.Ref(broker());
// Raise a TypeError if the {target} is not a constructor.
if (!target_ref.map().is_constructor()) {
......
......@@ -8,6 +8,7 @@
#include <algorithm>
#endif
#include "src/api-inl.h"
#include "src/ast/modules.h"
#include "src/bootstrapper.h"
#include "src/boxed-float.h"
......@@ -16,6 +17,7 @@
#include "src/compiler/per-isolate-compiler-cache.h"
#include "src/objects-inl.h"
#include "src/objects/allocation-site-inl.h"
#include "src/objects/api-callbacks.h"
#include "src/objects/cell-inl.h"
#include "src/objects/heap-number-inl.h"
#include "src/objects/instance-type-inl.h"
......@@ -23,6 +25,7 @@
#include "src/objects/js-array-inl.h"
#include "src/objects/js-regexp-inl.h"
#include "src/objects/module-inl.h"
#include "src/objects/templates.h"
#include "src/utils.h"
#include "src/vector-slot-pair.h"
......@@ -108,7 +111,7 @@ class PropertyCellData : public HeapObjectData {
PropertyDetails property_details() const { return property_details_; }
void Serialize(JSHeapBroker* broker);
ObjectData* value() { return value_; }
ObjectData* value() const { return value_; }
private:
PropertyDetails const property_details_;
......@@ -117,6 +120,47 @@ class PropertyCellData : public HeapObjectData {
ObjectData* value_ = nullptr;
};
class FunctionTemplateInfoData : public HeapObjectData {
public:
FunctionTemplateInfoData(JSHeapBroker* broker, ObjectData** storage,
Handle<FunctionTemplateInfo> object);
void Serialize(JSHeapBroker* broker);
ObjectData* call_code() const { return call_code_; }
private:
bool serialized_ = false;
ObjectData* call_code_ = nullptr;
};
class CallHandlerInfoData : public HeapObjectData {
public:
CallHandlerInfoData(JSHeapBroker* broker, ObjectData** storage,
Handle<CallHandlerInfo> object);
Address callback() const { return callback_; }
void Serialize(JSHeapBroker* broker);
ObjectData* data() const { return data_; }
private:
Address const callback_;
bool serialized_ = false;
ObjectData* data_ = nullptr;
};
FunctionTemplateInfoData::FunctionTemplateInfoData(
JSHeapBroker* broker, ObjectData** storage,
Handle<FunctionTemplateInfo> object)
: HeapObjectData(broker, storage, object) {}
CallHandlerInfoData::CallHandlerInfoData(JSHeapBroker* broker,
ObjectData** storage,
Handle<CallHandlerInfo> object)
: HeapObjectData(broker, storage, object),
callback_(v8::ToCData<Address>(object->callback())) {}
void JSHeapBroker::IncrementTracingIndentation() { ++trace_indentation_; }
void JSHeapBroker::DecrementTracingIndentation() { --trace_indentation_; }
......@@ -156,6 +200,30 @@ void PropertyCellData::Serialize(JSHeapBroker* broker) {
value_ = broker->GetOrCreateData(cell->value());
}
void FunctionTemplateInfoData::Serialize(JSHeapBroker* broker) {
if (serialized_) return;
serialized_ = true;
TraceScope tracer(broker, this, "FunctionTemplateInfoData::Serialize");
auto function_template_info = Handle<FunctionTemplateInfo>::cast(object());
DCHECK_NULL(call_code_);
call_code_ = broker->GetOrCreateData(function_template_info->call_code());
if (call_code_->IsCallHandlerInfo()) {
call_code_->AsCallHandlerInfo()->Serialize(broker);
}
}
void CallHandlerInfoData::Serialize(JSHeapBroker* broker) {
if (serialized_) return;
serialized_ = true;
TraceScope tracer(broker, this, "CallHandlerInfoData::Serialize");
auto call_handler_info = Handle<CallHandlerInfo>::cast(object());
DCHECK_NULL(data_);
data_ = broker->GetOrCreateData(call_handler_info->data());
}
class JSObjectField {
public:
bool IsDouble() const { return object_ == nullptr; }
......@@ -799,6 +867,12 @@ class MapData : public HeapObjectData {
return constructor_;
}
void SerializeBackPointer(JSHeapBroker* broker);
HeapObjectData* GetBackPointer() const {
CHECK(serialized_backpointer_);
return backpointer_;
}
void SerializePrototype(JSHeapBroker* broker);
bool serialized_prototype() const { return serialized_prototype_; }
ObjectData* prototype() const {
......@@ -836,6 +910,9 @@ class MapData : public HeapObjectData {
bool serialized_constructor_ = false;
ObjectData* constructor_ = nullptr;
bool serialized_backpointer_ = false;
HeapObjectData* backpointer_ = nullptr;
bool serialized_prototype_ = false;
ObjectData* prototype_ = nullptr;
......@@ -1554,6 +1631,16 @@ void MapData::SerializeConstructor(JSHeapBroker* broker) {
constructor_ = broker->GetOrCreateData(map->GetConstructor());
}
void MapData::SerializeBackPointer(JSHeapBroker* broker) {
if (serialized_backpointer_) return;
serialized_backpointer_ = true;
TraceScope tracer(broker, this, "MapData::SerializeBackPointer");
Handle<Map> map = Handle<Map>::cast(object());
DCHECK_NULL(backpointer_);
backpointer_ = broker->GetOrCreateData(map->GetBackPointer())->AsHeapObject();
}
void MapData::SerializePrototype(JSHeapBroker* broker) {
if (serialized_prototype_) return;
serialized_prototype_ = true;
......@@ -2541,6 +2628,7 @@ BIMODAL_ACCESSOR_C(Map, int, UnusedPropertyFields)
BIMODAL_ACCESSOR(Map, HeapObject, prototype)
BIMODAL_ACCESSOR_C(Map, InstanceType, instance_type)
BIMODAL_ACCESSOR(Map, Object, GetConstructor)
BIMODAL_ACCESSOR(Map, HeapObject, GetBackPointer)
#define DEF_NATIVE_CONTEXT_ACCESSOR(type, name) \
BIMODAL_ACCESSOR(NativeContext, type, name)
......@@ -2550,6 +2638,10 @@ BROKER_NATIVE_CONTEXT_FIELDS(DEF_NATIVE_CONTEXT_ACCESSOR)
BIMODAL_ACCESSOR(PropertyCell, Object, value)
BIMODAL_ACCESSOR_C(PropertyCell, PropertyDetails, property_details)
BIMODAL_ACCESSOR(FunctionTemplateInfo, Object, call_code)
BIMODAL_ACCESSOR(CallHandlerInfo, Object, data)
BIMODAL_ACCESSOR_C(SharedFunctionInfo, int, builtin_id)
BIMODAL_ACCESSOR(SharedFunctionInfo, BytecodeArray, GetBytecodeArray)
#define DEF_SFI_ACCESSOR(type, name) \
......@@ -2615,6 +2707,13 @@ bool StringRef::IsExternalString() const {
return data()->AsString()->is_external_string();
}
Address CallHandlerInfoRef::callback() const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
return v8::ToCData<Address>(object()->callback());
}
return HeapObjectRef::data()->AsCallHandlerInfo()->callback();
}
bool StringRef::IsSeqString() const {
IF_BROKER_DISABLED_ACCESS_HANDLE_C(String, IsSeqString);
return data()->AsString()->is_seq_string();
......@@ -2888,6 +2987,11 @@ void FeedbackVectorRef::SerializeSlots() {
data()->AsFeedbackVector()->SerializeSlots(broker());
}
bool NameRef::IsUniqueName() const {
// Must match Name::IsUniqueName.
return IsInternalizedString() || IsSymbol();
}
ObjectRef JSRegExpRef::data() const {
IF_BROKER_DISABLED_ACCESS_HANDLE(JSRegExp, Object, data);
return ObjectRef(broker(), ObjectRef::data()->AsJSRegExp()->data());
......@@ -3027,6 +3131,12 @@ void MapRef::SerializeOwnDescriptors() {
data()->AsMap()->SerializeOwnDescriptors(broker());
}
void MapRef::SerializeBackPointer() {
if (broker()->mode() == JSHeapBroker::kDisabled) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
data()->AsMap()->SerializeBackPointer(broker());
}
void MapRef::SerializePrototype() {
if (broker()->mode() == JSHeapBroker::kDisabled) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
......@@ -3085,6 +3195,12 @@ void PropertyCellRef::Serialize() {
data()->AsPropertyCell()->Serialize(broker());
}
void FunctionTemplateInfoRef::Serialize() {
if (broker()->mode() == JSHeapBroker::kDisabled) return;
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
data()->AsFunctionTemplateInfo()->Serialize(broker());
}
base::Optional<PropertyCellRef> JSGlobalProxyRef::GetPropertyCell(
NameRef const& name, bool serialize) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
......
......@@ -21,8 +21,9 @@ namespace v8 {
namespace internal {
class BytecodeArray;
class VectorSlotPair;
class CallHandlerInfo;
class FixedDoubleArray;
class FunctionTemplateInfo;
class HeapNumber;
class InternalizedString;
class JSBoundFunction;
......@@ -32,6 +33,7 @@ class JSRegExp;
class JSTypedArray;
class NativeContext;
class ScriptContextTable;
class VectorSlotPair;
namespace compiler {
......@@ -72,11 +74,13 @@ enum class OddballType : uint8_t {
V(Symbol) \
/* Subtypes of HeapObject */ \
V(AllocationSite) \
V(CallHandlerInfo) \
V(Cell) \
V(Code) \
V(DescriptorArray) \
V(FeedbackVector) \
V(FixedArrayBase) \
V(FunctionTemplateInfo) \
V(HeapNumber) \
V(JSObject) \
V(Map) \
......@@ -377,6 +381,8 @@ class NameRef : public HeapObjectRef {
public:
using HeapObjectRef::HeapObjectRef;
Handle<Name> object() const;
bool IsUniqueName() const;
};
class ScriptContextTableRef : public HeapObjectRef {
......@@ -409,6 +415,26 @@ class FeedbackVectorRef : public HeapObjectRef {
void SerializeSlots();
};
class FunctionTemplateInfoRef : public HeapObjectRef {
public:
using HeapObjectRef::HeapObjectRef;
Handle<FunctionTemplateInfo> object() const;
void Serialize();
ObjectRef call_code() const;
};
class CallHandlerInfoRef : public HeapObjectRef {
public:
using HeapObjectRef::HeapObjectRef;
Handle<CallHandlerInfo> object() const;
Address callback() const;
void Serialize();
ObjectRef data() const;
};
class AllocationSiteRef : public HeapObjectRef {
public:
using HeapObjectRef::HeapObjectRef;
......@@ -467,13 +493,14 @@ class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef {
bool supports_fast_array_resize() const;
bool IsMapOfCurrentGlobalProxy() const;
OddballType oddball_type() const;
#define DEF_TESTER(Type, ...) bool Is##Type##Map() const;
INSTANCE_TYPE_CHECKERS(DEF_TESTER)
#undef DEF_TESTER
ObjectRef GetConstructor() const;
OddballType oddball_type() const;
base::Optional<MapRef> AsElementsKind(ElementsKind kind) const;
void SerializeBackPointer();
HeapObjectRef GetBackPointer() const;
void SerializePrototype();
bool serialized_prototype() const;
......@@ -493,6 +520,11 @@ class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef {
FieldIndex GetFieldIndexFor(int descriptor_index) const;
ObjectRef GetFieldType(int descriptor_index) const;
bool IsUnboxedDoubleField(int descriptor_index) const;
// Available after calling JSFunctionRef::Serialize on a function that has
// this map as initial map.
ObjectRef GetConstructor() const;
base::Optional<MapRef> AsElementsKind(ElementsKind kind) const;
};
class FixedArrayBaseRef : public HeapObjectRef {
......
......@@ -105,17 +105,17 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
KeyedAccessStoreMode store_mode);
Reduction ReduceNamedAccessFromNexus(Node* node, Node* value,
FeedbackNexus const& nexus,
Handle<Name> name,
NameRef const& name,
AccessMode access_mode);
Reduction ReduceNamedAccess(Node* node, Node* value,
MapHandles const& receiver_maps,
Handle<Name> name, AccessMode access_mode,
NameRef const& name, AccessMode access_mode,
Node* key = nullptr);
Reduction ReduceGlobalAccess(Node* node, Node* receiver, Node* value,
Handle<Name> name, AccessMode access_mode,
NameRef const& name, AccessMode access_mode,
Node* key = nullptr);
Reduction ReduceGlobalAccess(Node* node, Node* receiver, Node* value,
Handle<Name> name, AccessMode access_mode,
NameRef const& name, AccessMode access_mode,
Node* key, PropertyCellRef const& property_cell);
Reduction ReduceKeyedLoadFromHeapConstant(Node* node, Node* key,
FeedbackNexus const& nexus,
......@@ -154,20 +154,20 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
ValueEffectControl BuildPropertyAccess(Node* receiver, Node* value,
Node* context, Node* frame_state,
Node* effect, Node* control,
Handle<Name> name,
NameRef const& name,
ZoneVector<Node*>* if_exceptions,
PropertyAccessInfo const& access_info,
AccessMode access_mode);
ValueEffectControl BuildPropertyLoad(Node* receiver, Node* context,
Node* frame_state, Node* effect,
Node* control, Handle<Name> name,
Node* control, NameRef const& name,
ZoneVector<Node*>* if_exceptions,
PropertyAccessInfo const& access_info);
ValueEffectControl BuildPropertyStore(Node* receiver, Node* value,
Node* context, Node* frame_state,
Node* effect, Node* control,
Handle<Name> name,
NameRef const& name,
ZoneVector<Node*>* if_exceptions,
PropertyAccessInfo const& access_info,
AccessMode access_mode);
......@@ -188,8 +188,8 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
PropertyAccessInfo const& access_info);
Node* InlineApiCall(Node* receiver, Node* holder, Node* frame_state,
Node* value, Node** effect, Node** control,
Handle<SharedFunctionInfo> shared_info,
Handle<FunctionTemplateInfo> function_template_info);
SharedFunctionInfoRef const& shared_info,
FunctionTemplateInfoRef const& function_template_info);
// Construct the appropriate subgraph for element access.
ValueEffectControl BuildElementAccess(
......@@ -208,7 +208,7 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
// Construct appropriate subgraph to check that the {value} matches
// the previously recorded {name} feedback.
Node* BuildCheckEqualsName(Handle<Name> name, Node* value, Node* effect,
Node* BuildCheckEqualsName(NameRef const& name, Node* value, Node* effect,
Node* control);
// Checks if we can turn the hole into undefined when loading an element
......
......@@ -196,8 +196,8 @@ struct HeapObjectMatcher final
return this->HasValue() && this->Value().address() == value.address();
}
ObjectRef Ref(JSHeapBroker* broker) const {
return ObjectRef(broker, this->Value());
HeapObjectRef Ref(JSHeapBroker* broker) const {
return HeapObjectRef(broker, this->Value());
}
};
......
......@@ -391,7 +391,7 @@ NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMaps(
ZoneHandleSet<Map>* maps_return) {
HeapObjectMatcher m(receiver);
if (m.HasValue()) {
HeapObjectRef receiver = m.Ref(broker).AsHeapObject();
HeapObjectRef receiver = m.Ref(broker);
// We don't use ICs for the Array.prototype and the Object.prototype
// because the runtime has to be able to intercept them properly, so
// we better make sure that TurboFan doesn't outsmart the system here
......@@ -575,8 +575,7 @@ bool NodeProperties::CanBePrimitive(JSHeapBroker* broker, Node* receiver,
case IrOpcode::kJSToObject:
return false;
case IrOpcode::kHeapConstant: {
HeapObjectRef value =
HeapObjectMatcher(receiver).Ref(broker).AsHeapObject();
HeapObjectRef value = HeapObjectMatcher(receiver).Ref(broker);
return value.map().IsPrimitiveMap();
}
default: {
......@@ -617,8 +616,7 @@ bool NodeProperties::CanBeNullOrUndefined(JSHeapBroker* broker, Node* receiver,
case IrOpcode::kToBoolean:
return false;
case IrOpcode::kHeapConstant: {
HeapObjectRef value =
HeapObjectMatcher(receiver).Ref(broker).AsHeapObject();
HeapObjectRef value = HeapObjectMatcher(receiver).Ref(broker);
OddballType type = value.map().oddball_type();
return type == OddballType::kNull || type == OddballType::kUndefined;
}
......
......@@ -148,7 +148,7 @@ void PropertyAccessBuilder::BuildCheckMaps(Node* receiver, Node** effect,
MapHandles const& receiver_maps) {
HeapObjectMatcher m(receiver);
if (m.HasValue()) {
MapRef receiver_map = m.Ref(broker()).AsHeapObject().map();
MapRef receiver_map = m.Ref(broker()).map();
if (receiver_map.is_stable()) {
for (Handle<Map> map : receiver_maps) {
if (MapRef(broker(), map).equals(receiver_map)) {
......@@ -195,7 +195,8 @@ Node* PropertyAccessBuilder::ResolveHolder(
}
Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
Handle<Name> name, PropertyAccessInfo const& access_info, Node* receiver) {
NameRef const& name, PropertyAccessInfo const& access_info,
Node* receiver) {
// Optimize immutable property loads.
// First, determine if we have a constant holder to load from.
......@@ -204,14 +205,14 @@ Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
if (!access_info.holder().ToHandle(&holder)) {
// Otherwise, try to match the {receiver} as a constant.
HeapObjectMatcher m(receiver);
if (!m.HasValue() || !m.Value()->IsJSObject()) return nullptr;
if (!m.HasValue() || !m.Ref(broker()).IsJSObject()) return nullptr;
// Let us make sure the actual map of the constant receiver is among
// the maps in {access_info}.
Handle<Map> receiver_map = handle(m.Value()->map(), isolate());
MapRef receiver_map = m.Ref(broker()).map();
if (std::find_if(access_info.receiver_maps().begin(),
access_info.receiver_maps().end(), [&](Handle<Map> map) {
return map.address() == receiver_map.address();
return map.address() == receiver_map.object().address();
}) == access_info.receiver_maps().end()) {
// The map of the receiver is not in the feedback, let us bail out.
return nullptr;
......@@ -229,7 +230,7 @@ Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
// TODO(turbofan): Given that we already have the field_index here, we
// might be smarter in the future and not rely on the LookupIterator.
LookupIterator it(isolate(), holder, name,
LookupIterator it(isolate(), holder, name.object(),
LookupIterator::OWN_SKIP_INTERCEPTOR);
if (it.state() == LookupIterator::DATA) {
bool is_readonly_non_configurable = it.IsReadOnly() && !it.IsConfigurable();
......@@ -257,7 +258,7 @@ Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
}
Node* PropertyAccessBuilder::BuildLoadDataField(
Handle<Name> name, PropertyAccessInfo const& access_info, Node* receiver,
NameRef const& name, PropertyAccessInfo const& access_info, Node* receiver,
Node** effect, Node** control) {
DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
if (Node* value =
......@@ -278,7 +279,7 @@ Node* PropertyAccessBuilder::BuildLoadDataField(
FieldAccess field_access = {
kTaggedBase,
field_index.offset(),
name,
name.object(),
MaybeHandle<Map>(),
field_type,
MachineType::TypeForRepresentation(field_representation),
......@@ -287,14 +288,11 @@ Node* PropertyAccessBuilder::BuildLoadDataField(
if (field_representation == MachineRepresentation::kFloat64) {
if (!field_index.is_inobject() || field_index.is_hidden_field() ||
!FLAG_unbox_double_fields) {
FieldAccess const storage_access = {kTaggedBase,
field_index.offset(),
name,
MaybeHandle<Map>(),
Type::OtherInternal(),
MachineType::TaggedPointer(),
kPointerWriteBarrier,
LoadSensitivity::kCritical};
FieldAccess const storage_access = {
kTaggedBase, field_index.offset(),
name.object(), MaybeHandle<Map>(),
Type::OtherInternal(), MachineType::TaggedPointer(),
kPointerWriteBarrier, LoadSensitivity::kCritical};
storage = *effect = graph()->NewNode(
simplified()->LoadField(storage_access), storage, *effect, *control);
field_access.offset = HeapNumber::kValueOffset;
......@@ -305,8 +303,9 @@ Node* PropertyAccessBuilder::BuildLoadDataField(
// used by the LoadElimination to eliminate map checks on the result.
Handle<Map> field_map;
if (access_info.field_map().ToHandle(&field_map)) {
if (field_map->is_stable()) {
dependencies()->DependOnStableMap(MapRef(broker(), field_map));
MapRef field_map_ref(broker(), field_map);
if (field_map_ref.is_stable()) {
dependencies()->DependOnStableMap(field_map_ref);
field_access.map = field_map;
}
}
......
......@@ -7,6 +7,7 @@
#include <vector>
#include "src/compiler/js-heap-broker.h"
#include "src/handles.h"
#include "src/objects/map.h"
#include "src/zone/zone-containers.h"
......@@ -46,7 +47,7 @@ class PropertyAccessBuilder {
// Builds the actual load for data-field and data-constant-field
// properties (without heap-object or map checks).
Node* BuildLoadDataField(Handle<Name> name,
Node* BuildLoadDataField(NameRef const& name,
PropertyAccessInfo const& access_info,
Node* receiver, Node** effect, Node** control);
......@@ -59,7 +60,7 @@ class PropertyAccessBuilder {
CommonOperatorBuilder* common() const;
SimplifiedOperatorBuilder* simplified() const;
Node* TryBuildLoadConstantDataField(Handle<Name> name,
Node* TryBuildLoadConstantDataField(NameRef const& name,
PropertyAccessInfo const& access_info,
Node* receiver);
// Returns a node with the holder for the property access described by
......
......@@ -684,10 +684,10 @@ void Map::AppendDescriptor(Isolate* isolate, Descriptor* desc) {
#endif
}
Object Map::GetBackPointer() const {
HeapObject Map::GetBackPointer() const {
Object object = constructor_or_backpointer();
if (object->IsMap()) {
return object;
return Map::cast(object);
}
return GetReadOnlyRoots().undefined_value();
}
......
......@@ -576,7 +576,7 @@ class Map : public HeapObject {
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
// [back pointer]: points back to the parent map from which a transition
// leads to this map. The field overlaps with the constructor (see above).
inline Object GetBackPointer() const;
inline HeapObject GetBackPointer() const;
inline void SetBackPointer(Object value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment