Commit 1195b0e2 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Initial support for keyed access to fast JSArrays.

This adds some initial support for keyed element access to fast,
non-holey JSArray objects.

Also renames PropertyAccessInfoFactory to AccessInfoFactory and
PropertyAccessMode to AccessMode.

R=jarin@chromium.org
BUG=v8:4470
LOG=n

Review URL: https://codereview.chromium.org/1418213010

Cr-Commit-Position: refs/heads/master@{#31717}
parent 0fa11bfb
...@@ -692,6 +692,8 @@ source_set("v8_base") { ...@@ -692,6 +692,8 @@ source_set("v8_base") {
"src/compilation-statistics.h", "src/compilation-statistics.h",
"src/compiler/access-builder.cc", "src/compiler/access-builder.cc",
"src/compiler/access-builder.h", "src/compiler/access-builder.h",
"src/compiler/access-info.cc",
"src/compiler/access-info.h",
"src/compiler/all-nodes.cc", "src/compiler/all-nodes.cc",
"src/compiler/all-nodes.h", "src/compiler/all-nodes.h",
"src/compiler/ast-graph-builder.cc", "src/compiler/ast-graph-builder.cc",
...@@ -823,8 +825,6 @@ source_set("v8_base") { ...@@ -823,8 +825,6 @@ source_set("v8_base") {
"src/compiler/pipeline.h", "src/compiler/pipeline.h",
"src/compiler/pipeline-statistics.cc", "src/compiler/pipeline-statistics.cc",
"src/compiler/pipeline-statistics.h", "src/compiler/pipeline-statistics.h",
"src/compiler/property-access-info.cc",
"src/compiler/property-access-info.h",
"src/compiler/raw-machine-assembler.cc", "src/compiler/raw-machine-assembler.cc",
"src/compiler/raw-machine-assembler.h", "src/compiler/raw-machine-assembler.h",
"src/compiler/register-allocator.cc", "src/compiler/register-allocator.cc",
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#include "src/accessors.h" #include "src/accessors.h"
#include "src/compilation-dependencies.h" #include "src/compilation-dependencies.h"
#include "src/compiler/property-access-info.h" #include "src/compiler/access-info.h"
#include "src/field-index-inl.h" #include "src/field-index-inl.h"
#include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker! #include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker!
#include "src/type-cache.h" #include "src/type-cache.h"
...@@ -16,11 +16,35 @@ namespace v8 { ...@@ -16,11 +16,35 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
std::ostream& operator<<(std::ostream& os, PropertyAccessMode access_mode) { namespace {
bool CanInlineElementAccess(Handle<Map> map) {
// TODO(bmeurer): IsJSObjectMap
// TODO(bmeurer): !map->has_dictionary_elements()
// TODO(bmeurer): !map->has_sloppy_arguments_elements()
return map->IsJSArrayMap() && map->has_fast_elements() &&
!map->has_indexed_interceptor() && !map->is_access_check_needed();
}
bool CanInlinePropertyAccess(Handle<Map> map) {
// TODO(bmeurer): Add support for Number primitives.
// if (map->instance_type() == HEAP_NUMBER_TYPE) return false;
if (map->instance_type() < FIRST_NONSTRING_TYPE) return true;
return map->IsJSObjectMap() && !map->is_dictionary_map() &&
!map->has_named_interceptor() &&
// TODO(verwaest): Whitelist contexts to which we have access.
!map->is_access_check_needed();
}
} // namespace
std::ostream& operator<<(std::ostream& os, AccessMode access_mode) {
switch (access_mode) { switch (access_mode) {
case PropertyAccessMode::kLoad: case AccessMode::kLoad:
return os << "Load"; return os << "Load";
case PropertyAccessMode::kStore: case AccessMode::kStore:
return os << "Store"; return os << "Store";
} }
UNREACHABLE(); UNREACHABLE();
...@@ -52,6 +76,9 @@ PropertyAccessInfo PropertyAccessInfo::DataField( ...@@ -52,6 +76,9 @@ PropertyAccessInfo PropertyAccessInfo::DataField(
} }
ElementAccessInfo::ElementAccessInfo() : receiver_type_(Type::None()) {}
PropertyAccessInfo::PropertyAccessInfo() PropertyAccessInfo::PropertyAccessInfo()
: kind_(kInvalid), receiver_type_(Type::None()), field_type_(Type::Any()) {} : kind_(kInvalid), receiver_type_(Type::None()), field_type_(Type::Any()) {}
...@@ -86,9 +113,8 @@ PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder, ...@@ -86,9 +113,8 @@ PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder,
field_type_(field_type) {} field_type_(field_type) {}
PropertyAccessInfoFactory::PropertyAccessInfoFactory( AccessInfoFactory::AccessInfoFactory(CompilationDependencies* dependencies,
CompilationDependencies* dependencies, Handle<Context> native_context, Handle<Context> native_context, Zone* zone)
Zone* zone)
: dependencies_(dependencies), : dependencies_(dependencies),
native_context_(native_context), native_context_(native_context),
isolate_(native_context->GetIsolate()), isolate_(native_context->GetIsolate()),
...@@ -96,23 +122,52 @@ PropertyAccessInfoFactory::PropertyAccessInfoFactory( ...@@ -96,23 +122,52 @@ PropertyAccessInfoFactory::PropertyAccessInfoFactory(
zone_(zone) {} zone_(zone) {}
namespace { bool AccessInfoFactory::ComputeElementAccessInfo(
Handle<Map> map, AccessMode access_mode, ElementAccessInfo* access_info) {
// Check if it is safe to inline element access for the {map}.
if (!CanInlineElementAccess(map)) return false;
bool CanInlinePropertyAccess(Handle<Map> map) { // TODO(bmeurer): Add support for holey elements.
// TODO(bmeurer): Do something about the number stuff. ElementsKind elements_kind = map->elements_kind();
if (map->instance_type() == HEAP_NUMBER_TYPE) return false; if (IsHoleyElementsKind(elements_kind)) return false;
if (map->instance_type() < FIRST_NONSTRING_TYPE) return true;
return map->IsJSObjectMap() && !map->is_dictionary_map() && // Certain (monomorphic) stores need a prototype chain check because shape
!map->has_named_interceptor() && // changes could allow callbacks on elements in the chain that are not
// TODO(verwaest): Whitelist contexts to which we have access. // compatible with monomorphic keyed stores.
!map->is_access_check_needed(); MaybeHandle<JSObject> holder;
if (access_mode == AccessMode::kStore && map->prototype()->IsJSObject()) {
for (PrototypeIterator i(map); !i.IsAtEnd(); i.Advance()) {
Handle<JSReceiver> prototype =
PrototypeIterator::GetCurrent<JSReceiver>(i);
if (!prototype->IsJSObject()) return false;
holder = Handle<JSObject>::cast(prototype);
}
}
*access_info =
ElementAccessInfo(Type::Class(map, zone()), elements_kind, holder);
return true;
} }
} // namespace
bool AccessInfoFactory::ComputeElementAccessInfos(
MapHandleList const& maps, AccessMode access_mode,
ZoneVector<ElementAccessInfo>* access_infos) {
for (Handle<Map> map : maps) {
if (Map::TryUpdate(map).ToHandle(&map)) {
ElementAccessInfo access_info;
if (!ComputeElementAccessInfo(map, access_mode, &access_info)) {
return false;
}
access_infos->push_back(access_info);
}
}
return true;
}
bool PropertyAccessInfoFactory::ComputePropertyAccessInfo( bool AccessInfoFactory::ComputePropertyAccessInfo(
Handle<Map> map, Handle<Name> name, PropertyAccessMode access_mode, Handle<Map> map, Handle<Name> name, AccessMode access_mode,
PropertyAccessInfo* access_info) { PropertyAccessInfo* access_info) {
// Check if it is safe to inline property access for the {map}. // Check if it is safe to inline property access for the {map}.
if (!CanInlinePropertyAccess(map)) return false; if (!CanInlinePropertyAccess(map)) return false;
...@@ -121,7 +176,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo( ...@@ -121,7 +176,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo(
Handle<Map> receiver_map = map; Handle<Map> receiver_map = map;
// We support fast inline cases for certain JSObject getters. // We support fast inline cases for certain JSObject getters.
if (access_mode == PropertyAccessMode::kLoad && if (access_mode == AccessMode::kLoad &&
LookupSpecialFieldAccessor(map, name, access_info)) { LookupSpecialFieldAccessor(map, name, access_info)) {
return true; return true;
} }
...@@ -133,7 +188,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo( ...@@ -133,7 +188,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo(
int const number = descriptors->SearchWithCache(*name, *map); int const number = descriptors->SearchWithCache(*name, *map);
if (number != DescriptorArray::kNotFound) { if (number != DescriptorArray::kNotFound) {
PropertyDetails const details = descriptors->GetDetails(number); PropertyDetails const details = descriptors->GetDetails(number);
if (access_mode == PropertyAccessMode::kStore) { if (access_mode == AccessMode::kStore) {
// Don't bother optimizing stores to read-only properties. // Don't bother optimizing stores to read-only properties.
if (details.IsReadOnly()) { if (details.IsReadOnly()) {
return false; return false;
...@@ -170,7 +225,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo( ...@@ -170,7 +225,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo(
Type::TaggedPointer(), zone()); Type::TaggedPointer(), zone());
if (field_type->Is(Type::None())) { if (field_type->Is(Type::None())) {
// Store is not safe if the field type was cleared. // Store is not safe if the field type was cleared.
if (access_mode == PropertyAccessMode::kStore) return false; if (access_mode == AccessMode::kStore) return false;
// The field type was cleared by the GC, so we don't know anything // The field type was cleared by the GC, so we don't know anything
// about the contents now. // about the contents now.
...@@ -216,7 +271,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo( ...@@ -216,7 +271,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo(
// Store to property not found on the receiver or any prototype, we need // Store to property not found on the receiver or any prototype, we need
// to transition to a new data property. // to transition to a new data property.
// Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver) // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
if (access_mode == PropertyAccessMode::kStore) { if (access_mode == AccessMode::kStore) {
return LookupTransition(receiver_map, name, holder, access_info); return LookupTransition(receiver_map, name, holder, access_info);
} }
// The property was not found, return undefined or throw depending // The property was not found, return undefined or throw depending
...@@ -242,9 +297,8 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo( ...@@ -242,9 +297,8 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo(
} }
bool PropertyAccessInfoFactory::ComputePropertyAccessInfos( bool AccessInfoFactory::ComputePropertyAccessInfos(
MapHandleList const& maps, Handle<Name> name, MapHandleList const& maps, Handle<Name> name, AccessMode access_mode,
PropertyAccessMode access_mode,
ZoneVector<PropertyAccessInfo>* access_infos) { ZoneVector<PropertyAccessInfo>* access_infos) {
for (Handle<Map> map : maps) { for (Handle<Map> map : maps) {
if (Map::TryUpdate(map).ToHandle(&map)) { if (Map::TryUpdate(map).ToHandle(&map)) {
...@@ -259,7 +313,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfos( ...@@ -259,7 +313,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfos(
} }
bool PropertyAccessInfoFactory::LookupSpecialFieldAccessor( bool AccessInfoFactory::LookupSpecialFieldAccessor(
Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) { Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) {
// Check for special JSObject field accessors. // Check for special JSObject field accessors.
int offset; int offset;
...@@ -294,9 +348,9 @@ bool PropertyAccessInfoFactory::LookupSpecialFieldAccessor( ...@@ -294,9 +348,9 @@ bool PropertyAccessInfoFactory::LookupSpecialFieldAccessor(
} }
bool PropertyAccessInfoFactory::LookupTransition( bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name,
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) return false;
Handle<Map> transition_map; Handle<Map> transition_map;
...@@ -349,9 +403,7 @@ bool PropertyAccessInfoFactory::LookupTransition( ...@@ -349,9 +403,7 @@ bool PropertyAccessInfoFactory::LookupTransition(
} }
Factory* PropertyAccessInfoFactory::factory() const { Factory* AccessInfoFactory::factory() const { return isolate()->factory(); }
return isolate()->factory();
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef V8_COMPILER_PROPERTY_ACCESS_INFO_H_ #ifndef V8_COMPILER_ACCESS_INFO_H_
#define V8_COMPILER_PROPERTY_ACCESS_INFO_H_ #define V8_COMPILER_ACCESS_INFO_H_
#include <iosfwd> #include <iosfwd>
...@@ -23,9 +23,30 @@ class TypeCache; ...@@ -23,9 +23,30 @@ class TypeCache;
namespace compiler { namespace compiler {
// Whether we are loading a property or storing to a property. // Whether we are loading a property or storing to a property.
enum class PropertyAccessMode { kLoad, kStore }; enum class AccessMode { kLoad, kStore };
std::ostream& operator<<(std::ostream&, PropertyAccessMode); std::ostream& operator<<(std::ostream&, AccessMode);
// This class encapsulates all information required to access a certain element.
class ElementAccessInfo final {
public:
ElementAccessInfo();
ElementAccessInfo(Type* receiver_type, ElementsKind elements_kind,
MaybeHandle<JSObject> holder)
: elements_kind_(elements_kind),
holder_(holder),
receiver_type_(receiver_type) {}
MaybeHandle<JSObject> holder() const { return holder_; }
ElementsKind elements_kind() const { return elements_kind_; }
Type* receiver_type() const { return receiver_type_; }
private:
ElementsKind elements_kind_;
MaybeHandle<JSObject> holder_;
Type* receiver_type_;
};
// This class encapsulates all information required to access a certain // This class encapsulates all information required to access a certain
...@@ -78,17 +99,22 @@ class PropertyAccessInfo final { ...@@ -78,17 +99,22 @@ class PropertyAccessInfo final {
}; };
// Factory class for {PropertyAccessInfo}s. // Factory class for {ElementAccessInfo}s and {PropertyAccessInfo}s.
class PropertyAccessInfoFactory final { class AccessInfoFactory final {
public: public:
PropertyAccessInfoFactory(CompilationDependencies* dependencies, AccessInfoFactory(CompilationDependencies* dependencies,
Handle<Context> native_context, Zone* zone); Handle<Context> native_context, Zone* zone);
bool ComputeElementAccessInfo(Handle<Map> map, AccessMode access_mode,
ElementAccessInfo* access_info);
bool ComputeElementAccessInfos(MapHandleList const& maps,
AccessMode access_mode,
ZoneVector<ElementAccessInfo>* access_infos);
bool ComputePropertyAccessInfo(Handle<Map> map, Handle<Name> name, bool ComputePropertyAccessInfo(Handle<Map> map, Handle<Name> name,
PropertyAccessMode access_mode, AccessMode access_mode,
PropertyAccessInfo* access_info); PropertyAccessInfo* access_info);
bool ComputePropertyAccessInfos(MapHandleList const& maps, Handle<Name> name, bool ComputePropertyAccessInfos(MapHandleList const& maps, Handle<Name> name,
PropertyAccessMode access_mode, AccessMode access_mode,
ZoneVector<PropertyAccessInfo>* access_infos); ZoneVector<PropertyAccessInfo>* access_infos);
private: private:
...@@ -110,11 +136,11 @@ class PropertyAccessInfoFactory final { ...@@ -110,11 +136,11 @@ class PropertyAccessInfoFactory final {
TypeCache const& type_cache_; TypeCache const& type_cache_;
Zone* const zone_; Zone* const zone_;
DISALLOW_COPY_AND_ASSIGN(PropertyAccessInfoFactory); DISALLOW_COPY_AND_ASSIGN(AccessInfoFactory);
}; };
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
#endif // V8_COMPILER_PROPERTY_ACCESS_INFO_H_ #endif // V8_COMPILER_ACCESS_INFO_H_
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
#define V8_COMPILER_JS_NATIVE_CONTEXT_SPECIALIZATION_H_ #define V8_COMPILER_JS_NATIVE_CONTEXT_SPECIALIZATION_H_
#include "src/base/flags.h" #include "src/base/flags.h"
#include "src/compiler/access-info.h"
#include "src/compiler/graph-reducer.h" #include "src/compiler/graph-reducer.h"
#include "src/compiler/property-access-info.h"
#include "src/compiler/simplified-operator.h" #include "src/compiler/simplified-operator.h"
namespace v8 { namespace v8 {
...@@ -65,13 +65,17 @@ class JSNativeContextSpecialization final : public AdvancedReducer { ...@@ -65,13 +65,17 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
} }
Reduction Replace(Node* node, Handle<Object> value); Reduction Replace(Node* node, Handle<Object> value);
Reduction ReduceElementAccess(Node* node, Node* index, Node* value,
MapHandleList const& receiver_maps,
AccessMode access_mode,
LanguageMode language_mode);
Reduction ReduceKeyedAccess(Node* node, Node* index, Node* value, Reduction ReduceKeyedAccess(Node* node, Node* index, Node* value,
FeedbackNexus const& nexus, FeedbackNexus const& nexus,
PropertyAccessMode access_mode, AccessMode access_mode,
LanguageMode language_mode); LanguageMode language_mode);
Reduction ReduceNamedAccess(Node* node, Node* value, Reduction ReduceNamedAccess(Node* node, Node* value,
MapHandleList const& receiver_maps, MapHandleList const& receiver_maps,
Handle<Name> name, PropertyAccessMode access_mode, Handle<Name> name, AccessMode access_mode,
LanguageMode language_mode, LanguageMode language_mode,
Node* index = nullptr); Node* index = nullptr);
...@@ -96,9 +100,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer { ...@@ -96,9 +100,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
Handle<Context> native_context() const { return native_context_; } Handle<Context> native_context() const { return native_context_; }
CompilationDependencies* dependencies() const { return dependencies_; } CompilationDependencies* dependencies() const { return dependencies_; }
Zone* zone() const { return zone_; } Zone* zone() const { return zone_; }
PropertyAccessInfoFactory& access_info_factory() { AccessInfoFactory& access_info_factory() { return access_info_factory_; }
return access_info_factory_;
}
JSGraph* const jsgraph_; JSGraph* const jsgraph_;
Flags const flags_; Flags const flags_;
...@@ -107,7 +109,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer { ...@@ -107,7 +109,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
CompilationDependencies* const dependencies_; CompilationDependencies* const dependencies_;
Zone* const zone_; Zone* const zone_;
TypeCache const& type_cache_; TypeCache const& type_cache_;
PropertyAccessInfoFactory access_info_factory_; AccessInfoFactory access_info_factory_;
DISALLOW_COPY_AND_ASSIGN(JSNativeContextSpecialization); DISALLOW_COPY_AND_ASSIGN(JSNativeContextSpecialization);
}; };
......
...@@ -451,6 +451,8 @@ ...@@ -451,6 +451,8 @@
'../../src/compilation-statistics.h', '../../src/compilation-statistics.h',
'../../src/compiler/access-builder.cc', '../../src/compiler/access-builder.cc',
'../../src/compiler/access-builder.h', '../../src/compiler/access-builder.h',
'../../src/compiler/access-info.cc',
'../../src/compiler/access-info.h',
'../../src/compiler/all-nodes.cc', '../../src/compiler/all-nodes.cc',
'../../src/compiler/all-nodes.h', '../../src/compiler/all-nodes.h',
'../../src/compiler/ast-graph-builder.cc', '../../src/compiler/ast-graph-builder.cc',
...@@ -583,8 +585,6 @@ ...@@ -583,8 +585,6 @@
'../../src/compiler/pipeline.h', '../../src/compiler/pipeline.h',
'../../src/compiler/pipeline-statistics.cc', '../../src/compiler/pipeline-statistics.cc',
'../../src/compiler/pipeline-statistics.h', '../../src/compiler/pipeline-statistics.h',
'../../src/compiler/property-access-info.cc',
'../../src/compiler/property-access-info.h',
'../../src/compiler/raw-machine-assembler.cc', '../../src/compiler/raw-machine-assembler.cc',
'../../src/compiler/raw-machine-assembler.h', '../../src/compiler/raw-machine-assembler.h',
'../../src/compiler/register-allocator.cc', '../../src/compiler/register-allocator.cc',
......
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