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") {
"src/compilation-statistics.h",
"src/compiler/access-builder.cc",
"src/compiler/access-builder.h",
"src/compiler/access-info.cc",
"src/compiler/access-info.h",
"src/compiler/all-nodes.cc",
"src/compiler/all-nodes.h",
"src/compiler/ast-graph-builder.cc",
......@@ -823,8 +825,6 @@ source_set("v8_base") {
"src/compiler/pipeline.h",
"src/compiler/pipeline-statistics.cc",
"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.h",
"src/compiler/register-allocator.cc",
......
......@@ -6,7 +6,7 @@
#include "src/accessors.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/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker!
#include "src/type-cache.h"
......@@ -16,11 +16,35 @@ namespace v8 {
namespace internal {
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) {
case PropertyAccessMode::kLoad:
case AccessMode::kLoad:
return os << "Load";
case PropertyAccessMode::kStore:
case AccessMode::kStore:
return os << "Store";
}
UNREACHABLE();
......@@ -52,6 +76,9 @@ PropertyAccessInfo PropertyAccessInfo::DataField(
}
ElementAccessInfo::ElementAccessInfo() : receiver_type_(Type::None()) {}
PropertyAccessInfo::PropertyAccessInfo()
: kind_(kInvalid), receiver_type_(Type::None()), field_type_(Type::Any()) {}
......@@ -86,9 +113,8 @@ PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder,
field_type_(field_type) {}
PropertyAccessInfoFactory::PropertyAccessInfoFactory(
CompilationDependencies* dependencies, Handle<Context> native_context,
Zone* zone)
AccessInfoFactory::AccessInfoFactory(CompilationDependencies* dependencies,
Handle<Context> native_context, Zone* zone)
: dependencies_(dependencies),
native_context_(native_context),
isolate_(native_context->GetIsolate()),
......@@ -96,23 +122,52 @@ PropertyAccessInfoFactory::PropertyAccessInfoFactory(
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): Do something about the number stuff.
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();
// TODO(bmeurer): Add support for holey elements.
ElementsKind elements_kind = map->elements_kind();
if (IsHoleyElementsKind(elements_kind)) return false;
// Certain (monomorphic) stores need a prototype chain check because shape
// changes could allow callbacks on elements in the chain that are not
// compatible with monomorphic keyed stores.
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(
Handle<Map> map, Handle<Name> name, PropertyAccessMode access_mode,
bool AccessInfoFactory::ComputePropertyAccessInfo(
Handle<Map> map, Handle<Name> name, AccessMode access_mode,
PropertyAccessInfo* access_info) {
// Check if it is safe to inline property access for the {map}.
if (!CanInlinePropertyAccess(map)) return false;
......@@ -121,7 +176,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo(
Handle<Map> receiver_map = map;
// We support fast inline cases for certain JSObject getters.
if (access_mode == PropertyAccessMode::kLoad &&
if (access_mode == AccessMode::kLoad &&
LookupSpecialFieldAccessor(map, name, access_info)) {
return true;
}
......@@ -133,7 +188,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo(
int const number = descriptors->SearchWithCache(*name, *map);
if (number != DescriptorArray::kNotFound) {
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.
if (details.IsReadOnly()) {
return false;
......@@ -170,7 +225,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo(
Type::TaggedPointer(), zone());
if (field_type->Is(Type::None())) {
// 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
// about the contents now.
......@@ -216,7 +271,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo(
// Store to property not found on the receiver or any prototype, we need
// to transition to a new data property.
// 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);
}
// The property was not found, return undefined or throw depending
......@@ -242,9 +297,8 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfo(
}
bool PropertyAccessInfoFactory::ComputePropertyAccessInfos(
MapHandleList const& maps, Handle<Name> name,
PropertyAccessMode access_mode,
bool AccessInfoFactory::ComputePropertyAccessInfos(
MapHandleList const& maps, Handle<Name> name, AccessMode access_mode,
ZoneVector<PropertyAccessInfo>* access_infos) {
for (Handle<Map> map : maps) {
if (Map::TryUpdate(map).ToHandle(&map)) {
......@@ -259,7 +313,7 @@ bool PropertyAccessInfoFactory::ComputePropertyAccessInfos(
}
bool PropertyAccessInfoFactory::LookupSpecialFieldAccessor(
bool AccessInfoFactory::LookupSpecialFieldAccessor(
Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) {
// Check for special JSObject field accessors.
int offset;
......@@ -294,9 +348,9 @@ bool PropertyAccessInfoFactory::LookupSpecialFieldAccessor(
}
bool PropertyAccessInfoFactory::LookupTransition(
Handle<Map> map, Handle<Name> name, MaybeHandle<JSObject> holder,
PropertyAccessInfo* access_info) {
bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name,
MaybeHandle<JSObject> holder,
PropertyAccessInfo* access_info) {
// Check if the {map} has a data transition with the given {name}.
if (map->unused_property_fields() == 0) return false;
Handle<Map> transition_map;
......@@ -349,9 +403,7 @@ bool PropertyAccessInfoFactory::LookupTransition(
}
Factory* PropertyAccessInfoFactory::factory() const {
return isolate()->factory();
}
Factory* AccessInfoFactory::factory() const { return isolate()->factory(); }
} // namespace compiler
} // namespace internal
......
......@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMPILER_PROPERTY_ACCESS_INFO_H_
#define V8_COMPILER_PROPERTY_ACCESS_INFO_H_
#ifndef V8_COMPILER_ACCESS_INFO_H_
#define V8_COMPILER_ACCESS_INFO_H_
#include <iosfwd>
......@@ -23,9 +23,30 @@ class TypeCache;
namespace compiler {
// 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
......@@ -78,17 +99,22 @@ class PropertyAccessInfo final {
};
// Factory class for {PropertyAccessInfo}s.
class PropertyAccessInfoFactory final {
// Factory class for {ElementAccessInfo}s and {PropertyAccessInfo}s.
class AccessInfoFactory final {
public:
PropertyAccessInfoFactory(CompilationDependencies* dependencies,
Handle<Context> native_context, Zone* zone);
AccessInfoFactory(CompilationDependencies* dependencies,
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,
PropertyAccessMode access_mode,
AccessMode access_mode,
PropertyAccessInfo* access_info);
bool ComputePropertyAccessInfos(MapHandleList const& maps, Handle<Name> name,
PropertyAccessMode access_mode,
AccessMode access_mode,
ZoneVector<PropertyAccessInfo>* access_infos);
private:
......@@ -110,11 +136,11 @@ class PropertyAccessInfoFactory final {
TypeCache const& type_cache_;
Zone* const zone_;
DISALLOW_COPY_AND_ASSIGN(PropertyAccessInfoFactory);
DISALLOW_COPY_AND_ASSIGN(AccessInfoFactory);
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_PROPERTY_ACCESS_INFO_H_
#endif // V8_COMPILER_ACCESS_INFO_H_
......@@ -6,8 +6,8 @@
#define V8_COMPILER_JS_NATIVE_CONTEXT_SPECIALIZATION_H_
#include "src/base/flags.h"
#include "src/compiler/access-info.h"
#include "src/compiler/graph-reducer.h"
#include "src/compiler/property-access-info.h"
#include "src/compiler/simplified-operator.h"
namespace v8 {
......@@ -65,13 +65,17 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
}
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,
FeedbackNexus const& nexus,
PropertyAccessMode access_mode,
AccessMode access_mode,
LanguageMode language_mode);
Reduction ReduceNamedAccess(Node* node, Node* value,
MapHandleList const& receiver_maps,
Handle<Name> name, PropertyAccessMode access_mode,
Handle<Name> name, AccessMode access_mode,
LanguageMode language_mode,
Node* index = nullptr);
......@@ -96,9 +100,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
Handle<Context> native_context() const { return native_context_; }
CompilationDependencies* dependencies() const { return dependencies_; }
Zone* zone() const { return zone_; }
PropertyAccessInfoFactory& access_info_factory() {
return access_info_factory_;
}
AccessInfoFactory& access_info_factory() { return access_info_factory_; }
JSGraph* const jsgraph_;
Flags const flags_;
......@@ -107,7 +109,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
CompilationDependencies* const dependencies_;
Zone* const zone_;
TypeCache const& type_cache_;
PropertyAccessInfoFactory access_info_factory_;
AccessInfoFactory access_info_factory_;
DISALLOW_COPY_AND_ASSIGN(JSNativeContextSpecialization);
};
......
......@@ -451,6 +451,8 @@
'../../src/compilation-statistics.h',
'../../src/compiler/access-builder.cc',
'../../src/compiler/access-builder.h',
'../../src/compiler/access-info.cc',
'../../src/compiler/access-info.h',
'../../src/compiler/all-nodes.cc',
'../../src/compiler/all-nodes.h',
'../../src/compiler/ast-graph-builder.cc',
......@@ -583,8 +585,6 @@
'../../src/compiler/pipeline.h',
'../../src/compiler/pipeline-statistics.cc',
'../../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.h',
'../../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