[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: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60828}
This commit is contained in:
Georg Neis 2019-04-12 17:51:23 +02:00 committed by Commit Bot
parent 20a93efef5
commit d7fb4a64c1
11 changed files with 260 additions and 115 deletions

View File

@ -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()) {

View File

@ -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) {

View File

@ -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 {

View File

@ -774,7 +774,7 @@ namespace {
FieldAccess ForPropertyCellValue(MachineRepresentation representation,
Type type, MaybeHandle<Map> map,
Handle<Name> name) {
NameRef const& name) {
WriteBarrierKind kind = kFullWriteBarrier;
if (representation == MachineRepresentation::kTaggedSigned) {
kind = kNoWriteBarrier;
@ -783,25 +783,25 @@ FieldAccess ForPropertyCellValue(MachineRepresentation representation,
}
MachineType r = MachineType::TypeForRepresentation(representation);
FieldAccess access = {
kTaggedBase, PropertyCell::kValueOffset, name, map, type, r, kind};
kTaggedBase, PropertyCell::kValueOffset, name.object(), map, type, r,
kind};
return access;
}
} // namespace
Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
Node* node, Node* receiver, Node* value, Handle<Name> name,
Node* node, Node* receiver, Node* value, NameRef const& name,
AccessMode access_mode, Node* key) {
NameRef name_ref(broker(), name);
base::Optional<PropertyCellRef> cell =
native_context().global_proxy_object().GetPropertyCell(name_ref);
native_context().global_proxy_object().GetPropertyCell(name);
return cell.has_value() ? ReduceGlobalAccess(node, receiver, value, name,
access_mode, key, *cell)
: NoChange();
}
Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
Node* node, Node* receiver, Node* value, Handle<Name> name,
Node* node, Node* receiver, Node* value, NameRef const& name,
AccessMode access_mode, Node* key, PropertyCellRef const& property_cell) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
@ -1024,8 +1024,9 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) {
}
CHECK(processed->IsPropertyCell());
return ReduceGlobalAccess(node, nullptr, nullptr, p.name(), AccessMode::kLoad,
nullptr, processed->property_cell());
return ReduceGlobalAccess(node, nullptr, nullptr, NameRef(broker(), p.name()),
AccessMode::kLoad, nullptr,
processed->property_cell());
}
Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
@ -1057,7 +1058,7 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
}
if (processed->IsPropertyCell()) {
return ReduceGlobalAccess(node, nullptr, value, p.name(),
return ReduceGlobalAccess(node, nullptr, value, NameRef(broker(), p.name()),
AccessMode::kStore, nullptr,
processed->property_cell());
}
@ -1066,8 +1067,8 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
}
Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* node, Node* value, MapHandles const& receiver_maps, Handle<Name> name,
AccessMode access_mode, Node* key) {
Node* node, Node* value, MapHandles const& receiver_maps,
NameRef const& name, AccessMode access_mode, Node* key) {
DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
node->opcode() == IrOpcode::kJSStoreNamed ||
node->opcode() == IrOpcode::kJSLoadProperty ||
@ -1095,7 +1096,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
graph()->zone());
ZoneVector<PropertyAccessInfo> access_infos(zone());
if (!access_info_factory.ComputePropertyAccessInfos(
receiver_maps, name, access_mode, &access_infos)) {
receiver_maps, name.object(), access_mode, &access_infos)) {
return NoChange();
}
@ -1330,7 +1331,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
}
Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
Node* node, Node* value, FeedbackNexus const& nexus, Handle<Name> name,
Node* node, Node* value, FeedbackNexus const& nexus, NameRef const& name,
AccessMode access_mode) {
DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
node->opcode() == IrOpcode::kJSStoreNamed ||
@ -1364,12 +1365,12 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
NamedAccess const& p = NamedAccessOf(node->op());
Node* const receiver = NodeProperties::GetValueInput(node, 0);
NameRef name(broker(), p.name());
// Check if we have a constant receiver.
HeapObjectMatcher m(receiver);
if (m.HasValue()) {
ObjectRef object = m.Ref(broker());
NameRef name(broker(), p.name());
if (object.IsJSFunction() &&
name.equals(ObjectRef(broker(), factory()->prototype_string()))) {
// Optimize "prototype" property of functions.
@ -1404,7 +1405,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
// Try to lower the named access based on the {receiver_maps}.
return ReduceNamedAccessFromNexus(node, jsgraph()->Dead(), nexus, p.name(),
return ReduceNamedAccessFromNexus(node, jsgraph()->Dead(), nexus, name,
AccessMode::kLoad);
}
@ -1418,8 +1419,8 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
// Try to lower the named access based on the {receiver_maps}.
return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
AccessMode::kStore);
return ReduceNamedAccessFromNexus(
node, value, nexus, NameRef(broker(), p.name()), AccessMode::kStore);
}
Reduction JSNativeContextSpecialization::ReduceJSStoreNamedOwn(Node* node) {
@ -1432,7 +1433,8 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreNamedOwn(Node* node) {
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
// Try to lower the creation of a named property based on the {receiver_maps}.
return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
return ReduceNamedAccessFromNexus(node, value, nexus,
NameRef(broker(), p.name()),
AccessMode::kStoreInLiteral);
}
@ -1714,7 +1716,7 @@ Reduction JSNativeContextSpecialization::ReduceKeyedLoadFromHeapConstant(
Node* control = NodeProperties::GetControlInput(node);
HeapObjectMatcher mreceiver(receiver);
HeapObjectRef receiver_ref = mreceiver.Ref(broker()).AsHeapObject();
HeapObjectRef receiver_ref = mreceiver.Ref(broker());
if (receiver_ref.map().oddball_type() == OddballType::kHole ||
receiver_ref.map().oddball_type() == OddballType::kNull ||
receiver_ref.map().oddball_type() == OddballType::kUndefined ||
@ -1821,8 +1823,9 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
// Check if we have feedback for a named access.
base::Optional<NameRef> name = GetNameFeedback(broker(), nexus);
if (name.has_value()) {
return ReduceNamedAccess(node, value, receiver_maps, name->object(),
access_mode, key);
DCHECK_EQ(nexus.GetKeyType(), PROPERTY);
return ReduceNamedAccess(node, value, receiver_maps, *name, access_mode,
key);
}
// Try to lower element access based on the {receiver_maps}.
@ -2026,24 +2029,23 @@ Node* JSNativeContextSpecialization::InlinePropertyGetterCall(
PropertyAccessInfo const& access_info) {
Node* target = jsgraph()->Constant(access_info.constant());
FrameStateInfo const& frame_info = FrameStateInfoOf(frame_state->op());
Handle<SharedFunctionInfo> shared_info =
frame_info.shared_info().ToHandleChecked();
// Introduce the call to the getter function.
Node* value;
if (access_info.constant()->IsJSFunction()) {
ObjectRef constant(broker(), access_info.constant());
if (constant.IsJSFunction()) {
value = *effect = *control = graph()->NewNode(
jsgraph()->javascript()->Call(2, CallFrequency(), VectorSlotPair(),
ConvertReceiverMode::kNotNullOrUndefined),
target, receiver, context, frame_state, *effect, *control);
} else {
DCHECK(access_info.constant()->IsFunctionTemplateInfo());
Handle<FunctionTemplateInfo> function_template_info(
Handle<FunctionTemplateInfo>::cast(access_info.constant()));
DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
auto function_template_info = constant.AsFunctionTemplateInfo();
function_template_info.Serialize();
Node* holder =
access_info.holder().is_null()
? receiver
: jsgraph()->Constant(access_info.holder().ToHandleChecked());
SharedFunctionInfoRef shared_info(
broker(), frame_info.shared_info().ToHandleChecked());
value = InlineApiCall(receiver, holder, frame_state, nullptr, effect,
control, shared_info, function_template_info);
}
@ -2065,23 +2067,22 @@ void JSNativeContextSpecialization::InlinePropertySetterCall(
PropertyAccessInfo const& access_info) {
Node* target = jsgraph()->Constant(access_info.constant());
FrameStateInfo const& frame_info = FrameStateInfoOf(frame_state->op());
Handle<SharedFunctionInfo> shared_info =
frame_info.shared_info().ToHandleChecked();
// Introduce the call to the setter function.
if (access_info.constant()->IsJSFunction()) {
ObjectRef constant(broker(), access_info.constant());
if (constant.IsJSFunction()) {
*effect = *control = graph()->NewNode(
jsgraph()->javascript()->Call(3, CallFrequency(), VectorSlotPair(),
ConvertReceiverMode::kNotNullOrUndefined),
target, receiver, value, context, frame_state, *effect, *control);
} else {
DCHECK(access_info.constant()->IsFunctionTemplateInfo());
Handle<FunctionTemplateInfo> function_template_info(
Handle<FunctionTemplateInfo>::cast(access_info.constant()));
DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
auto function_template_info = constant.AsFunctionTemplateInfo();
function_template_info.Serialize();
Node* holder =
access_info.holder().is_null()
? receiver
: jsgraph()->Constant(access_info.holder().ToHandleChecked());
SharedFunctionInfoRef shared_info(
broker(), frame_info.shared_info().ToHandleChecked());
InlineApiCall(receiver, holder, frame_state, value, effect, control,
shared_info, function_template_info);
}
@ -2098,11 +2099,10 @@ void JSNativeContextSpecialization::InlinePropertySetterCall(
Node* JSNativeContextSpecialization::InlineApiCall(
Node* receiver, Node* holder, Node* frame_state, Node* value, Node** effect,
Node** control, Handle<SharedFunctionInfo> shared_info,
Handle<FunctionTemplateInfo> function_template_info) {
Handle<CallHandlerInfo> call_handler_info = handle(
CallHandlerInfo::cast(function_template_info->call_code()), isolate());
Handle<Object> call_data_object(call_handler_info->data(), isolate());
Node** control, SharedFunctionInfoRef const& shared_info,
FunctionTemplateInfoRef const& function_template_info) {
auto call_handler_info =
function_template_info.call_code().AsCallHandlerInfo();
// Only setters have a value.
int const argc = value == nullptr ? 0 : 1;
@ -2116,8 +2116,8 @@ Node* JSNativeContextSpecialization::InlineApiCall(
1 /* implicit receiver */,
CallDescriptor::kNeedsFrameState);
Node* data = jsgraph()->Constant(call_data_object);
ApiFunction function(v8::ToCData<Address>(call_handler_info->callback()));
Node* data = jsgraph()->Constant(call_handler_info.data());
ApiFunction function(call_handler_info.callback());
Node* function_reference =
graph()->NewNode(common()->ExternalConstant(ExternalReference::Create(
&function, ExternalReference::DIRECT_API_CALL)));
@ -2146,11 +2146,10 @@ Node* JSNativeContextSpecialization::InlineApiCall(
JSNativeContextSpecialization::ValueEffectControl
JSNativeContextSpecialization::BuildPropertyLoad(
Node* receiver, Node* context, Node* frame_state, Node* effect,
Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions,
Node* control, NameRef const& name, ZoneVector<Node*>* if_exceptions,
PropertyAccessInfo const& access_info) {
// Determine actual holder and perform prototype chain checks.
Handle<JSObject> holder;
PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
if (access_info.holder().ToHandle(&holder)) {
dependencies()->DependOnStablePrototypeChains(
access_info.receiver_maps(), kStartAtPrototype,
@ -2176,6 +2175,7 @@ JSNativeContextSpecialization::BuildPropertyLoad(
value = graph()->NewNode(simplified()->StringLength(), receiver);
} else {
DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
value = access_builder.BuildLoadDataField(name, access_info, receiver,
&effect, &control);
}
@ -2196,14 +2196,13 @@ JSNativeContextSpecialization::BuildPropertyTest(
Node* value = access_info.IsNotFound() ? jsgraph()->FalseConstant()
: jsgraph()->TrueConstant();
return ValueEffectControl(value, effect, control);
}
JSNativeContextSpecialization::ValueEffectControl
JSNativeContextSpecialization::BuildPropertyAccess(
Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect,
Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions,
Node* control, NameRef const& name, ZoneVector<Node*>* if_exceptions,
PropertyAccessInfo const& access_info, AccessMode access_mode) {
switch (access_mode) {
case AccessMode::kLoad:
@ -2223,7 +2222,7 @@ JSNativeContextSpecialization::BuildPropertyAccess(
JSNativeContextSpecialization::ValueEffectControl
JSNativeContextSpecialization::BuildPropertyStore(
Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect,
Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions,
Node* control, NameRef const& name, ZoneVector<Node*>* if_exceptions,
PropertyAccessInfo const& access_info, AccessMode access_mode) {
// Determine actual holder and perform prototype chain checks.
Handle<JSObject> holder;
@ -2265,7 +2264,7 @@ JSNativeContextSpecialization::BuildPropertyStore(
FieldAccess field_access = {
kTaggedBase,
field_index.offset(),
name,
name.object(),
MaybeHandle<Map>(),
field_type,
MachineType::TypeForRepresentation(field_representation),
@ -2298,13 +2297,11 @@ JSNativeContextSpecialization::BuildPropertyStore(
field_access.write_barrier_kind = kPointerWriteBarrier;
} else {
// We just store directly to the MutableHeapNumber.
FieldAccess const storage_access = {kTaggedBase,
field_index.offset(),
name,
MaybeHandle<Map>(),
Type::OtherInternal(),
MachineType::TaggedPointer(),
kPointerWriteBarrier};
FieldAccess const storage_access = {
kTaggedBase, field_index.offset(),
name.object(), MaybeHandle<Map>(),
Type::OtherInternal(), MachineType::TaggedPointer(),
kPointerWriteBarrier};
storage = effect =
graph()->NewNode(simplified()->LoadField(storage_access),
storage, effect, control);
@ -2393,14 +2390,15 @@ JSNativeContextSpecialization::BuildPropertyStore(
if (access_info.transition_map().ToHandle(&transition_map)) {
// Check if we need to grow the properties backing store
// with this transitioning store.
Handle<Map> original_map(Map::cast(transition_map->GetBackPointer()),
isolate());
if (original_map->UnusedPropertyFields() == 0) {
MapRef transition_map_ref(broker(), transition_map);
transition_map_ref.SerializeBackPointer();
MapRef original_map = transition_map_ref.GetBackPointer().AsMap();
if (original_map.UnusedPropertyFields() == 0) {
DCHECK(!field_index.is_inobject());
// Reallocate the properties {storage}.
storage = effect = BuildExtendPropertiesBackingStore(
MapRef(broker(), original_map), storage, effect, control);
original_map, storage, effect, control);
// Perform the actual store.
effect = graph()->NewNode(simplified()->StoreField(field_access),
@ -2459,15 +2457,16 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
if (!Map::TryUpdate(isolate(), receiver_map).ToHandle(&receiver_map))
return NoChange();
Handle<Name> cached_name(
Name::cast(nexus.GetFeedbackExtra()->GetHeapObjectAssumeStrong()),
isolate());
NameRef cached_name(
broker(),
handle(Name::cast(nexus.GetFeedbackExtra()->GetHeapObjectAssumeStrong()),
isolate()));
PropertyAccessInfo access_info;
AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone());
if (!access_info_factory.ComputePropertyAccessInfo(
receiver_map, cached_name, AccessMode::kStoreInLiteral,
receiver_map, cached_name.object(), AccessMode::kStoreInLiteral,
&access_info)) {
return NoChange();
}
@ -2485,7 +2484,7 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
// Ensure that {name} matches the cached name.
Node* name = NodeProperties::GetValueInput(node, 1);
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), name,
jsgraph()->HeapConstant(cached_name));
jsgraph()->Constant(cached_name));
effect = graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongName),
check, effect, control);
@ -3249,15 +3248,15 @@ Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore(
return a.Finish();
}
Node* JSNativeContextSpecialization::BuildCheckEqualsName(Handle<Name> name,
Node* JSNativeContextSpecialization::BuildCheckEqualsName(NameRef const& name,
Node* value,
Node* effect,
Node* control) {
DCHECK(name->IsUniqueName());
DCHECK(name.IsUniqueName());
Operator const* const op =
name->IsSymbol() ? simplified()->CheckEqualsSymbol()
: simplified()->CheckEqualsInternalizedString();
return graph()->NewNode(op, jsgraph()->HeapConstant(name), value, effect,
name.IsSymbol() ? simplified()->CheckEqualsSymbol()
: simplified()->CheckEqualsInternalizedString();
return graph()->NewNode(op, jsgraph()->Constant(name), value, effect,
control);
}

View File

@ -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

View File

@ -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());
}
};

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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();
}

View File

@ -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);