Commit 225cb9fa authored by jarin's avatar jarin Committed by Commit bot

[turbofan] Introduce map-guarded generic handler for named store.

This helps if the polymorhpic case has other maps with fast accesses.

In box2d (with high number of iterations and warm-up), we spend about 2.7% of running time in StoreIC; after this change it is only 0.2%.

Review-Url: https://codereview.chromium.org/2494673002
Cr-Commit-Position: refs/heads/master@{#40957}
parent 08f09ed7
...@@ -94,6 +94,12 @@ PropertyAccessInfo PropertyAccessInfo::AccessorConstant( ...@@ -94,6 +94,12 @@ PropertyAccessInfo PropertyAccessInfo::AccessorConstant(
return PropertyAccessInfo(kAccessorConstant, holder, constant, receiver_maps); return PropertyAccessInfo(kAccessorConstant, holder, constant, receiver_maps);
} }
// static
PropertyAccessInfo PropertyAccessInfo::Generic(MapList const& receiver_maps) {
return PropertyAccessInfo(kGeneric, MaybeHandle<JSObject>(), Handle<Object>(),
receiver_maps);
}
PropertyAccessInfo::PropertyAccessInfo() PropertyAccessInfo::PropertyAccessInfo()
: kind_(kInvalid), : kind_(kInvalid),
field_representation_(MachineRepresentation::kNone), field_representation_(MachineRepresentation::kNone),
...@@ -167,6 +173,12 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that) { ...@@ -167,6 +173,12 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that) {
} }
return false; return false;
} }
case kGeneric: {
this->receiver_maps_.insert(this->receiver_maps_.end(),
that->receiver_maps_.begin(),
that->receiver_maps_.end());
return true;
}
} }
UNREACHABLE(); UNREACHABLE();
...@@ -478,7 +490,10 @@ bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name, ...@@ -478,7 +490,10 @@ bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name,
MaybeHandle<JSObject> holder, MaybeHandle<JSObject> holder,
PropertyAccessInfo* access_info) { PropertyAccessInfo* access_info) {
// Check if the {map} has a data transition with the given {name}. // Check if the {map} has a data transition with the given {name}.
if (map->unused_property_fields() == 0) return false; if (map->unused_property_fields() == 0) {
*access_info = PropertyAccessInfo::Generic(MapList{map});
return true;
}
Handle<Map> transition_map; Handle<Map> transition_map;
if (TransitionArray::SearchTransition(map, kData, name, NONE) if (TransitionArray::SearchTransition(map, kData, name, NONE)
.ToHandle(&transition_map)) { .ToHandle(&transition_map)) {
......
...@@ -61,7 +61,8 @@ class PropertyAccessInfo final { ...@@ -61,7 +61,8 @@ class PropertyAccessInfo final {
kNotFound, kNotFound,
kDataConstant, kDataConstant,
kDataField, kDataField,
kAccessorConstant kAccessorConstant,
kGeneric
}; };
static PropertyAccessInfo NotFound(MapList const& receiver_maps, static PropertyAccessInfo NotFound(MapList const& receiver_maps,
...@@ -78,6 +79,7 @@ class PropertyAccessInfo final { ...@@ -78,6 +79,7 @@ class PropertyAccessInfo final {
static PropertyAccessInfo AccessorConstant(MapList const& receiver_maps, static PropertyAccessInfo AccessorConstant(MapList const& receiver_maps,
Handle<Object> constant, Handle<Object> constant,
MaybeHandle<JSObject> holder); MaybeHandle<JSObject> holder);
static PropertyAccessInfo Generic(MapList const& receiver_maps);
PropertyAccessInfo(); PropertyAccessInfo();
...@@ -87,6 +89,7 @@ class PropertyAccessInfo final { ...@@ -87,6 +89,7 @@ class PropertyAccessInfo final {
bool IsDataConstant() const { return kind() == kDataConstant; } bool IsDataConstant() const { return kind() == kDataConstant; }
bool IsDataField() const { return kind() == kDataField; } bool IsDataField() const { return kind() == kDataField; }
bool IsAccessorConstant() const { return kind() == kAccessorConstant; } bool IsAccessorConstant() const { return kind() == kAccessorConstant; }
bool IsGeneric() const { return kind() == kGeneric; }
bool HasTransitionMap() const { return !transition_map().is_null(); } bool HasTransitionMap() const { return !transition_map().is_null(); }
......
...@@ -102,7 +102,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadContext(Node* node) { ...@@ -102,7 +102,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadContext(Node* node) {
Reduction JSNativeContextSpecialization::ReduceNamedAccess( Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* node, Node* value, MapHandleList const& receiver_maps, Node* node, Node* value, MapHandleList const& receiver_maps,
Handle<Name> name, AccessMode access_mode, LanguageMode language_mode, Handle<Name> name, AccessMode access_mode, LanguageMode language_mode,
Node* index) { Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot, Node* index) {
DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
node->opcode() == IrOpcode::kJSStoreNamed || node->opcode() == IrOpcode::kJSStoreNamed ||
node->opcode() == IrOpcode::kJSLoadProperty || node->opcode() == IrOpcode::kJSLoadProperty ||
...@@ -127,10 +127,20 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( ...@@ -127,10 +127,20 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
} }
// TODO(turbofan): Add support for inlining into try blocks. // TODO(turbofan): Add support for inlining into try blocks.
if (NodeProperties::IsExceptionalCall(node) || bool is_exceptional = NodeProperties::IsExceptionalCall(node);
!(flags() & kAccessorInliningEnabled)) {
for (auto access_info : access_infos) { for (auto access_info : access_infos) {
if (access_info.IsAccessorConstant()) return NoChange(); if (access_info.IsAccessorConstant()) {
// Accessor in try-blocks are not supported yet.
if (is_exceptional || !(flags() & kAccessorInliningEnabled)) {
return NoChange();
}
} else if (access_info.IsGeneric()) {
// We do not handle generic calls in try blocks.
if (is_exceptional) return NoChange();
// We only handle the generic store IC case.
if (vector->GetKind(slot) != FeedbackVectorSlotKind::STORE_IC) {
return NoChange();
}
} }
} }
...@@ -168,9 +178,9 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( ...@@ -168,9 +178,9 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
} }
// Generate the actual property access. // Generate the actual property access.
ValueEffectControl continuation = ValueEffectControl continuation = BuildPropertyAccess(
BuildPropertyAccess(receiver, value, context, frame_state_lazy, effect, receiver, value, context, frame_state_lazy, effect, control, name,
control, name, access_info, access_mode); access_info, access_mode, language_mode, vector, slot);
value = continuation.value(); value = continuation.value();
effect = continuation.effect(); effect = continuation.effect();
control = continuation.control(); control = continuation.control();
...@@ -282,7 +292,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( ...@@ -282,7 +292,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
// Generate the actual property access. // Generate the actual property access.
ValueEffectControl continuation = BuildPropertyAccess( ValueEffectControl continuation = BuildPropertyAccess(
this_receiver, this_value, context, frame_state_lazy, this_effect, this_receiver, this_value, context, frame_state_lazy, this_effect,
this_control, name, access_info, access_mode); this_control, name, access_info, access_mode, language_mode, vector,
slot);
values.push_back(continuation.value()); values.push_back(continuation.value());
effects.push_back(continuation.effect()); effects.push_back(continuation.effect());
controls.push_back(continuation.control()); controls.push_back(continuation.control());
...@@ -349,7 +360,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus( ...@@ -349,7 +360,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
// Try to lower the named access based on the {receiver_maps}. // Try to lower the named access based on the {receiver_maps}.
return ReduceNamedAccess(node, value, receiver_maps, name, access_mode, return ReduceNamedAccess(node, value, receiver_maps, name, access_mode,
language_mode); language_mode, nexus.vector_handle(), nexus.slot());
} }
...@@ -758,16 +769,17 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess( ...@@ -758,16 +769,17 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
} else { } else {
name = factory()->InternalizeName(name); name = factory()->InternalizeName(name);
return ReduceNamedAccess(node, value, receiver_maps, name, access_mode, return ReduceNamedAccess(node, value, receiver_maps, name, access_mode,
language_mode); language_mode, nexus.vector_handle(),
nexus.slot());
} }
} }
} }
// Check if we have feedback for a named access. // Check if we have feedback for a named access.
if (Name* name = nexus.FindFirstName()) { if (Name* name = nexus.FindFirstName()) {
return ReduceNamedAccess(node, value, receiver_maps, return ReduceNamedAccess(
handle(name, isolate()), access_mode, node, value, receiver_maps, handle(name, isolate()), access_mode,
language_mode, index); language_mode, nexus.vector_handle(), nexus.slot(), index);
} else if (nexus.GetKeyType() != ELEMENT) { } else if (nexus.GetKeyType() != ELEMENT) {
// The KeyedLoad/StoreIC has seen non-element accesses, so we cannot assume // The KeyedLoad/StoreIC has seen non-element accesses, so we cannot assume
// that the {index} is a valid array index, thus we just let the IC continue // that the {index} is a valid array index, thus we just let the IC continue
...@@ -841,7 +853,8 @@ JSNativeContextSpecialization::ValueEffectControl ...@@ -841,7 +853,8 @@ JSNativeContextSpecialization::ValueEffectControl
JSNativeContextSpecialization::BuildPropertyAccess( JSNativeContextSpecialization::BuildPropertyAccess(
Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect, Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect,
Node* control, Handle<Name> name, PropertyAccessInfo const& access_info, Node* control, Handle<Name> name, PropertyAccessInfo const& access_info,
AccessMode access_mode) { AccessMode access_mode, LanguageMode language_mode,
Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot) {
// Determine actual holder and perform prototype chain checks. // Determine actual holder and perform prototype chain checks.
Handle<JSObject> holder; Handle<JSObject> holder;
if (access_info.holder().ToHandle(&holder)) { if (access_info.holder().ToHandle(&holder)) {
...@@ -943,8 +956,7 @@ JSNativeContextSpecialization::BuildPropertyAccess( ...@@ -943,8 +956,7 @@ JSNativeContextSpecialization::BuildPropertyAccess(
break; break;
} }
} }
} else { } else if (access_info.IsDataField()) {
DCHECK(access_info.IsDataField());
FieldIndex const field_index = access_info.field_index(); FieldIndex const field_index = access_info.field_index();
Type* const field_type = access_info.field_type(); Type* const field_type = access_info.field_type();
MachineRepresentation const field_representation = MachineRepresentation const field_representation =
...@@ -1096,6 +1108,28 @@ JSNativeContextSpecialization::BuildPropertyAccess( ...@@ -1096,6 +1108,28 @@ JSNativeContextSpecialization::BuildPropertyAccess(
jsgraph()->UndefinedConstant(), effect); jsgraph()->UndefinedConstant(), effect);
} }
} }
} else {
DCHECK(access_info.IsGeneric());
DCHECK_EQ(AccessMode::kStore, access_mode);
DCHECK_EQ(FeedbackVectorSlotKind::STORE_IC, vector->GetKind(slot));
Callable callable =
CodeFactory::StoreICInOptimizedCode(isolate(), language_mode);
const CallInterfaceDescriptor& descriptor = callable.descriptor();
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), descriptor,
descriptor.GetStackParameterCount(), CallDescriptor::kNeedsFrameState,
Operator::kNoProperties);
Node* stub_code = jsgraph()->HeapConstant(callable.code());
Node* name_node = jsgraph()->HeapConstant(name);
Node* slot_node = jsgraph()->Constant(vector->GetIndex(slot));
Node* vector_node = jsgraph()->HeapConstant(vector);
Node* inputs[] = {stub_code, receiver, name_node, value, slot_node,
vector_node, context, frame_state, effect, control};
value = effect = control =
graph()->NewNode(common()->Call(desc), arraysize(inputs), inputs);
control = graph()->NewNode(common()->IfSuccess(), control);
} }
return ValueEffectControl(value, effect, control); return ValueEffectControl(value, effect, control);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/base/flags.h" #include "src/base/flags.h"
#include "src/compiler/graph-reducer.h" #include "src/compiler/graph-reducer.h"
#include "src/deoptimize-reason.h" #include "src/deoptimize-reason.h"
#include "src/type-feedback-vector.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -15,7 +16,6 @@ namespace internal { ...@@ -15,7 +16,6 @@ namespace internal {
// Forward declarations. // Forward declarations.
class CompilationDependencies; class CompilationDependencies;
class Factory; class Factory;
class FeedbackNexus;
namespace compiler { namespace compiler {
...@@ -78,7 +78,8 @@ class JSNativeContextSpecialization final : public AdvancedReducer { ...@@ -78,7 +78,8 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
MapHandleList const& receiver_maps, MapHandleList const& receiver_maps,
Handle<Name> name, AccessMode access_mode, Handle<Name> name, AccessMode access_mode,
LanguageMode language_mode, LanguageMode language_mode,
Node* index = nullptr); Handle<TypeFeedbackVector> vector,
FeedbackVectorSlot slot, Node* index = nullptr);
Reduction ReduceSoftDeoptimize(Node* node, DeoptimizeReason reason); Reduction ReduceSoftDeoptimize(Node* node, DeoptimizeReason reason);
...@@ -99,12 +100,12 @@ class JSNativeContextSpecialization final : public AdvancedReducer { ...@@ -99,12 +100,12 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
}; };
// Construct the appropriate subgraph for property access. // Construct the appropriate subgraph for property access.
ValueEffectControl BuildPropertyAccess(Node* receiver, Node* value, ValueEffectControl BuildPropertyAccess(
Node* context, Node* frame_state, Node* receiver, Node* value, Node* context, Node* frame_state,
Node* effect, Node* control, Node* effect, Node* control, Handle<Name> name,
Handle<Name> name, PropertyAccessInfo const& access_info, AccessMode access_mode,
PropertyAccessInfo const& access_info, LanguageMode language_mode, Handle<TypeFeedbackVector> vector,
AccessMode access_mode); FeedbackVectorSlot slot);
// Construct the appropriate subgraph for element access. // Construct the appropriate subgraph for element access.
ValueEffectControl BuildElementAccess(Node* receiver, Node* index, ValueEffectControl BuildElementAccess(Node* receiver, Node* index,
......
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