LCOV - code coverage report
Current view: top level - src/compiler - access-info.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 200 223 89.7 %
Date: 2017-04-26 Functions: 12 23 52.2 %

          Line data    Source code
       1             : // Copyright 2015 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include <ostream>
       6             : 
       7             : #include "src/accessors.h"
       8             : #include "src/compilation-dependencies.h"
       9             : #include "src/compiler/access-info.h"
      10             : #include "src/compiler/type-cache.h"
      11             : #include "src/field-index-inl.h"
      12             : #include "src/field-type.h"
      13             : #include "src/ic/call-optimization.h"
      14             : #include "src/objects-inl.h"
      15             : 
      16             : namespace v8 {
      17             : namespace internal {
      18             : namespace compiler {
      19             : 
      20             : namespace {
      21             : 
      22       35987 : bool CanInlineElementAccess(Handle<Map> map) {
      23       35987 :   if (!map->IsJSObjectMap()) return false;
      24       35727 :   if (map->is_access_check_needed()) return false;
      25       35727 :   if (map->has_indexed_interceptor()) return false;
      26             :   ElementsKind const elements_kind = map->elements_kind();
      27       35715 :   if (IsFastElementsKind(elements_kind)) return true;
      28        7334 :   if (IsFixedTypedArrayElementsKind(elements_kind)) return true;
      29        1823 :   return false;
      30             : }
      31             : 
      32             : 
      33      122057 : bool CanInlinePropertyAccess(Handle<Map> map) {
      34             :   // We can inline property access to prototypes of all primitives, except
      35             :   // the special Oddball ones that have no wrapper counterparts (i.e. Null,
      36             :   // Undefined and TheHole).
      37             :   STATIC_ASSERT(ODDBALL_TYPE == LAST_PRIMITIVE_TYPE);
      38      122057 :   if (map->IsBooleanMap()) return true;
      39      121944 :   if (map->instance_type() < LAST_PRIMITIVE_TYPE) return true;
      40      236499 :   return map->IsJSObjectMap() && !map->is_dictionary_map() &&
      41      236486 :          !map->has_named_interceptor() &&
      42             :          // TODO(verwaest): Whitelist contexts to which we have access.
      43      118526 :          !map->is_access_check_needed();
      44             : }
      45             : 
      46             : }  // namespace
      47             : 
      48             : 
      49           0 : std::ostream& operator<<(std::ostream& os, AccessMode access_mode) {
      50           0 :   switch (access_mode) {
      51             :     case AccessMode::kLoad:
      52           0 :       return os << "Load";
      53             :     case AccessMode::kStore:
      54           0 :       return os << "Store";
      55             :     case AccessMode::kStoreInLiteral:
      56           0 :       return os << "StoreInLiteral";
      57             :   }
      58           0 :   UNREACHABLE();
      59             :   return os;
      60             : }
      61             : 
      62           0 : ElementAccessInfo::ElementAccessInfo() {}
      63             : 
      64           0 : ElementAccessInfo::ElementAccessInfo(MapList const& receiver_maps,
      65             :                                      ElementsKind elements_kind)
      66       26914 :     : elements_kind_(elements_kind), receiver_maps_(receiver_maps) {}
      67             : 
      68             : // static
      69           0 : PropertyAccessInfo PropertyAccessInfo::NotFound(MapList const& receiver_maps,
      70             :                                                 MaybeHandle<JSObject> holder) {
      71           0 :   return PropertyAccessInfo(holder, receiver_maps);
      72             : }
      73             : 
      74             : // static
      75           0 : PropertyAccessInfo PropertyAccessInfo::DataConstant(
      76             :     MapList const& receiver_maps, Handle<Object> constant,
      77             :     MaybeHandle<JSObject> holder) {
      78           0 :   return PropertyAccessInfo(kDataConstant, holder, constant, receiver_maps);
      79             : }
      80             : 
      81             : // static
      82           0 : PropertyAccessInfo PropertyAccessInfo::DataField(
      83             :     PropertyConstness constness, MapList const& receiver_maps,
      84             :     FieldIndex field_index, MachineRepresentation field_representation,
      85             :     Type* field_type, MaybeHandle<Map> field_map, MaybeHandle<JSObject> holder,
      86             :     MaybeHandle<Map> transition_map) {
      87       18784 :   Kind kind = constness == kConst ? kDataConstantField : kDataField;
      88             :   return PropertyAccessInfo(kind, holder, transition_map, field_index,
      89             :                             field_representation, field_type, field_map,
      90           0 :                             receiver_maps);
      91             : }
      92             : 
      93             : // static
      94           0 : PropertyAccessInfo PropertyAccessInfo::AccessorConstant(
      95             :     MapList const& receiver_maps, Handle<Object> constant,
      96             :     MaybeHandle<JSObject> holder) {
      97           0 :   return PropertyAccessInfo(kAccessorConstant, holder, constant, receiver_maps);
      98             : }
      99             : 
     100        1371 : PropertyAccessInfo::PropertyAccessInfo()
     101             :     : kind_(kInvalid),
     102             :       field_representation_(MachineRepresentation::kNone),
     103      191257 :       field_type_(Type::None()) {}
     104             : 
     105           0 : PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder,
     106             :                                        MapList const& receiver_maps)
     107             :     : kind_(kNotFound),
     108             :       receiver_maps_(receiver_maps),
     109             :       holder_(holder),
     110             :       field_representation_(MachineRepresentation::kNone),
     111        6915 :       field_type_(Type::None()) {}
     112             : 
     113           0 : PropertyAccessInfo::PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
     114             :                                        Handle<Object> constant,
     115             :                                        MapList const& receiver_maps)
     116             :     : kind_(kind),
     117             :       receiver_maps_(receiver_maps),
     118             :       constant_(constant),
     119             :       holder_(holder),
     120             :       field_representation_(MachineRepresentation::kNone),
     121      183786 :       field_type_(Type::Any()) {}
     122             : 
     123           0 : PropertyAccessInfo::PropertyAccessInfo(
     124             :     Kind kind, MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map,
     125             :     FieldIndex field_index, MachineRepresentation field_representation,
     126             :     Type* field_type, MaybeHandle<Map> field_map, MapList const& receiver_maps)
     127             :     : kind_(kind),
     128             :       receiver_maps_(receiver_maps),
     129             :       transition_map_(transition_map),
     130             :       holder_(holder),
     131             :       field_index_(field_index),
     132             :       field_representation_(field_representation),
     133             :       field_type_(field_type),
     134       59782 :       field_map_(field_map) {}
     135             : 
     136        6469 : bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that,
     137             :                                AccessMode access_mode, Zone* zone) {
     138        6469 :   if (this->kind_ != that->kind_) return false;
     139        6173 :   if (this->holder_.address() != that->holder_.address()) return false;
     140             : 
     141        5686 :   switch (this->kind_) {
     142             :     case kInvalid:
     143             :       break;
     144             : 
     145             :     case kDataField:
     146             :     case kDataConstantField: {
     147             :       // Check if we actually access the same field.
     148        9518 :       if (this->kind_ == that->kind_ &&
     149             :           this->field_index_ == that->field_index_) {
     150        2296 :         switch (access_mode) {
     151             :           case AccessMode::kLoad: {
     152        2125 :             if (this->field_representation_ != that->field_representation_) {
     153         576 :               if (!IsAnyTagged(this->field_representation_) ||
     154             :                   !IsAnyTagged(that->field_representation_)) {
     155             :                 return false;
     156             :               }
     157         288 :               this->field_representation_ = MachineRepresentation::kTagged;
     158             :             }
     159        2125 :             if (this->field_map_.address() != that->field_map_.address()) {
     160           8 :               this->field_map_ = MaybeHandle<Map>();
     161             :             }
     162             :             break;
     163             :           }
     164             :           case AccessMode::kStore:
     165             :           case AccessMode::kStoreInLiteral: {
     166             :             // For stores, the field map and field representation information
     167             :             // must match exactly, otherwise we cannot merge the stores. We
     168             :             // also need to make sure that in case of transitioning stores,
     169             :             // the transition targets match.
     170         342 :             if (this->field_map_.address() != that->field_map_.address() ||
     171         342 :                 this->field_representation_ != that->field_representation_ ||
     172             :                 this->transition_map_.address() !=
     173             :                     that->transition_map_.address()) {
     174             :               return false;
     175             :             }
     176             :             break;
     177             :           }
     178             :         }
     179             :         // Merge the field type.
     180             :         this->field_type_ =
     181        2208 :             Type::Union(this->field_type_, that->field_type_, zone);
     182             :         // Merge the receiver maps.
     183             :         this->receiver_maps_.insert(this->receiver_maps_.end(),
     184             :                                     that->receiver_maps_.begin(),
     185        5037 :                                     that->receiver_maps_.end());
     186        2208 :         return true;
     187             :       }
     188             :       return false;
     189             :     }
     190             : 
     191             :     case kDataConstant:
     192             :     case kAccessorConstant: {
     193             :       // Check if we actually access the same constant.
     194         917 :       if (this->constant_.address() == that->constant_.address()) {
     195             :         this->receiver_maps_.insert(this->receiver_maps_.end(),
     196             :                                     that->receiver_maps_.begin(),
     197         611 :                                     that->receiver_maps_.end());
     198         611 :         return true;
     199             :       }
     200             :       return false;
     201             :     }
     202             : 
     203             :     case kNotFound: {
     204             :       this->receiver_maps_.insert(this->receiver_maps_.end(),
     205             :                                   that->receiver_maps_.begin(),
     206          10 :                                   that->receiver_maps_.end());
     207          10 :       return true;
     208             :     }
     209             :   }
     210             : 
     211           0 :   UNREACHABLE();
     212             :   return false;
     213             : }
     214             : 
     215      115970 : AccessInfoFactory::AccessInfoFactory(CompilationDependencies* dependencies,
     216             :                                      Handle<Context> native_context, Zone* zone)
     217             :     : dependencies_(dependencies),
     218             :       native_context_(native_context),
     219             :       isolate_(native_context->GetIsolate()),
     220      115970 :       type_cache_(TypeCache::Get()),
     221      347910 :       zone_(zone) {
     222             :   DCHECK(native_context->IsNativeContext());
     223      115970 : }
     224             : 
     225             : 
     226        3259 : bool AccessInfoFactory::ComputeElementAccessInfo(
     227             :     Handle<Map> map, AccessMode access_mode, ElementAccessInfo* access_info) {
     228             :   // Check if it is safe to inline element access for the {map}.
     229        3259 :   if (!CanInlineElementAccess(map)) return false;
     230             :   ElementsKind const elements_kind = map->elements_kind();
     231        7692 :   *access_info = ElementAccessInfo(MapList{map}, elements_kind);
     232        2564 :   return true;
     233             : }
     234             : 
     235       26415 : bool AccessInfoFactory::ComputeElementAccessInfos(
     236        6195 :     MapHandleList const& maps, AccessMode access_mode,
     237             :     ZoneVector<ElementAccessInfo>* access_infos) {
     238             :   // For polymorphic loads of similar elements kinds (i.e. all tagged or all
     239             :   // double), always use the "worst case" code without a transition. This is
     240             :   // much faster than transitioning the elements to the worst case, trading a
     241             :   // TransitionElementsKind for a CheckMaps, avoiding mutation of the array.
     242             :   //
     243             :   // Similarly, for polymorphic stores of compatible elements kind that
     244             :   // differ only in holeyness, always use the "holey case" code without a
     245             :   // transition. This is beneficial, because CheckMaps can often be optimized
     246             :   // whereas TransitionElementsKind can block optimizations. And as above, we
     247             :   // avoid mutation of the array (we still mutate the array contents).
     248             :   ElementAccessInfo access_info;
     249       26415 :   if (ConsolidateElementAccess(maps, access_mode, &access_info)) {
     250       24350 :     access_infos->push_back(access_info);
     251       24350 :     return true;
     252             :   }
     253             : 
     254             :   // Collect possible transition targets.
     255             :   MapHandleList possible_transition_targets(maps.length());
     256        7981 :   for (Handle<Map> map : maps) {
     257        7702 :     if (Map::TryUpdate(map).ToHandle(&map)) {
     258       10837 :       if (CanInlineElementAccess(map) &&
     259        6678 :           IsFastElementsKind(map->elements_kind()) &&
     260             :           GetInitialFastElementsKind() != map->elements_kind()) {
     261        2125 :         possible_transition_targets.Add(map);
     262             :       }
     263             :     }
     264             :   }
     265             : 
     266             :   // Separate the actual receiver maps and the possible transition sources.
     267             :   MapHandleList receiver_maps(maps.length());
     268        2065 :   MapTransitionList transitions(maps.length());
     269        7981 :   for (Handle<Map> map : maps) {
     270        7702 :     if (Map::TryUpdate(map).ToHandle(&map)) {
     271             :       Map* transition_target =
     272        3851 :           map->FindElementsKindTransitionedMap(&possible_transition_targets);
     273        3851 :       if (transition_target == nullptr) {
     274        3418 :         receiver_maps.Add(map);
     275             :       } else {
     276             :         DCHECK(!map->is_stable());
     277         866 :         transitions.push_back(std::make_pair(map, handle(transition_target)));
     278             :       }
     279             :     }
     280             :   }
     281             : 
     282        6694 :   for (Handle<Map> receiver_map : receiver_maps) {
     283             :     // Compute the element access information.
     284             :     ElementAccessInfo access_info;
     285        3259 :     if (!ComputeElementAccessInfo(receiver_map, access_mode, &access_info)) {
     286         695 :       return false;
     287             :     }
     288             : 
     289             :     // Collect the possible transitions for the {receiver_map}.
     290       11287 :     for (auto transition : transitions) {
     291        6159 :       if (transition.second.is_identical_to(receiver_map)) {
     292         433 :         access_info.transitions().push_back(transition);
     293             :       }
     294             :     }
     295             : 
     296             :     // Schedule the access information.
     297        2564 :     access_infos->push_back(access_info);
     298        2564 :   }
     299       27785 :   return true;
     300             : }
     301             : 
     302             : 
     303       94951 : bool AccessInfoFactory::ComputePropertyAccessInfo(
     304             :     Handle<Map> map, Handle<Name> name, AccessMode access_mode,
     305      464916 :     PropertyAccessInfo* access_info) {
     306             :   // Check if it is safe to inline property access for the {map}.
     307       94951 :   if (!CanInlinePropertyAccess(map)) return false;
     308             : 
     309             :   // Compute the receiver type.
     310             :   Handle<Map> receiver_map = map;
     311             : 
     312             :   // Property lookups require the name to be internalized.
     313       94475 :   name = isolate()->factory()->InternalizeName(name);
     314             : 
     315             :   // We support fast inline cases for certain JSObject getters.
     316      180879 :   if (access_mode == AccessMode::kLoad &&
     317       86404 :       LookupSpecialFieldAccessor(map, name, access_info)) {
     318             :     return true;
     319             :   }
     320             : 
     321             :   MaybeHandle<JSObject> holder;
     322       27106 :   do {
     323             :     // Lookup the named property on the {map}.
     324             :     Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
     325             :     int const number = descriptors->SearchWithCache(isolate(), *name, *map);
     326      114879 :     if (number != DescriptorArray::kNotFound) {
     327       81012 :       PropertyDetails const details = descriptors->GetDetails(number);
     328       81012 :       if (access_mode == AccessMode::kStore ||
     329             :           access_mode == AccessMode::kStoreInLiteral) {
     330             :         // Don't bother optimizing stores to read-only properties.
     331        3618 :         if (details.IsReadOnly()) {
     332             :           return false;
     333             :         }
     334             :         // Check for store to data property on a prototype.
     335        3582 :         if (details.kind() == kData && !holder.is_null()) {
     336             :           // Store to property not found on the receiver but on a prototype, we
     337             :           // need to transition to a new data property.
     338             :           // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
     339         127 :           return LookupTransition(receiver_map, name, holder, access_info);
     340             :         }
     341             :       }
     342       80849 :       if (details.location() == kField) {
     343       18784 :         if (details.kind() == kData) {
     344             :           int index = descriptors->GetFieldIndex(number);
     345             :           Representation details_representation = details.representation();
     346             :           FieldIndex field_index = FieldIndex::ForPropertyIndex(
     347       37568 :               *map, index, details_representation.IsDouble());
     348             :           Type* field_type = Type::NonInternal();
     349             :           MachineRepresentation field_representation =
     350             :               MachineRepresentation::kTagged;
     351             :           MaybeHandle<Map> field_map;
     352       18784 :           if (details_representation.IsSmi()) {
     353             :             field_type = Type::SignedSmall();
     354             :             field_representation = MachineRepresentation::kTaggedSigned;
     355       13835 :           } else if (details_representation.IsDouble()) {
     356         483 :             field_type = type_cache_.kFloat64;
     357             :             field_representation = MachineRepresentation::kFloat64;
     358       13352 :           } else if (details_representation.IsHeapObject()) {
     359             :             // Extract the field type from the property details (make sure its
     360             :             // representation is TaggedPointer to reflect the heap object case).
     361             :             field_representation = MachineRepresentation::kTaggedPointer;
     362             :             Handle<FieldType> descriptors_field_type(
     363        7298 :                 descriptors->GetFieldType(number), isolate());
     364        7298 :             if (descriptors_field_type->IsNone()) {
     365             :               // Store is not safe if the field type was cleared.
     366           0 :               if (access_mode == AccessMode::kStore) return false;
     367             : 
     368             :               // The field type was cleared by the GC, so we don't know anything
     369             :               // about the contents now.
     370        7298 :             } else if (descriptors_field_type->IsClass()) {
     371             :               // Add proper code dependencies in case of stable field map(s).
     372             :               Handle<Map> field_owner_map(map->FindFieldOwner(number),
     373        2566 :                                           isolate());
     374             :               dependencies()->AssumeFieldOwner(field_owner_map);
     375             : 
     376             :               // Remember the field map, and try to infer a useful type.
     377        2566 :               field_type = Type::For(descriptors_field_type->AsClass());
     378        2566 :               field_map = descriptors_field_type->AsClass();
     379             :             }
     380             :           }
     381       56352 :           *access_info = PropertyAccessInfo::DataField(
     382             :               details.constness(), MapList{receiver_map}, field_index,
     383       18784 :               field_representation, field_type, field_map, holder);
     384       18784 :           return true;
     385             :         } else {
     386             :           DCHECK_EQ(kAccessor, details.kind());
     387             :           // TODO(turbofan): Add support for general accessors?
     388             :           return false;
     389             :         }
     390             : 
     391             :       } else {
     392             :         DCHECK_EQ(kDescriptor, details.location());
     393       62065 :         if (details.kind() == kData) {
     394             :           DCHECK(!FLAG_track_constant_fields);
     395      179706 :           *access_info = PropertyAccessInfo::DataConstant(
     396             :               MapList{receiver_map},
     397       59902 :               handle(descriptors->GetValue(number), isolate()), holder);
     398       59902 :           return true;
     399             :         } else {
     400             :           DCHECK_EQ(kAccessor, details.kind());
     401             :           Handle<Object> accessors(descriptors->GetValue(number), isolate());
     402        2163 :           if (!accessors->IsAccessorPair()) return false;
     403             :           Handle<Object> accessor(
     404             :               access_mode == AccessMode::kLoad
     405             :                   ? Handle<AccessorPair>::cast(accessors)->getter()
     406             :                   : Handle<AccessorPair>::cast(accessors)->setter(),
     407        1423 :               isolate());
     408        1423 :           if (!accessor->IsJSFunction()) {
     409          64 :             CallOptimization optimization(accessor);
     410          64 :             if (!optimization.is_simple_api_call()) {
     411          55 :               return false;
     412             :             }
     413           9 :             if (V8_UNLIKELY(FLAG_runtime_stats)) return false;
     414             :           }
     415        1368 :           if (access_mode == AccessMode::kLoad) {
     416             :             Handle<Name> cached_property_name;
     417         863 :             if (FunctionTemplateInfo::TryGetCachedPropertyName(isolate(),
     418             :                                                                accessor)
     419        1726 :                     .ToHandle(&cached_property_name)) {
     420           8 :               if (ComputePropertyAccessInfo(map, cached_property_name,
     421             :                                             access_mode, access_info)) {
     422           8 :                 return true;
     423             :               }
     424             :             }
     425             :           }
     426        4080 :           *access_info = PropertyAccessInfo::AccessorConstant(
     427        1360 :               MapList{receiver_map}, accessor, holder);
     428        1360 :           return true;
     429             :         }
     430             :       }
     431             :       UNREACHABLE();
     432             :       return false;
     433             :     }
     434             : 
     435             :     // Don't search on the prototype chain for special indices in case of
     436             :     // integer indexed exotic objects (see ES6 section 9.4.5).
     437       34702 :     if (map->IsJSTypedArrayMap() && name->IsString() &&
     438         414 :         IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) {
     439             :       return false;
     440             :     }
     441             : 
     442             :     // Don't search on the prototype when storing in literals
     443       33860 :     if (access_mode == AccessMode::kStoreInLiteral) {
     444         123 :       return LookupTransition(receiver_map, name, holder, access_info);
     445             :     }
     446             : 
     447             :     // Don't lookup private symbols on the prototype chain.
     448       33737 :     if (name->IsPrivate()) return false;
     449             : 
     450             :     // Walk up the prototype chain.
     451       33731 :     if (!map->prototype()->IsJSObject()) {
     452             :       // Perform the implicit ToObject for primitives here.
     453             :       // Implemented according to ES6 section 7.3.2 GetV (V, P).
     454             :       Handle<JSFunction> constructor;
     455        9276 :       if (Map::GetConstructorFunction(map, native_context())
     456       18552 :               .ToHandle(&constructor)) {
     457             :         map = handle(constructor->initial_map(), isolate());
     458             :         DCHECK(map->prototype()->IsJSObject());
     459        6625 :       } else if (map->prototype()->IsNull(isolate())) {
     460             :         // Store to property not found on the receiver or any prototype, we need
     461             :         // to transition to a new data property.
     462             :         // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
     463        6618 :         if (access_mode == AccessMode::kStore) {
     464        4313 :           return LookupTransition(receiver_map, name, holder, access_info);
     465             :         }
     466             :         // The property was not found, return undefined or throw depending
     467             :         // on the language mode of the load operation.
     468             :         // Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver)
     469        6915 :         *access_info =
     470        2305 :             PropertyAccessInfo::NotFound(MapList{receiver_map}, holder);
     471        2305 :         return true;
     472             :       } else {
     473             :         return false;
     474             :       }
     475             :     }
     476             :     Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
     477       27106 :     if (map_prototype->map()->is_deprecated()) {
     478             :       // Try to migrate the prototype object so we don't embed the deprecated
     479             :       // map into the optimized code.
     480           0 :       JSObject::TryMigrateInstance(map_prototype);
     481             :     }
     482             :     map = handle(map_prototype->map(), isolate());
     483             :     holder = map_prototype;
     484             :   } while (CanInlinePropertyAccess(map));
     485             :   return false;
     486             : }
     487             : 
     488       88184 : bool AccessInfoFactory::ComputePropertyAccessInfos(
     489             :     MapHandleList const& maps, Handle<Name> name, AccessMode access_mode,
     490        6469 :     ZoneVector<PropertyAccessInfo>* access_infos) {
     491      268602 :   for (Handle<Map> map : maps) {
     492      187166 :     if (Map::TryUpdate(map).ToHandle(&map)) {
     493             :       PropertyAccessInfo access_info;
     494       93572 :       if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) {
     495             :         return false;
     496             :       }
     497             :       // Try to merge the {access_info} with an existing one.
     498             :       bool merged = false;
     499      188086 :       for (PropertyAccessInfo& other_info : *access_infos) {
     500        6469 :         if (other_info.Merge(&access_info, access_mode, zone())) {
     501             :           merged = true;
     502             :           break;
     503             :         }
     504             :       }
     505       92223 :       if (!merged) access_infos->push_back(access_info);
     506             :     }
     507             :   }
     508       86835 :   return true;
     509             : }
     510             : 
     511       26415 : bool AccessInfoFactory::ConsolidateElementAccess(
     512      108519 :     MapHandleList const& maps, AccessMode access_mode,
     513             :     ElementAccessInfo* access_info) {
     514       26415 :   if (maps.is_empty()) return false;
     515             :   InstanceType instance_type = maps.first()->instance_type();
     516             :   ElementsKind elements_kind = maps.first()->elements_kind();
     517       26415 :   MapList receiver_maps(maps.length());
     518      106454 :   for (int i = 0; i < maps.length(); ++i) {
     519       28877 :     Handle<Map> map = maps[i];
     520       57070 :     if (!CanInlineElementAccess(map) || map->instance_type() != instance_type) {
     521             :       return false;
     522             :     }
     523             :     ElementsKind other_kind = map->elements_kind();
     524       27908 :     if (IsHoleyElementsKind(elements_kind)) {
     525             :       other_kind = GetHoleyElementsKind(other_kind);
     526       20960 :     } else if (IsHoleyElementsKind(other_kind)) {
     527             :       elements_kind = GetHoleyElementsKind(elements_kind);
     528             :     }
     529       27908 :     if (elements_kind != other_kind) {
     530        1864 :       if (access_mode != AccessMode::kLoad) return false;
     531         866 :       if (IsFastDoubleElementsKind(elements_kind) !=
     532             :           IsFastDoubleElementsKind(other_kind)) {
     533             :         return false;
     534             :       }
     535         822 :       if (IsMoreGeneralElementsKindTransition(elements_kind, other_kind)) {
     536             :         elements_kind = other_kind;
     537         822 :       } else if (!IsMoreGeneralElementsKindTransition(other_kind,
     538         822 :                                                       elements_kind)) {
     539             :         return false;
     540             :       }
     541             :     }
     542       53624 :     receiver_maps[i] = map;
     543             :   }
     544       24350 :   *access_info = ElementAccessInfo(receiver_maps, elements_kind);
     545       24350 :   return true;
     546             : }
     547             : 
     548       86404 : bool AccessInfoFactory::LookupSpecialFieldAccessor(
     549             :     Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) {
     550             :   // Check for special JSObject field accessors.
     551             :   int offset;
     552       86404 :   if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) {
     553        6590 :     FieldIndex field_index = FieldIndex::ForInObjectOffset(offset);
     554             :     Type* field_type = Type::NonInternal();
     555             :     MachineRepresentation field_representation = MachineRepresentation::kTagged;
     556        6590 :     if (map->IsStringMap()) {
     557             :       DCHECK(Name::Equals(factory()->length_string(), name));
     558             :       // The String::length property is always a smi in the range
     559             :       // [0, String::kMaxLength].
     560         880 :       field_type = type_cache_.kStringLengthType;
     561             :       field_representation = MachineRepresentation::kTaggedSigned;
     562        5710 :     } else if (map->IsJSArrayMap()) {
     563             :       DCHECK(Name::Equals(factory()->length_string(), name));
     564             :       // The JSArray::length property is a smi in the range
     565             :       // [0, FixedDoubleArray::kMaxLength] in case of fast double
     566             :       // elements, a smi in the range [0, FixedArray::kMaxLength]
     567             :       // in case of other fast elements, and [0, kMaxUInt32] in
     568             :       // case of other arrays.
     569        5710 :       if (IsFastDoubleElementsKind(map->elements_kind())) {
     570         179 :         field_type = type_cache_.kFixedDoubleArrayLengthType;
     571             :         field_representation = MachineRepresentation::kTaggedSigned;
     572        5531 :       } else if (IsFastElementsKind(map->elements_kind())) {
     573        5306 :         field_type = type_cache_.kFixedArrayLengthType;
     574             :         field_representation = MachineRepresentation::kTaggedSigned;
     575             :       } else {
     576         225 :         field_type = type_cache_.kJSArrayLengthType;
     577             :       }
     578             :     }
     579             :     // Special fields are always mutable.
     580       19770 :     *access_info = PropertyAccessInfo::DataField(
     581        6590 :         kMutable, MapList{map}, field_index, field_representation, field_type);
     582             :     return true;
     583             :   }
     584             :   return false;
     585             : }
     586             : 
     587             : 
     588        4563 : bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name,
     589             :                                          MaybeHandle<JSObject> holder,
     590        6350 :                                          PropertyAccessInfo* access_info) {
     591             :   // Check if the {map} has a data transition with the given {name}.
     592             :   Handle<Map> transition_map;
     593        4563 :   if (TransitionArray::SearchTransition(map, kData, name, NONE)
     594        9126 :           .ToHandle(&transition_map)) {
     595             :     int const number = transition_map->LastAdded();
     596             :     PropertyDetails const details =
     597        4532 :         transition_map->instance_descriptors()->GetDetails(number);
     598             :     // Don't bother optimizing stores to read-only properties.
     599        4532 :     if (details.IsReadOnly()) return false;
     600             :     // TODO(bmeurer): Handle transition to data constant?
     601        4532 :     if (details.location() != kField) return false;
     602             :     int const index = details.field_index();
     603             :     Representation details_representation = details.representation();
     604             :     FieldIndex field_index = FieldIndex::ForPropertyIndex(
     605        9034 :         *transition_map, index, details_representation.IsDouble());
     606             :     Type* field_type = Type::NonInternal();
     607             :     MaybeHandle<Map> field_map;
     608             :     MachineRepresentation field_representation = MachineRepresentation::kTagged;
     609        4517 :     if (details_representation.IsSmi()) {
     610             :       field_type = Type::SignedSmall();
     611             :       field_representation = MachineRepresentation::kTaggedSigned;
     612        1604 :     } else if (details_representation.IsDouble()) {
     613         121 :       field_type = type_cache_.kFloat64;
     614             :       field_representation = MachineRepresentation::kFloat64;
     615        1483 :     } else if (details_representation.IsHeapObject()) {
     616             :       // Extract the field type from the property details (make sure its
     617             :       // representation is TaggedPointer to reflect the heap object case).
     618             :       field_representation = MachineRepresentation::kTaggedPointer;
     619             :       Handle<FieldType> descriptors_field_type(
     620             :           transition_map->instance_descriptors()->GetFieldType(number),
     621        1405 :           isolate());
     622        1405 :       if (descriptors_field_type->IsNone()) {
     623             :         // Store is not safe if the field type was cleared.
     624             :         return false;
     625        1405 :       } else if (descriptors_field_type->IsClass()) {
     626             :         // Add proper code dependencies in case of stable field map(s).
     627             :         Handle<Map> field_owner_map(transition_map->FindFieldOwner(number),
     628         214 :                                     isolate());
     629             :         dependencies()->AssumeFieldOwner(field_owner_map);
     630             : 
     631             :         // Remember the field map, and try to infer a useful type.
     632         214 :         field_type = Type::For(descriptors_field_type->AsClass());
     633         214 :         field_map = descriptors_field_type->AsClass();
     634             :       }
     635             :     }
     636        4517 :     dependencies()->AssumeMapNotDeprecated(transition_map);
     637             :     // Transitioning stores are never stores to constant fields.
     638       13551 :     *access_info = PropertyAccessInfo::DataField(
     639             :         kMutable, MapList{map}, field_index, field_representation, field_type,
     640        4517 :         field_map, holder, transition_map);
     641        4517 :     return true;
     642             :   }
     643             :   return false;
     644             : }
     645             : 
     646             : 
     647           0 : Factory* AccessInfoFactory::factory() const { return isolate()->factory(); }
     648             : 
     649             : }  // namespace compiler
     650             : }  // namespace internal
     651             : }  // namespace v8

Generated by: LCOV version 1.10